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