uint8 pcie_ltrenable(void *pch, uint32 mask, uint32 val) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 reg_val; uint8 offset; offset = pi->pciecap_devctrl2_offset; if (!offset) return 0; reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32)); /* set operation */ if (mask) { if (val) reg_val |= PCIE_CAP_DEVCTRL2_LTR_ENAB_MASK; else reg_val &= ~PCIE_CAP_DEVCTRL2_LTR_ENAB_MASK; OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), reg_val); reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32)); } if (reg_val & PCIE_CAP_DEVCTRL2_LTR_ENAB_MASK) return 1; else return 0; }
/* ***** Support functions ***** */ static uint32 pcie_devcontrol_mrrs(void *pch, uint32 mask, uint32 val) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 reg_val; uint8 offset; offset = pi->pciecap_devctrl_offset; if (!offset) return 0; reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32)); /* set operation */ if (mask) { if (val > PCIE_CAP_DEVCTRL_MRRS_128B) { if (PCIE_GEN1(pi->sih) && (pi->sih->buscorerev < 18)) { PCI_ERROR(("%s pcie corerev %d doesn't support >128B MRRS", __FUNCTION__, pi->sih->buscorerev)); val = PCIE_CAP_DEVCTRL_MRRS_128B; } } reg_val &= ~PCIE_CAP_DEVCTRL_MRRS_MASK; reg_val |= (val << PCIE_CAP_DEVCTRL_MRRS_SHIFT) & PCIE_CAP_DEVCTRL_MRRS_MASK; OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), reg_val); reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32)); } return reg_val; }
/* ***** Support functions ***** */ uint8 pcie_clkreq(void *pch, uint32 mask, uint32 val) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 reg_val; uint8 offset; offset = pi->pciecap_lcreg_offset; if (!offset) return 0; reg_val = OSL_PCI_READ_CONFIG(pi->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(pi->osh, offset, sizeof(uint32), reg_val); reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32)); } if (reg_val & PCIE_CLKREQ_ENAB) return 1; else return 0; }
uint16 pcie_get_ssid(void* pch) { uint32 ssid = OSL_PCI_READ_CONFIG(((pcicore_info_t *)pch)->osh, PCI_CFG_SVID, sizeof(uint32)); return (uint16)(ssid >> 16); }
/* return TRUE if PM capability exists in the pci config space * Uses and caches the information using core handle */ static bool pcicore_pmecap(pcicore_info_t *pi) { uint8 cap_ptr; uint32 pmecap; sbpcieregs_t *pcieregs = pi->regs.pcieregs; uint16*reg16; if (!pi->pmecap_offset) { cap_ptr = pcicore_find_pci_capability(pi->osh, PCI_CAP_POWERMGMTCAP_ID, NULL, NULL); if (!cap_ptr) return FALSE; pi->pmecap_offset = cap_ptr; reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV8]; pi->pmebits = R_REG(pi->osh, reg16); pmecap = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset, sizeof(uint32)); /* At least one state can generate PME */ pi->pmecap = (pmecap & PME_CAP_PM_STATES) != 0; } return (pi->pmecap); }
void pcie_set_L1substate(void *pch, uint32 substate) { pcicore_info_t *pi = (pcicore_info_t *)pch; si_t *sih = pi->sih; sbpcieregs_t *pcieregs = pi->regs.pcieregs; uint32 data; ASSERT(PCIE_GEN2(sih)); ASSERT(substate <= 3); if (substate != 0) { /* turn on ASPM L1 */ data = pcie_readreg(sih, pcieregs, PCIE_CONFIGREGS, pi->pciecap_lcreg_offset); pcie_writereg(sih, pcieregs, PCIE_CONFIGREGS, pi->pciecap_lcreg_offset, data | 2); /* enable LTR */ pcie_ltrenable(pch, 1, 1); } /* PML1_sub_control1 can only be accessed by OSL_PCI_xxxx_CONFIG */ data = OSL_PCI_READ_CONFIG(pi->osh, PCIECFGREG_PML1_SUB_CTRL1, sizeof(uint32)) & 0xfffffff0; /* JIRA:SWWLAN-28455 */ if (substate & 1) data |= PCI_PM_L1_2_ENA_MASK | ASPM_L1_2_ENA_MASK; if (substate & 2) data |= PCI_PM_L1_1_ENA_MASK | ASPM_L1_1_ENA_MASK; OSL_PCI_WRITE_CONFIG(pi->osh, PCIECFGREG_PML1_SUB_CTRL1, sizeof(uint32), data); }
static uint32 pcie_devcontrol_mps(void *pch, uint32 mask, uint32 val) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 reg_val; uint8 offset; offset = pi->pciecap_devctrl_offset; if (!offset) return 0; reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32)); /* set operation */ if (mask) { reg_val &= ~PCIE_CAP_DEVCTRL_MPS_MASK; reg_val |= (val << PCIE_CAP_DEVCTRL_MPS_SHIFT) & PCIE_CAP_DEVCTRL_MPS_MASK; OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), reg_val); reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32)); } return reg_val; }
/* * Return TRUE if PME status set */ bool pcicore_pmestat(void *pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 w; if (!pcicore_pmecap(pi)) return FALSE; w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32)); return (w & PME_CSR_PME_STAT) == PME_CSR_PME_STAT; }
int pcie_configspace_cache(void* pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint offset = 0; uint32 *tmp = (uint32 *)pi->pcie_configspace; while (offset < PCI_CONFIG_SPACE_SIZE) { *tmp++ = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32)); offset += 4; } return 0; }
/* Enable PME generation */ void pcicore_pmeen(void *pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 w; /* if not pmecapable return */ if (!pcicore_pmecap(pi)) return; w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32)); w |= (PME_CSR_PME_EN); OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32), w); }
/* JIRA:SWWLAN-28745 val and return value: 0 Disabled 1 Enable using Message signaling[Var A] 2 Enable using Message signaling[Var B] 3 Enable using WAKE# signaling */ uint8 pcie_obffenable(void *pch, uint32 mask, uint32 val) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 reg_val; uint8 offset; offset = pi->pciecap_devctrl2_offset; if (!offset) return 0; reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32)); /* set operation */ if (mask) { reg_val = (reg_val & ~PCIE_CAP_DEVCTRL2_OBFF_ENAB_MASK) | ((val << PCIE_CAP_DEVCTRL2_OBFF_ENAB_SHIFT) & PCIE_CAP_DEVCTRL2_OBFF_ENAB_MASK); OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), reg_val); reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32)); } return (reg_val & PCIE_CAP_DEVCTRL2_OBFF_ENAB_MASK) >> PCIE_CAP_DEVCTRL2_OBFF_ENAB_SHIFT; }
/* Just uses PCI config accesses to find out, when needed before sb_attach is done */ bool pcicore_pmecap_fast(osl_t *osh) { uint8 cap_ptr; uint32 pmecap; cap_ptr = pcicore_find_pci_capability(osh, PCI_CAP_POWERMGMTCAP_ID, NULL, NULL); if (!cap_ptr) return FALSE; pmecap = OSL_PCI_READ_CONFIG(osh, cap_ptr, sizeof(uint32)); return ((pmecap & PME_CAP_PM_STATES) != 0); }
uint32 pcie_lcreg(void *pch, uint32 mask, uint32 val) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint8 offset; offset = pi->pciecap_lcreg_offset; if (!offset) return 0; /* set operation */ if (mask) OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), val); return OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32)); }
/* Needs to happen when update to shadow SROM is needed * : Coming out of 'standby'/'hibernate' * : If pcie_war_aspm_ovr state changed */ static void pcie_war_aspm_clkreq(pcicore_info_t *pi) { sbpcieregs_t *pcieregs = pi->regs.pcieregs; si_t *sih = pi->sih; uint16 val16, *reg16; uint32 w; if (!PCIEGEN1_ASPM(sih)) return; /* bypass this on QT or VSIM */ if (!ISSIM_ENAB(sih)) { reg16 = &pcieregs->sprom[SRSH_ASPM_OFFSET]; val16 = R_REG(pi->osh, reg16); val16 &= ~SRSH_ASPM_ENB; if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB) val16 |= SRSH_ASPM_ENB; else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB) val16 |= SRSH_ASPM_L1_ENB; else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB) val16 |= SRSH_ASPM_L0s_ENB; W_REG(pi->osh, reg16, val16); w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32)); w &= ~PCIE_ASPM_ENAB; w |= pi->pcie_war_aspm_ovr; OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32), w); } reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5]; val16 = R_REG(pi->osh, reg16); if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) { val16 |= SRSH_CLKREQ_ENB; pi->pcie_pr42767 = TRUE; } else val16 &= ~SRSH_CLKREQ_ENB; W_REG(pi->osh, reg16, val16); }
/* Disable PME generation, clear the PME status bit if set */ void pcicore_pmeclr(void *pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 w; if (!pcicore_pmecap(pi)) return; pcie_war_pmebits(pi); w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32)); PCI_ERROR(("pcicore_pci_pmeclr PMECSR : 0x%x\n", w)); /* PMESTAT is cleared by writing 1 to it */ w &= ~(PME_CSR_PME_EN); OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32), w); }
/* Needs to happen when update to shadow SROM is needed * : Coming out of 'standby'/'hibernate' * : If pcie_war_aspm_ovr state changed */ static void pcie_war_aspm_clkreq(pcicore_info_t *pi) { sbpcieregs_t *pcieregs = pi->regs.pcieregs; si_t *sih = pi->sih; uint16 val16, *reg16; uint32 w; if (!PCIE_ASPM(sih)) return; /* PR43448 WAR: Enable ASPM in the shadow SROM and Link control */ /* bypass this on QT or VSIM */ if (sih->chippkg != HDLSIM_PKG_ID && sih->chippkg != HWSIM_PKG_ID) { reg16 = &pcieregs->sprom[SRSH_ASPM_OFFSET]; val16 = R_REG(pi->osh, reg16); if (!pi->pcie_war_aspm_ovr) val16 |= SRSH_ASPM_ENB; else val16 &= ~SRSH_ASPM_ENB; W_REG(pi->osh, reg16, val16); w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32)); if (!pi->pcie_war_aspm_ovr) w |= PCIE_ASPM_ENAB; else w &= ~PCIE_ASPM_ENAB; OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32), w); } /* PR42767 WAR: if clockreq is not advertized in SROM, advertize it */ reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5]; val16 = R_REG(pi->osh, reg16); if (!pi->pcie_war_aspm_ovr) { val16 |= SRSH_CLKREQ_ENB; pi->pcie_pr42767 = TRUE; } else val16 &= ~SRSH_CLKREQ_ENB; W_REG(pi->osh, reg16, val16); }
/* When the device is going to enter D3 state (or the system is going to enter S3/S4 states */ void pcicore_sleep(void *pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 w; if (!pi || !PCIE_ASPM(pi->sih)) return; /* PR43448: Clear ASPM L1 when going to sleep as while coming out of standby/sleep, * ASPM L1 should not be accidentally enabled before driver has a chance to apply * the WAR */ w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32)); w &= ~PCIE_CAP_LCREG_ASPML1; OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32), w); /* Clear the state for PR42767 to make sure it's applied on the way up */ pi->pcie_pr42767 = FALSE; }
void pcicore_pmestatclr(void *pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 w; if (!pcicore_pmecap(pi)) return; pcie_war_pmebits(pi); w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32)); PCI_ERROR(("pcicore_pmestatclr PMECSR : 0x%x\n", w)); /* Writing a 1 to PMESTAT will clear it */ if ((w & PME_CSR_PME_STAT) == PME_CSR_PME_STAT) { OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32), w); } }
/* return TRUE if PM capability exists in the pci config space * Uses and caches the information using core handle */ static bool pcicore_pmecap(pcicore_info_t *pi) { uint8 cap_ptr; uint32 pmecap; if (!pi->pmecap_offset) { cap_ptr = pcicore_find_pci_capability(pi->osh, PCI_CAP_POWERMGMTCAP_ID, NULL, NULL); if (!cap_ptr) return FALSE; pi->pmecap_offset = cap_ptr; pmecap = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset, sizeof(uint32)); /* At least one state can generate PME */ pi->pmecap = (pmecap & PME_CAP_PM_STATES) != 0; } return (pi->pmecap); }
uint32 pcie_get_L1substate(void *pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; si_t *sih = pi->sih; uint32 data, substate = 0; ASSERT(PCIE_GEN2(sih)); UNUSED_PARAMETER(sih); data = OSL_PCI_READ_CONFIG(pi->osh, PCIECFGREG_PML1_SUB_CTRL1, sizeof(uint32)); /* JIRA:SWWLAN-28455 */ if (data & (PCI_PM_L1_2_ENA_MASK | ASPM_L1_2_ENA_MASK)) substate |= 1; if (data & (PCI_PM_L1_1_ENA_MASK | ASPM_L1_1_ENA_MASK)) substate |= 2; return substate; }
/* Disable PME generation, clear the PME status bit if set and * return TRUE if PME status set */ bool pcicore_pmeclr(void *pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 w; bool ret = FALSE; if (!pcicore_pmecap(pi)) return ret; w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32)); PCI_ERROR(("pcicore_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(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32), w); return ret; }
/* When the device is going to enter D3 state (or the system is going to enter S3/S4 states */ void pcicore_sleep(void *pch) { pcicore_info_t *pi = (pcicore_info_t *)pch; uint32 w; if (!pi || !PCIE_GEN1(pi->sih)) return; pcie_power_save_upd(pi, FALSE); if (!PCIEGEN1_ASPM(pi->sih)) return; w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32)); w &= ~PCIE_CAP_LCREG_ASPML1; OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32), w); pi->pcie_pr42767 = FALSE; }
/* support only 16-bit word write into srom */ int srom_write(uint bus, 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; /* check input - 16-bit access only */ if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2)) return 1; crc_range = ((bus == PCMCIA_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(bus, 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 = ~crc8((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 (bus == PCI_BUS) { srom = (uint16*)((uint)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(500); /* write srom */ for (i = 0; i < nw; i++) { W_REG(&srom[off + i], p[i]); bcm_mdelay(20); } /* disable writes to the SPROM */ OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & ~SPROM_WRITEEN); } else if (bus == PCMCIA_BUS) { /* enable writes to the SPROM */ if (sprom_cmd_pcmcia(osh, SROM_WEN)) return 1; bcm_mdelay(500); /* write srom */ for (i = 0; i < nw; i++) { sprom_write_pcmcia(osh, (uint16)(off + i), p[i]); bcm_mdelay(20); } /* disable writes to the SPROM */ if (sprom_cmd_pcmcia(osh, SROM_WDS)) return 1; } else { return 1; } bcm_mdelay(500); return 0; }
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); }
/* * Initialize nonvolatile variable table from sprom. * Return 0 on success, nonzero on error. */ static int initvars_srom_pci(void *sbh, void *curmap, char **vars, uint *count) { uint16 w, *b; uint8 sromrev = 0; struct ether_addr ea; char eabuf[32]; uint32 w32; int woff, i; char *vp, *base; osl_t *osh = sb_osh(sbh); bool flash = FALSE; char name[SB_DEVPATH_BUFSZ+16], *value; char devpath[SB_DEVPATH_BUFSZ]; int err; /* * Apply CRC over SROM content regardless SROM is present or not, * and use variable <devpath>sromrev's existance in flash to decide * if we should return an error when CRC fails or read SROM variables * from flash. */ b = MALLOC(osh, SROM_MAX); ASSERT(b); if (!b) return -2; err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, 64, TRUE); if (b[SROM4_SIGN] == SROM4_SIGNATURE) { /* sromrev >= 4, read more */ err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, SROM4_WORDS, TRUE); sromrev = b[SROM4_WORDS - 1] & 0xff; } else if (err == 0) { /* srom is good and is rev < 4 */ /* top word of sprom contains version and crc8 */ sromrev = b[63] & 0xff; /* bcm4401 sroms misprogrammed */ if (sromrev == 0x10) sromrev = 1; } if (err) { #ifdef WLTEST BS_ERROR(("SROM Crc Error, so see if we could use a default\n")); w32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); if (w32 & SPROM_OTPIN_USE) { BS_ERROR(("srom crc failed with OTP, use default vars....\n")); vp = base = mfgsromvars; if (sb_chip(sbh) == BCM4311_CHIP_ID) { BS_ERROR(("setting the devid to be 4311\n")); vp += sprintf(vp, "devid=0x4311"); vp++; } bcopy(defaultsromvars, vp, MFGSROM_DEFVARSLEN); vp += MFGSROM_DEFVARSLEN; goto varsdone; } else { BS_ERROR(("srom crc failed with SPROM....\n")); #endif /* WLTEST */ if ((err = sb_devpath(sbh, devpath, sizeof(devpath)))) return err; sprintf(name, "%ssromrev", devpath); if (!(value = getvar(NULL, name))) return (-1); sromrev = (uint8)bcm_strtoul(value, NULL, 0); flash = TRUE; #ifdef WLTEST } #endif /* WLTEST */ } /* srom version check */ if (sromrev > 4) return (-2); ASSERT(vars); ASSERT(count); base = vp = MALLOC(osh, VARS_MAX); ASSERT(vp); if (!vp) return -2; /* read variables from flash */ if (flash) { if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath))) goto err; goto varsdone; } vp += sprintf(vp, "sromrev=%d", sromrev); vp++; if (sromrev >= 4) { uint path, pathbase; const uint pathbases[MAX_PATH] = {SROM4_PATH0, SROM4_PATH1, SROM4_PATH2, SROM4_PATH3}; vp += sprintf(vp, "boardrev=%d", b[SROM4_BREV]); vp++; vp += sprintf(vp, "boardflags=%d", (b[SROM4_BFL1] << 16) | b[SROM4_BFL0]); vp++; vp += sprintf(vp, "boardflags2=%d", (b[SROM4_BFL3] << 16) | b[SROM4_BFL2]); vp++; /* The macaddr */ ea.octet[0] = (b[SROM4_MACHI] >> 8) & 0xff; ea.octet[1] = b[SROM4_MACHI] & 0xff; ea.octet[2] = (b[SROM4_MACMID] >> 8) & 0xff; ea.octet[3] = b[SROM4_MACMID] & 0xff; ea.octet[4] = (b[SROM4_MACLO] >> 8) & 0xff; ea.octet[5] = b[SROM4_MACLO] & 0xff; bcm_ether_ntoa(&ea, eabuf); vp += sprintf(vp, "macaddr=%s", eabuf); vp++; w = b[SROM4_CCODE]; if (w == 0) vp += sprintf(vp, "ccode="); else vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff)); vp++; vp += sprintf(vp, "regrev=%d", b[SROM4_REGREV]); vp++; w = b[SROM4_LEDBH10]; if ((w != 0) && (w != 0xffff)) { /* ledbh0 */ vp += sprintf(vp, "ledbh0=%d", (w & 0xff)); vp++; /* ledbh1 */ vp += sprintf(vp, "ledbh1=%d", (w >> 8) & 0xff); vp++; }
/* Attach to PCI-SPI Host Controller Hardware */ bool spi_hw_attach(sdioh_info_t *sd) { osl_t *osh; spih_info_t *si; sd_trace(("%s: enter\n", __FUNCTION__)); osh = sd->osh; if ((si = (spih_info_t *)MALLOC(osh, sizeof(spih_info_t))) == NULL) { sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); return FALSE; } bzero(si, sizeof(spih_info_t)); sd->controller = si; si->osh = sd->osh; si->rev = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_REV, 4) & 0xFF; if (si->rev < 3) { sd_err(("Host controller %d not supported, please upgrade to rev >= 3\n", si->rev)); MFREE(osh, si, sizeof(spih_info_t)); return (FALSE); } sd_err(("Attaching to Generic PCI SPI Host Controller Rev %d\n", si->rev)); /* FPGA Revision < 3 not supported by driver anymore. */ ASSERT(si->rev >= 3); si->bar0 = sd->bar0; /* Rev < 10 PciSpiHost has 2 BARs: * BAR0 = PCI Core Registers * BAR1 = PciSpiHost Registers (all other cores on backplane) * * Rev 10 and up use a different PCI core which only has a single * BAR0 which contains the PciSpiHost Registers. */ if (si->rev < 10) { si->pciregs = (spih_pciregs_t *)spi_reg_map(osh, (uintptr)si->bar0, sizeof(spih_pciregs_t)); sd_err(("Mapped PCI Core regs to BAR0 at %p\n", si->pciregs)); si->bar1 = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_BAR1, 4); si->regs = (spih_regs_t *)spi_reg_map(osh, (uintptr)si->bar1, sizeof(spih_regs_t)); sd_err(("Mapped SPI Controller regs to BAR1 at %p\n", si->regs)); } else { si->regs = (spih_regs_t *)spi_reg_map(osh, (uintptr)si->bar0, sizeof(spih_regs_t)); sd_err(("Mapped SPI Controller regs to BAR0 at %p\n", si->regs)); si->pciregs = NULL; } /* Enable SPI Controller, 16.67MHz SPI Clock */ SPIPCI_WREG(osh, &si->regs->spih_ctrl, 0x000000d1); /* Set extended feature register to defaults */ SPIPCI_WREG(osh, &si->regs->spih_ext, 0x00000000); /* Set GPIO CS# High (de-asserted) */ SPIPCI_WREG(osh, &si->regs->spih_gpio_data, SPIH_CS); /* set GPIO[0] to output for CS# */ /* set GPIO[1] to output for power control */ /* set GPIO[2] to input for card detect */ SPIPCI_WREG(osh, &si->regs->spih_gpio_ctrl, (SPIH_CS | SPIH_SLOT_POWER)); /* Clear out the Read FIFO in case there is any stuff left in there from a previous run. */ while ((SPIPCI_RREG(osh, &si->regs->spih_stat) & SPIH_RFEMPTY) == 0) { SPIPCI_RREG(osh, &si->regs->spih_data); } /* Wait for power to stabilize to the SDIO Card (100msec was insufficient) */ OSL_DELAY(250000); /* Check card detect on FPGA Revision >= 4 */ if (si->rev >= 4) { if (SPIPCI_RREG(osh, &si->regs->spih_gpio_data) & SPIH_CARD_DETECT) { sd_err(("%s: no card detected in SD slot\n", __FUNCTION__)); spi_reg_unmap(osh, (uintptr)si->regs, sizeof(spih_regs_t)); if (si->pciregs) { spi_reg_unmap(osh, (uintptr)si->pciregs, sizeof(spih_pciregs_t)); } MFREE(osh, si, sizeof(spih_info_t)); return FALSE; } } /* Interrupts are level sensitive */ SPIPCI_WREG(osh, &si->regs->spih_int_edge, 0x80000000); /* Interrupts are active low. */ SPIPCI_WREG(osh, &si->regs->spih_int_pol, 0x40000004); /* Enable interrupts through PCI Core. */ if (si->pciregs) { SPIPCI_WREG(osh, &si->pciregs->ICR, PCI_INT_PROP_EN); } sd_trace(("%s: exit\n", __FUNCTION__)); return TRUE; }
bool spi_hw_attach(sdioh_info_t *sd) { osl_t *osh; spih_info_t *si; sd_trace(("%s: enter\n", __FUNCTION__)); osh = sd->osh; if ((si = (spih_info_t *)MALLOC(osh, sizeof(spih_info_t))) == NULL) { sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); return FALSE; } bzero(si, sizeof(spih_info_t)); sd->controller = si; si->osh = sd->osh; si->rev = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_REV, 4) & 0xFF; if (si->rev < 3) { sd_err(("Host controller %d not supported, please upgrade to rev >= 3\n", si->rev)); MFREE(osh, si, sizeof(spih_info_t)); return (FALSE); } sd_err(("Attaching to Generic PCI SPI Host Controller Rev %d\n", si->rev)); ASSERT(si->rev >= 3); si->bar0 = sd->bar0; if (si->rev < 10) { si->pciregs = (spih_pciregs_t *)spi_reg_map(osh, (uintptr)si->bar0, sizeof(spih_pciregs_t)); sd_err(("Mapped PCI Core regs to BAR0 at %p\n", si->pciregs)); si->bar1 = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_BAR1, 4); si->regs = (spih_regs_t *)spi_reg_map(osh, (uintptr)si->bar1, sizeof(spih_regs_t)); sd_err(("Mapped SPI Controller regs to BAR1 at %p\n", si->regs)); } else { si->regs = (spih_regs_t *)spi_reg_map(osh, (uintptr)si->bar0, sizeof(spih_regs_t)); sd_err(("Mapped SPI Controller regs to BAR0 at %p\n", si->regs)); si->pciregs = NULL; } SPIPCI_WREG(osh, &si->regs->spih_ctrl, 0x000000d1); SPIPCI_WREG(osh, &si->regs->spih_ext, 0x00000000); SPIPCI_WREG(osh, &si->regs->spih_gpio_data, SPIH_CS); SPIPCI_WREG(osh, &si->regs->spih_gpio_ctrl, (SPIH_CS | SPIH_SLOT_POWER)); while ((SPIPCI_RREG(osh, &si->regs->spih_stat) & SPIH_RFEMPTY) == 0) { SPIPCI_RREG(osh, &si->regs->spih_data); } OSL_DELAY(250000); if (si->rev >= 4) { if (SPIPCI_RREG(osh, &si->regs->spih_gpio_data) & SPIH_CARD_DETECT) { sd_err(("%s: no card detected in SD slot\n", __FUNCTION__)); spi_reg_unmap(osh, (uintptr)si->regs, sizeof(spih_regs_t)); if (si->pciregs) { spi_reg_unmap(osh, (uintptr)si->pciregs, sizeof(spih_pciregs_t)); } MFREE(osh, si, sizeof(spih_info_t)); return FALSE; } } SPIPCI_WREG(osh, &si->regs->spih_int_edge, 0x80000000); SPIPCI_WREG(osh, &si->regs->spih_int_pol, 0x40000004); if (si->pciregs) { SPIPCI_WREG(osh, &si->pciregs->ICR, PCI_INT_PROP_EN); } sd_trace(("%s: exit\n", __FUNCTION__)); return TRUE; }
uint32 pcie_get_bar0(void* pch) { return OSL_PCI_READ_CONFIG(((pcicore_info_t *)pch)->osh, PCI_CFG_BAR0, sizeof(uint32)); }
/* 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; }