[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260209-stm32_risab-v1-2-ef0b2b6a7e0a@foss.st.com>
Date: Mon, 9 Feb 2026 15:59:32 +0100
From: Gatien Chevallier <gatien.chevallier@...s.st.com>
To: Rob Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>, Maxime Coquelin
<mcoquelin.stm32@...il.com>, Alexandre Torgue <alexandre.torgue@...s.st.com>
CC: <devicetree@...r.kernel.org>, <linux-stm32@...md-mailman.stormreply.com>,
<linux-arm-kernel@...ts.infradead.org>, <linux-kernel@...r.kernel.org>,
Gatien Chevallier <gatien.chevallier@...s.st.com>, Theo GOUREAU
<theo.goureau-ext@...com>
Subject: [PATCH 2/7] soc: st: add RISAB dump debug driver
This driver creates an entry in the debugfs to dump RISAB memory
regions configurations.
Signed-off-by: Theo GOUREAU <theo.goureau-ext@...com>
Signed-off-by: Gatien Chevallier <gatien.chevallier@...s.st.com>
---
MAINTAINERS | 1 +
drivers/soc/Kconfig | 1 +
drivers/soc/Makefile | 1 +
drivers/soc/st/Kconfig | 11 ++
drivers/soc/st/Makefile | 1 +
drivers/soc/st/stm32_risab.c | 329 +++++++++++++++++++++++++++++++++++++++++++
6 files changed, 344 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index b9a1276e94a9..64a5b894c6b8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25096,6 +25096,7 @@ STM32 SoC FIREWALL DRIVERS
M: Gatien Chevallier <gatien.chevallier@...s.st.com>
S: Maintained
F: Documentation/devicetree/bindings/soc/st/*risa*
+F: drivers/soc/st/*risa*
STM32 TIMER/LPTIMER DRIVERS
M: Fabrice Gasnier <fabrice.gasnier@...s.st.com>
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index a2d65adffb80..dfe5cec59262 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -24,6 +24,7 @@ source "drivers/soc/renesas/Kconfig"
source "drivers/soc/rockchip/Kconfig"
source "drivers/soc/samsung/Kconfig"
source "drivers/soc/sophgo/Kconfig"
+source "drivers/soc/st/Kconfig"
source "drivers/soc/sunxi/Kconfig"
source "drivers/soc/tegra/Kconfig"
source "drivers/soc/ti/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index c9e689080ceb..894bd6ebaaa4 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -30,6 +30,7 @@ obj-y += renesas/
obj-y += rockchip/
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
obj-y += sophgo/
+obj-y += st/
obj-y += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += ti/
diff --git a/drivers/soc/st/Kconfig b/drivers/soc/st/Kconfig
new file mode 100644
index 000000000000..6c293af58f2a
--- /dev/null
+++ b/drivers/soc/st/Kconfig
@@ -0,0 +1,11 @@
+if ARCH_STM32 || COMPILE_TEST
+
+config STM32_RISAB
+ tristate "STM32 RISAB"
+ depends on (ARM64 || COMPILE_TEST) && DEBUG_FS
+ default y
+ help
+ Say y to enable RISAB dump debug helper driver. This creates an entry
+ in the debugfs to dump RISAB pages and blocks RIF configurations.
+
+endif # ARCH_STM32 || COMPILE_TEST
diff --git a/drivers/soc/st/Makefile b/drivers/soc/st/Makefile
new file mode 100644
index 000000000000..6b53f3eda801
--- /dev/null
+++ b/drivers/soc/st/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_STM32_RISAB) += stm32_risab.o
diff --git a/drivers/soc/st/stm32_risab.c b/drivers/soc/st/stm32_risab.c
new file mode 100644
index 000000000000..f1f0300817e2
--- /dev/null
+++ b/drivers/soc/st/stm32_risab.c
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026, STMicroelectronics - All Rights Reserved
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+/*
+ * RISAB constants
+ */
+#define RISAB_NUMBER_OF_PAGES_MAX 32
+#define RISAB_BLOCKS_PER_PAGES 8
+#define RISAB_NUMBER_OF_CID 7
+#define RISAB_PAGE_SIZE 0x1000
+
+/*
+ * RISAB configuration register
+ */
+#define RISAB_CR 0x000
+#define RISAB_CR_SRWIAD BIT(31)
+#define RISAB_CR_GLOCK BIT(0)
+
+/*
+ * RISAB configuration lock register
+ */
+#define RISAB_RCFGLOCKR 0x010
+
+/*
+ * RISAB page y=0..31 security and privileged configuration registers
+ */
+#define RISAB_PG_SECCFGR(y) (0x100 + 0x4 * (y))
+#define RISAB_PG_PRIVCFGR(y) (0x200 + 0x4 * (y))
+#define RISAB_PG_C2PRIVCFGR(y) (0x600 + 0x4 * (y))
+
+/*
+ * RISAB compartment x=0..6 privilege, read and write configuration registers
+ */
+#define RISAB_CIDPRIVCFGR(x) (0x800 + 0x20 * (x))
+#define RISAB_CIDRDCFGR(x) (0x808 + 0x20 * (x))
+#define RISAB_CIDWRCFGR(x) (0x810 + 0x20 * (x))
+
+/*
+ * RISAB page y=0..31 CID configuration registers
+ */
+#define RISAB_PG_CIDCFGR(y) (0xA00 + 0x4 * (y))
+#define RISAB_PG_CIDCFGR_DCCID_MASK GENMASK(6, 4)
+#define RISAB_PG_CIDCFGR_DCEN BIT(2)
+#define RISAB_PG_CIDCFGR_CFEN BIT(0)
+
+/*
+ * RISAB hardware configuration registers
+ */
+#define RISAB_HWCFGR1 0xFF0
+#define RISAB_HWCFGR1_LOG_NUM_PAGE_MASK GENMASK(27, 24)
+#define RISAB_HWCFGR1_LOG_NUM_PAGE_SHIFT 24
+
+struct risab_debug_data {
+ bool sec[RISAB_BLOCKS_PER_PAGES];
+ bool priv[RISAB_BLOCKS_PER_PAGES];
+ bool c2priv[RISAB_BLOCKS_PER_PAGES];
+ u8 dccid;
+ bool dcen;
+ bool cfen;
+};
+
+struct risab_generic_debug_data {
+ bool srwiad;
+ bool glock;
+ bool rlock[RISAB_NUMBER_OF_PAGES_MAX];
+ bool ppriv[RISAB_NUMBER_OF_CID][RISAB_NUMBER_OF_PAGES_MAX];
+ bool prden[RISAB_NUMBER_OF_CID][RISAB_NUMBER_OF_PAGES_MAX];
+ bool pwren[RISAB_NUMBER_OF_CID][RISAB_NUMBER_OF_PAGES_MAX];
+};
+
+struct risab_pdata {
+ void __iomem *base;
+ struct device *dev;
+ struct dentry *dbg_entry;
+ u32 risab_map_base;
+ struct clk *clk;
+ u32 nb_pages;
+};
+
+static void stm32_risab_fill_dev_dbg_entry(struct risab_pdata *pdata,
+ struct risab_debug_data *dbg_entry, int page)
+{
+ u32 risab_pg_c2privcfgr = readl_relaxed(pdata->base + RISAB_PG_C2PRIVCFGR(page));
+ u32 risab_pg_privcfgr = readl_relaxed(pdata->base + RISAB_PG_PRIVCFGR(page));
+ u32 risab_pg_seccfgr = readl_relaxed(pdata->base + RISAB_PG_SECCFGR(page));
+ u32 risab_pg_cidcfgr = readl_relaxed(pdata->base + RISAB_PG_CIDCFGR(page));
+ int block;
+
+ for (block = 0; block < RISAB_BLOCKS_PER_PAGES; block++) {
+ dbg_entry->sec[block] = risab_pg_seccfgr & BIT(block);
+ dbg_entry->priv[block] = risab_pg_privcfgr & BIT(block);
+ dbg_entry->c2priv[block] = risab_pg_c2privcfgr & BIT(block);
+ }
+
+ dbg_entry->dccid = FIELD_GET(RISAB_PG_CIDCFGR_DCCID_MASK, risab_pg_cidcfgr);
+ dbg_entry->dcen = risab_pg_cidcfgr & RISAB_PG_CIDCFGR_DCEN;
+ dbg_entry->cfen = risab_pg_cidcfgr & RISAB_PG_CIDCFGR_CFEN;
+}
+
+static void stm32_risab_fill_dev_generic_dbg_entry(struct risab_pdata *pdata,
+ struct risab_generic_debug_data *dbg_entry)
+{
+ u32 risab_rcfglockr = readl_relaxed(pdata->base + RISAB_RCFGLOCKR);
+ u32 risab_cr = readl_relaxed(pdata->base + RISAB_CR);
+ int page, compartment;
+
+ dbg_entry->srwiad = risab_cr & RISAB_CR_SRWIAD;
+ dbg_entry->glock = risab_cr & RISAB_CR_GLOCK;
+
+ for (page = 0; page < pdata->nb_pages; page++)
+ dbg_entry->rlock[page] = risab_rcfglockr & BIT(page);
+
+ for (compartment = 0; compartment < RISAB_NUMBER_OF_CID; compartment++) {
+ u32 risab_cidprivcfgr = readl_relaxed(pdata->base + RISAB_CIDPRIVCFGR(compartment));
+ u32 risab_cidrdcfgr = readl_relaxed(pdata->base + RISAB_CIDRDCFGR(compartment));
+ u32 risab_cidwrcfgr = readl_relaxed(pdata->base + RISAB_CIDWRCFGR(compartment));
+
+ for (page = 0; page < pdata->nb_pages; page++) {
+ dbg_entry->ppriv[compartment][page] = risab_cidprivcfgr & BIT(page);
+ dbg_entry->prden[compartment][page] = risab_cidrdcfgr & BIT(page);
+ dbg_entry->pwren[compartment][page] = risab_cidwrcfgr & BIT(page);
+ }
+ }
+}
+
+static int stm32_risab_conf_dump_show(struct seq_file *s, void *data)
+{
+ struct risab_pdata *pdata = (struct risab_pdata *)s->private;
+ struct risab_generic_debug_data generic_dbg_entry;
+ struct risab_debug_data dbg_entry;
+ int ret, page, compartment, block;
+
+ ret = clk_prepare_enable(pdata->clk);
+ if (ret) {
+ dev_err(pdata->dev, "Couldn't enable RISAB clock");
+ return ret;
+ }
+
+ stm32_risab_fill_dev_generic_dbg_entry(pdata, &generic_dbg_entry);
+
+ seq_puts(s, "=============================================\n");
+ seq_printf(s, " RISAB dump (%s)\n", pdata->dev->of_node->full_name);
+ seq_puts(s, "=============================================\n");
+
+ seq_printf(s, "Secure read/write illegal access disable (SRWIAD): %d.\n",
+ generic_dbg_entry.srwiad);
+ seq_printf(s, "Global lock (GLOCK): %d.\n", generic_dbg_entry.glock);
+
+ seq_puts(s, "| Page |");
+ seq_puts(s, "| Res. |");
+ seq_puts(s, "| priv. (p) read (r) write (w) per compartment |");
+ seq_puts(s, "| Delegated |");
+ seq_puts(s, "| CID |");
+ seq_puts(s, "| secure (s) default priv. (p) compartment2 priv. (P) per block |\n");
+
+ seq_puts(s, "| start add. end add. |");
+ seq_puts(s, "| lock |");
+ seq_puts(s, "| CID0 | CID1 | CID2 | CID3 | CID4 | CID5 | CID6 |");
+ seq_puts(s, "| conf. CID |");
+ seq_puts(s, "| filtering |");
+ seq_puts(s, "| blck0 | blck1 | blck2 | blck3 | blck4 | blck5 | blck6 | blck7 |\n");
+
+ for (page = 0; page < pdata->nb_pages; page++) {
+ stm32_risab_fill_dev_dbg_entry(pdata, &dbg_entry, page);
+ seq_printf(s, "| %2d 0x%08x 0x%08x |",
+ page,
+ pdata->risab_map_base + page * RISAB_PAGE_SIZE,
+ pdata->risab_map_base + (page + 1) * RISAB_PAGE_SIZE - 1
+ );
+ seq_printf(s, "| %3s |", generic_dbg_entry.rlock[page] ? "Yes" : "No");
+ for (compartment = 0; compartment < RISAB_NUMBER_OF_CID; compartment++) {
+ seq_printf(s, "| %1s %1s %1s ",
+ generic_dbg_entry.ppriv[compartment][page] ? "p" : " ",
+ generic_dbg_entry.prden[compartment][page] ? "r" : " ",
+ generic_dbg_entry.pwren[compartment][page] ? "w" : " "
+ );
+ }
+
+ if (dbg_entry.dcen)
+ seq_printf(s, "|| 0x%04x |", dbg_entry.dccid);
+ else
+ seq_puts(s, "|| disabled |");
+
+ seq_printf(s, "| %-9s |", dbg_entry.cfen ? "enabled" : "disabled");
+ for (block = 0; block < RISAB_BLOCKS_PER_PAGES; block++) {
+ seq_printf(s, "| %1s %1s %1s ",
+ dbg_entry.sec[block] ? "s" : " ",
+ dbg_entry.priv[block] && !dbg_entry.cfen ? "p" : " ",
+ dbg_entry.c2priv[block] ? "P" : " "
+ );
+ }
+ seq_puts(s, "|\n");
+ }
+
+ clk_disable_unprepare(pdata->clk);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(stm32_risab_conf_dump);
+
+static int stm32_risab_register_debugfs(struct risab_pdata *pdata)
+{
+ struct dentry *root = NULL;
+
+ root = debugfs_lookup("stm32_firewall", NULL);
+ if (!root)
+ root = debugfs_create_dir("stm32_firewall", NULL);
+
+ if (IS_ERR(root))
+ return PTR_ERR(root);
+
+ pdata->dbg_entry = debugfs_create_file(dev_name(pdata->dev), 0444,
+ root, pdata, &stm32_risab_conf_dump_fops);
+
+ return 0;
+}
+
+static int stm32_risab_get_nb_pages(struct risab_pdata *pdata)
+{
+ u32 risab_hwcfgr1, nb_pages_shift;
+ int ret, nb_page;
+
+ ret = clk_prepare_enable(pdata->clk);
+ if (ret) {
+ dev_err(pdata->dev, "Failed to enable clk: %d\n", ret);
+ return ret;
+ }
+
+ risab_hwcfgr1 = readl_relaxed(pdata->base + RISAB_HWCFGR1);
+ nb_pages_shift = FIELD_GET(RISAB_HWCFGR1_LOG_NUM_PAGE_MASK,
+ risab_hwcfgr1);
+ nb_page = BIT(nb_pages_shift);
+
+ if (nb_page > RISAB_NUMBER_OF_PAGES_MAX) {
+ dev_err(pdata->dev, "RISAB number of pages is greater than %d",
+ RISAB_NUMBER_OF_PAGES_MAX);
+ ret = -EINVAL;
+ goto err_clk_disable;
+ }
+
+ ret = nb_page;
+
+err_clk_disable:
+ clk_disable_unprepare(pdata->clk);
+
+ return ret;
+}
+
+static int stm32_risab_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct risab_pdata *pdata;
+ void __iomem *mmio;
+ int err, nb_pages;
+ struct clk *clk;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ mmio = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(mmio))
+ return PTR_ERR(mmio);
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Failed to get clk\n");
+
+ pdata->base = mmio;
+ pdata->clk = clk;
+ pdata->dev = &pdev->dev;
+
+ err = of_property_read_u32(np, "st,mem-map", &pdata->risab_map_base);
+ if (err) {
+ return dev_err_probe(&pdev->dev, err,
+ "Couldn't read the memory range covered by the RISAB\n");
+ }
+
+ nb_pages = stm32_risab_get_nb_pages(pdata);
+ if (nb_pages < 0)
+ return dev_err_probe(&pdev->dev, nb_pages, "Couldn't read RISAB number of pages\n");
+
+ pdata->nb_pages = nb_pages;
+
+ platform_set_drvdata(pdev, pdata);
+
+ return stm32_risab_register_debugfs(pdata);
+}
+
+static void stm32_risab_remove(struct platform_device *pdev)
+{
+ struct risab_pdata *pdata = platform_get_drvdata(pdev);
+
+ debugfs_remove(pdata->dbg_entry);
+}
+
+static const struct of_device_id stm32_risab_match[] = {
+ { .compatible = "st,stm32mp25-risab", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, stm32_risab_match);
+
+static struct platform_driver stm32_risab_driver = {
+ .probe = stm32_risab_probe,
+ .remove = stm32_risab_remove,
+ .driver = {
+ .name = "stm32-risab",
+ .of_match_table = stm32_risab_match,
+ },
+};
+module_platform_driver(stm32_risab_driver);
+
+MODULE_AUTHOR("Gatien Chevallier <gatien.chevallier@...s.st.com>");
+MODULE_LICENSE("GPL");
--
2.43.0
Powered by blists - more mailing lists