summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/southbridge/intel/common/Kconfig7
-rw-r--r--src/southbridge/intel/common/Makefile.inc3
-rw-r--r--src/southbridge/intel/common/acpi_pirq_gen.c115
-rw-r--r--src/southbridge/intel/common/acpi_pirq_gen.h42
-rw-r--r--src/southbridge/intel/common/rcba_pirq.c42
-rw-r--r--src/southbridge/intel/common/rcba_pirq.h44
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 */