The programmer is my newly built serprog with STM32 MCU. Please refer to https://github.com/dword1511/serprog-stm32vcp .
These flash chips are first bought to test the programmer rather than flashrom itself :) The programmer has been verified by me with a commercial CH341A-based programmer, and a few bricks as well :)
Some performance information about flashrom with these chips can be found at: https://github.com/dword1511/serprog-stm32vcp/blob/master/PERFORMANCE (btw, SST25VF040B is really slow at writing! Is it supposed to be this slow?)
The pasted logs are organized in probe-write-read-erase sequences.
AT25F512A: http://paste.flashrom.org/view.php?id=1569 AT26DF161A: http://paste.flashrom.org/view.php?id=1570 EN25F05: http://paste.flashrom.org/view.php?id=1571 MX25L12845E(mistaken as 'MX25L12805(D)'): http://paste.flashrom.org/view.php?id=1572 Pm25LV010A: http://paste.flashrom.org/view.php?id=1573 SST25VF040B: http://paste.flashrom.org/view.php?id=1574 SST25VF040B with REMS: http://paste.flashrom.org/view.php?id=1575 M25P05-A: http://paste.flashrom.org/view.php?id=1576
On Wed, 03 Apr 2013 00:11:11 +0800 Chi Zhang zhangchi866@gmail.com wrote:
The programmer is my newly built serprog with STM32 MCU. Please refer to https://github.com/dword1511/serprog-stm32vcp .
Nice stuff :) What was the motivation for that project? Should we add it to http://flashrom.org/Serprog ?
These flash chips are first bought to test the programmer rather than flashrom itself :) The programmer has been verified by me with a commercial CH341A-based programmer, and a few bricks as well :)
Some performance information about flashrom with these chips can be found at: https://github.com/dword1511/serprog-stm32vcp/blob/master/PERFORMANCE (btw, SST25VF040B is really slow at writing! Is it supposed to be this slow?)
I think the problem is the AAI write mode. It requires a lot of tiny communication steps and this is were serprog, CDC and USB are really bad at... (long round trip times).
The pasted logs are organized in probe-write-read-erase sequences.
AT25F512A: http://paste.flashrom.org/view.php?id=1569
Added to my tested_stuff branch.
AT26DF161A: http://paste.flashrom.org/view.php?id=1570
That one needs some further analysis: "Some block protection in effect, disabling... Block protection could not be disabled!"
Added to my tested_stuff branch.
MX25L12845E(mistaken as 'MX25L12805(D)'): http://paste.flashrom.org/view.php?id=1572
Macronix really likes to share IDs... we need to look at the 45 series more closely.
Pm25LV010A: http://paste.flashrom.org/view.php?id=1573
Added to my "Refine PMC Pm25LV series" patch. http://patchwork.coreboot.org/patch/3926/
You probably want to take a look at this patch too as it adds support for the Pm25LD512C you have in your performance file: http://patchwork.coreboot.org/patch/3925/
SST25VF040B: http://paste.flashrom.org/view.php?id=1574 SST25VF040B with REMS: http://paste.flashrom.org/view.php?id=1575 M25P05-A: http://paste.flashrom.org/view.php?id=1576
All added to my tested_stuff branch.
Also, there exists a patch set that adds support for the AT45DB161D, but we have not decided if we want to go with that implementation. See http://patchwork.coreboot.org/patch/3873/ etc.
The two sanyo chips are completely unsupported yet I think...
Thanks a lot for your effort!
在 2013年4月2日 星期二 20:40:39,Stefan Tauner 写道:
On Wed, 03 Apr 2013 00:11:11 +0800
Chi Zhang zhangchi866@gmail.com wrote:
The programmer is my newly built serprog with STM32 MCU. Please refer to https://github.com/dword1511/serprog-stm32vcp .
Nice stuff :) What was the motivation for that project? Should we add it to http://flashrom.org/Serprog ?
At first I built a serprog with ATMEGA8L. But that one was slow and requires a UART to USB bridge and so some extra wirings. As I remember there was a STM32 USB virtual COM port example, I decided to build a serprog without a physical UART and aim at high speed.
You can put it on the wiki page if you like, I will be very proud of it :)
These flash chips are first bought to test the programmer rather than flashrom itself :) The programmer has been verified by me with a commercial CH341A-based programmer, and a few bricks as well :)
Some performance information about flashrom with these chips can be found at: https://github.com/dword1511/serprog-stm32vcp/blob/master/PERFORMANCE (btw, SST25VF040B is really slow at writing! Is it supposed to be this slow?)
I think the problem is the AAI write mode. It requires a lot of tiny communication steps and this is were serprog, CDC and USB are really bad at... (long round trip times).
I see. Thanks.
The pasted logs are organized in probe-write-read-erase sequences.
AT25F512A: http://paste.flashrom.org/view.php?id=1569
Added to my tested_stuff branch.
AT26DF161A: http://paste.flashrom.org/view.php?id=1570
That one needs some further analysis: "Some block protection in effect, disabling... Block protection could not be disabled!"
Saw that too. But interestingly write and erase still work. Maybe because nWP is pulled high?
$ flashrom -p serprog:dev=/dev/ttyACM0:4000000,spispeed=36000000 -E ...... $ flashrom -p serprog:dev=/dev/ttyACM0:4000000,spispeed=36000000 -r tmp ...... $ hd tmp 00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| * 00200000 $ flashrom -p serprog:dev=/dev/ttyACM0:4000000,spispeed=36000000 -w rand2mb.bin ...... $ flashrom -p serprog:dev=/dev/ttyACM0:4000000,spispeed=36000000 -r tmp ...... $ md5sum rand2mb.bin tmp 31db08a08c250f8848e361271a8d8b4d rand2mb.bin 31db08a08c250f8848e361271a8d8b4d tmp $ flashrom -p serprog:dev=/dev/ttyACM0:4000000,spispeed=36000000 -E ...... $ flashrom -p serprog:dev=/dev/ttyACM0:4000000,spispeed=36000000 -r tmp ...... $ hd tmp 00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| * 00200000
Added to my tested_stuff branch.
MX25L12845E(mistaken as 'MX25L12805(D)'): http://paste.flashrom.org/view.php?id=1572
Macronix really likes to share IDs... we need to look at the 45 series more closely.
Pm25LV010A: http://paste.flashrom.org/view.php?id=1573
Added to my "Refine PMC Pm25LV series" patch. http://patchwork.coreboot.org/patch/3926/
You probably want to take a look at this patch too as it adds support for the Pm25LD512C you have in your performance file: http://patchwork.coreboot.org/patch/3925/
Will test.
SST25VF040B: http://paste.flashrom.org/view.php?id=1574 SST25VF040B with REMS: http://paste.flashrom.org/view.php?id=1575 M25P05-A: http://paste.flashrom.org/view.php?id=1576
All added to my tested_stuff branch.
Also, there exists a patch set that adds support for the AT45DB161D, but we have not decided if we want to go with that implementation. See http://patchwork.coreboot.org/patch/3873/ etc.
AT45 have different pinout with 25 series. I will have to add some wirings.
The two sanyo chips are completely unsupported yet I think...
I found them on my hard disk PCB. No plan for testing them though. They are still in use.
Thanks a lot for your effort!
On Wed, 03 Apr 2013 12:21:07 +0800 Chi Zhang zhangchi866@gmail.com wrote:
在 2013年4月2日 星期二 20:40:39,Stefan Tauner 写道:
On Wed, 03 Apr 2013 00:11:11 +0800
Chi Zhang zhangchi866@gmail.com wrote:
The programmer is my newly built serprog with STM32 MCU. Please refer to https://github.com/dword1511/serprog-stm32vcp .
Nice stuff :) What was the motivation for that project? Should we add it to http://flashrom.org/Serprog ?
At first I built a serprog with ATMEGA8L. But that one was slow and requires a UART to USB bridge and so some extra wirings. As I remember there was a STM32 USB virtual COM port example, I decided to build a serprog without a physical UART and aim at high speed.
I see (the google translation of your blog is a bit hard to read ;). For even higher speed one would need to implement something with more "intelligence" in the micro controller like we described here: http://www.flashrom.org/GSoC#Design_and_implementation_of_a_native_USB_flash...
You can put it on the wiki page if you like, I will be very proud of it :)
Will do, thank you.
AT26DF161A: http://paste.flashrom.org/view.php?id=1570
That one needs some further analysis: "Some block protection in effect, disabling... Block protection could not be disabled!"
Saw that too. But interestingly write and erase still work. Maybe because nWP is pulled high?
The message was just cosmetically a problem. flashrom had the wrong representation of the status register encoded. It thought there are write protections active while that was just the status of the nWP pin. It tried to force that low which obviously did not work, but continued anyway. I don't know yet why my patch did not work. I will reply to your other mails when I do...
Also, there exists a patch set that adds support for the AT45DB161D, but we have not decided if we want to go with that implementation. See http://patchwork.coreboot.org/patch/3873/ etc.
AT45 have different pinout with 25 series. I will have to add some wirings.
Right. Sorry for not mentioning it.
The two sanyo chips are completely unsupported yet I think...
I found them on my hard disk PCB. No plan for testing them though. They are still in use.
Ah ok. According to their datasheets they are licensed from SST but use the Sanyo manufacturer ID. So adding support for them manually is needed but it is probably not hard.
On Wed, 03 Apr 2013 12:21:07 +0800 Chi Zhang zhangchi866@gmail.com wrote:
You can put it on the wiki page if you like, I will be very proud of it :)
I have finally added it, thanks: http://flashrom.org/Serprog#serprog-stm32vcp_by_Chi_Zhang
Applied patch: http://patchwork.coreboot.org/patch/3927/ And now AT26DF161A is NOT working any more.
On Wed, 03 Apr 2013 12:40:07 +0800 Chi Zhang zhangchi866@gmail.com wrote:
Applied patch: http://patchwork.coreboot.org/patch/3927/ And now AT26DF161A is NOT working any more.
I have to admit that I don't understand the problem yet at all. It should have worked IMHO. If you have some time please retry with -VV again after applying the following patch on top of the previous patch (3927). This should print what we actually try to write to the status register to disable the alleged write protection. Maybe I am misreading the datasheet, and if so the debug output should make it easier to understand what's going on.
--- spi25_statusreg.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/spi25_statusreg.c b/spi25_statusreg.c index c089157..b514204 100644 --- a/spi25_statusreg.c +++ b/spi25_statusreg.c @@ -96,6 +96,7 @@ int spi_write_status_register(struct flashctx *flash, int status) int feature_bits = flash->chip->feature_bits; int ret = 1;
+ msg_cdbg2("Trying to write 0x%02x to the status register.\n", status); if (!(feature_bits & (FEATURE_WRSR_WREN | FEATURE_WRSR_EWSR))) { msg_cdbg("Missing status register write definition, assuming " "EWSR is needed\n"); @@ -165,6 +166,7 @@ static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_m status = spi_read_status_register(flash); if ((status & bp_mask) != 0) { msg_cerr("Block protection could not be disabled!\n"); + flash->chip->printlock(flash); return 1; } msg_cdbg("disabled.\n");
在 2013年4月19日 星期五 02:28:02,Stefan Tauner 写道:
On Wed, 03 Apr 2013 12:40:07 +0800
Chi Zhang zhangchi866@gmail.com wrote:
Applied patch: http://patchwork.coreboot.org/patch/3927/ And now AT26DF161A is NOT working any more.
I have to admit that I don't understand the problem yet at all. It should have worked IMHO. If you have some time please retry with -VV again after applying the following patch on top of the previous patch (3927). This should print what we actually try to write to the status register to disable the alleged write protection. Maybe I am misreading the datasheet, and if so the debug output should make it easier to understand what's going on.
Done with latest SVN version (r1671) and patch 3927 and the patch in your mail.
http://paste.flashrom.org/view.php?id=1618
Unpatched r1671 still works:
On Fri, 19 Apr 2013 10:44:29 +0800 Chi Zhang zhangchi866@gmail.com wrote:
在 2013年4月19日 星期五 02:28:02,Stefan Tauner 写道:
On Wed, 03 Apr 2013 12:40:07 +0800
Chi Zhang zhangchi866@gmail.com wrote:
Applied patch: http://patchwork.coreboot.org/patch/3927/ And now AT26DF161A is NOT working any more.
I have to admit that I don't understand the problem yet at all. It should have worked IMHO. If you have some time please retry with -VV again after applying the following patch on top of the previous patch (3927). This should print what we actually try to write to the status register to disable the alleged write protection. Maybe I am misreading the datasheet, and if so the debug output should make it easier to understand what's going on.
Done with latest SVN version (r1671) and patch 3927 and the patch in your mail.
Thanks for testing. This is quite odd: we do the right thing IMHO. The relevant code is in spi25_statusreg.c spi_disable_blockprotect_at25df() calls spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 1 << 4) In the beginning the status register is 0x1C, i.e. the status register is not locked, the hardware protection pin is not asserted, only the write protection bits are set. spi_disable_blockprotect_generic() correctly detects that and tries to set the protection bits to 0 by trying to write 0x10 (not touching the r/o WP pin bit), but that apparently has no effect.
Unpatched r1671 still works:
Interestingly here the initial contents of the status register are what we would expect them to be after unlocking(!). Maybe the chip reacts too slow? Do you have another explanation for that behavior?
The patch below adds a delay of five seconds after trying to write to the status register for unlocking.
diff --git a/spi25_statusreg.c b/spi25_statusreg.c index b325a2e..b692851 100644 --- a/spi25_statusreg.c +++ b/spi25_statusreg.c @@ -163,6 +163,7 @@ static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_m msg_cerr("spi_write_status_register failed.\n"); return result; } + programmer_delay(5*1000*1000); status = spi_read_status_register(flash); if ((status & bp_mask) != 0) { msg_cerr("Block protection could not be disabled!\n");
在 2013年4月20日 星期六 11:36:53,Stefan Tauner 写道:
Thanks for testing. This is quite odd: we do the right thing IMHO. The relevant code is in spi25_statusreg.c spi_disable_blockprotect_at25df() calls spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 1 << 4) In the beginning the status register is 0x1C, i.e. the status register is not locked, the hardware protection pin is not asserted, only the write protection bits are set. spi_disable_blockprotect_generic() correctly detects that and tries to set the protection bits to 0 by trying to write 0x10 (not touching the r/o WP pin bit), but that apparently has no effect.
Interestingly here the initial contents of the status register are what we would expect them to be after unlocking(!). Maybe the chip reacts too slow? Do you have another explanation for that behavior?
The patch below adds a delay of five seconds after trying to write to the status register for unlocking.
Will test later on Monday. Now I am at home and do not have access to the hardware.
在 2013年4月20日 星期六 11:36:53,Stefan Tauner 写道:
Thanks for testing. This is quite odd: we do the right thing IMHO. The relevant code is in spi25_statusreg.c spi_disable_blockprotect_at25df() calls spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 1 << 4) In the beginning the status register is 0x1C, i.e. the status register is not locked, the hardware protection pin is not asserted, only the write protection bits are set. spi_disable_blockprotect_generic() correctly detects that and tries to set the protection bits to 0 by trying to write 0x10 (not touching the r/o WP pin bit), but that apparently has no effect.
Interestingly here the initial contents of the status register are what we would expect them to be after unlocking(!). Maybe the chip reacts too slow? Do you have another explanation for that behavior?
The patch below adds a delay of five seconds after trying to write to the status register for unlocking.
It seems the delay patch did not work: http://paste.flashrom.org/view.php?id=1623
Without patch 3927 or the delay patch, but with the patch showing the register: http://paste.flashrom.org/view.php?id=1624
That shows without patch 3927 the register has been turnned into 0x10 successfully.
I broke unlocking them correctly in r1635 while refactoring (NB: the commit log including the overly selfconfident statement about the "bug in spi_disable_blockprotect_at25df()").
Affected chips have per sector protection bits and the write protection bits in the status register do indicate if none, some or all sectors are protected. It is possible to globally (un)lock all sectors at once but in a way that was not anticipated when refactoring the spi25 unlocking functions into spi_disable_blockprotect_generic(). To globally unprotect not only the protection bits (2 and 3) have 0 to be written to them but also bits 4 and 5 which normally would not be touched by spi_disable_blockprotect_generic(). Some of the chips also support a permanent lockdown with fuses which we do not handle yet.
To fix this without copying the whole method I introduce another mask parameter to spi_disable_blockprotect_generic() namely unprotect_mask. See verbose comments inline for details.
Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at --- chipdrivers.h | 4 ++-- flashchips.c | 26 +++++++++++------------ flashchips.h | 6 ++++-- spi25_statusreg.c | 60 +++++++++++++++++++++++++++++++++++------------------ 4 files changed, 59 insertions(+), 37 deletions(-)
diff --git a/chipdrivers.h b/chipdrivers.h index dd20631..fd522a6 100644 --- a/chipdrivers.h +++ b/chipdrivers.h @@ -77,8 +77,8 @@ int spi_prettyprint_status_register_at25f4096(struct flashctx *flash); int spi_prettyprint_status_register_at25fs010(struct flashctx *flash); int spi_prettyprint_status_register_at25fs040(struct flashctx *flash); int spi_prettyprint_status_register_at26df081a(struct flashctx *flash); -int spi_disable_blockprotect_at25df(struct flashctx *flash); -int spi_disable_blockprotect_at25df_sec(struct flashctx *flash); +int spi_disable_blockprotect_at2x_global_unprotect(struct flashctx *flash); +int spi_disable_blockprotect_at2x_global_unprotect_sec(struct flashctx *flash); int spi_disable_blockprotect_at25f(struct flashctx *flash); int spi_disable_blockprotect_at25f512a(struct flashctx *flash); int spi_disable_blockprotect_at25f512b(struct flashctx *flash); diff --git a/flashchips.c b/flashchips.c index cbbb138..37315d1 100644 --- a/flashchips.c +++ b/flashchips.c @@ -1353,7 +1353,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at25df, - .unlock = spi_disable_blockprotect_at25df, + .unlock = spi_disable_blockprotect_at2x_global_unprotect, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, /* 2.3-3.6V & 2.7-3.6V models available */ @@ -1391,7 +1391,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at25df, - .unlock = spi_disable_blockprotect_at25df, + .unlock = spi_disable_blockprotect_at2x_global_unprotect, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, /* 2.3-3.6V & 2.7-3.6V models available */ @@ -1429,7 +1429,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at25df, - .unlock = spi_disable_blockprotect_at25df, + .unlock = spi_disable_blockprotect_at2x_global_unprotect, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {1600, 2000}, /* Datasheet says range is 1.65-1.95 V */ @@ -1467,7 +1467,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at25df_sec, - .unlock = spi_disable_blockprotect_at25df_sec, + .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, @@ -1505,7 +1505,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at25df_sec, - .unlock = spi_disable_blockprotect_at25df_sec, + .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, @@ -1543,7 +1543,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at25df, - .unlock = spi_disable_blockprotect_at25df, + .unlock = spi_disable_blockprotect_at2x_global_unprotect, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, @@ -1582,7 +1582,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at25df_sec, - .unlock = spi_disable_blockprotect_at25df_sec, + .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, @@ -1620,7 +1620,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at25df_sec, - .unlock = spi_disable_blockprotect_at25df_sec, + .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, @@ -1659,7 +1659,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at25df_sec, - .unlock = spi_disable_blockprotect_at25df_sec, + .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, @@ -1959,7 +1959,7 @@ const struct flashchip flashchips[] = { .block_erase = spi_block_erase_20, } }, - .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */ + .printlock = spi_prettyprint_status_register_plain, /* Supports also an incompatible page write (of exactly 256 B) and an auto-erasing write. */ .write = spi_chip_write_1, .read = spi_chip_read, /* Fast read (0x0B) supported */ @@ -1998,7 +1998,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at26df081a, - .unlock = spi_disable_blockprotect_at25df, + .unlock = spi_disable_blockprotect_at2x_global_unprotect, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, @@ -2036,7 +2036,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at25df, - .unlock = spi_disable_blockprotect, + .unlock = spi_disable_blockprotect_at2x_global_unprotect, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, @@ -2074,7 +2074,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at26df081a, - .unlock = spi_disable_blockprotect, + .unlock = spi_disable_blockprotect_at2x_global_unprotect, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, diff --git a/flashchips.h b/flashchips.h index 62be293..62bda41 100644 --- a/flashchips.h +++ b/flashchips.h @@ -130,13 +130,15 @@ #define ATMEL_ID 0x1F /* Atmel */ #define ATMEL_AT25DF021 0x4300 #define ATMEL_AT25DF041A 0x4401 -#define ATMEL_AT25DF081 0x4502 +#define ATMEL_AT25DF081 0x4502 /* EDI 0x00. AT25DL081 has same ID + EDI 0x0100 */ #define ATMEL_AT25DF081A 0x4501 /* Yes, 81A has a lower number than 81 */ #define ATMEL_AT25DF161 0x4602 #define ATMEL_AT25DF321 0x4700 /* Same as 26DF321 */ #define ATMEL_AT25DF321A 0x4701 #define ATMEL_AT25DF641 0x4800 -#define ATMEL_AT25DQ161 0x8600 +#define ATMEL_AT25DL161 0x4603 /* EDI 0x0100 */ +#define ATMEL_AT25DQ161 0x8600 /* EDI 0x0100 */ +#define ATMEL_AT25DQ321 0x8700 /* EDI 0x0100 */ #define ATMEL_AT25F512 0x65 /* guessed, no device ID in datasheet. Needs AT25F_RDID */ #define ATMEL_AT25F512A 0x65 /* Needs AT25F_RDID */ #define ATMEL_AT25F512B 0x6500 diff --git a/spi25_statusreg.c b/spi25_statusreg.c index 53952fe..2c6e802 100644 --- a/spi25_statusreg.c +++ b/spi25_statusreg.c @@ -126,11 +126,24 @@ uint8_t spi_read_status_register(struct flashctx *flash) /* A generic block protection disable. * Tests if a protection is enabled with the block protection mask (bp_mask) and returns success otherwise. * Tests if the register bits are locked with the lock_mask (lock_mask). - * Tests if a hardware protection is active (i.e. low) with the write protection mask (wp_mask) and bails out - * in that case. - * Finally tries to disable engaged protections and checks if any locks are still set. + * Tests if a hardware protection is active (i.e. low pin/high bit value) with the write protection mask + * (wp_mask) and bails out in that case. + * If there are register lock bits set we try to disable them by unsetting those bits of the previous register + * contents that are set in the lock_mask. We then check if removing the lock bits has worked and continue as if + * they never had been engaged: + * If the lock bits are out of the way try to disable engaged protections. + * To support uncommon global unprotects (e.g. on most AT2[56]xx1(A)) unprotect_mask can be used to force + * bits to 0 additionally to those set in bp_mask and lock_mask. Only bits set in unprotect_mask are potentially + * preserved when doing the final unprotect. + * + * To sum up: + * bp_mask: set those bits that correspond to the bits in the status register that indicate an active protection + * (which should be unset after this function returns). + * lock_mask: set the bits that correspond to the bits that lock changing the bits above. + * wp_mask: set the bits that correspond to bits indicating non-software revocable protections. + * unprotect_mask: set the bits that should be preserved if possible when unprotecting. */ -static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_mask, uint8_t lock_mask, uint8_t wp_mask) +static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_mask, uint8_t lock_mask, uint8_t wp_mask, uint8_t unprotect_mask) { uint8_t status; int result; @@ -154,10 +167,15 @@ static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_m msg_cerr("spi_write_status_register failed.\n"); return result; } + status = spi_read_status_register(flash); + if ((status & lock_mask) != 0) { + msg_cerr("unsetting lock bit(s) failed.\n"); + return 1; + } msg_cdbg("done.\n"); } /* Global unprotect. Make sure to mask the register lock bit as well. */ - result = spi_write_status_register(flash, status & ~(bp_mask | lock_mask)); + result = spi_write_status_register(flash, status & ~(bp_mask | lock_mask) & unprotect_mask); if (result) { msg_cerr("spi_write_status_register failed.\n"); return result; @@ -174,7 +192,7 @@ static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_m /* A common block protection disable that tries to unset the status register bits masked by 0x3C. */ int spi_disable_blockprotect(struct flashctx *flash) { - return spi_disable_blockprotect_generic(flash, 0x3C, 0, 0); + return spi_disable_blockprotect_generic(flash, 0x3C, 0, 0, 0xFF); }
@@ -488,49 +506,51 @@ int spi_prettyprint_status_register_at26df081a(struct flashctx *flash) return 0; }
-int spi_disable_blockprotect_at25df(struct flashctx *flash) +/* Some Atmel DataFlash chips support per sector protection bits and the write protection bits in the status + * register do indicate if none, some or all sectors are protected. It is possible to globally (un)lock all + * sectors at once by writing 0 not only the protection bits (2 and 3) but also completely unrelated bits (4 and + * 5) which normally are not touched. + * Affected are all known Atmel chips matched by AT2[56]D[FLQ]..1A? but the AT26DF041. */ +int spi_disable_blockprotect_at2x_global_unprotect(struct flashctx *flash) { - return spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 1 << 4); + return spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 1 << 4, 0x00); }
-int spi_disable_blockprotect_at25df_sec(struct flashctx *flash) +int spi_disable_blockprotect_at2x_global_unprotect_sec(struct flashctx *flash) { /* FIXME: We should check the security lockdown. */ msg_cinfo("Ignoring security lockdown (if present)\n"); - return spi_disable_blockprotect_at25df(flash); + return spi_disable_blockprotect_at2x_global_unprotect(flash); }
int spi_disable_blockprotect_at25f(struct flashctx *flash) { - return spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 0); + return spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 0, 0xFF); }
int spi_disable_blockprotect_at25f512a(struct flashctx *flash) { - return spi_disable_blockprotect_generic(flash, 0x04, 1 << 7, 0); + return spi_disable_blockprotect_generic(flash, 0x04, 1 << 7, 0, 0xFF); }
int spi_disable_blockprotect_at25f512b(struct flashctx *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); + return spi_disable_blockprotect_generic(flash, 0x04, 1 << 7, 1 << 4, 0xFF); }
int spi_disable_blockprotect_at25f4096(struct flashctx *flash) { - return spi_disable_blockprotect_generic(flash, 0x1C, 1 << 7, 0); + return spi_disable_blockprotect_generic(flash, 0x1C, 1 << 7, 0, 0xFF); }
int spi_disable_blockprotect_at25fs010(struct flashctx *flash) { - return spi_disable_blockprotect_generic(flash, 0x6C, 1 << 7, 0); + return spi_disable_blockprotect_generic(flash, 0x6C, 1 << 7, 0, 0xFF); }
int spi_disable_blockprotect_at25fs040(struct flashctx *flash) { - return spi_disable_blockprotect_generic(flash, 0x7C, 1 << 7, 0); + return spi_disable_blockprotect_generic(flash, 0x7C, 1 << 7, 0, 0xFF); }
/* === Intel === */ @@ -538,7 +558,7 @@ int spi_disable_blockprotect_at25fs040(struct flashctx *flash) /* TODO: Clear P_FAIL and E_FAIL with Clear SR Fail Flags Command (30h) here? */ int spi_disable_blockprotect_s33(struct flashctx *flash) { - return spi_disable_blockprotect_generic(flash, 0x1C, 1 << 7, 0); + return spi_disable_blockprotect_generic(flash, 0x1C, 1 << 7, 0, 0xFF); }
int spi_prettyprint_status_register_s33(struct flashctx *flash)
Tested AT45DB161D and Pm25LD512C after applying:
http://patchwork.coreboot.org/patch/3873/ http://patchwork.coreboot.org/patch/3871/ http://patchwork.coreboot.org/patch/3926/ http://patchwork.coreboot.org/patch/3925/ http://patchwork.coreboot.org/patch/3927/
AT45DB161D: http://paste.flashrom.org/view.php?id=1580 Pm25LD512C: http://paste.flashrom.org/view.php?id=1579
On Wed, 03 Apr 2013 14:19:22 +0800 Chi Zhang zhangchi866@gmail.com wrote:
AT45DB161D: http://paste.flashrom.org/view.php?id=1580 Pm25LD512C: http://paste.flashrom.org/view.php?id=1579
Looks good (apart from bugs already fixed), thanks! I have marked them as supported in my code.
Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at ---
Chi, can you please retest yours with this patch applied with "-VV" added to the command line? I am pretty sure that I know what happened and that this is the right thing to do but seeing it working is always nicer ;)
flashchips.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/flashchips.c b/flashchips.c index 16726ad..a807afc 100644 --- a/flashchips.c +++ b/flashchips.c @@ -2036,7 +2036,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at25df, - .unlock = spi_disable_blockprotect, + .unlock = spi_disable_blockprotect_at25df, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, @@ -2074,7 +2074,7 @@ const struct flashchip flashchips[] = { } }, .printlock = spi_prettyprint_status_register_at26df081a, - .unlock = spi_disable_blockprotect, + .unlock = spi_disable_blockprotect_at25df, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600},