
On 2/12/20 7:37 PM, Patrick Delaunay wrote:
Add BSEC lock access (read / write) at 0xC0000000 offset of misc driver. The write access only available for Trusted boot mode, based on new SMC STM32_SMC_WRLOCK_OTP.
With the fuse command, the permanent lock status is accessed with 0x10000000 offset (0xC0000000 - 0x8000000 for OTP sense/program divided by u32 size), for example:
Read lock status of fuse 57 (0x39)
STM32MP> fuse sense 0 0x10000039 1
Sensing bank 0:
Word 0x10000039: 00000000
Set permanent lock of fuse 57 (0x39)
STM32MP> fuse prog 0 0x10000039 1
Sensing bank 0:
Word 0x10000039: 00000000
WARNING: the OTP lock is updated only after reboot
WARING: Programming lock or fuses is an irreversible operation! This may brick your system.
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com
arch/arm/mach-stm32mp/bsec.c | 88 +++++++++++++------ arch/arm/mach-stm32mp/cpu.c | 6 -- arch/arm/mach-stm32mp/include/mach/stm32.h | 9 +- .../mach-stm32mp/include/mach/stm32mp1_smc.h | 1 + doc/board/st/stm32mp1.rst | 34 ++++--- 5 files changed, 95 insertions(+), 43 deletions(-)
diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 1d904caae1..3b923f088e 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -12,8 +12,6 @@ #include <linux/iopoll.h>
#define BSEC_OTP_MAX_VALUE 95
-#ifndef CONFIG_STM32MP1_TRUSTED #define BSEC_TIMEOUT_US 10000
/* BSEC REGISTER OFFSET (base relative) */ @@ -24,9 +22,10 @@ #define BSEC_OTP_LOCK_OFF 0x010 #define BSEC_DISTURBED_OFF 0x01C #define BSEC_ERROR_OFF 0x034 -#define BSEC_SPLOCK_OFF 0x064 /* Program safmem sticky lock */ -#define BSEC_SWLOCK_OFF 0x07C /* write in OTP sticky lock */ -#define BSEC_SRLOCK_OFF 0x094 /* shadowing sticky lock */ +#define BSEC_WRLOCK_OFF 0x04C /* OTP write permananet lock */ +#define BSEC_SPLOCK_OFF 0x064 /* OTP write sticky lock */ +#define BSEC_SWLOCK_OFF 0x07C /* shadow write sticky lock */ +#define BSEC_SRLOCK_OFF 0x094 /* shadow read sticky lock */ #define BSEC_OTP_DATA_OFF 0x200
/* BSEC_CONFIGURATION Register MASK */ @@ -53,12 +52,12 @@ #define BSEC_LOCK_PROGRAM 0x04
/**
- bsec_check_error() - Check status of one otp
- @base: base address of bsec IP
- bsec_lock() - manage lock for each type SR/SP/SW
- @address: address of bsec IP register
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
- Return: 0 if no error, -EAGAIN or -ENOTSUPP
*/
- Return: true if locked else false
-static u32 bsec_check_error(u32 base, u32 otp) +static bool bsec_read_lock(u32 address, u32 otp) { u32 bit; u32 bank; @@ -66,21 +65,17 @@ static u32 bsec_check_error(u32 base, u32 otp) bit = 1 << (otp & OTP_LOCK_MASK); bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32);
- if (readl(base + BSEC_DISTURBED_OFF + bank) & bit)
return -EAGAIN;
- else if (readl(base + BSEC_ERROR_OFF + bank) & bit)
return -ENOTSUPP;
- return 0;
- return !!(readl(address + bank) & bit);
}
+#ifndef CONFIG_STM32MP1_TRUSTED /**
- bsec_lock() - manage lock for each type SR/SP/SW
- @address: address of bsec IP register
- bsec_check_error() - Check status of one otp
- @base: base address of bsec IP
- @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
- Return: true if locked else false
*/
- Return: 0 if no error, -EAGAIN or -ENOTSUPP
-static bool bsec_read_lock(u32 address, u32 otp) +static u32 bsec_check_error(u32 base, u32 otp) { u32 bit; u32 bank; @@ -88,7 +83,12 @@ static bool bsec_read_lock(u32 address, u32 otp) bit = 1 << (otp & OTP_LOCK_MASK); bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32);
- return !!(readl(address + bank) & bit);
- if (readl(base + BSEC_DISTURBED_OFF + bank) & bit)
return -EAGAIN;
- else if (readl(base + BSEC_ERROR_OFF + bank) & bit)
return -ENOTSUPP;
- return 0;
}
/** @@ -324,6 +324,16 @@ static int stm32mp_bsec_read_shadow(struct udevice *dev, u32 *val, u32 otp) #endif }
+static int stm32mp_bsec_read_lock(struct udevice *dev, u32 *val, u32 otp) +{
- struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
- /* return OTP permanent write lock status */
- *val = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp);
- return 0;
+}
static int stm32mp_bsec_write_otp(struct udevice *dev, u32 val, u32 otp) { #ifdef CONFIG_STM32MP1_TRUSTED @@ -350,17 +360,36 @@ static int stm32mp_bsec_write_shadow(struct udevice *dev, u32 val, u32 otp) #endif }
+static int stm32mp_bsec_write_lock(struct udevice *dev, u32 val, u32 otp) +{ +#ifdef CONFIG_STM32MP1_TRUSTED
- if (val == 1)
return stm32_smc_exec(STM32_SMC_BSEC,
STM32_SMC_WRLOCK_OTP,
otp, 0);
- if (val == 0)
return 0; /* nothing to do */
- return -EINVAL;
+#else
- return -ENOTSUPP;
+#endif +}
static int stm32mp_bsec_read(struct udevice *dev, int offset, void *buf, int size) { int ret; int i;
- bool shadow = true;
- bool shadow = true, lock = false; int nb_otp = size / sizeof(u32); int otp; unsigned int offs = offset;
- if (offs >= STM32_BSEC_OTP_OFFSET) {
- if (offs >= STM32_BSEC_LOCK_OFFSET) {
offs -= STM32_BSEC_LOCK_OFFSET;
lock = true;
- } else if (offs >= STM32_BSEC_OTP_OFFSET) { offs -= STM32_BSEC_OTP_OFFSET; shadow = false; }
@@ -373,7 +402,9 @@ static int stm32mp_bsec_read(struct udevice *dev, int offset, for (i = otp; i < (otp + nb_otp) && i <= BSEC_OTP_MAX_VALUE; i++) { u32 *addr = &((u32 *)buf)[i - otp];
if (shadow)
if (lock)
ret = stm32mp_bsec_read_lock(dev, addr, i);
else ret = stm32mp_bsec_read_otp(dev, addr, i);else if (shadow) ret = stm32mp_bsec_read_shadow(dev, addr, i);
@@ -392,12 +423,15 @@ static int stm32mp_bsec_write(struct udevice *dev, int offset, { int ret = 0; int i;
- bool shadow = true;
- bool shadow = true, lock = false; int nb_otp = size / sizeof(u32); int otp; unsigned int offs = offset;
- if (offs >= STM32_BSEC_OTP_OFFSET) {
- if (offs >= STM32_BSEC_LOCK_OFFSET) {
offs -= STM32_BSEC_LOCK_OFFSET;
lock = true;
- } else if (offs >= STM32_BSEC_OTP_OFFSET) { offs -= STM32_BSEC_OTP_OFFSET; shadow = false; }
@@ -410,7 +444,9 @@ static int stm32mp_bsec_write(struct udevice *dev, int offset, for (i = otp; i < otp + nb_otp && i <= BSEC_OTP_MAX_VALUE; i++) { u32 *val = &((u32 *)buf)[i - otp];
if (shadow)
if (lock)
ret = stm32mp_bsec_write_lock(dev, *val, i);
else ret = stm32mp_bsec_write_otp(dev, *val, i);else if (shadow) ret = stm32mp_bsec_write_shadow(dev, *val, i);
diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index ea0bd94605..5febed735c 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -61,12 +61,6 @@ #define BOOTROM_INSTANCE_MASK GENMASK(31, 16) #define BOOTROM_INSTANCE_SHIFT 16
-/* BSEC OTP index */ -#define BSEC_OTP_RPN 1 -#define BSEC_OTP_SERIAL 13 -#define BSEC_OTP_PKG 16 -#define BSEC_OTP_MAC 57
/* Device Part Number (RPN) = OTP_DATA1 lower 8 bits */ #define RPN_SHIFT 0 #define RPN_MASK GENMASK(7, 0) diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index f0636005e5..6daf9f7121 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -119,7 +119,14 @@ enum forced_boot_mode { #define STM32_BSEC_SHADOW(id) (STM32_BSEC_SHADOW_OFFSET + (id) * 4) #define STM32_BSEC_OTP_OFFSET 0x80000000 #define STM32_BSEC_OTP(id) (STM32_BSEC_OTP_OFFSET + (id) * 4)
+#define STM32_BSEC_LOCK_OFFSET 0xC0000000 +#define STM32_BSEC_LOCK(id) (STM32_BSEC_LOCK_OFFSET + (id) * 4)
+/* BSEC OTP index */ +#define BSEC_OTP_RPN 1 +#define BSEC_OTP_SERIAL 13 +#define BSEC_OTP_PKG 16 +#define BSEC_OTP_MAC 57 #define BSEC_OTP_BOARD 59
#endif /* __ASSEMBLY__*/ diff --git a/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h b/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h index 8130546b27..7b9167c356 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h @@ -27,6 +27,7 @@ #define STM32_SMC_READ_OTP 0x04 #define STM32_SMC_READ_ALL 0x05 #define STM32_SMC_WRITE_ALL 0x06 +#define STM32_SMC_WRLOCK_OTP 0x07
/* SMC error codes */ #define STM32_SMC_OK 0x0 diff --git a/doc/board/st/stm32mp1.rst b/doc/board/st/stm32mp1.rst index 131f4902a3..274f8d9710 100644 --- a/doc/board/st/stm32mp1.rst +++ b/doc/board/st/stm32mp1.rst @@ -402,20 +402,26 @@ For STMicroelectonics board, it is retrieved in STM32MP15x OTP :
- OTP_58[15:0] = MAC_ADDR[47:32]
To program a MAC address on virgin OTP words above, you can use the fuse command -on bank 0 to access to internal OTP: +on bank 0 to access to internal OTP and lock them:
Prerequisite: check if a MAC address isn't yet programmed in OTP
-1) check OTP: their value must be equal to 0 +1) check OTP: their value must be equal to 0::
- STM32MP> fuse sense 0 57 2
- Sensing bank 0:
- Word 0x00000039: 00000000 00000000
- STM32MP> fuse sense 0 57 2
- Sensing bank 0:
- Word 0x00000039: 00000000 00000000
+2) check environment variable::
- STM32MP> env print ethaddr
- ## Error: "ethaddr" not defined
-2) check environment variable +3) check lock status of fuse 57 & 58 (at 0x39, 0=unlocked, 1=locked)::
- STM32MP> env print ethaddr
- ## Error: "ethaddr" not defined
- STM32MP> fuse sense 0 0x10000039 2
- Sensing bank 0:
Word 0x10000039: 00000000 00000000
Example to set mac address "12:34:56:78:9a:bc"
@@ -429,11 +435,19 @@ Example to set mac address "12:34:56:78:9a:bc" Sensing bank 0: Word 0x00000039: 78563412 0000bc9a
-3) next REBOOT, in the trace:: +3) Lock OTP::
- STM32MP> fuse prog 0 0x10000039 1 1
- STM32MP> fuse sense 0 0x10000039 2
- Sensing bank 0:
Word 0x10000039: 00000001 00000001
+4) next REBOOT, in the trace::
Acked-by: Patrice Chotard patrice.chotard@st.com
Thanks
Patrice
### Setting environment from OTP MAC address = "12:34:56:78:9a:bc"
-4) check env update:: +5) check env update::
STM32MP> env print ethaddr ethaddr=12:34:56:78:9a:bc
Acked-by: Patrice Chotard patrice.chotard@st.com
Thanks
Patrice