soc/intel/common: Add APIs to check CSE's write protection info

The patch add APIs to check CSE Region's write protection information.
Also, adds helper functions to get the SPI controller's MMIO address
to access to BIOS_GPR0 register. The BIOS_GPR0 indicates write and read
protection details.

During the coreboot image build, write protection is enabled for CSE RO.
It is enabled through a Intel MFIT XML configuration.

TEST=Verify write protection information of CSE Region

Signed-off-by: Sridhar Siricilla <sridhar.siricilla@intel.com>
Change-Id: If1da0fc410a15996f2e139809f7652127ef8761b
Reviewed-on: https://review.coreboot.org/c/coreboot/+/62986
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
diff --git a/src/soc/intel/common/block/include/intelblocks/spi.h b/src/soc/intel/common/block/include/intelblocks/spi.h
index 38c9a57..4ab4105 100644
--- a/src/soc/intel/common/block/include/intelblocks/spi.h
+++ b/src/soc/intel/common/block/include/intelblocks/spi.h
@@ -3,6 +3,17 @@
 #ifndef SOC_INTEL_COMMON_BLOCK_SPI_H
 #define SOC_INTEL_COMMON_BLOCK_SPI_H
 
+#include <types.h>
+
+/*
+ * Check if write protection for CSE RO is enabled or not.
+ * Returns true if write protection for CSE RO is enabled, false otherwise.
+ */
+bool is_spi_wp_cse_ro_en(void);
+
+/* Gets CSE RO's write protected area's base address and limit */
+void spi_get_wp_cse_ro_range(uint32_t *base, uint32_t *limit);
+
 /*
  * SoC overrides
  *
diff --git a/src/soc/intel/common/block/spi/spi.c b/src/soc/intel/common/block/spi/spi.c
index 50e1bea..0716e1a 100644
--- a/src/soc/intel/common/block/spi/spi.c
+++ b/src/soc/intel/common/block/spi/spi.c
@@ -1,8 +1,12 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 
+#define __SIMPLE_DEVICE__
+
 #include <device/device.h>
+#include <device/mmio.h>
 #include <device/pci.h>
 #include <device/pci_ids.h>
+#include <device/pci_ops.h>
 #include <device/spi.h>
 #include <intelblocks/fast_spi.h>
 #include <intelblocks/gspi.h>
@@ -20,6 +24,83 @@
 
 const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);
 
+#define MMIO_BIOS_GPR0	0x98
+
+union spi_bios_gpr0 {
+	struct {
+		/* Specified write protection is enabled */
+		/*
+		 * This field corresponds to flash address bits 26:12
+		 * and specifies the lower limit of protected range.
+		 */
+		uint32_t protect_range_base:15;
+
+		/* Specifies read protection is enabled */
+		uint32_t read_protect_en:1;
+
+		/*
+		 * This field corresponds to flash address bits 26:12
+		 * and specifies the upper limit of the protected range
+		 */
+		uint32_t protect_range_limit:15;
+
+		uint32_t write_protect_en:1;
+	} __packed fields;
+
+	uint32_t data;
+};
+
+/* Read SPI BAR 0 from PCI configuration space */
+static uintptr_t get_spi_bar(pci_devfn_t dev)
+{
+	uintptr_t bar;
+
+	bar = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
+	assert(bar != 0);
+	/*
+	 * Bits 31-12 are the base address as per EDS for SPI,
+	 * Don't care about 0-11 bit
+	 */
+	return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
+}
+
+static uint32_t spi_read_bar(pci_devfn_t dev, uint32_t offset)
+{
+	return read32p(get_spi_bar(dev) + offset);
+}
+
+static uint32_t spi_read_bios_gpr0(void)
+{
+	return spi_read_bar(PCH_DEV_SPI, MMIO_BIOS_GPR0);
+}
+
+static uint32_t spi_get_wp_cse_ro_start_offset(union spi_bios_gpr0 bios_gpr0)
+{
+	return bios_gpr0.fields.protect_range_base << 12;
+}
+
+static uint32_t spi_get_wp_cse_ro_limit(union spi_bios_gpr0 bios_gpr0)
+{
+	return bios_gpr0.fields.protect_range_limit << 12 | 0xfff;
+}
+
+bool is_spi_wp_cse_ro_en(void)
+{
+	union spi_bios_gpr0 bios_gpr0;
+
+	bios_gpr0.data = spi_read_bios_gpr0();
+	return !!bios_gpr0.fields.write_protect_en;
+}
+
+void spi_get_wp_cse_ro_range(uint32_t *base, uint32_t *limit)
+{
+	union spi_bios_gpr0 bios_gpr0;
+
+	bios_gpr0.data = spi_read_bios_gpr0();
+	*base = spi_get_wp_cse_ro_start_offset(bios_gpr0);
+	*limit = spi_get_wp_cse_ro_limit(bios_gpr0);
+}
+
 static int spi_dev_to_bus(struct device *dev)
 {
 	return spi_soc_devfn_to_bus(dev->path.pci.devfn);