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