blob: 40bbe083a7bd8bef524c47a8b61a73cd46377ce2 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From 28758a9da77954ed323f86123ef448c6a563c037 Mon Sep 17 00:00:00 2001
2From: Florian Fainelli <florian@openwrt.org>
3Date: Mon, 28 Jan 2013 20:06:22 +0100
4Subject: [PATCH 04/11] MIPS: BCM63XX: add OHCI/EHCI configuration bits to
5 common USB code
6
7This patch updates the common USB code touching the USB private
8registers with the specific bits to properly enable OHCI and EHCI
9controllers on BCM63xx SoCs. As a result we now need to protect access
10to Read Modify Write sequences using a spinlock because we cannot
11guarantee that any of the exposed helper will not be called
12concurrently.
13
14Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
15Signed-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_ */