diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 420d44b4b2e479..8a05f125b0983a 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1719,6 +1719,9 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, u8 bank; u8 is_ofst_odd = 0; loff_t addr = 0; + u8 cur_bank; + u8 nxt_bank; + u32 bank_size; #define OFFSET_16_MB 0x1000000 @@ -1756,10 +1759,36 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, } } - /* Die cross over issue is not handled */ if (nor->addr_width == 4) { - rem_bank_len = (mtd->size >> stack_shift) - - (offset << nor->shift); + /* + * Some flash devices like N25Q512 have multiple dies + * in it. Read operation in these devices is bounded + * by its die segment. In a continuous read, across + * multiple dies, when the last byte of the selected + * die segment is read, the next byte read is the + * first byte of the same die segment. This is Die + * cross over issue. So to handle this issue, split + * a read transaction, that spans across multiple + * banks, into one read per bank. Bank size is 16MB + * for single and dual stacked mode and 32MB for dual + * parallel mode. + */ + if (nor->spi->multi_die) { + bank_size = (OFFSET_16_MB << nor->shift); + cur_bank = offset / bank_size; + nxt_bank = (offset + len) / bank_size; + if (cur_bank != nxt_bank) + rem_bank_len = (bank_size * + (cur_bank + 1)) - + offset; + else + rem_bank_len = (mtd->size >> + stack_shift) - + (offset << nor->shift); + } else { + rem_bank_len = (mtd->size >> stack_shift) - + (offset << nor->shift); + } } if (nor->addr_width == 3) write_ear(nor, offset);