// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2023, STMicroelectronics - All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "stm32_firewall.h" /* * RIFSC offset register */ #define RIFSC_RISC_SECCFGR0 0x10 #define RIFSC_RISC_PRIVCFGR0 0x30 #define RIFSC_RISC_PER0_CIDCFGR 0x100 #define RIFSC_RISC_PER0_SEMCR 0x104 #define RIFSC_RISC_REG0_ACFGR 0x900 #define RIFSC_RISC_REG3_AADDR 0x924 #define RIFSC_RISC_HWCFGR2 0xFEC /* * SEMCR register */ #define SEMCR_MUTEX BIT(0) /* * HWCFGR2 register */ #define HWCFGR2_CONF1_MASK GENMASK(15, 0) #define HWCFGR2_CONF2_MASK GENMASK(23, 16) #define HWCFGR2_CONF3_MASK GENMASK(31, 24) /* * RIFSC miscellaneous */ #define RIFSC_RISC_CFEN_MASK BIT(0) #define RIFSC_RISC_SEM_EN_MASK BIT(1) #define RIFSC_RISC_SCID_MASK GENMASK(6, 4) #define RIFSC_RISC_SEML_SHIFT 16 #define RIFSC_RISC_SEMWL_MASK GENMASK(23, 16) #define RIFSC_RISC_PER_ID_MASK GENMASK(31, 24) #define RIFSC_RISC_PERx_CID_MASK (RIFSC_RISC_CFEN_MASK | \ RIFSC_RISC_SEM_EN_MASK | \ RIFSC_RISC_SCID_MASK | \ RIFSC_RISC_SEMWL_MASK) #define IDS_PER_RISC_SEC_PRIV_REGS 32 /* RIF miscellaneous */ /* * CIDCFGR register fields */ #define CIDCFGR_CFEN BIT(0) #define CIDCFGR_SEMEN BIT(1) #define CIDCFGR_SEMWL(x) BIT(RIFSC_RISC_SEML_SHIFT + (x)) #define SEMWL_SHIFT 16 /* Compartiment IDs */ #define RIF_CID0 0x0 #define RIF_CID1 0x1 #if defined(CONFIG_DEBUG_FS) #define RIFSC_RISUP_ENTRIES 128 #define RIFSC_RIMU_ENTRIES 16 #define RIFSC_RISAL_SUBREGIONS 2 #define RIFSC_RISAL_GRANULARITY 8 #define RIFSC_RIMC_ATTR0 0xC10 #define RIFSC_RIMC_CIDSEL BIT(2) #define RIFSC_RIMC_MCID_MASK GENMASK(6, 4) #define RIFSC_RIMC_MSEC BIT(8) #define RIFSC_RIMC_MPRIV BIT(9) #define RIFSC_RISC_SRCID_MASK GENMASK(6, 4) #define RIFSC_RISC_SRPRIV BIT(9) #define RIFSC_RISC_SRSEC BIT(8) #define RIFSC_RISC_SRRLOCK BIT(1) #define RIFSC_RISC_SREN BIT(0) #define RIFSC_RISC_SRLENGTH_MASK GENMASK(27, 16) #define RIFSC_RISC_SRSTART_MASK GENMASK(10, 0) static const char *stm32mp21_rifsc_rimu_names[RIFSC_RIMU_ENTRIES] = { "ETR", "SDMMC1", "SDMMC2", "SDMMC3", "OTG_HS", "USBH", "ETH1", "ETH2", "RESERVED", "RESERVED", "DCMIPP", "LTDC_L1/L2", "LTDC_L3", "RESERVED", "RESERVED", "RESERVED", }; static const char *stm32mp25_rifsc_rimu_names[RIFSC_RIMU_ENTRIES] = { "ETR", "SDMMC1", "SDMMC2", "SDMMC3", "USB3DR", "USBH", "ETH1", "ETH2", "PCIE", "GPU", "DMCIPP", "LTDC_L0/L1", "LTDC_L2", "LTDC_ROT", "VDEC", "VENC" }; static const char *stm32mp21_rifsc_risup_names[RIFSC_RISUP_ENTRIES] = { "TIM1", "TIM2", "TIM3", "TIM4", "TIM5", "TIM6", "TIM7", "TIM8", "TIM10", "TIM11", "TIM12", "TIM13", "TIM14", "TIM15", "TIM16", "TIM17", "RESERVED", "LPTIM1", "LPTIM2", "LPTIM3", "LPTIM4", "LPTIM5", "SPI1", "SPI2", "SPI3", "SPI4", "SPI5", "SPI6", "RESERVED", "RESERVED", "SPDIFRX", "USART1", "USART2", "USART3", "UART4", "UART5", "USART6", "UART7", "RESERVED", "RESERVED", "LPUART1", "I2C1", "I2C2", "I2C3", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "SAI1", "SAI2", "SAI3", "SAI4", "RESERVED", "MDF1", "RESERVED", "FDCAN", "HDP", "ADC1", "ADC2", "ETH1", "ETH2", "RESERVED", "USBH", "RESERVED", "RESERVED", "OTG_HS", "DDRPERFM", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "STGEN", "OCTOSPI1", "RESERVED", "SDMMC1", "SDMMC2", "SDMMC3", "RESERVED", "LTDC_CMN", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "CSI", "DCMIPP", "DCMI_PSSI", "RESERVED", "RESERVED", "RESERVED", "RNG1", "RNG2", "PKA", "SAES", "HASH1", "HASH2", "CRYP1", "CRYP2", "IWDG1", "IWDG2", "IWDG3", "IWDG4", "WWDG1", "RESERVED", "VREFBUF", "DTS", "RAMCFG", "CRC", "SERC", "RESERVED", "RESERVED", "RESERVED", "I3C1", "I3C2", "I3C3", "RESERVED", "ICACHE_DCACHE", "LTDC_L1L2", "LTDC_L3", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "OTFDEC1", "RESERVED", "IAC", }; static const char *stm32mp25_rifsc_risup_names[RIFSC_RISUP_ENTRIES] = { "TIM1", "TIM2", "TIM3", "TIM4", "TIM5", "TIM6", "TIM7", "TIM8", "TIM10", "TIM11", "TIM12", "TIM13", "TIM14", "TIM15", "TIM16", "TIM17", "TIM20", "LPTIM1", "LPTIM2", "LPTIM3", "LPTIM4", "LPTIM5", "SPI1", "SPI2", "SPI3", "SPI4", "SPI5", "SPI6", "SPI7", "SPI8", "SPDIFRX", "USART1", "USART2", "USART3", "UART4", "UART5", "USART6", "UART7", "UART8", "UART9", "LPUART1", "I2C1", "I2C2", "I2C3", "I2C4", "I2C5", "I2C6", "I2C7", "I2C8", "SAI1", "SAI2", "SAI3", "SAI4", "RESERVED", "MDF1", "ADF1", "FDCAN", "HDP", "ADC12", "ADC3", "ETH1", "ETH2", "RESERVED", "USBH", "RESERVED", "RESERVED", "USB3DR", "COMBOPHY", "PCIE", "UCPD1", "ETHSW_DEIP", "ETHSW_ACM_CF", "ETHSW_ACM_MSGBU", "STGEN", "OCTOSPI1", "OCTOSPI2", "SDMMC1", "SDMMC2", "SDMMC3", "GPU", "LTDC_CMN", "DSI_CMN", "RESERVED", "RESERVED", "LVDS", "RESERVED", "CSI", "DCMIPP", "DCMI_PSSI", "VDEC", "VENC", "RESERVED", "RNG", "PKA", "SAES", "HASH", "CRYP1", "CRYP2", "IWDG1", "IWDG2", "IWDG3", "IWDG4", "IWDG5", "WWDG1", "WWDG2", "RESERVED", "VREFBUF", "DTS", "RAMCFG", "CRC", "SERC", "OCTOSPIM", "GICV2M", "RESERVED", "I3C1", "I3C2", "I3C3", "I3C4", "ICACHE_DCACHE", "LTDC_L0L1", "LTDC_L2", "LTDC_ROT", "DSI_TRIG", "DSI_RDFIFO", "RESERVED", "OTFDEC1", "OTFDEC2", "IAC", }; struct rifsc_risup_debug_data { char dev_name[15]; u8 dev_cid; u8 dev_sem_cids; u8 dev_id; bool dev_cid_filt_en; bool dev_sem_en; bool dev_priv; bool dev_sec; }; struct rifsc_rimu_debug_data { char m_name[11]; u8 m_cid; bool cidsel; bool m_sec; bool m_priv; }; struct rifsc_subreg_debug_data { bool sr_sec; bool sr_priv; u8 sr_cid; bool sr_rlock; bool sr_enable; u16 sr_start; u16 sr_length; }; struct stm32_rifsc_resources_names { const char **device_names; const char **initiator_names; }; struct rifsc_dbg_private { const struct stm32_rifsc_resources_names *res_names; void __iomem *mmio; unsigned int nb_risup; unsigned int nb_rimu; unsigned int nb_risal; }; static const struct stm32_rifsc_resources_names rifsc_mp21_res_names = { .device_names = stm32mp21_rifsc_risup_names, .initiator_names = stm32mp21_rifsc_rimu_names, }; static const struct stm32_rifsc_resources_names rifsc_mp25_res_names = { .device_names = stm32mp25_rifsc_risup_names, .initiator_names = stm32mp25_rifsc_rimu_names, }; static void stm32_rifsc_fill_rimu_dbg_entry(struct rifsc_dbg_private *rifsc, struct rifsc_rimu_debug_data *dbg_entry, int i) { const struct stm32_rifsc_resources_names *dbg_names = rifsc->res_names; u32 rimc_attr = readl_relaxed(rifsc->mmio + RIFSC_RIMC_ATTR0 + 0x4 * i); snprintf(dbg_entry->m_name, sizeof(dbg_entry->m_name), "%s", dbg_names->initiator_names[i]); dbg_entry->m_cid = FIELD_GET(RIFSC_RIMC_MCID_MASK, rimc_attr); dbg_entry->cidsel = rimc_attr & RIFSC_RIMC_CIDSEL; dbg_entry->m_sec = rimc_attr & RIFSC_RIMC_MSEC; dbg_entry->m_priv = rimc_attr & RIFSC_RIMC_MPRIV; } static void stm32_rifsc_fill_dev_dbg_entry(struct rifsc_dbg_private *rifsc, struct rifsc_risup_debug_data *dbg_entry, int i) { const struct stm32_rifsc_resources_names *dbg_names = rifsc->res_names; u32 cid_cfgr, sec_cfgr, priv_cfgr; u8 reg_id = i / IDS_PER_RISC_SEC_PRIV_REGS; u8 reg_offset = i % IDS_PER_RISC_SEC_PRIV_REGS; cid_cfgr = readl_relaxed(rifsc->mmio + RIFSC_RISC_PER0_CIDCFGR + 0x8 * i); sec_cfgr = readl_relaxed(rifsc->mmio + RIFSC_RISC_SECCFGR0 + 0x4 * reg_id); priv_cfgr = readl_relaxed(rifsc->mmio + RIFSC_RISC_PRIVCFGR0 + 0x4 * reg_id); snprintf(dbg_entry->dev_name, sizeof(dbg_entry->dev_name), "%s", dbg_names->device_names[i]); dbg_entry->dev_id = i; dbg_entry->dev_cid_filt_en = cid_cfgr & CIDCFGR_CFEN; dbg_entry->dev_sem_en = cid_cfgr & CIDCFGR_SEMEN; dbg_entry->dev_cid = FIELD_GET(RIFSC_RISC_SCID_MASK, cid_cfgr); dbg_entry->dev_sem_cids = FIELD_GET(RIFSC_RISC_SEMWL_MASK, cid_cfgr); dbg_entry->dev_sec = sec_cfgr & BIT(reg_offset) ? true : false; dbg_entry->dev_priv = priv_cfgr & BIT(reg_offset) ? true : false; } static void stm32_rifsc_fill_subreg_dbg_entry(struct rifsc_dbg_private *rifsc, struct rifsc_subreg_debug_data *dbg_entry, int i, int j) { u32 risc_xcfgr = readl_relaxed(rifsc->mmio + RIFSC_RISC_REG0_ACFGR + 0x10 * i + 0x8 * j); u32 risc_xaddr; dbg_entry->sr_sec = risc_xcfgr & RIFSC_RISC_SRSEC; dbg_entry->sr_priv = risc_xcfgr & RIFSC_RISC_SRPRIV; dbg_entry->sr_cid = FIELD_GET(RIFSC_RISC_SRCID_MASK, risc_xcfgr); dbg_entry->sr_rlock = risc_xcfgr & RIFSC_RISC_SRRLOCK; dbg_entry->sr_enable = risc_xcfgr & RIFSC_RISC_SREN; if (i == 2) { risc_xaddr = readl_relaxed(rifsc->mmio + RIFSC_RISC_REG3_AADDR + 0x8 * j); dbg_entry->sr_length = FIELD_GET(RIFSC_RISC_SRLENGTH_MASK, risc_xaddr); dbg_entry->sr_start = FIELD_GET(RIFSC_RISC_SRSTART_MASK, risc_xaddr); } else { dbg_entry->sr_start = 0; dbg_entry->sr_length = U16_MAX; } } static int stm32_rifsc_conf_dump_show(struct seq_file *s, void *data) { struct rifsc_dbg_private *rifsc = (struct rifsc_dbg_private *)s->private; int i, j; seq_puts(s, "\n=============================================\n"); seq_puts(s, " RIFSC dump\n"); seq_puts(s, "=============================================\n\n"); seq_puts(s, "\n=============================================\n"); seq_puts(s, " RISUP dump\n"); seq_puts(s, "=============================================\n"); seq_printf(s, "\n| %-15s |", "Peripheral name"); seq_puts(s, "| Firewall ID |"); seq_puts(s, "| N/SECURE |"); seq_puts(s, "| N/PRIVILEGED |"); seq_puts(s, "| CID filtering |"); seq_puts(s, "| Semaphore mode |"); seq_puts(s, "| SCID |"); seq_printf(s, "| %7s |\n", "SEMWL"); for (i = 0; i < RIFSC_RISUP_ENTRIES && i < rifsc->nb_risup; i++) { struct rifsc_risup_debug_data d_dbg_entry; stm32_rifsc_fill_dev_dbg_entry(rifsc, &d_dbg_entry, i); seq_printf(s, "| %-15s |", d_dbg_entry.dev_name); seq_printf(s, "| %-11d |", d_dbg_entry.dev_id); seq_printf(s, "| %-8s |", d_dbg_entry.dev_sec ? "SEC" : "NSEC"); seq_printf(s, "| %-12s |", d_dbg_entry.dev_priv ? "PRIV" : "NPRIV"); seq_printf(s, "| %-13s |", str_enabled_disabled(d_dbg_entry.dev_cid_filt_en)); seq_printf(s, "| %-14s |", str_enabled_disabled(d_dbg_entry.dev_sem_en)); seq_printf(s, "| %-4d |", d_dbg_entry.dev_cid); seq_printf(s, "| %#-7x |\n", d_dbg_entry.dev_sem_cids); } seq_puts(s, "\n=============================================\n"); seq_puts(s, " RIMU dump\n"); seq_puts(s, "=============================================\n"); seq_puts(s, "| RIMU's name |"); seq_puts(s, "| CIDSEL |"); seq_puts(s, "| MCID |"); seq_puts(s, "| N/SECURE |"); seq_puts(s, "| N/PRIVILEGED |\n"); for (i = 0; i < RIFSC_RIMU_ENTRIES && rifsc->nb_rimu; i++) { struct rifsc_rimu_debug_data m_dbg_entry; stm32_rifsc_fill_rimu_dbg_entry(rifsc, &m_dbg_entry, i); seq_printf(s, "| %-11s |", m_dbg_entry.m_name); seq_printf(s, "| %-6s |", m_dbg_entry.cidsel ? "CIDSEL" : ""); seq_printf(s, "| %-4d |", m_dbg_entry.m_cid); seq_printf(s, "| %-8s |", m_dbg_entry.m_sec ? "SEC" : "NSEC"); seq_printf(s, "| %-12s |\n", m_dbg_entry.m_priv ? "PRIV" : "NPRIV"); } if (rifsc->nb_risal > 0) { seq_puts(s, "\n=============================================\n"); seq_puts(s, " RISAL dump\n"); seq_puts(s, "=============================================\n"); seq_puts(s, "| Memory |"); seq_puts(s, "| Subreg. |"); seq_puts(s, "| N/SECURE |"); seq_puts(s, "| N/PRIVILEGED |"); seq_puts(s, "| Subreg. CID |"); seq_puts(s, "| Resource lock |"); seq_puts(s, "| Subreg. enable |"); seq_puts(s, "| Subreg. start |"); seq_puts(s, "| Subreg. end |\n"); for (i = 0; i < rifsc->nb_risal; i++) { for (j = 0; j < RIFSC_RISAL_SUBREGIONS; j++) { struct rifsc_subreg_debug_data sr_dbg_entry; stm32_rifsc_fill_subreg_dbg_entry(rifsc, &sr_dbg_entry, i, j); seq_printf(s, "| LPSRAM%1d |", i + 1); seq_printf(s, "| %1s |", (j == 0) ? "A" : "B"); seq_printf(s, "| %-8s |", sr_dbg_entry.sr_sec ? "SEC" : "NSEC"); seq_printf(s, "| %-12s |", sr_dbg_entry.sr_priv ? "PRIV" : "NPRIV"); seq_printf(s, "| 0x%-9x |", sr_dbg_entry.sr_cid); seq_printf(s, "| %-13s |", sr_dbg_entry.sr_rlock ? "locked (1)" : "unlocked (0)"); seq_printf(s, "| %-14s |", str_enabled_disabled(sr_dbg_entry.sr_enable)); seq_printf(s, "| 0x%-11x |", sr_dbg_entry.sr_start); seq_printf(s, "| 0x%-11x |\n", sr_dbg_entry.sr_start + sr_dbg_entry.sr_length - 1); } } } return 0; } DEFINE_SHOW_ATTRIBUTE(stm32_rifsc_conf_dump); static int stm32_rifsc_register_debugfs(struct stm32_firewall_controller *rifsc_controller, u32 nb_risup, u32 nb_rimu, u32 nb_risal) { struct rifsc_dbg_private *rifsc_priv; struct dentry *root = NULL; rifsc_priv = devm_kzalloc(rifsc_controller->dev, sizeof(*rifsc_priv), GFP_KERNEL); if (!rifsc_priv) return -ENOMEM; rifsc_priv->mmio = rifsc_controller->mmio; rifsc_priv->nb_risup = nb_risup; rifsc_priv->nb_rimu = nb_rimu; rifsc_priv->nb_risal = nb_risal; rifsc_priv->res_names = of_device_get_match_data(rifsc_controller->dev); root = debugfs_lookup("stm32_firewall", NULL); if (!root) root = debugfs_create_dir("stm32_firewall", NULL); if (IS_ERR(root)) return PTR_ERR(root); debugfs_create_file("rifsc", 0444, root, rifsc_priv, &stm32_rifsc_conf_dump_fops); return 0; } #endif /* defined(CONFIG_DEBUG_FS) */ static bool stm32_rifsc_is_semaphore_available(void __iomem *addr) { return !(readl(addr) & SEMCR_MUTEX); } static int stm32_rif_acquire_semaphore(struct stm32_firewall_controller *stm32_firewall_controller, int id) { void __iomem *addr = stm32_firewall_controller->mmio + RIFSC_RISC_PER0_SEMCR + 0x8 * id; writel(SEMCR_MUTEX, addr); /* Check that CID1 has the semaphore */ if (stm32_rifsc_is_semaphore_available(addr) || FIELD_GET(RIFSC_RISC_SCID_MASK, readl(addr)) != RIF_CID1) return -EACCES; return 0; } static void stm32_rif_release_semaphore(struct stm32_firewall_controller *stm32_firewall_controller, int id) { void __iomem *addr = stm32_firewall_controller->mmio + RIFSC_RISC_PER0_SEMCR + 0x8 * id; if (stm32_rifsc_is_semaphore_available(addr)) return; writel(SEMCR_MUTEX, addr); /* Ok if another compartment takes the semaphore before the check */ WARN_ON(!stm32_rifsc_is_semaphore_available(addr) && FIELD_GET(RIFSC_RISC_SCID_MASK, readl(addr)) == RIF_CID1); } static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32 firewall_id) { struct stm32_firewall_controller *rifsc_controller = ctrl; u32 reg_offset, reg_id, sec_reg_value, cid_reg_value; int rc; if (firewall_id >= rifsc_controller->max_entries) { dev_err(rifsc_controller->dev, "Invalid sys bus ID %u", firewall_id); return -EINVAL; } /* * RIFSC_RISC_PRIVCFGRx and RIFSC_RISC_SECCFGRx both handle configuration access for * 32 peripherals. On the other hand, there is one _RIFSC_RISC_PERx_CIDCFGR register * per peripheral */ reg_id = firewall_id / IDS_PER_RISC_SEC_PRIV_REGS; reg_offset = firewall_id % IDS_PER_RISC_SEC_PRIV_REGS; sec_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_SECCFGR0 + 0x4 * reg_id); cid_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_PER0_CIDCFGR + 0x8 * firewall_id); /* First check conditions for semaphore mode, which doesn't take into account static CID. */ if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) { if (cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT)) { /* Static CID is irrelevant if semaphore mode */ goto skip_cid_check; } else { dev_dbg(rifsc_controller->dev, "Invalid bus semaphore configuration: index %d\n", firewall_id); return -EACCES; } } /* * Skip CID check if CID filtering isn't enabled or filtering is enabled on CID0, which * corresponds to whatever CID. */ if (!(cid_reg_value & CIDCFGR_CFEN) || FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) == RIF_CID0) goto skip_cid_check; /* Coherency check with the CID configuration */ if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) { dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n", firewall_id); return -EACCES; } skip_cid_check: /* Check security configuration */ if (sec_reg_value & BIT(reg_offset)) { dev_dbg(rifsc_controller->dev, "Invalid security configuration for peripheral: %d\n", firewall_id); return -EACCES; } /* * If the peripheral is in semaphore mode, take the semaphore so that * the CID1 has the ownership. */ if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) { rc = stm32_rif_acquire_semaphore(rifsc_controller, firewall_id); if (rc) { dev_err(rifsc_controller->dev, "Couldn't acquire semaphore for peripheral: %d\n", firewall_id); return rc; } } return 0; } static void stm32_rifsc_release_access(struct stm32_firewall_controller *ctrl, u32 firewall_id) { stm32_rif_release_semaphore(ctrl, firewall_id); } static int stm32_rifsc_probe(struct platform_device *pdev) { struct stm32_firewall_controller *rifsc_controller; struct device_node *np = pdev->dev.of_node; u32 nb_risup, nb_rimu, nb_risal; struct resource *res; void __iomem *mmio; int rc; rifsc_controller = devm_kzalloc(&pdev->dev, sizeof(*rifsc_controller), GFP_KERNEL); if (!rifsc_controller) return -ENOMEM; mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(mmio)) return PTR_ERR(mmio); rifsc_controller->dev = &pdev->dev; rifsc_controller->mmio = mmio; rifsc_controller->name = dev_driver_string(rifsc_controller->dev); rifsc_controller->type = STM32_PERIPHERAL_FIREWALL | STM32_MEMORY_FIREWALL; rifsc_controller->grant_access = stm32_rifsc_grant_access; rifsc_controller->release_access = stm32_rifsc_release_access; /* Get number of RIFSC entries*/ nb_risup = FIELD_GET(HWCFGR2_CONF1_MASK, readl(rifsc_controller->mmio + RIFSC_RISC_HWCFGR2)); nb_rimu = FIELD_GET(HWCFGR2_CONF2_MASK, readl(rifsc_controller->mmio + RIFSC_RISC_HWCFGR2)); nb_risal = FIELD_GET(HWCFGR2_CONF3_MASK, readl(rifsc_controller->mmio + RIFSC_RISC_HWCFGR2)); /* * On STM32MP21, RIFSC_RISC_HWCFGR2 shows an incorrect number of RISAL (NUM_RISAL is 3 * instead of 0). A software workaround is implemented using the st,mem-map property in the * device tree. This property is absent or left empty if there is no RISAL. */ if (of_device_is_compatible(np, "st,stm32mp21-rifsc")) nb_risal = 0; rifsc_controller->max_entries = nb_risup + nb_rimu + nb_risal; platform_set_drvdata(pdev, rifsc_controller); rc = stm32_firewall_controller_register(rifsc_controller); if (rc) { dev_err(rifsc_controller->dev, "Couldn't register as a firewall controller: %d", rc); return rc; } rc = stm32_firewall_populate_bus(rifsc_controller); if (rc) { dev_err(rifsc_controller->dev, "Couldn't populate RIFSC bus: %d", rc); return rc; } #if defined(CONFIG_DEBUG_FS) rc = stm32_rifsc_register_debugfs(rifsc_controller, nb_risup, nb_rimu, nb_risal); if (rc) return dev_err_probe(rifsc_controller->dev, rc, "Failed creating debugfs entry\n"); #endif /* Populate all allowed nodes */ return of_platform_populate(np, NULL, NULL, &pdev->dev); } static const struct of_device_id stm32_rifsc_of_match[] = { { .compatible = "st,stm32mp25-rifsc", #if defined(CONFIG_DEBUG_FS) .data = &rifsc_mp25_res_names, #endif }, { .compatible = "st,stm32mp21-rifsc", #if defined(CONFIG_DEBUG_FS) .data = &rifsc_mp21_res_names, #endif }, {} }; MODULE_DEVICE_TABLE(of, stm32_rifsc_of_match); static struct platform_driver stm32_rifsc_driver = { .probe = stm32_rifsc_probe, .driver = { .name = "stm32-rifsc", .of_match_table = stm32_rifsc_of_match, }, }; module_platform_driver(stm32_rifsc_driver); MODULE_AUTHOR("Gatien Chevallier "); MODULE_DESCRIPTION("STMicroelectronics RIFSC driver"); MODULE_LICENSE("GPL");