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