diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-10-15 13:44:23 +1100 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-10-15 14:45:27 +1100 |
commit | 8463764f7e4383e1e2339eee174d4151337bc467 (patch) | |
tree | 56db78dfd6b9a8df3d8045292c631030f22232c7 /libflash | |
parent | a9efc5faa0ef2d8126a8a217a3f9f806071fe1db (diff) | |
download | skiboot-8463764f7e4383e1e2339eee174d4151337bc467.zip skiboot-8463764f7e4383e1e2339eee174d4151337bc467.tar.gz skiboot-8463764f7e4383e1e2339eee174d4151337bc467.tar.bz2 |
libflash: Sync with pflash 0.8.3
Fixes 64MB chip support, improve Macronix settings, add Micron
chip support, etc...
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'libflash')
-rw-r--r-- | libflash/libflash-priv.h | 56 | ||||
-rw-r--r-- | libflash/libflash.c | 75 |
2 files changed, 86 insertions, 45 deletions
diff --git a/libflash/libflash-priv.h b/libflash/libflash-priv.h index 44fa513..c394d4c 100644 --- a/libflash/libflash-priv.h +++ b/libflash/libflash-priv.h @@ -21,21 +21,30 @@ #include <ccan/container_of/container_of.h> /* Flash commands */ -#define CMD_PP 0x02 -#define CMD_READ 0x03 -#define CMD_WRDI 0x04 -#define CMD_RDSR 0x05 -#define CMD_WREN 0x06 -#define CMD_SE 0x20 -#define CMD_RDSCUR 0x2b -#define CMD_BE32K 0x52 -#define CMD_CE 0x60 -#define CMD_RDID 0x9f -#define CMD_EN4B 0xb7 -#define CMD_BE 0xd8 -#define CMD_RDDPB 0xe0 -#define CMD_RDSPB 0xe2 -#define CMD_EX4B 0xe9 +#define CMD_WRSR 0x01 /* Write Status Register (also config. on Macronix) */ +#define CMD_PP 0x02 /* Page Program */ +#define CMD_READ 0x03 /* READ */ +#define CMD_WRDI 0x04 /* Write Disable */ +#define CMD_RDSR 0x05 /* Read Status Register */ +#define CMD_WREN 0x06 /* Write Enable */ +#define CMD_RDCR 0x15 /* Read configuration register (Macronix) */ +#define CMD_SE 0x20 /* Sector (4K) Erase */ +#define CMD_RDSCUR 0x2b /* Read Security Register (Macronix) */ +#define CMD_BE32K 0x52 /* Block (32K) Erase */ +#define CMD_RDSFDP 0x5a /* Read SFDP JEDEC info */ +#define CMD_CE 0x60 /* Chip Erase (Macronix/Winbond) */ +#define CMD_MIC_WREVCONF 0x61 /* Micron Write Enhanced Volatile Config */ +#define CMD_MIC_RDEVCONF 0x65 /* Micron Read Enhanced Volatile Config */ +#define CMD_MIC_RDFLST 0x70 /* Micron Read Flag Status */ +#define CMD_MIC_WRVCONF 0x81 /* Micron Write Volatile Config */ +#define CMD_MIC_RDVCONF 0x85 /* Micron Read Volatile Config */ +#define CMD_RDID 0x9f /* Read JEDEC ID */ +#define CMD_EN4B 0xb7 /* Enable 4B addresses */ +#define CMD_MIC_BULK_ERASE 0xc7 /* Micron Bulk Erase */ +#define CMD_BE 0xd8 /* Block (64K) Erase */ +#define CMD_RDDPB 0xe0 /* Read dynamic protection (Macronix) */ +#define CMD_RDSPB 0xe2 /* Read static protection (Macronix) */ +#define CMD_EX4B 0xe9 /* Exit 4B addresses */ /* Flash status bits */ #define STAT_WIP 0x01 @@ -49,7 +58,9 @@ struct flash_info { #define FL_ERASE_4K 0x00000001 /* Supports 4k erase */ #define FL_ERASE_32K 0x00000002 /* Supports 32k erase */ #define FL_ERASE_64K 0x00000004 /* Supports 64k erase */ -#define FL_ERASE_CHIP 0x00000008 /* Supports 64k erase */ +#define FL_ERASE_CHIP 0x00000008 /* Supports 0x60 cmd chip erase */ +#define FL_ERASE_BULK 0x00000010 /* Supports 0xc7 cmd bulk erase */ +#define FL_MICRON_BUGS 0x00000020 /* Various micron bug workarounds */ #define FL_ERASE_ALL (FL_ERASE_4K | FL_ERASE_32K | FL_ERASE_64K | \ FL_ERASE_CHIP) #define FL_CAN_4B 0x00000010 /* Supports 4b mode */ @@ -76,7 +87,7 @@ struct spi_flash_ctrl { * **************************************************/ /* - * - setup(ctrl, info, tsize) + * - setup(ctrl, tsize) * * Provides the controller with an option to configure itself * based on the specific flash type. It can also override some @@ -84,8 +95,7 @@ struct spi_flash_ctrl { * which can be needed for high level controllers. It can also * override the total flash size. */ - int (*setup)(struct spi_flash_ctrl *ctrl, struct flash_info *info, - uint32_t *tsize); + int (*setup)(struct spi_flash_ctrl *ctrl, uint32_t *tsize); /* * - set_4b(ctrl, enable) @@ -208,6 +218,14 @@ struct spi_flash_ctrl { int (*cmd_wr)(struct spi_flash_ctrl *ctrl, uint8_t cmd, bool has_addr, uint32_t addr, const void *buffer, uint32_t size); + + /* The core will establish this at init, after chip ID has + * been probed + */ + struct flash_info *finfo; }; +extern int fl_wren(struct spi_flash_ctrl *ct); +extern int fl_sync_wait_idle(struct spi_flash_ctrl *ct); + #endif /* LIBFLASH_PRIV_H */ diff --git a/libflash/libflash.c b/libflash/libflash.c index a3e6ff2..f438efe 100644 --- a/libflash/libflash.c +++ b/libflash/libflash.c @@ -21,10 +21,13 @@ #include "libflash-priv.h" static const struct flash_info flash_info[] = { - { 0xc22019, 0x02000000, FL_ERASE_ALL | FL_CAN_4B, "MXxxL25635F"}, - { 0xc2201a, 0x04000000, FL_ERASE_ALL | FL_CAN_4B, "MXxxL51235F"}, - { 0xef4018, 0x01000000, FL_ERASE_ALL, "W25Q128BV" }, - { 0x55aa55, 0x00100000, FL_ERASE_ALL | FL_CAN_4B, "TEST_FLASH"}, + { 0xc22019, 0x02000000, FL_ERASE_ALL | FL_CAN_4B, "Macronix MXxxL25635F"}, + { 0xc2201a, 0x04000000, FL_ERASE_ALL | FL_CAN_4B, "Macronix MXxxL51235F"}, + { 0xef4018, 0x01000000, FL_ERASE_ALL, "Winbond W25Q128BV" }, + { 0x20ba20, 0x04000000, FL_ERASE_4K | FL_ERASE_64K | FL_CAN_4B | + FL_ERASE_BULK | FL_MICRON_BUGS, + "Micron N25Qx512Ax" }, + { 0x55aa55, 0x00100000, FL_ERASE_ALL | FL_CAN_4B, "TEST_FLASH" }, }; struct flash_chip { @@ -37,24 +40,22 @@ struct flash_chip { void *smart_buf; /* Buffer for smart writes */ }; -static int fl_read_stat(struct flash_chip *c, uint8_t *stat) +static int fl_read_stat(struct spi_flash_ctrl *ct, uint8_t *stat) { - struct spi_flash_ctrl *ct = c->ctrl; - return ct->cmd_rd(ct, CMD_RDSR, false, 0, stat, 1); } -static int fl_wren(struct flash_chip *c) +/* Exported for internal use */ +int fl_wren(struct spi_flash_ctrl *ct) { - struct spi_flash_ctrl *ct = c->ctrl; uint8_t stat; int i, rc; /* Some flashes need it to be hammered */ - for (i = 0; i < 10; i++) { + for (i = 0; i < 1000; i++) { rc = ct->cmd_wr(ct, CMD_WREN, false, 0, NULL, 0); if (rc) return rc; - rc = fl_read_stat(c, &stat); + rc = fl_read_stat(ct, &stat); if (rc) return rc; if (stat & STAT_WEN) return 0; @@ -62,18 +63,33 @@ static int fl_wren(struct flash_chip *c) return FLASH_ERR_WREN_TIMEOUT; } +static void fl_micron_status(struct spi_flash_ctrl *ct) +{ + uint8_t flst; + + /* + * After a success status on a write or erase, we + * need to do that command or some chip variants will + * lock + */ + ct->cmd_rd(ct, CMD_MIC_RDFLST, false, 0, &flst, 1); +} + /* Synchronous write completion, probably need a yield hook */ -static int fl_sync_wait_idle(struct flash_chip *c) +int fl_sync_wait_idle(struct spi_flash_ctrl *ct) { - int rc; uint8_t stat; + int rc; /* XXX Add timeout */ for (;;) { - rc = fl_read_stat(c, &stat); + rc = fl_read_stat(ct, &stat); if (rc) return rc; - if (!(stat & STAT_WIP)) + if (!(stat & STAT_WIP)) { + if (ct->finfo->flags & FL_MICRON_BUGS) + fl_micron_status(ct); return 0; + } } /* return FLASH_ERR_WIP_TIMEOUT; */ } @@ -157,7 +173,7 @@ int flash_erase(struct flash_chip *c, uint32_t dst, uint32_t size) fl_get_best_erase(c, dst, size, &chunk, &cmd); /* Poke write enable */ - rc = fl_wren(c); + rc = fl_wren(ct); if (rc) return rc; @@ -167,7 +183,7 @@ int flash_erase(struct flash_chip *c, uint32_t dst, uint32_t size) return rc; /* Wait for write complete */ - rc = fl_sync_wait_idle(c); + rc = fl_sync_wait_idle(ct); if (rc) return rc; @@ -183,7 +199,7 @@ int flash_erase_chip(struct flash_chip *c) int rc; /* XXX TODO: Fallback to using normal erases */ - if (!(c->info.flags & FL_ERASE_CHIP)) + if (!(c->info.flags & (FL_ERASE_CHIP|FL_ERASE_BULK))) return FLASH_ERR_CHIP_ER_NOT_SUPPORTED; FL_DBG("LIBFLASH: Erasing chip...\n"); @@ -192,15 +208,18 @@ int flash_erase_chip(struct flash_chip *c) if (ct->erase) return ct->erase(ct, 0, 0xffffffff); - rc = fl_wren(c); + rc = fl_wren(ct); if (rc) return rc; - rc = ct->cmd_wr(ct, CMD_CE, false, 0, NULL, 0); + if (c->info.flags & FL_ERASE_CHIP) + rc = ct->cmd_wr(ct, CMD_CE, false, 0, NULL, 0); + else + rc = ct->cmd_wr(ct, CMD_MIC_BULK_ERASE, false, 0, NULL, 0); if (rc) return rc; /* Wait for write complete */ - return fl_sync_wait_idle(c); + return fl_sync_wait_idle(ct); } static int fl_wpage(struct flash_chip *c, uint32_t dst, const void *src, @@ -212,7 +231,7 @@ static int fl_wpage(struct flash_chip *c, uint32_t dst, const void *src, if (size < 1 || size > 0x100) return FLASH_ERR_BAD_PAGE_SIZE; - rc = fl_wren(c); + rc = fl_wren(ct); if (rc) return rc; rc = ct->cmd_wr(ct, CMD_PP, true, dst, src, size); @@ -220,7 +239,7 @@ static int fl_wpage(struct flash_chip *c, uint32_t dst, const void *src, return rc; /* Wait for write complete */ - return fl_sync_wait_idle(c); + return fl_sync_wait_idle(ct); } int flash_write(struct flash_chip *c, uint32_t dst, const void *src, @@ -406,7 +425,6 @@ int flash_smart_write(struct flash_chip *c, uint32_t dst, const void *src, return 0; } - static int flash_identify(struct flash_chip *c) { struct spi_flash_ctrl *ct = c->ctrl; @@ -446,18 +464,19 @@ static int flash_identify(struct flash_chip *c) if (info->id == iid) break; } - if (info->id != iid) + if (!info || info->id != iid) return FLASH_ERR_CHIP_UNKNOWN; c->info = *info; c->tsize = info->size; + ct->finfo = &c->info; /* * Let controller know about our settings and possibly * override them */ if (ct->setup) { - rc = ct->setup(ct, &c->info, &c->tsize); + rc = ct->setup(ct, &c->tsize); if (rc) return rc; } @@ -485,6 +504,10 @@ static int flash_set_4b(struct flash_chip *c, bool enable) { struct spi_flash_ctrl *ct = c->ctrl; + /* Some flash chips want this */ + fl_wren(ct); + /* Ignore error in case chip is write protected */ + return ct->cmd_wr(ct, enable ? CMD_EN4B : CMD_EX4B, false, 0, NULL, 0); } |