diff options
-rw-r--r-- | src/northbridge/intel/haswell/haswell.h | 9 | ||||
-rw-r--r-- | src/northbridge/intel/haswell/northbridge.c | 457 |
2 files changed, 275 insertions, 191 deletions
diff --git a/src/northbridge/intel/haswell/haswell.h b/src/northbridge/intel/haswell/haswell.h index 967a186e81..bbb51aaf81 100644 --- a/src/northbridge/intel/haswell/haswell.h +++ b/src/northbridge/intel/haswell/haswell.h @@ -63,7 +63,6 @@ #define MCHBAR 0x48 #define PCIEXBAR 0x60 #define DMIBAR 0x68 -#define X60BAR 0x60 #define GGC 0x50 /* GMCH Graphics Control */ @@ -91,8 +90,14 @@ #define G_SMRAME (1 << 3) #define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) -#define TOM 0xa0 +#define MESEG_BASE 0x70 /* Management Engine Base. */ +#define MESEG_LIMIT 0x78 /* Management Engine Limit. */ +#define REMAPBASE 0x90 /* Remap base. */ +#define REMAPLIMIT 0x98 /* Remap limit. */ +#define TOM 0xa0 /* Top of DRAM in memory controller space. */ #define TOUUD 0xa8 /* Top of Upper Usable DRAM */ +#define BDSM 0xb0 /* Base Data Stolen Memory */ +#define BGSM 0xb4 /* Base GTT Stolen Memory */ #define TSEG 0xb8 /* TSEG base */ #define TOLUD 0xbc /* Top of Low Used Memory */ diff --git a/src/northbridge/intel/haswell/northbridge.c b/src/northbridge/intel/haswell/northbridge.c index 5731077999..e97ef55699 100644 --- a/src/northbridge/intel/haswell/northbridge.c +++ b/src/northbridge/intel/haswell/northbridge.c @@ -65,19 +65,14 @@ void cbmem_post_handling(void) update_mrc_cache(); } -static int get_pcie_bar(u32 *base, u32 *len) +static int get_pcie_bar(device_t dev, unsigned int index, u32 *base, u32 *len) { - device_t dev; u32 pciexbar_reg; *base = 0; *len = 0; - dev = dev_find_slot(0, PCI_DEVFN(0, 0)); - if (!dev) - return 0; - - pciexbar_reg = pci_read_config32(dev, PCIEXBAR); + pciexbar_reg = pci_read_config32(dev, index); if (!(pciexbar_reg & (1 << 0))) return 0; @@ -100,221 +95,305 @@ static int get_pcie_bar(u32 *base, u32 *len) return 0; } -static void add_fixed_resources(struct device *dev, int index) +static void pci_domain_set_resources(device_t dev) { - struct resource *resource; - u32 pcie_config_base, pcie_config_size; - - printk(BIOS_DEBUG, "Adding UMA memory area base=0x%llx " - "size=0x%llx\n", uma_memory_base, uma_memory_size); - resource = new_resource(dev, index); - resource->base = (resource_t) uma_memory_base; - resource->size = (resource_t) uma_memory_size; - resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE | - IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; - - /* Clear these values here so they don't get used by MTRR code */ - uma_memory_base = 0; - uma_memory_size = 0; - - if (get_pcie_bar(&pcie_config_base, &pcie_config_size)) { - printk(BIOS_DEBUG, "Adding PCIe config bar base=0x%08x " - "size=0x%x\n", pcie_config_base, pcie_config_size); - resource = new_resource(dev, index+1); - resource->base = (resource_t) pcie_config_base; - resource->size = (resource_t) pcie_config_size; - resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE | - IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; - } - - mmio_resource(dev, index++, legacy_hole_base_k, legacy_hole_size_k); + assign_resources(dev->link_list); +} -#if CONFIG_CHROMEOS_RAMOOPS - mmio_resource(dev, index++, CONFIG_CHROMEOS_RAMOOPS_RAM_START >> 10, - CONFIG_CHROMEOS_RAMOOPS_RAM_SIZE >> 10); + /* TODO We could determine how many PCIe busses we need in + * the bar. For now that number is hardcoded to a max of 64. + * See e7525/northbridge.c for an example. + */ +static struct device_operations pci_domain_ops = { + .read_resources = pci_domain_read_resources, + .set_resources = pci_domain_set_resources, + .enable_resources = NULL, + .init = NULL, + .scan_bus = pci_domain_scan_bus, +#if CONFIG_MMCONF_SUPPORT_DEFAULT + .ops_pci_bus = &pci_ops_mmconf, +#else + .ops_pci_bus = &pci_cf8_conf1, #endif +}; - /* Required for SandyBridge sighting 3715511 */ - bad_ram_resource(dev, index++, 0x20000000 >> 10, 0x00200000 >> 10); - bad_ram_resource(dev, index++, 0x40000000 >> 10, 0x00200000 >> 10); +static int get_bar(device_t dev, unsigned int index, u32 *base, u32 *len) +{ + u32 bar; + + bar = pci_read_config32(dev, index); + + /* If not enabled don't report it. */ + if (!(bar & 0x1)) + return 0; + + /* Knock down the enable bit. */ + *base = bar & ~1; + + return 1; } -static void pci_domain_set_resources(device_t dev) +/* There are special BARs that actually are programmed in the MCHBAR. These + * Intel special features, but they do consume resources that need to be + * accounted for. */ +static int get_bar_in_mchbar(device_t dev, unsigned int index, u32 *base, + u32 *len) { - uint64_t tom, me_base, touud; - uint32_t tseg_base, uma_size, tolud; - uint16_t ggc; - unsigned long long tomk; + u32 bar; - /* Total Memory 2GB example: - * - * 00000000 0000MB-1992MB 1992MB RAM (writeback) - * 7c800000 1992MB-2000MB 8MB TSEG (SMRR) - * 7d000000 2000MB-2002MB 2MB GFX GTT (uncached) - * 7d200000 2002MB-2034MB 32MB GFX UMA (uncached) - * 7f200000 2034MB TOLUD - * 7f800000 2040MB MEBASE - * 7f800000 2040MB-2048MB 8MB ME UMA (uncached) - * 80000000 2048MB TOM - * 100000000 4096MB-4102MB 6MB RAM (writeback) - * - * Total Memory 4GB example: - * - * 00000000 0000MB-2768MB 2768MB RAM (writeback) - * ad000000 2768MB-2776MB 8MB TSEG (SMRR) - * ad800000 2776MB-2778MB 2MB GFX GTT (uncached) - * ada00000 2778MB-2810MB 32MB GFX UMA (uncached) - * afa00000 2810MB TOLUD - * ff800000 4088MB MEBASE - * ff800000 4088MB-4096MB 8MB ME UMA (uncached) - * 100000000 4096MB TOM - * 100000000 4096MB-5374MB 1278MB RAM (writeback) - * 14fe00000 5368MB TOUUD - */ + bar = MCHBAR32(index); - /* Top of Upper Usable DRAM, including remap */ - touud = pci_read_config32(dev, TOUUD+4); - touud <<= 32; - touud |= pci_read_config32(dev, TOUUD) & ~1; - - /* Top of Lower Usable DRAM */ - tolud = pci_read_config32(dev, TOLUD) & ~1; - - /* Top of Memory - does not account for any UMA */ - tom = pci_read_config32(dev, 0xa4); - tom <<= 32; - tom |= pci_read_config32(dev, 0xa0) & ~1; - - printk(BIOS_DEBUG, "TOUUD 0x%llx TOLUD 0x%08x TOM 0x%llx\n", - touud, tolud, tom); - - /* ME UMA needs excluding if total memory <4GB */ - me_base = pci_read_config32(dev, 0x74); - me_base <<= 32; - me_base |= pci_read_config32(dev, 0x70); - - printk(BIOS_DEBUG, "MEBASE 0x%llx\n", me_base); - - tomk = tolud >> 10; - if (me_base == tolud) { - /* ME is from MEBASE-TOM */ - uma_size = (tom - me_base) >> 10; - /* Increment TOLUD to account for ME as RAM */ - tolud += uma_size << 10; - /* UMA starts at old TOLUD */ - uma_memory_base = tomk * 1024ULL; - uma_memory_size = uma_size * 1024ULL; - printk(BIOS_DEBUG, "ME UMA base 0x%llx size %uM\n", - me_base, uma_size >> 10); - } + /* If not enabled don't report it. */ + if (!(bar & 0x1)) + return 0; + + /* Knock down the enable bit. */ + *base = bar & ~1; - /* Graphics memory comes next */ - ggc = pci_read_config16(dev, GGC); - if (!(ggc & 2)) { - printk(BIOS_DEBUG, "IGD decoded, subtracting "); - - /* Graphics memory */ - uma_size = ((ggc >> 3) & 0x1f) * 32 * 1024ULL; - printk(BIOS_DEBUG, "%uM UMA", uma_size >> 10); - tomk -= uma_size; - uma_memory_base = tomk * 1024ULL; - uma_memory_size += uma_size * 1024ULL; - - /* GTT Graphics Stolen Memory Size (GGMS) */ - uma_size = ((ggc >> 8) & 0x3) * 1024ULL; - tomk -= uma_size; - uma_memory_base = tomk * 1024ULL; - uma_memory_size += uma_size * 1024ULL; - printk(BIOS_DEBUG, " and %uM GTT\n", uma_size >> 10); + return 1; +} + +struct fixed_mmio_descriptor { + unsigned int index; + u32 size; + int (*get_resource)(device_t dev, unsigned int index, + u32 *base, u32 *size); + const char *description; +}; + +#define SIZE_KB(x) ((x)*1024) +struct fixed_mmio_descriptor mc_fixed_resources[] = { + { PCIEXBAR, SIZE_KB(0), get_pcie_bar, "PCIEXBAR" }, + { MCHBAR, SIZE_KB(32), get_bar, "MCHBAR" }, + { DMIBAR, SIZE_KB(4), get_bar, "DMIBAR" }, + { EPBAR, SIZE_KB(4), get_bar, "EPBAR" }, + { 0x5420, SIZE_KB(4), get_bar_in_mchbar, "GDXCBAR" }, + { 0x5408, SIZE_KB(16), get_bar_in_mchbar, "EDRAMBAR" }, +}; +#undef SIZE_KB + +/* + * Add all known fixed MMIO ranges that hang off the host bridge/memory + * controller device. + */ +static void mc_add_fixed_mmio_resources(device_t dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mc_fixed_resources); i++) { + u32 base; + u32 size; + struct resource *resource; + unsigned int index; + + size = mc_fixed_resources[i].size; + index = mc_fixed_resources[i].index; + if (!mc_fixed_resources[i].get_resource(dev, index, + &base, &size)) + continue; + + resource = new_resource(dev, mc_fixed_resources[i].index); + resource->flags = IORESOURCE_MEM | IORESOURCE_FIXED | + IORESOURCE_STORED | IORESOURCE_RESERVE | + IORESOURCE_ASSIGNED; + resource->base = base; + resource->size = size; + printk(BIOS_DEBUG, "%s: Adding %s @ %x 0x%08lx-0x%08lx.\n", + __func__, mc_fixed_resources[i].description, index, + (unsigned long)base, (unsigned long)(base + size - 1)); } +} - /* Calculate TSEG size from its base which must be below GTT */ - tseg_base = pci_read_config32(dev, 0xb8); - uma_size = (uma_memory_base - tseg_base) >> 10; - tomk -= uma_size; - uma_memory_base = tomk * 1024ULL; - uma_memory_size += uma_size * 1024ULL; - printk(BIOS_DEBUG, "TSEG base 0x%08x size %uM\n", - tseg_base, uma_size >> 10); +/* Host Memory Map: + * + * +--------------------------+ TOUUD + * | | + * +--------------------------+ 4GiB + * | PCI Address Space | + * +--------------------------+ TOLUD (also maps into MC address space) + * | iGD | + * +--------------------------+ BDSM + * | GTT | + * +--------------------------+ BGSM + * | TSEG | + * +--------------------------+ TSEGMB + * | Usage DRAM | + * +--------------------------+ 0 + * + * Some of the base registers above can be equal making the size of those + * regions 0. The reason is because the memory controller internally subtracts + * the base registers from each other to determine sizes of the regions. In + * other words, the memory map is in a fixed order no matter what. + */ - printk(BIOS_INFO, "Available memory below 4GB: %lluM\n", tomk >> 10); +struct map_entry { + int reg; + int is_64_bit; + int is_limit; + const char *description; +}; - /* Report the memory regions */ - ram_resource(dev, 3, 0, legacy_hole_base_k); - ram_resource(dev, 4, legacy_hole_base_k + legacy_hole_size_k, - (tomk - (legacy_hole_base_k + legacy_hole_size_k))); +static void read_map_entry(device_t dev, struct map_entry *entry, + uint64_t *result) +{ + uint64_t value; + uint64_t mask; - /* - * If >= 4GB installed then memory from TOLUD to 4GB - * is remapped above TOM, TOUUD will account for both - */ - touud >>= 10; /* Convert to KB */ - if (touud > 4096 * 1024) { - ram_resource(dev, 5, 4096 * 1024, touud - (4096 * 1024)); - printk(BIOS_INFO, "Available memory above 4GB: %lluM\n", - (touud >> 10) - 4096); + /* All registers are on a 1MiB granularity. */ + mask = ((1ULL<<20)-1); + mask = ~mask; + + value = 0; + + if (entry->is_64_bit) { + value = pci_read_config32(dev, entry->reg + 4); + value <<= 32; } - add_fixed_resources(dev, 6); + value |= pci_read_config32(dev, entry->reg); + value &= mask; - assign_resources(dev->link_list); + if (entry->is_limit) + value |= ~mask; - /* Leave some space for ACPI, PIRQ and MP tables */ - high_tables_base = (tomk * 1024) - HIGH_MEMORY_SIZE; - high_tables_size = HIGH_MEMORY_SIZE; + *result = value; } - /* TODO We could determine how many PCIe busses we need in - * the bar. For now that number is hardcoded to a max of 64. - * See e7525/northbridge.c for an example. - */ -static struct device_operations pci_domain_ops = { - .read_resources = pci_domain_read_resources, - .set_resources = pci_domain_set_resources, - .enable_resources = NULL, - .init = NULL, - .scan_bus = pci_domain_scan_bus, -#if CONFIG_MMCONF_SUPPORT_DEFAULT - .ops_pci_bus = &pci_ops_mmconf, -#else - .ops_pci_bus = &pci_cf8_conf1, -#endif +#define MAP_ENTRY(reg_, is_64_, is_limit_, desc_) \ + { \ + .reg = reg_, \ + .is_64_bit = is_64_, \ + .is_limit = is_limit_, \ + .description = desc_, \ + } + +#define MAP_ENTRY_BASE_64(reg_, desc_) \ + MAP_ENTRY(reg_, 1, 0, desc_) +#define MAP_ENTRY_LIMIT_64(reg_, desc_) \ + MAP_ENTRY(reg_, 1, 1, desc_) +#define MAP_ENTRY_BASE_32(reg_, desc_) \ + MAP_ENTRY(reg_, 0, 0, desc_) + +enum { + TOM_REG, + TOUUD_REG, + MESEG_BASE_REG, + MESEG_LIMIT_REG, + REMAP_BASE_REG, + REMAP_LIMIT_REG, + TOLUD_REG, + BGSM_REG, + BDSM_REG, + TSEG_REG, + // Must be last. + NUM_MAP_ENTRIES }; -static void mc_read_resources(device_t dev) +static struct map_entry memory_map[NUM_MAP_ENTRIES] = { + [TOM_REG] = MAP_ENTRY_BASE_64(TOM, "TOM"), + [TOUUD_REG] = MAP_ENTRY_BASE_64(TOUUD, "TOUUD"), + [MESEG_BASE_REG] = MAP_ENTRY_BASE_64(MESEG_BASE, "MESEG_BASE"), + [MESEG_LIMIT_REG] = MAP_ENTRY_LIMIT_64(MESEG_LIMIT, "MESEG_LIMIT"), + [REMAP_BASE_REG] = MAP_ENTRY_BASE_64(REMAPBASE, "REMAP_BASE"), + [REMAP_LIMIT_REG] = MAP_ENTRY_LIMIT_64(REMAPLIMIT, "REMAP_LIMIT"), + [TOLUD_REG] = MAP_ENTRY_BASE_32(TOLUD, "TOLUD"), + [BGSM_REG] = MAP_ENTRY_BASE_32(BDSM, "BDSM"), + [BDSM_REG] = MAP_ENTRY_BASE_32(BGSM, "BGSM"), + [TSEG_REG] = MAP_ENTRY_BASE_32(TSEG, "TESGMB"), +}; + +static void mc_read_map_entries(device_t dev, uint64_t *values) { + int i; + for (i = 0; i < NUM_MAP_ENTRIES; i++) { + read_map_entry(dev, &memory_map[i], &values[i]); + } +} + +static void mc_report_map_entries(device_t dev, uint64_t *values) +{ + int i; + for (i = 0; i < NUM_MAP_ENTRIES; i++) { + printk(BIOS_DEBUG, "MC MAP: %s: 0x%llx\n", + memory_map[i].description, values[i]); + } + /* One can validate the BDSM and BGSM against the GGC. */ + printk(BIOS_DEBUG, "MC MAP: GGC: 0x%x\n", pci_read_config16(dev, GGC)); +} + +static void mc_add_dram_resources(device_t dev) +{ + unsigned long base_k, size_k; + unsigned long index; struct resource *resource; + uint64_t mc_values[NUM_MAP_ENTRIES]; - pci_dev_read_resources(dev); + /* Read in the MAP registers and report their values. */ + mc_read_map_entries(dev, &mc_values[0]); + mc_report_map_entries(dev, &mc_values[0]); - /* So, this is one of the big mysteries in the coreboot resource - * allocator. This resource should make sure that the address space - * of the PCIe memory mapped config space bar. But it does not. + /* + * There are 4 host memory ranges that should be added: + * - 0 -> 0xa0000 : cacheable + * - 0xc0000 -> TSEG : cacheable + * - TESG -> TOLUD: not cacheable with standard MTRRs and reserved + * - 4GiB -> TOUUD: cacheable + * + * The range 0xa0000 -> 0xc0000 does not have any resources + * associated with it to handle legacy VGA memory. If this range + * is not omitted the mtrr code will setup the area as cacheable + * causing VGA access to not work. + * + * The resource index starts low and should not meet or exceed + * PCI_BASE_ADDRESS_0. In this case there are only 3 entries so there + * are no conflicts in the index space. */ + index = 0; + + /* 0 - > 0xa0000 */ + base_k = 0; + size_k = 0xa0000 >> 10; + ram_resource(dev, index++, base_k, size_k); + + /* 0xa0000 -> TSEG */ + base_k = 0xc0000 >> 10; + size_k = (unsigned long)(mc_values[TSEG_REG] >> 10) - base_k; + ram_resource(dev, index++, base_k, size_k); + + /* TSEG -> TOLUD */ + resource = new_resource(dev, index++); + resource->base = mc_values[TSEG_REG]; + resource->size = mc_values[TOLUD_REG] - resource->base; + resource->flags = IORESOURCE_MEM | IORESOURCE_FIXED | + IORESOURCE_STORED | IORESOURCE_RESERVE | + IORESOURCE_ASSIGNED; + + /* 4GiB -> TOUUD */ + base_k = 4096 * 1024; /* 4GiB */ + size_k = (unsigned long)(mc_values[TOUUD_REG] >> 10) - base_k; + ram_resource(dev, index++, base_k, size_k); + + mmio_resource(dev, index++, legacy_hole_base_k, legacy_hole_size_k); +#if CONFIG_CHROMEOS_RAMOOPS + mmio_resource(dev, index++, CONFIG_CHROMEOS_RAMOOPS_RAM_START >> 10, + CONFIG_CHROMEOS_RAMOOPS_RAM_SIZE >> 10); +#endif - /* We use 0xcf as an unused index for our PCIe bar so that we find it again */ - resource = new_resource(dev, 0xcf); - resource->base = DEFAULT_PCIEXBAR; - resource->size = 64 * 1024 * 1024; /* 64MB hard coded PCIe config space */ - resource->flags = - IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | - IORESOURCE_ASSIGNED; - printk(BIOS_DEBUG, "Adding PCIe enhanced config space BAR 0x%08lx-0x%08lx.\n", - (unsigned long)(resource->base), (unsigned long)(resource->base + resource->size)); + /* Leave some space for ACPI, PIRQ and MP tables */ + high_tables_size = HIGH_MEMORY_SIZE; + high_tables_base = mc_values[TSEG_REG] - high_tables_size; } -static void mc_set_resources(device_t dev) +static void mc_read_resources(device_t dev) { - struct resource *resource; + /* Read standard PCI resources. */ + pci_dev_read_resources(dev); - /* Report the PCIe BAR */ - resource = find_resource(dev, 0xcf); - if (resource) { - report_resource_stored(dev, resource, "<mmconfig>"); - } + /* Add all fixed MMIO resources. */ + mc_add_fixed_mmio_resources(dev); - /* And call the normal set_resources */ - pci_dev_set_resources(dev); + /* Calculate and add DRAM resources. */ + mc_add_dram_resources(dev); } static void intel_set_subsystem(device_t dev, unsigned vendor, unsigned device) @@ -453,7 +532,7 @@ static struct pci_operations intel_pci_ops = { static struct device_operations mc_ops = { .read_resources = mc_read_resources, - .set_resources = mc_set_resources, + .set_resources = pci_dev_set_resources, .enable_resources = pci_dev_enable_resources, .init = northbridge_init, .enable = northbridge_enable, |