diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/southbridge/intel/common/Kconfig | 7 | ||||
-rw-r--r-- | src/southbridge/intel/common/Makefile.inc | 3 | ||||
-rw-r--r-- | src/southbridge/intel/common/acpi_pirq_gen.c | 115 | ||||
-rw-r--r-- | src/southbridge/intel/common/acpi_pirq_gen.h | 42 | ||||
-rw-r--r-- | src/southbridge/intel/common/rcba_pirq.c | 42 | ||||
-rw-r--r-- | src/southbridge/intel/common/rcba_pirq.h | 44 |
6 files changed, 253 insertions, 0 deletions
diff --git a/src/southbridge/intel/common/Kconfig b/src/southbridge/intel/common/Kconfig index 6ce6b33579..0d2e3b1690 100644 --- a/src/southbridge/intel/common/Kconfig +++ b/src/southbridge/intel/common/Kconfig @@ -12,6 +12,13 @@ config SOUTHBRIDGE_INTEL_COMMON_SPI def_bool n select SPI_FLASH +config SOUTHBRIDGE_INTEL_COMMON_PIRQ_ACPI_GEN + def_bool n + +config SOUTHBRIDGE_INTEL_COMMON_RCBA_PIRQ + def_bool n + select SOUTHBRIDGE_INTEL_COMMON_PIRQ_ACPI_GEN + config HAVE_INTEL_CHIPSET_LOCKDOWN def_bool n diff --git a/src/southbridge/intel/common/Makefile.inc b/src/southbridge/intel/common/Makefile.inc index 0128505d66..2feefcb96a 100644 --- a/src/southbridge/intel/common/Makefile.inc +++ b/src/southbridge/intel/common/Makefile.inc @@ -33,4 +33,7 @@ ifeq ($(CONFIG_SPI_FLASH_SMM),y) smm-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SPI) += spi.c endif +ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_PIRQ_ACPI_GEN) += acpi_pirq_gen.c +ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_RCBA_PIRQ) += rcba_pirq.c + endif diff --git a/src/southbridge/intel/common/acpi_pirq_gen.c b/src/southbridge/intel/common/acpi_pirq_gen.c new file mode 100644 index 0000000000..3ff591c1e5 --- /dev/null +++ b/src/southbridge/intel/common/acpi_pirq_gen.c @@ -0,0 +1,115 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Arthur Heymans <arthur@aheymans.xyz> + * + * 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; version 2 of the License. + * + * 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. + */ + +#include <arch/acpigen.h> +#include <arch/io.h> +#include <console/console.h> +#include <device/pci_def.h> +#include <string.h> + +#include "acpi_pirq_gen.h" + +enum emit_type { + EMIT_NONE, + EMIT_APIC, + EMIT_PICM, +}; + +static size_t enumerate_root_pci_pins(const enum emit_type emit, + const char *lpcb_path) +{ + char buffer[DEVICE_PATH_MAX]; + device_t dev; + pci_pin_t prev_int_pin = PCI_INT_NONE; + u8 prev_pci_dev = 0; + size_t num_devs = 0; + + for (dev = all_devices; dev; dev = dev->next) { + u8 pci_dev; + u8 int_pin; + pirq_t pirq; + + if (dev->path.type != DEVICE_PATH_PCI || + dev->bus->secondary != 0) + continue; + + pci_dev = PCI_SLOT(dev->path.pci.devfn); + int_pin = pci_read_config8(dev, PCI_INTERRUPT_PIN); + + if (int_pin == PCI_INT_NONE || int_pin > PCI_INT_D) + continue; + + pirq = intel_common_map_pirq(dev, int_pin); + if (emit == EMIT_NONE) /* Only print on the first pass */ + printk(BIOS_SPEW, "ACPI_PIRQ_GEN: %s: pin=%d pirq=%d\n", + dev_path(dev), int_pin, pirq); + + if (pirq == PIRQ_NONE) + continue; + + /* Avoid duplicate entries */ + if (prev_pci_dev == pci_dev && prev_int_pin == int_pin) { + continue; + } else { + prev_int_pin = int_pin; + prev_pci_dev = pci_dev; + } + if (emit != EMIT_NONE) { + acpigen_write_package(4); + acpigen_write_dword((pci_dev << 16) | 0xffff); + acpigen_write_dword(int_pin - PCI_INT_A); + if (emit == EMIT_APIC) { + acpigen_write_dword(0); + acpigen_write_dword(16 + (pirq - PIRQ_A)); + } else { + snprintf(buffer, sizeof(buffer), + "%s.LNK%c", + lpcb_path, 'A' + pirq - PIRQ_A); + acpigen_emit_namestring(buffer); + acpigen_write_dword(0); + } + acpigen_pop_len(); + } + num_devs++; + } + return num_devs; +} + +void intel_acpi_gen_def_acpi_pirq(device_t dev) +{ + const char *lpcb_path = acpi_device_path(dev); + const size_t num_devs = enumerate_root_pci_pins(EMIT_NONE, lpcb_path); + + if (!lpcb_path) + die("ACPI_PIRQ_GEN: Missing LPCB ACPI path\n"); + + acpigen_write_scope("\\_SB.PCI0"); + acpigen_write_method("_PRT", 0); + acpigen_write_if(); + acpigen_emit_namestring("PICM"); + acpigen_emit_byte(RETURN_OP); + acpigen_write_package(num_devs); + enumerate_root_pci_pins(EMIT_APIC, lpcb_path); + acpigen_pop_len(); /* package */ + acpigen_pop_len(); /* if PICM */ + acpigen_write_else(); + acpigen_emit_byte(RETURN_OP); + acpigen_write_package(num_devs); + enumerate_root_pci_pins(EMIT_PICM, lpcb_path); + acpigen_pop_len(); /* package */ + acpigen_pop_len(); /* else PICM */ + acpigen_pop_len(); /* _PRT */ + acpigen_pop_len(); /* \_SB */ +} diff --git a/src/southbridge/intel/common/acpi_pirq_gen.h b/src/southbridge/intel/common/acpi_pirq_gen.h new file mode 100644 index 0000000000..bd702da80d --- /dev/null +++ b/src/southbridge/intel/common/acpi_pirq_gen.h @@ -0,0 +1,42 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Arthur Heymans <arthur@aheymans.xyz> + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef INTEL_COMMON_ACPI_PIRQ_GEN_H +#define INTEL_COMMON_ACPI_PIRQ_GEN_H + +typedef enum pci_pin { + PCI_INT_NONE = 0, + PCI_INT_A, + PCI_INT_B, + PCI_INT_C, + PCI_INT_D, +} pci_pin_t; + +typedef enum pirq { + PIRQ_NONE = 0, + PIRQ_A, + PIRQ_B, + PIRQ_C, + PIRQ_D, + PIRQ_E, + PIRQ_F, + PIRQ_G, + PIRQ_H, +} pirq_t; + +void intel_acpi_gen_def_acpi_pirq(device_t dev); +enum pirq intel_common_map_pirq(const device_t dev, const pci_pin_t pci_pin); + +#endif diff --git a/src/southbridge/intel/common/rcba_pirq.c b/src/southbridge/intel/common/rcba_pirq.c new file mode 100644 index 0000000000..186115472f --- /dev/null +++ b/src/southbridge/intel/common/rcba_pirq.c @@ -0,0 +1,42 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <southbridge/intel/common/acpi_pirq_gen.h> +#include <southbridge/intel/common/rcba_pirq.h> + +#define MAX_SLOT 31 +#define MIN_SLOT 19 + +static const u32 pirq_dir_route_reg[MAX_SLOT - MIN_SLOT + 1] = { + D19IR, D20IR, D21IR, D22IR, D23IR, 0, D25IR, + D26IR, D27IR, D28IR, D29IR, D30IR, D31IR, +}; + +enum pirq intel_common_map_pirq(const device_t dev, const pci_pin_t pci_pin) +{ + u8 slot = PCI_SLOT(dev->path.pci.devfn); + u8 shift = 4 * (pci_pin - PCI_INT_A); + u8 pirq; + u16 reg; + + if (pci_pin < 1 || pci_pin > 4) { + printk(BIOS_ERR, "Slot %d PCI pin %d out of bounds\n", + slot, pci_pin); + return PIRQ_NONE; + } + + if (slot < MIN_SLOT || slot > MAX_SLOT) { + /* non-PCH devices use 1:1 mapping. */ + return pci_pin; + } + + reg = pirq_dir_route_reg[slot - MIN_SLOT]; + + pirq = ((RCBA16(reg) >> shift) & 0xf); + if (pirq > 8) { + printk(BIOS_ERR, "Reg 0x%04x PIRQ %c out of bounds\n", + reg, 'A' + pirq); + return PIRQ_NONE; + } + return PIRQ_A + pirq; +} diff --git a/src/southbridge/intel/common/rcba_pirq.h b/src/southbridge/intel/common/rcba_pirq.h new file mode 100644 index 0000000000..cf76fb32f5 --- /dev/null +++ b/src/southbridge/intel/common/rcba_pirq.h @@ -0,0 +1,44 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * Copyright (C) 2012 The Chromium OS Authors. All rights reserved. + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef SOUTHBRIDGE_INTEL_COMMON_RCBA_PIRQ_H +#define SOUTHBRIDGE_INTEL_COMMON_RCBA_PIRQ_H + +/* + * The DnnIR registers use common RCBA offsets across these chipsets: + * bd82x6x, i82801, i89xx, ibexpeak, lynxpoint + * + * However not all registers are in use on all of these. + */ + +#define D31IR 0x3140 /* 16bit */ +#define D30IR 0x3142 /* 16bit */ +#define D29IR 0x3144 /* 16bit */ +#define D28IR 0x3146 /* 16bit */ +#define D27IR 0x3148 /* 16bit */ +#define D26IR 0x314c /* 16bit */ +#define D25IR 0x3150 /* 16bit */ +#define D23IR 0x3158 /* 16bit */ +#define D22IR 0x315c /* 16bit */ +#define D21IR 0x3164 /* 16bit */ +#define D20IR 0x3160 /* 16bit */ +#define D19IR 0x3168 /* 16bit */ + +#define DEFAULT_RCBA 0xfed1c000 + +#define RCBA16(x) (*((volatile u16 *)(DEFAULT_RCBA + (x)))) + +#endif /* SOUTHBRIDGE_INTEL_COMMON_RCBA_PIRQ_H */ |