aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm-2.4/files/arch/mips/bcm947xx/sbutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm-2.4/files/arch/mips/bcm947xx/sbutils.c')
-rw-r--r--target/linux/brcm-2.4/files/arch/mips/bcm947xx/sbutils.c2681
1 files changed, 1879 insertions, 802 deletions
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 672e027d88..244a1324f6 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,123 @@
* 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 $
+ * $Id$
*/
#include <typedefs.h>
#include <bcmdefs.h>
#include <osl.h>
-#include <bcmutils.h>
#include <sbutils.h>
#include <bcmdevs.h>
#include <sbconfig.h>
#include <sbchipc.h>
+#include <sbextif.h>
#include <sbpci.h>
#include <sbpcie.h>
#include <pcicfg.h>
#include <sbpcmcia.h>
-#include <sbextif.h>
#include <sbsocram.h>
+#include <bcmnvram.h>
#include <bcmsrom.h>
-#ifdef __mips__
-#include <mipsinc.h>
-#endif /* __mips__ */
+#include <hndpmu.h>
/* debug/trace */
#define SB_ERROR(args)
-typedef uint32 (*sb_intrsoff_t)(void *intr_arg);
-typedef void (*sb_intrsrestore_t)(void *intr_arg, uint32 arg);
-typedef bool (*sb_intrsenabled_t)(void *intr_arg);
+#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 */
- void *osh; /* osl os handle */
- void *sdh; /* bcmsdh handle */
+ uint curidx; /* current core index */
+ uint dev_coreid; /* the core provides driver functions */
- void *curmap; /* current regs va */
- void *regs[SB_MAXCORES]; /* other regs va */
+ bool memseg; /* flag to toggle MEM_SEG register */
- uint curidx; /* current core index */
- uint dev_coreid; /* the core provides driver functions */
+ uint gpioidx; /* gpio control core index */
+ uint gpioid; /* gpio control coretype */
- bool memseg; /* flag to toggle MEM_SEG register */
+ uint numcores; /* # discovered cores */
+ uint coreid[SB_MAXCORES]; /* id of each core */
- uint gpioidx; /* gpio control core index */
- uint gpioid; /* gpio control coretype */
+ 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 numcores; /* # discovered cores */
- uint coreid[SB_MAXCORES]; /* id of each core */
+ 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 */
- 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 */
+ uint8 pmecap_offset; /* PM Capability offset in the config space */
+ bool pmecap; /* Capable of generating PME */
+ 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 +129,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 +169,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 +222,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 +274,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 +303,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;
+ return &ksi.sb;
}
-#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SB_BUS) */
+#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);
- }
-}
-
-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 +360,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 +378,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 +397,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 +407,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 +415,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 +433,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 +453,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 +486,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 +508,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 +542,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;
-uint
-sb_coreid(sb_t *sbh)
+ 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));
+
+ 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 +693,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 +712,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 +727,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 +759,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 +770,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 +783,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 +791,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 +803,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 +838,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 +864,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 +881,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 +901,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 +913,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 +977,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 +996,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 +1032,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)
{
- return (sb_find_pci_capability(si, PCI_CAP_PCIECAP_ID, NULL, NULL));
+ 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);
}
-/* scan the sb enumerated space to identify all cores */
-static void
-BCMINITFN(sb_scan)(sb_info_t *si)
+/* Enable PME generation and disable clkreq */
+void sb_pci_pmeen(sb_t * sbh)
{
+ 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);
+ }
+}
+
+/* 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 +1325,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 +1383,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 +1400,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 +1418,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 +1435,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 +1444,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 +1469,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 +1484,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 +1493,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 +1522,7 @@ sb_setcoreidx(sb_t *sbh, uint coreidx)
}
si->curmap = si->regs[coreidx];
break;
-#endif /* BCMJTAG */
+#endif /* BCMJTAG */
}
si->curidx = coreidx;
@@ -1123,14 +1535,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 +1547,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 +1555,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 +1563,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 +1571,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 +1579,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 +1594,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 +1609,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 +1617,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 +1628,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 +1653,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 +1662,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 +1672,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 +1681,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 +1703,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 +1877,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 +1902,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 +1922,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 +1945,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 +1961,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 +2001,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 +2015,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 +2053,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 +2095,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 +2104,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 +2154,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 +2287,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 +2305,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 +2390,7 @@ sb_base(uint32 admatch)
return (base);
}
-uint32
-sb_size(uint32 admatch)
+uint32 sb_size(uint32 admatch)
{
uint32 size;
uint type;
@@ -1743,21 +2401,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 +2444,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 +2476,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 +2490,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 +2505,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 +2514,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 +2549,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 +2569,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 +2594,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 +2605,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 +2614,7 @@ sb_clock(sb_t *sbh)
rate = rate / 2;
}
+ end:
/* switch back to previous core */
sb_setcoreidx(sbh, idx);
@@ -1937,9 +2623,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 +2643,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 +2651,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 +2674,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 +2686,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 +2710,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 +2722,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 +2746,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 +2785,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 +2816,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 +2838,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 +2850,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 +2872,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 +2884,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 +2906,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 +2919,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,78 +2933,318 @@ 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));
+}
+
+uint32 sb_gpiopull(sb_t * sbh, bool updown, uint32 mask, uint32 val)
+{
+ sb_info_t *si;
+ uint offs;
+
+ si = SB_INFO(sbh);
+ if (si->sb.ccrev < 20)
+ return -1;
+
+ offs =
+ (updown ? OFFSETOF(chipcregs_t, gpiopulldown) :
+ OFFSETOF(chipcregs_t, gpiopullup));
+ return (sb_corereg(sbh, SB_CC_IDX, offs, mask, val));
+}
+
+uint32 sb_gpioevent(sb_t * sbh, uint regtype, uint32 mask, uint32 val)
+{
+ sb_info_t *si;
+ uint offs;
+
+ si = SB_INFO(sbh);
+ if (si->sb.ccrev < 11)
+ return -1;
+
+ 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;
+
+ return (sb_corereg(sbh, SB_CC_IDX, offs, mask, val));
+}
+
+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;
+
+ ASSERT(event);
+ ASSERT(cb);
+
+ 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)
+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))
+ (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);
+ cc = (chipcregs_t *) sb_setcoreidx(&si->sb, si->curidx);
return (R_REG(si->osh, &cc->slow_clk_ctl) & SCC_SS_MASK);
- } else /* Insta-clock */
+ } 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)
+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);
+ 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) & CAP_PWR_CTL);
+ 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? (PCIMAXFREQ/64) : (PCIMINFREQ/64));
+ return (max_freq ? (PCIMAXFREQ / 64)
+ : (PCIMINFREQ / 64));
else
- return (max? (XTALMAXFREQ/32) : (XTALMINFREQ/32));
+ 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);
+ 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);
+ return (max_freq ? LPOMAXFREQ : LPOMINFREQ);
else if (slowclk == SCC_SS_XTAL)
- return (max? (XTALMAXFREQ/div) : (XTALMINFREQ/div));
+ return (max_freq ? (XTALMAXFREQ / div)
+ : (XTALMINFREQ / div));
else if (slowclk == SCC_SS_PCI)
- return (max? (PCIMAXFREQ/div) : (PCIMINFREQ/div));
+ 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 ? XTALMAXFREQ : (XTALMINFREQ/div));
+ return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div));
}
return (0);
}
-static void
-BCMINITFN(sb_clkctl_setdelay)(sb_info_t *si, void *chipcregs)
-{
- chipcregs_t * cc;
+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;
@@ -2341,15 +3264,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 +3279,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 +3316,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 +3347,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 +3416,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 +3430,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 +3441,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 +3486,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 +3498,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 +3506,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;
- core = sb_coreid(sbh);
- unit = sb_coreunit(sbh);
+ si = SB_INFO(sbh);
- chip = sb_chip(sbh);
- chippkg = sb_chippkg(sbh);
+ INTR_OFF(si, intr_val);
- progif = 0;
- header = PCI_HEADER_NORMAL;
+ 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 */
+
+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;
+
+ return device;
+}
+
+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 +3631,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 +3655,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 +3678,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 +3708,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 +3720,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 +3752,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 +3822,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 +3835,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 +3882,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 +4004,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 +4017,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 +4080,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 +4088,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 +4100,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 +4121,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 +4152,29 @@ sb_socram_size(sb_t *sbh)
coreinfo = R_REG(si->osh, &regs->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