From c8ca26b888cd04cd7804628b9de6062365c100b3 Mon Sep 17 00:00:00 2001 From: Amit Kumar Mahapatra Date: Thu, 1 Aug 2019 18:52:55 +0530 Subject: [PATCH] mtd: spi-nor: Fixed die crossover issue Read operation in multi die flash devices is bounded by its die segment. In a continuous read, that spans across multiple die, 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 crossover issue. This patch fixes this issue by splitting a read transaction, that spans across multiple banks, into one read per bank. Bank size for single and dual stacked connection is 16MB and for dual parallel connection its 32MB. Signed-off-by: Amit Kumar Mahapatra Reviewed-by: Naga Sureshkumar Relli Signed-off-by: Radhey Shyam Pandey --- drivers/mtd/spi-nor/spi-nor.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) 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);