OTP Access Utility Guide
Introduction
This document describes the usage of the OTP access utilities in:
U-Boot environment : otpread / otpwrite
Linux TA/CA environment: factory_util 6 otpread / otpwrite
OTP (One-Time Programmable) memory allows permanent configuration of security keys, boot policies, and OEM information.
OTP Field Definitions Table
Each OTP index has a fixed access permission and a valid data mask. Only bits set in the mask are allowed to be programmed.
“Atomic Item” indicates whether the field MUST be programmed as part of the atomic security provisioning group.
Index |
Name |
Read / Write Permission |
Mask |
Atomic Item |
Comments |
|---|---|---|---|---|---|
0-31 |
OTP_USER_DATA_0 ~ 31 |
Read / Write |
0xFFFFFFFF |
NO |
User Data |
100 |
OTP_K0_OEM_HASH_0 |
Write Only |
0xFFFFFFFF |
YES |
OEM Root Public Key Hash word 0 (256-bit) |
101 |
OTP_K0_OEM_HASH_1 |
Write Only |
0xFFFFFFFF |
YES |
OEM Root Public Key Hash word 1 |
102 |
OTP_K0_OEM_HASH_2 |
Write Only |
0xFFFFFFFF |
YES |
OEM Root Public Key Hash word 2 |
103 |
OTP_K0_OEM_HASH_3 |
Write Only |
0xFFFFFFFF |
YES |
OEM Root Public Key Hash word 3 |
104 |
OTP_K0_OEM_HASH_4 |
Write Only |
0xFFFFFFFF |
YES |
OEM Root Public Key Hash word 4 |
105 |
OTP_K0_OEM_HASH_5 |
Write Only |
0xFFFFFFFF |
YES |
OEM Root Public Key Hash word 5 |
106 |
OTP_K0_OEM_HASH_6 |
Write Only |
0xFFFFFFFF |
YES |
OEM Root Public Key Hash word 6 |
107 |
OTP_K0_OEM_HASH_7 |
Write Only |
0xFFFFFFFF |
YES |
OEM Root Public Key Hash word 7 |
108 |
OTP_AESK0_0 |
Write Only |
0xFFFFFFFF |
YES |
AES Root Key K0 word 0 (0-3 total 128-bit) |
109 |
OTP_AESK0_1 |
Write Only |
0xFFFFFFFF |
YES |
AES Root Key K0 word 1 |
110 |
OTP_AESK0_2 |
Write Only |
0xFFFFFFFF |
YES |
AES Root Key K0 word 2 |
111 |
OTP_AESK0_3 |
Write Only |
0xFFFFFFFF |
YES |
AES Root Key K0 word 3 |
112 |
OTP_REE_SEGID |
Read / Write |
0xFFFFFFFF |
YES |
32-bit REE segmentation ID |
113 |
OTP_REE_SECURITY_ENABLE |
Read / Write |
0x00000001 |
YES |
1 = Enable REE security |
114 |
OTP_BOOT_SECURITY_ENABLE |
Read / Write |
0x00000001 |
NO |
1 = Enable Secure Boot |
115 |
OTP_MP_PROVISION_DONE |
Read / Write |
0x00000001 |
NO |
1 = Factory provisioning complete |
116 |
OTP_SCS_AREA_SIZE_SEL |
Read / Write |
0x00000003 |
NO |
2-bit Secure Code Storage size select |
117 |
OTP_REE_JTAG_PROTECTION_POLICY |
Read / Write |
0x00000003 |
NO |
2-bit JTAG access policy |
200 |
OTP_EMMC_BOOT_DISABLE |
Read / Write |
0x00000001 |
NO |
1 = Disable eMMC boot |
201 |
OTP_SPI_BOOT_DISABLE |
Read / Write |
0x00000001 |
NO |
1 = Disable SPI boot |
202 |
OTP_DOLBY_AUDIO_DISABLE |
Read Only |
0x00000001 |
NO |
1 = Disable Dolby Audio |
203 |
OTP_OEM_AUDIO_CUSTOMER_ID |
Write Only |
0xFFFFFFFF |
NO |
32-bit OEM Audio Customer ID |
204 |
OTP_PRODUCTION_CHIP_FLAG |
Read / Write |
0x00000007 |
NO |
3-bit 0:Development chip 7: Production Chip |
205 |
OTP_USB_BOOT_DISABLE |
Read / Write |
0x00000001 |
NO |
1 = Disable USB boot |
206 |
OTP_FIELD_MAX |
N/A |
N/A |
N/A |
Enum boundary only |
Notes:
- OTP_USER_DATA_0 ~ 31:
This field is provided for user data storage. It supports per-bit masking programming.
- OTP_MP_PROVISION_DONE:
Set this field to 1 means all the MP provision are completed. There’s no restriction for otpread/otpwrite to distinguish this field to do anything different. But it would be a good indicator for provision are all complete if set OTP_MP_PROVISION_DONE = 1. It’s up to user to use this field if using otpread/otpwrite to do fusing stuff.
- OTP_SCS_AREA_SIZE_SEL:
0x0 : 385K (default)
- OTP_REE_JTAG_PROTECTION_POLICY:
0x0 : JTAG always enabled
0x1 : JTAG password protected
0x2 : JTAG always disabled
0x3 : JTAG always disabled
- OTP_PRODUCTION_CHIP_FLAG:
0x0 : Development chip. Both development and production image can run on this chip.
0x7 : Production chip. Only production image can run on this chip.
Notes: Basically, only production chips are shipped to customers. This field can be used to prevent development images from running on production chips.
- OTP_OEM_AUDIO_CUSTOMER_ID:
This field is used to store a 32-bit customer ID for Dolby Audio feature customization.
- OTP_BOOT_SECURITY_ENABLE:
This field by default is enabled in Astra chips before shipping to customers.
U-BOOT OTP Commands
otpread
- Usage:
otpread <otp_index> otpread 0 otpread 1
- Return Codes:
0x00000000 : Success 0xFF000001 : STATUS_FAILURE 0xFF000050 : STATUS_OTP_INVALID_IDX 0xFF000052 : STATUS_OTP_ERROR_WRITEONLY_FIELD
otpwrite
- Usage:
otpwrite <otp_index> <data> <mask> otpwrite 1 0x500 0xFFF otpwrite 2 0x1A2B3C4D 0xFFFFFFFF otpwrite 3 0x1A2B0000 0xFFFF0000 otpwrite 4 0x00010000 0x00010000
- Return Codes:
0x00000000 : Success 0xFF000001 : STATUS_FAILURE 0xFF000050 : STATUS_OTP_INVALID_IDX 0xFF000051 : STATUS_OTP_ERROR_READONLY_FIELD
- Examples:
=> otpread 0 otp operation succeed read otp[0] data=0x0000beaf, mask=0xffffffff => otpread 1 otp operation succeed read otp[1] data=0xbeafbeaf, mask=0xbeafffff => otpread 2 otp operation succeed read otp[2] data=0x0000beaf, mask=0x0000ffff => otpread 100 otp operation failed do_otp_read: ret = 0xff000052 read otp[100] data=0xdeadbeaf, mask=0xffffffff
Linux TA/CA OTP Commands
factory_util 6 otpread
- Usage:
factory_util 6 otpread <otp_index> factory_util 6 otpread 0 factory_util 6 otpread 1
- Return Codes:
0x00000000 : Success 0xFF000001 : STATUS_FAILURE 0xFF000050 : STATUS_OTP_INVALID_IDX 0xFF000052 : STATUS_OTP_ERROR_WRITEONLY_FIELD
factory_util 6 otpwrite
- Usage:
factory_util 6 otpwrite <otp_index> <data> <mask> factory_util 6 otpwrite 1 0x500 0xFFF factory_util 6 otpwrite 2 0x1A2B3C4D 0xFFFFFFFF factory_util 6 otpwrite 3 0x1A2B0000 0xFFFF0000 factory_util 6 otpwrite 4 0x00010000 0x00010000
- Return Codes:
0x00000000 : Success 0xFF000001 : STATUS_FAILURE 0xFF000050 : STATUS_OTP_INVALID_IDX 0xFF000051 : STATUS_OTP_ERROR_READONLY_FIELD
- Examples:
root@sl1640:~# factory_util 6 otpread 0 D/TA: __GP11_TA_InvokeCommandEntryPoint:82 CommandID = 0xe00c _otp_read: idx=0, val=0x0000BEAF, mask=0xFFFFFFFF OTP[0] = 0x0000BEAF, mask=0xFFFFFFFF root@sl1640:~# factory_util 6 otpread 1 D/TA: __GP11_TA_InvokeCommandEntryPoint:82 CommandID = 0xe00c _otp_read: idx=1, val=0xBEAFBEAF, mask=0xBEAFFFFF OTP[1] = 0xBEAFBEAF, mask=0xBEAFFFFF root@sl1640:~# factory_util 6 otpread 100 D/TA: __GP11_TA_InvokeCommandEntryPoint:82 CommandID = 0xe00c _otp_read:744: Invoke failed, res=0xff000052 origin=4 _otp_read: idx=100, val=0xDEADBEAF, mask=0xFFFFFFFF otpread failed for index 100 (status=1)
Note
By default, the factory utilities are installed in astra-media images. If not present, can add the package by adding below line to conf/local.conf and build image.
IMAGE_INSTALL_append = “ synasdk-factory-ta synasdk-drm-factory-ca-program”
- Once package is installed, should find below ta and factory utilities in the target device:
/usr/lib/optee_armtz/1316a183-894d-43fe-9893-bb946ae10420.ta
/usr/bin/factory_util
Common OTP Index List
Idx
Name
0
OTP_USER_DATA_0
1
OTP_USER_DATA_1
:
:
31
OTP_USER_DATA_31
100
OTP_K0_OEM_HASH_0
101
OTP_K0_OEM_HASH_1
102
OTP_K0_OEM_HASH_2
103
OTP_K0_OEM_HASH_3
104
OTP_K0_OEM_HASH_4
105
OTP_K0_OEM_HASH_5
106
OTP_K0_OEM_HASH_6
107
OTP_K0_OEM_HASH_7
108
OTP_AESK0_0
109
OTP_AESK0_1
110
OTP_AESK0_2
111
OTP_AESK0_3
112
OTP_REE_SEGID
113
OTP_REE_SECURITY_ENABLE
114
OTP_BOOT_SECURITY_ENABLE
115
OTP_MP_PROVISION_DONE
116
OTP_SCS_AREA_SIZE_SEL
117
OTP_REE_JTAG_PROTECTION_POLICY
200
OTP_EMMC_BOOT_DISABLE
201
OTP_SPI_BOOT_DISABLE
202
OTP_DOLBY_AUDIO_DISABLE
203
OTP_OEM_AUDIO_CUSTOMER_ID
204
OTP_PRODUCTION_CHIP_FLAG
205
OTP_USB_BOOT_DISABLE
206
OTP_FIELD_MAX
Important Programming Rules
Except for OTP_USER_DATA_0-31 which supports per-bits fusing access, for other fields, please follow below mask guideline:
1-bit fields must use mask = 0x00000001
2-bit fields must use mask = 0x00000003
3-bit fields must use mask = 0x00000007
32-bit fields must use mask = 0xFFFFFFFF
WRITE-ONLY OTP Field Readback Behavior
If a write-only field is read:
- Return Code:
0xFF000052 : STATUS_OTP_ERROR_WRITEONLY_FIELD
- Returned Data:
0xDEADBEAF (INVALID DUMMY DATA)
- Returned Mask:
VALID. Mask would reflect whether the OTP field is programmed. 0x0 = not programmed; 0xFFFFFFFF = fully programmed.
- Examples:
root@sl1640:~# factory_util 6 otpread 100 _otp_read:744: Invoke failed, res=0xff000052 origin=4 _otp_read: idx=100, val=0xDEADBEAF, mask=0xFFFFFFFF otpread failed for index 100 (status=1)
If the mask=0xFFFFFFFF, which means all the 32-bits of the field are all programmed.
OTP_USER_DATA_0~31 Mask Usage
Write of OTP_USER_DATA_0~31 would only program bits set in the mask. Bits not set in the mask would remain unchanged.
If the mask specifies bits already programmed, those bits would be ignored and not cause error.
- Supports:
Per-bit masking
Per-n-bit masking
Full 32-bit masking
- Examples:
# Per-bit masking examples => otpwrite 0 0x00000001 0x00000001 => otpwrite 0 0x000000F0 0x000000F0 => otpwrite 0 0xA5A5A5A5 0xFFFFFFFF # Bit masking examples # Preexisting otp[5] = 0x0000000a, mask=0x0000000f # Write otp[5] 0x000000a7 mask=0x000000ff # Final otp[5] = 0x000000aa, mask=0x000000ff => otpwrite 5 0xA 0xF otp operation succeed => otpread 5 otp operation succeed read otp[5] data=0x0000000a, mask=0x0000000f => otpwrite 5 0xa7 0xff otp operation succeed => otpread 5 otp operation succeed read otp[5] data=0x000000aa, mask=0x000000ff
Atomic Programming Rules
Atomic group includes:
OTP_K0_OEM_HASH_0 ~ OTP_K0_OEM_HASH_7
OTP_AESK0_0 ~ OTP_AESK0_3
OTP_REE_SEGID
OTP_REE_SECURITY_ENABLE
Rules:
ALL atomic items must be programmed in ONE SESSION. Once reboot or power loss, it would mean enter a new SESSION.
NO reboot or power loss is allowed before completion.
It is FORBIDDEN to program HASH/AESK0 and set OTP_REE_SECURITY_ENABLE = 0.
Any violation may result in PERMANENT BRICK.
Notes:
There’s no constrain for the command sequence of atomic items inside the same SESSION.
For none-atomic fields, there’s no constrain to program in any SESSION.
Tools to generate OTP commands
It is strongly recommended to use the helper script gen_otp_command.py to generate OTP programming commands instead of writing them by hand.
The tool can be found under Factory repository at
factory/scripts/[platypus/dolphin/myna2/]/factory. platypus: SL1640, dolphin: SL1680, myna2: SL1620.
- Examples: (Platypus: SL1640)
$sdk/factory/scripts/platypus/factory$ ./gen_otp_command.py
When the command completes, two files will be generated in the current directory:
otp_commands_uboot.txt: U-Boot otpwrite commands
otp_commands_linux.txt: Linux factory_util 6 otpwrite commands
The script performs the following:
- Reads OTP configuration from
configs/oem_config.conf
keys/K0_REE_hash.bin
keys/AESK0.bin
Applies the mask rules described in this document
- Enforces atomic programming rules for:
OTP_K0_OEM_HASH_0 ~ 7
OTP_AESK0_0 ~ 3
OTP_REE_SEGID
OTP_REE_SECURITY_ENABLE
- Treats OTP_MP_PROVISION_DONE as a special case:
If its value is 0, the command is skipped and a [SKIP] message is printed
User can perform the OTP_MP_PROVISION_DONE = 1 command when ALL the OTP fields are done in the LAST production SESSION.
Tags atomic items in the debug output with [Atomic]
A sample configs/oem_config.conf configuration file is shown below
### This file contains default settings for OTP programming during manufacturing.
### Modify the parameters as needed for your specific OEM requirements.
### Items commented out are optional and can be enabled if required.
[Segmentation ID]
ree_segid = 0x2E32000A
[Version]
ree_version = 0
[OTP_REE_SECURITY_ENABLE]
ree_security_enable = 1
[OTP_BOOT_SECURITY_ENABLE]
#boot_security_enable = 1
[OTP_MP_PROVISION_DONE]
mp_provision_done = 0
[OTP_SCS_AREA_SIZE_SEL]
scs_area_size_sel = 0
[OTP_REE_JTAG_PROTECTION_POLICY]
ree_jtag_protection_policy = 1
[OTP_EMMC_BOOT_DISABLE]
emmc_boot_disable = 0
[OTP_SPI_BOOT_DISABLE]
spi_boot_disable = 0
[OTP_USB_BOOT_DISABLE]
usb_boot_disable = 0
[OTP_OEM_AUDIO_CUSTOMER_ID]
#oem_audio_customer_id = 0x00000000
[OTP_PRODUCTION_CHIP_FLAG]
#production_chip_flag = 7
Below is a sample execution log:
$sdk/factory/scripts/platypus/factory$ ./gen_otp_command.py [SKIP] OTP_MP_PROVISION_DONE value is 0, command not generated otpwrite 100 0xc4ddf49e 0xffffffff [Atomic] otpwrite 101 0xe0593948 0xffffffff [Atomic] otpwrite 102 0xde9b8638 0xffffffff [Atomic] otpwrite 103 0x81ace868 0xffffffff [Atomic] otpwrite 104 0x2a629998 0xffffffff [Atomic] otpwrite 105 0xd105297d 0xffffffff [Atomic] otpwrite 106 0x8559f683 0xffffffff [Atomic] otpwrite 107 0xd92484ee 0xffffffff [Atomic] otpwrite 108 0x60c500da 0xffffffff [Atomic] otpwrite 109 0x08625e40 0xffffffff [Atomic] otpwrite 110 0xf5c13936 0xffffffff [Atomic] otpwrite 111 0x908e3b76 0xffffffff [Atomic] otpwrite 112 0x00000000 0xffffffff [Atomic] otpwrite 113 0x00000001 0x00000001 [Atomic] otpwrite 116 0x00000000 0x00000003 otpwrite 117 0x00000001 0x00000003 otpwrite 200 0x00000000 0x00000001 otpwrite 201 0x00000000 0x00000001 otpwrite 205 0x00000000 0x00000001 [OK] Wrote 19 lines to otp_commands_uboot.txt [OK] Wrote 19 lines to otp_commands_linux.txt
Notes:
Lines tagged with [Atomic] belong to the atomic security group and MUST be programmed as part of one provisioning session without reboot or power loss.
- otp_commands_uboot.txt contains commands in the form to perform in u-boot:
otpwrite <idx> <value> <mask>
- otp_commands_linux.txt contains commands in the form to perform in Linux:
factory_util 6 otpwrite <idx> <value> <mask>