diff options
author | Florian Fainelli <florian@openwrt.org> | 2012-10-08 09:11:40 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-22 14:29:12 -0400 |
commit | 216d0fded417d26a19049038788813af126b9d66 (patch) | |
tree | a8b90b43d8d0bd804dae305c0bd9babe0250f620 /arch/mips/alchemy | |
parent | bb5da43e4525d3338f51edb980e3067b111b78aa (diff) |
USB: move common alchemy USB routines to arch/mips/alchemy/common.c
A previous patch converted the Alchemy platform to use the OHCI and EHCI
platform drivers. As a result, all the common logic to handle USB present in
drivers/usb/host/alchemy-common.c has no reason to remain here, so we move it
to arch/mips/alchemy/common/usb.c which is a more appropriate place. This
change was suggested by Manuel Lauss.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch/mips/alchemy')
-rw-r--r-- | arch/mips/alchemy/common/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/alchemy/common/usb.c | 614 |
2 files changed, 615 insertions, 1 deletions
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile index 407ebc00e661..cb83d8d21aef 100644 --- a/arch/mips/alchemy/common/Makefile +++ b/arch/mips/alchemy/common/Makefile | |||
@@ -6,7 +6,7 @@ | |||
6 | # | 6 | # |
7 | 7 | ||
8 | obj-y += prom.o time.o clocks.o platform.o power.o setup.o \ | 8 | obj-y += prom.o time.o clocks.o platform.o power.o setup.o \ |
9 | sleeper.o dma.o dbdma.o vss.o irq.o | 9 | sleeper.o dma.o dbdma.o vss.o irq.o usb.o |
10 | 10 | ||
11 | # optional gpiolib support | 11 | # optional gpiolib support |
12 | ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),) | 12 | ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),) |
diff --git a/arch/mips/alchemy/common/usb.c b/arch/mips/alchemy/common/usb.c new file mode 100644 index 000000000000..936af8359fb2 --- /dev/null +++ b/arch/mips/alchemy/common/usb.c | |||
@@ -0,0 +1,614 @@ | |||
1 | /* | ||
2 | * USB block power/access management abstraction. | ||
3 | * | ||
4 | * Au1000+: The OHCI block control register is at the far end of the OHCI memory | ||
5 | * area. Au1550 has OHCI on different base address. No need to handle | ||
6 | * UDC here. | ||
7 | * Au1200: one register to control access and clocks to O/EHCI, UDC and OTG | ||
8 | * as well as the PHY for EHCI and UDC. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/syscore_ops.h> | ||
17 | #include <asm/mach-au1x00/au1000.h> | ||
18 | |||
19 | /* control register offsets */ | ||
20 | #define AU1000_OHCICFG 0x7fffc | ||
21 | #define AU1550_OHCICFG 0x07ffc | ||
22 | #define AU1200_USBCFG 0x04 | ||
23 | |||
24 | /* Au1000 USB block config bits */ | ||
25 | #define USBHEN_RD (1 << 4) /* OHCI reset-done indicator */ | ||
26 | #define USBHEN_CE (1 << 3) /* OHCI block clock enable */ | ||
27 | #define USBHEN_E (1 << 2) /* OHCI block enable */ | ||
28 | #define USBHEN_C (1 << 1) /* OHCI block coherency bit */ | ||
29 | #define USBHEN_BE (1 << 0) /* OHCI Big-Endian */ | ||
30 | |||
31 | /* Au1200 USB config bits */ | ||
32 | #define USBCFG_PFEN (1 << 31) /* prefetch enable (undoc) */ | ||
33 | #define USBCFG_RDCOMB (1 << 30) /* read combining (undoc) */ | ||
34 | #define USBCFG_UNKNOWN (5 << 20) /* unknown, leave this way */ | ||
35 | #define USBCFG_SSD (1 << 23) /* serial short detect en */ | ||
36 | #define USBCFG_PPE (1 << 19) /* HS PHY PLL */ | ||
37 | #define USBCFG_UCE (1 << 18) /* UDC clock enable */ | ||
38 | #define USBCFG_ECE (1 << 17) /* EHCI clock enable */ | ||
39 | #define USBCFG_OCE (1 << 16) /* OHCI clock enable */ | ||
40 | #define USBCFG_FLA(x) (((x) & 0x3f) << 8) | ||
41 | #define USBCFG_UCAM (1 << 7) /* coherent access (undoc) */ | ||
42 | #define USBCFG_GME (1 << 6) /* OTG mem access */ | ||
43 | #define USBCFG_DBE (1 << 5) /* UDC busmaster enable */ | ||
44 | #define USBCFG_DME (1 << 4) /* UDC mem enable */ | ||
45 | #define USBCFG_EBE (1 << 3) /* EHCI busmaster enable */ | ||
46 | #define USBCFG_EME (1 << 2) /* EHCI mem enable */ | ||
47 | #define USBCFG_OBE (1 << 1) /* OHCI busmaster enable */ | ||
48 | #define USBCFG_OME (1 << 0) /* OHCI mem enable */ | ||
49 | #define USBCFG_INIT_AU1200 (USBCFG_PFEN | USBCFG_RDCOMB | USBCFG_UNKNOWN |\ | ||
50 | USBCFG_SSD | USBCFG_FLA(0x20) | USBCFG_UCAM | \ | ||
51 | USBCFG_GME | USBCFG_DBE | USBCFG_DME | \ | ||
52 | USBCFG_EBE | USBCFG_EME | USBCFG_OBE | \ | ||
53 | USBCFG_OME) | ||
54 | |||
55 | /* Au1300 USB config registers */ | ||
56 | #define USB_DWC_CTRL1 0x00 | ||
57 | #define USB_DWC_CTRL2 0x04 | ||
58 | #define USB_VBUS_TIMER 0x10 | ||
59 | #define USB_SBUS_CTRL 0x14 | ||
60 | #define USB_MSR_ERR 0x18 | ||
61 | #define USB_DWC_CTRL3 0x1C | ||
62 | #define USB_DWC_CTRL4 0x20 | ||
63 | #define USB_OTG_STATUS 0x28 | ||
64 | #define USB_DWC_CTRL5 0x2C | ||
65 | #define USB_DWC_CTRL6 0x30 | ||
66 | #define USB_DWC_CTRL7 0x34 | ||
67 | #define USB_PHY_STATUS 0xC0 | ||
68 | #define USB_INT_STATUS 0xC4 | ||
69 | #define USB_INT_ENABLE 0xC8 | ||
70 | |||
71 | #define USB_DWC_CTRL1_OTGD 0x04 /* set to DISable OTG */ | ||
72 | #define USB_DWC_CTRL1_HSTRS 0x02 /* set to ENable EHCI */ | ||
73 | #define USB_DWC_CTRL1_DCRS 0x01 /* set to ENable UDC */ | ||
74 | |||
75 | #define USB_DWC_CTRL2_PHY1RS 0x04 /* set to enable PHY1 */ | ||
76 | #define USB_DWC_CTRL2_PHY0RS 0x02 /* set to enable PHY0 */ | ||
77 | #define USB_DWC_CTRL2_PHYRS 0x01 /* set to enable PHY */ | ||
78 | |||
79 | #define USB_DWC_CTRL3_OHCI1_CKEN (1 << 19) | ||
80 | #define USB_DWC_CTRL3_OHCI0_CKEN (1 << 18) | ||
81 | #define USB_DWC_CTRL3_EHCI0_CKEN (1 << 17) | ||
82 | #define USB_DWC_CTRL3_OTG0_CKEN (1 << 16) | ||
83 | |||
84 | #define USB_SBUS_CTRL_SBCA 0x04 /* coherent access */ | ||
85 | |||
86 | #define USB_INTEN_FORCE 0x20 | ||
87 | #define USB_INTEN_PHY 0x10 | ||
88 | #define USB_INTEN_UDC 0x08 | ||
89 | #define USB_INTEN_EHCI 0x04 | ||
90 | #define USB_INTEN_OHCI1 0x02 | ||
91 | #define USB_INTEN_OHCI0 0x01 | ||
92 | |||
93 | static DEFINE_SPINLOCK(alchemy_usb_lock); | ||
94 | |||
95 | static inline void __au1300_usb_phyctl(void __iomem *base, int enable) | ||
96 | { | ||
97 | unsigned long r, s; | ||
98 | |||
99 | r = __raw_readl(base + USB_DWC_CTRL2); | ||
100 | s = __raw_readl(base + USB_DWC_CTRL3); | ||
101 | |||
102 | s &= USB_DWC_CTRL3_OHCI1_CKEN | USB_DWC_CTRL3_OHCI0_CKEN | | ||
103 | USB_DWC_CTRL3_EHCI0_CKEN | USB_DWC_CTRL3_OTG0_CKEN; | ||
104 | |||
105 | if (enable) { | ||
106 | /* simply enable all PHYs */ | ||
107 | r |= USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | | ||
108 | USB_DWC_CTRL2_PHYRS; | ||
109 | __raw_writel(r, base + USB_DWC_CTRL2); | ||
110 | wmb(); | ||
111 | } else if (!s) { | ||
112 | /* no USB block active, do disable all PHYs */ | ||
113 | r &= ~(USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | | ||
114 | USB_DWC_CTRL2_PHYRS); | ||
115 | __raw_writel(r, base + USB_DWC_CTRL2); | ||
116 | wmb(); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | static inline void __au1300_ohci_control(void __iomem *base, int enable, int id) | ||
121 | { | ||
122 | unsigned long r; | ||
123 | |||
124 | if (enable) { | ||
125 | __raw_writel(1, base + USB_DWC_CTRL7); /* start OHCI clock */ | ||
126 | wmb(); | ||
127 | |||
128 | r = __raw_readl(base + USB_DWC_CTRL3); /* enable OHCI block */ | ||
129 | r |= (id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN | ||
130 | : USB_DWC_CTRL3_OHCI1_CKEN; | ||
131 | __raw_writel(r, base + USB_DWC_CTRL3); | ||
132 | wmb(); | ||
133 | |||
134 | __au1300_usb_phyctl(base, enable); /* power up the PHYs */ | ||
135 | |||
136 | r = __raw_readl(base + USB_INT_ENABLE); | ||
137 | r |= (id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1; | ||
138 | __raw_writel(r, base + USB_INT_ENABLE); | ||
139 | wmb(); | ||
140 | |||
141 | /* reset the OHCI start clock bit */ | ||
142 | __raw_writel(0, base + USB_DWC_CTRL7); | ||
143 | wmb(); | ||
144 | } else { | ||
145 | r = __raw_readl(base + USB_INT_ENABLE); | ||
146 | r &= ~((id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1); | ||
147 | __raw_writel(r, base + USB_INT_ENABLE); | ||
148 | wmb(); | ||
149 | |||
150 | r = __raw_readl(base + USB_DWC_CTRL3); | ||
151 | r &= ~((id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN | ||
152 | : USB_DWC_CTRL3_OHCI1_CKEN); | ||
153 | __raw_writel(r, base + USB_DWC_CTRL3); | ||
154 | wmb(); | ||
155 | |||
156 | __au1300_usb_phyctl(base, enable); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static inline void __au1300_ehci_control(void __iomem *base, int enable) | ||
161 | { | ||
162 | unsigned long r; | ||
163 | |||
164 | if (enable) { | ||
165 | r = __raw_readl(base + USB_DWC_CTRL3); | ||
166 | r |= USB_DWC_CTRL3_EHCI0_CKEN; | ||
167 | __raw_writel(r, base + USB_DWC_CTRL3); | ||
168 | wmb(); | ||
169 | |||
170 | r = __raw_readl(base + USB_DWC_CTRL1); | ||
171 | r |= USB_DWC_CTRL1_HSTRS; | ||
172 | __raw_writel(r, base + USB_DWC_CTRL1); | ||
173 | wmb(); | ||
174 | |||
175 | __au1300_usb_phyctl(base, enable); | ||
176 | |||
177 | r = __raw_readl(base + USB_INT_ENABLE); | ||
178 | r |= USB_INTEN_EHCI; | ||
179 | __raw_writel(r, base + USB_INT_ENABLE); | ||
180 | wmb(); | ||
181 | } else { | ||
182 | r = __raw_readl(base + USB_INT_ENABLE); | ||
183 | r &= ~USB_INTEN_EHCI; | ||
184 | __raw_writel(r, base + USB_INT_ENABLE); | ||
185 | wmb(); | ||
186 | |||
187 | r = __raw_readl(base + USB_DWC_CTRL1); | ||
188 | r &= ~USB_DWC_CTRL1_HSTRS; | ||
189 | __raw_writel(r, base + USB_DWC_CTRL1); | ||
190 | wmb(); | ||
191 | |||
192 | r = __raw_readl(base + USB_DWC_CTRL3); | ||
193 | r &= ~USB_DWC_CTRL3_EHCI0_CKEN; | ||
194 | __raw_writel(r, base + USB_DWC_CTRL3); | ||
195 | wmb(); | ||
196 | |||
197 | __au1300_usb_phyctl(base, enable); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | static inline void __au1300_udc_control(void __iomem *base, int enable) | ||
202 | { | ||
203 | unsigned long r; | ||
204 | |||
205 | if (enable) { | ||
206 | r = __raw_readl(base + USB_DWC_CTRL1); | ||
207 | r |= USB_DWC_CTRL1_DCRS; | ||
208 | __raw_writel(r, base + USB_DWC_CTRL1); | ||
209 | wmb(); | ||
210 | |||
211 | __au1300_usb_phyctl(base, enable); | ||
212 | |||
213 | r = __raw_readl(base + USB_INT_ENABLE); | ||
214 | r |= USB_INTEN_UDC; | ||
215 | __raw_writel(r, base + USB_INT_ENABLE); | ||
216 | wmb(); | ||
217 | } else { | ||
218 | r = __raw_readl(base + USB_INT_ENABLE); | ||
219 | r &= ~USB_INTEN_UDC; | ||
220 | __raw_writel(r, base + USB_INT_ENABLE); | ||
221 | wmb(); | ||
222 | |||
223 | r = __raw_readl(base + USB_DWC_CTRL1); | ||
224 | r &= ~USB_DWC_CTRL1_DCRS; | ||
225 | __raw_writel(r, base + USB_DWC_CTRL1); | ||
226 | wmb(); | ||
227 | |||
228 | __au1300_usb_phyctl(base, enable); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | static inline void __au1300_otg_control(void __iomem *base, int enable) | ||
233 | { | ||
234 | unsigned long r; | ||
235 | if (enable) { | ||
236 | r = __raw_readl(base + USB_DWC_CTRL3); | ||
237 | r |= USB_DWC_CTRL3_OTG0_CKEN; | ||
238 | __raw_writel(r, base + USB_DWC_CTRL3); | ||
239 | wmb(); | ||
240 | |||
241 | r = __raw_readl(base + USB_DWC_CTRL1); | ||
242 | r &= ~USB_DWC_CTRL1_OTGD; | ||
243 | __raw_writel(r, base + USB_DWC_CTRL1); | ||
244 | wmb(); | ||
245 | |||
246 | __au1300_usb_phyctl(base, enable); | ||
247 | } else { | ||
248 | r = __raw_readl(base + USB_DWC_CTRL1); | ||
249 | r |= USB_DWC_CTRL1_OTGD; | ||
250 | __raw_writel(r, base + USB_DWC_CTRL1); | ||
251 | wmb(); | ||
252 | |||
253 | r = __raw_readl(base + USB_DWC_CTRL3); | ||
254 | r &= ~USB_DWC_CTRL3_OTG0_CKEN; | ||
255 | __raw_writel(r, base + USB_DWC_CTRL3); | ||
256 | wmb(); | ||
257 | |||
258 | __au1300_usb_phyctl(base, enable); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | static inline int au1300_usb_control(int block, int enable) | ||
263 | { | ||
264 | void __iomem *base = | ||
265 | (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); | ||
266 | int ret = 0; | ||
267 | |||
268 | switch (block) { | ||
269 | case ALCHEMY_USB_OHCI0: | ||
270 | __au1300_ohci_control(base, enable, 0); | ||
271 | break; | ||
272 | case ALCHEMY_USB_OHCI1: | ||
273 | __au1300_ohci_control(base, enable, 1); | ||
274 | break; | ||
275 | case ALCHEMY_USB_EHCI0: | ||
276 | __au1300_ehci_control(base, enable); | ||
277 | break; | ||
278 | case ALCHEMY_USB_UDC0: | ||
279 | __au1300_udc_control(base, enable); | ||
280 | break; | ||
281 | case ALCHEMY_USB_OTG0: | ||
282 | __au1300_otg_control(base, enable); | ||
283 | break; | ||
284 | default: | ||
285 | ret = -ENODEV; | ||
286 | } | ||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | static inline void au1300_usb_init(void) | ||
291 | { | ||
292 | void __iomem *base = | ||
293 | (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); | ||
294 | |||
295 | /* set some sane defaults. Note: we don't fiddle with DWC_CTRL4 | ||
296 | * here at all: Port 2 routing (EHCI or UDC) must be set either | ||
297 | * by boot firmware or platform init code; I can't autodetect | ||
298 | * a sane setting. | ||
299 | */ | ||
300 | __raw_writel(0, base + USB_INT_ENABLE); /* disable all USB irqs */ | ||
301 | wmb(); | ||
302 | __raw_writel(0, base + USB_DWC_CTRL3); /* disable all clocks */ | ||
303 | wmb(); | ||
304 | __raw_writel(~0, base + USB_MSR_ERR); /* clear all errors */ | ||
305 | wmb(); | ||
306 | __raw_writel(~0, base + USB_INT_STATUS); /* clear int status */ | ||
307 | wmb(); | ||
308 | /* set coherent access bit */ | ||
309 | __raw_writel(USB_SBUS_CTRL_SBCA, base + USB_SBUS_CTRL); | ||
310 | wmb(); | ||
311 | } | ||
312 | |||
313 | static inline void __au1200_ohci_control(void __iomem *base, int enable) | ||
314 | { | ||
315 | unsigned long r = __raw_readl(base + AU1200_USBCFG); | ||
316 | if (enable) { | ||
317 | __raw_writel(r | USBCFG_OCE, base + AU1200_USBCFG); | ||
318 | wmb(); | ||
319 | udelay(2000); | ||
320 | } else { | ||
321 | __raw_writel(r & ~USBCFG_OCE, base + AU1200_USBCFG); | ||
322 | wmb(); | ||
323 | udelay(1000); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | static inline void __au1200_ehci_control(void __iomem *base, int enable) | ||
328 | { | ||
329 | unsigned long r = __raw_readl(base + AU1200_USBCFG); | ||
330 | if (enable) { | ||
331 | __raw_writel(r | USBCFG_ECE | USBCFG_PPE, base + AU1200_USBCFG); | ||
332 | wmb(); | ||
333 | udelay(1000); | ||
334 | } else { | ||
335 | if (!(r & USBCFG_UCE)) /* UDC also off? */ | ||
336 | r &= ~USBCFG_PPE; /* yes: disable HS PHY PLL */ | ||
337 | __raw_writel(r & ~USBCFG_ECE, base + AU1200_USBCFG); | ||
338 | wmb(); | ||
339 | udelay(1000); | ||
340 | } | ||
341 | } | ||
342 | |||
343 | static inline void __au1200_udc_control(void __iomem *base, int enable) | ||
344 | { | ||
345 | unsigned long r = __raw_readl(base + AU1200_USBCFG); | ||
346 | if (enable) { | ||
347 | __raw_writel(r | USBCFG_UCE | USBCFG_PPE, base + AU1200_USBCFG); | ||
348 | wmb(); | ||
349 | } else { | ||
350 | if (!(r & USBCFG_ECE)) /* EHCI also off? */ | ||
351 | r &= ~USBCFG_PPE; /* yes: disable HS PHY PLL */ | ||
352 | __raw_writel(r & ~USBCFG_UCE, base + AU1200_USBCFG); | ||
353 | wmb(); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | static inline int au1200_coherency_bug(void) | ||
358 | { | ||
359 | #if defined(CONFIG_DMA_COHERENT) | ||
360 | /* Au1200 AB USB does not support coherent memory */ | ||
361 | if (!(read_c0_prid() & 0xff)) { | ||
362 | printk(KERN_INFO "Au1200 USB: this is chip revision AB !!\n"); | ||
363 | printk(KERN_INFO "Au1200 USB: update your board or re-configure" | ||
364 | " the kernel\n"); | ||
365 | return -ENODEV; | ||
366 | } | ||
367 | #endif | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static inline int au1200_usb_control(int block, int enable) | ||
372 | { | ||
373 | void __iomem *base = | ||
374 | (void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); | ||
375 | int ret = 0; | ||
376 | |||
377 | switch (block) { | ||
378 | case ALCHEMY_USB_OHCI0: | ||
379 | ret = au1200_coherency_bug(); | ||
380 | if (ret && enable) | ||
381 | goto out; | ||
382 | __au1200_ohci_control(base, enable); | ||
383 | break; | ||
384 | case ALCHEMY_USB_UDC0: | ||
385 | __au1200_udc_control(base, enable); | ||
386 | break; | ||
387 | case ALCHEMY_USB_EHCI0: | ||
388 | ret = au1200_coherency_bug(); | ||
389 | if (ret && enable) | ||
390 | goto out; | ||
391 | __au1200_ehci_control(base, enable); | ||
392 | break; | ||
393 | default: | ||
394 | ret = -ENODEV; | ||
395 | } | ||
396 | out: | ||
397 | return ret; | ||
398 | } | ||
399 | |||
400 | |||
401 | /* initialize USB block(s) to a known working state */ | ||
402 | static inline void au1200_usb_init(void) | ||
403 | { | ||
404 | void __iomem *base = | ||
405 | (void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); | ||
406 | __raw_writel(USBCFG_INIT_AU1200, base + AU1200_USBCFG); | ||
407 | wmb(); | ||
408 | udelay(1000); | ||
409 | } | ||
410 | |||
411 | static inline void au1000_usb_init(unsigned long rb, int reg) | ||
412 | { | ||
413 | void __iomem *base = (void __iomem *)KSEG1ADDR(rb + reg); | ||
414 | unsigned long r = __raw_readl(base); | ||
415 | |||
416 | #if defined(__BIG_ENDIAN) | ||
417 | r |= USBHEN_BE; | ||
418 | #endif | ||
419 | r |= USBHEN_C; | ||
420 | |||
421 | __raw_writel(r, base); | ||
422 | wmb(); | ||
423 | udelay(1000); | ||
424 | } | ||
425 | |||
426 | |||
427 | static inline void __au1xx0_ohci_control(int enable, unsigned long rb, int creg) | ||
428 | { | ||
429 | void __iomem *base = (void __iomem *)KSEG1ADDR(rb); | ||
430 | unsigned long r = __raw_readl(base + creg); | ||
431 | |||
432 | if (enable) { | ||
433 | __raw_writel(r | USBHEN_CE, base + creg); | ||
434 | wmb(); | ||
435 | udelay(1000); | ||
436 | __raw_writel(r | USBHEN_CE | USBHEN_E, base + creg); | ||
437 | wmb(); | ||
438 | udelay(1000); | ||
439 | |||
440 | /* wait for reset complete (read reg twice: au1500 erratum) */ | ||
441 | while (__raw_readl(base + creg), | ||
442 | !(__raw_readl(base + creg) & USBHEN_RD)) | ||
443 | udelay(1000); | ||
444 | } else { | ||
445 | __raw_writel(r & ~(USBHEN_CE | USBHEN_E), base + creg); | ||
446 | wmb(); | ||
447 | } | ||
448 | } | ||
449 | |||
450 | static inline int au1000_usb_control(int block, int enable, unsigned long rb, | ||
451 | int creg) | ||
452 | { | ||
453 | int ret = 0; | ||
454 | |||
455 | switch (block) { | ||
456 | case ALCHEMY_USB_OHCI0: | ||
457 | __au1xx0_ohci_control(enable, rb, creg); | ||
458 | break; | ||
459 | default: | ||
460 | ret = -ENODEV; | ||
461 | } | ||
462 | return ret; | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | * alchemy_usb_control - control Alchemy on-chip USB blocks | ||
467 | * @block: USB block to target | ||
468 | * @enable: set 1 to enable a block, 0 to disable | ||
469 | */ | ||
470 | int alchemy_usb_control(int block, int enable) | ||
471 | { | ||
472 | unsigned long flags; | ||
473 | int ret; | ||
474 | |||
475 | spin_lock_irqsave(&alchemy_usb_lock, flags); | ||
476 | switch (alchemy_get_cputype()) { | ||
477 | case ALCHEMY_CPU_AU1000: | ||
478 | case ALCHEMY_CPU_AU1500: | ||
479 | case ALCHEMY_CPU_AU1100: | ||
480 | ret = au1000_usb_control(block, enable, | ||
481 | AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); | ||
482 | break; | ||
483 | case ALCHEMY_CPU_AU1550: | ||
484 | ret = au1000_usb_control(block, enable, | ||
485 | AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); | ||
486 | break; | ||
487 | case ALCHEMY_CPU_AU1200: | ||
488 | ret = au1200_usb_control(block, enable); | ||
489 | break; | ||
490 | case ALCHEMY_CPU_AU1300: | ||
491 | ret = au1300_usb_control(block, enable); | ||
492 | break; | ||
493 | default: | ||
494 | ret = -ENODEV; | ||
495 | } | ||
496 | spin_unlock_irqrestore(&alchemy_usb_lock, flags); | ||
497 | return ret; | ||
498 | } | ||
499 | EXPORT_SYMBOL_GPL(alchemy_usb_control); | ||
500 | |||
501 | |||
502 | static unsigned long alchemy_usb_pmdata[2]; | ||
503 | |||
504 | static void au1000_usb_pm(unsigned long br, int creg, int susp) | ||
505 | { | ||
506 | void __iomem *base = (void __iomem *)KSEG1ADDR(br); | ||
507 | |||
508 | if (susp) { | ||
509 | alchemy_usb_pmdata[0] = __raw_readl(base + creg); | ||
510 | /* There appears to be some undocumented reset register.... */ | ||
511 | __raw_writel(0, base + 0x04); | ||
512 | wmb(); | ||
513 | __raw_writel(0, base + creg); | ||
514 | wmb(); | ||
515 | } else { | ||
516 | __raw_writel(alchemy_usb_pmdata[0], base + creg); | ||
517 | wmb(); | ||
518 | } | ||
519 | } | ||
520 | |||
521 | static void au1200_usb_pm(int susp) | ||
522 | { | ||
523 | void __iomem *base = | ||
524 | (void __iomem *)KSEG1ADDR(AU1200_USB_OTG_PHYS_ADDR); | ||
525 | if (susp) { | ||
526 | /* save OTG_CAP/MUX registers which indicate port routing */ | ||
527 | /* FIXME: write an OTG driver to do that */ | ||
528 | alchemy_usb_pmdata[0] = __raw_readl(base + 0x00); | ||
529 | alchemy_usb_pmdata[1] = __raw_readl(base + 0x04); | ||
530 | } else { | ||
531 | /* restore access to all MMIO areas */ | ||
532 | au1200_usb_init(); | ||
533 | |||
534 | /* restore OTG_CAP/MUX registers */ | ||
535 | __raw_writel(alchemy_usb_pmdata[0], base + 0x00); | ||
536 | __raw_writel(alchemy_usb_pmdata[1], base + 0x04); | ||
537 | wmb(); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | static void au1300_usb_pm(int susp) | ||
542 | { | ||
543 | void __iomem *base = | ||
544 | (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); | ||
545 | /* remember Port2 routing */ | ||
546 | if (susp) { | ||
547 | alchemy_usb_pmdata[0] = __raw_readl(base + USB_DWC_CTRL4); | ||
548 | } else { | ||
549 | au1300_usb_init(); | ||
550 | __raw_writel(alchemy_usb_pmdata[0], base + USB_DWC_CTRL4); | ||
551 | wmb(); | ||
552 | } | ||
553 | } | ||
554 | |||
555 | static void alchemy_usb_pm(int susp) | ||
556 | { | ||
557 | switch (alchemy_get_cputype()) { | ||
558 | case ALCHEMY_CPU_AU1000: | ||
559 | case ALCHEMY_CPU_AU1500: | ||
560 | case ALCHEMY_CPU_AU1100: | ||
561 | au1000_usb_pm(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG, susp); | ||
562 | break; | ||
563 | case ALCHEMY_CPU_AU1550: | ||
564 | au1000_usb_pm(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG, susp); | ||
565 | break; | ||
566 | case ALCHEMY_CPU_AU1200: | ||
567 | au1200_usb_pm(susp); | ||
568 | break; | ||
569 | case ALCHEMY_CPU_AU1300: | ||
570 | au1300_usb_pm(susp); | ||
571 | break; | ||
572 | } | ||
573 | } | ||
574 | |||
575 | static int alchemy_usb_suspend(void) | ||
576 | { | ||
577 | alchemy_usb_pm(1); | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | static void alchemy_usb_resume(void) | ||
582 | { | ||
583 | alchemy_usb_pm(0); | ||
584 | } | ||
585 | |||
586 | static struct syscore_ops alchemy_usb_pm_ops = { | ||
587 | .suspend = alchemy_usb_suspend, | ||
588 | .resume = alchemy_usb_resume, | ||
589 | }; | ||
590 | |||
591 | static int __init alchemy_usb_init(void) | ||
592 | { | ||
593 | switch (alchemy_get_cputype()) { | ||
594 | case ALCHEMY_CPU_AU1000: | ||
595 | case ALCHEMY_CPU_AU1500: | ||
596 | case ALCHEMY_CPU_AU1100: | ||
597 | au1000_usb_init(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); | ||
598 | break; | ||
599 | case ALCHEMY_CPU_AU1550: | ||
600 | au1000_usb_init(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); | ||
601 | break; | ||
602 | case ALCHEMY_CPU_AU1200: | ||
603 | au1200_usb_init(); | ||
604 | break; | ||
605 | case ALCHEMY_CPU_AU1300: | ||
606 | au1300_usb_init(); | ||
607 | break; | ||
608 | } | ||
609 | |||
610 | register_syscore_ops(&alchemy_usb_pm_ops); | ||
611 | |||
612 | return 0; | ||
613 | } | ||
614 | arch_initcall(alchemy_usb_init); | ||