mtd: spi-nor: add a new framework for SPI NOR
Subsystems (5)
v5 cover mtd: spi-nor: add a new framework for SPI NOR
1.) Why add a new framework for SPI NOR?
The SPI-NOR controller such as Freescale's Quadspi controller is working in a different way from the SPI bus. It should knows the NOR commands to find the right LUT sequence. Unfortunately, the current code can not meet this requirement.
2.) How does this patch set do?
This patch set adds a new spi-nor layer.
Before this patch, the layer is like:
MTD
------------------------
m25p80
------------------------
spi bus driver
------------------------
SPI NOR chipAfter this patch, the layer is like:
MTD
------------------------
spi-nor
------------------------
m25p80
------------------------
spi bus driver
------------------------
SPI NOR chipWith the spi-nor controller driver(Freescale Quadspi), it looks like:
MTD
------------------------
spi-nor
------------------------
fsl-quadspi
------------------------
SPI NOR chip3.) more details
This patch set adds a new data structrue spi_nor{}, clones most the common
code to spi-nor.c. Add spi_nor_xfer_cfg {} for the fundamental primitives:
read_xfer/write_xfer.
Make the m25p80.c/fsl_quaspi.c use the new APIs.
4.) Change log:
v4 --> v5:
[1] rebase the patch set on the l2-mtd tree.
[2] fixed bugs in the fsl-quadspi driver.
[3] tested the fsl-quadspi with imx6sx board.
v3 --> v4:
[1] move the wait_till_ready to the @read hook.
[2] convert to linux-doc style comment.
[3] remove the some DT property for QuadSPI driver, such as "fsl,nor-size".
[4] others
v2 --> v3:
[1] add prepare/unprepare hooks for spi_nor{}.
[2] add a new "priv" field for spi_nor{}.
[3] add the Freescale Quadspi driver which supports the Quad read by default.
v1 --> v2:
[1] follow Angus's advice, add more hooks and data structrures. [2] others.
*** BLURB HERE ***
Huang Shijie (8):
mtd: spi-nor: copy the SPI NOR commands to a new header file
mtd: spi-nor: add the basic data structures
mtd: spi-nor: add the framework for SPI NOR
Documentation: add the document for the SPI NOR framework
mtd: m25p80: use the SPI nor framework
mtd: spi-nor: add a helper to find the spi_device_id
Documentation: add the binding file for Freescale QuadSPI driver
mtd: spi-nor: Add Freescale QuadSPI driver
.../devicetree/bindings/mtd/fsl-quadspi.txt | 35 + Documentation/mtd/spi-nor.txt | 59 + drivers/mtd/Kconfig | 2 + drivers/mtd/Makefile | 1 + drivers/mtd/devices/m25p80.c | 1302 ++------------------ drivers/mtd/spi-nor/Kconfig | 12 + drivers/mtd/spi-nor/Makefile | 2 + drivers/mtd/spi-nor/fsl-quadspi.c | 1009 +++++++++++++++ drivers/mtd/spi-nor/spi-nor.c | 1099 +++++++++++++++++ include/linux/mtd/spi-nor.h | 197 +++ 10 files changed, 2521 insertions(+), 1197 deletions(-) create mode 100644 Documentation/devicetree/bindings/mtd/fsl-quadspi.txt create mode 100644 Documentation/mtd/spi-nor.txt create mode 100644 drivers/mtd/spi-nor/Kconfig create mode 100644 drivers/mtd/spi-nor/Makefile create mode 100644 drivers/mtd/spi-nor/fsl-quadspi.c create mode 100644 drivers/mtd/spi-nor/spi-nor.c create mode 100644 include/linux/mtd/spi-nor.h
Signature · 1 line
1.7.2.rc3
PATCH v5 1/8 mtd: spi-nor: copy the SPI NOR commands to a new header file
This patch adds a new header :spi-nor.h,
and copies all the SPI NOR commands and relative macros into this new header.
This hearder can be used by the m25p80.c and other spi-nor controller, such as Freescale's Quadspi.
--- include/linux/mtd/spi-nor.h | 55 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 55 insertions(+), 0 deletions(-) create mode 100644 include/linux/mtd/spi-nor.h
include/linux/mtd/spi-nor.h new file +55 -0
@@ -0,0 +1,55 @@ +#ifndef __LINUX_MTD_SPI_NOR_H +#define __LINUX_MTD_SPI_NOR_H + +/* Flash opcodes. */ +#define OPCODE_WREN 0x06/* Write enable */ +#define OPCODE_RDSR 0x05/* Read status register */ +#define OPCODE_WRSR 0x01/* Write status register 1 byte */ +#define OPCODE_NORM_READ 0x03/* Read data bytes (low frequency) */ +#define OPCODE_FAST_READ 0x0b/* Read data bytes (high frequency) */ +#define OPCODE_DUAL_READ 0x3b/* Read data bytes (Dual SPI) */ +#define OPCODE_QUAD_READ 0x6b/* Read data bytes (Quad SPI) */ +#define OPCODE_PP 0x02/* Page program (up to 256 bytes) */ +#define OPCODE_BE_4K 0x20/* Erase 4KiB block */ +#define OPCODE_BE_4K_PMC 0xd7/* Erase 4KiB block on PMC chips */ +#define OPCODE_BE_32K 0x52/* Erase 32KiB block */ +#define OPCODE_CHIP_ERASE 0xc7/* Erase whole flash chip */ +#define OPCODE_SE 0xd8/* Sector erase (usually 64KiB) */ +#define OPCODE_RDID 0x9f/* Read JEDEC ID */ +#define OPCODE_RDCR 0x35/* Read configuration register */ + +/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ +#define OPCODE_NORM_READ_4B 0x13/* Read data bytes (low frequency) */ +#define OPCODE_FAST_READ_4B 0x0c/* Read data bytes (high frequency) */ +#define OPCODE_DUAL_READ_4B 0x3c/* Read data bytes (Dual SPI) */ +#define OPCODE_QUAD_READ_4B 0x6c/* Read data bytes (Quad SPI) */ +#define OPCODE_PP_4B 0x12/* Page program (up to 256 bytes) */ +#define OPCODE_SE_4B 0xdc/* Sector erase (usually 64KiB) */ + +/* Used for SST flashes only. */ +#define OPCODE_BP 0x02/* Byte program */ +#define OPCODE_WRDI 0x04/* Write disable */ +#define OPCODE_AAI_WP 0xad/* Auto address increment word program */ + +/* Used for Macronix and Winbond flashes. */ +#define OPCODE_EN4B 0xb7/* Enter 4-byte mode */ +#define OPCODE_EX4B 0xe9/* Exit 4-byte mode */ + +/* Used for Spansion flashes only. */ +#define OPCODE_BRWR 0x17/* Bank register write */ + +/* Status Register bits. */ +#define SR_WIP 1/* Write in progress */ +#define SR_WEL 2/* Write enable latch */ +/* meaning of other SR_* bits may differ between vendors */ +#define SR_BP0 4/* Block protect 0 */ +#define SR_BP1 8/* Block protect 1 */ +#define SR_BP2 0x10/* Block protect 2 */ +#define SR_SRWD 0x80/* SR write protect */ + +#define SR_QUAD_EN_MX 0x40/* Macronix Quad I/O */ + +/* Configuration Register bits. */ +#define CR_QUAD_EN_SPAN 0x2/* Spansion Quad I/O */ + +#endif
Signature · 1 line
1.7.2.rc3
PATCH v5 1/8 mtd: spi-nor: copy the SPI NOR commands to a new header file
Quoted 8 lines · Huang Shijie
This patch adds a new header :spi-nor.h,
and copies all the SPI NOR commands and relative macros into this new header.This hearder can be used by the
m25p80.cand other spi-nor controller, such as Freescale's Quadspi.Signed-off-by Huang Shijie <[email protected]>
Please keep me on CC ;-)
I honestly have to wonder ... why do you not 'move' these definitions instead of copying them ?
Best regards,
Marek Vasut
PATCH v5 1/8 mtd: spi-nor: copy the SPI NOR commands to a new header file
? 2014?03?05? 06:13, Marek Vasut ??:
Quoted 1 line
Please keep me on CC;-)
sorry, My fault :(
Quoted 3 lines
I honestly have to wonder ... why do you not 'move' these definitions instead of copying them ?
In the first version , i did so:
http://marc.info/?l=linux-arm-kernel&m=138544933522564&w=2
if I need to resend the patch set again, i can change to move the commands to the new header.
thanks
Huang Shijie
PATCH v5 1/8 mtd: spi-nor: copy the SPI NOR commands to a new header file
Quoted 5 lines · Huang Shijie
? 2014?03?05? 06:13, Marek Vasut ??:
Quoted 1 line
Please keep me on CC;-)
sorry, My fault :(
Quoted 8 lines
Quoted 2 lines
I honestly have to wonder ... why do you not 'move' these definitions instead of copying them ?
In the first version , i did so:
http://marc.info/?l=linux-arm-kernel&m=138544933522564&w=2if I need to resend the patch set again, i can change to move the commands to the new header.
Why didn't you keep it like that? Was there some reason for that ?
Best regards,
Marek Vasut
PATCH v5 1/8 mtd: spi-nor: copy the SPI NOR commands to a new header file
? 2014?03?05? 11:43, Marek Vasut ??:
Quoted 1 line
Why didn't you keep it like that? Was there some reason for that ?
http://marc.info/?l=linux-arm-kernel&m=138545182232220&w=4
Pekon suggestted do not touch the m25p80.c. So i just copy these commands to a new header. Anyway, it's really not an important issue for me. :)
thanks
Huang Shijie
PATCH v5 1/8 mtd: spi-nor: copy the SPI NOR commands to a new header file
Hi Marek, Shijie,
Quoted 10 lines
From: Huang Shijie [mailto:b32955 at freescale.com]
? 2014?03?05? 11:43, Marek Vasut ??:
Quoted 1 line
Why didn't you keep it like that? Was there some reason for that ?
http://marc.info/?l=linux-arm-kernel&m=138545182232220&w=4
Pekon suggestted do not touch the
m25p80.c. So i just copy these commands to a new header. Anyway, it's really not an important issue for me. :)
My opinion was that we should not touch m25p80.c because:
(1) As m25p80 is already working for various vendors. So unless multiple platforms start using SPI NOR framework, m25p80.c should remain untouched.
(2) we should not clutter header file with vendor specific op-codes as used in m25p80. I was of the opinion that instead of hard-coding the vendor specific info as MACROs, such information should be taken from DT or platform-data.
However, this was my thought during initial versions of SPI NOR patches. But now if you think that SPI NOR is stable enough that same header info can be reused without conflicts, then no problems.
(Apologies to Huang Shijie for re-work :-) ).
with regards, pekon
PATCH v5 1/8 mtd: spi-nor: copy the SPI NOR commands to a new header file
Quoted 21 lines · Pekon
Hi Marek, Shijie,
Quoted 10 lines
From: Huang Shijie [mailto:b32955 at freescale.com]
? 2014?03?05? 11:43, Marek Vasut ??:
Quoted 1 line
Why didn't you keep it like that? Was there some reason for that ?
http://marc.info/?l=linux-arm-kernel&m=138545182232220&w=4
Pekon suggestted do not touch the
m25p80.c. So i just copy these commands to a new header. Anyway, it's really not an important issue for me. :)My opinion was that we should not touch
m25p80.cbecause:
(1) As m25p80 is already working for various vendors. So unless multiple platforms start using SPI NOR framework,m25p80.cshould remain
untouched. (2) we should not clutter header file with vendor specific op-codes as used in m25p80. I was of the opinion that instead of hard-coding the vendor specific info as MACROs, such information should be taken from DT or platform-data.
Quoted 5 lines
However, this was my thought during initial versions of SPI NOR patches. But now if you think that SPI NOR is stable enough that same header info can be reused without conflicts, then no problems.
(Apologies to Huang Shijie for re-work :-) ).
Ah, thanks for explaining, understood. Given that the m25p80.c is reworked later in the series anyway, I'm mostly OK with this patch ... even though I'd prefer to see no duplication throughout the series ;-)
Best regards,
Marek Vasut
PATCH v5 1/8 mtd: spi-nor: copy the SPI NOR commands to a new header file
In reply to Huang ShijieQuoted 2 lines · Huang Shijie
This patch adds a new header :spi-nor.h,
and copies all the SPI NOR commands and relative macros into this new header.
...
include/linux/mtd/spi-nor.h line 3
Quoted 9 lines
include/linux/mtd/spi-nor.h new file +3
-0@@ -0,0 +1,55 @@ +#ifndef __LINUX_MTD_SPI_NOR_H +#define __LINUX_MTD_SPI_NOR_H +
You're missing a copyright and license header. Please submit one against l2-mtd.git/spinor, preferably after the patch series I just sent out that renames a few things here.
Regarding copyright assignments (also an issue with spi-nor.c): please carry the original copyright from m25p80.c, and add your own or your employer's wherever your work was a significant addition.
Quoted 42 lines
include/linux/mtd/spi-nor.h new file +42
-0+/* Flash opcodes. */ +#define OPCODE_WREN 0x06/* Write enable */ +#define OPCODE_RDSR 0x05/* Read status register */ +#define OPCODE_WRSR 0x01/* Write status register 1 byte */ +#define OPCODE_NORM_READ 0x03/* Read data bytes (low frequency) */ +#define OPCODE_FAST_READ 0x0b/* Read data bytes (high frequency) */ +#define OPCODE_DUAL_READ 0x3b/* Read data bytes (Dual SPI) */ +#define OPCODE_QUAD_READ 0x6b/* Read data bytes (Quad SPI) */ +#define OPCODE_PP 0x02/* Page program (up to 256 bytes) */ +#define OPCODE_BE_4K 0x20/* Erase 4KiB block */ +#define OPCODE_BE_4K_PMC 0xd7/* Erase 4KiB block on PMC chips */ +#define OPCODE_BE_32K 0x52/* Erase 32KiB block */ +#define OPCODE_CHIP_ERASE 0xc7/* Erase whole flash chip */ +#define OPCODE_SE 0xd8/* Sector erase (usually 64KiB) */ +#define OPCODE_RDID 0x9f/* Read JEDEC ID */ +#define OPCODE_RDCR 0x35/* Read configuration register */ + +/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ +#define OPCODE_NORM_READ_4B 0x13/* Read data bytes (low frequency) */ +#define OPCODE_FAST_READ_4B 0x0c/* Read data bytes (high frequency) */ +#define OPCODE_DUAL_READ_4B 0x3c/* Read data bytes (Dual SPI) */ +#define OPCODE_QUAD_READ_4B 0x6c/* Read data bytes (Quad SPI) */ +#define OPCODE_PP_4B 0x12/* Page program (up to 256 bytes) */ +#define OPCODE_SE_4B 0xdc/* Sector erase (usually 64KiB) */ + +/* Used for SST flashes only. */ +#define OPCODE_BP 0x02/* Byte program */ +#define OPCODE_WRDI 0x04/* Write disable */ +#define OPCODE_AAI_WP 0xad/* Auto address increment word program */ + +/* Used for Macronix and Winbond flashes. */ +#define OPCODE_EN4B 0xb7/* Enter 4-byte mode */ +#define OPCODE_EX4B 0xe9/* Exit 4-byte mode */ + +/* Used for Spansion flashes only. */ +#define OPCODE_BRWR 0x17/* Bank register write */ + +/* Status Register bits. */ +#define SR_WIP 1/* Write in progress */ +#define SR_WEL 2/* Write enable latch */ +/* meaning of other SR_* bits may differ between vendors */ +#define SR_BP0 4/* Block protect 0 */
include/linux/mtd/spi-nor.h line 55
Quoted 10 lines
include/linux/mtd/spi-nor.h new file +10
-0+#define SR_BP1 8/* Block protect 1 */ +#define SR_BP2 0x10/* Block protect 2 */ +#define SR_SRWD 0x80/* SR write protect */ + +#define SR_QUAD_EN_MX 0x40/* Macronix Quad I/O */ + +/* Configuration Register bits. */ +#define CR_QUAD_EN_SPAN 0x2/* Spansion Quad I/O */ + +#endif
Brian
PATCH v5 2/8 mtd: spi-nor: add the basic data structures
In reply to Huang ShijieThe spi_nor{} is cloned from the m25p{}.
The spi_nor{} can be used by both the m25p80 and spi-nor controller.
We also add the spi_nor_xfer_cfg{} which can be used by the two fundamental primitives: read_xfer/write_xfer.
1) the hooks for spi_nor{}:
@prepare/unpreare: used to do some work before or after the
read/write/erase/lock/unlock.
@read_xfer/write_xfer: We can use these two hooks to code all
the following hooks if the driver tries to implement them by itself.
@read_reg: used to read the registers, such as read status register,
read configure register.
@write_reg: used to write the registers, such as write enable,
erase sector.
@read_id: read out the ID info.
@wait_till_ready: wait till the NOR becomes ready. @read: read out the data from the NOR.
@write: write data to the NOR.
@erase: erase a sector of the NOR.
2) Add a new field sst_write_second for the SST NOR write.
--- include/linux/mtd/spi-nor.h | 110 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 110 insertions(+), 0 deletions(-)
include/linux/mtd/spi-nor.h +110 -0
@@ -52,4 +52,114 @@/* Configuration Register bits. */ #define CR_QUAD_EN_SPAN 0x2/* Spansion Quad I/O */ +enum read_mode { +SPI_NOR_NORMAL =0 , +SPI_NOR_FAST , +SPI_NOR_DUAL , +SPI_NOR_QUAD , +}; + +/** +* struct spi_nor_xfer_cfg - Structure for defining a Serial Flash transfer +* @wren: command for "Write Enable", or 0x00 for not required +* @cmd: command for operation +* @cmd_pins: number of pins to send @cmd (1, 2, 4) +* @addr: address for operation +* @addr_pins: number of pins to send @addr (1, 2, 4) +* @addr_width: number of address bytes +* (3,4, or 0 for address not required) +* @mode: mode data +* @mode_pins: number of pins to send @mode (1, 2, 4) +* @mode_cycles: number of mode cycles (0 for mode not required) +* @dummy_cycles: number of dummy cycles (0 for dummy not required) +*/ +struct spi_nor_xfer_cfg { +u8 wren; +u8 cmd; +u8 cmd_pins; +u32 addr; +u8 addr_pins; +u8 addr_width; +u8 mode; +u8 mode_pins; +u8 mode_cycles; +u8 dummy_cycles; +}; + +#define SPI_NOR_MAX_CMD_SIZE 8 +enum spi_nor_ops { +SPI_NOR_OPS_READ =0 , +SPI_NOR_OPS_WRITE , +SPI_NOR_OPS_ERASE , +SPI_NOR_OPS_LOCK , +SPI_NOR_OPS_UNLOCK , +}; + +/** +* 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. +* @page_size: the page size of the SPI NOR +* @addr_width: number of address bytes +* @erase_opcode: the opcode for erasing a sector +* @read_opcode: the read opcode +* @read_dummy: the dummy needed by the read operation +* @program_opcode: the program opcode +* @flash_read: the mode of the read +* @sst_write_second: used by the SST write operation +* @cfg: used by the read_xfer/write_xfer +* @cmd_buf: used by the write_reg +* @prepare: [OPTIONAL] do some preparations for the +* read/write/erase/lock/unlock operations +* @unprepare: [OPTIONAL] do some post work after the +* read/write/erase/lock/unlock operations +* @read_xfer: [OPTIONAL] the read fundamental primitive +* @write_xfer: [OPTIONAL] the writefundamental primitive +* @read_reg: [DRIVER-SPECIFIC] read out the register +* @write_reg: [DRIVER-SPECIFIC] write data to the register +* @read_id: [REPLACEABLE] read out the ID data, and find +* the proper spi_device_id +* @wait_till_ready: [REPLACEABLE] wait till the NOR becomes ready +* @read: [DRIVER-SPECIFIC] read data from the SPI NOR +* @write: [DRIVER-SPECIFIC] write data to the SPI NOR +* @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR +* at the offset @offs +* @priv: the private data +*/ +struct spi_nor { +struct mtd_info *mtd; +struct mutex lock; +struct device *dev; +u32 page_size; +u8 addr_width; +u8 erase_opcode; +u8 read_opcode; +u8 read_dummy; +u8 program_opcode; +enum read_mode flash_read; +bool sst_write_second; +struct spi_nor_xfer_cfg cfg; +u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE ]; + +int (*prepare)(struct spi_nor *nor,enum spi_nor_ops ops); +void (*unprepare)(struct spi_nor *nor,enum spi_nor_ops ops); +int (*read_xfer)(struct spi_nor *nor,struct spi_nor_xfer_cfg *cfg, +u8 *buf,size_t len); +int (*write_xfer)(struct spi_nor *nor,struct spi_nor_xfer_cfg *cfg, +u8 *buf,size_t len); +int (*read_reg)(struct spi_nor *nor,u8 opcode,u8 *buf,int len); +int (*write_reg)(struct spi_nor *nor,u8 opcode,u8 *buf,int len, +int write_enable); +const struct spi_device_id *(*read_id)(struct spi_nor *nor); +int (*wait_till_ready)(struct spi_nor *nor); + +int (*read)(struct spi_nor *nor,loff_t from, +size_t len,size_t *retlen,u_char *read_buf); +void (*write)(struct spi_nor *nor,loff_t to, +size_t len,size_t *retlen,const u_char *write_buf); +int (*erase)(struct spi_nor *nor,loff_t offs); + +void *priv; +};#endif
Signature · 1 line
1.7.2.rc3
PATCH v5 3/8 mtd: spi-nor: add the framework for SPI NOR
In reply to Huang ShijieThis patch cloned most of the m25p80.c. In theory, it adds a new spi-nor layer.
Before this patch, the layer is like:
MTD
------------------------
m25p80
------------------------
spi bus driver
------------------------
SPI NOR chipAfter this patch, the layer is like:
MTD
------------------------
spi-nor
------------------------
m25p80
------------------------
spi bus driver
------------------------
SPI NOR chipWith the spi-nor controller driver(Freescale Quadspi), it looks like:
MTD
------------------------
spi-nor
------------------------
fsl-quadspi
------------------------
SPI NOR chipNew APIs:
spi_nor_scan: used to scan a spi-nor flash.
--- drivers/mtd/Kconfig | 2 + drivers/mtd/Makefile | 1 + drivers/mtd/spi-nor/Kconfig | 6 + drivers/mtd/spi-nor/Makefile | 1 + drivers/mtd/spi-nor/spi-nor.c | 1087 +++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/spi-nor.h | 20 + 6 files changed, 1117 insertions(+), 0 deletions(-) create mode 100644 drivers/mtd/spi-nor/Kconfig create mode 100644 drivers/mtd/spi-nor/Makefile create mode 100644 drivers/mtd/spi-nor/spi-nor.c
drivers/mtd/Kconfig +2 -0
@@ -321,6 +321,8 @@ source "drivers/mtd/onenand/Kconfig" source "drivers/mtd/lpddr/Kconfig" +source "drivers/mtd/spi-nor/Kconfig" + source "drivers/mtd/ubi/Kconfig" endif # MTD
drivers/mtd/Makefile +1 -0
@@ -32,4 +32,5 @@ inftl-objs := inftlcore.o inftlmount.o obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/ +obj-$(CONFIG_MTD_SPI_NOR_BASE) += spi-nor/ obj-$(CONFIG_MTD_UBI) += ubi/
drivers/mtd/spi-nor/Kconfig new file +6 -0
@@ -0,0 +1,6 @@ +config MTD_SPI_NOR_BASE + bool "the framework for SPI-NOR support" + depends on MTD + help + This is the framework for the SPI NOR which can be used by the SPI + device drivers and the SPI-NOR device driver.
drivers/mtd/spi-nor/Makefile new file +1 -0
@@ -0,0 +1 @@ +obj-$(CONFIG_MTD_SPI_NOR_BASE) += spi-nor.o
drivers/mtd/spi-nor/spi-nor.c new file +1087 -0
1,087 lines not on this page · raw message
include/linux/mtd/spi-nor.h +20 -0
@@ -162,4 +162,24 @@ struct spi_nor { void *priv; }; + +/** +* spi_nor_scan() - scan the SPI NOR +* @nor: the spi_nor structure +* @id: the spi_device_id provided by the driver +* @mode: the read mode supported by the driver +* +* The drivers can use this fuction to scan the SPI NOR. +* In the scanning, it will try to get all the necessary information to +* fill the mtd_info{} and the spi_nor{}. +* +* The board may assigns a spi_device_id with @id which be used to compared with +* the spi_device_id detected by the scanning. +* +* Return: 0 for success, others for failure. +*/ +int spi_nor_scan (struct spi_nor *nor,const struct spi_device_id *id, +enum read_mode mode); +extern const struct spi_device_id spi_nor_ids[]; +#endif
Signature · 1 line
1.7.2.rc3
PATCH v5 3/8 mtd: spi-nor: add the framework for SPI NOR
Quoted 1 line · Huang Shijie
This patch cloned most of the
m25p80.c. In theory, it adds a new spi-nor layer.
...
drivers/mtd/spi-nor/spi-nor.c line 2
Quoted 8 lines
drivers/mtd/spi-nor/spi-nor.c new file +2
-0@@ -0,0 +1,1087 @@ +/* +* Cloned most of the code from the m25p80.c
Please include a copyright notice here. This should carry both the original m25p80.c copyright notice, as well as your own additional copyright if you choose. For instance:
* Based on m25p80.c, by Mike Lavender (mike at steroidmicros.com), with
* influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c *
* Copyright ? 2005, Intec Automation Inc.
* Copyright ? 2014, Freescale Semiconductor, Inc.
drivers/mtd/spi-nor/spi-nor.c line 14
Quoted 12 lines
drivers/mtd/spi-nor/spi-nor.c new file +12
-0+* +* This code is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/mutex.h> +#include <linux/math64.h>
...
Brian
PATCH v5 3/8 mtd: spi-nor: add the framework for SPI NOR
Quoted 16 lines · Brian Norris
Quoted 1 line · Huang Shijie
This patch cloned most of the
m25p80.c. In theory, it adds a new spi-nor layer....
drivers/mtd/spi-nor/spi-nor.c line 2
Quoted 8 lines
drivers/mtd/spi-nor/spi-nor.c new file +2
-0@@ -0,0 +1,1087 @@ +/* +* Cloned most of the code from the m25p80.c Please include a copyright notice here. This should carry both the original
m25p80.ccopyright notice, as well as your own additional copyright if you choose. For instance:
Quoted 6 lines
* Based on
m25p80.c, by Mike Lavender (mike at steroidmicros.com), with
* influence fromlart.c(Abraham Van Der Merwe) andmtd_dataflash.c*
* Copyright ? 2005, Intec Automation Inc.
* Copyright ? 2014, Freescale Semiconductor, Inc.
I will send a patch to add the copyright info which will based on your patch set.
thanks
Huang Shijie
PATCH v5 4/8 Documentation: add the document for the SPI NOR framework
In reply to Huang ShijieThis patch adds the document for the SPI NOR framework.
--- Documentation/mtd/spi-nor.txt | 59 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 59 insertions(+), 0 deletions(-) create mode 100644 Documentation/mtd/spi-nor.txt
Documentation/mtd/spi-nor.txt new file +59 -0
@@ -0,0 +1,59 @@ + SPI NOR framework + ============================================ + +Part I - why we need this framework? +------------------------------------- + +The SPI bus controller only deals with the byte stream. +Some controller does not works like a SPI bus controller, it works +like a SPI NOR controller instead, such as the Freescale's QuadSPI controller. + +The Freescale's QuadSPI controller should knows the NOR commands to +find the right LUT sequence. Unfortunately, the old code can not meet +this requirement. + +Part II - How does the framework work? +------------------------------------- + +This framework just adds a new layer between the MTD and the SPI bus driver. +With this new layer, the SPI NOR controller driver does not depend on the +m25p80 code anymore. + + Before this framework, the layer is like: + + MTD + ------------------------ + m25p80 + ------------------------ + SPI bus driver + ------------------------ + SPI NOR chip + + After this framework, the layer is like: + MTD + ------------------------ + SPI NOR framework + ------------------------ + m25p80 + ------------------------ + SPI bus driver + ------------------------ + SPI NOR chip + + With the SPI NOR controller driver(Freescale QuadSPI), it looks like: + MTD + ------------------------ + SPI NOR framework + ------------------------ + fsl-quadSPI + ------------------------ + SPI NOR chip + +Part III - How can the drivers use the framework +------------------------------------- + +The main API is the spi_nor_scan(). Before you call the hook, you should +initialize the necessary fields for spi_nor{}. +Please see the drivers/mtd/spi-nor/spi-nor.c for detail. +Please also reference to the fsl-quadspi.c when you want to write a new driver +for a SPI NOR controller.
Signature · 1 line
1.7.2.rc3
PATCH v5 4/8 Documentation: add the document for the SPI NOR framework
24.02.2014, 15:26, "Huang Shijie" <[email protected]>:
Quoted 17 lines
This patch adds the document for the SPI NOR framework.
Signed-off-by Huang Shijie <[email protected]>---
?Documentation/mtd/spi-nor.txt | ??59 +++++++++++++++++++++++++++++++++++++++++ ?1 files changed, 59 insertions(+), 0 deletions(-)
?create mode 100644Documentation/mtd/spi-nor.txtDocumentation/mtd/spi-nor.txt new file +3
-0@@ -0,0 +1,59 @@ + ?????????????????????????SPI NOR framework + ??????????????============================================ +
Documentation/mtd/spi-nor.txt line 13
Quoted 10 lines
Documentation/mtd/spi-nor.txt new file +10
-0+Part I - why we need this framework? +------------------------------------- + +The SPI bus controller only deals with the byte stream. +Some controller does not works like a SPI bus controller, it works +like a SPI NOR controller instead, such as the Freescale's QuadSPI controller. + +The Freescale's QuadSPI controller should knows the NOR commands to +find the right LUT sequence. Unfortunately, the old code can not meet +this requirement.
should know
Quoted 49 lines
Documentation/mtd/spi-nor.txt new file +46
-1+ +Part II - How does the framework work? +------------------------------------- + +This framework just adds a new layer between the MTD and the SPI bus driver. +With this new layer, the SPI NOR controller driver does not depend on the +m25p80 code anymore. + + ??Before this framework, the layer is like: + + ??????????????????MTD + ????????------------------------ + ?????????????????m25p80 + ????????------------------------ + ??????SPI bus driver + ????????------------------------ + ???????SPI NOR chip + + ??After this framework, the layer is like: + ??????????????????MTD + ????????------------------------ + ?????????????SPI NOR framework + ????????------------------------ + ?????????????????m25p80 + ????????------------------------ + ??????SPI bus driver + ????????------------------------ + ??????SPI NOR chip + + ?With the SPI NOR controller driver(Freescale QuadSPI), it looks like: + ??????????????????MTD + ????????------------------------ + ?????????????SPI NOR framework + ????????------------------------ + ???????????????fsl-quadSPI + ????????------------------------ + ??????SPI NOR chip + +Part III - How can the drivers use the framework +------------------------------------- + +The main API is the spi_nor_scan(). Before you call the hook, you should +initialize the necessary fields for spi_nor{}. +Please see the drivers/mtd/spi-nor/spi-nor.c for detail. +Please also reference to the fsl-quadspi.c when you want to write a new driver +for a SPI NOR controller. --1.7.2.rc3
Quoted 3 lines
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
Regards,
Konstantin
PATCH v5 4/8 Documentation: add the document for the SPI NOR framework
? 2014?02?24? 23:17, Konstantin Tokarev ??:
Quoted 1 line
should know
sorry for my poor english. thanks a lot.
Huang Shijie
PATCH v5 4/8 Documentation: add the document for the SPI NOR framework
In reply to Huang ShijieThis patch adds the document for the SPI NOR framework.
---
fix a typo
--- Documentation/mtd/spi-nor.txt | 59 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 59 insertions(+), 0 deletions(-) create mode 100644 Documentation/mtd/spi-nor.txt
Documentation/mtd/spi-nor.txt new file +59 -0
@@ -0,0 +1,59 @@ + SPI NOR framework + ============================================ + +Part I - why we need this framework? +------------------------------------- + +The SPI bus controller only deals with the byte stream. +Some controller does not works like a SPI bus controller, it works +like a SPI NOR controller instead, such as the Freescale's QuadSPI controller. + +The Freescale's QuadSPI controller should know the NOR commands to +find the right LUT sequence. Unfortunately, the old code can not meet +this requirement. + +Part II - How does the framework work? +------------------------------------- + +This framework just adds a new layer between the MTD and the SPI bus driver. +With this new layer, the SPI NOR controller driver does not depend on the +m25p80 code anymore. + + Before this framework, the layer is like: + + MTD + ------------------------ + m25p80 + ------------------------ + SPI bus driver + ------------------------ + SPI NOR chip + + After this framework, the layer is like: + MTD + ------------------------ + SPI NOR framework + ------------------------ + m25p80 + ------------------------ + SPI bus driver + ------------------------ + SPI NOR chip + + With the SPI NOR controller driver(Freescale QuadSPI), it looks like: + MTD + ------------------------ + SPI NOR framework + ------------------------ + fsl-quadSPI + ------------------------ + SPI NOR chip + +Part III - How can the drivers use the framework +------------------------------------- + +The main API is the spi_nor_scan(). Before you call the hook, you should +initialize the necessary fields for spi_nor{}. +Please see the drivers/mtd/spi-nor/spi-nor.c for detail. +Please also reference to the fsl-quadspi.c when you want to write a new driver +for a SPI NOR controller.
Signature · 1 line
1.7.2.rc3
PATCH v5 5/8 mtd: m25p80: use the SPI nor framework
In reply to Huang ShijieUse the new SPI nor framework, and rewrite the m25p80:
(0) remove all the NOR comands.
(1) change the m25p->command to an array.
(2) implement the necessary hooks, such as m25p80_read/m25p80_write.
Tested with the m25p32.
--- drivers/mtd/devices/m25p80.c | 1302 ++++-------------------------------------- 1 files changed, 105 insertions(+), 1197 deletions(-)
drivers/mtd/devices/m25p80.c +105 -1197
@@ -19,485 +19,98 @@#include <linux/errno.h> #include <linux/module.h> #include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/mutex.h> -#include <linux/math64.h> -#include <linux/slab.h> -#include <linux/sched.h> -#include <linux/mod_devicetable.h> -#include <linux/mtd/cfi.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> -#include <linux/of_platform.h> #include <linux/spi/spi.h> #include <linux/spi/flash.h> +#include <linux/mtd/spi-nor.h> -/* Flash opcodes. */ -#define OPCODE_WREN 0x06/* Write enable */ -#define OPCODE_RDSR 0x05/* Read status register */ -#define OPCODE_WRSR 0x01/* Write status register 1 byte */ -#define OPCODE_NORM_READ 0x03/* Read data bytes (low frequency) */ -#define OPCODE_FAST_READ 0x0b/* Read data bytes (high frequency) */ -#define OPCODE_DUAL_READ 0x3b/* Read data bytes (Dual SPI) */ -#define OPCODE_QUAD_READ 0x6b/* Read data bytes (Quad SPI) */ -#define OPCODE_PP 0x02/* Page program (up to 256 bytes) */ -#define OPCODE_BE_4K 0x20/* Erase 4KiB block */ -#define OPCODE_BE_4K_PMC 0xd7/* Erase 4KiB block on PMC chips */ -#define OPCODE_BE_32K 0x52/* Erase 32KiB block */ -#define OPCODE_CHIP_ERASE 0xc7/* Erase whole flash chip */ -#define OPCODE_SE 0xd8/* Sector erase (usually 64KiB) */ -#define OPCODE_RDID 0x9f/* Read JEDEC ID */ -#define OPCODE_RDCR 0x35/* Read configuration register */ - -/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ -#define OPCODE_NORM_READ_4B 0x13/* Read data bytes (low frequency) */ -#define OPCODE_FAST_READ_4B 0x0c/* Read data bytes (high frequency) */ -#define OPCODE_DUAL_READ_4B 0x3c/* Read data bytes (Dual SPI) */ -#define OPCODE_QUAD_READ_4B 0x6c/* Read data bytes (Quad SPI) */ -#define OPCODE_PP_4B 0x12/* Page program (up to 256 bytes) */ -#define OPCODE_SE_4B 0xdc/* Sector erase (usually 64KiB) */ - -/* Used for SST flashes only. */ -#define OPCODE_BP 0x02/* Byte program */ -#define OPCODE_WRDI 0x04/* Write disable */ -#define OPCODE_AAI_WP 0xad/* Auto address increment word program */ - -/* Used for Macronix and Winbond flashes. */ -#define OPCODE_EN4B 0xb7/* Enter 4-byte mode */ -#define OPCODE_EX4B 0xe9/* Exit 4-byte mode */ - -/* Used for Spansion flashes only. */ -#define OPCODE_BRWR 0x17/* Bank register write */ - -/* Status Register bits. */ -#define SR_WIP 1/* Write in progress */ -#define SR_WEL 2/* Write enable latch */ -/* meaning of other SR_* bits may differ between vendors */ -#define SR_BP0 4/* Block protect 0 */ -#define SR_BP1 8/* Block protect 1 */ -#define SR_BP2 0x10/* Block protect 2 */ -#define SR_SRWD 0x80/* SR write protect */ - -#define SR_QUAD_EN_MX 0x40/* Macronix Quad I/O */ - -/* Configuration Register bits. */ -#define CR_QUAD_EN_SPAN 0x2/* Spansion Quad I/O */ - -/* Define max times to check status register before we give up. */ -#define MAX_READY_WAIT_JIFFIES (40 * HZ)/* M25P16 specs 40s max chip erase */ #define MAX_CMD_SIZE 6 - -#define JEDEC_MFR (_jedec_id) ((_jedec_id) >> 16) - -/****************************************************************************/ - -enum read_type { -M25P80_NORMAL =0 , -M25P80_FAST , -M25P80_DUAL , -M25P80_QUAD , -}; -struct m25p {struct spi_device *spi; -struct mutex lock; +struct spi_nor spi_nor;struct mtd_info mtd; -u16 page_size; -u16 addr_width; -u8 erase_opcode; -u8 read_opcode; -u8 program_opcode; -u8 *command; -enum read_type flash_read; +u8 command[MAX_CMD_SIZE ]; }; -static inline struct m25p *mtd_to_m25p (struct mtd_info *mtd) -{ - return container_of(mtd, struct m25p, mtd); -} - -/****************************************************************************/ - -/* -* Internal helper functions -*/ - -/* -* Read the status register, returning its value in the location -* Return the status register value. -* Returns negative if error occurred. -*/ -static int read_sr (struct m25p *flash) -{ -ssize_t retval; -u8 code =OPCODE_RDSR ; -u8 val; - - retval =spi_write_then_read (flash->spi, &code,1 , &val,1 ); - -if (retval <0 ) { -dev_err (&flash->spi->dev,"error %d reading SR\n" , - (int ) retval); -return retval; - } - -return val; -} - -/* -* Read configuration register, returning its value in the -* location. Return the configuration register value. -* Returns negative if error occured. -*/ -static int read_cr (struct m25p *flash) -{ -u8 code =OPCODE_RDCR ; -int ret; -u8 val; - - ret =spi_write_then_read (flash->spi, &code,1 , &val,1 ); -if (ret <0 ) { -dev_err (&flash->spi->dev,"error %d reading CR\n" , ret); -return ret; - } - -return val; -} - -/* -* Write status register 1 byte -* Returns negative if error occurred. -*/ -static int write_sr (struct m25p *flash,u8 val) -{ - flash->command[0 ] =OPCODE_WRSR ; - flash->command[1 ] = val; - -return spi_write (flash->spi, flash->command,2 ); -} - -/* -* Set write enable latch with Write Enable command. -* Returns negative if error occurred. -*/ -static inline int write_enable (struct m25p *flash) -{ -u8 code =OPCODE_WREN ; - -return spi_write_then_read (flash->spi, &code,1 ,NULL ,0 ); -} - -/* -* Send write disble instruction to the chip. -*/ -static inline int write_disable (struct m25p *flash) -{ -u8 code =OPCODE_WRDI ; - -return spi_write_then_read (flash->spi, &code,1 ,NULL ,0 ); -} - -/* -* Enable/disable 4-byte addressing mode. -*/ -static inline int set_4byte (struct m25p *flash,u32 jedec_id,int enable) -{ -int status; -bool need_wren = false; - -switch (JEDEC_MFR (jedec_id)) { -case CFI_MFR_ST :/* Micron, actually */ -/* Some Micron need WREN command; all will accept it */ - need_wren = true; -case CFI_MFR_MACRONIX : -case 0xEF /* winbond */ : -if (need_wren) -write_enable (flash); - - flash->command[0 ] = enable ?OPCODE_EN4B :OPCODE_EX4B ; - status =spi_write (flash->spi, flash->command,1 ); - -if (need_wren) -write_disable (flash); - -return status; -default : -/* Spansion style */ - flash->command[0 ] =OPCODE_BRWR ; - flash->command[1 ] = enable <<7 ; -return spi_write (flash->spi, flash->command,2 ); - } -} - -/* -* Service routine to read status register until ready, or timeout occurs. -* Returns non-zero if error. -*/ -static int wait_till_ready (struct m25p *flash) -{ -unsigned long deadline; -int sr; - - deadline = jiffies +MAX_READY_WAIT_JIFFIES ; - -do { -if ((sr =read_sr (flash)) <0 ) -break ; -else if (!(sr &SR_WIP )) -return 0 ; - -cond_resched (); - - }while (!time_after_eq (jiffies, deadline)); - -return 1 ; -} - -/* -* Write status Register and configuration register with 2 bytes -* The first byte will be written to the status register, while the -* second byte will be written to the configuration register. -* Return negative if error occured. -*/ -static int write_sr_cr (struct m25p *flash,u16 val) -{ - flash->command[0 ] =OPCODE_WRSR ; - flash->command[1 ] = val &0xff ; - flash->command[2 ] = (val >>8 ); - -return spi_write (flash->spi, flash->command,3 ); -} - -static int macronix_quad_enable (struct m25p *flash) -{ -int ret, val; -u8 cmd[2 ]; - cmd[0 ] =OPCODE_WRSR ; - - val =read_sr (flash); - cmd[1 ] = val |SR_QUAD_EN_MX ; -write_enable (flash); - -spi_write (flash->spi, &cmd,2 ); - -if (wait_till_ready (flash)) -return 1 ; - - ret =read_sr (flash); -if (!(ret >0 && (ret &SR_QUAD_EN_MX ))) { -dev_err (&flash->spi->dev,"Macronix Quad bit not set\n" ); -return -EINVAL ; - } - -return 0 ; -} - -static int spansion_quad_enable (struct m25p *flash) +static int m25p80_read_reg (struct spi_nor *nor,u8 code,u8 *val,int len) { +struct m25p *flash = nor->priv; +struct spi_device *spi = flash->spi;int ret; -int quad_en =CR_QUAD_EN_SPAN <<8 ; - -write_enable (flash); - ret =write_sr_cr (flash, quad_en); -if (ret <0 ) { -dev_err (&flash->spi->dev, -"error while writing configuration register\n" ); -return -EINVAL ; - } - -/* read back and check it */ - ret =read_cr (flash); -if (!(ret >0 && (ret &CR_QUAD_EN_SPAN ))) { -dev_err (&flash->spi->dev,"Spansion Quad bit not set\n" ); -return -EINVAL ; - } - -return 0 ; -} - -static int set_quad_mode (struct m25p *flash,u32 jedec_id) -{ -int status; - -switch (JEDEC_MFR (jedec_id)) { -case CFI_MFR_MACRONIX : - status =macronix_quad_enable (flash); -if (status) { -dev_err (&flash->spi->dev, -"Macronix quad-read not enabled\n" ); -return -EINVAL ; - } -return status; -default : - status =spansion_quad_enable (flash); -if (status) { -dev_err (&flash->spi->dev, -"Spansion quad-read not enabled\n" ); -return -EINVAL ; - } -return status; - } -} - -/* -* Erase the whole flash memory -* -* Returns 0 if successful, non-zero otherwise. -*/ -static int erase_chip (struct m25p *flash) -{ -pr_debug ("%s: %s %lldKiB\n" ,dev_name (&flash->spi->dev), __func__, - (long long )(flash->mtd.size >>10 )); + ret =spi_write_then_read (spi, &code,1 , val, len); +if (ret <0 ) +dev_err (&spi->dev,"error %d reading %x\n" , ret, code); -/* Wait until finished previous write command. */ -if (wait_till_ready (flash)) -return 1 ; - -/* Send write enable, then erase commands. */ -write_enable (flash); - -/* Set up command buffer. */ - flash->command[0 ] =OPCODE_CHIP_ERASE ; - -spi_write (flash->spi, flash->command,1 ); - -return 0 ; +return ret; } -static void m25p_addr2cmd (struct m25p *flash,unsigned int addr,u8 *cmd) +static void m25p_addr2cmd (struct spi_nor *nor,unsigned int addr,u8 *cmd) {/* opcode is in cmd[0] */ - cmd[1 ] = addr >> (flash->addr_width *8 -8 ); - cmd[2 ] = addr >> (flash->addr_width *8 -16 ); - cmd[3 ] = addr >> (flash->addr_width *8 -24 ); - cmd[4 ] = addr >> (flash->addr_width *8 -32 ); + cmd[1 ] = addr >> (nor->addr_width *8 -8 ); + cmd[2 ] = addr >> (nor->addr_width *8 -16 ); + cmd[3 ] = addr >> (nor->addr_width *8 -24 ); + cmd[4 ] = addr >> (nor->addr_width *8 -32 ); } -static int m25p_cmdsz (struct m25p *flash) +static int m25p_cmdsz (struct spi_nor *nor) { -return 1 + flash->addr_width; +return 1 + nor->addr_width; } -/* -* Erase one sector of flash memory at offset ``offset'' which is any -* address within the sector which should be erased. -* -* Returns 0 if successful, non-zero otherwise. -*/ -static int erase_sector (struct m25p *flash,u32 offset) +static int m25p80_write_reg (struct spi_nor *nor,u8 opcode,u8 *buf,int len, +int wr_en) { -pr_debug ("%s: %s %dKiB at 0x%08x\n" ,dev_name (&flash->spi->dev), - __func__, flash->mtd.erasesize /1024 , offset); - -/* Wait until finished previous write command. */ -if (wait_till_ready (flash)) -return 1 ; +struct m25p *flash = nor->priv; +struct spi_device *spi = flash->spi; -/* Send write enable, then erase commands. */ -write_enable (flash); - -/* Set up command buffer. */ - flash->command[0 ] = flash->erase_opcode; -m25p_addr2cmd (flash, offset, flash->command); - -spi_write (flash->spi, flash->command,m25p_cmdsz (flash)); + flash->command[0 ] = opcode; +if (buf) +memcpy (&flash->command[1 ], buf, len); -return 0 ; +return spi_write (spi, flash->command, len +1 ); } -/****************************************************************************/ - -/* -* MTD implementation -*/ - -/* -* Erase an address range on the flash chip. The address range may extend -* one or more erase sectors. Return an error is there is a problem erasing. -*/ -static int m25p80_erase (struct mtd_info *mtd,struct erase_info *instr) +static void m25p80_write (struct spi_nor *nor,loff_t to,size_t len, +size_t *retlen,const u_char *buf) { -struct m25p *flash =mtd_to_m25p (mtd); -u32 addr,len; -uint32_t rem; - -pr_debug ("%s: %s at 0x%llx, len %lld\n" ,dev_name (&flash->spi->dev), - __func__, (long long )instr->addr, - (long long )instr->len); - -div_u64_rem (instr->len, mtd->erasesize, &rem); -if (rem) -return -EINVAL ; - - addr = instr->addr; - len = instr->len; - -mutex_lock (&flash->lock); - -/* whole-chip erase? */ -if (len == flash->mtd.size) { -if (erase_chip (flash)) { - instr->state =MTD_ERASE_FAILED ; -mutex_unlock (&flash->lock); -return -EIO ; - } +struct m25p *flash = nor->priv; +struct spi_device *spi = flash->spi; +struct spi_transfer t[2 ] = {}; +struct spi_message m; +int cmd_sz =m25p_cmdsz (nor); -/* REVISIT in some cases we could speed up erasing large regions -* by using OPCODE_SE instead of OPCODE_BE_4K. We may have set up -* to use "small sector erase", but that's not always optimal. -*/ +spi_message_init (&m); -/* "sector"-at-a-time erase */ - }else { -while (len) { -if (erase_sector (flash, addr)) { - instr->state =MTD_ERASE_FAILED ; -mutex_unlock (&flash->lock); -return -EIO ; - } +if (nor->program_opcode ==OPCODE_AAI_WP && nor->sst_write_second) + cmd_sz =1 ; - addr += mtd->erasesize; - len -= mtd->erasesize; - } - } + flash->command[0 ] = nor->program_opcode; +m25p_addr2cmd (nor, to, flash->command); -mutex_unlock (&flash->lock); + t[0 ].tx_buf = flash->command; + t[0 ].len = cmd_sz; +spi_message_add_tail (&t[0 ], &m); - instr->state =MTD_ERASE_DONE ; -mtd_erase_callback (instr); + t[1 ].tx_buf = buf; + t[1 ].len = len; +spi_message_add_tail (&t[1 ], &m); -return 0 ; -} +spi_sync (spi, &m); -/* -* Dummy Cycle calculation for different type of read. -* It can be used to support more commands with -* different dummy cycle requirements. -*/ -static inline int m25p80_dummy_cycles_read (struct m25p *flash) -{ -switch (flash->flash_read) { -case M25P80_FAST : -case M25P80_DUAL : -case M25P80_QUAD : -return 1 ; -case M25P80_NORMAL : -return 0 ; -default : -dev_err (&flash->spi->dev,"No valid read type supported\n" ); -return -1 ; - } + *retlen += m.actual_length - cmd_sz; } -static inline unsigned int m25p80_rx_nbits (const struct m25p *flash) +static inline unsigned int m25p80_rx_nbits (struct spi_nor *nor) { -switch (flash->flash_read) { -case M25P80_DUAL : +switch (nor->flash_read) { +case SPI_NOR_DUAL :return 2 ; -case M25P80_QUAD : +case SPI_NOR_QUAD :return 4 ;default :return 0 ;
@@ -505,589 +118,72 @@ static inline unsigned int m25p80_rx_nbits(const struct m25p *flash) }/* -* Read an address range from the flash chip. The address range +* Read an address range from the nor chip. The address range * may be any size provided it is within the physical boundaries. */ -static int m25p80_read (struct mtd_info *mtd,loff_t from,size_t len, -size_t *retlen,u_char *buf) +static int m25p80_read (struct spi_nor *nor,loff_t from,size_t len, +size_t *retlen,u_char *buf) { -struct m25p *flash =mtd_to_m25p (mtd); +struct m25p *flash = nor->priv; +struct spi_device *spi = flash->spi;struct spi_transfer t[2 ];struct spi_message m; -uint8_t opcode; -int dummy; +int dummy = nor->read_dummy; +int ret; -pr_debug ("%s: %s from 0x%08x, len %zd\n" ,dev_name (&flash->spi->dev), - __func__, (u32 )from, len); +/* Wait till previous write/erase is done. */ + ret = nor->wait_till_ready (nor); +if (ret) +return ret;spi_message_init (&m);memset (t,0 , (sizeof t)); - dummy =m25p80_dummy_cycles_read (flash); -if (dummy <0 ) { -dev_err (&flash->spi->dev,"No valid read command supported\n" ); -return -EINVAL ; - } + flash->command[0 ] = nor->read_opcode; +m25p_addr2cmd (nor, from, flash->command); t[0 ].tx_buf = flash->command; - t[0 ].len =m25p_cmdsz (flash) + dummy; + t[0 ].len =m25p_cmdsz (nor) + dummy;spi_message_add_tail (&t[0 ], &m); t[1 ].rx_buf = buf; - t[1 ].rx_nbits =m25p80_rx_nbits (flash); + t[1 ].rx_nbits =m25p80_rx_nbits (nor); t[1 ].len = len;spi_message_add_tail (&t[1 ], &m); -mutex_lock (&flash->lock); - -/* Wait till previous write/erase is done. */ -if (wait_till_ready (flash)) { -/* REVISIT status return?? */ -mutex_unlock (&flash->lock); -return 1 ; - } - -/* Set up the write data buffer. */ - opcode = flash->read_opcode; - flash->command[0 ] = opcode; -m25p_addr2cmd (flash, from, flash->command); - -spi_sync (flash->spi, &m); - - *retlen = m.actual_length -m25p_cmdsz (flash) - dummy; - -mutex_unlock (&flash->lock); +spi_sync (spi, &m); + *retlen = m.actual_length -m25p_cmdsz (nor) - dummy;return 0 ; } -/* -* Write an address range to the flash chip. Data must be written in -* FLASH_PAGESIZE chunks. The address range may be any size provided -* it is within the physical boundaries. -*/ -static int m25p80_write (struct mtd_info *mtd,loff_t to,size_t len, -size_t *retlen,const u_char *buf) +static int m25p80_erase (struct spi_nor *nor,loff_t offset) { -struct m25p *flash =mtd_to_m25p (mtd); -u32 page_offset, page_size; -struct spi_transfer t[2 ]; -struct spi_message m; - -pr_debug ("%s: %s to 0x%08x, len %zd\n" ,dev_name (&flash->spi->dev), - __func__, (u32 )to, len); - -spi_message_init (&m); -memset (t,0 , (sizeof t)); - - t[0 ].tx_buf = flash->command; - t[0 ].len =m25p_cmdsz (flash); -spi_message_add_tail (&t[0 ], &m); - - t[1 ].tx_buf = buf; -spi_message_add_tail (&t[1 ], &m); - -mutex_lock (&flash->lock); - -/* Wait until finished previous write command. */ -if (wait_till_ready (flash)) { -mutex_unlock (&flash->lock); -return 1 ; - } - -write_enable (flash); - -/* Set up the opcode in the write buffer. */ - flash->command[0 ] = flash->program_opcode; -m25p_addr2cmd (flash, to, flash->command); - - page_offset = to & (flash->page_size -1 ); - -/* do all the bytes fit onto one page? */ -if (page_offset + len <= flash->page_size) { - t[1 ].len = len; - -spi_sync (flash->spi, &m); - - *retlen = m.actual_length -m25p_cmdsz (flash); - }else { -u32 i; - -/* the size of data remaining on the first page */ - page_size = flash->page_size - page_offset; - - t[1 ].len = page_size; -spi_sync (flash->spi, &m); - - *retlen = m.actual_length -m25p_cmdsz (flash); - -/* write everything in flash->page_size chunks */ -for (i = page_size; i < len; i += page_size) { - page_size = len - i; -if (page_size > flash->page_size) - page_size = flash->page_size; - -/* write the next page to flash */ -m25p_addr2cmd (flash, to + i, flash->command); - - t[1 ].tx_buf = buf + i; - t[1 ].len = page_size; - -wait_till_ready (flash); - -write_enable (flash); - -spi_sync (flash->spi, &m); - - *retlen += m.actual_length -m25p_cmdsz (flash); - } - } - -mutex_unlock (&flash->lock); - -return 0 ; -} - -static int sst_write (struct mtd_info *mtd,loff_t to,size_t len, -size_t *retlen,const u_char *buf) -{ -struct m25p *flash =mtd_to_m25p (mtd); -struct spi_transfer t[2 ]; -struct spi_message m; -size_t actual; -int cmd_sz, ret; - -pr_debug ("%s: %s to 0x%08x, len %zd\n" ,dev_name (&flash->spi->dev), - __func__, (u32 )to, len); - -spi_message_init (&m); -memset (t,0 , (sizeof t)); - - t[0 ].tx_buf = flash->command; - t[0 ].len =m25p_cmdsz (flash); -spi_message_add_tail (&t[0 ], &m); - - t[1 ].tx_buf = buf; -spi_message_add_tail (&t[1 ], &m); +struct m25p *flash = nor->priv; +int ret; -mutex_lock (&flash->lock); +dev_dbg (nor->dev,"%dKiB at 0x%08x\n" , + flash->mtd.erasesize /1024 , (u32 )offset);/* Wait until finished previous write command. */ - ret =wait_till_ready (flash); + ret = nor->wait_till_ready (nor);if (ret) - goto time_out; - -write_enable (flash); - - actual = to %2 ; -/* Start write from odd address. */ -if (actual) { - flash->command[0 ] =OPCODE_BP ; -m25p_addr2cmd (flash, to, flash->command); - -/* write one byte. */ - t[1 ].len =1 ; -spi_sync (flash->spi, &m); - ret =wait_till_ready (flash); -if (ret) - goto time_out; - *retlen += m.actual_length -m25p_cmdsz (flash); - } - to += actual; - - flash->command[0 ] =OPCODE_AAI_WP ; -m25p_addr2cmd (flash, to, flash->command); - -/* Write out most of the data here. */ - cmd_sz =m25p_cmdsz (flash); -for (; actual < len -1 ; actual +=2 ) { - t[0 ].len = cmd_sz; -/* write two bytes. */ - t[1 ].len =2 ; - t[1 ].tx_buf = buf + actual; +return ret; -spi_sync (flash->spi, &m); - ret =wait_till_ready (flash); -if (ret) - goto time_out; - *retlen += m.actual_length - cmd_sz; - cmd_sz =1 ; - to +=2 ; - } -write_disable (flash); - ret =wait_till_ready (flash); +/* Send write enable, then erase commands. */ + ret = nor->write_reg (nor,OPCODE_WREN ,NULL ,0 ,0 );if (ret) - goto time_out; - -/* Write out trailing byte if it exists. */ -if (actual != len) { -write_enable (flash); - flash->command[0 ] =OPCODE_BP ; -m25p_addr2cmd (flash, to, flash->command); - t[0 ].len =m25p_cmdsz (flash); - t[1 ].len =1 ; - t[1 ].tx_buf = buf + actual; - -spi_sync (flash->spi, &m); - ret =wait_till_ready (flash); -if (ret) - goto time_out; - *retlen += m.actual_length -m25p_cmdsz (flash); -write_disable (flash); - } - -time_out: -mutex_unlock (&flash->lock); -return ret; -} - -static int m25p80_lock (struct mtd_info *mtd,loff_t ofs,uint64_t len) -{ -struct m25p *flash =mtd_to_m25p (mtd); -uint32_t offset = ofs; -uint8_t status_old, status_new; -int res =0 ; - -mutex_lock (&flash->lock); -/* Wait until finished previous command */ -if (wait_till_ready (flash)) { - res =1 ; - goto err; - } - - status_old =read_sr (flash); - -if (offset < flash->mtd.size-(flash->mtd.size/2 )) - status_new = status_old |SR_BP2 |SR_BP1 |SR_BP0 ; -else if (offset < flash->mtd.size-(flash->mtd.size/4 )) - status_new = (status_old & ~SR_BP0 ) |SR_BP2 |SR_BP1 ; -else if (offset < flash->mtd.size-(flash->mtd.size/8 )) - status_new = (status_old & ~SR_BP1 ) |SR_BP2 |SR_BP0 ; -else if (offset < flash->mtd.size-(flash->mtd.size/16 )) - status_new = (status_old & ~(SR_BP0 |SR_BP1 )) |SR_BP2 ; -else if (offset < flash->mtd.size-(flash->mtd.size/32 )) - status_new = (status_old & ~SR_BP2 ) |SR_BP1 |SR_BP0 ; -else if (offset < flash->mtd.size-(flash->mtd.size/64 )) - status_new = (status_old & ~(SR_BP2 |SR_BP0 )) |SR_BP1 ; -else - status_new = (status_old & ~(SR_BP2 |SR_BP1 )) |SR_BP0 ; - -/* Only modify protection if it will not unlock other areas */ -if ((status_new&(SR_BP2 |SR_BP1 |SR_BP0 )) > - (status_old&(SR_BP2 |SR_BP1 |SR_BP0 ))) { -write_enable (flash); -if (write_sr (flash, status_new) <0 ) { - res =1 ; - goto err; - } - } - -err:mutex_unlock (&flash->lock); -return res; -} - -static int m25p80_unlock (struct mtd_info *mtd,loff_t ofs,uint64_t len) -{ -struct m25p *flash =mtd_to_m25p (mtd); -uint32_t offset = ofs; -uint8_t status_old, status_new; -int res =0 ; - -mutex_lock (&flash->lock); -/* Wait until finished previous command */ -if (wait_till_ready (flash)) { - res =1 ; - goto err; - } - - status_old =read_sr (flash); - -if (offset+len > flash->mtd.size-(flash->mtd.size/64 )) - status_new = status_old & ~(SR_BP2 |SR_BP1 |SR_BP0 ); -else if (offset+len > flash->mtd.size-(flash->mtd.size/32 )) - status_new = (status_old & ~(SR_BP2 |SR_BP1 )) |SR_BP0 ; -else if (offset+len > flash->mtd.size-(flash->mtd.size/16 )) - status_new = (status_old & ~(SR_BP2 |SR_BP0 )) |SR_BP1 ; -else if (offset+len > flash->mtd.size-(flash->mtd.size/8 )) - status_new = (status_old & ~SR_BP2 ) |SR_BP1 |SR_BP0 ; -else if (offset+len > flash->mtd.size-(flash->mtd.size/4 )) - status_new = (status_old & ~(SR_BP0 |SR_BP1 )) |SR_BP2 ; -else if (offset+len > flash->mtd.size-(flash->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 (flash); -if (write_sr (flash, status_new) <0 ) { - res =1 ; - goto err; - } - } - -err:mutex_unlock (&flash->lock); -return res; -} - -/****************************************************************************/ - -/* -* SPI device driver setup and teardown -*/ - -struct flash_info { -/* JEDEC id zero means "no ID" (most older chips); otherwise it has -* a high byte of zero plus three data bytes: the manufacturer id, -* then a two byte device id. -*/ -u32 jedec_id; -u16 ext_id; - -/* The size listed here is what works with OPCODE_SE, which isn't -* necessarily called a "sector" by the vendor. -*/ -unsigned sector_size; -u16 n_sectors; - -u16 page_size; -u16 addr_width; - -u16 flags; -#define SECT_4K 0x01/* OPCODE_BE_4K works uniformly */ -#define M25P_NO_ERASE 0x02/* No erase command needed */ -#define SST_WRITE 0x04/* use SST byte programming */ -#define M25P_NO_FR 0x08/* Can't do fastread */ -#define SECT_4K_PMC 0x10/* OPCODE_BE_4K_PMC works uniformly */ -#define M25P80_DUAL_READ 0x20/* Flash supports Dual Read */ -#define M25P80_QUAD_READ 0x40/* Flash supports Quad Read */ -}; - -#define INFO (_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ - ((kernel_ulong_t)&(struct flash_info) { \ - .jedec_id = (_jedec_id), \ - .ext_id = (_ext_id), \ - .sector_size = (_sector_size), \ - .n_sectors = (_n_sectors), \ - .page_size = 256, \ - .flags = (_flags), \ - }) - -#define CAT25_INFO (_sector_size, _n_sectors, _page_size, _addr_width, _flags) \ - ((kernel_ulong_t)&(struct flash_info) { \ - .sector_size = (_sector_size), \ - .n_sectors = (_n_sectors), \ - .page_size = (_page_size), \ - .addr_width = (_addr_width), \ - .flags = (_flags), \ - }) - -/* NOTE: double check command sets and memory organization when you add -* more flash chips. This current list focusses on newer chips, which -* have been converging on command sets which including JEDEC ID. -*/ -static const struct spi_device_id m25p_ids[] = { -/* Atmel -- some are (confusingly) marketed as "DataFlash" */ - {"at25fs010" ,INFO (0x1f6601 ,0 ,32 *1024 ,4 ,SECT_4K ) }, - {"at25fs040" ,INFO (0x1f6604 ,0 ,64 *1024 ,8 ,SECT_4K ) }, - - {"at25df041a" ,INFO (0x1f4401 ,0 ,64 *1024 ,8 ,SECT_4K ) }, - {"at25df321a" ,INFO (0x1f4701 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - {"at25df641" ,INFO (0x1f4800 ,0 ,64 *1024 ,128 ,SECT_4K ) }, - - {"at26f004" ,INFO (0x1f0400 ,0 ,64 *1024 ,8 ,SECT_4K ) }, - {"at26df081a" ,INFO (0x1f4501 ,0 ,64 *1024 ,16 ,SECT_4K ) }, - {"at26df161a" ,INFO (0x1f4601 ,0 ,64 *1024 ,32 ,SECT_4K ) }, - {"at26df321" ,INFO (0x1f4700 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - - {"at45db081d" ,INFO (0x1f2500 ,0 ,64 *1024 ,16 ,SECT_4K ) }, - -/* EON -- en25xxx */ - {"en25f32" ,INFO (0x1c3116 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - {"en25p32" ,INFO (0x1c2016 ,0 ,64 *1024 ,64 ,0 ) }, - {"en25q32b" ,INFO (0x1c3016 ,0 ,64 *1024 ,64 ,0 ) }, - {"en25p64" ,INFO (0x1c2017 ,0 ,64 *1024 ,128 ,0 ) }, - {"en25q64" ,INFO (0x1c3017 ,0 ,64 *1024 ,128 ,SECT_4K ) }, - {"en25qh256" ,INFO (0x1c7019 ,0 ,64 *1024 ,512 ,0 ) }, - -/* ESMT */ - {"f25l32pa" ,INFO (0x8c2016 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - -/* Everspin */ - {"mr25h256" ,CAT25_INFO (32 *1024 ,1 ,256 ,2 ,M25P_NO_ERASE |M25P_NO_FR ) }, - {"mr25h10" ,CAT25_INFO (128 *1024 ,1 ,256 ,3 ,M25P_NO_ERASE |M25P_NO_FR ) }, - -/* GigaDevice */ - {"gd25q32" ,INFO (0xc84016 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - {"gd25q64" ,INFO (0xc84017 ,0 ,64 *1024 ,128 ,SECT_4K ) }, - -/* Intel/Numonyx -- xxxs33b */ - {"160s33b" ,INFO (0x898911 ,0 ,64 *1024 ,32 ,0 ) }, - {"320s33b" ,INFO (0x898912 ,0 ,64 *1024 ,64 ,0 ) }, - {"640s33b" ,INFO (0x898913 ,0 ,64 *1024 ,128 ,0 ) }, - -/* Macronix */ - {"mx25l2005a" ,INFO (0xc22012 ,0 ,64 *1024 ,4 ,SECT_4K ) }, - {"mx25l4005a" ,INFO (0xc22013 ,0 ,64 *1024 ,8 ,SECT_4K ) }, - {"mx25l8005" ,INFO (0xc22014 ,0 ,64 *1024 ,16 ,0 ) }, - {"mx25l1606e" ,INFO (0xc22015 ,0 ,64 *1024 ,32 ,SECT_4K ) }, - {"mx25l3205d" ,INFO (0xc22016 ,0 ,64 *1024 ,64 ,0 ) }, - {"mx25l3255e" ,INFO (0xc29e16 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - {"mx25l6405d" ,INFO (0xc22017 ,0 ,64 *1024 ,128 ,0 ) }, - {"mx25l12805d" ,INFO (0xc22018 ,0 ,64 *1024 ,256 ,0 ) }, - {"mx25l12855e" ,INFO (0xc22618 ,0 ,64 *1024 ,256 ,0 ) }, - {"mx25l25635e" ,INFO (0xc22019 ,0 ,64 *1024 ,512 ,0 ) }, - {"mx25l25655e" ,INFO (0xc22619 ,0 ,64 *1024 ,512 ,0 ) }, - {"mx66l51235l" ,INFO (0xc2201a ,0 ,64 *1024 ,1024 ,M25P80_QUAD_READ ) }, - -/* Micron */ - {"n25q064" ,INFO (0x20ba17 ,0 ,64 *1024 ,128 ,0 ) }, - {"n25q128a11" ,INFO (0x20bb18 ,0 ,64 *1024 ,256 ,0 ) }, - {"n25q128a13" ,INFO (0x20ba18 ,0 ,64 *1024 ,256 ,0 ) }, - {"n25q256a" ,INFO (0x20ba19 ,0 ,64 *1024 ,512 ,SECT_4K ) }, - {"n25q512a" ,INFO (0x20bb20 ,0 ,64 *1024 ,1024 ,SECT_4K ) }, - -/* PMC */ - {"pm25lv512" ,INFO (0 ,0 ,32 *1024 ,2 ,SECT_4K_PMC ) }, - {"pm25lv010" ,INFO (0 ,0 ,32 *1024 ,4 ,SECT_4K_PMC ) }, - {"pm25lq032" ,INFO (0x7f9d46 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - -/* Spansion -- single (large) sector size only, at least -* for the chips listed here (without boot sectors). -*/ - {"s25sl032p" ,INFO (0x010215 ,0x4d00 ,64 *1024 ,64 ,0 ) }, - {"s25sl064p" ,INFO (0x010216 ,0x4d00 ,64 *1024 ,128 ,0 ) }, - {"s25fl256s0" ,INFO (0x010219 ,0x4d00 ,256 *1024 ,128 ,0 ) }, - {"s25fl256s1" ,INFO (0x010219 ,0x4d01 ,64 *1024 ,512 ,M25P80_DUAL_READ |M25P80_QUAD_READ ) }, - {"s25fl512s" ,INFO (0x010220 ,0x4d00 ,256 *1024 ,256 ,M25P80_DUAL_READ |M25P80_QUAD_READ ) }, - {"s70fl01gs" ,INFO (0x010221 ,0x4d00 ,256 *1024 ,256 ,0 ) }, - {"s25sl12800" ,INFO (0x012018 ,0x0300 ,256 *1024 ,64 ,0 ) }, - {"s25sl12801" ,INFO (0x012018 ,0x0301 ,64 *1024 ,256 ,0 ) }, - {"s25fl129p0" ,INFO (0x012018 ,0x4d00 ,256 *1024 ,64 ,0 ) }, - {"s25fl129p1" ,INFO (0x012018 ,0x4d01 ,64 *1024 ,256 ,0 ) }, - {"s25sl004a" ,INFO (0x010212 ,0 ,64 *1024 ,8 ,0 ) }, - {"s25sl008a" ,INFO (0x010213 ,0 ,64 *1024 ,16 ,0 ) }, - {"s25sl016a" ,INFO (0x010214 ,0 ,64 *1024 ,32 ,0 ) }, - {"s25sl032a" ,INFO (0x010215 ,0 ,64 *1024 ,64 ,0 ) }, - {"s25sl064a" ,INFO (0x010216 ,0 ,64 *1024 ,128 ,0 ) }, - {"s25fl008k" ,INFO (0xef4014 ,0 ,64 *1024 ,16 ,SECT_4K ) }, - {"s25fl016k" ,INFO (0xef4015 ,0 ,64 *1024 ,32 ,SECT_4K ) }, - {"s25fl064k" ,INFO (0xef4017 ,0 ,64 *1024 ,128 ,SECT_4K ) }, - -/* SST -- large erase sizes are "overlays", "sectors" are 4K */ - {"sst25vf040b" ,INFO (0xbf258d ,0 ,64 *1024 ,8 ,SECT_4K |SST_WRITE ) }, - {"sst25vf080b" ,INFO (0xbf258e ,0 ,64 *1024 ,16 ,SECT_4K |SST_WRITE ) }, - {"sst25vf016b" ,INFO (0xbf2541 ,0 ,64 *1024 ,32 ,SECT_4K |SST_WRITE ) }, - {"sst25vf032b" ,INFO (0xbf254a ,0 ,64 *1024 ,64 ,SECT_4K |SST_WRITE ) }, - {"sst25vf064c" ,INFO (0xbf254b ,0 ,64 *1024 ,128 ,SECT_4K ) }, - {"sst25wf512" ,INFO (0xbf2501 ,0 ,64 *1024 ,1 ,SECT_4K |SST_WRITE ) }, - {"sst25wf010" ,INFO (0xbf2502 ,0 ,64 *1024 ,2 ,SECT_4K |SST_WRITE ) }, - {"sst25wf020" ,INFO (0xbf2503 ,0 ,64 *1024 ,4 ,SECT_4K |SST_WRITE ) }, - {"sst25wf040" ,INFO (0xbf2504 ,0 ,64 *1024 ,8 ,SECT_4K |SST_WRITE ) }, - -/* ST Microelectronics -- newer production may have feature updates */ - {"m25p05" ,INFO (0x202010 ,0 ,32 *1024 ,2 ,0 ) }, - {"m25p10" ,INFO (0x202011 ,0 ,32 *1024 ,4 ,0 ) }, - {"m25p20" ,INFO (0x202012 ,0 ,64 *1024 ,4 ,0 ) }, - {"m25p40" ,INFO (0x202013 ,0 ,64 *1024 ,8 ,0 ) }, - {"m25p80" ,INFO (0x202014 ,0 ,64 *1024 ,16 ,0 ) }, - {"m25p16" ,INFO (0x202015 ,0 ,64 *1024 ,32 ,0 ) }, - {"m25p32" ,INFO (0x202016 ,0 ,64 *1024 ,64 ,0 ) }, - {"m25p64" ,INFO (0x202017 ,0 ,64 *1024 ,128 ,0 ) }, - {"m25p128" ,INFO (0x202018 ,0 ,256 *1024 ,64 ,0 ) }, - {"n25q032" ,INFO (0x20ba16 ,0 ,64 *1024 ,64 ,0 ) }, - - {"m25p05-nonjedec" ,INFO (0 ,0 ,32 *1024 ,2 ,0 ) }, - {"m25p10-nonjedec" ,INFO (0 ,0 ,32 *1024 ,4 ,0 ) }, - {"m25p20-nonjedec" ,INFO (0 ,0 ,64 *1024 ,4 ,0 ) }, - {"m25p40-nonjedec" ,INFO (0 ,0 ,64 *1024 ,8 ,0 ) }, - {"m25p80-nonjedec" ,INFO (0 ,0 ,64 *1024 ,16 ,0 ) }, - {"m25p16-nonjedec" ,INFO (0 ,0 ,64 *1024 ,32 ,0 ) }, - {"m25p32-nonjedec" ,INFO (0 ,0 ,64 *1024 ,64 ,0 ) }, - {"m25p64-nonjedec" ,INFO (0 ,0 ,64 *1024 ,128 ,0 ) }, - {"m25p128-nonjedec" ,INFO (0 ,0 ,256 *1024 ,64 ,0 ) }, - - {"m45pe10" ,INFO (0x204011 ,0 ,64 *1024 ,2 ,0 ) }, - {"m45pe80" ,INFO (0x204014 ,0 ,64 *1024 ,16 ,0 ) }, - {"m45pe16" ,INFO (0x204015 ,0 ,64 *1024 ,32 ,0 ) }, - - {"m25pe20" ,INFO (0x208012 ,0 ,64 *1024 ,4 ,0 ) }, - {"m25pe80" ,INFO (0x208014 ,0 ,64 *1024 ,16 ,0 ) }, - {"m25pe16" ,INFO (0x208015 ,0 ,64 *1024 ,32 ,SECT_4K ) }, - - {"m25px16" ,INFO (0x207115 ,0 ,64 *1024 ,32 ,SECT_4K ) }, - {"m25px32" ,INFO (0x207116 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - {"m25px32-s0" ,INFO (0x207316 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - {"m25px32-s1" ,INFO (0x206316 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - {"m25px64" ,INFO (0x207117 ,0 ,64 *1024 ,128 ,0 ) }, - -/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ - {"w25x10" ,INFO (0xef3011 ,0 ,64 *1024 ,2 ,SECT_4K ) }, - {"w25x20" ,INFO (0xef3012 ,0 ,64 *1024 ,4 ,SECT_4K ) }, - {"w25x40" ,INFO (0xef3013 ,0 ,64 *1024 ,8 ,SECT_4K ) }, - {"w25x80" ,INFO (0xef3014 ,0 ,64 *1024 ,16 ,SECT_4K ) }, - {"w25x16" ,INFO (0xef3015 ,0 ,64 *1024 ,32 ,SECT_4K ) }, - {"w25x32" ,INFO (0xef3016 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - {"w25q32" ,INFO (0xef4016 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - {"w25q32dw" ,INFO (0xef6016 ,0 ,64 *1024 ,64 ,SECT_4K ) }, - {"w25x64" ,INFO (0xef3017 ,0 ,64 *1024 ,128 ,SECT_4K ) }, - {"w25q64" ,INFO (0xef4017 ,0 ,64 *1024 ,128 ,SECT_4K ) }, - {"w25q128" ,INFO (0xef4018 ,0 ,64 *1024 ,256 ,SECT_4K ) }, - {"w25q80" ,INFO (0xef5014 ,0 ,64 *1024 ,16 ,SECT_4K ) }, - {"w25q80bl" ,INFO (0xef4014 ,0 ,64 *1024 ,16 ,SECT_4K ) }, - {"w25q128" ,INFO (0xef4018 ,0 ,64 *1024 ,256 ,SECT_4K ) }, - {"w25q256" ,INFO (0xef4019 ,0 ,64 *1024 ,512 ,SECT_4K ) }, - -/* Catalyst / On Semiconductor -- non-JEDEC */ - {"cat25c11" ,CAT25_INFO (16 ,8 ,16 ,1 ,M25P_NO_ERASE |M25P_NO_FR ) }, - {"cat25c03" ,CAT25_INFO (32 ,8 ,16 ,2 ,M25P_NO_ERASE |M25P_NO_FR ) }, - {"cat25c09" ,CAT25_INFO (128 ,8 ,32 ,2 ,M25P_NO_ERASE |M25P_NO_FR ) }, - {"cat25c17" ,CAT25_INFO (256 ,8 ,32 ,2 ,M25P_NO_ERASE |M25P_NO_FR ) }, - {"cat25128" ,CAT25_INFO (2048 ,8 ,64 ,2 ,M25P_NO_ERASE |M25P_NO_FR ) }, - { }, -}; -MODULE_DEVICE_TABLE (spi, m25p_ids); - -static const struct spi_device_id *jedec_probe (struct spi_device *spi) -{ -int tmp; -u8 code =OPCODE_RDID ; -u8 id[5 ]; -u32 jedec; -u16 ext_jedec; -struct flash_info *info; +return ret; -/* JEDEC also defines an optional "extended device information" -* string for after vendor-specific data, after the three bytes -* we use here. Supporting some chips might require using it. -*/ - tmp =spi_write_then_read (spi, &code,1 , id,5 ); -if (tmp <0 ) { -pr_debug ("%s: error %d reading JEDEC ID\n" , -dev_name (&spi->dev), tmp); -return ERR_PTR (tmp); - } - jedec = id[0 ]; - jedec = jedec <<8 ; - jedec |= id[1 ]; - jedec = jedec <<8 ; - jedec |= id[2 ]; +/* Set up command buffer. */ + flash->command[0 ] = nor->erase_opcode; +m25p_addr2cmd (nor, offset, flash->command); - ext_jedec = id[3 ] <<8 | id[4 ]; +spi_write (flash->spi, flash->command,m25p_cmdsz (nor)); -for (tmp =0 ; tmp <ARRAY_SIZE (m25p_ids) -1 ; tmp++) { - info = (void *)m25p_ids[tmp].driver_data; -if (info->jedec_id == jedec) { -if (info->ext_id ==0 || info->ext_id == ext_jedec) -return &m25p_ids[tmp]; - } - } -dev_err (&spi->dev,"unrecognized JEDEC id %06x\n" , jedec); -return ERR_PTR (-ENODEV ); +return 0 ; } -/* * board specific setup should have ensured the SPI clock used here * matches what the READ command supports, at least until this driver
@@ -1095,231 +191,43 @@ static const struct spi_device_id *jedec_probe(struct spi_device *spi)*/ static int m25p_probe (struct spi_device *spi) { -const struct spi_device_id *id =spi_get_device_id (spi); -struct flash_platform_data *data; -struct m25p *flash; -struct flash_info *info; -unsigned i;struct mtd_part_parser_data ppdata; -struct device_node *np = spi->dev.of_node; +struct flash_platform_data *data; +struct m25p *flash; +struct spi_nor *nor; +enum read_mode mode =SPI_NOR_NORMAL ;int 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 (&spi->dev); -if (data && data->type) { -const struct spi_device_id *plat_id; - -for (i =0 ; i <ARRAY_SIZE (m25p_ids) -1 ; i++) { - plat_id = &m25p_ids[i]; -if (strcmp (data->type, plat_id->name)) -continue ; -break ; - } - -if (i <ARRAY_SIZE (m25p_ids) -1 ) - id = plat_id; -else -dev_warn (&spi->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 (spi); -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 (&spi->dev,"found %s, expected %s\n" , - jid->name, id->name); - id = jid; - info = (void *)jid->driver_data; - } - } - flash =devm_kzalloc (&spi->dev,sizeof (*flash),GFP_KERNEL );if (!flash)return -ENOMEM ; - flash->command =devm_kzalloc (&spi->dev,MAX_CMD_SIZE ,GFP_KERNEL ); -if (!flash->command) -return -ENOMEM ; - - flash->spi = spi; -mutex_init (&flash->lock); -spi_set_drvdata (spi, flash); - -/* -* Atmel, SST and Intel/Numonyx serial flash tend to power -* up with the software protection bits set -*/ + nor = &flash->spi_nor; -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 (flash); -write_sr (flash,0 ); - } - -if (data && data->name) - flash->mtd.name = data->name; -else - flash->mtd.name =dev_name (&spi->dev); - - flash->mtd.type =MTD_NORFLASH ; - flash->mtd.writesize =1 ; - flash->mtd.flags =MTD_CAP_NORFLASH ; - flash->mtd.size = info->sector_size * info->n_sectors; - flash->mtd._erase = m25p80_erase; - flash->mtd._read = m25p80_read; - -/* flash protection support for STmicro chips */ -if (JEDEC_MFR (info->jedec_id) ==CFI_MFR_ST ) { - flash->mtd._lock = m25p80_lock; - flash->mtd._unlock = m25p80_unlock; - } +/* install the hooks */ + nor->read = m25p80_read; + nor->write = m25p80_write; + nor->erase = m25p80_erase; + nor->write_reg = m25p80_write_reg; + nor->read_reg = m25p80_read_reg; -/* sst flash chips use AAI word program */ -if (info->flags &SST_WRITE ) - flash->mtd._write = sst_write; -else - flash->mtd._write = m25p80_write; + nor->dev = &spi->dev; + nor->mtd = &flash->mtd; + nor->priv = flash; -/* prefer "small sector" erase if possible */ -if (info->flags &SECT_4K ) { - flash->erase_opcode =OPCODE_BE_4K ; - flash->mtd.erasesize =4096 ; - }else if (info->flags &SECT_4K_PMC ) { - flash->erase_opcode =OPCODE_BE_4K_PMC ; - flash->mtd.erasesize =4096 ; - }else { - flash->erase_opcode =OPCODE_SE ; - flash->mtd.erasesize = info->sector_size; - } +spi_set_drvdata (spi, flash); + flash->mtd.priv = nor; + flash->spi = spi; -if (info->flags &M25P_NO_ERASE ) - flash->mtd.flags |=MTD_NO_ERASE ; +if (spi->mode &SPI_RX_QUAD ) + mode =SPI_NOR_QUAD ; + ret =spi_nor_scan (nor,spi_get_device_id (spi), mode); +if (ret) +return ret; + data =dev_get_platdata (&spi->dev); ppdata.of_node = spi->dev.of_node; - flash->mtd.dev.parent = &spi->dev; - flash->page_size = info->page_size; - flash->mtd.writebufsize = flash->page_size; - -if (np) { -/* If we were instantiated by DT, use it */ -if (of_property_read_bool (np,"m25p,fast-read" )) - flash->flash_read =M25P80_FAST ; -else - flash->flash_read =M25P80_NORMAL ; - }else { -/* If we weren't instantiated by DT, default to fast-read */ - flash->flash_read =M25P80_FAST ; - } - -/* Some devices cannot do fast-read, no matter what DT tells us */ -if (info->flags &M25P_NO_FR ) - flash->flash_read =M25P80_NORMAL ; - -/* Quad/Dual-read mode takes precedence over fast/normal */ -if (spi->mode &SPI_RX_QUAD && info->flags &M25P80_QUAD_READ ) { - ret =set_quad_mode (flash, info->jedec_id); -if (ret) { -dev_err (&flash->spi->dev,"quad mode not supported\n" ); -return ret; - } - flash->flash_read =M25P80_QUAD ; - }else if (spi->mode &SPI_RX_DUAL && info->flags &M25P80_DUAL_READ ) { - flash->flash_read =M25P80_DUAL ; - } -/* Default commands */ -switch (flash->flash_read) { -case M25P80_QUAD : - flash->read_opcode =OPCODE_QUAD_READ ; -break ; -case M25P80_DUAL : - flash->read_opcode =OPCODE_DUAL_READ ; -break ; -case M25P80_FAST : - flash->read_opcode =OPCODE_FAST_READ ; -break ; -case M25P80_NORMAL : - flash->read_opcode =OPCODE_NORM_READ ; -break ; -default : -dev_err (&flash->spi->dev,"No Read opcode defined\n" ); -return -EINVAL ; - } - - flash->program_opcode =OPCODE_PP ; - -if (info->addr_width) - flash->addr_width = info->addr_width; -else if (flash->mtd.size >0x1000000 ) { -/* enable 4-byte addressing if the device exceeds 16MiB */ - flash->addr_width =4 ; -if (JEDEC_MFR (info->jedec_id) ==CFI_MFR_AMD ) { -/* Dedicated 4-byte command set */ -switch (flash->flash_read) { -case M25P80_QUAD : - flash->read_opcode =OPCODE_QUAD_READ_4B ; -break ; -case M25P80_DUAL : - flash->read_opcode =OPCODE_DUAL_READ_4B ; -break ; -case M25P80_FAST : - flash->read_opcode =OPCODE_FAST_READ_4B ; -break ; -case M25P80_NORMAL : - flash->read_opcode =OPCODE_NORM_READ_4B ; -break ; - } - flash->program_opcode =OPCODE_PP_4B ; -/* No small sector erase for 4-byte command set */ - flash->erase_opcode =OPCODE_SE_4B ; - flash->mtd.erasesize = info->sector_size; - }else -set_4byte (flash, info->jedec_id,1 ); - }else { - flash->addr_width =3 ; - } - -dev_info (&spi->dev,"%s (%lld Kbytes)\n" , id->name, - (long long )flash->mtd.size >>10 ); - -pr_debug ("mtd .name = %s, .size = 0x%llx (%lldMiB) " -".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n" , - flash->mtd.name, - (long long )flash->mtd.size, (long long )(flash->mtd.size >>20 ), - flash->mtd.erasesize, flash->mtd.erasesize /1024 , - flash->mtd.numeraseregions); - -if (flash->mtd.numeraseregions) -for (i =0 ; i < flash->mtd.numeraseregions; i++) -pr_debug ("mtd.eraseregions[%d] = { .offset = 0x%llx, " -".erasesize = 0x%.8x (%uKiB), " -".numblocks = %d }\n" , - i, (long long )flash->mtd.eraseregions[i].offset, - flash->mtd.eraseregions[i].erasesize, - flash->mtd.eraseregions[i].erasesize /1024 , - flash->mtd.eraseregions[i].numblocks); - - -/* partitions should match sector boundaries; and it may be good to -* use readonly partitions for writeprotected sectors (BP2..BP0). -*/ return mtd_device_parse_register (&flash->mtd,NULL , &ppdata, data ? data->parts :NULL , data ? data->nr_parts :0 );
@@ -1340,7 +248,7 @@ static struct spi_driver m25p80_driver = { .name = "m25p80", .owner = THIS_MODULE, }, - .id_table = m25p_ids, + .id_table = spi_nor_ids, .probe = m25p_probe, .remove = m25p_remove,
Signature · 1 line
1.7.2.rc3
PATCH v5 5/8 mtd: m25p80: use the SPI nor framework
Use the new SPI nor framework, and rewrite the m25p80:
(0) remove all the NOR comands.
(1) change the m25p->command to an array.
(2) implement the necessary hooks, such as m25p80_read/m25p80_write.
Tested with the m25p32.
---
add back the dependency information in the Kconfig.
--- drivers/mtd/devices/Kconfig | 2 +- drivers/mtd/devices/m25p80.c | 1302 ++++-------------------------------------- 2 files changed, 106 insertions(+), 1198 deletions(-)
drivers/mtd/devices/Kconfig +1 -1
@@ -80,7 +80,7 @@ config MTD_DATAFLASH_OTP config MTD_M25P80 tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" - depends on SPI_MASTER + depends on SPI_MASTER && MTD_SPI_NOR_BASE help This enables access to most modern SPI flash chips, used for program and data storage. Series supported include Atmel AT26DF,
drivers/mtd/devices/m25p80.c +105 -1197
1,417 lines not on this page · raw message
Signature · 1 line
1.7.2.rc3
PATCH v5 5/8 mtd: m25p80: use the SPI nor framework
+ Russell
Quoted 12 lines · Huang Shijie
add back the dependency information in the
Kconfig.--- drivers/mtd/devices/Kconfig | 2 +- drivers/mtd/devices/m25p80.c | 1302 ++++-------------------------------------- 2 files changed, 106 insertions(+), 1198 deletions(-)drivers/mtd/devices/Kconfig +0
-0
drivers/mtd/devices/Kconfig config MTD_DATAFLASH_OTP · line 86
Quoted 8 lines
drivers/mtd/devices/Kconfig +1
-1@@ -80,7 +80,7 @@ config MTD_DATAFLASH_OTP config MTD_M25P80 tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" - depends on SPI_MASTER + depends on SPI_MASTER && MTD_SPI_NOR_BASE help This enables access to most modern SPI flash chips, used for program and data storage. Series supported include Atmel AT26DF,
Now that M25P80 depends on MTD_SPI_NOR_BASE (which I proposed to rename to MTD_SPI_NOR a few hours ago), shouldn't we be updating everybody's defconfigs? As it stands, the defconfigs that use M25P80 will just drop it silently when built.
And if so, I'm not sure how this should be handled. Should defconfig patches be sent to their respective arch maintainers?
Also, I think m25p80.c is no longer a "self-contained MTD device driver" and should be moved under drivers/mtd/spi-nor/.
(Once these questions are settled, did you want to handle cooking the patches, Huang, or should I?)
Brian
PATCH v5 5/8 mtd: m25p80: use the SPI nor framework
Quoted 13 lines · Brian Norris
drivers/mtd/devices/Kconfig config MTD_DATAFLASH_OTP · line 86
Quoted 7 lines
config
MTD_M25P80drivers/mtd/devices/Kconfig +1
-1tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" - depends on SPI_MASTER + depends on SPI_MASTER && MTD_SPI_NOR_BASE help This enables access to most modern SPI flash chips, used for program and data storage. Series supported include Atmel AT26DF,Now that M25P80 depends on
MTD_SPI_NOR_BASE(which I proposed to rename toMTD_SPI_NORa few hours ago), shouldn't we be updating everybody's defconfigs? As it stands, the defconfigs that use M25P80 will just drop it silently when built.
Quoted 2 lines
And if so, I'm not sure how this should be handled. Should defconfig patches be sent to their respective arch maintainers?
IMHO, we should create a patch or several patches to add the MTD_SPI_NOR to the defconfigs.
Another method is to select the MTD_SPI_NOR which we enable the MTD.
Quoted 3 lines
Also, I think
m25p80.cis no longer a "self-contained MTD device driver" and should be moved underdrivers/mtd/spi-nor/.
If we move the m25p80.c to the drivers/mtd/spi-nor/, we also need to move other drivers too.
thanks
Huang Shijie
PATCH v5 5/8 mtd: m25p80: use the SPI nor framework
Quoted 14 lines · Huang Shijie
Quoted 13 lines · Brian Norris
drivers/mtd/devices/Kconfig config MTD_DATAFLASH_OTP · line 86
Quoted 7 lines
config
MTD_M25P80drivers/mtd/devices/Kconfig +1
-1tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" - depends on SPI_MASTER + depends on SPI_MASTER && MTD_SPI_NOR_BASE help This enables access to most modern SPI flash chips, used for program and data storage. Series supported include Atmel AT26DF,Now that M25P80 depends on
MTD_SPI_NOR_BASE(which I proposed to rename toMTD_SPI_NORa few hours ago), shouldn't we be updating everybody's defconfigs? As it stands, the defconfigs that use M25P80 will just drop it silently when built.
Quoted 5 lines
Quoted 2 lines
And if so, I'm not sure how this should be handled. Should defconfig patches be sent to their respective arch maintainers?
IMHO, we should create a patch or several patches to add the
MTD_SPI_NORto the defconfigs.
Yeah, I think that's best.
Quoted 1 line
Another method is to select the
MTD_SPI_NORwhich we enable the MTD.
I'm pretty sure it's a rule that drivers should not 'select' subsystems.
Quoted 4 lines
Quoted 2 lines
Also, I think
m25p80.cis no longer a "self-contained MTD device driver" and should be moved underdrivers/mtd/spi-nor/.If we move the
m25p80.cto thedrivers/mtd/spi-nor/, we also need to move other drivers too.
Which ones? I think it only makes sense to move those that depend on the same core code (i.e., spi-nor.c), or have a close relation to it (so Lee's st_spi_fsm.c is a candidate).
Brian
PATCH v5 5/8 mtd: m25p80: use the SPI nor framework
Quoted 4 lines · Brian Norris
Quoted 2 lines
IMHO, we should create a patch or several patches to add the
MTD_SPI_NORto the defconfigs.Yeah, I think that's best.
I will create a patch when i back to office.
Or you can create it yourself.
Quoted 9 lines
Quoted 5 lines
Quoted 3 lines
Also, I think
m25p80.cis no longer a "self-contained MTD device driver" and should be moved underdrivers/mtd/spi-nor/.If we move the
m25p80.cto thedrivers/mtd/spi-nor/, we also need to move other drivers too.Which ones? I think it only makes sense to move those that depend on the same core code (i.e.,
spi-nor.c), or have a close relation to it (so Lee'sst_spi_fsm.cis a candidate).
yes, i mean the st_spi_fsm.c and other drivers which will use the spi-nor core code in the future.
thanks
Huang Shijie
PATCH v5 5/8 mtd: m25p80: use the SPI nor framework
Quoted 14 lines · Huang Shijie
Quoted 4 lines · Brian Norris
Quoted 2 lines
IMHO, we should create a patch or several patches to add the
MTD_SPI_NORto the defconfigs.Yeah, I think that's best.
I will create a patch when i back to office.
Or you can create it yourself.Quoted 6 lines
Quoted 5 lines
Quoted 3 lines
Also, I think
m25p80.cis no longer a "self-contained MTD device driver" and should be moved underdrivers/mtd/spi-nor/.If we move the
m25p80.cto thedrivers/mtd/spi-nor/, we also need to move other drivers too.
Quoted 6 lines
Quoted 3 lines
Which ones? I think it only makes sense to move those that depend on the same core code (i.e.,
spi-nor.c), or have a close relation to it (so Lee'sst_spi_fsm.cis a candidate).yes, i mean the
st_spi_fsm.cand other drivers which will use the spi-nor core code in the future.
+1 - happy with this.
Signature · 4 lines
Lee Jones Linaro STMicroelectronics Landing Team Lead Linaro.org ? Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
PATCH v5 6/8 mtd: spi-nor: add a helper to find the spi_device_id
In reply to Huang ShijieAdd the spi_nor_match_id() to find the proper spi_device_id with the NOR flash's name in the spi_nor_ids table.
--- drivers/mtd/spi-nor/spi-nor.c | 12 ++++++++++++ include/linux/mtd/spi-nor.h | 12 ++++++++++++ 2 files changed, 24 insertions(+), 0 deletions(-)
drivers/mtd/spi-nor/spi-nor.c +12 -0
@@ -1081,6 +1081,18 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,return 0 ; } +const struct spi_device_id *spi_nor_match_id (char *name) +{ +const struct spi_device_id *id = spi_nor_ids; + +while (id->name[0 ]) { +if (!strcmp (name, id->name)) +return id; + id++; + } +return NULL ; +} +MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("Huang Shijie <[email protected]>" );MODULE_AUTHOR ("Mike Lavender" );
include/linux/mtd/spi-nor.h +12 -0
@@ -182,4 +182,16 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, enum read_mode mode);extern const struct spi_device_id spi_nor_ids[]; +/** +* spi_nor_match_id() - find the spi_device_id by the name +* @name: the name of the spi_device_id +* +* The drivers use this function to find the spi_device_id +* specified by the @name. +* +* Return: returns the right spi_device_id pointer on success, +* and returns NULL on failure. +*/ +const struct spi_device_id *spi_nor_match_id (char *name); +#endif
Signature · 1 line
1.7.2.rc3
PATCH v5 7/8 Documentation: add the binding file for Freescale QuadSPI driver
In reply to Huang ShijieThis patch adds the binding file for Freescale QuadSPI driver.
--- .../devicetree/bindings/mtd/fsl-quadspi.txt | 35 ++++++++++++++++++++ 1 files changed, 35 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/mtd/fsl-quadspi.txt
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +35 -0
@@ -0,0 +1,35 @@ +* Freescale Quad Serial Peripheral Interface(QuadSPI) + +Required properties: + - compatible : Should be "fsl,vf610-qspi" + - reg : the first contains the register location and length, + the second contains the memory mapping address and length + - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" + - interrupts : Should contain the interrupt for the device + - clocks : The clocks needed by the QuadSPI controller + - clock-names : the name of the clocks + +Optional properties: + - fsl,qspi-has-second-chip: The controller has two buses, bus A and bus B. + Each bus can be connected with two NOR flashes. + Most of the time, each bus only has one NOR flash + connected, this is the default case. + But if there are two NOR flashes connected to the + bus, you should enable this property. + (Please check the board's schematic.) + +Example: + +qspi0: quadspi at 40044000 { + compatible = "fsl,vf610-qspi"; + reg = <0x40044000 0x1000>, <0x20000000 0x10000000>; + reg-names = "QuadSPI", "QuadSPI-memory"; + interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks VF610_CLK_QSPI0_EN>, + <&clks VF610_CLK_QSPI0>; + clock-names = "qspi_en", "qspi"; + + flash0: s25fl128s at 0 { + .... + }; +};
Signature · 1 line
1.7.2.rc3
PATCH v5 8/8 mtd: spi-nor: Add Freescale QuadSPI driver
In reply to Huang Shijie(0) What is the QuadSPI controller?
The QuadSPI(Quad Serial Peripheral Interface) acts as an interface to one single or two external serial flash devices, each with up to 4 bidirectional data lines.
(1) The QuadSPI controller is driven by the LUT(Look-up Table) registers. The LUT registers are a look-up-table for sequences of instructions. A valid sequence consists of four LUT registers.
(2) The definition of the LUT register shows below:
---------------------------------------------------
| INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
---------------------------------------------------
There are several types of INSTRx, such as:
CMD : the SPI NOR command.
ADDR : the address for the SPI NOR command.
DUMMY : the dummy cycles needed by the SPI NOR command.
....
There are several types of PADx, such as:
PAD1 : use a singe I/O line.
PAD2 : use two I/O lines.
PAD4 : use quad I/O lines.
....
(3) Test this driver with the JFFS2 and UBIFS:
For jffs2:
-------------
#flash_eraseall /dev/mtd0
#mount -t jffs2 /dev/mtdblock0 tmp
#bonnie++ -d tmp -u 0 -s 10 -r 5
For ubifs:
-------------
#flash_eraseall /dev/mtd0
#ubiattach /dev/ubi_ctrl -m 0
#ubimkvol /dev/ubi0 -N test -m
#mount -t ubifs ubi0:test tmp
#bonnie++ -d tmp -u 0 -s 10 -r 5
--- drivers/mtd/spi-nor/Kconfig | 6 + drivers/mtd/spi-nor/Makefile | 1 + drivers/mtd/spi-nor/fsl-quadspi.c | 1009 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1016 insertions(+), 0 deletions(-) create mode 100644 drivers/mtd/spi-nor/fsl-quadspi.c
drivers/mtd/spi-nor/Kconfig +6 -0
@@ -4,3 +4,9 @@ config MTD_SPI_NOR_BASE help This is the framework for the SPI NOR which can be used by the SPI device drivers and the SPI-NOR device driver. +config SPI_FSL_QUADSPI + tristate "Freescale Quad SPI controller" + depends on ARCH_MXC && MTD_SPI_NOR_BASE + help + This enables support for the Quad SPI controller in master mode. + We only connect the NOR to this controller now.
drivers/mtd/spi-nor/Makefile +1 -0
@@ -1 +1,2 @@ obj-$(CONFIG_MTD_SPI_NOR_BASE) += spi-nor.o +obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
drivers/mtd/spi-nor/fsl-quadspi.c new file +1009 -0
1,009 lines not on this page · raw message
Signature · 1 line
1.7.2.rc3
v5 cover mtd: spi-nor: add a new framework for SPI NOR
In reply to Huang ShijieQuoted 43 lines · Huang Shijie
1.) Why add a new framework for SPI NOR?
The SPI-NOR controller such as Freescale's Quadspi controller is working in a different way from the SPI bus. It should knows the NOR commands to find the right LUT sequence. Unfortunately, the current code can not meet this requirement.2.) How does this patch set do?
This patch set adds a new spi-nor layer.
Before this patch, the layer is like:MTD ------------------------ m25p80 ------------------------ spi bus driver ------------------------ SPI NOR chipAfter this patch, the layer is like: MTD ------------------------ spi-nor ------------------------ m25p80 ------------------------ spi bus driver ------------------------ SPI NOR chipWith the spi-nor controller driver(Freescale Quadspi), it looks like:
MTD ------------------------ spi-nor ------------------------ fsl-quadspi ------------------------ SPI NOR chip3.) more details
This patch set adds a new data structrue spi_nor{}, clones most the
common code tospi-nor.c. Addspi_nor_xfer_cfg{} for the fundamental
primitives: read_xfer/write_xfer.
Quoted 7 lines
Make the
m25p80.c/fsl_quaspi.cuse the new APIs.4.) Change log:
v4 --> v5:
[1] rebase the patch set on the l2-mtd tree.
[2] fixed bugs in the fsl-quadspi driver.
[3] tested the fsl-quadspi with imx6sx board.
It's starting to take a really nice shape, I really like it :)
v5 cover mtd: spi-nor: add a new framework for SPI NOR
In reply to Huang ShijieOn Mon, Feb 24, 2014 at 06:37:34PM +0800, Huang Shijie wrote:
Hi Brian:
Could you please review this patch set? I really hope it can be merged as soon as possibel. But now, the patch set has stalled for a long time.
Since you have pushed the patches for m25p80.c, i have to rebase this patch set again and again...
thanks
Huang Shijie
v5 cover mtd: spi-nor: add a new framework for SPI NOR
Quoted 3 lines · Huang Shijie
On Mon, Feb 24, 2014 at 06:37:34PM +0800, Huang Shijie wrote:
Could you please review this patch set? I really hope it can be merged as soon as possibel. But now, the patch set has stalled for a long time.
I'm sorry for the delay. Others are in the same position of delay (e.g., Lee's SPI-NOR driver), because I simply have not had the time to really devote this the attention it deserves, especially considering how it rearchitects such an important, commonly-used driver.
Nonetheless, I will try to give your patches some more attention soon.
Quoted 2 lines
Since you have pushed the patches for
m25p80.c, i have to rebase this patch set again and again...
You mean locally? I promise you, I can handle rebasing on my reviewing end for small one-line conflicts like new chip IDs, so don't rebase and resend simply for that. Unless I find substantive things that you should change, I'd only expect at most one more rebase to be necessary.
Brian
v5 cover mtd: spi-nor: add a new framework for SPI NOR
+ Lee, Marek
Hi Huang,
Quoted 12 lines · Brian Norris
Quoted 3 lines · Huang Shijie
On Mon, Feb 24, 2014 at 06:37:34PM +0800, Huang Shijie wrote:
Could you please review this patch set? I really hope it can be merged as soon as possibel. But now, the patch set has stalled for a long time.I'm sorry for the delay. Others are in the same position of delay (e.g., Lee's SPI-NOR driver), because I simply have not had the time to really devote this the attention it deserves, especially considering how it rearchitects such an important, commonly-used driver.
Nonetheless, I will try to give your patches some more attention soon.
Quoted 7 lines
Quoted 2 lines
Since you have pushed the patches for
m25p80.c, i have to rebase this patch set again and again...You mean locally? I promise you, I can handle rebasing on my reviewing end for small one-line conflicts like new chip IDs, so don't rebase and resend simply for that. Unless I find substantive things that you should change, I'd only expect at most one more rebase to be necessary.
Unfortunately, I did not get the time to review and test this sufficiently for the 3.15 merge window, but to avoid further delay, I've queued it up in l2-mtd.git [1] under its own branch for now. I rebased it myself, to accommodate for changes to m25p80.c since your submission. Please take a look at the branch.
If all goes well, I should merge the spinor branch into master some time after the 3.15 merge window closes, so it will get linux-next testing. For any additional comments/corrections (I have a few), please just submit patches on top, rather than resending the whole series.
Marek, what was your opinion on this series? Last response I saw was "looking good"; is that an Ack? Or did you have any more gating requests?
Personally, I think it looks ready enough, and it's better to merge this than not. I was able to test with my platforms, with no regression.
Lee, I have a few patches that do some trivial unification of your ST SPI FSM driver and the SPI-NOR framework. I plan to send these out soon, and I will begin applying any ST-FSM patches to the same spinor branch along with Huang's code. I hope that you can spend some effort on improving integration within the next few months in preparation for 3.16, when I expect this to all go upstream.
Thanks,
Brian
[1] branch spinor, at http://git.infradead.org/l2-mtd.git
v5 cover mtd: spi-nor: add a new framework for SPI NOR
? 2014?04?09? 11:36, Brian Norris ??:
Quoted 2 lines
For any additional comments/corrections (I have a few), please just submit patches on top, rather than resending the whole series.
thanks a lot!
i am happy that we can add more features on base of the spi nor framework.
Huang Shijie
v5 cover mtd: spi-nor: add a new framework for SPI NOR
In reply to Brian NorrisQuoted 37 lines · Brian Norris
+ Lee, Marek
Hi Huang,
Quoted 13 lines · Brian Norris
Quoted 4 lines · Huang Shijie
On Mon, Feb 24, 2014 at 06:37:34PM +0800, Huang Shijie wrote:
Could you please review this patch set? I really hope it can be merged as soon as possibel. But now, the patch set has stalled for a long time.I'm sorry for the delay. Others are in the same position of delay (e.g., Lee's SPI-NOR driver), because I simply have not had the time to really devote this the attention it deserves, especially considering how it rearchitects such an important, commonly-used driver.
Nonetheless, I will try to give your patches some more attention soon.
Quoted 7 lines
Quoted 2 lines
Since you have pushed the patches for
m25p80.c, i have to rebase this patch set again and again...You mean locally? I promise you, I can handle rebasing on my reviewing end for small one-line conflicts like new chip IDs, so don't rebase and resend simply for that. Unless I find substantive things that you should change, I'd only expect at most one more rebase to be necessary.
Unfortunately, I did not get the time to review and test this sufficiently for the 3.15 merge window, but to avoid further delay, I've queued it up in l2-mtd.git [1] under its own branch for now. I rebased it myself, to accommodate for changes to
m25p80.csince your submission. Please take a look at the branch.If all goes well, I should merge the spinor branch into master some time after the 3.15 merge window closes, so it will get linux-next testing. For any additional comments/corrections (I have a few), please just submit patches on top, rather than resending the whole series.
Quoted 6 lines
Marek, what was your opinion on this series? Last response I saw was "looking good"; is that an Ack? Or did you have any more gating requests?
Personally, I think it looks ready enough, and it's better to merge this than not. I was able to test with my platforms, with no regression.
It looked OK to me, so that's an:
Thanks for watching over this!
Best regards,
Marek Vasut
v5 cover mtd: spi-nor: add a new framework for SPI NOR
In reply to Brian NorrisQuoted 43 lines
+ Lee, Marek
Hi Huang,
Quoted 12 lines · Brian Norris
Quoted 3 lines · Huang Shijie
On Mon, Feb 24, 2014 at 06:37:34PM +0800, Huang Shijie wrote:
Could you please review this patch set? I really hope it can be merged as soon as possibel. But now, the patch set has stalled for a long time.I'm sorry for the delay. Others are in the same position of delay (e.g., Lee's SPI-NOR driver), because I simply have not had the time to really devote this the attention it deserves, especially considering how it rearchitects such an important, commonly-used driver.
Nonetheless, I will try to give your patches some more attention soon.
Quoted 7 lines
Quoted 2 lines
Since you have pushed the patches for
m25p80.c, i have to rebase this patch set again and again...You mean locally? I promise you, I can handle rebasing on my reviewing end for small one-line conflicts like new chip IDs, so don't rebase and resend simply for that. Unless I find substantive things that you should change, I'd only expect at most one more rebase to be necessary.
Unfortunately, I did not get the time to review and test this sufficiently for the 3.15 merge window, but to avoid further delay, I've queued it up in l2-mtd.git [1] under its own branch for now. I rebased it myself, to accommodate for changes to
m25p80.csince your submission. Please take a look at the branch.If all goes well, I should merge the spinor branch into master some time after the 3.15 merge window closes, so it will get linux-next testing. For any additional comments/corrections (I have a few), please just submit patches on top, rather than resending the whole series.
Marek, what was your opinion on this series? Last response I saw was "looking good"; is that an Ack? Or did you have any more gating requests?
Personally, I think it looks ready enough, and it's better to merge this than not. I was able to test with my platforms, with no regression.
Quoted 6 lines
Lee, I have a few patches that do some trivial unification of your ST SPI FSM driver and the SPI-NOR framework. I plan to send these out soon, and I will begin applying any ST-FSM patches to the same spinor branch along with Huang's code. I hope that you can spend some effort on improving integration within the next few months in preparation for 3.16, when I expect this to all go upstream.
I certainly plan to. Although, I'm up to my neck in the ST BCH NAND driver at the moment. Trying to re-spin something that'll be accepted i.e. more intensive use of the framework.
Quick question, is there a chat medium for MTD? Somewhere for quick-fire questions i.e. an IRC channel or similar?
Quoted 1 line
[1] branch spinor, at http://git.infradead.org/l2-mtd.git
Signature · 4 lines
Lee Jones Linaro STMicroelectronics Landing Team Lead Linaro.org ? Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
v5 cover mtd: spi-nor: add a new framework for SPI NOR
Quoted 2 lines · Lee Jones
Quick question, is there a chat medium for MTD? Somewhere for quick-fire questions i.e. an IRC channel or similar?
OFTC #mtd channel. It's noted at the bottom here:
http://www.linux-mtd.infradead.org/mail.html
Many of us lurk there, but quickness varies :)
Brian