LOCAL int flashWrite(int sectorNum, char *buff, unsigned int offset, unsigned int count) { unsigned char *curBuffPtr, *sectorOffsetPtr; unsigned int len = count; int bytes; curBuffPtr = (unsigned char *)buff; sectorOffsetPtr = (unsigned char *)((sectorNum * FLASH_SECTOR_SIZE) + offset); /* Write holding block */ while (len) { if ((bytes = sflash_write(sih, cc, (unsigned int)sectorOffsetPtr, len, curBuffPtr)) < 0) { printf("flashWrite(): Failed: Sector %d, address 0x%x\n", sectorNum, (int)sectorOffsetPtr); return (ERROR); } /* Polling until command completion. Returns zero when complete. */ while (sflash_poll(sih, cc, (unsigned int)sectorOffsetPtr)); sectorOffsetPtr += bytes; len -= bytes; curBuffPtr += bytes; } return (OK); }
static int sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout) { int now = jiffies; int ret = 0; for (;;) { if (!sflash_poll(sflash->sbh, sflash->cc, offset)) { ret = 0; break; } if (time_after(jiffies, now + timeout)) { printk(KERN_ERR "sflash: timeout\n"); ret = -ETIMEDOUT; break; } if (current->need_resched) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(timeout / 10); } else udelay(1); } return ret; }
LOCAL int flashEraseDevices(volatile unsigned char *sectorBasePtr) { int ret = 0; if (flashVerbose) { printf("Erasing Sector @ 0x%08x\n",(unsigned int)sectorBasePtr); } /* Erase block */ if ((ret = sflash_erase(sih, cc, (unsigned int)sectorBasePtr)) < 0) { return (ERROR); } /* Polling until command completion. Returns zero when complete. */ while (sflash_poll(sih, cc, (unsigned int)sectorBasePtr)); if (flashVerbose > 1) printf("flashEraseDevices(): all devices erased\n"); return (OK); }
/* * writes the appropriate range of flash, a NULL buf simply erases * the region of flash */ int sflash_commit(si_t *sih, chipcregs_t *cc, uint offset, uint len, const uchar *buf) { struct sflash *sfl; uchar *block = NULL, *cur_ptr, *blk_ptr; uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder; uint blk_offset, blk_len, copied; int bytes, ret = 0; osl_t *osh; ASSERT(sih); osh = si_osh(sih); /* Check address range */ if (len <= 0) return 0; sfl = &sflash; if ((offset + len) > sfl->size) return -1; blocksize = sfl->blocksize; mask = blocksize - 1; /* Allocate a block of mem */ if (!(block = MALLOC(osh, blocksize))) return -1; while (len) { /* Align offset */ cur_offset = offset & ~mask; cur_length = blocksize; cur_ptr = block; remainder = blocksize - (offset & mask); if (len < remainder) cur_retlen = len; else cur_retlen = remainder; /* buf == NULL means erase only */ if (buf) { /* Copy existing data into holding block if necessary */ if ((offset & mask) || (len < blocksize)) { blk_offset = cur_offset; blk_len = cur_length; blk_ptr = cur_ptr; /* Copy entire block */ while (blk_len) { copied = sflash_read(sih, cc, blk_offset, blk_len, blk_ptr); blk_offset += copied; blk_len -= copied; blk_ptr += copied; } } /* Copy input data into holding block */ memcpy(cur_ptr + (offset & mask), buf, cur_retlen); } /* Erase block */ if ((ret = sflash_erase(sih, cc, (uint) cur_offset)) < 0) goto done; while (sflash_poll(sih, cc, (uint) cur_offset)); /* buf == NULL means erase only */ if (!buf) { offset += cur_retlen; len -= cur_retlen; continue; } /* Write holding block */ while (cur_length > 0) { if ((bytes = sflash_write(sih, cc, (uint) cur_offset, (uint) cur_length, (uchar *) cur_ptr)) < 0) { ret = bytes; goto done; } while (sflash_poll(sih, cc, (uint) cur_offset)); cur_offset += bytes; cur_length -= bytes; cur_ptr += bytes; } offset += cur_retlen; len -= cur_retlen; buf += cur_retlen; } ret = len; done: if (block) MFREE(osh, block, blocksize); return ret; }
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 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; }