The NXP i.MX6UL CPU provides a set of one-time programmable bits (eFuses) structured as 16 banks. Each bank is composed of eight 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 6UL 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.MX6UL OTP memory driver device tree binding is documented at Documentation/devicetree/bindings/nvmem/imx-ocotp.txt.

i.MX6UL device tree
ocotp: ocotp-ctrl@021bc000 {
	compatible = "fsl,imx6ul-ocotp", "syscon";
	reg = <0x021bc000 0x4000>;
	clocks = <&clks IMX6UL_CLK_OCOTP>;
	#address-cells = <1>;
	#size-cells = <1>;
};

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

ConnectCore 6UL 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: 00328003 e6b3f362 0c2549d4 7031003d
00000010: 02410002 00000000 00000000 00000000
00000020: 00000080 00000000 00000099 00000000
00000030: 00000000 00000000 5a451d69 00000000
00000040: badabada badabada badabada badabada
*
00000060: 00000000 00000000 00000000 00000000
*
00000080: 00000000 00000000 00000000 00000540
00000090: 00000000 badabada 00000003 00000000
000000a0: 00000000 00000000 00000000 00000000
000000b0: 00000000 00000040 00000000 00000000
000000c0: 00000000 00000000 00000000 00000000
*
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" * 8) + "Word"\$

For example, for Bank 4 Word 3, the offset is 4 * 4 + 3 = 35.

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=35 | hexdump -v -e '4/4 "%08x " "\n"'
00000540

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 4 Word 3, the offset is 4 * 4 + 3 = 35.

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=35 conv=notrunc