Messages in this thread Patch in this message | | | From | Cyrille Pitchen <> | Subject | [RFC PATCH v6 4/4] mtd: spi-nor: add spi_nor_init() function | Date | Sun, 16 Apr 2017 23:41:58 +0200 |
| |
This patch extracts some chunks from spi_nor_scan() and moves them into a new spi_nor_init() function.
Indeed, spi_nor_init() regroups all the required SPI flash commands to be sent to the SPI flash memory before performing any runtime operations (Fast Read, Page Program, Sector Erase, ...). Hence spi_nor_init(): 1) removes the flash protection if applicable for certain vendors. 2) sets the Quad Enable bit, if needed, before using Quad SPI protocols. 3) makes the memory enter its (stateful) 4-byte address mode, if needed, for SPI flash memory > 128Mbits not supporting the 4-byte address instruction set.
spi_nor_scan() now ends by calling spi_nor_init() once the probe phase has completed. Further patches could also use spi_nor_init() to implement the mtd->_resume() handler for the spi-nor framework.
Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> --- drivers/mtd/spi-nor/spi-nor.c | 71 ++++++++++++++++++++++++++++--------------- include/linux/mtd/spi-nor.h | 8 +++++ 2 files changed, 55 insertions(+), 24 deletions(-)
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 2377fe54f8b9..523fd9d85f57 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -255,6 +255,8 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode); nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode); nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode); + + nor->flags |= SNOR_F_4B_OPCODES; } /* Enable/disable 4-byte addressing mode. */ @@ -1836,6 +1838,45 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, return 0; } +static int spi_nor_init(struct spi_nor *nor) +{ + const struct flash_info *info = nor->info; + struct device *dev = nor->dev; + int ret; + + /* + * 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 || + info->flags & SPI_NOR_HAS_LOCK) { + write_enable(nor); + write_sr(nor, 0); + spi_nor_wait_till_ready(nor); + } + + /* Set the Quad Enable bit, if needed. */ + if (nor->flash_quad_enable) { + ret = nor->flash_quad_enable(nor); + if (ret) { + dev_err(dev, "quad mode not supported\n"); + return ret; + } + } + + /* + * For SPI flash memories above 128Mib, enter the 4-byte address mode + * only if the 4-byte address instruction set is not supported. + */ + if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES)) + set_4byte(nor, info, 1); + + return 0; +} + int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps) { @@ -1903,20 +1944,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (ret) return ret; - /* - * 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 || - info->flags & SPI_NOR_HAS_LOCK) { - write_enable(nor); - write_sr(nor, 0); - spi_nor_wait_till_ready(nor); - } - if (!mtd->name) mtd->name = dev_name(dev); mtd->priv = nor; @@ -1987,14 +2014,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (ret) return ret; - if (nor->flash_quad_enable) { - ret = nor->flash_quad_enable(nor); - if (ret) { - dev_err(dev, "quad mode not supported\n"); - return ret; - } - } - if (info->addr_width) nor->addr_width = info->addr_width; else if (mtd->size > 0x1000000) { @@ -2003,8 +2022,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || info->flags & SPI_NOR_4B_OPCODES) spi_nor_set_4byte_opcodes(nor, info); - else - set_4byte(nor, info, 1); } else { nor->addr_width = 3; } @@ -2021,6 +2038,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, return ret; } + /* Send all the required SPI flash commands to initialize the memory. */ + nor->info = info; + ret = spi_nor_init(nor); + if (ret) + return ret; + dev_info(dev, "%s (%lld Kbytes)\n", info->name, (long long)mtd->size >> 10); diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index e0c58d9d9286..618ecac9337a 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -214,9 +214,16 @@ enum spi_nor_option_flags { SNOR_F_NO_OP_CHIP_ERASE = BIT(2), SNOR_F_S3AN_ADDR_DEFAULT = BIT(3), SNOR_F_READY_XSR_RDY = BIT(4), + SNOR_F_4B_OPCODES = BIT(5), }; /** + * struct flash_info - Forward declaration of a structure used internally by + * spi_nor_scan() and spi_nor_init(). + */ +struct flash_info; + +/** * struct spi_nor - Structure for defining a the SPI NOR layer * @mtd: point to a mtd_info structure * @lock: the lock for the read/write/erase/lock/unlock operations @@ -255,6 +262,7 @@ struct spi_nor { struct mtd_info mtd; struct mutex lock; struct device *dev; + const struct flash_info *info; u32 page_size; u8 addr_width; u8 erase_opcode; -- 2.9.3
| |