diff options
Diffstat (limited to 'drivers/mtd/spi-nor/sst.c')
| -rw-r--r-- | drivers/mtd/spi-nor/sst.c | 229 |
1 files changed, 153 insertions, 76 deletions
diff --git a/drivers/mtd/spi-nor/sst.c b/drivers/mtd/spi-nor/sst.c index 980f4c09c91d..175211fe6a5e 100644 --- a/drivers/mtd/spi-nor/sst.c +++ b/drivers/mtd/spi-nor/sst.c @@ -8,14 +8,17 @@ #include "core.h" +/* SST flash_info mfr_flag. Used to specify SST byte programming. */ +#define SST_WRITE BIT(0) + #define SST26VF_CR_BPNV BIT(3) -static int sst26vf_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) +static int sst26vf_nor_lock(struct spi_nor *nor, loff_t ofs, u64 len) { return -EOPNOTSUPP; } -static int sst26vf_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) +static int sst26vf_nor_unlock(struct spi_nor *nor, loff_t ofs, u64 len) { int ret; @@ -35,64 +38,152 @@ static int sst26vf_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) return spi_nor_global_block_unlock(nor); } -static int sst26vf_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) +static int sst26vf_nor_is_locked(struct spi_nor *nor, loff_t ofs, u64 len) { return -EOPNOTSUPP; } -static const struct spi_nor_locking_ops sst26vf_locking_ops = { - .lock = sst26vf_lock, - .unlock = sst26vf_unlock, - .is_locked = sst26vf_is_locked, +static const struct spi_nor_locking_ops sst26vf_nor_locking_ops = { + .lock = sst26vf_nor_lock, + .unlock = sst26vf_nor_unlock, + .is_locked = sst26vf_nor_is_locked, }; -static void sst26vf_default_init(struct spi_nor *nor) +static int sst26vf_nor_late_init(struct spi_nor *nor) { - nor->params->locking_ops = &sst26vf_locking_ops; + nor->params->locking_ops = &sst26vf_nor_locking_ops; + + return 0; } -static const struct spi_nor_fixups sst26vf_fixups = { - .default_init = sst26vf_default_init, +static const struct spi_nor_fixups sst26vf_nor_fixups = { + .late_init = sst26vf_nor_late_init, }; -static const struct flash_info sst_parts[] = { - /* SST -- large erase sizes are "overlays", "sectors" are 4K */ - { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, - SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, - { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, - SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, - { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, - SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, - { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, - SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, - { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_4BIT_BP | SPI_NOR_HAS_LOCK | - SPI_NOR_SWP_IS_VOLATILE) }, - { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, - SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, - { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, - SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, - { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, - SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, - { "sst25wf020a", INFO(0x621612, 0, 64 * 1024, 4, SECT_4K | SPI_NOR_HAS_LOCK) }, - { "sst25wf040b", INFO(0x621613, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_HAS_LOCK) }, - { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, - SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, - { "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, - SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, - { "sst26wf016b", INFO(0xbf2651, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | - SPI_NOR_QUAD_READ) }, - { "sst26vf016b", INFO(0xbf2641, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ) }, - { "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) - .fixups = &sst26vf_fixups }, +static const struct flash_info sst_nor_parts[] = { + { + .id = SNOR_ID(0x62, 0x16, 0x12), + .name = "sst25wf020a", + .size = SZ_256K, + .flags = SPI_NOR_HAS_LOCK, + .no_sfdp_flags = SECT_4K, + }, { + .id = SNOR_ID(0x62, 0x16, 0x13), + .name = "sst25wf040b", + .size = SZ_512K, + .flags = SPI_NOR_HAS_LOCK, + .no_sfdp_flags = SECT_4K, + }, { + .id = SNOR_ID(0xbf, 0x25, 0x01), + .name = "sst25wf512", + .size = SZ_64K, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE, + .no_sfdp_flags = SECT_4K, + .mfr_flags = SST_WRITE, + }, { + .id = SNOR_ID(0xbf, 0x25, 0x02), + .name = "sst25wf010", + .size = SZ_128K, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE, + .no_sfdp_flags = SECT_4K, + .mfr_flags = SST_WRITE, + }, { + .id = SNOR_ID(0xbf, 0x25, 0x03), + .name = "sst25wf020", + .size = SZ_256K, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE, + .no_sfdp_flags = SECT_4K, + .mfr_flags = SST_WRITE, + }, { + .id = SNOR_ID(0xbf, 0x25, 0x04), + .name = "sst25wf040", + .size = SZ_512K, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE, + .no_sfdp_flags = SECT_4K, + .mfr_flags = SST_WRITE, + }, { + .id = SNOR_ID(0xbf, 0x25, 0x05), + .name = "sst25wf080", + .size = SZ_1M, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE, + .no_sfdp_flags = SECT_4K, + .mfr_flags = SST_WRITE, + }, { + .id = SNOR_ID(0xbf, 0x25, 0x41), + .name = "sst25vf016b", + .size = SZ_2M, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE, + .no_sfdp_flags = SECT_4K, + .mfr_flags = SST_WRITE, + }, { + .id = SNOR_ID(0xbf, 0x25, 0x4a), + .name = "sst25vf032b", + .size = SZ_4M, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE, + .no_sfdp_flags = SECT_4K, + .mfr_flags = SST_WRITE, + }, { + .id = SNOR_ID(0xbf, 0x25, 0x4b), + .name = "sst25vf064c", + .size = SZ_8M, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP | SPI_NOR_SWP_IS_VOLATILE, + .no_sfdp_flags = SECT_4K, + }, { + .id = SNOR_ID(0xbf, 0x25, 0x8d), + .name = "sst25vf040b", + .size = SZ_512K, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE, + .no_sfdp_flags = SECT_4K, + .mfr_flags = SST_WRITE, + }, { + .id = SNOR_ID(0xbf, 0x25, 0x8e), + .name = "sst25vf080b", + .size = SZ_1M, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE, + .no_sfdp_flags = SECT_4K, + .mfr_flags = SST_WRITE, + }, { + .id = SNOR_ID(0xbf, 0x26, 0x41), + .name = "sst26vf016b", + .size = SZ_2M, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ, + }, { + .id = SNOR_ID(0xbf, 0x26, 0x42), + .name = "sst26vf032b", + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE, + .fixups = &sst26vf_nor_fixups, + }, { + .id = SNOR_ID(0xbf, 0x26, 0x43), + .name = "sst26vf064b", + .size = SZ_8M, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, + .fixups = &sst26vf_nor_fixups, + }, { + .id = SNOR_ID(0xbf, 0x26, 0x51), + .name = "sst26wf016b", + .size = SZ_2M, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, + } }; -static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static int sst_nor_write_data(struct spi_nor *nor, loff_t to, size_t len, + const u_char *buf) +{ + u8 op = (len == 1) ? SPINOR_OP_BP : SPINOR_OP_AAI_WP; + int ret; + + nor->program_opcode = op; + ret = spi_nor_write_data(nor, to, len, buf); + if (ret < 0) + return ret; + WARN(ret != len, "While writing %zu byte written %i bytes\n", len, ret); + + return spi_nor_wait_till_ready(nor); +} + +static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { struct spi_nor *nor = mtd_to_spi_nor(mtd); size_t actual = 0; @@ -100,7 +191,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; @@ -112,16 +203,10 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, /* Start write from odd address. */ if (to % 2) { - nor->program_opcode = SPINOR_OP_BP; - /* write one byte. */ - ret = spi_nor_write_data(nor, to, 1, buf); + ret = sst_nor_write_data(nor, to, 1, buf); if (ret < 0) goto out; - WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret); - ret = spi_nor_wait_till_ready(nor); - if (ret) - goto out; to++; actual++; @@ -129,16 +214,11 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, /* Write out most of the data here. */ for (; actual < len - 1; actual += 2) { - nor->program_opcode = SPINOR_OP_AAI_WP; - /* write two bytes. */ - ret = spi_nor_write_data(nor, to, 2, buf + actual); + ret = sst_nor_write_data(nor, to, 2, buf + actual); if (ret < 0) goto out; - WARN(ret != 2, "While writing 2 bytes written %i bytes\n", ret); - ret = spi_nor_wait_till_ready(nor); - if (ret) - goto out; + to += 2; nor->sst_write_second = true; } @@ -158,14 +238,9 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, if (ret) goto out; - nor->program_opcode = SPINOR_OP_BP; - ret = spi_nor_write_data(nor, to, 1, buf + actual); + ret = sst_nor_write_data(nor, to, 1, buf + actual); if (ret < 0) goto out; - WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret); - ret = spi_nor_wait_till_ready(nor); - if (ret) - goto out; actual += 1; @@ -177,19 +252,21 @@ out: return ret; } -static void sst_post_sfdp_fixups(struct spi_nor *nor) +static int sst_nor_late_init(struct spi_nor *nor) { - if (nor->info->flags & SST_WRITE) - nor->mtd._write = sst_write; + if (nor->info->mfr_flags & SST_WRITE) + nor->mtd._write = sst_nor_write; + + return 0; } -static const struct spi_nor_fixups sst_fixups = { - .post_sfdp = sst_post_sfdp_fixups, +static const struct spi_nor_fixups sst_nor_fixups = { + .late_init = sst_nor_late_init, }; const struct spi_nor_manufacturer spi_nor_sst = { .name = "sst", - .parts = sst_parts, - .nparts = ARRAY_SIZE(sst_parts), - .fixups = &sst_fixups, + .parts = sst_nor_parts, + .nparts = ARRAY_SIZE(sst_nor_parts), + .fixups = &sst_nor_fixups, }; |
