Last edited one year ago

How to update OTP with U-Boot

Applicable for STM32MP13x lines, STM32MP15x lines

This page explains how to manually update OTP with the U-Boot fuse command.

1. The fuse command[edit source]

Warning white.png Warning
Programming fuses is an irreversible operation!
This may brick your system.
Use this command only if you are sure of what you are doing!

The fuse command allows you to update the OTP words in U-Boot:

  • sense/program to directly access the OTP value (for a permanent update)
  • read/override to access only the shadow cache value (for a temporary update).
  help fuse        
 fuse - Fuse sub-system
 
 Usage:
 fuse read <bank> <word> [<cnt>] - read 1 or 'cnt' fuse words,
     starting at 'word'
 fuse sense  <bank> <word> [<cnt>] - sense 1 or 'cnt' fuse words,
     starting at 'word'
 fuse prog [-y]  <bank> <word> <hexval> [<hexval>...] - program 1 or
     several fuse words, starting at 'word' (PERMANENT)
 fuse override  <bank> <word> <hexval> [<hexval>...] - override 1 or
     several fuse words, starting at 'word'.

See doc/README.fuse for details.

2. STM32MP support[edit source]

The fuse command is implemented in drivers/misc/stm32mp_fuse.c :

  • For the STM32MP15x lines More info.png with 2 banks:
  • For the STM32MP13x lines More info.png with 1 bank:

2.1. STM32MP OTP[edit source]

<bank> = 0 provides access to the 96 STM32MP13x or STM32MP15x OTP words with the BSEC driver: arch/arm/mach-stm32mp/bsec.c .

Refer to the STM32MP13 reference manuals or STM32MP15 reference manuals for the OTP layout.

The OTP<index> words value and lock status (0=unlocked, 1=locked) are available with <index> = 0 to 95  :

  • for value: <word> = <index>
  • for lock status: <word> = 0x10000000 + <index>
    not shadowed, only support operation sense and program
    the status bit-field is same than STM32CubeProgrammer OTP management:
    • [0]: 1 bit read error detected: 1 = OTP value isn't valid
    • [26]: 1 bit lock error
    • [27]: 1 bit sticky programming lock
    • [28]: 1 bit shadow write sticky lock
    • [29]: 1 bit shadow read sticky lock
    • [30]: 1 bit permanent write lock

Only 32 lower OTPs words are accessible by default, the software needs to manage exceptions to allow some upper OTPs to be accessed by the non-secure world as described in BSEC_device_tree_configuration.

Warning white.png Warning

These upper OTP words are ECC-protected. To avoid an invalid ECC, computed after a second write operation, these 64 upper OTPs should be be permanent write locked when they are programmed.

2.1.1. Simple OTP examples[edit source]

1) Read OTP value for OTP57 and 58 (2 OTP words)

  fuse sense 0 57 2
 Sensing bank 0:
 Word 0x00000039: 42e18000 0000e448

2) Check lock status of OTP 57 - 60 (4 words at index 57 = 0x39)

   fuse sense 0 0x10000039 4
 Sensing bank 0:
 Word 0x10000039: 40000000 40000000 40000000 00000000

3) Display shadow values for all OTPs

When only the 32 lower OTPs are accessible:

  fuse read 0 0 32
 Reading bank 0:
 
 Word 0x00000000: 00000017 00008001 00000000 00000000
 Word 0x00000004: 00000000 00000000 00000000 00000000
 Word 0x00000008: 00000000 82004000 00000000 00000000
 Word 0x0000000c: 7d04f0db 00470022 33385115 34383330
 Word 0x00000010: 22986562 27010551 7a470140 06cc1608
 Word 0x00000014: 5e560054 00000000 00000000 401a300c
 Word 0x00000018: ffffffff ffffffff ffffffff ffffffff
 Word 0x0000001c: ffffffff ffffffff ffffffff ffffffff
 

When all the 96 OTPs are available:

  fuse read 0 0 96
 Reading bank 0:
 
 Word 0x00000000: 00000017 00008000 00000000 00000000
 Word 0x00000004: 00000000 00000000 00000000 00000000
 Word 0x00000008: 00000000 00000000 00000000 00000000
 Word 0x0000000c: 7cf5f0f9 00410032 33385116 34383330
 Word 0x00000010: 129675aa 2931215e 7a550000 069013ec
 Word 0x00000014: 5e360042 00000000 00000000 40133023
 Word 0x00000018: 00000000 00000000 00000000 00000000
 Word 0x0000001c: 00000000 00000000 00000000 00000000
 Word 0x00000020: 00000000 00000000 00000000 00000000
 Word 0x00000024: 00000000 00000000 00000000 00000000
 Word 0x00000028: aa333e40 b5e90dda f15f4678 8ab41400
 Word 0x0000002c: b74efe3a f0a03b1b 01e016b3 d06a79dd
 Word 0x00000030: 48b96fbe 20fbd352 6732dbf4 edc395f9
 Word 0x00000034: cdf15575 418fd3d0 0bb7d994 8dc929d0
 Word 0x00000038: 00000000 42e18000 0000e448 12722301
 Word 0x0000003c: 00000000 00000000 00000000 00000000
 Word 0x00000040: 00000000 00000000 00000000 00000000
 Word 0x00000044: 00000000 00000000 00000000 00000000
 Word 0x00000048: 00000000 00000000 00000000 00000000
 Word 0x0000004c: 00000000 00000000 00000000 00000000
 Word 0x00000050: 00000000 00000000 00000000 00000000
 Word 0x00000054: 00000000 00000000 00000000 00000000
 Word 0x00000058: 00000000 00000000 00000000 00000000
 Word 0x0000005c: 00000000 00000000 00000000 00000000

4) Override value for one OTP

  fuse override 0 0x0000005c 1 
 Overriding bank 0 word 0x0000005c with 0x00000001...
 
  fuse read 0 0x0000005c      
 Reading bank 0:
 
 Word 0x0000005c: 00000001
 
  fuse sense 0 0x0000005c
 Sensing bank 0:
 
 Word 0x0000005c: 00000000


2.1.2. MAC address example for STM32MP13x[edit source]

For STM32MP13 boards, the two MAC address are retrieved in the 3 OTP words:

  • OTP_57[31:0] = MAC_ADDR1[31:0]
  • OTP_58[15:0] = MAC_ADDR1[47:32]
  • OTP_58[31:16] = MAC_ADDR2[15:0]
  • OTP_59[31:0] = MAC_ADDR2[47:16]

See the full sequence in previous chapter, with a added OTP, for example:

 fuse prog -y 0 57 e17ae710 e71094a2 95a2e17a
 fuse read 0 57 3
Reading bank 0:

Word 0x00000039: e17ae710 e71094a2 95a2e17a
 env print
... 
eth1addr=10:e7:7a:e1:a2:95
ethaddr=10:e7:7a:e1:a2:94
...

2.1.3. MAC address example for STM32MP15x[edit source]

For STM32MP15 boards, the MAC address[1] is retrieved in the 2 OTP words:

  • OTP_57[31:0] = MAC_ADDR[31:0]
  • 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 internal OTP words and lock them:

Prerequisite: check if a MAC address isn't yet programmed in OTP.

1) Check OTPs: their value must be equal to 0:

    fuse sense 0 57 2
   Sensing bank 0:
   Word 0x00000039: 00000000 00000000

2) Check environment variable:

    env print ethaddr
   ## Error: "ethaddr" not defined

3) Check lock status of OTP 57 & 58 (at 0x39, 0=unlocked, 1=locked):

    fuse sense 0 0x10000039 2
   Sensing bank 0:
      Word 0x10000039: 00000000 00000000

Example to set MAC address "12:34:56:78:9a:bc"

1) Write OTP:

    fuse prog -y 0 57 0x78563412 0x0000bc9a
Warning white.png Warning
This prog command cannot be executed twice because the upper OTPs are ECC-protected. If you program twice the same upper OTP words with different values, these OTPs will be permanently Invalid and cause an error if accessed. To avoid an issue for a second undesired write operation, these upper OTPs must be locked when programmed.

2) Read OTP:

    fuse sense 0 57 2
   Sensing bank 0:
   Word 0x00000039: 78563412 0000bc9a

3) Lock OTP:

    fuse prog 0 0x10000039 0x40000000 0x40000000
   
    fuse sense 0 0x10000039 2
   Sensing bank 0:
      Word 0x10000039: 40000000 40000000

4) OTP is used after REBOOT, in the trace:

   ### Setting environment from OTP MAC address = "12:34:56:78:9a:bc"

5) Check env update:

    env print ethaddr
   ethaddr=12:34:56:78:9a:bc

2.2. STPMIC1 NVM[edit source]

<bank> = 1 provides access to the non-volatile memory (NVM) of the PMIC on the board when PMIC is managed by U-Boot.

It is not the case in OpenSTLinux, when OP-TEE is used.

For STPMIC1, the NVM has 8 bytes as defined in datasheet: DS12792, with <word> = <0xf8> to <0xff>.

1) Read the values of the 8 NVM

  fuse read 1 0xf8 8
 Reading bank 1:
 
 Word 0x000000f8: 000000ee 00000092 000000c0 00000002
 Word 0x000000fc: 000000f2 00000080 00000002 00000033

2) Read 2 NVM shadow values

  fuse sense 1 0xf9 2
 Sensing bank 1:
 
 Word 0x000000f9: 00000092 000000c0

3) Update the NVM at index 0xfc with value 0xf2

  fuse prog 1 0xfc 0xf2
 Programming bank 1 word 0x000000fc to 0x000000f2...
 Warning: Programming fuses is an irreversible operation!
          This may brick your system.
          Use this command only if you are sure of what you are doing!
 
 Really perform this fuse programming? <y/N>
 y

3. References[edit source]