From: Simeon Marijon <simeon.mari...@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.mari...@foss.st.com>
Signed-off-by: Patrice Chotard <patrice.chot...@foss.st.com>
Reviewed-by: Patrick Delaunay <patrick.delau...@foss.st.com>

---

Changes in v3:
  - Fix typo in SPDX-License-Identifier

 arch/arm/mach-stm32mp/Kconfig      |   9 +
 arch/arm/mach-stm32mp/Makefile     |   2 +
 arch/arm/mach-stm32mp/tamp_nvram.c | 664 +++++++++++++++++++++++++++++
 3 files changed, 675 insertions(+)
 create mode 100644 arch/arm/mach-stm32mp/tamp_nvram.c

diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
index 002da2e3d3b..d7323659811 100644
--- a/arch/arm/mach-stm32mp/Kconfig
+++ b/arch/arm/mach-stm32mp/Kconfig
@@ -144,6 +144,15 @@ config STM32_ECDSA_VERIFY
          ROM API provided on STM32MP.
          The ROM API is only available during SPL for now.
 
+config STM32MP_TAMP_NVMEM
+       bool "STM32 TAMP backup registers via NVMEM API"
+       select NVMEM
+       default y
+       help
+         Say y to enable the uclass driver for TAMP Backup registers using the
+         NVMEM API. It allows to access to boot mode or others shared 
information
+         between software components/execution levels.
+
 config CMD_STM32KEY
        bool "command stm32key to fuse public key hash"
        depends on CMDLINE
diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile
index 103e3410ad9..ecd49fe668d 100644
--- a/arch/arm/mach-stm32mp/Makefile
+++ b/arch/arm/mach-stm32mp/Makefile
@@ -13,6 +13,8 @@ obj-$(CONFIG_STM32MP13X) += stm32mp1/
 obj-$(CONFIG_STM32MP25X) += stm32mp2/
 
 obj-$(CONFIG_MFD_STM32_TIMERS) += timers.o
+obj-$(CONFIG_STM32MP_TAMP_NVMEM) += tamp_nvram.o
+
 obj-$(CONFIG_STM32_ECDSA_VERIFY) += ecdsa_romapi.o
 ifndef CONFIG_XPL_BUILD
 obj-y += cmd_stm32prog/
diff --git a/arch/arm/mach-stm32mp/tamp_nvram.c 
b/arch/arm/mach-stm32mp/tamp_nvram.c
new file mode 100644
index 00000000000..9edd001b540
--- /dev/null
+++ b/arch/arm/mach-stm32mp/tamp_nvram.c
@@ -0,0 +1,664 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
+/*
+ * Copyright (C) 2025, STMicroelectronics - All Rights Reserved
+ */
+#define LOG_CATEGORY UCLASS_MISC
+
+#include <clk.h>
+#include <dm.h>
+#include <log.h>
+#include <misc.h>
+#include <regmap.h>
+#include <tee.h>
+#include <asm/io.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+
+#define RIF_CID1                       0x1
+#define CURRENT_CID                    RIF_CID1
+#define NB_ZONES_STM32MP1              3
+#define NB_ZONES_STM32MP2              7
+
+#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_plat {
+       void __iomem *base;
+       void __iomem *parent_base;
+       fdt_size_t size;
+       fdt_size_t parent_size;
+       unsigned int nb_total_regs;
+};
+
+struct stm32_tamp_nvram_priv {
+       int *idx_bkpreg_zones_end;
+       struct regmap *config_regmap;
+       struct regmap *bkpregs_regmap;
+       enum stm32_tamp_bkpreg_access *bkpreg_access;
+};
+
+struct stm32_tamp_nvram_drvdata {
+       const unsigned int nb_zones;
+       const struct reg_field *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 const struct stm32_tamp_nvram_drvdata stm32mp1_tamp_nvram = {
+       .nb_zones = NB_ZONES_STM32MP1,
+       .reg_fields = stm32mp1_tamp_nvram_zone_cfg_fields,
+};
+
+static const struct stm32_tamp_nvram_drvdata stm32mp25_tamp_nvram = {
+       .nb_zones = NB_ZONES_STM32MP2,
+       .reg_fields = stm32mp25_tamp_nvram_zone_cfg_fields,
+};
+
+static int stm32_tamp_is_compartment_isolation_enabled_mp2X(struct udevice 
*dev)
+{
+       struct stm32_tamp_nvram_priv *priv = dev_get_priv(dev);
+       int nb_compartment_enabled = 0;
+       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_OR_NULL(cfen_field)) {
+                       dev_err(dev, "Can't allocate field for reading 
configuration\n");
+                       return -ENOMEM;
+               }
+               if (regmap_field_read(cfen_field, &cfen) != 0) {
+                       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 == 0)
+               return 0;
+       else if (nb_compartment_enabled == NB_COMPARTMENT_STM32MP2)
+               return 1;
+       else
+               return -EINVAL;
+}
+
+static bool *stm32_tamp_get_compartment_owner_mp2X(struct udevice *dev)
+{
+       struct stm32_tamp_nvram_priv *priv = dev_get_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(dev);
+       if (isolation_enabled < 0)
+               return NULL;
+
+       compartment_owner = devm_kcalloc(dev,
+                                        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 (regmap_field_read(cid_field, &cid_per_zone) != 0) {
+                               dev_err(dev, "Can't read field for registers 
zones\n");
+                               devm_regmap_field_free(dev, cid_field);
+                               devm_kfree(dev, 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 
udevice *dev)
+{
+       struct stm32_tamp_nvram_drvdata *drvdata =
+               (struct stm32_tamp_nvram_drvdata *)dev_get_driver_data(dev);
+       unsigned int nb_zones = drvdata->nb_zones;
+       bool *compartment_owner;
+       enum stm32_tamp_bkpreg_access *bkpreg_access;
+
+       compartment_owner = stm32_tamp_get_compartment_owner_mp2X(dev);
+       if (IS_ERR(compartment_owner))
+               return ERR_PTR(-ENODEV);
+
+       bkpreg_access = devm_kcalloc(dev,
+                                    NB_ZONES_STM32MP2,
+                                    sizeof(*bkpreg_access),
+                                    GFP_KERNEL);
+
+       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);
+                       return ERR_PTR(-ENODEV);
+               }
+       }
+
+       return bkpreg_access;
+}
+
+static int stm32_tamp_nvram_bkpreg_get_zone_idx(struct udevice *dev, int reg)
+{
+       struct stm32_tamp_nvram_priv *priv = dev_get_priv(dev);
+       struct stm32_tamp_nvram_drvdata *drvdata =
+               (struct stm32_tamp_nvram_drvdata *)dev_get_driver_data(dev);
+       int *idx_bkpreg_zones_end = priv->idx_bkpreg_zones_end;
+       int nb_zones = drvdata->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 udevice *dev, int reg, bool 
read_only)
+{
+       struct stm32_tamp_nvram_priv *priv = dev_get_priv(dev);
+       int protection_zone_idx = stm32_tamp_nvram_bkpreg_get_zone_idx(dev, 
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 int stm32_tamp_nvram_write_byte(struct udevice *dev, u32 offset, u8 
byte)
+{
+       struct stm32_tamp_nvram_priv *priv = dev_get_priv(dev);
+       int offset_aligned = ALIGN_DOWN(offset, sizeof(u32));
+       int byte_in_word = offset - offset_aligned;
+       u32 read_value, to_be_writen_value;
+       u32 reg_idx = offset_aligned / sizeof(u32);
+
+       if (!stm32_tamp_nvram_rights(dev, reg_idx, false))
+               return -EIO;
+
+       regmap_read(priv->bkpregs_regmap, offset_aligned, &read_value);
+       to_be_writen_value = read_value & ~(0xFFUL << byte_in_word * 8);
+       to_be_writen_value |=  (u32)byte << (byte_in_word * 8);
+
+       return regmap_write(priv->bkpregs_regmap, offset_aligned, 
to_be_writen_value);
+}
+
+static int stm32_tamp_nvram_read_byte(struct udevice *dev, unsigned int 
offset, u8 *byte)
+{
+       struct stm32_tamp_nvram_priv *priv = dev_get_priv(dev);
+       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);
+
+       if (!stm32_tamp_nvram_rights(dev, reg_idx, true))
+               return -EIO;
+
+       regmap_read(priv->bkpregs_regmap, offset_aligned, &read_value);
+       *byte = (read_value >> (byte_in_word * 8)) & 0xFF;
+
+       return 0;
+}
+
+static int stm32_tamp_nvram_read(struct udevice *dev, int offset, void *buf, 
int size)
+{
+       struct stm32_tamp_nvram_priv *priv = dev_get_priv(dev);
+       u8 byte;
+       u8 *buf_u8 = buf;
+       u32 temp_u32;
+       int i, ret;
+       int total = offset + size;
+       u32 reg_idx;
+
+       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(dev, reg_idx, true)) {
+                               dev_dbg(dev, "Backup register %u is not allowed 
to be read\n",
+                                       reg_idx);
+                               temp_u32 = 0;
+                       } else {
+                               regmap_read(priv->bkpregs_regmap, i, &temp_u32);
+                       }
+                       memcpy(buf_u8, &temp_u32, sizeof(u32));
+                       buf_u8 += sizeof(u32);
+                       i += sizeof(u32);
+               } else {
+                       ret = stm32_tamp_nvram_read_byte(dev, i, &byte);
+                       if (ret != 0) {
+                               dev_dbg(dev, "Backup register %u is not allowed 
to be read\n",
+                                       reg_idx);
+                               byte = 0;
+                       }
+                       *buf_u8 = byte;
+                       i++;
+                       buf_u8++;
+               }
+       }
+
+       return size;
+}
+
+static int stm32_tamp_nvram_write(struct udevice *dev, int offset, const void 
*buf, int size)
+{
+       struct stm32_tamp_nvram_priv *priv = dev_get_priv(dev);
+       u8 *buf_u8 = (u8 *)buf;
+       u32 temp_u32;
+       size_t total = offset + size;
+       int i, ret;
+       u32 reg_idx;
+
+       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(dev, reg_idx, false)) {
+                               memcpy(&temp_u32, buf_u8, sizeof(u32));
+                               regmap_write(priv->bkpregs_regmap, i, temp_u32);
+                       } else {
+                               dev_dbg(dev, "Backup register %u is not allowed 
to be written",
+                                       reg_idx);
+                       }
+                       buf_u8 += sizeof(u32);
+                       i += sizeof(u32);
+               } else {
+                       ret = stm32_tamp_nvram_write_byte(dev, i, *buf_u8);
+                       if (ret != 0)
+                               dev_dbg(dev, "Backup register %u is not allowed 
to be written",
+                                       reg_idx);
+                       i++;
+                       buf_u8++;
+               }
+       }
+
+       return size;
+}
+
+static const struct misc_ops stm32_tamp_nvram_ops = {
+       .read = stm32_tamp_nvram_read,
+       .write = stm32_tamp_nvram_write,
+};
+
+static u32 *stm32_tamp_nvram_get_backup_zones(struct udevice *dev)
+{
+       struct stm32_tamp_nvram_plat *plat = dev_get_plat(dev);
+       struct stm32_tamp_nvram_priv *priv = dev_get_priv(dev);
+       const struct stm32_tamp_nvram_drvdata *drvdata =
+               (struct stm32_tamp_nvram_drvdata *)dev_get_driver_data(dev);
+       int nb_zones = drvdata->nb_zones;
+       int zone_idx;
+       int *idx_bkpreg_zones_end;
+       struct regmap *tamp_regmap = priv->config_regmap;
+       u32 offset_field;
+
+       idx_bkpreg_zones_end = devm_kcalloc(dev,
+                                           sizeof(*idx_bkpreg_zones_end),
+                                           nb_zones,
+                                           GFP_KERNEL);
+       if (IS_ERR_OR_NULL(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 = 
drvdata->reg_fields[zone_idx];
+               struct regmap_field *field = devm_regmap_field_alloc(dev,
+                                                                    
tamp_regmap,
+                                                                    reg_field);
+
+               if (IS_ERR_OR_NULL(field)) {
+                       dev_err(dev, "Can't allocate registers zones\n");
+                       devm_kfree(dev, idx_bkpreg_zones_end);
+                       return ERR_PTR(-ENOMEM);
+               }
+               if (regmap_field_read(field, &offset_field) != 0) {
+                       dev_err(dev, "Can't read field for registers zones\n");
+                       devm_kfree(dev, idx_bkpreg_zones_end);
+                       return ERR_PTR(-EIO);
+               }
+
+               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] = plat->nb_total_regs - 1;
+
+       return idx_bkpreg_zones_end;
+}
+
+static void stm32_tamp_nvram_print_zones(struct udevice *dev)
+{
+       struct stm32_tamp_nvram_priv *priv = dev_get_priv(dev);
+       int *zones_end = priv->idx_bkpreg_zones_end;
+
+       if (device_is_compatible(dev, "st,stm32mp25-tamp-nvram")) {
+               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(dev, 
zones_end[BKPREG_PROTECTION_ZONE_1_RIF1],
+                                               true) ?
+                               'R' :
+                               '-',
+                       stm32_tamp_nvram_rights(dev, 
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(dev, 
zones_end[BKPREG_PROTECTION_ZONE_1_RIF2],
+                                               true) ?
+                               'R' :
+                               '-',
+                       stm32_tamp_nvram_rights(dev, 
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(dev, 
zones_end[BKPREG_PROTECTION_ZONE_2_RIF1],
+                                               true) ?
+                               'R' :
+                               '-',
+                       stm32_tamp_nvram_rights(dev, 
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(dev, 
zones_end[BKPREG_PROTECTION_ZONE_2_RIF2],
+                                               true) ?
+                               'R' :
+                               '-',
+                       stm32_tamp_nvram_rights(dev, 
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(dev, 
zones_end[BKPREG_PROTECTION_ZONE_3_RIF1],
+                                               true) ?
+                               'R' :
+                               '-',
+                       stm32_tamp_nvram_rights(dev, 
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(dev, 
zones_end[BKPREG_PROTECTION_ZONE_3_RIF0],
+                                               true) ?
+                               'R' :
+                               '-',
+                       stm32_tamp_nvram_rights(dev, 
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(dev, 
zones_end[BKPREG_PROTECTION_ZONE_3_RIF2],
+                                               true) ?
+                               'R' :
+                               '-',
+                       stm32_tamp_nvram_rights(dev, 
zones_end[BKPREG_PROTECTION_ZONE_3_RIF2],
+                                               false) ?
+                               'W' :
+                               '-');
+       } else if (device_is_compatible(dev, "st,stm32mp15-tamp-nvram")) {
+               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(dev, 
zones_end[BKPREG_PROTECTION_ZONE_1], true) ?
+                               'R' :
+                               '-',
+                       stm32_tamp_nvram_rights(dev, 
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(dev, 
zones_end[BKPREG_PROTECTION_ZONE_2], true) ?
+                               'R' :
+                               '-',
+                       stm32_tamp_nvram_rights(dev, 
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(dev, 
zones_end[BKPREG_PROTECTION_ZONE_3], true) ?
+                               'R' :
+                               '-',
+                       stm32_tamp_nvram_rights(dev, 
zones_end[BKPREG_PROTECTION_ZONE_3], false) ?
+                               'W' :
+                               '-');
+       }
+}
+
+static int stm32_tamp_nvram_of_to_plat(struct udevice *dev)
+{
+       struct stm32_tamp_nvram_plat *plat = dev_get_plat(dev);
+       fdt_addr_t addr = dev_read_addr_size_index(dev, 0, &plat->size);
+       fdt_addr_t parent_addr = dev_read_addr_size_index(dev->parent, 0, 
&plat->parent_size);
+
+       if (addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+       plat->base = (void __iomem *)addr;
+
+       if (parent_addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+       plat->parent_base = (void __iomem *)parent_addr;
+
+       if (plat->size == FDT_ADDR_T_NONE)
+               return -EOPNOTSUPP;
+
+       plat->nb_total_regs =  plat->size / sizeof(uint32_t);
+
+       return 0;
+}
+
+static int stm32_tamp_nvram_probe(struct udevice *dev)
+{
+       struct stm32_tamp_nvram_plat *plat = dev_get_plat(dev);
+       struct stm32_tamp_nvram_priv *priv = dev_get_priv(dev);
+       struct regmap_config config_regmap;
+       struct regmap_config bckreg_regmap;
+
+       config_regmap.r_start = (ulong)(plat->parent_base);
+       config_regmap.r_size = plat->parent_size;
+       config_regmap.reg_offset_shift = 0;
+       config_regmap.width = REGMAP_SIZE_32;
+       priv->config_regmap = devm_regmap_init(dev, NULL, NULL, &config_regmap);
+
+       bckreg_regmap.r_start = (ulong)(plat->base);
+       bckreg_regmap.r_size = plat->size;
+       bckreg_regmap.reg_offset_shift = 0;
+       bckreg_regmap.width = REGMAP_SIZE_32;
+       priv->bkpregs_regmap = devm_regmap_init(dev, NULL, NULL, 
&bckreg_regmap);
+
+       priv->idx_bkpreg_zones_end = stm32_tamp_nvram_get_backup_zones(dev);
+       if (IS_ERR_OR_NULL(priv->idx_bkpreg_zones_end)) {
+               dev_err(dev, "Failed to get the backup zone from tamp 
regs\n\n");
+               return -ENODEV;
+       }
+
+       if (device_is_compatible(dev, "st,stm32mp25-tamp-nvram")) {
+               priv->bkpreg_access = stm32_tamp_get_access_rights_mp2X(dev);
+               if (IS_ERR_OR_NULL(priv->bkpreg_access))
+                       return -ENODEV;
+       } else {
+               priv->bkpreg_access = stm32mp1_tamp_bkpreg_access;
+       }
+
+       stm32_tamp_nvram_print_zones(dev);
+
+       return 0;
+}
+
+static int stm32_tamp_nvram_remove(struct udevice *dev)
+{
+       return 0;
+}
+
+static const struct udevice_id stm32_tamp_nvram_ids[] = {
+       { .compatible = "st,stm32mp15-tamp-nvram", .data = 
(ulong)&stm32mp1_tamp_nvram },
+       { .compatible = "st,stm32mp25-tamp-nvram", .data = 
(ulong)&stm32mp25_tamp_nvram },
+       {},
+};
+
+U_BOOT_DRIVER(stm32_tamp_nvram) = {
+       .name = "stm32_tamp_nvram",
+       .id = UCLASS_MISC,
+       .of_match = stm32_tamp_nvram_ids,
+       .priv_auto = sizeof(struct stm32_tamp_nvram_priv),
+       .plat_auto = sizeof(struct stm32_tamp_nvram_plat),
+       .ops = &stm32_tamp_nvram_ops,
+       .of_to_plat = of_match_ptr(stm32_tamp_nvram_of_to_plat),
+       .probe = stm32_tamp_nvram_probe,
+       .remove = stm32_tamp_nvram_remove,
+};
+
-- 
2.25.1

base-commit: cb7555e93075114fe4af0adb806877ac4d4ef80d
branch: upstream_nvram_driver_v3

Reply via email to