static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct spi_nor *nor = mtd_to_spi_nor(mtd); uint32_t offset = ofs; uint8_t status_old, status_new; int ret = 0; ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); if (ret) return ret; /* Wait until finished previous command */ ret = wait_till_ready(nor); if (ret) goto err; status_old = read_sr(nor); if (offset+len > mtd->size - (mtd->size / 64)) status_new = status_old & ~(SR_BP2 | SR_BP1 | SR_BP0); else if (offset+len > mtd->size - (mtd->size / 32)) status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0; else if (offset+len > mtd->size - (mtd->size / 16)) status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1; else if (offset+len > mtd->size - (mtd->size / 8)) status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0; else if (offset+len > mtd->size - (mtd->size / 4)) status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2; else if (offset+len > mtd->size - (mtd->size / 2)) status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0; else status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1; /* Only modify protection if it will not lock other areas */ if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) < (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { write_enable(nor); ret = write_sr(nor, status_new); if (ret) goto err; } err: spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); return ret; }
static void __init chips_hw_init(void) { int i; for (i = 0; i < ARRAY_SIZE(chips_init_xr); ++i) write_xr(chips_init_xr[i].addr, chips_init_xr[i].data); outb(0x29, 0x3c2); /* set misc output reg */ for (i = 0; i < ARRAY_SIZE(chips_init_sr); ++i) write_sr(chips_init_sr[i].addr, chips_init_sr[i].data); for (i = 0; i < ARRAY_SIZE(chips_init_gr); ++i) write_gr(chips_init_gr[i].addr, chips_init_gr[i].data); for (i = 0; i < ARRAY_SIZE(chips_init_ar); ++i) write_ar(chips_init_ar[i].addr, chips_init_ar[i].data); for (i = 0; i < ARRAY_SIZE(chips_init_cr); ++i) write_cr(chips_init_cr[i].addr, chips_init_cr[i].data); for (i = 0; i < ARRAY_SIZE(chips_init_fr); ++i) write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); }
int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, enum read_mode mode) { struct flash_info *info; struct flash_platform_data *data; struct device *dev = nor->dev; struct mtd_info *mtd = nor->mtd; struct device_node *np = dev->of_node; int ret; int i; ret = spi_nor_check(nor); if (ret) return ret; /* Platform data helps sort out which chip type we have, as * well as how this board partitions it. If we don't have * a chip ID, try the JEDEC id commands; they'll work for most * newer chips, even if we don't recognize the particular chip. */ data = dev_get_platdata(dev); if (data && data->type) { const struct spi_device_id *plat_id; for (i = 0; i < ARRAY_SIZE(spi_nor_ids) - 1; i++) { plat_id = &spi_nor_ids[i]; if (strcmp(data->type, plat_id->name)) continue; break; } if (i < ARRAY_SIZE(spi_nor_ids) - 1) id = plat_id; else dev_warn(dev, "unrecognized id %s\n", data->type); } info = (void *)id->driver_data; if (info->jedec_id) { const struct spi_device_id *jid; jid = jedec_probe(nor); if (IS_ERR(jid)) { return PTR_ERR(jid); } else if (jid != id) { /* * JEDEC knows better, so overwrite platform ID. We * can't trust partitions any longer, but we'll let * mtd apply them anyway, since some partitions may be * marked read-only, and we don't want to lose that * information, even if it's not 100% accurate. */ dev_warn(dev, "found %s, expected %s\n", jid->name, id->name); id = jid; info = (void *)jid->driver_data; } } mutex_init(&nor->lock); /* * Atmel, SST and Intel/Numonyx serial nor tend to power * up with the software protection bits set */ if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ATMEL || JEDEC_MFR(info->jedec_id) == CFI_MFR_INTEL || JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) { write_enable(nor); write_sr(nor, 0); } if (data && data->name) mtd->name = data->name; else mtd->name = dev_name(dev); mtd->type = MTD_NORFLASH; mtd->writesize = 1; mtd->flags = MTD_CAP_NORFLASH; mtd->size = info->sector_size * info->n_sectors; mtd->_erase = spi_nor_erase; mtd->_read = spi_nor_read; /* nor protection support for STmicro chips */ if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) { mtd->_lock = spi_nor_lock; mtd->_unlock = spi_nor_unlock; } /* sst nor chips use AAI word program */ if (info->flags & SST_WRITE) mtd->_write = sst_write; else mtd->_write = spi_nor_write; /* prefer "small sector" erase if possible */ if (info->flags & SECT_4K) { nor->erase_opcode = SPINOR_OP_BE_4K; mtd->erasesize = 4096; } else if (info->flags & SECT_4K_PMC) { nor->erase_opcode = SPINOR_OP_BE_4K_PMC; mtd->erasesize = 4096; } else { nor->erase_opcode = SPINOR_OP_SE; mtd->erasesize = info->sector_size; } if (info->flags & SPI_NOR_NO_ERASE) mtd->flags |= MTD_NO_ERASE; mtd->dev.parent = dev; nor->page_size = info->page_size; mtd->writebufsize = nor->page_size; if (np) { /* If we were instantiated by DT, use it */ if (of_property_read_bool(np, "m25p,fast-read")) nor->flash_read = SPI_NOR_FAST; else nor->flash_read = SPI_NOR_NORMAL; } else { /* If we weren't instantiated by DT, default to fast-read */ nor->flash_read = SPI_NOR_FAST; } /* Some devices cannot do fast-read, no matter what DT tells us */ if (info->flags & SPI_NOR_NO_FR) nor->flash_read = SPI_NOR_NORMAL; /* Quad/Dual-read mode takes precedence over fast/normal */ if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) { ret = set_quad_mode(nor, info->jedec_id); if (ret) { dev_err(dev, "quad mode not supported\n"); return ret; } nor->flash_read = SPI_NOR_QUAD; } else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) { nor->flash_read = SPI_NOR_DUAL; } /* Default commands */ switch (nor->flash_read) { case SPI_NOR_QUAD: nor->read_opcode = SPINOR_OP_READ_1_1_4; break; case SPI_NOR_DUAL: nor->read_opcode = SPINOR_OP_READ_1_1_2; break; case SPI_NOR_FAST: nor->read_opcode = SPINOR_OP_READ_FAST; break; case SPI_NOR_NORMAL: nor->read_opcode = SPINOR_OP_READ; break; default: dev_err(dev, "No Read opcode defined\n"); return -EINVAL; } nor->program_opcode = SPINOR_OP_PP; if (info->addr_width) nor->addr_width = info->addr_width; else if (mtd->size > 0x1000000) { /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { /* Dedicated 4-byte command set */ switch (nor->flash_read) { case SPI_NOR_QUAD: nor->read_opcode = SPINOR_OP_READ4_1_1_4; break; case SPI_NOR_DUAL: nor->read_opcode = SPINOR_OP_READ4_1_1_2; break; case SPI_NOR_FAST: nor->read_opcode = SPINOR_OP_READ4_FAST; break; case SPI_NOR_NORMAL: nor->read_opcode = SPINOR_OP_READ4; break; } nor->program_opcode = SPINOR_OP_PP_4B; /* No small sector erase for 4-byte command set */ nor->erase_opcode = SPINOR_OP_SE_4B; mtd->erasesize = info->sector_size; } else set_4byte(nor, info->jedec_id, 1); } else { nor->addr_width = 3; } nor->read_dummy = spi_nor_read_dummy_cycles(nor); dev_info(dev, "%s (%lld Kbytes)\n", id->name, (long long)mtd->size >> 10); dev_dbg(dev, "mtd .name = %s, .size = 0x%llx (%lldMiB), " ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", mtd->name, (long long)mtd->size, (long long)(mtd->size >> 20), mtd->erasesize, mtd->erasesize / 1024, mtd->numeraseregions); if (mtd->numeraseregions) for (i = 0; i < mtd->numeraseregions; i++) dev_dbg(dev, "mtd.eraseregions[%d] = { .offset = 0x%llx, " ".erasesize = 0x%.8x (%uKiB), " ".numblocks = %d }\n", i, (long long)mtd->eraseregions[i].offset, mtd->eraseregions[i].erasesize, mtd->eraseregions[i].erasesize / 1024, mtd->eraseregions[i].numblocks); return 0; }
int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) { const struct flash_info *info = NULL; struct device *dev = nor->dev; struct mtd_info *mtd = &nor->mtd; struct device_node *np = nor->flash_node; int ret; int i; ret = spi_nor_check(nor); if (ret) return ret; if (name) info = spi_nor_match_id(name); /* Try to auto-detect if chip name wasn't specified or not found */ if (!info) info = spi_nor_read_id(nor); if (IS_ERR_OR_NULL(info)) return -ENOENT; /* * If caller has specified name of flash model that can normally be * detected using JEDEC, let's verify it. */ if (name && info->id_len) { const struct flash_info *jinfo; jinfo = spi_nor_read_id(nor); if (IS_ERR(jinfo)) { return PTR_ERR(jinfo); } else if (jinfo != info) { /* * JEDEC knows better, so overwrite platform ID. We * can't trust partitions any longer, but we'll let * mtd apply them anyway, since some partitions may be * marked read-only, and we don't want to lose that * information, even if it's not 100% accurate. */ dev_warn(dev, "found %s, expected %s\n", jinfo->name, info->name); info = jinfo; } } mutex_init(&nor->lock); /* * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up * with the software protection bits set */ if (JEDEC_MFR(info) == SNOR_MFR_ATMEL || JEDEC_MFR(info) == SNOR_MFR_INTEL || JEDEC_MFR(info) == SNOR_MFR_SST || JEDEC_MFR(info) == SNOR_MFR_WINBOND) { write_enable(nor); write_sr(nor, 0); } if (!mtd->name) mtd->name = dev_name(dev); mtd->priv = nor; mtd->type = MTD_NORFLASH; mtd->writesize = 1; mtd->flags = MTD_CAP_NORFLASH; mtd->size = info->sector_size * info->n_sectors; mtd->_erase = spi_nor_erase; mtd->_read = spi_nor_read; /* NOR protection support for STmicro/Micron chips and similar */ if (JEDEC_MFR(info) == SNOR_MFR_MICRON || JEDEC_MFR(info) == SNOR_MFR_WINBOND) { nor->flash_lock = stm_lock; nor->flash_unlock = stm_unlock; nor->flash_is_locked = stm_is_locked; } if (nor->flash_lock && nor->flash_unlock && nor->flash_is_locked) { mtd->_lock = spi_nor_lock; mtd->_unlock = spi_nor_unlock; mtd->_is_locked = spi_nor_is_locked; } /* sst nor chips use AAI word program */ if (info->flags & SST_WRITE) mtd->_write = sst_write; else mtd->_write = spi_nor_write; if (info->flags & USE_FSR) nor->flags |= SNOR_F_USE_FSR; #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS /* prefer "small sector" erase if possible */ if (info->flags & SECT_4K) { nor->erase_opcode = SPINOR_OP_BE_4K; mtd->erasesize = 4096; } else if (info->flags & SECT_4K_PMC) { nor->erase_opcode = SPINOR_OP_BE_4K_PMC; mtd->erasesize = 4096; } else #endif { nor->erase_opcode = SPINOR_OP_SE; mtd->erasesize = info->sector_size; } if (info->flags & SPI_NOR_NO_ERASE) mtd->flags |= MTD_NO_ERASE; mtd->dev.parent = dev; nor->page_size = info->page_size; mtd->writebufsize = nor->page_size; if (np) { /* If we were instantiated by DT, use it */ if (of_property_read_bool(np, "m25p,fast-read")) nor->flash_read = SPI_NOR_FAST; else nor->flash_read = SPI_NOR_NORMAL; } else { /* If we weren't instantiated by DT, default to fast-read */ nor->flash_read = SPI_NOR_FAST; } /* Some devices cannot do fast-read, no matter what DT tells us */ if (info->flags & SPI_NOR_NO_FR) nor->flash_read = SPI_NOR_NORMAL; /* Quad/Dual-read mode takes precedence over fast/normal */ if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) { ret = set_quad_mode(nor, info); if (ret) { dev_err(dev, "quad mode not supported\n"); return ret; } nor->flash_read = SPI_NOR_QUAD; } else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) { nor->flash_read = SPI_NOR_DUAL; } /* Default commands */ switch (nor->flash_read) { case SPI_NOR_QUAD: nor->read_opcode = SPINOR_OP_READ_1_1_4; break; case SPI_NOR_DUAL: nor->read_opcode = SPINOR_OP_READ_1_1_2; break; case SPI_NOR_FAST: nor->read_opcode = SPINOR_OP_READ_FAST; break; case SPI_NOR_NORMAL: nor->read_opcode = SPINOR_OP_READ; break; default: dev_err(dev, "No Read opcode defined\n"); return -EINVAL; } nor->program_opcode = SPINOR_OP_PP; if (info->addr_width) nor->addr_width = info->addr_width; else if (mtd->size > 0x1000000) { /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) { /* Dedicated 4-byte command set */ switch (nor->flash_read) { case SPI_NOR_QUAD: nor->read_opcode = SPINOR_OP_READ4_1_1_4; break; case SPI_NOR_DUAL: nor->read_opcode = SPINOR_OP_READ4_1_1_2; break; case SPI_NOR_FAST: nor->read_opcode = SPINOR_OP_READ4_FAST; break; case SPI_NOR_NORMAL: nor->read_opcode = SPINOR_OP_READ4; break; } nor->program_opcode = SPINOR_OP_PP_4B; /* No small sector erase for 4-byte command set */ nor->erase_opcode = SPINOR_OP_SE_4B; mtd->erasesize = info->sector_size; } else set_4byte(nor, info, 1); } else { nor->addr_width = 3; } nor->read_dummy = spi_nor_read_dummy_cycles(nor); dev_info(dev, "%s (%lld Kbytes)\n", info->name, (long long)mtd->size >> 10); dev_dbg(dev, "mtd .name = %s, .size = 0x%llx (%lldMiB), " ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", mtd->name, (long long)mtd->size, (long long)(mtd->size >> 20), mtd->erasesize, mtd->erasesize / 1024, mtd->numeraseregions); if (mtd->numeraseregions) for (i = 0; i < mtd->numeraseregions; i++) dev_dbg(dev, "mtd.eraseregions[%d] = { .offset = 0x%llx, " ".erasesize = 0x%.8x (%uKiB), " ".numblocks = %d }\n", i, (long long)mtd->eraseregions[i].offset, mtd->eraseregions[i].erasesize, mtd->eraseregions[i].erasesize / 1024, mtd->eraseregions[i].numblocks); return 0; }