aboutsummaryrefslogtreecommitdiff
path: root/src/southbridge/intel/lynxpoint/lpc.c
diff options
context:
space:
mode:
authorAaron Durbin <adurbin@chromium.org>2012-12-19 14:38:01 -0600
committerRonald G. Minnich <rminnich@gmail.com>2013-03-14 20:18:57 +0100
commit6f561afa4a635958dedf20ffda9a40c6f5e5699e (patch)
tree5caf818c7f05c5caa4885e0c6604492e4e5ad907 /src/southbridge/intel/lynxpoint/lpc.c
parent26e7dd703dea8dce30829d8bb73c1f27a2178d72 (diff)
lynxpoint: lpc resource reservations
This commit updates the Lynx Point resource reservations before the coreboot allocator assigns resources. There is no need to mark anything as subtractive decode because there are no devices/buses linked to the LPC device. The I/O range reservations consists of claiming the first 4KiB of I/O space. The PMBASE, GPIOBASE, and LPC generic I/O decode ranges are checked against the default claimed range. If those ranges overlap or fall outside of the default range then those resources are added. The MMIO range reservations consist of claiming everything from the I/O APIC to 4GiB. The RCBA and the LPC Generic Memory range register are then conditionally added if they fall outside of the default MMIO range. Change-Id: I0f560a03814a2b15961fdbe61e4164cd54cff7a5 Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/2682 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Diffstat (limited to 'src/southbridge/intel/lynxpoint/lpc.c')
-rw-r--r--src/southbridge/intel/lynxpoint/lpc.c167
1 files changed, 112 insertions, 55 deletions
diff --git a/src/southbridge/intel/lynxpoint/lpc.c b/src/southbridge/intel/lynxpoint/lpc.c
index a44d80f802..facea7cdd6 100644
--- a/src/southbridge/intel/lynxpoint/lpc.c
+++ b/src/southbridge/intel/lynxpoint/lpc.c
@@ -574,74 +574,131 @@ static void lpc_init(struct device *dev)
pch_fixups(dev);
}
-static void pch_lpc_read_resources(device_t dev)
+static void pch_lpc_add_mmio_resources(device_t dev)
{
+ u32 reg;
struct resource *res;
- config_t *config = dev->chip_info;
- u8 io_index = 0;
-
- /* Get the normal PCI resources of this device. */
- pci_dev_read_resources(dev);
-
- /* Add an extra subtractive resource for both memory and I/O. */
- res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
- res->base = 0;
- res->size = 0x1000;
- res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
- IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+ const u32 default_decode_base = IO_APIC_ADDR;
- /* GPIOBASE */
- res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
- res->base = DEFAULT_GPIOBASE;
- res->size = DEFAULT_GPIOSIZE;
- res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
- IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
-
- res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
- res->base = 0xff800000;
- res->size = 0x00800000; /* 8 MB for flash */
- res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
- IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
-
- res = new_resource(dev, io_index++); /* IOAPIC */
- res->base = IO_APIC_ADDR;
- res->size = 0x00001000;
+ /*
+ * Just report all resources from IO-APIC base to 4GiB. Don't mark
+ * them reserved as that may upset the OS if this range is marked
+ * as reserved in the e820.
+ */
+ res = new_resource(dev, OIC);
+ res->base = default_decode_base;
+ res->size = 0 - default_decode_base;
res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
- /* Set PCH IO decode ranges if required.*/
- if ((config->gen1_dec & 0xFFFC) > 0x1000) {
- res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
- res->base = config->gen1_dec & 0xFFFC;
- res->size = (config->gen1_dec >> 16) & 0xFC;
- res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
- IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+ /* RCBA */
+ if (DEFAULT_RCBA < default_decode_base) {
+ res = new_resource(dev, RCBA);
+ res->base = DEFAULT_RCBA;
+ res->size = 16 * 1024;
+ res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED |
+ IORESOURCE_FIXED | IORESOURCE_RESERVE;
}
- if ((config->gen2_dec & 0xFFFC) > 0x1000) {
- res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
- res->base = config->gen2_dec & 0xFFFC;
- res->size = (config->gen2_dec >> 16) & 0xFC;
- res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
- IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+ /* Check LPC Memory Decode register. */
+ reg = pci_read_config32(dev, LGMR);
+ if (reg & 1) {
+ reg &= ~0xffff;
+ if (reg < default_decode_base) {
+ res = new_resource(dev, LGMR);
+ res->base = reg;
+ res->size = 16 * 1024;
+ res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED |
+ IORESOURCE_FIXED | IORESOURCE_RESERVE;
+ }
}
+}
- if ((config->gen3_dec & 0xFFFC) > 0x1000) {
- res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
- res->base = config->gen3_dec & 0xFFFC;
- res->size = (config->gen3_dec >> 16) & 0xFC;
- res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
- IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
- }
+/* Default IO range claimed by the LPC device. The upper bound is exclusive. */
+#define LPC_DEFAULT_IO_RANGE_LOWER 0
+#define LPC_DEFAULT_IO_RANGE_UPPER 0x1000
+
+static inline int pch_io_range_in_default(u16 base, u16 size)
+{
+ /* Does it start above the range? */
+ if (base >= LPC_DEFAULT_IO_RANGE_UPPER)
+ return 0;
+
+ /* Is it entirely contained? */
+ if (base >= LPC_DEFAULT_IO_RANGE_LOWER &&
+ (base + size) < LPC_DEFAULT_IO_RANGE_UPPER)
+ return 1;
+
+ /* This will return not in range for partial overlaps. */
+ return 0;
+}
+
+/*
+ * Note: this function assumes there is no overlap with the default LPC device's
+ * claimed range: LPC_DEFAULT_IO_RANGE_LOWER -> LPC_DEFAULT_IO_RANGE_UPPER.
+ */
+static void pch_lpc_add_io_resource(device_t dev, u16 base, u16 size, int index)
+{
+ struct resource *res;
+
+ if (pch_io_range_in_default(base, size))
+ return;
- if ((config->gen4_dec & 0xFFFC) > 0x1000) {
- res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
- res->base = config->gen4_dec & 0xFFFC;
- res->size = (config->gen4_dec >> 16) & 0xFC;
- res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
- IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+ res = new_resource(dev, index);
+ res->base = base;
+ res->size = size;
+ res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+}
+
+static void pch_lpc_add_gen_io_resources(device_t dev, int reg_value, int index)
+{
+ /*
+ * Check if the register is enabled. If so and the base exceeds the
+ * device's deafult claim range add the resoure.
+ */
+ if (reg_value & 1) {
+ u16 base = reg_value & 0xfffc;
+ u16 size = (0x3 | ((reg_value >> 16) & 0xfc)) + 1;
+ pch_lpc_add_io_resource(dev, base, size, index);
}
}
+static void pch_lpc_add_io_resources(device_t dev)
+{
+ struct resource *res;
+ config_t *config = dev->chip_info;
+
+ /* Add the default claimed IO range for the LPC device. */
+ res = new_resource(dev, 0);
+ res->base = LPC_DEFAULT_IO_RANGE_LOWER;
+ res->size = LPC_DEFAULT_IO_RANGE_UPPER - LPC_DEFAULT_IO_RANGE_LOWER;
+ res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+
+ /* GPIOBASE */
+ pch_lpc_add_io_resource(dev, DEFAULT_GPIOBASE, DEFAULT_GPIOSIZE,
+ GPIO_BASE);
+
+ /* PMBASE */
+ pch_lpc_add_io_resource(dev, DEFAULT_PMBASE, 128, PMBASE);
+
+ /* LPC Generic IO Decode range. */
+ pch_lpc_add_gen_io_resources(dev, config->gen1_dec, LPC_GEN1_DEC);
+ pch_lpc_add_gen_io_resources(dev, config->gen2_dec, LPC_GEN2_DEC);
+ pch_lpc_add_gen_io_resources(dev, config->gen3_dec, LPC_GEN3_DEC);
+ pch_lpc_add_gen_io_resources(dev, config->gen4_dec, LPC_GEN4_DEC);
+}
+
+static void pch_lpc_read_resources(device_t dev)
+{
+ /* Get the normal PCI resources of this device. */
+ pci_dev_read_resources(dev);
+
+ /* Add non-standard MMIO resources. */
+ pch_lpc_add_mmio_resources(dev);
+
+ /* Add IO resources. */
+ pch_lpc_add_io_resources(dev);
+}
+
static void pch_lpc_enable_resources(device_t dev)
{
pch_decode_init(dev);