aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configs/imx28_xea_defconfig1
-rw-r--r--drivers/mtd/spi/sandbox.c2
-rw-r--r--drivers/mtd/spi/spi-nor-core.c399
-rw-r--r--drivers/spi/Kconfig7
-rw-r--r--drivers/spi/altera_spi.c4
-rw-r--r--drivers/spi/atcspi200_spi.c2
-rw-r--r--drivers/spi/ath79_spi.c2
-rw-r--r--drivers/spi/atmel_spi.c6
-rw-r--r--drivers/spi/bcm63xx_hsspi.c42
-rw-r--r--drivers/spi/bcm63xx_spi.c6
-rw-r--r--drivers/spi/bcmbca_hsspi.c34
-rw-r--r--drivers/spi/cf_spi.c6
-rw-r--r--drivers/spi/davinci_spi.c8
-rw-r--r--drivers/spi/fsl_dspi.c18
-rw-r--r--drivers/spi/fsl_espi.c4
-rw-r--r--drivers/spi/fsl_qspi.c4
-rw-r--r--drivers/spi/gxp_spi.c2
-rw-r--r--drivers/spi/mpc8xx_spi.c4
-rw-r--r--drivers/spi/mpc8xxx_spi.c10
-rw-r--r--drivers/spi/mscc_bb_spi.c4
-rw-r--r--drivers/spi/mxc_spi.c6
-rw-r--r--drivers/spi/npcm_fiu_spi.c14
-rw-r--r--drivers/spi/nxp_fspi.c2
-rw-r--r--drivers/spi/octeon_spi.c2
-rw-r--r--drivers/spi/omap3_spi.c4
-rw-r--r--drivers/spi/pic32_spi.c2
-rw-r--r--drivers/spi/rk_spi.c4
-rw-r--r--drivers/spi/rockchip_sfc.c2
-rw-r--r--drivers/spi/spi-aspeed-smc.c28
-rw-r--r--drivers/spi/spi-mxic.c6
-rw-r--r--drivers/spi/spi-qup.c4
-rw-r--r--drivers/spi/spi-sifive.c6
-rw-r--r--drivers/spi/spi-sn-f-ospi.c2
-rw-r--r--drivers/spi/spi-sunxi.c6
-rw-r--r--drivers/spi/spi-synquacer.c4
-rw-r--r--drivers/spi/spi-uclass.c34
-rw-r--r--drivers/spi/stm32_qspi.c2
-rw-r--r--drivers/spi/stm32_spi.c4
-rw-r--r--drivers/spi/ti_qspi.c14
-rw-r--r--drivers/spi/xilinx_spi.c6
-rw-r--r--drivers/spi/zynq_qspi.c119
-rw-r--r--drivers/spi/zynq_spi.c6
-rw-r--r--drivers/spi/zynqmp_gqspi.c141
-rw-r--r--include/linux/mtd/spi-nor.h12
-rw-r--r--include/spi.h23
-rw-r--r--lib/acpi/acpi_device.c2
46 files changed, 792 insertions, 228 deletions
diff --git a/configs/imx28_xea_defconfig b/configs/imx28_xea_defconfig
index 822a329..8008e4c 100644
--- a/configs/imx28_xea_defconfig
+++ b/configs/imx28_xea_defconfig
@@ -126,6 +126,7 @@ CONFIG_SPECIFY_CONSOLE_INDEX=y
CONFIG_DM_SERIAL=y
CONFIG_SPI=y
CONFIG_DM_SPI=y
+# CONFIG_SPI_ADVANCE is not set
CONFIG_MXS_SPI=y
CONFIG_SPL_CRC8=y
# CONFIG_SPL_OF_LIBFDT is not set
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c
index 2d5a16b..e5ebc34 100644
--- a/drivers/mtd/spi/sandbox.c
+++ b/drivers/mtd/spi/sandbox.c
@@ -138,7 +138,7 @@ static int sandbox_sf_probe(struct udevice *dev)
return ret;
}
slave_plat = dev_get_parent_plat(dev);
- cs = slave_plat->cs;
+ cs = slave_plat->cs[0];
debug("found at cs %d\n", cs);
if (!pdata->filename) {
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 982dd25..ce4b062 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -461,8 +461,9 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
}
/*
- * Read the status register, returning its value in the location
- * Return the status register value.
+ * Return the status register value. If the chip is parallel, then the
+ * read will be striped, so we should read 2 bytes to get the sr
+ * register value from both of the parallel chips.
* Returns negative if error occurred.
*/
static int read_sr(struct spi_nor *nor)
@@ -494,18 +495,29 @@ static int read_sr(struct spi_nor *nor)
if (spi_nor_protocol_is_dtr(nor->reg_proto))
op.data.nbytes = 2;
- ret = spi_nor_read_write_reg(nor, &op, val);
- if (ret < 0) {
- pr_debug("error %d reading SR\n", (int)ret);
- return ret;
+ if (nor->flags & SNOR_F_HAS_PARALLEL) {
+ op.data.nbytes = 2;
+ ret = spi_nor_read_write_reg(nor, &op, &val[0]);
+ if (ret < 0) {
+ pr_debug("error %d reading SR\n", (int)ret);
+ return ret;
+ }
+ val[0] |= val[1];
+ } else {
+ ret = spi_nor_read_write_reg(nor, &op, &val[0]);
+ if (ret < 0) {
+ pr_debug("error %d reading SR\n", (int)ret);
+ return ret;
+ }
}
- return *val;
+ return val[0];
}
/*
- * Read the flag status register, returning its value in the location
- * Return the status register value.
+ * Return the flag status register value. If the chip is parallel, then
+ * the read will be striped, so we should read 2 bytes to get the fsr
+ * register value from both of the parallel chips.
* Returns negative if error occurred.
*/
static int read_fsr(struct spi_nor *nor)
@@ -537,13 +549,23 @@ static int read_fsr(struct spi_nor *nor)
if (spi_nor_protocol_is_dtr(nor->reg_proto))
op.data.nbytes = 2;
- ret = spi_nor_read_write_reg(nor, &op, val);
- if (ret < 0) {
- pr_debug("error %d reading FSR\n", ret);
- return ret;
+ if (nor->flags & SNOR_F_HAS_PARALLEL) {
+ op.data.nbytes = 2;
+ ret = spi_nor_read_write_reg(nor, &op, &val[0]);
+ if (ret < 0) {
+ pr_debug("error %d reading SR\n", (int)ret);
+ return ret;
+ }
+ val[0] &= val[1];
+ } else {
+ ret = spi_nor_read_write_reg(nor, &op, &val[0]);
+ if (ret < 0) {
+ pr_debug("error %d reading FSR\n", ret);
+ return ret;
+ }
}
- return *val;
+ return val[0];
}
/*
@@ -662,12 +684,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->flags & SNOR_F_HAS_PARALLEL)
+ 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:
@@ -881,12 +908,32 @@ 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;
+ struct mtd_info *mtd = &nor->mtd;
+
+ /* Wait until previous write command is finished */
+ if (spi_nor_wait_till_ready(nor))
+ return 1;
+
+ if (nor->flags & (SNOR_F_HAS_PARALLEL | SNOR_F_HAS_STACKED) &&
+ mtd->size <= SZ_32M)
+ return 0;
+
+ if (mtd->size <= SZ_16M)
+ return 0;
+
+ offset = offset % (u32)mtd->size;
+ bank_sel = offset >> 24;
- bank_sel = offset / SZ_16M;
- if (bank_sel == nor->bank_curr)
- goto bar_end;
+ upage_curr = nor->spi->flags & SPI_XFER_U_PAGE;
+
+ if (!(nor->flags & SNOR_F_HAS_STACKED) && bank_sel == nor->bank_curr)
+ return 0;
+ else if (upage_curr == nor->upage_prev && bank_sel == nor->bank_curr)
+ return 0;
+
+ nor->upage_prev = upage_curr;
cmd = nor->bank_write_cmd;
write_enable(nor);
@@ -896,15 +943,19 @@ static int write_bar(struct spi_nor *nor, u32 offset)
return ret;
}
-bar_end:
nor->bank_curr = bank_sel;
- return nor->bank_curr;
+
+ return write_disable(nor);
}
static int read_bar(struct spi_nor *nor, const struct flash_info *info)
{
u8 curr_bank = 0;
int ret;
+ struct mtd_info *mtd = &nor->mtd;
+
+ if (mtd->size <= SZ_16M)
+ return 0;
switch (JEDEC_MFR(info)) {
case SNOR_MFR_SPANSION:
@@ -916,15 +967,30 @@ static int read_bar(struct spi_nor *nor, const struct flash_info *info)
nor->bank_write_cmd = SPINOR_OP_WREAR;
}
+ if (nor->flags & SNOR_F_HAS_PARALLEL)
+ nor->spi->flags |= SPI_XFER_LOWER;
+
ret = nor->read_reg(nor, nor->bank_read_cmd,
- &curr_bank, 1);
+ &curr_bank, 1);
if (ret) {
debug("SF: fail to read bank addr register\n");
return ret;
}
nor->bank_curr = curr_bank;
- return 0;
+ // Make sure both chips use the same BAR
+ if (nor->flags & SNOR_F_HAS_PARALLEL) {
+ write_enable(nor);
+ ret = nor->write_reg(nor, nor->bank_write_cmd, &curr_bank, 1);
+ if (ret)
+ return ret;
+
+ ret = write_disable(nor);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
}
#endif
@@ -988,8 +1054,8 @@ 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, offset;
bool addr_known = false;
- u32 addr, len, rem;
int ret, err;
dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
@@ -1014,6 +1080,19 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
ret = -EINTR;
goto erase_err;
}
+
+ offset = addr;
+ if (nor->flags & SNOR_F_HAS_PARALLEL)
+ offset /= 2;
+
+ if (nor->flags & SNOR_F_HAS_STACKED) {
+ if (offset >= (mtd->size / 2)) {
+ offset = offset - (mtd->size / 2);
+ nor->spi->flags |= SPI_XFER_U_PAGE;
+ } else {
+ nor->spi->flags &= ~SPI_XFER_U_PAGE;
+ }
+ }
#ifdef CONFIG_SPI_FLASH_BAR
ret = write_bar(nor, addr);
if (ret < 0)
@@ -1419,6 +1498,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->flags & SNOR_F_HAS_PARALLEL)
+ 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);
@@ -1443,28 +1525,67 @@ 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;
+ loff_t offset = from;
+ u32 read_len = 0;
+ u32 rem_bank_len = 0;
+ u8 bank;
+ bool is_ofst_odd = false;
dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
+ if ((nor->flags & SNOR_F_HAS_PARALLEL) && (offset & 1)) {
+ /* We can hit this case when we use file system like ubifs */
+ from--;
+ len++;
+ is_ofst_odd = true;
+ }
+
while (len) {
- loff_t addr = from;
- size_t read_len = len;
+ if (nor->addr_width == 3) {
+ if (nor->flags & SNOR_F_HAS_PARALLEL) {
+ bank = (u32)from / (SZ_16M << 0x01);
+ rem_bank_len = ((SZ_16M << 0x01) *
+ (bank + 1)) - from;
+ } else {
+ bank = (u32)from / SZ_16M;
+ rem_bank_len = (SZ_16M * (bank + 1)) - from;
+ }
+ }
+ offset = from;
+
+ if (nor->flags & SNOR_F_HAS_STACKED) {
+ if (offset >= (mtd->size / 2)) {
+ offset = offset - (mtd->size / 2);
+ nor->spi->flags |= SPI_XFER_U_PAGE;
+ } else {
+ nor->spi->flags &= ~SPI_XFER_U_PAGE;
+ }
+ }
-#ifdef CONFIG_SPI_FLASH_BAR
- u32 remain_len;
+ if (nor->flags & SNOR_F_HAS_PARALLEL)
+ offset /= 2;
- ret = write_bar(nor, addr);
- if (ret < 0)
- return log_ret(ret);
- remain_len = (SZ_16M * (nor->bank_curr + 1)) - addr;
+ if (nor->addr_width == 3) {
+#ifdef CONFIG_SPI_FLASH_BAR
+ ret = write_bar(nor, offset);
+ if (ret < 0)
+ return log_ret(ret);
+#endif
+ }
- if (len < remain_len)
+ if (len < rem_bank_len)
read_len = len;
else
- read_len = remain_len;
-#endif
+ read_len = rem_bank_len;
+
+ if (read_len == 0)
+ return -EIO;
+
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret)
+ goto read_err;
- ret = nor->read(nor, addr, read_len, buf);
+ ret = nor->read(nor, offset, read_len, buf);
if (ret == 0) {
/* We shouldn't see 0-length reads */
ret = -EIO;
@@ -1473,8 +1594,15 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
if (ret < 0)
goto read_err;
- *retlen += ret;
- buf += ret;
+ if (is_ofst_odd == true) {
+ memmove(buf, (buf + 1), (len - 1));
+ *retlen += (ret - 1);
+ buf += ret - 1;
+ is_ofst_odd = false;
+ } else {
+ *retlen += ret;
+ buf += ret;
+ }
from += ret;
len -= ret;
}
@@ -1769,6 +1897,7 @@ 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;
+ u32 offset;
#ifdef CONFIG_SPI_FLASH_SST
/* sst nor chips use AAI word program */
@@ -1778,6 +1907,27 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
+ if (!len)
+ return 0;
+
+ /*
+ * Cannot write to odd offset in parallel mode,
+ * so write 2 bytes first
+ */
+ if ((nor->flags & SNOR_F_HAS_PARALLEL) && (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;
@@ -1795,17 +1945,37 @@ 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->flags & SNOR_F_HAS_PARALLEL)
+ offset /= 2;
+
+ if (nor->flags & SNOR_F_HAS_STACKED) {
+ if (offset >= (mtd->size / 2)) {
+ offset = offset - (mtd->size / 2);
+ nor->spi->flags |= SPI_XFER_U_PAGE;
+ } else {
+ nor->spi->flags &= ~SPI_XFER_U_PAGE;
+ }
+ }
+
+ if (nor->addr_width == 3) {
#ifdef CONFIG_SPI_FLASH_BAR
- ret = write_bar(nor, addr);
- if (ret < 0)
- return ret;
+ ret = write_bar(nor, offset);
+ if (ret < 0)
+ return ret;
#endif
+ }
+
+ 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;
@@ -1813,6 +1983,11 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
ret = spi_nor_wait_till_ready(nor);
if (ret)
goto write_err;
+
+ ret = write_disable(nor);
+ if (ret)
+ goto write_err;
+
*retlen += written;
i += written;
}
@@ -1853,6 +2028,10 @@ static int macronix_quad_enable(struct spi_nor *nor)
if (ret)
return ret;
+ ret = write_disable(nor);
+ if (ret)
+ return ret;
+
ret = read_sr(nor);
if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
dev_err(nor->dev, "Macronix Quad bit not set\n");
@@ -1914,7 +2093,7 @@ static int spansion_quad_enable_volatile(struct spi_nor *nor, u32 addr_base,
return -EINVAL;
}
- return 0;
+ return write_disable(nor);
}
#endif
@@ -2090,6 +2269,10 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr,
nor->read_dummy = 8;
while (len) {
+ /* Both chips are identical, so should be the SFDP data */
+ if (nor->flags & SNOR_F_HAS_PARALLEL)
+ nor->spi->flags |= SPI_XFER_LOWER;
+
ret = nor->read(nor, addr, len, (u8 *)buf);
if (!ret || ret > len) {
ret = -EIO;
@@ -2784,6 +2967,13 @@ static int spi_nor_init_params(struct spi_nor *nor,
const struct flash_info *info,
struct spi_nor_flash_parameter *params)
{
+#if CONFIG_IS_ENABLED(DM_SPI)
+ struct udevice *dev = nor->spi->dev;
+ u64 flash_size[SNOR_FLASH_CNT_MAX] = {0};
+ u32 idx = 0, i = 0;
+ int rc;
+#endif
+
/* Set legacy flash parameters as default. */
memset(params, 0, sizeof(*params));
@@ -2902,6 +3092,62 @@ static int spi_nor_init_params(struct spi_nor *nor,
}
}
+#if CONFIG_IS_ENABLED(DM_SPI)
+ /*
+ * The flashes that are connected in stacked mode should be of same make.
+ * Except the flash size all other properties are identical for all the
+ * flashes connected in stacked mode.
+ * The flashes that are connected in parallel mode should be identical.
+ */
+ while (i < SNOR_FLASH_CNT_MAX) {
+ rc = ofnode_read_u64_index(dev_ofnode(dev), "stacked-memories",
+ idx, &flash_size[i]);
+ if (rc == -EINVAL) {
+ break;
+ } else if (rc == -EOVERFLOW) {
+ idx++;
+ } else {
+ idx++;
+ i++;
+ if (!(nor->flags & SNOR_F_HAS_STACKED))
+ nor->flags |= SNOR_F_HAS_STACKED;
+ if (!(nor->spi->flags & SPI_XFER_STACKED))
+ nor->spi->flags |= SPI_XFER_STACKED;
+ }
+ }
+
+ i = 0;
+ idx = 0;
+ while (i < SNOR_FLASH_CNT_MAX) {
+ rc = ofnode_read_u64_index(dev_ofnode(dev), "parallel-memories",
+ idx, &flash_size[i]);
+ if (rc == -EINVAL) {
+ break;
+ } else if (rc == -EOVERFLOW) {
+ idx++;
+ } else {
+ idx++;
+ i++;
+ if (!(nor->flags & SNOR_F_HAS_PARALLEL))
+ nor->flags |= SNOR_F_HAS_PARALLEL;
+ }
+ }
+
+ if (nor->flags & (SNOR_F_HAS_STACKED | SNOR_F_HAS_PARALLEL)) {
+ params->size = 0;
+ for (idx = 0; idx < SNOR_FLASH_CNT_MAX; idx++)
+ params->size += flash_size[idx];
+ }
+ /*
+ * In parallel-memories the erase operation is
+ * performed on both the flashes simultaneously
+ * so, double the erasesize.
+ */
+ if (nor->flags & SNOR_F_HAS_PARALLEL) {
+ nor->mtd.erasesize <<= 1;
+ params->page_size <<= 1;
+ }
+#endif
spi_nor_post_sfdp_fixups(nor, params);
return 0;
@@ -3216,16 +3462,54 @@ static int spi_nor_select_erase(struct spi_nor *nor,
/* prefer "small sector" erase if possible */
if (info->flags & SECT_4K) {
nor->erase_opcode = SPINOR_OP_BE_4K;
- mtd->erasesize = 4096;
+ /*
+ * In parallel-memories the erase operation is
+ * performed on both the flashes simultaneously
+ * so, double the erasesize.
+ */
+ if (nor->flags & SNOR_F_HAS_PARALLEL)
+ mtd->erasesize = 4096 * 2;
+ else
+ mtd->erasesize = 4096;
} else if (info->flags & SECT_4K_PMC) {
nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
- mtd->erasesize = 4096;
+ /*
+ * In parallel-memories the erase operation is
+ * performed on both the flashes simultaneously
+ * so, double the erasesize.
+ */
+ if (nor->flags & SNOR_F_HAS_PARALLEL)
+ mtd->erasesize = 4096 * 2;
+ else
+ mtd->erasesize = 4096;
} else
#endif
{
nor->erase_opcode = SPINOR_OP_SE;
- mtd->erasesize = info->sector_size;
+ /*
+ * In parallel-memories the erase operation is
+ * performed on both the flashes simultaneously
+ * so, double the erasesize.
+ */
+ if (nor->flags & SNOR_F_HAS_PARALLEL)
+ mtd->erasesize = info->sector_size * 2;
+ else
+ mtd->erasesize = info->sector_size;
+ }
+
+ if ((JEDEC_MFR(info) == SNOR_MFR_SST) && info->flags & SECT_4K) {
+ nor->erase_opcode = SPINOR_OP_BE_4K;
+ /*
+ * In parallel-memories the erase operation is
+ * performed on both the flashes simultaneously
+ * so, double the erasesize.
+ */
+ if (nor->flags & SNOR_F_HAS_PARALLEL)
+ mtd->erasesize = 4096 * 2;
+ else
+ mtd->erasesize = 4096;
}
+
return 0;
}
@@ -3847,6 +4131,9 @@ static int spi_nor_init(struct spi_nor *nor)
{
int err;
+ if (nor->flags & SNOR_F_HAS_PARALLEL)
+ nor->spi->flags |= SPI_NOR_ENABLE_MULTI_CS;
+
err = spi_nor_octal_dtr_enable(nor);
if (err) {
dev_dbg(nor->dev, "Octal DTR mode not supported\n");
@@ -4013,6 +4300,7 @@ int spi_nor_scan(struct spi_nor *nor)
struct spi_slave *spi = nor->spi;
int ret;
int cfi_mtd_nb = 0;
+ bool shift = 0;
#ifdef CONFIG_FLASH_CFI_MTD
cfi_mtd_nb = CFI_FLASH_BANKS;
@@ -4150,7 +4438,9 @@ int spi_nor_scan(struct spi_nor *nor)
nor->addr_width = 3;
}
- if (nor->addr_width == 3 && mtd->size > SZ_16M) {
+ if (nor->flags & (SNOR_F_HAS_PARALLEL | SNOR_F_HAS_STACKED))
+ shift = 1;
+ if (nor->addr_width == 3 && (mtd->size >> shift) > SZ_16M) {
#ifndef CONFIG_SPI_FLASH_BAR
/* enable 4-byte addressing if the device exceeds 16MiB */
nor->addr_width = 4;
@@ -4160,6 +4450,7 @@ int spi_nor_scan(struct spi_nor *nor)
#else
/* Configure the BAR - discover bank cmds and read current bank */
nor->addr_width = 3;
+ set_4byte(nor, info, 0);
ret = read_bar(nor, info);
if (ret < 0)
return ret;
@@ -4177,6 +4468,14 @@ int spi_nor_scan(struct spi_nor *nor)
if (ret)
return ret;
+ if (nor->flags & SNOR_F_HAS_STACKED) {
+ nor->spi->flags |= SPI_XFER_U_PAGE;
+ ret = spi_nor_init(nor);
+ if (ret)
+ return ret;
+ nor->spi->flags &= ~SPI_XFER_U_PAGE;
+ }
+
nor->rdsr_dummy = params.rdsr_dummy;
nor->rdsr_addr_nbytes = params.rdsr_addr_nbytes;
nor->name = info->name;
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 35030ab..238e622 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -50,6 +50,13 @@ config SPI_DIRMAP
improvements as it automates the whole process of sending SPI memory
operations every time a new region is accessed.
+config SPI_ADVANCE
+ bool "Enable the advance feature"
+ default y
+ help
+ Enable the SPI advance feature support. By default this is set to y.
+ If you intend not to use the advance feature support you should say n here.
+
if DM_SPI
config ALTERA_SPI
diff --git a/drivers/spi/altera_spi.c b/drivers/spi/altera_spi.c
index 8e227d1..dafaf11 100644
--- a/drivers/spi/altera_spi.c
+++ b/drivers/spi/altera_spi.c
@@ -95,7 +95,7 @@ static int altera_spi_xfer(struct udevice *dev, unsigned int bitlen,
uint32_t reg, data, start;
debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
- dev_seq(bus), slave_plat->cs, bitlen, bytes, flags);
+ dev_seq(bus), slave_plat->cs[0], bitlen, bytes, flags);
if (bitlen == 0)
goto done;
@@ -110,7 +110,7 @@ static int altera_spi_xfer(struct udevice *dev, unsigned int bitlen,
readl(&regs->rxdata);
if (flags & SPI_XFER_BEGIN)
- spi_cs_activate(dev, slave_plat->cs);
+ spi_cs_activate(dev, slave_plat->cs[0]);
while (bytes--) {
if (txp)
diff --git a/drivers/spi/atcspi200_spi.c b/drivers/spi/atcspi200_spi.c
index 929bf90..100d668 100644
--- a/drivers/spi/atcspi200_spi.c
+++ b/drivers/spi/atcspi200_spi.c
@@ -320,7 +320,7 @@ static int atcspi200_spi_claim_bus(struct udevice *dev)
struct udevice *bus = dev->parent;
struct nds_spi_slave *ns = dev_get_priv(bus);
- if (slave_plat->cs >= ns->num_cs) {
+ if (slave_plat->cs[0] >= ns->num_cs) {
printf("Invalid SPI chipselect\n");
return -EINVAL;
}
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
index faefac7..965a844 100644
--- a/drivers/spi/ath79_spi.c
+++ b/drivers/spi/ath79_spi.c
@@ -73,7 +73,7 @@ static int ath79_spi_xfer(struct udevice *dev, unsigned int bitlen,
if (restbits)
bytes++;
- out = AR71XX_SPI_IOC_CS_ALL & ~(AR71XX_SPI_IOC_CS(slave->cs));
+ out = AR71XX_SPI_IOC_CS_ALL & ~(AR71XX_SPI_IOC_CS(slave->cs[0]));
while (bytes > 0) {
bytes--;
curbyte = 0;
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 79f0100..aaf3edd 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -125,7 +125,7 @@ static int atmel_spi_claim_bus(struct udevice *dev)
struct atmel_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
struct at91_spi *reg_base = bus_plat->regs;
- u32 cs = slave_plat->cs;
+ u32 cs = slave_plat->cs[0];
u32 freq = priv->freq;
u32 scbr, csrx, mode;
@@ -174,7 +174,7 @@ static void atmel_spi_cs_activate(struct udevice *dev)
struct udevice *bus = dev_get_parent(dev);
struct atmel_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- u32 cs = slave_plat->cs;
+ u32 cs = slave_plat->cs[0];
if (!dm_gpio_is_valid(&priv->cs_gpios[cs]))
return;
@@ -189,7 +189,7 @@ static void atmel_spi_cs_deactivate(struct udevice *dev)
struct udevice *bus = dev_get_parent(dev);
struct atmel_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- u32 cs = slave_plat->cs;
+ u32 cs = slave_plat->cs[0];
if (!dm_gpio_is_valid(&priv->cs_gpios[cs]))
return;
diff --git a/drivers/spi/bcm63xx_hsspi.c b/drivers/spi/bcm63xx_hsspi.c
index 1aa43fd..e9f0b34 100644
--- a/drivers/spi/bcm63xx_hsspi.c
+++ b/drivers/spi/bcm63xx_hsspi.c
@@ -174,7 +174,7 @@ static void bcm63xx_hsspi_activate_cs(struct bcm63xx_hsspi_priv *priv,
set = DIV_ROUND_UP(2048, set);
set &= SPI_PFL_CLK_FREQ_MASK;
set |= SPI_PFL_CLK_RSTLOOP_MASK;
- writel(set, priv->regs + SPI_PFL_CLK_REG(plat->cs));
+ writel(set, priv->regs + SPI_PFL_CLK_REG(plat->cs[0]));
/* profile signal */
set = 0;
@@ -192,29 +192,29 @@ static void bcm63xx_hsspi_activate_cs(struct bcm63xx_hsspi_priv *priv,
if (speed > SPI_MAX_SYNC_CLOCK)
set |= SPI_PFL_SIG_ASYNCIN_MASK;
- clrsetbits_32(priv->regs + SPI_PFL_SIG_REG(plat->cs), clr, set);
+ clrsetbits_32(priv->regs + SPI_PFL_SIG_REG(plat->cs[0]), clr, set);
/* global control */
set = 0;
clr = 0;
if (priv->xfer_mode == HSSPI_XFER_MODE_PREPEND) {
- if (priv->cs_pols & BIT(plat->cs))
- set |= BIT(plat->cs);
+ if (priv->cs_pols & BIT(plat->cs[0]))
+ set |= BIT(plat->cs[0]);
else
- clr |= BIT(plat->cs);
+ clr |= BIT(plat->cs[0]);
} else {
/* invert cs polarity */
- if (priv->cs_pols & BIT(plat->cs))
- clr |= BIT(plat->cs);
+ if (priv->cs_pols & BIT(plat->cs[0]))
+ clr |= BIT(plat->cs[0]);
else
- set |= BIT(plat->cs);
+ set |= BIT(plat->cs[0]);
/* invert dummy cs polarity */
- if (priv->cs_pols & BIT(!plat->cs))
- clr |= BIT(!plat->cs);
+ if (priv->cs_pols & BIT(!plat->cs[0]))
+ clr |= BIT(!plat->cs[0]);
else
- set |= BIT(!plat->cs);
+ set |= BIT(!plat->cs[0]);
}
clrsetbits_32(priv->regs + SPI_CTL_REG, clr, set);
@@ -290,7 +290,7 @@ static int bcm63xx_hsspi_xfer_dummy_cs(struct udevice *dev, unsigned int data_by
if (plat->mode & SPI_3WIRE)
val |= SPI_PFL_MODE_3WIRE_MASK;
- writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs));
+ writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs[0]));
/* transfer loop */
while (data_bytes > 0) {
@@ -310,9 +310,9 @@ static int bcm63xx_hsspi_xfer_dummy_cs(struct udevice *dev, unsigned int data_by
/* issue the transfer */
val = SPI_CMD_OP_START;
- val |= (plat->cs << SPI_CMD_PFL_SHIFT) &
+ val |= (plat->cs[0] << SPI_CMD_PFL_SHIFT) &
SPI_CMD_PFL_MASK;
- val |= (!plat->cs << SPI_CMD_SLAVE_SHIFT) &
+ val |= (!plat->cs[0] << SPI_CMD_SLAVE_SHIFT) &
SPI_CMD_SLAVE_MASK;
writel(val, priv->regs + SPI_CMD_REG);
@@ -450,7 +450,7 @@ static int bcm63xx_hsspi_xfer_prepend(struct udevice *dev, unsigned int data_byt
}
}
val |= (priv->prepend_cnt << SPI_PFL_MODE_PREPCNT_SHIFT);
- writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs));
+ writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs[0]));
/* set fifo operation */
val = opcode | (data_bytes & HSSPI_FIFO_OP_BYTES_MASK);
@@ -459,9 +459,9 @@ static int bcm63xx_hsspi_xfer_prepend(struct udevice *dev, unsigned int data_byt
/* issue the transfer */
val = SPI_CMD_OP_START;
- val |= (plat->cs << SPI_CMD_PFL_SHIFT) &
+ val |= (plat->cs[0] << SPI_CMD_PFL_SHIFT) &
SPI_CMD_PFL_MASK;
- val |= (plat->cs << SPI_CMD_SLAVE_SHIFT) &
+ val |= (plat->cs[0] << SPI_CMD_SLAVE_SHIFT) &
SPI_CMD_SLAVE_MASK;
writel(val, priv->regs + SPI_CMD_REG);
@@ -537,16 +537,16 @@ static int bcm63xx_hsspi_child_pre_probe(struct udevice *dev)
struct spi_slave *slave = dev_get_parent_priv(dev);
/* check cs */
- if (plat->cs >= priv->num_cs) {
- printf("no cs %u\n", plat->cs);
+ if (plat->cs[0] >= priv->num_cs) {
+ printf("no cs %u\n", plat->cs[0]);
return -ENODEV;
}
/* cs polarity */
if (plat->mode & SPI_CS_HIGH)
- priv->cs_pols |= BIT(plat->cs);
+ priv->cs_pols |= BIT(plat->cs[0]);
else
- priv->cs_pols &= ~BIT(plat->cs);
+ priv->cs_pols &= ~BIT(plat->cs[0]);
/*
* set the max read/write size to make sure each xfer are within the
diff --git a/drivers/spi/bcm63xx_spi.c b/drivers/spi/bcm63xx_spi.c
index 595b41c..e02ec7e 100644
--- a/drivers/spi/bcm63xx_spi.c
+++ b/drivers/spi/bcm63xx_spi.c
@@ -275,7 +275,7 @@ static int bcm63xx_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* issue the transfer */
cmd = SPI_CMD_OP_START;
- cmd |= (plat->cs << SPI_CMD_SLAVE_SHIFT) & SPI_CMD_SLAVE_MASK;
+ cmd |= (plat->cs[0] << SPI_CMD_SLAVE_SHIFT) & SPI_CMD_SLAVE_MASK;
cmd |= (priv->tx_bytes << SPI_CMD_PREPEND_SHIFT);
if (plat->mode & SPI_3WIRE)
cmd |= SPI_CMD_3WIRE_MASK;
@@ -353,8 +353,8 @@ static int bcm63xx_spi_child_pre_probe(struct udevice *dev)
struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev);
/* check cs */
- if (plat->cs >= priv->num_cs) {
- printf("no cs %u\n", plat->cs);
+ if (plat->cs[0] >= priv->num_cs) {
+ printf("no cs %u\n", plat->cs[0]);
return -ENODEV;
}
diff --git a/drivers/spi/bcmbca_hsspi.c b/drivers/spi/bcmbca_hsspi.c
index eff9e11..209ca71 100644
--- a/drivers/spi/bcmbca_hsspi.c
+++ b/drivers/spi/bcmbca_hsspi.c
@@ -155,7 +155,7 @@ static void bcmbca_hsspi_setup_clock(struct bcmbca_hsspi_priv *priv,
set = DIV_ROUND_UP(2048, set);
set &= SPI_PFL_CLK_FREQ_MASK;
set |= SPI_PFL_CLK_RSTLOOP_MASK;
- writel(set, priv->regs + SPI_PFL_CLK_REG(plat->cs));
+ writel(set, priv->regs + SPI_PFL_CLK_REG(plat->cs[0]));
/* profile signal */
set = 0;
@@ -173,16 +173,16 @@ static void bcmbca_hsspi_setup_clock(struct bcmbca_hsspi_priv *priv,
if (priv->speed > SPI_MAX_SYNC_CLOCK)
set |= SPI_PFL_SIG_ASYNCIN_MASK;
- clrsetbits_32(priv->regs + SPI_PFL_SIG_REG(plat->cs), clr, set);
+ clrsetbits_32(priv->regs + SPI_PFL_SIG_REG(plat->cs[0]), clr, set);
/* global control */
set = 0;
clr = 0;
- if (priv->cs_pols & BIT(plat->cs))
- set |= BIT(plat->cs);
+ if (priv->cs_pols & BIT(plat->cs[0]))
+ set |= BIT(plat->cs[0]);
else
- clr |= BIT(plat->cs);
+ clr |= BIT(plat->cs[0]);
clrsetbits_32(priv->regs + SPI_CTL_REG, clr, set);
}
@@ -194,7 +194,7 @@ static void bcmbca_hsspi_activate_cs(struct bcmbca_hsspi_priv *priv,
/* set the override bit */
val = readl(priv->spim_ctrl);
- val |= BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
+ val |= BIT(plat->cs[0] + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
writel(val, priv->spim_ctrl);
}
@@ -205,7 +205,7 @@ static void bcmbca_hsspi_deactivate_cs(struct bcmbca_hsspi_priv *priv,
/* clear the cs override bit */
val = readl(priv->spim_ctrl);
- val &= ~BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
+ val &= ~BIT(plat->cs[0] + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
writel(val, priv->spim_ctrl);
}
@@ -250,7 +250,7 @@ static int bcmbca_hsspi_xfer(struct udevice *dev, unsigned int bitlen,
if (plat->mode & SPI_3WIRE)
val |= SPI_PFL_MODE_3WIRE_MASK;
- writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs));
+ writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs[0]));
/* transfer loop */
while (data_bytes > 0) {
@@ -276,9 +276,9 @@ static int bcmbca_hsspi_xfer(struct udevice *dev, unsigned int bitlen,
/* issue the transfer */
val = SPI_CMD_OP_START;
- val |= (plat->cs << SPI_CMD_PFL_SHIFT) &
+ val |= (plat->cs[0] << SPI_CMD_PFL_SHIFT) &
SPI_CMD_PFL_MASK;
- val |= (plat->cs << SPI_CMD_SLAVE_SHIFT) &
+ val |= (plat->cs[0] << SPI_CMD_SLAVE_SHIFT) &
SPI_CMD_SLAVE_MASK;
writel(val, priv->regs + SPI_CMD_REG);
@@ -326,22 +326,22 @@ static int bcmbca_hsspi_child_pre_probe(struct udevice *dev)
u32 val;
/* check cs */
- if (plat->cs >= priv->num_cs) {
- dev_err(dev, "no cs %u\n", plat->cs);
+ if (plat->cs[0] >= priv->num_cs) {
+ dev_err(dev, "no cs %u\n", plat->cs[0]);
return -EINVAL;
}
/* cs polarity */
if (plat->mode & SPI_CS_HIGH)
- priv->cs_pols |= BIT(plat->cs);
+ priv->cs_pols |= BIT(plat->cs[0]);
else
- priv->cs_pols &= ~BIT(plat->cs);
+ priv->cs_pols &= ~BIT(plat->cs[0]);
/* set the polarity to spim cs register */
val = readl(priv->spim_ctrl);
- val &= ~BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
- if (priv->cs_pols & BIT(plat->cs))
- val |= BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
+ val &= ~BIT(plat->cs[0] + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
+ if (priv->cs_pols & BIT(plat->cs[0]))
+ val |= BIT(plat->cs[0] + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
writel(val, priv->spim_ctrl);
return 0;
diff --git a/drivers/spi/cf_spi.c b/drivers/spi/cf_spi.c
index 8234468..84077c0 100644
--- a/drivers/spi/cf_spi.c
+++ b/drivers/spi/cf_spi.c
@@ -123,7 +123,7 @@ static int coldfire_spi_claim_bus(struct udevice *dev)
/* Clear FIFO and resume transfer */
clrbits_be32(&dspi->mcr, DSPI_MCR_CTXF | DSPI_MCR_CRXF);
- dspi_chip_select(slave_plat->cs);
+ dspi_chip_select(slave_plat->cs[0]);
return 0;
}
@@ -139,7 +139,7 @@ static int coldfire_spi_release_bus(struct udevice *dev)
/* Clear FIFO */
clrbits_be32(&dspi->mcr, DSPI_MCR_CTXF | DSPI_MCR_CRXF);
- dspi_chip_unselect(slave_plat->cs);
+ dspi_chip_unselect(slave_plat->cs[0]);
return 0;
}
@@ -168,7 +168,7 @@ static int coldfire_spi_xfer(struct udevice *dev, unsigned int bitlen,
if ((flags & SPI_XFER_BEGIN) == SPI_XFER_BEGIN)
ctrl |= DSPI_TFR_CONT;
- ctrl = setup_ctrl(ctrl, slave_plat->cs);
+ ctrl = setup_ctrl(ctrl, slave_plat->cs[0]);
if (len > 1) {
int tmp_len = len - 1;
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index 04c134b..e5c1373 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -339,13 +339,13 @@ static int davinci_spi_claim_bus(struct udevice *dev)
struct udevice *bus = dev->parent;
struct davinci_spi_slave *ds = dev_get_priv(bus);
- if (slave_plat->cs >= ds->num_cs) {
+ if (slave_plat->cs[0] >= ds->num_cs) {
printf("Invalid SPI chipselect\n");
return -EINVAL;
}
ds->half_duplex = slave_plat->mode & SPI_PREAMBLE;
- return __davinci_spi_claim_bus(ds, slave_plat->cs);
+ return __davinci_spi_claim_bus(ds, slave_plat->cs[0]);
}
static int davinci_spi_release_bus(struct udevice *dev)
@@ -364,11 +364,11 @@ static int davinci_spi_xfer(struct udevice *dev, unsigned int bitlen,
struct udevice *bus = dev->parent;
struct davinci_spi_slave *ds = dev_get_priv(bus);
- if (slave->cs >= ds->num_cs) {
+ if (slave->cs[0] >= ds->num_cs) {
printf("Invalid SPI chipselect\n");
return -EINVAL;
}
- ds->cur_cs = slave->cs;
+ ds->cur_cs = slave->cs[0];
return __davinci_spi_xfer(ds, bitlen, dout, din, flags);
}
diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c
index 1d4d90c..f2393c0 100644
--- a/drivers/spi/fsl_dspi.c
+++ b/drivers/spi/fsl_dspi.c
@@ -452,9 +452,9 @@ static int fsl_dspi_child_pre_probe(struct udevice *dev)
unsigned char pcssck = 0, cssck = 0;
unsigned char pasc = 0, asc = 0;
- if (slave_plat->cs >= priv->num_chipselect) {
+ if (slave_plat->cs[0] >= priv->num_chipselect) {
debug("DSPI invalid chipselect number %d(max %d)!\n",
- slave_plat->cs, priv->num_chipselect - 1);
+ slave_plat->cs[0], priv->num_chipselect - 1);
return -EINVAL;
}
@@ -469,12 +469,12 @@ static int fsl_dspi_child_pre_probe(struct udevice *dev)
/* Set After SCK delay scale values */
ns_delay_scale(&pasc, &asc, sck_cs_delay, priv->bus_clk);
- priv->ctar_val[slave_plat->cs] = DSPI_CTAR_DEFAULT_VALUE |
+ priv->ctar_val[slave_plat->cs[0]] = DSPI_CTAR_DEFAULT_VALUE |
DSPI_CTAR_PCSSCK(pcssck) |
DSPI_CTAR_PASC(pasc);
debug("DSPI pre_probe slave device on CS %u, max_hz %u, mode 0x%x.\n",
- slave_plat->cs, slave_plat->max_hz, slave_plat->mode);
+ slave_plat->cs[0], slave_plat->max_hz, slave_plat->mode);
return 0;
}
@@ -527,13 +527,13 @@ static int fsl_dspi_claim_bus(struct udevice *dev)
priv = dev_get_priv(bus);
/* processor special preparation work */
- cpu_dspi_claim_bus(dev_seq(bus), slave_plat->cs);
+ cpu_dspi_claim_bus(dev_seq(bus), slave_plat->cs[0]);
/* configure transfer mode */
- fsl_dspi_cfg_ctar_mode(priv, slave_plat->cs, priv->mode);
+ fsl_dspi_cfg_ctar_mode(priv, slave_plat->cs[0], priv->mode);
/* configure active state of CSX */
- fsl_dspi_cfg_cs_active_state(priv, slave_plat->cs,
+ fsl_dspi_cfg_cs_active_state(priv, slave_plat->cs[0],
priv->mode);
fsl_dspi_clr_fifo(priv);
@@ -559,7 +559,7 @@ static int fsl_dspi_release_bus(struct udevice *dev)
dspi_halt(priv, 1);
/* processor special release work */
- cpu_dspi_release_bus(dev_seq(bus), slave_plat->cs);
+ cpu_dspi_release_bus(dev_seq(bus), slave_plat->cs[0]);
return 0;
}
@@ -615,7 +615,7 @@ static int fsl_dspi_xfer(struct udevice *dev, unsigned int bitlen,
bus = dev->parent;
priv = dev_get_priv(bus);
- return dspi_xfer(priv, slave_plat->cs, bitlen, dout, din, flags);
+ return dspi_xfer(priv, slave_plat->cs[0], bitlen, dout, din, flags);
}
static int fsl_dspi_set_speed(struct udevice *bus, uint speed)
diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c
index 2638ed2..7ed35aa 100644
--- a/drivers/spi/fsl_espi.c
+++ b/drivers/spi/fsl_espi.c
@@ -513,8 +513,8 @@ static int fsl_espi_child_pre_probe(struct udevice *dev)
struct udevice *bus = dev->parent;
struct fsl_spi_slave *fsl = dev_get_priv(bus);
- debug("%s cs %u\n", __func__, slave_plat->cs);
- fsl->cs = slave_plat->cs;
+ debug("%s cs %u\n", __func__, slave_plat->cs[0]);
+ fsl->cs = slave_plat->cs[0];
return 0;
}
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 8a0a53c..c7f5548 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -510,10 +510,10 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_slave *slave)
struct dm_spi_slave_plat *plat =
dev_get_parent_plat(slave->dev);
- if (q->selected == plat->cs)
+ if (q->selected == plat->cs[0])
return;
- q->selected = plat->cs;
+ q->selected = plat->cs[0];
fsl_qspi_invalidate(q);
}
diff --git a/drivers/spi/gxp_spi.c b/drivers/spi/gxp_spi.c
index 70d76ac..3ee369c 100644
--- a/drivers/spi/gxp_spi.c
+++ b/drivers/spi/gxp_spi.c
@@ -87,7 +87,7 @@ static int gxp_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *do
value = readl(priv->base + OFFSET_SPIMCFG);
value &= ~(1 << 24);
/* set chipselect */
- value |= (slave_plat->cs << 24);
+ value |= (slave_plat->cs[0] << 24);
/* addr reg and addr size */
if (len >= 4) {
diff --git a/drivers/spi/mpc8xx_spi.c b/drivers/spi/mpc8xx_spi.c
index 7e72fb9..51cc487 100644
--- a/drivers/spi/mpc8xx_spi.c
+++ b/drivers/spi/mpc8xx_spi.c
@@ -148,7 +148,7 @@ static void mpc8xx_spi_cs_activate(struct udevice *dev)
struct mpc8xx_priv *priv = dev_get_priv(dev->parent);
struct dm_spi_slave_plat *platdata = dev_get_parent_plat(dev);
- dm_gpio_set_value(&priv->gpios[platdata->cs], 1);
+ dm_gpio_set_value(&priv->gpios[platdata->cs[0]], 1);
}
static void mpc8xx_spi_cs_deactivate(struct udevice *dev)
@@ -156,7 +156,7 @@ static void mpc8xx_spi_cs_deactivate(struct udevice *dev)
struct mpc8xx_priv *priv = dev_get_priv(dev->parent);
struct dm_spi_slave_plat *platdata = dev_get_parent_plat(dev);
- dm_gpio_set_value(&priv->gpios[platdata->cs], 0);
+ dm_gpio_set_value(&priv->gpios[platdata->cs[0]], 0);
}
static int mpc8xx_spi_xfer_one(struct udevice *dev, size_t count,
diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c
index cd624f4..b34e1c2 100644
--- a/drivers/spi/mpc8xxx_spi.c
+++ b/drivers/spi/mpc8xxx_spi.c
@@ -113,7 +113,7 @@ static void mpc8xxx_spi_cs_activate(struct udevice *dev)
struct mpc8xxx_priv *priv = dev_get_priv(dev->parent);
struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev);
- dm_gpio_set_value(&priv->gpios[plat->cs], 1);
+ dm_gpio_set_value(&priv->gpios[plat->cs[0]], 1);
}
static void mpc8xxx_spi_cs_deactivate(struct udevice *dev)
@@ -121,7 +121,7 @@ static void mpc8xxx_spi_cs_deactivate(struct udevice *dev)
struct mpc8xxx_priv *priv = dev_get_priv(dev->parent);
struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev);
- dm_gpio_set_value(&priv->gpios[plat->cs], 0);
+ dm_gpio_set_value(&priv->gpios[plat->cs[0]], 0);
}
static int mpc8xxx_spi_xfer(struct udevice *dev, uint bitlen,
@@ -137,10 +137,10 @@ static int mpc8xxx_spi_xfer(struct udevice *dev, uint bitlen,
ulong type = dev_get_driver_data(bus);
debug("%s: slave %s:%u dout %08X din %08X bitlen %u\n", __func__,
- bus->name, plat->cs, (uint)dout, (uint)din, bitlen);
- if (plat->cs >= priv->cs_count) {
+ bus->name, plat->cs[0], (uint)dout, (uint)din, bitlen);
+ if (plat->cs[0] >= priv->cs_count) {
dev_err(dev, "chip select index %d too large (cs_count=%d)\n",
- plat->cs, priv->cs_count);
+ plat->cs[0], priv->cs_count);
return -EINVAL;
}
if (bitlen % 8) {
diff --git a/drivers/spi/mscc_bb_spi.c b/drivers/spi/mscc_bb_spi.c
index ad4daeb..75ab4ab 100644
--- a/drivers/spi/mscc_bb_spi.c
+++ b/drivers/spi/mscc_bb_spi.c
@@ -123,11 +123,11 @@ int mscc_bb_spi_xfer(struct udevice *dev, unsigned int bitlen,
u8 *rxd = din;
debug("spi_xfer: slave %s:%s cs%d mode %d, dout %p din %p bitlen %u\n",
- dev->parent->name, dev->name, plat->cs, plat->mode, dout,
+ dev->parent->name, dev->name, plat->cs[0], plat->mode, dout,
din, bitlen);
if (flags & SPI_XFER_BEGIN)
- mscc_bb_spi_cs_activate(priv, plat->mode, plat->cs);
+ mscc_bb_spi_cs_activate(priv, plat->mode, plat->cs[0]);
count = bitlen / 8;
for (i = 0; i < count; i++) {
diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c
index ff61a14..b864a69 100644
--- a/drivers/spi/mxc_spi.c
+++ b/drivers/spi/mxc_spi.c
@@ -135,7 +135,7 @@ static void mxc_spi_cs_activate(struct mxc_spi_slave *mxcs)
struct udevice *dev = mxcs->dev;
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- u32 cs = slave_plat->cs;
+ u32 cs = slave_plat->cs[0];
if (!dm_gpio_is_valid(&mxcs->cs_gpios[cs]))
return;
@@ -153,7 +153,7 @@ static void mxc_spi_cs_deactivate(struct mxc_spi_slave *mxcs)
struct udevice *dev = mxcs->dev;
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- u32 cs = slave_plat->cs;
+ u32 cs = slave_plat->cs[0];
if (!dm_gpio_is_valid(&mxcs->cs_gpios[cs]))
return;
@@ -633,7 +633,7 @@ static int mxc_spi_claim_bus(struct udevice *dev)
mxcs->dev = dev;
- return mxc_spi_claim_bus_internal(mxcs, slave_plat->cs);
+ return mxc_spi_claim_bus_internal(mxcs, slave_plat->cs[0]);
}
static int mxc_spi_release_bus(struct udevice *dev)
diff --git a/drivers/spi/npcm_fiu_spi.c b/drivers/spi/npcm_fiu_spi.c
index 73c5064..7b8271c 100644
--- a/drivers/spi/npcm_fiu_spi.c
+++ b/drivers/spi/npcm_fiu_spi.c
@@ -203,7 +203,7 @@ static int npcm_fiu_spi_xfer(struct udevice *dev, unsigned int bitlen,
int len;
if (flags & SPI_XFER_BEGIN)
- activate_cs(regs, slave_plat->cs);
+ activate_cs(regs, slave_plat->cs[0]);
while (bytes) {
len = (bytes > CHUNK_SIZE) ? CHUNK_SIZE : bytes;
@@ -222,7 +222,7 @@ static int npcm_fiu_spi_xfer(struct udevice *dev, unsigned int bitlen,
}
if (flags & SPI_XFER_END)
- deactivate_cs(regs, slave_plat->cs);
+ deactivate_cs(regs, slave_plat->cs[0]);
return ret;
}
@@ -325,9 +325,9 @@ static int npcm_fiu_exec_op(struct spi_slave *slave,
bytes = op->data.nbytes;
addr = (u32)op->addr.val;
if (!bytes) {
- activate_cs(regs, slave_plat->cs);
+ activate_cs(regs, slave_plat->cs[0]);
ret = npcm_fiu_uma_operation(priv, op, addr, NULL, NULL, 0, false);
- deactivate_cs(regs, slave_plat->cs);
+ deactivate_cs(regs, slave_plat->cs[0]);
return ret;
}
@@ -339,9 +339,9 @@ static int npcm_fiu_exec_op(struct spi_slave *slave,
* Use HW-control CS for read to avoid clock and timing issues.
*/
if (op->data.dir == SPI_MEM_DATA_OUT)
- activate_cs(regs, slave_plat->cs);
+ activate_cs(regs, slave_plat->cs[0]);
else
- writel(FIELD_PREP(UMA_CTS_DEV_NUM_MASK, slave_plat->cs) | UMA_CTS_SW_CS,
+ writel(FIELD_PREP(UMA_CTS_DEV_NUM_MASK, slave_plat->cs[0]) | UMA_CTS_SW_CS,
&regs->uma_cts);
while (bytes) {
len = (bytes > CHUNK_SIZE) ? CHUNK_SIZE : bytes;
@@ -361,7 +361,7 @@ static int npcm_fiu_exec_op(struct spi_slave *slave,
rx += len;
}
if (op->data.dir == SPI_MEM_DATA_OUT)
- deactivate_cs(regs, slave_plat->cs);
+ deactivate_cs(regs, slave_plat->cs[0]);
return 0;
}
diff --git a/drivers/spi/nxp_fspi.c b/drivers/spi/nxp_fspi.c
index fefdaaa..7489c89 100644
--- a/drivers/spi/nxp_fspi.c
+++ b/drivers/spi/nxp_fspi.c
@@ -962,7 +962,7 @@ static int nxp_fspi_claim_bus(struct udevice *dev)
bus = dev->parent;
f = dev_get_priv(bus);
- nxp_fspi_select_mem(f, slave_plat->cs);
+ nxp_fspi_select_mem(f, slave_plat->cs[0]);
return 0;
}
diff --git a/drivers/spi/octeon_spi.c b/drivers/spi/octeon_spi.c
index 4bc38be..0e6e0f7 100644
--- a/drivers/spi/octeon_spi.c
+++ b/drivers/spi/octeon_spi.c
@@ -93,7 +93,7 @@ static u64 octeon_spi_set_mpicfg(struct udevice *dev)
if (max_speed > OCTEON_SPI_MAX_CLOCK_HZ)
max_speed = OCTEON_SPI_MAX_CLOCK_HZ;
- debug("\n slave params %d %d %d\n", slave->cs,
+ debug("\n slave params %d %d %d\n", slave->cs[0],
slave->max_hz, slave->mode);
cpha = !!(slave->mode & SPI_CPHA);
cpol = !!(slave->mode & SPI_CPOL);
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index 3d82fc7..35bd876 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -393,7 +393,7 @@ static int omap3_spi_claim_bus(struct udevice *dev)
struct omap3_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- priv->cs = slave_plat->cs;
+ priv->cs = slave_plat->cs[0];
if (!priv->freq)
priv->freq = slave_plat->max_hz;
@@ -422,7 +422,7 @@ static int omap3_spi_set_wordlen(struct udevice *dev, unsigned int wordlen)
struct omap3_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- priv->cs = slave_plat->cs;
+ priv->cs = slave_plat->cs[0];
priv->wordlen = wordlen;
_omap3_spi_set_wordlen(priv);
diff --git a/drivers/spi/pic32_spi.c b/drivers/spi/pic32_spi.c
index e11ae7f..c4b31dc 100644
--- a/drivers/spi/pic32_spi.c
+++ b/drivers/spi/pic32_spi.c
@@ -247,7 +247,7 @@ static int pic32_spi_xfer(struct udevice *slave, unsigned int bitlen,
slave_plat = dev_get_parent_plat(slave);
debug("spi_xfer: bus:%i cs:%i flags:%lx\n",
- dev_seq(bus), slave_plat->cs, flags);
+ dev_seq(bus), slave_plat->cs[0], flags);
debug("msg tx %p, rx %p submitted of %d byte(s)\n",
tx_buf, rx_buf, len);
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c
index 4571dc9..2c3d70b 100644
--- a/drivers/spi/rk_spi.c
+++ b/drivers/spi/rk_spi.c
@@ -444,7 +444,7 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* Assert CS before transfer */
if (flags & SPI_XFER_BEGIN)
- spi_cs_activate(dev, slave_plat->cs);
+ spi_cs_activate(dev, slave_plat->cs[0]);
/*
* To ensure fast loading of firmware images (e.g. full U-Boot
@@ -507,7 +507,7 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* Deassert CS after transfer */
if (flags & SPI_XFER_END)
- spi_cs_deactivate(dev, slave_plat->cs);
+ spi_cs_deactivate(dev, slave_plat->cs[0]);
rkspi_enable_chip(regs, false);
if (!out)
diff --git a/drivers/spi/rockchip_sfc.c b/drivers/spi/rockchip_sfc.c
index 596c22a..71e9b70 100644
--- a/drivers/spi/rockchip_sfc.c
+++ b/drivers/spi/rockchip_sfc.c
@@ -409,7 +409,7 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
/* set the Controller */
ctrl |= SFC_CTRL_PHASE_SEL_NEGETIVE;
- cmd |= plat->cs << SFC_CMD_CS_SHIFT;
+ cmd |= plat->cs[0] << SFC_CMD_CS_SHIFT;
dev_dbg(sfc->dev, "sfc addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n",
op->addr.nbytes, op->addr.buswidth,
diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index d91d58d..4b468da 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -192,7 +192,7 @@ static u32 ast2400_get_clk_setting(struct udevice *dev, uint max_hz)
if (found) {
hclk_div = hclk_masks[i] << 8;
- priv->flashes[slave_plat->cs].max_freq = hclk_clk / (i + 1);
+ priv->flashes[slave_plat->cs[0]].max_freq = hclk_clk / (i + 1);
}
dev_dbg(dev, "found: %s, hclk: %d, max_clk: %d\n", found ? "yes" : "no",
@@ -200,7 +200,7 @@ static u32 ast2400_get_clk_setting(struct udevice *dev, uint max_hz)
if (found) {
dev_dbg(dev, "h_div: %d (mask %x), speed: %d\n",
- i + 1, hclk_masks[i], priv->flashes[slave_plat->cs].max_freq);
+ i + 1, hclk_masks[i], priv->flashes[slave_plat->cs[0]].max_freq);
}
return hclk_div;
@@ -311,7 +311,7 @@ static u32 ast2500_get_clk_setting(struct udevice *dev, uint max_hz)
for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) {
if (hclk_clk / (i + 1) <= max_hz) {
found = true;
- priv->flashes[slave_plat->cs].max_freq =
+ priv->flashes[slave_plat->cs[0]].max_freq =
hclk_clk / (i + 1);
break;
}
@@ -325,7 +325,7 @@ static u32 ast2500_get_clk_setting(struct udevice *dev, uint max_hz)
for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) {
if (hclk_clk / ((i + 1) * 4) <= max_hz) {
found = true;
- priv->flashes[slave_plat->cs].max_freq =
+ priv->flashes[slave_plat->cs[0]].max_freq =
hclk_clk / ((i + 1) * 4);
break;
}
@@ -340,7 +340,7 @@ end:
if (found) {
dev_dbg(dev, "h_div: %d (mask %x), speed: %d\n",
- i + 1, hclk_masks[i], priv->flashes[slave_plat->cs].max_freq);
+ i + 1, hclk_masks[i], priv->flashes[slave_plat->cs[0]].max_freq);
}
return hclk_div;
@@ -456,7 +456,7 @@ static u32 ast2600_get_clk_setting(struct udevice *dev, uint max_hz)
if (found) {
hclk_div = ((j << 24) | hclk_masks[i] << 8);
- priv->flashes[slave_plat->cs].max_freq =
+ priv->flashes[slave_plat->cs[0]].max_freq =
hclk_clk / (i + 1 + j * 16);
break;
}
@@ -467,7 +467,7 @@ static u32 ast2600_get_clk_setting(struct udevice *dev, uint max_hz)
if (found) {
dev_dbg(dev, "base_clk: %d, h_div: %d (mask %x), speed: %d\n",
- j, i + 1, hclk_masks[i], priv->flashes[slave_plat->cs].max_freq);
+ j, i + 1, hclk_masks[i], priv->flashes[slave_plat->cs[0]].max_freq);
}
return hclk_div;
@@ -588,7 +588,7 @@ static int aspeed_spi_exec_op_user_mode(struct spi_slave *slave,
struct udevice *bus = dev->parent;
struct aspeed_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(slave->dev);
- u32 cs = slave_plat->cs;
+ u32 cs = slave_plat->cs[0];
u32 ce_ctrl_reg = (u32)&priv->regs->ce_ctrl[cs];
u32 ce_ctrl_val;
struct aspeed_spi_flash *flash = &priv->flashes[cs];
@@ -668,7 +668,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
const struct aspeed_spi_info *info = priv->info;
struct spi_mem_op op_tmpl = desc->info.op_tmpl;
u32 i;
- u32 cs = slave_plat->cs;
+ u32 cs = slave_plat->cs[0];
u32 cmd_io_conf;
u32 ce_ctrl_reg;
@@ -725,7 +725,7 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,
struct udevice *dev = desc->slave->dev;
struct aspeed_spi_priv *priv = dev_get_priv(dev->parent);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- u32 cs = slave_plat->cs;
+ u32 cs = slave_plat->cs[0];
int ret;
dev_dbg(dev, "read op:0x%x, addr:0x%llx, len:0x%x\n",
@@ -750,7 +750,7 @@ static struct aspeed_spi_flash *aspeed_spi_get_flash(struct udevice *dev)
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
struct aspeed_spi_plat *plat = dev_get_plat(bus);
struct aspeed_spi_priv *priv = dev_get_priv(bus);
- u32 cs = slave_plat->cs;
+ u32 cs = slave_plat->cs[0];
if (cs >= plat->max_cs) {
dev_err(dev, "invalid CS %u\n", cs);
@@ -1069,10 +1069,10 @@ static int aspeed_spi_claim_bus(struct udevice *dev)
struct udevice *bus = dev->parent;
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
struct aspeed_spi_priv *priv = dev_get_priv(dev->parent);
- struct aspeed_spi_flash *flash = &priv->flashes[slave_plat->cs];
+ struct aspeed_spi_flash *flash = &priv->flashes[slave_plat->cs[0]];
u32 clk_setting;
- dev_dbg(bus, "%s: claim bus CS%u\n", bus->name, slave_plat->cs);
+ dev_dbg(bus, "%s: claim bus CS%u\n", bus->name, slave_plat->cs[0]);
if (flash->max_freq == 0) {
clk_setting = priv->info->get_clk_setting(dev, slave_plat->max_hz);
@@ -1090,7 +1090,7 @@ static int aspeed_spi_release_bus(struct udevice *dev)
struct udevice *bus = dev->parent;
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- dev_dbg(bus, "%s: release bus CS%u\n", bus->name, slave_plat->cs);
+ dev_dbg(bus, "%s: release bus CS%u\n", bus->name, slave_plat->cs[0]);
if (!aspeed_spi_get_flash(dev))
return -ENODEV;
diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index b98bcd9..3835865 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -366,8 +366,8 @@ static int mxic_spi_mem_exec_op(struct spi_slave *slave,
nio = 2;
writel(HC_CFG_NIO(nio) |
- HC_CFG_TYPE(slave_plat->cs, HC_CFG_TYPE_SPI_NOR) |
- HC_CFG_SLV_ACT(slave_plat->cs) | HC_CFG_IDLE_SIO_LVL(1) |
+ HC_CFG_TYPE(slave_plat->cs[0], HC_CFG_TYPE_SPI_NOR) |
+ HC_CFG_SLV_ACT(slave_plat->cs[0]) | HC_CFG_IDLE_SIO_LVL(1) |
HC_CFG_MAN_CS_EN,
priv->regs + HC_CFG);
writel(HC_EN_BIT, priv->regs + HC_EN);
@@ -396,7 +396,7 @@ static int mxic_spi_mem_exec_op(struct spi_slave *slave,
ss_ctrl |= OP_READ;
}
- writel(ss_ctrl, priv->regs + SS_CTRL(slave_plat->cs));
+ writel(ss_ctrl, priv->regs + SS_CTRL(slave_plat->cs[0]));
writel(readl(priv->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT,
priv->regs + HC_CFG);
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 836c550..dc001e6 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -718,7 +718,7 @@ static int qup_spi_xfer(struct udevice *dev, unsigned int bitlen,
if (ret != 0)
return ret;
- ret = qup_spi_set_cs(bus, slave_plat->cs, false);
+ ret = qup_spi_set_cs(bus, slave_plat->cs[0], false);
if (ret != 0)
return ret;
}
@@ -736,7 +736,7 @@ static int qup_spi_xfer(struct udevice *dev, unsigned int bitlen,
}
if (flags & SPI_XFER_END) {
- ret = qup_spi_set_cs(bus, slave_plat->cs, true);
+ ret = qup_spi_set_cs(bus, slave_plat->cs[0], true);
if (ret != 0)
return ret;
}
diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
index 0c8666c..15407d4 100644
--- a/drivers/spi/spi-sifive.c
+++ b/drivers/spi/spi-sifive.c
@@ -108,13 +108,13 @@ static void sifive_spi_prep_device(struct sifive_spi *spi,
{
/* Update the chip select polarity */
if (slave_plat->mode & SPI_CS_HIGH)
- spi->cs_inactive &= ~BIT(slave_plat->cs);
+ spi->cs_inactive &= ~BIT(slave_plat->cs[0]);
else
- spi->cs_inactive |= BIT(slave_plat->cs);
+ spi->cs_inactive |= BIT(slave_plat->cs[0]);
writel(spi->cs_inactive, spi->regs + SIFIVE_SPI_REG_CSDEF);
/* Select the correct device */
- writel(slave_plat->cs, spi->regs + SIFIVE_SPI_REG_CSID);
+ writel(slave_plat->cs[0], spi->regs + SIFIVE_SPI_REG_CSID);
}
static int sifive_spi_set_cs(struct sifive_spi *spi,
diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c
index fc82791..364ba4b 100644
--- a/drivers/spi/spi-sn-f-ospi.c
+++ b/drivers/spi/spi-sn-f-ospi.c
@@ -497,7 +497,7 @@ static int f_ospi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
int err = 0;
slave_plat = dev_get_parent_plat(slave->dev);
- ospi->chip_select = slave_plat->cs;
+ ospi->chip_select = slave_plat->cs[0];
switch (op->data.dir) {
case SPI_MEM_DATA_IN:
diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c
index 13725ee..9be4a1e 100644
--- a/drivers/spi/spi-sunxi.c
+++ b/drivers/spi/spi-sunxi.c
@@ -352,7 +352,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
}
if (flags & SPI_XFER_BEGIN)
- sun4i_spi_set_cs(bus, slave_plat->cs, true);
+ sun4i_spi_set_cs(bus, slave_plat->cs[0], true);
/* Reset FIFOs */
setbits_le32(SPI_REG(priv, SPI_FCR), SPI_BIT(priv, SPI_FCR_RF_RST) |
@@ -383,7 +383,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
false, SUN4I_SPI_TIMEOUT_MS, false);
if (ret < 0) {
printf("ERROR: sun4i_spi: Timeout transferring data\n");
- sun4i_spi_set_cs(bus, slave_plat->cs, false);
+ sun4i_spi_set_cs(bus, slave_plat->cs[0], false);
return ret;
}
@@ -394,7 +394,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
}
if (flags & SPI_XFER_END)
- sun4i_spi_set_cs(bus, slave_plat->cs, false);
+ sun4i_spi_set_cs(bus, slave_plat->cs[0], false);
return 0;
}
diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c
index eb522fd..a3c0ad1 100644
--- a/drivers/spi/spi-synquacer.c
+++ b/drivers/spi/spi-synquacer.c
@@ -193,12 +193,12 @@ static void synquacer_spi_config(struct udevice *dev, void *rx, const void *tx)
/* if nothing to do */
if (slave_plat->mode == priv->mode &&
rwflag == priv->rwflag &&
- slave_plat->cs == priv->cs &&
+ slave_plat->cs[0] == priv->cs &&
slave_plat->max_hz == priv->speed)
return;
priv->rwflag = rwflag;
- priv->cs = slave_plat->cs;
+ priv->cs = slave_plat->cs[0];
priv->mode = slave_plat->mode;
priv->speed = slave_plat->max_hz;
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 6e28172..bf987ea 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -224,7 +224,7 @@ int spi_chip_select(struct udevice *dev)
{
struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev);
- return plat ? plat->cs : -ENOENT;
+ return plat ? plat->cs[0] : -ENOENT;
}
int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp)
@@ -261,8 +261,8 @@ int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp)
struct dm_spi_slave_plat *plat;
plat = dev_get_parent_plat(dev);
- dev_dbg(bus, "%s: plat=%p, cs=%d\n", __func__, plat, plat->cs);
- if (plat->cs == cs) {
+ dev_dbg(bus, "%s: plat=%p, cs=%d\n", __func__, plat, plat->cs[0]);
+ if (plat->cs[0] == cs) {
*devp = dev;
return 0;
}
@@ -415,7 +415,7 @@ int _spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
return ret;
}
plat = dev_get_parent_plat(dev);
- plat->cs = cs;
+ plat->cs[0] = cs;
if (speed) {
plat->max_hz = speed;
} else {
@@ -446,6 +446,12 @@ int _spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
slave = dev_get_parent_priv(dev);
bus_data = dev_get_uclass_priv(bus);
+#if CONFIG_IS_ENABLED(SPI_ADVANCE)
+ if ((dev_read_bool(dev, "parallel-memories")) && !slave->multi_cs_cap) {
+ dev_err(dev, "controller doesn't support multi CS\n");
+ return -EINVAL;
+ }
+#endif
/*
* In case the operation speed is not yet established by
* dm_spi_claim_bus() ensure the bus is configured properly.
@@ -508,8 +514,26 @@ int spi_slave_of_to_plat(struct udevice *dev, struct dm_spi_slave_plat *plat)
{
int mode = 0;
int value;
+ int ret;
+
+ ret = dev_read_u32_array(dev, "reg", plat->cs, SPI_CS_CNT_MAX);
+
+ if (IS_ENABLED(CONFIG_SPL_BUILD)) {
+ if (ret == -FDT_ERR_BADLAYOUT) {
+ dev_read_u32(dev, "reg", &plat->cs[0]);
+ } else {
+ dev_err(dev, "has no valid 'reg' property (%d)\n", ret);
+ return ret;
+ }
+ } else {
+ if (ret == -EOVERFLOW) {
+ dev_read_u32(dev, "reg", &plat->cs[0]);
+ } else if (ret) {
+ dev_err(dev, "has no valid 'reg' property (%d)\n", ret);
+ return ret;
+ }
+ }
- plat->cs = dev_read_u32_default(dev, "reg", -1);
plat->max_hz = dev_read_u32_default(dev, "spi-max-frequency",
SPI_DEFAULT_SPEED_HZ);
if (dev_read_bool(dev, "spi-cpol"))
diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c
index 2812a4d..3216ec8 100644
--- a/drivers/spi/stm32_qspi.c
+++ b/drivers/spi/stm32_qspi.c
@@ -394,7 +394,7 @@ static int stm32_qspi_claim_bus(struct udevice *dev)
{
struct stm32_qspi_priv *priv = dev_get_priv(dev->parent);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- int slave_cs = slave_plat->cs;
+ int slave_cs = slave_plat->cs[0];
if (slave_cs >= STM32_QSPI_MAX_CHIP)
return -ENODEV;
diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c
index 97b83b1..a1f31cf 100644
--- a/drivers/spi/stm32_spi.c
+++ b/drivers/spi/stm32_spi.c
@@ -434,7 +434,7 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen,
slave_plat = dev_get_parent_plat(slave);
if (flags & SPI_XFER_BEGIN)
- stm32_spi_set_cs(bus, slave_plat->cs, false);
+ stm32_spi_set_cs(bus, slave_plat->cs[0], false);
/* Be sure to have data in fifo before starting data transfer */
if (priv->tx_buf)
@@ -485,7 +485,7 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen,
stm32_spi_stopxfer(bus);
if (flags & SPI_XFER_END)
- stm32_spi_set_cs(bus, slave_plat->cs, true);
+ stm32_spi_set_cs(bus, slave_plat->cs[0], true);
return xfer_status;
}
diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c
index a16412e..1f2494e 100644
--- a/drivers/spi/ti_qspi.c
+++ b/drivers/spi/ti_qspi.c
@@ -163,7 +163,7 @@ static int ti_qspi_xfer(struct udevice *dev, unsigned int bitlen,
uchar *rxp = din;
uint status;
int timeout;
- unsigned int cs = slave->cs;
+ unsigned int cs = slave->cs[0];
bus = dev->parent;
priv = dev_get_priv(bus);
@@ -344,7 +344,7 @@ static int ti_qspi_exec_mem_op(struct spi_slave *slave,
if (from + op->data.nbytes > priv->mmap_size)
return -ENOTSUPP;
- ti_qspi_setup_mmap_read(priv, slave_plat->cs, op->cmd.opcode,
+ ti_qspi_setup_mmap_read(priv, slave_plat->cs[0], op->cmd.opcode,
op->data.buswidth, op->addr.nbytes,
op->dummy.nbytes);
@@ -363,7 +363,7 @@ static int ti_qspi_claim_bus(struct udevice *dev)
bus = dev->parent;
priv = dev_get_priv(bus);
- if (slave_plat->cs > priv->num_cs) {
+ if (slave_plat->cs[0] > priv->num_cs) {
debug("invalid qspi chip select\n");
return -EINVAL;
}
@@ -371,13 +371,13 @@ static int ti_qspi_claim_bus(struct udevice *dev)
writel(MM_SWITCH, &priv->base->memswitch);
if (priv->ctrl_mod_mmap)
ti_qspi_ctrl_mode_mmap(priv->ctrl_mod_mmap,
- slave_plat->cs, true);
+ slave_plat->cs[0], true);
writel(priv->dc, &priv->base->dc);
writel(0, &priv->base->cmd);
writel(0, &priv->base->data);
- priv->dc <<= slave_plat->cs * 8;
+ priv->dc <<= slave_plat->cs[0] * 8;
writel(priv->dc, &priv->base->dc);
return 0;
@@ -395,12 +395,12 @@ static int ti_qspi_release_bus(struct udevice *dev)
writel(~MM_SWITCH, &priv->base->memswitch);
if (priv->ctrl_mod_mmap)
ti_qspi_ctrl_mode_mmap(priv->ctrl_mod_mmap,
- slave_plat->cs, false);
+ slave_plat->cs[0], false);
writel(0, &priv->base->dc);
writel(0, &priv->base->cmd);
writel(0, &priv->base->data);
- writel(0, TI_QSPI_SETUP_REG(priv, slave_plat->cs));
+ writel(0, TI_QSPI_SETUP_REG(priv, slave_plat->cs[0]));
return 0;
}
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 0e7fa3a..b2af17e 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -291,7 +291,7 @@ static void xilinx_spi_startup_block(struct udevice *dev)
* Perform a dummy read as a work around for
* the startup block issue.
*/
- spi_cs_activate(dev, slave_plat->cs);
+ spi_cs_activate(dev, slave_plat->cs[0]);
txp = 0x9f;
start_transfer(dev, (void *)&txp, NULL, 1);
@@ -306,7 +306,7 @@ static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
int ret;
- spi_cs_activate(dev, slave_plat->cs);
+ spi_cs_activate(dev, slave_plat->cs[0]);
ret = start_transfer(dev, dout, din, bitlen / 8);
spi_cs_deactivate(dev);
return ret;
@@ -331,7 +331,7 @@ static int xilinx_spi_mem_exec_op(struct spi_slave *spi,
startup++;
}
- spi_cs_activate(spi->dev, slave_plat->cs);
+ spi_cs_activate(spi->dev, slave_plat->cs[0]);
if (op->cmd.opcode) {
ret = start_transfer(spi->dev, (void *)&op->cmd.opcode,
diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c
index b71b9a6..281a367 100644
--- a/drivers/spi/zynq_qspi.c
+++ b/drivers/spi/zynq_qspi.c
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * (C) Copyright 2013 Xilinx, Inc.
+ * (C) Copyright 2013 - 2022, Xilinx, Inc.
* (C) Copyright 2015 Jagan Teki <jteki@openedev.com>
+ * (C) Copyright 2023, Advanced Micro Devices, Inc.
*
* Xilinx Zynq Quad-SPI(QSPI) controller driver (master mode only)
*/
@@ -12,10 +13,12 @@
#include <log.h>
#include <malloc.h>
#include <spi.h>
+#include <spi_flash.h>
#include <asm/global_data.h>
#include <asm/io.h>
#include <linux/bitops.h>
#include <spi-mem.h>
+#include "../mtd/spi/sf_internal.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -41,6 +44,21 @@ DECLARE_GLOBAL_DATA_PTR;
#define ZYNQ_QSPI_TXD_00_01_OFFSET 0x80 /* Transmit 1-byte inst */
#define ZYNQ_QSPI_TXD_00_10_OFFSET 0x84 /* Transmit 2-byte inst */
#define ZYNQ_QSPI_TXD_00_11_OFFSET 0x88 /* Transmit 3-byte inst */
+#define ZYNQ_QSPI_FR_QOUT_CODE 0x6B /* read instruction code */
+
+#define QSPI_SELECT_LOWER_CS BIT(0)
+#define QSPI_SELECT_UPPER_CS BIT(1)
+
+/*
+ * QSPI Linear Configuration Register
+ *
+ * It is named Linear Configuration but it controls other modes when not in
+ * linear mode also.
+ */
+#define ZYNQ_QSPI_LCFG_TWO_MEM_MASK 0x40000000 /* QSPI Enable Bit Mask */
+#define ZYNQ_QSPI_LCFG_SEP_BUS_MASK 0x20000000 /* QSPI Enable Bit Mask */
+#define ZYNQ_QSPI_LCFG_U_PAGE 0x10000000 /* QSPI Upper memory set */
+#define ZYNQ_QSPI_LCFG_DUMMY_SHIFT 8
#define ZYNQ_QSPI_TXFIFO_THRESHOLD 1 /* Tx FIFO threshold level*/
#define ZYNQ_QSPI_RXFIFO_THRESHOLD 32 /* Rx FIFO threshold level */
@@ -100,7 +118,11 @@ struct zynq_qspi_priv {
int bytes_to_transfer;
int bytes_to_receive;
unsigned int is_inst;
+ unsigned int is_parallel;
+ unsigned int is_stacked;
+ unsigned int u_page;
unsigned cs_change:1;
+ unsigned is_strip:1;
};
static int zynq_qspi_of_to_plat(struct udevice *bus)
@@ -111,7 +133,6 @@ static int zynq_qspi_of_to_plat(struct udevice *bus)
plat->regs = (struct zynq_qspi_regs *)fdtdec_get_addr(blob,
node, "reg");
-
return 0;
}
@@ -146,6 +167,9 @@ static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv)
/* Disable Interrupts */
writel(ZYNQ_QSPI_IXR_ALL_MASK, &regs->idr);
+ /* Disable linear mode as the boot loader may have used it */
+ writel(0x0, &regs->lqspicfg);
+
/* Clear the TX and RX threshold reg */
writel(ZYNQ_QSPI_TXFIFO_THRESHOLD, &regs->txftr);
writel(ZYNQ_QSPI_RXFIFO_THRESHOLD, &regs->rxftr);
@@ -163,12 +187,11 @@ static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv)
confr |= ZYNQ_QSPI_CR_IFMODE_MASK | ZYNQ_QSPI_CR_MCS_MASK |
ZYNQ_QSPI_CR_PCS_MASK | ZYNQ_QSPI_CR_FW_MASK |
ZYNQ_QSPI_CR_MSTREN_MASK;
- writel(confr, &regs->cr);
- /* Disable the LQSPI feature */
- confr = readl(&regs->lqspicfg);
- confr &= ~ZYNQ_QSPI_LQSPICFG_LQMODE_MASK;
- writel(confr, &regs->lqspicfg);
+ if (priv->is_stacked)
+ confr |= 0x10;
+
+ writel(confr, &regs->cr);
/* Enable SPI */
writel(ZYNQ_QSPI_ENR_SPI_EN_MASK, &regs->enr);
@@ -180,6 +203,7 @@ static int zynq_qspi_child_pre_probe(struct udevice *bus)
struct zynq_qspi_priv *priv = dev_get_priv(bus->parent);
priv->max_hz = slave->max_hz;
+ slave->multi_cs_cap = true;
return 0;
}
@@ -362,8 +386,8 @@ static void zynq_qspi_fill_tx_fifo(struct zynq_qspi_priv *priv, u32 size)
unsigned len, offset;
struct zynq_qspi_regs *regs = priv->regs;
static const unsigned offsets[4] = {
- ZYNQ_QSPI_TXD_00_00_OFFSET, ZYNQ_QSPI_TXD_00_01_OFFSET,
- ZYNQ_QSPI_TXD_00_10_OFFSET, ZYNQ_QSPI_TXD_00_11_OFFSET };
+ ZYNQ_QSPI_TXD_00_01_OFFSET, ZYNQ_QSPI_TXD_00_10_OFFSET,
+ ZYNQ_QSPI_TXD_00_11_OFFSET, ZYNQ_QSPI_TXD_00_00_OFFSET };
while ((fifocount < size) &&
(priv->bytes_to_transfer > 0)) {
@@ -385,7 +409,11 @@ static void zynq_qspi_fill_tx_fifo(struct zynq_qspi_priv *priv, u32 size)
return;
len = priv->bytes_to_transfer;
zynq_qspi_write_data(priv, &data, len);
- offset = (priv->rx_buf) ? offsets[0] : offsets[len];
+ if ((priv->is_parallel || priv->is_stacked) &&
+ !priv->is_inst && (len % 2))
+ len++;
+ offset = (priv->rx_buf) ?
+ offsets[3] : offsets[len - 1];
writel(data, &regs->cr + (offset / 4));
}
}
@@ -490,6 +518,7 @@ static int zynq_qspi_irq_poll(struct zynq_qspi_priv *priv)
*/
static int zynq_qspi_start_transfer(struct zynq_qspi_priv *priv)
{
+ static u8 current_u_page;
u32 data = 0;
struct zynq_qspi_regs *regs = priv->regs;
@@ -499,6 +528,34 @@ static int zynq_qspi_start_transfer(struct zynq_qspi_priv *priv)
priv->bytes_to_transfer = priv->len;
priv->bytes_to_receive = priv->len;
+ if (priv->is_parallel)
+ writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ ZYNQ_QSPI_LCFG_SEP_BUS_MASK |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FR_QOUT_CODE), &regs->lqspicfg);
+
+ if (priv->is_inst && priv->is_stacked && current_u_page != priv->u_page) {
+ if (priv->u_page) {
+ /* Configure two memories on shared bus
+ * by enabling upper mem
+ */
+ writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ ZYNQ_QSPI_LCFG_U_PAGE |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FR_QOUT_CODE),
+ &regs->lqspicfg);
+ } else {
+ /* Configure two memories on shared bus
+ * by enabling lower mem
+ */
+ writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FR_QOUT_CODE),
+ &regs->lqspicfg);
+ }
+ current_u_page = priv->u_page;
+ }
+
if (priv->len < 4)
zynq_qspi_fill_tx_fifo(priv, priv->len);
else
@@ -585,20 +642,21 @@ static int zynq_qspi_xfer(struct udevice *dev, unsigned int bitlen,
struct zynq_qspi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- priv->cs = slave_plat->cs;
+ priv->cs = slave_plat->cs[0];
priv->tx_buf = dout;
priv->rx_buf = din;
priv->len = bitlen / 8;
- debug("zynq_qspi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx\n",
- dev_seq(bus), slave_plat->cs, bitlen, priv->len, flags);
+ debug("%s: bus:%i cs[0]:%i bitlen:%i len:%i flags:%lx\n", __func__,
+ dev_seq(bus), slave_plat->cs[0], bitlen, priv->len, flags);
/*
* Festering sore.
* Assume that the beginning of a transfer with bits to
* transmit must contain a device command.
*/
- if (dout && flags & SPI_XFER_BEGIN)
+ if ((dout && flags & SPI_XFER_BEGIN) ||
+ (flags & SPI_XFER_END && !priv->is_strip))
priv->is_inst = 1;
else
priv->is_inst = 0;
@@ -608,6 +666,11 @@ static int zynq_qspi_xfer(struct udevice *dev, unsigned int bitlen,
else
priv->cs_change = 0;
+ if (flags & SPI_XFER_U_PAGE)
+ priv->u_page = 1;
+ else
+ priv->u_page = 0;
+
zynq_qspi_transfer(priv);
return 0;
@@ -671,14 +734,34 @@ static int zynq_qspi_set_mode(struct udevice *bus, uint mode)
return 0;
}
+bool update_stripe(const struct spi_mem_op *op)
+{
+ if (op->cmd.opcode == SPINOR_OP_BE_4K ||
+ op->cmd.opcode == SPINOR_OP_CHIP_ERASE ||
+ op->cmd.opcode == SPINOR_OP_SE ||
+ op->cmd.opcode == SPINOR_OP_WREAR
+ )
+ return false;
+
+ return true;
+}
+
static int zynq_qspi_exec_op(struct spi_slave *slave,
const struct spi_mem_op *op)
{
+ struct udevice *bus = slave->dev->parent;
+ struct zynq_qspi_priv *priv = dev_get_priv(bus);
int op_len, pos = 0, ret, i;
unsigned int flag = 0;
const u8 *tx_buf = NULL;
u8 *rx_buf = NULL;
+ if ((slave->flags & QSPI_SELECT_LOWER_CS) &&
+ (slave->flags & QSPI_SELECT_UPPER_CS))
+ priv->is_parallel = true;
+ if (slave->flags & SPI_XFER_STACKED)
+ priv->is_stacked = true;
+
if (op->data.nbytes) {
if (op->data.dir == SPI_MEM_DATA_IN)
rx_buf = op->data.buf.in;
@@ -703,6 +786,9 @@ static int zynq_qspi_exec_op(struct spi_slave *slave,
if (op->dummy.nbytes)
memset(op_buf + pos, 0xff, op->dummy.nbytes);
+ if (slave->flags & SPI_XFER_U_PAGE)
+ flag |= SPI_XFER_U_PAGE;
+
/* 1st transfer: opcode + address + dummy cycles */
/* Make sure to set END bit if no tx or rx data messages follow */
if (!tx_buf && !rx_buf)
@@ -713,6 +799,8 @@ static int zynq_qspi_exec_op(struct spi_slave *slave,
if (ret)
return ret;
+ priv->is_strip = update_stripe(op);
+
/* 2nd transfer: rx or tx data path */
if (tx_buf || rx_buf) {
ret = zynq_qspi_xfer(slave->dev, op->data.nbytes * 8, tx_buf,
@@ -721,6 +809,9 @@ static int zynq_qspi_exec_op(struct spi_slave *slave,
return ret;
}
+ priv->is_parallel = false;
+ priv->is_stacked = false;
+ slave->flags &= ~SPI_XFER_MASK;
spi_release_bus(slave);
return 0;
diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c
index ebcb5b6..53b59ae 100644
--- a/drivers/spi/zynq_spi.c
+++ b/drivers/spi/zynq_spi.c
@@ -241,15 +241,15 @@ static int zynq_spi_xfer(struct udevice *dev, unsigned int bitlen,
u8 *rx_buf = din, buf;
u32 ts, status;
- debug("spi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx\n",
- dev_seq(bus), slave_plat->cs, bitlen, len, flags);
+ debug("spi_xfer: bus:%i cs[0]:%i bitlen:%i len:%i flags:%lx\n",
+ dev_seq(bus), slave_plat->cs[0], bitlen, len, flags);
if (bitlen % 8) {
debug("spi_xfer: Non byte aligned SPI transfer\n");
return -1;
}
- priv->cs = slave_plat->cs;
+ priv->cs = slave_plat->cs[0];
if (flags & SPI_XFER_BEGIN)
spi_cs_activate(dev);
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c
index 61349a4..28eadff 100644
--- a/drivers/spi/zynqmp_gqspi.c
+++ b/drivers/spi/zynqmp_gqspi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * (C) Copyright 2018 Xilinx
- *
+ * (C) Copyright 2013 - 2022, Xilinx, Inc.
+ * (C) Copyright 2023, Advanced Micro Devices, Inc.
* Xilinx ZynqMP Generic Quad-SPI(QSPI) controller driver(master mode only)
*/
@@ -24,6 +24,8 @@
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/sizes.h>
+#include <linux/mtd/spi-nor.h>
+#include "../mtd/spi/sf_internal.h"
#include <zynqmp_firmware.h>
#define GQSPI_GFIFO_STRT_MODE_MASK BIT(29)
@@ -87,6 +89,9 @@
#define SPI_XFER_ON_LOWER 1
#define SPI_XFER_ON_UPPER 2
+#define GQSPI_SELECT_LOWER_CS BIT(0)
+#define GQSPI_SELECT_UPPER_CS BIT(1)
+
#define GQSPI_DMA_ALIGN 0x4
#define GQSPI_MAX_BAUD_RATE_VAL 7
#define GQSPI_DFLT_BAUD_RATE_VAL 2
@@ -182,13 +187,14 @@ struct zynqmp_qspi_priv {
int bytes_to_transfer;
int bytes_to_receive;
const struct spi_mem_op *op;
+ unsigned int is_parallel;
+ unsigned int u_page;
+ unsigned int bus;
+ unsigned int stripe;
+ unsigned int flags;
+ u32 max_hz;
};
-__weak int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value)
-{
- return 0;
-}
-
static int zynqmp_qspi_of_to_plat(struct udevice *bus)
{
struct zynqmp_qspi_plat *plat = dev_get_plat(bus);
@@ -233,8 +239,30 @@ static u32 zynqmp_qspi_bus_select(struct zynqmp_qspi_priv *priv)
{
u32 gqspi_fifo_reg = 0;
- gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS |
- GQSPI_GFIFO_CS_LOWER;
+ if (priv->is_parallel) {
+ if (priv->bus == SPI_XFER_ON_BOTH)
+ gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS |
+ GQSPI_GFIFO_UP_BUS |
+ GQSPI_GFIFO_CS_UPPER |
+ GQSPI_GFIFO_CS_LOWER;
+ else if (priv->bus == SPI_XFER_ON_LOWER)
+ gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS |
+ GQSPI_GFIFO_CS_UPPER |
+ GQSPI_GFIFO_CS_LOWER;
+ else if (priv->bus == SPI_XFER_ON_UPPER)
+ gqspi_fifo_reg = GQSPI_GFIFO_UP_BUS |
+ GQSPI_GFIFO_CS_LOWER |
+ GQSPI_GFIFO_CS_UPPER;
+ else
+ debug("Wrong Bus selection:0x%x\n", priv->bus);
+ } else {
+ if (priv->u_page)
+ gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS |
+ GQSPI_GFIFO_CS_UPPER;
+ else
+ gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS |
+ GQSPI_GFIFO_CS_LOWER;
+ }
return gqspi_fifo_reg;
}
@@ -294,8 +322,15 @@ static void zynqmp_qspi_chipselect(struct zynqmp_qspi_priv *priv, int is_on)
gqspi_fifo_reg |= GQSPI_SPI_MODE_SPI |
GQSPI_IMD_DATA_CS_ASSERT;
} else {
- gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS;
- gqspi_fifo_reg |= GQSPI_IMD_DATA_CS_DEASSERT;
+ if (priv->is_parallel) {
+ gqspi_fifo_reg = GQSPI_GFIFO_UP_BUS |
+ GQSPI_GFIFO_LOW_BUS;
+ } else if (priv->u_page) {
+ gqspi_fifo_reg = GQSPI_GFIFO_UP_BUS;
+ } else {
+ gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS;
+ gqspi_fifo_reg |= GQSPI_IMD_DATA_CS_DEASSERT;
+ }
}
zynqmp_qspi_fill_gen_fifo(priv, gqspi_fifo_reg);
@@ -365,12 +400,13 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed)
log_debug("%s, Speed: %d, Max: %d\n", __func__, speed, plat->frequency);
- if (speed > plat->frequency)
- speed = plat->frequency;
+ /*
+ * If speed == 0 or speed > max freq, then set speed to highest
+ */
+ if (!speed || speed > priv->max_hz)
+ speed = priv->max_hz;
if (plat->speed_hz != speed) {
- /* Set the clock frequency */
- /* If speed == 0, default to lowest speed */
while ((baud_rate_val < 8) &&
((plat->frequency /
(2 << baud_rate_val)) > speed))
@@ -392,6 +428,18 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed)
return 0;
}
+static int zynqmp_qspi_child_pre_probe(struct udevice *bus)
+{
+ struct spi_slave *slave = dev_get_parent_priv(bus);
+ struct zynqmp_qspi_priv *priv = dev_get_priv(bus->parent);
+
+ slave->multi_cs_cap = true;
+ slave->bytemode = SPI_4BYTE_MODE;
+ priv->max_hz = slave->max_hz;
+
+ return 0;
+}
+
static int zynqmp_qspi_probe(struct udevice *bus)
{
struct zynqmp_qspi_plat *plat = dev_get_plat(bus);
@@ -456,12 +504,17 @@ static int zynqmp_qspi_set_mode(struct udevice *bus, uint mode)
static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size)
{
- u32 data;
+ u32 data, ier;
int ret = 0;
struct zynqmp_qspi_regs *regs = priv->regs;
u32 *buf = (u32 *)priv->tx_buf;
u32 len = size;
+ /* Enable interrupts */
+ ier = readl(&regs->ier);
+ ier |= GQSPI_IXR_ALL_MASK | GQSPI_IXR_TXFIFOEMPTY_MASK;
+ writel(ier, &regs->ier);
+
while (size) {
ret = wait_for_bit_le32(&regs->isr, GQSPI_IXR_TXNFULL_MASK, 1,
GQSPI_TIMEOUT, 1);
@@ -584,6 +637,9 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv)
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth);
gen_fifo_cmd |= GQSPI_GFIFO_TX | GQSPI_GFIFO_DATA_XFR_MASK;
+ if (priv->stripe)
+ gen_fifo_cmd |= GQSPI_GFIFO_STRIPE_MASK;
+
while (priv->len) {
len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
@@ -718,6 +774,9 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv)
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth);
gen_fifo_cmd |= GQSPI_GFIFO_RX | GQSPI_GFIFO_DATA_XFR_MASK;
+ if (priv->stripe)
+ gen_fifo_cmd |= GQSPI_GFIFO_STRIPE_MASK;
+
/*
* Check if receive buffer is aligned to 4 byte and length
* is multiples of four byte as we are using dma to receive.
@@ -758,6 +817,33 @@ static int zynqmp_qspi_release_bus(struct udevice *dev)
return 0;
}
+static bool zynqmp_qspi_update_stripe(const struct spi_mem_op *op)
+{
+ /*
+ * This is a list of opcodes for which we must not use striped access
+ * even in dual parallel mode, but instead broadcast the same data to
+ * both chips. This is primarily erase commands and writing some
+ * registers.
+ */
+ switch (op->cmd.opcode) {
+ case SPINOR_OP_BE_4K:
+ case SPINOR_OP_BE_32K:
+ case SPINOR_OP_CHIP_ERASE:
+ case SPINOR_OP_SE:
+ case SPINOR_OP_BE_32K_4B:
+ case SPINOR_OP_SE_4B:
+ case SPINOR_OP_BE_4K_4B:
+ case SPINOR_OP_WRSR:
+ case SPINOR_OP_WREAR:
+ case SPINOR_OP_BRWR:
+ return false;
+ case SPINOR_OP_WRSR2:
+ return op->addr.nbytes != 0;
+ default:
+ return true;
+ }
+}
+
static int zynqmp_qspi_exec_op(struct spi_slave *slave,
const struct spi_mem_op *op)
{
@@ -769,6 +855,25 @@ static int zynqmp_qspi_exec_op(struct spi_slave *slave,
priv->rx_buf = op->data.buf.in;
priv->len = op->data.nbytes;
+ if (slave->flags & SPI_XFER_U_PAGE)
+ priv->u_page = 1;
+ else
+ priv->u_page = 0;
+
+ if ((slave->flags & GQSPI_SELECT_LOWER_CS) &&
+ (slave->flags & GQSPI_SELECT_UPPER_CS))
+ priv->is_parallel = true;
+
+ priv->stripe = 0;
+ priv->bus = 0;
+
+ if (priv->is_parallel) {
+ if (slave->flags & SPI_XFER_MASK)
+ priv->bus = (slave->flags & SPI_XFER_MASK) >> 8;
+ if (zynqmp_qspi_update_stripe(op))
+ priv->stripe = 1;
+ }
+
zynqmp_qspi_chipselect(priv, 1);
/* Send opcode, addr, dummy */
@@ -782,6 +887,9 @@ static int zynqmp_qspi_exec_op(struct spi_slave *slave,
zynqmp_qspi_chipselect(priv, 0);
+ priv->is_parallel = false;
+ slave->flags &= ~SPI_XFER_MASK;
+
return ret;
}
@@ -812,4 +920,5 @@ U_BOOT_DRIVER(zynqmp_qspi) = {
.plat_auto = sizeof(struct zynqmp_qspi_plat),
.priv_auto = sizeof(struct zynqmp_qspi_priv),
.probe = zynqmp_qspi_probe,
+ .child_pre_probe = zynqmp_qspi_child_pre_probe,
};
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index d1dbf3e..b0e9df4 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -13,6 +13,9 @@
#include <linux/mtd/mtd.h>
#include <spi-mem.h>
+/* In parallel configuration enable multiple CS */
+#define SPI_NOR_ENABLE_MULTI_CS (BIT(0) | BIT(1))
+
/*
* Manufacturer IDs
*
@@ -177,6 +180,12 @@
/* Status Register 2 bits. */
#define SR2_QUAD_EN_BIT7 BIT(7)
+/*
+ * Maximum number of flashes that can be connected
+ * in stacked/parallel configuration
+ */
+#define SNOR_FLASH_CNT_MAX 2
+
/* For Cypress flash. */
#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
@@ -294,6 +303,8 @@ enum spi_nor_option_flags {
SNOR_F_BROKEN_RESET = BIT(6),
SNOR_F_SOFT_RESET = BIT(7),
SNOR_F_IO_MODE_EN_VOLATILE = BIT(8),
+ SNOR_F_HAS_STACKED = BIT(9),
+ SNOR_F_HAS_PARALLEL = BIT(10),
};
struct spi_nor;
@@ -551,6 +562,7 @@ 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;
diff --git a/include/spi.h b/include/spi.h
index 7e38cc2..ee0f86f 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -38,6 +38,18 @@
#define SPI_DEFAULT_WORDLEN 8
+#define SPI_3BYTE_MODE 0x0
+#define SPI_4BYTE_MODE 0x1
+
+/* 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)
+
+/* Max no. of CS supported per spi device */
+#define SPI_CS_CNT_MAX 2
+
/**
* struct dm_spi_bus - SPI bus info
*
@@ -71,7 +83,7 @@ struct dm_spi_bus {
* @mode: SPI mode to use for this device (see SPI mode flags)
*/
struct dm_spi_slave_plat {
- unsigned int cs;
+ unsigned int cs[SPI_CS_CNT_MAX];
uint max_hz;
uint mode;
};
@@ -155,6 +167,15 @@ struct spi_slave {
#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_U_PAGE BIT(4)
+#define SPI_XFER_STACKED BIT(5)
+ /*
+ * Flag indicating that the spi-controller has multi chip select
+ * capability and can assert/de-assert more than one chip select
+ * at once.
+ */
+ bool multi_cs_cap;
+ u32 bytemode;
};
/**
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index ed94194..0f3044b 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -728,7 +728,7 @@ static int acpi_device_set_spi(const struct udevice *dev, struct acpi_spi *spi,
plat = dev_get_parent_plat(slave->dev);
memset(spi, '\0', sizeof(*spi));
- spi->device_select = plat->cs;
+ spi->device_select = plat->cs[0];
spi->device_select_polarity = SPI_POLARITY_LOW;
spi->wire_mode = SPI_4_WIRE_MODE;
spi->speed = plat->max_hz;