summaryrefslogtreecommitdiff
path: root/src/soc/intel/common/block/gpio/gpio.c
diff options
context:
space:
mode:
authorNick Vaccaro <nvaccaro@google.com>2021-10-12 17:26:52 -0700
committerNick Vaccaro <nvaccaro@google.com>2021-12-07 00:17:27 +0000
commitb6f29c9bf47724168a58c196aa1d2ec65302731e (patch)
treeb99e0d56d9dbfc04c9c6a62c0674e00328623e9c /src/soc/intel/common/block/gpio/gpio.c
parenteb3260b9715842d5abda28ac920afde696afd88c (diff)
soc/intel/common: add generic gpio lock mechanism
For added security, there are some gpios that an SoC will want to lock once initially configured, such as gpios attached to non-host (x86) controllers, so that they can't be recofigured at a later point in time by rogue code. Likewise, a mainboard may have some gpios connected to secure busses and/or devices that they want to protect from being changed post initial configuration. This change adds a generic gpio locking mechanism that allows the SoC to export a list of GPIOs to be locked down and allows the mainboard to export a list of GPIOs that it wants locked down once initialization is complete. Use the SOC_INTEL_COMMON_BLOCK_SMM_LOCK_GPIO_PADS Kconfig option to enable this feature. BUG=b:201430600 TEST='emerge-brya coreboot chromeos-bootimage', flash and verify brya0 boots successfully to kernel. Signed-off-by: Nick Vaccaro <nvaccaro@google.com> Change-Id: I42979fb89567d8bcd9392da4fb8c4113ef427b14 Reviewed-on: https://review.coreboot.org/c/coreboot/+/58351 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Diffstat (limited to 'src/soc/intel/common/block/gpio/gpio.c')
-rw-r--r--src/soc/intel/common/block/gpio/gpio.c117
1 files changed, 77 insertions, 40 deletions
diff --git a/src/soc/intel/common/block/gpio/gpio.c b/src/soc/intel/common/block/gpio/gpio.c
index d4a312bf9a..ce23a2eedc 100644
--- a/src/soc/intel/common/block/gpio/gpio.c
+++ b/src/soc/intel/common/block/gpio/gpio.c
@@ -447,14 +447,27 @@ 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)
+static int sideband_msg_err(int status, int response)
{
- const struct pad_community *comm = gpio_get_community(pad);
- size_t rel_pad;
+ if (status || response) {
+ printk(BIOS_ERR, "%s: error status=%x response=%x\n",
+ __func__, status, response);
+ return (status == -1) ? -1 : response;
+ }
+
+ return 0;
+}
+
+int gpio_lock_pads(const struct gpio_lock_config *pad_list, const size_t count)
+{
+ const struct pad_community *comm;
+ enum gpio_lock_action action;
+ int status, err_response = 0;
+ uint8_t response;
uint16_t offset;
+ size_t rel_pad;
uint32_t data;
- uint8_t response;
- int status;
+ gpio_t pad;
/*
* FSP-S will unlock all the GPIO pads and hide the P2SB device. With
@@ -468,23 +481,13 @@ int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action action)
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__);
+ if ((pad_list == NULL) || (count == 0)) {
+ printk(BIOS_ERR, "%s: Error: pad_list null or count = 0!\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,
@@ -494,35 +497,69 @@ int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action action)
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;
+ for (int x = 0; x < count; x++) {
+ int err;
+
+ pad = pad_list[x].gpio;
+ action = pad_list[x].action;
+
+ if (!(action & GPIO_LOCK_FULL)) {
+ printk(BIOS_ERR, "%s: Error: no action specified for pad %d!\n",
+ __func__, pad);
+ continue;
+ }
+
+ comm = gpio_get_community(pad);
+ rel_pad = relative_pad_in_comm(comm, pad);
+ offset = comm->pad_cfg_lock_offset;
+ if (!offset) {
+ printk(BIOS_ERR, "%s: Error: offset not defined for pad %d!\n",
+ __func__, pad);
+ continue;
+ }
+ offset += gpio_group_index_scaled(comm, rel_pad, 2 * sizeof(uint32_t));
+
+ data = gpio_bitmask_within_group(comm, rel_pad);
+ msg.pid = comm->port;
+ msg.offset = offset;
+
+ if (action & GPIO_LOCK_CONFIG) {
+ if (CONFIG(DEBUG_GPIO))
+ printk(BIOS_INFO, "%s: Locking pad %d configuration\n",
+ __func__, pad);
+ status = pcr_execute_sideband_msg(&msg, &data, &response);
+ if ((err = sideband_msg_err(status, response)) != 0) {
+ err_response = err;
+ continue;
+ }
}
- }
- 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;
+ if (action & GPIO_LOCK_TX) {
+ if (CONFIG(DEBUG_GPIO))
+ printk(BIOS_INFO, "%s: Locking pad %d TX state\n",
+ __func__, pad);
+ msg.offset += 4;
+ status = pcr_execute_sideband_msg(&msg, &data, &response);
+ if ((err = sideband_msg_err(status, response)) != 0) {
+ err_response = err;
+ continue;
+ }
}
}
p2sb_hide();
- return 0;
+
+ return err_response;
+}
+
+int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action action)
+{
+ const struct gpio_lock_config pads = {
+ .gpio = pad,
+ .action = action
+ };
+
+ return gpio_lock_pads(&pads, 1);
}
void gpio_set(gpio_t gpio_num, int value)