1 /***********************license start***********************************
2 * Copyright (c) 2003-2017 Cavium Inc. ([email protected]). All rights
3 * reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * * Neither the name of Cavium Inc. nor the names of
19 * its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written
21 * permission.
22 *
23 * This Software, including technical data, may be subject to U.S. export
24 * control laws, including the U.S. Export Administration Act and its
25 * associated regulations, and may be subject to export or import
26 * regulations in other countries.
27 *
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
31 * TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
32 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
33 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
34 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
35 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
36 * QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK
37 * ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39 #include <bdk.h>
40 #include <libbdk-arch/bdk-csrs-gpio.h>
41 #include <libbdk-arch/bdk-csrs-usbdrd.h>
42 #include <libbdk-arch/bdk-csrs-usbh.h>
43 #include <libbdk-hal/bdk-usb.h>
44 #include <libbdk-hal/bdk-config.h>
45
46 /* This code is an optional part of the BDK. It is only linked in
47 if BDK_REQUIRE() needs it */
48 BDK_REQUIRE_DEFINE(USB);
49
50 /**
51 * Write to DWC3 indirect debug control register
52 *
53 * @param node Node to write to
54 * @param usb_port USB port to write to
55 * @param val 32bit value to write
56 */
write_cr_dbg_cfg(bdk_node_t node,int usb_port,uint64_t val)57 static void write_cr_dbg_cfg(bdk_node_t node, int usb_port, uint64_t val)
58 {
59 if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX))
60 BDK_CSR_WRITE(node, BDK_USBDRDX_UCTL_PORTX_CR_DBG_CFG(usb_port, 0), val);
61 else
62 BDK_CSR_WRITE(node, BDK_USBHX_UCTL_PORTX_CR_DBG_CFG(usb_port, 0), val);
63 }
64
65 /**
66 * Poll the DWC3 internal status until the ACK bit matches a desired value. Return
67 * the final status.
68 *
69 * @param node Node to query
70 * @param usb_port USB port to query
71 * @param desired_ack
72 * Desired ACK bit state
73 *
74 * @return Final status with ACK at correct state
75 */
get_cr_dbg_status(bdk_node_t node,int usb_port,int desired_ack)76 static bdk_usbdrdx_uctl_portx_cr_dbg_status_t get_cr_dbg_status(bdk_node_t node, int usb_port, int desired_ack)
77 {
78 const int TIMEOUT = 1000000; /* 1 sec */
79 bdk_usbdrdx_uctl_portx_cr_dbg_status_t status;
80 if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX))
81 {
82 if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_USBDRDX_UCTL_PORTX_CR_DBG_STATUS(usb_port, 0), ack, ==, desired_ack, TIMEOUT))
83 {
84 BDK_TRACE(USB_XHCI, "N%d.USB%d: Timeout waiting for indirect ACK\n", node, usb_port);
85 status.u = -1;
86 }
87 else
88 status.u = BDK_CSR_READ(node, BDK_USBDRDX_UCTL_PORTX_CR_DBG_STATUS(usb_port, 0));
89 }
90 else
91 {
92 if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_USBHX_UCTL_PORTX_CR_DBG_STATUS(usb_port, 0), ack, ==, desired_ack, TIMEOUT))
93 {
94 BDK_TRACE(USB_XHCI, "N%d.USB%d: Timeout waiting for indirect ACK\n", node, usb_port);
95 status.u = -1;
96 }
97 else
98 status.u = BDK_CSR_READ(node, BDK_USBHX_UCTL_PORTX_CR_DBG_STATUS(usb_port, 0));
99 }
100 return status;
101 }
102
103 /**
104 * Perform an indirect read of an internal register inside the DWC3 usb block
105 *
106 * @param node Node to read
107 * @param usb_port USB port to read
108 * @param addr Indirect register address
109 *
110 * @return Value of the indirect register
111 */
dwc3_uphy_indirect_read(bdk_node_t node,int usb_port,uint32_t addr)112 static uint32_t dwc3_uphy_indirect_read(bdk_node_t node, int usb_port, uint32_t addr)
113 {
114 bdk_usbdrdx_uctl_portx_cr_dbg_cfg_t dbg_cfg;
115 bdk_usbdrdx_uctl_portx_cr_dbg_status_t status;
116
117 /* See the CSR description for USBHX_UCTL_PORTX_CR_DBG_CFG, which describes
118 the steps implemented by this function */
119
120 dbg_cfg.u = 0;
121 dbg_cfg.s.data_in = addr;
122 write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
123
124 dbg_cfg.s.cap_addr = 1;
125 write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
126
127 status = get_cr_dbg_status(node, usb_port, 1);
128 if (status.u == (uint64_t)-1)
129 return 0xffffffff;
130
131 write_cr_dbg_cfg(node, usb_port, 0);
132 get_cr_dbg_status(node, usb_port, 0);
133
134 dbg_cfg.u = 0;
135 dbg_cfg.s.read = 1;
136 write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
137
138 status = get_cr_dbg_status(node, usb_port, 1);
139
140 write_cr_dbg_cfg(node, usb_port, 0);
141 get_cr_dbg_status(node, usb_port, 0);
142
143 return status.s.data_out;
144 }
145
146 /**
147 * Perform an indirect write of an internal register inside the DWC3 usb block
148 *
149 * @param node Node to write
150 * @param usb_port USB port to write
151 * @param addr Indirect register address
152 * @param value Value for write
153 */
dwc3_uphy_indirect_write(bdk_node_t node,int usb_port,uint32_t addr,uint16_t value)154 static void dwc3_uphy_indirect_write(bdk_node_t node, int usb_port, uint32_t addr, uint16_t value)
155 {
156 bdk_usbdrdx_uctl_portx_cr_dbg_cfg_t dbg_cfg;
157
158 /* See the CSR description for USBHX_UCTL_PORTX_CR_DBG_CFG, which describes
159 the steps implemented by this function */
160
161 dbg_cfg.u = 0;
162 dbg_cfg.s.data_in = addr;
163 write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
164
165 dbg_cfg.s.cap_addr = 1;
166 write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
167
168 get_cr_dbg_status(node, usb_port, 1);
169
170 write_cr_dbg_cfg(node, usb_port, 0);
171 get_cr_dbg_status(node, usb_port, 0);
172
173 dbg_cfg.u = 0;
174 dbg_cfg.s.data_in = value;
175 write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
176
177 dbg_cfg.s.cap_data = 1;
178 write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
179
180 get_cr_dbg_status(node, usb_port, 1);
181
182 write_cr_dbg_cfg(node, usb_port, 0);
183 get_cr_dbg_status(node, usb_port, 0);
184
185 dbg_cfg.u = 0;
186 dbg_cfg.s.write = 1;
187 write_cr_dbg_cfg(node, usb_port, dbg_cfg.u);
188
189 get_cr_dbg_status(node, usb_port, 1);
190
191 write_cr_dbg_cfg(node, usb_port, 0);
192 get_cr_dbg_status(node, usb_port, 0);
193 }
194
195 /**
196 * Errata USB-29206 - The USB HS PLL in all 28nm devices has a
197 * design issue that may cause the VCO to lock up on
198 * initialization. The Synopsys VCO is designed with an even
199 * number of stages and no kick-start circuit, which makes us
200 * believe that there is no question a latched up
201 * (non-oscillating) state is possible. The workaround is to
202 * check the PLL lock bit, which is just based on a counter and
203 * will not set if the VCO is not oscillating, and if it's not
204 * set do a power down/power up cycle on the PLL, which tests
205 * have proven is much more likely to guarantee the VCO will
206 * start oscillating. Part of the problem appears to be that
207 * the normal init sequence holds the VCO in reset during the
208 * power up sequence, whereas the plain power up/down sequence
209 * does not, so the voltage changing may be helping the circuit
210 * to oscillate.
211 *
212 * @param node Node to check
213 * @param usb_port USB port to check
214 *
215 * @return Zero on success, negative on failure
216 */
dwc3_uphy_check_pll(bdk_node_t node,int usb_port)217 static int dwc3_uphy_check_pll(bdk_node_t node, int usb_port)
218 {
219 /* Internal indirect register that reports if the phy PLL has lock. This will
220 be 1 if lock, 0 if no lock */
221 const int DWC3_INT_IND_PLL_LOCK_REG = 0x200b;
222 /* Internal indirect UPHY register that controls the power to the UPHY PLL */
223 const int DWC3_INT_IND_UPHY_PLL_PU = 0x2012;
224 /* Write enable bit for DWC3_INT_IND_PLL_POWER_CTL */
225 const int DWC3_INT_IND_UPHY_PLL_PU_WE = 0x20;
226 /* Power enable bit for DWC3_INT_IND_PLL_POWER_CTL */
227 const int DWC3_INT_IND_UPHY_PLL_PU_POWER_EN = 0x02;
228
229 uint32_t pll_locked = dwc3_uphy_indirect_read(node, usb_port, DWC3_INT_IND_PLL_LOCK_REG);
230 int retry_count = 0;
231 while (!pll_locked)
232 {
233 if (retry_count >= 3)
234 {
235 bdk_error("N%d.USB%d: USB2 PLL failed to lock\n", node, usb_port);
236 return -1;
237 }
238
239 retry_count++;
240 BDK_TRACE(USB_XHCI, "N%d.USB%d: USB2 PLL didn't lock, retry %d\n", node, usb_port, retry_count);
241
242 /* Turn on write enable for PLL power control */
243 uint32_t pwr_val = dwc3_uphy_indirect_read(node, usb_port, DWC3_INT_IND_UPHY_PLL_PU);
244 pwr_val |= DWC3_INT_IND_UPHY_PLL_PU_WE;
245 dwc3_uphy_indirect_write(node, usb_port, DWC3_INT_IND_UPHY_PLL_PU, pwr_val);
246
247 /* Power down the PLL */
248 pwr_val &= ~DWC3_INT_IND_UPHY_PLL_PU_POWER_EN;
249 dwc3_uphy_indirect_write(node, usb_port, DWC3_INT_IND_UPHY_PLL_PU, pwr_val);
250 bdk_wait_usec(1000);
251
252 /* Power on the PLL */
253 pwr_val |= DWC3_INT_IND_UPHY_PLL_PU_POWER_EN;
254 dwc3_uphy_indirect_write(node, usb_port, DWC3_INT_IND_UPHY_PLL_PU, pwr_val);
255 bdk_wait_usec(1000);
256
257 /* Check for PLL Lock again */
258 pll_locked = dwc3_uphy_indirect_read(node, usb_port, DWC3_INT_IND_PLL_LOCK_REG);
259 }
260 return 0;
261 }
262
263 /**
264 * Initialize the clocks for USB such that it is ready for a generic XHCI driver
265 *
266 * @param node Node to init
267 * @param usb_port Port to intialize
268 * @param clock_type Type of clock connected to the usb port
269 *
270 * @return Zero on success, negative on failure
271 */
272
bdk_usb_initialize(bdk_node_t node,int usb_port,bdk_usb_clock_t clock_type)273 int bdk_usb_initialize(bdk_node_t node, int usb_port, bdk_usb_clock_t clock_type)
274 {
275 int is_usbdrd = !CAVIUM_IS_MODEL(CAVIUM_CN88XX);
276
277 /* Perform the following steps to initiate a cold reset. */
278
279 /* 1. Wait for all voltages to reach a stable state. Ensure the
280 reference clock is up and stable.
281 a. If 3.3V is up first, 0.85V must be soon after (within tens of ms). */
282
283 /* 2. Wait for IOI reset to deassert. */
284
285 /* 3. If Over Current indication and/or Port Power Control features
286 are desired, program the GPIO CSRs appropriately.
287 a. For Over Current Indication, select a GPIO for the input and
288 program GPIO_USBH_CTL[SEL].
289 b. For Port Power Control, set one of
290 GPIO_BIT_CFG(0..19)[OUTPUT_SEL] = USBH_VBUS_CTRL. */
291
292 /* 4. Assert all resets:
293 a. UPHY reset: USBDRD(0..1)_UCTL_CTL[UPHY_RST] = 1
294 b. UAHC reset: USBDRD(0..1)_UCTL_CTL[UAHC_RST] = 1
295 c. UCTL reset: USBDRD(0..1)_UCTL_CTL[UCTL_RST] = 1 */
296 if (is_usbdrd)
297 {
298 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
299 c.s.uphy_rst = 1;
300 c.s.uahc_rst = 1;
301 c.s.uctl_rst = 1);
302 }
303 else
304 {
305 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
306 c.s.uphy_rst = 1;
307 c.s.uahc_rst = 1;
308 c.s.uctl_rst = 1);
309 }
310
311 /* 5. Configure the controller clock:
312 a. Reset the clock dividers: USBDRD(0..1)_UCTL_CTL[H_CLKDIV_RST] = 1.
313 b. Select the controller clock frequency
314 USBDRD(0..1)_UCTL_CTL[H_CLKDIV] = desired value.
315 USBDRD(0..1)_UCTL_CTL[H_CLKDIV_EN] = 1 to enable the controller
316 clock.
317 Read USBDRD(0..1)_UCTL_CTL to ensure the values take effect.
318 c. Deassert the controller clock divider reset: USB-
319 DRD(0..1)_UCTL_CTL[H_CLKDIV_RST] = 0. */
320 uint64_t sclk_rate = bdk_clock_get_rate(node, BDK_CLOCK_SCLK);
321 uint64_t divider = (sclk_rate + 300000000-1) / 300000000;
322 /*
323 ** According to HRM Rules are:
324 ** - clock must be below 300MHz
325 ** USB3 full-rate requires 150 MHz or better
326 ** USB3 requires 125 MHz
327 ** USB2 full rate requires 90 MHz
328 ** USB2 requires 62.5 MHz
329 */
330 if (divider <= 1)
331 divider = 0;
332 else if (divider <= 2)
333 divider = 1;
334 else if (divider <= 4)
335 divider = 2;
336 else if (divider <= 6)
337 divider = 3;
338 else if (divider <= 8)
339 divider = 4;
340 else if (divider <= 16)
341 divider = 5;
342 else if (divider <= 24)
343 divider = 6;
344 else
345 divider = 7;
346 if (is_usbdrd)
347 {
348 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
349 c.s.h_clkdiv_rst = 1);
350 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
351 c.s.h_clkdiv_sel = divider;
352 c.s.h_clk_en = 1);
353 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
354 c.s.h_clkdiv_rst = 0);
355 }
356 else
357 {
358 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
359 c.s.h_clkdiv_rst = 1);
360 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
361 c.s.h_clkdiv_sel = divider;
362 c.s.h_clk_en = 1);
363 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
364 c.s.h_clkdiv_rst = 0);
365 }
366 {
367 static bool printit[2] = {true,true};
368 if (printit[usb_port]) {
369 uint64_t fr_div;
370 if (divider < 5) fr_div = divider * 2;
371 else fr_div = 8 * (divider - 3);
372 uint64_t freq = 0;
373 if (fr_div > 0)
374 freq = (typeof(freq)) (sclk_rate / fr_div);
375 const char *token;
376 if (freq < 62500000ULL) token = "???Low";
377 else if (freq < 90000000ULL) token = "USB2";
378 else if (freq < 125000000ULL) token = "USB2 Full";
379 else if (freq < 150000000ULL) token = "USB3";
380 else token = "USB3 Full";
381 BDK_TRACE(USB_XHCI, "Freq %lld - %s\n",
382 (unsigned long long)freq, token);
383 printit[usb_port] = false;
384 }
385 }
386
387 /* 6. Configure the strap signals in USBDRD(0..1)_UCTL_CTL.
388 a. Reference clock configuration (see Table 31.2): USB-
389 DRD(0..1)_UCTL_CTL[REF_CLK_FSEL, MPLL_MULTIPLIER,
390 REF_CLK_SEL, REF_CLK_DIV2].
391 b. Configure and enable spread-spectrum for SuperSpeed:
392 USBDRD(0..1)_UCTL_CTL[SSC_RANGE, SSC_EN, SSC_REF_CLK_SEL].
393 c. Enable USBDRD(0..1)_UCTL_CTL[REF_SSP_EN].
394 d. Configure PHY ports:
395 USBDRD(0..1)_UCTL_CTL[USB*_PORT_PERM_ATTACH, USB*_PORT_DISABLE]. */
396 if (is_usbdrd)
397 {
398 int ref_clk_src = 0;
399 int ref_clk_fsel = 0x27;
400 if (CAVIUM_IS_MODEL(CAVIUM_CN83XX)) {
401 if (BDK_USB_CLOCK_SS_PAD_HS_PAD != clock_type) {
402 bdk_error("Node %d usb_port %d: usb clock type %d is invalid\n", node, usb_port, clock_type);
403 return -1;
404 }
405 }
406 else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX)) {
407 switch (clock_type)
408 {
409 default:
410 bdk_error("Node %d usb_port %d: usb clock type %d is invalid\n", node, usb_port, clock_type);
411 return -1;
412 case BDK_USB_CLOCK_SS_PAD_HS_PAD : ref_clk_src = 2; break;
413 case BDK_USB_CLOCK_SS_REF0_HS_REF0 : ref_clk_src = 0; break; /* Superspeed and high speed use DLM/QLM ref clock 0 */
414 case BDK_USB_CLOCK_SS_REF1_HS_REF1 : ref_clk_src = 1; break; /* Superspeed and high speed use DLM/QLM ref clock 1 */
415 case BDK_USB_CLOCK_SS_PAD_HS_PLL : ref_clk_src = 6; ref_clk_fsel = 0x7; break; /* Superspeed uses PAD clock, high speed uses PLL ref clock */
416 case BDK_USB_CLOCK_SS_REF0_HS_PLL : ref_clk_src = 4; ref_clk_fsel = 0x7; break; /* Superspeed uses DLM/QLM ref clock 0, high speed uses PLL ref clock */
417 case BDK_USB_CLOCK_SS_REF1_HS_PLL: ref_clk_src = 5; ref_clk_fsel =0x7; break; /* Superspeed uses DLM/QLM ref clock 1, high speed uses PLL ref clock */
418 }
419 }
420 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
421 c.s.ref_clk_fsel = ref_clk_fsel;
422 c.s.mpll_multiplier = 0x19;
423 c.s.ref_clk_sel = ref_clk_src;
424 c.s.ref_clk_div2 = 0);
425 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
426 c.s.ssc_en = 1;
427 c.s.ssc_ref_clk_sel = 0);
428 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
429 c.s.ref_ssp_en = 1);
430 }
431 else
432 {
433 if (BDK_USB_CLOCK_SS_PAD_HS_PAD != clock_type) {
434 bdk_error("Node %d usb_port %d: usb clock type %d is invalid\n", node, usb_port, clock_type);
435 return -1;
436 }
437 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
438 c.s.ref_clk_fsel = 0x27;
439 c.s.mpll_multiplier = 0;
440 c.s.ref_clk_sel = 0;
441 c.s.ref_clk_div2 = 0);
442 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
443 c.s.ssc_en = 1;
444 c.s.ssc_ref_clk_sel = 0);
445 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
446 c.s.ref_ssp_en = 1);
447 }
448 /* Hardware default is for ports to be enabled and not perm attach. Don't
449 change it */
450
451 /* 7. The PHY resets in lowest-power mode. Power up the per-port PHY
452 logic by enabling the following:
453 a. USBDRD(0..1)_UCTL_CTL [HS_POWER_EN] if high-speed/full-speed/low-
454 speed functionality needed.
455 b. USBDRD(0..1)_UCTL_CTL [SS_POWER_EN] if SuperSpeed functionality
456 needed. */
457 if (is_usbdrd)
458 {
459 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
460 c.s.hs_power_en = 1;
461 c.s.ss_power_en = 1);
462 }
463 else
464 {
465 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
466 c.s.hs_power_en = 1;
467 c.s.ss_power_en = 1);
468 }
469
470 /* 8. Wait 10 controller-clock cycles from step 5. for controller clock
471 to start and async FIFO to properly reset. */
472 bdk_wait_usec(1);
473
474 /* 9. Deassert UCTL and UAHC resets:
475 a. USBDRD(0..1)_UCTL_CTL[UCTL_RST] = 0
476 b. USBDRD(0..1)_UCTL_CTL[UAHC_RST] = 0
477 c. [optional] For port-power control:
478 - Set one of GPIO_BIT_CFG(0..47)[PIN_SEL] = USB0_VBUS_CTRLor USB1_VBUS_CTRL.
479 - Set USBDRD(0..1)_UCTL_HOST_CFG[PPC_EN] = 1 and USBDRD(0..1)_UCTL_HOST_CFG[PPC_ACTIVE_HIGH_EN] = 1.
480 - Wait for the external power management chip to power the VBUS.ional port-power control.
481 ]
482 d. You will have to wait 10 controller-clock cycles before accessing
483 any controller-clock-only registers. */
484 if (is_usbdrd)
485 {
486 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
487 c.s.uctl_rst = 0);
488 }
489 else
490 {
491 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
492 c.s.uctl_rst = 0);
493 }
494 bdk_wait_usec(1);
495
496 int usb_gpio = bdk_config_get_int(BDK_CONFIG_USB_PWR_GPIO, node, usb_port);
497 int usb_polarity = bdk_config_get_int(BDK_CONFIG_USB_PWR_GPIO_POLARITY, node, usb_port);
498 if (-1 != usb_gpio) {
499 int gsrc = BDK_GPIO_PIN_SEL_E_USBX_VBUS_CTRL_CN88XX(usb_port);
500 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX)) {
501 gsrc = BDK_GPIO_PIN_SEL_E_USBX_VBUS_CTRL_CN88XX(usb_port);
502 }
503 else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX)) {
504 gsrc = BDK_GPIO_PIN_SEL_E_USBX_VBUS_CTRL_CN81XX(usb_port);
505 }
506 else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX)) {
507 gsrc = BDK_GPIO_PIN_SEL_E_USBX_VBUS_CTRL_CN83XX(usb_port);}
508 else {
509 bdk_error("USB_VBUS_CTRL GPIO: unknown chip model\n");
510 }
511
512 BDK_CSR_MODIFY(c,node,BDK_GPIO_BIT_CFGX(usb_gpio),
513 c.s.pin_sel = gsrc;
514 c.s.pin_xor = (usb_polarity) ? 0 : 1;
515 );
516
517 if (is_usbdrd)
518 {
519 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_HOST_CFG(usb_port),
520 c.s.ppc_en = 1;
521 c.s.ppc_active_high_en = 1);
522 }
523 else
524 {
525 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_HOST_CFG(usb_port),
526 c.s.ppc_en = 1;
527 c.s.ppc_active_high_en = 1);
528 }
529 bdk_wait_usec(100000);
530 }
531
532 if (is_usbdrd)
533 {
534 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
535 c.s.uahc_rst = 0);
536 }
537 else
538 {
539 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
540 c.s.uahc_rst = 0);
541 }
542
543 bdk_wait_usec(100000);
544 bdk_wait_usec(1);
545
546 /* 10. Enable conditional coprocessor clock of UCTL by writing USB-
547 DRD(0..1)_UCTL_CTL[CSCLK_EN] = 1. */
548 if (is_usbdrd)
549 {
550 if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
551 {
552 /* CN9XXX make coprocessor clock automatic */
553 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
554 c.cn83xx.csclk_en = 1);
555 }
556 }
557 else
558 {
559 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
560 c.s.csclk_en = 1);
561 }
562
563 /* 11. Set USBDRD(0..1)_UCTL_CTL[DRD_MODE] to 1 for device mode, 0 for
564 host mode. */
565 if (is_usbdrd)
566 {
567 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
568 c.s.drd_mode = 0);
569 }
570
571 /* 12. Soft reset the UPHY and UAHC logic via the UAHC controls:
572 a. USBDRD(0..1)_UAHC_GUSB2PHYCFG(0)[PHYSOFTRST] = 1
573 b. USBDRD(0..1)_UAHC_GUSB3PIPECTL(0)[PHYSOFTRST] = 1
574 c. USBDRD(0..1)_UAHC_GCTL[CORESOFTRESET] = 1 */
575 if (is_usbdrd)
576 {
577 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GUSB2PHYCFGX(usb_port, 0),
578 c.s.physoftrst = 1);
579 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GUSB3PIPECTLX(usb_port, 0),
580 c.s.physoftrst = 1);
581 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GCTL(usb_port),
582 c.s.coresoftreset = 1);
583 }
584 else
585 {
586 BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GUSB2PHYCFGX(usb_port, 0),
587 c.s.physoftrst = 1);
588 BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GUSB3PIPECTLX(usb_port, 0),
589 c.s.physoftrst = 1);
590 BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GCTL(usb_port),
591 c.s.coresoftreset = 1);
592 }
593
594 /* 13. Program USBDRD(0..1)_UAHC_GCTL[PRTCAPDIR] to 0x2 for device mode
595 or 0x1 for host mode. */
596 if (is_usbdrd)
597 {
598 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GCTL(usb_port),
599 c.s.prtcapdir = 1);
600 }
601 else
602 {
603 BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GCTL(usb_port),
604 c.s.prtcapdir = 1);
605 }
606
607 /* 14. Wait 10us after step 13. for the PHY to complete its reset. */
608 bdk_wait_usec(10);
609
610 /* 15. Deassert UPHY reset: USBDRD(0..1)_UCTL_CTL[UPHY_RST] = 0. */
611 if (is_usbdrd)
612 {
613 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UCTL_CTL(usb_port),
614 c.s.uphy_rst = 0);
615 }
616 else
617 {
618 BDK_CSR_MODIFY(c, node, BDK_USBHX_UCTL_CTL(usb_port),
619 c.s.uphy_rst = 0);
620 }
621
622 /* 16. Wait for at least 45us after step 15. for UPHY to output
623 stable PHYCLOCK. */
624 bdk_wait_usec(45);
625
626 /* Workround Errata USB-29206 */
627 if (dwc3_uphy_check_pll(node, usb_port))
628 return -1;
629
630 /* 17. Initialize any other strap signals necessary and make sure they
631 propagate by reading back the last register written.
632 a. UCTL
633 USBDRD(0..1)_UCTL_PORT0_CFG_*[*_TUNE]
634 USBDRD(0..1)_UCTL_PORT0_CFG_*[PCS_*]
635 USBDRD(0..1)_UCTL_PORT0_CFG_*[LANE0_TX_TERM_OFFSET]
636 USBDRD(0..1)_UCTL_PORT0_CFG_*[TX_VBOOST_LVL]
637 USBDRD(0..1)_UCTL__PORT0_CFG_*[LOS_BIAS]
638 USBDRD(0..1)_UCTL_HOST_CFG
639 USBDRD(0..1)_UCTL_SHIM_CFG
640 b. UAHC: only the following UAHC registers are accessible during
641 CoreSoftReset.
642 USBDRD(0..1)_UAHC_GCTL
643 USBDRD(0..1)_UAHC_GUCTL
644 USBDRD(0..1)_UAHC_GSTS
645 USBDRD(0..1)_UAHC_GUID
646 USBDRD(0..1)_UAHC_GUSB2PHYCFG(0)
647 USBDRD(0..1)_UAHC_GUSB3PIPECTL(0) */
648
649 /* 18. Release soft reset the UPHY and UAHC logic via the UAHC controls:
650 a. USBDRD(0..1)_UAHC_GUSB2PHYCFG(0)[PHYSOFTRST] = 0
651 b. USBDRD(0..1)_UAHC_GUSB3PIPECTL(0)[PHYSOFTRST] = 0
652 c. USBDRD(0..1)_UAHC_GCTL[CORESOFTRESET] = 0 */
653 if (is_usbdrd)
654 {
655 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GUSB2PHYCFGX(usb_port, 0),
656 c.s.physoftrst = 0);
657 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GUSB3PIPECTLX(usb_port, 0),
658 c.s.physoftrst = 0);
659 BDK_CSR_MODIFY(c, node, BDK_USBDRDX_UAHC_GCTL(usb_port),
660 c.s.coresoftreset = 0);
661 }
662 else
663 {
664 BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GUSB2PHYCFGX(usb_port, 0),
665 c.s.physoftrst = 0);
666 BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GUSB3PIPECTLX(usb_port, 0),
667 c.s.physoftrst = 0);
668 BDK_CSR_MODIFY(c, node, BDK_USBHX_UAHC_GCTL(usb_port),
669 c.s.coresoftreset = 0);
670 }
671
672 /* 19. Configure the remaining UAHC_G* registers as needed, including
673 any that were not configured in step 17.-b. */
674
675 /* 20. Initialize the USB controller:
676 a. To initialize the UAHC as a USB host controller, the application
677 should perform the steps described in the xHCI specification
678 (UAHC_X* registers). The xHCI sequence starts with poll for a 0 in
679 USBDRD(0..1)_UAHC_USBSTS[CNR].
680 b. To initialize the UAHC as a device, the application should TBD. The
681 device initiation sequence starts with a device soft reset by
682 setting USBDRD(0..1)_UAHC_DCTL[CSFTRST] = 1 and wait for a read
683 operation to return 0. */
684 return 0;
685 }
686