Add spi-nor flash device pm support
Subsystems (2)
v8 cover Add spi-nor flash device pm support
Changes since v7
spi-nor.h
- Fix comment style
spi-nor.c
- Fix condition check to set_4byte() when nor->addr_width == 4 in spi_nor_init()
- Bring back quad_enable logic to spi_nor_setup() and remove it from spi_nor_scan()
- Remove duplicate comment section in spi_nor_scan()
- Leave dev_info() string as before in spi_nor_scan()
The V8 changes below implements power management support using the mtd handlers for resume in the spi-nor driver. spi-nor mtd pm resume() calls newly implemented spi_nor_init() function that sets up the spi-nor flash to its pre-suspend/power-on probed state. This is needed S2/S3 PM on platfroms that turn off power to the spi-nor flash on pm suspend.
Kamal Dasu (2):
mtd: spi-nor: add spi_nor_init() function
mtd: spi-nor: Add spi-nor mtd resume handler
drivers/mtd/spi-nor/spi-nor.c | 68 +++++++++++++++++++++++++++++++------------ include/linux/mtd/spi-nor.h | 10 +++++++ 2 files changed, 60 insertions(+), 18 deletions(-)
Signature · 1 line
1.9.1
PATCH v8 1/2 mtd: spi-nor: add spi_nor_init() function
This patch extracts some chunks from spi_nor_init_params and 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.
--- drivers/mtd/spi-nor/spi-nor.c | 54 ++++++++++++++++++++++++++++--------------- include/linux/mtd/spi-nor.h | 10 ++++++++ 2 files changed, 46 insertions(+), 18 deletions(-)
drivers/mtd/spi-nor/spi-nor.c +36 -18
@@ -1832,14 +1832,42 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,/* Enable Quad I/O if needed. */ enable_quad_io = (spi_nor_get_protocol_width (nor->read_proto) ==4 ||spi_nor_get_protocol_width (nor->write_proto) ==4 ); -if (enable_quad_io && params->quad_enable) { - err = params->quad_enable (nor); +if (enable_quad_io && params->quad_enable) + nor->quad_enable = params->quad_enable; + +return 0 ; +} + +static int spi_nor_init (struct spi_nor *nor) +{ +int err; + +/* +* Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up +* with the software protection bits set +*/ +if (JEDEC_MFR (nor->info) ==SNOR_MFR_ATMEL || +JEDEC_MFR (nor->info) ==SNOR_MFR_INTEL || +JEDEC_MFR (nor->info) ==SNOR_MFR_SST || + nor->info->flags &SPI_NOR_HAS_LOCK ) { +write_enable (nor); +write_sr (nor,0 ); +spi_nor_wait_till_ready (nor); + } + +if (nor->quad_enable) { + err = nor->quad_enable (nor);if (err) {dev_err (nor->dev,"quad mode not supported\n" );return err; } } +if ((nor->addr_width ==4 ) && + (JEDEC_MFR (nor->info) !=SNOR_MFR_SPANSION ) && + !(nor->info->flags &SPI_NOR_4B_OPCODES )) +set_4byte (nor, nor->info,1 ); +return 0 ; }
@@ -1910,20 +1938,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;
@@ -2002,8 +2016,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 ; }
@@ -2020,6 +2032,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,return ret; } +/* Send all the required SPI flash commands to initialize device */ + 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 );
include/linux/mtd/spi-nor.h +10 -0
@@ -221,10 +221,17 @@ enum spi_nor_option_flags { };/** +* struct flash_info - Forward declaration of a structure used internally by +* spi_nor_scan() +*/ +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 * @dev: point to a spi device, or a spi nor controller device. +* @info: spi-nor part JDEC MFR id and other info * @page_size: the page size of the SPI NOR * @addr_width: number of address bytes * @erase_opcode: the opcode for erasing a sector
@@ -251,6 +258,7 @@ enum spi_nor_option_flags {* @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is +* @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode * completely locked * @priv: the private data */
@@ -258,6 +266,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;
@@ -285,6 +294,7 @@ struct spi_nor {int (*flash_lock)(struct spi_nor *nor,loff_t ofs,uint64_t len);int (*flash_unlock)(struct spi_nor *nor,loff_t ofs,uint64_t len);int (*flash_is_locked)(struct spi_nor *nor,loff_t ofs,uint64_t len); +int (*quad_enable)(struct spi_nor *nor);void *priv; };
Signature · 1 line
1.9.1
Cyrille Pitchen
AppliedRe: [PATCH v8 1/2] mtd: spi-nor: add spi_nor_init() function
Le 22/08/2017 à 22:45, Kamal Dasu a écrit :
Quoted 12 lines
This patch extracts some chunks from
spi_nor_init_paramsandspi_nor_scan()
and moves them into a newspi_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, ...). Hencespi_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.
Quoted 5 lines
spi_nor_scan()now ends by callingspi_nor_init()once the probe phase has completed. Further patches could also usespi_nor_init()to implement themtd->_resume()handler for the spi-nor framework.Signed-off-by Kamal Dasu <[email protected]>
Applied to the spi-nor/next branch of l2-mtd with a tiny change below
Thanks!
Quoted 10 lines
--- drivers/mtd/spi-nor/spi-nor.c | 54 ++++++++++++++++++++++++++++--------------- include/linux/mtd/spi-nor.h | 10 ++++++++ 2 files changed, 46 insertions(+), 18 deletions(-)drivers/mtd/spi-nor/spi-nor.c +0
-0
drivers/mtd/spi-nor/spi-nor.c static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, · line 1836
Quoted 7 lines
drivers/mtd/spi-nor/spi-nor.c +2
-2@@ -1832,14 +1832,42 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,/* Enable Quad I/O if needed. */ enable_quad_io = (spi_nor_get_protocol_width (nor->read_proto) ==4 ||spi_nor_get_protocol_width (nor->write_proto) ==4 ); -if (enable_quad_io && params->quad_enable) { - err = params->quad_enable (nor); +if (enable_quad_io && params->quad_enable) + nor->quad_enable = params->quad_enable;
+ else
+ nor->quad_enable = NULL;
hence nor->quad_enable is always initialized.
Quoted 127 lines
drivers/mtd/spi-nor/spi-nor.c +34
-16+ +return 0 ; +} + +static int spi_nor_init (struct spi_nor *nor) +{ +int err; + +/* +* Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up +* with the software protection bits set +*/ +if (JEDEC_MFR (nor->info) ==SNOR_MFR_ATMEL || +JEDEC_MFR (nor->info) ==SNOR_MFR_INTEL || +JEDEC_MFR (nor->info) ==SNOR_MFR_SST || + nor->info->flags &SPI_NOR_HAS_LOCK ) { +write_enable (nor); +write_sr (nor,0 ); +spi_nor_wait_till_ready (nor); + } + +if (nor->quad_enable) { + err = nor->quad_enable (nor);if (err) {dev_err (nor->dev,"quad mode not supported\n" );return err; } } +if ((nor->addr_width ==4 ) && + (JEDEC_MFR (nor->info) !=SNOR_MFR_SPANSION ) && + !(nor->info->flags &SPI_NOR_4B_OPCODES )) +set_4byte (nor, nor->info,1 ); +return 0 ; }@@ -1910,20 +1938,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;@@ -2002,8 +2016,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 ; }@@ -2020,6 +2032,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,return ret; } +/* Send all the required SPI flash commands to initialize device */ + 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 );include/linux/mtd/spi-nor.h +10
-0@@ -221,10 +221,17 @@ enum spi_nor_option_flags { };/** +* struct flash_info - Forward declaration of a structure used internally by +* spi_nor_scan() +*/ +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 * @dev: point to a spi device, or a spi nor controller device. +* @info: spi-nor part JDEC MFR id and other info * @page_size: the page size of the SPI NOR * @addr_width: number of address bytes * @erase_opcode: the opcode for erasing a sector @@ -251,6 +258,7 @@ enum spi_nor_option_flags {* @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is +* @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode * completely locked * @priv: the private data */ @@ -258,6 +266,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;@@ -285,6 +294,7 @@ struct spi_nor {int (*flash_lock)(struct spi_nor *nor,loff_t ofs,uint64_t len);int (*flash_unlock)(struct spi_nor *nor,loff_t ofs,uint64_t len);int (*flash_is_locked)(struct spi_nor *nor,loff_t ofs,uint64_t len); +int (*quad_enable)(struct spi_nor *nor);void *priv; };
PATCH v8 2/2 mtd: spi-nor: Add spi-nor mtd resume handler
In reply to Kamal DasuImplemented and populated spi-nor mtd PM handlers for resume ops. spi-nor resume op re-initializes spi-nor flash to its probed state by calling the newly implemented spi_nor_init() function.
--- drivers/mtd/spi-nor/spi-nor.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/mtd/spi-nor/spi-nor.c +14 -0
@@ -1871,6 +1871,19 @@ static int spi_nor_init(struct spi_nor *nor)return 0 ; } +/* mtd resume handler */ +static void spi_nor_resume (struct mtd_info *mtd) +{ +struct spi_nor *nor =mtd_to_spi_nor (mtd); +struct device *dev = nor->dev; +int ret; + +/* re-initialize the nor chip */ + ret =spi_nor_init (nor); +if (ret) +dev_err (dev,"resume() failed\n" ); +} +int spi_nor_scan (struct spi_nor *nor,const char *name,const struct spi_nor_hwcaps *hwcaps) {
@@ -1947,6 +1960,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, mtd->size = params.size; mtd->_erase = spi_nor_erase; mtd->_read = spi_nor_read; + mtd->_resume = spi_nor_resume;/* NOR protection support for STmicro/Micron chips and similar */ if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
Signature · 1 line
1.9.1
Re: [PATCH v8 2/2] mtd: spi-nor: Add spi-nor mtd resume handler
Hi Kamal,
Quoted 34 lines · Kamal Dasu
Implemented and populated spi-nor mtd PM handlers for resume ops. spi-nor resume op re-initializes spi-nor flash to its probed state by calling the newly implemented
spi_nor_init()function.Signed-off-by Kamal Dasu <[email protected]>--- drivers/mtd/spi-nor/spi-nor.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)drivers/mtd/spi-nor/spi-nor.c +13
-0@@ -1871,6 +1871,19 @@ static int spi_nor_init(struct spi_nor *nor)return 0 ; } +/* mtd resume handler */ +static void spi_nor_resume (struct mtd_info *mtd) +{ +struct spi_nor *nor =mtd_to_spi_nor (mtd); +struct device *dev = nor->dev; +int ret; + +/* re-initialize the nor chip */ + ret =spi_nor_init (nor); +if (ret) +dev_err (dev,"resume() failed\n" ); +} +int spi_nor_scan (struct spi_nor *nor,const char *name,const struct spi_nor_hwcaps *hwcaps) {
drivers/mtd/spi-nor/spi-nor.c int spi_nor_scan(struct spi_nor *nor, const char *name, · line 1964
Quoted 5 lines
drivers/mtd/spi-nor/spi-nor.c +1
-0@@ -1947,6 +1960,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, mtd->size = params.size; mtd->_erase = spi_nor_erase; mtd->_read = spi_nor_read; + mtd->_resume = spi_nor_resume;
The series now looks good to me. Just waiting for Marek's acked-by/reviewed-by to double-check.
Marek: I can't test with the Cadence QSPI controller but based on the line "mtd->dev.parent = nor->dev;" in spi_nor_scan(), I think this patch won't conflit with the already PM code in the cadence-quadspi.c driver.
As far as I understand, cqspi_resume() will be called before mtd_resume() / spi_nor_resume().
Best regards,
Cyrille
Quoted 3 lines
drivers/mtd/spi-nor/spi-nor.c +0
-0/* NOR protection support for STmicro/Micron chips and similar */ if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
Cyrille Pitchen
AppliedRe: [PATCH v8 2/2] mtd: spi-nor: Add spi-nor mtd resume handler
In reply to Kamal DasuLe 22/08/2017 à 22:45, Kamal Dasu a écrit :
Quoted 5 lines
Implemented and populated spi-nor mtd PM handlers for resume ops. spi-nor resume op re-initializes spi-nor flash to its probed state by calling the newly implemented
spi_nor_init()function.Signed-off-by Kamal Dasu <[email protected]>
Applied to the spi-nor/next branch of l2-mtd
Thanks!
Quoted 37 lines
--- drivers/mtd/spi-nor/spi-nor.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)drivers/mtd/spi-nor/spi-nor.c +14
-0@@ -1871,6 +1871,19 @@ static int spi_nor_init(struct spi_nor *nor)return 0 ; } +/* mtd resume handler */ +static void spi_nor_resume (struct mtd_info *mtd) +{ +struct spi_nor *nor =mtd_to_spi_nor (mtd); +struct device *dev = nor->dev; +int ret; + +/* re-initialize the nor chip */ + ret =spi_nor_init (nor); +if (ret) +dev_err (dev,"resume() failed\n" ); +} +int spi_nor_scan (struct spi_nor *nor,const char *name,const struct spi_nor_hwcaps *hwcaps) {@@ -1947,6 +1960,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, mtd->size = params.size; mtd->_erase = spi_nor_erase; mtd->_read = spi_nor_read; + mtd->_resume = spi_nor_resume;/* NOR protection support for STmicro/Micron chips and similar */ if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||