📄 sbutils.c
字号:
if (slowclk == SCC_SS_PCI) return (max? (PCIMAXFREQ/64) : (PCIMINFREQ/64)); else return (max? (XTALMAXFREQ/32) : (XTALMINFREQ/32)); } else if (si->sb.ccrev < 10) { div = 4 * (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1); if (slowclk == SCC_SS_LPO) return (max? LPOMAXFREQ : LPOMINFREQ); else if (slowclk == SCC_SS_XTAL) return (max? (XTALMAXFREQ/div) : (XTALMINFREQ/div)); else if (slowclk == SCC_SS_PCI) return (max? (PCIMAXFREQ/div) : (PCIMINFREQ/div)); else ASSERT(0); } else { /* Chipc rev 10 is InstaClock */ div = R_REG(&cc->system_clk_ctl) >> SYCC_CD_SHIFT; div = 4 * (div + 1); return (max ? XTALMAXFREQ : (XTALMINFREQ/div)); } return (0);}static voidBCMINITFN(sb_clkctl_setdelay)(sb_info_t *si, void *chipcregs){ chipcregs_t * cc; uint slowmaxfreq, pll_delay, slowclk; uint pll_on_delay, fref_sel_delay; pll_delay = PLL_DELAY; /* If the slow clock is not sourced by the xtal then add the xtal_on_delay * since the xtal will also be powered down by dynamic clk control logic. */ slowclk = sb_slowclk_src(si); if (slowclk != SCC_SS_XTAL) pll_delay += XTAL_ON_DELAY; /* Starting with 4318 it is ILP that is used for the delays */ slowmaxfreq = sb_slowclk_freq(si, (si->sb.ccrev >= 10) ? FALSE : TRUE); pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; cc = (chipcregs_t *)chipcregs; W_REG(&cc->pll_on_delay, pll_on_delay); W_REG(&cc->fref_sel_delay, fref_sel_delay);}/* initialize power control delay registers */voidBCMINITFN(sb_clkctl_init)(sb_t *sbh){ sb_info_t *si; uint origidx; chipcregs_t *cc; si = SB_INFO(sbh); origidx = si->curidx; if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL) return; if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL)) goto done; /* set all Instaclk chip ILP to 1 MHz */ else if (si->sb.ccrev >= 10) SET_REG(&cc->system_clk_ctl, SYCC_CD_MASK, (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); sb_clkctl_setdelay(si, (void *)cc);done: sb_setcoreidx(sbh, origidx);}/* return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */uint16sb_clkctl_fast_pwrup_delay(sb_t *sbh){ sb_info_t *si; uint origidx; chipcregs_t *cc; uint slowminfreq; uint16 fpdelay; uint intr_val = 0; si = SB_INFO(sbh); fpdelay = 0; origidx = si->curidx; INTR_OFF(si, intr_val); if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL) goto done; if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL)) goto done; slowminfreq = sb_slowclk_freq(si, FALSE); fpdelay = (((R_REG(&cc->pll_on_delay) + 2) * 1000000) + (slowminfreq - 1)) / slowminfreq;done: sb_setcoreidx(sbh, origidx); INTR_RESTORE(si, intr_val); return (fpdelay);}/* turn primary xtal and/or pll off/on */intsb_clkctl_xtal(sb_t *sbh, uint what, bool on){ sb_info_t *si; uint32 in, out, outen; si = SB_INFO(sbh); switch (BUSTYPE(si->sb.bustype)) { case PCI_BUS: /* pcie core doesn't have any mapping to control the xtal pu */ if (PCIE(si)) return -1; in = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_IN, sizeof(uint32)); out = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof(uint32)); outen = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof(uint32)); /* * Avoid glitching the clock if GPRS is already using it. * We can't actually read the state of the PLLPD so we infer it * by the value of XTAL_PU which *is* readable via gpioin. */ if (on && (in & PCI_CFG_GPIO_XTAL)) return (0); if (what & XTAL) outen |= PCI_CFG_GPIO_XTAL; if (what & PLL) outen |= PCI_CFG_GPIO_PLL; if (on) { /* turn primary xtal on */ if (what & XTAL) { out |= PCI_CFG_GPIO_XTAL; if (what & PLL) out |= PCI_CFG_GPIO_PLL; OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT, sizeof(uint32), out); OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof(uint32), outen); OSL_DELAY(XTAL_ON_DELAY); } /* turn pll on */ if (what & PLL) { out &= ~PCI_CFG_GPIO_PLL; OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT, sizeof(uint32), out); OSL_DELAY(2000); } } else { if (what & XTAL) out &= ~PCI_CFG_GPIO_XTAL; if (what & PLL) out |= PCI_CFG_GPIO_PLL; OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT, sizeof(uint32), out); OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof(uint32), outen); } default: return (-1); } return (0);}/* set dynamic clk control mode (forceslow, forcefast, dynamic) *//* returns true if we are forcing fast clock */boolsb_clkctl_clk(sb_t *sbh, uint mode){ sb_info_t *si; uint origidx; chipcregs_t *cc; uint32 scc; uint intr_val = 0; si = SB_INFO(sbh); /* chipcommon cores prior to rev6 don't support dynamic clock control */ if (si->sb.ccrev < 6) return (FALSE); /* Chips with ccrev 10 are EOL and they don't have SYCC_HR which we use below */ ASSERT(si->sb.ccrev != 10); INTR_OFF(si, intr_val); origidx = si->curidx; /* "Force HT clock on" all the time, no dynamic clk ctl */ if ((si->sb.chip == BCM4311_CHIP_ID) && (si->sb.chiprev <= 1)) goto done; cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0); ASSERT(cc != NULL); if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL)) goto done; switch (mode) { case CLK_FAST: /* force fast (pll) clock */ if (si->sb.ccrev < 10) { /* don't forget to force xtal back on before we clear SCC_DYN_XTAL.. */ sb_clkctl_xtal(&si->sb, XTAL, ON); SET_REG(&cc->slow_clk_ctl, (SCC_XC | SCC_FS | SCC_IP), SCC_IP); } else OR_REG(&cc->system_clk_ctl, SYCC_HR); break; case CLK_DYNAMIC: /* enable dynamic clock control */ if (si->sb.ccrev < 10) { scc = R_REG(&cc->slow_clk_ctl); scc &= ~(SCC_FS | SCC_IP | SCC_XC); if ((scc & SCC_SS_MASK) != SCC_SS_XTAL) scc |= SCC_XC; W_REG(&cc->slow_clk_ctl, scc); /* for dynamic control, we have to release our xtal_pu "force on" */ if (scc & SCC_XC) sb_clkctl_xtal(&si->sb, XTAL, OFF); } else { /* Instaclock */ AND_REG(&cc->system_clk_ctl, ~SYCC_HR); } break; default: ASSERT(0); }done: sb_setcoreidx(sbh, origidx); INTR_RESTORE(si, intr_val); return (mode == CLK_FAST);}/* register driver interrupt disabling and restoring callback functions */voidsb_register_intr_callback(sb_t *sbh, void *intrsoff_fn, void *intrsrestore_fn, void *intrsenabled_fn, void *intr_arg){ sb_info_t *si; si = SB_INFO(sbh); si->intr_arg = intr_arg; si->intrsoff_fn = (sb_intrsoff_t)intrsoff_fn; si->intrsrestore_fn = (sb_intrsrestore_t)intrsrestore_fn; si->intrsenabled_fn = (sb_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.) */ si->dev_coreid = si->coreid[si->curidx];}voidsb_corepciid(sb_t *sbh, uint16 *pcivendor, uint16 *pcidevice, uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif){ uint vendor, core, unit; uint chip, chippkg; char varname[SB_DEVPATH_BUFSZ + 8]; uint8 class, subclass, progif; char devpath[SB_DEVPATH_BUFSZ]; vendor = sb_corevendor(sbh); core = sb_coreid(sbh); unit = sb_coreunit(sbh); chip = sb_chip(sbh); chippkg = sb_chippkg(sbh); progif = 0; /* Known vendor translations */ switch (vendor) { case SB_VEND_BCM: vendor = VENDOR_BROADCOM; break; } /* Determine class based on known core codes */ switch (core) { case SB_PCI: case SB_PCIE: class = PCI_CLASS_BRIDGE; subclass = PCI_BRIDGE_PCI; break; case SB_CC: class = PCI_CLASS_MEMORY; subclass = PCI_MEMORY_FLASH; break; case SB_D11: class = PCI_CLASS_NET; subclass = PCI_NET_OTHER; /* Let nvram variable override core ID */ sb_devpath(sbh, devpath, sizeof(devpath)); sprintf(varname, "%sdevid", devpath); if ((core = getintvar(NULL, varname))) break; /* * no longer support wl%did, but keep the code * here for backward compatibility. */ sprintf(varname, "wl%did", unit); if ((core = getintvar(NULL, varname))) break; /* ignore it */ core = 0xffffffff; break; default: class = subclass = progif = 0xff; break; } *pcivendor = (uint16)vendor; *pcidevice = (uint16)core; *pciclass = class; *pcisubclass = subclass; *pciprogif = progif;}/* use the mdio interface to write to mdio slaves */static intsb_pcie_mdiowrite(sb_info_t *si, uint physmedia, uint regaddr, uint val){ uint mdiodata; uint i = 0; sbpcieregs_t *pcieregs; pcieregs = (sbpcieregs_t*) sb_setcoreidx(&si->sb, si->sb.buscoreidx); ASSERT(pcieregs); /* enable mdio access to SERDES */ W_REG((&pcieregs->mdiocontrol), MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); mdiodata = MDIODATA_START | MDIODATA_WRITE | (physmedia << MDIODATA_DEVADDR_SHF) | (regaddr << MDIODATA_REGADDR_SHF) | MDIODATA_TA | val; W_REG((&pcieregs->mdiodata), mdiodata); PR28829_DELAY(); /* retry till the transaction is complete */ while (i < 10) { if (R_REG(&(pcieregs->mdiocontrol)) & MDIOCTL_ACCESS_DONE) { /* Disable mdio access to SERDES */ W_REG((&pcieregs->mdiocontrol), 0); return 0; } OSL_DELAY(1000); i++; } SB_ERROR(("sb_pcie_mdiowrite: timed out\n")); /* Disable mdio access to SERDES */ W_REG((&pcieregs->mdiocontrol), 0); ASSERT(0); return 1;}/* indirect way to read pcie config regs */uintsb_pcie_readreg(void *sb, void* arg1, uint offset){ sb_info_t *si; sb_t *sbh; uint retval = 0xFFFFFFFF; sbpcieregs_t *pcieregs; uint addrtype; sbh = (sb_t *)sb; si = SB_INFO(sbh); ASSERT(PCIE(si)); pcieregs = (sbpcieregs_t *)sb_setcore(sbh, SB_PCIE, 0); ASSERT(pcieregs); addrtype = (uint)((uintptr)arg1); switch (addrtype) { case PCIE_CONFIGREGS: W_REG((&pcieregs->configaddr), offset); retval = R_REG(&(pcieregs->configdata)); break; case PCIE_PCIEREGS: W_REG(&(pcieregs->pcieaddr), offset); retval = R_REG(&(pcieregs->pciedata)); break; default: ASSERT(0); break; } return retval;}/* indirect way to write pcie config/mdio/pciecore regs */uintsb_pcie_writereg(sb_t *sbh, void *arg1, uint offset, uint val){ sb_info_t *si; sbpcieregs_t *pcieregs; uint addrtype; si = SB_INFO(sbh); ASSERT(PCIE(si)); pcieregs = (sbpcieregs_t *)sb_setcore(sbh, SB_PCIE, 0); ASSERT(pcieregs); addrtype = (uint)((uintptr)arg1); switch (addrtype) { case PCIE_CONFIGREGS: W_REG((&pcieregs->configaddr), offset); W_REG((&pcieregs->configdata), val); break; case PCIE_PCIEREGS: W_REG((&pcieregs->pcieaddr), offset); W_REG((&pcieregs->pciedata), val); break; default: ASSERT(0); break; } return 0;}/* Build device path. Support SB, PCI, and JTAG for now. */intsb_devpath(sb_t *sbh, char *path, int size){ ASSERT(path); ASSERT(size >= SB_DEVPATH_BUFSZ); switch (BUSTYPE((SB_INFO(sbh))->sb.bustype)) { case PCI_BUS: ASSERT((SB_INFO(sbh))->osh); sprintf(path, "pci/%u/%u/", OSL_PCI_BUS((SB_INFO(sbh))->osh), OSL_PCI_SLOT((SB_INFO(sbh))->osh)); break; default: ASSERT(0); break; } return 0;}/* Fix chip's configuration. The current core may be changed upon return */static intsb_pci_fixcfg(sb_info_t *si){ uint origidx, pciidx; sbpciregs_t *pciregs; sbpcieregs_t *pcieregs; uint16 val16, *reg16; char name[SB_DEVPATH_BUFSZ+16], *value; char devpath[SB_DEVPATH_BUFSZ]; ASSERT(BUSTYPE(si->sb.bustype) == PCI_BUS); /* Fix PCI(e) SROM shadow area */ /* save the current index */ origidx = sb_coreidx(&si->sb); /* check 'pi' is correct and fix it if not */ if (si->sb.buscoretype == SB_PCIE) { pcieregs = (sbpcieregs_t *)sb_setcore(&si->sb, SB_PCIE, 0); ASSERT(pcieregs); reg16 = &pcieregs->sprom[SRSH_PI_OFFSET]; } else if (si->sb.buscoretype == SB_PCI) { pciregs = (sbpciregs_t *)sb_setcore(&si->sb, SB_PCI, 0); ASSERT(pciregs); reg16 = &pciregs->sprom[SRSH_PI_OFFSET]; } else { ASSERT(0); return -1; } pciidx = sb_coreidx(&si->sb); val16 = R_REG(reg16); if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (uint16)pciidx) { val16 = (uint16)(pciidx << SRSH_PI_SHIFT) | (val16 & ~SRSH_PI_MASK); W_REG(reg16, val16); } /* restore the original index */ sb_setcoreidx(&si->sb, origidx); /* Fix bar0window */ /* !do it last, it changes the current core! */ if (sb_devpath(&si->sb, devpath, sizeof(devpath))) return -1; sprintf(name, "%sb0w", devpath); if ((value = getvar(NULL, name))) { OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32), bcm_strtoul(value, NULL, 16)); /* update curidx since the current core is changed */ si->curidx = _sb_coreidx(si); if (si->curidx == BADIDX) { SB_ERROR(("sb_pci_fixcfg: bad core index\n")); return -1; } } return 0;}static uintsb_chipc_capability(sb_t *sbh){ sb_info_t *si; si = SB_INFO(sbh); /* Make sure that there is ChipCommon core present */ if (si->coreid[SB_CC_IDX] == SB_CC) return (sb_corereg(si, SB_CC_IDX, OFFSETOF(chipcregs_t, capabilities), 0, 0)); return 0;}/* Return ADDR64 capability of the backplane */boolsb_backplane64(sb_t *sbh){ return (sb_chipc_capability(sbh) & CAP_BKPLN64);}voidsb_btcgpiowar(sb_t *sbh){ sb_info_t *si; uint origidx; uint intr_val = 0; chipcregs_t *cc; si = SB_INFO(sbh); /* Make sure that there is ChipCommon core present && * UART_TX is strapped to 1 */ if (!(sb_chipc_capability(sbh) & CAP_UARTGPIO)) return; /* sb_corereg cannot be used as we have to guarantee 8-bit read/writes */ INTR_OFF(si, intr_val); origidx = sb_coreidx(sbh); cc = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0); if (cc == NULL) goto end; W_REG(&cc->uart0mcr, R_REG(&cc->uart0mcr) | 0x04);end: /* restore the original index */ sb_setcoreidx(sbh, origidx); INTR_RESTORE(si, intr_val);}/* check if the device is removed */boolsb_deviceremoved(sb_t *sbh){ uint32 w; sb_info_t *si; si = SB_INFO(sbh); switch (BUSTYPE(si->sb.bustype)) { case PCI_BUS: ASSERT(si->osh); w = OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_VID, sizeof(uint32)); if ((w & 0xFFFF) != VENDOR_BROADCOM) return TRUE; else return FALSE; default: return FALSE; } return FALSE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -