xref: /optee_os/core/drivers/atmel_piobu.c (revision 33a0c8350ac15de18e20ca47c5267b803fed76f8)
11fe98f82SClément Léger // SPDX-License-Identifier: BSD-2-Clause
21fe98f82SClément Léger /*
31fe98f82SClément Léger  * Copyright 2022 Microchip
41fe98f82SClément Léger  *
51fe98f82SClément Léger  * Driver for AT91 PIOBU
61fe98f82SClément Léger  */
71fe98f82SClément Léger 
81fe98f82SClément Léger #include <assert.h>
91fe98f82SClément Léger #include <drivers/atmel_rtc.h>
106dcd18c8SClément Léger #include <drivers/gpio.h>
111fe98f82SClément Léger #include <dt-bindings/gpio/atmel,piobu.h>
121fe98f82SClément Léger #include <io.h>
131fe98f82SClément Léger #include <kernel/boot.h>
141fe98f82SClément Léger #include <kernel/dt.h>
159e3c57c8SEtienne Carriere #include <kernel/dt_driver.h>
16*33a0c835SEtienne Carriere #include <kernel/interrupt.h>
171fe98f82SClément Léger #include <kernel/pm.h>
181fe98f82SClément Léger #include <libfdt.h>
191fe98f82SClément Léger #include <mm/core_memprot.h>
201fe98f82SClément Léger 
211fe98f82SClément Léger #define SECUMOD_MAX_PINS		8
221fe98f82SClément Léger #define SECUMOD_PIN_MASK		(BIT(SECUMOD_MAX_PINS) - 1)
231fe98f82SClément Léger #define SECUMOD_PIN_SHIFT		16
241fe98f82SClément Léger #define SECUMOD_PIN_VAL(pin)		BIT(SECUMOD_PIN_SHIFT + (pin))
251fe98f82SClément Léger 
261fe98f82SClément Léger #define DT_GPIO_CELLS			2
271fe98f82SClément Léger 
281fe98f82SClément Léger #define SECUMOD_CR			0x0
291fe98f82SClément Léger #define SECUMOD_CR_KEY_SHIFT		16
301fe98f82SClément Léger #define SECUMOD_CR_KEY			SHIFT_U32(0x89CA, SECUMOD_CR_KEY_SHIFT)
311fe98f82SClément Léger #define SECUMOD_CR_BACKUP		BIT(0)
321fe98f82SClément Léger #define SECUMOD_CR_NORMAL		BIT(1)
331fe98f82SClément Léger 
341fe98f82SClément Léger #define SECUMOD_SR			0x8
351fe98f82SClément Léger #define SECUMOD_SR_JTAG			BIT(3)
361fe98f82SClément Léger #define SECUMOD_SR_TST_PIN			BIT(2)
371fe98f82SClément Léger 
381fe98f82SClément Léger #define SECUMOD_SCR			0x10
391fe98f82SClément Léger 
401fe98f82SClément Léger #define SECUMOD_PIOBU(x)		(0x18 + (x) * 0x4)
411fe98f82SClément Léger #define SECUMOD_PIOBU_AFV_MASK		GENMASK_32(3, 0)
421fe98f82SClément Léger #define SECUMOD_PIOBU_RFV_SHIFT		4
431fe98f82SClément Léger #define SECUMOD_PIOBU_OUTPUT		BIT(8)
441fe98f82SClément Léger #define SECUMOD_PIOBU_SOD		BIT(9)
451fe98f82SClément Léger #define SECUMOD_PIOBU_PDS		BIT(10)
461fe98f82SClément Léger #define SECUMOD_PIOBU_PULLUP_SHIFT	12
471fe98f82SClément Léger #define SECUMOD_PIOBU_SWITCH_SHIFT	15
481fe98f82SClément Léger 
491fe98f82SClément Léger #define SECUMOD_JTAGCR			0x68
501fe98f82SClément Léger #define SECUMOD_JTAGCR_FNTRST		0x1
511fe98f82SClément Léger 
521fe98f82SClément Léger #define SECUMOD_BMPR			0x7C
531fe98f82SClément Léger #define SECUMOD_NMPR			0x80
541fe98f82SClément Léger #define SECUMOD_NIEPR			0x84
551fe98f82SClément Léger #define SECUMOD_NIDPR			0x88
561fe98f82SClément Léger #define SECUMOD_NIMPR			0x8C
571fe98f82SClément Léger #define SECUMOD_WKPR			0x90
581fe98f82SClément Léger 
591fe98f82SClément Léger static vaddr_t secumod_base;
601fe98f82SClément Léger static uint32_t gpio_protected;
611fe98f82SClément Léger static struct gpio_chip secumod_chip;
621fe98f82SClément Léger 
631fe98f82SClément Léger /*
641fe98f82SClément Léger  * Get value from GPIO controller
651fe98f82SClément Léger  * chip:        pointer to GPIO controller chip instance
661fe98f82SClément Léger  * gpio_pin:    pin from which value needs to be read
671fe98f82SClément Léger  * Return target GPIO pin level.
681fe98f82SClément Léger  */
698bc270b1SClément Léger static enum gpio_level secumod_gpio_get_value(struct gpio_chip *chip __unused,
701fe98f82SClément Léger 					      unsigned int gpio_pin)
711fe98f82SClément Léger {
721fe98f82SClément Léger 	vaddr_t piobu_addr = 0;
731fe98f82SClément Léger 	uint32_t piobu = 0;
741fe98f82SClément Léger 
751fe98f82SClément Léger 	assert(gpio_pin < SECUMOD_MAX_PINS &&
761fe98f82SClément Léger 	       !(gpio_protected & BIT32(gpio_pin)));
771fe98f82SClément Léger 
781fe98f82SClément Léger 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
791fe98f82SClément Léger 	piobu = io_read32(piobu_addr);
801fe98f82SClément Léger 
811fe98f82SClément Léger 	if (piobu & SECUMOD_PIOBU_PDS)
821fe98f82SClément Léger 		return GPIO_LEVEL_HIGH;
831fe98f82SClément Léger 	else
841fe98f82SClément Léger 		return GPIO_LEVEL_LOW;
851fe98f82SClément Léger }
861fe98f82SClément Léger 
871fe98f82SClément Léger /*
881fe98f82SClément Léger  * Set value for GPIO controller
891fe98f82SClément Léger  * chip:        pointer to GPIO controller chip instance
901fe98f82SClément Léger  * gpio_pin:    pin to which value needs to be written
911fe98f82SClément Léger  * value:       Level state for the target pin
921fe98f82SClément Léger  */
938bc270b1SClément Léger static void secumod_gpio_set_value(struct gpio_chip *chip __unused,
941fe98f82SClément Léger 				   unsigned int gpio_pin, enum gpio_level value)
951fe98f82SClément Léger {
961fe98f82SClément Léger 	vaddr_t piobu_addr = 0;
971fe98f82SClément Léger 
981fe98f82SClément Léger 	assert(gpio_pin < SECUMOD_MAX_PINS &&
991fe98f82SClément Léger 	       !(gpio_protected & BIT32(gpio_pin)));
1001fe98f82SClément Léger 
1011fe98f82SClément Léger 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
1021fe98f82SClément Léger 
1031fe98f82SClément Léger 	if (value == GPIO_LEVEL_HIGH)
1041fe98f82SClément Léger 		io_setbits32(piobu_addr, SECUMOD_PIOBU_SOD);
1051fe98f82SClément Léger 	else
1061fe98f82SClément Léger 		io_clrbits32(piobu_addr, SECUMOD_PIOBU_SOD);
1071fe98f82SClément Léger }
1081fe98f82SClément Léger 
1091fe98f82SClément Léger /*
1101fe98f82SClément Léger  * Get direction from GPIO controller
1111fe98f82SClément Léger  * chip:        pointer to GPIO controller chip instance
1121fe98f82SClément Léger  * gpio_pin:    pin from which direction needs to be read
1131fe98f82SClément Léger  */
1148bc270b1SClément Léger static enum gpio_dir secumod_gpio_get_direction(struct gpio_chip *chip __unused,
1151fe98f82SClément Léger 						unsigned int gpio_pin)
1161fe98f82SClément Léger {
1171fe98f82SClément Léger 	vaddr_t piobu_addr = 0;
1181fe98f82SClément Léger 	uint32_t piobu = 0;
1191fe98f82SClément Léger 
1201fe98f82SClément Léger 	assert(gpio_pin < SECUMOD_MAX_PINS &&
1211fe98f82SClément Léger 	       !(gpio_protected & BIT32(gpio_pin)));
1221fe98f82SClément Léger 
1231fe98f82SClément Léger 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
1241fe98f82SClément Léger 	piobu = io_read32(piobu_addr);
1251fe98f82SClément Léger 
1261fe98f82SClément Léger 	if (piobu & SECUMOD_PIOBU_OUTPUT)
1271fe98f82SClément Léger 		return GPIO_DIR_OUT;
1281fe98f82SClément Léger 	else
1291fe98f82SClément Léger 		return GPIO_DIR_IN;
1301fe98f82SClément Léger }
1311fe98f82SClément Léger 
1321fe98f82SClément Léger /*
1331fe98f82SClément Léger  * Set direction for GPIO controller
1341fe98f82SClément Léger  * chip:        pointer to GPIO controller chip instance
1351fe98f82SClément Léger  * gpio_pin:    pin on which direction needs to be set
1361fe98f82SClément Léger  * direction:   direction which needs to be set on pin
1371fe98f82SClément Léger  */
1388bc270b1SClément Léger static void secumod_gpio_set_direction(struct gpio_chip *chip __unused,
1398bc270b1SClément Léger 				       unsigned int gpio_pin,
1408bc270b1SClément Léger 				       enum gpio_dir direction)
1411fe98f82SClément Léger {
1421fe98f82SClément Léger 	vaddr_t piobu_addr = 0;
1431fe98f82SClément Léger 
1441fe98f82SClément Léger 	assert(gpio_pin < SECUMOD_MAX_PINS &&
1451fe98f82SClément Léger 	       !(gpio_protected & BIT32(gpio_pin)));
1461fe98f82SClément Léger 
1471fe98f82SClément Léger 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
1481fe98f82SClément Léger 
1491fe98f82SClément Léger 	if (direction == GPIO_DIR_OUT)
1501fe98f82SClément Léger 		io_setbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
1511fe98f82SClément Léger 	else
1521fe98f82SClément Léger 		io_clrbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
1531fe98f82SClément Léger }
1541fe98f82SClément Léger 
1551fe98f82SClément Léger /*
1561fe98f82SClément Léger  * Get interrupt from GPIO controller
1571fe98f82SClément Léger  * chip:        pointer to GPIO controller chip instance
1581fe98f82SClément Léger  * gpio_pin:    pin from which interrupt value needs to be read
1591fe98f82SClément Léger  */
1608bc270b1SClément Léger static enum gpio_interrupt
1618bc270b1SClément Léger secumod_gpio_get_interrupt(struct gpio_chip *chip __unused,
1621fe98f82SClément Léger 			   unsigned int gpio_pin)
1631fe98f82SClément Léger {
1641fe98f82SClément Léger 	vaddr_t nimpr_addr = secumod_base + SECUMOD_NIMPR;
1651fe98f82SClément Léger 	uint32_t data = 0;
1661fe98f82SClément Léger 
1671fe98f82SClément Léger 	assert(gpio_pin < SECUMOD_MAX_PINS &&
1681fe98f82SClément Léger 	       !(gpio_protected & BIT32(gpio_pin)));
1691fe98f82SClément Léger 
1701fe98f82SClément Léger 	data = io_read32(nimpr_addr);
1711fe98f82SClément Léger 
1721fe98f82SClément Léger 	if (data & SECUMOD_PIN_VAL(gpio_pin))
1731fe98f82SClément Léger 		return GPIO_INTERRUPT_ENABLE;
1741fe98f82SClément Léger 	else
1751fe98f82SClément Léger 		return GPIO_INTERRUPT_DISABLE;
1761fe98f82SClément Léger }
1771fe98f82SClément Léger 
1781fe98f82SClément Léger /*
1791fe98f82SClément Léger  * Set interrupt event for GPIO controller
1801fe98f82SClément Léger  * chip:        pointer to GPIO controller chip instance
1811fe98f82SClément Léger  * gpio_pin:    pin on which interrupt value needs to be set
1821fe98f82SClément Léger  * interrupt:   interrupt value which needs to be set on pin
1831fe98f82SClément Léger  */
1848bc270b1SClément Léger static void secumod_gpio_set_interrupt(struct gpio_chip *chip __unused,
1851fe98f82SClément Léger 				       unsigned int gpio_pin,
1861fe98f82SClément Léger 				       enum gpio_interrupt interrupt)
1871fe98f82SClément Léger {
1881fe98f82SClément Léger 	vaddr_t niepr_addr = secumod_base + SECUMOD_NIEPR;
1891fe98f82SClément Léger 
1901fe98f82SClément Léger 	assert(gpio_pin < SECUMOD_MAX_PINS &&
1911fe98f82SClément Léger 	       !(gpio_protected & BIT32(gpio_pin)));
1921fe98f82SClément Léger 
1931fe98f82SClément Léger 	if (interrupt == GPIO_INTERRUPT_ENABLE)
1941fe98f82SClément Léger 		io_setbits32(niepr_addr, SECUMOD_PIN_VAL(gpio_pin));
1951fe98f82SClément Léger 	else
1961fe98f82SClément Léger 		io_clrbits32(niepr_addr, SECUMOD_PIN_VAL(gpio_pin));
1971fe98f82SClément Léger }
1981fe98f82SClément Léger 
1991fe98f82SClément Léger static const struct gpio_ops atmel_piobu_ops = {
2008bc270b1SClément Léger 	.get_direction = secumod_gpio_get_direction,
2018bc270b1SClément Léger 	.set_direction = secumod_gpio_set_direction,
2028bc270b1SClément Léger 	.get_value = secumod_gpio_get_value,
2038bc270b1SClément Léger 	.set_value = secumod_gpio_set_value,
2048bc270b1SClément Léger 	.get_interrupt = secumod_gpio_get_interrupt,
2058bc270b1SClément Léger 	.set_interrupt = secumod_gpio_set_interrupt,
2061fe98f82SClément Léger };
2071fe98f82SClément Léger 
208b357d34fSEtienne Carriere static TEE_Result secumod_dt_get(struct dt_pargs *pargs, void *data,
209b357d34fSEtienne Carriere 				 struct gpio **out_gpio)
210b786cc03SClément Léger {
211b357d34fSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
212b786cc03SClément Léger 	struct gpio *gpio = NULL;
213b786cc03SClément Léger 	struct gpio_chip *chip = data;
214b786cc03SClément Léger 
215b357d34fSEtienne Carriere 	res = gpio_dt_alloc_pin(pargs, &gpio);
216b357d34fSEtienne Carriere 	if (res)
217b357d34fSEtienne Carriere 		return res;
218b786cc03SClément Léger 
219b786cc03SClément Léger 	if (gpio_protected & BIT32(gpio->pin)) {
220b786cc03SClément Léger 		free(gpio);
221b357d34fSEtienne Carriere 		return TEE_ERROR_GENERIC;
222b786cc03SClément Léger 	}
223b786cc03SClément Léger 
224b786cc03SClément Léger 	gpio->chip = chip;
225b357d34fSEtienne Carriere 	*out_gpio = gpio;
226b786cc03SClément Léger 
227b357d34fSEtienne Carriere 	return TEE_SUCCESS;
228b786cc03SClément Léger }
229b786cc03SClément Léger 
2301fe98f82SClément Léger static enum itr_return secumod_it_handler(struct itr_handler *handler __unused)
2311fe98f82SClément Léger {
2321fe98f82SClément Léger 	int i = 0;
2331fe98f82SClément Léger 	struct optee_rtc_time tm = { };
2341fe98f82SClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
2351fe98f82SClément Léger 	uint32_t sr = io_read32(secumod_base + SECUMOD_SR);
2361fe98f82SClément Léger 
2371fe98f82SClément Léger 	for (i = 0; i < SECUMOD_MAX_PINS; i++) {
2381fe98f82SClément Léger 		if (sr & SECUMOD_PIN_VAL(i))
2391fe98f82SClément Léger 			EMSG("Detected tampering on pin %d", i);
2401fe98f82SClément Léger 	}
2411fe98f82SClément Léger 
2421fe98f82SClément Léger 	if (sr & SECUMOD_SR_JTAG)
2431fe98f82SClément Léger 		EMSG("JTAG tampering attempt");
2441fe98f82SClément Léger 
2451fe98f82SClément Léger 	if (sr & SECUMOD_SR_TST_PIN)
2461fe98f82SClément Léger 		EMSG("Test pin tampering attempt");
2471fe98f82SClément Léger 
2481fe98f82SClément Léger 	res = atmel_rtc_get_tamper_timestamp(&tm);
2491fe98f82SClément Léger 	if (!res) {
2501fe98f82SClément Léger 		EMSG("Date of tampering: %02"PRIu32"/%02"PRIu32"/%02"PRIu32"",
2511fe98f82SClément Léger 		     tm.tm_mday, tm.tm_mon, tm.tm_year);
2521fe98f82SClément Léger 		EMSG("Time of tampering: %02"PRIu32":%02"PRIu32":%02"PRIu32"",
2531fe98f82SClément Léger 		     tm.tm_hour, tm.tm_min, tm.tm_sec);
2541fe98f82SClément Léger 	}
2551fe98f82SClément Léger 
2561fe98f82SClément Léger 	io_write32(secumod_base + SECUMOD_SCR,
2571fe98f82SClément Léger 		   SECUMOD_PIN_MASK << SECUMOD_PIN_SHIFT);
2581fe98f82SClément Léger 
2591fe98f82SClément Léger 	panic("Tampering detected, system halted");
2601fe98f82SClément Léger 
2611fe98f82SClément Léger 	return ITRR_HANDLED;
2621fe98f82SClément Léger }
2631fe98f82SClément Léger 
2641fe98f82SClément Léger static struct itr_handler secumod_itr_handler = {
2651fe98f82SClément Léger 	.it = AT91C_ID_SECUMOD,
2661fe98f82SClément Léger 	.handler = secumod_it_handler,
2671fe98f82SClément Léger };
2681fe98f82SClément Léger 
2691fe98f82SClément Léger static void secumod_interrupt_init(void)
2701fe98f82SClément Léger {
27157fec118SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
27257fec118SEtienne Carriere 
27357fec118SEtienne Carriere 	secumod_itr_handler.chip = interrupt_get_main_chip();
27457fec118SEtienne Carriere 
27557fec118SEtienne Carriere 	res = interrupt_add_configure_handler(&secumod_itr_handler,
27657fec118SEtienne Carriere 					      IRQ_TYPE_LEVEL_HIGH, 7);
27757fec118SEtienne Carriere 	if (res)
27857fec118SEtienne Carriere 		panic();
27957fec118SEtienne Carriere 
28057fec118SEtienne Carriere 	interrupt_enable(secumod_itr_handler.chip, secumod_itr_handler.it);
2811fe98f82SClément Léger }
2821fe98f82SClément Léger 
2831fe98f82SClément Léger static void secumod_cfg_input_pio(uint8_t gpio_pin, uint32_t config)
2841fe98f82SClément Léger {
2851fe98f82SClément Léger 	vaddr_t piobu_addr = 0;
2861fe98f82SClément Léger 	uint8_t afv = 0;
2871fe98f82SClément Léger 	uint8_t rfv = 0;
2881fe98f82SClément Léger 	uint8_t pull_mode = PIOBU_PIN_PULL_NONE;
2891fe98f82SClément Léger 	uint8_t def_level = PIOBU_PIN_DEF_LEVEL_LOW;
2901fe98f82SClément Léger 
2911fe98f82SClément Léger 	assert(gpio_pin < SECUMOD_MAX_PINS);
2921fe98f82SClément Léger 
2931fe98f82SClément Léger 	piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin);
2941fe98f82SClément Léger 
2951fe98f82SClément Léger 	/* Set GPIO as input */
2961fe98f82SClément Léger 	io_clrbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT);
2971fe98f82SClément Léger 
2981fe98f82SClément Léger 	afv = PIOBU_PIN_AFV(config);
2991fe98f82SClément Léger 	rfv = PIOBU_PIN_RFV(config);
3001fe98f82SClément Léger 	pull_mode = PIOBU_PIN_PULL_MODE(config);
3011fe98f82SClément Léger 	def_level = PIOBU_PIN_DEF_LEVEL(config);
3021fe98f82SClément Léger 
3031fe98f82SClément Léger 	io_write32(piobu_addr, afv | rfv << SECUMOD_PIOBU_RFV_SHIFT |
3041fe98f82SClément Léger 		   pull_mode << SECUMOD_PIOBU_PULLUP_SHIFT |
3051fe98f82SClément Léger 		   def_level << SECUMOD_PIOBU_SWITCH_SHIFT);
3061fe98f82SClément Léger 
3071fe98f82SClément Léger 	/* Enable Tampering Interrupt */
3088bc270b1SClément Léger 	secumod_gpio_set_interrupt(&secumod_chip, gpio_pin,
3098bc270b1SClément Léger 				   GPIO_INTERRUPT_ENABLE);
3101fe98f82SClément Léger 
3111fe98f82SClément Léger 	/* Enable Intrusion Detection */
3121fe98f82SClément Léger 	io_setbits32(secumod_base + SECUMOD_NMPR, SECUMOD_PIN_VAL(gpio_pin));
3131fe98f82SClément Léger 
3141fe98f82SClément Léger 	/* Enable Wakeup */
3151fe98f82SClément Léger 	if (PIOBU_PIN_WAKEUP(config))
3161fe98f82SClément Léger 		io_setbits32(secumod_base + SECUMOD_WKPR,
3171fe98f82SClément Léger 			     SECUMOD_PIN_VAL(gpio_pin));
3181fe98f82SClément Léger 
3191fe98f82SClément Léger 	gpio_protected |= BIT32(gpio_pin);
3201fe98f82SClément Léger }
3211fe98f82SClément Léger 
3221fe98f82SClément Léger static void secumod_hw_init(const void *fdt, int node)
3231fe98f82SClément Léger {
3241fe98f82SClément Léger 	int i = 0;
3251fe98f82SClément Léger 	int len = 0;
3261fe98f82SClément Léger 	uint8_t gpio_pin = 0;
3271fe98f82SClément Léger 	uint32_t config = 0;
3281fe98f82SClément Léger 	const uint32_t *prop = NULL;
3291fe98f82SClément Léger 
3301fe98f82SClément Léger 	/* Disable JTAG Reset and Debug */
3311fe98f82SClément Léger 	io_write32(secumod_base + SECUMOD_JTAGCR, SECUMOD_JTAGCR_FNTRST);
3321fe98f82SClément Léger 
3331fe98f82SClément Léger 	/* Switch IOs to normal mode */
3341fe98f82SClément Léger 	io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
3351fe98f82SClément Léger 		   SECUMOD_CR_NORMAL);
3361fe98f82SClément Léger 
3371fe98f82SClément Léger 	/* Clear all detection intrusion in normal mode */
3381fe98f82SClément Léger 	io_write32(secumod_base + SECUMOD_NMPR, 0);
3391fe98f82SClément Léger 
3401fe98f82SClément Léger 	/* Clear Alarms */
3411fe98f82SClément Léger 	io_write32(secumod_base + SECUMOD_SCR,
3421fe98f82SClément Léger 		   SECUMOD_PIN_MASK << SECUMOD_PIN_SHIFT);
3431fe98f82SClément Léger 
3441fe98f82SClément Léger 	/* Configure each IOs */
3451fe98f82SClément Léger 	prop = fdt_getprop(fdt, node, "gpios", &len);
3461fe98f82SClément Léger 	if (!prop)
3471fe98f82SClément Léger 		return;
3481fe98f82SClément Léger 
3491fe98f82SClément Léger 	len /= sizeof(uint32_t);
3501fe98f82SClément Léger 	for (i = 0; i < len; i += DT_GPIO_CELLS) {
3511fe98f82SClément Léger 		gpio_pin = fdt32_to_cpu(prop[i]);
3521fe98f82SClément Léger 		config = fdt32_to_cpu(prop[i + 1]);
3531fe98f82SClément Léger 
3541fe98f82SClément Léger 		secumod_cfg_input_pio(gpio_pin, config);
3551fe98f82SClément Léger 	}
3561fe98f82SClément Léger }
3571fe98f82SClément Léger 
3581fe98f82SClément Léger #ifdef CFG_PM_ARM32
3591fe98f82SClément Léger static TEE_Result piobu_pm(enum pm_op op, uint32_t pm_hint __unused,
3601fe98f82SClément Léger 			   const struct pm_callback_handle *hdl __unused)
3611fe98f82SClément Léger {
3621fe98f82SClément Léger 	switch (op) {
3631fe98f82SClément Léger 	case PM_OP_RESUME:
3641fe98f82SClément Léger 		io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
3651fe98f82SClément Léger 			   SECUMOD_CR_NORMAL);
3661fe98f82SClément Léger 		break;
3671fe98f82SClément Léger 	case PM_OP_SUSPEND:
3681fe98f82SClément Léger 		/* Enter backup mode before suspending */
3691fe98f82SClément Léger 		io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY |
3701fe98f82SClément Léger 			   SECUMOD_CR_BACKUP);
3711fe98f82SClément Léger 		break;
3721fe98f82SClément Léger 	default:
3731fe98f82SClément Léger 		panic("Invalid PM operation");
3741fe98f82SClément Léger 	}
3751fe98f82SClément Léger 
3761fe98f82SClément Léger 	return TEE_SUCCESS;
3771fe98f82SClément Léger }
3781fe98f82SClément Léger 
3791fe98f82SClément Léger static void piobu_register_pm(void)
3801fe98f82SClément Léger {
3811fe98f82SClément Léger 	register_pm_driver_cb(piobu_pm, NULL, "piobu");
3821fe98f82SClément Léger }
3831fe98f82SClément Léger #else
3841fe98f82SClément Léger static void piobu_register_pm(void) {}
3851fe98f82SClément Léger #endif
3861fe98f82SClément Léger 
3871fe98f82SClément Léger static TEE_Result atmel_secumod_probe(const void *fdt, int node,
3881fe98f82SClément Léger 				      const void *compat_data __unused)
3891fe98f82SClément Léger {
3901fe98f82SClément Léger 	size_t size = 0;
3911fe98f82SClément Léger 
3921fe98f82SClément Léger 	if (secumod_base)
3931fe98f82SClément Léger 		return TEE_ERROR_GENERIC;
3941fe98f82SClément Léger 
395a5d5bbc8SVesa Jääskeläinen 	if (dt_map_dev(fdt, node, &secumod_base, &size, DT_MAP_AUTO) < 0)
3961fe98f82SClément Léger 		return TEE_ERROR_GENERIC;
3971fe98f82SClément Léger 
3981fe98f82SClément Léger 	secumod_hw_init(fdt, node);
3991fe98f82SClément Léger 	secumod_interrupt_init();
4001fe98f82SClément Léger 
4011fe98f82SClément Léger 	secumod_chip.ops = &atmel_piobu_ops;
4021fe98f82SClément Léger 
4031fe98f82SClément Léger 	piobu_register_pm();
4041fe98f82SClément Léger 
405b786cc03SClément Léger 	assert(gpio_ops_is_valid(&atmel_piobu_ops));
406b786cc03SClément Léger 
407b786cc03SClément Léger 	return gpio_register_provider(fdt, node, secumod_dt_get, &secumod_chip);
4081fe98f82SClément Léger }
4091fe98f82SClément Léger 
4101fe98f82SClément Léger static const struct dt_device_match atmel_secumod_match_table[] = {
4111fe98f82SClément Léger 	{ .compatible = "atmel,sama5d2-secumod" },
4121fe98f82SClément Léger 	{ }
4131fe98f82SClément Léger };
4141fe98f82SClément Léger 
4151fe98f82SClément Léger DEFINE_DT_DRIVER(atmel_secumod_dt_driver) = {
4161fe98f82SClément Léger 	.name = "atmel_secumod",
4171fe98f82SClément Léger 	.type = DT_DRIVER_NOTYPE,
4181fe98f82SClément Léger 	.match_table = atmel_secumod_match_table,
4191fe98f82SClément Léger 	.probe = atmel_secumod_probe,
4201fe98f82SClément Léger };
421