The STM STM32MP25 CPU provides a set of one-time programmable bits (OTPs) structured as 12288 effective bits on 384 words (from 0 to 383).
OTP words are organized in regions:
-
lower OTP (OTP0 to OTP127), programmable bit by bit
-
mid OTP (OTP128 to OTP255), programmable as full word, ECC protected
-
upper OTP (OTP256 to OTP383), for secrets, not reachable in BSEC open state; ECC protected
The OTPs are accessed through 32-bit words.
Kernel configuration
You can manage the OTP driver support through the kernel configuration option:
-
STM32 factory-programmed memory support (
CONFIG_NVMEM_STM32_ROMEM
)
This option is enabled as built-in on the ConnectCore MP25 default kernel configuration file.
Kernel driver
The memory driver is located at:
File | Description |
---|---|
STM32 factory-programmed memory support |
Device tree bindings
The STM32MP25 OTP memory driver device tree binding are documented at
File | Description |
---|---|
STM32 BSEC device tree binding |
|
Generic NVMEM device tree bindings |
|
Generic device tree bindings |
The STM32MP25 device tree include file defines the bsec
node and inside it, a number of relevant OTP words.
bsec: efuse@44000000 {
compatible = "st,stm32mp25-bsec";
reg = <0x44000000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
part_number_otp@24 {
reg = <0x24 0x4>;
};
package_otp@1e8 {
reg = <0x1e8 0x1>;
bits = <0 3>;
};
};
The ConnectCore MP25 defines OTP words used by the SOM, such as Digi hardware ID. It also sets the OTP words as read-only by default, to prevent accidental programming:
&bsec {
/* By default, make the OTP bits read-only */
read-only;
/* Digi hardware ID (HWID) stored in OTP23, OTP24, OTP25 */
hwid: hwid@5c {
reg = <0x5c 0xc>;
};
};
OTP user space usage
The OTP words are accessible through the sysfs at /sys/bus/nvmem/devices/stm32-romem0/nvmem
.
Upper region OTP bits are not reachable when the device is in open state. |
Read the OTP bits
To dump the values of all OTP words:
# hexdump -e '"%08_ax: " 4/4 "%08x " "\n"' /sys/bus/nvmem/devices/stm32-romem0/nvmem
00000000: aaaa5555 000000ff 0000000f 0000000f
00000010: 0000f0ff 003f0033 41365005 00373653
00000020: 00000000 80002000 00000106 00000000
00000030: 00000000 00000000 00000000 00000000
*
00000050: 00000000 00000000 00000000 6250000e
00000060: 00011401 00037090 00000000 00000000
00000070: 00000000 00000000 00000000 00000000
*
00000190: 00000000 00000000 00000000 cf5e5e0b
000001a0: 00000000 00000000 4a744e74 42124211
000001b0: 00000000 00000000 00000715 0a071007
000001c0: c0000209 00f800a0 00000000 0000affc
000001d0: 00000000 00000000 00000000 00000000
000001e0: 461fc8f1 01597b78 99c57871 ce877777
000001f0: 00018db6 00000000 00000000 00000000
00000200: 623e9942 c5197db6 8f735c78 f596864f
00000210: 040cb6e7 2f42d0b4 b8075a56 ce78bc46
00000220: 55ac20ff d3131ba5 06d6009c 8fc74d70
00000230: c0eb1273 c25418d7 63f2afd7 034fb37f
00000240: 00000000 00000000 00000000 00000000
*
00000280: c311602e fd06d257 4fd1e6c0 7e60b27e
00000290: 6f5b49cf ccce81c9 13f54b85 4a62ea1b
000002a0: 28748355 fae39ecf 64cc5e82 eea66455
000002b0: 9a7ac1c2 28af42e8 af575b78 5c355df7
000002c0: 00000000 00000000 00000000 00000000
*
000003f0: 00000000 00000000 00000000 7664cd2c
00000400: 00000000 00000000 00000000 00000000
*
000005b0: 00000000 00000000 00000000
Certain OTP words, such as security keys, cannot be read so they show as 00000000 .
|
To dump only a certain OTP word use the dd
command, skip the offset of the word, and pipe the result to hexdump
.
For instance, to dump OTP word 12, use:
# dd status=none if=/sys/bus/nvmem/devices/stm32-romem0/nvmem of=/dev/stdout bs=4 count=1 skip=12 | hexdump -v -e '4/4 "%08x " "\n"'
00000000
Write the OTP bits
OTP bits can be blown just once. Programming them is an irreversible operation. OTP bits on ECC-protected regions should only be written once. Writing a second time may lead to errors. |
By default, OTP bits access is configured as read-only on Linux device tree. To enable write permissions, add the following to your Linux device tree:
&bsec {
/delete-property/read-only;
};
Recompile the Linux device tree and deploy it to your device.
OTP bits access is done in 32-bit words.
To write a 32-bit value to a specific word, use printf
and pipe the output to dd
:
# printf <value> | dd of=/sys/bus/nvmem/devices/stm32-romem0/nvmem bs=4 count=1 seek=<offset> conv=notrunc
where:
-
<value>
is the 32-bit value to write. Specify the value in little-endian byte order. -
bs=4
sets the block size in 4 bytes (a full 32-bit word). -
count=1
sets the blocks (words) to write (1 = 4 bytes). -
seek=<offset>
sets the offset (in words) where to write. -
conv=notrunc
avoids truncating the output.
For example, to write the word 0x12345678
to word N, swap the bytes to present them in little-endian to the printf
command:
# printf '\x78\x56\x34\x12' | dd of=/sys/bus/nvmem/devices/stm32-romem0/nvmem bs=4 count=1 seek=N conv=notrunc
Programming of the OTP bits happens without user confirmation. Make sure you double check the value and the word offset you want to program before running a command like this. |