writeprotect.c: refuse to work with chip if OTP WPS == 1

Perform the check right in read_wp_bits() as it's used by various WP
operations and also because its results won't make sense if WPS bit is
on and can't be changed.

Change-Id: I143186066a1d3af89809b7135886cb8b0d038085
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
Original-Reviewed-on: https://review.coreboot.org/c/flashrom/+/66836
Original-Reviewed-by: Edward O'Callaghan <quasisec@chromium.org>
Original-Reviewed-by: Nikolai Artemiev <nartemiev@google.com>
Reviewed-on: https://review.coreboot.org/c/flashrom-stable/+/71005
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/writeprotect.c b/writeprotect.c
index 48c5ae6..e3a1410 100644
--- a/writeprotect.c
+++ b/writeprotect.c
@@ -53,6 +53,25 @@
 	size_t i;
 	enum flashrom_wp_result ret;
 
+	/*
+	 * Write protection select bit (WPS) controls kind of write protection
+	 * that is used by the chip. When set, BP bits are ignored and each
+	 * block/sector has its own WP bit managed by special commands. When
+	 * the bit is set and we can't change it, just bail out until
+	 * implementation is extended to handle this kind of WP.
+	 */
+	if (bit_map->wps.reg != INVALID_REG && bit_map->wps.writability != RW) {
+		bool wps_bit_present;
+		uint8_t wps;
+
+		ret = read_bit(&wps, &wps_bit_present, flash, bit_map->wps);
+		if (ret != FLASHROM_WP_OK)
+			return ret;
+
+		if (wps_bit_present && wps)
+			return FLASHROM_WP_ERR_UNSUPPORTED_STATE;
+	}
+
 	ret = read_bit(&bits->tb,  &bits->tb_bit_present,  flash, bit_map->tb);
 	if (ret != FLASHROM_WP_OK)
 		return ret;
@@ -73,8 +92,6 @@
 	if (ret != FLASHROM_WP_OK)
 		return ret;
 
-	/* Note: WPS bit isn't read here, because it's not part of any range. */
-
 	for (i = 0; i < ARRAY_SIZE(bits->bp); i++) {
 		if (bit_map->bp[i].reg == INVALID_REG)
 			break;