Unlock ST M50FW002 correctly
Refactor ST M50 family unlocking
TODO: Unify write_lockbits_49fl00x() and unlock_block_stm50() and unlock_w39_fwh_block() and unlock_82802ab() and write_lockbits_block_49lfxxxc(). They all use exactly the same mechanism, but they don't share any code.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-stm50fw002_unlock/flashchips.c =================================================================== --- flashrom-stm50fw002_unlock/flashchips.c (Revision 1437) +++ flashrom-stm50fw002_unlock/flashchips.c (Arbeitskopie) @@ -7523,9 +7523,9 @@ .total_size = 256, .page_size = 64 * 1024, .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, + .tested = TEST_OK_PREW, .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */ + .probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (82802ab.c) */ .block_erasers = { { @@ -7536,9 +7536,12 @@ {16 * 1024, 1}, }, .block_erase = erase_block_82802ab, + }, { + .eraseblocks = { {256 * 1024, 1}, }, + .block_erase = NULL, /* Only in A/A mux mode */ } }, - .unlock = unlock_stm50flw0x0x, + .unlock = unlock_stm50fw002, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ Index: flashrom-stm50fw002_unlock/stm50flw0x0x.c =================================================================== --- flashrom-stm50fw002_unlock/stm50flw0x0x.c (Revision 1437) +++ flashrom-stm50fw002_unlock/stm50flw0x0x.c (Arbeitskopie) @@ -3,6 +3,7 @@ * * Copyright (C) 2008 Claus Gindhart claus.gindhart@kontron.com * Copyright (C) 2009 Sean Nelson audiohacked@gmail.com + * Copyright (C) 2011 Carl-Daniel Hailfinger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,6 +32,21 @@ #include "flashchips.h" #include "chipdrivers.h"
+#define STM50_UNLOCKED 0x00 + +static int unlock_block_stm50(struct flashchip *flash, int offset) +{ + chipaddr lock = flash->virtual_registers + offset + 2; + + msg_cdbg("Unlocking at 0x%x\n", offset); + chip_writeb(STM50_UNLOCKED, lock); + if (chip_readb(lock) != STM50_UNLOCKED) { + msg_cerr("Cannot unlock at 0x%x\n", offset); + return -1; + } + return 0; +} + /* * claus.gindhart@kontron.com * The ST M50FLW080B and STM50FLW080B chips have to be unlocked, @@ -38,8 +54,6 @@ */ static int unlock_block_stm50flw0x0x(struct flashchip *flash, int offset) { - chipaddr wrprotect = flash->virtual_registers + 2; - static const uint8_t unlock_sector = 0x00; int j;
/* @@ -58,22 +72,12 @@ || (offset == 0xF0000)) {
// unlock each 4k-sector - for (j = 0; j < 0x10000; j += 0x1000) { - msg_cdbg("unlocking at 0x%x\n", offset + j); - chip_writeb(unlock_sector, wrprotect + offset + j); - if (chip_readb(wrprotect + offset + j) != unlock_sector) { - msg_cerr("Cannot unlock sector @ 0x%x\n", - offset + j); + for (j = 0; j < 0x10000; j += 0x1000) + if (unlock_block_stm50(flash, offset + j)) return -1; - } - } } else { - msg_cdbg("unlocking at 0x%x\n", offset); - chip_writeb(unlock_sector, wrprotect + offset); - if (chip_readb(wrprotect + offset) != unlock_sector) { - msg_cerr("Cannot unlock sector @ 0x%x\n", offset); + if (unlock_block_stm50(flash, offset)) return -1; - } }
return 0; @@ -93,6 +97,27 @@ return 0; }
+/* FIXME: Should this be moved to a generic walk_unlockregions()? */ +int unlock_stm50fw002(struct flashchip *flash) +{ + static const struct eraseblock unlockregions[4] = { + {64 * 1024, 3}, + {32 * 1024, 1}, + {8 * 1024, 2}, + {16 * 1024, 1}}; + int i, j; + int addr = 0; + + for (i = 0; i < 4; i++) { + for (j = 0; j < unlockregions[i].count; j++) { + if (unlock_block_stm50(flash, addr)) + return 1; + addr += unlockregions[i].size; + } + } + return 0; +} + /* This function is unused. */ int erase_sector_stm50flw0x0x(struct flashchip *flash, unsigned int sector, unsigned int sectorsize) { Index: flashrom-stm50fw002_unlock/chipdrivers.h =================================================================== --- flashrom-stm50fw002_unlock/chipdrivers.h (Revision 1437) +++ flashrom-stm50fw002_unlock/chipdrivers.h (Arbeitskopie) @@ -146,5 +146,6 @@ /* stm50flw0x0x.c */ int erase_sector_stm50flw0x0x(struct flashchip *flash, unsigned int block, unsigned int blocksize); int unlock_stm50flw0x0x(struct flashchip *flash); +int unlock_stm50fw002(struct flashchip *flash);
#endif /* !__CHIPDRIVERS_H__ */
Am 12.09.2011 20:12 schrieb Carl-Daniel Hailfinger:
Unlock ST M50FW002 correctly
Refactor ST M50 family unlocking
TODO: Unify write_lockbits_49fl00x() and unlock_block_stm50() and unlock_w39_fwh_block() and unlock_82802ab() and write_lockbits_block_49lfxxxc(). They all use exactly the same mechanism, but they don't share any code.
Refactor locking for all chips with locking at register space address +2
Unlock ST M50FW002 correctly. Refactor Winbond W39*, ST M50*, PMC Pm49*, SST 49LF00*, ... locking
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-82802ab_lock_refactor/w39.c =================================================================== --- flashrom-82802ab_lock_refactor/w39.c (Revision 1437) +++ flashrom-82802ab_lock_refactor/w39.c (Arbeitskopie) @@ -21,7 +21,10 @@
#include "flash.h"
-static int printlock_w39_fwh_block(struct flashchip *flash, int offset) +#define RWLOCK ((1 << 2) | (1 << 0)) +#define LOCKDOWN (1 << 1) + +static int printlock_regspace2_block(struct flashchip *flash, int offset) { chipaddr wrprotect = flash->virtual_registers + offset + 2; uint8_t locking; @@ -56,30 +59,67 @@ }
/* Read or write lock present? */ - return (locking & ((1 << 2) | (1 << 0))) ? -1 : 0; + return (locking & RWLOCK) ? -1 : 0; }
-static int unlock_w39_fwh_block(struct flashchip *flash, int offset) +int changelock_regspace2_block(struct flashchip *flash, int offset, uint8_t bits) { chipaddr wrprotect = flash->virtual_registers + offset + 2; uint8_t locking;
+ if (bits & 0xf8) { + msg_cerr("Invalid locking change 0x%02x requested at 0x%08x! " + "Please report a bug at flashrom@flashrom.org\n", + bits, offset); + return -1; + } locking = chip_readb(wrprotect); - /* Read or write lock present? */ - if (locking & ((1 << 2) | (1 << 0))) { + /* Did we request a change of read/write/lockdown? */ + if (((locking ^ bits) & (RWLOCK | LOCKDOWN)) == 0) { + msg_cdbg2("Locking status at 0x%08x not changed\n", offset); + return 0; + } + /* Change read or write lock? */ + if ((locking ^ bits) & RWLOCK) { /* Lockdown active? */ - if (locking & (1 << 1)) { - msg_cerr("Can't unlock block at 0x%08x!\n", offset); + if (locking & LOCKDOWN) { + msg_cerr("Can't change locking status at 0x%08x due to " + "lockdown!\n", offset); return -1; } else { - msg_cdbg("Unlocking block at 0x%08x\n", offset); - chip_writeb(0, wrprotect); + /* Do not lockdown yet. */ + msg_cdbg("Changing locking status at 0x%08x\n", offset); + chip_writeb(bits & RWLOCK, wrprotect); + if (chip_readb(wrprotect) != (bits & RWLOCK)) { + msg_cerr("Locking status change FAILED at " + "0x%08x!\n", offset); + return -1; + } } } + if ((locking & LOCKDOWN) && !(bits & LOCKDOWN)) { + msg_cerr("Lockdown can't be removed at 0x%08x!\n", offset); + /* FIXME: Is this really an error? */ + return -1; + } + if (!(locking & LOCKDOWN) && (bits & LOCKDOWN)) { + msg_cdbg("Enabling lockdown at 0x%08x\n", offset); + chip_writeb(bits, wrprotect); + if (chip_readb(wrprotect) != (bits)) { + msg_cerr("Lockdown status change FAILED at " + "0x%08x!\n", offset); + return -1; + } + }
return 0; }
+static int unlock_w39_fwh_block(struct flashchip *flash, int offset) +{ + return changelock_regspace2_block(flash, offset, 0x00); +} + static uint8_t w39_idmode_readb(struct flashchip *flash, int offset) { chipaddr bios = flash->virtual_memory; @@ -143,7 +183,7 @@ /* Print lock status of the complete chip */ for (i = 0; i < total_size; i += flash->page_size) - ret |= printlock_w39_fwh_block(flash, i); + ret |= printlock_regspace2_block(flash, i);
return ret; } Index: flashrom-82802ab_lock_refactor/sst49lfxxxc.c =================================================================== --- flashrom-82802ab_lock_refactor/sst49lfxxxc.c (Revision 1437) +++ flashrom-82802ab_lock_refactor/sst49lfxxxc.c (Arbeitskopie) @@ -23,15 +23,6 @@ #include "flash.h" #include "chipdrivers.h"
-static int write_lockbits_block_49lfxxxc(struct flashchip *flash, unsigned long address, unsigned char bits) -{ - unsigned long lock = flash->virtual_registers + address + 2; - msg_cdbg("lockbits at address=0x%08lx is 0x%01x\n", lock, chip_readb(lock)); - chip_writeb(bits, lock); - - return 0; -} - static int write_lockbits_49lfxxxc(struct flashchip *flash, unsigned char bits) { chipaddr registers = flash->virtual_registers; @@ -40,16 +31,16 @@
msg_cdbg("\nbios=0x%08lx\n", registers); for (i = 0; left > 65536; i++, left -= 65536) { - write_lockbits_block_49lfxxxc(flash, i * 65536, bits); + changelock_regspace2_block(flash, i * 65536, bits); } address = i * 65536; - write_lockbits_block_49lfxxxc(flash, address, bits); + changelock_regspace2_block(flash, address, bits); address += 32768; - write_lockbits_block_49lfxxxc(flash, address, bits); + changelock_regspace2_block(flash, address, bits); address += 8192; - write_lockbits_block_49lfxxxc(flash, address, bits); + changelock_regspace2_block(flash, address, bits); address += 8192; - write_lockbits_block_49lfxxxc(flash, address, bits); + changelock_regspace2_block(flash, address, bits);
return 0; } Index: flashrom-82802ab_lock_refactor/82802ab.c =================================================================== --- flashrom-82802ab_lock_refactor/82802ab.c (Revision 1437) +++ flashrom-82802ab_lock_refactor/82802ab.c (Arbeitskopie) @@ -110,10 +110,10 @@ int unlock_82802ab(struct flashchip *flash) { int i; - //chipaddr wrprotect = flash->virtual_registers + page + 2;
for (i = 0; i < flash->total_size * 1024; i+= flash->page_size) - chip_writeb(0, flash->virtual_registers + i + 2); + if (changelock_regspace2_block(flash, i, 0x00)) + return -1;
return 0; } Index: flashrom-82802ab_lock_refactor/pm49fl00x.c =================================================================== --- flashrom-82802ab_lock_refactor/pm49fl00x.c (Revision 1437) +++ flashrom-82802ab_lock_refactor/pm49fl00x.c (Arbeitskopie) @@ -21,29 +21,30 @@ */
#include "flash.h" +#include "chipdrivers.h"
-static void write_lockbits_49fl00x(chipaddr bios, int size, - unsigned char bits, int block_size) +static int write_lockbits_49fl00x(struct flashchip *flash, uint8_t bits, + int block_size) { - int i, left = size; + int i, left = flash->total_size * 1024;
for (i = 0; left >= block_size; i++, left -= block_size) { /* pm49fl002 */ if (block_size == 16384 && i % 2) continue;
- chip_writeb(bits, bios + (i * block_size) + 2); + if (changelock_regspace2_block(flash, i * block_size, bits)) + return -1; } + return 0; }
int unlock_49fl00x(struct flashchip *flash) { - write_lockbits_49fl00x(flash->virtual_registers, flash->total_size * 1024, 0, flash->page_size); - return 0; + return write_lockbits_49fl00x(flash, 0, flash->page_size); }
int lock_49fl00x(struct flashchip *flash) { - write_lockbits_49fl00x(flash->virtual_registers, flash->total_size * 1024, 1, flash->page_size); - return 0; + return write_lockbits_49fl00x(flash, 1, flash->page_size); } Index: flashrom-82802ab_lock_refactor/flashchips.c =================================================================== --- flashrom-82802ab_lock_refactor/flashchips.c (Revision 1437) +++ flashrom-82802ab_lock_refactor/flashchips.c (Arbeitskopie) @@ -7523,9 +7523,9 @@ .total_size = 256, .page_size = 64 * 1024, .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, + .tested = TEST_OK_PREW, .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */ + .probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (82802ab.c) */ .block_erasers = { { @@ -7536,9 +7536,12 @@ {16 * 1024, 1}, }, .block_erase = erase_block_82802ab, + }, { + .eraseblocks = { {256 * 1024, 1}, }, + .block_erase = NULL, /* Only in A/A mux mode */ } }, - .unlock = unlock_stm50flw0x0x, + .unlock = unlock_stm50fw002, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ Index: flashrom-82802ab_lock_refactor/stm50flw0x0x.c =================================================================== --- flashrom-82802ab_lock_refactor/stm50flw0x0x.c (Revision 1437) +++ flashrom-82802ab_lock_refactor/stm50flw0x0x.c (Arbeitskopie) @@ -3,6 +3,7 @@ * * Copyright (C) 2008 Claus Gindhart claus.gindhart@kontron.com * Copyright (C) 2009 Sean Nelson audiohacked@gmail.com + * Copyright (C) 2011 Carl-Daniel Hailfinger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,8 +39,6 @@ */ static int unlock_block_stm50flw0x0x(struct flashchip *flash, int offset) { - chipaddr wrprotect = flash->virtual_registers + 2; - static const uint8_t unlock_sector = 0x00; int j;
/* @@ -58,23 +57,11 @@ || (offset == 0xF0000)) {
// unlock each 4k-sector - for (j = 0; j < 0x10000; j += 0x1000) { - msg_cdbg("unlocking at 0x%x\n", offset + j); - chip_writeb(unlock_sector, wrprotect + offset + j); - if (chip_readb(wrprotect + offset + j) != unlock_sector) { - msg_cerr("Cannot unlock sector @ 0x%x\n", - offset + j); + for (j = 0; j < 0x10000; j += 0x1000) + if (changelock_regspace2_block(flash, offset + j, 0x00)) return -1; - } - } - } else { - msg_cdbg("unlocking at 0x%x\n", offset); - chip_writeb(unlock_sector, wrprotect + offset); - if (chip_readb(wrprotect + offset) != unlock_sector) { - msg_cerr("Cannot unlock sector @ 0x%x\n", offset); + } else if (changelock_regspace2_block(flash, offset, 0x00)) return -1; - } - }
return 0; } @@ -84,7 +71,7 @@ int i;
for (i = 0; i < flash->total_size * 1024; i+= flash->page_size) { - if(unlock_block_stm50flw0x0x(flash, i)) { + if (unlock_block_stm50flw0x0x(flash, i)) { msg_cerr("UNLOCK FAILED!\n"); return -1; } @@ -93,6 +80,27 @@ return 0; }
+/* FIXME: Should this be moved to a generic walk_unlockregions()? */ +int unlock_stm50fw002(struct flashchip *flash) +{ + static const struct eraseblock unlockregions[4] = { + {64 * 1024, 3}, + {32 * 1024, 1}, + {8 * 1024, 2}, + {16 * 1024, 1}}; + int i, j; + int addr = 0; + + for (i = 0; i < 4; i++) { + for (j = 0; j < unlockregions[i].count; j++) { + if (changelock_regspace2_block(flash, addr, 0x00)) + return 1; + addr += unlockregions[i].size; + } + } + return 0; +} + /* This function is unused. */ int erase_sector_stm50flw0x0x(struct flashchip *flash, unsigned int sector, unsigned int sectorsize) { Index: flashrom-82802ab_lock_refactor/chipdrivers.h =================================================================== --- flashrom-82802ab_lock_refactor/chipdrivers.h (Revision 1437) +++ flashrom-82802ab_lock_refactor/chipdrivers.h (Arbeitskopie) @@ -139,6 +139,8 @@ int printlock_w39v080fa_dual(struct flashchip *flash); int unlock_w39v040fb(struct flashchip *flash); int unlock_w39v080fa(struct flashchip *flash); +int printlock_regspace2_block(struct flashchip *flash, int offset); +int changelock_regspace2_block(struct flashchip *flash, int offset, uint8_t bits);
/* w29ee011.c */ int probe_w29ee011(struct flashchip *flash); @@ -146,5 +148,6 @@ /* stm50flw0x0x.c */ int erase_sector_stm50flw0x0x(struct flashchip *flash, unsigned int block, unsigned int blocksize); int unlock_stm50flw0x0x(struct flashchip *flash); +int unlock_stm50fw002(struct flashchip *flash);
#endif /* !__CHIPDRIVERS_H__ */
Refactor Winbond W39*, ST M50*, PMC Pm49*, SST 49LF00*, ... locking Unlock ST M50FW002 correctly.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net ---
Rebased, slightly refined and also a bit checked :)
IMHO TODOs: - separate/different file for the *regspace2* functions - write_lockbits_49lfxxxc: this looks overly complicated, maybe try to use a scheme similar to unlock_stm50fw002, but with taking the total size into account by making the first sector size filling the chip up or so... - the RWLOCK and LOCKDOWN defines should be in chipdrivers.h because other files need to know about it!
82802ab.c | 6 +++--- chipdrivers.h | 3 +++ flashchips.c | 9 +++++--- pm49fl00x.c | 20 +++++++---------- sst49lfxxxc.c | 22 +++++-------------- stm50flw0x0x.c | 48 +++++++++++++++++++++++------------------ w39.c | 66 ++++++++++++++++++++++++++++++++++++++++---------------- 7 files changed, 100 insertions(+), 74 deletions(-)
diff --git a/82802ab.c b/82802ab.c index 608995d..c06568f 100644 --- a/82802ab.c +++ b/82802ab.c @@ -109,11 +109,11 @@ uint8_t wait_82802ab(struct flashctx *flash)
int unlock_82802ab(struct flashctx *flash) { - int i; - //chipaddr wrprotect = flash->virtual_registers + page + 2; + unsigned int i;
for (i = 0; i < flash->chip->total_size * 1024; i+= flash->chip->page_size) - chip_writeb(flash, 0, flash->virtual_registers + i + 2); + if (changelock_regspace2_block(flash, i, 0x00)) + return -1;
return 0; } diff --git a/chipdrivers.h b/chipdrivers.h index b43e16e..d5facc6 100644 --- a/chipdrivers.h +++ b/chipdrivers.h @@ -150,6 +150,8 @@ int printlock_w39v080fa_dual(struct flashctx *flash); int unlock_w39v040fb(struct flashctx *flash); int unlock_w39v080fa(struct flashctx *flash); int printlock_at49f(struct flashctx *flash); +int printlock_regspace2_block(struct flashctx *flash, int offset); +int changelock_regspace2_block(const struct flashctx *flash, int offset, uint8_t bits);
/* w29ee011.c */ int probe_w29ee011(struct flashctx *flash); @@ -157,6 +159,7 @@ int probe_w29ee011(struct flashctx *flash); /* stm50flw0x0x.c */ int erase_sector_stm50flw0x0x(struct flashctx *flash, unsigned int block, unsigned int blocksize); int unlock_stm50flw0x0x(struct flashctx *flash); +int unlock_stm50fw002(struct flashctx *flash);
/* en29lv640b.c */ int probe_en29lv640b(struct flashctx *flash); diff --git a/flashchips.c b/flashchips.c index 8fe50bd..7c4e827 100644 --- a/flashchips.c +++ b/flashchips.c @@ -8151,9 +8151,9 @@ const struct flashchip flashchips[] = { .total_size = 256, .page_size = 64 * 1024, .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, + .tested = TEST_OK_PREW, .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */ + .probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (82802ab.c) */ .block_erasers = { { @@ -8164,9 +8164,12 @@ const struct flashchip flashchips[] = { {16 * 1024, 1}, }, .block_erase = erase_block_82802ab, + }, { + .eraseblocks = { {256 * 1024, 1}, }, + .block_erase = NULL, /* Only in A/A mux mode */ } }, - .unlock = unlock_stm50flw0x0x, + .unlock = unlock_stm50fw002, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ diff --git a/pm49fl00x.c b/pm49fl00x.c index fe28d2b..2f81f1f 100644 --- a/pm49fl00x.c +++ b/pm49fl00x.c @@ -21,33 +21,29 @@ */
#include "flash.h" +#include "chipdrivers.h"
-static void write_lockbits_49fl00x(const struct flashctx *flash, - unsigned int size, unsigned char bits, - unsigned int block_size) +static int write_lockbits_49fl00x(const struct flashctx *flash, unsigned char bits, unsigned int block_size) { - unsigned int i, left = size; - chipaddr bios = flash->virtual_registers; + unsigned int i, left = flash->chip->total_size * 1024;
for (i = 0; left >= block_size; i++, left -= block_size) { /* pm49fl002 */ if (block_size == 16384 && i % 2) continue;
- chip_writeb(flash, bits, bios + (i * block_size) + 2); + if (changelock_regspace2_block(flash, i * block_size, bits)) + return -1; } + return 0; }
int unlock_49fl00x(struct flashctx *flash) { - write_lockbits_49fl00x(flash, flash->chip->total_size * 1024, 0, - flash->chip->page_size); - return 0; + return write_lockbits_49fl00x(flash, 0, flash->chip->page_size); }
int lock_49fl00x(struct flashctx *flash) { - write_lockbits_49fl00x(flash, flash->chip->total_size * 1024, 1, - flash->chip->page_size); - return 0; + return write_lockbits_49fl00x(flash, 1, flash->chip->page_size); } diff --git a/sst49lfxxxc.c b/sst49lfxxxc.c index bb21559..14063cb 100644 --- a/sst49lfxxxc.c +++ b/sst49lfxxxc.c @@ -23,18 +23,6 @@ #include "flash.h" #include "chipdrivers.h"
-static int write_lockbits_block_49lfxxxc(struct flashctx *flash, - unsigned long address, - unsigned char bits) -{ - unsigned long lock = flash->virtual_registers + address + 2; - msg_cdbg("lockbits at address=0x%08lx is 0x%01x\n", lock, - chip_readb(flash, lock)); - chip_writeb(flash, bits, lock); - - return 0; -} - static int write_lockbits_49lfxxxc(struct flashctx *flash, unsigned char bits) { chipaddr registers = flash->virtual_registers; @@ -43,16 +31,16 @@ static int write_lockbits_49lfxxxc(struct flashctx *flash, unsigned char bits)
msg_cdbg("\nbios=0x%08lx\n", registers); for (i = 0; left > 65536; i++, left -= 65536) { - write_lockbits_block_49lfxxxc(flash, i * 65536, bits); + changelock_regspace2_block(flash, i * 65536, bits); } address = i * 65536; - write_lockbits_block_49lfxxxc(flash, address, bits); + changelock_regspace2_block(flash, address, bits); address += 32768; - write_lockbits_block_49lfxxxc(flash, address, bits); + changelock_regspace2_block(flash, address, bits); address += 8192; - write_lockbits_block_49lfxxxc(flash, address, bits); + changelock_regspace2_block(flash, address, bits); address += 8192; - write_lockbits_block_49lfxxxc(flash, address, bits); + changelock_regspace2_block(flash, address, bits);
return 0; } diff --git a/stm50flw0x0x.c b/stm50flw0x0x.c index e6c7c05..a710b8f 100644 --- a/stm50flw0x0x.c +++ b/stm50flw0x0x.c @@ -3,6 +3,7 @@ * * Copyright (C) 2008 Claus Gindhart claus.gindhart@kontron.com * Copyright (C) 2009 Sean Nelson audiohacked@gmail.com + * Copyright (C) 2011 Carl-Daniel Hailfinger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,10 +37,8 @@ * The ST M50FLW080B and STM50FLW080B chips have to be unlocked, * before you can erase them or write to them. */ -static int unlock_block_stm50flw0x0x(struct flashctx *flash, int offset) +static int unlock_block_stm50flw0x0x(struct flashctx *flash, unsigned int offset) { - chipaddr wrprotect = flash->virtual_registers + 2; - static const uint8_t unlock_sector = 0x00; int j;
/* @@ -58,25 +57,11 @@ static int unlock_block_stm50flw0x0x(struct flashctx *flash, int offset) || (offset == 0xF0000)) {
// unlock each 4k-sector - for (j = 0; j < 0x10000; j += 0x1000) { - msg_cdbg("unlocking at 0x%x\n", offset + j); - chip_writeb(flash, unlock_sector, - wrprotect + offset + j); - if (chip_readb(flash, wrprotect + offset + j) != - unlock_sector) { - msg_cerr("Cannot unlock sector @ 0x%x\n", - offset + j); + for (j = 0; j < 0x10000; j += 0x1000) + if (changelock_regspace2_block(flash, offset + j, 0x00)) return -1; - } - } - } else { - msg_cdbg("unlocking at 0x%x\n", offset); - chip_writeb(flash, unlock_sector, wrprotect + offset); - if (chip_readb(flash, wrprotect + offset) != unlock_sector) { - msg_cerr("Cannot unlock sector @ 0x%x\n", offset); + } else if (changelock_regspace2_block(flash, offset, 0x00)) return -1; - } - }
return 0; } @@ -86,7 +71,7 @@ int unlock_stm50flw0x0x(struct flashctx *flash) int i;
for (i = 0; i < flash->chip->total_size * 1024; i+= flash->chip->page_size) { - if(unlock_block_stm50flw0x0x(flash, i)) { + if (unlock_block_stm50flw0x0x(flash, i)) { msg_cerr("UNLOCK FAILED!\n"); return -1; } @@ -95,6 +80,27 @@ int unlock_stm50flw0x0x(struct flashctx *flash) return 0; }
+/* FIXME: Should this be moved to a generic walk_unlockregions()? */ +int unlock_stm50fw002(struct flashctx *flash) +{ + static const struct eraseblock unlockregions[4] = { + {64 * 1024, 3}, + {32 * 1024, 1}, + {8 * 1024, 2}, + {16 * 1024, 1}}; + int i, j; + int addr = 0; + + for (i = 0; i < 4; i++) { + for (j = 0; j < unlockregions[i].count; j++) { + if (changelock_regspace2_block(flash, addr, 0x00)) + return 1; + addr += unlockregions[i].size; + } + } + return 0; +} + /* This function is unused. */ int erase_sector_stm50flw0x0x(struct flashctx *flash, unsigned int sector, unsigned int sectorsize) diff --git a/w39.c b/w39.c index da61d23..e903e24 100644 --- a/w39.c +++ b/w39.c @@ -21,14 +21,15 @@
#include "flash.h"
-static int printlock_w39_fwh_block(struct flashctx *flash, unsigned int offset) +#define RWLOCK ((1 << 2) | (1 << 0)) +#define LOCKDOWN (1 << 1) + +static int printlock_regspace2_block(struct flashctx *flash, unsigned int offset) { chipaddr wrprotect = flash->virtual_registers + offset + 2; - uint8_t locking; - - locking = chip_readb(flash, wrprotect); + uint8_t state = chip_readb(flash, wrprotect); msg_cdbg("Lock status of block at 0x%08x is ", offset); - switch (locking & 0x7) { + switch (state & 0x7) { case 0: msg_cdbg("Full Access.\n"); break; @@ -36,7 +37,7 @@ static int printlock_w39_fwh_block(struct flashctx *flash, unsigned int offset) msg_cdbg("Write Lock (Default State).\n"); break; case 2: - msg_cdbg("Locked Open (Full Access, Lock Down).\n"); + msg_cdbg("Locked Open (Full Access, Locked Down).\n"); break; case 3: msg_cerr("Error: Write Lock, Locked Down.\n"); @@ -56,24 +57,53 @@ static int printlock_w39_fwh_block(struct flashctx *flash, unsigned int offset) }
/* Read or write lock present? */ - return (locking & ((1 << 2) | (1 << 0))) ? -1 : 0; + return (state & RWLOCK) ? -1 : 0; }
-static int unlock_w39_fwh_block(struct flashctx *flash, unsigned int offset) +int changelock_regspace2_block(const struct flashctx *flash, unsigned int offset, uint8_t new_bits) { chipaddr wrprotect = flash->virtual_registers + offset + 2; - uint8_t locking; + uint8_t old;
- locking = chip_readb(flash, wrprotect); - /* Read or write lock present? */ - if (locking & ((1 << 2) | (1 << 0))) { + if (new_bits & 0xf8) { // FIXME: define a mask? + msg_cerr("Invalid locking change 0x%02x requested at 0x%08x! " + "Please report a bug at flashrom@flashrom.org\n", + new_bits, offset); + return -1; + } + old = chip_readb(flash, wrprotect); + /* Did we request a change of read/write/lockdown? */ + if (((old ^ new_bits) & (RWLOCK | LOCKDOWN)) == 0) { + msg_cdbg2("Locking status at 0x%08x not changed\n", offset); + return 0; + } + /* Change read or write lock? */ + if ((old ^ new_bits) & RWLOCK) { /* Lockdown active? */ - if (locking & (1 << 1)) { - msg_cerr("Can't unlock block at 0x%08x!\n", offset); + if (old & LOCKDOWN) { + msg_cerr("Can't change locking status at 0x%08x due to lockdown!\n", offset); return -1; } else { - msg_cdbg("Unlocking block at 0x%08x\n", offset); - chip_writeb(flash, 0, wrprotect); + /* Do not lockdown yet. */ + msg_cdbg("Changing locking status at 0x%08x to 0x%02x\n", offset, new_bits & RWLOCK); + chip_writeb(flash, new_bits & RWLOCK, wrprotect); + if (chip_readb(flash, wrprotect) != (new_bits & RWLOCK)) { + msg_cerr("Locking status change FAILED at 0x%08x!\n", offset); + return -1; + } + } + } + if ((old & LOCKDOWN) && !(new_bits & LOCKDOWN)) { + msg_cerr("Lockdown can't be removed at 0x%08x!\n", offset); + /* FIXME: Is this really an error? */ + return -1; + } + if (!(old & LOCKDOWN) && (new_bits & LOCKDOWN)) { + msg_cdbg("Enabling lockdown at 0x%08x\n", offset); + chip_writeb(flash, new_bits, wrprotect); + if (chip_readb(flash, wrprotect) != new_bits) { + msg_cerr("Lockdown status change FAILED at 0x%08x!\n", offset); + return -1; } }
@@ -143,7 +173,7 @@ static int printlock_w39_fwh(struct flashctx *flash) /* Print lock status of the complete chip */ for (i = 0; i < total_size; i += flash->chip->page_size) - ret |= printlock_w39_fwh_block(flash, i); + ret |= printlock_regspace2_block(flash, i);
return ret; } @@ -154,7 +184,7 @@ static int unlock_w39_fwh(struct flashctx *flash) /* Unlock the complete chip */ for (i = 0; i < total_size; i += flash->chip->page_size) - if (unlock_w39_fwh_block(flash, i)) + if (changelock_regspace2_block(flash, i, 0x00)) return -1;
return 0;
This includes PMC Pm49*, SST 49LF00*, ST M50* and Winbond W39* family. The erase and write test status bits of all affected chips have been reset.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net Signed-off-by: Stefan Tauner stefan.tauner@alumni.tuwien.ac.at ---
I have noticed that the resulting patch of your previous approach was way too easy to review. I have fixed that for you. :P I have put the new generic unlock functions to jedec.c lacking a better alternative, suggestions are welcome. The function names are also very open for debate.
82802ab.c | 11 ---- Makefile | 2 +- chipdrivers.h | 17 +++--- flashchips.c | 77 ++++++++++++++------------- jedec.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pm49fl00x.c | 53 ------------------- sst49lfxxxc.c | 39 -------------- stm50.c | 57 +------------------- w39.c | 112 ++------------------------------------- 9 files changed, 221 insertions(+), 314 deletions(-) delete mode 100644 pm49fl00x.c
diff --git a/82802ab.c b/82802ab.c index 9e39852..e450b5d 100644 --- a/82802ab.c +++ b/82802ab.c @@ -108,17 +108,6 @@ uint8_t wait_82802ab(struct flashctx *flash) return status; }
-int unlock_82802ab(struct flashctx *flash) -{ - int i; - //chipaddr wrprotect = flash->virtual_registers + page + 2; - - for (i = 0; i < flash->chip->total_size * 1024; i+= flash->chip->page_size) - chip_writeb(flash, 0, flash->virtual_registers + i + 2); - - return 0; -} - int erase_block_82802ab(struct flashctx *flash, unsigned int page, unsigned int pagesize) { diff --git a/Makefile b/Makefile index 346d46a..d2feb2a 100644 --- a/Makefile +++ b/Makefile @@ -331,7 +331,7 @@ endif # Flash chip drivers and bus support infrastructure.
CHIP_OBJS = jedec.o stm50.o w39.o w29ee011.o \ - sst28sf040.o m29f400bt.o 82802ab.o pm49fl00x.o \ + sst28sf040.o m29f400bt.o 82802ab.o \ sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o spi25.o spi25_statusreg.o \ opaque.o sfdp.o en29lv640b.o at45db.o
diff --git a/chipdrivers.h b/chipdrivers.h index 7fe3202..4add6ef 100644 --- a/chipdrivers.h +++ b/chipdrivers.h @@ -130,7 +130,6 @@ int probe_82802ab(struct flashctx *flash); int erase_block_82802ab(struct flashctx *flash, unsigned int page, unsigned int pagesize); int write_82802ab(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len); void print_status_82802ab(uint8_t status); -int unlock_82802ab(struct flashctx *flash); int unlock_28f004s5(struct flashctx *flash); int unlock_lh28f008bjt(struct flashctx *flash);
@@ -145,6 +144,13 @@ int erase_sector_jedec(struct flashctx *flash, unsigned int page, unsigned int p int erase_block_jedec(struct flashctx *flash, unsigned int page, unsigned int blocksize); int erase_chip_block_jedec(struct flashctx *flash, unsigned int page, unsigned int blocksize);
+int unlock_regspace2_uniform_32k(struct flashctx *flash); +int unlock_regspace2_uniform_64k(struct flashctx *flash); +int unlock_regspace2_block_eraser_0(struct flashctx *flash); +int unlock_regspace2_block_eraser_1(struct flashctx *flash); +int unlock_regspace2_block(const struct flashctx *flash, chipaddr off); +int printlock_regspace2_uniform_64k(struct flashctx *flash); + /* m29f400bt.c */ int probe_m29f400bt(struct flashctx *flash); int block_erase_m29f400bt(struct flashctx *flash, unsigned int start, unsigned int len); @@ -152,10 +158,6 @@ int block_erase_chip_m29f400bt(struct flashctx *flash, unsigned int start, unsig int write_m29f400bt(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len); void protect_m29f400bt(struct flashctx *flash, chipaddr bios);
-/* pm49fl00x.c */ -int unlock_49fl00x(struct flashctx *flash); -int lock_49fl00x(struct flashctx *flash); - /* sst28sf040.c */ int erase_chip_28sf040(struct flashctx *flash, unsigned int addr, unsigned int blocklen); int erase_sector_28sf040(struct flashctx *flash, unsigned int address, unsigned int sector_size); @@ -165,7 +167,6 @@ int protect_28sf040(struct flashctx *flash);
/* sst49lfxxxc.c */ int erase_sector_49lfxxxc(struct flashctx *flash, unsigned int address, unsigned int sector_size); -int unlock_49lfxxxc(struct flashctx *flash);
/* sst_fwhub.c */ int printlock_sst_fwhub(struct flashctx *flash); @@ -185,8 +186,6 @@ int printlock_w39v040fc(struct flashctx *flash); int printlock_w39v080a(struct flashctx *flash); int printlock_w39v080fa(struct flashctx *flash); int printlock_w39v080fa_dual(struct flashctx *flash); -int unlock_w39v040fb(struct flashctx *flash); -int unlock_w39v080fa(struct flashctx *flash); int printlock_at49f(struct flashctx *flash);
/* w29ee011.c */ @@ -194,8 +193,6 @@ int probe_w29ee011(struct flashctx *flash);
/* stm50.c */ int erase_sector_stm50(struct flashctx *flash, unsigned int block, unsigned int blocksize); -int unlock_stm50_uniform(struct flashctx *flash); -int unlock_stm50_nonuniform(struct flashctx *flash);
/* en29lv640b.c */ int probe_en29lv640b(struct flashctx *flash); diff --git a/flashchips.c b/flashchips.c index 78c18ca..092ceb6 100644 --- a/flashchips.c +++ b/flashchips.c @@ -1382,7 +1382,7 @@ const struct flashchip flashchips[] = { .total_size = 512, .page_size = 64 * 1024, .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, - .tested = TEST_OK_PREW, + .tested = TEST_OK_PR, .probe = probe_jedec, .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ .block_erasers = @@ -1395,7 +1395,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_chip_block_jedec, } }, - .unlock = unlock_49fl00x, + .unlock = unlock_regspace2_uniform_64k, .write = write_jedec_1, .read = read_memmapped, .voltage = {3000, 3600}, @@ -2993,7 +2993,7 @@ const struct flashchip flashchips[] = { }, }, .printlock = NULL, /* TODO */ - .unlock = NULL, /* unlock_82802ab() not correct(?) */ + .unlock = NULL, /* FIXME: unlock_regspace2_uniform_64k() not correct(?) */ .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, @@ -5901,7 +5901,7 @@ const struct flashchip flashchips[] = { .total_size = 512, .page_size = 64 * 1024, .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_OK_PREW, + .tested = TEST_OK_PR, .probe = probe_82802ab, .probe_timing = TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */ .block_erasers = @@ -5911,7 +5911,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, }, }, - .unlock = unlock_82802ab, + .unlock = unlock_regspace2_uniform_64k, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, @@ -5936,7 +5936,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, }, }, - .unlock = unlock_82802ab, + .unlock = unlock_regspace2_uniform_64k, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, @@ -9020,7 +9020,7 @@ const struct flashchip flashchips[] = { .total_size = 256, .page_size = 16 * 1024, .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, - .tested = TEST_OK_PREW, + .tested = TEST_OK_PR, .probe = probe_jedec, .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ .block_erasers = @@ -9036,7 +9036,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_chip_block_jedec, } }, - .unlock = unlock_49fl00x, + .unlock = unlock_regspace2_uniform_32k, .write = write_jedec_1, .read = read_memmapped, .voltage = {3000, 3600}, @@ -9051,7 +9051,7 @@ const struct flashchip flashchips[] = { .total_size = 512, .page_size = 64 * 1024, .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, - .tested = TEST_OK_PREW, + .tested = TEST_OK_PR, .probe = probe_jedec, .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ .block_erasers = @@ -9067,7 +9067,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_chip_block_jedec, } }, - .unlock = unlock_49fl00x, + .unlock = unlock_regspace2_uniform_64k, .write = write_jedec_1, .read = read_memmapped, .voltage = {3000, 3600}, @@ -9349,7 +9349,7 @@ const struct flashchip flashchips[] = { .block_erase = NULL, /* 30 D0, only in A/A mux mode */ }, }, - .unlock = unlock_82802ab, + .unlock = unlock_regspace2_uniform_64k, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, @@ -10891,7 +10891,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, } }, - .unlock = unlock_49lfxxxc, + .unlock = unlock_regspace2_block_eraser_1, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, @@ -10956,7 +10956,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, } }, - .unlock = unlock_49lfxxxc, + .unlock = unlock_regspace2_block_eraser_1, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, @@ -10971,7 +10971,7 @@ const struct flashchip flashchips[] = { .total_size = 2048, .page_size = 4 * 1024, .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_OK_PREW, + .tested = TEST_OK_PR, .probe = probe_82802ab, .probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */ .block_erasers = @@ -10989,7 +10989,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, } }, - .unlock = unlock_49lfxxxc, + .unlock = unlock_regspace2_block_eraser_1, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, @@ -11094,7 +11094,7 @@ const struct flashchip flashchips[] = { .total_size = 512, .page_size = 64 * 1024, .feature_bits = FEATURE_EITHER_RESET | FEATURE_REGISTERMAP, - .tested = TEST_OK_PREW, + .tested = TEST_OK_PR, .probe = probe_jedec, .probe_timing = 1, /* 150ns */ .block_erasers = @@ -11110,7 +11110,7 @@ const struct flashchip flashchips[] = { .block_erase = NULL, } }, - .unlock = unlock_82802ab, + .unlock = unlock_regspace2_uniform_64k, .write = write_jedec_1, .read = read_memmapped, .voltage = {3000, 3600}, @@ -11155,7 +11155,7 @@ const struct flashchip flashchips[] = { .total_size = 2048, .page_size = 4 * 1024, .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_OK_PRE, + .tested = TEST_OK_PR, .probe = probe_82802ab, .probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */ .block_erasers = @@ -11173,7 +11173,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, } }, - .unlock = unlock_49lfxxxc, + .unlock = unlock_regspace2_block_eraser_1, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, @@ -11441,7 +11441,7 @@ const struct flashchip flashchips[] = { } }, .write = write_82802ab, - .unlock = unlock_stm50_uniform, + .unlock = unlock_regspace2_uniform_64k, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ }, @@ -11474,7 +11474,7 @@ const struct flashchip flashchips[] = { } }, .write = write_82802ab, - .unlock = unlock_stm50_uniform, + .unlock = unlock_regspace2_uniform_64k, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ }, @@ -11488,7 +11488,7 @@ const struct flashchip flashchips[] = { .total_size = 1024, .page_size = 0, .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_OK_PRE, + .tested = TEST_OK_PR, .probe = probe_82802ab, .probe_timing = TIMING_FIXME, .block_erasers = @@ -11506,7 +11506,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, } }, - .unlock = unlock_stm50_nonuniform, + .unlock = unlock_regspace2_block_eraser_0, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ @@ -11539,7 +11539,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, } }, - .unlock = unlock_stm50_nonuniform, + .unlock = unlock_regspace2_block_eraser_0, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ @@ -11554,9 +11554,9 @@ const struct flashchip flashchips[] = { .total_size = 256, .page_size = 0, .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, + .tested = TEST_OK_PR, .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */ + .probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (82802ab.c) */ .block_erasers = { { @@ -11567,9 +11567,12 @@ const struct flashchip flashchips[] = { {16 * 1024, 1}, }, .block_erase = erase_block_82802ab, + }, { + .eraseblocks = { {256 * 1024, 1}, }, + .block_erase = NULL, /* Only in A/A mux mode */ } }, - .unlock = unlock_stm50_nonuniform, + .unlock = unlock_regspace2_block_eraser_0, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ @@ -11594,7 +11597,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, } }, - .unlock = unlock_stm50_uniform, + .unlock = unlock_regspace2_uniform_64k, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ @@ -11619,7 +11622,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, } }, - .unlock = unlock_stm50_uniform, + .unlock = unlock_regspace2_uniform_64k, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ @@ -11634,7 +11637,7 @@ const struct flashchip flashchips[] = { .total_size = 1024, .page_size = 0, .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_OK_PREW, + .tested = TEST_OK_PR, .probe = probe_82802ab, .probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (82802ab.c) */ .block_erasers = @@ -11644,7 +11647,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, } }, - .unlock = unlock_stm50_uniform, + .unlock = unlock_regspace2_uniform_64k, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ @@ -11669,7 +11672,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, } }, - .unlock = unlock_stm50_uniform, + .unlock = unlock_regspace2_uniform_64k, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ @@ -11700,7 +11703,7 @@ const struct flashchip flashchips[] = { .block_erase = erase_block_82802ab, } }, - .unlock = unlock_stm50_nonuniform, + .unlock = unlock_regspace2_block_eraser_0, .write = write_82802ab, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program & erase */ @@ -13000,7 +13003,7 @@ const struct flashchip flashchips[] = { .total_size = 512, .page_size = 64 * 1024, .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, - .tested = TEST_OK_PREW, + .tested = TEST_OK_PR, .probe = probe_jedec, .probe_timing = 10, .block_erasers = @@ -13014,7 +13017,7 @@ const struct flashchip flashchips[] = { } }, .printlock = printlock_w39v040fb, - .unlock = unlock_w39v040fb, + .unlock = unlock_regspace2_uniform_64k, .write = write_jedec_1, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program */ @@ -13205,7 +13208,7 @@ const struct flashchip flashchips[] = { .total_size = 1024, .page_size = 64 * 1024, .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, - .tested = TEST_OK_PREW, + .tested = TEST_OK_PR, .probe = probe_jedec, .probe_timing = 10, .block_erasers = @@ -13219,7 +13222,7 @@ const struct flashchip flashchips[] = { } }, .printlock = printlock_w39v080fa, - .unlock = unlock_w39v080fa, + .unlock = unlock_regspace2_uniform_64k, .write = write_jedec_1, .read = read_memmapped, .voltage = {3000, 3600}, /* Also has 12V fast program */ diff --git a/jedec.c b/jedec.c index 08cc88b..3bc4900 100644 --- a/jedec.c +++ b/jedec.c @@ -6,6 +6,7 @@ * Copyright (C) 2006 coresystems GmbH info@coresystems.de * Copyright (C) 2007 Carl-Daniel Hailfinger * Copyright (C) 2009 Sean Nelson audiohacked@gmail.com + * Copyright (C) 2014 Stefan Tauner * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -510,3 +511,169 @@ int erase_chip_jedec(struct flashctx *flash) mask = getaddrmask(flash->chip); return erase_chip_jedec_common(flash, mask); } + +struct unlockblock { + unsigned int size; + unsigned int count; +}; + +typedef int (*unlockblock_func)(const struct flashctx *flash, chipaddr offset); +static int regspace2_walk_unlockblocks(const struct flashctx *flash, const struct unlockblock *block, unlockblock_func func) +{ + chipaddr off = flash->virtual_registers + 2; + while (block->count != 0) { + unsigned int j; + for (j = 0; j < block->count; j++) { + if (func(flash, off)) + return -1; + off += block->size; + } + block++; + } + return 0; +} + +#define REG2_RWLOCK ((1 << 2) | (1 << 0)) +#define REG2_LOCKDOWN (1 << 1) +#define REG2_MASK (REG2_RWLOCK | REG2_LOCKDOWN) + +static int printlock_regspace2_block(const struct flashctx *flash, chipaddr offset) +{ + chipaddr wrprotect = flash->virtual_registers + offset + 2; + uint8_t state = chip_readb(flash, wrprotect); + msg_cdbg("Lock status of block at 0x%0*" PRIxPTR " is ", PRIxPTR_WIDTH, offset); + switch (state & REG2_MASK) { + case 0: + msg_cdbg("Full Access.\n"); + break; + case 1: + msg_cdbg("Write Lock (Default State).\n"); + break; + case 2: + msg_cdbg("Locked Open (Full Access, Locked Down).\n"); + break; + case 3: + msg_cdbg("Write Lock, Locked Down.\n"); + break; + case 4: + msg_cdbg("Read Lock.\n"); + break; + case 5: + msg_cdbg("Read/Write Lock.\n"); + break; + case 6: + msg_cdbg("Read Lock, Locked Down.\n"); + break; + case 7: + msg_cdbg("Read/Write Lock, Locked Down.\n"); + break; + } + return 0; +} + +int printlock_regspace2_blocks(const struct flashctx *flash, const struct unlockblock *blocks) +{ + return regspace2_walk_unlockblocks(flash, blocks, &printlock_regspace2_block); +} + +static int printlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size) +{ + const unsigned int elems = flash->chip->total_size * 1024 / block_size; + struct unlockblock blocks[2] = {{.size = block_size, .count = elems}}; + return regspace2_walk_unlockblocks(flash, blocks, &printlock_regspace2_block); +} + +int printlock_regspace2_uniform_64k(struct flashctx *flash) +{ + return printlock_regspace2_uniform(flash, 64 * 1024); +} + +static int changelock_regspace2_block(const struct flashctx *flash, chipaddr offset, uint8_t new_bits) +{ + chipaddr wrprotect = flash->virtual_registers + offset + 2; + uint8_t old; + + if (new_bits & ~REG2_MASK) { + msg_cerr("Invalid locking change 0x%02x requested at 0x%0*" PRIxPTR "! " + "Please report a bug at flashrom@flashrom.org\n", + new_bits, PRIxPTR_WIDTH, offset); + return -1; + } + old = chip_readb(flash, wrprotect); + /* Early exist if no change (of read/write/lockdown) was requested. */ + if (((old ^ new_bits) & REG2_MASK) == 0) { + msg_cdbg2("Locking status at 0x%0*" PRIxPTR " not changed\n", PRIxPTR_WIDTH, offset); + return 0; + } + /* Normally lockdowns can not be cleared. Try nevertheless if requested. */ + if ((old & REG2_LOCKDOWN) && !(new_bits & REG2_LOCKDOWN)) { + chip_writeb(flash, old & ~REG2_LOCKDOWN, wrprotect); + if (chip_readb(flash, wrprotect) != (old & ~REG2_LOCKDOWN)) { + msg_cerr("Lockdown can't be removed at 0x%0*" PRIxPTR "!\n", PRIxPTR_WIDTH, offset); + return -1; + } + } + /* Change read or write lock? */ + if ((old ^ new_bits) & REG2_RWLOCK) { + /* Do not lockdown yet. */ + msg_cdbg("Changing locking status at 0x%0*" PRIxPTR " to 0x%02x\n", PRIxPTR_WIDTH, offset, new_bits & REG2_RWLOCK); + chip_writeb(flash, new_bits & REG2_RWLOCK, wrprotect); + if (chip_readb(flash, wrprotect) != (new_bits & REG2_RWLOCK)) { + msg_cerr("Locking status change FAILED at 0x%0*" PRIxPTR "!\n", PRIxPTR_WIDTH, offset); + return -1; + } + } + /* Enable lockdown if requested. */ + if (!(old & REG2_LOCKDOWN) && (new_bits & REG2_LOCKDOWN)) { + msg_cdbg("Enabling lockdown at 0x%0*" PRIxPTR "\n", PRIxPTR_WIDTH, offset); + chip_writeb(flash, new_bits, wrprotect); + if (chip_readb(flash, wrprotect) != new_bits) { + msg_cerr("Enabling lockdown FAILED at 0x%0*" PRIxPTR "!\n", PRIxPTR_WIDTH, offset); + return -1; + } + } + + return 0; +} + +int unlock_regspace2_block(const struct flashctx *flash, chipaddr off) +{ + chipaddr wrprotect = flash->virtual_registers + off + 2; + uint8_t old = chip_readb(flash, wrprotect); + /* We don't care for the lockdown bit as long as the RW locks are 0 after we're done */ + return changelock_regspace2_block(flash, off, old & ~REG2_RWLOCK); +} + +static int unlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size) +{ + const unsigned int elems = flash->chip->total_size * 1024 / block_size; + struct unlockblock blocks[2] = {{.size = block_size, .count = elems}}; + return regspace2_walk_unlockblocks(flash, blocks, &unlock_regspace2_block); +} + +int unlock_regspace2_uniform_64k(struct flashctx *flash) +{ + return unlock_regspace2_uniform(flash, 64 * 1024); +} + +int unlock_regspace2_uniform_32k(struct flashctx *flash) +{ + return unlock_regspace2_uniform(flash, 32 * 1024); +} + +int unlock_regspace2_block_eraser_0(struct flashctx *flash) +{ + // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated). + const struct unlockblock *unlockblocks = + (const struct unlockblock *)flash->chip->block_erasers[0].eraseblocks; + return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block); +} + +int unlock_regspace2_block_eraser_1(struct flashctx *flash) +{ + // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated). + const struct unlockblock *unlockblocks = + (const struct unlockblock *)flash->chip->block_erasers[1].eraseblocks; + return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block); +} + diff --git a/pm49fl00x.c b/pm49fl00x.c deleted file mode 100644 index fe28d2b..0000000 --- a/pm49fl00x.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2004 Tyan Corporation - * Copyright (C) 2007 Nikolay Petukhov nikolay.petukhov@gmail.com - * Copyright (C) 2007 Reinder E.N. de Haan lb_reha@mveas.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "flash.h" - -static void write_lockbits_49fl00x(const struct flashctx *flash, - unsigned int size, unsigned char bits, - unsigned int block_size) -{ - unsigned int i, left = size; - chipaddr bios = flash->virtual_registers; - - for (i = 0; left >= block_size; i++, left -= block_size) { - /* pm49fl002 */ - if (block_size == 16384 && i % 2) - continue; - - chip_writeb(flash, bits, bios + (i * block_size) + 2); - } -} - -int unlock_49fl00x(struct flashctx *flash) -{ - write_lockbits_49fl00x(flash, flash->chip->total_size * 1024, 0, - flash->chip->page_size); - return 0; -} - -int lock_49fl00x(struct flashctx *flash) -{ - write_lockbits_49fl00x(flash, flash->chip->total_size * 1024, 1, - flash->chip->page_size); - return 0; -} diff --git a/sst49lfxxxc.c b/sst49lfxxxc.c index 3d17b5b..d6c85c8 100644 --- a/sst49lfxxxc.c +++ b/sst49lfxxxc.c @@ -23,45 +23,6 @@ #include "flash.h" #include "chipdrivers.h"
-static int write_lockbits_block_49lfxxxc(struct flashctx *flash, - unsigned long address, - unsigned char bits) -{ - unsigned long lock = flash->virtual_registers + address + 2; - msg_cdbg("lockbits at address=0x%08lx is 0x%01x\n", lock, - chip_readb(flash, lock)); - chip_writeb(flash, bits, lock); - - return 0; -} - -static int write_lockbits_49lfxxxc(struct flashctx *flash, unsigned char bits) -{ - chipaddr registers = flash->virtual_registers; - unsigned int i, left = flash->chip->total_size * 1024; - unsigned long address; - - msg_cdbg("\nbios=0x%08" PRIxPTR "\n", registers); - for (i = 0; left > 65536; i++, left -= 65536) { - write_lockbits_block_49lfxxxc(flash, i * 65536, bits); - } - address = i * 65536; - write_lockbits_block_49lfxxxc(flash, address, bits); - address += 32768; - write_lockbits_block_49lfxxxc(flash, address, bits); - address += 8192; - write_lockbits_block_49lfxxxc(flash, address, bits); - address += 8192; - write_lockbits_block_49lfxxxc(flash, address, bits); - - return 0; -} - -int unlock_49lfxxxc(struct flashctx *flash) -{ - return write_lockbits_49lfxxxc(flash, 0); -} - int erase_sector_49lfxxxc(struct flashctx *flash, unsigned int address, unsigned int sector_size) { diff --git a/stm50.c b/stm50.c index edcfdd2..4aa1566 100644 --- a/stm50.c +++ b/stm50.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Claus Gindhart claus.gindhart@kontron.com * Copyright (C) 2009 Sean Nelson audiohacked@gmail.com - * Copyright (C) 2013 Stefan Tauner + * Copyright (C) 2011 Carl-Daniel Hailfinger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,63 +27,8 @@ */
#include "flash.h" -#include "flashchips.h" #include "chipdrivers.h"
-static int stm50_unlock_address(struct flashctx *flash, int offset) -{ - chipaddr wrprotect = flash->virtual_registers + 2; - static const uint8_t unlock_sector = 0x00; - msg_cdbg("unlocking at 0x%x\n", offset); - chip_writeb(flash, unlock_sector, wrprotect + offset); - if (chip_readb(flash, wrprotect + offset) != unlock_sector) { - msg_cerr("Cannot unlock address 0x%x\n", offset); - return -1; - } - return 0; -} - -/* Chips known to use a non-uniform block and sector layout for locking (as well as for erasing): - * Name Size Address range of lock registers - * M50FLW080A 1MB FFB00002 - FFBFF002 - * M50FLW080B 1MB FFB00002 - FFBFF002 - * M50FW002 256k FFBC0002 - FFBFC002 - * M50LPW116 2MB FFA00002 - FFBFC002 - */ -int unlock_stm50_nonuniform(struct flashctx *flash) -{ - int i; - struct eraseblock *eraseblocks = flash->chip->block_erasers[0].eraseblocks; - unsigned int done = 0; - for (i = 0; i < NUM_ERASEREGIONS && eraseblocks[i].count != 0; i++) { - unsigned int block_size = eraseblocks[i].size; - unsigned int block_count = eraseblocks[i].count; - - int j; - for (j = 0; j < block_count; j++) { - if (stm50_unlock_address(flash, done)) { - msg_cerr("UNLOCK FAILED!\n"); - return -1; - } - done += block_count * block_size; - } - } - return 0; -} - -/* Unlocking for uniform 64 kB blocks starting at offset 2 of the feature registers. */ -int unlock_stm50_uniform(struct flashctx *flash) -{ - int i; - for (i = 0; i < flash->chip->total_size * 1024; i+= 64 * 1024) { - if (stm50_unlock_address(flash, i)) { - msg_cerr("UNLOCK FAILED!\n"); - return -1; - } - } - return 0; -} - static int stm50_erase_sector(struct flashctx *flash, unsigned int addr) { chipaddr bios = flash->virtual_memory + addr; diff --git a/w39.c b/w39.c index 9dcb06a..4dd366c 100644 --- a/w39.c +++ b/w39.c @@ -20,65 +20,7 @@ */
#include "flash.h" - -static int printlock_w39_fwh_block(struct flashctx *flash, unsigned int offset) -{ - chipaddr wrprotect = flash->virtual_registers + offset + 2; - uint8_t locking; - - locking = chip_readb(flash, wrprotect); - msg_cdbg("Lock status of block at 0x%08x is ", offset); - switch (locking & 0x7) { - case 0: - msg_cdbg("Full Access.\n"); - break; - case 1: - msg_cdbg("Write Lock (Default State).\n"); - break; - case 2: - msg_cdbg("Locked Open (Full Access, Lock Down).\n"); - break; - case 3: - msg_cerr("Error: Write Lock, Locked Down.\n"); - break; - case 4: - msg_cdbg("Read Lock.\n"); - break; - case 5: - msg_cdbg("Read/Write Lock.\n"); - break; - case 6: - msg_cerr("Error: Read Lock, Locked Down.\n"); - break; - case 7: - msg_cerr("Error: Read/Write Lock, Locked Down.\n"); - break; - } - - /* Read or write lock present? */ - return (locking & ((1 << 2) | (1 << 0))) ? -1 : 0; -} - -static int unlock_w39_fwh_block(struct flashctx *flash, unsigned int offset) -{ - chipaddr wrprotect = flash->virtual_registers + offset + 2; - uint8_t locking; - - locking = chip_readb(flash, wrprotect); - /* Read or write lock present? */ - if (locking & ((1 << 2) | (1 << 0))) { - /* Lockdown active? */ - if (locking & (1 << 1)) { - msg_cerr("Can't unlock block at 0x%08x!\n", offset); - return -1; - } else { - msg_cdbg("Unlocking block at 0x%08x\n", offset); - chip_writeb(flash, 0, wrprotect); - } - } - - return 0; -} +#include "chipdrivers.h"
static uint8_t w39_idmode_readb(struct flashctx *flash, unsigned int offset) { @@ -145,30 +87,6 @@ static int printlock_w39_common(struct flashctx *flash, unsigned int offset) return printlock_w39_tblwp(lock); }
-static int printlock_w39_fwh(struct flashctx *flash) -{ - unsigned int i, total_size = flash->chip->total_size * 1024; - int ret = 0; - - /* Print lock status of the complete chip */ - for (i = 0; i < total_size; i += flash->chip->page_size) - ret |= printlock_w39_fwh_block(flash, i); - - return ret; -} - -static int unlock_w39_fwh(struct flashctx *flash) -{ - unsigned int i, total_size = flash->chip->total_size * 1024; - - /* Unlock the complete chip */ - for (i = 0; i < total_size; i += flash->chip->page_size) - if (unlock_w39_fwh_block(flash, i)) - return -1; - - return 0; -} - int printlock_w39f010(struct flashctx *flash) { uint8_t lock; @@ -267,7 +185,7 @@ int printlock_w39v040fa(struct flashctx *flash) int ret = 0;
ret = printlock_w39v040a(flash); - ret |= printlock_w39_fwh(flash); + ret |= printlock_regspace2_uniform_64k(flash);
return ret; } @@ -277,7 +195,7 @@ int printlock_w39v040fb(struct flashctx *flash) int ret = 0;
ret = printlock_w39v040b(flash); - ret |= printlock_w39_fwh(flash); + ret |= printlock_regspace2_uniform_64k(flash);
return ret; } @@ -288,7 +206,7 @@ int printlock_w39v040fc(struct flashctx *flash)
/* W39V040C and W39V040FC use different WP/TBL offsets. */ ret = printlock_w39_common(flash, 0x7fff2); - ret |= printlock_w39_fwh(flash); + ret |= printlock_regspace2_uniform_64k(flash);
return ret; } @@ -303,7 +221,7 @@ int printlock_w39v080fa(struct flashctx *flash) int ret = 0;
ret = printlock_w39v080a(flash); - ret |= printlock_w39_fwh(flash); + ret |= printlock_regspace2_uniform_64k(flash);
return ret; } @@ -316,26 +234,6 @@ int printlock_w39v080fa_dual(struct flashctx *flash) return -1; }
-int unlock_w39v040fb(struct flashctx *flash) -{ - if (unlock_w39_fwh(flash)) - return -1; - if (printlock_w39_common(flash, 0x7fff2)) - return -1; - - return 0; -} - -int unlock_w39v080fa(struct flashctx *flash) -{ - if (unlock_w39_fwh(flash)) - return -1; - if (printlock_w39_common(flash, 0xffff2)) - return -1; - - return 0; -} - int printlock_at49f(struct flashctx *flash) { uint8_t lock = w39_idmode_readb(flash, 0x00002);