xref: /optee_os/core/drivers/firewall/stm32_serc.c (revision 321b5b24cecd51bcb74606108a6c6a022d7d5146)
1612f3e4fSGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause
2612f3e4fSGatien Chevallier /*
3612f3e4fSGatien Chevallier  * Copyright (c) 2022-2024, STMicroelectronics
4612f3e4fSGatien Chevallier  */
5612f3e4fSGatien Chevallier #include <drivers/clk.h>
6612f3e4fSGatien Chevallier #include <drivers/clk_dt.h>
7612f3e4fSGatien Chevallier #include <drivers/stm32_rif.h>
8*321b5b24SGatien Chevallier #include <drivers/stm32_serc.h>
9612f3e4fSGatien Chevallier #include <io.h>
10612f3e4fSGatien Chevallier #include <kernel/boot.h>
11612f3e4fSGatien Chevallier #include <kernel/dt.h>
12612f3e4fSGatien Chevallier #include <kernel/interrupt.h>
13612f3e4fSGatien Chevallier #include <kernel/panic.h>
14612f3e4fSGatien Chevallier #include <kernel/pm.h>
15612f3e4fSGatien Chevallier #include <libfdt.h>
16612f3e4fSGatien Chevallier #include <mm/core_memprot.h>
17612f3e4fSGatien Chevallier #include <tee_api_defines.h>
18612f3e4fSGatien Chevallier #include <trace.h>
19612f3e4fSGatien Chevallier #include <util.h>
20612f3e4fSGatien Chevallier 
21612f3e4fSGatien Chevallier /* SERC offset register */
22612f3e4fSGatien Chevallier #define _SERC_IER0		U(0x000)
23612f3e4fSGatien Chevallier #define _SERC_ISR0		U(0x040)
24612f3e4fSGatien Chevallier #define _SERC_ICR0		U(0x080)
25612f3e4fSGatien Chevallier #define _SERC_ENABLE		U(0x100)
26612f3e4fSGatien Chevallier 
27612f3e4fSGatien Chevallier #define _SERC_HWCFGR		U(0x3F0)
28612f3e4fSGatien Chevallier #define _SERC_VERR		U(0x3F4)
29612f3e4fSGatien Chevallier 
30612f3e4fSGatien Chevallier /* SERC_ENABLE register fields */
31612f3e4fSGatien Chevallier #define _SERC_ENABLE_SERFEN	BIT(0)
32612f3e4fSGatien Chevallier 
33612f3e4fSGatien Chevallier /* SERC_HWCFGR register fields */
34612f3e4fSGatien Chevallier #define _SERC_HWCFGR_CFG1_MASK	GENMASK_32(7, 0)
35612f3e4fSGatien Chevallier #define _SERC_HWCFGR_CFG1_SHIFT	U(0)
36612f3e4fSGatien Chevallier #define _SERC_HWCFGR_CFG2_MASK	GENMASK_32(18, 16)
37612f3e4fSGatien Chevallier #define _SERC_HWCFGR_CFG2_SHIFT	U(16)
38612f3e4fSGatien Chevallier 
39612f3e4fSGatien Chevallier /* SERC_VERR register fields */
40612f3e4fSGatien Chevallier #define _SERC_VERR_MINREV_MASK	GENMASK_32(3, 0)
41612f3e4fSGatien Chevallier #define _SERC_VERR_MINREV_SHIFT	U(0)
42612f3e4fSGatien Chevallier #define _SERC_VERR_MAJREV_MASK	GENMASK_32(7, 4)
43612f3e4fSGatien Chevallier #define _SERC_VERR_MAJREV_SHIFT	U(4)
44612f3e4fSGatien Chevallier 
45612f3e4fSGatien Chevallier /* Periph id per register */
46612f3e4fSGatien Chevallier #define _PERIPH_IDS_PER_REG	U(32)
47612f3e4fSGatien Chevallier 
48612f3e4fSGatien Chevallier #define _SERC_FLD_PREP(field, value)	(SHIFT_U32((value), \
49612f3e4fSGatien Chevallier 						   (field ## _SHIFT)) & \
50612f3e4fSGatien Chevallier 					 (field ## _MASK))
51612f3e4fSGatien Chevallier #define _SERC_FLD_GET(field, value)	(((uint32_t)(value) & \
52612f3e4fSGatien Chevallier 					  (field ## _MASK)) >> \
53612f3e4fSGatien Chevallier 					 (field ## _SHIFT))
54612f3e4fSGatien Chevallier 
55612f3e4fSGatien Chevallier #define SERC_EXCEPT_MSB_BIT(x) ((x) * _PERIPH_IDS_PER_REG + \
56612f3e4fSGatien Chevallier 				_PERIPH_IDS_PER_REG - 1)
57612f3e4fSGatien Chevallier #define SERC_EXCEPT_LSB_BIT(x) ((x) * _PERIPH_IDS_PER_REG)
58612f3e4fSGatien Chevallier 
59612f3e4fSGatien Chevallier /**
60612f3e4fSGatien Chevallier  * struct serc_driver_data - Hardware information on the SERC peripheral
61612f3e4fSGatien Chevallier  *
62612f3e4fSGatien Chevallier  * @version: Peripheral version number
63612f3e4fSGatien Chevallier  * @num_ilac: Number of SERC lines
64612f3e4fSGatien Chevallier  */
65612f3e4fSGatien Chevallier struct serc_driver_data {
66612f3e4fSGatien Chevallier 	uint32_t version;
67612f3e4fSGatien Chevallier 	uint8_t num_ilac;
68612f3e4fSGatien Chevallier };
69612f3e4fSGatien Chevallier 
70612f3e4fSGatien Chevallier /**
71612f3e4fSGatien Chevallier  * struct stm32_serc_platdata - Platform data for the SERC driver
72612f3e4fSGatien Chevallier  *
73612f3e4fSGatien Chevallier  * @irq_chip: Reference to the SERC's IRQ chip
74612f3e4fSGatien Chevallier  * @clock: Reference on the SERC clock
75612f3e4fSGatien Chevallier  * @base: Base address of the SERC peripheral
76612f3e4fSGatien Chevallier  * @irq: ID of the SERC interrupt
77612f3e4fSGatien Chevallier  */
78612f3e4fSGatien Chevallier struct stm32_serc_platdata {
79612f3e4fSGatien Chevallier 	struct itr_chip *irq_chip;
80612f3e4fSGatien Chevallier 	struct clk *clock;
81612f3e4fSGatien Chevallier 	vaddr_t base;
82612f3e4fSGatien Chevallier 	size_t irq;
83612f3e4fSGatien Chevallier };
84612f3e4fSGatien Chevallier 
85612f3e4fSGatien Chevallier /**
86612f3e4fSGatien Chevallier  * struct serc_device - SERC device private data
87612f3e4fSGatien Chevallier  * @pdata: Platform data read from the DT
88612f3e4fSGatien Chevallier  * @ddata: Device data read from the hardware
89612f3e4fSGatien Chevallier  * @itr: Interrupt handler reference
90612f3e4fSGatien Chevallier  */
91612f3e4fSGatien Chevallier struct serc_device {
92612f3e4fSGatien Chevallier 	struct stm32_serc_platdata pdata;
93612f3e4fSGatien Chevallier 	struct serc_driver_data *ddata;
94612f3e4fSGatien Chevallier 	struct itr_handler *itr;
95612f3e4fSGatien Chevallier };
96612f3e4fSGatien Chevallier 
97612f3e4fSGatien Chevallier static struct serc_device serc_dev;
98612f3e4fSGatien Chevallier 
stm32_serc_get_hwdata(void)99612f3e4fSGatien Chevallier static void stm32_serc_get_hwdata(void)
100612f3e4fSGatien Chevallier {
101612f3e4fSGatien Chevallier 	struct stm32_serc_platdata *pdata = &serc_dev.pdata;
102612f3e4fSGatien Chevallier 	struct serc_driver_data *ddata = serc_dev.ddata;
103612f3e4fSGatien Chevallier 	vaddr_t base = pdata->base;
104612f3e4fSGatien Chevallier 	uint32_t regval = 0;
105612f3e4fSGatien Chevallier 
106612f3e4fSGatien Chevallier 	regval = io_read32(base + _SERC_HWCFGR);
107612f3e4fSGatien Chevallier 
108612f3e4fSGatien Chevallier 	ddata->num_ilac = _SERC_FLD_GET(_SERC_HWCFGR_CFG1, regval);
109612f3e4fSGatien Chevallier 
110612f3e4fSGatien Chevallier 	ddata->version = io_read32(base + _SERC_VERR);
111612f3e4fSGatien Chevallier 
112612f3e4fSGatien Chevallier 	DMSG("SERC version %"PRIu32".%"PRIu32,
113612f3e4fSGatien Chevallier 	     _SERC_FLD_GET(_SERC_VERR_MAJREV, ddata->version),
114612f3e4fSGatien Chevallier 	     _SERC_FLD_GET(_SERC_VERR_MINREV, ddata->version));
115612f3e4fSGatien Chevallier 
116612f3e4fSGatien Chevallier 	DMSG("HW cap: num ilac:[%"PRIu8"]", ddata->num_ilac);
117612f3e4fSGatien Chevallier }
118612f3e4fSGatien Chevallier 
stm32_serc_parse_fdt(const void * fdt,int node)119612f3e4fSGatien Chevallier static TEE_Result stm32_serc_parse_fdt(const void *fdt, int node)
120612f3e4fSGatien Chevallier {
121612f3e4fSGatien Chevallier 	struct stm32_serc_platdata *pdata = &serc_dev.pdata;
122612f3e4fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
123612f3e4fSGatien Chevallier 	struct dt_node_info dt_info = { };
124612f3e4fSGatien Chevallier 	struct io_pa_va base = { };
125612f3e4fSGatien Chevallier 
126612f3e4fSGatien Chevallier 	fdt_fill_device_info(fdt, &dt_info, node);
127612f3e4fSGatien Chevallier 	if (dt_info.reg == DT_INFO_INVALID_REG)
128612f3e4fSGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
129612f3e4fSGatien Chevallier 
130612f3e4fSGatien Chevallier 	res = interrupt_dt_get(fdt, node, &pdata->irq_chip, &pdata->irq);
131612f3e4fSGatien Chevallier 	if (res)
132612f3e4fSGatien Chevallier 		return res;
133612f3e4fSGatien Chevallier 
134612f3e4fSGatien Chevallier 	base.pa = dt_info.reg;
135612f3e4fSGatien Chevallier 	pdata->base = io_pa_or_va_secure(&base, dt_info.reg_size);
136612f3e4fSGatien Chevallier 
137612f3e4fSGatien Chevallier 	return clk_dt_get_by_index(fdt, node, 0, &pdata->clock);
138612f3e4fSGatien Chevallier }
139612f3e4fSGatien Chevallier 
stm32_serc_handle_ilac(void)140*321b5b24SGatien Chevallier void stm32_serc_handle_ilac(void)
141612f3e4fSGatien Chevallier {
142612f3e4fSGatien Chevallier 	struct stm32_serc_platdata *pdata = &serc_dev.pdata;
143612f3e4fSGatien Chevallier 	struct serc_driver_data *ddata = serc_dev.ddata;
144*321b5b24SGatien Chevallier 	unsigned int nreg = 0;
145*321b5b24SGatien Chevallier 	bool do_panic = false;
146612f3e4fSGatien Chevallier 	unsigned int i = 0;
147*321b5b24SGatien Chevallier 	vaddr_t base = 0;
148612f3e4fSGatien Chevallier 	uint32_t isr = 0;
149612f3e4fSGatien Chevallier 
150*321b5b24SGatien Chevallier 	if (!ddata || !pdata)
151*321b5b24SGatien Chevallier 		return;
152*321b5b24SGatien Chevallier 
153*321b5b24SGatien Chevallier 	nreg = DIV_ROUND_UP(ddata->num_ilac, _PERIPH_IDS_PER_REG);
154*321b5b24SGatien Chevallier 	base = pdata->base;
155*321b5b24SGatien Chevallier 
156612f3e4fSGatien Chevallier 	for (i = 0; i < nreg; i++) {
157612f3e4fSGatien Chevallier 		uint32_t offset = sizeof(uint32_t) * i;
158612f3e4fSGatien Chevallier 		unsigned int j = 0;
159612f3e4fSGatien Chevallier 
160612f3e4fSGatien Chevallier 		isr = io_read32(base + _SERC_ISR0 + offset);
161612f3e4fSGatien Chevallier 		isr &= io_read32(base + _SERC_IER0 + offset);
162612f3e4fSGatien Chevallier 
163612f3e4fSGatien Chevallier 		if (!isr)
164612f3e4fSGatien Chevallier 			continue;
165612f3e4fSGatien Chevallier 
166*321b5b24SGatien Chevallier 		do_panic = true;
167612f3e4fSGatien Chevallier 		EMSG("SERC exceptions [%d:%d]: %#"PRIx32,
168612f3e4fSGatien Chevallier 		     SERC_EXCEPT_MSB_BIT(i), SERC_EXCEPT_LSB_BIT(i), isr);
169612f3e4fSGatien Chevallier 
170612f3e4fSGatien Chevallier 		for (j = 0; j < _PERIPH_IDS_PER_REG; j++) {
171612f3e4fSGatien Chevallier 			EMSG("SERC exception ID: %d",
172612f3e4fSGatien Chevallier 			     SERC_EXCEPT_LSB_BIT(i) + __builtin_ffs(isr) - 1);
173612f3e4fSGatien Chevallier 
174612f3e4fSGatien Chevallier 			io_write32(base + _SERC_ICR0 + offset,
175612f3e4fSGatien Chevallier 				   BIT(__builtin_ffs(isr) - 1));
176612f3e4fSGatien Chevallier 
177612f3e4fSGatien Chevallier 			isr = io_read32(base + _SERC_ISR0 + offset);
178612f3e4fSGatien Chevallier 			isr &= io_read32(base + _SERC_IER0 + offset);
179612f3e4fSGatien Chevallier 
180612f3e4fSGatien Chevallier 			if (!isr)
181612f3e4fSGatien Chevallier 				break;
182612f3e4fSGatien Chevallier 		}
183612f3e4fSGatien Chevallier 	}
184612f3e4fSGatien Chevallier 
1851c32a0eaSGatien Chevallier 	stm32_rif_access_violation_action();
186*321b5b24SGatien Chevallier 	if (IS_ENABLED(CFG_STM32_PANIC_ON_SERC_EVENT) && do_panic)
1871c32a0eaSGatien Chevallier 		panic();
188612f3e4fSGatien Chevallier }
189612f3e4fSGatien Chevallier 
stm32_serc_itr(struct itr_handler * h __unused)190612f3e4fSGatien Chevallier static enum itr_return stm32_serc_itr(struct itr_handler *h __unused)
191612f3e4fSGatien Chevallier {
192612f3e4fSGatien Chevallier 	stm32_serc_handle_ilac();
193612f3e4fSGatien Chevallier 
194612f3e4fSGatien Chevallier 	return ITRR_HANDLED;
195612f3e4fSGatien Chevallier }
196612f3e4fSGatien Chevallier 
stm32_serc_setup(void)197612f3e4fSGatien Chevallier static void stm32_serc_setup(void)
198612f3e4fSGatien Chevallier {
199612f3e4fSGatien Chevallier 	struct stm32_serc_platdata *pdata = &serc_dev.pdata;
200612f3e4fSGatien Chevallier 	struct serc_driver_data *ddata = serc_dev.ddata;
201612f3e4fSGatien Chevallier 	vaddr_t base = serc_dev.pdata.base;
202612f3e4fSGatien Chevallier 	uint32_t nreg = DIV_ROUND_UP(ddata->num_ilac, _PERIPH_IDS_PER_REG);
203612f3e4fSGatien Chevallier 	uint32_t i = 0;
204612f3e4fSGatien Chevallier 
205612f3e4fSGatien Chevallier 	io_setbits32(pdata->base + _SERC_ENABLE, _SERC_ENABLE_SERFEN);
206612f3e4fSGatien Chevallier 
207612f3e4fSGatien Chevallier 	for (i = 0; i < nreg; i++) {
208612f3e4fSGatien Chevallier 		vaddr_t reg_ofst = base + sizeof(uint32_t) * i;
209612f3e4fSGatien Chevallier 
210612f3e4fSGatien Chevallier 		/* Clear status flags */
211612f3e4fSGatien Chevallier 		io_write32(reg_ofst + _SERC_ICR0, ~0x0);
212612f3e4fSGatien Chevallier 		/* Enable all peripherals of nreg */
213612f3e4fSGatien Chevallier 		io_write32(reg_ofst + _SERC_IER0, ~0x0);
214612f3e4fSGatien Chevallier 	}
215612f3e4fSGatien Chevallier }
216612f3e4fSGatien Chevallier 
probe_serc_device(const void * fdt,int node)217612f3e4fSGatien Chevallier static TEE_Result probe_serc_device(const void *fdt, int node)
218612f3e4fSGatien Chevallier {
219612f3e4fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
220612f3e4fSGatien Chevallier 
221612f3e4fSGatien Chevallier 	res = stm32_serc_parse_fdt(fdt, node);
222612f3e4fSGatien Chevallier 	if (res)
223612f3e4fSGatien Chevallier 		return res;
224612f3e4fSGatien Chevallier 
225612f3e4fSGatien Chevallier 	/* Unbalanced clock enable to have the SERC running */
226612f3e4fSGatien Chevallier 	if (clk_enable(serc_dev.pdata.clock))
227612f3e4fSGatien Chevallier 		panic();
228612f3e4fSGatien Chevallier 
229612f3e4fSGatien Chevallier 	stm32_serc_get_hwdata();
230612f3e4fSGatien Chevallier 	stm32_serc_setup();
231612f3e4fSGatien Chevallier 
232612f3e4fSGatien Chevallier 	res = interrupt_alloc_add_handler(serc_dev.pdata.irq_chip,
233612f3e4fSGatien Chevallier 					  serc_dev.pdata.irq, stm32_serc_itr,
234612f3e4fSGatien Chevallier 					  ITRF_TRIGGER_LEVEL, NULL,
235612f3e4fSGatien Chevallier 					  &serc_dev.itr);
236612f3e4fSGatien Chevallier 	if (res)
237612f3e4fSGatien Chevallier 		panic();
238612f3e4fSGatien Chevallier 
239612f3e4fSGatien Chevallier 	interrupt_enable(serc_dev.pdata.irq_chip, serc_dev.itr->it);
240612f3e4fSGatien Chevallier 
241612f3e4fSGatien Chevallier 	return TEE_SUCCESS;
242612f3e4fSGatien Chevallier }
243612f3e4fSGatien Chevallier 
stm32_serc_pm(enum pm_op op,unsigned int pm_hint,const struct pm_callback_handle * hdl __unused)244612f3e4fSGatien Chevallier static TEE_Result stm32_serc_pm(enum pm_op op, unsigned int pm_hint,
245612f3e4fSGatien Chevallier 				const struct pm_callback_handle *hdl __unused)
246612f3e4fSGatien Chevallier {
247612f3e4fSGatien Chevallier 	if (!PM_HINT_IS_STATE(pm_hint, CONTEXT))
248612f3e4fSGatien Chevallier 		return TEE_SUCCESS;
249612f3e4fSGatien Chevallier 
250612f3e4fSGatien Chevallier 	if (op == PM_OP_RESUME) {
251612f3e4fSGatien Chevallier 		if (clk_enable(serc_dev.pdata.clock))
252612f3e4fSGatien Chevallier 			panic();
253612f3e4fSGatien Chevallier 		stm32_serc_setup();
254612f3e4fSGatien Chevallier 	} else {
255612f3e4fSGatien Chevallier 		clk_disable(serc_dev.pdata.clock);
256612f3e4fSGatien Chevallier 	}
257612f3e4fSGatien Chevallier 
258612f3e4fSGatien Chevallier 	return TEE_SUCCESS;
259612f3e4fSGatien Chevallier }
260612f3e4fSGatien Chevallier 
stm32_serc_probe(const void * fdt,int node,const void * compat_data __unused)261612f3e4fSGatien Chevallier static TEE_Result stm32_serc_probe(const void *fdt, int node,
262612f3e4fSGatien Chevallier 				   const void *compat_data __unused)
263612f3e4fSGatien Chevallier {
264612f3e4fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
265612f3e4fSGatien Chevallier 
266612f3e4fSGatien Chevallier 	serc_dev.ddata = calloc(1, sizeof(*serc_dev.ddata));
267612f3e4fSGatien Chevallier 	if (!serc_dev.ddata)
268612f3e4fSGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
269612f3e4fSGatien Chevallier 
270612f3e4fSGatien Chevallier 	res = probe_serc_device(fdt, node);
271612f3e4fSGatien Chevallier 	if (res) {
272612f3e4fSGatien Chevallier 		free(serc_dev.ddata);
273612f3e4fSGatien Chevallier 		return res;
274612f3e4fSGatien Chevallier 	}
275612f3e4fSGatien Chevallier 
276612f3e4fSGatien Chevallier 	register_pm_core_service_cb(stm32_serc_pm, NULL, "stm32-serc");
277612f3e4fSGatien Chevallier 
278612f3e4fSGatien Chevallier 	return TEE_SUCCESS;
279612f3e4fSGatien Chevallier }
280612f3e4fSGatien Chevallier 
281612f3e4fSGatien Chevallier static const struct dt_device_match stm32_serc_match_table[] = {
282612f3e4fSGatien Chevallier 	{ .compatible = "st,stm32mp25-serc" },
283612f3e4fSGatien Chevallier 	{ }
284612f3e4fSGatien Chevallier };
285612f3e4fSGatien Chevallier 
286612f3e4fSGatien Chevallier DEFINE_DT_DRIVER(stm32_serc_dt_driver) = {
287612f3e4fSGatien Chevallier 	.name = "stm32-serc",
288612f3e4fSGatien Chevallier 	.match_table = stm32_serc_match_table,
289612f3e4fSGatien Chevallier 	.probe = stm32_serc_probe,
290612f3e4fSGatien Chevallier };
291