diff options
author | Aseda Aboagye <aaboagye@google.com> | 2021-06-15 23:11:41 -0700 |
---|---|---|
committer | Karthik Ramasubramanian <kramasub@google.com> | 2021-06-19 00:03:50 +0000 |
commit | e58e6f2adfb65fb960cdc41289a5186b4370fd1e (patch) | |
tree | c69e90da471a29041ba245ae44123b720f803a3c /src/soc/intel/common/block/gpio | |
parent | 095f97b58f10087b1350e62d8162827c8689c7a2 (diff) |
soc/intel/common/block/gpio: Add `gpio_lock_pad()`
This commit adds a method for locking a GPIO pad configuration and its
TX state. When the configuration is locked, the following registers
become Read-Only and software writes to these registers have no effect.
Pad Configuration registers
GPI_NMI_EN
GPI_SMI_EN
GPI_GPE_EN
Note that this is only effective if the pad is owned by the host (set in
the PAD_OWN register).
Intel platforms that wish to leverage this function need to define the
PADCFGLOCK offset for their platform.
BUG=b:191189275
BRANCH=None
TEST=With some other code, call gpio_lock_pad() against a pad and verify
that the pad configuration is locked and the state of the pad cannot be
changed from the OS.
Signed-off-by: Aseda Aboagye <aaboagye@google.com>
Change-Id: Id3c0da2f6942099c0289ca1e33a33c176f49d380
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55557
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
Diffstat (limited to 'src/soc/intel/common/block/gpio')
-rw-r--r-- | src/soc/intel/common/block/gpio/gpio.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/src/soc/intel/common/block/gpio/gpio.c b/src/soc/intel/common/block/gpio/gpio.c index 8f1c3a5601..d4a312bf9a 100644 --- a/src/soc/intel/common/block/gpio/gpio.c +++ b/src/soc/intel/common/block/gpio/gpio.c @@ -8,6 +8,7 @@ #include <intelblocks/gpio.h> #include <gpio.h> #include <intelblocks/itss.h> +#include <intelblocks/p2sb.h> #include <intelblocks/pcr.h> #include <soc/pm.h> #include <stdlib.h> @@ -446,6 +447,84 @@ int gpio_get(gpio_t gpio_num) return !!(reg & PAD_CFG0_RX_STATE); } +int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action action) +{ + const struct pad_community *comm = gpio_get_community(pad); + size_t rel_pad; + uint16_t offset; + uint32_t data; + uint8_t response; + int status; + + /* + * FSP-S will unlock all the GPIO pads and hide the P2SB device. With + * the device hidden, we will not be able to send the sideband interface + * message to lock the GPIO configuration. Therefore, we need to unhide + * the P2SB device which can only be done in SMM requiring that this + * function is called from SMM. + */ + if (!ENV_SMM) { + printk(BIOS_ERR, "%s: Error: must be called from SMM!\n", __func__); + return -1; + } + + if (!(action & GPIO_LOCK_FULL)) { + printk(BIOS_ERR, "%s: Error: no action specified!\n", __func__); + return -1; + } + + rel_pad = relative_pad_in_comm(comm, pad); + offset = comm->pad_cfg_lock_offset; + if (!offset) { + printk(BIOS_ERR, "%s: Error: offset is not defined!\n", __func__); + return -1; + } + offset += gpio_group_index_scaled(comm, rel_pad, 2 * sizeof(uint32_t)); + + /* We must use the sideband interface in order to lock the pad. */ + struct pcr_sbi_msg msg = { + .pid = comm->port, + .offset = offset, + .opcode = GPIO_LOCK_UNLOCK, + .is_posted = false, + .fast_byte_enable = 0xF, + .bar = 0, + .fid = 0, + }; + + p2sb_unhide(); + + data = gpio_bitmask_within_group(comm, rel_pad); + + if (action & GPIO_LOCK_CONFIG) { + printk(BIOS_INFO, "%s: Locking pad %d configuration\n", + __func__, pad); + status = pcr_execute_sideband_msg(&msg, &data, &response); + if (status || response) { + printk(BIOS_ERR, "%s: error status=%x response=%x\n", __func__, status, + response); + p2sb_hide(); + return status == -1 ? -1 : response; + } + } + + if (action & GPIO_LOCK_TX) { + printk(BIOS_INFO, "%s: Locking pad %d TX state\n", __func__, + pad); + msg.offset = msg.offset + 4; + status = pcr_execute_sideband_msg(&msg, &data, &response); + if (status || response) { + printk(BIOS_ERR, "%s: error status=%x response=%x\n", __func__, status, + response); + p2sb_hide(); + return status == -1 ? -1 : response; + } + } + + p2sb_hide(); + return 0; +} + void gpio_set(gpio_t gpio_num, int value) { const struct pad_community *comm = gpio_get_community(gpio_num); |