xref: /optee_os/core/drivers/atmel_piobu.c (revision 039e02df2716a0ed886b56e1e07b7ac1d8597228)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2022 Microchip
4  *
5  * Driver for AT91 PIOBU
6  */
7 
8 #include <assert.h>
9 #include <drivers/atmel_rtc.h>
10 #include <dt-bindings/gpio/atmel,piobu.h>
11 #include <gpio.h>
12 #include <io.h>
13 #include <kernel/boot.h>
14 #include <kernel/dt.h>
15 #include <kernel/pm.h>
16 #include <libfdt.h>
17 #include <mm/core_memprot.h>
18 
19 #define SECUMOD_MAX_PINS		8
20 #define SECUMOD_PIN_MASK		(BIT(SECUMOD_MAX_PINS) - 1)
21 #define SECUMOD_PIN_SHIFT		16
22 #define SECUMOD_PIN_VAL(pin)		BIT(SECUMOD_PIN_SHIFT + (pin))
23 
24 #define DT_GPIO_CELLS			2
25 
26 #define SECUMOD_CR			0x0
27 #define SECUMOD_CR_KEY_SHIFT		16
28 #define SECUMOD_CR_KEY			SHIFT_U32(0x89CA, SECUMOD_CR_KEY_SHIFT)
29 #define SECUMOD_CR_BACKUP		BIT(0)
30 #define SECUMOD_CR_NORMAL		BIT(1)
31 
32 #define SECUMOD_SR			0x8
33 #define SECUMOD_SR_JTAG			BIT(3)
34 #define SECUMOD_SR_TST_PIN			BIT(2)
35 
36 #define SECUMOD_SCR			0x10
37 
38 #define SECUMOD_PIOBU(x)		(0x18 + (x) * 0x4)
39 #define SECUMOD_PIOBU_AFV_MASK		GENMASK_32(3, 0)
40 #define SECUMOD_PIOBU_RFV_SHIFT		4
41 #define SECUMOD_PIOBU_OUTPUT		BIT(8)
42 #define SECUMOD_PIOBU_SOD		BIT(9)
43 #define SECUMOD_PIOBU_PDS		BIT(10)
44 #define SECUMOD_PIOBU_PULLUP_SHIFT	12
45 #define SECUMOD_PIOBU_SWITCH_SHIFT	15
46 
47 #define SECUMOD_JTAGCR			0x68
48 #define SECUMOD_JTAGCR_FNTRST		0x1
49 
50 #define SECUMOD_BMPR			0x7C
51 #define SECUMOD_NMPR			0x80
52 #define SECUMOD_NIEPR			0x84
53 #define SECUMOD_NIDPR			0x88
54 #define SECUMOD_NIMPR			0x8C
55 #define SECUMOD_WKPR			0x90
56 
57 static vaddr_t secumod_base;
58 static uint32_t gpio_protected;
59 static struct gpio_chip secumod_chip;
60 
61 /*
62  * Get value from GPIO controller
63  * chip:        pointer to GPIO controller chip instance
64  * gpio_pin:    pin from which value needs to be read
65  * Return target GPIO pin level.
66  */
67 static enum gpio_level gpio_get_value(struct gpio_chip *chip __unused,
68 				      unsigned int gpio_pin)
69 {
70 	vaddr_t piobu_addr = 0;
71 	uint32_t piobu = 0;
72 
73 	assert(gpio_pin < SECUMOD_MAX_PINS &&
74 	       !(gpio_protected & BIT32(gpio_pin)));
75 
76 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
77 	piobu = io_read32(piobu_addr);
78 
79 	if (piobu & SECUMOD_PIOBU_PDS)
80 		return GPIO_LEVEL_HIGH;
81 	else
82 		return GPIO_LEVEL_LOW;
83 }
84 
85 /*
86  * Set value for GPIO controller
87  * chip:        pointer to GPIO controller chip instance
88  * gpio_pin:    pin to which value needs to be written
89  * value:       Level state for the target pin
90  */
91 static void gpio_set_value(struct gpio_chip *chip __unused,
92 			   unsigned int gpio_pin, enum gpio_level value)
93 {
94 	vaddr_t piobu_addr = 0;
95 
96 	assert(gpio_pin < SECUMOD_MAX_PINS &&
97 	       !(gpio_protected & BIT32(gpio_pin)));
98 
99 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
100 
101 	if (value == GPIO_LEVEL_HIGH)
102 		io_setbits32(piobu_addr, SECUMOD_PIOBU_SOD);
103 	else
104 		io_clrbits32(piobu_addr, SECUMOD_PIOBU_SOD);
105 }
106 
107 /*
108  * Get direction from GPIO controller
109  * chip:        pointer to GPIO controller chip instance
110  * gpio_pin:    pin from which direction needs to be read
111  */
112 static enum gpio_dir gpio_get_direction(struct gpio_chip *chip __unused,
113 					unsigned int gpio_pin)
114 {
115 	vaddr_t piobu_addr = 0;
116 	uint32_t piobu = 0;
117 
118 	assert(gpio_pin < SECUMOD_MAX_PINS &&
119 	       !(gpio_protected & BIT32(gpio_pin)));
120 
121 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
122 	piobu = io_read32(piobu_addr);
123 
124 	if (piobu & SECUMOD_PIOBU_OUTPUT)
125 		return GPIO_DIR_OUT;
126 	else
127 		return GPIO_DIR_IN;
128 }
129 
130 /*
131  * Set direction for GPIO controller
132  * chip:        pointer to GPIO controller chip instance
133  * gpio_pin:    pin on which direction needs to be set
134  * direction:   direction which needs to be set on pin
135  */
136 static void gpio_set_direction(struct gpio_chip *chip __unused,
137 			       unsigned int gpio_pin, enum gpio_dir direction)
138 {
139 	vaddr_t piobu_addr = 0;
140 
141 	assert(gpio_pin < SECUMOD_MAX_PINS &&
142 	       !(gpio_protected & BIT32(gpio_pin)));
143 
144 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
145 
146 	if (direction == GPIO_DIR_OUT)
147 		io_setbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
148 	else
149 		io_clrbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
150 }
151 
152 /*
153  * Get interrupt from GPIO controller
154  * chip:        pointer to GPIO controller chip instance
155  * gpio_pin:    pin from which interrupt value needs to be read
156  */
157 static enum gpio_interrupt gpio_get_interrupt(struct gpio_chip *chip __unused,
158 					      unsigned int gpio_pin)
159 {
160 	vaddr_t nimpr_addr = secumod_base + SECUMOD_NIMPR;
161 	uint32_t data = 0;
162 
163 	assert(gpio_pin < SECUMOD_MAX_PINS &&
164 	       !(gpio_protected & BIT32(gpio_pin)));
165 
166 	data = io_read32(nimpr_addr);
167 
168 	if (data & SECUMOD_PIN_VAL(gpio_pin))
169 		return GPIO_INTERRUPT_ENABLE;
170 	else
171 		return GPIO_INTERRUPT_DISABLE;
172 }
173 
174 /*
175  * Set interrupt event for GPIO controller
176  * chip:        pointer to GPIO controller chip instance
177  * gpio_pin:    pin on which interrupt value needs to be set
178  * interrupt:   interrupt value which needs to be set on pin
179  */
180 static void gpio_set_interrupt(struct gpio_chip *chip __unused,
181 			       unsigned int gpio_pin,
182 			       enum gpio_interrupt interrupt)
183 {
184 	vaddr_t niepr_addr = secumod_base + SECUMOD_NIEPR;
185 
186 	assert(gpio_pin < SECUMOD_MAX_PINS &&
187 	       !(gpio_protected & BIT32(gpio_pin)));
188 
189 	if (interrupt == GPIO_INTERRUPT_ENABLE)
190 		io_setbits32(niepr_addr, SECUMOD_PIN_VAL(gpio_pin));
191 	else
192 		io_clrbits32(niepr_addr, SECUMOD_PIN_VAL(gpio_pin));
193 }
194 
195 static const struct gpio_ops atmel_piobu_ops = {
196 	.get_direction = gpio_get_direction,
197 	.set_direction = gpio_set_direction,
198 	.get_value = gpio_get_value,
199 	.set_value = gpio_set_value,
200 	.get_interrupt = gpio_get_interrupt,
201 	.set_interrupt = gpio_set_interrupt,
202 };
203 
204 static enum itr_return secumod_it_handler(struct itr_handler *handler __unused)
205 {
206 	int i = 0;
207 	struct optee_rtc_time tm = { };
208 	TEE_Result res = TEE_ERROR_GENERIC;
209 	uint32_t sr = io_read32(secumod_base + SECUMOD_SR);
210 
211 	for (i = 0; i < SECUMOD_MAX_PINS; i++) {
212 		if (sr & SECUMOD_PIN_VAL(i))
213 			EMSG("Detected tampering on pin %d", i);
214 	}
215 
216 	if (sr & SECUMOD_SR_JTAG)
217 		EMSG("JTAG tampering attempt");
218 
219 	if (sr & SECUMOD_SR_TST_PIN)
220 		EMSG("Test pin tampering attempt");
221 
222 	res = atmel_rtc_get_tamper_timestamp(&tm);
223 	if (!res) {
224 		EMSG("Date of tampering: %02"PRIu32"/%02"PRIu32"/%02"PRIu32"",
225 		     tm.tm_mday, tm.tm_mon, tm.tm_year);
226 		EMSG("Time of tampering: %02"PRIu32":%02"PRIu32":%02"PRIu32"",
227 		     tm.tm_hour, tm.tm_min, tm.tm_sec);
228 	}
229 
230 	io_write32(secumod_base + SECUMOD_SCR,
231 		   SECUMOD_PIN_MASK << SECUMOD_PIN_SHIFT);
232 
233 	panic("Tampering detected, system halted");
234 
235 	return ITRR_HANDLED;
236 }
237 
238 static struct itr_handler secumod_itr_handler = {
239 	.it = AT91C_ID_SECUMOD,
240 	.handler = secumod_it_handler,
241 };
242 
243 static void secumod_interrupt_init(void)
244 {
245 	itr_add_type_prio(&secumod_itr_handler, IRQ_TYPE_LEVEL_HIGH, 7);
246 	itr_enable(secumod_itr_handler.it);
247 }
248 
249 static void secumod_cfg_input_pio(uint8_t gpio_pin, uint32_t config)
250 {
251 	vaddr_t piobu_addr = 0;
252 	uint8_t afv = 0;
253 	uint8_t rfv = 0;
254 	uint8_t pull_mode = PIOBU_PIN_PULL_NONE;
255 	uint8_t def_level = PIOBU_PIN_DEF_LEVEL_LOW;
256 
257 	assert(gpio_pin < SECUMOD_MAX_PINS);
258 
259 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
260 
261 	/* Set GPIO as input */
262 	io_clrbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
263 
264 	afv = PIOBU_PIN_AFV(config);
265 	rfv = PIOBU_PIN_RFV(config);
266 	pull_mode = PIOBU_PIN_PULL_MODE(config);
267 	def_level = PIOBU_PIN_DEF_LEVEL(config);
268 
269 	io_write32(piobu_addr, afv | rfv << SECUMOD_PIOBU_RFV_SHIFT |
270 		   pull_mode << SECUMOD_PIOBU_PULLUP_SHIFT |
271 		   def_level << SECUMOD_PIOBU_SWITCH_SHIFT);
272 
273 	/* Enable Tampering Interrupt */
274 	gpio_set_interrupt(&secumod_chip, gpio_pin, GPIO_INTERRUPT_ENABLE);
275 
276 	/* Enable Intrusion Detection */
277 	io_setbits32(secumod_base + SECUMOD_NMPR, SECUMOD_PIN_VAL(gpio_pin));
278 
279 	/* Enable Wakeup */
280 	if (PIOBU_PIN_WAKEUP(config))
281 		io_setbits32(secumod_base + SECUMOD_WKPR,
282 			     SECUMOD_PIN_VAL(gpio_pin));
283 
284 	gpio_protected |= BIT32(gpio_pin);
285 }
286 
287 static void secumod_hw_init(const void *fdt, int node)
288 {
289 	int i = 0;
290 	int len = 0;
291 	uint8_t gpio_pin = 0;
292 	uint32_t config = 0;
293 	const uint32_t *prop = NULL;
294 
295 	/* Disable JTAG Reset and Debug */
296 	io_write32(secumod_base + SECUMOD_JTAGCR, SECUMOD_JTAGCR_FNTRST);
297 
298 	/* Switch IOs to normal mode */
299 	io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
300 		   SECUMOD_CR_NORMAL);
301 
302 	/* Clear all detection intrusion in normal mode */
303 	io_write32(secumod_base + SECUMOD_NMPR, 0);
304 
305 	/* Clear Alarms */
306 	io_write32(secumod_base + SECUMOD_SCR,
307 		   SECUMOD_PIN_MASK << SECUMOD_PIN_SHIFT);
308 
309 	/* Configure each IOs */
310 	prop = fdt_getprop(fdt, node, "gpios", &len);
311 	if (!prop)
312 		return;
313 
314 	len /= sizeof(uint32_t);
315 	for (i = 0; i < len; i += DT_GPIO_CELLS) {
316 		gpio_pin = fdt32_to_cpu(prop[i]);
317 		config = fdt32_to_cpu(prop[i + 1]);
318 
319 		secumod_cfg_input_pio(gpio_pin, config);
320 	}
321 }
322 
323 #ifdef CFG_PM_ARM32
324 static TEE_Result piobu_pm(enum pm_op op, uint32_t pm_hint __unused,
325 			   const struct pm_callback_handle *hdl __unused)
326 {
327 	switch (op) {
328 	case PM_OP_RESUME:
329 		io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
330 			   SECUMOD_CR_NORMAL);
331 		break;
332 	case PM_OP_SUSPEND:
333 		/* Enter backup mode before suspending */
334 		io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
335 			   SECUMOD_CR_BACKUP);
336 		break;
337 	default:
338 		panic("Invalid PM operation");
339 	}
340 
341 	return TEE_SUCCESS;
342 }
343 
344 static void piobu_register_pm(void)
345 {
346 	register_pm_driver_cb(piobu_pm, NULL, "piobu");
347 }
348 #else
349 static void piobu_register_pm(void) {}
350 #endif
351 
352 static TEE_Result atmel_secumod_probe(const void *fdt, int node,
353 				      const void *compat_data __unused)
354 {
355 	size_t size = 0;
356 
357 	if (secumod_base)
358 		return TEE_ERROR_GENERIC;
359 
360 	if (dt_map_dev(fdt, node, &secumod_base, &size) < 0)
361 		return TEE_ERROR_GENERIC;
362 
363 	secumod_hw_init(fdt, node);
364 	secumod_interrupt_init();
365 
366 	secumod_chip.ops = &atmel_piobu_ops;
367 
368 	piobu_register_pm();
369 
370 	return TEE_SUCCESS;
371 }
372 
373 static const struct dt_device_match atmel_secumod_match_table[] = {
374 	{ .compatible = "atmel,sama5d2-secumod" },
375 	{ }
376 };
377 
378 DEFINE_DT_DRIVER(atmel_secumod_dt_driver) = {
379 	.name = "atmel_secumod",
380 	.type = DT_DRIVER_NOTYPE,
381 	.match_table = atmel_secumod_match_table,
382 	.probe = atmel_secumod_probe,
383 };
384