aboutsummaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0013-mtd-spi-QSPI-flash-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0013-mtd-spi-QSPI-flash-support.patch')
-rw-r--r--meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0013-mtd-spi-QSPI-flash-support.patch1763
1 files changed, 1763 insertions, 0 deletions
diff --git a/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0013-mtd-spi-QSPI-flash-support.patch b/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0013-mtd-spi-QSPI-flash-support.patch
new file mode 100644
index 0000000..beec9c9
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0013-mtd-spi-QSPI-flash-support.patch
@@ -0,0 +1,1763 @@
+From 423d01a1b367d82a3855972483530968309cbbd4 Mon Sep 17 00:00:00 2001
+From: Daisuke Matsushita <daisuke.matsushita.ns@hitachi.com>
+Date: Tue, 21 Mar 2017 15:05:15 +0900
+Subject: [PATCH] mtd: spi: Add QSPI flash
+
+This supports QSPI flash
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ arch/arm/include/asm/arch-rcar_gen3/rcar-base.h | 1
+ drivers/mtd/spi/sf.c | 15
+ drivers/mtd/spi/sf_internal.h | 195 ++++++---
+ drivers/mtd/spi/sf_ops.c | 64 +++
+ drivers/mtd/spi/sf_params.c | 249 +++++++-----
+ drivers/mtd/spi/sf_probe.c | 72 +--
+ drivers/spi/Makefile | 1
+ drivers/spi/rcar_gen3_qspi.c | 484 ++++++++++++++++++++++++
+ drivers/spi/rcar_gen3_qspi.h | 301 ++++++++++++++
+ include/linux/bitops.h | 1
+ include/spi.h | 22 -
+ 11 files changed, 1191 insertions(+), 214 deletions(-)
+ create mode 100644 drivers/spi/rcar_gen3_qspi.c
+ create mode 100644 drivers/spi/rcar_gen3_qspi.h
+
+diff --git a/arch/arm/include/asm/arch-rcar_gen3/rcar-base.h b/arch/arm/include/asm/arch-rcar_gen3/rcar-base.h
+index 59d34b8..b75e4fb 100644
+--- a/arch/arm/include/asm/arch-rcar_gen3/rcar-base.h
++++ b/arch/arm/include/asm/arch-rcar_gen3/rcar-base.h
+@@ -18,6 +18,7 @@
+ #define LBSC_BASE 0xEE220200
+ #define TMU_BASE 0xE61E0000
+ #define GPIO5_BASE 0xE6055000
++#define SH_QSPI_BASE 0xEE200000
+
+ /* SCIF */
+ #define SCIF0_BASE 0xE6E60000
+diff --git a/drivers/mtd/spi/sf.c b/drivers/mtd/spi/sf.c
+index 664e860..4e27bab 100644
+--- a/drivers/mtd/spi/sf.c
++++ b/drivers/mtd/spi/sf.c
+@@ -8,7 +8,11 @@
+ */
+
+ #include <common.h>
++#if defined(CONFIG_RCAR_GEN3)
++#include "../../spi/rcar_gen3_qspi.h"
++#else
+ #include <spi.h>
++#endif
+
+ static int spi_flash_read_write(struct spi_slave *spi,
+ const u8 *cmd, size_t cmd_len,
+@@ -25,16 +29,13 @@ static int spi_flash_read_write(struct spi_slave *spi,
+ if (data_len == 0)
+ flags |= SPI_XFER_END;
+
+- ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
++ ret = spi_xfer_cmd(spi, *cmd);
+ if (ret) {
+- debug("SF: Failed to send command (%zu bytes): %d\n",
+- cmd_len, ret);
++ debug("SF: Failed to send command (%zu bytes): %d\n", cmd_len, ret);
+ } else if (data_len != 0) {
+- ret = spi_xfer(spi, data_len * 8, data_out, data_in,
+- SPI_XFER_END);
++ ret = spi_xfer(spi, data_len * 8, data_out, data_in, flags|SPI_XFER_END);
+ if (ret)
+- debug("SF: Failed to transfer %zu bytes of data: %d\n",
+- data_len, ret);
++ debug("SF: Failed to transfer %zu bytes of data: %d\n", data_len, ret);
+ }
+
+ return ret;
+diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
+index 785f7a9..aacee1a 100644
+--- a/drivers/mtd/spi/sf_internal.h
++++ b/drivers/mtd/spi/sf_internal.h
+@@ -12,6 +12,7 @@
+
+ #include <linux/types.h>
+ #include <linux/compiler.h>
++#include <spi_flash.h>
+
+ /* Dual SPI flash memories - see SPI_COMM_DUAL_... */
+ enum spi_dual_flash {
+@@ -20,33 +21,6 @@ enum spi_dual_flash {
+ SF_DUAL_PARALLEL_FLASH = 1 << 1,
+ };
+
+-/* Enum list - Full read commands */
+-enum spi_read_cmds {
+- ARRAY_SLOW = 1 << 0,
+- ARRAY_FAST = 1 << 1,
+- DUAL_OUTPUT_FAST = 1 << 2,
+- DUAL_IO_FAST = 1 << 3,
+- QUAD_OUTPUT_FAST = 1 << 4,
+- QUAD_IO_FAST = 1 << 5,
+-};
+-
+-/* Normal - Extended - Full command set */
+-#define RD_NORM (ARRAY_SLOW | ARRAY_FAST)
+-#define RD_EXTN (RD_NORM | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
+-#define RD_FULL (RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
+-
+-/* sf param flags */
+-enum {
+- SECT_4K = 1 << 0,
+- SECT_32K = 1 << 1,
+- E_FSR = 1 << 2,
+- SST_BP = 1 << 3,
+- SST_WP = 1 << 4,
+- WR_QPP = 1 << 5,
+-};
+-
+-#define SST_WR (SST_BP | SST_WP)
+-
+ #define SPI_FLASH_3B_ADDR_LEN 3
+ #define SPI_FLASH_CMD_LEN (1 + SPI_FLASH_3B_ADDR_LEN)
+ #define SPI_FLASH_16MB_BOUN 0x1000000
+@@ -57,31 +31,101 @@ enum {
+ #define SPI_FLASH_CFI_MFR_MACRONIX 0xc2
+ #define SPI_FLASH_CFI_MFR_WINBOND 0xef
+
+-/* Erase commands */
+-#define CMD_ERASE_4K 0x20
+-#define CMD_ERASE_32K 0x52
+-#define CMD_ERASE_CHIP 0xc7
+-#define CMD_ERASE_64K 0xd8
++/* Read Device ID */
++#define CMD_READ_ID 0x9f
++#define CMD_READ_SFDP 0x5a
++#define CMD_READ_QUAD_ID 0xaf
+
+-/* Write commands */
++/* Register Access */
++#define CMD_READ_STATUS 0x05
++#define CMD_READ_STATUS2 0x07
++#define CMD_READ_STATUS1 0x35
++#define CMD_READ_CONFIG 0x35
++#define CMD_READ_ANY_REG 0x65
+ #define CMD_WRITE_STATUS 0x01
+-#define CMD_PAGE_PROGRAM 0x02
+ #define CMD_WRITE_DISABLE 0x04
+-#define CMD_READ_STATUS 0x05
+-#define CMD_QUAD_PAGE_PROGRAM 0x32
+-#define CMD_READ_STATUS1 0x35
+ #define CMD_WRITE_ENABLE 0x06
+-#define CMD_READ_CONFIG 0x35
+-#define CMD_FLAG_STATUS 0x70
++#define CMD_WRITE_ANY_REG 0x71
++#define CMD_CLSR 0x30
++#define CMD_CLSR_ALT 0x82
++#define CMD_4BYTE_ADDR_MODE 0xb7
++#define CMD_SET_BURST_LEN 0xc0
++#define CMD_EVALUATE_ERASE_STATUS 0xd0
++#define CMD_ECC_READ 0x19
++#define CMD_ECC_READ_ADDR4 0x18
++#define CMD_DLPRD 0x41
++#define CMD_PNVDLR 0x43
++#define CMD_WVDLR 0x4a
+
+ /* Read commands */
+ #define CMD_READ_ARRAY_SLOW 0x03
++#define CMD_READ_ARRAY_SLOW_ADDR4 0x13
+ #define CMD_READ_ARRAY_FAST 0x0b
++#define CMD_READ_ARRAY_FAST_ADDR4 0x0c
+ #define CMD_READ_DUAL_OUTPUT_FAST 0x3b
+ #define CMD_READ_DUAL_IO_FAST 0xbb
++#define CMD_READ_DUAL_IO_FAST_ADDR4 0xbc
+ #define CMD_READ_QUAD_OUTPUT_FAST 0x6b
+ #define CMD_READ_QUAD_IO_FAST 0xeb
+-#define CMD_READ_ID 0x9f
++#define CMD_READ_QUAD_IO_FAST_ADDR4 0xec
++#define CMD_READ_QUAD_IO_DDR 0xed
++#define CMD_READ_QUAD_IO_DDR_ADDR4 0xee
++
++/* Write commands */
++#define CMD_PAGE_PROGRAM 0x02
++#define CMD_PAGE_PROGRAM_ADDR4 0x12
++#define CMD_QUAD_PAGE_PROGRAM 0x32
++#define CMD_FLAG_STATUS 0x70
++
++/* Erase commands */
++#define CMD_ERASE_4K 0x20
++#define CMD_ERASE_4K_ADDR4 0x21
++#define CMD_ERASE_32K 0x52
++#define CMD_ERASE_CHIP 0xc7
++#define CMD_ERASE_64K 0xd8
++#define CMD_ERASE_256K_ADDR4 0xdc
++#define CMD_BULK_ERASE 0x60
++#define CMD_BULK_ERASE_ALT 0xc7
++
++/* Erase Program / Suspend Program */
++#define CMD_EPS 0x75
++#define CMD_EPS_ALT 0x85
++#define CMD_EPS_ALT2 0xb0
++#define CMD_EPR 0x7a
++#define CMD_EPR_ALT 0x8a
++#define CMD_EPR_ALT2 0x30
++
++/* One Time Program Array */
++#define CMD_OTP_PROGRAM 0x42
++#define CMD_OTP_READ 0x4b
++
++/* Advanced Sector Protection */
++#define CMD_DYB_READ 0xfa
++#define CMD_DYB_READ_ADDR4 0xe0
++#define CMD_DYB_WRITE 0xfb
++#define CMD_DYB_WRITE_ADDR4 0xe1
++#define CMD_PPB_READ 0xfc
++#define CMD_PPB_READ_ADDR4 0xe2
++#define CMD_PPB_PROGRAM 0xfd
++#define CMD_PPB_PROGRAM_ADDR4 0xe3
++#define CMD_PPB_ERASE 0xe4
++#define CMD_ASP_READ 0x2b
++#define CMD_ASP_PROGRAM 0x2f
++#define CMD_PPB_LOCKBIT_READ 0xa7
++#define CMD_PPB_LOCKBIT_WRITE 0xa6
++#define CMD_PASSWD_READ 0xe7
++#define CMD_PASSWD_PROGRAM 0xe8
++#define CMD_PASSWD_UNLOCK 0xe9
++
++/* Reset */
++#define CMD_SOFT_RESET_ENABLE 0x66
++#define CMD_SOFT_RESET 0x99
++#define CMD_LEGACY_SOFT_RESET 0xf0
++#define CMD_MODE_BIT_RESET 0xff
++
++/* DPD */
++#define CMD_ENT_DEEP_POWER_DOWN 0xb9
++#define CMD_REL_DEEP_POWER_DOWN 0xab
+
+ /* Bank addr access commands */
+ #ifdef CONFIG_SPI_FLASH_BAR
+@@ -94,13 +138,22 @@ enum {
+ /* Common status */
+ #define STATUS_WIP (1 << 0)
+ #define STATUS_QEB_WINSPAN (1 << 1)
+-#define STATUS_QEB_MXIC (1 << 6)
++#define STATUS_QEB_MXIC (1 << 6)
+ #define STATUS_PEC (1 << 7)
+
+ #ifdef CONFIG_SYS_SPI_ST_ENABLE_WP_PIN
+ #define STATUS_SRWD (1 << 7) /* SR write protect */
+ #endif
+
++/* Status Register 1(SR1V) */
++#define SR1V_WEL (1 << 1)
++#define SR1V_WIP (1 << 0)
++
++/* Status Register 2(SR2V) */
++#define SR2V_ESTAT (1 << 2)
++#define SR2V_ES (1 << 1)
++#define SR2V_PS (1 << 0)
++
+ /* Flash timeout values */
+ #define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ)
+ #define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ)
+@@ -117,25 +170,43 @@ int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
+ const void *buf);
+ #endif
+
+-/**
+- * struct spi_flash_params - SPI/QSPI flash device params structure
+- *
+- * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO])
+- * @jedec: Device jedec ID (0x[1byte_manuf_id][2byte_dev_id])
+- * @ext_jedec: Device ext_jedec ID
+- * @sector_size: Sector size of this device
+- * @nr_sectors: No.of sectors on this device
+- * @e_rd_cmd: Enum list for read commands
+- * @flags: Important param, for flash specific behaviour
+- */
++#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 JEDEC_FID(info) ((info)->id[5])
++#define SPI_FLASH_MAX_ID_LEN 6
++
+ struct spi_flash_params {
+- const char *name;
+- u32 jedec;
+- u16 ext_jedec;
+- u32 sector_size;
+- u32 nr_sectors;
+- u8 e_rd_cmd;
+- u16 flags;
++ /* Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) */
++ const 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_FLASH_MAX_ID_LEN];
++ u8 id_len;
++
++ /*
++ * The size listed here is what works with SPINOR_OP_SE, which isn't
++ * necessarily called a "sector" by the vendor.
++ */
++ u32 sector_size;
++ u32 n_sectors;
++
++ u16 page_size;
++
++ u16 flags;
++#define SECT_4K BIT(0) /* CMD_ERASE_4K works uniformly */
++#define E_FSR BIT(1) /* use flag status register for */
++#define SST_WR BIT(2) /* use SST byte/word programming */
++#define WR_QPP BIT(3) /* use Quad Page Program */
++#define RD_QUAD BIT(4) /* use Quad Read */
++#define RD_DUAL BIT(5) /* use Dual Read */
++#define RD_QUADIO BIT(6) /* use Quad IO Read */
++#define RD_DUALIO BIT(7) /* use Dual IO Read */
++#define RD_FULL (RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO)
+ };
+
+ extern const struct spi_flash_params spi_flash_params_table[];
+@@ -164,6 +235,12 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len);
+ /* Read the status register */
+ int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs);
+
++/* Read the status register2 */
++int spi_flash_cmd_read_status2(struct spi_flash *flash, u8 *rs);
++
++/* Evaluate Erase Status */
++int spi_flash_cmd_evaluate_erase_status(struct spi_flash *flash, u32 addr);
++
+ /* Program the status register */
+ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws);
+
+diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
+index 34bc54e..6af38c1 100644
+--- a/drivers/mtd/spi/sf_ops.c
++++ b/drivers/mtd/spi/sf_ops.c
+@@ -11,7 +11,11 @@
+ #include <common.h>
+ #include <errno.h>
+ #include <malloc.h>
++#if defined(CONFIG_RCAR_GEN3)
++#include "../../spi/rcar_gen3_qspi.h"
++#else
+ #include <spi.h>
++#endif
+ #include <spi_flash.h>
+ #include <watchdog.h>
+
+@@ -40,6 +44,38 @@ int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs)
+ return 0;
+ }
+
++int spi_flash_cmd_read_status2(struct spi_flash *flash, u8 *rs)
++{
++ int ret;
++ u8 cmd;
++
++ cmd = CMD_READ_STATUS2;
++ ret = spi_flash_read_common(flash, &cmd, 1, rs, 1);
++ if (ret < 0) {
++ debug("SF: fail to read status register2\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++int spi_flash_cmd_evaluate_erase_status(struct spi_flash *flash, u32 addr)
++{
++ int ret;
++ u8 cmd;
++
++ cmd = CMD_EVALUATE_ERASE_STATUS;
++ spi_set_addr(addr & 0x00ffffff);
++
++ ret = spi_xfer_cmd(flash->spi, (int)cmd);
++ if (ret < 0) {
++ debug("SF: fail to Evaluate Erase Status\n");
++ return ret;
++ }
++
++ return 0;
++}
++
+ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws)
+ {
+ u8 cmd;
+@@ -158,7 +194,10 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
+ {
+ struct spi_slave *spi = flash->spi;
+ unsigned long timebase;
++#ifdef CONFIG_SF_DUAL_FLASH
+ unsigned long flags = SPI_XFER_BEGIN;
++#endif
++
+ int ret;
+ u8 status;
+ u8 check_status = 0x0;
+@@ -174,7 +213,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
+ if (spi->flags & SPI_XFER_U_PAGE)
+ flags |= SPI_XFER_U_PAGE;
+ #endif
+- ret = spi_xfer(spi, 8, &cmd, NULL, flags);
++ ret = spi_xfer_cmd(spi, cmd);
+ if (ret) {
+ debug("SF: fail to read %s status register\n",
+ cmd == CMD_READ_STATUS ? "read" : "flag");
+@@ -250,6 +289,8 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
+ u32 erase_size, erase_addr;
+ u8 cmd[SPI_FLASH_CMD_LEN];
+ int ret = -1;
++ u8 read_sts;
++ int wait_msec, wait_interval;
+
+ erase_size = flash->erase_size;
+ if (offset % erase_size || len % erase_size) {
+@@ -270,6 +311,7 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
+ if (ret < 0)
+ return ret;
+ #endif
++ spi_set_addr(erase_addr);
+ spi_flash_addr(erase_addr, cmd);
+
+ debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
+@@ -285,6 +327,24 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
+ len -= erase_size;
+ }
+
++ /* Wait for Erase Complete */
++ wait_msec = 0;
++ wait_interval = 100;
++ while (wait_msec < 3000) { /* Max 3sec */
++ mdelay(wait_interval);
++ ret = spi_flash_cmd_evaluate_erase_status(flash, offset-erase_size);
++ WaitReadyDevice(flash->spi);
++ ret = spi_flash_cmd_read_status2(flash, &read_sts);
++ if (read_sts & SR2V_ESTAT) {
++ break;
++ }
++ wait_msec += wait_interval;
++ }
++
++ if ((ret != 0) || (read_sts != SR2V_ESTAT)) {
++ ret = -1;
++ }
++
+ return ret;
+ }
+
+@@ -319,6 +379,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
+ chunk_len = min(chunk_len,
+ (size_t)flash->spi->max_write_size);
+
++ spi_set_addr(write_addr);
+ spi_flash_addr(write_addr, cmd);
+
+ debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
+@@ -409,6 +470,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
+ else
+ read_len = remain_len;
+
++ spi_set_addr(read_addr);
+ spi_flash_addr(read_addr, cmd);
+
+ ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len);
+diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c
+index c12e8c6..bd19bfb 100644
+--- a/drivers/mtd/spi/sf_params.c
++++ b/drivers/mtd/spi/sf_params.c
+@@ -12,129 +12,172 @@
+
+ #include "sf_internal.h"
+
+-/* SPI/QSPI flash device params structure */
++/* Used when the "_ext_id" is two bytes at most */
++#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
++ .id = { \
++ ((_jedec_id) >> 16) & 0xff, \
++ ((_jedec_id) >> 8) & 0xff, \
++ (_jedec_id) & 0xff, \
++ ((_ext_id) >> 8) & 0xff, \
++ (_ext_id) & 0xff, \
++ }, \
++ .id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))), \
++ .sector_size = (_sector_size), \
++ .n_sectors = (_n_sectors), \
++ .page_size = 256, \
++ .flags = (_flags),
++
++#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
++ .id = { \
++ ((_jedec_id) >> 16) & 0xff, \
++ ((_jedec_id) >> 8) & 0xff, \
++ (_jedec_id) & 0xff, \
++ ((_ext_id) >> 16) & 0xff, \
++ ((_ext_id) >> 8) & 0xff, \
++ (_ext_id) & 0xff, \
++ }, \
++ .id_len = 6, \
++ .sector_size = (_sector_size), \
++ .n_sectors = (_n_sectors), \
++ .page_size = 256, \
++ .flags = (_flags),
++
+ const struct spi_flash_params spi_flash_params_table[] = {
+ #ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */
+- {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, RD_NORM, SECT_4K},
+- {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K},
+- {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K},
+- {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K},
+- {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, RD_NORM, SECT_4K},
+- {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K},
+- {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
+- {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K},
++ {"at45db011d", INFO(0x1f2200, 0x0, 64 * 1024, 4, SECT_4K) },
++ {"at45db021d", INFO(0x1f2300, 0x0, 64 * 1024, 8, SECT_4K) },
++ {"at45db041d", INFO(0x1f2400, 0x0, 64 * 1024, 8, SECT_4K) },
++ {"at45db081d", INFO(0x1f2500, 0x0, 64 * 1024, 16, SECT_4K) },
++ {"at45db161d", INFO(0x1f2600, 0x0, 64 * 1024, 32, SECT_4K) },
++ {"at45db321d", INFO(0x1f2700, 0x0, 64 * 1024, 64, SECT_4K) },
++ {"at45db641d", INFO(0x1f2800, 0x0, 64 * 1024, 128, SECT_4K) },
++ {"at25df321a", INFO(0x1f4701, 0x0, 64 * 1024, 64, SECT_4K) },
++ {"at25df321", INFO(0x1f4700, 0x0, 64 * 1024, 64, SECT_4K) },
++ {"at26df081a", INFO(0x1f4501, 0x0, 64 * 1024, 16, SECT_4K) },
+ #endif
+ #ifdef CONFIG_SPI_FLASH_EON /* EON */
+- {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, RD_NORM, 0},
+- {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
+- {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, RD_NORM, 0},
+- {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, RD_NORM, 0},
++ {"en25q32b", INFO(0x1c3016, 0x0, 64 * 1024, 64, 0) },
++ {"en25q64", INFO(0x1c3017, 0x0, 64 * 1024, 128, SECT_4K) },
++ {"en25q128b", INFO(0x1c3018, 0x0, 64 * 1024, 256, 0) },
++ {"en25s64", INFO(0x1c3817, 0x0, 64 * 1024, 128, 0) },
+ #endif
+ #ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */
+- {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
+- {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K},
++ {"gd25q64b", INFO(0xc84017, 0x0, 64 * 1024, 128, SECT_4K) },
++ {"gd25lq32", INFO(0xc86016, 0x0, 64 * 1024, 64, SECT_4K) },
++#endif
++#ifdef CONFIG_SPI_FLASH_ISSI /* ISSI */
++ {"is25lp032", INFO(0x9d6016, 0x0, 64 * 1024, 64, 0) },
++ {"is25lp064", INFO(0x9d6017, 0x0, 64 * 1024, 128, 0) },
++ {"is25lp128", INFO(0x9d6018, 0x0, 64 * 1024, 256, 0) },
+ #endif
+ #ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */
+- {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, RD_NORM, 0},
+- {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, RD_NORM, 0},
+- {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, RD_NORM, 0},
+- {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, RD_NORM, 0},
+- {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, RD_NORM, 0},
+- {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, RD_NORM, 0},
+- {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
+- {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP},
+- {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP},
+- {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
++ {"mx25l2006e", INFO(0xc22012, 0x0, 64 * 1024, 4, 0) },
++ {"mx25l4005", INFO(0xc22013, 0x0, 64 * 1024, 8, 0) },
++ {"mx25l8005", INFO(0xc22014, 0x0, 64 * 1024, 16, 0) },
++ {"mx25l1605d", INFO(0xc22015, 0x0, 64 * 1024, 32, 0) },
++ {"mx25l3205d", INFO(0xc22016, 0x0, 64 * 1024, 64, 0) },
++ {"mx25l6405d", INFO(0xc22017, 0x0, 64 * 1024, 128, 0) },
++ {"mx25l12805", INFO(0xc22018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP) },
++ {"mx25l25635f", INFO(0xc22019, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP) },
++ {"mx25l51235f", INFO(0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL | WR_QPP) },
++ {"mx25l12855e", INFO(0xc22618, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP) },
++ {"mx66u51235f", INFO(0xc2253a, 0x0, 64 * 1024, 1024, RD_FULL | WR_QPP) },
++ {"mx66l1g45g", INFO(0xc2201b, 0x0, 64 * 1024, 2048, RD_FULL | WR_QPP) },
+ #endif
+ #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */
+- {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, RD_NORM, 0},
+- {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, RD_NORM, 0},
+- {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, RD_NORM, 0},
+- {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, RD_NORM, 0},
+- {"S25FL116K", 0x014015, 0x0, 64 * 1024, 128, RD_NORM, 0},
+- {"S25FL164K", 0x014017, 0x0140, 64 * 1024, 128, RD_NORM, 0},
+- {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, RD_FULL, WR_QPP},
+- {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, RD_FULL, WR_QPP},
+- {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, RD_FULL, WR_QPP},
+- {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, RD_FULL, WR_QPP},
+- {"S25FL128S_256K", 0x012018, 0x4d00, 256 * 1024, 64, RD_FULL, WR_QPP},
+- {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, RD_FULL, WR_QPP},
+- {"S25FL256S_256K", 0x010219, 0x4d00, 256 * 1024, 128, RD_FULL, WR_QPP},
+- {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_FULL, WR_QPP},
+- {"S25FL512S_256K", 0x010220, 0x4d00, 256 * 1024, 256, RD_FULL, WR_QPP},
+- {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, RD_FULL, WR_QPP},
+- {"S25FL512S_512K", 0x010220, 0x4f00, 256 * 1024, 256, RD_FULL, WR_QPP},
++ {"s25fl008a", INFO(0x010213, 0x0, 64 * 1024, 16, 0) },
++ {"s25fl016a", INFO(0x010214, 0x0, 64 * 1024, 32, 0) },
++ {"s25fl032a", INFO(0x010215, 0x0, 64 * 1024, 64, 0) },
++ {"s25fl064a", INFO(0x010216, 0x0, 64 * 1024, 128, 0) },
++ {"s25fl116k", INFO(0x014015, 0x0, 64 * 1024, 128, 0) },
++ {"s25fl164k", INFO(0x014017, 0x0140, 64 * 1024, 128, 0) },
++ {"s25fl128p_256k", INFO(0x012018, 0x0300, 256 * 1024, 64, RD_FULL | WR_QPP) },
++ {"s25fl128p_64k", INFO(0x012018, 0x0301, 64 * 1024, 256, RD_FULL | WR_QPP) },
++ {"s25fl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, RD_FULL | WR_QPP) },
++ {"s25fl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, RD_FULL | WR_QPP) },
++ {"s25fl128s_256k", INFO(0x012018, 0x4d00, 256 * 1024, 64, RD_FULL | WR_QPP) },
++ {"s25fl128s_64k", INFO(0x012018, 0x4d01, 64 * 1024, 256, RD_FULL | WR_QPP) },
++ {"s25fl256s_256k", INFO(0x010219, 0x4d00, 256 * 1024, 128, RD_FULL | WR_QPP) },
++ {"s25fl256s_64k", INFO(0x010219, 0x4d01, 64 * 1024, 512, RD_FULL | WR_QPP) },
++ {"s25fs256s_64k", INFO6(0x010219, 0x4d0181, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
++ {"s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 2048, RD_FULL | WR_QPP | SECT_4K) },
++ {"s25fl512s_256k", INFO(0x010220, 0x4d00, 256 * 1024, 256, RD_FULL | WR_QPP) },
++ {"s25fl512s_64k", INFO(0x010220, 0x4d01, 64 * 1024, 1024, RD_FULL | WR_QPP) },
++ {"s25fl512s_512k", INFO(0x010220, 0x4f00, 256 * 1024, 256, RD_FULL | WR_QPP) },
+ #endif
+ #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */
+- {"M25P10", 0x202011, 0x0, 32 * 1024, 4, RD_NORM, 0},
+- {"M25P20", 0x202012, 0x0, 64 * 1024, 4, RD_NORM, 0},
+- {"M25P40", 0x202013, 0x0, 64 * 1024, 8, RD_NORM, 0},
+- {"M25P80", 0x202014, 0x0, 64 * 1024, 16, RD_NORM, 0},
+- {"M25P16", 0x202015, 0x0, 64 * 1024, 32, RD_NORM, 0},
+- {"M25PE16", 0x208015, 0x1000, 64 * 1024, 32, RD_NORM, 0},
+- {"M25PX16", 0x207115, 0x1000, 64 * 1024, 32, RD_EXTN, 0},
+- {"M25P32", 0x202016, 0x0, 64 * 1024, 64, RD_NORM, 0},
+- {"M25P64", 0x202017, 0x0, 64 * 1024, 128, RD_NORM, 0},
+- {"M25P128", 0x202018, 0x0, 256 * 1024, 64, RD_NORM, 0},
+- {"M25PX64", 0x207117, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
+- {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
+- {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
+- {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
+- {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
+- {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
+- {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
+- {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K},
+- {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K},
+- {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP | E_FSR | SECT_4K},
+- {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP | E_FSR | SECT_4K},
+- {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, RD_FULL, WR_QPP | E_FSR | SECT_4K},
+- {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, RD_FULL, WR_QPP | E_FSR | SECT_4K},
++ {"m25p10", INFO(0x202011, 0x0, 32 * 1024, 4, 0) },
++ {"m25p20", INFO(0x202012, 0x0, 64 * 1024, 4, 0) },
++ {"m25p40", INFO(0x202013, 0x0, 64 * 1024, 8, 0) },
++ {"m25p80", INFO(0x202014, 0x0, 64 * 1024, 16, 0) },
++ {"m25p16", INFO(0x202015, 0x0, 64 * 1024, 32, 0) },
++ {"m25pE16", INFO(0x208015, 0x1000, 64 * 1024, 32, 0) },
++ {"m25pX16", INFO(0x207115, 0x1000, 64 * 1024, 32, RD_QUAD | RD_DUAL) },
++ {"m25p32", INFO(0x202016, 0x0, 64 * 1024, 64, 0) },
++ {"m25p64", INFO(0x202017, 0x0, 64 * 1024, 128, 0) },
++ {"m25p128", INFO(0x202018, 0x0, 256 * 1024, 64, 0) },
++ {"m25pX64", INFO(0x207117, 0x0, 64 * 1024, 128, SECT_4K) },
++ {"n25q016a", INFO(0x20bb15, 0x0, 64 * 1024, 32, SECT_4K) },
++ {"n25q32", INFO(0x20ba16, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K) },
++ {"n25q32a", INFO(0x20bb16, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K) },
++ {"n25q64", INFO(0x20ba17, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K) },
++ {"n25q64a", INFO(0x20bb17, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K) },
++ {"n25q128", INFO(0x20ba18, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP) },
++ {"n25q128a", INFO(0x20bb18, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP) },
++ {"n25q256", INFO(0x20ba19, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
++ {"n25q256a", INFO(0x20bb19, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
++ {"n25q512", INFO(0x20ba20, 0x0, 64 * 1024, 1024, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
++ {"n25q512a", INFO(0x20bb20, 0x0, 64 * 1024, 1024, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
++ {"n25q1024", INFO(0x20ba21, 0x0, 64 * 1024, 2048, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
++ {"n25q1024a", INFO(0x20bb21, 0x0, 64 * 1024, 2048, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
++ {"mt25qu02g", INFO(0x20bb22, 0x0, 64 * 1024, 4096, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
++ {"mt25ql02g", INFO(0x20ba22, 0x0, 64 * 1024, 4096, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+ #endif
+ #ifdef CONFIG_SPI_FLASH_SST /* SST */
+- {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR},
+- {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K | SST_WR},
+- {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, RD_NORM, SECT_4K | SST_WR},
+- {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K | SST_WR},
+- {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
+- {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, RD_NORM, SECT_4K | SST_WR},
+- {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, RD_NORM, SECT_4K | SST_WR},
+- {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, RD_NORM, SECT_4K | SST_WR},
+- {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR},
+- {"SST25WF040B", 0x621613, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR},
+- {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K | SST_WR},
++ {"sst25vf040b", INFO(0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | SST_WR) },
++ {"sst25vf080b", INFO(0xbf258e, 0x0, 64 * 1024, 16, SECT_4K | SST_WR) },
++ {"sst25vf016b", INFO(0xbf2541, 0x0, 64 * 1024, 32, SECT_4K | SST_WR) },
++ {"sst25vf032b", INFO(0xbf254a, 0x0, 64 * 1024, 64, SECT_4K | SST_WR) },
++ {"sst25vf064c", INFO(0xbf254b, 0x0, 64 * 1024, 128, SECT_4K) },
++ {"sst25wf512", INFO(0xbf2501, 0x0, 64 * 1024, 1, SECT_4K | SST_WR) },
++ {"sst25wf010", INFO(0xbf2502, 0x0, 64 * 1024, 2, SECT_4K | SST_WR) },
++ {"sst25wf020", INFO(0xbf2503, 0x0, 64 * 1024, 4, SECT_4K | SST_WR) },
++ {"sst25wf040", INFO(0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | SST_WR) },
++ {"sst25wf040b", INFO(0x621613, 0x0, 64 * 1024, 8, SECT_4K) },
++ {"sst25wf080", INFO(0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | SST_WR) },
+ #endif
+ #ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */
+- {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, RD_NORM, 0},
+- {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, RD_NORM, 0},
+- {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, RD_NORM, 0},
+- {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K},
+- {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, RD_NORM, SECT_4K},
+- {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K},
+- {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
+- {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, RD_FULL, WR_QPP | SECT_4K},
+- {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, RD_FULL, WR_QPP | SECT_4K},
+- {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
+- {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
+- {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP | SECT_4K},
+- {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K},
+- {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, RD_FULL, WR_QPP | SECT_4K},
+- {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, RD_FULL, WR_QPP | SECT_4K},
+- {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
+- {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
+- {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP | SECT_4K},
++ {"w25p80", INFO(0xef2014, 0x0, 64 * 1024, 16, 0) },
++ {"w25p16", INFO(0xef2015, 0x0, 64 * 1024, 32, 0) },
++ {"w25p32", INFO(0xef2016, 0x0, 64 * 1024, 64, 0) },
++ {"w25x40", INFO(0xef3013, 0x0, 64 * 1024, 8, SECT_4K) },
++ {"w25x16", INFO(0xef3015, 0x0, 64 * 1024, 32, SECT_4K) },
++ {"w25x32", INFO(0xef3016, 0x0, 64 * 1024, 64, SECT_4K) },
++ {"w25x64", INFO(0xef3017, 0x0, 64 * 1024, 128, SECT_4K) },
++ {"w25q80bl", INFO(0xef4014, 0x0, 64 * 1024, 16, RD_FULL | WR_QPP | SECT_4K) },
++ {"w25q16cl", INFO(0xef4015, 0x0, 64 * 1024, 32, RD_FULL | WR_QPP | SECT_4K) },
++ {"w25q32bv", INFO(0xef4016, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K) },
++ {"w25q64cv", INFO(0xef4017, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K) },
++ {"w25q128bv", INFO(0xef4018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP | SECT_4K) },
++ {"w25q256", INFO(0xef4019, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
++ {"w25q80bw", INFO(0xef5014, 0x0, 64 * 1024, 16, RD_FULL | WR_QPP | SECT_4K) },
++ {"w25q16dw", INFO(0xef6015, 0x0, 64 * 1024, 32, RD_FULL | WR_QPP | SECT_4K) },
++ {"w25q32dw", INFO(0xef6016, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K) },
++ {"w25q64dw", INFO(0xef6017, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K) },
++ {"w25q128fw", INFO(0xef6018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP | SECT_4K) },
+ #endif
+ {}, /* Empty entry to terminate the list */
+ /*
+ * Note:
+ * Below paired flash devices has similar spi_flash params.
+- * (S25FL129P_64K, S25FL128S_64K)
+- * (W25Q80BL, W25Q80BV)
+- * (W25Q16CL, W25Q16DV)
+- * (W25Q32BV, W25Q32FV_SPI)
+- * (W25Q64CV, W25Q64FV_SPI)
+- * (W25Q128BV, W25Q128FV_SPI)
+- * (W25Q32DW, W25Q32FV_QPI)
+- * (W25Q64DW, W25Q64FV_QPI)
+- * (W25Q128FW, W25Q128FV_QPI)
++ * (s25fl129p_64k, s25fl128s_64k)
++ * (w25q80bl, w25q80bv)
++ * (w25q16cl, w25q16dv)
++ * (w25q32bv, w25q32fv_spi)
++ * (w25q64cv, w25q64fv_spi)
++ * (w25q128bv, w25q128fv_spi)
++ * (w25q32dw, w25q32fv_qpi)
++ * (w25q64dw, w25q64fv_qpi)
++ * (w25q128fw, w25q128fv_qpi)
+ */
+ };
+diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
+index 4103723..28ef787 100644
+--- a/drivers/mtd/spi/sf_probe.c
++++ b/drivers/mtd/spi/sf_probe.c
+@@ -21,16 +21,6 @@
+
+ DECLARE_GLOBAL_DATA_PTR;
+
+-/* Read commands array */
+-static u8 spi_read_cmds_array[] = {
+- CMD_READ_ARRAY_SLOW,
+- CMD_READ_ARRAY_FAST,
+- CMD_READ_DUAL_OUTPUT_FAST,
+- CMD_READ_DUAL_IO_FAST,
+- CMD_READ_QUAD_OUTPUT_FAST,
+- CMD_READ_QUAD_IO_FAST,
+-};
+-
+ #ifdef CONFIG_SPI_FLASH_MACRONIX
+ static int spi_flash_set_qeb_mxic(struct spi_flash *flash)
+ {
+@@ -102,19 +92,27 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
+ struct spi_flash *flash)
+ {
+ const struct spi_flash_params *params;
+- u8 cmd;
++ u8 manufacture_id = idcode[0];
+ u16 jedec = idcode[1] << 8 | idcode[2];
+ u16 ext_jedec = idcode[3] << 8 | idcode[4];
++ u8 family_id = idcode[5];
+
+ /* Validate params from spi_flash_params table */
+ params = spi_flash_params_table;
+ for (; params->name != NULL; params++) {
+- if ((params->jedec >> 16) == idcode[0]) {
+- if ((params->jedec & 0xFFFF) == jedec) {
+- if (params->ext_jedec == 0)
+- break;
+- else if (params->ext_jedec == ext_jedec)
++ if (JEDEC_MFR(params) == manufacture_id) {
++ if (JEDEC_ID(params) == jedec) {
++ if (params->id_len - 3 == 0) {
+ break;
++ } else if (params->id_len - 3 == 2) {
++ if (JEDEC_EXT(params) == ext_jedec) {
++ break;
++ }
++ } else {
++ if ((JEDEC_EXT(params) == (ext_jedec & 0xFF00)) && (JEDEC_FID(params) == family_id)) {
++ break;
++ }
++ }
+ }
+ }
+ }
+@@ -149,48 +147,48 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
+
+ /* Compute the flash size */
+ flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
++ flash->page_size = params->page_size;
+ /*
+ * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the
+ * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with
+ * the 0x4d00 Extended JEDEC code have 512b pages. All of the others
+ * have 256b pages.
+ */
+- if (ext_jedec == 0x4d00) {
+- if ((jedec == 0x0215) || (jedec == 0x216))
+- flash->page_size = 256;
+- else
++ if ((ext_jedec & 0xFF00) == 0x4d00) {
++ if ((jedec != 0x0215) && (jedec != 0x0216) && (jedec != 0x220)) {
+ flash->page_size = 512;
+- } else {
+- flash->page_size = 256;
++ }
+ }
++
+ flash->page_size <<= flash->shift;
+ flash->sector_size = params->sector_size << flash->shift;
+- flash->size = flash->sector_size * params->nr_sectors << flash->shift;
++ flash->size = flash->sector_size * params->n_sectors << flash->shift;
+ #ifdef CONFIG_SF_DUAL_FLASH
+ if (flash->dual_flash & SF_DUAL_STACKED_FLASH)
+ flash->size <<= 1;
+ #endif
+
++#ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS
+ /* Compute erase sector and command */
+ if (params->flags & SECT_4K) {
+ flash->erase_cmd = CMD_ERASE_4K;
+ flash->erase_size = 4096 << flash->shift;
+- } else if (params->flags & SECT_32K) {
+- flash->erase_cmd = CMD_ERASE_32K;
+- flash->erase_size = 32768 << flash->shift;
+- } else {
+- flash->erase_cmd = CMD_ERASE_64K;
++ } else
++#endif
++ {
++ flash->erase_cmd = CMD_ERASE_256K_ADDR4;
+ flash->erase_size = flash->sector_size;
+ }
+
+ /* Look for the fastest read cmd */
+- cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx);
+- if (cmd) {
+- cmd = spi_read_cmds_array[cmd - 1];
+- flash->read_cmd = cmd;
++ if (flash->spi->op_mode_rx & SPI_RX_SLOW) {
++ flash->read_cmd = CMD_READ_ARRAY_SLOW;
++ } else if ((flash->spi->op_mode_rx & SPI_RX_QUAD) && (params->flags & RD_QUAD)) {
++ flash->read_cmd = CMD_READ_QUAD_OUTPUT_FAST;
++ } else if ((flash->spi->op_mode_rx & SPI_RX_DUAL) && (params->flags & RD_DUAL)) {
++ flash->read_cmd = CMD_READ_DUAL_OUTPUT_FAST;
+ } else {
+- /* Go for default supported read cmd */
+- flash->read_cmd = CMD_READ_ARRAY_FAST;
++ flash->read_cmd = CMD_READ_ARRAY_FAST_ADDR4;
+ }
+
+ /* Not require to look for fastest only two write cmds yet */
+@@ -198,7 +196,7 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
+ flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
+ else
+ /* Go for default supported write cmd */
+- flash->write_cmd = CMD_PAGE_PROGRAM;
++ flash->write_cmd = CMD_PAGE_PROGRAM_ADDR4;
+
+ /* Read dummy_byte: dummy byte is determined based on the
+ * dummy cycles of a particular command.
+@@ -324,7 +322,7 @@ static int spi_enable_wp_pin(struct spi_flash *flash)
+ */
+ int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash)
+ {
+- u8 idcode[5];
++ u8 idcode[SPI_FLASH_MAX_ID_LEN];
+ int ret;
+
+ /* Setup spi_slave */
+@@ -385,6 +383,7 @@ int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash)
+ puts("\n");
+ #endif
+ #ifndef CONFIG_SPI_FLASH_BAR
++#ifndef CONFIG_R8A7797
+ if (((flash->dual_flash == SF_SINGLE_FLASH) &&
+ (flash->size > SPI_FLASH_16MB_BOUN)) ||
+ ((flash->dual_flash > SF_SINGLE_FLASH) &&
+@@ -393,6 +392,7 @@ int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash)
+ puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
+ }
+ #endif
++#endif
+ if (spi_enable_wp_pin(flash))
+ puts("Enable WP pin failed\n");
+
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index ce6f1cc..fd1dd7c 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -39,6 +39,7 @@ obj-$(CONFIG_MXC_SPI) += mxc_spi.o
+ obj-$(CONFIG_MXS_SPI) += mxs_spi.o
+ obj-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o
+ obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o
++obj-$(CONFIG_RCAR_GEN3_QSPI) += rcar_gen3_qspi.o
+ obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
+ obj-$(CONFIG_SH_SPI) += sh_spi.o
+ obj-$(CONFIG_SH_QSPI) += sh_qspi.o
+diff --git a/drivers/spi/rcar_gen3_qspi.c b/drivers/spi/rcar_gen3_qspi.c
+new file mode 100644
+index 0000000..5095b07
+--- /dev/null
++++ b/drivers/spi/rcar_gen3_qspi.c
+@@ -0,0 +1,485 @@
++/*
++ * R-CarH3 QSPI (Quad SPI) driver
++ *
++ */
++
++#include <common.h>
++#include <malloc.h>
++#include "rcar_gen3_qspi.h"
++#include <asm/arch/rcar_gen3.h>
++#include <asm/arch/rpc-flash.h>
++#include <asm/io.h>
++
++#include "../mtd/spi/sf_internal.h"
++
++/* if DEBUG_PRINT defined, Output debug log */
++//#define DEBUG_PRINT
++#ifdef DEBUG_PRINT
++#define debug_print(format, arg...) printf("[DBG] " format, ## arg)
++#else
++#define debug_print(format, arg...) do {} while(0)
++#endif
++
++struct rcar_gen3_qspi_regs {
++ unsigned int cmncr;
++ unsigned int ssldr;
++ unsigned int dummy0;
++ unsigned int drcr;
++ unsigned int drcmr;
++ unsigned int drear;
++ unsigned int dropr;
++ unsigned int drenr;
++ unsigned int smcr;
++ unsigned int smcmr;
++ unsigned int smadr;
++ unsigned int smopr;
++ unsigned int smenr;
++ unsigned int dummy1;
++ unsigned int smrdr0;
++ unsigned int smrdr1;
++ unsigned int smwdr0;
++ unsigned int smwdr1;
++ unsigned int cmnsr;
++ unsigned int dummy2[3];
++ unsigned int drdmcr;
++ unsigned int drdrenr;
++ unsigned int smdmcr;
++ unsigned int smdrenr;
++ unsigned int dummy3[5];
++ unsigned int phycnt;
++ unsigned int phyoffset1;
++ unsigned int phyoffset2;
++ unsigned int phyint;
++ unsigned int dummy4[7];
++ unsigned int div_reg;
++};
++
++struct sh_qspi_slave {
++ struct spi_slave slave;
++ struct rcar_gen3_qspi_regs *regs;
++};
++
++const SPI_COMMAND spi_cmd_tbl[] = {
++ { CMD_READ_ID, SPI_CMD_READ, SPI_DATA_ENABLE, 0, 0, "Read ID (JEDEC Manufacturer ID and JEDEC CFI)" },
++ { CMD_READ_SFDP, SPI_CMD_READ, SPI_DATA_ENABLE, 3, 8, "Read JEDEC Serial Flash Discoverable Parameters" },
++ { CMD_READ_QUAD_ID, SPI_CMD_READ, SPI_DATA_ENABLE, 0, 0, "Read Quad ID" },
++ { CMD_READ_STATUS, SPI_CMD_READ, SPI_DATA_ENABLE, 0, 0, "Read Status Register-1" },
++ { CMD_READ_STATUS2, SPI_CMD_READ, SPI_DATA_ENABLE, 0, 0, "Read Status Register-2" },
++ { CMD_READ_CONFIG, SPI_CMD_READ, SPI_DATA_ENABLE, 0, 0, "Read Configuration Register-1" },
++ { CMD_READ_ANY_REG, SPI_CMD_READ, SPI_DATA_ENABLE, 3, 8, "Read Any Register" },
++ { CMD_WRITE_STATUS, SPI_CMD_WRITE, SPI_DATA_ENABLE, 0, 0, "Write Register (Status-1, Configuration-1)" },
++ { CMD_WRITE_DISABLE, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Write Disable" },
++ { CMD_WRITE_ENABLE, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Write Enable" },
++ { CMD_WRITE_ANY_REG, SPI_CMD_WRITE, SPI_DATA_ENABLE, 3, 0, "Write Any Register" },
++ { CMD_CLSR, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Clear Status Register-1 - Erase/Prog. Fail Reset" },
++ { CMD_CLSR_ALT, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Clear Status Register-1 - Erase/Prog. Fail Reset" },
++ { CMD_4BYTE_ADDR_MODE, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Enter 4-byte Address Mode" },
++ { CMD_SET_BURST_LEN, SPI_CMD_WRITE, SPI_DATA_ENABLE, 0, 0, "Set Burst Length" },
++ { CMD_EVALUATE_ERASE_STATUS, SPI_CMD_OTHER, SPI_DATA_DISABLE, 3, 0, "Evaluate Erase Status" },
++ { CMD_ECC_READ, SPI_CMD_READ, SPI_DATA_ENABLE, 3, 8, "ECC Read (3- or 4-byte address)" },
++ { CMD_ECC_READ_ADDR4, SPI_CMD_READ, SPI_DATA_ENABLE, 4, 8, "ECC Read (4-byte address)" },
++ { CMD_DLPRD, SPI_CMD_READ, SPI_DATA_ENABLE, 0, 0, "Data Learning Pattern Read" },
++ { CMD_PNVDLR, SPI_CMD_WRITE, SPI_DATA_ENABLE, 0, 0, "Program NV Data Learning Register" },
++ { CMD_WVDLR, SPI_CMD_WRITE, SPI_DATA_ENABLE, 0, 0, "Write Volatile Data Learning Register" },
++ { CMD_READ_ARRAY_SLOW, SPI_CMD_READ, SPI_DATA_ENABLE, 3, 0, "Read (3- or 4-byte address)" },
++ { CMD_READ_ARRAY_SLOW_ADDR4, SPI_CMD_READ, SPI_DATA_ENABLE, 4, 0, "Read (4-byte address)" },
++ { CMD_READ_ARRAY_FAST, SPI_CMD_READ, SPI_DATA_ENABLE, 3, 8, "Fast Read (3- or 4-byte address)" },
++ { CMD_READ_ARRAY_FAST_ADDR4, SPI_CMD_READ, SPI_DATA_ENABLE, 4, 8, "Fast Read (4-byte address)" },
++ { CMD_READ_DUAL_IO_FAST, SPI_CMD_READ, SPI_DATA_ENABLE, 3, 8, "Dual I/O Read (3- or 4-byte address)" },
++ { CMD_READ_DUAL_IO_FAST_ADDR4, SPI_CMD_READ, SPI_DATA_ENABLE, 4, 8, "Dual I/O Read (4-byte address)" },
++ { CMD_READ_QUAD_IO_FAST, SPI_CMD_READ, SPI_DATA_ENABLE, 3, 8, "Quad I/O Read (3- or 4-byte address)" },
++ { CMD_READ_QUAD_IO_FAST_ADDR4, SPI_CMD_READ, SPI_DATA_ENABLE, 4, 8, "Quad I/O Read (4-byte address)" },
++ { CMD_READ_QUAD_IO_DDR, SPI_CMD_READ, SPI_DATA_ENABLE, 3, 8, "DDR Quad I/O Read (3- or 4-byte address)" },
++ { CMD_READ_QUAD_IO_DDR_ADDR4, SPI_CMD_READ, SPI_DATA_ENABLE, 4, 8, "DDR Quad I/O Read (4-byte address)" },
++ { CMD_PAGE_PROGRAM, SPI_CMD_WRITE, SPI_DATA_ENABLE, 3, 0, "Page Program (3- or 4-byte address)" },
++ { CMD_PAGE_PROGRAM_ADDR4, SPI_CMD_WRITE, SPI_DATA_ENABLE, 4, 0, "Page Program (4-byte address)" },
++ { CMD_ERASE_4K, SPI_CMD_ERASE, SPI_DATA_DISABLE, 3, 0, "Parameter 4 kB-sector Erase (3- or 4-byte address)" },
++ { CMD_ERASE_4K_ADDR4, SPI_CMD_ERASE, SPI_DATA_DISABLE, 4, 0, "Parameter 4 kB-sector Erase (4-byte address)" },
++ { CMD_ERASE_64K, SPI_CMD_ERASE, SPI_DATA_DISABLE, 3, 0, "Erase 256 kB (3- or 4-byte address)" },
++ { CMD_ERASE_256K_ADDR4, SPI_CMD_ERASE, SPI_DATA_DISABLE, 4, 0, "Erase 256 kB (4-byte address)" },
++ { CMD_BULK_ERASE, SPI_CMD_ERASE, SPI_DATA_DISABLE, 0, 0, "Bulk Erase" },
++ { CMD_BULK_ERASE_ALT, SPI_CMD_ERASE, SPI_DATA_DISABLE, 0, 0, "Bulk Erase (alternate command)" },
++ { CMD_EPS, SPI_CMD_ERASE, SPI_DATA_DISABLE, 0, 0, "Erase / Program Suspend" },
++ { CMD_EPS_ALT, SPI_CMD_ERASE, SPI_DATA_DISABLE, 0, 0, "Erase / Program Suspend" },
++ { CMD_EPS_ALT2, SPI_CMD_ERASE, SPI_DATA_DISABLE, 0, 0, "Erase / Program Suspend" },
++ { CMD_EPR, SPI_CMD_ERASE, SPI_DATA_DISABLE, 0, 0, "Erase / Program Resume" },
++ { CMD_EPR_ALT, SPI_CMD_ERASE, SPI_DATA_DISABLE, 0, 0, "Erase / Program Resume" },
++ { CMD_EPR_ALT2, SPI_CMD_ERASE, SPI_DATA_DISABLE, 0, 0, "Erase / Program Resume" },
++ { CMD_OTP_PROGRAM, SPI_CMD_WRITE, SPI_DATA_ENABLE, 3, 0, "OTP Program" },
++ { CMD_OTP_READ, SPI_CMD_WRITE, SPI_DATA_ENABLE, 3, 0, "OTP Read" },
++ { CMD_DYB_READ, SPI_CMD_READ, SPI_DATA_ENABLE, 3, 0, "DYB Read" },
++ { CMD_DYB_READ_ADDR4, SPI_CMD_READ, SPI_DATA_ENABLE, 4, 0, "DYB Read" },
++ { CMD_DYB_WRITE, SPI_CMD_WRITE, SPI_DATA_ENABLE, 3, 0, "DYB Write" },
++ { CMD_DYB_WRITE_ADDR4, SPI_CMD_WRITE, SPI_DATA_ENABLE, 4, 0, "DYB Write" },
++ { CMD_PPB_READ, SPI_CMD_READ, SPI_DATA_ENABLE, 3, 0, "PPB Read" },
++ { CMD_PPB_READ_ADDR4, SPI_CMD_READ, SPI_DATA_ENABLE, 3, 0, "PPB Read" },
++ { CMD_PPB_PROGRAM, SPI_CMD_WRITE, SPI_DATA_DISABLE, 3, 0, "PPB Program" },
++ { CMD_PPB_PROGRAM_ADDR4, SPI_CMD_WRITE, SPI_DATA_DISABLE, 3, 0, "PPB Program" },
++ { CMD_PPB_ERASE, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "PPB Erase" },
++ { CMD_ASP_READ, SPI_CMD_READ, SPI_DATA_ENABLE, 0, 0, "ASP Read" },
++ { CMD_ASP_PROGRAM, SPI_CMD_WRITE, SPI_DATA_ENABLE, 0, 0, "ASP Program" },
++ { CMD_PPB_LOCKBIT_READ, SPI_CMD_READ, SPI_DATA_ENABLE, 0, 0, "PPB Lock Bit Read" },
++ { CMD_PPB_LOCKBIT_WRITE, SPI_CMD_WRITE, SPI_DATA_DISABLE, 0, 0, "PPB Lock Bit Write" },
++ { CMD_PASSWD_READ, SPI_CMD_READ, SPI_DATA_ENABLE, 0, 0, "Password Read" },
++ { CMD_PASSWD_PROGRAM, SPI_CMD_WRITE, SPI_DATA_ENABLE, 0, 0, "Password Program" },
++ { CMD_PASSWD_UNLOCK, SPI_CMD_OTHER, SPI_DATA_ENABLE, 0, 0, "Password Unlock" },
++ { CMD_SOFT_RESET_ENABLE, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Software Reset Enable" },
++ { CMD_SOFT_RESET, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Software Reset" },
++ { CMD_LEGACY_SOFT_RESET, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Legacy Software Reset" },
++ { CMD_MODE_BIT_RESET, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Mode Bit Reset" },
++ { CMD_ENT_DEEP_POWER_DOWN, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Enter Deep Power-Down Mode" },
++ { CMD_REL_DEEP_POWER_DOWN, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Release from Deep Power-Down Mode" },
++ { SPI_COMMAND_LAST, SPI_CMD_OTHER, SPI_DATA_DISABLE, 0, 0, "Last Command" },
++};
++
++static inline struct sh_qspi_slave *to_sh_qspi(struct spi_slave *slave)
++{
++ return container_of(slave, struct sh_qspi_slave, slave);
++}
++
++void spi_set_addr(uint32_t addr)
++{
++ debug_print("Set Addr: %08X\n", addr);
++ out_le32(RPC_SMADR, addr);
++ return;
++}
++
++static void rcar_gen3_qspi_init(void)
++{
++ out_le32(RPC_PHYCNT, 0x80000260);
++ out_le32(RPC_CMNCR, 0x81FFF300);
++
++ return;
++}
++
++int spi_cs_is_valid(unsigned int bus, unsigned int cs)
++{
++ return 1;
++}
++
++void spi_cs_activate(struct spi_slave *slave)
++{
++ out_le32(RPC_PHYCNT, 0x80000260);
++
++ return;
++}
++
++void spi_cs_deactivate(struct spi_slave *slave)
++{
++ out_le32(RPC_SMCR, SPI_SMCR_SPIE);
++ WaitRpcTxEnd();
++ out_le32(RPC_PHYCNT, 0x00000274);
++ out_le32(RPC_DRCR, 0x01FF0301);
++
++ return;
++}
++
++void spi_init(void)
++{
++ /* nothing to do */
++}
++
++struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
++ unsigned int max_hz, unsigned int mode)
++{
++ struct sh_qspi_slave *ss;
++
++ if (!spi_cs_is_valid(bus, cs))
++ return NULL;
++
++ ss = spi_alloc_slave(struct sh_qspi_slave, bus, cs);
++ if (!ss) {
++ printf("SPI_error: Fail to allocate sh_qspi_slave\n");
++ return NULL;
++ }
++
++ ss->regs = (struct rcar_gen3_qspi_regs *)SH_QSPI_BASE;
++
++ /* Init R-Car-Gen3 QSPI */
++ rcar_gen3_qspi_init();
++
++ return &ss->slave;
++}
++
++void spi_free_slave(struct spi_slave *slave)
++{
++ struct sh_qspi_slave *spi = to_sh_qspi(slave);
++
++ free(spi);
++}
++
++int spi_claim_bus(struct spi_slave *slave)
++{
++ return 0;
++}
++
++void spi_release_bus(struct spi_slave *slave)
++{
++}
++
++#define BUFFER_SIZE (128)
++int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
++ void *din, unsigned long flags)
++{
++ unsigned long nbyte, rnbyte, wnbyte;
++ int i, ret = 0;
++ uint32_t *tdata_l = (uint32_t *)dout;
++ uint32_t *rdata_l = (uint32_t *)din;
++ uint8_t *ptr_b;
++ uint32_t readVal, writeVal;
++
++ if (dout == NULL && din == NULL) {
++ if (flags & SPI_XFER_END)
++ spi_cs_deactivate(slave);
++ return 0;
++ }
++
++ if (bitlen % 8) {
++ printf("%s: bitlen is not 8bit alined %d", __func__, bitlen);
++ return 1;
++ }
++
++ if (flags & SPI_XFER_BEGIN) {
++ spi_cs_activate(slave);
++ }
++
++ /* Set Data Enable 32bit */
++ readVal = in_le32(RPC_SMENR);
++ writeVal = (readVal & 0xffff0000);
++ writeVal |= SPI_SMENR_SPIDE_32BIT;
++ out_le32(RPC_SMENR, writeVal);
++
++ nbyte = bitlen / 8;
++ if (tdata_l != NULL)
++ wnbyte = nbyte;
++ else
++ wnbyte = 0;
++
++ if (rdata_l != NULL)
++ rnbyte = nbyte;
++ else
++ rnbyte = 0;
++
++ while (wnbyte > 0) {
++ if (wnbyte < BYTE_32BIT) {
++ out_8(RPC_SMWDR0, *(uint8_t*)tdata_l);
++ /* Set Data Enable 8bit */
++ readVal = in_le32(RPC_SMENR);
++ writeVal = (readVal & 0xffff0000);
++ writeVal |= SPI_SMENR_SPIDE_8BIT;
++ out_le32(RPC_SMENR, writeVal);
++ }else{
++ out_le32(RPC_SMWDR0, *tdata_l);
++ }
++
++ if (wnbyte >= BYTE_32BIT) {
++ tdata_l++;
++ wnbyte -= BYTE_32BIT;
++ }else{
++ ptr_b = (uint8_t*) tdata_l;
++ ptr_b++;
++ tdata_l = (uint32_t*) ptr_b;
++ wnbyte -= BYTE_8BIT;
++ }
++
++ if (wnbyte > 0) {
++ out_le32(RPC_SMCR, SPI_SMCR_SSLKP | SPI_SMCR_SPIWE | SPI_SMCR_SPIE);
++ }else{
++ out_le32(RPC_SMCR, SPI_SMCR_SPIWE | SPI_SMCR_SPIE);
++ }
++
++ WaitRpcTxEnd();
++
++ if (wnbyte == 0) {
++ WaitReadyDevice(slave);
++ }
++ }
++
++ while (rnbyte > 0) {
++ if (rnbyte < BYTE_32BIT) {
++ readVal = in_le32(RPC_SMRDR0);
++ ptr_b = (uint8_t*) rdata_l;
++ for(i=0; i<rnbyte; i++) {
++ *ptr_b = (readVal >> (8*i)) & 0x000000ff;
++ ptr_b++;
++ }
++ }else{
++ *rdata_l = in_le32(RPC_SMRDR0);
++ }
++
++ rdata_l++;
++
++ if(slave->spi_cmd->cmd_code == CMD_READ_ARRAY_FAST_ADDR4) {
++ readVal = in_le32(RPC_SMENR);
++ writeVal = readVal | 0x0000CF00;
++ out_le32(RPC_SMENR, writeVal);
++ readVal = in_le32(RPC_SMADR);
++ readVal += BYTE_32BIT;
++ spi_set_addr(readVal);
++ out_le32(RPC_SMCR, SPI_SMCR_SPIRE | SPI_SMCR_SPIE);
++ }else{
++ if (rnbyte > BYTE_32BIT) {
++ out_le32(RPC_SMCR, SPI_SMCR_SSLKP | SPI_SMCR_SPIRE | SPI_SMCR_SPIE);
++ }else{
++ out_le32(RPC_SMCR, SPI_SMCR_SPIRE | SPI_SMCR_SPIE);
++ }
++ }
++
++ WaitRpcTxEnd();
++
++ if (rnbyte >= BYTE_32BIT) {
++ rnbyte -= BYTE_32BIT;
++ }else{
++ rnbyte = 0;
++ }
++ }
++
++ if (flags & SPI_XFER_END){
++ spi_cs_deactivate(slave);
++ }
++
++ return ret;
++}
++
++int spi_xfer_cmd(struct spi_slave *slave, int cmd_no)
++{
++ uint32_t readVal, writeVal, dummy_cyc;
++ const SPI_COMMAND *cur_cmd_tbl;
++ cur_cmd_tbl = spi_cmd_tbl;
++
++ while(cur_cmd_tbl->cmd_code != SPI_COMMAND_LAST) {
++ if(cur_cmd_tbl->cmd_code != cmd_no) {
++ cur_cmd_tbl++;
++ continue;
++ }
++
++ slave->spi_cmd = cur_cmd_tbl;
++
++ spi_cs_activate(slave);
++ out_le32(RPC_SMCMR, cmd_no << SPI_SMCMR_CMD_BIT);
++ debug_print("SPI CODE:0x%02X [ %s ]\n", cur_cmd_tbl->cmd_code, cur_cmd_tbl->cmd_desc);
++
++ readVal = in_le32(RPC_SMENR);
++ writeVal = readVal & 0xFFFF0000;
++ writeVal |= SPI_SMENR_CDE;
++
++ /* Setting Address */
++ switch (cur_cmd_tbl->addr_len) {
++ case 3:
++ writeVal |= SPI_SMENR_ADE_3BYTE;
++ break;
++ case 4:
++ writeVal |= SPI_SMENR_ADE_4BYTE;
++ break;
++ default:
++ writeVal |= SPI_SMENR_ADE_DISABLE;
++ break;
++ }
++
++ /* Setting dummy cycle */
++ if (cur_cmd_tbl->dummy_len != 0) {
++ writeVal |= SPI_SMENR_DME;
++ dummy_cyc = cur_cmd_tbl->dummy_len - 1;
++ out_le32(RPC_SMDMCR, dummy_cyc);
++ }
++ out_le32(RPC_SMENR, writeVal);
++
++ switch(cur_cmd_tbl->rw_type) {
++ case SPI_CMD_READ:
++ readVal = in_le32(RPC_SMENR);
++ writeVal = readVal & 0xFFFFFFF0;
++ writeVal |= SPI_SMENR_SPIDE_32BIT;
++ out_le32(RPC_SMENR, writeVal);
++
++ if(cur_cmd_tbl->data_enable == SPI_DATA_ENABLE) {
++ if(cur_cmd_tbl->cmd_code == CMD_READ_ARRAY_FAST_ADDR4) {
++ out_le32(RPC_SMCR, SPI_SMCR_SPIRE | SPI_SMCR_SPIE);
++ }else{
++ out_le32(RPC_SMCR, SPI_SMCR_SSLKP | SPI_SMCR_SPIRE | SPI_SMCR_SPIE);
++ }
++ }else{
++ out_le32(RPC_SMCR, SPI_SMCR_SPIRE | SPI_SMCR_SPIE);
++ }
++ break;
++ case SPI_CMD_WRITE:
++ if(cur_cmd_tbl->data_enable == SPI_DATA_ENABLE) {
++ out_le32(RPC_SMCR, SPI_SMCR_SSLKP | SPI_SMCR_SPIWE | SPI_SMCR_SPIE);
++ }else{
++ out_le32(RPC_SMCR, SPI_SMCR_SPIWE | SPI_SMCR_SPIE);
++ }
++ break;
++ default:
++ if(cur_cmd_tbl->data_enable == SPI_DATA_ENABLE) {
++ out_le32(RPC_SMCR, SPI_SMCR_SSLKP | SPI_SMCR_SPIE);
++ }else{
++ out_le32(RPC_SMCR, SPI_SMCR_SPIE);
++ }
++ break;
++ }
++
++ WaitRpcTxEnd();
++
++ if (cur_cmd_tbl->data_enable != SPI_DATA_ENABLE) {
++ spi_cs_deactivate(slave);
++ }
++ break;
++ }
++
++ if(cur_cmd_tbl->cmd_code == SPI_COMMAND_LAST) {
++ printf("Unknown SPI Command : %02x\n", cmd_no);
++ return -1;
++ }
++ return 0;
++}
++
++void WaitRpcTxEnd(void)
++{
++ uint32_t dataL=0;
++
++ while(1) {
++ dataL = in_le32(RPC_CMNSR);
++ if(dataL & 0x00000001) {
++ break;
++ }
++ // Wait for TEND = 1
++ if(ctrlc()) {
++ puts("abort\n");
++ return;
++ }
++ udelay(1);
++ }
++ return;
++}
++
++void WaitReadyDevice(struct spi_slave *slave)
++{
++ int ret;
++ u8 status;
++ while(1) {
++ ret = spi_get_read_status(slave, &status);
++ if (ret < 0) {
++ printf("SF: fail to get read status\n");
++ return;
++ }
++ if ((status & SR1V_WIP) == 0) {
++ break;
++ }
++ udelay(1);
++ }
++ return;
++}
++
++int spi_get_read_status(struct spi_slave *slave, u8 *rs)
++{
++ int ret;
++ u8 cmd;
++
++ cmd = CMD_READ_STATUS;
++ ret = spi_flash_cmd_read(slave, &cmd, 1, rs, 1);
++ if (ret < 0) {
++ debug("SF: fail to get read status register\n");
++ return ret;
++ }
++
++ return 0;
++}
+diff --git a/drivers/spi/rcar_gen3_qspi.h b/drivers/spi/rcar_gen3_qspi.h
+new file mode 100644
+index 0000000..deb18d3
+--- /dev/null
++++ b/drivers/spi/rcar_gen3_qspi.h
+@@ -0,0 +1,301 @@
++/*
++ * Common R-Car-Gen3 QSPI Interface: Controller-specific definitions
++ *
++ */
++
++#ifndef _R_CAR_GEN3_QSPI_H_
++#define _R_CAR_GEN3_QSPI_H_
++
++/* SPI transfer flags */
++#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */
++#define SPI_XFER_END 0x02 /* Deassert CS after transfer */
++#define SPI_XFER_MMAP 0x08 /* Memory Mapped start */
++#define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */
++#define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END)
++#define SPI_XFER_U_PAGE (1 << 5)
++
++#define SPI_COMMAND_LAST 0xffffffff
++#define SPI_SMCMR_CMD_BIT 16
++
++#define SPI_CMD_OTHER 0
++#define SPI_CMD_READ 1
++#define SPI_CMD_WRITE 2
++#define SPI_CMD_ERASE 3
++
++#define SPI_DATA_DISABLE 0
++#define SPI_DATA_ENABLE 1
++
++#define SPI_SMCR_SPIE 0x00000001
++#define SPI_SMCR_SPIWE 0x00000002
++#define SPI_SMCR_SPIRE 0x00000004
++#define SPI_SMCR_SSLKP 0x00000100
++
++#define SPI_SMENR_DME (1 << 15)
++#define SPI_SMENR_CDE (1 << 14)
++#define SPI_SMENR_ADE_DISABLE (0x0 << 8)
++#define SPI_SMENR_ADE_3BYTE (0x7 << 8)
++#define SPI_SMENR_ADE_4BYTE (0xF << 8)
++#define SPI_SMENR_SPIDE_DISABLE (0x0)
++#define SPI_SMENR_SPIDE_8BIT (0x8)
++#define SPI_SMENR_SPIDE_16BIT (0xC)
++#define SPI_SMENR_SPIDE_32BIT (0xF)
++
++#define BYTE_32BIT (4)
++#define BYTE_8BIT (1)
++
++typedef struct {
++ uint32_t cmd_code;
++ uint8_t rw_type;
++ uint32_t data_enable;
++ uint32_t addr_len;
++ uint32_t dummy_len;
++ char* cmd_desc;
++} SPI_COMMAND;
++
++/**
++ * struct spi_slave - Representation of a SPI slave
++ *
++ * For driver model this is the per-child data used by the SPI bus. It can
++ * be accessed using dev_get_parentdata() on the slave device. The SPI uclass
++ * sets uip per_child_auto_alloc_size to sizeof(struct spi_slave), and the
++ * driver should not override it. Two platform data fields (max_hz and mode)
++ * are copied into this structure to provide an initial value. This allows
++ * them to be changed, since we should never change platform data in drivers.
++ *
++ * If not using driver model, drivers are expected to extend this with
++ * controller-specific data.
++ *
++ * @dev: SPI slave device
++ * @max_hz: Maximum speed for this slave
++ * @mode: SPI mode to use for this slave (see SPI mode flags)
++ * @bus: ID of the bus that the slave is attached to. For
++ * driver model this is the sequence number of the SPI
++ * bus (bus->seq) so does not need to be stored
++ * @cs: ID of the chip select connected to the slave.
++ * @op_mode_rx: SPI RX operation mode.
++ * @op_mode_tx: SPI TX operation mode.
++ * @wordlen: Size of SPI word in number of bits
++ * @max_write_size: If non-zero, the maximum number of bytes which can
++ * be written at once, excluding command bytes.
++ * @memory_map: Address of read-only SPI flash access.
++ * @option: Varies SPI bus options - separate, shared bus.
++ * @flags: Indication of SPI flags.
++ */
++struct spi_slave {
++#ifdef CONFIG_DM_SPI
++ struct udevice *dev; /* struct spi_slave is dev->parentdata */
++ uint max_hz;
++ uint mode;
++#else
++ unsigned int bus;
++ unsigned int cs;
++#endif
++ u8 op_mode_rx;
++ u8 op_mode_tx;
++ unsigned int wordlen;
++ unsigned int max_write_size;
++ void *memory_map;
++ u8 option;
++ u8 flags;
++ const SPI_COMMAND *spi_cmd;
++};
++
++/**
++ * Initialization, must be called once on start up.
++ *
++ * TODO: I don't think we really need this.
++ */
++void spi_init(void);
++
++/**
++ * spi_do_alloc_slave - Allocate a new SPI slave (internal)
++ *
++ * Allocate and zero all fields in the spi slave, and set the bus/chip
++ * select. Use the helper macro spi_alloc_slave() to call this.
++ *
++ * @offset: Offset of struct spi_slave within slave structure.
++ * @size: Size of slave structure.
++ * @bus: Bus ID of the slave chip.
++ * @cs: Chip select ID of the slave chip on the specified bus.
++ */
++void *spi_do_alloc_slave(int offset, int size, unsigned int bus,
++ unsigned int cs);
++
++/**
++ * spi_alloc_slave - Allocate a new SPI slave
++ *
++ * Allocate and zero all fields in the spi slave, and set the bus/chip
++ * select.
++ *
++ * @_struct: Name of structure to allocate (e.g. struct tegra_spi).
++ * This structure must contain a member 'struct spi_slave *slave'.
++ * @bus: Bus ID of the slave chip.
++ * @cs: Chip select ID of the slave chip on the specified bus.
++ */
++#define spi_alloc_slave(_struct, bus, cs) \
++ spi_do_alloc_slave(offsetof(_struct, slave), \
++ sizeof(_struct), bus, cs)
++
++/**
++ * spi_alloc_slave_base - Allocate a new SPI slave with no private data
++ *
++ * Allocate and zero all fields in the spi slave, and set the bus/chip
++ * select.
++ *
++ * @bus: Bus ID of the slave chip.
++ * @cs: Chip select ID of the slave chip on the specified bus.
++ */
++#define spi_alloc_slave_base(bus, cs) \
++ spi_do_alloc_slave(0, sizeof(struct spi_slave), bus, cs)
++
++/**
++ * Set up communications parameters for a SPI slave.
++ *
++ * This must be called once for each slave. Note that this function
++ * usually doesn't touch any actual hardware, it only initializes the
++ * contents of spi_slave so that the hardware can be easily
++ * initialized later.
++ *
++ * @bus: Bus ID of the slave chip.
++ * @cs: Chip select ID of the slave chip on the specified bus.
++ * @max_hz: Maximum SCK rate in Hz.
++ * @mode: Clock polarity, clock phase and other parameters.
++ *
++ * Returns: A spi_slave reference that can be used in subsequent SPI
++ * calls, or NULL if one or more of the parameters are not supported.
++ */
++struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
++ unsigned int max_hz, unsigned int mode);
++
++/**
++ * Free any memory associated with a SPI slave.
++ *
++ * @slave: The SPI slave
++ */
++void spi_free_slave(struct spi_slave *slave);
++
++/**
++ * Claim the bus and prepare it for communication with a given slave.
++ *
++ * This must be called before doing any transfers with a SPI slave. It
++ * will enable and initialize any SPI hardware as necessary, and make
++ * sure that the SCK line is in the correct idle state. It is not
++ * allowed to claim the same bus for several slaves without releasing
++ * the bus in between.
++ *
++ * @slave: The SPI slave
++ *
++ * Returns: 0 if the bus was claimed successfully, or a negative value
++ * if it wasn't.
++ */
++int spi_claim_bus(struct spi_slave *slave);
++
++/**
++ * Release the SPI bus
++ *
++ * This must be called once for every call to spi_claim_bus() after
++ * all transfers have finished. It may disable any SPI hardware as
++ * appropriate.
++ *
++ * @slave: The SPI slave
++ */
++void spi_release_bus(struct spi_slave *slave);
++
++/**
++ * Set the word length for SPI transactions
++ *
++ * Set the word length (number of bits per word) for SPI transactions.
++ *
++ * @slave: The SPI slave
++ * @wordlen: The number of bits in a word
++ *
++ * Returns: 0 on success, -1 on failure.
++ */
++int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen);
++
++/**
++ * SPI transfer
++ *
++ * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
++ * "bitlen" bits in the SPI MISO port. That's just the way SPI works.
++ *
++ * The source of the outgoing bits is the "dout" parameter and the
++ * destination of the input bits is the "din" parameter. Note that "dout"
++ * and "din" can point to the same memory location, in which case the
++ * input data overwrites the output data (since both are buffered by
++ * temporary variables, this is OK).
++ *
++ * spi_xfer() interface:
++ * @slave: The SPI slave which will be sending/receiving the data.
++ * @bitlen: How many bits to write and read.
++ * @dout: Pointer to a string of bits to send out. The bits are
++ * held in a byte array and are sent MSB first.
++ * @din: Pointer to a string of bits that will be filled in.
++ * @flags: A bitwise combination of SPI_XFER_* flags.
++ *
++ * Returns: 0 on success, not 0 on failure
++ */
++int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
++ void *din, unsigned long flags);
++
++/**
++ * Determine if a SPI chipselect is valid.
++ * This function is provided by the board if the low-level SPI driver
++ * needs it to determine if a given chipselect is actually valid.
++ *
++ * Returns: 1 if bus:cs identifies a valid chip on this board, 0
++ * otherwise.
++ */
++int spi_cs_is_valid(unsigned int bus, unsigned int cs);
++
++#ifndef CONFIG_DM_SPI
++/**
++ * Activate a SPI chipselect.
++ * This function is provided by the board code when using a driver
++ * that can't control its chipselects automatically (e.g.
++ * common/soft_spi.c). When called, it should activate the chip select
++ * to the device identified by "slave".
++ */
++void spi_cs_activate(struct spi_slave *slave);
++
++/**
++ * Deactivate a SPI chipselect.
++ * This function is provided by the board code when using a driver
++ * that can't control its chipselects automatically (e.g.
++ * common/soft_spi.c). When called, it should deactivate the chip
++ * select to the device identified by "slave".
++ */
++void spi_cs_deactivate(struct spi_slave *slave);
++
++/**
++ * Set transfer speed.
++ * This sets a new speed to be applied for next spi_xfer().
++ * @slave: The SPI slave
++ * @hz: The transfer speed
++ */
++void spi_set_speed(struct spi_slave *slave, uint hz);
++#endif
++
++
++/**
++ * Set up a SPI slave for a particular device tree node
++ *
++ * This calls spi_setup_slave() with the correct bus number. Call
++ * spi_free_slave() to free it later.
++ *
++ * @param blob: Device tree blob
++ * @param slave_node: Slave node to use
++ * @param spi_node: SPI peripheral node to use
++ * @return pointer to new spi_slave structure
++ */
++struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
++ int spi_node);
++
++/* QSPI Flash Read/Write function */
++void spi_set_addr(uint32_t addr);
++int spi_xfer_cmd(struct spi_slave *slave, int cmd_no);
++void WaitRpcTxEnd(void);
++void WaitReadyDevice(struct spi_slave *slave);
++int spi_get_read_status(struct spi_slave *slave, u8 *rs);
++
++#endif /* _R_CAR_GEN3_QSPI_H_ */
+diff --git a/include/linux/bitops.h b/include/linux/bitops.h
+index e724310..3bf04d2 100644
+--- a/include/linux/bitops.h
++++ b/include/linux/bitops.h
+@@ -104,6 +104,7 @@ static inline unsigned int generic_hweight8(unsigned int w)
+ return (res & 0x0F) + ((res >> 4) & 0x0F);
+ }
+
++#define BIT(nr) (1UL << (nr))
+ #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+ #define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+
+diff --git a/include/spi.h b/include/spi.h
+index c58e453..d6978c7 100644
+--- a/include/spi.h
++++ b/include/spi.h
+@@ -11,18 +11,24 @@
+ #define _SPI_H_
+
+ /* SPI mode flags */
+-#define SPI_CPHA 0x01 /* clock phase */
+-#define SPI_CPOL 0x02 /* clock polarity */
++#define SPI_CPHA BIT(0) /* clock phase */
++#define SPI_CPOL BIT(1) /* clock polarity */
+ #define SPI_MODE_0 (0|0) /* (original MicroWire) */
+ #define SPI_MODE_1 (0|SPI_CPHA)
+ #define SPI_MODE_2 (SPI_CPOL|0)
+ #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
+-#define SPI_CS_HIGH 0x04 /* CS active high */
+-#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
+-#define SPI_3WIRE 0x10 /* SI/SO signals shared */
+-#define SPI_LOOP 0x20 /* loopback mode */
+-#define SPI_SLAVE 0x40 /* slave mode */
+-#define SPI_PREAMBLE 0x80 /* Skip preamble bytes */
++#define SPI_CS_HIGH BIT(2) /* CS active high */
++#define SPI_LSB_FIRST BIT(3) /* per-word bits-on-wire */
++#define SPI_3WIRE BIT(4) /* SI/SO signals shared */
++#define SPI_LOOP BIT(5) /* loopback mode */
++#define SPI_SLAVE BIT(6) /* slave mode */
++#define SPI_PREAMBLE BIT(7) /* Skip preamble bytes */
++#define SPI_TX_BYTE BIT(8) /* transmit with 1 wire byte */
++#define SPI_TX_DUAL BIT(9) /* transmit with 2 wires */
++#define SPI_TX_QUAD BIT(10) /* transmit with 4 wires */
++#define SPI_RX_SLOW BIT(11) /* receive with 1 wire slow */
++#define SPI_RX_DUAL BIT(12) /* receive with 2 wires */
++#define SPI_RX_QUAD BIT(13) /* receive with 4 wires */
+
+ /* SPI transfer flags */
+ #define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */
+--
+1.9.1