Frans Hendriks has uploaded this change for review.

View Change

src/soc/intel/braswell/southcluster.c: Correct configuration of interrupts

The level/edge mode of PIRQ is not configured and i8259 PIC not initialized.
Add calls to i8259_configure_irq_trigger(), write_pci_config_irqs() and
setup_i8259() to correct the configuration of interrupts.

BUG=N/A
TEST=Intel CherryHill CRB

Change-Id: I128cb35dd0e348a9cd9fb162651e0aa2b7e4a3ef
Signed-off-by: Frans Hendriks <fhendriks@eltan.com>
---
M src/soc/intel/braswell/include/soc/irq.h
M src/soc/intel/braswell/southcluster.c
2 files changed, 114 insertions(+), 3 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/19/29419/1
diff --git a/src/soc/intel/braswell/include/soc/irq.h b/src/soc/intel/braswell/include/soc/irq.h
index 4375c20..9a3c40d 100644
--- a/src/soc/intel/braswell/include/soc/irq.h
+++ b/src/soc/intel/braswell/include/soc/irq.h
@@ -154,6 +154,7 @@
#define PIRQ_PIC_IRQ12 0xc
#define PIRQ_PIC_IRQ14 0xe
#define PIRQ_PIC_IRQ15 0xf
+#define PIRQ_PIC_UNKNOWN_UNUSED 0xff

/* Overloaded term, but these values determine the per device route. */
#define PIRQA 0
diff --git a/src/soc/intel/braswell/southcluster.c b/src/soc/intel/braswell/southcluster.c
index ca87d63..537d66d 100644
--- a/src/soc/intel/braswell/southcluster.c
+++ b/src/soc/intel/braswell/southcluster.c
@@ -26,6 +26,7 @@
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
+#include <pc80/i8259.h>
#include <pc80/mc146818rtc.h>
#include <romstage_handoff.h>
#include <soc/acpi.h>
@@ -78,6 +79,105 @@
#define LPC_DEFAULT_IO_RANGE_LOWER 0
#define LPC_DEFAULT_IO_RANGE_UPPER 0x1000

+/*
+ * Write PCI config space IRQ assignments. PCI devices have the INT_LINE
+ * (0x3C) and INT_PIN (0x3D) registers which report interrupt routing
+ * information to operating systems and drivers. The INT_PIN register is
+ * generally read only and reports which interrupt pin A - D it uses. The
+ * INT_LINE register is configurable and reports which IRQ (generally the
+ * PIC IRQs 1 - 15) it will use. This needs to take interrupt pin swizzling
+ * on devices that are downstream on a PCI bridge into account.
+ *
+ * This function will loop through all enabled PCI devices and program the
+ * INT_LINE register with the correct PIC IRQ number for the INT_PIN that it
+ * uses. It then configures each interrupt in the pic to be level triggered.
+ */
+static void write_pci_config_irqs(void)
+{
+ device_t irq_dev;
+ device_t targ_dev;
+ uint8_t int_line = 0;
+ uint8_t original_int_pin = 0;
+ uint8_t new_int_pin = 0;
+ uint16_t current_bdf = 0;
+ uint16_t parent_bdf = 0;
+ uint8_t pirq = 0;
+ uint8_t device_num = 0;
+ const struct soc_irq_route *ir = &global_soc_irq_route;
+
+ if (ir == NULL) {
+ printk(BIOS_WARNING, "Warning: Can't write PCI IRQ assignments because"
+ " 'global_braswell_irq_route' structure does not exist\n");
+ return;
+ }
+
+ /*
+ * Loop through all enabled devices and program their
+ * INT_LINE, INT_PIN registers from values taken from
+ * the Interrupt Route registers in the ILB
+ */
+ printk(BIOS_DEBUG, "PCI_CFG IRQ: Write PCI config space IRQ assignments\n");
+ for(irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
+
+ if ((irq_dev->path.type != DEVICE_PATH_PCI) ||
+ (!irq_dev->enabled))
+ continue;
+
+ current_bdf = irq_dev->path.pci.devfn |
+ irq_dev->bus->secondary << 8;
+
+ /*
+ * Step 1: Get the INT_PIN and device structure to look for
+ * in the pirq_data table defined in the mainboard directory.
+ */
+ targ_dev = NULL;
+ new_int_pin = get_pci_irq_pins(irq_dev, &targ_dev);
+ if (targ_dev == NULL || new_int_pin < 1)
+ continue;
+
+ /* Get the original INT_PIN for record keeping */
+ original_int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
+
+ parent_bdf = targ_dev->path.pci.devfn
+ | targ_dev->bus->secondary << 8;
+ device_num = PCI_SLOT(parent_bdf);
+
+ if (ir->pcidev[device_num] == 0) {
+ printk(BIOS_WARNING,
+ "Warning: PCI Device %d does not have an IRQ entry, skipping it\n",
+ device_num);
+ continue;
+ }
+
+ /* Find the PIRQ that is attached to the INT_PIN this device uses */
+ pirq = (ir->pcidev[device_num] >> ((new_int_pin - 1) * 4)) & 0x7;
+
+ /* Get the INT_LINE this device/function will use */
+ int_line = ir->pic[pirq];
+
+ if (int_line != PIRQ_PIC_IRQDISABLE) {
+ /* Set this IRQ to level triggered since it is used by a PCI device */
+ i8259_configure_irq_trigger(int_line, IRQ_LEVEL_TRIGGERED);
+ /* Set the Interrupt Line register in PCI config space */
+ pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
+ } else {
+ /* Set the Interrupt line register as "unknown or unused" */
+ pci_write_config8(irq_dev, PCI_INTERRUPT_LINE,
+ PIRQ_PIC_UNKNOWN_UNUSED);
+ }
+
+ printk(BIOS_SPEW, "\tINT_PIN\t\t: %d (%s)\n",
+ original_int_pin, pin_to_str(original_int_pin));
+ if (parent_bdf != current_bdf)
+ printk(BIOS_SPEW, "\tSwizzled to\t: %d (%s)\n",
+ new_int_pin, pin_to_str(new_int_pin));
+ printk(BIOS_SPEW, "\tPIRQ\t\t: %c\n"
+ "\tINT_LINE\t: 0x%X (IRQ %d)\n",
+ 'A' + pirq, int_line, int_line);
+ }
+ printk(BIOS_DEBUG, "PCI_CFG IRQ: Finished writing PCI config space IRQ assignments\n");
+}
+
static inline int io_range_in_default(int base, int size)
{
/* Does it start above the range? */
@@ -161,7 +261,6 @@
const unsigned long pr_base = ILB_BASE_ADDRESS + 0x08;
const unsigned long ir_base = ILB_BASE_ADDRESS + 0x20;
void *gen_pmcon1 = (void *)(PMC_BASE_ADDRESS + GEN_PMCON1);
- void *actl = (void *)(ILB_BASE_ADDRESS + ACTL);
const struct soc_irq_route *ir = &global_soc_irq_route;
struct soc_intel_braswell_config *config = dev->chip_info;

@@ -178,8 +277,14 @@
write16((void *)(ir_base + i*sizeof(ir->pcidev[i])),
ir->pcidev[i]);

- /* Route SCI to IRQ9 */
- write32(actl, (read32(actl) & ~SCIS_MASK) | SCIS_IRQ9);
+ /* Interrupt 9 should be level triggered (SCI) */
+ i8259_configure_irq_trigger(9, 1);
+
+ for (i = 0; i < NUM_PIRQS; i++) {
+ if ( ir->pic[i] ) {
+ i8259_configure_irq_trigger(ir->pic[i], 1);
+ }
+ }

sc_rtc_init();

@@ -192,6 +297,11 @@
read32(gen_pmcon1) & ~DIS_SLP_X_STRCH_SUS_UP);
}

+ /* Write IRQ assignments to PCI config space */
+ write_pci_config_irqs();
+
+ /* Initialize i8259 pic */
+ setup_i8259();
}

/*

To view, visit change 29419. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I128cb35dd0e348a9cd9fb162651e0aa2b7e4a3ef
Gerrit-Change-Number: 29419
Gerrit-PatchSet: 1
Gerrit-Owner: Frans Hendriks <fhendriks@eltan.com>