]>
Commit | Line | Data |
---|---|---|
6b92487d | 1 | /* |
ba699a5f | 2 | * (C) Copyright 2009, 2011, 2016 Freescale Semiconductor, Inc. |
4ef01010 | 3 | * |
6b92487d MT |
4 | * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB |
5 | * | |
6 | * Author: Tor Krill tor@excito.com | |
7 | * | |
1a459660 | 8 | * SPDX-License-Identifier: GPL-2.0+ |
6b92487d MT |
9 | */ |
10 | ||
11 | #include <common.h> | |
12 | #include <pci.h> | |
13 | #include <usb.h> | |
6b92487d | 14 | #include <asm/io.h> |
e162c6b1 | 15 | #include <usb/ehci-ci.h> |
1b719e66 | 16 | #include <hwconfig.h> |
c26c80a1 | 17 | #include <fsl_usb.h> |
a1c04e27 | 18 | #include <fdt_support.h> |
ba699a5f | 19 | #include <dm.h> |
6b92487d | 20 | |
2731b9a8 | 21 | #include "ehci.h" |
6b92487d | 22 | |
ba699a5f RB |
23 | DECLARE_GLOBAL_DATA_PTR; |
24 | ||
a1c04e27 NB |
25 | #ifndef CONFIG_USB_MAX_CONTROLLER_COUNT |
26 | #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 | |
27 | #endif | |
28 | ||
ba699a5f RB |
29 | #ifdef CONFIG_DM_USB |
30 | struct ehci_fsl_priv { | |
31 | struct ehci_ctrl ehci; | |
32 | fdt_addr_t hcd_base; | |
33 | char *phy_type; | |
34 | }; | |
35 | #endif | |
36 | ||
896720ce | 37 | static void set_txfifothresh(struct usb_ehci *, u32); |
ba699a5f RB |
38 | #ifdef CONFIG_DM_USB |
39 | static int ehci_fsl_init(struct ehci_fsl_priv *priv, struct usb_ehci *ehci, | |
40 | struct ehci_hccr *hccr, struct ehci_hcor *hcor); | |
41 | #else | |
1e61ce9f RB |
42 | static int ehci_fsl_init(int index, struct usb_ehci *ehci, |
43 | struct ehci_hccr *hccr, struct ehci_hcor *hcor); | |
ba699a5f | 44 | #endif |
896720ce | 45 | |
047cea36 SL |
46 | /* Check USB PHY clock valid */ |
47 | static int usb_phy_clk_valid(struct usb_ehci *ehci) | |
48 | { | |
49 | if (!((in_be32(&ehci->control) & PHY_CLK_VALID) || | |
50 | in_be32(&ehci->prictrl))) { | |
51 | printf("USB PHY clock invalid!\n"); | |
52 | return 0; | |
53 | } else { | |
54 | return 1; | |
55 | } | |
56 | } | |
57 | ||
ba699a5f RB |
58 | #ifdef CONFIG_DM_USB |
59 | static int ehci_fsl_ofdata_to_platdata(struct udevice *dev) | |
60 | { | |
61 | struct ehci_fsl_priv *priv = dev_get_priv(dev); | |
62 | const void *prop; | |
63 | ||
64 | prop = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy_type", | |
65 | NULL); | |
66 | if (prop) { | |
67 | priv->phy_type = (char *)prop; | |
68 | debug("phy_type %s\n", priv->phy_type); | |
69 | } | |
70 | ||
71 | return 0; | |
72 | } | |
73 | ||
74 | static int ehci_fsl_init_after_reset(struct ehci_ctrl *ctrl) | |
75 | { | |
76 | struct usb_ehci *ehci = NULL; | |
77 | struct ehci_fsl_priv *priv = container_of(ctrl, struct ehci_fsl_priv, | |
78 | ehci); | |
79 | ||
80 | ehci = (struct usb_ehci *)priv->hcd_base; | |
81 | if (ehci_fsl_init(priv, ehci, priv->ehci.hccr, priv->ehci.hcor) < 0) | |
82 | return -ENXIO; | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | static const struct ehci_ops fsl_ehci_ops = { | |
88 | .init_after_reset = ehci_fsl_init_after_reset, | |
89 | }; | |
90 | ||
91 | static int ehci_fsl_probe(struct udevice *dev) | |
92 | { | |
93 | struct ehci_fsl_priv *priv = dev_get_priv(dev); | |
94 | struct usb_ehci *ehci = NULL; | |
95 | struct ehci_hccr *hccr; | |
96 | struct ehci_hcor *hcor; | |
97 | ||
98 | /* | |
99 | * Get the base address for EHCI controller from the device node | |
100 | */ | |
101 | priv->hcd_base = dev_get_addr(dev); | |
102 | if (priv->hcd_base == FDT_ADDR_T_NONE) { | |
103 | debug("Can't get the EHCI register base address\n"); | |
104 | return -ENXIO; | |
105 | } | |
106 | ehci = (struct usb_ehci *)priv->hcd_base; | |
107 | hccr = (struct ehci_hccr *)(&ehci->caplength); | |
108 | hcor = (struct ehci_hcor *) | |
109 | ((u32)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); | |
110 | ||
111 | if (ehci_fsl_init(priv, ehci, hccr, hcor) < 0) | |
112 | return -ENXIO; | |
113 | ||
114 | debug("ehci-fsl: init hccr %x and hcor %x hc_length %d\n", | |
115 | (u32)hccr, (u32)hcor, | |
116 | (u32)HC_LENGTH(ehci_readl(&hccr->cr_capbase))); | |
117 | ||
118 | return ehci_register(dev, hccr, hcor, &fsl_ehci_ops, 0, USB_INIT_HOST); | |
119 | } | |
120 | ||
121 | static int ehci_fsl_remove(struct udevice *dev) | |
122 | { | |
123 | int ret; | |
124 | ||
125 | ret = ehci_deregister(dev); | |
126 | if (ret) | |
127 | return ret; | |
128 | ||
129 | return 0; | |
130 | } | |
131 | ||
132 | static const struct udevice_id ehci_usb_ids[] = { | |
133 | { .compatible = "fsl-usb2-mph", }, | |
134 | { .compatible = "fsl-usb2-dr", }, | |
135 | { } | |
136 | }; | |
137 | ||
138 | U_BOOT_DRIVER(ehci_fsl) = { | |
139 | .name = "ehci_fsl", | |
140 | .id = UCLASS_USB, | |
141 | .of_match = ehci_usb_ids, | |
142 | .ofdata_to_platdata = ehci_fsl_ofdata_to_platdata, | |
143 | .probe = ehci_fsl_probe, | |
144 | .remove = ehci_fsl_remove, | |
145 | .ops = &ehci_usb_ops, | |
146 | .platdata_auto_alloc_size = sizeof(struct usb_platdata), | |
147 | .priv_auto_alloc_size = sizeof(struct ehci_fsl_priv), | |
148 | .flags = DM_FLAG_ALLOC_PRIV_DMA, | |
149 | }; | |
150 | #else | |
6b92487d MT |
151 | /* |
152 | * Create the appropriate control structures to manage | |
153 | * a new EHCI host controller. | |
154 | * | |
155 | * Excerpts from linux ehci fsl driver. | |
156 | */ | |
127efc4f TK |
157 | int ehci_hcd_init(int index, enum usb_init_type init, |
158 | struct ehci_hccr **hccr, struct ehci_hcor **hcor) | |
6b92487d | 159 | { |
77354e9d | 160 | struct usb_ehci *ehci = NULL; |
1e61ce9f RB |
161 | |
162 | switch (index) { | |
163 | case 0: | |
164 | ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB1_ADDR; | |
165 | break; | |
166 | case 1: | |
167 | ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB2_ADDR; | |
168 | break; | |
169 | default: | |
170 | printf("ERROR: wrong controller index!!\n"); | |
171 | return -EINVAL; | |
172 | }; | |
173 | ||
174 | *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); | |
175 | *hcor = (struct ehci_hcor *)((uint32_t) *hccr + | |
176 | HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); | |
177 | ||
178 | return ehci_fsl_init(index, ehci, *hccr, *hcor); | |
179 | } | |
180 | ||
181 | /* | |
182 | * Destroy the appropriate control structures corresponding | |
183 | * the the EHCI host controller. | |
184 | */ | |
185 | int ehci_hcd_stop(int index) | |
186 | { | |
187 | return 0; | |
188 | } | |
ba699a5f | 189 | #endif |
1e61ce9f | 190 | |
ba699a5f RB |
191 | #ifdef CONFIG_DM_USB |
192 | static int ehci_fsl_init(struct ehci_fsl_priv *priv, struct usb_ehci *ehci, | |
193 | struct ehci_hccr *hccr, struct ehci_hcor *hcor) | |
194 | #else | |
1e61ce9f RB |
195 | static int ehci_fsl_init(int index, struct usb_ehci *ehci, |
196 | struct ehci_hccr *hccr, struct ehci_hcor *hcor) | |
ba699a5f | 197 | #endif |
1e61ce9f | 198 | { |
1b719e66 | 199 | const char *phy_type = NULL; |
ba699a5f | 200 | #ifndef CONFIG_DM_USB |
1b719e66 | 201 | size_t len; |
0ecb15c8 | 202 | char current_usb_controller[5]; |
ba699a5f | 203 | #endif |
dd22f7cf KG |
204 | #ifdef CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY |
205 | char usb_phy[5]; | |
1b719e66 RM |
206 | |
207 | usb_phy[0] = '\0'; | |
dd22f7cf | 208 | #endif |
11856919 NB |
209 | if (has_erratum_a007075()) { |
210 | /* | |
211 | * A 5ms delay is needed after applying soft-reset to the | |
212 | * controller to let external ULPI phy come out of reset. | |
213 | * This delay needs to be added before re-initializing | |
214 | * the controller after soft-resetting completes | |
215 | */ | |
216 | mdelay(5); | |
217 | } | |
6b92487d | 218 | |
6b92487d | 219 | /* Set to Host mode */ |
08066152 | 220 | setbits_le32(&ehci->usbmode, CM_HOST); |
6b92487d | 221 | |
08066152 VM |
222 | out_be32(&ehci->snoop1, SNOOP_SIZE_2GB); |
223 | out_be32(&ehci->snoop2, 0x80000000 | SNOOP_SIZE_2GB); | |
6b92487d MT |
224 | |
225 | /* Init phy */ | |
ba699a5f RB |
226 | #ifdef CONFIG_DM_USB |
227 | if (priv->phy_type) | |
228 | phy_type = priv->phy_type; | |
229 | #else | |
230 | memset(current_usb_controller, '\0', 5); | |
231 | snprintf(current_usb_controller, sizeof(current_usb_controller), | |
232 | "usb%d", index+1); | |
233 | ||
0ecb15c8 NB |
234 | if (hwconfig_sub(current_usb_controller, "phy_type")) |
235 | phy_type = hwconfig_subarg(current_usb_controller, | |
236 | "phy_type", &len); | |
ba699a5f | 237 | #endif |
4ef01010 | 238 | else |
1b719e66 RM |
239 | phy_type = getenv("usb_phy_type"); |
240 | ||
241 | if (!phy_type) { | |
242 | #ifdef CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY | |
243 | /* if none specified assume internal UTMI */ | |
244 | strcpy(usb_phy, "utmi"); | |
245 | phy_type = usb_phy; | |
246 | #else | |
247 | printf("WARNING: USB phy type not defined !!\n"); | |
248 | return -1; | |
249 | #endif | |
250 | } | |
251 | ||
91d7746d | 252 | if (!strncmp(phy_type, "utmi", 4)) { |
1b719e66 | 253 | #if defined(CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY) |
15231f6d NB |
254 | clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK, |
255 | PHY_CLK_SEL_UTMI); | |
256 | clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK, | |
257 | UTMI_PHY_EN); | |
1b719e66 RM |
258 | udelay(1000); /* delay required for PHY Clk to appear */ |
259 | #endif | |
1e61ce9f | 260 | out_le32(&(hcor)->or_portsc[0], PORT_PTS_UTMI); |
15231f6d NB |
261 | clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK, |
262 | USB_EN); | |
1b719e66 | 263 | } else { |
15231f6d NB |
264 | clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK, |
265 | PHY_CLK_SEL_ULPI); | |
266 | clrsetbits_be32(&ehci->control, UTMI_PHY_EN | | |
267 | CONTROL_REGISTER_W1C_MASK, USB_EN); | |
1b719e66 | 268 | udelay(1000); /* delay required for PHY Clk to appear */ |
047cea36 SL |
269 | if (!usb_phy_clk_valid(ehci)) |
270 | return -EINVAL; | |
1e61ce9f | 271 | out_le32(&(hcor)->or_portsc[0], PORT_PTS_ULPI); |
1b719e66 | 272 | } |
6b92487d | 273 | |
08066152 VM |
274 | out_be32(&ehci->prictrl, 0x0000000c); |
275 | out_be32(&ehci->age_cnt_limit, 0x00000040); | |
276 | out_be32(&ehci->sictrl, 0x00000001); | |
6b92487d | 277 | |
08066152 | 278 | in_le32(&ehci->usbmode); |
6b92487d | 279 | |
f3dff695 | 280 | if (has_erratum_a007798()) |
896720ce NB |
281 | set_txfifothresh(ehci, TXFIFOTHRESH); |
282 | ||
0dc78ff8 NB |
283 | if (has_erratum_a004477()) { |
284 | /* | |
285 | * When reset is issued while any ULPI transaction is ongoing | |
286 | * then it may result to corruption of ULPI Function Control | |
287 | * Register which eventually causes phy clock to enter low | |
288 | * power mode which stops the clock. Thus delay is required | |
289 | * before reset to let ongoing ULPI transaction complete. | |
290 | */ | |
291 | udelay(1); | |
292 | } | |
6b92487d MT |
293 | return 0; |
294 | } | |
295 | ||
896720ce NB |
296 | /* |
297 | * Setting the value of TXFIFO_THRESH field in TXFILLTUNING register | |
298 | * to counter DDR latencies in writing data into Tx buffer. | |
299 | * This prevents Tx buffer from getting underrun | |
300 | */ | |
301 | static void set_txfifothresh(struct usb_ehci *ehci, u32 txfifo_thresh) | |
302 | { | |
303 | u32 cmd; | |
304 | cmd = ehci_readl(&ehci->txfilltuning); | |
305 | cmd &= ~TXFIFO_THRESH_MASK; | |
306 | cmd |= TXFIFO_THRESH(txfifo_thresh); | |
307 | ehci_writel(&ehci->txfilltuning, cmd); | |
308 | } |