[coreboot-gerrit] New patch to review for coreboot: 3325bdf CIMx: Set up the PCI IRQ routing

Mike Loptien (mike.loptien@se-eng.com) gerrit at coreboot.org
Tue May 27 22:58:03 CEST 2014


Mike Loptien (mike.loptien at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5877

-gerrit

commit 3325bdf5e64a3f95da2961a074999736a31edb2a
Author: Mike Loptien <mike.loptien at se-eng.com>
Date:   Mon Jan 20 17:57:39 2014 -0700

    CIMx: Set up the PCI IRQ routing
    
    The PCI_INTR table is an Index/Data pair of I/O ports
    0xC00 and 0xC01.  This table is responsible for physically
    routing IRQs to the PIC and IOAPIC.  The settings given
    in this table are chipset and mainboard dependent, so the
    table values will reside in the mainboard.c file. This
    allows for a system to uniquely set its IRQ routing.
    The function to write the PCI_INTR table resides in
    cimx_util.c because the indices into the table have
    the same definitions for all SBx00 FCH chipsets.
    
    The next piece is a function that will read the PCI_INTR
    table and program the INT_LINE and INT_PIN registers in
    PCI config space appropriately.  This function will read
    a devices' INT_PIN register, which is always hardcoded to
    a value if it uses hardware interrupts.  It then uses this
    value, along with the device and function numbers to
    determine an index into the PCI_INTR table.  It will read
    the table and program the corresponding value into the PCI
    config space register 0x3C, INT_LINE.  Finally, it will set
    this IRQ number to LEVEL_TRIGGERED on the PIC because it is
    a PCI device interrupt and the must be level triggered.
    
    For example, the SB800 USB EHCI device 0:18.2 has an INT_PIN
    value hardcoded to 2.  This corresponds to PIN B.  On the
    Persimmon mainboard, I want the USB device to use IRQ 11.  I
    will program the PCI_INTR table at index 0x31 (this USB device
    index) to 11.  This function will then read the INT_PIN register,
    read the PCI_INTR table, and then program the INT_LINE register
    with the value it read.  It will then set the IRQ on the PIC to
    LEVEL_TRIGGERED by writing a 1 to I/O port 0x4D1 at bit position 4.
    
    Also, the SB700 has slightly different register definitions than
    the newer SB800 and SB900 so it needs its own set of #defines for
    the pci_intr registers.
    
    Change-Id: I6de858289a17fa1e1abacf6328ea5099be74b1d6
    Signed-off-by: Mike Loptien <mike.loptien at se-eng.com>
    Reviewed-on: http://gerrit/3027
    Reviewed-by: Marc Jones <marc.jones at se-eng.com>
    Tested-by: Automated Builds <automated.builds at se-eng.com>
---
 src/include/pc80/i8259.h                      |  67 +++++++++-
 src/mainboard/amd/persimmon/mainboard.c       |  93 +++++++++++++-
 src/mainboard/amd/persimmon/mptable.c         | 149 +++++++++++-----------
 src/northbridge/amd/agesa/family14/pci_devs.h |  55 ++++++++
 src/southbridge/amd/cimx/cimx_util.c          | 173 ++++++++++++++++++++++++++
 src/southbridge/amd/cimx/cimx_util.h          | 111 ++++++++++++++++-
 src/southbridge/amd/cimx/sb800/late.c         |  68 ++++++----
 src/southbridge/amd/cimx/sb800/pci_devs.h     | 106 ++++++++++++++++
 8 files changed, 720 insertions(+), 102 deletions(-)

diff --git a/src/include/pc80/i8259.h b/src/include/pc80/i8259.h
index 7e99e4b..5a32b29 100644
--- a/src/include/pc80/i8259.h
+++ b/src/include/pc80/i8259.h
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2007-2009 coresystems GmbH
+ * Copyright (C) 2013 Sage Electronic Engineering, LLC.
  *
  * 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
@@ -20,10 +21,74 @@
 #ifndef PC80_I8259_H
 #define PC80_I8259_H
 
-void setup_i8259(void);
+/*
+ * IRQ numbers and common usage
+ * If an IRQ does not say it is 'Reserved'
+ * then it can be used by a device.
+ */
+/* PIC IRQs */
+#define IRQ_DIS		0x1F	/* IRQ is disabled */
+#define IRQ_0		0x00	/* Reserved - Timer IRQ */
+#define IRQ_1		0x01	/* Keyboard controller */
+#define IRQ_2		0x02	/* Reserved - Cascade to Slave PIC */
+#define IRQ_3		0x03	/* Serial Port 2 & 4 */
+#define IRQ_4		0x04	/* Serial Port 1 & 3 */
+#define IRQ_5		0x05	/* Parallel Port 2 & 3 or Sound Card */
+#define IRQ_6		0x06	/* Floppy Disk Controller */
+#define IRQ_7		0x07	/* Parallel Port 1 */
+#define IRQ_8		0x08	/* Reserved - RTC */
+#define IRQ_9		0x09	/* Reserved - ACPI System Control Interrupt */
+#define IRQ_10		0x0A	/* Free or SCSI or NIC */
+#define IRQ_11		0x0B	/* Free or SCSI or NIC */
+#define IRQ_12		0x0C	/* PS/2 Mouse */
+#define IRQ_13		0x0D	/* Reserved - CPU Floating Point Unit */
+#define IRQ_14		0x0E	/* Primary ATA */
+#define IRQ_15		0x0F	/* Secondary ATA */
+#define IRQ_RES		((1 << IRQ_0) | (1 << IRQ_1) | (1 << IRQ_2) \
+					| (1 << IRQ_8) | (1 << IRQ_9) | (1 << IRQ_13))
+
+#define MASTER_PIC_ICW1		0x20
+#define SLAVE_PIC_ICW1		0xa0
+#define   ICW_SELECT		(1 << 4)
+#define   OCW_SELECT		(0 << 4)
+#define   ADI			(1 << 2)
+#define   SNGL			(1 << 1)
+#define   IC4			(1 << 0)
+
+#define MASTER_PIC_ICW2		0x21
+#define SLAVE_PIC_ICW2		0xa1
+#define   INT_VECTOR_MASTER	0x20
+#define   IRQ0			0x00
+#define   IRQ1			0x01
+#define   INT_VECTOR_SLAVE	0x28
+#define   IRQ8			0x00
+#define   IRQ9			0x01
+
+#define MASTER_PIC_ICW3		0x21
+#define   CASCADED_PIC		(1 << 2)
+
+#define MASTER_PIC_ICW4		0x21
+#define SLAVE_PIC_ICW4		0xa1
+#define   MICROPROCESSOR_MODE	(1 << 0)
+
+#define SLAVE_PIC_ICW3		0xa1
+#define    SLAVE_ID		0x02
+
+#define MASTER_PIC_OCW1 	0x21
+#define SLAVE_PIC_OCW1		0xa1
+#define    IRQ2			(1 << 2)
+#define    ALL_IRQS		0xff
+
+#define ELCR1			0x4d0
+#define ELCR2			0x4d1
 
 #define IRQ_LEVEL_TRIGGERED	1
 #define IRQ_EDGE_TRIGGERED	0
+
+u16 pic_read_irq_mask(void);
+void pic_write_irq_mask(u16 mask);
+void pic_irq_enable(u8 int_num, u8 mask);
+void setup_i8259(void);
 void i8259_configure_irq_trigger(int int_num, int is_level_triggered);
 
 #endif /* PC80_I8259_H */
diff --git a/src/mainboard/amd/persimmon/mainboard.c b/src/mainboard/amd/persimmon/mainboard.c
index b17bc6a..566eb84 100644
--- a/src/mainboard/amd/persimmon/mainboard.c
+++ b/src/mainboard/amd/persimmon/mainboard.c
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2011 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013 Sage Electronic Engineering, LLC.
  *
  * 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
@@ -23,16 +24,101 @@
 #include <arch/io.h>
 #include <cpu/x86/msr.h>
 #include <device/pci_def.h>
-#include <southbridge/amd/sb800/sb800.h>
+#include <southbridge/amd/cimx/cimx_util.h>
 #include <arch/acpi.h>
 #include "BiosCallOuts.h"
 #include <cpu/amd/agesa/s3_resume.h>
 #include <cpu/amd/mtrr.h>
 #include "SBPLATFORM.h"
+#include <southbridge/amd/cimx/sb800/pci_devs.h>
+#include <northbridge/amd/agesa/family14/pci_devs.h>
 
 void set_pcie_reset(void);
 void set_pcie_dereset(void);
 
+/***********************************************************
+ * These arrays set up the FCH PCI_INTR registers 0xC00/0xC01.
+ * This table is responsible for physically routing the PIC and
+ * IOAPIC IRQs to the different PCI devices on the system.  It
+ * is read and written via registers 0xC00/0xC01 as an
+ * Index/Data pair.  These values are chipset and mainboard
+ * dependent and should be updated accordingly.
+ *
+ * These values are used by the PCI configuration space,
+ * MP Tables.  TODO: Make ACPI use these values too.
+ *
+ * The Persimmon PCI INTA/B/C/D pins are connected to
+ * FCH pins INTE/F/G/H on the schematic so these need
+ * to be routed as well.
+ */
+u8 mainboard_picr_data[FCH_INT_TABLE_SIZE] = {
+	[0x00] = 0x0A,0x0B,0x0A,0x0B,0x0A,0x0B,0x0A,0x0B,	/* INTA# - INTH# */
+	[0x08] = 0x00,0xF0,0x00,0x00,0x1F,0x1F,0x1F,0x1F,	/* Misc-nil,0,1,2, INT from Serial irq */
+	[0x10] = 0x1F,0x1F,0x1F,0x0A,0x1F,0x1F,0x1F,		/* SCI, SMBUS0, ASF, HDA, FC, GEC, PerMon */
+	[0x20] = 0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,				/* IMC INT0 - 5 */
+	[0x30] = 0x0A,0x0B,0x0A,0x0B,0x1F,0x1F,0x0A,		/* USB Devs 18/19/20/22 INTA-C */
+	[0x40] = 0x0B,0x0B,									/* IDE, SATA */
+	[0x50] = 0x0A,0x0B,0x0A,0x0B						/* GPPInt0 - 3 */
+};
+
+u8 mainboard_intr_data[FCH_INT_TABLE_SIZE] = {
+	[0x00] = 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,	/* INTA# - INTH# */
+	[0x08] = 0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F,	/* Misc-nil,0,1,2, INT from Serial irq */
+	[0x10] = 0x09,0x1F,0x1F,0x10,0x1F,0x12,0x1F,		/* SCI, SMBUS0, ASF, HDA, FC, GEC, PerMon */
+	[0x20] = 0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,				/* IMC INT0 - 5 */
+	[0x30] = 0x12,0x11,0x12,0x11,0x12,0x11,0x12,		/* USB Devs 18/19/22/20 INTA-C */
+	[0x40] = 0x11,0x13,									/* IDE, SATA */
+	[0x50] = 0x10,0x11,0x12,0x13						/* GPPInt0 - 3 */
+};
+
+/*
+ * This table defines the index into the picr/intr_data
+ * tables for each device.  Any enabled device and slot
+ * that uses hardware interrupts should have an entry
+ * in this table to define its index into the FCH
+ * PCI_INTR register 0xC00/0xC01.  This index will define
+ * the interrupt that it should use.  Putting PIRQ_A into
+ * the PIN A index for a device will tell that device to
+ * use PIC IRQ 11 if it uses PIN A for its hardware INT.
+ */
+/*
+ * Persimmon has PCI/PCIe slot INT_PINA/B/C/D connected to
+ * PIRQE/F/G/H so PIN A on off-chip devices should get
+ * mapped to PIRQE, etc.
+ */
+static const struct pirq_struct mainboard_pirq_data[] = {
+	/* {PCI dev, fn		PCI INT {PIN A, PIN B, PIN C, PIN D}}, */
+	{GFX_DEVFN, {PIRQ_A, PIRQ_B, PIRQ_NC, PIRQ_NC}},			/* VGA:		01.0 */
+	{NB_PCIE_PORT1_DEVFN, {PIRQ_E, PIRQ_F, PIRQ_G, PIRQ_H}},	/* NIC:		04.0 */
+	{NB_PCIE_PORT3_DEVFN, {PIRQ_E, PIRQ_F, PIRQ_G, PIRQ_H}},	/* PCIe bdg:06.0 */
+	{SATA_DEVFN, {PIRQ_SATA, PIRQ_NC, PIRQ_NC, PIRQ_NC}},		/* SATA:	11.0 */
+	{OHCI1_DEVFN, {PIRQ_OHCI1, PIRQ_NC, PIRQ_NC, PIRQ_NC}},		/* OHCI1:	18.0 */
+	{EHCI1_DEVFN, {PIRQ_NC, PIRQ_EHCI1, PIRQ_NC, PIRQ_NC}},		/* EHCI1:	18.2 */
+	{OHCI2_DEVFN, {PIRQ_OHCI2, PIRQ_NC, PIRQ_NC, PIRQ_NC}},		/* OHCI2:	19.0 */
+	{EHCI2_DEVFN, {PIRQ_NC, PIRQ_EHCI2, PIRQ_NC, PIRQ_NC}},		/* EHCI2:	19.2 */
+	{SMBUS_DEVFN, {PIRQ_SMBUS, PIRQ_NC, PIRQ_NC, PIRQ_NC}},		/* SMBUS:	20.0 */
+	{IDE_DEVFN, {PIRQ_NC, PIRQ_IDE, PIRQ_NC, PIRQ_NC}},			/* IDE:		20.1 */
+	{HDA_DEVFN, {PIRQ_HDA, PIRQ_NC, PIRQ_NC, PIRQ_NC}},			/* HDA:		20.2 */
+	{SB_PCI_PORT_DEVFN, {PIRQ_E, PIRQ_F, PIRQ_G, PIRQ_H}},		/* PCI bdg:	20.4 */
+	{OHCI4_DEVFN, {PIRQ_NC, PIRQ_NC, PIRQ_OHCI4, PIRQ_NC}},		/* OHCI4:	20.5 */
+	{OHCI3_DEVFN, {PIRQ_OHCI3, PIRQ_NC, PIRQ_NC, PIRQ_NC}},		/* OHCI3:	22.0 */
+	{EHCI3_DEVFN, {PIRQ_NC, PIRQ_EHCI3, PIRQ_NC, PIRQ_NC}},		/* EHCI3:	22.2 */
+	{0xFF, {0xFF, 0xFF, 0xFF, 0xFF}},	/* End of the array */
+};
+
+/* PIRQ Setup */
+
+extern const struct pirq_struct * pirq_data_ptr;
+extern u8 * intr_data_ptr;
+extern u8 * picr_data_ptr;
+
+static void pirq_setup(void)
+{
+	pirq_data_ptr = mainboard_pirq_data;
+	intr_data_ptr = mainboard_intr_data;
+	picr_data_ptr = mainboard_picr_data;
+}
+
 /**
  * TODO
  * SB CIMx callback
@@ -59,7 +145,7 @@ static void mainboard_enable(device_t dev)
 
 /*
  * The mainboard is the first place that we get control in ramstage. Check
- * for S3 resume and call the approriate AGESA/CIMx resume functions.
+ * for S3 resume and call the appropriate AGESA/CIMx resume functions.
  */
 #if CONFIG_HAVE_ACPI_RESUME
 	acpi_slp_type = acpi_get_sleep_type();
@@ -82,6 +168,9 @@ static void mainboard_enable(device_t dev)
 	 */
 	pm_iowrite(0x29, 0x80);
 	pm_iowrite(0x28, 0x61);
+
+	/* Initialize the PIRQ data structures for consumption */
+	pirq_setup();
 }
 
 struct chip_operations mainboard_ops = {
diff --git a/src/mainboard/amd/persimmon/mptable.c b/src/mainboard/amd/persimmon/mptable.c
index 6b8aaa6..aacf50a 100644
--- a/src/mainboard/amd/persimmon/mptable.c
+++ b/src/mainboard/amd/persimmon/mptable.c
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2011 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013 Sage Electronic Engineering, LLC.
  *
  * 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
@@ -26,124 +27,122 @@
 #include <stdint.h>
 #include <cpu/amd/amdfam14.h>
 #include <SBPLATFORM.h>
+#include <southbridge/amd/cimx/cimx_util.h>
+#include <drivers/generic/ioapic/chip.h>
 
+#define IO_APIC_ID    (CONFIG_MAX_CPUS + 1)
 extern u8 bus_sb800[6];
-
 extern u32 apicid_sb800;
+extern u8 * intr_data_ptr;
 
 extern u32 bus_type[256];
 extern u32 sbdn_sb800;
 
-u8 intr_data[] = {
-	[0x00] = 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, /* INTA# - INTH# */
-	[0x08] = 0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F, /* Misc-nil,0,1,2, INT from Serial irq */
-	[0x10] = 0x09,0x1F,0x1F,0x10,0x1F,0x12,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-	0x12,0x11,0x12,0x11,0x12,0x11,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-	0x11,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-	0x10,0x11,0x12,0x13
-};
-
 static void *smp_write_config_table(void *v)
 {
 	struct mp_config_table *mc;
 	int bus_isa;
-
+	u32 dword;
+	/* Intialize the MP_Table */
 	mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN);
 
 	mptable_init(mc, LOCAL_APIC_ADDR);
-	memcpy(mc->mpc_oem, "AMD	 ", 8);
 
+	/*
+	 * Type 0: Processor Entries:
+	 * LAPIC ID, LAPIC Version, CPU Flags:EN/BP,
+	 * CPU Signature (Stepping, Model, Family),
+	 * Feature Flags
+	 */
 	smp_write_processors(mc);
 
+	/* Get Bus Configuration */
 	get_bus_conf();
 
+	/*
+	 * Type 1: Bus Entries:
+	 * Bus ID, Bus Type
+	 */
 	mptable_write_buses(mc, NULL, &bus_isa);
 
-	/* I/O APICs:	 APIC ID Version State	 Address */
-
-	u32 dword;
-	u8 byte;
-
-	ReadPMIO(SB_PMIOA_REG34, AccWidthUint32, &dword);
-	dword &= 0xFFFFFFF0;
+	/*
+	 * Type 2: I/O APICs:
+	 * APIC ID, Version, APIC Flags:EN, Address
+	 */
+	dword = 0;
+	dword = pm_ioread(0x34) & 0xF0;
+	dword |= (pm_ioread(0x35) & 0xFF) << 8;
+	dword |= (pm_ioread(0x36) & 0xFF) << 16;
+	dword |= (pm_ioread(0x37) & 0xFF) << 24;
+	/* Set IO APIC ID onto IO_APIC_ID */
+	write32 (dword, 0x00);
+	write32 (dword + 0x10, IO_APIC_ID << 24);
+	apicid_sb800 = IO_APIC_ID;
 	smp_write_ioapic(mc, apicid_sb800, 0x21, dword);
 
-	for (byte = 0x0; byte < sizeof(intr_data); byte ++) {
-	outb(byte | 0x80, 0xC00);
-	outb(intr_data[byte], 0xC01);
-	}
-
-	/* I/O Ints:	Type	Polarity	Trigger	 Bus ID	 IRQ	APIC ID PIN# */
-#define IO_LOCAL_INT(type, intr, apicid, pin) \
-	smp_write_lintsrc(mc, (type), MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, bus_isa, (intr), (apicid), (pin));
-
+	/*
+	 * Type 3: I/O Interrupt Table Entries:
+	 * Int Type, Int Polarity, Int Level, Source Bus ID,
+	 * Source Bus IRQ, Dest APIC ID, Dest PIN#
+	 */
 	mptable_add_isa_interrupts(mc, bus_isa, apicid_sb800, 0);
 
 	/* PCI interrupts are level triggered, and are
 	 * associated with a specific bus/device/function tuple.
 	 */
-#if !CONFIG_GENERATE_ACPI_TABLES
 #define PCI_INT(bus, dev, fn, pin) \
 		smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb800, (pin))
-#else
-#define PCI_INT(bus, dev, fn, pin)
-#endif
 
-	/* APU Internal Graphic Device*/
-	PCI_INT(0x0, 0x01, 0x0, intr_data[0x02]);
-	PCI_INT(0x0, 0x01, 0x1, intr_data[0x03]);
+	/* APU Internal Graphic Device */
+	PCI_INT(0x0, 0x01, 0x0, intr_data_ptr[PIRQ_C]);
+	PCI_INT(0x0, 0x01, 0x1, intr_data_ptr[PIRQ_D]);
+
+	/* SMBUS / ACPI */
+	PCI_INT(0x0, 0x14, 0x0, intr_data_ptr[PIRQ_SMBUS]);
 
-	//PCI_INT(0x0, 0x14, 0x1, 0x11); /* IDE. */
-	PCI_INT(0x0, 0x14, 0x0, 0x10);
-	/* Southbridge HD Audio: */
-	PCI_INT(0x0, 0x14, 0x2, 0x12);
+	/* Southbridge HD Audio */
+	PCI_INT(0x0, 0x14, 0x2, intr_data_ptr[PIRQ_HDA]);
 
-	PCI_INT(0x0, 0x12, 0x0, intr_data[0x30]); /* USB */
-	PCI_INT(0x0, 0x12, 0x1, intr_data[0x31]);
-	PCI_INT(0x0, 0x13, 0x0, intr_data[0x32]);
-	PCI_INT(0x0, 0x13, 0x1, intr_data[0x33]);
-	PCI_INT(0x0, 0x16, 0x0, intr_data[0x34]);
-	PCI_INT(0x0, 0x16, 0x1, intr_data[0x35]);
+	/* LPC */
+	PCI_INT(0x0, 0x14, 0x3, intr_data_ptr[PIRQ_C]);
 
-	/* sata */
-	PCI_INT(0x0, 0x11, 0x0, intr_data[0x41]);
+	/* USB */
+	PCI_INT(0x0, 0x12, 0x0, intr_data_ptr[PIRQ_OHCI1]);
+	PCI_INT(0x0, 0x12, 0x2, intr_data_ptr[PIRQ_EHCI1]);
+	PCI_INT(0x0, 0x13, 0x0, intr_data_ptr[PIRQ_OHCI2]);
+	PCI_INT(0x0, 0x13, 0x2, intr_data_ptr[PIRQ_EHCI2]);
+	PCI_INT(0x0, 0x14, 0x5, intr_data_ptr[PIRQ_OHCI4]);
 
-	/* on board NIC & Slot PCIE.	*/
+	 /* IDE */
+	PCI_INT(0x0, 0x14, 0x1, intr_data_ptr[PIRQ_IDE]);
+
+	/* SATA */
+	PCI_INT(0x0, 0x11, 0x0, intr_data_ptr[PIRQ_SATA]);
+
+	/* on board NIC & Slot PCIE */
+	PCI_INT(0x1, 0x0, 0x0, intr_data_ptr[PIRQ_E]);	/* Use INTE */
+	PCI_INT(0x2, 0x0, 0x0, intr_data_ptr[PIRQ_E]);	/* Use INTE */
 
 	/* PCI slots */
-	/* PCI_SLOT 0. */
-	PCI_INT(bus_sb800[1], 0x5, 0x0, 0x14);
-	PCI_INT(bus_sb800[1], 0x5, 0x1, 0x15);
-	PCI_INT(bus_sb800[1], 0x5, 0x2, 0x16);
-	PCI_INT(bus_sb800[1], 0x5, 0x3, 0x17);
-
-	/* PCI_SLOT 1. */
-	PCI_INT(bus_sb800[1], 0x6, 0x0, 0x15);
-	PCI_INT(bus_sb800[1], 0x6, 0x1, 0x16);
-	PCI_INT(bus_sb800[1], 0x6, 0x2, 0x17);
-	PCI_INT(bus_sb800[1], 0x6, 0x3, 0x14);
-
-	/* PCI_SLOT 2. */
-	PCI_INT(bus_sb800[1], 0x7, 0x0, 0x16);
-	PCI_INT(bus_sb800[1], 0x7, 0x1, 0x17);
-	PCI_INT(bus_sb800[1], 0x7, 0x2, 0x14);
-	PCI_INT(bus_sb800[1], 0x7, 0x3, 0x15);
-
-	PCI_INT(bus_sb800[2], 0x0, 0x0, 0x12);
-	PCI_INT(bus_sb800[2], 0x0, 0x1, 0x13);
-	PCI_INT(bus_sb800[2], 0x0, 0x2, 0x14);
+	/* PCI_SLOT 0 */
+	PCI_INT(bus_sb800[1], 0x5, 0x0, intr_data_ptr[PIRQ_E]);	/* INTA -> INTE */
+	PCI_INT(bus_sb800[1], 0x5, 0x1, intr_data_ptr[PIRQ_F]);	/* INTB -> INTF */
+	PCI_INT(bus_sb800[1], 0x5, 0x2, intr_data_ptr[PIRQ_G]);	/* INTC -> INTG */
+	PCI_INT(bus_sb800[1], 0x5, 0x3, intr_data_ptr[PIRQ_H]);	/* INTD -> INTH */
 
 	/* PCIe PortA */
-	PCI_INT(0x0, 0x15, 0x0, 0x10);
+	PCI_INT(0x0, 0x15, 0x0, intr_data_ptr[PIRQ_E]);	/* INTA -> INTE */
 	/* PCIe PortB */
-	PCI_INT(0x0, 0x15, 0x1, 0x11);
+	PCI_INT(0x0, 0x15, 0x1, intr_data_ptr[PIRQ_F]);	/* INTB -> INTF */
 	/* PCIe PortC */
-	PCI_INT(0x0, 0x15, 0x2, 0x12);
+	PCI_INT(0x0, 0x15, 0x2, intr_data_ptr[PIRQ_G]);	/* INTC -> INTG */
 	/* PCIe PortD */
-	PCI_INT(0x0, 0x15, 0x3, 0x13);
+	PCI_INT(0x0, 0x15, 0x3, intr_data_ptr[PIRQ_H]);	/* INTD -> INTH */
 
 	/*Local Ints:	 Type	Polarity	Trigger	 Bus ID	 IRQ	APIC ID PIN# */
+#define IO_LOCAL_INT(type, intr, apicid, pin) \
+		smp_write_lintsrc(mc, (type), MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, bus_isa, (intr), (apicid), (pin));
+
 	IO_LOCAL_INT(mp_ExtINT, 0x0, MP_APIC_ALL, 0x0);
 	IO_LOCAL_INT(mp_NMI, 0x0, MP_APIC_ALL, 0x1);
 	/* There is no extension information... */
@@ -155,6 +154,6 @@ static void *smp_write_config_table(void *v)
 unsigned long write_smp_table(unsigned long addr)
 {
 	void *v;
-	v = smp_write_floating_table(addr, 0);
+	v = smp_write_floating_table(addr, 0);	/* ADDR, Enable Virtual Wire */
 	return (unsigned long)smp_write_config_table(v);
 }
diff --git a/src/northbridge/amd/agesa/family14/pci_devs.h b/src/northbridge/amd/agesa/family14/pci_devs.h
new file mode 100644
index 0000000..c257d3d
--- /dev/null
+++ b/src/northbridge/amd/agesa/family14/pci_devs.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google Inc.
+ * Copyright (C) 2014 Sage Electronic Engineering, LLC.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _AMD_FAM14_PCI_DEVS_H_
+#define _AMD_FAM14_PCI_DEVS_H_
+
+#define BUS0 0
+
+/* Graphics and Display */
+#define GFX_DEV 0x1
+#define GFX_FUNC 0
+# define GFX_DEVFN PCI_DEVFN(GFX_DEV,GFX_FUNC)
+
+/* PCI Ports */
+#define PCI_PORT_DEV 0x14
+#define PCI_PORT_FUNC 4
+# define PCI_PORT_DEVID 0x4384
+# define PCI_PORT_DEVFN PCI_DEVFN(PCI_PORT_DEV,PCI_PORT_FUNC)
+
+/* PCIe Ports */
+#define NB_PCIE_PORT1_DEV 0x4
+#define NB_PCIE_PORT2_DEV 0x5
+#define NB_PCIE_PORT3_DEV 0x6
+#define NB_PCIE_PORT4_DEV 0x7
+#define NB_PCIE_PORT5_DEV 0x8
+#define NB_PCIE_FUNC 0
+# define NB_PCIE_PORT1_DEVID 0x1512
+# define NB_PCIE_PORT2_DEVID 0x1513
+# define NB_PCIE_PORT3_DEVID 0x1514
+# define NB_PCIE_PORT4_DEVID 0x1515
+# define NB_PCIE_PORT5_DEVID 0x1516
+# define NB_PCIE_PORT1_DEVFN PCI_DEVFN(NB_PCIE_PORT1_DEV,NB_PCIE_FUNC)
+# define NB_PCIE_PORT2_DEVFN PCI_DEVFN(NB_PCIE_PORT2_DEV,NB_PCIE_FUNC)
+# define NB_PCIE_PORT3_DEVFN PCI_DEVFN(NB_PCIE_PORT3_DEV,NB_PCIE_FUNC)
+# define NB_PCIE_PORT4_DEVFN PCI_DEVFN(NB_PCIE_PORT4_DEV,NB_PCIE_FUNC)
+# define NB_PCIE_PORT5_DEVFN PCI_DEVFN(NB_PCIE_PORT5_DEV,NB_PCIE_FUNC)
+
+#endif /* _AMD_FAM14_PCI_DEVS_H_ */
diff --git a/src/southbridge/amd/cimx/cimx_util.c b/src/southbridge/amd/cimx/cimx_util.c
index a3c6ad7..bf8fbfd 100644
--- a/src/southbridge/amd/cimx/cimx_util.c
+++ b/src/southbridge/amd/cimx/cimx_util.c
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2014 Sage Electronic Engineering, LLC.
  *
  * 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
@@ -16,8 +17,180 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
+
+#include <console/console.h>
+#include <device/pci.h>
 #include <arch/io.h>
+#include <string.h>
 #include "cimx_util.h"
+#include <pc80/i8259.h>
+
+#ifndef __PRE_RAM__
+#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB800) || \
+	IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB900)
+const char * intr_types[] = {
+	[0x00] = "INTA#\t", "INTB#\t", "INTC#\t", "INTD#\t", "INTE#\t", "INTF#\t", "INTG#\t", "INTH#\t",
+	[0x08] = "Misc\t", "Misc0\t", "Misc1\t", "Misc2\t", "Ser IRQ INTA", "Ser IRQ INTB", "Ser IRQ INTC", "Ser IRQ INTD",
+	[0x10] = "SCI\t", "SMBUS0\t", "ASF\t", "HDA\t", "FC\t\t", "GEC\t", "PerMon\t",
+	[0x20] = "IMC INT0\t", "IMC INT1\t", "IMC INT2\t", "IMC INT3\t", "IMC INT4\t", "IMC INT5\t",
+	[0x30] = "Dev18.0 INTA", "Dev18.2 INTB", "Dev19.0 INTA", "Dev19.2 INTB", "Dev22.0 INTA", "Dev22.2 INTB", "Dev20.5 INTC",
+	[0x40] = "IDE\t", "SATA\t",
+	[0x50] = "GPPInt0\t", "GPPInt1\t", "GPPInt2\t", "GPPInt3\t"
+};
+#elif IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB700)
+const char * intr_types[] = {
+	[0x00] = "INTA#\t", "INTB#\t", "INTC#\t", "INTD#\t",
+	[0x04] = "ACPI\t", "SMBUS\t", "RSVD\t", "RSVD\t", "RSVD\t",
+	[0x09] = "INTE#\t", "INTF#\t", "INTG#\t", "INTH#\t",
+};
+#endif
+
+const struct pirq_struct * pirq_data_ptr = NULL;
+const u8 * intr_data_ptr = NULL;
+const u8 * picr_data_ptr = NULL;
+
+/*
+ * Read the FCH PCI_INTR registers 0xC00/0xC01 at a
+ * given index and a given PIC (0) or IOAPIC (1) mode
+ */
+u8 read_pci_int_idx(u8 index, int mode)
+{
+	outb((mode << 7) | index, PCI_INTR_INDEX);
+	return inb(PCI_INTR_DATA);
+}
+
+/*
+ * Write a value to the FCH PCI_INTR registers 0xC00/0xC01
+ * at a given index and PIC (0) or IOAPIC (1) mode
+ */
+void write_pci_int_idx(u8 index, int mode, u8 data)
+{
+	outb((mode << 7) | index, PCI_INTR_INDEX);
+	outb(data, PCI_INTR_DATA);
+}
+
+/*
+ * Write the FCH PCI_INTR registers 0xC00/0xC01 with values
+ * given in global variables intr_data and picr_data.
+ * These variables are defined in mainboard.c
+ */
+void write_pci_int_table (void)
+{
+	u8 byte;
+
+	if(picr_data_ptr == NULL || intr_data_ptr == NULL){
+		printk(BIOS_ERR, "Warning: Can't write PCI_INTR 0xC00/0xC01 registers because\n"
+				"'mainboard_picr_data' or 'mainboard_intr_data' tables are NULL\n");
+		return;
+	}
+
+	/* PIC IRQ routine */
+	printk(BIOS_DEBUG, "PCI_INTR tables: Writing registers C00/C01 for PIC mode PCI IRQ routing:\n"
+			"\tPCI_INTR_INDEX\t\tPCI_INTR_DATA\n");
+	for (byte = 0; byte < FCH_INT_TABLE_SIZE; byte++) {
+		if (intr_types[byte]) {
+			write_pci_int_idx(byte, 0, (u8) picr_data_ptr[byte]);
+			printk(BIOS_DEBUG, "\t0x%02X %s\t: 0x%02X\n",
+					byte, intr_types[byte], read_pci_int_idx(byte, 0));
+		}
+	}
+
+	/* APIC IRQ routine */
+	printk(BIOS_DEBUG, "PCI_INTR tables: Writing registers C00/C01 for APIC mode PCI IRQ routing:\n"
+			"\tPCI_INTR_INDEX\t\tPCI_INTR_DATA\n");
+	for (byte = 0; byte < FCH_INT_TABLE_SIZE; byte++) {
+		if (intr_types[byte]) {
+			write_pci_int_idx(byte, 1, (u8) intr_data_ptr[byte]);
+			printk(BIOS_DEBUG, "\t0x%02X %s\t: 0x%02X\n",
+					byte, intr_types[byte], read_pci_int_idx(byte, 1));
+		}
+	}
+}
+
+/*
+ * Function to write the PCI config space Interrupt
+ * registers based on the values given in PCI_INTR
+ * table at I/O port 0xC00/0xC01
+ */
+void write_pci_cfg_irqs(void)
+{
+	device_t dev;
+	int int_pin = 0;	/* Value of the INT_PIN register 0x3D */
+	int int_line = 0;	/* IRQ number read from PCI_INTR table and programmed to INT_LINE reg 0x3C */
+	int c00_idx = 0;	/* Index into PCI_INTR table, 0xC00/0xC01 */
+	int devfn = 0;		/* A PCI Device and Function number */
+	int i = 0;
+
+	if (pirq_data_ptr == NULL) {
+		printk(BIOS_WARNING, "Warning: Can't write PCI IRQ assignments because"
+				" 'mainboard_pirq_data' structure does not exist\n");
+		return;
+	}
+
+	/* Populate the PCI cfg space header with the IRQ assignment */
+	printk(BIOS_DEBUG, "PCI_CFG IRQ: Write PCI config space IRQ assignments\n");
+	for (dev = all_devices; dev; dev = dev->next) {
+		devfn = dev->path.pci.devfn;
+
+		if (!(dev->enabled))
+			continue;	/* Skip disabled devices */
+
+		/* Get the INT_PIN that this dev uses */
+		int_pin = pci_read_config8(dev, PCI_INTERRUPT_PIN);
+		if (int_pin < 1 || int_pin > 4)
+			continue;	/* Device has INT_PIN = 0 so we do not need to set up an IRQ for it */
+
+		printk(BIOS_SPEW, "PCI_CFG IRQ: Found dev %01x:%02xh.%02xh\n",
+				dev->bus->secondary, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+		/* Find the index into the PCI_INTR table for this device */
+		i = 0;
+		c00_idx = 0xFF;	/* Will check to make sure it changed */
+		while ((pirq_data_ptr[i].devfn != 0xFF) || (pirq_data_ptr[i].PIN[0] != 0xFF)) {
+			if (pirq_data_ptr[i].devfn != devfn) {
+				i++;
+				continue;
+			}
+			c00_idx = pirq_data_ptr[i].PIN[int_pin - 1];	/* PIN_A is index 0 in pirq_data array but 1 in PCI cfg reg */
+			break;	/* Found our device, stop looping */
+		}
+
+		/* Make sure we got a valid index */
+		if (c00_idx == 0xFF) {
+			printk(BIOS_SPEW, "PCI Devfn (0x%x) not found in pirq_data table\n", devfn);
+			continue;
+		} else if (c00_idx == 0x1F) {
+			printk(BIOS_SPEW, "Got index 0x1F (Not Connected), perhaps this device was defined wrong?\n");
+			continue;
+		}
+
+		/* Program the INT_LINE register (0x3C) in PCI config space */
+		int_line = read_pci_int_idx(c00_idx, 0);	/* Get the IRQ associated with this INT_PIN */
+		if (int_line == IRQ_DIS) {
+			printk(BIOS_SPEW, "Got IRQ 0x1F (disabled), perhaps this device was defined wrong?\n");
+			continue;
+		} else if ((1 << int_line) & IRQ_RES) {
+			printk(BIOS_WARNING, "WARNING: PCI IRQ %d is reserved, check the mainboard_picr_data table\n"
+					"Skipping write of PCI config space\n", int_line);
+			continue;
+		}
+		pci_write_config8(dev, PCI_INTERRUPT_LINE, int_line);	/* Set INT_LINE reg with value from PCI_INTR table */
+
+		/* Set this IRQ to level triggered since it is used by PCI devices */
+		i8259_configure_irq_trigger(int_line, IRQ_LEVEL_TRIGGERED);
+
+		printk(BIOS_SPEW, "\tINT_PIN\t\t: %d (%s)\n", int_pin,
+				(int_pin == 1) ? "PIN A":
+				(int_pin == 2) ? "PIN B":
+				(int_pin == 3) ? "PIN C":
+				(int_pin == 4) ? "PIN D" : "Unknown INT_PIN!");
+		printk(BIOS_SPEW, "\tINT_LINE\t: 0x%x (IRQ %d)\n"
+				"\tPCI_INTR idx\t: 0x%02x (%s)\n",
+				int_line, int_line, c00_idx, intr_types[c00_idx]);
+	}
+	printk(BIOS_DEBUG, "PCI_CFG IRQ: Finished writing PCI config space IRQ assignments\n");
+}
+#endif /* __PRE_RAM__ */
 
 static void pmio_write_index(u16 port_base, u8 reg, u8 value)
 {
diff --git a/src/southbridge/amd/cimx/cimx_util.h b/src/southbridge/amd/cimx/cimx_util.h
index 1e806ba..0f53497 100644
--- a/src/southbridge/amd/cimx/cimx_util.h
+++ b/src/southbridge/amd/cimx/cimx_util.h
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2014 Sage Electronic Engineering, LLC.
  *
  * 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
@@ -22,15 +23,123 @@
 
 #include <stdint.h>
 
-/* Power management index/data registers */
+/*
+ * PIRQ and device routing - these define the index
+ * into the FCH PCI_INTR 0xC00/0xC01 interrupt
+ * routing table
+ */
+#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB800) || \
+	IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB900)
+#define FCH_INT_TABLE_SIZE 0x54
+#define PIRQ_NC		0x1F	/* Not Used */
+#define PIRQ_A		0x00	/* INT A */
+#define PIRQ_B		0x01	/* INT B */
+#define PIRQ_C		0x02	/* INT C */
+#define PIRQ_D		0x03	/* INT D */
+#define PIRQ_E		0x04	/* INT E */
+#define PIRQ_F		0x05	/* INT F */
+#define PIRQ_G		0x06	/* INT G */
+#define PIRQ_H		0x07	/* INT H */
+#define PIRQ_MISC	0x08	/* Miscellaneous IRQ Settings - See FCH Spec */
+#define PIRQ_MISC0	0x09	/* Miscellaneous0 IRQ Settings */
+#define PIRQ_MISC1	0x0A	/* Miscellaneous1 IRQ Settings */
+#define PIRQ_MISC2	0x0B	/* Miscellaneous2 IRQ Settings */
+#define PIRQ_SIRQA	0x0C	/* Serial IRQ INTA */
+#define PIRQ_SIRQB	0x0D	/* Serial IRQ INTA */
+#define PIRQ_SIRQC	0x0E	/* Serial IRQ INTA */
+#define PIRQ_SIRQD	0x0F	/* Serial IRQ INTA */
+#define PIRQ_SCI	0x10	/* SCI IRQ */
+#define PIRQ_SMBUS	0x11	/* SMBUS	14h.0 */
+#define PIRQ_ASF	0x12	/* ASF */
+#define PIRQ_HDA	0x13	/* HDA		14h.2 */
+#define PIRQ_FC		0x14	/* FC */
+#define PIRQ_GEC	0x15	/* GEC */
+#define PIRQ_PMON	0x16	/* Performance Monitor */
+#define PIRQ_IMC0	0x20	/* IMC INT0 */
+#define PIRQ_IMC1	0x21	/* IMC INT1 */
+#define PIRQ_IMC2	0x22	/* IMC INT2 */
+#define PIRQ_IMC3	0x23	/* IMC INT3 */
+#define PIRQ_IMC4	0x24	/* IMC INT4 */
+#define PIRQ_IMC5	0x25	/* IMC INT5 */
+#define PIRQ_OHCI1	0x30	/* USB OHCI	12h.0 */
+#define PIRQ_EHCI1	0x31	/* USB EHCI	12h.2 */
+#define PIRQ_OHCI2	0x32	/* USB OHCI	13h.0 */
+#define PIRQ_EHCI2	0x33	/* USB EHCI	13h.2 */
+#define PIRQ_OHCI3	0x34	/* USB OHCI	16h.0 */
+#define PIRQ_EHCI3	0x35	/* USB EHCI	16h.2 */
+#define PIRQ_OHCI4	0x36	/* USB OHCI	14h.5 */
+#define PIRQ_IDE	0x40	/* IDE		14h.1 */
+#define PIRQ_SATA	0x41	/* SATA		11h.0 */
+#define PIRQ_GPP0	0x50	/* GPP INT 0 */
+#define PIRQ_GPP1	0x51	/* GPP INT 1 */
+#define PIRQ_GPP2	0x52	/* GPP INT 2 */
+#define PIRQ_GPP3	0x53	/* GPP INT 3 */
+#elif IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB700)
+#define FCH_INT_TABLE_SIZE 0xD
+#define PIRQ_NC		0x1F	/* Not Used */
+#define PIRQ_A		0x00	/* INT A */
+#define PIRQ_B		0x01	/* INT B */
+#define PIRQ_C		0x02	/* INT C */
+#define PIRQ_D		0x03	/* INT D */
+#define PIRQ_ACPI	0x04	/* ACPI */
+#define PIRQ_SMBUS	0x05	/* SMBUS */
+/* Index 6, 7, 8 are all reserved */
+#define PIRQ_E		0x09	/* INT E */
+#define PIRQ_F		0x0A	/* INT F */
+#define PIRQ_G		0x0B	/* INT G */
+#define PIRQ_H		0x0C	/* INT H */
+#endif
+
+/*
+ * IRQ numbers and common usage
+ * If an IRQ does not say it is 'Reserved'
+ * then it can be used by a device.
+ */
+/* PIC IRQs */
+#define IRQ_DIS		0x1F	/* IRQ is disabled */
+#define IRQ_0		0x00	/* Reserved - Timer IRQ */
+#define IRQ_1		0x01	/* Keyboard controller */
+#define IRQ_2		0x02	/* Reserved - Cascade to Slave PIC */
+#define IRQ_3		0x03	/* Serial Port 2 & 4 */
+#define IRQ_4		0x04	/* Serial Port 1 & 3 */
+#define IRQ_5		0x05	/* Parallel Port 2 & 3 or Sound Card */
+#define IRQ_6		0x06	/* Floppy Disk Controller */
+#define IRQ_7		0x07	/* Parallel Port 1 */
+#define IRQ_8		0x08	/* Reserved - RTC */
+#define IRQ_9		0x09	/* Reserved - ACPI System Control Interrupt */
+#define IRQ_10		0x0A	/* Free or SCSI or NIC */
+#define IRQ_11		0x0B	/* Free or SCSI or NIC */
+#define IRQ_12		0x0C	/* PS/2 Mouse */
+#define IRQ_13		0x0D	/* Reserved - CPU Floating Point Unit */
+#define IRQ_14		0x0E	/* Primary ATA */
+#define IRQ_15		0x0F	/* Secondary ATA */
+
+/* FCH index/data registers */
 #define PM_INDEX	0xcd6
 #define PM_DATA		0xcd7
+#define BIOSRAM_INDEX	0xcd4
+#define BIOSRAM_DATA	0xcd5
 #define PM2_INDEX	0xcd0
 #define PM2_DATA	0xcd1
+#define PCI_INTR_INDEX	0xc00
+#define PCI_INTR_DATA	0xc01
 
 void pm_iowrite(u8 reg, u8 value);
 u8 pm_ioread(u8 reg);
 void pm2_iowrite(u8 reg, u8 value);
 u8 pm2_ioread(u8 reg);
 
+#ifndef __PRE_RAM__
+
+struct pirq_struct {
+u8 devfn;
+u8 PIN[4];	/* PINA/B/C/D are index 0/1/2/3 */
+};
+
+u8 read_pci_int_idx(u8 index, int mode);
+void write_pci_int_idx(u8 index, int mode, u8 data);
+void write_pci_cfg_irqs(void);
+void write_pci_int_table (void);
+#endif /* __PRE_RAM */
+
 #endif /* CIMX_UTIL_H */
diff --git a/src/southbridge/amd/cimx/sb800/late.c b/src/southbridge/amd/cimx/sb800/late.c
index 40b422b..ecc53af 100644
--- a/src/southbridge/amd/cimx/sb800/late.c
+++ b/src/southbridge/amd/cimx/sb800/late.c
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2011 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013 Sage Electronic Engineering, LLC.
  *
  * 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
@@ -36,6 +37,7 @@
 #include "sb_cimx.h"		/* AMD CIMX wrapper entries */
 #include "smbus.h"
 #include "fan.h"
+#include <southbridge/amd/cimx/cimx_util.h>
 
 /*implement in mainboard.c*/
 void set_pcie_reset(void);
@@ -339,10 +341,10 @@ static void sb800_enable(device_t dev)
 	struct southbridge_amd_cimx_sb800_config *sb_chip =
 		(struct southbridge_amd_cimx_sb800_config *)(dev->chip_info);
 
-	printk(BIOS_DEBUG, "sb800_enable() ");
-
+	printk(BIOS_DEBUG, "%s: Enabling ", __func__);
 	switch (dev->path.pci.devfn) {
-	case (0x11 << 3) | 0: /* 0:11.0  SATA */
+	case (0x11 << 3) | 0: /* 0:11h.0  SATA */
+		printk(BIOS_DEBUG, "SATA: 0:11h.0\n");
 		/* the first sb800 device */
 		switch (GPP_CFGMODE) { /* config the GPP PCIe ports */
 		case GPP_CFGMODE_X2200:
@@ -372,8 +374,16 @@ static void sb800_enable(device_t dev)
 		}
 		break;
 
-	case (0x14 << 3) | 0: /* 0:14:0 SMBUS */
-		printk(BIOS_INFO, "sm_init().\n");
+	case (0x14 << 3) | 0: /* 0:14h:0 SMBUS */
+		printk(BIOS_DEBUG, "SMBUS: 0:14h.0\n");
+
+		/* Write PCI_INTR table */
+		write_pci_int_table();
+
+		/* Now that all the devices are set up, write their IRQs */
+		write_pci_cfg_irqs();
+
+		printk(BIOS_INFO, "sm_init()\n");
 		clear_ioapic(IO_APIC_ADDR);
 #if CONFIG_CPU_AMD_AGESA
 		/* Assign the ioapic ID the next available number after the processor core local APIC IDs */
@@ -392,23 +402,25 @@ static void sb800_enable(device_t dev)
 #endif
 		break;
 
-	case (0x14 << 3) | 1: /* 0:14:1 IDE */
+	case (0x14 << 3) | 1: /* 0:14h:1 IDE */
+		printk(BIOS_DEBUG, "IDE: 0:14h.1\n");
 		break;
 
-	case (0x14 << 3) | 2: /* 0:14:2 HDA */
+	case (0x14 << 3) | 2: /* 0:14h:2 HDA */
+		printk(BIOS_DEBUG, "HDA: 0:14h.2\n");
 		if (dev->enabled) {
   			if (AZALIA_DISABLE == sb_config->AzaliaController) {
   				sb_config->AzaliaController = AZALIA_AUTO;
 			}
-			printk(BIOS_DEBUG, "hda enabled\n");
+			printk(BIOS_DEBUG, "\thda enabled\n");
 		} else {
   			sb_config->AzaliaController = AZALIA_DISABLE;
-			printk(BIOS_DEBUG, "hda disabled\n");
+			printk(BIOS_DEBUG, "\thda disabled\n");
 		}
 		break;
 
-
-	case (0x14 << 3) | 3: /* 0:14:3 LPC */
+	case (0x14 << 3) | 3: /* 0:14h:3 LPC */
+		printk(BIOS_DEBUG, "LPC: 0:14h.3\n");
 		/* Initialize the fans */
 #if CONFIG_SB800_IMC_FAN_CONTROL
 		init_sb800_IMC_fans(dev);
@@ -417,20 +429,23 @@ static void sb800_enable(device_t dev)
 #endif
 		break;
 
-	case (0x14 << 3) | 4: /* 0:14:4 PCI */
+	case (0x14 << 3) | 4: /* 0:14h:4 PCI */
+		printk(BIOS_DEBUG, "PCI Bridge: 0:14h.4\n");
 		break;
 
-	case (0x14 << 3) | 6: /* 0:14:6 GEC */
+	case (0x14 << 3) | 6: /* 0:14h:6 GEC */
+		printk(BIOS_DEBUG, "GEC: 0:14h.6\n");
 		if (dev->enabled) {
 			sb_config->GecConfig = 0;
-			printk(BIOS_DEBUG, "gec enabled\n");
+			printk(BIOS_DEBUG, "\tgec enabled\n");
 		} else {
 			sb_config->GecConfig = 1;
-			printk(BIOS_DEBUG, "gec disabled\n");
+			printk(BIOS_DEBUG, "\tgec disabled\n");
 		}
 		break;
 
-	case (0x15 << 3) | 0: /* 0:15:0 PCIe PortA */
+	case (0x15 << 3) | 0: /* 0:15h:0 PCIe PortA */
+		printk(BIOS_DEBUG, "PCIe PortA: 0:15h.0\n");
 		{
 			device_t device;
 			for (device = dev; device; device = device->next) {
@@ -449,25 +464,32 @@ static void sb800_enable(device_t dev)
 		}
 		break;
 
-	case (0x12 << 3) | 0: /* 0:12:0 OHCI-USB1 */
+	case (0x12 << 3) | 0: /* 0:12h:0 OHCI-USB1 */
+		printk(BIOS_DEBUG, "USB OHCI1: 0:12h.0\n");
 		sb_config->USBMODE.UsbMode.Ohci1 = dev->enabled;
 		break;
-	case (0x12 << 3) | 2: /* 0:12:2 EHCI-USB1 */
+	case (0x12 << 3) | 2: /* 0:12h:2 EHCI-USB1 */
+		printk(BIOS_DEBUG, "USB EHCI1: 0:12h.2\n");
 		sb_config->USBMODE.UsbMode.Ehci1 = dev->enabled;
 		break;
-	case (0x13 << 3) | 0: /* 0:13:0 OHCI-USB2 */
+	case (0x13 << 3) | 0: /* 0:13h:0 OHCI-USB2 */
+		printk(BIOS_DEBUG, "USB OHCI2: 0:13h.0\n");
 		sb_config->USBMODE.UsbMode.Ohci2 = dev->enabled;
 		break;
-	case (0x13 << 3) | 2: /* 0:13:2 EHCI-USB2 */
+	case (0x13 << 3) | 2: /* 0:13h:2 EHCI-USB2 */
+		printk(BIOS_DEBUG, "USB EHCI2: 0:13.2\n");
 		sb_config->USBMODE.UsbMode.Ehci2 = dev->enabled;
 		break;
-	case (0x14 << 3) | 5: /* 0:14:5 OHCI-USB4 */
+	case (0x14 << 3) | 5: /* 0:14h:5 OHCI-USB4 */
+		printk(BIOS_DEBUG, "USB OHCI4: 0:14h.5\n");
 		sb_config->USBMODE.UsbMode.Ohci4 = dev->enabled;
 		break;
-	case (0x16 << 3) | 0: /* 0:16:0 OHCI-USB3 */
+	case (0x16 << 3) | 0: /* 0:16h:0 OHCI-USB3 */
+		printk(BIOS_DEBUG, "USB OHCI3: 0:16h.0\n");
 		sb_config->USBMODE.UsbMode.Ohci3 = dev->enabled;
 		break;
-	case (0x16 << 3) | 2: /* 0:16:2 EHCI-USB3 */
+	case (0x16 << 3) | 2: /* 0:16h:2 EHCI-USB3 */
+		printk(BIOS_DEBUG, "USB EHCI3: 0:16h.2\n");
 		sb_config->USBMODE.UsbMode.Ehci3 = dev->enabled;
 
 		/* call the CIMX entry at the last sb800 device,
diff --git a/src/southbridge/amd/cimx/sb800/pci_devs.h b/src/southbridge/amd/cimx/sb800/pci_devs.h
new file mode 100644
index 0000000..b0d7521
--- /dev/null
+++ b/src/southbridge/amd/cimx/sb800/pci_devs.h
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google Inc.
+ * Copyright (C) 2014 Sage Electronic Engineering, LLC.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _CIMX_SB00_PCI_DEVS_H_
+#define _CIMX_SB00_PCI_DEVS_H_
+
+#define BUS0 0
+
+/* SATA */
+#define SATA_DEV 0x11
+#define SATA_FUNC 0
+# define SATA_IDE_DEVID 0x4390
+# define AHCI_DEVID 0x4391
+# define RAID_DEVID 0x4392
+# define RAID5_DEVID 0x4393
+# define SATA_DEVFN PCI_DEVFN(SATA_DEV,SATA_FUNC)
+
+/* OHCI */
+#define OHCI1_DEV 0x12
+#define OHCI1_FUNC 0
+#define OHCI2_DEV 0x13
+#define OHCI2_FUNC 0
+#define OHCI3_DEV 0x16
+#define OHCI3_FUNC 0
+#define OHCI4_DEV 0x14
+#define OHCI4_FUNC 5
+# define OHCI_DEVID 0x4397
+# define OHCI1_DEVFN PCI_DEVFN(OHCI1_DEV,OHCI1_FUNC)
+# define OHCI2_DEVFN PCI_DEVFN(OHCI2_DEV,OHCI2_FUNC)
+# define OHCI3_DEVFN PCI_DEVFN(OHCI3_DEV,OHCI3_FUNC)
+# define OHCI4_DEVFN PCI_DEVFN(OHCI4_DEV,OHCI4_FUNC)
+
+/* EHCI */
+#define EHCI1_DEV 0x12
+#define EHCI1_FUNC 2
+#define EHCI2_DEV 0x13
+#define EHCI2_FUNC 2
+#define EHCI3_DEV 0x16
+#define EHCI3_FUNC 2
+# define EHCI_DEVID 0x4396
+# define EHCI1_DEVFN PCI_DEVFN(EHCI1_DEV,EHCI1_FUNC)
+# define EHCI2_DEVFN PCI_DEVFN(EHCI2_DEV,EHCI2_FUNC)
+# define EHCI3_DEVFN PCI_DEVFN(EHCI3_DEV,EHCI3_FUNC)
+
+/* IDE */
+#define IDE_DEV 0x14
+#define IDE_FUNC 1
+# define IDE_DEVID 0x439C
+# define IDE_DEVFN PCI_DEVFN(IDE_DEV,IDE_FUNC)
+
+/* HD Audio */
+#define HDA_DEV 0x14
+#define HDA_FUNC 2
+# define HDA_DEVID 0x4383
+# define HDA_DEVFN PCI_DEVFN(HDA_DEV,HDA_FUNC)
+
+/* PCI Ports */
+#define SB_PCI_PORT_DEV 0x14
+#define SB_PCI_PORT_FUNC 4
+# define SB_PCI_PORT_DEVID 0x4384
+# define SB_PCI_PORT_DEVFN PCI_DEVFN(SB_PCI_PORT_DEV,SB_PCI_PORT_FUNC)
+
+/* PCIe Ports */
+#define SB_PCIE_DEV 0x15
+#define SB_PCIE_PORT1_FUNC 0
+#define SB_PCIE_PORT2_FUNC 1
+#define SB_PCIE_PORT3_FUNC 2
+#define SB_PCIE_PORT4_FUNC 3
+# define SB_PCIE_PORT1_DEVID 0x43A0
+# define SB_PCIE_PORT2_DEVID 0x43A1
+# define SB_PCIE_PORT3_DEVID 0x43A2
+# define SB_PCIE_PORT4_DEVID 0x43A3
+# define SB_PCIE_PORT1_DEVFN PCI_DEVFN(SB_PCIE_DEV,SB_PCIE_PORT1_FUNC)
+# define SB_PCIE_PORT2_DEVFN PCI_DEVFN(SB_PCIE_DEV,SB_PCIE_PORT2_FUNC)
+# define SB_PCIE_PORT3_DEVFN PCI_DEVFN(SB_PCIE_DEV,SB_PCIE_PORT3_FUNC)
+# define SB_PCIE_PORT4_DEVFN PCI_DEVFN(SB_PCIE_DEV,SB_PCIE_PORT4_FUNC)
+
+/* Fusion Controller Hub */
+#define PCU_DEV 0x14
+#define LPC_DEV PCU_DEV
+#define LPC_FUNC 3
+#define SMBUS_DEV 0x14
+#define SMBUS_FUNC 0
+# define LPC_DEVID 0x439D
+# define SMBUS_DEVID 0x4385
+# define LPC_DEVFN PCI_DEVFN(LPC_DEV,LPC_FUNC)
+# define SMBUS_DEVFN PCI_DEVFN(SMBUS_DEV,SMBUS_FUNC)
+
+#endif /* _CIMX_SB800_PCI_DEVS_H_ */



More information about the coreboot-gerrit mailing list