spi25: Try to set volatile quad-enable (QE) automatically

Some chips have a volatile QE bit. Setting this won't wear the status/
configuration register, so we'll try to do so automatically.

Change-Id: I6a4b864d7af1f3ecedd95524f127b5486f999933
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/191
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/include/flash.h b/include/flash.h
index fb64304..9743e3e 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -461,6 +461,7 @@
 	int address_high_byte;
 	bool in_4ba_mode;
 	bool in_qpi_mode;
+	bool volatile_qe_enabled;
 	/* For SPI flash chips, we dynamically select the fast-read operation. */
 	struct spi_read_op *spi_fast_read;
 
diff --git a/spi25_prepare.c b/spi25_prepare.c
index 6ad1f7f..3efc83b 100644
--- a/spi25_prepare.c
+++ b/spi25_prepare.c
@@ -110,15 +110,27 @@
 		return 0;
 
 	/* Check QE bit if present */
+	flash->volatile_qe_enabled = false;
 	if (flash->chip->reg_bits.qe.reg != INVALID_REG) {
 		const struct reg_bit_info qe = flash->chip->reg_bits.qe;
+		const uint8_t mask = 1 << qe.bit_index;
 		uint8_t reg_val;
 
 		if (spi_read_register(flash, qe.reg, &reg_val)) {
-			msg_cwarn("Failed read chip register!\n");
 			reg_val = 0;
+		} else if (!(reg_val & mask) &&
+			   (flash->chip->feature_bits & FEATURE_WRSR_EWSR)) {
+			msg_pdbg("Trying to set volatile quad-enable (QE).\n");
+			reg_val |= mask;
+			if (spi_write_register(flash, qe.reg, reg_val, WRSR_VOLATILE_BITS) ||
+			    spi_read_register(flash, qe.reg, &reg_val)) {
+				reg_val = 0;
+			} else if (reg_val & mask) {
+				flash->volatile_qe_enabled = true;
+			}
 		}
-		if (!(reg_val & 1 << qe.bit_index)) {
+
+		if (!(reg_val & mask)) {
 			msg_cinfo("Quad-enable (QE) bit is unknown or unset, disabling quad i/o.\n");
 			flash->chip->feature_bits &= ~FEATURE_ANY_QUAD;
 		} else {
@@ -267,5 +279,15 @@
 		if (spi_exit_qpi(flash))
 			msg_cwarn("Failed to exit QPI mode!\n");
 	}
+	if (flash->volatile_qe_enabled) {
+		msg_pdbg("Trying to restore volatile quad-enable (QE) state.\n");
+		const struct reg_bit_info qe = flash->chip->reg_bits.qe;
+		uint8_t reg_val;
+
+		if (!spi_read_register(flash, qe.reg, &reg_val)) {
+			reg_val &= ~(1 << qe.bit_index);
+			spi_write_register(flash, qe.reg, reg_val, WRSR_VOLATILE_BITS);
+		}
+	}
 	free(flash->spi_fast_read);
 }