4BA: Add spi_exit_4ba function to switch SPI flash to 3-byte addressing

Change-Id: I553e7fb5028f35e14a3a81b3fa8903c1b321a223
Signed-off-by: Ed Swierk <eswierk@skyportsystems.com>
Reviewed-on: https://review.coreboot.org/20509
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/chipdrivers.h b/chipdrivers.h
index 20529d5..16a75a9 100644
--- a/chipdrivers.h
+++ b/chipdrivers.h
@@ -198,6 +198,8 @@
 /* spi4ba.c */
 int spi_enter_4ba_b7(struct flashctx *flash);
 int spi_enter_4ba_b7_we(struct flashctx *flash);
+int spi_exit_4ba_e9(struct flashctx *flash);
+int spi_exit_4ba_e9_we(struct flashctx *flash);
 int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte);
 int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
 int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
diff --git a/spi4ba.c b/spi4ba.c
index 93f19c4..a44e067 100644
--- a/spi4ba.c
+++ b/spi4ba.c
@@ -78,6 +78,49 @@
 	return result;
 }
 
+/* Exit 4-bytes addressing mode (without sending WREN before) */
+int spi_exit_4ba_e9(struct flashctx *flash)
+{
+	const unsigned char cmd[JEDEC_EXIT_4_BYTE_ADDR_MODE_OUTSIZE] = { JEDEC_EXIT_4_BYTE_ADDR_MODE };
+
+	msg_trace("-> %s\n", __func__);
+
+	/* Switch to 3-bytes addressing mode  */
+	return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
+}
+
+/* Exit 4-bytes addressing mode with sending WREN before */
+int spi_exit_4ba_e9_we(struct flashctx *flash)
+{
+	int result;
+	struct spi_command cmds[] = {
+	{
+		.writecnt	= JEDEC_WREN_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_WREN },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= JEDEC_EXIT_4_BYTE_ADDR_MODE_OUTSIZE,
+		.writearr	= (const unsigned char[]){ JEDEC_EXIT_4_BYTE_ADDR_MODE },
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}, {
+		.writecnt	= 0,
+		.writearr	= NULL,
+		.readcnt	= 0,
+		.readarr	= NULL,
+	}};
+
+	msg_trace("-> %s\n", __func__);
+
+	/* Switch to 3-bytes addressing mode  */
+	result = spi_send_multicommand(flash, cmds);
+	if (result) {
+		msg_cerr("%s failed during command execution\n", __func__);
+	}
+	return result;
+}
+
 /* Program one flash byte from 4-bytes addressing mode */
 int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte)
 {
diff --git a/spi4ba.h b/spi4ba.h
index 8e500d1..8a01792 100644
--- a/spi4ba.h
+++ b/spi4ba.h
@@ -80,6 +80,10 @@
 int spi_enter_4ba_b7(struct flashctx *flash);
 int spi_enter_4ba_b7_we(struct flashctx *flash);
 
+/* exit 4-bytes addressing mode */
+int spi_exit_4ba_e9(struct flashctx *flash);
+int spi_exit_4ba_e9_we(struct flashctx *flash);
+
 /* read/write flash bytes in 4-bytes addressing mode */
 int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte);
 int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);