union cvmx_pcie_address {
uint64_t u64; struct {
uint64_t upper:2; /* Normally 2 for XKPHYS */
uint64_t reserved_49_61:13; /* Must be zero */
uint64_t io:1; /* 1 for IO space access */
uint64_t did:5; /* PCIe DID = 3 */
uint64_t subdid:3; /* PCIe SubDID = 1 */
uint64_t reserved_36_39:4; /* Must be zero */
uint64_t es:2; /* Endian swap = 1 */
uint64_t port:2; /* PCIe port 0,1 */
uint64_t reserved_29_31:3; /* Must be zero */ /* *Selectsthetypeoftheconfigurationrequest(0=type0, *1=type1).
*/
uint64_t ty:1; /* Target bus number sent in the ID in the request. */
uint64_t bus:8; /* *TargetdevicenumbersentintheIDinthe *request.NotethatDevmustbezerofortype0 *configurationrequests.
*/
uint64_t dev:5; /* Target function number sent in the ID in the request. */
uint64_t func:3; /* *Selectsaregisterintheconfigurationspaceof *thetarget.
*/
uint64_t reg:12;
} config; struct {
uint64_t upper:2; /* Normally 2 for XKPHYS */
uint64_t reserved_49_61:13; /* Must be zero */
uint64_t io:1; /* 1 for IO space access */
uint64_t did:5; /* PCIe DID = 3 */
uint64_t subdid:3; /* PCIe SubDID = 2 */
uint64_t reserved_36_39:4; /* Must be zero */
uint64_t es:2; /* Endian swap = 1 */
uint64_t port:2; /* PCIe port 0,1 */
uint64_t address:32; /* PCIe IO address */
} io; struct {
uint64_t upper:2; /* Normally 2 for XKPHYS */
uint64_t reserved_49_61:13; /* Must be zero */
uint64_t io:1; /* 1 for IO space access */
uint64_t did:5; /* PCIe DID = 3 */
uint64_t subdid:3; /* PCIe SubDID = 3-6 */
uint64_t reserved_36_39:4; /* Must be zero */
uint64_t address:36; /* PCIe Mem address */
} mem;
};
/** *BuildaPCIeconfigspacerequestaddressforadevice * *@pcie_port:PCIeporttoaccess *@bus:Subbus *@dev:DeviceID *@fn:Devicesubfunction *@reg:Registertoaccess * *Returns64bitOcteonIOaddress
*/ staticinline uint64_t __cvmx_pcie_build_config_addr(int pcie_port, int bus, int dev, int fn, int reg)
{ union cvmx_pcie_address pcie_addr; union cvmx_pciercx_cfg006 pciercx_cfg006; union cvmx_pciercx_cfg032 pciercx_cfg032;
/** *Read8bitsfromaDevice'sconfigspace * *@pcie_port:PCIeportthedeviceison *@bus:Subbus *@dev:DeviceID *@fn:Devicesubfunction *@reg:Registertoaccess * *ReturnsResultoftheread
*/ static uint8_t cvmx_pcie_config_read8(int pcie_port, int bus, int dev, int fn, int reg)
{
uint64_t address =
__cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); if (address) return cvmx_read64_uint8(address); else return0xff;
}
/** *Read16bitsfromaDevice'sconfigspace * *@pcie_port:PCIeportthedeviceison *@bus:Subbus *@dev:DeviceID *@fn:Devicesubfunction *@reg:Registertoaccess * *ReturnsResultoftheread
*/ static uint16_t cvmx_pcie_config_read16(int pcie_port, int bus, int dev, int fn, int reg)
{
uint64_t address =
__cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); if (address) return le16_to_cpu(cvmx_read64_uint16(address)); else return0xffff;
}
/** *Read32bitsfromaDevice'sconfigspace * *@pcie_port:PCIeportthedeviceison *@bus:Subbus *@dev:DeviceID *@fn:Devicesubfunction *@reg:Registertoaccess * *ReturnsResultoftheread
*/ static uint32_t cvmx_pcie_config_read32(int pcie_port, int bus, int dev, int fn, int reg)
{
uint64_t address =
__cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); if (address) return le32_to_cpu(cvmx_read64_uint32(address)); else return0xffffffff;
}
/** *Write8bitstoaDevice'sconfigspace * *@pcie_port:PCIeportthedeviceison *@bus:Subbus *@dev:DeviceID *@fn:Devicesubfunction *@reg:Registertoaccess *@val:Valuetowrite
*/ staticvoid cvmx_pcie_config_write8(int pcie_port, int bus, int dev, int fn, int reg, uint8_t val)
{
uint64_t address =
__cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); if (address)
cvmx_write64_uint8(address, val);
}
/** *Write16bitstoaDevice'sconfigspace * *@pcie_port:PCIeportthedeviceison *@bus:Subbus *@dev:DeviceID *@fn:Devicesubfunction *@reg:Registertoaccess *@val:Valuetowrite
*/ staticvoid cvmx_pcie_config_write16(int pcie_port, int bus, int dev, int fn, int reg, uint16_t val)
{
uint64_t address =
__cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); if (address)
cvmx_write64_uint16(address, cpu_to_le16(val));
}
/** *Write32bitstoaDevice'sconfigspace * *@pcie_port:PCIeportthedeviceison *@bus:Subbus *@dev:DeviceID *@fn:Devicesubfunction *@reg:Registertoaccess *@val:Valuetowrite
*/ staticvoid cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn, int reg, uint32_t val)
{
uint64_t address =
__cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); if (address)
cvmx_write64_uint32(address, cpu_to_le32(val));
}
/** *InitializetheRCconfigspaceCSRs * *@pcie_port:PCIeporttoinitialize
*/ staticvoid __cvmx_pcie_rc_initialize_config_space(int pcie_port)
{ union cvmx_pciercx_cfg030 pciercx_cfg030; union cvmx_pciercx_cfg070 pciercx_cfg070; union cvmx_pciercx_cfg001 pciercx_cfg001; union cvmx_pciercx_cfg032 pciercx_cfg032; union cvmx_pciercx_cfg006 pciercx_cfg006; union cvmx_pciercx_cfg008 pciercx_cfg008; union cvmx_pciercx_cfg009 pciercx_cfg009; union cvmx_pciercx_cfg010 pciercx_cfg010; union cvmx_pciercx_cfg011 pciercx_cfg011; union cvmx_pciercx_cfg035 pciercx_cfg035; union cvmx_pciercx_cfg075 pciercx_cfg075; union cvmx_pciercx_cfg034 pciercx_cfg034;
/* Active State Power Management (PCIE*_CFG032[ASLPC]) */
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);
/** *InitializeahostmodePCIegen1link.ThisfunctiontakesaPCIe *portfromresettoalinkupstate.Softwarecanthenbegin *configuringtherestofthelink. * *@pcie_port:PCIeporttoinitialize * *ReturnsZeroonsuccess
*/ staticint __cvmx_pcie_rc_initialize_link_gen1(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);
/* 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);
/* *CN52XXpass1.0:Duetoabugin2ndorderCDR,itneedsto *bedisabled.
*/ 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 * octeon_get_clock_rate()) {
cvmx_dprintf("PCIe: Port %d link timeout\n", pcie_port); return -1;
}
__delay(10000);
pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
} while (pciercx_cfg032.s.dlla == 0);
/* Clear all pending errors */
cvmx_write_csr(CVMX_PEXP_NPEI_INT_SUM, cvmx_read_csr(CVMX_PEXP_NPEI_INT_SUM));
/** *InitializeaPCIegen1portforuseinhost(RC)mode.Itdoesn't *enumeratethebus. * *@pcie_port:PCIeporttoinitialize * *ReturnsZeroonsuccess
*/ staticint __cvmx_pcie_rc_initialize_gen1(int pcie_port)
{ int i; int base;
u64 addr_swizzle; union cvmx_ciu_soft_prst ciu_soft_prst; union cvmx_pescx_bist_status pescx_bist_status; union cvmx_pescx_bist_status2 pescx_bist_status2; union cvmx_npei_ctl_status npei_ctl_status; union cvmx_npei_mem_access_ctl npei_mem_access_ctl; union cvmx_npei_mem_access_subidx mem_access_subid; union cvmx_npei_dbg_data npei_dbg_data; union cvmx_pescx_ctl_status2 pescx_ctl_status2; union cvmx_pciercx_cfg032 pciercx_cfg032; union cvmx_npei_bar1_indexx bar1_index;
retry: /* *Makesurewearen'ttryingtosetupatargetmodeinterface *inhostmode.
*/
npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); if ((pcie_port == 0) && !npei_ctl_status.s.host_mode) {
cvmx_dprintf("PCIe: Port %d in endpoint mode\n", pcie_port); return -1;
}
/* *MakesureaCN52XXisn'ttryingtobringupport1whenit *isdisabled.
*/ if (OCTEON_IS_MODEL(OCTEON_CN52XX)) {
npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); if ((pcie_port == 1) && npei_dbg_data.cn52xx.qlm0_link_width) {
cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called on port1, but port1 is disabled\n"); return -1;
}
}
/* *PESCX_BIST_STATUS2[PCLK_RUN]wasmissingonpass1of *CN56XXandCN52XX,soweonlyprobeitonnewerchips
*/ if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { /* Clear PCLK_RUN so we can check if the clock is running */
pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));
pescx_ctl_status2.s.pclk_run = 1;
cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), pescx_ctl_status2.u64); /* Now that we cleared PCLK_RUN, wait for it to be set *againtellingustheclockisrunning
*/ if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CTL_STATUS2(pcie_port), union cvmx_pescx_ctl_status2, pclk_run, ==, 1, 10000)) {
cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", pcie_port); return -1;
}
}
/* *CheckandmakesurePCIecameoutofreset.Ifitdoesn't *theboardprobablyhasn'twiredtheclocksupandthe *interfaceshouldbeskipped.
*/
pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); if (pescx_ctl_status2.s.pcierst) {
cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port); return -1;
}
/* *CheckBIST2status.Ifanybitsaresetskipthis *interface.ThisisanattempttocatchPCIE-813onpass1 *parts.
*/
pescx_bist_status2.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port)); if (pescx_bist_status2.u64) {
cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this port isn't hooked up, skipping.\n",
pcie_port); return -1;
}
/* Check BIST status */
pescx_bist_status.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port)); if (pescx_bist_status.u64)
cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n",
pcie_port, CAST64(pescx_bist_status.u64));
/* Initialize the config space CSRs */
__cvmx_pcie_rc_initialize_config_space(pcie_port);
/* Bring the link up */ if (__cvmx_pcie_rc_initialize_link_gen1(pcie_port)) {
cvmx_dprintf("PCIe: Failed to initialize port %d, probably the slot is empty\n",
pcie_port); return -1;
}
/* Store merge control (NPEI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */
npei_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL);
npei_mem_access_ctl.s.max_word = 0; /* Allow 16 words to combine */
npei_mem_access_ctl.s.timer = 127; /* Wait up to 127 cycles for more data */
cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL, npei_mem_access_ctl.u64);
/* Setup Mem access SubDIDs */
mem_access_subid.u64 = 0;
mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
mem_access_subid.s.nmerge = 1; /* Due to an errata on pass 1 chips, no merging is allowed. */
mem_access_subid.s.esr = 1; /* Endian-swap for Reads. */
mem_access_subid.s.esw = 1; /* Endian-swap for Writes. */
mem_access_subid.s.nsr = 0; /* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */
mem_access_subid.s.nsw = 0; /* Enable Snoop for Writes. */
mem_access_subid.s.ror = 0; /* Disable Relaxed Ordering for Reads. */
mem_access_subid.s.row = 0; /* Disable Relaxed Ordering for Writes. */
mem_access_subid.s.ba = 0; /* PCIe Address Bits <63:34>. */
/* *Setupmemaccess12-15forport0,16-19forport1, *supplying36bitsofaddressspace.
*/ for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) {
cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64);
mem_access_subid.s.ba += 1; /* Set each SUBID to extend the addressable range */
}
/* *Disablethepeertopeerforwardingregister.Thismustbe *setupbytheOSafteritenumeratesthebusandassigns *addressestothePCIebusses.
*/ for (i = 0; i < 4; i++) {
cvmx_write_csr(CVMX_PESCX_P2P_BARX_START(i, pcie_port), -1);
cvmx_write_csr(CVMX_PESCX_P2P_BARX_END(i, pcie_port), -1);
}
/* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */
cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0);
/* BAR1 follows BAR2 with a gap so it has the same address as for gen2. */
cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE);
/* Update in_fif_p_count for its offset with respect to out_p_count */
in_fif_p_count = (in_fif_p_count + in_p_offset) & 0xff;
/* Read the OUT_P_COUNT from the debug select */
cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd00f : 0xc80f);
cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT);
dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
out_p_count = (dbg_data.s.data>>1) & 0xff;
/* Check that the two counters are aligned */ if (out_p_count != in_fif_p_count) {
cvmx_dprintf("PCIe: Port %d aligning TLP counters as workaround to maintain ordering\n", pcie_port); while (in_fif_p_count != 0) {
cvmx_write64_uint32(write_address, 0);
__delay(10000);
in_fif_p_count = (in_fif_p_count + 1) & 0xff;
} /* *TheEBH5200boardswappedthePCIereset *linesontheboard.Thismeanswemust *bringbothlinksdownandup,whichwill *causethePCIe0toneedalignment *again.Lotsofmessageswillbedisplayed, *buteverythingshouldwork
*/ if ((cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) &&
(pcie_port == 1))
cvmx_pcie_rc_initialize(0); /* Rety bringing this port up */ goto retry;
}
}
/* Display the link status */
pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, pciercx_cfg032.s.nlw);
return0;
}
/** *InitializeahostmodePCIegen2link.ThisfunctiontakesaPCIe *portfromresettoalinkupstate.Softwarecanthenbegin *configuringtherestofthelink. * *@pcie_port:PCIeporttoinitialize * *ReturnZeroonsuccess.
*/ staticint __cvmx_pcie_rc_initialize_link_gen2(int pcie_port)
{
uint64_t start_cycle; union cvmx_pemx_ctl_status pem_ctl_status; union cvmx_pciercx_cfg032 pciercx_cfg032; union cvmx_pciercx_cfg448 pciercx_cfg448;
/* Bring up the link */
pem_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port));
pem_ctl_status.s.lnk_enb = 1;
cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pem_ctl_status.u64);
/* Wait for the link to come up */
start_cycle = cvmx_get_cycle(); do { if (cvmx_get_cycle() - start_cycle > octeon_get_clock_rate()) return -1;
__delay(10000);
pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
} while ((pciercx_cfg032.s.dlla == 0) || (pciercx_cfg032.s.lt == 1));
/** *InitializeaPCIegen2portforuseinhost(RC)mode.Itdoesn'tenumerate *thebus. * *@pcie_port:PCIeporttoinitialize * *ReturnsZeroonsuccess.
*/ staticint __cvmx_pcie_rc_initialize_gen2(int pcie_port)
{ int i; union cvmx_ciu_soft_prst ciu_soft_prst; union cvmx_mio_rst_ctlx mio_rst_ctl; union cvmx_pemx_bar_ctl pemx_bar_ctl; union cvmx_pemx_ctl_status pemx_ctl_status; union cvmx_pemx_bist_status pemx_bist_status; union cvmx_pemx_bist_status2 pemx_bist_status2; union cvmx_pciercx_cfg032 pciercx_cfg032; union cvmx_pciercx_cfg515 pciercx_cfg515; union cvmx_sli_ctl_portx sli_ctl_portx; union cvmx_sli_mem_access_ctl sli_mem_access_ctl; union cvmx_sli_mem_access_subidx mem_access_subid; union cvmx_sriox_status_reg sriox_status_reg; union cvmx_pemx_bar1_indexx bar1_index;
if (octeon_has_feature(OCTEON_FEATURE_SRIO)) { /* Make sure this interface isn't SRIO */ if (OCTEON_IS_MODEL(OCTEON_CN66XX)) { /* *TheCN66XXrequiresreadingthe *MIO_QLMX_CFGregistertofigureoutthe *porttype.
*/ union cvmx_mio_qlmx_cfg qlmx_cfg;
qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(pcie_port));
if (qlmx_cfg.s.qlm_spd == 15) {
pr_notice("PCIe: Port %d is disabled, skipping.\n", pcie_port); return -1;
}
switch (qlmx_cfg.s.qlm_spd) { case0x1: /* SRIO 1x4 short */ case0x3: /* SRIO 1x4 long */ case0x4: /* SRIO 2x2 short */ case0x6: /* SRIO 2x2 long */
pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port); return -1; case0x9: /* SGMII */
pr_notice("PCIe: Port %d is SGMII, skipping.\n", pcie_port); return -1; case0xb: /* XAUI */
pr_notice("PCIe: Port %d is XAUI, skipping.\n", pcie_port); return -1; case0x0: /* PCIE gen2 */ case0x8: /* PCIE gen2 (alias) */ case0x2: /* PCIE gen1 */ case0xa: /* PCIE gen1 (alias) */ break; default:
pr_notice("PCIe: Port %d is unknown, skipping.\n", pcie_port); return -1;
}
} else {
sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(pcie_port)); if (sriox_status_reg.s.srio) {
pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port); return -1;
}
}
}
#if0 /* This code is so that the PCIe analyzer is able to see 63XX traffic */
pr_notice("PCIE : init for pcie analyzer.\n");
cvmx_helper_qlm_jtag_init();
cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
cvmx_helper_qlm_jtag_update(pcie_port); #endif
/* Make sure we aren't trying to setup a target mode interface in host mode */
mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port)); if (!mio_rst_ctl.s.host_mode) {
pr_notice("PCIe: Port %d in endpoint mode.\n", pcie_port); return -1;
}
/* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */ if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) { if (pcie_port) { union cvmx_ciu_qlm ciu_qlm;
ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1);
ciu_qlm.s.txbypass = 1;
ciu_qlm.s.txdeemph = 5;
ciu_qlm.s.txmargin = 0x17;
cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64);
} else { union cvmx_ciu_qlm ciu_qlm;
ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0);
ciu_qlm.s.txbypass = 1;
ciu_qlm.s.txdeemph = 5;
ciu_qlm.s.txmargin = 0x17;
cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64);
}
} /* Bring the PCIe out of reset */ if (pcie_port)
ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); else
ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); /* *AfterachipresetthePCIewillalsobeinreset.Ifit *isn't,mostlikelysomeoneistryingtoinititagain *withoutaproperPCIereset
*/ if (ciu_soft_prst.s.soft_prst == 0) { /* Reset the port */
ciu_soft_prst.s.soft_prst = 1; if (pcie_port)
cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); else
cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); /* Wait until pcie resets the ports. */
udelay(2000);
} if (pcie_port) {
ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
ciu_soft_prst.s.soft_prst = 0;
cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
} else {
ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
ciu_soft_prst.s.soft_prst = 0;
cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
}
/* Wait for PCIe reset to complete */
udelay(1000);
/* *CheckandmakesurePCIecameoutofreset.Ifitdoesn't *theboardprobablyhasn'twiredtheclocksupandthe *interfaceshouldbeskipped.
*/ if (CVMX_WAIT_FOR_FIELD64(CVMX_MIO_RST_CTLX(pcie_port), union cvmx_mio_rst_ctlx, rst_done, ==, 1, 10000)) {
pr_notice("PCIe: Port %d stuck in reset, skipping.\n", pcie_port); return -1;
}
/* Check BIST status */
pemx_bist_status.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS(pcie_port)); if (pemx_bist_status.u64)
pr_notice("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status.u64));
pemx_bist_status2.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS2(pcie_port)); /* Errata PCIE-14766 may cause the lower 6 bits to be randomly set on CN63XXp1 */ if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
pemx_bist_status2.u64 &= ~0x3full; if (pemx_bist_status2.u64)
pr_notice("PCIe: BIST2 FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status2.u64));
/* Initialize the config space CSRs */
__cvmx_pcie_rc_initialize_config_space(pcie_port);
/* Bring the link up */ if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) { /* *Somegen1devicesdon'thandlethegen2training *correctly.Disablegen2andtryagainwithonly *gen1
*/ union cvmx_pciercx_cfg031 pciercx_cfg031;
pciercx_cfg031.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG031(pcie_port));
pciercx_cfg031.s.mls = 1;
cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), pciercx_cfg031.u32); if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) {
pr_notice("PCIe: Link timeout on port %d, probably the slot is empty\n", pcie_port); return -1;
}
}
/* Store merge control (SLI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */
sli_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL);
sli_mem_access_ctl.s.max_word = 0; /* Allow 16 words to combine */
sli_mem_access_ctl.s.timer = 127; /* Wait up to 127 cycles for more data */
cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL, sli_mem_access_ctl.u64);
/* Setup Mem access SubDIDs */
mem_access_subid.u64 = 0;
mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
mem_access_subid.s.nmerge = 0; /* Allow merging as it works on CN6XXX. */
mem_access_subid.s.esr = 1; /* Endian-swap for Reads. */
mem_access_subid.s.esw = 1; /* Endian-swap for Writes. */
mem_access_subid.s.wtype = 0; /* "No snoop" and "Relaxed ordering" are not set */
mem_access_subid.s.rtype = 0; /* "No snoop" and "Relaxed ordering" are not set */ /* PCIe Address Bits <63:34>. */ if (OCTEON_IS_MODEL(OCTEON_CN68XX))
mem_access_subid.cn68xx.ba = 0; else
mem_access_subid.s.ba = 0;
/* *Setupmemaccess12-15forport0,16-19forport1, *supplying36bitsofaddressspace.
*/ for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) {
cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64); /* Set each SUBID to extend the addressable range */
__cvmx_increment_ba(&mem_access_subid);
}
/* *Disablethepeertopeerforwardingregister.Thismustbe *setupbytheOSafteritenumeratesthebusandassigns *addressestothePCIebusses.
*/ for (i = 0; i < 4; i++) {
cvmx_write_csr(CVMX_PEMX_P2P_BARX_START(i, pcie_port), -1);
cvmx_write_csr(CVMX_PEMX_P2P_BARX_END(i, pcie_port), -1);
}
/* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */
cvmx_write_csr(CVMX_PEMX_P2N_BAR0_START(pcie_port), 0);
/* Display the link status */
pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
pr_notice("PCIe: Port %d link active, %d lanes, speed gen%d\n", pcie_port, pciercx_cfg032.s.nlw, pciercx_cfg032.s.ls);
return0;
}
/** *InitializeaPCIeportforuseinhost(RC)mode.Itdoesn'tenumeratethebus. * *@pcie_port:PCIeporttoinitialize * *ReturnsZeroonsuccess
*/ staticint cvmx_pcie_rc_initialize(int pcie_port)
{ int result; if (octeon_has_feature(OCTEON_FEATURE_NPEI))
result = __cvmx_pcie_rc_initialize_gen1(pcie_port); else
result = __cvmx_pcie_rc_initialize_gen2(pcie_port); return result;
}
/* Above was cvmx-pcie.c, below original pcie.c */
if ((deviceid & 0xffff) == IDT_VENDOR_ID) return1; return0;
}
/** *InitializetheOcteonPCIecontrollers * *Returns
*/ staticint __init octeon_pcie_setup(void)
{ int result; int host_mode; int srio_war15205 = 0, port; union cvmx_sli_ctl_portx sli_ctl_portx; union cvmx_sriox_status_reg sriox_status_reg;
/* These chips don't have PCIe */ if (!octeon_has_feature(OCTEON_FEATURE_PCIE)) return0;
/* No PCIe simulation */ if (octeon_is_simulation()) return0;
/* Disable PCI if instructed on the command line */ if (pcie_disable) return0;
/* Point pcibios_map_irq() to the PCIe version of it */
octeon_pcibios_map_irq = octeon_pcie_pcibios_map_irq;
if (host_mode) {
pr_notice("PCIe: Initializing port 0\n"); /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) ||
OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) {
sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(0)); if (sriox_status_reg.s.srio) {
srio_war15205 += 1; /* Port is SRIO */
port = 0;
}
}
result = cvmx_pcie_rc_initialize(0); if (result == 0) {
uint32_t device0; /* Memory offsets are physical addresses */
octeon_pcie0_controller.mem_offset =
cvmx_pcie_get_mem_base_address(0); /* IO offsets are Mips virtual addresses */
octeon_pcie0_controller.io_map_base =
CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address
(0));
octeon_pcie0_controller.io_offset = 0; /* *TokeepthingssimilartoPCI,westart *deviceaddressesatthesameplaceasPCI *uisngbigbarsupport.Thisnormally *translatesto4GB-256MB,whichisthesame *asmostx86PCs.
*/
octeon_pcie0_controller.mem_resource->start =
cvmx_pcie_get_mem_base_address(0) +
(4ul << 30) - (OCTEON_PCI_BAR1_HOLE_SIZE << 20);
octeon_pcie0_controller.mem_resource->end =
cvmx_pcie_get_mem_base_address(0) +
cvmx_pcie_get_mem_size(0) - 1; /* *Portsmustbeabove16KBfortheISAbus *filteringinthePCI-XtoPCIbridge.
*/
octeon_pcie0_controller.io_resource->start = 4 << 10;
octeon_pcie0_controller.io_resource->end =
cvmx_pcie_get_io_size(0) - 1;
msleep(100); /* Some devices need extra time */
register_pci_controller(&octeon_pcie0_controller);
device0 = cvmx_pcie_config_read32(0, 0, 0, 0, 0);
enable_pcie_bus_num_war[0] =
device_needs_bus_num_war(device0);
}
} else {
pr_notice("PCIe: Port 0 in endpoint mode, skipping.\n"); /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) ||
OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) {
srio_war15205 += 1;
port = 0;
}
}
if (octeon_has_feature(OCTEON_FEATURE_NPEI)) {
host_mode = 1; /* Skip the 2nd port on CN52XX if port 0 is in 4 lane mode */ if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { union cvmx_npei_dbg_data dbg_data;
dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); if (dbg_data.cn52xx.qlm0_link_width)
host_mode = 0;
}
} else { union cvmx_mio_rst_ctlx mio_rst_ctl;
mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(1));
host_mode = mio_rst_ctl.s.host_mode;
}
if (host_mode) {
pr_notice("PCIe: Initializing port 1\n"); /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) ||
OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) {
sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(1)); if (sriox_status_reg.s.srio) {
srio_war15205 += 1; /* Port is SRIO */
port = 1;
}
}
result = cvmx_pcie_rc_initialize(1); if (result == 0) {
uint32_t device0; /* Memory offsets are physical addresses */
octeon_pcie1_controller.mem_offset =
cvmx_pcie_get_mem_base_address(1); /* *Tocalculatetheaddressforaccessingthe2ndPCIedevice, *either'io_map_base'(pci_iomap()),or'mips_io_port_base' *(ioport_map())valueisaddedto *pci_resource_start(dev,bar)).The'mips_io_port_base'isset *onlyoncebasedonfirstPCIe.Alsochanging'io_map_base' *basedonfirstslot'svaluesothatboththeroutineswill *workproperly.
*/
octeon_pcie1_controller.io_map_base =
CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(0)); /* IO offsets are Mips virtual addresses */
octeon_pcie1_controller.io_offset =
cvmx_pcie_get_io_base_address(1) -
cvmx_pcie_get_io_base_address(0); /* *TokeepthingssimilartoPCI,westartdevice *addressesatthesameplaceasPCIuisngbigbar *support.Thisnormallytranslatesto4GB-256MB, *whichisthesameasmostx86PCs.
*/
octeon_pcie1_controller.mem_resource->start =
cvmx_pcie_get_mem_base_address(1) + (4ul << 30) -
(OCTEON_PCI_BAR1_HOLE_SIZE << 20);
octeon_pcie1_controller.mem_resource->end =
cvmx_pcie_get_mem_base_address(1) +
cvmx_pcie_get_mem_size(1) - 1; /* *Portsmustbeabove16KBfortheISAbusfiltering *inthePCI-XtoPCIbridge.
*/
octeon_pcie1_controller.io_resource->start =
cvmx_pcie_get_io_base_address(1) -
cvmx_pcie_get_io_base_address(0);
octeon_pcie1_controller.io_resource->end =
octeon_pcie1_controller.io_resource->start +
cvmx_pcie_get_io_size(1) - 1;
msleep(100); /* Some devices need extra time */
register_pci_controller(&octeon_pcie1_controller);
device0 = cvmx_pcie_config_read32(1, 0, 0, 0, 0);
enable_pcie_bus_num_war[1] =
device_needs_bus_num_war(device0);
}
} else {
pr_notice("PCIe: Port 1 not in root complex mode, skipping.\n"); /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) ||
OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) {
srio_war15205 += 1;
port = 1;
}
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.51Bemerkung:
(vorverarbeitet am 2026-10-01)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.