spi25: Check quad-enable (QE) bit

When a chip has a quad-enable bit, check its status and disable
quad i/o if the bit isn't set. Note, some chips have a volatile
QE bit that we could set/reset automatically without wear. This
would require more work on the register infrastructure and chip
database, though.

Change-Id: I8a0b9b3dee14f344d4794c91d7d6fb962a8bea87
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/164
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/include/programmer.h b/include/programmer.h
index cc219be..54cbdc0 100644
--- a/include/programmer.h
+++ b/include/programmer.h
@@ -502,6 +502,10 @@
 {
 	return flash->mst.spi->features & SPI_MASTER_NO_4BA_MODES;
 }
+static inline bool spi_master_quad(const struct flashctx *const flash)
+{
+	return flash->mst.spi->features & SPI_MASTER_QUAD;
+}
 
 /* usbdev.c */
 struct libusb_device_handle;
diff --git a/spi25_prepare.c b/spi25_prepare.c
index 76ad9a7..7482c5c 100644
--- a/spi25_prepare.c
+++ b/spi25_prepare.c
@@ -77,6 +77,31 @@
 	return 0;
 }
 
+static int spi_prepare_quad_io(struct flashctx *const flash)
+{
+	if (!spi_master_quad(flash))
+		return 0;
+
+	/* Check QE bit if present */
+	if (flash->chip->reg_bits.qe.reg != INVALID_REG) {
+		const struct reg_bit_info qe = flash->chip->reg_bits.qe;
+		uint8_t reg_val;
+
+		if (spi_read_register(flash, qe.reg, &reg_val)) {
+			msg_cwarn("Failed read chip register!\n");
+			reg_val = 0;
+		}
+		if (!(reg_val & 1 << qe.bit_index)) {
+			msg_cinfo("Quad-enable (QE) bit is unknown or unset, disabling quad i/o.\n");
+			flash->chip->feature_bits &= ~FEATURE_ANY_QUAD;
+		} else {
+			msg_cdbg("Quad-enable (QE) bit is set.\n");
+		}
+	}
+
+	return 0;
+}
+
 int spi_prepare_io(struct flashctx *const flash, const enum preparation_steps prep)
 {
 	if (prep != PREPARE_FULL)
@@ -86,6 +111,10 @@
 	if (ret)
 		return ret;
 
+	ret = spi_prepare_quad_io(flash);
+	if (ret)
+		return ret;
+
 	return 0;
 }