diff --git a/src/northbridge/intel/sandybridge/chip.h b/src/northbridge/intel/sandybridge/chip.h index d002824287..7dddb8abd0 100644 --- a/src/northbridge/intel/sandybridge/chip.h +++ b/src/northbridge/intel/sandybridge/chip.h @@ -52,6 +52,72 @@ struct northbridge_intel_sandybridge_config { * Maximum PCI mmio size in MiB. */ u16 pci_mmio_size; + + /* Data for RAM init */ + + /* DIMM SPD address. Use 8bit notation where BIT0 is always zero. */ + u8 spd_addresses[4]; + + /* PEI data for RAM init and early silicon init */ + u8 ts_addresses[4]; + + bool ec_present; + bool ddr3lv_support; + + /* N mode functionality. Leave this setting at 0. + * 0 Auto + * 1 1N + * 2 2N + */ + enum { + DDR_NMODE_AUTO = 0, + DDR_NMODE_1N, + DDR_NMODE_2N, + } nmode; + + /* DDR refresh rate config. JEDEC Standard No.21-C Annex K allows + * for DIMM SPD data to specify whether double-rate is required for + * extended operating temperature range. + * 0 Enable double rate based upon temperature thresholds + * 1 Normal rate + * 2 Always enable double rate + */ + enum { + DDR_REFRESH_RATE_TEMP_THRES = 0, + DDR_REFRESH_REATE_NORMAL, + DDR_REFRESH_RATE_DOUBLE, + } ddr_refresh_rate_config; + + /* + * USB Port Configuration: + * [0] = enable + * [1] = overcurrent pin + * [2] = length + * + * Ports 0-7 can be mapped to OC0-OC3 + * Ports 8-13 can be mapped to OC4-OC7 + * + * Port Length + * MOBILE: + * < 0x050 = Setting 1 (back panel, 1-5in, lowest tx amplitude) + * < 0x140 = Setting 2 (back panel, 5-14in, highest tx amplitude) + * DESKTOP: + * < 0x080 = Setting 1 (front/back panel, <8in, lowest tx amplitude) + * < 0x130 = Setting 2 (back panel, 8-13in, higher tx amplitude) + * < 0x150 = Setting 3 (back panel, 13-15in, highest tx amplitude) + */ + u16 usb_port_config[16][3]; + + struct { + /* 0: Disable, 1: Enable, 2: Auto, 3: Smart Auto */ + u8 mode : 2; + /* 4 bit mask, 1: switchable, 0: not switchable */ + u8 hs_port_switch_mask : 4; + /* 0: No xHCI preOS driver, 1: xHCI preOS driver */ + u8 preboot_support : 1; + /* 0: Disable, 1: Enable */ + u8 xhci_streams : 1; + } usb3; }; #endif /* NORTHBRIDGE_INTEL_SANDYBRIDGE_CHIP_H */ diff --git a/src/northbridge/intel/sandybridge/raminit_mrc.c b/src/northbridge/intel/sandybridge/raminit_mrc.c index 1c9e021025..a35d9d814e 100644 --- a/src/northbridge/intel/sandybridge/raminit_mrc.c +++ b/src/northbridge/intel/sandybridge/raminit_mrc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include "raminit.h" #include "pei_data.h" #include "sandybridge.h" +#include "chip.h" #include #include @@ -275,6 +277,89 @@ struct mrc_var_data { u32 reserved[4]; } __packed; +static void northbridge_fill_pei_data(struct pei_data *pei_data) +{ + pei_data->mchbar = (uintptr_t)DEFAULT_MCHBAR; + pei_data->dmibar = (uintptr_t)DEFAULT_DMIBAR; + pei_data->epbar = DEFAULT_EPBAR; + pei_data->pciexbar = CONFIG_MMCONF_BASE_ADDRESS; + pei_data->hpet_address = CONFIG_HPET_ADDRESS; + pei_data->thermalbase = 0xfed08000; + pei_data->system_type = get_platform_type() == PLATFORM_MOBILE ? 0 : 1; + pei_data->tseg_size = CONFIG_SMM_TSEG_SIZE; + + if ((cpu_get_cpuid() & 0xffff0) == 0x306a0) { + const struct device *dev = pcidev_on_root(1, 0); + pei_data->pcie_init = dev && dev->enabled; + } else { + pei_data->pcie_init = 0; + } +} + +static void southbridge_fill_pei_data(struct pei_data *pei_data) +{ + const struct device *dev = pcidev_on_root(0x19, 0); + + pei_data->smbusbar = SMBUS_IO_BASE; + pei_data->wdbbar = 0x4000000; + pei_data->wdbsize = 0x1000; + pei_data->rcba = (uintptr_t)DEFAULT_RCBABASE; + pei_data->pmbase = DEFAULT_PMBASE; + pei_data->gpiobase = DEFAULT_GPIOBASE; + pei_data->gbe_enable = dev && dev->enabled; +} + +static void devicetree_fill_pei_data(struct pei_data *pei_data) +{ + const struct northbridge_intel_sandybridge_config *cfg; + + const struct device *dev = pcidev_on_root(0, 0); + if (!dev || !dev->chip_info) + return; + + cfg = dev->chip_info; + + switch (cfg->max_mem_clock_mhz) { + /* MRC only supports fixed numbers of frequencies */ + default: + printk(BIOS_WARNING, "RAMINIT: Limiting DDR3 clock to 800 Mhz\n"); + /* fallthrough */ + case 400: + pei_data->max_ddr3_freq = 800; + break; + case 533: + pei_data->max_ddr3_freq = 1066; + break; + case 666: + pei_data->max_ddr3_freq = 1333; + break; + case 800: + pei_data->max_ddr3_freq = 1600; + break; + + } + + memcpy(pei_data->spd_addresses, cfg->spd_addresses, + sizeof(pei_data->spd_addresses)); + + memcpy(pei_data->ts_addresses, cfg->ts_addresses, + sizeof(pei_data->ts_addresses)); + + pei_data->ec_present = cfg->ec_present; + pei_data->ddr3lv_support = cfg->ddr3lv_support; + + pei_data->nmode = cfg->nmode; + pei_data->ddr_refresh_rate_config = cfg->ddr_refresh_rate_config; + + memcpy(pei_data->usb_port_config, cfg->usb_port_config, + sizeof(pei_data->usb_port_config)); + + pei_data->usb3.mode = cfg->usb3.mode; + pei_data->usb3.hs_port_switch_mask = cfg->usb3.hs_port_switch_mask; + pei_data->usb3.preboot_support = cfg->usb3.preboot_support; + pei_data->usb3.xhci_streams = cfg->usb3.xhci_streams; +} + void perform_raminit(int s3resume) { int cbmem_was_initted; @@ -285,10 +370,25 @@ void perform_raminit(int s3resume) if (!mainboard_should_reset_usb(s3resume)) enable_usb_bar(); + memset(&pei_data, 0, sizeof(pei_data)); + pei_data.pei_version = PEI_VERSION, + + northbridge_fill_pei_data(&pei_data); + southbridge_fill_pei_data(&pei_data); + devicetree_fill_pei_data(&pei_data); mainboard_fill_pei_data(&pei_data); post_code(0x3a); + /* Fill after mainboard_fill_pei_data as it might provide spd_data */ + pei_data.dimm_channel0_disabled = + (!pei_data.spd_addresses[0] && !pei_data.spd_data[0][0]) + + (!pei_data.spd_addresses[1] && !pei_data.spd_data[1][0]) * 2; + + pei_data.dimm_channel1_disabled = + (!pei_data.spd_addresses[2] && !pei_data.spd_data[2][0]) + + (!pei_data.spd_addresses[3] && !pei_data.spd_data[3][0]) * 2; + /* Fix spd_data. MRC only uses spd_data[0] and ignores the other */ for (size_t i = 1; i < ARRAY_SIZE(pei_data.spd_data); i++) { if (pei_data.spd_data[i][0] && !pei_data.spd_data[0][0]) {