diff --git a/src/soc/intel/alderlake/Kconfig b/src/soc/intel/alderlake/Kconfig index 6b98c207a8f..c4b579128a5 100644 --- a/src/soc/intel/alderlake/Kconfig +++ b/src/soc/intel/alderlake/Kconfig @@ -63,6 +63,7 @@ config SOC_INTEL_ALDERLAKE select SOC_INTEL_COMMON_BLOCK_CPU_SMMRELOCATE select SOC_INTEL_COMMON_BLOCK_DTT select SOC_INTEL_COMMON_BLOCK_GPIO_DUAL_ROUTE_SUPPORT + select SOC_INTEL_COMMON_BLOCK_GPIO_HAS_PLTRST_PAD select SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_SBI select SOC_INTEL_COMMON_BLOCK_GSPI_VERSION_2 select SOC_INTEL_COMMON_BLOCK_SCS if SOC_INTEL_ALDERLAKE_PCH_N diff --git a/src/soc/intel/alderlake/Makefile.mk b/src/soc/intel/alderlake/Makefile.mk index 1947015f929..821008643d0 100644 --- a/src/soc/intel/alderlake/Makefile.mk +++ b/src/soc/intel/alderlake/Makefile.mk @@ -48,6 +48,7 @@ ramstage-y += xhci.c ramstage-$(CONFIG_SOC_INTEL_CRASHLOG) += crashlog.c smm-y += elog.c +smm-$(CONFIG_SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_PLTRST_PAD) += gpio_lock.c smm-y += p2sb.c smm-y += pmutil.c smm-y += smihandler.c diff --git a/src/soc/intel/alderlake/gpio_lock.c b/src/soc/intel/alderlake/gpio_lock.c new file mode 100644 index 00000000000..5d4568e386c --- /dev/null +++ b/src/soc/intel/alderlake/gpio_lock.c @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include + +/* + * GPP_B13 drives PLTRST# as its native function 1 on Alder Lake PCH-P/N as + * well as on PCH-S. Locking the pad configuration keeps system software from + * switching the pad to GPIO mode and pulsing it, which would reset a discrete + * TPM without restarting the measured boot chain. + */ +static const struct gpio_lock_config pltrst_pad[] = { + { .pad = GPP_B13, .lock_action = GPIO_LOCK_CONFIG }, +}; + +const struct gpio_lock_config *soc_gpio_lock_config(size_t *num) +{ + *num = ARRAY_SIZE(pltrst_pad); + return pltrst_pad; +} diff --git a/src/soc/intel/common/block/gpio/Kconfig b/src/soc/intel/common/block/gpio/Kconfig index 60a5967bdea..d14847a8b50 100644 --- a/src/soc/intel/common/block/gpio/Kconfig +++ b/src/soc/intel/common/block/gpio/Kconfig @@ -55,6 +55,37 @@ config SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR Starting with MTL SoC, the recommendation is to use PCR for locking down the GPIO configuration. +# Selected by SoCs that return the pad driving PLTRST# from +# soc_gpio_lock_config(). +config SOC_INTEL_COMMON_BLOCK_GPIO_HAS_PLTRST_PAD + bool + +config SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_PLTRST_PAD + bool "Lock the PLTRST# pad configuration" + default y + depends on SOC_INTEL_COMMON_BLOCK_GPIO_HAS_PLTRST_PAD + depends on HAVE_SMI_HANDLER + depends on INTEL_CHIPSET_LOCKDOWN + depends on SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_SBI || \ + SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR + select SOC_INTEL_COMMON_BLOCK_SMM_LOCK_GPIO_PADS + help + PLTRST# is the native function of a GPIO pad. As long as that pad + configuration stays writable, system software can switch the pad to + GPIO mode and drive a platform reset edge. A discrete TPM is reset by + that edge while the host keeps running, so its PCRs are cleared + without restarting the measured boot chain and can be replayed with + arbitrary values. + + Lock the pad configuration from the SMM finalize handler, i.e. after + FSP has run its notify phases, so the pad mode can no longer be + changed. Only the configuration is locked. The Tx state is left + writable, as it has no effect while the pad drives PLTRST#. + + Say N on a board that does not use this pad for PLTRST#, or that uses + it as a GPIO: locking the configuration of a pad that already is in + GPIO mode does not keep software from driving it. + # Indicate if SoC supports 4 bits Pad Mode with PAD_CFG_DW0 registers config SOC_INTEL_COMMON_BLOCK_GPIO_PMODE_4BITS bool diff --git a/src/soc/intel/common/block/gpio/gpio.c b/src/soc/intel/common/block/gpio/gpio.c index d74e01da627..788cbde7fe3 100644 --- a/src/soc/intel/common/block/gpio/gpio.c +++ b/src/soc/intel/common/block/gpio/gpio.c @@ -554,6 +554,29 @@ int gpio_tx_get(gpio_t gpio_num) return !!(reg & PAD_CFG0_TX_STATE); } +static int +gpio_pad_config_lock_verify(const struct gpio_lock_config *pad_info, + uint8_t pid, uint16_t offset, const uint32_t bit_mask) +{ + int ret = 0; + + if ((pad_info->lock_action & GPIO_LOCK_CONFIG) == GPIO_LOCK_CONFIG && + !(pcr_read32(pid, offset) & bit_mask)) { + printk(BIOS_ERR, "%s: Error: pad %d configuration still unlocked!\n", + __func__, pad_info->pad); + ret = -1; + } + + if ((pad_info->lock_action & GPIO_LOCK_TX) == GPIO_LOCK_TX && + !(pcr_read32(pid, offset + sizeof(uint32_t)) & bit_mask)) { + printk(BIOS_ERR, "%s: Error: pad %d Tx state still unlocked!\n", + __func__, pad_info->pad); + ret = -1; + } + + return ret; +} + static void gpio_pad_config_lock_using_sbi(const struct gpio_lock_config *pad_info, uint8_t pid, uint16_t offset, const uint32_t bit_mask) @@ -601,12 +624,32 @@ gpio_pad_config_lock_using_sbi(const struct gpio_lock_config *pad_info, } } +static void +gpio_pad_config_lock_using_pcr(const struct gpio_lock_config *pad_info, + uint8_t pid, uint16_t offset, const uint32_t bit_mask) +{ + if ((pad_info->lock_action & GPIO_LOCK_CONFIG) == GPIO_LOCK_CONFIG) { + if (CONFIG(DEBUG_GPIO)) + printk(BIOS_INFO, "%s: Locking pad %d configuration\n", + __func__, pad_info->pad); + pcr_or32(pid, offset, bit_mask); + } + + if ((pad_info->lock_action & GPIO_LOCK_TX) == GPIO_LOCK_TX) { + if (CONFIG(DEBUG_GPIO)) + printk(BIOS_INFO, "%s: Locking pad %d TX state\n", + __func__, pad_info->pad); + pcr_or32(pid, offset + sizeof(uint32_t), bit_mask); + } +} + int gpio_lock_pads(const struct gpio_lock_config *pad_list, const size_t count) { const struct pad_community *comm; uint16_t offset; size_t rel_pad; gpio_t pad; + int ret = 0; if (!CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_LOCK_GPIO_PADS)) return -1; @@ -645,29 +688,21 @@ int gpio_lock_pads(const struct gpio_lock_config *pad_list, const size_t count) const uint32_t bit_mask = gpio_bitmask_within_group(comm, rel_pad); - gpio_pad_config_lock_using_sbi(&pad_list[x], comm->port, offset, bit_mask); + /* Use the lock method the SoC selected, as done outside of SMM */ + if (CONFIG(SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR)) + gpio_pad_config_lock_using_pcr(&pad_list[x], comm->port, offset, + bit_mask); + else + gpio_pad_config_lock_using_sbi(&pad_list[x], comm->port, offset, + bit_mask); + + if (gpio_pad_config_lock_verify(&pad_list[x], comm->port, offset, bit_mask)) + ret = -1; } p2sb_hide(); -} - -static void -gpio_pad_config_lock_using_pcr(const struct gpio_lock_config *pad_info, - uint8_t pid, uint16_t offset, const uint32_t bit_mask) -{ - if ((pad_info->lock_action & GPIO_LOCK_CONFIG) == GPIO_LOCK_CONFIG) { - if (CONFIG(DEBUG_GPIO)) - printk(BIOS_INFO, "%s: Locking pad %d configuration\n", - __func__, pad_info->pad); - pcr_or32(pid, offset, bit_mask); - } - if ((pad_info->lock_action & GPIO_LOCK_TX) == GPIO_LOCK_TX) { - if (CONFIG(DEBUG_GPIO)) - printk(BIOS_INFO, "%s: Locking pad %d TX state\n", - __func__, pad_info->pad); - pcr_or32(pid, offset + sizeof(uint32_t), bit_mask); - } + return ret; } static int gpio_non_smm_lock_pad(const struct gpio_lock_config *pad_info) @@ -710,9 +745,10 @@ static int gpio_non_smm_lock_pad(const struct gpio_lock_config *pad_info) } else { printk(BIOS_ERR, "%s: Error: No pad configuration lock method is selected!\n", __func__); + return -1; } - return 0; + return gpio_pad_config_lock_verify(pad_info, comm->port, offset, bit_mask); } int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action lock_action) @@ -726,7 +762,12 @@ int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action lock_action) .lock_action = lock_action }; - if (!ENV_SMM && !CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_LOCK_GPIO_PADS)) + /* + * gpio_lock_pads() only works in SMM. Pads locked while configuring + * them, i.e. from the pad tables in ramstage, have to go through the + * non-SMM path even when the SoC also locks pads from SMM. + */ + if (!ENV_SMM) return gpio_non_smm_lock_pad(&pads); return gpio_lock_pads(&pads, 1); diff --git a/src/soc/intel/tigerlake/Kconfig b/src/soc/intel/tigerlake/Kconfig index 4065d9d328b..8183f81096e 100644 --- a/src/soc/intel/tigerlake/Kconfig +++ b/src/soc/intel/tigerlake/Kconfig @@ -55,7 +55,9 @@ config SOC_INTEL_TIGERLAKE select SOC_INTEL_COMMON_BLOCK_CPU_SMMRELOCATE select SOC_INTEL_COMMON_BLOCK_DTT select SOC_INTEL_COMMON_BLOCK_GPIO_DUAL_ROUTE_SUPPORT + select SOC_INTEL_COMMON_BLOCK_GPIO_HAS_PLTRST_PAD select SOC_INTEL_COMMON_BLOCK_GPIO_IOSTANDBY + select SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_SBI select SOC_INTEL_COMMON_BLOCK_GSPI_VERSION_2 select SOC_INTEL_COMMON_BLOCK_HDA select SOC_INTEL_COMMON_BLOCK_HECI1_DISABLE_USING_PMC_IPC diff --git a/src/soc/intel/tigerlake/Makefile.mk b/src/soc/intel/tigerlake/Makefile.mk index 27e07a99b4e..52b2ac9798b 100644 --- a/src/soc/intel/tigerlake/Makefile.mk +++ b/src/soc/intel/tigerlake/Makefile.mk @@ -49,6 +49,7 @@ smm-y += pmutil.c smm-y += smihandler.c smm-y += uart.c smm-y += elog.c +smm-$(CONFIG_SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_PLTRST_PAD) += gpio_lock.c smm-y += xhci.c ifeq ($(CONFIG_SOC_INTEL_TIGERLAKE_PCH_H),y) diff --git a/src/soc/intel/tigerlake/gpio.c b/src/soc/intel/tigerlake/gpio.c index 7053f3a207a..808de41d6ad 100644 --- a/src/soc/intel/tigerlake/gpio.c +++ b/src/soc/intel/tigerlake/gpio.c @@ -94,6 +94,7 @@ static const struct pad_community tgl_communities[] = { .last_pad = GPP_A24, .num_gpi_regs = NUM_GPIO_COM0_GPI_REGS, .pad_cfg_base = PAD_CFG_BASE, + .pad_cfg_lock_offset = PAD_CFG_LOCK_OFFSET, .host_own_reg_0 = HOSTSW_OWN_REG_0, .gpi_int_sts_reg_0 = GPI_INT_STS_0, .gpi_int_en_reg_0 = GPI_INT_EN_0, @@ -121,6 +122,7 @@ static const struct pad_community tgl_communities[] = { .last_pad = vI2S2_RXD, .num_gpi_regs = NUM_GPIO_COM1_GPI_REGS, .pad_cfg_base = PAD_CFG_BASE, + .pad_cfg_lock_offset = PAD_CFG_LOCK_OFFSET, .host_own_reg_0 = HOSTSW_OWN_REG_0, .gpi_int_sts_reg_0 = GPI_INT_STS_0, .gpi_int_en_reg_0 = GPI_INT_EN_0, @@ -147,6 +149,7 @@ static const struct pad_community tgl_communities[] = { .last_pad = GPD_DRAM_RESETB, .num_gpi_regs = NUM_GPIO_COM2_GPI_REGS, .pad_cfg_base = PAD_CFG_BASE, + .pad_cfg_lock_offset = PAD_CFG_LOCK_OFFSET, .host_own_reg_0 = HOSTSW_OWN_REG_0, .gpi_int_sts_reg_0 = GPI_INT_STS_0, .gpi_int_en_reg_0 = GPI_INT_EN_0, @@ -171,6 +174,7 @@ static const struct pad_community tgl_communities[] = { .last_pad = GPP_DBG_PMODE, .num_gpi_regs = NUM_GPIO_COM4_GPI_REGS, .pad_cfg_base = PAD_CFG_BASE, + .pad_cfg_lock_offset = PAD_CFG_LOCK_OFFSET, .host_own_reg_0 = HOSTSW_OWN_REG_0, .gpi_int_sts_reg_0 = GPI_INT_STS_0, .gpi_int_en_reg_0 = GPI_INT_EN_0, @@ -198,6 +202,7 @@ static const struct pad_community tgl_communities[] = { .last_pad = GPP_CLK_LOOPBK, .num_gpi_regs = NUM_GPIO_COM5_GPI_REGS, .pad_cfg_base = PAD_CFG_BASE, + .pad_cfg_lock_offset = PAD_CFG_LOCK_OFFSET, .host_own_reg_0 = HOSTSW_OWN_REG_0, .gpi_int_sts_reg_0 = GPI_INT_STS_0, .gpi_int_en_reg_0 = GPI_INT_EN_0, diff --git a/src/soc/intel/tigerlake/gpio_lock.c b/src/soc/intel/tigerlake/gpio_lock.c new file mode 100644 index 00000000000..ce55a250c81 --- /dev/null +++ b/src/soc/intel/tigerlake/gpio_lock.c @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include + +/* + * GPP_B13 drives PLTRST# as its native function 1 on Tiger Lake PCH-LP as + * well as on PCH-H. Locking the pad configuration keeps system software from + * switching the pad to GPIO mode and pulsing it, which would reset a discrete + * TPM without restarting the measured boot chain. + */ +static const struct gpio_lock_config pltrst_pad[] = { + { .pad = GPP_B13, .lock_action = GPIO_LOCK_CONFIG }, +}; + +const struct gpio_lock_config *soc_gpio_lock_config(size_t *num) +{ + *num = ARRAY_SIZE(pltrst_pad); + return pltrst_pad; +} diff --git a/src/soc/intel/tigerlake/gpio_pch_h.c b/src/soc/intel/tigerlake/gpio_pch_h.c index 64662d735b1..b47ad75cac2 100644 --- a/src/soc/intel/tigerlake/gpio_pch_h.c +++ b/src/soc/intel/tigerlake/gpio_pch_h.c @@ -79,6 +79,7 @@ static const struct pad_community tgl_communities[] = { .last_pad = GPIO_COM0_END, .num_gpi_regs = NUM_GPIO_COM0_GPI_REGS, .pad_cfg_base = PAD_CFG_BASE, + .pad_cfg_lock_offset = PAD_CFG_LOCK_OFFSET, .host_own_reg_0 = HOSTSW_OWN_REG_0, .gpi_int_sts_reg_0 = GPI_INT_STS_0, .gpi_int_en_reg_0 = GPI_INT_EN_0, @@ -100,6 +101,7 @@ static const struct pad_community tgl_communities[] = { .last_pad = GPIO_COM1_END, .num_gpi_regs = NUM_GPIO_COM1_GPI_REGS, .pad_cfg_base = PAD_CFG_BASE, + .pad_cfg_lock_offset = PAD_CFG_LOCK_OFFSET, .host_own_reg_0 = HOSTSW_OWN_REG_0, .gpi_int_sts_reg_0 = GPI_INT_STS_0, .gpi_int_en_reg_0 = GPI_INT_EN_0, @@ -121,6 +123,7 @@ static const struct pad_community tgl_communities[] = { .last_pad = GPIO_COM2_END, .num_gpi_regs = NUM_GPIO_COM2_GPI_REGS, .pad_cfg_base = PAD_CFG_BASE, + .pad_cfg_lock_offset = PAD_CFG_LOCK_OFFSET, .host_own_reg_0 = HOSTSW_OWN_REG_0, .gpi_int_sts_reg_0 = GPI_INT_STS_0, .gpi_int_en_reg_0 = GPI_INT_EN_0, @@ -140,6 +143,7 @@ static const struct pad_community tgl_communities[] = { .last_pad = GPIO_COM3_END, .num_gpi_regs = NUM_GPIO_COM3_GPI_REGS, .pad_cfg_base = PAD_CFG_BASE, + .pad_cfg_lock_offset = PAD_CFG_LOCK_OFFSET, .host_own_reg_0 = HOSTSW_OWN_REG_0, .gpi_int_sts_reg_0 = GPI_INT_STS_0, .gpi_int_en_reg_0 = GPI_INT_EN_0, @@ -161,6 +165,7 @@ static const struct pad_community tgl_communities[] = { .last_pad = GPIO_COM4_END, .num_gpi_regs = NUM_GPIO_COM4_GPI_REGS, .pad_cfg_base = PAD_CFG_BASE, + .pad_cfg_lock_offset = PAD_CFG_LOCK_OFFSET, .host_own_reg_0 = HOSTSW_OWN_REG_0, .gpi_int_sts_reg_0 = GPI_INT_STS_0, .gpi_int_en_reg_0 = GPI_INT_EN_0, @@ -180,6 +185,7 @@ static const struct pad_community tgl_communities[] = { .last_pad = GPIO_COM5_END, .num_gpi_regs = NUM_GPIO_COM5_GPI_REGS, .pad_cfg_base = PAD_CFG_BASE, + .pad_cfg_lock_offset = PAD_CFG_LOCK_OFFSET, .host_own_reg_0 = HOSTSW_OWN_REG_0, .gpi_int_sts_reg_0 = GPI_INT_STS_0, .gpi_int_en_reg_0 = GPI_INT_EN_0, diff --git a/src/soc/intel/tigerlake/include/soc/gpio_defs.h b/src/soc/intel/tigerlake/include/soc/gpio_defs.h index 57eeaf3f0e1..2a46f526c3f 100644 --- a/src/soc/intel/tigerlake/include/soc/gpio_defs.h +++ b/src/soc/intel/tigerlake/include/soc/gpio_defs.h @@ -22,6 +22,9 @@ (NUM_GPIO_COM2_GPI_REGS) +\ (NUM_GPIO_COM4_GPI_REGS) +\ (NUM_GPIO_COM5_GPI_REGS)) + +#define PAD_CFG_LOCK_OFFSET 0x80 + /* * IOxAPIC IRQs for the GPIOs */ diff --git a/src/soc/intel/tigerlake/include/soc/gpio_defs_pch_h.h b/src/soc/intel/tigerlake/include/soc/gpio_defs_pch_h.h index abf99b809f9..fc4ca62cce9 100644 --- a/src/soc/intel/tigerlake/include/soc/gpio_defs_pch_h.h +++ b/src/soc/intel/tigerlake/include/soc/gpio_defs_pch_h.h @@ -24,6 +24,9 @@ (NUM_GPIO_COM3_GPI_REGS) +\ (NUM_GPIO_COM4_GPI_REGS) +\ (NUM_GPIO_COM5_GPI_REGS)) + +#define PAD_CFG_LOCK_OFFSET 0x90 + /* * IOxAPIC IRQs for the GPIOs */