/* initialize PMU resources */ void si_pmu_res_init(struct si_pub *sih) { chipcregs_t *cc; uint origidx; u32 min_mask = 0, max_mask = 0; /* Remember original core before switch to chipc */ origidx = ai_coreidx(sih); cc = ai_setcoreidx(sih, SI_CC_IDX); /* Determine min/max rsrc masks */ si_pmu_res_masks(sih, &min_mask, &max_mask); /* It is required to program max_mask first and then min_mask */ /* Program max resource mask */ if (max_mask) W_REG(&cc->max_res_mask, max_mask); /* Program min resource mask */ if (min_mask) W_REG(&cc->min_res_mask, min_mask); /* Add some delay; allow resources to come up and settle. */ mdelay(2); /* Return to original core */ ai_setcoreidx(sih, origidx); }
void si_pmu_sprom_enable(struct si_pub *sih, bool enable) { chipcregs_t *cc; uint origidx; /* Remember original core before switch to chipc */ origidx = ai_coreidx(sih); cc = ai_setcoreidx(sih, SI_CC_IDX); /* Return to original core */ ai_setcoreidx(sih, origidx); }
u32 si_pmu_measure_alpclk(struct si_pub *sih) { chipcregs_t *cc; uint origidx; u32 alp_khz; if (sih->pmurev < 10) return 0; /* Remember original core before switch to chipc */ origidx = ai_coreidx(sih); cc = ai_setcoreidx(sih, SI_CC_IDX); if (R_REG(&cc->pmustatus) & PST_EXTLPOAVAIL) { u32 ilp_ctr, alp_hz; /* * Enable the reg to measure the freq, * in case it was disabled before */ W_REG(&cc->pmu_xtalfreq, 1U << PMU_XTALFREQ_REG_MEASURE_SHIFT); /* Delay for well over 4 ILP clocks */ udelay(1000); /* Read the latched number of ALP ticks per 4 ILP ticks */ ilp_ctr = R_REG(&cc->pmu_xtalfreq) & PMU_XTALFREQ_REG_ILPCTR_MASK; /* * Turn off the PMU_XTALFREQ_REG_MEASURE_SHIFT * bit to save power */ W_REG(&cc->pmu_xtalfreq, 0); /* Calculate ALP frequency */ alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4; /* * Round to nearest 100KHz, and at * the same time convert to KHz */ alp_khz = (alp_hz + 50000) / 100000 * 100; } else alp_khz = 0; /* Return to original core */ ai_setcoreidx(sih, origidx); return alp_khz; }
/* initialize PMU */ void si_pmu_init(struct si_pub *sih) { chipcregs_t *cc; uint origidx; /* Remember original core before switch to chipc */ origidx = ai_coreidx(sih); cc = ai_setcoreidx(sih, SI_CC_IDX); if (sih->pmurev == 1) AND_REG(&cc->pmucontrol, ~PCTL_NOILP_ON_WAIT); else if (sih->pmurev >= 2) OR_REG(&cc->pmucontrol, PCTL_NOILP_ON_WAIT); /* Return to original core */ ai_setcoreidx(sih, origidx); }
void * si_setcoreidx(si_t *sih, uint coreidx) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_setcoreidx(sih, coreidx); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_setcoreidx(sih, coreidx); else { ASSERT(0); return NULL; } }
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; }
/* initialize PLL */ void si_pmu_pll_init(struct si_pub *sih, uint xtalfreq) { chipcregs_t *cc; uint origidx; /* Remember original core before switch to chipc */ origidx = ai_coreidx(sih); cc = ai_setcoreidx(sih, SI_CC_IDX); switch (sih->chip) { case BCM4313_CHIP_ID: case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: /* ??? */ break; default: break; } /* Return to original core */ ai_setcoreidx(sih, origidx); }
/* initialize PMU chip controls and other chip level stuff */ void si_pmu_chip_init(struct si_pub *sih) { uint origidx; /* Gate off SPROM clock and chip select signals */ si_pmu_sprom_enable(sih, false); /* Remember original core */ origidx = ai_coreidx(sih); /* Return to original core */ ai_setcoreidx(sih, origidx); }
/* * This function changes logical "focus" to the indicated core; * must be called with interrupts off. * Moreover, callers should keep interrupts off during switching out of and back to d11 core */ void * si_setcore(si_t *sih, uint coreid, uint coreunit) { uint idx; idx = si_findcoreidx(sih, coreid, coreunit); if (!GOODIDX(idx)) return (NULL); if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_setcoreidx(sih, idx); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_setcoreidx(sih, idx); else { ASSERT(0); return NULL; } }