169d5fd8fSJohnny Huang /* 269d5fd8fSJohnny Huang * This program is distributed in the hope that it will be useful, 369d5fd8fSJohnny Huang * but WITHOUT ANY WARRANTY; without even the implied warranty of 469d5fd8fSJohnny Huang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 569d5fd8fSJohnny Huang * GNU General Public License for more details. 669d5fd8fSJohnny Huang * 769d5fd8fSJohnny Huang * You should have received a copy of the GNU General Public License 869d5fd8fSJohnny Huang * along with this program; if not, write to the Free Software 969d5fd8fSJohnny Huang * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1069d5fd8fSJohnny Huang */ 114c1c9b35SJohnny Huang #include <stdlib.h> 1269d5fd8fSJohnny Huang #include <common.h> 1369d5fd8fSJohnny Huang #include <console.h> 1469d5fd8fSJohnny Huang #include <bootretry.h> 1569d5fd8fSJohnny Huang #include <cli.h> 1669d5fd8fSJohnny Huang #include <command.h> 1769d5fd8fSJohnny Huang #include <console.h> 184c1c9b35SJohnny Huang #include <malloc.h> 1969d5fd8fSJohnny Huang #include <inttypes.h> 2069d5fd8fSJohnny Huang #include <mapmem.h> 2169d5fd8fSJohnny Huang #include <asm/io.h> 2269d5fd8fSJohnny Huang #include <linux/compiler.h> 2369d5fd8fSJohnny Huang 2469d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR; 2569d5fd8fSJohnny Huang 2669d5fd8fSJohnny Huang #define OTP_PASSWD 0x349fe38a 2769d5fd8fSJohnny Huang #define RETRY 3 28a6d0d645SJohnny Huang #define OTP_REGION_STRAP 1 29a6d0d645SJohnny Huang #define OTP_REGION_CONF 2 30a6d0d645SJohnny Huang #define OTP_REGION_DATA 3 31a6d0d645SJohnny Huang #define OTP_REGION_ALL 4 3269d5fd8fSJohnny Huang 33e1f9e54eSJohnny Huang #define DISABLE_SECREG_PROG BIT(0) 34e1f9e54eSJohnny Huang #define ENABLE_SEC_BOOT BIT(1) 35e1f9e54eSJohnny Huang #define INIT_PROG_DONE BIT(2) 36e1f9e54eSJohnny Huang #define ENABLE_USERREG_ECC BIT(3) 37e1f9e54eSJohnny Huang #define ENABLE_SECREG_ECC BIT(4) 38e1f9e54eSJohnny Huang #define DISABLE_LOW_SEC_KEY BIT(5) 39e1f9e54eSJohnny Huang #define IGNORE_SEC_BOOT_HWSTRAP BIT(6) 40e1f9e54eSJohnny Huang #define SEC_BOOT_MDOES(x) (x >> 7) 41e1f9e54eSJohnny Huang #define SEC_MODE1 0x0 42e1f9e54eSJohnny Huang #define SEC_MODE2 0x1 43e1f9e54eSJohnny Huang #define OTP_BIT_CELL_MODES(x) ((x >> 8) & 0x3) 44e1f9e54eSJohnny Huang #define SINGLE_CELL_MODE 0x0 45e1f9e54eSJohnny Huang #define DIFFERENTIAL_MODE 0x1 46e1f9e54eSJohnny Huang #define DIFFERENTIAL_REDUDANT_MODE 0x2 47e1f9e54eSJohnny Huang #define CRYPTO_MODES(x) ((x >> 10) & 0x3) 48e1f9e54eSJohnny Huang #define CRYPTO_RSA1024 0x0 49e1f9e54eSJohnny Huang #define CRYPTO_RSA2048 0x1 50e1f9e54eSJohnny Huang #define CRYPTO_RSA3072 0x2 51e1f9e54eSJohnny Huang #define CRYPTO_RSA4096 0x3 52e1f9e54eSJohnny Huang #define HASH_MODES(x) ((x >> 12) & 0x3) 53e1f9e54eSJohnny Huang #define HASH_SAH224 0x0 54e1f9e54eSJohnny Huang #define HASH_SAH256 0x1 55e1f9e54eSJohnny Huang #define HASH_SAH384 0x2 56e1f9e54eSJohnny Huang #define HASH_SAH512 0x3 57e1f9e54eSJohnny Huang #define SECREG_SIZE(x) ((x >> 16) & 0x3f) 58e1f9e54eSJohnny Huang #define WRITE_PROTECT_SECREG BIT(22) 59e1f9e54eSJohnny Huang #define WRITE_PROTECT_USERREG BIT(23) 60e1f9e54eSJohnny Huang #define WRITE_PROTECT_CONFREG BIT(24) 61e1f9e54eSJohnny Huang #define WRITE_PROTECT_STRAPREG BIT(25) 62e1f9e54eSJohnny Huang #define ENABLE_COPY_TO_SRAM BIT(26) 63e1f9e54eSJohnny Huang #define ENABLE_IMAGE_ENC BIT(27) 64e1f9e54eSJohnny Huang #define WRITE_PROTECT_KEY_RETIRE BIT(29) 65e1f9e54eSJohnny Huang #define ENABLE_SIPROM_RED BIT(30) 66e1f9e54eSJohnny Huang #define ENABLE_SIPROM_MLOCK BIT(31) 67e1f9e54eSJohnny Huang 68e1f9e54eSJohnny Huang #define VENDER_ID(x) (x & 0xFFFF) 69e1f9e54eSJohnny Huang #define KEY_REVISION(x) ((x >> 16) & 0xFFFF) 70e1f9e54eSJohnny Huang 71e1f9e54eSJohnny Huang #define SEC_BOOT_HEADER_OFFSET(x) (x & 0xFFFF) 72e1f9e54eSJohnny Huang 73e1f9e54eSJohnny Huang #define KEYS_VALID_BITS(x) (x & 0xff) 74e1f9e54eSJohnny Huang #define KEYS_RETIRE_BITS(x) ((x >> 16) & 0xff) 754c1c9b35SJohnny Huang 764c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" 774c1c9b35SJohnny Huang #define PBWIDTH 60 784c1c9b35SJohnny Huang 794c1c9b35SJohnny Huang void printProgress(int numerator, int denominator, char *format, ...) 804c1c9b35SJohnny Huang { 814c1c9b35SJohnny Huang int val = numerator * 100 / denominator; 824c1c9b35SJohnny Huang int lpad = numerator * PBWIDTH / denominator; 834c1c9b35SJohnny Huang int rpad = PBWIDTH - lpad; 844c1c9b35SJohnny Huang char buffer[256]; 854c1c9b35SJohnny Huang va_list aptr; 864c1c9b35SJohnny Huang 874c1c9b35SJohnny Huang va_start(aptr, format); 884c1c9b35SJohnny Huang vsprintf(buffer, format, aptr); 894c1c9b35SJohnny Huang va_end(aptr); 904c1c9b35SJohnny Huang 914c1c9b35SJohnny Huang printf("\r%3d%% [%.*s%*s] %s", val, lpad, PBSTR, rpad, "", buffer); 924c1c9b35SJohnny Huang if (numerator == denominator) 934c1c9b35SJohnny Huang printf("\n"); 944c1c9b35SJohnny Huang } 954c1c9b35SJohnny Huang 9669d5fd8fSJohnny Huang struct otpstrap { 9769d5fd8fSJohnny Huang int value; 9869d5fd8fSJohnny Huang int option_array[7]; 9969d5fd8fSJohnny Huang int remain_times; 10069d5fd8fSJohnny Huang int writeable_option; 10169d5fd8fSJohnny Huang int protected; 10269d5fd8fSJohnny Huang }; 10369d5fd8fSJohnny Huang 10469d5fd8fSJohnny Huang static int otp_read_data(uint32_t offset, uint32_t *data) 10569d5fd8fSJohnny Huang { 10669d5fd8fSJohnny Huang writel(offset, 0x1e6f2010); //Read address 10769d5fd8fSJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 10869d5fd8fSJohnny Huang udelay(2); 10969d5fd8fSJohnny Huang data[0] = readl(0x1e6f2020); 11069d5fd8fSJohnny Huang data[1] = readl(0x1e6f2024); 11169d5fd8fSJohnny Huang return 1; 11269d5fd8fSJohnny Huang } 11369d5fd8fSJohnny Huang 11469d5fd8fSJohnny Huang static int otp_read_config(uint32_t offset, uint32_t *data) 11569d5fd8fSJohnny Huang { 11669d5fd8fSJohnny Huang int config_offset; 11769d5fd8fSJohnny Huang 11869d5fd8fSJohnny Huang config_offset = 0x800; 11969d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 12069d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 12169d5fd8fSJohnny Huang 12269d5fd8fSJohnny Huang writel(config_offset, 0x1e6f2010); //Read address 12369d5fd8fSJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 12469d5fd8fSJohnny Huang udelay(2); 12569d5fd8fSJohnny Huang data[0] = readl(0x1e6f2020); 12669d5fd8fSJohnny Huang 12769d5fd8fSJohnny Huang return 1; 12869d5fd8fSJohnny Huang } 12969d5fd8fSJohnny Huang 13069d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count) 13169d5fd8fSJohnny Huang { 13269d5fd8fSJohnny Huang int i; 13369d5fd8fSJohnny Huang uint32_t ret[1]; 13469d5fd8fSJohnny Huang 13569d5fd8fSJohnny Huang if (offset + dw_count > 32) 13669d5fd8fSJohnny Huang return -1; 13769d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i ++) { 13869d5fd8fSJohnny Huang otp_read_config(i, ret); 13969d5fd8fSJohnny Huang printf("OTPCFG%d: %08X\n", i, ret[0]); 14069d5fd8fSJohnny Huang } 14169d5fd8fSJohnny Huang printf("\n"); 14269d5fd8fSJohnny Huang return 1; 14369d5fd8fSJohnny Huang } 14469d5fd8fSJohnny Huang 14569d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count) 14669d5fd8fSJohnny Huang { 14769d5fd8fSJohnny Huang int i; 14869d5fd8fSJohnny Huang uint32_t ret[2]; 14969d5fd8fSJohnny Huang 15069d5fd8fSJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 15169d5fd8fSJohnny Huang return -1; 15269d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 15369d5fd8fSJohnny Huang otp_read_data(i, ret); 15469d5fd8fSJohnny Huang if (i % 4 == 0) 15569d5fd8fSJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 15669d5fd8fSJohnny Huang else 15769d5fd8fSJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 15869d5fd8fSJohnny Huang 15969d5fd8fSJohnny Huang } 16069d5fd8fSJohnny Huang printf("\n"); 16169d5fd8fSJohnny Huang return 1; 16269d5fd8fSJohnny Huang } 16369d5fd8fSJohnny Huang 16469d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr) 16569d5fd8fSJohnny Huang { 16669d5fd8fSJohnny Huang uint32_t ret; 16769d5fd8fSJohnny Huang uint32_t *buf; 16869d5fd8fSJohnny Huang 16969d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 17069d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 17169d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 17269d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 17369d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 17469d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //Compare address 17569d5fd8fSJohnny Huang writel(buf[0], 0x1e6f2020); //Compare data 1 17669d5fd8fSJohnny Huang writel(buf[1], 0x1e6f2024); //Compare data 2 17769d5fd8fSJohnny Huang writel(buf[2], 0x1e6f2028); //Compare data 3 17869d5fd8fSJohnny Huang writel(buf[3], 0x1e6f202c); //Compare data 4 17969d5fd8fSJohnny Huang writel(0x23b1e363, 0x1e6f2004); //Compare command 18069d5fd8fSJohnny Huang udelay(10); 18169d5fd8fSJohnny Huang ret = readl(0x1e6f2014); //Compare command 18269d5fd8fSJohnny Huang if (ret & 0x1) 18369d5fd8fSJohnny Huang return 0; 18469d5fd8fSJohnny Huang else 18569d5fd8fSJohnny Huang return -1; 18669d5fd8fSJohnny Huang } 18769d5fd8fSJohnny Huang 18869d5fd8fSJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data) 18969d5fd8fSJohnny Huang { 19069d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //write address 19169d5fd8fSJohnny Huang writel(data, 0x1e6f2020); //write data 19269d5fd8fSJohnny Huang writel(0x23b1e362, 0x1e6f2004); //write command 19369d5fd8fSJohnny Huang udelay(100); 19469d5fd8fSJohnny Huang } 19569d5fd8fSJohnny Huang 19669d5fd8fSJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit) 19769d5fd8fSJohnny Huang { 19869d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //write address 19969d5fd8fSJohnny Huang writel(prog_bit, 0x1e6f2020); //write data 20069d5fd8fSJohnny Huang writel(0x23b1e364, 0x1e6f2004); //write command 20169d5fd8fSJohnny Huang udelay(85); 20269d5fd8fSJohnny Huang } 20369d5fd8fSJohnny Huang 204a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value) 20569d5fd8fSJohnny Huang { 20669d5fd8fSJohnny Huang int ret; 20769d5fd8fSJohnny Huang 20869d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //Read address 20969d5fd8fSJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 21069d5fd8fSJohnny Huang udelay(2); 21169d5fd8fSJohnny Huang ret = readl(0x1e6f2020); 212a6d0d645SJohnny Huang // printf("verify_bit = %x\n", ret); 21369d5fd8fSJohnny Huang if (((ret >> bit_offset) & 1) == value) 21469d5fd8fSJohnny Huang return 0; 21569d5fd8fSJohnny Huang else 21669d5fd8fSJohnny Huang return -1; 21769d5fd8fSJohnny Huang } 21869d5fd8fSJohnny Huang 219*d90825e2SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *keep, uint32_t *compare, int size) 2204c1c9b35SJohnny Huang { 2214c1c9b35SJohnny Huang uint32_t ret[2]; 2224c1c9b35SJohnny Huang 2234c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 2244c1c9b35SJohnny Huang 2254c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 2264c1c9b35SJohnny Huang writel(otp_addr, 0x1e6f2010); //Read address 2274c1c9b35SJohnny Huang else 2284c1c9b35SJohnny Huang writel(otp_addr - 1, 0x1e6f2010); //Read address 2294c1c9b35SJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 2304c1c9b35SJohnny Huang udelay(2); 2314c1c9b35SJohnny Huang ret[0] = readl(0x1e6f2020); 2324c1c9b35SJohnny Huang ret[1] = readl(0x1e6f2024); 2334c1c9b35SJohnny Huang if (size == 1) { 2344c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 2354c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 236*d90825e2SJohnny Huang if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0])) { 2374c1c9b35SJohnny Huang compare[0] = 0; 2384c1c9b35SJohnny Huang return 0; 2394c1c9b35SJohnny Huang } else { 2404c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 2414c1c9b35SJohnny Huang return -1; 2424c1c9b35SJohnny Huang } 2434c1c9b35SJohnny Huang 2444c1c9b35SJohnny Huang } else { 2454c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 246*d90825e2SJohnny Huang if ((value[0] & ~keep[0]) == (ret[1] & ~keep[0])) { 2474c1c9b35SJohnny Huang compare[0] = ~0; 2484c1c9b35SJohnny Huang return 0; 2494c1c9b35SJohnny Huang } else { 250*d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 2514c1c9b35SJohnny Huang return -1; 2524c1c9b35SJohnny Huang } 2534c1c9b35SJohnny Huang } 2544c1c9b35SJohnny Huang } else if (size == 2) { 2554c1c9b35SJohnny Huang // otp_addr should be even 256*d90825e2SJohnny Huang if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0]) && (value[1] & ~keep[1]) == (ret[1] & ~keep[1])) { 2574c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 2584c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 2594c1c9b35SJohnny Huang compare[0] = 0; 2604c1c9b35SJohnny Huang compare[1] = ~0; 2614c1c9b35SJohnny Huang return 0; 2624c1c9b35SJohnny Huang } else { 2634c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 2644c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 2654c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 2664c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 2674c1c9b35SJohnny Huang return -1; 2684c1c9b35SJohnny Huang } 2694c1c9b35SJohnny Huang } else { 2704c1c9b35SJohnny Huang return -1; 2714c1c9b35SJohnny Huang } 2724c1c9b35SJohnny Huang } 2734c1c9b35SJohnny Huang 274*d90825e2SJohnny Huang void otp_soak(int soak) 275*d90825e2SJohnny Huang { 276*d90825e2SJohnny Huang if (soak) { 277*d90825e2SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 278*d90825e2SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 279*d90825e2SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 280*d90825e2SJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 281*d90825e2SJohnny Huang } else { 282*d90825e2SJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 283*d90825e2SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 284*d90825e2SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 285*d90825e2SJohnny Huang writel(0x04190760, 0x1e602008); //normal program 286*d90825e2SJohnny Huang } 287*d90825e2SJohnny Huang } 288*d90825e2SJohnny Huang 289*d90825e2SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t keep, uint32_t prog_address) 290*d90825e2SJohnny Huang { 291*d90825e2SJohnny Huang int j, bit_value, prog_bit; 292*d90825e2SJohnny Huang 293*d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 294*d90825e2SJohnny Huang if ((keep >> j) & 0x1) 295*d90825e2SJohnny Huang continue; 296*d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 297*d90825e2SJohnny Huang if (prog_address % 2 == 0) { 298*d90825e2SJohnny Huang if (bit_value) 299*d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 300*d90825e2SJohnny Huang else 301*d90825e2SJohnny Huang continue; 302*d90825e2SJohnny Huang } else { 303*d90825e2SJohnny Huang prog_address |= 1 << 15; 304*d90825e2SJohnny Huang if (bit_value) 305*d90825e2SJohnny Huang continue; 306*d90825e2SJohnny Huang else 307*d90825e2SJohnny Huang prog_bit = 0x1 << j; 308*d90825e2SJohnny Huang } 309*d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 310*d90825e2SJohnny Huang } 311*d90825e2SJohnny Huang } 312*d90825e2SJohnny Huang 31369d5fd8fSJohnny Huang static int otp_conf_parse(uint32_t *OTPCFG) 31469d5fd8fSJohnny Huang { 3154c1c9b35SJohnny Huang int tmp, i; 3164c1c9b35SJohnny Huang int pass = 0; 31769d5fd8fSJohnny Huang 31869d5fd8fSJohnny Huang printf("OTPCFG0-D[0]\n"); 319e1f9e54eSJohnny Huang if (OTPCFG[0] & DISABLE_SECREG_PROG) 32069d5fd8fSJohnny Huang printf(" Disable Secure Region programming\n"); 32169d5fd8fSJohnny Huang else 32269d5fd8fSJohnny Huang printf(" Enable Secure Region programming\n"); 32369d5fd8fSJohnny Huang printf("OTPCFG0-D[1]\n"); 324e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SEC_BOOT) 32569d5fd8fSJohnny Huang printf(" Enable Secure Boot\n"); 32669d5fd8fSJohnny Huang else 32769d5fd8fSJohnny Huang printf(" Disable Secure Boot\n"); 32869d5fd8fSJohnny Huang printf("OTPCFG0-D[3]\n"); 329e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_USERREG_ECC) 33069d5fd8fSJohnny Huang printf(" User region ECC enable\n"); 33169d5fd8fSJohnny Huang else 33269d5fd8fSJohnny Huang printf(" User region ECC disable\n"); 33369d5fd8fSJohnny Huang printf("OTPCFG0-D[4]\n"); 334e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SECREG_ECC) 33569d5fd8fSJohnny Huang printf(" Secure Region ECC enable\n"); 33669d5fd8fSJohnny Huang else 33769d5fd8fSJohnny Huang printf(" Secure Region ECC disable\n"); 33869d5fd8fSJohnny Huang printf("OTPCFG0-D[5]\n"); 339e1f9e54eSJohnny Huang if (OTPCFG[0] & DISABLE_LOW_SEC_KEY) 34069d5fd8fSJohnny Huang printf(" Disable low security key\n"); 34169d5fd8fSJohnny Huang else 34269d5fd8fSJohnny Huang printf(" Enable low security key\n"); 34369d5fd8fSJohnny Huang printf("OTPCFG0-D[6]\n"); 344e1f9e54eSJohnny Huang if (OTPCFG[0] & IGNORE_SEC_BOOT_HWSTRAP) 34569d5fd8fSJohnny Huang printf(" Ignore Secure Boot hardware strap\n"); 34669d5fd8fSJohnny Huang else 34769d5fd8fSJohnny Huang printf(" Do not ignore Secure Boot hardware strap\n"); 34869d5fd8fSJohnny Huang printf("OTPCFG0-D[7]\n"); 349e1f9e54eSJohnny Huang if (SEC_BOOT_MDOES(OTPCFG[0]) == SEC_MODE1) 350e1f9e54eSJohnny Huang printf(" Secure Boot Mode: 1\n"); 351e1f9e54eSJohnny Huang else 352e1f9e54eSJohnny Huang printf(" Secure Boot Mode: 2\n"); 35369d5fd8fSJohnny Huang printf("OTPCFG0-D[9:8]\n"); 35469d5fd8fSJohnny Huang printf(" OTP bit cell mode : "); 355e1f9e54eSJohnny Huang tmp = OTP_BIT_CELL_MODES(OTPCFG[0]); 356e1f9e54eSJohnny Huang if (tmp == SINGLE_CELL_MODE) { 35769d5fd8fSJohnny Huang printf("Single cell mode (recommended)\n"); 358e1f9e54eSJohnny Huang } else if (tmp == DIFFERENTIAL_MODE) { 35969d5fd8fSJohnny Huang printf("Differnetial mode\n"); 360e1f9e54eSJohnny Huang } else if (tmp == DIFFERENTIAL_REDUDANT_MODE) { 36169d5fd8fSJohnny Huang printf("Differential-redundant mode\n"); 36269d5fd8fSJohnny Huang } else { 36369d5fd8fSJohnny Huang printf("Value error\n"); 36469d5fd8fSJohnny Huang return -1; 36569d5fd8fSJohnny Huang } 36669d5fd8fSJohnny Huang printf("OTPCFG0-D[11:10]\n"); 36769d5fd8fSJohnny Huang printf(" RSA mode : "); 368e1f9e54eSJohnny Huang tmp = CRYPTO_MODES(OTPCFG[0]); 369e1f9e54eSJohnny Huang if (tmp == CRYPTO_RSA1024) { 37069d5fd8fSJohnny Huang printf("RSA1024\n"); 371e1f9e54eSJohnny Huang } else if (tmp == CRYPTO_RSA2048) { 37269d5fd8fSJohnny Huang printf("RSA2048\n"); 373e1f9e54eSJohnny Huang } else if (tmp == CRYPTO_RSA3072) { 37469d5fd8fSJohnny Huang printf("RSA3072\n"); 37569d5fd8fSJohnny Huang } else { 37669d5fd8fSJohnny Huang printf("RSA4096\n"); 37769d5fd8fSJohnny Huang } 37869d5fd8fSJohnny Huang printf("OTPCFG0-D[13:12]\n"); 37969d5fd8fSJohnny Huang printf(" SHA mode : "); 380e1f9e54eSJohnny Huang tmp = HASH_MODES(OTPCFG[0]); 381e1f9e54eSJohnny Huang if (tmp == HASH_SAH224) { 38269d5fd8fSJohnny Huang printf("SHA224\n"); 383e1f9e54eSJohnny Huang } else if (tmp == HASH_SAH256) { 38469d5fd8fSJohnny Huang printf("SHA256\n"); 385e1f9e54eSJohnny Huang } else if (tmp == HASH_SAH384) { 38669d5fd8fSJohnny Huang printf("SHA384\n"); 38769d5fd8fSJohnny Huang } else { 38869d5fd8fSJohnny Huang printf("SHA512\n"); 38969d5fd8fSJohnny Huang } 39069d5fd8fSJohnny Huang 39169d5fd8fSJohnny Huang printf("OTPCFG0-D[21:16]\n"); 392e1f9e54eSJohnny Huang printf(" Secure Region size (DW): %x\n", SECREG_SIZE(OTPCFG[0])); 39369d5fd8fSJohnny Huang 39469d5fd8fSJohnny Huang printf("OTPCFG0-D[22]\n"); 395e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_SECREG) 39669d5fd8fSJohnny Huang printf(" Secure Region : Write Protect\n"); 39769d5fd8fSJohnny Huang else 39869d5fd8fSJohnny Huang printf(" Secure Region : Writable\n"); 39969d5fd8fSJohnny Huang printf("OTPCFG0-D[23]\n"); 400e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_USERREG) 40169d5fd8fSJohnny Huang printf(" User Region : Write Protect\n"); 40269d5fd8fSJohnny Huang else 40369d5fd8fSJohnny Huang printf(" User Region : Writable\n"); 40469d5fd8fSJohnny Huang printf("OTPCFG0-D[24]\n"); 405e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_CONFREG) 40669d5fd8fSJohnny Huang printf(" Configure Region : Write Protect\n"); 40769d5fd8fSJohnny Huang else 40869d5fd8fSJohnny Huang printf(" Configure Region : Writable\n"); 40969d5fd8fSJohnny Huang printf("OTPCFG0-D[25]\n"); 410e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_STRAPREG) 41169d5fd8fSJohnny Huang printf(" OTP strap Region : Write Protect\n"); 41269d5fd8fSJohnny Huang else 41369d5fd8fSJohnny Huang printf(" OTP strap Region : Writable\n"); 41469d5fd8fSJohnny Huang printf("OTPCFG0-D[26]\n"); 415e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_COPY_TO_SRAM) 41669d5fd8fSJohnny Huang printf(" Copy Boot Image to Internal SRAM\n"); 41769d5fd8fSJohnny Huang else 41869d5fd8fSJohnny Huang printf(" Disable Copy Boot Image to Internal SRAM\n"); 41969d5fd8fSJohnny Huang printf("OTPCFG0-D[27]\n"); 420e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_IMAGE_ENC) 42169d5fd8fSJohnny Huang printf(" Enable image encryption\n"); 42269d5fd8fSJohnny Huang else 42369d5fd8fSJohnny Huang printf(" Disable image encryption\n"); 42469d5fd8fSJohnny Huang printf("OTPCFG0-D[29]\n"); 425e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_KEY_RETIRE) 42669d5fd8fSJohnny Huang printf(" OTP key retire Region : Write Protect\n"); 42769d5fd8fSJohnny Huang else 42869d5fd8fSJohnny Huang printf(" OTP key retire Region : Writable\n"); 42969d5fd8fSJohnny Huang printf("OTPCFG0-D[30]\n"); 430e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SIPROM_RED) 43169d5fd8fSJohnny Huang printf(" SIPROM RED_EN redundancy repair enable\n"); 43269d5fd8fSJohnny Huang else 43369d5fd8fSJohnny Huang printf(" SIPROM RED_EN redundancy repair disable\n"); 43469d5fd8fSJohnny Huang printf("OTPCFG0-D[31]\n"); 435e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SIPROM_MLOCK) 43669d5fd8fSJohnny Huang printf(" SIPROM Mlock memory lock enable\n"); 43769d5fd8fSJohnny Huang else 43869d5fd8fSJohnny Huang printf(" SIPROM Mlock memory lock disable\n"); 43969d5fd8fSJohnny Huang 44069d5fd8fSJohnny Huang printf("OTPCFG2-D[15:0]\n"); 441e1f9e54eSJohnny Huang printf(" Vender ID : %x\n", VENDER_ID(OTPCFG[2])); 44269d5fd8fSJohnny Huang 44369d5fd8fSJohnny Huang printf("OTPCFG2-D[31:16]\n"); 444e1f9e54eSJohnny Huang printf(" Key Revision : %x\n", KEY_REVISION(OTPCFG[2])); 44569d5fd8fSJohnny Huang 44669d5fd8fSJohnny Huang printf("OTPCFG3-D[15:0]\n"); 447e1f9e54eSJohnny Huang printf(" Secure boot header offset : %x\n", 448e1f9e54eSJohnny Huang SEC_BOOT_HEADER_OFFSET(OTPCFG[3])); 44969d5fd8fSJohnny Huang 45069d5fd8fSJohnny Huang printf("OTPCFG4-D[7:0]\n"); 451e1f9e54eSJohnny Huang tmp = KEYS_VALID_BITS(OTPCFG[4]); 452e1f9e54eSJohnny Huang if (tmp != 0) { 45369d5fd8fSJohnny Huang for (i = 0; i < 7; i++) { 45469d5fd8fSJohnny Huang if (tmp == (1 << i)) { 455e1f9e54eSJohnny Huang pass = i + 1; 45669d5fd8fSJohnny Huang } 45769d5fd8fSJohnny Huang } 458e1f9e54eSJohnny Huang } else { 459e1f9e54eSJohnny Huang pass = 0; 460e1f9e54eSJohnny Huang } 461e1f9e54eSJohnny Huang printf(" Keys valid : %d\n", pass); 46269d5fd8fSJohnny Huang 46369d5fd8fSJohnny Huang printf("OTPCFG4-D[23:16]\n"); 464e1f9e54eSJohnny Huang tmp = KEYS_RETIRE_BITS(OTPCFG[4]); 465e1f9e54eSJohnny Huang if (tmp != 0) { 46669d5fd8fSJohnny Huang for (i = 0; i < 7; i++) { 46769d5fd8fSJohnny Huang if (tmp == (1 << i)) { 468e1f9e54eSJohnny Huang pass = i + 1; 46969d5fd8fSJohnny Huang } 47069d5fd8fSJohnny Huang } 471e1f9e54eSJohnny Huang } else { 472e1f9e54eSJohnny Huang pass = 0; 47369d5fd8fSJohnny Huang } 47469d5fd8fSJohnny Huang printf(" Keys Retire ID : %d\n", pass); 47569d5fd8fSJohnny Huang 47669d5fd8fSJohnny Huang printf("OTPCFG5-D[31:0]\n"); 47769d5fd8fSJohnny Huang printf(" User define data, random number low : %x\n", OTPCFG[5]); 47869d5fd8fSJohnny Huang 47969d5fd8fSJohnny Huang printf("OTPCFG6-D[31:0]\n"); 48069d5fd8fSJohnny Huang printf(" User define data, random number high : %x\n", OTPCFG[6]); 48169d5fd8fSJohnny Huang 48269d5fd8fSJohnny Huang printf("OTPCFG8-D[31:0]\n"); 48369d5fd8fSJohnny Huang printf(" Redundancy Repair : %x\n", OTPCFG[8]); 48469d5fd8fSJohnny Huang 48569d5fd8fSJohnny Huang printf("OTPCFG10-D[31:0]\n"); 48669d5fd8fSJohnny Huang printf(" Manifest ID low : %x\n", OTPCFG[10]); 48769d5fd8fSJohnny Huang 48869d5fd8fSJohnny Huang printf("OTPCFG11-D[31:0]\n"); 48969d5fd8fSJohnny Huang printf(" Manifest ID high : %x\n", OTPCFG[11]); 49069d5fd8fSJohnny Huang return 0; 49169d5fd8fSJohnny Huang 49269d5fd8fSJohnny Huang } 49369d5fd8fSJohnny Huang 49469d5fd8fSJohnny Huang static void buf_print(char *buf, int len) 49569d5fd8fSJohnny Huang { 49669d5fd8fSJohnny Huang int i; 49769d5fd8fSJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 49869d5fd8fSJohnny Huang for (i = 0; i < len; i++) { 49969d5fd8fSJohnny Huang if (i % 16 == 0) { 50069d5fd8fSJohnny Huang printf("%04X: ", i); 50169d5fd8fSJohnny Huang } 50269d5fd8fSJohnny Huang printf("%02X ", buf[i]); 50369d5fd8fSJohnny Huang if ((i + 1) % 16 == 0) { 50469d5fd8fSJohnny Huang printf("\n"); 50569d5fd8fSJohnny Huang } 50669d5fd8fSJohnny Huang } 50769d5fd8fSJohnny Huang } 50869d5fd8fSJohnny Huang 509*d90825e2SJohnny Huang static int otp_data_parse(uint32_t *buf) 51069d5fd8fSJohnny Huang { 51169d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 51269d5fd8fSJohnny Huang char *byte_buf; 51369d5fd8fSJohnny Huang int i = 0, len = 0; 51469d5fd8fSJohnny Huang byte_buf = (char *)buf; 51569d5fd8fSJohnny Huang while (1) { 51669d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 51769d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 51869d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 51969d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 52069d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 52169d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 52269d5fd8fSJohnny Huang printf("Key[%d]:\n", i); 52369d5fd8fSJohnny Huang printf("Key Type: "); 52469d5fd8fSJohnny Huang switch (key_type) { 52569d5fd8fSJohnny Huang case 0: 52669d5fd8fSJohnny Huang printf("AES-256 as OEM platform key for image encryption/decryption\n"); 52769d5fd8fSJohnny Huang break; 52869d5fd8fSJohnny Huang case 1: 52969d5fd8fSJohnny Huang printf("AES-256 as secret vault key\n"); 53069d5fd8fSJohnny Huang break; 53169d5fd8fSJohnny Huang case 4: 53269d5fd8fSJohnny Huang printf("HMAC as encrypted OEM HMAC keys in Mode 1\n"); 53369d5fd8fSJohnny Huang break; 53469d5fd8fSJohnny Huang case 8: 53569d5fd8fSJohnny Huang printf("RSA-public as OEM DSS public keys in Mode 2\n"); 53669d5fd8fSJohnny Huang break; 53769d5fd8fSJohnny Huang case 9: 53869d5fd8fSJohnny Huang printf("RSA-public as SOC public key\n"); 53969d5fd8fSJohnny Huang break; 54069d5fd8fSJohnny Huang case 10: 54169d5fd8fSJohnny Huang printf("RSA-public as AES key decryption key\n"); 54269d5fd8fSJohnny Huang break; 54369d5fd8fSJohnny Huang case 13: 54469d5fd8fSJohnny Huang printf("RSA-private as SOC private key\n"); 54569d5fd8fSJohnny Huang break; 54669d5fd8fSJohnny Huang case 14: 54769d5fd8fSJohnny Huang printf("RSA-private as AES key decryption key\n"); 54869d5fd8fSJohnny Huang break; 54969d5fd8fSJohnny Huang default: 55069d5fd8fSJohnny Huang printf("key_type error: %x\n", key_type); 55169d5fd8fSJohnny Huang return -1; 55269d5fd8fSJohnny Huang } 55369d5fd8fSJohnny Huang if (key_type == 4) { 55469d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 55569d5fd8fSJohnny Huang switch (key_length) { 55669d5fd8fSJohnny Huang case 0: 55769d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 55869d5fd8fSJohnny Huang break; 55969d5fd8fSJohnny Huang case 1: 56069d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 56169d5fd8fSJohnny Huang break; 56269d5fd8fSJohnny Huang case 2: 56369d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 56469d5fd8fSJohnny Huang break; 56569d5fd8fSJohnny Huang case 3: 56669d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 56769d5fd8fSJohnny Huang break; 56869d5fd8fSJohnny Huang } 569cd1610b4SJohnny Huang } else if (key_type != 0 && key_type != 1) { 57069d5fd8fSJohnny Huang printf("RSA SHA Type: "); 57169d5fd8fSJohnny Huang switch (key_length) { 57269d5fd8fSJohnny Huang case 0: 57369d5fd8fSJohnny Huang printf("RSA1024\n"); 57469d5fd8fSJohnny Huang len = 0x100; 57569d5fd8fSJohnny Huang break; 57669d5fd8fSJohnny Huang case 1: 57769d5fd8fSJohnny Huang printf("RSA2048\n"); 57869d5fd8fSJohnny Huang len = 0x200; 57969d5fd8fSJohnny Huang break; 58069d5fd8fSJohnny Huang case 2: 58169d5fd8fSJohnny Huang printf("RSA3072\n"); 58269d5fd8fSJohnny Huang len = 0x300; 58369d5fd8fSJohnny Huang break; 58469d5fd8fSJohnny Huang case 3: 58569d5fd8fSJohnny Huang printf("RSA4096\n"); 58669d5fd8fSJohnny Huang len = 0x400; 58769d5fd8fSJohnny Huang break; 58869d5fd8fSJohnny Huang } 58969d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 59069d5fd8fSJohnny Huang } 59169d5fd8fSJohnny Huang if (key_type == 4 || key_type == 8) 59269d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 59369d5fd8fSJohnny Huang printf("Key Value:\n"); 59469d5fd8fSJohnny Huang if (key_type == 4) { 59569d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 59669d5fd8fSJohnny Huang } else if (key_type == 0 || key_type == 1) { 59769d5fd8fSJohnny Huang printf("AES Key:\n"); 59869d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 59969d5fd8fSJohnny Huang printf("AES IV:\n"); 60069d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 60169d5fd8fSJohnny Huang 60269d5fd8fSJohnny Huang } else { 60369d5fd8fSJohnny Huang printf("RSA mod:\n"); 60469d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 60569d5fd8fSJohnny Huang printf("RSA exp:\n"); 60669d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 60769d5fd8fSJohnny Huang } 60869d5fd8fSJohnny Huang if (last) 60969d5fd8fSJohnny Huang break; 61069d5fd8fSJohnny Huang i++; 61169d5fd8fSJohnny Huang } 61269d5fd8fSJohnny Huang return 0; 61369d5fd8fSJohnny Huang } 61469d5fd8fSJohnny Huang 615a6d0d645SJohnny Huang static int otp_prog_conf(uint32_t *buf) 61669d5fd8fSJohnny Huang { 617a6d0d645SJohnny Huang int i, k; 618*d90825e2SJohnny Huang int pass = 0; 619*d90825e2SJohnny Huang int soak = 0; 620a6d0d645SJohnny Huang uint32_t prog_address; 621a6d0d645SJohnny Huang uint32_t data[12]; 622a6d0d645SJohnny Huang uint32_t compare[2]; 623*d90825e2SJohnny Huang uint32_t *buf_keep = &buf[12]; 624*d90825e2SJohnny Huang uint32_t data_masked; 625*d90825e2SJohnny Huang uint32_t buf_masked; 62669d5fd8fSJohnny Huang 627a6d0d645SJohnny Huang printf("Read OTP Config Region:\n"); 628a6d0d645SJohnny Huang 629a6d0d645SJohnny Huang printProgress(0, 12, ""); 630a6d0d645SJohnny Huang for (i = 0; i < 12 ; i ++) { 631a6d0d645SJohnny Huang printProgress(i + 1, 12, ""); 63269d5fd8fSJohnny Huang prog_address = 0x800; 633a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 634a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 635a6d0d645SJohnny Huang otp_read_data(prog_address, &data[i]); 636a6d0d645SJohnny Huang } 637a6d0d645SJohnny Huang 638a6d0d645SJohnny Huang printf("Check writable...\n"); 639a6d0d645SJohnny Huang for (i = 0; i < 12; i++) { 640*d90825e2SJohnny Huang data_masked = data[i] & ~buf_keep[i]; 641*d90825e2SJohnny Huang buf_masked = buf[i] & ~buf_keep[i]; 642*d90825e2SJohnny Huang if (data_masked == buf_masked) 64369d5fd8fSJohnny Huang continue; 644*d90825e2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 645a6d0d645SJohnny Huang continue; 646a6d0d645SJohnny Huang } else { 647a6d0d645SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 648a6d0d645SJohnny Huang printf("OTPCFG[%d] = %x\n", i, data[i]); 649a6d0d645SJohnny Huang printf("Input [%d] = %x\n", i, buf[i]); 650*d90825e2SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_keep[i]); 651*d90825e2SJohnny Huang return -1; 652a6d0d645SJohnny Huang } 653a6d0d645SJohnny Huang } 654a6d0d645SJohnny Huang 655a6d0d645SJohnny Huang printf("Start Programing...\n"); 656a6d0d645SJohnny Huang printProgress(0, 12, ""); 657*d90825e2SJohnny Huang otp_soak(0); 658a6d0d645SJohnny Huang for (i = 0; i < 12; i++) { 659*d90825e2SJohnny Huang data_masked = data[i] & ~buf_keep[i]; 660*d90825e2SJohnny Huang buf_masked = buf[i] & ~buf_keep[i]; 661a6d0d645SJohnny Huang prog_address = 0x800; 662a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 663a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 664*d90825e2SJohnny Huang if (data_masked == buf_masked) { 665a6d0d645SJohnny Huang printProgress(i + 1, 12, "[%03X]=%08X HIT", prog_address, buf[i]); 666a6d0d645SJohnny Huang continue; 667a6d0d645SJohnny Huang } 668*d90825e2SJohnny Huang if (soak) { 669*d90825e2SJohnny Huang soak = 0; 670*d90825e2SJohnny Huang otp_soak(0); 671*d90825e2SJohnny Huang } 672a6d0d645SJohnny Huang printProgress(i + 1, 12, "[%03X]=%08X ", prog_address, buf[i]); 673a6d0d645SJohnny Huang 674*d90825e2SJohnny Huang otp_prog_dw(buf[i], buf_keep[i], prog_address); 675a6d0d645SJohnny Huang 67669d5fd8fSJohnny Huang pass = 0; 67769d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 678*d90825e2SJohnny Huang if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 1) != 0) { 679*d90825e2SJohnny Huang if (soak == 0) { 680*d90825e2SJohnny Huang soak = 1; 681*d90825e2SJohnny Huang otp_soak(1); 682*d90825e2SJohnny Huang } 683a6d0d645SJohnny Huang otp_prog_dw(compare[0], prog_address, 1); 684a6d0d645SJohnny Huang } else { 68569d5fd8fSJohnny Huang pass = 1; 68669d5fd8fSJohnny Huang break; 68769d5fd8fSJohnny Huang } 68869d5fd8fSJohnny Huang } 689a6d0d645SJohnny Huang } 690a6d0d645SJohnny Huang 69169d5fd8fSJohnny Huang if (!pass) 692a6d0d645SJohnny Huang return -1; 693a6d0d645SJohnny Huang 694*d90825e2SJohnny Huang return 0; 695*d90825e2SJohnny Huang 69669d5fd8fSJohnny Huang } 69769d5fd8fSJohnny Huang 69869d5fd8fSJohnny Huang static void otp_strp_status(struct otpstrap *otpstrap) 69969d5fd8fSJohnny Huang { 70069d5fd8fSJohnny Huang uint32_t OTPSTRAP_RAW[2]; 70169d5fd8fSJohnny Huang int i, j; 70269d5fd8fSJohnny Huang 70369d5fd8fSJohnny Huang for (j = 0; j < 64; j++) { 70469d5fd8fSJohnny Huang otpstrap[j].value = 0; 70569d5fd8fSJohnny Huang otpstrap[j].remain_times = 7; 70669d5fd8fSJohnny Huang otpstrap[j].writeable_option = -1; 70769d5fd8fSJohnny Huang otpstrap[j].protected = 0; 70869d5fd8fSJohnny Huang } 70969d5fd8fSJohnny Huang 71069d5fd8fSJohnny Huang for (i = 16; i < 30; i += 2) { 71169d5fd8fSJohnny Huang int option = (i - 16) / 2; 71269d5fd8fSJohnny Huang otp_read_config(i, &OTPSTRAP_RAW[0]); 71369d5fd8fSJohnny Huang otp_read_config(i + 1, &OTPSTRAP_RAW[1]); 71469d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 71569d5fd8fSJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 71669d5fd8fSJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 71769d5fd8fSJohnny Huang otpstrap[j].writeable_option = option; 71869d5fd8fSJohnny Huang } 71969d5fd8fSJohnny Huang if (bit_value == 1) 72069d5fd8fSJohnny Huang otpstrap[j].remain_times --; 72169d5fd8fSJohnny Huang otpstrap[j].value ^= bit_value; 72269d5fd8fSJohnny Huang otpstrap[j].option_array[option] = bit_value; 72369d5fd8fSJohnny Huang } 72469d5fd8fSJohnny Huang for (j = 32; j < 64; j++) { 72569d5fd8fSJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 72669d5fd8fSJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 72769d5fd8fSJohnny Huang otpstrap[j].writeable_option = option; 72869d5fd8fSJohnny Huang } 72969d5fd8fSJohnny Huang if (bit_value == 1) 73069d5fd8fSJohnny Huang otpstrap[j].remain_times --; 73169d5fd8fSJohnny Huang otpstrap[j].value ^= bit_value; 73269d5fd8fSJohnny Huang otpstrap[j].option_array[option] = bit_value; 73369d5fd8fSJohnny Huang } 73469d5fd8fSJohnny Huang } 73569d5fd8fSJohnny Huang otp_read_config(30, &OTPSTRAP_RAW[0]); 73669d5fd8fSJohnny Huang otp_read_config(31, &OTPSTRAP_RAW[1]); 73769d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 73869d5fd8fSJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 73969d5fd8fSJohnny Huang otpstrap[j].protected = 1; 74069d5fd8fSJohnny Huang } 74169d5fd8fSJohnny Huang for (j = 32; j < 64; j++) { 74269d5fd8fSJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 74369d5fd8fSJohnny Huang otpstrap[j].protected = 1; 74469d5fd8fSJohnny Huang } 74569d5fd8fSJohnny Huang } 74669d5fd8fSJohnny Huang 74769d5fd8fSJohnny Huang static int otp_strap_parse(uint32_t *buf) 74869d5fd8fSJohnny Huang { 74969d5fd8fSJohnny Huang int i; 75069d5fd8fSJohnny Huang uint32_t *strap_keep = buf + 2; 75169d5fd8fSJohnny Huang uint32_t *strap_protect = buf + 4; 75269d5fd8fSJohnny Huang int bit, pbit, kbit; 75369d5fd8fSJohnny Huang int fail = 0; 75469d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 75569d5fd8fSJohnny Huang 75669d5fd8fSJohnny Huang otp_strp_status(otpstrap); 75769d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 75869d5fd8fSJohnny Huang if (i < 32) { 75969d5fd8fSJohnny Huang bit = (buf[0] >> i) & 0x1; 76069d5fd8fSJohnny Huang kbit = (strap_keep[0] >> i) & 0x1; 76169d5fd8fSJohnny Huang pbit = (strap_protect[0] >> i) & 0x1; 76269d5fd8fSJohnny Huang } else { 76369d5fd8fSJohnny Huang bit = (buf[1] >> (i - 32)) & 0x1; 76469d5fd8fSJohnny Huang kbit = (strap_keep[1] >> (i - 32)) & 0x1; 76569d5fd8fSJohnny Huang pbit = (strap_protect[1] >> (i - 32)) & 0x1; 76669d5fd8fSJohnny Huang } 76769d5fd8fSJohnny Huang 76869d5fd8fSJohnny Huang if (kbit == 1) { 76969d5fd8fSJohnny Huang continue; 77069d5fd8fSJohnny Huang } else { 77169d5fd8fSJohnny Huang printf("OTPSTRAP[%d]:\n", i); 77269d5fd8fSJohnny Huang } 77369d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 77469d5fd8fSJohnny Huang printf(" The value is same as before, skip it.\n"); 77569d5fd8fSJohnny Huang continue; 77669d5fd8fSJohnny Huang } 77769d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 77869d5fd8fSJohnny Huang printf(" This bit is protected and is not writable\n"); 77969d5fd8fSJohnny Huang fail = 1; 78069d5fd8fSJohnny Huang continue; 78169d5fd8fSJohnny Huang } 78269d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 78369d5fd8fSJohnny Huang printf(" This bit is no remaining number of times to write.\n"); 78469d5fd8fSJohnny Huang fail = 1; 78569d5fd8fSJohnny Huang continue; 78669d5fd8fSJohnny Huang } 78769d5fd8fSJohnny Huang if (pbit == 1) { 78869d5fd8fSJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 78969d5fd8fSJohnny Huang } 790cd1610b4SJohnny Huang printf(" Write 1 to OTPSTRAP[%d] OPTION[%d], that value becomes from %d to %d.\n", i, otpstrap[i].writeable_option + 1, otpstrap[i].value, otpstrap[i].value ^ 1); 79169d5fd8fSJohnny Huang } 79269d5fd8fSJohnny Huang if (fail == 1) 79369d5fd8fSJohnny Huang return -1; 79469d5fd8fSJohnny Huang else 79569d5fd8fSJohnny Huang return 0; 79669d5fd8fSJohnny Huang } 79769d5fd8fSJohnny Huang 798cd1610b4SJohnny Huang static void otp_print_strap(int start, int count) 79969d5fd8fSJohnny Huang { 80069d5fd8fSJohnny Huang int i, j; 80169d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 80269d5fd8fSJohnny Huang 80369d5fd8fSJohnny Huang otp_strp_status(otpstrap); 80469d5fd8fSJohnny Huang 805cd1610b4SJohnny Huang for (i = start; i < start + count; i++) { 80669d5fd8fSJohnny Huang printf("OTPSTRAP[%d]:\n", i); 80769d5fd8fSJohnny Huang printf(" OTP Option value: "); 80869d5fd8fSJohnny Huang for (j = 1; j <= 7; j++) 80969d5fd8fSJohnny Huang printf("[%d]:%d ", j, otpstrap[i].option_array[j - 1]); 81069d5fd8fSJohnny Huang printf("\n"); 81169d5fd8fSJohnny Huang printf(" OTP Value: %d\n", otpstrap[i].value); 81269d5fd8fSJohnny Huang printf(" Status:\n"); 81369d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 81469d5fd8fSJohnny Huang printf(" OTPSTRAP[%d] is protected and is not writable\n", i); 81569d5fd8fSJohnny Huang } else { 81669d5fd8fSJohnny Huang printf(" OTPSTRAP[%d] is not protected ", i); 81769d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 81869d5fd8fSJohnny Huang printf("and no remaining number of times to write.\n"); 81969d5fd8fSJohnny Huang } else { 82069d5fd8fSJohnny Huang printf("and still can write %d number of times\n", otpstrap[i].remain_times); 82169d5fd8fSJohnny Huang } 82269d5fd8fSJohnny Huang } 82369d5fd8fSJohnny Huang } 82469d5fd8fSJohnny Huang } 82569d5fd8fSJohnny Huang 82669d5fd8fSJohnny Huang static int otp_prog_strap(uint32_t *buf) 82769d5fd8fSJohnny Huang { 82869d5fd8fSJohnny Huang int i, j; 82969d5fd8fSJohnny Huang uint32_t *strap_keep = buf + 2; 83069d5fd8fSJohnny Huang uint32_t *strap_protect = buf + 4; 83169d5fd8fSJohnny Huang uint32_t prog_bit, prog_address; 83269d5fd8fSJohnny Huang int bit, pbit, kbit, offset; 83369d5fd8fSJohnny Huang int fail = 0; 83469d5fd8fSJohnny Huang int pass, soak; 83569d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 83669d5fd8fSJohnny Huang 83769d5fd8fSJohnny Huang otp_strp_status(otpstrap); 83869d5fd8fSJohnny Huang 83969d5fd8fSJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 84069d5fd8fSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 84169d5fd8fSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 84269d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 8434c1c9b35SJohnny Huang printProgress(i + 1, 64, ""); 84469d5fd8fSJohnny Huang prog_address = 0x800; 84569d5fd8fSJohnny Huang if (i < 32) { 84669d5fd8fSJohnny Huang offset = i; 84769d5fd8fSJohnny Huang bit = (buf[0] >> offset) & 0x1; 84869d5fd8fSJohnny Huang kbit = (strap_keep[0] >> offset) & 0x1; 84969d5fd8fSJohnny Huang pbit = (strap_protect[0] >> offset) & 0x1; 85069d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 85169d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 85269d5fd8fSJohnny Huang 85369d5fd8fSJohnny Huang } else { 85469d5fd8fSJohnny Huang offset = (i - 32); 85569d5fd8fSJohnny Huang bit = (buf[1] >> offset) & 0x1; 85669d5fd8fSJohnny Huang kbit = (strap_keep[1] >> offset) & 0x1; 85769d5fd8fSJohnny Huang pbit = (strap_protect[1] >> offset) & 0x1; 85869d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 85969d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 86069d5fd8fSJohnny Huang } 86169d5fd8fSJohnny Huang prog_bit = ~(0x1 << offset); 86269d5fd8fSJohnny Huang 86369d5fd8fSJohnny Huang if (kbit == 1) { 86469d5fd8fSJohnny Huang continue; 86569d5fd8fSJohnny Huang } 86669d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 86769d5fd8fSJohnny Huang continue; 86869d5fd8fSJohnny Huang } 86969d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 87069d5fd8fSJohnny Huang fail = 1; 87169d5fd8fSJohnny Huang continue; 87269d5fd8fSJohnny Huang } 87369d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 87469d5fd8fSJohnny Huang fail = 1; 87569d5fd8fSJohnny Huang continue; 87669d5fd8fSJohnny Huang } 87769d5fd8fSJohnny Huang pass = 0; 87869d5fd8fSJohnny Huang soak = 0; 8794b65a65dSJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 8804b65a65dSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 8814b65a65dSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 8824b65a65dSJohnny Huang writel(0x04190760, 0x1e602008); //normal program 88369d5fd8fSJohnny Huang for (j = 0; j < RETRY; j++) { 88469d5fd8fSJohnny Huang if (!soak) { 88569d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 886a6d0d645SJohnny Huang if (verify_bit(prog_address, offset, 1) == 0) { 88769d5fd8fSJohnny Huang pass = 1; 88869d5fd8fSJohnny Huang break; 88969d5fd8fSJohnny Huang } 89069d5fd8fSJohnny Huang soak = 1; 8914b65a65dSJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 8924b65a65dSJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 8934b65a65dSJohnny Huang otp_write(0x1000, 0x4820); // Write MR 89469d5fd8fSJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 8954b65a65dSJohnny Huang } 89669d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 897a6d0d645SJohnny Huang if (verify_bit(prog_address, offset, 1) == 0) { 89869d5fd8fSJohnny Huang pass = 1; 89969d5fd8fSJohnny Huang break; 90069d5fd8fSJohnny Huang } 90169d5fd8fSJohnny Huang } 90269d5fd8fSJohnny Huang if (!pass) 90369d5fd8fSJohnny Huang return -1; 90469d5fd8fSJohnny Huang 90569d5fd8fSJohnny Huang if (pbit == 0) 90669d5fd8fSJohnny Huang continue; 90769d5fd8fSJohnny Huang prog_address = 0x800; 90869d5fd8fSJohnny Huang if (i < 32) 90969d5fd8fSJohnny Huang prog_address |= 0x60c; 91069d5fd8fSJohnny Huang else 91169d5fd8fSJohnny Huang prog_address |= 0x60e; 91269d5fd8fSJohnny Huang 91369d5fd8fSJohnny Huang for (j = 0; j < RETRY; j++) { 91469d5fd8fSJohnny Huang if (!soak) { 91569d5fd8fSJohnny Huang writel(0x04190760, 0x1e602008); //normal program 91669d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 917a6d0d645SJohnny Huang if (verify_bit(prog_address, offset, 1) == 0) { 91869d5fd8fSJohnny Huang pass = 1; 91969d5fd8fSJohnny Huang break; 92069d5fd8fSJohnny Huang } 92169d5fd8fSJohnny Huang soak = 1; 92269d5fd8fSJohnny Huang } 92369d5fd8fSJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 92469d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 925a6d0d645SJohnny Huang if (verify_bit(prog_address, offset, 1) == 0) { 92669d5fd8fSJohnny Huang pass = 1; 92769d5fd8fSJohnny Huang break; 92869d5fd8fSJohnny Huang } 92969d5fd8fSJohnny Huang } 93069d5fd8fSJohnny Huang if (!pass) 93169d5fd8fSJohnny Huang return -1; 93269d5fd8fSJohnny Huang 93369d5fd8fSJohnny Huang } 93469d5fd8fSJohnny Huang if (fail == 1) 93569d5fd8fSJohnny Huang return -1; 93669d5fd8fSJohnny Huang else 93769d5fd8fSJohnny Huang return 0; 93869d5fd8fSJohnny Huang 93969d5fd8fSJohnny Huang } 94069d5fd8fSJohnny Huang 941cd1610b4SJohnny Huang static void otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset, int soak) 942cd1610b4SJohnny Huang { 943cd1610b4SJohnny Huang int prog_bit; 944cd1610b4SJohnny Huang 945cd1610b4SJohnny Huang if (soak) { 946cd1610b4SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 947cd1610b4SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 948cd1610b4SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 949cd1610b4SJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 950cd1610b4SJohnny Huang } else { 951cd1610b4SJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 952cd1610b4SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 953cd1610b4SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 954cd1610b4SJohnny Huang writel(0x04190760, 0x1e602008); //normal program 955cd1610b4SJohnny Huang } 956cd1610b4SJohnny Huang if (prog_address % 2 == 0) { 957cd1610b4SJohnny Huang if (value) 958cd1610b4SJohnny Huang prog_bit = ~(0x1 << bit_offset); 959cd1610b4SJohnny Huang else 960cd1610b4SJohnny Huang return; 961cd1610b4SJohnny Huang } else { 962cd1610b4SJohnny Huang prog_address |= 1 << 15; 963cd1610b4SJohnny Huang if (!value) 964cd1610b4SJohnny Huang prog_bit = 0x1 << bit_offset; 965cd1610b4SJohnny Huang else 966cd1610b4SJohnny Huang return; 967cd1610b4SJohnny Huang } 968cd1610b4SJohnny Huang otp_prog(prog_address, prog_bit); 969cd1610b4SJohnny Huang } 970cd1610b4SJohnny Huang 971*d90825e2SJohnny Huang static int otp_prog_data(uint32_t *buf) 9724c1c9b35SJohnny Huang { 9734c1c9b35SJohnny Huang int i, k; 9744c1c9b35SJohnny Huang int pass; 975*d90825e2SJohnny Huang int soak = 0; 9764c1c9b35SJohnny Huang uint32_t prog_address; 977*d90825e2SJohnny Huang uint32_t data[2048]; 9784c1c9b35SJohnny Huang uint32_t compare[2]; 979*d90825e2SJohnny Huang uint32_t *buf_keep = &buf[2048]; 9804c1c9b35SJohnny Huang 981*d90825e2SJohnny Huang uint32_t data0_masked; 982*d90825e2SJohnny Huang uint32_t data1_masked; 983*d90825e2SJohnny Huang uint32_t buf0_masked; 984*d90825e2SJohnny Huang uint32_t buf1_masked; 9854c1c9b35SJohnny Huang 9864c1c9b35SJohnny Huang printf("Read OTP Data:\n"); 9874c1c9b35SJohnny Huang 988*d90825e2SJohnny Huang printProgress(0, 2048, ""); 989*d90825e2SJohnny Huang for (i = 0; i < 2048 ; i += 2) { 990*d90825e2SJohnny Huang printProgress(i + 2, 2048, ""); 991*d90825e2SJohnny Huang otp_read_data(i, &data[i]); 9924c1c9b35SJohnny Huang } 993*d90825e2SJohnny Huang 9944c1c9b35SJohnny Huang 9954c1c9b35SJohnny Huang printf("Check writable...\n"); 996*d90825e2SJohnny Huang for (i = 0; i < 2048; i++) { 997*d90825e2SJohnny Huang data0_masked = data[i] & ~buf_keep[i]; 998*d90825e2SJohnny Huang buf0_masked = buf[i] & ~buf_keep[i]; 999*d90825e2SJohnny Huang if (data0_masked == buf0_masked) 10004c1c9b35SJohnny Huang continue; 1001*d90825e2SJohnny Huang if (i % 2 == 0) { 1002*d90825e2SJohnny Huang if ((data0_masked | buf0_masked) == buf0_masked) { 10034c1c9b35SJohnny Huang continue; 10044c1c9b35SJohnny Huang } else { 10054c1c9b35SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1006*d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 10074c1c9b35SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1008*d90825e2SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_keep[i]); 10094c1c9b35SJohnny Huang return -1; 101069d5fd8fSJohnny Huang } 1011*d90825e2SJohnny Huang } else { 1012*d90825e2SJohnny Huang if ((data0_masked & buf0_masked) == buf0_masked) { 1013*d90825e2SJohnny Huang continue; 1014*d90825e2SJohnny Huang } else { 1015*d90825e2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1016*d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1017*d90825e2SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1018*d90825e2SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_keep[i]); 1019*d90825e2SJohnny Huang return -1; 1020*d90825e2SJohnny Huang } 1021*d90825e2SJohnny Huang } 1022*d90825e2SJohnny Huang } 102369d5fd8fSJohnny Huang 1024*d90825e2SJohnny Huang printf("Start Programing...\n"); 1025*d90825e2SJohnny Huang printProgress(0, 2048, ""); 1026*d90825e2SJohnny Huang 1027*d90825e2SJohnny Huang for (i = 0; i < 2048; i += 2) { 1028*d90825e2SJohnny Huang prog_address = i; 1029*d90825e2SJohnny Huang data0_masked = data[i] & ~buf_keep[i]; 1030*d90825e2SJohnny Huang buf0_masked = buf[i] & ~buf_keep[i]; 1031*d90825e2SJohnny Huang data1_masked = data[i + 1] & ~buf_keep[i + 1]; 1032*d90825e2SJohnny Huang buf1_masked = buf[i + 1] & ~buf_keep[i + 1]; 1033*d90825e2SJohnny Huang if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked)) { 1034*d90825e2SJohnny Huang printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]); 1035*d90825e2SJohnny Huang continue; 1036*d90825e2SJohnny Huang } 1037*d90825e2SJohnny Huang if (soak) { 1038*d90825e2SJohnny Huang soak = 0; 1039*d90825e2SJohnny Huang otp_soak(0); 1040*d90825e2SJohnny Huang } 1041*d90825e2SJohnny Huang if (data1_masked == buf1_masked) { 1042*d90825e2SJohnny Huang printProgress(i + 2, 2048, "[%03X]=%08X ;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]); 1043*d90825e2SJohnny Huang otp_prog_dw(buf[i], buf_keep[i], prog_address); 1044*d90825e2SJohnny Huang } else if (data0_masked == buf0_masked) { 1045*d90825e2SJohnny Huang printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X ", prog_address, buf[i], prog_address + 1, buf[i + 1]); 1046*d90825e2SJohnny Huang otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1); 1047*d90825e2SJohnny Huang } else { 1048*d90825e2SJohnny Huang printProgress(i + 2, 2048, "[%03X]=%08X ;[%03X]=%08X ", prog_address, buf[i], prog_address + 1, buf[i + 1]); 1049*d90825e2SJohnny Huang otp_prog_dw(buf[i], buf_keep[i], prog_address); 1050*d90825e2SJohnny Huang otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1); 1051*d90825e2SJohnny Huang } 1052*d90825e2SJohnny Huang 1053*d90825e2SJohnny Huang pass = 0; 1054*d90825e2SJohnny Huang for (k = 0; k < RETRY; k++) { 1055*d90825e2SJohnny Huang if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 2) != 0) { 1056*d90825e2SJohnny Huang if (soak == 0) { 1057*d90825e2SJohnny Huang soak = 1; 1058*d90825e2SJohnny Huang otp_soak(1); 1059*d90825e2SJohnny Huang } 1060*d90825e2SJohnny Huang if (compare[0] != 0) { 1061*d90825e2SJohnny Huang otp_prog_dw(compare[0], buf_keep[i], prog_address); 1062*d90825e2SJohnny Huang } 1063*d90825e2SJohnny Huang if (compare[1] != ~0) { 1064*d90825e2SJohnny Huang otp_prog_dw(compare[1], buf_keep[i], prog_address + 1); 1065*d90825e2SJohnny Huang } 1066*d90825e2SJohnny Huang } else { 1067*d90825e2SJohnny Huang pass = 1; 1068*d90825e2SJohnny Huang break; 1069*d90825e2SJohnny Huang } 1070*d90825e2SJohnny Huang } 1071*d90825e2SJohnny Huang 1072*d90825e2SJohnny Huang if (!pass) 1073*d90825e2SJohnny Huang return -1; 1074*d90825e2SJohnny Huang } 1075*d90825e2SJohnny Huang return 0; 1076*d90825e2SJohnny Huang 1077*d90825e2SJohnny Huang } 1078*d90825e2SJohnny Huang 1079*d90825e2SJohnny Huang static int do_otp_prog(int addr, int byte_size, int nconfirm) 108069d5fd8fSJohnny Huang { 108169d5fd8fSJohnny Huang int ret; 1082*d90825e2SJohnny Huang int mode; 108369d5fd8fSJohnny Huang uint32_t *buf; 1084*d90825e2SJohnny Huang uint32_t *data_region = NULL; 1085*d90825e2SJohnny Huang uint32_t *conf_region = NULL; 1086*d90825e2SJohnny Huang uint32_t *strap_region = NULL; 108769d5fd8fSJohnny Huang 1088*d90825e2SJohnny Huang buf = map_physmem(addr, byte_size, MAP_WRBACK); 108969d5fd8fSJohnny Huang if (!buf) { 109069d5fd8fSJohnny Huang puts("Failed to map physical memory\n"); 109169d5fd8fSJohnny Huang return 1; 109269d5fd8fSJohnny Huang } 1093*d90825e2SJohnny Huang 1094*d90825e2SJohnny Huang if (((buf[0] >> 29) & 0x7) == 0x7) { 1095*d90825e2SJohnny Huang mode = OTP_REGION_ALL; 1096*d90825e2SJohnny Huang conf_region = &buf[1]; 1097*d90825e2SJohnny Huang strap_region = &buf[25]; 1098*d90825e2SJohnny Huang data_region = &buf[31]; 1099*d90825e2SJohnny Huang } else { 1100*d90825e2SJohnny Huang if (buf[0] & BIT(29)) { 1101*d90825e2SJohnny Huang mode = OTP_REGION_DATA; 1102*d90825e2SJohnny Huang data_region = &buf[31]; 1103*d90825e2SJohnny Huang } 1104*d90825e2SJohnny Huang if (buf[0] & BIT(30)) { 1105*d90825e2SJohnny Huang mode = OTP_REGION_CONF; 1106*d90825e2SJohnny Huang strap_region = &buf[25]; 1107*d90825e2SJohnny Huang } 1108*d90825e2SJohnny Huang if (buf[0] & BIT(31)) { 1109*d90825e2SJohnny Huang mode = OTP_REGION_STRAP; 1110*d90825e2SJohnny Huang conf_region = &buf[1]; 1111*d90825e2SJohnny Huang } 1112*d90825e2SJohnny Huang } 1113*d90825e2SJohnny Huang 111469d5fd8fSJohnny Huang if (!nconfirm) { 1115a6d0d645SJohnny Huang if (mode == OTP_REGION_CONF) { 1116*d90825e2SJohnny Huang if (otp_conf_parse(conf_region) < 0) { 111769d5fd8fSJohnny Huang printf("OTP config error, please check.\n"); 111869d5fd8fSJohnny Huang return -1; 111969d5fd8fSJohnny Huang } 1120a6d0d645SJohnny Huang } else if (mode == OTP_REGION_DATA) { 1121*d90825e2SJohnny Huang if (otp_data_parse(data_region) < 0) { 112269d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 112369d5fd8fSJohnny Huang return -1; 112469d5fd8fSJohnny Huang } 1125a6d0d645SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 1126*d90825e2SJohnny Huang if (otp_strap_parse(strap_region) < 0) { 112769d5fd8fSJohnny Huang printf("OTP strap error, please check.\n"); 112869d5fd8fSJohnny Huang return -1; 112969d5fd8fSJohnny Huang } 1130a6d0d645SJohnny Huang } else if (mode == OTP_REGION_ALL) { 1131*d90825e2SJohnny Huang if (otp_conf_parse(conf_region) < 0) { 113269d5fd8fSJohnny Huang printf("OTP config error, please check.\n"); 113369d5fd8fSJohnny Huang return -1; 113469d5fd8fSJohnny Huang } 1135*d90825e2SJohnny Huang if (otp_strap_parse(strap_region) < 0) { 113669d5fd8fSJohnny Huang printf("OTP strap error, please check.\n"); 113769d5fd8fSJohnny Huang return -1; 113869d5fd8fSJohnny Huang } 1139*d90825e2SJohnny Huang if (otp_data_parse(data_region) < 0) { 114069d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 114169d5fd8fSJohnny Huang return -1; 114269d5fd8fSJohnny Huang } 114369d5fd8fSJohnny Huang } 114469d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 114569d5fd8fSJohnny Huang if (!confirm_yesno()) { 114669d5fd8fSJohnny Huang printf(" Aborting\n"); 114769d5fd8fSJohnny Huang return 1; 114869d5fd8fSJohnny Huang } 114969d5fd8fSJohnny Huang } 1150a6d0d645SJohnny Huang if (mode == OTP_REGION_CONF) { 1151*d90825e2SJohnny Huang return otp_prog_conf(conf_region); 1152a6d0d645SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 1153*d90825e2SJohnny Huang return otp_prog_strap(strap_region); 1154a6d0d645SJohnny Huang } else if (mode == OTP_REGION_DATA) { 1155*d90825e2SJohnny Huang return otp_prog_data(data_region); 1156a6d0d645SJohnny Huang } else if (mode == OTP_REGION_ALL) { 115769d5fd8fSJohnny Huang printf("programing data region ... "); 1158*d90825e2SJohnny Huang ret = otp_prog_data(data_region); 115969d5fd8fSJohnny Huang if (ret < 0) { 116069d5fd8fSJohnny Huang printf("Error\n"); 116169d5fd8fSJohnny Huang return ret; 116269d5fd8fSJohnny Huang } else { 116369d5fd8fSJohnny Huang printf("Done\n"); 116469d5fd8fSJohnny Huang } 116569d5fd8fSJohnny Huang printf("programing strap region ... "); 1166*d90825e2SJohnny Huang ret = otp_prog_strap(strap_region); 116769d5fd8fSJohnny Huang if (ret < 0) { 116869d5fd8fSJohnny Huang printf("Error\n"); 116969d5fd8fSJohnny Huang return ret; 117069d5fd8fSJohnny Huang } else { 117169d5fd8fSJohnny Huang printf("Done\n"); 117269d5fd8fSJohnny Huang } 117369d5fd8fSJohnny Huang printf("programing configuration region ... "); 1174*d90825e2SJohnny Huang ret = otp_prog_conf(conf_region); 117569d5fd8fSJohnny Huang if (ret < 0) { 117669d5fd8fSJohnny Huang printf("Error\n"); 117769d5fd8fSJohnny Huang return ret; 117869d5fd8fSJohnny Huang } 117969d5fd8fSJohnny Huang printf("Done\n"); 118069d5fd8fSJohnny Huang return ret; 118169d5fd8fSJohnny Huang } 118269d5fd8fSJohnny Huang return 0; 118369d5fd8fSJohnny Huang } 1184cd1610b4SJohnny Huang 1185cd1610b4SJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int protect, int nconfirm) 1186cd1610b4SJohnny Huang { 1187cd1610b4SJohnny Huang uint32_t ret[2]; 1188cd1610b4SJohnny Huang uint32_t strap_buf[6]; 1189*d90825e2SJohnny Huang uint32_t prog_address = 0; 1190cd1610b4SJohnny Huang struct otpstrap otpstrap[64]; 1191cd1610b4SJohnny Huang int otp_bit; 1192cd1610b4SJohnny Huang int i; 1193cd1610b4SJohnny Huang int pass; 1194cd1610b4SJohnny Huang 1195cd1610b4SJohnny Huang switch (mode) { 1196a6d0d645SJohnny Huang case OTP_REGION_CONF: 1197cd1610b4SJohnny Huang otp_read_config(otp_dw_offset, ret); 1198cd1610b4SJohnny Huang prog_address = 0x800; 1199cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 1200cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 1201cd1610b4SJohnny Huang otp_bit = (ret[0] >> bit_offset) & 0x1; 1202cd1610b4SJohnny Huang if (otp_bit == value) { 1203cd1610b4SJohnny Huang printf("OTPCFG%X[%d] = %d\n", otp_dw_offset, bit_offset, value); 1204cd1610b4SJohnny Huang printf("No need to program\n"); 1205cd1610b4SJohnny Huang return 0; 1206cd1610b4SJohnny Huang } 1207cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1208cd1610b4SJohnny Huang printf("OTPCFG%X[%d] = 1\n", otp_dw_offset, bit_offset); 1209cd1610b4SJohnny Huang printf("OTP is programed, which can't be clean\n"); 1210cd1610b4SJohnny Huang return -1; 1211cd1610b4SJohnny Huang } 1212cd1610b4SJohnny Huang printf("Program OTPCFG%X[%d] to 1\n", otp_dw_offset, bit_offset); 1213cd1610b4SJohnny Huang break; 1214a6d0d645SJohnny Huang case OTP_REGION_DATA: 1215cd1610b4SJohnny Huang prog_address = otp_dw_offset; 1216cd1610b4SJohnny Huang 1217cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 1218cd1610b4SJohnny Huang otp_read_data(otp_dw_offset, ret); 1219cd1610b4SJohnny Huang otp_bit = (ret[0] >> bit_offset) & 0x1; 1220cd1610b4SJohnny Huang } else { 1221cd1610b4SJohnny Huang otp_read_data(otp_dw_offset - 1, ret); 1222cd1610b4SJohnny Huang otp_bit = (ret[1] >> bit_offset) & 0x1; 1223cd1610b4SJohnny Huang } 1224cd1610b4SJohnny Huang if (otp_bit == value) { 1225cd1610b4SJohnny Huang printf("OTPDATA%X[%d] = %d\n", otp_dw_offset, bit_offset, value); 1226cd1610b4SJohnny Huang printf("No need to program\n"); 1227cd1610b4SJohnny Huang return 0; 1228cd1610b4SJohnny Huang } 1229cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1230cd1610b4SJohnny Huang printf("OTPDATA%X[%d] = 1\n", otp_dw_offset, bit_offset); 1231cd1610b4SJohnny Huang printf("OTP is programed, which can't be clean\n"); 1232cd1610b4SJohnny Huang return -1; 1233cd1610b4SJohnny Huang } 1234cd1610b4SJohnny Huang printf("Program OTPDATA%X[%d] to 1\n", otp_dw_offset, bit_offset); 1235cd1610b4SJohnny Huang break; 1236a6d0d645SJohnny Huang case OTP_REGION_STRAP: 1237cd1610b4SJohnny Huang otp_strp_status(otpstrap); 1238cd1610b4SJohnny Huang otp_print_strap(bit_offset, 1); 1239cd1610b4SJohnny Huang if (bit_offset < 32) { 1240cd1610b4SJohnny Huang strap_buf[0] = value << bit_offset; 1241cd1610b4SJohnny Huang strap_buf[2] = ~BIT(bit_offset); 1242cd1610b4SJohnny Huang strap_buf[3] = ~0; 1243cd1610b4SJohnny Huang strap_buf[5] = 0; 1244cd1610b4SJohnny Huang if (protect) 1245cd1610b4SJohnny Huang strap_buf[4] = BIT(bit_offset); 1246cd1610b4SJohnny Huang else 1247cd1610b4SJohnny Huang strap_buf[4] = 0; 1248cd1610b4SJohnny Huang } else { 1249cd1610b4SJohnny Huang strap_buf[1] = value << (bit_offset - 32); 1250cd1610b4SJohnny Huang strap_buf[2] = ~0; 1251cd1610b4SJohnny Huang strap_buf[3] = ~BIT(bit_offset - 32); 1252cd1610b4SJohnny Huang strap_buf[4] = 0; 1253cd1610b4SJohnny Huang if (protect) 1254cd1610b4SJohnny Huang strap_buf[5] = BIT(bit_offset - 32); 1255cd1610b4SJohnny Huang else 1256cd1610b4SJohnny Huang strap_buf[5] = 0; 1257cd1610b4SJohnny Huang } 1258cd1610b4SJohnny Huang if (otp_strap_parse(strap_buf) < 0) 1259cd1610b4SJohnny Huang return -1; 1260cd1610b4SJohnny Huang break; 1261cd1610b4SJohnny Huang } 1262cd1610b4SJohnny Huang 1263cd1610b4SJohnny Huang if (!nconfirm) { 1264cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1265cd1610b4SJohnny Huang if (!confirm_yesno()) { 1266cd1610b4SJohnny Huang printf(" Aborting\n"); 1267cd1610b4SJohnny Huang return 1; 1268cd1610b4SJohnny Huang } 1269cd1610b4SJohnny Huang } 1270cd1610b4SJohnny Huang 1271cd1610b4SJohnny Huang switch (mode) { 1272a6d0d645SJohnny Huang case OTP_REGION_STRAP: 1273cd1610b4SJohnny Huang return otp_prog_strap(strap_buf); 1274a6d0d645SJohnny Huang case OTP_REGION_CONF: 1275a6d0d645SJohnny Huang case OTP_REGION_DATA: 1276cd1610b4SJohnny Huang otp_prog_bit(value, prog_address, bit_offset, 0); 1277cd1610b4SJohnny Huang pass = -1; 1278cd1610b4SJohnny Huang for (i = 0; i < RETRY; i++) { 1279a6d0d645SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 1280cd1610b4SJohnny Huang otp_prog_bit(value, prog_address, bit_offset, 1); 1281cd1610b4SJohnny Huang } else { 1282cd1610b4SJohnny Huang pass = 0; 1283cd1610b4SJohnny Huang break; 1284cd1610b4SJohnny Huang } 1285cd1610b4SJohnny Huang } 1286cd1610b4SJohnny Huang return pass; 1287cd1610b4SJohnny Huang } 1288cd1610b4SJohnny Huang 1289cd1610b4SJohnny Huang return -1; 1290cd1610b4SJohnny Huang } 1291cd1610b4SJohnny Huang 129269d5fd8fSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, 129369d5fd8fSJohnny Huang char *const argv[]) 129469d5fd8fSJohnny Huang { 129569d5fd8fSJohnny Huang char *cmd; 129669d5fd8fSJohnny Huang int mode = 0; 129769d5fd8fSJohnny Huang int nconfirm = 0; 1298cd1610b4SJohnny Huang uint32_t addr = 0; 1299cd1610b4SJohnny Huang uint32_t otp_addr = 0; 1300cd1610b4SJohnny Huang int dw_count = 0; 1301*d90825e2SJohnny Huang int byte_size = 0; 1302cd1610b4SJohnny Huang int bit_offset = 0; 1303cd1610b4SJohnny Huang int value = 0; 1304cd1610b4SJohnny Huang int protect = 0; 130569d5fd8fSJohnny Huang 130669d5fd8fSJohnny Huang 130769d5fd8fSJohnny Huang 130869d5fd8fSJohnny Huang if (argc < 2) { 130969d5fd8fSJohnny Huang usage: 131069d5fd8fSJohnny Huang return CMD_RET_USAGE; 131169d5fd8fSJohnny Huang } 131269d5fd8fSJohnny Huang 131369d5fd8fSJohnny Huang cmd = argv[1]; 131469d5fd8fSJohnny Huang if (!strcmp(cmd, "read")) { 131569d5fd8fSJohnny Huang if (!strcmp(argv[2], "conf")) 1316a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 131769d5fd8fSJohnny Huang else if (!strcmp(argv[2], "data")) 1318a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 131969d5fd8fSJohnny Huang else if (!strcmp(argv[2], "strap")) 1320a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 132169d5fd8fSJohnny Huang else 132269d5fd8fSJohnny Huang goto usage; 132369d5fd8fSJohnny Huang 132469d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 132569d5fd8fSJohnny Huang otp_addr = simple_strtoul(argv[3], NULL, 16); 132669d5fd8fSJohnny Huang dw_count = simple_strtoul(argv[4], NULL, 16); 1327a6d0d645SJohnny Huang if (mode == OTP_REGION_CONF) { 132869d5fd8fSJohnny Huang otp_print_config(otp_addr, dw_count); 1329a6d0d645SJohnny Huang } else if (mode == OTP_REGION_DATA) { 133069d5fd8fSJohnny Huang otp_print_data(otp_addr, dw_count); 1331a6d0d645SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 1332cd1610b4SJohnny Huang otp_print_strap(0, 64); 133369d5fd8fSJohnny Huang } 133469d5fd8fSJohnny Huang } else if (!strcmp(cmd, "prog")) { 1335*d90825e2SJohnny Huang // if (!strcmp(argv[2], "conf")) 1336*d90825e2SJohnny Huang // mode = OTP_REGION_CONF; 1337*d90825e2SJohnny Huang // else if (!strcmp(argv[2], "strap")) 1338*d90825e2SJohnny Huang // mode = OTP_REGION_STRAP; 1339*d90825e2SJohnny Huang // else if (!strcmp(argv[2], "data")) 1340*d90825e2SJohnny Huang // mode = OTP_REGION_DATA; 1341*d90825e2SJohnny Huang // else if (!strcmp(argv[2], "all")) 1342*d90825e2SJohnny Huang // mode = OTP_REGION_ALL; 1343*d90825e2SJohnny Huang // else 1344*d90825e2SJohnny Huang // goto usage; 134569d5fd8fSJohnny Huang 1346*d90825e2SJohnny Huang if (!strcmp(argv[2], "f")) 134769d5fd8fSJohnny Huang nconfirm = 1; 134869d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 1349*d90825e2SJohnny Huang addr = simple_strtoul(argv[2 + nconfirm], NULL, 16); 1350*d90825e2SJohnny Huang byte_size = simple_strtoul(argv[3 + nconfirm], NULL, 16); 1351*d90825e2SJohnny Huang return do_otp_prog(addr, byte_size, nconfirm); 1352cd1610b4SJohnny Huang } else if (!strcmp(cmd, "pb")) { 1353cd1610b4SJohnny Huang if (!strcmp(argv[2], "conf")) 1354a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 1355cd1610b4SJohnny Huang else if (!strcmp(argv[2], "strap")) 1356a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 1357cd1610b4SJohnny Huang else if (!strcmp(argv[2], "data")) 1358a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 1359cd1610b4SJohnny Huang else 1360cd1610b4SJohnny Huang goto usage; 1361cd1610b4SJohnny Huang if (!strcmp(argv[3], "f")) 1362cd1610b4SJohnny Huang nconfirm = 1; 1363cd1610b4SJohnny Huang 1364a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 1365cd1610b4SJohnny Huang bit_offset = simple_strtoul(argv[3 + nconfirm], NULL, 16); 1366cd1610b4SJohnny Huang value = simple_strtoul(argv[4 + nconfirm], NULL, 16); 1367cd1610b4SJohnny Huang protect = simple_strtoul(argv[5 + nconfirm], NULL, 16); 1368cd1610b4SJohnny Huang if (bit_offset >= 64) 1369cd1610b4SJohnny Huang return -1; 1370cd1610b4SJohnny Huang } else { 1371cd1610b4SJohnny Huang otp_addr = simple_strtoul(argv[3 + nconfirm], NULL, 16); 1372cd1610b4SJohnny Huang bit_offset = simple_strtoul(argv[4 + nconfirm], NULL, 16); 1373cd1610b4SJohnny Huang value = simple_strtoul(argv[5 + nconfirm], NULL, 16); 1374cd1610b4SJohnny Huang if (bit_offset >= 32) 1375cd1610b4SJohnny Huang return -1; 1376cd1610b4SJohnny Huang } 1377cd1610b4SJohnny Huang if (value != 0 && value != 1) 1378cd1610b4SJohnny Huang return -1; 1379cd1610b4SJohnny Huang 1380cd1610b4SJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 1381cd1610b4SJohnny Huang return do_otp_prog_bit(mode, otp_addr, bit_offset, value, protect, nconfirm); 138269d5fd8fSJohnny Huang } else if (!strcmp(cmd, "comp")) { 138369d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 138469d5fd8fSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 138569d5fd8fSJohnny Huang otp_addr = simple_strtoul(argv[3], NULL, 16); 138669d5fd8fSJohnny Huang if (otp_compare(otp_addr, addr) >= 0) { 138769d5fd8fSJohnny Huang printf("Compare pass\n"); 138869d5fd8fSJohnny Huang } else { 138969d5fd8fSJohnny Huang printf("Compare fail\n"); 139069d5fd8fSJohnny Huang } 139169d5fd8fSJohnny Huang } else { 139269d5fd8fSJohnny Huang goto usage; 139369d5fd8fSJohnny Huang } 139469d5fd8fSJohnny Huang 139569d5fd8fSJohnny Huang 139669d5fd8fSJohnny Huang return 0; 139769d5fd8fSJohnny Huang } 139869d5fd8fSJohnny Huang 139969d5fd8fSJohnny Huang 140069d5fd8fSJohnny Huang U_BOOT_CMD( 140169d5fd8fSJohnny Huang otp, 7, 0, do_ast_otp, 140269d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 1403cd1610b4SJohnny Huang "read conf|strap|data <otp_dw_offset> <dw_count>\n" 1404*d90825e2SJohnny Huang "otp prog [f] <addr> <byte_size>\n" 1405cd1610b4SJohnny Huang "otp pb conf|data [f] <otp_dw_offset> <bit_offset> <value>\n" 1406cd1610b4SJohnny Huang "otp pb strap [f] <bit_offset> <value> <protect>\n" 1407cd1610b4SJohnny Huang "otp comp <addr> <otp_dw_offset>\n" 140869d5fd8fSJohnny Huang ); 1409