[flashrom] [PATCH] Refactor locking for all chips with locking at register space address +2.
Stefan Tauner
stefan.tauner at student.tuwien.ac.at
Sun Sep 2 11:19:40 CEST 2012
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 at 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 at kontron.com>
* Copyright (C) 2009 Sean Nelson <audiohacked at 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 at 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;
--
Kind regards, Stefan Tauner
More information about the flashrom
mailing list