diff --git a/src/northbridge/intel/haswell/memmap.c b/src/northbridge/intel/haswell/memmap.c index 807ee2a358..ac36e25999 100644 --- a/src/northbridge/intel/haswell/memmap.c +++ b/src/northbridge/intel/haswell/memmap.c @@ -9,27 +9,56 @@ #include #include #include +#include + #include "haswell.h" -static uintptr_t smm_region_start(void) +static uintptr_t northbridge_get_tseg_base(void) +{ + return ALIGN_DOWN(pci_read_config32(HOST_BRIDGE, TSEG), 1 * MiB); +} + +static size_t northbridge_get_tseg_size(void) +{ + return CONFIG_SMM_TSEG_SIZE; +} + +/* + * Return the topmost memory address below 4 GiB available for general + * use, from software's view of memory. Do not confuse this with TOLUD, + * which applies to the DRAM as viewed by the memory controller itself. + */ +static uintptr_t top_of_low_usable_memory(void) { /* - * Base of TSEG is top of usable DRAM below 4GiB. The register has - * 1 MiB alignment. + * Base of DPR is top of usable DRAM below 4 GiB. However, DPR + * isn't always enabled. Unlike most memory map registers, the + * DPR register stores top of DPR instead of its base address. + * Unless binary-patched, Haswell MRC.bin does not enable DPR. + * Top of DPR is R/O, and mirrored from TSEG base by hardware. */ - uintptr_t tom = pci_read_config32(HOST_BRIDGE, TSEG); - return ALIGN_DOWN(tom, 1 * MiB); + uintptr_t tolum = northbridge_get_tseg_base(); + + const union dpr_register dpr = { + .raw = pci_read_config32(HOST_BRIDGE, DPR), + }; + + /* Subtract DMA Protected Range size if enabled */ + if (dpr.epm) + tolum -= dpr.size * MiB; + + return tolum; } void *cbmem_top_chipset(void) { - return (void *)smm_region_start(); + return (void *)top_of_low_usable_memory(); } void smm_region(uintptr_t *start, size_t *size) { - *start = smm_region_start(); - *size = CONFIG_SMM_TSEG_SIZE; + *start = northbridge_get_tseg_base(); + *size = northbridge_get_tseg_size(); } void fill_postcar_frame(struct postcar_frame *pcf) diff --git a/src/northbridge/intel/haswell/northbridge.c b/src/northbridge/intel/haswell/northbridge.c index e1c26d162c..5619d95728 100644 --- a/src/northbridge/intel/haswell/northbridge.c +++ b/src/northbridge/intel/haswell/northbridge.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "chip.h" #include "haswell.h" @@ -162,7 +163,8 @@ static void mc_add_fixed_mmio_resources(struct device *dev) } } -/* Host Memory Map: +/* + * Host Memory Map: * * +--------------------------+ TOUUD * | | @@ -175,6 +177,8 @@ static void mc_add_fixed_mmio_resources(struct device *dev) * +--------------------------+ BGSM * | TSEG | * +--------------------------+ TSEGMB + * | DPR | + * +--------------------------+ (DPR top - DPR size) * | Usage DRAM | * +--------------------------+ 0 * @@ -285,6 +289,12 @@ static void mc_add_dram_resources(struct device *dev, int *resource_cnt) mc_read_map_entries(dev, &mc_values[0]); mc_report_map_entries(dev, &mc_values[0]); + /* The DPR register is special */ + const union dpr_register dpr = { + .raw = pci_read_config32(dev, DPR), + }; + printk(BIOS_DEBUG, "MC MAP: DPR: 0x%x\n", dpr.raw); + /* * These are the host memory ranges that should be added: * - 0 -> 0xa0000: cacheable @@ -318,11 +328,20 @@ static void mc_add_dram_resources(struct device *dev, int *resource_cnt) size_k = (0xa0000 >> 10) - base_k; ram_resource(dev, index++, base_k, size_k); - /* 0xc0000 -> TSEG */ + /* 0xc0000 -> DPR base */ base_k = 0xc0000 >> 10; - size_k = (unsigned long)(mc_values[TSEG_REG] >> 10) - base_k; + size_k = (unsigned long)(mc_values[TSEG_REG] >> 10) - (base_k + dpr.size); ram_resource(dev, index++, base_k, size_k); + /* DPR base -> TSEG */ + if (dpr.size) { + resource = new_resource(dev, index++); + resource->base = (dpr.top - dpr.size) * MiB; + resource->size = dpr.size * MiB; + resource->flags = IORESOURCE_MEM | IORESOURCE_STORED | IORESOURCE_CACHEABLE | + IORESOURCE_RESERVE | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + } + /* TSEG -> BGSM */ resource = new_resource(dev, index++); resource->base = mc_values[TSEG_REG]; diff --git a/src/northbridge/intel/haswell/registers/host_bridge.h b/src/northbridge/intel/haswell/registers/host_bridge.h index d348fd4a61..7746801804 100644 --- a/src/northbridge/intel/haswell/registers/host_bridge.h +++ b/src/northbridge/intel/haswell/registers/host_bridge.h @@ -25,6 +25,9 @@ #define PAVPC 0x58 #define DPR 0x5c +#define DPR_EPM (1 << 2) +#define DPR_PRS (1 << 1) +#define DPR_SIZE_MASK 0xff0 #define PCIEXBAR 0x60 #define DMIBAR 0x68