siemens/mc_bdx1: Set up opcode menu for SPI controller

Since SPI controller opcode registers are locked by FSP, they need to be
initialized to a known good state before ReadyToBoot event and after
every SPI flash access (e.g. for MRC cache) has been finished in order
to enable the OS to use SPI controller without constraints.

Change-Id: I0a66344cd44e036c3999ae98d539072299cf5112
Signed-off-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-on: https://review.coreboot.org/15547
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
diff --git a/src/mainboard/siemens/mc_bdx1/mainboard.c b/src/mainboard/siemens/mc_bdx1/mainboard.c
index af886a9..bad072b 100644
--- a/src/mainboard/siemens/mc_bdx1/mainboard.c
+++ b/src/mainboard/siemens/mc_bdx1/mainboard.c
@@ -31,9 +31,57 @@
 #include <boot/coreboot_tables.h>
 #include <hwilib.h>
 #include <i210.h>
+#include <soc/pci_devs.h>
 
 #define MAX_PATH_DEPTH		12
 #define MAX_NUM_MAPPINGS	10
+
+/*
+ * SPI Opcode Menu setup for SPIBAR lock down
+ * should support most common flash chips.
+ */
+#define SPI_OPMENU_0 0x01 /* WRSR: Write Status Register */
+#define SPI_OPTYPE_0 0x01 /* Write, no address */
+
+#define SPI_OPMENU_1 0x02 /* BYPR: Byte Program */
+#define SPI_OPTYPE_1 0x03 /* Write, address required */
+
+#define SPI_OPMENU_2 0x03 /* READ: Read Data */
+#define SPI_OPTYPE_2 0x02 /* Read, address required */
+
+#define SPI_OPMENU_3 0x05 /* RDSR: Read Status Register */
+#define SPI_OPTYPE_3 0x00 /* Read, no address */
+
+#define SPI_OPMENU_4 0x20 /* SE20: Sector Erase 0x20 */
+#define SPI_OPTYPE_4 0x03 /* Write, address required */
+
+#define SPI_OPMENU_5 0x9f /* RDID: Read ID */
+#define SPI_OPTYPE_5 0x00 /* Read, no address */
+
+#define SPI_OPMENU_6 0xd8 /* BED8: Block Erase 0xd8 */
+#define SPI_OPTYPE_6 0x03 /* Write, address required */
+
+#define SPI_OPMENU_7 0x0b /* FAST: Fast Read */
+#define SPI_OPTYPE_7 0x02 /* Read, address required */
+
+#define SPI_OPMENU_UPPER ((SPI_OPMENU_7 << 24) | (SPI_OPMENU_6 << 16) | \
+			  (SPI_OPMENU_5 << 8) | SPI_OPMENU_4)
+#define SPI_OPMENU_LOWER ((SPI_OPMENU_3 << 24) | (SPI_OPMENU_2 << 16) | \
+			  (SPI_OPMENU_1 << 8) | SPI_OPMENU_0)
+
+#define SPI_OPTYPE ((SPI_OPTYPE_7 << 14) | (SPI_OPTYPE_6 << 12) | \
+		    (SPI_OPTYPE_5 << 10) | (SPI_OPTYPE_4 << 8) | \
+		    (SPI_OPTYPE_3 << 6) | (SPI_OPTYPE_2 << 4) | \
+		    (SPI_OPTYPE_1 << 2) | (SPI_OPTYPE_0))
+
+#define SPI_OPPREFIX ((0x50 << 8) | 0x06) /* EWSR and WREN */
+
+#define SPIBAR_OFFSET		0x3800
+#define SPI_REG_PREOP		0x94
+#define SPI_REG_OPTYPE		0x96
+#define SPI_REG_OPMENU_L	0x98
+#define SPI_REG_OPMENU_H	0x9c
+
 /*
  * mainboard_enable is executed as first thing after enumerate_buses().
  * This is the earliest point to add customization.
@@ -42,6 +90,25 @@
 {
 
 }
+
+static void mainboard_final(void *chip_info)
+{
+	void *spi_base = NULL;
+	uint32_t rcba = 0;
+	device_t dev = dev_find_slot(0, PCI_DEVFN(LPC_DEV, LPC_FUNC));
+
+	/* Get address of SPI controller. */
+	rcba = (pci_read_config32(dev, 0xf0) & 0xffffc000);
+	if (!rcba)
+		return;
+	spi_base = (void *)(rcba + SPIBAR_OFFSET);
+	/* Setup OPCODE menu */
+	write16((spi_base + SPI_REG_PREOP), SPI_OPPREFIX);
+	write16((spi_base + SPI_REG_OPTYPE), SPI_OPTYPE);
+	write32((spi_base + SPI_REG_OPMENU_L), SPI_OPMENU_LOWER);
+	write32((spi_base + SPI_REG_OPMENU_H), SPI_OPMENU_UPPER);
+}
+
 /** \brief This function can decide if a given MAC address is valid or not.
  *         Currently, addresses filled with 0xff or 0x00 are not valid.
  * @param  mac  Buffer to the MAC address to check
@@ -116,4 +183,5 @@
 
 struct chip_operations mainboard_ops = {
 	.enable_dev = mainboard_enable,
+	.final = mainboard_final
 };