aboutsummaryrefslogtreecommitdiff
path: root/libflash
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-15 13:44:23 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-15 14:45:27 +1100
commit8463764f7e4383e1e2339eee174d4151337bc467 (patch)
tree56db78dfd6b9a8df3d8045292c631030f22232c7 /libflash
parenta9efc5faa0ef2d8126a8a217a3f9f806071fe1db (diff)
downloadskiboot-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.h56
-rw-r--r--libflash/libflash.c75
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);
}