1 /***********************license start***************
2 * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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
23 * This Software, including technical data, may be subject to U.S. export control
24 * laws, including the U.S. Export Administration Act and its associated
25 * regulations, and may be subject to export or import regulations in other
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 TO
31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR
37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
44 * "cvmx-usbd.c" defines a set of low level USB functions to help
45 * developers create Octeon USB devices for various operating
46 * systems. These functions provide a generic API to the Octeon
47 * USB blocks, hiding the internal hardware specific
50 * <hr>$Revision: 32636 $<hr>
53 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
54 #include <asm/octeon/cvmx.h>
55 #include <asm/octeon/cvmx-clock.h>
56 #include <asm/octeon/cvmx-sysinfo.h>
57 #include <asm/octeon/cvmx-usbnx-defs.h>
58 #include <asm/octeon/cvmx-usbcx-defs.h>
59 #include <asm/octeon/cvmx-usbd.h>
60 #include <asm/octeon/cvmx-swap.h>
61 #include <asm/octeon/cvmx-helper.h>
62 #include <asm/octeon/cvmx-helper-board.h>
65 #include "cvmx-clock.h"
66 #include "cvmx-sysinfo.h"
67 #include "cvmx-usbd.h"
68 #include "cvmx-swap.h"
69 #include "cvmx-helper.h"
70 #include "cvmx-helper-board.h"
73 #define ULL unsigned long long
77 * Read a USB 32bit CSR. It performs the necessary address swizzle for 32bit
80 * @param usb USB device state populated by
81 * cvmx_usbd_initialize().
82 * @param address 64bit address to read
84 * @return Result of the read
86 static inline uint32_t __cvmx_usbd_read_csr32(cvmx_usbd_state_t *usb, uint64_t address)
88 uint32_t result = cvmx_read64_uint32(address ^ 4);
95 * Write a USB 32bit CSR. It performs the necessary address swizzle for 32bit
98 * @param usb USB device state populated by
99 * cvmx_usbd_initialize().
100 * @param address 64bit address to write
101 * @param value Value to write
103 static inline void __cvmx_usbd_write_csr32(cvmx_usbd_state_t *usb, uint64_t address, uint32_t value)
105 cvmx_write64_uint32(address ^ 4, value);
106 cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
111 * Calls the user supplied callback when an event happens.
113 * @param usb USB device state populated by
114 * cvmx_usbd_initialize().
115 * @param reason Reason for the callback
116 * @param endpoint_num
118 * @param bytes_transferred
121 static void __cvmx_usbd_callback(cvmx_usbd_state_t *usb, cvmx_usbd_callback_t reason, int endpoint_num, int bytes_transferred)
123 if (usb->callback[reason])
125 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
126 cvmx_dprintf("%s: Calling callback reason=%d endpoint=%d bytes=%d func=%p data=%p\n",
127 __FUNCTION__, reason, endpoint_num, bytes_transferred, usb->callback[reason], usb->callback_data[reason]);
128 usb->callback[reason](reason, endpoint_num, bytes_transferred, usb->callback_data[reason]);
132 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
133 cvmx_dprintf("%s: No callback for reason=%d endpoint=%d bytes=%d\n",
134 __FUNCTION__, reason, endpoint_num, bytes_transferred);
140 * Perform USB device mode initialization after a reset completes.
141 * This should be called after USBC0/1_GINTSTS[USBRESET] and
142 * corresponds to section 22.6.1.1, "Initialization on USB Reset",
145 * @param usb USB device state populated by
146 * cvmx_usbd_initialize().
148 * @return Zero or negative on error.
150 static int __cvmx_usbd_device_reset_complete(cvmx_usbd_state_t *usb)
152 cvmx_usbcx_ghwcfg2_t usbcx_ghwcfg2;
153 cvmx_usbcx_ghwcfg3_t usbcx_ghwcfg3;
154 cvmx_usbcx_doepmsk_t usbcx_doepmsk;
155 cvmx_usbcx_diepmsk_t usbcx_diepmsk;
156 cvmx_usbcx_daintmsk_t usbc_daintmsk;
157 cvmx_usbcx_gnptxfsiz_t gnptxfsiz;
161 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
162 cvmx_dprintf("%s: Processing reset\n", __FUNCTION__);
164 usbcx_ghwcfg2.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GHWCFG2(usb->index));
165 usbcx_ghwcfg3.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GHWCFG3(usb->index));
167 /* Set up the data FIFO RAM for each of the FIFOs */
168 fifo_space = usbcx_ghwcfg3.s.dfifodepth;
170 /* Start at the top of the FIFO and assign space for each periodic fifo */
171 for (i=usbcx_ghwcfg2.s.numdeveps; i>0; i--)
173 cvmx_usbcx_dptxfsizx_t siz;
174 siz.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DPTXFSIZX(i, usb->index));
175 fifo_space -= siz.s.dptxfsize;
176 siz.s.dptxfstaddr = fifo_space;
177 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DPTXFSIZX(i, usb->index), siz.u32);
180 /* Assign half the leftover space to the non periodic tx fifo */
181 gnptxfsiz.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index));
182 gnptxfsiz.s.nptxfdep = fifo_space / 2;
183 fifo_space -= gnptxfsiz.s.nptxfdep;
184 gnptxfsiz.s.nptxfstaddr = fifo_space;
185 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), gnptxfsiz.u32);
187 /* Assign the remain space to the RX fifo */
188 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GRXFSIZ(usb->index), fifo_space);
190 /* Unmask the common endpoint interrupts */
191 usbcx_doepmsk.u32 = 0;
192 usbcx_doepmsk.s.setupmsk = 1;
193 usbcx_doepmsk.s.epdisbldmsk = 1;
194 usbcx_doepmsk.s.xfercomplmsk = 1;
195 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPMSK(usb->index), usbcx_doepmsk.u32);
196 usbcx_diepmsk.u32 = 0;
197 usbcx_diepmsk.s.epdisbldmsk = 1;
198 usbcx_diepmsk.s.xfercomplmsk = 1;
199 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPMSK(usb->index), usbcx_diepmsk.u32);
201 usbc_daintmsk.u32 = 0;
202 usbc_daintmsk.s.inepmsk = -1;
203 usbc_daintmsk.s.outepmsk = -1;
204 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DAINTMSK(usb->index), usbc_daintmsk.u32);
206 /* Set all endpoints to NAK */
207 for (i=0; i<usbcx_ghwcfg2.s.numdeveps+1; i++)
209 cvmx_usbcx_doepctlx_t usbc_doepctl;
210 usbc_doepctl.u32 = 0;
211 usbc_doepctl.s.snak = 1;
212 usbc_doepctl.s.usbactep = 1;
213 usbc_doepctl.s.mps = (i==0) ? 0 : 64;
214 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPCTLX(i, usb->index), usbc_doepctl.u32);
222 * Initialize a USB port for use. This must be called before any
223 * other access to the Octeon USB port is made. The port starts
224 * off in the disabled state.
226 * @param usb Pointer to an empty cvmx_usbd_state_t structure
227 * that will be populated by the initialize call.
228 * This structure is then passed to all other USB
230 * @param usb_port_number
231 * Which Octeon USB port to initialize.
232 * @param flags Flags to control hardware initialization. See
233 * cvmx_usbd_initialize_flags_t for the flag
234 * definitions. Some flags are mandatory.
236 * @return Zero or a negative on error.
238 int cvmx_usbd_initialize(cvmx_usbd_state_t *usb,
240 cvmx_usbd_initialize_flags_t flags)
242 cvmx_usbnx_clk_ctl_t usbn_clk_ctl;
243 cvmx_usbnx_usbp_ctl_status_t usbn_usbp_ctl_status;
245 if (cvmx_unlikely(flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
246 cvmx_dprintf("%s: Called\n", __FUNCTION__);
248 memset(usb, 0, sizeof(*usb));
249 usb->init_flags = flags;
250 usb->index = usb_port_number;
252 /* Try to determine clock type automatically */
253 if ((usb->init_flags & (CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_XI |
254 CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_GND)) == 0)
256 if (__cvmx_helper_board_usb_get_clock_type() == USB_CLOCK_TYPE_CRYSTAL_12)
257 usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_XI; /* Only 12 MHZ crystals are supported */
259 usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_GND;
262 if (usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_GND)
264 /* Check for auto ref clock frequency */
265 if (!(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_CLOCK_MHZ_MASK))
266 switch (__cvmx_helper_board_usb_get_clock_type())
268 case USB_CLOCK_TYPE_REF_12:
269 usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_12MHZ;
271 case USB_CLOCK_TYPE_REF_24:
272 usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_24MHZ;
274 case USB_CLOCK_TYPE_REF_48:
276 usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_48MHZ;
281 /* Power On Reset and PHY Initialization */
283 /* 1. Wait for DCOK to assert (nothing to do) */
284 /* 2a. Write USBN0/1_CLK_CTL[POR] = 1 and
285 USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0 */
286 usbn_clk_ctl.u64 = cvmx_read_csr(CVMX_USBNX_CLK_CTL(usb->index));
287 usbn_clk_ctl.s.por = 1;
288 usbn_clk_ctl.s.hrst = 0;
289 usbn_clk_ctl.s.prst = 0;
290 usbn_clk_ctl.s.hclk_rst = 0;
291 usbn_clk_ctl.s.enable = 0;
292 /* 2b. Select the USB reference clock/crystal parameters by writing
293 appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON] */
294 if (usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_GND)
296 /* The USB port uses 12/24/48MHz 2.5V board clock
297 source at USB_XO. USB_XI should be tied to GND.
298 Most Octeon evaluation boards require this setting */
299 if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
301 usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */
302 usbn_clk_ctl.cn31xx.p_xenbn = 0;
304 else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
305 usbn_clk_ctl.cn56xx.p_rtype = 2; /* From CN56XX,CN50XX manual */
307 usbn_clk_ctl.cn52xx.p_rtype = 1; /* From CN52XX manual */
309 switch (usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_CLOCK_MHZ_MASK)
311 case CVMX_USBD_INITIALIZE_FLAGS_CLOCK_12MHZ:
312 usbn_clk_ctl.s.p_c_sel = 0;
314 case CVMX_USBD_INITIALIZE_FLAGS_CLOCK_24MHZ:
315 usbn_clk_ctl.s.p_c_sel = 1;
317 case CVMX_USBD_INITIALIZE_FLAGS_CLOCK_48MHZ:
318 usbn_clk_ctl.s.p_c_sel = 2;
324 /* The USB port uses a 12MHz crystal as clock source
325 at USB_XO and USB_XI */
326 if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
328 usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */
329 usbn_clk_ctl.cn31xx.p_xenbn = 1;
331 else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
332 usbn_clk_ctl.cn56xx.p_rtype = 0; /* From CN56XX,CN50XX manual */
334 usbn_clk_ctl.cn52xx.p_rtype = 0; /* From CN52XX manual */
336 usbn_clk_ctl.s.p_c_sel = 0;
338 /* 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and
339 setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down such
340 that USB is as close as possible to 125Mhz */
342 int divisor = (cvmx_clock_get_rate(CVMX_CLOCK_CORE)+125000000-1)/125000000;
343 if (divisor < 4) /* Lower than 4 doesn't seem to work properly */
345 usbn_clk_ctl.s.divide = divisor;
346 usbn_clk_ctl.s.divide2 = 0;
348 cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
349 /* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */
350 usbn_clk_ctl.s.hclk_rst = 1;
351 cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
352 /* 2e. Wait 64 core-clock cycles for HCLK to stabilize */
354 /* 3. Program the power-on reset field in the USBN clock-control register:
355 USBN_CLK_CTL[POR] = 0 */
356 usbn_clk_ctl.s.por = 0;
357 cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
358 /* 4. Wait 1 ms for PHY clock to start */
359 cvmx_wait_usec(1000);
360 /* 5. Program the Reset input from automatic test equipment field in the
361 USBP control and status register: USBN_USBP_CTL_STATUS[ATE_RESET] = 1 */
362 usbn_usbp_ctl_status.u64 = cvmx_read_csr(CVMX_USBNX_USBP_CTL_STATUS(usb->index));
363 usbn_usbp_ctl_status.s.ate_reset = 1;
364 cvmx_write_csr(CVMX_USBNX_USBP_CTL_STATUS(usb->index), usbn_usbp_ctl_status.u64);
365 /* 6. Wait 10 cycles */
367 /* 7. Clear ATE_RESET field in the USBN clock-control register:
368 USBN_USBP_CTL_STATUS[ATE_RESET] = 0 */
369 usbn_usbp_ctl_status.s.ate_reset = 0;
370 cvmx_write_csr(CVMX_USBNX_USBP_CTL_STATUS(usb->index), usbn_usbp_ctl_status.u64);
371 /* 8. Program the PHY reset field in the USBN clock-control register:
372 USBN_CLK_CTL[PRST] = 1 */
373 usbn_clk_ctl.s.prst = 1;
374 cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
375 /* 9. Program the USBP control and status register to select host or
376 device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for
378 usbn_usbp_ctl_status.s.hst_mode = 1;
379 usbn_usbp_ctl_status.s.dm_pulld = 0;
380 usbn_usbp_ctl_status.s.dp_pulld = 0;
381 cvmx_write_csr(CVMX_USBNX_USBP_CTL_STATUS(usb->index), usbn_usbp_ctl_status.u64);
384 /* 11. Program the hreset_n field in the USBN clock-control register:
385 USBN_CLK_CTL[HRST] = 1 */
386 usbn_clk_ctl.s.hrst = 1;
387 cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
388 /* 12. Proceed to USB core initialization */
389 usbn_clk_ctl.s.enable = 1;
390 cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
393 /* Program the following fields in the global AHB configuration
394 register (USBC_GAHBCFG)
395 DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode
396 Burst length, USBC_GAHBCFG[HBSTLEN] = 0
397 Nonperiodic TxFIFO empty level (slave mode only),
398 USBC_GAHBCFG[NPTXFEMPLVL]
399 Periodic TxFIFO empty level (slave mode only),
400 USBC_GAHBCFG[PTXFEMPLVL]
401 Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1 */
403 cvmx_usbcx_gahbcfg_t usbcx_gahbcfg;
404 usbcx_gahbcfg.u32 = 0;
405 usbcx_gahbcfg.s.dmaen = 1;
406 usbcx_gahbcfg.s.hbstlen = 0;
407 usbcx_gahbcfg.s.nptxfemplvl = 1;
408 usbcx_gahbcfg.s.ptxfemplvl = 1;
409 usbcx_gahbcfg.s.glblintrmsk = 1;
410 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index), usbcx_gahbcfg.u32);
413 /* Program the following fields in USBC_GUSBCFG register.
414 HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0
415 ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0
416 USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5
417 PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0 */
419 cvmx_usbcx_gusbcfg_t usbcx_gusbcfg;
420 usbcx_gusbcfg.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index));
421 usbcx_gusbcfg.s.toutcal = 0;
422 usbcx_gusbcfg.s.ddrsel = 0;
423 usbcx_gusbcfg.s.usbtrdtim = 0x5;
424 usbcx_gusbcfg.s.phylpwrclksel = 0;
425 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index), usbcx_gusbcfg.u32);
428 /* Program the following fields in the USBC0/1_DCFG register:
429 Device speed, USBC0/1_DCFG[DEVSPD] = 0 (high speed)
430 Non-zero-length status OUT handshake, USBC0/1_DCFG[NZSTSOUTHSHK]=0
431 Periodic frame interval (if periodic endpoints are supported),
432 USBC0/1_DCFG[PERFRINT] = 1 */
434 cvmx_usbcx_dcfg_t usbcx_dcfg;
435 usbcx_dcfg.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCFG(usb->index));
436 usbcx_dcfg.s.devspd = 0;
437 usbcx_dcfg.s.nzstsouthshk = 0;
438 usbcx_dcfg.s.perfrint = 1;
439 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DCFG(usb->index), usbcx_dcfg.u32);
442 /* Program the USBC0/1_GINTMSK register */
444 cvmx_usbcx_gintmsk_t usbcx_gintmsk;
445 usbcx_gintmsk.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GINTMSK(usb->index));
446 usbcx_gintmsk.s.oepintmsk = 1;
447 usbcx_gintmsk.s.inepintmsk = 1;
448 usbcx_gintmsk.s.enumdonemsk = 1;
449 usbcx_gintmsk.s.usbrstmsk = 1;
450 usbcx_gintmsk.s.usbsuspmsk = 1;
451 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index), usbcx_gintmsk.u32);
454 cvmx_usbd_disable(usb);
457 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
458 EXPORT_SYMBOL(cvmx_usbd_initialize);
463 * Shutdown a USB port after a call to cvmx_usbd_initialize().
465 * @param usb USB device state populated by
466 * cvmx_usbd_initialize().
468 * @return Zero or a negative on error.
470 int cvmx_usbd_shutdown(cvmx_usbd_state_t *usb)
472 cvmx_usbnx_clk_ctl_t usbn_clk_ctl;
474 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
475 cvmx_dprintf("%s: Called\n", __FUNCTION__);
477 /* Disable the clocks and put them in power on reset */
478 usbn_clk_ctl.u64 = cvmx_read_csr(CVMX_USBNX_CLK_CTL(usb->index));
479 usbn_clk_ctl.s.enable = 1;
480 usbn_clk_ctl.s.por = 1;
481 usbn_clk_ctl.s.hclk_rst = 1;
482 usbn_clk_ctl.s.prst = 0;
483 usbn_clk_ctl.s.hrst = 0;
484 cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
487 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
488 EXPORT_SYMBOL(cvmx_usbd_shutdown);
493 * Enable a USB port. After this call succeeds, the USB port is
494 * online and servicing requests.
496 * @param usb USB device state populated by
497 * cvmx_usb_initialize().
499 * @return Zero or negative on error.
501 int cvmx_usbd_enable(cvmx_usbd_state_t *usb)
503 cvmx_usbcx_dctl_t usbcx_dctl;
504 usbcx_dctl.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCTL(usb->index));
505 usbcx_dctl.s.cgoutnak = 1;
506 usbcx_dctl.s.sftdiscon = 0;
507 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DCTL(usb->index), usbcx_dctl.u32);
510 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
511 EXPORT_SYMBOL(cvmx_usbd_enable);
516 * Disable a USB port. After this call the USB port will not
517 * generate data transfers and will not generate events.
519 * @param usb USB device state populated by
520 * cvmx_usb_initialize().
522 * @return Zero or negative on error.
524 int cvmx_usbd_disable(cvmx_usbd_state_t *usb)
526 cvmx_usbcx_dctl_t usbcx_dctl;
527 usbcx_dctl.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCTL(usb->index));
528 usbcx_dctl.s.sgoutnak = 1;
529 usbcx_dctl.s.sftdiscon = 1;
530 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DCTL(usb->index), usbcx_dctl.u32);
533 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
534 EXPORT_SYMBOL(cvmx_usbd_disable);
539 * Register a callback function to process USB events
541 * @param usb USB device state populated by
542 * cvmx_usbd_initialize().
543 * @param reason The reason this callback should be called
544 * @param func Function to call
545 * @param user_data User supplied data for the callback
547 * @return Zero on succes, negative on failure
549 int cvmx_usbd_register(cvmx_usbd_state_t *usb, cvmx_usbd_callback_t reason, cvmx_usbd_callback_func_t func, void *user_data)
551 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
552 cvmx_dprintf("%s: Register reason=%d func=%p data=%p\n",
553 __FUNCTION__, reason, func, user_data);
554 usb->callback[reason] = func;
555 usb->callback_data[reason] = user_data;
558 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
559 EXPORT_SYMBOL(cvmx_usbd_register);
564 * Poll a device mode endpoint for status
566 * @param usb USB device state populated by
567 * cvmx_usbd_initialize().
568 * @param endpoint_num
571 * @return Zero on success
573 static int __cvmx_usbd_poll_in_endpoint(cvmx_usbd_state_t *usb, int endpoint_num)
575 cvmx_usbcx_diepintx_t usbc_diepint;
577 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
578 cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num);
580 usbc_diepint.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DIEPINTX(endpoint_num, usb->index));
581 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPINTX(endpoint_num, usb->index), usbc_diepint.u32);
583 if (usbc_diepint.s.epdisbld)
585 /* Endpoint Disabled Interrupt (EPDisbld)
586 This bit indicates that the endpoint is disabled per the
587 application's request. */
590 if (usbc_diepint.s.xfercompl)
592 cvmx_usbcx_dieptsizx_t usbc_dieptsiz;
593 int bytes_transferred;
594 /* Transfer Completed Interrupt (XferCompl)
595 Indicates that the programmed transfer is complete on the AHB
596 as well as on the USB, for this endpoint. */
597 usbc_dieptsiz.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DIEPTSIZX(endpoint_num, usb->index));
598 bytes_transferred = usb->endpoint[endpoint_num].buffer_length - usbc_dieptsiz.s.xfersize;
599 __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_IN_COMPLETE, endpoint_num, bytes_transferred);
607 * Poll a device mode endpoint for status
609 * @param usb USB device state populated by
610 * cvmx_usbd_initialize().
611 * @param endpoint_num
614 * @return Zero on success
616 static int __cvmx_usbd_poll_out_endpoint(cvmx_usbd_state_t *usb, int endpoint_num)
618 cvmx_usbcx_doepintx_t usbc_doepint;
620 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
621 cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num);
623 usbc_doepint.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DOEPINTX(endpoint_num, usb->index));
624 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPINTX(endpoint_num, usb->index), usbc_doepint.u32);
626 if (usbc_doepint.s.setup)
628 /* SETUP Phase Done (SetUp)
629 Applies to control OUT endpoints only.
630 Indicates that the SETUP phase for the control endpoint is
631 complete and no more back-to-back SETUP packets were
632 received for the current control transfer. On this interrupt, the
633 application can decode the received SETUP data packet. */
634 __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_DEVICE_SETUP, endpoint_num, 0);
636 if (usbc_doepint.s.epdisbld)
638 /* Endpoint Disabled Interrupt (EPDisbld)
639 This bit indicates that the endpoint is disabled per the
640 application's request. */
643 if (usbc_doepint.s.xfercompl)
645 cvmx_usbcx_doeptsizx_t usbc_doeptsiz;
646 int bytes_transferred;
647 /* Transfer Completed Interrupt (XferCompl)
648 Indicates that the programmed transfer is complete on the AHB
649 as well as on the USB, for this endpoint. */
650 usbc_doeptsiz.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DOEPTSIZX(endpoint_num, usb->index));
651 bytes_transferred = usb->endpoint[endpoint_num].buffer_length - usbc_doeptsiz.s.xfersize;
652 __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_OUT_COMPLETE, endpoint_num, bytes_transferred);
660 * Poll the USB block for status and call all needed callback
661 * handlers. This function is meant to be called in the interrupt
662 * handler for the USB controller. It can also be called
663 * periodically in a loop for non-interrupt based operation.
665 * @param usb USB device state populated by
666 * cvmx_usbd_initialize().
668 * @return Zero or negative on error.
670 int cvmx_usbd_poll(cvmx_usbd_state_t *usb)
672 cvmx_usbcx_gintsts_t usbc_gintsts;
674 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
675 cvmx_dprintf("%s: Called\n", __FUNCTION__);
677 /* Read the pending interrupts */
678 usbc_gintsts.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GINTSTS(usb->index));
679 usbc_gintsts.u32 &= __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GINTMSK(usb->index));
681 /* Clear the interrupts now that we know about them */
682 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32);
684 if (usbc_gintsts.s.usbsusp)
685 __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_SUSPEND, 0, 0);
687 if (usbc_gintsts.s.enumdone)
688 __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_ENUM_COMPLETE, 0, 0);
690 if (usbc_gintsts.s.usbrst)
692 /* USB Reset (USBRst)
693 The core sets this bit to indicate that a reset is
694 detected on the USB. */
695 __cvmx_usbd_device_reset_complete(usb);
696 __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_RESET, 0, 0);
699 if (usbc_gintsts.s.oepint || usbc_gintsts.s.iepint)
701 cvmx_usbcx_daint_t usbc_daint;
702 usbc_daint.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DAINT(usb->index));
703 if (usbc_daint.s.inepint)
705 int active_endpoints = usbc_daint.s.inepint;
707 while (active_endpoints)
710 CVMX_CLZ(endpoint, active_endpoints);
711 endpoint = 31 - endpoint;
712 __cvmx_usbd_poll_in_endpoint(usb, endpoint);
713 active_endpoints ^= 1<<endpoint;
716 if (usbc_daint.s.outepint)
718 int active_endpoints = usbc_daint.s.outepint;
720 while (active_endpoints)
723 CVMX_CLZ(endpoint, active_endpoints);
724 endpoint = 31 - endpoint;
725 __cvmx_usbd_poll_out_endpoint(usb, endpoint);
726 active_endpoints ^= 1<<endpoint;
733 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
734 EXPORT_SYMBOL(cvmx_usbd_poll);
738 * Get the current USB address
740 * @param usb USB device state populated by
741 * cvmx_usbd_initialize().
743 * @return The USB address
745 int cvmx_usbd_get_address(cvmx_usbd_state_t *usb)
747 cvmx_usbcx_dcfg_t usbc_dcfg;
748 usbc_dcfg.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCFG(usb->index));
749 return usbc_dcfg.s.devaddr;
751 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
752 EXPORT_SYMBOL(cvmx_usbd_get_address);
756 * Set the current USB address
758 * @param usb USB device state populated by
759 * cvmx_usbd_initialize().
760 * @param address Address to set
762 void cvmx_usbd_set_address(cvmx_usbd_state_t *usb, int address)
764 cvmx_usbcx_dcfg_t usbc_dcfg;
765 usbc_dcfg.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCFG(usb->index));
766 usbc_dcfg.s.devaddr = address;
767 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DCFG(usb->index), usbc_dcfg.u32);
769 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
770 EXPORT_SYMBOL(cvmx_usbd_set_address);
774 * Get the current USB speed
776 * @param usb USB device state populated by
777 * cvmx_usbd_initialize().
779 * @return The USB speed
781 cvmx_usbd_speed_t cvmx_usbd_get_speed(cvmx_usbd_state_t *usb)
783 cvmx_usbcx_dsts_t usbcx_dsts;
784 usbcx_dsts.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DSTS(usb->index));
785 return usbcx_dsts.s.enumspd;
787 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
788 EXPORT_SYMBOL(cvmx_usbd_get_speed);
792 * Set the current USB speed
794 * @param usb USB device state populated by
795 * cvmx_usbd_initialize().
796 * @param speed The requested speed
798 void cvmx_usbd_set_speed(cvmx_usbd_state_t *usb, cvmx_usbd_speed_t speed)
800 cvmx_usbcx_dcfg_t usbcx_dcfg;
801 usbcx_dcfg.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCFG(usb->index));
802 usbcx_dcfg.s.devspd = speed;
803 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DCFG(usb->index), usbcx_dcfg.u32);
805 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
806 EXPORT_SYMBOL(cvmx_usbd_set_speed);
810 * Enable an endpoint to respond to an OUT transaction
812 * @param usb USB device state populated by
813 * cvmx_usbd_initialize().
814 * @param endpoint_num
815 * Endpoint number to enable
816 * @param transfer_type
817 * Transfer type for the endpoint
818 * @param max_packet_size
819 * Maximum packet size for the endpoint
820 * @param buffer Buffer to receive the data
821 * @param buffer_length
822 * Length of the buffer in bytes
824 * @return Zero on success, negative on failure
826 int cvmx_usbd_out_endpoint_enable(cvmx_usbd_state_t *usb,
827 int endpoint_num, cvmx_usbd_transfer_t transfer_type,
828 int max_packet_size, uint64_t buffer, int buffer_length)
830 cvmx_usbcx_doepctlx_t usbc_doepctl;
831 cvmx_usbcx_doeptsizx_t usbc_doeptsiz;
833 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
834 cvmx_dprintf("%s: endpoint=%d buffer=0x%llx length=%d\n",
835 __FUNCTION__, endpoint_num, (ULL)buffer, buffer_length);
837 usb->endpoint[endpoint_num].buffer_length = buffer_length;
839 CVMX_SYNCW; /* Flush out pending writes before enable */
841 /* Clear any pending interrupts */
842 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPINTX(endpoint_num, usb->index),
843 __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DOEPINTX(endpoint_num, usb->index)));
845 /* Setup the locations the DMA engines use */
846 cvmx_write_csr(CVMX_USBNX_DMA0_INB_CHN0(usb->index) + endpoint_num*8, buffer);
848 usbc_doeptsiz.u32 = 0;
849 usbc_doeptsiz.s.mc = 1;
850 usbc_doeptsiz.s.pktcnt = (buffer_length + max_packet_size - 1) / max_packet_size;
851 if (usbc_doeptsiz.s.pktcnt == 0)
852 usbc_doeptsiz.s.pktcnt = 1;
853 usbc_doeptsiz.s.xfersize = buffer_length;
854 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPTSIZX(endpoint_num, usb->index), usbc_doeptsiz.u32);
856 usbc_doepctl.u32 = 0;
857 usbc_doepctl.s.epena = 1;
858 usbc_doepctl.s.setd1pid = 0;
859 usbc_doepctl.s.setd0pid = 0;
860 usbc_doepctl.s.cnak = 1;
861 usbc_doepctl.s.eptype = transfer_type;
862 usbc_doepctl.s.usbactep = 1;
863 if (endpoint_num == 0)
865 switch (max_packet_size)
868 usbc_doepctl.s.mps = 3;
871 usbc_doepctl.s.mps = 2;
874 usbc_doepctl.s.mps = 1;
877 usbc_doepctl.s.mps = 0;
882 usbc_doepctl.s.mps = max_packet_size;
883 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPCTLX(endpoint_num, usb->index), usbc_doepctl.u32);
887 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
888 EXPORT_SYMBOL(cvmx_usbd_out_endpoint_enable);
893 * Disable an OUT endpoint
895 * @param usb USB device state populated by
896 * cvmx_usbd_initialize().
897 * @param endpoint_num
898 * Endpoint number to disable
900 * @return Zero on success, negative on failure
902 int cvmx_usbd_out_endpoint_disable(cvmx_usbd_state_t *usb, int endpoint_num)
904 cvmx_usbcx_doepctlx_t usbc_doepctl;
906 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
907 cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num);
909 usbc_doepctl.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DOEPCTLX(endpoint_num, usb->index));
910 if (usbc_doepctl.s.epena && !usbc_doepctl.s.epdis)
912 usbc_doepctl.s.epdis = 1;
913 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPCTLX(endpoint_num, usb->index), usbc_doepctl.u32);
917 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
918 EXPORT_SYMBOL(cvmx_usbd_out_endpoint_disable);
923 * Enable an endpoint to respond to an IN transaction
925 * @param usb USB device state populated by
926 * cvmx_usbd_initialize().
927 * @param endpoint_num
928 * Endpoint number to enable
929 * @param transfer_type
930 * Transfer type for the endpoint
931 * @param max_packet_size
932 * Maximum packet size for the endpoint
933 * @param buffer Buffer to send
934 * @param buffer_length
935 * Length of the buffer in bytes
937 * @return Zero on success, negative on failure
939 int cvmx_usbd_in_endpoint_enable(cvmx_usbd_state_t *usb,
940 int endpoint_num, cvmx_usbd_transfer_t transfer_type,
941 int max_packet_size, uint64_t buffer, int buffer_length)
943 cvmx_usbcx_diepctlx_t usbc_diepctl;
944 cvmx_usbcx_dieptsizx_t usbc_dieptsiz;
946 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
947 cvmx_dprintf("%s: endpoint=%d buffer=0x%llx length=%d\n",
948 __FUNCTION__, endpoint_num, (ULL)buffer, buffer_length);
950 usb->endpoint[endpoint_num].buffer_length = buffer_length;
952 CVMX_SYNCW; /* Flush out pending writes before enable */
954 /* Clear any pending interrupts */
955 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPINTX(endpoint_num, usb->index),
956 __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DIEPINTX(endpoint_num, usb->index)));
958 usbc_dieptsiz.u32 = 0;
959 usbc_dieptsiz.s.mc = 1;
962 cvmx_write_csr(CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + endpoint_num*8, buffer);
963 usbc_dieptsiz.s.pktcnt = (buffer_length + max_packet_size - 1) / max_packet_size;
964 if (usbc_dieptsiz.s.pktcnt == 0)
965 usbc_dieptsiz.s.pktcnt = 1;
966 usbc_dieptsiz.s.xfersize = buffer_length;
970 usbc_dieptsiz.s.pktcnt = 0;
971 usbc_dieptsiz.s.xfersize = 0;
973 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPTSIZX(endpoint_num, usb->index), usbc_dieptsiz.u32);
975 usbc_diepctl.u32 = 0;
976 usbc_diepctl.s.epena = (buffer != 0);
977 usbc_diepctl.s.setd1pid = 0;
978 usbc_diepctl.s.setd0pid = (buffer == 0);
979 usbc_diepctl.s.cnak = 1;
980 usbc_diepctl.s.txfnum = endpoint_num;
981 usbc_diepctl.s.eptype = transfer_type;
982 usbc_diepctl.s.usbactep = 1;
983 usbc_diepctl.s.nextep = endpoint_num;
984 if (endpoint_num == 0)
986 switch (max_packet_size)
989 usbc_diepctl.s.mps = 3;
992 usbc_diepctl.s.mps = 2;
995 usbc_diepctl.s.mps = 1;
998 usbc_diepctl.s.mps = 0;
1003 usbc_diepctl.s.mps = max_packet_size;
1004 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPCTLX(endpoint_num, usb->index), usbc_diepctl.u32);
1008 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1009 EXPORT_SYMBOL(cvmx_usbd_in_endpoint_enable);
1014 * Disable an IN endpoint
1016 * @param usb USB device state populated by
1017 * cvmx_usbd_initialize().
1018 * @param endpoint_num
1019 * Endpoint number to disable
1021 * @return Zero on success, negative on failure
1023 int cvmx_usbd_in_endpoint_disable(cvmx_usbd_state_t *usb, int endpoint_num)
1025 cvmx_usbcx_diepctlx_t usbc_diepctl;
1027 if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
1028 cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num);
1030 usbc_diepctl.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DIEPCTLX(endpoint_num, usb->index));
1031 if (usbc_diepctl.s.epena && !usbc_diepctl.s.epdis)
1033 usbc_diepctl.s.epdis = 1;
1034 __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPCTLX(endpoint_num, usb->index), usbc_diepctl.u32);
1038 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1039 EXPORT_SYMBOL(cvmx_usbd_in_endpoint_disable);