1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2019 Broadcom.
4 */
5
6 #include <drivers/bcm_gpio.h>
7 #include <io.h>
8 #include <kernel/pseudo_ta.h>
9 #include <trace.h>
10
11 #define GPIO_SERVICE_UUID \
12 { 0x6272636D, 0x2018, 0x1101, \
13 { 0x42, 0x43, 0x4D, 0x5F, 0x47, 0x50, 0x49, 0x4F } }
14
15 /*
16 * Configure GPIO Pin
17 *
18 * [in] value[0].a: gpio pin number
19 * [in] value[0].b: direction to configure
20 */
21 #define PTA_BCM_GPIO_CMD_CFG 0
22
23 /*
24 * Set GPIO pin
25 *
26 * [in] value[0].a: gpio pin number
27 * [in] value[0].b: value drive on pin
28 */
29 #define PTA_BCM_GPIO_CMD_SET 1
30
31 /*
32 * Get GPIO pin
33 *
34 * [in] value[0].a: gpio pin number
35 * [out] value[1].a: value read from gpio pin
36 */
37 #define PTA_BCM_GPIO_CMD_GET 2
38
39 #define GPIO_TA_NAME "pta_bcm_gpio.ta"
40
pta_gpio_config(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])41 static TEE_Result pta_gpio_config(uint32_t param_types,
42 TEE_Param params[TEE_NUM_PARAMS])
43 {
44 uint32_t gpio_num = 0;
45 struct bcm_gpio_chip *bcm_gc = NULL;
46 struct gpio_chip *gc = NULL;
47 bool dir = false;
48 TEE_Result res = TEE_SUCCESS;
49 uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
50 TEE_PARAM_TYPE_NONE,
51 TEE_PARAM_TYPE_NONE,
52 TEE_PARAM_TYPE_NONE);
53
54 if (exp_param_types != param_types) {
55 EMSG("Invalid Param types");
56 return TEE_ERROR_BAD_PARAMETERS;
57 }
58
59 gpio_num = params[0].value.a;
60 dir = params[0].value.b;
61
62 bcm_gc = bcm_gpio_pin_to_chip(gpio_num);
63 if (!bcm_gc) {
64 EMSG("GPIO %u not supported", gpio_num);
65 return TEE_ERROR_NOT_SUPPORTED;
66 }
67
68 gc = &bcm_gc->chip;
69
70 /* Make gpio secure. */
71 iproc_gpio_set_secure(gpio_num);
72
73 if (dir) {
74 /* Set GPIO to output with default value to 0 */
75 gc->ops->set_direction(NULL, gpio_num, GPIO_DIR_OUT);
76 gc->ops->set_value(NULL, gpio_num, 0);
77 } else {
78 gc->ops->set_direction(NULL, gpio_num, GPIO_DIR_IN);
79 }
80
81 return res;
82 }
83
pta_gpio_set(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])84 static TEE_Result pta_gpio_set(uint32_t param_types,
85 TEE_Param params[TEE_NUM_PARAMS])
86 {
87 uint32_t gpio_num = 0;
88 uint32_t val = 0;
89 TEE_Result res = TEE_SUCCESS;
90 struct bcm_gpio_chip *bcm_gc = NULL;
91 struct gpio_chip *gc = NULL;
92 uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
93 TEE_PARAM_TYPE_NONE,
94 TEE_PARAM_TYPE_NONE,
95 TEE_PARAM_TYPE_NONE);
96
97 if (exp_param_types != param_types) {
98 EMSG("Invalid Param types");
99 return TEE_ERROR_BAD_PARAMETERS;
100 }
101
102 gpio_num = params[0].value.a;
103 val = !!params[0].value.b;
104
105 bcm_gc = bcm_gpio_pin_to_chip(gpio_num);
106 if (!bcm_gc) {
107 EMSG("GPIO %u not supported", gpio_num);
108 return TEE_ERROR_NOT_SUPPORTED;
109 }
110
111 gc = &bcm_gc->chip;
112
113 /*
114 * For setting a value to GPIO Pin,
115 * need to make sure the PIN is configured in
116 * output direction.
117 */
118 if (gc->ops->get_direction(NULL, gpio_num) != GPIO_DIR_OUT) {
119 EMSG("gpio pin %u is configured as INPUT", gpio_num);
120 return TEE_ERROR_ACCESS_DENIED;
121 }
122
123 gc->ops->set_value(NULL, gpio_num, val);
124
125 DMSG("GPIO(%d) value = 0x%08x", gpio_num,
126 gc->ops->get_value(NULL, gpio_num));
127
128 return res;
129 }
130
pta_gpio_get(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])131 static TEE_Result pta_gpio_get(uint32_t param_types,
132 TEE_Param params[TEE_NUM_PARAMS])
133 {
134 uint32_t gpio_num = 0;
135 struct bcm_gpio_chip *bcm_gc = NULL;
136 struct gpio_chip *gc = NULL;
137 uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
138 TEE_PARAM_TYPE_VALUE_OUTPUT,
139 TEE_PARAM_TYPE_NONE,
140 TEE_PARAM_TYPE_NONE);
141
142 if (exp_param_types != param_types) {
143 EMSG("Invalid Param types");
144 return TEE_ERROR_BAD_PARAMETERS;
145 }
146
147 gpio_num = params[0].value.a;
148
149 bcm_gc = bcm_gpio_pin_to_chip(gpio_num);
150 if (!bcm_gc) {
151 EMSG("GPIO %u not supported", gpio_num);
152 return TEE_ERROR_NOT_SUPPORTED;
153 }
154
155 gc = &bcm_gc->chip;
156
157 params[1].value.a = gc->ops->get_value(NULL, gpio_num);
158
159 DMSG("gpio(%d) value = 0x%08x", gpio_num, params[1].value.a);
160
161 return TEE_SUCCESS;
162 }
163
invoke_command(void * session_context __unused,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])164 static TEE_Result invoke_command(void *session_context __unused,
165 uint32_t cmd_id,
166 uint32_t param_types,
167 TEE_Param params[TEE_NUM_PARAMS])
168 {
169 TEE_Result res = TEE_SUCCESS;
170
171 DMSG("command entry point[%d] for \"%s\"", cmd_id, GPIO_TA_NAME);
172
173 switch (cmd_id) {
174 case PTA_BCM_GPIO_CMD_CFG:
175 res = pta_gpio_config(param_types, params);
176 break;
177 case PTA_BCM_GPIO_CMD_SET:
178 res = pta_gpio_set(param_types, params);
179 break;
180 case PTA_BCM_GPIO_CMD_GET:
181 res = pta_gpio_get(param_types, params);
182 break;
183 default:
184 EMSG("cmd: %d Not supported %s\n", cmd_id, GPIO_TA_NAME);
185 res = TEE_ERROR_NOT_SUPPORTED;
186 break;
187 }
188
189 return res;
190 }
191
192 pseudo_ta_register(.uuid = GPIO_SERVICE_UUID,
193 .name = GPIO_TA_NAME,
194 .flags = PTA_DEFAULT_FLAGS,
195 .invoke_command_entry_point = invoke_command);
196