mirror of
https://review.coreboot.org/flashrom.git
synced 2025-04-27 23:22:37 +02:00
Add detailed status register printing and unlocking for all ATMEL AT25* chips
Add support for Atmel AT25DF081A and AT25DQ161. Some chips require EWSR before WRSR, others require WREN before WRSR, and some support both variants. Add feature_bits to select the correct SPI command, and default to EWSR. Corresponding to flashrom svn r1115. Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> Tested-by: Steven Rosario Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
This commit is contained in:
parent
f792c7d4cb
commit
fd7075ae75
@ -47,7 +47,17 @@ int spi_chip_write_1_new(struct flashchip *flash, uint8_t *buf, int start, int l
|
|||||||
int spi_chip_write_256_new(struct flashchip *flash, uint8_t *buf, int start, int len);
|
int spi_chip_write_256_new(struct flashchip *flash, uint8_t *buf, int start, int len);
|
||||||
int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);
|
int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);
|
||||||
uint8_t spi_read_status_register(void);
|
uint8_t spi_read_status_register(void);
|
||||||
|
int spi_prettyprint_status_register_at25df(struct flashchip *flash);
|
||||||
|
int spi_prettyprint_status_register_at25df_sec(struct flashchip *flash);
|
||||||
|
int spi_prettyprint_status_register_at25f(struct flashchip *flash);
|
||||||
|
int spi_prettyprint_status_register_at25fs010(struct flashchip *flash);
|
||||||
|
int spi_prettyprint_status_register_at25fs040(struct flashchip *flash);
|
||||||
int spi_disable_blockprotect(struct flashchip *flash);
|
int spi_disable_blockprotect(struct flashchip *flash);
|
||||||
|
int spi_disable_blockprotect_at25df(struct flashchip *flash);
|
||||||
|
int spi_disable_blockprotect_at25df_sec(struct flashchip *flash);
|
||||||
|
int spi_disable_blockprotect_at25f(struct flashchip *flash);
|
||||||
|
int spi_disable_blockprotect_at25fs010(struct flashchip *flash);
|
||||||
|
int spi_disable_blockprotect_at25fs040(struct flashchip *flash);
|
||||||
int spi_byte_program(int addr, uint8_t databyte);
|
int spi_byte_program(int addr, uint8_t databyte);
|
||||||
int spi_nbyte_program(int addr, uint8_t *bytes, int len);
|
int spi_nbyte_program(int addr, uint8_t *bytes, int len);
|
||||||
int spi_nbyte_read(int addr, uint8_t *bytes, int len);
|
int spi_nbyte_read(int addr, uint8_t *bytes, int len);
|
||||||
|
6
flash.h
6
flash.h
@ -69,8 +69,9 @@ enum chipbustype {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* How many different erase functions do we have per chip?
|
* How many different erase functions do we have per chip?
|
||||||
|
* Atmel AT25FS010 has 6 different functions.
|
||||||
*/
|
*/
|
||||||
#define NUM_ERASEFUNCTIONS 5
|
#define NUM_ERASEFUNCTIONS 6
|
||||||
|
|
||||||
#define FEATURE_REGISTERMAP (1 << 0)
|
#define FEATURE_REGISTERMAP (1 << 0)
|
||||||
#define FEATURE_BYTEWRITES (1 << 1)
|
#define FEATURE_BYTEWRITES (1 << 1)
|
||||||
@ -82,6 +83,9 @@ enum chipbustype {
|
|||||||
#define FEATURE_ADDR_2AA (1 << 2)
|
#define FEATURE_ADDR_2AA (1 << 2)
|
||||||
#define FEATURE_ADDR_AAA (2 << 2)
|
#define FEATURE_ADDR_AAA (2 << 2)
|
||||||
#define FEATURE_ADDR_SHIFTED (1 << 5)
|
#define FEATURE_ADDR_SHIFTED (1 << 5)
|
||||||
|
#define FEATURE_WRSR_EWSR (1 << 6)
|
||||||
|
#define FEATURE_WRSR_WREN (1 << 7)
|
||||||
|
#define FEATURE_WRSR_EITHER (FEATURE_WRSR_EWSR | FEATURE_WRSR_WREN)
|
||||||
|
|
||||||
struct flashchip {
|
struct flashchip {
|
||||||
const char *vendor;
|
const char *vendor;
|
||||||
|
115
flashchips.c
115
flashchips.c
@ -789,6 +789,7 @@ struct flashchip flashchips[] = {
|
|||||||
.model_id = AT_25DF021,
|
.model_id = AT_25DF021,
|
||||||
.total_size = 256,
|
.total_size = 256,
|
||||||
.page_size = 256,
|
.page_size = 256,
|
||||||
|
.feature_bits = FEATURE_WRSR_WREN,
|
||||||
.tested = TEST_UNTESTED,
|
.tested = TEST_UNTESTED,
|
||||||
.probe = probe_spi_rdid,
|
.probe = probe_spi_rdid,
|
||||||
.probe_timing = TIMING_ZERO,
|
.probe_timing = TIMING_ZERO,
|
||||||
@ -811,7 +812,8 @@ struct flashchip flashchips[] = {
|
|||||||
.block_erase = spi_block_erase_c7,
|
.block_erase = spi_block_erase_c7,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.unlock = spi_disable_blockprotect,
|
.printlock = spi_prettyprint_status_register_at25df,
|
||||||
|
.unlock = spi_disable_blockprotect_at25df,
|
||||||
.write = spi_chip_write_256,
|
.write = spi_chip_write_256,
|
||||||
.read = spi_chip_read,
|
.read = spi_chip_read,
|
||||||
},
|
},
|
||||||
@ -824,6 +826,7 @@ struct flashchip flashchips[] = {
|
|||||||
.model_id = AT_25DF041A,
|
.model_id = AT_25DF041A,
|
||||||
.total_size = 512,
|
.total_size = 512,
|
||||||
.page_size = 256,
|
.page_size = 256,
|
||||||
|
.feature_bits = FEATURE_WRSR_WREN,
|
||||||
.tested = TEST_UNTESTED,
|
.tested = TEST_UNTESTED,
|
||||||
.probe = probe_spi_rdid,
|
.probe = probe_spi_rdid,
|
||||||
.probe_timing = TIMING_ZERO,
|
.probe_timing = TIMING_ZERO,
|
||||||
@ -846,7 +849,8 @@ struct flashchip flashchips[] = {
|
|||||||
.block_erase = spi_block_erase_c7,
|
.block_erase = spi_block_erase_c7,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.unlock = spi_disable_blockprotect,
|
.printlock = spi_prettyprint_status_register_at25df,
|
||||||
|
.unlock = spi_disable_blockprotect_at25df,
|
||||||
.write = spi_chip_write_256,
|
.write = spi_chip_write_256,
|
||||||
.read = spi_chip_read,
|
.read = spi_chip_read,
|
||||||
},
|
},
|
||||||
@ -859,6 +863,7 @@ struct flashchip flashchips[] = {
|
|||||||
.model_id = AT_25DF081,
|
.model_id = AT_25DF081,
|
||||||
.total_size = 1024,
|
.total_size = 1024,
|
||||||
.page_size = 256,
|
.page_size = 256,
|
||||||
|
.feature_bits = FEATURE_WRSR_WREN,
|
||||||
.tested = TEST_UNTESTED,
|
.tested = TEST_UNTESTED,
|
||||||
.probe = probe_spi_rdid,
|
.probe = probe_spi_rdid,
|
||||||
.probe_timing = TIMING_ZERO,
|
.probe_timing = TIMING_ZERO,
|
||||||
@ -881,7 +886,45 @@ struct flashchip flashchips[] = {
|
|||||||
.block_erase = spi_block_erase_c7,
|
.block_erase = spi_block_erase_c7,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.unlock = spi_disable_blockprotect,
|
.printlock = spi_prettyprint_status_register_at25df,
|
||||||
|
.unlock = spi_disable_blockprotect_at25df,
|
||||||
|
.write = spi_chip_write_256,
|
||||||
|
.read = spi_chip_read,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.vendor = "Atmel",
|
||||||
|
.name = "AT25DF081A",
|
||||||
|
.bustype = CHIP_BUSTYPE_SPI,
|
||||||
|
.manufacture_id = ATMEL_ID,
|
||||||
|
.model_id = AT_25DF081A,
|
||||||
|
.total_size = 1024,
|
||||||
|
.page_size = 256,
|
||||||
|
.feature_bits = FEATURE_WRSR_WREN,
|
||||||
|
.tested = TEST_UNTESTED,
|
||||||
|
.probe = probe_spi_rdid,
|
||||||
|
.probe_timing = TIMING_ZERO,
|
||||||
|
.block_erasers =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.eraseblocks = { {4 * 1024, 256} },
|
||||||
|
.block_erase = spi_block_erase_20,
|
||||||
|
}, {
|
||||||
|
.eraseblocks = { {32 * 1024, 32} },
|
||||||
|
.block_erase = spi_block_erase_52,
|
||||||
|
}, {
|
||||||
|
.eraseblocks = { {64 * 1024, 16} },
|
||||||
|
.block_erase = spi_block_erase_d8,
|
||||||
|
}, {
|
||||||
|
.eraseblocks = { {1024 * 1024, 1} },
|
||||||
|
.block_erase = spi_block_erase_60,
|
||||||
|
}, {
|
||||||
|
.eraseblocks = { {1024 * 1024, 1} },
|
||||||
|
.block_erase = spi_block_erase_c7,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.printlock = spi_prettyprint_status_register_at25df_sec,
|
||||||
|
.unlock = spi_disable_blockprotect_at25df_sec,
|
||||||
.write = spi_chip_write_256,
|
.write = spi_chip_write_256,
|
||||||
.read = spi_chip_read,
|
.read = spi_chip_read,
|
||||||
},
|
},
|
||||||
@ -894,6 +937,7 @@ struct flashchip flashchips[] = {
|
|||||||
.model_id = AT_25DF161,
|
.model_id = AT_25DF161,
|
||||||
.total_size = 2048,
|
.total_size = 2048,
|
||||||
.page_size = 256,
|
.page_size = 256,
|
||||||
|
.feature_bits = FEATURE_WRSR_WREN,
|
||||||
.tested = TEST_UNTESTED,
|
.tested = TEST_UNTESTED,
|
||||||
.probe = probe_spi_rdid,
|
.probe = probe_spi_rdid,
|
||||||
.probe_timing = TIMING_ZERO,
|
.probe_timing = TIMING_ZERO,
|
||||||
@ -916,7 +960,8 @@ struct flashchip flashchips[] = {
|
|||||||
.block_erase = spi_block_erase_c7,
|
.block_erase = spi_block_erase_c7,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.unlock = spi_disable_blockprotect,
|
.printlock = spi_prettyprint_status_register_at25df_sec,
|
||||||
|
.unlock = spi_disable_blockprotect_at25df_sec,
|
||||||
.write = spi_chip_write_256,
|
.write = spi_chip_write_256,
|
||||||
.read = spi_chip_read,
|
.read = spi_chip_read,
|
||||||
},
|
},
|
||||||
@ -929,6 +974,7 @@ struct flashchip flashchips[] = {
|
|||||||
.model_id = AT_25DF321,
|
.model_id = AT_25DF321,
|
||||||
.total_size = 4096,
|
.total_size = 4096,
|
||||||
.page_size = 256,
|
.page_size = 256,
|
||||||
|
.feature_bits = FEATURE_WRSR_WREN,
|
||||||
.tested = TEST_OK_PRW,
|
.tested = TEST_OK_PRW,
|
||||||
.probe = probe_spi_rdid,
|
.probe = probe_spi_rdid,
|
||||||
.probe_timing = TIMING_ZERO,
|
.probe_timing = TIMING_ZERO,
|
||||||
@ -951,7 +997,8 @@ struct flashchip flashchips[] = {
|
|||||||
.block_erase = spi_block_erase_c7,
|
.block_erase = spi_block_erase_c7,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.unlock = spi_disable_blockprotect,
|
.printlock = spi_prettyprint_status_register_at25df,
|
||||||
|
.unlock = spi_disable_blockprotect_at25df,
|
||||||
.write = spi_chip_write_256,
|
.write = spi_chip_write_256,
|
||||||
.read = spi_chip_read,
|
.read = spi_chip_read,
|
||||||
},
|
},
|
||||||
@ -964,6 +1011,7 @@ struct flashchip flashchips[] = {
|
|||||||
.model_id = AT_25DF321A,
|
.model_id = AT_25DF321A,
|
||||||
.total_size = 4096,
|
.total_size = 4096,
|
||||||
.page_size = 256,
|
.page_size = 256,
|
||||||
|
.feature_bits = FEATURE_WRSR_WREN,
|
||||||
.tested = TEST_UNTESTED,
|
.tested = TEST_UNTESTED,
|
||||||
.probe = probe_spi_rdid,
|
.probe = probe_spi_rdid,
|
||||||
.probe_timing = TIMING_ZERO,
|
.probe_timing = TIMING_ZERO,
|
||||||
@ -986,7 +1034,8 @@ struct flashchip flashchips[] = {
|
|||||||
.block_erase = spi_block_erase_c7,
|
.block_erase = spi_block_erase_c7,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.unlock = spi_disable_blockprotect,
|
.printlock = spi_prettyprint_status_register_at25df_sec,
|
||||||
|
.unlock = spi_disable_blockprotect_at25df_sec,
|
||||||
.write = spi_chip_write_256,
|
.write = spi_chip_write_256,
|
||||||
.read = spi_chip_read,
|
.read = spi_chip_read,
|
||||||
},
|
},
|
||||||
@ -999,6 +1048,7 @@ struct flashchip flashchips[] = {
|
|||||||
.model_id = AT_25DF641,
|
.model_id = AT_25DF641,
|
||||||
.total_size = 8192,
|
.total_size = 8192,
|
||||||
.page_size = 256,
|
.page_size = 256,
|
||||||
|
.feature_bits = FEATURE_WRSR_WREN,
|
||||||
.tested = TEST_UNTESTED,
|
.tested = TEST_UNTESTED,
|
||||||
.probe = probe_spi_rdid,
|
.probe = probe_spi_rdid,
|
||||||
.probe_timing = TIMING_ZERO,
|
.probe_timing = TIMING_ZERO,
|
||||||
@ -1021,7 +1071,45 @@ struct flashchip flashchips[] = {
|
|||||||
.block_erase = spi_block_erase_c7,
|
.block_erase = spi_block_erase_c7,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.unlock = spi_disable_blockprotect,
|
.printlock = spi_prettyprint_status_register_at25df_sec,
|
||||||
|
.unlock = spi_disable_blockprotect_at25df_sec,
|
||||||
|
.write = spi_chip_write_256,
|
||||||
|
.read = spi_chip_read,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.vendor = "Atmel",
|
||||||
|
.name = "AT25DQ161",
|
||||||
|
.bustype = CHIP_BUSTYPE_SPI,
|
||||||
|
.manufacture_id = ATMEL_ID,
|
||||||
|
.model_id = AT_25DQ161,
|
||||||
|
.total_size = 2048,
|
||||||
|
.page_size = 256,
|
||||||
|
.feature_bits = FEATURE_WRSR_WREN,
|
||||||
|
.tested = TEST_UNTESTED,
|
||||||
|
.probe = probe_spi_rdid,
|
||||||
|
.probe_timing = TIMING_ZERO,
|
||||||
|
.block_erasers =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.eraseblocks = { {4 * 1024, 512} },
|
||||||
|
.block_erase = spi_block_erase_20,
|
||||||
|
}, {
|
||||||
|
.eraseblocks = { {32 * 1024, 64} },
|
||||||
|
.block_erase = spi_block_erase_52,
|
||||||
|
}, {
|
||||||
|
.eraseblocks = { {64 * 1024, 32} },
|
||||||
|
.block_erase = spi_block_erase_d8,
|
||||||
|
}, {
|
||||||
|
.eraseblocks = { {2 * 1024 * 1024, 1} },
|
||||||
|
.block_erase = spi_block_erase_60,
|
||||||
|
}, {
|
||||||
|
.eraseblocks = { {2 * 1024 * 1024, 1} },
|
||||||
|
.block_erase = spi_block_erase_c7,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.printlock = spi_prettyprint_status_register_at25df_sec,
|
||||||
|
.unlock = spi_disable_blockprotect_at25df_sec,
|
||||||
.write = spi_chip_write_256,
|
.write = spi_chip_write_256,
|
||||||
.read = spi_chip_read,
|
.read = spi_chip_read,
|
||||||
},
|
},
|
||||||
@ -1034,6 +1122,7 @@ struct flashchip flashchips[] = {
|
|||||||
.model_id = AT_25F512B,
|
.model_id = AT_25F512B,
|
||||||
.total_size = 64,
|
.total_size = 64,
|
||||||
.page_size = 256,
|
.page_size = 256,
|
||||||
|
.feature_bits = FEATURE_WRSR_WREN,
|
||||||
.tested = TEST_UNTESTED,
|
.tested = TEST_UNTESTED,
|
||||||
.probe = probe_spi_rdid,
|
.probe = probe_spi_rdid,
|
||||||
.probe_timing = TIMING_ZERO,
|
.probe_timing = TIMING_ZERO,
|
||||||
@ -1056,7 +1145,8 @@ struct flashchip flashchips[] = {
|
|||||||
.block_erase = spi_block_erase_c7,
|
.block_erase = spi_block_erase_c7,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.unlock = spi_disable_blockprotect,
|
.printlock = spi_prettyprint_status_register_at25f,
|
||||||
|
.unlock = spi_disable_blockprotect_at25f,
|
||||||
.write = spi_chip_write_256,
|
.write = spi_chip_write_256,
|
||||||
.read = spi_chip_read,
|
.read = spi_chip_read,
|
||||||
},
|
},
|
||||||
@ -1077,6 +1167,9 @@ struct flashchip flashchips[] = {
|
|||||||
{
|
{
|
||||||
.eraseblocks = { {4 * 1024, 32} },
|
.eraseblocks = { {4 * 1024, 32} },
|
||||||
.block_erase = spi_block_erase_20,
|
.block_erase = spi_block_erase_20,
|
||||||
|
}, {
|
||||||
|
.eraseblocks = { {4 * 1024, 32} },
|
||||||
|
.block_erase = spi_block_erase_d7,
|
||||||
}, {
|
}, {
|
||||||
.eraseblocks = { {32 * 1024, 4} },
|
.eraseblocks = { {32 * 1024, 4} },
|
||||||
.block_erase = spi_block_erase_52,
|
.block_erase = spi_block_erase_52,
|
||||||
@ -1091,7 +1184,8 @@ struct flashchip flashchips[] = {
|
|||||||
.block_erase = spi_block_erase_c7,
|
.block_erase = spi_block_erase_c7,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.unlock = spi_disable_blockprotect,
|
.printlock = spi_prettyprint_status_register_at25fs010,
|
||||||
|
.unlock = spi_disable_blockprotect_at25fs010,
|
||||||
.write = spi_chip_write_256,
|
.write = spi_chip_write_256,
|
||||||
.read = spi_chip_read,
|
.read = spi_chip_read,
|
||||||
},
|
},
|
||||||
@ -1126,7 +1220,8 @@ struct flashchip flashchips[] = {
|
|||||||
.block_erase = spi_block_erase_c7,
|
.block_erase = spi_block_erase_c7,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.unlock = spi_disable_blockprotect,
|
.printlock = spi_prettyprint_status_register_at25fs040,
|
||||||
|
.unlock = spi_disable_blockprotect_at25fs040,
|
||||||
.write = spi_chip_write_256,
|
.write = spi_chip_write_256,
|
||||||
.read = spi_chip_read,
|
.read = spi_chip_read,
|
||||||
},
|
},
|
||||||
|
@ -110,12 +110,19 @@
|
|||||||
#define AT_25DF021 0x4300
|
#define AT_25DF021 0x4300
|
||||||
#define AT_25DF041A 0x4401
|
#define AT_25DF041A 0x4401
|
||||||
#define AT_25DF081 0x4502
|
#define AT_25DF081 0x4502
|
||||||
|
#define AT_25DF081A 0x4501 /* Yes, 81A has a lower number than 81 */
|
||||||
#define AT_25DF161 0x4602
|
#define AT_25DF161 0x4602
|
||||||
#define AT_25DF321 0x4700 /* Same as 26DF321 */
|
#define AT_25DF321 0x4700 /* Same as 26DF321 */
|
||||||
#define AT_25DF321A 0x4701
|
#define AT_25DF321A 0x4701
|
||||||
#define AT_25DF641 0x4800
|
#define AT_25DF641 0x4800
|
||||||
#define AT_25F512A 0x65 /* Needs special RDID. AT25F512A_RDID 15 1d */
|
#define AT_25DQ161 0x8600
|
||||||
|
#define AT25F512 /* No device ID found in datasheet. Vendor ID
|
||||||
|
* can be read with AT25F512A_RDID */
|
||||||
|
#define AT_25F512A 0x65 /* Needs AT25F512A_RDID */
|
||||||
#define AT_25F512B 0x6500
|
#define AT_25F512B 0x6500
|
||||||
|
#define AT25F1024 /* No device ID found in datasheet. Vendor ID
|
||||||
|
* can be read with AT25F512A_RDID */
|
||||||
|
#define AT_25F1024A 0x60 /* Needs AT25F512A_RDID */
|
||||||
#define AT_25FS010 0x6601
|
#define AT_25FS010 0x6601
|
||||||
#define AT_25FS040 0x6604
|
#define AT_25FS040 0x6604
|
||||||
#define AT_26DF041 0x4400
|
#define AT_26DF041 0x4400
|
||||||
|
2
spi.c
2
spi.c
@ -30,8 +30,6 @@
|
|||||||
|
|
||||||
enum spi_controller spi_controller = SPI_CONTROLLER_NONE;
|
enum spi_controller spi_controller = SPI_CONTROLLER_NONE;
|
||||||
|
|
||||||
void spi_prettyprint_status_register(struct flashchip *flash);
|
|
||||||
|
|
||||||
const struct spi_programmer spi_programmer[] = {
|
const struct spi_programmer spi_programmer[] = {
|
||||||
{ /* SPI_CONTROLLER_NONE */
|
{ /* SPI_CONTROLLER_NONE */
|
||||||
.command = NULL,
|
.command = NULL,
|
||||||
|
3
spi.h
3
spi.h
@ -31,7 +31,7 @@
|
|||||||
#define JEDEC_RDID_INSIZE 0x03
|
#define JEDEC_RDID_INSIZE 0x03
|
||||||
|
|
||||||
/* AT25F512A has bit 3 as don't care bit in commands */
|
/* AT25F512A has bit 3 as don't care bit in commands */
|
||||||
#define AT25F512A_RDID 0x15
|
#define AT25F512A_RDID 0x15 /* 0x15 or 0x1d */
|
||||||
#define AT25F512A_RDID_OUTSIZE 0x01
|
#define AT25F512A_RDID_OUTSIZE 0x01
|
||||||
#define AT25F512A_RDID_INSIZE 0x02
|
#define AT25F512A_RDID_INSIZE 0x02
|
||||||
|
|
||||||
@ -123,5 +123,6 @@
|
|||||||
#define SPI_INVALID_OPCODE -2
|
#define SPI_INVALID_OPCODE -2
|
||||||
#define SPI_INVALID_ADDRESS -3
|
#define SPI_INVALID_ADDRESS -3
|
||||||
#define SPI_INVALID_LENGTH -4
|
#define SPI_INVALID_LENGTH -4
|
||||||
|
#define SPI_FLASHROM_BUG -5
|
||||||
|
|
||||||
#endif /* !__SPI_H__ */
|
#endif /* !__SPI_H__ */
|
||||||
|
326
spi25.c
326
spi25.c
@ -312,7 +312,16 @@ uint8_t spi_read_status_register(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Prettyprint the status register. Common definitions. */
|
/* Prettyprint the status register. Common definitions. */
|
||||||
void spi_prettyprint_status_register_common(uint8_t status)
|
static void spi_prettyprint_status_register_welwip(uint8_t status)
|
||||||
|
{
|
||||||
|
msg_cdbg("Chip status register: Write Enable Latch (WEL) is "
|
||||||
|
"%sset\n", (status & (1 << 1)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Write In Progress (WIP/BUSY) is "
|
||||||
|
"%sset\n", (status & (1 << 0)) ? "" : "not ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prettyprint the status register. Common definitions. */
|
||||||
|
static void spi_prettyprint_status_register_common(uint8_t status)
|
||||||
{
|
{
|
||||||
msg_cdbg("Chip status register: Bit 5 / Block Protect 3 (BP3) is "
|
msg_cdbg("Chip status register: Bit 5 / Block Protect 3 (BP3) is "
|
||||||
"%sset\n", (status & (1 << 5)) ? "" : "not ");
|
"%sset\n", (status & (1 << 5)) ? "" : "not ");
|
||||||
@ -322,10 +331,7 @@ void spi_prettyprint_status_register_common(uint8_t status)
|
|||||||
"%sset\n", (status & (1 << 3)) ? "" : "not ");
|
"%sset\n", (status & (1 << 3)) ? "" : "not ");
|
||||||
msg_cdbg("Chip status register: Bit 2 / Block Protect 0 (BP0) is "
|
msg_cdbg("Chip status register: Bit 2 / Block Protect 0 (BP0) is "
|
||||||
"%sset\n", (status & (1 << 2)) ? "" : "not ");
|
"%sset\n", (status & (1 << 2)) ? "" : "not ");
|
||||||
msg_cdbg("Chip status register: Write Enable Latch (WEL) is "
|
spi_prettyprint_status_register_welwip(status);
|
||||||
"%sset\n", (status & (1 << 1)) ? "" : "not ");
|
|
||||||
msg_cdbg("Chip status register: Write In Progress (WIP/BUSY) is "
|
|
||||||
"%sset\n", (status & (1 << 0)) ? "" : "not ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prettyprint the status register. Works for
|
/* Prettyprint the status register. Works for
|
||||||
@ -338,6 +344,121 @@ void spi_prettyprint_status_register_amic_a25l(uint8_t status)
|
|||||||
spi_prettyprint_status_register_common(status);
|
spi_prettyprint_status_register_common(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Prettyprint the status register. Common definitions. */
|
||||||
|
static void spi_prettyprint_status_register_at25_srplepewpp(uint8_t status)
|
||||||
|
{
|
||||||
|
msg_cdbg("Chip status register: Sector Protection Register Lock (SRPL) "
|
||||||
|
"is %sset\n", (status & (1 << 7)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Bit 6 "
|
||||||
|
"is %sset\n", (status & (1 << 6)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Erase/Program Error (EPE) "
|
||||||
|
"is %sset\n", (status & (1 << 5)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: WP# pin (WPP) "
|
||||||
|
"is %sactive\n", (status & (1 << 4)) ? "not " : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_prettyprint_status_register_at25df(struct flashchip *flash)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
|
||||||
|
status = spi_read_status_register();
|
||||||
|
msg_cdbg("Chip status register is %02x\n", status);
|
||||||
|
|
||||||
|
spi_prettyprint_status_register_at25_srplepewpp(status);
|
||||||
|
msg_cdbg("Chip status register: Software Protection Status (SWP): ");
|
||||||
|
switch (status & (3 << 2)) {
|
||||||
|
case 0x0 << 2:
|
||||||
|
msg_cdbg("no sectors are protected\n");
|
||||||
|
break;
|
||||||
|
case 0x1 << 2:
|
||||||
|
msg_cdbg("some sectors are protected\n");
|
||||||
|
/* FIXME: Read individual Sector Protection Registers. */
|
||||||
|
break;
|
||||||
|
case 0x3 << 2:
|
||||||
|
msg_cdbg("all sectors are protected\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
msg_cdbg("reserved for future use\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spi_prettyprint_status_register_welwip(status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_prettyprint_status_register_at25df_sec(struct flashchip *flash)
|
||||||
|
{
|
||||||
|
/* FIXME: We should check the security lockdown. */
|
||||||
|
msg_cdbg("Ignoring security lockdown (if present)\n");
|
||||||
|
msg_cdbg("Ignoring status register byte 2\n");
|
||||||
|
return spi_prettyprint_status_register_at25df(flash);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_prettyprint_status_register_at25f(struct flashchip *flash)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
|
||||||
|
status = spi_read_status_register();
|
||||||
|
msg_cdbg("Chip status register is %02x\n", status);
|
||||||
|
|
||||||
|
spi_prettyprint_status_register_at25_srplepewpp(status);
|
||||||
|
msg_cdbg("Chip status register: Bit 3 "
|
||||||
|
"is %sset\n", (status & (1 << 3)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Block Protect 0 (BP0) is "
|
||||||
|
"%sset, %s sectors are protected\n",
|
||||||
|
(status & (1 << 2)) ? "" : "not ",
|
||||||
|
(status & (1 << 2)) ? "all" : "no");
|
||||||
|
spi_prettyprint_status_register_welwip(status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_prettyprint_status_register_at25fs010(struct flashchip *flash)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
|
||||||
|
status = spi_read_status_register();
|
||||||
|
msg_cdbg("Chip status register is %02x\n", status);
|
||||||
|
|
||||||
|
msg_cdbg("Chip status register: Status Register Write Protect (WPEN) "
|
||||||
|
"is %sset\n", (status & (1 << 7)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Bit 6 / Block Protect 4 (BP4) is "
|
||||||
|
"%sset\n", (status & (1 << 6)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Bit 5 / Block Protect 3 (BP3) is "
|
||||||
|
"%sset\n", (status & (1 << 5)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Bit 4 is "
|
||||||
|
"%sset\n", (status & (1 << 4)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Bit 3 / Block Protect 1 (BP1) is "
|
||||||
|
"%sset\n", (status & (1 << 3)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Bit 2 / Block Protect 0 (BP0) is "
|
||||||
|
"%sset\n", (status & (1 << 2)) ? "" : "not ");
|
||||||
|
/* FIXME: Pretty-print detailed sector protection status. */
|
||||||
|
spi_prettyprint_status_register_welwip(status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_prettyprint_status_register_at25fs040(struct flashchip *flash)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
|
||||||
|
status = spi_read_status_register();
|
||||||
|
msg_cdbg("Chip status register is %02x\n", status);
|
||||||
|
|
||||||
|
msg_cdbg("Chip status register: Status Register Write Protect (WPEN) "
|
||||||
|
"is %sset\n", (status & (1 << 7)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Bit 6 / Block Protect 4 (BP4) is "
|
||||||
|
"%sset\n", (status & (1 << 6)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Bit 5 / Block Protect 3 (BP3) is "
|
||||||
|
"%sset\n", (status & (1 << 5)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Bit 4 / Block Protect 2 (BP2) is "
|
||||||
|
"%sset\n", (status & (1 << 4)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Bit 3 / Block Protect 1 (BP1) is "
|
||||||
|
"%sset\n", (status & (1 << 3)) ? "" : "not ");
|
||||||
|
msg_cdbg("Chip status register: Bit 2 / Block Protect 0 (BP0) is "
|
||||||
|
"%sset\n", (status & (1 << 2)) ? "" : "not ");
|
||||||
|
/* FIXME: Pretty-print detailed sector protection status. */
|
||||||
|
spi_prettyprint_status_register_welwip(status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Prettyprint the status register. Works for
|
/* Prettyprint the status register. Works for
|
||||||
* ST M25P series
|
* ST M25P series
|
||||||
* MX MX25L series
|
* MX MX25L series
|
||||||
@ -732,12 +853,12 @@ int spi_write_status_enable(void)
|
|||||||
* This is according the SST25VF016 datasheet, who knows it is more
|
* This is according the SST25VF016 datasheet, who knows it is more
|
||||||
* generic that this...
|
* generic that this...
|
||||||
*/
|
*/
|
||||||
int spi_write_status_register(int status)
|
static int spi_write_status_register_ewsr(struct flashchip *flash, int status)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
struct spi_command cmds[] = {
|
struct spi_command cmds[] = {
|
||||||
{
|
{
|
||||||
/* FIXME: WRSR requires either EWSR or WREN depending on chip type. */
|
/* WRSR requires either EWSR or WREN depending on chip type. */
|
||||||
.writecnt = JEDEC_EWSR_OUTSIZE,
|
.writecnt = JEDEC_EWSR_OUTSIZE,
|
||||||
.writearr = (const unsigned char[]){ JEDEC_EWSR },
|
.writearr = (const unsigned char[]){ JEDEC_EWSR },
|
||||||
.readcnt = 0,
|
.readcnt = 0,
|
||||||
@ -759,9 +880,59 @@ int spi_write_status_register(int status)
|
|||||||
msg_cerr("%s failed during command execution\n",
|
msg_cerr("%s failed during command execution\n",
|
||||||
__func__);
|
__func__);
|
||||||
}
|
}
|
||||||
|
/* WRSR performs a self-timed erase before the changes take effect. */
|
||||||
|
programmer_delay(100 * 1000);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int spi_write_status_register_wren(struct flashchip *flash, int status)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
struct spi_command cmds[] = {
|
||||||
|
{
|
||||||
|
/* WRSR requires either EWSR or WREN depending on chip type. */
|
||||||
|
.writecnt = JEDEC_WREN_OUTSIZE,
|
||||||
|
.writearr = (const unsigned char[]){ JEDEC_WREN },
|
||||||
|
.readcnt = 0,
|
||||||
|
.readarr = NULL,
|
||||||
|
}, {
|
||||||
|
.writecnt = JEDEC_WRSR_OUTSIZE,
|
||||||
|
.writearr = (const unsigned char[]){ JEDEC_WRSR, (unsigned char) status },
|
||||||
|
.readcnt = 0,
|
||||||
|
.readarr = NULL,
|
||||||
|
}, {
|
||||||
|
.writecnt = 0,
|
||||||
|
.writearr = NULL,
|
||||||
|
.readcnt = 0,
|
||||||
|
.readarr = NULL,
|
||||||
|
}};
|
||||||
|
|
||||||
|
result = spi_send_multicommand(cmds);
|
||||||
|
if (result) {
|
||||||
|
msg_cerr("%s failed during command execution\n",
|
||||||
|
__func__);
|
||||||
|
}
|
||||||
|
/* WRSR performs a self-timed erase before the changes take effect. */
|
||||||
|
programmer_delay(100 * 1000);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_write_status_register(struct flashchip *flash, int status)
|
||||||
|
{
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
if (!(flash->feature_bits & (FEATURE_WRSR_WREN | FEATURE_WRSR_EWSR))) {
|
||||||
|
msg_cdbg("Missing status register write definition, assuming "
|
||||||
|
"EWSR is needed\n");
|
||||||
|
flash->feature_bits |= FEATURE_WRSR_EWSR;
|
||||||
|
}
|
||||||
|
if (flash->feature_bits & FEATURE_WRSR_WREN)
|
||||||
|
ret = spi_write_status_register_wren(flash, status);
|
||||||
|
if (ret && (flash->feature_bits & FEATURE_WRSR_EWSR))
|
||||||
|
ret = spi_write_status_register_ewsr(flash, status);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int spi_byte_program(int addr, uint8_t databyte)
|
int spi_byte_program(int addr, uint8_t databyte)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
@ -844,26 +1015,153 @@ int spi_nbyte_program(int addr, uint8_t *bytes, int len)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A generic brute-force block protection disable works like this:
|
||||||
|
* Write 0x00 to the status register. Check if any locks are still set (that
|
||||||
|
* part is chip specific). Repeat once.
|
||||||
|
*/
|
||||||
int spi_disable_blockprotect(struct flashchip *flash)
|
int spi_disable_blockprotect(struct flashchip *flash)
|
||||||
{
|
{
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
status = spi_read_status_register();
|
status = spi_read_status_register();
|
||||||
/* If there is block protection in effect, unprotect it first. */
|
/* If block protection is disabled, stop here. */
|
||||||
|
if ((status & 0x3c) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
msg_cdbg("Some block protection in effect, disabling\n");
|
||||||
|
result = spi_write_status_register(flash, status & ~0x3c);
|
||||||
|
if (result) {
|
||||||
|
msg_cerr("spi_write_status_register failed\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
status = spi_read_status_register();
|
||||||
if ((status & 0x3c) != 0) {
|
if ((status & 0x3c) != 0) {
|
||||||
msg_cdbg("Some block protection in effect, disabling\n");
|
msg_cerr("Block protection could not be disabled!\n");
|
||||||
result = spi_write_status_register(status & ~0x3c);
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_disable_blockprotect_at25df(struct flashchip *flash)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
status = spi_read_status_register();
|
||||||
|
/* If block protection is disabled, stop here. */
|
||||||
|
if ((status & (3 << 2)) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
msg_cdbg("Some block protection in effect, disabling\n");
|
||||||
|
if (status & (1 << 7)) {
|
||||||
|
msg_cdbg("Need to disable Sector Protection Register Lock\n");
|
||||||
|
if ((status & (1 << 4)) == 0) {
|
||||||
|
msg_cerr("WP# pin is active, disabling "
|
||||||
|
"write protection is impossible.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* All bits except bit 7 (SPRL) are readonly. */
|
||||||
|
result = spi_write_status_register(flash, status & ~(1 << 7));
|
||||||
if (result) {
|
if (result) {
|
||||||
msg_cerr("spi_write_status_register failed\n");
|
msg_cerr("spi_write_status_register failed\n");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
status = spi_read_status_register();
|
|
||||||
if ((status & 0x3c) != 0) {
|
}
|
||||||
msg_cerr("Block protection could not be disabled!\n");
|
/* Global unprotect. Make sure to mask SPRL as well. */
|
||||||
return 1;
|
result = spi_write_status_register(flash, status & ~0xbc);
|
||||||
|
if (result) {
|
||||||
|
msg_cerr("spi_write_status_register failed\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
status = spi_read_status_register();
|
||||||
|
if ((status & (3 << 2)) != 0) {
|
||||||
|
msg_cerr("Block protection could not be disabled!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_disable_blockprotect_at25df_sec(struct flashchip *flash)
|
||||||
|
{
|
||||||
|
/* FIXME: We should check the security lockdown. */
|
||||||
|
msg_cinfo("Ignoring security lockdown (if present)\n");
|
||||||
|
return spi_disable_blockprotect_at25df(flash);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_disable_blockprotect_at25f(struct flashchip *flash)
|
||||||
|
{
|
||||||
|
/* spi_disable_blockprotect_at25df is not really the right way to do
|
||||||
|
* this, but the side effects of said function work here as well.
|
||||||
|
*/
|
||||||
|
return spi_disable_blockprotect_at25df(flash);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_disable_blockprotect_at25fs010(struct flashchip *flash)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
status = spi_read_status_register();
|
||||||
|
/* If block protection is disabled, stop here. */
|
||||||
|
if ((status & 0x6c) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
msg_cdbg("Some block protection in effect, disabling\n");
|
||||||
|
if (status & (1 << 7)) {
|
||||||
|
msg_cdbg("Need to disable Status Register Write Protect\n");
|
||||||
|
/* Clear bit 7 (WPEN). */
|
||||||
|
result = spi_write_status_register(flash, status & ~(1 << 7));
|
||||||
|
if (result) {
|
||||||
|
msg_cerr("spi_write_status_register failed\n");
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Global unprotect. Make sure to mask WPEN as well. */
|
||||||
|
result = spi_write_status_register(flash, status & ~0xec);
|
||||||
|
if (result) {
|
||||||
|
msg_cerr("spi_write_status_register failed\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
status = spi_read_status_register();
|
||||||
|
if ((status & 0x6c) != 0) {
|
||||||
|
msg_cerr("Block protection could not be disabled!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int spi_disable_blockprotect_at25fs040(struct flashchip *flash)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
status = spi_read_status_register();
|
||||||
|
/* If block protection is disabled, stop here. */
|
||||||
|
if ((status & 0x7c) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
msg_cdbg("Some block protection in effect, disabling\n");
|
||||||
|
if (status & (1 << 7)) {
|
||||||
|
msg_cdbg("Need to disable Status Register Write Protect\n");
|
||||||
|
/* Clear bit 7 (WPEN). */
|
||||||
|
result = spi_write_status_register(flash, status & ~(1 << 7));
|
||||||
|
if (result) {
|
||||||
|
msg_cerr("spi_write_status_register failed\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Global unprotect. Make sure to mask WPEN as well. */
|
||||||
|
result = spi_write_status_register(flash, status & ~0xfc);
|
||||||
|
if (result) {
|
||||||
|
msg_cerr("spi_write_status_register failed\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
status = spi_read_status_register();
|
||||||
|
if ((status & 0x7c) != 0) {
|
||||||
|
msg_cerr("Block protection could not be disabled!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user