diff options
author | Rafał Miłecki <rafal@milecki.pl> | 2017-02-09 01:53:44 +0300 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2017-02-09 02:07:59 +0300 |
commit | ccc38234fdc70120be79e7fb2df5c27ca5cd4c8a (patch) | |
tree | 475e969045afe56f802d0fb1205edb662fa536c8 /drivers/mtd/devices/bcm47xxsflash.c | |
parent | 9c8d7ff32a0aa001ac8506180e1662ecdf927f32 (diff) | |
download | linux-ccc38234fdc70120be79e7fb2df5c27ca5cd4c8a.tar.xz |
mtd: bcm47xxsflash: support reading flash out of mapping window
For reading flash content we use MMIO but it's possible to read only
first 16 MiB this way. It's simply an arch design/limitation.
To support flash sizes bigger than 16 MiB implement indirect access
using ChipCommon registers.
This has been tested using MX25L25635F.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Acked-by: Marek Vasut <marek.vasut@gmail.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd/devices/bcm47xxsflash.c')
-rw-r--r-- | drivers/mtd/devices/bcm47xxsflash.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c index 4decd8c0360a..e2bd81817df4 100644 --- a/drivers/mtd/devices/bcm47xxsflash.c +++ b/drivers/mtd/devices/bcm47xxsflash.c @@ -105,15 +105,33 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct bcm47xxsflash *b47s = mtd->priv; + size_t orig_len = len; /* Check address range */ if ((from + len) > mtd->size) return -EINVAL; - memcpy_fromio(buf, b47s->window + from, len); - *retlen = len; + /* Read as much as possible using fast MMIO window */ + if (from < BCM47XXSFLASH_WINDOW_SZ) { + size_t memcpy_len; - return len; + memcpy_len = min(len, (size_t)(BCM47XXSFLASH_WINDOW_SZ - from)); + memcpy_fromio(buf, b47s->window + from, memcpy_len); + from += memcpy_len; + len -= memcpy_len; + buf += memcpy_len; + } + + /* Use indirect access for content out of the window */ + for (; len; len--) { + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++); + bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B); + *buf++ = b47s->cc_read(b47s, BCMA_CC_FLASHDATA); + } + + *retlen = orig_len; + + return orig_len; } static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len, |