[U-Boot] [PATCH v9 02/21] mtd: Add SPI-NOR core support
Simon Glass
sjg at chromium.org
Sat Nov 5 17:10:14 CET 2016
Hi Jagan,
On 30 October 2016 at 12:23, Jagan Teki <jagan at openedev.com> wrote:
> Some of the SPI device drivers at drivers/spi not a real
> spi controllers, Unlike normal/generic SPI controllers they
> operates only with SPI-NOR flash devices. these were technically
> termed as SPI-NOR controllers, Ex: drivers/spi/fsl_qspi.c
>
> The problem with these were resides at drivers/spi is entire
> SPI layer becomes SPI-NOR flash oriented which is absolutely
> a wrong indication where SPI layer getting effected more with
> flash operations - So this SPI-NOR core will resolve this issue
> by separating all SPI-NOR flash operations from spi layer and
> creats a generic layer called SPI-NOR core which can be used to
> interact SPI-NOR to SPI driver interface layer and the SPI-NOR
> controller driver. The idea is taken from Linux spi-nor framework.
>
> ------------------------------
> cmd_sf.c
> ------------------------------
> mtd-uclass
> -------------------------------
> SPI-NOR Core
> -------------------------------
> m25p80.c zynq_qspi
> -------------------------------
> spi-uclass SPI NOR chip
> -------------------------------
> spi drivers
> -------------------------------
> SPI NOR chip
> -------------------------------
>
> Signed-off-by: Jagan Teki <jagan at openedev.com>
> ---
> Makefile | 1 +
> drivers/mtd/spi-nor/Makefile | 9 +
> drivers/mtd/spi-nor/spi-nor-ids.c | 176 +++++++++++
> drivers/mtd/spi-nor/spi-nor.c | 648 ++++++++++++++++++++++++++++++++++++++
> include/linux/err.h | 5 +
> include/linux/mtd/spi-nor.h | 207 ++++++++++++
> 6 files changed, 1046 insertions(+)
> create mode 100644 drivers/mtd/spi-nor/Makefile
> create mode 100644 drivers/mtd/spi-nor/spi-nor-ids.c
> create mode 100644 drivers/mtd/spi-nor/spi-nor.c
> create mode 100644 include/linux/mtd/spi-nor.h
>
[...]
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> new file mode 100644
> index 0000000..4e5b3ba
> --- /dev/null
> +++ b/include/linux/mtd/spi-nor.h
> @@ -0,0 +1,207 @@
> +/*
> + * SPI NOR Core header file.
> + *
> + * Copyright (C) 2016 Jagan Teki <jagan at openedev.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#ifndef __MTD_SPI_NOR_H
> +#define __MTD_SPI_NOR_H
> +
> +#include <common.h>
> +
> +/*
> + * Manufacturer IDs
> + *
> + * The first byte returned from the flash after sending opcode SPINOR_OP_RDID.
> + * Sometimes these are the same as CFI IDs, but sometimes they aren't.
> + */
> +#define SNOR_MFR_ATMEL 0x1f
> +#define SNOR_MFR_MACRONIX 0xc2
> +#define SNOR_MFR_MICRON 0x20 /* ST Micro <--> Micron */
> +#define SNOR_MFR_SPANSION 0x01
> +#define SNOR_MFR_SST 0xbf
> +#define SNOR_MFR_WINBOND 0xef
> +
> +/**
> + * SPI NOR opcodes.
> + *
> + * Note on opcode nomenclature: some opcodes have a format like
> + * SNOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
> + * of I/O lines used for the opcode, address, and data (respectively). The
> + * FUNCTION has an optional suffix of '4', to represent an opcode which
> + * requires a 4-byte (32-bit) address.
> + */
> +#define SNOR_OP_WRDI 0x04 /* Write disable */
> +#define SNOR_OP_WREN 0x06 /* Write enable */
> +#define SNOR_OP_RDSR 0x05 /* Read status register */
> +#define SNOR_OP_WRSR 0x01 /* Write status register 1 byte */
> +#define SNOR_OP_READ 0x03 /* Read data bytes (low frequency) */
> +#define SNOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */
> +#define SNOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */
> +#define SNOR_OP_READ_1_1_2_IO 0xbb /* Read data bytes (Dual IO SPI) */
> +#define SNOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */
> +#define SNOR_OP_READ_1_1_4_IO 0xeb /* Read data bytes (Quad IO SPI) */
> +#define SNOR_OP_BRWR 0x17 /* Bank register write */
> +#define SNOR_OP_BRRD 0x16 /* Bank register read */
> +#define SNOR_OP_WREAR 0xC5 /* Write extended address register */
> +#define SNOR_OP_RDEAR 0xC8 /* Read extended address register */
> +#define SNOR_OP_PP 0x02 /* Page program (up to 256 bytes) */
> +#define SNOR_OP_QPP 0x32 /* Quad Page program */
> +#define SNOR_OP_BE_4K 0x20 /* Erase 4KiB block */
> +#define SNOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
> +#define SNOR_OP_BE_32K 0x52 /* Erase 32KiB block */
> +#define SPINOR_OP_CHIP_ERASE 0xc7 /* Erase whole flash chip */
> +#define SNOR_OP_SE 0xd8 /* Sector erase (usually 64KiB) */
> +#define SNOR_OP_RDID 0x9f /* Read JEDEC ID */
> +#define SNOR_OP_RDCR 0x35 /* Read configuration register */
> +#define SNOR_OP_RDFSR 0x70 /* Read flag status register */
> +
> +/* Used for SST flashes only. */
> +#define SNOR_OP_BP 0x02 /* Byte program */
> +#define SNOR_OP_AAI_WP 0xad /* Auto addr increment word program */
> +
> +/* Status Register bits. */
> +#define SR_WIP BIT(0) /* Write in progress */
> +#define SR_WEL BIT(1) /* Write enable latch */
> +
> +/* meaning of other SR_* bits may differ between vendors */
> +#define SR_BP0 BIT(2) /* Block protect 0 */
> +#define SR_BP1 BIT(3) /* Block protect 1 */
> +#define SR_BP2 BIT(4) /* Block protect 2 */
> +#define SR_SRWD BIT(7) /* SR write protect */
> +
> +#define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */
> +
> +/* Flag Status Register bits */
> +#define FSR_READY BIT(7)
> +
> +/* Configuration Register bits. */
> +#define CR_QUAD_EN_SPAN BIT(1) /* Spansion/Winbond Quad I/O */
> +
> +/* Flash timeout values */
> +#define SNOR_READY_WAIT_PROG (2 * CONFIG_SYS_HZ)
> +#define SNOR_READY_WAIT_ERASE (5 * CONFIG_SYS_HZ)
> +#define SNOR_MAX_CMD_SIZE 4
> +#define SNOR_16MB_BOUN 0x1000000
> +
> +enum snor_option_flags {
> + SNOR_F_SST_WRITE = BIT(0),
> + SNOR_F_USE_FSR = BIT(1),
> + SNOR_F_U_PAGE = BIT(1),
> +};
> +
> +enum mode {
> + SNOR_READ = BIT(0),
> + SNOR_READ_1_1_2 = BIT(1),
> + SNOR_READ_1_1_4 = BIT(2),
> + SNOR_READ_1_1_2_IO = BIT(3),
> + SNOR_READ_1_1_4_IO = BIT(4),
> + SNOR_WRITE_1_1_BYTE = BIT(5),
> + SNOR_WRITE_1_1_4 = BIT(6),
> +};
> +
> +#define JEDEC_MFR(info) ((info)->id[0])
> +#define JEDEC_ID(info) (((info)->id[1]) << 8 | ((info)->id[2]))
> +#define JEDEC_EXT(info) (((info)->id[3]) << 8 | ((info)->id[4]))
> +#define SPI_NOR_MAX_ID_LEN 6
> +
> +struct spi_nor_info {
> + char *name;
> +
> + /*
> + * This array stores the ID bytes.
> + * The first three bytes are the JEDIC ID.
> + * JEDEC ID zero means "no ID" (mostly older chips).
> + */
> + u8 id[SPI_NOR_MAX_ID_LEN];
> + u8 id_len;
> +
> + /* The size listed here is what works with SNOR_OP_SE, which isn't
> + * necessarily called a "sector" by the vendor.
> + */
> + unsigned sector_size;
> + u16 n_sectors;
> +
> + u16 page_size;
> +
> + u16 flags;
> +#define SECT_4K BIT(0)
> +#define E_FSR BIT(1)
> +#define SST_WR BIT(2)
> +#define WR_QPP BIT(3)
> +#define RD_QUAD BIT(4)
> +#define RD_DUAL BIT(5)
> +#define RD_QUADIO BIT(6)
> +#define RD_DUALIO BIT(7)
> +#define RD_FULL (RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO)
> +};
> +
> +extern const struct spi_nor_info spi_nor_ids[];
> +
> +/**
> + * struct spi_nor - Structure for defining a the SPI NOR layer
> + *
> + * @dev: SPI NOR device
> + * @name: name of the SPI NOR device
> + * @page_size: the page size of the SPI NOR
> + * @addr_width: number of address bytes
> + * @erase_opcode: the opcode for erasing a sector
> + * @read_opcode: the read opcode
> + * @read_dummy: the dummy bytes needed by the read operation
> + * @program_opcode: the program opcode
> + * @max_write_size: If non-zero, the maximum number of bytes which can
> + * be written at once, excluding command bytes.
> + * @flags: flag options for the current SPI-NOR (SNOR_F_*)
> + * @mode: read, write mode or any other mode bits.
> + * @read_mode: read mode.
> + * @cmd_buf: used by the write_reg
> + * @read_reg: [DRIVER-SPECIFIC] read out the register
> + * @write_reg: [DRIVER-SPECIFIC] write data to the register
> + * @read: [DRIVER-SPECIFIC] read data from the SPI NOR
> + * @write: [DRIVER-SPECIFIC] write data to the SPI NOR
> + * @memory_map: address of read-only SPI NOR access
> + * @priv: the private data
> + */
> +struct spi_nor {
> + struct udevice *dev;
> + const char *name;
> + u32 page_size;
> + u8 addr_width;
> + u8 erase_opcode;
> + u8 read_opcode;
> + u8 read_dummy;
> + u8 program_opcode;
> + u32 max_write_size;
> + u32 flags;
> + u8 mode;
> + u8 read_mode;
> + u8 cmd_buf[SNOR_MAX_CMD_SIZE];
> +
> + int (*read_reg)(struct spi_nor *nor, u8 cmd, u8 *val, int len);
> + int (*write_reg)(struct spi_nor *nor, u8 cmd, u8 *data, int len);
> +
> + int (*read)(struct spi_nor *nor, loff_t from, size_t len,
> + u_char *read_buf);
> + int (*write)(struct spi_nor *nor, loff_t to, size_t len,
> + const u_char *write_buf);
Sos is SPI_NOR a uclass? It seems like you have different drivers for
it, and so it should be. Perhaps the SPI_NOR uclass should be a child
of the MTD uclass?
> +
> + void *memory_map;
> + void *priv;
> +};
> +
> +/**
> + * spi_nor_scan() - scan the SPI NOR
> + *
> + * @dev: SPI NOR device
> + *
> + * The drivers can use this fuction to scan the SPI NOR.
> + * In the scanning, it will try to get all the necessary information to
> + * fill the mtd_info{} and the spi_nor{}.
> + *
> + * @return 0 if OK, -ve on error
> + */
> +int spi_nor_scan(struct udevice *dev);
> +
> +#endif /* __MTD_SPI_NOR_H */
> --
> 2.7.4
>
Regards,
Simon
More information about the U-Boot
mailing list