1215976Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3215976Sjmallett * reserved. 4215976Sjmallett * 5215976Sjmallett * 6215976Sjmallett * Redistribution and use in source and binary forms, with or without 7215976Sjmallett * modification, are permitted provided that the following conditions are 8215976Sjmallett * met: 9215976Sjmallett * 10215976Sjmallett * * Redistributions of source code must retain the above copyright 11215976Sjmallett * notice, this list of conditions and the following disclaimer. 12215976Sjmallett * 13215976Sjmallett * * Redistributions in binary form must reproduce the above 14215976Sjmallett * copyright notice, this list of conditions and the following 15215976Sjmallett * disclaimer in the documentation and/or other materials provided 16215976Sjmallett * with the distribution. 17215976Sjmallett 18232812Sjmallett * * Neither the name of Cavium Inc. nor the names of 19215976Sjmallett * its contributors may be used to endorse or promote products 20215976Sjmallett * derived from this software without specific prior written 21215976Sjmallett * permission. 22215976Sjmallett 23215976Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215976Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215976Sjmallett * regulations, and may be subject to export or import regulations in other 26215976Sjmallett * countries. 27215976Sjmallett 28215976Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30215976Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215976Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215976Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215976Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215976Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215976Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215976Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215976Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38215976Sjmallett ***********************license end**************************************/ 39215976Sjmallett 40215976Sjmallett 41215976Sjmallett/** 42215976Sjmallett * @file 43215976Sjmallett * 44215976Sjmallett * "cvmx-usbd.c" defines a set of low level USB functions to help 45215976Sjmallett * developers create Octeon USB devices for various operating 46215976Sjmallett * systems. These functions provide a generic API to the Octeon 47215976Sjmallett * USB blocks, hiding the internal hardware specific 48215976Sjmallett * operations. 49215976Sjmallett * 50215976Sjmallett * <hr>$Revision: 32636 $<hr> 51215976Sjmallett */ 52215976Sjmallett 53215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 54215976Sjmallett#include <asm/octeon/cvmx.h> 55215976Sjmallett#include <asm/octeon/cvmx-clock.h> 56215976Sjmallett#include <asm/octeon/cvmx-sysinfo.h> 57215976Sjmallett#include <asm/octeon/cvmx-usbnx-defs.h> 58215976Sjmallett#include <asm/octeon/cvmx-usbcx-defs.h> 59215976Sjmallett#include <asm/octeon/cvmx-usbd.h> 60215976Sjmallett#include <asm/octeon/cvmx-swap.h> 61215976Sjmallett#include <asm/octeon/cvmx-helper.h> 62215976Sjmallett#include <asm/octeon/cvmx-helper-board.h> 63215976Sjmallett#else 64215976Sjmallett#include "cvmx.h" 65215976Sjmallett#include "cvmx-clock.h" 66215976Sjmallett#include "cvmx-sysinfo.h" 67215976Sjmallett#include "cvmx-usbd.h" 68215976Sjmallett#include "cvmx-swap.h" 69215976Sjmallett#include "cvmx-helper.h" 70215976Sjmallett#include "cvmx-helper-board.h" 71215976Sjmallett#endif 72215976Sjmallett 73215976Sjmallett#define ULL unsigned long long 74215976Sjmallett 75215976Sjmallett/** 76215976Sjmallett * @INTERNAL 77215976Sjmallett * Read a USB 32bit CSR. It performs the necessary address swizzle for 32bit 78215976Sjmallett * CSRs. 79215976Sjmallett * 80215976Sjmallett * @param usb USB device state populated by 81215976Sjmallett * cvmx_usbd_initialize(). 82215976Sjmallett * @param address 64bit address to read 83215976Sjmallett * 84215976Sjmallett * @return Result of the read 85215976Sjmallett */ 86215976Sjmallettstatic inline uint32_t __cvmx_usbd_read_csr32(cvmx_usbd_state_t *usb, uint64_t address) 87215976Sjmallett{ 88215976Sjmallett uint32_t result = cvmx_read64_uint32(address ^ 4); 89215976Sjmallett return result; 90215976Sjmallett} 91215976Sjmallett 92215976Sjmallett 93215976Sjmallett/** 94215976Sjmallett * @INTERNAL 95215976Sjmallett * Write a USB 32bit CSR. It performs the necessary address swizzle for 32bit 96215976Sjmallett * CSRs. 97215976Sjmallett * 98215976Sjmallett * @param usb USB device state populated by 99215976Sjmallett * cvmx_usbd_initialize(). 100215976Sjmallett * @param address 64bit address to write 101215976Sjmallett * @param value Value to write 102215976Sjmallett */ 103215976Sjmallettstatic inline void __cvmx_usbd_write_csr32(cvmx_usbd_state_t *usb, uint64_t address, uint32_t value) 104215976Sjmallett{ 105215976Sjmallett cvmx_write64_uint32(address ^ 4, value); 106215976Sjmallett cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index)); 107215976Sjmallett} 108215976Sjmallett 109215976Sjmallett/** 110215976Sjmallett * @INTERNAL 111215976Sjmallett * Calls the user supplied callback when an event happens. 112215976Sjmallett * 113215976Sjmallett * @param usb USB device state populated by 114215976Sjmallett * cvmx_usbd_initialize(). 115215976Sjmallett * @param reason Reason for the callback 116215976Sjmallett * @param endpoint_num 117215976Sjmallett * Endpoint number 118215976Sjmallett * @param bytes_transferred 119215976Sjmallett * Bytes transferred 120215976Sjmallett */ 121215976Sjmallettstatic void __cvmx_usbd_callback(cvmx_usbd_state_t *usb, cvmx_usbd_callback_t reason, int endpoint_num, int bytes_transferred) 122215976Sjmallett{ 123215976Sjmallett if (usb->callback[reason]) 124215976Sjmallett { 125215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 126215976Sjmallett cvmx_dprintf("%s: Calling callback reason=%d endpoint=%d bytes=%d func=%p data=%p\n", 127215976Sjmallett __FUNCTION__, reason, endpoint_num, bytes_transferred, usb->callback[reason], usb->callback_data[reason]); 128215976Sjmallett usb->callback[reason](reason, endpoint_num, bytes_transferred, usb->callback_data[reason]); 129215976Sjmallett } 130215976Sjmallett else 131215976Sjmallett { 132215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 133215976Sjmallett cvmx_dprintf("%s: No callback for reason=%d endpoint=%d bytes=%d\n", 134215976Sjmallett __FUNCTION__, reason, endpoint_num, bytes_transferred); 135215976Sjmallett } 136215976Sjmallett} 137215976Sjmallett 138215976Sjmallett/** 139215976Sjmallett * @INTERNAL 140215976Sjmallett * Perform USB device mode initialization after a reset completes. 141215976Sjmallett * This should be called after USBC0/1_GINTSTS[USBRESET] and 142215976Sjmallett * corresponds to section 22.6.1.1, "Initialization on USB Reset", 143215976Sjmallett * in the manual. 144215976Sjmallett * 145215976Sjmallett * @param usb USB device state populated by 146215976Sjmallett * cvmx_usbd_initialize(). 147215976Sjmallett * 148215976Sjmallett * @return Zero or negative on error. 149215976Sjmallett */ 150215976Sjmallettstatic int __cvmx_usbd_device_reset_complete(cvmx_usbd_state_t *usb) 151215976Sjmallett{ 152215976Sjmallett cvmx_usbcx_ghwcfg2_t usbcx_ghwcfg2; 153215976Sjmallett cvmx_usbcx_ghwcfg3_t usbcx_ghwcfg3; 154215976Sjmallett cvmx_usbcx_doepmsk_t usbcx_doepmsk; 155215976Sjmallett cvmx_usbcx_diepmsk_t usbcx_diepmsk; 156215976Sjmallett cvmx_usbcx_daintmsk_t usbc_daintmsk; 157215976Sjmallett cvmx_usbcx_gnptxfsiz_t gnptxfsiz; 158215976Sjmallett int fifo_space; 159215976Sjmallett int i; 160215976Sjmallett 161215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 162215976Sjmallett cvmx_dprintf("%s: Processing reset\n", __FUNCTION__); 163215976Sjmallett 164215976Sjmallett usbcx_ghwcfg2.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GHWCFG2(usb->index)); 165215976Sjmallett usbcx_ghwcfg3.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GHWCFG3(usb->index)); 166215976Sjmallett 167215976Sjmallett /* Set up the data FIFO RAM for each of the FIFOs */ 168215976Sjmallett fifo_space = usbcx_ghwcfg3.s.dfifodepth; 169215976Sjmallett 170215976Sjmallett /* Start at the top of the FIFO and assign space for each periodic fifo */ 171215976Sjmallett for (i=usbcx_ghwcfg2.s.numdeveps; i>0; i--) 172215976Sjmallett { 173215976Sjmallett cvmx_usbcx_dptxfsizx_t siz; 174215976Sjmallett siz.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DPTXFSIZX(i, usb->index)); 175215976Sjmallett fifo_space -= siz.s.dptxfsize; 176215976Sjmallett siz.s.dptxfstaddr = fifo_space; 177215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DPTXFSIZX(i, usb->index), siz.u32); 178215976Sjmallett } 179215976Sjmallett 180215976Sjmallett /* Assign half the leftover space to the non periodic tx fifo */ 181215976Sjmallett gnptxfsiz.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index)); 182215976Sjmallett gnptxfsiz.s.nptxfdep = fifo_space / 2; 183215976Sjmallett fifo_space -= gnptxfsiz.s.nptxfdep; 184215976Sjmallett gnptxfsiz.s.nptxfstaddr = fifo_space; 185215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), gnptxfsiz.u32); 186215976Sjmallett 187215976Sjmallett /* Assign the remain space to the RX fifo */ 188215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GRXFSIZ(usb->index), fifo_space); 189215976Sjmallett 190215976Sjmallett /* Unmask the common endpoint interrupts */ 191215976Sjmallett usbcx_doepmsk.u32 = 0; 192215976Sjmallett usbcx_doepmsk.s.setupmsk = 1; 193215976Sjmallett usbcx_doepmsk.s.epdisbldmsk = 1; 194215976Sjmallett usbcx_doepmsk.s.xfercomplmsk = 1; 195215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPMSK(usb->index), usbcx_doepmsk.u32); 196215976Sjmallett usbcx_diepmsk.u32 = 0; 197215976Sjmallett usbcx_diepmsk.s.epdisbldmsk = 1; 198215976Sjmallett usbcx_diepmsk.s.xfercomplmsk = 1; 199215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPMSK(usb->index), usbcx_diepmsk.u32); 200215976Sjmallett 201215976Sjmallett usbc_daintmsk.u32 = 0; 202215976Sjmallett usbc_daintmsk.s.inepmsk = -1; 203215976Sjmallett usbc_daintmsk.s.outepmsk = -1; 204215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DAINTMSK(usb->index), usbc_daintmsk.u32); 205215976Sjmallett 206215976Sjmallett /* Set all endpoints to NAK */ 207215976Sjmallett for (i=0; i<usbcx_ghwcfg2.s.numdeveps+1; i++) 208215976Sjmallett { 209215976Sjmallett cvmx_usbcx_doepctlx_t usbc_doepctl; 210215976Sjmallett usbc_doepctl.u32 = 0; 211215976Sjmallett usbc_doepctl.s.snak = 1; 212215976Sjmallett usbc_doepctl.s.usbactep = 1; 213215976Sjmallett usbc_doepctl.s.mps = (i==0) ? 0 : 64; 214215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPCTLX(i, usb->index), usbc_doepctl.u32); 215215976Sjmallett } 216215976Sjmallett 217215976Sjmallett return 0; 218215976Sjmallett} 219215976Sjmallett 220215976Sjmallett 221215976Sjmallett/** 222215976Sjmallett * Initialize a USB port for use. This must be called before any 223215976Sjmallett * other access to the Octeon USB port is made. The port starts 224215976Sjmallett * off in the disabled state. 225215976Sjmallett * 226215976Sjmallett * @param usb Pointer to an empty cvmx_usbd_state_t structure 227215976Sjmallett * that will be populated by the initialize call. 228215976Sjmallett * This structure is then passed to all other USB 229215976Sjmallett * functions. 230215976Sjmallett * @param usb_port_number 231215976Sjmallett * Which Octeon USB port to initialize. 232215976Sjmallett * @param flags Flags to control hardware initialization. See 233215976Sjmallett * cvmx_usbd_initialize_flags_t for the flag 234215976Sjmallett * definitions. Some flags are mandatory. 235215976Sjmallett * 236215976Sjmallett * @return Zero or a negative on error. 237215976Sjmallett */ 238215976Sjmallettint cvmx_usbd_initialize(cvmx_usbd_state_t *usb, 239215976Sjmallett int usb_port_number, 240215976Sjmallett cvmx_usbd_initialize_flags_t flags) 241215976Sjmallett{ 242215976Sjmallett cvmx_usbnx_clk_ctl_t usbn_clk_ctl; 243215976Sjmallett cvmx_usbnx_usbp_ctl_status_t usbn_usbp_ctl_status; 244215976Sjmallett 245215976Sjmallett if (cvmx_unlikely(flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 246215976Sjmallett cvmx_dprintf("%s: Called\n", __FUNCTION__); 247215976Sjmallett 248250132Seadler memset(usb, 0, sizeof(*usb)); 249215976Sjmallett usb->init_flags = flags; 250215976Sjmallett usb->index = usb_port_number; 251215976Sjmallett 252215976Sjmallett /* Try to determine clock type automatically */ 253215976Sjmallett if ((usb->init_flags & (CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_XI | 254215976Sjmallett CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_GND)) == 0) 255215976Sjmallett { 256215976Sjmallett if (__cvmx_helper_board_usb_get_clock_type() == USB_CLOCK_TYPE_CRYSTAL_12) 257215976Sjmallett usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_XI; /* Only 12 MHZ crystals are supported */ 258215976Sjmallett else 259215976Sjmallett usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_GND; 260215976Sjmallett } 261215976Sjmallett 262215976Sjmallett if (usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_GND) 263215976Sjmallett { 264215976Sjmallett /* Check for auto ref clock frequency */ 265215976Sjmallett if (!(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_CLOCK_MHZ_MASK)) 266215976Sjmallett switch (__cvmx_helper_board_usb_get_clock_type()) 267215976Sjmallett { 268215976Sjmallett case USB_CLOCK_TYPE_REF_12: 269215976Sjmallett usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_12MHZ; 270215976Sjmallett break; 271215976Sjmallett case USB_CLOCK_TYPE_REF_24: 272215976Sjmallett usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_24MHZ; 273215976Sjmallett break; 274215976Sjmallett case USB_CLOCK_TYPE_REF_48: 275215976Sjmallett default: 276215976Sjmallett usb->init_flags |= CVMX_USBD_INITIALIZE_FLAGS_CLOCK_48MHZ; 277215976Sjmallett break; 278215976Sjmallett } 279215976Sjmallett } 280215976Sjmallett 281215976Sjmallett /* Power On Reset and PHY Initialization */ 282215976Sjmallett 283215976Sjmallett /* 1. Wait for DCOK to assert (nothing to do) */ 284215976Sjmallett /* 2a. Write USBN0/1_CLK_CTL[POR] = 1 and 285215976Sjmallett USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0 */ 286215976Sjmallett usbn_clk_ctl.u64 = cvmx_read_csr(CVMX_USBNX_CLK_CTL(usb->index)); 287215976Sjmallett usbn_clk_ctl.s.por = 1; 288215976Sjmallett usbn_clk_ctl.s.hrst = 0; 289215976Sjmallett usbn_clk_ctl.s.prst = 0; 290215976Sjmallett usbn_clk_ctl.s.hclk_rst = 0; 291215976Sjmallett usbn_clk_ctl.s.enable = 0; 292215976Sjmallett /* 2b. Select the USB reference clock/crystal parameters by writing 293215976Sjmallett appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON] */ 294215976Sjmallett if (usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_CLOCK_XO_GND) 295215976Sjmallett { 296215976Sjmallett /* The USB port uses 12/24/48MHz 2.5V board clock 297215976Sjmallett source at USB_XO. USB_XI should be tied to GND. 298215976Sjmallett Most Octeon evaluation boards require this setting */ 299215976Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) 300215976Sjmallett { 301215976Sjmallett usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */ 302215976Sjmallett usbn_clk_ctl.cn31xx.p_xenbn = 0; 303215976Sjmallett } 304215976Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 305215976Sjmallett usbn_clk_ctl.cn56xx.p_rtype = 2; /* From CN56XX,CN50XX manual */ 306215976Sjmallett else 307215976Sjmallett usbn_clk_ctl.cn52xx.p_rtype = 1; /* From CN52XX manual */ 308215976Sjmallett 309215976Sjmallett switch (usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) 310215976Sjmallett { 311215976Sjmallett case CVMX_USBD_INITIALIZE_FLAGS_CLOCK_12MHZ: 312215976Sjmallett usbn_clk_ctl.s.p_c_sel = 0; 313215976Sjmallett break; 314215976Sjmallett case CVMX_USBD_INITIALIZE_FLAGS_CLOCK_24MHZ: 315215976Sjmallett usbn_clk_ctl.s.p_c_sel = 1; 316215976Sjmallett break; 317215976Sjmallett case CVMX_USBD_INITIALIZE_FLAGS_CLOCK_48MHZ: 318215976Sjmallett usbn_clk_ctl.s.p_c_sel = 2; 319215976Sjmallett break; 320215976Sjmallett } 321215976Sjmallett } 322215976Sjmallett else 323215976Sjmallett { 324215976Sjmallett /* The USB port uses a 12MHz crystal as clock source 325215976Sjmallett at USB_XO and USB_XI */ 326215976Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) 327215976Sjmallett { 328215976Sjmallett usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */ 329215976Sjmallett usbn_clk_ctl.cn31xx.p_xenbn = 1; 330215976Sjmallett } 331215976Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 332215976Sjmallett usbn_clk_ctl.cn56xx.p_rtype = 0; /* From CN56XX,CN50XX manual */ 333215976Sjmallett else 334215976Sjmallett usbn_clk_ctl.cn52xx.p_rtype = 0; /* From CN52XX manual */ 335215976Sjmallett 336215976Sjmallett usbn_clk_ctl.s.p_c_sel = 0; 337215976Sjmallett } 338215976Sjmallett /* 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and 339215976Sjmallett setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down such 340215976Sjmallett that USB is as close as possible to 125Mhz */ 341215976Sjmallett { 342215976Sjmallett int divisor = (cvmx_clock_get_rate(CVMX_CLOCK_CORE)+125000000-1)/125000000; 343215976Sjmallett if (divisor < 4) /* Lower than 4 doesn't seem to work properly */ 344215976Sjmallett divisor = 4; 345215976Sjmallett usbn_clk_ctl.s.divide = divisor; 346215976Sjmallett usbn_clk_ctl.s.divide2 = 0; 347215976Sjmallett } 348215976Sjmallett cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); 349215976Sjmallett /* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */ 350215976Sjmallett usbn_clk_ctl.s.hclk_rst = 1; 351215976Sjmallett cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); 352215976Sjmallett /* 2e. Wait 64 core-clock cycles for HCLK to stabilize */ 353215976Sjmallett cvmx_wait(64); 354215976Sjmallett /* 3. Program the power-on reset field in the USBN clock-control register: 355215976Sjmallett USBN_CLK_CTL[POR] = 0 */ 356215976Sjmallett usbn_clk_ctl.s.por = 0; 357215976Sjmallett cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); 358215976Sjmallett /* 4. Wait 1 ms for PHY clock to start */ 359215976Sjmallett cvmx_wait_usec(1000); 360215976Sjmallett /* 5. Program the Reset input from automatic test equipment field in the 361215976Sjmallett USBP control and status register: USBN_USBP_CTL_STATUS[ATE_RESET] = 1 */ 362215976Sjmallett usbn_usbp_ctl_status.u64 = cvmx_read_csr(CVMX_USBNX_USBP_CTL_STATUS(usb->index)); 363215976Sjmallett usbn_usbp_ctl_status.s.ate_reset = 1; 364215976Sjmallett cvmx_write_csr(CVMX_USBNX_USBP_CTL_STATUS(usb->index), usbn_usbp_ctl_status.u64); 365215976Sjmallett /* 6. Wait 10 cycles */ 366215976Sjmallett cvmx_wait(10); 367215976Sjmallett /* 7. Clear ATE_RESET field in the USBN clock-control register: 368215976Sjmallett USBN_USBP_CTL_STATUS[ATE_RESET] = 0 */ 369215976Sjmallett usbn_usbp_ctl_status.s.ate_reset = 0; 370215976Sjmallett cvmx_write_csr(CVMX_USBNX_USBP_CTL_STATUS(usb->index), usbn_usbp_ctl_status.u64); 371215976Sjmallett /* 8. Program the PHY reset field in the USBN clock-control register: 372215976Sjmallett USBN_CLK_CTL[PRST] = 1 */ 373215976Sjmallett usbn_clk_ctl.s.prst = 1; 374215976Sjmallett cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); 375215976Sjmallett /* 9. Program the USBP control and status register to select host or 376215976Sjmallett device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for 377215976Sjmallett device */ 378215976Sjmallett usbn_usbp_ctl_status.s.hst_mode = 1; 379215976Sjmallett usbn_usbp_ctl_status.s.dm_pulld = 0; 380215976Sjmallett usbn_usbp_ctl_status.s.dp_pulld = 0; 381215976Sjmallett cvmx_write_csr(CVMX_USBNX_USBP_CTL_STATUS(usb->index), usbn_usbp_ctl_status.u64); 382215976Sjmallett /* 10. Wait 1 �s */ 383215976Sjmallett cvmx_wait_usec(1); 384215976Sjmallett /* 11. Program the hreset_n field in the USBN clock-control register: 385215976Sjmallett USBN_CLK_CTL[HRST] = 1 */ 386215976Sjmallett usbn_clk_ctl.s.hrst = 1; 387215976Sjmallett cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); 388215976Sjmallett /* 12. Proceed to USB core initialization */ 389215976Sjmallett usbn_clk_ctl.s.enable = 1; 390215976Sjmallett cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); 391215976Sjmallett cvmx_wait_usec(1); 392215976Sjmallett 393215976Sjmallett /* Program the following fields in the global AHB configuration 394215976Sjmallett register (USBC_GAHBCFG) 395215976Sjmallett DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode 396215976Sjmallett Burst length, USBC_GAHBCFG[HBSTLEN] = 0 397215976Sjmallett Nonperiodic TxFIFO empty level (slave mode only), 398215976Sjmallett USBC_GAHBCFG[NPTXFEMPLVL] 399215976Sjmallett Periodic TxFIFO empty level (slave mode only), 400215976Sjmallett USBC_GAHBCFG[PTXFEMPLVL] 401215976Sjmallett Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1 */ 402215976Sjmallett { 403215976Sjmallett cvmx_usbcx_gahbcfg_t usbcx_gahbcfg; 404215976Sjmallett usbcx_gahbcfg.u32 = 0; 405215976Sjmallett usbcx_gahbcfg.s.dmaen = 1; 406215976Sjmallett usbcx_gahbcfg.s.hbstlen = 0; 407215976Sjmallett usbcx_gahbcfg.s.nptxfemplvl = 1; 408215976Sjmallett usbcx_gahbcfg.s.ptxfemplvl = 1; 409215976Sjmallett usbcx_gahbcfg.s.glblintrmsk = 1; 410215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index), usbcx_gahbcfg.u32); 411215976Sjmallett } 412215976Sjmallett 413215976Sjmallett /* Program the following fields in USBC_GUSBCFG register. 414215976Sjmallett HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0 415215976Sjmallett ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0 416215976Sjmallett USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5 417215976Sjmallett PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0 */ 418215976Sjmallett { 419215976Sjmallett cvmx_usbcx_gusbcfg_t usbcx_gusbcfg; 420215976Sjmallett usbcx_gusbcfg.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index)); 421215976Sjmallett usbcx_gusbcfg.s.toutcal = 0; 422215976Sjmallett usbcx_gusbcfg.s.ddrsel = 0; 423215976Sjmallett usbcx_gusbcfg.s.usbtrdtim = 0x5; 424215976Sjmallett usbcx_gusbcfg.s.phylpwrclksel = 0; 425215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index), usbcx_gusbcfg.u32); 426215976Sjmallett } 427215976Sjmallett 428215976Sjmallett /* Program the following fields in the USBC0/1_DCFG register: 429215976Sjmallett Device speed, USBC0/1_DCFG[DEVSPD] = 0 (high speed) 430215976Sjmallett Non-zero-length status OUT handshake, USBC0/1_DCFG[NZSTSOUTHSHK]=0 431215976Sjmallett Periodic frame interval (if periodic endpoints are supported), 432215976Sjmallett USBC0/1_DCFG[PERFRINT] = 1 */ 433215976Sjmallett { 434215976Sjmallett cvmx_usbcx_dcfg_t usbcx_dcfg; 435215976Sjmallett usbcx_dcfg.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCFG(usb->index)); 436215976Sjmallett usbcx_dcfg.s.devspd = 0; 437215976Sjmallett usbcx_dcfg.s.nzstsouthshk = 0; 438215976Sjmallett usbcx_dcfg.s.perfrint = 1; 439215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DCFG(usb->index), usbcx_dcfg.u32); 440215976Sjmallett } 441215976Sjmallett 442215976Sjmallett /* Program the USBC0/1_GINTMSK register */ 443215976Sjmallett { 444215976Sjmallett cvmx_usbcx_gintmsk_t usbcx_gintmsk; 445215976Sjmallett usbcx_gintmsk.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GINTMSK(usb->index)); 446215976Sjmallett usbcx_gintmsk.s.oepintmsk = 1; 447215976Sjmallett usbcx_gintmsk.s.inepintmsk = 1; 448215976Sjmallett usbcx_gintmsk.s.enumdonemsk = 1; 449215976Sjmallett usbcx_gintmsk.s.usbrstmsk = 1; 450215976Sjmallett usbcx_gintmsk.s.usbsuspmsk = 1; 451215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index), usbcx_gintmsk.u32); 452215976Sjmallett } 453215976Sjmallett 454215976Sjmallett cvmx_usbd_disable(usb); 455215976Sjmallett return 0; 456215976Sjmallett} 457215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 458215976SjmallettEXPORT_SYMBOL(cvmx_usbd_initialize); 459215976Sjmallett#endif 460215976Sjmallett 461215976Sjmallett 462215976Sjmallett/** 463215976Sjmallett * Shutdown a USB port after a call to cvmx_usbd_initialize(). 464215976Sjmallett * 465215976Sjmallett * @param usb USB device state populated by 466215976Sjmallett * cvmx_usbd_initialize(). 467215976Sjmallett * 468215976Sjmallett * @return Zero or a negative on error. 469215976Sjmallett */ 470215976Sjmallettint cvmx_usbd_shutdown(cvmx_usbd_state_t *usb) 471215976Sjmallett{ 472215976Sjmallett cvmx_usbnx_clk_ctl_t usbn_clk_ctl; 473215976Sjmallett 474215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 475215976Sjmallett cvmx_dprintf("%s: Called\n", __FUNCTION__); 476215976Sjmallett 477215976Sjmallett /* Disable the clocks and put them in power on reset */ 478215976Sjmallett usbn_clk_ctl.u64 = cvmx_read_csr(CVMX_USBNX_CLK_CTL(usb->index)); 479215976Sjmallett usbn_clk_ctl.s.enable = 1; 480215976Sjmallett usbn_clk_ctl.s.por = 1; 481215976Sjmallett usbn_clk_ctl.s.hclk_rst = 1; 482215976Sjmallett usbn_clk_ctl.s.prst = 0; 483215976Sjmallett usbn_clk_ctl.s.hrst = 0; 484215976Sjmallett cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64); 485215976Sjmallett return 0; 486215976Sjmallett} 487215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 488215976SjmallettEXPORT_SYMBOL(cvmx_usbd_shutdown); 489215976Sjmallett#endif 490215976Sjmallett 491215976Sjmallett 492215976Sjmallett/** 493215976Sjmallett * Enable a USB port. After this call succeeds, the USB port is 494215976Sjmallett * online and servicing requests. 495215976Sjmallett * 496215976Sjmallett * @param usb USB device state populated by 497215976Sjmallett * cvmx_usb_initialize(). 498215976Sjmallett * 499215976Sjmallett * @return Zero or negative on error. 500215976Sjmallett */ 501215976Sjmallettint cvmx_usbd_enable(cvmx_usbd_state_t *usb) 502215976Sjmallett{ 503215976Sjmallett cvmx_usbcx_dctl_t usbcx_dctl; 504215976Sjmallett usbcx_dctl.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCTL(usb->index)); 505215976Sjmallett usbcx_dctl.s.cgoutnak = 1; 506215976Sjmallett usbcx_dctl.s.sftdiscon = 0; 507215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DCTL(usb->index), usbcx_dctl.u32); 508215976Sjmallett return 0; 509215976Sjmallett} 510215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 511215976SjmallettEXPORT_SYMBOL(cvmx_usbd_enable); 512215976Sjmallett#endif 513215976Sjmallett 514215976Sjmallett 515215976Sjmallett/** 516215976Sjmallett * Disable a USB port. After this call the USB port will not 517215976Sjmallett * generate data transfers and will not generate events. 518215976Sjmallett * 519215976Sjmallett * @param usb USB device state populated by 520215976Sjmallett * cvmx_usb_initialize(). 521215976Sjmallett * 522215976Sjmallett * @return Zero or negative on error. 523215976Sjmallett */ 524215976Sjmallettint cvmx_usbd_disable(cvmx_usbd_state_t *usb) 525215976Sjmallett{ 526215976Sjmallett cvmx_usbcx_dctl_t usbcx_dctl; 527215976Sjmallett usbcx_dctl.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCTL(usb->index)); 528215976Sjmallett usbcx_dctl.s.sgoutnak = 1; 529215976Sjmallett usbcx_dctl.s.sftdiscon = 1; 530215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DCTL(usb->index), usbcx_dctl.u32); 531215976Sjmallett return 0; 532215976Sjmallett} 533215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 534215976SjmallettEXPORT_SYMBOL(cvmx_usbd_disable); 535215976Sjmallett#endif 536215976Sjmallett 537215976Sjmallett 538215976Sjmallett/** 539215976Sjmallett * Register a callback function to process USB events 540215976Sjmallett * 541215976Sjmallett * @param usb USB device state populated by 542215976Sjmallett * cvmx_usbd_initialize(). 543215976Sjmallett * @param reason The reason this callback should be called 544215976Sjmallett * @param func Function to call 545215976Sjmallett * @param user_data User supplied data for the callback 546215976Sjmallett * 547215976Sjmallett * @return Zero on succes, negative on failure 548215976Sjmallett */ 549215976Sjmallettint cvmx_usbd_register(cvmx_usbd_state_t *usb, cvmx_usbd_callback_t reason, cvmx_usbd_callback_func_t func, void *user_data) 550215976Sjmallett{ 551215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 552215976Sjmallett cvmx_dprintf("%s: Register reason=%d func=%p data=%p\n", 553215976Sjmallett __FUNCTION__, reason, func, user_data); 554215976Sjmallett usb->callback[reason] = func; 555215976Sjmallett usb->callback_data[reason] = user_data; 556215976Sjmallett return 0; 557215976Sjmallett} 558215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 559215976SjmallettEXPORT_SYMBOL(cvmx_usbd_register); 560215976Sjmallett#endif 561215976Sjmallett 562215976Sjmallett/** 563215976Sjmallett * @INTERNAL 564215976Sjmallett * Poll a device mode endpoint for status 565215976Sjmallett * 566215976Sjmallett * @param usb USB device state populated by 567215976Sjmallett * cvmx_usbd_initialize(). 568215976Sjmallett * @param endpoint_num 569215976Sjmallett * Endpoint to poll 570215976Sjmallett * 571215976Sjmallett * @return Zero on success 572215976Sjmallett */ 573215976Sjmallettstatic int __cvmx_usbd_poll_in_endpoint(cvmx_usbd_state_t *usb, int endpoint_num) 574215976Sjmallett{ 575215976Sjmallett cvmx_usbcx_diepintx_t usbc_diepint; 576215976Sjmallett 577215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 578215976Sjmallett cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num); 579215976Sjmallett 580215976Sjmallett usbc_diepint.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DIEPINTX(endpoint_num, usb->index)); 581215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPINTX(endpoint_num, usb->index), usbc_diepint.u32); 582215976Sjmallett 583215976Sjmallett if (usbc_diepint.s.epdisbld) 584215976Sjmallett { 585215976Sjmallett /* Endpoint Disabled Interrupt (EPDisbld) 586215976Sjmallett This bit indicates that the endpoint is disabled per the 587215976Sjmallett application's request. */ 588215976Sjmallett /* Nothing to do */ 589215976Sjmallett } 590215976Sjmallett if (usbc_diepint.s.xfercompl) 591215976Sjmallett { 592215976Sjmallett cvmx_usbcx_dieptsizx_t usbc_dieptsiz; 593215976Sjmallett int bytes_transferred; 594215976Sjmallett /* Transfer Completed Interrupt (XferCompl) 595215976Sjmallett Indicates that the programmed transfer is complete on the AHB 596215976Sjmallett as well as on the USB, for this endpoint. */ 597215976Sjmallett usbc_dieptsiz.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DIEPTSIZX(endpoint_num, usb->index)); 598215976Sjmallett bytes_transferred = usb->endpoint[endpoint_num].buffer_length - usbc_dieptsiz.s.xfersize; 599215976Sjmallett __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_IN_COMPLETE, endpoint_num, bytes_transferred); 600215976Sjmallett } 601215976Sjmallett return 0; 602215976Sjmallett} 603215976Sjmallett 604215976Sjmallett 605215976Sjmallett/** 606215976Sjmallett * @INTERNAL 607215976Sjmallett * Poll a device mode endpoint for status 608215976Sjmallett * 609215976Sjmallett * @param usb USB device state populated by 610215976Sjmallett * cvmx_usbd_initialize(). 611215976Sjmallett * @param endpoint_num 612215976Sjmallett * Endpoint to poll 613215976Sjmallett * 614215976Sjmallett * @return Zero on success 615215976Sjmallett */ 616215976Sjmallettstatic int __cvmx_usbd_poll_out_endpoint(cvmx_usbd_state_t *usb, int endpoint_num) 617215976Sjmallett{ 618215976Sjmallett cvmx_usbcx_doepintx_t usbc_doepint; 619215976Sjmallett 620215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 621215976Sjmallett cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num); 622215976Sjmallett 623215976Sjmallett usbc_doepint.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DOEPINTX(endpoint_num, usb->index)); 624215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPINTX(endpoint_num, usb->index), usbc_doepint.u32); 625215976Sjmallett 626215976Sjmallett if (usbc_doepint.s.setup) 627215976Sjmallett { 628215976Sjmallett /* SETUP Phase Done (SetUp) 629215976Sjmallett Applies to control OUT endpoints only. 630215976Sjmallett Indicates that the SETUP phase for the control endpoint is 631215976Sjmallett complete and no more back-to-back SETUP packets were 632215976Sjmallett received for the current control transfer. On this interrupt, the 633215976Sjmallett application can decode the received SETUP data packet. */ 634215976Sjmallett __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_DEVICE_SETUP, endpoint_num, 0); 635215976Sjmallett } 636215976Sjmallett if (usbc_doepint.s.epdisbld) 637215976Sjmallett { 638215976Sjmallett /* Endpoint Disabled Interrupt (EPDisbld) 639215976Sjmallett This bit indicates that the endpoint is disabled per the 640215976Sjmallett application's request. */ 641215976Sjmallett /* Nothing to do */ 642215976Sjmallett } 643215976Sjmallett if (usbc_doepint.s.xfercompl) 644215976Sjmallett { 645215976Sjmallett cvmx_usbcx_doeptsizx_t usbc_doeptsiz; 646215976Sjmallett int bytes_transferred; 647215976Sjmallett /* Transfer Completed Interrupt (XferCompl) 648215976Sjmallett Indicates that the programmed transfer is complete on the AHB 649215976Sjmallett as well as on the USB, for this endpoint. */ 650215976Sjmallett usbc_doeptsiz.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DOEPTSIZX(endpoint_num, usb->index)); 651215976Sjmallett bytes_transferred = usb->endpoint[endpoint_num].buffer_length - usbc_doeptsiz.s.xfersize; 652215976Sjmallett __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_OUT_COMPLETE, endpoint_num, bytes_transferred); 653215976Sjmallett } 654215976Sjmallett 655215976Sjmallett return 0; 656215976Sjmallett} 657215976Sjmallett 658215976Sjmallett 659215976Sjmallett/** 660215976Sjmallett * Poll the USB block for status and call all needed callback 661215976Sjmallett * handlers. This function is meant to be called in the interrupt 662215976Sjmallett * handler for the USB controller. It can also be called 663215976Sjmallett * periodically in a loop for non-interrupt based operation. 664215976Sjmallett * 665215976Sjmallett * @param usb USB device state populated by 666215976Sjmallett * cvmx_usbd_initialize(). 667215976Sjmallett * 668215976Sjmallett * @return Zero or negative on error. 669215976Sjmallett */ 670215976Sjmallettint cvmx_usbd_poll(cvmx_usbd_state_t *usb) 671215976Sjmallett{ 672215976Sjmallett cvmx_usbcx_gintsts_t usbc_gintsts; 673215976Sjmallett 674215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 675215976Sjmallett cvmx_dprintf("%s: Called\n", __FUNCTION__); 676215976Sjmallett 677215976Sjmallett /* Read the pending interrupts */ 678215976Sjmallett usbc_gintsts.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GINTSTS(usb->index)); 679215976Sjmallett usbc_gintsts.u32 &= __cvmx_usbd_read_csr32(usb, CVMX_USBCX_GINTMSK(usb->index)); 680215976Sjmallett 681215976Sjmallett /* Clear the interrupts now that we know about them */ 682215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32); 683215976Sjmallett 684215976Sjmallett if (usbc_gintsts.s.usbsusp) 685215976Sjmallett __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_SUSPEND, 0, 0); 686215976Sjmallett 687215976Sjmallett if (usbc_gintsts.s.enumdone) 688215976Sjmallett __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_ENUM_COMPLETE, 0, 0); 689215976Sjmallett 690215976Sjmallett if (usbc_gintsts.s.usbrst) 691215976Sjmallett { 692215976Sjmallett /* USB Reset (USBRst) 693215976Sjmallett The core sets this bit to indicate that a reset is 694215976Sjmallett detected on the USB. */ 695215976Sjmallett __cvmx_usbd_device_reset_complete(usb); 696215976Sjmallett __cvmx_usbd_callback(usb, CVMX_USBD_CALLBACK_RESET, 0, 0); 697215976Sjmallett } 698215976Sjmallett 699215976Sjmallett if (usbc_gintsts.s.oepint || usbc_gintsts.s.iepint) 700215976Sjmallett { 701215976Sjmallett cvmx_usbcx_daint_t usbc_daint; 702215976Sjmallett usbc_daint.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DAINT(usb->index)); 703215976Sjmallett if (usbc_daint.s.inepint) 704215976Sjmallett { 705215976Sjmallett int active_endpoints = usbc_daint.s.inepint; 706215976Sjmallett 707215976Sjmallett while (active_endpoints) 708215976Sjmallett { 709215976Sjmallett int endpoint; 710215976Sjmallett CVMX_CLZ(endpoint, active_endpoints); 711215976Sjmallett endpoint = 31 - endpoint; 712215976Sjmallett __cvmx_usbd_poll_in_endpoint(usb, endpoint); 713215976Sjmallett active_endpoints ^= 1<<endpoint; 714215976Sjmallett } 715215976Sjmallett } 716215976Sjmallett if (usbc_daint.s.outepint) 717215976Sjmallett { 718215976Sjmallett int active_endpoints = usbc_daint.s.outepint; 719215976Sjmallett 720215976Sjmallett while (active_endpoints) 721215976Sjmallett { 722215976Sjmallett int endpoint; 723215976Sjmallett CVMX_CLZ(endpoint, active_endpoints); 724215976Sjmallett endpoint = 31 - endpoint; 725215976Sjmallett __cvmx_usbd_poll_out_endpoint(usb, endpoint); 726215976Sjmallett active_endpoints ^= 1<<endpoint; 727215976Sjmallett } 728215976Sjmallett } 729215976Sjmallett } 730215976Sjmallett 731215976Sjmallett return 0; 732215976Sjmallett} 733215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 734215976SjmallettEXPORT_SYMBOL(cvmx_usbd_poll); 735215976Sjmallett#endif 736215976Sjmallett 737215976Sjmallett/** 738215976Sjmallett * Get the current USB address 739215976Sjmallett * 740215976Sjmallett * @param usb USB device state populated by 741215976Sjmallett * cvmx_usbd_initialize(). 742215976Sjmallett * 743215976Sjmallett * @return The USB address 744215976Sjmallett */ 745215976Sjmallettint cvmx_usbd_get_address(cvmx_usbd_state_t *usb) 746215976Sjmallett{ 747215976Sjmallett cvmx_usbcx_dcfg_t usbc_dcfg; 748215976Sjmallett usbc_dcfg.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCFG(usb->index)); 749215976Sjmallett return usbc_dcfg.s.devaddr; 750215976Sjmallett} 751215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 752215976SjmallettEXPORT_SYMBOL(cvmx_usbd_get_address); 753215976Sjmallett#endif 754215976Sjmallett 755215976Sjmallett/** 756215976Sjmallett * Set the current USB address 757215976Sjmallett * 758215976Sjmallett * @param usb USB device state populated by 759215976Sjmallett * cvmx_usbd_initialize(). 760215976Sjmallett * @param address Address to set 761215976Sjmallett */ 762215976Sjmallettvoid cvmx_usbd_set_address(cvmx_usbd_state_t *usb, int address) 763215976Sjmallett{ 764215976Sjmallett cvmx_usbcx_dcfg_t usbc_dcfg; 765215976Sjmallett usbc_dcfg.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCFG(usb->index)); 766215976Sjmallett usbc_dcfg.s.devaddr = address; 767215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DCFG(usb->index), usbc_dcfg.u32); 768215976Sjmallett} 769215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 770215976SjmallettEXPORT_SYMBOL(cvmx_usbd_set_address); 771215976Sjmallett#endif 772215976Sjmallett 773215976Sjmallett/** 774215976Sjmallett * Get the current USB speed 775215976Sjmallett * 776215976Sjmallett * @param usb USB device state populated by 777215976Sjmallett * cvmx_usbd_initialize(). 778215976Sjmallett * 779215976Sjmallett * @return The USB speed 780215976Sjmallett */ 781215976Sjmallettcvmx_usbd_speed_t cvmx_usbd_get_speed(cvmx_usbd_state_t *usb) 782215976Sjmallett{ 783215976Sjmallett cvmx_usbcx_dsts_t usbcx_dsts; 784215976Sjmallett usbcx_dsts.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DSTS(usb->index)); 785215976Sjmallett return usbcx_dsts.s.enumspd; 786215976Sjmallett} 787215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 788215976SjmallettEXPORT_SYMBOL(cvmx_usbd_get_speed); 789215976Sjmallett#endif 790215976Sjmallett 791215976Sjmallett/** 792215976Sjmallett * Set the current USB speed 793215976Sjmallett * 794215976Sjmallett * @param usb USB device state populated by 795215976Sjmallett * cvmx_usbd_initialize(). 796215976Sjmallett * @param speed The requested speed 797215976Sjmallett */ 798215976Sjmallettvoid cvmx_usbd_set_speed(cvmx_usbd_state_t *usb, cvmx_usbd_speed_t speed) 799215976Sjmallett{ 800215976Sjmallett cvmx_usbcx_dcfg_t usbcx_dcfg; 801215976Sjmallett usbcx_dcfg.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DCFG(usb->index)); 802215976Sjmallett usbcx_dcfg.s.devspd = speed; 803215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DCFG(usb->index), usbcx_dcfg.u32); 804215976Sjmallett} 805215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 806215976SjmallettEXPORT_SYMBOL(cvmx_usbd_set_speed); 807215976Sjmallett#endif 808215976Sjmallett 809215976Sjmallett/** 810215976Sjmallett * Enable an endpoint to respond to an OUT transaction 811215976Sjmallett * 812215976Sjmallett * @param usb USB device state populated by 813215976Sjmallett * cvmx_usbd_initialize(). 814215976Sjmallett * @param endpoint_num 815215976Sjmallett * Endpoint number to enable 816215976Sjmallett * @param transfer_type 817215976Sjmallett * Transfer type for the endpoint 818215976Sjmallett * @param max_packet_size 819215976Sjmallett * Maximum packet size for the endpoint 820215976Sjmallett * @param buffer Buffer to receive the data 821215976Sjmallett * @param buffer_length 822215976Sjmallett * Length of the buffer in bytes 823215976Sjmallett * 824215976Sjmallett * @return Zero on success, negative on failure 825215976Sjmallett */ 826215976Sjmallettint cvmx_usbd_out_endpoint_enable(cvmx_usbd_state_t *usb, 827215976Sjmallett int endpoint_num, cvmx_usbd_transfer_t transfer_type, 828215976Sjmallett int max_packet_size, uint64_t buffer, int buffer_length) 829215976Sjmallett{ 830215976Sjmallett cvmx_usbcx_doepctlx_t usbc_doepctl; 831215976Sjmallett cvmx_usbcx_doeptsizx_t usbc_doeptsiz; 832215976Sjmallett 833215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 834215976Sjmallett cvmx_dprintf("%s: endpoint=%d buffer=0x%llx length=%d\n", 835215976Sjmallett __FUNCTION__, endpoint_num, (ULL)buffer, buffer_length); 836215976Sjmallett 837215976Sjmallett usb->endpoint[endpoint_num].buffer_length = buffer_length; 838215976Sjmallett 839215976Sjmallett CVMX_SYNCW; /* Flush out pending writes before enable */ 840215976Sjmallett 841215976Sjmallett /* Clear any pending interrupts */ 842215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPINTX(endpoint_num, usb->index), 843215976Sjmallett __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DOEPINTX(endpoint_num, usb->index))); 844215976Sjmallett 845215976Sjmallett /* Setup the locations the DMA engines use */ 846215976Sjmallett cvmx_write_csr(CVMX_USBNX_DMA0_INB_CHN0(usb->index) + endpoint_num*8, buffer); 847215976Sjmallett 848215976Sjmallett usbc_doeptsiz.u32 = 0; 849215976Sjmallett usbc_doeptsiz.s.mc = 1; 850215976Sjmallett usbc_doeptsiz.s.pktcnt = (buffer_length + max_packet_size - 1) / max_packet_size; 851215976Sjmallett if (usbc_doeptsiz.s.pktcnt == 0) 852215976Sjmallett usbc_doeptsiz.s.pktcnt = 1; 853215976Sjmallett usbc_doeptsiz.s.xfersize = buffer_length; 854215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPTSIZX(endpoint_num, usb->index), usbc_doeptsiz.u32); 855215976Sjmallett 856215976Sjmallett usbc_doepctl.u32 = 0; 857215976Sjmallett usbc_doepctl.s.epena = 1; 858215976Sjmallett usbc_doepctl.s.setd1pid = 0; 859215976Sjmallett usbc_doepctl.s.setd0pid = 0; 860215976Sjmallett usbc_doepctl.s.cnak = 1; 861215976Sjmallett usbc_doepctl.s.eptype = transfer_type; 862215976Sjmallett usbc_doepctl.s.usbactep = 1; 863215976Sjmallett if (endpoint_num == 0) 864215976Sjmallett { 865215976Sjmallett switch (max_packet_size) 866215976Sjmallett { 867215976Sjmallett case 8: 868215976Sjmallett usbc_doepctl.s.mps = 3; 869215976Sjmallett break; 870215976Sjmallett case 16: 871215976Sjmallett usbc_doepctl.s.mps = 2; 872215976Sjmallett break; 873215976Sjmallett case 32: 874215976Sjmallett usbc_doepctl.s.mps = 1; 875215976Sjmallett break; 876215976Sjmallett default: 877215976Sjmallett usbc_doepctl.s.mps = 0; 878215976Sjmallett break; 879215976Sjmallett } 880215976Sjmallett } 881215976Sjmallett else 882215976Sjmallett usbc_doepctl.s.mps = max_packet_size; 883215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPCTLX(endpoint_num, usb->index), usbc_doepctl.u32); 884215976Sjmallett 885215976Sjmallett return 0; 886215976Sjmallett} 887215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 888215976SjmallettEXPORT_SYMBOL(cvmx_usbd_out_endpoint_enable); 889215976Sjmallett#endif 890215976Sjmallett 891215976Sjmallett 892215976Sjmallett/** 893215976Sjmallett * Disable an OUT endpoint 894215976Sjmallett * 895215976Sjmallett * @param usb USB device state populated by 896215976Sjmallett * cvmx_usbd_initialize(). 897215976Sjmallett * @param endpoint_num 898215976Sjmallett * Endpoint number to disable 899215976Sjmallett * 900215976Sjmallett * @return Zero on success, negative on failure 901215976Sjmallett */ 902215976Sjmallettint cvmx_usbd_out_endpoint_disable(cvmx_usbd_state_t *usb, int endpoint_num) 903215976Sjmallett{ 904215976Sjmallett cvmx_usbcx_doepctlx_t usbc_doepctl; 905215976Sjmallett 906215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 907215976Sjmallett cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num); 908215976Sjmallett 909215976Sjmallett usbc_doepctl.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DOEPCTLX(endpoint_num, usb->index)); 910215976Sjmallett if (usbc_doepctl.s.epena && !usbc_doepctl.s.epdis) 911215976Sjmallett { 912215976Sjmallett usbc_doepctl.s.epdis = 1; 913215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DOEPCTLX(endpoint_num, usb->index), usbc_doepctl.u32); 914215976Sjmallett } 915215976Sjmallett return 0; 916215976Sjmallett} 917215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 918215976SjmallettEXPORT_SYMBOL(cvmx_usbd_out_endpoint_disable); 919215976Sjmallett#endif 920215976Sjmallett 921215976Sjmallett 922215976Sjmallett/** 923215976Sjmallett * Enable an endpoint to respond to an IN transaction 924215976Sjmallett * 925215976Sjmallett * @param usb USB device state populated by 926215976Sjmallett * cvmx_usbd_initialize(). 927215976Sjmallett * @param endpoint_num 928215976Sjmallett * Endpoint number to enable 929215976Sjmallett * @param transfer_type 930215976Sjmallett * Transfer type for the endpoint 931215976Sjmallett * @param max_packet_size 932215976Sjmallett * Maximum packet size for the endpoint 933215976Sjmallett * @param buffer Buffer to send 934215976Sjmallett * @param buffer_length 935215976Sjmallett * Length of the buffer in bytes 936215976Sjmallett * 937215976Sjmallett * @return Zero on success, negative on failure 938215976Sjmallett */ 939215976Sjmallettint cvmx_usbd_in_endpoint_enable(cvmx_usbd_state_t *usb, 940215976Sjmallett int endpoint_num, cvmx_usbd_transfer_t transfer_type, 941215976Sjmallett int max_packet_size, uint64_t buffer, int buffer_length) 942215976Sjmallett{ 943215976Sjmallett cvmx_usbcx_diepctlx_t usbc_diepctl; 944215976Sjmallett cvmx_usbcx_dieptsizx_t usbc_dieptsiz; 945215976Sjmallett 946215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 947215976Sjmallett cvmx_dprintf("%s: endpoint=%d buffer=0x%llx length=%d\n", 948215976Sjmallett __FUNCTION__, endpoint_num, (ULL)buffer, buffer_length); 949215976Sjmallett 950215976Sjmallett usb->endpoint[endpoint_num].buffer_length = buffer_length; 951215976Sjmallett 952215976Sjmallett CVMX_SYNCW; /* Flush out pending writes before enable */ 953215976Sjmallett 954215976Sjmallett /* Clear any pending interrupts */ 955215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPINTX(endpoint_num, usb->index), 956215976Sjmallett __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DIEPINTX(endpoint_num, usb->index))); 957215976Sjmallett 958215976Sjmallett usbc_dieptsiz.u32 = 0; 959215976Sjmallett usbc_dieptsiz.s.mc = 1; 960215976Sjmallett if (buffer) 961215976Sjmallett { 962215976Sjmallett cvmx_write_csr(CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + endpoint_num*8, buffer); 963215976Sjmallett usbc_dieptsiz.s.pktcnt = (buffer_length + max_packet_size - 1) / max_packet_size; 964215976Sjmallett if (usbc_dieptsiz.s.pktcnt == 0) 965215976Sjmallett usbc_dieptsiz.s.pktcnt = 1; 966215976Sjmallett usbc_dieptsiz.s.xfersize = buffer_length; 967215976Sjmallett } 968215976Sjmallett else 969215976Sjmallett { 970215976Sjmallett usbc_dieptsiz.s.pktcnt = 0; 971215976Sjmallett usbc_dieptsiz.s.xfersize = 0; 972215976Sjmallett } 973215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPTSIZX(endpoint_num, usb->index), usbc_dieptsiz.u32); 974215976Sjmallett 975215976Sjmallett usbc_diepctl.u32 = 0; 976215976Sjmallett usbc_diepctl.s.epena = (buffer != 0); 977215976Sjmallett usbc_diepctl.s.setd1pid = 0; 978215976Sjmallett usbc_diepctl.s.setd0pid = (buffer == 0); 979215976Sjmallett usbc_diepctl.s.cnak = 1; 980215976Sjmallett usbc_diepctl.s.txfnum = endpoint_num; 981215976Sjmallett usbc_diepctl.s.eptype = transfer_type; 982215976Sjmallett usbc_diepctl.s.usbactep = 1; 983215976Sjmallett usbc_diepctl.s.nextep = endpoint_num; 984215976Sjmallett if (endpoint_num == 0) 985215976Sjmallett { 986215976Sjmallett switch (max_packet_size) 987215976Sjmallett { 988215976Sjmallett case 8: 989215976Sjmallett usbc_diepctl.s.mps = 3; 990215976Sjmallett break; 991215976Sjmallett case 16: 992215976Sjmallett usbc_diepctl.s.mps = 2; 993215976Sjmallett break; 994215976Sjmallett case 32: 995215976Sjmallett usbc_diepctl.s.mps = 1; 996215976Sjmallett break; 997215976Sjmallett default: 998215976Sjmallett usbc_diepctl.s.mps = 0; 999215976Sjmallett break; 1000215976Sjmallett } 1001215976Sjmallett } 1002215976Sjmallett else 1003215976Sjmallett usbc_diepctl.s.mps = max_packet_size; 1004215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPCTLX(endpoint_num, usb->index), usbc_diepctl.u32); 1005215976Sjmallett 1006215976Sjmallett return 0; 1007215976Sjmallett} 1008215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 1009215976SjmallettEXPORT_SYMBOL(cvmx_usbd_in_endpoint_enable); 1010215976Sjmallett#endif 1011215976Sjmallett 1012215976Sjmallett 1013215976Sjmallett/** 1014215976Sjmallett * Disable an IN endpoint 1015215976Sjmallett * 1016215976Sjmallett * @param usb USB device state populated by 1017215976Sjmallett * cvmx_usbd_initialize(). 1018215976Sjmallett * @param endpoint_num 1019215976Sjmallett * Endpoint number to disable 1020215976Sjmallett * 1021215976Sjmallett * @return Zero on success, negative on failure 1022215976Sjmallett */ 1023215976Sjmallettint cvmx_usbd_in_endpoint_disable(cvmx_usbd_state_t *usb, int endpoint_num) 1024215976Sjmallett{ 1025215976Sjmallett cvmx_usbcx_diepctlx_t usbc_diepctl; 1026215976Sjmallett 1027215976Sjmallett if (cvmx_unlikely(usb->init_flags & CVMX_USBD_INITIALIZE_FLAGS_DEBUG)) 1028215976Sjmallett cvmx_dprintf("%s: endpoint=%d\n", __FUNCTION__, endpoint_num); 1029215976Sjmallett 1030215976Sjmallett usbc_diepctl.u32 = __cvmx_usbd_read_csr32(usb, CVMX_USBCX_DIEPCTLX(endpoint_num, usb->index)); 1031215976Sjmallett if (usbc_diepctl.s.epena && !usbc_diepctl.s.epdis) 1032215976Sjmallett { 1033215976Sjmallett usbc_diepctl.s.epdis = 1; 1034215976Sjmallett __cvmx_usbd_write_csr32(usb, CVMX_USBCX_DIEPCTLX(endpoint_num, usb->index), usbc_diepctl.u32); 1035215976Sjmallett } 1036215976Sjmallett return 0; 1037215976Sjmallett} 1038215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 1039215976SjmallettEXPORT_SYMBOL(cvmx_usbd_in_endpoint_disable); 1040215976Sjmallett#endif 1041215976Sjmallett 1042