static int pciegen1_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; if (!PCIE_GEN1(pi->sih)) ASSERT(0); /* enable mdio access to SERDES */ W_REG(pi->osh, (&pcieregs->u.pcie1.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->u.pcie1.mdiodata, mdiodata); PR28829_DELAY(); /* retry till the transaction is complete */ while (i < pcie_serdes_spinwait) { if (R_REG(pi->osh, &(pcieregs->u.pcie1.mdiocontrol)) & MDIOCTL_ACCESS_DONE) { if (!write) { PR28829_DELAY(); *val = (R_REG(pi->osh, &(pcieregs->u.pcie1.mdiodata)) & MDIODATA_MASK); } /* Disable mdio access to SERDES */ W_REG(pi->osh, (&pcieregs->u.pcie1.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->u.pcie1.mdiocontrol), 0); return 1; }
static bool pcie_mdiosetblock(pcicore_info_t *pi, uint blk) { sbpcieregs_t *pcieregs = pi->regs.pcieregs; uint mdiodata, i = 0; uint pcie_serdes_spinwait = 200; mdiodata = MDIODATA_START | MDIODATA_WRITE | (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | \ (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) | MDIODATA_TA | (blk << 4); 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) { break; } OSL_DELAY(1000); i++; } if (i >= pcie_serdes_spinwait) { PCI_ERROR(("pcie_mdiosetblock: timed out\n")); return FALSE; } return TRUE; }
static bool pcie2_mdiosetblock(pcicore_info_t *pi, uint blk) { sbpcieregs_t *pcieregs = pi->regs.pcieregs; uint mdiodata, mdioctrl, i = 0; uint pcie_serdes_spinwait = 200; mdioctrl = MDIOCTL2_DIVISOR_VAL | (0x1F << MDIOCTL2_REGADDR_SHF); W_REG(pi->osh, &pcieregs->u.pcie2.mdiocontrol, mdioctrl); mdiodata = (blk << MDIODATA2_DEVADDR_SHF) | MDIODATA2_DONE; W_REG(pi->osh, &pcieregs->u.pcie2.mdiowrdata, mdiodata); PR28829_DELAY(); /* retry till the transaction is complete */ while (i < pcie_serdes_spinwait) { if (!(R_REG(pi->osh, &(pcieregs->u.pcie2.mdiowrdata)) & MDIODATA2_DONE)) { break; } OSL_DELAY(1000); i++; } if (i >= pcie_serdes_spinwait) { PCI_ERROR(("pcie_mdiosetblock: timed out\n")); return FALSE; } return TRUE; }