/** * @INTERNAL * Initialize a host mode PCIe link. This function takes a PCIe * port from reset to a link up state. Software can then begin * configuring the rest of the link. * * @param pcie_port PCIe port to initialize * * @return Zero on success */ static int __cvmx_pcie_rc_initialize_link(int pcie_port) { uint64_t start_cycle; cvmx_pescx_ctl_status_t pescx_ctl_status; cvmx_pciercx_cfg452_t pciercx_cfg452; cvmx_pciercx_cfg032_t pciercx_cfg032; cvmx_pciercx_cfg448_t pciercx_cfg448; /* Set the lane width */ pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port)); pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); if (pescx_ctl_status.s.qlm_cfg == 0) { /* We're in 8 lane (56XX) or 4 lane (54XX) mode */ pciercx_cfg452.s.lme = 0xf; } else { /* We're in 4 lane (56XX) or 2 lane (52XX) mode */ pciercx_cfg452.s.lme = 0x7; } cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32); /* CN52XX pass 1.x has an errata where length mismatches on UR responses can cause bus errors on 64bit memory reads. Turning off length error checking fixes this */ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { cvmx_pciercx_cfg455_t pciercx_cfg455; pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port)); pciercx_cfg455.s.m_cpl_len_err = 1; cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32); } /* Lane swap needs to be manually enabled for CN52XX */ if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1)) { pescx_ctl_status.s.lane_swp = 1; cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port),pescx_ctl_status.u64); } /* Bring up the link */ pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); pescx_ctl_status.s.lnk_enb = 1; cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64); /* CN52XX pass 1.0: Due to a bug in 2nd order CDR, it needs to be disabled */ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0)) __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0); /* Wait for the link to come up */ start_cycle = cvmx_get_cycle(); do { if (cvmx_get_cycle() - start_cycle > 2*cvmx_sysinfo_get()->cpu_clock_hz) { cvmx_dprintf("PCIe: Port %d link timeout\n", pcie_port); return -1; } cvmx_wait(10000); pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); } while (pciercx_cfg032.s.dlla == 0); /* Update the Replay Time Limit. Empirically, some PCIe devices take a little longer to respond than expected under load. As a workaround for this we configure the Replay Time Limit to the value expected for a 512 byte MPS instead of our actual 256 byte MPS. The numbers below are directly from the PCIe spec table 3-4 */ pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); switch (pciercx_cfg032.s.nlw) { case 1: /* 1 lane */ pciercx_cfg448.s.rtl = 1677; break; case 2: /* 2 lanes */ pciercx_cfg448.s.rtl = 867; break; case 4: /* 4 lanes */ pciercx_cfg448.s.rtl = 462; break; case 8: /* 8 lanes */ pciercx_cfg448.s.rtl = 258; break; } cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); return 0; }
/** * @INTERNAL * Initialize the RC config space CSRs * * @param pcie_port PCIe port to initialize */ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) { /* Max Payload Size (PCIE*_CFG030[MPS]) */ /* Max Read Request Size (PCIE*_CFG030[MRRS]) */ /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */ /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */ { cvmx_pciercx_cfg030_t pciercx_cfg030; pciercx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port)); pciercx_cfg030.s.mps = 0; /* Max payload size = 128 bytes for best Octeon DMA performance */ pciercx_cfg030.s.mrrs = 0; /* Max read request size = 128 bytes for best Octeon DMA performance */ pciercx_cfg030.s.ro_en = 1; /* Enable relaxed order processing. This will allow devices to affect read response ordering */ pciercx_cfg030.s.ns_en = 1; /* Enable no snoop processing. Not used by Octeon */ pciercx_cfg030.s.ce_en = 1; /* Correctable error reporting enable. */ pciercx_cfg030.s.nfe_en = 1; /* Non-fatal error reporting enable. */ pciercx_cfg030.s.fe_en = 1; /* Fatal error reporting enable. */ pciercx_cfg030.s.ur_en = 1; /* Unsupported request reporting enable. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), pciercx_cfg030.u32); } /* Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match PCIE*_CFG030[MPS] */ /* Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not exceed PCIE*_CFG030[MRRS] */ { cvmx_npei_ctl_status2_t npei_ctl_status2; npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2); npei_ctl_status2.s.mps = 0; /* Max payload size = 128 bytes for best Octeon DMA performance */ npei_ctl_status2.s.mrrs = 0; /* Max read request size = 128 bytes for best Octeon DMA performance */ cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); } /* ECRC Generation (PCIE*_CFG070[GE,CE]) */ { cvmx_pciercx_cfg070_t pciercx_cfg070; pciercx_cfg070.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port)); pciercx_cfg070.s.ge = 1; /* ECRC generation enable. */ pciercx_cfg070.s.ce = 1; /* ECRC check enable. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), pciercx_cfg070.u32); } /* Access Enables (PCIE*_CFG001[MSAE,ME]) */ /* ME and MSAE should always be set. */ /* Interrupt Disable (PCIE*_CFG001[I_DIS]) */ /* System Error Message Enable (PCIE*_CFG001[SEE]) */ { cvmx_pciercx_cfg001_t pciercx_cfg001; pciercx_cfg001.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port)); pciercx_cfg001.s.msae = 1; /* Memory space enable. */ pciercx_cfg001.s.me = 1; /* Bus master enable. */ pciercx_cfg001.s.i_dis = 1; /* INTx assertion disable. */ pciercx_cfg001.s.see = 1; /* SERR# enable */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), pciercx_cfg001.u32); } /* Advanced Error Recovery Message Enables */ /* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG066(pcie_port), 0); /* Use CVMX_PCIERCX_CFG067 hardware default */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0); /* Active State Power Management (PCIE*_CFG032[ASLPC]) */ { cvmx_pciercx_cfg032_t pciercx_cfg032; pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), pciercx_cfg032.u32); } /* Entrance Latencies (PCIE*_CFG451[L0EL,L1EL]) */ // FIXME: Anything needed here? /* Link Width Mode (PCIERCn_CFG452[LME]) - Set during cvmx_pcie_rc_initialize_link() */ /* Primary Bus Number (PCIERCn_CFG006[PBNUM]) */ { /* We set the primary bus number to 1 so IDT bridges are happy. They don't like zero */ cvmx_pciercx_cfg006_t pciercx_cfg006; pciercx_cfg006.u32 = 0; pciercx_cfg006.s.pbnum = 1; pciercx_cfg006.s.sbnum = 1; pciercx_cfg006.s.subbnum = 1; cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), pciercx_cfg006.u32); } /* Memory-mapped I/O BAR (PCIERCn_CFG008) */ /* Most applications should disable the memory-mapped I/O BAR by */ /* setting PCIERCn_CFG008[ML_ADDR] < PCIERCn_CFG008[MB_ADDR] */ { cvmx_pciercx_cfg008_t pciercx_cfg008; pciercx_cfg008.u32 = 0; pciercx_cfg008.s.mb_addr = 0x100; pciercx_cfg008.s.ml_addr = 0; cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), pciercx_cfg008.u32); } /* Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011) */ /* Most applications should disable the prefetchable BAR by setting */ /* PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] < */ /* PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE] */ { cvmx_pciercx_cfg009_t pciercx_cfg009; cvmx_pciercx_cfg010_t pciercx_cfg010; cvmx_pciercx_cfg011_t pciercx_cfg011; pciercx_cfg009.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port)); pciercx_cfg010.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port)); pciercx_cfg011.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port)); pciercx_cfg009.s.lmem_base = 0x100; pciercx_cfg009.s.lmem_limit = 0; pciercx_cfg010.s.umem_base = 0x100; pciercx_cfg011.s.umem_limit = 0; cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), pciercx_cfg009.u32); cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), pciercx_cfg010.u32); cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), pciercx_cfg011.u32); } /* System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE]) */ /* PME Interrupt Enables (PCIERCn_CFG035[PMEIE]) */ { cvmx_pciercx_cfg035_t pciercx_cfg035; pciercx_cfg035.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port)); pciercx_cfg035.s.secee = 1; /* System error on correctable error enable. */ pciercx_cfg035.s.sefee = 1; /* System error on fatal error enable. */ pciercx_cfg035.s.senfee = 1; /* System error on non-fatal error enable. */ pciercx_cfg035.s.pmeie = 1; /* PME interrupt enable. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), pciercx_cfg035.u32); } /* Advanced Error Recovery Interrupt Enables */ /* (PCIERCn_CFG075[CERE,NFERE,FERE]) */ { cvmx_pciercx_cfg075_t pciercx_cfg075; pciercx_cfg075.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port)); pciercx_cfg075.s.cere = 1; /* Correctable error reporting enable. */ pciercx_cfg075.s.nfere = 1; /* Non-fatal error reporting enable. */ pciercx_cfg075.s.fere = 1; /* Fatal error reporting enable. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), pciercx_cfg075.u32); } /* HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], */ /* PCIERCn_CFG034[DLLS_EN,CCINT_EN]) */ { cvmx_pciercx_cfg034_t pciercx_cfg034; pciercx_cfg034.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port)); pciercx_cfg034.s.hpint_en = 1; /* Hot-plug interrupt enable. */ pciercx_cfg034.s.dlls_en = 1; /* Data Link Layer state changed enable */ pciercx_cfg034.s.ccint_en = 1; /* Command completed interrupt enable. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), pciercx_cfg034.u32); } }
/** * Get the speed (Gbaud) of the QLM in Mhz. * * @param qlm QLM to examine * * @return Speed in Mhz */ int cvmx_qlm_get_gbaud_mhz(int qlm) { if (OCTEON_IS_MODEL(OCTEON_CN63XX)) { if (qlm == 2) { cvmx_gmxx_inf_mode_t inf_mode; inf_mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(0)); switch (inf_mode.s.speed) { case 0: return 5000; /* 5 Gbaud */ case 1: return 2500; /* 2.5 Gbaud */ case 2: return 2500; /* 2.5 Gbaud */ case 3: return 1250; /* 1.25 Gbaud */ case 4: return 1250; /* 1.25 Gbaud */ case 5: return 6250; /* 6.25 Gbaud */ case 6: return 5000; /* 5 Gbaud */ case 7: return 2500; /* 2.5 Gbaud */ case 8: return 3125; /* 3.125 Gbaud */ case 9: return 2500; /* 2.5 Gbaud */ case 10: return 1250; /* 1.25 Gbaud */ case 11: return 5000; /* 5 Gbaud */ case 12: return 6250; /* 6.25 Gbaud */ case 13: return 3750; /* 3.75 Gbaud */ case 14: return 3125; /* 3.125 Gbaud */ default: return 0; /* Disabled */ } } else { cvmx_sriox_status_reg_t status_reg; status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(qlm)); if (status_reg.s.srio) { cvmx_sriomaintx_port_0_ctl2_t sriomaintx_port_0_ctl2; sriomaintx_port_0_ctl2.u32 = cvmx_read_csr(CVMX_SRIOMAINTX_PORT_0_CTL2(qlm)); switch (sriomaintx_port_0_ctl2.s.sel_baud) { case 1: return 1250; /* 1.25 Gbaud */ case 2: return 2500; /* 2.5 Gbaud */ case 3: return 3125; /* 3.125 Gbaud */ case 4: return 5000; /* 5 Gbaud */ case 5: return 6250; /* 6.250 Gbaud */ default: return 0; /* Disabled */ } } else { cvmx_pciercx_cfg032_t pciercx_cfg032; pciercx_cfg032.u32 = cvmx_read_csr(CVMX_PCIERCX_CFG032(qlm)); switch (pciercx_cfg032.s.ls) { case 1: return 2500; case 2: return 5000; case 4: return 8000; default: { cvmx_mio_rst_boot_t mio_rst_boot; mio_rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT); if ((qlm == 0) && mio_rst_boot.s.qlm0_spd == 0xf) return 0; if ((qlm == 1) && mio_rst_boot.s.qlm1_spd == 0xf) return 0; return 5000; /* Best guess I can make */ } } } } } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF71XX)) { cvmx_mio_qlmx_cfg_t qlm_cfg; qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm)); switch (qlm_cfg.s.qlm_spd) { case 0: return 5000; /* 5 Gbaud */ case 1: return 2500; /* 2.5 Gbaud */ case 2: return 2500; /* 2.5 Gbaud */ case 3: return 1250; /* 1.25 Gbaud */ case 4: return 1250; /* 1.25 Gbaud */ case 5: return 6250; /* 6.25 Gbaud */ case 6: return 5000; /* 5 Gbaud */ case 7: return 2500; /* 2.5 Gbaud */ case 8: return 3125; /* 3.125 Gbaud */ case 9: return 2500; /* 2.5 Gbaud */ case 10: return 1250; /* 1.25 Gbaud */ case 11: return 5000; /* 5 Gbaud */ case 12: return 6250; /* 6.25 Gbaud */ case 13: return 3750; /* 3.75 Gbaud */ case 14: return 3125; /* 3.125 Gbaud */ default: return 0; /* Disabled */ } } return 0; }
/** * Initialize a host mode PCIe link. This function takes a PCIe * port from reset to a link up state. Software can then begin * configuring the rest of the link. * * @pcie_port: PCIe port to initialize * * Returns Zero on success */ static int __cvmx_pcie_rc_initialize_link(int pcie_port) { uint64_t start_cycle; union cvmx_pescx_ctl_status pescx_ctl_status; union cvmx_pciercx_cfg452 pciercx_cfg452; union cvmx_pciercx_cfg032 pciercx_cfg032; union cvmx_pciercx_cfg448 pciercx_cfg448; /* Set the lane width */ pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port)); pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); if (pescx_ctl_status.s.qlm_cfg == 0) { /* We're in 8 lane (56XX) or 4 lane (54XX) mode */ pciercx_cfg452.s.lme = 0xf; } else { /* We're in 4 lane (56XX) or 2 lane (52XX) mode */ pciercx_cfg452.s.lme = 0x7; } cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32); /* * CN52XX pass 1.x has an errata where length mismatches on UR * responses can cause bus errors on 64bit memory * reads. Turning off length error checking fixes this. */ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { union cvmx_pciercx_cfg455 pciercx_cfg455; pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port)); pciercx_cfg455.s.m_cpl_len_err = 1; cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32); } /* Lane swap needs to be manually enabled for CN52XX */ if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1)) { pescx_ctl_status.s.lane_swp = 1; cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64); } /* Bring up the link */ pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); pescx_ctl_status.s.lnk_enb = 1; cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64); /* * CN52XX pass 1.0: Due to a bug in 2nd order CDR, it needs to * be disabled. */ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0)) __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0); /* Wait for the link to come up */ cvmx_dprintf("PCIe: Waiting for port %d link\n", pcie_port); start_cycle = cvmx_get_cycle(); do { if (cvmx_get_cycle() - start_cycle > 2 * cvmx_sysinfo_get()->cpu_clock_hz) { cvmx_dprintf("PCIe: Port %d link timeout\n", pcie_port); return -1; } cvmx_wait(10000); pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); } while (pciercx_cfg032.s.dlla == 0); /* Display the link status */ cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, pciercx_cfg032.s.nlw); pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); switch (pciercx_cfg032.s.nlw) { case 1: /* 1 lane */ pciercx_cfg448.s.rtl = 1677; break; case 2: /* 2 lanes */ pciercx_cfg448.s.rtl = 867; break; case 4: /* 4 lanes */ pciercx_cfg448.s.rtl = 462; break; case 8: /* 8 lanes */ pciercx_cfg448.s.rtl = 258; break; } cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); return 0; }
/** * Get the speed (Gbaud) of the QLM in Mhz. * * @param qlm QLM to examine * * @return Speed in Mhz */ int cvmx_qlm_get_gbaud_mhz(int qlm) { if (OCTEON_IS_MODEL(OCTEON_CN63XX)) { if (qlm == 2) { cvmx_gmxx_inf_mode_t inf_mode; inf_mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(0)); switch (inf_mode.s.speed) { case 0: return 5000; /* 5 Gbaud */ case 1: return 2500; /* 2.5 Gbaud */ case 2: return 2500; /* 2.5 Gbaud */ case 3: return 1250; /* 1.25 Gbaud */ case 4: return 1250; /* 1.25 Gbaud */ case 5: return 6250; /* 6.25 Gbaud */ case 6: return 5000; /* 5 Gbaud */ case 7: return 2500; /* 2.5 Gbaud */ case 8: return 3125; /* 3.125 Gbaud */ case 9: return 2500; /* 2.5 Gbaud */ case 10: return 1250; /* 1.25 Gbaud */ case 11: return 5000; /* 5 Gbaud */ case 12: return 6250; /* 6.25 Gbaud */ case 13: return 3750; /* 3.75 Gbaud */ case 14: return 3125; /* 3.125 Gbaud */ default: return 0; /* Disabled */ } } else { cvmx_sriox_status_reg_t status_reg; status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(qlm)); if (status_reg.s.srio) { cvmx_sriomaintx_port_0_ctl2_t sriomaintx_port_0_ctl2; sriomaintx_port_0_ctl2.u32 = cvmx_read_csr(CVMX_SRIOMAINTX_PORT_0_CTL2(qlm)); switch (sriomaintx_port_0_ctl2.s.sel_baud) { case 1: return 1250; /* 1.25 Gbaud */ case 2: return 2500; /* 2.5 Gbaud */ case 3: return 3125; /* 3.125 Gbaud */ case 4: return 5000; /* 5 Gbaud */ case 5: return 6250; /* 6.250 Gbaud */ default: return 0; /* Disabled */ } } else { cvmx_pciercx_cfg032_t pciercx_cfg032; pciercx_cfg032.u32 = cvmx_read_csr(CVMX_PCIERCX_CFG032(qlm)); switch (pciercx_cfg032.s.ls) { case 1: return 2500; case 2: return 5000; case 4: return 8000; default: { cvmx_mio_rst_boot_t mio_rst_boot; mio_rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT); if ((qlm == 0) && mio_rst_boot.s.qlm0_spd == 0xf) return 0; if ((qlm == 1) && mio_rst_boot.s.qlm1_spd == 0xf) return 0; return 5000; /* Best guess I can make */ } } } } } else if (OCTEON_IS_OCTEON2()) { cvmx_mio_qlmx_cfg_t qlm_cfg; qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm)); switch (qlm_cfg.s.qlm_spd) { case 0: return 5000; /* 5 Gbaud */ case 1: return 2500; /* 2.5 Gbaud */ case 2: return 2500; /* 2.5 Gbaud */ case 3: return 1250; /* 1.25 Gbaud */ case 4: return 1250; /* 1.25 Gbaud */ case 5: return 6250; /* 6.25 Gbaud */ case 6: return 5000; /* 5 Gbaud */ case 7: return 2500; /* 2.5 Gbaud */ case 8: return 3125; /* 3.125 Gbaud */ case 9: return 2500; /* 2.5 Gbaud */ case 10: return 1250; /* 1.25 Gbaud */ case 11: return 5000; /* 5 Gbaud */ case 12: return 6250; /* 6.25 Gbaud */ case 13: return 3750; /* 3.75 Gbaud */ case 14: return 3125; /* 3.125 Gbaud */ default: return 0; /* Disabled */ } } else if (OCTEON_IS_MODEL(OCTEON_CN70XX)) { cvmx_gserx_dlmx_mpll_multiplier_t mpll_multiplier; uint64_t meas_refclock; uint64_t freq; /* Measure the reference clock */ meas_refclock = cvmx_qlm_measure_clock(qlm); /* Multiply to get the final frequency */ mpll_multiplier.u64 = cvmx_read_csr(CVMX_GSERX_DLMX_MPLL_MULTIPLIER(qlm, 0)); freq = meas_refclock * mpll_multiplier.s.mpll_multiplier; freq = (freq + 500000) / 1000000; return freq; } return 0; }