summaryrefslogtreecommitdiff
path: root/src/soc/amd
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/amd')
-rw-r--r--src/soc/amd/common/block/include/amdblocks/chip.h4
-rw-r--r--src/soc/amd/common/block/include/amdblocks/espi.h31
-rw-r--r--src/soc/amd/common/block/lpc/Makefile.inc5
-rw-r--r--src/soc/amd/common/block/lpc/espi_util.c291
4 files changed, 331 insertions, 0 deletions
diff --git a/src/soc/amd/common/block/include/amdblocks/chip.h b/src/soc/amd/common/block/include/amdblocks/chip.h
index 6e3c973c97..b0348115e9 100644
--- a/src/soc/amd/common/block/include/amdblocks/chip.h
+++ b/src/soc/amd/common/block/include/amdblocks/chip.h
@@ -4,6 +4,7 @@
#ifndef __AMDBLOCKS_CHIP_H__
#define __AMDBLOCKS_CHIP_H__
+#include <amdblocks/espi.h>
#include <amdblocks/spi.h>
struct soc_amd_common_config {
@@ -17,6 +18,9 @@ struct soc_amd_common_config {
* TPM speed - 66MHz
*/
struct spi_config spi_config;
+
+ /* eSPI configuration */
+ struct espi_config espi_config;
};
/*
diff --git a/src/soc/amd/common/block/include/amdblocks/espi.h b/src/soc/amd/common/block/include/amdblocks/espi.h
index 82410e58d3..53cc5f9f3f 100644
--- a/src/soc/amd/common/block/include/amdblocks/espi.h
+++ b/src/soc/amd/common/block/include/amdblocks/espi.h
@@ -4,6 +4,9 @@
#ifndef __AMDBLOCKS_ESPI_H__
#define __AMDBLOCKS_ESPI_H__
+#include <stdint.h>
+#include <stddef.h>
+
/* eSPI MMIO base lives at an offset of 0x10000 from the address in SPI BAR. */
#define ESPI_OFFSET_FROM_BAR 0x10000
@@ -24,4 +27,32 @@
#define ESPI_GENERIC_MMIO_WIN_COUNT 4
#define ESPI_GENERIC_MMIO_MAX_WIN_SIZE 0x10000
+struct espi_config {
+ /* Bitmap for standard IO decodes. Use ESPI_DECODE_IO_* above. */
+ uint32_t std_io_decode_bitmap;
+
+ struct {
+ uint16_t base;
+ size_t size;
+ } generic_io_range[ESPI_GENERIC_IO_WIN_COUNT];
+};
+
+/*
+ * Open I/O window using the provided base and size.
+ * Return value: 0 = success, -1 = error.
+ */
+int espi_open_io_window(uint16_t base, size_t size);
+
+/*
+ * Open MMIO window using the provided base and size.
+ * Return value: 0 = success, -1 = error.
+ */
+int espi_open_mmio_window(uint32_t base, size_t size);
+
+/*
+ * Configure generic and standard I/O decode windows using the espi_config structure settings
+ * provided by mainboard in device tree.
+ */
+void espi_configure_decodes(void);
+
#endif /* __AMDBLOCKS_ESPI_H__ */
diff --git a/src/soc/amd/common/block/lpc/Makefile.inc b/src/soc/amd/common/block/lpc/Makefile.inc
index 72b1e42013..7db176b31d 100644
--- a/src/soc/amd/common/block/lpc/Makefile.inc
+++ b/src/soc/amd/common/block/lpc/Makefile.inc
@@ -6,3 +6,8 @@ romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c
postcar-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c
ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c
smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c
+
+bootblock-$(CONFIG_SOC_AMD_COMMON_BLOCK_USE_ESPI) += espi_util.c
+romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_USE_ESPI) += espi_util.c
+ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_USE_ESPI) += espi_util.c
+verstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_USE_ESPI) += espi_util.c
diff --git a/src/soc/amd/common/block/lpc/espi_util.c b/src/soc/amd/common/block/lpc/espi_util.c
new file mode 100644
index 0000000000..2585c46138
--- /dev/null
+++ b/src/soc/amd/common/block/lpc/espi_util.c
@@ -0,0 +1,291 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* This file is part of the coreboot project. */
+
+#include <amdblocks/chip.h>
+#include <amdblocks/espi.h>
+#include <amdblocks/lpc.h>
+#include <arch/mmio.h>
+#include <console/console.h>
+#include <soc/pci_devs.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <types.h>
+
+static uintptr_t espi_get_bar(void)
+{
+ uintptr_t espi_spi_base = lpc_get_spibase();
+ return espi_spi_base + ESPI_OFFSET_FROM_BAR;
+}
+
+static uint32_t espi_read32(int reg)
+{
+ return read32((void *)(espi_get_bar() + reg));
+}
+
+static void espi_write32(int reg, uint32_t val)
+{
+ write32((void *)(espi_get_bar() + reg), val);
+}
+
+static uint16_t espi_read16(int reg)
+{
+ return read16((void *)(espi_get_bar() + reg));
+}
+
+static void espi_write16(int reg, uint16_t val)
+{
+ write16((void *)(espi_get_bar() + reg), val);
+}
+
+static uint8_t espi_read8(int reg)
+{
+ return read8((void *)(espi_get_bar() + reg));
+}
+
+static void espi_write8(int reg, uint8_t val)
+{
+ write8((void *)(espi_get_bar() + reg), val);
+}
+
+static void espi_enable_decode(int decode_en)
+{
+ uint32_t val;
+
+ val = espi_read32(ESPI_DECODE);
+ val |= decode_en;
+ espi_write32(ESPI_DECODE, val);
+}
+
+static bool espi_is_decode_enabled(int decode)
+{
+ uint32_t val;
+
+ val = espi_read32(ESPI_DECODE);
+ return !!(val & decode);
+}
+
+static int espi_find_io_window(uint16_t win_base)
+{
+ int i;
+
+ for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
+ if (!espi_is_decode_enabled(ESPI_DECODE_IO_RANGE_EN(i)))
+ continue;
+
+ if (espi_read16(ESPI_IO_RANGE_BASE(i)) == win_base)
+ return i;
+ }
+
+ return -1;
+}
+
+static int espi_get_unused_io_window(void)
+{
+ int i;
+
+ for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
+ if (!espi_is_decode_enabled(ESPI_DECODE_IO_RANGE_EN(i)))
+ return i;
+ }
+
+ return -1;
+}
+
+/*
+ * Returns decode enable bits for standard IO port addresses. If port address is not supported
+ * by standard decode or if the size of window is not 1, then it returns -1.
+ */
+static int espi_std_io_decode(uint16_t base, size_t size)
+{
+ int ret = -1;
+
+ if (size != 1)
+ return ret;
+
+ switch (base) {
+ case 0x80:
+ ret = ESPI_DECODE_IO_0x80_EN;
+ break;
+ case 0x60:
+ case 0x64:
+ ret = ESPI_DECODE_IO_0X60_0X64_EN;
+ break;
+ case 0x2e:
+ case 0x2f:
+ ret = ESPI_DECODE_IO_0X2E_0X2F_EN;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+static size_t espi_get_io_window_size(int idx)
+{
+ return espi_read8(ESPI_IO_RANGE_SIZE(idx)) + 1;
+}
+
+static void espi_write_io_window(int idx, uint16_t base, size_t size)
+{
+ espi_write16(ESPI_IO_RANGE_BASE(idx), base);
+ espi_write8(ESPI_IO_RANGE_SIZE(idx), size - 1);
+}
+
+static int espi_open_generic_io_window(uint16_t base, size_t size)
+{
+ size_t win_size;
+ int idx;
+
+ for (; size; size -= win_size, base += win_size) {
+ win_size = MIN(size, ESPI_GENERIC_IO_MAX_WIN_SIZE);
+
+ idx = espi_find_io_window(base);
+ if (idx != -1) {
+ size_t curr_size = espi_get_io_window_size(idx);
+
+ if (curr_size > win_size) {
+ printk(BIOS_INFO, "eSPI window already configured to be larger than requested! ");
+ printk(BIOS_INFO, "Base: 0x%x, Requested size: 0x%zx, Actual size: 0x%zx\n",
+ base, win_size, curr_size);
+ } else if (curr_size < win_size) {
+ espi_write_io_window(idx, base, win_size);
+ printk(BIOS_INFO, "eSPI window at base: 0x%x resized from 0x%zx to 0x%zx\n",
+ base, curr_size, win_size);
+ }
+
+ continue;
+ }
+
+ idx = espi_get_unused_io_window();
+ if (idx == -1) {
+ printk(BIOS_ERR, "Cannot open IO window base %x size %zx\n", base,
+ size);
+ printk(BIOS_ERR, "ERROR: No more available IO windows!\n");
+ return -1;
+ }
+
+ espi_write_io_window(idx, base, win_size);
+ espi_enable_decode(ESPI_DECODE_IO_RANGE_EN(idx));
+ }
+
+ return 0;
+}
+
+int espi_open_io_window(uint16_t base, size_t size)
+{
+ int std_io;
+
+ std_io = espi_std_io_decode(base, size);
+ if (std_io != -1) {
+ espi_enable_decode(std_io);
+ return 0;
+ }
+
+ return espi_open_generic_io_window(base, size);
+}
+
+static int espi_find_mmio_window(uint32_t win_base)
+{
+ int i;
+
+ for (i = 0; i < ESPI_GENERIC_MMIO_WIN_COUNT; i++) {
+ if (!espi_is_decode_enabled(ESPI_DECODE_MMIO_RANGE_EN(i)))
+ continue;
+
+ if (espi_read32(ESPI_MMIO_RANGE_BASE(i)) == win_base)
+ return i;
+ }
+
+ return -1;
+}
+
+static int espi_get_unused_mmio_window(void)
+{
+ int i;
+
+ for (i = 0; i < ESPI_GENERIC_MMIO_WIN_COUNT; i++) {
+ if (!espi_is_decode_enabled(ESPI_DECODE_MMIO_RANGE_EN(i)))
+ return i;
+ }
+
+ return -1;
+
+}
+
+static size_t espi_get_mmio_window_size(int idx)
+{
+ return espi_read16(ESPI_MMIO_RANGE_SIZE(idx)) + 1;
+}
+
+static void espi_write_mmio_window(int idx, uint32_t base, size_t size)
+{
+ espi_write32(ESPI_MMIO_RANGE_BASE(idx), base);
+ espi_write16(ESPI_MMIO_RANGE_SIZE(idx), size - 1);
+}
+
+int espi_open_mmio_window(uint32_t base, size_t size)
+{
+ size_t win_size;
+ int idx;
+
+ for (; size; size -= win_size, base += win_size) {
+ win_size = MIN(size, ESPI_GENERIC_MMIO_MAX_WIN_SIZE);
+
+ idx = espi_find_mmio_window(base);
+ if (idx != -1) {
+ size_t curr_size = espi_get_mmio_window_size(idx);
+
+ if (curr_size > win_size) {
+ printk(BIOS_INFO, "eSPI window already configured to be larger than requested! ");
+ printk(BIOS_INFO, "Base: 0x%x, Requested size: 0x%zx, Actual size: 0x%zx\n",
+ base, win_size, curr_size);
+ } else if (curr_size < win_size) {
+ espi_write_mmio_window(idx, base, win_size);
+ printk(BIOS_INFO, "eSPI window at base: 0x%x resized from 0x%zx to 0x%zx\n",
+ base, curr_size, win_size);
+ }
+
+ continue;
+ }
+
+ idx = espi_get_unused_mmio_window();
+ if (idx == -1) {
+ printk(BIOS_ERR, "Cannot open IO window base %x size %zx\n", base,
+ size);
+ printk(BIOS_ERR, "ERROR: No more available MMIO windows!\n");
+ return -1;
+ }
+
+ espi_write_mmio_window(idx, base, win_size);
+ espi_enable_decode(ESPI_DECODE_MMIO_RANGE_EN(idx));
+ }
+
+ return 0;
+}
+
+static const struct espi_config *espi_get_config(void)
+{
+ const struct soc_amd_common_config *soc_cfg = soc_get_common_config();
+
+ if (!soc_cfg)
+ die("Common config structure is NULL!\n");
+
+ return &soc_cfg->espi_config;
+}
+
+void espi_configure_decodes(void)
+{
+ int i;
+ const struct espi_config *cfg = espi_get_config();
+
+ espi_enable_decode(cfg->std_io_decode_bitmap);
+
+ for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
+ if (cfg->generic_io_range[i].size == 0)
+ continue;
+ espi_open_generic_io_window(cfg->generic_io_range[i].base,
+ cfg->generic_io_range[i].size);
+ }
+}