brcm63xx: add preliminary support for 3.13
[openwrt.git] / target / linux / brcm63xx / patches-3.13 / 103-MIPS-BCM63XX-add-OHCI-EHCI-configuration-bits-to-com.patch
1 From 28758a9da77954ed323f86123ef448c6a563c037 Mon Sep 17 00:00:00 2001
2 From: Florian Fainelli <florian@openwrt.org>
3 Date: Mon, 28 Jan 2013 20:06:22 +0100
4 Subject: [PATCH 04/11] MIPS: BCM63XX: add OHCI/EHCI configuration bits to
5  common USB code
6
7 This patch updates the common USB code touching the USB private
8 registers with the specific bits to properly enable OHCI and EHCI
9 controllers on BCM63xx SoCs. As a result we now need to protect access
10 to Read Modify Write sequences using a spinlock because we cannot
11 guarantee that any of the exposed helper will not be called
12 concurrently.
13
14 Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
15 Signed-off-by: Florian Fainelli <florian@openwrt.org>
16 ---
17  arch/mips/bcm63xx/usb-common.c                     |   97 ++++++++++++++++++++
18  .../include/asm/mach-bcm63xx/bcm63xx_usb_priv.h    |    2 +
19  2 files changed, 99 insertions(+)
20
21 --- a/arch/mips/bcm63xx/usb-common.c
22 +++ b/arch/mips/bcm63xx/usb-common.c
23 @@ -5,10 +5,12 @@
24   * License.  See the file "COPYING" in the main directory of this archive
25   * for more details.
26   *
27 + * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
28   * Copyright (C) 2012 Kevin Cernekee <cernekee@gmail.com>
29   * Copyright (C) 2012 Broadcom Corporation
30   *
31   */
32 +#include <linux/spinlock.h>
33  #include <linux/export.h>
34  
35  #include <bcm63xx_cpu.h>
36 @@ -16,9 +18,14 @@
37  #include <bcm63xx_io.h>
38  #include <bcm63xx_usb_priv.h>
39  
40 +static DEFINE_SPINLOCK(usb_priv_reg_lock);
41 +
42  void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device)
43  {
44         u32 val;
45 +       unsigned long flags;
46 +
47 +       spin_lock_irqsave(&usb_priv_reg_lock, flags);
48  
49         val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
50         if (is_device) {
51 @@ -36,12 +43,17 @@ void bcm63xx_usb_priv_select_phy_mode(u3
52         else
53                 val &= ~USBH_PRIV_SWAP_USBD_MASK;
54         bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_SWAP_6368_REG);
55 +
56 +       spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
57  }
58  EXPORT_SYMBOL(bcm63xx_usb_priv_select_phy_mode);
59  
60  void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on)
61  {
62         u32 val;
63 +       unsigned long flags;
64 +
65 +       spin_lock_irqsave(&usb_priv_reg_lock, flags);
66  
67         val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
68         if (is_on)
69 @@ -49,5 +61,90 @@ void bcm63xx_usb_priv_select_pullup(u32
70         else
71                 val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
72         bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
73 +
74 +       spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
75  }
76  EXPORT_SYMBOL(bcm63xx_usb_priv_select_pullup);
77 +
78 +/* The following array represents the meaning of the DESC/DATA
79 + * endian swapping with respect to the CPU configured endianness
80 + *
81 + * DATA        ENDN    mmio    descriptor
82 + * 0   0       BE      invalid
83 + * 0   1       BE      LE
84 + * 1   0       BE      BE
85 + * 1   1       BE      invalid
86 + *
87 + * Since BCM63XX SoCs are configured to be in big-endian mode
88 + * we want configuration at line 3.
89 + */
90 +void bcm63xx_usb_priv_ohci_cfg_set(void)
91 +{
92 +       u32 reg;
93 +       unsigned long flags;
94 +
95 +       spin_lock_irqsave(&usb_priv_reg_lock, flags);
96 +
97 +       if (BCMCPU_IS_6348())
98 +               bcm_rset_writel(RSET_OHCI_PRIV, 0, OHCI_PRIV_REG);
99 +       else if (BCMCPU_IS_6358()) {
100 +               reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6358_REG);
101 +               reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
102 +               reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
103 +               bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6358_REG);
104 +               /*
105 +                * The magic value comes for the original vendor BSP
106 +                * and is needed for USB to work. Datasheet does not
107 +                * help, so the magic value is used as-is.
108 +                */
109 +               bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020,
110 +                               USBH_PRIV_TEST_6358_REG);
111 +
112 +       } else if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368()) {
113 +               reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
114 +               reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
115 +               reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
116 +               bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
117 +
118 +               reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
119 +               reg |= USBH_PRIV_SETUP_IOC_MASK;
120 +               bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
121 +       }
122 +
123 +       spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
124 +}
125 +
126 +void bcm63xx_usb_priv_ehci_cfg_set(void)
127 +{
128 +       u32 reg;
129 +       unsigned long flags;
130 +
131 +       spin_lock_irqsave(&usb_priv_reg_lock, flags);
132 +
133 +       if (BCMCPU_IS_6358()) {
134 +               reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6358_REG);
135 +               reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
136 +               reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
137 +               bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6358_REG);
138 +
139 +               /*
140 +                * The magic value comes for the original vendor BSP
141 +                * and is needed for USB to work. Datasheet does not
142 +                * help, so the magic value is used as-is.
143 +                */
144 +               bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020,
145 +                               USBH_PRIV_TEST_6358_REG);
146 +
147 +       } else if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368()) {
148 +               reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
149 +               reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
150 +               reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
151 +               bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
152 +
153 +               reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
154 +               reg |= USBH_PRIV_SETUP_IOC_MASK;
155 +               bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
156 +       }
157 +
158 +       spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
159 +}
160 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
161 +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
162 @@ -5,5 +5,7 @@
163  
164  void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device);
165  void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on);
166 +void bcm63xx_usb_priv_ohci_cfg_set(void);
167 +void bcm63xx_usb_priv_ehci_cfg_set(void);
168  
169  #endif /* BCM63XX_USB_PRIV_H_ */