[PATCH 1/2] stm32mp: bsec: add permanent lock write support

Add support of the permanent lock support in U-Boot proper when BSEC is not managed by secure monitor (TF-A SP_MIN or OP-TEE).
This patch avoid issue with stm32key command and fuse command on basic boot for this missing feature of U-Boot BSEC driver.
Reported-by: Johann Neuhauser jneuhauser@dh-electronics.com Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com ---
arch/arm/mach-stm32mp/bsec.c | 90 +++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 27d1829501..fd6e1a3957 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -18,6 +18,7 @@ #include <linux/iopoll.h>
#define BSEC_OTP_MAX_VALUE 95 +#define BSEC_OTP_UPPER_START 32 #define BSEC_TIMEOUT_US 10000
/* BSEC REGISTER OFFSET (base relative) */ @@ -41,6 +42,7 @@ /* BSEC_CONTROL Register */ #define BSEC_READ 0x000 #define BSEC_WRITE 0x100 +#define BSEC_LOCK 0x200
/* LOCK Register */ #define OTP_LOCK_MASK 0x1F @@ -61,6 +63,11 @@ */ #define BSEC_LOCK_PROGRAM 0x04
+/* + * OTP status: bit 0 permanent lock + */ +#define BSEC_LOCK_PERM BIT(0) + /** * bsec_lock() - manage lock for each type SR/SP/SW * @address: address of bsec IP register @@ -284,6 +291,65 @@ static int bsec_program_otp(struct udevice *dev, long base, u32 val, u32 otp) return ret; }
+/** + * bsec_permanent_lock_otp() - permanent lock of OTP in SAFMEM + * @dev: bsec IP device + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: 0 if no error + */ +static int bsec_permanent_lock_otp(struct udevice *dev, long base, uint32_t otp) +{ + int ret; + bool power_up = false; + u32 val, addr; + + /* check if safemem is power up */ + if (!(readl(base + BSEC_OTP_STATUS_OFF) & BSEC_MODE_PWR_MASK)) { + ret = bsec_power_safmem(base, true); + if (ret) + return ret; + + power_up = true; + } + + /* + * low OTPs = 2 bits word for low OTPs, 1 bits per word for upper OTP + * and only 16 bits used in WRDATA + */ + if (otp < BSEC_OTP_UPPER_START) { + addr = otp / 8; + val = 0x03 << ((otp * 2) & 0xF); + } else { + addr = BSEC_OTP_UPPER_START / 8 + + ((otp - BSEC_OTP_UPPER_START) / 16); + val = 0x01 << (otp & 0xF); + } + + /* set value in write register*/ + writel(val, base + BSEC_OTP_WRDATA_OFF); + + /* set BSEC_OTP_CTRL_OFF with the otp addr and lock request*/ + writel(addr | BSEC_WRITE | BSEC_LOCK, base + BSEC_OTP_CTRL_OFF); + + /* check otp status*/ + ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF, + val, (val & BSEC_MODE_BUSY_MASK) == 0, + BSEC_TIMEOUT_US); + if (ret) + return ret; + + if (val & BSEC_MODE_PROGFAIL_MASK) + ret = -EACCES; + else + ret = bsec_check_error(base, otp); + + if (power_up) + bsec_power_safmem(base, false); + + return ret; +} + /* BSEC MISC driver *******************************************************/ struct stm32mp_bsec_plat { u32 base; @@ -339,9 +405,14 @@ static int stm32mp_bsec_read_shadow(struct udevice *dev, u32 *val, u32 otp) static int stm32mp_bsec_read_lock(struct udevice *dev, u32 *val, u32 otp) { struct stm32mp_bsec_plat *plat = dev_get_plat(dev); + u32 wrlock;
/* return OTP permanent write lock status */ - *val = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp); + wrlock = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp); + + *val = 0; + if (wrlock) + *val = BSEC_LOCK_PERM;
return 0; } @@ -377,15 +448,22 @@ static int stm32mp_bsec_write_shadow(struct udevice *dev, u32 val, u32 otp)
static int stm32mp_bsec_write_lock(struct udevice *dev, u32 val, u32 otp) { - if (!IS_ENABLED(CONFIG_ARM_SMCCC) || IS_ENABLED(CONFIG_SPL_BUILD)) - return -ENOTSUPP; + struct stm32mp_bsec_plat *plat; + + /* only permanent write lock is supported in U-Boot */ + if (!(val & BSEC_LOCK_PERM)) { + dev_dbg(dev, "lock option without BSEC_LOCK_PERM: %x\n", val); + return 0; /* nothing to do */ + }
- if (val == 1) + if (IS_ENABLED(CONFIG_ARM_SMCCC) && !IS_ENABLED(CONFIG_SPL_BUILD)) return stm32_smc_exec(STM32_SMC_BSEC, STM32_SMC_WRLOCK_OTP, otp, 0); - if (val == 0) - return 0; /* nothing to do */ + + plat = dev_get_plat(dev); + + return bsec_permanent_lock_otp(dev, plat->base, otp);
return -EINVAL; }

Add the missing @dev reference in some function description.
Fixes: b66bfdf238b9 ("arm: stm32mp: bsec: migrate trace to log macro") Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com ---
arch/arm/mach-stm32mp/bsec.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index fd6e1a3957..506caa0a31 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -167,6 +167,7 @@ static int bsec_power_safmem(u32 base, bool power)
/** * bsec_shadow_register() - copy safmen otp to bsec data + * @dev: bsec IP device * @base: base address of bsec IP * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) * Return: 0 if no error @@ -210,6 +211,7 @@ static int bsec_shadow_register(struct udevice *dev, u32 base, u32 otp)
/** * bsec_read_shadow() - read an otp data value from shadow + * @dev: bsec IP device * @base: base address of bsec IP * @val: read value * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) @@ -224,6 +226,7 @@ static int bsec_read_shadow(struct udevice *dev, u32 base, u32 *val, u32 otp)
/** * bsec_write_shadow() - write value in BSEC data register in shadow + * @dev: bsec IP device * @base: base address of bsec IP * @val: value to write * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) @@ -242,6 +245,7 @@ static int bsec_write_shadow(struct udevice *dev, u32 base, u32 val, u32 otp)
/** * bsec_program_otp() - program a bit in SAFMEM + * @dev: bsec IP device * @base: base address of bsec IP * @val: value to program * @otp: otp number (0 - BSEC_OTP_MAX_VALUE)

Hi Patrick
On 2/15/22 16:08, Patrick Delaunay wrote:
Add the missing @dev reference in some function description.
Fixes: b66bfdf238b9 ("arm: stm32mp: bsec: migrate trace to log macro") Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com
arch/arm/mach-stm32mp/bsec.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index fd6e1a3957..506caa0a31 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -167,6 +167,7 @@ static int bsec_power_safmem(u32 base, bool power)
/**
- bsec_shadow_register() - copy safmen otp to bsec data
- @dev: bsec IP device
- @base: base address of bsec IP
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
- Return: 0 if no error
@@ -210,6 +211,7 @@ static int bsec_shadow_register(struct udevice *dev, u32 base, u32 otp)
/**
- bsec_read_shadow() - read an otp data value from shadow
- @dev: bsec IP device
- @base: base address of bsec IP
- @val: read value
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
@@ -224,6 +226,7 @@ static int bsec_read_shadow(struct udevice *dev, u32 base, u32 *val, u32 otp)
/**
- bsec_write_shadow() - write value in BSEC data register in shadow
- @dev: bsec IP device
- @base: base address of bsec IP
- @val: value to write
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
@@ -242,6 +245,7 @@ static int bsec_write_shadow(struct udevice *dev, u32 base, u32 val, u32 otp)
/**
- bsec_program_otp() - program a bit in SAFMEM
- @dev: bsec IP device
- @base: base address of bsec IP
- @val: value to program
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
Reviewed-by: Patrice Chotard patrice.chotard@foss.st.com
Thanks Patrice

Hi PAtrick
On 2/15/22 16:08, Patrick Delaunay wrote:
Add the missing @dev reference in some function description.
Fixes: b66bfdf238b9 ("arm: stm32mp: bsec: migrate trace to log macro") Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com
arch/arm/mach-stm32mp/bsec.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index fd6e1a3957..506caa0a31 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -167,6 +167,7 @@ static int bsec_power_safmem(u32 base, bool power)
/**
- bsec_shadow_register() - copy safmen otp to bsec data
- @dev: bsec IP device
- @base: base address of bsec IP
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
- Return: 0 if no error
@@ -210,6 +211,7 @@ static int bsec_shadow_register(struct udevice *dev, u32 base, u32 otp)
/**
- bsec_read_shadow() - read an otp data value from shadow
- @dev: bsec IP device
- @base: base address of bsec IP
- @val: read value
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
@@ -224,6 +226,7 @@ static int bsec_read_shadow(struct udevice *dev, u32 base, u32 *val, u32 otp)
/**
- bsec_write_shadow() - write value in BSEC data register in shadow
- @dev: bsec IP device
- @base: base address of bsec IP
- @val: value to write
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
@@ -242,6 +245,7 @@ static int bsec_write_shadow(struct udevice *dev, u32 base, u32 val, u32 otp)
/**
- bsec_program_otp() - program a bit in SAFMEM
- @dev: bsec IP device
- @base: base address of bsec IP
- @val: value to program
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
Applied to u-boot-stm32
Thanks Patrice

-----Original Message----- From: Patrick Delaunay [mailto:patrick.delaunay@foss.st.com] Sent: Tuesday, February 15, 2022 4:09 PM
Add support of the permanent lock support in U-Boot proper when BSEC is not managed by secure monitor (TF-A SP_MIN or OP-TEE).
This patch avoid issue with stm32key command and fuse command on basic boot for this missing feature of U-Boot BSEC driver.
Reported-by: Johann Neuhauser jneuhauser@dh-electronics.com Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com
arch/arm/mach-stm32mp/bsec.c | 90 +++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 27d1829501..fd6e1a3957 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -18,6 +18,7 @@ #include <linux/iopoll.h>
#define BSEC_OTP_MAX_VALUE 95 +#define BSEC_OTP_UPPER_START 32 #define BSEC_TIMEOUT_US 10000
/* BSEC REGISTER OFFSET (base relative) */ @@ -41,6 +42,7 @@ /* BSEC_CONTROL Register */ #define BSEC_READ 0x000 #define BSEC_WRITE 0x100 +#define BSEC_LOCK 0x200
/* LOCK Register */ #define OTP_LOCK_MASK 0x1F @@ -61,6 +63,11 @@ */ #define BSEC_LOCK_PROGRAM 0x04
+/*
- OTP status: bit 0 permanent lock
- */
+#define BSEC_LOCK_PERM BIT(0)
/**
- bsec_lock() - manage lock for each type SR/SP/SW
- @address: address of bsec IP register
@@ -284,6 +291,65 @@ static int bsec_program_otp(struct udevice *dev, long base, u32 val, u32 otp) return ret; }
+/**
- bsec_permanent_lock_otp() - permanent lock of OTP in SAFMEM
- @dev: bsec IP device
- @base: base address of bsec IP
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
- Return: 0 if no error
- */
+static int bsec_permanent_lock_otp(struct udevice *dev, long base, uint32_t otp) +{
int ret;
bool power_up = false;
u32 val, addr;
/* check if safemem is power up */
if (!(readl(base + BSEC_OTP_STATUS_OFF) & BSEC_MODE_PWR_MASK)) {
ret = bsec_power_safmem(base, true);
if (ret)
return ret;
power_up = true;
}
/*
* low OTPs = 2 bits word for low OTPs, 1 bits per word for upper OTP
* and only 16 bits used in WRDATA
*/
if (otp < BSEC_OTP_UPPER_START) {
addr = otp / 8;
val = 0x03 << ((otp * 2) & 0xF);
} else {
addr = BSEC_OTP_UPPER_START / 8 +
((otp - BSEC_OTP_UPPER_START) / 16);
val = 0x01 << (otp & 0xF);
}
/* set value in write register*/
writel(val, base + BSEC_OTP_WRDATA_OFF);
/* set BSEC_OTP_CTRL_OFF with the otp addr and lock request*/
writel(addr | BSEC_WRITE | BSEC_LOCK, base + BSEC_OTP_CTRL_OFF);
/* check otp status*/
ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF,
val, (val & BSEC_MODE_BUSY_MASK) == 0,
BSEC_TIMEOUT_US);
if (ret)
return ret;
if (val & BSEC_MODE_PROGFAIL_MASK)
ret = -EACCES;
else
ret = bsec_check_error(base, otp);
if (power_up)
bsec_power_safmem(base, false);
return ret;
+}
/* BSEC MISC driver *******************************************************/ struct stm32mp_bsec_plat { u32 base; @@ -339,9 +405,14 @@ static int stm32mp_bsec_read_shadow(struct udevice *dev, u32 *val, u32 otp) static int stm32mp_bsec_read_lock(struct udevice *dev, u32 *val, u32 otp) { struct stm32mp_bsec_plat *plat = dev_get_plat(dev);
u32 wrlock; /* return OTP permanent write lock status */
*val = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp);
wrlock = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp);
*val = 0;
if (wrlock)
*val = BSEC_LOCK_PERM; return 0;
} @@ -377,15 +448,22 @@ static int stm32mp_bsec_write_shadow(struct udevice *dev, u32 val, u32 otp)
static int stm32mp_bsec_write_lock(struct udevice *dev, u32 val, u32 otp) {
if (!IS_ENABLED(CONFIG_ARM_SMCCC) || IS_ENABLED(CONFIG_SPL_BUILD))
return -ENOTSUPP;
struct stm32mp_bsec_plat *plat;
/* only permanent write lock is supported in U-Boot */
if (!(val & BSEC_LOCK_PERM)) {
dev_dbg(dev, "lock option without BSEC_LOCK_PERM: %x\n", val);
return 0; /* nothing to do */
}
if (val == 1)
if (IS_ENABLED(CONFIG_ARM_SMCCC) && !IS_ENABLED(CONFIG_SPL_BUILD)) return stm32_smc_exec(STM32_SMC_BSEC, STM32_SMC_WRLOCK_OTP, otp, 0);
if (val == 0)
return 0; /* nothing to do */
plat = dev_get_plat(dev);
return bsec_permanent_lock_otp(dev, plat->base, otp); return -EINVAL;
}
2.25.1
Tested-by: Johann Neuhauser jneuhauser@dh-electronics.com

Hi Patrick
2 minor remarks below
On 2/15/22 16:08, Patrick Delaunay wrote:
Add support of the permanent lock support in U-Boot proper when BSEC is not managed by secure monitor (TF-A SP_MIN or OP-TEE).
This patch avoid issue with stm32key command and fuse command
s/avoid/avoids
on basic boot for this missing feature of U-Boot BSEC driver.
Reported-by: Johann Neuhauser jneuhauser@dh-electronics.com Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com
arch/arm/mach-stm32mp/bsec.c | 90 +++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 27d1829501..fd6e1a3957 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -18,6 +18,7 @@ #include <linux/iopoll.h>
#define BSEC_OTP_MAX_VALUE 95 +#define BSEC_OTP_UPPER_START 32 #define BSEC_TIMEOUT_US 10000
/* BSEC REGISTER OFFSET (base relative) */ @@ -41,6 +42,7 @@ /* BSEC_CONTROL Register */ #define BSEC_READ 0x000 #define BSEC_WRITE 0x100 +#define BSEC_LOCK 0x200
/* LOCK Register */ #define OTP_LOCK_MASK 0x1F @@ -61,6 +63,11 @@ */ #define BSEC_LOCK_PROGRAM 0x04
+/*
- OTP status: bit 0 permanent lock
- */
+#define BSEC_LOCK_PERM BIT(0)
/**
- bsec_lock() - manage lock for each type SR/SP/SW
- @address: address of bsec IP register
@@ -284,6 +291,65 @@ static int bsec_program_otp(struct udevice *dev, long base, u32 val, u32 otp) return ret; }
+/**
- bsec_permanent_lock_otp() - permanent lock of OTP in SAFMEM
- @dev: bsec IP device
- @base: base address of bsec IP
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
- Return: 0 if no error
- */
+static int bsec_permanent_lock_otp(struct udevice *dev, long base, uint32_t otp) +{
- int ret;
- bool power_up = false;
- u32 val, addr;
- /* check if safemem is power up */
- if (!(readl(base + BSEC_OTP_STATUS_OFF) & BSEC_MODE_PWR_MASK)) {
ret = bsec_power_safmem(base, true);
if (ret)
return ret;
power_up = true;
- }
- /*
* low OTPs = 2 bits word for low OTPs, 1 bits per word for upper OTP
s/2 bits word/2 bits per word
* and only 16 bits used in WRDATA
*/
- if (otp < BSEC_OTP_UPPER_START) {
addr = otp / 8;
val = 0x03 << ((otp * 2) & 0xF);
- } else {
addr = BSEC_OTP_UPPER_START / 8 +
((otp - BSEC_OTP_UPPER_START) / 16);
val = 0x01 << (otp & 0xF);
- }
- /* set value in write register*/
- writel(val, base + BSEC_OTP_WRDATA_OFF);
- /* set BSEC_OTP_CTRL_OFF with the otp addr and lock request*/
- writel(addr | BSEC_WRITE | BSEC_LOCK, base + BSEC_OTP_CTRL_OFF);
- /* check otp status*/
- ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF,
val, (val & BSEC_MODE_BUSY_MASK) == 0,
BSEC_TIMEOUT_US);
- if (ret)
return ret;
- if (val & BSEC_MODE_PROGFAIL_MASK)
ret = -EACCES;
- else
ret = bsec_check_error(base, otp);
- if (power_up)
bsec_power_safmem(base, false);
- return ret;
+}
/* BSEC MISC driver *******************************************************/ struct stm32mp_bsec_plat { u32 base; @@ -339,9 +405,14 @@ static int stm32mp_bsec_read_shadow(struct udevice *dev, u32 *val, u32 otp) static int stm32mp_bsec_read_lock(struct udevice *dev, u32 *val, u32 otp) { struct stm32mp_bsec_plat *plat = dev_get_plat(dev);
u32 wrlock;
/* return OTP permanent write lock status */
- *val = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp);
wrlock = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp);
*val = 0;
if (wrlock)
*val = BSEC_LOCK_PERM;
return 0;
} @@ -377,15 +448,22 @@ static int stm32mp_bsec_write_shadow(struct udevice *dev, u32 val, u32 otp)
static int stm32mp_bsec_write_lock(struct udevice *dev, u32 val, u32 otp) {
- if (!IS_ENABLED(CONFIG_ARM_SMCCC) || IS_ENABLED(CONFIG_SPL_BUILD))
return -ENOTSUPP;
- struct stm32mp_bsec_plat *plat;
- /* only permanent write lock is supported in U-Boot */
- if (!(val & BSEC_LOCK_PERM)) {
dev_dbg(dev, "lock option without BSEC_LOCK_PERM: %x\n", val);
return 0; /* nothing to do */
- }
- if (val == 1)
- if (IS_ENABLED(CONFIG_ARM_SMCCC) && !IS_ENABLED(CONFIG_SPL_BUILD)) return stm32_smc_exec(STM32_SMC_BSEC, STM32_SMC_WRLOCK_OTP, otp, 0);
- if (val == 0)
return 0; /* nothing to do */
plat = dev_get_plat(dev);
return bsec_permanent_lock_otp(dev, plat->base, otp);
return -EINVAL;
}
Reviewed-by: Patrice Chotard patrice.chotard@foss.st.com
Thanks Patrice

HI Patrick
On 2/15/22 16:08, Patrick Delaunay wrote:
Add support of the permanent lock support in U-Boot proper when BSEC is not managed by secure monitor (TF-A SP_MIN or OP-TEE).
This patch avoid issue with stm32key command and fuse command on basic boot for this missing feature of U-Boot BSEC driver.
Reported-by: Johann Neuhauser jneuhauser@dh-electronics.com Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com
arch/arm/mach-stm32mp/bsec.c | 90 +++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 27d1829501..fd6e1a3957 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -18,6 +18,7 @@ #include <linux/iopoll.h>
#define BSEC_OTP_MAX_VALUE 95 +#define BSEC_OTP_UPPER_START 32 #define BSEC_TIMEOUT_US 10000
/* BSEC REGISTER OFFSET (base relative) */ @@ -41,6 +42,7 @@ /* BSEC_CONTROL Register */ #define BSEC_READ 0x000 #define BSEC_WRITE 0x100 +#define BSEC_LOCK 0x200
/* LOCK Register */ #define OTP_LOCK_MASK 0x1F @@ -61,6 +63,11 @@ */ #define BSEC_LOCK_PROGRAM 0x04
+/*
- OTP status: bit 0 permanent lock
- */
+#define BSEC_LOCK_PERM BIT(0)
/**
- bsec_lock() - manage lock for each type SR/SP/SW
- @address: address of bsec IP register
@@ -284,6 +291,65 @@ static int bsec_program_otp(struct udevice *dev, long base, u32 val, u32 otp) return ret; }
+/**
- bsec_permanent_lock_otp() - permanent lock of OTP in SAFMEM
- @dev: bsec IP device
- @base: base address of bsec IP
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
- Return: 0 if no error
- */
+static int bsec_permanent_lock_otp(struct udevice *dev, long base, uint32_t otp) +{
- int ret;
- bool power_up = false;
- u32 val, addr;
- /* check if safemem is power up */
- if (!(readl(base + BSEC_OTP_STATUS_OFF) & BSEC_MODE_PWR_MASK)) {
ret = bsec_power_safmem(base, true);
if (ret)
return ret;
power_up = true;
- }
- /*
* low OTPs = 2 bits word for low OTPs, 1 bits per word for upper OTP
* and only 16 bits used in WRDATA
*/
- if (otp < BSEC_OTP_UPPER_START) {
addr = otp / 8;
val = 0x03 << ((otp * 2) & 0xF);
- } else {
addr = BSEC_OTP_UPPER_START / 8 +
((otp - BSEC_OTP_UPPER_START) / 16);
val = 0x01 << (otp & 0xF);
- }
- /* set value in write register*/
- writel(val, base + BSEC_OTP_WRDATA_OFF);
- /* set BSEC_OTP_CTRL_OFF with the otp addr and lock request*/
- writel(addr | BSEC_WRITE | BSEC_LOCK, base + BSEC_OTP_CTRL_OFF);
- /* check otp status*/
- ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF,
val, (val & BSEC_MODE_BUSY_MASK) == 0,
BSEC_TIMEOUT_US);
- if (ret)
return ret;
- if (val & BSEC_MODE_PROGFAIL_MASK)
ret = -EACCES;
- else
ret = bsec_check_error(base, otp);
- if (power_up)
bsec_power_safmem(base, false);
- return ret;
+}
/* BSEC MISC driver *******************************************************/ struct stm32mp_bsec_plat { u32 base; @@ -339,9 +405,14 @@ static int stm32mp_bsec_read_shadow(struct udevice *dev, u32 *val, u32 otp) static int stm32mp_bsec_read_lock(struct udevice *dev, u32 *val, u32 otp) { struct stm32mp_bsec_plat *plat = dev_get_plat(dev);
u32 wrlock;
/* return OTP permanent write lock status */
- *val = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp);
wrlock = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp);
*val = 0;
if (wrlock)
*val = BSEC_LOCK_PERM;
return 0;
} @@ -377,15 +448,22 @@ static int stm32mp_bsec_write_shadow(struct udevice *dev, u32 val, u32 otp)
static int stm32mp_bsec_write_lock(struct udevice *dev, u32 val, u32 otp) {
- if (!IS_ENABLED(CONFIG_ARM_SMCCC) || IS_ENABLED(CONFIG_SPL_BUILD))
return -ENOTSUPP;
- struct stm32mp_bsec_plat *plat;
- /* only permanent write lock is supported in U-Boot */
- if (!(val & BSEC_LOCK_PERM)) {
dev_dbg(dev, "lock option without BSEC_LOCK_PERM: %x\n", val);
return 0; /* nothing to do */
- }
- if (val == 1)
- if (IS_ENABLED(CONFIG_ARM_SMCCC) && !IS_ENABLED(CONFIG_SPL_BUILD)) return stm32_smc_exec(STM32_SMC_BSEC, STM32_SMC_WRLOCK_OTP, otp, 0);
- if (val == 0)
return 0; /* nothing to do */
plat = dev_get_plat(dev);
return bsec_permanent_lock_otp(dev, plat->base, otp);
return -EINVAL;
}
Applied to u-boot-stm32
Thanks Patrice
participants (3)
-
Johann Neuhauser
-
Patrice CHOTARD
-
Patrick Delaunay