writeprotect: add {get,set}_wp_mode()

Tested: flashrom --wp-{enable,disable,status}

Change-Id: I7b68e940f0e1359281806c98e1da119b4caf8405
Signed-off-by: Nikolai Artemiev <nartemiev@google.com>
Original-Reviewed-on: https://review.coreboot.org/c/flashrom/+/58483
Original-Reviewed-by: Anastasia Klimchuk <aklm@chromium.org>
Original-Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Original-Reviewed-by: Nico Huber <nico.h@gmx.de>
Original-Reviewed-by: Edward O'Callaghan <quasisec@chromium.org>
Reviewed-on: https://review.coreboot.org/c/flashrom-stable/+/70973
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/libflashrom.h b/libflashrom.h
index db04467..c35f331 100644
--- a/libflashrom.h
+++ b/libflashrom.h
@@ -126,7 +126,9 @@
 	FLASHROM_WP_ERR_READ_FAILED = 3,
 	FLASHROM_WP_ERR_WRITE_FAILED = 4,
 	FLASHROM_WP_ERR_VERIFY_FAILED = 5,
-	FLASHROM_WP_ERR_RANGE_UNSUPPORTED = 6
+	FLASHROM_WP_ERR_RANGE_UNSUPPORTED = 6,
+	FLASHROM_WP_ERR_MODE_UNSUPPORTED = 7,
+	FLASHROM_WP_ERR_RANGE_LIST_UNAVAILABLE = 8
 };
 
 enum flashrom_wp_mode {
diff --git a/writeprotect.c b/writeprotect.c
index 28d692d..ecf471f 100644
--- a/writeprotect.c
+++ b/writeprotect.c
@@ -353,6 +353,50 @@
 	return ret;
 }
 
+/** Get the mode selected by a WP configuration. */
+static int get_wp_mode(enum flashrom_wp_mode *mode, const struct wp_bits *bits)
+{
+	if (!bits->srp_bit_present)
+		return FLASHROM_WP_ERR_CHIP_UNSUPPORTED;
+
+	if (bits->srl_bit_present && bits->srl == 1) {
+		*mode = bits->srp ? FLASHROM_WP_MODE_PERMANENT :
+				    FLASHROM_WP_MODE_POWER_CYCLE;
+	} else {
+		*mode = bits->srp ? FLASHROM_WP_MODE_HARDWARE :
+				    FLASHROM_WP_MODE_DISABLED;
+	}
+
+	return FLASHROM_WP_OK;
+}
+
+/** Modify a wp_bits structure such that it will select a specified protection mode. */
+static int set_wp_mode(struct wp_bits *bits, const enum flashrom_wp_mode mode)
+{
+	switch (mode) {
+	case FLASHROM_WP_MODE_DISABLED:
+		bits->srl = 0;
+		bits->srp = 0;
+		return FLASHROM_WP_OK;
+
+	case FLASHROM_WP_MODE_HARDWARE:
+		bits->srl = 0;
+		bits->srp = 1;
+		return FLASHROM_WP_OK;
+
+	case FLASHROM_WP_MODE_POWER_CYCLE:
+	case FLASHROM_WP_MODE_PERMANENT:
+	default:
+		/*
+		 * Don't try to enable power cycle or permanent protection for
+		 * now. Those modes may be possible to activate on some chips,
+		 * but they are usually unavailable by default or require special
+		 * commands to activate.
+		 */
+		return FLASHROM_WP_ERR_MODE_UNSUPPORTED;
+	}
+}
+
 static bool chip_supported(struct flashctx *flash)
 {
 	return (flash->chip != NULL) && (flash->chip->decode_range != NULL);
@@ -372,11 +416,8 @@
 	if (ret == FLASHROM_WP_OK)
 		ret = get_wp_range(&cfg->range, flash, &bits);
 
-	/* TODO: implement and get_wp_mode() and call it */
-	/*
 	if (ret == FLASHROM_WP_OK)
 		ret = get_wp_mode(&cfg->mode, &bits);
-	*/
 
 	return ret;
 }
@@ -399,11 +440,8 @@
 		ret = write_wp_bits(flash, bits);
 
 	/* Set protection mode */
-	/* TODO: implement set_wp_mode() and use it */
-	/*
 	if (ret == FLASHROM_WP_OK)
 		ret = set_wp_mode(&bits, cfg->mode);
-	*/
 	if (ret == FLASHROM_WP_OK)
 		ret = write_wp_bits(flash, bits);