/** * Initialize and start the SPI interface. * * @param interface The identifier of the packet interface to configure and * use as a SPI interface. * @param mode The operating mode for the SPI interface. The interface * can operate as a full duplex (both Tx and Rx data paths * active) or as a halfplex (either the Tx data path is * active or the Rx data path is active, but not both). * @param timeout Timeout to wait for clock synchronization in seconds * @return Zero on success, negative of failure. */ int cvmx_spi_start_interface(int interface, cvmx_spi_mode_t mode, int timeout) { uint64_t timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; cvmx_spxx_trn4_ctl_t spxx_trn4_ctl; cvmx_spxx_clk_stat_t stat; cvmx_stxx_com_ctl_t stxx_com_ctl; cvmx_srxx_com_ctl_t srxx_com_ctl; cvmx_stxx_spi4_dat_t stxx_spi4_dat; uint64_t count; cvmx_pko_reg_gmx_port_mode_t pko_mode; if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))) return -1; cvmx_dprintf ("SPI%d: mode %s, cal_len: %d, cal_rep: %d\n", interface, modes[mode], CAL_LEN, CAL_REP); // Configure for 16 ports (PKO -> GMX FIFO partition setting) // ---------------------------------------------------------- pko_mode.u64 = cvmx_read_csr(CVMX_PKO_REG_GMX_PORT_MODE); if (interface == 0) { pko_mode.s.mode0 = 0; } else { pko_mode.s.mode1 = 0; } cvmx_write_csr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64); // Configure GMX // ------------------------------------------------- cvmx_write_csr (CVMX_GMXX_TX_PRTS(interface), 0xA); // PRTS [ 4: 0] ( 5b) = 10 // Bringing up Spi4 Interface // ------------------------------------------------- // Reset the Spi4 deskew logic // ------------------------------------------------- cvmx_write_csr (CVMX_SPXX_DBG_DESKEW_CTL(interface), 0x00200000); // DLLDIS [ 0: 0] ( 1b) = 0 // DLLFRC [ 1: 1] ( 1b) = 0 // OFFDLY [ 7: 2] ( 6b) = 0 // BITSEL [12: 8] ( 5b) = 0 // OFFSET [17:13] ( 5b) = 0 // MUX [18:18] ( 1b) = 0 // INC [19:19] ( 1b) = 0 // DEC [20:20] ( 1b) = 0 // CLRDLY [21:21] ( 1b) = 1 // Forces a reset cvmx_wait (100 * MS); // Setup the CLKDLY right in the middle // ------------------------------------------------- cvmx_write_csr (CVMX_SPXX_CLK_CTL(interface), 0x00000830); // SRXDLCK [ 0: 0] ( 1b) = 0 // RCVTRN [ 1: 1] ( 1b) = 0 // DRPTRN [ 2: 2] ( 1b) = 0 // SNDTRN [ 3: 3] ( 1b) = 0 // STATRCV [ 4: 4] ( 1b) = 1 // Enable status channel Rx // STATDRV [ 5: 5] ( 1b) = 1 // Enable status channel Tx // RUNBIST [ 6: 6] ( 1b) = 0 // CLKDLY [11: 7] ( 5b) = 10 // 16 is the middle of the range // SRXLCK [12:12] ( 1b) = 0 // STXLCK [13:13] ( 1b) = 0 // SEETRN [14:14] ( 1b) = 0 cvmx_wait (100 * MS); // Reset SRX0 DLL // ------------------------------------------------- cvmx_write_csr (CVMX_SPXX_CLK_CTL(interface), 0x00000831); // SRXDLCK [ 0: 0] ( 1b) = 1 // Restart the DLL // RCVTRN [ 1: 1] ( 1b) = 0 // DRPTRN [ 2: 2] ( 1b) = 0 // SNDTRN [ 3: 3] ( 1b) = 0 // STATRCV [ 4: 4] ( 1b) = 1 // STATDRV [ 5: 5] ( 1b) = 1 // RUNBIST [ 6: 6] ( 1b) = 0 // CLKDLY [11: 7] ( 5b) = 10 // SRXLCK [12:12] ( 1b) = 0 // STXLCK [13:13] ( 1b) = 0 // SEETRN [14:14] ( 1b) = 0 // Waiting for Inf0 Spi4 RX DLL to lock // ------------------------------------------------- cvmx_wait (100 * MS); // Enable dynamic alignment // ------------------------------------------------- spxx_trn4_ctl.u64 = 0; spxx_trn4_ctl.s.mux_en = 1; spxx_trn4_ctl.s.macro_en = 1; spxx_trn4_ctl.s.maxdist = 16; spxx_trn4_ctl.s.jitter = 1; cvmx_write_csr (CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64); // MUX_EN [ 0: 0] ( 1b) = 1 // MACRO_EN [ 1: 1] ( 1b) = 1 // MAXDIST [ 6: 2] ( 5b) = 16 // SET_BOOT [ 7: 7] ( 1b) = 0 // CLR_BOOT [ 8: 8] ( 1b) = 1 // JITTER [11: 9] ( 3b) = 1 // TRNTEST [12:12] ( 1b) = 0 cvmx_write_csr (CVMX_SPXX_DBG_DESKEW_CTL(interface), 0x0); // DLLDIS [ 0: 0] ( 1b) = 0 // DLLFRC [ 1: 1] ( 1b) = 0 // OFFDLY [ 7: 2] ( 6b) = 0 // BITSEL [12: 8] ( 5b) = 0 // OFFSET [17:13] ( 5b) = 0 // MUX [18:18] ( 1b) = 0 // INC [19:19] ( 1b) = 0 // DEC [20:20] ( 1b) = 0 // CLRDLY [21:21] ( 1b) = 0 if (mode & CVMX_SPI_MODE_RX_HALFPLEX) { // SRX0 Ports // ------------------------------------------------- cvmx_write_csr (CVMX_SRXX_COM_CTL(interface), 0x00000090); // INF_EN [ 0: 0] ( 1b) = 0 // ST_EN [ 3: 3] ( 1b) = 0 // PRTS [ 9: 4] ( 6b) = 9 // SRX0 Calendar Table // ------------------------------------------------- cvmx_write_csr (CVMX_SRXX_SPI4_CALX(0, interface), 0x00013210); // PRT0 [ 4: 0] ( 5b) = 0 // PRT1 [ 9: 5] ( 5b) = 1 // PRT2 [14:10] ( 5b) = 2 // PRT3 [19:15] ( 5b) = 3 // ODDPAR [20:20] ( 1b) = 1 cvmx_write_csr (CVMX_SRXX_SPI4_CALX(1, interface), 0x00017654); // PRT0 [ 4: 0] ( 5b) = 4 // PRT1 [ 9: 5] ( 5b) = 5 // PRT2 [14:10] ( 5b) = 6 // PRT3 [19:15] ( 5b) = 7 // ODDPAR [20:20] ( 1b) = 1 cvmx_write_csr (CVMX_SRXX_SPI4_CALX(2, interface), 0x00000098); // PRT0 [ 4: 0] ( 5b) = 8 // PRT1 [ 9: 5] ( 5b) = 9 // PRT2 [14:10] ( 5b) = 0 // PRT3 [19:15] ( 5b) = 0 // ODDPAR [20:20] ( 1b) = 0 cvmx_write_csr (CVMX_SRXX_SPI4_STAT(interface), (CAL_REP << 8) | CAL_LEN); // LEN [ 7: 0] ( 8b) = a // M [15: 8] ( 8b) = 1 } if (mode & CVMX_SPI_MODE_TX_HALFPLEX) { // STX0 Config // ------------------------------------------------- cvmx_write_csr (CVMX_STXX_ARB_CTL(interface), 0x0); // IGNTPA [ 3: 3] ( 1b) = 0 // MINTRN [ 5: 5] ( 1b) = 0 cvmx_write_csr (CVMX_GMXX_TX_SPI_MAX(interface), 0x0408); // MAX2 [15: 8] ( 8b) = 4 // MAX1 [ 7: 0] ( 8b) = 8 cvmx_write_csr (CVMX_GMXX_TX_SPI_THRESH(interface), 0x4); // THRESH [ 5: 0] ( 6b) = 4 cvmx_write_csr (CVMX_GMXX_TX_SPI_CTL(interface), 0x0); // ENFORCE [ 2: 2] ( 1b) = 0 // TPA_CLR [ 1: 1] ( 1b) = 0 // CONT_PKT [ 0: 0] ( 1b) = 0 // STX0 Training Control // ------------------------------------------------- stxx_spi4_dat.u64 = 0; stxx_spi4_dat.s.alpha = 32; /*Minimum needed by dynamic alignment*/ stxx_spi4_dat.s.max_t = 0xFFFF; /*Minimum interval is 0x20*/ cvmx_write_csr (CVMX_STXX_SPI4_DAT(interface), stxx_spi4_dat.u64); // MAX_T [15: 0] (16b) = 0 // ALPHA [31:16] (16b) = 0 // STX0 Calendar Table // ------------------------------------------------- cvmx_write_csr (CVMX_STXX_SPI4_CALX(0, interface), 0x00013210); // PRT0 [ 4: 0] ( 5b) = 0 // PRT1 [ 9: 5] ( 5b) = 1 // PRT2 [14:10] ( 5b) = 2 // PRT3 [19:15] ( 5b) = 3 // ODDPAR [20:20] ( 1b) = 1 cvmx_write_csr (CVMX_STXX_SPI4_CALX(1, interface), 0x00017654); // PRT0 [ 4: 0] ( 5b) = 4 // PRT1 [ 9: 5] ( 5b) = 5 // PRT2 [14:10] ( 5b) = 6 // PRT3 [19:15] ( 5b) = 7 // ODDPAR [20:20] ( 1b) = 1 cvmx_write_csr (CVMX_STXX_SPI4_CALX(2, interface), 0x00000098); // PRT0 [ 4: 0] ( 5b) = 8 // PRT1 [ 9: 5] ( 5b) = 9 // PRT2 [14:10] ( 5b) = 0 // PRT3 [19:15] ( 5b) = 0 // ODDPAR [20:20] ( 1b) = 0 cvmx_write_csr (CVMX_STXX_SPI4_STAT(interface), (CAL_REP << 8) | CAL_LEN); // LEN [ 7: 0] ( 8b) = a // M [15: 8] ( 8b) = 1 } /* Regardless of operating mode, both Tx and Rx clocks must be present * for the SPI interface to operate. */ cvmx_dprintf ("SPI%d: Waiting to see TsClk...\n", interface); count = 0; timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; do { /* Do we see the TsClk transitioning? */ stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT(interface)); count = count + 1; #ifdef DEBUG if ((count % 5000000) == 10) { cvmx_dprintf ("SPI%d: CLK_STAT 0x%016llX\n" " s4 (%d,%d) d4 (%d,%d)\n", interface, (unsigned long long)stat.u64, stat.s.s4clk0, stat.s.s4clk1, stat.s.d4clk0, stat.s.d4clk1); } #endif if (cvmx_get_cycle() > timeout_time) { cvmx_dprintf ("SPI%d: Timeout\n", interface); return -1; } } while (stat.s.s4clk0 == 0 || stat.s.s4clk1 == 0); cvmx_dprintf ("SPI%d: Waiting to see RsClk...\n", interface); timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; do { /* Do we see the RsClk transitioning? */ stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT(interface)); if (cvmx_get_cycle() > timeout_time) { cvmx_dprintf ("SPI%d: Timeout\n", interface); return -1; } } while (stat.s.d4clk0 == 0 || stat.s.d4clk1 == 0); // SRX0 & STX0 Inf0 Links are configured - begin training // ------------------------------------------------- cvmx_write_csr (CVMX_SPXX_CLK_CTL(interface), 0x0000083f); // SRXDLCK [ 0: 0] ( 1b) = 1 // RCVTRN [ 1: 1] ( 1b) = 1 // DRPTRN [ 2: 2] ( 1b) = 1 ...was 0 // SNDTRN [ 3: 3] ( 1b) = 1 // STATRCV [ 4: 4] ( 1b) = 1 // STATDRV [ 5: 5] ( 1b) = 1 // RUNBIST [ 6: 6] ( 1b) = 0 // CLKDLY [11: 7] ( 5b) = 10 // SRXLCK [12:12] ( 1b) = 0 // STXLCK [13:13] ( 1b) = 0 // SEETRN [14:14] ( 1b) = 0 cvmx_wait (1000 * MS); // SRX0 clear the boot bit // ------------------------------------------------- spxx_trn4_ctl.s.clr_boot = 1; cvmx_write_csr (CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64); // Wait for the training sequence to complete // ------------------------------------------------- // SPX0_CLK_STAT - SPX0_CLK_STAT[SRXTRN] should be 1 (bit8) cvmx_dprintf ("SPI%d: Waiting for training\n", interface); cvmx_wait (1000 * MS); timeout_time = cvmx_get_cycle() + 1000ull * MS * 600; /* Wait a really long time here */ do { stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT(interface)); if (cvmx_get_cycle() > timeout_time) { cvmx_dprintf ("SPI%d: Timeout\n", interface); return -1; } } while (stat.s.srxtrn == 0); if (mode & CVMX_SPI_MODE_RX_HALFPLEX) { // SRX0 interface should be good, send calendar data // ------------------------------------------------- cvmx_dprintf ("SPI%d: Rx is synchronized, start sending calendar data\n", interface); srxx_com_ctl.u64 = 0; srxx_com_ctl.s.prts = 9; srxx_com_ctl.s.inf_en = 1; srxx_com_ctl.s.st_en = 1; cvmx_write_csr (CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64); } if (mode & CVMX_SPI_MODE_TX_HALFPLEX) { // STX0 has achieved sync // The corespondant board should be sending calendar data // Enable the STX0 STAT receiver. // ------------------------------------------------- stxx_com_ctl.u64 = 0; stxx_com_ctl.s.inf_en = 1; stxx_com_ctl.s.st_en = 1; cvmx_write_csr (CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64); // Waiting for calendar sync on STX0 STAT // ------------------------------------------------- // SPX0_CLK_STAT - SPX0_CLK_STAT[STXCAL] should be 1 (bit10) cvmx_dprintf ("SPI%d: Waiting to sync on STX[%d] STAT\n", interface, interface); timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; do { stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT (interface)); if (cvmx_get_cycle() > timeout_time) { cvmx_dprintf ("SPI%d: Timeout\n", interface); return -1; } } while (stat.s.stxcal == 0); } // Inf0 is synched // ------------------------------------------------- // SPX0 is up if (mode & CVMX_SPI_MODE_RX_HALFPLEX) { srxx_com_ctl.s.inf_en = 1; cvmx_write_csr (CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64); cvmx_dprintf ("SPI%d: Rx is now up\n", interface); } if (mode & CVMX_SPI_MODE_TX_HALFPLEX) { stxx_com_ctl.s.inf_en = 1; cvmx_write_csr (CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64); cvmx_dprintf ("SPI%d: Tx is now up\n", interface); } cvmx_write_csr (CVMX_GMXX_RXX_FRM_MIN (0,interface), 40); cvmx_write_csr (CVMX_GMXX_RXX_FRM_MAX (0,interface), 64*1024 - 4); cvmx_write_csr (CVMX_GMXX_RXX_JABBER (0,interface), 64*1024 - 4); return 0; }
/** * Callback to setup calendar and miscellaneous settings before clock detection * * @interface: The identifier of the packet interface to configure and * use as a SPI interface. * @mode: The operating mode for the SPI interface. The interface * can operate as a full duplex (both Tx and Rx data paths * active) or as a halfplex (either the Tx data path is * active or the Rx data path is active, but not both). * @num_ports: Number of ports to configure on SPI * * Returns Zero on success, non-zero error code on failure (will cause * SPI initialization to abort) */ int cvmx_spi_calendar_setup_cb(int interface, cvmx_spi_mode_t mode, int num_ports) { int port; int index; if (mode & CVMX_SPI_MODE_RX_HALFPLEX) { union cvmx_srxx_com_ctl srxx_com_ctl; union cvmx_srxx_spi4_stat srxx_spi4_stat; /* SRX0 number of Ports */ srxx_com_ctl.u64 = 0; srxx_com_ctl.s.prts = num_ports - 1; srxx_com_ctl.s.st_en = 0; srxx_com_ctl.s.inf_en = 0; cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64); /* SRX0 Calendar Table. This round robbins through all ports */ port = 0; index = 0; while (port < num_ports) { union cvmx_srxx_spi4_calx srxx_spi4_calx; srxx_spi4_calx.u64 = 0; srxx_spi4_calx.s.prt0 = port++; srxx_spi4_calx.s.prt1 = port++; srxx_spi4_calx.s.prt2 = port++; srxx_spi4_calx.s.prt3 = port++; srxx_spi4_calx.s.oddpar = ~(cvmx_dpop(srxx_spi4_calx.u64) & 1); cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), srxx_spi4_calx.u64); index++; } srxx_spi4_stat.u64 = 0; srxx_spi4_stat.s.len = num_ports; srxx_spi4_stat.s.m = 1; cvmx_write_csr(CVMX_SRXX_SPI4_STAT(interface), srxx_spi4_stat.u64); } if (mode & CVMX_SPI_MODE_TX_HALFPLEX) { union cvmx_stxx_arb_ctl stxx_arb_ctl; union cvmx_gmxx_tx_spi_max gmxx_tx_spi_max; union cvmx_gmxx_tx_spi_thresh gmxx_tx_spi_thresh; union cvmx_gmxx_tx_spi_ctl gmxx_tx_spi_ctl; union cvmx_stxx_spi4_stat stxx_spi4_stat; union cvmx_stxx_spi4_dat stxx_spi4_dat; /* STX0 Config */ stxx_arb_ctl.u64 = 0; stxx_arb_ctl.s.igntpa = 0; stxx_arb_ctl.s.mintrn = 0; cvmx_write_csr(CVMX_STXX_ARB_CTL(interface), stxx_arb_ctl.u64); gmxx_tx_spi_max.u64 = 0; gmxx_tx_spi_max.s.max1 = 8; gmxx_tx_spi_max.s.max2 = 4; gmxx_tx_spi_max.s.slice = 0; cvmx_write_csr(CVMX_GMXX_TX_SPI_MAX(interface), gmxx_tx_spi_max.u64); gmxx_tx_spi_thresh.u64 = 0; gmxx_tx_spi_thresh.s.thresh = 4; cvmx_write_csr(CVMX_GMXX_TX_SPI_THRESH(interface), gmxx_tx_spi_thresh.u64); gmxx_tx_spi_ctl.u64 = 0; gmxx_tx_spi_ctl.s.tpa_clr = 0; gmxx_tx_spi_ctl.s.cont_pkt = 0; cvmx_write_csr(CVMX_GMXX_TX_SPI_CTL(interface), gmxx_tx_spi_ctl.u64); /* STX0 Training Control */ stxx_spi4_dat.u64 = 0; /*Minimum needed by dynamic alignment */ stxx_spi4_dat.s.alpha = 32; stxx_spi4_dat.s.max_t = 0xFFFF; /*Minimum interval is 0x20 */ cvmx_write_csr(CVMX_STXX_SPI4_DAT(interface), stxx_spi4_dat.u64); /* STX0 Calendar Table. This round robbins through all ports */ port = 0; index = 0; while (port < num_ports) { union cvmx_stxx_spi4_calx stxx_spi4_calx; stxx_spi4_calx.u64 = 0; stxx_spi4_calx.s.prt0 = port++; stxx_spi4_calx.s.prt1 = port++; stxx_spi4_calx.s.prt2 = port++; stxx_spi4_calx.s.prt3 = port++; stxx_spi4_calx.s.oddpar = ~(cvmx_dpop(stxx_spi4_calx.u64) & 1); cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), stxx_spi4_calx.u64); index++; } stxx_spi4_stat.u64 = 0; stxx_spi4_stat.s.len = num_ports; stxx_spi4_stat.s.m = 1; cvmx_write_csr(CVMX_STXX_SPI4_STAT(interface), stxx_spi4_stat.u64); } return 0; }
int cvmx_spi_calendar_setup_cb(int interface, cvmx_spi_mode_t mode, int num_ports) { int port; int index; if (mode & CVMX_SPI_MODE_RX_HALFPLEX) { union cvmx_srxx_com_ctl srxx_com_ctl; union cvmx_srxx_spi4_stat srxx_spi4_stat; srxx_com_ctl.u64 = 0; srxx_com_ctl.s.prts = num_ports - 1; srxx_com_ctl.s.st_en = 0; srxx_com_ctl.s.inf_en = 0; cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64); port = 0; index = 0; while (port < num_ports) { union cvmx_srxx_spi4_calx srxx_spi4_calx; srxx_spi4_calx.u64 = 0; srxx_spi4_calx.s.prt0 = port++; srxx_spi4_calx.s.prt1 = port++; srxx_spi4_calx.s.prt2 = port++; srxx_spi4_calx.s.prt3 = port++; srxx_spi4_calx.s.oddpar = ~(cvmx_dpop(srxx_spi4_calx.u64) & 1); cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), srxx_spi4_calx.u64); index++; } srxx_spi4_stat.u64 = 0; srxx_spi4_stat.s.len = num_ports; srxx_spi4_stat.s.m = 1; cvmx_write_csr(CVMX_SRXX_SPI4_STAT(interface), srxx_spi4_stat.u64); } if (mode & CVMX_SPI_MODE_TX_HALFPLEX) { union cvmx_stxx_arb_ctl stxx_arb_ctl; union cvmx_gmxx_tx_spi_max gmxx_tx_spi_max; union cvmx_gmxx_tx_spi_thresh gmxx_tx_spi_thresh; union cvmx_gmxx_tx_spi_ctl gmxx_tx_spi_ctl; union cvmx_stxx_spi4_stat stxx_spi4_stat; union cvmx_stxx_spi4_dat stxx_spi4_dat; stxx_arb_ctl.u64 = 0; stxx_arb_ctl.s.igntpa = 0; stxx_arb_ctl.s.mintrn = 0; cvmx_write_csr(CVMX_STXX_ARB_CTL(interface), stxx_arb_ctl.u64); gmxx_tx_spi_max.u64 = 0; gmxx_tx_spi_max.s.max1 = 8; gmxx_tx_spi_max.s.max2 = 4; gmxx_tx_spi_max.s.slice = 0; cvmx_write_csr(CVMX_GMXX_TX_SPI_MAX(interface), gmxx_tx_spi_max.u64); gmxx_tx_spi_thresh.u64 = 0; gmxx_tx_spi_thresh.s.thresh = 4; cvmx_write_csr(CVMX_GMXX_TX_SPI_THRESH(interface), gmxx_tx_spi_thresh.u64); gmxx_tx_spi_ctl.u64 = 0; gmxx_tx_spi_ctl.s.tpa_clr = 0; gmxx_tx_spi_ctl.s.cont_pkt = 0; cvmx_write_csr(CVMX_GMXX_TX_SPI_CTL(interface), gmxx_tx_spi_ctl.u64); stxx_spi4_dat.u64 = 0; stxx_spi4_dat.s.alpha = 32; stxx_spi4_dat.s.max_t = 0xFFFF; cvmx_write_csr(CVMX_STXX_SPI4_DAT(interface), stxx_spi4_dat.u64); port = 0; index = 0; while (port < num_ports) { union cvmx_stxx_spi4_calx stxx_spi4_calx; stxx_spi4_calx.u64 = 0; stxx_spi4_calx.s.prt0 = port++; stxx_spi4_calx.s.prt1 = port++; stxx_spi4_calx.s.prt2 = port++; stxx_spi4_calx.s.prt3 = port++; stxx_spi4_calx.s.oddpar = ~(cvmx_dpop(stxx_spi4_calx.u64) & 1); cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), stxx_spi4_calx.u64); index++; } stxx_spi4_stat.u64 = 0; stxx_spi4_stat.s.len = num_ports; stxx_spi4_stat.s.m = 1; cvmx_write_csr(CVMX_STXX_SPI4_STAT(interface), stxx_spi4_stat.u64); } return 0; }