Commit 10849371 authored by Aaro Koskinen's avatar Aaro Koskinen Committed by Greg Kroah-Hartman

staging: octeon-usb: cvmx-usb: reformat long comments

Reformat long comments according to multi-line comment style.
Signed-off-by: default avatarAaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent eeb90cb2
...@@ -78,9 +78,11 @@ ...@@ -78,9 +78,11 @@
#define MAX_TRANSFER_BYTES ((1<<19)-1) /* The low level hardware can transfer a maximum of this number of bytes in each transfer. The field is 19 bits wide */ #define MAX_TRANSFER_BYTES ((1<<19)-1) /* The low level hardware can transfer a maximum of this number of bytes in each transfer. The field is 19 bits wide */
#define MAX_TRANSFER_PACKETS ((1<<10)-1) /* The low level hardware can transfer a maximum of this number of packets in each transfer. The field is 10 bits wide */ #define MAX_TRANSFER_PACKETS ((1<<10)-1) /* The low level hardware can transfer a maximum of this number of packets in each transfer. The field is 10 bits wide */
/* These defines disable the normal read and write csr. This is so I can add /*
extra debug stuff to the usb specific version and I won't use the normal * These defines disable the normal read and write csr. This is so I can add
version by mistake */ * extra debug stuff to the usb specific version and I won't use the normal
* version by mistake
*/
#define cvmx_read_csr use_cvmx_usb_read_csr64_instead_of_cvmx_read_csr #define cvmx_read_csr use_cvmx_usb_read_csr64_instead_of_cvmx_read_csr
#define cvmx_write_csr use_cvmx_usb_write_csr64_instead_of_cvmx_write_csr #define cvmx_write_csr use_cvmx_usb_write_csr64_instead_of_cvmx_write_csr
...@@ -227,8 +229,10 @@ typedef struct { ...@@ -227,8 +229,10 @@ typedef struct {
} while (0); \ } while (0); \
result; }) result; })
/* This macro logically sets a single field in a CSR. It does the sequence /*
read, modify, and write */ * This macro logically sets a single field in a CSR. It does the sequence
* read, modify, and write
*/
#define USB_SET_FIELD32(address, type, field, value) \ #define USB_SET_FIELD32(address, type, field, value) \
do { \ do { \
type c; \ type c; \
...@@ -562,23 +566,30 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number, ...@@ -562,23 +566,30 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number,
__cvmx_usb_append_pipe(&usb->free_pipes, usb->pipe + i); __cvmx_usb_append_pipe(&usb->free_pipes, usb->pipe + i);
} }
/* Power On Reset and PHY Initialization */ /*
* Power On Reset and PHY Initialization
/* 1. Wait for DCOK to assert (nothing to do) */ *
/* 2a. Write USBN0/1_CLK_CTL[POR] = 1 and * 1. Wait for DCOK to assert (nothing to do)
USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0 */ *
* 2a. Write USBN0/1_CLK_CTL[POR] = 1 and
* USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0
*/
usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index)); usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
usbn_clk_ctl.s.por = 1; usbn_clk_ctl.s.por = 1;
usbn_clk_ctl.s.hrst = 0; usbn_clk_ctl.s.hrst = 0;
usbn_clk_ctl.s.prst = 0; usbn_clk_ctl.s.prst = 0;
usbn_clk_ctl.s.hclk_rst = 0; usbn_clk_ctl.s.hclk_rst = 0;
usbn_clk_ctl.s.enable = 0; usbn_clk_ctl.s.enable = 0;
/* 2b. Select the USB reference clock/crystal parameters by writing /*
appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON] */ * 2b. Select the USB reference clock/crystal parameters by writing
* appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON]
*/
if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) { if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) {
/* The USB port uses 12/24/48MHz 2.5V board clock /*
source at USB_XO. USB_XI should be tied to GND. * The USB port uses 12/24/48MHz 2.5V board clock
Most Octeon evaluation boards require this setting */ * source at USB_XO. USB_XI should be tied to GND.
* Most Octeon evaluation boards require this setting
*/
if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) { if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */ usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */
usbn_clk_ctl.cn31xx.p_xenbn = 0; usbn_clk_ctl.cn31xx.p_xenbn = 0;
...@@ -599,8 +610,10 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number, ...@@ -599,8 +610,10 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number,
break; break;
} }
} else { } else {
/* The USB port uses a 12MHz crystal as clock source /*
at USB_XO and USB_XI */ * The USB port uses a 12MHz crystal as clock source
* at USB_XO and USB_XI
*/
if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) { if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */ usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */
usbn_clk_ctl.cn31xx.p_xenbn = 1; usbn_clk_ctl.cn31xx.p_xenbn = 1;
...@@ -611,9 +624,11 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number, ...@@ -611,9 +624,11 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number,
usbn_clk_ctl.s.p_c_sel = 0; usbn_clk_ctl.s.p_c_sel = 0;
} }
/* 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and /*
setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down such * 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and
that USB is as close as possible to 125Mhz */ * setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down
* such that USB is as close as possible to 125Mhz
*/
{ {
int divisor = (octeon_get_clock_rate()+125000000-1)/125000000; int divisor = (octeon_get_clock_rate()+125000000-1)/125000000;
if (divisor < 4) /* Lower than 4 doesn't seem to work properly */ if (divisor < 4) /* Lower than 4 doesn't seem to work properly */
...@@ -629,41 +644,55 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number, ...@@ -629,41 +644,55 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number,
usbn_clk_ctl.u64); usbn_clk_ctl.u64);
/* 2e. Wait 64 core-clock cycles for HCLK to stabilize */ /* 2e. Wait 64 core-clock cycles for HCLK to stabilize */
cvmx_wait(64); cvmx_wait(64);
/* 3. Program the power-on reset field in the USBN clock-control register: /*
USBN_CLK_CTL[POR] = 0 */ * 3. Program the power-on reset field in the USBN clock-control
* register:
* USBN_CLK_CTL[POR] = 0
*/
usbn_clk_ctl.s.por = 0; usbn_clk_ctl.s.por = 0;
__cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
usbn_clk_ctl.u64); usbn_clk_ctl.u64);
/* 4. Wait 1 ms for PHY clock to start */ /* 4. Wait 1 ms for PHY clock to start */
mdelay(1); mdelay(1);
/* 5. Program the Reset input from automatic test equipment field in the /*
USBP control and status register: USBN_USBP_CTL_STATUS[ATE_RESET] = 1 */ * 5. Program the Reset input from automatic test equipment field in the
* USBP control and status register:
* USBN_USBP_CTL_STATUS[ATE_RESET] = 1
*/
usbn_usbp_ctl_status.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index)); usbn_usbp_ctl_status.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index));
usbn_usbp_ctl_status.s.ate_reset = 1; usbn_usbp_ctl_status.s.ate_reset = 1;
__cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index), __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
usbn_usbp_ctl_status.u64); usbn_usbp_ctl_status.u64);
/* 6. Wait 10 cycles */ /* 6. Wait 10 cycles */
cvmx_wait(10); cvmx_wait(10);
/* 7. Clear ATE_RESET field in the USBN clock-control register: /*
USBN_USBP_CTL_STATUS[ATE_RESET] = 0 */ * 7. Clear ATE_RESET field in the USBN clock-control register:
* USBN_USBP_CTL_STATUS[ATE_RESET] = 0
*/
usbn_usbp_ctl_status.s.ate_reset = 0; usbn_usbp_ctl_status.s.ate_reset = 0;
__cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index), __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
usbn_usbp_ctl_status.u64); usbn_usbp_ctl_status.u64);
/* 8. Program the PHY reset field in the USBN clock-control register: /*
USBN_CLK_CTL[PRST] = 1 */ * 8. Program the PHY reset field in the USBN clock-control register:
* USBN_CLK_CTL[PRST] = 1
*/
usbn_clk_ctl.s.prst = 1; usbn_clk_ctl.s.prst = 1;
__cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
usbn_clk_ctl.u64); usbn_clk_ctl.u64);
/* 9. Program the USBP control and status register to select host or /*
device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for * 9. Program the USBP control and status register to select host or
device */ * device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for
* device
*/
usbn_usbp_ctl_status.s.hst_mode = 0; usbn_usbp_ctl_status.s.hst_mode = 0;
__cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index), __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
usbn_usbp_ctl_status.u64); usbn_usbp_ctl_status.u64);
/* 10. Wait 1 us */ /* 10. Wait 1 us */
udelay(1); udelay(1);
/* 11. Program the hreset_n field in the USBN clock-control register: /*
USBN_CLK_CTL[HRST] = 1 */ * 11. Program the hreset_n field in the USBN clock-control register:
* USBN_CLK_CTL[HRST] = 1
*/
usbn_clk_ctl.s.hrst = 1; usbn_clk_ctl.s.hrst = 1;
__cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
usbn_clk_ctl.u64); usbn_clk_ctl.u64);
...@@ -673,20 +702,24 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number, ...@@ -673,20 +702,24 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number,
usbn_clk_ctl.u64); usbn_clk_ctl.u64);
udelay(1); udelay(1);
/* USB Core Initialization */ /*
* USB Core Initialization
/* 1. Read USBC_GHWCFG1, USBC_GHWCFG2, USBC_GHWCFG3, USBC_GHWCFG4 to *
determine USB core configuration parameters. */ * 1. Read USBC_GHWCFG1, USBC_GHWCFG2, USBC_GHWCFG3, USBC_GHWCFG4 to
/* Nothing needed */ * determine USB core configuration parameters.
/* 2. Program the following fields in the global AHB configuration *
register (USBC_GAHBCFG) * Nothing needed
DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode *
Burst length, USBC_GAHBCFG[HBSTLEN] = 0 * 2. Program the following fields in the global AHB configuration
Nonperiodic TxFIFO empty level (slave mode only), * register (USBC_GAHBCFG)
USBC_GAHBCFG[NPTXFEMPLVL] * DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode
Periodic TxFIFO empty level (slave mode only), * Burst length, USBC_GAHBCFG[HBSTLEN] = 0
USBC_GAHBCFG[PTXFEMPLVL] * Nonperiodic TxFIFO empty level (slave mode only),
Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1 */ * USBC_GAHBCFG[NPTXFEMPLVL]
* Periodic TxFIFO empty level (slave mode only),
* USBC_GAHBCFG[PTXFEMPLVL]
* Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1
*/
{ {
cvmx_usbcx_gahbcfg_t usbcx_gahbcfg; cvmx_usbcx_gahbcfg_t usbcx_gahbcfg;
/* Due to an errata, CN31XX doesn't support DMA */ /* Due to an errata, CN31XX doesn't support DMA */
...@@ -707,11 +740,13 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number, ...@@ -707,11 +740,13 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number,
__cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index), __cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index),
usbcx_gahbcfg.u32); usbcx_gahbcfg.u32);
} }
/* 3. Program the following fields in USBC_GUSBCFG register. /*
HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0 * 3. Program the following fields in USBC_GUSBCFG register.
ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0 * HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0
USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5 * ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0
PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0 */ * USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5
* PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0
*/
{ {
cvmx_usbcx_gusbcfg_t usbcx_gusbcfg; cvmx_usbcx_gusbcfg_t usbcx_gusbcfg;
usbcx_gusbcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index)); usbcx_gusbcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index));
...@@ -722,10 +757,12 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number, ...@@ -722,10 +757,12 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number,
__cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index), __cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index),
usbcx_gusbcfg.u32); usbcx_gusbcfg.u32);
} }
/* 4. The software must unmask the following bits in the USBC_GINTMSK /*
register. * 4. The software must unmask the following bits in the USBC_GINTMSK
OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1 * register.
Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1 */ * OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1
* Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1
*/
{ {
cvmx_usbcx_gintmsk_t usbcx_gintmsk; cvmx_usbcx_gintmsk_t usbcx_gintmsk;
int channel; int channel;
...@@ -747,16 +784,20 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number, ...@@ -747,16 +784,20 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number,
} }
{ {
/* Host Port Initialization */ /*
* Host Port Initialization
/* 1. Program the host-port interrupt-mask field to unmask, *
USBC_GINTMSK[PRTINT] = 1 */ * 1. Program the host-port interrupt-mask field to unmask,
* USBC_GINTMSK[PRTINT] = 1
*/
USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t,
prtintmsk, 1); prtintmsk, 1);
USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t,
disconnintmsk, 1); disconnintmsk, 1);
/* 2. Program the USBC_HCFG register to select full-speed host or /*
high-speed host. */ * 2. Program the USBC_HCFG register to select full-speed host
* or high-speed host.
*/
{ {
cvmx_usbcx_hcfg_t usbcx_hcfg; cvmx_usbcx_hcfg_t usbcx_hcfg;
usbcx_hcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index)); usbcx_hcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index));
...@@ -764,11 +805,15 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number, ...@@ -764,11 +805,15 @@ int cvmx_usb_initialize(cvmx_usb_state_t *state, int usb_port_number,
usbcx_hcfg.s.fslspclksel = 0; usbcx_hcfg.s.fslspclksel = 0;
__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32); __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32);
} }
/* 3. Program the port power bit to drive VBUS on the USB, /*
USBC_HPRT[PRTPWR] = 1 */ * 3. Program the port power bit to drive VBUS on the USB,
* USBC_HPRT[PRTPWR] = 1
*/
USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtpwr, 1); USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtpwr, 1);
/* Steps 4-15 from the manual are done later in the port enable */ /*
* Steps 4-15 from the manual are done later in the port enable
*/
} }
return 0; return 0;
...@@ -827,8 +872,10 @@ int cvmx_usb_enable(cvmx_usb_state_t *state) ...@@ -827,8 +872,10 @@ int cvmx_usb_enable(cvmx_usb_state_t *state)
usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
/* If the port is already enabled the just return. We don't need to do /*
anything */ * If the port is already enabled the just return. We don't need to do
* anything
*/
if (usb->usbcx_hprt.s.prtena) if (usb->usbcx_hprt.s.prtena)
return 0; return 0;
...@@ -840,8 +887,10 @@ int cvmx_usb_enable(cvmx_usb_state_t *state) ...@@ -840,8 +887,10 @@ int cvmx_usb_enable(cvmx_usb_state_t *state)
/* Program the port reset bit to start the reset process */ /* Program the port reset bit to start the reset process */
USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtrst, 1); USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtrst, 1);
/* Wait at least 50ms (high speed), or 10ms (full speed) for the reset /*
process to complete. */ * Wait at least 50ms (high speed), or 10ms (full speed) for the reset
* process to complete.
*/
mdelay(50); mdelay(50);
/* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */ /* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */
...@@ -856,13 +905,17 @@ int cvmx_usb_enable(cvmx_usb_state_t *state) ...@@ -856,13 +905,17 @@ int cvmx_usb_enable(cvmx_usb_state_t *state)
usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
usbcx_ghwcfg3.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GHWCFG3(usb->index)); usbcx_ghwcfg3.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GHWCFG3(usb->index));
/* 13. Program the USBC_GRXFSIZ register to select the size of the receive /*
FIFO (25%). */ * 13. Program the USBC_GRXFSIZ register to select the size of the
* receive FIFO (25%).
*/
USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), cvmx_usbcx_grxfsiz_t, USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), cvmx_usbcx_grxfsiz_t,
rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4); rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4);
/* 14. Program the USBC_GNPTXFSIZ register to select the size and the /*
start address of the non- periodic transmit FIFO for nonperiodic * 14. Program the USBC_GNPTXFSIZ register to select the size and the
transactions (50%). */ * start address of the non- periodic transmit FIFO for nonperiodic
* transactions (50%).
*/
{ {
cvmx_usbcx_gnptxfsiz_t siz; cvmx_usbcx_gnptxfsiz_t siz;
siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index)); siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index));
...@@ -870,8 +923,11 @@ int cvmx_usb_enable(cvmx_usb_state_t *state) ...@@ -870,8 +923,11 @@ int cvmx_usb_enable(cvmx_usb_state_t *state)
siz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4; siz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4;
__cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), siz.u32); __cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), siz.u32);
} }
/* 15. Program the USBC_HPTXFSIZ register to select the size and start /*
address of the periodic transmit FIFO for periodic transactions (25%). */ * 15. Program the USBC_HPTXFSIZ register to select the size and start
* address of the periodic transmit FIFO for periodic transactions
* (25%).
*/
{ {
cvmx_usbcx_hptxfsiz_t siz; cvmx_usbcx_hptxfsiz_t siz;
siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index)); siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index));
...@@ -1112,8 +1168,10 @@ int cvmx_usb_open_pipe(cvmx_usb_state_t *state, cvmx_usb_pipe_flags_t flags, ...@@ -1112,8 +1168,10 @@ int cvmx_usb_open_pipe(cvmx_usb_state_t *state, cvmx_usb_pipe_flags_t flags,
pipe->max_packet = max_packet; pipe->max_packet = max_packet;
pipe->transfer_type = transfer_type; pipe->transfer_type = transfer_type;
pipe->transfer_dir = transfer_dir; pipe->transfer_dir = transfer_dir;
/* All pipes use interval to rate limit NAK processing. Force an interval /*
if one wasn't supplied */ * All pipes use interval to rate limit NAK processing. Force an
* interval if one wasn't supplied
*/
if (!interval) if (!interval)
interval = 1; interval = 1;
if (__cvmx_usb_pipe_needs_split(usb, pipe)) { if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
...@@ -1131,8 +1189,10 @@ int cvmx_usb_open_pipe(cvmx_usb_state_t *state, cvmx_usb_pipe_flags_t flags, ...@@ -1131,8 +1189,10 @@ int cvmx_usb_open_pipe(cvmx_usb_state_t *state, cvmx_usb_pipe_flags_t flags,
pipe->split_sc_frame = -1; pipe->split_sc_frame = -1;
__cvmx_usb_append_pipe(&usb->idle_pipes, pipe); __cvmx_usb_append_pipe(&usb->idle_pipes, pipe);
/* We don't need to tell the hardware about this pipe yet since /*
it doesn't have any submitted requests */ * We don't need to tell the hardware about this pipe yet since
* it doesn't have any submitted requests
*/
return __cvmx_usb_get_pipe_handle(usb, pipe); return __cvmx_usb_get_pipe_handle(usb, pipe);
} }
...@@ -1198,8 +1258,10 @@ static void __cvmx_usb_poll_rx_fifo(cvmx_usb_internal_state_t *usb) ...@@ -1198,8 +1258,10 @@ static void __cvmx_usb_poll_rx_fifo(cvmx_usb_internal_state_t *usb)
*/ */
static int __cvmx_usb_fill_tx_hw(cvmx_usb_internal_state_t *usb, cvmx_usb_tx_fifo_t *fifo, int available) static int __cvmx_usb_fill_tx_hw(cvmx_usb_internal_state_t *usb, cvmx_usb_tx_fifo_t *fifo, int available)
{ {
/* We're done either when there isn't anymore space or the software FIFO /*
is empty */ * We're done either when there isn't anymore space or the software FIFO
* is empty
*/
while (available && (fifo->head != fifo->tail)) { while (available && (fifo->head != fifo->tail)) {
int i = fifo->tail; int i = fifo->tail;
const uint32_t *ptr = cvmx_phys_to_ptr(fifo->entry[i].address); const uint32_t *ptr = cvmx_phys_to_ptr(fifo->entry[i].address);
...@@ -1219,8 +1281,10 @@ static int __cvmx_usb_fill_tx_hw(cvmx_usb_internal_state_t *usb, cvmx_usb_tx_fif ...@@ -1219,8 +1281,10 @@ static int __cvmx_usb_fill_tx_hw(cvmx_usb_internal_state_t *usb, cvmx_usb_tx_fif
fifo->entry[i].address += words * 4; fifo->entry[i].address += words * 4;
fifo->entry[i].size -= words; fifo->entry[i].size -= words;
/* Write the HW fifo data. The read every three writes is due /*
to an errata on CN3XXX chips */ * Write the HW fifo data. The read every three writes is due
* to an errata on CN3XXX chips
*/
while (words > 3) { while (words > 3) {
cvmx_write64_uint32(csr_address, *ptr++); cvmx_write64_uint32(csr_address, *ptr++);
cvmx_write64_uint32(csr_address, *ptr++); cvmx_write64_uint32(csr_address, *ptr++);
...@@ -1351,8 +1415,10 @@ static void __cvmx_usb_start_channel_control(cvmx_usb_internal_state_t *usb, ...@@ -1351,8 +1415,10 @@ static void __cvmx_usb_start_channel_control(cvmx_usb_internal_state_t *usb,
bytes_to_transfer = sizeof(*header); bytes_to_transfer = sizeof(*header);
/* All Control operations start with a setup going OUT */ /* All Control operations start with a setup going OUT */
USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, epdir, CVMX_USB_DIRECTION_OUT); USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, epdir, CVMX_USB_DIRECTION_OUT);
/* Setup send the control header instead of the buffer data. The /*
buffer data will be used in the next stage */ * Setup send the control header instead of the buffer data. The
* buffer data will be used in the next stage
*/
__cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, transaction->control_header); __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, transaction->control_header);
break; break;
case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE: case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
...@@ -1406,28 +1472,36 @@ static void __cvmx_usb_start_channel_control(cvmx_usb_internal_state_t *usb, ...@@ -1406,28 +1472,36 @@ static void __cvmx_usb_start_channel_control(cvmx_usb_internal_state_t *usb,
break; break;
} }
/* Make sure the transfer never exceeds the byte limit of the hardware. /*
Further bytes will be sent as continued transactions */ * Make sure the transfer never exceeds the byte limit of the hardware.
* Further bytes will be sent as continued transactions
*/
if (bytes_to_transfer > MAX_TRANSFER_BYTES) { if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
/* Round MAX_TRANSFER_BYTES to a multiple of out packet size */ /* Round MAX_TRANSFER_BYTES to a multiple of out packet size */
bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet; bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
bytes_to_transfer *= pipe->max_packet; bytes_to_transfer *= pipe->max_packet;
} }
/* Calculate the number of packets to transfer. If the length is zero /*
we still need to transfer one packet */ * Calculate the number of packets to transfer. If the length is zero
* we still need to transfer one packet
*/
packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet; packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
if (packets_to_transfer == 0) if (packets_to_transfer == 0)
packets_to_transfer = 1; packets_to_transfer = 1;
else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) { else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
/* Limit to one packet when not using DMA. Channels must be restarted /*
between every packet for IN transactions, so there is no reason to * Limit to one packet when not using DMA. Channels must be
do multiple packets in a row */ * restarted between every packet for IN transactions, so there
* is no reason to do multiple packets in a row
*/
packets_to_transfer = 1; packets_to_transfer = 1;
bytes_to_transfer = packets_to_transfer * pipe->max_packet; bytes_to_transfer = packets_to_transfer * pipe->max_packet;
} else if (packets_to_transfer > MAX_TRANSFER_PACKETS) { } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
/* Limit the number of packet and data transferred to what the /*
hardware can handle */ * Limit the number of packet and data transferred to what the
* hardware can handle
*/
packets_to_transfer = MAX_TRANSFER_PACKETS; packets_to_transfer = MAX_TRANSFER_PACKETS;
bytes_to_transfer = packets_to_transfer * pipe->max_packet; bytes_to_transfer = packets_to_transfer * pipe->max_packet;
} }
...@@ -1517,17 +1591,24 @@ static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb, ...@@ -1517,17 +1591,24 @@ static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb,
int packets_to_transfer; int packets_to_transfer;
int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes; int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes;
/* ISOCHRONOUS transactions store each individual transfer size in the /*
packet structure, not the global buffer_length */ * ISOCHRONOUS transactions store each individual transfer size
* in the packet structure, not the global buffer_length
*/
if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS) if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
bytes_to_transfer = transaction->iso_packets[0].length - transaction->actual_bytes; bytes_to_transfer = transaction->iso_packets[0].length - transaction->actual_bytes;
/* We need to do split transactions when we are talking to non high /*
speed devices that are behind a high speed hub */ * We need to do split transactions when we are talking to non
* high speed devices that are behind a high speed hub
*/
if (__cvmx_usb_pipe_needs_split(usb, pipe)) { if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
/* On the start split phase (stage is even) record the frame number we /*
will need to send the split complete. We only store the lower two bits * On the start split phase (stage is even) record the
since the time ahead can only be two frames */ * frame number we will need to send the split complete.
* We only store the lower two bits since the time ahead
* can only be two frames
*/
if ((transaction->stage&1) == 0) { if ((transaction->stage&1) == 0) {
if (transaction->type == CVMX_USB_TRANSFER_BULK) if (transaction->type == CVMX_USB_TRANSFER_BULK)
pipe->split_sc_frame = (usb->frame_number + 1) & 0x7f; pipe->split_sc_frame = (usb->frame_number + 1) & 0x7f;
...@@ -1541,64 +1622,94 @@ static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb, ...@@ -1541,64 +1622,94 @@ static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb,
usbc_hcsplt.s.prtaddr = pipe->hub_port; usbc_hcsplt.s.prtaddr = pipe->hub_port;
usbc_hcsplt.s.compsplt = (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE); usbc_hcsplt.s.compsplt = (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE);
/* SPLIT transactions can only ever transmit one data packet so /*
limit the transfer size to the max packet size */ * SPLIT transactions can only ever transmit one data
* packet so limit the transfer size to the max packet
* size
*/
if (bytes_to_transfer > pipe->max_packet) if (bytes_to_transfer > pipe->max_packet)
bytes_to_transfer = pipe->max_packet; bytes_to_transfer = pipe->max_packet;
/* ISOCHRONOUS OUT splits are unique in that they limit /*
data transfers to 188 byte chunks representing the * ISOCHRONOUS OUT splits are unique in that they limit
begin/middle/end of the data or all */ * data transfers to 188 byte chunks representing the
* begin/middle/end of the data or all
*/
if (!usbc_hcsplt.s.compsplt && if (!usbc_hcsplt.s.compsplt &&
(pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) && (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
(pipe->transfer_type == CVMX_USB_TRANSFER_ISOCHRONOUS)) { (pipe->transfer_type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
/* Clear the split complete frame number as there isn't going /*
to be a split complete */ * Clear the split complete frame number as
* there isn't going to be a split complete
*/
pipe->split_sc_frame = -1; pipe->split_sc_frame = -1;
/* See if we've started this transfer and sent data */ /*
* See if we've started this transfer and sent
* data
*/
if (transaction->actual_bytes == 0) { if (transaction->actual_bytes == 0) {
/* Nothing sent yet, this is either a begin or the /*
entire payload */ * Nothing sent yet, this is either a
* begin or the entire payload
*/
if (bytes_to_transfer <= 188) if (bytes_to_transfer <= 188)
usbc_hcsplt.s.xactpos = 3; /* Entire payload in one go */ usbc_hcsplt.s.xactpos = 3; /* Entire payload in one go */
else else
usbc_hcsplt.s.xactpos = 2; /* First part of payload */ usbc_hcsplt.s.xactpos = 2; /* First part of payload */
} else { } else {
/* Continuing the previous data, we must either be /*
in the middle or at the end */ * Continuing the previous data, we must
* either be in the middle or at the end
*/
if (bytes_to_transfer <= 188) if (bytes_to_transfer <= 188)
usbc_hcsplt.s.xactpos = 1; /* End of payload */ usbc_hcsplt.s.xactpos = 1; /* End of payload */
else else
usbc_hcsplt.s.xactpos = 0; /* Middle of payload */ usbc_hcsplt.s.xactpos = 0; /* Middle of payload */
} }
/* Again, the transfer size is limited to 188 bytes */ /*
* Again, the transfer size is limited to 188
* bytes
*/
if (bytes_to_transfer > 188) if (bytes_to_transfer > 188)
bytes_to_transfer = 188; bytes_to_transfer = 188;
} }
} }
/* Make sure the transfer never exceeds the byte limit of the hardware. /*
Further bytes will be sent as continued transactions */ * Make sure the transfer never exceeds the byte limit of the
* hardware. Further bytes will be sent as continued
* transactions
*/
if (bytes_to_transfer > MAX_TRANSFER_BYTES) { if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
/* Round MAX_TRANSFER_BYTES to a multiple of out packet size */ /*
* Round MAX_TRANSFER_BYTES to a multiple of out packet
* size
*/
bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet; bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
bytes_to_transfer *= pipe->max_packet; bytes_to_transfer *= pipe->max_packet;
} }
/* Calculate the number of packets to transfer. If the length is zero /*
we still need to transfer one packet */ * Calculate the number of packets to transfer. If the length is
* zero we still need to transfer one packet
*/
packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet; packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
if (packets_to_transfer == 0) if (packets_to_transfer == 0)
packets_to_transfer = 1; packets_to_transfer = 1;
else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) { else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
/* Limit to one packet when not using DMA. Channels must be restarted /*
between every packet for IN transactions, so there is no reason to * Limit to one packet when not using DMA. Channels must
do multiple packets in a row */ * be restarted between every packet for IN
* transactions, so there is no reason to do multiple
* packets in a row
*/
packets_to_transfer = 1; packets_to_transfer = 1;
bytes_to_transfer = packets_to_transfer * pipe->max_packet; bytes_to_transfer = packets_to_transfer * pipe->max_packet;
} else if (packets_to_transfer > MAX_TRANSFER_PACKETS) { } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
/* Limit the number of packet and data transferred to what the /*
hardware can handle */ * Limit the number of packet and data transferred to
* what the hardware can handle
*/
packets_to_transfer = MAX_TRANSFER_PACKETS; packets_to_transfer = MAX_TRANSFER_PACKETS;
bytes_to_transfer = packets_to_transfer * pipe->max_packet; bytes_to_transfer = packets_to_transfer * pipe->max_packet;
} }
...@@ -1608,7 +1719,9 @@ static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb, ...@@ -1608,7 +1719,9 @@ static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb,
/* Update the DATA0/DATA1 toggle */ /* Update the DATA0/DATA1 toggle */
usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe); usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
/* High speed pipes may need a hardware ping before they start */ /*
* High speed pipes may need a hardware ping before they start
*/
if (pipe->flags & __CVMX_USB_PIPE_FLAGS_NEED_PING) if (pipe->flags & __CVMX_USB_PIPE_FLAGS_NEED_PING)
usbc_hctsiz.s.dopng = 1; usbc_hctsiz.s.dopng = 1;
...@@ -1620,13 +1733,18 @@ static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb, ...@@ -1620,13 +1733,18 @@ static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb,
{ {
cvmx_usbcx_hccharx_t usbc_hcchar = {.u32 = 0}; cvmx_usbcx_hccharx_t usbc_hcchar = {.u32 = 0};
/* Set the startframe odd/even properly. This is only used for periodic */ /*
* Set the startframe odd/even properly. This is only used for
* periodic
*/
usbc_hcchar.s.oddfrm = usb->frame_number&1; usbc_hcchar.s.oddfrm = usb->frame_number&1;
/* Set the number of back to back packets allowed by this endpoint. /*
Split transactions interpret "ec" as the number of immediate * Set the number of back to back packets allowed by this
retries of failure. These retries happen too quickly, so we * endpoint. Split transactions interpret "ec" as the number of
disable these entirely for splits */ * immediate retries of failure. These retries happen too
* quickly, so we disable these entirely for splits
*/
if (__cvmx_usb_pipe_needs_split(usb, pipe)) if (__cvmx_usb_pipe_needs_split(usb, pipe))
usbc_hcchar.s.ec = 1; usbc_hcchar.s.ec = 1;
else if (pipe->multi_count < 1) else if (pipe->multi_count < 1)
...@@ -1656,8 +1774,10 @@ static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb, ...@@ -1656,8 +1774,10 @@ static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb,
break; break;
case CVMX_USB_TRANSFER_ISOCHRONOUS: case CVMX_USB_TRANSFER_ISOCHRONOUS:
if (!__cvmx_usb_pipe_needs_split(usb, pipe)) { if (!__cvmx_usb_pipe_needs_split(usb, pipe)) {
/* ISO transactions require different PIDs depending on direction /*
and how many packets are needed */ * ISO transactions require different PIDs depending on
* direction and how many packets are needed
*/
if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) { if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
if (pipe->multi_count < 2) /* Need DATA0 */ if (pipe->multi_count < 2) /* Need DATA0 */
USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), cvmx_usbcx_hctsizx_t, pid, 0); USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), cvmx_usbcx_hctsizx_t, pid, 0);
...@@ -1745,9 +1865,11 @@ static void __cvmx_usb_schedule(cvmx_usb_internal_state_t *usb, int is_sof) ...@@ -1745,9 +1865,11 @@ static void __cvmx_usb_schedule(cvmx_usb_internal_state_t *usb, int is_sof)
/* Find a pipe needing service */ /* Find a pipe needing service */
pipe = NULL; pipe = NULL;
if (is_sof) { if (is_sof) {
/* Only process periodic pipes on SOF interrupts. This way we are /*
sure that the periodic data is sent in the beginning of the * Only process periodic pipes on SOF interrupts. This
frame */ * way we are sure that the periodic data is sent in the
* beginning of the frame
*/
pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_ISOCHRONOUS, usb->frame_number); pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_ISOCHRONOUS, usb->frame_number);
if (likely(!pipe)) if (likely(!pipe))
pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_INTERRUPT, usb->frame_number); pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_INTERRUPT, usb->frame_number);
...@@ -1764,8 +1886,10 @@ static void __cvmx_usb_schedule(cvmx_usb_internal_state_t *usb, int is_sof) ...@@ -1764,8 +1886,10 @@ static void __cvmx_usb_schedule(cvmx_usb_internal_state_t *usb, int is_sof)
} }
done: done:
/* Only enable SOF interrupts when we have transactions pending in the /*
future that might need to be scheduled */ * Only enable SOF interrupts when we have transactions pending in the
* future that might need to be scheduled
*/
need_sof = 0; need_sof = 0;
for (ttype = CVMX_USB_TRANSFER_CONTROL; ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) { for (ttype = CVMX_USB_TRANSFER_CONTROL; ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) {
pipe = usb->active_pipes[ttype].head; pipe = usb->active_pipes[ttype].head;
...@@ -1850,15 +1974,19 @@ static void __cvmx_usb_perform_complete(cvmx_usb_internal_state_t *usb, ...@@ -1850,15 +1974,19 @@ static void __cvmx_usb_perform_complete(cvmx_usb_internal_state_t *usb,
if (usb->active_split == transaction) if (usb->active_split == transaction)
usb->active_split = NULL; usb->active_split = NULL;
/* Isochronous transactions need extra processing as they might not be done /*
after a single data transfer */ * Isochronous transactions need extra processing as they might not be
* done after a single data transfer
*/
if (unlikely(transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)) { if (unlikely(transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
/* Update the number of bytes transferred in this ISO packet */ /* Update the number of bytes transferred in this ISO packet */
transaction->iso_packets[0].length = transaction->actual_bytes; transaction->iso_packets[0].length = transaction->actual_bytes;
transaction->iso_packets[0].status = complete_code; transaction->iso_packets[0].status = complete_code;
/* If there are more ISOs pending and we succeeded, schedule the next /*
one */ * If there are more ISOs pending and we succeeded, schedule the
* next one
*/
if ((transaction->iso_number_packets > 1) && (complete_code == CVMX_USB_COMPLETE_SUCCESS)) { if ((transaction->iso_number_packets > 1) && (complete_code == CVMX_USB_COMPLETE_SUCCESS)) {
transaction->actual_bytes = 0; /* No bytes transferred for this packet as of yet */ transaction->actual_bytes = 0; /* No bytes transferred for this packet as of yet */
transaction->iso_number_packets--; /* One less ISO waiting to transfer */ transaction->iso_number_packets--; /* One less ISO waiting to transfer */
...@@ -2296,8 +2424,10 @@ int cvmx_usb_cancel(cvmx_usb_state_t *state, int pipe_handle, int submit_handle) ...@@ -2296,8 +2424,10 @@ int cvmx_usb_cancel(cvmx_usb_state_t *state, int pipe_handle, int submit_handle)
if (unlikely((transaction->flags & __CVMX_USB_TRANSACTION_FLAGS_IN_USE) == 0)) if (unlikely((transaction->flags & __CVMX_USB_TRANSACTION_FLAGS_IN_USE) == 0))
return -EINVAL; return -EINVAL;
/* If the transaction is the HEAD of the queue and scheduled. We need to /*
treat it special */ * If the transaction is the HEAD of the queue and scheduled. We need to
* treat it special
*/
if ((pipe->head == transaction) && if ((pipe->head == transaction) &&
(pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED)) { (pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED)) {
cvmx_usbcx_hccharx_t usbc_hcchar; cvmx_usbcx_hccharx_t usbc_hcchar;
...@@ -2468,15 +2598,19 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel) ...@@ -2468,15 +2598,19 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index)); usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) { if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) {
/* There seems to be a bug in CN31XX which can cause interrupt /*
IN transfers to get stuck until we do a write of HCCHARX * There seems to be a bug in CN31XX which can cause
without changing things */ * interrupt IN transfers to get stuck until we do a
* write of HCCHARX without changing things
*/
__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32); __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
return 0; return 0;
} }
/* In non DMA mode the channels don't halt themselves. We need to /*
manually disable channels that are left running */ * In non DMA mode the channels don't halt themselves. We need
* to manually disable channels that are left running
*/
if (!usbc_hcint.s.chhltd) { if (!usbc_hcint.s.chhltd) {
if (usbc_hcchar.s.chena) { if (usbc_hcchar.s.chena) {
cvmx_usbcx_hcintmskx_t hcintmsk; cvmx_usbcx_hcintmskx_t hcintmsk;
...@@ -2495,8 +2629,10 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel) ...@@ -2495,8 +2629,10 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
} }
} }
} else { } else {
/* There is are no interrupts that we need to process when the channel is /*
still running */ * There is are no interrupts that we need to process when the
* channel is still running
*/
if (!usbc_hcint.s.chhltd) if (!usbc_hcint.s.chhltd)
return 0; return 0;
} }
...@@ -2514,33 +2650,45 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel) ...@@ -2514,33 +2650,45 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
transaction = pipe->head; transaction = pipe->head;
CVMX_PREFETCH0(transaction); CVMX_PREFETCH0(transaction);
/* Disconnect this pipe from the HW channel. Later the schedule function will /*
figure out which pipe needs to go */ * Disconnect this pipe from the HW channel. Later the schedule
* function will figure out which pipe needs to go
*/
usb->pipe_for_channel[channel] = NULL; usb->pipe_for_channel[channel] = NULL;
pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED; pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED;
/* Read the channel config info so we can figure out how much data /*
transfered */ * Read the channel config info so we can figure out how much data
* transfered
*/
usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index)); usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index)); usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
/* Calculating the number of bytes successfully transferred is dependent on /*
the transfer direction */ * Calculating the number of bytes successfully transferred is dependent
* on the transfer direction
*/
packets_processed = transaction->pktcnt - usbc_hctsiz.s.pktcnt; packets_processed = transaction->pktcnt - usbc_hctsiz.s.pktcnt;
if (usbc_hcchar.s.epdir) { if (usbc_hcchar.s.epdir) {
/* IN transactions are easy. For every byte received the hardware /*
decrements xfersize. All we need to do is subtract the current * IN transactions are easy. For every byte received the
value of xfersize from its starting value and we know how many * hardware decrements xfersize. All we need to do is subtract
bytes were written to the buffer */ * the current value of xfersize from its starting value and we
* know how many bytes were written to the buffer
*/
bytes_this_transfer = transaction->xfersize - usbc_hctsiz.s.xfersize; bytes_this_transfer = transaction->xfersize - usbc_hctsiz.s.xfersize;
} else { } else {
/* OUT transaction don't decrement xfersize. Instead pktcnt is /*
decremented on every successful packet send. The hardware does * OUT transaction don't decrement xfersize. Instead pktcnt is
this when it receives an ACK, or NYET. If it doesn't * decremented on every successful packet send. The hardware
receive one of these responses pktcnt doesn't change */ * does this when it receives an ACK, or NYET. If it doesn't
* receive one of these responses pktcnt doesn't change
*/
bytes_this_transfer = packets_processed * usbc_hcchar.s.mps; bytes_this_transfer = packets_processed * usbc_hcchar.s.mps;
/* The last packet may not be a full transfer if we didn't have /*
enough data */ * The last packet may not be a full transfer if we didn't have
* enough data
*/
if (bytes_this_transfer > transaction->xfersize) if (bytes_this_transfer > transaction->xfersize)
bytes_this_transfer = transaction->xfersize; bytes_this_transfer = transaction->xfersize;
} }
...@@ -2550,56 +2698,77 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel) ...@@ -2550,56 +2698,77 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
else else
bytes_in_last_packet = bytes_this_transfer; bytes_in_last_packet = bytes_this_transfer;
/* As a special case, setup transactions output the setup header, not /*
the user's data. For this reason we don't count setup data as bytes * As a special case, setup transactions output the setup header, not
transferred */ * the user's data. For this reason we don't count setup data as bytes
* transferred
*/
if ((transaction->stage == CVMX_USB_STAGE_SETUP) || if ((transaction->stage == CVMX_USB_STAGE_SETUP) ||
(transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE)) (transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE))
bytes_this_transfer = 0; bytes_this_transfer = 0;
/* Add the bytes transferred to the running total. It is important that /*
bytes_this_transfer doesn't count any data that needs to be * Add the bytes transferred to the running total. It is important that
retransmitted */ * bytes_this_transfer doesn't count any data that needs to be
* retransmitted
*/
transaction->actual_bytes += bytes_this_transfer; transaction->actual_bytes += bytes_this_transfer;
if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS) if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
buffer_space_left = transaction->iso_packets[0].length - transaction->actual_bytes; buffer_space_left = transaction->iso_packets[0].length - transaction->actual_bytes;
else else
buffer_space_left = transaction->buffer_length - transaction->actual_bytes; buffer_space_left = transaction->buffer_length - transaction->actual_bytes;
/* We need to remember the PID toggle state for the next transaction. The /*
hardware already updated it for the next transaction */ * We need to remember the PID toggle state for the next transaction.
* The hardware already updated it for the next transaction
*/
pipe->pid_toggle = !(usbc_hctsiz.s.pid == 0); pipe->pid_toggle = !(usbc_hctsiz.s.pid == 0);
/* For high speed bulk out, assume the next transaction will need to do a /*
ping before proceeding. If this isn't true the ACK processing below * For high speed bulk out, assume the next transaction will need to do
will clear this flag */ * a ping before proceeding. If this isn't true the ACK processing below
* will clear this flag
*/
if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) && if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
(pipe->transfer_type == CVMX_USB_TRANSFER_BULK) && (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
(pipe->transfer_dir == CVMX_USB_DIRECTION_OUT)) (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT))
pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING; pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
if (usbc_hcint.s.stall) { if (usbc_hcint.s.stall) {
/* STALL as a response means this transaction cannot be completed /*
because the device can't process transactions. Tell the user. Any * STALL as a response means this transaction cannot be
data that was transferred will be counted on the actual bytes * completed because the device can't process transactions. Tell
transferred */ * the user. Any data that was transferred will be counted on
* the actual bytes transferred
*/
pipe->pid_toggle = 0; pipe->pid_toggle = 0;
__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_STALL); __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_STALL);
} else if (usbc_hcint.s.xacterr) { } else if (usbc_hcint.s.xacterr) {
/* We know at least one packet worked if we get a ACK or NAK. Reset the retry counter */ /*
* We know at least one packet worked if we get a ACK or NAK.
* Reset the retry counter
*/
if (usbc_hcint.s.nak || usbc_hcint.s.ack) if (usbc_hcint.s.nak || usbc_hcint.s.ack)
transaction->retries = 0; transaction->retries = 0;
transaction->retries++; transaction->retries++;
if (transaction->retries > MAX_RETRIES) { if (transaction->retries > MAX_RETRIES) {
/* XactErr as a response means the device signaled something wrong with /*
the transfer. For example, PID toggle errors cause these */ * XactErr as a response means the device signaled
* something wrong with the transfer. For example, PID
* toggle errors cause these
*/
__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_XACTERR); __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_XACTERR);
} else { } else {
/* If this was a split then clear our split in progress marker */ /*
* If this was a split then clear our split in progress
* marker
*/
if (usb->active_split == transaction) if (usb->active_split == transaction)
usb->active_split = NULL; usb->active_split = NULL;
/* Rewind to the beginning of the transaction by anding off the /*
split complete bit */ * Rewind to the beginning of the transaction by anding
* off the split complete bit
*/
transaction->stage &= ~1; transaction->stage &= ~1;
pipe->split_sc_frame = -1; pipe->split_sc_frame = -1;
pipe->next_tx_frame += pipe->interval; pipe->next_tx_frame += pipe->interval;
...@@ -2614,38 +2783,49 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel) ...@@ -2614,38 +2783,49 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
/* We'll retry the exact same transaction again */ /* We'll retry the exact same transaction again */
transaction->retries++; transaction->retries++;
} else if (usbc_hcint.s.nyet) { } else if (usbc_hcint.s.nyet) {
/* NYET as a response is only allowed in three cases: as a response to /*
a ping, as a response to a split transaction, and as a response to * NYET as a response is only allowed in three cases: as a
a bulk out. The ping case is handled by hardware, so we only have * response to a ping, as a response to a split transaction, and
splits and bulk out */ * as a response to a bulk out. The ping case is handled by
* hardware, so we only have splits and bulk out
*/
if (!__cvmx_usb_pipe_needs_split(usb, pipe)) { if (!__cvmx_usb_pipe_needs_split(usb, pipe)) {
transaction->retries = 0; transaction->retries = 0;
/* If there is more data to go then we need to try again. Otherwise /*
this transaction is complete */ * If there is more data to go then we need to try
* again. Otherwise this transaction is complete
*/
if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet))
__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
} else { } else {
/* Split transactions retry the split complete 4 times then rewind /*
to the start split and do the entire transactions again */ * Split transactions retry the split complete 4 times
* then rewind to the start split and do the entire
* transactions again
*/
transaction->retries++; transaction->retries++;
if ((transaction->retries & 0x3) == 0) { if ((transaction->retries & 0x3) == 0) {
/* Rewind to the beginning of the transaction by anding off the /*
split complete bit */ * Rewind to the beginning of the transaction by
* anding off the split complete bit
*/
transaction->stage &= ~1; transaction->stage &= ~1;
pipe->split_sc_frame = -1; pipe->split_sc_frame = -1;
} }
} }
} else if (usbc_hcint.s.ack) { } else if (usbc_hcint.s.ack) {
transaction->retries = 0; transaction->retries = 0;
/* The ACK bit can only be checked after the other error bits. This is /*
because a multi packet transfer may succeed in a number of packets * The ACK bit can only be checked after the other error bits.
and then get a different response on the last packet. In this case * This is because a multi packet transfer may succeed in a
both ACK and the last response bit will be set. If none of the * number of packets and then get a different response on the
other response bits is set, then the last packet must have been an * last packet. In this case both ACK and the last response bit
ACK */ * will be set. If none of the other response bits is set, then
* the last packet must have been an ACK
/* Since we got an ACK, we know we don't need to do a ping on this *
pipe */ * Since we got an ACK, we know we don't need to do a ping on
* this pipe
*/
pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_NEED_PING; pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_NEED_PING;
switch (transaction->type) { switch (transaction->type) {
...@@ -2680,9 +2860,12 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel) ...@@ -2680,9 +2860,12 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
case CVMX_USB_STAGE_DATA: case CVMX_USB_STAGE_DATA:
if (__cvmx_usb_pipe_needs_split(usb, pipe)) { if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE; transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE;
/* For setup OUT data that are splits, the hardware /*
doesn't appear to count transferred data. Here * For setup OUT data that are splits,
we manually update the data transferred */ * the hardware doesn't appear to count
* transferred data. Here we manually
* update the data transferred
*/
if (!usbc_hcchar.s.epdir) { if (!usbc_hcchar.s.epdir) {
if (buffer_space_left < pipe->max_packet) if (buffer_space_left < pipe->max_packet)
transaction->actual_bytes += buffer_space_left; transaction->actual_bytes += buffer_space_left;
...@@ -2715,10 +2898,12 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel) ...@@ -2715,10 +2898,12 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
break; break;
case CVMX_USB_TRANSFER_BULK: case CVMX_USB_TRANSFER_BULK:
case CVMX_USB_TRANSFER_INTERRUPT: case CVMX_USB_TRANSFER_INTERRUPT:
/* The only time a bulk transfer isn't complete when /*
it finishes with an ACK is during a split transaction. For * The only time a bulk transfer isn't complete when it
splits we need to continue the transfer if more data is * finishes with an ACK is during a split transaction.
needed */ * For splits we need to continue the transfer if more
* data is needed
*/
if (__cvmx_usb_pipe_needs_split(usb, pipe)) { if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL) if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL)
transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE; transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
...@@ -2746,23 +2931,33 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel) ...@@ -2746,23 +2931,33 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
break; break;
case CVMX_USB_TRANSFER_ISOCHRONOUS: case CVMX_USB_TRANSFER_ISOCHRONOUS:
if (__cvmx_usb_pipe_needs_split(usb, pipe)) { if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
/* ISOCHRONOUS OUT splits don't require a complete split stage. /*
Instead they use a sequence of begin OUT splits to transfer * ISOCHRONOUS OUT splits don't require a
the data 188 bytes at a time. Once the transfer is complete, * complete split stage. Instead they use a
the pipe sleeps until the next schedule interval */ * sequence of begin OUT splits to transfer the
* data 188 bytes at a time. Once the transfer
* is complete, the pipe sleeps until the next
* schedule interval
*/
if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) { if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
/* If no space left or this wasn't a max size packet then /*
this transfer is complete. Otherwise start it again * If no space left or this wasn't a max
to send the next 188 bytes */ * size packet then this transfer is
* complete. Otherwise start it again to
* send the next 188 bytes
*/
if (!buffer_space_left || (bytes_this_transfer < 188)) { if (!buffer_space_left || (bytes_this_transfer < 188)) {
pipe->next_tx_frame += pipe->interval; pipe->next_tx_frame += pipe->interval;
__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
} }
} else { } else {
if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) { if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) {
/* We are in the incoming data phase. Keep getting /*
data until we run out of space or get a small * We are in the incoming data
packet */ * phase. Keep getting data
* until we run out of space or
* get a small packet
*/
if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) { if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
pipe->next_tx_frame += pipe->interval; pipe->next_tx_frame += pipe->interval;
__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
...@@ -2780,10 +2975,12 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel) ...@@ -2780,10 +2975,12 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
/* If this was a split then clear our split in progress marker */ /* If this was a split then clear our split in progress marker */
if (usb->active_split == transaction) if (usb->active_split == transaction)
usb->active_split = NULL; usb->active_split = NULL;
/* NAK as a response means the device couldn't accept the transaction, /*
but it should be retried in the future. Rewind to the beginning of * NAK as a response means the device couldn't accept the
the transaction by anding off the split complete bit. Retry in the * transaction, but it should be retried in the future. Rewind
next interval */ * to the beginning of the transaction by anding off the split
* complete bit. Retry in the next interval
*/
transaction->retries = 0; transaction->retries = 0;
transaction->stage &= ~1; transaction->stage &= ~1;
pipe->next_tx_frame += pipe->interval; pipe->next_tx_frame += pipe->interval;
...@@ -2797,8 +2994,10 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel) ...@@ -2797,8 +2994,10 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
/* We'll retry the exact same transaction again */ /* We'll retry the exact same transaction again */
transaction->retries++; transaction->retries++;
} else { } else {
/* We get channel halted interrupts with no result bits sets when the /*
cable is unplugged */ * We get channel halted interrupts with no result bits
* sets when the cable is unplugged
*/
__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR); __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR);
} }
} }
...@@ -2843,10 +3042,13 @@ int cvmx_usb_poll(cvmx_usb_state_t *state) ...@@ -2843,10 +3042,13 @@ int cvmx_usb_poll(cvmx_usb_state_t *state)
__cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32); __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32);
if (usbc_gintsts.s.rxflvl) { if (usbc_gintsts.s.rxflvl) {
/* RxFIFO Non-Empty (RxFLvl) /*
Indicates that there is at least one packet pending to be read * RxFIFO Non-Empty (RxFLvl)
from the RxFIFO. */ * Indicates that there is at least one packet pending to be
/* In DMA mode this is handled by hardware */ * read from the RxFIFO.
*
* In DMA mode this is handled by hardware
*/
if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
__cvmx_usb_poll_rx_fifo(usb); __cvmx_usb_poll_rx_fifo(usb);
} }
...@@ -2857,18 +3059,20 @@ int cvmx_usb_poll(cvmx_usb_state_t *state) ...@@ -2857,18 +3059,20 @@ int cvmx_usb_poll(cvmx_usb_state_t *state)
} }
if (usbc_gintsts.s.disconnint || usbc_gintsts.s.prtint) { if (usbc_gintsts.s.disconnint || usbc_gintsts.s.prtint) {
cvmx_usbcx_hprt_t usbc_hprt; cvmx_usbcx_hprt_t usbc_hprt;
/* Disconnect Detected Interrupt (DisconnInt) /*
Asserted when a device disconnect is detected. */ * Disconnect Detected Interrupt (DisconnInt)
* Asserted when a device disconnect is detected.
/* Host Port Interrupt (PrtInt) *
The core sets this bit to indicate a change in port status of one * Host Port Interrupt (PrtInt)
of the O2P USB core ports in Host mode. The application must * The core sets this bit to indicate a change in port status of
read the Host Port Control and Status (HPRT) register to * one of the O2P USB core ports in Host mode. The application
determine the exact event that caused this interrupt. The * must read the Host Port Control and Status (HPRT) register to
application must clear the appropriate status bit in the Host Port * determine the exact event that caused this interrupt. The
Control and Status register to clear this bit. */ * application must clear the appropriate status bit in the Host
* Port Control and Status register to clear this bit.
/* Call the user's port callback */ *
* Call the user's port callback
*/
__cvmx_usb_perform_callback(usb, NULL, NULL, __cvmx_usb_perform_callback(usb, NULL, NULL,
CVMX_USB_CALLBACK_PORT_CHANGED, CVMX_USB_CALLBACK_PORT_CHANGED,
CVMX_USB_COMPLETE_SUCCESS); CVMX_USB_COMPLETE_SUCCESS);
...@@ -2878,15 +3082,18 @@ int cvmx_usb_poll(cvmx_usb_state_t *state) ...@@ -2878,15 +3082,18 @@ int cvmx_usb_poll(cvmx_usb_state_t *state)
__cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index), usbc_hprt.u32); __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index), usbc_hprt.u32);
} }
if (usbc_gintsts.s.hchint) { if (usbc_gintsts.s.hchint) {
/* Host Channels Interrupt (HChInt) /*
The core sets this bit to indicate that an interrupt is pending on * Host Channels Interrupt (HChInt)
one of the channels of the core (in Host mode). The application * The core sets this bit to indicate that an interrupt is
must read the Host All Channels Interrupt (HAINT) register to * pending on one of the channels of the core (in Host mode).
determine the exact number of the channel on which the * The application must read the Host All Channels Interrupt
interrupt occurred, and then read the corresponding Host * (HAINT) register to determine the exact number of the channel
Channel-n Interrupt (HCINTn) register to determine the exact * on which the interrupt occurred, and then read the
cause of the interrupt. The application must clear the * corresponding Host Channel-n Interrupt (HCINTn) register to
appropriate status bit in the HCINTn register to clear this bit. */ * determine the exact cause of the interrupt. The application
* must clear the appropriate status bit in the HCINTn register
* to clear this bit.
*/
cvmx_usbcx_haint_t usbc_haint; cvmx_usbcx_haint_t usbc_haint;
usbc_haint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINT(usb->index)); usbc_haint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINT(usb->index));
while (usbc_haint.u32) { while (usbc_haint.u32) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment