diff options
| author | Miquel Raynal <miquel.raynal@bootlin.com> | 2022-03-18 20:14:12 +0100 |
|---|---|---|
| committer | Miquel Raynal <miquel.raynal@bootlin.com> | 2022-03-18 20:14:42 +0100 |
| commit | 4e371d996590f3a7e82a086d499c912c1930e968 (patch) | |
| tree | 0c7b300670901f498238b32e59c307eddf338489 /drivers/mtd | |
| parent | 8f877b7eab9d60a9deef6beae95656b77d55ab75 (diff) | |
| parent | 151c6b49d679872d6fc0b50e0ad96303091694a2 (diff) | |
| download | linux-4e371d996590f3a7e82a086d499c912c1930e968.tar.gz linux-4e371d996590f3a7e82a086d499c912c1930e968.tar.bz2 linux-4e371d996590f3a7e82a086d499c912c1930e968.zip | |
Merge tag 'spi-nor/for-5.18' into mtd/next
SPI NOR core changes:
- move vendor specific code out of the core into vendor drivers.
- unify all function and object names in the vendor modules.
- make setup() callback optional to improve readability.
- skip erase logic when the SPI_NOR_NO_ERASE flag is set at flash
declaration.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Diffstat (limited to 'drivers/mtd')
25 files changed, 629 insertions, 536 deletions
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 6ed6c51fac69..d503821a3e60 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -264,16 +264,20 @@ static int phram_setup(const char *val) } } - if (erasesize) - div_u64_rem(len, (uint32_t)erasesize, &rem); - if (len == 0 || erasesize == 0 || erasesize > len - || erasesize > UINT_MAX || rem) { + || erasesize > UINT_MAX) { parse_err("illegal erasesize or len\n"); ret = -EINVAL; goto error; } + div_u64_rem(len, (uint32_t)erasesize, &rem); + if (rem) { + parse_err("len is not multiple of erasesize\n"); + ret = -EINVAL; + goto error; + } + ret = register_device(name, start, len, (uint32_t)erasesize); if (ret) goto error; diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 20408b7db540..d986ab4e4c35 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -42,7 +42,8 @@ config MTD_NAND_OMAP2 tristate "OMAP2, OMAP3, OMAP4 and Keystone NAND controller" depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST depends on HAS_IOMEM - select OMAP_GPMC if ARCH_K3 + select MEMORY + select OMAP_GPMC help Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4 and Keystone platforms. diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 7c0f02069ea0..df1b73da49d4 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -2106,7 +2106,7 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, mtd->oobsize / trans, host->hwcfg.sector_size_1k); - if (!ret) { + if (ret != -EBADMSG) { *err_addr = brcmnand_get_uncorrecc_addr(ctrl); if (*err_addr) diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 1b64c5a5140d..ded4df473928 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -2285,7 +2285,7 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip, this->hw.must_apply_timings = false; ret = gpmi_nfc_apply_timings(this); if (ret) - return ret; + goto out_pm; } dev_dbg(this->dev, "%s: %d instructions\n", __func__, op->ninstrs); @@ -2414,6 +2414,7 @@ unmap: this->bch = false; +out_pm: pm_runtime_mark_last_busy(this->dev); pm_runtime_put_autosuspend(this->dev); diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c index efe0ffe4f1ab..9054559e52dd 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c @@ -68,9 +68,14 @@ static struct ingenic_ecc *ingenic_ecc_get(struct device_node *np) struct ingenic_ecc *ecc; pdev = of_find_device_by_node(np); - if (!pdev || !platform_get_drvdata(pdev)) + if (!pdev) return ERR_PTR(-EPROBE_DEFER); + if (!platform_get_drvdata(pdev)) { + put_device(&pdev->dev); + return ERR_PTR(-EPROBE_DEFER); + } + ecc = platform_get_drvdata(pdev); clk_prepare_enable(ecc->clk); diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 7c6efa3b6255..1a77542c6d67 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -2,7 +2,6 @@ /* * Copyright (c) 2016, The Linux Foundation. All rights reserved. */ - #include <linux/clk.h> #include <linux/slab.h> #include <linux/bitops.h> @@ -3073,10 +3072,6 @@ static int qcom_nandc_probe(struct platform_device *pdev) if (dma_mapping_error(dev, nandc->base_dma)) return -ENXIO; - ret = qcom_nandc_alloc(nandc); - if (ret) - goto err_nandc_alloc; - ret = clk_prepare_enable(nandc->core_clk); if (ret) goto err_core_clk; @@ -3085,6 +3080,10 @@ static int qcom_nandc_probe(struct platform_device *pdev) if (ret) goto err_aon_clk; + ret = qcom_nandc_alloc(nandc); + if (ret) + goto err_nandc_alloc; + ret = qcom_nandc_setup(nandc); if (ret) goto err_setup; @@ -3096,15 +3095,14 @@ static int qcom_nandc_probe(struct platform_device *pdev) return 0; err_setup: + qcom_nandc_unalloc(nandc); +err_nandc_alloc: clk_disable_unprepare(nandc->aon_clk); err_aon_clk: clk_disable_unprepare(nandc->core_clk); err_core_clk: - qcom_nandc_unalloc(nandc); -err_nandc_alloc: dma_unmap_resource(dev, res->start, resource_size(res), DMA_BIDIRECTIONAL, 0); - return ret; } diff --git a/drivers/mtd/parsers/qcomsmempart.c b/drivers/mtd/parsers/qcomsmempart.c index 06a818cd2433..4311b89d8df0 100644 --- a/drivers/mtd/parsers/qcomsmempart.c +++ b/drivers/mtd/parsers/qcomsmempart.c @@ -58,11 +58,11 @@ static int parse_qcomsmem_part(struct mtd_info *mtd, const struct mtd_partition **pparts, struct mtd_part_parser_data *data) { + size_t len = SMEM_FLASH_PTABLE_HDR_LEN; + int ret, i, j, tmpparts, numparts = 0; struct smem_flash_pentry *pentry; struct smem_flash_ptable *ptable; - size_t len = SMEM_FLASH_PTABLE_HDR_LEN; struct mtd_partition *parts; - int ret, i, numparts; char *name, *c; if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_4K_SECTORS) @@ -75,7 +75,8 @@ static int parse_qcomsmem_part(struct mtd_info *mtd, pr_debug("Parsing partition table info from SMEM\n"); ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); if (IS_ERR(ptable)) { - pr_err("Error reading partition table header\n"); + if (PTR_ERR(ptable) != -EPROBE_DEFER) + pr_err("Error reading partition table header\n"); return PTR_ERR(ptable); } @@ -87,8 +88,8 @@ static int parse_qcomsmem_part(struct mtd_info *mtd, } /* Ensure that # of partitions is less than the max we have allocated */ - numparts = le32_to_cpu(ptable->numparts); - if (numparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) { + tmpparts = le32_to_cpu(ptable->numparts); + if (tmpparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) { pr_err("Partition numbers exceed the max limit\n"); return -EINVAL; } @@ -116,11 +117,17 @@ static int parse_qcomsmem_part(struct mtd_info *mtd, return PTR_ERR(ptable); } + for (i = 0; i < tmpparts; i++) { + pentry = &ptable->pentry[i]; + if (pentry->name[0] != '\0') + numparts++; + } + parts = kcalloc(numparts, sizeof(*parts), GFP_KERNEL); if (!parts) return -ENOMEM; - for (i = 0; i < numparts; i++) { + for (i = 0, j = 0; i < tmpparts; i++) { pentry = &ptable->pentry[i]; if (pentry->name[0] == '\0') continue; @@ -135,24 +142,25 @@ static int parse_qcomsmem_part(struct mtd_info *mtd, for (c = name; *c != '\0'; c++) *c = tolower(*c); - parts[i].name = name; - parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; - parts[i].mask_flags = pentry->attr; - parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; + parts[j].name = name; + parts[j].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; + parts[j].mask_flags = pentry->attr; + parts[j].size = le32_to_cpu(pentry->length) * mtd->erasesize; pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", i, pentry->name, le32_to_cpu(pentry->offset), le32_to_cpu(pentry->length), pentry->attr); + j++; } pr_debug("SMEM partition table found: ver: %d len: %d\n", - le32_to_cpu(ptable->version), numparts); + le32_to_cpu(ptable->version), tmpparts); *pparts = parts; return numparts; out_free_parts: - while (--i >= 0) - kfree(parts[i].name); + while (--j >= 0) + kfree(parts[j].name); kfree(parts); *pparts = NULL; @@ -166,6 +174,8 @@ static void parse_qcomsmem_cleanup(const struct mtd_partition *pparts, for (i = 0; i < nr_parts; i++) kfree(pparts[i].name); + + kfree(pparts); } static const struct of_device_id qcomsmem_of_match_table[] = { diff --git a/drivers/mtd/spi-nor/atmel.c b/drivers/mtd/spi-nor/atmel.c index d6d889ce8876..656dd80a0be7 100644 --- a/drivers/mtd/spi-nor/atmel.c +++ b/drivers/mtd/spi-nor/atmel.c @@ -16,12 +16,12 @@ * is to unlock the whole flash array on startup. Therefore, we have to support * exactly this operation. */ -static int atmel_at25fs_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) +static int at25fs_nor_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) { return -EOPNOTSUPP; } -static int atmel_at25fs_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) +static int at25fs_nor_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) { int ret; @@ -37,28 +37,28 @@ static int atmel_at25fs_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) return ret; } -static int atmel_at25fs_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) +static int at25fs_nor_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) { return -EOPNOTSUPP; } -static const struct spi_nor_locking_ops atmel_at25fs_locking_ops = { - .lock = atmel_at25fs_lock, - .unlock = atmel_at25fs_unlock, - .is_locked = atmel_at25fs_is_locked, +static const struct spi_nor_locking_ops at25fs_nor_locking_ops = { + .lock = at25fs_nor_lock, + .unlock = at25fs_nor_unlock, + .is_locked = at25fs_nor_is_locked, }; -static void atmel_at25fs_late_init(struct spi_nor *nor) +static void at25fs_nor_late_init(struct spi_nor *nor) { - nor->params->locking_ops = &atmel_at25fs_locking_ops; + nor->params->locking_ops = &at25fs_nor_locking_ops; } -static const struct spi_nor_fixups atmel_at25fs_fixups = { - .late_init = atmel_at25fs_late_init, +static const struct spi_nor_fixups at25fs_nor_fixups = { + .late_init = at25fs_nor_late_init, }; /** - * atmel_set_global_protection - Do a Global Protect or Unprotect command + * atmel_nor_set_global_protection - Do a Global Protect or Unprotect command * @nor: pointer to 'struct spi_nor' * @ofs: offset in bytes * @len: len in bytes @@ -66,8 +66,8 @@ static const struct spi_nor_fixups atmel_at25fs_fixups = { * * Return: 0 on success, -error otherwise. */ -static int atmel_set_global_protection(struct spi_nor *nor, loff_t ofs, - uint64_t len, bool is_protect) +static int atmel_nor_set_global_protection(struct spi_nor *nor, loff_t ofs, + uint64_t len, bool is_protect) { int ret; u8 sr; @@ -116,17 +116,20 @@ static int atmel_set_global_protection(struct spi_nor *nor, loff_t ofs, return spi_nor_write_sr(nor, nor->bouncebuf, 1); } -static int atmel_global_protect(struct spi_nor *nor, loff_t ofs, uint64_t len) +static int atmel_nor_global_protect(struct spi_nor *nor, loff_t ofs, + uint64_t len) { - return atmel_set_global_protection(nor, ofs, len, true); + return atmel_nor_set_global_protection(nor, ofs, len, true); } -static int atmel_global_unprotect(struct spi_nor *nor, loff_t ofs, uint64_t len) +static int atmel_nor_global_unprotect(struct spi_nor *nor, loff_t ofs, + uint64_t len) { - return atmel_set_global_protection(nor, ofs, len, false); + return atmel_nor_set_global_protection(nor, ofs, len, false); } -static int atmel_is_global_protected(struct spi_nor *nor, loff_t ofs, uint64_t len) +static int atmel_nor_is_global_protected(struct spi_nor *nor, loff_t ofs, + uint64_t len) { int ret; @@ -140,47 +143,47 @@ static int atmel_is_global_protected(struct spi_nor *nor, loff_t ofs, uint64_t l return ((nor->bouncebuf[0] & ATMEL_SR_GLOBAL_PROTECT_MASK) == ATMEL_SR_GLOBAL_PROTECT_MASK); } -static const struct spi_nor_locking_ops atmel_global_protection_ops = { - .lock = atmel_global_protect, - .unlock = atmel_global_unprotect, - .is_locked = atmel_is_global_protected, +static const struct spi_nor_locking_ops atmel_nor_global_protection_ops = { + .lock = atmel_nor_global_protect, + .unlock = atmel_nor_global_unprotect, + .is_locked = atmel_nor_is_global_protected, }; -static void atmel_global_protection_late_init(struct spi_nor *nor) +static void atmel_nor_global_protection_late_init(struct spi_nor *nor) { - nor->params->locking_ops = &atmel_global_protection_ops; + nor->params->locking_ops = &atmel_nor_global_protection_ops; } -static const struct spi_nor_fixups atmel_global_protection_fixups = { - .late_init = atmel_global_protection_late_init, +static const struct spi_nor_fixups atmel_nor_global_protection_fixups = { + .late_init = atmel_nor_global_protection_late_init, }; -static const struct flash_info atmel_parts[] = { +static const struct flash_info atmel_nor_parts[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4) FLAGS(SPI_NOR_HAS_LOCK) NO_SFDP_FLAGS(SECT_4K) - .fixups = &atmel_at25fs_fixups }, + .fixups = &at25fs_nor_fixups }, { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8) FLAGS(SPI_NOR_HAS_LOCK) NO_SFDP_FLAGS(SECT_4K) - .fixups = &atmel_at25fs_fixups }, + .fixups = &at25fs_nor_fixups }, { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8) FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) NO_SFDP_FLAGS(SECT_4K) - .fixups = &atmel_global_protection_fixups }, + .fixups = &atmel_nor_global_protection_fixups }, { "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64) FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) NO_SFDP_FLAGS(SECT_4K) - .fixups = &atmel_global_protection_fixups }, + .fixups = &atmel_nor_global_protection_fixups }, { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64) FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) NO_SFDP_FLAGS(SECT_4K) - .fixups = &atmel_global_protection_fixups }, + .fixups = &atmel_nor_global_protection_fixups }, { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128) FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) NO_SFDP_FLAGS(SECT_4K) - .fixups = &atmel_global_protection_fixups }, + .fixups = &atmel_nor_global_protection_fixups }, { "at25sl321", INFO(0x1f4216, 0, 64 * 1024, 64) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8) @@ -188,21 +191,21 @@ static const struct flash_info atmel_parts[] = { { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16) FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) NO_SFDP_FLAGS(SECT_4K) - .fixups = &atmel_global_protection_fixups }, + .fixups = &atmel_nor_global_protection_fixups }, { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32) FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) NO_SFDP_FLAGS(SECT_4K) - .fixups = &atmel_global_protection_fixups }, + .fixups = &atmel_nor_global_protection_fixups }, { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64) FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) NO_SFDP_FLAGS(SECT_4K) - .fixups = &atmel_global_protection_fixups }, + .fixups = &atmel_nor_global_protection_fixups }, { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16) NO_SFDP_FLAGS(SECT_4K) }, }; const struct spi_nor_manufacturer spi_nor_atmel = { .name = "atmel", - .parts = atmel_parts, - .nparts = ARRAY_SIZE(atmel_parts), + .parts = atmel_nor_parts, + .nparts = ARRAY_SIZE(atmel_nor_parts), }; diff --git a/drivers/mtd/spi-nor/catalyst.c b/drivers/mtd/spi-nor/catalyst.c index ae4d67e01bb3..6d310815fb12 100644 --- a/drivers/mtd/spi-nor/catalyst.c +++ b/drivers/mtd/spi-nor/catalyst.c @@ -8,7 +8,7 @@ #include "core.h" -static const struct flash_info catalyst_parts[] = { +static const struct flash_info catalyst_nor_parts[] = { /* Catalyst / On Semiconductor -- non-JEDEC */ { "cat25c11", CAT25_INFO(16, 8, 16, 1) }, { "cat25c03", CAT25_INFO(32, 8, 16, 2) }, @@ -19,6 +19,6 @@ static const struct flash_info catalyst_parts[] = { const struct spi_nor_manufacturer spi_nor_catalyst = { .name = "catalyst", - .parts = catalyst_parts, - .nparts = ARRAY_SIZE(catalyst_parts), + .parts = catalyst_nor_parts, + .nparts = ARRAY_SIZE(catalyst_nor_parts), }; diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 04ea180118e3..b4f141ad9c9c 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -157,8 +157,8 @@ static int spi_nor_spimem_exec_op(struct spi_nor *nor, struct spi_mem_op *op) return spi_mem_exec_op(nor->spimem, op); } -static int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode, - u8 *buf, size_t len) +int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode, + u8 *buf, size_t len) { if (spi_nor_protocol_is_dtr(nor->reg_proto)) return -EOPNOTSUPP; @@ -166,8 +166,8 @@ static int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode, return nor->controller_ops->read_reg(nor, opcode, buf, len); } -static int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode, - const u8 *buf, size_t len) +int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode, + const u8 *buf, size_t len) { if (spi_nor_protocol_is_dtr(nor->reg_proto)) return -EOPNOTSUPP; @@ -413,50 +413,6 @@ int spi_nor_read_sr(struct spi_nor *nor, u8 *sr) } /** - * spi_nor_read_fsr() - Read the Flag Status Register. - * @nor: pointer to 'struct spi_nor' - * @fsr: pointer to a DMA-able buffer where the value of the - * Flag Status Register will be written. Should be at least 2 - * bytes. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr) -{ - int ret; - - if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, fsr, 0)); - - if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) { - op.addr.nbytes = nor->params->rdsr_addr_nbytes; - op.dummy.nbytes = nor->params->rdsr_dummy; - /* - * We don't want to read only one byte in DTR mode. So, - * read 2 and then discard the second byte. - */ - op.data.nbytes = 2; - } - - spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); - - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, fsr, - 1); - } - - if (ret) - dev_dbg(nor->dev, "error %d reading FSR\n", ret); - - return ret; -} - -/** * spi_nor_read_cr() - Read the Configuration Register using the * SPINOR_OP_RDCR (35h) command. * @nor: pointer to 'struct spi_nor' @@ -599,189 +555,21 @@ int spi_nor_write_ear(struct spi_nor *nor, u8 ear) } /** - * spi_nor_xread_sr() - Read the Status Register on S3AN flashes. - * @nor: pointer to 'struct spi_nor'. - * @sr: pointer to a DMA-able buffer where the value of the - * Status Register will be written. - * - * Return: 0 on success, -errno otherwise. - */ -int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr) -{ - int ret; - - if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_XRDSR, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, sr, 0)); - - spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); - - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_XRDSR, sr, - 1); - } - - if (ret) - dev_dbg(nor->dev, "error %d reading XRDSR\n", ret); - - return ret; -} - -/** - * spi_nor_xsr_ready() - Query the Status Register of the S3AN flash to see if - * the flash is ready for new commands. - * @nor: pointer to 'struct spi_nor'. - * - * Return: 1 if ready, 0 if not ready, -errno on errors. - */ -static int spi_nor_xsr_ready(struct spi_nor *nor) -{ - int ret; - - ret = spi_nor_xread_sr(nor, nor->bouncebuf); - if (ret) - return ret; - - return !!(nor->bouncebuf[0] & XSR_RDY); -} - -/** - * spi_nor_clear_sr() - Clear the Status Register. - * @nor: pointer to 'struct spi_nor'. - */ -static void spi_nor_clear_sr(struct spi_nor *nor) -{ - int ret; - - if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); - - spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); - - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR, - NULL, 0); - } - - if (ret) - dev_dbg(nor->dev, "error %d clearing SR\n", ret); -} - -/** * spi_nor_sr_ready() - Query the Status Register to see if the flash is ready * for new commands. * @nor: pointer to 'struct spi_nor'. * * Return: 1 if ready, 0 if not ready, -errno on errors. */ -static int spi_nor_sr_ready(struct spi_nor *nor) -{ - int ret = spi_nor_read_sr(nor, nor->bouncebuf); - - if (ret) - return ret; - - if (nor->flags & SNOR_F_USE_CLSR && - nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) { - if (nor->bouncebuf[0] & SR_E_ERR) - dev_err(nor->dev, "Erase Error occurred\n"); - else - dev_err(nor->dev, "Programming Error occurred\n"); - - spi_nor_clear_sr(nor); - - /* - * WEL bit remains set to one when an erase or page program - * error occurs. Issue a Write Disable command to protect - * against inadvertent writes that can possibly corrupt the - * contents of the memory. - */ - ret = spi_nor_write_disable(nor); - if (ret) - return ret; - - return -EIO; - } - - return !(nor->bouncebuf[0] & SR_WIP); -} - -/** - * spi_nor_clear_fsr() - Clear the Flag Status Register. - * @nor: pointer to 'struct spi_nor'. - */ -static void spi_nor_clear_fsr(struct spi_nor *nor) +int spi_nor_sr_ready(struct spi_nor *nor) { int ret; - if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); - - spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); - - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLFSR, - NULL, 0); - } - - if (ret) - dev_dbg(nor->dev, "error %d clearing FSR\n", ret); -} - -/** - * spi_nor_fsr_ready() - Query the Flag Status Register to see if the flash is - * ready for new commands. - * @nor: pointer to 'struct spi_nor'. - * - * Return: 1 if ready, 0 if not ready, -errno on errors. - */ -static int spi_nor_fsr_ready(struct spi_nor *nor) -{ - int ret = spi_nor_read_fsr(nor, nor->bouncebuf); - + ret = spi_nor_read_sr(nor, nor->bouncebuf); if (ret) return ret; - if (nor->bouncebuf[0] & (FSR_E_ERR | FSR_P_ERR)) { - if (nor->bouncebuf[0] & FSR_E_ERR) - dev_err(nor->dev, "Erase operation failed.\n"); - else - dev_err(nor->dev, "Program operation failed.\n"); - - if (nor->bouncebuf[0] & FSR_PT_ERR) - dev_err(nor->dev, - "Attempted to modify a protected sector.\n"); - - spi_nor_clear_fsr(nor); - - /* - * WEL bit remains set to one when an erase or page program - * error occurs. Issue a Write Disable command to protect - * against inadvertent writes that can possibly corrupt the - * contents of the memory. - */ - ret = spi_nor_write_disable(nor); - if (ret) - return ret; - - return -EIO; - } - - return !!(nor->bouncebuf[0] & FSR_READY); + return !(nor->bouncebuf[0] & SR_WIP); } /** @@ -792,18 +580,11 @@ static int spi_nor_fsr_ready(struct spi_nor *nor) */ static int spi_nor_ready(struct spi_nor *nor) { - int sr, fsr; + /* Flashes might override the standard routine. */ + if (nor->params->ready) + return nor->params->ready(nor); - if (nor->flags & SNOR_F_READY_XSR_RDY) - sr = spi_nor_xsr_ready(nor); - else - sr = spi_nor_sr_ready(nor); - if (sr < 0) - return sr; - fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1; - if (fsr < 0) - return fsr; - return sr && fsr; + return spi_nor_sr_ready(nor); } /** @@ -2532,11 +2313,12 @@ static int spi_nor_setup(struct spi_nor *nor, { int ret; - if (nor->params->setup) { + if (nor->params->setup) ret = nor->params->setup(nor, hwcaps); - if (ret) - return ret; - } + else + ret = spi_nor_default_setup(nor, hwcaps); + if (ret) + return ret; return spi_nor_set_addr_width(nor); } @@ -2666,20 +2448,6 @@ static void spi_nor_init_flags(struct spi_nor *nor) if (flags & NO_CHIP_ERASE) nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; - - if (flags & USE_CLSR) - nor->flags |= SNOR_F_USE_CLSR; - - if (flags & USE_FSR) - nor->flags |= SNOR_F_USE_FSR; - - /* - * Make sure the XSR_RDY flag is set before calling - * spi_nor_wait_till_ready(). Xilinx S3AN share MFR - * with Atmel SPI NOR. - */ - if (flags & SPI_NOR_XSR_RDY) - nor->flags |= SNOR_F_READY_XSR_RDY; } /** @@ -2786,7 +2554,6 @@ static void spi_nor_init_default_params(struct spi_nor *nor) params->quad_enable = spi_nor_sr2_bit1_quad_enable; params->set_4byte_addr_mode = spansion_set_4byte_addr_mode; - params->setup = spi_nor_default_setup; params->otp.org = &info->otp_org; /* Default to 16-bit Write Status (01h) Command */ @@ -3181,10 +2948,11 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor) mtd->flags = MTD_CAP_NORFLASH; if (nor->info->flags & SPI_NOR_NO_ERASE) mtd->flags |= MTD_NO_ERASE; + else + mtd->_erase = spi_nor_erase; mtd->writesize = nor->params->writesize; mtd->writebufsize = nor->params->page_size; mtd->size = nor->params->size; - mtd->_erase = spi_nor_erase; mtd->_read = spi_nor_read; /* Might be already set by some SST flashes. */ if (!mtd->_write) diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 2afb610853a9..b7fd760e3b47 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -12,23 +12,20 @@ #define SPI_NOR_MAX_ID_LEN 6 enum spi_nor_option_flags { - SNOR_F_USE_FSR = BIT(0), - SNOR_F_HAS_SR_TB = BIT(1), - SNOR_F_NO_OP_CHIP_ERASE = BIT(2), - SNOR_F_READY_XSR_RDY = BIT(3), - SNOR_F_USE_CLSR = BIT(4), - SNOR_F_BROKEN_RESET = BIT(5), - SNOR_F_4B_OPCODES = BIT(6), - SNOR_F_HAS_4BAIT = BIT(7), - SNOR_F_HAS_LOCK = BIT(8), - SNOR_F_HAS_16BIT_SR = BIT(9), - SNOR_F_NO_READ_CR = BIT(10), - SNOR_F_HAS_SR_TB_BIT6 = BIT(11), - SNOR_F_HAS_4BIT_BP = BIT(12), - SNOR_F_HAS_SR_BP3_BIT6 = BIT(13), - SNOR_F_IO_MODE |
