From 034dd6241b55ab2256eecb845e941fa9b45da38e Mon Sep 17 00:00:00 2001 From: Yunhui Cui Date: Thu, 28 Apr 2016 17:03:57 +0800 Subject: [PATCH 110/113] mtd: spi-nor: fsl-quad: add flash S25FS extra support [context adjustment] not apply changes of arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts There are some boards have the same QSPI controller but have different vendor flash, So, the controller can use the same compatible and share the driver, just for a different flash to do the appropriate adaptation. Based on this, we need add the vendor field in spi-nor, Because we will use the field to distribute corresponding LUT for different flash operations. Signed-off-by: Yunhui Cui Signed-off-by: Pratiyush Mohan Srivastava Signed-off-by: Prabhakar Kushwaha Integrated-by: Jiang Yutang --- drivers/mtd/spi-nor/fsl-quadspi.c | 47 ++++++++++++++++++++++++++++++------- drivers/mtd/spi-nor/spi-nor.c | 5 ++-- include/linux/mtd/spi-nor.h | 1 + 3 files changed, 42 insertions(+), 11 deletions(-) --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -213,6 +213,9 @@ #define QUADSPI_MIN_IOMAP SZ_4M +#define FLASH_VENDOR_SPANSION_FS "s25fs" +#define SPANSION_S25FS_FAMILY (1 << 1) + enum fsl_qspi_devtype { FSL_QUADSPI_VYBRID, FSL_QUADSPI_IMX6SX, @@ -329,6 +332,18 @@ static inline int has_added_amba_base_in return q->devtype_data->driver_data & QUADSPI_AMBA_BASE_INTERNAL; } +static u32 fsl_get_nor_vendor(struct spi_nor *nor) +{ + u32 vendor_id; + + if (nor->vendor) { + if (memcmp(nor->vendor, FLASH_VENDOR_SPANSION_FS, + sizeof(FLASH_VENDOR_SPANSION_FS) - 1)) + vendor_id = SPANSION_S25FS_FAMILY; + } + return vendor_id; +} + /* * R/W functions for big- or little-endian registers: * The qSPI controller's endian is independent of the CPU core's endian. @@ -394,13 +409,15 @@ static void fsl_qspi_init_lut(struct fsl int rxfifo = q->devtype_data->rxfifo; u32 lut_base; int i; - const struct fsl_qspi_devtype_data *devtype_data = q->devtype_data; + u32 vendor; struct spi_nor *nor = &q->nor[0]; u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT; u8 read_op = nor->read_opcode; u8 read_dm = nor->read_dummy; + vendor = fsl_get_nor_vendor(nor); + fsl_qspi_unlock_lut(q); /* Clear all the LUT table */ @@ -418,12 +435,25 @@ static void fsl_qspi_init_lut(struct fsl LUT1(FSL_READ, PAD1, rxfifo), base + QUADSPI_LUT(lut_base + 1)); } else if (nor->flash_read == SPI_NOR_QUAD) { - qspi_writel(q, LUT0(CMD, PAD1, read_op) | - LUT1(ADDR, PAD1, addrlen), - base + QUADSPI_LUT(lut_base)); - qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) | - LUT1(FSL_READ, PAD4, rxfifo), - base + QUADSPI_LUT(lut_base + 1)); + if (q->nor_size == 0x4000000) { + read_op = 0xEC; + qspi_writel(q, + LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD4, addrlen), + base + QUADSPI_LUT(lut_base)); + qspi_writel(q, + LUT0(MODE, PAD4, 0xff) | LUT1(DUMMY, PAD4, read_dm), + base + QUADSPI_LUT(lut_base + 1)); + qspi_writel(q, + LUT0(FSL_READ, PAD4, rxfifo), + base + QUADSPI_LUT(lut_base + 2)); + } else { + qspi_writel(q, LUT0(CMD, PAD1, read_op) | + LUT1(ADDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); + qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) | + LUT1(FSL_READ, PAD4, rxfifo), + base + QUADSPI_LUT(lut_base + 1)); + } } else if (nor->flash_read == SPI_NOR_DDR_QUAD) { /* read mode : 1-4-4, such as Spansion s25fl128s. */ qspi_writel(q, LUT0(CMD, PAD1, read_op) @@ -510,7 +540,8 @@ static void fsl_qspi_init_lut(struct fsl * use the same value 0x65. But it indicates different meaning. */ lut_base = SEQID_RDAR_OR_RD_EVCR * 4; - if (devtype_data->devtype == FSL_QUADSPI_LS2080A) { + + if (vendor == SPANSION_S25FS_FAMILY) { /* * Read any device register. * Used for Spansion S25FS-S family flash only. --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -798,7 +798,6 @@ static const struct flash_info spi_nor_i { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fs256s1", INFO6(0x010219, 0x4d0181, 64 * 1024, 512, 0)}, - { "s25fs512s", INFO6(0x010220, 0x4d0081, 128 * 1024, 512, 0)}, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, @@ -965,11 +964,9 @@ static int spansion_s25fs_disable_4kb_er ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1); if (ret) return ret; -/* if (!(cr3v & CR3V_4KB_ERASE_UNABLE)) return -EPERM; -*/ return 0; } @@ -1343,6 +1340,8 @@ int spi_nor_scan(struct spi_nor *nor, co if (!mtd->name) mtd->name = dev_name(dev); + if (info->name) + nor->vendor = info->name; mtd->priv = nor; mtd->type = MTD_NORFLASH; mtd->writesize = 1; --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -172,6 +172,7 @@ struct spi_nor { bool sst_write_second; u32 flags; u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE]; + char *vendor; int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops); void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);