On 19. 11. 19 15:20, Ashok Reddy Soma wrote:
> Add dual parallel and dual stacked support in spi-nor framework.
> Add dual flash support for nor-scan, read and write.
> 
> Signed-off-by: Ashok Reddy Soma <ashok.reddy.s...@xilinx.com>
> ---
> Hi,
> 
> I have added dual parallel and dual stacked related changes to the
> spi-nor framework. I have tested this for dual parallel configuration
> on zynqmp platform. I am in process of testing dual stacked
> configuration.
> 
> Please let me know if my approach is correct. If it is okay, i will
> split this in to meaningful patches and send.
> 
> Thanks in advance,
> Ashok Reddy Soma
> ---
>  drivers/mtd/spi/sf_internal.h  |   9 +
>  drivers/mtd/spi/spi-nor-core.c | 363 ++++++++++++++++++++++++++++-----
>  drivers/spi/spi-mem.c          |  19 +-
>  include/linux/mtd/spi-nor.h    |   4 +
>  include/spi.h                  |   9 +
>  5 files changed, 351 insertions(+), 53 deletions(-)
> 
> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> index 5c643034c6..d836261f01 100644
> --- a/drivers/mtd/spi/sf_internal.h
> +++ b/drivers/mtd/spi/sf_internal.h
> @@ -15,6 +15,15 @@
>  #define SPI_NOR_MAX_ID_LEN   6
>  #define SPI_NOR_MAX_ADDR_WIDTH       4
>  
> +/* Dual SPI flash memories - see SPI_COMM_DUAL_... */
> +enum spi_dual_flash {
> +     SF_SINGLE_FLASH = 0,
> +     SF_DUAL_STACKED_FLASH   = BIT(0),
> +     SF_DUAL_PARALLEL_FLASH  = BIT(1),
> +};
> +
> +#define SPI_FLASH_16MB_BOUN             0x1000000
> +
>  struct flash_info {
>  #if !CONFIG_IS_ENABLED(SPI_FLASH_TINY)
>       char            *name;
> diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> index 5a8c084255..a53c78ff22 100644
> --- a/drivers/mtd/spi/spi-nor-core.c
> +++ b/drivers/mtd/spi/spi-nor-core.c
> @@ -21,6 +21,7 @@
>  #include <spi-mem.h>
>  #include <spi.h>
>  
> +#include <linux/mtd/spi-nor.h>
>  #include "sf_internal.h"
>  
>  /* Define max times to check status register before we give up. */
> @@ -34,6 +35,11 @@
>  
>  #define DEFAULT_READY_WAIT_JIFFIES           (40UL * HZ)
>  
> +#define SPI_MASTER_QUAD_MODE    BIT(6)       /* support quad mode */
> +#define SPI_MASTER_DATA_STRIPE  BIT(7)       /* support data stripe */
> +#define SPI_MASTER_BOTH_CS      BIT(8)          /* assert both chip selects 
> */
> +#define SPI_MASTER_U_PAGE       BIT(9)       /* select upper flash */
> +
>  static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
>               *op, void *buf)
>  {
> @@ -146,15 +152,24 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, 
> loff_t to, size_t len,
>  static int read_sr(struct spi_nor *nor)
>  {
>       int ret;
> -     u8 val;
> +     u8 val[2];
>  
> -     ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
> -     if (ret < 0) {
> +     if (nor->isparallel) {
> +         ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 2);
> +         if (ret < 0) {
> +             pr_debug("error %d reading SR\n", (int)ret);
> +             return ret;
> +         }
> +         val[0] |= val[1];
> +     } else {
> +         ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 1);
> +         if (ret < 0) {
>               pr_debug("error %d reading SR\n", (int)ret);
>               return ret;
> +         }
>       }
>  
> -     return val;
> +     return val[0];
>  }
>  
>  /*
> @@ -165,15 +180,24 @@ static int read_sr(struct spi_nor *nor)
>  static int read_fsr(struct spi_nor *nor)
>  {
>       int ret;
> -     u8 val;
> +     u8 val[2];
>  
> -     ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1);
> -     if (ret < 0) {
> +     if (nor->isparallel) {
> +         ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 2);
> +         if (ret < 0) {
> +             pr_debug("error %d reading SR\n", (int)ret);
> +             return ret;
> +         }
> +         val[0] &= val[1];
> +     } else {
> +         ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 1);
> +         if (ret < 0) {
>               pr_debug("error %d reading FSR\n", ret);
>               return ret;
> +         }
>       }
>  
> -     return val;
> +     return val[0];
>  }
>  
>  /*
> @@ -288,12 +312,17 @@ static u8 spi_nor_convert_3to4_erase(u8 opcode)
>  static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
>                                     const struct flash_info *info)
>  {
> +     bool shift = 0;
> +
> +     if (nor->isparallel)
> +         shift = 1;
> +
>       /* Do some manufacturer fixups first */
>       switch (JEDEC_MFR(info)) {
>       case SNOR_MFR_SPANSION:
>               /* No small sector erase for 4-byte command set */
>               nor->erase_opcode = SPINOR_OP_SE;
> -             nor->mtd.erasesize = info->sector_size;
> +             nor->mtd.erasesize = info->sector_size << shift;
>               break;
>  
>       default:
> @@ -465,12 +494,19 @@ static int clean_bar(struct spi_nor *nor)
>  
>  static int write_bar(struct spi_nor *nor, u32 offset)
>  {
> -     u8 cmd, bank_sel;
> +     u8 cmd, bank_sel, upage_curr;
>       int ret;
>  
> -     bank_sel = offset / SZ_16M;
> -     if (bank_sel == nor->bank_curr)
> -             goto bar_end;
> +     bank_sel = offset / (SZ_16M << nor->shift);
> +
> +     upage_curr = nor->spi->flags & SPI_XFER_U_PAGE;
> +
> +     if ((!nor->isstacked) || (nor->upage_prev == upage_curr)) {
> +             if (bank_sel == nor->bank_curr)
> +                     goto bar_end;
> +     } else {
> +             nor->upage_prev = upage_curr;
> +     }
>  
>       cmd = nor->bank_write_cmd;
>       write_enable(nor);
> @@ -488,8 +524,12 @@ bar_end:
>  static int read_bar(struct spi_nor *nor, const struct flash_info *info)
>  {
>       u8 curr_bank = 0;
> +     u8 curr_bank_up = 0;
>       int ret;
>  
> +     if (nor->size <= SPI_FLASH_16MB_BOUN)
> +         goto bar_end;
> +
>       switch (JEDEC_MFR(info)) {
>       case SNOR_MFR_SPANSION:
>               nor->bank_read_cmd = SPINOR_OP_BRRD;
> @@ -500,12 +540,31 @@ static int read_bar(struct spi_nor *nor, const struct 
> flash_info *info)
>               nor->bank_write_cmd = SPINOR_OP_WREAR;
>       }
>  
> -     ret = nor->read_reg(nor, nor->bank_read_cmd,
> +     if (nor->isparallel) {
> +             nor->spi->flags |= SPI_XFER_LOWER;
> +             ret = nor->read_reg(nor, nor->bank_read_cmd,
>                                   &curr_bank, 1);
> -     if (ret) {
> -             debug("SF: fail to read bank addr register\n");
> -             return ret;
> +             if (ret)
> +                     return ret;
> +
> +             nor->spi->flags |= SPI_XFER_UPPER;
> +             ret = nor->read_reg(nor, nor->bank_read_cmd,
> +                                 &curr_bank_up, 1);
> +             if (ret)
> +                     return ret;
> +             if (curr_bank != curr_bank_up) {
> +                     printf("Incorrect Bank selections Dual parallel\n");
> +                     return -EINVAL;
> +             }
> +     } else {
> +             ret = nor->read_reg(nor, nor->bank_read_cmd,
> +                                 &curr_bank, 1);
> +             if (ret) {
> +                 debug("SF: fail to read bank addr register\n");
> +                 return ret;
> +             }
>       }
> +bar_end:
>       nor->bank_curr = curr_bank;
>  
>       return 0;
> @@ -540,7 +599,7 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 
> addr)
>  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, rem;
> +     u32 addr, len, rem, offset;
>       int ret;
>  
>       dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
> @@ -554,14 +613,37 @@ static int spi_nor_erase(struct mtd_info *mtd, struct 
> erase_info *instr)
>       len = instr->len;
>  
>       while (len) {
> +             write_enable(nor);
> +             offset = addr;
> +             if (nor->isparallel) {
> +                     offset /= 2;
> +                     nor->spi->flags |= SPI_XFER_STRIPE;
> +             }
> +
> +             if (nor->isstacked) {
> +                     if (offset >= (mtd->size / 2)) {
> +                             offset = offset - (mtd->size / 2);
> +                             nor->spi->flags |= SPI_MASTER_U_PAGE;
> +                     } else {
> +                             nor->spi->flags &= ~SPI_MASTER_U_PAGE;
> +                     }
> +             }
> +             if (nor->addr_width == 3) {
>  #ifdef CONFIG_SPI_FLASH_BAR
> -             ret = write_bar(nor, addr);
> -             if (ret < 0)
> -                     return ret;
> +                     /* Update Extended Address Register */
> +                     ret = write_bar(nor, offset);
> +                     if (ret)
> +                             goto erase_err;
>  #endif
> +             }
> +
> +             ret = spi_nor_wait_till_ready(nor);
> +             if (ret)
> +                     goto erase_err;
> +
>               write_enable(nor);
>  
> -             ret = spi_nor_erase_sector(nor, addr);
> +             ret = spi_nor_erase_sector(nor, offset);
>               if (ret)
>                       goto erase_err;
>  
> @@ -861,12 +943,33 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, 
> uint64_t len)
>  static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
>  {
>       int status;
> +     u8 sr;
> +     int status_up;
> +     u8 sr_up;
> +
> +     if (nor->isparallel) {
> +         nor->spi->flags |= SPI_XFER_LOWER;
> +         sr = read_sr(nor);
> +         if (sr < 0)
> +             return 0;
> +         status = stm_is_locked_sr(nor, ofs, len, sr);
> +
> +         nor->spi->flags |= SPI_XFER_UPPER;
> +         sr_up = read_sr(nor);
> +         if (sr_up < 0)
> +             return sr_up;
> +         status_up = stm_is_locked_sr(nor, ofs, len, sr_up);
> +         status = status && status_up;
> +
> +         return status;
> +     } else {
>  
>       status = read_sr(nor);
>       if (status < 0)
>               return status;
>  
>       return stm_is_locked_sr(nor, ofs, len, status);
> +     }
>  }
>  #endif /* CONFIG_SPI_FLASH_STMICRO */
>  
> @@ -876,6 +979,9 @@ static const struct flash_info *spi_nor_read_id(struct 
> spi_nor *nor)
>       u8                      id[SPI_NOR_MAX_ID_LEN];
>       const struct flash_info *info;
>  
> +     if (nor->isparallel)
> +         nor->spi->flags |= SPI_XFER_LOWER;
> +
>       tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
>       if (tmp < 0) {
>               dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
> @@ -900,28 +1006,98 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t 
> from, size_t len,
>  {
>       struct spi_nor *nor = mtd_to_spi_nor(mtd);
>       int ret;
> +     u32 offset = from;
> +     u32 stack_shift = 0;
> +     u32 read_len = 0;
> +     u32 rem_bank_len = 0;
> +     u8 bank;
> +     u8 is_ofst_odd = 0;
> +     u8 cur_bank;
> +     u8 nxt_bank;
> +     u32 bank_size;
> +
> +#define OFFSET_16_MB 0x1000000
>  
>       dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
>  
> +     if ((nor->isparallel) && (offset & 1)) {
> +         /* We can hit this case when we use file system like ubifs */
> +         from = (loff_t)(from - 1);
> +         len = (size_t)(len + 1);
> +         is_ofst_odd = 1;
> +     }
> +
>       while (len) {
> -             loff_t addr = from;
> -             size_t read_len = len;
> +             if (nor->addr_width == 3) {
> +                     bank = (u32)from / (OFFSET_16_MB << nor->shift);
> +                     rem_bank_len = ((OFFSET_16_MB << nor->shift) *
> +                                     (bank + 1)) - from;
> +             }
> +             offset = from;
>  
> -#ifdef CONFIG_SPI_FLASH_BAR
> -             u32 remain_len;
> +             if (nor->isparallel) {
> +                     offset /= 2;
> +                     nor->spi->flags = SPI_XFER_STRIPE;
> +             }
>  
> -             ret = write_bar(nor, addr);
> -             if (ret < 0)
> -                     return log_ret(ret);
> -             remain_len = (SZ_16M * (nor->bank_curr + 1)) - addr;
> +             if (nor->isstacked) {
> +                     stack_shift = 1;
> +                     if (offset >= (mtd->size / 2)) {
> +                             offset = offset - (mtd->size / 2);
> +                             nor->spi->flags |= SPI_MASTER_U_PAGE;
> +                     } else {
> +                             nor->spi->flags &= ~SPI_MASTER_U_PAGE;
> +                     }
> +             }
>  
> -             if (len < remain_len)
> -                     read_len = len;
> -             else
> -                     read_len = remain_len;
> +             if (nor->addr_width == 4) {
> +                     /*
> +                      * Some flash devices like N25Q512 have multiple dies
> +                      * in it. Read operation in these devices is bounded
> +                      * by its die segment. In a continuous read, across
> +                      * multiple dies, when the last byte of the selected
> +                      * die segment is read, the next byte read is the
> +                      * first byte of the same die segment. This is Die
> +                      * cross over issue. So to handle this issue, split
> +                      * a read transaction, that spans across multiple
> +                      * banks, into one read per bank. Bank size is 16MB
> +                      * for single and dual stacked mode and 32MB for dual
> +                      * parallel mode.
> +                      */
> +                     if (nor->spi && nor->spi->multi_die) {
> +                             bank_size = (OFFSET_16_MB << nor->shift);
> +                             cur_bank = offset / bank_size;
> +                             nxt_bank = (offset + len) / bank_size;
> +                             if (cur_bank != nxt_bank)
> +                                     rem_bank_len = (bank_size *
> +                                                     (cur_bank + 1)) -
> +                                                     offset;
> +                             else
> +                                     rem_bank_len = (mtd->size >>
> +                                                     stack_shift) -
> +                                                     (offset << nor->shift);
> +                     } else {
> +                             rem_bank_len = (mtd->size >> stack_shift) -
> +                                             (offset << nor->shift);
> +                     }
> +             }
> +
> +             if (nor->addr_width == 3) {
> +#ifdef CONFIG_SPI_FLASH_BAR
> +                 write_bar(nor, offset);
>  #endif
> +             }
> +
> +             if (len < rem_bank_len)
> +                 read_len = len;
> +             else
> +                 read_len = rem_bank_len;
>  
> -             ret = nor->read(nor, addr, read_len, buf);
> +             ret = spi_nor_wait_till_ready(nor);
> +             if (ret)
> +                     goto read_err;
> +
> +             ret = nor->read(nor, offset, read_len, buf);
>               if (ret == 0) {
>                       /* We shouldn't see 0-length reads */
>                       ret = -EIO;
> @@ -930,7 +1106,12 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t 
> from, size_t len,
>               if (ret < 0)
>                       goto read_err;
>  
> -             *retlen += ret;
> +             if (is_ofst_odd == 1) {
> +                     memcpy(buf, (buf + 1), (len - 1));
> +                     *retlen += (ret - 1);
> +             } else {
> +                     *retlen += ret;
> +             }
>               buf += ret;
>               from += ret;
>               len -= ret;
> @@ -1223,12 +1404,41 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t 
> to, size_t len,
>       struct spi_nor *nor = mtd_to_spi_nor(mtd);
>       size_t page_offset, page_remain, i;
>       ssize_t ret;
> +     ssize_t written;
> +     loff_t addr;
> +     u8 bank = 0;
> +     u32 offset, stack_shift = 0;
> +     u32 rem_bank_len = 0;
>  
>       dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
>  
> +     /*
> +      * Cannot write to odd offset in parallel mode,
> +      * so write 2 bytes first
> +      */
> +     if ((nor->isparallel) && (to & 1)) {
> +
> +             u8 two[2] = {0xff, buf[0]};
> +             size_t local_retlen;
> +
> +             ret = spi_nor_write(mtd, to & ~1, 2, &local_retlen, two);
> +             if (ret < 0)
> +                     return ret;
> +
> +             *retlen += 1; /* We've written only one actual byte */
> +             ++buf;
> +             --len;
> +             ++to;
> +     }
> +
>       for (i = 0; i < len; ) {
> -             ssize_t written;
> -             loff_t addr = to + i;
> +             addr = to + i;
> +
> +             if (nor->addr_width == 3) {
> +                     bank = (u32)to / (OFFSET_16_MB << nor->shift);
> +                     rem_bank_len = ((OFFSET_16_MB << nor->shift) *
> +                                     (bank + 1)) - to;
> +             }
>  
>               /*
>                * If page_size is a power of two, the offset can be quickly
> @@ -1245,17 +1455,51 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t 
> to, size_t len,
>  
>                       page_offset = do_div(aux, nor->page_size);
>               }
> -             /* the size of data remaining on the first page */
> -             page_remain = min_t(size_t,
> -                                 nor->page_size - page_offset, len - i);
>  
> +             offset = (to + i);
> +             if (nor->isparallel) {
> +                     offset /= 2;
> +                     nor->spi->flags |= SPI_XFER_STRIPE;
> +             }
> +
> +             if (nor->isstacked) {
> +                     stack_shift = 1;
> +                     if (offset >= (mtd->size / 2)) {
> +                             offset = offset - (mtd->size / 2);
> +                             nor->spi->flags |= SPI_MASTER_U_PAGE;
> +                     } else {
> +                             nor->spi->flags &= ~SPI_MASTER_U_PAGE;
> +                     }
> +             }
> +
> +             /* Die cross over issue is not handled */
> +             if (nor->addr_width == 4)
> +                     rem_bank_len = (mtd->size >> stack_shift) - offset;
> +             if (nor->addr_width == 3) {
>  #ifdef CONFIG_SPI_FLASH_BAR
> -             ret = write_bar(nor, addr);
> -             if (ret < 0)
> -                     return ret;
> +                     write_bar(nor, offset);
>  #endif
> +             }
> +             if (nor->isstacked) {
> +                     if (len <= rem_bank_len) {
> +                             page_remain = min_t(size_t, nor->page_size -
> +                                                 page_offset, len - i);
> +                     } else {
> +                             /* size of data remaining on the first page */
> +                             page_remain = rem_bank_len;
> +                     }
> +             } else {
> +                     page_remain = min_t(size_t, nor->page_size -
> +                                         page_offset, len - i);
> +             }
> +
> +             ret = spi_nor_wait_till_ready(nor);
> +             if (ret)
> +                     goto write_err;
> +
> +
>               write_enable(nor);
> -             ret = nor->write(nor, addr, page_remain, buf + i);
> +             ret = nor->write(nor, offset, page_remain, buf + i);
>               if (ret < 0)
>                       goto write_err;
>               written = ret;
> @@ -1265,6 +1509,13 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t 
> to, size_t len,
>                       goto write_err;
>               *retlen += written;
>               i += written;
> +             if (written != page_remain) {
> +                     dev_err(nor->dev,
> +                             "While writing %zu bytes written %zd bytes\n",
> +                             page_remain, written);
> +                     ret = -EIO;
> +                     goto write_err;
> +             }
>       }
>  
>  write_err:
> @@ -2094,6 +2345,12 @@ static int spi_nor_init_params(struct spi_nor *nor,
>       params->size = info->sector_size * info->n_sectors;
>       params->page_size = info->page_size;
>  
> +     if (nor->isparallel)
> +             params->page_size <<= nor->shift;
> +
> +     if (nor->isparallel || nor->isstacked)
> +             params->size <<= nor->shift;
> +
>       /* (Fast) Read settings. */
>       params->hwcaps.mask |= SNOR_HWCAPS_READ;
>       spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ],
> @@ -2280,24 +2537,27 @@ static int spi_nor_select_erase(struct spi_nor *nor,
>                               const struct flash_info *info)
>  {
>       struct mtd_info *mtd = &nor->mtd;
> +     bool shift = 0;
>  
>       /* Do nothing if already configured from SFDP. */
>       if (mtd->erasesize)
>               return 0;
>  
> +     if (nor->isparallel)
> +         shift = 1;
>  #ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS
>       /* prefer "small sector" erase if possible */
>       if (info->flags & SECT_4K) {
>               nor->erase_opcode = SPINOR_OP_BE_4K;
> -             mtd->erasesize = 4096;
> +             mtd->erasesize = 4096 << shift;
>       } else if (info->flags & SECT_4K_PMC) {
>               nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
> -             mtd->erasesize = 4096;
> +             mtd->erasesize = 4096 << shift;
>       } else
>  #endif
>       {
>               nor->erase_opcode = SPINOR_OP_SE;
> -             mtd->erasesize = info->sector_size;
> +             mtd->erasesize = info->sector_size << shift;
>       }
>       return 0;
>  }
> @@ -2442,9 +2702,14 @@ int spi_nor_scan(struct spi_nor *nor)
>                       hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;
>       }
>  
> -     info = spi_nor_read_id(nor);
> +     nor->isparallel = (spi->option == SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
> +     nor->isstacked = (spi->option == SF_DUAL_STACKED_FLASH) ? 1 : 0;
> +     nor->shift = (nor->isparallel || nor->isstacked) ? 1 : 0;
> +
> +     info = (struct flash_info *)spi_nor_read_id(nor);
>       if (IS_ERR_OR_NULL(info))
>               return -ENOENT;
> +
>       /* Parse the Serial Flash Discoverable Parameters table. */
>       ret = spi_nor_init_params(nor, info, &params);
>       if (ret)
> diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
> index 7788ab9953..2471132f41 100644
> --- a/drivers/spi/spi-mem.c
> +++ b/drivers/spi/spi-mem.c
> @@ -202,7 +202,7 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct 
> spi_mem_op *op)
>       const u8 *tx_buf = NULL;
>       u8 *rx_buf = NULL;
>       int op_len;
> -     u32 flag;
> +     u32 flag = 0;
>       int ret;
>       int i;
>  
> @@ -362,24 +362,35 @@ int spi_mem_exec_op(struct spi_slave *slave, const 
> struct spi_mem_op *op)
>       if (op->dummy.nbytes)
>               memset(op_buf + pos, 0xff, op->dummy.nbytes);
>  
> +     if (slave->flags & SPI_XFER_U_PAGE)
> +             flag |= SPI_XFER_U_PAGE;
> +
> +     if (slave->flags & SPI_XFER_LOWER)
> +             flag |= SPI_XFER_LOWER;
> +     if (slave->flags & SPI_XFER_UPPER)
> +             flag |= SPI_XFER_UPPER;
> +     if (slave->flags & SPI_XFER_STRIPE)
> +             flag |= SPI_XFER_STRIPE;
> +
>       /* 1st transfer: opcode + address + dummy cycles */
> -     flag = SPI_XFER_BEGIN;
>       /* Make sure to set END bit if no tx or rx data messages follow */
>       if (!tx_buf && !rx_buf)
>               flag |= SPI_XFER_END;
>  
> -     ret = spi_xfer(slave, op_len * 8, op_buf, NULL, flag);
> +     ret = spi_xfer(slave, op_len * 8, op_buf, NULL, flag | SPI_XFER_BEGIN);
>       if (ret)
>               return ret;
>  
>       /* 2nd transfer: rx or tx data path */
>       if (tx_buf || rx_buf) {
>               ret = spi_xfer(slave, op->data.nbytes * 8, tx_buf,
> -                            rx_buf, SPI_XFER_END);
> +                            rx_buf, flag | SPI_XFER_END);
>               if (ret)
>                       return ret;
>       }
>  
> +     slave->flags &= ~SPI_XFER_MASK;
> +
>       spi_release_bus(slave);
>  
>       for (i = 0; i < pos; i++)
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> index f9964a7664..c7475e7a12 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -309,11 +309,15 @@ struct spi_nor {
>       u8                      bank_read_cmd;
>       u8                      bank_write_cmd;
>       u8                      bank_curr;
> +     u8                      upage_prev;
>  #endif
>       enum spi_nor_protocol   read_proto;
>       enum spi_nor_protocol   write_proto;
>       enum spi_nor_protocol   reg_proto;
>       bool                    sst_write_second;
> +     bool                    shift;
> +     bool                    isparallel;
> +     bool                    isstacked;
>       u32                     flags;
>       u8                      cmd_buf[SPI_NOR_MAX_CMD_SIZE];
>  
> diff --git a/include/spi.h b/include/spi.h
> index 6fbb4336ce..69f69e590c 100644
> --- a/include/spi.h
> +++ b/include/spi.h
> @@ -31,6 +31,12 @@
>  #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_STRIPE (1 << 6)
> +#define SPI_XFER_MASK   (3 << 8)
> +#define SPI_XFER_LOWER  (1 << 8)
> +#define SPI_XFER_UPPER  (2 << 8)
> +
>  /* Header byte that marks the start of the message */
>  #define SPI_PREAMBLE_END_BYTE        0xec
>  
> @@ -108,13 +114,16 @@ struct spi_slave {
>       unsigned int max_read_size;
>       unsigned int max_write_size;
>       void *memory_map;
> +     u8 option;
>  
>       u8 flags;
> +     bool multi_die;                 /* flash with multiple dies*/
>  #define SPI_XFER_BEGIN               BIT(0)  /* Assert CS before transfer */
>  #define SPI_XFER_END         BIT(1)  /* Deassert CS after transfer */
>  #define SPI_XFER_ONCE                (SPI_XFER_BEGIN | SPI_XFER_END)
>  #define SPI_XFER_MMAP                BIT(2)  /* Memory Mapped start */
>  #define SPI_XFER_MMAP_END    BIT(3)  /* Memory Mapped End */
> +#define SPI_XFER_U_PAGE         BIT(4)
>  };
>  
>  /**
> 

Jagan: any comment?

M
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to