The NXP {cpu-family} 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 6 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 {cpu-family} OTP memory driver device tree binding is documented at Documentation/devicetree/bindings/nvmem/imx-ocotp.txt.

{cpu-family} device tree
ocotp: ocotp@21bc000 {
	compatible = "fsl,imx6q-ocotp", "syscon";
	reg = <0x021bc000 0x4000>;
	clocks = <&clks IMX6QDL_CLK_IIM>;
};

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

ConnectCore 6 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: 20220003 e31698d7 0f0a89d4 202200c0
00000010: 00600302 00000000 00000000 00000000
00000020: 00000080 00000040 0000009f 00000000
00000030: 00000000 80000000 5654de69 00000000
00000040: badabada badabada badabada badabada
*
00000060: 00000000 00000000 00000000 00000000
*
00000080: 00000000 00000000 b0208705 3f100450
00000090: 00000000 00000000 00000003 00000000
000000a0: 00000000 00000000 00000000 00000000
*
00000100: 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" * 8) + "Word"\$

For example, for Bank 4 Word 3, the offset is 4 * 8 + 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" * 8) + "Word"\$

For example, for Bank 4 Word 3, the offset is 4 * 8 + 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