xref: /optee_os/core/drivers/firewall/stm32_iac.c (revision 1c32a0ea6beeeeaaef3ff7bf2e5d4015555dfae8)
1571a39d1SGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause
2571a39d1SGatien Chevallier /*
3571a39d1SGatien Chevallier  * Copyright (c) 2022-2024, STMicroelectronics
4571a39d1SGatien Chevallier  */
5571a39d1SGatien Chevallier #include <drivers/stm32_rif.h>
6571a39d1SGatien Chevallier #include <io.h>
7571a39d1SGatien Chevallier #include <kernel/boot.h>
8571a39d1SGatien Chevallier #include <kernel/dt.h>
9571a39d1SGatien Chevallier #include <kernel/interrupt.h>
10571a39d1SGatien Chevallier #include <kernel/panic.h>
11571a39d1SGatien Chevallier #include <libfdt.h>
12571a39d1SGatien Chevallier #include <mm/core_memprot.h>
13571a39d1SGatien Chevallier #include <tee_api_defines.h>
14571a39d1SGatien Chevallier #include <trace.h>
15571a39d1SGatien Chevallier #include <util.h>
16571a39d1SGatien Chevallier 
17571a39d1SGatien Chevallier /* IAC offset register */
18571a39d1SGatien Chevallier #define _IAC_IER0		U(0x000)
19571a39d1SGatien Chevallier #define _IAC_ISR0		U(0x080)
20571a39d1SGatien Chevallier #define _IAC_ICR0		U(0x100)
21571a39d1SGatien Chevallier #define _IAC_IISR0		U(0x36C)
22571a39d1SGatien Chevallier 
23571a39d1SGatien Chevallier #define _IAC_HWCFGR2		U(0x3EC)
24571a39d1SGatien Chevallier #define _IAC_HWCFGR1		U(0x3F0)
25571a39d1SGatien Chevallier #define _IAC_VERR		U(0x3F4)
26571a39d1SGatien Chevallier 
27571a39d1SGatien Chevallier /* IAC_HWCFGR2 register fields */
28571a39d1SGatien Chevallier #define _IAC_HWCFGR2_CFG1_MASK	GENMASK_32(3, 0)
29571a39d1SGatien Chevallier #define _IAC_HWCFGR2_CFG1_SHIFT	0
30571a39d1SGatien Chevallier #define _IAC_HWCFGR2_CFG2_MASK	GENMASK_32(7, 4)
31571a39d1SGatien Chevallier #define _IAC_HWCFGR2_CFG2_SHIFT	4
32571a39d1SGatien Chevallier 
33571a39d1SGatien Chevallier /* IAC_HWCFGR1 register fields */
34571a39d1SGatien Chevallier #define _IAC_HWCFGR1_CFG1_MASK	GENMASK_32(3, 0)
35571a39d1SGatien Chevallier #define _IAC_HWCFGR1_CFG1_SHIFT	0
36571a39d1SGatien Chevallier #define _IAC_HWCFGR1_CFG2_MASK	GENMASK_32(7, 4)
37571a39d1SGatien Chevallier #define _IAC_HWCFGR1_CFG2_SHIFT	4
38571a39d1SGatien Chevallier #define _IAC_HWCFGR1_CFG3_MASK	GENMASK_32(11, 8)
39571a39d1SGatien Chevallier #define _IAC_HWCFGR1_CFG3_SHIFT	8
40571a39d1SGatien Chevallier #define _IAC_HWCFGR1_CFG4_MASK	GENMASK_32(15, 12)
41571a39d1SGatien Chevallier #define _IAC_HWCFGR1_CFG4_SHIFT	12
42571a39d1SGatien Chevallier #define _IAC_HWCFGR1_CFG5_MASK	GENMASK_32(24, 16)
43571a39d1SGatien Chevallier #define _IAC_HWCFGR1_CFG5_SHIFT	16
44571a39d1SGatien Chevallier 
45571a39d1SGatien Chevallier /* IAC_VERR register fields */
46571a39d1SGatien Chevallier #define _IAC_VERR_MINREV_MASK	GENMASK_32(3, 0)
47571a39d1SGatien Chevallier #define _IAC_VERR_MINREV_SHIFT	0
48571a39d1SGatien Chevallier #define _IAC_VERR_MAJREV_MASK	GENMASK_32(7, 4)
49571a39d1SGatien Chevallier #define _IAC_VERR_MAJREV_SHIFT	4
50571a39d1SGatien Chevallier 
51571a39d1SGatien Chevallier /* Periph ID per register */
52571a39d1SGatien Chevallier #define _PERIPH_IDS_PER_REG	32
53571a39d1SGatien Chevallier 
54571a39d1SGatien Chevallier #define _IAC_FLD_PREP(field, value)	(SHIFT_U32((value), \
55571a39d1SGatien Chevallier 						   (field ## _SHIFT)) & \
56571a39d1SGatien Chevallier 					 (field ## _MASK))
57571a39d1SGatien Chevallier #define _IAC_FLD_GET(field, value)	(((uint32_t)(value) & \
58571a39d1SGatien Chevallier 					  (field ## _MASK)) >> \
59571a39d1SGatien Chevallier 					 (field ## _SHIFT))
60571a39d1SGatien Chevallier 
61571a39d1SGatien Chevallier #define IAC_EXCEPT_MSB_BIT(x)		((x) * _PERIPH_IDS_PER_REG + \
62571a39d1SGatien Chevallier 					 _PERIPH_IDS_PER_REG - 1)
63571a39d1SGatien Chevallier #define IAC_EXCEPT_LSB_BIT(x)		((x) * _PERIPH_IDS_PER_REG)
64571a39d1SGatien Chevallier #define IAC_FIRST_ILAC_IN_REG(x)	(__builtin_ffs((x)) - 1)
65571a39d1SGatien Chevallier #define IAC_ILAC_ID(reg_val, offset)	(IAC_FIRST_ILAC_IN_REG(reg_val) + \
66571a39d1SGatien Chevallier 					 IAC_EXCEPT_LSB_BIT(offset))
67571a39d1SGatien Chevallier 
68571a39d1SGatien Chevallier /**
69571a39d1SGatien Chevallier  * struct iac_driver_data - Hardware information on the IAC peripheral
70571a39d1SGatien Chevallier  *
71571a39d1SGatien Chevallier  * @version: Peripheral version number
72571a39d1SGatien Chevallier  * @num_ilac: Number of IAC lines
73571a39d1SGatien Chevallier  */
74571a39d1SGatien Chevallier struct iac_driver_data {
75571a39d1SGatien Chevallier 	uint32_t version;
76571a39d1SGatien Chevallier 	uint8_t num_ilac;
77571a39d1SGatien Chevallier };
78571a39d1SGatien Chevallier 
79571a39d1SGatien Chevallier /**
80571a39d1SGatien Chevallier  * struct stm32_iac_platdata - Platform data for the IAC driver
81571a39d1SGatien Chevallier  *
82571a39d1SGatien Chevallier  * @irq_chip: Reference to the main IRQ chip of the platform
83571a39d1SGatien Chevallier  * @base: Virtual base address of the IAC peripheral
84571a39d1SGatien Chevallier  * @irq: ID of the IAC interrupt
85571a39d1SGatien Chevallier  */
86571a39d1SGatien Chevallier struct stm32_iac_platdata {
87571a39d1SGatien Chevallier 	struct itr_chip *irq_chip;
88571a39d1SGatien Chevallier 	vaddr_t base;
89571a39d1SGatien Chevallier 	size_t irq;
90571a39d1SGatien Chevallier };
91571a39d1SGatien Chevallier 
92571a39d1SGatien Chevallier /**
93571a39d1SGatien Chevallier  * struct iac_device - IAC device private data
94571a39d1SGatien Chevallier  * @pdata: Platform data read from the DT
95571a39d1SGatien Chevallier  * @ddata: Device data read from the hardware
96571a39d1SGatien Chevallier  * @itr: Interrupt handler reference
97571a39d1SGatien Chevallier  */
98571a39d1SGatien Chevallier struct iac_device {
99571a39d1SGatien Chevallier 	struct stm32_iac_platdata pdata;
100571a39d1SGatien Chevallier 	struct iac_driver_data *ddata;
101571a39d1SGatien Chevallier 	struct itr_handler *itr;
102571a39d1SGatien Chevallier };
103571a39d1SGatien Chevallier 
104571a39d1SGatien Chevallier static struct iac_device iac_dev;
105571a39d1SGatien Chevallier 
stm32_iac_get_hwdata(void)106571a39d1SGatien Chevallier static void stm32_iac_get_hwdata(void)
107571a39d1SGatien Chevallier {
108571a39d1SGatien Chevallier 	struct iac_driver_data *ddata = iac_dev.ddata;
109571a39d1SGatien Chevallier 	vaddr_t base = iac_dev.pdata.base;
110571a39d1SGatien Chevallier 	uint32_t regval = 0;
111571a39d1SGatien Chevallier 
112571a39d1SGatien Chevallier 	regval = io_read32(base + _IAC_HWCFGR1);
113571a39d1SGatien Chevallier 	ddata->num_ilac = _IAC_FLD_GET(_IAC_HWCFGR1_CFG5, regval);
114571a39d1SGatien Chevallier 
115571a39d1SGatien Chevallier 	ddata->version = io_read32(base + _IAC_VERR);
116571a39d1SGatien Chevallier 
117571a39d1SGatien Chevallier 	DMSG("IAC version %"PRIu32".%"PRIu32,
118571a39d1SGatien Chevallier 	     _IAC_FLD_GET(_IAC_VERR_MAJREV, ddata->version),
119571a39d1SGatien Chevallier 	     _IAC_FLD_GET(_IAC_VERR_MINREV, ddata->version));
120571a39d1SGatien Chevallier 
121571a39d1SGatien Chevallier 	DMSG("HW cap: enabled, num ilac:[%"PRIu8"]", ddata->num_ilac);
122571a39d1SGatien Chevallier }
123571a39d1SGatien Chevallier 
stm32_iac_parse_fdt(const void * fdt,int node)124571a39d1SGatien Chevallier static TEE_Result stm32_iac_parse_fdt(const void *fdt, int node)
125571a39d1SGatien Chevallier {
126571a39d1SGatien Chevallier 	struct stm32_iac_platdata *pdata = &iac_dev.pdata;
127571a39d1SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
128571a39d1SGatien Chevallier 	struct dt_node_info dt_info = { };
129571a39d1SGatien Chevallier 	struct io_pa_va base = { };
130571a39d1SGatien Chevallier 
131571a39d1SGatien Chevallier 	fdt_fill_device_info(fdt, &dt_info, node);
132571a39d1SGatien Chevallier 	if (dt_info.reg == DT_INFO_INVALID_REG)
133571a39d1SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
134571a39d1SGatien Chevallier 
135571a39d1SGatien Chevallier 	res = interrupt_dt_get(fdt, node, &pdata->irq_chip, &pdata->irq);
136571a39d1SGatien Chevallier 	if (res)
137571a39d1SGatien Chevallier 		return res;
138571a39d1SGatien Chevallier 
139571a39d1SGatien Chevallier 	base.pa = dt_info.reg;
140571a39d1SGatien Chevallier 	pdata->base = io_pa_or_va_secure(&base, dt_info.reg_size);
141571a39d1SGatien Chevallier 
142571a39d1SGatien Chevallier 	return TEE_SUCCESS;
143571a39d1SGatien Chevallier }
144571a39d1SGatien Chevallier 
stm32_iac_itr(struct itr_handler * h __unused)145571a39d1SGatien Chevallier static enum itr_return stm32_iac_itr(struct itr_handler *h __unused)
146571a39d1SGatien Chevallier {
147571a39d1SGatien Chevallier 	struct iac_driver_data *ddata = iac_dev.ddata;
148571a39d1SGatien Chevallier 	vaddr_t base = iac_dev.pdata.base;
149571a39d1SGatien Chevallier 	unsigned int nreg = DIV_ROUND_UP(ddata->num_ilac, _PERIPH_IDS_PER_REG);
150571a39d1SGatien Chevallier 	unsigned int i = 0;
151571a39d1SGatien Chevallier 	uint32_t isr = 0;
152571a39d1SGatien Chevallier 
153571a39d1SGatien Chevallier 	for (i = 0; i < nreg; i++) {
154571a39d1SGatien Chevallier 		uint32_t offset = sizeof(uint32_t) * i;
155571a39d1SGatien Chevallier 		unsigned int j = 0;
156571a39d1SGatien Chevallier 
157571a39d1SGatien Chevallier 		isr = io_read32(base + _IAC_ISR0 + offset);
158571a39d1SGatien Chevallier 		isr &= io_read32(base + _IAC_IER0 + offset);
159571a39d1SGatien Chevallier 
160571a39d1SGatien Chevallier 		if (!isr)
161571a39d1SGatien Chevallier 			continue;
162571a39d1SGatien Chevallier 
163571a39d1SGatien Chevallier 		EMSG("IAC exceptions [%d:%d]: %#"PRIx32, IAC_EXCEPT_MSB_BIT(i),
164571a39d1SGatien Chevallier 		     IAC_EXCEPT_LSB_BIT(i), isr);
165571a39d1SGatien Chevallier 
166571a39d1SGatien Chevallier 		for (j = 0; j < _PERIPH_IDS_PER_REG; j++) {
167571a39d1SGatien Chevallier 			EMSG("IAC exception ID: %d", IAC_ILAC_ID(isr, i));
168571a39d1SGatien Chevallier 
169571a39d1SGatien Chevallier 			io_write32(base + _IAC_ICR0 + offset,
170571a39d1SGatien Chevallier 				   BIT(IAC_FIRST_ILAC_IN_REG(isr)));
171571a39d1SGatien Chevallier 
172571a39d1SGatien Chevallier 			isr = io_read32(base + _IAC_ISR0 + offset);
173571a39d1SGatien Chevallier 			isr &= io_read32(base + _IAC_IER0 + offset);
174571a39d1SGatien Chevallier 
175571a39d1SGatien Chevallier 			if (!isr)
176571a39d1SGatien Chevallier 				break;
177571a39d1SGatien Chevallier 		}
178571a39d1SGatien Chevallier 	}
179571a39d1SGatien Chevallier 
180*1c32a0eaSGatien Chevallier 	stm32_rif_access_violation_action();
181*1c32a0eaSGatien Chevallier 	if (IS_ENABLED(CFG_STM32_PANIC_ON_IAC_EVENT))
182*1c32a0eaSGatien Chevallier 		panic();
183571a39d1SGatien Chevallier 
184571a39d1SGatien Chevallier 	return ITRR_HANDLED;
185571a39d1SGatien Chevallier }
186571a39d1SGatien Chevallier 
stm32_iac_setup(void)187571a39d1SGatien Chevallier static void stm32_iac_setup(void)
188571a39d1SGatien Chevallier {
189571a39d1SGatien Chevallier 	struct iac_driver_data *ddata = iac_dev.ddata;
190571a39d1SGatien Chevallier 	vaddr_t base = iac_dev.pdata.base;
191571a39d1SGatien Chevallier 	unsigned int nreg = DIV_ROUND_UP(ddata->num_ilac, _PERIPH_IDS_PER_REG);
192571a39d1SGatien Chevallier 	unsigned int i = 0;
193571a39d1SGatien Chevallier 
194571a39d1SGatien Chevallier 	for (i = 0; i < nreg; i++) {
195571a39d1SGatien Chevallier 		vaddr_t reg_ofst = base + sizeof(uint32_t) * i;
196571a39d1SGatien Chevallier 
197571a39d1SGatien Chevallier 		/* Clear status flags */
198571a39d1SGatien Chevallier 		io_write32(reg_ofst + _IAC_ICR0, ~0x0);
199571a39d1SGatien Chevallier 		/* Enable all peripherals of nreg */
200571a39d1SGatien Chevallier 		io_write32(reg_ofst + _IAC_IER0, ~0x0);
201571a39d1SGatien Chevallier 	}
202571a39d1SGatien Chevallier }
203571a39d1SGatien Chevallier 
probe_iac_device(const void * fdt,int node)204571a39d1SGatien Chevallier static TEE_Result probe_iac_device(const void *fdt, int node)
205571a39d1SGatien Chevallier {
206571a39d1SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
207571a39d1SGatien Chevallier 	bool is_tdcid = false;
208571a39d1SGatien Chevallier 
209571a39d1SGatien Chevallier 	res = stm32_rifsc_check_tdcid(&is_tdcid);
210571a39d1SGatien Chevallier 	if (res)
211571a39d1SGatien Chevallier 		return res;
212571a39d1SGatien Chevallier 
213571a39d1SGatien Chevallier 	/* IAC must be managed by the trusted domain CID */
214571a39d1SGatien Chevallier 	if (!is_tdcid)
215571a39d1SGatien Chevallier 		return TEE_ERROR_ACCESS_DENIED;
216571a39d1SGatien Chevallier 
217571a39d1SGatien Chevallier 	res = stm32_iac_parse_fdt(fdt, node);
218571a39d1SGatien Chevallier 	if (res)
219571a39d1SGatien Chevallier 		return res;
220571a39d1SGatien Chevallier 
221571a39d1SGatien Chevallier 	stm32_iac_get_hwdata();
222571a39d1SGatien Chevallier 	stm32_iac_setup();
223571a39d1SGatien Chevallier 
224571a39d1SGatien Chevallier 	res = interrupt_alloc_add_handler(iac_dev.pdata.irq_chip,
225571a39d1SGatien Chevallier 					  iac_dev.pdata.irq, stm32_iac_itr,
226571a39d1SGatien Chevallier 					  ITRF_TRIGGER_LEVEL, NULL,
227571a39d1SGatien Chevallier 					  &iac_dev.itr);
228571a39d1SGatien Chevallier 	if (res)
229571a39d1SGatien Chevallier 		panic();
230571a39d1SGatien Chevallier 
231571a39d1SGatien Chevallier 	interrupt_enable(iac_dev.pdata.irq_chip, iac_dev.itr->it);
232571a39d1SGatien Chevallier 
233571a39d1SGatien Chevallier 	return TEE_SUCCESS;
234571a39d1SGatien Chevallier }
235571a39d1SGatien Chevallier 
stm32_iac_probe(const void * fdt,int node,const void * compat_data __unused)236571a39d1SGatien Chevallier static TEE_Result stm32_iac_probe(const void *fdt, int node,
237571a39d1SGatien Chevallier 				  const void *compat_data __unused)
238571a39d1SGatien Chevallier {
239571a39d1SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
240571a39d1SGatien Chevallier 
241571a39d1SGatien Chevallier 	iac_dev.ddata = calloc(1, sizeof(*iac_dev.ddata));
242571a39d1SGatien Chevallier 	if (!iac_dev.ddata)
243571a39d1SGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
244571a39d1SGatien Chevallier 
245571a39d1SGatien Chevallier 	res = probe_iac_device(fdt, node);
246571a39d1SGatien Chevallier 	if (res)
247571a39d1SGatien Chevallier 		free(iac_dev.ddata);
248571a39d1SGatien Chevallier 
249571a39d1SGatien Chevallier 	return res;
250571a39d1SGatien Chevallier }
251571a39d1SGatien Chevallier 
252571a39d1SGatien Chevallier static const struct dt_device_match stm32_iac_match_table[] = {
253571a39d1SGatien Chevallier 	{ .compatible = "st,stm32mp25-iac" },
254571a39d1SGatien Chevallier 	{ }
255571a39d1SGatien Chevallier };
256571a39d1SGatien Chevallier 
257571a39d1SGatien Chevallier DEFINE_DT_DRIVER(stm32_iac_dt_driver) = {
258571a39d1SGatien Chevallier 	.name = "stm32-iac",
259571a39d1SGatien Chevallier 	.match_table = stm32_iac_match_table,
260571a39d1SGatien Chevallier 	.probe = stm32_iac_probe,
261571a39d1SGatien Chevallier };
262