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