* [PATCH v4 0/3] Add STM32 TAMP nvram driver support
@ 2026-11-04 15:20 Patrice Chotard
2026-11-04 15:20 ` [PATCH v4 1/3] dt-bindings: nvmem: add STM32MPX TAMP backup registers Patrice Chotard
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Patrice Chotard @ 2026-11-04 15:20 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Christophe Roullier, Srinivas Kandagatla
Cc: Simeon Marijon, linux-stm32, devicetree, linux-arm-kernel,
linux-kernel, Patrice Chotard, Gatien Chevallier
Propose bindings and driver to enable TAMP nvram driver
support for STM32MP SoC's family.
It allows to expose TAMP backup registers as nvmem cells.
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
Changes in v4:
- Make usage of of_device_get_match_data() wrapper.
- Rework ioremap of syscon's memory region to avoid overlapping
between parent and child node. This allows to remove
bkpregs_regmap_cfg declaration for both STM32MP1 and STM32MP2.
_ Add select MFD_SYSCON in Kconfig.
- Link to v3: https://patch.msgid.link/20261016-upstream_nvram_reworked-v3-0-f65908490cf7@foss.st.com
Changes in v3:
- Fix issue found by sashiko-bot:
- rely on the already resolved priv->data->nb_zones instead of
of_device_is_compatible() to set priv->bkpreg_access
- Fix max_register of stm32mp1_tamp_nvram_regmap_cfg and
stm32mp2_tamp_nvram_regmap_cfg
- Update zones_end type to int*
- Replace both memcpy by put_unaligned_le32 and get_unaligned_le32
- Link to v2: https://patch.msgid.link/20260930-upstream_nvram_reworked-v2-0-cfda749ee0b7@foss.st.com
Changes in v2:
- Update commit title of nvmem dt-bindings's patch.
- Add required compatible for patternProperties in stm32/st,stm32-syscon.yaml.
- Fix issue found by sashiko-bot:
- Add freeing compartment_owner.
- Replace regmap_read/regmap_write by regmap_update_bits in stm32_tamp_nvram_write_byte().
- Update error return in stm32_tamp_nvram_read_byte(), stm32_tamp_nvram_write_byte(),
stm32_tamp_nvram_read() and stm32_tamp_nvram_write() to return the actual regmap_read() /
regmap_write() error instead of -EIO.
- Add freeing field and update error return values for stm32_tamp_nvram_get_backup_zones().
- Update error return for stm32_tamp_nvram_probe().
- Link to v1: https://patch.msgid.link/20260910-upstream_nvram_reworked-v1-0-521c16175cef@foss.st.com
To: Simeon Marijon <simeon.marijon@foss.st.com>
To: Patrice Chotard <patrice.chotard@foss.st.com>
To: Srinivas Kandagatla <srini@kernel.org>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
To: Maxime Coquelin <mcoquelin.stm32@gmail.com>
To: Alexandre Torgue <alexandre.torgue@foss.st.com>
To: Christophe Roullier <christophe.roullier@foss.st.com>
Cc: linux-stm32@st-md-mailman.stormreply.com
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
Patrice Chotard (1):
dt-bindings: arm: stm32: allow TAMP nvram child node for syscon
Simeon Marijon (2):
dt-bindings: nvmem: add STM32MPX TAMP backup registers
nvmem: stm32: add TAMP nvmem driver
.../bindings/arm/stm32/st,stm32-syscon.yaml | 38 +-
.../bindings/nvmem/st,stm32-tamp-nvram.yaml | 57 ++
MAINTAINERS | 8 +
drivers/nvmem/Kconfig | 11 +
drivers/nvmem/Makefile | 2 +
drivers/nvmem/stm32-tamp-nvram.c | 680 +++++++++++++++++++++
6 files changed, 793 insertions(+), 3 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20260909-upstream_nvram_reworked-f84a4b37817c
Best regards,
--
Patrice Chotard <patrice.chotard@foss.st.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v4 1/3] dt-bindings: nvmem: add STM32MPX TAMP backup registers
2026-11-04 15:20 [PATCH v4 0/3] Add STM32 TAMP nvram driver support Patrice Chotard
@ 2026-11-04 15:20 ` Patrice Chotard
2026-11-04 15:20 ` [PATCH v4 2/3] dt-bindings: arm: stm32: allow TAMP nvram child node for syscon Patrice Chotard
2026-11-04 15:20 ` [PATCH v4 3/3] nvmem: stm32: add TAMP nvmem driver Patrice Chotard
2 siblings, 0 replies; 5+ messages in thread
From: Patrice Chotard @ 2026-11-04 15:20 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Christophe Roullier, Srinivas Kandagatla
Cc: Simeon Marijon, linux-stm32, devicetree, linux-arm-kernel,
linux-kernel, Patrice Chotard
From: Simeon Marijon <simeon.marijon@foss.st.com>
Adds the binding documentation for TAMP backup registers.
The backup registers is a part of the TAMP device of STM32 MPU.
Signed-off-by: Simeon Marijon <simeon.marijon@foss.st.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
.../bindings/nvmem/st,stm32-tamp-nvram.yaml | 57 ++++++++++++++++++++++
MAINTAINERS | 7 +++
2 files changed, 64 insertions(+)
diff --git a/Documentation/devicetree/bindings/nvmem/st,stm32-tamp-nvram.yaml b/Documentation/devicetree/bindings/nvmem/st,stm32-tamp-nvram.yaml
new file mode 100644
index 000000000000..4af3b88db566
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/st,stm32-tamp-nvram.yaml
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/st,stm32-tamp-nvram.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 backup registers as NVMEM
+
+description: |
+ This represents STM32 backup registers area presented as nvmem cells.
+ This contains various information (e.g. boot mode passed to bootloaders).
+
+maintainers:
+ - Simeon Marijon <simeon.marijon@foss.st.com>
+ - Patrice Chotard <patrice.chotard@foss.st.com>
+
+allOf:
+ - $ref: nvmem.yaml#
+
+properties:
+ compatible:
+ enum:
+ - st,stm32mp15-tamp-nvram
+ - st,stm32mp25-tamp-nvram
+
+ reg:
+ description:
+ TAMP Registers bank location and size.
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ nvram: nvram@5c00a100 {
+ reg = <0x5c00a100 0x80>;
+ compatible = "st,stm32mp15-tamp-nvram";
+
+ nvmem-layout {
+ compatible = "fixed-layout";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* Data cells */
+ wakeup_sec: tamp-bkp@0 {
+ reg = <0x0 0x4>;
+ };
+ boot_mode: tamp-bkp@50 {
+ /*see boot mode selection feature*/
+ reg = <0x50 0x4>;
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 93abbb315065..13f5c94b0bf8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26918,6 +26918,13 @@ F: Documentation/arch/arm/stm32/stm32-dma-mdma-chaining.rst
F: Documentation/devicetree/bindings/dma/stm32/
F: drivers/dma/stm32/
+STM32 TAMP DRIVERS
+M: Simeon Marijon <simeon.marijon@foss.st.com>
+M: Patrice Chotard <patrice.chotard@foss.st.com>
+L: linux-stm32@st-md-mailman.stormreply.com (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/nvmem/st,stm32-tamp-nvram.yaml
+
STM32 TIMER/LPTIMER DRIVERS
M: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
S: Maintained
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v4 2/3] dt-bindings: arm: stm32: allow TAMP nvram child node for syscon
2026-11-04 15:20 [PATCH v4 0/3] Add STM32 TAMP nvram driver support Patrice Chotard
2026-11-04 15:20 ` [PATCH v4 1/3] dt-bindings: nvmem: add STM32MPX TAMP backup registers Patrice Chotard
@ 2026-11-04 15:20 ` Patrice Chotard
2026-11-04 15:39 ` sashiko-bot
2026-11-04 15:20 ` [PATCH v4 3/3] nvmem: stm32: add TAMP nvmem driver Patrice Chotard
2 siblings, 1 reply; 5+ messages in thread
From: Patrice Chotard @ 2026-11-04 15:20 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Christophe Roullier, Srinivas Kandagatla
Cc: Simeon Marijon, linux-stm32, devicetree, linux-arm-kernel,
linux-kernel, Patrice Chotard
The STM32 TAMP node (compatible "st,stm32-tamp", "syscon", "simple-mfd")
exposes its backup registers through an nvram child node described by
nvmem/st,stm32-tamp-nvram.yaml. That requires the TAMP node to carry
"#address-cells", "#size-cells", "ranges" and an "nvram@..." child.
st,stm32-syscon.yaml uses "additionalProperties: false" and only allowed
into the DTSI made "make dtbs_check" fail on every STM32MP TAMP node:
tamp@5c00a000 (st,stm32-tamp): 'nvram@5c00a100', 'ranges' do not match
any of the regexes: '^pinctrl-[0-9]+$'
Allow the addressing properties and the nvram child, gated on the
st,stm32-tamp compatible so the other syscon variants stay strict.
"#size-cells" may be 1 or 2: the STM32MP21 soc bus uses two size cells
(an empty "ranges" requires the node to match its parent) while the
other STM32MP SoCs use one.
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
.../bindings/arm/stm32/st,stm32-syscon.yaml | 38 ++++++++++++++++++++--
1 file changed, 35 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml b/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml
index a559f8b03b84..51cb565e05ed 100644
--- a/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml
+++ b/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml
@@ -43,13 +43,19 @@ properties:
const: 1
"#size-cells":
- const: 1
+ enum: [1, 2]
+
+ ranges: true
patternProperties:
"^phy@2[48]00$":
type: object
$ref: /schemas/phy/st,stm32-usb2phy.yaml
+ "^nvram@[0-9a-f]+$":
+ type: object
+ $ref: /schemas/nvmem/st,stm32-tamp-nvram.yaml
+
required:
- compatible
- reg
@@ -84,11 +90,37 @@ allOf:
- phy@2800
else:
properties:
- '#address-cells': false
'#clock-cells': false
- '#size-cells': false
phy@2400: false
phy@2800: false
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: st,stm32-tamp
+ then:
+ required:
+ - "#address-cells"
+ - "#size-cells"
+ - ranges
+ else:
+ properties:
+ ranges: false
+ patternProperties:
+ "^nvram@[0-9a-f]+$": false
+ - if:
+ not:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - st,stm32-tamp
+ - st,stm32mp23-syscfg
+ - st,stm32mp25-syscfg
+ then:
+ properties:
+ '#address-cells': false
+ '#size-cells': false
additionalProperties: false
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v4 3/3] nvmem: stm32: add TAMP nvmem driver
2026-11-04 15:20 [PATCH v4 0/3] Add STM32 TAMP nvram driver support Patrice Chotard
2026-11-04 15:20 ` [PATCH v4 1/3] dt-bindings: nvmem: add STM32MPX TAMP backup registers Patrice Chotard
2026-11-04 15:20 ` [PATCH v4 2/3] dt-bindings: arm: stm32: allow TAMP nvram child node for syscon Patrice Chotard
@ 2026-11-04 15:20 ` Patrice Chotard
2 siblings, 0 replies; 5+ messages in thread
From: Patrice Chotard @ 2026-11-04 15:20 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Christophe Roullier, Srinivas Kandagatla
Cc: Simeon Marijon, linux-stm32, devicetree, linux-arm-kernel,
linux-kernel, Patrice Chotard, Gatien Chevallier
From: Simeon Marijon <simeon.marijon@foss.st.com>
TAMP backup registers will be exposed as nvmem cells.
Each registers ([0..127] for STM32MP2, [0..31] for STM32MP1) could be
exposed as nvmem cells under the nvram node in device tree.
Signed-off-by: Simeon Marijon <simeon.marijon@foss.st.com>
Signed-off-by: Gatien Chevallier <gatien.chevallier@foss.st.com>
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
MAINTAINERS | 1 +
drivers/nvmem/Kconfig | 11 +
drivers/nvmem/Makefile | 2 +
drivers/nvmem/stm32-tamp-nvram.c | 680 +++++++++++++++++++++++++++++++++++++++
4 files changed, 694 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 13f5c94b0bf8..eb7b9f746be6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26924,6 +26924,7 @@ M: Patrice Chotard <patrice.chotard@foss.st.com>
L: linux-stm32@st-md-mailman.stormreply.com (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/nvmem/st,stm32-tamp-nvram.yaml
+F: drivers/nvmem/stm32-tamp-nvram.c
STM32 TIMER/LPTIMER DRIVERS
M: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index d2f5bb236663..a0675f89015c 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -516,6 +516,17 @@ config NVMEM_STM32_ROMEM
This driver can also be built as a module. If so, the module
will be called nvmem-stm32-romem.
+config NVMEM_STM32_TAMP
+ tristate "STMicroelectronics STM32 TAMP backup registers support"
+ depends on ARCH_STM32 || COMPILE_TEST
+ select MFD_SYSCON
+ help
+ Say y here to enable access for STMicroelectronics STM32
+ TAMP backup registers.
+
+ This driver can also be built as a module. If so, the module
+ will be called nvmem_stm32_tamp_nvram.
+
config NVMEM_SUNPLUS_OCOTP
tristate "Sunplus SoC OTP support"
depends on SOC_SP7021 || COMPILE_TEST
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 5e70bad9f0f9..73ec68e53556 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -88,6 +88,8 @@ nvmem_sprd_efuse-y := sprd-efuse.o
obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o
nvmem_stm32_romem-y := stm32-romem.o
nvmem_stm32_romem-$(CONFIG_NVMEM_STM32_BSEC_OPTEE_TA) += stm32-bsec-optee-ta.o
+obj-$(CONFIG_NVMEM_STM32_TAMP) += nvmem_stm32_tamp_nvram.o
+nvmem_stm32_tamp_nvram-y := stm32-tamp-nvram.o
obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o
nvmem_sunplus_ocotp-y := sunplus-ocotp.o
obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o
diff --git a/drivers/nvmem/stm32-tamp-nvram.c b/drivers/nvmem/stm32-tamp-nvram.c
new file mode 100644
index 000000000000..81096a5d0282
--- /dev/null
+++ b/drivers/nvmem/stm32-tamp-nvram.c
@@ -0,0 +1,680 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * STM32 Tamp backup registers access driver
+ *
+ * Copyright (C) 2026, STMicroelectronics - All Rights Reserved
+ * Author: Simeon Marijon <simeon.marijon@foss.st.com> for STMicroelectronics.
+ */
+
+#include <linux/align.h>
+#include <linux/bits.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#define RIF_CID1 0x1
+#define CURRENT_CID RIF_CID1
+#define NB_ZONES_STM32MP1 3
+#define NB_ZONES_STM32MP2 7
+#define NB_REGS_STM32MP1 32
+#define NB_REGS_STM32MP2 128
+
+#define _TAMP_SECCFGR 0x20U
+#define _TAMP_BKPRIFR(x) (0x70U + 0x4U * ((x) - 1))
+#define _TAMP_RXCIDCFGR(x) (0x80U + 0x4U * ((x)))
+
+#define BKPREG_PROTECTION_ZONE_1 0
+#define BKPREG_PROTECTION_ZONE_2 1
+#define BKPREG_PROTECTION_ZONE_3 2
+
+#define BKPREG_PROTECTION_ZONE_1_RIF1 0
+#define BKPREG_PROTECTION_ZONE_1_RIF2 1
+#define BKPREG_PROTECTION_ZONE_2_RIF1 2
+#define BKPREG_PROTECTION_ZONE_2_RIF2 3
+#define BKPREG_PROTECTION_ZONE_3_RIF1 4
+#define BKPREG_PROTECTION_ZONE_3_RIF0 5
+#define BKPREG_PROTECTION_ZONE_3_RIF2 6
+#define NB_COMPARTMENT_STM32MP2 3
+
+enum stm32_tamp_bkpreg_access {
+ BKP_READ_WRITE,
+ BKP_READ,
+ BKP_NO
+};
+
+struct stm32_tamp_nvram_priv {
+ struct nvmem_config cfg;
+ const struct stm32_tamp_nvram_plat *data;
+ int *idx_bkpreg_zones_end;
+ struct device *dev;
+ struct regmap *config_regmap;
+ struct regmap *bkpregs_regmap;
+ unsigned int bkpregs_offset;
+ enum stm32_tamp_bkpreg_access *bkpreg_access;
+};
+
+struct stm32_tamp_nvram_plat {
+ const unsigned int nb_zones;
+ const unsigned int nb_regs;
+ const struct reg_field *config_reg_fields;
+};
+
+static const struct reg_field stm32mp1_tamp_nvram_zone_cfg_fields[NB_ZONES_STM32MP1 - 1] = {
+ [BKPREG_PROTECTION_ZONE_1] = REG_FIELD(_TAMP_SECCFGR, 0, 7),
+ [BKPREG_PROTECTION_ZONE_2] = REG_FIELD(_TAMP_SECCFGR, 16, 23),
+};
+
+static const struct reg_field stm32mp25_tamp_nvram_zone_cfg_fields[NB_ZONES_STM32MP2 - 1] = {
+ [BKPREG_PROTECTION_ZONE_1_RIF1] = REG_FIELD(_TAMP_BKPRIFR(1), 0, 7),
+ [BKPREG_PROTECTION_ZONE_1_RIF2] = REG_FIELD(_TAMP_SECCFGR, 0, 7),
+ [BKPREG_PROTECTION_ZONE_2_RIF1] = REG_FIELD(_TAMP_BKPRIFR(2), 0, 7),
+ [BKPREG_PROTECTION_ZONE_2_RIF2] = REG_FIELD(_TAMP_SECCFGR, 16, 23),
+ [BKPREG_PROTECTION_ZONE_3_RIF1] = REG_FIELD(_TAMP_BKPRIFR(3), 0, 7),
+ [BKPREG_PROTECTION_ZONE_3_RIF0] = REG_FIELD(_TAMP_BKPRIFR(3), 16, 23),
+};
+
+static const struct reg_field stm32mp25_tamp_nvram_rxcidcfg_cfen_fields[NB_COMPARTMENT_STM32MP2] = {
+ REG_FIELD(_TAMP_RXCIDCFGR(0), 0, 0),
+ REG_FIELD(_TAMP_RXCIDCFGR(1), 0, 0),
+ REG_FIELD(_TAMP_RXCIDCFGR(2), 0, 0),
+};
+
+static const struct reg_field stm32mp25_tamp_nvram_rxcidcfg_fields[NB_COMPARTMENT_STM32MP2] = {
+ REG_FIELD(_TAMP_RXCIDCFGR(0), 4, 6),
+ REG_FIELD(_TAMP_RXCIDCFGR(1), 4, 6),
+ REG_FIELD(_TAMP_RXCIDCFGR(2), 4, 6),
+};
+
+static enum stm32_tamp_bkpreg_access stm32mp1_tamp_bkpreg_access[NB_ZONES_STM32MP1] = {
+ [BKPREG_PROTECTION_ZONE_1] = BKP_NO,
+ [BKPREG_PROTECTION_ZONE_2] = BKP_READ,
+ [BKPREG_PROTECTION_ZONE_3] = BKP_READ_WRITE,
+};
+
+static int stm32_tamp_is_compartment_isolation_enabled_mp2x(struct stm32_tamp_nvram_priv *priv)
+{
+ int nb_compartment_enabled = 0;
+ struct device *dev = priv->dev;
+ u32 cfen;
+ struct regmap_field *cfen_field;
+
+ for (int i = 0; i < NB_COMPARTMENT_STM32MP2; i++) {
+ cfen_field = devm_regmap_field_alloc(dev,
+ priv->config_regmap,
+ stm32mp25_tamp_nvram_rxcidcfg_cfen_fields[i]);
+ if (IS_ERR(cfen_field)) {
+ dev_err(dev, "Can't allocate field for reading configuration\n");
+ return PTR_ERR(cfen_field);
+ }
+
+ if (regmap_field_read(cfen_field, &cfen)) {
+ dev_err(dev, "Can't read field for registers zones\n");
+ devm_regmap_field_free(dev, cfen_field);
+ return -EINVAL;
+ }
+
+ nb_compartment_enabled += cfen;
+ devm_regmap_field_free(dev, cfen_field);
+ }
+
+ if (!nb_compartment_enabled)
+ return 0;
+ else if (nb_compartment_enabled == NB_COMPARTMENT_STM32MP2)
+ return 1;
+ else
+ return -EINVAL;
+}
+
+static bool *stm32_tamp_get_compartment_owner_mp2x(struct stm32_tamp_nvram_priv *priv)
+{
+ struct device *dev = priv->dev;
+ struct regmap_field *cid_field;
+ u32 cid_per_zone;
+ int isolation_enabled;
+ bool *compartment_owner;
+
+ isolation_enabled = stm32_tamp_is_compartment_isolation_enabled_mp2x(priv);
+ if (isolation_enabled < 0)
+ return ERR_PTR(-EINVAL);
+
+ compartment_owner = kcalloc(NB_COMPARTMENT_STM32MP2,
+ sizeof(*compartment_owner),
+ GFP_KERNEL);
+
+ if (!compartment_owner)
+ return ERR_PTR(-ENOMEM);
+
+ for (int i = 0; i < NB_COMPARTMENT_STM32MP2; i++) {
+ if (isolation_enabled) {
+ cid_field = devm_regmap_field_alloc(dev,
+ priv->config_regmap,
+ stm32mp25_tamp_nvram_rxcidcfg_fields[i]
+ );
+ if (IS_ERR(cid_field)) {
+ kfree(compartment_owner);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (regmap_field_read(cid_field, &cid_per_zone)) {
+ dev_err(dev, "Can't read field for registers zones\n");
+ devm_regmap_field_free(dev, cid_field);
+ kfree(compartment_owner);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (cid_per_zone == CURRENT_CID)
+ compartment_owner[i] = true;
+ else
+ compartment_owner[i] = false;
+
+ devm_regmap_field_free(dev, cid_field);
+ } else {
+ compartment_owner[i] = true;
+ }
+ }
+
+ return compartment_owner;
+}
+
+static enum stm32_tamp_bkpreg_access *stm32_tamp_get_access_rights_mp2x(struct stm32_tamp_nvram_priv
+ *priv)
+{
+ struct device *dev = priv->dev;
+ unsigned int nb_zones = priv->data->nb_zones;
+ bool *compartment_owner;
+ enum stm32_tamp_bkpreg_access *bkpreg_access;
+
+ compartment_owner = stm32_tamp_get_compartment_owner_mp2x(priv);
+ if (IS_ERR(compartment_owner))
+ return ERR_PTR(-ENODEV);
+
+ bkpreg_access = devm_kcalloc(dev,
+ NB_ZONES_STM32MP2,
+ sizeof(*bkpreg_access),
+ GFP_KERNEL);
+
+ if (!bkpreg_access) {
+ kfree(compartment_owner);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (int protection_zone_idx = 0; protection_zone_idx < nb_zones;
+ protection_zone_idx++) {
+ switch (protection_zone_idx) {
+ case BKPREG_PROTECTION_ZONE_1_RIF1:
+ bkpreg_access[protection_zone_idx] = BKP_NO;
+ break;
+ case BKPREG_PROTECTION_ZONE_1_RIF2:
+ bkpreg_access[protection_zone_idx] = BKP_NO;
+ break;
+ case BKPREG_PROTECTION_ZONE_2_RIF1:
+ if (compartment_owner[1] || compartment_owner[2])
+ bkpreg_access[protection_zone_idx] = BKP_READ;
+ else
+ bkpreg_access[protection_zone_idx] = BKP_NO;
+ break;
+ case BKPREG_PROTECTION_ZONE_2_RIF2:
+ if (compartment_owner[1] || compartment_owner[2])
+ bkpreg_access[protection_zone_idx] = BKP_READ;
+ else
+ bkpreg_access[protection_zone_idx] = BKP_NO;
+ break;
+ case BKPREG_PROTECTION_ZONE_3_RIF1:
+ if (compartment_owner[1])
+ bkpreg_access[protection_zone_idx] = BKP_READ_WRITE;
+ else if (compartment_owner[0] || compartment_owner[2])
+ bkpreg_access[protection_zone_idx] = BKP_READ;
+ else
+ bkpreg_access[protection_zone_idx] = BKP_NO;
+ break;
+ case BKPREG_PROTECTION_ZONE_3_RIF0:
+ if (compartment_owner[0])
+ bkpreg_access[protection_zone_idx] = BKP_READ_WRITE;
+ else if (compartment_owner[1] || compartment_owner[2])
+ bkpreg_access[protection_zone_idx] = BKP_READ;
+ else
+ bkpreg_access[protection_zone_idx] = BKP_NO;
+ break;
+ case BKPREG_PROTECTION_ZONE_3_RIF2:
+ if (compartment_owner[2])
+ bkpreg_access[protection_zone_idx] = BKP_READ_WRITE;
+ else if (compartment_owner[0] || compartment_owner[1])
+ bkpreg_access[protection_zone_idx] = BKP_READ;
+ else
+ bkpreg_access[protection_zone_idx] = BKP_NO;
+ break;
+ default:
+ devm_kfree(dev, bkpreg_access);
+ kfree(compartment_owner);
+ return ERR_PTR(-ENODEV);
+ }
+ }
+
+ kfree(compartment_owner);
+
+ return bkpreg_access;
+}
+
+static int stm32_tamp_nvram_bkpreg_get_zone(struct stm32_tamp_nvram_priv *priv, int reg)
+{
+ int *idx_bkpreg_zones_end = priv->idx_bkpreg_zones_end;
+ int nb_zones = priv->data->nb_zones;
+ int protection_zone_idx;
+
+ if (reg < 0)
+ return -1; /* negative reg is the boundary of an empty zone */
+
+ for (protection_zone_idx = 0; protection_zone_idx < nb_zones; protection_zone_idx++) {
+ if (reg <= idx_bkpreg_zones_end[protection_zone_idx])
+ break;
+ }
+
+ if (protection_zone_idx >= nb_zones)
+ return -1; /* the reg is not a part of any zone */
+
+ return protection_zone_idx;
+}
+
+static bool stm32_tamp_nvram_rights(struct stm32_tamp_nvram_priv *priv, int reg, bool read_only)
+{
+ struct device *dev = priv->dev;
+ int protection_zone_idx = stm32_tamp_nvram_bkpreg_get_zone(priv, reg);
+
+ if (protection_zone_idx < 0)
+ return false;
+
+ switch (priv->bkpreg_access[protection_zone_idx]) {
+ case BKP_READ_WRITE:
+ return true;
+ case BKP_READ:
+ return read_only;
+ case BKP_NO:
+ return false;
+ default:
+ dev_err(dev, "Can't get access rights for the zone\n");
+ return false;
+ }
+
+ return false;
+}
+
+static const struct stm32_tamp_nvram_plat stm32mp1_tamp_nvram = {
+ .nb_zones = NB_ZONES_STM32MP1,
+ .nb_regs = NB_REGS_STM32MP1,
+ .config_reg_fields = stm32mp1_tamp_nvram_zone_cfg_fields,
+};
+
+static const struct stm32_tamp_nvram_plat stm32mp25_tamp_nvram = {
+ .nb_zones = NB_ZONES_STM32MP2,
+ .nb_regs = NB_REGS_STM32MP2,
+ .config_reg_fields = stm32mp25_tamp_nvram_zone_cfg_fields,
+};
+
+static int stm32_tamp_nvram_write_byte(struct stm32_tamp_nvram_priv *priv, u32 offset, u8 byte)
+{
+ int offset_aligned = ALIGN_DOWN(offset, sizeof(u32));
+ unsigned int shift = (offset - offset_aligned) * 8;
+ u32 reg_idx = offset_aligned / sizeof(u32);
+
+ if (!stm32_tamp_nvram_rights(priv, reg_idx, false))
+ return -EACCES;
+
+ return regmap_update_bits(priv->bkpregs_regmap, priv->bkpregs_offset + offset_aligned,
+ 0xFFUL << shift, (u32)byte << shift);
+}
+
+static int stm32_tamp_nvram_read_byte(struct stm32_tamp_nvram_priv *priv, u32 offset, u8 *byte)
+{
+ int offset_aligned = ALIGN_DOWN(offset, sizeof(u32));
+ int byte_in_word = offset - offset_aligned;
+ u32 read_value;
+ u32 reg_idx = offset_aligned / sizeof(u32);
+ int ret;
+
+ if (!stm32_tamp_nvram_rights(priv, reg_idx, true))
+ return -EACCES;
+
+ ret = regmap_read(priv->bkpregs_regmap, priv->bkpregs_offset + offset_aligned,
+ &read_value);
+ if (ret)
+ return ret;
+
+ *byte = (read_value >> (byte_in_word * 8)) & 0xFF;
+
+ return 0;
+}
+
+static int stm32_tamp_nvram_read(void *context, unsigned int offset, void *buf, size_t bytes)
+{
+ struct stm32_tamp_nvram_priv *priv = context;
+ struct device *dev = priv->dev;
+ u32 temp_u32;
+ u32 reg_idx;
+ int i, ret;
+ size_t total = offset + bytes;
+ u8 byte;
+ u8 *buf_u8 = buf;
+
+ i = offset;
+ while (i < total) {
+ reg_idx = i / sizeof(u32);
+ if (i + sizeof(u32) <= total && IS_ALIGNED(i, sizeof(u32))) {
+ if (!stm32_tamp_nvram_rights(priv, reg_idx, true)) {
+ dev_dbg(dev, "Backup register %u is not allowed to be read\n",
+ reg_idx);
+ temp_u32 = 0;
+ } else {
+ ret = regmap_read(priv->bkpregs_regmap,
+ priv->bkpregs_offset + i, &temp_u32);
+ if (ret)
+ return ret;
+ }
+ put_unaligned_le32(temp_u32, buf_u8);
+ buf_u8 += sizeof(u32);
+ i += sizeof(u32);
+ } else {
+ ret = stm32_tamp_nvram_read_byte(priv, i, &byte);
+ if (ret == -EACCES) {
+ dev_dbg(dev, "Backup register %u is not allowed to be read\n",
+ reg_idx);
+ byte = 0;
+ } else if (ret) {
+ return ret;
+ }
+
+ *buf_u8 = byte;
+ i++;
+ buf_u8++;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_tamp_nvram_write(void *context, unsigned int offset, void *buf, size_t bytes)
+{
+ struct stm32_tamp_nvram_priv *priv = context;
+ struct device *dev = priv->dev;
+ u32 temp_u32;
+ u32 reg_idx;
+ int i, ret;
+ size_t total = offset + bytes;
+ u8 *buf_u8 = (u8 *)buf;
+
+ i = offset;
+ while (i < total) {
+ reg_idx = i / sizeof(u32);
+ if (i + sizeof(u32) <= total && IS_ALIGNED(i, sizeof(u32))) {
+ if (stm32_tamp_nvram_rights(priv, reg_idx, false)) {
+ temp_u32 = get_unaligned_le32(buf_u8);
+ ret = regmap_write(priv->bkpregs_regmap,
+ priv->bkpregs_offset + i, temp_u32);
+ if (ret)
+ return ret;
+ } else {
+ dev_dbg(dev, "Backup register %u is not allowed to be written\n",
+ reg_idx);
+ }
+ buf_u8 += sizeof(u32);
+ i += sizeof(u32);
+ } else {
+ ret = stm32_tamp_nvram_write_byte(priv, i, *buf_u8);
+ if (ret == -EACCES) {
+ dev_dbg(dev, "Backup register %u is not allowed to be written\n",
+ reg_idx);
+ } else if (ret) {
+ return ret;
+ }
+
+ i++;
+ buf_u8++;
+ }
+ }
+
+ return 0;
+}
+
+static int *stm32_tamp_nvram_get_backup_zones(struct stm32_tamp_nvram_priv *priv)
+{
+ struct device *dev = priv->dev;
+ struct regmap *tamp_regmap = priv->config_regmap;
+ u32 offset_field;
+ int nb_zones = priv->data->nb_zones;
+ int zone_idx;
+ int *idx_bkpreg_zones_end;
+
+ idx_bkpreg_zones_end = devm_kcalloc(dev,
+ nb_zones,
+ sizeof(*idx_bkpreg_zones_end),
+ GFP_KERNEL);
+ if (!idx_bkpreg_zones_end) {
+ dev_err(dev, "Can't allocate registers zones\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* Get the n-1 frontiers of zone within the tamp configuration registers */
+ for (zone_idx = 0; zone_idx < nb_zones - 1; zone_idx++) {
+ const struct reg_field reg_field = priv->data->config_reg_fields[zone_idx];
+ struct regmap_field *field;
+ int ret;
+
+ field = devm_regmap_field_alloc(dev, tamp_regmap, reg_field);
+ if (IS_ERR(field)) {
+ dev_err(dev, "Can't allocate registers zones\n");
+ devm_kfree(dev, idx_bkpreg_zones_end);
+ return ERR_CAST(field);
+ }
+
+ ret = regmap_field_read(field, &offset_field);
+ devm_regmap_field_free(dev, field);
+ if (ret) {
+ dev_err(dev, "Can't read field for registers zones\n");
+ devm_kfree(dev, idx_bkpreg_zones_end);
+ return ERR_PTR(ret);
+ }
+
+ idx_bkpreg_zones_end[zone_idx] = offset_field - 1;
+ }
+
+ /* The last zone end is defined by the number of registers in TAMP */
+ idx_bkpreg_zones_end[zone_idx] = priv->data->nb_regs - 1;
+
+ return idx_bkpreg_zones_end;
+}
+
+static const struct of_device_id stm32_tamp_nvram_of_match[] = {
+ { .compatible = "st,stm32mp15-tamp-nvram",
+ .data = &stm32mp1_tamp_nvram },
+ { .compatible = "st,stm32mp25-tamp-nvram",
+ .data = &stm32mp25_tamp_nvram },
+ {},
+};
+
+static int stm32_tamp_nvram_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct stm32_tamp_nvram_priv *priv;
+ struct resource *res, parent_res;
+ int *zones_end;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &pdev->dev;
+ priv->data = of_device_get_match_data(dev);
+ if (!priv->data) {
+ dev_err(dev, "Can't get platform data of the node\n");
+ return -ENODEV;
+ }
+
+ priv->config_regmap = syscon_node_to_regmap(dev->parent->of_node);
+ if (IS_ERR(priv->config_regmap))
+ return dev_err_probe(dev, PTR_ERR(priv->config_regmap),
+ "Can't get TAMP syscon regmap\n");
+
+ priv->idx_bkpreg_zones_end = stm32_tamp_nvram_get_backup_zones(priv);
+ if (IS_ERR(priv->idx_bkpreg_zones_end))
+ return dev_err_probe(dev, PTR_ERR(priv->idx_bkpreg_zones_end),
+ "Can't determine protection zone\n");
+
+ zones_end = priv->idx_bkpreg_zones_end;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res) {
+ dev_err(dev, "Can't get resource\n");
+ return -ENODEV;
+ }
+
+ /*
+ * The backup registers belong to the parent TAMP syscon, which other
+ * drivers (e.g. remoteproc) also access: go through the syscon regmap
+ * so that all accesses are serialized by the same lock.
+ */
+ if (of_address_to_resource(dev->parent->of_node, 0, &parent_res) ||
+ !resource_contains(&parent_res, res))
+ return dev_err_probe(dev, -EINVAL,
+ "Backup registers not within TAMP parent range\n");
+
+ priv->bkpregs_regmap = priv->config_regmap;
+ priv->bkpregs_offset = res->start - parent_res.start;
+
+ priv->cfg.name = "stm32-tamp-nvram";
+ priv->cfg.word_size = 1;
+ priv->cfg.stride = 1;
+ priv->cfg.dev = dev;
+ priv->cfg.priv = priv;
+ priv->cfg.owner = THIS_MODULE;
+ priv->cfg.type = NVMEM_TYPE_BATTERY_BACKED;
+ priv->cfg.size = resource_size(res);
+ priv->cfg.reg_read = stm32_tamp_nvram_read;
+ priv->cfg.reg_write = stm32_tamp_nvram_write;
+
+ if (priv->data->nb_zones == NB_ZONES_STM32MP2) {
+ priv->bkpreg_access = stm32_tamp_get_access_rights_mp2x(priv);
+
+ if (IS_ERR(priv->bkpreg_access))
+ return PTR_ERR(priv->bkpreg_access);
+
+ dev_dbg(dev, "\n"
+ "Zone 1-RIF1 %3d - %3d %c%c\n"
+ "Zone 1-RIF2 %3d - %3d %c%c\n"
+ "Zone 2-RIF1 %3d - %3d %c%c\n"
+ "Zone 2-RIF2 %3d - %3d %c%c\n"
+ "Zone 3-RIF1 %3d - %3d %c%c\n"
+ "Zone 3-RIF0 %3d - %3d %c%c\n"
+ "Zone 3-RIF2 %3d - %3d %c%c\n",
+ 0,
+ zones_end[BKPREG_PROTECTION_ZONE_1_RIF1],
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_1_RIF1],
+ true) ? 'R' : '-',
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_1_RIF1],
+ false) ? 'W' : '-',
+ zones_end[BKPREG_PROTECTION_ZONE_1_RIF1] + 1,
+ zones_end[BKPREG_PROTECTION_ZONE_1_RIF2],
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_1_RIF2],
+ true) ? 'R' : '-',
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_1_RIF2],
+ false) ? 'W' : '-',
+ zones_end[BKPREG_PROTECTION_ZONE_1_RIF2] + 1,
+ zones_end[BKPREG_PROTECTION_ZONE_2_RIF1],
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_2_RIF1],
+ true) ? 'R' : '-',
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_2_RIF1],
+ false) ? 'W' : '-',
+ zones_end[BKPREG_PROTECTION_ZONE_2_RIF1] + 1,
+ zones_end[BKPREG_PROTECTION_ZONE_2_RIF2],
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_2_RIF2],
+ true) ? 'R' : '-',
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_2_RIF2],
+ false) ? 'W' : '-',
+ zones_end[BKPREG_PROTECTION_ZONE_2_RIF2] + 1,
+ zones_end[BKPREG_PROTECTION_ZONE_3_RIF1],
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_3_RIF1],
+ true) ? 'R' : '-',
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_3_RIF1],
+ false) ? 'W' : '-',
+ zones_end[BKPREG_PROTECTION_ZONE_3_RIF1] + 1,
+ zones_end[BKPREG_PROTECTION_ZONE_3_RIF0],
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_3_RIF0],
+ true) ? 'R' : '-',
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_3_RIF0],
+ false) ? 'W' : '-',
+ zones_end[BKPREG_PROTECTION_ZONE_3_RIF0] + 1,
+ zones_end[BKPREG_PROTECTION_ZONE_3_RIF2],
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_3_RIF2],
+ true) ? 'R' : '-',
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_3_RIF2],
+ false) ? 'W' : '-'
+ );
+ } else if (priv->data->nb_zones == NB_ZONES_STM32MP1) {
+ priv->bkpreg_access = stm32mp1_tamp_bkpreg_access;
+
+ dev_dbg(dev, "\n"
+ "Zone 1 %3d - %3d %c%c\n"
+ "Zone 2 %3d - %3d %c%c\n"
+ "Zone 3 %3d - %3d %c%c\n",
+ 0,
+ zones_end[BKPREG_PROTECTION_ZONE_1],
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_1],
+ true) ? 'R' : '-',
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_1],
+ false) ? 'W' : '-',
+ zones_end[BKPREG_PROTECTION_ZONE_1] + 1,
+ zones_end[BKPREG_PROTECTION_ZONE_2],
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_2],
+ true) ? 'R' : '-',
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_2],
+ false) ? 'W' : '-',
+ zones_end[BKPREG_PROTECTION_ZONE_2] + 1,
+ zones_end[BKPREG_PROTECTION_ZONE_3],
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_3],
+ true) ? 'R' : '-',
+ stm32_tamp_nvram_rights(priv,
+ zones_end[BKPREG_PROTECTION_ZONE_3],
+ false) ? 'W' : '-');
+ }
+
+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg));
+}
+
+MODULE_DEVICE_TABLE(of, stm32_tamp_nvram_of_match);
+
+static struct platform_driver stm32_tamp_nvram_driver = {
+ .probe = stm32_tamp_nvram_probe,
+ .driver = {
+ .name = "stm32-tamp-nvram",
+ .of_match_table = stm32_tamp_nvram_of_match,
+ },
+};
+
+module_platform_driver(stm32_tamp_nvram_driver)
+MODULE_AUTHOR("Simeon Marijon <simeon.marijon@foss.st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 NVMEM TAMP Backup registers");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v4 2/3] dt-bindings: arm: stm32: allow TAMP nvram child node for syscon
2026-11-04 15:20 ` [PATCH v4 2/3] dt-bindings: arm: stm32: allow TAMP nvram child node for syscon Patrice Chotard
@ 2026-11-04 15:39 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-11-04 15:39 UTC (permalink / raw)
To: Patrice Chotard; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] dt-bindings: arm: stm32: requiring ranges on tamp breaks childless nodes
- [Medium] dt-bindings: arm: stm32: unwieldy conditionals and #size-cells relaxation
- [Low] dt-bindings: arm: stm32: truncated sentence in commit message
--
commit 955fce49004502ff39ca0c0307ffc1b3b2ac4184
Author: Patrice Chotard <patrice.chotard@foss.st.com>
dt-bindings: arm: stm32: allow TAMP nvram child node for syscon
This commit updates Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml
to allow addressing properties (#address-cells, #size-cells, and ranges) and
an nvram child node on st,stm32-tamp nodes.
> dt-bindings: arm: stm32: allow TAMP nvram child node for syscon
>
> The STM32 TAMP node (compatible "st,stm32-tamp", "syscon", "simple-mfd")
> exposes its backup registers through an nvram child node described by
> nvmem/st,stm32-tamp-nvram.yaml. That requires the TAMP node to carry
> "#address-cells", "#size-cells", "ranges" and an "nvram@..." child.
>
> st,stm32-syscon.yaml uses "additionalProperties: false" and only allowed
> into the DTSI made "make dtbs_check" fail on every STM32MP TAMP node:
>
> tamp@5c00a000 (st,stm32-tamp): 'nvram@5c00a100', 'ranges' do not match
> any of the regexes: '^pinctrl-[0-9]+$'
>
> Allow the addressing properties and the nvram child, gated on the
> st,stm32-tamp compatible so the other syscon variants stay strict.
> "#size-cells" may be 1 or 2: the STM32MP21 soc bus uses two size cells
> (an empty "ranges" requires the node to match its parent) while the
> other STM32MP SoCs use one.
>
> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
[Severity: Low]
This isn't a bug, but it looks like a line starting with #address-cells was
stripped as a comment by git commit in the second paragraph, leaving a
truncated sentence ("and only allowed into the DTSI made").
> diff --git a/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml b/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml
> index a559f8b03b842..51cb565e05edb 100644
> --- a/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml
> +++ b/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml
> @@ -43,13 +43,19 @@ properties:
> const: 1
>
> "#size-cells":
> - const: 1
> + enum: [1, 2]
> +
> + ranges: true
>
> patternProperties:
> "^phy@2[48]00$":
> type: object
> $ref: /schemas/phy/st,stm32-usb2phy.yaml
>
> + "^nvram@[0-9a-f]+$":
> + type: object
> + $ref: /schemas/nvmem/st,stm32-tamp-nvram.yaml
> +
> required:
> - compatible
> - reg
> @@ -84,11 +90,37 @@ allOf:
> - phy@2800
> else:
> properties:
> - '#address-cells': false
> '#clock-cells': false
> - '#size-cells': false
> phy@2400: false
> phy@2800: false
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: st,stm32-tamp
> + then:
> + required:
> + - "#address-cells"
> + - "#size-cells"
> + - ranges
[Severity: Medium]
Does unconditionally requiring #address-cells, #size-cells, and ranges for
st,stm32-tamp cause a dtbs_check regression on existing device trees without
child nodes?
In arch/arm/boot/dts/st/stm32mp151.dtsi, the tamp@5c00a000 node has no child
nodes and does not specify #address-cells, #size-cells, or ranges:
tamp: tamp@5c00a000 {
compatible = "st,stm32-tamp", "syscon", "simple-mfd";
reg = <0x5c00a000 0x400>;
};
Additionally, properties.compatible in st,stm32-syscon.yaml allows the
two-item form without simple-mfd:
- items:
- enum:
- st,stm32-tamp
...
- const: syscon
where bus addressing properties would not apply when no child node is
present. Should #address-cells, #size-cells, and ranges remain optional (or
only be required when child nodes are present) so childless st,stm32-tamp
nodes stay valid?
> + else:
> + properties:
> + ranges: false
> + patternProperties:
> + "^nvram@[0-9a-f]+$": false
> + - if:
> + not:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - st,stm32-tamp
> + - st,stm32mp23-syscfg
> + - st,stm32mp25-syscfg
> + then:
> + properties:
> + '#address-cells': false
> + '#size-cells': false
[Severity: Medium]
Because top-level #size-cells in properties was widened from const: 1 to
enum: [1, 2] without restricting 2 to st,stm32-tamp, doesn't this also allow
#size-cells = <2> on st,stm32mp23-syscfg and st,stm32mp25-syscfg?
Also, with st,stm32-tamp now needing its own ranges, nvram@... child pattern,
and #size-cells rules alongside the existing USB2 PHY conditionals for
st,stm32mp23-syscfg and st,stm32mp25-syscfg, would it be cleaner to split
st,stm32-tamp into a separate binding schema document rather than adding more
per-compatible if-then blocks to st,stm32-syscon.yaml?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261104-upstream_nvram_reworked-v4-0-144024496a44@foss.st.com?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-11-04 15:39 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-04 15:20 [PATCH v4 0/3] Add STM32 TAMP nvram driver support Patrice Chotard
2026-11-04 15:20 ` [PATCH v4 1/3] dt-bindings: nvmem: add STM32MPX TAMP backup registers Patrice Chotard
2026-11-04 15:20 ` [PATCH v4 2/3] dt-bindings: arm: stm32: allow TAMP nvram child node for syscon Patrice Chotard
2026-11-04 15:39 ` sashiko-bot
2026-11-04 15:20 ` [PATCH v4 3/3] nvmem: stm32: add TAMP nvmem driver Patrice Chotard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox