/* Initialize nand flash access */ hndsflash_t * hndsflash_init(si_t *sih) { uint32 origidx; ASSERT(sih); /* Already initialized ? */ if (hndsflash) return hndsflash; /* spin lock here */ origidx = si_coreidx(sih); #ifdef __mips__ if (!hndsflash) hndsflash = ccsflash_init(sih); #endif /* __mips__ */ #ifdef __ARM_ARCH_7A__ if (!hndsflash) hndsflash = spiflash_init(sih); #endif /* __ARM_ARCH_7A__ */ si_setcoreidx(sih, origidx); return hndsflash; }
/* * Read host bridge PCI config registers from Silicon Backplane ( >= rev8 ). * * It returns TRUE to indicate that access to the host bridge's pci config * from SI is ok, and values in 'addr' and 'val' are valid. * * It can only read registers at multiple of 4-bytes. Callers must pick up * needed bytes from 'val' based on 'off' value. Value in 'addr' reflects * the register address where value in 'val' is read. */ static bool si_pcihb_read_config(si_t *sih, uint bus, uint dev, uint func, uint off, uint32 **addr, uint32 *val) { sbpciregs_t *pci; osl_t *osh; uint coreidx; bool ret = FALSE; uint8 port; /* sanity check */ ASSERT(PCIE_IS_BUS_HOST_BRIDGE(bus)); ASSERT(dev == pci_hbslot); /* we support only two functions on device 0 */ if (func > 1) return FALSE; /* Convert logical bus to physical port/bus for following processing */ port = PCIE_GET_PORT_BY_BUS(bus); osh = si_osh(sih); /* read pci config when core rev >= 8 */ coreidx = si_coreidx(sih); pci = (sbpciregs_t *)si_setcore(sih, PCI_CORE_ID, port); if (pci) { if (si_corerev(sih) >= PCI_HBSBCFG_REV) { *addr = (uint32 *)&pci->pcicfg[func][off >> 2]; *val = R_REG(osh, *addr); ret = TRUE; } } else {
/* Initialize nand flash access */ hndnand_t * hndnand_init(si_t *sih) { uint32 origidx; ASSERT(sih); /* Already initialized ? */ if (hndnand) return hndnand; origidx = si_coreidx(sih); #ifdef __mips__ if (!hndnand) hndnand = nflash_init(sih); #endif #ifdef __ARM_ARCH_7A__ if (!hndnand) hndnand = nandcore_init(sih); #endif si_setcoreidx(sih, origidx); return hndnand; }
bool BCMATTACHFN(si_cc_register_isr)(si_t *sih, cc_isr_fn isr, uint32 ccintmask, void *cbdata) { bool done = FALSE; chipcregs_t *regs; uint origidx; uint i; /* Save the current core index */ origidx = si_coreidx(sih); regs = si_setcoreidx(sih, SI_CC_IDX); ASSERT(regs); for (i = 0; i < MAX_CC_INT_SOURCE; i++) { if (cc_isr_desc[i].isr == NULL) { cc_isr_desc[i].isr = isr; cc_isr_desc[i].cbdata = cbdata; cc_isr_desc[i].intmask = ccintmask; done = TRUE; break; } } if (done) { cc_intmask = R_REG(si_osh(sih), ®s->intmask); cc_intmask |= ccintmask; W_REG(si_osh(sih), ®s->intmask, cc_intmask); } /* restore original coreidx */ si_setcoreidx(sih, origidx); return done; }
/* * Read host bridge PCI config registers from Silicon Backplane ( >= rev8 ). * * It returns TRUE to indicate that access to the host bridge's pci config * from SI is ok, and values in 'addr' and 'val' are valid. * * It can only read registers at multiple of 4-bytes. Callers must pick up * needed bytes from 'val' based on 'off' value. Value in 'addr' reflects * the register address where value in 'val' is read. */ static bool si_pcihb_read_config(si_t *sih, uint coreunit, uint bus, uint dev, uint func, uint off, uint32 **addr, uint32 *val) { sbpciregs_t *pci; osl_t *osh; uint coreidx; bool ret = FALSE; /* sanity check */ ASSERT(hndpci_is_hostbridge(bus, dev)); /* we support only two functions on device 0 */ if (func > 1) return FALSE; osh = si_osh(sih); /* read pci config when core rev >= 8 */ coreidx = si_coreidx(sih); pci = (sbpciregs_t *)si_setcore(sih, PCI_CORE_ID, coreunit); if (pci) { if (si_corerev(sih) >= PCI_HBSBCFG_REV) { *addr = (uint32 *)&pci->pcicfg[func][off >> 2]; *val = R_REG(osh, *addr); ret = TRUE; } } else {
int si_bist_cc(si_t *sih, uint32 *biststatus) { si_info_t *sii; uint origidx; uint intr_val = 0; int error = 0; void *regs; int status; bool wasup; sii = SI_INFO(sih); SI_ERROR(("doing the bist on ChipC\n")); /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); /* Switch to CC core */ if (!(regs = si_setcore(sih, CC_CORE_ID, 0))) goto done; /* Get info for determining size */ if (!(wasup = si_iscoreup(sih))) si_core_reset(sih, 0, 0); status = si_corebist(sih); if (status == BCME_ERROR) { *biststatus = si_corereg(sih, si_coreidx(&sii->pub), 12, 0, 0); /* XXX: OTP gives the BIST error */ *biststatus &= ~(0x1); if (*biststatus) error = 1; } /* Return to previous state and core */ if (!wasup) si_core_disable(sih, 0); /* Return to previous state and core */ si_setcoreidx(sih, origidx); *biststatus = 0; done: INTR_RESTORE(sii, intr_val); return error; }
/* * Switch to 'coreidx', issue a single arbitrary 32bit * register mask&set operation, * switch back to the original core, and return the new value. * * When using the silicon backplane, no fidleing with interrupts * or core switches are needed. * * Also, when using pci/pcie, we can optimize away the core switching * for pci registers * and (on newer pci cores) chipcommon registers. */ uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) { uint origidx = 0; u32 *r = NULL; uint w; uint intr_val = 0; bool fast = false; si_info_t *sii; sii = SI_INFO(sih); ASSERT(GOODIDX(coreidx)); ASSERT(regoff < SI_CORE_SIZE); ASSERT((val & ~mask) == 0); if (coreidx >= SI_MAXCORES) return 0; if (!fast) { INTR_OFF(sii, intr_val); /* save current core index */ origidx = si_coreidx(&sii->pub); /* switch core */ r = (u32 *) ((unsigned char *) sb_setcoreidx(&sii->pub, coreidx) + regoff); } ASSERT(r != NULL); /* mask and set */ if (mask || val) { if (regoff >= SBCONFIGOFF) { w = (R_SBREG(sii, r) & ~mask) | val; W_SBREG(sii, r, w); } else { w = (R_REG(sii->osh, r) & ~mask) | val; W_REG(sii->osh, r, w); } } /* readback */ if (regoff >= SBCONFIGOFF) w = R_SBREG(sii, r); else w = R_REG(sii->osh, r); if (!fast) { /* restore core index */ if (origidx != coreidx) sb_setcoreidx(&sii->pub, origidx); INTR_RESTORE(sii, intr_val); } return w; }
/* * We utilize chipcommon configuration register SBFlagSt to implement a * smart shared IRQ handling machenism through which only ISRs registered * for the SB cores that raised the interrupt are invoked. This machenism * relies on the SBFlagSt register's reliable recording of the SB cores * that raised the interrupt. */ void __init arch_init_irq(void) { int i; uint32 coreidx, mips_core_id; void *regs; if (BCM330X(current_cpu_data.processor_id)) mips_core_id = MIPS33_CORE_ID; else if (MIPS74K(current_cpu_data.processor_id)) mips_core_id = MIPS74K_CORE_ID; else { printk(KERN_ERR "MIPS CPU type %x unknown", current_cpu_data.processor_id); return; } /* Cache chipc and mips33 config registers */ ASSERT(bcm947xx_sih); coreidx = si_coreidx(bcm947xx_sih); regs = si_setcore(bcm947xx_sih, mips_core_id, 0); mipsirq = si_irq(bcm947xx_sih); if (bcm947xx_sih->socitype == SOCI_SB) { if (regs) mipssbr = (sbconfig_t *)((ulong)regs + SBCONFIGOFF); if ((regs = si_setcore(bcm947xx_sih, CC_CORE_ID, 0))) ccsbr = (sbconfig_t *)((ulong)regs + SBCONFIGOFF); } si_setcoreidx(bcm947xx_sih, coreidx); if (BCM330X(current_cpu_data.processor_id)) { /* Cache mips33 sbintvec register */ if (mipssbr) shints = R_REG(NULL, &mipssbr->sbintvec); } else { uint32 *intmask; /* Use intmask5 register to route the timer interrupt */ intmask = (uint32 *) &((mips74kregs_t *)regs)->intmask[5]; W_REG(NULL, intmask, 1 << 31); intmask = (uint32 *) &((mips74kregs_t *)regs)->intmask[0]; shints = R_REG(NULL, intmask); /* Save the pointer to mips core registers */ mips_corereg = regs; } /* Install interrupt controllers */ for (i = 0; i < NR_IRQS; i++) { set_irq_chip(i, (i < SBMIPS_NUMIRQS ? &brcm_irq_type : &brcm_irq2_type)); } }
/* Enable register access to the chip */ static void adm_enable(adm_info_t *adm) { void *regs; /* Save current core index */ adm->coreidx = si_coreidx(adm->sih); /* Switch to GPIO core for faster access */ regs = si_gpiosetcore(adm->sih); ASSERT(regs); }
/* set the core to socram run bist and return bist status back */ int si_bist_socram(si_t *sih, uint32 *biststatus) { si_info_t *sii; uint origidx; uint intr_val = 0; sbsocramregs_t *regs; int error = 0; uint status = 0; SI_ERROR(("doing the bist on SOCRAM\n")); sii = SI_INFO(sih); /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); /* Switch to SOCRAM core */ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) goto done; si_core_reset(sih, SICF_BIST_EN, SICF_BIST_EN); /* Wait for bist done */ SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); status = si_core_sflags(sih, 0, 0); if (status & SISF_BIST_DONE) { if (status & SISF_BIST_ERROR) { *biststatus = R_REG(sii->osh, ®s->biststat); /* hnd_bist gives errors for ROM bist test, so ignore it */ *biststatus &= 0xFFFF; if (!*biststatus) error = 0; else error = 1; } } si_core_reset(sih, 0, 0); /* Return to previous state and core */ si_setcoreidx(sih, origidx); done: INTR_RESTORE(sii, intr_val); return error; }
void board_power_init(si_t *sih) { uint origidx; chipcregs_t *cc; int gpio; /* Drive gpio pin to HIGH to enable on-board switching regulator for COMA mode */ origidx = si_coreidx(sih); if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) != NULL) { gpio = getgpiopin(NULL, "coma_swreg", GPIO_PIN_NOTDEFINED); if (gpio != GPIO_PIN_NOTDEFINED) { gpio = 1 << gpio; si_gpioout(sih, gpio, gpio, GPIO_DRV_PRIORITY); si_gpioouten(sih, gpio, gpio, GPIO_DRV_PRIORITY); } } si_setcoreidx(sih, origidx); }
void pcie_watchdog_reset(osl_t *osh, si_t *sih, sbpcieregs_t *sbpcieregs) { uint32 val, i, lsc; uint16 cfg_offset[] = {PCIECFGREG_STATUS_CMD, PCIECFGREG_PM_CSR, PCIECFGREG_MSI_CAP, PCIECFGREG_MSI_ADDR_L, PCIECFGREG_MSI_ADDR_H, PCIECFGREG_MSI_DATA, PCIECFGREG_LINK_STATUS_CTRL2, PCIECFGREG_RBAR_CTRL, PCIECFGREG_PML1_SUB_CTRL1, PCIECFGREG_REG_BAR2_CONFIG, PCIECFGREG_REG_BAR3_CONFIG}; uint32 origidx = si_coreidx(sih); /* Disable/restore ASPM Control to protect the watchdog reset */ W_REG(osh, &sbpcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL); lsc = R_REG(osh, &sbpcieregs->configdata); val = lsc & (~PCIE_ASPM_ENAB); W_REG(osh, &sbpcieregs->configdata, val); si_setcore(sih, PCIE2_CORE_ID, 0); si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, 4); OSL_DELAY(100000); #ifdef BCMQT OSL_DELAY(200000); #endif /* BCMQT */ W_REG(osh, &sbpcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL); W_REG(osh, &sbpcieregs->configdata, lsc); /* Write configuration registers back to the shadow registers * cause shadow registers are cleared out after watchdog reset. */ for (i = 0; i < ARRAYSIZE(cfg_offset); i++) { W_REG(osh, &sbpcieregs->configaddr, cfg_offset[i]); val = R_REG(osh, &sbpcieregs->configdata); W_REG(osh, &sbpcieregs->configdata, val); } si_setcoreidx(sih, origidx); }
/* Return the RAM size of the SOCRAM core */ uint32 si_socram_size(si_t *sih) { si_info_t *sii; uint origidx; uint intr_val = 0; sbsocramregs_t *regs; bool wasup; uint corerev; uint32 coreinfo; uint memsize = 0; sii = SI_INFO(sih); /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); /* Switch to SOCRAM core */ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) goto done; /* Get info for determining size */ if (!(wasup = si_iscoreup(sih))) si_core_reset(sih, 0, 0); corerev = si_corerev(sih); coreinfo = R_REG(sii->osh, ®s->coreinfo); /* Calculate size from coreinfo based on rev */ if (corerev == 0) memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); else if (corerev < 3) { memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; } else {
/** * Balance between stable SDIO operation and power consumption is achieved using this function. * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this * function should read the VDDIO itself to select the correct table. For now it has been solved * with the 'BCM_SDIO_VDDIO' preprocessor constant. * * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if * hardware supports this), if no hw support drive strength is not programmed. */ void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) { sdiod_drive_str_t *str_tab = NULL; uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */ uint32 str_shift = 0; uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */ uint32 str_ovr_pmuval = 0; /* position of bit within this register */ pmuregs_t *pmu; uint origidx; if (!(sih->cccaps & CC_CAP_PMU)) { return; } /* Remember original core before switch to chipc/pmu */ origidx = si_coreidx(sih); if (AOB_ENAB(sih)) { pmu = si_setcore(sih, PMU_CORE_ID, 0); } else { pmu = si_setcoreidx(sih, SI_CC_IDX); } ASSERT(pmu != NULL); switch (SDIOD_DRVSTR_KEY(CHIPID(sih->chip), sih->pmurev)) { case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1; str_mask = 0x30000000; str_shift = 28; break; case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): if (sih->pmurev == 8) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; } else if (sih->pmurev == 11) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; } str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; str_mask = 0x00001800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): #if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3; } #else if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8; } #endif /* BCM_SDIO_VDDIO */ str_mask = 0x00000007; str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR; break; default: PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", bcm_chipname( CHIPID(sih->chip), chn, 8), CHIPREV(sih->chiprev), sih->pmurev)); break; } if (str_tab != NULL) { uint32 cc_data_temp; int i; /* Pick the lowest available drive strength equal or greater than the * requested strength. Drive strength of 0 requests tri-state. */ for (i = 0; drivestrength < str_tab[i].strength; i++) ; if (i > 0 && drivestrength > str_tab[i].strength) i--; W_REG(osh, &pmu->chipcontrol_addr, PMU_CHIPCTL1); cc_data_temp = R_REG(osh, &pmu->chipcontrol_data); cc_data_temp &= ~str_mask; cc_data_temp |= str_tab[i].sel << str_shift; W_REG(osh, &pmu->chipcontrol_data, cc_data_temp); if (str_ovr_pmuval) { /* enables the selected drive strength */ W_REG(osh, &pmu->chipcontrol_addr, str_ovr_pmuctl); OR_REG(osh, &pmu->chipcontrol_data, str_ovr_pmuval); } PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", drivestrength, str_tab[i].strength)); } /* Return to original core */ si_setcoreidx(sih, origidx); } /* si_sdiod_drive_strength_init */
int si_bist_d11(si_t *sih, uint32 *biststatus1, uint32 *biststatus2) { si_info_t *sii; uint origidx; uint intr_val = 0; void *regs; int error = 0; bool wasup; uint32 offset = SBCONFIGOFF + SBTMSTATELOW; uint32 max_res_mask; uint32 pmu_ctrl; *biststatus1 = 0; *biststatus2 = 0; SI_ERROR(("doing the bist on D11\n")); sii = SI_INFO(sih); if (CHIPTYPE(sih->socitype) != SOCI_SB) { return 0; } /* Block ints and save current core */ INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); /* Switch to D11 core */ if (!(regs = si_setcore(sih, D11_CORE_ID, 0))) goto done; /* Get info for determining size */ /* coming out of reset device shoudl have clk enabled, bw set, etc */ if (!(wasup = si_iscoreup(sih))) si_core_reset(sih, 0x4F, 0x4F); max_res_mask = si_corereg(sih, 0, OFFSETOF(chipcregs_t, max_res_mask), 0, 0); si_corereg(sih, 0, OFFSETOF(chipcregs_t, max_res_mask), ~0, 0x3fffff); if (si_corerev(&sii->pub) == 20) { uint32 phy_reset_val; uint32 bist_test_val, bist_status; /* XXX: enable the phy PLL */ pmu_ctrl = si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, 0, 0); pmu_ctrl |= 0x000010000; si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, ~0, pmu_ctrl); SPINWAIT(((si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, 0, 0) & 0x01000000) == 0), 1000000); pmu_ctrl = si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, 0, 0); /* take the phy out of reset */ phy_reset_val = si_corereg(sih, si_coreidx(&sii->pub), offset, 0, 0); phy_reset_val &= ~(0x0008 << SBTML_SICF_SHIFT); si_corereg(sih, si_coreidx(&sii->pub), offset, ~0, phy_reset_val); phy_reset_val = si_corereg(sih, si_coreidx(&sii->pub), offset, 0, 0); /* enable bist first */ bist_test_val = si_corereg(sih, si_coreidx(&sii->pub), offset, 0, 0); bist_test_val |= (SICF_BIST_EN << 16); si_corereg(sih, si_coreidx(&sii->pub), offset, ~0, bist_test_val); SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 1000000); bist_status = si_core_sflags(sih, 0, 0); SI_ERROR(("status are 0x%08x\n", bist_status)); if (bist_status & SISF_BIST_DONE) { if (bist_status & SISF_BIST_ERROR) { error = 1; *biststatus1 = si_corereg(sih, si_coreidx(&sii->pub), 12, 0, 0); *biststatus2 = si_corereg(sih, si_coreidx(&sii->pub), 16, 0, 0); } } /* stop the phy pll */ pmu_ctrl = si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, 0, 0); pmu_ctrl &= ~0x10000; si_corereg(sih, si_coreidx(&sii->pub), 0x1e8, ~0, pmu_ctrl); } /* remove the resource mask */ si_corereg(sih, 0, OFFSETOF(chipcregs_t, max_res_mask), ~0, max_res_mask); /* Return to previous state and core */ if (!wasup) si_core_disable(sih, 0); /* Return to previous state and core */ si_setcoreidx(sih, origidx); done: INTR_RESTORE(sii, intr_val); return error; }
/* * Setup the gige core. * Resetting the core will lose all settings. */ void hndgige_init(si_t *sih, uint32 unit, bool *rgmii) { volatile pci_config_regs *pci; sbgige_pcishim_t *ocp; sbconfig_t *sb; osl_t *osh; uint32 statelow; uint32 statehigh; uint32 base; uint32 idx; void *regs; /* Sanity checks */ ASSERT(sih); ASSERT(rgmii); idx = si_coreidx(sih); /* point to the gige core registers */ regs = si_setcore(sih, GIGETH_CORE_ID, unit); ASSERT(regs); osh = si_osh(sih); pci = &((sbgige_t *)regs)->pcicfg; ocp = &((sbgige_t *)regs)->pcishim; sb = &((sbgige_t *)regs)->sbconfig; /* Enable the core clock and memory access */ if (!si_iscoreup(sih)) si_core_reset(sih, 0, 0); /* * Setup the 64K memory-mapped region base address through BAR0. * Leave the other BAR values alone. */ base = si_addrspace(sih, 1); W_REG(osh, &pci->base[0], base); W_REG(osh, &pci->base[1], 0); /* * Enable the PCI memory access anyway. Any PCI config commands * issued before the core is enabled will go to the emulation * only and will not go to the real PCI config registers. */ OR_REG(osh, &pci->command, 2); /* * Enable the posted write flush scheme as follows: * * - Enable flush on any core register read * - Enable timeout on the flush * - Disable the interrupt mask when flushing * * This differs from the default setting only in that interrupts are * not masked. Since posted writes are not flushed on interrupt, the * driver must explicitly request a flush in its interrupt handling * by reading a core register. */ W_REG(osh, &ocp->FlushStatusControl, 0x68); /* * Determine whether the GbE is in GMII or RGMII mode. This is * indicated in bit 16 of the SBTMStateHigh register, which is * part of the core-specific flags field. * * For GMII, bypass the Rx/Tx DLLs, i.e. add no delay to RXC/GTXC * within the core. For RGMII, do not bypass the DLLs, resulting * in added delay for RXC/GTXC. The SBTMStateLow register contains * the controls for doing this in the core-specific flags field: * * bit 24 - Enable DLL controls * bit 20 - Bypass Rx DLL * bit 19 - Bypass Tx DLL */ statelow = R_REG(osh, &sb->sbtmstatelow); /* DLL controls */ statehigh = R_REG(osh, &sb->sbtmstatehigh); /* GMII/RGMII mode */ if ((statehigh & (1 << 16)) != 0) /* RGMII */ { statelow &= ~(1 << 20); /* no Rx bypass (delay) */ statelow &= ~(1 << 19); /* no Tx bypass (delay) */ *rgmii = TRUE; } else /* GMII */ { statelow |= (1 << 20); /* Rx bypass (no delay) */ statelow |= (1 << 19); /* Tx bypass (no delay) */ *rgmii = FALSE; } statelow |= (1 << 24); /* enable DLL controls */ W_REG(osh, &sb->sbtmstatelow, statelow); si_setcoreidx(sih, idx); }
static void chipreset(struct bcm4xxx *ch) { bcmenetregs_t *regs; uint32 clk, mdc; ET_TRACE(("et%d: chipreset\n", ch->etc->unit)); regs = ch->regs; if (!si_iscoreup(ch->sih)) { if (!ch->etc->nicmode) si_pci_setup(ch->sih, (1 << si_coreidx(ch->sih))); /* power on reset: reset the enet core */ si_core_reset(ch->sih, 0, 0); goto chipinreset; } /* read counters before resetting the chip */ if (ch->mibgood) chipstatsupd(ch); /* reset the tx dma engine */ if (ch->di) dma_txreset(ch->di); /* set emac into loopback mode to ensure no rx traffic */ W_REG(ch->osh, ®s->rxconfig, ERC_LE); OSL_DELAY(1); /* reset the rx dma engine */ if (ch->di) dma_rxreset(ch->di); /* reset core */ si_core_reset(ch->sih, 0, 0); chipinreset: /* must clear mib registers by hand */ W_REG(ch->osh, ®s->mibcontrol, EMC_RZ); (void) R_REG(ch->osh, ®s->mib.tx_broadcast_pkts); (void) R_REG(ch->osh, ®s->mib.tx_multicast_pkts); (void) R_REG(ch->osh, ®s->mib.tx_len_64); (void) R_REG(ch->osh, ®s->mib.tx_len_65_to_127); (void) R_REG(ch->osh, ®s->mib.tx_len_128_to_255); (void) R_REG(ch->osh, ®s->mib.tx_len_256_to_511); (void) R_REG(ch->osh, ®s->mib.tx_len_512_to_1023); (void) R_REG(ch->osh, ®s->mib.tx_len_1024_to_max); (void) R_REG(ch->osh, ®s->mib.tx_jabber_pkts); (void) R_REG(ch->osh, ®s->mib.tx_oversize_pkts); (void) R_REG(ch->osh, ®s->mib.tx_fragment_pkts); (void) R_REG(ch->osh, ®s->mib.tx_underruns); (void) R_REG(ch->osh, ®s->mib.tx_total_cols); (void) R_REG(ch->osh, ®s->mib.tx_single_cols); (void) R_REG(ch->osh, ®s->mib.tx_multiple_cols); (void) R_REG(ch->osh, ®s->mib.tx_excessive_cols); (void) R_REG(ch->osh, ®s->mib.tx_late_cols); (void) R_REG(ch->osh, ®s->mib.tx_defered); (void) R_REG(ch->osh, ®s->mib.tx_carrier_lost); (void) R_REG(ch->osh, ®s->mib.tx_pause_pkts); (void) R_REG(ch->osh, ®s->mib.rx_broadcast_pkts); (void) R_REG(ch->osh, ®s->mib.rx_multicast_pkts); (void) R_REG(ch->osh, ®s->mib.rx_len_64); (void) R_REG(ch->osh, ®s->mib.rx_len_65_to_127); (void) R_REG(ch->osh, ®s->mib.rx_len_128_to_255); (void) R_REG(ch->osh, ®s->mib.rx_len_256_to_511); (void) R_REG(ch->osh, ®s->mib.rx_len_512_to_1023); (void) R_REG(ch->osh, ®s->mib.rx_len_1024_to_max); (void) R_REG(ch->osh, ®s->mib.rx_jabber_pkts); (void) R_REG(ch->osh, ®s->mib.rx_oversize_pkts); (void) R_REG(ch->osh, ®s->mib.rx_fragment_pkts); (void) R_REG(ch->osh, ®s->mib.rx_missed_pkts); (void) R_REG(ch->osh, ®s->mib.rx_crc_align_errs); (void) R_REG(ch->osh, ®s->mib.rx_undersize); (void) R_REG(ch->osh, ®s->mib.rx_crc_errs); (void) R_REG(ch->osh, ®s->mib.rx_align_errs); (void) R_REG(ch->osh, ®s->mib.rx_symbol_errs); (void) R_REG(ch->osh, ®s->mib.rx_pause_pkts); (void) R_REG(ch->osh, ®s->mib.rx_nonpause_pkts); ch->mibgood = TRUE; /* * We want the phy registers to be accessible even when * the driver is "downed" so initialize MDC preamble, frequency, * and whether internal or external phy here. */ /* default: 100Mhz SI clock and external phy */ W_REG(ch->osh, ®s->mdiocontrol, 0x94); if (ch->etc->deviceid == BCM47XX_ENET_ID) { /* 47xx chips: find out the clock */ if ((clk = si_clock(ch->sih)) != 0) { mdc = 0x80 | ((clk + (MDC_RATIO / 2)) / MDC_RATIO); W_REG(ch->osh, ®s->mdiocontrol, mdc); } else { ET_ERROR(("et%d: chipreset: Could not figure out backplane clock, " "using 100Mhz\n", ch->etc->unit)); } } /* some chips have internal phy, some don't */ if (!(R_REG(ch->osh, ®s->devcontrol) & DC_IP)) { W_REG(ch->osh, ®s->enetcontrol, EC_EP); } else if (R_REG(ch->osh, ®s->devcontrol) & DC_ER) { AND_REG(ch->osh, ®s->devcontrol, ~DC_ER); OSL_DELAY(100); chipphyinit(ch, ch->etc->phyaddr); } /* clear persistent sw intstatus */ ch->intstatus = 0; }
static uint32 config_cmd(si_t *sih, uint bus, uint dev, uint func, uint off) { uint coreidx; sbpciregs_t *pci; uint32 addr = 0, *sbtopci1; osl_t *osh; uint8 port; /* CardBusMode supports only one device */ if (cardbus && dev > 1) return 0; /* Convert logical bus to physical port/bus for following processing */ port = PCIE_GET_PORT_BY_BUS(bus); if (port == 1) { /* 1-based bus number */ bus = bus - PCIE_PORT1_BUS_START + 1; } osh = si_osh(sih); coreidx = si_coreidx(sih); pci = (sbpciregs_t *)si_setcore(sih, PCI_CORE_ID, port); if (pci) { sbtopci1 = &pci->sbtopci1; } else { sbpcieregs_t *pcie; pcie = (sbpcieregs_t *)si_setcore(sih, PCIE_CORE_ID, port); /* Issue config commands only when the data link is up (atleast * one external pcie device is present). */ if (pcie && (dev < 2) && (pcie_readreg(osh, pcie, PCIE_PCIEREGS, PCIE_DLLP_LSREG) & PCIE_DLLP_LSREG_LINKUP)) { sbtopci1 = &pcie->sbtopcie1; } else { si_setcoreidx(sih, coreidx); return 0; } } /* Type 0 transaction */ if (bus == 1) { /* Skip unwired slots */ if (dev < PCI_SLOT_MAX) { /* Slide the PCI window to the appropriate slot */ if (pci) { uint32 win; win = (SBTOPCI_CFG0 | ((1 << (dev + PCI_SLOTAD_MAP)) & SBTOPCI1_MASK)); W_REG(osh, sbtopci1, win); addr = (SI_PCI_CFG(port) | ((1 << (dev + PCI_SLOTAD_MAP)) & ~SBTOPCI1_MASK) | (func << PCICFG_FUN_SHIFT) | (off & ~3)); } else { W_REG(osh, sbtopci1, SBTOPCI_CFG0); addr = (SI_PCI_CFG(port) | (dev << PCIECFG_SLOT_SHIFT) | (func << PCIECFG_FUN_SHIFT) | (off & ~3)); } } } else { /* Type 1 transaction */ addr = SI_PCI_CFG(port); if (pci) { addr |= PCI_CONFIG_ADDR(bus, dev, func, (off & ~3)); /* * Higher bus bits (which lets the address exceed the 64MB space) * should be specified in sbtopci1's UpperAddress. */ W_REG(osh, sbtopci1, SBTOPCI_CFG1 | (addr & SBTOPCI1_MASK)); /* To not exceed the 64MB space (by using UA instead) */ addr &= ~SBTOPCI1_MASK; } else { addr |= PCIE_CONFIG_ADDR((bus - 1), dev, func, (off & ~3)); /* * Higher bus bits (which lets the address exceed the 64MB space) * should be specified in sbtopci1's UpperAddress. */ W_REG(osh, sbtopci1, SBTOPCI_CFG1 | (addr & SBTOPCIE1_MASK)); /* To not exceed the 64MB space (by using UA instead) */ addr &= ~SBTOPCIE1_MASK; } } si_setcoreidx(sih, coreidx); return addr; }
static void * chipattach(etc_info_t *etc, void *osh, void *regsva) { struct bcm4xxx *ch; bcmenetregs_t *regs; char name[16]; char *var; uint boardflags, boardtype; ET_TRACE(("et%d: chipattach: regsva 0x%lx\n", etc->unit, (ulong)regsva)); if ((ch = (struct bcm4xxx *)MALLOC(osh, sizeof(struct bcm4xxx))) == NULL) { ET_ERROR(("et%d: chipattach: out of memory, malloced %d bytes\n", etc->unit, MALLOCED(osh))); return (NULL); } bzero((char *)ch, sizeof(struct bcm4xxx)); ch->etc = etc; ch->et = etc->et; ch->osh = osh; /* store the pointer to the sw mib */ etc->mib = (void *)&ch->mib; /* get si handle */ if ((ch->sih = si_attach(etc->deviceid, ch->osh, regsva, PCI_BUS, NULL, &ch->vars, &ch->vars_size)) == NULL) { ET_ERROR(("et%d: chipattach: si_attach error\n", etc->unit)); goto fail; } /* We used to have an assert here like: * si_coreid(ch->sih) == ENET_CORE_ID * but srom-less systems and simulators don't have a way to * provide a default bar0window so we were relying on nvram * variables. At some point we decided that we could do away * with that since the wireless driver was simply doing a * setcore in attach. So we need to do the same here for * the ethernet. */ if ((regs = (bcmenetregs_t *)si_setcore(ch->sih, ENET_CORE_ID, etc->unit)) == NULL) { ET_ERROR(("et%d: chipattach: Could not setcore to the ENET core\n", etc->unit)); goto fail; } ch->regs = regs; etc->chip = ch->sih->chip; etc->chiprev = ch->sih->chiprev; etc->coreid = si_coreid(ch->sih); etc->corerev = si_corerev(ch->sih); etc->nicmode = !(ch->sih->bustype == SI_BUS); etc->coreunit = si_coreunit(ch->sih); etc->boardflags = getintvar(ch->vars, "boardflags"); etc->hwrxoff = HWRXOFF; boardflags = etc->boardflags; boardtype = ch->sih->boardtype; /* Backplane clock ticks per microsecs: used by gptimer, intrecvlazy */ etc->bp_ticks_usec = si_clock(ch->sih) / 1000000; /* get our local ether addr */ sprintf(name, "et%dmacaddr", etc->coreunit); var = getvar(ch->vars, name); if (var == NULL) { ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc->unit, name)); goto fail; } bcm_ether_atoe(var, &etc->perm_etheraddr); if (ETHER_ISNULLADDR(&etc->perm_etheraddr)) { ET_ERROR(("et%d: chipattach: invalid format: %s=%s\n", etc->unit, name, var)); goto fail; } bcopy((char *)&etc->perm_etheraddr, (char *)&etc->cur_etheraddr, ETHER_ADDR_LEN); /* * Too much can go wrong in scanning MDC/MDIO playing "whos my phy?" . * Instead, explicitly require the environment var "et<coreunit>phyaddr=<val>". */ /* get our phyaddr value */ sprintf(name, "et%dphyaddr", etc->coreunit); var = getvar(ch->vars, name); if (var == NULL) { ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc->unit, name)); goto fail; } etc->phyaddr = bcm_atoi(var) & EPHY_MASK; /* nvram says no phy is present */ if (etc->phyaddr == EPHY_NONE) { ET_ERROR(("et%d: chipattach: phy not present\n", etc->unit)); goto fail; } /* get our mdc/mdio port number */ sprintf(name, "et%dmdcport", etc->coreunit); var = getvar(ch->vars, name); if (var == NULL) { ET_ERROR(("et%d: chipattach: NVRAM_GET(%s) not found\n", etc->unit, name)); goto fail; } etc->mdcport = bcm_atoi(var); /* configure pci core */ si_pci_setup(ch->sih, (1 << si_coreidx(ch->sih))); /* reset the enet core */ chipreset(ch); /* dma attach */ sprintf(name, "et%d", etc->coreunit); if ((ch->di = dma_attach(osh, name, ch->sih, (void *)®s->dmaregs.xmt, (void *)®s->dmaregs.rcv, NTXD, NRXD, RXBUFSZ, -1, NRXBUFPOST, HWRXOFF, &et_msg_level)) == NULL) { ET_ERROR(("et%d: chipattach: dma_attach failed\n", etc->unit)); goto fail; } etc->txavail[TX_Q0] = (uint *)&ch->di->txavail; /* set default sofware intmask */ ch->intmask = DEF_INTMASK; /* * For the 5222 dual phy shared mdio contortion, our phy is * on someone elses mdio pins. This other enet enet * may not yet be attached so we must defer the et_phyfind(). */ /* if local phy: reset it once now */ if (etc->mdcport == etc->coreunit) chipphyreset(ch, etc->phyaddr); #ifdef ETROBO /* * Broadcom Robo ethernet switch. */ if ((boardflags & BFL_ENETROBO) && (etc->phyaddr == EPHY_NOREG)) { /* Attach to the switch */ if (!(etc->robo = bcm_robo_attach(ch->sih, ch, ch->vars, (miird_f)bcm47xx_et_chops.phyrd, (miiwr_f)bcm47xx_et_chops.phywr))) { ET_ERROR(("et%d: chipattach: robo_attach failed\n", etc->unit)); goto fail; } /* Enable the switch and set it to a known good state */ if (bcm_robo_enable_device(etc->robo)) { ET_ERROR(("et%d: chipattach: robo_enable_device failed\n", etc->unit)); goto fail; } /* Configure the switch to do VLAN */ if ((boardflags & BFL_ENETVLAN) && bcm_robo_config_vlan(etc->robo, etc->perm_etheraddr.octet)) { ET_ERROR(("et%d: chipattach: robo_config_vlan failed\n", etc->unit)); goto fail; } /* Enable switching/forwarding */ if (bcm_robo_enable_switch(etc->robo)) { ET_ERROR(("et%d: chipattach: robo_enable_switch failed\n", etc->unit)); goto fail; } } #endif /* ETROBO */ #ifdef ETADM /* * ADMtek ethernet switch. */ if (boardflags & BFL_ENETADM) { /* Attach to the device */ if (!(ch->adm = adm_attach(ch->sih, ch->vars))) { ET_ERROR(("et%d: chipattach: adm_attach failed\n", etc->unit)); goto fail; } /* Enable the external switch and set it to a known good state */ if (adm_enable_device(ch->adm)) { ET_ERROR(("et%d: chipattach: adm_enable_device failed\n", etc->unit)); goto fail; } /* Configure the switch */ if ((boardflags & BFL_ENETVLAN) && adm_config_vlan(ch->adm)) { ET_ERROR(("et%d: chipattach: adm_config_vlan failed\n", etc->unit)); goto fail; } } #endif /* ETADM */ return ((void *)ch); fail: chipdetach(ch); return (NULL); }
static uint32 config_cmd(si_t *sih, uint coreunit, uint bus, uint dev, uint func, uint off) { uint coreidx; sbpciregs_t *pci; uint32 addr = 0, *sbtopci1; osl_t *osh; /* CardBusMode supports only one device */ if (cardbus && dev > 1) return 0; osh = si_osh(sih); coreidx = si_coreidx(sih); pci = (sbpciregs_t *)si_setcore(sih, PCI_CORE_ID, coreunit); if (pci) { sbtopci1 = &pci->sbtopci1; } else { sbpcieregs_t *pcie; pcie = (sbpcieregs_t *)si_setcore(sih, PCIE_CORE_ID, coreunit); /* Issue config commands only when the data link is up (atleast * one external pcie device is present). */ if (pcie && (dev < 2) && (pcie_readreg(sih, pcie, PCIE_PCIEREGS, PCIE_DLLP_LSREG) & PCIE_DLLP_LSREG_LINKUP)) { sbtopci1 = &pcie->sbtopcie1; } else { si_setcoreidx(sih, coreidx); return 0; } } /* Type 0 transaction */ if (!hndpci_is_hostbridge(bus, dev)) { /* Skip unwired slots */ if (dev < PCI_SLOT_MAX) { /* Slide the PCI window to the appropriate slot */ if (pci) { uint32 win; win = (SBTOPCI_CFG0 | ((1 << (dev + PCI_SLOTAD_MAP)) & SBTOPCI1_MASK)); W_REG(osh, sbtopci1, win); addr = (pci_membase_cfg[coreunit] | ((1 << (dev + PCI_SLOTAD_MAP)) & ~SBTOPCI1_MASK) | (func << PCICFG_FUN_SHIFT) | (off & ~3)); } else { W_REG(osh, sbtopci1, SBTOPCI_CFG0); addr = (pci_membase_cfg[coreunit] | (dev << PCIECFG_SLOT_SHIFT) | (func << PCIECFG_FUN_SHIFT) | (off & ~3)); } } } else { /* Type 1 transaction */ W_REG(osh, sbtopci1, SBTOPCI_CFG1); addr = (pci_membase_cfg[coreunit] | (pci ? PCI_CONFIG_ADDR(bus, dev, func, (off & ~3)) : PCIE_CONFIG_ADDR((bus - 1), dev, func, (off & ~3)))); } si_setcoreidx(sih, coreidx); return addr; }
void board_pinmux_init(si_t *sih) { uint origidx; chipcommonbregs_t *chipcb; origidx = si_coreidx(sih); chipcb = si_setcore(sih, NS_CCB_CORE_ID, 0); if (chipcb != NULL) { /* Default select the mux pins for GPIO */ W_REG(osh, &chipcb->cru_gpio_control0, 0x1fffff); } si_setcoreidx(sih, origidx); si_gpioouten(sih, PWR_LED_GPIO, PWR_LED_GPIO, GPIO_DRV_PRIORITY); si_gpioouten(sih, USB_LED_GPIO, USB_LED_GPIO, GPIO_DRV_PRIORITY); #ifdef RTAC68U si_gpioouten(sih, TURBO_LED_GPIO, TURBO_LED_GPIO, GPIO_DRV_PRIORITY); #endif #ifndef RTN18U si_gpioouten(sih, WL5G_LED_GPIO, WL5G_LED_GPIO, GPIO_DRV_PRIORITY); si_gpioouten(sih, USB3_LED_GPIO, USB3_LED_GPIO, GPIO_DRV_PRIORITY); #endif #ifndef RTAC68U si_gpioouten(sih, WAN_LED_GPIO, WAN_LED_GPIO, GPIO_DRV_PRIORITY); si_gpioouten(sih, LAN_LED_GPIO, LAN_LED_GPIO, GPIO_DRV_PRIORITY); #endif #ifndef RTN18U // for RT-AC56U & RT-AC68U si_gpioouten(sih, USB_PWR1_GPIO, USB_PWR1_GPIO, GPIO_DRV_PRIORITY); #ifndef RTAC68U si_gpioouten(sih, USB_PWR2_GPIO, USB_PWR2_GPIO, GPIO_DRV_PRIORITY); #endif #endif #ifdef RTN18U // RT-N18U si_gpioouten(sih, USB_PWR1_GPIO, USB_PWR1_GPIO, GPIO_DRV_PRIORITY); si_gpioouten(sih, WL2G_LED_GPIO, WL2G_LED_GPIO, GPIO_DRV_PRIORITY); si_gpioouten(sih, USB3_LED_GPIO, USB3_LED_GPIO, GPIO_DRV_PRIORITY); #endif si_gpioout(sih, PWR_LED_GPIO, 0, GPIO_DRV_PRIORITY); si_gpioout(sih, USB_LED_GPIO, USB_LED_GPIO, GPIO_DRV_PRIORITY); #ifdef RTAC68U si_gpioout(sih, TURBO_LED_GPIO, 0, GPIO_DRV_PRIORITY); #endif #ifndef RTN18U // for RT-AC56U & RT-AC68U to enable USB power si_gpioout(sih, WL5G_LED_GPIO, WL5G_LED_GPIO, GPIO_DRV_PRIORITY); si_gpioout(sih, USB3_LED_GPIO, USB3_LED_GPIO, GPIO_DRV_PRIORITY); #endif #ifndef RTAC68U si_gpioout(sih, WAN_LED_GPIO, WAN_LED_GPIO, GPIO_DRV_PRIORITY); si_gpioout(sih, LAN_LED_GPIO, LAN_LED_GPIO, GPIO_DRV_PRIORITY); #endif #ifndef RTN18U // for RT-AC56U & RT-AC68U to enable USB power si_gpioout(sih, USB_PWR1_GPIO, USB_PWR1_GPIO, GPIO_DRV_PRIORITY); #ifndef RTAC68U si_gpioout(sih, USB_PWR2_GPIO, USB_PWR2_GPIO, GPIO_DRV_PRIORITY); #endif #endif #ifdef RTN18U // RT-N18U /* enable USB power */ si_gpioout(sih, USB_PWR1_GPIO, USB_PWR1_GPIO, GPIO_DRV_PRIORITY); /* power on LEDs */ si_gpioout(sih, PWR_LED_GPIO, PWR_LED_GPIO, GPIO_DRV_PRIORITY); si_gpioout(sih, WL2G_LED_GPIO, WL2G_LED_GPIO, GPIO_DRV_PRIORITY); si_gpioout(sih, WAN_LED_GPIO, WAN_LED_GPIO, GPIO_DRV_PRIORITY); si_gpioout(sih, LAN_LED_GPIO, LAN_LED_GPIO, GPIO_DRV_PRIORITY); si_gpioout(sih, USB_LED_GPIO, USB_LED_GPIO, GPIO_DRV_PRIORITY); si_gpioout(sih, USB3_LED_GPIO, USB3_LED_GPIO, GPIO_DRV_PRIORITY); #endif }
static int __init init_bcm947xx_map(void) { ulong flags; uint coreidx; chipcregs_t *cc; uint32 fltype; uint window_addr = 0, window_size = 0; size_t size; int ret = 0; #ifdef CONFIG_MTD_PARTITIONS struct mtd_partition *parts; #endif spin_lock_irqsave(&sih_lock, flags); coreidx = si_coreidx(sih); /* Check strapping option if chipcommon exists */ if ((cc = si_setcore(sih, CC_CORE_ID, 0))) { fltype = readl(&cc->capabilities) & CC_CAP_FLASH_MASK; if (fltype == PFLASH) { bcm947xx_map.map_priv_2 = 1; window_addr = 0x1c000000; bcm947xx_map.size = window_size = 32 * 1024 * 1024; if ((readl(&cc->flash_config) & CC_CFG_DS) == 0) bcm947xx_map.bankwidth = 1; } } else { fltype = PFLASH; bcm947xx_map.map_priv_2 = 0; window_addr = WINDOW_ADDR; bcm947xx_map.size = window_size = WINDOW_SIZE; } si_setcoreidx(sih, coreidx); spin_unlock_irqrestore(&sih_lock, flags); if (fltype != PFLASH) { printk(KERN_ERR "pflash: found no supported devices\n"); ret = -ENODEV; goto fail; } bcm947xx_map.virt = ioremap(window_addr, window_size); if (bcm947xx_map.virt == NULL) { printk(KERN_ERR "pflash: ioremap failed\n"); ret = -EIO; goto fail; } if ((bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map)) == NULL) { printk(KERN_ERR "pflash: cfi_probe failed\n"); ret = -ENXIO; goto fail; } bcm947xx_mtd->owner = THIS_MODULE; /* Allow size override for testing */ size = flash ? : bcm947xx_mtd->size; printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, window_addr); #ifdef CONFIG_MTD_PARTITIONS parts = init_mtd_partitions(bcm947xx_mtd, size); ret = add_mtd_partitions(bcm947xx_mtd, parts, 4); if (ret) { printk(KERN_ERR "pflash: add_mtd_partitions failed\n"); goto fail; } #endif return 0; fail: if (bcm947xx_mtd) map_destroy(bcm947xx_mtd); if (bcm947xx_map.map_priv_1) iounmap((void *) bcm947xx_map.map_priv_1); bcm947xx_map.map_priv_1 = 0; return ret; }