xref: /optee_os/core/drivers/firewall/stm32_iac.c (revision 571a39d108036f8d65fc3cfd7fa7036689e94ba2)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2022-2024, STMicroelectronics
4  */
5 #include <drivers/stm32_rif.h>
6 #include <io.h>
7 #include <kernel/boot.h>
8 #include <kernel/dt.h>
9 #include <kernel/interrupt.h>
10 #include <kernel/panic.h>
11 #include <libfdt.h>
12 #include <mm/core_memprot.h>
13 #include <tee_api_defines.h>
14 #include <trace.h>
15 #include <util.h>
16 
17 /* IAC offset register */
18 #define _IAC_IER0		U(0x000)
19 #define _IAC_ISR0		U(0x080)
20 #define _IAC_ICR0		U(0x100)
21 #define _IAC_IISR0		U(0x36C)
22 
23 #define _IAC_HWCFGR2		U(0x3EC)
24 #define _IAC_HWCFGR1		U(0x3F0)
25 #define _IAC_VERR		U(0x3F4)
26 
27 /* IAC_HWCFGR2 register fields */
28 #define _IAC_HWCFGR2_CFG1_MASK	GENMASK_32(3, 0)
29 #define _IAC_HWCFGR2_CFG1_SHIFT	0
30 #define _IAC_HWCFGR2_CFG2_MASK	GENMASK_32(7, 4)
31 #define _IAC_HWCFGR2_CFG2_SHIFT	4
32 
33 /* IAC_HWCFGR1 register fields */
34 #define _IAC_HWCFGR1_CFG1_MASK	GENMASK_32(3, 0)
35 #define _IAC_HWCFGR1_CFG1_SHIFT	0
36 #define _IAC_HWCFGR1_CFG2_MASK	GENMASK_32(7, 4)
37 #define _IAC_HWCFGR1_CFG2_SHIFT	4
38 #define _IAC_HWCFGR1_CFG3_MASK	GENMASK_32(11, 8)
39 #define _IAC_HWCFGR1_CFG3_SHIFT	8
40 #define _IAC_HWCFGR1_CFG4_MASK	GENMASK_32(15, 12)
41 #define _IAC_HWCFGR1_CFG4_SHIFT	12
42 #define _IAC_HWCFGR1_CFG5_MASK	GENMASK_32(24, 16)
43 #define _IAC_HWCFGR1_CFG5_SHIFT	16
44 
45 /* IAC_VERR register fields */
46 #define _IAC_VERR_MINREV_MASK	GENMASK_32(3, 0)
47 #define _IAC_VERR_MINREV_SHIFT	0
48 #define _IAC_VERR_MAJREV_MASK	GENMASK_32(7, 4)
49 #define _IAC_VERR_MAJREV_SHIFT	4
50 
51 /* Periph ID per register */
52 #define _PERIPH_IDS_PER_REG	32
53 
54 #define _IAC_FLD_PREP(field, value)	(SHIFT_U32((value), \
55 						   (field ## _SHIFT)) & \
56 					 (field ## _MASK))
57 #define _IAC_FLD_GET(field, value)	(((uint32_t)(value) & \
58 					  (field ## _MASK)) >> \
59 					 (field ## _SHIFT))
60 
61 #define IAC_EXCEPT_MSB_BIT(x)		((x) * _PERIPH_IDS_PER_REG + \
62 					 _PERIPH_IDS_PER_REG - 1)
63 #define IAC_EXCEPT_LSB_BIT(x)		((x) * _PERIPH_IDS_PER_REG)
64 #define IAC_FIRST_ILAC_IN_REG(x)	(__builtin_ffs((x)) - 1)
65 #define IAC_ILAC_ID(reg_val, offset)	(IAC_FIRST_ILAC_IN_REG(reg_val) + \
66 					 IAC_EXCEPT_LSB_BIT(offset))
67 
68 /**
69  * struct iac_driver_data - Hardware information on the IAC peripheral
70  *
71  * @version: Peripheral version number
72  * @num_ilac: Number of IAC lines
73  */
74 struct iac_driver_data {
75 	uint32_t version;
76 	uint8_t num_ilac;
77 };
78 
79 /**
80  * struct stm32_iac_platdata - Platform data for the IAC driver
81  *
82  * @irq_chip: Reference to the main IRQ chip of the platform
83  * @base: Virtual base address of the IAC peripheral
84  * @irq: ID of the IAC interrupt
85  */
86 struct stm32_iac_platdata {
87 	struct itr_chip *irq_chip;
88 	vaddr_t base;
89 	size_t irq;
90 };
91 
92 /**
93  * struct iac_device - IAC device private data
94  * @pdata: Platform data read from the DT
95  * @ddata: Device data read from the hardware
96  * @itr: Interrupt handler reference
97  */
98 struct iac_device {
99 	struct stm32_iac_platdata pdata;
100 	struct iac_driver_data *ddata;
101 	struct itr_handler *itr;
102 };
103 
104 static struct iac_device iac_dev;
105 
106 static void stm32_iac_get_hwdata(void)
107 {
108 	struct iac_driver_data *ddata = iac_dev.ddata;
109 	vaddr_t base = iac_dev.pdata.base;
110 	uint32_t regval = 0;
111 
112 	regval = io_read32(base + _IAC_HWCFGR1);
113 	ddata->num_ilac = _IAC_FLD_GET(_IAC_HWCFGR1_CFG5, regval);
114 
115 	ddata->version = io_read32(base + _IAC_VERR);
116 
117 	DMSG("IAC version %"PRIu32".%"PRIu32,
118 	     _IAC_FLD_GET(_IAC_VERR_MAJREV, ddata->version),
119 	     _IAC_FLD_GET(_IAC_VERR_MINREV, ddata->version));
120 
121 	DMSG("HW cap: enabled, num ilac:[%"PRIu8"]", ddata->num_ilac);
122 }
123 
124 static TEE_Result stm32_iac_parse_fdt(const void *fdt, int node)
125 {
126 	struct stm32_iac_platdata *pdata = &iac_dev.pdata;
127 	TEE_Result res = TEE_ERROR_GENERIC;
128 	struct dt_node_info dt_info = { };
129 	struct io_pa_va base = { };
130 
131 	fdt_fill_device_info(fdt, &dt_info, node);
132 	if (dt_info.reg == DT_INFO_INVALID_REG)
133 		return TEE_ERROR_BAD_PARAMETERS;
134 
135 	res = interrupt_dt_get(fdt, node, &pdata->irq_chip, &pdata->irq);
136 	if (res)
137 		return res;
138 
139 	base.pa = dt_info.reg;
140 	pdata->base = io_pa_or_va_secure(&base, dt_info.reg_size);
141 
142 	return TEE_SUCCESS;
143 }
144 
145 static __noreturn void access_violation_action(void)
146 {
147 	DMSG("Ooops...");
148 	panic();
149 }
150 
151 static enum itr_return stm32_iac_itr(struct itr_handler *h __unused)
152 {
153 	struct iac_driver_data *ddata = iac_dev.ddata;
154 	vaddr_t base = iac_dev.pdata.base;
155 	unsigned int nreg = DIV_ROUND_UP(ddata->num_ilac, _PERIPH_IDS_PER_REG);
156 	unsigned int i = 0;
157 	uint32_t isr = 0;
158 
159 	for (i = 0; i < nreg; i++) {
160 		uint32_t offset = sizeof(uint32_t) * i;
161 		unsigned int j = 0;
162 
163 		isr = io_read32(base + _IAC_ISR0 + offset);
164 		isr &= io_read32(base + _IAC_IER0 + offset);
165 
166 		if (!isr)
167 			continue;
168 
169 		EMSG("IAC exceptions [%d:%d]: %#"PRIx32, IAC_EXCEPT_MSB_BIT(i),
170 		     IAC_EXCEPT_LSB_BIT(i), isr);
171 
172 		for (j = 0; j < _PERIPH_IDS_PER_REG; j++) {
173 			EMSG("IAC exception ID: %d", IAC_ILAC_ID(isr, i));
174 
175 			io_write32(base + _IAC_ICR0 + offset,
176 				   BIT(IAC_FIRST_ILAC_IN_REG(isr)));
177 
178 			isr = io_read32(base + _IAC_ISR0 + offset);
179 			isr &= io_read32(base + _IAC_IER0 + offset);
180 
181 			if (!isr)
182 				break;
183 		}
184 	}
185 
186 	access_violation_action();
187 
188 	return ITRR_HANDLED;
189 }
190 
191 static void stm32_iac_setup(void)
192 {
193 	struct iac_driver_data *ddata = iac_dev.ddata;
194 	vaddr_t base = iac_dev.pdata.base;
195 	unsigned int nreg = DIV_ROUND_UP(ddata->num_ilac, _PERIPH_IDS_PER_REG);
196 	unsigned int i = 0;
197 
198 	for (i = 0; i < nreg; i++) {
199 		vaddr_t reg_ofst = base + sizeof(uint32_t) * i;
200 
201 		/* Clear status flags */
202 		io_write32(reg_ofst + _IAC_ICR0, ~0x0);
203 		/* Enable all peripherals of nreg */
204 		io_write32(reg_ofst + _IAC_IER0, ~0x0);
205 	}
206 }
207 
208 static TEE_Result probe_iac_device(const void *fdt, int node)
209 {
210 	TEE_Result res = TEE_ERROR_GENERIC;
211 	bool is_tdcid = false;
212 
213 	res = stm32_rifsc_check_tdcid(&is_tdcid);
214 	if (res)
215 		return res;
216 
217 	/* IAC must be managed by the trusted domain CID */
218 	if (!is_tdcid)
219 		return TEE_ERROR_ACCESS_DENIED;
220 
221 	res = stm32_iac_parse_fdt(fdt, node);
222 	if (res)
223 		return res;
224 
225 	stm32_iac_get_hwdata();
226 	stm32_iac_setup();
227 
228 	res = interrupt_alloc_add_handler(iac_dev.pdata.irq_chip,
229 					  iac_dev.pdata.irq, stm32_iac_itr,
230 					  ITRF_TRIGGER_LEVEL, NULL,
231 					  &iac_dev.itr);
232 	if (res)
233 		panic();
234 
235 	interrupt_enable(iac_dev.pdata.irq_chip, iac_dev.itr->it);
236 
237 	return TEE_SUCCESS;
238 }
239 
240 static TEE_Result stm32_iac_probe(const void *fdt, int node,
241 				  const void *compat_data __unused)
242 {
243 	TEE_Result res = TEE_ERROR_GENERIC;
244 
245 	iac_dev.ddata = calloc(1, sizeof(*iac_dev.ddata));
246 	if (!iac_dev.ddata)
247 		return TEE_ERROR_OUT_OF_MEMORY;
248 
249 	res = probe_iac_device(fdt, node);
250 	if (res)
251 		free(iac_dev.ddata);
252 
253 	return res;
254 }
255 
256 static const struct dt_device_match stm32_iac_match_table[] = {
257 	{ .compatible = "st,stm32mp25-iac" },
258 	{ }
259 };
260 
261 DEFINE_DT_DRIVER(stm32_iac_dt_driver) = {
262 	.name = "stm32-iac",
263 	.match_table = stm32_iac_match_table,
264 	.probe = stm32_iac_probe,
265 };
266