feat(st-drivers): add RISAF driver

Introduction of Resource Isolation Slave for Address space - Full
(RISAF) driver to configure main memory regions with access rights
defined in device node in DT(through FCONF compliance) or statically.

The driver is enabled as BL2 sources. Add driver-related platform
services.
RISAF base addresses and key size are set in platform definitions.

Signed-off-by: Nicolas Le Bayon <nicolas.le.bayon@st.com>
Signed-off-by: Loic Pallardy <loic.pallardy@st.com>
Signed-off-by: Maxime Méré <maxime.mere@foss.st.com>
Change-Id: Iae99985e8db7cb2b27f9ca25669e74c8e08792d2
diff --git a/drivers/st/rif/stm32mp2_risaf.c b/drivers/st/rif/stm32mp2_risaf.c
new file mode 100644
index 0000000..84fe944
--- /dev/null
+++ b/drivers/st/rif/stm32mp2_risaf.c
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 2025, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp2_risaf.h>
+#include <dt-bindings/soc/rif.h>
+#include <lib/mmio.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+#include <stm32mp_fconf_getter.h>
+
+static struct stm32mp2_risaf_platdata stm32mp2_risaf;
+static int region_per_instance[RISAF_MAX_INSTANCE];
+
+#if ENABLE_ASSERTIONS
+static bool valid_protreg_id(int instance, uint32_t id)
+{
+	uint32_t max_id;
+
+	max_id = mmio_read_32(stm32mp2_risaf.base[instance] + _RISAF_HWCFGR);
+	max_id = (max_id & _RISAF_HWCFGR_CFG1_MASK) >> _RISAF_HWCFGR_CFG1_SHIFT;
+
+	return id < max_id;
+}
+
+static bool valid_instance(int instance)
+{
+	return (instance < RISAF_MAX_INSTANCE) && (stm32mp2_risaf.base[instance] != 0U);
+}
+#endif
+
+static bool risaf_is_hw_encryption_functional(int instance)
+{
+	return (mmio_read_32(stm32mp2_risaf.base[instance] + _RISAF_SR) & _RISAF_SR_ENCDIS) !=
+	       _RISAF_SR_ENCDIS;
+}
+
+static int check_region_boundaries(int instance, uintptr_t addr, size_t len)
+{
+	uintptr_t end_address;
+	uintptr_t mem_base = stm32_risaf_get_memory_base(instance);
+
+	if ((addr < mem_base) || (len == 0U)) {
+		return -EINVAL;
+	}
+
+	/* Get physical end address */
+	end_address = mem_base + stm32_risaf_get_memory_size(instance) - 1U;
+	if ((addr > end_address) || ((addr - 1U + len) > end_address)) {
+		return -EINVAL;
+	}
+
+	if ((stm32mp2_risaf.granularity[instance] == 0U) ||
+	    ((addr % stm32mp2_risaf.granularity[instance]) != 0U) ||
+	    ((len % stm32mp2_risaf.granularity[instance]) != 0U)) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static bool do_regions_overlap(uintptr_t addr1, size_t len1, uintptr_t addr2, size_t len2)
+{
+	return !((addr1 >= (addr2 + len2)) || (addr2 >= (addr1 + len1)));
+}
+
+static int check_region_overlap(void)
+{
+	struct stm32mp2_risaf_platdata *pdata = &stm32mp2_risaf;
+	int i;
+	uintptr_t addr;
+	size_t length;
+	int instance;
+	int region_id;
+
+	if (pdata->nregions <= 1) {
+		/*
+		 * No region found, or first region found.
+		 * No need to check overlap with previous ones.
+		 */
+		return 0;
+	}
+
+	region_id = pdata->nregions - 1;
+	addr = pdata->region[region_id].addr;
+	length = pdata->region[region_id].len;
+	instance = pdata->region[region_id].instance;
+
+	for (i = 0; i < region_id; i++) {
+		if (pdata->region[i].instance != instance) {
+			continue;
+		}
+
+		if (do_regions_overlap(addr, length,
+				       pdata->region[i].addr, pdata->region[i].len)) {
+			ERROR("RISAF%d: Regions %d and %d overlap\n", instance + 1, region_id, i);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int risaf_configure_region(int instance, uint32_t region_id, uint32_t cfg,
+				  uint32_t cid_cfg, uintptr_t saddr, uintptr_t eaddr)
+{
+	uintptr_t base = stm32mp2_risaf.base[instance];
+	uint32_t hwcfgr;
+	uint32_t mask_lsb;
+	uint32_t mask_msb;
+	uint32_t mask;
+
+	assert(valid_instance(instance));
+	assert(valid_protreg_id(instance, region_id));
+
+	mmio_clrbits_32(base + _RISAF_REG_CFGR(region_id), _RISAF_REG_CFGR_BREN);
+
+	/* Get address mask depending on RISAF instance HW configuration */
+	hwcfgr =  mmio_read_32(base + _RISAF_HWCFGR);
+	mask_lsb = (hwcfgr & _RISAF_HWCFGR_CFG3_MASK) >> _RISAF_HWCFGR_CFG3_SHIFT;
+	mask_msb = mask_lsb + ((hwcfgr & _RISAF_HWCFGR_CFG4_MASK) >> _RISAF_HWCFGR_CFG4_SHIFT) - 1U;
+	mask = GENMASK_32(mask_msb, mask_lsb);
+
+	mmio_clrsetbits_32(base + _RISAF_REG_STARTR(region_id), mask,
+			   (saddr - stm32_risaf_get_memory_base(instance)) & mask);
+	mmio_clrsetbits_32(base + _RISAF_REG_ENDR(region_id), mask,
+			   (eaddr - stm32_risaf_get_memory_base(instance)) & mask);
+
+	mmio_clrsetbits_32(base + _RISAF_REG_CIDCFGR(region_id), _RISAF_REG_CIDCFGR_ALL_MASK,
+			   cid_cfg & _RISAF_REG_CIDCFGR_ALL_MASK);
+
+	mmio_clrsetbits_32(base + _RISAF_REG_CFGR(region_id),
+			   _RISAF_REG_CFGR_ALL_MASK, cfg & _RISAF_REG_CFGR_ALL_MASK);
+
+	if ((cfg & _RISAF_REG_CFGR_ENC) == _RISAF_REG_CFGR_ENC) {
+		if (!risaf_is_hw_encryption_functional(instance)) {
+			ERROR("RISAF%d: encryption disabled\n", instance + 1);
+			return -EIO;
+		}
+
+		if ((cfg & _RISAF_REG_CFGR_SEC) != _RISAF_REG_CFGR_SEC) {
+			ERROR("RISAF%d: encryption on non secure area\n", instance + 1);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static void risaf_conf_protreg(void)
+{
+	struct stm32mp2_risaf_platdata *pdata = &stm32mp2_risaf;
+	int idx;
+
+	for (idx = 0; idx < RISAF_MAX_INSTANCE; idx++) {
+		int n;
+
+		if (pdata->base[idx] == 0) {
+			continue;
+		}
+
+		if (clk_enable(pdata->clock[idx]) != 0) {
+			ERROR("%s: RISAF@%lx clock failed\n", __func__, pdata->base[idx]);
+			panic();
+		}
+
+		for (n = 0; n < pdata->nregions; n++) {
+			uint32_t id;
+			uint32_t value;
+			uint32_t cfg;
+			uint32_t cid_cfg;
+			uintptr_t start_addr;
+			uintptr_t end_addr;
+
+			if (pdata->region[n].instance != idx) {
+				continue;
+			}
+
+			value = pdata->region[n].cfg;
+			id = (value & DT_RISAF_REG_ID_MASK);
+			assert(valid_protreg_id(idx, id));
+
+			cfg = (((value & DT_RISAF_EN_MASK) >> DT_RISAF_EN_SHIFT) <<
+			       _RISAF_REG_CFGR_BREN_SHIFT) |
+			      (((value & DT_RISAF_SEC_MASK) >> DT_RISAF_SEC_SHIFT) <<
+			       _RISAF_REG_CFGR_SEC_SHIFT) |
+			      (((value & DT_RISAF_ENC_MASK) >> DT_RISAF_ENC_SHIFT) <<
+			       _RISAF_REG_CFGR_ENC_SHIFT) |
+			      (((value & DT_RISAF_PRIV_MASK) >> DT_RISAF_PRIV_SHIFT) <<
+			       _RISAF_REG_CFGR_PRIVC_SHIFT);
+
+			cid_cfg = (((value & DT_RISAF_WRITE_MASK) >> DT_RISAF_WRITE_SHIFT) <<
+				   _RISAF_REG_CIDCFGR_WRENC_SHIFT) |
+				  (((value & DT_RISAF_READ_MASK) >> DT_RISAF_READ_SHIFT) <<
+				   _RISAF_REG_CIDCFGR_RDENC_SHIFT);
+
+			start_addr = pdata->region[n].addr;
+			end_addr = (start_addr - 1U) + pdata->region[n].len;
+
+			if (risaf_configure_region(idx, id, cfg, cid_cfg,
+						   start_addr, end_addr) < 0) {
+				ERROR("%s: failed to configure region %u of RISAF@%lx\n",
+				      __func__, id, pdata->base[idx]);
+				panic();
+			}
+		}
+
+		clk_disable(pdata->clock[idx]);
+	}
+}
+
+static int risaf_get_dt_node(struct dt_node_info *info, int offset)
+{
+	return dt_get_node(info, offset, DT_RISAF_COMPAT);
+}
+
+static int risaf_get_instance_from_region(uintptr_t address, size_t length)
+{
+	struct stm32mp2_risaf_platdata *pdata = &stm32mp2_risaf;
+	unsigned int idx;
+	int instance = -1;
+
+	for (idx = 0U; idx < RISAF_MAX_INSTANCE; idx++) {
+		if (pdata->base[idx] == 0U) {
+			continue;
+		}
+
+		if (check_region_boundaries(idx, address, length) == 0) {
+			instance = idx;
+		}
+	}
+
+	return instance;
+}
+
+/*
+ * Register region in platfoirm data structure if parameters are valid.
+ * If instance is known, related entry parameter is filled, else it is equal to -1.
+ */
+static int risaf_register_region(void *fdt, int node, int instance)
+{
+	struct stm32mp2_risaf_platdata *pdata = &stm32mp2_risaf;
+	const fdt32_t *cuint;
+	int len = 0;
+	int inst;
+	uintptr_t address;
+	size_t length;
+	uint32_t protreg;
+
+	/*  Get address and length */
+	cuint = fdt_getprop(fdt, node, "reg", &len);
+	if ((cuint == NULL) || (len != RISAF_REGION_REG_SIZE)) {
+		ERROR("RISAF: No or bad reg entry in DT\n");
+		return -EINVAL;
+	}
+
+	address = (uintptr_t)fdt32_to_cpu(cuint[0]) << 32;
+	address |= fdt32_to_cpu(cuint[1]);
+	length = (size_t)fdt32_to_cpu(cuint[2]) << 32;
+	length |= fdt32_to_cpu(cuint[3]);
+
+	/* Get instance */
+	inst = risaf_get_instance_from_region(address, length);
+	if (inst < 0) {
+		ERROR("RISAF: No instance found in DT\n");
+		return -EINVAL;
+	}
+
+	if ((instance != -1) && (inst != instance)) {
+		ERROR("RISAF%d: Region not located in expected address space\n", instance + 1);
+		return -EINVAL;
+	}
+
+	/* Get protreg configuration */
+	cuint = fdt_getprop(fdt, node, "st,protreg", &len);
+	if ((cuint == NULL) || (len != RISAF_REGION_PROTREG_SIZE)) {
+		ERROR("RISAF%d: No or bad st,protreg entry in DT\n", inst + 1);
+		return -EINVAL;
+	}
+
+	protreg = fdt32_to_cpu(*cuint);
+
+	/* Check if region max is reached for the current instance */
+	region_per_instance[inst]++;
+	if (region_per_instance[inst] > stm32_risaf_get_max_region(inst)) {
+		ERROR("RISAF%d: Too many entries in DT\n", inst + 1);
+		return -EINVAL;
+	}
+
+	if (check_region_boundaries(inst, address, length) != 0) {
+		ERROR("RISAF%d: Region %d exceeds limits\n", inst + 1, pdata->nregions);
+		return -EINVAL;
+	}
+
+	/* Register region configuration */
+	pdata->region[pdata->nregions].instance = inst;
+	pdata->region[pdata->nregions].cfg = protreg;
+	pdata->region[pdata->nregions].addr = address;
+	pdata->region[pdata->nregions].len = length;
+	pdata->nregions++;
+
+	if (check_region_overlap() != 0) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * From DT, retrieve base address, clock ID and all region information for each RISAF instance.
+ * Check boundaries for each region and overlap for each instance.
+ */
+static int risaf_parse_fdt(void)
+{
+	struct stm32mp2_risaf_platdata *pdata = &stm32mp2_risaf;
+	struct dt_node_info risaf_info;
+	int node = -1;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	for (node = risaf_get_dt_node(&risaf_info, node); node >= 0;
+	     node = risaf_get_dt_node(&risaf_info, node)) {
+		int idx;
+		int nregions;
+		int inst_maxregions;
+		int i;
+		int len = 0;
+		const fdt32_t *conf_list;
+		uint32_t granularity;
+
+		idx = stm32_risaf_get_instance(risaf_info.base);
+		if ((idx < 0) || (risaf_info.clock < 0)) {
+			continue;
+		}
+
+		pdata->base[idx] = risaf_info.base;
+		pdata->clock[idx] = (unsigned long)risaf_info.clock;
+
+		/* Get IP region granularity */
+		if (clk_enable(pdata->clock[idx]) != 0) {
+			ERROR("%s: clock enable failed.\n", __func__);
+			panic();
+		}
+
+		granularity = mmio_read_32(pdata->base[idx] + _RISAF_HWCFGR);
+		clk_disable(pdata->clock[idx]);
+		granularity = BIT_32((granularity & _RISAF_HWCFGR_CFG3_MASK) >>
+				  _RISAF_HWCFGR_CFG3_SHIFT);
+		pdata->granularity[idx] = granularity;
+
+		conf_list = fdt_getprop(fdt, node, "memory-region", &len);
+		if (conf_list == NULL) {
+			len = 0;
+		}
+
+		nregions = (unsigned int)len / sizeof(uint32_t);
+
+		inst_maxregions = stm32_risaf_get_max_region(idx);
+		if (inst_maxregions <= 0) {
+			continue;
+		}
+
+		if ((nregions > inst_maxregions) ||
+		    ((pdata->nregions + nregions) > RISAF_MAX_REGION)) {
+			ERROR("RISAF%d: Too many entries in DT\n", idx + 1);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < nregions; i++) {
+			int pnode = 0;
+
+			pnode = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(conf_list[i]));
+			if (pnode < 0) {
+				continue;
+			}
+
+			if (risaf_register_region(fdt, pnode, idx) != 0) {
+				ERROR("RISAF%d: Region %d error\n", idx + 1, pdata->nregions);
+				return -EINVAL;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static uintptr_t risaf_base[RISAF_MAX_INSTANCE];
+static unsigned long risaf_clock[RISAF_MAX_INSTANCE];
+static uint32_t risaf_granularity[RISAF_MAX_INSTANCE];
+static struct stm32mp2_risaf_region risaf_region[RISAF_MAX_REGION];
+
+/* Construct platform data structure */
+static int risaf_get_platdata(struct stm32mp2_risaf_platdata *pdata)
+{
+	pdata->base = risaf_base;
+	pdata->clock = risaf_clock;
+	pdata->granularity = risaf_granularity;
+	pdata->region = risaf_region;
+
+	return 0;
+}
+
+/*
+ * @brief  Write the encryption key for a given instance.
+ * @param  instance: RISAF instance ID.
+ *         key: Pointer to the encryption key buffer.
+ * @retval 0 if OK, negative value else.
+ */
+int stm32mp2_risaf_write_encryption_key(int instance, uint8_t *key)
+{
+	uint64_t timeout_ref;
+	uint32_t i;
+	uintptr_t base = stm32mp2_risaf.base[instance];
+
+	if (base == 0U) {
+		return -EINVAL;
+	}
+
+	if (key == NULL) {
+		return -EINVAL;
+	}
+
+	for (i = 0U; i < RISAF_ENCRYPTION_KEY_SIZE_IN_BYTES; i += sizeof(uint32_t)) {
+		uint32_t key_val = 0U;
+
+		memcpy(&key_val, key + i, sizeof(uint32_t));
+
+		mmio_write_32(base + _RISAF_KEYR + i, key_val);
+	}
+
+	timeout_ref = timeout_init_us(RISAF_TIMEOUT_1MS_IN_US);
+
+	while (((mmio_read_32(base + _RISAF_SR) & _RISAF_SR_KEYVALID) != _RISAF_SR_KEYVALID) ||
+	       ((mmio_read_32(base + _RISAF_SR) & _RISAF_SR_KEYRDY) != _RISAF_SR_KEYRDY)) {
+		if (timeout_elapsed(timeout_ref)) {
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * @brief  Lock the RISAF IP registers for a given instance.
+ * @param  instance: RISAF instance ID.
+ * @retval 0 if OK, negative value else.
+ */
+int stm32mp2_risaf_lock(int instance)
+{
+	uintptr_t base = stm32mp2_risaf.base[instance];
+
+	if (base == 0U) {
+		return -EINVAL;
+	}
+
+	mmio_setbits_32(base + _RISAF_CR, _RISAF_CR_GLOCK);
+
+	return 0;
+}
+
+/*
+ * @brief  Get the RISAF lock state for a given instance.
+ * @param  instance: RISAF instance ID.
+ *         state: lock state, true if locked, false else.
+ * @retval 0 if OK, negative value else.
+ */
+int stm32mp2_risaf_is_locked(int instance, bool *state)
+{
+	uintptr_t base = stm32mp2_risaf.base[instance];
+
+	if (base == 0U) {
+		return -EINVAL;
+	}
+
+	*state = (mmio_read_32(base + _RISAF_CR) & _RISAF_CR_GLOCK) == _RISAF_CR_GLOCK;
+
+	return 0;
+}
+
+int stm32mp2_risaf_init(void)
+{
+	int err;
+
+	err = risaf_get_platdata(&stm32mp2_risaf);
+	if (err != 0) {
+		return err;
+	}
+
+	err = risaf_parse_fdt();
+	if (err != 0) {
+		return err;
+	}
+
+	risaf_conf_protreg();
+
+	return err;
+}
+
+static int risaf_parse_fwconfig(uintptr_t config)
+{
+	struct stm32mp2_risaf_platdata *pdata = &stm32mp2_risaf;
+	unsigned int i;
+	int node = -1;
+	int subnode;
+	const void *fdt = (const void *)config;
+	const char *compatible_str = "st,stm32mp2-mem-firewall";
+
+	node = fdt_node_offset_by_compatible(fdt, -1, compatible_str);
+	if (node < 0) {
+		ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str);
+		return node;
+	}
+
+	fdt_for_each_subnode(subnode, fdt, node) {
+		if (risaf_register_region((void *)fdt, subnode, -1) != 0) {
+			ERROR("RISAF: Region %d error\n", pdata->nregions);
+			return -EINVAL;
+		}
+	}
+
+	for (i = 0U; i < RISAF_MAX_INSTANCE; i++) {
+		if ((region_per_instance[i] == 0) && (stm32_risaf_get_max_region(i) != 0)) {
+			INFO("RISAF%u: No configuration in DT, use default\n", i + 1);
+		}
+	}
+
+	return 0;
+}
+
+static int fconf_populate_risaf(uintptr_t config)
+{
+	int err;
+
+	err = risaf_parse_fwconfig(config);
+	if (err != 0) {
+		return err;
+	}
+
+	risaf_conf_protreg();
+
+	return err;
+}
+
+FCONF_REGISTER_POPULATOR(FW_CONFIG, risaf_config, fconf_populate_risaf);
diff --git a/include/drivers/st/stm32mp2_risaf.h b/include/drivers/st/stm32mp2_risaf.h
new file mode 100644
index 0000000..a8a62b5
--- /dev/null
+++ b/include/drivers/st/stm32mp2_risaf.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2025, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP2_RISAF_H
+#define STM32MP2_RISAF_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/* RISAF general registers (base relative) */
+#define _RISAF_CR			U(0x00)
+#define _RISAF_SR			U(0x04)
+#define _RISAF_KEYR			U(0x30)
+#define _RISAF_HWCFGR			U(0xFF0)
+
+/* RISAF general register field description */
+/* _RISAF_CR register fields */
+#define _RISAF_CR_GLOCK			BIT_32(0)
+/* _RISAF_SR register fields */
+#define _RISAF_SR_KEYVALID		BIT_32(0)
+#define _RISAF_SR_KEYRDY		BIT_32(1)
+#define _RISAF_SR_ENCDIS		BIT_32(2)
+/* _RISAF_HWCFGR register fields */
+#define _RISAF_HWCFGR_CFG1_SHIFT	0
+#define _RISAF_HWCFGR_CFG1_MASK		GENMASK_32(7, 0)
+#define _RISAF_HWCFGR_CFG2_SHIFT	8
+#define _RISAF_HWCFGR_CFG2_MASK		GENMASK_32(15, 8)
+#define _RISAF_HWCFGR_CFG3_SHIFT	16
+#define _RISAF_HWCFGR_CFG3_MASK		GENMASK_32(23, 16)
+#define _RISAF_HWCFGR_CFG4_SHIFT	24
+#define _RISAF_HWCFGR_CFG4_MASK		GENMASK_32(31, 24)
+
+/* RISAF region registers (base relative) */
+#define _RISAF_REG_BASE			U(0x40)
+#define _RISAF_REG_SIZE			U(0x40)
+#define _RISAF_REG(n)			(_RISAF_REG_BASE + (((n) - 1) * _RISAF_REG_SIZE))
+#define _RISAF_REG_CFGR_OFFSET		U(0x0)
+#define _RISAF_REG_CFGR(n)		(_RISAF_REG(n) + _RISAF_REG_CFGR_OFFSET)
+#define _RISAF_REG_STARTR_OFFSET	U(0x4)
+#define _RISAF_REG_STARTR(n)		(_RISAF_REG(n) + _RISAF_REG_STARTR_OFFSET)
+#define _RISAF_REG_ENDR_OFFSET		U(0x8)
+#define _RISAF_REG_ENDR(n)		(_RISAF_REG(n) + _RISAF_REG_ENDR_OFFSET)
+#define _RISAF_REG_CIDCFGR_OFFSET	U(0xC)
+#define _RISAF_REG_CIDCFGR(n)		(_RISAF_REG(n) + _RISAF_REG_CIDCFGR_OFFSET)
+
+/* RISAF region register field description */
+/* _RISAF_REG_CFGR(n) register fields */
+#define _RISAF_REG_CFGR_BREN_SHIFT	0
+#define _RISAF_REG_CFGR_BREN		BIT_32(_RISAF_REG_CFGR_BREN_SHIFT)
+#define _RISAF_REG_CFGR_SEC_SHIFT	8
+#define _RISAF_REG_CFGR_SEC		BIT_32(_RISAF_REG_CFGR_SEC_SHIFT)
+#define _RISAF_REG_CFGR_ENC_SHIFT	15
+#define _RISAF_REG_CFGR_ENC		BIT_32(_RISAF_REG_CFGR_ENC_SHIFT)
+#define _RISAF_REG_CFGR_PRIVC_SHIFT	16
+#define _RISAF_REG_CFGR_PRIVC_MASK	GENMASK_32(23, 16)
+#define _RISAF_REG_CFGR_ALL_MASK	(_RISAF_REG_CFGR_BREN | _RISAF_REG_CFGR_SEC | \
+					 _RISAF_REG_CFGR_ENC | _RISAF_REG_CFGR_PRIVC_MASK)
+/* _RISAF_REG_CIDCFGR(n) register fields */
+#define _RISAF_REG_CIDCFGR_RDENC_SHIFT		0
+#define _RISAF_REG_CIDCFGR_RDENC_MASK		GENMASK_32(7, 0)
+#define _RISAF_REG_CIDCFGR_WRENC_SHIFT		16
+#define _RISAF_REG_CIDCFGR_WRENC_MASK		GENMASK_32(23, 16)
+#define _RISAF_REG_CIDCFGR_ALL_MASK		(_RISAF_REG_CIDCFGR_RDENC_MASK | \
+						 _RISAF_REG_CIDCFGR_WRENC_MASK)
+
+/* Device Tree related definitions */
+#define DT_RISAF_COMPAT			"st,stm32-risaf"
+#define DT_RISAF_REG_ID_MASK		U(0xF)
+#define DT_RISAF_EN_SHIFT		5
+#define DT_RISAF_EN_MASK		BIT_32(DT_RISAF_EN_SHIFT)
+#define DT_RISAF_SEC_SHIFT		6
+#define DT_RISAF_SEC_MASK		BIT_32(DT_RISAF_SEC_SHIFT)
+#define DT_RISAF_ENC_SHIFT		7
+#define DT_RISAF_ENC_MASK		BIT_32(DT_RISAF_ENC_SHIFT)
+#define DT_RISAF_PRIV_SHIFT		8
+#define DT_RISAF_PRIV_MASK		GENMASK_32(15, 8)
+#define DT_RISAF_READ_SHIFT		16
+#define DT_RISAF_READ_MASK		GENMASK_32(23, 16)
+#define DT_RISAF_WRITE_SHIFT		24
+#define DT_RISAF_WRITE_MASK		GENMASK_32(31, 24)
+
+/* RISAF max properties */
+#define RISAF_REGION_REG_SIZE		(4 * sizeof(uint32_t))
+#define RISAF_REGION_PROTREG_SIZE	(1 * sizeof(uint32_t))
+#define RISAF_TIMEOUT_1MS_IN_US		U(1000)
+
+/* RISAF encryption key size in bytes */
+#define RISAF_ENCRYPTION_KEY_SIZE_IN_BYTES	U(16)
+
+struct stm32mp2_risaf_region {
+	int instance;
+	uint32_t cfg;
+	uintptr_t addr;
+	size_t len;
+};
+
+struct stm32mp2_risaf_platdata {
+	uintptr_t *base;
+	unsigned long *clock;
+	uint32_t *granularity;
+	struct stm32mp2_risaf_region *region;
+	int nregions;
+};
+
+int stm32mp2_risaf_write_encryption_key(int instance, uint8_t *key);
+int stm32mp2_risaf_lock(int instance);
+int stm32mp2_risaf_is_locked(int instance, bool *state);
+int stm32mp2_risaf_init(void);
+
+#endif /* STM32MP2_RISAF_H */
diff --git a/plat/st/stm32mp2/bl2_plat_setup.c b/plat/st/stm32mp2/bl2_plat_setup.c
index 1d49fe7..3b94989 100644
--- a/plat/st/stm32mp2/bl2_plat_setup.c
+++ b/plat/st/stm32mp2/bl2_plat_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023-2024, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2023-2025, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -94,6 +94,10 @@
 		panic();
 	}
 
+	if (stm32mp2_risaf_init() < 0) {
+		panic();
+	}
+
 	/* Map DDR for binary load, now with cacheable attribute */
 	ret = mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE,
 				      STM32MP_DDR_MAX_SIZE, MT_MEMORY | MT_RW | MT_SECURE);
diff --git a/plat/st/stm32mp2/include/stm32mp2_private.h b/plat/st/stm32mp2/include/stm32mp2_private.h
index 4bb8c52..fda2276 100644
--- a/plat/st/stm32mp2/include/stm32mp2_private.h
+++ b/plat/st/stm32mp2/include/stm32mp2_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2024-2025, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,6 +11,21 @@
 
 uint32_t stm32mp_syscfg_get_chip_dev_id(void);
 
+/* Get RISAF platform instance ID from peripheral IO memory base address */
+int stm32_risaf_get_instance(uintptr_t base);
+
+/* Get RISAF peripheral IO memory base address from platform instance ID */
+uintptr_t stm32_risaf_get_base(int instance);
+
+/* Get RISAF maximum number of regions from platform instance ID */
+int stm32_risaf_get_max_region(int instance);
+
+/* Get RISAF memory base address from platform instance ID */
+uintptr_t stm32_risaf_get_memory_base(int instance);
+
+/* Get RISAF memory size in bytes from platform instance ID */
+size_t stm32_risaf_get_memory_size(int instance);
+
 /* Get DDRDBG peripheral IO memory base address */
 uintptr_t stm32_ddrdbg_get_base(void);
 
diff --git a/plat/st/stm32mp2/platform.mk b/plat/st/stm32mp2/platform.mk
index a7cd991..5d6b0d3 100644
--- a/plat/st/stm32mp2/platform.mk
+++ b/plat/st/stm32mp2/platform.mk
@@ -215,6 +215,8 @@
 
 BL2_SOURCES			+=	drivers/st/crypto/stm32_hash.c
 
+BL2_SOURCES			+=	drivers/st/rif/stm32mp2_risaf.c
+
 ifneq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC}),)
 BL2_SOURCES			+=	drivers/st/mmc/stm32_sdmmc2.c
 endif
diff --git a/plat/st/stm32mp2/stm32mp2_def.h b/plat/st/stm32mp2/stm32mp2_def.h
index 27fc5f9..e978b77 100644
--- a/plat/st/stm32mp2/stm32mp2_def.h
+++ b/plat/st/stm32mp2/stm32mp2_def.h
@@ -11,6 +11,7 @@
 #ifndef __ASSEMBLER__
 #include <drivers/st/bsec.h>
 #include <drivers/st/stm32mp2_clk.h>
+#include <drivers/st/stm32mp2_risaf.h>
 #endif
 #if STM32MP21
 #include <drivers/st/stm32mp21_pwr.h>
@@ -35,6 +36,7 @@
 #include <dt-bindings/reset/stm32mp25-resets.h>
 #endif /* STM32MP25 */
 #include <dt-bindings/gpio/stm32-gpio.h>
+#include <dt-bindings/soc/rif.h>
 
 #ifndef __ASSEMBLER__
 #include <boot_api.h>
@@ -276,6 +278,13 @@
 #define STM32MP_SDMMC3_BASE			U(0x48240000)
 
 /*******************************************************************************
+ * STM32MP2 OSPI
+ ******************************************************************************/
+/* OSPI 1 & 2 memory map area */
+#define STM32MP_OSPI_MM_BASE			U(0x60000000)
+#define STM32MP_OSPI_MM_SIZE			U(0x10000000)
+
+/*******************************************************************************
  * STM32MP2 BSEC / OTP
  ******************************************************************************/
 /*
@@ -413,9 +422,52 @@
 /*******************************************************************************
  * STM32MP RIF
  ******************************************************************************/
+#define RISAB1_BASE				U(0x420F0000)
+#define RISAB2_BASE				U(0x42100000)
 #define RISAB3_BASE				U(0x42110000)
 #define RISAB5_BASE				U(0x42130000)
 
+#define RISAF1_INST				0
+#define RISAF2_INST				1
+#define RISAF4_INST				3
+#define RISAF5_INST				4
+#define RISAF_MAX_INSTANCE			5
+
+#define RISAF1_BASE				U(0x420A0000)
+#define RISAF2_BASE				U(0x420B0000)
+#define RISAF4_BASE				U(0x420D0000)
+#define RISAF5_BASE				U(0x420E0000)
+
+#define USE_RISAF2
+#define USE_RISAF4
+
+#ifdef USE_RISAF1
+#define RISAF1_MAX_REGION			4
+#else
+#define RISAF1_MAX_REGION			0
+#endif
+#ifdef USE_RISAF2
+#define RISAF2_MAX_REGION			4
+#else
+#define RISAF2_MAX_REGION			0
+#endif
+#ifdef USE_RISAF4
+/* Consider only encrypted region maximum number, to save memory consumption */
+#define RISAF4_MAX_REGION			4
+#else
+#define RISAF4_MAX_REGION			0
+#endif
+#ifdef USE_RISAF5
+#define RISAF5_MAX_REGION			2
+#else
+#define RISAF5_MAX_REGION			0
+#endif
+#define RISAF_MAX_REGION			(RISAF1_MAX_REGION + RISAF2_MAX_REGION + \
+						 RISAF4_MAX_REGION + RISAF5_MAX_REGION)
+
+#define RISAF_KEY_SIZE_IN_BYTES			RISAF_ENCRYPTION_KEY_SIZE_IN_BYTES
+#define RISAF_SEED_SIZE_IN_BYTES		U(4)
+
 /*******************************************************************************
  * STM32MP CA35SSC
  ******************************************************************************/
diff --git a/plat/st/stm32mp2/stm32mp2_private.c b/plat/st/stm32mp2/stm32mp2_private.c
index ea9d2fc..2070cea 100644
--- a/plat/st/stm32mp2/stm32mp2_private.c
+++ b/plat/st/stm32mp2/stm32mp2_private.c
@@ -1,10 +1,11 @@
 /*
- * Copyright (c) 2023-2024, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2023-2025, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <assert.h>
+#include <errno.h>
 
 #include <lib/xlat_tables/xlat_tables_v2.h>
 
@@ -324,6 +325,66 @@
 	return false;
 }
 
+int stm32_risaf_get_instance(uintptr_t base)
+{
+	switch (base) {
+	case RISAF2_BASE:
+		return (int)RISAF2_INST;
+	case RISAF4_BASE:
+		return (int)RISAF4_INST;
+	default:
+		return -ENODEV;
+	}
+}
+
+uintptr_t stm32_risaf_get_base(int instance)
+{
+	switch (instance) {
+	case RISAF2_INST:
+		return (uintptr_t)RISAF2_BASE;
+	case RISAF4_INST:
+		return (uintptr_t)RISAF4_BASE;
+	default:
+		return 0U;
+	}
+}
+
+int stm32_risaf_get_max_region(int instance)
+{
+	switch (instance) {
+	case RISAF2_INST:
+		return (int)RISAF2_MAX_REGION;
+	case RISAF4_INST:
+		return (int)RISAF4_MAX_REGION;
+	default:
+		return 0;
+	}
+}
+
+uintptr_t stm32_risaf_get_memory_base(int instance)
+{
+	switch (instance) {
+	case RISAF2_INST:
+		return (uintptr_t)STM32MP_OSPI_MM_BASE;
+	case RISAF4_INST:
+		return (uintptr_t)STM32MP_DDR_BASE;
+	default:
+		return 0U;
+	}
+}
+
+size_t stm32_risaf_get_memory_size(int instance)
+{
+	switch (instance) {
+	case RISAF2_INST:
+		return STM32MP_OSPI_MM_SIZE;
+	case RISAF4_INST:
+		return dt_get_ddr_size();
+	default:
+		return 0U;
+	}
+}
+
 uintptr_t stm32_get_bkpr_boot_mode_addr(void)
 {
 	return tamp_bkpr(BKPR_BOOT_MODE);