Commit | Line | Data |
---|---|---|
7e98aa46 GJ |
1 | /* |
2 | * Atheros AR7XXX/AR9XXX USB Host Controller device | |
3 | * | |
4 | * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | |
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | |
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 | ||
8d3e03e1 | 28 | static struct resource ath79_ohci_resources[2]; |
7e98aa46 GJ |
29 | |
30 | static u64 ath79_ohci_dmamask = DMA_BIT_MASK(32); | |
5d98cd4e HM |
31 | |
32 | static struct usb_ohci_pdata ath79_ohci_pdata = { | |
33 | }; | |
34 | ||
7e98aa46 | 35 | static struct platform_device ath79_ohci_device = { |
5d98cd4e | 36 | .name = "ohci-platform", |
7e98aa46 GJ |
37 | .id = -1, |
38 | .resource = ath79_ohci_resources, | |
39 | .num_resources = ARRAY_SIZE(ath79_ohci_resources), | |
40 | .dev = { | |
41 | .dma_mask = &ath79_ohci_dmamask, | |
42 | .coherent_dma_mask = DMA_BIT_MASK(32), | |
5d98cd4e | 43 | .platform_data = &ath79_ohci_pdata, |
7e98aa46 GJ |
44 | }, |
45 | }; | |
46 | ||
8d3e03e1 | 47 | static struct resource ath79_ehci_resources[2]; |
7e98aa46 GJ |
48 | |
49 | static u64 ath79_ehci_dmamask = DMA_BIT_MASK(32); | |
5d98cd4e HM |
50 | |
51 | static struct usb_ehci_pdata ath79_ehci_pdata_v1 = { | |
52 | .has_synopsys_hc_bug = 1, | |
5d98cd4e HM |
53 | }; |
54 | ||
55 | static struct usb_ehci_pdata ath79_ehci_pdata_v2 = { | |
56 | .caps_offset = 0x100, | |
57 | .has_tt = 1, | |
5d98cd4e HM |
58 | }; |
59 | ||
7e98aa46 | 60 | static struct platform_device ath79_ehci_device = { |
5d98cd4e | 61 | .name = "ehci-platform", |
7e98aa46 GJ |
62 | .id = -1, |
63 | .resource = ath79_ehci_resources, | |
64 | .num_resources = ARRAY_SIZE(ath79_ehci_resources), | |
65 | .dev = { | |
66 | .dma_mask = &ath79_ehci_dmamask, | |
67 | .coherent_dma_mask = DMA_BIT_MASK(32), | |
68 | }, | |
69 | }; | |
70 | ||
8d3e03e1 GJ |
71 | static void __init ath79_usb_init_resource(struct resource res[2], |
72 | unsigned long base, | |
73 | unsigned long size, | |
74 | int irq) | |
75 | { | |
76 | res[0].flags = IORESOURCE_MEM; | |
77 | res[0].start = base; | |
78 | res[0].end = base + size - 1; | |
79 | ||
80 | res[1].flags = IORESOURCE_IRQ; | |
81 | res[1].start = irq; | |
82 | res[1].end = irq; | |
83 | } | |
84 | ||
7e98aa46 GJ |
85 | #define AR71XX_USB_RESET_MASK (AR71XX_RESET_USB_HOST | \ |
86 | AR71XX_RESET_USB_PHY | \ | |
87 | AR71XX_RESET_USB_OHCI_DLL) | |
88 | ||
89 | static void __init ath79_usb_setup(void) | |
90 | { | |
91 | void __iomem *usb_ctrl_base; | |
92 | ||
93 | ath79_device_reset_set(AR71XX_USB_RESET_MASK); | |
94 | mdelay(1000); | |
95 | ath79_device_reset_clear(AR71XX_USB_RESET_MASK); | |
96 | ||
97 | usb_ctrl_base = ioremap(AR71XX_USB_CTRL_BASE, AR71XX_USB_CTRL_SIZE); | |
98 | ||
99 | /* Turning on the Buff and Desc swap bits */ | |
100 | __raw_writel(0xf0000, usb_ctrl_base + AR71XX_USB_CTRL_REG_CONFIG); | |
101 | ||
102 | /* WAR for HW bug. Here it adjusts the duration between two SOFS */ | |
103 | __raw_writel(0x20c00, usb_ctrl_base + AR71XX_USB_CTRL_REG_FLADJ); | |
104 | ||
105 | iounmap(usb_ctrl_base); | |
106 | ||
107 | mdelay(900); | |
108 | ||
8d3e03e1 GJ |
109 | ath79_usb_init_resource(ath79_ohci_resources, AR71XX_OHCI_BASE, |
110 | AR71XX_OHCI_SIZE, ATH79_MISC_IRQ_OHCI); | |
7e98aa46 GJ |
111 | platform_device_register(&ath79_ohci_device); |
112 | ||
8d3e03e1 GJ |
113 | ath79_usb_init_resource(ath79_ehci_resources, AR71XX_EHCI_BASE, |
114 | AR71XX_EHCI_SIZE, ATH79_CPU_IRQ_USB); | |
5d98cd4e | 115 | ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v1; |
7e98aa46 GJ |
116 | platform_device_register(&ath79_ehci_device); |
117 | } | |
118 | ||
119 | static void __init ar7240_usb_setup(void) | |
120 | { | |
121 | void __iomem *usb_ctrl_base; | |
122 | ||
123 | ath79_device_reset_clear(AR7240_RESET_OHCI_DLL); | |
124 | ath79_device_reset_set(AR7240_RESET_USB_HOST); | |
125 | ||
126 | mdelay(1000); | |
127 | ||
128 | ath79_device_reset_set(AR7240_RESET_OHCI_DLL); | |
129 | ath79_device_reset_clear(AR7240_RESET_USB_HOST); | |
130 | ||
131 | usb_ctrl_base = ioremap(AR7240_USB_CTRL_BASE, AR7240_USB_CTRL_SIZE); | |
132 | ||
133 | /* WAR for HW bug. Here it adjusts the duration between two SOFS */ | |
134 | __raw_writel(0x3, usb_ctrl_base + AR71XX_USB_CTRL_REG_FLADJ); | |
135 | ||
136 | iounmap(usb_ctrl_base); | |
137 | ||
8d3e03e1 GJ |
138 | ath79_usb_init_resource(ath79_ohci_resources, AR7240_OHCI_BASE, |
139 | AR7240_OHCI_SIZE, ATH79_CPU_IRQ_USB); | |
7e98aa46 GJ |
140 | platform_device_register(&ath79_ohci_device); |
141 | } | |
142 | ||
143 | static void __init ar724x_usb_setup(void) | |
144 | { | |
145 | ath79_device_reset_set(AR724X_RESET_USBSUS_OVERRIDE); | |
146 | mdelay(10); | |
147 | ||
148 | ath79_device_reset_clear(AR724X_RESET_USB_HOST); | |
149 | mdelay(10); | |
150 | ||
151 | ath79_device_reset_clear(AR724X_RESET_USB_PHY); | |
152 | mdelay(10); | |
153 | ||
8d3e03e1 GJ |
154 | ath79_usb_init_resource(ath79_ehci_resources, AR724X_EHCI_BASE, |
155 | AR724X_EHCI_SIZE, ATH79_CPU_IRQ_USB); | |
5d98cd4e | 156 | ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; |
7e98aa46 GJ |
157 | platform_device_register(&ath79_ehci_device); |
158 | } | |
159 | ||
160 | static void __init ar913x_usb_setup(void) | |
161 | { | |
162 | ath79_device_reset_set(AR913X_RESET_USBSUS_OVERRIDE); | |
163 | mdelay(10); | |
164 | ||
165 | ath79_device_reset_clear(AR913X_RESET_USB_HOST); | |
166 | mdelay(10); | |
167 | ||
168 | ath79_device_reset_clear(AR913X_RESET_USB_PHY); | |
169 | mdelay(10); | |
170 | ||
8d3e03e1 GJ |
171 | ath79_usb_init_resource(ath79_ehci_resources, AR913X_EHCI_BASE, |
172 | AR913X_EHCI_SIZE, ATH79_CPU_IRQ_USB); | |
5d98cd4e | 173 | ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; |
7e98aa46 GJ |
174 | platform_device_register(&ath79_ehci_device); |
175 | } | |
176 | ||
c279b775 GJ |
177 | static void __init ar933x_usb_setup(void) |
178 | { | |
179 | ath79_device_reset_set(AR933X_RESET_USBSUS_OVERRIDE); | |
180 | mdelay(10); | |
181 | ||
182 | ath79_device_reset_clear(AR933X_RESET_USB_HOST); | |
183 | mdelay(10); | |
184 | ||
185 | ath79_device_reset_clear(AR933X_RESET_USB_PHY); | |
186 | mdelay(10); | |
187 | ||
8d3e03e1 GJ |
188 | ath79_usb_init_resource(ath79_ehci_resources, AR933X_EHCI_BASE, |
189 | AR933X_EHCI_SIZE, ATH79_CPU_IRQ_USB); | |
5d98cd4e | 190 | ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; |
c279b775 GJ |
191 | platform_device_register(&ath79_ehci_device); |
192 | } | |
193 | ||
00ffed58 GJ |
194 | static void __init ar934x_usb_setup(void) |
195 | { | |
196 | u32 bootstrap; | |
197 | ||
198 | bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); | |
199 | if (bootstrap & AR934X_BOOTSTRAP_USB_MODE_DEVICE) | |
200 | return; | |
201 | ||
202 | ath79_device_reset_set(AR934X_RESET_USBSUS_OVERRIDE); | |
203 | udelay(1000); | |
204 | ||
205 | ath79_device_reset_clear(AR934X_RESET_USB_PHY); | |
206 | udelay(1000); | |
207 | ||
208 | ath79_device_reset_clear(AR934X_RESET_USB_PHY_ANALOG); | |
209 | udelay(1000); | |
210 | ||
211 | ath79_device_reset_clear(AR934X_RESET_USB_HOST); | |
212 | udelay(1000); | |
213 | ||
214 | ath79_usb_init_resource(ath79_ehci_resources, AR934X_EHCI_BASE, | |
215 | AR934X_EHCI_SIZE, ATH79_CPU_IRQ_USB); | |
216 | ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; | |
217 | platform_device_register(&ath79_ehci_device); | |
218 | } | |
219 | ||
7e98aa46 GJ |
220 | void __init ath79_register_usb(void) |
221 | { | |
222 | if (soc_is_ar71xx()) | |
223 | ath79_usb_setup(); | |
224 | else if (soc_is_ar7240()) | |
225 | ar7240_usb_setup(); | |
226 | else if (soc_is_ar7241() || soc_is_ar7242()) | |
227 | ar724x_usb_setup(); | |
228 | else if (soc_is_ar913x()) | |
229 | ar913x_usb_setup(); | |
c279b775 GJ |
230 | else if (soc_is_ar933x()) |
231 | ar933x_usb_setup(); | |
00ffed58 GJ |
232 | else if (soc_is_ar934x()) |
233 | ar934x_usb_setup(); | |
7e98aa46 GJ |
234 | else |
235 | BUG(); | |
236 | } |