@@ -31,9 +31,11 @@
int probe_spi_rems(struct flashchip *flash);
int probe_spi_res1(struct flashchip *flash);
int probe_spi_res2(struct flashchip *flash);
+int probe_spi_mx_2017(struct flashchip *flash);
int spi_write_enable(void);
int spi_write_disable(void);
int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_20_4or64k(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_d7(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
@@ -3959,14 +3959,14 @@
.total_size = 2048,
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
- .tested = TEST_OK_PREW,
+ .tested = TEST_OK_PRW,
.probe = probe_spi_rdid,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
- .eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20, /* This erase function has 64k blocksize for eLiteFlash */
+ .eraseblocks = { {64 * 1024, 32} },
+ .block_erase = spi_block_erase_20_4or64k, /* This erase function has 64k blocksize for eLiteFlash */
}, {
.eraseblocks = { {64 * 1024, 32} }, /* Not supported in MX25L1605 (eLiteFlash) and MX25L1605D */
.block_erase = spi_block_erase_52,
@@ -4063,16 +4063,16 @@
.total_size = 4096,
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
- .tested = TEST_OK_PREW,
+ .tested = TEST_OK_PRW,
.probe = probe_spi_rdid,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
- .eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .eraseblocks = { {64 * 1024, 64} },
+ .block_erase = spi_block_erase_20_4or64k,
}, {
- .eraseblocks = { {4 * 1024, 1024} },
+ .eraseblocks = { {64 * 1024, 64} },
.block_erase = spi_block_erase_d8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
@@ -4132,12 +4132,46 @@
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PROBE,
- .probe = probe_spi_rdid,
+ .probe = probe_spi_mx_2017,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 128} },
+ .block_erase = spi_block_erase_20_4or64k,
+ }, {
+ .eraseblocks = { {64 * 1024, 128} },
+ .block_erase = spi_block_erase_d8,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = spi_block_erase_60,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = spi_block_erase_c7,
+ }
+ },
+ .unlock = spi_disable_blockprotect,
+ .write = spi_chip_write_256,
+ .read = spi_chip_read,
+ .voltage = {2700, 3600},
+ },
+
+ {
+ .vendor = "Macronix",
+ .name = "MX25L6445E",
+ .bustype = CHIP_BUSTYPE_SPI,
+ .manufacture_id = MACRONIX_ID,
+ .model_id = MACRONIX_MX25L6445E,
+ .total_size = 8192,
+ .page_size = 256,
+ .feature_bits = FEATURE_WRSR_WREN,
+ .tested = TEST_OK_PREW,
+ .probe = probe_spi_mx_2017,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 2048} },
.block_erase = spi_block_erase_20,
}, {
.eraseblocks = { {64 * 1024, 128} },
@@ -356,7 +356,8 @@
#define MACRONIX_MX25L8005 0x2014 /* Same as MX25V8005 */
#define MACRONIX_MX25L1605 0x2015 /* MX25L1605{,A,D} */
#define MACRONIX_MX25L3205 0x2016 /* MX25L3205{,A} */
-#define MACRONIX_MX25L6405 0x2017 /* MX25L3205{,D} */
+#define MACRONIX_MX25L6405 0x2017 /* MX25L6405, MX25L6406E */
+#define MACRONIX_MX25L6445E 0x16 /* MX25L6445E, MX25L6405D ID = REMS2 answer */
#define MACRONIX_MX25L12805 0x2018 /* MX25L12805 */
#define MACRONIX_MX25L1635D 0x2415
#define MACRONIX_MX25L1635E 0x2515 /* MX25L1635{E} */
@@ -40,6 +40,21 @@
#define JEDEC_REMS_OUTSIZE 0x04
#define JEDEC_REMS_INSIZE 0x02
+/* Read Electronic Manufacturer Signature for 2x I/O mode */
+#define JEDEC_REMS2 0xef
+#define JEDEC_REMS2_OUTSIZE 0x04
+#define JEDEC_REMS2_INSIZE 0x02
+
+/* Read Electronic Manufacturer Signature for 4x I/O mode */
+#define JEDEC_REMS4 0xdf
+#define JEDEC_REMS4_OUTSIZE 0x04
+#define JEDEC_REMS4_INSIZE 0x02
+
+/* Read Electronic Manufacturer Signature for 4x I/O DT mode */
+#define JEDEC_REMS4D 0xcf
+#define JEDEC_REMS4D_OUTSIZE 0x04
+#define JEDEC_REMS4D_INSIZE 0x02
+
/* Read Electronic Signature */
#define JEDEC_RES 0xab
#define JEDEC_RES_OUTSIZE 0x04
@@ -22,6 +22,7 @@
* Contains the common SPI chip driver functions
*/
+#include <stdlib.h>
#include <string.h>
#include "flash.h"
#include "flashchips.h"
@@ -66,6 +67,27 @@
return 0;
}
+static int spi_rems2(unsigned char *readarr)
+{
+ unsigned char cmd[JEDEC_REMS2_OUTSIZE] = { JEDEC_REMS2, 0, 0, 0 };
+ uint32_t readaddr;
+ int ret;
+
+ ret = spi_send_command(sizeof(cmd), JEDEC_REMS2_INSIZE, cmd, readarr);
+ if (ret == SPI_INVALID_ADDRESS) {
+ /* Find the lowest even address allowed for reads. */
+ readaddr = (spi_get_valid_read_addr() + 1) & ~1;
+ cmd[1] = (readaddr >> 16) & 0xff,
+ cmd[2] = (readaddr >> 8) & 0xff,
+ cmd[3] = (readaddr >> 0) & 0xff,
+ ret = spi_send_command(sizeof(cmd), JEDEC_REMS2_INSIZE, cmd, readarr);
+ }
+ if (ret)
+ return ret;
+ msg_cspew("REMS2 returned %02x %02x. ", readarr[0], readarr[1]);
+ return 0;
+}
+
static int spi_res(unsigned char *readarr, int bytes)
{
unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, 0, 0, 0 };
@@ -173,6 +195,58 @@
return probe_spi_rdid_generic(flash, 3);
}
+int probe_spi_mx_2017(struct flashchip *flash)
+{
+ unsigned char readarr[4];
+ uint32_t id1;
+ uint32_t id2;
+ uint32_t id3;
+ uint32_t id4;
+
+ if (spi_rdid(readarr, 3)) {
+ msg_cdbg("\n");
+ return 0;
+ }
+ id1 = readarr[0];
+ id2 = (readarr[1] << 8) | readarr[2];
+
+ if (id1 == MACRONIX_ID && id2 == MACRONIX_MX25L6405) {
+ /* Now we have detected the 2017h class of Macronix flash devices.
+ * We can further differentiate two classes:
+ * -those who support the REMS2 function do always have 4KB sector size
+ * (at least i have not found one with 64KB yet),
+ * and
+ * -those who don't support the REMS2 function might have 4KB or 64KB
+ * (some have 4KB, e.g. MX25L6406E, some have 64KB, e.g. MX25L6405 (not D))
+ * for erase function 20h.
+ */
+ if (spi_rems2(readarr)) {
+ msg_cdbg("\n");
+ return 0;
+ }
+ id3 = readarr[0];
+ id4 = readarr[1];
+ msg_cdbg("%s: id1 0x%02x, id2 0x%02x, id3 0x%02x, id4 0x%02x\n", __func__, id1, id2, id3, id4);
+ if (id3 == MACRONIX_ID && id4 == MACRONIX_MX25L6445E) {
+ /* MACRONIX_MX25L6445E class, always 4KB sector */
+ if (flash->model_id == MACRONIX_MX25L6445E)
+ return 1;
+ else
+ return 0;
+ } else {
+ /* MACRONIX_MX25L6405 class, might have 4KB or 64KB sector */
+ if (flash->model_id == MACRONIX_MX25L6405)
+ return 1;
+ else
+ return 0;
+ }
+ } else {
+ msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+ }
+ /* neither MACRONIX_MX25L6405 nor MACRONIX_MX25L6445E */
+ return 0;
+}
+
int probe_spi_rdid4(struct flashchip *flash)
{
/* Some SPI controllers do not support commands with writecnt=1 and
@@ -694,6 +768,79 @@
return 0;
}
+/* Sector size might be 4KB or 64KB, but on call to this function this is unknown.
+ * So we do a first erase command and then check if mem in the complete 64KB sector is erased.
+ * If not we assume 4KB and so we repeat the erase for each 4KB sector in the 64KB block
+ * (which is not erased already).
+ * PLEASE NOTE: the .eraseblocks block size must be set to 64KB if you use this function.
+ */
+int spi_block_erase_20_4or64k(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
+{
+ int result, i, j, fully_erased, sector_erased;
+ unsigned int curraddr, currblocklen;
+ uint8_t *readbuf;
+
+ if (blocklen != (64 * 1024)) {
+ msg_gerr("%s: blocklen not 64KB! Please report a bug at "
+ "flashrom@flashrom.org\n", __func__);
+ return 1;
+ }
+
+ readbuf = malloc(blocklen);
+ if (!readbuf) {
+ msg_gerr("Out of memory!\n");
+ exit(1);
+ }
+
+ for (i = 0; i < 16; i++) { /* there are 16 4KB sectors in 64KB */
+
+ curraddr = addr + (i * (4 * 1024));
+
+ if (i > 0) {
+ /* Skip the sector erase if the sector is already erased */
+ sector_erased = 1;
+ result = flash->read(flash, readbuf, curraddr, (4 * 1024));
+ if (result) {
+ msg_gerr("Erase impossible because read failed "
+ "at 0x%x (len 0x%x)\n", curraddr, (4 * 1024));
+ break;
+ }
+ for (j = 0; j < currblocklen; j++)
+ if (readbuf[j] != 0xFF)
+ sector_erased = 0;
+ if (sector_erased)
+ continue; /* Sector is already erased */
+ }
+
+ result = spi_block_erase_20 (flash, curraddr, (4 * 1024)); /* last parameter (blocklen) is unused */
+ if (result) break;
+
+ if (0 == i) {
+ curraddr += 4 * 1024;
+ currblocklen = (64*1024)-(4*1024);
+ fully_erased = 1;
+ result = flash->read(flash, readbuf, curraddr, currblocklen);
+ if (result) {
+ msg_gerr("Erase impossible because read failed "
+ "at 0x%x (len 0x%x)\n", curraddr, currblocklen);
+ break;
+ }
+ for (j = 0; j < currblocklen; j++)
+ if (readbuf[j] != 0xFF)
+ fully_erased = 0;
+ if (fully_erased) {
+ /* This means either that the SE command has erased the full 64KB
+ * or that the remaining 64KB sector was already erased before.
+ * Anyhow, we can now exit without calling the SE command again.
+ */
+ break;
+ }
+ }
+ }
+ free(readbuf);
+ return result;
+}
+
int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen)
{
if ((addr != 0) || (blocklen != flash->total_size * 1024)) {