]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
a94bb7a4 SM |
2 | /* |
3 | * Copyright (c) 2015 Sanchayan Maity <[email protected]> | |
4 | * Copyright (C) 2015 Toradex AG | |
5 | * | |
6 | * Based on ehci-mx6 driver | |
a94bb7a4 SM |
7 | */ |
8 | ||
9 | #include <common.h> | |
0885cdb9 | 10 | #include <dm.h> |
f7ae49fc | 11 | #include <log.h> |
a94bb7a4 SM |
12 | #include <usb.h> |
13 | #include <errno.h> | |
14 | #include <linux/compiler.h> | |
15 | #include <asm/io.h> | |
0885cdb9 | 16 | #include <asm-generic/gpio.h> |
a94bb7a4 SM |
17 | #include <asm/arch/clock.h> |
18 | #include <asm/arch/imx-regs.h> | |
19 | #include <asm/arch/crm_regs.h> | |
552a848e SB |
20 | #include <asm/mach-imx/iomux-v3.h> |
21 | #include <asm/mach-imx/regs-usbphy.h> | |
c05ed00a | 22 | #include <linux/delay.h> |
e162c6b1 | 23 | #include <usb/ehci-ci.h> |
b08c8c48 | 24 | #include <linux/libfdt.h> |
0885cdb9 | 25 | #include <fdtdec.h> |
a94bb7a4 SM |
26 | |
27 | #include "ehci.h" | |
28 | ||
29 | #define USB_NC_REG_OFFSET 0x00000800 | |
30 | ||
31 | #define ANADIG_PLL_CTRL_EN_USB_CLKS (1 << 6) | |
32 | ||
33 | #define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */ | |
34 | #define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */ | |
35 | ||
36 | /* USBCMD */ | |
37 | #define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ | |
38 | #define UCMD_RESET (1 << 1) /* controller reset */ | |
39 | ||
0885cdb9 SM |
40 | DECLARE_GLOBAL_DATA_PTR; |
41 | ||
a94bb7a4 SM |
42 | static const unsigned phy_bases[] = { |
43 | USB_PHY0_BASE_ADDR, | |
44 | USB_PHY1_BASE_ADDR, | |
45 | }; | |
46 | ||
47 | static const unsigned nc_reg_bases[] = { | |
48 | USBC0_BASE_ADDR, | |
49 | USBC1_BASE_ADDR, | |
50 | }; | |
51 | ||
52 | static void usb_internal_phy_clock_gate(int index) | |
53 | { | |
54 | void __iomem *phy_reg; | |
55 | ||
56 | phy_reg = (void __iomem *)phy_bases[index]; | |
57 | clrbits_le32(phy_reg + USBPHY_CTRL, USBPHY_CTRL_CLKGATE); | |
58 | } | |
59 | ||
60 | static void usb_power_config(int index) | |
61 | { | |
62 | struct anadig_reg __iomem *anadig = | |
63 | (struct anadig_reg __iomem *)ANADIG_BASE_ADDR; | |
64 | void __iomem *pll_ctrl; | |
65 | ||
66 | switch (index) { | |
67 | case 0: | |
68 | pll_ctrl = &anadig->pll3_ctrl; | |
69 | clrbits_le32(pll_ctrl, ANADIG_PLL3_CTRL_BYPASS); | |
70 | setbits_le32(pll_ctrl, ANADIG_PLL3_CTRL_ENABLE | |
71 | | ANADIG_PLL3_CTRL_POWERDOWN | |
72 | | ANADIG_PLL_CTRL_EN_USB_CLKS); | |
73 | break; | |
74 | case 1: | |
75 | pll_ctrl = &anadig->pll7_ctrl; | |
76 | clrbits_le32(pll_ctrl, ANADIG_PLL7_CTRL_BYPASS); | |
77 | setbits_le32(pll_ctrl, ANADIG_PLL7_CTRL_ENABLE | |
78 | | ANADIG_PLL7_CTRL_POWERDOWN | |
79 | | ANADIG_PLL_CTRL_EN_USB_CLKS); | |
80 | break; | |
81 | default: | |
82 | return; | |
83 | } | |
84 | } | |
85 | ||
86 | static void usb_phy_enable(int index, struct usb_ehci *ehci) | |
87 | { | |
88 | void __iomem *phy_reg; | |
89 | void __iomem *phy_ctrl; | |
90 | void __iomem *usb_cmd; | |
91 | ||
92 | phy_reg = (void __iomem *)phy_bases[index]; | |
93 | phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); | |
94 | usb_cmd = (void __iomem *)&ehci->usbcmd; | |
95 | ||
96 | /* Stop then Reset */ | |
97 | clrbits_le32(usb_cmd, UCMD_RUN_STOP); | |
98 | while (readl(usb_cmd) & UCMD_RUN_STOP) | |
99 | ; | |
100 | ||
101 | setbits_le32(usb_cmd, UCMD_RESET); | |
102 | while (readl(usb_cmd) & UCMD_RESET) | |
103 | ; | |
104 | ||
105 | /* Reset USBPHY module */ | |
106 | setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST); | |
107 | udelay(10); | |
108 | ||
109 | /* Remove CLKGATE and SFTRST */ | |
110 | clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST); | |
111 | udelay(10); | |
112 | ||
113 | /* Power up the PHY */ | |
114 | writel(0, phy_reg + USBPHY_PWD); | |
115 | ||
116 | /* Enable FS/LS device */ | |
117 | setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 | | |
118 | USBPHY_CTRL_ENUTMILEVEL3); | |
119 | } | |
120 | ||
121 | static void usb_oc_config(int index) | |
122 | { | |
123 | void __iomem *ctrl; | |
124 | ||
125 | ctrl = (void __iomem *)(nc_reg_bases[index] + USB_NC_REG_OFFSET); | |
126 | ||
127 | setbits_le32(ctrl, UCTRL_OVER_CUR_POL); | |
128 | setbits_le32(ctrl, UCTRL_OVER_CUR_DIS); | |
129 | } | |
130 | ||
08c11cb5 SM |
131 | int __weak board_usb_phy_mode(int port) |
132 | { | |
133 | return 0; | |
134 | } | |
135 | ||
60ed2864 SM |
136 | int __weak board_ehci_hcd_init(int port) |
137 | { | |
138 | return 0; | |
139 | } | |
140 | ||
0885cdb9 SM |
141 | int ehci_vf_common_init(struct usb_ehci *ehci, int index) |
142 | { | |
143 | int ret; | |
144 | ||
145 | /* Do board specific initialisation */ | |
146 | ret = board_ehci_hcd_init(index); | |
147 | if (ret) | |
148 | return ret; | |
149 | ||
150 | usb_power_config(index); | |
151 | usb_oc_config(index); | |
152 | usb_internal_phy_clock_gate(index); | |
153 | usb_phy_enable(index, ehci); | |
154 | ||
155 | return 0; | |
156 | } | |
157 | ||
fd09c205 | 158 | #if !CONFIG_IS_ENABLED(DM_USB) |
a94bb7a4 SM |
159 | int ehci_hcd_init(int index, enum usb_init_type init, |
160 | struct ehci_hccr **hccr, struct ehci_hcor **hcor) | |
161 | { | |
162 | struct usb_ehci *ehci; | |
08c11cb5 | 163 | enum usb_init_type type; |
0885cdb9 | 164 | int ret; |
a94bb7a4 SM |
165 | |
166 | if (index >= ARRAY_SIZE(nc_reg_bases)) | |
167 | return -EINVAL; | |
168 | ||
a94bb7a4 SM |
169 | ehci = (struct usb_ehci *)nc_reg_bases[index]; |
170 | ||
0885cdb9 SM |
171 | ret = ehci_vf_common_init(index); |
172 | if (ret) | |
173 | return ret; | |
a94bb7a4 SM |
174 | |
175 | *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); | |
176 | *hcor = (struct ehci_hcor *)((uint32_t)*hccr + | |
177 | HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); | |
178 | ||
08c11cb5 SM |
179 | type = board_usb_phy_mode(index); |
180 | if (type != init) | |
181 | return -ENODEV; | |
182 | ||
a94bb7a4 SM |
183 | if (init == USB_INIT_DEVICE) { |
184 | setbits_le32(&ehci->usbmode, CM_DEVICE); | |
185 | writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc); | |
186 | setbits_le32(&ehci->portsc, USB_EN); | |
187 | } else if (init == USB_INIT_HOST) { | |
188 | setbits_le32(&ehci->usbmode, CM_HOST); | |
189 | writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc); | |
190 | setbits_le32(&ehci->portsc, USB_EN); | |
191 | } | |
192 | ||
193 | return 0; | |
194 | } | |
195 | ||
196 | int ehci_hcd_stop(int index) | |
197 | { | |
198 | return 0; | |
199 | } | |
0885cdb9 SM |
200 | #else |
201 | /* Possible port types (dual role mode) */ | |
202 | enum dr_mode { | |
203 | DR_MODE_NONE = 0, | |
204 | DR_MODE_HOST, /* supports host operation */ | |
205 | DR_MODE_DEVICE, /* supports device operation */ | |
206 | DR_MODE_OTG, /* supports both */ | |
207 | }; | |
208 | ||
209 | struct ehci_vf_priv_data { | |
210 | struct ehci_ctrl ctrl; | |
211 | struct usb_ehci *ehci; | |
212 | struct gpio_desc cdet_gpio; | |
213 | enum usb_init_type init_type; | |
214 | enum dr_mode dr_mode; | |
215 | u32 portnr; | |
216 | }; | |
217 | ||
218 | static int vf_usb_ofdata_to_platdata(struct udevice *dev) | |
219 | { | |
220 | struct ehci_vf_priv_data *priv = dev_get_priv(dev); | |
221 | const void *dt_blob = gd->fdt_blob; | |
e160f7d4 | 222 | int node = dev_of_offset(dev); |
0885cdb9 SM |
223 | const char *mode; |
224 | ||
225 | priv->portnr = dev->seq; | |
226 | ||
a821c4af | 227 | priv->ehci = (struct usb_ehci *)devfdt_get_addr(dev); |
0885cdb9 SM |
228 | mode = fdt_getprop(dt_blob, node, "dr_mode", NULL); |
229 | if (mode) { | |
230 | if (0 == strcmp(mode, "host")) { | |
231 | priv->dr_mode = DR_MODE_HOST; | |
232 | priv->init_type = USB_INIT_HOST; | |
233 | } else if (0 == strcmp(mode, "peripheral")) { | |
234 | priv->dr_mode = DR_MODE_DEVICE; | |
235 | priv->init_type = USB_INIT_DEVICE; | |
236 | } else if (0 == strcmp(mode, "otg")) { | |
237 | priv->dr_mode = DR_MODE_OTG; | |
238 | /* | |
239 | * We set init_type to device by default when OTG | |
240 | * mode is requested. If a valid gpio is provided | |
241 | * we will switch the init_type based on the state | |
242 | * of the gpio pin. | |
243 | */ | |
244 | priv->init_type = USB_INIT_DEVICE; | |
245 | } else { | |
246 | debug("%s: Cannot decode dr_mode '%s'\n", | |
247 | __func__, mode); | |
248 | return -EINVAL; | |
249 | } | |
250 | } else { | |
251 | priv->dr_mode = DR_MODE_HOST; | |
252 | priv->init_type = USB_INIT_HOST; | |
253 | } | |
254 | ||
255 | if (priv->dr_mode == DR_MODE_OTG) { | |
150c5afe SG |
256 | gpio_request_by_name_nodev(offset_to_ofnode(node), |
257 | "fsl,cdet-gpio", 0, &priv->cdet_gpio, | |
258 | GPIOD_IS_IN); | |
0885cdb9 SM |
259 | if (dm_gpio_is_valid(&priv->cdet_gpio)) { |
260 | if (dm_gpio_get_value(&priv->cdet_gpio)) | |
261 | priv->init_type = USB_INIT_DEVICE; | |
262 | else | |
263 | priv->init_type = USB_INIT_HOST; | |
264 | } | |
265 | } | |
266 | ||
267 | return 0; | |
268 | } | |
269 | ||
270 | static int vf_init_after_reset(struct ehci_ctrl *dev) | |
271 | { | |
272 | struct ehci_vf_priv_data *priv = dev->priv; | |
273 | enum usb_init_type type = priv->init_type; | |
274 | struct usb_ehci *ehci = priv->ehci; | |
275 | int ret; | |
276 | ||
277 | ret = ehci_vf_common_init(priv->ehci, priv->portnr); | |
278 | if (ret) | |
279 | return ret; | |
280 | ||
281 | if (type == USB_INIT_DEVICE) | |
282 | return 0; | |
283 | ||
284 | setbits_le32(&ehci->usbmode, CM_HOST); | |
285 | writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc); | |
286 | setbits_le32(&ehci->portsc, USB_EN); | |
287 | ||
288 | mdelay(10); | |
289 | ||
290 | return 0; | |
291 | } | |
292 | ||
293 | static const struct ehci_ops vf_ehci_ops = { | |
294 | .init_after_reset = vf_init_after_reset | |
295 | }; | |
296 | ||
297 | static int vf_usb_bind(struct udevice *dev) | |
298 | { | |
299 | static int num_controllers; | |
300 | ||
301 | /* | |
302 | * Without this hack, if we return ENODEV for USB Controller 0, on | |
303 | * probe for the next controller, USB Controller 1 will be given a | |
304 | * sequence number of 0. This conflicts with our requirement of | |
305 | * sequence numbers while initialising the peripherals. | |
306 | */ | |
307 | dev->req_seq = num_controllers; | |
308 | num_controllers++; | |
309 | ||
310 | return 0; | |
311 | } | |
312 | ||
313 | static int ehci_usb_probe(struct udevice *dev) | |
314 | { | |
315 | struct usb_platdata *plat = dev_get_platdata(dev); | |
316 | struct ehci_vf_priv_data *priv = dev_get_priv(dev); | |
317 | struct usb_ehci *ehci = priv->ehci; | |
318 | struct ehci_hccr *hccr; | |
319 | struct ehci_hcor *hcor; | |
320 | int ret; | |
321 | ||
322 | ret = ehci_vf_common_init(ehci, priv->portnr); | |
323 | if (ret) | |
324 | return ret; | |
325 | ||
326 | if (priv->init_type != plat->init_type) | |
327 | return -ENODEV; | |
328 | ||
329 | if (priv->init_type == USB_INIT_HOST) { | |
330 | setbits_le32(&ehci->usbmode, CM_HOST); | |
331 | writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc); | |
332 | setbits_le32(&ehci->portsc, USB_EN); | |
333 | } | |
334 | ||
335 | mdelay(10); | |
336 | ||
337 | hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); | |
338 | hcor = (struct ehci_hcor *)((uint32_t)hccr + | |
339 | HC_LENGTH(ehci_readl(&hccr->cr_capbase))); | |
340 | ||
341 | return ehci_register(dev, hccr, hcor, &vf_ehci_ops, 0, priv->init_type); | |
342 | } | |
343 | ||
0885cdb9 SM |
344 | static const struct udevice_id vf_usb_ids[] = { |
345 | { .compatible = "fsl,vf610-usb" }, | |
346 | { } | |
347 | }; | |
348 | ||
349 | U_BOOT_DRIVER(usb_ehci) = { | |
350 | .name = "ehci_vf", | |
351 | .id = UCLASS_USB, | |
352 | .of_match = vf_usb_ids, | |
353 | .bind = vf_usb_bind, | |
354 | .probe = ehci_usb_probe, | |
99e2df47 | 355 | .remove = ehci_deregister, |
0885cdb9 SM |
356 | .ops = &ehci_usb_ops, |
357 | .ofdata_to_platdata = vf_usb_ofdata_to_platdata, | |
358 | .platdata_auto_alloc_size = sizeof(struct usb_platdata), | |
359 | .priv_auto_alloc_size = sizeof(struct ehci_vf_priv_data), | |
360 | .flags = DM_FLAG_ALLOC_PRIV_DMA, | |
361 | }; | |
362 | #endif |