[coreboot-gerrit] Change in coreboot[master]: src/soc/intel/braswell/southcluster.c: Correct configuration of inter...

Frans Hendriks (Code Review) gerrit at coreboot.org
Thu Nov 1 11:38:26 CET 2018


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 at 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 https://review.coreboot.org/29419
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/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 at eltan.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20181101/47f1c939/attachment.html>


More information about the coreboot-gerrit mailing list