Alexandru Gagniuc (mr.nuke.me@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1430
-gerrit
commit fe72b9101299ba6ff28cf99ca61a7d1a84f7307e Author: Alexandru Gagniuc mr.nuke.me@gmail.com Date: Fri Aug 10 03:55:42 2012 -0500
util/inteltool: Extend to read various bits on VIA systems
Reading of configuration bits is implemented via a new featuere called "quirks". Quirks are device configurations that cannot be accessed directly. They are implemented as hierarchical configurations in the PCI or memory address spaces (index/data register pairs). Such configurations refer to hardware parameters that are board specific. Those parameters would otherwise be difficult to extract from a system running the vendor's firmware.
Change-Id: Icbd39eaf7c7da5568732d77dbf2aed135f835754 Signed-off-by: Alexandru Gagniuc mr.nuke.me@gmail.com --- util/inteltool/Makefile | 5 +- util/inteltool/inteltool.c | 32 ++++++++-- util/inteltool/inteltool.h | 21 ++++++- util/inteltool/quirks/quirks.c | 115 +++++++++++++++++++++++++++++++++++ util/inteltool/quirks/quirks.h | 37 +++++++++++ util/inteltool/quirks/vx900_quirks.c | 81 ++++++++++++++++++++++++ 6 files changed, 282 insertions(+), 9 deletions(-)
diff --git a/util/inteltool/Makefile b/util/inteltool/Makefile index 2028a4a..e0dfa23 100644 --- a/util/inteltool/Makefile +++ b/util/inteltool/Makefile @@ -24,10 +24,11 @@ PROGRAM = inteltool CC ?= gcc INSTALL ?= /usr/bin/install PREFIX ?= /usr/local -CFLAGS ?= -O2 -g -Wall -W +CFLAGS ?= -O2 -g -Wall -W -I$(shell pwd) LDFLAGS += -lpci -lz
-OBJS = inteltool.o cpu.o gpio.o rootcmplx.o powermgt.o memory.o pcie.o amb.o +OBJS = inteltool.o cpu.o gpio.o rootcmplx.o powermgt.o memory.o pcie.o amb.o \ + quirks/quirks.c quirks/vx900_quirks.c
OS_ARCH = $(shell uname) ifeq ($(OS_ARCH), Darwin) diff --git a/util/inteltool/inteltool.c b/util/inteltool/inteltool.c index 0618f4b..3b6d02d 100644 --- a/util/inteltool/inteltool.c +++ b/util/inteltool/inteltool.c @@ -150,6 +150,13 @@ static const struct { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HM70, "HM70" }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_NM70, "NM70" }, { PCI_VENDOR_ID_INTEL, 0x2310, "DH89xxCC" }, + /* + * VIA chips go below this line + */ + /* Host bridges/DRAM controllers (Northbridges) */ + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX900, "VX900"}, + /* Southbridges (LPC controllers) */ + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX900_LPC, "VX900" }, };
#ifndef __DARWIN__ @@ -209,6 +216,7 @@ void print_usage(const char *name) " -P | --pciexpress: dump northbridge PCIEXBAR registers\n\n" " -M | --msrs: dump CPU MSRs\n" " -A | --ambs: dump AMB registers\n" + " -q | --quirks: dump special configuration bits\n" " -a | --all: dump all known registers\n" "\n"); exit(1); @@ -226,7 +234,7 @@ int main(int argc, char *argv[]) int dump_gpios = 0, dump_mchbar = 0, dump_rcba = 0; int dump_pmbase = 0, dump_epbar = 0, dump_dmibar = 0; int dump_pciexbar = 0, dump_coremsrs = 0, dump_ambs = 0; - int show_gpio_diffs = 0; + int show_gpio_diffs = 0, dump_quirks = 0;
static struct option long_options[] = { {"version", 0, 0, 'v'}, @@ -241,11 +249,12 @@ int main(int argc, char *argv[]) {"pciexpress", 0, 0, 'P'}, {"msrs", 0, 0, 'M'}, {"ambs", 0, 0, 'A'}, + {"quirks", 0, 0, 'q'}, {"all", 0, 0, 'a'}, {0, 0, 0, 0} };
- while ((opt = getopt_long(argc, argv, "vh?gGrpmedPMaA", + while ((opt = getopt_long(argc, argv, "vh?gGrpmedPMaAq", long_options, &option_index)) != EOF) { switch (opt) { case 'v': @@ -294,6 +303,9 @@ int main(int argc, char *argv[]) case 'A': dump_ambs = 1; break; + case 'q': + dump_quirks = 1; + break; case 'h': case '?': default: @@ -347,8 +359,9 @@ int main(int argc, char *argv[])
pci_fill_info(sb, PCI_FILL_IDENT|PCI_FILL_BASES|PCI_FILL_SIZES|PCI_FILL_CLASS);
- if (sb->vendor_id != PCI_VENDOR_ID_INTEL) { - printf("Not an Intel(R) southbridge.\n"); + if ((sb->vendor_id != PCI_VENDOR_ID_INTEL) && + (sb->vendor_id != PCI_VENDOR_ID_VIA)) { + printf("Not a supported southbridge.\n"); exit(1); }
@@ -360,8 +373,9 @@ int main(int argc, char *argv[])
pci_fill_info(nb, PCI_FILL_IDENT|PCI_FILL_BASES|PCI_FILL_SIZES|PCI_FILL_CLASS);
- if (nb->vendor_id != PCI_VENDOR_ID_INTEL) { - printf("Not an Intel(R) northbridge.\n"); + if ((nb->vendor_id != PCI_VENDOR_ID_INTEL) && + (nb->vendor_id != PCI_VENDOR_ID_VIA)) { + printf("Not a supported northbridge.\n"); exit(1); }
@@ -439,6 +453,12 @@ int main(int argc, char *argv[]) if (dump_ambs) { print_ambs(nb, pacc); } + + if (dump_quirks) { + print_quirks_north(nb, pacc); + print_quirks_south(sb, pacc); + } + /* Clean up */ pci_free_dev(nb); // pci_free_dev(sb); // TODO: glibc detected "double free or corruption" diff --git a/util/inteltool/inteltool.h b/util/inteltool/inteltool.h index 7872a5f..3108b7c 100644 --- a/util/inteltool/inteltool.h +++ b/util/inteltool/inteltool.h @@ -3,6 +3,7 @@ * * Copyright (C) 2008-2010 by coresystems GmbH * Copyright (C) 2009 Carl-Daniel Hailfinger + * Copyright (C) 2013 Alexandru Gagniuc * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#ifndef _INTELTOOL_H +#define _INTELTOOL_H + #include <stdint.h>
#if defined(__GLIBC__) @@ -36,7 +40,10 @@ #endif
#define INTELTOOL_VERSION "1.0" - +\ +/*============================================================================== + * = Intel Section + *----------------------------------------------------------------------------*/ /* Tested chipsets: */ #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_ICH 0x2410 @@ -140,6 +147,14 @@ #define PCI_DEVICE_ID_INTEL_CORE_3RD_GEN 0x0154 /* Ivy Bridge */ #define PCI_DEVICE_ID_INTEL_CORE_4TH_GEN 0x0c04 /* Haswell */
+/*============================================================================== + *= VIA Section + *----------------------------------------------------------------------------*/ +#define PCI_VENDOR_ID_VIA 0x1106 +#define PCI_DEVICE_ID_VIA_VX900 0x0410 +#define PCI_DEVICE_ID_VIA_VX900_SATA 0x9001 +#define PCI_DEVICE_ID_VIA_VX900_LPC 0x8410 + #define ARRAY_SIZE(a) ((int)(sizeof(a) / sizeof((a)[0])))
#if !defined(__DARWIN__) && !defined(__FreeBSD__) @@ -170,3 +185,7 @@ int print_epbar(struct pci_dev *nb); int print_dmibar(struct pci_dev *nb); int print_pciexbar(struct pci_dev *nb); int print_ambs(struct pci_dev *nb, struct pci_access *pacc); +int print_quirks_north(struct pci_dev *nb, struct pci_access *pacc); +int print_quirks_south(struct pci_dev *sb, struct pci_access *pacc); + +#endif /* _INTELTOOL_H */ diff --git a/util/inteltool/quirks/quirks.c b/util/inteltool/quirks/quirks.c new file mode 100644 index 0000000..dc529c1 --- /dev/null +++ b/util/inteltool/quirks/quirks.c @@ -0,0 +1,115 @@ +/* + * viatool - dump all registers on a VIA CPU + chipset based system. + * + * Copyright (C) 2013 Alexandru Gagniuc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * a long with this program. If not, see http://www.gnu.org/licenses/. + */ + +#include "quirks.h" +#include <inteltool.h> +#include <stdio.h> +#include <stddef.h> + +extern struct quirk_list vx900_sb_quirk_list; + +struct quirk_list *sb_quirks[] = { + &vx900_sb_quirk_list, + 0, +}; + +struct quirk_list *nb_quirks[] = { + 0, +}; + +int print_quirks(struct pci_dev *sb, struct pci_access *pacc, + struct quirk_list **qlists); + +int print_quirks_north(struct pci_dev *nb, struct pci_access *pacc) +{ + printf("\n====== Northbridge Quirks =======\n\n"); + return print_quirks(nb, pacc, nb_quirks); +} + +int print_quirks_south(struct pci_dev *sb, struct pci_access *pacc) +{ + printf("\n====== Southbridge Quirks =======\n\n"); + return print_quirks(sb, pacc, sb_quirks); +} + +int print_quirks(struct pci_dev *sb, struct pci_access *pacc, + struct quirk_list **qlists) +{ + size_t i, j; + struct quirk *q; + struct quirk_list *qlist; + struct pci_dev *dev; + + for (i = 0;; i++) { + qlist = qlists[i]; + + if (qlist == NULL) { + /* OOPS. We've tried all we know, but no quirk */ + printf("No quirks supported.\n"); + break; + } + + /* Is this the right device ? */ + if ((qlist->pci_vendor_id != sb->vendor_id) || + qlist->pci_device_id != sb->device_id) + continue; + + for (j = 0;; j++) { + q = &qlist->dev_quirks[j]; + + if (q->pci_device_id == 0) + break; + + printf("Probing PCI device %i:%.2x.%i\n", + q->pci_bus, q->pci_dev, q->pci_func); + + dev = pci_get_dev(pacc, q->pci_domain, q->pci_bus, + q->pci_dev, q->pci_func); + + if (!dev) { + perror("Error: no device found\n"); + continue; + } + + pci_fill_info(dev, PCI_FILL_IDENT | + PCI_FILL_BASES | + PCI_FILL_SIZES | PCI_FILL_CLASS); + + if (dev->device_id != q->pci_device_id) { + printf("Expected %.4x:%.4x, got %.4x:%.4x\n", + q->pci_vendor_id, q->pci_device_id, + dev->vendor_id, dev->device_id); + continue; + } + + if (!q->quirk_func) { + perror("BUG: Quirk missing.\n"); + continue; + } + + q->quirk_func(dev); + /* On to next quirk */ + } + + /* Done. No need to go through the remainder of the list */ + break; + } + + return 0; +} diff --git a/util/inteltool/quirks/quirks.h b/util/inteltool/quirks/quirks.h new file mode 100644 index 0000000..d9b9bbd --- /dev/null +++ b/util/inteltool/quirks/quirks.h @@ -0,0 +1,37 @@ +/* + * inteltool - dump all registers on a Intel or VIA CPU + chipset based system. + * + * Copyright (C) 2013 Alexandru Gagniuc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * a long with this program. If not, see http://www.gnu.org/licenses/. + */ + +#include <inteltool.h> + +struct quirk { + int pci_domain; + int pci_bus; + int pci_dev; + int pci_func; + int pci_vendor_id; + int pci_device_id; + int (*quirk_func) (struct pci_dev * dev); +}; + +struct quirk_list { + int pci_vendor_id; + int pci_device_id; + /* NULL-terminated list of quirks */ + struct quirk *dev_quirks; +}; diff --git a/util/inteltool/quirks/vx900_quirks.c b/util/inteltool/quirks/vx900_quirks.c new file mode 100644 index 0000000..6e73886 --- /dev/null +++ b/util/inteltool/quirks/vx900_quirks.c @@ -0,0 +1,81 @@ +/* + * viatool - dump all registers on a VIA CPU + chipset based system. + * + * Copyright (C) 2013 Alexandru Gagniuc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * a long with this program. If not, see http://www.gnu.org/licenses/. + */ + +#include "quirks.h" + +#include <stdio.h> + +typedef u8 sata_phy_config[64]; + +static u32 sata_phy_read32(struct pci_dev *dev, u8 index) +{ + /* The SATA PHY control registers are accessed by a funny index/value + * scheme. Each byte (0,1,2,3) has its own 4-bit index */ + index = (index >> 2) & 0xf; + u16 i16 = index | (index << 4) | (index << 8) | (index << 12); + /* The index */ + pci_write_word(dev, 0x68, i16); + /* The value */ + return pci_read_long(dev, 0x64); +} + +static void vx900_sata_read_phy_config(struct pci_dev *dev, sata_phy_config cfg) +{ + size_t i; + u32 *data = (u32 *) cfg; + for (i = 0; i < (sizeof(sata_phy_config)) >> 2; i++) { + data[i] = sata_phy_read32(dev, i << 2); + } +} + +static int quirk_vx900_sata(struct pci_dev *dev) +{ + sata_phy_config ephy; + + /* Get all the info in one pass */ + vx900_sata_read_phy_config(dev, ephy); + + /* Put it on the terminal for the user to read and be done with it */ + printf("SATA PHY config:\n"); + unsigned int i; + for (i = 0; i < sizeof(sata_phy_config); i++) { + if ((i & 0x0f) == 0) { + printf("%.2x :", i); + } + if ((i & 0x0f) == 0x08) + printf("| "); + printf("%.2x ", ephy[i]); + if ((i & 0x0f) == 0x0f) { + printf("\n"); + } + } + return 0; +} + +static struct quirk vx900_sb_quirks[] = { + {0, 0, 0x0f, 0, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX900_SATA, + quirk_vx900_sata}, + {0, 0, 0, 0, 0, 0, 0}, +}; + +struct quirk_list vx900_sb_quirk_list = { + .pci_vendor_id = PCI_VENDOR_ID_VIA, + .pci_device_id = PCI_DEVICE_ID_VIA_VX900_LPC, + .dev_quirks = vx900_sb_quirks +};