]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/octeon-sdk/cvmx-usbd.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / octeon-sdk / cvmx-usbd.c
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  */
86 static 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  */
103 static 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  */
121 static 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  */
150 static 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  */
238 int 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
458 EXPORT_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  */
470 int 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
488 EXPORT_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  */
501 int 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
511 EXPORT_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  */
524 int 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
534 EXPORT_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  */
549 int 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
559 EXPORT_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  */
573 static 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  */
616 static 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  */
670 int 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
734 EXPORT_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  */
745 int 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
752 EXPORT_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  */
762 void 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
770 EXPORT_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  */
781 cvmx_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
788 EXPORT_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  */
798 void 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
806 EXPORT_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  */
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)
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
888 EXPORT_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  */
902 int 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
918 EXPORT_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  */
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)
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
1009 EXPORT_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  */
1023 int 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
1039 EXPORT_SYMBOL(cvmx_usbd_in_endpoint_disable);
1040 #endif
1041