[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