uint32 si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) { si_info_t *sii; sii = SI_INFO(sih); /* only cores on SI_BUS share GPIO's and only applcation users need to * reserve/release GPIO */ if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); return -1; } /* make sure only one bit is set */ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); return -1; } /* already released */ if (!(si_gpioreservation & gpio_bitmask)) return -1; /* clear reservation */ si_gpioreservation &= ~gpio_bitmask; return si_gpioreservation; }
/* * Initialize local vars from the right source for this platform. * Return 0 on success, nonzero on error. */ int srom_var_init(void *sbh, uint bustype, void *curmap, void *osh, char **vars, int *count) { ASSERT(bustype == BUSTYPE(bustype)); if (vars == NULL) return (0); switch (BUSTYPE(bustype)) { case SB_BUS: /* These two could be asserts ... */ *vars = NULL; *count = 0; return(0); case PCI_BUS: ASSERT(curmap); /* can not be NULL */ return(initvars_srom_pci(osh, curmap, vars, count)); case PCMCIA_BUS: return(initvars_cis_pcmcia(sbh, curmap, osh, vars, count)); default: ASSERT(0); } return (-1); }
/* support only 16-bit word read from srom */ int srom_read(uint bustype, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf) { void *srom; uint i, off, nw; ASSERT(bustype == BUSTYPE(bustype)); /* check input - 16-bit access only */ if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2)) return 1; off = byteoff / 2; nw = nbytes / 2; if (BUSTYPE(bustype) == PCI_BUS) { if (!curmap) return 1; srom = (uchar*)curmap + PCI_BAR0_SPROM_OFFSET; if (sprom_read_pci(srom, off, buf, nw, FALSE)) return 1; } else if (BUSTYPE(bustype) == PCMCIA_BUS) { for (i = 0; i < nw; i++) { if (sprom_read_pcmcia(osh, (uint16)(off + i), (uint16*)(buf + i))) return 1; } } else { return 1; } return 0; }
/* * Initialize local vars from the right source for this platform. * Return 0 on success, nonzero on error. */ int srom_var_init(void *sbh, uint bustype, void *curmap, osl_t *osh, char **vars, uint *count) { ASSERT(bustype == BUSTYPE(bustype)); if (vars == NULL || count == NULL) return (0); switch (BUSTYPE(bustype)) { case SB_BUS: case JTAG_BUS: return initvars_flash_sb(sbh, vars, count); case PCI_BUS: ASSERT(curmap); /* can not be NULL */ return initvars_srom_pci(sbh, curmap, vars, count); case PCMCIA_BUS: return initvars_cis_pcmcia(sbh, osh, vars, count); default: ASSERT(0); } return (-1); }
static void sb_write_sbreg(si_info_t *sii, 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 (PCMCIA(sii)) { INTR_OFF(sii, intr_val); tmp = 1; OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ } if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { #ifdef IL_BIGENDIAN dummy = R_REG(sii->osh, sbr); W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); dummy = R_REG(sii->osh, sbr); W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); #else dummy = R_REG(sii->osh, sbr); W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); dummy = R_REG(sii->osh, sbr); W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); #endif /* IL_BIGENDIAN */ } else
uint pcie_writereg(si_t *sih, sbpcieregs_t *pcieregs, uint addrtype, uint offset, uint val) { osl_t *osh = si_osh(sih); ASSERT(pcieregs != NULL); BCM_REFERENCE(osh); if ((BUSTYPE(sih->bustype) == SI_BUS) || PCIE_GEN1(sih)) { switch (addrtype) { case PCIE_CONFIGREGS: W_REG(osh, (&pcieregs->configaddr), offset); W_REG(osh, (&pcieregs->configdata), val); break; case PCIE_PCIEREGS: W_REG(osh, (&pcieregs->u.pcie1.pcieindaddr), offset); W_REG(osh, (&pcieregs->u.pcie1.pcieinddata), val); break; default: ASSERT(0); break; } } else if (PCIE_GEN2(sih)) { W_REG(osh, (&pcieregs->configaddr), offset); W_REG(osh, (&pcieregs->configdata), val); } return 0; }
static int tbdffmt(Fmt* fmt) { char *p; int l, r; uint type, tbdf; if((p = malloc(READSTR)) == nil) return fmtstrcpy(fmt, "(tbdfconv)"); switch(fmt->r){ case 'T': tbdf = va_arg(fmt->args, uint); type = BUSTYPE(tbdf); if(type < nelem(bustypes)) l = snprint(p, READSTR, bustypes[type]); else l = snprint(p, READSTR, "%d", type); snprint(p+l, READSTR-l, ".%d.%d.%d", BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf)); break; default: snprint(p, READSTR, "(tbdfconv)"); break; } r = fmtstrcpy(fmt, p); free(p); return r; }
/* may be called with core in reset */ void si_detach(si_t *sih) { si_info_t *sii; uint idx; sii = SI_INFO(sih); if (sii == NULL) return; if (BUSTYPE(sih->bustype) == SI_BUS) for (idx = 0; idx < SI_MAXCORES; idx++) if (sii->common_info->regs[idx]) { REG_UNMAP(sii->common_info->regs[idx]); sii->common_info->regs[idx] = NULL; } if (1 == sii->common_info->attach_count--) { MFREE(sii->osh, sii->common_info, sizeof(si_common_info_t)); common_info_alloced = NULL; } #if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) if (sii != &ksii) #endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ MFREE(sii->osh, sii, sizeof(si_info_t)); }
static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) { /* need to set memseg flag for CF card first before any sb registers access */ if (BUSTYPE(bustype) == PCMCIA_BUS) sii->memseg = TRUE; if (BUSTYPE(bustype) == SDIO_BUS) { int err; uint8 clkset; /* Try forcing SDIO core to do ALPAvail request only */ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); if (!err) { uint8 clkval; /* If register supported, wait for ALPAvail and then force ALP */ clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL); if ((clkval & ~SBSDIO_AVBITS) == clkset) { SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), PMU_MAX_TRANSITION_DLY); if (!SBSDIO_ALPAV(clkval)) { SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n", clkval)); return FALSE; } clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); OSL_DELAY(65); } } #ifndef MMC_SDIO_FORCE_PULLUP /* Also, disable the extra SDIO pull-ups */ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); #endif } return TRUE; }
/* mask&set gpio interrupt mask bits */ uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority) { si_info_t *sii; uint regoff; sii = SI_INFO(sih); regoff = 0; /* gpios could be shared on router platforms */ if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { mask = priority ? (si_gpioreservation & mask) : ((si_gpioreservation | mask) & ~(si_gpioreservation)); val &= mask; } regoff = OFFSETOF(chipcregs_t, gpiointmask); return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); }
/* mask&set gpio output bits */ uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) { uint regoff; regoff = 0; /* gpios could be shared on router platforms * ignore reservation if it's high priority (e.g., test apps) */ if ((priority != GPIO_HI_PRIORITY) && (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { mask = priority ? (si_gpioreservation & mask) : ((si_gpioreservation | mask) & ~(si_gpioreservation)); val &= mask; } regoff = OFFSETOF(chipcregs_t, gpioout); return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); }
static void sb_write_sbreg(si_info_t *sii, 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 (PCMCIA(sii)) { INTR_OFF(sii, intr_val); tmp = 1; OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ } /* * WAR for PR18509, PR3864 and PR17322 * The config registers are always written as 32-bits. If write 16 bits, * the other 16 bits are random, which needs to be controlled to avoid side-effect. * This is required only for PCMCIA bus. */ if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { #ifdef IL_BIGENDIAN dummy = R_REG(sii->osh, sbr); W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); dummy = R_REG(sii->osh, sbr); W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); #else dummy = R_REG(sii->osh, sbr); W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); dummy = R_REG(sii->osh, sbr); W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); #endif /* IL_BIGENDIAN */ } else
static void sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v) { uint8 tmp; volatile uint32 dummy; uint32 intr_val = 0; if (PCMCIA(sii)) { INTR_OFF(sii, intr_val); tmp = 1; OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); } if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { dummy = R_REG(sii->osh, sbr); BCM_REFERENCE(dummy); W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); dummy = R_REG(sii->osh, sbr); BCM_REFERENCE(dummy); W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); } else
static int mpintrenablex(Vctl* v, int tbdf) { Bus *bus; Aintr *aintr; Apic *apic; Pcidev *pcidev; int bno, dno, hi, irq, lo, n, type, vno; char *typenm; /* * Find the bus. */ type = BUSTYPE(tbdf); bno = BUSBNO(tbdf); dno = BUSDNO(tbdf); if(type == BusISA) bno = mpisabus; vno = -1; for(bus = mpbus; bus != nil; bus = bus->next){ if(bus->type != type) continue; if(bus->busno == bno) break; } if(bus == nil){ typenm = type < 0 || type >= nelem(buses)? "": buses[type]; print("mpintrenablex: can't find bus type %d (%s) for irq %d " "%s busno %d\n", type, typenm, v->irq, v->name, bno); return -1; } /* * For PCI devices the interrupt pin (INT[ABCD]) and device * number are encoded into the entry irq field, so create something * to match on. The interrupt pin used by the device has to be * obtained from the PCI config space. */ if(bus->type == BusPCI){ pcidev = pcimatchtbdf(tbdf); if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0) irq = (dno<<2)|(n-1); else irq = -1; //print("pcidev %#uX: irq %#uX v->irq %#uX\n", tbdf, irq, v->irq); } else irq = v->irq; /* * Find a matching interrupt entry from the list of interrupts * attached to this bus. */ for(aintr = bus->aintr; aintr; aintr = aintr->next){ if(aintr->intr->irq != irq) continue; if (0) { PCMPintr* p = aintr->intr; print("mpintrenablex: bus %d intin %d irq %d\n", p->busno, p->intin, p->irq); } /* * Check if already enabled. Multifunction devices may share * INT[A-D]# so, if already enabled, check the polarity matches * and the trigger is level. * * Should check the devices differ only in the function number, * but that can wait for the planned enable/disable rewrite. * The RDT read here is safe for now as currently interrupts * are never disabled once enabled. */ apic = aintr->apic; ioapicrdtr(apic, aintr->intr->intin, 0, &lo); if(!(lo & ApicIMASK)){ vno = lo & 0xFF; //print("%s vector %d (!imask)\n", v->name, vno); n = mpintrinit(bus, aintr->intr, vno, v->irq); n |= ApicPHYSICAL; /* no-op */ lo &= ~(ApicRemoteIRR|ApicDELIVS); if(n != lo || !(n & ApicLEVEL)){ print("mpintrenable: multiple botch irq%d, tbdf %uX, lo %8.8uX, n %8.8uX\n", v->irq, tbdf, lo, n); return -1; } break; } /* * With the APIC a unique vector can be assigned to each * request to enable an interrupt. There are two reasons this * is a good idea: * 1) to prevent lost interrupts, no more than 2 interrupts * should be assigned per block of 16 vectors (there is an * in-service entry and a holding entry for each priority * level and there is one priority level per block of 16 * interrupts). * 2) each input pin on the IOAPIC will receive a different * vector regardless of whether the devices on that pin use * the same IRQ as devices on another pin. */ vno = VectorAPIC + (incref(&mpvnoref)-1)*8; //print("%s vector %d (imask)\n", v->name, vno); if(vno > MaxVectorAPIC){ print("mpintrenable: vno %d, irq %d, tbdf %uX\n", vno, v->irq, tbdf); return -1; } hi = mpintrcpu()<<24; lo = mpintrinit(bus, aintr->intr, vno, v->irq); //print("lo 0x%uX: busno %d intr %d vno %d irq %d elcr 0x%uX\n", // lo, bus->busno, aintr->intr->irq, vno, // v->irq, i8259elcr); if(lo & ApicIMASK) return -1; lo |= ApicPHYSICAL; /* no-op */ if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC) ioapicrdtw(apic, aintr->intr->intin, hi, lo); //else // print("lo not enabled 0x%uX %d\n", // apic->flags, apic->type); break; } if (aintr) { v->isr = lapicisr; v->eoi = lapiceoi; } return vno; }
static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, uint *origidx, void *regs) { bool pci, pcie, pcie_gen2 = FALSE; uint i; uint pciidx, pcieidx, pcirev, pcierev; cc = si_setcoreidx(&sii->pub, SI_CC_IDX); ASSERT((uintptr)cc); /* get chipcommon rev */ sii->pub.ccrev = (int)si_corerev(&sii->pub); /* get chipcommon chipstatus */ if (sii->pub.ccrev >= 11) sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); /* get chipcommon capabilites */ sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); /* get chipcommon extended capabilities */ if (sii->pub.ccrev >= 35) sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); /* get pmu rev and caps */ if (sii->pub.cccaps & CC_CAP_PMU) { sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; } SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, sii->pub.pmucaps)); /* figure out bus/orignal core idx */ sii->pub.buscoretype = NODEV_CORE_ID; sii->pub.buscorerev = (uint)NOREV; sii->pub.buscoreidx = BADIDX; pci = pcie = FALSE; pcirev = pcierev = (uint)NOREV; pciidx = pcieidx = BADIDX; for (i = 0; i < sii->numcores; i++) { uint cid, crev; si_setcoreidx(&sii->pub, i); cid = si_coreid(&sii->pub); crev = si_corerev(&sii->pub); /* Display cores found */ SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", i, cid, crev, sii->coresba[i], sii->regs[i])); if (BUSTYPE(bustype) == PCI_BUS) { if (cid == PCI_CORE_ID) { pciidx = i; pcirev = crev; pci = TRUE; } else if ((cid == PCIE_CORE_ID) || (cid == PCIE2_CORE_ID)) { pcieidx = i; pcierev = crev; pcie = TRUE; if (cid == PCIE2_CORE_ID) pcie_gen2 = TRUE; } } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && (cid == PCMCIA_CORE_ID)) { sii->pub.buscorerev = crev; sii->pub.buscoretype = cid; sii->pub.buscoreidx = i; } else if (((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) && ((cid == PCMCIA_CORE_ID) || (cid == SDIOD_CORE_ID))) { sii->pub.buscorerev = crev; sii->pub.buscoretype = cid; sii->pub.buscoreidx = i; } /* find the core idx before entering this func. */ if ((savewin && (savewin == sii->coresba[i])) || (regs == sii->regs[i])) *origidx = i; } if (pci) { sii->pub.buscoretype = PCI_CORE_ID; sii->pub.buscorerev = pcirev; sii->pub.buscoreidx = pciidx; } else if (pcie) { if (pcie_gen2) sii->pub.buscoretype = PCIE2_C
static si_info_t * si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, uint bustype, void *sdh, char **vars, uint *varsz) { struct si_pub *sih = &sii->pub; uint32 w, savewin; chipcregs_t *cc; char *pvars = NULL; uint origidx; ASSERT(GOODREGS(regs)); bzero((uchar*)sii, sizeof(si_info_t)); { if (NULL == (common_info_alloced = (void *)MALLOC(osh, sizeof(si_common_info_t)))) { SI_ERROR(("si_doattach: malloc failed! malloced %dbytes\n", MALLOCED(osh))); return (NULL); } bzero((uchar*)(common_info_alloced), sizeof(si_common_info_t)); } sii->common_info = (si_common_info_t *)common_info_alloced; sii->common_info->attach_count++; savewin = 0; sih->buscoreidx = BADIDX; sii->curmap = regs; sii->sdh = sdh; sii->osh = osh; /* find Chipcommon address */ if (bustype == PCI_BUS) { savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) savewin = SI_ENUM_BASE; OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); cc = (chipcregs_t *)regs; } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { cc = (chipcregs_t *)sii->curmap; } else { cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); } sih->bustype = bustype; if (bustype != BUSTYPE(bustype)) { SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype))); return NULL; } /* bus/core/clk setup for register access */ if (!si_buscore_prep(sii, bustype, devid, sdh)) { SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); return NULL; } /* ChipID recognition. * We assume we can read chipid at offset 0 from the regs arg. * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon), * some way of recognizing them needs to be added here. */ w = R_REG(osh, &cc->chipid); sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; /* Might as wll fill in chip id rev & pkg */ sih->chip = w & CID_ID_MASK; sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chippkg != BCM4329_289PIN_PKG_ID)) sih->chippkg = BCM4329_182PIN_PKG_ID; sih->issim = IS_SIM(sih->chippkg); /* scan for cores */ if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) { SI_MSG(("Found chip type SB (0x%08x)\n", w)); sb_scan(&sii->pub, regs, devid); } else if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) { SI_MSG(("Found chip type AI (0x%08x)\n", w)); /* pass chipc address instead of original core base */ ai_scan(&sii->pub, (void *)cc, devid); } else { SI_ERROR(("Found chip of unkown type (0x%08x)\n", w)); return NULL; } /* no cores found, bail out */ if (sii->numcores == 0) { SI_ERROR(("si_doattach: could not find any cores\n")); return NULL; } /* bus/core/clk setup */ origidx = SI_CC_IDX; if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { SI_ERROR(("si_doattach: si_buscore_setup failed\n")); return NULL; } pvars = NULL; if (sii->pub.ccrev >= 20) { cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); W_REG(osh, &cc->gpiopullup, 0); W_REG(osh, &cc->gpiopulldown, 0); si_setcoreidx(sih, origidx); } /* Skip PMU initialization from the Dongle Host. * Firmware will take care of it when it comes up. */ return (sii); }
static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, uint *origidx, void *regs) { bool pci, pcie; uint i; uint pciidx, pcieidx, pcirev, pcierev; cc = si_setcoreidx(&sii->pub, SI_CC_IDX); ASSERT((uintptr)cc); /* get chipcommon rev */ sii->pub.ccrev = (int)si_corerev(&sii->pub); /* get chipcommon chipstatus */ if (sii->pub.ccrev >= 11) sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); /* get chipcommon capabilites */ sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); /* get pmu rev and caps */ if (sii->pub.cccaps & CC_CAP_PMU) { sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; } SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, sii->pub.pmucaps)); /* figure out bus/orignal core idx */ sii->pub.buscoretype = NODEV_CORE_ID; sii->pub.buscorerev = NOREV; sii->pub.buscoreidx = BADIDX; pci = pcie = FALSE; pcirev = pcierev = NOREV; pciidx = pcieidx = BADIDX; for (i = 0; i < sii->numcores; i++) { uint cid, crev; si_setcoreidx(&sii->pub, i); cid = si_coreid(&sii->pub); crev = si_corerev(&sii->pub); /* Display cores found */ SI_MSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", i, cid, crev, sii->common_info->coresba[i], sii->common_info->regs[i])); if (BUSTYPE(bustype) == PCI_BUS) { if (cid == PCI_CORE_ID) { pciidx = i; pcirev = crev; pci = TRUE; } else if (cid == PCIE_CORE_ID) { pcieidx = i; pcierev = crev; pcie = TRUE; } } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && (cid == PCMCIA_CORE_ID)) { sii->pub.buscorerev = crev; sii->pub.buscoretype = cid; sii->pub.buscoreidx = i; } else if (((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) && ((cid == PCMCIA_CORE_ID) || (cid == SDIOD_CORE_ID))) { sii->pub.buscorerev = crev; sii->pub.buscoretype = cid; sii->pub.buscoreidx = i; } /* find the core idx before entering this func. */ if ((savewin && (savewin == sii->common_info->coresba[i])) || (regs == sii->common_info->regs[i])) *origidx = i; } SI_MSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, sii->pub.buscorerev)); if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) && (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (sii->pub.chiprev <= 3)) OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL); /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was * already running. */ if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) si_core_disable(&sii->pub, 0); } /* return to the original core */ si_setcoreidx(&sii->pub, *origidx); return TRUE; }
/* support only 16-bit word write into srom */ int srom_write(uint bustype, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf) { uint16 *srom; uint i, off, nw, crc_range; uint16 image[SPROM_SIZE], *p; uint8 crc; volatile uint32 val32; ASSERT(bustype == BUSTYPE(bustype)); /* check input - 16-bit access only */ if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2)) return 1; crc_range = (((BUSTYPE(bustype) == PCMCIA_BUS) || (BUSTYPE(bustype) == SDIO_BUS)) ? SPROM_SIZE : SPROM_CRC_RANGE) * 2; /* if changes made inside crc cover range */ if (byteoff < crc_range) { nw = (((byteoff + nbytes) > crc_range) ? byteoff + nbytes : crc_range) / 2; /* read data including entire first 64 words from srom */ if (srom_read(bustype, curmap, osh, 0, nw * 2, image)) return 1; /* make changes */ bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes); /* calculate crc */ htol16_buf(image, crc_range); crc = ~hndcrc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE); ltoh16_buf(image, crc_range); image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff); p = image; off = 0; } else { p = buf; off = byteoff / 2; nw = nbytes / 2; } if (BUSTYPE(bustype) == PCI_BUS) { srom = (uint16*)((uchar*)curmap + PCI_BAR0_SPROM_OFFSET); /* enable writes to the SPROM */ val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); val32 |= SPROM_WRITEEN; OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32); bcm_mdelay(WRITE_ENABLE_DELAY); /* write srom */ for (i = 0; i < nw; i++) { W_REG(&srom[off + i], p[i]); bcm_mdelay(WRITE_WORD_DELAY); } /* disable writes to the SPROM */ OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & ~SPROM_WRITEEN); } else if (BUSTYPE(bustype) == PCMCIA_BUS) { /* enable writes to the SPROM */ if (sprom_cmd_pcmcia(osh, SROM_WEN)) return 1; bcm_mdelay(WRITE_ENABLE_DELAY); /* write srom */ for (i = 0; i < nw; i++) { sprom_write_pcmcia(osh, (uint16)(off + i), p[i]); bcm_mdelay(WRITE_WORD_DELAY); } /* disable writes to the SPROM */ if (sprom_cmd_pcmcia(osh, SROM_WDS)) return 1; } else { return 1; } bcm_mdelay(WRITE_ENABLE_DELAY); return 0; }
/* support only 16-bit word write into srom */ int srom_write(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf) { uint16 *srom; uint i, nw, crc_range; uint16 image[SPROM_SIZE]; uint8 crc; volatile uint32 val32; ASSERT(bustype == BUSTYPE(bustype)); /* check input - 16-bit access only */ if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2)) return 1; /* Are we writing the whole thing at once? */ if ((byteoff == 0) && ((nbytes == SPROM_SIZE) || (nbytes == (SPROM_CRC_RANGE * 2)) || (nbytes == (SROM4_WORDS * 2)))) { crc_range = nbytes; bcopy((void*)buf, (void*)image, nbytes); nw = nbytes / 2; } else { if ((BUSTYPE(bustype) == PCMCIA_BUS) || (BUSTYPE(bustype) == SDIO_BUS)) crc_range = SPROM_SIZE; else crc_range = SPROM_CRC_RANGE * 2; /* Tentative */ nw = crc_range / 2; /* read first 64 words from srom */ if (srom_read(bustype, curmap, osh, 0, crc_range, image)) return 1; if (image[SROM4_SIGN] == SROM4_SIGNATURE) { crc_range = SROM4_WORDS; nw = crc_range / 2; if (srom_read(bustype, curmap, osh, 0, crc_range, image)) return 1; } /* make changes */ bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes); } /* calculate crc */ htol16_buf(image, crc_range); crc = ~hndcrc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE); ltoh16_buf(image, crc_range); image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff); if (BUSTYPE(bustype) == PCI_BUS) { srom = (uint16*)((uchar*)curmap + PCI_BAR0_SPROM_OFFSET); /* enable writes to the SPROM */ val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); val32 |= SPROM_WRITEEN; OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32); bcm_mdelay(WRITE_ENABLE_DELAY); /* write srom */ for (i = 0; i < nw; i++) { W_REG(osh, &srom[i], image[i]); bcm_mdelay(WRITE_WORD_DELAY); } /* disable writes to the SPROM */ OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & ~SPROM_WRITEEN); } else if (BUSTYPE(bustype) == PCMCIA_BUS) { /* enable writes to the SPROM */ if (sprom_cmd_pcmcia(osh, SROM_WEN)) return 1; bcm_mdelay(WRITE_ENABLE_DELAY); /* write srom */ for (i = 0; i < nw; i++) { sprom_write_pcmcia(osh, (uint16)(i), image[i]); bcm_mdelay(WRITE_WORD_DELAY); } /* disable writes to the SPROM */ if (sprom_cmd_pcmcia(osh, SROM_WDS)) return 1; } else { return 1; } bcm_mdelay(WRITE_ENABLE_DELAY); return 0; }