util/amdtool: Add utility to dump useful information on AMD CPUs
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>
This commit is contained in:
parent
3cf976e51a
commit
8f3626c4b5
17 changed files with 2952 additions and 0 deletions
1
util/amdtool/.gitignore
vendored
Normal file
1
util/amdtool/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
amdtool
|
||||
85
util/amdtool/Makefile
Normal file
85
util/amdtool/Makefile
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
PROGRAM = amdtool
|
||||
|
||||
top ?= $(abspath ../..)
|
||||
|
||||
CC ?= gcc
|
||||
INSTALL ?= /usr/bin/env install
|
||||
PREFIX ?= /usr/local
|
||||
CFLAGS ?= -O2 -g -Wall -Wextra -Wmissing-prototypes
|
||||
LDFLAGS += -lpci -lz
|
||||
|
||||
CPPFLAGS += -I$(top)/util/amdtool
|
||||
CPPFLAGS += -I$(top)/src/commonlib/include -I$(top)/src/commonlib/bsd/include
|
||||
CPPFLAGS += -I$(top)/src/arch/x86/include
|
||||
|
||||
OBJS = amdtool.o gpio.o acpimmio.o spi.o lpc.o psb.o smn.o cpu.o irq.o espi.o
|
||||
|
||||
OS_ARCH = $(shell uname)
|
||||
ifeq ($(OS_ARCH), Darwin)
|
||||
LDFLAGS += -framework DirectHW
|
||||
endif
|
||||
ifeq ($(OS_ARCH), FreeBSD)
|
||||
CPPFLAGS += -I/usr/local/include
|
||||
LDFLAGS += -L/usr/local/lib
|
||||
LIBS = -lz
|
||||
endif
|
||||
ifeq ($(OS_ARCH), NetBSD)
|
||||
CPPFLAGS += -I/usr/pkg/include
|
||||
LDFLAGS += -L/usr/pkg/lib -Wl,-rpath-link,/usr/pkg/lib -lz -lpciutils -lpci -l$(shell uname -p)
|
||||
endif
|
||||
|
||||
all: pciutils dep $(PROGRAM)
|
||||
|
||||
$(PROGRAM): $(OBJS)
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $(PROGRAM) $(OBJS) $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f $(PROGRAM) *.o *~ junit.xml .dependencies
|
||||
|
||||
distclean: clean
|
||||
rm -f .dependencies
|
||||
|
||||
dep:
|
||||
@$(CC) $(CFLAGS) $(CPPFLAGS) -MM *.c > .dependencies
|
||||
|
||||
define LIBPCI_TEST
|
||||
/* Avoid a failing test due to libpci header symbol shadowing breakage */
|
||||
#define index shadow_workaround_index
|
||||
#ifdef __NetBSD__
|
||||
#include <pciutils/pci.h>
|
||||
#else
|
||||
#include <pci/pci.h>
|
||||
#endif
|
||||
struct pci_access *pacc;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
pacc = pci_alloc();
|
||||
return 0;
|
||||
}
|
||||
endef
|
||||
export LIBPCI_TEST
|
||||
|
||||
pciutils:
|
||||
@printf "\nChecking for pciutils and zlib... "
|
||||
@echo "$$LIBPCI_TEST" > .test.c
|
||||
@$(CC) $(CFLAGS) $(CPPFLAGS) .test.c -o .test $(LDFLAGS) \
|
||||
>/dev/null 2>&1 && \
|
||||
printf "found.\n" || ( printf "not found.\n\n"; \
|
||||
printf "Please install pciutils-devel and zlib-devel.\n"; \
|
||||
printf "See README for more information.\n\n"; \
|
||||
rm -f .test.c .test; exit 1)
|
||||
@rm -rf .test.c .test .test.dSYM
|
||||
|
||||
install: $(PROGRAM)
|
||||
$(INSTALL) -d $(DESTDIR)$(PREFIX)/sbin
|
||||
$(INSTALL) $(PROGRAM) $(DESTDIR)$(PREFIX)/sbin
|
||||
$(INSTALL) -d $(DESTDIR)$(PREFIX)/share/man/man8
|
||||
$(INSTALL) -p -m644 $(PROGRAM).8 $(DESTDIR)$(PREFIX)/share/man/man8
|
||||
|
||||
.PHONY: all clean distclean dep pciutils
|
||||
|
||||
-include .dependencies
|
||||
185
util/amdtool/acpimmio.c
Normal file
185
util/amdtool/acpimmio.c
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
/* 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);
|
||||
}
|
||||
12
util/amdtool/acpimmio.h
Normal file
12
util/amdtool/acpimmio.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/* amdtool - dump all registers on an AMD CPU + chipset based system */
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef AMDTOOL_ACPIMMIO_H
|
||||
#define AMDTOOL_ACPIMMIO_H 1
|
||||
|
||||
#include "amdtool.h"
|
||||
|
||||
const uint8_t *get_acpi_mmio_bar(struct pci_dev *sb);
|
||||
void acpimmio_cleanup(void);
|
||||
|
||||
#endif
|
||||
63
util/amdtool/amdtool.8
Normal file
63
util/amdtool/amdtool.8
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
.TH AMDTOOL 8
|
||||
.SH NAME
|
||||
amdtool \- a tool for dumping AMD CPU / chipset configuration parameters
|
||||
.SH SYNOPSIS
|
||||
.B amdtool \fR[\fB\-vh?gGlcMApsa\fR]
|
||||
.SH DESCRIPTION
|
||||
.B amdtool
|
||||
is a handy little tool for dumping the configuration space of AMD
|
||||
CPUs, northbridges and southbridges.
|
||||
.sp
|
||||
This tool has been developed for the coreboot project (see
|
||||
.B https://coreboot.org
|
||||
for details on coreboot).
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B "\-h, \-\-help"
|
||||
Show a help text and exit.
|
||||
.TP
|
||||
.B "\-v, \-\-version"
|
||||
Show version information and exit.
|
||||
.TP
|
||||
.B "\-a, \-\-all"
|
||||
Dump all known information listed below.
|
||||
.TP
|
||||
.B "\-c, \-\-cpu"
|
||||
Dump CPU information and features.
|
||||
.TP
|
||||
.B "\-g, \-\-gpio"
|
||||
Dump Fusion Controller Hub (FCH) southbridge GPIO registers.
|
||||
.TP
|
||||
.B "\-G, \-\-gpio-diffs"
|
||||
Show only GPIO register differences from hardware defaults.
|
||||
.TP
|
||||
.B "\-i, \-\-irq-routing"
|
||||
Dump Fusion Controller Hub (FCH) southbridge IRQ routing registers.
|
||||
.TP
|
||||
.B "\-s, \-\-spi"
|
||||
Dump Fusion Controller Hub (FCH) southbridge SPI registers.
|
||||
.TP
|
||||
.B "\-l, \-\-lpc"
|
||||
Dump Fusion Controller Hub (FCH) southbridge LPC registers.
|
||||
.TP
|
||||
.B "\-M, \-\-msrs"
|
||||
Dump AMD CPU MSRs.
|
||||
.TP
|
||||
.B "\-A, \-\-acpimmio"
|
||||
Dump Fusion Controller Hub (FCH) southbridge ACPI MMIO registers.
|
||||
.TP
|
||||
.B "\-p, \-\-psb"
|
||||
Dump Platform Secure Boot State.
|
||||
.SH BUGS
|
||||
Please report any bugs on the coreboot mailing list
|
||||
.RB "(" https://coreboot.org/Mailinglist ")."
|
||||
.SH LICENCE
|
||||
.B amdtool
|
||||
is covered by the GNU General Public License (GPL), version 2.
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2024 3mdeb
|
||||
.SH AUTHORS
|
||||
Michał Żygowski <michal.zygowski@3mdeb.com>
|
||||
.PP
|
||||
This manual page was written by Michał Żygowski <michal.zygowski@3mdeb.com>.
|
||||
It is licensed under the terms of the GNU GPL (version 2).
|
||||
403
util/amdtool/amdtool.c
Normal file
403
util/amdtool/amdtool.c
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
/* 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 <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <getopt.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "acpimmio.h"
|
||||
#include "amdtool.h"
|
||||
#include "smn.h"
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#include <machine/sysarch.h>
|
||||
#endif
|
||||
|
||||
static const struct {
|
||||
uint16_t vendor_id, device_id;
|
||||
char *name;
|
||||
} supported_chips_list[] = {
|
||||
/* Host bridges/DRAM controllers (Northbridges) */
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_BRH_ROOT_COMPLEX, "Turin Root Complex" },
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_0, "Turin Data Fabric 0" },
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_1, "Turin Data Fabric 1" },
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_2, "Turin Data Fabric 2" },
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_3, "Turin Data Fabric 3" },
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_4, "Turin Data Fabric 4" },
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_5, "Turin Data Fabric 5" },
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_6, "Turin Data Fabric 6" },
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_7, "Turin Data Fabric 7" },
|
||||
|
||||
/* FCHs (Southbridges) */
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FCH_SMB_1, "FCH SMBus Controller" },
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FCH_LPC_1, "FCH LPC Bridge" },
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FCH_SMB_2, "FCH SMBus Controller" },
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FCH_LPC_2, "FCH LPC Bridge" },
|
||||
};
|
||||
|
||||
#ifndef __DARWIN__
|
||||
static int fd_mem;
|
||||
|
||||
void *map_physical(uint64_t phys_addr, size_t len)
|
||||
{
|
||||
void *virt_addr;
|
||||
|
||||
virt_addr = mmap(0, len, PROT_WRITE | PROT_READ, MAP_SHARED,
|
||||
fd_mem, (off_t) phys_addr);
|
||||
|
||||
if (virt_addr == MAP_FAILED) {
|
||||
printf("Error mapping physical memory 0x%08" PRIx64 "[0x%zx]\n",
|
||||
phys_addr, len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return virt_addr;
|
||||
}
|
||||
|
||||
void unmap_physical(void *virt_addr, size_t len)
|
||||
{
|
||||
munmap(virt_addr, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct pci_access *pacc;
|
||||
|
||||
static struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device)
|
||||
{
|
||||
struct pci_dev *temp;
|
||||
struct pci_filter filter;
|
||||
|
||||
pci_filter_init(NULL, &filter);
|
||||
filter.vendor = vendor;
|
||||
filter.device = device;
|
||||
|
||||
for (temp = pacc->devices; temp; temp = temp->next)
|
||||
if (pci_filter_match(&filter, temp))
|
||||
return temp;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int find_smbus_dev_rev(uint16_t vendor, uint16_t device)
|
||||
{
|
||||
struct pci_dev *smbus_dev = pci_dev_find(vendor, device);
|
||||
if (!smbus_dev) {
|
||||
printf("No SMBus device with ID %04X:%04X found.\n", vendor, device);
|
||||
perror("ERROR: SMBus device not found.\n");
|
||||
return -1;
|
||||
}
|
||||
return pci_read_byte(smbus_dev, PCI_REVISION_ID);
|
||||
}
|
||||
|
||||
static void print_version(void)
|
||||
{
|
||||
printf("amdtool v%s -- ", AMDTOOL_VERSION);
|
||||
printf("Copyright (C) 2024 3mdeb\n\n");
|
||||
printf("This program is free software: you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License as published by\n"
|
||||
"the Free Software Foundation, version 2 of the License.\n\n"
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
"GNU General Public License for more details.\n\n");
|
||||
}
|
||||
|
||||
static void print_usage(const char *name)
|
||||
{
|
||||
printf("usage: %s [-vh?gicspGlMAa]\n", name);
|
||||
printf("\n"
|
||||
" -v | --version: print the version\n"
|
||||
" -h | --help: print this help\n\n"
|
||||
" -s | --spi: dump southbridge spi and bios_cntrl registers\n"
|
||||
" -g | --gpio: dump southbridge GPIO registers\n"
|
||||
" -G | --gpio-diffs: show GPIO differences from defaults\n"
|
||||
" -i | --irq-routing dump IRQ routing registers\n"
|
||||
" -l | --lpc: dump southbridge LPC/eSPI Interface registers\n\n"
|
||||
" -c | --cpu: dump CPU information and features\n\n"
|
||||
" -M | --msrs: dump CPU MSRs\n"
|
||||
" -A | --acpimmio: dump southbridge ACPI MMIO registers\n"
|
||||
" -p | --psb: dump Platform Secure Boot state\n"
|
||||
" -a | --all: dump all known (safe) registers\n"
|
||||
"\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void print_system_info(struct pci_dev *nb, struct pci_dev *sb,
|
||||
struct pci_dev *smb, struct pci_dev *gfx)
|
||||
{
|
||||
unsigned int id, i;
|
||||
char *sbname = "unknown", *nbname = "unknown", *gfxname = "unknown", *smbname = "unknown";
|
||||
|
||||
id = cpuid(1);
|
||||
|
||||
/* Determine names */
|
||||
for (i = 0; i < ARRAY_SIZE(supported_chips_list); i++) {
|
||||
if (nb->device_id == supported_chips_list[i].device_id)
|
||||
nbname = supported_chips_list[i].name;
|
||||
if (sb->device_id == supported_chips_list[i].device_id)
|
||||
sbname = supported_chips_list[i].name;
|
||||
if (smb->device_id == supported_chips_list[i].device_id)
|
||||
smbname = supported_chips_list[i].name;
|
||||
}
|
||||
if (gfx) {
|
||||
for (i = 0; i < ARRAY_SIZE(supported_chips_list); i++)
|
||||
if (gfx->device_id == supported_chips_list[i].device_id)
|
||||
gfxname = supported_chips_list[i].name;
|
||||
}
|
||||
printf("CPU: ID 0x%x, Processor Type 0x%x, Family 0x%x, Model 0x%x, Stepping 0x%x\n",
|
||||
id, (id >> 12) & 0x3, ((id >> 8) & 0xf) + ((id >> 20) & 0xff),
|
||||
((id >> 12) & 0xf0) + ((id >> 4) & 0xf), (id & 0xf));
|
||||
|
||||
printf("Northbridge: %04x:%04x (%s)\n",
|
||||
nb->vendor_id, nb->device_id, nbname);
|
||||
|
||||
printf("Southbridge SMBus: %04x:%04x rev %02x (%s)\n",
|
||||
smb->vendor_id, smb->device_id, pci_read_byte(smb, PCI_REVISION_ID), smbname);
|
||||
|
||||
printf("Southbridge LPC: %04x:%04x rev %02x (%s)\n",
|
||||
sb->vendor_id, sb->device_id, pci_read_byte(sb, PCI_REVISION_ID), sbname);
|
||||
|
||||
if (gfx)
|
||||
printf("Integrated Graphics: %04x:%04x (%s)\n",
|
||||
gfx->vendor_id, gfx->device_id, gfxname);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct pci_dev *sb = NULL, *nb, *gfx = NULL, *smb = NULL, *dev;
|
||||
int opt, option_index = 0;
|
||||
|
||||
int dump_gpios = 0, dump_coremsrs = 0, dump_acpimmio = 0, dump_cpu = 0;
|
||||
int dump_spi = 0, dump_lpc = 0, show_gpio_diffs = 0, dump_psb = 0, dump_irq = 0;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"version", 0, 0, 'v'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{"gpios", 0, 0, 'g'},
|
||||
{"gpio-diffs", 0, 0, 'G'},
|
||||
{"irq-routing", 0, 0, 'i'},
|
||||
{"lpc", 0, 0, 'l'},
|
||||
{"cpu", 0, 0, 'c'},
|
||||
{"msrs", 0, 0, 'M'},
|
||||
{"acpimmio", 0, 0, 'A'},
|
||||
{"psb", 0, 0, 'p'},
|
||||
{"spi", 0, 0, 's'},
|
||||
{"all", 0, 0, 'a'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "vh?gGilcMApsa",
|
||||
long_options, &option_index)) != EOF) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
print_version();
|
||||
exit(0);
|
||||
break;
|
||||
case 'g':
|
||||
dump_gpios = 1;
|
||||
break;
|
||||
case 'G':
|
||||
show_gpio_diffs = 1;
|
||||
break;
|
||||
case 'i':
|
||||
dump_irq = 1;
|
||||
break;
|
||||
case 'l':
|
||||
dump_lpc = 1;
|
||||
break;
|
||||
case 'c':
|
||||
dump_cpu = 1;
|
||||
break;
|
||||
case 'M':
|
||||
dump_coremsrs = 1;
|
||||
break;
|
||||
case 'A':
|
||||
dump_acpimmio = 1;
|
||||
break;
|
||||
case 'p':
|
||||
dump_psb = 1;
|
||||
break;
|
||||
case 's':
|
||||
dump_spi = 1;
|
||||
break;
|
||||
case 'a':
|
||||
dump_gpios = 1;
|
||||
show_gpio_diffs = 1;
|
||||
dump_irq = 1;
|
||||
dump_lpc = 1;
|
||||
dump_cpu = 1;
|
||||
dump_coremsrs = 1;
|
||||
dump_acpimmio = 1;
|
||||
dump_spi = 1;
|
||||
dump_psb = 1;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
if (open("/dev/io", O_RDWR) < 0) {
|
||||
perror("/dev/io");
|
||||
#elif defined(__NetBSD__)
|
||||
# ifdef __i386__
|
||||
if (i386_iopl(3)) {
|
||||
perror("iopl");
|
||||
# else
|
||||
if (x86_64_iopl(3)) {
|
||||
perror("iopl");
|
||||
# endif
|
||||
#else
|
||||
if (iopl(3)) {
|
||||
perror("iopl");
|
||||
#endif
|
||||
printf("You need to be root.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifndef __DARWIN__
|
||||
if ((fd_mem = open("/dev/mem", O_RDWR)) < 0) {
|
||||
perror("Can not open /dev/mem");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
pacc = pci_alloc();
|
||||
pacc->method = PCI_ACCESS_I386_TYPE1;
|
||||
pci_init(pacc);
|
||||
pci_scan_bus(pacc);
|
||||
|
||||
/* Find the required devices */
|
||||
for (dev = pacc->devices; dev; dev = dev->next) {
|
||||
pci_fill_info(dev, PCI_FILL_CLASS);
|
||||
/* The ISA/LPC bridge can be 0x1f, 0x07, or 0x04 so we probe. */
|
||||
if (dev->device_class == 0x0601) { /* ISA/LPC bridge */
|
||||
if (sb == NULL) {
|
||||
sb = dev;
|
||||
} else {
|
||||
fprintf(stderr, "Multiple devices with class ID"
|
||||
" 0x0601, using %02x%02x:%02x.%02x\n",
|
||||
sb->domain, sb->bus, sb->dev, sb->func);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sb) {
|
||||
printf("No southbridge found.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pci_fill_info(sb, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
|
||||
|
||||
if (sb->vendor_id != PCI_VENDOR_ID_AMD) {
|
||||
printf("Not an AMD southbridge.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
nb = pci_get_dev(pacc, 0, 0, 0x00, 0);
|
||||
if (!nb) {
|
||||
printf("No northbridge found.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pci_fill_info(nb, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
|
||||
|
||||
if (nb->vendor_id != PCI_VENDOR_ID_AMD) {
|
||||
printf("Not an AMD northbridge.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
smb = pci_get_dev(pacc, 0, 0, 0x14, 0);
|
||||
if (!smb) {
|
||||
printf("No SMBus Controller found.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pci_fill_info(smb, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
|
||||
|
||||
if (smb->vendor_id != PCI_VENDOR_ID_AMD) {
|
||||
printf("Not an AMD southbridge.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
gfx = pci_get_dev(pacc, 0, 0, 0x02, 0);
|
||||
if (gfx) {
|
||||
pci_fill_info(gfx, PCI_FILL_IDENT | PCI_FILL_BASES |
|
||||
PCI_FILL_CLASS);
|
||||
if ((gfx->device_class & 0xff00) != 0x0300)
|
||||
gfx = NULL;
|
||||
else if (gfx->vendor_id != PCI_VENDOR_ID_AMD)
|
||||
gfx = NULL;
|
||||
}
|
||||
|
||||
print_system_info(nb, sb, smb, gfx);
|
||||
|
||||
init_smn(nb);
|
||||
|
||||
/* Now do the deed */
|
||||
|
||||
if (dump_lpc) {
|
||||
print_lpc(sb);
|
||||
printf("\n\n");
|
||||
print_espi(sb);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
if (dump_cpu) {
|
||||
print_cpu_info();
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
if (dump_coremsrs) {
|
||||
print_amd_msrs();
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
if (dump_acpimmio) {
|
||||
print_acpimmio(sb);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
if (dump_gpios) {
|
||||
print_gpios(sb, 1, show_gpio_diffs);
|
||||
printf("\n\n");
|
||||
} else if (show_gpio_diffs) {
|
||||
print_gpios(sb, 0, show_gpio_diffs);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
if (dump_spi) {
|
||||
print_spi(sb);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
if (dump_irq) {
|
||||
print_irq_routing(sb);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
if (dump_psb) {
|
||||
print_psb(nb);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
/* Clean up */
|
||||
acpimmio_cleanup();
|
||||
pci_free_dev(nb);
|
||||
/* `sb` wasn't allocated by pci_get_dev() */
|
||||
pci_cleanup(pacc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
127
util/amdtool/amdtool.h
Normal file
127
util/amdtool/amdtool.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/* amdtool - dump all registers on an AMD CPU + chipset based system */
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef AMDTOOL_H
|
||||
#define AMDTOOL_H 1
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/stddef.h>
|
||||
#endif
|
||||
#include <arch/mmio.h>
|
||||
#include <commonlib/helpers.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/io.h>
|
||||
#endif
|
||||
#if (defined(__MACH__) && defined(__APPLE__))
|
||||
/* DirectHW is available here: https://www.coreboot.org/DirectHW */
|
||||
#define __DARWIN__
|
||||
#include <DirectHW/DirectHW.h>
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#include <pciutils/pci.h>
|
||||
#else
|
||||
#include <pci/pci.h>
|
||||
#endif
|
||||
|
||||
/* This #include is needed for freebsd_{rd,wr}msr. */
|
||||
#if defined(__FreeBSD__)
|
||||
#include <machine/cpufunc.h>
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
static inline uint8_t inb(unsigned port)
|
||||
{
|
||||
uint8_t data;
|
||||
__asm volatile("inb %w1,%0" : "=a" (data) : "d" (port));
|
||||
return data;
|
||||
}
|
||||
static inline uint16_t inw(unsigned port)
|
||||
{
|
||||
uint16_t data;
|
||||
__asm volatile("inw %w1,%0": "=a" (data) : "d" (port));
|
||||
return data;
|
||||
}
|
||||
static inline uint32_t inl(unsigned port)
|
||||
{
|
||||
uint32_t data;
|
||||
__asm volatile("inl %w1,%0": "=a" (data) : "d" (port));
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline void outb(uint8_t value, uint16_t port)
|
||||
{
|
||||
__asm__ __volatile__ ("outb %0, %w1" : : "a" (value), "d" (port));
|
||||
}
|
||||
|
||||
static inline void outw(uint16_t value, uint16_t port)
|
||||
{
|
||||
__asm__ __volatile__ ("outw %0, %w1" : : "a" (value), "d" (port));
|
||||
}
|
||||
|
||||
static inline void outl(uint32_t value, uint16_t port)
|
||||
{
|
||||
__asm__ __volatile__ ("outl %0, %w1" : : "a" (value), "d" (port));
|
||||
}
|
||||
#endif
|
||||
|
||||
#define AMDTOOL_VERSION "0.1"
|
||||
|
||||
#define PCI_VENDOR_ID_AMD 0x1022
|
||||
|
||||
#define PCI_DEVICE_ID_AMD_FCH_SMB_1 0x780b
|
||||
#define PCI_DEVICE_ID_AMD_FCH_LPC_1 0x780e
|
||||
#define PCI_DEVICE_ID_AMD_FCH_SMB_2 0x790b
|
||||
#define PCI_DEVICE_ID_AMD_FCH_LPC_2 0x790e
|
||||
|
||||
#define PCI_DEVICE_ID_AMD_BRH_ROOT_COMPLEX 0x153a
|
||||
#define PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_0 0x12c0
|
||||
#define PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_1 0x12c1
|
||||
#define PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_2 0x12c2
|
||||
#define PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_3 0x12c3
|
||||
#define PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_4 0x12c4
|
||||
#define PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_5 0x12c5
|
||||
#define PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_6 0x12c6
|
||||
#define PCI_DEVICE_ID_AMD_BRH_DATA_FABRIC_7 0x12c7
|
||||
|
||||
#define CPUID_TURIN_C1 0x00b00f21
|
||||
|
||||
#if !defined(__DARWIN__) && !defined(__FreeBSD__)
|
||||
typedef struct { uint32_t hi, lo; } msr_t;
|
||||
#endif
|
||||
#if defined (__FreeBSD__)
|
||||
/* FreeBSD already has conflicting definitions for wrmsr/rdmsr. */
|
||||
#undef rdmsr
|
||||
#undef wrmsr
|
||||
#define rdmsr freebsd_rdmsr
|
||||
#define wrmsr freebsd_wrmsr
|
||||
typedef struct { uint32_t hi, lo; } msr_t;
|
||||
#endif
|
||||
typedef struct { uint16_t addr; int size; char *name; } io_register_t;
|
||||
typedef struct {
|
||||
uint32_t eax;
|
||||
uint32_t ebx;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
} cpuid_result_t;
|
||||
|
||||
void *map_physical(uint64_t phys_addr, size_t len);
|
||||
void unmap_physical(void *virt_addr, size_t len);
|
||||
|
||||
int find_smbus_dev_rev(uint16_t vendor, uint16_t device);
|
||||
|
||||
uint32_t cpuid(uint32_t eax);
|
||||
int print_amd_msrs(void);
|
||||
int print_cpu_info(void);
|
||||
int print_lpc(struct pci_dev *sb);
|
||||
int print_espi(struct pci_dev *sb);
|
||||
int print_gpios(struct pci_dev *sb, int show_all, int show_diffs);
|
||||
int print_spi(struct pci_dev *sb);
|
||||
int print_acpimmio(struct pci_dev *sb);
|
||||
void print_psb(struct pci_dev *nb);
|
||||
int print_irq_routing(struct pci_dev *sb);
|
||||
|
||||
#endif
|
||||
564
util/amdtool/cpu.c
Normal file
564
util/amdtool/cpu.c
Normal file
|
|
@ -0,0 +1,564 @@
|
|||
/* amdtool - dump all registers on an AMD CPU + chipset based system */
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "amdtool.h"
|
||||
#include "smn.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
# define BREG "%%rbx"
|
||||
#else
|
||||
# define BREG "%%ebx"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t number;
|
||||
char *name;
|
||||
} msr_entry_t;
|
||||
|
||||
int fd_msr;
|
||||
|
||||
uint32_t cpuid(uint32_t eax)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
#if defined(__PIC__) || defined(__DARWIN__) && !defined(__LP64__)
|
||||
asm volatile (
|
||||
"push " BREG "\n\t"
|
||||
"cpuid\n\t"
|
||||
"pop " BREG "\n\t"
|
||||
: "=a" (ret) : "a" (eax) : "%ecx", "%edx"
|
||||
);
|
||||
#else
|
||||
asm ("cpuid" : "=a" (ret) : "a" (eax) : "%ebx", "%ecx", "%edx");
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline cpuid_result_t cpuid_ext(uint32_t eax, unsigned int ecx)
|
||||
{
|
||||
cpuid_result_t result;
|
||||
|
||||
#ifndef __DARWIN__
|
||||
asm volatile (
|
||||
"mov %%ebx, %%edi;"
|
||||
"cpuid;"
|
||||
"mov %%ebx, %%esi;"
|
||||
"mov %%edi, %%ebx;"
|
||||
: "=a" (result.eax),
|
||||
"=S" (result.ebx),
|
||||
"=c" (result.ecx),
|
||||
"=d" (result.edx)
|
||||
: "0" (eax), "2" (ecx)
|
||||
: "edi");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef __DARWIN__
|
||||
int msr_readerror = 0;
|
||||
|
||||
static msr_t rdmsr(unsigned int addr)
|
||||
{
|
||||
uint32_t buf[2];
|
||||
msr_t msr = { 0xffffffff, 0xffffffff };
|
||||
|
||||
if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
|
||||
perror("Could not lseek() to MSR");
|
||||
close(fd_msr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (read(fd_msr, buf, 8) == 8) {
|
||||
msr.lo = buf[0];
|
||||
msr.hi = buf[1];
|
||||
return msr;
|
||||
}
|
||||
|
||||
if (errno == 5) {
|
||||
printf(" (*)"); // Not all bits of the MSR could be read
|
||||
msr_readerror = 1;
|
||||
} else {
|
||||
// A severe error.
|
||||
perror("Could not read() MSR");
|
||||
close(fd_msr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return msr;
|
||||
}
|
||||
|
||||
static int open_and_seek(int cpu, unsigned long msr, int mode, int *fd)
|
||||
{
|
||||
char dev[32];
|
||||
char temp_string[50];
|
||||
|
||||
snprintf(dev, sizeof(dev), "/dev/cpu/%d/msr", cpu);
|
||||
*fd = open(dev, mode);
|
||||
|
||||
if (*fd < 0) {
|
||||
snprintf(temp_string, sizeof(temp_string), "open(\"%s\")", dev);
|
||||
perror(temp_string);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lseek(*fd, msr, SEEK_SET) == (off_t)-1) {
|
||||
snprintf(temp_string, sizeof(temp_string), "lseek(%lu)", msr);
|
||||
perror(temp_string);
|
||||
close(*fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static msr_t rdmsr_from_cpu(int cpu, unsigned long addr)
|
||||
{
|
||||
int fd;
|
||||
msr_t msr = { 0xffffffff, 0xffffffff };
|
||||
uint32_t buf[2];
|
||||
char temp_string[50];
|
||||
|
||||
if (open_and_seek(cpu, addr, O_RDONLY, &fd) < 0) {
|
||||
snprintf(temp_string, sizeof(temp_string),
|
||||
"Could not read MSR for CPU#%d", cpu);
|
||||
perror(temp_string);
|
||||
}
|
||||
|
||||
if (read(fd, buf, 8) == 8) {
|
||||
msr.lo = buf[0];
|
||||
msr.hi = buf[1];
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return msr;
|
||||
}
|
||||
|
||||
static int get_number_of_cpus(void)
|
||||
{
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
}
|
||||
|
||||
static bool is_sme_supported(void)
|
||||
{
|
||||
cpuid_result_t cpuid_regs;
|
||||
|
||||
if (cpuid(0x80000000) < 0x8000001f)
|
||||
return false;
|
||||
|
||||
cpuid_regs = cpuid_ext(0x8000001f, 0x0);
|
||||
return !!(cpuid_regs.eax & 1);
|
||||
}
|
||||
|
||||
static bool is_sme_enabled(int cpunum)
|
||||
{
|
||||
msr_t data;
|
||||
data = rdmsr_from_cpu(cpunum, 0xC0010010);
|
||||
return !!(data.lo & (1 << 23));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int print_sme(void)
|
||||
{
|
||||
int error = -1;
|
||||
#ifndef __DARWIN__
|
||||
int ncpus = get_number_of_cpus();
|
||||
int i = 0;
|
||||
bool sme_supported;
|
||||
|
||||
printf("\n============= Dumping AMD SME status =============\n");
|
||||
|
||||
if (ncpus < 1) {
|
||||
perror("Failed to get number of CPUs");
|
||||
error = -1;
|
||||
} else {
|
||||
sme_supported = is_sme_supported();
|
||||
for (i = 0; i < ncpus ; i++) {
|
||||
|
||||
printf("------------- CPU %d ----------------\n", i);
|
||||
printf("SME supported : %s\n",
|
||||
sme_supported ? "YES" : "NO");
|
||||
if (sme_supported)
|
||||
printf("SME enabled : %s\n",
|
||||
is_sme_enabled(i) ? "YES" : "NO");
|
||||
}
|
||||
error = 0;
|
||||
}
|
||||
printf("====================================================\n\n");
|
||||
#endif
|
||||
return error;
|
||||
}
|
||||
|
||||
static bool is_sev_supported(void)
|
||||
{
|
||||
cpuid_result_t cpuid_regs;
|
||||
|
||||
if (cpuid(0x80000000) < 0x8000001f)
|
||||
return false;
|
||||
|
||||
cpuid_regs = cpuid_ext(0x8000001f, 0x0);
|
||||
return !!(cpuid_regs.eax & 2);
|
||||
}
|
||||
|
||||
static bool is_sev_es_supported(void)
|
||||
{
|
||||
cpuid_result_t cpuid_regs;
|
||||
|
||||
if (cpuid(0x80000000) < 0x8000001f)
|
||||
return false;
|
||||
|
||||
cpuid_regs = cpuid_ext(0x8000001f, 0x0);
|
||||
return !!(cpuid_regs.eax & 8);
|
||||
}
|
||||
|
||||
static bool is_sev_snp_supported(void)
|
||||
{
|
||||
cpuid_result_t cpuid_regs;
|
||||
|
||||
if (cpuid(0x80000000) < 0x8000001f)
|
||||
return false;
|
||||
|
||||
cpuid_regs = cpuid_ext(0x8000001f, 0x0);
|
||||
return !!(cpuid_regs.eax & 0x10);
|
||||
}
|
||||
|
||||
static bool is_sev_enabled(int cpunum)
|
||||
{
|
||||
msr_t data;
|
||||
|
||||
data = rdmsr_from_cpu(cpunum, 0xC0010131);
|
||||
return !!(data.lo & 1);
|
||||
}
|
||||
|
||||
static bool is_sev_es_enabled(int cpunum)
|
||||
{
|
||||
msr_t data;
|
||||
|
||||
data = rdmsr_from_cpu(cpunum, 0xC0010131);
|
||||
return !!(data.lo & 2);
|
||||
}
|
||||
|
||||
static bool is_sev_snp_enabled(int cpunum)
|
||||
{
|
||||
msr_t data;
|
||||
|
||||
data = rdmsr_from_cpu(cpunum, 0xC0010131);
|
||||
return !!(data.lo & 4);
|
||||
}
|
||||
|
||||
static unsigned int get_sev_max_guest_num(void)
|
||||
{
|
||||
cpuid_result_t cpuid_regs;
|
||||
|
||||
cpuid_regs = cpuid_ext(0x8000001f, 0x0);
|
||||
return cpuid_regs.ecx;
|
||||
}
|
||||
|
||||
static unsigned int get_sev_min_asid(void)
|
||||
{
|
||||
cpuid_result_t cpuid_regs;
|
||||
|
||||
cpuid_regs = cpuid_ext(0x8000001f, 0x0);
|
||||
return cpuid_regs.edx;
|
||||
}
|
||||
|
||||
static int print_sev(void)
|
||||
{
|
||||
int error = -1;
|
||||
#ifndef __DARWIN__
|
||||
int ncpus = get_number_of_cpus();
|
||||
int i = 0;
|
||||
bool sev_supported, sev_es_supported, sev_snp_supported;
|
||||
unsigned int max_guest, min_asid;
|
||||
|
||||
printf("\n============= Dumping AMD SEV status =============\n");
|
||||
|
||||
if (ncpus < 1) {
|
||||
perror("Failed to get number of CPUs");
|
||||
error = -1;
|
||||
} else {
|
||||
/*
|
||||
* The following use CPUID, so should be the same for each core
|
||||
* in the scope of processor.
|
||||
*/
|
||||
sev_supported = is_sev_supported();
|
||||
sev_es_supported = is_sev_es_supported();
|
||||
sev_snp_supported = is_sev_snp_supported();
|
||||
if (sev_supported) {
|
||||
max_guest = get_sev_max_guest_num();
|
||||
min_asid = get_sev_min_asid();
|
||||
}
|
||||
|
||||
for (i = 0; i < ncpus ; i++) {
|
||||
printf("------------- CPU %d ----------------\n", i);
|
||||
printf("SEV supported : %s\n",
|
||||
sev_supported ? "YES" : "NO");
|
||||
if (sev_supported) {
|
||||
printf("Max SEV encrypted guests : %u\n",
|
||||
max_guest);
|
||||
printf("Min SEV ASID : %u\n",
|
||||
min_asid);
|
||||
printf("SEV enabled : %s\n",
|
||||
is_sev_enabled(i) ? "YES" : "NO");
|
||||
}
|
||||
printf("SEV-ES supported : %s\n",
|
||||
sev_es_supported ? "YES" : "NO");
|
||||
if (sev_es_supported)
|
||||
printf("SEV-ES enabled : %s\n",
|
||||
is_sev_es_enabled(i) ? "YES" : "NO");
|
||||
printf("SEV-SNP supported : %s\n",
|
||||
sev_snp_supported ? "YES" : "NO");
|
||||
if (sev_snp_supported)
|
||||
printf("SEV-SNP enabled : %s\n",
|
||||
is_sev_snp_enabled(i) ? "YES" : "NO");
|
||||
}
|
||||
error = 0;
|
||||
}
|
||||
printf("====================================================");
|
||||
#endif
|
||||
return error;
|
||||
}
|
||||
|
||||
static void get_cpu_brand_string(char *cpu_string)
|
||||
{
|
||||
u32 tmp[13];
|
||||
cpuid_result_t res;
|
||||
const char *str = "Unknown Processor Name";
|
||||
int i, j;
|
||||
|
||||
if (cpuid(0x80000000) >= 0x80000004) {
|
||||
j = 0;
|
||||
for (i = 0; i < 3; i++) {
|
||||
res = cpuid_ext(0x80000002 + i, 0x0);
|
||||
tmp[j++] = res.eax;
|
||||
tmp[j++] = res.ebx;
|
||||
tmp[j++] = res.ecx;
|
||||
tmp[j++] = res.edx;
|
||||
}
|
||||
tmp[12] = 0;
|
||||
str = (const char *)tmp;
|
||||
}
|
||||
|
||||
strcpy(cpu_string, str);
|
||||
}
|
||||
|
||||
#define CPU_BRAND_STRING_LEN 48
|
||||
|
||||
static int print_cpu_features(void)
|
||||
{
|
||||
int error = -1;
|
||||
#ifndef __DARWIN__
|
||||
cpuid_result_t cpuid_regs;
|
||||
|
||||
printf("\n============= AMD CPU features =============\n");
|
||||
|
||||
if (cpuid(0x80000000) >= 0x80000001) {
|
||||
cpuid_regs = cpuid_ext(0x80000001, 0x0);
|
||||
printf("SVM supported : %s\n",
|
||||
cpuid_regs.ecx & (1 << 2) ? "YES" : "NO");
|
||||
printf("SKINIT supported : %s\n",
|
||||
cpuid_regs.ecx & (1 << 12) ? "YES" : "NO");
|
||||
}
|
||||
|
||||
error = 0;
|
||||
|
||||
printf("====================================================\n");
|
||||
#endif
|
||||
return error;
|
||||
}
|
||||
|
||||
int print_cpu_info(void)
|
||||
{
|
||||
int ret;
|
||||
char brand_string[CPU_BRAND_STRING_LEN + 1];
|
||||
|
||||
get_cpu_brand_string(brand_string);
|
||||
printf("CPU brand string: %s\n", brand_string);
|
||||
|
||||
ret = print_cpu_features();
|
||||
ret += print_sme();
|
||||
ret += print_sev();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const msr_entry_t common_msrs[] = {
|
||||
{ 0x001b, "IA32_APIC_BASE" },
|
||||
{ 0x008b, "MICROCODE_PATCH_LEVEL" },
|
||||
{ 0x00fe, "IA32_MTRRCAP" },
|
||||
{ 0x0179, "IA32_MCG_CAP" },
|
||||
{ 0x017a, "IA32_MCG_STATUS" },
|
||||
{ 0x017b, "IA32_MCG_CONTROL" },
|
||||
{ 0x01d9, "IA32_DEBUGCTL" },
|
||||
{ 0x0200, "IA32_MTRR_PHYSBASE0" },
|
||||
{ 0x0201, "IA32_MTRR_PHYSMASK0" },
|
||||
{ 0x0202, "IA32_MTRR_PHYSBASE1" },
|
||||
{ 0x0203, "IA32_MTRR_PHYSMASK1" },
|
||||
{ 0x0204, "IA32_MTRR_PHYSBASE2" },
|
||||
{ 0x0205, "IA32_MTRR_PHYSMASK2" },
|
||||
{ 0x0206, "IA32_MTRR_PHYSBASE3" },
|
||||
{ 0x0207, "IA32_MTRR_PHYSMASK3" },
|
||||
{ 0x0208, "IA32_MTRR_PHYSBASE4" },
|
||||
{ 0x0209, "IA32_MTRR_PHYSMASK4" },
|
||||
{ 0x020a, "IA32_MTRR_PHYSBASE5" },
|
||||
{ 0x020b, "IA32_MTRR_PHYSMASK5" },
|
||||
{ 0x020c, "IA32_MTRR_PHYSBASE6" },
|
||||
{ 0x020d, "IA32_MTRR_PHYSMASK6" },
|
||||
{ 0x020e, "IA32_MTRR_PHYSBASE7" },
|
||||
{ 0x020f, "IA32_MTRR_PHYSMASK7" },
|
||||
{ 0x0250, "IA32_MTRR_FIX64K_00000" },
|
||||
{ 0x0258, "IA32_MTRR_FIX16K_80000" },
|
||||
{ 0x0259, "IA32_MTRR_FIX16K_A0000" },
|
||||
{ 0x0268, "IA32_MTRR_FIX4K_C0000" },
|
||||
{ 0x0269, "IA32_MTRR_FIX4K_C8000" },
|
||||
{ 0x026a, "IA32_MTRR_FIX4K_D0000" },
|
||||
{ 0x026b, "IA32_MTRR_FIX4K_D8000" },
|
||||
{ 0x026c, "IA32_MTRR_FIX4K_E0000" },
|
||||
{ 0x026d, "IA32_MTRR_FIX4K_E8000" },
|
||||
{ 0x026e, "IA32_MTRR_FIX4K_F0000" },
|
||||
{ 0x026f, "IA32_MTRR_FIX4K_F8000" },
|
||||
{ 0x0277, "IA32_PAT" },
|
||||
{ 0x02ff, "IA32_MTRR_DEF_TYPE" },
|
||||
{ 0xc0000080, "EFER" },
|
||||
{ 0xc0010010, "SYS_CFG" },
|
||||
{ 0xc0010015, "HWCR" },
|
||||
{ 0xc0010016, "IORR_BASE0" },
|
||||
{ 0xc0010017, "IORR_MASK0" },
|
||||
{ 0xc0010018, "IORR_BASE1" },
|
||||
{ 0xc0010019, "IORR_MASK1" },
|
||||
{ 0xc001001a, "TOP_MEM" },
|
||||
{ 0xc001001d, "TOM2" },
|
||||
{ 0xc0010030, "PROCESSOR_NAME_STRING0" },
|
||||
{ 0xc0010031, "PROCESSOR_NAME_STRING1" },
|
||||
{ 0xc0010032, "PROCESSOR_NAME_STRING2" },
|
||||
{ 0xc0010033, "PROCESSOR_NAME_STRING3" },
|
||||
{ 0xc0010034, "PROCESSOR_NAME_STRING4" },
|
||||
{ 0xc0010035, "PROCESSOR_NAME_STRING5" },
|
||||
{ 0xc0010050, "SMI_ON_IO_TRAP0" },
|
||||
{ 0xc0010051, "SMI_ON_IO_TRAP1" },
|
||||
{ 0xc0010052, "SMI_ON_IO_TRAP2" },
|
||||
{ 0xc0010053, "SMI_ON_IO_TRAP3" },
|
||||
{ 0xc0010054, "SMI_ON_IO_TRAP_CTL_STS" },
|
||||
{ 0xc0010056, "SMI_TRIGGER_IO_CYCLE" },
|
||||
{ 0xc0010058, "MMCONF_BASE_ADDR" },
|
||||
{ 0xc0010061, "PSTATE_CURRENT_LIMIT" },
|
||||
{ 0xc0010062, "PSTATE_CNTRL" },
|
||||
{ 0xc0010063, "PSTATE_STATUS" },
|
||||
{ 0xc0010064, "PSTATE0_DEF" },
|
||||
{ 0xc0010065, "PSTATE1_DEF" },
|
||||
{ 0xc0010066, "PSTATE2_DEF" },
|
||||
{ 0xc0010067, "PSTATE3_DEF" },
|
||||
{ 0xc0010068, "PSTATE4_DEF" },
|
||||
{ 0xc0010069, "PSTATE5_DEF" },
|
||||
{ 0xc001006a, "PSTATE6_DEF" },
|
||||
{ 0xc001006b, "PSTATE7_DEF" },
|
||||
{ 0xc0010073, "CSTATE_BASE_ADDR" },
|
||||
{ 0xc0010074, "CPU_WDT_CFG" },
|
||||
{ 0xc0010111, "SMM_BASE" },
|
||||
{ 0xc0010112, "SMM_TSEG_BASE" },
|
||||
{ 0xc0010113, "SMM_TSEG_MASK" },
|
||||
{ 0xc0010114, "VM_CR" },
|
||||
{ 0xc0010118, "SVM_LOCK_KEY" },
|
||||
{ 0xc0010119, "SMM_LOCK_KEY" },
|
||||
{ 0xc0010131, "SEV_STATUS" },
|
||||
{ 0xc0010140, "OSVW_ID_LENGTH" },
|
||||
{ 0xc0010141, "OSVW_STATUS" },
|
||||
{ 0xc0010292, "PWR_MNGMNT_MISC" },
|
||||
{ 0xc0010293, "HW_PSTATE_STATUS" },
|
||||
{ 0xc0010294, "CSTATE_POLICY" },
|
||||
{ 0xc0010296, "CSTATE_CONFIG" },
|
||||
{ 0xc0010297, "PWR_MNGMNT_DEFAULT" },
|
||||
{ 0xc0010299, "RAPL_PWR_UNIT" },
|
||||
{ 0xc001029a, "CORE_ENERGY_STS" },
|
||||
{ 0xc001029b, "PKG_ENERGY_STS" },
|
||||
{ 0xc00102b0, "CPPC_CAP1" },
|
||||
{ 0xc00102b1, "CPPC_ENABLE" },
|
||||
{ 0xc00102b2, "CPPC_CAP2" },
|
||||
{ 0xc00102b3, "CPPC_REQUEST" },
|
||||
{ 0xc00102b4, "CPPC_STATUS" },
|
||||
{ 0xc0011002, "CPUID_7_FEATURES" },
|
||||
{ 0xc0011003, "CPUID_PWR_THERM" },
|
||||
{ 0xc0011004, "CPUID_FEATURES" },
|
||||
{ 0xc0011005, "CPUID_EXT_FEATURES" },
|
||||
{ 0xc001100c, "NODE_ID/SCRATCH" },
|
||||
{ 0xC0011020, "LS_CFG" },
|
||||
{ 0xC0011021, "IC_CFG" },
|
||||
{ 0xc0011022, "DC_CFG" },
|
||||
{ 0xc0011023, "TW_CFG" },
|
||||
{ 0xc0011028, "FP_CFG" },
|
||||
{ 0xc0011029, "ME_CFG" },
|
||||
{ 0xc001102a, "BU_CFG2" },
|
||||
{ 0xc001102b, "L2_PFCFG" },
|
||||
{ 0xC001102d, "LS_CFG2" },
|
||||
{ 0xc001102e, "BP_CFG" },
|
||||
{ 0xc00110a2, "PSP_ADDR" },
|
||||
};
|
||||
|
||||
int print_amd_msrs(void)
|
||||
{
|
||||
unsigned int i, id;
|
||||
msr_t msr;
|
||||
|
||||
typedef struct {
|
||||
unsigned int model;
|
||||
const msr_entry_t *global_msrs;
|
||||
unsigned int num_global_msrs;
|
||||
} cpu_t;
|
||||
|
||||
cpu_t cpulist[] = {
|
||||
{ CPUID_TURIN_C1, common_msrs, ARRAY_SIZE(common_msrs) },
|
||||
};
|
||||
|
||||
cpu_t *cpu = NULL;
|
||||
|
||||
/* Get CPU family, model and stepping */
|
||||
id = cpuid(1);
|
||||
for (i = 0; i < ARRAY_SIZE(cpulist); i++) {
|
||||
if(cpulist[i].model == id) {
|
||||
cpu = &cpulist[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cpu) {
|
||||
printf("Error: Dumping MSRs on this CPU (0x%06x) is not (yet) supported.\n", id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef __DARWIN__
|
||||
fd_msr = open("/dev/cpu/0/msr", O_RDWR);
|
||||
if (fd_msr < 0) {
|
||||
perror("Error while opening /dev/cpu/0/msr");
|
||||
printf("Did you run 'modprobe msr'?\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("\n===================== MSRs =====================\n");
|
||||
|
||||
for (i = 0; i < cpu->num_global_msrs; i++) {
|
||||
msr = rdmsr(cpu->global_msrs[i].number);
|
||||
printf(" MSR 0x%08X = 0x%08X:0x%08X (%s)\n",
|
||||
cpu->global_msrs[i].number, msr.hi, msr.lo,
|
||||
cpu->global_msrs[i].name);
|
||||
}
|
||||
|
||||
#ifndef __DARWIN__
|
||||
close(fd_msr);
|
||||
|
||||
if (msr_readerror)
|
||||
printf("\n(*) Some MSRs could not be read. The marked values are unreliable.\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
2
util/amdtool/description.md
Normal file
2
util/amdtool/description.md
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Provides information about the AMD CPU/chipset hardware configuration
|
||||
(register contents, MSRs, etc). `C`
|
||||
199
util/amdtool/espi.c
Normal file
199
util/amdtool/espi.c
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/* 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 BRH_ESPI0_SMN_BASE 0x02DC5000
|
||||
#define BRH_ESPI1_SMN_BASE 0x02DCA000
|
||||
|
||||
static const io_register_t kunlun_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)
|
||||
{
|
||||
size_t i, espi, num_espi, cfg_registers_size = 0;
|
||||
uint32_t spibar_phys, spibar_mask;
|
||||
const io_register_t *cfg_registers;
|
||||
int smbus_rev = 0;
|
||||
|
||||
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:
|
||||
num_espi = 2;
|
||||
cfg_registers = kunlun_espi_cfg_registers;
|
||||
cfg_registers_size = ARRAY_SIZE(kunlun_espi_cfg_registers);
|
||||
espi_smn_addr[0] = BRH_ESPI0_SMN_BASE;
|
||||
espi_smn_addr[1] = BRH_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;
|
||||
}
|
||||
394
util/amdtool/gpio.c
Normal file
394
util/amdtool/gpio.c
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
/* 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 "acpimmio.h"
|
||||
#include "amdtool.h"
|
||||
#include "smn.h"
|
||||
|
||||
#define AMD_IOMUX_MAX_FUNC_COUNT 4
|
||||
#define AMD_IOMUX_SIZE 0x100
|
||||
#define AMD_GPIO_BANK_SIZE (0x100 / 4)
|
||||
|
||||
#define AMD_BRH_IOMUX_SMN_BASE 0x02D01000
|
||||
|
||||
static uint8_t *iomux_base;
|
||||
static uint32_t *gpio_base;
|
||||
|
||||
struct gpio_group {
|
||||
const uint8_t *iomux_defaults;
|
||||
const char *const *gpio_names;
|
||||
const unsigned int gpio_bank_count;
|
||||
const uint32_t *gpio_defaults;
|
||||
const uint16_t *special_gpio_regs;
|
||||
const uint16_t special_gpio_regs_size;
|
||||
const uint16_t acpimmio_gpio_offset;
|
||||
const uint16_t acpimmio_iomux_offset;
|
||||
};
|
||||
|
||||
/* For better readiability and less SLOC, we override the initialized values.
|
||||
* Hide the warnings, as they will overflow the screen and make it harder to
|
||||
* focus on real compielr errors and warnings.
|
||||
*/
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Woverride-init"
|
||||
|
||||
const char *const kunlun_iomux_gpio_names[] = {
|
||||
[0 ... AMD_IOMUX_MAX_FUNC_COUNT * AMD_IOMUX_SIZE - 1] = "",
|
||||
[0x00 * 4] = "PWR_BTN_L", "GPIO0", "GPIO0", "GPIO0",
|
||||
[0x01 * 4] = "SYS_RESET_L", "GPIO1", "GPIO1", "GPIO1",
|
||||
[0x02 * 4] = "WAKE_L", "GPIO2", "GPIO2", "GPIO2",
|
||||
[0x03 * 4] = "GPIO3", "GPIO3", "GPIO3", "GPIO3",
|
||||
[0x04 * 4] = "GPIO4", "SATA_ACT_L", "GPIO4", "GPIO4",
|
||||
[0x05 * 4] = "GPIO5", "DEVSLP0", "GPIO5", "GPIO5",
|
||||
[0x06 * 4] = "GPIO6", "DEVSLP1", "GPIO6", "GPIO6",
|
||||
[0x07 * 4] = "GPIO7", "GPIO7", "GPIO7", "GPIO7",
|
||||
[0x0C * 4] = "PWRGD_OUT", "GPIO12", "GPIO12", "GPIO12",
|
||||
[0x0D * 4] = "I2C4_SCL", "GPIO13", "GPIO13", "GPIO13",
|
||||
[0x0E * 4] = "I2C4_SDA", "GPIO14", "GPIO14", "GPIO14",
|
||||
[0x10 * 4] = "USB10_OC0_L", "GPIO16", "GPIO16", "GPIO16",
|
||||
[0x11 * 4] = "USB11_OC1_L", "GPIO17", "GPIO17", "GPIO17",
|
||||
[0x13 * 4] = "I2C5_SCL", "SMBUS1_SCL", "GPIO19", "GPIO19",
|
||||
[0x14 * 4] = "I2C5_SDA", "SMBUS1_SDA", "GPIO20", "GPIO20",
|
||||
[0x15 * 4] = "GPIO21", "GPIO21", "GPIO21", "n/a",
|
||||
[0x16 * 4] = "GPIO22", "n/a", "GPIO22", "GPIO22",
|
||||
[0x17 * 4] = "ESPI_RSTOUT_L", "GPIO23", "GPIO23", "GPIO23",
|
||||
[0x18 * 4] = "SMERR_L", "GPIO24", "GPIO24", "GPIO24",
|
||||
[0x1A * 4] = "PCIE_RST_L", "GPIO26", "GPIO26", "GPIO26",
|
||||
[0x1C * 4] = "X48M_OUT", "GPIO28", "GPIO28", "GPIO28",
|
||||
[0x4A * 4] = "ESPI_CLK2", "GPIO74", "GPIO74" "GPIO74",
|
||||
[0x4B * 4] = "ESPI_CLK1", "GPIO75", "GPIO75", "n/a",
|
||||
[0x4C * 4] = "GPIO76", "SPI_TPM_CS_L", "GPIO76", "GPIO76",
|
||||
[0x56 * 4] = "GPIO86", "GPIO86", "LPC_SMI_L", "GPIO86",
|
||||
[0x57 * 4] = "GPIO87", "n/a", "GPIO87", "GPIO87",
|
||||
[0x58 * 4] = "GPIO88", "n/a", "GPIO88", "GPIO88",
|
||||
[0x59 * 4] = "GENINT1_L", "PM_INTR_L", "GPIO89", "GPIO89",
|
||||
[0x68 * 4] = "GPIO104", "GPIO104", "n/a", "GPIO104",
|
||||
[0x69 * 4] = "GPIO105", "GPIO105", "n/a", "GPIO105",
|
||||
[0x6A * 4] = "GPIO106", "GPIO106", "n/a", "GPIO106",
|
||||
[0x6B * 4] = "GPIO107", "GPIO107", "n/a", "GPIO107",
|
||||
[0x6C * 4] = "ESPI0_ALERT_D1", "GPIO108", "n/a", "GPIO108",
|
||||
[0x6D * 4] = "GPIO109", "GPIO109", "n/a", "GPIO109",
|
||||
[0x6E * 4] = "ESPI1_ALERT_D1", "GPIO110", "GPIO110", "GPIO110",
|
||||
[0x73 * 4] = "GPIO115", "CLK_REQ1_L", "GPIO115", "GPIO115",
|
||||
[0x74 * 4] = "GPIO116", "CLK_REQ2_L", "GPIO116", "GPIO116",
|
||||
[0x75 * 4] = "ESPI_CLK0", "GPIO117", "GPIO117", "GPIO117",
|
||||
[0x76 * 4] = "SPI_CS0_L", "GPIO118", "GPIO118", "GPIO118",
|
||||
[0x77 * 4] = "SPI_CS1_L", "GPIO119", "GPIO119", "GPIO119",
|
||||
[0x78 * 4] = "ESPI0_D0/SPI0_D0", "GPIO120", "GPIO120", "GPIO120",
|
||||
[0x79 * 4] = "ESPI0_D1/SPI0_D1", "GPIO121", "GPIO121", "GPIO121",
|
||||
[0x7A * 4] = "ESPI0_D2/SPI0_D2", "GPIO122", "GPIO122", "GPIO122",
|
||||
[0x7B * 4] = "ESPI0_D3/SPI0_D3", "GPIO123", "GPIO123", "GPIO123",
|
||||
[0x7C * 4] = "ESPI_CS0_L", "GPIO124", "GPIO124", "GPIO124",
|
||||
[0x7D * 4] = "ESPI_CS1_L", "GPIO125", "GPIO125", "GPIO125",
|
||||
[0x7E * 4] = "SPI_CS2_L", "GPIO126", "GPIO126", "GPIO126",
|
||||
[0x81 * 4] = "ESPI_RSTIN_L", "KBRST_L", "GPIO129", "GPIO129",
|
||||
[0x83 * 4] = "ESPI1_D0/SPI1_D0", "GPIO131", "GPIO131", "GPIO131",
|
||||
[0x84 * 4] = "ESPI1_D1/SPI1_D1", "GPIO132", "GPIO132", "GPIO132",
|
||||
[0x85 * 4] = "ESPI1_D2/SPI1_D2", "GPIO133", "GPIO133", "GPIO133",
|
||||
[0x86 * 4] = "ESPI1_D3/SPI1_D3", "GPIO134", "GPIO134", "GPIO134",
|
||||
[0x87 * 4] = "UART0_CTS_L", "UART2_RXD", "GPIO135", "GPIO135",
|
||||
[0x88 * 4] = "UART0_RXD", "GPIO136", "GPIO136", "GPIO136",
|
||||
[0x89 * 4] = "UART0_RTS_L", "UART2_TXD", "GPIO137", "GPIO137",
|
||||
[0x8A * 4] = "UART0_TXD", "GPIO138", "GPIO138", "GPIO138",
|
||||
[0x8B * 4] = "UART0_INTR", "GPIO139", "GPIO139", "GPIO139",
|
||||
[0x8D * 4] = "UART1_RXD", "GPIO141", "GPIO141", "GPIO141",
|
||||
[0x8E * 4] = "UART1_TXD", "GPIO142", "GPIO142", "GPIO142",
|
||||
[0x91 * 4] = "I3C0_SCL", "I2C0_SCL", "SMBUS0_SCL", "GPIO145",
|
||||
[0x92 * 4] = "I3C0_SDA", "I2C0_SDA", "SMBUS0_SDA", "GPIO146",
|
||||
[0x93 * 4] = "I3C1_SCL", "I2C1_SCL", "GPIO147", "GPIO147",
|
||||
[0x94 * 4] = "I3C1_SDA", "I2C1_SDA", "GPIO148", "GPIO148",
|
||||
[0x95 * 4] = "I3C2_SCL", "I2C2_SCL", "GPIO149", "GPIO149",
|
||||
[0x96 * 4] = "I3C2_SDA", "I2C2_SDA", "GPIO150", "GPIO150",
|
||||
[0x97 * 4] = "I3C3_SCL", "I2C3_SCL", "GPIO151", "GPIO151",
|
||||
[0x98 * 4] = "I3C3_SDA", "I2C3_SDA", "GPIO152", "GPIO152",
|
||||
};
|
||||
|
||||
const uint8_t kunlun_iomux_group_defaults[] = {
|
||||
[0 ... AMD_IOMUX_SIZE - 1] = 0x00,
|
||||
[0x13] = 0x01,
|
||||
[0x14] = 0x01,
|
||||
[0x87] = 0x02,
|
||||
[0x89] = 0x02,
|
||||
[0x8A] = 0x01,
|
||||
[0x8E] = 0x01,
|
||||
};
|
||||
|
||||
const uint32_t kunlun_gpio_group_defaults[] = {
|
||||
[0 ... 4 * AMD_GPIO_BANK_SIZE - 1] = 0,
|
||||
[0x0000] = 0x00140000, 0x00140000, 0x00140000, 0x00140000,
|
||||
[0x0010 / 4] = 0x00140000, 0x00240000, 0x00240000, 0x00240000,
|
||||
[0x0020 / 4] = 0x00240000, 0x00240000, 0x00140000, 0x00140000,
|
||||
[0x0030 / 4] = 0x00040000, 0x00040000, 0x00040000, 0x00000000,
|
||||
[0x0040 / 4] = 0x00140000, 0x00140000, 0x00140000, 0x00040000,
|
||||
[0x0050 / 4] = 0x00040000, 0x00240000, 0x00240000, 0x00140000,
|
||||
[0x0060 / 4] = 0x00140000, 0x00000000, 0x00040000, 0x00240000,
|
||||
[0x0070 / 4] = 0x00240000, 0x00140000, 0x00140000, 0x00140000,
|
||||
[0x0080 / 4] = 0x00240000, 0x00000000, 0x00000000, 0x00000000,
|
||||
[0x00A0 / 4] = 0x00240000, 0x00000000, 0x00140000, 0x00000000,
|
||||
[0x0120 / 4] = 0x00000000, 0x00000000, 0x00240000, 0x00240000,
|
||||
[0x0130 / 4] = 0x00140000, 0x00000000, 0x00000000, 0x00000000,
|
||||
[0x0150 / 4] = 0x00000000, 0x00000000, 0x00240000, 0x00240000,
|
||||
[0x0160 / 4] = 0x00240000, 0x00140000, 0x00000001, 0x00000000,
|
||||
[0x01A0 / 4] = 0x00240000, 0x00240000, 0x00240000, 0x00240000,
|
||||
[0x01B0 / 4] = 0x00140000, 0x00240000, 0x00000000, 0x00000000,
|
||||
[0x01C0 / 4] = 0x00000000, 0x00000000, 0x00000000, 0x00140000,
|
||||
[0x01D0 / 4] = 0x00140000, 0x00240000, 0x00140000, 0x00140000,
|
||||
[0x01E0 / 4] = 0x00140000, 0x00140000, 0x00140000, 0x00140000,
|
||||
[0x01F0 / 4] = 0x00140000, 0x00140000, 0x00140000, 0x00000000,
|
||||
[0x0200 / 4] = 0x00000000, 0x00140000, 0x00000000, 0x00140000,
|
||||
[0x0210 / 4] = 0x00140000, 0x00140000, 0x00140000, 0x00240000,
|
||||
[0x0220 / 4] = 0x00240000, 0x00140000, 0x00140000, 0x00240000,
|
||||
[0x0230 / 4] = 0x00000000, 0x00240000, 0x00140000, 0x00000000,
|
||||
[0x0240 / 4] = 0x00040000, 0x00040000, 0x00040000, 0x00040000,
|
||||
[0x0250 / 4] = 0x00040000, 0x00040000, 0x00040000, 0x00040000,
|
||||
[0x0260 / 4] = 0x00040000, 0x00000000, 0x00000000, 0x00000000,
|
||||
};
|
||||
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
const uint16_t kunlun_special_gpio_regs[] = {
|
||||
0x0fc, 0x1fc, 0x2f0, 0x02f4, 0x2f8, 0x2fc
|
||||
};
|
||||
|
||||
const struct gpio_group kunlun_gpio_group = {
|
||||
.iomux_defaults = kunlun_iomux_group_defaults,
|
||||
.gpio_names = kunlun_iomux_gpio_names,
|
||||
.gpio_bank_count = 4,
|
||||
.gpio_defaults = kunlun_gpio_group_defaults,
|
||||
.special_gpio_regs = kunlun_special_gpio_regs,
|
||||
.special_gpio_regs_size = ARRAY_SIZE(kunlun_special_gpio_regs),
|
||||
.acpimmio_gpio_offset = 0x1500,
|
||||
.acpimmio_iomux_offset = 0x0d00,
|
||||
};
|
||||
|
||||
static const io_register_t fch_gpio_reg_fields[] = {
|
||||
{ 0, 4, "DebounceTmrOut" },
|
||||
{ 4, 1, "DebounceTmrOutUnit" },
|
||||
{ 5, 2, "DebounceCntrl." },
|
||||
{ 7, 1, "DebounceTmrLarge." },
|
||||
{ 9, 3, "Trigger Type" },
|
||||
{ 11, 1, "Enable interrupt status" },
|
||||
{ 12, 1, "Enable interrupt delivery" },
|
||||
{ 13, 3, "Wake Control" },
|
||||
{ 16, 1, "Pin Status" },
|
||||
{ 17, 2, "DrvStrengthSel" },
|
||||
{ 19, 1, "Reserved" },
|
||||
{ 20, 1, "Pull Up Enable" },
|
||||
{ 21, 1, "Pull Down Enable" },
|
||||
{ 22, 1, "Output Value" },
|
||||
{ 23, 1, "Output Enable" },
|
||||
{ 24, 1, "SW Control In" },
|
||||
{ 25, 1, "SW Control Enable" },
|
||||
{ 25, 1, "RX Disable" },
|
||||
{ 27, 1, "Reserved" },
|
||||
{ 28, 1, "Interrupt Status" },
|
||||
{ 29, 1, "Wake Status" },
|
||||
{ 30, 1, "Less2SecSts" },
|
||||
{ 31, 1, "Less10SecSts" },
|
||||
};
|
||||
|
||||
const char * const drive_strength[] = {
|
||||
"Unsupported",
|
||||
"60 Ohms",
|
||||
"40 Ohms",
|
||||
"80 Ohms"
|
||||
};
|
||||
|
||||
const char * const wake_cntrl[] = {
|
||||
"S0i3",
|
||||
"S3",
|
||||
"S4/S5"
|
||||
};
|
||||
|
||||
const char * const debounce_cntrl[] = {
|
||||
"No debounce",
|
||||
"Preserve low glitch",
|
||||
"Preserve high glitch",
|
||||
"Remove glitch"
|
||||
};
|
||||
|
||||
const char * const trigger_type[] = {
|
||||
[0] = "High edge",
|
||||
[1] = "High level",
|
||||
[2] = "Low edge",
|
||||
[3] = "Low level",
|
||||
[4] = "Both edges",
|
||||
[5 ... 8] = "Reserved",
|
||||
};
|
||||
|
||||
static void print_iomux_reg(uint16_t addr, uint8_t reg, const char *const *gpio_names)
|
||||
{
|
||||
printf("IOMUXx%02x: 0x%02x (%s)\n",
|
||||
addr, reg, gpio_names[addr * 4 + reg]);
|
||||
}
|
||||
|
||||
static void print_iomux_diff(const uint8_t reg, const uint8_t def, const uint8_t diff,
|
||||
const char *const *gpio_names)
|
||||
{
|
||||
printf("IOMUXx%02x: 0x%02x (%s) DEFAULT\n",
|
||||
reg, def, gpio_names[reg * 4 + def]);
|
||||
printf("IOMUXx%02x: 0x%02x DIFF\n", reg, diff);
|
||||
}
|
||||
|
||||
static void print_gpio_reg(uint16_t addr, uint32_t reg, bool verbose)
|
||||
{
|
||||
size_t i;
|
||||
const char *attr;
|
||||
|
||||
printf("GPIOx%04x: 0x%08"PRIx32"\n", addr * 4, reg);
|
||||
|
||||
if (!verbose)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fch_gpio_reg_fields); i++) {
|
||||
uint32_t val = reg >> fch_gpio_reg_fields[i].addr;
|
||||
val &= ((1 << fch_gpio_reg_fields[i].size) - 1);
|
||||
switch(i) {
|
||||
case 2: attr = debounce_cntrl[val]; break;
|
||||
case 4: attr = trigger_type[val]; break;
|
||||
case 7: attr = wake_cntrl[val]; break;
|
||||
case 9: attr = drive_strength[val]; break;
|
||||
default: attr = NULL; break;
|
||||
}
|
||||
if (attr)
|
||||
printf("0x%04x = %s (%s)\n", val, fch_gpio_reg_fields[i].name, attr);
|
||||
else
|
||||
printf("0x%04x = %s\n", val, fch_gpio_reg_fields[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_gpio_diff(const uint16_t reg, const uint32_t def, const uint32_t diff)
|
||||
{
|
||||
printf("GPIOx%04x: 0x%08x DEFAULT\n", reg * 4, def);
|
||||
printf("GPIOx%04x: 0x%08x DIFF\n", reg * 4, diff);
|
||||
}
|
||||
|
||||
static bool is_special_gpio_register(uint16_t reg, const struct gpio_group *sb_gpio_group)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sb_gpio_group->special_gpio_regs_size; i++) {
|
||||
if (reg == sb_gpio_group->special_gpio_regs[i])
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int print_gpios(struct pci_dev *sb, int show_all, int show_diffs)
|
||||
{
|
||||
size_t i;
|
||||
const struct gpio_group *sb_gpio_group = NULL;
|
||||
const uint8_t *acpi_mmio_bar;
|
||||
uint32_t acpi_mmio_smn_bar;
|
||||
uint32_t gpio_reg, gpio_diff;
|
||||
uint8_t iomux_reg, iomux_diff;
|
||||
int smbus_rev;
|
||||
bool use_smn = false;
|
||||
|
||||
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:
|
||||
sb_gpio_group = &kunlun_gpio_group;
|
||||
acpi_mmio_smn_bar = AMD_BRH_IOMUX_SMN_BASE;
|
||||
use_smn = true;
|
||||
break;
|
||||
default:
|
||||
printf("Error: Dumping GPIOs on this southbridge is not (yet) supported.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
printf("Error: Dumping GPIOs on this southbridge is not (yet) supported.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (show_diffs && !show_all)
|
||||
printf("\n========== GPIO DIFFS ===========\n\n");
|
||||
else
|
||||
printf("\n============= GPIOS =============\n\n");
|
||||
|
||||
acpi_mmio_bar = get_acpi_mmio_bar(sb);
|
||||
|
||||
if (!acpi_mmio_bar && !use_smn)
|
||||
return 1;
|
||||
|
||||
if (use_smn) {
|
||||
iomux_base = (uint8_t *)(uintptr_t)(acpi_mmio_smn_bar + sb_gpio_group->acpimmio_iomux_offset);
|
||||
gpio_base = (uint32_t *)(uintptr_t)(acpi_mmio_smn_bar + sb_gpio_group->acpimmio_gpio_offset);
|
||||
|
||||
printf("ACPI MMIO IOMUX 0x%08x (SMN)\n\n", acpi_mmio_smn_bar + sb_gpio_group->acpimmio_iomux_offset);
|
||||
printf("ACPI MMIO GPIO 0x%08x (SMN)\n\n", acpi_mmio_smn_bar + sb_gpio_group->acpimmio_gpio_offset);
|
||||
} else {
|
||||
iomux_base = (uint8_t *)(acpi_mmio_bar + sb_gpio_group->acpimmio_iomux_offset);
|
||||
gpio_base = (uint32_t *)(acpi_mmio_bar + sb_gpio_group->acpimmio_gpio_offset);
|
||||
|
||||
printf("ACPI MMIO IOMUX 0x%08lx (MEM)\n\n", (uintptr_t)acpi_mmio_bar + sb_gpio_group->acpimmio_iomux_offset);
|
||||
printf("ACPI MMIO GPIO 0x%08lx (MEM)\n\n", (uintptr_t)acpi_mmio_bar + sb_gpio_group->acpimmio_gpio_offset);
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < AMD_IOMUX_SIZE; i++) {
|
||||
if (use_smn)
|
||||
iomux_reg = smn_read8((uint32_t)(uintptr_t)(iomux_base + i)) & 3;
|
||||
else
|
||||
iomux_reg = read8(iomux_base + i) & 3;
|
||||
|
||||
if (show_all)
|
||||
print_iomux_reg(i, iomux_reg, sb_gpio_group->gpio_names);
|
||||
|
||||
if (show_diffs) {
|
||||
iomux_diff = iomux_reg ^ sb_gpio_group->iomux_defaults[i];
|
||||
if (iomux_diff) {
|
||||
if (!show_all)
|
||||
print_iomux_reg(i, iomux_reg, sb_gpio_group->gpio_names);
|
||||
print_iomux_diff(i, sb_gpio_group->iomux_defaults[i],
|
||||
iomux_diff, sb_gpio_group->gpio_names);
|
||||
if (!show_all)
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < AMD_GPIO_BANK_SIZE * sb_gpio_group->gpio_bank_count; i++) {
|
||||
if (use_smn)
|
||||
gpio_reg = smn_read32((uint32_t)(uintptr_t)(gpio_base + i)) ;
|
||||
else
|
||||
gpio_reg = read32(gpio_base + i);
|
||||
|
||||
print_gpio_reg(i, gpio_reg, false);
|
||||
|
||||
if (show_diffs) {
|
||||
gpio_diff = gpio_reg ^ sb_gpio_group->gpio_defaults[i];
|
||||
if (gpio_diff)
|
||||
print_gpio_diff(i, sb_gpio_group->gpio_defaults[i], gpio_diff);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_all) {
|
||||
printf("\n========== GPIO CONFIG ===========\n\n");
|
||||
|
||||
for (i = 0; i < AMD_GPIO_BANK_SIZE * sb_gpio_group->gpio_bank_count; i++) {
|
||||
if (is_special_gpio_register(i * 4, sb_gpio_group))
|
||||
continue;
|
||||
|
||||
if (use_smn)
|
||||
gpio_reg = smn_read32((uint32_t)(uintptr_t)(gpio_base + i)) ;
|
||||
else
|
||||
gpio_reg = read32(gpio_base + i);
|
||||
|
||||
print_gpio_reg(i, gpio_reg, true);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
180
util/amdtool/irq.c
Normal file
180
util/amdtool/irq.c
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/* 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_PCI_INTR_IDX 0xc00
|
||||
#define AMD_PCI_INTR_DATA 0xc01
|
||||
|
||||
#define PCI_INTR_ROUTE_IOAPIC 0x80
|
||||
|
||||
struct irq_routing_table {
|
||||
const io_register_t irq_reg;
|
||||
void (*print_irq_reg)(uint8_t val);
|
||||
};
|
||||
|
||||
static void print_misc_irq(uint8_t val)
|
||||
{
|
||||
static const char * const irq14_irq15_map[] = {
|
||||
"legacy IDE",
|
||||
"SATA_IDE",
|
||||
"SATA2",
|
||||
"SERIRQ/PCI",
|
||||
};
|
||||
|
||||
printf("\tIRQ0 source: %s\n"
|
||||
"\tIRQ1 source: %s\n"
|
||||
"\tIRQ8 source: %s\n"
|
||||
"\tIRQ12 source: %s\n"
|
||||
"\tIRQ14 mapped to: %s\n"
|
||||
"\tIRQ15 mapped to: %s\n",
|
||||
val & 0x1 ? "SERIRQ/PCI" : "i8254",
|
||||
val & 0x2 ? "SERIRQ/PCI" : "IMC",
|
||||
val & 0x4 ? "SERIRQ/PCI" : "RTC",
|
||||
val & 0x8 ? "SERIRQ/PCI" : "IMC",
|
||||
irq14_irq15_map[(val >> 4) & 0x3],
|
||||
irq14_irq15_map[(val >> 6) & 0x3]);
|
||||
}
|
||||
|
||||
static void print_misc0_irq(uint8_t val)
|
||||
{
|
||||
printf("\t%s\n"
|
||||
"\tUSB IRQ1 source: %s\n"
|
||||
"\tUSB IRQ12 source: %s\n"
|
||||
"\tIRQ1/IRQ12 mask: %sabled\n"
|
||||
"\tIRQ input: %s\n"
|
||||
"\tIRQ1 filter: %sabled\n"
|
||||
"\tIRQ12 filter: %sabled\n"
|
||||
"\tINTR delay 600ns: %sabled\n",
|
||||
val & 0x1 ? "IOAPIC INT2 from PIC IRQ0, IOAPIC INT0 from PIC INTR"
|
||||
: "IOAPIC INT0 from PIC IRQ0, IOAPIC INT2 from PIC INTR",
|
||||
val & 0x2 ? "IMC IRQ1" : "serial IRQ1",
|
||||
val & 0x4 ? "IMC IRQ12" : "serial IRQ12",
|
||||
val & 0x8 ? "en" : "dis",
|
||||
val & 0x10 ? "enabled" : "masked off",
|
||||
val & 0x20 ? "en" : "dis",
|
||||
val & 0x40 ? "en" : "dis",
|
||||
val & 0x80 ? "en" : "dis");
|
||||
}
|
||||
|
||||
static const struct irq_routing_table kunlun_irq_routing[] = {
|
||||
{ { 0x00, 1, "INTA#" }, NULL },
|
||||
{ { 0x01, 1, "INTB#" }, NULL },
|
||||
{ { 0x02, 1, "INTC#" }, NULL },
|
||||
{ { 0x03, 1, "INTD#" }, NULL },
|
||||
{ { 0x04, 1, "INTE#" }, NULL },
|
||||
{ { 0x05, 1, "INTF#/GENINT2" }, NULL },
|
||||
{ { 0x06, 1, "INTG#" }, NULL },
|
||||
{ { 0x07, 1, "INTH#" }, NULL },
|
||||
{ { 0x08, 1, "Misc" }, print_misc_irq },
|
||||
{ { 0x09, 1, "Misc0" }, print_misc0_irq },
|
||||
{ { 0x0A, 1, "Misc1/HPET_L" }, NULL },
|
||||
{ { 0x0B, 1, "Misc2/HPET_H" }, NULL },
|
||||
{ { 0x0C, 1, "INTA from SERIRQ" }, NULL },
|
||||
{ { 0x0D, 1, "INTB from SERIRQ" }, NULL },
|
||||
{ { 0x0E, 1, "INTC from SERIRQ" }, NULL },
|
||||
{ { 0x0F, 1, "INTD from SERIRQ" }, NULL },
|
||||
{ { 0x10, 1, "SCI" }, NULL },
|
||||
{ { 0x11, 1, "SMBUS0" }, NULL },
|
||||
{ { 0x12, 1, "ASF" }, NULL },
|
||||
{ { 0x13, 1, "HDA" }, NULL },
|
||||
{ { 0x14, 1, "GBE0" }, NULL },
|
||||
{ { 0x15, 1, "GBE1" }, NULL },
|
||||
{ { 0x16, 1, "PerMon" }, NULL },
|
||||
{ { 0x17, 1, "SD" }, NULL },
|
||||
{ { 0x1A, 1, "SDIO" }, NULL },
|
||||
{ { 0x20, 1, "CIR (no IRQ connected)" }, NULL },
|
||||
{ { 0x21, 1, "GPIOa (from PAD_FANIN0)" }, NULL },
|
||||
{ { 0x22, 1, "GPIOb (from PAD_FANOUT0)" }, NULL },
|
||||
{ { 0x23, 1, "GPIOc (no IRQ connected)" }, NULL },
|
||||
{ { 0x30, 1, "USB Emu" }, NULL },
|
||||
{ { 0x31, 1, "USB Dual Role 1" }, NULL },
|
||||
{ { 0x32, 1, "USB Dual Role 2" }, NULL },
|
||||
{ { 0x34, 1, "XHCI0" }, NULL },
|
||||
{ { 0x35, 1, "USB SSIC" }, NULL },
|
||||
{ { 0x40, 1, "IDE" }, NULL },
|
||||
{ { 0x41, 1, "SATA" }, NULL },
|
||||
{ { 0x42, 1, "UFS" }, NULL },
|
||||
{ { 0x43, 1, "EMMC" }, NULL },
|
||||
{ { 0x50, 1, "GPPInt0" }, NULL },
|
||||
{ { 0x51, 1, "GPPInt1" }, NULL },
|
||||
{ { 0x52, 1, "GPPInt2" }, NULL },
|
||||
{ { 0x53, 1, "GPPInt3" }, NULL },
|
||||
{ { 0x60, 1, "Gevent SCI interrupt" }, NULL },
|
||||
{ { 0x61, 1, "Gevent SMI interrupt" }, NULL },
|
||||
{ { 0x62, 1, "GPIO controller interrupt" }, NULL },
|
||||
{ { 0x70, 1, "I2C0/I3C0" }, NULL },
|
||||
{ { 0x71, 1, "I2C1/I3C1" }, NULL },
|
||||
{ { 0x72, 1, "I2C2/I3C2" }, NULL },
|
||||
{ { 0x73, 1, "I2C3/I3C3" }, NULL },
|
||||
{ { 0x74, 1, "UART0" }, NULL },
|
||||
{ { 0x75, 1, "UART1" }, NULL },
|
||||
{ { 0x76, 1, "I2C4" }, NULL },
|
||||
{ { 0x77, 1, "I2C5" }, NULL },
|
||||
{ { 0x78, 1, "UART2" }, NULL },
|
||||
{ { 0x79, 1, "UART3" }, NULL },
|
||||
};
|
||||
|
||||
static uint8_t read_irq_reg(uint8_t addr)
|
||||
{
|
||||
outb(addr, AMD_PCI_INTR_IDX);
|
||||
return inb(AMD_PCI_INTR_DATA);
|
||||
}
|
||||
|
||||
int print_irq_routing(struct pci_dev *sb)
|
||||
{
|
||||
int i, irq_table_size;
|
||||
const struct irq_routing_table *irq_table = NULL;
|
||||
int smbus_rev;
|
||||
uint8_t reg;
|
||||
|
||||
printf("\n============= IRQ routing ==============\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:
|
||||
irq_table_size = ARRAY_SIZE(kunlun_irq_routing);
|
||||
irq_table = kunlun_irq_routing;
|
||||
break;
|
||||
default:
|
||||
printf("Error: Dumping IRQ routing on this southbridge is not (yet) supported.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
printf("Error: Dumping IRQ routing on this southbridge is not (yet) supported.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("PIC routing:\n\n");
|
||||
for (i = 0; i < irq_table_size; i++) {
|
||||
reg = read_irq_reg(irq_table[i].irq_reg.addr);
|
||||
printf("IRQ REG 0x%02x = 0x%02x (%s)\n", irq_table[i].irq_reg.addr,
|
||||
reg, irq_table[i].irq_reg.name);
|
||||
if (irq_table[i].print_irq_reg)
|
||||
irq_table[i].print_irq_reg(reg);
|
||||
}
|
||||
|
||||
printf("\nIOAPIC routing:\n\n");
|
||||
for (i = 0; i < irq_table_size; i++) {
|
||||
reg = read_irq_reg(irq_table[i].irq_reg.addr | PCI_INTR_ROUTE_IOAPIC);
|
||||
printf("IRQ REG 0x%02x = 0x%02x (%s)\n",
|
||||
irq_table[i].irq_reg.addr | PCI_INTR_ROUTE_IOAPIC,
|
||||
reg, irq_table[i].irq_reg.name);
|
||||
if (irq_table[i].print_irq_reg)
|
||||
irq_table[i].print_irq_reg(reg);
|
||||
}
|
||||
|
||||
printf("========================================\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
126
util/amdtool/lpc.c
Normal file
126
util/amdtool/lpc.c
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/* 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 <inttypes.h>
|
||||
#include <commonlib/helpers.h>
|
||||
#include "amdtool.h"
|
||||
|
||||
static const io_register_t kunlun_lpc_cfg_registers[] = {
|
||||
{0x00, 4, "ID"},
|
||||
{0x04, 2, "CMD"},
|
||||
{0x06, 2, "STS"},
|
||||
{0x08, 1, "RID"},
|
||||
{0x09, 1, "CC[2]"},
|
||||
{0x0A, 1, "CC[1]"},
|
||||
{0x0B, 1, "CC[0]"},
|
||||
{0x0C, 1, "CLSIZE"},
|
||||
{0x0D, 1, "LATTMR"},
|
||||
{0x0E, 1, "HTYPE"},
|
||||
{0x2C, 4, "SS"},
|
||||
{0x34, 1, "CAPP"},
|
||||
{0x40, 1, "PCICTL"},
|
||||
{0x44, 4, "IOPDE"},
|
||||
{0x48, 4, "IOMPDE"},
|
||||
{0x4C, 4, "MEMRNG"},
|
||||
{0x50, 4, "ROMPROT[0]"},
|
||||
{0x54, 4, "ROMPROT[1]"},
|
||||
{0x58, 4, "ROMPROT[2]"},
|
||||
{0x5C, 4, "ROMPROT[3]"},
|
||||
{0x60, 2, "LPCMEMADDRSTART"},
|
||||
{0x62, 2, "LPCMEMADDREND"},
|
||||
{0x64, 2, "PCIWIDEIO[0]"},
|
||||
{0x66, 2, "PCIWIDEIO[1]"},
|
||||
{0x68, 2, "ROMADDRSTART[0]"},
|
||||
{0x6A, 2, "ROMADDREND[0]"},
|
||||
{0x6C, 2, "ROMADDRSTART[1]"},
|
||||
{0x6E, 2, "ROMADDREND[1]"},
|
||||
{0x70, 4, "FWHUBSEL"},
|
||||
{0x74, 4, "ALTWIDEIO"},
|
||||
{0x78, 4, "MISCCTL"},
|
||||
{0x7C, 1, "TPM"},
|
||||
{0x7D, 1, "LPCCLKCNTL"},
|
||||
{0x84, 4, "TMKBCBASELO"},
|
||||
{0x88, 4, "TMKBCBASEHI"},
|
||||
{0x8C, 2, "TMKBCREMAP"},
|
||||
{0x90, 2, "PCIWIDEIO[2]"},
|
||||
{0x98, 4, "EC_LPC_CTL"},
|
||||
{0x9C, 4, "GEC_SHDWROM_ADDR"},
|
||||
{0xA0, 4, "SPIBASE"},
|
||||
{0xA4, 2, "EC_PORT_ADDR"},
|
||||
{0xA8, 4, "ROM3_LO"},
|
||||
{0xAC, 4, "ROM3_HI"},
|
||||
{0xB8, 4, "ROMDMACTL"},
|
||||
{0xBA, 1, "EC_CTL"},
|
||||
{0xBB, 1, "HOST_CTL"},
|
||||
{0xC8, 4, "CLIENT_ROM_PROTECT"},
|
||||
{0xCC, 4, "AUTO_ROM_CFG"},
|
||||
{0xD0, 4, "CLKCTL"},
|
||||
{0xD4, 4, "CLKRUNOPT"},
|
||||
{0xDC, 4, "MISCCTL"},
|
||||
{0xE0, 4, "ROMPROT[4]"},
|
||||
{0xE4, 4, "ROMPROT[5]"},
|
||||
{0xE8, 4, "ROMPROT[6]"},
|
||||
{0xEC, 4, "ROMPROT[7]"},
|
||||
};
|
||||
|
||||
int print_lpc(struct pci_dev *sb)
|
||||
{
|
||||
size_t i, cfg_registers_size = 0;
|
||||
const io_register_t *cfg_registers;
|
||||
int smbus_rev = 0;
|
||||
|
||||
printf("\n========== LPC =========\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:
|
||||
cfg_registers = kunlun_lpc_cfg_registers;
|
||||
cfg_registers_size = ARRAY_SIZE(kunlun_lpc_cfg_registers);
|
||||
break;
|
||||
default:
|
||||
printf("Error: Dumping LPC on this southbridge is not (yet) supported.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
printf("Error: Dumping LPC on this southbridge is not (yet) supported.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
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,
|
||||
pci_read_long(sb, cfg_registers[i].addr),
|
||||
cfg_registers[i].name);
|
||||
break;
|
||||
case 2:
|
||||
printf("0x%04x: 0x%04x (%s)\n",
|
||||
cfg_registers[i].addr,
|
||||
pci_read_word(sb, cfg_registers[i].addr),
|
||||
cfg_registers[i].name);
|
||||
break;
|
||||
case 1:
|
||||
printf("0x%04x: 0x%02x (%s)\n",
|
||||
cfg_registers[i].addr,
|
||||
pci_read_byte(sb, cfg_registers[i].addr),
|
||||
cfg_registers[i].name);
|
||||
break;
|
||||
default:
|
||||
printf("Error: register size %d not implemented.\n",
|
||||
cfg_registers[i].size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
149
util/amdtool/psb.c
Normal file
149
util/amdtool/psb.c
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/* 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 SMN_PSP_PUBLIC_BASE 0x3800000
|
||||
|
||||
#define MP0_C2P_MSG_BASE 0x10500
|
||||
#define MPASP_C2P_MSG_BASE 0x10900
|
||||
|
||||
#define CORE_2_PSP_MSG_37_OFFSET (MPASP_C2P_MSG_BASE + (37 * 4))
|
||||
#define CORE_2_PSP_MSG_38_OFFSET (MPASP_C2P_MSG_BASE + (38 * 4))
|
||||
|
||||
static const io_register_t breithorn_c2p_msg_37_fields[] = {
|
||||
{0x00, 8, "PLATFORM_VENDOR_ID"},
|
||||
{0x08, 4, "PLATFORM_MODEL_ID"},
|
||||
{0x0c, 4, "BIOS_KEY_REVISION_ID"},
|
||||
{0x10, 4, "ROOT_KEY_SELECT"},
|
||||
{0x18, 1, "PLATFORM_SECURE_BOOT_EN"},
|
||||
{0x19, 1, "DISABLE_BIOS_KEY_ANTIROLLBACK"},
|
||||
{0x1a, 1, "DISABLE_AMD_KEY_USAGE"},
|
||||
{0x1b, 1, "DISABLE_SECURE_DEBUG_UNLOCK"},
|
||||
{0x1c, 1, "CUSTOMER_KEY_LOCK"},
|
||||
};
|
||||
|
||||
static const io_register_t breithorn_c2p_msg_38_fields[] = {
|
||||
{0x00, 8, "PSB Status/Error"},
|
||||
{0x08, 1, "PSB Fusing Readiness"},
|
||||
{0x0c, 1, "SPL Fuse Update Required"},
|
||||
{0x0d, 1, "SPL Fuse Error"},
|
||||
{0x0e, 1, "SPL Entry Error"},
|
||||
{0x0f, 1, "SPL Table Missing"},
|
||||
{0x1c, 1, "HSTISTATE_PSP_SECURE_EN"},
|
||||
{0x1d, 1, "HSTISTATE_PSP_PLATFORM_SECURE_EN"},
|
||||
{0x1e, 1, "HSTISTATE_PSP_DEBUG_LOCK_ON"},
|
||||
{0x1f, 1, "HSTISTATE_PSP_CUSTOMER_KEY_LOCK_ON"},
|
||||
};
|
||||
/* For better readiability and less SLOC, we override the initialized values.
|
||||
* Hide the warnings, as they will overflow the screen and make it harder to
|
||||
* focus on real compiler errors and warnings.
|
||||
*/
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Woverride-init"
|
||||
|
||||
const char *const c2p_msg_38_error_codes[] = {
|
||||
[0 ... 0xff] = "Other",
|
||||
[0x00] = "PSB passed/no error",
|
||||
[0x22] = "BIOS signing key entry not found",
|
||||
[0x3e] = "Error reading fuse info",
|
||||
[0x64] = "Timeout error attempting to fuse",
|
||||
[0x6c] = "Error in BIOS Directory Table - Reset image not found",
|
||||
[0x6f] = "OEM BIOS signing key usage flag violation",
|
||||
[0x78] = "BIOS RTM signature entry not found",
|
||||
[0x79] = "BIOS copy to DRAM failed",
|
||||
[0x7a] = "BIOS RTM signature verification failed",
|
||||
[0x7b] = "OEM BIOS signing key failed signature verification",
|
||||
[0x7c] = "Platform Vendor ID and/or Model ID binding violation",
|
||||
[0x7d] = "BIOS Copy bit is unset for reset image",
|
||||
[0x7e] = "Requested fuse is already blown",
|
||||
[0x7f] = "Error with actual fusing operation",
|
||||
[0x80] = "Processor1: Error reading fuse info",
|
||||
[0x81] = "Processor1: Requested fuse is already blown",
|
||||
[0x82] = "Processor1: Platform Vendor ID and/or Model ID binding violation",
|
||||
[0x83] = "Processor1: Error with actual fusing operation",
|
||||
[0x92] = "Error in BIOS Directory Table - Firmware type mismatch",
|
||||
};
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
static void print_psb_status_v2(const char * const *psb_status_codes,
|
||||
const io_register_t *status_fields, size_t status_size,
|
||||
const io_register_t *hsti_fields, size_t hsti_size)
|
||||
{
|
||||
uint32_t status, hsti;
|
||||
uint8_t psb_state;
|
||||
size_t i;
|
||||
|
||||
status = smn_read32(SMN_PSP_PUBLIC_BASE + CORE_2_PSP_MSG_37_OFFSET);
|
||||
printf("PSB: STATUS = %08"PRIx32"\n", status);
|
||||
|
||||
if (status_fields) {
|
||||
for (i = 0; i < status_size; i++) {
|
||||
unsigned int val = status >> status_fields[i].addr;
|
||||
val &= ((1 << status_fields[i].size) -1);
|
||||
printf("0x%04x = %s\n", val, status_fields[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
hsti = smn_read32(SMN_PSP_PUBLIC_BASE + CORE_2_PSP_MSG_38_OFFSET);
|
||||
printf("PSB: HSTI = %08"PRIx32"\n", hsti);
|
||||
|
||||
if (hsti_fields) {
|
||||
for (i = 0; i < hsti_size; i++) {
|
||||
unsigned int val = hsti >> hsti_fields[i].addr;
|
||||
val &= ((1 << hsti_fields[i].size) -1);
|
||||
if (psb_status_codes && i == 0)
|
||||
printf("0x%04x = %s (%s)\n", val, hsti_fields[i].name, psb_status_codes[val]);
|
||||
else
|
||||
printf("0x%04x = %s\n", val, hsti_fields[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
psb_state = ((status >> 23) & 2) | ((status >> 28) & 1);
|
||||
switch (psb_state) {
|
||||
case 0:
|
||||
printf("PSB state: NOT ENABLED\n");
|
||||
printf("You may flash other firmware!\n"
|
||||
"But the Platform Secure Boot state may still be changed to ENABLED or DISABLED!\n");
|
||||
break;
|
||||
case 1:
|
||||
printf("PSB state: DISABLED\n");
|
||||
printf("You may flash other firmware!\n"
|
||||
"Platform Secure Boot is permanently DISABLED!\n");
|
||||
break;
|
||||
case 2:
|
||||
printf("PSB state: ENABLED\n");
|
||||
printf("You may NOT flash other firmware!\n"
|
||||
"Platform Secure Boot is permanently ENABLED!\n");
|
||||
break;
|
||||
default:
|
||||
printf("PSB state: UNKNOWN\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void print_psb(struct pci_dev *nb)
|
||||
{
|
||||
printf("============= Platform Secure Boot ==============\n\n");
|
||||
|
||||
switch (nb->device_id) {
|
||||
case PCI_DEVICE_ID_AMD_BRH_ROOT_COMPLEX:
|
||||
print_psb_status_v2(c2p_msg_38_error_codes,
|
||||
breithorn_c2p_msg_37_fields,
|
||||
ARRAY_SIZE(breithorn_c2p_msg_37_fields),
|
||||
breithorn_c2p_msg_38_fields,
|
||||
ARRAY_SIZE(breithorn_c2p_msg_38_fields));
|
||||
break;
|
||||
default:
|
||||
printf("Error: Dumping PSB status on this northbridge is not (yet) supported.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
printf("\n=================================================\n");
|
||||
}
|
||||
42
util/amdtool/smn.c
Normal file
42
util/amdtool/smn.c
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* amdtool - dump all registers on an AMD CPU + chipset based system */
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include "smn.h"
|
||||
#include "amdtool.h"
|
||||
|
||||
#define SMN_INDIRECT_INDEX 0xB8
|
||||
#define SMN_INDIRECT_DATA 0xBC
|
||||
|
||||
static struct pci_dev *nb_dev = NULL;
|
||||
|
||||
uint32_t smn_read32(uint32_t addr)
|
||||
{
|
||||
if (!nb_dev)
|
||||
return UINT32_MAX;
|
||||
|
||||
pci_write_long(nb_dev, SMN_INDIRECT_INDEX, addr & 0xfffffffc);
|
||||
return pci_read_long(nb_dev, SMN_INDIRECT_DATA);
|
||||
}
|
||||
|
||||
uint16_t smn_read16(uint32_t addr)
|
||||
{
|
||||
if (!nb_dev)
|
||||
return UINT8_MAX;
|
||||
|
||||
pci_write_long(nb_dev, SMN_INDIRECT_INDEX, addr & 0xfffffffc);
|
||||
return pci_read_word(nb_dev, SMN_INDIRECT_DATA + (addr & 2));
|
||||
}
|
||||
|
||||
uint8_t smn_read8(uint32_t addr)
|
||||
{
|
||||
if (!nb_dev)
|
||||
return UINT8_MAX;
|
||||
|
||||
pci_write_long(nb_dev, SMN_INDIRECT_INDEX, addr & 0xfffffffc);
|
||||
return pci_read_byte(nb_dev, SMN_INDIRECT_DATA + (addr & 3));
|
||||
}
|
||||
|
||||
void init_smn(struct pci_dev *nb)
|
||||
{
|
||||
nb_dev = nb;
|
||||
}
|
||||
15
util/amdtool/smn.h
Normal file
15
util/amdtool/smn.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/* amdtool - dump all registers on an AMD CPU + chipset based system */
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef AMDTOOL_SMN_H
|
||||
#define AMDTOOL_SMN_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include "amdtool.h"
|
||||
|
||||
uint32_t smn_read32(uint32_t addr);
|
||||
uint16_t smn_read16(uint32_t addr);
|
||||
uint8_t smn_read8(uint32_t addr);
|
||||
void init_smn(struct pci_dev *nb);
|
||||
|
||||
#endif
|
||||
405
util/amdtool/spi.c
Normal file
405
util/amdtool/spi.c
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
/* 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 BRH_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 kunlun_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 char * const kunlun_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 kunlun_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 = kunlun_spi_cntl0_fields;
|
||||
size = ARRAY_SIZE(kunlun_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)
|
||||
{
|
||||
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:
|
||||
spi_alt_cs = spi_read8(0x1d);
|
||||
spi_alt_cs_register = kunlun_alt_spi_cs_fields;
|
||||
size = ARRAY_SIZE(kunlun_alt_spi_cs_fields);
|
||||
break;
|
||||
default:
|
||||
printf("Error: Dumping SPI_ALT_CS on this southbridge is not (yet) supported.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
printf("Error: Dumping SPI_ALT_CS on this southbridge is not (yet) supported.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = kunlun_spi100_speed_values;
|
||||
values_size = ARRAY_SIZE(kunlun_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)
|
||||
{
|
||||
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(kunlun_spi_bar_registers);
|
||||
spi_register = kunlun_spi_bar_registers;
|
||||
spibar_mask = 0xffffff00;
|
||||
spi_smn_base = BRH_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);
|
||||
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)
|
||||
{
|
||||
return print_spibar(sb);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue