The NXP i.MX8M Mini CPU provides a set of one-time programmable bits (eFuses) structured as 15 banks. Each bank is composed of four words of 32 bits each.

Kernel configuration

You can manage the OTP driver support through the kernel configuration option:

  • NXP NVMEM On-Chip OTP Memory support (CONFIG_NVMEM_IMX_OCOTP)

This option is enabled as built-in on the ConnectCore 8M Mini default kernel configuration file.

Kernel driver

The OTP memory driver is located at:

File Description

drivers/nvmem/imx-ocotp.c

i.MX 6/7/8 On-Chip OTP Controller support

Device tree bindings

The i.MX8M Mini OTP memory driver device tree binding is documented at Documentation/devicetree/bindings/nvmem/imx-ocotp.txt.

i.MX8M Mini device tree
ocotp: ocotp-ctrl@30350000 {
	compatible = "fsl,imx8mq-ocotp", "fsl,imx7d-ocotp", "syscon";
	reg = <0x30350000 0x10000>;
	clocks = <&clk IMX8MM_CLK_OCOTP_ROOT>;
	/* For nvmem subnodes */
	#address-cells = <1>;
	#size-cells = <1>;
};

The ConnectCore 8M Mini device tree sets read-only access to the OTP bits to prevent accidental programming of the e-fuses.

ConnectCore 8M Mini device tree
&ocotp {
	/* By default, make the OTP bits read-only */
	read-only;
};

OTP user space usage

The OTP words are accessible through the sysfs at /sys/bus/nvmem/devices/imx-ocotp0/nvmem.

Read the OTP bits

To dump the values of all OTP words:

~# hexdump -e '"%08_ax: " 4/4 "%08x " "\n"' /sys/bus/nvmem/devices/imx-ocotp0/nvmem
00000000: feafa9eb 50d00200 24226998 00000000
00000010: 20000800 00020000 0000007f 08000000
00000020: 00000000 00000000 00000000 00000000
00000030: 00000000 00000000 00000000 013c7b3a
00000040: badabada badabada badabada badabada
*
00000060: 00000000 00000000 00000000 00000000
*
00000090: 14100009 118e0b01 0007b848 00000000
000000a0: badabada badabada badabada badabada
*
000000c0: 00000000 00000000 00000000 00000000
*
000000f0: badabada badabada badabada 00000000
00000100: 00000000 00000000 00000000 00000000
*
00000130: badabada badabada badabada badabada
00000140: 55002001 00028840 0003f000 0000eddc
00000150: a8c1302b 0000ede8 a881300b 00025c54
00000160: 52801e00 00000000 00000000 00000000
00000170: 00000000 00000000 00000000 00000000
*
000003e0: 00000000 00000000 00000001 07c31a01
000003f0: badabada badabada badabada badabada
The values showing badabada correspond to OTP words that cannot be read, such as encryption keys.

To dump only a certain OTP word, do not use the -s parameter of the hexdump command. Instead, use the dd command and pipe the result to hexdump. To calculate the offset of the word, use the formula:

\$"Offset" = ("Bank" * 4) + "Word"\$

For example, for Bank 9 Word 1, the offset is 9 * 4 + 1 = 37.

Use dd with a block size (bs) of 4 bytes, a count of 1 word, and skip the calculated offset:

~# dd status=none if=/sys/bus/nvmem/devices/imx-ocotp0/nvmem of=/dev/stdout bs=4 count=1 skip=37 | hexdump -v -e '4/4 "%08x " "\n"'
118e0b01

Write the OTP bits

OTP bits can be blown just once. Programming them is an irreversible operation.

By default, OTP bit access is configured as read-only. To enable write permissions, add the following to your device tree:

&ocotp {
	/delete-property/read-only;
};

Recompile the device tree and deploy it to your device.

OTP bit 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/imx-ocotp0/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 in 1 (4 bytes).

  • seek=<offset> sets the offset (in words) where to write.

  • conv=notrunc avoids truncating the output.

To calculate the offset of the word, use the formula:

\$"Offset" = ("Bank" * 4) + "Word"\$

For example, for Bank 9 Word 1, the offset is 9 * 4 + 1 = 37.

To write the word 0x12345678 to that offset, swap the bytes to present them in little-endian to the printf command:

~$ printf '\x78\x56\x34\x12' | dd of=/sys/bus/nvmem/devices/imx-ocotp0/nvmem bs=4 count=1 seek=37 conv=notrunc