Skip to contentSkip to conversation

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

PATCH Superseded Huang Shijie 8 participants 36 messages Dec 16, 2013 – Dec 18, 2013

Subsystems (4)

v3 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v3 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/fsl_quaspi.c use the new APIs.

4.) Change log:
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.

Huang Shijie (7):
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
mtd: spi-nor: add a helper to find the spi_device_id
Documentation: add the binding file for Quadspi driver
mtd: spi-nor: Add Freescale QuadSpi driver

 .../devicetree/bindings/mtd/fsl-quadspi.txt        |   31 +
 drivers/mtd/Kconfig                                |    2 +
 drivers/mtd/Makefile                               |    1 +
 drivers/mtd/devices/Kconfig                        |    2 +-
 drivers/mtd/devices/m25p80.c                       | 1271 ++------------------
 drivers/mtd/spi-nor/Kconfig                        |   12 +
 drivers/mtd/spi-nor/Makefile                       |    2 +
 drivers/mtd/spi-nor/fsl-quadspi.c                  |  927 ++++++++++++++
 drivers/mtd/spi-nor/spi-nor.c                      | 1098 +++++++++++++++++
 include/linux/mtd/spi-nor.h                        |  167 +++
 10 files changed, 2335 insertions(+), 1178 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/fsl-quadspi.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
#1 lore raw

PATCH v3 1/7 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 v3 1/7 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.c and other spi-nor controller, such as Freescale's Quadspi.

It would be much nicer if you also removed the commands in this same patch from the m25p80.c file.

Best regards,
Marek Vasut

#3 lore raw

PATCH v3 1/7 mtd: spi-nor: copy the SPI NOR commands to a new header file

Quoted 5 lines · Marek Vasut
Quoted 4 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.

Quoted 7 lines
Quoted 4 lines

This hearder can be used by the m25p80.c and other spi-nor controller, such as Freescale's Quadspi.

It would be much nicer if you also removed the commands in this same patch from the m25p80.c file.

my earlier version did so. :)

So keep it as it is now.

thanks
Huang Shijie

#4 lore raw

PATCH v3 2/7 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{}:
@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 |  108 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 108 insertions(+), 0 deletions(-)
include/linux/mtd/spi-nor.h +108 -0
index ab2ea1e..83ca63d 100644
@@ -50,4 +50,112 @@
 /* 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
+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 {
+	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];
+
+	/*
+	 * Do some work before or after we run these operations:
+	 *   read/write/erese/lock/unlock
+	 */
+	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+
+	/*
+	 * The two fundamental primitives, you can use them to implement
+	 * all the other hooks, except the prepare/unprepare.
+	 */
+	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);
+
+	/*
+	 * The two hooks are used to read/write SPI NOR register, such as
+	 * read status register, write status register.
+         */
+	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);
+
+	/*
+	 * The hook for reading out the ID, the spi-nor controller drivers
+         * can fill it with its own implementation if the default
+	 * could not meet its requirement.
+	 */
+	const struct spi_device_id *(*read_id)(struct spi_nor *nor);
+
+	/*
+	 * The hook for "Wait till ready", some spi-nor controller drivers
+	 * may fill it with its own implementation.
+	 */
+	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 a sector(4K/64K, etc..) */
+	int (*erase)(struct spi_nor *nor, loff_t offs);
+
+	void *priv;
+};
 #endif
Signature · 1 line
1.7.2.rc3
#5 lore raw

PATCH v3 2/7 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{}:
@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 |  108

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

include/linux/mtd/spi-nor.h +8 -0
index ab2ea1e..83ca63d 100644
@@ -50,4 +50,112 @@
 /* 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 37 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 +27 -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
+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 {
+	struct mtd_info		*mtd;
+	struct mutex		lock;
+
+	/* pointer to a spi device */

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

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

You do want to split the function pointers below and the device configuration above into separate structures.

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

Quoted 6 lines
include/linux/mtd/spi-nor.h +6 -0
+	/* for write_reg */
+	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+
+	/*
+	 * Do some work before or after we run these operations:
+	 *   read/write/erese/lock/unlock

Proper kernel-doc style comments for this structure would be nice.

Quoted 7 lines
include/linux/mtd/spi-nor.h +7 -0
+	 */
+	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+
+	/*
+	 * The two fundamental primitives, you can use them to implement
+	 * all the other hooks, except the prepare/unprepare.

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

Quoted 10 lines
include/linux/mtd/spi-nor.h +10 -0
+	 */
+	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);
+
+	/*
+	 * The two hooks are used to read/write SPI NOR register, such as
+	 * read status register, write status register.
+         */

The format of the comment is messed up, please fix globally.

Quoted 8 lines
include/linux/mtd/spi-nor.h +8 -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, int len,
+			int write_enable);
+
+	/*
+	 * The hook for reading out the ID, the spi-nor controller drivers
+         * can fill it with its own implementation if the default
+	 * could not meet its requirement.

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

Quoted 10 lines
include/linux/mtd/spi-nor.h +10 -0
+	 */
+	const struct spi_device_id *(*read_id)(struct spi_nor *nor);
+
+	/*
+	 * The hook for "Wait till ready", some spi-nor controller drivers
+	 * may fill it with its own implementation.
+	 */
+	int (*wait_till_ready)(struct spi_nor *nor);
+
+	/* write */

write ... what ? I get it, but a proper documentation for new API would be _nice_ . Besides, I do not understand the parameters at all. Neither do I understand how to implement driver based on this API.

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

Quoted 6 lines
include/linux/mtd/spi-nor.h +6 -0
+	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 a sector(4K/64K, etc..) */

How do you select the erase size here (this is not documented, I dont understand it at all)?

Quoted 5 lines
include/linux/mtd/spi-nor.h +4 -0
+	int (*erase)(struct spi_nor *nor, loff_t offs);
+
+	void *priv;
+};
 #endif
#6 lore raw

PATCH v3 2/7 mtd: spi-nor: add the basic data structures

Quoted 10 lines · Marek Vasut
Quoted 9 lines · Huang Shijie
include/linux/mtd/spi-nor.h +9 -0
+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;
Quoted 8 lines

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

Quoted 5 lines
include/linux/mtd/spi-nor.h +5 -0
+	u8			read_dummy;
+	u8			program_opcode;
+	enum read_mode		flash_read;
+	bool			sst_write_second;
+	struct spi_nor_xfer_cfg	cfg;

You do want to split the function pointers below and the device configuration above into separate structures.

sorry, i prefer to keep them in one data structrue, just like the nand_chip{} does.

Quoted 9 lines

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

Quoted 7 lines
include/linux/mtd/spi-nor.h +6 -0
+	/* for write_reg */
+	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+
+	/*
+	 * Do some work before or after we run these operations:
+	 *   read/write/erese/lock/unlock

Proper kernel-doc style comments for this structure would be nice.

Do you mean the style used by nand_chip{}?

thanks
Huang Shijie

#7 lore raw

PATCH v3 2/7 mtd: spi-nor: add the basic data structures

Quoted 20 lines · Huang Shijie
Quoted 10 lines · Marek Vasut
Quoted 9 lines · Huang Shijie
include/linux/mtd/spi-nor.h +9 -0
+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;
Quoted 8 lines

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

Quoted 5 lines
include/linux/mtd/spi-nor.h +5 -0
+	u8			read_dummy;
+	u8			program_opcode;
+	enum read_mode		flash_read;
+	bool			sst_write_second;
+	struct spi_nor_xfer_cfg	cfg;

You do want to split the function pointers below and the device configuration above into separate structures.

Quoted 2 lines

sorry, i prefer to keep them in one data structrue, just like the nand_chip{} does.

Can you explain why?

Quoted 10 lines
Quoted 8 lines

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

Quoted 6 lines
include/linux/mtd/spi-nor.h +6 -0
+	/* for write_reg */
+	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+
+	/*
+	 * Do some work before or after we run these operations:
+	 *   read/write/erese/lock/unlock

Proper kernel-doc style comments for this structure would be nice.

Do you mean the style used by nand_chip{}?

Yes. See Documentation/kernel-doc-nano-HOWTO.txt

Best regards,
Marek Vasut

#8 lore raw

PATCH v3 2/7 mtd: spi-nor: add the basic data structures

Quoted 21 lines · Marek Vasut
Quoted 20 lines · Huang Shijie
Quoted 18 lines · Marek Vasut
Quoted 4 lines · Huang Shijie
include/linux/mtd/spi-nor.h +4 -0
+struct spi_nor { > > +	struct mtd_info		*mtd;
+	struct mutex		lock;
+
+	/* pointer to a spi device */

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

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

You do want to split the function pointers below and the device configuration above into separate structures.

Quoted 3 lines
Quoted 2 lines

sorry, i prefer to keep them in one data structrue, just like the nand_chip{} does.

Take @read_reg for example, currently, we call it with nor->read_reg(); If we add a new data structrue for these hooks, we wil call it with nor->ops->read_reg().

So just like the nand_chip{}, make the code more simple.

thanks
Huang Shijie

#9 lore raw

PATCH v3 3/7 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 | 1086 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h   |    5 +
 6 files changed, 1101 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 +1086 -0

1,086 lines not on this page · raw message

include/linux/mtd/spi-nor.h +5 -0
index 83ca63d..a0c2a8b 100644
@@ -158,4 +158,9 @@ struct spi_nor {
 
 	void *priv;
 };
+
+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
#10 lore raw

PATCH v3 3/7 mtd: spi-nor: add the framework for SPI NOR

Quoted 743 lines · 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 | 1086 +++++++++++++++++++++++++++++++++++++++++
  include/linux/mtd/spi-nor.h   |    5 +
  6 files changed, 1101 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 +647 -0
new file mode 100644
index 0000000..eb72bce
@@ -0,0 +1,1086 @@
+/*
+ * Cloned most of the code from the m25p80.c
+ *
+ * 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/init.h>
+#include<linux/err.h>
+#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/flash.h>
+#include<linux/mtd/spi-nor.h>
+
+/* 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 JEDEC_MFR(_jedec_id)	((_jedec_id)>>  16)
+
+/*
+ * 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 spi_nor *nor)
+{
+	int ret;
+	u8 val;
+
+	ret = nor->read_reg(nor, OPCODE_RDSR,&val, 1);
+	if (ret<  0) {
+		pr_err("error %d reading SR\n", (int) ret);
+		return ret;
+	}
+
+	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 spi_nor *nor)
+{
+	int ret;
+	u8 val;
+
+	ret = nor->read_reg(nor, OPCODE_RDCR,&val, 1);
+	if (ret<  0) {
+		dev_err(nor->dev, "error %d reading CR\n", ret);
+		return ret;
+	}
+
+	return val;
+}
+
+/*
+ * Dummy Cycle calculation for different type of read.
+ * It can be used to support more commands with
+ * different dummy cycle requirements.
+ */
+static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
+{
+	switch (nor->flash_read) {
+	case SPI_NOR_FAST:
+	case SPI_NOR_QUAD:
+		return 1;
+	case SPI_NOR_NORMAL:
+		return 0;
+	}
+	return 0;
+}
+
+/*
+ * Write status register 1 byte
+ * Returns negative if error occurred.
+ */
+static inline int write_sr(struct spi_nor *nor, u8 val)
+{
+	nor->cmd_buf[0] = val;
+	return nor->write_reg(nor, OPCODE_WRSR, nor->cmd_buf, 1, 0);
+}
+
+/*
+ * Set write enable latch with Write Enable command.
+ * Returns negative if error occurred.
+ */
+static inline int write_enable(struct spi_nor *nor)
+{
+	return nor->write_reg(nor, OPCODE_WREN, NULL, 0, 0);
+}
+
+/*
+ * 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 spi_nor *nor, u16 val)
+{
+	nor->cmd_buf[0] = val&  0xff;
+	nor->cmd_buf[1] = (val>>  8);
+
+	return nor->write_reg(nor, OPCODE_WRSR, nor->cmd_buf, 2, 0);
+}
+
+/*
+ * Send write disble instruction to the chip.
+ */
+static inline int write_disable(struct spi_nor *nor)
+{
+	return nor->write_reg(nor, OPCODE_WRDI, NULL, 0, 0);
+}
+
+static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
+{
+	return mtd->priv;
+}
+
+/* Enable/disable 4-byte addressing mode. */
+static inline int set_4byte(struct spi_nor *nor, u32 jedec_id, int enable)
+{
+	int status;
+	bool need_wren = false;
+	u8 cmd;
+
+	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(nor);
+
+		cmd = enable ? OPCODE_EN4B : OPCODE_EX4B;
+		status = nor->write_reg(nor, cmd, NULL, 0, 0);
+		if (need_wren)
+			write_disable(nor);
+
+		return status;
+	default:
+		/* Spansion style */
+		nor->cmd_buf[0] = enable<<  7;
+		return nor->write_reg(nor, OPCODE_BRWR, nor->cmd_buf, 1, 0);
+	}
+}
+
+static int spi_nor_wait_till_ready(struct spi_nor *nor)
+{
+	unsigned long deadline;
+	int sr;
+
+	deadline = jiffies + MAX_READY_WAIT_JIFFIES;
+
+	do {
+		cond_resched();
+
+		if ((sr = read_sr(nor))<  0)
+			break;
+		else if (!(sr&  SR_WIP))
+			return 0;
+	} while (!time_after_eq(jiffies, deadline));
+
+	return -ETIMEDOUT;
+}
+
+/*
+ * Service routine to read status register until ready, or timeout occurs.
+ * Returns non-zero if error.
+ */
+static int wait_till_ready(struct spi_nor *nor)
+{
+	return nor->wait_till_ready(nor);
+}
+
+/*
+ * Erase the whole flash memory
+ *
+ * Returns 0 if successful, non-zero otherwise.
+ */
+static int erase_chip(struct spi_nor *nor)
+{
+	int ret;
+
+	dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd->size>>  10));
+
+	/* Wait until finished previous write command. */
+	ret = wait_till_ready(nor);
+	if (ret)
+		return ret;
+
+	/* Send write enable, then erase commands. */
+	write_enable(nor);
+
+	return nor->write_reg(nor, OPCODE_CHIP_ERASE, NULL, 0, 0);
+}
+
+static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+	int ret = 0;
+
+	mutex_lock(&nor->lock);
+
+	if (nor->prepare) {
+		ret = nor->prepare(nor, ops);
+		if (ret) {
+			dev_err(nor->dev, "failed in the preparation.\n");
+			mutex_unlock(&nor->lock);
+			return ret;
+		}
+	}
+	return ret;
+}
+
+static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+	if (nor->unprepare)
+		nor->unprepare(nor, ops);
+	mutex_unlock(&nor->lock);
+}
+
+/*
+ * Erase an address range on the nor chip.  The address range may extend
+ * one or more erase sectors.  Return an error is there is a problem erasing.
+ */
+static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+	u32 addr,len;
+	uint32_t rem;
+	int ret;
+
+	dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (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;
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_ERASE);
+	if (ret)
+		return ret;
+
+	/* whole-chip erase? */
+	if (len == mtd->size) {
+		if (erase_chip(nor)) {
+			ret = -EIO;
+			goto erase_err;
+		}
+
+	/* 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.
+	 */
+
+	/* "sector"-at-a-time erase */
+	} else {
+		while (len) {
+			if (nor->erase(nor, addr)) {
+				ret = -EIO;
+				goto erase_err;
+			}
+
+			addr += mtd->erasesize;
+			len -= mtd->erasesize;
+		}
+	}
+
+	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+
+	instr->state = MTD_ERASE_DONE;
+	mtd_erase_callback(instr);
+
+	return ret;
+
+erase_err:
+	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+	instr->state = MTD_ERASE_FAILED;
+	return ret;
+}
+
+static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+	uint32_t offset = ofs;
+	uint8_t status_old, status_new;
+	int ret = 0;
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK);
+	if (ret)
+		return ret;
+
+	/* Wait until finished previous command */
+	ret = wait_till_ready(nor);
+	if (ret)
+		goto err;
+
+	status_old = read_sr(nor);
+
+	if (offset<  mtd->size - (mtd->size / 2))
+		status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0;
+	else if (offset<  mtd->size - (mtd->size / 4))
+		status_new = (status_old&  ~SR_BP0) | SR_BP2 | SR_BP1;
+	else if (offset<  mtd->size - (mtd->size / 8))
+		status_new = (status_old&  ~SR_BP1) | SR_BP2 | SR_BP0;
+	else if (offset<  mtd->size - (mtd->size / 16))
+		status_new = (status_old&  ~(SR_BP0 | SR_BP1)) | SR_BP2;
+	else if (offset<  mtd->size - (mtd->size / 32))
+		status_new = (status_old&  ~SR_BP2) | SR_BP1 | SR_BP0;
+	else if (offset<  mtd->size - (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(nor);
+		ret = write_sr(nor, status_new);
+		if (ret)
+			goto err;
+	}
+
+err:
+	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
+	return ret;
+}
+
+static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+	uint32_t offset = ofs;
+	uint8_t status_old, status_new;
+	int ret = 0;
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
+	if (ret)
+		return ret;
+
+	/* Wait until finished previous command */
+	ret = wait_till_ready(nor);
+	if (ret)
+		goto err;
+
+	status_old = read_sr(nor);
+
+	if (offset+len>  mtd->size - (mtd->size / 64))
+		status_new = status_old&  ~(SR_BP2 | SR_BP1 | SR_BP0);
+	else if (offset+len>  mtd->size - (mtd->size / 32))
+		status_new = (status_old&  ~(SR_BP2 | SR_BP1)) | SR_BP0;
+	else if (offset+len>  mtd->size - (mtd->size / 16))
+		status_new = (status_old&  ~(SR_BP2 | SR_BP0)) | SR_BP1;
+	else if (offset+len>  mtd->size - (mtd->size / 8))
+		status_new = (status_old&  ~SR_BP2) | SR_BP1 | SR_BP0;
+	else if (offset+len>  mtd->size - (mtd->size / 4))
+		status_new = (status_old&  ~(SR_BP0 | SR_BP1)) | SR_BP2;
+	else if (offset+len>  mtd->size - (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(nor);
+		ret = write_sr(nor, status_new);
+		if (ret)
+			goto err;
+	}
+
+err:
+	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK);
+	return ret;
+}
+
+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	SPI_NOR_NO_ERASE	0x02	/* No erase command needed */
+#define	SST_WRITE		0x04	/* use SST byte programming */
+#define	SPI_NOR_NO_FR		0x08	/* Can't do fastread */
+#define	SECT_4K_PMC		0x10	/* OPCODE_BE_4K_PMC works uniformly */
+#define	SPI_NOR_QUAD_READ	0x20    /* 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 nor chips.  This current list focusses on newer chips, which
+ * have been converging on command sets which including JEDEC ID.
+ */
+const struct spi_device_id spi_nor_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, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "mr25h10",  CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_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, SPI_NOR_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, SPI_NOR_QUAD_READ) },
+	{ "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) },
+	{ "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) },
+	{ "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, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "cat25c03", CAT25_INFO(  32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ },
+};
+
+static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor)
+{
+	int			tmp;
+	u8			id[5];
+	u32			jedec;
+	u16                     ext_jedec;
+	struct flash_info	*info;
+
+	tmp = nor->read_reg(nor, OPCODE_RDID, id, 5);
+	if (tmp<  0) {
+		dev_dbg(nor->dev, " error %d reading JEDEC ID\n", tmp);
+		return ERR_PTR(tmp);
+	}
+	jedec = id[0];
+	jedec = jedec<<  8;
+	jedec |= id[1];
+	jedec = jedec<<  8;
+	jedec |= id[2];
+
+	ext_jedec = id[3]<<  8 | id[4];
+
+	for (tmp = 0; tmp<  ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {
+		info = (void *)spi_nor_ids[tmp].driver_data;
+		if (info->jedec_id == jedec) {
+			if (info->ext_id != 0&&  info->ext_id != ext_jedec)
+				continue;
+			return&spi_nor_ids[tmp];
+		}
+	}
+	pr_err("unrecognized JEDEC id %06x\n", jedec);
+	return ERR_PTR(-ENODEV);
+}
+
+static const struct spi_device_id *jedec_probe(struct spi_nor *nor)
+{
+	return nor->read_id(nor);
+}
+
+static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
+			size_t *retlen, u_char *buf)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+	int ret;
+
+	dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);

drivers/mtd/spi-nor/spi-nor.c line 657

Quoted 10 lines
drivers/mtd/spi-nor/spi-nor.c new file +10 -0
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
+	if (ret)
+		return ret;
+
+	/* Wait till previous write/erase is done. */
+	ret = wait_till_ready(nor);
+	if (ret)
+		goto read_err;
+

Can you shift "wait_till_ready" above spi_nor_lock_and_prep? One usecase for asking for above change is that I am planning to use this _prep api for switching to memory mapped mode for read and once I am switched to mmap mode, read_sr calls in wait_till_ready will not work for me.

Quoted 443 lines
drivers/mtd/spi-nor/spi-nor.c new file +429 -0
+	ret = nor->read(nor, from, len, retlen, buf);
+
+read_err:
+	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
+	return ret;
+}
+
+static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
+		size_t *retlen, const u_char *buf)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+	size_t actual;
+	int ret;
+
+	dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
+	if (ret)
+		return ret;
+
+	/* Wait until finished previous write command. */
+	ret = wait_till_ready(nor);
+	if (ret)
+		goto time_out;
+
+	write_enable(nor);
+
+	nor->sst_write_second = false;
+
+	actual = to % 2;
+	/* Start write from odd address. */
+	if (actual) {
+		nor->program_opcode = OPCODE_BP;
+
+		/* write one byte. */
+		nor->write(nor, to, 1, retlen, buf);
+		ret = wait_till_ready(nor);
+		if (ret)
+			goto time_out;
+	}
+	to += actual;
+
+	/* Write out most of the data here. */
+	for (; actual<  len - 1; actual += 2) {
+		nor->program_opcode = OPCODE_AAI_WP;
+
+		/* write two bytes. */
+		nor->write(nor, to, 2, retlen, buf + actual);
+		ret = wait_till_ready(nor);
+		if (ret)
+			goto time_out;
+		to += 2;
+		nor->sst_write_second = true;
+	}
+	nor->sst_write_second = false;
+
+	write_disable(nor);
+	ret = wait_till_ready(nor);
+	if (ret)
+		goto time_out;
+
+	/* Write out trailing byte if it exists. */
+	if (actual != len) {
+		write_enable(nor);
+
+		nor->program_opcode = OPCODE_BP;
+		nor->write(nor, to, 1, retlen, buf + actual);
+
+		ret = wait_till_ready(nor);
+		if (ret)
+			goto time_out;
+		write_disable(nor);
+	}
+time_out:
+	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+	return ret;
+}
+
+/*
+ * Write an address range to the nor 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 spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
+	size_t *retlen, const u_char *buf)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+	u32 page_offset, page_size, i;
+	int ret;
+
+	dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
+	if (ret)
+		return ret;
+
+	/* Wait until finished previous write command. */
+	ret = wait_till_ready(nor);
+	if (ret)
+		goto write_err;
+
+	write_enable(nor);
+
+	page_offset = to&  (nor->page_size - 1);
+
+	/* do all the bytes fit onto one page? */
+	if (page_offset + len<= nor->page_size) {
+		nor->write(nor, to, len, retlen, buf);
+	} else {
+		/* the size of data remaining on the first page */
+		page_size = nor->page_size - page_offset;
+		nor->write(nor, to, page_size, retlen, buf);
+
+		/* write everything in nor->page_size chunks */
+		for (i = page_size; i<  len; i += page_size) {
+			page_size = len - i;
+			if (page_size>  nor->page_size)
+				page_size = nor->page_size;
+
+			wait_till_ready(nor);
+			write_enable(nor);
+
+			nor->write(nor, to + i, page_size, retlen, buf + i);
+		}
+	}
+
+write_err:
+	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+	return 0;
+}
+
+static int macronix_quad_enable(struct spi_nor *nor)
+{
+	int ret, val;
+
+	val = read_sr(nor);
+	write_enable(nor);
+
+	nor->cmd_buf[0] = val | SR_QUAD_EN_MX;
+	nor->write_reg(nor, OPCODE_WRSR, nor->cmd_buf, 1, 0);
+
+	if (wait_till_ready(nor))
+		return 1;
+
+	ret = read_sr(nor);
+	if (!(ret>  0&&  (ret&  SR_QUAD_EN_MX))) {
+		dev_err(nor->dev, "Macronix Quad bit not set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int spansion_quad_enable(struct spi_nor *nor)
+{
+	int ret;
+	int quad_en = CR_QUAD_EN_SPAN<<  8;
+
+	write_enable(nor);
+
+	ret = write_sr_cr(nor, quad_en);
+	if (ret<  0) {
+		dev_err(nor->dev,
+			"error while writing configuration register\n");
+		return -EINVAL;
+	}
+
+	/* read back and check it */
+	ret = read_cr(nor);
+	if (!(ret>  0&&  (ret&  CR_QUAD_EN_SPAN))) {
+		dev_err(nor->dev, "Spansion Quad bit not set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int set_quad_mode(struct spi_nor *nor, u32 jedec_id)
+{
+	int status;
+
+	switch (JEDEC_MFR(jedec_id)) {
+	case CFI_MFR_MACRONIX:
+		status = macronix_quad_enable(nor);
+		if (status) {
+			dev_err(nor->dev, "Macronix quad-read not enabled\n");
+			return -EINVAL;
+		}
+		return status;
+	default:
+		status = spansion_quad_enable(nor);
+		if (status) {
+			dev_err(nor->dev, "Spansion quad-read not enabled\n");
+			return -EINVAL;
+		}
+		return status;
+	}
+}
+
+static int spi_nor_check(struct spi_nor *nor)
+{
+	if (!nor->dev || !nor->read || !nor->write ||
+		!nor->read_reg || !nor->write_reg || !nor->erase) {
+		pr_err("spi-nor: please fill all the necessary fields!\n");
+		return -EINVAL;
+	}
+
+	if (!nor->read_id)
+		nor->read_id = spi_nor_read_id;
+	if (!nor->wait_till_ready)
+		nor->wait_till_ready = spi_nor_wait_till_ready;
+
+	return 0;
+}
+
+int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
+			enum read_mode mode)
+{
+	struct flash_info		*info;
+	struct flash_platform_data	*data;
+	struct device *dev = nor->dev;
+	struct mtd_info *mtd = nor->mtd;
+	struct device_node *np = dev->of_node;
+	int ret;
+	int i;
+
+	ret = spi_nor_check(nor);
+	if (ret)
+		return 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(dev);
+	if (data&&  data->type) {
+		const struct spi_device_id *plat_id;
+
+		for (i = 0; i<  ARRAY_SIZE(spi_nor_ids) - 1; i++) {
+			plat_id =&spi_nor_ids[i];
+			if (strcmp(data->type, plat_id->name))
+				continue;
+			break;
+		}
+
+		if (i<  ARRAY_SIZE(spi_nor_ids) - 1)
+			id = plat_id;
+		else
+			dev_warn(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(nor);
+		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(dev, "found %s, expected %s\n",
+				 jid->name, id->name);
+			id = jid;
+			info = (void *)jid->driver_data;
+		}
+	}
+
+	mutex_init(&nor->lock);
+
+	/*
+	 * Atmel, SST and Intel/Numonyx serial nor tend to power
+	 * up with the software protection bits set
+	 */
+
+	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(nor);
+		write_sr(nor, 0);
+	}
+
+	if (data&&  data->name)
+		mtd->name = data->name;
+	else
+		mtd->name = dev_name(dev);
+
+	mtd->type = MTD_NORFLASH;
+	mtd->writesize = 1;
+	mtd->flags = MTD_CAP_NORFLASH;
+	mtd->size = info->sector_size * info->n_sectors;
+	mtd->_erase = spi_nor_erase;
+	mtd->_read = spi_nor_read;
+
+	/* nor protection support for STmicro chips */
+	if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) {
+		mtd->_lock = spi_nor_lock;
+		mtd->_unlock = spi_nor_unlock;
+	}
+
+	/* sst nor chips use AAI word program */
+	if (info->flags&  SST_WRITE)
+		mtd->_write = sst_write;
+	else
+		mtd->_write = spi_nor_write;
+
+	/* prefer "small sector" erase if possible */
+	if (info->flags&  SECT_4K) {
+		nor->erase_opcode = OPCODE_BE_4K;
+		mtd->erasesize = 4096;
+	} else if (info->flags&  SECT_4K_PMC) {
+		nor->erase_opcode = OPCODE_BE_4K_PMC;
+		mtd->erasesize = 4096;
+	} else {
+		nor->erase_opcode = OPCODE_SE;
+		mtd->erasesize = info->sector_size;
+	}
+
+	if (info->flags&  SPI_NOR_NO_ERASE)
+		mtd->flags |= MTD_NO_ERASE;
+
+	mtd->dev.parent = dev;
+	nor->page_size = info->page_size;
+	mtd->writebufsize = nor->page_size;
+
+	if (np) {
+		/* If we were instantiated by DT, use it */
+		if (of_property_read_bool(np, "m25p,fast-read"))
+			nor->flash_read = SPI_NOR_FAST;
+	} else {
+		/* If we weren't instantiated by DT, default to fast-read */
+		nor->flash_read = SPI_NOR_FAST;
+	}
+
+	/* Some devices cannot do fast-read, no matter what DT tells us */
+	if (info->flags&  SPI_NOR_NO_FR)
+		nor->flash_read = SPI_NOR_NORMAL;
+
+	/* Quad-read mode takes precedence over fast/normal */
+	if (mode == SPI_NOR_QUAD&&  info->flags&  SPI_NOR_QUAD_READ) {
+		ret = set_quad_mode(nor, info->jedec_id);
+		if (ret) {
+			dev_err(dev, "quad mode not supported\n");
+			return ret;
+		}
+		nor->flash_read = SPI_NOR_QUAD;
+	}
+
+	/* Default commands */
+	switch (nor->flash_read) {
+	case SPI_NOR_QUAD:
+		nor->read_opcode = OPCODE_QUAD_READ;
+		break;
+	case SPI_NOR_FAST:
+		nor->read_opcode = OPCODE_FAST_READ;
+		break;
+	case SPI_NOR_NORMAL:
+		nor->read_opcode = OPCODE_NORM_READ;
+		break;
+	default:
+		dev_err(dev, "No Read opcode defined\n");
+		return -EINVAL;
+	}
+
+	nor->program_opcode = OPCODE_PP;
+
+	if (info->addr_width)
+		nor->addr_width = info->addr_width;
+	else if (mtd->size>  0x1000000) {
+		/* enable 4-byte addressing if the device exceeds 16MiB */
+		nor->addr_width = 4;
+		if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
+			/* Dedicated 4-byte command set */
+			switch (nor->flash_read) {
+			case SPI_NOR_QUAD:
+				nor->read_opcode = OPCODE_QUAD_READ;
+				break;
+			case SPI_NOR_FAST:
+				nor->read_opcode = OPCODE_FAST_READ_4B;
+				break;
+			case SPI_NOR_NORMAL:
+				nor->read_opcode = OPCODE_NORM_READ_4B;
+				break;
+			}
+			nor->program_opcode = OPCODE_PP_4B;
+			/* No small sector erase for 4-byte command set */
+			nor->erase_opcode = OPCODE_SE_4B;
+			mtd->erasesize = info->sector_size;
+		} else
+			set_4byte(nor, info->jedec_id, 1);
+	} else {
+		nor->addr_width = 3;
+	}
+
+	nor->read_dummy = spi_nor_read_dummy_cycles(nor);
+
+	dev_info(dev, "%s (%lld Kbytes)\n", id->name,
+			(long long)mtd->size>>  10);
+
+	dev_dbg(dev, "mtd .name = %s, .size = 0x%llx (%lldMiB) "
+			".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
+		mtd->name,
+		(long long)mtd->size, (long long)(mtd->size>>  20),
+		mtd->erasesize, mtd->erasesize / 1024,
+		mtd->numeraseregions);
+
+	if (mtd->numeraseregions)
+		for (i = 0; i<  mtd->numeraseregions; i++)
+			dev_dbg(dev,
+				"mtd.eraseregions[%d] = { .offset = 0x%llx, "
+				".erasesize = 0x%.8x (%uKiB), "
+				".numblocks = %d }\n",
+				i, (long long)mtd->eraseregions[i].offset,
+				mtd->eraseregions[i].erasesize,
+				mtd->eraseregions[i].erasesize / 1024,
+				mtd->eraseregions[i].numblocks);
+	return 0;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale Semiconductor Inc.");
+MODULE_DESCRIPTION("framework for SPI NOR nor");
include/linux/mtd/spi-nor.h +5 -0
index 83ca63d..a0c2a8b 100644
@@ -158,4 +158,9 @@ struct spi_nor {
 
  	void *priv;
  };
+
+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
#11 lore raw

PATCH v3 3/7 mtd: spi-nor: add the framework for SPI NOR

Quoted 15 lines · Sourav Poddar
Quoted 15 lines
drivers/mtd/spi-nor/spi-nor.c new file +15 -0
+static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
+			size_t *retlen, u_char *buf)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+	int ret;
+
+	dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
+	if (ret)
+		return ret;
+
+	/* Wait till previous write/erase is done. */
+	ret = wait_till_ready(nor);
+	if (ret)
Quoted 9 lines

drivers/mtd/spi-nor/spi-nor.c line 657

Quoted 2 lines
drivers/mtd/spi-nor/spi-nor.c new file +2 -0
+		goto read_err;
+

Can you shift "wait_till_ready" above spi_nor_lock_and_prep? One usecase for asking for above change is that I am planning to use this _prep api for switching to memory mapped mode for read and once I am switched to mmap mode, read_sr calls in wait_till_ready will not work for me.

you can implement your own wait_till_ready here.

Only we have grabbed the lock, then we can do the transactions with the NOR.

We can not call the wait_till_ready before we grab the lock, it is wrong.

If you really can not implement your own wait_till_ready, the final solution is removing the wait_till_ready in this function, and add the wait_till_ready in the nor->read() hook.

thanks
Huang Shijie

#12 lore raw

PATCH v3 3/7 mtd: spi-nor: add the framework for SPI NOR

Quoted 24 lines · Huang Shijie
Quoted 14 lines · Sourav Poddar
Quoted 14 lines
drivers/mtd/spi-nor/spi-nor.c new file +14 -0
+static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
+			size_t *retlen, u_char *buf)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+	int ret;
+
+	dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
+	if (ret)
+		return ret;
+
+	/* Wait till previous write/erase is done. */
+	ret = wait_till_ready(nor);
Quoted 9 lines

drivers/mtd/spi-nor/spi-nor.c line 657

Quoted 3 lines
drivers/mtd/spi-nor/spi-nor.c new file +3 -0
+	if (ret)
+		goto read_err;
+

Can you shift "wait_till_ready" above spi_nor_lock_and_prep? One usecase for asking for above change is that I am planning to use this _prep api for switching to memory mapped mode for read and once I am switched to mmap mode, read_sr calls in wait_till_ready will not work for me.

Quoted 1 line

you can implement your own wait_till_ready here.

I think no point doing this, since it does the same function for me.

Quoted 9 lines

Only we have grabbed the lock, then we can do the transactions with the NOR.

We can not call the wait_till_ready before we grab the lock, it is wrong.

If you really can not implement your own wait_till_ready, the final solution is removing the wait_till_ready in this function, and add the wait_till_ready in the nor->read() hook.

Yes, this can be done. So, that if you want to do memcpy do it before this condition is hit.

Quoted 4 lines

thanks
Huang Shijie

#13 lore raw

PATCH v3 3/7 mtd: spi-nor: add the framework for SPI NOR

Quoted 32 lines · Sourav Poddar
Quoted 24 lines · Huang Shijie
Quoted 14 lines · Sourav Poddar
Quoted 14 lines
drivers/mtd/spi-nor/spi-nor.c new file +14 -0
+static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
+			size_t *retlen, u_char *buf)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+	int ret;
+
+	dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
+	if (ret)
+		return ret;
+
+	/* Wait till previous write/erase is done. */
+	ret = wait_till_ready(nor);
Quoted 9 lines

drivers/mtd/spi-nor/spi-nor.c line 657

Quoted 3 lines
drivers/mtd/spi-nor/spi-nor.c new file +3 -0
+	if (ret)
+		goto read_err;
+

Can you shift "wait_till_ready" above spi_nor_lock_and_prep? One usecase for asking for above change is that I am planning to use this _prep api for switching to memory mapped mode for read and once I am switched to mmap mode, read_sr calls in wait_till_ready will not work for me.

Quoted 1 line

you can implement your own wait_till_ready here.

I think no point doing this, since it does the same function for me.

Quoted 5 lines

Only we have grabbed the lock, then we can do the transactions with the NOR.

We can not call the wait_till_ready before we grab the lock, it is wrong.

Quoted 7 lines
Quoted 4 lines

If you really can not implement your own wait_till_ready, the final solution is removing the wait_till_ready in this function, and add the wait_till_ready in the nor->read() hook.

Yes, this can be done. So, that if you want to do memcpy do it before this condition is hit.

ok.

I can fix it in the next version.

thanks
Huang Shijie

#14 lore raw

PATCH v3 3/7 mtd: spi-nor: add the framework for SPI NOR

In reply to Huang Shijie
Quoted 33 lines · 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
Quoted 2 lines

New APIs:
spi_nor_scan: used to scan a spi-nor flash.

Document every single one function with a proper kernel-doc style annotations please.

Best regards,
Marek Vasut

#15 lore raw

PATCH v3 4/7 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 | 1271 ++++--------------------------------------
 2 files changed, 95 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 +94 -1177

1,379 lines not on this page · raw message

Signature · 1 line
1.7.2.rc3
#16 lore raw

PATCH v3 5/7 mtd: spi-nor: add a helper to find the spi_device_id

In reply to Huang Shijie

Add the spi_nor_match_id() to find the proper spi_device_id in the spi_nor_ids table.

---
 drivers/mtd/spi-nor/spi-nor.c |   12 ++++++++++++
 include/linux/mtd/spi-nor.h   |    1 +
 2 files changed, 13 insertions(+), 0 deletions(-)
drivers/mtd/spi-nor/spi-nor.c +12 -0
index eb72bce..268d019 100644
@@ -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("Freescale Semiconductor Inc.");
 MODULE_DESCRIPTION("framework for SPI NOR nor");
include/linux/mtd/spi-nor.h +1 -0
index a0c2a8b..7ed66d1 100644
@@ -162,5 +162,6 @@ struct spi_nor {
 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[];
+const struct spi_device_id * spi_nor_match_id(char *name);
 
 #endif
Signature · 1 line
1.7.2.rc3
#17 lore raw

PATCH v3 6/7 Documentation: add the binding file for Quadspi driver

In reply to Huang Shijie

This patch adds the binding file for Freescale Quadspi driver.

---
 .../devicetree/bindings/mtd/fsl-quadspi.txt        |   31 ++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/fsl-quadspi.txt
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +31 -0
new file mode 100644
index 0000000..3475cfa
@@ -0,0 +1,31 @@
+* Freescale Quad Serial Peripheral Interface(QuadSPI)
+
+Required properties:
+- compatible : Should be "fsl,vf610-qspi"
+- reg : Offset and length of the register set for the device
+- interrupts : Should contain the interrupt for the device
+- clocks : The clocks needed by the QuadSPI controller
+- clock-names : the name of the clocks
+- fsl,nor-num : Contains the number of SPI NOR chips connected to
+                the controller.
+- fsl,nor-size : the size of each SPI NOR.
+- fsl,max-frequency : the frequency at which the SPI NOR works.
+
+Example:
+
+qspi0: quadspi at 40044000 {
+	compatible = "fsl,vf610-qspi";
+	reg = <0x40044000 0x1000>;
+	interrupts = <0 24 0x04>;
+	clocks = <&clks VF610_CLK_QSPI0_EN>,
+		<&clks VF610_CLK_QSPI0>;
+	clock-names = "qspi_en", "qspi";
+	fsl,nor-num = <1>;
+	fsl,nor-size = <0x1000000>;
+	fsl,max-frequency = <66000000>;
+	status = "okay";
+
+	flash0: s25fl128s at 0 {
+		....
+	};
+};
Signature · 1 line
1.7.2.rc3
#18 lore raw

PATCH v3 6/7 Documentation: add the binding file for Quadspi driver

Quoted 3 lines · Huang Shijie

This patch adds the binding file for Freescale Quadspi driver.

I might be blind and/or tired, but I don't see devicetree-discuss in the CC. Next time please CC this ML ( devicetree-discuss AT lists.ozlabs.org ) so the bindings are reviewed by experts .

Best regards,
Marek Vasut

#19 lore raw

PATCH v3 6/7 Documentation: add the binding file for Quadspi driver

Hello Marek,

Marek Vasut wrote on?2013-12-17:

Quoted 8 lines · Huang Shijie
Quoted 3 lines

This patch adds the binding file for Freescale Quadspi driver.

I might be blind and/or tired, but I don't see devicetree-discuss in the CC. Next time please CC this ML ( devicetree-discuss AT lists.ozlabs.org ) so the bindings are reviewed by experts .

I am sure you talking about the new list at devicetree at vger.kernel.org?

Quoted 3 lines

Best regards,
Marek Vasut

Best Regards,
Thomas
---
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
---

#20 lore raw

PATCH v3 6/7 Documentation: add the binding file for Quadspi driver

Quoted 6 lines · thomas.langer at lantiq.com

Hello Marek,

Marek Vasut wrote on 2013-12-17:

Quoted 3 lines · Huang Shijie
Quoted 2 lines

This patch adds the binding file for Freescale Quadspi driver.

Quoted 7 lines
Quoted 5 lines
Quoted 1 line

I might be blind and/or tired, but I don't see devicetree-discuss in the CC. Next time please CC this ML ( devicetree-discuss AT lists.ozlabs.org ) so the bindings are reviewed by experts .

I am sure you talking about the new list at devicetree at vger.kernel.org?

Yes, thanks for correcting it.

Best regards,
Marek Vasut

#21 lore raw

PATCH v3 6/7 Documentation: add the binding file for Quadspi driver

In reply to Huang Shijie

[ adding Cc: to devicetree; make sure to keep 'binding' in the
subject line upon re-submission, such that reviewers can tell whether you introduce a new binding, or just use an existing binding and implement it in a dts/dtsi file ]

Quoted 17 lines · Huang Shijie

This patch adds the binding file for Freescale Quadspi driver.

---
 .../devicetree/bindings/mtd/fsl-quadspi.txt        |   31 ++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/fsl-quadspi.txt
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +2 -0
new file mode 100644
index 0000000..3475cfa
@@ -0,0 +1,31 @@
+* Freescale Quad Serial Peripheral Interface(QuadSPI)
+

Documentation/devicetree/bindings/mtd/fsl-quadspi.txt line 12

Quoted 10 lines
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +10 -0
+Required properties:
+- compatible : Should be "fsl,vf610-qspi"
+- reg : Offset and length of the register set for the device
+- interrupts : Should contain the interrupt for the device
+- clocks : The clocks needed by the QuadSPI controller
+- clock-names : the name of the clocks
+- fsl,nor-num : Contains the number of SPI NOR chips connected to
+                the controller.
+- fsl,nor-size : the size of each SPI NOR.
+- fsl,max-frequency : the frequency at which the SPI NOR works.

Those "fsl,*" properties somehow feel strange. I comment on details below the example since this should even better show why I feel so.

Quoted 9 lines
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +9 -0
+
+Example:
+
+qspi0: quadspi at 40044000 {
+	compatible = "fsl,vf610-qspi";
+	reg = <0x40044000 0x1000>;
+	interrupts = <0 24 0x04>;
+	clocks = <&clks VF610_CLK_QSPI0_EN>,
+		<&clks VF610_CLK_QSPI0>;

Documentation/devicetree/bindings/mtd/fsl-quadspi.txt line 31

Quoted 10 lines
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +10 -0
+	clock-names = "qspi_en", "qspi";
+	fsl,nor-num = <1>;
+	fsl,nor-size = <0x1000000>;
+	fsl,max-frequency = <66000000>;
+	status = "okay";
+
+	flash0: s25fl128s at 0 {
+		....
+	};
+};

The number of chips connected to the controller should reflect in the child nodes of the SPI NOR controller, and need not get specified in redundant ways and with potential for errors when they can get determined at runtime.

The capacity of the flash chip as well as the maximum frequency which the flash chip operates at should be features of the flash chip (in combination with the board), i.e. of the child node and not the controller. SPI slaves already have a documented property for the purpose of limiting transfer rates when they are lower than the controller's i.e. busses capabilities. Can't tell from the top of my head whether there is a property for the maximum frequency which a controller should use across the whole bus. In any case, either the property needs to get moved, or the description should get updated to say "the max frequency at which the controller will send data" or something.

The capacity of the flash chip should be a consequence of either having gathered CFI information (if available) or having identified the chip by its JEDEC ID and looked up its features in an internal database. Users should not need to specify the capacity of the flash chip in the device tree.

If the 'fsl,nor-size' property remains (which I doubt at the moment), you cannot describe "the size of each" chip in one single-cell spec. So the documentation should get extended to reflect multi-chip setups. But I'd rather assume that the property is not needed at all.

You can omit the 'status = "okay"' line since that is the default already in the absence of the keyword. This property is most useful to declare yet not enable by default components in .dtsi files and to do enable them in individual board files if applicable. This aspect need not be shown in the binding example of a QSPI controller.

I'd suggest to use symbolic names for the flags in the last interrupt specifier cell, as you do for clock items.

And while I'm in nitpick mode :) let me say that I dislike the blanking around the colons in the properties discussion, but I'm as well aware that these are "inspired by" the early OF/DT documents. There may be as many expectations about formatting of a document as there are readers/consumers.

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#22 lore raw

PATCH v3 6/7 Documentation: add the binding file for Quadspi driver

Quoted 36 lines · Gerhard Sittig
Quoted 4 lines

+++ b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt

Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +2 -0
@@ -0,0 +1,31 @@
+* Freescale Quad Serial Peripheral Interface(QuadSPI)
+

Documentation/devicetree/bindings/mtd/fsl-quadspi.txt line 12

Quoted 10 lines
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +10 -0
+Required properties:
+- compatible : Should be "fsl,vf610-qspi"
+- reg : Offset and length of the register set for the device
+- interrupts : Should contain the interrupt for the device
+- clocks : The clocks needed by the QuadSPI controller
+- clock-names : the name of the clocks
+- fsl,nor-num : Contains the number of SPI NOR chips connected to
+                the controller.
+- fsl,nor-size : the size of each SPI NOR.
+- fsl,max-frequency : the frequency at which the SPI NOR works.

Those "fsl,*" properties somehow feel strange. I comment on details below the example since this should even better show why I feel so.

Quoted 17 lines
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +17 -0
+
+Example:
+
+qspi0: quadspi at 40044000 {
+	compatible = "fsl,vf610-qspi";
+	reg = <0x40044000 0x1000>;
+	interrupts = <0 24 0x04>;
+	clocks = <&clks VF610_CLK_QSPI0_EN>,
+		<&clks VF610_CLK_QSPI0>;
+	clock-names = "qspi_en", "qspi";
+	fsl,nor-num = <1>;
+	fsl,nor-size = <0x1000000>;
+	fsl,max-frequency = <66000000>;
+	status = "okay";
+
+	flash0: s25fl128s at 0 {
+		....
Quoted 8 lines

Documentation/devicetree/bindings/mtd/fsl-quadspi.txt line 31

Quoted 2 lines
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +2 -0
+	};
+};

The number of chips connected to the controller should reflect in the child nodes of the SPI NOR controller, and need not get specified in redundant ways and with potential for errors when they can get determined at runtime.

thanks. I have already removed this property in the next version.

Quoted 4 lines

The capacity of the flash chip as well as the maximum frequency which the flash chip operates at should be features of the flash chip (in combination with the board), i.e. of the child node and

agree.
thanks.

Quoted 9 lines

not the controller. SPI slaves already have a documented property for the purpose of limiting transfer rates when they are lower than the controller's i.e. busses capabilities. Can't tell from the top of my head whether there is a property for the maximum frequency which a controller should use across the whole bus. In any case, either the property needs to get moved, or the description should get updated to say "the max frequency at which the controller will send data" or something.

Quoted 5 lines

The capacity of the flash chip should be a consequence of either having gathered CFI information (if available) or having identified the chip by its JEDEC ID and looked up its features in an internal database. Users should not need to specify the capacity of the flash chip in the device tree.

I will remove it in the next version.

Quoted 15 lines

If the 'fsl,nor-size' property remains (which I doubt at the moment), you cannot describe "the size of each" chip in one single-cell spec. So the documentation should get extended to reflect multi-chip setups. But I'd rather assume that the property is not needed at all.

You can omit the 'status = "okay"' line since that is the default already in the absence of the keyword. This property is most useful to declare yet not enable by default components in .dtsi files and to do enable them in individual board files if applicable. This aspect need not be shown in the binding example of a QSPI controller.

Quoted 2 lines

I'd suggest to use symbolic names for the flags in the last interrupt specifier cell, as you do for clock items.

I will use the symbolic name if it has.
But if it not have a symbolic name, i have to keep it as it is now.

Thanks
Huang Shijie

#23 lore raw

PATCH v3 6/7 Documentation: add the binding file for Quadspi driver

Quoted 16 lines · Huang Shijie
Quoted 6 lines · Gerhard Sittig
Quoted 6 lines

+++ b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt [ ... ]

Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +4 -0
+Example:
+
+qspi0: quadspi at 40044000 {
+	compatible = "fsl,vf610-qspi";
Quoted 8 lines

Documentation/devicetree/bindings/mtd/fsl-quadspi.txt line 30

Quoted 4 lines
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file +3 -0
+	reg = <0x40044000 0x1000>;
+	interrupts = <0 24 0x04>;
[ ... ]
+};

[ ... ]
I'd suggest to use symbolic names for the flags in the last interrupt specifier cell, as you do for clock items.

Quoted 2 lines

I will use the symbolic name if it has.
But if it not have a symbolic name, i have to keep it as it is now.

To avoid potential confusion: I meant symbolic names for the _flags_ of the interrupt specifier (i.e. trigger type and polarity). The <dt-bindings/interrupt-controller/irq.h> file has IRQ_TYPE_LEVEL_HIGH with value 4 for you.

virtually yours
Gerhard Sittig

Signature · 3 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
#24 lore raw

PATCH v3 7/7 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 |  927 +++++++++++++++++++++++++++++++++++++
 3 files changed, 934 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/spi-nor/fsl-quadspi.c
drivers/mtd/spi-nor/Kconfig +6 -0
index 41591af..64cfc39 100644
@@ -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
index 7dfe1f9..51f9d8b 100644
@@ -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 +927 -0

927 lines not on this page · raw message

Signature · 1 line
1.7.2.rc3
#25 lore raw

PATCH v3 7/7 mtd: spi-nor: Add Freescale QuadSpi driver

On Monday, December 16, 2013 at 09:58:50 AM, Huang Shijie wrote:
[...]

drivers/mtd/spi-nor/fsl-quadspi.c line 166

Quoted 6 lines
drivers/mtd/spi-nor/fsl-quadspi.c new file +6 -0
+/* Macros for constructing the LUT register. */
+#define LUT0(ins, pad, opr)						\
+		(((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \
+		((LUT_##ins) << INSTR0_SHIFT))
+
+#define LUT1(ins, pad, opr)	(LUT0(ins, pad, opr) << OPRND1_SHIFT)

Change this into an inline function, that way you'd get type-checking here.

[...]

drivers/mtd/spi-nor/fsl-quadspi.c line 186

Quoted 3 lines
drivers/mtd/spi-nor/fsl-quadspi.c new file +3 -0
+enum fsl_qspi_devtype {
+	FSL_QUADSPI_VYBRID,
+	FSL_QUADSPI_IMX6SLX

Will the SLX be only a single-core chip?

drivers/mtd/spi-nor/fsl-quadspi.c line 198

Quoted 12 lines
drivers/mtd/spi-nor/fsl-quadspi.c new file +12 -0
+};
+
+struct fsl_qspi_devtype_data {
+	enum fsl_qspi_devtype devtype;
+	u32 memmap_base;
+	int rxfifo;
+	int txfifo;
+};
+
+static struct fsl_qspi_devtype_data vybrid_data = {
+	.devtype = FSL_QUADSPI_VYBRID,
+	.memmap_base = 0x20000000,

This memmap_base should come from DT prop.

drivers/mtd/spi-nor/fsl-quadspi.c line 200

Quoted 2 lines
drivers/mtd/spi-nor/fsl-quadspi.c new file +2 -0
+	.rxfifo = 128,
+	.txfifo = 64

Ditto for both of these too. They're HW props.

Quoted 1 line

+};

[...]

Best regards,
Marek Vasut

#26 lore raw

PATCH v3 7/7 mtd: spi-nor: Add Freescale QuadSpi driver

Quoted 11 lines · Marek Vasut

On Monday, December 16, 2013 at 09:58:50 AM, Huang Shijie wrote:
[...]

drivers/mtd/spi-nor/fsl-quadspi.c line 166

Quoted 6 lines
drivers/mtd/spi-nor/fsl-quadspi.c new file +6 -0
+/* Macros for constructing the LUT register. */
+#define LUT0(ins, pad, opr)						\
+		(((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \
+		((LUT_##ins) << INSTR0_SHIFT))
+
+#define LUT1(ins, pad, opr)	(LUT0(ins, pad, opr) << OPRND1_SHIFT)

Change this into an inline function, that way you'd get type-checking here.

Could an inline function do the name-link? such as LUT_##ins ?

Quoted 8 lines

[...]

drivers/mtd/spi-nor/fsl-quadspi.c line 186

Quoted 3 lines
drivers/mtd/spi-nor/fsl-quadspi.c new file +3 -0
+enum fsl_qspi_devtype {
+	FSL_QUADSPI_VYBRID,
+	FSL_QUADSPI_IMX6SLX

Will the SLX be only a single-core chip?

yes.

Quoted 15 lines

drivers/mtd/spi-nor/fsl-quadspi.c line 198

Quoted 13 lines
drivers/mtd/spi-nor/fsl-quadspi.c new file +12 -0
+};
+
+struct fsl_qspi_devtype_data {
+	enum fsl_qspi_devtype devtype;
+	u32 memmap_base;
+	int rxfifo;
+	int txfifo;
+};
+
+static struct fsl_qspi_devtype_data vybrid_data = {
+	.devtype = FSL_QUADSPI_VYBRID,
+	.memmap_base = 0x20000000,

This memmap_base should come from DT prop.

yes, i think it should be frome DT property.

Quoted 4 lines

drivers/mtd/spi-nor/fsl-quadspi.c line 200

Quoted 3 lines
drivers/mtd/spi-nor/fsl-quadspi.c new file +2 -0
+	.rxfifo = 128,
+	.txfifo = 64

these two depend on the IP, not board specific.
So they should not in the DT.

thanks
Huang Shijie

#27 lore raw

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

In reply to Huang Shijie

Hi Shijie,

Quoted 1 line

From: Huang Shijie [mailto:b32955 at freescale.com]

[...]

Quoted 9 lines

Huang Shijie (7):
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
mtd: spi-nor: add a helper to find the spi_device_id
Documentation: add the binding file for Quadspi driver
mtd: spi-nor: Add Freescale QuadSpi driver

Quoted 5 lines
.../devicetree/bindings/mtd/fsl-quadspi.txt        |   31 +
drivers/mtd/Kconfig                                |    2 +
drivers/mtd/Makefile                               |    1 +
drivers/mtd/devices/Kconfig                        |    2 +-
drivers/mtd/devices/m25p80.c                       | 1271 ++------------------

As much base code is copied from m25p90.c,
Do you mind keeping the sign-offs of the original contributors of m25p80.c at-least in patches where much code is ported ?
This would at-least give some credit to original authors and contributors.

with regards, pekon

#28 lore raw

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

Quoted 4 lines · Pekon

As much base code is copied from m25p90.c,
Do you mind keeping the sign-offs of the original contributors of m25p80.c at-least in patches where much code is ported ?

I have added the lines in the spi-nor.c:

" Cloned most of the code from the m25p80.c"

Quoted 1 line

This would at-least give some credit to original authors and contributors.

I do not change any authors information of m25p80.c.

If it is not enough? Could you remind me what to do ?

thanks
Huang Shijie

#29 lore raw

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

Quoted 6 lines

From: Huang Shijie [mailto:b32955 at freescale.com]

Quoted 4 lines · Pekon

As much base code is copied from m25p90.c,
Do you mind keeping the sign-offs of the original contributors of m25p80.c at-least in patches where much code is ported ?

Quoted 9 lines

I have added the lines in the spi-nor.c:

" Cloned most of the code from the m25p80.c"

Quoted 1 line

This would at-least give some credit to original authors and contributors.

I do not change any authors information of m25p80.c.

If it is not enough? Could you remind me what to do ?

(1) Add sign-offs of main authors of m25p80, so that original contributors still remains in path of submission [1].

(2) Also, please remove following from spi-nor.c However, you can keep this in fsl-quadspi.c. +MODULE_AUTHOR("Freescale Semiconductor Inc.");
I'm sure this was _not_ present in original m25p80.c
(m25p80.c was started as ST's driver as per MODULE_DESCRIPTION)

(3) +MODULE_LICENSE("GPL");
Also, I assume the license version should be "GPLv2" ?

Request you please _not_ to tag generic driver frameworks with any specific company names, and let open-source be independent of any commercial company tags. Otherwise eventually everything generic driver will have some or other company name associated with it.
And this should be followed by everyone (include myself).

I'm not sure why maintainers are not objecting to this. David, Brian ??

[1] https://www.kernel.org/doc/Documentation/SubmittingPatches
"12) Sign your work"

with regards, pekon

#30 lore raw

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

Quoted 10 lines · Pekon
Quoted 10 lines

From: Huang Shijie [mailto:b32955 at freescale.com]

Quoted 4 lines · Pekon

As much base code is copied from m25p90.c,
Do you mind keeping the sign-offs of the original contributors of m25p80.c at-least in patches where much code is ported ?

I have added the lines in the spi-nor.c:

" Cloned most of the code from the m25p80.c"

Quoted 7 lines
Quoted 5 lines
Quoted 1 line

This would at-least give some credit to original authors and contributors.

I do not change any authors information of m25p80.c.

If it is not enough? Could you remind me what to do ?

(1) Add sign-offs of main authors of m25p80, so that original contributors still remains in path of submission [1].

Do you mean add the sign-offs in end of the patch 3's commit message?:

Quoted 6 lines

(2) Also, please remove following from spi-nor.c However, you can keep this in fsl-quadspi.c. +MODULE_AUTHOR("Freescale Semiconductor Inc.");
I'm sure this was _not_ present in original m25p80.c
(m25p80.c was started as ST's driver as per MODULE_DESCRIPTION)

okay.

Quoted 3 lines

(3) +MODULE_LICENSE("GPL");
Also, I assume the license version should be "GPLv2" ?

yes. it should be v2.

thanks
Huang Shijie

#31 lore raw

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

Quoted 2 lines

From: Huang Shijie [mailto:b32955 at freescale.com]

Quoted 1 line

From: Pekon Gupta [mailto:pekon at ti.com]

[...]

Quoted 5 lines
Quoted 2 lines

(1) Add sign-offs of main authors of m25p80, so that original contributors still remains in path of submission [1].

Do you mean add the sign-offs in end of the patch 3's commit message?:

I think Mike's email ID is no-more valid. So you can either find out his current email-Id from other sources. OR
add David's or someone else's ID which has equivalent number of contributions in m25p80.c (that you can figure out from either commit logs or git blame).

Quoted 8 lines
Quoted 6 lines

(2) Also, please remove following from spi-nor.c However, you can keep this in fsl-quadspi.c. +MODULE_AUTHOR("Freescale Semiconductor Inc.");
I'm sure this was _not_ present in original m25p80.c
(m25p80.c was started as ST's driver as per MODULE_DESCRIPTION)

okay.

Thanks much.
You can put your name instead, I don't mind that bcoz you have worked to get this framework assembled by joining different pieces.

However, please use a email-id which is valid for long-term (preferably your personal ID), so that even if your association with your company ends, still there is some way to track you and keep you in loop of future patches for this framework.

Quoted 6 lines
Quoted 3 lines

(3) +MODULE_LICENSE("GPL");
Also, I assume the license version should be "GPLv2" ?

yes. it should be v2.

with regards, pekon

#32 lore raw

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

Quoted 5 lines · Pekon
Quoted 2 lines

From: Huang Shijie [mailto:b32955 at freescale.com]

Quoted 1 line

From: Pekon Gupta [mailto:pekon at ti.com]

[...]

Quoted 2 lines
Quoted 2 lines

(1) Add sign-offs of main authors of m25p80, so that original contributors still remains in path of submission [1].

Quoted 8 lines
Quoted 3 lines

Do you mean add the sign-offs in end of the patch 3's commit message?:

I think Mike's email ID is no-more valid. So you can either find out his current email-Id from other sources. OR
add David's or someone else's ID which has equivalent number of contributions in m25p80.c (that you can figure out from either commit logs or git blame).

ok, i will find other valid email ID, if i fail, i will add David's.

thanks
Huang Shijie

#33 lore raw

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

In reply to Gupta, Pekon
Quoted 6 lines · Pekon
Quoted 6 lines

From: Huang Shijie [mailto:b32955 at freescale.com]

Quoted 4 lines · Pekon

As much base code is copied from m25p90.c,
Do you mind keeping the sign-offs of the original contributors of m25p80.c at-least in patches where much code is ported ?

Quoted 8 lines
Quoted 8 lines

I have added the lines in the spi-nor.c:

" Cloned most of the code from the m25p80.c"

Quoted 1 line

This would at-least give some credit to original authors and contributors.

I do not change any authors information of m25p80.c.

If it is not enough? Could you remind me what to do ?

In case you clone most of the code from m25p80.c, you need to keep the copyright of that file as well, and add yours on top of it.

Quoted 3 lines
Quoted 1 line

(1) Add sign-offs of main authors of m25p80, so that original contributors still remains in path of submission [1].

The sign-off shouldn't be added by anyone than the person himself. The sign-off tag is generally used in the following cases as far as I know.

1. When the patch is authored, the author A should surely add his sign-off in the first place.

2. If person B submits A's patch with some or without any change on the patch, B should add his sign-off.

3. Maintainer C should add his sign-off when he applies the patch.

In any case, one's sign-off shouldn't be added anyone but himself. I do not see the need to add sign-off of m25p80 authors at the current situation.

Quoted 6 lines

(2) Also, please remove following from spi-nor.c However, you can keep this in fsl-quadspi.c. +MODULE_AUTHOR("Freescale Semiconductor Inc.");
I'm sure this was _not_ present in original m25p80.c
(m25p80.c was started as ST's driver as per MODULE_DESCRIPTION)

Are you talking about drivers/mtd/devices/m25p80.c? If so, I'm seeing the following lines in the file.

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mike Lavender"); MODULE_DESCRIPTION("MTD SPI driver for ST M25Pxx flash chips");

I think we should keep the original MODULE_LICENSE and MODULE_AUTHOR, add a new MODULE_AUTHOR("Huang Shijie <[email protected]>") line, and update MODULE_DESCRIPTION line properly.

Quoted 3 lines

(3) +MODULE_LICENSE("GPL");
Also, I assume the license version should be "GPLv2" ?

If this is from original m25p80.c, we shouldn't change it, IMO.

Quoted 4 lines

Request you please _not_ to tag generic driver frameworks with any specific company names, and let open-source be independent of any commercial company tags.

Are you sure about that? Run git grep "redhat" on folder kernel\ and see what you get.

Quoted 2 lines

Otherwise eventually everything generic driver will have some or other company name associated with it.

What's the problem of that? People are paid to do generic work, and why shouldn't their employer's name be mentioned to give the credit. As long as the copyright is GPL, the code can be used, modified and distributed freely, and I do not see any problem with having company name in there.

Shawn

Quoted 10 lines

And this should be followed by everyone (include myself).

I'm not sure why maintainers are not objecting to this. David, Brian ??

[1] https://www.kernel.org/doc/Documentation/SubmittingPatches
"12) Sign your work"

with regards, pekon

#34 lore raw

Hi Shawn,

Quoted 4 lines

From: Shawn Guo [mailto:shawn.guo at linaro.org]

Quoted 3 lines · Pekon
Quoted 2 lines

From: Huang Shijie [mailto:b32955 at freescale.com]

Quoted 1 line · Pekon

[...]

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

As much base code is copied from m25p90.c,
Do you mind keeping the sign-offs of the original contributors of m25p80.c at-least in patches where much code is ported ?

I have added the lines in the spi-nor.c:

" Cloned most of the code from the m25p80.c"

Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line

This would at-least give some credit to original authors and contributors.

I do not change any authors information of m25p80.c.

If it is not enough? Could you remind me what to do ?

In case you clone most of the code from m25p80.c, you need to keep the copyright of that file as well, and add yours on top of it.

Agree...

Quoted 10 lines
Quoted 3 lines
Quoted 1 line

(1) Add sign-offs of main authors of m25p80, so that original contributors still remains in path of submission [1].

The sign-off shouldn't be added by anyone than the person himself. The sign-off tag is generally used in the following cases as far as I know.

1. When the patch is authored, the author A should surely add his sign-off in the first place.

Quoted 9 lines

2. If person B submits A's patch with some or without any change on the patch, B should add his sign-off.

3. Maintainer C should add his sign-off when he applies the patch.

In any case, one's sign-off shouldn't be added anyone but himself. I do not see the need to add sign-off of m25p80 authors at the current situation.

Agree..
So I meant sign-off with permission from the original authors themselves. And Sign-offs can be multiple (but with permission of-course). OR, you can ask the original author to sign-off for you..

Quoted 10 lines
Quoted 6 lines

(2) Also, please remove following from spi-nor.c However, you can keep this in fsl-quadspi.c. +MODULE_AUTHOR("Freescale Semiconductor Inc.");
I'm sure this was _not_ present in original m25p80.c
(m25p80.c was started as ST's driver as per MODULE_DESCRIPTION)

Are you talking about drivers/mtd/devices/m25p80.c? If so, I'm seeing the following lines in the file.

Quoted 8 lines

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mike Lavender"); MODULE_DESCRIPTION("MTD SPI driver for ST M25Pxx flash chips");

I think we should keep the original MODULE_LICENSE and MODULE_AUTHOR, add a new MODULE_AUTHOR("Huang Shijie <[email protected]>") line, and update MODULE_DESCRIPTION line properly.

As indicated in previous thread also,
if the engineer's association with the company is broken then the email-id in MODULE_AUTHOR becomes invalid. Hence to keep long term tractability of the developer I suggested to use 'personal mail-id' here. MODULE_AUTHOR should have a email-id which is valid for long term, because you might need to at-least loop-in Author in longer time when there are some bug-fix or considerable code change.
(This problem was also pointed out earlier in one of the emails by greg-kh,
But I'm unable to trace that now).

Quoted 6 lines
Quoted 3 lines

(3) +MODULE_LICENSE("GPL");
Also, I assume the license version should be "GPLv2" ?

If this is from original m25p80.c, we shouldn't change it, IMO.

As I can understand from general threads on google.
GPLv2 gives some additional protection to free-software companies from patent litigations of proprietary software companies. As this code is not exact replica of m25p80.c, so it should be made GPLv2 or better .. But sincerely, I do not have too much knowledge into this,
So I'll let maintainers decide if they see benefit in moving to GPLv2 ?

Quoted 8 lines
Quoted 4 lines

Request you please _not_ to tag generic driver frameworks with any specific company names, and let open-source be independent of any commercial company tags.

Are you sure about that? Run git grep "redhat" on folder kernel\ and see what you get.

Something which may have been done repeatedly in past, may not mean it is correct OR the only way to do it. :-)

Quoted 9 lines
Quoted 2 lines

Otherwise eventually everything generic driver will have some or other company name associated with it.

What's the problem of that? People are paid to do generic work, and why shouldn't their employer's name be mentioned to give the credit. As long as the copyright is GPL, the code can be used, modified and distributed freely, and I do not see any problem with having company name in there.

It's not about who is taking credit. It's about how will you track the developer if after few years you want some significant changes in the code he wrote. You would agree, it's difficult to track developers just by their company names or company IDs.
It's perfectly okay, if you want to give credits of your work to anyone (whether any company or individual). But that you can mention in commit logs.

All I said was using company names in Headers or MODULE_AUTHOR of *generic frameworks*. A generic framework is maintained and updated by community at large. And over course of time other people contribute more than the author. So tagging a company name there would sound like _repeatedly_ giving credit to company or yourself, even if most of the original code is changed now. Does that make sense ?

So, I just suggested to keep generic framework code free from all these. However, You are free to do anything in your controller specific code.

with regards, pekon

#35 lore raw
Quoted 6 lines · Pekon

All I said was using company names in Headers or MODULE_AUTHOR of *generic frameworks*. A generic framework is maintained and updated by community at large. And over course of time other people contribute more than the author. So tagging a company name there would sound like _repeatedly_ giving credit to company or yourself, even if most of the original code is changed now. Does that make sense ?

I could somehow buy in the argument of using person email over company one in MODULE_AUTHOR(), but still not the one that do not use company name in Headers.

In this case, Huang works for Freescale and Freescale pays him to do the work, so Huang shares the authorship and Freescale shares the copyright. There is nothing wrong adding Freescale copyright into the file header, based on my understanding. When other people make significant changes and contributions to the file, they are welcomed to add more copyright info on top of the existing ones.

I'm not a lawyer, and more than happy to be corrected if I'm wrong.

Shawn