[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