Created
January 30, 2014 21:47
-
-
Save devicenull/8720588 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/chipdrivers.h b/chipdrivers.h | |
index 851e90a..3f31293 100644 | |
--- a/chipdrivers.h | |
+++ b/chipdrivers.h | |
@@ -52,6 +52,7 @@ int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int b | |
int spi_block_erase_c7(struct flashctx *flash, unsigned int addr, unsigned int blocklen); | |
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_dc(struct flashctx *flash, unsigned int addr, unsigned int blocklen); | |
int spi_block_erase_db(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, uint8_t *buf, unsigned int start, unsigned int len); | |
diff --git a/spi.h b/spi.h | |
index de5b3be..63dcdf9 100644 | |
--- a/spi.h | |
+++ b/spi.h | |
@@ -101,6 +101,11 @@ | |
#define JEDEC_BE_D8_OUTSIZE 0x04 | |
#define JEDEC_BE_D8_INSIZE 0x00 | |
+/* Block Erase 0xdc is supported by Spansion chips. */ | |
+#define JEDEC_BE_DC 0xdc | |
+#define JEDEC_BE_DC_OUTSIZE 0x05 | |
+#define JEDEC_BE_DC_INSIZE 0x00 | |
+ | |
/* Block Erase 0xd7 is supported by PMC chips. */ | |
#define JEDEC_BE_D7 0xd7 | |
#define JEDEC_BE_D7_OUTSIZE 0x04 | |
@@ -121,6 +126,10 @@ | |
#define JEDEC_RDSR_OUTSIZE 0x01 | |
#define JEDEC_RDSR_INSIZE 0x01 | |
+#define JEDEC_4_READ 0x13 | |
+#define JEDEC_4_READ_OUTSIZE 0x05 | |
+/* JEDEC_4_READ_INSIZE : any length */ | |
+ | |
/* Status Register Bits */ | |
#define SPI_SR_WIP (0x01 << 0) | |
#define SPI_SR_WEL (0x01 << 1) | |
@@ -146,6 +155,10 @@ | |
#define JEDEC_BYTE_PROGRAM_OUTSIZE 0x05 | |
#define JEDEC_BYTE_PROGRAM_INSIZE 0x00 | |
+#define JEDEC_4_BYTE_PROGRAM 0x12 | |
+#define JEDEC_4_BYTE_PROGRAM_OUTSIZE 0x06 | |
+#define JEDEC_4_BYTE_PROGRAM_INSIZE 0x00 | |
+ | |
/* Write AAI word (SST25VF080B) */ | |
#define JEDEC_AAI_WORD_PROGRAM 0xad | |
#define JEDEC_AAI_WORD_PROGRAM_OUTSIZE 0x06 | |
diff --git a/spi25.c b/spi25.c | |
index e001196..c1a6e0f 100644 | |
--- a/spi25.c | |
+++ b/spi25.c | |
@@ -649,6 +649,48 @@ int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int b | |
return 0; | |
} | |
+/* Block size is usually 256k */ | |
+int spi_block_erase_dc(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_DC_OUTSIZE, | |
+ .writearr = (const unsigned char[]){ | |
+ JEDEC_BE_DC, | |
+ (addr >> 24) & 0xff, | |
+ (addr >> 16) & 0xff, | |
+ (addr >> 8) & 0xff, | |
+ (addr & 0xff) | |
+ }, | |
+ .readcnt = 0, | |
+ .readarr = NULL, | |
+ }, { | |
+ .writecnt = 0, | |
+ .writearr = NULL, | |
+ .readcnt = 0, | |
+ .readarr = NULL, | |
+ }}; | |
+ | |
+ 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; | |
+} | |
+ | |
+ | |
/* Sector size is usually 4k, though Macronix eliteflash has 64k */ | |
int spi_block_erase_20(struct flashctx *flash, unsigned int addr, | |
unsigned int blocklen) | |
@@ -831,6 +873,8 @@ erasefunc_t *spi_get_erasefn_from_opcode(uint8_t opcode) | |
return &spi_block_erase_d7; | |
case 0xd8: | |
return &spi_block_erase_d8; | |
+ case 0xdc: | |
+ return &spi_block_erase_dc; | |
case 0xdb: | |
return &spi_block_erase_db; | |
default: | |
@@ -844,6 +888,7 @@ int spi_byte_program(struct flashctx *flash, unsigned int addr, | |
uint8_t databyte) | |
{ | |
int result; | |
+ uint8_t cmd[JEDEC_4_BYTE_PROGRAM_OUTSIZE]; | |
struct spi_command cmds[] = { | |
{ | |
.writecnt = JEDEC_WREN_OUTSIZE, | |
@@ -851,14 +896,6 @@ int spi_byte_program(struct flashctx *flash, unsigned int addr, | |
.readcnt = 0, | |
.readarr = NULL, | |
}, { | |
- .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE, | |
- .writearr = (const unsigned char[]){ | |
- JEDEC_BYTE_PROGRAM, | |
- (addr >> 16) & 0xff, | |
- (addr >> 8) & 0xff, | |
- (addr & 0xff), | |
- databyte | |
- }, | |
.readcnt = 0, | |
.readarr = NULL, | |
}, { | |
@@ -868,6 +905,32 @@ int spi_byte_program(struct flashctx *flash, unsigned int addr, | |
.readarr = NULL, | |
}}; | |
+ /* We always use the 4-byte commands for chips bigger than 16 | |
+ * MB as we don't know what's in the 'bank address | |
+ * register'. */ | |
+ if (flash->chip->total_size > 16 * 1024) { | |
+ | |
+ cmds[1].writecnt = JEDEC_4_BYTE_PROGRAM_OUTSIZE; | |
+ cmds[1].writearr = cmd; | |
+ | |
+ cmd[0] = JEDEC_4_BYTE_PROGRAM; | |
+ cmd[1] = (addr >> 24) & 0xff; | |
+ cmd[2] = (addr >> 16) & 0xff; | |
+ cmd[3] = (addr >> 8) & 0xff; | |
+ cmd[4] = (addr >> 0) & 0xff; | |
+ cmd[5] = databyte; | |
+ } else { | |
+ | |
+ cmds[1].writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE; | |
+ cmds[1].writearr = cmd; | |
+ | |
+ cmd[0] = JEDEC_BYTE_PROGRAM; | |
+ cmd[1] = (addr >> 16) & 0xff; | |
+ cmd[2] = (addr >> 8) & 0xff; | |
+ cmd[3] = (addr >> 0) & 0xff; | |
+ cmd[4] = databyte; | |
+ } | |
+ | |
result = spi_send_multicommand(flash, cmds); | |
if (result) { | |
msg_cerr("%s failed during command execution at address 0x%x\n", | |
@@ -880,13 +943,7 @@ int spi_nbyte_program(struct flashctx *flash, unsigned int addr, uint8_t *bytes, | |
unsigned int len) | |
{ | |
int result; | |
- /* FIXME: Switch to malloc based on len unless that kills speed. */ | |
- unsigned char cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + 256] = { | |
- JEDEC_BYTE_PROGRAM, | |
- (addr >> 16) & 0xff, | |
- (addr >> 8) & 0xff, | |
- (addr >> 0) & 0xff, | |
- }; | |
+ uint8_t cmd[JEDEC_4_BYTE_PROGRAM_OUTSIZE - 1 + 512]; | |
struct spi_command cmds[] = { | |
{ | |
.writecnt = JEDEC_WREN_OUTSIZE, | |
@@ -894,8 +951,8 @@ int spi_nbyte_program(struct flashctx *flash, unsigned int addr, uint8_t *bytes, | |
.readcnt = 0, | |
.readarr = NULL, | |
}, { | |
- .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + len, | |
- .writearr = cmd, | |
+ .writecnt = 0, | |
+ .writearr = NULL, | |
.readcnt = 0, | |
.readarr = NULL, | |
}, { | |
@@ -909,12 +966,36 @@ int spi_nbyte_program(struct flashctx *flash, unsigned int addr, uint8_t *bytes, | |
msg_cerr("%s called for zero-length write\n", __func__); | |
return 1; | |
} | |
- if (len > 256) { | |
+ if (len > 512) { | |
msg_cerr("%s called for too long a write\n", __func__); | |
return 1; | |
} | |
- memcpy(&cmd[4], bytes, len); | |
+ /* We always use the 4-byte commands for chips bigger than 16 | |
+ * MB as we don't know what's in the 'bank address | |
+ * register'. */ | |
+ if (flash->chip->total_size > 16 * 1024) { | |
+ cmds[1].writecnt = JEDEC_4_BYTE_PROGRAM_OUTSIZE - 1 + len; | |
+ cmds[1].writearr = cmd; | |
+ | |
+ cmd[0] = JEDEC_4_BYTE_PROGRAM; | |
+ cmd[1] = (addr >> 24) & 0xff; | |
+ cmd[2] = (addr >> 16) & 0xff; | |
+ cmd[3] = (addr >> 8) & 0xff; | |
+ cmd[4] = (addr >> 0) & 0xff; | |
+ | |
+ memcpy(&cmd[5], bytes, len); | |
+ } else { | |
+ cmds[1].writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + len; | |
+ cmds[1].writearr = cmd; | |
+ | |
+ cmd[0] = JEDEC_BYTE_PROGRAM; | |
+ cmd[1] = (addr >> 16) & 0xff; | |
+ cmd[2] = (addr >> 8) & 0xff; | |
+ cmd[3] = (addr >> 0) & 0xff; | |
+ | |
+ memcpy(&cmd[4], bytes, len); | |
+ } | |
result = spi_send_multicommand(flash, cmds); | |
if (result) { | |
@@ -927,15 +1008,27 @@ int spi_nbyte_program(struct flashctx *flash, unsigned int addr, uint8_t *bytes, | |
int spi_nbyte_read(struct flashctx *flash, unsigned int address, uint8_t *bytes, | |
unsigned int len) | |
{ | |
- const unsigned char cmd[JEDEC_READ_OUTSIZE] = { | |
- JEDEC_READ, | |
- (address >> 16) & 0xff, | |
- (address >> 8) & 0xff, | |
- (address >> 0) & 0xff, | |
- }; | |
+ unsigned char cmd[JEDEC_4_READ_OUTSIZE]; | |
+ unsigned int cmd_len; | |
+ | |
+ if (flash->chip->total_size > 16 * 1024) { | |
+ cmd[0] = JEDEC_4_READ; | |
+ cmd[1] = (address >> 24) & 0xff; | |
+ cmd[2] = (address >> 16) & 0xff; | |
+ cmd[3] = (address >> 8) & 0xff; | |
+ cmd[4] = (address >> 0) & 0xff; | |
+ cmd_len = JEDEC_4_READ_OUTSIZE; | |
+ } else { | |
+ cmd[0] = JEDEC_READ; | |
+ cmd[1] = (address >> 16) & 0xff; | |
+ cmd[2] = (address >> 8) & 0xff; | |
+ cmd[3] = (address >> 0) & 0xff; | |
+ cmd_len = JEDEC_READ_OUTSIZE; | |
+ } | |
+ | |
/* Send Read */ | |
- return spi_send_command(flash, sizeof(cmd), len, cmd, bytes); | |
+ return spi_send_command(flash, cmd_len, len, cmd, bytes); | |
} | |
/* | |
@@ -947,27 +1040,21 @@ int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start, | |
unsigned int len, unsigned int chunksize) | |
{ | |
int rc = 0; | |
- unsigned int i, j, starthere, lenhere, toread; | |
+ unsigned int pos, j, lenhere, towrite, page_end; | |
unsigned int page_size = flash->chip->page_size; | |
- /* Warning: This loop has a very unusual condition and body. | |
- * The loop needs to go through each page with at least one affected | |
- * byte. The lowest page number is (start / page_size) since that | |
- * division rounds down. The highest page number we want is the page | |
- * where the last byte of the range lives. That last byte has the | |
- * address (start + len - 1), thus the highest page number is | |
- * (start + len - 1) / page_size. Since we want to include that last | |
- * page as well, the loop condition uses <=. | |
- */ | |
- for (i = start / page_size; i <= (start + len - 1) / page_size; i++) { | |
- /* Byte position of the first byte in the range in this page. */ | |
- /* starthere is an offset to the base address of the chip. */ | |
- starthere = max(start, i * page_size); | |
+ if (page_size & (page_size - 1)) { | |
+ msg_cerr("page_size not a power of 2 (%u)?\n", page_size); | |
+ } | |
+ | |
+ for (pos = start; pos < (start + len); pos += lenhere) { | |
+ /* This is the end of the current page (start of the next page). */ | |
+ page_end = (pos & ~(page_size - 1)) + page_size; | |
/* Length of bytes in the range in this page. */ | |
- lenhere = min(start + len, (i + 1) * page_size) - starthere; | |
+ lenhere = min(start + len, page_end) - pos; | |
for (j = 0; j < lenhere; j += chunksize) { | |
- toread = min(chunksize, lenhere - j); | |
- rc = spi_nbyte_read(flash, starthere + j, buf + starthere - start + j, toread); | |
+ towrite = min(chunksize, lenhere - j); | |
+ rc = spi_nbyte_program(flash, pos + j, buf + pos - start + j, towrite); | |
if (rc) | |
break; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment