Commit d8f8f68f authored by Timothy Pearson's avatar Timothy Pearson

Add support for the MT25QL512 PNOR devices used on Talos II / Blackbird

parent d04c0b5c
......@@ -43,8 +43,10 @@ int probe_spi_at25f(struct flashctx *flash);
int spi_write_enable(struct flashctx *flash);
int spi_write_disable(struct flashctx *flash);
int spi_block_erase_20(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_21(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_50(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_52(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_5c(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_60(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_62(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_81(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
......@@ -53,6 +55,7 @@ int spi_block_erase_c7(struct flashctx *flash, unsigned int addr, unsigned int b
int spi_block_erase_d7(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_d8(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_dc(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
erasefunc_t *spi_get_erasefn_from_opcode(uint8_t opcode);
int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
int spi_byte_program(struct flashctx *flash, unsigned int addr, uint8_t databyte);
......@@ -199,10 +202,15 @@ int write_en29lv640b(struct flashctx *flash, const uint8_t *buf, unsigned int st
int spi_enter_4ba_b7(struct flashctx *flash);
int spi_enter_4ba_b7_we(struct flashctx *flash);
int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte);
int spi_byte_program_4ba_12(struct flashctx *flash, unsigned int addr, uint8_t databyte);
int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
int spi_nbyte_program_4ba_12(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
int spi_nbyte_read_4ba_13(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_21_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_dc_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_byte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t databyte);
int spi_nbyte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
......
......@@ -9875,6 +9875,47 @@ const struct flashchip flashchips[] = {
.voltage = {2700, 3600},
},
{
.vendor = "Micron",
.name = "MT25QL512", /* L = 3V, uniform 64KB/4KB blocks/sectors */
.bustype = BUS_SPI,
.manufacture_id = ST_ID,
.model_id = ST_N25Q512__3G,
.total_size = 65536,
.page_size = 256,
/* supports SFDP */
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_SUPPORT,
.four_bytes_addr_funcs =
{
.enter_4ba = spi_enter_4ba_b7, /* enter 4-bytes addressing mode by CMD B7 */
.read_nbyte = spi_nbyte_read_4ba_13, /* read from 4-bytes addressing mode */
.program_byte = spi_byte_program_4ba_12, /* write from 4-bytes addressing mode */
.program_nbyte = spi_nbyte_program_4ba_12 /* write from 4-bytes addressing mode */
},
.tested = TEST_OK_PREW,
.probe = probe_spi_rdid,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16384} },
.block_erase = spi_block_erase_21_4ba,
}, {
.eraseblocks = { {64 * 1024, 1024} },
.block_erase = spi_block_erase_dc_4ba,
}, {
.eraseblocks = { {65536 * 1024, 1} },
.block_erase = spi_block_erase_c7,
}
},
.printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
.unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
.write = spi_chip_write_256, /* Multi I/O supported */
.read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
{
.vendor = "MoselVitelic",
.name = "V29C51000B",
......
......@@ -853,6 +853,7 @@
#define ST_N25Q512__3E 0xBA20 /* N25Q512, 3.0V, (uniform sectors expected) */
#define ST_N25Q512__1E 0xBB20 /* N25Q512, 1.8V, (uniform sectors expected) */
#define ST_N25Q00A__3E 0xBA21 /* N25Q00A, 3.0V, (uniform sectors expected) */
#define ST_N25Q512__3G 0xBA20 /* N25Q512/MT25QL512, 3.0V, (uniform sectors expected) */
#define ST_NP5Q032 0xDA16 /* Phase-change memory (PCM), 3V */
#define ST_NP5Q064 0xDA17 /* Phase-change memory (PCM), 3V */
#define ST_NP5Q128 0xDA18 /* Phase-change memory (PCM), 3V */
......
......@@ -119,6 +119,46 @@ int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr,
return result;
}
/* Program one flash byte from 4-bytes addressing mode */
int spi_byte_program_4ba_12(struct flashctx *flash, unsigned int addr,
uint8_t databyte)
{
int result;
struct spi_command cmds[] = {
{
.writecnt = JEDEC_WREN_OUTSIZE,
.writearr = (const unsigned char[]){ JEDEC_WREN },
.readcnt = 0,
.readarr = NULL,
}, {
.writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE + 1,
.writearr = (const unsigned char[]){
0x12,
(addr >> 24) & 0xff,
(addr >> 16) & 0xff,
(addr >> 8) & 0xff,
(addr & 0xff),
databyte
},
.readcnt = 0,
.readarr = NULL,
}, {
.writecnt = 0,
.writearr = NULL,
.readcnt = 0,
.readarr = NULL,
}};
msg_trace("-> %s (0x%08X)\n", __func__, addr);
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%s failed during command execution at address 0x%x\n",
__func__, addr);
}
return result;
}
/* Program flash bytes from 4-bytes addressing mode */
int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr,
const uint8_t *bytes, unsigned int len)
......@@ -170,6 +210,57 @@ int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr,
return result;
}
/* Program flash bytes from 4-bytes addressing mode */
int spi_nbyte_program_4ba_12(struct flashctx *flash, unsigned int addr,
const uint8_t *bytes, unsigned int len)
{
int result;
unsigned char cmd[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1 + 256] = {
0x12,
(addr >> 24) & 0xff,
(addr >> 16) & 0xff,
(addr >> 8) & 0xff,
(addr >> 0) & 0xff
};
struct spi_command cmds[] = {
{
.writecnt = JEDEC_WREN_OUTSIZE,
.writearr = (const unsigned char[]){ JEDEC_WREN },
.readcnt = 0,
.readarr = NULL,
}, {
.writecnt = (JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1 + len,
.writearr = cmd,
.readcnt = 0,
.readarr = NULL,
}, {
.writecnt = 0,
.writearr = NULL,
.readcnt = 0,
.readarr = NULL,
}};
msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
if (!len) {
msg_cerr("%s called for zero-length write\n", __func__);
return 1;
}
if (len > 256) {
msg_cerr("%s called for too long a write\n", __func__);
return 1;
}
memcpy(&cmd[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1], bytes, len);
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%s failed during command execution at address 0x%x\n",
__func__, addr);
}
return result;
}
/* Read flash bytes from 4-bytes addressing mode */
int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr,
uint8_t *bytes, unsigned int len)
......@@ -188,6 +279,24 @@ int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr,
return spi_send_command(flash, sizeof(cmd), len, cmd, bytes);
}
/* Read flash bytes from 4-bytes addressing mode */
int spi_nbyte_read_4ba_13(struct flashctx *flash, unsigned int addr,
uint8_t *bytes, unsigned int len)
{
const unsigned char cmd[JEDEC_READ_OUTSIZE + 1] = {
0x13,
(addr >> 24) & 0xff,
(addr >> 16) & 0xff,
(addr >> 8) & 0xff,
(addr >> 0) & 0xff
};
msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
/* Send Read */
return spi_send_command(flash, sizeof(cmd), len, cmd, bytes);
}
/* Erases 4 KB of flash from 4-bytes addressing mode */
int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
......@@ -234,6 +343,52 @@ int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr,
return 0;
}
/* Erases 4 KB of flash from 4-bytes addressing mode */
int spi_block_erase_21_4ba(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
{
int result;
struct spi_command cmds[] = {
{
.writecnt = JEDEC_WREN_OUTSIZE,
.writearr = (const unsigned char[]){ JEDEC_WREN },
.readcnt = 0,
.readarr = NULL,
}, {
.writecnt = JEDEC_SE_OUTSIZE + 1,
.writearr = (const unsigned char[]){
0x21,
(addr >> 24) & 0xff,
(addr >> 16) & 0xff,
(addr >> 8) & 0xff,
(addr & 0xff)
},
.readcnt = 0,
.readarr = NULL,
}, {
.writecnt = 0,
.writearr = NULL,
.readcnt = 0,
.readarr = NULL,
}};
msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%s failed during command execution at address 0x%x\n",
__func__, addr);
return result;
}
/* Wait until the Write-In-Progress bit is cleared.
* This usually takes 15-800 ms, so wait in 10 ms steps.
*/
while (spi_read_status_register(flash) & SPI_SR_WIP)
programmer_delay(10 * 1000);
/* FIXME: Check the status register for errors. */
return 0;
}
/* Erases 32 KB of flash from 4-bytes addressing mode */
int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
......@@ -280,6 +435,53 @@ int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr,
return 0;
}
/* Erases 32 KB of flash from 4-bytes addressing mode */
int spi_block_erase_dc_4ba(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
{
int result;
struct spi_command cmds[] = {
{
.writecnt = JEDEC_WREN_OUTSIZE,
.writearr = (const unsigned char[]){ JEDEC_WREN },
.readcnt = 0,
.readarr = NULL,
}, {
.writecnt = JEDEC_BE_52_OUTSIZE + 1,
.writearr = (const unsigned char[]){
0xdc,
(addr >> 24) & 0xff,
(addr >> 16) & 0xff,
(addr >> 8) & 0xff,
(addr & 0xff)
},
.readcnt = 0,
.readarr = NULL,
}, {
.writecnt = 0,
.writearr = NULL,
.readcnt = 0,
.readarr = NULL,
}};
msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%s failed during command execution at address 0x%x\n",
__func__, addr);
return result;
}
/* Wait until the Write-In-Progress bit is cleared.
* This usually takes 100-4000 ms, so wait in 100 ms steps.
*/
while (spi_read_status_register(flash) & SPI_SR_WIP)
programmer_delay(100 * 1000);
/* FIXME: Check the status register for errors. */
return 0;
}
/* Erases 64 KB of flash from 4-bytes addressing mode */
int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment