diff options
Diffstat (limited to 'src/southbridge/intel/lynxpoint')
-rw-r--r-- | src/southbridge/intel/lynxpoint/lpc.c | 167 | ||||
-rw-r--r-- | src/southbridge/intel/lynxpoint/pch.h | 1 |
2 files changed, 113 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); diff --git a/src/southbridge/intel/lynxpoint/pch.h b/src/southbridge/intel/lynxpoint/pch.h index 5a3725ef29..6739843141 100644 --- a/src/southbridge/intel/lynxpoint/pch.h +++ b/src/southbridge/intel/lynxpoint/pch.h @@ -185,6 +185,7 @@ unsigned get_gpios(const int *gpio_num_array); #define LPC_GEN2_DEC 0x88 /* LPC IF Generic Decode Range 2 */ #define LPC_GEN3_DEC 0x8c /* LPC IF Generic Decode Range 3 */ #define LPC_GEN4_DEC 0x90 /* LPC IF Generic Decode Range 4 */ +#define LGMR 0x98 /* LPC Generic Memory Range */ /* PCI Configuration Space (D31:F1): IDE */ #define PCH_IDE_DEV PCI_DEV(0, 0x1f, 1) |