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