Add an utility similar to inteltool, which dumps useful information for porting a board to coreboot. TEST=Use amdtool on Gigabyte MZ33-AR1 with vendor BIOS and coreboot. Change-Id: I34405897d0f5670038e7923f3680a28090d92821 Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/89492 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Michał Kopeć <michal.kopec@3mdeb.com>
185 lines
4.6 KiB
C
185 lines
4.6 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 <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <inttypes.h>
|
|
#include <assert.h>
|
|
#include "acpimmio.h"
|
|
#include "amdtool.h"
|
|
|
|
#define ACPIMMIO_REGION_SIZE 0x100
|
|
|
|
const uint8_t *acpimmio_bar = NULL;
|
|
size_t acpimmio_size = 0;
|
|
|
|
static const io_register_t kunlun_acpi_mmio_regions[] = {
|
|
{ 0x0000, ACPIMMIO_REGION_SIZE, "SMB PCI" },
|
|
{ 0x0200, ACPIMMIO_REGION_SIZE, "SMI" },
|
|
{ 0x0300, ACPIMMIO_REGION_SIZE, "PMIO" },
|
|
{ 0x0400, ACPIMMIO_REGION_SIZE, "PMIO2" },
|
|
{ 0x0500, ACPIMMIO_REGION_SIZE, "BIOS RAM" },
|
|
{ 0x0600, ACPIMMIO_REGION_SIZE, "CMOS RAM" },
|
|
{ 0x0700, ACPIMMIO_REGION_SIZE, "CMOS" },
|
|
{ 0x0800, ACPIMMIO_REGION_SIZE, "ACPI" },
|
|
{ 0x0900, ACPIMMIO_REGION_SIZE, "ASF" },
|
|
{ 0x0a00, ACPIMMIO_REGION_SIZE, "SMB IO" },
|
|
{ 0x0b00, ACPIMMIO_REGION_SIZE, "WDT" },
|
|
{ 0x0c00, ACPIMMIO_REGION_SIZE, "HPET" },
|
|
{ 0x0d00, ACPIMMIO_REGION_SIZE, "IOMUX" },
|
|
{ 0x0e00, ACPIMMIO_REGION_SIZE, "MISC" },
|
|
{ 0x1000, ACPIMMIO_REGION_SIZE, "Serial debug" },
|
|
{ 0x1100, ACPIMMIO_REGION_SIZE, "Shadow timer" },
|
|
{ 0x1200, ACPIMMIO_REGION_SIZE, "Remote GPIO+IOMUX" },
|
|
{ 0x1300, ACPIMMIO_REGION_SIZE, "MISC2" },
|
|
{ 0x1400, ACPIMMIO_REGION_SIZE, "DP-VGA" },
|
|
{ 0x1500, ACPIMMIO_REGION_SIZE, "GPIO0" },
|
|
{ 0x1600, ACPIMMIO_REGION_SIZE, "GPIO1" },
|
|
{ 0x1700, ACPIMMIO_REGION_SIZE, "GPIO2" },
|
|
{ 0x1800, ACPIMMIO_REGION_SIZE, "GPIO3" },
|
|
{ 0x1900, ACPIMMIO_REGION_SIZE, "GPIO4" },
|
|
{ 0x1d00, ACPIMMIO_REGION_SIZE, "AC DC TIMER" },
|
|
{ 0x1e00, ACPIMMIO_REGION_SIZE, "AOAC" },
|
|
};
|
|
|
|
static uint8_t pmio_read8(uint8_t reg)
|
|
{
|
|
outb(reg, 0xcd6);
|
|
return inb(0xcd7);
|
|
}
|
|
|
|
static void print_region(const uint32_t offset)
|
|
{
|
|
unsigned int i, j;
|
|
|
|
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
|
|
|
|
for (i = 0; i < 0x100; i += 16) {
|
|
printf("%02x: ", i);
|
|
for (j = 0; j < 16; j++) {
|
|
printf("%02"PRIx8, read8(acpimmio_bar + offset + i + j));
|
|
if (j < 15)
|
|
printf(" ");
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
static void print_acpi_mmio_regions(const io_register_t *acpi_mmio_regions, size_t size)
|
|
{
|
|
size_t i;
|
|
|
|
if (acpi_mmio_regions == NULL)
|
|
return;
|
|
|
|
for (i = 0; i < size; i++) {
|
|
printf("\n========== %s (offset 0x%04x) ==========\n",
|
|
acpi_mmio_regions[i].name, acpi_mmio_regions[i].addr);
|
|
print_region(acpi_mmio_regions[i].addr);
|
|
}
|
|
}
|
|
|
|
static int init_acpimmio(struct pci_dev *sb)
|
|
{
|
|
pciaddr_t acpimmio_phys;
|
|
bool acpimmio_enabled = false;
|
|
int smbus_rev = 0;
|
|
|
|
if (acpimmio_bar)
|
|
return 1;
|
|
|
|
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:
|
|
acpimmio_phys = 0xfed80000;
|
|
acpimmio_size = 0x2000;
|
|
acpimmio_enabled = !!(pmio_read8(0x4) & 0x2);
|
|
break;
|
|
default:
|
|
printf("Error: Dumping ACPI MMIO on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
perror("Error: Dumping ACPI MMIO on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
if (!acpimmio_enabled) {
|
|
perror("ACPI MMIO not decoded by the soutbridge\n");
|
|
return 1;
|
|
}
|
|
|
|
if (acpimmio_phys == 0 || acpimmio_size == 0) {
|
|
perror("Error: Invalid ACPI MMIO address or size.\n");
|
|
return 1;
|
|
}
|
|
|
|
printf("ACPI MMIO = 0x%08"PRIx64" (size 0x%"PRIx64") (MEM)\n\n", (uint64_t)acpimmio_phys, acpimmio_size);
|
|
acpimmio_bar = map_physical(acpimmio_phys, acpimmio_size);
|
|
if (!acpimmio_bar) {
|
|
perror("Error mapping ACPI MMIO");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int print_acpimmio(struct pci_dev *sb)
|
|
{
|
|
int smbus_rev = 0;
|
|
size_t acpimmio_regions_size = 0;
|
|
const io_register_t *acpi_mmio_regions = NULL;
|
|
|
|
printf("\n========== ACPI MMIO ==========\n\n");
|
|
|
|
if (init_acpimmio(sb))
|
|
return 1;
|
|
|
|
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:
|
|
acpi_mmio_regions = kunlun_acpi_mmio_regions;
|
|
acpimmio_regions_size = ARRAY_SIZE(kunlun_acpi_mmio_regions);
|
|
break;
|
|
default:
|
|
printf("Error: Dumping ACPI MMIO on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
perror("Error: Dumping ACPI MMIO on this southbridge is not (yet) supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
print_acpi_mmio_regions(acpi_mmio_regions, acpimmio_regions_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
const uint8_t *get_acpi_mmio_bar(struct pci_dev *sb)
|
|
{
|
|
init_acpimmio(sb);
|
|
|
|
return (const uint8_t *)acpimmio_bar;
|
|
}
|
|
|
|
void acpimmio_cleanup(void)
|
|
{
|
|
if (acpimmio_bar)
|
|
unmap_physical((void *)acpimmio_bar, acpimmio_size);
|
|
}
|