Hi Vignesh, Jagan,

Thanks for the review comments. 

I will split in to patches and revert.

Vignesh, 
I will do some cleanup and try to address your comments wherever applicable in 
the next drop. 

Thanks,
Ashok

> -----Original Message-----
> From: Vignesh Raghavendra <vigne...@ti.com>
> Sent: Wednesday, December 4, 2019 3:36 PM
> To: Ashok Reddy Soma <ashok...@xilinx.com>; u-boot@lists.denx.de;
> ja...@amarulasolutions.com
> Cc: Michal Simek <mich...@xilinx.com>
> Subject: Re: [RFC PATCH] spi: spi-nor: Add dual flash support in spi-nor
> framework
> 
> Hi,
> 
> On 26/11/19 12:39 pm, Michal Simek wrote:
> > 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.
> >>
> 
> How does the DT representation of these flashes look like?
> Is it in alignment with Linux proposal here:
> https://patchwork.ozlabs.org/patch/1201508/?
> 
> Also could you provide a concise summary of what changes in programming
> sequence to support dual flashes? This will ease process of review.
> 
> >> Signed-off-by: Ashok Reddy Soma <ashok.reddy.s...@xilinx.com>
> >> ---
> [...]
> 
> >> 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
> >> +
> 
> Do we need this constant? Can we just use SZ_16M instead?
> 
> >>  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 */
> 
> Why can't SPI_RX_QUAD/SPI_TX_QUAD be used?
> 
> >> +#define SPI_MASTER_DATA_STRIPE  BIT(7)    /* support data stripe
> */
> 
> What does this mean? In particular what is "data stripe"?
> 
> >> +#define SPI_MASTER_BOTH_CS      BIT(8)          /* assert both chip 
> >> selects
> */
> 
> I don't see any users of above flags.
> 
> >> +#define SPI_MASTER_U_PAGE       BIT(9)    /* select upper flash */
> >> +
> 
> These macros need to be moved to include/spi.h where rest of the flag fields
> are defined.
> I see this flag is being set in nor->spi->flags, but who uses it? Its very 
> difficult
> to review patches when there are no users. Without any users, this comes a
> dead code which will be dropped while cleaning up.
> 
> 
> >>  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;
> 
> 
> Above bit of code is repeated more than once in this patch.
> You should refractor and add a wrapper for nor->read_reg() that takes care
> of these manipulations for dual parallel flash. Can it be extend further to
> handle stacked as well?
> 
> Individual helpers (such as read_fsr() below) to read/write registers should
> not have to bother about flash geometry but just use above helper.
> 
> >> +      }
> >>    }
> >>
> >> -  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;
> >> +
> 
> Hmm, is read_bar() called when flash size is <=16M?
> 
> >>    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) {
> 
> Who sets nor->spi->multi_die?
> 
> I have stopped reviewing at this point... This series is incomplete and 
> difficult
> to review.
> Please split this into two patch, one adding support for dual parallel flash 
> and
> one adding dual stacked. Also, include all dependent controller changes and
> other changes as separate patches.
> 
> BTW Is there a datasheet for dual flashes or an appnote?
> 
> Regards
> Vignesh
> 
> >> +                          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
> >
> 
> --
> Regards
> Vignesh

Reply via email to