blob: 5df8b7193aacbc74ae8018060e49714beedcddc2 [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2016 - 2017 Intel Corp.
* Copyright (C) 2017 Online SAS.
*
* 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 <cbmem.h>
#include <cf9_reset.h>
#include <console/console.h>
#include <cpu/x86/mtrr.h>
#include <device/pci_ops.h>
#include <soc/fiamux.h>
#include <soc/iomap.h>
#include <soc/pci_devs.h>
#include <soc/pcr.h>
#include <soc/pmc.h>
#include <soc/romstage.h>
#include <soc/smbus.h>
#include <soc/smm.h>
#include <soc/soc_util.h>
#include <soc/hob_mem.h>
void __weak mainboard_config_gpios(void) {}
#if IS_ENABLED(CONFIG_DISPLAY_HOBS)
static void display_fsp_smbios_memory_info_hob(void)
{
const FSP_SMBIOS_MEMORY_INFO *memory_info_hob;
/* Get the memory info HOB */
memory_info_hob = soc_get_fsp_smbios_memory_info_hob();
if (memory_info_hob == NULL)
return;
soc_display_fsp_smbios_memory_info_hob(memory_info_hob);
}
#endif
static void early_pmc_init(void)
{
/* PMC (B0:D31:F2). */
pci_devfn_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);
full_reset();
}
}
}
}
static void early_tco_init(void)
{
/* SMBUS (B0:D31:F4). */
pci_devfn_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. */
postcar_frame_add_romcache(&pcf, 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;
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;
num = mainboard_get_hsio_config(&hsio_config);
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;
}
}
__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);
}