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