diff options
Diffstat (limited to 'openwrt/package/linux/kernel-source/drivers/net/hnd/sbutils.c')
-rw-r--r-- | openwrt/package/linux/kernel-source/drivers/net/hnd/sbutils.c | 2164 |
1 files changed, 0 insertions, 2164 deletions
diff --git a/openwrt/package/linux/kernel-source/drivers/net/hnd/sbutils.c b/openwrt/package/linux/kernel-source/drivers/net/hnd/sbutils.c deleted file mode 100644 index 1b221e0b3..000000000 --- a/openwrt/package/linux/kernel-source/drivers/net/hnd/sbutils.c +++ /dev/null @@ -1,2164 +0,0 @@ -/* - * Misc utility routines for accessing chip-specific features - * of the SiliconBackplane-based Broadcom chips. - * - * Copyright 2004, Broadcom Corporation - * All Rights Reserved. - * - * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY - * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM - * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. - * $Id$ - */ - -#include <typedefs.h> -#include <osl.h> -#include <bcmutils.h> -#include <bcmdevs.h> -#include <sbconfig.h> -#include <sbchipc.h> -#include <sbpci.h> -#include <pcicfg.h> -#include <sbpcmcia.h> -#include <sbextif.h> -#include <sbutils.h> -#include <bcmsrom.h> - -/* debug/trace */ -#define SB_ERROR(args) - -typedef uint32 (*sb_intrsoff_t)(void *intr_arg); -typedef void (*sb_intrsrestore_t)(void *intr_arg, uint32 arg); -typedef bool (*sb_intrsenabled_t)(void *intr_arg); - -/* misc sb info needed by some of the routines */ -typedef struct sb_info { - uint chip; /* chip number */ - uint chiprev; /* chip revision */ - uint chippkg; /* chip package option */ - uint boardtype; /* board type */ - uint boardvendor; /* board vendor id */ - uint bus; /* what bus type we are going through */ - - void *osh; /* osl os handle */ - void *sdh; /* bcmsdh handle */ - - void *curmap; /* current regs va */ - void *regs[SB_MAXCORES]; /* other regs va */ - - uint curidx; /* current core index */ - uint dev_coreid; /* the core provides driver functions */ - uint pciidx; /* pci core index */ - uint pcirev; /* pci core rev */ - - uint pcmciaidx; /* pcmcia core index */ - uint pcmciarev; /* pcmcia core rev */ - bool memseg; /* flag to toggle MEM_SEG register */ - - uint ccrev; /* chipc core rev */ - - uint gpioidx; /* gpio control core index */ - uint gpioid; /* gpio control coretype */ - - uint numcores; /* # discovered cores */ - uint coreid[SB_MAXCORES]; /* id of each core */ - - void *intr_arg; /* interrupt callback function arg */ - sb_intrsoff_t intrsoff_fn; /* function turns chip interrupts off */ - sb_intrsrestore_t intrsrestore_fn; /* function restore chip interrupts */ - sb_intrsenabled_t intrsenabled_fn; /* function to check if chip interrupts are enabled */ -} sb_info_t; - -/* local prototypes */ -static void* sb_doattach(sb_info_t *si, uint devid, void *osh, void *regs, uint bustype, void *sdh, char **vars, int *varsz); -static void sb_scan(sb_info_t *si); -static uint sb_corereg(void *sbh, uint coreidx, uint regoff, uint mask, uint val); -static uint _sb_coreidx(void *sbh); -static uint sb_findcoreidx(void *sbh, uint coreid, uint coreunit); -static uint sb_pcidev2chip(uint pcidev); -static uint sb_chip2numcores(uint chip); - -#define SB_INFO(sbh) (sb_info_t*)sbh -#define SET_SBREG(sbh, r, mask, val) W_SBREG((sbh), (r), ((R_SBREG((sbh), (r)) & ~(mask)) | (val))) -#define GOODCOREADDR(x) (((x) >= SB_ENUM_BASE) && ((x) <= SB_ENUM_LIM) && ISALIGNED((x), SB_CORE_SIZE)) -#define GOODREGS(regs) (regs && ISALIGNED(regs, SB_CORE_SIZE)) -#define REGS2SB(va) (sbconfig_t*) ((uint)(va) + SBCONFIGOFF) -#define GOODIDX(idx) (((uint)idx) < SB_MAXCORES) -#define BADIDX (SB_MAXCORES+1) - -#define R_SBREG(sbh, sbr) sb_read_sbreg((sbh), (sbr)) -#define W_SBREG(sbh, sbr, v) sb_write_sbreg((sbh), (sbr), (v)) -#define AND_SBREG(sbh, sbr, v) W_SBREG((sbh), (sbr), (R_SBREG((sbh), (sbr)) & (v))) -#define OR_SBREG(sbh, sbr, v) W_SBREG((sbh), (sbr), (R_SBREG((sbh), (sbr)) | (v))) - -/* - * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/ - * after core switching to avoid invalid register accesss inside ISR. - */ -#define INTR_OFF(si, intr_val) \ - if ((si)->intrsoff_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \ - intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); } -#define INTR_RESTORE(si, intr_val) \ - if ((si)->intrsrestore_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \ - (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); } - -/* power control defines */ -#define LPOMINFREQ 25000 /* low power oscillator min */ -#define LPOMAXFREQ 43000 /* low power oscillator max */ -#define XTALMINFREQ 19800000 /* 20mhz - 1% */ -#define XTALMAXFREQ 20200000 /* 20mhz + 1% */ -#define PCIMINFREQ 25000000 /* 25mhz */ -#define PCIMAXFREQ 34000000 /* 33mhz + fudge */ -#define SCC_DEF_DIV 0 /* default slow clock divider */ - -#define XTAL_ON_DELAY 1000 /* Xtal power on delay in us */ - -#define SCC_LOW2FAST_LIMIT 5000 /* turn on fast clock time, in unit of ms */ - - -static uint32 -sb_read_sbreg(void *sbh, volatile uint32 *sbr) -{ - sb_info_t *si; - uint8 tmp; - uint32 val, intr_val = 0; - - si = SB_INFO(sbh); - - /* - * compact flash only has 11 bits address, while we needs 12 bits address. - * MEM_SEG will be OR'd with other 11 bits address in hardware, - * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). - * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special - */ - if(si->memseg) { - INTR_OFF(si, intr_val); - tmp = 1; - OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1); - sbr = (uint32 *) (((uint32) sbr) & ~(1 << 11)); /* mask out bit 11*/ - } - - val = R_REG(sbr); - - if(si->memseg) { - tmp = 0; - OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1); - INTR_RESTORE(si, intr_val); - } - - return (val); -} - -static void -sb_write_sbreg(void *sbh, volatile uint32 *sbr, uint32 v) -{ - sb_info_t *si; - uint8 tmp; - volatile uint32 dummy; - uint32 intr_val = 0; - - si = SB_INFO(sbh); - - /* - * compact flash only has 11 bits address, while we needs 12 bits address. - * MEM_SEG will be OR'd with other 11 bits address in hardware, - * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). - * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special - */ - if(si->memseg) { - INTR_OFF(si, intr_val); - tmp = 1; - OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1); - sbr = (uint32 *) (((uint32) sbr) & ~(1 << 11)); /* mask out bit 11*/ - } - - if (si->bus == PCMCIA_BUS) { -#ifdef IL_BIGENDIAN - dummy = R_REG(sbr); - W_REG((volatile uint16 *)((uint32)sbr + 2), (uint16)((v >> 16) & 0xffff)); - dummy = R_REG(sbr); - W_REG((volatile uint16 *)sbr, (uint16)(v & 0xffff)); -#else - dummy = R_REG(sbr); - W_REG((volatile uint16 *)sbr, (uint16)(v & 0xffff)); - dummy = R_REG(sbr); - W_REG((volatile uint16 *)((uint32)sbr + 2), (uint16)((v >> 16) & 0xffff)); -#endif - } else - W_REG(sbr, v); - - if(si->memseg) { - tmp = 0; - OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1); - INTR_RESTORE(si, intr_val); - } -} - -/* - * Allocate a sb 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 - */ -void* -sb_attach(uint devid, void *osh, void *regs, uint bustype, void *sdh, char **vars, int *varsz) -{ - sb_info_t *si; - - /* alloc sb_info_t */ - if ((si = MALLOC(sizeof (sb_info_t))) == NULL) { - SB_ERROR(("sb_attach: malloc failed!\n")); - return (NULL); - } - - return (sb_doattach(si, devid, osh, regs, bustype, sdh, vars, varsz)); -} - -/* global kernel resource */ -static sb_info_t ksi; - -/* generic kernel variant of sb_attach() */ -void* -sb_kattach() -{ - uint32 *regs; - char *unused; - int varsz; - - if (ksi.curmap == NULL) { - uint32 cid; - - regs = (uint32 *)REG_MAP(SB_ENUM_BASE, SB_CORE_SIZE); - cid = R_REG((uint32 *)regs); - if (((cid & (CID_ID_MASK | CID_PKG_MASK)) == 0x00104712) && - ((cid & CID_REV_MASK) <= 0x00020000)) { - uint32 *scc, val; - - scc = (uint32 *)((uint32)regs + OFFSETOF(chipcregs_t, slow_clk_ctl)); - val = R_REG(scc); - SB_ERROR((" initial scc = 0x%x\n", val)); - val |= SCC_SS_XTAL; - W_REG(scc, val); - } - - sb_doattach(&ksi, BCM4710_DEVICE_ID, NULL, (void*)regs, - SB_BUS, NULL, &unused, &varsz); - } - - return &ksi; -} - -static void* -sb_doattach(sb_info_t *si, uint devid, void *osh, void *regs, uint bustype, void *sdh, char **vars, int *varsz) -{ - uint origidx; - chipcregs_t *cc; - uint32 w; - - ASSERT(GOODREGS(regs)); - - bzero((uchar*)si, sizeof (sb_info_t)); - - si->pciidx = si->gpioidx = BADIDX; - - si->osh = osh; - si->curmap = regs; - si->sdh = sdh; - - /* check to see if we are a sb core mimic'ing a pci core */ - if (bustype == PCI_BUS) { - if (OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof (uint32)) == 0xffffffff) - bustype = SB_BUS; - else - bustype = PCI_BUS; - } - - si->bus = bustype; - - if (si->bus == PCMCIA_BUS) - /* need to set memseg flag for CF card first before any sb registers access, - * such as the access inside sb_scan. the card type is detected and memseg - * flag is reassigned later after srom_var_init. there should be no effect - * for PCMCIA cards even though the memseg flag is set - */ - si->memseg = TRUE; - - /* kludge to enable the clock on the 4306 which lacks a slowclock */ - if (si->bus == PCI_BUS) - sb_pwrctl_xtal((void*)si, XTAL|PLL, ON); - - /* initialize current core index value */ - si->curidx = _sb_coreidx((void*)si); - if (si->curidx == BADIDX) - goto bad; - - /* keep and reuse the initial register mapping */ - origidx = si->curidx; - if (si->bus == SB_BUS) - si->regs[origidx] = regs; - - /* is core-0 a chipcommon core? */ - si->numcores = 1; - cc = (chipcregs_t*) sb_setcoreidx((void*)si, 0); - if (sb_coreid((void*)si) != SB_CC) - cc = NULL; - - /* determine chip id and rev */ - if (cc) { - /* chip common core found! */ - si->chip = R_REG(&cc->chipid) & CID_ID_MASK; - si->chiprev = (R_REG(&cc->chipid) & CID_REV_MASK) >> CID_REV_SHIFT; - si->chippkg = (R_REG(&cc->chipid) & CID_PKG_MASK) >> CID_PKG_SHIFT; - } else { - /* The only pcmcia chip without a chipcommon core is a 4301 */ - if (si->bus == PCMCIA_BUS) - devid = BCM4301_DEVICE_ID; - - /* no chip common core -- must convert device id to chip id */ - if ((si->chip = sb_pcidev2chip(devid)) == 0) { - SB_ERROR(("sb_attach: unrecognized device id 0x%04x\n", devid)); - goto bad; - } - } - - /* get chipcommon rev */ - si->ccrev = cc? sb_corerev((void*)si) : 0; - - /* determine numcores */ - if ((si->ccrev == 4) || (si->ccrev >= 6)) - si->numcores = (R_REG(&cc->chipid) & CID_CC_MASK) >> CID_CC_SHIFT; - else - si->numcores = sb_chip2numcores(si->chip); - - /* return to original core */ - sb_setcoreidx((void*)si, origidx); - - /* sanity checks */ - ASSERT(si->chip); - - /* scan for cores */ - sb_scan(si); - - /* initialize the vars after sb_scan so that the core rev. information - * collected by sb_scan is available for the srom_var_init. - */ - if (srom_var_init(si, si->bus, si->curmap, osh, vars, varsz)) { - SB_ERROR(("sb_attach: srom_var_init failed\n")); - goto bad; - } - - if (cc == NULL) { - /* - * The chip revision number is hardwired into all - * of the pci function config rev fields and is - * independent from the individual core revision numbers. - * For example, the "A0" silicon of each chip is chip rev 0. - * For PCMCIA we get it from the CIS instead. - */ - if (si->bus == PCMCIA_BUS) { - ASSERT(vars); - si->chiprev = getintvar(*vars, "chiprev"); - } else if (si->bus == PCI_BUS) { - w = OSL_PCI_READ_CONFIG(osh, PCI_CFG_REV, sizeof (uint32)); - si->chiprev = w & 0xff; - } else - si->chiprev = 0; - } - - if (si->bus == PCMCIA_BUS) { - w = getintvar(*vars, "regwindowsz"); - si->memseg = (w <= CFTABLE_REGWIN_2K) ? TRUE : FALSE; - } - - /* pci core is required */ - if (!GOODIDX(si->pciidx)) { - SB_ERROR(("sb_attach: pci core not found\n")); - goto bad; - } - - /* gpio control core is required */ - if (!GOODIDX(si->gpioidx)) { - SB_ERROR(("sb_attach: gpio control core not found\n")); - goto bad; - } - - /* get boardtype and boardrev */ - switch (si->bus) { - case PCI_BUS: - /* do a pci config read to get subsystem id and subvendor id */ - w = OSL_PCI_READ_CONFIG(osh, PCI_CFG_SVID, sizeof (uint32)); - si->boardvendor = w & 0xffff; - si->boardtype = (w >> 16) & 0xffff; - break; - - case PCMCIA_BUS: - case SDIO_BUS: - si->boardvendor = getintvar(*vars, "manfid"); - si->boardtype = getintvar(*vars, "prodid"); - break; - - case SB_BUS: - si->boardvendor = VENDOR_BROADCOM; - si->boardtype = 0xffff; - break; - } - - if (si->boardtype == 0) { - SB_ERROR(("sb_attach: unknown board type\n")); - ASSERT(si->boardtype); - } - - /* clear any previous epidiag-induced target abort */ - sb_taclear((void*)si); - - return ((void*)si); - -bad: - MFREE(si, sizeof (sb_info_t)); - return (NULL); -} - -uint -sb_coreid(void *sbh) -{ - sb_info_t *si; - sbconfig_t *sb; - - si = SB_INFO(sbh); - sb = REGS2SB(si->curmap); - - return ((R_SBREG(sbh, &(sb)->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT); -} - -uint -sb_coreidx(void *sbh) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - return (si->curidx); -} - -/* return current index of core */ -static uint -_sb_coreidx(void *sbh) -{ - sb_info_t *si; - sbconfig_t *sb; - uint32 sbaddr = 0; - - si = SB_INFO(sbh); - ASSERT(si); - - switch (si->bus) { - case SB_BUS: - sb = REGS2SB(si->curmap); - sbaddr = sb_base(R_SBREG(sbh, &sb->sbadmatch0)); - break; - - case PCI_BUS: - sbaddr = OSL_PCI_READ_CONFIG(si->osh, PCI_BAR0_WIN, sizeof (uint32)); - break; - - case PCMCIA_BUS: { - uint8 tmp; - - OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_ADDR0, &tmp, 1); - sbaddr = (uint)tmp << 12; - OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_ADDR1, &tmp, 1); - sbaddr |= (uint)tmp << 16; - OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_ADDR2, &tmp, 1); - sbaddr |= (uint)tmp << 24; - break; - } - default: - ASSERT(0); - } - - if (!GOODCOREADDR(sbaddr)) - return BADIDX; - - return ((sbaddr - SB_ENUM_BASE) / SB_CORE_SIZE); -} - -uint -sb_corevendor(void *sbh) -{ - sb_info_t *si; - sbconfig_t *sb; - - si = SB_INFO(sbh); - sb = REGS2SB(si->curmap); - - return ((R_SBREG(sbh, &(sb)->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT); -} - -uint -sb_corerev(void *sbh) -{ - sb_info_t *si; - sbconfig_t *sb; - - si = SB_INFO(sbh); - sb = REGS2SB(si->curmap); - - return (R_SBREG(sbh, &(sb)->sbidhigh) & SBIDH_RC_MASK); -} - -#define SBTML_ALLOW (SBTML_PE | SBTML_FGC | SBTML_FL_MASK) - -/* set/clear sbtmstatelow core-specific flags */ -uint32 -sb_coreflags(void *sbh, uint32 mask, uint32 val) -{ - sb_info_t *si; - sbconfig_t *sb; - uint32 w; - - si = SB_INFO(sbh); - sb = REGS2SB(si->curmap); - - ASSERT((val & ~mask) == 0); - ASSERT((mask & ~SBTML_ALLOW) == 0); - - /* mask and set */ - if (mask || val) { - w = (R_SBREG(sbh, &sb->sbtmstatelow) & ~mask) | val; - W_SBREG(sbh, &sb->sbtmstatelow, w); - } - - /* return the new value */ - return (R_SBREG(sbh, &sb->sbtmstatelow) & SBTML_ALLOW); -} - -/* set/clear sbtmstatehigh core-specific flags */ -uint32 -sb_coreflagshi(void *sbh, uint32 mask, uint32 val) -{ - sb_info_t *si; - sbconfig_t *sb; - uint32 w; - - si = SB_INFO(sbh); - sb = REGS2SB(si->curmap); - - ASSERT((val & ~mask) == 0); - ASSERT((mask & ~SBTMH_FL_MASK) == 0); - - /* mask and set */ - if (mask || val) { - w = (R_SBREG(sbh, &sb->sbtmstatehigh) & ~mask) | val; - W_SBREG(sbh, &sb->sbtmstatehigh, w); - } - - /* return the new value */ - return (R_SBREG(sbh, &sb->sbtmstatehigh) & SBTMH_FL_MASK); -} - -bool -sb_iscoreup(void *sbh) -{ - sb_info_t *si; - sbconfig_t *sb; - - si = SB_INFO(sbh); - sb = REGS2SB(si->curmap); - - return ((R_SBREG(sbh, &(sb)->sbtmstatelow) & (SBTML_RESET | SBTML_REJ | SBTML_CLK)) == SBTML_CLK); -} - -/* - * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, - * switch back to the original core, and return the new value. - */ -static uint -sb_corereg(void *sbh, uint coreidx, uint regoff, uint mask, uint val) -{ - sb_info_t *si; - uint origidx; - uint32 *r; - uint w; - uint intr_val = 0; - - ASSERT(GOODIDX(coreidx)); - ASSERT(regoff < SB_CORE_SIZE); - ASSERT((val & ~mask) == 0); - - si = SB_INFO(sbh); - - INTR_OFF(si, intr_val); - - /* save current core index */ - origidx = sb_coreidx(sbh); - - /* switch core */ - r = (uint32*) ((uint) sb_setcoreidx(sbh, coreidx) + regoff); - - /* mask and set */ - if (mask || val) { - if (regoff >= SBCONFIGOFF) { - w = (R_SBREG(sbh, r) & ~mask) | val; - W_SBREG(sbh, r, w); - } else { - w = (R_REG(r) & ~mask) | val; - W_REG(r, w); - } - } - - /* readback */ - if (regoff >= SBCONFIGOFF) - w = R_SBREG(sbh, r); - else - w = R_REG(r); - - /* restore core index */ - if (origidx != coreidx) - sb_setcoreidx(sbh, origidx); - - INTR_RESTORE(si, intr_val); - return (w); -} - -/* scan the sb enumerated space to identify all cores */ -static void -sb_scan(sb_info_t *si) -{ - void *sbh; - uint origidx; - uint i; - - sbh = (void*) si; - - /* numcores should already be set */ - ASSERT((si->numcores > 0) && (si->numcores <= SB_MAXCORES)); - - /* save current core index */ - origidx = sb_coreidx(sbh); - - si->pciidx = si->gpioidx = BADIDX; - - for (i = 0; i < si->numcores; i++) { - sb_setcoreidx(sbh, i); - si->coreid[i] = sb_coreid(sbh); - - if (si->coreid[i] == SB_PCI) { - si->pciidx = i; - si->pcirev = sb_corerev(sbh); - - } else if (si->coreid[i] == SB_PCMCIA) { - si->pcmciaidx = i; - si->pcmciarev = sb_corerev(sbh); - } - } - - /* - * Find the gpio "controlling core" type and index. - * Precedence: - * - if there's a chip common core - use that - * - else if there's a pci core (rev >= 2) - use that - * - else there had better be an extif core (4710 only) - */ - if (GOODIDX(sb_findcoreidx(sbh, SB_CC, 0))) { - si->gpioidx = sb_findcoreidx(sbh, SB_CC, 0); - si->gpioid = SB_CC; - } else if (GOODIDX(si->pciidx) && (si->pcirev >= 2)) { - si->gpioidx = si->pciidx; - si->gpioid = SB_PCI; - } else if (sb_findcoreidx(sbh, SB_EXTIF, 0)) { - si->gpioidx = sb_findcoreidx(sbh, SB_EXTIF, 0); - si->gpioid = SB_EXTIF; - } - - /* return to original core index */ - sb_setcoreidx(sbh, origidx); -} - -/* may be called with core in reset */ -void -sb_detach(void *sbh) -{ - sb_info_t *si; - uint idx; - - si = SB_INFO(sbh); - - if (si == NULL) - return; - - if (si->bus == SB_BUS) - for (idx = 0; idx < SB_MAXCORES; idx++) - if (si->regs[idx]) { - REG_UNMAP(si->regs[idx]); - si->regs[idx] = NULL; - } - - MFREE(si, sizeof (sb_info_t)); -} - -/* use pci dev id to determine chip id for chips not having a chipcommon core */ -static uint -sb_pcidev2chip(uint pcidev) -{ - if ((pcidev >= BCM4710_DEVICE_ID) && (pcidev <= BCM47XX_USB_ID)) - return (BCM4710_DEVICE_ID); - if ((pcidev >= BCM4610_DEVICE_ID) && (pcidev <= BCM4610_USB_ID)) - return (BCM4610_DEVICE_ID); - if ((pcidev >= BCM4402_DEVICE_ID) && (pcidev <= BCM4402_V90_ID)) - return (BCM4402_DEVICE_ID); - if ((pcidev >= BCM4307_V90_ID) && (pcidev <= BCM4307_D11B_ID)) - return (BCM4307_DEVICE_ID); - if (pcidev == BCM4301_DEVICE_ID) - return (BCM4301_DEVICE_ID); - - return (0); -} - -/* convert chip number to number of i/o cores */ -static uint -sb_chip2numcores(uint chip) -{ - if (chip == 0x4710) - return (9); - if (chip == 0x4610) - return (9); - if (chip == 0x4402) - return (3); - if ((chip == 0x4307) || (chip == 0x4301)) - return (5); - if (chip == 0x4310) - return (8); - if (chip == 0x4306) /* < 4306c0 */ - return (6); - if (chip == 0x4704) - return (9); - if (chip == 0x5365) - return (7); - - SB_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", chip)); - ASSERT(0); - return (1); -} - -/* return index of coreid or BADIDX if not found */ -static uint -sb_findcoreidx(void *sbh, uint coreid, uint coreunit) -{ - sb_info_t *si; - uint found; - uint i; - - si = SB_INFO(sbh); - found = 0; - - for (i = 0; i < si->numcores; i++) - if (si->coreid[i] == coreid) { - if (found == coreunit) - return (i); - found++; - } - - return (BADIDX); -} - -/* - * this function changes logical "focus" to the indiciated core, - * must be called with interrupt off. - * Moreover, callers should keep interrupts off during switching out of and back to d11 core - */ -void* -sb_setcoreidx(void *sbh, uint coreidx) -{ - sb_info_t *si; - uint32 sbaddr; - uint8 tmp; - - si = SB_INFO(sbh); - - if (coreidx >= si->numcores) - return (NULL); - - /* - * If the user has provided an interrupt mask enabled function, - * then assert interrupts are disabled before switching the core. - */ - ASSERT((si->intrsenabled_fn == NULL) || !(*(si)->intrsenabled_fn)((si)->intr_arg)); - - sbaddr = SB_ENUM_BASE + (coreidx * SB_CORE_SIZE); - - switch (si->bus) { - case SB_BUS: - /* map new one */ - if (!si->regs[coreidx]) { - si->regs[coreidx] = (void*)REG_MAP(sbaddr, SB_CORE_SIZE); - ASSERT(GOODREGS(si->regs[coreidx])); - } - si->curmap = si->regs[coreidx]; - break; - - case PCI_BUS: - /* point bar0 window */ - OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, 4, sbaddr); - break; - - case PCMCIA_BUS: - tmp = (sbaddr >> 12) & 0x0f; - OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_ADDR0, &tmp, 1); - tmp = (sbaddr >> 16) & 0xff; - OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_ADDR1, &tmp, 1); - tmp = (sbaddr >> 24) & 0xff; - OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_ADDR2, &tmp, 1); - break; - } - - si->curidx = coreidx; - - return (si->curmap); -} - -/* - * this function changes logical "focus" to the indiciated core, - * must be called with interrupt off. - * Moreover, callers should keep interrupts off during switching out of and back to d11 core - */ -void* -sb_setcore(void *sbh, uint coreid, uint coreunit) -{ - sb_info_t *si; - uint idx; - - si = SB_INFO(sbh); - - idx = sb_findcoreidx(sbh, coreid, coreunit); - if (!GOODIDX(idx)) - return (NULL); - - return (sb_setcoreidx(sbh, idx)); -} - -/* return chip number */ -uint -sb_chip(void *sbh) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - return (si->chip); -} - -/* return chip revision number */ -uint -sb_chiprev(void *sbh) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - return (si->chiprev); -} - -/* return chip common revision number */ -uint -sb_chipcrev(void *sbh) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - return (si->ccrev); -} - -/* return chip package option */ -uint -sb_chippkg(void *sbh) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - return (si->chippkg); -} - -/* return PCI core rev. */ -uint -sb_pcirev(void *sbh) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - return (si->pcirev); -} - -/* return PCMCIA core rev. */ -uint -sb_pcmciarev(void *sbh) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - return (si->pcmciarev); -} - -/* return board vendor id */ -uint -sb_boardvendor(void *sbh) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - return (si->boardvendor); -} - -/* return boardtype */ -uint -sb_boardtype(void *sbh) -{ - sb_info_t *si; - char *var; - - si = SB_INFO(sbh); - - if (si->bus == SB_BUS && si->boardtype == 0xffff) { - /* boardtype format is a hex string */ - si->boardtype = getintvar(NULL, "boardtype"); - - /* backward compatibility for older boardtype string format */ - if ((si->boardtype == 0) && (var = getvar(NULL, "boardtype"))) { - if (!strcmp(var, "bcm94710dev")) - si->boardtype = BCM94710D_BOARD; - else if (!strcmp(var, "bcm94710ap")) - si->boardtype = BCM94710AP_BOARD; - else if (!strcmp(var, "bcm94310u")) - si->boardtype = BCM94310U_BOARD; - else if (!strcmp(var, "bu4711")) - si->boardtype = BU4711_BOARD; - else if (!strcmp(var, "bu4710")) - si->boardtype = BU4710_BOARD; - else if (!strcmp(var, "bcm94702mn")) - si->boardtype = BCM94702MN_BOARD; - else if (!strcmp(var, "bcm94710r1")) - si->boardtype = BCM94710R1_BOARD; - else if (!strcmp(var, "bcm94710r4")) - si->boardtype = BCM94710R4_BOARD; - else if (!strcmp(var, "bcm94702cpci")) - si->boardtype = BCM94702CPCI_BOARD; - else if (!strcmp(var, "bcm95380_rr")) - si->boardtype = BCM95380RR_BOARD; - } - } - - return (si->boardtype); -} - -/* return board bus style */ -uint -sb_boardstyle(void *sbh) -{ - sb_info_t *si; - uint16 w; - - si = SB_INFO(sbh); - - if (si->bus == PCMCIA_BUS) - return (BOARDSTYLE_PCMCIA); - - if (si->bus == SB_BUS) - return (BOARDSTYLE_SOC); - - /* bus is PCI */ - - if (OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_CIS, sizeof (uint32)) != 0) - return (BOARDSTYLE_CARDBUS); - - if ((srom_read(si->bus, si->curmap, si->osh, (SPROM_SIZE - 1) * 2, 2, &w) == 0) && - (w == 0x0313)) - return (BOARDSTYLE_CARDBUS); - - return (BOARDSTYLE_PCI); -} - -/* return boolean if sbh device is in pci hostmode or client mode */ -uint -sb_bus(void *sbh) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - return (si->bus); -} - -/* return list of found cores */ -uint -sb_corelist(void *sbh, uint coreid[]) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - - bcopy((uchar*)si->coreid, (uchar*)coreid, (si->numcores * sizeof (uint))); - return (si->numcores); -} - -/* return current register mapping */ -void * -sb_coreregs(void *sbh) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - ASSERT(GOODREGS(si->curmap)); - - return (si->curmap); -} - -/* traverse all cores to find and clear source of serror */ -static void -sb_serr_clear(void *sbh) -{ - sb_info_t *si; - sbconfig_t *sb; - uint origidx; - uint i, intr_val = 0; - void * corereg = NULL; - - si = SB_INFO(sbh); - - INTR_OFF(si, intr_val); - origidx = sb_coreidx(sbh); - - for (i = 0; i < si->numcores; i++) { - corereg = sb_setcoreidx(sbh, i); - if (NULL != corereg) { - sb = REGS2SB(corereg); - if ((si->chip == BCM4317_DEVICE_ID) && (si->chiprev == 0)) { - W_SBREG(sbh, &sb->sbtmstatehigh, 0); - } else { - if ((R_SBREG(sbh, &sb->sbtmstatehigh)) & SBTMH_SERR) { - AND_SBREG(sbh, &sb->sbtmstatehigh, ~SBTMH_SERR); - SB_ERROR(("sb_serr_clear: SError at core 0x%x\n", sb_coreid(sbh))); - } - } - } - } - - sb_setcoreidx(sbh, origidx); - INTR_RESTORE(si, intr_val); -} - -/* check if any inband, outband or timeout errors has happened and clear them */ -/* !! must be called with chip clk on */ -bool -sb_taclear(void *sbh) -{ - sb_info_t *si; - sbconfig_t *sb; - uint origidx; - uint intr_val = 0; - bool rc = FALSE; - uint32 inband = 0, serror = 0, timeout = 0; - void *corereg = NULL; - volatile uint32 imstate, tmstate; - - si = SB_INFO(sbh); - - if (si->bus == PCI_BUS) { - volatile uint32 stcmd; - - /* inband error is Target abort for PCI */ - stcmd = OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_CMD, sizeof(uint32)); - inband = stcmd & PCI_CFG_CMD_STAT_TA; - if (inband) - OSL_PCI_WRITE_CONFIG(si->osh, PCI_CFG_CMD, sizeof(uint32), stcmd); - - /* serror */ - stcmd = OSL_PCI_READ_CONFIG(si->osh, PCI_INT_STATUS, sizeof(uint32)); - serror = stcmd & PCI_SBIM_STATUS_SERR; - if (serror) { - sb_serr_clear(sbh); - OSL_PCI_WRITE_CONFIG(si->osh, PCI_INT_STATUS, sizeof(uint32), stcmd); - } - - /* timeout */ - imstate = sb_corereg(sbh, si->pciidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbimstate), 0, 0); - if ((imstate != 0xffffffff) && (imstate & (SBIM_IBE | SBIM_TO))) { - sb_corereg(sbh, si->pciidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbimstate), ~0, - (imstate & ~(SBIM_IBE | SBIM_TO))); - /* inband = imstate & SBIM_IBE; same as TA above */ - timeout = imstate & SBIM_TO; - } - - } else if (si->bus == PCMCIA_BUS) { - - INTR_OFF(si, intr_val); - origidx = sb_coreidx(sbh); - - corereg = sb_setcore(sbh, SB_PCMCIA, 0); - if (NULL != corereg) { - sb = REGS2SB(corereg); - - imstate = R_SBREG(sbh, &sb->sbimstate); - /* handle surprise removal */ - if ((imstate != 0xffffffff) && (imstate & (SBIM_IBE | SBIM_TO))) { - AND_SBREG(sbh, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); - inband = imstate & SBIM_IBE; - timeout = imstate & SBIM_TO; - } - tmstate = R_SBREG(sbh, &sb->sbtmstatehigh); - if ((tmstate != 0xffffffff) && (tmstate & SBTMH_INT_STATUS)) { - if (!inband) { - serror = 1; - sb_serr_clear(sbh); - } - OR_SBREG(sbh, &sb->sbtmstatelow, SBTML_INT_ACK); - AND_SBREG(sbh, &sb->sbtmstatelow, ~SBTML_INT_ACK); - } - } - sb_setcoreidx(sbh, origidx); - INTR_RESTORE(si, intr_val); - - } else if (si->bus == SDIO_BUS) { - - INTR_OFF(si, intr_val); - origidx = sb_coreidx(sbh); - - corereg = sb_setcore(sbh, SB_PCMCIA, 0); - if (NULL != corereg) { - sb = REGS2SB(corereg); - - imstate = R_SBREG(sbh, &sb->sbimstate); - if ((imstate != 0xffffffff) && (imstate & (SBIM_IBE | SBIM_TO))) { - AND_SBREG(sbh, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); - /* inband = imstate & SBIM_IBE; cmd error */ - timeout = imstate & SBIM_TO; - } - tmstate = R_SBREG(sbh, &sb->sbtmstatehigh); - if ((tmstate != 0xffffffff) && (tmstate & SBTMH_INT_STATUS)) { - sb_serr_clear(sbh); - serror = 1; - OR_SBREG(sbh, &sb->sbtmstatelow, SBTML_INT_ACK); - AND_SBREG(sbh, &sb->sbtmstatelow, ~SBTML_INT_ACK); - } - } - - sb_setcoreidx(sbh, origidx); - INTR_RESTORE(si, intr_val); - } - - if ((inband | timeout | serror) != 0) { - rc = TRUE; - SB_ERROR(("sb_taclear: inband 0x%x, serror 0x%x, timeout 0x%x!\n", inband, serror, timeout)); - } - - return (rc); -} - -/* do buffered registers update */ -void -sb_commit(void *sbh) -{ - sb_info_t *si; - sbpciregs_t *pciregs; - uint origidx; - uint intr_val = 0; - - si = SB_INFO(sbh); - - origidx = si->curidx; - ASSERT(GOODIDX(origidx)); - - INTR_OFF(si, intr_val); - /* switch over to pci core */ - pciregs = (sbpciregs_t*) sb_setcore(sbh, SB_PCI, 0); - - /* do the buffer registers update */ - W_REG(&pciregs->bcastaddr, SB_COMMIT); - W_REG(&pciregs->bcastdata, 0x0); - - /* restore core index */ - sb_setcoreidx(sbh, origidx); - INTR_RESTORE(si, intr_val); -} - -/* reset and re-enable a core */ -void -sb_core_reset(void *sbh, uint32 bits) -{ - sb_info_t *si; - sbconfig_t *sb; - volatile uint32 dummy; - - si = SB_INFO(sbh); - ASSERT(GOODREGS(si->curmap)); - sb = REGS2SB(si->curmap); - - /* - * Must do the disable sequence first to work for arbitrary current core state. - */ - sb_core_disable(sbh, bits); - - /* - * Now do the initialization sequence. - */ - - /* set reset while enabling the clock and forcing them on throughout the core */ - W_SBREG(sbh, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | SBTML_RESET | bits)); - dummy = R_SBREG(sbh, &sb->sbtmstatelow); - - if (sb_coreid(sbh) == SB_ILINE100) { - bcm_mdelay(50); - } else { - OSL_DELAY(1); - } - - if (R_SBREG(sbh, &sb->sbtmstatehigh) & SBTMH_SERR) { - W_SBREG(sbh, &sb->sbtmstatehigh, 0); - } - if ((dummy = R_SBREG(sbh, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) { - AND_SBREG(sbh, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); - } - - /* clear reset and allow it to propagate throughout the core */ - W_SBREG(sbh, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | bits)); - dummy = R_SBREG(sbh, &sb->sbtmstatelow); - OSL_DELAY(1); - - /* leave clock enabled */ - W_SBREG(sbh, &sb->sbtmstatelow, (SBTML_CLK | bits)); - dummy = R_SBREG(sbh, &sb->sbtmstatelow); - OSL_DELAY(1); -} - -void -sb_core_tofixup(void *sbh) -{ - sb_info_t *si; - sbconfig_t *sb; - - si = SB_INFO(sbh); - - if (si->pcirev >= 5) - return; - - ASSERT(GOODREGS(si->curmap)); - sb = REGS2SB(si->curmap); - - if (si->bus == SB_BUS) { - SET_SBREG(sbh, &sb->sbimconfiglow, - SBIMCL_RTO_MASK | SBIMCL_STO_MASK, - (0x5 << SBIMCL_RTO_SHIFT) | 0x3); - } else { - if (sb_coreid(sbh) == SB_PCI) { - SET_SBREG(sbh, &sb->sbimconfiglow, - SBIMCL_RTO_MASK | SBIMCL_STO_MASK, - (0x3 << SBIMCL_RTO_SHIFT) | 0x2); - } else { - SET_SBREG(sbh, &sb->sbimconfiglow, (SBIMCL_RTO_MASK | SBIMCL_STO_MASK), 0); - } - } - - sb_commit(sbh); -} - -void -sb_core_disable(void *sbh, uint32 bits) -{ - sb_info_t *si; - volatile uint32 dummy; - sbconfig_t *sb; - - si = SB_INFO(sbh); - - ASSERT(GOODREGS(si->curmap)); - sb = REGS2SB(si->curmap); - - /* must return if core is already in reset */ - if (R_SBREG(sbh, &sb->sbtmstatelow) & SBTML_RESET) - return; - - /* put into reset and return if clocks are not enabled */ - if ((R_SBREG(sbh, &sb->sbtmstatelow) & SBTML_CLK) == 0) - goto disable; - - /* set the reject bit */ - W_SBREG(sbh, &sb->sbtmstatelow, (SBTML_CLK | SBTML_REJ)); - - /* spin until reject is set */ - while ((R_SBREG(sbh, &sb->sbtmstatelow) & SBTML_REJ) == 0) - OSL_DELAY(1); - - /* spin until sbtmstatehigh.busy is clear */ - while (R_SBREG(sbh, &sb->sbtmstatehigh) & SBTMH_BUSY) - OSL_DELAY(1); - - /* set reset and reject while enabling the clocks */ - W_SBREG(sbh, &sb->sbtmstatelow, (bits | SBTML_FGC | SBTML_CLK | SBTML_REJ | SBTML_RESET)); - dummy = R_SBREG(sbh, &sb->sbtmstatelow); - OSL_DELAY(10); - - disable: - /* leave reset and reject asserted */ - W_SBREG(sbh, &sb->sbtmstatelow, (bits | SBTML_REJ | SBTML_RESET)); - OSL_DELAY(1); -} - -void -sb_watchdog(void *sbh, uint ticks) -{ - sb_info_t *si = SB_INFO(sbh); - - /* instant NMI */ - switch (si->gpioid) { - case SB_CC: - sb_corereg(sbh, si->gpioidx, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); - break; - case SB_EXTIF: - sb_corereg(sbh, si->gpioidx, OFFSETOF(extifregs_t, watchdog), ~0, ticks); - break; - } -} - -/* initialize the pcmcia core */ -void -sb_pcmcia_init(void *sbh) -{ - sb_info_t *si; - uint8 cor; - - si = SB_INFO(sbh); - - /* enable d11 mac interrupts */ - if (si->chip == BCM4301_DEVICE_ID) { - /* Have to use FCR2 in 4301 */ - OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_FCR2 + PCMCIA_COR, &cor, 1); - cor |= COR_IRQEN | COR_FUNEN; - OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_FCR2 + PCMCIA_COR, &cor, 1); - } else { - OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_FCR0 + PCMCIA_COR, &cor, 1); - cor |= COR_IRQEN | COR_FUNEN; - OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_FCR0 + PCMCIA_COR, &cor, 1); - } - -} - - -/* - * Configure the pci core for pci client (NIC) action - * and get appropriate dma offset value. - * coremask is the bitvec of cores by index to be enabled. - */ -void -sb_pci_setup(void *sbh, uint32 *dmaoffset, uint coremask) -{ - sb_info_t *si; - sbconfig_t *sb; - sbpciregs_t *pciregs; - uint32 sbflag; - uint32 w; - uint idx; - - si = SB_INFO(sbh); - - if (dmaoffset) - *dmaoffset = 0; - - /* if not pci bus, we're done */ - if (si->bus != PCI_BUS) - return; - - ASSERT(si->pciidx); - - /* get current core index */ - idx = si->curidx; - - /* we interrupt on this backplane flag number */ - ASSERT(GOODREGS(si->curmap)); - sb = REGS2SB(si->curmap); - sbflag = R_SBREG(sbh, &sb->sbtpsflag) & SBTPS_NUM0_MASK; - - /* switch over to pci core */ - pciregs = (sbpciregs_t*) sb_setcoreidx(sbh, si->pciidx); - sb = REGS2SB(pciregs); - - /* - * Enable sb->pci interrupts. Assume - * PCI rev 2.3 support was added in pci core rev 6 and things changed.. - */ - if (si->pcirev < 6) { - /* set sbintvec bit for our flag number */ - OR_SBREG(sbh, &sb->sbintvec, (1 << sbflag)); - } else { - /* pci config write to set this core bit in PCIIntMask */ - w = OSL_PCI_READ_CONFIG(si->osh, PCI_INT_MASK, sizeof(uint32)); - w |= (coremask << PCI_SBIM_SHIFT); - OSL_PCI_WRITE_CONFIG(si->osh, PCI_INT_MASK, sizeof(uint32), w); - } - - /* enable prefetch and bursts for sonics-to-pci translation 2 */ - OR_REG(&pciregs->sbtopci2, (SBTOPCI_PREF|SBTOPCI_BURST)); - - if (si->pcirev < 5) { - SET_SBREG(sbh, &sb->sbimconfiglow, SBIMCL_RTO_MASK | SBIMCL_STO_MASK, - (0x3 << SBIMCL_RTO_SHIFT) | 0x2); - sb_commit(sbh); - } - - /* switch back to previous core */ - sb_setcoreidx(sbh, idx); - - /* use large sb pci dma window */ - if (dmaoffset) - *dmaoffset = SB_PCI_DMA; -} - -uint32 -sb_base(uint32 admatch) -{ - uint32 base; - uint type; - - type = admatch & SBAM_TYPE_MASK; - ASSERT(type < 3); - - base = 0; - - if (type == 0) { - base = admatch & SBAM_BASE0_MASK; - } else if (type == 1) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - base = admatch & SBAM_BASE1_MASK; - } else if (type == 2) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - base = admatch & SBAM_BASE2_MASK; - } - - return (base); -} - -uint32 -sb_size(uint32 admatch) -{ - uint32 size; - uint type; - - type = admatch & SBAM_TYPE_MASK; - ASSERT(type < 3); - - size = 0; - - if (type == 0) { - size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1); - } else if (type == 1) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1); - } else if (type == 2) { - ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ - size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1); - } - - return (size); -} - -/* return the core-type instantiation # of the current core */ -uint -sb_coreunit(void *sbh) -{ - sb_info_t *si; - uint idx; - uint coreid; - uint coreunit; - uint i; - - si = SB_INFO(sbh); - coreunit = 0; - - idx = si->curidx; - - ASSERT(GOODREGS(si->curmap)); - coreid = sb_coreid(sbh); - - /* count the cores of our type */ - for (i = 0; i < idx; i++) - if (si->coreid[i] == coreid) - coreunit++; - - return (coreunit); -} - -static INLINE 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 SB would run at given a set of clockcontrol values */ -uint32 -sb_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_TYPE1) || (pll_type == PLL_TYPE4)) { - 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_TYPE3) { - return (100000000); - } else - ASSERT((pll_type >= PLL_TYPE1) && (pll_type <= PLL_TYPE4)); - - clock = CC_CLOCK_BASE * 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_TYPE4)) { - m1 = factor6(m1); - if (pll_type == PLL_TYPE1) - 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); - } -} - -/* returns the current speed the SB is running at */ -uint32 -sb_clock(void *sbh) -{ - sb_info_t *si; - extifregs_t *eir; - chipcregs_t *cc; - uint32 n, m; - uint idx; - uint32 pll_type, rate; - uint intr_val = 0; - - si = SB_INFO(sbh); - idx = si->curidx; - pll_type = PLL_TYPE1; - - INTR_OFF(si, intr_val); - - /* switch to extif or chipc core */ - if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) { - n = R_REG(&eir->clockcontrol_n); - m = R_REG(&eir->clockcontrol_sb); - } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) { - pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK; - n = R_REG(&cc->clockcontrol_n); - m = R_REG(&cc->clockcontrol_sb); - } else { - INTR_RESTORE(si, intr_val); - return 0; - } - - /* calculate rate */ - rate = sb_clock_rate(pll_type, n, m); - - /* switch back to previous core */ - sb_setcoreidx(sbh, idx); - - INTR_RESTORE(si, intr_val); - - return rate; -} - -/* change logical "focus" to the gpio core for optimized access */ -void* -sb_gpiosetcore(void *sbh) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - - return (sb_setcoreidx(sbh, si->gpioidx)); -} - -/* mask&set gpiocontrol bits */ -uint32 -sb_gpiocontrol(void *sbh, uint32 mask, uint32 val) -{ - sb_info_t *si; - uint regoff; - - si = SB_INFO(sbh); - regoff = 0; - - switch (si->gpioid) { - case SB_CC: - regoff = OFFSETOF(chipcregs_t, gpiocontrol); - break; - - case SB_PCI: - regoff = OFFSETOF(sbpciregs_t, gpiocontrol); - break; - - case SB_EXTIF: - return (0); - } - - return (sb_corereg(sbh, si->gpioidx, regoff, mask, val)); -} - -/* mask&set gpio output enable bits */ -uint32 -sb_gpioouten(void *sbh, uint32 mask, uint32 val) -{ - sb_info_t *si; - uint regoff; - - si = SB_INFO(sbh); - regoff = 0; - - switch (si->gpioid) { - case SB_CC: - regoff = OFFSETOF(chipcregs_t, gpioouten); - break; - - case SB_PCI: - regoff = OFFSETOF(sbpciregs_t, gpioouten); - break; - - case SB_EXTIF: - regoff = OFFSETOF(extifregs_t, gpio[0].outen); - break; - } - - return (sb_corereg(sbh, si->gpioidx, regoff, mask, val)); -} - -/* mask&set gpio output bits */ -uint32 -sb_gpioout(void *sbh, uint32 mask, uint32 val) -{ - sb_info_t *si; - uint regoff; - - si = SB_INFO(sbh); - regoff = 0; - - switch (si->gpioid) { - case SB_CC: - regoff = OFFSETOF(chipcregs_t, gpioout); - break; - - case SB_PCI: - regoff = OFFSETOF(sbpciregs_t, gpioout); - break; - - case SB_EXTIF: - regoff = OFFSETOF(extifregs_t, gpio[0].out); - break; - } - - return (sb_corereg(sbh, si->gpioidx, regoff, mask, val)); -} - -/* return the current gpioin register value */ -uint32 -sb_gpioin(void *sbh) -{ - sb_info_t *si; - uint regoff; - - si = SB_INFO(sbh); - regoff = 0; - - switch (si->gpioid) { - case SB_CC: - regoff = OFFSETOF(chipcregs_t, gpioin); - break; - - case SB_PCI: - regoff = OFFSETOF(sbpciregs_t, gpioin); - break; - - case SB_EXTIF: - regoff = OFFSETOF(extifregs_t, gpioin); - break; - } - - return (sb_corereg(sbh, si->gpioidx, regoff, 0, 0)); -} - -/* mask&set gpio interrupt polarity bits */ -uint32 -sb_gpiointpolarity(void *sbh, uint32 mask, uint32 val) -{ - sb_info_t *si; - uint regoff; - - si = SB_INFO(sbh); - regoff = 0; - - switch (si->gpioid) { - case SB_CC: - regoff = OFFSETOF(chipcregs_t, gpiointpolarity); - break; - - case SB_PCI: - /* pci gpio implementation does not support interrupt polarity */ - ASSERT(0); - break; - - case SB_EXTIF: - regoff = OFFSETOF(extifregs_t, gpiointpolarity); - break; - } - - return (sb_corereg(sbh, si->gpioidx, regoff, mask, val)); -} - -/* mask&set gpio interrupt mask bits */ -uint32 -sb_gpiointmask(void *sbh, uint32 mask, uint32 val) -{ - sb_info_t *si; - uint regoff; - - si = SB_INFO(sbh); - regoff = 0; - - switch (si->gpioid) { - case SB_CC: - regoff = OFFSETOF(chipcregs_t, gpiointmask); - break; - - case SB_PCI: - /* pci gpio implementation does not support interrupt mask */ - ASSERT(0); - break; - - case SB_EXTIF: - regoff = OFFSETOF(extifregs_t, gpiointmask); - break; - } - - return (sb_corereg(sbh, si->gpioidx, regoff, mask, val)); -} - - -/* - * Return the slow clock source. - * Three sources of SLOW CLOCK: LPO, Xtal, PCI - */ -static uint -sb_slowclk_src(void *sbh) -{ - sb_info_t *si; - chipcregs_t *cc; - uint32 v; - - si = SB_INFO(sbh); - - ASSERT(sb_coreid(sbh) == SB_CC); - - if (si->ccrev < 6) { - switch (si->bus) { - case PCMCIA_BUS: return (SCC_SS_XTAL); - case PCI_BUS: - v = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32)); - if (v & PCI_CFG_GPIO_SCS) - return (SCC_SS_PCI); - else - return (SCC_SS_XTAL); - default: return (SCC_SS_XTAL); - } - } else if (si->ccrev < 10) { - cc = (chipcregs_t*) sb_setcoreidx(sbh, si->curidx); - v = R_REG(&cc->slow_clk_ctl) & SCC_SS_MASK; - return (v); - } else { - return (SCC_SS_XTAL); - } -} - -/* - * Return the slowclock min or max frequency. - * Three sources of SLOW CLOCK: - * 1. On Chip LPO - 32khz or 160khz - * 2. On Chip Xtal OSC - 20mhz/4*(divider+1) - * 3. External PCI clock - 66mhz/4*(divider+1) - */ -static uint -sb_slowclk_freq(void *sbh, bool max) -{ - sb_info_t *si; - chipcregs_t *cc; - uint32 slowclk; - uint div; - - si = SB_INFO(sbh); - - ASSERT(sb_coreid(sbh) == SB_CC); - - cc = (chipcregs_t*) sb_setcoreidx(sbh, si->curidx); - - /* shouldn't be here unless we've established the chip has dynamic power control */ - ASSERT(R_REG(&cc->capabilities) & CAP_PWR_CTL); - - slowclk = sb_slowclk_src(sbh); - if (si->ccrev < 6) { - if (slowclk == SCC_SS_PCI) - return (max? (PCIMAXFREQ/64) : (PCIMINFREQ/64)); - else - return (max? (XTALMAXFREQ/32) : (XTALMINFREQ/32)); - } else if (si->ccrev < 10) { - div = 4 * (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHF) + 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_SHF; - div = 4 * (div + 1); - return (max ? XTALMAXFREQ : (XTALMINFREQ/div)); - } - return (0); -} - -static void -sb_pwrctl_setdelay(void *sbh, 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 power control logic. - */ - slowclk = sb_slowclk_src(sbh); - if (slowclk != SCC_SS_XTAL) - pll_delay += XTAL_ON_DELAY; - - slowmaxfreq = sb_slowclk_freq(sbh, 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); -} - -/* set or get slow clock divider */ -int -sb_pwrctl_slowclk(void *sbh, bool set, uint *div) -{ - sb_info_t *si; - uint origidx; - chipcregs_t *cc; - uint intr_val = 0; - uint err = 0; - - si = SB_INFO(sbh); - - /* chipcommon cores prior to rev6 don't support slowclkcontrol */ - if (si->ccrev < 6) - return 1; - - /* chipcommon cores rev10 are a whole new ball game */ - if (si->ccrev >= 10) - return 1; - - if (set && ((*div % 4) || (*div < 4))) - return 2; - - INTR_OFF(si, intr_val); - origidx = si->curidx; - cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0); - ASSERT(cc != NULL); - - if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL)) { - err = 3; - goto done; - } - - if (set) { - SET_REG(&cc->slow_clk_ctl, SCC_CD_MASK, ((*div / 4 - 1) << SCC_CD_SHF)); - sb_pwrctl_setdelay(sbh, (void *)cc); - } else - *div = 4 * (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHF) + 1); - -done: - sb_setcoreidx(sbh, origidx); - INTR_RESTORE(si, intr_val); - return err; -} - -/* initialize power control delay registers */ -void -sb_pwrctl_init(void *sbh) -{ - sb_info_t *si; - uint origidx; - chipcregs_t *cc; - - si = SB_INFO(sbh); - - if (si->bus == SB_BUS) - return; - - 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; - - /* 4317pc does not work with SlowClock less than 5Mhz */ - if (si->bus == PCMCIA_BUS) { - if ((si->ccrev >= 6) && (si->ccrev < 10)) - SET_REG(&cc->slow_clk_ctl, SCC_CD_MASK, (SCC_DEF_DIV << SCC_CD_SHF)); - } - - sb_pwrctl_setdelay(sbh, (void *)cc); - -done: - sb_setcoreidx(sbh, origidx); -} - -/* return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */ -uint16 -sb_pwrctl_fast_pwrup_delay(void *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; - - if (si->bus == SB_BUS) - goto done; - - 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(sbh, 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 */ -int -sb_pwrctl_xtal(void *sbh, uint what, bool on) -{ - sb_info_t *si; - uint32 in, out, outen; - - si = SB_INFO(sbh); - - switch (si->bus) { - - - case PCMCIA_BUS: - return (0); - - - case PCI_BUS: - - 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)); - - /* - * 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 power control mode (forceslow, forcefast, dynamic) */ -/* returns true if ignore pll off is set and false if it is not */ -bool -sb_pwrctl_clk(void *sbh, uint mode) -{ - sb_info_t *si; - uint origidx; - chipcregs_t *cc; - uint32 scc; - bool forcefastclk=FALSE; - uint intr_val = 0; - - si = SB_INFO(sbh); - - /* chipcommon cores prior to rev6 don't support slowclkcontrol */ - if (si->ccrev < 6) - return (FALSE); - - /* chipcommon cores rev10 are a whole new ball game */ - if (si->ccrev >= 10) - return (FALSE); - - INTR_OFF(si, intr_val); - - origidx = si->curidx; - - 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 */ - /* don't forget to force xtal back on before we clear SCC_DYN_XTAL.. */ - sb_pwrctl_xtal(sbh, XTAL, ON); - - SET_REG(&cc->slow_clk_ctl, (SCC_XC | SCC_FS | SCC_IP), SCC_IP); - break; - - case CLK_SLOW: /* force slow clock */ - if ((si->bus == SDIO_BUS) || (si->bus == PCMCIA_BUS)) - return (-1); - - if (si->ccrev >= 6) - OR_REG(&cc->slow_clk_ctl, SCC_FS); - break; - - case CLK_DYNAMIC: /* enable dynamic power control */ - 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_pwrctl_xtal(sbh, XTAL, OFF); - break; - } - - /* Is the h/w forcing the use of the fast clk */ - forcefastclk = (bool)((R_REG(&cc->slow_clk_ctl) & SCC_IP) == SCC_IP); - -done: - sb_setcoreidx(sbh, origidx); - INTR_RESTORE(si, intr_val); - return (forcefastclk); -} - -/* register driver interrupt disabling and restoring callback functions */ -void -sb_register_intr_callback(void *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]; -} - - |