Skip to contentSkip to conversation

mtd: spi-nor: add a new framework for SPI NOR

PATCH Superseded Huang Shijie 5 participants 14 messages Dec 6, 2013 – Dec 12, 2013

Subsystems (3)

v2 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v2 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 chip

After this patch, the layer is like:

                   MTD
         ------------------------
                  spi-nor
         ------------------------
                  m25p80
         ------------------------
	       spi bus driver
         ------------------------
	       SPI NOR chip

With the spi-nor controller driver(Freescale Quadspi), it looks like:

                   MTD
         ------------------------
                  spi-nor
         ------------------------
                fsl-quadspi
         ------------------------
	       SPI NOR chip

3.) 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 use the new APIs.

Let's discuss the SPI nor framework in the new thread. :)

4.) TODO list:
3.1) add the new spi_nor_device{} for the spi-nor controller's device. 3.2) add the Freescale Quadspi driver.

v1 --> v2:

	[1] follow Angus's advice, add more hooks and data structrures.
	[2] others.

Huang Shijie (4):
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
mtd: m25p80: use the SPI nor framework

 drivers/mtd/Kconfig           |    2 +
 drivers/mtd/Makefile          |    1 +
 drivers/mtd/devices/Kconfig   |    2 +-
 drivers/mtd/devices/m25p80.c  | 1261 +++--------------------------------------
 drivers/mtd/spi-nor/Kconfig   |    6 +
 drivers/mtd/spi-nor/Makefile  |    1 +
 drivers/mtd/spi-nor/spi-nor.c | 1042 ++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h   |  132 +++++
 8 files changed, 1277 insertions(+), 1170 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
 create mode 100644 include/linux/mtd/spi-nor.h
Signature · 1 line
1.7.2.rc3
#1 lore raw

PATCH v2 1/4 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 |   53 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 53 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/mtd/spi-nor.h
include/linux/mtd/spi-nor.h new file +53 -0
new file mode 100644
index 0000000..ab2ea1e
@@ -0,0 +1,53 @@
+#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_QUAD_READ        0x6b    /* Read data bytes */
+#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_QUAD_READ_4B	0x6c    /* Read data bytes */
+#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
#2 lore raw

PATCH v2 2/4 mtd: spi-nor: add the basic data structures

In reply to Huang Shijie

The 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{}:
@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 |   74 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 74 insertions(+), 0 deletions(-)
include/linux/mtd/spi-nor.h +74 -0
index ab2ea1e..b3e08c2 100644
@@ -50,4 +50,78 @@
 /* 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_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
+struct spi_nor {
+	struct mtd_info		*mtd;
+	struct mutex		lock;
+
+	/* pointer to a spi device */
+	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;
+
+	/* for write_reg */
+	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+
+	/* the two fundamental primitives */
+	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);
+
+	/* write */
+	void (*write)(struct spi_nor *nor, loff_t to,
+			size_t len, size_t *retlen, const u_char *buf);
+	/* read */
+	int (*read)(struct spi_nor *nor, loff_t from,
+			size_t len, size_t *retlen, u_char *buf);
+	/* erase */
+	int (*erase)(struct spi_nor *nor, loff_t offs);
+};
 #endif
Signature · 1 line
1.7.2.rc3
#3 lore raw

PATCH v2 2/4 mtd: spi-nor: add the basic data structures

Quoted 46 lines · Huang Shijie

The 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{}:
@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 |   74

+++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 74 insertions(+), 0 deletions(-)

include/linux/mtd/spi-nor.h +9 -0
index ab2ea1e..b3e08c2 100644
@@ -50,4 +50,78 @@
 /* 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_QUAD,
+};
+
+/*
+ * struct spi_nor_xfer_cfg - Structure for defining a Serial Flash
Quoted 1 line

transfer + * @wren: command for "Write Enable", or 0x00 for not

required

Quoted 42 lines

+ * @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)
+ */

include/linux/mtd/spi-nor.h +32 -0
+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
+struct spi_nor {
+	struct mtd_info		*mtd;
+	struct mutex		lock;
+
+	/* pointer to a spi device */
+	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;
+
+	/* for write_reg */
+	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];

include/linux/mtd/spi-nor.h line 114

Quoted 10 lines
include/linux/mtd/spi-nor.h +10 -0
+
+	/* the two fundamental primitives */
+	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);

Does the vybrid really support accelerated SPI NOR register IO or does it emulate it with read/write or read_xfer/write_xfer accessors ? If the later, just drop this stuff for now.

include/linux/mtd/spi-nor.h line 125

Quoted 11 lines
include/linux/mtd/spi-nor.h +11 -0
+	const struct spi_device_id *(*read_id)(struct spi_nor *nor);
+	int (*wait_till_ready)(struct spi_nor *nor);
+
+	/* write */
+	void (*write)(struct spi_nor *nor, loff_t to,
+			size_t len, size_t *retlen, const u_char *buf);
+	/* read */
+	int (*read)(struct spi_nor *nor, loff_t from,
+			size_t len, size_t *retlen, u_char *buf);
+	/* erase */
+	int (*erase)(struct spi_nor *nor, loff_t offs);

How do you specify what to erase (sub-sector, sector, whole chip) here ?

Quoted 2 lines

+};
#endif

#4 lore raw

PATCH v2 2/4 mtd: spi-nor: add the basic data structures

Quoted 10 lines · Marek Vasut
Quoted 9 lines · Huang Shijie

The spi_nor{} is cloned from the m25p{}.

include/linux/mtd/spi-nor.h +8 -0
+	struct spi_nor_xfer_cfg	cfg;
+
+	/* for write_reg */
+	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+
+	/* the two fundamental primitives */
+	int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+			 u8 *buf, size_t len);
Quoted 8 lines

include/linux/mtd/spi-nor.h line 114

Quoted 6 lines
include/linux/mtd/spi-nor.h +6 -0
+	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);

Does the vybrid really support accelerated SPI NOR register IO or does it

The vybrid does not support the accelerated SPI NOR register IO. these hooks are for Lee's driver.

Quoted 2 lines

emulate it with read/write or read_xfer/write_xfer accessors ? If the later, just drop this stuff for now.

What is the "stuff" mean? the "write_enable" ?

Quoted 14 lines

include/linux/mtd/spi-nor.h line 125

Quoted 12 lines
include/linux/mtd/spi-nor.h +11 -0
+	const struct spi_device_id *(*read_id)(struct spi_nor *nor);
+	int (*wait_till_ready)(struct spi_nor *nor);
+
+	/* write */
+	void (*write)(struct spi_nor *nor, loff_t to,
+			size_t len, size_t *retlen, const u_char *buf);
+	/* read */
+	int (*read)(struct spi_nor *nor, loff_t from,
+			size_t len, size_t *retlen, u_char *buf);
+	/* erase */
+	int (*erase)(struct spi_nor *nor, loff_t offs);

How do you specify what to erase (sub-sector, sector, whole chip) here ?

I use a write_reg(OPCODE_ERASE_CHIP) to erase the whole chip. Please read the patch 3.

This hook is used to erase a sector.

Btw, what is the sub-sector mean? which opcodes for the sub-sector?

thanks
Huang Shijie

#5 lore raw

PATCH v2 2/4 mtd: spi-nor: add the basic data structures

Quoted 20 lines · Huang Shijie
Quoted 10 lines · Marek Vasut
Quoted 9 lines · Huang Shijie

The spi_nor{} is cloned from the m25p{}.

include/linux/mtd/spi-nor.h +8 -0
+	struct spi_nor_xfer_cfg	cfg;
+
+	/* for write_reg */
+	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+
+	/* the two fundamental primitives */
+	int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+			 u8 *buf, size_t len);
Quoted 8 lines

include/linux/mtd/spi-nor.h line 114

Quoted 6 lines
include/linux/mtd/spi-nor.h +6 -0
+	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);

Does the vybrid really support accelerated SPI NOR register IO or does it

Quoted 2 lines

The vybrid does not support the accelerated SPI NOR register IO. these hooks are for Lee's driver.

Which one please?

Quoted 4 lines
Quoted 2 lines

emulate it with read/write or read_xfer/write_xfer accessors ? If the later, just drop this stuff for now.

What is the "stuff" mean? the "write_enable" ?

This stuff -- I mean 'read SPI NOR register' and 'write SPI NOR register'. I would love to see an API which grows as needed, not an API which is bloated by unused function right from the start.

Quoted 14 lines
Quoted 5 lines
Quoted 5 lines
include/linux/mtd/spi-nor.h +5 -0
+	const struct spi_device_id *(*read_id)(struct spi_nor *nor);
+	int (*wait_till_ready)(struct spi_nor *nor);
+
+	/* write */
+	void (*write)(struct spi_nor *nor, loff_t to,
Quoted 8 lines

include/linux/mtd/spi-nor.h line 125

Quoted 6 lines
include/linux/mtd/spi-nor.h +6 -0
+			size_t len, size_t *retlen, const u_char *buf);
+	/* read */
+	int (*read)(struct spi_nor *nor, loff_t from,
+			size_t len, size_t *retlen, u_char *buf);
+	/* erase */
+	int (*erase)(struct spi_nor *nor, loff_t offs);

How do you specify what to erase (sub-sector, sector, whole chip) here ?

Quoted 4 lines

I use a write_reg(OPCODE_ERASE_CHIP) to erase the whole chip. Please read the patch 3.

This hook is used to erase a sector.

I suspect we might need a much better documentation for this structure, it is hardly clear which function does what ;-)

Quoted 1 line

Btw, what is the sub-sector mean? which opcodes for the sub-sector?

On large chips with for example 64K big sectors, you can erase a sub-sector area, usually a 4K one. This reduces the wear of the chip. See these defines in m25p80.c :

  46 #define OPCODE_BE_4K            0x20    /* Erase 4KiB block */
  48 #define OPCODE_BE_32K           0x52    /* Erase 32KiB block */
  49 #define OPCODE_CHIP_ERASE       0xc7    /* Erase whole flash chip */

Best regards,
Marek Vasut

#6 lore raw

PATCH v2 2/4 mtd: spi-nor: add the basic data structures

Quoted 18 lines
Quoted 18 lines
Quoted 17 lines
Quoted 5 lines

The spi_nor{} is cloned from the m25p{}.

include/linux/mtd/spi-nor.h +4 -0
+	struct spi_nor_xfer_cfg	cfg;
+
+	/* for write_reg */
+	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];

include/linux/mtd/spi-nor.h line 114

Quoted 10 lines
include/linux/mtd/spi-nor.h +10 -0
+
+	/* the two fundamental primitives */
+	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);

Does the vybrid really support accelerated SPI NOR register IO or does it

Quoted 4 lines
Quoted 2 lines

The vybrid does not support the accelerated SPI NOR register IO. these hooks are for Lee's driver.

Which one please?

It's not in Mainline yet, but the patches are on the list.

If you search for st_spi_fsm, you'll find them.

Signature · 4 lines
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
#7 lore raw

PATCH v2 2/4 mtd: spi-nor: add the basic data structures

In reply to Marek Vasut
Quoted 5 lines · Marek Vasut
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
include/linux/mtd/spi-nor.h +5 -0
+
+	/* the two fundamental primitives */
+	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,
Quoted 8 lines
Quoted 5 lines
Quoted 5 lines

include/linux/mtd/spi-nor.h line 114

Quoted 5 lines
include/linux/mtd/spi-nor.h +5 -0
+			  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);

This stuff -- I mean 'read SPI NOR register' and 'write SPI NOR register'. I would love to see an API which grows as needed, not an API which is bloated by unused function right from the start.

I should send out my fsl-quadspi driver in the next version.

The read_reg/write_reg are implemented by the m25p80 and fsl-quadspi now.

I think Lee's driver can implemente the read_xfer/write_xfer.

Quoted 15 lines
Quoted 15 lines
Quoted 14 lines

include/linux/mtd/spi-nor.h line 125

Quoted 12 lines
include/linux/mtd/spi-nor.h +11 -0
+	const struct spi_device_id *(*read_id)(struct spi_nor *nor);
+	int (*wait_till_ready)(struct spi_nor *nor);
+
+	/* write */
+	void (*write)(struct spi_nor *nor, loff_t to,
+			size_t len, size_t *retlen, const u_char *buf);
+	/* read */
+	int (*read)(struct spi_nor *nor, loff_t from,
+			size_t len, size_t *retlen, u_char *buf);
+	/* erase */
+	int (*erase)(struct spi_nor *nor, loff_t offs);

How do you specify what to erase (sub-sector, sector, whole chip) here ?

Quoted 7 lines
Quoted 4 lines

I use a write_reg(OPCODE_ERASE_CHIP) to erase the whole chip. Please read the patch 3.

This hook is used to erase a sector.

I suspect we might need a much better documentation for this structure, it is hardly clear which function does what ;-)

sorry, i will add more comment in the next version.

Quoted 10 lines
Quoted 2 lines

Btw, what is the sub-sector mean? which opcodes for the sub-sector?

On large chips with for example 64K big sectors, you can erase a sub-sector area, usually a 4K one. This reduces the wear of the chip. See these defines in m25p80.c :

  46 #define OPCODE_BE_4K            0x20    /* Erase 4KiB block */
  48 #define OPCODE_BE_32K           0x52    /* Erase 32KiB block */
  49 #define OPCODE_CHIP_ERASE       0xc7    /* Erase whole flash chip */

ok.

the @erase hook can be used for sub-sector too.

thanks
Huang Shijie

#8 lore raw

PATCH v2 2/4 mtd: spi-nor: add the basic data structures

Quoted 10 lines · Huang Shijie
Quoted 9 lines · Marek Vasut
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
include/linux/mtd/spi-nor.h +3 -0
+
+	/* the two fundamental primitives */
+	int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg

*cfg, + u8 *buf, size_t len);

(quoted diff) +1 -0
+	int (*write_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg

*cfg, + u8 *buf, size_t len);

(quoted diff) +2 -0
+
+	int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int

len); + int (*write_reg)(struct spi_nor *nor, u8 opcode, u8

*buf,

Quoted 6 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line

int len, + int write_enable);

This stuff -- I mean 'read SPI NOR register' and 'write SPI NOR register'. I would love to see an API which grows as needed, not an API which is bloated by unused function right from the start.

Quoted 6 lines

I should send out my fsl-quadspi driver in the next version.

The read_reg/write_reg are implemented by the m25p80 and fsl-quadspi now.

I think Lee's driver can implemente the read_xfer/write_xfer.

OK

Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 6 lines
Quoted 6 lines
include/linux/mtd/spi-nor.h +6 -0
+	const struct spi_device_id *(*read_id)(struct spi_nor *nor);
+	int (*wait_till_ready)(struct spi_nor *nor);
+
+	/* write */
+	void (*write)(struct spi_nor *nor, loff_t to,
+			size_t len, size_t *retlen, const u_char *buf);
Quoted 8 lines

include/linux/mtd/spi-nor.h line 125

Quoted 5 lines
include/linux/mtd/spi-nor.h +5 -0
+	/* read */
+	int (*read)(struct spi_nor *nor, loff_t from,
+			size_t len, size_t *retlen, u_char *buf);
+	/* erase */
+	int (*erase)(struct spi_nor *nor, loff_t offs);

How do you specify what to erase (sub-sector, sector, whole chip) here ?

I use a write_reg(OPCODE_ERASE_CHIP) to erase the whole chip. Please read the patch 3.

Quoted 6 lines
Quoted 4 lines
Quoted 1 line

This hook is used to erase a sector.

I suspect we might need a much better documentation for this structure, it is hardly clear which function does what ;-)

sorry, i will add more comment in the next version.

Thanks ;-)

Quoted 6 lines
Quoted 6 lines
Quoted 1 line

Btw, what is the sub-sector mean? which opcodes for the sub-sector?

On large chips with for example 64K big sectors, you can erase a sub-sector area, usually a 4K one. This reduces the wear of the chip. See these defines in

Quoted 8 lines
Quoted 4 lines

m25p80.c :

  46 #define OPCODE_BE_4K            0x20    /* Erase 4KiB block */
  48 #define OPCODE_BE_32K           0x52    /* Erase 32KiB block */
  49 #define OPCODE_CHIP_ERASE       0xc7    /* Erase whole flash chip */

ok.

the @erase hook can be used for sub-sector too.

I don't quite get how, but maybe you can elaborate on that one more in the next version of the patches :)

Best regards,
Marek Vasut

#9 lore raw

PATCH v2 3/4 mtd: spi-nor: add the framework for SPI NOR

In reply to Huang Shijie

This 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 chip

After this patch, the layer is like:

                   MTD
         ------------------------
                  spi-nor
         ------------------------
                  m25p80
         ------------------------
	       spi bus driver
         ------------------------
	       SPI NOR chip

With the spi-nor controller driver(Freescale Quadspi), it looks like:

                   MTD
         ------------------------
                  spi-nor
         ------------------------
                fsl-quadspi
         ------------------------
	       SPI NOR chip

New 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 | 1042 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h   |    5 +
 6 files changed, 1057 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
index 5fab4e6e..8adb5af 100644
@@ -320,6 +320,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
index 4cfb31e..40fd153 100644
@@ -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
new file mode 100644
index 0000000..41591af
@@ -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
new file mode 100644
index 0000000..7dfe1f9
@@ -0,0 +1 @@
+obj-$(CONFIG_MTD_SPI_NOR_BASE)	+= spi-nor.o
drivers/mtd/spi-nor/spi-nor.c new file +1042 -0

1,042 lines not on this page · raw message

include/linux/mtd/spi-nor.h +5 -0
index b3e08c2..6a47604 100644
@@ -124,4 +124,9 @@ struct spi_nor {
 	/* erase */
 	int (*erase)(struct spi_nor *nor, loff_t offs);
 };
+
+int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
+			bool quad_read);
+extern const struct spi_device_id spi_nor_ids[];
+
 #endif
Signature · 1 line
1.7.2.rc3
#10 lore raw

PATCH 1/1 mtd: m25p80: use the SPI nor framework

In reply to Huang Shijie

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 m25p_read/m25p_write.

Tested with the m25p32.

---
 drivers/mtd/devices/Kconfig  |    2 +-
 drivers/mtd/devices/m25p80.c | 1269 +++---------------------------------------
 2 files changed, 93 insertions(+), 1178 deletions(-)
drivers/mtd/devices/Kconfig +1 -1
index 0128138..004b17b 100644
@@ -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 +92 -1177

1,377 lines not on this page · raw message

Signature · 1 line
1.7.2.rc3
#11 lore raw

v2 cover mtd: spi-nor: add a new framework for SPI NOR

In reply to Huang Shijie

Hi Huang,

Quoted 71 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 chip

    After this patch, the layer is like:
                    MTD
          ------------------------
                   spi-nor
          ------------------------
                   m25p80
          ------------------------
	       spi bus driver
          ------------------------
	       SPI NOR chip
   With the spi-nor controller driver(Freescale Quadspi), it looks like:
                    MTD
          ------------------------
                   spi-nor
          ------------------------
                 fsl-quadspi
          ------------------------
	       SPI NOR chip

3.) 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 use the new APIs.

Let's discuss the SPI nor framework in the new thread. :)

4.) TODO list:
3.1) add the new spi_nor_device{} for the spi-nor controller's device. 3.2) add the Freescale Quadspi driver.

v1 --> v2:

	[1] follow Angus's advice, add more hooks and data structrures.
	[2] others.

Huang Shijie (4):
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
mtd: m25p80: use the SPI nor framework

  drivers/mtd/Kconfig           |    2 +
  drivers/mtd/Makefile          |    1 +
  drivers/mtd/devices/Kconfig   |    2 +-
  drivers/mtd/devices/m25p80.c  | 1261 +++--------------------------------------
  drivers/mtd/spi-nor/Kconfig   |    6 +
  drivers/mtd/spi-nor/Makefile  |    1 +
  drivers/mtd/spi-nor/spi-nor.c | 1042 ++++++++++++++++++++++++++++++++++
  include/linux/mtd/spi-nor.h   |  132 +++++
  8 files changed, 1277 insertions(+), 1170 deletions(-)
Quoted 5 lines

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 create mode 100644 include/linux/mtd/spi-nor.h

I have a requirement for a memory mapped operation for my spi flash driver.

A brief explanation about the requirement is here..

ti qspi supports two modes of operation, one is SPI mode(normal), other is the memory mapped read mode.

For SPI mode, the state machine remains the same as it is with other spi controller
available.

For memory mapped, there is something more which we need to do around ..

1. There is a qspi "set up" register available, which needs to be filled with
information like flash opcode, dummy bytes etc. In short, flash
specific
details.
2 if the above register is configured with the required opcodes, then
whenever
we need to use memory mapped operations, we need to do is to
switch our
qspi controller to memory mapped mode.
Switching of this mode to memory mapped needs
a ) write to a particular qspi register
b) write to control module(optional based on SOC).

3. Once the above steps are configured, then the flash data will be mapped to a
particular memory address(SOC specific) from where the flash data
can be read.

The series
https://www.mail-archive.com/linux-omap at vger.kernel.org/msg98691.html tries to work on the above features, and tries to add a support for the same in the
spi framework and m25p80 code.

As you see in my patches, once we take care of the above points and add support
for memory mapped in m25p80 and qspi, then while doing a read in m25p80 we can
do memcpy at the beginning of m25p80_read and can bypass the entire SPI framework for memory mapped read operation. Throughput almost gets doubles with this,
as compared to normal SPI operations.

So, my intention of reviving this here is to add one more feature set, which I suppose
spi nor framework should handle and to see what needs to be added more for this feature.

Please get back, if you need more info on this concept.

#12 lore raw

v2 cover mtd: spi-nor: add a new framework for SPI NOR

Quoted 9 lines · Sourav Poddar

As you see in my patches, once we take care of the above points and add support
for memory mapped in m25p80 and qspi, then while doing a read in m25p80 we can
do memcpy at the beginning of m25p80_read and can bypass the entire SPI framework for memory mapped read operation. Throughput almost gets doubles with this,
as compared to normal SPI operations.

Quoted 4 lines

So, my intention of reviving this here is to add one more feature set, which I suppose
spi nor framework should handle and to see what needs to be added more for this feature.

I already read your patch.

My quadspi driver also uses the memory map mode.
The memory map mode is the default mode for the quadspi driver's read.

You can setup the registers for memory map in the probe() or some other places. And use the spi_nor->read() hook to do the memcpy in your driver.

thanks
Huang Shijie

#13 lore raw

v2 cover mtd: spi-nor: add a new framework for SPI NOR

Quoted 17 lines · Huang Shijie
Quoted 9 lines · Sourav Poddar

As you see in my patches, once we take care of the above points and add support
for memory mapped in m25p80 and qspi, then while doing a read in m25p80 we can
do memcpy at the beginning of m25p80_read and can bypass the entire SPI framework for memory mapped read operation. Throughput almost gets doubles with this,
as compared to normal SPI operations.

Quoted 4 lines

So, my intention of reviving this here is to add one more feature set, which I suppose
spi nor framework should handle and to see what needs to be added more for this feature.

I already read your patch.

Quoted 7 lines

My quadspi driver also uses the memory map mode.
The memory map mode is the default mode for the quadspi driver's read.

You can setup the registers for memory map in the probe() or some other places. And use the spi_nor->read() hook to do the memcpy in your driver.

So, setting these registers should be set in my qspi controller driver in spi layer.
There registers requires flash opcodes and other flash specific parameters. I dont intend
to get this from dt, so need this information to be send via the mtd layer. So, dont think if
the present hooks will help me out.

Secondly, I had a dependency on few registers to switch between memory mapped mode and
spi mode. So, even though read is by default memory mapped, I need to write to qspi register
to switch to memory mapped mode and once the read is done, switch the controller back to
SPI mode.

So all in all, some hooks like
- configure_master_from_slave
- enable_mmap/disable_mmap is desired.

Do you think, we can handle/integrate this case in the above framework?

Quoted 3 lines

thanks
Huang Shijie