Frans Hendriks has uploaded this change for review. ( https://review.coreboot.org/29419
Change subject: src/soc/intel/braswell/southcluster.c: Correct configuration of interrupts ......................................................................
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(); }
/*