]>
Commit | Line | Data |
---|---|---|
7e98aa46 GJ |
1 | /* |
2 | * Atheros AR7XXX/AR9XXX USB Host Controller device | |
3 | * | |
4 | * Copyright (C) 2008-2011 Gabor Juhos <[email protected]> | |
5 | * Copyright (C) 2008 Imre Kaloz <[email protected]> | |
6 | * | |
7 | * Parts of this file are based on Atheros' 2.6.15 BSP | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License version 2 as published | |
11 | * by the Free Software Foundation. | |
12 | */ | |
13 | ||
14 | #include <linux/kernel.h> | |
15 | #include <linux/init.h> | |
16 | #include <linux/delay.h> | |
17 | #include <linux/irq.h> | |
18 | #include <linux/dma-mapping.h> | |
19 | #include <linux/platform_device.h> | |
5d98cd4e HM |
20 | #include <linux/usb/ehci_pdriver.h> |
21 | #include <linux/usb/ohci_pdriver.h> | |
7e98aa46 GJ |
22 | |
23 | #include <asm/mach-ath79/ath79.h> | |
24 | #include <asm/mach-ath79/ar71xx_regs.h> | |
25 | #include "common.h" | |
26 | #include "dev-usb.h" | |
27 | ||
90a938d1 | 28 | static u64 ath79_usb_dmamask = DMA_BIT_MASK(32); |
5d98cd4e HM |
29 | |
30 | static struct usb_ohci_pdata ath79_ohci_pdata = { | |
31 | }; | |
32 | ||
5d98cd4e HM |
33 | static struct usb_ehci_pdata ath79_ehci_pdata_v1 = { |
34 | .has_synopsys_hc_bug = 1, | |
5d98cd4e HM |
35 | }; |
36 | ||
37 | static struct usb_ehci_pdata ath79_ehci_pdata_v2 = { | |
38 | .caps_offset = 0x100, | |
39 | .has_tt = 1, | |
5d98cd4e HM |
40 | }; |
41 | ||
90a938d1 GJ |
42 | static void __init ath79_usb_register(const char *name, int id, |
43 | unsigned long base, unsigned long size, | |
44 | int irq, const void *data, | |
45 | size_t data_size) | |
8d3e03e1 | 46 | { |
90a938d1 GJ |
47 | struct resource res[2]; |
48 | struct platform_device *pdev; | |
49 | ||
50 | memset(res, 0, sizeof(res)); | |
51 | ||
8d3e03e1 GJ |
52 | res[0].flags = IORESOURCE_MEM; |
53 | res[0].start = base; | |
54 | res[0].end = base + size - 1; | |
55 | ||
56 | res[1].flags = IORESOURCE_IRQ; | |
57 | res[1].start = irq; | |
58 | res[1].end = irq; | |
90a938d1 GJ |
59 | |
60 | pdev = platform_device_register_resndata(NULL, name, id, | |
61 | res, ARRAY_SIZE(res), | |
62 | data, data_size); | |
63 | ||
64 | if (IS_ERR(pdev)) { | |
65 | pr_err("ath79: unable to register USB at %08lx, err=%d\n", | |
66 | base, (int) PTR_ERR(pdev)); | |
67 | return; | |
68 | } | |
69 | ||
70 | pdev->dev.dma_mask = &ath79_usb_dmamask; | |
71 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | |
8d3e03e1 GJ |
72 | } |
73 | ||
7e98aa46 GJ |
74 | #define AR71XX_USB_RESET_MASK (AR71XX_RESET_USB_HOST | \ |
75 | AR71XX_RESET_USB_PHY | \ | |
76 | AR71XX_RESET_USB_OHCI_DLL) | |
77 | ||
78 | static void __init ath79_usb_setup(void) | |
79 | { | |
80 | void __iomem *usb_ctrl_base; | |
81 | ||
82 | ath79_device_reset_set(AR71XX_USB_RESET_MASK); | |
83 | mdelay(1000); | |
84 | ath79_device_reset_clear(AR71XX_USB_RESET_MASK); | |
85 | ||
86 | usb_ctrl_base = ioremap(AR71XX_USB_CTRL_BASE, AR71XX_USB_CTRL_SIZE); | |
87 | ||
88 | /* Turning on the Buff and Desc swap bits */ | |
89 | __raw_writel(0xf0000, usb_ctrl_base + AR71XX_USB_CTRL_REG_CONFIG); | |
90 | ||
91 | /* WAR for HW bug. Here it adjusts the duration between two SOFS */ | |
92 | __raw_writel(0x20c00, usb_ctrl_base + AR71XX_USB_CTRL_REG_FLADJ); | |
93 | ||
94 | iounmap(usb_ctrl_base); | |
95 | ||
96 | mdelay(900); | |
97 | ||
90a938d1 GJ |
98 | ath79_usb_register("ohci-platform", -1, |
99 | AR71XX_OHCI_BASE, AR71XX_OHCI_SIZE, | |
100 | ATH79_MISC_IRQ(6), | |
101 | &ath79_ohci_pdata, sizeof(ath79_ohci_pdata)); | |
7e98aa46 | 102 | |
90a938d1 GJ |
103 | ath79_usb_register("ehci-platform", -1, |
104 | AR71XX_EHCI_BASE, AR71XX_EHCI_SIZE, | |
105 | ATH79_CPU_IRQ(3), | |
106 | &ath79_ehci_pdata_v1, sizeof(ath79_ehci_pdata_v1)); | |
7e98aa46 GJ |
107 | } |
108 | ||
109 | static void __init ar7240_usb_setup(void) | |
110 | { | |
111 | void __iomem *usb_ctrl_base; | |
112 | ||
113 | ath79_device_reset_clear(AR7240_RESET_OHCI_DLL); | |
114 | ath79_device_reset_set(AR7240_RESET_USB_HOST); | |
115 | ||
116 | mdelay(1000); | |
117 | ||
118 | ath79_device_reset_set(AR7240_RESET_OHCI_DLL); | |
119 | ath79_device_reset_clear(AR7240_RESET_USB_HOST); | |
120 | ||
121 | usb_ctrl_base = ioremap(AR7240_USB_CTRL_BASE, AR7240_USB_CTRL_SIZE); | |
122 | ||
123 | /* WAR for HW bug. Here it adjusts the duration between two SOFS */ | |
124 | __raw_writel(0x3, usb_ctrl_base + AR71XX_USB_CTRL_REG_FLADJ); | |
125 | ||
126 | iounmap(usb_ctrl_base); | |
127 | ||
90a938d1 GJ |
128 | ath79_usb_register("ohci-platform", -1, |
129 | AR7240_OHCI_BASE, AR7240_OHCI_SIZE, | |
130 | ATH79_CPU_IRQ(3), | |
131 | &ath79_ohci_pdata, sizeof(ath79_ohci_pdata)); | |
7e98aa46 GJ |
132 | } |
133 | ||
134 | static void __init ar724x_usb_setup(void) | |
135 | { | |
136 | ath79_device_reset_set(AR724X_RESET_USBSUS_OVERRIDE); | |
137 | mdelay(10); | |
138 | ||
139 | ath79_device_reset_clear(AR724X_RESET_USB_HOST); | |
140 | mdelay(10); | |
141 | ||
142 | ath79_device_reset_clear(AR724X_RESET_USB_PHY); | |
143 | mdelay(10); | |
144 | ||
90a938d1 GJ |
145 | ath79_usb_register("ehci-platform", -1, |
146 | AR724X_EHCI_BASE, AR724X_EHCI_SIZE, | |
147 | ATH79_CPU_IRQ(3), | |
148 | &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); | |
7e98aa46 GJ |
149 | } |
150 | ||
151 | static void __init ar913x_usb_setup(void) | |
152 | { | |
153 | ath79_device_reset_set(AR913X_RESET_USBSUS_OVERRIDE); | |
154 | mdelay(10); | |
155 | ||
156 | ath79_device_reset_clear(AR913X_RESET_USB_HOST); | |
157 | mdelay(10); | |
158 | ||
159 | ath79_device_reset_clear(AR913X_RESET_USB_PHY); | |
160 | mdelay(10); | |
161 | ||
90a938d1 GJ |
162 | ath79_usb_register("ehci-platform", -1, |
163 | AR913X_EHCI_BASE, AR913X_EHCI_SIZE, | |
164 | ATH79_CPU_IRQ(3), | |
165 | &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); | |
7e98aa46 GJ |
166 | } |
167 | ||
c279b775 GJ |
168 | static void __init ar933x_usb_setup(void) |
169 | { | |
170 | ath79_device_reset_set(AR933X_RESET_USBSUS_OVERRIDE); | |
171 | mdelay(10); | |
172 | ||
173 | ath79_device_reset_clear(AR933X_RESET_USB_HOST); | |
174 | mdelay(10); | |
175 | ||
176 | ath79_device_reset_clear(AR933X_RESET_USB_PHY); | |
177 | mdelay(10); | |
178 | ||
90a938d1 GJ |
179 | ath79_usb_register("ehci-platform", -1, |
180 | AR933X_EHCI_BASE, AR933X_EHCI_SIZE, | |
181 | ATH79_CPU_IRQ(3), | |
182 | &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); | |
c279b775 GJ |
183 | } |
184 | ||
00ffed58 GJ |
185 | static void __init ar934x_usb_setup(void) |
186 | { | |
187 | u32 bootstrap; | |
188 | ||
189 | bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); | |
190 | if (bootstrap & AR934X_BOOTSTRAP_USB_MODE_DEVICE) | |
191 | return; | |
192 | ||
193 | ath79_device_reset_set(AR934X_RESET_USBSUS_OVERRIDE); | |
194 | udelay(1000); | |
195 | ||
196 | ath79_device_reset_clear(AR934X_RESET_USB_PHY); | |
197 | udelay(1000); | |
198 | ||
199 | ath79_device_reset_clear(AR934X_RESET_USB_PHY_ANALOG); | |
200 | udelay(1000); | |
201 | ||
202 | ath79_device_reset_clear(AR934X_RESET_USB_HOST); | |
203 | udelay(1000); | |
204 | ||
90a938d1 GJ |
205 | ath79_usb_register("ehci-platform", -1, |
206 | AR934X_EHCI_BASE, AR934X_EHCI_SIZE, | |
207 | ATH79_CPU_IRQ(3), | |
208 | &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); | |
00ffed58 GJ |
209 | } |
210 | ||
82c46840 GJ |
211 | static void __init qca955x_usb_setup(void) |
212 | { | |
213 | ath79_usb_register("ehci-platform", 0, | |
214 | QCA955X_EHCI0_BASE, QCA955X_EHCI_SIZE, | |
215 | ATH79_IP3_IRQ(0), | |
216 | &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); | |
217 | ||
218 | ath79_usb_register("ehci-platform", 1, | |
219 | QCA955X_EHCI1_BASE, QCA955X_EHCI_SIZE, | |
220 | ATH79_IP3_IRQ(1), | |
221 | &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); | |
222 | } | |
223 | ||
7e98aa46 GJ |
224 | void __init ath79_register_usb(void) |
225 | { | |
226 | if (soc_is_ar71xx()) | |
227 | ath79_usb_setup(); | |
228 | else if (soc_is_ar7240()) | |
229 | ar7240_usb_setup(); | |
230 | else if (soc_is_ar7241() || soc_is_ar7242()) | |
231 | ar724x_usb_setup(); | |
232 | else if (soc_is_ar913x()) | |
233 | ar913x_usb_setup(); | |
c279b775 GJ |
234 | else if (soc_is_ar933x()) |
235 | ar933x_usb_setup(); | |
00ffed58 GJ |
236 | else if (soc_is_ar934x()) |
237 | ar934x_usb_setup(); | |
82c46840 GJ |
238 | else if (soc_is_qca955x()) |
239 | qca955x_usb_setup(); | |
7e98aa46 GJ |
240 | else |
241 | BUG(); | |
242 | } |