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>
424 lines
11 KiB
C
424 lines
11 KiB
C
/* amdtool - dump all registers on an AMD CPU + chipset based system */
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "amdtool.h"
|
|
#include "smn.h"
|
|
|
|
#define AMD_FCH_SPIBAR_OFFSET 0xa0
|
|
|
|
#define SPI_SMN_BASE 0x2DC4000
|
|
|
|
static const io_register_t spi100_speed_cfg_fields[] = {
|
|
{ 0x0, 4, "TPM Speed" },
|
|
{ 0x4, 4, "Alt Speed" },
|
|
{ 0x8, 4, "Fast Read Speed" },
|
|
{ 0xc, 4, "Normal Speed" },
|
|
};
|
|
|
|
static const io_register_t spi100_host_prefetch_cfg_fields[] = {
|
|
{ 0x0, 7, "Host Prefetch Size" },
|
|
{ 0x7, 1, "Host Prefetch on 64B Boudnary" },
|
|
{ 0x8, 4, "Host Hit Range" },
|
|
{ 0xc, 1, "Host Will Hit Enable" },
|
|
{ 0xd, 1, "Host Hit Soon Enable" },
|
|
{ 0xe, 1, "Host Burst Enable" },
|
|
{ 0xf, 1, "Host Burst to 4DW Enable" },
|
|
};
|
|
|
|
static const io_register_t spi_cntl0_fields[] = {
|
|
{ 0x0, 8, "Spi OpCode (Reserved)" },
|
|
{ 0x8, 1, "Disable Index Retry" },
|
|
{ 0x9, 1, "Index Cacheline Stop" },
|
|
{ 0xA, 2, "ROM Protection Compare Range" },
|
|
{ 0x12, 1, "SPI Read Mode [0]" },
|
|
{ 0x15, 1, "Illegal Access" },
|
|
{ 0x16, 1, "SPI MAC Access ROM Enable" },
|
|
{ 0x17, 1, "SPI Host Access ROM Enable" },
|
|
{ 0x1c, 1, "SPI Clock Gate" },
|
|
{ 0x1d, 1, "SPI Read Mode [1]" },
|
|
{ 0x1e, 1, "SPI Read Mode [2]" },
|
|
{ 0x1f, 1, "SPI Busy" },
|
|
};
|
|
|
|
static const io_register_t kunlun_alt_spi_cs_fields[] = {
|
|
{ 0x0, 2, "Alt SPI CS Enable" },
|
|
{ 0x3, 1, "SPI Protect Enable 0" },
|
|
{ 0x5, 1, "SPI Protect Lock" },
|
|
{ 0x6, 1, "Lock SPI CS" },
|
|
};
|
|
|
|
static const io_register_t tacoma_alt_spi_cs_fields[] = {
|
|
{ 0x0, 2, "Alt SPI CS Enable" },
|
|
{ 0x3, 1, "SPI Protect Enable 0" },
|
|
{ 0x5, 1, "SPI Protect Lock" },
|
|
};
|
|
|
|
static const char * const spi100_speed_values[] = {
|
|
"66.66 MHz",
|
|
"33.33 MHz",
|
|
"22.22 MHz",
|
|
"16.66 Mhz",
|
|
"100 MHz",
|
|
"800 KHz",
|
|
"Defined in SPIx6C[5:0]",
|
|
"Defined in SPIx6C[13:8]"
|
|
};
|
|
|
|
static const io_register_t spi_bar_registers[] = {
|
|
{ 0x00, 4, "SPI Control 0" },
|
|
{ 0x04, 4, "SPI Restricted Command" },
|
|
{ 0x08, 4, "SPI Restricted Command 2" },
|
|
{ 0x0C, 4, "SPI Control 1" },
|
|
{ 0x10, 4, "ESPI Control" },
|
|
{ 0x14, 4, "SPI Command Value 1" },
|
|
{ 0x18, 4, "SPI Command Value 2" },
|
|
{ 0x1C, 1, "ROMCP CS" },
|
|
{ 0x1D, 1, "SPI ALT CS" },
|
|
{ 0x20, 4, "SPI100 Enable" },
|
|
{ 0x24, 4, "SPI100 Precyc0" },
|
|
{ 0x28, 4, "SPI100 Precyc1" },
|
|
{ 0x2C, 2, "SPI100 Host Prefetch Config" },
|
|
{ 0x2E, 2, "TPM SPI DI Timeout" },
|
|
{ 0x30, 2, "ROM2 Address Override" },
|
|
{ 0x32, 2, "SPI100 Dummy Cycle Config" },
|
|
{ 0x32, 2, "SPI100 Rx Timing Config" },
|
|
{ 0x40, 1, "DDR Command Code" },
|
|
{ 0x41, 1, "QDR Command Code" },
|
|
{ 0x42, 1, "DPR Command Code" },
|
|
{ 0x43, 1, "QPR Command Code" },
|
|
{ 0x44, 1, "Mode Byte" },
|
|
{ 0x50, 4, "Addr32 Control 0" },
|
|
{ 0x54, 4, "Addr32 Control 1" },
|
|
{ 0x58, 4, "Addr32 Control 2" },
|
|
{ 0x5C, 4, "Addr32 Control 3" },
|
|
{ 0x60, 4, "BAR 64MB ROM3 Low" },
|
|
{ 0x64, 4, "BAR 64MB ROM3 High" },
|
|
{ 0x68, 4, "SPI Restricted Command 3" },
|
|
{ 0x6C, 4, "SPI Speed" },
|
|
{ 0x70, 4, "Host Interrupt" },
|
|
{ 0x74, 4, "LPC SPI Interrupt" },
|
|
{ 0x78, 4, "Flash Idle COunt" },
|
|
{ 0xFC, 2, "SPI Misc Control" },
|
|
};
|
|
|
|
|
|
int use_smn_access = 0;
|
|
volatile uint8_t *spibar = NULL;
|
|
uint32_t spi_smn_base = 0;
|
|
|
|
static uint8_t spi_read8(uint32_t offset)
|
|
{
|
|
if (use_smn_access)
|
|
return smn_read8(spi_smn_base + offset);
|
|
else
|
|
return read8(spibar + offset);
|
|
}
|
|
|
|
static uint16_t spi_read16(uint32_t offset)
|
|
{
|
|
if (use_smn_access)
|
|
return smn_read16(spi_smn_base + offset);
|
|
else
|
|
return read16(spibar + offset);
|
|
}
|
|
|
|
static uint32_t spi_read32(uint32_t offset)
|
|
{
|
|
if (use_smn_access)
|
|
return smn_read32(spi_smn_base + offset);
|
|
else
|
|
return read32(spibar + offset);
|
|
}
|
|
|
|
static int print_spi_cntrl0(struct pci_dev *sb)
|
|
{
|
|
int i, size = 0;
|
|
int smbus_rev = 0;
|
|
uint32_t spi_cntrl0 = UINT32_MAX;
|
|
const io_register_t *spi_cntrl_register = NULL;
|
|
|
|
printf("\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:
|
|
spi_cntrl0 = spi_read32(0);
|
|
spi_cntrl_register = spi_cntl0_fields;
|
|
size = ARRAY_SIZE(spi_cntl0_fields);
|
|
break;
|
|
default:
|
|
printf("Error: Dumping SPI CNTRL on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
printf("Error: Dumping SPI CNTRL on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
printf("SPI_CNTRL0 = 0x%08x\n\n", spi_cntrl0);
|
|
|
|
if (spi_cntrl_register) {
|
|
for (i = 0; i < size; i++) {
|
|
unsigned int val = spi_cntrl0 >> spi_cntrl_register[i].addr;
|
|
val &= ((1 << spi_cntrl_register[i].size) -1);
|
|
printf("0x%04x = %s\n", val, spi_cntrl_register[i].name);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int print_spi_alt_cs(struct pci_dev *sb, struct pci_dev *nb)
|
|
{
|
|
int i, size = 0;
|
|
int smbus_rev = 0;
|
|
uint8_t spi_alt_cs = 0xff;
|
|
const io_register_t *spi_alt_cs_register = NULL;
|
|
|
|
printf("\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:
|
|
switch (nb->device_id) {
|
|
case PCI_DEVICE_ID_AMD_BRH_ROOT_COMPLEX:
|
|
spi_alt_cs = spi_read8(0x1d);
|
|
spi_alt_cs_register = kunlun_alt_spi_cs_fields;
|
|
size = ARRAY_SIZE(kunlun_alt_spi_cs_fields);
|
|
break;
|
|
case PCI_DEVICE_ID_AMD_PHX_ROOT_COMPLEX:
|
|
spi_alt_cs = spi_read8(0x1d);
|
|
spi_alt_cs_register = tacoma_alt_spi_cs_fields;
|
|
size = ARRAY_SIZE(tacoma_alt_spi_cs_fields);
|
|
break;
|
|
default:
|
|
goto alt_cs_err;
|
|
}
|
|
break;
|
|
default:
|
|
goto alt_cs_err;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
goto alt_cs_err;
|
|
}
|
|
|
|
printf("SPI_ALT_CS = 0x%02x\n\n", spi_alt_cs);
|
|
|
|
if (spi_alt_cs_register) {
|
|
for (i = 0; i < size; i++) {
|
|
unsigned int val = spi_alt_cs >> spi_alt_cs_register[i].addr;
|
|
val &= ((1 << spi_alt_cs_register[i].size) -1);
|
|
printf("0x%04x = %s\n", val, spi_alt_cs_register[i].name);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
alt_cs_err:
|
|
printf("Error: Dumping SPI_ALT_CS on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
static int print_spi_speed_config(struct pci_dev *sb)
|
|
{
|
|
size_t i, size = 0, values_size = 0;
|
|
uint16_t spi_speed_cfg = UINT16_MAX;
|
|
const io_register_t *spi_speed_cfg_register = NULL;
|
|
const char * const *speed_values = NULL;
|
|
int smbus_rev = 0;
|
|
|
|
printf("\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:
|
|
spi_speed_cfg = spi_read16(0x22);
|
|
spi_speed_cfg_register = spi100_speed_cfg_fields;
|
|
size = ARRAY_SIZE(spi100_speed_cfg_fields);
|
|
speed_values = spi100_speed_values;
|
|
values_size = ARRAY_SIZE(spi100_speed_values);
|
|
break;
|
|
default:
|
|
printf("Error: Dumping SPI100_SPEED_CFG on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
printf("Error: Dumping SPI100_SPEED_CFG on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
printf("SPI100_SPEED_CFG = 0x%04x\n\n", spi_speed_cfg);
|
|
|
|
if (spi_speed_cfg_register && speed_values) {
|
|
for (i = 0; i < size; i++) {
|
|
unsigned int val = spi_speed_cfg >> spi_speed_cfg_register[i].addr;
|
|
val &= ((1 << spi_speed_cfg_register[i].size) -1);
|
|
if (val < values_size)
|
|
printf("0x%04x = %s (%s)\n", val, spi_speed_cfg_register[i].name,
|
|
speed_values[val]);
|
|
else
|
|
printf("0x%04x = %s (Reserved)\n", val, spi_speed_cfg_register[i].name);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int print_spi_host_prefetch(struct pci_dev *sb)
|
|
{
|
|
int i, size = 0;
|
|
uint16_t spi_host_prefetch = UINT16_MAX;
|
|
const io_register_t *spi_host_prefetch_register = NULL;
|
|
int smbus_rev = 0;
|
|
|
|
printf("\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:
|
|
spi_host_prefetch = spi_read16(0x2c);
|
|
spi_host_prefetch_register = spi100_host_prefetch_cfg_fields;
|
|
size = ARRAY_SIZE(spi100_host_prefetch_cfg_fields);
|
|
break;
|
|
default:
|
|
printf("Error: Dumping SPI100_HOST_PREFETCH_CFG on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
printf("Error: Dumping SPI100_HOST_PREFETCH_CFG on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
printf("SPI100_HOST_PREFETCH_CFG = 0x%04x\n\n", spi_host_prefetch);
|
|
|
|
if (spi_host_prefetch_register) {
|
|
for (i = 0; i < size; i++) {
|
|
unsigned int val = spi_host_prefetch >> spi_host_prefetch_register[i].addr;
|
|
val &= ((1 << spi_host_prefetch_register[i].size) - 1);
|
|
printf("0x%04x = %s\n", val, spi_host_prefetch_register[i].name);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int print_spibar(struct pci_dev *sb, struct pci_dev *nb)
|
|
{
|
|
int i, size = 0, spi_size = 0x1000;
|
|
uint32_t spibar_phys, spibar_mask;
|
|
const io_register_t *spi_register = NULL;
|
|
int smbus_rev;
|
|
|
|
printf("\n============= SPI Bar ==============\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:
|
|
size = ARRAY_SIZE(spi_bar_registers);
|
|
spi_register = spi_bar_registers;
|
|
spibar_mask = 0xffffff00;
|
|
spi_smn_base = SPI_SMN_BASE;
|
|
break;
|
|
default:
|
|
printf("Error: Dumping SPI on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
printf("Error: Dumping SPI 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 || (spibar_phys == 0xffffffff)) {
|
|
if (spi_smn_base != 0) {
|
|
use_smn_access = 1;
|
|
} else {
|
|
perror("Error SPIBAR not programmed");
|
|
return 1;
|
|
}
|
|
} else {
|
|
if (spibar_phys == UINT32_MAX) {
|
|
perror("Error SPIBAR invalid");
|
|
return 1;
|
|
}
|
|
|
|
spibar = map_physical(spibar_phys & spibar_mask, spi_size);
|
|
if (spibar == NULL) {
|
|
perror("Error mapping SPIBAR");
|
|
return 1;
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < size; i++) {
|
|
switch(spi_register[i].size) {
|
|
case 1:
|
|
printf("0x%08x = %s\n", spi_read8(spi_register[i].addr), spi_register[i].name);
|
|
break;
|
|
case 2:
|
|
printf("0x%08x = %s\n", spi_read16(spi_register[i].addr), spi_register[i].name);
|
|
break;
|
|
case 4:
|
|
printf("0x%08x = %s\n", spi_read32(spi_register[i].addr), spi_register[i].name);
|
|
break;
|
|
case 8:
|
|
printf("0x%08x%08x = %s\n", spi_read32(spi_register[i].addr + 4),
|
|
spi_read32(spi_register[i].addr), spi_register[i].name);
|
|
break;
|
|
}
|
|
}
|
|
|
|
print_spi_cntrl0(sb);
|
|
print_spi_alt_cs(sb, nb);
|
|
print_spi_speed_config(sb);
|
|
print_spi_host_prefetch(sb);
|
|
|
|
if (spibar)
|
|
unmap_physical((void *)spibar, spi_size);
|
|
|
|
printf("\n====================================\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int print_spi(struct pci_dev *sb, struct pci_dev *nb)
|
|
{
|
|
return print_spibar(sb, nb);
|
|
}
|