coreboot/util/amdtool/espi.c
Michał Żygowski 7436c59875 util/amdtool: Add support for Phoenix AM5 CPUs
Add register tables and device IDs for Phoenix AM5 desktop CPUs.

TEST=Dump all data with amdtool on MSI PRO B650M-A.

Change-Id: Ia7af9194fb7516e98b7cddee2bfc65af12d56dc0
Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/90009
Reviewed-by: Michał Kopeć <michal.kopec@3mdeb.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2025-11-18 13:30:29 +00:00

202 lines
5.2 KiB
C

/* amdtool - dump all registers on an AMD CPU + chipset based system */
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <commonlib/helpers.h>
#include "amdtool.h"
#include "smn.h"
#define AMD_FCH_SPIBAR_OFFSET 0xa0
#define SPIBAR_ESPI_MMIO_OFFSET 0x10000
#define SPI_MMIO_BASE 0xfec10000
#define ESPI0_MMIO_BASE 0xfec20000
#define ESPI1_MMIO_BASE 0xfec30000
#define ESPI_MMIO_SIZE 0x10000
#define ESPI0_SMN_BASE 0x02DC5000
#define ESPI1_SMN_BASE 0x02DCA000
static const io_register_t espi_cfg_registers[] = {
{0x2C, 4, "MASTER_CAP"},
{0x30, 4, "GLBL_CTL0"},
{0x34, 4, "GLBL_CTL1"},
{0x40, 4, "SLAVE0_DECODE_EN"},
{0x44, 2, "IO_BASE[0]"},
{0x46, 2, "IO_BASE[1]"},
{0x48, 2, "IO_BASE[2]"},
{0x4A, 2, "IO_BASE[3]"},
{0x4C, 1, "IO_SIZE[0]"},
{0x4D, 1, "IO_SIZE[1]"},
{0x4E, 1, "IO_SIZE[2]"},
{0x4F, 1, "IO_SIZE[3]"},
{0x50, 4, "MMIO_BASE[0]"},
{0x54, 4, "MMIO_BASE[1]"},
{0x58, 4, "MMIO_BASE[2]"},
{0x5C, 4, "MMIO_BASE[3]"},
{0x60, 2, "MMIO_SIZE[0]"},
{0x62, 2, "MMIO_SIZE[1]"},
{0x64, 2, "MMIO_SIZE[2]"},
{0x66, 2, "MMIO_SIZE[3]"},
{0x68, 4, "SLAVE0_CFG"},
{0x6C, 4, "SLAVE0_INT_EN"},
{0x70, 4, "SLAVE0_INT_STS"},
{0x80, 2, "IO_BASE[4]"},
{0x82, 2, "IO_BASE[5]"},
{0x84, 2, "IO_BASE[6]"},
{0x86, 2, "IO_BASE[7]"},
{0x88, 1, "IO_SIZE[4]"},
{0x89, 1, "IO_SIZE[5]"},
{0x8A, 1, "IO_SIZE[6]"},
{0x8B, 1, "IO_SIZE[7]"},
{0x8C, 2, "IO_BASE[8]"},
{0x8E, 2, "IO_BASE[9]"},
{0x90, 2, "IO_BASE[10]"},
{0x92, 2, "IO_BASE[11]"},
{0x94, 1, "IO_SIZE[8]"},
{0x95, 1, "IO_SIZE[9]"},
{0x96, 1, "IO_SIZE[10]"},
{0x97, 1, "IO_SIZE[11]"},
{0xA8, 4, "SLAVE0_RXVW_MISC_CNTL"},
{0xAC, 4, "SLAVE0_RXVW_POLARITY"},
{0xB0, 2, "IO_BASE[12]"},
{0xB2, 2, "IO_BASE[13]"},
{0xB4, 2, "IO_BASE[14]"},
{0xB6, 2, "IO_BASE[15]"},
{0xB8, 1, "IO_SIZE[12]"},
{0xB9, 1, "IO_SIZE[13]"},
{0xBA, 1, "IO_SIZE[14]"},
{0xBB, 1, "IO_SIZE[15]"},
{0xBC, 4, "MMIO_BASE[4]"},
{0xC0, 4, "MMIO_SIZE[4]"},
{0xC4, 4, "MMIO_CPU_TEMP"},
{0xC8, 4, "MMIO_RTC_TIME"},
{0xCC, 4, "ESPI_MISC_CTL1"},
};
static bool use_smn = false;
static uint32_t espi_smn_addr[2] = { 0, 0 };
static volatile uint8_t *espibar;
static uint32_t espi_read32(const io_register_t *reg, size_t espi_cntrlr)
{
if (use_smn)
return smn_read32(espi_smn_addr[espi_cntrlr] + reg->addr);
else
return read32(espibar + (espi_cntrlr * ESPI_MMIO_SIZE) + reg->addr);
}
static uint32_t espi_read16(const io_register_t *reg, size_t espi_cntrlr)
{
if (use_smn)
return smn_read16(espi_smn_addr[espi_cntrlr] + reg->addr);
else
return read16(espibar + (espi_cntrlr * ESPI_MMIO_SIZE) + reg->addr);
}
static uint32_t espi_read8(const io_register_t *reg, size_t espi_cntrlr)
{
if (use_smn)
return smn_read8(espi_smn_addr[espi_cntrlr] + reg->addr);
else
return read8(espibar + (espi_cntrlr * ESPI_MMIO_SIZE) + reg->addr);
}
int print_espi(struct pci_dev *sb, struct pci_dev *nb)
{
size_t i, espi, cfg_registers_size = 0;
uint32_t spibar_phys, spibar_mask;
const io_register_t *cfg_registers;
int smbus_rev = 0;
size_t num_espi = 1;
printf("\n========== eSPI ==========\n\n");
switch (sb->device_id) {
case PCI_DEVICE_ID_AMD_FCH_LPC_2:
smbus_rev = find_smbus_dev_rev(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FCH_SMB_2);
if (smbus_rev == -1)
return 1;
switch (smbus_rev) {
case 0x71:
if (nb->device_id == PCI_DEVICE_ID_AMD_BRH_ROOT_COMPLEX)
num_espi = 2;
cfg_registers = espi_cfg_registers;
cfg_registers_size = ARRAY_SIZE(espi_cfg_registers);
espi_smn_addr[0] = ESPI0_SMN_BASE;
espi_smn_addr[1] = ESPI1_SMN_BASE;
spibar_mask = 0xffffff00;
break;
default:
printf("Error: Dumping eSPI on this southbridge is not (yet) supported.\n");
return 1;
}
break;
default:
printf("Error: Dumping eSPI on this southbridge is not (yet) supported.\n");
return 1;
}
spibar_phys = pci_read_long(sb, AMD_FCH_SPIBAR_OFFSET);
if ((spibar_phys & spibar_mask) == 0) {
perror("Error SPIBAR not programmed");
return 1;
}
if (spibar_phys == UINT32_MAX) {
spibar_phys = SPI_MMIO_BASE;
}
spibar_phys &= spibar_mask;
espibar = map_physical(spibar_phys + SPIBAR_ESPI_MMIO_OFFSET,
ESPI_MMIO_SIZE * num_espi);
if (espibar == NULL) {
perror("Error mapping ESPI BAR, trying SMN");
use_smn = true;
}
for (espi = 0; espi < num_espi; espi++) {
printf("\n---------- eSPI %lu ----------\n\n", espi);
if (use_smn)
printf("ESPI%lu 0x%08x (SMN)\n\n", espi, espi_smn_addr[espi]);
else
printf("ESPI%lu 0x%08x (MEM)\n\n", espi,
(uint32_t)(spibar_phys + SPIBAR_ESPI_MMIO_OFFSET + (ESPI_MMIO_SIZE * espi)));
for (i = 0; i < cfg_registers_size; i++) {
switch (cfg_registers[i].size) {
case 4:
printf("0x%04x: 0x%08x (%s)\n",
cfg_registers[i].addr,
espi_read32(&cfg_registers[i], espi),
cfg_registers[i].name);
break;
case 2:
printf("0x%04x: 0x%04x (%s)\n",
cfg_registers[i].addr,
espi_read16(&cfg_registers[i], espi),
cfg_registers[i].name);
break;
case 1:
printf("0x%04x: 0x%02x (%s)\n",
cfg_registers[i].addr,
espi_read8(&cfg_registers[i], espi),
cfg_registers[i].name);
break;
default:
printf("Error: register size %d not implemented.\n",
cfg_registers[i].size);
break;
}
}
}
return 0;
}