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