arm: stm32mp: bsec: add permanent lock support in bsec driver
authorPatrick Delaunay <patrick.delaunay@st.com>
Wed, 12 Feb 2020 18:37:38 +0000 (19:37 +0100)
committerPatrick Delaunay <patrick.delaunay@st.com>
Tue, 24 Mar 2020 13:05:35 +0000 (14:05 +0100)
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>
arch/arm/mach-stm32mp/bsec.c
arch/arm/mach-stm32mp/cpu.c
arch/arm/mach-stm32mp/include/mach/stm32.h
arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h
doc/board/st/stm32mp1.rst

index 1d904caae11464d6d569759913280601005c7593..3b923f088e764f30a3fcd8ae7785b323b81d2989 100644 (file)
@@ -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) */
 #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 */
 #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 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);
index ea0bd94605b77eac27a2045bfd5ca0403e2046fe..5febed735c8daeaad00c1554164f7fb60b6c260f 100644 (file)
 #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)
index f0636005e5d9d4736007449272c165e9534b143b..6daf9f7121636ae5536342e08a0e1db313183da5 100644 (file)
@@ -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__*/
index 8130546b273a40188fba921272e5f5c28956fd69..7b9167c3562923ac6e2e3c00837662a9e55d83c2 100644 (file)
@@ -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
index 1640bf910ec9064910afbdb5de64d09762e7725e..ee42af6579d9f7a43b2284538cc2676c989de7a3 100644 (file)
@@ -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::
+
+    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"
 
@@ -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