From a404133547c98094a326f60b83e1576ba94b8c06 Mon Sep 17 00:00:00 2001 From: Mariusz Szafranski Date: Wed, 2 Aug 2017 17:28:17 +0200 Subject: soc/intel/denverton_ns: Add support for Intel Atom C3000 SoC This change adds support for Intel Atom C3000 SoC ("Denverton" and "Denverton-NS"). Code is partially based on Apollo Lake/Skylake code. Change-Id: I53d69aede3b92f1fe06b74a96cc40187fb9825f1 Signed-off-by: Mariusz Szafranski Reviewed-on: https://review.coreboot.org/20861 Tested-by: build bot (Jenkins) Reviewed-by: FEI WANG --- src/soc/intel/denverton_ns/romstage.c | 295 ++++++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 src/soc/intel/denverton_ns/romstage.c (limited to 'src/soc/intel/denverton_ns/romstage.c') diff --git a/src/soc/intel/denverton_ns/romstage.c b/src/soc/intel/denverton_ns/romstage.c new file mode 100644 index 0000000000..512d8ccb3c --- /dev/null +++ b/src/soc/intel/denverton_ns/romstage.c @@ -0,0 +1,295 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 - 2017 Intel Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void __attribute__((weak)) mainboard_config_gpios(void) {} + +#if IS_ENABLED(CONFIG_DISPLAY_HOBS) +static void display_fsp_smbios_memory_info_hob(void) +{ + int channel, dimm; + size_t hob_size; + const DIMM_INFO *dimm_info; + const CHANNEL_INFO *channel_info; + const FSP_SMBIOS_MEMORY_INFO *memory_info_hob; + + /* Locate the memory info HOB */ + memory_info_hob = fsp_find_smbios_memory_info(&hob_size); + + /* Display the data in the FSP_SMBIOS_MEMORY_INFO HOB */ + if (memory_info_hob) { + printk(BIOS_DEBUG, "FSP_SMBIOS_MEMORY_INFO HOB\n"); + printk(BIOS_DEBUG, " 0x%02x: Revision\n", + memory_info_hob->Revision); + printk(BIOS_DEBUG, " 0x%02x: MemoryType\n", + memory_info_hob->MemoryType); + printk(BIOS_DEBUG, " %d: MemoryFrequencyInMHz\n", + memory_info_hob->MemoryFrequencyInMHz); + printk(BIOS_DEBUG, " %d: DataWidth in bits\n", + memory_info_hob->DataWidth); + printk(BIOS_DEBUG, " 0x%02x: ErrorCorrectionType\n", + memory_info_hob->ErrorCorrectionType); + printk(BIOS_DEBUG, " 0x%02x: ChannelCount\n", + memory_info_hob->ChannelCount); + for (channel = 0; channel < memory_info_hob->ChannelCount; + channel++) { + channel_info = &memory_info_hob->ChannelInfo[channel]; + printk(BIOS_DEBUG, " Channel %d\n", channel); + printk(BIOS_DEBUG, " 0x%02x: ChannelId\n", + channel_info->ChannelId); + printk(BIOS_DEBUG, " 0x%02x: DimmCount\n", + channel_info->DimmCount); + for (dimm = 0; dimm < channel_info->DimmCount; + dimm++) { + dimm_info = &channel_info->DimmInfo[dimm]; + printk(BIOS_DEBUG, " DIMM %d\n", dimm); + printk(BIOS_DEBUG, " 0x%02x: DimmId\n", + dimm_info->DimmId); + printk(BIOS_DEBUG, " %d: SizeInMb\n", + dimm_info->SizeInMb); + printk(BIOS_DEBUG, " 0x%04x: MfgId\n", + dimm_info->MfgId); + printk(BIOS_DEBUG, "%*.*s: ModulePartNum\n", + (int)sizeof(dimm_info->ModulePartNum), + (int)sizeof(dimm_info->ModulePartNum), + dimm_info->ModulePartNum); + } + } + } else { + printk(BIOS_DEBUG, "FSP_SMBIOS_MEMORY_INFO HOB not found!!!\n"); + } +} +#endif + +static void early_pmc_init(void) +{ + /* PMC (B0:D31:F2). */ + device_t dev = PCH_PMC_DEV; + + /* Is PMC present */ + if (pci_read_config16(dev, 0) == 0xffff) { + printk(BIOS_ERR, "PMC controller (B0:D31:F2) does not present!\n"); + return; + } + + uint32_t pwrm_base = + pci_read_config32(dev, PMC_PWRM_BASE) & MASK_PMC_PWRM_BASE; + if (!pwrm_base) { + printk(BIOS_ERR, "PWRM base address is not configured!\n"); + return; + } + + /* Workaround for sighting report (doc#: 560805) v1.86. + 42. System Might Hang In AC Power Loss + Problem : + When removing and reapplying AC power to the board, + the system might hang at serial output + 'RESET required : change of frequency' + due to PMC ROM change on B0. + Implication : + 1. This issue is only shown in B0 stepping. + 2. This issue does not impact a system without an RTC battery. + Alternative workaround : + Remove RTC battery on the board if possible. + Status : Plan Fix. + */ + if (silicon_stepping() == SILICON_REV_DENVERTON_B0) { + if (!(pci_read_config32(dev, PMC_GEN_PMCON_B) + & PMC_GEN_PMCON_B_RTC_PWR_STS)) { + if (read32((void *)(pwrm_base + 0x124)) + & ((1 << 11) | (1 << 12))) { + /* Performs a global reset */ + printk(BIOS_DEBUG, + "Requesting Global Reset...\n"); + pci_write_config32(dev, PMC_ETR3, + pci_read_config32(dev, PMC_ETR3) + | PMC_ETR3_CF9GR); + hard_reset(); + } + } + } +} + +static void early_tco_init(void) +{ + /* SMBUS (B0:D31:F4). */ + device_t dev = PCI_DEV(0, SMBUS_DEV, SMBUS_FUNC); + + /* Configure TCO base address */ + if (pci_read_config16(dev, TCOBASE) == 0xffff) { + printk(BIOS_ERR, "SMBus controller (B0:D31:F4) does not present!\n"); + return; + } + uint16_t tco_ctl = pci_read_config16(dev, TCOCTL); + if (tco_ctl & TCOBASE_LOCK) { + printk(BIOS_ERR, "TCO base register already has been locked!\n"); + } else { + pci_write_config16(dev, TCOCTL, tco_ctl & (~TCOBASE_EN)); + pci_write_config16(dev, TCOBASE, DEFAULT_TCO_BASE | 0x1); + pci_write_config16(dev, TCOCTL, tco_ctl | TCOBASE_EN); + } + + uint16_t tco_base = pci_read_config16(dev, TCOBASE) & MASK_TCOBASE; + printk(BIOS_DEBUG, "TCO base address set to 0x%x!\n", tco_base); + + /* Disable the TCO timer expiration from causing a system reset */ + MMIO32_OR(PCH_PCR_ADDRESS(PID_SMB, PCR_SMBUS_GC), + (uint32_t)PCR_SMBUS_GC_NR); + + /* Halt the TCO timer */ + uint16_t reg16 = inw(tco_base + TCO1_CNT); + reg16 |= TCO_TMR_HLT; + outw(reg16, tco_base + TCO1_CNT); + + /* Clear the Second TCO status bit */ + reg16 = inw(tco_base + TCO2_STS); + reg16 |= TCO2_STS_SECOND_TO; + outw(reg16, tco_base + TCO2_STS); +} + +asmlinkage void car_stage_entry(void) +{ + + struct postcar_frame pcf; + uintptr_t top_of_ram; + +#if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) + void *smm_base; + size_t smm_size; + uintptr_t tseg_base; +#endif + + console_init(); + + printk(BIOS_DEBUG, "FSP TempRamInit was successful...\n"); + + mainboard_config_gpios(); + early_tco_init(); + early_pmc_init(); + + fsp_memory_init(false); + +#if IS_ENABLED(CONFIG_DISPLAY_HOBS) + display_fsp_smbios_memory_info_hob(); +#endif + + if (postcar_frame_init(&pcf, 1 * KiB)) + die("Unable to initialize postcar frame.\n"); + + /* + * We need to make sure ramstage will be run cached. At this point exact + * location of ramstage in cbmem is not known. Instruct postcar to cache + * 16 megs under cbmem top which is a safe bet to cover ramstage. + */ + top_of_ram = (uintptr_t)cbmem_top(); + postcar_frame_add_mtrr(&pcf, top_of_ram - 16 * MiB, 16 * MiB, + MTRR_TYPE_WRBACK); + + /* Cache the memory-mapped boot media. */ + if (IS_ENABLED(CONFIG_BOOT_DEVICE_MEMORY_MAPPED)) + postcar_frame_add_mtrr(&pcf, -CONFIG_ROM_SIZE, CONFIG_ROM_SIZE, + MTRR_TYPE_WRPROT); +#if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) + /* + * Cache the TSEG region at the top of ram. This region is + * not restricted to SMM mode until SMM has been relocated. + * By setting the region to cacheable it provides faster access + * when relocating the SMM handler as well as using the TSEG + * region for other purposes. + */ + smm_region(&smm_base, &smm_size); + tseg_base = (uintptr_t)smm_base; + postcar_frame_add_mtrr(&pcf, tseg_base, smm_size, MTRR_TYPE_WRBACK); +#endif + + run_postcar_phase(&pcf); +} + +static void soc_memory_init_params(FSP_M_CONFIG *m_cfg) +{ + FSPM_UPD *mupd = container_of(m_cfg, FSPM_UPD, FspmConfig); + size_t num; + uint16_t supported_hsio_lanes; + uint8_t boardid = board_id(); + BL_HSIO_INFORMATION *hsio_config; + + /* Set the parameters for MemoryInit */ + m_cfg->PcdEnableIQAT = IS_ENABLED(CONFIG_IQAT_ENABLE); + + /* if ME HECI communication is disabled, apply default one*/ + if (mupd->FspmConfig.PcdMeHeciCommunication == 0) { + + /* Configure FIA MUX PCD */ + /* Assume the validating silicon has max lanes. */ + supported_hsio_lanes = BL_ME_FIA_MUX_LANE_NUM_MAX; + + switch (boardid) { + case BoardIdHarcuvar: + num = ARRAY_SIZE(harcuvar_hsio_config); + hsio_config = + (BL_HSIO_INFORMATION *)harcuvar_hsio_config; + break; + default: + num = 0; + hsio_config = NULL; + break; + } + + if (get_fiamux_hsio_info(supported_hsio_lanes, num, + &hsio_config)) + die("HSIO Configuration is invalid, please correct " + "it!"); + + /* Check the requested FIA MUX Configuration */ + if (!(&hsio_config->FiaConfig)) { + die("Requested FIA MUX Configuration is invalid," + " please correct it!"); + } + + mupd->FspmConfig.PcdHsioLanesNumber = + (uint32_t)hsio_config->NumLanesSupported; + mupd->FspmConfig.PcdFiaMuxConfigPtr = + (uint32_t)&hsio_config->FiaConfig; + } +} + +__attribute__((weak)) void mainboard_memory_init_params(FSPM_UPD *mupd) +{ + /* Do nothing */ +} + +void platform_fsp_memory_init_params_cb(FSPM_UPD *mupd, uint32_t version) +{ + FSP_M_CONFIG *m_cfg = &mupd->FspmConfig; + + soc_memory_init_params(m_cfg); + + mainboard_memory_init_params(mupd); +} -- cgit v1.2.3