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