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 33*2a856b9aSJohnny Huang #define OTP_USAGE -1 34*2a856b9aSJohnny Huang #define OTP_FAILURE -2 35*2a856b9aSJohnny Huang #define OTP_SUCCESS 0 36*2a856b9aSJohnny Huang 37e1f9e54eSJohnny Huang #define DISABLE_SECREG_PROG BIT(0) 38e1f9e54eSJohnny Huang #define ENABLE_SEC_BOOT BIT(1) 39e1f9e54eSJohnny Huang #define INIT_PROG_DONE BIT(2) 40e1f9e54eSJohnny Huang #define ENABLE_USERREG_ECC BIT(3) 41e1f9e54eSJohnny Huang #define ENABLE_SECREG_ECC BIT(4) 42e1f9e54eSJohnny Huang #define DISABLE_LOW_SEC_KEY BIT(5) 43e1f9e54eSJohnny Huang #define IGNORE_SEC_BOOT_HWSTRAP BIT(6) 44e1f9e54eSJohnny Huang #define SEC_BOOT_MDOES(x) (x >> 7) 45e1f9e54eSJohnny Huang #define SEC_MODE1 0x0 46e1f9e54eSJohnny Huang #define SEC_MODE2 0x1 47e1f9e54eSJohnny Huang #define OTP_BIT_CELL_MODES(x) ((x >> 8) & 0x3) 48e1f9e54eSJohnny Huang #define SINGLE_CELL_MODE 0x0 49e1f9e54eSJohnny Huang #define DIFFERENTIAL_MODE 0x1 50e1f9e54eSJohnny Huang #define DIFFERENTIAL_REDUDANT_MODE 0x2 51e1f9e54eSJohnny Huang #define CRYPTO_MODES(x) ((x >> 10) & 0x3) 52e1f9e54eSJohnny Huang #define CRYPTO_RSA1024 0x0 53e1f9e54eSJohnny Huang #define CRYPTO_RSA2048 0x1 54e1f9e54eSJohnny Huang #define CRYPTO_RSA3072 0x2 55e1f9e54eSJohnny Huang #define CRYPTO_RSA4096 0x3 56e1f9e54eSJohnny Huang #define HASH_MODES(x) ((x >> 12) & 0x3) 57e1f9e54eSJohnny Huang #define HASH_SAH224 0x0 58e1f9e54eSJohnny Huang #define HASH_SAH256 0x1 59e1f9e54eSJohnny Huang #define HASH_SAH384 0x2 60e1f9e54eSJohnny Huang #define HASH_SAH512 0x3 61e1f9e54eSJohnny Huang #define SECREG_SIZE(x) ((x >> 16) & 0x3f) 62e1f9e54eSJohnny Huang #define WRITE_PROTECT_SECREG BIT(22) 63e1f9e54eSJohnny Huang #define WRITE_PROTECT_USERREG BIT(23) 64e1f9e54eSJohnny Huang #define WRITE_PROTECT_CONFREG BIT(24) 65e1f9e54eSJohnny Huang #define WRITE_PROTECT_STRAPREG BIT(25) 66e1f9e54eSJohnny Huang #define ENABLE_COPY_TO_SRAM BIT(26) 67e1f9e54eSJohnny Huang #define ENABLE_IMAGE_ENC BIT(27) 68e1f9e54eSJohnny Huang #define WRITE_PROTECT_KEY_RETIRE BIT(29) 69e1f9e54eSJohnny Huang #define ENABLE_SIPROM_RED BIT(30) 70e1f9e54eSJohnny Huang #define ENABLE_SIPROM_MLOCK BIT(31) 71e1f9e54eSJohnny Huang 72e1f9e54eSJohnny Huang #define VENDER_ID(x) (x & 0xFFFF) 73e1f9e54eSJohnny Huang #define KEY_REVISION(x) ((x >> 16) & 0xFFFF) 74e1f9e54eSJohnny Huang 75e1f9e54eSJohnny Huang #define SEC_BOOT_HEADER_OFFSET(x) (x & 0xFFFF) 76e1f9e54eSJohnny Huang 77e1f9e54eSJohnny Huang #define KEYS_VALID_BITS(x) (x & 0xff) 78e1f9e54eSJohnny Huang #define KEYS_RETIRE_BITS(x) ((x >> 16) & 0xff) 794c1c9b35SJohnny Huang 804c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" 814c1c9b35SJohnny Huang #define PBWIDTH 60 824c1c9b35SJohnny Huang 834c1c9b35SJohnny Huang void printProgress(int numerator, int denominator, char *format, ...) 844c1c9b35SJohnny Huang { 854c1c9b35SJohnny Huang int val = numerator * 100 / denominator; 864c1c9b35SJohnny Huang int lpad = numerator * PBWIDTH / denominator; 874c1c9b35SJohnny Huang int rpad = PBWIDTH - lpad; 884c1c9b35SJohnny Huang char buffer[256]; 894c1c9b35SJohnny Huang va_list aptr; 904c1c9b35SJohnny Huang 914c1c9b35SJohnny Huang va_start(aptr, format); 924c1c9b35SJohnny Huang vsprintf(buffer, format, aptr); 934c1c9b35SJohnny Huang va_end(aptr); 944c1c9b35SJohnny Huang 954c1c9b35SJohnny Huang printf("\r%3d%% [%.*s%*s] %s", val, lpad, PBSTR, rpad, "", buffer); 964c1c9b35SJohnny Huang if (numerator == denominator) 974c1c9b35SJohnny Huang printf("\n"); 984c1c9b35SJohnny Huang } 994c1c9b35SJohnny Huang 10069d5fd8fSJohnny Huang struct otpstrap { 10169d5fd8fSJohnny Huang int value; 10269d5fd8fSJohnny Huang int option_array[7]; 10369d5fd8fSJohnny Huang int remain_times; 10469d5fd8fSJohnny Huang int writeable_option; 10569d5fd8fSJohnny Huang int protected; 10669d5fd8fSJohnny Huang }; 10769d5fd8fSJohnny Huang 108*2a856b9aSJohnny Huang static void otp_read_data(uint32_t offset, uint32_t *data) 10969d5fd8fSJohnny Huang { 11069d5fd8fSJohnny Huang writel(offset, 0x1e6f2010); //Read address 11169d5fd8fSJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 11269d5fd8fSJohnny Huang udelay(2); 11369d5fd8fSJohnny Huang data[0] = readl(0x1e6f2020); 11469d5fd8fSJohnny Huang data[1] = readl(0x1e6f2024); 11569d5fd8fSJohnny Huang } 11669d5fd8fSJohnny Huang 117*2a856b9aSJohnny Huang static void otp_read_config(uint32_t offset, uint32_t *data) 11869d5fd8fSJohnny Huang { 11969d5fd8fSJohnny Huang int config_offset; 12069d5fd8fSJohnny Huang 12169d5fd8fSJohnny Huang config_offset = 0x800; 12269d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 12369d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 12469d5fd8fSJohnny Huang 12569d5fd8fSJohnny Huang writel(config_offset, 0x1e6f2010); //Read address 12669d5fd8fSJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 12769d5fd8fSJohnny Huang udelay(2); 12869d5fd8fSJohnny Huang data[0] = readl(0x1e6f2020); 12969d5fd8fSJohnny Huang } 13069d5fd8fSJohnny Huang 13169d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count) 13269d5fd8fSJohnny Huang { 13369d5fd8fSJohnny Huang int i; 13469d5fd8fSJohnny Huang uint32_t ret[1]; 13569d5fd8fSJohnny Huang 13669d5fd8fSJohnny Huang if (offset + dw_count > 32) 137*2a856b9aSJohnny Huang return OTP_USAGE; 13869d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i ++) { 13969d5fd8fSJohnny Huang otp_read_config(i, ret); 14069d5fd8fSJohnny Huang printf("OTPCFG%d: %08X\n", i, ret[0]); 14169d5fd8fSJohnny Huang } 14269d5fd8fSJohnny Huang printf("\n"); 143*2a856b9aSJohnny Huang return OTP_SUCCESS; 14469d5fd8fSJohnny Huang } 14569d5fd8fSJohnny Huang 14669d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count) 14769d5fd8fSJohnny Huang { 14869d5fd8fSJohnny Huang int i; 14969d5fd8fSJohnny Huang uint32_t ret[2]; 15069d5fd8fSJohnny Huang 15169d5fd8fSJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 152*2a856b9aSJohnny Huang return OTP_USAGE; 15369d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 15469d5fd8fSJohnny Huang otp_read_data(i, ret); 15569d5fd8fSJohnny Huang if (i % 4 == 0) 15669d5fd8fSJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 15769d5fd8fSJohnny Huang else 15869d5fd8fSJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 15969d5fd8fSJohnny Huang 16069d5fd8fSJohnny Huang } 16169d5fd8fSJohnny Huang printf("\n"); 162*2a856b9aSJohnny Huang return OTP_SUCCESS; 16369d5fd8fSJohnny Huang } 16469d5fd8fSJohnny Huang 16569d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr) 16669d5fd8fSJohnny Huang { 16769d5fd8fSJohnny Huang uint32_t ret; 16869d5fd8fSJohnny Huang uint32_t *buf; 16969d5fd8fSJohnny Huang 17069d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 17169d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 17269d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 17369d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 17469d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 17569d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //Compare address 17669d5fd8fSJohnny Huang writel(buf[0], 0x1e6f2020); //Compare data 1 17769d5fd8fSJohnny Huang writel(buf[1], 0x1e6f2024); //Compare data 2 17869d5fd8fSJohnny Huang writel(buf[2], 0x1e6f2028); //Compare data 3 17969d5fd8fSJohnny Huang writel(buf[3], 0x1e6f202c); //Compare data 4 18069d5fd8fSJohnny Huang writel(0x23b1e363, 0x1e6f2004); //Compare command 18169d5fd8fSJohnny Huang udelay(10); 18269d5fd8fSJohnny Huang ret = readl(0x1e6f2014); //Compare command 18369d5fd8fSJohnny Huang if (ret & 0x1) 18469d5fd8fSJohnny Huang return 0; 18569d5fd8fSJohnny Huang else 18669d5fd8fSJohnny Huang return -1; 18769d5fd8fSJohnny Huang } 18869d5fd8fSJohnny Huang 18969d5fd8fSJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data) 19069d5fd8fSJohnny Huang { 19169d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //write address 19269d5fd8fSJohnny Huang writel(data, 0x1e6f2020); //write data 19369d5fd8fSJohnny Huang writel(0x23b1e362, 0x1e6f2004); //write command 19469d5fd8fSJohnny Huang udelay(100); 19569d5fd8fSJohnny Huang } 19669d5fd8fSJohnny Huang 19769d5fd8fSJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit) 19869d5fd8fSJohnny Huang { 19969d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //write address 20069d5fd8fSJohnny Huang writel(prog_bit, 0x1e6f2020); //write data 20169d5fd8fSJohnny Huang writel(0x23b1e364, 0x1e6f2004); //write command 20269d5fd8fSJohnny Huang udelay(85); 20369d5fd8fSJohnny Huang } 20469d5fd8fSJohnny Huang 205a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value) 20669d5fd8fSJohnny Huang { 20769d5fd8fSJohnny Huang int ret; 20869d5fd8fSJohnny Huang 20969d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //Read address 21069d5fd8fSJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 21169d5fd8fSJohnny Huang udelay(2); 21269d5fd8fSJohnny Huang ret = readl(0x1e6f2020); 213a6d0d645SJohnny Huang // printf("verify_bit = %x\n", ret); 21469d5fd8fSJohnny Huang if (((ret >> bit_offset) & 1) == value) 21569d5fd8fSJohnny Huang return 0; 21669d5fd8fSJohnny Huang else 21769d5fd8fSJohnny Huang return -1; 21869d5fd8fSJohnny Huang } 21969d5fd8fSJohnny Huang 220d90825e2SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *keep, uint32_t *compare, int size) 2214c1c9b35SJohnny Huang { 2224c1c9b35SJohnny Huang uint32_t ret[2]; 2234c1c9b35SJohnny Huang 2244c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 2254c1c9b35SJohnny Huang 2264c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 2274c1c9b35SJohnny Huang writel(otp_addr, 0x1e6f2010); //Read address 2284c1c9b35SJohnny Huang else 2294c1c9b35SJohnny Huang writel(otp_addr - 1, 0x1e6f2010); //Read address 2304c1c9b35SJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 2314c1c9b35SJohnny Huang udelay(2); 2324c1c9b35SJohnny Huang ret[0] = readl(0x1e6f2020); 2334c1c9b35SJohnny Huang ret[1] = readl(0x1e6f2024); 2344c1c9b35SJohnny Huang if (size == 1) { 2354c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 2364c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 237d90825e2SJohnny Huang if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0])) { 2384c1c9b35SJohnny Huang compare[0] = 0; 2394c1c9b35SJohnny Huang return 0; 2404c1c9b35SJohnny Huang } else { 2414c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 2424c1c9b35SJohnny Huang return -1; 2434c1c9b35SJohnny Huang } 2444c1c9b35SJohnny Huang 2454c1c9b35SJohnny Huang } else { 2464c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 247d90825e2SJohnny Huang if ((value[0] & ~keep[0]) == (ret[1] & ~keep[0])) { 2484c1c9b35SJohnny Huang compare[0] = ~0; 2494c1c9b35SJohnny Huang return 0; 2504c1c9b35SJohnny Huang } else { 251d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 2524c1c9b35SJohnny Huang return -1; 2534c1c9b35SJohnny Huang } 2544c1c9b35SJohnny Huang } 2554c1c9b35SJohnny Huang } else if (size == 2) { 2564c1c9b35SJohnny Huang // otp_addr should be even 257d90825e2SJohnny Huang if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0]) && (value[1] & ~keep[1]) == (ret[1] & ~keep[1])) { 2584c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 2594c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 2604c1c9b35SJohnny Huang compare[0] = 0; 2614c1c9b35SJohnny Huang compare[1] = ~0; 2624c1c9b35SJohnny Huang return 0; 2634c1c9b35SJohnny Huang } else { 2644c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 2654c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 2664c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 2674c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 2684c1c9b35SJohnny Huang return -1; 2694c1c9b35SJohnny Huang } 2704c1c9b35SJohnny Huang } else { 2714c1c9b35SJohnny Huang return -1; 2724c1c9b35SJohnny Huang } 2734c1c9b35SJohnny Huang } 2744c1c9b35SJohnny Huang 275d90825e2SJohnny Huang void otp_soak(int soak) 276d90825e2SJohnny Huang { 277d90825e2SJohnny Huang if (soak) { 278d90825e2SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 279d90825e2SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 280d90825e2SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 281d90825e2SJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 282d90825e2SJohnny Huang } else { 283d90825e2SJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 284d90825e2SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 285d90825e2SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 286d90825e2SJohnny Huang writel(0x04190760, 0x1e602008); //normal program 287d90825e2SJohnny Huang } 288d90825e2SJohnny Huang } 289d90825e2SJohnny Huang 290d90825e2SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t keep, uint32_t prog_address) 291d90825e2SJohnny Huang { 292d90825e2SJohnny Huang int j, bit_value, prog_bit; 293d90825e2SJohnny Huang 294d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 295d90825e2SJohnny Huang if ((keep >> j) & 0x1) 296d90825e2SJohnny Huang continue; 297d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 298d90825e2SJohnny Huang if (prog_address % 2 == 0) { 299d90825e2SJohnny Huang if (bit_value) 300d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 301d90825e2SJohnny Huang else 302d90825e2SJohnny Huang continue; 303d90825e2SJohnny Huang } else { 304d90825e2SJohnny Huang prog_address |= 1 << 15; 305d90825e2SJohnny Huang if (bit_value) 306d90825e2SJohnny Huang continue; 307d90825e2SJohnny Huang else 308d90825e2SJohnny Huang prog_bit = 0x1 << j; 309d90825e2SJohnny Huang } 310d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 311d90825e2SJohnny Huang } 312d90825e2SJohnny Huang } 313d90825e2SJohnny Huang 31469d5fd8fSJohnny Huang static int otp_conf_parse(uint32_t *OTPCFG) 31569d5fd8fSJohnny Huang { 3164c1c9b35SJohnny Huang int tmp, i; 3174c1c9b35SJohnny Huang int pass = 0; 318442839bbSJohnny Huang uint32_t *OTPCFG_KEEP = &OTPCFG[12]; 31969d5fd8fSJohnny Huang 320442839bbSJohnny Huang if (OTPCFG_KEEP[0] & DISABLE_SECREG_PROG) { 321442839bbSJohnny Huang printf("OTPCFG0-D[0]\n"); 322442839bbSJohnny Huang printf(" Skip\n"); 323442839bbSJohnny Huang } else { 32469d5fd8fSJohnny Huang printf("OTPCFG0-D[0]\n"); 325e1f9e54eSJohnny Huang if (OTPCFG[0] & DISABLE_SECREG_PROG) 32669d5fd8fSJohnny Huang printf(" Disable Secure Region programming\n"); 32769d5fd8fSJohnny Huang else 32869d5fd8fSJohnny Huang printf(" Enable Secure Region programming\n"); 329442839bbSJohnny Huang } 330442839bbSJohnny Huang 331442839bbSJohnny Huang if (OTPCFG_KEEP[0] & ENABLE_SEC_BOOT) { 332442839bbSJohnny Huang printf("OTPCFG0-D[1]\n"); 333442839bbSJohnny Huang printf(" Skip\n"); 334442839bbSJohnny Huang } else { 335442839bbSJohnny Huang 33669d5fd8fSJohnny Huang printf("OTPCFG0-D[1]\n"); 337e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SEC_BOOT) 33869d5fd8fSJohnny Huang printf(" Enable Secure Boot\n"); 33969d5fd8fSJohnny Huang else 34069d5fd8fSJohnny Huang printf(" Disable Secure Boot\n"); 341442839bbSJohnny Huang } 342442839bbSJohnny Huang 343442839bbSJohnny Huang if (OTPCFG_KEEP[0] & ENABLE_USERREG_ECC) { 344442839bbSJohnny Huang printf("OTPCFG0-D[3]\n"); 345442839bbSJohnny Huang printf(" Skip\n"); 346442839bbSJohnny Huang } else { 34769d5fd8fSJohnny Huang printf("OTPCFG0-D[3]\n"); 348e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_USERREG_ECC) 34969d5fd8fSJohnny Huang printf(" User region ECC enable\n"); 35069d5fd8fSJohnny Huang else 35169d5fd8fSJohnny Huang printf(" User region ECC disable\n"); 352442839bbSJohnny Huang } 353442839bbSJohnny Huang 354442839bbSJohnny Huang if (OTPCFG_KEEP[0] & ENABLE_SECREG_ECC) { 355442839bbSJohnny Huang printf("OTPCFG0-D[4]\n"); 356442839bbSJohnny Huang printf(" Skip\n"); 357442839bbSJohnny Huang } else { 35869d5fd8fSJohnny Huang printf("OTPCFG0-D[4]\n"); 359e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SECREG_ECC) 36069d5fd8fSJohnny Huang printf(" Secure Region ECC enable\n"); 36169d5fd8fSJohnny Huang else 36269d5fd8fSJohnny Huang printf(" Secure Region ECC disable\n"); 363442839bbSJohnny Huang } 364442839bbSJohnny Huang 365442839bbSJohnny Huang if (OTPCFG_KEEP[0] & DISABLE_LOW_SEC_KEY) { 366442839bbSJohnny Huang printf("OTPCFG0-D[5]\n"); 367442839bbSJohnny Huang printf(" Skip\n"); 368442839bbSJohnny Huang } else { 36969d5fd8fSJohnny Huang printf("OTPCFG0-D[5]\n"); 370e1f9e54eSJohnny Huang if (OTPCFG[0] & DISABLE_LOW_SEC_KEY) 37169d5fd8fSJohnny Huang printf(" Disable low security key\n"); 37269d5fd8fSJohnny Huang else 37369d5fd8fSJohnny Huang printf(" Enable low security key\n"); 374442839bbSJohnny Huang } 375442839bbSJohnny Huang 376442839bbSJohnny Huang if (OTPCFG_KEEP[0] & IGNORE_SEC_BOOT_HWSTRAP) { 377442839bbSJohnny Huang printf("OTPCFG0-D[6]\n"); 378442839bbSJohnny Huang printf(" Skip\n"); 379442839bbSJohnny Huang } else { 38069d5fd8fSJohnny Huang printf("OTPCFG0-D[6]\n"); 381e1f9e54eSJohnny Huang if (OTPCFG[0] & IGNORE_SEC_BOOT_HWSTRAP) 38269d5fd8fSJohnny Huang printf(" Ignore Secure Boot hardware strap\n"); 38369d5fd8fSJohnny Huang else 38469d5fd8fSJohnny Huang printf(" Do not ignore Secure Boot hardware strap\n"); 385442839bbSJohnny Huang } 386442839bbSJohnny Huang 387442839bbSJohnny Huang if (SEC_BOOT_MDOES(OTPCFG_KEEP[0]) == 0x1) { 388442839bbSJohnny Huang printf("OTPCFG0-D[7]\n"); 389442839bbSJohnny Huang printf(" Skip\n"); 390442839bbSJohnny Huang } else { 39169d5fd8fSJohnny Huang printf("OTPCFG0-D[7]\n"); 392e1f9e54eSJohnny Huang if (SEC_BOOT_MDOES(OTPCFG[0]) == SEC_MODE1) 393e1f9e54eSJohnny Huang printf(" Secure Boot Mode: 1\n"); 394e1f9e54eSJohnny Huang else 395e1f9e54eSJohnny Huang printf(" Secure Boot Mode: 2\n"); 396442839bbSJohnny Huang } 397442839bbSJohnny Huang 398442839bbSJohnny Huang if (OTP_BIT_CELL_MODES(OTPCFG_KEEP[0]) == 0x3) { 399442839bbSJohnny Huang printf("OTPCFG0-D[9:8]\n"); 400442839bbSJohnny Huang printf(" Skip\n"); 401442839bbSJohnny Huang } else { 40269d5fd8fSJohnny Huang printf("OTPCFG0-D[9:8]\n"); 40369d5fd8fSJohnny Huang printf(" OTP bit cell mode : "); 404e1f9e54eSJohnny Huang tmp = OTP_BIT_CELL_MODES(OTPCFG[0]); 405e1f9e54eSJohnny Huang if (tmp == SINGLE_CELL_MODE) { 40669d5fd8fSJohnny Huang printf("Single cell mode (recommended)\n"); 407e1f9e54eSJohnny Huang } else if (tmp == DIFFERENTIAL_MODE) { 40869d5fd8fSJohnny Huang printf("Differnetial mode\n"); 409e1f9e54eSJohnny Huang } else if (tmp == DIFFERENTIAL_REDUDANT_MODE) { 41069d5fd8fSJohnny Huang printf("Differential-redundant mode\n"); 41169d5fd8fSJohnny Huang } else { 41269d5fd8fSJohnny Huang printf("Value error\n"); 41369d5fd8fSJohnny Huang return -1; 41469d5fd8fSJohnny Huang } 415442839bbSJohnny Huang } 416442839bbSJohnny Huang if (CRYPTO_MODES(OTPCFG_KEEP[0]) == 0x3) { 417442839bbSJohnny Huang printf("OTPCFG0-D[11:10]\n"); 418442839bbSJohnny Huang printf(" Skip\n"); 419442839bbSJohnny Huang } else { 42069d5fd8fSJohnny Huang printf("OTPCFG0-D[11:10]\n"); 42169d5fd8fSJohnny Huang printf(" RSA mode : "); 422e1f9e54eSJohnny Huang tmp = CRYPTO_MODES(OTPCFG[0]); 423e1f9e54eSJohnny Huang if (tmp == CRYPTO_RSA1024) { 42469d5fd8fSJohnny Huang printf("RSA1024\n"); 425e1f9e54eSJohnny Huang } else if (tmp == CRYPTO_RSA2048) { 42669d5fd8fSJohnny Huang printf("RSA2048\n"); 427e1f9e54eSJohnny Huang } else if (tmp == CRYPTO_RSA3072) { 42869d5fd8fSJohnny Huang printf("RSA3072\n"); 42969d5fd8fSJohnny Huang } else { 43069d5fd8fSJohnny Huang printf("RSA4096\n"); 43169d5fd8fSJohnny Huang } 432442839bbSJohnny Huang } 433442839bbSJohnny Huang if (HASH_MODES(OTPCFG_KEEP[0]) == 0x3) { 434442839bbSJohnny Huang printf("OTPCFG0-D[13:12]\n"); 435442839bbSJohnny Huang printf(" Skip\n"); 436442839bbSJohnny Huang } else { 43769d5fd8fSJohnny Huang printf("OTPCFG0-D[13:12]\n"); 43869d5fd8fSJohnny Huang printf(" SHA mode : "); 439e1f9e54eSJohnny Huang tmp = HASH_MODES(OTPCFG[0]); 440e1f9e54eSJohnny Huang if (tmp == HASH_SAH224) { 44169d5fd8fSJohnny Huang printf("SHA224\n"); 442e1f9e54eSJohnny Huang } else if (tmp == HASH_SAH256) { 44369d5fd8fSJohnny Huang printf("SHA256\n"); 444e1f9e54eSJohnny Huang } else if (tmp == HASH_SAH384) { 44569d5fd8fSJohnny Huang printf("SHA384\n"); 44669d5fd8fSJohnny Huang } else { 44769d5fd8fSJohnny Huang printf("SHA512\n"); 44869d5fd8fSJohnny Huang } 449442839bbSJohnny Huang } 45069d5fd8fSJohnny Huang 451442839bbSJohnny Huang if (SECREG_SIZE(OTPCFG_KEEP[0]) == 0x3f) { 452442839bbSJohnny Huang printf("OTPCFG0-D[21:16]\n"); 453442839bbSJohnny Huang printf(" Skip\n"); 454442839bbSJohnny Huang } else { 45569d5fd8fSJohnny Huang printf("OTPCFG0-D[21:16]\n"); 456e1f9e54eSJohnny Huang printf(" Secure Region size (DW): %x\n", SECREG_SIZE(OTPCFG[0])); 457442839bbSJohnny Huang } 45869d5fd8fSJohnny Huang 459442839bbSJohnny Huang if (OTPCFG_KEEP[0] & WRITE_PROTECT_SECREG) { 460442839bbSJohnny Huang printf("OTPCFG0-D[22]\n"); 461442839bbSJohnny Huang printf(" Skip\n"); 462442839bbSJohnny Huang } else { 46369d5fd8fSJohnny Huang printf("OTPCFG0-D[22]\n"); 464e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_SECREG) 46569d5fd8fSJohnny Huang printf(" Secure Region : Write Protect\n"); 46669d5fd8fSJohnny Huang else 46769d5fd8fSJohnny Huang printf(" Secure Region : Writable\n"); 468442839bbSJohnny Huang } 469442839bbSJohnny Huang 470442839bbSJohnny Huang if (OTPCFG_KEEP[0] & WRITE_PROTECT_USERREG) { 471442839bbSJohnny Huang printf("OTPCFG0-D[23]\n"); 472442839bbSJohnny Huang printf(" Skip\n"); 473442839bbSJohnny Huang } else { 47469d5fd8fSJohnny Huang printf("OTPCFG0-D[23]\n"); 475e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_USERREG) 47669d5fd8fSJohnny Huang printf(" User Region : Write Protect\n"); 47769d5fd8fSJohnny Huang else 47869d5fd8fSJohnny Huang printf(" User Region : Writable\n"); 479442839bbSJohnny Huang } 480442839bbSJohnny Huang 481442839bbSJohnny Huang if (OTPCFG_KEEP[0] & WRITE_PROTECT_CONFREG) { 482442839bbSJohnny Huang printf("OTPCFG0-D[24]\n"); 483442839bbSJohnny Huang printf(" Skip\n"); 484442839bbSJohnny Huang } else { 48569d5fd8fSJohnny Huang printf("OTPCFG0-D[24]\n"); 486e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_CONFREG) 48769d5fd8fSJohnny Huang printf(" Configure Region : Write Protect\n"); 48869d5fd8fSJohnny Huang else 48969d5fd8fSJohnny Huang printf(" Configure Region : Writable\n"); 490442839bbSJohnny Huang } 491442839bbSJohnny Huang 492442839bbSJohnny Huang if (OTPCFG_KEEP[0] & WRITE_PROTECT_STRAPREG) { 493442839bbSJohnny Huang printf("OTPCFG0-D[25]\n"); 494442839bbSJohnny Huang printf(" Skip\n"); 495442839bbSJohnny Huang } else { 49669d5fd8fSJohnny Huang printf("OTPCFG0-D[25]\n"); 497e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_STRAPREG) 49869d5fd8fSJohnny Huang printf(" OTP strap Region : Write Protect\n"); 49969d5fd8fSJohnny Huang else 50069d5fd8fSJohnny Huang printf(" OTP strap Region : Writable\n"); 501442839bbSJohnny Huang } 502442839bbSJohnny Huang 503442839bbSJohnny Huang if (OTPCFG_KEEP[0] & ENABLE_COPY_TO_SRAM) { 504442839bbSJohnny Huang printf("OTPCFG0-D[25]\n"); 505442839bbSJohnny Huang printf(" Skip\n"); 506442839bbSJohnny Huang } else { 50769d5fd8fSJohnny Huang printf("OTPCFG0-D[26]\n"); 508e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_COPY_TO_SRAM) 50969d5fd8fSJohnny Huang printf(" Copy Boot Image to Internal SRAM\n"); 51069d5fd8fSJohnny Huang else 51169d5fd8fSJohnny Huang printf(" Disable Copy Boot Image to Internal SRAM\n"); 512442839bbSJohnny Huang } 513442839bbSJohnny Huang if (OTPCFG_KEEP[0] & ENABLE_IMAGE_ENC) { 514442839bbSJohnny Huang printf("OTPCFG0-D[27]\n"); 515442839bbSJohnny Huang printf(" Skip\n"); 516442839bbSJohnny Huang } else { 51769d5fd8fSJohnny Huang printf("OTPCFG0-D[27]\n"); 518e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_IMAGE_ENC) 51969d5fd8fSJohnny Huang printf(" Enable image encryption\n"); 52069d5fd8fSJohnny Huang else 52169d5fd8fSJohnny Huang printf(" Disable image encryption\n"); 522442839bbSJohnny Huang } 523442839bbSJohnny Huang 524442839bbSJohnny Huang if (OTPCFG_KEEP[0] & WRITE_PROTECT_KEY_RETIRE) { 525442839bbSJohnny Huang printf("OTPCFG0-D[29]\n"); 526442839bbSJohnny Huang printf(" Skip\n"); 527442839bbSJohnny Huang } else { 52869d5fd8fSJohnny Huang printf("OTPCFG0-D[29]\n"); 529e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_KEY_RETIRE) 53069d5fd8fSJohnny Huang printf(" OTP key retire Region : Write Protect\n"); 53169d5fd8fSJohnny Huang else 53269d5fd8fSJohnny Huang printf(" OTP key retire Region : Writable\n"); 533442839bbSJohnny Huang } 534442839bbSJohnny Huang 535442839bbSJohnny Huang if (OTPCFG_KEEP[0] & ENABLE_SIPROM_RED) { 536442839bbSJohnny Huang printf("OTPCFG0-D[30]\n"); 537442839bbSJohnny Huang printf(" Skip\n"); 538442839bbSJohnny Huang } else { 53969d5fd8fSJohnny Huang printf("OTPCFG0-D[30]\n"); 540e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SIPROM_RED) 54169d5fd8fSJohnny Huang printf(" SIPROM RED_EN redundancy repair enable\n"); 54269d5fd8fSJohnny Huang else 54369d5fd8fSJohnny Huang printf(" SIPROM RED_EN redundancy repair disable\n"); 544442839bbSJohnny Huang } 545442839bbSJohnny Huang 546442839bbSJohnny Huang if (OTPCFG_KEEP[0] & ENABLE_SIPROM_MLOCK) { 547442839bbSJohnny Huang printf("OTPCFG0-D[31]\n"); 548442839bbSJohnny Huang printf(" Skip\n"); 549442839bbSJohnny Huang } else { 55069d5fd8fSJohnny Huang printf("OTPCFG0-D[31]\n"); 551e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SIPROM_MLOCK) 55269d5fd8fSJohnny Huang printf(" SIPROM Mlock memory lock enable\n"); 55369d5fd8fSJohnny Huang else 55469d5fd8fSJohnny Huang printf(" SIPROM Mlock memory lock disable\n"); 555442839bbSJohnny Huang } 556442839bbSJohnny Huang if (SECREG_SIZE(OTPCFG_KEEP[2]) == 0xFFFF) { 557442839bbSJohnny Huang printf("OTPCFG2-D[15:0]\n"); 558442839bbSJohnny Huang printf(" Skip\n"); 559442839bbSJohnny Huang } else { 56069d5fd8fSJohnny Huang printf("OTPCFG2-D[15:0]\n"); 561e1f9e54eSJohnny Huang printf(" Vender ID : %x\n", VENDER_ID(OTPCFG[2])); 562442839bbSJohnny Huang } 56369d5fd8fSJohnny Huang 564442839bbSJohnny Huang if (SECREG_SIZE(OTPCFG_KEEP[2]) == 0xFFFF) { 565442839bbSJohnny Huang printf("OTPCFG2-D[31:16]\n"); 566442839bbSJohnny Huang printf(" Skip\n"); 567442839bbSJohnny Huang } else { 56869d5fd8fSJohnny Huang printf("OTPCFG2-D[31:16]\n"); 569e1f9e54eSJohnny Huang printf(" Key Revision : %x\n", KEY_REVISION(OTPCFG[2])); 570442839bbSJohnny Huang } 57169d5fd8fSJohnny Huang 572442839bbSJohnny Huang if (SEC_BOOT_HEADER_OFFSET(OTPCFG_KEEP[3]) == 0xFFFF) { 573442839bbSJohnny Huang printf("OTPCFG3-D[15:0]\n"); 574442839bbSJohnny Huang printf(" Skip\n"); 575442839bbSJohnny Huang } else { 57669d5fd8fSJohnny Huang printf("OTPCFG3-D[15:0]\n"); 577e1f9e54eSJohnny Huang printf(" Secure boot header offset : %x\n", 578e1f9e54eSJohnny Huang SEC_BOOT_HEADER_OFFSET(OTPCFG[3])); 579442839bbSJohnny Huang } 58069d5fd8fSJohnny Huang 581442839bbSJohnny Huang if (KEYS_VALID_BITS(OTPCFG_KEEP[4]) == 0xFF) { 582442839bbSJohnny Huang printf("OTPCFG4-D[7:0]\n"); 583442839bbSJohnny Huang printf(" Skip\n"); 584442839bbSJohnny Huang } else { 58569d5fd8fSJohnny Huang printf("OTPCFG4-D[7:0]\n"); 586e1f9e54eSJohnny Huang tmp = KEYS_VALID_BITS(OTPCFG[4]); 587e1f9e54eSJohnny Huang if (tmp != 0) { 58869d5fd8fSJohnny Huang for (i = 0; i < 7; i++) { 58969d5fd8fSJohnny Huang if (tmp == (1 << i)) { 590e1f9e54eSJohnny Huang pass = i + 1; 59169d5fd8fSJohnny Huang } 59269d5fd8fSJohnny Huang } 593e1f9e54eSJohnny Huang } else { 594e1f9e54eSJohnny Huang pass = 0; 595e1f9e54eSJohnny Huang } 596e1f9e54eSJohnny Huang printf(" Keys valid : %d\n", pass); 597442839bbSJohnny Huang } 598442839bbSJohnny Huang if (KEYS_RETIRE_BITS(OTPCFG_KEEP[4]) == 0xFF) { 599442839bbSJohnny Huang printf("OTPCFG4-D[23:16]\n"); 600442839bbSJohnny Huang printf(" Skip\n"); 601442839bbSJohnny Huang } else { 60269d5fd8fSJohnny Huang printf("OTPCFG4-D[23:16]\n"); 603e1f9e54eSJohnny Huang tmp = KEYS_RETIRE_BITS(OTPCFG[4]); 604e1f9e54eSJohnny Huang if (tmp != 0) { 60569d5fd8fSJohnny Huang for (i = 0; i < 7; i++) { 60669d5fd8fSJohnny Huang if (tmp == (1 << i)) { 607e1f9e54eSJohnny Huang pass = i + 1; 60869d5fd8fSJohnny Huang } 60969d5fd8fSJohnny Huang } 610e1f9e54eSJohnny Huang } else { 611e1f9e54eSJohnny Huang pass = 0; 61269d5fd8fSJohnny Huang } 61369d5fd8fSJohnny Huang printf(" Keys Retire ID : %d\n", pass); 614442839bbSJohnny Huang } 615442839bbSJohnny Huang if (OTPCFG_KEEP[5] == 0xFFFFFFFF) { 616442839bbSJohnny Huang printf("OTPCFG5-D[31:0]\n"); 617442839bbSJohnny Huang printf(" Skip\n"); 618442839bbSJohnny Huang } else { 61969d5fd8fSJohnny Huang printf("OTPCFG5-D[31:0]\n"); 62069d5fd8fSJohnny Huang printf(" User define data, random number low : %x\n", OTPCFG[5]); 621442839bbSJohnny Huang } 62269d5fd8fSJohnny Huang 623442839bbSJohnny Huang if (OTPCFG_KEEP[6] == 0xFFFFFFFF) { 624442839bbSJohnny Huang printf("OTPCFG6-D[31:0]\n"); 625442839bbSJohnny Huang printf(" Skip\n"); 626442839bbSJohnny Huang } else { 62769d5fd8fSJohnny Huang printf("OTPCFG6-D[31:0]\n"); 62869d5fd8fSJohnny Huang printf(" User define data, random number high : %x\n", OTPCFG[6]); 629442839bbSJohnny Huang } 63069d5fd8fSJohnny Huang 631442839bbSJohnny Huang if (OTPCFG_KEEP[8] == 0xFFFFFFFF) { 632442839bbSJohnny Huang printf("OTPCFG8-D[31:0]\n"); 633442839bbSJohnny Huang printf(" Skip\n"); 634442839bbSJohnny Huang } else { 63569d5fd8fSJohnny Huang printf("OTPCFG8-D[31:0]\n"); 63669d5fd8fSJohnny Huang printf(" Redundancy Repair : %x\n", OTPCFG[8]); 637442839bbSJohnny Huang } 63869d5fd8fSJohnny Huang 639442839bbSJohnny Huang if (OTPCFG_KEEP[10] == 0xFFFFFFFF) { 640442839bbSJohnny Huang printf("OTPCFG10-D[31:0]\n"); 641442839bbSJohnny Huang printf(" Skip\n"); 642442839bbSJohnny Huang } else { 64369d5fd8fSJohnny Huang printf("OTPCFG10-D[31:0]\n"); 64469d5fd8fSJohnny Huang printf(" Manifest ID low : %x\n", OTPCFG[10]); 645442839bbSJohnny Huang } 64669d5fd8fSJohnny Huang 647442839bbSJohnny Huang if (OTPCFG_KEEP[11] == 0xFFFFFFFF) { 648442839bbSJohnny Huang printf("OTPCFG11-D[31:0]\n"); 649442839bbSJohnny Huang printf(" Skip\n"); 650442839bbSJohnny Huang } else { 65169d5fd8fSJohnny Huang printf("OTPCFG11-D[31:0]\n"); 65269d5fd8fSJohnny Huang printf(" Manifest ID high : %x\n", OTPCFG[11]); 653442839bbSJohnny Huang } 654442839bbSJohnny Huang 65569d5fd8fSJohnny Huang return 0; 65669d5fd8fSJohnny Huang 65769d5fd8fSJohnny Huang } 65869d5fd8fSJohnny Huang 65969d5fd8fSJohnny Huang static void buf_print(char *buf, int len) 66069d5fd8fSJohnny Huang { 66169d5fd8fSJohnny Huang int i; 66269d5fd8fSJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 66369d5fd8fSJohnny Huang for (i = 0; i < len; i++) { 66469d5fd8fSJohnny Huang if (i % 16 == 0) { 66569d5fd8fSJohnny Huang printf("%04X: ", i); 66669d5fd8fSJohnny Huang } 66769d5fd8fSJohnny Huang printf("%02X ", buf[i]); 66869d5fd8fSJohnny Huang if ((i + 1) % 16 == 0) { 66969d5fd8fSJohnny Huang printf("\n"); 67069d5fd8fSJohnny Huang } 67169d5fd8fSJohnny Huang } 67269d5fd8fSJohnny Huang } 67369d5fd8fSJohnny Huang 674d90825e2SJohnny Huang static int otp_data_parse(uint32_t *buf) 67569d5fd8fSJohnny Huang { 67669d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 67769d5fd8fSJohnny Huang char *byte_buf; 67869d5fd8fSJohnny Huang int i = 0, len = 0; 67969d5fd8fSJohnny Huang byte_buf = (char *)buf; 68069d5fd8fSJohnny Huang while (1) { 68169d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 68269d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 68369d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 68469d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 68569d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 68669d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 68769d5fd8fSJohnny Huang printf("Key[%d]:\n", i); 68869d5fd8fSJohnny Huang printf("Key Type: "); 68969d5fd8fSJohnny Huang switch (key_type) { 69069d5fd8fSJohnny Huang case 0: 69169d5fd8fSJohnny Huang printf("AES-256 as OEM platform key for image encryption/decryption\n"); 69269d5fd8fSJohnny Huang break; 69369d5fd8fSJohnny Huang case 1: 69469d5fd8fSJohnny Huang printf("AES-256 as secret vault key\n"); 69569d5fd8fSJohnny Huang break; 69669d5fd8fSJohnny Huang case 4: 69769d5fd8fSJohnny Huang printf("HMAC as encrypted OEM HMAC keys in Mode 1\n"); 69869d5fd8fSJohnny Huang break; 69969d5fd8fSJohnny Huang case 8: 70069d5fd8fSJohnny Huang printf("RSA-public as OEM DSS public keys in Mode 2\n"); 70169d5fd8fSJohnny Huang break; 70269d5fd8fSJohnny Huang case 9: 70369d5fd8fSJohnny Huang printf("RSA-public as SOC public key\n"); 70469d5fd8fSJohnny Huang break; 70569d5fd8fSJohnny Huang case 10: 70669d5fd8fSJohnny Huang printf("RSA-public as AES key decryption key\n"); 70769d5fd8fSJohnny Huang break; 70869d5fd8fSJohnny Huang case 13: 70969d5fd8fSJohnny Huang printf("RSA-private as SOC private key\n"); 71069d5fd8fSJohnny Huang break; 71169d5fd8fSJohnny Huang case 14: 71269d5fd8fSJohnny Huang printf("RSA-private as AES key decryption key\n"); 71369d5fd8fSJohnny Huang break; 71469d5fd8fSJohnny Huang default: 71569d5fd8fSJohnny Huang printf("key_type error: %x\n", key_type); 71669d5fd8fSJohnny Huang return -1; 71769d5fd8fSJohnny Huang } 71869d5fd8fSJohnny Huang if (key_type == 4) { 71969d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 72069d5fd8fSJohnny Huang switch (key_length) { 72169d5fd8fSJohnny Huang case 0: 72269d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 72369d5fd8fSJohnny Huang break; 72469d5fd8fSJohnny Huang case 1: 72569d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 72669d5fd8fSJohnny Huang break; 72769d5fd8fSJohnny Huang case 2: 72869d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 72969d5fd8fSJohnny Huang break; 73069d5fd8fSJohnny Huang case 3: 73169d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 73269d5fd8fSJohnny Huang break; 73369d5fd8fSJohnny Huang } 734cd1610b4SJohnny Huang } else if (key_type != 0 && key_type != 1) { 73569d5fd8fSJohnny Huang printf("RSA SHA Type: "); 73669d5fd8fSJohnny Huang switch (key_length) { 73769d5fd8fSJohnny Huang case 0: 73869d5fd8fSJohnny Huang printf("RSA1024\n"); 73969d5fd8fSJohnny Huang len = 0x100; 74069d5fd8fSJohnny Huang break; 74169d5fd8fSJohnny Huang case 1: 74269d5fd8fSJohnny Huang printf("RSA2048\n"); 74369d5fd8fSJohnny Huang len = 0x200; 74469d5fd8fSJohnny Huang break; 74569d5fd8fSJohnny Huang case 2: 74669d5fd8fSJohnny Huang printf("RSA3072\n"); 74769d5fd8fSJohnny Huang len = 0x300; 74869d5fd8fSJohnny Huang break; 74969d5fd8fSJohnny Huang case 3: 75069d5fd8fSJohnny Huang printf("RSA4096\n"); 75169d5fd8fSJohnny Huang len = 0x400; 75269d5fd8fSJohnny Huang break; 75369d5fd8fSJohnny Huang } 75469d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 75569d5fd8fSJohnny Huang } 75669d5fd8fSJohnny Huang if (key_type == 4 || key_type == 8) 75769d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 75869d5fd8fSJohnny Huang printf("Key Value:\n"); 75969d5fd8fSJohnny Huang if (key_type == 4) { 76069d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 76169d5fd8fSJohnny Huang } else if (key_type == 0 || key_type == 1) { 76269d5fd8fSJohnny Huang printf("AES Key:\n"); 76369d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 76469d5fd8fSJohnny Huang printf("AES IV:\n"); 76569d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 76669d5fd8fSJohnny Huang 76769d5fd8fSJohnny Huang } else { 76869d5fd8fSJohnny Huang printf("RSA mod:\n"); 76969d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 77069d5fd8fSJohnny Huang printf("RSA exp:\n"); 77169d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 77269d5fd8fSJohnny Huang } 77369d5fd8fSJohnny Huang if (last) 77469d5fd8fSJohnny Huang break; 77569d5fd8fSJohnny Huang i++; 77669d5fd8fSJohnny Huang } 77769d5fd8fSJohnny Huang return 0; 77869d5fd8fSJohnny Huang } 77969d5fd8fSJohnny Huang 780a6d0d645SJohnny Huang static int otp_prog_conf(uint32_t *buf) 78169d5fd8fSJohnny Huang { 782a6d0d645SJohnny Huang int i, k; 783d90825e2SJohnny Huang int pass = 0; 784d90825e2SJohnny Huang int soak = 0; 785a6d0d645SJohnny Huang uint32_t prog_address; 786a6d0d645SJohnny Huang uint32_t data[12]; 787a6d0d645SJohnny Huang uint32_t compare[2]; 788d90825e2SJohnny Huang uint32_t *buf_keep = &buf[12]; 789d90825e2SJohnny Huang uint32_t data_masked; 790d90825e2SJohnny Huang uint32_t buf_masked; 79169d5fd8fSJohnny Huang 792a6d0d645SJohnny Huang printf("Read OTP Config Region:\n"); 793a6d0d645SJohnny Huang 794a6d0d645SJohnny Huang printProgress(0, 12, ""); 795a6d0d645SJohnny Huang for (i = 0; i < 12 ; i ++) { 796a6d0d645SJohnny Huang printProgress(i + 1, 12, ""); 79769d5fd8fSJohnny Huang prog_address = 0x800; 798a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 799a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 800a6d0d645SJohnny Huang otp_read_data(prog_address, &data[i]); 801a6d0d645SJohnny Huang } 802a6d0d645SJohnny Huang 803a6d0d645SJohnny Huang printf("Check writable...\n"); 804a6d0d645SJohnny Huang for (i = 0; i < 12; i++) { 805d90825e2SJohnny Huang data_masked = data[i] & ~buf_keep[i]; 806d90825e2SJohnny Huang buf_masked = buf[i] & ~buf_keep[i]; 807d90825e2SJohnny Huang if (data_masked == buf_masked) 80869d5fd8fSJohnny Huang continue; 809d90825e2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 810a6d0d645SJohnny Huang continue; 811a6d0d645SJohnny Huang } else { 812a6d0d645SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 813a6d0d645SJohnny Huang printf("OTPCFG[%d] = %x\n", i, data[i]); 814a6d0d645SJohnny Huang printf("Input [%d] = %x\n", i, buf[i]); 815d90825e2SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_keep[i]); 816*2a856b9aSJohnny Huang return OTP_FAILURE; 817a6d0d645SJohnny Huang } 818a6d0d645SJohnny Huang } 819a6d0d645SJohnny Huang 820a6d0d645SJohnny Huang printf("Start Programing...\n"); 821a6d0d645SJohnny Huang printProgress(0, 12, ""); 822d90825e2SJohnny Huang otp_soak(0); 823a6d0d645SJohnny Huang for (i = 0; i < 12; i++) { 824d90825e2SJohnny Huang data_masked = data[i] & ~buf_keep[i]; 825d90825e2SJohnny Huang buf_masked = buf[i] & ~buf_keep[i]; 826a6d0d645SJohnny Huang prog_address = 0x800; 827a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 828a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 829d90825e2SJohnny Huang if (data_masked == buf_masked) { 830a6d0d645SJohnny Huang printProgress(i + 1, 12, "[%03X]=%08X HIT", prog_address, buf[i]); 831a6d0d645SJohnny Huang continue; 832a6d0d645SJohnny Huang } 833d90825e2SJohnny Huang if (soak) { 834d90825e2SJohnny Huang soak = 0; 835d90825e2SJohnny Huang otp_soak(0); 836d90825e2SJohnny Huang } 837a6d0d645SJohnny Huang printProgress(i + 1, 12, "[%03X]=%08X ", prog_address, buf[i]); 838a6d0d645SJohnny Huang 839d90825e2SJohnny Huang otp_prog_dw(buf[i], buf_keep[i], prog_address); 840a6d0d645SJohnny Huang 84169d5fd8fSJohnny Huang pass = 0; 84269d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 843d90825e2SJohnny Huang if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 1) != 0) { 844d90825e2SJohnny Huang if (soak == 0) { 845d90825e2SJohnny Huang soak = 1; 846d90825e2SJohnny Huang otp_soak(1); 847d90825e2SJohnny Huang } 848a6d0d645SJohnny Huang otp_prog_dw(compare[0], prog_address, 1); 849a6d0d645SJohnny Huang } else { 85069d5fd8fSJohnny Huang pass = 1; 85169d5fd8fSJohnny Huang break; 85269d5fd8fSJohnny Huang } 85369d5fd8fSJohnny Huang } 854a6d0d645SJohnny Huang } 855a6d0d645SJohnny Huang 85669d5fd8fSJohnny Huang if (!pass) 857*2a856b9aSJohnny Huang return OTP_FAILURE; 858a6d0d645SJohnny Huang 859*2a856b9aSJohnny Huang return OTP_SUCCESS; 860d90825e2SJohnny Huang 86169d5fd8fSJohnny Huang } 86269d5fd8fSJohnny Huang 86369d5fd8fSJohnny Huang static void otp_strp_status(struct otpstrap *otpstrap) 86469d5fd8fSJohnny Huang { 86569d5fd8fSJohnny Huang uint32_t OTPSTRAP_RAW[2]; 86669d5fd8fSJohnny Huang int i, j; 86769d5fd8fSJohnny Huang 86869d5fd8fSJohnny Huang for (j = 0; j < 64; j++) { 86969d5fd8fSJohnny Huang otpstrap[j].value = 0; 87069d5fd8fSJohnny Huang otpstrap[j].remain_times = 7; 87169d5fd8fSJohnny Huang otpstrap[j].writeable_option = -1; 87269d5fd8fSJohnny Huang otpstrap[j].protected = 0; 87369d5fd8fSJohnny Huang } 87469d5fd8fSJohnny Huang 87569d5fd8fSJohnny Huang for (i = 16; i < 30; i += 2) { 87669d5fd8fSJohnny Huang int option = (i - 16) / 2; 87769d5fd8fSJohnny Huang otp_read_config(i, &OTPSTRAP_RAW[0]); 87869d5fd8fSJohnny Huang otp_read_config(i + 1, &OTPSTRAP_RAW[1]); 87969d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 88069d5fd8fSJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 88169d5fd8fSJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 88269d5fd8fSJohnny Huang otpstrap[j].writeable_option = option; 88369d5fd8fSJohnny Huang } 88469d5fd8fSJohnny Huang if (bit_value == 1) 88569d5fd8fSJohnny Huang otpstrap[j].remain_times --; 88669d5fd8fSJohnny Huang otpstrap[j].value ^= bit_value; 88769d5fd8fSJohnny Huang otpstrap[j].option_array[option] = bit_value; 88869d5fd8fSJohnny Huang } 88969d5fd8fSJohnny Huang for (j = 32; j < 64; j++) { 89069d5fd8fSJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 89169d5fd8fSJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 89269d5fd8fSJohnny Huang otpstrap[j].writeable_option = option; 89369d5fd8fSJohnny Huang } 89469d5fd8fSJohnny Huang if (bit_value == 1) 89569d5fd8fSJohnny Huang otpstrap[j].remain_times --; 89669d5fd8fSJohnny Huang otpstrap[j].value ^= bit_value; 89769d5fd8fSJohnny Huang otpstrap[j].option_array[option] = bit_value; 89869d5fd8fSJohnny Huang } 89969d5fd8fSJohnny Huang } 90069d5fd8fSJohnny Huang otp_read_config(30, &OTPSTRAP_RAW[0]); 90169d5fd8fSJohnny Huang otp_read_config(31, &OTPSTRAP_RAW[1]); 90269d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 90369d5fd8fSJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 90469d5fd8fSJohnny Huang otpstrap[j].protected = 1; 90569d5fd8fSJohnny Huang } 90669d5fd8fSJohnny Huang for (j = 32; j < 64; j++) { 90769d5fd8fSJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 90869d5fd8fSJohnny Huang otpstrap[j].protected = 1; 90969d5fd8fSJohnny Huang } 91069d5fd8fSJohnny Huang } 91169d5fd8fSJohnny Huang 91269d5fd8fSJohnny Huang static int otp_strap_parse(uint32_t *buf) 91369d5fd8fSJohnny Huang { 91469d5fd8fSJohnny Huang int i; 91569d5fd8fSJohnny Huang uint32_t *strap_keep = buf + 2; 91669d5fd8fSJohnny Huang uint32_t *strap_protect = buf + 4; 91769d5fd8fSJohnny Huang int bit, pbit, kbit; 91869d5fd8fSJohnny Huang int fail = 0; 91969d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 92069d5fd8fSJohnny Huang 92169d5fd8fSJohnny Huang otp_strp_status(otpstrap); 92269d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 92369d5fd8fSJohnny Huang if (i < 32) { 92469d5fd8fSJohnny Huang bit = (buf[0] >> i) & 0x1; 92569d5fd8fSJohnny Huang kbit = (strap_keep[0] >> i) & 0x1; 92669d5fd8fSJohnny Huang pbit = (strap_protect[0] >> i) & 0x1; 92769d5fd8fSJohnny Huang } else { 92869d5fd8fSJohnny Huang bit = (buf[1] >> (i - 32)) & 0x1; 92969d5fd8fSJohnny Huang kbit = (strap_keep[1] >> (i - 32)) & 0x1; 93069d5fd8fSJohnny Huang pbit = (strap_protect[1] >> (i - 32)) & 0x1; 93169d5fd8fSJohnny Huang } 93269d5fd8fSJohnny Huang 93369d5fd8fSJohnny Huang if (kbit == 1) { 93469d5fd8fSJohnny Huang continue; 93569d5fd8fSJohnny Huang } else { 93669d5fd8fSJohnny Huang printf("OTPSTRAP[%d]:\n", i); 93769d5fd8fSJohnny Huang } 93869d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 93969d5fd8fSJohnny Huang printf(" The value is same as before, skip it.\n"); 94069d5fd8fSJohnny Huang continue; 94169d5fd8fSJohnny Huang } 94269d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 94369d5fd8fSJohnny Huang printf(" This bit is protected and is not writable\n"); 94469d5fd8fSJohnny Huang fail = 1; 94569d5fd8fSJohnny Huang continue; 94669d5fd8fSJohnny Huang } 94769d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 94869d5fd8fSJohnny Huang printf(" This bit is no remaining number of times to write.\n"); 94969d5fd8fSJohnny Huang fail = 1; 95069d5fd8fSJohnny Huang continue; 95169d5fd8fSJohnny Huang } 95269d5fd8fSJohnny Huang if (pbit == 1) { 95369d5fd8fSJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 95469d5fd8fSJohnny Huang } 955cd1610b4SJohnny 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); 95669d5fd8fSJohnny Huang } 95769d5fd8fSJohnny Huang if (fail == 1) 95869d5fd8fSJohnny Huang return -1; 95969d5fd8fSJohnny Huang else 96069d5fd8fSJohnny Huang return 0; 96169d5fd8fSJohnny Huang } 96269d5fd8fSJohnny Huang 963*2a856b9aSJohnny Huang static int otp_print_strap(int start, int count) 96469d5fd8fSJohnny Huang { 96569d5fd8fSJohnny Huang int i, j; 96669d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 96769d5fd8fSJohnny Huang 968*2a856b9aSJohnny Huang if (start < 0 || start > 64) 969*2a856b9aSJohnny Huang return OTP_USAGE; 970*2a856b9aSJohnny Huang 971*2a856b9aSJohnny Huang if ((start + count) < 0 || (start + count) > 64) 972*2a856b9aSJohnny Huang return OTP_USAGE; 973*2a856b9aSJohnny Huang 97469d5fd8fSJohnny Huang otp_strp_status(otpstrap); 97569d5fd8fSJohnny Huang 976cd1610b4SJohnny Huang for (i = start; i < start + count; i++) { 97769d5fd8fSJohnny Huang printf("OTPSTRAP[%d]:\n", i); 97869d5fd8fSJohnny Huang printf(" OTP Option value: "); 97969d5fd8fSJohnny Huang for (j = 1; j <= 7; j++) 98069d5fd8fSJohnny Huang printf("[%d]:%d ", j, otpstrap[i].option_array[j - 1]); 98169d5fd8fSJohnny Huang printf("\n"); 98269d5fd8fSJohnny Huang printf(" OTP Value: %d\n", otpstrap[i].value); 98369d5fd8fSJohnny Huang printf(" Status:\n"); 98469d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 98569d5fd8fSJohnny Huang printf(" OTPSTRAP[%d] is protected and is not writable\n", i); 98669d5fd8fSJohnny Huang } else { 98769d5fd8fSJohnny Huang printf(" OTPSTRAP[%d] is not protected ", i); 98869d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 98969d5fd8fSJohnny Huang printf("and no remaining number of times to write.\n"); 99069d5fd8fSJohnny Huang } else { 99169d5fd8fSJohnny Huang printf("and still can write %d number of times\n", otpstrap[i].remain_times); 99269d5fd8fSJohnny Huang } 99369d5fd8fSJohnny Huang } 99469d5fd8fSJohnny Huang } 995*2a856b9aSJohnny Huang 996*2a856b9aSJohnny Huang return OTP_SUCCESS; 99769d5fd8fSJohnny Huang } 99869d5fd8fSJohnny Huang 99969d5fd8fSJohnny Huang static int otp_prog_strap(uint32_t *buf) 100069d5fd8fSJohnny Huang { 100169d5fd8fSJohnny Huang int i, j; 100269d5fd8fSJohnny Huang uint32_t *strap_keep = buf + 2; 100369d5fd8fSJohnny Huang uint32_t *strap_protect = buf + 4; 100469d5fd8fSJohnny Huang uint32_t prog_bit, prog_address; 100569d5fd8fSJohnny Huang int bit, pbit, kbit, offset; 100669d5fd8fSJohnny Huang int fail = 0; 100769d5fd8fSJohnny Huang int pass, soak; 100869d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 100969d5fd8fSJohnny Huang 101069d5fd8fSJohnny Huang otp_strp_status(otpstrap); 101169d5fd8fSJohnny Huang 101269d5fd8fSJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 101369d5fd8fSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 101469d5fd8fSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 101569d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 10164c1c9b35SJohnny Huang printProgress(i + 1, 64, ""); 101769d5fd8fSJohnny Huang prog_address = 0x800; 101869d5fd8fSJohnny Huang if (i < 32) { 101969d5fd8fSJohnny Huang offset = i; 102069d5fd8fSJohnny Huang bit = (buf[0] >> offset) & 0x1; 102169d5fd8fSJohnny Huang kbit = (strap_keep[0] >> offset) & 0x1; 102269d5fd8fSJohnny Huang pbit = (strap_protect[0] >> offset) & 0x1; 102369d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 102469d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 102569d5fd8fSJohnny Huang 102669d5fd8fSJohnny Huang } else { 102769d5fd8fSJohnny Huang offset = (i - 32); 102869d5fd8fSJohnny Huang bit = (buf[1] >> offset) & 0x1; 102969d5fd8fSJohnny Huang kbit = (strap_keep[1] >> offset) & 0x1; 103069d5fd8fSJohnny Huang pbit = (strap_protect[1] >> offset) & 0x1; 103169d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 103269d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 103369d5fd8fSJohnny Huang } 103469d5fd8fSJohnny Huang prog_bit = ~(0x1 << offset); 103569d5fd8fSJohnny Huang 103669d5fd8fSJohnny Huang if (kbit == 1) { 103769d5fd8fSJohnny Huang continue; 103869d5fd8fSJohnny Huang } 103969d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 104069d5fd8fSJohnny Huang continue; 104169d5fd8fSJohnny Huang } 104269d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 104369d5fd8fSJohnny Huang fail = 1; 104469d5fd8fSJohnny Huang continue; 104569d5fd8fSJohnny Huang } 104669d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 104769d5fd8fSJohnny Huang fail = 1; 104869d5fd8fSJohnny Huang continue; 104969d5fd8fSJohnny Huang } 105069d5fd8fSJohnny Huang pass = 0; 105169d5fd8fSJohnny Huang soak = 0; 10524b65a65dSJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 10534b65a65dSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 10544b65a65dSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 10554b65a65dSJohnny Huang writel(0x04190760, 0x1e602008); //normal program 105669d5fd8fSJohnny Huang for (j = 0; j < RETRY; j++) { 105769d5fd8fSJohnny Huang if (!soak) { 105869d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 1059a6d0d645SJohnny Huang if (verify_bit(prog_address, offset, 1) == 0) { 106069d5fd8fSJohnny Huang pass = 1; 106169d5fd8fSJohnny Huang break; 106269d5fd8fSJohnny Huang } 106369d5fd8fSJohnny Huang soak = 1; 10644b65a65dSJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 10654b65a65dSJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 10664b65a65dSJohnny Huang otp_write(0x1000, 0x4820); // Write MR 106769d5fd8fSJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 10684b65a65dSJohnny Huang } 106969d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 1070a6d0d645SJohnny Huang if (verify_bit(prog_address, offset, 1) == 0) { 107169d5fd8fSJohnny Huang pass = 1; 107269d5fd8fSJohnny Huang break; 107369d5fd8fSJohnny Huang } 107469d5fd8fSJohnny Huang } 107569d5fd8fSJohnny Huang if (!pass) 1076*2a856b9aSJohnny Huang return OTP_FAILURE; 107769d5fd8fSJohnny Huang 107869d5fd8fSJohnny Huang if (pbit == 0) 107969d5fd8fSJohnny Huang continue; 108069d5fd8fSJohnny Huang prog_address = 0x800; 108169d5fd8fSJohnny Huang if (i < 32) 108269d5fd8fSJohnny Huang prog_address |= 0x60c; 108369d5fd8fSJohnny Huang else 108469d5fd8fSJohnny Huang prog_address |= 0x60e; 108569d5fd8fSJohnny Huang 108669d5fd8fSJohnny Huang for (j = 0; j < RETRY; j++) { 108769d5fd8fSJohnny Huang if (!soak) { 108869d5fd8fSJohnny Huang writel(0x04190760, 0x1e602008); //normal program 108969d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 1090a6d0d645SJohnny Huang if (verify_bit(prog_address, offset, 1) == 0) { 109169d5fd8fSJohnny Huang pass = 1; 109269d5fd8fSJohnny Huang break; 109369d5fd8fSJohnny Huang } 109469d5fd8fSJohnny Huang soak = 1; 109569d5fd8fSJohnny Huang } 109669d5fd8fSJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 109769d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 1098a6d0d645SJohnny Huang if (verify_bit(prog_address, offset, 1) == 0) { 109969d5fd8fSJohnny Huang pass = 1; 110069d5fd8fSJohnny Huang break; 110169d5fd8fSJohnny Huang } 110269d5fd8fSJohnny Huang } 110369d5fd8fSJohnny Huang if (!pass) 1104*2a856b9aSJohnny Huang return OTP_FAILURE; 110569d5fd8fSJohnny Huang 110669d5fd8fSJohnny Huang } 110769d5fd8fSJohnny Huang if (fail == 1) 1108*2a856b9aSJohnny Huang return OTP_FAILURE; 110969d5fd8fSJohnny Huang else 1110*2a856b9aSJohnny Huang return OTP_SUCCESS; 111169d5fd8fSJohnny Huang 111269d5fd8fSJohnny Huang } 111369d5fd8fSJohnny Huang 1114cd1610b4SJohnny Huang static void otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset, int soak) 1115cd1610b4SJohnny Huang { 1116cd1610b4SJohnny Huang int prog_bit; 1117cd1610b4SJohnny Huang 1118cd1610b4SJohnny Huang if (soak) { 1119cd1610b4SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 1120cd1610b4SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 1121cd1610b4SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 1122cd1610b4SJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 1123cd1610b4SJohnny Huang } else { 1124cd1610b4SJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 1125cd1610b4SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 1126cd1610b4SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 1127cd1610b4SJohnny Huang writel(0x04190760, 0x1e602008); //normal program 1128cd1610b4SJohnny Huang } 1129cd1610b4SJohnny Huang if (prog_address % 2 == 0) { 1130cd1610b4SJohnny Huang if (value) 1131cd1610b4SJohnny Huang prog_bit = ~(0x1 << bit_offset); 1132cd1610b4SJohnny Huang else 1133cd1610b4SJohnny Huang return; 1134cd1610b4SJohnny Huang } else { 1135cd1610b4SJohnny Huang prog_address |= 1 << 15; 1136cd1610b4SJohnny Huang if (!value) 1137cd1610b4SJohnny Huang prog_bit = 0x1 << bit_offset; 1138cd1610b4SJohnny Huang else 1139cd1610b4SJohnny Huang return; 1140cd1610b4SJohnny Huang } 1141cd1610b4SJohnny Huang otp_prog(prog_address, prog_bit); 1142cd1610b4SJohnny Huang } 1143cd1610b4SJohnny Huang 1144d90825e2SJohnny Huang static int otp_prog_data(uint32_t *buf) 11454c1c9b35SJohnny Huang { 11464c1c9b35SJohnny Huang int i, k; 11474c1c9b35SJohnny Huang int pass; 1148d90825e2SJohnny Huang int soak = 0; 11494c1c9b35SJohnny Huang uint32_t prog_address; 1150d90825e2SJohnny Huang uint32_t data[2048]; 11514c1c9b35SJohnny Huang uint32_t compare[2]; 1152d90825e2SJohnny Huang uint32_t *buf_keep = &buf[2048]; 11534c1c9b35SJohnny Huang 1154d90825e2SJohnny Huang uint32_t data0_masked; 1155d90825e2SJohnny Huang uint32_t data1_masked; 1156d90825e2SJohnny Huang uint32_t buf0_masked; 1157d90825e2SJohnny Huang uint32_t buf1_masked; 11584c1c9b35SJohnny Huang 11594c1c9b35SJohnny Huang printf("Read OTP Data:\n"); 11604c1c9b35SJohnny Huang 1161d90825e2SJohnny Huang printProgress(0, 2048, ""); 1162d90825e2SJohnny Huang for (i = 0; i < 2048 ; i += 2) { 1163d90825e2SJohnny Huang printProgress(i + 2, 2048, ""); 1164d90825e2SJohnny Huang otp_read_data(i, &data[i]); 11654c1c9b35SJohnny Huang } 1166d90825e2SJohnny Huang 11674c1c9b35SJohnny Huang 11684c1c9b35SJohnny Huang printf("Check writable...\n"); 1169d90825e2SJohnny Huang for (i = 0; i < 2048; i++) { 1170d90825e2SJohnny Huang data0_masked = data[i] & ~buf_keep[i]; 1171d90825e2SJohnny Huang buf0_masked = buf[i] & ~buf_keep[i]; 1172d90825e2SJohnny Huang if (data0_masked == buf0_masked) 11734c1c9b35SJohnny Huang continue; 1174d90825e2SJohnny Huang if (i % 2 == 0) { 1175d90825e2SJohnny Huang if ((data0_masked | buf0_masked) == buf0_masked) { 11764c1c9b35SJohnny Huang continue; 11774c1c9b35SJohnny Huang } else { 11784c1c9b35SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1179d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 11804c1c9b35SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1181d90825e2SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_keep[i]); 1182*2a856b9aSJohnny Huang return OTP_FAILURE; 118369d5fd8fSJohnny Huang } 1184d90825e2SJohnny Huang } else { 1185d90825e2SJohnny Huang if ((data0_masked & buf0_masked) == buf0_masked) { 1186d90825e2SJohnny Huang continue; 1187d90825e2SJohnny Huang } else { 1188d90825e2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1189d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1190d90825e2SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1191d90825e2SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_keep[i]); 1192*2a856b9aSJohnny Huang return OTP_FAILURE; 1193d90825e2SJohnny Huang } 1194d90825e2SJohnny Huang } 1195d90825e2SJohnny Huang } 119669d5fd8fSJohnny Huang 1197d90825e2SJohnny Huang printf("Start Programing...\n"); 1198d90825e2SJohnny Huang printProgress(0, 2048, ""); 1199d90825e2SJohnny Huang 1200d90825e2SJohnny Huang for (i = 0; i < 2048; i += 2) { 1201d90825e2SJohnny Huang prog_address = i; 1202d90825e2SJohnny Huang data0_masked = data[i] & ~buf_keep[i]; 1203d90825e2SJohnny Huang buf0_masked = buf[i] & ~buf_keep[i]; 1204d90825e2SJohnny Huang data1_masked = data[i + 1] & ~buf_keep[i + 1]; 1205d90825e2SJohnny Huang buf1_masked = buf[i + 1] & ~buf_keep[i + 1]; 1206d90825e2SJohnny Huang if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked)) { 1207d90825e2SJohnny Huang printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]); 1208d90825e2SJohnny Huang continue; 1209d90825e2SJohnny Huang } 1210d90825e2SJohnny Huang if (soak) { 1211d90825e2SJohnny Huang soak = 0; 1212d90825e2SJohnny Huang otp_soak(0); 1213d90825e2SJohnny Huang } 1214d90825e2SJohnny Huang if (data1_masked == buf1_masked) { 1215d90825e2SJohnny Huang printProgress(i + 2, 2048, "[%03X]=%08X ;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]); 1216d90825e2SJohnny Huang otp_prog_dw(buf[i], buf_keep[i], prog_address); 1217d90825e2SJohnny Huang } else if (data0_masked == buf0_masked) { 1218d90825e2SJohnny Huang printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X ", prog_address, buf[i], prog_address + 1, buf[i + 1]); 1219d90825e2SJohnny Huang otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1); 1220d90825e2SJohnny Huang } else { 1221d90825e2SJohnny Huang printProgress(i + 2, 2048, "[%03X]=%08X ;[%03X]=%08X ", prog_address, buf[i], prog_address + 1, buf[i + 1]); 1222d90825e2SJohnny Huang otp_prog_dw(buf[i], buf_keep[i], prog_address); 1223d90825e2SJohnny Huang otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1); 1224d90825e2SJohnny Huang } 1225d90825e2SJohnny Huang 1226d90825e2SJohnny Huang pass = 0; 1227d90825e2SJohnny Huang for (k = 0; k < RETRY; k++) { 1228d90825e2SJohnny Huang if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 2) != 0) { 1229d90825e2SJohnny Huang if (soak == 0) { 1230d90825e2SJohnny Huang soak = 1; 1231d90825e2SJohnny Huang otp_soak(1); 1232d90825e2SJohnny Huang } 1233d90825e2SJohnny Huang if (compare[0] != 0) { 1234d90825e2SJohnny Huang otp_prog_dw(compare[0], buf_keep[i], prog_address); 1235d90825e2SJohnny Huang } 1236d90825e2SJohnny Huang if (compare[1] != ~0) { 1237d90825e2SJohnny Huang otp_prog_dw(compare[1], buf_keep[i], prog_address + 1); 1238d90825e2SJohnny Huang } 1239d90825e2SJohnny Huang } else { 1240d90825e2SJohnny Huang pass = 1; 1241d90825e2SJohnny Huang break; 1242d90825e2SJohnny Huang } 1243d90825e2SJohnny Huang } 1244d90825e2SJohnny Huang 1245d90825e2SJohnny Huang if (!pass) 1246*2a856b9aSJohnny Huang return OTP_FAILURE; 1247d90825e2SJohnny Huang } 1248*2a856b9aSJohnny Huang return OTP_SUCCESS; 1249d90825e2SJohnny Huang 1250d90825e2SJohnny Huang } 1251d90825e2SJohnny Huang 1252d90825e2SJohnny Huang static int do_otp_prog(int addr, int byte_size, int nconfirm) 125369d5fd8fSJohnny Huang { 125469d5fd8fSJohnny Huang int ret; 1255d90825e2SJohnny Huang int mode; 125669d5fd8fSJohnny Huang uint32_t *buf; 1257d90825e2SJohnny Huang uint32_t *data_region = NULL; 1258d90825e2SJohnny Huang uint32_t *conf_region = NULL; 1259d90825e2SJohnny Huang uint32_t *strap_region = NULL; 126069d5fd8fSJohnny Huang 1261d90825e2SJohnny Huang buf = map_physmem(addr, byte_size, MAP_WRBACK); 126269d5fd8fSJohnny Huang if (!buf) { 126369d5fd8fSJohnny Huang puts("Failed to map physical memory\n"); 1264*2a856b9aSJohnny Huang return OTP_FAILURE; 126569d5fd8fSJohnny Huang } 1266d90825e2SJohnny Huang 1267d90825e2SJohnny Huang if (((buf[0] >> 29) & 0x7) == 0x7) { 1268d90825e2SJohnny Huang mode = OTP_REGION_ALL; 1269d90825e2SJohnny Huang conf_region = &buf[1]; 1270d90825e2SJohnny Huang strap_region = &buf[25]; 1271d90825e2SJohnny Huang data_region = &buf[31]; 1272d90825e2SJohnny Huang } else { 1273d90825e2SJohnny Huang if (buf[0] & BIT(29)) { 1274d90825e2SJohnny Huang mode = OTP_REGION_DATA; 1275d90825e2SJohnny Huang data_region = &buf[31]; 1276d90825e2SJohnny Huang } 1277d90825e2SJohnny Huang if (buf[0] & BIT(30)) { 1278d90825e2SJohnny Huang mode = OTP_REGION_CONF; 1279d90825e2SJohnny Huang strap_region = &buf[25]; 1280d90825e2SJohnny Huang } 1281d90825e2SJohnny Huang if (buf[0] & BIT(31)) { 1282d90825e2SJohnny Huang mode = OTP_REGION_STRAP; 1283d90825e2SJohnny Huang conf_region = &buf[1]; 1284d90825e2SJohnny Huang } 1285d90825e2SJohnny Huang } 128669d5fd8fSJohnny Huang if (!nconfirm) { 1287a6d0d645SJohnny Huang if (mode == OTP_REGION_CONF) { 1288d90825e2SJohnny Huang if (otp_conf_parse(conf_region) < 0) { 128969d5fd8fSJohnny Huang printf("OTP config error, please check.\n"); 1290*2a856b9aSJohnny Huang return OTP_FAILURE; 129169d5fd8fSJohnny Huang } 1292a6d0d645SJohnny Huang } else if (mode == OTP_REGION_DATA) { 1293d90825e2SJohnny Huang if (otp_data_parse(data_region) < 0) { 129469d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 1295*2a856b9aSJohnny Huang return OTP_FAILURE; 129669d5fd8fSJohnny Huang } 1297a6d0d645SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 1298d90825e2SJohnny Huang if (otp_strap_parse(strap_region) < 0) { 129969d5fd8fSJohnny Huang printf("OTP strap error, please check.\n"); 1300*2a856b9aSJohnny Huang return OTP_FAILURE; 130169d5fd8fSJohnny Huang } 1302a6d0d645SJohnny Huang } else if (mode == OTP_REGION_ALL) { 1303d90825e2SJohnny Huang if (otp_conf_parse(conf_region) < 0) { 130469d5fd8fSJohnny Huang printf("OTP config error, please check.\n"); 1305*2a856b9aSJohnny Huang return OTP_FAILURE; 130669d5fd8fSJohnny Huang } 1307d90825e2SJohnny Huang if (otp_strap_parse(strap_region) < 0) { 130869d5fd8fSJohnny Huang printf("OTP strap error, please check.\n"); 1309*2a856b9aSJohnny Huang return OTP_FAILURE; 131069d5fd8fSJohnny Huang } 1311d90825e2SJohnny Huang if (otp_data_parse(data_region) < 0) { 131269d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 1313*2a856b9aSJohnny Huang return OTP_FAILURE; 131469d5fd8fSJohnny Huang } 131569d5fd8fSJohnny Huang } 131669d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 131769d5fd8fSJohnny Huang if (!confirm_yesno()) { 131869d5fd8fSJohnny Huang printf(" Aborting\n"); 1319*2a856b9aSJohnny Huang return OTP_FAILURE; 132069d5fd8fSJohnny Huang } 132169d5fd8fSJohnny Huang } 1322a6d0d645SJohnny Huang if (mode == OTP_REGION_CONF) { 1323d90825e2SJohnny Huang return otp_prog_conf(conf_region); 1324a6d0d645SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 1325d90825e2SJohnny Huang return otp_prog_strap(strap_region); 1326a6d0d645SJohnny Huang } else if (mode == OTP_REGION_DATA) { 1327d90825e2SJohnny Huang return otp_prog_data(data_region); 1328a6d0d645SJohnny Huang } else if (mode == OTP_REGION_ALL) { 132969d5fd8fSJohnny Huang printf("programing data region ... "); 1330d90825e2SJohnny Huang ret = otp_prog_data(data_region); 1331*2a856b9aSJohnny Huang if (ret != 0) { 133269d5fd8fSJohnny Huang printf("Error\n"); 133369d5fd8fSJohnny Huang return ret; 133469d5fd8fSJohnny Huang } else { 133569d5fd8fSJohnny Huang printf("Done\n"); 133669d5fd8fSJohnny Huang } 133769d5fd8fSJohnny Huang printf("programing strap region ... "); 1338d90825e2SJohnny Huang ret = otp_prog_strap(strap_region); 1339*2a856b9aSJohnny Huang if (ret != 0) { 134069d5fd8fSJohnny Huang printf("Error\n"); 134169d5fd8fSJohnny Huang return ret; 134269d5fd8fSJohnny Huang } else { 134369d5fd8fSJohnny Huang printf("Done\n"); 134469d5fd8fSJohnny Huang } 134569d5fd8fSJohnny Huang printf("programing configuration region ... "); 1346d90825e2SJohnny Huang ret = otp_prog_conf(conf_region); 1347*2a856b9aSJohnny Huang if (ret != 0) { 134869d5fd8fSJohnny Huang printf("Error\n"); 134969d5fd8fSJohnny Huang return ret; 135069d5fd8fSJohnny Huang } 135169d5fd8fSJohnny Huang printf("Done\n"); 1352*2a856b9aSJohnny Huang return OTP_SUCCESS; 135369d5fd8fSJohnny Huang } 1354cd1610b4SJohnny Huang 1355*2a856b9aSJohnny Huang return OTP_USAGE; 1356*2a856b9aSJohnny Huang } 1357*2a856b9aSJohnny Huang 1358*2a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 1359cd1610b4SJohnny Huang { 1360cd1610b4SJohnny Huang uint32_t ret[2]; 1361cd1610b4SJohnny Huang uint32_t strap_buf[6]; 1362d90825e2SJohnny Huang uint32_t prog_address = 0; 1363cd1610b4SJohnny Huang struct otpstrap otpstrap[64]; 1364cd1610b4SJohnny Huang int otp_bit; 1365cd1610b4SJohnny Huang int i; 1366cd1610b4SJohnny Huang int pass; 1367cd1610b4SJohnny Huang 1368cd1610b4SJohnny Huang switch (mode) { 1369a6d0d645SJohnny Huang case OTP_REGION_CONF: 1370cd1610b4SJohnny Huang otp_read_config(otp_dw_offset, ret); 1371cd1610b4SJohnny Huang prog_address = 0x800; 1372cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 1373cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 1374cd1610b4SJohnny Huang otp_bit = (ret[0] >> bit_offset) & 0x1; 1375cd1610b4SJohnny Huang if (otp_bit == value) { 1376cd1610b4SJohnny Huang printf("OTPCFG%X[%d] = %d\n", otp_dw_offset, bit_offset, value); 1377cd1610b4SJohnny Huang printf("No need to program\n"); 1378*2a856b9aSJohnny Huang return OTP_SUCCESS; 1379cd1610b4SJohnny Huang } 1380cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1381cd1610b4SJohnny Huang printf("OTPCFG%X[%d] = 1\n", otp_dw_offset, bit_offset); 1382cd1610b4SJohnny Huang printf("OTP is programed, which can't be clean\n"); 1383*2a856b9aSJohnny Huang return OTP_FAILURE; 1384cd1610b4SJohnny Huang } 1385cd1610b4SJohnny Huang printf("Program OTPCFG%X[%d] to 1\n", otp_dw_offset, bit_offset); 1386cd1610b4SJohnny Huang break; 1387a6d0d645SJohnny Huang case OTP_REGION_DATA: 1388cd1610b4SJohnny Huang prog_address = otp_dw_offset; 1389cd1610b4SJohnny Huang 1390cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 1391cd1610b4SJohnny Huang otp_read_data(otp_dw_offset, ret); 1392cd1610b4SJohnny Huang otp_bit = (ret[0] >> bit_offset) & 0x1; 1393cd1610b4SJohnny Huang } else { 1394cd1610b4SJohnny Huang otp_read_data(otp_dw_offset - 1, ret); 1395cd1610b4SJohnny Huang otp_bit = (ret[1] >> bit_offset) & 0x1; 1396cd1610b4SJohnny Huang } 1397cd1610b4SJohnny Huang if (otp_bit == value) { 1398cd1610b4SJohnny Huang printf("OTPDATA%X[%d] = %d\n", otp_dw_offset, bit_offset, value); 1399cd1610b4SJohnny Huang printf("No need to program\n"); 1400*2a856b9aSJohnny Huang return OTP_SUCCESS; 1401cd1610b4SJohnny Huang } 1402cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1403cd1610b4SJohnny Huang printf("OTPDATA%X[%d] = 1\n", otp_dw_offset, bit_offset); 1404cd1610b4SJohnny Huang printf("OTP is programed, which can't be clean\n"); 1405*2a856b9aSJohnny Huang return OTP_FAILURE; 1406cd1610b4SJohnny Huang } 1407cd1610b4SJohnny Huang printf("Program OTPDATA%X[%d] to 1\n", otp_dw_offset, bit_offset); 1408cd1610b4SJohnny Huang break; 1409a6d0d645SJohnny Huang case OTP_REGION_STRAP: 1410cd1610b4SJohnny Huang otp_strp_status(otpstrap); 1411cd1610b4SJohnny Huang otp_print_strap(bit_offset, 1); 1412cd1610b4SJohnny Huang if (bit_offset < 32) { 1413cd1610b4SJohnny Huang strap_buf[0] = value << bit_offset; 1414cd1610b4SJohnny Huang strap_buf[2] = ~BIT(bit_offset); 1415cd1610b4SJohnny Huang strap_buf[3] = ~0; 1416cd1610b4SJohnny Huang strap_buf[5] = 0; 1417*2a856b9aSJohnny Huang // if (protect) 1418*2a856b9aSJohnny Huang // strap_buf[4] = BIT(bit_offset); 1419*2a856b9aSJohnny Huang // else 1420*2a856b9aSJohnny Huang // strap_buf[4] = 0; 1421cd1610b4SJohnny Huang } else { 1422cd1610b4SJohnny Huang strap_buf[1] = value << (bit_offset - 32); 1423cd1610b4SJohnny Huang strap_buf[2] = ~0; 1424cd1610b4SJohnny Huang strap_buf[3] = ~BIT(bit_offset - 32); 1425cd1610b4SJohnny Huang strap_buf[4] = 0; 1426*2a856b9aSJohnny Huang // if (protect) 1427*2a856b9aSJohnny Huang // strap_buf[5] = BIT(bit_offset - 32); 1428*2a856b9aSJohnny Huang // else 1429*2a856b9aSJohnny Huang // strap_buf[5] = 0; 1430cd1610b4SJohnny Huang } 1431cd1610b4SJohnny Huang if (otp_strap_parse(strap_buf) < 0) 1432*2a856b9aSJohnny Huang return OTP_FAILURE; 1433cd1610b4SJohnny Huang break; 1434cd1610b4SJohnny Huang } 1435cd1610b4SJohnny Huang 1436cd1610b4SJohnny Huang if (!nconfirm) { 1437cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1438cd1610b4SJohnny Huang if (!confirm_yesno()) { 1439cd1610b4SJohnny Huang printf(" Aborting\n"); 1440*2a856b9aSJohnny Huang return OTP_FAILURE; 1441cd1610b4SJohnny Huang } 1442cd1610b4SJohnny Huang } 1443cd1610b4SJohnny Huang 1444cd1610b4SJohnny Huang switch (mode) { 1445a6d0d645SJohnny Huang case OTP_REGION_STRAP: 1446cd1610b4SJohnny Huang return otp_prog_strap(strap_buf); 1447a6d0d645SJohnny Huang case OTP_REGION_CONF: 1448a6d0d645SJohnny Huang case OTP_REGION_DATA: 1449cd1610b4SJohnny Huang otp_prog_bit(value, prog_address, bit_offset, 0); 1450cd1610b4SJohnny Huang pass = -1; 1451cd1610b4SJohnny Huang for (i = 0; i < RETRY; i++) { 1452a6d0d645SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 1453cd1610b4SJohnny Huang otp_prog_bit(value, prog_address, bit_offset, 1); 1454cd1610b4SJohnny Huang } else { 1455cd1610b4SJohnny Huang pass = 0; 1456cd1610b4SJohnny Huang break; 1457cd1610b4SJohnny Huang } 1458cd1610b4SJohnny Huang } 1459*2a856b9aSJohnny Huang if (pass == 0) 1460*2a856b9aSJohnny Huang return OTP_SUCCESS; 1461cd1610b4SJohnny Huang } 1462cd1610b4SJohnny Huang 1463*2a856b9aSJohnny Huang return OTP_USAGE; 1464cd1610b4SJohnny Huang } 1465cd1610b4SJohnny Huang 1466*2a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 146769d5fd8fSJohnny Huang { 1468*2a856b9aSJohnny Huang uint32_t offset, count; 1469*2a856b9aSJohnny Huang int ret; 147069d5fd8fSJohnny Huang 1471*2a856b9aSJohnny Huang if (argc == 4) { 1472*2a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 1473*2a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 1474*2a856b9aSJohnny Huang } else if (argc == 3) { 1475*2a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 1476*2a856b9aSJohnny Huang count = 1; 1477*2a856b9aSJohnny Huang } else { 147869d5fd8fSJohnny Huang return CMD_RET_USAGE; 147969d5fd8fSJohnny Huang } 148069d5fd8fSJohnny Huang 148169d5fd8fSJohnny Huang 1482*2a856b9aSJohnny Huang if (!strcmp(argv[1], "conf")) { 148369d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 1484*2a856b9aSJohnny Huang ret = otp_print_config(offset, count); 1485*2a856b9aSJohnny Huang } else if (!strcmp(argv[1], "data")) { 1486*2a856b9aSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 1487*2a856b9aSJohnny Huang ret = otp_print_data(offset, count); 1488*2a856b9aSJohnny Huang } else if (!strcmp(argv[1], "strap")) { 1489*2a856b9aSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 1490*2a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 1491*2a856b9aSJohnny Huang } else { 1492*2a856b9aSJohnny Huang return CMD_RET_USAGE; 149369d5fd8fSJohnny Huang } 149469d5fd8fSJohnny Huang 1495*2a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 1496*2a856b9aSJohnny Huang return CMD_RET_SUCCESS; 1497*2a856b9aSJohnny Huang else 1498*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1499*2a856b9aSJohnny Huang 1500*2a856b9aSJohnny Huang } 1501*2a856b9aSJohnny Huang 1502*2a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 1503*2a856b9aSJohnny Huang { 1504*2a856b9aSJohnny Huang phys_addr_t addr; 1505*2a856b9aSJohnny Huang uint32_t byte_size; 1506*2a856b9aSJohnny Huang int ret; 1507*2a856b9aSJohnny Huang 1508*2a856b9aSJohnny Huang if (argc == 4) { 1509*2a856b9aSJohnny Huang if (strcmp(argv[1], "f")) 1510*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1511*2a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 1512*2a856b9aSJohnny Huang byte_size = simple_strtoul(argv[3], NULL, 16); 151369d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 1514*2a856b9aSJohnny Huang ret = do_otp_prog(addr, byte_size, 1); 1515*2a856b9aSJohnny Huang } else if (argc == 3) { 1516*2a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 1517*2a856b9aSJohnny Huang byte_size = simple_strtoul(argv[2], NULL, 16); 1518*2a856b9aSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 1519*2a856b9aSJohnny Huang ret = do_otp_prog(addr, byte_size, 0); 1520*2a856b9aSJohnny Huang } else { 1521*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1522*2a856b9aSJohnny Huang } 1523*2a856b9aSJohnny Huang 1524*2a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 1525*2a856b9aSJohnny Huang return CMD_RET_SUCCESS; 1526*2a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 1527*2a856b9aSJohnny Huang return CMD_RET_FAILURE; 1528*2a856b9aSJohnny Huang else 1529*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1530*2a856b9aSJohnny Huang } 1531*2a856b9aSJohnny Huang 1532*2a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 1533*2a856b9aSJohnny Huang { 1534*2a856b9aSJohnny Huang int mode = 0; 1535*2a856b9aSJohnny Huang int nconfirm = 0; 1536*2a856b9aSJohnny Huang int otp_addr = 0; 1537*2a856b9aSJohnny Huang int bit_offset; 1538*2a856b9aSJohnny Huang int value; 1539*2a856b9aSJohnny Huang int ret; 1540*2a856b9aSJohnny Huang 1541*2a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 1542*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1543*2a856b9aSJohnny Huang 1544*2a856b9aSJohnny Huang /* Drop the pb cmd */ 1545*2a856b9aSJohnny Huang argc--; 1546*2a856b9aSJohnny Huang argv++; 1547*2a856b9aSJohnny Huang 1548*2a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 1549a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 1550*2a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 1551a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 1552*2a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 1553a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 1554cd1610b4SJohnny Huang else 1555*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1556*2a856b9aSJohnny Huang 1557*2a856b9aSJohnny Huang /* Drop the region cmd */ 1558*2a856b9aSJohnny Huang argc--; 1559*2a856b9aSJohnny Huang argv++; 1560*2a856b9aSJohnny Huang 1561*2a856b9aSJohnny Huang if (!strcmp(argv[0], "f")) { 1562cd1610b4SJohnny Huang nconfirm = 1; 1563*2a856b9aSJohnny Huang /* Drop the force option */ 1564*2a856b9aSJohnny Huang argc--; 1565*2a856b9aSJohnny Huang argv++; 1566*2a856b9aSJohnny Huang } 1567cd1610b4SJohnny Huang 1568a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 1569*2a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 1570*2a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 1571cd1610b4SJohnny Huang if (bit_offset >= 64) 1572*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1573cd1610b4SJohnny Huang } else { 1574*2a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 1575*2a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 1576*2a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 1577cd1610b4SJohnny Huang if (bit_offset >= 32) 1578*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1579cd1610b4SJohnny Huang } 1580cd1610b4SJohnny Huang if (value != 0 && value != 1) 1581*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1582cd1610b4SJohnny Huang 1583cd1610b4SJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 1584*2a856b9aSJohnny Huang ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 1585*2a856b9aSJohnny Huang 1586*2a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 1587*2a856b9aSJohnny Huang return CMD_RET_SUCCESS; 1588*2a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 1589*2a856b9aSJohnny Huang return CMD_RET_FAILURE; 1590*2a856b9aSJohnny Huang else 1591*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1592*2a856b9aSJohnny Huang } 1593*2a856b9aSJohnny Huang 1594*2a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 1595*2a856b9aSJohnny Huang { 1596*2a856b9aSJohnny Huang phys_addr_t addr; 1597*2a856b9aSJohnny Huang int otp_addr = 0; 1598*2a856b9aSJohnny Huang 1599*2a856b9aSJohnny Huang if (argc != 3) 1600*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1601*2a856b9aSJohnny Huang 160269d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 1603*2a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 1604*2a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 1605*2a856b9aSJohnny Huang if (otp_compare(otp_addr, addr) == 0) { 160669d5fd8fSJohnny Huang printf("Compare pass\n"); 1607*2a856b9aSJohnny Huang return CMD_RET_SUCCESS; 160869d5fd8fSJohnny Huang } else { 160969d5fd8fSJohnny Huang printf("Compare fail\n"); 1610*2a856b9aSJohnny Huang return CMD_RET_FAILURE; 161169d5fd8fSJohnny Huang } 161269d5fd8fSJohnny Huang } 161369d5fd8fSJohnny Huang 1614*2a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 1615*2a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 1616*2a856b9aSJohnny Huang U_BOOT_CMD_MKENT(prog, 4, 0, do_otpprog, "", ""), 1617*2a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 1618*2a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 161969d5fd8fSJohnny Huang 1620*2a856b9aSJohnny Huang }; 1621*2a856b9aSJohnny Huang 1622*2a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 1623*2a856b9aSJohnny Huang { 1624*2a856b9aSJohnny Huang cmd_tbl_t *cp; 1625*2a856b9aSJohnny Huang 1626*2a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 1627*2a856b9aSJohnny Huang 1628*2a856b9aSJohnny Huang /* Drop the mmc command */ 1629*2a856b9aSJohnny Huang argc--; 1630*2a856b9aSJohnny Huang argv++; 1631*2a856b9aSJohnny Huang 1632*2a856b9aSJohnny Huang if (cp == NULL || argc > cp->maxargs) 1633*2a856b9aSJohnny Huang return CMD_RET_USAGE; 1634*2a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 1635*2a856b9aSJohnny Huang return CMD_RET_SUCCESS; 1636*2a856b9aSJohnny Huang 1637*2a856b9aSJohnny Huang return cp->cmd(cmdtp, flag, argc, argv); 163869d5fd8fSJohnny Huang } 163969d5fd8fSJohnny Huang 164069d5fd8fSJohnny Huang U_BOOT_CMD( 164169d5fd8fSJohnny Huang otp, 7, 0, do_ast_otp, 164269d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 1643*2a856b9aSJohnny Huang "read conf|data <otp_dw_offset> <dw_count>\n" 1644*2a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 1645*2a856b9aSJohnny Huang "otp info conf|strap|data <otp_dw_offset> <dw_count>\n" 1646d90825e2SJohnny Huang "otp prog [f] <addr> <byte_size>\n" 1647cd1610b4SJohnny Huang "otp pb conf|data [f] <otp_dw_offset> <bit_offset> <value>\n" 1648cd1610b4SJohnny Huang "otp pb strap [f] <bit_offset> <value> <protect>\n" 1649*2a856b9aSJohnny Huang "otp cmp <addr> <otp_dw_offset>\n" 165069d5fd8fSJohnny Huang ); 1651