Last edited 2 years ago

How to update OTP with U-Boot


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

1. The fuse command[edit source]

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 :

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.

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

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]