On 5/5/25 14:38, Patrick DELAUNAY wrote:
> Hi,
>
> minor remark to be coherent between SoC family
>
> STM32MP1 <=> STM32MP2 for some part of the driver code
>
> but STM32MP1 <=> STM32MP25 for other part of the code
>
> and stm32mp15 <=> stm32mp25 for compatible
>
>
> On 4/29/25 08:53, Patrice Chotard wrote:
>> 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;
>
> + const enum stm32_tamp_bkpreg_access *bkpreg_access;
>
> as the acesss right are fixed after probe
ok
>
>
>> +};
>> +
>> +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),
>> +};
>> +
>
> I propose to rename it to
>
> stm32mp2_tamp_nvram_zone_cfg_fields[]
>
> to be coherent with stm32mp1_tamp_nvram_zone_cfg_fields[]
>
> and same for other array
>
> stm32mp2_tamp_nvram_rxcidcfg_cfen_fields[]
> stm32mp2_tamp_nvram_rxcidcfg_fields[]
ok
>
>> +static const struct reg_field [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,
>> +};
>> +
>
>
> please change to
>
> static const enum stm32_tamp_bkpreg_access
> stm32mp1_tamp_bkpreg_access[NB_ZONES_STM32MP1] = {
>
done
>
>> +static const struct stm32_tamp_nvram_drvdata stm32mp1_tamp_nvram = {
>> + .nb_zones = NB_ZONES_STM32MP1,
>> + .reg_fields = stm32mp1_tamp_nvram_zone_cfg_fields,
>> +};
>> +
>
> and to "stm32mp2_tamp_nvram"
done
>
>> +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)
I proposed also to rename this function to
stm32mp2_tamp_is_compartment_isolation_enabled
>> +{
>> + 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;
>> +}
>
> function name can be more simple: stm32mp2_tamp_get_compartment_owner()
done
>
>> +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;
>> +}
>> +
>
> same here => stm32mp2_tamp_get_access_rights()
>
> and return const (the generated array is not mofdifiable)
>
> +static const enum stm32_tamp_bkpreg_access
> *stm32mp2_tamp_get_access_rights(struct udevice *dev)
done
>
>> +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;
>> + }
>> +
>
> to need to check the compatible , information is already provide by ucall
> with drvdata
>
> + const struct stm32_tamp_nvram_drvdata *drvdata =
> + (struct stm32_tamp_nvram_drvdata *)dev_get_driver_data(dev);
> + if (drvdata == &stm32mp25_tamp_nvram) {
>
done
>> + 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;
>> + }
>> +
>
> or better
>
> or add element in drvdata
>
> struct stm32_tamp_nvram_drvdata {
> const unsigned int nb_zones;
> const struct reg_field *reg_fields;
> + const enum stm32_tamp_bkpreg_access (*get_access)(struct udevice *dev)
> };
>
> with :
>
> static const enum stm32_tamp_bkpreg_access
> *stm32mp1_tamp_get_access_rights(struct udevice *dev) {
> return stm32mp1_tamp_bkpreg_access;
> }
>
>
> and with :
>
> stm32mp1_tamp_nvram.get_access = stm32mp1_tamp_get_access_rights;
>
> stm32mp2_tamp_nvram.get_access = stm32mp2_tamp_get_access_rights;
>
>
> all this code becomes generic
>
> priv->bkpreg_access = drvdata->get_access(dev);
ok, perfect ;-)
>
>> + 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,
>> +};
>> +
>
>
> Regards
>
>
> Patrick
>