/* * Erase an address range on the nor chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. */ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) { struct spi_nor *nor = mtd_to_spi_nor(mtd); u32 addr, len; uint32_t rem; int ret; dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr, (long long)instr->len); div_u64_rem(instr->len, mtd->erasesize, &rem); if (rem) return -EINVAL; addr = instr->addr; len = instr->len; ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_ERASE); if (ret) return ret; /* whole-chip erase? */ if (len == mtd->size) { if (erase_chip(nor)) { ret = -EIO; goto erase_err; } /* REVISIT in some cases we could speed up erasing large regions * by using SPINOR_OP_SE instead of SPINOR_OP_BE_4K. We may have set up * to use "small sector erase", but that's not always optimal. */ /* "sector"-at-a-time erase */ } else { while (len) { if (nor->erase(nor, addr)) { ret = -EIO; goto erase_err; } addr += mtd->erasesize; len -= mtd->erasesize; } } spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return ret; erase_err: spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); instr->state = MTD_ERASE_FAILED; return ret; }
static int sflash_erase(struct mtd_info *mtd, struct erase_info *instr) { struct map_info *map = mtd->priv; MV_SFLASH_INFO *sflash = map->fldrv_priv; /* MV_SFLASH_INFO *sflash = mtd->priv;*/ MV_U32 fsec, lsec; int i; MV_ULONG flags = 0, sflash_in_irq = 0; DB(printk("\nINFO: %s - Addr %08x, len %d",__FUNCTION__, instr->addr, instr->len)); if(instr->addr & (mtd->erasesize - 1)) { printk(KERN_NOTICE "\nError: %s - Erase address not sector alligned",__FUNCTION__); return -EINVAL; } if(instr->len & (mtd->erasesize - 1)) { printk(KERN_NOTICE "\nError: %s - Erase length is not sector alligned",__FUNCTION__); return -EINVAL; } if(instr->len + instr->addr > mtd->size) { printk(KERN_NOTICE "\nError: %s - Erase exceeded flash size",__FUNCTION__); return -EINVAL; } #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) fsec = (instr->addr / mtd->erasesize); lsec = (fsec +(instr->len / mtd->erasesize)); #else fsec = instr->addr; do_div(fsec, mtd->erasesize); lsec = instr->len; do_div(lsec, mtd->erasesize); lsec = (fsec + lsec); #endif DB(printk("\nINFO: %s - from sector %u to %u",__FUNCTION__, fsec, lsec-1)); sflash_disable_irqs(flags, sflash_in_irq); for (i=fsec; i<lsec; i++) { if (mvSFlashSectorErase(sflash, i) != MV_OK) { sflash_enable_irqs(flags, sflash_in_irq); printk(KERN_NOTICE "\nError: %s - mvSFlashSectorErase on sector %d",__FUNCTION__, i); return -1; } } sflash_enable_irqs(flags, sflash_in_irq); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) { if (check_offs_len(mtd, instr->addr, instr->len)) return -EINVAL; memset((char *)mtd->priv + instr->addr, 0xff, instr->len); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
/* * Erase an address range on the flash chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. */ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) { struct m25p *flash = mtd_to_m25p(mtd); u32 addr,len; DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", flash->spi->dev.bus_id, __func__, "at", (u32)instr->addr, instr->len); /* sanity checks */ if (instr->addr + instr->len > flash->mtd.size) return -EINVAL; if ((instr->addr % mtd->erasesize) != 0 || (instr->len % mtd->erasesize) != 0) { return -EINVAL; } addr = instr->addr; len = instr->len; mutex_lock(&flash->lock); /* whole-chip erase? */ if (len == flash->mtd.size && erase_chip(flash)) { instr->state = MTD_ERASE_FAILED; mutex_unlock(&flash->lock); return -EIO; /* REVISIT in some cases we could speed up erasing large regions * by using OPCODE_SE instead of OPCODE_BE_4K. We may have set up * to use "small sector erase", but that's not always optimal. */ /* "sector"-at-a-time erase */ } else { while (len) { if (erase_sector(flash, addr)) { instr->state = MTD_ERASE_FAILED; mutex_unlock(&flash->lock); return -EIO; } addr += mtd->erasesize; len -= mtd->erasesize; } } mutex_unlock(&flash->lock); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
/******************************************************************* * mtd stuff ******************************************************************/ static int bcmmtd_erase(struct mtd_info *mtd, struct erase_info *instr) { uint32_t rem; u32 addr,len; int partition, offset; int ret; BlockCache *bc; /* sanity czech */ if (instr->addr + instr->len > mtd->size) return -EINVAL; div_u64_rem(instr->len, mtd->erasesize, &rem); if (rem) return -EINVAL; addr = instr->addr; len = instr->len; #if DEBUG_VFLASH_MTD printk("-->%s addr = %08x len = %08x\n", __func__, (unsigned int)addr, (unsigned int)len); #endif /* whole-chip erase is not supported */ if (len == mtd->size) { instr->state = MTD_ERASE_FAILED; return -EIO; } else { while (len) { bc = find_block_cache(addr); if (bc) { invalidate_block_cache(bc); release_block_cache(bc); } partition = get_flash_partition(addr); offset = addr - flash_partition_ptr[partition].offset; ret = vflash_erase_block(partition, offset, mtd->erasesize); if (ret < 0) return ret; addr += mtd->erasesize; len -= mtd->erasesize; } } instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
/* erase a specified part of the device */ static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr) { struct blkmtd_dev *dev = mtd->priv; struct mtd_erase_region_info *einfo = mtd->eraseregions; int numregions = mtd->numeraseregions; size_t from; u_long len; int err = -EIO; size_t retlen; instr->state = MTD_ERASING; from = instr->addr; len = instr->len; /* check erase region has valid start and length */ DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%zx len = 0x%lx\n", mtd->name+9, from, len); while(numregions) { DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n", einfo->offset, einfo->erasesize, einfo->numblocks); if(from >= einfo->offset && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) { if(len == einfo->erasesize && ( (from - einfo->offset) % einfo->erasesize == 0)) break; } numregions--; einfo++; } if(!numregions) { /* Not a valid erase block */ err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from); instr->state = MTD_ERASE_FAILED; err = -EIO; } if(instr->state != MTD_ERASE_FAILED) { /* do the erase */ DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len); err = write_pages(dev, NULL, from, len, &retlen); if(err || retlen != len) { err("erase failed err = %d", err); instr->state = MTD_ERASE_FAILED; } else { instr->state = MTD_ERASE_DONE; } } DEBUG(3, "blkmtd: erase: checking callback\n"); mtd_erase_callback(instr); DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err); return err; }
static int slram_erase(struct mtd_info *mtd, struct erase_info *instr) { slram_priv_t *priv = mtd->priv; memset(priv->start + instr->addr, 0xff, instr->len); /* This'll catch a few races. Free the thing before returning :) * I don't feel at all ashamed. This kind of thing is possible anyway * with flash, but unlikely. */ instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return(0); }
static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr) { struct map_info *map = mtd->priv; map_word allff; unsigned long i; allff = map_word_ff(map); for (i=0; i<instr->len; i += map_bankwidth(map)) map_write(map, allff, instr->addr + i); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
/* * Erase is an asynchronous operation. Device drivers are supposed * to call instr->callback() whenever the operation completes, even * if it completes with a failure. * Callers are supposed to pass a callback function and wait for it * to be called before writing to the block. */ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) { if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr) return -EINVAL; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; if (!instr->len) { instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; } return mtd->_erase(mtd, instr); }
/** * gluebi_erase - erase operation of emulated MTD devices. * @mtd: the MTD device description object * @instr: the erase operation description * * This function calls the erase callback when finishes. Returns zero in case * of success and a negative error code in case of failure. */ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) { int err, i, lnum, count; struct ubi_volume *vol; struct ubi_device *ubi; dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len, (unsigned long long)instr->addr); if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) return -EINVAL; if (instr->len < 0 || instr->addr + instr->len > mtd->size) return -EINVAL; if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd)) return -EINVAL; lnum = mtd_div_by_eb(instr->addr, mtd); count = mtd_div_by_eb(instr->len, mtd); vol = container_of(mtd, struct ubi_volume, gluebi_mtd); ubi = vol->ubi; if (ubi->ro_mode) return -EROFS; for (i = 0; i < count; i++) { err = ubi_eba_unmap_leb(ubi, vol, lnum + i); if (err) goto out_err; } /* * MTD erase operations are synchronous, so we have to make sure the * physical eraseblock is wiped out. */ err = ubi_wl_flush(ubi); if (err) goto out_err; instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; out_err: instr->state = MTD_ERASE_FAILED; instr->fail_addr = (long long)lnum * mtd->erasesize; return err; }
/** * gluebi_erase - erase operation of emulated MTD devices. * @mtd: the MTD device description object * @instr: the erase operation description * * This function calls the erase callback when finishes. Returns zero in case * of success and a negative error code in case of failure. */ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) { int err, i, lnum, count; struct ubi_volume *vol; struct ubi_device *ubi; dbg_msg("erase %u bytes at offset %u", instr->len, instr->addr); if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) return -EINVAL; if (instr->len < 0 || instr->addr + instr->len > mtd->size) return -EINVAL; if (instr->addr % mtd->writesize || instr->len % mtd->writesize) return -EINVAL; lnum = instr->addr / mtd->erasesize; count = instr->len / mtd->erasesize; vol = container_of(mtd, struct ubi_volume, gluebi_mtd); ubi = vol->ubi; if (ubi->ro_mode) return -EROFS; for (i = 0; i < count; i++) { err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum + i); if (err) goto out_err; } /* * MTD erase operations are synchronous, so we have to make sure the * physical eraseblock is wiped out. */ err = ubi_wl_flush(ubi); if (err) goto out_err; instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; out_err: instr->state = MTD_ERASE_FAILED; instr->fail_addr = lnum * mtd->erasesize; return err; }
static int ps3vram_erase(struct mtd_info *mtd, struct erase_info *instr) { struct ps3vram_priv *priv = mtd->priv; if (instr->addr + instr->len > mtd->size) return -EINVAL; /* Set bytes to 0xFF */ memset(priv->base + instr->addr, 0xFF, instr->len); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr) { /* Yeah, it's inefficient. Who cares? It's faster than a _real_ flash erase. */ struct map_info *map = mtd->priv; map_word allff; unsigned long i; allff = map_word_ff(map); for (i=0; i<instr->len; i += map_bankwidth(map)) map_write(map, allff, instr->addr + i); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) { struct efx_nic *efx = mtd->priv; int rc; rc = efx->type->mtd_erase(mtd, erase->addr, erase->len); if (rc == 0) { erase->state = MTD_ERASE_DONE; } else { erase->state = MTD_ERASE_FAILED; erase->fail_addr = MTD_FAIL_ADDR_UNKNOWN; } mtd_erase_callback(erase); return rc; }
static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) { struct efx_mtd *efx_mtd = mtd->priv; int rc; rc = efx_mtd->ops->erase(mtd, erase->addr, erase->len); if (rc == 0) { erase->state = MTD_ERASE_DONE; } else { erase->state = MTD_ERASE_FAILED; erase->fail_addr = 0xffffffff; } mtd_erase_callback(erase); return rc; }
static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) { DEBUG(MTD_DEBUG_LEVEL2, "ram_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len); if (instr->addr + instr->len > mtd->size) { DEBUG(MTD_DEBUG_LEVEL1, "ram_erase() out of bounds (%ld > %ld)\n", (long)(instr->addr + instr->len), (long)mtd->size); return -EINVAL; } memset((char *)mtd->priv + instr->addr, 0xff, instr->len); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
/* * Erase an address range on the flash chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. */ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) { struct m25p *flash = mtd_to_m25p(mtd); u32 addr,len; DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", flash->spi->dev.bus_id, __func__, "at", (u32)instr->addr, instr->len); /* sanity checks */ if (instr->addr + instr->len > flash->mtd.size) return -EINVAL; if ((instr->addr % mtd->erasesize) != 0 || (instr->len % mtd->erasesize) != 0) { return -EINVAL; } addr = instr->addr; len = instr->len; mutex_lock(&flash->lock); /* REVISIT in some cases we could speed up erasing large regions * by using OPCODE_SE instead of OPCODE_BE_4K */ /* now erase those sectors */ while (len) { if (erase_sector(flash, addr)) { instr->state = MTD_ERASE_FAILED; mutex_unlock(&flash->lock); return -EIO; } addr += mtd->erasesize; len -= mtd->erasesize; } mutex_unlock(&flash->lock); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
static int sst25l_erase(struct mtd_info *mtd, struct erase_info *instr) { struct sst25l_flash *flash = to_sst25l_flash(mtd); uint32_t addr, end; int err; /* Sanity checks */ if (instr->addr + instr->len > flash->mtd.size) return -EINVAL; if ((uint32_t)instr->len % mtd->erasesize) return -EINVAL; if ((uint32_t)instr->addr % mtd->erasesize) return -EINVAL; addr = instr->addr; end = addr + instr->len; mutex_lock(&flash->lock); err = sst25l_wait_till_ready(flash); if (err) { mutex_unlock(&flash->lock); return err; } while (addr < end) { err = sst25l_erase_sector(flash, addr); if (err) { mutex_unlock(&flash->lock); instr->state = MTD_ERASE_FAILED; dev_err(&flash->spi->dev, "Erase failed\n"); return err; } addr += mtd->erasesize; } mutex_unlock(&flash->lock); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
static int tile_srom_erase(struct mtd_info *mtd, struct erase_info *instr) { struct tile_srom_dev *dev = to_tile_srom_dev(mtd); u32 addr, end; /* Sanity checks */ if (instr->addr + instr->len > mtd->size) return -EINVAL; if ((u32)instr->len & (mtd->erasesize - 1)) { pr_err("tile_srom: erase length invalid: erase size %#x, " "length %#x\n", mtd->erasesize, (u32)instr->len); return -EINVAL; } if ((u32)instr->addr & (mtd->erasesize - 1)) { pr_err("tile_srom: erase addr invalid: erase size %#X, " "addr %#x\n", mtd->erasesize, (u32)instr->addr); return -EINVAL; } addr = instr->addr; end = addr + instr->len; while (addr < end) { int hv_retval; char dummy = 0; hv_retval = hv_dev_pwrite(dev->hv_devhdl, 0, (HV_VirtAddr)&dummy, sizeof(dummy), SROM_ERASE_OFF | (u32) addr); if (hv_retval != sizeof(dummy)) { DEBUG(MTD_DEBUG_LEVEL1, "hv_dev_pwrite for erase" " failed, error %d\n", hv_retval); return -EIO; } addr += mtd->erasesize; } instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
/** * @mtd: the device * @erase: the erase info * Returns 0 if erase successful or -ERRNO if an error occurred */ static int powernv_flash_erase(struct mtd_info *mtd, struct erase_info *erase) { int rc; erase->state = MTD_ERASING; /* todo: register our own notifier to do a true async implementation */ rc = powernv_flash_async_op(mtd, FLASH_OP_ERASE, erase->addr, erase->len, NULL, NULL); if (rc) { erase->fail_addr = erase->addr; erase->state = MTD_ERASE_FAILED; } else { erase->state = MTD_ERASE_DONE; } mtd_erase_callback(erase); return rc; }
/* We could store these in the mtd structure, but we only support 1 device.. static struct mtd_info *mtd_info; */ static int sf_erase(struct mtd_info *mtd, struct erase_info *instr) { int ret; struct wmt_sf_info_t *info = (struct wmt_sf_info_t *)mtd->priv; struct sfreg_t *sfreg = info->reg; REG32_VAL(PMCEU_ADDR) |= SF_CLOCK_EN; ret = spi_flash_sector_erase((unsigned long)instr->addr, sfreg); if (ret != ERR_OK) { printk(KERN_ERR "sf_erase() error at address 0x%lx \n", (unsigned long)instr->addr); return -EINVAL; } instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); REG32_VAL(PMCEU_ADDR) &= ~(SF_CLOCK_EN); return 0; }
static int ps3vram_erase(struct mtd_info *mtd, struct erase_info *instr) { struct ps3vram_priv *priv = mtd->priv; if (instr->addr + instr->len > mtd->size) return -EINVAL; mutex_lock(&priv->lock); ps3vram_cache_flush(mtd); /* Set bytes to 0xFF */ memset_io(priv->ddr_base + instr->addr, 0xFF, instr->len); mutex_unlock(&priv->lock); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) { flash_info_t *fi = mtd->priv; size_t a_start = fi->start[0] + instr->addr; size_t a_end = a_start + instr->len; int s_first = -1; int s_last = -1; int error, sect; for (sect = 0; sect < fi->sector_count - 1; sect++) { if (a_start == fi->start[sect]) s_first = sect; if (a_end == fi->start[sect + 1]) { s_last = sect; break; } } if (s_first >= 0 && s_first <= s_last) { instr->state = MTD_ERASING; flash_set_verbose(0); error = flash_erase(fi, s_first, s_last); flash_set_verbose(1); if (error) { instr->state = MTD_ERASE_FAILED; return -EIO; } instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; } return -EINVAL; }
static int spiflash_erase (struct mtd_info *mtd,struct erase_info *instr) { struct opcodes *ptr_opcode; u32 temp, reg; /* sanity checks */ if (instr->addr + instr->len > mtd->size) return (-EINVAL); if (!spiflash_wait_ready(FL_ERASING)) return -EINTR; spiflash_sendcmd(SPI_WRITE_ENABLE, 0); busy_wait((reg = spiflash_regread32(SPI_FLASH_CTL)) & SPI_CTL_BUSY, 0); reg = spiflash_regread32(SPI_FLASH_CTL); ptr_opcode = &stm_opcodes[SPI_SECTOR_ERASE]; temp = ((__u32)instr->addr << 8) | (__u32)(ptr_opcode->code); spiflash_regwrite32(SPI_FLASH_OPCODE, temp); reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | ptr_opcode->tx_cnt | SPI_CTL_START; spiflash_regwrite32(SPI_FLASH_CTL, reg); /* this will take some time */ spin_unlock_bh(&spidata->mutex); msleep(800); spin_lock_bh(&spidata->mutex); busy_wait(spiflash_sendcmd(SPI_RD_STATUS, 0) & SPI_STATUS_WIP, 20); spiflash_done(); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
/* * Erase pages of flash. */ static int ifx_dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) { struct dataflash_t *priv = (struct dataflash_t *)mtd->priv; unsigned blocksize = priv->page_size << 3; u8 *command; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) uint32_t rem; IFX_DATA_FLASH_PRINT("erase addr=0x%llx len %lld\n", (long long)instr->addr, (long long)instr->len); #else IFX_DATA_FLASH_PRINT("erase addr=0x%x len 0x%x\n", instr->addr, instr->len); #endif /* Sanity checks */ if (instr->addr + instr->len > mtd->size) return -EINVAL; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) div_u64_rem(instr->len, priv->page_size, &rem); if (rem) return -EINVAL; div_u64_rem(instr->addr, priv->page_size, &rem); if (rem) return -EINVAL; #else if (((instr->len % priv->page_size) != 0) || ((instr->addr % priv->page_size) != 0)) { return -EINVAL; } #endif command = priv->command; down(&priv->lock); while (instr->len > 0) { unsigned int pageaddr; int do_block; /* Calculate flash page address; use block erase (for speed) if * we're at a block boundary and need to erase the whole block. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) pageaddr = div_u64(instr->addr, priv->page_size); #else pageaddr = instr->addr / priv->page_size; #endif do_block = (pageaddr & 0x7) == 0 && instr->len >= blocksize; pageaddr = pageaddr << priv->page_offset; command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE; command[1] = (u8)(pageaddr >> 16); command[2] = (u8)(pageaddr >> 8); command[3] = 0; IFX_DATA_FLASH_PRINT("ERASE %s: (%x) %x %x %x [%i]\n", do_block ? "block" : "page", command[0], command[1], command[2], command[3], pageaddr); ifx_dataflash_session(priv->spi, command, 4, 0, NULL, 0, NULL, 0); if (do_block) { instr->addr += blocksize; instr->len -= blocksize; } else { instr->addr += priv->page_size; instr->len -= priv->page_size; } } up(&priv->lock); /* Inform MTD subsystem that erase is complete */ instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
static int flash_erase (struct mtd_info *mtd,struct erase_info *instr) { __u32 addr,len; int i,first; #ifdef LART_DEBUG printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n",__FUNCTION__,instr->addr,instr->len); #endif /* sanity checks */ if (instr->addr + instr->len > mtd->size) return (-EINVAL); /* * check that both start and end of the requested erase are * aligned with the erasesize at the appropriate addresses. * * skip all erase regions which are ended before the start of * the requested erase. Actually, to save on the calculations, * we skip to the first erase region which starts after the * start of the requested erase, and then go back one. */ for (i = 0; i < mtd->numeraseregions && instr->addr >= mtd->eraseregions[i].offset; i++) ; i--; /* * ok, now i is pointing at the erase region in which this * erase request starts. Check the start of the requested * erase range is aligned with the erase size which is in * effect here. */ if (instr->addr & (mtd->eraseregions[i].erasesize - 1)) return (-EINVAL); /* Remember the erase region we start on */ first = i; /* * next, check that the end of the requested erase is aligned * with the erase region at that address. * * as before, drop back one to point at the region in which * the address actually falls */ for (; i < mtd->numeraseregions && instr->addr + instr->len >= mtd->eraseregions[i].offset; i++) ; i--; /* is the end aligned on a block boundary? */ if ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1)) return (-EINVAL); addr = instr->addr; len = instr->len; i = first; /* now erase those blocks */ while (len) { if (!erase_block (addr)) { instr->state = MTD_ERASE_FAILED; return (-EIO); } addr += mtd->eraseregions[i].erasesize; len -= mtd->eraseregions[i].erasesize; if (addr == mtd->eraseregions[i].offset + (mtd->eraseregions[i].erasesize * mtd->eraseregions[i].numblocks)) i++; } instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return (0); }
/* * Erase pages of flash. */ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) { struct dataflash *priv = mtd->priv; struct spi_device *spi = priv->spi; struct spi_transfer x = { .tx_dma = 0, }; struct spi_message msg; unsigned blocksize = priv->page_size << 3; uint8_t *command; uint32_t rem; pr_debug("%s: erase addr=0x%llx len 0x%llx\n", dev_name(&spi->dev), (long long)instr->addr, (long long)instr->len); div_u64_rem(instr->len, priv->page_size, &rem); if (rem) return -EINVAL; div_u64_rem(instr->addr, priv->page_size, &rem); if (rem) return -EINVAL; spi_message_init(&msg); x.tx_buf = command = priv->command; x.len = 4; spi_message_add_tail(&x, &msg); mutex_lock(&priv->lock); while (instr->len > 0) { unsigned int pageaddr; int status; int do_block; /* Calculate flash page address; use block erase (for speed) if * we're at a block boundary and need to erase the whole block. */ pageaddr = div_u64(instr->addr, priv->page_size); do_block = (pageaddr & 0x7) == 0 && instr->len >= blocksize; pageaddr = pageaddr << priv->page_offset; command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE; command[1] = (uint8_t)(pageaddr >> 16); command[2] = (uint8_t)(pageaddr >> 8); command[3] = 0; pr_debug("ERASE %s: (%x) %x %x %x [%i]\n", do_block ? "block" : "page", command[0], command[1], command[2], command[3], pageaddr); status = spi_sync(spi, &msg); (void) dataflash_waitready(spi); if (status < 0) { printk(KERN_ERR "%s: erase %x, err %d\n", dev_name(&spi->dev), pageaddr, status); /* REVISIT: can retry instr->retries times; or * giveup and instr->fail_addr = instr->addr; */ continue; } if (do_block) { instr->addr += blocksize; instr->len -= blocksize; } else { instr->addr += priv->page_size; instr->len -= priv->page_size; } } mutex_unlock(&priv->lock); /* Inform MTD subsystem that erase is complete */ instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; } /* * Read from the DataFlash device. * from : Start offset in flash device * len : Amount to read * retlen : About of data actually read * buf : Buffer containing the data */ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct dataflash *priv = mtd->priv; struct spi_transfer x[2] = { { .tx_dma = 0, }, }; struct spi_message msg; unsigned int addr; uint8_t *command; int status; pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev), (unsigned)from, (unsigned)(from + len)); /* Calculate flash page/byte address */ addr = (((unsigned)from / priv->page_size) << priv->page_offset) + ((unsigned)from % priv->page_size); command = priv->command; pr_debug("READ: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); spi_message_init(&msg); x[0].tx_buf = command; x[0].len = 8; spi_message_add_tail(&x[0], &msg); x[1].rx_buf = buf; x[1].len = len; spi_message_add_tail(&x[1], &msg); mutex_lock(&priv->lock); /* Continuous read, max clock = f(car) which may be less than * the peak rate available. Some chips support commands with * fewer "don't care" bytes. Both buffers stay unchanged. */ command[0] = OP_READ_CONTINUOUS; command[1] = (uint8_t)(addr >> 16); command[2] = (uint8_t)(addr >> 8); command[3] = (uint8_t)(addr >> 0); /* plus 4 "don't care" bytes */ status = spi_sync(priv->spi, &msg); mutex_unlock(&priv->lock); if (status >= 0) { *retlen = msg.actual_length - 8; status = 0; } else pr_debug("%s: read %x..%x --> %d\n", dev_name(&priv->spi->dev), (unsigned)from, (unsigned)(from + len), status); return status; }
/* * Erase an address range on the flash chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. */ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) { struct m25p *flash = mtd_to_m25p(mtd); u32 addr,len; uint64_t tmpdiv; int rem, rem1; DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", flash->spi->dev.bus_id, __FUNCTION__, "at", (u32)instr->addr, instr->len); /* sanity checks */ if (instr->addr + instr->len > device_size(&(flash->mtd))) return -EINVAL; tmpdiv = (uint64_t) instr->addr; rem = do_div(tmpdiv, mtd->erasesize); tmpdiv = (uint64_t) instr->len; rem1 = do_div(tmpdiv, mtd->erasesize); if (rem != 0 || rem1 != 0) { return -EINVAL; } addr = instr->addr; len = instr->len; mutex_lock(&flash->lock); /* REVISIT in some cases we could speed up erasing large regions * by using OPCODE_SE instead of OPCODE_BE_4K */ /* now erase those sectors */ while (len) { #ifdef CONFIG_MIPS_BRCM97XXX /* BSPI remaps each 4MB segment */ if (erase_sector(flash, (addr + 0x400000) & 0xffffff)) { #else if (erase_sector(flash, addr)) { #endif instr->state = MTD_ERASE_FAILED; mutex_unlock(&flash->lock); return -EIO; } addr += mtd->erasesize; len -= mtd->erasesize; } mutex_unlock(&flash->lock); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; } /* * Read an address range from the flash chip. The address range * may be any size provided it is within the physical boundaries. */ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct m25p *flash = mtd_to_m25p(mtd); struct spi_transfer t[2]; struct spi_message m; size_t total_len = len; DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", flash->spi->dev.bus_id, __FUNCTION__, "from", (u32)from, len); /* sanity checks */ if (!len) return 0; if (from + len > device_size(&(flash->mtd))) return -EINVAL; if (retlen) *retlen = 0; total_len = len; while(total_len) { len = total_len; #if 0 //defined(BRCM_SPI_SS_WAR) /* * For testing purposes only - read 12 bytes at a time: * * 3548a0 MSPI has a 12-byte limit (PR42350). * MSPI emulated via BSPI has no such limit. * In production BSPI is always used because it is much faster. */ if(len > 12) len = 12; #endif #ifdef CONFIG_MIPS_BRCM97XXX /* don't cross a 4MB boundary due to remapping */ len = min(len, (0x400000 - ((u32)from & 0x3fffff))); #endif spi_message_init(&m); memset(t, 0, (sizeof t)); t[0].tx_buf = flash->command; t[0].len = sizeof(flash->command); spi_message_add_tail(&t[0], &m); t[1].rx_buf = buf; t[1].len = len; spi_message_add_tail(&t[1], &m); /* Byte count starts at zero. */ mutex_lock(&flash->lock); /* Wait till previous write/erase is done. */ if (wait_till_ready(flash)) { /* REVISIT status return?? */ mutex_unlock(&flash->lock); return 1; } /* FIXME switch to OPCODE_FAST_READ. It's required for higher * clocks; and at this writing, every chip this driver handles * supports that opcode. */ /* Set up the write data buffer. */ flash->command[0] = OPCODE_READ; #ifdef CONFIG_MIPS_BRCM97XXX /* BSPI remaps each 4MB segment */ flash->command[1] = ((from >> 16) + 0x40) & 0xff; #else flash->command[1] = from >> 16; #endif flash->command[2] = from >> 8; flash->command[3] = from; spi_sync(flash->spi, &m); *retlen += m.actual_length - sizeof(flash->command); mutex_unlock(&flash->lock); from += len; buf += len; total_len -= len; } return 0; } /* * Write an address range to the flash chip. Data must be written in * FLASH_PAGESIZE chunks. The address range may be any size provided * it is within the physical boundaries. */ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct m25p *flash = mtd_to_m25p(mtd); u32 page_offset, page_size; struct spi_transfer t[2]; struct spi_message m; DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", flash->spi->dev.bus_id, __FUNCTION__, "to", (u32)to, len); if (retlen) *retlen = 0; /* sanity checks */ if (!len) return(0); if (to + len > device_size(&(flash->mtd))) return -EINVAL; #ifdef BRCM_SPI_SS_WAR if(len > 12) return -EIO; #endif spi_message_init(&m); memset(t, 0, (sizeof t)); t[0].tx_buf = flash->command; t[0].len = sizeof(flash->command); spi_message_add_tail(&t[0], &m); t[1].tx_buf = buf; spi_message_add_tail(&t[1], &m); mutex_lock(&flash->lock); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) return 1; write_enable(flash); /* Set up the opcode in the write buffer. */ flash->command[0] = OPCODE_PP; #ifdef CONFIG_MIPS_BRCM97XXX /* BSPI remaps each 4MB segment */ flash->command[1] = ((to >> 16) + 0x40) & 0xff; #else flash->command[1] = to >> 16; #endif flash->command[2] = to >> 8; flash->command[3] = to; /* what page do we start with? */ page_offset = to % FLASH_PAGESIZE; /* do all the bytes fit onto one page? */ if (page_offset + len <= FLASH_PAGESIZE) { t[1].len = len; spi_sync(flash->spi, &m); *retlen = m.actual_length - sizeof(flash->command); } else { u32 i; /* the size of data remaining on the first page */ page_size = FLASH_PAGESIZE - page_offset; t[1].len = page_size; spi_sync(flash->spi, &m); *retlen = m.actual_length - sizeof(flash->command); /* write everything in PAGESIZE chunks */ for (i = page_size; i < len; i += page_size) { page_size = len - i; if (page_size > FLASH_PAGESIZE) page_size = FLASH_PAGESIZE; /* write the next page to flash */ #ifdef CONFIG_MIPS_BRCM97XXX /* BSPI remaps each 4MB segment */ flash->command[1] = (((to + i) >> 16) + 0x40) & 0xff; #else flash->command[1] = (to + i) >> 16; #endif flash->command[2] = (to + i) >> 8; flash->command[3] = (to + i); t[1].tx_buf = buf + i; t[1].len = page_size; wait_till_ready(flash); write_enable(flash); spi_sync(flash->spi, &m); if (retlen) *retlen += m.actual_length - sizeof(flash->command); } } mutex_unlock(&flash->lock); return 0; } /****************************************************************************/ /* * SPI device driver setup and teardown */ struct flash_info { char *name; /* JEDEC id zero means "no ID" (most older chips); otherwise it has * a high byte of zero plus three data bytes: the manufacturer id, * then a two byte device id. */ u32 jedec_id; /* The size listed here is what works with OPCODE_SE, which isn't * necessarily called a "sector" by the vendor. */ unsigned sector_size; u16 n_sectors; u16 flags; #define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */ }; /* NOTE: double check command sets and memory organization when you add * more flash chips. This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. */ static struct flash_info __devinitdata m25p_data [] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ { "at25fs010", 0x1f6601, 32 * 1024, 4, SECT_4K, }, { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, }, { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, }, { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, }, { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, }, { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, }, { "at26df321", 0x1f4701, 64 * 1024, 64, SECT_4K, }, /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). */ { "s25sl004a", 0x010212, 64 * 1024, 8, }, { "s25sl008a", 0x010213, 64 * 1024, 16, }, { "s25sl016a", 0x010214, 64 * 1024, 32, }, { "s25sl032a", 0x010215, 64 * 1024, 64, }, { "s25sl064a", 0x010216, 64 * 1024, 128, }, #ifdef CONFIG_MIPS_BRCM97XXX { "s25fl128p", 0x012018, 64 * 1024, 256, }, #endif /* SST -- large erase sizes are "overlays", "sectors" are 4K */ { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, }, { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, }, { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, }, { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, }, /* ST Microelectronics -- newer production may have feature updates */ { "m25p05", 0x202010, 32 * 1024, 2, }, { "m25p10", 0x202011, 32 * 1024, 4, }, { "m25p20", 0x202012, 64 * 1024, 4, }, { "m25p40", 0x202013, 64 * 1024, 8, }, #ifndef CONFIG_MIPS_BRCM97XXX /* ID 0 is detected when there's nothing on the bus */ { "m25p80", 0, 64 * 1024, 16, }, #endif { "m25p16", 0x202015, 64 * 1024, 32, }, { "m25p32", 0x202016, 64 * 1024, 64, }, { "m25p64", 0x202017, 64 * 1024, 128, }, { "m25p128", 0x202018, 256 * 1024, 64, }, { "m45pe80", 0x204014, 64 * 1024, 16, }, { "m45pe16", 0x204015, 64 * 1024, 32, }, { "m25pe80", 0x208014, 64 * 1024, 16, }, { "m25pe16", 0x208015, 64 * 1024, 32, SECT_4K, }, /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, }, { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, }, { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, }, { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, }, { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, }, { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, }, { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, }, }; static struct flash_info *__devinit jedec_probe(struct spi_device *spi) { int tmp; u8 code = OPCODE_RDID; u8 id[3]; u32 jedec; struct flash_info *info; /* JEDEC also defines an optional "extended device information" * string for after vendor-specific data, after the three bytes * we use here. Supporting some chips might require using it. */ tmp = spi_write_then_read(spi, &code, 1, id, 3); if (tmp < 0) { DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", spi->dev.bus_id, tmp); return NULL; } jedec = id[0]; jedec = jedec << 8; jedec |= id[1]; jedec = jedec << 8; jedec |= id[2]; for (tmp = 0, info = m25p_data; tmp < ARRAY_SIZE(m25p_data); tmp++, info++) { if (info->jedec_id == jedec) return info; } dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); return NULL; }
/* * Erase pages of flash. */ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) { struct dataflash *priv = mtd->priv; struct spi_device *spi = priv->spi; struct spi_transfer x; struct spi_message msg; unsigned blocksize = priv->page_size << 3; uint8_t *command; uint32_t rem; pr_debug("%s: erase addr=0x%llx len 0x%llx\n", dev_name(&spi->dev), (long long)instr->addr, (long long)instr->len); div_u64_rem(instr->len, priv->page_size, &rem); if (rem) return -EINVAL; div_u64_rem(instr->addr, priv->page_size, &rem); if (rem) return -EINVAL; spi_message_init(&msg); memset(&x, 0, sizeof(x)); x.tx_buf = command = priv->command; x.len = 4; spi_message_add_tail(&x, &msg); while (instr->len > 0) { unsigned int pageaddr; int status; int do_block; /* Calculate flash page address; use block erase (for speed) if * we're at a block boundary and need to erase the whole block. */ pageaddr = div_u64(instr->addr, priv->page_size); do_block = (pageaddr & 0x7) == 0 && instr->len >= blocksize; pageaddr = pageaddr << priv->page_offset; command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE; command[1] = (uint8_t)(pageaddr >> 16); command[2] = (uint8_t)(pageaddr >> 8); command[3] = 0; pr_debug("ERASE %s: (%x) %x %x %x [%i]\n", do_block ? "block" : "page", command[0], command[1], command[2], command[3], pageaddr); status = spi_sync(spi, &msg); (void) dataflash_waitready(spi); if (status < 0) { printk(KERN_ERR "%s: erase %x, err %d\n", dev_name(&spi->dev), pageaddr, status); /* REVISIT: can retry instr->retries times; or * giveup and instr->fail_addr = instr->addr; */ continue; } if (do_block) { instr->addr += blocksize; instr->len -= blocksize; } else { instr->addr += priv->page_size; instr->len -= priv->page_size; } } /* Inform MTD subsystem that erase is complete */ instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }