aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm63xx/patches-4.1/103-MIPS-BCM63XX-add-OHCI-EHCI-configuration-bits-to-com.patch
blob: 40bbe083a7bd8bef524c47a8b61a73cd46377ce2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
From 28758a9da77954ed323f86123ef448c6a563c037 Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Mon, 28 Jan 2013 20:06:22 +0100
Subject: [PATCH 04/11] MIPS: BCM63XX: add OHCI/EHCI configuration bits to
 common USB code

This patch updates the common USB code touching the USB private
registers with the specific bits to properly enable OHCI and EHCI
controllers on BCM63xx SoCs. As a result we now need to protect access
to Read Modify Write sequences using a spinlock because we cannot
guarantee that any of the exposed helper will not be called
concurrently.

Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
 arch/mips/bcm63xx/usb-common.c                     |   97 ++++++++++++++++++++
 .../include/asm/mach-bcm63xx/bcm63xx_usb_priv.h    |    2 +
 2 files changed, 99 insertions(+)

--- a/arch/mips/bcm63xx/usb-common.c
+++ b/arch/mips/bcm63xx/usb-common.c
@@ -5,10 +5,12 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
  * Copyright (C) 2012 Kevin Cernekee <cernekee@gmail.com>
  * Copyright (C) 2012 Broadcom Corporation
  *
  */
+#include <linux/spinlock.h>
 #include <linux/export.h>
 
 #include <bcm63xx_cpu.h>
@@ -16,9 +18,14 @@
 #include <bcm63xx_io.h>
 #include <bcm63xx_usb_priv.h>
 
+static DEFINE_SPINLOCK(usb_priv_reg_lock);
+
 void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device)
 {
 	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&usb_priv_reg_lock, flags);
 
 	val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
 	if (is_device) {
@@ -36,12 +43,17 @@ void bcm63xx_usb_priv_select_phy_mode(u3
 	else
 		val &= ~USBH_PRIV_SWAP_USBD_MASK;
 	bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_SWAP_6368_REG);
+
+	spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
 }
 EXPORT_SYMBOL(bcm63xx_usb_priv_select_phy_mode);
 
 void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on)
 {
 	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&usb_priv_reg_lock, flags);
 
 	val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
 	if (is_on)
@@ -49,5 +61,90 @@ void bcm63xx_usb_priv_select_pullup(u32
 	else
 		val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
 	bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
+
+	spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
 }
 EXPORT_SYMBOL(bcm63xx_usb_priv_select_pullup);
+
+/* The following array represents the meaning of the DESC/DATA
+ * endian swapping with respect to the CPU configured endianness
+ *
+ * DATA	ENDN	mmio	descriptor
+ * 0	0	BE	invalid
+ * 0	1	BE	LE
+ * 1	0	BE	BE
+ * 1	1	BE	invalid
+ *
+ * Since BCM63XX SoCs are configured to be in big-endian mode
+ * we want configuration at line 3.
+ */
+void bcm63xx_usb_priv_ohci_cfg_set(void)
+{
+	u32 reg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&usb_priv_reg_lock, flags);
+
+	if (BCMCPU_IS_6348())
+		bcm_rset_writel(RSET_OHCI_PRIV, 0, OHCI_PRIV_REG);
+	else if (BCMCPU_IS_6358()) {
+		reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6358_REG);
+		reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
+		reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
+		bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6358_REG);
+		/*
+		 * The magic value comes for the original vendor BSP
+		 * and is needed for USB to work. Datasheet does not
+		 * help, so the magic value is used as-is.
+		 */
+		bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020,
+				USBH_PRIV_TEST_6358_REG);
+
+	} else if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368()) {
+		reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
+		reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
+		reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
+		bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
+
+		reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
+		reg |= USBH_PRIV_SETUP_IOC_MASK;
+		bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
+	}
+
+	spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
+}
+
+void bcm63xx_usb_priv_ehci_cfg_set(void)
+{
+	u32 reg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&usb_priv_reg_lock, flags);
+
+	if (BCMCPU_IS_6358()) {
+		reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6358_REG);
+		reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
+		reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
+		bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6358_REG);
+
+		/*
+		 * The magic value comes for the original vendor BSP
+		 * and is needed for USB to work. Datasheet does not
+		 * help, so the magic value is used as-is.
+		 */
+		bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020,
+				USBH_PRIV_TEST_6358_REG);
+
+	} else if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368()) {
+		reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
+		reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
+		reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
+		bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
+
+		reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
+		reg |= USBH_PRIV_SETUP_IOC_MASK;
+		bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
+	}
+
+	spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
+}
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
@@ -5,5 +5,7 @@
 
 void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device);
 void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on);
+void bcm63xx_usb_priv_ohci_cfg_set(void);
+void bcm63xx_usb_priv_ehci_cfg_set(void);
 
 #endif /* BCM63XX_USB_PRIV_H_ */