/* restore coreidx and restore interrupt */ void si_restore_core(si_t *sih, uint coreid, uint intr_val) { si_info_t *sii; sii = SI_INFO(sih); si_setcoreidx(sih, coreid); INTR_RESTORE(sii, intr_val); }
/* trigger watchdog reset after ms milliseconds */ void si_watchdog_ms(si_t *sih, uint32 ms) { si_info_t *sii; sii = SI_INFO(sih); si_watchdog(sih, wd_msticks * ms); }
/* return list of found cores */ uint si_corelist(si_t *sih, uint coreid[]) { si_info_t *sii; sii = SI_INFO(sih); bcopy((uchar*)sii->common_info->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); return (sii->numcores); }
/* return current register mapping */ void * si_coreregs(si_t *sih) { si_info_t *sii; sii = SI_INFO(sih); ASSERT(GOODREGS(sii->curmap)); return (sii->curmap); }
uint sb_coreid(si_t *sih) { si_info_t *sii; sbconfig_t *sb; sii = SI_INFO(sih); sb = REGS2SB(sii->curmap); return (R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT; }
/* 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 si_setosh(si_t *sih, osl_t *osh) { si_info_t *sii; sii = SI_INFO(sih); if (sii->osh != NULL) { SI_ERROR(("osh is already set....\n")); ASSERT(!sii->osh); } sii->osh = osh; }
uint sb_corerev(si_t *sih) { si_info_t *sii; sbconfig_t *sb; uint sbidh; sii = SI_INFO(sih); sb = REGS2SB(sii->curmap); sbidh = R_SBREG(sii, &sb->sbidhigh); return SBCOREREV(sbidh); }
/* 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)); }
bool sb_iscoreup(si_t *sih) { si_info_t *sii; sbconfig_t *sb; sii = SI_INFO(sih); sb = REGS2SB(sii->curmap); return (R_SBREG(sii, &sb->sbtmstatelow) & (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) == (SICF_CLOCK_EN << SBTML_SICF_SHIFT); }
/* 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)); }
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))); }
/* Turn off interrupt as required by sb_setcore, before switch core */ void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) { void *cc; si_info_t *sii; sii = SI_INFO(sih); INTR_OFF(sii, *intr_val); *origidx = sii->curidx; cc = si_setcore(sih, coreid, 0); ASSERT(cc != NULL); return cc; }
/* initialize the sdio core */ void si_sdio_init(si_t *sih) { si_info_t *sii = SI_INFO(sih); if (((sih->buscoretype == PCMCIA_CORE_ID) && (sih->buscorerev >= 8)) || (sih->buscoretype == SDIOD_CORE_ID)) { uint idx; #ifdef HTC_KlocWork sdpcmd_regs_t *sdpregs=NULL; #else sdpcmd_regs_t *sdpregs; #endif /* get the current core index */ idx = sii->curidx; ASSERT(idx == si_findcoreidx(sih, D11_CORE_ID, 0)); /* switch to sdio core */ if (!(sdpregs = (sdpcmd_regs_t *)si_setcore(sih, PCMCIA_CORE_ID, 0))) sdpregs = (sdpcmd_regs_t *)si_setcore(sih, SDIOD_CORE_ID, 0); ASSERT(sdpregs); SI_MSG(("si_sdio_init: For PCMCIA/SDIO Corerev %d, enable ints from core %d " "through SD core %d (%p)\n", sih->buscorerev, idx, sii->curidx, sdpregs)); #ifdef HTC_KlocWork if (sdpregs != NULL) { /* enable backplane error and core interrupts */ W_REG(sii->osh, &sdpregs->hostintmask, I_SBINT); W_REG(sii->osh, &sdpregs->sbintmask, (I_SB_SERR | I_SB_RESPERR | (1 << idx))); } else SI_ERROR(("[HTCKW] si_sdio_init: sdpregs is NULL\n")); #else /* enable backplane error and core interrupts */ W_REG(sii->osh, &sdpregs->hostintmask, I_SBINT); W_REG(sii->osh, &sdpregs->sbintmask, (I_SB_SERR | I_SB_RESPERR | (1 << idx))); #endif /* switch back to previous core */ si_setcoreidx(sih, idx); } /* enable interrupts */ bcmsdh_intr_enable(sii->sdh); }
/* set the core to socram run bist and return bist status back */ int si_bist_socram(si_t *sih, uint32 *biststatus) { si_info_t *sii; uint origidx; uint intr_val = 0; sbsocramregs_t *regs; int error = 0; uint status = 0; SI_ERROR(("doing the bist on SOCRAM\n")); sii = SI_INFO(sih); /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); /* Switch to SOCRAM core */ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) goto done; si_core_reset(sih, SICF_BIST_EN, SICF_BIST_EN); /* Wait for bist done */ SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); status = si_core_sflags(sih, 0, 0); if (status & SISF_BIST_DONE) { if (status & SISF_BIST_ERROR) { *biststatus = R_REG(sii->osh, ®s->biststat); /* hnd_bist gives errors for ROM bist test, so ignore it */ *biststatus &= 0xFFFF; if (!*biststatus) error = 0; else error = 1; } } si_core_reset(sih, 0, 0); /* Return to previous state and core */ si_setcoreidx(sih, origidx); done: INTR_RESTORE(sii, intr_val); return error; }
/* register driver interrupt disabling and restoring callback functions */ void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, void *intrsenabled_fn, void *intr_arg) { si_info_t *sii; sii = SI_INFO(sih); sii->intr_arg = intr_arg; sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn; sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn; sii->intrsenabled_fn = (si_intrsenabled_t)intrsenabled_fn; /* save current core id. when this function called, the current core * must be the core which provides driver functions(il, et, wl, etc.) */ sii->dev_coreid = sii->common_info->coreid[sii->curidx]; }
uint si_intflag(si_t *sih) { si_info_t *sii = SI_INFO(sih); if (CHIPTYPE(sih->socitype) == SOCI_SB) { sbconfig_t *ccsbr = (sbconfig_t *)((uintptr)((ulong) (sii->common_info->coresba[SI_CC_IDX]) + SBCONFIGOFF)); return R_REG(sii->osh, &ccsbr->sbflagst); } else if (CHIPTYPE(sih->socitype) == SOCI_AI) return R_REG(sii->osh, ((uint32 *)(uintptr) (sii->common_info->oob_router + OOB_STATUSA))); else { ASSERT(0); return 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; }
/* Release access to the RoboSwitch */ void robo_detach(void *rinfo) { robo_info_t *robo = (robo_info_t *)rinfo; si_info_t *sii; sii = SI_INFO((si_t*)robo->sbh); if (robo->regs) { REG_UNMAP(robo->regs); robo->regs = NULL; } COMPILER_REFERENCE(sii); /* Free private state */ MFREE(sii->osh, robo, sizeof(robo_info_t)); }
/* 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)); }
static void _switch_release_grant(void *rinfo) { uint32 regval; robo_info_t *robo = (robo_info_t *)rinfo; si_info_t *sii; osl_t *osh; nssrabregs_t *regs; /* pointer to chip registers */ sii = SI_INFO((si_t*)robo->sbh); osh = sii->osh; regs = robo->regs; COMPILER_REFERENCE(osh); regval = R_REG(osh, ®s->chipcommonb_srab_sw_if); regval &= ~CHIPCOMMONB_SRAB_SW_IF_RCAREQ_MASK; W_REG(osh, ®s->chipcommonb_srab_sw_if, regval); }
static uint64 _switch_reg_read(void *rinfo, uint8 page, uint8 offset) { uint64 value = ~(uint64)0; uint32 regval; uint32 timeout = ROBO_POLL_TIMEOUT; robo_info_t *robo = (robo_info_t *)rinfo; si_info_t *sii; osl_t *osh; nssrabregs_t *regs; /* pointer to chip registers */ sii = SI_INFO((si_t*)robo->sbh); osh = sii->osh; regs = robo->regs; COMPILER_REFERENCE(osh); /* Assemble read command */ _switch_request_grant(rinfo); regval = ((page << CHIPCOMMONB_SRAB_CMDSTAT_SRA_PAGE_SHIFT) | (offset << CHIPCOMMONB_SRAB_CMDSTAT_SRA_OFFSET_SHIFT) | CHIPCOMMONB_SRAB_CMDSTAT_SRA_GORDYN_MASK); W_REG(osh, ®s->chipcommonb_srab_cmdstat, regval); /* Wait for command complete */ while (R_REG(osh, ®s->chipcommonb_srab_cmdstat) & CHIPCOMMONB_SRAB_CMDSTAT_SRA_GORDYN_MASK) { if (!--timeout) { SRAB_ERR(("robo_read: timeout")); _switch_interface_reset(rinfo); break; } } if (timeout) { /* Didn't time out, read and return the value */ value = (((uint64)R_REG(osh, ®s->chipcommonb_srab_rdh)) << 32) | R_REG(osh, ®s->chipcommonb_srab_rdl); } _switch_release_grant(rinfo); return value; }
/* return index of coreid or BADIDX if not found */ uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit) { si_info_t *sii; uint found; uint i; sii = SI_INFO(sih); found = 0; for (i = 0; i < sii->numcores; i++) if (sii->common_info->coreid[i] == coreid) { if (found == coreunit) return (i); found++; } return (BADIDX); }
/* Get access to the RoboSwitch */ void * robo_attach(void *sih) { robo_info_t *robo; si_info_t *sii; nssrabregs_t *regs; /* pointer to chip registers */ struct si_pub *sii_pub = NULL; uint32 base_addr; sii = SI_INFO((si_t*)sih); /* Allocate private state */ if (!(robo = MALLOC(sii->osh, sizeof(robo_info_t)))) { SRAB_ERR(("robo_attach: out of memory")); return NULL; } else { robo_sbh = (void *)robo; } bzero((char *) robo, sizeof(robo_info_t)); robo->sbh = sih; sii_pub = &sii->pub; if (sii_pub->chip == BCM53020_CHIP_ID) { base_addr = NSP_CCB_SRAB_BASE; } else { base_addr = CCB_SRAB_BASE; } if ((regs = (void*)REG_MAP(base_addr, CORE_SIZE)) == NULL) { SRAB_ERR(("robo_attach: can't get base address")); return NULL; } /* printk("%d: robo_attach: regs=0x%x\n",__LINE__,(uint32)regs);*/ robo->regs = regs; #ifdef _KERNEL_ /* Initialize lock */ spin_lock_init(&robo->lock); #endif return robo; }
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 si_gpio_handler_process(si_t *sih) { si_info_t *sii; gpioh_item_t *h; uint32 status; uint32 level = si_gpioin(sih); uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0); sii = SI_INFO(sih); for (h = sii->gpioh_head; h != NULL; h = h->next) { if (h->handler) { status = (h->level ? level : edge); if (status & h->event) h->handler(status, h->arg); } } si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */ }
static void _switch_reg_write(void *rinfo, uint8 page, uint8 offset, uint64 value) { uint32 regval; uint32 timeout = ROBO_POLL_TIMEOUT; robo_info_t *robo = (robo_info_t *)rinfo; si_info_t *sii; osl_t *osh; nssrabregs_t *regs; /* pointer to chip registers */ sii = SI_INFO((si_t*)robo->sbh); osh = sii->osh; regs = robo->regs; COMPILER_REFERENCE(osh); _switch_request_grant(rinfo); /* Load the value to write */ W_REG(osh, ®s->chipcommonb_srab_wdh, (uint32)(value >> 32)); W_REG(osh, ®s->chipcommonb_srab_wdl, (uint32)(value)); /* Issue the write command */ regval = ((page << CHIPCOMMONB_SRAB_CMDSTAT_SRA_PAGE_SHIFT) | (offset << CHIPCOMMONB_SRAB_CMDSTAT_SRA_OFFSET_SHIFT) | CHIPCOMMONB_SRAB_CMDSTAT_SRA_GORDYN_MASK | CHIPCOMMONB_SRAB_CMDSTAT_SRA_WRITE_MASK); W_REG(osh, ®s->chipcommonb_srab_cmdstat, regval); /* Wait for command complete */ while (R_REG(osh, ®s->chipcommonb_srab_cmdstat) & CHIPCOMMONB_SRAB_CMDSTAT_SRA_GORDYN_MASK) { if (!--timeout) { SRAB_ERR(("robo_write: timeout")); _switch_interface_reset(rinfo); break; } } _switch_release_grant(rinfo); }
/* Return the RAM size of the SOCRAM core */ uint32 si_socram_size(si_t *sih) { si_info_t *sii; uint origidx; uint intr_val = 0; sbsocramregs_t *regs; bool wasup; uint corerev; uint32 coreinfo; uint memsize = 0; sii = SI_INFO(sih); /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); /* Switch to SOCRAM core */ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) goto done; /* Get info for determining size */ if (!(wasup = si_iscoreup(sih))) si_core_reset(sih, 0, 0); corerev = si_corerev(sih); coreinfo = R_REG(sii->osh, ®s->coreinfo); /* Calculate size from coreinfo based on rev */ if (corerev == 0) memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); else if (corerev < 3) { memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; } else {
/* return the core-type instantiation # of the current core */ uint si_coreunit(si_t *sih) { si_info_t *sii; uint idx; uint coreid; uint coreunit; uint i; sii = SI_INFO(sih); coreunit = 0; idx = sii->curidx; ASSERT(GOODREGS(sii->curmap)); coreid = si_coreid(sih); /* count the cores of our type */ for (i = 0; i < idx; i++) if (sii->common_info->coreid[i] == coreid) coreunit++; return (coreunit); }