xref: /optee_os/core/drivers/stm32_ipcc.c (revision 2a844736c5ceb2b6d60cfb4731b80c56622da2fe)
1e26b8e0fSGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause
2e26b8e0fSGatien Chevallier /*
3e26b8e0fSGatien Chevallier  * Copyright (c) 2022-2024, STMicroelectronics
4e26b8e0fSGatien Chevallier  */
5e26b8e0fSGatien Chevallier 
6e26b8e0fSGatien Chevallier #include <arm.h>
7e26b8e0fSGatien Chevallier #include <config.h>
8e26b8e0fSGatien Chevallier #include <drivers/clk.h>
9e26b8e0fSGatien Chevallier #include <drivers/clk_dt.h>
10e26b8e0fSGatien Chevallier #include <drivers/stm32_rif.h>
11e26b8e0fSGatien Chevallier #include <io.h>
12e26b8e0fSGatien Chevallier #include <kernel/boot.h>
13e26b8e0fSGatien Chevallier #include <kernel/delay.h>
14e26b8e0fSGatien Chevallier #include <kernel/dt.h>
15e26b8e0fSGatien Chevallier #include <kernel/dt_driver.h>
16e26b8e0fSGatien Chevallier #include <kernel/panic.h>
17e26b8e0fSGatien Chevallier #include <kernel/pm.h>
18e26b8e0fSGatien Chevallier #include <libfdt.h>
19e26b8e0fSGatien Chevallier #include <mm/core_memprot.h>
20e26b8e0fSGatien Chevallier #include <stdbool.h>
21e26b8e0fSGatien Chevallier #include <stdlib.h>
22e26b8e0fSGatien Chevallier #include <stm32_util.h>
23e26b8e0fSGatien Chevallier #include <trace.h>
24e26b8e0fSGatien Chevallier 
25e26b8e0fSGatien Chevallier #define IPCC_C1SECCFGR			U(0x80)
26e26b8e0fSGatien Chevallier #define IPCC_C1PRIVCFGR			U(0x84)
27e26b8e0fSGatien Chevallier #define IPCC_C1CIDCFGR			U(0x88)
28e26b8e0fSGatien Chevallier #define IPCC_C2SECCFGR			U(0x90)
29e26b8e0fSGatien Chevallier #define IPCC_C2PRIVCFGR			U(0x94)
30e26b8e0fSGatien Chevallier #define IPCC_C2CIDCFGR			U(0x98)
31e26b8e0fSGatien Chevallier #define IPCC_HWCFGR			U(0x3F0)
32e26b8e0fSGatien Chevallier 
33e26b8e0fSGatien Chevallier /*
34e26b8e0fSGatien Chevallier  * CIDCFGR register bitfields
35e26b8e0fSGatien Chevallier  */
36*2a844736SGatien Chevallier #define IPCC_CIDCFGR_CFEN		BIT(0)
37e26b8e0fSGatien Chevallier #define IPCC_CIDCFGR_SCID_MASK		GENMASK_32(6, 4)
38e26b8e0fSGatien Chevallier #define IPCC_CIDCFGR_CONF_MASK		(_CIDCFGR_CFEN |	 \
39e26b8e0fSGatien Chevallier 					 IPCC_CIDCFGR_SCID_MASK)
40e26b8e0fSGatien Chevallier 
41e26b8e0fSGatien Chevallier /*
42e26b8e0fSGatien Chevallier  * PRIVCFGR register bitfields
43e26b8e0fSGatien Chevallier  */
44e26b8e0fSGatien Chevallier #define IPCC_PRIVCFGR_MASK		GENMASK_32(15, 0)
45e26b8e0fSGatien Chevallier 
46e26b8e0fSGatien Chevallier /*
47e26b8e0fSGatien Chevallier  * SECCFGR register bitfields
48e26b8e0fSGatien Chevallier  */
49e26b8e0fSGatien Chevallier #define IPCC_SECCFGR_MASK		GENMASK_32(15, 0)
50e26b8e0fSGatien Chevallier 
51e26b8e0fSGatien Chevallier /*
52e26b8e0fSGatien Chevallier  * IPCC_HWCFGR register bitfields
53e26b8e0fSGatien Chevallier  */
54e26b8e0fSGatien Chevallier #define IPCC_HWCFGR_CHAN_MASK		GENMASK_32(7, 0)
55e26b8e0fSGatien Chevallier 
56e26b8e0fSGatien Chevallier /*
57e26b8e0fSGatien Chevallier  * Miscellaneous
58e26b8e0fSGatien Chevallier  */
59e26b8e0fSGatien Chevallier #define IPCC_NB_MAX_RIF_CHAN		U(16)
60e26b8e0fSGatien Chevallier 
61e26b8e0fSGatien Chevallier struct ipcc_pdata {
62e26b8e0fSGatien Chevallier 	/*
63e26b8e0fSGatien Chevallier 	 * An IPCC has nb_channels_cfg channel configuration for its
64e26b8e0fSGatien Chevallier 	 * (nb_channels_cfg / 2) bi-directionnal channels
65e26b8e0fSGatien Chevallier 	 */
66e26b8e0fSGatien Chevallier 	unsigned int nb_channels_cfg;
67e26b8e0fSGatien Chevallier 	struct clk *ipcc_clock;
68e26b8e0fSGatien Chevallier 	vaddr_t base;
69ce5fe041SGatien Chevallier 	struct rif_conf_data *conf_data;
70*2a844736SGatien Chevallier 	bool is_tdcid;
71e26b8e0fSGatien Chevallier 
72e26b8e0fSGatien Chevallier 	STAILQ_ENTRY(ipcc_pdata) link;
73e26b8e0fSGatien Chevallier };
74e26b8e0fSGatien Chevallier 
75e26b8e0fSGatien Chevallier static STAILQ_HEAD(, ipcc_pdata) ipcc_list =
76e26b8e0fSGatien Chevallier 		STAILQ_HEAD_INITIALIZER(ipcc_list);
77e26b8e0fSGatien Chevallier 
78e26b8e0fSGatien Chevallier /* This function expects IPCC bus clock is enabled */
apply_rif_config(struct ipcc_pdata * ipcc_d)79*2a844736SGatien Chevallier static void apply_rif_config(struct ipcc_pdata *ipcc_d)
80e26b8e0fSGatien Chevallier {
81*2a844736SGatien Chevallier 	bool proc1_cidfilt = false;
82*2a844736SGatien Chevallier 	bool proc2_cidfilt = false;
83e26b8e0fSGatien Chevallier 	uint32_t priv_proc_1 = 0;
84e26b8e0fSGatien Chevallier 	uint32_t priv_proc_2 = 0;
85e26b8e0fSGatien Chevallier 	uint32_t sec_proc_1 = 0;
86e26b8e0fSGatien Chevallier 	uint32_t sec_proc_2 = 0;
87*2a844736SGatien Chevallier 	unsigned int cid1 = 0;
88*2a844736SGatien Chevallier 	unsigned int cid2 = 0;
89e26b8e0fSGatien Chevallier 	unsigned int i = 0;
90e26b8e0fSGatien Chevallier 	bool is_cid_configured = false;
91e26b8e0fSGatien Chevallier 
92ce5fe041SGatien Chevallier 	if (!ipcc_d->conf_data)
93ce5fe041SGatien Chevallier 		return;
94ce5fe041SGatien Chevallier 
95e26b8e0fSGatien Chevallier 	/*
96e26b8e0fSGatien Chevallier 	 * Check that the number of channel supported by hardware
97e26b8e0fSGatien Chevallier 	 * is coherent with the config
98e26b8e0fSGatien Chevallier 	 */
99e26b8e0fSGatien Chevallier 	assert((io_read32(ipcc_d->base + IPCC_HWCFGR) &
100e26b8e0fSGatien Chevallier 			  IPCC_HWCFGR_CHAN_MASK) >=
101e26b8e0fSGatien Chevallier 	       ipcc_d->nb_channels_cfg / 2);
102e26b8e0fSGatien Chevallier 
103e26b8e0fSGatien Chevallier 	/*
104e26b8e0fSGatien Chevallier 	 * When TDCID, OP-TEE should be the one to set the CID filtering
105e26b8e0fSGatien Chevallier 	 * configuration. Clearing previous configuration prevents
106e26b8e0fSGatien Chevallier 	 * undesired events during the only legitimate configuration.
107e26b8e0fSGatien Chevallier 	 */
108*2a844736SGatien Chevallier 	if (ipcc_d->is_tdcid) {
109e26b8e0fSGatien Chevallier 		/* IPCC Processor 1 */
110e26b8e0fSGatien Chevallier 		io_clrbits32(ipcc_d->base + IPCC_C1CIDCFGR,
111e26b8e0fSGatien Chevallier 			     IPCC_CIDCFGR_CONF_MASK);
112e26b8e0fSGatien Chevallier 
113e26b8e0fSGatien Chevallier 		/* IPCC Processor 2 */
114e26b8e0fSGatien Chevallier 		io_clrbits32(ipcc_d->base + IPCC_C2CIDCFGR,
115e26b8e0fSGatien Chevallier 			     IPCC_CIDCFGR_CONF_MASK);
116e26b8e0fSGatien Chevallier 	}
117e26b8e0fSGatien Chevallier 
118*2a844736SGatien Chevallier 	cid1 = io_read32(ipcc_d->base + IPCC_C1CIDCFGR) &
119*2a844736SGatien Chevallier 	       IPCC_CIDCFGR_SCID_MASK;
120*2a844736SGatien Chevallier 	cid2 = io_read32(ipcc_d->base + IPCC_C2CIDCFGR) &
121*2a844736SGatien Chevallier 	       IPCC_CIDCFGR_SCID_MASK;
122*2a844736SGatien Chevallier 
123*2a844736SGatien Chevallier 	proc1_cidfilt = io_read32(ipcc_d->base + IPCC_C1CIDCFGR) &
124*2a844736SGatien Chevallier 		       IPCC_CIDCFGR_CFEN;
125*2a844736SGatien Chevallier 	proc2_cidfilt = io_read32(ipcc_d->base + IPCC_C2CIDCFGR) &
126*2a844736SGatien Chevallier 		       IPCC_CIDCFGR_CFEN;
127*2a844736SGatien Chevallier 
128e26b8e0fSGatien Chevallier 	/* Split the sec and priv configuration for IPCC processor 1 and 2 */
129ce5fe041SGatien Chevallier 	sec_proc_1 = ipcc_d->conf_data->sec_conf[0] &
130e26b8e0fSGatien Chevallier 		     GENMASK_32(IPCC_NB_MAX_RIF_CHAN - 1, 0);
131ce5fe041SGatien Chevallier 	priv_proc_1 = ipcc_d->conf_data->priv_conf[0] &
132e26b8e0fSGatien Chevallier 		      GENMASK_32(IPCC_NB_MAX_RIF_CHAN - 1, 0);
133e26b8e0fSGatien Chevallier 
134ce5fe041SGatien Chevallier 	sec_proc_2 = (ipcc_d->conf_data->sec_conf[0] &
135e26b8e0fSGatien Chevallier 		      GENMASK_32((IPCC_NB_MAX_RIF_CHAN * 2) - 1,
136e26b8e0fSGatien Chevallier 				 IPCC_NB_MAX_RIF_CHAN)) >>
137e26b8e0fSGatien Chevallier 		     IPCC_NB_MAX_RIF_CHAN;
138ce5fe041SGatien Chevallier 	priv_proc_2 = (ipcc_d->conf_data->priv_conf[0] &
139e26b8e0fSGatien Chevallier 		       GENMASK_32((IPCC_NB_MAX_RIF_CHAN * 2) - 1,
140e26b8e0fSGatien Chevallier 				  IPCC_NB_MAX_RIF_CHAN)) >>
141e26b8e0fSGatien Chevallier 		      IPCC_NB_MAX_RIF_CHAN;
142e26b8e0fSGatien Chevallier 
143e26b8e0fSGatien Chevallier 	/* Security and privilege RIF configuration */
144*2a844736SGatien Chevallier 	if (!proc1_cidfilt || cid1 == RIF_CID1) {
145*2a844736SGatien Chevallier 		io_clrsetbits32(ipcc_d->base + IPCC_C1PRIVCFGR,
146*2a844736SGatien Chevallier 				IPCC_PRIVCFGR_MASK, priv_proc_1);
147*2a844736SGatien Chevallier 		io_clrsetbits32(ipcc_d->base + IPCC_C1SECCFGR,
148*2a844736SGatien Chevallier 				IPCC_SECCFGR_MASK, sec_proc_1);
149*2a844736SGatien Chevallier 	}
150*2a844736SGatien Chevallier 	if (!proc2_cidfilt || cid2 == RIF_CID1) {
151*2a844736SGatien Chevallier 		io_clrsetbits32(ipcc_d->base + IPCC_C2PRIVCFGR,
152*2a844736SGatien Chevallier 				IPCC_PRIVCFGR_MASK, priv_proc_2);
153*2a844736SGatien Chevallier 		io_clrsetbits32(ipcc_d->base + IPCC_C2SECCFGR,
154*2a844736SGatien Chevallier 				IPCC_SECCFGR_MASK, sec_proc_2);
155*2a844736SGatien Chevallier 	}
156e26b8e0fSGatien Chevallier 
157e26b8e0fSGatien Chevallier 	/*
158e26b8e0fSGatien Chevallier 	 * Evaluate RIF CID filtering configuration before setting it.
159e26b8e0fSGatien Chevallier 	 * Parsed configuration must have consistency. If CID filtering
160e26b8e0fSGatien Chevallier 	 * is enabled for an IPCC channel, then it must be the case for all
161e26b8e0fSGatien Chevallier 	 * channels of this processor. This is a configuration check.
162e26b8e0fSGatien Chevallier 	 */
163e26b8e0fSGatien Chevallier 	for (i = 0; i < IPCC_NB_MAX_RIF_CHAN; i++) {
164ce5fe041SGatien Chevallier 		if (!(BIT(i) & ipcc_d->conf_data->access_mask[0]))
165e26b8e0fSGatien Chevallier 			continue;
166e26b8e0fSGatien Chevallier 
167e26b8e0fSGatien Chevallier 		if (!is_cid_configured &&
168ce5fe041SGatien Chevallier 		    (BIT(0) & ipcc_d->conf_data->cid_confs[i])) {
169e26b8e0fSGatien Chevallier 			is_cid_configured = true;
170*2a844736SGatien Chevallier 			if (i > 0)
171e26b8e0fSGatien Chevallier 				panic("Inconsistent IPCC CID filtering RIF configuration");
172e26b8e0fSGatien Chevallier 		}
173e26b8e0fSGatien Chevallier 
174e26b8e0fSGatien Chevallier 		if (is_cid_configured &&
175ce5fe041SGatien Chevallier 		    !(BIT(0) & ipcc_d->conf_data->cid_confs[i]))
176e26b8e0fSGatien Chevallier 			panic("Inconsistent IPCC CID filtering RIF configuration");
177e26b8e0fSGatien Chevallier 	}
178e26b8e0fSGatien Chevallier 
179e26b8e0fSGatien Chevallier 	/* IPCC processor 1 CID filtering configuration */
180*2a844736SGatien Chevallier 	if (!ipcc_d->is_tdcid)
181e26b8e0fSGatien Chevallier 		return;
182e26b8e0fSGatien Chevallier 
183e26b8e0fSGatien Chevallier 	io_clrsetbits32(ipcc_d->base + IPCC_C1CIDCFGR,
184e26b8e0fSGatien Chevallier 			IPCC_CIDCFGR_CONF_MASK,
185ce5fe041SGatien Chevallier 			ipcc_d->conf_data->cid_confs[0]);
186e26b8e0fSGatien Chevallier 
187e26b8e0fSGatien Chevallier 	/*
188e26b8e0fSGatien Chevallier 	 * Reset this field to evaluate CID filtering configuration
189e26b8e0fSGatien Chevallier 	 * for processor 2
190e26b8e0fSGatien Chevallier 	 */
191e26b8e0fSGatien Chevallier 	is_cid_configured = false;
192e26b8e0fSGatien Chevallier 
193e26b8e0fSGatien Chevallier 	for (i = IPCC_NB_MAX_RIF_CHAN; i < IPCC_NB_MAX_RIF_CHAN * 2; i++) {
194ce5fe041SGatien Chevallier 		if (!(BIT(i) & ipcc_d->conf_data->access_mask[0]))
195e26b8e0fSGatien Chevallier 			continue;
196e26b8e0fSGatien Chevallier 
197e26b8e0fSGatien Chevallier 		if (!is_cid_configured &&
198ce5fe041SGatien Chevallier 		    (BIT(0) & ipcc_d->conf_data->cid_confs[i])) {
199e26b8e0fSGatien Chevallier 			is_cid_configured = true;
200*2a844736SGatien Chevallier 			if (i > IPCC_NB_MAX_RIF_CHAN)
201e26b8e0fSGatien Chevallier 				panic("Inconsistent IPCC CID filtering RIF configuration");
202e26b8e0fSGatien Chevallier 		}
203e26b8e0fSGatien Chevallier 
204e26b8e0fSGatien Chevallier 		if (is_cid_configured &&
205ce5fe041SGatien Chevallier 		    !(BIT(0) & ipcc_d->conf_data->cid_confs[i]))
206e26b8e0fSGatien Chevallier 			panic("Inconsistent IPCC CID filtering RIF configuration");
207e26b8e0fSGatien Chevallier 	}
208e26b8e0fSGatien Chevallier 
209e26b8e0fSGatien Chevallier 	/* IPCC Processor 2 CID filtering configuration */
210e26b8e0fSGatien Chevallier 	io_clrsetbits32(ipcc_d->base + IPCC_C2CIDCFGR,
211e26b8e0fSGatien Chevallier 			IPCC_CIDCFGR_CONF_MASK,
212ce5fe041SGatien Chevallier 			ipcc_d->conf_data->cid_confs[IPCC_NB_MAX_RIF_CHAN]);
213e26b8e0fSGatien Chevallier }
214e26b8e0fSGatien Chevallier 
stm32_ipcc_pm_resume(struct ipcc_pdata * ipcc)215e26b8e0fSGatien Chevallier static void stm32_ipcc_pm_resume(struct ipcc_pdata *ipcc)
216e26b8e0fSGatien Chevallier {
217*2a844736SGatien Chevallier 	apply_rif_config(ipcc);
218e26b8e0fSGatien Chevallier }
219e26b8e0fSGatien Chevallier 
stm32_ipcc_pm_suspend(struct ipcc_pdata * ipcc __unused)220e26b8e0fSGatien Chevallier static void stm32_ipcc_pm_suspend(struct ipcc_pdata *ipcc __unused)
221e26b8e0fSGatien Chevallier {
222e26b8e0fSGatien Chevallier 	/*
223e26b8e0fSGatien Chevallier 	 * Do nothing because IPCC forbids RIF configuration read if CID
224e26b8e0fSGatien Chevallier 	 * filtering is enabled. We'll simply restore the device tree RIF
225e26b8e0fSGatien Chevallier 	 * configuration.
226e26b8e0fSGatien Chevallier 	 */
227e26b8e0fSGatien Chevallier }
228e26b8e0fSGatien Chevallier 
229e26b8e0fSGatien Chevallier static TEE_Result
stm32_ipcc_pm(enum pm_op op,unsigned int pm_hint,const struct pm_callback_handle * pm_handle)230e26b8e0fSGatien Chevallier stm32_ipcc_pm(enum pm_op op, unsigned int pm_hint,
231e26b8e0fSGatien Chevallier 	      const struct pm_callback_handle *pm_handle)
232e26b8e0fSGatien Chevallier {
233e26b8e0fSGatien Chevallier 	struct ipcc_pdata *ipcc = pm_handle->handle;
234e26b8e0fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
235e26b8e0fSGatien Chevallier 
236*2a844736SGatien Chevallier 	if (!PM_HINT_IS_STATE(pm_hint, CONTEXT) || !ipcc->is_tdcid)
237e26b8e0fSGatien Chevallier 		return TEE_SUCCESS;
238e26b8e0fSGatien Chevallier 
239e26b8e0fSGatien Chevallier 	res = clk_enable(ipcc->ipcc_clock);
240e26b8e0fSGatien Chevallier 	if (res)
241e26b8e0fSGatien Chevallier 		return res;
242e26b8e0fSGatien Chevallier 
243e26b8e0fSGatien Chevallier 	if (op == PM_OP_RESUME)
244e26b8e0fSGatien Chevallier 		stm32_ipcc_pm_resume(ipcc);
245e26b8e0fSGatien Chevallier 	else
246e26b8e0fSGatien Chevallier 		stm32_ipcc_pm_suspend(ipcc);
247e26b8e0fSGatien Chevallier 
248e26b8e0fSGatien Chevallier 	clk_disable(ipcc->ipcc_clock);
249e26b8e0fSGatien Chevallier 
250e26b8e0fSGatien Chevallier 	return TEE_SUCCESS;
251e26b8e0fSGatien Chevallier }
252e26b8e0fSGatien Chevallier 
parse_dt(const void * fdt,int node,struct ipcc_pdata * ipcc_d)253e26b8e0fSGatien Chevallier static TEE_Result parse_dt(const void *fdt, int node, struct ipcc_pdata *ipcc_d)
254e26b8e0fSGatien Chevallier {
255e26b8e0fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
256e26b8e0fSGatien Chevallier 	struct dt_node_info info = { };
257ce5fe041SGatien Chevallier 	const fdt32_t *cuint = NULL;
258e26b8e0fSGatien Chevallier 	struct io_pa_va addr = { };
259ce5fe041SGatien Chevallier 	unsigned int i = 0;
260ce5fe041SGatien Chevallier 	int lenp = 0;
261e26b8e0fSGatien Chevallier 
262e26b8e0fSGatien Chevallier 	fdt_fill_device_info(fdt, &info, node);
263e26b8e0fSGatien Chevallier 	assert(info.reg != DT_INFO_INVALID_REG &&
264e26b8e0fSGatien Chevallier 	       info.reg_size != DT_INFO_INVALID_REG_SIZE);
265e26b8e0fSGatien Chevallier 
266e26b8e0fSGatien Chevallier 	addr.pa = info.reg;
267e26b8e0fSGatien Chevallier 	ipcc_d->base = io_pa_or_va_secure(&addr, info.reg_size);
268e26b8e0fSGatien Chevallier 	assert(ipcc_d->base);
269e26b8e0fSGatien Chevallier 
270e26b8e0fSGatien Chevallier 	/* Gate the IP */
271e26b8e0fSGatien Chevallier 	res = clk_dt_get_by_index(fdt, node, 0, &ipcc_d->ipcc_clock);
272e26b8e0fSGatien Chevallier 	if (res)
273e26b8e0fSGatien Chevallier 		return res;
274e26b8e0fSGatien Chevallier 
275e26b8e0fSGatien Chevallier 	cuint = fdt_getprop(fdt, node, "st,protreg", &lenp);
276ce5fe041SGatien Chevallier 	if (!cuint) {
277ce5fe041SGatien Chevallier 		DMSG("No RIF configuration available");
278ce5fe041SGatien Chevallier 		return TEE_SUCCESS;
279ce5fe041SGatien Chevallier 	}
280ce5fe041SGatien Chevallier 
281ce5fe041SGatien Chevallier 	ipcc_d->conf_data = calloc(1, sizeof(*ipcc_d->conf_data));
282ce5fe041SGatien Chevallier 	if (!ipcc_d->conf_data)
283ce5fe041SGatien Chevallier 		panic();
284e26b8e0fSGatien Chevallier 
285e26b8e0fSGatien Chevallier 	ipcc_d->nb_channels_cfg = (unsigned int)(lenp / sizeof(uint32_t));
286e26b8e0fSGatien Chevallier 	assert(ipcc_d->nb_channels_cfg <= (IPCC_NB_MAX_RIF_CHAN * 2));
287e26b8e0fSGatien Chevallier 
288ce5fe041SGatien Chevallier 	ipcc_d->conf_data->cid_confs = calloc(IPCC_NB_MAX_RIF_CHAN * 2,
289e26b8e0fSGatien Chevallier 					      sizeof(uint32_t));
290ce5fe041SGatien Chevallier 	ipcc_d->conf_data->sec_conf = calloc(1, sizeof(uint32_t));
291ce5fe041SGatien Chevallier 	ipcc_d->conf_data->priv_conf = calloc(1, sizeof(uint32_t));
292ce5fe041SGatien Chevallier 	ipcc_d->conf_data->access_mask = calloc(1, sizeof(uint32_t));
293ce5fe041SGatien Chevallier 	if (!ipcc_d->conf_data->cid_confs || !ipcc_d->conf_data->sec_conf ||
294ce5fe041SGatien Chevallier 	    !ipcc_d->conf_data->priv_conf || !ipcc_d->conf_data->access_mask)
295ce5fe041SGatien Chevallier 		panic("Missing memory capacity for ipcc RIF configuration");
296e26b8e0fSGatien Chevallier 
297e26b8e0fSGatien Chevallier 	for (i = 0; i < ipcc_d->nb_channels_cfg; i++)
298ce5fe041SGatien Chevallier 		stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), ipcc_d->conf_data,
299e26b8e0fSGatien Chevallier 				    IPCC_NB_MAX_RIF_CHAN * 2);
300e26b8e0fSGatien Chevallier 
301e26b8e0fSGatien Chevallier 	return TEE_SUCCESS;
302e26b8e0fSGatien Chevallier }
303e26b8e0fSGatien Chevallier 
stm32_ipcc_probe(const void * fdt,int node,const void * compat_data __unused)304e26b8e0fSGatien Chevallier static TEE_Result stm32_ipcc_probe(const void *fdt, int node,
305e26b8e0fSGatien Chevallier 				   const void *compat_data __unused)
306e26b8e0fSGatien Chevallier {
307e26b8e0fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
308e26b8e0fSGatien Chevallier 	struct ipcc_pdata *ipcc_d = NULL;
309e26b8e0fSGatien Chevallier 
310e26b8e0fSGatien Chevallier 	ipcc_d = calloc(1, sizeof(*ipcc_d));
311e26b8e0fSGatien Chevallier 	if (!ipcc_d)
312e26b8e0fSGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
313e26b8e0fSGatien Chevallier 
314*2a844736SGatien Chevallier 	res = stm32_rifsc_check_tdcid(&ipcc_d->is_tdcid);
315*2a844736SGatien Chevallier 	if (res)
316*2a844736SGatien Chevallier 		goto err;
317*2a844736SGatien Chevallier 
318e26b8e0fSGatien Chevallier 	res = parse_dt(fdt, node, ipcc_d);
319e26b8e0fSGatien Chevallier 	if (res)
320e26b8e0fSGatien Chevallier 		goto err;
321e26b8e0fSGatien Chevallier 
322e26b8e0fSGatien Chevallier 	res = clk_enable(ipcc_d->ipcc_clock);
323e26b8e0fSGatien Chevallier 	if (res)
324e26b8e0fSGatien Chevallier 		panic("Cannot access IPCC clock");
325e26b8e0fSGatien Chevallier 
326*2a844736SGatien Chevallier 	apply_rif_config(ipcc_d);
327e26b8e0fSGatien Chevallier 
328e26b8e0fSGatien Chevallier 	clk_disable(ipcc_d->ipcc_clock);
329e26b8e0fSGatien Chevallier 
330e26b8e0fSGatien Chevallier 	STAILQ_INSERT_TAIL(&ipcc_list, ipcc_d, link);
331e26b8e0fSGatien Chevallier 
332e26b8e0fSGatien Chevallier 	register_pm_core_service_cb(stm32_ipcc_pm, ipcc_d, "stm32-ipcc");
333e26b8e0fSGatien Chevallier 
334*2a844736SGatien Chevallier 	return TEE_SUCCESS;
335e26b8e0fSGatien Chevallier 
336e26b8e0fSGatien Chevallier err:
337e26b8e0fSGatien Chevallier 	/* Free all allocated resources */
338ce5fe041SGatien Chevallier 	if (ipcc_d->conf_data) {
339ce5fe041SGatien Chevallier 		free(ipcc_d->conf_data->access_mask);
340ce5fe041SGatien Chevallier 		free(ipcc_d->conf_data->cid_confs);
341ce5fe041SGatien Chevallier 		free(ipcc_d->conf_data->priv_conf);
342ce5fe041SGatien Chevallier 		free(ipcc_d->conf_data->sec_conf);
343ce5fe041SGatien Chevallier 	}
344ce5fe041SGatien Chevallier 	free(ipcc_d->conf_data);
345e26b8e0fSGatien Chevallier 	free(ipcc_d);
346e26b8e0fSGatien Chevallier 
347e26b8e0fSGatien Chevallier 	return res;
348e26b8e0fSGatien Chevallier }
349e26b8e0fSGatien Chevallier 
350e26b8e0fSGatien Chevallier static const struct dt_device_match stm32_ipcc_match_table[] = {
351e26b8e0fSGatien Chevallier 	{ .compatible = "st,stm32mp25-ipcc" },
352e26b8e0fSGatien Chevallier 	{ }
353e26b8e0fSGatien Chevallier };
354e26b8e0fSGatien Chevallier 
355e26b8e0fSGatien Chevallier DEFINE_DT_DRIVER(stm32_ipcc_dt_driver) = {
356e26b8e0fSGatien Chevallier 	.name = "st,stm32mp-ipcc",
357e26b8e0fSGatien Chevallier 	.match_table = stm32_ipcc_match_table,
358e26b8e0fSGatien Chevallier 	.probe = stm32_ipcc_probe,
359e26b8e0fSGatien Chevallier };
360