xref: /optee_os/core/drivers/atmel_piobu.c (revision 4b17205bb9712a077992ac68eb980e9c3bd81348)
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 <drivers/gpio.h>
11 #include <dt-bindings/gpio/atmel,piobu.h>
12 #include <io.h>
13 #include <kernel/boot.h>
14 #include <kernel/dt.h>
15 #include <kernel/dt_driver.h>
16 #include <kernel/interrupt.h>
17 #include <kernel/pm.h>
18 #include <libfdt.h>
19 #include <mm/core_memprot.h>
20 
21 #define SECUMOD_MAX_PINS		(piobu_device->compat->max_pins)
22 #define SECUMOD_PIN_MASK		(BIT(SECUMOD_MAX_PINS) - 1)
23 #define SECUMOD_PIN_SHIFT		16
24 #define SECUMOD_PIN_VAL(pin)		BIT(SECUMOD_PIN_SHIFT + (pin))
25 
26 #define DT_GPIO_CELLS			2
27 
28 #define SECUMOD_CR			0x0
29 #define SECUMOD_CR_KEY_SHIFT		16
30 #define SECUMOD_CR_KEY			SHIFT_U32(0x89CA, SECUMOD_CR_KEY_SHIFT)
31 #define SECUMOD_CR_BACKUP		BIT(0)
32 #define SECUMOD_CR_NORMAL		BIT(1)
33 
34 #define SECUMOD_SR			0x8
35 #define SECUMOD_SR_JTAG			BIT(3)
36 #define SECUMOD_SR_TST_PIN			BIT(2)
37 
38 #define SECUMOD_SCR			0x10
39 
40 #define SECUMOD_PIOBU(x)		(0x18 + (x) * 0x4)
41 #define SECUMOD_PIOBU_AFV_MASK		GENMASK_32(3, 0)
42 #define SECUMOD_PIOBU_RFV_SHIFT		4
43 #define SECUMOD_PIOBU_OUTPUT		BIT(8)
44 #define SECUMOD_PIOBU_SOD		BIT(9)
45 #define SECUMOD_PIOBU_PDS		BIT(10)
46 #define SECUMOD_PIOBU_PULLUP_SHIFT	12
47 #define SECUMOD_PIOBU_SWITCH_SHIFT	15
48 
49 #define SECUMOD_JTAGCR_FNTRST		0x1
50 
51 /*
52  * PIOBU instance data
53  * @compat - Reference to compat data passed at driver initialization
54  */
55 struct piobu_instance {
56 	struct piobu_compat *compat;
57 };
58 
59 /*
60  * @max_pins	the number of the tamper I/Os
61  * @of_jtagcr	offset of SECUMOD JTAG Protection Control Register
62  * @of_bmpr	offset of SECUMOD Backup Mode Protection Register
63  * @of_nmpr	offset of SECUMOD Normal Mode Protection Register
64  * @of_niepr	offset of SECUMOD Normal Interrupt Enable Protection Register
65  * @of_nidpr	offset of SECUMOD Normal Interrupt Disable Protection Register
66  * @of_nimpr	offset of SECUMOD Normal Interrupt Mask Protection Register
67  * @of_wkpr	offset of SECUMOD Wake-up Register
68  */
69 struct piobu_compat {
70 	uint8_t max_pins;
71 	uint8_t of_jtagcr;
72 	uint8_t of_bmpr;
73 	uint8_t of_nmpr;
74 	uint8_t of_niepr;
75 	uint8_t of_nidpr;
76 	uint8_t of_nimpr;
77 	uint8_t of_wkpr;
78 };
79 
80 /* Expects at most a single instance */
81 static struct piobu_instance *piobu_device;
82 
83 static vaddr_t secumod_base;
84 static uint32_t gpio_protected;
85 static struct gpio_chip secumod_chip;
86 
87 /*
88  * Get value from GPIO controller
89  * chip:        pointer to GPIO controller chip instance
90  * gpio_pin:    pin from which value needs to be read
91  * Return target GPIO pin level.
92  */
secumod_gpio_get_value(struct gpio_chip * chip __unused,unsigned int gpio_pin)93 static enum gpio_level secumod_gpio_get_value(struct gpio_chip *chip __unused,
94 					      unsigned int gpio_pin)
95 {
96 	vaddr_t piobu_addr = 0;
97 	uint32_t piobu = 0;
98 
99 	assert(gpio_pin < SECUMOD_MAX_PINS &&
100 	       !(gpio_protected & BIT32(gpio_pin)));
101 
102 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
103 	piobu = io_read32(piobu_addr);
104 
105 	if (piobu & SECUMOD_PIOBU_PDS)
106 		return GPIO_LEVEL_HIGH;
107 	else
108 		return GPIO_LEVEL_LOW;
109 }
110 
111 /*
112  * Set value for GPIO controller
113  * chip:        pointer to GPIO controller chip instance
114  * gpio_pin:    pin to which value needs to be written
115  * value:       Level state for the target pin
116  */
secumod_gpio_set_value(struct gpio_chip * chip __unused,unsigned int gpio_pin,enum gpio_level value)117 static void secumod_gpio_set_value(struct gpio_chip *chip __unused,
118 				   unsigned int gpio_pin, enum gpio_level value)
119 {
120 	vaddr_t piobu_addr = 0;
121 
122 	assert(gpio_pin < SECUMOD_MAX_PINS &&
123 	       !(gpio_protected & BIT32(gpio_pin)));
124 
125 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
126 
127 	if (value == GPIO_LEVEL_HIGH)
128 		io_setbits32(piobu_addr, SECUMOD_PIOBU_SOD);
129 	else
130 		io_clrbits32(piobu_addr, SECUMOD_PIOBU_SOD);
131 }
132 
133 /*
134  * Get direction from GPIO controller
135  * chip:        pointer to GPIO controller chip instance
136  * gpio_pin:    pin from which direction needs to be read
137  */
secumod_gpio_get_direction(struct gpio_chip * chip __unused,unsigned int gpio_pin)138 static enum gpio_dir secumod_gpio_get_direction(struct gpio_chip *chip __unused,
139 						unsigned int gpio_pin)
140 {
141 	vaddr_t piobu_addr = 0;
142 	uint32_t piobu = 0;
143 
144 	assert(gpio_pin < SECUMOD_MAX_PINS &&
145 	       !(gpio_protected & BIT32(gpio_pin)));
146 
147 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
148 	piobu = io_read32(piobu_addr);
149 
150 	if (piobu & SECUMOD_PIOBU_OUTPUT)
151 		return GPIO_DIR_OUT;
152 	else
153 		return GPIO_DIR_IN;
154 }
155 
156 /*
157  * Set direction for GPIO controller
158  * chip:        pointer to GPIO controller chip instance
159  * gpio_pin:    pin on which direction needs to be set
160  * direction:   direction which needs to be set on pin
161  */
secumod_gpio_set_direction(struct gpio_chip * chip __unused,unsigned int gpio_pin,enum gpio_dir direction)162 static void secumod_gpio_set_direction(struct gpio_chip *chip __unused,
163 				       unsigned int gpio_pin,
164 				       enum gpio_dir direction)
165 {
166 	vaddr_t piobu_addr = 0;
167 
168 	assert(gpio_pin < SECUMOD_MAX_PINS &&
169 	       !(gpio_protected & BIT32(gpio_pin)));
170 
171 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
172 
173 	if (direction == GPIO_DIR_OUT)
174 		io_setbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
175 	else
176 		io_clrbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
177 }
178 
179 /*
180  * Get interrupt from GPIO controller
181  * chip:        pointer to GPIO controller chip instance
182  * gpio_pin:    pin from which interrupt value needs to be read
183  */
184 static enum gpio_interrupt
secumod_gpio_get_interrupt(struct gpio_chip * chip __unused,unsigned int gpio_pin)185 secumod_gpio_get_interrupt(struct gpio_chip *chip __unused,
186 			   unsigned int gpio_pin)
187 {
188 	vaddr_t nimpr_addr = secumod_base + piobu_device->compat->of_nimpr;
189 	uint32_t data = 0;
190 
191 	assert(gpio_pin < SECUMOD_MAX_PINS &&
192 	       !(gpio_protected & BIT32(gpio_pin)));
193 
194 	data = io_read32(nimpr_addr);
195 
196 	if (data & SECUMOD_PIN_VAL(gpio_pin))
197 		return GPIO_INTERRUPT_ENABLE;
198 	else
199 		return GPIO_INTERRUPT_DISABLE;
200 }
201 
202 /*
203  * Set interrupt event for GPIO controller
204  * chip:        pointer to GPIO controller chip instance
205  * gpio_pin:    pin on which interrupt value needs to be set
206  * interrupt:   interrupt value which needs to be set on pin
207  */
secumod_gpio_set_interrupt(struct gpio_chip * chip __unused,unsigned int gpio_pin,enum gpio_interrupt interrupt)208 static void secumod_gpio_set_interrupt(struct gpio_chip *chip __unused,
209 				       unsigned int gpio_pin,
210 				       enum gpio_interrupt interrupt)
211 {
212 	vaddr_t niepr_addr = secumod_base + piobu_device->compat->of_niepr;
213 
214 	assert(gpio_pin < SECUMOD_MAX_PINS &&
215 	       !(gpio_protected & BIT32(gpio_pin)));
216 
217 	if (interrupt == GPIO_INTERRUPT_ENABLE)
218 		io_setbits32(niepr_addr, SECUMOD_PIN_VAL(gpio_pin));
219 	else
220 		io_clrbits32(niepr_addr, SECUMOD_PIN_VAL(gpio_pin));
221 }
222 
223 static const struct gpio_ops atmel_piobu_ops = {
224 	.get_direction = secumod_gpio_get_direction,
225 	.set_direction = secumod_gpio_set_direction,
226 	.get_value = secumod_gpio_get_value,
227 	.set_value = secumod_gpio_set_value,
228 	.get_interrupt = secumod_gpio_get_interrupt,
229 	.set_interrupt = secumod_gpio_set_interrupt,
230 };
231 
secumod_dt_get(struct dt_pargs * pargs,void * data,struct gpio ** out_gpio)232 static TEE_Result secumod_dt_get(struct dt_pargs *pargs, void *data,
233 				 struct gpio **out_gpio)
234 {
235 	TEE_Result res = TEE_ERROR_GENERIC;
236 	struct gpio *gpio = NULL;
237 	struct gpio_chip *chip = data;
238 
239 	res = gpio_dt_alloc_pin(pargs, &gpio);
240 	if (res)
241 		return res;
242 
243 	if (gpio_protected & BIT32(gpio->pin)) {
244 		free(gpio);
245 		return TEE_ERROR_GENERIC;
246 	}
247 
248 	gpio->chip = chip;
249 	*out_gpio = gpio;
250 
251 	return TEE_SUCCESS;
252 }
253 
secumod_it_handler(struct itr_handler * handler __unused)254 static enum itr_return secumod_it_handler(struct itr_handler *handler __unused)
255 {
256 	int i = 0;
257 	struct optee_rtc_time tm = { };
258 	TEE_Result res = TEE_ERROR_GENERIC;
259 	uint32_t sr = io_read32(secumod_base + SECUMOD_SR);
260 
261 	for (i = 0; i < SECUMOD_MAX_PINS; i++) {
262 		if (sr & SECUMOD_PIN_VAL(i))
263 			EMSG("Detected tampering on pin %d", i);
264 	}
265 
266 	if (sr & SECUMOD_SR_JTAG)
267 		EMSG("JTAG tampering attempt");
268 
269 	if (sr & SECUMOD_SR_TST_PIN)
270 		EMSG("Test pin tampering attempt");
271 
272 	res = atmel_rtc_get_tamper_timestamp(&tm);
273 	if (!res) {
274 		EMSG("Date of tampering: %02"PRIu32"/%02"PRIu32"/%02"PRIu32"",
275 		     tm.tm_mday, tm.tm_mon, tm.tm_year);
276 		EMSG("Time of tampering: %02"PRIu32":%02"PRIu32":%02"PRIu32"",
277 		     tm.tm_hour, tm.tm_min, tm.tm_sec);
278 	}
279 
280 	io_write32(secumod_base + SECUMOD_SCR,
281 		   SECUMOD_PIN_MASK << SECUMOD_PIN_SHIFT);
282 
283 	panic("Tampering detected, system halted");
284 
285 	return ITRR_HANDLED;
286 }
287 
288 static struct itr_handler secumod_itr_handler = {
289 	.it = AT91C_ID_SECUMOD,
290 	.handler = secumod_it_handler,
291 };
292 
secumod_interrupt_init(void)293 static void secumod_interrupt_init(void)
294 {
295 	TEE_Result res = TEE_ERROR_GENERIC;
296 
297 	secumod_itr_handler.chip = interrupt_get_main_chip();
298 
299 	res = interrupt_add_configure_handler(&secumod_itr_handler,
300 					      IRQ_TYPE_LEVEL_HIGH, 7);
301 	if (res)
302 		panic();
303 
304 	interrupt_enable(secumod_itr_handler.chip, secumod_itr_handler.it);
305 }
306 
secumod_cfg_input_pio(uint8_t gpio_pin,uint32_t config)307 static void secumod_cfg_input_pio(uint8_t gpio_pin, uint32_t config)
308 {
309 	vaddr_t piobu_addr = 0;
310 	uint8_t afv = 0;
311 	uint8_t rfv = 0;
312 	uint8_t pull_mode = PIOBU_PIN_PULL_NONE;
313 	uint8_t def_level = PIOBU_PIN_DEF_LEVEL_LOW;
314 
315 	assert(gpio_pin < SECUMOD_MAX_PINS);
316 
317 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
318 
319 	/* Set GPIO as input */
320 	io_clrbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
321 
322 	afv = PIOBU_PIN_AFV(config);
323 	rfv = PIOBU_PIN_RFV(config);
324 	pull_mode = PIOBU_PIN_PULL_MODE(config);
325 	def_level = PIOBU_PIN_DEF_LEVEL(config);
326 
327 	io_write32(piobu_addr, afv | rfv << SECUMOD_PIOBU_RFV_SHIFT |
328 		   pull_mode << SECUMOD_PIOBU_PULLUP_SHIFT |
329 		   def_level << SECUMOD_PIOBU_SWITCH_SHIFT);
330 
331 	/* Enable Tampering Interrupt */
332 	secumod_gpio_set_interrupt(&secumod_chip, gpio_pin,
333 				   GPIO_INTERRUPT_ENABLE);
334 
335 	/* Enable Intrusion Detection */
336 	io_setbits32(secumod_base + piobu_device->compat->of_nmpr,
337 		     SECUMOD_PIN_VAL(gpio_pin));
338 
339 	/* Enable Wakeup */
340 	if (PIOBU_PIN_WAKEUP(config))
341 		io_setbits32(secumod_base + piobu_device->compat->of_wkpr,
342 			     SECUMOD_PIN_VAL(gpio_pin));
343 
344 	gpio_protected |= BIT32(gpio_pin);
345 }
346 
secumod_hw_init(const void * fdt,int node)347 static void secumod_hw_init(const void *fdt, int node)
348 {
349 	int i = 0;
350 	int len = 0;
351 	uint8_t gpio_pin = 0;
352 	uint32_t config = 0;
353 	const uint32_t *prop = NULL;
354 
355 	/* Disable JTAG Reset and Debug */
356 	io_write32(secumod_base + piobu_device->compat->of_jtagcr,
357 		   SECUMOD_JTAGCR_FNTRST);
358 
359 	/* Switch IOs to normal mode */
360 	io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
361 		   SECUMOD_CR_NORMAL);
362 
363 	/* Clear all detection intrusion in normal mode */
364 	io_write32(secumod_base + piobu_device->compat->of_nmpr, 0);
365 
366 	/* Clear Alarms */
367 	io_write32(secumod_base + SECUMOD_SCR,
368 		   SECUMOD_PIN_MASK << SECUMOD_PIN_SHIFT);
369 
370 	/* Configure each IOs */
371 	prop = fdt_getprop(fdt, node, "gpios", &len);
372 	if (!prop)
373 		return;
374 
375 	len /= sizeof(uint32_t);
376 	for (i = 0; i < len; i += DT_GPIO_CELLS) {
377 		gpio_pin = fdt32_to_cpu(prop[i]);
378 		config = fdt32_to_cpu(prop[i + 1]);
379 
380 		secumod_cfg_input_pio(gpio_pin, config);
381 	}
382 }
383 
384 #ifdef CFG_PM_ARM32
piobu_pm(enum pm_op op,uint32_t pm_hint __unused,const struct pm_callback_handle * hdl __unused)385 static TEE_Result piobu_pm(enum pm_op op, uint32_t pm_hint __unused,
386 			   const struct pm_callback_handle *hdl __unused)
387 {
388 	switch (op) {
389 	case PM_OP_RESUME:
390 		io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
391 			   SECUMOD_CR_NORMAL);
392 		break;
393 	case PM_OP_SUSPEND:
394 		/* Enter backup mode before suspending */
395 		io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
396 			   SECUMOD_CR_BACKUP);
397 		break;
398 	default:
399 		panic("Invalid PM operation");
400 	}
401 
402 	return TEE_SUCCESS;
403 }
404 
piobu_register_pm(void)405 static void piobu_register_pm(void)
406 {
407 	register_pm_driver_cb(piobu_pm, NULL, "piobu");
408 }
409 #else
piobu_register_pm(void)410 static void piobu_register_pm(void) {}
411 #endif
412 
atmel_secumod_probe(const void * fdt,int node,const void * compat_data)413 static TEE_Result atmel_secumod_probe(const void *fdt, int node,
414 				      const void *compat_data)
415 {
416 	size_t size = 0;
417 
418 	if (secumod_base)
419 		return TEE_ERROR_GENERIC;
420 
421 	piobu_device = calloc(1, sizeof(*piobu_device));
422 	if (!piobu_device)
423 		return TEE_ERROR_OUT_OF_MEMORY;
424 
425 	piobu_device->compat = (struct piobu_compat *)compat_data;
426 
427 	if (dt_map_dev(fdt, node, &secumod_base, &size, DT_MAP_AUTO) < 0)
428 		return TEE_ERROR_GENERIC;
429 
430 	secumod_hw_init(fdt, node);
431 	secumod_interrupt_init();
432 
433 	secumod_chip.ops = &atmel_piobu_ops;
434 
435 	piobu_register_pm();
436 
437 	assert(gpio_ops_is_valid(&atmel_piobu_ops));
438 
439 	return gpio_register_provider(fdt, node, secumod_dt_get, &secumod_chip);
440 }
441 
442 static const struct piobu_compat sama5d2_compat = {
443 	.max_pins = 8,
444 	.of_jtagcr = 0x68,
445 	.of_bmpr = 0x7C,
446 	.of_nmpr = 0x80,
447 	.of_niepr = 0x84,
448 	.of_nidpr = 0x88,
449 	.of_nimpr = 0x8C,
450 	.of_wkpr = 0x90,
451 };
452 
453 static const struct piobu_compat sama7g54_compat = {
454 	.max_pins = 4,
455 	.of_jtagcr = 0x70,
456 	.of_bmpr = 0x84,
457 	.of_nmpr = 0x88,
458 	.of_niepr = 0x8C,
459 	.of_nidpr = 0x90,
460 	.of_nimpr = 0x94,
461 	.of_wkpr = 0x98,
462 };
463 
464 static const struct dt_device_match atmel_secumod_match_table[] = {
465 	{
466 		.compatible = "atmel,sama5d2-secumod",
467 		.compat_data = &sama5d2_compat,
468 	},
469 	{
470 		.compatible = "microchip,sama7g5-secumod",
471 		.compat_data = &sama7g54_compat,
472 	},
473 	{ }
474 };
475 
476 DEFINE_DT_DRIVER(atmel_secumod_dt_driver) = {
477 	.name = "atmel_secumod",
478 	.type = DT_DRIVER_NOTYPE,
479 	.match_table = atmel_secumod_match_table,
480 	.probe = atmel_secumod_probe,
481 };
482