]>
Commit | Line | Data |
---|---|---|
3f467529 WG |
1 | /* |
2 | * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> | |
3 | * Copyright (C) 2010 Freescale Semiconductor, Inc. | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
3f467529 WG |
6 | */ |
7 | ||
8 | #include <common.h> | |
9 | #include <usb.h> | |
10 | #include <errno.h> | |
8c25c259 | 11 | #include <wait_bit.h> |
3f467529 | 12 | #include <linux/compiler.h> |
e162c6b1 | 13 | #include <usb/ehci-ci.h> |
3f467529 WG |
14 | #include <asm/io.h> |
15 | #include <asm/arch/imx-regs.h> | |
16 | #include <asm/arch/clock.h> | |
552a848e SB |
17 | #include <asm/mach-imx/iomux-v3.h> |
18 | #include <asm/mach-imx/sys_proto.h> | |
bb42fb4f | 19 | #include <dm.h> |
c62db35d | 20 | #include <asm/mach-types.h> |
fcf9f9f9 | 21 | #include <power/regulator.h> |
3f467529 WG |
22 | |
23 | #include "ehci.h" | |
3f467529 | 24 | |
cccbddc3 PF |
25 | DECLARE_GLOBAL_DATA_PTR; |
26 | ||
3f467529 WG |
27 | #define USB_OTGREGS_OFFSET 0x000 |
28 | #define USB_H1REGS_OFFSET 0x200 | |
29 | #define USB_H2REGS_OFFSET 0x400 | |
30 | #define USB_H3REGS_OFFSET 0x600 | |
31 | #define USB_OTHERREGS_OFFSET 0x800 | |
32 | ||
33 | #define USB_H1_CTRL_OFFSET 0x04 | |
34 | ||
35 | #define USBPHY_CTRL 0x00000030 | |
36 | #define USBPHY_CTRL_SET 0x00000034 | |
37 | #define USBPHY_CTRL_CLR 0x00000038 | |
38 | #define USBPHY_CTRL_TOG 0x0000003c | |
39 | ||
40 | #define USBPHY_PWD 0x00000000 | |
41 | #define USBPHY_CTRL_SFTRST 0x80000000 | |
42 | #define USBPHY_CTRL_CLKGATE 0x40000000 | |
43 | #define USBPHY_CTRL_ENUTMILEVEL3 0x00008000 | |
44 | #define USBPHY_CTRL_ENUTMILEVEL2 0x00004000 | |
d1a52860 | 45 | #define USBPHY_CTRL_OTG_ID 0x08000000 |
3f467529 | 46 | |
3f467529 WG |
47 | #define ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000 |
48 | #define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000 | |
49 | ||
3f467529 WG |
50 | #define ANADIG_USB2_PLL_480_CTRL_BYPASS 0x00010000 |
51 | #define ANADIG_USB2_PLL_480_CTRL_ENABLE 0x00002000 | |
52 | #define ANADIG_USB2_PLL_480_CTRL_POWER 0x00001000 | |
53 | #define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040 | |
54 | ||
35554fc9 | 55 | #define USBNC_OFFSET 0x200 |
cccbddc3 | 56 | #define USBNC_PHY_STATUS_OFFSET 0x23C |
35554fc9 AA |
57 | #define USBNC_PHYSTATUS_ID_DIG (1 << 4) /* otg_id status */ |
58 | #define USBNC_PHYCFG2_ACAENB (1 << 4) /* otg_id detection enable */ | |
9a88180b | 59 | #define UCTRL_PWR_POL (1 << 9) /* OTG Polarity of Power Pin */ |
3f467529 WG |
60 | #define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */ |
61 | #define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */ | |
62 | ||
63 | /* USBCMD */ | |
3f467529 WG |
64 | #define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ |
65 | #define UCMD_RESET (1 << 1) /* controller reset */ | |
66 | ||
35554fc9 | 67 | #if defined(CONFIG_MX6) |
d1a52860 TK |
68 | static const unsigned phy_bases[] = { |
69 | USB_PHY0_BASE_ADDR, | |
70 | USB_PHY1_BASE_ADDR, | |
71 | }; | |
72 | ||
73 | static void usb_internal_phy_clock_gate(int index, int on) | |
3f467529 | 74 | { |
d1a52860 TK |
75 | void __iomem *phy_reg; |
76 | ||
77 | if (index >= ARRAY_SIZE(phy_bases)) | |
78 | return; | |
3f467529 | 79 | |
d1a52860 | 80 | phy_reg = (void __iomem *)phy_bases[index]; |
3f467529 | 81 | phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET; |
e38ff30a | 82 | writel(USBPHY_CTRL_CLKGATE, phy_reg); |
3f467529 WG |
83 | } |
84 | ||
d1a52860 | 85 | static void usb_power_config(int index) |
3f467529 | 86 | { |
3f29d962 WG |
87 | struct anatop_regs __iomem *anatop = |
88 | (struct anatop_regs __iomem *)ANATOP_BASE_ADDR; | |
d1a52860 TK |
89 | void __iomem *chrg_detect; |
90 | void __iomem *pll_480_ctrl_clr; | |
91 | void __iomem *pll_480_ctrl_set; | |
92 | ||
93 | switch (index) { | |
94 | case 0: | |
95 | chrg_detect = &anatop->usb1_chrg_detect; | |
96 | pll_480_ctrl_clr = &anatop->usb1_pll_480_ctrl_clr; | |
97 | pll_480_ctrl_set = &anatop->usb1_pll_480_ctrl_set; | |
98 | break; | |
99 | case 1: | |
100 | chrg_detect = &anatop->usb2_chrg_detect; | |
101 | pll_480_ctrl_clr = &anatop->usb2_pll_480_ctrl_clr; | |
102 | pll_480_ctrl_set = &anatop->usb2_pll_480_ctrl_set; | |
103 | break; | |
104 | default: | |
105 | return; | |
106 | } | |
3f467529 | 107 | /* |
d1a52860 | 108 | * Some phy and power's special controls |
3f467529 WG |
109 | * 1. The external charger detector needs to be disabled |
110 | * or the signal at DP will be poor | |
d1a52860 | 111 | * 2. The PLL's power and output to usb |
3f467529 WG |
112 | * is totally controlled by IC, so the Software only needs |
113 | * to enable them at initializtion. | |
114 | */ | |
e38ff30a | 115 | writel(ANADIG_USB2_CHRG_DETECT_EN_B | |
3f467529 | 116 | ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B, |
d1a52860 | 117 | chrg_detect); |
3f467529 | 118 | |
e38ff30a | 119 | writel(ANADIG_USB2_PLL_480_CTRL_BYPASS, |
d1a52860 | 120 | pll_480_ctrl_clr); |
3f467529 | 121 | |
e38ff30a | 122 | writel(ANADIG_USB2_PLL_480_CTRL_ENABLE | |
3f467529 WG |
123 | ANADIG_USB2_PLL_480_CTRL_POWER | |
124 | ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS, | |
d1a52860 | 125 | pll_480_ctrl_set); |
3f467529 WG |
126 | } |
127 | ||
d1a52860 TK |
128 | /* Return 0 : host node, <>0 : device mode */ |
129 | static int usb_phy_enable(int index, struct usb_ehci *ehci) | |
3f467529 | 130 | { |
d1a52860 TK |
131 | void __iomem *phy_reg; |
132 | void __iomem *phy_ctrl; | |
133 | void __iomem *usb_cmd; | |
f0c89d54 | 134 | int ret; |
3f467529 | 135 | |
d1a52860 TK |
136 | if (index >= ARRAY_SIZE(phy_bases)) |
137 | return 0; | |
138 | ||
139 | phy_reg = (void __iomem *)phy_bases[index]; | |
140 | phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); | |
141 | usb_cmd = (void __iomem *)&ehci->usbcmd; | |
142 | ||
3f467529 | 143 | /* Stop then Reset */ |
e38ff30a | 144 | clrbits_le32(usb_cmd, UCMD_RUN_STOP); |
8c25c259 MK |
145 | ret = wait_for_bit(__func__, usb_cmd, UCMD_RUN_STOP, false, 10000, |
146 | false); | |
f0c89d54 AA |
147 | if (ret) |
148 | return ret; | |
3f467529 | 149 | |
e38ff30a | 150 | setbits_le32(usb_cmd, UCMD_RESET); |
8c25c259 | 151 | ret = wait_for_bit(__func__, usb_cmd, UCMD_RESET, false, 10000, false); |
f0c89d54 AA |
152 | if (ret) |
153 | return ret; | |
3f467529 WG |
154 | |
155 | /* Reset USBPHY module */ | |
e38ff30a | 156 | setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST); |
3f467529 WG |
157 | udelay(10); |
158 | ||
159 | /* Remove CLKGATE and SFTRST */ | |
e38ff30a | 160 | clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST); |
3f467529 WG |
161 | udelay(10); |
162 | ||
163 | /* Power up the PHY */ | |
e38ff30a | 164 | writel(0, phy_reg + USBPHY_PWD); |
3f467529 | 165 | /* enable FS/LS device */ |
e38ff30a AA |
166 | setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 | |
167 | USBPHY_CTRL_ENUTMILEVEL3); | |
3f467529 | 168 | |
229dbba9 | 169 | return 0; |
3f467529 WG |
170 | } |
171 | ||
35554fc9 AA |
172 | int usb_phy_mode(int port) |
173 | { | |
174 | void __iomem *phy_reg; | |
175 | void __iomem *phy_ctrl; | |
176 | u32 val; | |
177 | ||
178 | phy_reg = (void __iomem *)phy_bases[port]; | |
179 | phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); | |
180 | ||
181 | val = readl(phy_ctrl); | |
182 | ||
183 | if (val & USBPHY_CTRL_OTG_ID) | |
184 | return USB_INIT_DEVICE; | |
185 | else | |
186 | return USB_INIT_HOST; | |
187 | } | |
188 | ||
d1a52860 TK |
189 | /* Base address for this IP block is 0x02184800 */ |
190 | struct usbnc_regs { | |
191 | u32 ctrl[4]; /* otg/host1-3 */ | |
192 | u32 uh2_hsic_ctrl; | |
193 | u32 uh3_hsic_ctrl; | |
194 | u32 otg_phy_ctrl_0; | |
195 | u32 uh1_phy_ctrl_0; | |
196 | }; | |
35554fc9 AA |
197 | #elif defined(CONFIG_MX7) |
198 | struct usbnc_regs { | |
199 | u32 ctrl1; | |
200 | u32 ctrl2; | |
201 | u32 reserve1[10]; | |
202 | u32 phy_cfg1; | |
203 | u32 phy_cfg2; | |
429ff447 | 204 | u32 reserve2; |
35554fc9 | 205 | u32 phy_status; |
429ff447 | 206 | u32 reserve3[4]; |
35554fc9 AA |
207 | u32 adp_cfg1; |
208 | u32 adp_cfg2; | |
209 | u32 adp_status; | |
210 | }; | |
211 | ||
212 | static void usb_power_config(int index) | |
213 | { | |
214 | struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + | |
215 | (0x10000 * index) + USBNC_OFFSET); | |
216 | void __iomem *phy_cfg2 = (void __iomem *)(&usbnc->phy_cfg2); | |
9a88180b | 217 | void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl1); |
35554fc9 | 218 | |
57de41e9 PF |
219 | /* |
220 | * Clear the ACAENB to enable usb_otg_id detection, | |
221 | * otherwise it is the ACA detection enabled. | |
222 | */ | |
223 | clrbits_le32(phy_cfg2, USBNC_PHYCFG2_ACAENB); | |
9a88180b SA |
224 | |
225 | /* Set power polarity to high active */ | |
c4483093 | 226 | #ifdef CONFIG_MXC_USB_OTG_HACTIVE |
9a88180b | 227 | setbits_le32(ctrl, UCTRL_PWR_POL); |
c4483093 SA |
228 | #else |
229 | clrbits_le32(ctrl, UCTRL_PWR_POL); | |
230 | #endif | |
35554fc9 AA |
231 | } |
232 | ||
233 | int usb_phy_mode(int port) | |
234 | { | |
235 | struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + | |
236 | (0x10000 * port) + USBNC_OFFSET); | |
237 | void __iomem *status = (void __iomem *)(&usbnc->phy_status); | |
238 | u32 val; | |
239 | ||
240 | val = readl(status); | |
241 | ||
242 | if (val & USBNC_PHYSTATUS_ID_DIG) | |
243 | return USB_INIT_DEVICE; | |
244 | else | |
245 | return USB_INIT_HOST; | |
246 | } | |
247 | #endif | |
d1a52860 TK |
248 | |
249 | static void usb_oc_config(int index) | |
3f467529 | 250 | { |
35554fc9 | 251 | #if defined(CONFIG_MX6) |
5546ad07 | 252 | struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + |
d1a52860 TK |
253 | USB_OTHERREGS_OFFSET); |
254 | void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]); | |
35554fc9 AA |
255 | #elif defined(CONFIG_MX7) |
256 | struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + | |
257 | (0x10000 * index) + USBNC_OFFSET); | |
258 | void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl1); | |
259 | #endif | |
3f467529 | 260 | |
3f467529 WG |
261 | #if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2 |
262 | /* mx6qarm2 seems to required a different setting*/ | |
e38ff30a | 263 | clrbits_le32(ctrl, UCTRL_OVER_CUR_POL); |
3f467529 | 264 | #else |
e38ff30a | 265 | setbits_le32(ctrl, UCTRL_OVER_CUR_POL); |
3f467529 | 266 | #endif |
3f467529 | 267 | |
e38ff30a | 268 | setbits_le32(ctrl, UCTRL_OVER_CUR_DIS); |
229dbba9 PF |
269 | } |
270 | ||
74f0610e | 271 | /** |
79d867c2 | 272 | * board_usb_phy_mode - override usb phy mode |
74f0610e AA |
273 | * @port: usb host/otg port |
274 | * | |
275 | * Target board specific, override usb_phy_mode. | |
276 | * When usb-otg is used as usb host port, iomux pad usb_otg_id can be | |
277 | * left disconnected in this case usb_phy_mode will not be able to identify | |
278 | * the phy mode that usb port is used. | |
279 | * Machine file overrides board_usb_phy_mode. | |
280 | * | |
281 | * Return: USB_INIT_DEVICE or USB_INIT_HOST | |
282 | */ | |
229dbba9 PF |
283 | int __weak board_usb_phy_mode(int port) |
284 | { | |
285 | return usb_phy_mode(port); | |
286 | } | |
287 | ||
74f0610e AA |
288 | /** |
289 | * board_ehci_hcd_init - set usb vbus voltage | |
290 | * @port: usb otg port | |
291 | * | |
292 | * Target board specific, setup iomux pad to setup supply vbus voltage | |
293 | * for usb otg port. Machine board file overrides board_ehci_hcd_init | |
294 | * | |
295 | * Return: 0 Success | |
296 | */ | |
f22e4fae BT |
297 | int __weak board_ehci_hcd_init(int port) |
298 | { | |
299 | return 0; | |
300 | } | |
301 | ||
74f0610e AA |
302 | /** |
303 | * board_ehci_power - enables/disables usb vbus voltage | |
304 | * @port: usb otg port | |
305 | * @on: on/off vbus voltage | |
306 | * | |
307 | * Enables/disables supply vbus voltage for usb otg port. | |
308 | * Machine board file overrides board_ehci_power | |
309 | * | |
310 | * Return: 0 Success | |
311 | */ | |
d1a52860 TK |
312 | int __weak board_ehci_power(int port, int on) |
313 | { | |
314 | return 0; | |
315 | } | |
316 | ||
bb42fb4f PF |
317 | int ehci_mx6_common_init(struct usb_ehci *ehci, int index) |
318 | { | |
319 | int ret; | |
320 | ||
321 | enable_usboh3_clk(1); | |
322 | mdelay(1); | |
323 | ||
324 | /* Do board specific initialization */ | |
325 | ret = board_ehci_hcd_init(index); | |
326 | if (ret) | |
327 | return ret; | |
328 | ||
329 | usb_power_config(index); | |
330 | usb_oc_config(index); | |
331 | ||
332 | #if defined(CONFIG_MX6) | |
333 | usb_internal_phy_clock_gate(index, 1); | |
334 | usb_phy_enable(index, ehci); | |
335 | #endif | |
336 | ||
337 | return 0; | |
338 | } | |
339 | ||
340 | #ifndef CONFIG_DM_USB | |
127efc4f TK |
341 | int ehci_hcd_init(int index, enum usb_init_type init, |
342 | struct ehci_hccr **hccr, struct ehci_hcor **hcor) | |
3f467529 | 343 | { |
d1a52860 | 344 | enum usb_init_type type; |
35554fc9 AA |
345 | #if defined(CONFIG_MX6) |
346 | u32 controller_spacing = 0x200; | |
347 | #elif defined(CONFIG_MX7) | |
348 | u32 controller_spacing = 0x10000; | |
349 | #endif | |
5546ad07 | 350 | struct usb_ehci *ehci = (struct usb_ehci *)(USB_BASE_ADDR + |
35554fc9 | 351 | (controller_spacing * index)); |
79d867c2 | 352 | int ret; |
3f467529 | 353 | |
d1a52860 TK |
354 | if (index > 3) |
355 | return -EINVAL; | |
3f467529 | 356 | |
bb42fb4f | 357 | ret = ehci_mx6_common_init(ehci, index); |
79d867c2 SA |
358 | if (ret) |
359 | return ret; | |
d1a52860 | 360 | |
229dbba9 | 361 | type = board_usb_phy_mode(index); |
3f467529 | 362 | |
bb42fb4f PF |
363 | if (hccr && hcor) { |
364 | *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); | |
365 | *hcor = (struct ehci_hcor *)((uint32_t)*hccr + | |
366 | HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); | |
367 | } | |
3f467529 | 368 | |
d1a52860 TK |
369 | if ((type == init) || (type == USB_INIT_DEVICE)) |
370 | board_ehci_power(index, (type == USB_INIT_DEVICE) ? 0 : 1); | |
371 | if (type != init) | |
372 | return -ENODEV; | |
373 | if (type == USB_INIT_DEVICE) | |
374 | return 0; | |
35554fc9 | 375 | |
d1a52860 | 376 | setbits_le32(&ehci->usbmode, CM_HOST); |
e38ff30a | 377 | writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); |
3f467529 WG |
378 | setbits_le32(&ehci->portsc, USB_EN); |
379 | ||
380 | mdelay(10); | |
381 | ||
382 | return 0; | |
383 | } | |
384 | ||
676ae068 | 385 | int ehci_hcd_stop(int index) |
3f467529 WG |
386 | { |
387 | return 0; | |
388 | } | |
bb42fb4f PF |
389 | #else |
390 | struct ehci_mx6_priv_data { | |
391 | struct ehci_ctrl ctrl; | |
392 | struct usb_ehci *ehci; | |
fcf9f9f9 | 393 | struct udevice *vbus_supply; |
bb42fb4f PF |
394 | enum usb_init_type init_type; |
395 | int portnr; | |
396 | }; | |
397 | ||
398 | static int mx6_init_after_reset(struct ehci_ctrl *dev) | |
399 | { | |
400 | struct ehci_mx6_priv_data *priv = dev->priv; | |
401 | enum usb_init_type type = priv->init_type; | |
402 | struct usb_ehci *ehci = priv->ehci; | |
403 | int ret; | |
404 | ||
405 | ret = ehci_mx6_common_init(priv->ehci, priv->portnr); | |
406 | if (ret) | |
407 | return ret; | |
408 | ||
fcf9f9f9 PF |
409 | if (priv->vbus_supply) { |
410 | ret = regulator_set_enable(priv->vbus_supply, | |
411 | (type == USB_INIT_DEVICE) ? | |
412 | false : true); | |
413 | if (ret) { | |
414 | puts("Error enabling VBUS supply\n"); | |
415 | return ret; | |
416 | } | |
417 | } | |
bb42fb4f PF |
418 | |
419 | if (type == USB_INIT_DEVICE) | |
420 | return 0; | |
421 | ||
422 | setbits_le32(&ehci->usbmode, CM_HOST); | |
423 | writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); | |
424 | setbits_le32(&ehci->portsc, USB_EN); | |
425 | ||
426 | mdelay(10); | |
427 | ||
428 | return 0; | |
429 | } | |
430 | ||
431 | static const struct ehci_ops mx6_ehci_ops = { | |
432 | .init_after_reset = mx6_init_after_reset | |
433 | }; | |
434 | ||
cccbddc3 PF |
435 | static int ehci_usb_phy_mode(struct udevice *dev) |
436 | { | |
437 | struct usb_platdata *plat = dev_get_platdata(dev); | |
a821c4af | 438 | void *__iomem addr = (void *__iomem)devfdt_get_addr(dev); |
cccbddc3 PF |
439 | void *__iomem phy_ctrl, *__iomem phy_status; |
440 | const void *blob = gd->fdt_blob; | |
e160f7d4 | 441 | int offset = dev_of_offset(dev), phy_off; |
cccbddc3 PF |
442 | u32 val; |
443 | ||
444 | /* | |
445 | * About fsl,usbphy, Refer to | |
446 | * Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt. | |
447 | */ | |
448 | if (is_mx6()) { | |
449 | phy_off = fdtdec_lookup_phandle(blob, | |
450 | offset, | |
451 | "fsl,usbphy"); | |
452 | if (phy_off < 0) | |
453 | return -EINVAL; | |
454 | ||
455 | addr = (void __iomem *)fdtdec_get_addr(blob, phy_off, | |
456 | "reg"); | |
457 | if ((fdt_addr_t)addr == FDT_ADDR_T_NONE) | |
458 | return -EINVAL; | |
459 | ||
460 | phy_ctrl = (void __iomem *)(addr + USBPHY_CTRL); | |
461 | val = readl(phy_ctrl); | |
462 | ||
463 | if (val & USBPHY_CTRL_OTG_ID) | |
464 | plat->init_type = USB_INIT_DEVICE; | |
465 | else | |
466 | plat->init_type = USB_INIT_HOST; | |
467 | } else if (is_mx7()) { | |
468 | phy_status = (void __iomem *)(addr + | |
469 | USBNC_PHY_STATUS_OFFSET); | |
470 | val = readl(phy_status); | |
471 | ||
472 | if (val & USBNC_PHYSTATUS_ID_DIG) | |
473 | plat->init_type = USB_INIT_DEVICE; | |
474 | else | |
475 | plat->init_type = USB_INIT_HOST; | |
476 | } else { | |
477 | return -EINVAL; | |
478 | } | |
479 | ||
480 | return 0; | |
481 | } | |
482 | ||
483 | static int ehci_usb_ofdata_to_platdata(struct udevice *dev) | |
484 | { | |
485 | struct usb_platdata *plat = dev_get_platdata(dev); | |
486 | const char *mode; | |
487 | ||
e160f7d4 | 488 | mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "dr_mode", NULL); |
cccbddc3 PF |
489 | if (mode) { |
490 | if (strcmp(mode, "peripheral") == 0) | |
491 | plat->init_type = USB_INIT_DEVICE; | |
492 | else if (strcmp(mode, "host") == 0) | |
493 | plat->init_type = USB_INIT_HOST; | |
494 | else if (strcmp(mode, "otg") == 0) | |
495 | return ehci_usb_phy_mode(dev); | |
496 | else | |
497 | return -EINVAL; | |
498 | ||
499 | return 0; | |
500 | } | |
501 | ||
502 | return ehci_usb_phy_mode(dev); | |
503 | } | |
504 | ||
bb42fb4f PF |
505 | static int ehci_usb_probe(struct udevice *dev) |
506 | { | |
507 | struct usb_platdata *plat = dev_get_platdata(dev); | |
a821c4af | 508 | struct usb_ehci *ehci = (struct usb_ehci *)devfdt_get_addr(dev); |
bb42fb4f | 509 | struct ehci_mx6_priv_data *priv = dev_get_priv(dev); |
fcf9f9f9 | 510 | enum usb_init_type type = plat->init_type; |
bb42fb4f PF |
511 | struct ehci_hccr *hccr; |
512 | struct ehci_hcor *hcor; | |
513 | int ret; | |
514 | ||
515 | priv->ehci = ehci; | |
516 | priv->portnr = dev->seq; | |
fcf9f9f9 PF |
517 | priv->init_type = type; |
518 | ||
519 | ret = device_get_supply_regulator(dev, "vbus-supply", | |
520 | &priv->vbus_supply); | |
521 | if (ret) | |
522 | debug("%s: No vbus supply\n", dev->name); | |
bb42fb4f PF |
523 | |
524 | ret = ehci_mx6_common_init(ehci, priv->portnr); | |
525 | if (ret) | |
526 | return ret; | |
527 | ||
fcf9f9f9 PF |
528 | if (priv->vbus_supply) { |
529 | ret = regulator_set_enable(priv->vbus_supply, | |
530 | (type == USB_INIT_DEVICE) ? | |
531 | false : true); | |
532 | if (ret) { | |
533 | puts("Error enabling VBUS supply\n"); | |
534 | return ret; | |
535 | } | |
536 | } | |
bb42fb4f PF |
537 | |
538 | if (priv->init_type == USB_INIT_HOST) { | |
539 | setbits_le32(&ehci->usbmode, CM_HOST); | |
540 | writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); | |
541 | setbits_le32(&ehci->portsc, USB_EN); | |
542 | } | |
543 | ||
544 | mdelay(10); | |
545 | ||
546 | hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); | |
547 | hcor = (struct ehci_hcor *)((uint32_t)hccr + | |
548 | HC_LENGTH(ehci_readl(&(hccr)->cr_capbase))); | |
549 | ||
550 | return ehci_register(dev, hccr, hcor, &mx6_ehci_ops, 0, priv->init_type); | |
551 | } | |
552 | ||
bb42fb4f PF |
553 | static const struct udevice_id mx6_usb_ids[] = { |
554 | { .compatible = "fsl,imx27-usb" }, | |
555 | { } | |
556 | }; | |
557 | ||
558 | U_BOOT_DRIVER(usb_mx6) = { | |
559 | .name = "ehci_mx6", | |
560 | .id = UCLASS_USB, | |
561 | .of_match = mx6_usb_ids, | |
cccbddc3 | 562 | .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, |
bb42fb4f | 563 | .probe = ehci_usb_probe, |
40527342 | 564 | .remove = ehci_deregister, |
bb42fb4f PF |
565 | .ops = &ehci_usb_ops, |
566 | .platdata_auto_alloc_size = sizeof(struct usb_platdata), | |
567 | .priv_auto_alloc_size = sizeof(struct ehci_mx6_priv_data), | |
568 | .flags = DM_FLAG_ALLOC_PRIV_DMA, | |
569 | }; | |
570 | #endif |