diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/siutils.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/siutils.c | 626 |
1 files changed, 455 insertions, 171 deletions
diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c index 0c0ffd5..2161202 100644 --- a/drivers/net/wireless/bcmdhd/siutils.c +++ b/drivers/net/wireless/bcmdhd/siutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2014, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: siutils.c 369572 2012-11-19 12:57:59Z $ + * $Id: siutils.c 434466 2013-11-06 12:34:26Z $ */ #include <bcm_cfg.h> @@ -48,6 +48,10 @@ #include <spid.h> #endif /* BCMSPI */ +#ifdef BCM_SDRBL +#include <hndcpu.h> +#endif /* BCM_SDRBL */ + #include "siutils_priv.h" /* local prototypes */ @@ -66,13 +70,19 @@ static uint32 si_gpioreservation = 0; int do_4360_pcie2_war = 0; -/* - * Allocate a si handle. +/* global kernel resource */ +static si_info_t ksii; +static si_cores_info_t ksii_cores_info; + +/** + * Allocate an si handle. This function may be called multiple times. + * * devid - pci device id (used to determine chip#) * osh - opaque OS handle * regs - virtual address of initial core registers * bustype - pci/pcmcia/sb/sdio/etc - * vars - pointer to a pointer area for "environment" variables + * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this + * function set 'vars' to NULL, making dereferencing of this parameter undesired. * varsz - pointer to int to return the size of the vars */ si_t * @@ -80,15 +90,24 @@ si_attach(uint devid, osl_t *osh, void *regs, uint bustype, void *sdh, char **vars, uint *varsz) { si_info_t *sii; - + si_cores_info_t *cores_info; /* alloc si_info_t */ - if ((sii = MALLOC(osh, sizeof (si_info_t))) == NULL) { + if ((sii = MALLOCZ(osh, sizeof (si_info_t))) == NULL) { SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); return (NULL); } + /* alloc si_cores_info_t */ + if ((cores_info = (si_cores_info_t *)MALLOCZ(osh, sizeof (si_cores_info_t))) == NULL) { + SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); + MFREE(osh, sii, sizeof(si_info_t)); + return (NULL); + } + sii->cores_info = cores_info; + if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) { MFREE(osh, sii, sizeof(si_info_t)); + MFREE(osh, cores_info, sizeof(si_cores_info_t)); return (NULL); } sii->vars = vars ? *vars : NULL; @@ -97,30 +116,27 @@ si_attach(uint devid, osl_t *osh, void *regs, return (si_t *)sii; } -/* global kernel resource */ -static si_info_t ksii; static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */ -/* generic kernel variant of si_attach() */ +/** generic kernel variant of si_attach() */ si_t * si_kattach(osl_t *osh) { static bool ksii_attached = FALSE; - - if (!osh) { - SI_ERROR(("%s: osh is NULL\n", __FUNCTION__)); - return NULL; - } + si_cores_info_t *cores_info; if (!ksii_attached) { void *regs = NULL; regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); + cores_info = (si_cores_info_t *)&ksii_cores_info; + ksii.cores_info = cores_info; + ASSERT(osh); 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) { + osh != SI_OSH ? &(ksii.vars) : NULL, + osh != SI_OSH ? &(ksii.varsz) : NULL) == NULL) { SI_ERROR(("si_kattach: si_doattach failed\n")); REG_UNMAP(regs); return NULL; @@ -210,6 +226,7 @@ static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, uint *origidx, void *regs) { + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; bool pci, pcie, pcie_gen2 = FALSE; uint i; uint pciidx, pcieidx, pcirev, pcierev; @@ -259,9 +276,24 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, /* Display cores found */ SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", - i, cid, crev, sii->coresba[i], sii->regs[i])); + i, cid, crev, cores_info->coresba[i], cores_info->regs[i])); + + if (BUSTYPE(bustype) == SI_BUS) { + /* now look at the chipstatus register to figure the pacakge */ + /* for SDIO but downloaded on PCIE dev */ + if (cid == PCIE2_CORE_ID) { + if ((CHIPID(sii->pub.chip) == BCM43602_CHIP_ID) || + ((CHIPID(sii->pub.chip) == BCM4345_CHIP_ID) && + CST4345_CHIPMODE_PCIE(sii->pub.chipst))) { + pcieidx = i; + pcierev = crev; + pcie = TRUE; + pcie_gen2 = TRUE; + } + } - if (BUSTYPE(bustype) == PCI_BUS) { + } + else if (BUSTYPE(bustype) == PCI_BUS) { if (cid == PCI_CORE_ID) { pciidx = i; pcirev = crev; @@ -289,11 +321,14 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, } /* find the core idx before entering this func. */ - if ((savewin && (savewin == sii->coresba[i])) || - (regs == sii->regs[i])) + if ((savewin && (savewin == cores_info->coresba[i])) || + (regs == cores_info->regs[i])) *origidx = i; } +#if defined(PCIE_FULL_DONGLE) + pci = FALSE; +#endif if (pci) { sii->pub.buscoretype = PCI_CORE_ID; sii->pub.buscorerev = pcirev; @@ -333,6 +368,12 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, +/** + * Allocate an si handle. This function may be called multiple times. + * + * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this + * function set 'vars' to NULL. + */ static si_info_t * si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, uint bustype, void *sdh, char **vars, uint *varsz) @@ -344,9 +385,8 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, uint origidx; #if !defined(_CFEZ_) || defined(CFG_WL) #endif - ASSERT(GOODREGS(regs)); - bzero((uchar*)sii, sizeof(si_info_t)); + ASSERT(GOODREGS(regs)); savewin = 0; @@ -357,6 +397,13 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, sii->osh = osh; + /* check to see if we are a si core mimic'ing a pci core */ + if ((bustype == PCI_BUS) && + (OSL_PCI_READ_CONFIG(sii->osh, PCI_SPROM_CONTROL, sizeof(uint32)) == 0xffffffff)) { + SI_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SI " + "devid:0x%x\n", __FUNCTION__, devid)); + bustype = SI_BUS; + } /* find Chipcommon address */ if (bustype == PCI_BUS) { @@ -396,6 +443,7 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, return NULL; } w = R_REG(osh, &cc->chipid); + if ((w & 0xfffff) == 148277) w -= 65532; sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; /* Might as wll fill in chip id rev & pkg */ sih->chip = w & CID_ID_MASK; @@ -470,6 +518,26 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, } #endif +#ifdef BCM_SDRBL + /* 4360 rom bootloader in PCIE case, if the SDR is enabled, But preotection is + * not turned on, then we want to hold arm in reset. + * Bottomline: In sdrenable case, we allow arm to boot only when protection is + * turned on. + */ + if (CHIP_HOSTIF_PCIE(&(sii->pub))) { + uint32 sflags = si_arm_sflags(&(sii->pub)); + + /* If SDR is enabled but protection is not turned on + * then we want to force arm to WFI. + */ + if ((sflags & (SISF_SDRENABLE | SISF_TCMPROT)) == SISF_SDRENABLE) { + disable_arm_irq(); + while (1) { + hnd_cpu_wait(sih); + } + } + } +#endif /* BCM_SDRBL */ pvars = NULL; BCM_REFERENCE(pvars); @@ -497,6 +565,7 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, /* clear any previous epidiag-induced target abort */ ASSERT(!si_taclear(sih, FALSE)); + return (sii); exit: @@ -504,27 +573,27 @@ exit: return NULL; } -/* may be called with core in reset */ +/** may be called with core in reset */ void si_detach(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint idx; - sii = SI_INFO(sih); - - if (sii == NULL) - return; - if (BUSTYPE(sih->bustype) == SI_BUS) for (idx = 0; idx < SI_MAXCORES; idx++) - if (sii->regs[idx]) { - REG_UNMAP(sii->regs[idx]); - sii->regs[idx] = NULL; + if (cores_info->regs[idx]) { + REG_UNMAP(cores_info->regs[idx]); + cores_info->regs[idx] = NULL; } +#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) + if (cores_info != &ksii_cores_info) +#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ + MFREE(sii->osh, cores_info, sizeof(si_cores_info_t)); #if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) if (sii != &ksii) @@ -554,14 +623,13 @@ si_setosh(si_t *sih, osl_t *osh) sii->osh = osh; } -/* register driver interrupt disabling and restoring callback functions */ +/** 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); + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; sii->intr_arg = intr_arg; sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn; sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn; @@ -569,7 +637,7 @@ si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_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->coreid[sii->curidx]; + sii->dev_coreid = cores_info->coreid[sii->curidx]; } void @@ -612,6 +680,17 @@ si_flag(si_t *sih) } } +uint +si_flag_alt(si_t *sih) +{ + if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_flag_alt(sih); + else { + ASSERT(0); + return 0; + } +} + void si_setint(si_t *sih, int siflag) { @@ -628,10 +707,10 @@ si_setint(si_t *sih, int siflag) uint si_coreid(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - sii = SI_INFO(sih); - return sii->coreid[sii->curidx]; + return cores_info->coreid[sii->curidx]; } uint @@ -643,17 +722,17 @@ si_coreidx(si_t *sih) return sii->curidx; } -/* return the core-type instantiation # of the current core */ +/** return the core-type instantiation # of the current core */ uint si_coreunit(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint idx; uint coreid; uint coreunit; uint i; - sii = SI_INFO(sih); coreunit = 0; idx = sii->curidx; @@ -663,7 +742,7 @@ si_coreunit(si_t *sih) /* count the cores of our type */ for (i = 0; i < idx; i++) - if (sii->coreid[i] == coreid) + if (cores_info->coreid[i] == coreid) coreunit++; return (coreunit); @@ -705,20 +784,20 @@ si_corerev(si_t *sih) } } -/* return index of coreid or BADIDX if not found */ +/** return index of coreid or BADIDX if not found */ uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint found; uint i; - sii = SI_INFO(sih); found = 0; for (i = 0; i < sii->numcores; i++) - if (sii->coreid[i] == coreid) { + if (cores_info->coreid[i] == coreid) { if (found == coreunit) return (i); found++; @@ -727,19 +806,49 @@ si_findcoreidx(si_t *sih, uint coreid, uint coreunit) return (BADIDX); } -/* return list of found cores */ +/** return total coreunit of coreid or zero if not found */ +uint +si_numcoreunits(si_t *sih, uint coreid) +{ + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + uint found; + uint i; + + found = 0; + + for (i = 0; i < sii->numcores; i++) + if (cores_info->coreid[i] == coreid) { + found++; + } + + return (found == 0? 0:found); +} + +/** return list of found cores */ uint si_corelist(si_t *sih, uint coreid[]) { + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; + + bcopy((uchar*)cores_info->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); + return (sii->numcores); +} + +/** return current wrapper mapping */ +void * +si_wrapperregs(si_t *sih) +{ si_info_t *sii; sii = SI_INFO(sih); + ASSERT(GOODREGS(sii->curwrap)); - bcopy((uchar*)sii->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); - return (sii->numcores); + return (sii->curwrap); } -/* return current register mapping */ +/** return current register mapping */ void * si_coreregs(si_t *sih) { @@ -751,7 +860,7 @@ si_coreregs(si_t *sih) return (sii->curmap); } -/* +/** * 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 @@ -792,14 +901,13 @@ si_setcoreidx(si_t *sih, uint coreidx) } } -/* Turn off interrupt as required by sb_setcore, before switch core */ +/** 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); + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; if (SI_FAST(sii)) { /* Overloading the origidx variable to remember the coreid, @@ -824,9 +932,9 @@ si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) void si_restore_core(si_t *sih, uint coreid, uint intr_val) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - sii = SI_INFO(sih); if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) return; @@ -971,6 +1079,27 @@ si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) } } +/* + * If there is no need for fiddling with interrupts or core switches (typically silicon + * back plane registers, pci registers and chipcommon registers), this function + * returns the register offset on this core to a mapped address. This address can + * be used for W_REG/R_REG directly. + * + * For accessing registers that would need a core switch, this function will return + * NULL. + */ +uint32 * +si_corereg_addr(si_t *sih, uint coreidx, uint regoff) +{ + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_corereg_addr(sih, coreidx, regoff); + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_corereg_addr(sih, coreidx, regoff); + else { + return 0; + } +} + void si_core_disable(si_t *sih, uint32 bits) { @@ -993,7 +1122,7 @@ si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ub_core_reset(sih, bits, resetbits); } -/* Run bist on current core. Caller needs to take care of core-specific bist hazards */ +/** Run bist on current core. Caller needs to take care of core-specific bist hazards */ int si_corebist(si_t *sih) { @@ -1032,7 +1161,7 @@ factor6(uint32 x) } } -/* calculate the speed the SI would run at given a set of clockcontrol values */ +/** calculate the speed the SI would run at given a set of clockcontrol values */ uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m) { @@ -1116,8 +1245,80 @@ si_clock_rate(uint32 pll_type, uint32 n, uint32 m) } } +/** + * Some chips could have multiple host interfaces, however only one will be active. + * For a given chip. Depending pkgopt and cc_chipst return the active host interface. + */ +uint +si_chip_hostif(si_t *sih) +{ + uint hosti = 0; + + switch (CHIPID(sih->chip)) { + + case BCM43602_CHIP_ID: + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + case BCM4360_CHIP_ID: + /* chippkg bit-0 == 0 is PCIE only pkgs + * chippkg bit-0 == 1 has both PCIE and USB cores enabled + */ + if ((sih->chippkg & 0x1) && (sih->chipst & CST4360_MODE_USB)) + hosti = CHIP_HOSTIF_USBMODE; + else + hosti = CHIP_HOSTIF_PCIEMODE; + + break; + + case BCM4335_CHIP_ID: + /* TBD: like in 4360, do we need to check pkg? */ + if (CST4335_CHIPMODE_USB20D(sih->chipst)) + hosti = CHIP_HOSTIF_USBMODE; + else if (CST4335_CHIPMODE_SDIOD(sih->chipst)) + hosti = CHIP_HOSTIF_SDIOMODE; + else + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + case BCM4345_CHIP_ID: + if (CST4345_CHIPMODE_USB20D(sih->chipst) || CST4345_CHIPMODE_HSIC(sih->chipst)) + hosti = CHIP_HOSTIF_USBMODE; + else if (CST4345_CHIPMODE_SDIOD(sih->chipst)) + hosti = CHIP_HOSTIF_SDIOMODE; + else if (CST4345_CHIPMODE_PCIE(sih->chipst)) + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + + case BCM4350_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM43556_CHIP_ID: + case BCM43558_CHIP_ID: + case BCM43566_CHIP_ID: + case BCM43568_CHIP_ID: + case BCM43569_CHIP_ID: + if (CST4350_CHIPMODE_USB20D(sih->chipst) || + CST4350_CHIPMODE_HSIC20D(sih->chipst) || + CST4350_CHIPMODE_USB30D(sih->chipst) || + CST4350_CHIPMODE_USB30D_WL(sih->chipst) || + CST4350_CHIPMODE_HSIC30D(sih->chipst)) + hosti = CHIP_HOSTIF_USBMODE; + else if (CST4350_CHIPMODE_SDIOD(sih->chipst)) + hosti = CHIP_HOSTIF_SDIOMODE; + else if (CST4350_CHIPMODE_PCIE(sih->chipst)) + hosti = CHIP_HOSTIF_PCIEMODE; + break; + + default: + break; + } + + return hosti; +} + -/* set chip watchdog reset timer to fire in 'ticks' */ +/** set chip watchdog reset timer to fire in 'ticks' */ void si_watchdog(si_t *sih, uint ticks) { @@ -1159,7 +1360,7 @@ si_watchdog(si_t *sih, uint ticks) } } -/* trigger watchdog reset after ms milliseconds */ +/** trigger watchdog reset after ms milliseconds */ void si_watchdog_ms(si_t *sih, uint32 ms) { @@ -1179,7 +1380,7 @@ si_taclear(si_t *sih, bool details) -/* return the slow clock source - LPO, XTAL, or PCI */ +/** return the slow clock source - LPO, XTAL, or PCI */ static uint si_slowclk_src(si_info_t *sii) { @@ -1196,12 +1397,13 @@ si_slowclk_src(si_info_t *sii) return (SCC_SS_XTAL); } else if (sii->pub.ccrev < 10) { cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx); + ASSERT(cc); return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); } else /* Insta-clock */ return (SCC_SS_XTAL); } -/* return the ILP (slowclock) min or max frequency */ +/** return the ILP (slowclock) min or max frequency */ static uint si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) { @@ -1266,7 +1468,7 @@ si_clkctl_setdelay(si_info_t *sii, void *chipcregs) W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay); } -/* initialize power control delay registers */ +/** initialize power control delay registers */ void si_clkctl_init(si_t *sih) { @@ -1302,14 +1504,14 @@ si_clkctl_init(si_t *sih) } -/* change logical "focus" to the gpio core for optimized access */ +/** change logical "focus" to the gpio core for optimized access */ void * si_gpiosetcore(si_t *sih) { return (si_setcoreidx(sih, SI_CC_IDX)); } -/* +/** * mask & set gpiocontrol bits. * If a gpiocontrol bit is set to 0, chipcommon controls the corresponding GPIO pin. * If a gpiocontrol bit is set to 1, the GPIO pin is no longer a GPIO and becomes dedicated @@ -1336,7 +1538,7 @@ si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority) return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); } -/* mask&set gpio output enable bits */ +/** mask&set gpio output enable bits */ uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority) { @@ -1358,7 +1560,7 @@ si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority) return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); } -/* mask&set gpio output bits */ +/** mask&set gpio output bits */ uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) { @@ -1380,7 +1582,7 @@ si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); } -/* reserve one gpio */ +/** reserve one gpio */ uint32 si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) { @@ -1406,12 +1608,12 @@ si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) return si_gpioreservation; } -/* release one gpio */ -/* +/** + * release one gpio. + * * releasing the gpio doesn't change the current value on the GPIO last write value - * persists till some one overwrites it + * persists till someone overwrites it. */ - uint32 si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) { @@ -1540,13 +1742,12 @@ void * si_gpio_handler_register(si_t *sih, uint32 event, bool level, gpio_handler_t cb, void *arg) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); gpioh_item_t *gi; ASSERT(event); ASSERT(cb != NULL); - sii = SI_INFO(sih); if (sih->ccrev < 11) return NULL; @@ -1568,10 +1769,9 @@ si_gpio_handler_register(si_t *sih, uint32 event, void si_gpio_handler_unregister(si_t *sih, void *gpioh) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); gpioh_item_t *p, *n; - sii = SI_INFO(sih); if (sih->ccrev < 11) return; @@ -1600,14 +1800,13 @@ si_gpio_handler_unregister(si_t *sih, void *gpioh) void si_gpio_handler_process(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); gpioh_item_t *h; uint32 level = si_gpioin(sih); uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0); uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0); uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0); - sii = SI_INFO(sih); for (h = sii->gpioh_head; h != NULL; h = h->next) { if (h->handler) { uint32 status = (h->level ? level : edge) & h->event; @@ -1635,7 +1834,7 @@ si_gpio_int_enable(si_t *sih, bool enable) } -/* Return the size of the specified SOCRAM bank */ +/** Return the size of the specified SOCRAM bank */ static uint socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 idx, uint8 mem_type) { @@ -1653,15 +1852,14 @@ socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 idx, uint8 mem_type) void si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect, uint8 *remap) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint origidx; uint intr_val = 0; sbsocramregs_t *regs; bool wasup; uint corerev; - sii = SI_INFO(sih); - /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); @@ -1728,7 +1926,8 @@ done: bool si_socdevram_remap_isenb(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint origidx; uint intr_val = 0; sbsocramregs_t *regs; @@ -1739,8 +1938,6 @@ si_socdevram_remap_isenb(si_t *sih) uint8 i; uint32 bankidx, bankinfo; - sii = SI_INFO(sih); - /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); @@ -1790,7 +1987,8 @@ si_socdevram_pkg(si_t *sih) uint32 si_socdevram_size(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint origidx; uint intr_val = 0; uint32 memsize = 0; @@ -1798,8 +1996,6 @@ si_socdevram_size(si_t *sih) bool wasup; uint corerev; - sii = SI_INFO(sih); - /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); @@ -1838,7 +2034,8 @@ done: uint32 si_socdevram_remap_size(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint origidx; uint intr_val = 0; uint32 memsize = 0, banksz; @@ -1850,8 +2047,6 @@ si_socdevram_remap_size(si_t *sih) uint8 i; uint32 bankidx, bankinfo; - sii = SI_INFO(sih); - /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); @@ -1901,11 +2096,12 @@ done: return memsize; } -/* Return the RAM size of the SOCRAM core */ +/** Return the RAM size of the SOCRAM core */ uint32 si_socram_size(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint origidx; uint intr_val = 0; @@ -1915,8 +2111,6 @@ si_socram_size(si_t *sih) uint32 coreinfo; uint memsize = 0; - sii = SI_INFO(sih); - /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); @@ -1965,11 +2159,12 @@ done: } -/* Return the TCM-RAM size of the ARMCR4 core. */ +/** Return the TCM-RAM size of the ARMCR4 core. */ uint32 si_tcm_size(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint origidx; uint intr_val = 0; uint8 *regs; @@ -1985,8 +2180,6 @@ si_tcm_size(si_t *sih) uint32 *arm_bidx; uint32 *arm_binfo; - sii = SI_INFO(sih); - /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); @@ -2028,10 +2221,28 @@ done: return memsize; } +bool +si_has_flops(si_t *sih) +{ + uint origidx, cr4_rev; + + /* Find out CR4 core revision */ + origidx = si_coreidx(sih); + if (si_setcore(sih, ARMCR4_CORE_ID, 0)) { + cr4_rev = si_corerev(sih); + si_setcoreidx(sih, origidx); + + if (cr4_rev == 1 || cr4_rev >= 3) + return TRUE; + } + return FALSE; +} + uint32 si_socram_srmem_size(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint origidx; uint intr_val = 0; @@ -2045,8 +2256,6 @@ si_socram_srmem_size(si_t *sih) return (32 * 1024); } - sii = SI_INFO(sih); - /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); @@ -2088,13 +2297,12 @@ done: void si_btcgpiowar(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; uint origidx; uint intr_val = 0; chipcregs_t *cc; - sii = SI_INFO(sih); - /* Make sure that there is ChipCommon core present && * UART_TX is strapped to 1 */ @@ -2120,14 +2328,13 @@ si_btcgpiowar(si_t *sih) void si_chipcontrl_btshd0_4331(si_t *sih, bool on) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); + si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; chipcregs_t *cc; uint origidx; uint32 val; uint intr_val = 0; - sii = SI_INFO(sih); - INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); @@ -2155,12 +2362,10 @@ si_chipcontrl_btshd0_4331(si_t *sih, bool on) void si_chipcontrl_restore(si_t *sih, uint32 val) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); chipcregs_t *cc; - uint origidx; + uint origidx = si_coreidx(sih); - sii = SI_INFO(sih); - origidx = si_coreidx(sih); cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); W_REG(sii->osh, &cc->chipcontrol, val); si_setcoreidx(sih, origidx); @@ -2169,13 +2374,11 @@ si_chipcontrl_restore(si_t *sih, uint32 val) uint32 si_chipcontrl_read(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); chipcregs_t *cc; - uint origidx; + uint origidx = si_coreidx(sih); uint32 val; - sii = SI_INFO(sih); - origidx = si_coreidx(sih); cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); val = R_REG(sii->osh, &cc->chipcontrol); si_setcoreidx(sih, origidx); @@ -2185,16 +2388,12 @@ si_chipcontrl_read(si_t *sih) void si_chipcontrl_epa4331(si_t *sih, bool on) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); chipcregs_t *cc; - uint origidx; + uint origidx = si_coreidx(sih); uint32 val; - sii = SI_INFO(sih); - origidx = si_coreidx(sih); - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - val = R_REG(sii->osh, &cc->chipcontrol); if (on) { @@ -2219,20 +2418,16 @@ si_chipcontrl_epa4331(si_t *sih, bool on) si_setcoreidx(sih, origidx); } -/* switch muxed pins, on: SROM, off: FEMCTRL */ +/** switch muxed pins, on: SROM, off: FEMCTRL. Called for a family of ac chips, not just 4360. */ void si_chipcontrl_srom4360(si_t *sih, bool on) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); chipcregs_t *cc; - uint origidx; + uint origidx = si_coreidx(sih); uint32 val; - sii = SI_INFO(sih); - origidx = si_coreidx(sih); - cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); - val = R_REG(sii->osh, &cc->chipcontrol); if (on) { @@ -2291,22 +2486,19 @@ si_pll_reset(si_t *sih) return (err); } -/* Enable BT-COEX & Ex-PA for 4313 */ +/** Enable BT-COEX & Ex-PA for 4313 */ void si_epa_4313war(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); chipcregs_t *cc; - uint origidx; - - sii = SI_INFO(sih); - origidx = si_coreidx(sih); + uint origidx = si_coreidx(sih); cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); /* EPA Fix */ W_REG(sii->osh, &cc->gpiocontrol, - R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); + R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); si_setcoreidx(sih, origidx); } @@ -2316,22 +2508,19 @@ si_clk_pmu_htavail_set(si_t *sih, bool set_clear) { } -/* Re-enable synth_pwrsw resource in min_res_mask for 4313 */ +/** Re-enable synth_pwrsw resource in min_res_mask for 4313 */ void si_pmu_synth_pwrsw_4313_war(si_t *sih) { } -/* WL/BT control for 4313 btcombo boards >= P250 */ +/** WL/BT control for 4313 btcombo boards >= P250 */ void si_btcombo_p250_4313_war(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); chipcregs_t *cc; - uint origidx; - - sii = SI_INFO(sih); - origidx = si_coreidx(sih); + uint origidx = si_coreidx(sih); cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); W_REG(sii->osh, &cc->gpiocontrol, @@ -2345,12 +2534,9 @@ si_btcombo_p250_4313_war(si_t *sih) void si_btc_enable_chipcontrol(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); chipcregs_t *cc; - uint origidx; - - sii = SI_INFO(sih); - origidx = si_coreidx(sih); + uint origidx = si_coreidx(sih); cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); @@ -2363,12 +2549,9 @@ si_btc_enable_chipcontrol(si_t *sih) void si_btcombo_43228_war(si_t *sih) { - si_info_t *sii; + si_info_t *sii = SI_INFO(sih); chipcregs_t *cc; - uint origidx; - - sii = SI_INFO(sih); - origidx = si_coreidx(sih); + uint origidx = si_coreidx(sih); cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); @@ -2378,19 +2561,16 @@ si_btcombo_43228_war(si_t *sih) si_setcoreidx(sih, origidx); } -/* check if the device is removed */ +/** check if the device is removed */ bool si_deviceremoved(si_t *sih) { uint32 w; - si_info_t *sii; - - sii = SI_INFO(sih); switch (BUSTYPE(sih->bustype)) { case PCI_BUS: - ASSERT(sii->osh != NULL); - w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_VID, sizeof(uint32)); + ASSERT(SI_INFO(sih)->osh != NULL); + w = OSL_PCI_READ_CONFIG(SI_INFO(sih)->osh, PCI_CFG_VID, sizeof(uint32)); if ((w & 0xFFFF) != VENDOR_BROADCOM) return TRUE; break; @@ -2413,6 +2593,7 @@ si_is_sprom_available(si_t *sih) sii = SI_INFO(sih); origidx = sii->curidx; cc = si_setcoreidx(sih, SI_CC_IDX); + ASSERT(cc); sromctrl = R_REG(sii->osh, &cc->sromcontrol); si_setcoreidx(sih, origidx); return (sromctrl & SRC_PRESENT); @@ -2455,10 +2636,19 @@ si_is_sprom_available(si_t *sih) return ((sih->chipst & CST4324_SPROM_MASK) && !(sih->chipst & CST4324_SFLASH_MASK)); case BCM4335_CHIP_ID: + case BCM4345_CHIP_ID: return ((sih->chipst & CST4335_SPROM_MASK) && !(sih->chipst & CST4335_SFLASH_MASK)); case BCM4350_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM43556_CHIP_ID: + case BCM43558_CHIP_ID: + case BCM43566_CHIP_ID: + case BCM43568_CHIP_ID: + case BCM43569_CHIP_ID: return (sih->chipst & CST4350_SPROM_PRESENT) != 0; + case BCM43602_CHIP_ID: + return (sih->chipst & CST43602_SPROM_PRESENT) != 0; case BCM43131_CHIP_ID: case BCM43217_CHIP_ID: case BCM43227_CHIP_ID: @@ -2474,12 +2664,10 @@ si_is_sprom_available(si_t *sih) uint32 si_get_sromctl(si_t *sih) { chipcregs_t *cc; - uint origidx; + uint origidx = si_coreidx(sih); uint32 sromctl; - osl_t *osh; + osl_t *osh = si_osh(sih); - osh = si_osh(sih); - origidx = si_coreidx(sih); cc = si_setcoreidx(sih, SI_CC_IDX); ASSERT((uintptr)cc); @@ -2493,11 +2681,9 @@ uint32 si_get_sromctl(si_t *sih) int si_set_sromctl(si_t *sih, uint32 value) { chipcregs_t *cc; - uint origidx; - osl_t *osh; + uint origidx = si_coreidx(sih); + osl_t *osh = si_osh(sih); - osh = si_osh(sih); - origidx = si_coreidx(sih); cc = si_setcoreidx(sih, SI_CC_IDX); ASSERT((uintptr)cc); @@ -2529,3 +2715,101 @@ si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 si_setcoreidx(sih, origidx); return ret_val; } + + +/* cleanup the hndrte timer from the host when ARM is been halted + * without a chance for ARM cleanup its resources + * If left not cleanup, Intr from a software timer can still + * request HT clk when ARM is halted. + */ +uint32 +si_pmu_res_req_timer_clr(si_t *sih) +{ + uint32 mask; + + mask = PRRT_REQ_ACTIVE | PRRT_INTEN; + if (CHIPID(sih->chip) != BCM4328_CHIP_ID) + mask <<= 14; + /* clear mask bits */ + si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, res_req_timer), mask, 0); + /* readback to ensure write completes */ + return si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, res_req_timer), 0, 0); +} + +/** turn on/off rfldo */ +void +si_pmu_rfldo(si_t *sih, bool on) +{ +} + +#ifdef SURVIVE_PERST_ENAB +static uint32 +si_pcie_survive_perst(si_t *sih, uint32 mask, uint32 val) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + + if (!PCIE(sii)) + return (0); + + return pcie_survive_perst(sii->pch, mask, val); +} + +static void +si_watchdog_reset(si_t *sih) +{ + si_info_t *sii = SI_INFO(sih); + chipcregs_t *cc; + uint32 origidx, i; + + origidx = si_coreidx(sih); + cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + /* issue a watchdog reset */ + W_REG(sii->osh, &cc->pmuwatchdog, 2); + /* do busy wait for 20ms */ + for (i = 0; i < 2000; i++) { + OSL_DELAY(10); + } + si_setcoreidx(sih, origidx); +} +#endif /* SURVIVE_PERST_ENAB */ + +void +si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 sperst_val) +{ +#ifdef SURVIVE_PERST_ENAB + if (BUSTYPE(sih->bustype) != PCI_BUS) + return; + + if ((CHIPID(sih->chip) != BCM4360_CHIP_ID && CHIPID(sih->chip) != BCM4352_CHIP_ID) || + (CHIPREV(sih->chiprev) >= 4)) + return; + + if (reset) { + si_info_t *sii = SI_INFO(sih); + uint32 bar0win, bar0win_after; + + /* save the bar0win */ + bar0win = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); + + si_watchdog_reset(sih); + + bar0win_after = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); + if (bar0win_after != bar0win) { + SI_ERROR(("%s: bar0win before %08x, bar0win after %08x\n", + __FUNCTION__, bar0win, bar0win_after)); + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32), bar0win); + } + } + if (sperst_mask) { + /* enable survive perst */ + si_pcie_survive_perst(sih, sperst_mask, sperst_val); + } +#endif /* SURVIVE_PERST_ENAB */ +} + +void +si_pcie_ltr_war(si_t *sih) +{ +} |