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