X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=arch%2Fx86%2Fcpu%2Fivybridge%2Fsdram.c;h=4372a5caf2d23e8942a078e580cef4014d37e530;hb=a69fdc7787bfa2f27eed74c2ee58c28ce932d502;hp=df2b9901fc0cc8a64944b544699e55b7d4c8bf0f;hpb=878cd63e02f63f245182a101807186b44e20f116;p=platform%2Fkernel%2Fu-boot.git diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c index df2b990..4372a5c 100644 --- a/arch/x86/cpu/ivybridge/sdram.c +++ b/arch/x86/cpu/ivybridge/sdram.c @@ -14,9 +14,15 @@ #include #include #include +#include +#include +#include +#include #include #include #include +#include +#include #include #include #include @@ -26,6 +32,10 @@ DECLARE_GLOBAL_DATA_PTR; +#define CMOS_OFFSET_MRC_SEED 152 +#define CMOS_OFFSET_MRC_SEED_S3 156 +#define CMOS_OFFSET_MRC_SEED_CHK 160 + /* * This function looks for the highest region of memory lower than 4GB which * has enough space for U-Boot where U-Boot is aligned on a page boundary. @@ -79,6 +89,130 @@ void dram_init_banksize(void) } } +static int read_seed_from_cmos(struct pei_data *pei_data) +{ + u16 c1, c2, checksum, seed_checksum; + struct udevice *dev; + int ret = 0; + + ret = uclass_get_device(UCLASS_RTC, 0, &dev); + if (ret) { + debug("Cannot find RTC: err=%d\n", ret); + return -ENODEV; + } + + /* + * Read scrambler seeds from CMOS RAM. We don't want to store them in + * SPI flash since they change on every boot and that would wear down + * the flash too much. So we store these in CMOS and the large MRC + * data in SPI flash. + */ + ret = rtc_read32(dev, CMOS_OFFSET_MRC_SEED, &pei_data->scrambler_seed); + if (!ret) { + ret = rtc_read32(dev, CMOS_OFFSET_MRC_SEED_S3, + &pei_data->scrambler_seed_s3); + } + if (ret) { + debug("Failed to read from RTC %s\n", dev->name); + return ret; + } + + debug("Read scrambler seed 0x%08x from CMOS 0x%02x\n", + pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED); + debug("Read S3 scrambler seed 0x%08x from CMOS 0x%02x\n", + pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3); + + /* Compute seed checksum and compare */ + c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed, + sizeof(u32)); + c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3, + sizeof(u32)); + checksum = add_ip_checksums(sizeof(u32), c1, c2); + + seed_checksum = rtc_read8(dev, CMOS_OFFSET_MRC_SEED_CHK); + seed_checksum |= rtc_read8(dev, CMOS_OFFSET_MRC_SEED_CHK + 1) << 8; + + if (checksum != seed_checksum) { + debug("%s: invalid seed checksum\n", __func__); + pei_data->scrambler_seed = 0; + pei_data->scrambler_seed_s3 = 0; + return -EINVAL; + } + + return 0; +} + +static int prepare_mrc_cache(struct pei_data *pei_data) +{ + struct mrc_data_container *mrc_cache; + struct mrc_region entry; + int ret; + + ret = read_seed_from_cmos(pei_data); + if (ret) + return ret; + ret = mrccache_get_region(NULL, &entry); + if (ret) + return ret; + mrc_cache = mrccache_find_current(&entry); + if (!mrc_cache) + return -ENOENT; + + pei_data->mrc_input = mrc_cache->data; + pei_data->mrc_input_len = mrc_cache->data_size; + debug("%s: at %p, size %x checksum %04x\n", __func__, + pei_data->mrc_input, pei_data->mrc_input_len, + mrc_cache->checksum); + + return 0; +} + +static int write_seeds_to_cmos(struct pei_data *pei_data) +{ + u16 c1, c2, checksum; + struct udevice *dev; + int ret = 0; + + ret = uclass_get_device(UCLASS_RTC, 0, &dev); + if (ret) { + debug("Cannot find RTC: err=%d\n", ret); + return -ENODEV; + } + + /* Save the MRC seed values to CMOS */ + rtc_write32(dev, CMOS_OFFSET_MRC_SEED, pei_data->scrambler_seed); + debug("Save scrambler seed 0x%08x to CMOS 0x%02x\n", + pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED); + + rtc_write32(dev, CMOS_OFFSET_MRC_SEED_S3, pei_data->scrambler_seed_s3); + debug("Save s3 scrambler seed 0x%08x to CMOS 0x%02x\n", + pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3); + + /* Save a simple checksum of the seed values */ + c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed, + sizeof(u32)); + c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3, + sizeof(u32)); + checksum = add_ip_checksums(sizeof(u32), c1, c2); + + rtc_write8(dev, CMOS_OFFSET_MRC_SEED_CHK, checksum & 0xff); + rtc_write8(dev, CMOS_OFFSET_MRC_SEED_CHK + 1, (checksum >> 8) & 0xff); + + return 0; +} + +/* Use this hook to save our SDRAM parameters */ +int misc_init_r(void) +{ + int ret; + + ret = mrccache_save(); + if (ret) + printf("Unable to save MRC data: %d\n", ret); + + return 0; +} + static const char *const ecc_decoder[] = { "inactive", "active on IO", @@ -141,6 +275,11 @@ static asmlinkage void console_tx_byte(unsigned char byte) #endif } +static int recovery_mode_enabled(void) +{ + return false; +} + /** * Find the PEI executable in the ROM and execute it. * @@ -165,11 +304,21 @@ int sdram_initialise(struct pei_data *pei_data) debug("Starting UEFI PEI System Agent\n"); + /* + * Do not pass MRC data in for recovery mode boot, + * Always pass it in for S3 resume. + */ + if (!recovery_mode_enabled() || + pei_data->boot_mode == PEI_BOOT_RESUME) { + ret = prepare_mrc_cache(pei_data); + if (ret) + debug("prepare_mrc_cache failed: %d\n", ret); + } + /* If MRC data is not found we cannot continue S3 resume. */ if (pei_data->boot_mode == PEI_BOOT_RESUME && !pei_data->mrc_input) { debug("Giving up in sdram_initialize: No MRC data\n"); - outb(0x6, PORT_RESET); - cpu_hlt(); + reset_cpu(0); } /* Pass console handler in pei_data */ @@ -177,13 +326,15 @@ int sdram_initialise(struct pei_data *pei_data) debug("PEI data at %p, size %x:\n", pei_data, sizeof(*pei_data)); - data = (char *)CONFIG_X86_MRC_START; + data = (char *)CONFIG_X86_MRC_ADDR; if (data) { int rv; int (*func)(struct pei_data *); + ulong start; debug("Calling MRC at %p\n", data); post_code(POST_PRE_MRC); + start = get_timer(0); func = (int (*)(struct pei_data *))data; rv = func(pei_data); post_code(POST_MRC); @@ -201,6 +352,7 @@ int sdram_initialise(struct pei_data *pei_data) printf("Nonzero MRC return value.\n"); return -EFAULT; } + debug("MRC execution time %lu ms\n", get_timer(start)); } else { printf("UEFI PEI System Agent not found.\n"); return -ENOSYS; @@ -215,12 +367,14 @@ int sdram_initialise(struct pei_data *pei_data) debug("System Agent Version %d.%d.%d Build %d\n", version >> 24 , (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); + debug("MRC output data length %#x at %p\n", pei_data->mrc_output_len, + pei_data->mrc_output); /* * Send ME init done for SandyBridge here. This is done inside the * SystemAgent binary on IvyBridge */ - done = pci_read_config32(PCH_DEV, PCI_DEVICE_ID); + done = x86_pci_read_config32(PCH_DEV, PCI_DEVICE_ID); done &= BASE_REV_MASK; if (BASE_REV_SNB == done) intel_early_me_init_done(ME_INIT_STATUS_SUCCESS); @@ -230,9 +384,27 @@ int sdram_initialise(struct pei_data *pei_data) post_system_agent_init(pei_data); report_memory_config(); + /* S3 resume: don't save scrambler seed or MRC data */ + if (pei_data->boot_mode != PEI_BOOT_RESUME) { + /* + * This will be copied to SDRAM in reserve_arch(), then written + * to SPI flash in mrccache_save() + */ + gd->arch.mrc_output = (char *)pei_data->mrc_output; + gd->arch.mrc_output_len = pei_data->mrc_output_len; + ret = write_seeds_to_cmos(pei_data); + if (ret) + debug("Failed to write seeds to CMOS: %d\n", ret); + } + return 0; } +int reserve_arch(void) +{ + return mrccache_reserve(); +} + static int copy_spd(struct pei_data *peid) { const int gpio_vector[] = {41, 42, 43, 10, -1}; @@ -361,24 +533,24 @@ static int sdram_find(pci_dev_t dev) */ /* Top of Upper Usable DRAM, including remap */ - touud = pci_read_config32(dev, TOUUD+4); + touud = x86_pci_read_config32(dev, TOUUD+4); touud <<= 32; - touud |= pci_read_config32(dev, TOUUD); + touud |= x86_pci_read_config32(dev, TOUUD); /* Top of Lower Usable DRAM */ - tolud = pci_read_config32(dev, TOLUD); + tolud = x86_pci_read_config32(dev, TOLUD); /* Top of Memory - does not account for any UMA */ - tom = pci_read_config32(dev, 0xa4); + tom = x86_pci_read_config32(dev, 0xa4); tom <<= 32; - tom |= pci_read_config32(dev, 0xa0); + tom |= x86_pci_read_config32(dev, 0xa0); debug("TOUUD %llx TOLUD %08x TOM %llx\n", touud, tolud, tom); /* ME UMA needs excluding if total memory <4GB */ - me_base = pci_read_config32(dev, 0x74); + me_base = x86_pci_read_config32(dev, 0x74); me_base <<= 32; - me_base |= pci_read_config32(dev, 0x70); + me_base |= x86_pci_read_config32(dev, 0x70); debug("MEBASE %llx\n", me_base); @@ -396,7 +568,7 @@ static int sdram_find(pci_dev_t dev) } /* Graphics memory comes next */ - ggc = pci_read_config16(dev, GGC); + ggc = x86_pci_read_config16(dev, GGC); if (!(ggc & 2)) { debug("IGD decoded, subtracting "); @@ -416,7 +588,7 @@ static int sdram_find(pci_dev_t dev) } /* Calculate TSEG size from its base which must be below GTT */ - tseg_base = pci_read_config32(dev, 0xb8); + tseg_base = x86_pci_read_config32(dev, 0xb8); uma_size = (uma_memory_base - tseg_base) >> 10; tomk -= uma_size; uma_memory_base = tomk * 1024ULL; @@ -430,6 +602,15 @@ static int sdram_find(pci_dev_t dev) add_memory_area(info, (2 << 28) + (2 << 20), 4 << 28); add_memory_area(info, (4 << 28) + (2 << 20), tseg_base); add_memory_area(info, 1ULL << 32, touud); + + /* Add MTRRs for memory */ + mtrr_add_request(MTRR_TYPE_WRBACK, 0, 2ULL << 30); + mtrr_add_request(MTRR_TYPE_WRBACK, 2ULL << 30, 512 << 20); + mtrr_add_request(MTRR_TYPE_WRBACK, 0xaULL << 28, 256 << 20); + mtrr_add_request(MTRR_TYPE_UNCACHEABLE, tseg_base, 16 << 20); + mtrr_add_request(MTRR_TYPE_UNCACHEABLE, tseg_base + (16 << 20), + 32 << 20); + /* * If >= 4GB installed then memory from TOLUD to 4GB * is remapped above TOM, TOUUD will account for both @@ -494,7 +675,7 @@ int dram_init(void) .mchbar = DEFAULT_MCHBAR, .dmibar = DEFAULT_DMIBAR, .epbar = DEFAULT_EPBAR, - .pciexbar = CONFIG_MMCONF_BASE_ADDRESS, + .pciexbar = CONFIG_PCIE_ECAM_BASE, .smbusbar = SMBUS_IO_BASE, .wdbbar = 0x4000000, .wdbsize = 0x1000, @@ -546,7 +727,7 @@ int dram_init(void) int ret; debug("Boot mode %d\n", gd->arch.pei_boot_mode); - debug("mcr_input %p\n", pei_data.mrc_input); + debug("mrc_input %p\n", pei_data.mrc_input); pei_data.boot_mode = gd->arch.pei_boot_mode; ret = copy_spd(&pei_data); if (!ret)