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 */ 11*4c1c9b35SJohnny 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> 18*4c1c9b35SJohnny 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 2869d5fd8fSJohnny Huang #define MODE_CONF 1 2969d5fd8fSJohnny Huang #define MODE_STRAP 2 3069d5fd8fSJohnny Huang #define MODE_DATA 3 3169d5fd8fSJohnny Huang #define MODE_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) 75*4c1c9b35SJohnny Huang 76*4c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" 77*4c1c9b35SJohnny Huang #define PBWIDTH 60 78*4c1c9b35SJohnny Huang 79*4c1c9b35SJohnny Huang void printProgress(int numerator, int denominator, char *format, ...) 80*4c1c9b35SJohnny Huang { 81*4c1c9b35SJohnny Huang int val = numerator * 100 / denominator; 82*4c1c9b35SJohnny Huang int lpad = numerator * PBWIDTH / denominator; 83*4c1c9b35SJohnny Huang int rpad = PBWIDTH - lpad; 84*4c1c9b35SJohnny Huang char buffer[256]; 85*4c1c9b35SJohnny Huang va_list aptr; 86*4c1c9b35SJohnny Huang 87*4c1c9b35SJohnny Huang va_start(aptr, format); 88*4c1c9b35SJohnny Huang vsprintf(buffer, format, aptr); 89*4c1c9b35SJohnny Huang va_end(aptr); 90*4c1c9b35SJohnny Huang 91*4c1c9b35SJohnny Huang printf("\r%3d%% [%.*s%*s] %s", val, lpad, PBSTR, rpad, "", buffer); 92*4c1c9b35SJohnny Huang if (numerator == denominator) 93*4c1c9b35SJohnny Huang printf("\n"); 94*4c1c9b35SJohnny Huang } 95*4c1c9b35SJohnny 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 204*4c1c9b35SJohnny Huang static int prog_conf_verify(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); 212*4c1c9b35SJohnny Huang // printf("prog_conf_verify = %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*4c1c9b35SJohnny Huang static uint32_t prog_data_dw_verify(uint32_t otp_addr, uint32_t *value, uint32_t *compare, int size) 220*4c1c9b35SJohnny Huang { 221*4c1c9b35SJohnny Huang uint32_t ret[2]; 222*4c1c9b35SJohnny Huang 223*4c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 224*4c1c9b35SJohnny Huang 225*4c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 226*4c1c9b35SJohnny Huang writel(otp_addr, 0x1e6f2010); //Read address 227*4c1c9b35SJohnny Huang else 228*4c1c9b35SJohnny Huang writel(otp_addr - 1, 0x1e6f2010); //Read address 229*4c1c9b35SJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 230*4c1c9b35SJohnny Huang udelay(2); 231*4c1c9b35SJohnny Huang ret[0] = readl(0x1e6f2020); 232*4c1c9b35SJohnny Huang ret[1] = readl(0x1e6f2024); 233*4c1c9b35SJohnny Huang if (size == 1) { 234*4c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 235*4c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 236*4c1c9b35SJohnny Huang if (value[0] == ret[0]) { 237*4c1c9b35SJohnny Huang compare[0] = 0; 238*4c1c9b35SJohnny Huang return 0; 239*4c1c9b35SJohnny Huang } else { 240*4c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 241*4c1c9b35SJohnny Huang return -1; 242*4c1c9b35SJohnny Huang } 243*4c1c9b35SJohnny Huang 244*4c1c9b35SJohnny Huang } else { 245*4c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 246*4c1c9b35SJohnny Huang if (value[0] == ret[1]) { 247*4c1c9b35SJohnny Huang compare[0] = ~0; 248*4c1c9b35SJohnny Huang return 0; 249*4c1c9b35SJohnny Huang } else { 250*4c1c9b35SJohnny Huang compare[0] = ~(value[0] ^ ret[0]); 251*4c1c9b35SJohnny Huang return -1; 252*4c1c9b35SJohnny Huang } 253*4c1c9b35SJohnny Huang } 254*4c1c9b35SJohnny Huang } else if (size == 2) { 255*4c1c9b35SJohnny Huang // otp_addr should be even 256*4c1c9b35SJohnny Huang if ((value[0] == ret[0]) && (value[1] == ret[1])) { 257*4c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 258*4c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 259*4c1c9b35SJohnny Huang compare[0] = 0; 260*4c1c9b35SJohnny Huang compare[1] = ~0; 261*4c1c9b35SJohnny Huang return 0; 262*4c1c9b35SJohnny Huang } else { 263*4c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 264*4c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 265*4c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 266*4c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 267*4c1c9b35SJohnny Huang return -1; 268*4c1c9b35SJohnny Huang } 269*4c1c9b35SJohnny Huang } else { 270*4c1c9b35SJohnny Huang return -1; 271*4c1c9b35SJohnny Huang } 272*4c1c9b35SJohnny Huang } 273*4c1c9b35SJohnny Huang 27469d5fd8fSJohnny Huang static int otp_conf_parse(uint32_t *OTPCFG) 27569d5fd8fSJohnny Huang { 276*4c1c9b35SJohnny Huang int tmp, i; 277*4c1c9b35SJohnny Huang int pass = 0; 27869d5fd8fSJohnny Huang 27969d5fd8fSJohnny Huang printf("OTPCFG0-D[0]\n"); 280e1f9e54eSJohnny Huang if (OTPCFG[0] & DISABLE_SECREG_PROG) 28169d5fd8fSJohnny Huang printf(" Disable Secure Region programming\n"); 28269d5fd8fSJohnny Huang else 28369d5fd8fSJohnny Huang printf(" Enable Secure Region programming\n"); 28469d5fd8fSJohnny Huang printf("OTPCFG0-D[1]\n"); 285e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SEC_BOOT) 28669d5fd8fSJohnny Huang printf(" Enable Secure Boot\n"); 28769d5fd8fSJohnny Huang else 28869d5fd8fSJohnny Huang printf(" Disable Secure Boot\n"); 28969d5fd8fSJohnny Huang printf("OTPCFG0-D[3]\n"); 290e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_USERREG_ECC) 29169d5fd8fSJohnny Huang printf(" User region ECC enable\n"); 29269d5fd8fSJohnny Huang else 29369d5fd8fSJohnny Huang printf(" User region ECC disable\n"); 29469d5fd8fSJohnny Huang printf("OTPCFG0-D[4]\n"); 295e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SECREG_ECC) 29669d5fd8fSJohnny Huang printf(" Secure Region ECC enable\n"); 29769d5fd8fSJohnny Huang else 29869d5fd8fSJohnny Huang printf(" Secure Region ECC disable\n"); 29969d5fd8fSJohnny Huang printf("OTPCFG0-D[5]\n"); 300e1f9e54eSJohnny Huang if (OTPCFG[0] & DISABLE_LOW_SEC_KEY) 30169d5fd8fSJohnny Huang printf(" Disable low security key\n"); 30269d5fd8fSJohnny Huang else 30369d5fd8fSJohnny Huang printf(" Enable low security key\n"); 30469d5fd8fSJohnny Huang printf("OTPCFG0-D[6]\n"); 305e1f9e54eSJohnny Huang if (OTPCFG[0] & IGNORE_SEC_BOOT_HWSTRAP) 30669d5fd8fSJohnny Huang printf(" Ignore Secure Boot hardware strap\n"); 30769d5fd8fSJohnny Huang else 30869d5fd8fSJohnny Huang printf(" Do not ignore Secure Boot hardware strap\n"); 30969d5fd8fSJohnny Huang printf("OTPCFG0-D[7]\n"); 310e1f9e54eSJohnny Huang if (SEC_BOOT_MDOES(OTPCFG[0]) == SEC_MODE1) 311e1f9e54eSJohnny Huang printf(" Secure Boot Mode: 1\n"); 312e1f9e54eSJohnny Huang else 313e1f9e54eSJohnny Huang printf(" Secure Boot Mode: 2\n"); 31469d5fd8fSJohnny Huang printf("OTPCFG0-D[9:8]\n"); 31569d5fd8fSJohnny Huang printf(" OTP bit cell mode : "); 316e1f9e54eSJohnny Huang tmp = OTP_BIT_CELL_MODES(OTPCFG[0]); 317e1f9e54eSJohnny Huang if (tmp == SINGLE_CELL_MODE) { 31869d5fd8fSJohnny Huang printf("Single cell mode (recommended)\n"); 319e1f9e54eSJohnny Huang } else if (tmp == DIFFERENTIAL_MODE) { 32069d5fd8fSJohnny Huang printf("Differnetial mode\n"); 321e1f9e54eSJohnny Huang } else if (tmp == DIFFERENTIAL_REDUDANT_MODE) { 32269d5fd8fSJohnny Huang printf("Differential-redundant mode\n"); 32369d5fd8fSJohnny Huang } else { 32469d5fd8fSJohnny Huang printf("Value error\n"); 32569d5fd8fSJohnny Huang return -1; 32669d5fd8fSJohnny Huang } 32769d5fd8fSJohnny Huang printf("OTPCFG0-D[11:10]\n"); 32869d5fd8fSJohnny Huang printf(" RSA mode : "); 329e1f9e54eSJohnny Huang tmp = CRYPTO_MODES(OTPCFG[0]); 330e1f9e54eSJohnny Huang if (tmp == CRYPTO_RSA1024) { 33169d5fd8fSJohnny Huang printf("RSA1024\n"); 332e1f9e54eSJohnny Huang } else if (tmp == CRYPTO_RSA2048) { 33369d5fd8fSJohnny Huang printf("RSA2048\n"); 334e1f9e54eSJohnny Huang } else if (tmp == CRYPTO_RSA3072) { 33569d5fd8fSJohnny Huang printf("RSA3072\n"); 33669d5fd8fSJohnny Huang } else { 33769d5fd8fSJohnny Huang printf("RSA4096\n"); 33869d5fd8fSJohnny Huang } 33969d5fd8fSJohnny Huang printf("OTPCFG0-D[13:12]\n"); 34069d5fd8fSJohnny Huang printf(" SHA mode : "); 341e1f9e54eSJohnny Huang tmp = HASH_MODES(OTPCFG[0]); 342e1f9e54eSJohnny Huang if (tmp == HASH_SAH224) { 34369d5fd8fSJohnny Huang printf("SHA224\n"); 344e1f9e54eSJohnny Huang } else if (tmp == HASH_SAH256) { 34569d5fd8fSJohnny Huang printf("SHA256\n"); 346e1f9e54eSJohnny Huang } else if (tmp == HASH_SAH384) { 34769d5fd8fSJohnny Huang printf("SHA384\n"); 34869d5fd8fSJohnny Huang } else { 34969d5fd8fSJohnny Huang printf("SHA512\n"); 35069d5fd8fSJohnny Huang } 35169d5fd8fSJohnny Huang 35269d5fd8fSJohnny Huang printf("OTPCFG0-D[21:16]\n"); 353e1f9e54eSJohnny Huang printf(" Secure Region size (DW): %x\n", SECREG_SIZE(OTPCFG[0])); 35469d5fd8fSJohnny Huang 35569d5fd8fSJohnny Huang printf("OTPCFG0-D[22]\n"); 356e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_SECREG) 35769d5fd8fSJohnny Huang printf(" Secure Region : Write Protect\n"); 35869d5fd8fSJohnny Huang else 35969d5fd8fSJohnny Huang printf(" Secure Region : Writable\n"); 36069d5fd8fSJohnny Huang printf("OTPCFG0-D[23]\n"); 361e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_USERREG) 36269d5fd8fSJohnny Huang printf(" User Region : Write Protect\n"); 36369d5fd8fSJohnny Huang else 36469d5fd8fSJohnny Huang printf(" User Region : Writable\n"); 36569d5fd8fSJohnny Huang printf("OTPCFG0-D[24]\n"); 366e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_CONFREG) 36769d5fd8fSJohnny Huang printf(" Configure Region : Write Protect\n"); 36869d5fd8fSJohnny Huang else 36969d5fd8fSJohnny Huang printf(" Configure Region : Writable\n"); 37069d5fd8fSJohnny Huang printf("OTPCFG0-D[25]\n"); 371e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_STRAPREG) 37269d5fd8fSJohnny Huang printf(" OTP strap Region : Write Protect\n"); 37369d5fd8fSJohnny Huang else 37469d5fd8fSJohnny Huang printf(" OTP strap Region : Writable\n"); 37569d5fd8fSJohnny Huang printf("OTPCFG0-D[26]\n"); 376e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_COPY_TO_SRAM) 37769d5fd8fSJohnny Huang printf(" Copy Boot Image to Internal SRAM\n"); 37869d5fd8fSJohnny Huang else 37969d5fd8fSJohnny Huang printf(" Disable Copy Boot Image to Internal SRAM\n"); 38069d5fd8fSJohnny Huang printf("OTPCFG0-D[27]\n"); 381e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_IMAGE_ENC) 38269d5fd8fSJohnny Huang printf(" Enable image encryption\n"); 38369d5fd8fSJohnny Huang else 38469d5fd8fSJohnny Huang printf(" Disable image encryption\n"); 38569d5fd8fSJohnny Huang printf("OTPCFG0-D[29]\n"); 386e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_KEY_RETIRE) 38769d5fd8fSJohnny Huang printf(" OTP key retire Region : Write Protect\n"); 38869d5fd8fSJohnny Huang else 38969d5fd8fSJohnny Huang printf(" OTP key retire Region : Writable\n"); 39069d5fd8fSJohnny Huang printf("OTPCFG0-D[30]\n"); 391e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SIPROM_RED) 39269d5fd8fSJohnny Huang printf(" SIPROM RED_EN redundancy repair enable\n"); 39369d5fd8fSJohnny Huang else 39469d5fd8fSJohnny Huang printf(" SIPROM RED_EN redundancy repair disable\n"); 39569d5fd8fSJohnny Huang printf("OTPCFG0-D[31]\n"); 396e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SIPROM_MLOCK) 39769d5fd8fSJohnny Huang printf(" SIPROM Mlock memory lock enable\n"); 39869d5fd8fSJohnny Huang else 39969d5fd8fSJohnny Huang printf(" SIPROM Mlock memory lock disable\n"); 40069d5fd8fSJohnny Huang 40169d5fd8fSJohnny Huang printf("OTPCFG2-D[15:0]\n"); 402e1f9e54eSJohnny Huang printf(" Vender ID : %x\n", VENDER_ID(OTPCFG[2])); 40369d5fd8fSJohnny Huang 40469d5fd8fSJohnny Huang printf("OTPCFG2-D[31:16]\n"); 405e1f9e54eSJohnny Huang printf(" Key Revision : %x\n", KEY_REVISION(OTPCFG[2])); 40669d5fd8fSJohnny Huang 40769d5fd8fSJohnny Huang printf("OTPCFG3-D[15:0]\n"); 408e1f9e54eSJohnny Huang printf(" Secure boot header offset : %x\n", 409e1f9e54eSJohnny Huang SEC_BOOT_HEADER_OFFSET(OTPCFG[3])); 41069d5fd8fSJohnny Huang 41169d5fd8fSJohnny Huang printf("OTPCFG4-D[7:0]\n"); 412e1f9e54eSJohnny Huang tmp = KEYS_VALID_BITS(OTPCFG[4]); 413e1f9e54eSJohnny Huang if (tmp != 0) { 41469d5fd8fSJohnny Huang for (i = 0; i < 7; i++) { 41569d5fd8fSJohnny Huang if (tmp == (1 << i)) { 416e1f9e54eSJohnny Huang pass = i + 1; 41769d5fd8fSJohnny Huang } 41869d5fd8fSJohnny Huang } 419e1f9e54eSJohnny Huang } else { 420e1f9e54eSJohnny Huang pass = 0; 421e1f9e54eSJohnny Huang } 422e1f9e54eSJohnny Huang printf(" Keys valid : %d\n", pass); 42369d5fd8fSJohnny Huang 42469d5fd8fSJohnny Huang printf("OTPCFG4-D[23:16]\n"); 425e1f9e54eSJohnny Huang tmp = KEYS_RETIRE_BITS(OTPCFG[4]); 426e1f9e54eSJohnny Huang if (tmp != 0) { 42769d5fd8fSJohnny Huang for (i = 0; i < 7; i++) { 42869d5fd8fSJohnny Huang if (tmp == (1 << i)) { 429e1f9e54eSJohnny Huang pass = i + 1; 43069d5fd8fSJohnny Huang } 43169d5fd8fSJohnny Huang } 432e1f9e54eSJohnny Huang } else { 433e1f9e54eSJohnny Huang pass = 0; 43469d5fd8fSJohnny Huang } 43569d5fd8fSJohnny Huang printf(" Keys Retire ID : %d\n", pass); 43669d5fd8fSJohnny Huang 43769d5fd8fSJohnny Huang printf("OTPCFG5-D[31:0]\n"); 43869d5fd8fSJohnny Huang printf(" User define data, random number low : %x\n", OTPCFG[5]); 43969d5fd8fSJohnny Huang 44069d5fd8fSJohnny Huang printf("OTPCFG6-D[31:0]\n"); 44169d5fd8fSJohnny Huang printf(" User define data, random number high : %x\n", OTPCFG[6]); 44269d5fd8fSJohnny Huang 44369d5fd8fSJohnny Huang printf("OTPCFG8-D[31:0]\n"); 44469d5fd8fSJohnny Huang printf(" Redundancy Repair : %x\n", OTPCFG[8]); 44569d5fd8fSJohnny Huang 44669d5fd8fSJohnny Huang printf("OTPCFG10-D[31:0]\n"); 44769d5fd8fSJohnny Huang printf(" Manifest ID low : %x\n", OTPCFG[10]); 44869d5fd8fSJohnny Huang 44969d5fd8fSJohnny Huang printf("OTPCFG11-D[31:0]\n"); 45069d5fd8fSJohnny Huang printf(" Manifest ID high : %x\n", OTPCFG[11]); 45169d5fd8fSJohnny Huang return 0; 45269d5fd8fSJohnny Huang 45369d5fd8fSJohnny Huang } 45469d5fd8fSJohnny Huang 45569d5fd8fSJohnny Huang static void buf_print(char *buf, int len) 45669d5fd8fSJohnny Huang { 45769d5fd8fSJohnny Huang int i; 45869d5fd8fSJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 45969d5fd8fSJohnny Huang for (i = 0; i < len; i++) { 46069d5fd8fSJohnny Huang if (i % 16 == 0) { 46169d5fd8fSJohnny Huang printf("%04X: ", i); 46269d5fd8fSJohnny Huang } 46369d5fd8fSJohnny Huang printf("%02X ", buf[i]); 46469d5fd8fSJohnny Huang if ((i + 1) % 16 == 0) { 46569d5fd8fSJohnny Huang printf("\n"); 46669d5fd8fSJohnny Huang } 46769d5fd8fSJohnny Huang } 46869d5fd8fSJohnny Huang } 46969d5fd8fSJohnny Huang 47069d5fd8fSJohnny Huang static int otp_data_parse(uint32_t *buf, int dw_count) 47169d5fd8fSJohnny Huang { 47269d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 47369d5fd8fSJohnny Huang char *byte_buf; 47469d5fd8fSJohnny Huang int i = 0, len = 0; 47569d5fd8fSJohnny Huang byte_buf = (char *)buf; 47669d5fd8fSJohnny Huang while (1) { 47769d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 47869d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 47969d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 48069d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 48169d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 48269d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 48369d5fd8fSJohnny Huang printf("Key[%d]:\n", i); 48469d5fd8fSJohnny Huang printf("Key Type: "); 48569d5fd8fSJohnny Huang switch (key_type) { 48669d5fd8fSJohnny Huang case 0: 48769d5fd8fSJohnny Huang printf("AES-256 as OEM platform key for image encryption/decryption\n"); 48869d5fd8fSJohnny Huang break; 48969d5fd8fSJohnny Huang case 1: 49069d5fd8fSJohnny Huang printf("AES-256 as secret vault key\n"); 49169d5fd8fSJohnny Huang break; 49269d5fd8fSJohnny Huang case 4: 49369d5fd8fSJohnny Huang printf("HMAC as encrypted OEM HMAC keys in Mode 1\n"); 49469d5fd8fSJohnny Huang break; 49569d5fd8fSJohnny Huang case 8: 49669d5fd8fSJohnny Huang printf("RSA-public as OEM DSS public keys in Mode 2\n"); 49769d5fd8fSJohnny Huang break; 49869d5fd8fSJohnny Huang case 9: 49969d5fd8fSJohnny Huang printf("RSA-public as SOC public key\n"); 50069d5fd8fSJohnny Huang break; 50169d5fd8fSJohnny Huang case 10: 50269d5fd8fSJohnny Huang printf("RSA-public as AES key decryption key\n"); 50369d5fd8fSJohnny Huang break; 50469d5fd8fSJohnny Huang case 13: 50569d5fd8fSJohnny Huang printf("RSA-private as SOC private key\n"); 50669d5fd8fSJohnny Huang break; 50769d5fd8fSJohnny Huang case 14: 50869d5fd8fSJohnny Huang printf("RSA-private as AES key decryption key\n"); 50969d5fd8fSJohnny Huang break; 51069d5fd8fSJohnny Huang default: 51169d5fd8fSJohnny Huang printf("key_type error: %x\n", key_type); 51269d5fd8fSJohnny Huang return -1; 51369d5fd8fSJohnny Huang } 51469d5fd8fSJohnny Huang if (key_type == 4) { 51569d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 51669d5fd8fSJohnny Huang switch (key_length) { 51769d5fd8fSJohnny Huang case 0: 51869d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 51969d5fd8fSJohnny Huang break; 52069d5fd8fSJohnny Huang case 1: 52169d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 52269d5fd8fSJohnny Huang break; 52369d5fd8fSJohnny Huang case 2: 52469d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 52569d5fd8fSJohnny Huang break; 52669d5fd8fSJohnny Huang case 3: 52769d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 52869d5fd8fSJohnny Huang break; 52969d5fd8fSJohnny Huang } 53069d5fd8fSJohnny Huang } else if (key_type != 0 || key_type != 1) { 53169d5fd8fSJohnny Huang printf("RSA SHA Type: "); 53269d5fd8fSJohnny Huang switch (key_length) { 53369d5fd8fSJohnny Huang case 0: 53469d5fd8fSJohnny Huang printf("RSA1024\n"); 53569d5fd8fSJohnny Huang len = 0x100; 53669d5fd8fSJohnny Huang break; 53769d5fd8fSJohnny Huang case 1: 53869d5fd8fSJohnny Huang printf("RSA2048\n"); 53969d5fd8fSJohnny Huang len = 0x200; 54069d5fd8fSJohnny Huang break; 54169d5fd8fSJohnny Huang case 2: 54269d5fd8fSJohnny Huang printf("RSA3072\n"); 54369d5fd8fSJohnny Huang len = 0x300; 54469d5fd8fSJohnny Huang break; 54569d5fd8fSJohnny Huang case 3: 54669d5fd8fSJohnny Huang printf("RSA4096\n"); 54769d5fd8fSJohnny Huang len = 0x400; 54869d5fd8fSJohnny Huang break; 54969d5fd8fSJohnny Huang } 55069d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 55169d5fd8fSJohnny Huang } 55269d5fd8fSJohnny Huang if (key_type == 4 || key_type == 8) 55369d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 55469d5fd8fSJohnny Huang printf("Key Value:\n"); 55569d5fd8fSJohnny Huang if (key_type == 4) { 55669d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 55769d5fd8fSJohnny Huang } else if (key_type == 0 || key_type == 1) { 55869d5fd8fSJohnny Huang printf("AES Key:\n"); 55969d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 56069d5fd8fSJohnny Huang printf("AES IV:\n"); 56169d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 56269d5fd8fSJohnny Huang 56369d5fd8fSJohnny Huang } else { 56469d5fd8fSJohnny Huang printf("RSA mod:\n"); 56569d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 56669d5fd8fSJohnny Huang printf("RSA exp:\n"); 56769d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 56869d5fd8fSJohnny Huang } 56969d5fd8fSJohnny Huang if (last) 57069d5fd8fSJohnny Huang break; 57169d5fd8fSJohnny Huang i++; 57269d5fd8fSJohnny Huang } 57369d5fd8fSJohnny Huang return 0; 57469d5fd8fSJohnny Huang } 57569d5fd8fSJohnny Huang 57669d5fd8fSJohnny Huang static int otp_prog_conf(uint32_t *buf, int otp_addr, int dw_count) 57769d5fd8fSJohnny Huang { 57869d5fd8fSJohnny Huang int i, j, k, bit_value; 57969d5fd8fSJohnny Huang int pass, soak; 58069d5fd8fSJohnny Huang uint32_t prog_bit, prog_address; 58169d5fd8fSJohnny Huang 58269d5fd8fSJohnny Huang for (i = 0; i < dw_count; i++) { 583*4c1c9b35SJohnny Huang printProgress(i + 1, dw_count, ""); 58469d5fd8fSJohnny Huang prog_address = 0x800; 58569d5fd8fSJohnny Huang prog_address |= ((i + otp_addr) / 8) * 0x200; 58669d5fd8fSJohnny Huang prog_address |= ((i + otp_addr) % 8) * 0x2; 58769d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 58869d5fd8fSJohnny Huang bit_value = (buf[i] >> j) & 0x1; 58969d5fd8fSJohnny Huang if (bit_value) 59069d5fd8fSJohnny Huang prog_bit = ~(0x1 << j); 59169d5fd8fSJohnny Huang else 59269d5fd8fSJohnny Huang continue; 59369d5fd8fSJohnny Huang pass = 0; 59469d5fd8fSJohnny Huang soak = 0; 5954b65a65dSJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 5964b65a65dSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 5974b65a65dSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 5984b65a65dSJohnny Huang writel(0x04190760, 0x1e602008); //normal program 59969d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 60069d5fd8fSJohnny Huang if (!soak) { 60169d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 602*4c1c9b35SJohnny Huang if (prog_conf_verify(prog_address, j, bit_value) == 0) { 60369d5fd8fSJohnny Huang pass = 1; 60469d5fd8fSJohnny Huang break; 60569d5fd8fSJohnny Huang } 60669d5fd8fSJohnny Huang soak = 1; 6074b65a65dSJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 6084b65a65dSJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 6094b65a65dSJohnny Huang otp_write(0x1000, 0x4820); // Write MR 61069d5fd8fSJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 6114b65a65dSJohnny Huang } 61269d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 613*4c1c9b35SJohnny Huang if (prog_conf_verify(prog_address, j, bit_value) == 0) { 61469d5fd8fSJohnny Huang pass = 1; 61569d5fd8fSJohnny Huang break; 61669d5fd8fSJohnny Huang } 61769d5fd8fSJohnny Huang } 61869d5fd8fSJohnny Huang if (!pass) 61969d5fd8fSJohnny Huang return -1; 62069d5fd8fSJohnny Huang } 62169d5fd8fSJohnny Huang } 62269d5fd8fSJohnny Huang return 0; 62369d5fd8fSJohnny Huang } 62469d5fd8fSJohnny Huang 62569d5fd8fSJohnny Huang static void otp_strp_status(struct otpstrap *otpstrap) 62669d5fd8fSJohnny Huang { 62769d5fd8fSJohnny Huang uint32_t OTPSTRAP_RAW[2]; 62869d5fd8fSJohnny Huang int i, j; 62969d5fd8fSJohnny Huang 63069d5fd8fSJohnny Huang for (j = 0; j < 64; j++) { 63169d5fd8fSJohnny Huang otpstrap[j].value = 0; 63269d5fd8fSJohnny Huang otpstrap[j].remain_times = 7; 63369d5fd8fSJohnny Huang otpstrap[j].writeable_option = -1; 63469d5fd8fSJohnny Huang otpstrap[j].protected = 0; 63569d5fd8fSJohnny Huang } 63669d5fd8fSJohnny Huang 63769d5fd8fSJohnny Huang for (i = 16; i < 30; i += 2) { 63869d5fd8fSJohnny Huang int option = (i - 16) / 2; 63969d5fd8fSJohnny Huang otp_read_config(i, &OTPSTRAP_RAW[0]); 64069d5fd8fSJohnny Huang otp_read_config(i + 1, &OTPSTRAP_RAW[1]); 64169d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 64269d5fd8fSJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 64369d5fd8fSJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 64469d5fd8fSJohnny Huang otpstrap[j].writeable_option = option; 64569d5fd8fSJohnny Huang } 64669d5fd8fSJohnny Huang if (bit_value == 1) 64769d5fd8fSJohnny Huang otpstrap[j].remain_times --; 64869d5fd8fSJohnny Huang otpstrap[j].value ^= bit_value; 64969d5fd8fSJohnny Huang otpstrap[j].option_array[option] = bit_value; 65069d5fd8fSJohnny Huang } 65169d5fd8fSJohnny Huang for (j = 32; j < 64; j++) { 65269d5fd8fSJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 65369d5fd8fSJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 65469d5fd8fSJohnny Huang otpstrap[j].writeable_option = option; 65569d5fd8fSJohnny Huang } 65669d5fd8fSJohnny Huang if (bit_value == 1) 65769d5fd8fSJohnny Huang otpstrap[j].remain_times --; 65869d5fd8fSJohnny Huang otpstrap[j].value ^= bit_value; 65969d5fd8fSJohnny Huang otpstrap[j].option_array[option] = bit_value; 66069d5fd8fSJohnny Huang } 66169d5fd8fSJohnny Huang } 66269d5fd8fSJohnny Huang otp_read_config(30, &OTPSTRAP_RAW[0]); 66369d5fd8fSJohnny Huang otp_read_config(31, &OTPSTRAP_RAW[1]); 66469d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 66569d5fd8fSJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 66669d5fd8fSJohnny Huang otpstrap[j].protected = 1; 66769d5fd8fSJohnny Huang } 66869d5fd8fSJohnny Huang for (j = 32; j < 64; j++) { 66969d5fd8fSJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 67069d5fd8fSJohnny Huang otpstrap[j].protected = 1; 67169d5fd8fSJohnny Huang } 67269d5fd8fSJohnny Huang } 67369d5fd8fSJohnny Huang 67469d5fd8fSJohnny Huang static int otp_strap_parse(uint32_t *buf) 67569d5fd8fSJohnny Huang { 67669d5fd8fSJohnny Huang int i; 67769d5fd8fSJohnny Huang uint32_t *strap_keep = buf + 2; 67869d5fd8fSJohnny Huang uint32_t *strap_protect = buf + 4; 67969d5fd8fSJohnny Huang int bit, pbit, kbit; 68069d5fd8fSJohnny Huang int fail = 0; 68169d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 68269d5fd8fSJohnny Huang 68369d5fd8fSJohnny Huang otp_strp_status(otpstrap); 68469d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 68569d5fd8fSJohnny Huang if (i < 32) { 68669d5fd8fSJohnny Huang bit = (buf[0] >> i) & 0x1; 68769d5fd8fSJohnny Huang kbit = (strap_keep[0] >> i) & 0x1; 68869d5fd8fSJohnny Huang pbit = (strap_protect[0] >> i) & 0x1; 68969d5fd8fSJohnny Huang } else { 69069d5fd8fSJohnny Huang bit = (buf[1] >> (i - 32)) & 0x1; 69169d5fd8fSJohnny Huang kbit = (strap_keep[1] >> (i - 32)) & 0x1; 69269d5fd8fSJohnny Huang pbit = (strap_protect[1] >> (i - 32)) & 0x1; 69369d5fd8fSJohnny Huang } 69469d5fd8fSJohnny Huang 69569d5fd8fSJohnny Huang if (kbit == 1) { 69669d5fd8fSJohnny Huang continue; 69769d5fd8fSJohnny Huang } else { 69869d5fd8fSJohnny Huang printf("OTPSTRAP[%d]:\n", i); 69969d5fd8fSJohnny Huang } 70069d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 70169d5fd8fSJohnny Huang printf(" The value is same as before, skip it.\n"); 70269d5fd8fSJohnny Huang continue; 70369d5fd8fSJohnny Huang } 70469d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 70569d5fd8fSJohnny Huang printf(" This bit is protected and is not writable\n"); 70669d5fd8fSJohnny Huang fail = 1; 70769d5fd8fSJohnny Huang continue; 70869d5fd8fSJohnny Huang } 70969d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 71069d5fd8fSJohnny Huang printf(" This bit is no remaining number of times to write.\n"); 71169d5fd8fSJohnny Huang fail = 1; 71269d5fd8fSJohnny Huang continue; 71369d5fd8fSJohnny Huang } 71469d5fd8fSJohnny Huang if (pbit == 1) { 71569d5fd8fSJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 71669d5fd8fSJohnny Huang } 71769d5fd8fSJohnny Huang printf(" Write 1 to OTPSTRAP[%d] OPTION[%d], that value becomes frome %d to %d.\n", i, otpstrap[i].writeable_option + 1, otpstrap[i].value, otpstrap[i].value ^ 1); 71869d5fd8fSJohnny Huang } 71969d5fd8fSJohnny Huang if (fail == 1) 72069d5fd8fSJohnny Huang return -1; 72169d5fd8fSJohnny Huang else 72269d5fd8fSJohnny Huang return 0; 72369d5fd8fSJohnny Huang } 72469d5fd8fSJohnny Huang 72569d5fd8fSJohnny Huang static void otp_print_strap(void) 72669d5fd8fSJohnny Huang { 72769d5fd8fSJohnny Huang int i, j; 72869d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 72969d5fd8fSJohnny Huang 73069d5fd8fSJohnny Huang otp_strp_status(otpstrap); 73169d5fd8fSJohnny Huang 73269d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 73369d5fd8fSJohnny Huang printf("OTPSTRAP[%d]:\n", i); 73469d5fd8fSJohnny Huang printf(" OTP Option value: "); 73569d5fd8fSJohnny Huang for (j = 1; j <= 7; j++) 73669d5fd8fSJohnny Huang printf("[%d]:%d ", j, otpstrap[i].option_array[j - 1]); 73769d5fd8fSJohnny Huang printf("\n"); 73869d5fd8fSJohnny Huang printf(" OTP Value: %d\n", otpstrap[i].value); 73969d5fd8fSJohnny Huang printf(" Status:\n"); 74069d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 74169d5fd8fSJohnny Huang printf(" OTPSTRAP[%d] is protected and is not writable\n", i); 74269d5fd8fSJohnny Huang } else { 74369d5fd8fSJohnny Huang printf(" OTPSTRAP[%d] is not protected ", i); 74469d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 74569d5fd8fSJohnny Huang printf("and no remaining number of times to write.\n"); 74669d5fd8fSJohnny Huang } else { 74769d5fd8fSJohnny Huang printf("and still can write %d number of times\n", otpstrap[i].remain_times); 74869d5fd8fSJohnny Huang } 74969d5fd8fSJohnny Huang } 75069d5fd8fSJohnny Huang } 75169d5fd8fSJohnny Huang } 75269d5fd8fSJohnny Huang 75369d5fd8fSJohnny Huang static int otp_prog_strap(uint32_t *buf) 75469d5fd8fSJohnny Huang { 75569d5fd8fSJohnny Huang int i, j; 75669d5fd8fSJohnny Huang uint32_t *strap_keep = buf + 2; 75769d5fd8fSJohnny Huang uint32_t *strap_protect = buf + 4; 75869d5fd8fSJohnny Huang uint32_t prog_bit, prog_address; 75969d5fd8fSJohnny Huang int bit, pbit, kbit, offset; 76069d5fd8fSJohnny Huang int fail = 0; 76169d5fd8fSJohnny Huang int pass, soak; 76269d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 76369d5fd8fSJohnny Huang 76469d5fd8fSJohnny Huang otp_strp_status(otpstrap); 76569d5fd8fSJohnny Huang 76669d5fd8fSJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 76769d5fd8fSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 76869d5fd8fSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 76969d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 770*4c1c9b35SJohnny Huang printProgress(i + 1, 64, ""); 77169d5fd8fSJohnny Huang prog_address = 0x800; 77269d5fd8fSJohnny Huang if (i < 32) { 77369d5fd8fSJohnny Huang offset = i; 77469d5fd8fSJohnny Huang bit = (buf[0] >> offset) & 0x1; 77569d5fd8fSJohnny Huang kbit = (strap_keep[0] >> offset) & 0x1; 77669d5fd8fSJohnny Huang pbit = (strap_protect[0] >> offset) & 0x1; 77769d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 77869d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 77969d5fd8fSJohnny Huang 78069d5fd8fSJohnny Huang } else { 78169d5fd8fSJohnny Huang offset = (i - 32); 78269d5fd8fSJohnny Huang bit = (buf[1] >> offset) & 0x1; 78369d5fd8fSJohnny Huang kbit = (strap_keep[1] >> offset) & 0x1; 78469d5fd8fSJohnny Huang pbit = (strap_protect[1] >> offset) & 0x1; 78569d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 78669d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 78769d5fd8fSJohnny Huang } 78869d5fd8fSJohnny Huang prog_bit = ~(0x1 << offset); 78969d5fd8fSJohnny Huang 79069d5fd8fSJohnny Huang if (kbit == 1) { 79169d5fd8fSJohnny Huang continue; 79269d5fd8fSJohnny Huang } 79369d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 79469d5fd8fSJohnny Huang continue; 79569d5fd8fSJohnny Huang } 79669d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 79769d5fd8fSJohnny Huang fail = 1; 79869d5fd8fSJohnny Huang continue; 79969d5fd8fSJohnny Huang } 80069d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 80169d5fd8fSJohnny Huang fail = 1; 80269d5fd8fSJohnny Huang continue; 80369d5fd8fSJohnny Huang } 80469d5fd8fSJohnny Huang pass = 0; 80569d5fd8fSJohnny Huang soak = 0; 8064b65a65dSJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 8074b65a65dSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 8084b65a65dSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 8094b65a65dSJohnny Huang writel(0x04190760, 0x1e602008); //normal program 81069d5fd8fSJohnny Huang for (j = 0; j < RETRY; j++) { 81169d5fd8fSJohnny Huang if (!soak) { 81269d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 813*4c1c9b35SJohnny Huang if (prog_conf_verify(prog_address, offset, 1) == 0) { 81469d5fd8fSJohnny Huang pass = 1; 81569d5fd8fSJohnny Huang break; 81669d5fd8fSJohnny Huang } 81769d5fd8fSJohnny Huang soak = 1; 8184b65a65dSJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 8194b65a65dSJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 8204b65a65dSJohnny Huang otp_write(0x1000, 0x4820); // Write MR 82169d5fd8fSJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 8224b65a65dSJohnny Huang } 82369d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 824*4c1c9b35SJohnny Huang if (prog_conf_verify(prog_address, offset, 1) == 0) { 82569d5fd8fSJohnny Huang pass = 1; 82669d5fd8fSJohnny Huang break; 82769d5fd8fSJohnny Huang } 82869d5fd8fSJohnny Huang } 82969d5fd8fSJohnny Huang if (!pass) 83069d5fd8fSJohnny Huang return -1; 83169d5fd8fSJohnny Huang 83269d5fd8fSJohnny Huang if (pbit == 0) 83369d5fd8fSJohnny Huang continue; 83469d5fd8fSJohnny Huang prog_address = 0x800; 83569d5fd8fSJohnny Huang if (i < 32) 83669d5fd8fSJohnny Huang prog_address |= 0x60c; 83769d5fd8fSJohnny Huang else 83869d5fd8fSJohnny Huang prog_address |= 0x60e; 83969d5fd8fSJohnny Huang 84069d5fd8fSJohnny Huang for (j = 0; j < RETRY; j++) { 84169d5fd8fSJohnny Huang if (!soak) { 84269d5fd8fSJohnny Huang writel(0x04190760, 0x1e602008); //normal program 84369d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 844*4c1c9b35SJohnny Huang if (prog_conf_verify(prog_address, offset, 1) == 0) { 84569d5fd8fSJohnny Huang pass = 1; 84669d5fd8fSJohnny Huang break; 84769d5fd8fSJohnny Huang } 84869d5fd8fSJohnny Huang soak = 1; 84969d5fd8fSJohnny Huang } 85069d5fd8fSJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 85169d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 852*4c1c9b35SJohnny Huang if (prog_conf_verify(prog_address, offset, 1) == 0) { 85369d5fd8fSJohnny Huang pass = 1; 85469d5fd8fSJohnny Huang break; 85569d5fd8fSJohnny Huang } 85669d5fd8fSJohnny Huang } 85769d5fd8fSJohnny Huang if (!pass) 85869d5fd8fSJohnny Huang return -1; 85969d5fd8fSJohnny Huang 86069d5fd8fSJohnny Huang } 86169d5fd8fSJohnny Huang if (fail == 1) 86269d5fd8fSJohnny Huang return -1; 86369d5fd8fSJohnny Huang else 86469d5fd8fSJohnny Huang return 0; 86569d5fd8fSJohnny Huang 86669d5fd8fSJohnny Huang } 86769d5fd8fSJohnny Huang 868*4c1c9b35SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t prog_address, int soak) 86969d5fd8fSJohnny Huang { 870*4c1c9b35SJohnny Huang int j, bit_value, prog_bit; 87169d5fd8fSJohnny Huang 872*4c1c9b35SJohnny Huang if (soak) { 873*4c1c9b35SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 874*4c1c9b35SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 875*4c1c9b35SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 876*4c1c9b35SJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 877*4c1c9b35SJohnny Huang } else { 878*4c1c9b35SJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 879*4c1c9b35SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 880*4c1c9b35SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 881*4c1c9b35SJohnny Huang writel(0x04190760, 0x1e602008); //normal program 882*4c1c9b35SJohnny Huang } 883*4c1c9b35SJohnny Huang 88469d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 885*4c1c9b35SJohnny Huang bit_value = (value >> j) & 0x1; 88669d5fd8fSJohnny Huang if (prog_address % 2 == 0) { 88769d5fd8fSJohnny Huang if (bit_value) 88869d5fd8fSJohnny Huang prog_bit = ~(0x1 << j); 88969d5fd8fSJohnny Huang else 89069d5fd8fSJohnny Huang continue; 89169d5fd8fSJohnny Huang } else { 89269d5fd8fSJohnny Huang prog_address |= 1 << 15; 89369d5fd8fSJohnny Huang if (bit_value) 89469d5fd8fSJohnny Huang continue; 89569d5fd8fSJohnny Huang else 89669d5fd8fSJohnny Huang prog_bit = 0x1 << j; 89769d5fd8fSJohnny Huang } 898*4c1c9b35SJohnny Huang otp_prog(prog_address, prog_bit); 899*4c1c9b35SJohnny Huang } 900*4c1c9b35SJohnny Huang } 901*4c1c9b35SJohnny Huang 902*4c1c9b35SJohnny Huang static int otp_prog_data(uint32_t *buf, int otp_addr, int dw_count) 903*4c1c9b35SJohnny Huang { 904*4c1c9b35SJohnny Huang int i, k; 905*4c1c9b35SJohnny Huang int pass; 906*4c1c9b35SJohnny Huang int addr_odd, count_odd; 907*4c1c9b35SJohnny Huang int d_size; 908*4c1c9b35SJohnny Huang uint32_t prog_address; 909*4c1c9b35SJohnny Huang uint32_t *data; 910*4c1c9b35SJohnny Huang uint32_t compare[2]; 911*4c1c9b35SJohnny Huang 912*4c1c9b35SJohnny Huang count_odd = dw_count % 2; 913*4c1c9b35SJohnny Huang addr_odd = otp_addr % 2; 914*4c1c9b35SJohnny Huang d_size = dw_count + (count_odd ^ addr_odd); 915*4c1c9b35SJohnny Huang data = malloc(d_size * 4); 916*4c1c9b35SJohnny Huang 917*4c1c9b35SJohnny Huang printf("Read OTP Data:\n"); 918*4c1c9b35SJohnny Huang 919*4c1c9b35SJohnny Huang printProgress(0, d_size, ""); 920*4c1c9b35SJohnny Huang if (!addr_odd) { 921*4c1c9b35SJohnny Huang for (i = 0; i < d_size ; i += 2) { 922*4c1c9b35SJohnny Huang printProgress(i + 2, d_size, ""); 923*4c1c9b35SJohnny Huang otp_read_data(i + otp_addr, &data[i]); 924*4c1c9b35SJohnny Huang } 925*4c1c9b35SJohnny Huang } else { 926*4c1c9b35SJohnny Huang otp_read_data(otp_addr - 1, &data[0]); 927*4c1c9b35SJohnny Huang data[0] = data[1]; 928*4c1c9b35SJohnny Huang for (i = 1; i < d_size ; i += 2) { 929*4c1c9b35SJohnny Huang printProgress(i + 2, d_size, ""); 930*4c1c9b35SJohnny Huang otp_read_data(i + otp_addr, &data[i]); 931*4c1c9b35SJohnny Huang } 932*4c1c9b35SJohnny Huang } 933*4c1c9b35SJohnny Huang 934*4c1c9b35SJohnny Huang printf("Check writable...\n"); 935*4c1c9b35SJohnny Huang for (i = 0; i < dw_count; i++) { 936*4c1c9b35SJohnny Huang if (data[i] == buf[i]) 937*4c1c9b35SJohnny Huang continue; 938*4c1c9b35SJohnny Huang if ((i + otp_addr) % 2 == 0) { 939*4c1c9b35SJohnny Huang if ((data[i] | buf[i]) == buf[i]) { 940*4c1c9b35SJohnny Huang continue; 941*4c1c9b35SJohnny Huang } else { 942*4c1c9b35SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 943*4c1c9b35SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i + otp_addr, data[i]); 944*4c1c9b35SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 945*4c1c9b35SJohnny Huang goto fail; 946*4c1c9b35SJohnny Huang } 947*4c1c9b35SJohnny Huang } else { 948*4c1c9b35SJohnny Huang if ((data[i] & buf[i]) == buf[i]) { 949*4c1c9b35SJohnny Huang continue; 950*4c1c9b35SJohnny Huang } else { 951*4c1c9b35SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 952*4c1c9b35SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i + otp_addr, data[i]); 953*4c1c9b35SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 954*4c1c9b35SJohnny Huang goto fail; 955*4c1c9b35SJohnny Huang } 956*4c1c9b35SJohnny Huang } 957*4c1c9b35SJohnny Huang } 958*4c1c9b35SJohnny Huang 959*4c1c9b35SJohnny Huang printf("Start Programing...\n"); 960*4c1c9b35SJohnny Huang 961*4c1c9b35SJohnny Huang printProgress(0, dw_count, ""); 962*4c1c9b35SJohnny Huang if (addr_odd) { 963*4c1c9b35SJohnny Huang if (data[0] != buf[0]) { 96469d5fd8fSJohnny Huang pass = 0; 965*4c1c9b35SJohnny Huang printProgress(1, dw_count, "[%08X] = %08X ", otp_addr, buf[0]); 966*4c1c9b35SJohnny Huang otp_prog_dw(buf[0], otp_addr, 0); 96769d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 968*4c1c9b35SJohnny Huang if (prog_data_dw_verify(otp_addr, &buf[0], compare, 1) != 0) { 969*4c1c9b35SJohnny Huang otp_prog_dw(compare[0], otp_addr, 1); 970*4c1c9b35SJohnny Huang } else { 97169d5fd8fSJohnny Huang pass = 1; 97269d5fd8fSJohnny Huang break; 97369d5fd8fSJohnny Huang } 97469d5fd8fSJohnny Huang } 97569d5fd8fSJohnny Huang if (!pass) 976*4c1c9b35SJohnny Huang goto fail; 977*4c1c9b35SJohnny Huang } else { 978*4c1c9b35SJohnny Huang printProgress(1, dw_count, "[%08X] = %08X HIT ", otp_addr, buf[0]); 97969d5fd8fSJohnny Huang } 98069d5fd8fSJohnny Huang } 981*4c1c9b35SJohnny Huang /* if otp_addr is odd, then begin from 1. */ 982*4c1c9b35SJohnny Huang /* if dw_count is odd, then program the last dw seperately. */ 983*4c1c9b35SJohnny Huang for (i = 0 + addr_odd; i < dw_count - (addr_odd ^ count_odd); i += 2) { 984*4c1c9b35SJohnny Huang prog_address = i + otp_addr; 985*4c1c9b35SJohnny Huang 986*4c1c9b35SJohnny Huang if ((data[i] == buf[i]) && (data[i + 1] == buf[i + 1])) { 987*4c1c9b35SJohnny Huang printProgress(i + 2, dw_count, "[%03X]=%08X HIT;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]); 988*4c1c9b35SJohnny Huang continue; 989*4c1c9b35SJohnny Huang } 990*4c1c9b35SJohnny Huang if (data[i + 1] == buf[i + 1]) { 991*4c1c9b35SJohnny Huang printProgress(i + 2, dw_count, "[%03X]=%08X ;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]); 992*4c1c9b35SJohnny Huang otp_prog_dw(buf[i], prog_address, 0); 993*4c1c9b35SJohnny Huang } else if (data[i] == buf[i]) { 994*4c1c9b35SJohnny Huang printProgress(i + 2, dw_count, "[%03X]=%08X HIT;[%03X]=%08X ", prog_address, buf[i], prog_address + 1, buf[i + 1]); 995*4c1c9b35SJohnny Huang otp_prog_dw(buf[i + 1], prog_address + 1, 0); 996*4c1c9b35SJohnny Huang } else { 997*4c1c9b35SJohnny Huang printProgress(i + 2, dw_count, "[%03X]=%08X ;[%03X]=%08X ", prog_address, buf[i], prog_address + 1, buf[i + 1]); 998*4c1c9b35SJohnny Huang otp_prog_dw(buf[i], prog_address, 0); 999*4c1c9b35SJohnny Huang otp_prog_dw(buf[i + 1], prog_address + 1, 0); 1000*4c1c9b35SJohnny Huang } 1001*4c1c9b35SJohnny Huang 1002*4c1c9b35SJohnny Huang pass = 0; 1003*4c1c9b35SJohnny Huang for (k = 0; k < RETRY; k++) { 1004*4c1c9b35SJohnny Huang if (prog_data_dw_verify(prog_address, &buf[i], compare, 2) != 0) { 1005*4c1c9b35SJohnny Huang if (compare[0] != 0) { 1006*4c1c9b35SJohnny Huang otp_prog_dw(compare[0], prog_address, 1); 1007*4c1c9b35SJohnny Huang } 1008*4c1c9b35SJohnny Huang if (compare[1] != ~0) { 1009*4c1c9b35SJohnny Huang otp_prog_dw(compare[1], prog_address + 1, 1); 1010*4c1c9b35SJohnny Huang } 1011*4c1c9b35SJohnny Huang } else { 1012*4c1c9b35SJohnny Huang pass = 1; 1013*4c1c9b35SJohnny Huang break; 1014*4c1c9b35SJohnny Huang } 1015*4c1c9b35SJohnny Huang } 1016*4c1c9b35SJohnny Huang 1017*4c1c9b35SJohnny Huang if (!pass) 1018*4c1c9b35SJohnny Huang goto fail; 1019*4c1c9b35SJohnny Huang } 1020*4c1c9b35SJohnny Huang 1021*4c1c9b35SJohnny Huang if (!(addr_odd ^ count_odd)) 1022*4c1c9b35SJohnny Huang goto pass; 1023*4c1c9b35SJohnny Huang 1024*4c1c9b35SJohnny Huang prog_address = otp_addr + dw_count - 1; 1025*4c1c9b35SJohnny Huang if (data[dw_count - 1] != buf[dw_count - 1]) { 1026*4c1c9b35SJohnny Huang printProgress(dw_count, dw_count, "[%08X] = %08X ", prog_address, buf[dw_count - 1]); 1027*4c1c9b35SJohnny Huang otp_prog_dw(buf[dw_count - 1], prog_address, 0); 1028*4c1c9b35SJohnny Huang for (k = 0; k < RETRY; k++) { 1029*4c1c9b35SJohnny Huang if (prog_data_dw_verify(prog_address, &buf[dw_count - 1], compare, 1) != 0) { 1030*4c1c9b35SJohnny Huang otp_prog_dw(compare[0], prog_address, 1); 1031*4c1c9b35SJohnny Huang } else { 1032*4c1c9b35SJohnny Huang pass = 1; 1033*4c1c9b35SJohnny Huang break; 1034*4c1c9b35SJohnny Huang } 1035*4c1c9b35SJohnny Huang } 1036*4c1c9b35SJohnny Huang if (!pass) 1037*4c1c9b35SJohnny Huang goto fail; 1038*4c1c9b35SJohnny Huang } else { 1039*4c1c9b35SJohnny Huang printProgress(dw_count, dw_count, "[%08X] = %08X HIT ", prog_address, buf[dw_count - 1]); 1040*4c1c9b35SJohnny Huang } 1041*4c1c9b35SJohnny Huang 1042*4c1c9b35SJohnny Huang pass: 1043*4c1c9b35SJohnny Huang free(data); 104469d5fd8fSJohnny Huang return 0; 1045*4c1c9b35SJohnny Huang 1046*4c1c9b35SJohnny Huang fail: 1047*4c1c9b35SJohnny Huang free(data); 1048*4c1c9b35SJohnny Huang return -1; 104969d5fd8fSJohnny Huang } 105069d5fd8fSJohnny Huang 105169d5fd8fSJohnny Huang static int do_otp_prog(int mode, int addr, int otp_addr, int dw_count, int nconfirm) 105269d5fd8fSJohnny Huang { 105369d5fd8fSJohnny Huang int ret; 105469d5fd8fSJohnny Huang uint32_t *buf; 105569d5fd8fSJohnny Huang 105669d5fd8fSJohnny Huang buf = map_physmem(addr, dw_count * 4, MAP_WRBACK); 105769d5fd8fSJohnny Huang if (!buf) { 105869d5fd8fSJohnny Huang puts("Failed to map physical memory\n"); 105969d5fd8fSJohnny Huang return 1; 106069d5fd8fSJohnny Huang } 106169d5fd8fSJohnny Huang if (!nconfirm) { 106269d5fd8fSJohnny Huang if (mode == MODE_CONF) { 106369d5fd8fSJohnny Huang if (otp_conf_parse(buf) < 0) { 106469d5fd8fSJohnny Huang printf("OTP config error, please check.\n"); 106569d5fd8fSJohnny Huang return -1; 106669d5fd8fSJohnny Huang } 106769d5fd8fSJohnny Huang } else if (mode == MODE_DATA) { 106869d5fd8fSJohnny Huang if (otp_data_parse(buf, dw_count) < 0) { 106969d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 107069d5fd8fSJohnny Huang return -1; 107169d5fd8fSJohnny Huang } 107269d5fd8fSJohnny Huang } else if (mode == MODE_STRAP) { 107369d5fd8fSJohnny Huang if (otp_strap_parse(buf) < 0) { 107469d5fd8fSJohnny Huang printf("OTP strap error, please check.\n"); 107569d5fd8fSJohnny Huang return -1; 107669d5fd8fSJohnny Huang } 107769d5fd8fSJohnny Huang } else if (mode == MODE_ALL) { 107869d5fd8fSJohnny Huang if (otp_conf_parse(buf) < 0) { 107969d5fd8fSJohnny Huang printf("OTP config error, please check.\n"); 108069d5fd8fSJohnny Huang return -1; 108169d5fd8fSJohnny Huang } 108269d5fd8fSJohnny Huang if (otp_strap_parse(&buf[12]) < 0) { 108369d5fd8fSJohnny Huang printf("OTP strap error, please check.\n"); 108469d5fd8fSJohnny Huang return -1; 108569d5fd8fSJohnny Huang } 108669d5fd8fSJohnny Huang if (otp_data_parse(&buf[18], dw_count - 18) < 0) { 108769d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 108869d5fd8fSJohnny Huang return -1; 108969d5fd8fSJohnny Huang } 109069d5fd8fSJohnny Huang } 109169d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 109269d5fd8fSJohnny Huang if (!confirm_yesno()) { 109369d5fd8fSJohnny Huang printf(" Aborting\n"); 109469d5fd8fSJohnny Huang return 1; 109569d5fd8fSJohnny Huang } 109669d5fd8fSJohnny Huang } 109769d5fd8fSJohnny Huang if (mode == MODE_CONF) { 109869d5fd8fSJohnny Huang return otp_prog_conf(buf, otp_addr, dw_count); 109969d5fd8fSJohnny Huang } else if (mode == MODE_STRAP) { 110069d5fd8fSJohnny Huang return otp_prog_strap(buf); 110169d5fd8fSJohnny Huang } else if (mode == MODE_DATA) { 110269d5fd8fSJohnny Huang return otp_prog_data(buf, otp_addr, dw_count); 110369d5fd8fSJohnny Huang } else if (mode == MODE_ALL) { 110469d5fd8fSJohnny Huang printf("programing data region ... "); 110569d5fd8fSJohnny Huang ret = otp_prog_data(&buf[16], 0, dw_count - 18); 110669d5fd8fSJohnny Huang if (ret < 0) { 110769d5fd8fSJohnny Huang printf("Error\n"); 110869d5fd8fSJohnny Huang return ret; 110969d5fd8fSJohnny Huang } else { 111069d5fd8fSJohnny Huang printf("Done\n"); 111169d5fd8fSJohnny Huang } 111269d5fd8fSJohnny Huang printf("programing strap region ... "); 111369d5fd8fSJohnny Huang ret = otp_prog_strap(&buf[12]); 111469d5fd8fSJohnny Huang if (ret < 0) { 111569d5fd8fSJohnny Huang printf("Error\n"); 111669d5fd8fSJohnny Huang return ret; 111769d5fd8fSJohnny Huang } else { 111869d5fd8fSJohnny Huang printf("Done\n"); 111969d5fd8fSJohnny Huang } 112069d5fd8fSJohnny Huang printf("programing configuration region ... "); 112169d5fd8fSJohnny Huang ret = otp_prog_conf(buf, 0, 12); 112269d5fd8fSJohnny Huang if (ret < 0) { 112369d5fd8fSJohnny Huang printf("Error\n"); 112469d5fd8fSJohnny Huang return ret; 112569d5fd8fSJohnny Huang } 112669d5fd8fSJohnny Huang printf("Done\n"); 112769d5fd8fSJohnny Huang return ret; 112869d5fd8fSJohnny Huang } 112969d5fd8fSJohnny Huang return 0; 113069d5fd8fSJohnny Huang } 113169d5fd8fSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, 113269d5fd8fSJohnny Huang char *const argv[]) 113369d5fd8fSJohnny Huang { 113469d5fd8fSJohnny Huang char *cmd; 113569d5fd8fSJohnny Huang int mode = 0; 113669d5fd8fSJohnny Huang int nconfirm = 0; 113769d5fd8fSJohnny Huang uint32_t addr, dw_count, otp_addr; 113869d5fd8fSJohnny Huang 113969d5fd8fSJohnny Huang 114069d5fd8fSJohnny Huang 114169d5fd8fSJohnny Huang if (argc < 2) { 114269d5fd8fSJohnny Huang usage: 114369d5fd8fSJohnny Huang return CMD_RET_USAGE; 114469d5fd8fSJohnny Huang } 114569d5fd8fSJohnny Huang 114669d5fd8fSJohnny Huang cmd = argv[1]; 114769d5fd8fSJohnny Huang if (!strcmp(cmd, "read")) { 114869d5fd8fSJohnny Huang if (!strcmp(argv[2], "conf")) 114969d5fd8fSJohnny Huang mode = MODE_CONF; 115069d5fd8fSJohnny Huang else if (!strcmp(argv[2], "data")) 115169d5fd8fSJohnny Huang mode = MODE_DATA; 115269d5fd8fSJohnny Huang else if (!strcmp(argv[2], "strap")) 115369d5fd8fSJohnny Huang mode = MODE_STRAP; 115469d5fd8fSJohnny Huang else 115569d5fd8fSJohnny Huang goto usage; 115669d5fd8fSJohnny Huang 115769d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 115869d5fd8fSJohnny Huang otp_addr = simple_strtoul(argv[3], NULL, 16); 115969d5fd8fSJohnny Huang dw_count = simple_strtoul(argv[4], NULL, 16); 116069d5fd8fSJohnny Huang if (mode == MODE_CONF) { 116169d5fd8fSJohnny Huang otp_print_config(otp_addr, dw_count); 116269d5fd8fSJohnny Huang } else if (mode == MODE_DATA) { 116369d5fd8fSJohnny Huang otp_print_data(otp_addr, dw_count); 116469d5fd8fSJohnny Huang } else if (mode == MODE_STRAP) { 116569d5fd8fSJohnny Huang otp_print_strap(); 116669d5fd8fSJohnny Huang } 116769d5fd8fSJohnny Huang } else if (!strcmp(cmd, "prog")) { 116869d5fd8fSJohnny Huang if (!strcmp(argv[2], "conf")) 116969d5fd8fSJohnny Huang mode = MODE_CONF; 117069d5fd8fSJohnny Huang else if (!strcmp(argv[2], "strap")) 117169d5fd8fSJohnny Huang mode = MODE_STRAP; 117269d5fd8fSJohnny Huang else if (!strcmp(argv[2], "data")) 117369d5fd8fSJohnny Huang mode = MODE_DATA; 117469d5fd8fSJohnny Huang else if (!strcmp(argv[2], "all")) 117569d5fd8fSJohnny Huang mode = MODE_ALL; 117669d5fd8fSJohnny Huang else 117769d5fd8fSJohnny Huang goto usage; 117869d5fd8fSJohnny Huang 117969d5fd8fSJohnny Huang if (!strcmp(argv[3], "f")) 118069d5fd8fSJohnny Huang nconfirm = 1; 118169d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 118269d5fd8fSJohnny Huang addr = simple_strtoul(argv[3 + nconfirm], NULL, 16); 118369d5fd8fSJohnny Huang otp_addr = simple_strtoul(argv[4 + nconfirm], NULL, 16); 118469d5fd8fSJohnny Huang dw_count = simple_strtoul(argv[5 + nconfirm], NULL, 16); 118569d5fd8fSJohnny Huang return do_otp_prog(mode, addr, otp_addr, dw_count, nconfirm); 118669d5fd8fSJohnny Huang } else if (!strcmp(cmd, "comp")) { 118769d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 118869d5fd8fSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 118969d5fd8fSJohnny Huang otp_addr = simple_strtoul(argv[3], NULL, 16); 119069d5fd8fSJohnny Huang if (otp_compare(otp_addr, addr) >= 0) { 119169d5fd8fSJohnny Huang printf("Compare pass\n"); 119269d5fd8fSJohnny Huang } else { 119369d5fd8fSJohnny Huang printf("Compare fail\n"); 119469d5fd8fSJohnny Huang } 119569d5fd8fSJohnny Huang } else { 119669d5fd8fSJohnny Huang goto usage; 119769d5fd8fSJohnny Huang } 119869d5fd8fSJohnny Huang 119969d5fd8fSJohnny Huang 120069d5fd8fSJohnny Huang return 0; 120169d5fd8fSJohnny Huang } 120269d5fd8fSJohnny Huang 120369d5fd8fSJohnny Huang 120469d5fd8fSJohnny Huang U_BOOT_CMD( 120569d5fd8fSJohnny Huang otp, 7, 0, do_ast_otp, 120669d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 120769d5fd8fSJohnny Huang "read conf|strap|data <otp_addr> <dw_count>\n" 120869d5fd8fSJohnny Huang "otp prog conf|strap|data|all [f] <addr> <otp_addr> <dw_count>\n" 120969d5fd8fSJohnny Huang "otp comp <addr> <otp_addr>" 121069d5fd8fSJohnny Huang ); 1211