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