[U-Boot] [RFC PATCH] spi: spi-nor: Add dual flash support in spi-nor framework
Michal Simek
michal.simek at xilinx.com
Tue Nov 26 07:09:53 UTC 2019
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.soma at 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(¶ms->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, ¶ms);
> 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
More information about the U-Boot
mailing list