|  | /* | 
|  | * Misc utility routines for accessing chip-specific features | 
|  | * of the SiliconBackplane-based Broadcom chips. | 
|  | * | 
|  | * Copyright (C) 1999-2011, Broadcom Corporation | 
|  | * | 
|  | *         Unless you and Broadcom execute a separate written software license | 
|  | * agreement governing use of this software, this software is licensed to you | 
|  | * under the terms of the GNU General Public License version 2 (the "GPL"), | 
|  | * available at http://www.broadcom.com/licenses/GPLv2.php, with the | 
|  | * following added to such license: | 
|  | * | 
|  | *      As a special exception, the copyright holders of this software give you | 
|  | * permission to link this software with independent modules, and to copy and | 
|  | * distribute the resulting executable under terms of your choice, provided that | 
|  | * you also meet, for each linked independent module, the terms and conditions of | 
|  | * the license of that module.  An independent module is a module which is not | 
|  | * derived from this software.  The special exception does not apply to any | 
|  | * modifications of the software. | 
|  | * | 
|  | *      Notwithstanding the above, under no circumstances may you combine this | 
|  | * 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,v 1.813.2.36 2011-02-10 23:43:55 Exp $ | 
|  | */ | 
|  |  | 
|  | #include <typedefs.h> | 
|  | #include <bcmdefs.h> | 
|  | #include <osl.h> | 
|  | #include <bcmutils.h> | 
|  | #include <siutils.h> | 
|  | #include <bcmdevs.h> | 
|  | #include <hndsoc.h> | 
|  | #include <sbchipc.h> | 
|  | #include <pcicfg.h> | 
|  | #include <sbpcmcia.h> | 
|  | #include <sbsocram.h> | 
|  | #include <bcmsdh.h> | 
|  | #include <sdio.h> | 
|  | #include <sbsdio.h> | 
|  | #include <sbhnddma.h> | 
|  | #include <sbsdpcmdev.h> | 
|  | #include <bcmsdpcm.h> | 
|  | #include <hndpmu.h> | 
|  |  | 
|  | #include "siutils_priv.h" | 
|  |  | 
|  | /* local prototypes */ | 
|  | 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); | 
|  | static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh); | 
|  | static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, | 
|  | uint *origidx, void *regs); | 
|  |  | 
|  |  | 
|  | /* global variable to indicate reservation/release of gpio's */ | 
|  | static uint32 si_gpioreservation = 0; | 
|  |  | 
|  | /* global flag to prevent shared resources from being initialized multiple times in si_attach() */ | 
|  |  | 
|  | /* | 
|  | * Allocate a si handle. | 
|  | * 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 | 
|  | * varsz - pointer to int to return the size of the vars | 
|  | */ | 
|  | si_t * | 
|  | si_attach(uint devid, osl_t *osh, void *regs, | 
|  | uint bustype, void *sdh, char **vars, uint *varsz) | 
|  | { | 
|  | si_info_t *sii; | 
|  |  | 
|  | /* alloc si_info_t */ | 
|  | if ((sii = MALLOC(osh, sizeof (si_info_t))) == NULL) { | 
|  | SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); | 
|  | return (NULL); | 
|  | } | 
|  |  | 
|  | if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) { | 
|  | MFREE(osh, sii, sizeof(si_info_t)); | 
|  | return (NULL); | 
|  | } | 
|  | sii->vars = vars ? *vars : NULL; | 
|  | sii->varsz = varsz ? *varsz : 0; | 
|  |  | 
|  | 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() */ | 
|  | si_t * | 
|  | si_kattach(osl_t *osh) | 
|  | { | 
|  | static bool ksii_attached = FALSE; | 
|  |  | 
|  | if (!ksii_attached) { | 
|  | void *regs; | 
|  | 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) { | 
|  | 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; | 
|  | } | 
|  |  | 
|  |  | 
|  | static bool | 
|  | si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) | 
|  | { | 
|  | /* need to set memseg flag for CF card first before any sb registers access */ | 
|  | if (BUSTYPE(bustype) == PCMCIA_BUS) | 
|  | sii->memseg = TRUE; | 
|  |  | 
|  |  | 
|  | if (BUSTYPE(bustype) == SDIO_BUS) { | 
|  | int err; | 
|  | uint8 clkset; | 
|  |  | 
|  | /* Try forcing SDIO core to do ALPAvail request only */ | 
|  | clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; | 
|  | bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); | 
|  | if (!err) { | 
|  | uint8 clkval; | 
|  |  | 
|  | /* If register supported, wait for ALPAvail and then force ALP */ | 
|  | clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL); | 
|  | if ((clkval & ~SBSDIO_AVBITS) == clkset) { | 
|  | SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, | 
|  | SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), | 
|  | PMU_MAX_TRANSITION_DLY); | 
|  | if (!SBSDIO_ALPAV(clkval)) { | 
|  | SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n", | 
|  | clkval)); | 
|  | return FALSE; | 
|  | } | 
|  | clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; | 
|  | bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, | 
|  | clkset, &err); | 
|  | OSL_DELAY(65); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Also, disable the extra SDIO pull-ups */ | 
|  | bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); | 
|  | } | 
|  |  | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static bool | 
|  | si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, | 
|  | uint *origidx, void *regs) | 
|  | { | 
|  | bool pci, pcie; | 
|  | uint i; | 
|  | uint pciidx, pcieidx, pcirev, pcierev; | 
|  |  | 
|  | cc = si_setcoreidx(&sii->pub, SI_CC_IDX); | 
|  | ASSERT((uintptr)cc); | 
|  |  | 
|  | /* get chipcommon rev */ | 
|  | sii->pub.ccrev = (int)si_corerev(&sii->pub); | 
|  |  | 
|  | /* get chipcommon chipstatus */ | 
|  | if (sii->pub.ccrev >= 11) | 
|  | sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); | 
|  |  | 
|  | /* get chipcommon capabilites */ | 
|  | sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); | 
|  | /* get chipcommon extended capabilities */ | 
|  |  | 
|  | if (sii->pub.ccrev >= 35) | 
|  | sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); | 
|  |  | 
|  | /* get pmu rev and caps */ | 
|  | if (sii->pub.cccaps & CC_CAP_PMU) { | 
|  | sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); | 
|  | sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; | 
|  | } | 
|  |  | 
|  | SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", | 
|  | sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, | 
|  | sii->pub.pmucaps)); | 
|  |  | 
|  | /* figure out bus/orignal core idx */ | 
|  | sii->pub.buscoretype = NODEV_CORE_ID; | 
|  | sii->pub.buscorerev = NOREV; | 
|  | sii->pub.buscoreidx = BADIDX; | 
|  |  | 
|  | pci = pcie = FALSE; | 
|  | pcirev = pcierev = NOREV; | 
|  | pciidx = pcieidx = BADIDX; | 
|  |  | 
|  | for (i = 0; i < sii->numcores; i++) { | 
|  | uint cid, crev; | 
|  |  | 
|  | si_setcoreidx(&sii->pub, i); | 
|  | cid = si_coreid(&sii->pub); | 
|  | crev = si_corerev(&sii->pub); | 
|  |  | 
|  | /* 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])); | 
|  |  | 
|  | if (BUSTYPE(bustype) == PCI_BUS) { | 
|  | if (cid == PCI_CORE_ID) { | 
|  | pciidx = i; | 
|  | pcirev = crev; | 
|  | pci = TRUE; | 
|  | } else if (cid == PCIE_CORE_ID) { | 
|  | pcieidx = i; | 
|  | pcierev = crev; | 
|  | pcie = TRUE; | 
|  | } | 
|  | } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && | 
|  | (cid == PCMCIA_CORE_ID)) { | 
|  | sii->pub.buscorerev = crev; | 
|  | sii->pub.buscoretype = cid; | 
|  | sii->pub.buscoreidx = i; | 
|  | } | 
|  | else if (((BUSTYPE(bustype) == SDIO_BUS) || | 
|  | (BUSTYPE(bustype) == SPI_BUS)) && | 
|  | ((cid == PCMCIA_CORE_ID) || | 
|  | (cid == SDIOD_CORE_ID))) { | 
|  | sii->pub.buscorerev = crev; | 
|  | sii->pub.buscoretype = cid; | 
|  | sii->pub.buscoreidx = i; | 
|  | } | 
|  |  | 
|  | /* find the core idx before entering this func. */ | 
|  | if ((savewin && (savewin == sii->coresba[i])) || | 
|  | (regs == sii->regs[i])) | 
|  | *origidx = i; | 
|  | } | 
|  |  | 
|  | if (pci) { | 
|  | sii->pub.buscoretype = PCI_CORE_ID; | 
|  | sii->pub.buscorerev = pcirev; | 
|  | sii->pub.buscoreidx = pciidx; | 
|  | } else if (pcie) { | 
|  | sii->pub.buscoretype = PCIE_CORE_ID; | 
|  | sii->pub.buscorerev = pcierev; | 
|  | sii->pub.buscoreidx = pcieidx; | 
|  | } | 
|  |  | 
|  | SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, | 
|  | sii->pub.buscorerev)); | 
|  |  | 
|  | if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) && | 
|  | (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3)) | 
|  | OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL); | 
|  |  | 
|  |  | 
|  | /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was | 
|  | * already running. | 
|  | */ | 
|  | if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { | 
|  | if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || | 
|  | si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) | 
|  | si_core_disable(&sii->pub, 0); | 
|  | } | 
|  |  | 
|  | /* return to the original core */ | 
|  | si_setcoreidx(&sii->pub, *origidx); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | 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) | 
|  | { | 
|  | struct si_pub *sih = &sii->pub; | 
|  | uint32 w, savewin; | 
|  | chipcregs_t *cc; | 
|  | char *pvars = NULL; | 
|  | uint origidx; | 
|  |  | 
|  | ASSERT(GOODREGS(regs)); | 
|  |  | 
|  | bzero((uchar*)sii, sizeof(si_info_t)); | 
|  |  | 
|  | savewin = 0; | 
|  |  | 
|  | sih->buscoreidx = BADIDX; | 
|  |  | 
|  | sii->curmap = regs; | 
|  | sii->sdh = sdh; | 
|  | sii->osh = osh; | 
|  |  | 
|  |  | 
|  |  | 
|  | /* find Chipcommon address */ | 
|  | if (bustype == PCI_BUS) { | 
|  | savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); | 
|  | if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) | 
|  | savewin = SI_ENUM_BASE; | 
|  | OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); | 
|  | cc = (chipcregs_t *)regs; | 
|  | } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { | 
|  | cc = (chipcregs_t *)sii->curmap; | 
|  | } else { | 
|  | cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); | 
|  | } | 
|  |  | 
|  | sih->bustype = bustype; | 
|  | if (bustype != BUSTYPE(bustype)) { | 
|  | SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", | 
|  | bustype, BUSTYPE(bustype))); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* bus/core/clk setup for register access */ | 
|  | if (!si_buscore_prep(sii, bustype, devid, sdh)) { | 
|  | SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* ChipID recognition. | 
|  | *   We assume we can read chipid at offset 0 from the regs arg. | 
|  | *   If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon), | 
|  | *   some way of recognizing them needs to be added here. | 
|  | */ | 
|  | w = R_REG(osh, &cc->chipid); | 
|  | sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; | 
|  | /* Might as wll fill in chip id rev & pkg */ | 
|  | sih->chip = w & CID_ID_MASK; | 
|  | sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; | 
|  | sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; | 
|  | if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK) | 
|  | >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT | | 
|  | CST4322_SPROM_PRESENT))) { | 
|  | SI_ERROR(("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__)); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) && | 
|  | (sih->chippkg != BCM4329_289PIN_PKG_ID)) { | 
|  | sih->chippkg = BCM4329_182PIN_PKG_ID; | 
|  | } | 
|  |  | 
|  | sih->issim = IS_SIM(sih->chippkg); | 
|  |  | 
|  | /* scan for cores */ | 
|  | if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) { | 
|  | SI_MSG(("Found chip type SB (0x%08x)\n", w)); | 
|  | sb_scan(&sii->pub, regs, devid); | 
|  | } else if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) { | 
|  | SI_MSG(("Found chip type AI (0x%08x)\n", w)); | 
|  | /* pass chipc address instead of original core base */ | 
|  | ai_scan(&sii->pub, (void *)(uintptr)cc, devid); | 
|  | } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) { | 
|  | SI_MSG(("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip)); | 
|  | /* pass chipc address instead of original core base */ | 
|  | ub_scan(&sii->pub, (void *)(uintptr)cc, devid); | 
|  | } else { | 
|  | SI_ERROR(("Found chip of unknown type (0x%08x)\n", w)); | 
|  | return NULL; | 
|  | } | 
|  | /* no cores found, bail out */ | 
|  | if (sii->numcores == 0) { | 
|  | SI_ERROR(("si_doattach: could not find any cores\n")); | 
|  | return NULL; | 
|  | } | 
|  | /* bus/core/clk setup */ | 
|  | origidx = SI_CC_IDX; | 
|  | if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { | 
|  | SI_ERROR(("si_doattach: si_buscore_setup failed\n")); | 
|  | goto exit; | 
|  | } | 
|  |  | 
|  | /* assume current core is CC */ | 
|  | if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID || | 
|  | CHIPID(sih->chip) == BCM43235_CHIP_ID || | 
|  | CHIPID(sih->chip) == BCM43238_CHIP_ID) && | 
|  | (CHIPREV(sii->pub.chiprev) == 0))) { | 
|  |  | 
|  | if ((cc->chipstatus & CST43236_BP_CLK) != 0) { | 
|  | uint clkdiv; | 
|  | clkdiv = R_REG(osh, &cc->clkdiv); | 
|  | /* otp_clk_div is even number, 120/14 < 9mhz */ | 
|  | clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT); | 
|  | W_REG(osh, &cc->clkdiv, clkdiv); | 
|  | SI_ERROR(("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv)); | 
|  | } | 
|  | OSL_DELAY(10); | 
|  | } | 
|  |  | 
|  |  | 
|  | pvars = NULL; | 
|  |  | 
|  |  | 
|  |  | 
|  | if (sii->pub.ccrev >= 20) { | 
|  | cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); | 
|  | ASSERT(cc != NULL); | 
|  | W_REG(osh, &cc->gpiopullup, 0); | 
|  | W_REG(osh, &cc->gpiopulldown, 0); | 
|  | si_setcoreidx(sih, origidx); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | return (sii); | 
|  |  | 
|  | exit: | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* may be called with core in reset */ | 
|  | void | 
|  | si_detach(si_t *sih) | 
|  | { | 
|  | si_info_t *sii; | 
|  | 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 !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) | 
|  | if (sii != &ksii) | 
|  | #endif	/* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ | 
|  | MFREE(sii->osh, sii, sizeof(si_info_t)); | 
|  | } | 
|  |  | 
|  | void * | 
|  | si_osh(si_t *sih) | 
|  | { | 
|  | si_info_t *sii; | 
|  |  | 
|  | sii = SI_INFO(sih); | 
|  | return sii->osh; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | /* 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->coreid[sii->curidx]; | 
|  | } | 
|  |  | 
|  | void | 
|  | si_deregister_intr_callback(si_t *sih) | 
|  | { | 
|  | si_info_t *sii; | 
|  |  | 
|  | sii = SI_INFO(sih); | 
|  | sii->intrsoff_fn = NULL; | 
|  | } | 
|  |  | 
|  | uint | 
|  | si_intflag(si_t *sih) | 
|  | { | 
|  | si_info_t *sii = SI_INFO(sih); | 
|  |  | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | return sb_intflag(sih); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return R_REG(sii->osh, ((uint32 *)(uintptr) | 
|  | (sii->oob_router + OOB_STATUSA))); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | uint | 
|  | si_flag(si_t *sih) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | return sb_flag(sih); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return ai_flag(sih); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_flag(sih); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | si_setint(si_t *sih, int siflag) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | sb_setint(sih, siflag); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | ai_setint(sih, siflag); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | ub_setint(sih, siflag); | 
|  | else | 
|  | ASSERT(0); | 
|  | } | 
|  |  | 
|  | uint | 
|  | si_coreid(si_t *sih) | 
|  | { | 
|  | si_info_t *sii; | 
|  |  | 
|  | sii = SI_INFO(sih); | 
|  | return sii->coreid[sii->curidx]; | 
|  | } | 
|  |  | 
|  | uint | 
|  | si_coreidx(si_t *sih) | 
|  | { | 
|  | si_info_t *sii; | 
|  |  | 
|  | sii = SI_INFO(sih); | 
|  | return sii->curidx; | 
|  | } | 
|  |  | 
|  | /* 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->coreid[i] == coreid) | 
|  | coreunit++; | 
|  |  | 
|  | return (coreunit); | 
|  | } | 
|  |  | 
|  | uint | 
|  | si_corevendor(si_t *sih) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | return sb_corevendor(sih); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return ai_corevendor(sih); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_corevendor(sih); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool | 
|  | si_backplane64(si_t *sih) | 
|  | { | 
|  | return ((sih->cccaps & CC_CAP_BKPLN64) != 0); | 
|  | } | 
|  |  | 
|  | uint | 
|  | si_corerev(si_t *sih) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | return sb_corerev(sih); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return ai_corerev(sih); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_corerev(sih); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* 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->coreid[i] == coreid) { | 
|  | if (found == coreunit) | 
|  | return (i); | 
|  | found++; | 
|  | } | 
|  |  | 
|  | return (BADIDX); | 
|  | } | 
|  |  | 
|  | /* return list of found cores */ | 
|  | uint | 
|  | si_corelist(si_t *sih, uint coreid[]) | 
|  | { | 
|  | si_info_t *sii; | 
|  |  | 
|  | sii = SI_INFO(sih); | 
|  |  | 
|  | bcopy((uchar*)sii->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); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * 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 if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_setcoreidx(sih, idx); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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 if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_setcoreidx(sih, coreidx); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* 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); | 
|  |  | 
|  | if (SI_FAST(sii)) { | 
|  | /* Overloading the origidx variable to remember the coreid, | 
|  | * this works because the core ids cannot be confused with | 
|  | * core indices. | 
|  | */ | 
|  | *origidx = coreid; | 
|  | if (coreid == CC_CORE_ID) | 
|  | return (void *)CCREGS_FAST(sii); | 
|  | else if (coreid == sih->buscoretype) | 
|  | return (void *)PCIEREGS(sii); | 
|  | } | 
|  | INTR_OFF(sii, *intr_val); | 
|  | *origidx = sii->curidx; | 
|  | cc = si_setcore(sih, coreid, 0); | 
|  | ASSERT(cc != NULL); | 
|  |  | 
|  | return cc; | 
|  | } | 
|  |  | 
|  | /* 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); | 
|  | if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) | 
|  | return; | 
|  |  | 
|  | si_setcoreidx(sih, coreid); | 
|  | INTR_RESTORE(sii, intr_val); | 
|  | } | 
|  |  | 
|  | int | 
|  | si_numaddrspaces(si_t *sih) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | return sb_numaddrspaces(sih); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return ai_numaddrspaces(sih); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_numaddrspaces(sih); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | uint32 | 
|  | si_addrspace(si_t *sih, uint asidx) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | return sb_addrspace(sih, asidx); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return ai_addrspace(sih, asidx); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_addrspace(sih, asidx); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | uint32 | 
|  | si_addrspacesize(si_t *sih, uint asidx) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | return sb_addrspacesize(sih, asidx); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return ai_addrspacesize(sih, asidx); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_addrspacesize(sih, asidx); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | uint32 | 
|  | si_core_cflags(si_t *sih, uint32 mask, uint32 val) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | return sb_core_cflags(sih, mask, val); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return ai_core_cflags(sih, mask, val); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_core_cflags(sih, mask, val); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | sb_core_cflags_wo(sih, mask, val); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | ai_core_cflags_wo(sih, mask, val); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | ub_core_cflags_wo(sih, mask, val); | 
|  | else | 
|  | ASSERT(0); | 
|  | } | 
|  |  | 
|  | uint32 | 
|  | si_core_sflags(si_t *sih, uint32 mask, uint32 val) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | return sb_core_sflags(sih, mask, val); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return ai_core_sflags(sih, mask, val); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_core_sflags(sih, mask, val); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool | 
|  | si_iscoreup(si_t *sih) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | return sb_iscoreup(sih); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return ai_iscoreup(sih); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_iscoreup(sih); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | uint | 
|  | si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val) | 
|  | { | 
|  | /* only for AI back plane chips */ | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return (ai_wrap_reg(sih, offset, mask, val)); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | uint | 
|  | si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | return sb_corereg(sih, coreidx, regoff, mask, val); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | return ai_corereg(sih, coreidx, regoff, mask, val); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | return ub_corereg(sih, coreidx, regoff, mask, val); | 
|  | else { | 
|  | ASSERT(0); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | si_core_disable(si_t *sih, uint32 bits) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | sb_core_disable(sih, bits); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | ai_core_disable(sih, bits); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | ub_core_disable(sih, bits); | 
|  | } | 
|  |  | 
|  | void | 
|  | si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) | 
|  | { | 
|  | if (CHIPTYPE(sih->socitype) == SOCI_SB) | 
|  | sb_core_reset(sih, bits, resetbits); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_AI) | 
|  | ai_core_reset(sih, bits, resetbits); | 
|  | else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) | 
|  | ub_core_reset(sih, bits, resetbits); | 
|  | } | 
|  |  | 
|  | /* Run bist on current core. Caller needs to take care of core-specific bist hazards */ | 
|  | int | 
|  | si_corebist(si_t *sih) | 
|  | { | 
|  | uint32 cflags; | 
|  | int result = 0; | 
|  |  | 
|  | /* Read core control flags */ | 
|  | cflags = si_core_cflags(sih, 0, 0); | 
|  |  | 
|  | /* Set bist & fgc */ | 
|  | si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC)); | 
|  |  | 
|  | /* Wait for bist done */ | 
|  | SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); | 
|  |  | 
|  | if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR) | 
|  | result = BCME_ERROR; | 
|  |  | 
|  | /* Reset core control flags */ | 
|  | si_core_cflags(sih, 0xffff, cflags); | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static uint32 | 
|  | factor6(uint32 x) | 
|  | { | 
|  | switch (x) { | 
|  | case CC_F6_2:	return 2; | 
|  | case CC_F6_3:	return 3; | 
|  | case CC_F6_4:	return 4; | 
|  | case CC_F6_5:	return 5; | 
|  | case CC_F6_6:	return 6; | 
|  | case CC_F6_7:	return 7; | 
|  | default:	return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* 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) | 
|  | { | 
|  | uint32 n1, n2, clock, m1, m2, m3, mc; | 
|  |  | 
|  | n1 = n & CN_N1_MASK; | 
|  | n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT; | 
|  |  | 
|  | if (pll_type == PLL_TYPE6) { | 
|  | if (m & CC_T6_MMASK) | 
|  | return CC_T6_M1; | 
|  | else | 
|  | return CC_T6_M0; | 
|  | } else if ((pll_type == PLL_TYPE1) || | 
|  | (pll_type == PLL_TYPE3) || | 
|  | (pll_type == PLL_TYPE4) || | 
|  | (pll_type == PLL_TYPE7)) { | 
|  | n1 = factor6(n1); | 
|  | n2 += CC_F5_BIAS; | 
|  | } else if (pll_type == PLL_TYPE2) { | 
|  | n1 += CC_T2_BIAS; | 
|  | n2 += CC_T2_BIAS; | 
|  | ASSERT((n1 >= 2) && (n1 <= 7)); | 
|  | ASSERT((n2 >= 5) && (n2 <= 23)); | 
|  | } else if (pll_type == PLL_TYPE5) { | 
|  | return (100000000); | 
|  | } else | 
|  | ASSERT(0); | 
|  | /* PLL types 3 and 7 use BASE2 (25Mhz) */ | 
|  | if ((pll_type == PLL_TYPE3) || | 
|  | (pll_type == PLL_TYPE7)) { | 
|  | clock = CC_CLOCK_BASE2 * n1 * n2; | 
|  | } else | 
|  | clock = CC_CLOCK_BASE1 * n1 * n2; | 
|  |  | 
|  | if (clock == 0) | 
|  | return 0; | 
|  |  | 
|  | m1 = m & CC_M1_MASK; | 
|  | m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT; | 
|  | m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT; | 
|  | mc = (m & CC_MC_MASK) >> CC_MC_SHIFT; | 
|  |  | 
|  | if ((pll_type == PLL_TYPE1) || | 
|  | (pll_type == PLL_TYPE3) || | 
|  | (pll_type == PLL_TYPE4) || | 
|  | (pll_type == PLL_TYPE7)) { | 
|  | m1 = factor6(m1); | 
|  | if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3)) | 
|  | m2 += CC_F5_BIAS; | 
|  | else | 
|  | m2 = factor6(m2); | 
|  | m3 = factor6(m3); | 
|  |  | 
|  | switch (mc) { | 
|  | case CC_MC_BYPASS:	return (clock); | 
|  | case CC_MC_M1:		return (clock / m1); | 
|  | case CC_MC_M1M2:	return (clock / (m1 * m2)); | 
|  | case CC_MC_M1M2M3:	return (clock / (m1 * m2 * m3)); | 
|  | case CC_MC_M1M3:	return (clock / (m1 * m3)); | 
|  | default:		return (0); | 
|  | } | 
|  | } else { | 
|  | ASSERT(pll_type == PLL_TYPE2); | 
|  |  | 
|  | m1 += CC_T2_BIAS; | 
|  | m2 += CC_T2M2_BIAS; | 
|  | m3 += CC_T2_BIAS; | 
|  | ASSERT((m1 >= 2) && (m1 <= 7)); | 
|  | ASSERT((m2 >= 3) && (m2 <= 10)); | 
|  | ASSERT((m3 >= 2) && (m3 <= 7)); | 
|  |  | 
|  | if ((mc & CC_T2MC_M1BYP) == 0) | 
|  | clock /= m1; | 
|  | if ((mc & CC_T2MC_M2BYP) == 0) | 
|  | clock /= m2; | 
|  | if ((mc & CC_T2MC_M3BYP) == 0) | 
|  | clock /= m3; | 
|  |  | 
|  | return (clock); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* set chip watchdog reset timer to fire in 'ticks' */ | 
|  | void | 
|  | si_watchdog(si_t *sih, uint ticks) | 
|  | { | 
|  | uint nb, maxt; | 
|  |  | 
|  | if (PMUCTL_ENAB(sih)) { | 
|  |  | 
|  | if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && | 
|  | (CHIPREV(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); | 
|  | } | 
|  |  | 
|  | nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24); | 
|  | /* The mips compiler uses the sllv instruction, | 
|  | * so we specially handle the 32-bit case. | 
|  | */ | 
|  | if (nb == 32) | 
|  | maxt = 0xffffffff; | 
|  | else | 
|  | maxt = ((1 << nb) - 1); | 
|  |  | 
|  | if (ticks == 1) | 
|  | ticks = 2; | 
|  | else if (ticks > maxt) | 
|  | ticks = maxt; | 
|  |  | 
|  | si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks); | 
|  | } else { | 
|  | maxt = (1 << 28) - 1; | 
|  | if (ticks > maxt) | 
|  | ticks = maxt; | 
|  |  | 
|  | si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* trigger watchdog reset after ms milliseconds */ | 
|  | void | 
|  | si_watchdog_ms(si_t *sih, uint32 ms) | 
|  | { | 
|  | si_watchdog(sih, wd_msticks * ms); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | /* 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 */ | 
|  | uint32 | 
|  | si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority) | 
|  | { | 
|  | uint regoff; | 
|  |  | 
|  | regoff = 0; | 
|  |  | 
|  | /* gpios could be shared on router platforms | 
|  | * ignore reservation if it's high priority (e.g., test apps) | 
|  | */ | 
|  | if ((priority != GPIO_HI_PRIORITY) && | 
|  | (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { | 
|  | mask = priority ? (si_gpioreservation & mask) : | 
|  | ((si_gpioreservation | mask) & ~(si_gpioreservation)); | 
|  | val &= mask; | 
|  | } | 
|  |  | 
|  | regoff = OFFSETOF(chipcregs_t, gpiocontrol); | 
|  | return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); | 
|  | } | 
|  |  | 
|  | /* mask&set gpio output enable bits */ | 
|  | uint32 | 
|  | si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority) | 
|  | { | 
|  | uint regoff; | 
|  |  | 
|  | regoff = 0; | 
|  |  | 
|  | /* gpios could be shared on router platforms | 
|  | * ignore reservation if it's high priority (e.g., test apps) | 
|  | */ | 
|  | if ((priority != GPIO_HI_PRIORITY) && | 
|  | (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { | 
|  | mask = priority ? (si_gpioreservation & mask) : | 
|  | ((si_gpioreservation | mask) & ~(si_gpioreservation)); | 
|  | val &= mask; | 
|  | } | 
|  |  | 
|  | regoff = OFFSETOF(chipcregs_t, gpioouten); | 
|  | return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); | 
|  | } | 
|  |  | 
|  | /* mask&set gpio output bits */ | 
|  | uint32 | 
|  | si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) | 
|  | { | 
|  | uint regoff; | 
|  |  | 
|  | regoff = 0; | 
|  |  | 
|  | /* gpios could be shared on router platforms | 
|  | * ignore reservation if it's high priority (e.g., test apps) | 
|  | */ | 
|  | if ((priority != GPIO_HI_PRIORITY) && | 
|  | (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { | 
|  | mask = priority ? (si_gpioreservation & mask) : | 
|  | ((si_gpioreservation | mask) & ~(si_gpioreservation)); | 
|  | val &= mask; | 
|  | } | 
|  |  | 
|  | regoff = OFFSETOF(chipcregs_t, gpioout); | 
|  | return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); | 
|  | } | 
|  |  | 
|  | /* reserve one gpio */ | 
|  | uint32 | 
|  | si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) | 
|  | { | 
|  | si_info_t *sii; | 
|  |  | 
|  | sii = SI_INFO(sih); | 
|  |  | 
|  | /* only cores on SI_BUS share GPIO's and only applcation users need to | 
|  | * reserve/release GPIO | 
|  | */ | 
|  | if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { | 
|  | ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); | 
|  | return 0xffffffff; | 
|  | } | 
|  | /* make sure only one bit is set */ | 
|  | if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { | 
|  | ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); | 
|  | return 0xffffffff; | 
|  | } | 
|  |  | 
|  | /* already reserved */ | 
|  | if (si_gpioreservation & gpio_bitmask) | 
|  | return 0xffffffff; | 
|  | /* set reservation */ | 
|  | si_gpioreservation |= gpio_bitmask; | 
|  |  | 
|  | return si_gpioreservation; | 
|  | } | 
|  |  | 
|  | /* release one gpio */ | 
|  | /* | 
|  | * releasing the gpio doesn't change the current value on the GPIO last write value | 
|  | * persists till some one overwrites it | 
|  | */ | 
|  |  | 
|  | uint32 | 
|  | si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) | 
|  | { | 
|  | si_info_t *sii; | 
|  |  | 
|  | sii = SI_INFO(sih); | 
|  |  | 
|  | /* only cores on SI_BUS share GPIO's and only applcation users need to | 
|  | * reserve/release GPIO | 
|  | */ | 
|  | if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { | 
|  | ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); | 
|  | return 0xffffffff; | 
|  | } | 
|  | /* make sure only one bit is set */ | 
|  | if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { | 
|  | ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); | 
|  | return 0xffffffff; | 
|  | } | 
|  |  | 
|  | /* already released */ | 
|  | if (!(si_gpioreservation & gpio_bitmask)) | 
|  | return 0xffffffff; | 
|  |  | 
|  | /* clear reservation */ | 
|  | si_gpioreservation &= ~gpio_bitmask; | 
|  |  | 
|  | return si_gpioreservation; | 
|  | } | 
|  |  | 
|  | /* 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)); | 
|  | } | 
|  |  | 
|  | /* mask&set gpio interrupt polarity bits */ | 
|  | uint32 | 
|  | si_gpiointpolarity(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, gpiointpolarity); | 
|  | return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); | 
|  | } | 
|  |  | 
|  | /* 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)); | 
|  | } | 
|  |  | 
|  | /* 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 0xffffffff; | 
|  |  | 
|  | /* gpio led powersave reg */ | 
|  | return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); | 
|  | } | 
|  |  | 
|  | /* 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 0xffffffff; | 
|  |  | 
|  | 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 0xffffffff; | 
|  |  | 
|  | offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup)); | 
|  | return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); | 
|  | } | 
|  |  | 
|  | 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 0xffffffff; | 
|  |  | 
|  | 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 0xffffffff; | 
|  |  | 
|  | return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); | 
|  | } | 
|  |  | 
|  | void * | 
|  | si_gpio_handler_register(si_t *sih, uint32 event, | 
|  | bool level, gpio_handler_t cb, void *arg) | 
|  | { | 
|  | si_info_t *sii; | 
|  | gpioh_item_t *gi; | 
|  |  | 
|  | ASSERT(event); | 
|  | ASSERT(cb != NULL); | 
|  |  | 
|  | sii = SI_INFO(sih); | 
|  | if (sih->ccrev < 11) | 
|  | return NULL; | 
|  |  | 
|  | if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL) | 
|  | return NULL; | 
|  |  | 
|  | bzero(gi, sizeof(gpioh_item_t)); | 
|  | gi->event = event; | 
|  | gi->handler = cb; | 
|  | gi->arg = arg; | 
|  | gi->level = level; | 
|  |  | 
|  | gi->next = sii->gpioh_head; | 
|  | sii->gpioh_head = gi; | 
|  |  | 
|  | return (void *)(gi); | 
|  | } | 
|  |  | 
|  | void | 
|  | si_gpio_handler_unregister(si_t *sih, void *gpioh) | 
|  | { | 
|  | si_info_t *sii; | 
|  | gpioh_item_t *p, *n; | 
|  |  | 
|  | sii = SI_INFO(sih); | 
|  | if (sih->ccrev < 11) | 
|  | return; | 
|  |  | 
|  | ASSERT(sii->gpioh_head != NULL); | 
|  | if ((void*)sii->gpioh_head == gpioh) { | 
|  | sii->gpioh_head = sii->gpioh_head->next; | 
|  | MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); | 
|  | return; | 
|  | } else { | 
|  | p = sii->gpioh_head; | 
|  | n = p->next; | 
|  | while (n) { | 
|  | if ((void*)n == gpioh) { | 
|  | p->next = n->next; | 
|  | MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); | 
|  | return; | 
|  | } | 
|  | p = n; | 
|  | n = n->next; | 
|  | } | 
|  | } | 
|  |  | 
|  | ASSERT(0); /* Not found in list */ | 
|  | } | 
|  |  | 
|  | void | 
|  | si_gpio_handler_process(si_t *sih) | 
|  | { | 
|  | si_info_t *sii; | 
|  | 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; | 
|  | uint32 polarity = (h->level ? levelp : edgep) & h->event; | 
|  |  | 
|  | /* polarity bitval is opposite of status bitval */ | 
|  | if (status ^ polarity) | 
|  | h->handler(status, h->arg); | 
|  | } | 
|  | } | 
|  |  | 
|  | si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */ | 
|  | } | 
|  |  | 
|  | 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 0xffffffff; | 
|  |  | 
|  | offs = OFFSETOF(chipcregs_t, intmask); | 
|  | return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Return the size of the specified SOCRAM bank */ | 
|  | static uint | 
|  | socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 index, uint8 mem_type) | 
|  | { | 
|  | uint banksize, bankinfo; | 
|  | uint bankidx = index | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT); | 
|  |  | 
|  | ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM); | 
|  |  | 
|  | W_REG(sii->osh, ®s->bankidx, bankidx); | 
|  | bankinfo = R_REG(sii->osh, ®s->bankinfo); | 
|  | banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1); | 
|  | return banksize; | 
|  | } | 
|  |  | 
|  | void | 
|  | si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect) | 
|  | { | 
|  | si_info_t *sii; | 
|  | 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); | 
|  |  | 
|  | if (!set) | 
|  | *enable = *protect = 0; | 
|  |  | 
|  | /* 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); | 
|  | if (corerev >= 10) { | 
|  | uint32 extcinfo; | 
|  | uint8 nb; | 
|  | uint8 i; | 
|  | uint32 bankidx, bankinfo; | 
|  |  | 
|  | extcinfo = R_REG(sii->osh, ®s->extracoreinfo); | 
|  | nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); | 
|  | for (i = 0; i < nb; i++) { | 
|  | bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); | 
|  | W_REG(sii->osh, ®s->bankidx, bankidx); | 
|  | bankinfo = R_REG(sii->osh, ®s->bankinfo); | 
|  | if (set) { | 
|  | bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK; | 
|  | bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK; | 
|  | if (*enable) { | 
|  | bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT); | 
|  | if (*protect) | 
|  | bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT); | 
|  | } | 
|  | W_REG(sii->osh, ®s->bankinfo, bankinfo); | 
|  | } | 
|  | else if (i == 0) { | 
|  | if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) { | 
|  | *enable = 1; | 
|  | if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK) | 
|  | *protect = 1; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Return to previous state and core */ | 
|  | if (!wasup) | 
|  | si_core_disable(sih, 0); | 
|  | si_setcoreidx(sih, origidx); | 
|  |  | 
|  | done: | 
|  | INTR_RESTORE(sii, intr_val); | 
|  | } | 
|  |  | 
|  | bool | 
|  | si_socdevram_pkg(si_t *sih) | 
|  | { | 
|  | if (si_socdevram_size(sih) > 0) | 
|  | return TRUE; | 
|  | else | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | uint32 | 
|  | si_socdevram_size(si_t *sih) | 
|  | { | 
|  | si_info_t *sii; | 
|  | uint origidx; | 
|  | uint intr_val = 0; | 
|  | uint32 memsize = 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); | 
|  |  | 
|  | /* 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); | 
|  | if (corerev >= 10) { | 
|  | uint32 extcinfo; | 
|  | uint8 nb; | 
|  | uint8 i; | 
|  |  | 
|  | extcinfo = R_REG(sii->osh, ®s->extracoreinfo); | 
|  | nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); | 
|  | for (i = 0; i < nb; i++) | 
|  | memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); | 
|  | } | 
|  |  | 
|  | /* Return to previous state and core */ | 
|  | if (!wasup) | 
|  | si_core_disable(sih, 0); | 
|  | si_setcoreidx(sih, origidx); | 
|  |  | 
|  | done: | 
|  | INTR_RESTORE(sii, intr_val); | 
|  |  | 
|  | return memsize; | 
|  | } | 
|  |  | 
|  | /* 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 if ((corerev <= 7) || (corerev == 12)) { | 
|  | uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; | 
|  | uint bsz = (coreinfo & SRCI_SRBSZ_MASK); | 
|  | uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; | 
|  | if (lss != 0) | 
|  | nb --; | 
|  | memsize = nb * (1 << (bsz + SR_BSZ_BASE)); | 
|  | if (lss != 0) | 
|  | memsize += (1 << ((lss - 1) + SR_BSZ_BASE)); | 
|  | } else { | 
|  | uint8 i; | 
|  | uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; | 
|  | for (i = 0; i < nb; i++) | 
|  | memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); | 
|  | } | 
|  |  | 
|  | /* Return to previous state and core */ | 
|  | if (!wasup) | 
|  | si_core_disable(sih, 0); | 
|  | si_setcoreidx(sih, origidx); | 
|  |  | 
|  | done: | 
|  | INTR_RESTORE(sii, intr_val); | 
|  |  | 
|  | return memsize; | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | si_btcgpiowar(si_t *sih) | 
|  | { | 
|  | si_info_t *sii; | 
|  | 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 | 
|  | */ | 
|  | if (!(sih->cccaps & CC_CAP_UARTGPIO)) | 
|  | return; | 
|  |  | 
|  | /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */ | 
|  | INTR_OFF(sii, intr_val); | 
|  |  | 
|  | origidx = si_coreidx(sih); | 
|  |  | 
|  | cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); | 
|  | ASSERT(cc != NULL); | 
|  |  | 
|  | W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04); | 
|  |  | 
|  | /* restore the original index */ | 
|  | si_setcoreidx(sih, origidx); | 
|  |  | 
|  | INTR_RESTORE(sii, intr_val); | 
|  | } | 
|  |  | 
|  | uint | 
|  | si_pll_reset(si_t *sih) | 
|  | { | 
|  | uint err = 0; | 
|  |  | 
|  | return (err); | 
|  | } | 
|  |  | 
|  | /* 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)); | 
|  | if ((w & 0xFFFF) != VENDOR_BROADCOM) | 
|  | return TRUE; | 
|  | break; | 
|  | } | 
|  | return FALSE; | 
|  | } |