From b471bdc47b2acabe0b5fcb0fb40a0b1c0602d3b3 Mon Sep 17 00:00:00 2001 From: Stefan Herbrechtsmeier Date: Tue, 14 Jun 2022 15:21:30 +0200 Subject: dm: core: Add functions to read 8/16-bit integers Add functions to read 8/16-bit integers like the existing functions for 32/64-bit to simplify read of 8/16-bit integers from device tree properties. Signed-off-by: Stefan Herbrechtsmeier Reviewed-by: Marek Vasut Reviewed-by: Simon Glass Reviewed-by: Simon Glass --- include/dm/of_access.h | 32 +++++++++++++++++++++++++ include/dm/ofnode.h | 40 +++++++++++++++++++++++++++++++ include/dm/read.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) (limited to 'include') diff --git a/include/dm/of_access.h b/include/dm/of_access.h index 5b7821d0a1b..83f34f0d2ad 100644 --- a/include/dm/of_access.h +++ b/include/dm/of_access.h @@ -264,6 +264,38 @@ struct device_node *of_find_node_by_prop_value(struct device_node *from, */ struct device_node *of_find_node_by_phandle(phandle handle); +/** + * of_read_u8() - Find and read a 8-bit integer from a property + * + * Search for a property in a device node and read a 8-bit value from + * it. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @outp: pointer to return value, modified only if return value is 0. + * + * Return: 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + */ +int of_read_u8(const struct device_node *np, const char *propname, u8 *outp); + +/** + * of_read_u16() - Find and read a 16-bit integer from a property + * + * Search for a property in a device node and read a 16-bit value from + * it. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @outp: pointer to return value, modified only if return value is 0. + * + * Return: 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + */ +int of_read_u16(const struct device_node *np, const char *propname, u16 *outp); + /** * of_read_u32() - Find and read a 32-bit integer from a property * diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 7ce1e4c6d91..f6085231bbd 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -221,6 +221,46 @@ static inline oftree oftree_default(void) */ bool ofnode_name_eq(ofnode node, const char *name); +/** + * ofnode_read_u8() - Read a 8-bit integer from a property + * + * @node: valid node reference to read property from + * @propname: name of the property to read from + * @outp: place to put value (if found) + * Return: 0 if OK, -ve on error + */ +int ofnode_read_u8(ofnode node, const char *propname, u8 *outp); + +/** + * ofnode_read_u8_default() - Read a 8-bit integer from a property + * + * @node: valid node reference to read property from + * @propname: name of the property to read from + * @def: default value to return if the property has no value + * Return: property value, or @def if not found + */ +u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def); + +/** + * ofnode_read_u16() - Read a 16-bit integer from a property + * + * @node: valid node reference to read property from + * @propname: name of the property to read from + * @outp: place to put value (if found) + * Return: 0 if OK, -ve on error + */ +int ofnode_read_u16(ofnode node, const char *propname, u16 *outp); + +/** + * ofnode_read_u16_default() - Read a 16-bit integer from a property + * + * @node: valid node reference to read property from + * @propname: name of the property to read from + * @def: default value to return if the property has no value + * Return: property value, or @def if not found + */ +u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def); + /** * ofnode_read_u32() - Read a 32-bit integer from a property * diff --git a/include/dm/read.h b/include/dm/read.h index 1b54b69acf0..122b9cd15b8 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -31,6 +31,47 @@ static inline const struct device_node *dev_np(const struct udevice *dev) #endif #if !defined(CONFIG_DM_DEV_READ_INLINE) || CONFIG_IS_ENABLED(OF_PLATDATA) +/** + * dev_read_u8() - read a 8-bit integer from a device's DT property + * + * @dev: device to read DT property from + * @propname: name of the property to read from + * @outp: place to put value (if found) + * Return: 0 if OK, -ve on error + */ +int dev_read_u8(const struct udevice *dev, const char *propname, u8 *outp); + +/** + * dev_read_u8_default() - read a 8-bit integer from a device's DT property + * + * @dev: device to read DT property from + * @propname: name of the property to read from + * @def: default value to return if the property has no value + * Return: property value, or @def if not found + */ +u8 dev_read_u8_default(const struct udevice *dev, const char *propname, u8 def); + +/** + * dev_read_u16() - read a 16-bit integer from a device's DT property + * + * @dev: device to read DT property from + * @propname: name of the property to read from + * @outp: place to put value (if found) + * Return: 0 if OK, -ve on error + */ +int dev_read_u16(const struct udevice *dev, const char *propname, u16 *outp); + +/** + * dev_read_u16_default() - read a 16-bit integer from a device's DT property + * + * @dev: device to read DT property from + * @propname: name of the property to read from + * @def: default value to return if the property has no value + * Return: property value, or @def if not found + */ +u16 dev_read_u16_default(const struct udevice *dev, const char *propname, + u16 def); + /** * dev_read_u32() - read a 32-bit integer from a device's DT property * @@ -772,6 +813,30 @@ phy_interface_t dev_read_phy_mode(const struct udevice *dev); #else /* CONFIG_DM_DEV_READ_INLINE is enabled */ #include +static inline int dev_read_u8(const struct udevice *dev, + const char *propname, u8 *outp) +{ + return ofnode_read_u8(dev_ofnode(dev), propname, outp); +} + +static inline int dev_read_u8_default(const struct udevice *dev, + const char *propname, u8 def) +{ + return ofnode_read_u8_default(dev_ofnode(dev), propname, def); +} + +static inline int dev_read_u16(const struct udevice *dev, + const char *propname, u16 *outp) +{ + return ofnode_read_u16(dev_ofnode(dev), propname, outp); +} + +static inline int dev_read_u16_default(const struct udevice *dev, + const char *propname, u16 def) +{ + return ofnode_read_u16_default(dev_ofnode(dev), propname, def); +} + static inline int dev_read_u32(const struct udevice *dev, const char *propname, u32 *outp) { -- cgit v1.3.1 From 94ccfb78a4d61cac7cbc78f23751ec1db949d29e Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Tue, 26 Jul 2022 16:21:42 +0200 Subject: drivers: tee: optee: discover OP-TEE services This change defines resources for OP-TEE service drivers to register themselves for being bound to when OP-TEE firmware reports the related service is supported. OP-TEE services are discovered during optee driver probe sequence which mandates optee driver is always probe once bound. Discovery of optee services and binding to related U-Boot drivers is embedded upon configuration switch CONFIG_OPTEE_SERVICE_DISCOVERY. Cc: Jens Wiklander Cc: Patrick Delaunay Signed-off-by: Etienne Carriere Reviewed-by: Patrick Delaunay --- drivers/tee/optee/Kconfig | 8 +++ drivers/tee/optee/core.c | 171 ++++++++++++++++++++++++++++++++++++++++++-- include/tee/optee_service.h | 34 +++++++++ 3 files changed, 208 insertions(+), 5 deletions(-) create mode 100644 include/tee/optee_service.h (limited to 'include') diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index d03028070b9..9dc65b0501e 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -37,6 +37,14 @@ config OPTEE_TA_SCP03 help Enables support for controlling (enabling, provisioning) the Secure Channel Protocol 03 operation in the OP-TEE SCP03 TA. + +config OPTEE_SERVICE_DISCOVERY + bool "OP-TEE service discovery" + default y + help + This implements automated driver binding of OP-TEE service drivers by + requesting OP-TEE firmware to enumerate its hosted services. + endmenu endif diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index c1f5fc4c7a1..9240277579b 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "optee_smc.h" #include "optee_msg.h" @@ -22,6 +23,25 @@ #define PAGELIST_ENTRIES_PER_PAGE \ ((OPTEE_MSG_NONCONTIG_PAGE_SIZE / sizeof(u64)) - 1) +/* + * PTA_DEVICE_ENUM interface exposed by OP-TEE to discover enumerated services + */ +#define PTA_DEVICE_ENUM { 0x7011a688, 0xddde, 0x4053, \ + { 0xa5, 0xa9, 0x7b, 0x3c, 0x4d, 0xdf, 0x13, 0xb8 } } +/* + * PTA_CMD_GET_DEVICES - List services without supplicant dependencies + * + * [out] memref[0]: List of the UUIDs of service enumerated by OP-TEE + */ +#define PTA_CMD_GET_DEVICES 0x0 + +/* + * PTA_CMD_GET_DEVICES_SUPP - List services depending on tee supplicant + * + * [out] memref[0]: List of the UUIDs of service enumerated by OP-TEE + */ +#define PTA_CMD_GET_DEVICES_SUPP 0x1 + typedef void (optee_invoke_fn)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, @@ -42,6 +62,134 @@ struct rpc_param { u32 a7; }; +static struct optee_service *find_service_driver(const struct tee_optee_ta_uuid *uuid) +{ + struct optee_service *service; + u8 loc_uuid[TEE_UUID_LEN]; + size_t service_cnt, idx; + + service_cnt = ll_entry_count(struct optee_service, optee_service); + service = ll_entry_start(struct optee_service, optee_service); + + for (idx = 0; idx < service_cnt; idx++, service++) { + tee_optee_ta_uuid_to_octets(loc_uuid, &service->uuid); + if (!memcmp(uuid, loc_uuid, sizeof(uuid))) + return service; + } + + return NULL; +} + +static int bind_service_list(struct udevice *dev, struct tee_shm *service_list, size_t count) +{ + const struct tee_optee_ta_uuid *service_uuid = (const void *)service_list->addr; + struct optee_service *service; + size_t idx; + int ret; + + for (idx = 0; idx < count; idx++) { + service = find_service_driver(service_uuid + idx); + if (!service) + continue; + + ret = device_bind_driver(dev, service->driver_name, service->driver_name, NULL); + if (ret) { + dev_warn(dev, "%s was not bound: %d, ignored\n", service->driver_name, ret); + continue; + } + } + + return 0; +} + +static int __enum_services(struct udevice *dev, struct tee_shm *shm, size_t *shm_size, u32 tee_sess) +{ + struct tee_invoke_arg arg = { }; + struct tee_param param = { }; + int ret = 0; + + arg.func = PTA_CMD_GET_DEVICES; + arg.session = tee_sess; + + /* Fill invoke cmd params */ + param.attr = TEE_PARAM_ATTR_TYPE_MEMREF_OUTPUT; + param.u.memref.shm = shm; + param.u.memref.size = *shm_size; + + ret = tee_invoke_func(dev, &arg, 1, ¶m); + if (ret || (arg.ret && arg.ret != TEE_ERROR_SHORT_BUFFER)) { + dev_err(dev, "PTA_CMD_GET_DEVICES invoke function err: 0x%x\n", arg.ret); + return -EINVAL; + } + + *shm_size = param.u.memref.size; + + return 0; +} + +static int enum_services(struct udevice *dev, struct tee_shm **shm, size_t *count, u32 tee_sess) +{ + size_t shm_size = 0; + int ret; + + ret = __enum_services(dev, NULL, &shm_size, tee_sess); + if (ret) + return ret; + + ret = tee_shm_alloc(dev, shm_size, 0, shm); + if (ret) { + dev_err(dev, "Failed to allocated shared memory: %d\n", ret); + return ret; + } + + ret = __enum_services(dev, *shm, &shm_size, tee_sess); + if (!ret) + *count = shm_size / sizeof(struct tee_optee_ta_uuid); + + return ret; +} + +static int open_enum_session(struct udevice *dev, u32 *tee_sess) +{ + const struct tee_optee_ta_uuid pta_uuid = PTA_DEVICE_ENUM; + struct tee_open_session_arg arg = { }; + int ret; + + tee_optee_ta_uuid_to_octets(arg.uuid, &pta_uuid); + + ret = tee_open_session(dev, &arg, 0, NULL); + if (ret || arg.ret) { + if (!ret) + ret = -EIO; + return ret; + } + + *tee_sess = arg.session; + + return 0; +} + +static int bind_service_drivers(struct udevice *dev) +{ + struct tee_shm *service_list = NULL; + size_t service_count; + u32 tee_sess; + int ret; + + ret = open_enum_session(dev, &tee_sess); + if (ret) + return ret; + + ret = enum_services(dev, &service_list, &service_count, tee_sess); + if (!ret) + ret = bind_service_list(dev, service_list, service_count); + + tee_shm_free(service_list); + tee_close_session(dev, tee_sess); + + return ret; +} + /** * reg_pair_to_ptr() - Make a pointer of 2 32-bit values * @reg0: High bits of the pointer @@ -638,6 +786,14 @@ static int optee_of_to_plat(struct udevice *dev) return 0; } +static int optee_bind(struct udevice *dev) +{ + if (IS_ENABLED(CONFIG_OPTEE_SERVICE_DISCOVERY)) + dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND); + + return 0; +} + static int optee_probe(struct udevice *dev) { struct optee_pdata *pdata = dev_get_plat(dev); @@ -667,11 +823,15 @@ static int optee_probe(struct udevice *dev) return -ENOENT; } - /* - * in U-Boot, the discovery of TA on the TEE bus is not supported: - * only bind the drivers associated to the supported OP-TEE TA - */ - if (IS_ENABLED(CONFIG_RNG_OPTEE)) { + if (IS_ENABLED(CONFIG_OPTEE_SERVICE_DISCOVERY)) { + ret = bind_service_drivers(dev); + if (ret) + return ret; + } else if (IS_ENABLED(CONFIG_RNG_OPTEE)) { + /* + * Discovery of TAs on the TEE bus is not supported in U-Boot: + * only bind the drivers associated to the supported OP-TEE TA + */ ret = device_bind_driver(dev, "optee-rng", "optee-rng", NULL); if (ret) return ret; @@ -691,6 +851,7 @@ U_BOOT_DRIVER(optee) = { .of_match = optee_match, .of_to_plat = optee_of_to_plat, .probe = optee_probe, + .bind = optee_bind, .ops = &optee_ops, .plat_auto = sizeof(struct optee_pdata), .priv_auto = sizeof(struct optee_private), diff --git a/include/tee/optee_service.h b/include/tee/optee_service.h new file mode 100644 index 00000000000..fca468af7c4 --- /dev/null +++ b/include/tee/optee_service.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * (C) Copyright 2022 Linaro Limited + */ + +#ifndef _OPTEE_SERVICE_H +#define _OPTEE_SERVICE_H + +/* + * struct optee_service - Discoverable OP-TEE service + * + * @driver_name - Name of the related driver + * @uuid - UUID of the OP-TEE service related to the driver + * + * Use macro OPTEE_SERVICE_DRIVER() to register a driver related to an + * OP-TEE service discovered when driver asks OP-TEE services enumaration. + */ +struct optee_service { + const char *driver_name; + const struct tee_optee_ta_uuid uuid; +}; + +#ifdef CONFIG_OPTEE_SERVICE_DISCOVERY +#define OPTEE_SERVICE_DRIVER(__name, __uuid, __drv_name) \ + ll_entry_declare(struct optee_service, __name, optee_service) = { \ + .uuid = __uuid, \ + .driver_name = __drv_name, \ + } +#else +#define OPTEE_SERVICE_DRIVER(__name, __uuid, __drv_name) \ + static int __name##__COUNTER__ __always_unused +#endif + +#endif /* _OPTEE_SERVICE_H */ -- cgit v1.3.1 From f6f681642f0d730887bfe944b029cb6f76a35fb6 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 30 Aug 2022 14:09:14 +0200 Subject: gpio: sandbox: Add GPIOD_IS_AF for gpio configured in alternate function This allows to test if a pin's label if displayed using gpio_get_status() when this pin is configured in alternate function. Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass Reviewed-by: Patrick Delaunay --- drivers/gpio/sandbox.c | 5 +++++ include/asm-generic/gpio.h | 1 + include/dt-bindings/gpio/sandbox-gpio.h | 3 +++ test/dm/gpio.c | 30 ++++++++++++++++++++++++++++++ 4 files changed, 39 insertions(+) (limited to 'include') diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index 106b2a7b27c..305f9a6ff62 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -196,6 +196,8 @@ static int sb_gpio_get_function(struct udevice *dev, unsigned offset) return GPIOF_OUTPUT; if (get_gpio_flag(dev, offset, GPIOD_IS_IN)) return GPIOF_INPUT; + if (get_gpio_flag(dev, offset, GPIOD_IS_AF)) + return GPIOF_FUNC; return GPIOF_INPUT; /*GPIO is not configurated */ } @@ -219,6 +221,9 @@ static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, if (args->args[1] & GPIO_OUT_ACTIVE) desc->flags |= GPIOD_IS_OUT_ACTIVE; + if (args->args[1] & GPIO_AF) + desc->flags |= GPIOD_IS_AF; + return 0; } diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 81f63f06f15..0fcf70983fb 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -127,6 +127,7 @@ struct gpio_desc { #define GPIOD_OPEN_SOURCE BIT(6) /* GPIO is open source type */ #define GPIOD_PULL_UP BIT(7) /* GPIO has pull-up enabled */ #define GPIOD_PULL_DOWN BIT(8) /* GPIO has pull-down enabled */ +#define GPIOD_IS_AF BIT(9) /* GPIO is an alternate function */ /* Flags for updating the above */ #define GPIOD_MASK_DIR (GPIOD_IS_OUT | GPIOD_IS_IN | \ diff --git a/include/dt-bindings/gpio/sandbox-gpio.h b/include/dt-bindings/gpio/sandbox-gpio.h index e4bfdb3ce1d..05f98365839 100644 --- a/include/dt-bindings/gpio/sandbox-gpio.h +++ b/include/dt-bindings/gpio/sandbox-gpio.h @@ -21,4 +21,7 @@ /* Bit 18 express GPIO output is active */ #define GPIO_OUT_ACTIVE 0x40000 +/* Bit 19 express GPIO set as alternate function */ +#define GPIO_AF 0x80000 + #endif diff --git a/test/dm/gpio.c b/test/dm/gpio.c index 33ae98701f4..a8c35d43704 100644 --- a/test/dm/gpio.c +++ b/test/dm/gpio.c @@ -778,3 +778,33 @@ static int dm_test_gpio_get_values_as_int_base3(struct unit_test_state *uts) } DM_TEST(dm_test_gpio_get_values_as_int_base3, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +/* Check that gpio_get_status return the label of a GPIO configured as GPIOD_AF */ +static int dm_test_gpio_function(struct unit_test_state *uts) +{ + struct gpio_desc desc; + struct udevice *dev; + ulong flags; + unsigned int offset, gpio; + char buf[80]; + + ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); + ut_asserteq_str("a-test", dev->name); + + /* request gpio_b 5 */ + ut_assertok(gpio_request_by_name(dev, "test-gpios", 2, &desc, 0)); + /* update gpio_b 5 function to GPIO_AF */ + ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_IS_AF, GPIOD_IS_AF)); + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_AF, flags); + /* check using gpio_get_status that label is displayed for a pin with GPIO_AF function */ + ut_assertok(gpio_lookup_name("b5", &dev, &offset, &gpio)); + ut_assertok(gpio_get_status(dev, offset, buf, sizeof(buf))); + ut_asserteq_str("b5: func a-test.test-gpios2", buf); + + ut_assertok(dm_gpio_free(dev, &desc)); + + return 0; +} +DM_TEST(dm_test_gpio_function, + UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); -- cgit v1.3.1