soc/intel/cannonlake: Perform dram top calculation based on HW registers

This patch ensures that entire system memory calculation is done
based on host bridge registers.

BRANCH=none
BUG=b:63974384
TEST=Build and boot cannonlake RVP successfully with below configurations
1. Booting to OS with no UPD change
2. Enable ProbelessTrace UPD and boot to OS.
3. Enable PRMRR with size 1MB and boot to OS.
4. Enable PRMRR with size 32MB and boot to OS.
5. Enable PRMRR with size 2MB and unable to boot to OS due to
unsupported PRMRR size.
6. Enable C6 DRAM with PRMRR size 0MB and boot to OS.

Change-Id: I0a430a24f52cdf6e2517a49910b77ab08a199ca2
Signed-off-by: Subrata Banik <subrata.banik@intel.com>
Reviewed-on: https://review.coreboot.org/21235
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
Subrata Banik 2017-08-30 18:29:33 +05:30
parent ce90c78d7f
commit a281c0f1bf
3 changed files with 114 additions and 6 deletions

View File

@ -65,8 +65,9 @@
#define HECI1_BASE_ADDRESS 0xFEDA2000 #define HECI1_BASE_ADDRESS 0xFEDA2000
/* CPU Trace reserved memory size */ /* PTT registers */
#define TRACE_MEMORY_SIZE 0x8000000 /* 128MiB */ #define PTT_TXT_BASE_ADDRESS 0xfed30800
#define PTT_PRESENT 0x00070000
/* /*
* I/O port address space * I/O port address space

View File

@ -40,4 +40,7 @@
#define MCH_DDR_POWER_LIMIT_LO 0x58e0 #define MCH_DDR_POWER_LIMIT_LO 0x58e0
#define MCH_DDR_POWER_LIMIT_HI 0x58e4 #define MCH_DDR_POWER_LIMIT_HI 0x58e4
#define IMRBASE 0x6A40
#define IMRLIMIT 0x6A48
#endif #endif

View File

@ -15,10 +15,16 @@
*/ */
#include <arch/io.h> #include <arch/io.h>
#include <cbmem.h> #include <cbmem.h>
#include <chip.h>
#include <console/console.h> #include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <fsp/util.h> #include <fsp/util.h>
#include <intelblocks/systemagent.h>
#include <soc/bootblock.h> #include <soc/bootblock.h>
#include <soc/pci_devs.h>
#include <soc/systemagent.h> #include <soc/systemagent.h>
#include <stdlib.h>
static void *top_of_ram_register(void) static void *top_of_ram_register(void)
{ {
@ -34,15 +40,113 @@ void clear_cbmem_top(void)
write32(top_of_ram_register(), 0); write32(top_of_ram_register(), 0);
} }
static bool is_ptt_enable(void)
{
if ((read32((void *)PTT_TXT_BASE_ADDRESS) & PTT_PRESENT) ==
PTT_PRESENT)
return true;
return false;
}
/*
* Host Memory Map:
*
* +--------------------------+ TOUUD
* | |
* +--------------------------+ 4GiB
* | PCI Address Space |
* +--------------------------+ TOLUD (also maps into MC address space)
* | iGD |
* +--------------------------+ BDSM
* | GTT |
* +--------------------------+ BGSM
* | TSEG |
* +--------------------------+ TSEGMB
* | DMA Protected Region |
* +--------------------------+ DPR
* | PRM (C6DRAM/SGX) |
* +--------------------------+ PRMRR
* | ME Stolen Memory |
* +--------------------------+ ME Stolen
* | PTT |
* +--------------------------+ top_of_ram
* | Reserved - FSP/CBMEM |
* +--------------------------+ TOLUM
* | 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.
*/
static uintptr_t calculate_dram_base(void)
{
const struct soc_intel_cannonlake_config *config;
const struct device *dev;
uintptr_t dram_base;
uintptr_t prmrr_base;
size_t prmrr_size;
size_t imr_size;
dev = dev_find_slot(0, PCI_DEVFN(SA_DEV_SLOT_IGD, 0));
/* Read TOLUD from Host Bridge offset */
dram_base = sa_get_tolud_base();
if (dev->enabled) {
/* Read BDSM from Host Bridge */
dram_base -= sa_get_dsm_size();
/* Read BGSM from Host Bridge */
dram_base -= sa_get_gsm_size();
}
/* Get TSEG size */
dram_base -= sa_get_tseg_size();
/* Get DPR size */
if (IS_ENABLED(CONFIG_SA_ENABLE_DPR))
dram_base -= sa_get_dpr_size();
config = dev->chip_info;
prmrr_size = config->PrmrrSize;
if (prmrr_size > 0) {
/*
* PRMRR Sizes that are > 1MB and < 32MB are
* not supported and will fail out.
*/
if ((prmrr_size > 1*MiB) && (prmrr_size < 32*MiB))
die("PRMRR Sizes that are > 1MB and < 32MB are not"
"supported!\n");
prmrr_base = dram_base - prmrr_size;
if (prmrr_size >= 32*MiB)
prmrr_base = ALIGN_DOWN(prmrr_base, 128*MiB);
dram_base = prmrr_base;
} else if (config->enable_c6dram && prmrr_size == 0) {
/* Allocate PRMRR memory for C6DRAM */
dram_base -= 1*MiB;
}
/* ME stolen memory */
imr_size = MCHBAR32(IMRLIMIT) - MCHBAR32(IMRBASE);
if (imr_size > 0)
dram_base -= imr_size;
if (is_ptt_enable())
dram_base -= 4*KiB; /* Allocate 4KB for PTT if enable */
return dram_base;
}
void cbmem_top_init(void) void cbmem_top_init(void)
{ {
struct range_entry fsp_mem;
uintptr_t top; uintptr_t top;
if (fsp_find_reserved_memory(&fsp_mem)) top = calculate_dram_base();
die("Can't file top of ram.\n");
top = ALIGN_UP(range_entry_base(&fsp_mem), 16 * MiB);
write32(top_of_ram_register(), top); write32(top_of_ram_register(), top);
} }