void dma_txreset(dma_info_t *di) { uint32 status; DMA_TRACE(("%s: dma_txreset\n", di->name)); /* address PR8249/PR7577 issue */ /* suspend tx DMA first */ W_REG(&di->regs->xmtcontrol, XC_SE); SPINWAIT((status = (R_REG(&di->regs->xmtstatus) & XS_XS_MASK)) != XS_XS_DISABLED && status != XS_XS_IDLE && status != XS_XS_STOPPED, 10000); /* PR2414 WAR: DMA engines are not disabled until transfer finishes */ W_REG(&di->regs->xmtcontrol, 0); SPINWAIT((status = (R_REG(&di->regs->xmtstatus) & XS_XS_MASK)) != XS_XS_DISABLED, 10000); if (status != XS_XS_DISABLED) { DMA_ERROR(("%s: dma_txreset: dma cannot be stopped\n", di->name)); } /* wait for the last transaction to complete */ OSL_DELAY(300); }
static int gmac_disable_dma(struct eth_dma *dma, int dir) { int status; debug("%s enter\n", __func__); if (dir == MAC_DMA_TX) { /* address PR8249/PR7577 issue */ /* suspend tx DMA first */ writel(D64_XC_SE, GMAC0_DMA_TX_CTRL_ADDR); SPINWAIT(((status = (readl(GMAC0_DMA_TX_STATUS0_ADDR) & D64_XS0_XS_MASK)) != D64_XS0_XS_DISABLED) && (status != D64_XS0_XS_IDLE) && (status != D64_XS0_XS_STOPPED), 10000); /* * PR2414 WAR: DMA engines are not disabled until * transfer finishes */ writel(0, GMAC0_DMA_TX_CTRL_ADDR); SPINWAIT(((status = (readl(GMAC0_DMA_TX_STATUS0_ADDR) & D64_XS0_XS_MASK)) != D64_XS0_XS_DISABLED), 10000); /* wait for the last transaction to complete */ udelay(2); status = (status == D64_XS0_XS_DISABLED); } else { /* * PR2414 WAR: DMA engines are not disabled until * transfer finishes */ writel(0, GMAC0_DMA_RX_CTRL_ADDR); SPINWAIT(((status = (readl(GMAC0_DMA_RX_STATUS0_ADDR) & D64_RS0_RS_MASK)) != D64_RS0_RS_DISABLED), 10000); status = (status == D64_RS0_RS_DISABLED); } return status; }
/* 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 dma_rxreset(dma_info_t *di) { uint32 status; DMA_TRACE(("%s: dma_rxreset\n", di->name)); /* PR2414 WAR: DMA engines are not disabled until transfer finishes */ W_REG(&di->regs->rcvcontrol, 0); SPINWAIT((status = (R_REG(&di->regs->rcvstatus) & RS_RS_MASK)) != RS_RS_DISABLED, 10000); if (status != RS_RS_DISABLED) { DMA_ERROR(("%s: dma_rxreset: dma cannot be stopped\n", di->name)); } }
static int brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev) { int err = 0; u8 clkval, clkset; /* Try forcing SDIO core to do ALPAvail request only */ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); if (err) { brcmf_dbg(ERROR, "error writing for HT off\n"); return err; } /* If register supported, wait for ALPAvail and then force ALP */ /* This may take up to 15 milliseconds */ clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL); if ((clkval & ~SBSDIO_AVBITS) != clkset) { brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n", clkset, clkval); return -EACCES; } SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), PMU_MAX_TRANSITION_DLY); if (!SBSDIO_ALPAV(clkval)) { brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n", clkval); return -EBUSY; } clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); udelay(65); /* Also, disable the extra SDIO pull-ups */ brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); return 0; }
/* * precondition: perimeter lock has been acquired */ void brcms_down(struct brcms_info *wl) { uint callbacks, ret_val = 0; /* call common down function */ ret_val = brcms_c_down(wl->wlc); callbacks = atomic_read(&wl->callbacks) - ret_val; /* wait for down callbacks to complete */ spin_unlock_bh(&wl->lock); /* For HIGH_only driver, it's important to actually schedule other work, * not just spin wait since everything runs at schedule level */ SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000); spin_lock_bh(&wl->lock); }
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; }
static uint16 chipphyrd(struct bcm4xxx *ch, uint phyaddr, uint reg) { bcmenetregs_t *regs; ASSERT(phyaddr < MAXEPHY); /* * BCM5222 dualphy shared mdio contortion. * remote phy: another emac controls our phy. */ if (ch->etc->mdcport != ch->etc->coreunit) { if (ch->etphy == NULL) { ch->etphy = et_phyfind(ch->et, ch->etc->mdcport); /* first time reset */ if (ch->etphy) chipphyreset(ch, ch->etc->phyaddr); } if (ch->etphy) return (et_phyrd(ch->etphy, phyaddr, reg)); else return (0xffff); } /* local phy: our emac controls our phy */ regs = ch->regs; /* clear mii_int */ W_REG(ch->osh, ®s->emacintstatus, EI_MII); /* issue the read */ W_REG(ch->osh, ®s->mdiodata, (MD_SB_START | MD_OP_READ | (phyaddr << MD_PMD_SHIFT) | (reg << MD_RA_SHIFT) | MD_TA_VALID)); /* wait for it to complete */ SPINWAIT(((R_REG(ch->osh, ®s->emacintstatus) & EI_MII) == 0), 100); if ((R_REG(ch->osh, ®s->emacintstatus) & EI_MII) == 0) { ET_ERROR(("et%d: chipphyrd: did not complete\n", ch->etc->unit)); } return (R_REG(ch->osh, ®s->mdiodata) & MD_DATA_MASK); }
static bool sdspi_switch_clock(sdioh_info_t *sd, bool ext_clk) { spih_info_t *si = (spih_info_t *)sd->controller; osl_t *osh = si->osh; spih_regs_t *regs = si->regs; SPIPCI_WREG(osh, ®s->spih_pll_ctrl, ext_clk ? SPIH_EXT_CLK : 0); SPINWAIT(((SPIPCI_RREG(osh, ®s->spih_pll_status) & SPIH_PLL_LOCKED) != SPIH_PLL_LOCKED), 1000); if ((SPIPCI_RREG(osh, ®s->spih_pll_status) & SPIH_PLL_LOCKED) != SPIH_PLL_LOCKED) { sd_err(("%s: timeout waiting for PLL to lock\n", __FUNCTION__)); return (FALSE); } return (TRUE); }
static void brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev, struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits, u32 in_resetbits) { u8 idx; u32 regdata; u32 wrapbase; idx = brcmf_sdio_chip_getinfidx(ci, coreid); if (idx == BRCMF_MAX_CORENUM) return; wrapbase = ci->c_inf[idx].wrapbase; /* if core is already in reset, just return */ regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL); if ((regdata & BCMA_RESET_CTL_RESET) != 0) return; /* configure reset */ brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL); regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL); /* put in reset */ brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_RESET_CTL, BCMA_RESET_CTL_RESET, NULL); usleep_range(10, 20); /* wait till reset is 1 */ SPINWAIT(brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL) != BCMA_RESET_CTL_RESET, 300); /* post reset configure */ brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL); regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL); }
static void chipwrcam(struct bcm4xxx *ch, struct ether_addr *ea, uint camindex) { uint32 w; ASSERT((R_REG(ch->osh, &ch->regs->camcontrol) & (CC_CB | CC_CE)) == 0); w = (ea->octet[2] << 24) | (ea->octet[3] << 16) | (ea->octet[4] << 8) | ea->octet[5]; W_REG(ch->osh, &ch->regs->camdatalo, w); w = CD_V | (ea->octet[0] << 8) | ea->octet[1]; W_REG(ch->osh, &ch->regs->camdatahi, w); W_REG(ch->osh, &ch->regs->camcontrol, ((camindex << CC_INDEX_SHIFT) | CC_WR)); /* spin until done */ SPINWAIT((R_REG(ch->osh, &ch->regs->camcontrol) & CC_CB), 1000); /* * This assertion is usually caused by the phy not providing a clock * to the bottom portion of the mac.. */ ASSERT((R_REG(ch->osh, &ch->regs->camcontrol) & CC_CB) == 0); }
/* Run bist on current core. Caller needs to take care of core-specific bist hazards */ int si_corebist(si_t *sih) { uint32 cflags; int result = 0; /* Read core control flags */ cflags = si_core_cflags(sih, 0, 0); /* Set bist & fgc */ si_core_cflags(sih, 0, (SICF_BIST_EN | SICF_FGC)); /* Wait for bist done */ SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR) result = BCME_ERROR; /* Reset core control flags */ si_core_cflags(sih, 0xffff, cflags); return result; }
static void chipphywr(struct bcm4xxx *ch, uint phyaddr, uint reg, uint16 v) { bcmenetregs_t *regs; ASSERT(phyaddr < MAXEPHY); /* * BCM5222 dualphy shared mdio contortion. * remote phy: another emac controls our phy. */ if (ch->etc->mdcport != ch->etc->coreunit) { if (ch->etphy == NULL) ch->etphy = et_phyfind(ch->et, ch->etc->mdcport); if (ch->etphy) et_phywr(ch->etphy, phyaddr, reg, v); return; } /* local phy: our emac controls our phy */ regs = ch->regs; /* clear mii_int */ W_REG(ch->osh, ®s->emacintstatus, EI_MII); ASSERT((R_REG(ch->osh, ®s->emacintstatus) & EI_MII) == 0); /* issue the write */ W_REG(ch->osh, ®s->mdiodata, (MD_SB_START | MD_OP_WRITE | (phyaddr << MD_PMD_SHIFT) | (reg << MD_RA_SHIFT) | MD_TA_VALID | v)); /* wait for it to complete */ SPINWAIT(((R_REG(ch->osh, ®s->emacintstatus) & EI_MII) == 0), 100); if ((R_REG(ch->osh, ®s->emacintstatus) & EI_MII) == 0) { ET_ERROR(("et%d: chipphywr: did not complete\n", ch->etc->unit)); } }
int sflash_write(si_t *sih, chipcregs_t *cc, uint offset, uint length, const uchar *buffer) { struct sflash *sfl; uint off = offset, len = length; const uint8 *buf = buffer; uint8 data; int ret = 0, ntry = 0; bool is4712b0; uint32 page, byte, mask; osl_t *osh; ASSERT(sih); osh = si_osh(sih); if (!len) return 0; sfl = &sflash; if ((off + len) > sfl->size) return -22; switch (sfl->type) { case SFLASH_ST: is4712b0 = (CHIPID(sih->chip) == BCM4712_CHIP_ID) && (CHIPREV(sih->chiprev) == 3); /* Enable writes */ retry: sflash_cmd(osh, cc, SFLASH_ST_WREN); off = offset; len = length; buf = buffer; ntry++; if (is4712b0) { mask = 1 << 14; W_REG(osh, &cc->flashaddress, off); data = GET_BYTE(buf); buf++; W_REG(osh, &cc->flashdata, data); /* Set chip select */ OR_REG(osh, &cc->gpioout, mask); /* Issue a page program with the first byte */ sflash_cmd(osh, cc, SFLASH_ST_PP); ret = 1; off++; len--; while (len > 0) { if ((off & 255) == 0) { /* Page boundary, drop cs and return */ AND_REG(osh, &cc->gpioout, ~mask); OSL_DELAY(1); if (!sflash_poll(sih, cc, off)) { /* Flash rejected command */ if (ntry <= ST_RETRIES) goto retry; else return -11; } return ret; } else { /* Write single byte */ data = GET_BYTE(buf); buf++; sflash_cmd(osh, cc, data); } ret++; off++; len--; } /* All done, drop cs */ AND_REG(osh, &cc->gpioout, ~mask); OSL_DELAY(1); if (!sflash_poll(sih, cc, off)) { /* Flash rejected command */ if (ntry <= ST_RETRIES) goto retry; else return -12; } } else if (sih->ccrev >= 20) { W_REG(osh, &cc->flashaddress, off); data = GET_BYTE(buf); buf++; W_REG(osh, &cc->flashdata, data); /* Issue a page program with CSA bit set */ sflash_cmd(osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP); ret = 1; off++; len--; while (len > 0) { if ((off & 255) == 0) { /* Page boundary, poll droping cs and return */ W_REG(NULL, &cc->flashcontrol, 0); OSL_DELAY(1); if (sflash_poll(sih, cc, off) == 0) { /* Flash rejected command */ SFL_MSG(("sflash: pp rejected, ntry: %d," " off: %d/%d, len: %d/%d, ret:" "%d\n", ntry, off, offset, len, length, ret)); if (ntry <= ST_RETRIES) goto retry; else return -11; } return ret; } else { /* Write single byte */ data = GET_BYTE(buf); buf++; sflash_cmd(osh, cc, SFLASH_ST_CSA | data); } ret++; off++; len--; } /* All done, drop cs & poll */ W_REG(NULL, &cc->flashcontrol, 0); OSL_DELAY(1); if (sflash_poll(sih, cc, off) == 0) { /* Flash rejected command */ SFL_MSG(("sflash: pp rejected, ntry: %d, off: %d/%d," " len: %d/%d, ret: %d\n", ntry, off, offset, len, length, ret)); if (ntry <= ST_RETRIES) goto retry; else return -12; } } else { ret = 1; W_REG(osh, &cc->flashaddress, off); data = GET_BYTE(buf); buf++; W_REG(osh, &cc->flashdata, data); /* Page program */ sflash_cmd(osh, cc, SFLASH_ST_PP); } break; case SFLASH_AT: mask = sfl->blocksize - 1; page = (off & ~mask) << 1; byte = off & mask; /* Read main memory page into buffer 1 */ if (byte || (len < sfl->blocksize)) { W_REG(osh, &cc->flashaddress, page); sflash_cmd(osh, cc, SFLASH_AT_BUF1_LOAD); /* 250 us for AT45DB321B */ SPINWAIT(sflash_poll(sih, cc, off), 1000); ASSERT(!sflash_poll(sih, cc, off)); } /* Write into buffer 1 */ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) { W_REG(osh, &cc->flashaddress, byte++); W_REG(osh, &cc->flashdata, *buf++); sflash_cmd(osh, cc, SFLASH_AT_BUF1_WRITE); } /* Write buffer 1 into main memory page */ W_REG(osh, &cc->flashaddress, page); sflash_cmd(osh, cc, SFLASH_AT_BUF1_PROGRAM); break; } return ret; }
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; }
int sflash_write(si_t *sih, chipcregs_t *cc, uint offset, uint length, const uchar *buffer) { struct sflash *sfl; uint off = offset, len = length; #if SFLASH_ST_PAGE_MODE_WRITE int tryn = 0; #else /* !SFLASH_ST_PAGE_MODE_WRITE */ uint quot = 0, remain = 0, wlen = 0; uint32 reg_val = 0; #endif /* SFLASH_ST_PAGE_MODE_WRITE */ const uchar *buf = buffer; int ret = 0; uint32 page, byte, mask; osl_t *osh; ASSERT(sih); osh = si_osh(sih); if (!len) return 0; sfl = &sflash; if ((off + len) > sfl->size) return -22; switch (sfl->type) { case SFLASH_ST: #if SFLASH_ST_PAGE_MODE_WRITE /* Enable writes */ retry: sflash_cmd(osh, cc, SFLASH_ST_WREN); off = offset; len = length; buf = buffer; tryn++; if (sih->ccrev >= 20) { W_REG(osh, &cc->sflashaddress, off); W_REG(osh, &cc->sflashdata, *buf++); /* Issue a page program with CSA bit set */ sflash_cmd(osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP); ret = 1; off++; len--; while (len > 0) { if ((off & 255) == 0) { /* Page boundary, poll droping cs and return */ W_REG(osh, &cc->sflashcontrol, 0); OSL_DELAY(1); if (sflash_poll(sih, cc, offset) != 0) { /* Flash rejected command */ SFL_MSG(("sflash: pp rejected, tryn: %d," " off: %d/%d, len: %d/%d, ret:" "%d\n", tryn, off, offset, len, length, ret)); if (tryn <= ST_RETRIES) goto retry; else return -11; } return ret; } else { /* Write single byte */ sflash_cmd(osh, cc, SFLASH_ST_CSA | *buf++); } ret++; off++; len--; } /* All done, drop cs & poll */ W_REG(osh, &cc->sflashcontrol, 0); OSL_DELAY(1); if (sflash_poll(sih, cc, offset) != 0) { /* Flash rejected command */ SFL_MSG(("sflash: pp rejected, tryn: %d, off: %d/%d," " len: %d/%d, ret: %d\n", tryn, off, offset, len, length, ret)); if (tryn <= ST_RETRIES) goto retry; else return -12; } } else { ret = 1; W_REG(osh, &cc->sflashaddress, off); W_REG(osh, &cc->sflashdata, *buf); /* Page program */ sflash_cmd(osh, cc, SFLASH_ST_PP); } #else /* !SFLASH_ST_PAGE_MODE_WRITE */ off = offset; len = length; buf = buffer; if (sih->ccrev >= 20) { ret = 0; while (len > 0) { /* Enable writes */ sflash_cmd(osh, cc, SFLASH_ST_WREN); /* Drop cs before starting a page program */ W_REG(osh, &cc->sflashcontrol, 0); W_REG(osh, &cc->sflashaddress, off); quot = (len / 4); remain = (len % 4); if (quot != 0) { /* len >= 4 bytes */ wlen = 4; reg_val = (*buf << 24); buf++; reg_val |= (*buf << 16); buf++; reg_val |= (*buf << 8); buf++; reg_val |= (*buf); buf++; W_REG(osh, &cc->sflashdata, reg_val); /* Issue a page program with CSA bit set : opcode+3 addres & 4 data bytes */ sflash_cmd(osh, cc, (SFLASH_ST_CSA | SFLASH_ST_PP3A4D)); } else { /* len < 4 bytes */ wlen = 1; W_REG(osh, &cc->sflashdata, *buf++); /* Issue a page program with CSA bit set : opcode+3 addres & 1 data bytes */ sflash_cmd(osh, cc, (SFLASH_ST_CSA | SFLASH_ST_PP)); } ret += wlen; off += wlen; len -= wlen; /* A page program done(1 or 4 data bytes), drop cs & poll */ W_REG(osh, &cc->sflashcontrol, 0); while (sflash_poll(sih, cc, offset) != 0) { /* Poll until command completion */ } /* Page boundary and return for 256 bytes write */ if ((off & 255) == 0) { return ret; } } } else { /* Enable writes */ sflash_cmd(osh, cc, SFLASH_ST_WREN); ret = 1; W_REG(osh, &cc->sflashaddress, off); W_REG(osh, &cc->sflashdata, *buf); /* Page program */ sflash_cmd(osh, cc, SFLASH_ST_PP); } #endif /* SFLASH_ST_PAGE_MODE_WRITE */ break; case SFLASH_AT: mask = sfl->blocksize - 1; page = (off & ~mask) << 1; byte = off & mask; /* Read main memory page into buffer 1 */ if (byte || (len < sfl->blocksize)) { W_REG(osh, &cc->sflashaddress, page); sflash_cmd(osh, cc, SFLASH_AT_BUF1_LOAD); /* 250 us for AT45DB321B */ SPINWAIT(sflash_poll(sih, cc, offset), 1000); ASSERT(!sflash_poll(sih, cc, offset)); } /* Write into buffer 1 */ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) { W_REG(osh, &cc->sflashaddress, byte++); W_REG(osh, &cc->sflashdata, *buf++); sflash_cmd(osh, cc, SFLASH_AT_BUF1_WRITE); } /* Write buffer 1 into main memory page */ W_REG(osh, &cc->sflashaddress, page); sflash_cmd(osh, cc, SFLASH_AT_BUF1_PROGRAM); break; } return ret; }
/* Write len bytes starting at offset into buf. Returns number of bytes * written. Caller should poll for completion. */ int sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf) { struct sflash *sfl; int ret = 0; bool is4712b0; uint32 page, byte, mask; if (!len) return 0; if ((offset + len) > sflash.size) return -22; sfl = &sflash; switch (sfl->type) { case SFLASH_ST: mask = R_REG(NULL, &cc->chipid); is4712b0 = (((mask & CID_ID_MASK) == BCM4712_CHIP_ID) && ((mask & CID_REV_MASK) == (3 << CID_REV_SHIFT))); /* Enable writes */ sflash_cmd(cc, SFLASH_ST_WREN); if (is4712b0) { mask = 1 << 14; W_REG(NULL, &cc->flashaddress, offset); W_REG(NULL, &cc->flashdata, *buf++); /* Set chip select */ OR_REG(NULL, &cc->gpioout, mask); /* Issue a page program with the first byte */ sflash_cmd(cc, SFLASH_ST_PP); ret = 1; offset++; len--; while (len > 0) { if ((offset & 255) == 0) { /* Page boundary, drop cs and return */ AND_REG(NULL, &cc->gpioout, ~mask); if (!sflash_poll(cc, offset)) { /* Flash rejected command */ return -11; } return ret; } else { /* Write single byte */ sflash_cmd(cc, *buf++); } ret++; offset++; len--; } /* All done, drop cs if needed */ if ((offset & 255) != 1) { /* Drop cs */ AND_REG(NULL, &cc->gpioout, ~mask); if (!sflash_poll(cc, offset)) { /* Flash rejected command */ return -12; } } } else { ret = 1; W_REG(NULL, &cc->flashaddress, offset); W_REG(NULL, &cc->flashdata, *buf); /* Page program */ sflash_cmd(cc, SFLASH_ST_PP); } break; case SFLASH_AT: mask = sfl->blocksize - 1; page = (offset & ~mask) << 1; byte = offset & mask; /* Read main memory page into buffer 1 */ if (byte || (len < sfl->blocksize)) { W_REG(NULL, &cc->flashaddress, page); sflash_cmd(cc, SFLASH_AT_BUF1_LOAD); /* 250 us for AT45DB321B */ SPINWAIT(sflash_poll(cc, offset), 1000); ASSERT(!sflash_poll(cc, offset)); } /* Write into buffer 1 */ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) { W_REG(NULL, &cc->flashaddress, byte++); W_REG(NULL, &cc->flashdata, *buf++); sflash_cmd(cc, SFLASH_AT_BUF1_WRITE); } /* Write buffer 1 into main memory page */ W_REG(NULL, &cc->flashaddress, page); sflash_cmd(cc, SFLASH_AT_BUF1_PROGRAM); break; } return ret; }
static void brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci, u16 coreid) { u32 regdata, base; u8 idx; idx = brcmf_sdio_chip_getinfidx(ci, coreid); base = ci->c_inf[idx].base; regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL); if (regdata & SSB_TMSLOW_RESET) return; regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL); if ((regdata & SSB_TMSLOW_CLOCK) != 0) { /* * set target reject and spin until busy is clear * (preserve core-specific bits) */ regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL); brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow), regdata | SSB_TMSLOW_REJECT, NULL); regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL); udelay(1); SPINWAIT((brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatehigh), NULL) & SSB_TMSHIGH_BUSY), 100000); regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatehigh), NULL); if (regdata & SSB_TMSHIGH_BUSY) brcmf_dbg(ERROR, "core state still busy\n"); regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow), NULL); if (regdata & SSB_IDLOW_INITIATOR) { regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbimstate), NULL); regdata |= SSB_IMSTATE_REJECT; brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate), regdata, NULL); regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbimstate), NULL); udelay(1); SPINWAIT((brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbimstate), NULL) & SSB_IMSTATE_BUSY), 100000); } /* set reset and reject while enabling the clocks */ regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET; brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow), regdata, NULL); regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL); udelay(10); /* clear the initiator reject bit */ regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow), NULL); if (regdata & SSB_IDLOW_INITIATOR) { regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbimstate), NULL); regdata &= ~SSB_IMSTATE_REJECT; brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate), regdata, NULL); } } /* leave reset and reject asserted */ brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow), (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL); udelay(1); }