Add support for selecting the erased bit value with a flag

Most flash chips are erased to ones and programmed to zeros. However, some
other chips, such as the ENE KB9012 internal flash, work the opposite way.

Change-Id: Ia7b0de8568e31f9bf263ba0ad6b051e837477b6b
Signed-off-by: Mike Banon <mikebdp2@gmail.com>
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
Reviewed-on: https://review.coreboot.org/23258
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/flash.h b/flash.h
index a71fec1..f2c6cbe 100644
--- a/flash.h
+++ b/flash.h
@@ -130,6 +130,13 @@
 #define FEATURE_4BA_NATIVE	(FEATURE_4BA_READ | FEATURE_4BA_FAST_READ | FEATURE_4BA_WRITE)
 #define FEATURE_4BA		(FEATURE_4BA_ENTER | FEATURE_4BA_EXT_ADDR | FEATURE_4BA_NATIVE)
 #define FEATURE_4BA_WREN	(FEATURE_4BA_ENTER_WREN | FEATURE_4BA_EXT_ADDR | FEATURE_4BA_NATIVE)
+/*
+ * Most flash chips are erased to ones and programmed to zeros. However, some
+ * other flash chips, such as the ENE KB9012 internal flash, work the opposite way.
+ */
+#define FEATURE_ERASED_ZERO	(1 << 16)
+
+#define ERASED_VALUE(flash)	(((flash)->chip->feature_bits & FEATURE_ERASED_ZERO) ? 0x00 : 0xff)
 
 enum test_state {
 	OK = 0,
@@ -309,7 +316,7 @@
 int read_flash_to_file(struct flashctx *flash, const char *filename);
 char *extract_param(const char *const *haystack, const char *needle, const char *delim);
 int verify_range(struct flashctx *flash, const uint8_t *cmpbuf, unsigned int start, unsigned int len);
-int need_erase(const uint8_t *have, const uint8_t *want, unsigned int len, enum write_granularity gran);
+int need_erase(const uint8_t *have, const uint8_t *want, unsigned int len, enum write_granularity gran, const uint8_t erased_value);
 void print_version(void);
 void print_buildinfo(void);
 void print_banner(void);
diff --git a/flashrom.c b/flashrom.c
index a7de995..26b9863 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -700,12 +700,13 @@
 {
 	int ret;
 	uint8_t *cmpbuf = malloc(len);
+	const uint8_t erased_value = ERASED_VALUE(flash);
 
 	if (!cmpbuf) {
 		msg_gerr("Could not allocate memory!\n");
 		exit(1);
 	}
-	memset(cmpbuf, 0xff, len);
+	memset(cmpbuf, erased_value, len);
 	ret = verify_range(flash, cmpbuf, start, len);
 	free(cmpbuf);
 	return ret;
@@ -758,7 +759,8 @@
 }
 
 /* Helper function for need_erase() that focuses on granularities of gran bytes. */
-static int need_erase_gran_bytes(const uint8_t *have, const uint8_t *want, unsigned int len, unsigned int gran)
+static int need_erase_gran_bytes(const uint8_t *have, const uint8_t *want, unsigned int len,
+                                 unsigned int gran, const uint8_t erased_value)
 {
 	unsigned int i, j, limit;
 	for (j = 0; j < len / gran; j++) {
@@ -768,7 +770,7 @@
 			continue;
 		/* have needs to be in erased state. */
 		for (i = 0; i < limit; i++)
-			if (have[j * gran + i] != 0xff)
+			if (have[j * gran + i] != erased_value)
 				return 1;
 	}
 	return 0;
@@ -788,7 +790,8 @@
  * @gran	write granularity (enum, not count)
  * @return      0 if no erase is needed, 1 otherwise
  */
-int need_erase(const uint8_t *have, const uint8_t *want, unsigned int len, enum write_granularity gran)
+int need_erase(const uint8_t *have, const uint8_t *want, unsigned int len,
+               enum write_granularity gran, const uint8_t erased_value)
 {
 	int result = 0;
 	unsigned int i;
@@ -803,31 +806,31 @@
 		break;
 	case write_gran_1byte:
 		for (i = 0; i < len; i++)
-			if ((have[i] != want[i]) && (have[i] != 0xff)) {
+			if ((have[i] != want[i]) && (have[i] != erased_value)) {
 				result = 1;
 				break;
 			}
 		break;
 	case write_gran_128bytes:
-		result = need_erase_gran_bytes(have, want, len, 128);
+		result = need_erase_gran_bytes(have, want, len, 128, erased_value);
 		break;
 	case write_gran_256bytes:
-		result = need_erase_gran_bytes(have, want, len, 256);
+		result = need_erase_gran_bytes(have, want, len, 256, erased_value);
 		break;
 	case write_gran_264bytes:
-		result = need_erase_gran_bytes(have, want, len, 264);
+		result = need_erase_gran_bytes(have, want, len, 264, erased_value);
 		break;
 	case write_gran_512bytes:
-		result = need_erase_gran_bytes(have, want, len, 512);
+		result = need_erase_gran_bytes(have, want, len, 512, erased_value);
 		break;
 	case write_gran_528bytes:
-		result = need_erase_gran_bytes(have, want, len, 528);
+		result = need_erase_gran_bytes(have, want, len, 528, erased_value);
 		break;
 	case write_gran_1024bytes:
-		result = need_erase_gran_bytes(have, want, len, 1024);
+		result = need_erase_gran_bytes(have, want, len, 1024, erased_value);
 		break;
 	case write_gran_1056bytes:
-		result = need_erase_gran_bytes(have, want, len, 1056);
+		result = need_erase_gran_bytes(have, want, len, 1056, erased_value);
 		break;
 	case write_gran_1byte_implicit_erase:
 		/* Do not erase, handle content changes from anything->0xff by writing 0xff. */
@@ -1772,11 +1775,12 @@
 	ret = 1;
 	bool skipped = true;
 	uint8_t *const curcontents = info->curcontents + info->erase_start;
-	if (need_erase(curcontents, newcontents, erase_len, flashctx->chip->gran)) {
+	const uint8_t erased_value = ERASED_VALUE(flashctx);
+	if (need_erase(curcontents, newcontents, erase_len, flashctx->chip->gran, erased_value)) {
 		if (erase_block(flashctx, info, erasefn))
 			goto _free_ret;
 		/* Erase was successful. Adjust curcontents. */
-		memset(curcontents, 0xff, erase_len);
+		memset(curcontents, erased_value, erase_len);
 		skipped = false;
 	}