mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 07:34:31 +00:00
arm: stm32mp: bsec: add permanent lock support in bsec driver
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> Acked-by: Patrice Chotard <patrice.chotard@st.com>
This commit is contained in:
parent
df2d1b8fc4
commit
7ae22d7278
5 changed files with 96 additions and 44 deletions
|
@ -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 */
|
||||
|
@ -52,6 +51,24 @@
|
|||
*/
|
||||
#define BSEC_LOCK_PROGRAM 0x04
|
||||
|
||||
/**
|
||||
* 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: true if locked else false
|
||||
*/
|
||||
static bool bsec_read_lock(u32 address, u32 otp)
|
||||
{
|
||||
u32 bit;
|
||||
u32 bank;
|
||||
|
||||
bit = 1 << (otp & OTP_LOCK_MASK);
|
||||
bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32);
|
||||
|
||||
return !!(readl(address + bank) & bit);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_STM32MP1_TRUSTED
|
||||
/**
|
||||
* bsec_check_error() - Check status of one otp
|
||||
* @base: base address of bsec IP
|
||||
|
@ -74,23 +91,6 @@ static u32 bsec_check_error(u32 base, u32 otp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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: true if locked else false
|
||||
*/
|
||||
static bool bsec_read_lock(u32 address, u32 otp)
|
||||
{
|
||||
u32 bit;
|
||||
u32 bank;
|
||||
|
||||
bit = 1 << (otp & OTP_LOCK_MASK);
|
||||
bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32);
|
||||
|
||||
return !!(readl(address + bank) & bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* bsec_read_SR_lock() - read SR lock (Shadowing)
|
||||
* @base: base address of bsec IP
|
||||
|
@ -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 if (shadow)
|
||||
ret = stm32mp_bsec_read_shadow(dev, addr, i);
|
||||
else
|
||||
ret = stm32mp_bsec_read_otp(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 if (shadow)
|
||||
ret = stm32mp_bsec_write_shadow(dev, *val, i);
|
||||
else
|
||||
ret = stm32mp_bsec_write_otp(dev, *val, i);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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__*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -416,20 +416,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
|
||||
2) check environment variable::
|
||||
|
||||
STM32MP> env print ethaddr
|
||||
## Error: "ethaddr" not defined
|
||||
STM32MP> env print ethaddr
|
||||
## Error: "ethaddr" not defined
|
||||
|
||||
3) check lock status of fuse 57 & 58 (at 0x39, 0=unlocked, 1=locked)::
|
||||
|
||||
STM32MP> fuse sense 0 0x10000039 2
|
||||
Sensing bank 0:
|
||||
Word 0x10000039: 00000000 00000000
|
||||
|
||||
Example to set mac address "12:34:56:78:9a:bc"
|
||||
|
||||
|
@ -443,11 +449,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::
|
||||
|
||||
### 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
|
||||
|
|
Loading…
Reference in a new issue