aboutsummaryrefslogtreecommitdiff
path: root/src/soc/intel/common/block/gpio
diff options
context:
space:
mode:
authorAseda Aboagye <aaboagye@google.com>2021-06-15 23:11:41 -0700
committerKarthik Ramasubramanian <kramasub@google.com>2021-06-19 00:03:50 +0000
commite58e6f2adfb65fb960cdc41289a5186b4370fd1e (patch)
treec69e90da471a29041ba245ae44123b720f803a3c /src/soc/intel/common/block/gpio
parent095f97b58f10087b1350e62d8162827c8689c7a2 (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.c79
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);