soc/amd/common/block/lpc: Add helpers for managing eSPI decode
This change adds the following helper functions for eSPI decode: 1. espi_open_io_window() - Open generic IO window decoded by eSPI 2. espi_open_mmio_window() - Open generic MMIO window decoded by eSPI 3. espi_configure_decodes() - Configures standard and generic I/O windows using the espi configuration provided by mainboard in device tree. BUG=b:153675913,b:154445472 Change-Id: Idb49ef0477280eb46ecad65131d4cd7357618941 Signed-off-by: Furquan Shaikh <furquan@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/41073 Reviewed-by: Aaron Durbin <adurbin@chromium.org> Reviewed-by: Raul Rangel <rrangel@chromium.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
dd5264612a
commit
f318e03495
|
@ -4,6 +4,7 @@
|
||||||
#ifndef __AMDBLOCKS_CHIP_H__
|
#ifndef __AMDBLOCKS_CHIP_H__
|
||||||
#define __AMDBLOCKS_CHIP_H__
|
#define __AMDBLOCKS_CHIP_H__
|
||||||
|
|
||||||
|
#include <amdblocks/espi.h>
|
||||||
#include <amdblocks/spi.h>
|
#include <amdblocks/spi.h>
|
||||||
|
|
||||||
struct soc_amd_common_config {
|
struct soc_amd_common_config {
|
||||||
|
@ -17,6 +18,9 @@ struct soc_amd_common_config {
|
||||||
* TPM speed - 66MHz
|
* TPM speed - 66MHz
|
||||||
*/
|
*/
|
||||||
struct spi_config spi_config;
|
struct spi_config spi_config;
|
||||||
|
|
||||||
|
/* eSPI configuration */
|
||||||
|
struct espi_config espi_config;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
#ifndef __AMDBLOCKS_ESPI_H__
|
#ifndef __AMDBLOCKS_ESPI_H__
|
||||||
#define __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. */
|
/* eSPI MMIO base lives at an offset of 0x10000 from the address in SPI BAR. */
|
||||||
#define ESPI_OFFSET_FROM_BAR 0x10000
|
#define ESPI_OFFSET_FROM_BAR 0x10000
|
||||||
|
|
||||||
|
@ -24,4 +27,32 @@
|
||||||
#define ESPI_GENERIC_MMIO_WIN_COUNT 4
|
#define ESPI_GENERIC_MMIO_WIN_COUNT 4
|
||||||
#define ESPI_GENERIC_MMIO_MAX_WIN_SIZE 0x10000
|
#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__ */
|
#endif /* __AMDBLOCKS_ESPI_H__ */
|
||||||
|
|
|
@ -6,3 +6,8 @@ romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c
|
||||||
postcar-$(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
|
ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c
|
||||||
smm-$(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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue