summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Niewöhner <foss@mniewoehner.de>2020-12-11 21:26:02 +0100
committerMichael Niewöhner <foss@mniewoehner.de>2020-12-28 17:47:04 +0000
commitdbb667ac08f8283eb38861151f971efd46736ab6 (patch)
tree6f05ddb27c8dab11f11cac66fa4a4aee4381d662 /src
parent5c2efa1990853545664a6f6e3ff94be79477d407 (diff)
device + util/sconfig: introduce new device `gpio`
Introduce a new device `gpio` that is going to be used for generic abstraction of gpio operations in the devicetree. The general idea behind this is that every chip can have gpios that shall be accessible in a very generic way by any driver through the devicetree. The chip that implements the chip-specific gpio operations has to assign them to the generic device operations struct, which then gets assigned to the gpio device during device probing. See CB:48583 for how this gets done for the SoCs using intelblocks/gpio. The gpio device then can be added to the devicetree with an alias name like in the following example: chip soc/whateverlake device gpio 0 alias soc_gpio on end ... end Any driver that requires access to this gpio device needs to have a device pointer (or multiple) and an option for specifying the gpio to be used in its chip config like this: struct drivers_ipmi_config { ... DEVTREE_CONST struct device *gpio_dev; u16 post_complete_gpio; ... }; The device `soc_gpio` can then be linked to the chip driver's `gpio_dev` above by using the syntax `use ... as ...`, which was introduced in commit 8e1ea52: chip drivers/ipmi use soc_gpio as gpio_dev register "bmc_jumper_gpio" = "GPP_D22" ... end The IPMI driver can then use the generic gpio operations without any knowlege of the chip's specifics: unsigned int gpio_val; const struct gpio_operations *gpio_ops; gpio_ops = dev_get_gpio_ops(conf->gpio_dev); gpio_val = gpio_ops->get(conf->bmc_jumper_gpio); For a full example have a look at CB:48096 and CB:48095. This change adds the new device type to sconfig and adds generic gpio operations to the `device_operations` struct. Also, a helper for getting the gpio operations from a device after checking them for NULL pointers gets added. Successfully tested on Supermicro X11SSM-F with CB:48097, X11SSH-TF with CB:48711 and OCP DeltaLake with CB:48672. Change-Id: Ic4572ad8b37bd1afd2fb213b2c67fb8aec536786 Tested-by: Johnny Lin <Johnny_Lin@wiwynn.com> Tested-by: Michael Niewöhner <foss@mniewoehner.de> Tested-by: Patrick Rudolph <siro@das-labor.org> Signed-off-by: Michael Niewöhner <foss@mniewoehner.de> Reviewed-on: https://review.coreboot.org/c/coreboot/+/48582 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Nico Huber <nico.h@gmx.de>
Diffstat (limited to 'src')
-rw-r--r--src/device/Makefile.inc2
-rw-r--r--src/device/device_const.c3
-rw-r--r--src/device/device_util.c6
-rw-r--r--src/device/gpio.c21
-rw-r--r--src/include/device/device.h2
-rw-r--r--src/include/device/gpio.h20
-rw-r--r--src/include/device/path.h7
7 files changed, 61 insertions, 0 deletions
diff --git a/src/device/Makefile.inc b/src/device/Makefile.inc
index bb125afb8f..808648d4b4 100644
--- a/src/device/Makefile.inc
+++ b/src/device/Makefile.inc
@@ -63,3 +63,5 @@ ramstage-$(CONFIG_RESOURCE_ALLOCATOR_V3) += resource_allocator_v3.c
ramstage-$(CONFIG_RESOURCE_ALLOCATOR_V4) += resource_allocator_v4.c
ramstage-$(CONFIG_XHCI_UTILS) += xhci.c
+
+ramstage-y += gpio.c
diff --git a/src/device/device_const.c b/src/device/device_const.c
index 2dc583ca27..5288a743b6 100644
--- a/src/device/device_const.c
+++ b/src/device/device_const.c
@@ -162,6 +162,9 @@ static int path_eq(const struct device_path *path1,
case DEVICE_PATH_LPC:
equal = (path1->lpc.addr == path2->lpc.addr);
break;
+ case DEVICE_PATH_GPIO:
+ equal = (path1->gpio.id == path2->gpio.id);
+ break;
default:
printk(BIOS_ERR, "Unknown device type: %d\n", path1->type);
break;
diff --git a/src/device/device_util.c b/src/device/device_util.c
index 452a87bf14..0bce26a99e 100644
--- a/src/device/device_util.c
+++ b/src/device/device_util.c
@@ -130,6 +130,9 @@ u32 dev_path_encode(const struct device *dev)
case DEVICE_PATH_USB:
ret |= dev->path.usb.port_type << 8 | dev->path.usb.port_id;
break;
+ case DEVICE_PATH_GPIO:
+ ret |= dev->path.gpio.id;
+ break;
case DEVICE_PATH_NONE:
case DEVICE_PATH_MMIO: /* don't care */
default:
@@ -223,6 +226,9 @@ const char *dev_path(const struct device *dev)
snprintf(buffer, sizeof(buffer), "LPC: %08lx",
dev->path.lpc.addr);
break;
+ case DEVICE_PATH_GPIO:
+ snprintf(buffer, sizeof(buffer), "GPIO: %d", dev->path.gpio.id);
+ break;
default:
printk(BIOS_ERR, "Unknown device path type: %d\n",
dev->path.type);
diff --git a/src/device/gpio.c b/src/device/gpio.c
new file mode 100644
index 0000000000..5e71497024
--- /dev/null
+++ b/src/device/gpio.c
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/gpio.h>
+
+const struct gpio_operations *dev_get_gpio_ops(struct device *dev)
+{
+ if (!dev) {
+ printk(BIOS_ERR, "Could not get gpio operations, device is NULL.");
+ return NULL;
+ } else if (!dev->ops) {
+ printk(BIOS_ERR, "Could not get gpio operations, dev->ops is NULL.");
+ return NULL;
+ } else if (!dev->ops->ops_gpio) {
+ printk(BIOS_ERR, "Could not get gpio operations, ops_gpio is NULL.");
+ return NULL;
+ }
+
+ return dev->ops->ops_gpio;
+}
diff --git a/src/include/device/device.h b/src/include/device/device.h
index 786a640f39..d83cfe4075 100644
--- a/src/include/device/device.h
+++ b/src/include/device/device.h
@@ -16,6 +16,7 @@ struct smbus_bus_operations;
struct pnp_mode_ops;
struct spi_bus_operations;
struct usb_bus_operations;
+struct gpio_operations;
/* Chip operations */
struct chip_operations {
@@ -62,6 +63,7 @@ struct device_operations {
const struct spi_bus_operations *ops_spi_bus;
const struct smbus_bus_operations *ops_smbus_bus;
const struct pnp_mode_ops *ops_pnp_mode;
+ const struct gpio_operations *ops_gpio;
};
/**
diff --git a/src/include/device/gpio.h b/src/include/device/gpio.h
new file mode 100644
index 0000000000..67975b3c45
--- /dev/null
+++ b/src/include/device/gpio.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __DEVICE_GPIO_H__
+#define __DEVICE_GPIO_H__
+
+#include <types.h>
+
+struct gpio_operations {
+ int (*get)(uint32_t gpio);
+ void (*set)(uint32_t gpio, int value);
+ void (*input_pulldown)(uint32_t gpio);
+ void (*input_pullup)(uint32_t gpio);
+ void (*input)(uint32_t gpio);
+ void (*output)(uint32_t gpio, int value);
+};
+
+/* Helper for getting gpio operations from a device */
+const struct gpio_operations *dev_get_gpio_ops(struct device *dev);
+
+#endif /* __DEVICE_GPIO_H__ */
diff --git a/src/include/device/path.h b/src/include/device/path.h
index 5690badc4c..0cdb997726 100644
--- a/src/include/device/path.h
+++ b/src/include/device/path.h
@@ -21,6 +21,7 @@ enum device_path_type {
DEVICE_PATH_MMIO,
DEVICE_PATH_ESPI,
DEVICE_PATH_LPC,
+ DEVICE_PATH_GPIO,
/*
* When adding path types to this table, please also update the
@@ -46,6 +47,7 @@ enum device_path_type {
"DEVICE_PATH_MMIO", \
"DEVICE_PATH_ESPI", \
"DEVICE_PATH_LPC", \
+ "DEVICE_PATH_GPIO", \
}
struct domain_path {
@@ -116,6 +118,10 @@ struct lpc_path {
uintptr_t addr;
};
+struct gpio_path {
+ unsigned int id;
+};
+
struct device_path {
enum device_path_type type;
union {
@@ -134,6 +140,7 @@ struct device_path {
struct mmio_path mmio;
struct espi_path espi;
struct lpc_path lpc;
+ struct gpio_path gpio;
};
};