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

drivers/nvmem/stm32-romem.c

STM32 factory-programmed memory support

Device tree bindings

The STM32MP25 OTP memory driver device tree binding are documented at

File Description

Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml

STM32 BSEC device tree binding

Documentation/devicetree/bindings/nvmem/nvmem.yaml

Generic NVMEM device tree bindings

Documentation/devicetree/bindings/nvmem/nvmem-consumer.yaml

Generic device tree bindings

The STM32MP25 device tree include file defines the bsec node and inside it, a number of relevant OTP words.

STM32MP25 device tree
	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:

ConnectCore MP25 device tree
&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.