@@ -1812,13 +1812,18 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len)
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;
+ struct spi_nor_flash_parameter *params;
+ u32 addr, len, offset, cur_cs_num = 0;
uint32_t rem;
int ret;
+ u64 sz;
dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
(long long)instr->len);
+ params = spi_nor_get_params(nor, 0);
+ sz = params->size;
+
if (spi_nor_has_uniform_erase(nor)) {
div_u64_rem(instr->len, mtd->erasesize, &rem);
if (rem)
@@ -1840,29 +1845,32 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
if (ret)
goto erase_err;
- ret = spi_nor_write_enable(nor);
- if (ret) {
+ while (cur_cs_num < SNOR_FLASH_CNT_MAX && params) {
+ nor->spimem->spi->cs_index_mask = 0x01 << cur_cs_num;
+ ret = spi_nor_write_enable(nor);
+ if (ret) {
+ spi_nor_unlock_device(nor);
+ goto erase_err;
+ }
+ ret = spi_nor_erase_chip(nor);
spi_nor_unlock_device(nor);
- goto erase_err;
- }
-
- ret = spi_nor_erase_chip(nor);
- spi_nor_unlock_device(nor);
- if (ret)
- goto erase_err;
+ if (ret)
+ goto erase_err;
- /*
- * Scale the timeout linearly with the size of the flash, with
- * a minimum calibrated to an old 2MB flash. We could try to
- * pull these from CFI/SFDP, but these values should be good
- * enough for now.
- */
- timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
- CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
- (unsigned long)(mtd->size / SZ_2M));
- ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
- if (ret)
- goto erase_err;
+ /*
+ * Scale the timeout linearly with the size of the flash, with
+ * a minimum calibrated to an old 2MB flash. We could try to
+ * pull these from CFI/SFDP, but these values should be good
+ * enough for now.
+ */
+ timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
+ CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
+ (unsigned long)(params->size / SZ_2M));
+ ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
+ if (ret)
+ goto erase_err;
+ cur_cs_num++;
+ }
/* REVISIT in some cases we could speed up erasing large regions
* by using SPINOR_OP_SE instead of SPINOR_OP_BE_4K. We may have set up
@@ -1871,18 +1879,31 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
/* "sector"-at-a-time erase */
} else if (spi_nor_has_uniform_erase(nor)) {
+ /* Determine the flash from which the operation need to start */
+ while ((cur_cs_num < SNOR_FLASH_CNT_MAX) && (addr > sz - 1) && params) {
+ cur_cs_num++;
+ params = spi_nor_get_params(nor, cur_cs_num);
+ sz += params->size;
+ }
+
while (len) {
ret = spi_nor_lock_device(nor);
if (ret)
goto erase_err;
+ nor->spimem->spi->cs_index_mask = 0x01 << cur_cs_num;
ret = spi_nor_write_enable(nor);
if (ret) {
spi_nor_unlock_device(nor);
goto erase_err;
}
+ offset = addr;
+ if (nor->flags & SNOR_F_HAS_STACKED) {
+ params = spi_nor_get_params(nor, cur_cs_num);
+ offset -= (sz - params->size);
+ }
- ret = spi_nor_erase_sector(nor, addr);
+ ret = spi_nor_erase_sector(nor, offset);
spi_nor_unlock_device(nor);
if (ret)
goto erase_err;
@@ -1893,13 +1914,45 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
addr += mtd->erasesize;
len -= mtd->erasesize;
+
+ /*
+ * Flash cross over condition in stacked mode.
+ */
+ if ((nor->flags & SNOR_F_HAS_STACKED) && (addr > sz - 1)) {
+ cur_cs_num++;
+ params = spi_nor_get_params(nor, cur_cs_num);
+ sz += params->size;
+ }
}
/* erase multiple sectors */
} else {
- ret = spi_nor_erase_multi_sectors(nor, addr, len);
- if (ret)
- goto erase_err;
+ u64 erase_len = 0;
+
+ /* Determine the flash from which the operation need to start */
+ while ((cur_cs_num < SNOR_FLASH_CNT_MAX) && (addr > sz - 1) && params) {
+ cur_cs_num++;
+ params = spi_nor_get_params(nor, cur_cs_num);
+ sz += params->size;
+ }
+ /* perform multi sector erase onec per Flash*/
+ while (len) {
+ erase_len = (len > (sz - addr)) ? (sz - addr) : len;
+ offset = addr;
+ nor->spimem->spi->cs_index_mask = 0x01 << cur_cs_num;
+ if (nor->flags & SNOR_F_HAS_STACKED) {
+ params = spi_nor_get_params(nor, cur_cs_num);
+ offset -= (sz - params->size);
+ }
+ ret = spi_nor_erase_multi_sectors(nor, offset, erase_len);
+ if (ret)
+ goto erase_err;
+ len -= erase_len;
+ addr += erase_len;
+ cur_cs_num++;
+ params = spi_nor_get_params(nor, cur_cs_num);
+ sz += params->size;
+ }
}
ret = spi_nor_write_disable(nor);
@@ -2098,9 +2151,11 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ struct spi_nor_flash_parameter *params;
+ ssize_t ret, read_len, len_lock = len;
loff_t from_lock = from;
- size_t len_lock = len;
- ssize_t ret;
+ u32 cur_cs_num = 0;
+ u64 sz;
dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
@@ -2108,9 +2163,23 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
if (ret)
return ret;
+ params = spi_nor_get_params(nor, 0);
+ sz = params->size;
+
+ /* Determine the flash from which the operation need to start */
+ while ((cur_cs_num < SNOR_FLASH_CNT_MAX) && (from > sz - 1) && params) {
+ cur_cs_num++;
+ params = spi_nor_get_params(nor, cur_cs_num);
+ sz += params->size;
+ }
while (len) {
loff_t addr = from;
+ nor->spimem->spi->cs_index_mask = 0x01 << cur_cs_num;
+ read_len = (len > (sz - addr)) ? (sz - addr) : len;
+ params = spi_nor_get_params(nor, cur_cs_num);
+ addr -= (sz - params->size);
+
addr = spi_nor_convert_addr(nor, addr);
ret = spi_nor_read_data(nor, addr, len, buf);
@@ -2122,11 +2191,22 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
if (ret < 0)
goto read_err;
- WARN_ON(ret > len);
+ WARN_ON(ret > read_len);
*retlen += ret;
buf += ret;
from += ret;
len -= ret;
+
+ /*
+ * Flash cross over condition in stacked mode.
+ *
+ */
+ if ((nor->flags & SNOR_F_HAS_STACKED) && (from > sz - 1)) {
+ cur_cs_num++;
+ params = spi_nor_get_params(nor, cur_cs_num);
+ sz += params->size;
+ }
+
}
ret = 0;
@@ -2147,8 +2227,9 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
struct spi_nor *nor = mtd_to_spi_nor(mtd);
struct spi_nor_flash_parameter *params;
size_t page_offset, page_remain, i;
+ u32 page_size, cur_cs_num = 0;
ssize_t ret;
- u32 page_size;
+ u64 sz;
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
@@ -2158,6 +2239,14 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
params = spi_nor_get_params(nor, 0);
page_size = params->page_size;
+ sz = params->size;
+
+ /* Determine the flash from which the operation need to start */
+ while ((cur_cs_num < SNOR_FLASH_CNT_MAX) && (to > sz - 1) && params) {
+ cur_cs_num++;
+ params = spi_nor_get_params(nor, cur_cs_num);
+ sz += params->size;
+ }
for (i = 0; i < len; ) {
ssize_t written;
@@ -2178,6 +2267,10 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
/* the size of data remaining on the first page */
page_remain = min_t(size_t, page_size - page_offset, len - i);
+ nor->spimem->spi->cs_index_mask = 0x01 << cur_cs_num;
+ params = spi_nor_get_params(nor, cur_cs_num);
+ addr -= (sz - params->size);
+
addr = spi_nor_convert_addr(nor, addr);
ret = spi_nor_lock_device(nor);
@@ -2201,6 +2294,15 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
goto write_err;
*retlen += written;
i += written;
+
+ /*
+ * Flash cross over condition in stacked mode.
+ */
+ if ((nor->flags & SNOR_F_HAS_STACKED) && ((to + i) > sz - 1)) {
+ cur_cs_num++;
+ params = spi_nor_get_params(nor, cur_cs_num);
+ sz += params->size;
+ }
}
write_err:
@@ -2314,8 +2416,6 @@ int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
static int spi_nor_spimem_check_op(struct spi_nor *nor,
struct spi_mem_op *op)
{
- struct spi_nor_flash_parameter *params = spi_nor_get_params(nor, 0);
-
/*
* First test with 4 address bytes. The opcode itself might
* be a 3B addressing opcode but we don't care, because
@@ -2324,7 +2424,7 @@ static int spi_nor_spimem_check_op(struct spi_nor *nor,
*/
op->addr.nbytes = 4;
if (!spi_mem_supports_op(nor->spimem, op)) {
- if (params->size > SZ_16M)
+ if (nor->mtd.size > SZ_16M)
return -EOPNOTSUPP;
/* If flash size <= 16MB, 3 address bytes are sufficient */
@@ -2925,6 +3025,10 @@ static void spi_nor_init_fixup_flags(struct spi_nor *nor)
static void spi_nor_late_init_params(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = spi_nor_get_params(nor, 0);
+ struct device_node *np = spi_nor_get_flash_node(nor);
+ u64 flash_size[SNOR_FLASH_CNT_MAX];
+ u32 idx = 0, i = 0;
+ int rc;
if (nor->manufacturer && nor->manufacturer->fixups &&
nor->manufacturer->fixups->late_init)
@@ -2948,6 +3052,36 @@ static void spi_nor_late_init_params(struct spi_nor *nor)
spi_nor_init_default_locking_ops(nor);
params->bank_size = div64_u64(params->size, nor->info->n_banks);
+ /*
+ * 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 = of_property_read_u64_index(np, "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->flags & SNOR_F_HAS_STACKED) {
+ for (idx = 1; idx < SNOR_FLASH_CNT_MAX; idx++) {
+ params = spi_nor_get_params(nor, idx);
+ params = devm_kzalloc(nor->dev, sizeof(*params), GFP_KERNEL);
+ if (params) {
+ memcpy(params, spi_nor_get_params(nor, 0), sizeof(*params));
+ params->size = flash_size[idx];
+ spi_nor_set_params(nor, idx, params);
+ }
+ }
+ }
}
/**
@@ -3155,16 +3289,30 @@ static int spi_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
*/
static int spi_nor_quad_enable(struct spi_nor *nor)
{
- struct spi_nor_flash_parameter *params = spi_nor_get_params(nor, 0);
+ struct spi_nor_flash_parameter *params;
+ int err, idx;
- if (!params->quad_enable)
- return 0;
+ for (idx = 0; idx < SNOR_FLASH_CNT_MAX; idx++) {
+ params = spi_nor_get_params(nor, idx);
+ if (params) {
+ if (!params->quad_enable)
+ return 0;
- if (!(spi_nor_get_protocol_width(nor->read_proto) == 4 ||
- spi_nor_get_protocol_width(nor->write_proto) == 4))
- return 0;
+ if (!(spi_nor_get_protocol_width(nor->read_proto) == 4 ||
+ spi_nor_get_protocol_width(nor->write_proto) == 4))
+ return 0;
+ /*
+ * Set the appropriate CS index before
+ * issuing the command.
+ */
+ nor->spimem->spi->cs_index_mask = 0x01 << idx;
- return params->quad_enable(nor);
+ err = params->quad_enable(nor);
+ if (err)
+ return err;
+ }
+ }
+ return err;
}
/**
@@ -3196,7 +3344,7 @@ int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
static int spi_nor_init(struct spi_nor *nor)
{
- int err;
+ int err, idx;
err = spi_nor_octal_dtr_enable(nor, true);
if (err) {
@@ -3237,9 +3385,18 @@ static int spi_nor_init(struct spi_nor *nor)
*/
WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
"enabling reset hack; may not recover from unexpected reboots\n");
- err = spi_nor_set_4byte_addr_mode(nor, true);
- if (err)
- return err;
+ for (idx = 0; idx < SNOR_FLASH_CNT_MAX; idx++) {
+ if (spi_nor_get_params(nor, idx)) {
+ /*
+ * Select the appropriate CS index before
+ * issuing the command.
+ */
+ nor->spimem->spi->cs_index_mask = 0x01 << idx;
+ err = spi_nor_set_4byte_addr_mode(nor, true);
+ if (err)
+ return err;
+ }
+ }
}
return 0;
@@ -3354,18 +3511,30 @@ static void spi_nor_put_device(struct mtd_info *mtd)
static void spi_nor_restore(struct spi_nor *nor)
{
int ret;
+ int idx;
/* restore the addressing mode */
if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
nor->flags & SNOR_F_BROKEN_RESET) {
- ret = spi_nor_set_4byte_addr_mode(nor, false);
- if (ret)
- /*
- * Do not stop the execution in the hope that the flash
- * will default to the 3-byte address mode after the
- * software reset.
- */
- dev_err(nor->dev, "Failed to exit 4-byte address mode, err = %d\n", ret);
+ for (idx = 0; idx < SNOR_FLASH_CNT_MAX; idx++) {
+ if (spi_nor_get_params(nor, idx)) {
+ /*
+ * Select the appropriate CS index before
+ * issuing the command.
+ */
+ nor->spimem->spi->cs_index_mask = 1 << idx;
+ ret = spi_nor_set_4byte_addr_mode(nor, false);
+ if (ret)
+ /*
+ * Do not stop the execution in the hope that the flash
+ * will default to the 3-byte address mode after the
+ * software reset.
+ */
+ dev_err(nor->dev,
+ "Failed to exit 4-byte address mode, err = %d\n",
+ ret);
+ }
+ }
}
if (nor->flags & SNOR_F_SOFT_RESET)
@@ -3432,6 +3601,8 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor)
struct spi_nor_flash_parameter *params = spi_nor_get_params(nor, 0);
struct mtd_info *mtd = &nor->mtd;
struct device *dev = nor->dev;
+ u64 total_sz = 0;
+ int idx;
spi_nor_set_mtd_locking_ops(nor);
spi_nor_set_mtd_otp_ops(nor);
@@ -3450,7 +3621,12 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor)
mtd->_erase = spi_nor_erase;
mtd->writesize = params->writesize;
mtd->writebufsize = params->page_size;
- mtd->size = params->size;
+ for (idx = 0; idx < SNOR_FLASH_CNT_MAX; idx++) {
+ params = spi_nor_get_params(nor, idx);
+ if (params)
+ total_sz += params->size;
+ }
+ mtd->size = total_sz;
mtd->_read = spi_nor_read;
/* Might be already set by some SST flashes. */
if (!mtd->_write)
@@ -11,6 +11,9 @@
#define SPI_NOR_MAX_ID_LEN 6
+/* In single configuration enable CS0 */
+#define SPI_NOR_ENABLE_CS0 BIT(0)
+
/* Standard SPI NOR flash operations. */
#define SPI_NOR_READID_OP(naddr, ndummy, buf, len) \
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDID, 0), \
@@ -132,6 +135,7 @@ enum spi_nor_option_flags {
SNOR_F_SWP_IS_VOLATILE = BIT(13),
SNOR_F_RWW = BIT(14),
SNOR_F_ECC = BIT(15),
+ SNOR_F_HAS_STACKED = BIT(16),
};
struct spi_nor_read_command {
@@ -127,6 +127,12 @@
#define SR2_LB3 BIT(5) /* Security Register Lock Bit 3 */
#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
+
/* Supported SPI protocols */
#define SNOR_PROTO_INST_MASK GENMASK(23, 16)
#define SNOR_PROTO_INST_SHIFT 16
@@ -412,7 +418,7 @@ struct spi_nor {
const struct spi_nor_controller_ops *controller_ops;
- struct spi_nor_flash_parameter *params;
+ struct spi_nor_flash_parameter *params[SNOR_FLASH_CNT_MAX];
struct {
struct spi_mem_dirmap_desc *rdesc;
@@ -435,13 +441,13 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
static inline struct spi_nor_flash_parameter *spi_nor_get_params(const struct spi_nor *nor, u8 idx)
{
- return nor->params;
+ return nor->params[idx];
}
static inline void spi_nor_set_params(struct spi_nor *nor, u8 idx,
struct spi_nor_flash_parameter *params)
{
- nor->params = params;
+ nor->params[idx] = params;
}
/**
* spi_nor_scan() - scan the SPI NOR