soc/intel/common: Add SMM common code for Intel Platforms

SMI code is very similar across Intel platforms. Move this code to
common/block/smi to allow it to be shared between platforms instead
of duplicating the code for each platform. smihandler.h has already
been made common so all it will contain is name changes and a move
to the common block location. Due to moving smihandler code, APL
changes are bundled here to show this change.

Change-Id: I599358f23d5de7564ef1ca414bccd54cebab5a4c
Signed-off-by: Brandon Breitenstein <brandon.breitenstein@intel.com>
Reviewed-on: https://review.coreboot.org/19392
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
Brandon Breitenstein 2017-06-08 17:32:02 -07:00 committed by Aaron Durbin
parent d9351099ef
commit a86d1b8af5
13 changed files with 198 additions and 57 deletions

View File

@ -68,7 +68,7 @@ config CPU_SPECIFIC_OPTIONS
select SOC_INTEL_COMMON_BLOCK_UART
select SOC_INTEL_COMMON_BLOCK_XDCI
select SOC_INTEL_COMMON_BLOCK_XHCI
select SOC_INTEL_COMMON_SMI
select SOC_INTEL_COMMON_BLOCK_SMM
select SOC_INTEL_COMMON_SPI_FLASH_PROTECT
select UDELAY_TSC
select TSC_CONSTANT_RATE

View File

@ -65,7 +65,6 @@ ramstage-y += spi.c
ramstage-y += pmutil.c
ramstage-y += pmc.c
ramstage-y += reset.c
ramstage-y += smi.c
ramstage-y += sram.c
ramstage-y += spi.c
ramstage-y += xdci.c

View File

@ -25,14 +25,15 @@
#include <cpu/x86/mtrr.h>
#include <device/device.h>
#include <device/pci.h>
#include <fsp/memmap.h>
#include <intelblocks/cpulib.h>
#include <intelblocks/fast_spi.h>
#include <intelblocks/msr.h>
#include <intelblocks/smm.h>
#include <reg_script.h>
#include <soc/cpu.h>
#include <soc/iomap.h>
#include <soc/pm.h>
#include <soc/smm.h>
#include <cpu/intel/turbo.h>
static const struct reg_script core_msr_script[] = {
@ -189,9 +190,9 @@ static const struct mp_ops mp_ops = {
.get_cpu_count = get_cpu_count,
.get_smm_info = get_smm_info,
.get_microcode_info = get_microcode_info,
.pre_mp_smm_init = southbridge_smm_clear_state,
.pre_mp_smm_init = smm_southbridge_clear_state,
.relocation_handler = relocation_handler,
.post_mp_init = southbridge_smm_enable_smi,
.post_mp_init = smm_southbridge_enable,
};
void apollolake_init_cpus(struct device *dev)

View File

@ -82,6 +82,20 @@
#define EOS (1 << SMI_EOS) /* End of SMI (deassert SMI#) */
#define GBL_SMI_EN (1 << SMI_GBL) /* Global SMI Enable */
/* SMI_EN Params for this platform to pass to enable_smi
*
* Enable SMI generation:
* - on APMC writes (io 0xb2)
* - on writes to SLP_EN (sleep states)
* - on writes to GBL_RLS (bios commands)
* - on eSPI events (does nothing on LPC systems)
* No SMIs:
* - on microcontroller writes (io 0x62/0x66)
* - on TCO events
*/
#define ENABLE_SMI_PARAMS \
(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS | GPIO_EN)
#define SMI_STS 0x44
/* Bits for SMI status */
#define PMC_OCP_SMI_STS 27

View File

@ -27,9 +27,9 @@
#include <assert.h>
#include <cbmem.h>
#include <device/pci.h>
#include <fsp/memmap.h>
#include <soc/systemagent.h>
#include <soc/pci_devs.h>
#include <soc/smm.h>
static uintptr_t smm_region_start(void)
{

View File

@ -14,25 +14,15 @@
* GNU General Public License for more details.
*/
#include <arch/hlt.h>
#include <arch/io.h>
#include <console/console.h>
#include <cpu/x86/cache.h>
#include <cpu/x86/smm.h>
#include <device/pci_def.h>
#include <elog.h>
#include <soc/nvs.h>
#include <soc/pm.h>
#include <intelblocks/smihandler.h>
#include <soc/gpio.h>
#include <soc/iomap.h>
#include <soc/pci_devs.h>
#include <soc/intel/common/smi.h>
#include <spi-generic.h>
#include <stdint.h>
#include <stdlib.h>
#include <soc/smm.h>
#include <soc/pm.h>
int smm_disable_busmaster(device_t dev)
int smihandler_disable_busmaster(device_t dev)
{
if (dev == PCH_DEV_PMC)
return 0;
@ -47,7 +37,8 @@ const struct smm_save_state_ops *get_smm_save_state_ops(void)
void __attribute__((weak))
mainboard_smi_gpi_handler(const struct gpi_status *sts) { }
static void southbridge_smi_gpi(const struct smm_save_state_ops *save_state_ops)
static void southbridge_smi_gpi(
const struct smm_save_state_ops *save_state_ops)
{
struct gpi_status smi_sts;
@ -59,10 +50,10 @@ static void southbridge_smi_gpi(const struct smm_save_state_ops *save_state_ops)
}
const smi_handler_t southbridge_smi[32] = {
[SLP_SMI_STS] = southbridge_smi_sleep,
[APM_SMI_STS] = southbridge_smi_apmc,
[FAKE_PM1_SMI_STS] = southbridge_smi_pm1,
[SLP_SMI_STS] = smihandler_southbridge_sleep,
[APM_SMI_STS] = smihandler_southbridge_apmc,
[FAKE_PM1_SMI_STS] = smihandler_southbridge_pm1,
[GPIO_SMI_STS] = southbridge_smi_gpi,
[TCO_SMI_STS] = southbridge_smi_tco,
[PERIODIC_SMI_STS] = southbridge_smi_periodic,
[TCO_SMI_STS] = smihandler_southbridge_tco,
[PERIODIC_SMI_STS] = smihandler_southbridge_periodic,
};

View File

@ -31,8 +31,6 @@ ramstage-$(CONFIG_SOC_INTEL_COMMON_GFX_OPREGION) += opregion.c
ramstage-$(CONFIG_SOC_INTEL_COMMON_ACPI) += ./acpi/acpi.c
ramstage-$(CONFIG_SOC_INTEL_COMMON_NHLT) += nhlt.c
smm-$(CONFIG_SOC_INTEL_COMMON_SMI) += smihandler.c
bootblock-$(CONFIG_MAINBOARD_HAS_TPM_CR50) += tpm_tis.c
verstage-$(CONFIG_MAINBOARD_HAS_TPM_CR50) += tpm_tis.c
romstage-$(CONFIG_MAINBOARD_HAS_TPM_CR50) += tpm_tis.c

View File

@ -13,8 +13,13 @@
* GNU General Public License for more details.
*/
#ifndef _INTEL_COMMON_SMI_H_
#define _INTEL_COMMON_SMI_H_
#ifndef SOC_INTEL_COMMON_BLOCK_SMI_HANDLER_H
#define SOC_INTEL_COMMON_BLOCK_SMI_HANDLER_H
#include <stdint.h>
struct gpi_status;
struct global_nvs_t;
/*
* The register value is used with get_reg and set_reg
@ -26,8 +31,7 @@ enum smm_reg {
RDX,
};
struct smm_save_state_ops {
struct smm_save_state_ops {
/* return io_misc_info from SMM Save State Area */
uint32_t (*get_io_misc_info)(void *state);
@ -50,63 +54,72 @@ const struct smm_save_state_ops *get_smm_save_state_ops(void);
/*
* southbridge_smi should be defined inside SOC specific code and should have
* handlers for any SMI events that need to be handled. Default handlers
* for some SMI events are provided in soc/intel/common/smihandler.c
* for some SMI events are provided in soc/intel/common/block/smm/smihandler.c
*/
extern const smi_handler_t southbridge_smi[32];
/*
* This function should be implemented in SOC specific code to handle
* the SMI event on SLP_EN. The default functionality is provided in
* soc/intel/common/smihandler.c
* soc/intel/common/block/smm/smihandler.c
*/
void southbridge_smi_sleep(const struct smm_save_state_ops *save_state_ops);
void smihandler_southbridge_sleep(
const struct smm_save_state_ops *save_state_ops);
/*
* This function should be implemented in SOC specific code to handle
* SMI_APM event. The default functionality is provided in
* soc/intel/common/smihandler.c
* soc/intel/common/block/smm/smihandler.c
*/
void southbridge_smi_apmc(const struct smm_save_state_ops *save_state_ops);
void smihandler_southbridge_apmc(
const struct smm_save_state_ops *save_state_ops);
/*
* This function should be implemented in SOC specific code to handle
* SMI_PM1 event. The default functionality is provided in
* soc/intel/common/smihandler.c
* soc/intel/common/block/smm/smihandler.c
*/
void southbridge_smi_pm1(const struct smm_save_state_ops *save_state_ops);
void smihandler_southbridge_pm1(
const struct smm_save_state_ops *save_state_ops);
/*
* This function should be implemented in SOC specific code to handle
* SMI_GPE0 event. The default functionality is provided in
* soc/intel/common/smihandler.c
* soc/intel/common/block/smm/smihandler.c
*/
void southbridge_smi_gpe0(const struct smm_save_state_ops *save_state_ops);
void smihandler_southbridge_gpe0(
const struct smm_save_state_ops *save_state_ops);
/*
* This function should be implemented in SOC specific code to handle
* SMI_TCO event. The default functionality is provided in
* soc/intel/common/smihandler.c
* soc/intel/common/block/smm/smihandler.c
*/
void southbridge_smi_tco(const struct smm_save_state_ops *save_state_ops);
void smihandler_southbridge_tco(
const struct smm_save_state_ops *save_state_ops);
/*
* This function should be implemented in SOC specific code to handle
* SMI PERIODIC_STS event. The default functionality is provided in
* soc/intel/common/smihandler.c
* soc/intel/common/block/smm/smihandler.c
*/
void southbridge_smi_periodic(const struct smm_save_state_ops *save_state_ops);
void smihandler_southbridge_periodic(
const struct smm_save_state_ops *save_state_ops);
/*
* This function returns a 1 or 0 depending on whether disable_busmaster
* needs to be done for the specified device on S5 entry
*/
int smm_disable_busmaster(device_t dev);
int smihandler_disable_busmaster(device_t dev);
/*
* Returns gnvs pointer within SMM context
*/
struct global_nvs_t *smm_get_gnvs(void);
/* Mainboard handler for GPI SMIs */
void mainboard_smi_gpi_handler(const struct gpi_status *sts);
extern const struct smm_save_state_ops em64t100_smm_ops;
extern const struct smm_save_state_ops em64t101_smm_ops;

View File

@ -0,0 +1,34 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 201 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*/
#ifndef SOC_INTEL_COMMON_BLOCK_SMM_H
#define SOC_INTEL_COMMON_BLOCK_SMM_H
/*
* This common code block relies on each specific SOC defining the macro
* ENABLE_SMI_PARAMS for the values needed for SMI enabling on the
* specific SOC
*/
/*
* The initialization of the southbridge is split into 2 compoments. One is
* for clearing the state in the SMM registers. The other is for enabling
* SMIs.
*/
void smm_southbridge_clear_state(void);
void smm_southbridge_enable(void);
#endif

View File

@ -0,0 +1,4 @@
config SOC_INTEL_COMMON_BLOCK_SMM
bool
help
Intel Processor common SMM support

View File

@ -0,0 +1,2 @@
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SMM) += smm.c
smm-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SMM) += smihandler.c

View File

@ -21,6 +21,7 @@
#include <cpu/x86/smm.h>
#include <device/pci_def.h>
#include <elog.h>
#include <intelblocks/smihandler.h>
#include <soc/nvs.h>
#include <soc/pm.h>
#include <soc/gpio.h>
@ -28,18 +29,17 @@
#include <spi-generic.h>
#include <stdint.h>
#include <stdlib.h>
#include "smi.h"
/* GNVS needs to be set by coreboot initiating a software SMI. */
static struct global_nvs_t *gnvs;
__attribute__((weak)) int smm_disable_busmaster(device_t dev)
__attribute__((weak)) int smihandler_disable_busmaster(device_t dev)
{
return 1;
}
static void *find_save_state(const struct smm_save_state_ops *save_state_ops,
int cmd)
int cmd)
{
int node;
void *state = NULL;
@ -70,6 +70,7 @@ static void *find_save_state(const struct smm_save_state_ops *save_state_ops,
return state;
}
/* Inherited from cpu/x86/smm.h resulting in a different signature */
void southbridge_smi_set_eos(void)
{
enable_smi(EOS);
@ -91,7 +92,7 @@ static void busmaster_disable_on_bus(int bus)
u32 reg32;
device_t dev = PCI_DEV(bus, slot, func);
if (!smm_disable_busmaster(dev))
if (!smihandler_disable_busmaster(dev))
continue;
val = pci_read_config32(dev, PCI_VENDOR_ID);
@ -127,7 +128,8 @@ static void busmaster_disable_on_bus(int bus)
}
void southbridge_smi_sleep(const struct smm_save_state_ops *save_state_ops)
void smihandler_southbridge_sleep(
const struct smm_save_state_ops *save_state_ops)
{
uint32_t reg32;
uint8_t slp_typ;
@ -205,8 +207,8 @@ void southbridge_smi_sleep(const struct smm_save_state_ops *save_state_ops)
}
}
static void southbridge_smi_gsmi(const struct
smm_save_state_ops *save_state_ops)
static void southbridge_smi_gsmi(
const struct smm_save_state_ops *save_state_ops)
{
u8 sub_command, ret;
void *io_smi = NULL;
@ -239,7 +241,8 @@ static void finalize(void)
}
void southbridge_smi_apmc(const struct smm_save_state_ops *save_state_ops)
void smihandler_southbridge_apmc(
const struct smm_save_state_ops *save_state_ops)
{
uint8_t reg8;
void *state = NULL;
@ -300,7 +303,8 @@ void southbridge_smi_apmc(const struct smm_save_state_ops *save_state_ops)
mainboard_smi_apmc(reg8);
}
void southbridge_smi_pm1(const struct smm_save_state_ops *save_state_ops)
void smihandler_southbridge_pm1(
const struct smm_save_state_ops *save_state_ops)
{
uint16_t pm1_sts = clear_pm1_status();
@ -317,12 +321,14 @@ void southbridge_smi_pm1(const struct smm_save_state_ops *save_state_ops)
}
}
void southbridge_smi_gpe0(const struct smm_save_state_ops *save_state_ops)
void smihandler_southbridge_gpe0(
const struct smm_save_state_ops *save_state_ops)
{
clear_gpe_status();
}
void southbridge_smi_tco(const struct smm_save_state_ops *save_state_ops)
void smihandler_southbridge_tco(
const struct smm_save_state_ops *save_state_ops)
{
uint32_t tco_sts = clear_tco_status();
@ -336,7 +342,8 @@ void southbridge_smi_tco(const struct smm_save_state_ops *save_state_ops)
}
}
void southbridge_smi_periodic(const struct smm_save_state_ops *save_state_ops)
void smihandler_southbridge_periodic(
const struct smm_save_state_ops *save_state_ops)
{
uint32_t reg32;

View File

@ -0,0 +1,78 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
* Copyright (C) 2014 Google Inc.
* Copyright (C) 2015 Intel Corporation.
*
* 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 <console/console.h>
#include <cpu/x86/smm.h>
#include <intelblocks/smm.h>
#include <soc/pm.h>
void smm_southbridge_clear_state(void)
{
printk(BIOS_DEBUG, "Clearing SMI status registers\n");
if (get_smi_en() & APMC_EN) {
printk(BIOS_INFO, "SMI# handler already enabled?\n");
return;
}
/* Dump and clear status registers */
clear_smi_status();
clear_pm1_status();
clear_tco_status();
clear_gpe_status();
}
void smm_southbridge_enable(void)
{
printk(BIOS_DEBUG, "Enabling SMIs.\n");
/* Configure events */
enable_pm1(PWRBTN_EN | GBL_EN);
disable_gpe(PME_B0_EN);
/*
* Enable SMI generation:
* - on APMC writes (io 0xb2)
* - on writes to SLP_EN (sleep states)
* - on writes to GBL_RLS (bios commands)
* - on eSPI events (does nothing on LPC systems)
* No SMIs:
* - on microcontroller writes (io 0x62/0x66)
* - on TCO events
*/
/* Enable SMI generation: */
enable_smi(ENABLE_SMI_PARAMS);
}
void smm_setup_structures(void *gnvs, void *tcg, void *smi1)
{
/*
* Issue SMI to set the gnvs pointer in SMM.
* tcg and smi1 are unused.
*
* EAX = APM_CNT_GNVS_UPDATE
* EBX = gnvs pointer
* EDX = APM_CNT
*/
asm volatile (
"outb %%al, %%dx\n\t"
: /* ignore result */
: "a" (APM_CNT_GNVS_UPDATE),
"b" ((u32)gnvs),
"d" (APM_CNT)
);
}