/* generic kernel variant of si_attach() */ si_t * si_kattach(osl_t *osh) { static bool ksii_attached = FALSE; if (!ksii_attached) { void *regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, SI_BUS, NULL, osh != SI_OSH ? &ksii.vars : NULL, osh != SI_OSH ? &ksii.varsz : NULL) == NULL) { if (NULL != ksii.common_info) MFREE(osh, ksii.common_info, sizeof(si_common_info_t)); SI_ERROR(("si_kattach: si_doattach failed\n")); REG_UNMAP(regs); return NULL; } REG_UNMAP(regs); /* save ticks normalized to ms for si_watchdog_ms() */ if (PMUCTL_ENAB(&ksii.pub)) { /* based on 32KHz ILP clock */ wd_msticks = 32; } else { wd_msticks = ALP_CLOCK / 1000; } ksii_attached = TRUE; SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n", ksii.pub.ccrev, wd_msticks)); } return &ksii.pub; }
/* 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); } }
/* query alp/xtal clock frequency */ u32 si_pmu_alp_clock(struct si_pub *sih) { u32 clock = ALP_CLOCK; /* bail out with default */ if (!PMUCTL_ENAB(sih)) return clock; switch (sih->chip) { case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: case BCM4313_CHIP_ID: /* always 20Mhz */ clock = 20000 * 1000; break; default: break; } return clock; }
u32 si_pmu_ilp_clock(struct si_pub *sih) { static u32 ilpcycles_per_sec; if (!PMUCTL_ENAB(sih)) return ILP_CLOCK; if (ilpcycles_per_sec == 0) { u32 start, end, delta; u32 origidx = ai_coreidx(sih); chipcregs_t *cc = ai_setcoreidx(sih, SI_CC_IDX); start = R_REG(&cc->pmutimer); mdelay(ILP_CALC_DUR); end = R_REG(&cc->pmutimer); delta = end - start; ilpcycles_per_sec = delta * (1000 / ILP_CALC_DUR); ai_setcoreidx(sih, origidx); } return ilpcycles_per_sec; }