| // SPDX-License-Identifier: BSD-2-Clause |
| /* |
| * Copyright 2019 Broadcom. |
| */ |
| |
| #include <drivers/bcm_gpio.h> |
| #include <io.h> |
| #include <kernel/pseudo_ta.h> |
| #include <trace.h> |
| |
| #define GPIO_SERVICE_UUID \ |
| { 0x6272636D, 0x2018, 0x1101, \ |
| { 0x42, 0x43, 0x4D, 0x5F, 0x47, 0x50, 0x49, 0x4F } } |
| |
| /* |
| * Configure GPIO Pin |
| * |
| * [in] value[0].a: gpio pin number |
| * [in] value[0].b: direction to configure |
| */ |
| #define PTA_BCM_GPIO_CMD_CFG 0 |
| |
| /* |
| * Set GPIO pin |
| * |
| * [in] value[0].a: gpio pin number |
| * [in] value[0].b: value drive on pin |
| */ |
| #define PTA_BCM_GPIO_CMD_SET 1 |
| |
| /* |
| * Get GPIO pin |
| * |
| * [in] value[0].a: gpio pin number |
| * [out] value[1].a: value read from gpio pin |
| */ |
| #define PTA_BCM_GPIO_CMD_GET 2 |
| |
| #define GPIO_TA_NAME "pta_bcm_gpio.ta" |
| |
| static TEE_Result pta_gpio_config(uint32_t param_types, |
| TEE_Param params[TEE_NUM_PARAMS]) |
| { |
| uint32_t gpio_num = 0; |
| struct bcm_gpio_chip *bcm_gc = NULL; |
| struct gpio_chip *gc = NULL; |
| bool dir = false; |
| TEE_Result res = TEE_SUCCESS; |
| uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, |
| TEE_PARAM_TYPE_NONE, |
| TEE_PARAM_TYPE_NONE, |
| TEE_PARAM_TYPE_NONE); |
| |
| if (exp_param_types != param_types) { |
| EMSG("Invalid Param types"); |
| return TEE_ERROR_BAD_PARAMETERS; |
| } |
| |
| gpio_num = params[0].value.a; |
| dir = params[0].value.b; |
| |
| bcm_gc = bcm_gpio_pin_to_chip(gpio_num); |
| if (!bcm_gc) { |
| EMSG("GPIO %u not supported", gpio_num); |
| return TEE_ERROR_NOT_SUPPORTED; |
| } |
| |
| gc = &bcm_gc->chip; |
| |
| /* Make gpio secure. */ |
| iproc_gpio_set_secure(gpio_num); |
| |
| if (dir) { |
| /* Set GPIO to output with default value to 0 */ |
| gc->ops->set_direction(gpio_num, GPIO_DIR_OUT); |
| gc->ops->set_value(gpio_num, 0); |
| } else { |
| gc->ops->set_direction(gpio_num, GPIO_DIR_IN); |
| } |
| |
| return res; |
| } |
| |
| static TEE_Result pta_gpio_set(uint32_t param_types, |
| TEE_Param params[TEE_NUM_PARAMS]) |
| { |
| uint32_t gpio_num = 0; |
| uint32_t val = 0; |
| TEE_Result res = TEE_SUCCESS; |
| struct bcm_gpio_chip *bcm_gc = NULL; |
| struct gpio_chip *gc = NULL; |
| uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, |
| TEE_PARAM_TYPE_NONE, |
| TEE_PARAM_TYPE_NONE, |
| TEE_PARAM_TYPE_NONE); |
| |
| if (exp_param_types != param_types) { |
| EMSG("Invalid Param types"); |
| return TEE_ERROR_BAD_PARAMETERS; |
| } |
| |
| gpio_num = params[0].value.a; |
| val = !!params[0].value.b; |
| |
| bcm_gc = bcm_gpio_pin_to_chip(gpio_num); |
| if (!bcm_gc) { |
| EMSG("GPIO %u not supported", gpio_num); |
| return TEE_ERROR_NOT_SUPPORTED; |
| } |
| |
| gc = &bcm_gc->chip; |
| |
| /* |
| * For setting a value to GPIO Pin, |
| * need to make sure the PIN is configured in |
| * output direction. |
| */ |
| if (gc->ops->get_direction(gpio_num) != GPIO_DIR_OUT) { |
| EMSG("gpio pin %u is configured as INPUT", gpio_num); |
| return TEE_ERROR_ACCESS_DENIED; |
| } |
| |
| gc->ops->set_value(gpio_num, val); |
| |
| DMSG("GPIO(%d) value = 0x%08x", gpio_num, gc->ops->get_value(gpio_num)); |
| |
| return res; |
| } |
| |
| static TEE_Result pta_gpio_get(uint32_t param_types, |
| TEE_Param params[TEE_NUM_PARAMS]) |
| { |
| uint32_t gpio_num = 0; |
| struct bcm_gpio_chip *bcm_gc = NULL; |
| struct gpio_chip *gc = NULL; |
| uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, |
| TEE_PARAM_TYPE_VALUE_OUTPUT, |
| TEE_PARAM_TYPE_NONE, |
| TEE_PARAM_TYPE_NONE); |
| |
| if (exp_param_types != param_types) { |
| EMSG("Invalid Param types"); |
| return TEE_ERROR_BAD_PARAMETERS; |
| } |
| |
| gpio_num = params[0].value.a; |
| |
| bcm_gc = bcm_gpio_pin_to_chip(gpio_num); |
| if (!bcm_gc) { |
| EMSG("GPIO %u not supported", gpio_num); |
| return TEE_ERROR_NOT_SUPPORTED; |
| } |
| |
| gc = &bcm_gc->chip; |
| |
| params[1].value.a = gc->ops->get_value(gpio_num); |
| |
| DMSG("gpio(%d) value = 0x%08x", gpio_num, params[1].value.a); |
| |
| return TEE_SUCCESS; |
| } |
| |
| static TEE_Result invoke_command(void *session_context __unused, |
| uint32_t cmd_id, |
| uint32_t param_types, |
| TEE_Param params[TEE_NUM_PARAMS]) |
| { |
| TEE_Result res = TEE_SUCCESS; |
| |
| DMSG("command entry point[%d] for \"%s\"", cmd_id, GPIO_TA_NAME); |
| |
| switch (cmd_id) { |
| case PTA_BCM_GPIO_CMD_CFG: |
| res = pta_gpio_config(param_types, params); |
| break; |
| case PTA_BCM_GPIO_CMD_SET: |
| res = pta_gpio_set(param_types, params); |
| break; |
| case PTA_BCM_GPIO_CMD_GET: |
| res = pta_gpio_get(param_types, params); |
| break; |
| default: |
| EMSG("cmd: %d Not supported %s\n", cmd_id, GPIO_TA_NAME); |
| res = TEE_ERROR_NOT_SUPPORTED; |
| break; |
| } |
| |
| return res; |
| } |
| |
| pseudo_ta_register(.uuid = GPIO_SERVICE_UUID, |
| .name = GPIO_TA_NAME, |
| .flags = PTA_DEFAULT_FLAGS, |
| .invoke_command_entry_point = invoke_command); |