xref: /optee_os/core/drivers/atmel_piobu.c (revision 79f8990d9d28539864d8f97f9f1cb32e289e595f)
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		8
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			0x68
50 #define SECUMOD_JTAGCR_FNTRST		0x1
51 
52 #define SECUMOD_BMPR			0x7C
53 #define SECUMOD_NMPR			0x80
54 #define SECUMOD_NIEPR			0x84
55 #define SECUMOD_NIDPR			0x88
56 #define SECUMOD_NIMPR			0x8C
57 #define SECUMOD_WKPR			0x90
58 
59 static vaddr_t secumod_base;
60 static uint32_t gpio_protected;
61 static struct gpio_chip secumod_chip;
62 
63 /*
64  * Get value from GPIO controller
65  * chip:        pointer to GPIO controller chip instance
66  * gpio_pin:    pin from which value needs to be read
67  * Return target GPIO pin level.
68  */
69 static enum gpio_level secumod_gpio_get_value(struct gpio_chip *chip __unused,
70 					      unsigned int gpio_pin)
71 {
72 	vaddr_t piobu_addr = 0;
73 	uint32_t piobu = 0;
74 
75 	assert(gpio_pin < SECUMOD_MAX_PINS &&
76 	       !(gpio_protected & BIT32(gpio_pin)));
77 
78 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
79 	piobu = io_read32(piobu_addr);
80 
81 	if (piobu & SECUMOD_PIOBU_PDS)
82 		return GPIO_LEVEL_HIGH;
83 	else
84 		return GPIO_LEVEL_LOW;
85 }
86 
87 /*
88  * Set value for GPIO controller
89  * chip:        pointer to GPIO controller chip instance
90  * gpio_pin:    pin to which value needs to be written
91  * value:       Level state for the target pin
92  */
93 static void secumod_gpio_set_value(struct gpio_chip *chip __unused,
94 				   unsigned int gpio_pin, enum gpio_level value)
95 {
96 	vaddr_t piobu_addr = 0;
97 
98 	assert(gpio_pin < SECUMOD_MAX_PINS &&
99 	       !(gpio_protected & BIT32(gpio_pin)));
100 
101 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
102 
103 	if (value == GPIO_LEVEL_HIGH)
104 		io_setbits32(piobu_addr, SECUMOD_PIOBU_SOD);
105 	else
106 		io_clrbits32(piobu_addr, SECUMOD_PIOBU_SOD);
107 }
108 
109 /*
110  * Get direction from GPIO controller
111  * chip:        pointer to GPIO controller chip instance
112  * gpio_pin:    pin from which direction needs to be read
113  */
114 static enum gpio_dir secumod_gpio_get_direction(struct gpio_chip *chip __unused,
115 						unsigned int gpio_pin)
116 {
117 	vaddr_t piobu_addr = 0;
118 	uint32_t piobu = 0;
119 
120 	assert(gpio_pin < SECUMOD_MAX_PINS &&
121 	       !(gpio_protected & BIT32(gpio_pin)));
122 
123 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
124 	piobu = io_read32(piobu_addr);
125 
126 	if (piobu & SECUMOD_PIOBU_OUTPUT)
127 		return GPIO_DIR_OUT;
128 	else
129 		return GPIO_DIR_IN;
130 }
131 
132 /*
133  * Set direction for GPIO controller
134  * chip:        pointer to GPIO controller chip instance
135  * gpio_pin:    pin on which direction needs to be set
136  * direction:   direction which needs to be set on pin
137  */
138 static void secumod_gpio_set_direction(struct gpio_chip *chip __unused,
139 				       unsigned int gpio_pin,
140 				       enum gpio_dir direction)
141 {
142 	vaddr_t piobu_addr = 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 
149 	if (direction == GPIO_DIR_OUT)
150 		io_setbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
151 	else
152 		io_clrbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
153 }
154 
155 /*
156  * Get interrupt from GPIO controller
157  * chip:        pointer to GPIO controller chip instance
158  * gpio_pin:    pin from which interrupt value needs to be read
159  */
160 static enum gpio_interrupt
161 secumod_gpio_get_interrupt(struct gpio_chip *chip __unused,
162 			   unsigned int gpio_pin)
163 {
164 	vaddr_t nimpr_addr = secumod_base + SECUMOD_NIMPR;
165 	uint32_t data = 0;
166 
167 	assert(gpio_pin < SECUMOD_MAX_PINS &&
168 	       !(gpio_protected & BIT32(gpio_pin)));
169 
170 	data = io_read32(nimpr_addr);
171 
172 	if (data & SECUMOD_PIN_VAL(gpio_pin))
173 		return GPIO_INTERRUPT_ENABLE;
174 	else
175 		return GPIO_INTERRUPT_DISABLE;
176 }
177 
178 /*
179  * Set interrupt event for GPIO controller
180  * chip:        pointer to GPIO controller chip instance
181  * gpio_pin:    pin on which interrupt value needs to be set
182  * interrupt:   interrupt value which needs to be set on pin
183  */
184 static void secumod_gpio_set_interrupt(struct gpio_chip *chip __unused,
185 				       unsigned int gpio_pin,
186 				       enum gpio_interrupt interrupt)
187 {
188 	vaddr_t niepr_addr = secumod_base + SECUMOD_NIEPR;
189 
190 	assert(gpio_pin < SECUMOD_MAX_PINS &&
191 	       !(gpio_protected & BIT32(gpio_pin)));
192 
193 	if (interrupt == GPIO_INTERRUPT_ENABLE)
194 		io_setbits32(niepr_addr, SECUMOD_PIN_VAL(gpio_pin));
195 	else
196 		io_clrbits32(niepr_addr, SECUMOD_PIN_VAL(gpio_pin));
197 }
198 
199 static const struct gpio_ops atmel_piobu_ops = {
200 	.get_direction = secumod_gpio_get_direction,
201 	.set_direction = secumod_gpio_set_direction,
202 	.get_value = secumod_gpio_get_value,
203 	.set_value = secumod_gpio_set_value,
204 	.get_interrupt = secumod_gpio_get_interrupt,
205 	.set_interrupt = secumod_gpio_set_interrupt,
206 };
207 
208 static TEE_Result secumod_dt_get(struct dt_pargs *pargs, void *data,
209 				 struct gpio **out_gpio)
210 {
211 	TEE_Result res = TEE_ERROR_GENERIC;
212 	struct gpio *gpio = NULL;
213 	struct gpio_chip *chip = data;
214 
215 	res = gpio_dt_alloc_pin(pargs, &gpio);
216 	if (res)
217 		return res;
218 
219 	if (gpio_protected & BIT32(gpio->pin)) {
220 		free(gpio);
221 		return TEE_ERROR_GENERIC;
222 	}
223 
224 	gpio->chip = chip;
225 	*out_gpio = gpio;
226 
227 	return TEE_SUCCESS;
228 }
229 
230 static enum itr_return secumod_it_handler(struct itr_handler *handler __unused)
231 {
232 	int i = 0;
233 	struct optee_rtc_time tm = { };
234 	TEE_Result res = TEE_ERROR_GENERIC;
235 	uint32_t sr = io_read32(secumod_base + SECUMOD_SR);
236 
237 	for (i = 0; i < SECUMOD_MAX_PINS; i++) {
238 		if (sr & SECUMOD_PIN_VAL(i))
239 			EMSG("Detected tampering on pin %d", i);
240 	}
241 
242 	if (sr & SECUMOD_SR_JTAG)
243 		EMSG("JTAG tampering attempt");
244 
245 	if (sr & SECUMOD_SR_TST_PIN)
246 		EMSG("Test pin tampering attempt");
247 
248 	res = atmel_rtc_get_tamper_timestamp(&tm);
249 	if (!res) {
250 		EMSG("Date of tampering: %02"PRIu32"/%02"PRIu32"/%02"PRIu32"",
251 		     tm.tm_mday, tm.tm_mon, tm.tm_year);
252 		EMSG("Time of tampering: %02"PRIu32":%02"PRIu32":%02"PRIu32"",
253 		     tm.tm_hour, tm.tm_min, tm.tm_sec);
254 	}
255 
256 	io_write32(secumod_base + SECUMOD_SCR,
257 		   SECUMOD_PIN_MASK << SECUMOD_PIN_SHIFT);
258 
259 	panic("Tampering detected, system halted");
260 
261 	return ITRR_HANDLED;
262 }
263 
264 static struct itr_handler secumod_itr_handler = {
265 	.it = AT91C_ID_SECUMOD,
266 	.handler = secumod_it_handler,
267 };
268 
269 static void secumod_interrupt_init(void)
270 {
271 	TEE_Result res = TEE_ERROR_GENERIC;
272 
273 	secumod_itr_handler.chip = interrupt_get_main_chip();
274 
275 	res = interrupt_add_configure_handler(&secumod_itr_handler,
276 					      IRQ_TYPE_LEVEL_HIGH, 7);
277 	if (res)
278 		panic();
279 
280 	interrupt_enable(secumod_itr_handler.chip, secumod_itr_handler.it);
281 }
282 
283 static void secumod_cfg_input_pio(uint8_t gpio_pin, uint32_t config)
284 {
285 	vaddr_t piobu_addr = 0;
286 	uint8_t afv = 0;
287 	uint8_t rfv = 0;
288 	uint8_t pull_mode = PIOBU_PIN_PULL_NONE;
289 	uint8_t def_level = PIOBU_PIN_DEF_LEVEL_LOW;
290 
291 	assert(gpio_pin < SECUMOD_MAX_PINS);
292 
293 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
294 
295 	/* Set GPIO as input */
296 	io_clrbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
297 
298 	afv = PIOBU_PIN_AFV(config);
299 	rfv = PIOBU_PIN_RFV(config);
300 	pull_mode = PIOBU_PIN_PULL_MODE(config);
301 	def_level = PIOBU_PIN_DEF_LEVEL(config);
302 
303 	io_write32(piobu_addr, afv | rfv << SECUMOD_PIOBU_RFV_SHIFT |
304 		   pull_mode << SECUMOD_PIOBU_PULLUP_SHIFT |
305 		   def_level << SECUMOD_PIOBU_SWITCH_SHIFT);
306 
307 	/* Enable Tampering Interrupt */
308 	secumod_gpio_set_interrupt(&secumod_chip, gpio_pin,
309 				   GPIO_INTERRUPT_ENABLE);
310 
311 	/* Enable Intrusion Detection */
312 	io_setbits32(secumod_base + SECUMOD_NMPR, SECUMOD_PIN_VAL(gpio_pin));
313 
314 	/* Enable Wakeup */
315 	if (PIOBU_PIN_WAKEUP(config))
316 		io_setbits32(secumod_base + SECUMOD_WKPR,
317 			     SECUMOD_PIN_VAL(gpio_pin));
318 
319 	gpio_protected |= BIT32(gpio_pin);
320 }
321 
322 static void secumod_hw_init(const void *fdt, int node)
323 {
324 	int i = 0;
325 	int len = 0;
326 	uint8_t gpio_pin = 0;
327 	uint32_t config = 0;
328 	const uint32_t *prop = NULL;
329 
330 	/* Disable JTAG Reset and Debug */
331 	io_write32(secumod_base + SECUMOD_JTAGCR, SECUMOD_JTAGCR_FNTRST);
332 
333 	/* Switch IOs to normal mode */
334 	io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
335 		   SECUMOD_CR_NORMAL);
336 
337 	/* Clear all detection intrusion in normal mode */
338 	io_write32(secumod_base + SECUMOD_NMPR, 0);
339 
340 	/* Clear Alarms */
341 	io_write32(secumod_base + SECUMOD_SCR,
342 		   SECUMOD_PIN_MASK << SECUMOD_PIN_SHIFT);
343 
344 	/* Configure each IOs */
345 	prop = fdt_getprop(fdt, node, "gpios", &len);
346 	if (!prop)
347 		return;
348 
349 	len /= sizeof(uint32_t);
350 	for (i = 0; i < len; i += DT_GPIO_CELLS) {
351 		gpio_pin = fdt32_to_cpu(prop[i]);
352 		config = fdt32_to_cpu(prop[i + 1]);
353 
354 		secumod_cfg_input_pio(gpio_pin, config);
355 	}
356 }
357 
358 #ifdef CFG_PM_ARM32
359 static TEE_Result piobu_pm(enum pm_op op, uint32_t pm_hint __unused,
360 			   const struct pm_callback_handle *hdl __unused)
361 {
362 	switch (op) {
363 	case PM_OP_RESUME:
364 		io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
365 			   SECUMOD_CR_NORMAL);
366 		break;
367 	case PM_OP_SUSPEND:
368 		/* Enter backup mode before suspending */
369 		io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
370 			   SECUMOD_CR_BACKUP);
371 		break;
372 	default:
373 		panic("Invalid PM operation");
374 	}
375 
376 	return TEE_SUCCESS;
377 }
378 
379 static void piobu_register_pm(void)
380 {
381 	register_pm_driver_cb(piobu_pm, NULL, "piobu");
382 }
383 #else
384 static void piobu_register_pm(void) {}
385 #endif
386 
387 static TEE_Result atmel_secumod_probe(const void *fdt, int node,
388 				      const void *compat_data __unused)
389 {
390 	size_t size = 0;
391 
392 	if (secumod_base)
393 		return TEE_ERROR_GENERIC;
394 
395 	if (dt_map_dev(fdt, node, &secumod_base, &size, DT_MAP_AUTO) < 0)
396 		return TEE_ERROR_GENERIC;
397 
398 	secumod_hw_init(fdt, node);
399 	secumod_interrupt_init();
400 
401 	secumod_chip.ops = &atmel_piobu_ops;
402 
403 	piobu_register_pm();
404 
405 	assert(gpio_ops_is_valid(&atmel_piobu_ops));
406 
407 	return gpio_register_provider(fdt, node, secumod_dt_get, &secumod_chip);
408 }
409 
410 static const struct dt_device_match atmel_secumod_match_table[] = {
411 	{ .compatible = "atmel,sama5d2-secumod" },
412 	{ }
413 };
414 
415 DEFINE_DT_DRIVER(atmel_secumod_dt_driver) = {
416 	.name = "atmel_secumod",
417 	.type = DT_DRIVER_NOTYPE,
418 	.match_table = atmel_secumod_match_table,
419 	.probe = atmel_secumod_probe,
420 };
421