1/***********************license start***************
2 * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). 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  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
26 * 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 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**************************************/
39
40
41/**
42 * @file
43 *
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
48 * operations.
49 *
50 * <hr>$Revision: 32636 $<hr>
51 */
52
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>
63#else
64#include "cvmx.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"
71#endif
72
73#define ULL unsigned long long
74
75/**
76 * @INTERNAL
77 * Read a USB 32bit CSR. It performs the necessary address swizzle for 32bit
78 * CSRs.
79 *
80 * @param usb     USB device state populated by
81 *                cvmx_usbd_initialize().
82 * @param address 64bit address to read
83 *
84 * @return Result of the read
85 */
86static inline uint32_t __cvmx_usbd_read_csr32(cvmx_usbd_state_t *usb, uint64_t address)
87{
88    uint32_t result = cvmx_read64_uint32(address ^ 4);
89    return result;
90}
91
92
93/**
94 * @INTERNAL
95 * Write a USB 32bit CSR. It performs the necessary address swizzle for 32bit
96 * CSRs.
97 *
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
102 */
103static inline void __cvmx_usbd_write_csr32(cvmx_usbd_state_t *usb, uint64_t address, uint32_t value)
104{
105    cvmx_write64_uint32(address ^ 4, value);
106    cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
107}
108
109/**
110 * @INTERNAL
111 * Calls the user supplied callback when an event happens.
112 *
113 * @param usb    USB device state populated by
114 *               cvmx_usbd_initialize().
115 * @param reason Reason for the callback
116 * @param endpoint_num
117 *               Endpoint number
118 * @param bytes_transferred
119 *               Bytes transferred
120 */
121static void __cvmx_usbd_callback(cvmx_usbd_state_t *usb, cvmx_usbd_callback_t reason, int endpoint_num, int bytes_transferred)
122{
123    if (usb->callback[reason])
124    {
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]);
129    }
130    else
131    {
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);
135    }
136}
137
138/**
139 * @INTERNAL
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",
143 * in the manual.
144 *
145 * @param usb    USB device state populated by
146 *               cvmx_usbd_initialize().
147 *
148 * @return Zero or negative on error.
149 */
150static int __cvmx_usbd_device_reset_complete(cvmx_usbd_state_t *usb)
151{
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;
158    int fifo_space;
159    int i;
160
161    if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
162        cvmx_dprintf("%s: Processing reset\n", __FUNCTION__);
163
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));
166
167    /* Set up the data FIFO RAM for each of the FIFOs */
168    fifo_space = usbcx_ghwcfg3.s.dfifodepth;
169
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--)
172    {
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);
178    }
179
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);
186
187    /* Assign the remain space to the RX fifo */
188    __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GRXFSIZ(usb->index), fifo_space);
189
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);
200
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);
205
206    /* Set all endpoints to NAK */
207    for (i=0; i<usbcx_ghwcfg2.s.numdeveps+1; i++)
208    {
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);
215    }
216
217    return 0;
218}
219
220
221/**
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.
225 *
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
229 *               functions.
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.
235 *
236 * @return Zero or a negative on error.
237 */
238int cvmx_usbd_initialize(cvmx_usbd_state_t *usb,
239                                      int usb_port_number,
240                                      cvmx_usbd_initialize_flags_t flags)
241{
242    cvmx_usbnx_clk_ctl_t usbn_clk_ctl;
243    cvmx_usbnx_usbp_ctl_status_t usbn_usbp_ctl_status;
244
245    if (cvmx_unlikely(flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
246        cvmx_dprintf("%s: Called\n", __FUNCTION__);
247
248    memset(usb, 0, sizeof(*usb));
249    usb->init_flags = flags;
250    usb->index = usb_port_number;
251
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)
255    {
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 */
258        else
259            usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_GND;
260    }
261
262    if (usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_GND)
263    {
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())
267            {
268                case USB_CLOCK_TYPE_REF_12:
269                    usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_12MHZ;
270                    break;
271                case USB_CLOCK_TYPE_REF_24:
272                    usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_24MHZ;
273                    break;
274                case USB_CLOCK_TYPE_REF_48:
275                default:
276                    usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_48MHZ;
277                    break;
278            }
279    }
280
281    /* Power On Reset and PHY Initialization */
282
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)
295    {
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))
300        {
301            usbn_clk_ctl.cn31xx.p_rclk  = 1; /* From CN31XX,CN30XX manual */
302            usbn_clk_ctl.cn31xx.p_xenbn = 0;
303        }
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 */
306        else
307            usbn_clk_ctl.cn52xx.p_rtype = 1; /* From CN52XX manual */
308
309        switch (usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_CLOCK_MHZ_MASK)
310        {
311            case CVMX_USBD_INITIALIZE_FLAGS_CLOCK_12MHZ:
312                usbn_clk_ctl.s.p_c_sel = 0;
313                break;
314            case CVMX_USBD_INITIALIZE_FLAGS_CLOCK_24MHZ:
315                usbn_clk_ctl.s.p_c_sel = 1;
316                break;
317            case CVMX_USBD_INITIALIZE_FLAGS_CLOCK_48MHZ:
318                usbn_clk_ctl.s.p_c_sel = 2;
319                break;
320        }
321    }
322    else
323    {
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))
327        {
328            usbn_clk_ctl.cn31xx.p_rclk  = 1; /* From CN31XX,CN30XX manual */
329            usbn_clk_ctl.cn31xx.p_xenbn = 1;
330        }
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 */
333        else
334            usbn_clk_ctl.cn52xx.p_rtype = 0; /* From CN52XX manual */
335
336        usbn_clk_ctl.s.p_c_sel = 0;
337    }
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 */
341    {
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 */
344            divisor = 4;
345        usbn_clk_ctl.s.divide = divisor;
346        usbn_clk_ctl.s.divide2 = 0;
347    }
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 */
353    cvmx_wait(64);
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 */
366    cvmx_wait(10);
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
377        device */
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);
382    /* 10. Wait 1 �s */
383    cvmx_wait_usec(1);
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);
391    cvmx_wait_usec(1);
392
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 */
402    {
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);
411    }
412
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 */
418    {
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);
426    }
427
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 */
433    {
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);
440    }
441
442    /* Program the USBC0/1_GINTMSK register */
443    {
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);
452    }
453
454    cvmx_usbd_disable(usb);
455    return 0;
456}
457#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
458EXPORT_SYMBOL(cvmx_usbd_initialize);
459#endif
460
461
462/**
463 * Shutdown a USB port after a call to cvmx_usbd_initialize().
464 *
465 * @param usb    USB device state populated by
466 *               cvmx_usbd_initialize().
467 *
468 * @return Zero or a negative on error.
469 */
470int cvmx_usbd_shutdown(cvmx_usbd_state_t *usb)
471{
472    cvmx_usbnx_clk_ctl_t usbn_clk_ctl;
473
474    if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
475        cvmx_dprintf("%s: Called\n", __FUNCTION__);
476
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);
485    return 0;
486}
487#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
488EXPORT_SYMBOL(cvmx_usbd_shutdown);
489#endif
490
491
492/**
493 * Enable a USB port. After this call succeeds, the USB port is
494 * online and servicing requests.
495 *
496 * @param usb  USB device state populated by
497 *               cvmx_usb_initialize().
498 *
499 * @return Zero or negative on error.
500 */
501int cvmx_usbd_enable(cvmx_usbd_state_t *usb)
502{
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);
508    return 0;
509}
510#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
511EXPORT_SYMBOL(cvmx_usbd_enable);
512#endif
513
514
515/**
516 * Disable a USB port. After this call the USB port will not
517 * generate data transfers and will not generate events.
518 *
519 * @param usb    USB device state populated by
520 *               cvmx_usb_initialize().
521 *
522 * @return Zero or negative on error.
523 */
524int cvmx_usbd_disable(cvmx_usbd_state_t *usb)
525{
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);
531    return 0;
532}
533#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
534EXPORT_SYMBOL(cvmx_usbd_disable);
535#endif
536
537
538/**
539 * Register a callback function to process USB events
540 *
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
546 *
547 * @return Zero on succes, negative on failure
548 */
549int cvmx_usbd_register(cvmx_usbd_state_t *usb, cvmx_usbd_callback_t reason, cvmx_usbd_callback_func_t func, void *user_data)
550{
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;
556    return 0;
557}
558#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
559EXPORT_SYMBOL(cvmx_usbd_register);
560#endif
561
562/**
563 * @INTERNAL
564 * Poll a device mode endpoint for status
565 *
566 * @param usb    USB device state populated by
567 *               cvmx_usbd_initialize().
568 * @param endpoint_num
569 *               Endpoint to poll
570 *
571 * @return Zero on success
572 */
573static int __cvmx_usbd_poll_in_endpoint(cvmx_usbd_state_t *usb, int endpoint_num)
574{
575    cvmx_usbcx_diepintx_t usbc_diepint;
576
577    if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
578        cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num);
579
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);
582
583    if (usbc_diepint.s.epdisbld)
584    {
585        /* Endpoint Disabled Interrupt (EPDisbld)
586            This bit indicates that the endpoint is disabled per the
587            application's request. */
588        /* Nothing to do */
589    }
590    if (usbc_diepint.s.xfercompl)
591    {
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);
600    }
601    return 0;
602}
603
604
605/**
606 * @INTERNAL
607 * Poll a device mode endpoint for status
608 *
609 * @param usb    USB device state populated by
610 *               cvmx_usbd_initialize().
611 * @param endpoint_num
612 *               Endpoint to poll
613 *
614 * @return Zero on success
615 */
616static int __cvmx_usbd_poll_out_endpoint(cvmx_usbd_state_t *usb, int endpoint_num)
617{
618    cvmx_usbcx_doepintx_t usbc_doepint;
619
620    if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
621        cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num);
622
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);
625
626    if (usbc_doepint.s.setup)
627    {
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);
635    }
636    if (usbc_doepint.s.epdisbld)
637    {
638        /* Endpoint Disabled Interrupt (EPDisbld)
639            This bit indicates that the endpoint is disabled per the
640            application's request. */
641        /* Nothing to do */
642    }
643    if (usbc_doepint.s.xfercompl)
644    {
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);
653    }
654
655    return 0;
656}
657
658
659/**
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.
664 *
665 * @param usb    USB device state populated by
666 *               cvmx_usbd_initialize().
667 *
668 * @return Zero or negative on error.
669 */
670int cvmx_usbd_poll(cvmx_usbd_state_t *usb)
671{
672    cvmx_usbcx_gintsts_t usbc_gintsts;
673
674    if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
675        cvmx_dprintf("%s: Called\n", __FUNCTION__);
676
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));
680
681    /* Clear the interrupts now that we know about them */
682    __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32);
683
684    if (usbc_gintsts.s.usbsusp)
685        __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_SUSPEND, 0, 0);
686
687    if (usbc_gintsts.s.enumdone)
688        __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_ENUM_COMPLETE, 0, 0);
689
690    if (usbc_gintsts.s.usbrst)
691    {
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);
697    }
698
699    if (usbc_gintsts.s.oepint || usbc_gintsts.s.iepint)
700    {
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)
704        {
705            int active_endpoints = usbc_daint.s.inepint;
706
707            while (active_endpoints)
708            {
709                int endpoint;
710                CVMX_CLZ(endpoint, active_endpoints);
711                endpoint = 31 - endpoint;
712                __cvmx_usbd_poll_in_endpoint(usb, endpoint);
713                active_endpoints ^= 1<<endpoint;
714            }
715        }
716        if (usbc_daint.s.outepint)
717        {
718            int active_endpoints = usbc_daint.s.outepint;
719
720            while (active_endpoints)
721            {
722                int endpoint;
723                CVMX_CLZ(endpoint, active_endpoints);
724                endpoint = 31 - endpoint;
725                __cvmx_usbd_poll_out_endpoint(usb, endpoint);
726                active_endpoints ^= 1<<endpoint;
727            }
728        }
729    }
730
731    return 0;
732}
733#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
734EXPORT_SYMBOL(cvmx_usbd_poll);
735#endif
736
737/**
738 * Get the current USB address
739 *
740 * @param usb    USB device state populated by
741 *               cvmx_usbd_initialize().
742 *
743 * @return The USB address
744 */
745int cvmx_usbd_get_address(cvmx_usbd_state_t *usb)
746{
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;
750}
751#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
752EXPORT_SYMBOL(cvmx_usbd_get_address);
753#endif
754
755/**
756 * Set the current USB address
757 *
758 * @param usb     USB device state populated by
759 *                cvmx_usbd_initialize().
760 * @param address Address to set
761 */
762void cvmx_usbd_set_address(cvmx_usbd_state_t *usb, int address)
763{
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);
768}
769#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
770EXPORT_SYMBOL(cvmx_usbd_set_address);
771#endif
772
773/**
774 * Get the current USB speed
775 *
776 * @param usb    USB device state populated by
777 *               cvmx_usbd_initialize().
778 *
779 * @return The USB speed
780 */
781cvmx_usbd_speed_t cvmx_usbd_get_speed(cvmx_usbd_state_t *usb)
782{
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;
786}
787#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
788EXPORT_SYMBOL(cvmx_usbd_get_speed);
789#endif
790
791/**
792 * Set the current USB speed
793 *
794 * @param usb    USB device state populated by
795 *               cvmx_usbd_initialize().
796 * @param speed  The requested speed
797 */
798void cvmx_usbd_set_speed(cvmx_usbd_state_t *usb, cvmx_usbd_speed_t speed)
799{
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);
804}
805#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
806EXPORT_SYMBOL(cvmx_usbd_set_speed);
807#endif
808
809/**
810 * Enable an endpoint to respond to an OUT transaction
811 *
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
823 *
824 * @return Zero on success, negative on failure
825 */
826int 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)
829{
830    cvmx_usbcx_doepctlx_t usbc_doepctl;
831    cvmx_usbcx_doeptsizx_t usbc_doeptsiz;
832
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);
836
837    usb->endpoint[endpoint_num].buffer_length = buffer_length;
838
839    CVMX_SYNCW; /* Flush out pending writes before enable */
840
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)));
844
845    /* Setup the locations the DMA engines use  */
846    cvmx_write_csr(CVMX_USBNX_DMA0_INB_CHN0(usb->index) + endpoint_num*8, buffer);
847
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);
855
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)
864    {
865        switch (max_packet_size)
866        {
867            case 8:
868                usbc_doepctl.s.mps = 3;
869                break;
870            case 16:
871                usbc_doepctl.s.mps = 2;
872                break;
873            case 32:
874                usbc_doepctl.s.mps = 1;
875                break;
876            default:
877                usbc_doepctl.s.mps = 0;
878                break;
879        }
880    }
881    else
882        usbc_doepctl.s.mps = max_packet_size;
883    __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPCTLX(endpoint_num, usb->index), usbc_doepctl.u32);
884
885    return 0;
886}
887#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
888EXPORT_SYMBOL(cvmx_usbd_out_endpoint_enable);
889#endif
890
891
892/**
893 * Disable an OUT endpoint
894 *
895 * @param usb    USB device state populated by
896 *               cvmx_usbd_initialize().
897 * @param endpoint_num
898 *               Endpoint number to disable
899 *
900 * @return Zero on success, negative on failure
901 */
902int cvmx_usbd_out_endpoint_disable(cvmx_usbd_state_t *usb, int endpoint_num)
903{
904    cvmx_usbcx_doepctlx_t usbc_doepctl;
905
906    if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
907        cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num);
908
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)
911    {
912        usbc_doepctl.s.epdis = 1;
913        __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPCTLX(endpoint_num, usb->index), usbc_doepctl.u32);
914    }
915    return 0;
916}
917#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
918EXPORT_SYMBOL(cvmx_usbd_out_endpoint_disable);
919#endif
920
921
922/**
923 * Enable an endpoint to respond to an IN transaction
924 *
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
936 *
937 * @return Zero on success, negative on failure
938 */
939int 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)
942{
943    cvmx_usbcx_diepctlx_t usbc_diepctl;
944    cvmx_usbcx_dieptsizx_t usbc_dieptsiz;
945
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);
949
950    usb->endpoint[endpoint_num].buffer_length = buffer_length;
951
952    CVMX_SYNCW; /* Flush out pending writes before enable */
953
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)));
957
958    usbc_dieptsiz.u32 = 0;
959    usbc_dieptsiz.s.mc = 1;
960    if (buffer)
961    {
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;
967    }
968    else
969    {
970        usbc_dieptsiz.s.pktcnt = 0;
971        usbc_dieptsiz.s.xfersize = 0;
972    }
973    __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPTSIZX(endpoint_num, usb->index), usbc_dieptsiz.u32);
974
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)
985    {
986        switch (max_packet_size)
987        {
988            case 8:
989                usbc_diepctl.s.mps = 3;
990                break;
991            case 16:
992                usbc_diepctl.s.mps = 2;
993                break;
994            case 32:
995                usbc_diepctl.s.mps = 1;
996                break;
997            default:
998                usbc_diepctl.s.mps = 0;
999                break;
1000        }
1001    }
1002    else
1003        usbc_diepctl.s.mps = max_packet_size;
1004    __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPCTLX(endpoint_num, usb->index), usbc_diepctl.u32);
1005
1006    return 0;
1007}
1008#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1009EXPORT_SYMBOL(cvmx_usbd_in_endpoint_enable);
1010#endif
1011
1012
1013/**
1014 * Disable an IN endpoint
1015 *
1016 * @param usb    USB device state populated by
1017 *               cvmx_usbd_initialize().
1018 * @param endpoint_num
1019 *               Endpoint number to disable
1020 *
1021 * @return Zero on success, negative on failure
1022 */
1023int cvmx_usbd_in_endpoint_disable(cvmx_usbd_state_t *usb, int endpoint_num)
1024{
1025    cvmx_usbcx_diepctlx_t usbc_diepctl;
1026
1027    if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG))
1028        cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num);
1029
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)
1032    {
1033        usbc_diepctl.s.epdis = 1;
1034        __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPCTLX(endpoint_num, usb->index), usbc_diepctl.u32);
1035    }
1036    return 0;
1037}
1038#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1039EXPORT_SYMBOL(cvmx_usbd_in_endpoint_disable);
1040#endif
1041
1042