diff options
author | Tobias Diedrich <ranma+coreboot@tdiedrich.de> | 2017-12-13 23:25:32 +0100 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2017-12-20 16:48:05 +0000 |
commit | 9d8be5a857dfcd10449fad58c514f7a95e4a7cb8 (patch) | |
tree | cf39d59530133b343625b21984e10c0d9b1f7252 /src/southbridge/intel/common | |
parent | fd305156cda099ae99b7077c87ef1dc8b33d255d (diff) |
sb/intel/common: Automatically generate ACPI PIRQ
Based on change I2b5d68adabf0840162c6f295af8d10d8d3007a34
(sb/intel/common: Add function to automatically generate ACPI PIRQ).
This adds functionality to generate PIRQ ACPI tables automatically based
on the chipset registers.
Mapping of PCI interrupt pin to PIRQ is done by the chipset-specific
intel_common_map_pirq() function, an shared implementation of which is
provided for the bd82x6x, i82801, i89xx, ibexpeak and lynxpoint
chipsets.
Example generated _PRT:
Scope (\_SB.PCI0)
{
Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table
{
If (PICM)
{
Return (Package (0x09)
{
Package (0x04)
{
0x0002FFFF,
0x00000000,
0x00000000,
0x00000010
},
Package (0x04)
{
0x001BFFFF,
0x00000000,
0x00000000,
0x00000010
},
Package (0x04)
{
0x001CFFFF,
0x00000000,
0x00000000,
0x00000011
},
Package (0x04)
{
0x001CFFFF,
0x00000001,
0x00000000,
0x00000015
},
Package (0x04)
{
0x001CFFFF,
0x00000002,
0x00000000,
0x00000013
},
Package (0x04)
{
0x001DFFFF,
0x00000000,
0x00000000,
0x00000013
},
Package (0x04)
{
0x001FFFFF,
0x00000000,
0x00000000,
0x00000011
},
Package (0x04)
{
0x001FFFFF,
0x00000001,
0x00000000,
0x00000017
},
Package (0x04)
{
0x0004FFFF,
0x00000000,
0x00000000,
0x00000010
}
})
}
Else
{
Return (Package (0x09)
{
Package (0x04)
{
0x0002FFFF,
0x00000000,
\_SB.PCI0.LPCB.LNKA,
0x00000000
},
Package (0x04)
{
0x001BFFFF,
0x00000000,
\_SB.PCI0.LPCB.LNKA,
0x00000000
},
Package (0x04)
{
0x001CFFFF,
0x00000000,
\_SB.PCI0.LPCB.LNKB,
0x00000000
},
Package (0x04)
{
0x001CFFFF,
0x00000001,
\_SB.PCI0.LPCB.LNKF,
0x00000000
},
Package (0x04)
{
0x001CFFFF,
0x00000002,
\_SB.PCI0.LPCB.LNKD,
0x00000000
},
Package (0x04)
{
0x001DFFFF,
0x00000000,
\_SB.PCI0.LPCB.LNKD,
0x00000000
},
Package (0x04)
{
0x001FFFFF,
0x00000000,
\_SB.PCI0.LPCB.LNKB,
0x00000000
},
Package (0x04)
{
0x001FFFFF,
0x00000001,
\_SB.PCI0.LPCB.LNKH,
0x00000000
},
Package (0x04)
{
0x0004FFFF,
0x00000000,
\_SB.PCI0.LPCB.LNKA,
0x00000000
}
})
}
}
}
Change-Id: Ic6b8ce4a9db50211a9c26221ca10105c5a0829a0
Signed-off-by: Tobias Diedrich <ranma+coreboot@tdiedrich.de>
Reviewed-on: https://review.coreboot.org/22810
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Diffstat (limited to 'src/southbridge/intel/common')
-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 */ |