X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/7ed9009bbdf799be5f9f1446c264b8504f483beb..0cc51371c037da2041da11d766d41122ded5a2d7:/target/linux/brcm-2.4/files/arch/mips/bcm947xx/sbutils.c diff --git a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/sbutils.c b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/sbutils.c index 672e027d8..5c85dd7c9 100644 --- a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/sbutils.c +++ b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/sbutils.c @@ -2,87 +2,122 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright 2006, Broadcom Corporation + * Copyright 2007, 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: sbutils.c,v 1.10 2006/04/08 07:12:42 honor Exp $ */ #include #include #include -#include #include #include #include #include +#include #include #include #include #include -#include #include +#include #include -#ifdef __mips__ -#include -#endif /* __mips__ */ +#include /* 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); +#ifdef BCMDBG +#define SB_MSG(args) printf args +#else +#define SB_MSG(args) +#endif /* BCMDBG */ + +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); + +typedef struct gpioh_item { + void *arg; + bool level; + gpio_handler_t handler; + uint32 event; + struct gpioh_item *next; +} gpioh_item_t; /* misc sb info needed by some of the routines */ typedef struct sb_info { - struct sb_pub sb; /* back plane public state (must be first field) */ + struct sb_pub sb; /* back plane public state (must be first field) */ + + 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 */ - void *osh; /* osl os handle */ - void *sdh; /* bcmsdh handle */ + bool memseg; /* flag to toggle MEM_SEG register */ - void *curmap; /* current regs va */ - void *regs[SB_MAXCORES]; /* other regs va */ + uint gpioidx; /* gpio control core index */ + uint gpioid; /* gpio control coretype */ - uint curidx; /* current core index */ - uint dev_coreid; /* the core provides driver functions */ + uint numcores; /* # discovered cores */ + uint coreid[SB_MAXCORES]; /* id of each core */ - bool memseg; /* flag to toggle MEM_SEG register */ + void *intr_arg; /* interrupt callback function arg */ + sb_intrsoff_t intrsoff_fn; /* turns chip interrupts off */ + sb_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */ + sb_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */ - uint gpioidx; /* gpio control core index */ - uint gpioid; /* gpio control coretype */ + uint8 pciecap_lcreg_offset; /* PCIE capability LCreg offset in the config space */ + bool pr42767_war; + uint8 pcie_polarity; + bool pcie_war_ovr; /* Override ASPM/Clkreq settings */ - uint numcores; /* # discovered cores */ - uint coreid[SB_MAXCORES]; /* id of each core */ + uint8 pmecap_offset; /* PM Capability offset in the config space */ + bool pmecap; /* Capable of generating PME */ - void *intr_arg; /* interrupt callback function arg */ - sb_intrsoff_t intrsoff_fn; /* turns chip interrupts off */ - sb_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */ - sb_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */ + gpioh_item_t *gpioh_head; /* GPIO event handlers list */ + char *vars; + uint varsz; } sb_info_t; /* local prototypes */ -static sb_info_t * sb_doattach(sb_info_t *si, uint devid, osl_t *osh, void *regs, - uint bustype, void *sdh, char **vars, uint *varsz); -static void sb_scan(sb_info_t *si); -static uint sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val); -static uint _sb_coreidx(sb_info_t *si); -static uint sb_findcoreidx(sb_info_t *si, uint coreid, uint coreunit); +static sb_info_t *sb_doattach(sb_info_t * si, uint devid, osl_t * osh, + void *regs, uint bustype, void *sdh, + char **vars, uint * varsz); +static void sb_scan(sb_info_t * si); +static uint _sb_coreidx(sb_info_t * si); static uint sb_pcidev2chip(uint pcidev); static uint sb_chip2numcores(uint chip); -static bool sb_ispcie(sb_info_t *si); -static bool sb_find_pci_capability(sb_info_t *si, uint8 req_cap_id, uchar *buf, uint32 *buflen); -static int sb_pci_fixcfg(sb_info_t *si); - +static bool sb_ispcie(sb_info_t * si); +static uint8 sb_find_pci_capability(sb_info_t * si, uint8 req_cap_id, + uchar * buf, uint32 * buflen); +static int sb_pci_fixcfg(sb_info_t * si); /* routines to access mdio slave device registers */ -static int sb_pcie_mdiowrite(sb_info_t *si, uint physmedia, uint readdr, uint val); -static void sb_war30841(sb_info_t *si); +static int sb_pcie_mdiowrite(sb_info_t * si, uint physmedia, uint readdr, + uint val); +static int sb_pcie_mdioread(sb_info_t * si, uint physmedia, uint readdr, + uint * ret_val); + +/* dev path concatenation util */ +static char *sb_devpathvar(sb_t * sbh, char *var, int len, const char *name); + +/* WARs */ +static void sb_war43448(sb_t * sbh); +static void sb_war43448_aspm(sb_t * sbh); +static void sb_war32414_forceHT(sb_t * sbh, bool forceHT); +static void sb_war30841(sb_info_t * si); +static void sb_war42767(sb_t * sbh); +static void sb_war42767_clkreq(sb_t * sbh); /* delay needed between the mdio control/ mdiodata register data access */ #define PR28829_DELAY() OSL_DELAY(10) @@ -93,19 +128,24 @@ static void sb_war30841(sb_info_t *si); /* global variable to indicate reservation/release of gpio's */ static uint32 sb_gpioreservation = 0; -#define SB_INFO(sbh) (sb_info_t*)sbh +/* global flag to prevent shared resources from being initialized multiple times in sb_attach() */ +static bool sb_onetimeinit = FALSE; + +#define SB_INFO(sbh) (sb_info_t*)(uintptr)sbh #define SET_SBREG(si, r, mask, val) \ W_SBREG((si), (r), ((R_SBREG((si), (r)) & ~(mask)) | (val))) -#define GOODCOREADDR(x) (((x) >= SB_ENUM_BASE) && ((x) <= SB_ENUM_LIM) && \ +#define GOODCOREADDR(x) (((x) >= SB_ENUM_BASE) && ((x) <= SB_ENUM_LIM) && \ ISALIGNED((x), SB_CORE_SIZE)) #define GOODREGS(regs) ((regs) && ISALIGNED((uintptr)(regs), SB_CORE_SIZE)) #define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF) +#define BADCOREADDR 0 #define GOODIDX(idx) (((uint)idx) < SB_MAXCORES) #define BADIDX (SB_MAXCORES+1) -#define NOREV -1 /* Invalid rev */ +#define NOREV -1 /* Invalid rev */ #define PCI(si) ((BUSTYPE(si->sb.bustype) == PCI_BUS) && (si->sb.buscoretype == SB_PCI)) #define PCIE(si) ((BUSTYPE(si->sb.bustype) == PCI_BUS) && (si->sb.buscoretype == SB_PCIE)) +#define PCMCIA(si) ((BUSTYPE(si->sb.bustype) == PCMCIA_BUS) && (si->memseg == TRUE)) /* sonicsrev */ #define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT) @@ -128,54 +168,51 @@ static uint32 sb_gpioreservation = 0; (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); } /* dynamic clock control defines */ -#define LPOMINFREQ 25000 /* low power oscillator min */ -#define LPOMAXFREQ 43000 /* low power oscillator max */ +#define LPOMINFREQ 25000 /* low power oscillator min */ +#define LPOMAXFREQ 43000 /* low power oscillator max */ #define XTALMINFREQ 19800000 /* 20 MHz - 1% */ #define XTALMAXFREQ 20200000 /* 20 MHz + 1% */ #define PCIMINFREQ 25000000 /* 25 MHz */ #define PCIMAXFREQ 34000000 /* 33 MHz + fudge */ -#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */ -#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */ - -/* different register spaces to access thr'u pcie indirect access */ -#define PCIE_CONFIGREGS 1 /* Access to config space */ -#define PCIE_PCIEREGS 2 /* Access to pcie registers */ +#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */ +#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */ /* force HT war check */ -#define FORCEHT_WAR32414(si) \ - ((PCIE(si)) && (((si->sb.chip == BCM4311_CHIP_ID) && (si->sb.chiprev == 1)) || \ - ((si->sb.chip == BCM4321_CHIP_ID) && (si->sb.chiprev <= 3)))) +#define FORCEHT_WAR32414(si) \ + (((PCIE(si)) && (si->sb.chip == BCM4311_CHIP_ID) && ((si->sb.chiprev <= 1))) || \ + ((PCI(si) || PCIE(si)) && (si->sb.chip == BCM4321_CHIP_ID) && (si->sb.chiprev <= 3))) + +#define PCIE_ASPMWARS(si) \ + ((PCIE(si)) && ((si->sb.buscorerev >= 3) && (si->sb.buscorerev <= 5))) /* GPIO Based LED powersave defines */ -#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ -#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ +#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ +#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ #define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME) -static uint32 -sb_read_sbreg(sb_info_t *si, volatile uint32 *sbr) +static uint32 sb_read_sbreg(sb_info_t * si, volatile uint32 * sbr) { uint8 tmp; uint32 val, intr_val = 0; - /* * 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) { + if (PCMCIA(si)) { INTR_OFF(si, intr_val); tmp = 1; OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1); - sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ + sbr = (volatile uint32 *)((uintptr) sbr & ~(1 << 11)); /* mask out bit 11 */ } val = R_REG(si->osh, sbr); - if (si->memseg) { + if (PCMCIA(si)) { tmp = 0; OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1); INTR_RESTORE(si, intr_val); @@ -184,43 +221,43 @@ sb_read_sbreg(sb_info_t *si, volatile uint32 *sbr) return (val); } -static void -sb_write_sbreg(sb_info_t *si, volatile uint32 *sbr, uint32 v) +static void sb_write_sbreg(sb_info_t * si, volatile uint32 * sbr, uint32 v) { uint8 tmp; volatile uint32 dummy; uint32 intr_val = 0; - /* * 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) { + if (PCMCIA(si)) { INTR_OFF(si, intr_val); tmp = 1; OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1); - sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ + sbr = (volatile uint32 *)((uintptr) sbr & ~(1 << 11)); /* mask out bit 11 */ } if (BUSTYPE(si->sb.bustype) == PCMCIA_BUS) { #ifdef IL_BIGENDIAN dummy = R_REG(si->osh, sbr); - W_REG(si->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); + W_REG(si->osh, ((volatile uint16 *)sbr + 1), + (uint16) ((v >> 16) & 0xffff)); dummy = R_REG(si->osh, sbr); - W_REG(si->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); + W_REG(si->osh, (volatile uint16 *)sbr, (uint16) (v & 0xffff)); #else dummy = R_REG(si->osh, sbr); - W_REG(si->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); + W_REG(si->osh, (volatile uint16 *)sbr, (uint16) (v & 0xffff)); dummy = R_REG(si->osh, sbr); - W_REG(si->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); -#endif /* IL_BIGENDIAN */ + W_REG(si->osh, ((volatile uint16 *)sbr + 1), + (uint16) ((v >> 16) & 0xffff)); +#endif /* IL_BIGENDIAN */ } else W_REG(si->osh, sbr, v); - if (si->memseg) { + if (PCMCIA(si)) { tmp = 0; OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1); INTR_RESTORE(si, intr_val); @@ -236,24 +273,27 @@ sb_write_sbreg(sb_info_t *si, volatile uint32 *sbr, uint32 v) * vars - pointer to a pointer area for "environment" variables * varsz - pointer to int to return the size of the vars */ -sb_t * -BCMINITFN(sb_attach)(uint devid, osl_t *osh, void *regs, - uint bustype, void *sdh, char **vars, uint *varsz) -{ +sb_t *sb_attach(uint devid, osl_t * osh, void *regs, + uint bustype, void *sdh, char **vars, + uint * varsz) { sb_info_t *si; /* alloc sb_info_t */ - if ((si = MALLOC(osh, sizeof (sb_info_t))) == NULL) { - SB_ERROR(("sb_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); + if ((si = MALLOC(osh, sizeof(sb_info_t))) == NULL) { + SB_ERROR(("sb_attach: malloc failed! malloced %d bytes\n", + MALLOCED(osh))); return (NULL); } - if (sb_doattach(si, devid, osh, regs, bustype, sdh, vars, (uint*)varsz) == NULL) { + if (sb_doattach(si, devid, osh, regs, bustype, sdh, vars, varsz) == + NULL) { MFREE(osh, si, sizeof(sb_info_t)); return (NULL); } + si->vars = vars ? *vars : NULL; + si->varsz = varsz ? *varsz : 0; - return (sb_t *)si; + return (sb_t *) si; } /* Using sb_kattach depends on SB_BUS support, either implicit */ @@ -262,74 +302,55 @@ BCMINITFN(sb_attach)(uint devid, osl_t *osh, void *regs, /* global kernel resource */ static sb_info_t ksi; -static bool ksi_attached = FALSE; /* generic kernel variant of sb_attach() */ -sb_t * -BCMINITFN(sb_kattach)(void) -{ - osl_t *osh = NULL; +sb_t *BCMINITFN(sb_kattach) (osl_t * osh) { + static bool ksi_attached = FALSE; uint32 *regs; if (!ksi_attached) { uint32 cid; - regs = (uint32 *)REG_MAP(SB_ENUM_BASE, SB_CORE_SIZE); - cid = R_REG(osh, (uint32 *)regs); + regs = (uint32 *) REG_MAP(SB_ENUM_BASE, SB_CORE_SIZE); + cid = R_REG(osh, (uint32 *) regs); if (((cid & CID_ID_MASK) == BCM4712_CHIP_ID) && ((cid & CID_PKG_MASK) != BCM4712LARGE_PKG_ID) && ((cid & CID_REV_MASK) <= (3 << CID_REV_SHIFT))) { uint32 *scc, val; - scc = (uint32 *)((uchar*)regs + OFFSETOF(chipcregs_t, slow_clk_ctl)); + scc = + (uint32 *) ((uchar *) regs + + OFFSETOF(chipcregs_t, slow_clk_ctl)); val = R_REG(osh, scc); SB_ERROR((" initial scc = 0x%x\n", val)); val |= SCC_SS_XTAL; W_REG(osh, scc, val); } - if (sb_doattach(&ksi, BCM4710_DEVICE_ID, osh, (void*)regs, - SB_BUS, NULL, NULL, NULL) == NULL) { + if (sb_doattach(&ksi, BCM4710_DEVICE_ID, osh, (void *)regs, SB_BUS, NULL, + osh != SB_OSH ? &ksi.vars : NULL, + osh != SB_OSH ? &ksi.varsz : NULL) == NULL) return NULL; - } - else - ksi_attached = TRUE; + ksi_attached = TRUE; } - return (sb_t *)&ksi; -} -#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SB_BUS) */ - -void -BCMINITFN(sb_war32414_forceHT)(sb_t *sbh, bool forceHT) -{ - sb_info_t *si; - - si = SB_INFO(sbh); - - - if (FORCEHT_WAR32414(si)) { - uint32 val = 0; - if (forceHT) - val = SYCC_HR; - sb_corereg((void*)si, SB_CC_IDX, OFFSETOF(chipcregs_t, system_clk_ctl), - SYCC_HR, val); - } + return &ksi.sb; } +#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SB_BUS) */ -static sb_info_t * -BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs, - uint bustype, void *sdh, char **vars, uint *varsz) -{ +static sb_info_t *BCMINITFN(sb_doattach) (sb_info_t * si, uint devid, + osl_t * osh, void *regs, + uint bustype, void *sdh, + char **vars, uint * varsz) { uint origidx; chipcregs_t *cc; sbconfig_t *sb; uint32 w; + char *pvars; ASSERT(GOODREGS(regs)); - bzero((uchar*)si, sizeof(sb_info_t)); - + bzero((uchar *) si, sizeof(sb_info_t)); si->sb.buscoreidx = si->gpioidx = BADIDX; si->curmap = regs; @@ -338,17 +359,16 @@ BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs, /* check to see if we are a sb core mimic'ing a pci core */ if (bustype == PCI_BUS) { - if (OSL_PCI_READ_CONFIG(si->osh, PCI_SPROM_CONTROL, sizeof(uint32)) == 0xffffffff) { - SB_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SB " - "devid:0x%x\n", __FUNCTION__, devid)); + if (OSL_PCI_READ_CONFIG + (si->osh, PCI_SPROM_CONTROL, + sizeof(uint32)) == 0xffffffff) { + SB_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SB " "devid:0x%x\n", __FUNCTION__, devid)); bustype = SB_BUS; } } - si->sb.bustype = bustype; if (si->sb.bustype != BUSTYPE(si->sb.bustype)) { - SB_ERROR(("sb_doattach: bus type %d does not match configured bus type %d\n", - si->sb.bustype, BUSTYPE(si->sb.bustype))); + SB_ERROR(("sb_doattach: bus type %d does not match configured bus type %d\n", si->sb.bustype, BUSTYPE(si->sb.bustype))); return NULL; } @@ -357,13 +377,14 @@ BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs, si->memseg = TRUE; /* kludge to enable the clock on the 4306 which lacks a slowclock */ - if (BUSTYPE(si->sb.bustype) == PCI_BUS) - sb_clkctl_xtal(&si->sb, XTAL|PLL, ON); + if (BUSTYPE(si->sb.bustype) == PCI_BUS && !sb_ispcie(si)) + sb_clkctl_xtal(&si->sb, XTAL | PLL, ON); if (BUSTYPE(si->sb.bustype) == PCI_BUS) { w = OSL_PCI_READ_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32)); if (!GOODCOREADDR(w)) - OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32), SB_ENUM_BASE); + OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, + sizeof(uint32), SB_ENUM_BASE); } /* initialize current core index value */ @@ -375,9 +396,9 @@ BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs, } /* get sonics backplane revision */ - sb = REGS2SB(si->curmap); - si->sb.sonicsrev = (R_SBREG(si, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; - + sb = REGS2SB(regs); + si->sb.sonicsrev = + (R_SBREG(si, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; /* keep and reuse the initial register mapping */ origidx = si->curidx; if (BUSTYPE(si->sb.bustype) == SB_BUS) @@ -385,7 +406,7 @@ BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs, /* is core-0 a chipcommon core? */ si->numcores = 1; - cc = (chipcregs_t*) sb_setcoreidx(&si->sb, 0); + cc = (chipcregs_t *) sb_setcoreidx(&si->sb, 0); if (sb_coreid(&si->sb) != SB_CC) cc = NULL; @@ -393,8 +414,12 @@ BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs, if (cc) { /* chip common core found! */ si->sb.chip = R_REG(si->osh, &cc->chipid) & CID_ID_MASK; - si->sb.chiprev = (R_REG(si->osh, &cc->chipid) & CID_REV_MASK) >> CID_REV_SHIFT; - si->sb.chippkg = (R_REG(si->osh, &cc->chipid) & CID_PKG_MASK) >> CID_PKG_SHIFT; + si->sb.chiprev = + (R_REG(si->osh, &cc->chipid) & CID_REV_MASK) >> + CID_REV_SHIFT; + si->sb.chippkg = + (R_REG(si->osh, &cc->chipid) & CID_PKG_MASK) >> + CID_PKG_SHIFT; } else { /* no chip common core -- must convert device id to chip id */ if ((si->sb.chip = sb_pcidev2chip(devid)) == 0) { @@ -407,9 +432,13 @@ BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs, /* get chipcommon rev */ si->sb.ccrev = cc ? (int)sb_corerev(&si->sb) : NOREV; + /* get chipcommon capabilites */ + si->sb.cccaps = cc ? R_REG(si->osh, &cc->capabilities) : 0; + /* determine numcores */ if (cc && ((si->sb.ccrev == 4) || (si->sb.ccrev >= 6))) - si->numcores = (R_REG(si->osh, &cc->chipid) & CID_CC_MASK) >> CID_CC_SHIFT; + si->numcores = + (R_REG(si->osh, &cc->chipid) & CID_CC_MASK) >> CID_CC_SHIFT; else si->numcores = sb_chip2numcores(si->sb.chip); @@ -423,19 +452,27 @@ BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs, sb_scan(si); /* fixup necessary chip/core configurations */ - if (BUSTYPE(si->sb.bustype) == PCI_BUS) { - if (sb_pci_fixcfg(si)) { - SB_ERROR(("sb_doattach: sb_pci_fixcfg failed\n")); - return NULL; - } + if (BUSTYPE(si->sb.bustype) == PCI_BUS && sb_pci_fixcfg(si)) { + SB_ERROR(("sb_doattach: sb_pci_fixcfg failed\n")); + return NULL; } - /* srom_var_init() depends on sb_scan() info */ - if (srom_var_init(si, si->sb.bustype, si->curmap, si->osh, vars, varsz)) { + /* Init nvram from sprom/otp if they exist */ + if (srom_var_init + (&si->sb, BUSTYPE(si->sb.bustype), regs, si->osh, vars, varsz)) { SB_ERROR(("sb_doattach: srom_var_init failed: bad srom\n")); return (NULL); } - + pvars = vars ? *vars : NULL; + + /* PMU specific initializations */ + if ((si->sb.cccaps & CC_CAP_PMU) && !sb_onetimeinit) { + sb_pmu_init(&si->sb, si->osh); + /* Find out Crystal frequency and init PLL */ + sb_pmu_pll_init(&si->sb, si->osh, getintvar(pvars, "xtalfreq")); + /* Initialize PMU resources (up/dn timers, dep masks, etc.) */ + sb_pmu_res_init(&si->sb, si->osh); + } if (cc == NULL) { /* * The chip revision number is hardwired into all @@ -448,17 +485,17 @@ BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs, ASSERT(vars); si->sb.chiprev = getintvar(*vars, "chiprev"); } else if (BUSTYPE(si->sb.bustype) == PCI_BUS) { - w = OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_REV, sizeof(uint32)); + w = OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_REV, + sizeof(uint32)); si->sb.chiprev = w & 0xff; } else si->sb.chiprev = 0; } if (BUSTYPE(si->sb.bustype) == PCMCIA_BUS) { - w = getintvar(*vars, "regwindowsz"); + w = getintvar(pvars, "regwindowsz"); si->memseg = (w <= CFTABLE_REGWIN_2K) ? TRUE : FALSE; } - /* gpio control core is required */ if (!GOODIDX(si->gpioidx)) { SB_ERROR(("sb_doattach: gpio control core not found\n")); @@ -470,21 +507,32 @@ BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs, case PCI_BUS: /* do a pci config read to get subsystem id and subvendor id */ w = OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_SVID, sizeof(uint32)); - si->sb.boardvendor = w & 0xffff; - si->sb.boardtype = (w >> 16) & 0xffff; + /* Let nvram variables override subsystem Vend/ID */ + if ((si->sb.boardvendor = + (uint16) sb_getdevpathintvar(&si->sb, "boardvendor")) == 0) + si->sb.boardvendor = w & 0xffff; + else + SB_ERROR(("Overriding boardvendor: 0x%x instead of 0x%x\n", si->sb.boardvendor, w & 0xffff)); + if ((si->sb.boardtype = + (uint16) sb_getdevpathintvar(&si->sb, "boardtype")) == 0) + si->sb.boardtype = (w >> 16) & 0xffff; + else + SB_ERROR(("Overriding boardtype: 0x%x instead of 0x%x\n", si->sb.boardtype, (w >> 16) & 0xffff)); break; case PCMCIA_BUS: - case SDIO_BUS: - si->sb.boardvendor = getintvar(*vars, "manfid"); - si->sb.boardtype = getintvar(*vars, "prodid"); + si->sb.boardvendor = getintvar(pvars, "manfid"); + si->sb.boardtype = getintvar(pvars, "prodid"); break; case SB_BUS: case JTAG_BUS: si->sb.boardvendor = VENDOR_BROADCOM; - if ((si->sb.boardtype = getintvar(NULL, "boardtype")) == 0) - si->sb.boardtype = 0xffff; + if (pvars == NULL + || ((si->sb.boardtype = getintvar(pvars, "prodid")) == 0)) + if ((si->sb.boardtype = + getintvar(NULL, "boardtype")) == 0) + si->sb.boardtype = 0xffff; break; } @@ -493,25 +541,147 @@ BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs, ASSERT(si->sb.boardtype); } + si->sb.boardflags = getintvar(pvars, "boardflags"); + /* setup the GPIO based LED powersave register */ if (si->sb.ccrev >= 16) { - if ((vars == NULL) || ((w = getintvar(*vars, "leddc")) == 0)) + if ((pvars == NULL) || ((w = getintvar(pvars, "leddc")) == 0)) w = DEFAULT_GPIOTIMERVAL; - sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimerval), ~0, w); + sb_corereg(&si->sb, SB_CC_IDX, + OFFSETOF(chipcregs_t, gpiotimerval), ~0, w); + } + + /* Determine if this board needs override */ + if (PCIE(si) && (si->sb.chip == BCM4321_CHIP_ID)) + si->pcie_war_ovr = ((si->sb.boardvendor == VENDOR_APPLE) && + ((uint8) getintvar(pvars, "sromrev") == 4) + && ((uint8) getintvar(pvars, "boardrev") <= + 0x71)) + || ((uint32) getintvar(pvars, "boardflags2") & + BFL2_PCIEWAR_OVR); + + if (PCIE_ASPMWARS(si)) { + sb_war43448_aspm((void *)si); + sb_war42767_clkreq((void *)si); } + if (FORCEHT_WAR32414(si)) { - /* set proper clk setup delays before forcing HT */ - sb_clkctl_init((void *)si); - sb_war32414_forceHT((void *)si, 1); + si->sb.pr32414 = TRUE; + sb_clkctl_init(&si->sb); + sb_war32414_forceHT(&si->sb, 1); + } + + if (PCIE(si) && ((si->sb.buscorerev == 6) || (si->sb.buscorerev == 7))) + si->sb.pr42780 = TRUE; + + if (PCIE_ASPMWARS(si)) + sb_pcieclkreq(&si->sb, 1, 0); + + if (PCIE(si) && + (((si->sb.chip == BCM4311_CHIP_ID) && (si->sb.chiprev == 2)) || + ((si->sb.chip == BCM4312_CHIP_ID) && (si->sb.chiprev == 0)))) + sb_set_initiator_to(&si->sb, 0x3, + sb_findcoreidx(&si->sb, SB_D11, 0)); + + /* Disable gpiopullup and gpiopulldown */ + if (!sb_onetimeinit && si->sb.ccrev >= 20) { + cc = (chipcregs_t *) sb_setcore(&si->sb, SB_CC, 0); + W_REG(osh, &cc->gpiopullup, 0); + W_REG(osh, &cc->gpiopulldown, 0); + sb_setcoreidx(&si->sb, origidx); } +#ifdef BCMDBG + /* clear any previous epidiag-induced target abort */ + sb_taclear(&si->sb); +#endif /* BCMDBG */ +#ifdef HNDRTE + sb_onetimeinit = TRUE; +#endif return (si); } +/* Enable/Disable clkreq for PCIE (4311B0/4321B1) */ +void sb_war42780_clkreq(sb_t * sbh, bool clkreq) { + sb_info_t *si; + + si = SB_INFO(sbh); + + /* Don't change clkreq value if serdespll war has not yet been applied */ + if (!si->pr42767_war && PCIE_ASPMWARS(si)) + return; + + sb_pcieclkreq(sbh, 1, (int32) clkreq); +} + +static void BCMINITFN(sb_war43448) (sb_t * sbh) { + sb_info_t *si; + + si = SB_INFO(sbh); + + /* if not pcie bus, we're done */ + if (!PCIE(si) || !PCIE_ASPMWARS(si)) + return; + + /* Restore the polarity */ + if (si->pcie_polarity != 0) + sb_pcie_mdiowrite((void *)(uintptr) & si->sb, MDIODATA_DEV_RX, + SERDES_RX_CTRL, si->pcie_polarity); +} + +static void BCMINITFN(sb_war43448_aspm) (sb_t * sbh) { + uint32 w; + uint16 val16, *reg16; + sbpcieregs_t *pcieregs; + sb_info_t *si; + + si = SB_INFO(sbh); + + /* if not pcie bus, we're done */ + if (!PCIE(si) || !PCIE_ASPMWARS(si)) + return; + + /* no ASPM stuff on QT or VSIM */ + if (si->sb.chippkg == HDLSIM_PKG_ID || si->sb.chippkg == HWSIM_PKG_ID) + return; + + pcieregs = (sbpcieregs_t *) sb_setcoreidx(sbh, si->sb.buscoreidx); + + /* Enable ASPM in the shadow SROM and Link control */ + reg16 = &pcieregs->sprom[SRSH_ASPM_OFFSET]; + val16 = R_REG(si->osh, reg16); + if (!si->pcie_war_ovr) + val16 |= SRSH_ASPM_ENB; + else + val16 &= ~SRSH_ASPM_ENB; + W_REG(si->osh, reg16, val16); + + w = OSL_PCI_READ_CONFIG(si->osh, si->pciecap_lcreg_offset, + sizeof(uint32)); + if (!si->pcie_war_ovr) + w |= PCIE_ASPM_ENAB; + else + w &= ~PCIE_ASPM_ENAB; + OSL_PCI_WRITE_CONFIG(si->osh, si->pciecap_lcreg_offset, sizeof(uint32), + w); +} + +static void BCMINITFN(sb_war32414_forceHT) (sb_t * sbh, bool forceHT) { + sb_info_t *si; + uint32 val = 0; + + si = SB_INFO(sbh); + + ASSERT(FORCEHT_WAR32414(si)); -uint -sb_coreid(sb_t *sbh) + if (forceHT) + val = SYCC_HR; + sb_corereg(sbh, SB_CC_IDX, OFFSETOF(chipcregs_t, system_clk_ctl), + SYCC_HR, val); +} + +uint sb_coreid(sb_t * sbh) { sb_info_t *si; sbconfig_t *sb; @@ -522,8 +692,18 @@ sb_coreid(sb_t *sbh) return ((R_SBREG(si, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT); } -uint -sb_coreidx(sb_t *sbh) +uint sb_flag(sb_t * sbh) +{ + sb_info_t *si; + sbconfig_t *sb; + + si = SB_INFO(sbh); + sb = REGS2SB(si->curmap); + + return R_SBREG(si, &sb->sbtpsflag) & SBTPS_NUM0_MASK; +} + +uint sb_coreidx(sb_t * sbh) { sb_info_t *si; @@ -531,10 +711,9 @@ sb_coreidx(sb_t *sbh) return (si->curidx); } -/* return current index of core */ -static uint -_sb_coreidx(sb_info_t *si) +static uint _sb_coreidx(sb_info_t * si) { + sbconfig_t *sb; uint32 sbaddr = 0; @@ -547,26 +726,27 @@ _sb_coreidx(sb_info_t *si) break; case PCI_BUS: - sbaddr = OSL_PCI_READ_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32)); + sbaddr = + OSL_PCI_READ_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32)); break; - case PCMCIA_BUS: { - uint8 tmp = 0; + case PCMCIA_BUS:{ + uint8 tmp = 0; - 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; - } + 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; + } #ifdef BCMJTAG case JTAG_BUS: - sbaddr = (uint32)si->curmap; + sbaddr = (uint32) si->curmap; break; -#endif /* BCMJTAG */ +#endif /* BCMJTAG */ default: ASSERT(0); @@ -578,8 +758,7 @@ _sb_coreidx(sb_info_t *si) return ((sbaddr - SB_ENUM_BASE) / SB_CORE_SIZE); } -uint -sb_corevendor(sb_t *sbh) +uint sb_corevendor(sb_t * sbh) { sb_info_t *si; sbconfig_t *sb; @@ -590,8 +769,7 @@ sb_corevendor(sb_t *sbh) return ((R_SBREG(si, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT); } -uint -sb_corerev(sb_t *sbh) +uint sb_corerev(sb_t * sbh) { sb_info_t *si; sbconfig_t *sb; @@ -604,8 +782,7 @@ sb_corerev(sb_t *sbh) return (SBCOREREV(sbidh)); } -void * -sb_osh(sb_t *sbh) +void *sb_osh(sb_t * sbh) { sb_info_t *si; @@ -613,8 +790,7 @@ sb_osh(sb_t *sbh) return si->osh; } -void -sb_setosh(sb_t *sbh, osl_t *osh) +void sb_setosh(sb_t * sbh, osl_t * osh) { sb_info_t *si; @@ -626,9 +802,25 @@ sb_setosh(sb_t *sbh, osl_t *osh) si->osh = osh; } +/* set sbtmstatelow core-specific flags */ +void sb_coreflags_wo(sb_t * 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); + + /* mask and set */ + w = (R_SBREG(si, &sb->sbtmstatelow) & ~mask) | val; + W_SBREG(si, &sb->sbtmstatelow, w); +} + /* set/clear sbtmstatelow core-specific flags */ -uint32 -sb_coreflags(sb_t *sbh, uint32 mask, uint32 val) +uint32 sb_coreflags(sb_t * sbh, uint32 mask, uint32 val) { sb_info_t *si; sbconfig_t *sb; @@ -645,13 +837,14 @@ sb_coreflags(sb_t *sbh, uint32 mask, uint32 val) W_SBREG(si, &sb->sbtmstatelow, w); } - /* return the new value */ + /* return the new value + * for write operation, the following readback ensures the completion of write opration. + */ return (R_SBREG(si, &sb->sbtmstatelow)); } /* set/clear sbtmstatehigh core-specific flags */ -uint32 -sb_coreflagshi(sb_t *sbh, uint32 mask, uint32 val) +uint32 sb_coreflagshi(sb_t * sbh, uint32 mask, uint32 val) { sb_info_t *si; sbconfig_t *sb; @@ -670,12 +863,11 @@ sb_coreflagshi(sb_t *sbh, uint32 mask, uint32 val) } /* return the new value */ - return (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_FL_MASK); + return (R_SBREG(si, &sb->sbtmstatehigh)); } /* Run bist on current core. Caller needs to take care of core-specific bist hazards */ -int -sb_corebist(sb_t *sbh) +int sb_corebist(sb_t * sbh) { uint32 sblo; sb_info_t *si; @@ -688,18 +880,18 @@ sb_corebist(sb_t *sbh) sblo = R_SBREG(si, &sb->sbtmstatelow); W_SBREG(si, &sb->sbtmstatelow, (sblo | SBTML_FGC | SBTML_BE)); - SPINWAIT(((R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_BISTD) == 0), 100000); + SPINWAIT(((R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_BISTD) == 0), + 100000); if (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_BISTF) - result = BCME_ERROR; + result = -1; W_SBREG(si, &sb->sbtmstatelow, sblo); return result; } -bool -sb_iscoreup(sb_t *sbh) +bool sb_iscoreup(sb_t * sbh) { sb_info_t *si; sbconfig_t *sb; @@ -708,7 +900,7 @@ sb_iscoreup(sb_t *sbh) sb = REGS2SB(si->curmap); return ((R_SBREG(si, &sb->sbtmstatelow) & - (SBTML_RESET | SBTML_REJ_MASK | SBTML_CLK)) == SBTML_CLK); + (SBTML_RESET | SBTML_REJ_MASK | SBTML_CLK)) == SBTML_CLK); } /* @@ -720,51 +912,62 @@ sb_iscoreup(sb_t *sbh) * Also, when using pci/pcie, we can optimize away the core switching for pci registers * and (on newer pci cores) chipcommon registers. */ -static uint -sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val) +uint sb_corereg(sb_t * sbh, uint coreidx, uint regoff, uint mask, uint val) { uint origidx = 0; uint32 *r = NULL; uint w; uint intr_val = 0; bool fast = FALSE; + sb_info_t *si; + + si = SB_INFO(sbh); ASSERT(GOODIDX(coreidx)); ASSERT(regoff < SB_CORE_SIZE); ASSERT((val & ~mask) == 0); -#ifdef notyet - if (si->sb.bustype == SB_BUS) { +#if 0 + if (BUSTYPE(si->sb.bustype) == SB_BUS) { /* If internal bus, we can always get at everything */ fast = TRUE; - r = (uint32 *)((uchar *)si->regs[coreidx] + regoff); - } else if (si->sb.bustype == PCI_BUS) { + /* map if does not exist */ + if (!si->regs[coreidx]) { + si->regs[coreidx] = + (void *)REG_MAP(si->coresba[coreidx], SB_CORE_SIZE); + ASSERT(GOODREGS(si->regs[coreidx])); + } + r = (uint32 *) ((uchar *) si->regs[coreidx] + regoff); + } else if (BUSTYPE(si->sb.bustype) == PCI_BUS) { /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ if ((si->coreid[coreidx] == SB_CC) && - ((si->sb.buscoretype == SB_PCIE) || - (si->sb.buscorerev >= 13))) { + ((si->sb.buscoretype == SB_PCIE) + || (si->sb.buscorerev >= 13))) { /* Chipc registers are mapped at 12KB */ fast = TRUE; - r = (uint32 *)((char *)si->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); + r = (uint32 *) ((char *)si->curmap + + PCI_16KB0_CCREGS_OFFSET + regoff); } else if (si->sb.buscoreidx == coreidx) { /* pci registers are at either in the last 2KB of an 8KB window * or, in pcie and pci rev 13 at 8KB */ fast = TRUE; - if ((si->sb.buscoretype == SB_PCIE) || - (si->sb.buscorerev >= 13)) - r = (uint32 *)((char *)si->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); + if ((si->sb.buscoretype == SB_PCIE) + || (si->sb.buscorerev >= 13)) + r = (uint32 *) ((char *)si->curmap + + PCI_16KB0_PCIREGS_OFFSET + + regoff); else - r = (uint32 *)((char *)si->curmap + - ((regoff >= SBCONFIGOFF) ? - PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + - regoff); + r = (uint32 *) ((char *)si->curmap + + ((regoff >= SBCONFIGOFF) ? + PCI_BAR0_PCISBR_OFFSET : + PCI_BAR0_PCIREGS_OFFSET) + + regoff); } } -#endif /* notyet */ +#endif if (!fast) { INTR_OFF(si, intr_val); @@ -773,7 +976,8 @@ sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val) origidx = sb_coreidx(&si->sb); /* switch core */ - r = (uint32*) ((uchar*) sb_setcoreidx(&si->sb, coreidx) + regoff); + r = (uint32 *) ((uchar *) sb_setcoreidx(&si->sb, coreidx) + + regoff); } ASSERT(r); @@ -791,8 +995,14 @@ sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val) /* readback */ if (regoff >= SBCONFIGOFF) w = R_SBREG(si, r); - else - w = R_REG(si->osh, r); + else { + if ((si->sb.chip == BCM5354_CHIP_ID) && + (coreidx == SB_CC_IDX) && + (regoff == OFFSETOF(chipcregs_t, watchdog))) { + w = val; + } else + w = R_REG(si->osh, r); + } if (!fast) { /* restore core index */ @@ -821,78 +1031,290 @@ sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val) #define read_pci_cfg_word(a) \ (WORD_VAL(OSL_PCI_READ_CONFIG(si->osh, DWORD_ALIGN(a), 4), a) & 0xffff) - -/* return TRUE if requested capability exists in the PCI config space */ -static bool -sb_find_pci_capability(sb_info_t *si, uint8 req_cap_id, uchar *buf, uint32 *buflen) +/* return cap_offset if requested capability exists in the PCI config space */ +static uint8 +sb_find_pci_capability(sb_info_t * si, uint8 req_cap_id, uchar * buf, + uint32 * buflen) { uint8 cap_id; - uint8 cap_ptr; - uint32 bufsize; + uint8 cap_ptr = 0; + uint32 bufsize; uint8 byte_val; if (BUSTYPE(si->sb.bustype) != PCI_BUS) - return FALSE; + goto end; /* check for Header type 0 */ byte_val = read_pci_cfg_byte(PCI_CFG_HDR); if ((byte_val & 0x7f) != PCI_HEADER_NORMAL) - return FALSE; + goto end; /* check if the capability pointer field exists */ byte_val = read_pci_cfg_byte(PCI_CFG_STAT); if (!(byte_val & PCI_CAPPTR_PRESENT)) - return FALSE; + goto end; cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR); /* check if the capability pointer is 0x00 */ if (cap_ptr == 0x00) - return FALSE; - + goto end; /* loop thr'u the capability list and see if the pcie capabilty exists */ cap_id = read_pci_cfg_byte(cap_ptr); while (cap_id != req_cap_id) { - cap_ptr = read_pci_cfg_byte((cap_ptr+1)); - if (cap_ptr == 0x00) break; + cap_ptr = read_pci_cfg_byte((cap_ptr + 1)); + if (cap_ptr == 0x00) + break; cap_id = read_pci_cfg_byte(cap_ptr); } if (cap_id != req_cap_id) { - return FALSE; + goto end; } /* found the caller requested capability */ if ((buf != NULL) && (buflen != NULL)) { + uint8 cap_data; + bufsize = *buflen; - if (!bufsize) goto end; + if (!bufsize) + goto end; *buflen = 0; /* copy the cpability data excluding cap ID and next ptr */ - cap_ptr += 2; - if ((bufsize + cap_ptr) > SZPCR) - bufsize = SZPCR - cap_ptr; + cap_data = cap_ptr + 2; + if ((bufsize + cap_data) > SZPCR) + bufsize = SZPCR - cap_data; *buflen = bufsize; while (bufsize--) { - *buf = read_pci_cfg_byte(cap_ptr); - cap_ptr++; + *buf = read_pci_cfg_byte(cap_data); + cap_data++; buf++; } } -end: + end: + return cap_ptr; +} + +uint8 sb_pcieclkreq(sb_t * sbh, uint32 mask, uint32 val) +{ + sb_info_t *si; + uint32 reg_val; + uint8 offset; + + si = SB_INFO(sbh); + + offset = si->pciecap_lcreg_offset; + if (!offset) + return 0; + + reg_val = OSL_PCI_READ_CONFIG(si->osh, offset, sizeof(uint32)); + /* set operation */ + if (mask) { + if (val) + reg_val |= PCIE_CLKREQ_ENAB; + else + reg_val &= ~PCIE_CLKREQ_ENAB; + OSL_PCI_WRITE_CONFIG(si->osh, offset, sizeof(uint32), reg_val); + reg_val = OSL_PCI_READ_CONFIG(si->osh, offset, sizeof(uint32)); + } + if (reg_val & PCIE_CLKREQ_ENAB) + return 1; + else + return 0; +} + +#ifdef BCMDBG + +uint32 sb_pcielcreg(sb_t * sbh, uint32 mask, uint32 val) +{ + sb_info_t *si; + uint32 reg_val; + uint8 offset; + + si = SB_INFO(sbh); + + if (!PCIE(si)) + return 0; + + offset = si->pciecap_lcreg_offset; + if (!offset) + return 0; + + /* set operation */ + if (mask) + OSL_PCI_WRITE_CONFIG(si->osh, offset, sizeof(uint32), val); + + reg_val = OSL_PCI_READ_CONFIG(si->osh, offset, sizeof(uint32)); + + return reg_val; +} + +uint8 sb_pcieL1plldown(sb_t * sbh) +{ + sb_info_t *si; + uint intr_val = 0; + uint origidx; + uint32 reg_val; + + si = SB_INFO(sbh); + + if (!PCIE(si)) + return 0; + if (!((si->sb.buscorerev == 3) || (si->sb.buscorerev == 4))) + return 0; + + if (!sb_pcieclkreq((void *)(uintptr) sbh, 0, 0)) { + SB_ERROR(("PCIEL1PLLDOWN requires Clkreq be enabled, so enable it\n")); + sb_pcieclkreq((void *)(uintptr) sbh, 1, 1); + } + reg_val = sb_pcielcreg((void *)(uintptr) sbh, 0, 0); + if (reg_val & PCIE_CAP_LCREG_ASPML0s) { + SB_ERROR(("PCIEL1PLLDOWN requires L0s to be disabled\n")); + reg_val &= ~PCIE_CAP_LCREG_ASPML0s; + sb_pcielcreg((void *)(uintptr) sbh, 1, reg_val); + } else + SB_ERROR(("PCIEL1PLLDOWN: L0s is already disabled\n")); + + /* turnoff intrs, change core, set original back, turn on intrs back on */ + origidx = si->curidx; + INTR_OFF(si, intr_val); + sb_setcore(sbh, SB_PCIE, 0); + + sb_pcie_writereg((void *)(uintptr) sbh, (void *)PCIE_PCIEREGS, + PCIE_DLLP_PCIE11, 0); + + sb_setcoreidx(sbh, origidx); + INTR_RESTORE(si, intr_val); + return 1; +} +#endif /* BCMDBG */ + +/* return TRUE if PCIE capability exists in the pci config space */ +static bool sb_ispcie(sb_info_t * si) +{ + uint8 cap_ptr; + + cap_ptr = sb_find_pci_capability(si, PCI_CAP_PCIECAP_ID, NULL, NULL); + if (!cap_ptr) + return FALSE; + + si->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET; + return TRUE; } -/* return TRUE if PCIE capability exists the pci config space */ -static inline bool -sb_ispcie(sb_info_t *si) +/* Wake-on-wireless-LAN (WOWL) support functions */ +/* return TRUE if PM capability exists in the pci config space */ +bool sb_pci_pmecap(sb_t * sbh) +{ + uint8 cap_ptr; + uint32 pmecap; + sb_info_t *si; + + si = SB_INFO(sbh); + + if (si == NULL || !(PCI(si) || PCIE(si))) + return FALSE; + + if (!si->pmecap_offset) { + cap_ptr = + sb_find_pci_capability(si, PCI_CAP_POWERMGMTCAP_ID, NULL, + NULL); + if (!cap_ptr) + return FALSE; + + si->pmecap_offset = cap_ptr; + + pmecap = + OSL_PCI_READ_CONFIG(si->osh, si->pmecap_offset, + sizeof(uint32)); + + /* At least one state can generate PME */ + si->pmecap = (pmecap & PME_CAP_PM_STATES) != 0; + } + + return (si->pmecap); +} + +/* Enable PME generation and disable clkreq */ +void sb_pci_pmeen(sb_t * sbh) { - return (sb_find_pci_capability(si, PCI_CAP_PCIECAP_ID, NULL, NULL)); + sb_info_t *si; + uint32 w; + si = SB_INFO(sbh); + + /* if not pmecapable return */ + if (!sb_pci_pmecap(sbh)) + return; + + w = OSL_PCI_READ_CONFIG(si->osh, si->pmecap_offset + PME_CSR_OFFSET, + sizeof(uint32)); + w |= (PME_CSR_PME_EN); + OSL_PCI_WRITE_CONFIG(si->osh, si->pmecap_offset + PME_CSR_OFFSET, + sizeof(uint32), w); + + /* Disable clkreq */ + if (si->pr42767_war) { + sb_pcieclkreq(sbh, 1, 0); + si->pr42767_war = FALSE; + } else if (si->sb.pr42780) { + sb_pcieclkreq(sbh, 1, 1); + } } -/* scan the sb enumerated space to identify all cores */ -static void -BCMINITFN(sb_scan)(sb_info_t *si) +/* Disable PME generation, clear the PME status bit if set and + * return TRUE if PME status set + */ +bool sb_pci_pmeclr(sb_t * sbh) { + sb_info_t *si; + uint32 w; + bool ret = FALSE; + + si = SB_INFO(sbh); + + if (!sb_pci_pmecap(sbh)) + return ret; + + w = OSL_PCI_READ_CONFIG(si->osh, si->pmecap_offset + PME_CSR_OFFSET, + sizeof(uint32)); + + SB_ERROR(("sb_pci_pmeclr PMECSR : 0x%x\n", w)); + ret = (w & PME_CSR_PME_STAT) == PME_CSR_PME_STAT; + + /* PMESTAT is cleared by writing 1 to it */ + w &= ~(PME_CSR_PME_EN); + + OSL_PCI_WRITE_CONFIG(si->osh, si->pmecap_offset + PME_CSR_OFFSET, + sizeof(uint32), w); + + return ret; +} + +/* use pci dev id to determine chip id for chips not having a chipcommon core */ +static uint BCMINITFN(sb_pcidev2chip) (uint pcidev) { + if ((pcidev >= BCM4710_DEVICE_ID) && (pcidev <= BCM47XX_USB_ID)) + return (BCM4710_CHIP_ID); + if ((pcidev >= BCM4402_ENET_ID) && (pcidev <= BCM4402_V90_ID)) + return (BCM4402_CHIP_ID); + if (pcidev == BCM4401_ENET_ID) + return (BCM4402_CHIP_ID); + if (pcidev == SDIOH_FPGA_ID) + return (SDIOH_FPGA_ID); + + return (0); +} + +/* Scan the enumeration space to find all cores starting from the given + * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba' + * is the default core address at chip POR time and 'regs' is the virtual + * address that the default core is mapped at. 'ncores' is the number of + * cores expected on bus 'sbba'. It returns the total number of cores + * starting from bus 'sbba', inclusive. + */ + +static void BCMINITFN(sb_scan) (sb_info_t * si) { + sb_t *sbh; uint origidx; uint i; bool pci; @@ -902,6 +1324,7 @@ BCMINITFN(sb_scan)(sb_info_t *si) uint pcirev; uint pcierev; + sbh = (sb_t *) si; /* numcores should already be set */ ASSERT((si->numcores > 0) && (si->numcores <= SB_MAXCORES)); @@ -959,14 +1382,14 @@ BCMINITFN(sb_scan)(sb_info_t *si) * - 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(si, SB_CC, 0))) { - si->gpioidx = sb_findcoreidx(si, SB_CC, 0); + if (GOODIDX(sb_findcoreidx(sbh, SB_CC, 0))) { + si->gpioidx = sb_findcoreidx(sbh, SB_CC, 0); si->gpioid = SB_CC; } else if (PCI(si) && (si->sb.buscorerev >= 2)) { si->gpioidx = si->sb.buscoreidx; si->gpioid = SB_PCI; - } else if (sb_findcoreidx(si, SB_EXTIF, 0)) { - si->gpioidx = sb_findcoreidx(si, SB_EXTIF, 0); + } else if (sb_findcoreidx(sbh, SB_EXTIF, 0)) { + si->gpioidx = sb_findcoreidx(sbh, SB_EXTIF, 0); si->gpioid = SB_EXTIF; } else ASSERT(si->gpioidx != BADIDX); @@ -976,8 +1399,7 @@ BCMINITFN(sb_scan)(sb_info_t *si) } /* may be called with core in reset */ -void -sb_detach(sb_t *sbh) +void sb_detach(sb_t * sbh) { sb_info_t *si; uint idx; @@ -995,29 +1417,13 @@ sb_detach(sb_t *sbh) } #if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SB_BUS) if (si != &ksi) -#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SB_BUS) */ +#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SB_BUS) */ MFREE(si->osh, si, sizeof(sb_info_t)); - } -/* use pci dev id to determine chip id for chips not having a chipcommon core */ -static uint -BCMINITFN(sb_pcidev2chip)(uint pcidev) -{ - if ((pcidev >= BCM4710_DEVICE_ID) && (pcidev <= BCM47XX_USB_ID)) - return (BCM4710_CHIP_ID); - if ((pcidev >= BCM4402_ENET_ID) && (pcidev <= BCM4402_V90_ID)) - return (BCM4402_CHIP_ID); - if (pcidev == BCM4401_ENET_ID) - return (BCM4402_CHIP_ID); - - return (0); -} /* convert chip number to number of i/o cores */ -static uint -BCMINITFN(sb_chip2numcores)(uint chip) -{ +static uint BCMINITFN(sb_chip2numcores) (uint chip) { if (chip == BCM4710_CHIP_ID) return (9); if (chip == BCM4402_CHIP_ID) @@ -1028,6 +1434,8 @@ BCMINITFN(sb_chip2numcores)(uint chip) return (9); if (chip == BCM5365_CHIP_ID) return (7); + if (chip == SDIOH_FPGA_ID) + return (2); SB_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", chip)); ASSERT(0); @@ -1035,12 +1443,14 @@ BCMINITFN(sb_chip2numcores)(uint chip) } /* return index of coreid or BADIDX if not found */ -static uint -sb_findcoreidx(sb_info_t *si, uint coreid, uint coreunit) +uint sb_findcoreidx(sb_t * 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++) @@ -1058,8 +1468,7 @@ sb_findcoreidx(sb_info_t *si, uint coreid, uint coreunit) * must be called with interrupt off. * Moreover, callers should keep interrupts off during switching out of and back to d11 core */ -void* -sb_setcoreidx(sb_t *sbh, uint coreidx) +void *sb_setcoreidx(sb_t * sbh, uint coreidx) { sb_info_t *si; uint32 sbaddr; @@ -1074,7 +1483,8 @@ sb_setcoreidx(sb_t *sbh, uint coreidx) * 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)); + ASSERT((si->intrsenabled_fn == NULL) + || !(*(si)->intrsenabled_fn) ((si)->intr_arg)); sbaddr = SB_ENUM_BASE + (coreidx * SB_CORE_SIZE); @@ -1082,7 +1492,8 @@ sb_setcoreidx(sb_t *sbh, uint coreidx) case SB_BUS: /* map new one */ if (!si->regs[coreidx]) { - si->regs[coreidx] = (void*)REG_MAP(sbaddr, SB_CORE_SIZE); + si->regs[coreidx] = + (void *)REG_MAP(sbaddr, SB_CORE_SIZE); ASSERT(GOODREGS(si->regs[coreidx])); } si->curmap = si->regs[coreidx]; @@ -1110,7 +1521,7 @@ sb_setcoreidx(sb_t *sbh, uint coreidx) } si->curmap = si->regs[coreidx]; break; -#endif /* BCMJTAG */ +#endif /* BCMJTAG */ } si->curidx = coreidx; @@ -1123,14 +1534,11 @@ sb_setcoreidx(sb_t *sbh, uint coreidx) * must be called with interrupt off. * Moreover, callers should keep interrupts off during switching out of and back to d11 core */ -void* -sb_setcore(sb_t *sbh, uint coreid, uint coreunit) +void *sb_setcore(sb_t * sbh, uint coreid, uint coreunit) { - sb_info_t *si; uint idx; - si = SB_INFO(sbh); - idx = sb_findcoreidx(si, coreid, coreunit); + idx = sb_findcoreidx(sbh, coreid, coreunit); if (!GOODIDX(idx)) return (NULL); @@ -1138,9 +1546,7 @@ sb_setcore(sb_t *sbh, uint coreid, uint coreunit) } /* return chip number */ -uint -sb_chip(sb_t *sbh) -{ +uint BCMINITFN(sb_chip) (sb_t * sbh) { sb_info_t *si; si = SB_INFO(sbh); @@ -1148,9 +1554,7 @@ sb_chip(sb_t *sbh) } /* return chip revision number */ -uint -sb_chiprev(sb_t *sbh) -{ +uint BCMINITFN(sb_chiprev) (sb_t * sbh) { sb_info_t *si; si = SB_INFO(sbh); @@ -1158,9 +1562,7 @@ sb_chiprev(sb_t *sbh) } /* return chip common revision number */ -uint -sb_chipcrev(sb_t *sbh) -{ +uint BCMINITFN(sb_chipcrev) (sb_t * sbh) { sb_info_t *si; si = SB_INFO(sbh); @@ -1168,9 +1570,7 @@ sb_chipcrev(sb_t *sbh) } /* return chip package option */ -uint -sb_chippkg(sb_t *sbh) -{ +uint BCMINITFN(sb_chippkg) (sb_t * sbh) { sb_info_t *si; si = SB_INFO(sbh); @@ -1178,18 +1578,14 @@ sb_chippkg(sb_t *sbh) } /* return PCI core rev. */ -uint -sb_pcirev(sb_t *sbh) -{ +uint BCMINITFN(sb_pcirev) (sb_t * sbh) { sb_info_t *si; si = SB_INFO(sbh); return (si->sb.buscorerev); } -bool -BCMINITFN(sb_war16165)(sb_t *sbh) -{ +bool BCMINITFN(sb_war16165) (sb_t * sbh) { sb_info_t *si; si = SB_INFO(sbh); @@ -1197,18 +1593,14 @@ BCMINITFN(sb_war16165)(sb_t *sbh) return (PCI(si) && (si->sb.buscorerev <= 10)); } -static void -BCMINITFN(sb_war30841)(sb_info_t *si) -{ +static void BCMINITFN(sb_war30841) (sb_info_t * si) { sb_pcie_mdiowrite(si, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128); sb_pcie_mdiowrite(si, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100); sb_pcie_mdiowrite(si, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466); } /* return PCMCIA core rev. */ -uint -BCMINITFN(sb_pcmciarev)(sb_t *sbh) -{ +uint BCMINITFN(sb_pcmciarev) (sb_t * sbh) { sb_info_t *si; si = SB_INFO(sbh); @@ -1216,9 +1608,7 @@ BCMINITFN(sb_pcmciarev)(sb_t *sbh) } /* return board vendor id */ -uint -sb_boardvendor(sb_t *sbh) -{ +uint BCMINITFN(sb_boardvendor) (sb_t * sbh) { sb_info_t *si; si = SB_INFO(sbh); @@ -1226,9 +1616,7 @@ sb_boardvendor(sb_t *sbh) } /* return boardtype */ -uint -sb_boardtype(sb_t *sbh) -{ +uint BCMINITFN(sb_boardtype) (sb_t * sbh) { sb_info_t *si; char *var; @@ -1239,7 +1627,8 @@ sb_boardtype(sb_t *sbh) si->sb.boardtype = getintvar(NULL, "boardtype"); /* backward compatibility for older boardtype string format */ - if ((si->sb.boardtype == 0) && (var = getvar(NULL, "boardtype"))) { + if ((si->sb.boardtype == 0) + && (var = getvar(NULL, "boardtype"))) { if (!strcmp(var, "bcm94710dev")) si->sb.boardtype = BCM94710D_BOARD; else if (!strcmp(var, "bcm94710ap")) @@ -1263,8 +1652,7 @@ sb_boardtype(sb_t *sbh) } /* return bus type of sbh device */ -uint -sb_bus(sb_t *sbh) +uint sb_bus(sb_t * sbh) { sb_info_t *si; @@ -1273,8 +1661,7 @@ sb_bus(sb_t *sbh) } /* return bus core type */ -uint -sb_buscoretype(sb_t *sbh) +uint sb_buscoretype(sb_t * sbh) { sb_info_t *si; @@ -1284,8 +1671,7 @@ sb_buscoretype(sb_t *sbh) } /* return bus core revision */ -uint -sb_buscorerev(sb_t *sbh) +uint sb_buscorerev(sb_t * sbh) { sb_info_t *si; si = SB_INFO(sbh); @@ -1294,20 +1680,19 @@ sb_buscorerev(sb_t *sbh) } /* return list of found cores */ -uint -sb_corelist(sb_t *sbh, uint coreid[]) +uint sb_corelist(sb_t * sbh, uint coreid[]) { sb_info_t *si; si = SB_INFO(sbh); - bcopy((uchar*)si->coreid, (uchar*)coreid, (si->numcores * sizeof(uint))); + bcopy((uchar *) si->coreid, (uchar *) coreid, + (si->numcores * sizeof(uint))); return (si->numcores); } /* return current register mapping */ -void * -sb_coreregs(sb_t *sbh) +void *sb_coreregs(sb_t * sbh) { sb_info_t *si; @@ -1317,10 +1702,166 @@ sb_coreregs(sb_t *sbh) return (si->curmap); } +#if defined(BCMDBG_ASSERT) +/* traverse all cores to find and clear source of serror */ +static void sb_serr_clear(sb_info_t * si) +{ + sbconfig_t *sb; + uint origidx; + uint i, intr_val = 0; + void *corereg = NULL; + + INTR_OFF(si, intr_val); + origidx = sb_coreidx(&si->sb); + + for (i = 0; i < si->numcores; i++) { + corereg = sb_setcoreidx(&si->sb, i); + if (NULL != corereg) { + sb = REGS2SB(corereg); + if ((R_SBREG(si, &sb->sbtmstatehigh)) & SBTMH_SERR) { + AND_SBREG(si, &sb->sbtmstatehigh, ~SBTMH_SERR); + SB_ERROR(("sb_serr_clear: SError at core 0x%x\n", sb_coreid(&si->sb))); + } + } + } + + sb_setcoreidx(&si->sb, 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(sb_t * 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 (BUSTYPE(si->sb.bustype) == 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) { +#ifdef BCMDBG + SB_ERROR(("inband:\n")); + sb_viewall((void *)si); +#endif + 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) { +#ifdef BCMDBG + SB_ERROR(("serror:\n")); + sb_viewall((void *)si); +#endif + sb_serr_clear(si); + OSL_PCI_WRITE_CONFIG(si->osh, PCI_INT_STATUS, + sizeof(uint32), stcmd); + } + + /* timeout */ + imstate = sb_corereg(sbh, si->sb.buscoreidx, + SBCONFIGOFF + OFFSETOF(sbconfig_t, + sbimstate), 0, 0); + if ((imstate != 0xffffffff) && (imstate & (SBIM_IBE | SBIM_TO))) { + sb_corereg(sbh, si->sb.buscoreidx, + SBCONFIGOFF + OFFSETOF(sbconfig_t, + sbimstate), ~0, + (imstate & ~(SBIM_IBE | SBIM_TO))); + /* inband = imstate & SBIM_IBE; same as TA above */ + timeout = imstate & SBIM_TO; + if (timeout) { +#ifdef BCMDBG + SB_ERROR(("timeout:\n")); + sb_viewall((void *)si); +#endif + } + } + + if (inband) { + /* dump errlog for sonics >= 2.3 */ + if (si->sb.sonicsrev == SONICS_2_2) ; + else { + uint32 imerrlog, imerrloga; + imerrlog = + sb_corereg(sbh, si->sb.buscoreidx, + SBIMERRLOG, 0, 0); + if (imerrlog & SBTMEL_EC) { + imerrloga = + sb_corereg(sbh, si->sb.buscoreidx, + SBIMERRLOGA, 0, 0); + /* clear errlog */ + sb_corereg(sbh, si->sb.buscoreidx, + SBIMERRLOG, ~0, 0); + SB_ERROR(("sb_taclear: ImErrLog 0x%x, ImErrLogA 0x%x\n", imerrlog, imerrloga)); + } + } + } + + } else if (BUSTYPE(si->sb.bustype) == 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(si, &sb->sbimstate); + /* handle surprise removal */ + if ((imstate != 0xffffffff) + && (imstate & (SBIM_IBE | SBIM_TO))) { + AND_SBREG(si, &sb->sbimstate, + ~(SBIM_IBE | SBIM_TO)); + inband = imstate & SBIM_IBE; + timeout = imstate & SBIM_TO; + } + tmstate = R_SBREG(si, &sb->sbtmstatehigh); + if ((tmstate != 0xffffffff) + && (tmstate & SBTMH_INT_STATUS)) { + if (!inband) { + serror = 1; + sb_serr_clear(si); + } + OR_SBREG(si, &sb->sbtmstatelow, SBTML_INT_ACK); + AND_SBREG(si, &sb->sbtmstatelow, + ~SBTML_INT_ACK); + } + } + sb_setcoreidx(sbh, origidx); + INTR_RESTORE(si, intr_val); + + } + + if (inband | timeout | serror) { + rc = TRUE; + SB_ERROR(("sb_taclear: inband 0x%x, serror 0x%x, timeout 0x%x!\n", inband, serror, timeout)); + } + + return (rc); +} +#endif /* BCMDBG */ /* do buffered registers update */ -void -sb_commit(sb_t *sbh) +void sb_commit(sb_t * sbh) { sb_info_t *si; uint origidx; @@ -1335,13 +1876,14 @@ sb_commit(sb_t *sbh) /* switch over to chipcommon core if there is one, else use pci */ if (si->sb.ccrev != NOREV) { - chipcregs_t *ccregs = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0); + chipcregs_t *ccregs = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0); /* do the buffer registers update */ W_REG(si->osh, &ccregs->broadcastaddress, SB_COMMIT); W_REG(si->osh, &ccregs->broadcastdata, 0x0); } else if (PCI(si)) { - sbpciregs_t *pciregs = (sbpciregs_t *)sb_setcore(sbh, SB_PCI, 0); + sbpciregs_t *pciregs = + (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0); /* do the buffer registers update */ W_REG(si->osh, &pciregs->bcastaddr, SB_COMMIT); @@ -1359,8 +1901,7 @@ sb_commit(sb_t *sbh) * bits - core specific bits that are set during and after reset sequence * resetbits - core specific bits that are set only during reset sequence */ -void -sb_core_reset(sb_t *sbh, uint32 bits, uint32 resetbits) +void sb_core_reset(sb_t * sbh, uint32 bits, uint32 resetbits) { sb_info_t *si; sbconfig_t *sb; @@ -1380,7 +1921,8 @@ sb_core_reset(sb_t *sbh, uint32 bits, uint32 resetbits) */ /* set reset while enabling the clock and forcing them on throughout the core */ - W_SBREG(si, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | SBTML_RESET | bits | resetbits)); + W_SBREG(si, &sb->sbtmstatelow, + (SBTML_FGC | SBTML_CLK | SBTML_RESET | bits | resetbits)); dummy = R_SBREG(si, &sb->sbtmstatelow); OSL_DELAY(1); @@ -1402,8 +1944,7 @@ sb_core_reset(sb_t *sbh, uint32 bits, uint32 resetbits) OSL_DELAY(1); } -void -sb_core_tofixup(sb_t *sbh) +void sb_core_tofixup(sb_t * sbh) { sb_info_t *si; sbconfig_t *sb; @@ -1419,15 +1960,16 @@ sb_core_tofixup(sb_t *sbh) if (BUSTYPE(si->sb.bustype) == SB_BUS) { SET_SBREG(si, &sb->sbimconfiglow, - SBIMCL_RTO_MASK | SBIMCL_STO_MASK, - (0x5 << SBIMCL_RTO_SHIFT) | 0x3); + SBIMCL_RTO_MASK | SBIMCL_STO_MASK, + (0x5 << SBIMCL_RTO_SHIFT) | 0x3); } else { if (sb_coreid(sbh) == SB_PCI) { SET_SBREG(si, &sb->sbimconfiglow, - SBIMCL_RTO_MASK | SBIMCL_STO_MASK, - (0x3 << SBIMCL_RTO_SHIFT) | 0x2); + SBIMCL_RTO_MASK | SBIMCL_STO_MASK, + (0x3 << SBIMCL_RTO_SHIFT) | 0x2); } else { - SET_SBREG(si, &sb->sbimconfiglow, (SBIMCL_RTO_MASK | SBIMCL_STO_MASK), 0); + SET_SBREG(si, &sb->sbimconfiglow, + (SBIMCL_RTO_MASK | SBIMCL_STO_MASK), 0); } } @@ -1458,11 +2000,10 @@ sb_core_tofixup(sb_t *sbh) #define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK) -uint32 -sb_set_initiator_to(sb_t *sbh, uint32 to) +uint32 sb_set_initiator_to(sb_t * sbh, uint32 to, uint idx) { sb_info_t *si; - uint origidx, idx; + uint origidx; uint intr_val = 0; uint32 tmp, ret = 0xffffffff; sbconfig_t *sb; @@ -1473,27 +2014,28 @@ sb_set_initiator_to(sb_t *sbh, uint32 to) return ret; /* Figure out the master core */ - idx = BADIDX; - switch (BUSTYPE(si->sb.bustype)) { - case PCI_BUS: - idx = si->sb.buscoreidx; - break; - case JTAG_BUS: - idx = SB_CC_IDX; - break; - case PCMCIA_BUS: - case SDIO_BUS: - idx = sb_findcoreidx(si, SB_PCMCIA, 0); - break; - case SB_BUS: - if ((idx = sb_findcoreidx(si, SB_MIPS33, 0)) == BADIDX) - idx = sb_findcoreidx(si, SB_MIPS, 0); - break; - default: - ASSERT(0); + if (idx == BADIDX) { + switch (BUSTYPE(si->sb.bustype)) { + case PCI_BUS: + idx = si->sb.buscoreidx; + break; + case JTAG_BUS: + idx = SB_CC_IDX; + break; + case PCMCIA_BUS: + case SDIO_BUS: + idx = sb_findcoreidx(sbh, SB_PCMCIA, 0); + break; + case SB_BUS: + if ((idx = sb_findcoreidx(sbh, SB_MIPS33, 0)) == BADIDX) + idx = sb_findcoreidx(sbh, SB_MIPS, 0); + break; + default: + ASSERT(0); + } + if (idx == BADIDX) + return ret; } - if (idx == BADIDX) - return ret; INTR_OFF(si, intr_val); origidx = sb_coreidx(sbh); @@ -1510,8 +2052,7 @@ sb_set_initiator_to(sb_t *sbh, uint32 to) return ret; } -void -sb_core_disable(sb_t *sbh, uint32 bits) +void sb_core_disable(sb_t * sbh, uint32 bits) { sb_info_t *si; volatile uint32 dummy; @@ -1553,7 +2094,8 @@ sb_core_disable(sb_t *sbh, uint32 bits) } /* set reset and reject while enabling the clocks */ - W_SBREG(si, &sb->sbtmstatelow, (bits | SBTML_FGC | SBTML_CLK | rej | SBTML_RESET)); + W_SBREG(si, &sb->sbtmstatelow, + (bits | SBTML_FGC | SBTML_CLK | rej | SBTML_RESET)); dummy = R_SBREG(si, &sb->sbtmstatelow); OSL_DELAY(10); @@ -1561,50 +2103,43 @@ sb_core_disable(sb_t *sbh, uint32 bits) if (R_SBREG(si, &sb->sbidlow) & SBIDL_INIT) AND_SBREG(si, &sb->sbimstate, ~SBIM_RJ); -disable: + disable: /* leave reset and reject asserted */ W_SBREG(si, &sb->sbtmstatelow, (bits | rej | SBTML_RESET)); OSL_DELAY(1); } /* set chip watchdog reset timer to fire in 'ticks' backplane cycles */ -void -sb_watchdog(sb_t *sbh, uint ticks) +void sb_watchdog(sb_t * sbh, uint ticks) { sb_info_t *si = SB_INFO(sbh); - /* make sure we come up in fast clock mode */ - sb_clkctl_clk(sbh, CLK_FAST); + /* make sure we come up in fast clock mode; or if clearing, clear clock */ + if (ticks) + sb_clkctl_clk(sbh, CLK_FAST); + else + sb_clkctl_clk(sbh, CLK_DYNAMIC); + + if (sbh->chip == BCM4328_CHIP_ID && ticks != 0) + sb_corereg(sbh, SB_CC_IDX, OFFSETOF(chipcregs_t, min_res_mask), + PMURES_BIT(RES4328_ROM_SWITCH), + PMURES_BIT(RES4328_ROM_SWITCH)); /* instant NMI */ switch (si->gpioid) { case SB_CC: -#ifdef __mips__ - if (sb_chip(sbh) == BCM4785_CHIP_ID && ticks <= 1) - MTC0(C0_BROADCOM, 4, (1 << 22)); -#endif /* __mips__ */ - sb_corereg(si, 0, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); -#ifdef __mips__ - if (sb_chip(sbh) == BCM4785_CHIP_ID && ticks <= 1) { - __asm__ __volatile__ ( - ".set\tmips3\n\t" - "sync\n\t" - "wait\n\t" - ".set\tmips0" - ); - while (1); - } -#endif /* __mips__ */ + sb_corereg(sbh, SB_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, + ticks); break; case SB_EXTIF: - sb_corereg(si, si->gpioidx, OFFSETOF(extifregs_t, watchdog), ~0, ticks); + sb_corereg(sbh, si->gpioidx, OFFSETOF(extifregs_t, watchdog), + ~0, ticks); break; } } /* initialize the pcmcia core */ -void -sb_pcmcia_init(sb_t *sbh) +void sb_pcmcia_init(sb_t * sbh) { sb_info_t *si; uint8 cor = 0; @@ -1618,21 +2153,120 @@ sb_pcmcia_init(sb_t *sbh) } +void BCMINITFN(sb_pci_up) (sb_t * sbh) { + sb_info_t *si = SB_INFO(sbh); + if (si->gpioid == SB_EXTIF) + return; + + /* if not pci bus, we're done */ + if (BUSTYPE(si->sb.bustype) != PCI_BUS) + return; + + if (FORCEHT_WAR32414(si)) + sb_war32414_forceHT(sbh, 1); + + if (PCIE_ASPMWARS(si) || si->sb.pr42780) + sb_pcieclkreq(sbh, 1, 0); + + if (PCIE(si) && + (((si->sb.chip == BCM4311_CHIP_ID) && (si->sb.chiprev == 2)) || + ((si->sb.chip == BCM4312_CHIP_ID) && (si->sb.chiprev == 0)))) + sb_set_initiator_to((void *)si, 0x3, + sb_findcoreidx((void *)si, SB_D11, 0)); +} + +/* Unconfigure and/or apply various WARs when system is going to sleep mode */ +void BCMUNINITFN(sb_pci_sleep) (sb_t * sbh) { + sb_info_t *si = SB_INFO(sbh); + if (si->gpioid == SB_EXTIF) + return; + uint32 w; + + /* if not pci bus, we're done */ + if (!PCIE(si) || !PCIE_ASPMWARS(si)) + return; + + w = OSL_PCI_READ_CONFIG(si->osh, si->pciecap_lcreg_offset, + sizeof(uint32)); + w &= ~PCIE_CAP_LCREG_ASPML1; + OSL_PCI_WRITE_CONFIG(si->osh, si->pciecap_lcreg_offset, sizeof(uint32), + w); +} + +/* Unconfigure and/or apply various WARs when going down */ +void BCMINITFN(sb_pci_down) (sb_t * sbh) { + sb_info_t *si = SB_INFO(sbh); + if (si->gpioid == SB_EXTIF) + return; + + /* if not pci bus, we're done */ + if (BUSTYPE(si->sb.bustype) != PCI_BUS) + return; + + if (FORCEHT_WAR32414(si)) + sb_war32414_forceHT(sbh, 0); + + if (si->pr42767_war) { + sb_pcieclkreq(sbh, 1, 1); + si->pr42767_war = FALSE; + } else if (si->sb.pr42780) { + sb_pcieclkreq(sbh, 1, 1); + } +} + +static void BCMINITFN(sb_war42767_clkreq) (sb_t * sbh) { + sbpcieregs_t *pcieregs; + uint16 val16, *reg16; + sb_info_t *si; + + si = SB_INFO(sbh); + + /* if not pcie bus, we're done */ + if (!PCIE(si) || !PCIE_ASPMWARS(si)) + return; + + pcieregs = (sbpcieregs_t *) sb_setcoreidx(sbh, si->sb.buscoreidx); + reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET]; + val16 = R_REG(si->osh, reg16); + /* if clockreq is not advertized advertize it */ + if (!si->pcie_war_ovr) { + val16 |= SRSH_CLKREQ_ENB; + si->pr42767_war = TRUE; + + si->sb.pr42780 = TRUE; + } else + val16 &= ~SRSH_CLKREQ_ENB; + W_REG(si->osh, reg16, val16); +} + +static void BCMINITFN(sb_war42767) (sb_t * sbh) { + uint32 w = 0; + sb_info_t *si; + + si = SB_INFO(sbh); + + /* if not pcie bus, we're done */ + if (!PCIE(si) || !PCIE_ASPMWARS(si)) + return; + + sb_pcie_mdioread(si, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w); + if (w & PLL_CTRL_FREQDET_EN) { + w &= ~PLL_CTRL_FREQDET_EN; + sb_pcie_mdiowrite(si, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w); + } +} /* * Configure the pci core for pci client (NIC) action * coremask is the bitvec of cores by index to be enabled. */ -void -BCMINITFN(sb_pci_setup)(sb_t *sbh, uint coremask) -{ +void BCMINITFN(sb_pci_setup) (sb_t * sbh, uint coremask) { sb_info_t *si; sbconfig_t *sb; sbpciregs_t *pciregs; uint32 sbflag; uint32 w; uint idx; - int reg_val; si = SB_INFO(sbh); @@ -1652,7 +2286,7 @@ BCMINITFN(sb_pci_setup)(sb_t *sbh, uint coremask) sbflag = R_SBREG(si, &sb->sbtpsflag) & SBTPS_NUM0_MASK; /* switch over to pci core */ - pciregs = (sbpciregs_t*) sb_setcoreidx(sbh, si->sb.buscoreidx); + pciregs = (sbpciregs_t *) sb_setcoreidx(sbh, si->sb.buscoreidx); sb = REGS2SB(pciregs); /* @@ -1670,45 +2304,69 @@ BCMINITFN(sb_pci_setup)(sb_t *sbh, uint coremask) } if (PCI(si)) { - OR_REG(si->osh, &pciregs->sbtopci2, (SBTOPCI_PREF|SBTOPCI_BURST)); + OR_REG(si->osh, &pciregs->sbtopci2, + (SBTOPCI_PREF | SBTOPCI_BURST)); if (si->sb.buscorerev >= 11) - OR_REG(si->osh, &pciregs->sbtopci2, SBTOPCI_RC_READMULTI); + OR_REG(si->osh, &pciregs->sbtopci2, + SBTOPCI_RC_READMULTI); if (si->sb.buscorerev < 5) { - SET_SBREG(si, &sb->sbimconfiglow, SBIMCL_RTO_MASK | SBIMCL_STO_MASK, - (0x3 << SBIMCL_RTO_SHIFT) | 0x2); + SET_SBREG(si, &sb->sbimconfiglow, + SBIMCL_RTO_MASK | SBIMCL_STO_MASK, + (0x3 << SBIMCL_RTO_SHIFT) | 0x2); sb_commit(sbh); } } -#ifdef PCIE_SUPPOER /* PCIE workarounds */ if (PCIE(si)) { if ((si->sb.buscorerev == 0) || (si->sb.buscorerev == 1)) { - reg_val = sb_pcie_readreg((void *)sbh, (void *)PCIE_PCIEREGS, - PCIE_TLP_WORKAROUNDSREG); - reg_val |= 0x8; - sb_pcie_writereg((void *)sbh, (void *)PCIE_PCIEREGS, - PCIE_TLP_WORKAROUNDSREG, reg_val); + w = sb_pcie_readreg((void *)(uintptr) sbh, + (void *)(uintptr) PCIE_PCIEREGS, + PCIE_TLP_WORKAROUNDSREG); + w |= 0x8; + sb_pcie_writereg((void *)(uintptr) sbh, + (void *)(uintptr) PCIE_PCIEREGS, + PCIE_TLP_WORKAROUNDSREG, w); } if (si->sb.buscorerev == 1) { - reg_val = sb_pcie_readreg((void *)sbh, (void *)PCIE_PCIEREGS, - PCIE_DLLP_LCREG); - reg_val |= (0x40); - sb_pcie_writereg(sbh, (void *)PCIE_PCIEREGS, PCIE_DLLP_LCREG, reg_val); + w = sb_pcie_readreg((void *)(uintptr) sbh, + (void *)(uintptr) PCIE_PCIEREGS, + PCIE_DLLP_LCREG); + w |= (0x40); + sb_pcie_writereg((void *)(uintptr) sbh, + (void *)(uintptr) PCIE_PCIEREGS, + PCIE_DLLP_LCREG, w); } if (si->sb.buscorerev == 0) sb_war30841(si); + + if ((si->sb.buscorerev >= 3) && (si->sb.buscorerev <= 5)) { + w = sb_pcie_readreg((void *)(uintptr) sbh, + (void *)(uintptr) PCIE_PCIEREGS, + PCIE_DLLP_PMTHRESHREG); + w &= ~(PCIE_L1THRESHOLDTIME_MASK); + w |= (PCIE_L1THRESHOLD_WARVAL << + PCIE_L1THRESHOLDTIME_SHIFT); + sb_pcie_writereg((void *)(uintptr) sbh, + (void *)(uintptr) PCIE_PCIEREGS, + PCIE_DLLP_PMTHRESHREG, w); + + sb_war43448(sbh); + + sb_war42767(sbh); + + sb_war43448_aspm(sbh); + sb_war42767_clkreq(sbh); + } } -#endif /* switch back to previous core */ sb_setcoreidx(sbh, idx); } -uint32 -sb_base(uint32 admatch) +uint32 sb_base(uint32 admatch) { uint32 base; uint type; @@ -1731,8 +2389,7 @@ sb_base(uint32 admatch) return (base); } -uint32 -sb_size(uint32 admatch) +uint32 sb_size(uint32 admatch) { uint32 size; uint type; @@ -1743,21 +2400,26 @@ sb_size(uint32 admatch) size = 0; if (type == 0) { - size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1); + 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); + 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); + size = + 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + + 1); } return (size); } /* return the core-type instantiation # of the current core */ -uint -sb_coreunit(sb_t *sbh) +uint sb_coreunit(sb_t * sbh) { sb_info_t *si; uint idx; @@ -1781,24 +2443,27 @@ sb_coreunit(sb_t *sbh) return (coreunit); } -static INLINE uint32 -factor6(uint32 x) -{ +static uint32 BCMINITFN(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; + 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 BCMINITFN(sb_clock_rate) (uint32 pll_type, uint32 n, uint32 m) { uint32 n1, n2, clock, m1, m2, m3, mc; n1 = n & CN_N1_MASK; @@ -1810,9 +2475,8 @@ sb_clock_rate(uint32 pll_type, uint32 n, uint32 m) else return CC_T6_M0; } else if ((pll_type == PLL_TYPE1) || - (pll_type == PLL_TYPE3) || - (pll_type == PLL_TYPE4) || - (pll_type == PLL_TYPE7)) { + (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) { @@ -1825,9 +2489,8 @@ sb_clock_rate(uint32 pll_type, uint32 n, uint32 m) } 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; + if ((pll_type == PLL_TYPE3) || (pll_type == PLL_TYPE7)) { + clock = CC_CLOCK_BASE2 * n1 * n2; } else clock = CC_CLOCK_BASE1 * n1 * n2; @@ -1841,8 +2504,7 @@ sb_clock_rate(uint32 pll_type, uint32 n, uint32 m) if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3) || - (pll_type == PLL_TYPE4) || - (pll_type == PLL_TYPE7)) { + (pll_type == PLL_TYPE4) || (pll_type == PLL_TYPE7)) { m1 = factor6(m1); if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3)) m2 += CC_F5_BIAS; @@ -1851,12 +2513,18 @@ sb_clock_rate(uint32 pll_type, uint32 n, uint32 m) 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); + 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); @@ -1880,15 +2548,13 @@ sb_clock_rate(uint32 pll_type, uint32 n, uint32 m) } /* returns the current speed the SB is running at */ -uint32 -sb_clock(sb_t *sbh) -{ +uint32 BCMINITFN(sb_clock) (sb_t * sbh) { sb_info_t *si; extifregs_t *eir; chipcregs_t *cc; uint32 n, m; uint idx; - uint32 pll_type, rate; + uint32 cap, pll_type, rate; uint intr_val = 0; si = SB_INFO(sbh); @@ -1902,7 +2568,24 @@ sb_clock(sb_t *sbh) n = R_REG(si->osh, &eir->clockcontrol_n); m = R_REG(si->osh, &eir->clockcontrol_sb); } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) { - pll_type = R_REG(si->osh, &cc->capabilities) & CAP_PLL_MASK; + + cap = R_REG(si->osh, &cc->capabilities); + + if (cap & CC_CAP_PMU) { + + if (sb_chip(sbh) == BCM5354_CHIP_ID) { + /* 5354 has a constant sb clock of 120MHz */ + rate = 120000000; + goto end; + } else + if (sb_chip(sbh) == BCM4328_CHIP_ID) { + rate = 80000000; + goto end; + } else + ASSERT(0); + } + + pll_type = cap & CC_CAP_PLL_MASK; if (pll_type == PLL_NONE) { INTR_RESTORE(si, intr_val); return 80000000; @@ -1910,7 +2593,8 @@ sb_clock(sb_t *sbh) n = R_REG(si->osh, &cc->clockcontrol_n); if (pll_type == PLL_TYPE6) m = R_REG(si->osh, &cc->clockcontrol_m3); - else if ((pll_type == PLL_TYPE3) && !(BCMINIT(sb_chip)(sbh) == 0x5365)) + else if (pll_type == PLL_TYPE3 + && !(BCMINIT(sb_chip) (sbh) == 0x5365)) m = R_REG(si->osh, &cc->clockcontrol_m2); else m = R_REG(si->osh, &cc->clockcontrol_sb); @@ -1920,7 +2604,7 @@ sb_clock(sb_t *sbh) } /* calculate rate */ - if (BCMINIT(sb_chip)(sbh) == 0x5365) + if (BCMINIT(sb_chip) (sbh) == 0x5365) rate = 100000000; else { rate = sb_clock_rate(pll_type, n, m); @@ -1929,6 +2613,7 @@ sb_clock(sb_t *sbh) rate = rate / 2; } + end: /* switch back to previous core */ sb_setcoreidx(sbh, idx); @@ -1937,9 +2622,17 @@ sb_clock(sb_t *sbh) return rate; } +uint32 BCMINITFN(sb_alp_clock) (sb_t * sbh) { + uint32 clock = ALP_CLOCK; + + if (sbh->cccaps & CC_CAP_PMU) + clock = sb_pmu_alp_clock(sbh, sb_osh(sbh)); + + return clock; +} + /* change logical "focus" to the gpio core for optimized access */ -void* -sb_gpiosetcore(sb_t *sbh) +void *sb_gpiosetcore(sb_t * sbh) { sb_info_t *si; @@ -1949,8 +2642,7 @@ sb_gpiosetcore(sb_t *sbh) } /* mask&set gpiocontrol bits */ -uint32 -sb_gpiocontrol(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) +uint32 sb_gpiocontrol(sb_t * sbh, uint32 mask, uint32 val, uint8 priority) { sb_info_t *si; uint regoff; @@ -1958,12 +2650,13 @@ sb_gpiocontrol(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) si = SB_INFO(sbh); regoff = 0; - priority = GPIO_DRV_PRIORITY; /* compatibility hack */ - - /* gpios could be shared on router platforms */ - if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) { + /* gpios could be shared on router platforms + * ignore reservation if it's high priority (e.g., test apps) + */ + if ((priority != GPIO_HI_PRIORITY) && + (BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) { mask = priority ? (sb_gpioreservation & mask) : - ((sb_gpioreservation | mask) & ~(sb_gpioreservation)); + ((sb_gpioreservation | mask) & ~(sb_gpioreservation)); val &= mask; } @@ -1980,12 +2673,11 @@ sb_gpiocontrol(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) return (0); } - return (sb_corereg(si, si->gpioidx, regoff, mask, val)); + return (sb_corereg(sbh, si->gpioidx, regoff, mask, val)); } /* mask&set gpio output enable bits */ -uint32 -sb_gpioouten(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) +uint32 sb_gpioouten(sb_t * sbh, uint32 mask, uint32 val, uint8 priority) { sb_info_t *si; uint regoff; @@ -1993,12 +2685,13 @@ sb_gpioouten(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) si = SB_INFO(sbh); regoff = 0; - priority = GPIO_DRV_PRIORITY; /* compatibility hack */ - - /* gpios could be shared on router platforms */ - if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) { + /* gpios could be shared on router platforms + * ignore reservation if it's high priority (e.g., test apps) + */ + if ((priority != GPIO_HI_PRIORITY) && + (BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) { mask = priority ? (sb_gpioreservation & mask) : - ((sb_gpioreservation | mask) & ~(sb_gpioreservation)); + ((sb_gpioreservation | mask) & ~(sb_gpioreservation)); val &= mask; } @@ -2016,12 +2709,11 @@ sb_gpioouten(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) break; } - return (sb_corereg(si, si->gpioidx, regoff, mask, val)); + return (sb_corereg(sbh, si->gpioidx, regoff, mask, val)); } /* mask&set gpio output bits */ -uint32 -sb_gpioout(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) +uint32 sb_gpioout(sb_t * sbh, uint32 mask, uint32 val, uint8 priority) { sb_info_t *si; uint regoff; @@ -2029,12 +2721,13 @@ sb_gpioout(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) si = SB_INFO(sbh); regoff = 0; - priority = GPIO_DRV_PRIORITY; /* compatibility hack */ - - /* gpios could be shared on router platforms */ - if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) { + /* gpios could be shared on router platforms + * ignore reservation if it's high priority (e.g., test apps) + */ + if ((priority != GPIO_HI_PRIORITY) && + (BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) { mask = priority ? (sb_gpioreservation & mask) : - ((sb_gpioreservation | mask) & ~(sb_gpioreservation)); + ((sb_gpioreservation | mask) & ~(sb_gpioreservation)); val &= mask; } @@ -2052,29 +2745,27 @@ sb_gpioout(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) break; } - return (sb_corereg(si, si->gpioidx, regoff, mask, val)); + return (sb_corereg(sbh, si->gpioidx, regoff, mask, val)); } /* reserve one gpio */ -uint32 -sb_gpioreserve(sb_t *sbh, uint32 gpio_bitmask, uint8 priority) +uint32 sb_gpioreserve(sb_t * sbh, uint32 gpio_bitmask, uint8 priority) { sb_info_t *si; si = SB_INFO(sbh); - priority = GPIO_DRV_PRIORITY; /* compatibility hack */ - /* only cores on SB_BUS share GPIO's and only applcation users need to * reserve/release GPIO */ - if ((BUSTYPE(si->sb.bustype) != SB_BUS) || (!priority)) { + if ((BUSTYPE(si->sb.bustype) != SB_BUS) || (!priority)) { ASSERT((BUSTYPE(si->sb.bustype) == SB_BUS) && (priority)); return -1; } /* make sure only one bit is set */ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { - ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); + ASSERT((gpio_bitmask) + && !((gpio_bitmask) & (gpio_bitmask - 1))); return -1; } @@ -2093,25 +2784,23 @@ sb_gpioreserve(sb_t *sbh, uint32 gpio_bitmask, uint8 priority) * persists till some one overwrites it */ -uint32 -sb_gpiorelease(sb_t *sbh, uint32 gpio_bitmask, uint8 priority) +uint32 sb_gpiorelease(sb_t * sbh, uint32 gpio_bitmask, uint8 priority) { sb_info_t *si; si = SB_INFO(sbh); - priority = GPIO_DRV_PRIORITY; /* compatibility hack */ - /* only cores on SB_BUS share GPIO's and only applcation users need to * reserve/release GPIO */ - if ((BUSTYPE(si->sb.bustype) != SB_BUS) || (!priority)) { + if ((BUSTYPE(si->sb.bustype) != SB_BUS) || (!priority)) { ASSERT((BUSTYPE(si->sb.bustype) == SB_BUS) && (priority)); return -1; } /* make sure only one bit is set */ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { - ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); + ASSERT((gpio_bitmask) + && !((gpio_bitmask) & (gpio_bitmask - 1))); return -1; } @@ -2126,8 +2815,7 @@ sb_gpiorelease(sb_t *sbh, uint32 gpio_bitmask, uint8 priority) } /* return the current gpioin register value */ -uint32 -sb_gpioin(sb_t *sbh) +uint32 sb_gpioin(sb_t * sbh) { sb_info_t *si; uint regoff; @@ -2149,12 +2837,11 @@ sb_gpioin(sb_t *sbh) break; } - return (sb_corereg(si, si->gpioidx, regoff, 0, 0)); + return (sb_corereg(sbh, si->gpioidx, regoff, 0, 0)); } /* mask&set gpio interrupt polarity bits */ -uint32 -sb_gpiointpolarity(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) +uint32 sb_gpiointpolarity(sb_t * sbh, uint32 mask, uint32 val, uint8 priority) { sb_info_t *si; uint regoff; @@ -2162,12 +2849,10 @@ sb_gpiointpolarity(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) si = SB_INFO(sbh); regoff = 0; - priority = GPIO_DRV_PRIORITY; /* compatibility hack */ - /* gpios could be shared on router platforms */ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) { mask = priority ? (sb_gpioreservation & mask) : - ((sb_gpioreservation | mask) & ~(sb_gpioreservation)); + ((sb_gpioreservation | mask) & ~(sb_gpioreservation)); val &= mask; } @@ -2186,12 +2871,11 @@ sb_gpiointpolarity(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) break; } - return (sb_corereg(si, si->gpioidx, regoff, mask, val)); + return (sb_corereg(sbh, si->gpioidx, regoff, mask, val)); } /* mask&set gpio interrupt mask bits */ -uint32 -sb_gpiointmask(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) +uint32 sb_gpiointmask(sb_t * sbh, uint32 mask, uint32 val, uint8 priority) { sb_info_t *si; uint regoff; @@ -2199,12 +2883,10 @@ sb_gpiointmask(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) si = SB_INFO(sbh); regoff = 0; - priority = GPIO_DRV_PRIORITY; /* compatibility hack */ - /* gpios could be shared on router platforms */ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) { mask = priority ? (sb_gpioreservation & mask) : - ((sb_gpioreservation | mask) & ~(sb_gpioreservation)); + ((sb_gpioreservation | mask) & ~(sb_gpioreservation)); val &= mask; } @@ -2223,12 +2905,11 @@ sb_gpiointmask(sb_t *sbh, uint32 mask, uint32 val, uint8 priority) break; } - return (sb_corereg(si, si->gpioidx, regoff, mask, val)); + return (sb_corereg(sbh, si->gpioidx, regoff, mask, val)); } /* assign the gpio to an led */ -uint32 -sb_gpioled(sb_t *sbh, uint32 mask, uint32 val) +uint32 sb_gpioled(sb_t * sbh, uint32 mask, uint32 val) { sb_info_t *si; @@ -2237,12 +2918,13 @@ sb_gpioled(sb_t *sbh, uint32 mask, uint32 val) return -1; /* gpio led powersave reg */ - return (sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); + return (sb_corereg + (sbh, SB_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, + val)); } -/* mask & set gpio timer val */ -uint32 -sb_gpiotimerval(sb_t *sbh, uint32 mask, uint32 gpiotimerval) +/* mask&set gpio timer val */ +uint32 sb_gpiotimerval(sb_t * sbh, uint32 mask, uint32 gpiotimerval) { sb_info_t *si; si = SB_INFO(sbh); @@ -2250,79 +2932,319 @@ sb_gpiotimerval(sb_t *sbh, uint32 mask, uint32 gpiotimerval) if (si->sb.ccrev < 16) return -1; - return (sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval)); + return (sb_corereg(sbh, SB_CC_IDX, + OFFSETOF(chipcregs_t, gpiotimerval), mask, + gpiotimerval)); } - -/* return the slow clock source - LPO, XTAL, or PCI */ -static uint -sb_slowclk_src(sb_info_t *si) +uint32 sb_gpiopull(sb_t * sbh, bool updown, uint32 mask, uint32 val) { - chipcregs_t *cc; - + sb_info_t *si; + uint offs; - ASSERT(sb_coreid(&si->sb) == SB_CC); + si = SB_INFO(sbh); + if (si->sb.ccrev < 20) + return -1; - if (si->sb.ccrev < 6) { - if ((BUSTYPE(si->sb.bustype) == PCI_BUS) && - (OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof(uint32)) & - PCI_CFG_GPIO_SCS)) - return (SCC_SS_PCI); - else - return (SCC_SS_XTAL); - } else if (si->sb.ccrev < 10) { - cc = (chipcregs_t*) sb_setcoreidx(&si->sb, si->curidx); - return (R_REG(si->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); - } else /* Insta-clock */ - return (SCC_SS_XTAL); + offs = + (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : + OFFSETOF(chipcregs_t, gpiopullup)); + return (sb_corereg(sbh, SB_CC_IDX, offs, mask, val)); } -/* return the ILP (slowclock) min or max frequency */ -static uint -sb_slowclk_freq(sb_info_t *si, bool max) +uint32 sb_gpioevent(sb_t * sbh, uint regtype, uint32 mask, uint32 val) { - chipcregs_t *cc; - uint32 slowclk; - uint div; + sb_info_t *si; + uint offs; + si = SB_INFO(sbh); + if (si->sb.ccrev < 11) + return -1; - ASSERT(sb_coreid(&si->sb) == SB_CC); + if (regtype == GPIO_REGEVT) + offs = OFFSETOF(chipcregs_t, gpioevent); + else if (regtype == GPIO_REGEVT_INTMSK) + offs = OFFSETOF(chipcregs_t, gpioeventintmask); + else if (regtype == GPIO_REGEVT_INTPOL) + offs = OFFSETOF(chipcregs_t, gpioeventintpolarity); + else + return -1; - cc = (chipcregs_t*) sb_setcoreidx(&si->sb, si->curidx); + return (sb_corereg(sbh, SB_CC_IDX, offs, mask, val)); +} - /* shouldn't be here unless we've established the chip has dynamic clk control */ - ASSERT(R_REG(si->osh, &cc->capabilities) & CAP_PWR_CTL); +void *BCMINITFN(sb_gpio_handler_register) (sb_t * sbh, uint32 event, + bool level, gpio_handler_t cb, + void *arg) { + sb_info_t *si; + gpioh_item_t *gi; - slowclk = sb_slowclk_src(si); - if (si->sb.ccrev < 6) { - if (slowclk == SCC_SS_PCI) - return (max? (PCIMAXFREQ/64) : (PCIMINFREQ/64)); - else - return (max? (XTALMAXFREQ/32) : (XTALMINFREQ/32)); - } else if (si->sb.ccrev < 10) { - div = 4 * (((R_REG(si->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1); - if (slowclk == SCC_SS_LPO) - return (max? LPOMAXFREQ : LPOMINFREQ); - else if (slowclk == SCC_SS_XTAL) - return (max? (XTALMAXFREQ/div) : (XTALMINFREQ/div)); - else if (slowclk == SCC_SS_PCI) - return (max? (PCIMAXFREQ/div) : (PCIMINFREQ/div)); - else - ASSERT(0); - } else { - /* Chipc rev 10 is InstaClock */ - div = R_REG(si->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; - div = 4 * (div + 1); - return (max ? XTALMAXFREQ : (XTALMINFREQ/div)); - } - return (0); -} + ASSERT(event); + ASSERT(cb); -static void -BCMINITFN(sb_clkctl_setdelay)(sb_info_t *si, void *chipcregs) -{ - chipcregs_t * cc; - uint slowmaxfreq, pll_delay, slowclk; + si = SB_INFO(sbh); + if (si->sb.ccrev < 11) + return NULL; + + if ((gi = MALLOC(si->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 = si->gpioh_head; + si->gpioh_head = gi; + + return (void *)(gi); +} + +void BCMINITFN(sb_gpio_handler_unregister) (sb_t * sbh, void *gpioh) { + sb_info_t *si; + gpioh_item_t *p, *n; + + si = SB_INFO(sbh); + if (si->sb.ccrev < 11) + return; + + ASSERT(si->gpioh_head); + if ((void *)si->gpioh_head == gpioh) { + si->gpioh_head = si->gpioh_head->next; + MFREE(si->osh, gpioh, sizeof(gpioh_item_t)); + return; + } else { + p = si->gpioh_head; + n = p->next; + while (n) { + if ((void *)n == gpioh) { + p->next = n->next; + MFREE(si->osh, gpioh, sizeof(gpioh_item_t)); + return; + } + p = n; + n = n->next; + } + } + + ASSERT(0); /* Not found in list */ +} + +void sb_gpio_handler_process(sb_t * sbh) +{ + sb_info_t *si; + gpioh_item_t *h; + uint32 status; + uint32 level = sb_gpioin(sbh); + uint32 edge = sb_gpioevent(sbh, GPIO_REGEVT, 0, 0); + + si = SB_INFO(sbh); + for (h = si->gpioh_head; h != NULL; h = h->next) { + if (h->handler) { + status = (h->level ? level : edge); + + if (status & h->event) + h->handler(status, h->arg); + } + } + + sb_gpioevent(sbh, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */ +} + +uint32 sb_gpio_int_enable(sb_t * sbh, bool enable) +{ + sb_info_t *si; + uint offs; + + si = SB_INFO(sbh); + if (si->sb.ccrev < 11) + return -1; + + offs = OFFSETOF(chipcregs_t, intmask); + return (sb_corereg + (sbh, SB_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); +} + +#ifdef BCMDBG +void sb_dump(sb_t * sbh, struct bcmstrbuf *b) +{ + sb_info_t *si; + uint i; + + si = SB_INFO(sbh); + + bcm_bprintf(b, + "si %p chip 0x%x chiprev 0x%x boardtype 0x%x boardvendor 0x%x bus %d\n", + si, si->sb.chip, si->sb.chiprev, si->sb.boardtype, + si->sb.boardvendor, si->sb.bustype); + bcm_bprintf(b, "osh %p curmap %p\n", si->osh, si->curmap); + bcm_bprintf(b, + "sonicsrev %d ccrev %d buscoretype 0x%x buscorerev %d curidx %d\n", + si->sb.sonicsrev, si->sb.ccrev, si->sb.buscoretype, + si->sb.buscorerev, si->curidx); + + bcm_bprintf(b, "forceHT %d ASPM overflowPR42780 %d pcie_polarity %d\n", + si->sb.pr32414, si->sb.pr42780, si->pcie_polarity); + + bcm_bprintf(b, "cores: "); + for (i = 0; i < si->numcores; i++) + bcm_bprintf(b, "0x%x ", si->coreid[i]); + bcm_bprintf(b, "\n"); +} + +/* print interesting sbconfig registers */ +void sb_dumpregs(sb_t * sbh, struct bcmstrbuf *b) +{ + sb_info_t *si; + sbconfig_t *sb; + uint origidx; + uint curidx, i, intr_val = 0; + + si = SB_INFO(sbh); + origidx = si->curidx; + + INTR_OFF(si, intr_val); + curidx = si->curidx; + + for (i = 0; i < si->numcores; i++) { + sb = REGS2SB(sb_setcoreidx(sbh, i)); + + bcm_bprintf(b, "core 0x%x: \n", si->coreid[i]); + bcm_bprintf(b, + "sbtmstatelow 0x%x sbtmstatehigh 0x%x sbidhigh 0x%x " + "sbimstate 0x%x\n sbimconfiglow 0x%x sbimconfighigh 0x%x\n", + R_SBREG(si, &sb->sbtmstatelow), R_SBREG(si, + &sb-> + sbtmstatehigh), + R_SBREG(si, &sb->sbidhigh), R_SBREG(si, + &sb->sbimstate), + R_SBREG(si, &sb->sbimconfiglow), R_SBREG(si, + &sb-> + sbimconfighigh)); + } + + sb_setcoreidx(sbh, origidx); + INTR_RESTORE(si, intr_val); +} + +void sb_view(sb_t * sbh) +{ + sb_info_t *si; + sbconfig_t *sb; + + si = SB_INFO(sbh); + sb = REGS2SB(si->curmap); + + if (si->sb.sonicsrev > SONICS_2_2) + SB_ERROR(("sbimerrlog 0x%x sbimerrloga 0x%x\n", + sb_corereg(sbh, sb_coreidx(&si->sb), SBIMERRLOG, 0, + 0), sb_corereg(sbh, sb_coreidx(&si->sb), + SBIMERRLOGA, 0, 0))); + + SB_ERROR(("sbipsflag 0x%x sbtpsflag 0x%x sbtmerrloga 0x%x sbtmerrlog 0x%x\n", R_SBREG(si, &sb->sbipsflag), R_SBREG(si, &sb->sbtpsflag), R_SBREG(si, &sb->sbtmerrloga), R_SBREG(si, &sb->sbtmerrlog))); + SB_ERROR(("sbadmatch3 0x%x sbadmatch2 0x%x sbadmatch1 0x%x\n", + R_SBREG(si, &sb->sbadmatch3), R_SBREG(si, &sb->sbadmatch2), + R_SBREG(si, &sb->sbadmatch1))); + SB_ERROR(("sbimstate 0x%x sbintvec 0x%x sbtmstatelow 0x%x sbtmstatehigh 0x%x\n", R_SBREG(si, &sb->sbimstate), R_SBREG(si, &sb->sbintvec), R_SBREG(si, &sb->sbtmstatelow), R_SBREG(si, &sb->sbtmstatehigh))); + SB_ERROR(("sbbwa0 0x%x sbimconfiglow 0x%x sbimconfighigh 0x%x sbadmatch0 0x%x\n", R_SBREG(si, &sb->sbbwa0), R_SBREG(si, &sb->sbimconfiglow), R_SBREG(si, &sb->sbimconfighigh), R_SBREG(si, &sb->sbadmatch0))); + SB_ERROR(("sbtmconfiglow 0x%x sbtmconfighigh 0x%x sbbconfig 0x%x sbbstate 0x%x\n", R_SBREG(si, &sb->sbtmconfiglow), R_SBREG(si, &sb->sbtmconfighigh), R_SBREG(si, &sb->sbbconfig), R_SBREG(si, &sb->sbbstate))); + SB_ERROR(("sbactcnfg 0x%x sbflagst 0x%x sbidlow 0x%x sbidhigh 0x%x\n", + R_SBREG(si, &sb->sbactcnfg), R_SBREG(si, &sb->sbflagst), + R_SBREG(si, &sb->sbidlow), R_SBREG(si, &sb->sbidhigh))); +} + +void sb_viewall(sb_t * sbh) +{ + sb_info_t *si; + uint curidx, i; + uint intr_val = 0; + + si = SB_INFO(sbh); + curidx = si->curidx; + + for (i = 0; i < si->numcores; i++) { + INTR_OFF(si, intr_val); + sb_setcoreidx(sbh, i); + sb_view(sbh); + INTR_RESTORE(si, intr_val); + } + + sb_setcoreidx(sbh, curidx); +} +#endif /* BCMDBG */ + +/* return the slow clock source - LPO, XTAL, or PCI */ +static uint sb_slowclk_src(sb_info_t * si) +{ + chipcregs_t *cc; + + ASSERT(sb_coreid(&si->sb) == SB_CC); + + if (si->sb.ccrev < 6) { + if ((BUSTYPE(si->sb.bustype) == PCI_BUS) && + (OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof(uint32)) + & PCI_CFG_GPIO_SCS)) + return (SCC_SS_PCI); + else + return (SCC_SS_XTAL); + } else if (si->sb.ccrev < 10) { + cc = (chipcregs_t *) sb_setcoreidx(&si->sb, si->curidx); + return (R_REG(si->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); + } else /* Insta-clock */ + return (SCC_SS_XTAL); +} + +/* return the ILP (slowclock) min or max frequency */ +static uint sb_slowclk_freq(sb_info_t * si, bool max_freq) +{ + chipcregs_t *cc; + uint32 slowclk; + uint div; + + ASSERT(sb_coreid(&si->sb) == SB_CC); + + cc = (chipcregs_t *) sb_setcoreidx(&si->sb, si->curidx); + + /* shouldn't be here unless we've established the chip has dynamic clk control */ + ASSERT(R_REG(si->osh, &cc->capabilities) & CC_CAP_PWR_CTL); + + slowclk = sb_slowclk_src(si); + if (si->sb.ccrev < 6) { + if (slowclk == SCC_SS_PCI) + return (max_freq ? (PCIMAXFREQ / 64) + : (PCIMINFREQ / 64)); + else + return (max_freq ? (XTALMAXFREQ / 32) + : (XTALMINFREQ / 32)); + } else if (si->sb.ccrev < 10) { + div = + 4 * + (((R_REG(si->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> + SCC_CD_SHIFT) + + 1); + if (slowclk == SCC_SS_LPO) + return (max_freq ? LPOMAXFREQ : LPOMINFREQ); + else if (slowclk == SCC_SS_XTAL) + return (max_freq ? (XTALMAXFREQ / div) + : (XTALMINFREQ / div)); + else if (slowclk == SCC_SS_PCI) + return (max_freq ? (PCIMAXFREQ / div) + : (PCIMINFREQ / div)); + else + ASSERT(0); + } else { + /* Chipc rev 10 is InstaClock */ + div = R_REG(si->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; + div = 4 * (div + 1); + return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div)); + } + return (0); +} + +static void BCMINITFN(sb_clkctl_setdelay) (sb_info_t * si, void *chipcregs) { + chipcregs_t *cc; + uint slowmaxfreq, pll_delay, slowclk; uint pll_on_delay, fref_sel_delay; pll_delay = PLL_DELAY; @@ -2341,15 +3263,13 @@ BCMINITFN(sb_clkctl_setdelay)(sb_info_t *si, void *chipcregs) pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; - cc = (chipcregs_t *)chipcregs; + cc = (chipcregs_t *) chipcregs; W_REG(si->osh, &cc->pll_on_delay, pll_on_delay); W_REG(si->osh, &cc->fref_sel_delay, fref_sel_delay); } /* initialize power control delay registers */ -void -BCMINITFN(sb_clkctl_init)(sb_t *sbh) -{ +void BCMINITFN(sb_clkctl_init) (sb_t * sbh) { sb_info_t *si; uint origidx; chipcregs_t *cc; @@ -2358,31 +3278,30 @@ BCMINITFN(sb_clkctl_init)(sb_t *sbh) origidx = si->curidx; - if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL) + if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0)) == NULL) return; if ((si->sb.chip == BCM4321_CHIP_ID) && (si->sb.chiprev < 2)) W_REG(si->osh, &cc->chipcontrol, - (si->sb.chiprev == 0) ? CHIPCTRL_4321A0_DEFAULT : CHIPCTRL_4321A1_DEFAULT); + (si->sb.chiprev == + 0) ? CHIPCTRL_4321A0_DEFAULT : CHIPCTRL_4321A1_DEFAULT); - if (!(R_REG(si->osh, &cc->capabilities) & CAP_PWR_CTL)) + if (!(R_REG(si->osh, &cc->capabilities) & CC_CAP_PWR_CTL)) goto done; /* set all Instaclk chip ILP to 1 MHz */ - else if (si->sb.ccrev >= 10) + if (si->sb.ccrev >= 10) SET_REG(si->osh, &cc->system_clk_ctl, SYCC_CD_MASK, - (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); + (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); - sb_clkctl_setdelay(si, (void *)cc); + sb_clkctl_setdelay(si, (void *)(uintptr) cc); -done: + done: sb_setcoreidx(sbh, origidx); } /* return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */ -uint16 -sb_clkctl_fast_pwrup_delay(sb_t *sbh) -{ +uint16 BCMINITFN(sb_clkctl_fast_pwrup_delay) (sb_t * sbh) { sb_info_t *si; uint origidx; chipcregs_t *cc; @@ -2396,25 +3315,29 @@ sb_clkctl_fast_pwrup_delay(sb_t *sbh) INTR_OFF(si, intr_val); - if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL) + if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0)) == NULL) goto done; - if (!(R_REG(si->osh, &cc->capabilities) & CAP_PWR_CTL)) + if (sbh->cccaps & CC_CAP_PMU) { + fpdelay = sb_pmu_fast_pwrup_delay(sbh, si->osh); + goto done; + } + + if (!(sbh->cccaps & CC_CAP_PWR_CTL)) goto done; slowminfreq = sb_slowclk_freq(si, FALSE); fpdelay = (((R_REG(si->osh, &cc->pll_on_delay) + 2) * 1000000) + - (slowminfreq - 1)) / slowminfreq; + (slowminfreq - 1)) / slowminfreq; -done: + done: sb_setcoreidx(sbh, origidx); INTR_RESTORE(si, intr_val); return (fpdelay); } /* turn primary xtal and/or pll off/on */ -int -sb_clkctl_xtal(sb_t *sbh, uint what, bool on) +int sb_clkctl_xtal(sb_t * sbh, uint what, bool on) { sb_info_t *si; uint32 in, out, outen; @@ -2423,66 +3346,68 @@ sb_clkctl_xtal(sb_t *sbh, uint what, bool on) switch (BUSTYPE(si->sb.bustype)) { + case PCMCIA_BUS: + return (0); - case PCMCIA_BUS: - return (0); - - - case PCI_BUS: + case PCI_BUS: - /* pcie core doesn't have any mapping to control the xtal pu */ - if (PCIE(si)) - return -1; + /* pcie core doesn't have any mapping to control the xtal pu */ + if (PCIE(si)) + return -1; - in = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_IN, sizeof(uint32)); - out = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof(uint32)); - outen = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof(uint32)); + in = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_IN, sizeof(uint32)); + out = + OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof(uint32)); + outen = + OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUTEN, + sizeof(uint32)); - /* - * Avoid glitching the clock if GPRS is already using it. - * We can't actually read the state of the PLLPD so we infer it - * by the value of XTAL_PU which *is* readable via gpioin. - */ - if (on && (in & PCI_CFG_GPIO_XTAL)) - return (0); + /* + * Avoid glitching the clock if GPRS is already using it. + * We can't actually read the state of the PLLPD so we infer it + * by the value of XTAL_PU which *is* readable via gpioin. + */ + if (on && (in & PCI_CFG_GPIO_XTAL)) + return (0); - if (what & XTAL) - outen |= PCI_CFG_GPIO_XTAL; - if (what & PLL) - outen |= PCI_CFG_GPIO_PLL; - - if (on) { - /* turn primary xtal on */ - if (what & XTAL) { - out |= PCI_CFG_GPIO_XTAL; - if (what & PLL) - out |= PCI_CFG_GPIO_PLL; - OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT, - sizeof(uint32), out); - OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUTEN, - sizeof(uint32), outen); - OSL_DELAY(XTAL_ON_DELAY); - } + if (what & XTAL) + outen |= PCI_CFG_GPIO_XTAL; + if (what & PLL) + outen |= PCI_CFG_GPIO_PLL; - /* 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 (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_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); } - default: - return (-1); + /* 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); @@ -2490,8 +3415,7 @@ sb_clkctl_xtal(sb_t *sbh, uint what, bool on) /* set dynamic clk control mode (forceslow, forcefast, dynamic) */ /* returns true if we are forcing fast clock */ -bool -sb_clkctl_clk(sb_t *sbh, uint mode) +bool sb_clkctl_clk(sb_t * sbh, uint mode) { sb_info_t *si; uint origidx; @@ -2505,7 +3429,6 @@ sb_clkctl_clk(sb_t *sbh, uint mode) if (si->sb.ccrev < 6) return (FALSE); - /* Chips with ccrev 10 are EOL and they don't have SYCC_HR which we use below */ ASSERT(si->sb.ccrev != 10); @@ -2517,31 +3440,41 @@ sb_clkctl_clk(sb_t *sbh, uint mode) (BUSTYPE(si->sb.bustype) == SB_BUS) && (si->sb.ccrev >= 10)) goto done; - /* PR32414WAR "Force HT clock on" all the time, no dynamic clk ctl */ - if ((si->sb.chip == BCM4311_CHIP_ID) && (si->sb.chiprev <= 1)) + if (FORCEHT_WAR32414(si)) goto done; - cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0); + cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0); ASSERT(cc != NULL); - if (!(R_REG(si->osh, &cc->capabilities) & CAP_PWR_CTL)) + if (!(R_REG(si->osh, &cc->capabilities) & CC_CAP_PWR_CTL) + && (si->sb.ccrev < 20)) goto done; switch (mode) { - case CLK_FAST: /* force fast (pll) clock */ + case CLK_FAST: /* force fast (pll) clock */ if (si->sb.ccrev < 10) { /* don't forget to force xtal back on before we clear SCC_DYN_XTAL.. */ sb_clkctl_xtal(&si->sb, XTAL, ON); - SET_REG(si->osh, &cc->slow_clk_ctl, (SCC_XC | SCC_FS | SCC_IP), SCC_IP); - } else + SET_REG(si->osh, &cc->slow_clk_ctl, + (SCC_XC | SCC_FS | SCC_IP), SCC_IP); + } else if (si->sb.ccrev < 20) { OR_REG(si->osh, &cc->system_clk_ctl, SYCC_HR); + } else { + OR_REG(si->osh, &cc->clk_ctl_st, CCS_FORCEHT); + } + /* wait for the PLL */ - OSL_DELAY(PLL_DELAY); + if (R_REG(si->osh, &cc->capabilities) & CC_CAP_PMU) { + SPINWAIT(((R_REG(si->osh, &cc->clk_ctl_st) & + CCS_HTAVAIL) == 0), PMU_MAX_TRANSITION_DLY); + ASSERT(R_REG(si->osh, &cc->clk_ctl_st) & CCS_HTAVAIL); + } else { + OSL_DELAY(PLL_DELAY); + } break; case CLK_DYNAMIC: /* enable dynamic clock control */ - if (si->sb.ccrev < 10) { scc = R_REG(si->osh, &cc->slow_clk_ctl); scc &= ~(SCC_FS | SCC_IP | SCC_XC); @@ -2552,9 +3485,11 @@ sb_clkctl_clk(sb_t *sbh, uint mode) /* for dynamic control, we have to release our xtal_pu "force on" */ if (scc & SCC_XC) sb_clkctl_xtal(&si->sb, XTAL, OFF); - } else { + } else if (si->sb.ccrev < 20) { /* Instaclock */ AND_REG(si->osh, &cc->system_clk_ctl, ~SYCC_HR); + } else { + AND_REG(si->osh, &cc->clk_ctl_st, ~CCS_FORCEHT); } break; @@ -2562,7 +3497,7 @@ sb_clkctl_clk(sb_t *sbh, uint mode) ASSERT(0); } -done: + done: sb_setcoreidx(sbh, origidx); INTR_RESTORE(si, intr_val); return (mode == CLK_FAST); @@ -2570,50 +3505,124 @@ done: /* register driver interrupt disabling and restoring callback functions */ void -sb_register_intr_callback(sb_t *sbh, void *intrsoff_fn, void *intrsrestore_fn, - void *intrsenabled_fn, void *intr_arg) +sb_register_intr_callback(sb_t * sbh, void *intrsoff_fn, + void *intrsrestore_fn, void *intrsenabled_fn, + void *intr_arg) { sb_info_t *si; si = SB_INFO(sbh); si->intr_arg = intr_arg; - si->intrsoff_fn = (sb_intrsoff_t)intrsoff_fn; - si->intrsrestore_fn = (sb_intrsrestore_t)intrsrestore_fn; - si->intrsenabled_fn = (sb_intrsenabled_t)intrsenabled_fn; + 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]; } +void sb_deregister_intr_callback(sb_t * sbh) +{ + sb_info_t *si; -int -sb_corepciid(sb_t *sbh, uint func, uint16 *pcivendor, uint16 *pcidevice, - uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, - uint8 *pciheader) + si = SB_INFO(sbh); + si->intrsoff_fn = NULL; +} + +#ifdef BCMDBG +/* dump dynamic clock control related registers */ +void sb_clkctl_dump(sb_t * sbh, struct bcmstrbuf *b) { - uint16 vendor = 0xffff, device = 0xffff; - uint core, unit; - uint chip, chippkg; - uint nfunc; - char varname[SB_DEVPATH_BUFSZ + 8]; - uint8 class, subclass, progif; - char devpath[SB_DEVPATH_BUFSZ]; - uint8 header; + sb_info_t *si; + chipcregs_t *cc; + uint origidx; + uint intr_val = 0; + + si = SB_INFO(sbh); + + INTR_OFF(si, intr_val); + + origidx = si->curidx; + + if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0)) == NULL) { + INTR_RESTORE(si, intr_val); + return; + } + + if (!(R_REG(si->osh, &cc->capabilities) & CC_CAP_PWR_CTL)) + goto done; + + bcm_bprintf(b, "pll_on_delay 0x%x fref_sel_delay 0x%x ", + cc->pll_on_delay, cc->fref_sel_delay); + if ((si->sb.ccrev >= 6) && (si->sb.ccrev < 10)) + bcm_bprintf(b, "slow_clk_ctl 0x%x ", cc->slow_clk_ctl); + if (si->sb.ccrev >= 10) { + bcm_bprintf(b, "system_clk_ctl 0x%x ", cc->system_clk_ctl); + bcm_bprintf(b, "clkstatestretch 0x%x ", cc->clkstatestretch); + } + if (BUSTYPE(si->sb.bustype) == PCI_BUS) + bcm_bprintf(b, "gpioout 0x%x gpioouten 0x%x ", + OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, + sizeof(uint32)), + OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUTEN, + sizeof(uint32))); + bcm_bprintf(b, "\n"); + + done: + sb_setcoreidx(sbh, origidx); + INTR_RESTORE(si, intr_val); +} +#endif /* BCMDBG */ - core = sb_coreid(sbh); - unit = sb_coreunit(sbh); +uint16 BCMINITFN(sb_d11_devid) (sb_t * sbh) { + sb_info_t *si = SB_INFO(sbh); + uint16 device; + +#if defined(BCM4328) + /* Fix device id for dual band BCM4328 */ + if (sbh->chip == BCM4328_CHIP_ID && + (sbh->chippkg == BCM4328USBDUAL_PKG_ID + || sbh->chippkg == BCM4328SDIODUAL_PKG_ID)) + device = BCM4328_D11DUAL_ID; + else +#endif /* BCM4328 */ + /* Let an nvram variable with devpath override devid */ + if ((device = (uint16) sb_getdevpathintvar(sbh, "devid")) != 0) ; + /* Get devid from OTP/SPROM depending on where the SROM is read */ + else if ((device = (uint16) getintvar(si->vars, "devid")) != 0) ; + /* + * no longer support wl0id, but keep the code + * here for backward compatibility. + */ + else if ((device = (uint16) getintvar(si->vars, "wl0id")) != 0) ; + /* Chip specific conversion */ + else if (sbh->chip == BCM4712_CHIP_ID) { + if (sbh->chippkg == BCM4712SMALL_PKG_ID) + device = BCM4306_D11G_ID; + else + device = BCM4306_D11DUAL_ID; + } + /* ignore it */ + else + device = 0xffff; - chip = sb_chip(sbh); - chippkg = sb_chippkg(sbh); + return device; +} - progif = 0; - header = PCI_HEADER_NORMAL; +int +BCMINITFN(sb_corepciid) (sb_t * sbh, uint func, uint16 * pcivendor, + uint16 * pcidevice, uint8 * pciclass, + uint8 * pcisubclass, uint8 * pciprogif, + uint8 * pciheader) { + uint16 vendor = 0xffff, device = 0xffff; + uint8 class, subclass, progif = 0; + uint8 header = PCI_HEADER_NORMAL; + uint32 core = sb_coreid(sbh); /* Verify whether the function exists for the core */ - nfunc = (core == SB_USB20H) ? 2 : 1; - if (func >= nfunc) - return BCME_ERROR; + if (func >= (uint) (core == SB_USB20H ? 2 : 1)) + return -1; /* Known vendor translations */ switch (sb_corevendor(sbh)) { @@ -2621,7 +3630,7 @@ sb_corepciid(sb_t *sbh, uint func, uint16 *pcivendor, uint16 *pcidevice, vendor = VENDOR_BROADCOM; break; default: - return BCME_ERROR; + return -1; } /* Determine class based on known core codes */ @@ -2645,20 +3654,20 @@ sb_corepciid(sb_t *sbh, uint func, uint16 *pcivendor, uint16 *pcidevice, case SB_MEMC: class = PCI_CLASS_MEMORY; subclass = PCI_MEMORY_RAM; - device = (uint16)core; + device = (uint16) core; break; case SB_PCI: case SB_PCIE: class = PCI_CLASS_BRIDGE; subclass = PCI_BRIDGE_PCI; - device = (uint16)core; + device = (uint16) core; header = PCI_HEADER_BRIDGE; break; case SB_MIPS: case SB_MIPS33: class = PCI_CLASS_CPU; subclass = PCI_CPU_MIPS; - device = (uint16)core; + device = (uint16) core; break; case SB_CODEC: class = PCI_CLASS_COMM; @@ -2668,31 +3677,21 @@ sb_corepciid(sb_t *sbh, uint func, uint16 *pcivendor, uint16 *pcidevice, case SB_USB: class = PCI_CLASS_SERIAL; subclass = PCI_SERIAL_USB; - progif = 0x10; /* OHCI */ + progif = 0x10; /* OHCI */ device = BCM47XX_USB_ID; break; case SB_USB11H: class = PCI_CLASS_SERIAL; subclass = PCI_SERIAL_USB; - progif = 0x10; /* OHCI */ + progif = 0x10; /* OHCI */ device = BCM47XX_USBH_ID; break; case SB_USB20H: class = PCI_CLASS_SERIAL; subclass = PCI_SERIAL_USB; - progif = func == 0 ? 0x10 : 0x20; /* OHCI/EHCI */ + progif = func == 0 ? 0x10 : 0x20; /* OHCI/EHCI */ device = BCM47XX_USB20H_ID; - header = 0x80; /* multifunction */ - break; - case SB_USB11D: - class = PCI_CLASS_SERIAL; - subclass = PCI_SERIAL_USB; - device = BCM47XX_USBD_ID; - break; - case SB_USB20D: - class = PCI_CLASS_SERIAL; - subclass = PCI_SERIAL_USB; - device = BCM47XX_USB20D_ID; + header = 0x80; /* multifunction */ break; case SB_IPSEC: class = PCI_CLASS_CRYPT; @@ -2708,33 +3707,7 @@ sb_corepciid(sb_t *sbh, uint func, uint16 *pcivendor, uint16 *pcidevice, case SB_CC: class = PCI_CLASS_MEMORY; subclass = PCI_MEMORY_FLASH; - device = (uint16)core; - break; - case SB_D11: - class = PCI_CLASS_NET; - subclass = PCI_NET_OTHER; - /* Let nvram variable override core ID */ - sb_devpath(sbh, devpath, sizeof(devpath)); - sprintf(varname, "%sdevid", devpath); - if ((device = (uint16)getintvar(NULL, varname))) - break; - /* - * no longer support wl%did, but keep the code - * here for backward compatibility. - */ - sprintf(varname, "wl%did", unit); - if ((device = (uint16)getintvar(NULL, varname))) - break; - /* Chip specific conversion */ - if (chip == BCM4712_CHIP_ID) { - if (chippkg == BCM4712SMALL_PKG_ID) - device = BCM4306_D11G_ID; - else - device = BCM4306_D11DUAL_ID; - break; - } - /* ignore it */ - device = 0xffff; + device = (uint16) core; break; case SB_SATAXOR: class = PCI_CLASS_XOR; @@ -2746,10 +3719,25 @@ sb_corepciid(sb_t *sbh, uint func, uint16 *pcivendor, uint16 *pcidevice, subclass = PCI_DASDI_IDE; device = BCM47XX_ATA100_ID; break; + case SB_USB11D: + class = PCI_CLASS_SERIAL; + subclass = PCI_SERIAL_USB; + device = BCM47XX_USBD_ID; + break; + case SB_USB20D: + class = PCI_CLASS_SERIAL; + subclass = PCI_SERIAL_USB; + device = BCM47XX_USB20D_ID; + break; + case SB_D11: + class = PCI_CLASS_NET; + subclass = PCI_NET_OTHER; + device = sb_d11_devid(sbh); + break; default: class = subclass = progif = 0xff; - device = (uint16)core; + device = (uint16) core; break; } @@ -2763,25 +3751,69 @@ sb_corepciid(sb_t *sbh, uint func, uint16 *pcivendor, uint16 *pcidevice, return 0; } +/* use the mdio interface to read from mdio slaves */ +static int +sb_pcie_mdioread(sb_info_t * si, uint physmedia, uint regaddr, uint * regval) +{ + uint mdiodata; + uint i = 0; + sbpcieregs_t *pcieregs; + + pcieregs = (sbpcieregs_t *) sb_setcoreidx(&si->sb, si->sb.buscoreidx); + ASSERT(pcieregs); + + /* enable mdio access to SERDES */ + W_REG(si->osh, (&pcieregs->mdiocontrol), + MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); + + mdiodata = MDIODATA_START | MDIODATA_READ | + (physmedia << MDIODATA_DEVADDR_SHF) | + (regaddr << MDIODATA_REGADDR_SHF) | MDIODATA_TA; + + W_REG(si->osh, &pcieregs->mdiodata, mdiodata); + + PR28829_DELAY(); + + /* retry till the transaction is complete */ + while (i < 10) { + if (R_REG(si->osh, &(pcieregs->mdiocontrol)) & + MDIOCTL_ACCESS_DONE) { + PR28829_DELAY(); + *regval = + (R_REG(si->osh, &(pcieregs->mdiodata)) & + MDIODATA_MASK); + /* Disable mdio access to SERDES */ + W_REG(si->osh, (&pcieregs->mdiocontrol), 0); + return 0; + } + OSL_DELAY(1000); + i++; + } + SB_ERROR(("sb_pcie_mdioread: timed out\n")); + /* Disable mdio access to SERDES */ + W_REG(si->osh, (&pcieregs->mdiocontrol), 0); + return 1; +} /* use the mdio interface to write to mdio slaves */ static int -sb_pcie_mdiowrite(sb_info_t *si, uint physmedia, uint regaddr, uint val) +sb_pcie_mdiowrite(sb_info_t * si, uint physmedia, uint regaddr, uint val) { uint mdiodata; uint i = 0; sbpcieregs_t *pcieregs; - pcieregs = (sbpcieregs_t*) sb_setcoreidx(&si->sb, si->sb.buscoreidx); + pcieregs = (sbpcieregs_t *) sb_setcoreidx(&si->sb, si->sb.buscoreidx); ASSERT(pcieregs); /* enable mdio access to SERDES */ - W_REG(si->osh, (&pcieregs->mdiocontrol), MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); + W_REG(si->osh, (&pcieregs->mdiocontrol), + MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); mdiodata = MDIODATA_START | MDIODATA_WRITE | - (physmedia << MDIODATA_DEVADDR_SHF) | - (regaddr << MDIODATA_REGADDR_SHF) | MDIODATA_TA | val; + (physmedia << MDIODATA_DEVADDR_SHF) | + (regaddr << MDIODATA_REGADDR_SHF) | MDIODATA_TA | val; W_REG(si->osh, (&pcieregs->mdiodata), mdiodata); @@ -2789,7 +3821,8 @@ sb_pcie_mdiowrite(sb_info_t *si, uint physmedia, uint regaddr, uint val) /* retry till the transaction is complete */ while (i < 10) { - if (R_REG(si->osh, &(pcieregs->mdiocontrol)) & MDIOCTL_ACCESS_DONE) { + if (R_REG(si->osh, &(pcieregs->mdiocontrol)) & + MDIOCTL_ACCESS_DONE) { /* Disable mdio access to SERDES */ W_REG(si->osh, (&pcieregs->mdiocontrol), 0); return 0; @@ -2801,48 +3834,45 @@ sb_pcie_mdiowrite(sb_info_t *si, uint physmedia, uint regaddr, uint val) SB_ERROR(("sb_pcie_mdiowrite: timed out\n")); /* Disable mdio access to SERDES */ W_REG(si->osh, (&pcieregs->mdiocontrol), 0); - ASSERT(0); return 1; } /* indirect way to read pcie config regs */ -uint -sb_pcie_readreg(void *sb, void* arg1, uint offset) +uint sb_pcie_readreg(void *sb, void *arg1, uint offset) { sb_info_t *si; - sb_t *sbh; + sb_t *sbh; uint retval = 0xFFFFFFFF; sbpcieregs_t *pcieregs; uint addrtype; - sbh = (sb_t *)sb; + sbh = (sb_t *) sb; si = SB_INFO(sbh); ASSERT(PCIE(si)); - pcieregs = (sbpcieregs_t *)sb_setcore(sbh, SB_PCIE, 0); + pcieregs = (sbpcieregs_t *) sb_setcore(sbh, SB_PCIE, 0); ASSERT(pcieregs); - addrtype = (uint)((uintptr)arg1); + addrtype = (uint) ((uintptr) arg1); switch (addrtype) { - case PCIE_CONFIGREGS: - W_REG(si->osh, (&pcieregs->configaddr), offset); - retval = R_REG(si->osh, &(pcieregs->configdata)); - break; - case PCIE_PCIEREGS: - W_REG(si->osh, &(pcieregs->pcieaddr), offset); - retval = R_REG(si->osh, &(pcieregs->pciedata)); - break; - default: - ASSERT(0); - break; + case PCIE_CONFIGREGS: + W_REG(si->osh, (&pcieregs->configaddr), offset); + retval = R_REG(si->osh, &(pcieregs->configdata)); + break; + case PCIE_PCIEREGS: + W_REG(si->osh, &(pcieregs->pcieindaddr), offset); + retval = R_REG(si->osh, &(pcieregs->pcieinddata)); + break; + default: + ASSERT(0); + break; } return retval; } /* indirect way to write pcie config/mdio/pciecore regs */ -uint -sb_pcie_writereg(sb_t *sbh, void *arg1, uint offset, uint val) +uint sb_pcie_writereg(sb_t * sbh, void *arg1, uint offset, uint val) { sb_info_t *si; sbpcieregs_t *pcieregs; @@ -2851,74 +3881,119 @@ sb_pcie_writereg(sb_t *sbh, void *arg1, uint offset, uint val) si = SB_INFO(sbh); ASSERT(PCIE(si)); - pcieregs = (sbpcieregs_t *)sb_setcore(sbh, SB_PCIE, 0); + pcieregs = (sbpcieregs_t *) sb_setcore(sbh, SB_PCIE, 0); ASSERT(pcieregs); - addrtype = (uint)((uintptr)arg1); + addrtype = (uint) ((uintptr) arg1); switch (addrtype) { - case PCIE_CONFIGREGS: - W_REG(si->osh, (&pcieregs->configaddr), offset); - W_REG(si->osh, (&pcieregs->configdata), val); - break; - case PCIE_PCIEREGS: - W_REG(si->osh, (&pcieregs->pcieaddr), offset); - W_REG(si->osh, (&pcieregs->pciedata), val); - break; - default: - ASSERT(0); - break; + case PCIE_CONFIGREGS: + W_REG(si->osh, (&pcieregs->configaddr), offset); + W_REG(si->osh, (&pcieregs->configdata), val); + break; + case PCIE_PCIEREGS: + W_REG(si->osh, (&pcieregs->pcieindaddr), offset); + W_REG(si->osh, (&pcieregs->pcieinddata), val); + break; + default: + ASSERT(0); + break; } return 0; } /* Build device path. Support SB, PCI, and JTAG for now. */ -int -sb_devpath(sb_t *sbh, char *path, int size) -{ +int BCMINITFN(sb_devpath) (sb_t * sbh, char *path, int size) { + int slen; ASSERT(path); ASSERT(size >= SB_DEVPATH_BUFSZ); + if (!path || size <= 0) + return -1; + switch (BUSTYPE((SB_INFO(sbh))->sb.bustype)) { case SB_BUS: case JTAG_BUS: - sprintf(path, "sb/%u/", sb_coreidx(sbh)); + slen = snprintf(path, (size_t) size, "sb/%u/", sb_coreidx(sbh)); break; case PCI_BUS: ASSERT((SB_INFO(sbh))->osh); - sprintf(path, "pci/%u/%u/", OSL_PCI_BUS((SB_INFO(sbh))->osh), - OSL_PCI_SLOT((SB_INFO(sbh))->osh)); + slen = snprintf(path, (size_t) size, "pci/%u/%u/", + OSL_PCI_BUS((SB_INFO(sbh))->osh), + OSL_PCI_SLOT((SB_INFO(sbh))->osh)); break; case PCMCIA_BUS: SB_ERROR(("sb_devpath: OSL_PCMCIA_BUS() not implemented, bus 1 assumed\n")); SB_ERROR(("sb_devpath: OSL_PCMCIA_SLOT() not implemented, slot 1 assumed\n")); - sprintf(path, "pc/%u/%u/", 1, 1); - break; - case SDIO_BUS: - SB_ERROR(("sb_devpath: device 0 assumed\n")); - sprintf(path, "sd/%u/", sb_coreidx(sbh)); + slen = snprintf(path, (size_t) size, "pc/1/1/"); break; default: + slen = -1; ASSERT(0); break; } + if (slen < 0 || slen >= size) { + path[0] = '\0'; + return -1; + } + return 0; } +/* Get a variable, but only if it has a devpath prefix */ +char *BCMINITFN(sb_getdevpathvar) (sb_t * sbh, const char *name) { + char varname[SB_DEVPATH_BUFSZ + 32]; + + sb_devpathvar(sbh, varname, sizeof(varname), name); + + return (getvar(NULL, varname)); +} + +/* Get a variable, but only if it has a devpath prefix */ +int BCMINITFN(sb_getdevpathintvar) (sb_t * sbh, const char *name) { + char varname[SB_DEVPATH_BUFSZ + 32]; + + sb_devpathvar(sbh, varname, sizeof(varname), name); + + return (getintvar(NULL, varname)); +} + +/* Concatenate the dev path with a varname into the given 'var' buffer + * and return the 'var' pointer. + * Nothing is done to the arguments if len == 0 or var is NULL, var is still returned. + * On overflow, the first char will be set to '\0'. + */ +static char *BCMINITFN(sb_devpathvar) (sb_t * sbh, char *var, int len, + const char *name) { + uint path_len; + + if (!var || len <= 0) + return var; + + if (sb_devpath(sbh, var, len) == 0) { + path_len = strlen(var); + + if (strlen(name) + 1 > (uint) (len - path_len)) + var[0] = '\0'; + else + strncpy(var + path_len, name, len - path_len - 1); + } + + return var; +} + /* * Fixup SROMless PCI device's configuration. * The current core may be changed upon return. */ -static int -sb_pci_fixcfg(sb_info_t *si) +static int sb_pci_fixcfg(sb_info_t * si) { uint origidx, pciidx; sbpciregs_t *pciregs; - sbpcieregs_t *pcieregs; + sbpcieregs_t *pcieregs = NULL; uint16 val16, *reg16; - char name[SB_DEVPATH_BUFSZ+16], *value; - char devpath[SB_DEVPATH_BUFSZ]; + uint32 w; ASSERT(BUSTYPE(si->sb.bustype) == PCI_BUS); @@ -2928,11 +4003,11 @@ sb_pci_fixcfg(sb_info_t *si) /* check 'pi' is correct and fix it if not */ if (si->sb.buscoretype == SB_PCIE) { - pcieregs = (sbpcieregs_t *)sb_setcore(&si->sb, SB_PCIE, 0); + pcieregs = (sbpcieregs_t *) sb_setcore(&si->sb, SB_PCIE, 0); ASSERT(pcieregs); reg16 = &pcieregs->sprom[SRSH_PI_OFFSET]; } else if (si->sb.buscoretype == SB_PCI) { - pciregs = (sbpciregs_t *)sb_setcore(&si->sb, SB_PCI, 0); + pciregs = (sbpciregs_t *) sb_setcore(&si->sb, SB_PCI, 0); ASSERT(pciregs); reg16 = &pciregs->sprom[SRSH_PI_OFFSET]; } else { @@ -2941,59 +4016,59 @@ sb_pci_fixcfg(sb_info_t *si) } pciidx = sb_coreidx(&si->sb); val16 = R_REG(si->osh, reg16); - if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (uint16)pciidx) { - val16 = (uint16)(pciidx << SRSH_PI_SHIFT) | (val16 & ~SRSH_PI_MASK); + if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (uint16) pciidx) { + val16 = + (uint16) (pciidx << SRSH_PI_SHIFT) | (val16 & + ~SRSH_PI_MASK); W_REG(si->osh, reg16, val16); } - /* restore the original index */ - sb_setcoreidx(&si->sb, origidx); + if (PCIE_ASPMWARS(si)) { + w = sb_pcie_readreg((void *)(uintptr) & si->sb, + (void *)PCIE_PCIEREGS, PCIE_PLP_STATUSREG); - /* - * Fixup bar0window in PCI config space to make the core indicated - * by the nvram variable the current core. - * !Do it last, it may change the current core! - */ - if (sb_devpath(&si->sb, devpath, sizeof(devpath))) - return -1; - sprintf(name, "%sb0w", devpath); - if ((value = getvar(NULL, name))) { - OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32), - bcm_strtoul(value, NULL, 16)); - /* update curidx since the current core is changed */ - si->curidx = _sb_coreidx(si); - if (si->curidx == BADIDX) { - SB_ERROR(("sb_pci_fixcfg: bad core index\n")); - return -1; + /* Detect the current polarity at attach and force that polarity and + * disable changing the polarity + */ + if ((w & PCIE_PLP_POLARITYINV_STAT) == 0) { + si->pcie_polarity = (SERDES_RX_CTRL_FORCE); + } else { + si->pcie_polarity = (SERDES_RX_CTRL_FORCE | + SERDES_RX_CTRL_POLARITY); } - } - return 0; -} + w = OSL_PCI_READ_CONFIG(si->osh, si->pciecap_lcreg_offset, + sizeof(uint32)); + if (w & PCIE_CLKREQ_ENAB) { + reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET]; + val16 = R_REG(si->osh, reg16); + /* if clockreq is not advertized clkreq should not be enabled */ + if (!(val16 & SRSH_CLKREQ_ENB)) + SB_ERROR(("WARNING: CLK REQ enabled already 0x%x\n", w)); + } -static uint -sb_chipc_capability(sb_t *sbh) -{ - sb_info_t *si; + sb_war43448(&si->sb); - si = SB_INFO(sbh); + sb_war42767(&si->sb); + + } + + /* restore the original index */ + sb_setcoreidx(&si->sb, origidx); - /* Make sure that there is ChipCommon core present */ - if (si->coreid[SB_CC_IDX] == SB_CC) - return (sb_corereg(si, SB_CC_IDX, OFFSETOF(chipcregs_t, capabilities), - 0, 0)); return 0; } /* Return ADDR64 capability of the backplane */ -bool -sb_backplane64(sb_t *sbh) +bool sb_backplane64(sb_t * sbh) { - return ((sb_chipc_capability(sbh) & CAP_BKPLN64) != 0); + sb_info_t *si; + + si = SB_INFO(sbh); + return ((si->sb.cccaps & CC_CAP_BKPLN64) != 0); } -void -sb_btcgpiowar(sb_t *sbh) +void sb_btcgpiowar(sb_t * sbh) { sb_info_t *si; uint origidx; @@ -3004,7 +4079,7 @@ sb_btcgpiowar(sb_t *sbh) /* Make sure that there is ChipCommon core present && * UART_TX is strapped to 1 */ - if (!(sb_chipc_capability(sbh) & CAP_UARTGPIO)) + if (!(si->sb.cccaps & CC_CAP_UARTGPIO)) return; /* sb_corereg cannot be used as we have to guarantee 8-bit read/writes */ @@ -3012,13 +4087,11 @@ sb_btcgpiowar(sb_t *sbh) origidx = sb_coreidx(sbh); - cc = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0); - if (cc == NULL) - goto end; + cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0); + ASSERT(cc); W_REG(si->osh, &cc->uart0mcr, R_REG(si->osh, &cc->uart0mcr) | 0x04); -end: /* restore the original index */ sb_setcoreidx(sbh, origidx); @@ -3026,8 +4099,7 @@ end: } /* check if the device is removed */ -bool -sb_deviceremoved(sb_t *sbh) +bool sb_deviceremoved(sb_t * sbh) { uint32 w; sb_info_t *si; @@ -3048,10 +4120,9 @@ sb_deviceremoved(sb_t *sbh) return FALSE; } +#if 0 /* Return the RAM size of the SOCRAM core */ -uint32 -sb_socram_size(sb_t *sbh) -{ +uint32 BCMINITFN(sb_socram_size) (sb_t * sbh) { sb_info_t *si; uint origidx; uint intr_val = 0; @@ -3080,24 +4151,29 @@ sb_socram_size(sb_t *sbh) coreinfo = R_REG(si->osh, ®s->coreinfo); /* Calculate size from coreinfo based on rev */ - switch (corerev) { - case 0: + if (corerev == 0) memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); - break; - default: /* rev >= 1 */ + else if (corerev < 3) { memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; - break; + } else { + 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)); } - /* Return to previous state and core */ if (!wasup) sb_core_disable(sbh, 0); sb_setcoreidx(sbh, origidx); -done: + done: INTR_RESTORE(si, intr_val); return memsize; } - +#endif