soc/intel/braswell: 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() - setup_i8259() - write_pci_config_irqs() to correct the configuration of interrupts. BUG=N/A TEST=Intel CherryHill CRB Change-Id: I128cb35dd0e348a9cd9fb162651e0aa2b7e4a3ef Signed-off-by: Frans Hendriks <fhendriks@eltan.com> Reviewed-on: https://review.coreboot.org/c/29419 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Michał Żygowski <michal.zygowski@3mdeb.com>
This commit is contained in:
parent
3e8504a325
commit
9348413c61
|
@ -155,6 +155,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
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <device/pci.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <pc80/i8254.h>
|
||||
#include <pc80/i8259.h>
|
||||
#include <romstage_handoff.h>
|
||||
#include <soc/acpi.h>
|
||||
#include <soc/iomap.h>
|
||||
|
@ -78,6 +79,112 @@ static void sc_add_mmio_resources(struct device *dev)
|
|||
#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)
|
||||
{
|
||||
struct device *irq_dev;
|
||||
struct device *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 PIRQ 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 */
|
||||
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 */
|
||||
i8259_configure_irq_trigger(int_line,
|
||||
IRQ_LEVEL_TRIGGERED);
|
||||
/* Set the Interrupt Line register */
|
||||
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 PIRQ assignments\n");
|
||||
}
|
||||
|
||||
static inline int io_range_in_default(int base, int size)
|
||||
{
|
||||
/* Does it start above the range? */
|
||||
|
@ -155,7 +262,6 @@ static void sc_init(struct device *dev)
|
|||
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;
|
||||
|
||||
|
@ -172,8 +278,13 @@ static void sc_init(struct device *dev)
|
|||
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);
|
||||
}
|
||||
|
||||
if (config->disable_slp_x_stretch_sus_fail) {
|
||||
printk(BIOS_DEBUG, "Disabling slp_x stretching.\n");
|
||||
|
@ -184,6 +295,12 @@ static void sc_init(struct device *dev)
|
|||
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();
|
||||
|
||||
/* Initialize i8254 timers */
|
||||
setup_i8254();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue