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