/* set chip watchdog reset timer to fire in 'ticks' */ void si_watchdog(si_t *sih, uint ticks) { if (PMUCTL_ENAB(sih)) { if (ticks == 1) ticks = 2; si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks); } else { /* instant NMI */ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); } }
/* set chip watchdog reset timer to fire in 'ticks' */ void si_watchdog(si_t *sih, uint ticks) { if (PMUCTL_ENAB(sih)) { if ((sih->chip == BCM4319_CHIP_ID) && (sih->chiprev == 0) && (ticks != 0)) { si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2); si_setcore(sih, USB20D_CORE_ID, 0); si_core_disable(sih, 1); si_setcore(sih, CC_CORE_ID, 0); } if (ticks == 1) ticks = 2; si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks); } else { /* instant NMI */ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); } }
/* centralized clkreq control policy */ static void pcie_clkreq_upd(pcicore_info_t *pi, uint state) { si_t *sih = pi->sih; ASSERT(PCIE(sih)); switch (state) { case SI_DOATTACH: /* XXX PR42780 WAR: Disable clk req when coming up */ if (PCIE_ASPM(sih)) pcie_clkreq((void *)pi, 1, 0); break; case SI_PCIDOWN: if (sih->buscorerev == 6) { /* turn on serdes PLL down */ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_addr), ~0, 0); si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_data), ~0x40, 0); } else if (pi->pcie_pr42767) { /* When the driver going down, enable clkreq if PR42767 has been applied. * Also, adjust the state as system could hibernate, so Serdes PLL WAR is * a must before doing this */ pcie_clkreq((void *)pi, 1, 1); } break; case SI_PCIUP: if (sih->buscorerev == 6) { /* turn off serdes PLL down */ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_addr), ~0, 0); si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_data), ~0x40, 0x40); } else if (PCIE_ASPM(sih)) { /* disable clkreq */ pcie_clkreq((void *)pi, 1, 0); } break; default: ASSERT(0); break; } }
/* assign the gpio to an led */ uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val) { si_info_t *sii; sii = SI_INFO(sih); if (sih->ccrev < 16) return -1; /* gpio led powersave reg */ return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); }
void pcie_disable_TL_clk_gating(void *pch) { /* disable TL clk gating is located in bit 4 of PCIEControl (Offset 0x000) */ pcicore_info_t *pi = (pcicore_info_t *)pch; si_t *sih = pi->sih; if (!PCIE_GEN1(sih) && !PCIE_GEN2(sih)) return; si_corereg(sih, sih->buscoreidx, 0, 0x10, 0x10); }
/* return the current gpioin register value */ uint32 si_gpioin(si_t *sih) { si_info_t *sii; uint regoff; sii = SI_INFO(sih); regoff = 0; regoff = OFFSETOF(chipcregs_t, gpioin); return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0)); }
uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val) { si_info_t *sii; uint offs; sii = SI_INFO(sih); if (sih->ccrev < 20) return -1; offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup)); return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); }
uint32 si_gpio_int_enable(si_t *sih, bool enable) { si_info_t *sii; uint offs; sii = SI_INFO(sih); if (sih->ccrev < 11) return -1; offs = OFFSETOF(chipcregs_t, intmask); return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); }
/* centralized clkreq control policy */ static void pcie_clkreq_upd(pcicore_info_t *pi, uint state) { si_t *sih = pi->sih; ASSERT(PCIE(sih)); if (!PCIE_GEN1(sih)) return; switch (state) { case SI_DOATTACH: if (PCIEGEN1_ASPM(sih)) pcie_clkreq((void *)pi, 1, 0); break; case SI_PCIDOWN: if (sih->buscorerev == 6) { /* turn on serdes PLL down */ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_addr), ~0, 0); si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_data), ~0x40, 0); } else if (pi->pcie_pr42767) { pcie_clkreq((void *)pi, 1, 1); } break; case SI_PCIUP: if (sih->buscorerev == 6) { /* turn off serdes PLL down */ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_addr), ~0, 0); si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_data), ~0x40, 0x40); } else if (PCIEGEN1_ASPM(sih)) { /* disable clkreq */ pcie_clkreq((void *)pi, 1, 0); } break; default: ASSERT(0); break; } }
/* mask&set gpio timer val */ uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval) { si_info_t *sii; sii = SI_INFO(sih); if (sih->ccrev < 16) return -1; return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval)); }
/* Needs to happen when coming out of 'standby'/'hibernate' */ static void pcie_war_noplldown(pcicore_info_t *pi) { sbpcieregs_t *pcieregs = pi->regs.pcieregs; uint16 *reg16; ASSERT(pi->sih->buscorerev == 7); /* turn off serdes PLL down */ si_corereg(pi->sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol), CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN); /* clear srom shadow backdoor */ reg16 = &pcieregs->sprom[SRSH_BD_OFFSET]; W_REG(pi->osh, reg16, 0); }
int si_bist_cc(si_t *sih, uint32 *biststatus) { si_info_t *sii; uint origidx; uint intr_val = 0; int error = 0; void *regs; int status; bool wasup; sii = SI_INFO(sih); SI_ERROR(("doing the bist on ChipC\n")); /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); /* Switch to CC core */ if (!(regs = si_setcore(sih, CC_CORE_ID, 0))) goto done; /* Get info for determining size */ if (!(wasup = si_iscoreup(sih))) si_core_reset(sih, 0, 0); status = si_corebist(sih); if (status == BCME_ERROR) { *biststatus = si_corereg(sih, si_coreidx(&sii->pub), 12, 0, 0); /* XXX: OTP gives the BIST error */ *biststatus &= ~(0x1); if (*biststatus) error = 1; } /* Return to previous state and core */ if (!wasup) si_core_disable(sih, 0); /* Return to previous state and core */ si_setcoreidx(sih, origidx); *biststatus = 0; done: INTR_RESTORE(sii, intr_val); return error; }
/* mask&set gpio interrupt mask bits */ uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority) { si_info_t *sii; uint regoff; sii = SI_INFO(sih); regoff = 0; /* gpios could be shared on router platforms */ if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { mask = priority ? (si_gpioreservation & mask) : ((si_gpioreservation | mask) & ~(si_gpioreservation)); val &= mask; } regoff = OFFSETOF(chipcregs_t, gpiointmask); return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); }
/* mask&set gpio output bits */ uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) { uint regoff; regoff = 0; /* gpios could be shared on router platforms * ignore reservation if it's high priority (e.g., test apps) */ if ((priority != GPIO_HI_PRIORITY) && (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { mask = priority ? (si_gpioreservation & mask) : ((si_gpioreservation | mask) & ~(si_gpioreservation)); val &= mask; } regoff = OFFSETOF(chipcregs_t, gpioout); return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); }
uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) { si_info_t *sii; uint offs; sii = SI_INFO(sih); if (sih->ccrev < 11) return -1; if (regtype == GPIO_REGEVT) offs = OFFSETOF(chipcregs_t, gpioevent); else if (regtype == GPIO_REGEVT_INTMSK) offs = OFFSETOF(chipcregs_t, gpioeventintmask); else if (regtype == GPIO_REGEVT_INTPOL) offs = OFFSETOF(chipcregs_t, gpioeventintpolarity); else return -1; return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); }
void pcie_watchdog_reset(osl_t *osh, si_t *sih, sbpcieregs_t *sbpcieregs) { uint32 val, i, lsc; uint16 cfg_offset[] = {PCIECFGREG_STATUS_CMD, PCIECFGREG_PM_CSR, PCIECFGREG_MSI_CAP, PCIECFGREG_MSI_ADDR_L, PCIECFGREG_MSI_ADDR_H, PCIECFGREG_MSI_DATA, PCIECFGREG_LINK_STATUS_CTRL2, PCIECFGREG_RBAR_CTRL, PCIECFGREG_PML1_SUB_CTRL1, PCIECFGREG_REG_BAR2_CONFIG, PCIECFGREG_REG_BAR3_CONFIG}; uint32 origidx = si_coreidx(sih); /* Disable/restore ASPM Control to protect the watchdog reset */ W_REG(osh, &sbpcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL); lsc = R_REG(osh, &sbpcieregs->configdata); val = lsc & (~PCIE_ASPM_ENAB); W_REG(osh, &sbpcieregs->configdata, val); si_setcore(sih, PCIE2_CORE_ID, 0); si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, 4); OSL_DELAY(100000); #ifdef BCMQT OSL_DELAY(200000); #endif /* BCMQT */ W_REG(osh, &sbpcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL); W_REG(osh, &sbpcieregs->configdata, lsc); /* Write configuration registers back to the shadow registers * cause shadow registers are cleared out after watchdog reset. */ for (i = 0; i < ARRAYSIZE(cfg_offset); i++) { W_REG(osh, &sbpcieregs->configaddr, cfg_offset[i]); val = R_REG(osh, &sbpcieregs->configdata); W_REG(osh, &sbpcieregs->configdata, val); } si_setcoreidx(sih, origidx); }
int si_bist_d11(si_t *sih, uint32 *biststatus1, uint32 *biststatus2) { si_info_t *sii; uint origidx; uint intr_val = 0; void *regs; int error = 0; bool wasup; uint32 offset = SBCONFIGOFF + SBTMSTATELOW; uint32 max_res_mask; uint32 pmu_ctrl; *biststatus1 = 0; *biststatus2 = 0; SI_ERROR(("doing the bist on D11\n")); sii = SI_INFO(sih); if (CHIPTYPE(sih->socitype) != SOCI_SB) { return 0; } /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); /* Switch to D11 core */ if (!(regs = si_setcore(sih, D11_CORE_ID, 0))) goto done; /* Get info for determining size */ /* coming out of reset device shoudl have clk enabled, bw set, etc */ if (!(wasup = si_iscoreup(sih))) si_core_reset(sih, 0x4F, 0x4F); max_res_mask = si_corereg(sih, 0, OFFSETOF(chipcregs_t, max_res_mask), 0, 0); si_corereg(sih, 0, OFFSETOF(chipcregs_t, max_res_mask), ~0, 0x3fffff); if (si_corerev(&sii->pub) == 20) { uint32 phy_reset_val; uint32 bist_test_val, bist_status; /* XXX: enable the phy PLL */ pmu_ctrl = si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, 0, 0); pmu_ctrl |= 0x000010000; si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, ~0, pmu_ctrl); SPINWAIT(((si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, 0, 0) & 0x01000000) == 0), 1000000); pmu_ctrl = si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, 0, 0); /* take the phy out of reset */ phy_reset_val = si_corereg(sih, si_coreidx(&sii->pub), offset, 0, 0); phy_reset_val &= ~(0x0008 << SBTML_SICF_SHIFT); si_corereg(sih, si_coreidx(&sii->pub), offset, ~0, phy_reset_val); phy_reset_val = si_corereg(sih, si_coreidx(&sii->pub), offset, 0, 0); /* enable bist first */ bist_test_val = si_corereg(sih, si_coreidx(&sii->pub), offset, 0, 0); bist_test_val |= (SICF_BIST_EN << 16); si_corereg(sih, si_coreidx(&sii->pub), offset, ~0, bist_test_val); SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 1000000); bist_status = si_core_sflags(sih, 0, 0); SI_ERROR(("status are 0x%08x\n", bist_status)); if (bist_status & SISF_BIST_DONE) { if (bist_status & SISF_BIST_ERROR) { error = 1; *biststatus1 = si_corereg(sih, si_coreidx(&sii->pub), 12, 0, 0); *biststatus2 = si_corereg(sih, si_coreidx(&sii->pub), 16, 0, 0); } } /* stop the phy pll */ pmu_ctrl = si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, 0, 0); pmu_ctrl &= ~0x10000; si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, ~0, pmu_ctrl); } /* remove the resource mask */ si_corereg(sih, 0, OFFSETOF(chipcregs_t, max_res_mask), ~0, max_res_mask); /* Return to previous state and core */ if (!wasup) si_core_disable(sih, 0); /* Return to previous state and core */ si_setcoreidx(sih, origidx); done: INTR_RESTORE(sii, intr_val); return error; }