static void pcie_war_pmebits(pcicore_info_t *pi) { sbpcieregs_t *pcieregs = pi->regs.pcieregs; uint16 val16, *reg16; if (pi->sih->buscorerev != 18 && pi->sih->buscorerev != 19) return; reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV8]; val16 = R_REG(pi->osh, reg16); if (val16 != pi->pmebits) { PCI_ERROR(("pcie_war_pmebits: pmebits mismatch 0x%x (was 0x%x)\n", val16, pi->pmebits)); pi->pmebits = 0x1f30; W_REG(pi->osh, reg16, pi->pmebits); val16 = R_REG(pi->osh, reg16); PCI_ERROR(("pcie_war_pmebits: update pmebits to 0x%x\n", val16)); } }
static int pcie_mdioop(pcicore_info_t *pi, uint physmedia, uint regaddr, bool write, uint *val) { sbpcieregs_t *pcieregs = pi->regs.pcieregs; uint mdiodata; uint i = 0; uint pcie_serdes_spinwait = 10; /* enable mdio access to SERDES */ W_REG(pi->osh, (&pcieregs->mdiocontrol), MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); if (pi->sih->buscorerev >= 10) { /* new serdes is slower in rw, using two layers of reg address mapping */ if (!pcie_mdiosetblock(pi, physmedia)) return 1; mdiodata = (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | \ (regaddr << MDIODATA_REGADDR_SHF); pcie_serdes_spinwait *= 20; } else { mdiodata = (physmedia << MDIODATA_DEVADDR_SHF_OLD) | \ (regaddr << MDIODATA_REGADDR_SHF_OLD); } if (!write) mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA); else mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | *val); W_REG(pi->osh, &pcieregs->mdiodata, mdiodata); PR28829_DELAY(); /* retry till the transaction is complete */ while (i < pcie_serdes_spinwait) { if (R_REG(pi->osh, &(pcieregs->mdiocontrol)) & MDIOCTL_ACCESS_DONE) { if (!write) { PR28829_DELAY(); *val = (R_REG(pi->osh, &(pcieregs->mdiodata)) & MDIODATA_MASK); } /* Disable mdio access to SERDES */ W_REG(pi->osh, (&pcieregs->mdiocontrol), 0); return 0; } OSL_DELAY(1000); i++; } PCI_ERROR(("pcie_mdioop: timed out op: %d\n", write)); /* Disable mdio access to SERDES */ W_REG(pi->osh, (&pcieregs->mdiocontrol), 0); return 1; }
/* WAR for PR5730: If the latency value is zero set it to 0x20, which exceeds the PCI burst * size; this is only seen on certain Ricoh controllers, and only on Vista, and should * only be applied to 4321 single/dualband cardbus cards for now */ static void pcicore_fixlatencytimer(pcicore_info_t* pch, uint8 timer_val) { pcicore_info_t *pi = (pcicore_info_t *)pch; osl_t *osh = pi->osh; uint8 lattim = read_pci_cfg_byte(PCI_CFG_LATTIM); if (!lattim) { PCI_ERROR(("%s: Modifying PCI_CFG_LATTIM from 0x%x to 0x%x\n", __FUNCTION__, lattim, timer_val)); write_pci_cfg_byte(PCI_CFG_LATTIM, timer_val); } }
uint32 pcicore_pciereg(void *pch, uint32 offset, uint32 mask, uint32 val, uint type) { uint32 reg_val = 0; pcicore_info_t *pi = (pcicore_info_t *)pch; sbpcieregs_t *pcieregs = pi->regs.pcieregs; if (mask) { PCI_ERROR(("PCIEREG: 0x%x writeval 0x%x\n", offset, val)); pcie_writereg(pi->sih, pcieregs, type, offset, val); } /* Should not read register 0x154 */ if (PCIE_GEN1(pi->sih) && pi->sih->buscorerev <= 5 && offset == PCIE_DLLP_PCIE11 && type == PCIE_PCIEREGS) return reg_val; reg_val = pcie_readreg(pi->sih, pcieregs, type, offset); PCI_ERROR(("PCIEREG: 0x%x readval is 0x%x\n", offset, reg_val)); return reg_val; }
uint32 pcicore_pciereg(void *pch, uint32 offset, uint32 mask, uint32 val, uint type) { uint32 reg_val = 0; pcicore_info_t *pi = (pcicore_info_t *)pch; sbpcieregs_t *pcieregs = pi->regs.pcieregs; osl_t *osh = pi->osh; if (mask) { PCI_ERROR(("PCIEREG: 0x%x writeval 0x%x\n", offset, val)); pcie_writereg(osh, pcieregs, type, offset, val); } /* Should not read register 0x154 */ /* PR42815: PCIE: Accesses to dlinkPCIE1_1 register (0x154 address) broken */ if (pi->sih->buscorerev <= 5 && offset == PCIE_DLLP_PCIE11 && type == PCIE_PCIEREGS) return reg_val; reg_val = pcie_readreg(osh, pcieregs, type, offset); PCI_ERROR(("PCIEREG: 0x%x readval is 0x%x\n", offset, reg_val)); return reg_val; }
/** * Initialize the PCI core. It's caller's responsibility to make sure that this is done * only once */ void * pcicore_init(si_t *sih, osl_t *osh, void *regs) { pcicore_info_t *pi; uint8 cap_ptr; ASSERT(sih->bustype == PCI_BUS); /* alloc pcicore_info_t */ if ((pi = MALLOC(osh, sizeof(pcicore_info_t))) == NULL) { PCI_ERROR(("pci_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); return (NULL); } bzero(pi, sizeof(pcicore_info_t)); pi->sih = sih; pi->osh = osh; if (sih->buscoretype == PCIE2_CORE_ID) { pi->regs.pcieregs = (sbpcieregs_t*)regs; cap_ptr = pcicore_find_pci_capability(pi->osh, PCI_CAP_PCIECAP_ID, NULL, NULL); ASSERT(cap_ptr); pi->pciecap_devctrl_offset = cap_ptr + PCIE_CAP_DEVCTRL_OFFSET; pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET; pi->pciecap_devctrl2_offset = cap_ptr + PCIE_CAP_DEVCTRL2_OFFSET; pi->pciecap_ltr0_reg_offset = cap_ptr + PCIE_CAP_LTR0_REG_OFFSET; pi->pciecap_ltr1_reg_offset = cap_ptr + PCIE_CAP_LTR1_REG_OFFSET; pi->pciecap_ltr2_reg_offset = cap_ptr + PCIE_CAP_LTR2_REG_OFFSET; } else if (sih->buscoretype == PCIE_CORE_ID) { pi->regs.pcieregs = (sbpcieregs_t*)regs; cap_ptr = pcicore_find_pci_capability(pi->osh, PCI_CAP_PCIECAP_ID, NULL, NULL); ASSERT(cap_ptr); pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET; pi->pciecap_devctrl_offset = cap_ptr + PCIE_CAP_DEVCTRL_OFFSET; pi->pciecap_devctrl2_offset = cap_ptr + PCIE_CAP_DEVCTRL2_OFFSET; pi->pciecap_ltr0_reg_offset = cap_ptr + PCIE_CAP_LTR0_REG_OFFSET; pi->pciecap_ltr1_reg_offset = cap_ptr + PCIE_CAP_LTR1_REG_OFFSET; pi->pciecap_ltr2_reg_offset = cap_ptr + PCIE_CAP_LTR2_REG_OFFSET; pi->pcie_power_save = TRUE; /* Enable pcie_power_save by default */ } else pi->regs.pciregs = (sbpciregs_t*)regs; return pi; }
/* Disable PME generation, clear the PME status bit if set */ void pcicore_pmeclr(void *pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 w; if (!pcicore_pmecap(pi)) return; pcie_war_pmebits(pi); w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32)); PCI_ERROR(("pcicore_pci_pmeclr PMECSR : 0x%x\n", w)); /* PMESTAT is cleared by writing 1 to it */ w &= ~(PME_CSR_PME_EN); OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32), w); }
void pcicore_pmestatclr(void *pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 w; if (!pcicore_pmecap(pi)) return; pcie_war_pmebits(pi); w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32)); PCI_ERROR(("pcicore_pmestatclr PMECSR : 0x%x\n", w)); /* Writing a 1 to PMESTAT will clear it */ if ((w & PME_CSR_PME_STAT) == PME_CSR_PME_STAT) { OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32), w); } }
/* Disable PME generation, clear the PME status bit if set and * return TRUE if PME status set */ bool pcicore_pmeclr(void *pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 w; bool ret = FALSE; if (!pcicore_pmecap(pi)) return ret; w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32)); PCI_ERROR(("pcicore_pci_pmeclr PMECSR : 0x%x\n", w)); ret = (w & PME_CSR_PME_STAT) == PME_CSR_PME_STAT; /* PMESTAT is cleared by writing 1 to it */ w &= ~(PME_CSR_PME_EN); OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32), w); return ret; }