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 */ 1169d5fd8fSJohnny Huang 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> 1869d5fd8fSJohnny Huang 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 33*e1f9e54eSJohnny Huang #define DISABLE_SECREG_PROG BIT(0) 34*e1f9e54eSJohnny Huang #define ENABLE_SEC_BOOT BIT(1) 35*e1f9e54eSJohnny Huang #define INIT_PROG_DONE BIT(2) 36*e1f9e54eSJohnny Huang #define ENABLE_USERREG_ECC BIT(3) 37*e1f9e54eSJohnny Huang #define ENABLE_SECREG_ECC BIT(4) 38*e1f9e54eSJohnny Huang #define DISABLE_LOW_SEC_KEY BIT(5) 39*e1f9e54eSJohnny Huang #define IGNORE_SEC_BOOT_HWSTRAP BIT(6) 40*e1f9e54eSJohnny Huang #define SEC_BOOT_MDOES(x) (x >> 7) 41*e1f9e54eSJohnny Huang #define SEC_MODE1 0x0 42*e1f9e54eSJohnny Huang #define SEC_MODE2 0x1 43*e1f9e54eSJohnny Huang #define OTP_BIT_CELL_MODES(x) ((x >> 8) & 0x3) 44*e1f9e54eSJohnny Huang #define SINGLE_CELL_MODE 0x0 45*e1f9e54eSJohnny Huang #define DIFFERENTIAL_MODE 0x1 46*e1f9e54eSJohnny Huang #define DIFFERENTIAL_REDUDANT_MODE 0x2 47*e1f9e54eSJohnny Huang #define CRYPTO_MODES(x) ((x >> 10) & 0x3) 48*e1f9e54eSJohnny Huang #define CRYPTO_RSA1024 0x0 49*e1f9e54eSJohnny Huang #define CRYPTO_RSA2048 0x1 50*e1f9e54eSJohnny Huang #define CRYPTO_RSA3072 0x2 51*e1f9e54eSJohnny Huang #define CRYPTO_RSA4096 0x3 52*e1f9e54eSJohnny Huang #define HASH_MODES(x) ((x >> 12) & 0x3) 53*e1f9e54eSJohnny Huang #define HASH_SAH224 0x0 54*e1f9e54eSJohnny Huang #define HASH_SAH256 0x1 55*e1f9e54eSJohnny Huang #define HASH_SAH384 0x2 56*e1f9e54eSJohnny Huang #define HASH_SAH512 0x3 57*e1f9e54eSJohnny Huang #define SECREG_SIZE(x) ((x >> 16) & 0x3f) 58*e1f9e54eSJohnny Huang #define WRITE_PROTECT_SECREG BIT(22) 59*e1f9e54eSJohnny Huang #define WRITE_PROTECT_USERREG BIT(23) 60*e1f9e54eSJohnny Huang #define WRITE_PROTECT_CONFREG BIT(24) 61*e1f9e54eSJohnny Huang #define WRITE_PROTECT_STRAPREG BIT(25) 62*e1f9e54eSJohnny Huang #define ENABLE_COPY_TO_SRAM BIT(26) 63*e1f9e54eSJohnny Huang #define ENABLE_IMAGE_ENC BIT(27) 64*e1f9e54eSJohnny Huang #define WRITE_PROTECT_KEY_RETIRE BIT(29) 65*e1f9e54eSJohnny Huang #define ENABLE_SIPROM_RED BIT(30) 66*e1f9e54eSJohnny Huang #define ENABLE_SIPROM_MLOCK BIT(31) 67*e1f9e54eSJohnny Huang 68*e1f9e54eSJohnny Huang #define VENDER_ID(x) (x & 0xFFFF) 69*e1f9e54eSJohnny Huang #define KEY_REVISION(x) ((x >> 16) & 0xFFFF) 70*e1f9e54eSJohnny Huang 71*e1f9e54eSJohnny Huang #define SEC_BOOT_HEADER_OFFSET(x) (x & 0xFFFF) 72*e1f9e54eSJohnny Huang 73*e1f9e54eSJohnny Huang #define KEYS_VALID_BITS(x) (x & 0xff) 74*e1f9e54eSJohnny Huang #define KEYS_RETIRE_BITS(x) ((x >> 16) & 0xff) 7569d5fd8fSJohnny Huang struct otpstrap { 7669d5fd8fSJohnny Huang int value; 7769d5fd8fSJohnny Huang int option_array[7]; 7869d5fd8fSJohnny Huang int remain_times; 7969d5fd8fSJohnny Huang int writeable_option; 8069d5fd8fSJohnny Huang int protected; 8169d5fd8fSJohnny Huang }; 8269d5fd8fSJohnny Huang 8369d5fd8fSJohnny Huang static int otp_read_data(uint32_t offset, uint32_t *data) 8469d5fd8fSJohnny Huang { 8569d5fd8fSJohnny Huang writel(offset, 0x1e6f2010); //Read address 8669d5fd8fSJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 8769d5fd8fSJohnny Huang udelay(2); 8869d5fd8fSJohnny Huang data[0] = readl(0x1e6f2020); 8969d5fd8fSJohnny Huang data[1] = readl(0x1e6f2024); 9069d5fd8fSJohnny Huang return 1; 9169d5fd8fSJohnny Huang } 9269d5fd8fSJohnny Huang 9369d5fd8fSJohnny Huang static int otp_read_config(uint32_t offset, uint32_t *data) 9469d5fd8fSJohnny Huang { 9569d5fd8fSJohnny Huang int config_offset; 9669d5fd8fSJohnny Huang 9769d5fd8fSJohnny Huang config_offset = 0x800; 9869d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 9969d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 10069d5fd8fSJohnny Huang 10169d5fd8fSJohnny Huang writel(config_offset, 0x1e6f2010); //Read address 10269d5fd8fSJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 10369d5fd8fSJohnny Huang udelay(2); 10469d5fd8fSJohnny Huang data[0] = readl(0x1e6f2020); 10569d5fd8fSJohnny Huang 10669d5fd8fSJohnny Huang return 1; 10769d5fd8fSJohnny Huang } 10869d5fd8fSJohnny Huang 10969d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count) 11069d5fd8fSJohnny Huang { 11169d5fd8fSJohnny Huang int i; 11269d5fd8fSJohnny Huang uint32_t ret[1]; 11369d5fd8fSJohnny Huang 11469d5fd8fSJohnny Huang if (offset + dw_count > 32) 11569d5fd8fSJohnny Huang return -1; 11669d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i ++) { 11769d5fd8fSJohnny Huang otp_read_config(i, ret); 11869d5fd8fSJohnny Huang printf("OTPCFG%d: %08X\n", i, ret[0]); 11969d5fd8fSJohnny Huang } 12069d5fd8fSJohnny Huang printf("\n"); 12169d5fd8fSJohnny Huang return 1; 12269d5fd8fSJohnny Huang } 12369d5fd8fSJohnny Huang 12469d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count) 12569d5fd8fSJohnny Huang { 12669d5fd8fSJohnny Huang int i; 12769d5fd8fSJohnny Huang uint32_t ret[2]; 12869d5fd8fSJohnny Huang 12969d5fd8fSJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 13069d5fd8fSJohnny Huang return -1; 13169d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 13269d5fd8fSJohnny Huang otp_read_data(i, ret); 13369d5fd8fSJohnny Huang if (i % 4 == 0) 13469d5fd8fSJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 13569d5fd8fSJohnny Huang else 13669d5fd8fSJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 13769d5fd8fSJohnny Huang 13869d5fd8fSJohnny Huang } 13969d5fd8fSJohnny Huang printf("\n"); 14069d5fd8fSJohnny Huang return 1; 14169d5fd8fSJohnny Huang } 14269d5fd8fSJohnny Huang 14369d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr) 14469d5fd8fSJohnny Huang { 14569d5fd8fSJohnny Huang uint32_t ret; 14669d5fd8fSJohnny Huang uint32_t *buf; 14769d5fd8fSJohnny Huang 14869d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 14969d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 15069d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 15169d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 15269d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 15369d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //Compare address 15469d5fd8fSJohnny Huang writel(buf[0], 0x1e6f2020); //Compare data 1 15569d5fd8fSJohnny Huang writel(buf[1], 0x1e6f2024); //Compare data 2 15669d5fd8fSJohnny Huang writel(buf[2], 0x1e6f2028); //Compare data 3 15769d5fd8fSJohnny Huang writel(buf[3], 0x1e6f202c); //Compare data 4 15869d5fd8fSJohnny Huang writel(0x23b1e363, 0x1e6f2004); //Compare command 15969d5fd8fSJohnny Huang udelay(10); 16069d5fd8fSJohnny Huang ret = readl(0x1e6f2014); //Compare command 16169d5fd8fSJohnny Huang if (ret & 0x1) 16269d5fd8fSJohnny Huang return 0; 16369d5fd8fSJohnny Huang else 16469d5fd8fSJohnny Huang return -1; 16569d5fd8fSJohnny Huang } 16669d5fd8fSJohnny Huang 16769d5fd8fSJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data) 16869d5fd8fSJohnny Huang { 16969d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //write address 17069d5fd8fSJohnny Huang writel(data, 0x1e6f2020); //write data 17169d5fd8fSJohnny Huang writel(0x23b1e362, 0x1e6f2004); //write command 17269d5fd8fSJohnny Huang udelay(100); 17369d5fd8fSJohnny Huang } 17469d5fd8fSJohnny Huang 17569d5fd8fSJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit) 17669d5fd8fSJohnny Huang { 17769d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //write address 17869d5fd8fSJohnny Huang writel(prog_bit, 0x1e6f2020); //write data 17969d5fd8fSJohnny Huang writel(0x23b1e364, 0x1e6f2004); //write command 18069d5fd8fSJohnny Huang udelay(85); 18169d5fd8fSJohnny Huang } 18269d5fd8fSJohnny Huang 18369d5fd8fSJohnny Huang static int prog_verify(uint32_t otp_addr, int bit_offset, int value) 18469d5fd8fSJohnny Huang { 18569d5fd8fSJohnny Huang int ret; 18669d5fd8fSJohnny Huang 18769d5fd8fSJohnny Huang writel(otp_addr, 0x1e6f2010); //Read address 18869d5fd8fSJohnny Huang writel(0x23b1e361, 0x1e6f2004); //trigger read 18969d5fd8fSJohnny Huang udelay(2); 19069d5fd8fSJohnny Huang ret = readl(0x1e6f2020); 19169d5fd8fSJohnny Huang // printf("prog_verify = %x\n", ret); 19269d5fd8fSJohnny Huang if (((ret >> bit_offset) & 1) == value) 19369d5fd8fSJohnny Huang return 0; 19469d5fd8fSJohnny Huang else 19569d5fd8fSJohnny Huang return -1; 19669d5fd8fSJohnny Huang } 19769d5fd8fSJohnny Huang 19869d5fd8fSJohnny Huang static int otp_conf_parse(uint32_t *OTPCFG) 19969d5fd8fSJohnny Huang { 20069d5fd8fSJohnny Huang int tmp, i, pass; 20169d5fd8fSJohnny Huang 20269d5fd8fSJohnny Huang printf("OTPCFG0-D[0]\n"); 203*e1f9e54eSJohnny Huang if (OTPCFG[0] & DISABLE_SECREG_PROG) 20469d5fd8fSJohnny Huang printf(" Disable Secure Region programming\n"); 20569d5fd8fSJohnny Huang else 20669d5fd8fSJohnny Huang printf(" Enable Secure Region programming\n"); 20769d5fd8fSJohnny Huang printf("OTPCFG0-D[1]\n"); 208*e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SEC_BOOT) 20969d5fd8fSJohnny Huang printf(" Enable Secure Boot\n"); 21069d5fd8fSJohnny Huang else 21169d5fd8fSJohnny Huang printf(" Disable Secure Boot\n"); 21269d5fd8fSJohnny Huang printf("OTPCFG0-D[3]\n"); 213*e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_USERREG_ECC) 21469d5fd8fSJohnny Huang printf(" User region ECC enable\n"); 21569d5fd8fSJohnny Huang else 21669d5fd8fSJohnny Huang printf(" User region ECC disable\n"); 21769d5fd8fSJohnny Huang printf("OTPCFG0-D[4]\n"); 218*e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SECREG_ECC) 21969d5fd8fSJohnny Huang printf(" Secure Region ECC enable\n"); 22069d5fd8fSJohnny Huang else 22169d5fd8fSJohnny Huang printf(" Secure Region ECC disable\n"); 22269d5fd8fSJohnny Huang printf("OTPCFG0-D[5]\n"); 223*e1f9e54eSJohnny Huang if (OTPCFG[0] & DISABLE_LOW_SEC_KEY) 22469d5fd8fSJohnny Huang printf(" Disable low security key\n"); 22569d5fd8fSJohnny Huang else 22669d5fd8fSJohnny Huang printf(" Enable low security key\n"); 22769d5fd8fSJohnny Huang printf("OTPCFG0-D[6]\n"); 228*e1f9e54eSJohnny Huang if (OTPCFG[0] & IGNORE_SEC_BOOT_HWSTRAP) 22969d5fd8fSJohnny Huang printf(" Ignore Secure Boot hardware strap\n"); 23069d5fd8fSJohnny Huang else 23169d5fd8fSJohnny Huang printf(" Do not ignore Secure Boot hardware strap\n"); 23269d5fd8fSJohnny Huang printf("OTPCFG0-D[7]\n"); 233*e1f9e54eSJohnny Huang if (SEC_BOOT_MDOES(OTPCFG[0]) == SEC_MODE1) 234*e1f9e54eSJohnny Huang printf(" Secure Boot Mode: 1\n"); 235*e1f9e54eSJohnny Huang else 236*e1f9e54eSJohnny Huang printf(" Secure Boot Mode: 2\n"); 23769d5fd8fSJohnny Huang printf("OTPCFG0-D[9:8]\n"); 23869d5fd8fSJohnny Huang printf(" OTP bit cell mode : "); 239*e1f9e54eSJohnny Huang tmp = OTP_BIT_CELL_MODES(OTPCFG[0]); 240*e1f9e54eSJohnny Huang if (tmp == SINGLE_CELL_MODE) { 24169d5fd8fSJohnny Huang printf("Single cell mode (recommended)\n"); 242*e1f9e54eSJohnny Huang } else if (tmp == DIFFERENTIAL_MODE) { 24369d5fd8fSJohnny Huang printf("Differnetial mode\n"); 244*e1f9e54eSJohnny Huang } else if (tmp == DIFFERENTIAL_REDUDANT_MODE) { 24569d5fd8fSJohnny Huang printf("Differential-redundant mode\n"); 24669d5fd8fSJohnny Huang } else { 24769d5fd8fSJohnny Huang printf("Value error\n"); 24869d5fd8fSJohnny Huang return -1; 24969d5fd8fSJohnny Huang } 25069d5fd8fSJohnny Huang printf("OTPCFG0-D[11:10]\n"); 25169d5fd8fSJohnny Huang printf(" RSA mode : "); 252*e1f9e54eSJohnny Huang tmp = CRYPTO_MODES(OTPCFG[0]); 253*e1f9e54eSJohnny Huang if (tmp == CRYPTO_RSA1024) { 25469d5fd8fSJohnny Huang printf("RSA1024\n"); 255*e1f9e54eSJohnny Huang } else if (tmp == CRYPTO_RSA2048) { 25669d5fd8fSJohnny Huang printf("RSA2048\n"); 257*e1f9e54eSJohnny Huang } else if (tmp == CRYPTO_RSA3072) { 25869d5fd8fSJohnny Huang printf("RSA3072\n"); 25969d5fd8fSJohnny Huang } else { 26069d5fd8fSJohnny Huang printf("RSA4096\n"); 26169d5fd8fSJohnny Huang } 26269d5fd8fSJohnny Huang printf("OTPCFG0-D[13:12]\n"); 26369d5fd8fSJohnny Huang printf(" SHA mode : "); 264*e1f9e54eSJohnny Huang tmp = HASH_MODES(OTPCFG[0]); 265*e1f9e54eSJohnny Huang if (tmp == HASH_SAH224) { 26669d5fd8fSJohnny Huang printf("SHA224\n"); 267*e1f9e54eSJohnny Huang } else if (tmp == HASH_SAH256) { 26869d5fd8fSJohnny Huang printf("SHA256\n"); 269*e1f9e54eSJohnny Huang } else if (tmp == HASH_SAH384) { 27069d5fd8fSJohnny Huang printf("SHA384\n"); 27169d5fd8fSJohnny Huang } else { 27269d5fd8fSJohnny Huang printf("SHA512\n"); 27369d5fd8fSJohnny Huang } 27469d5fd8fSJohnny Huang 27569d5fd8fSJohnny Huang printf("OTPCFG0-D[21:16]\n"); 276*e1f9e54eSJohnny Huang printf(" Secure Region size (DW): %x\n", SECREG_SIZE(OTPCFG[0])); 27769d5fd8fSJohnny Huang 27869d5fd8fSJohnny Huang printf("OTPCFG0-D[22]\n"); 279*e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_SECREG) 28069d5fd8fSJohnny Huang printf(" Secure Region : Write Protect\n"); 28169d5fd8fSJohnny Huang else 28269d5fd8fSJohnny Huang printf(" Secure Region : Writable\n"); 28369d5fd8fSJohnny Huang printf("OTPCFG0-D[23]\n"); 284*e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_USERREG) 28569d5fd8fSJohnny Huang printf(" User Region : Write Protect\n"); 28669d5fd8fSJohnny Huang else 28769d5fd8fSJohnny Huang printf(" User Region : Writable\n"); 28869d5fd8fSJohnny Huang printf("OTPCFG0-D[24]\n"); 289*e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_CONFREG) 29069d5fd8fSJohnny Huang printf(" Configure Region : Write Protect\n"); 29169d5fd8fSJohnny Huang else 29269d5fd8fSJohnny Huang printf(" Configure Region : Writable\n"); 29369d5fd8fSJohnny Huang printf("OTPCFG0-D[25]\n"); 294*e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_STRAPREG) 29569d5fd8fSJohnny Huang printf(" OTP strap Region : Write Protect\n"); 29669d5fd8fSJohnny Huang else 29769d5fd8fSJohnny Huang printf(" OTP strap Region : Writable\n"); 29869d5fd8fSJohnny Huang printf("OTPCFG0-D[26]\n"); 299*e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_COPY_TO_SRAM) 30069d5fd8fSJohnny Huang printf(" Copy Boot Image to Internal SRAM\n"); 30169d5fd8fSJohnny Huang else 30269d5fd8fSJohnny Huang printf(" Disable Copy Boot Image to Internal SRAM\n"); 30369d5fd8fSJohnny Huang printf("OTPCFG0-D[27]\n"); 304*e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_IMAGE_ENC) 30569d5fd8fSJohnny Huang printf(" Enable image encryption\n"); 30669d5fd8fSJohnny Huang else 30769d5fd8fSJohnny Huang printf(" Disable image encryption\n"); 30869d5fd8fSJohnny Huang printf("OTPCFG0-D[29]\n"); 309*e1f9e54eSJohnny Huang if (OTPCFG[0] & WRITE_PROTECT_KEY_RETIRE) 31069d5fd8fSJohnny Huang printf(" OTP key retire Region : Write Protect\n"); 31169d5fd8fSJohnny Huang else 31269d5fd8fSJohnny Huang printf(" OTP key retire Region : Writable\n"); 31369d5fd8fSJohnny Huang printf("OTPCFG0-D[30]\n"); 314*e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SIPROM_RED) 31569d5fd8fSJohnny Huang printf(" SIPROM RED_EN redundancy repair enable\n"); 31669d5fd8fSJohnny Huang else 31769d5fd8fSJohnny Huang printf(" SIPROM RED_EN redundancy repair disable\n"); 31869d5fd8fSJohnny Huang printf("OTPCFG0-D[31]\n"); 319*e1f9e54eSJohnny Huang if (OTPCFG[0] & ENABLE_SIPROM_MLOCK) 32069d5fd8fSJohnny Huang printf(" SIPROM Mlock memory lock enable\n"); 32169d5fd8fSJohnny Huang else 32269d5fd8fSJohnny Huang printf(" SIPROM Mlock memory lock disable\n"); 32369d5fd8fSJohnny Huang 32469d5fd8fSJohnny Huang printf("OTPCFG2-D[15:0]\n"); 325*e1f9e54eSJohnny Huang printf(" Vender ID : %x\n", VENDER_ID(OTPCFG[2])); 32669d5fd8fSJohnny Huang 32769d5fd8fSJohnny Huang printf("OTPCFG2-D[31:16]\n"); 328*e1f9e54eSJohnny Huang printf(" Key Revision : %x\n", KEY_REVISION(OTPCFG[2])); 32969d5fd8fSJohnny Huang 33069d5fd8fSJohnny Huang printf("OTPCFG3-D[15:0]\n"); 331*e1f9e54eSJohnny Huang printf(" Secure boot header offset : %x\n", 332*e1f9e54eSJohnny Huang SEC_BOOT_HEADER_OFFSET(OTPCFG[3])); 33369d5fd8fSJohnny Huang 33469d5fd8fSJohnny Huang printf("OTPCFG4-D[7:0]\n"); 335*e1f9e54eSJohnny Huang tmp = KEYS_VALID_BITS(OTPCFG[4]); 336*e1f9e54eSJohnny Huang if (tmp != 0) { 33769d5fd8fSJohnny Huang for (i = 0; i < 7; i++) { 33869d5fd8fSJohnny Huang if (tmp == (1 << i)) { 339*e1f9e54eSJohnny Huang pass = i + 1; 34069d5fd8fSJohnny Huang } 34169d5fd8fSJohnny Huang } 342*e1f9e54eSJohnny Huang } else { 343*e1f9e54eSJohnny Huang pass = 0; 344*e1f9e54eSJohnny Huang } 345*e1f9e54eSJohnny Huang printf(" Keys valid : %d\n", pass); 34669d5fd8fSJohnny Huang 34769d5fd8fSJohnny Huang printf("OTPCFG4-D[23:16]\n"); 348*e1f9e54eSJohnny Huang tmp = KEYS_RETIRE_BITS(OTPCFG[4]); 349*e1f9e54eSJohnny Huang if (tmp != 0) { 35069d5fd8fSJohnny Huang for (i = 0; i < 7; i++) { 35169d5fd8fSJohnny Huang if (tmp == (1 << i)) { 352*e1f9e54eSJohnny Huang pass = i + 1; 35369d5fd8fSJohnny Huang } 35469d5fd8fSJohnny Huang } 355*e1f9e54eSJohnny Huang } else { 356*e1f9e54eSJohnny Huang pass = 0; 35769d5fd8fSJohnny Huang } 35869d5fd8fSJohnny Huang printf(" Keys Retire ID : %d\n", pass); 35969d5fd8fSJohnny Huang 36069d5fd8fSJohnny Huang printf("OTPCFG5-D[31:0]\n"); 36169d5fd8fSJohnny Huang printf(" User define data, random number low : %x\n", OTPCFG[5]); 36269d5fd8fSJohnny Huang 36369d5fd8fSJohnny Huang printf("OTPCFG6-D[31:0]\n"); 36469d5fd8fSJohnny Huang printf(" User define data, random number high : %x\n", OTPCFG[6]); 36569d5fd8fSJohnny Huang 36669d5fd8fSJohnny Huang printf("OTPCFG8-D[31:0]\n"); 36769d5fd8fSJohnny Huang printf(" Redundancy Repair : %x\n", OTPCFG[8]); 36869d5fd8fSJohnny Huang 36969d5fd8fSJohnny Huang printf("OTPCFG10-D[31:0]\n"); 37069d5fd8fSJohnny Huang printf(" Manifest ID low : %x\n", OTPCFG[10]); 37169d5fd8fSJohnny Huang 37269d5fd8fSJohnny Huang printf("OTPCFG11-D[31:0]\n"); 37369d5fd8fSJohnny Huang printf(" Manifest ID high : %x\n", OTPCFG[11]); 37469d5fd8fSJohnny Huang return 0; 37569d5fd8fSJohnny Huang 37669d5fd8fSJohnny Huang } 37769d5fd8fSJohnny Huang 37869d5fd8fSJohnny Huang static void buf_print(char *buf, int len) 37969d5fd8fSJohnny Huang { 38069d5fd8fSJohnny Huang int i; 38169d5fd8fSJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 38269d5fd8fSJohnny Huang for (i = 0; i < len; i++) { 38369d5fd8fSJohnny Huang if (i % 16 == 0) { 38469d5fd8fSJohnny Huang printf("%04X: ", i); 38569d5fd8fSJohnny Huang } 38669d5fd8fSJohnny Huang printf("%02X ", buf[i]); 38769d5fd8fSJohnny Huang if ((i + 1) % 16 == 0) { 38869d5fd8fSJohnny Huang printf("\n"); 38969d5fd8fSJohnny Huang } 39069d5fd8fSJohnny Huang } 39169d5fd8fSJohnny Huang } 39269d5fd8fSJohnny Huang 39369d5fd8fSJohnny Huang static int otp_data_parse(uint32_t *buf, int dw_count) 39469d5fd8fSJohnny Huang { 39569d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 39669d5fd8fSJohnny Huang char *byte_buf; 39769d5fd8fSJohnny Huang int i = 0, len = 0; 39869d5fd8fSJohnny Huang byte_buf = (char *)buf; 39969d5fd8fSJohnny Huang while (1) { 40069d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 40169d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 40269d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 40369d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 40469d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 40569d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 40669d5fd8fSJohnny Huang printf("Key[%d]:\n", i); 40769d5fd8fSJohnny Huang printf("Key Type: "); 40869d5fd8fSJohnny Huang switch (key_type) { 40969d5fd8fSJohnny Huang case 0: 41069d5fd8fSJohnny Huang printf("AES-256 as OEM platform key for image encryption/decryption\n"); 41169d5fd8fSJohnny Huang break; 41269d5fd8fSJohnny Huang case 1: 41369d5fd8fSJohnny Huang printf("AES-256 as secret vault key\n"); 41469d5fd8fSJohnny Huang break; 41569d5fd8fSJohnny Huang case 4: 41669d5fd8fSJohnny Huang printf("HMAC as encrypted OEM HMAC keys in Mode 1\n"); 41769d5fd8fSJohnny Huang break; 41869d5fd8fSJohnny Huang case 8: 41969d5fd8fSJohnny Huang printf("RSA-public as OEM DSS public keys in Mode 2\n"); 42069d5fd8fSJohnny Huang break; 42169d5fd8fSJohnny Huang case 9: 42269d5fd8fSJohnny Huang printf("RSA-public as SOC public key\n"); 42369d5fd8fSJohnny Huang break; 42469d5fd8fSJohnny Huang case 10: 42569d5fd8fSJohnny Huang printf("RSA-public as AES key decryption key\n"); 42669d5fd8fSJohnny Huang break; 42769d5fd8fSJohnny Huang case 13: 42869d5fd8fSJohnny Huang printf("RSA-private as SOC private key\n"); 42969d5fd8fSJohnny Huang break; 43069d5fd8fSJohnny Huang case 14: 43169d5fd8fSJohnny Huang printf("RSA-private as AES key decryption key\n"); 43269d5fd8fSJohnny Huang break; 43369d5fd8fSJohnny Huang default: 43469d5fd8fSJohnny Huang printf("key_type error: %x\n", key_type); 43569d5fd8fSJohnny Huang return -1; 43669d5fd8fSJohnny Huang } 43769d5fd8fSJohnny Huang if (key_type == 4) { 43869d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 43969d5fd8fSJohnny Huang switch (key_length) { 44069d5fd8fSJohnny Huang case 0: 44169d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 44269d5fd8fSJohnny Huang break; 44369d5fd8fSJohnny Huang case 1: 44469d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 44569d5fd8fSJohnny Huang break; 44669d5fd8fSJohnny Huang case 2: 44769d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 44869d5fd8fSJohnny Huang break; 44969d5fd8fSJohnny Huang case 3: 45069d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 45169d5fd8fSJohnny Huang break; 45269d5fd8fSJohnny Huang } 45369d5fd8fSJohnny Huang } else if (key_type != 0 || key_type != 1) { 45469d5fd8fSJohnny Huang printf("RSA SHA Type: "); 45569d5fd8fSJohnny Huang switch (key_length) { 45669d5fd8fSJohnny Huang case 0: 45769d5fd8fSJohnny Huang printf("RSA1024\n"); 45869d5fd8fSJohnny Huang len = 0x100; 45969d5fd8fSJohnny Huang break; 46069d5fd8fSJohnny Huang case 1: 46169d5fd8fSJohnny Huang printf("RSA2048\n"); 46269d5fd8fSJohnny Huang len = 0x200; 46369d5fd8fSJohnny Huang break; 46469d5fd8fSJohnny Huang case 2: 46569d5fd8fSJohnny Huang printf("RSA3072\n"); 46669d5fd8fSJohnny Huang len = 0x300; 46769d5fd8fSJohnny Huang break; 46869d5fd8fSJohnny Huang case 3: 46969d5fd8fSJohnny Huang printf("RSA4096\n"); 47069d5fd8fSJohnny Huang len = 0x400; 47169d5fd8fSJohnny Huang break; 47269d5fd8fSJohnny Huang } 47369d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 47469d5fd8fSJohnny Huang } 47569d5fd8fSJohnny Huang if (key_type == 4 || key_type == 8) 47669d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 47769d5fd8fSJohnny Huang printf("Key Value:\n"); 47869d5fd8fSJohnny Huang if (key_type == 4) { 47969d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 48069d5fd8fSJohnny Huang } else if (key_type == 0 || key_type == 1) { 48169d5fd8fSJohnny Huang printf("AES Key:\n"); 48269d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 48369d5fd8fSJohnny Huang printf("AES IV:\n"); 48469d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 48569d5fd8fSJohnny Huang 48669d5fd8fSJohnny Huang } else { 48769d5fd8fSJohnny Huang printf("RSA mod:\n"); 48869d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 48969d5fd8fSJohnny Huang printf("RSA exp:\n"); 49069d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 49169d5fd8fSJohnny Huang } 49269d5fd8fSJohnny Huang if (last) 49369d5fd8fSJohnny Huang break; 49469d5fd8fSJohnny Huang i++; 49569d5fd8fSJohnny Huang } 49669d5fd8fSJohnny Huang return 0; 49769d5fd8fSJohnny Huang } 49869d5fd8fSJohnny Huang 49969d5fd8fSJohnny Huang static int otp_prog_conf(uint32_t *buf, int otp_addr, int dw_count) 50069d5fd8fSJohnny Huang { 50169d5fd8fSJohnny Huang int i, j, k, bit_value; 50269d5fd8fSJohnny Huang int pass, soak; 50369d5fd8fSJohnny Huang uint32_t prog_bit, prog_address; 50469d5fd8fSJohnny Huang 50569d5fd8fSJohnny Huang for (i = 0; i < dw_count; i++) { 50669d5fd8fSJohnny Huang prog_address = 0x800; 50769d5fd8fSJohnny Huang prog_address |= ((i + otp_addr) / 8) * 0x200; 50869d5fd8fSJohnny Huang prog_address |= ((i + otp_addr) % 8) * 0x2; 50969d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 51069d5fd8fSJohnny Huang bit_value = (buf[i] >> j) & 0x1; 51169d5fd8fSJohnny Huang if (bit_value) 51269d5fd8fSJohnny Huang prog_bit = ~(0x1 << j); 51369d5fd8fSJohnny Huang else 51469d5fd8fSJohnny Huang continue; 51569d5fd8fSJohnny Huang pass = 0; 51669d5fd8fSJohnny Huang soak = 0; 5174b65a65dSJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 5184b65a65dSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 5194b65a65dSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 5204b65a65dSJohnny Huang writel(0x04190760, 0x1e602008); //normal program 52169d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 52269d5fd8fSJohnny Huang if (!soak) { 52369d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 52469d5fd8fSJohnny Huang if (prog_verify(prog_address, j, bit_value) == 0) { 52569d5fd8fSJohnny Huang pass = 1; 52669d5fd8fSJohnny Huang break; 52769d5fd8fSJohnny Huang } 52869d5fd8fSJohnny Huang soak = 1; 5294b65a65dSJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 5304b65a65dSJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 5314b65a65dSJohnny Huang otp_write(0x1000, 0x4820); // Write MR 53269d5fd8fSJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 5334b65a65dSJohnny Huang } 53469d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 53569d5fd8fSJohnny Huang if (prog_verify(prog_address, j, bit_value) == 0) { 53669d5fd8fSJohnny Huang pass = 1; 53769d5fd8fSJohnny Huang break; 53869d5fd8fSJohnny Huang } 53969d5fd8fSJohnny Huang } 54069d5fd8fSJohnny Huang if (!pass) 54169d5fd8fSJohnny Huang return -1; 54269d5fd8fSJohnny Huang } 54369d5fd8fSJohnny Huang } 54469d5fd8fSJohnny Huang return 0; 54569d5fd8fSJohnny Huang } 54669d5fd8fSJohnny Huang 54769d5fd8fSJohnny Huang static void otp_strp_status(struct otpstrap *otpstrap) 54869d5fd8fSJohnny Huang { 54969d5fd8fSJohnny Huang uint32_t OTPSTRAP_RAW[2]; 55069d5fd8fSJohnny Huang int i, j; 55169d5fd8fSJohnny Huang 55269d5fd8fSJohnny Huang for (j = 0; j < 64; j++) { 55369d5fd8fSJohnny Huang otpstrap[j].value = 0; 55469d5fd8fSJohnny Huang otpstrap[j].remain_times = 7; 55569d5fd8fSJohnny Huang otpstrap[j].writeable_option = -1; 55669d5fd8fSJohnny Huang otpstrap[j].protected = 0; 55769d5fd8fSJohnny Huang } 55869d5fd8fSJohnny Huang 55969d5fd8fSJohnny Huang for (i = 16; i < 30; i += 2) { 56069d5fd8fSJohnny Huang int option = (i - 16) / 2; 56169d5fd8fSJohnny Huang otp_read_config(i, &OTPSTRAP_RAW[0]); 56269d5fd8fSJohnny Huang otp_read_config(i + 1, &OTPSTRAP_RAW[1]); 56369d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 56469d5fd8fSJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 56569d5fd8fSJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 56669d5fd8fSJohnny Huang otpstrap[j].writeable_option = option; 56769d5fd8fSJohnny Huang } 56869d5fd8fSJohnny Huang if (bit_value == 1) 56969d5fd8fSJohnny Huang otpstrap[j].remain_times --; 57069d5fd8fSJohnny Huang otpstrap[j].value ^= bit_value; 57169d5fd8fSJohnny Huang otpstrap[j].option_array[option] = bit_value; 57269d5fd8fSJohnny Huang } 57369d5fd8fSJohnny Huang for (j = 32; j < 64; j++) { 57469d5fd8fSJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 57569d5fd8fSJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 57669d5fd8fSJohnny Huang otpstrap[j].writeable_option = option; 57769d5fd8fSJohnny Huang } 57869d5fd8fSJohnny Huang if (bit_value == 1) 57969d5fd8fSJohnny Huang otpstrap[j].remain_times --; 58069d5fd8fSJohnny Huang otpstrap[j].value ^= bit_value; 58169d5fd8fSJohnny Huang otpstrap[j].option_array[option] = bit_value; 58269d5fd8fSJohnny Huang } 58369d5fd8fSJohnny Huang } 58469d5fd8fSJohnny Huang otp_read_config(30, &OTPSTRAP_RAW[0]); 58569d5fd8fSJohnny Huang otp_read_config(31, &OTPSTRAP_RAW[1]); 58669d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 58769d5fd8fSJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 58869d5fd8fSJohnny Huang otpstrap[j].protected = 1; 58969d5fd8fSJohnny Huang } 59069d5fd8fSJohnny Huang for (j = 32; j < 64; j++) { 59169d5fd8fSJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 59269d5fd8fSJohnny Huang otpstrap[j].protected = 1; 59369d5fd8fSJohnny Huang } 59469d5fd8fSJohnny Huang } 59569d5fd8fSJohnny Huang 59669d5fd8fSJohnny Huang static int otp_strap_parse(uint32_t *buf) 59769d5fd8fSJohnny Huang { 59869d5fd8fSJohnny Huang int i; 59969d5fd8fSJohnny Huang uint32_t *strap_keep = buf + 2; 60069d5fd8fSJohnny Huang uint32_t *strap_protect = buf + 4; 60169d5fd8fSJohnny Huang int bit, pbit, kbit; 60269d5fd8fSJohnny Huang int fail = 0; 60369d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 60469d5fd8fSJohnny Huang 60569d5fd8fSJohnny Huang otp_strp_status(otpstrap); 60669d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 60769d5fd8fSJohnny Huang if (i < 32) { 60869d5fd8fSJohnny Huang bit = (buf[0] >> i) & 0x1; 60969d5fd8fSJohnny Huang kbit = (strap_keep[0] >> i) & 0x1; 61069d5fd8fSJohnny Huang pbit = (strap_protect[0] >> i) & 0x1; 61169d5fd8fSJohnny Huang } else { 61269d5fd8fSJohnny Huang bit = (buf[1] >> (i - 32)) & 0x1; 61369d5fd8fSJohnny Huang kbit = (strap_keep[1] >> (i - 32)) & 0x1; 61469d5fd8fSJohnny Huang pbit = (strap_protect[1] >> (i - 32)) & 0x1; 61569d5fd8fSJohnny Huang } 61669d5fd8fSJohnny Huang 61769d5fd8fSJohnny Huang if (kbit == 1) { 61869d5fd8fSJohnny Huang continue; 61969d5fd8fSJohnny Huang } else { 62069d5fd8fSJohnny Huang printf("OTPSTRAP[%d]:\n", i); 62169d5fd8fSJohnny Huang } 62269d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 62369d5fd8fSJohnny Huang printf(" The value is same as before, skip it.\n"); 62469d5fd8fSJohnny Huang continue; 62569d5fd8fSJohnny Huang } 62669d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 62769d5fd8fSJohnny Huang printf(" This bit is protected and is not writable\n"); 62869d5fd8fSJohnny Huang fail = 1; 62969d5fd8fSJohnny Huang continue; 63069d5fd8fSJohnny Huang } 63169d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 63269d5fd8fSJohnny Huang printf(" This bit is no remaining number of times to write.\n"); 63369d5fd8fSJohnny Huang fail = 1; 63469d5fd8fSJohnny Huang continue; 63569d5fd8fSJohnny Huang } 63669d5fd8fSJohnny Huang if (pbit == 1) { 63769d5fd8fSJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 63869d5fd8fSJohnny Huang } 63969d5fd8fSJohnny 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); 64069d5fd8fSJohnny Huang } 64169d5fd8fSJohnny Huang if (fail == 1) 64269d5fd8fSJohnny Huang return -1; 64369d5fd8fSJohnny Huang else 64469d5fd8fSJohnny Huang return 0; 64569d5fd8fSJohnny Huang } 64669d5fd8fSJohnny Huang 64769d5fd8fSJohnny Huang static void otp_print_strap(void) 64869d5fd8fSJohnny Huang { 64969d5fd8fSJohnny Huang int i, j; 65069d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 65169d5fd8fSJohnny Huang 65269d5fd8fSJohnny Huang otp_strp_status(otpstrap); 65369d5fd8fSJohnny Huang 65469d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 65569d5fd8fSJohnny Huang printf("OTPSTRAP[%d]:\n", i); 65669d5fd8fSJohnny Huang printf(" OTP Option value: "); 65769d5fd8fSJohnny Huang for (j = 1; j <= 7; j++) 65869d5fd8fSJohnny Huang printf("[%d]:%d ", j, otpstrap[i].option_array[j - 1]); 65969d5fd8fSJohnny Huang printf("\n"); 66069d5fd8fSJohnny Huang printf(" OTP Value: %d\n", otpstrap[i].value); 66169d5fd8fSJohnny Huang printf(" Status:\n"); 66269d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 66369d5fd8fSJohnny Huang printf(" OTPSTRAP[%d] is protected and is not writable\n", i); 66469d5fd8fSJohnny Huang } else { 66569d5fd8fSJohnny Huang printf(" OTPSTRAP[%d] is not protected ", i); 66669d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 66769d5fd8fSJohnny Huang printf("and no remaining number of times to write.\n"); 66869d5fd8fSJohnny Huang } else { 66969d5fd8fSJohnny Huang printf("and still can write %d number of times\n", otpstrap[i].remain_times); 67069d5fd8fSJohnny Huang } 67169d5fd8fSJohnny Huang } 67269d5fd8fSJohnny Huang } 67369d5fd8fSJohnny Huang } 67469d5fd8fSJohnny Huang 67569d5fd8fSJohnny Huang static int otp_prog_strap(uint32_t *buf) 67669d5fd8fSJohnny Huang { 67769d5fd8fSJohnny Huang int i, j; 67869d5fd8fSJohnny Huang uint32_t *strap_keep = buf + 2; 67969d5fd8fSJohnny Huang uint32_t *strap_protect = buf + 4; 68069d5fd8fSJohnny Huang uint32_t prog_bit, prog_address; 68169d5fd8fSJohnny Huang int bit, pbit, kbit, offset; 68269d5fd8fSJohnny Huang int fail = 0; 68369d5fd8fSJohnny Huang int pass, soak; 68469d5fd8fSJohnny Huang struct otpstrap otpstrap[64]; 68569d5fd8fSJohnny Huang 68669d5fd8fSJohnny Huang otp_strp_status(otpstrap); 68769d5fd8fSJohnny Huang 68869d5fd8fSJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 68969d5fd8fSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 69069d5fd8fSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 69169d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 69269d5fd8fSJohnny Huang prog_address = 0x800; 69369d5fd8fSJohnny Huang if (i < 32) { 69469d5fd8fSJohnny Huang offset = i; 69569d5fd8fSJohnny Huang bit = (buf[0] >> offset) & 0x1; 69669d5fd8fSJohnny Huang kbit = (strap_keep[0] >> offset) & 0x1; 69769d5fd8fSJohnny Huang pbit = (strap_protect[0] >> offset) & 0x1; 69869d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 69969d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 70069d5fd8fSJohnny Huang 70169d5fd8fSJohnny Huang } else { 70269d5fd8fSJohnny Huang offset = (i - 32); 70369d5fd8fSJohnny Huang bit = (buf[1] >> offset) & 0x1; 70469d5fd8fSJohnny Huang kbit = (strap_keep[1] >> offset) & 0x1; 70569d5fd8fSJohnny Huang pbit = (strap_protect[1] >> offset) & 0x1; 70669d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 70769d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 70869d5fd8fSJohnny Huang } 70969d5fd8fSJohnny Huang prog_bit = ~(0x1 << offset); 71069d5fd8fSJohnny Huang 71169d5fd8fSJohnny Huang if (kbit == 1) { 71269d5fd8fSJohnny Huang continue; 71369d5fd8fSJohnny Huang } 71469d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 71569d5fd8fSJohnny Huang continue; 71669d5fd8fSJohnny Huang } 71769d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 71869d5fd8fSJohnny Huang fail = 1; 71969d5fd8fSJohnny Huang continue; 72069d5fd8fSJohnny Huang } 72169d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 72269d5fd8fSJohnny Huang fail = 1; 72369d5fd8fSJohnny Huang continue; 72469d5fd8fSJohnny Huang } 72569d5fd8fSJohnny Huang pass = 0; 72669d5fd8fSJohnny Huang soak = 0; 7274b65a65dSJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 7284b65a65dSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 7294b65a65dSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 7304b65a65dSJohnny Huang writel(0x04190760, 0x1e602008); //normal program 73169d5fd8fSJohnny Huang for (j = 0; j < RETRY; j++) { 73269d5fd8fSJohnny Huang if (!soak) { 73369d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 73469d5fd8fSJohnny Huang if (prog_verify(prog_address, offset, 1) == 0) { 73569d5fd8fSJohnny Huang pass = 1; 73669d5fd8fSJohnny Huang break; 73769d5fd8fSJohnny Huang } 73869d5fd8fSJohnny Huang soak = 1; 7394b65a65dSJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 7404b65a65dSJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 7414b65a65dSJohnny Huang otp_write(0x1000, 0x4820); // Write MR 74269d5fd8fSJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 7434b65a65dSJohnny Huang } 74469d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 74569d5fd8fSJohnny Huang if (prog_verify(prog_address, offset, 1) == 0) { 74669d5fd8fSJohnny Huang pass = 1; 74769d5fd8fSJohnny Huang break; 74869d5fd8fSJohnny Huang } 74969d5fd8fSJohnny Huang } 75069d5fd8fSJohnny Huang if (!pass) 75169d5fd8fSJohnny Huang return -1; 75269d5fd8fSJohnny Huang 75369d5fd8fSJohnny Huang if (pbit == 0) 75469d5fd8fSJohnny Huang continue; 75569d5fd8fSJohnny Huang prog_address = 0x800; 75669d5fd8fSJohnny Huang if (i < 32) 75769d5fd8fSJohnny Huang prog_address |= 0x60c; 75869d5fd8fSJohnny Huang else 75969d5fd8fSJohnny Huang prog_address |= 0x60e; 76069d5fd8fSJohnny Huang 76169d5fd8fSJohnny Huang for (j = 0; j < RETRY; j++) { 76269d5fd8fSJohnny Huang if (!soak) { 76369d5fd8fSJohnny Huang writel(0x04190760, 0x1e602008); //normal program 76469d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 76569d5fd8fSJohnny Huang if (prog_verify(prog_address, offset, 1) == 0) { 76669d5fd8fSJohnny Huang pass = 1; 76769d5fd8fSJohnny Huang break; 76869d5fd8fSJohnny Huang } 76969d5fd8fSJohnny Huang soak = 1; 77069d5fd8fSJohnny Huang } 77169d5fd8fSJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 77269d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 77369d5fd8fSJohnny Huang if (prog_verify(prog_address, offset, 1) == 0) { 77469d5fd8fSJohnny Huang pass = 1; 77569d5fd8fSJohnny Huang break; 77669d5fd8fSJohnny Huang } 77769d5fd8fSJohnny Huang } 77869d5fd8fSJohnny Huang if (!pass) 77969d5fd8fSJohnny Huang return -1; 78069d5fd8fSJohnny Huang 78169d5fd8fSJohnny Huang } 78269d5fd8fSJohnny Huang if (fail == 1) 78369d5fd8fSJohnny Huang return -1; 78469d5fd8fSJohnny Huang else 78569d5fd8fSJohnny Huang return 0; 78669d5fd8fSJohnny Huang 78769d5fd8fSJohnny Huang } 78869d5fd8fSJohnny Huang 78969d5fd8fSJohnny Huang static int otp_prog_data(uint32_t *buf, int otp_addr, int dw_count) 79069d5fd8fSJohnny Huang { 79169d5fd8fSJohnny Huang int i, j, k, bit_value; 79269d5fd8fSJohnny Huang int pass, soak; 79369d5fd8fSJohnny Huang uint32_t prog_bit, prog_address; 79469d5fd8fSJohnny Huang 79569d5fd8fSJohnny Huang for (i = 0; i < dw_count; i++) { 79669d5fd8fSJohnny Huang prog_address = i + otp_addr; 79769d5fd8fSJohnny Huang for (j = 0; j < 32; j++) { 79869d5fd8fSJohnny Huang bit_value = (buf[i] >> j) & 0x1; 79969d5fd8fSJohnny Huang if (prog_address % 2 == 0) { 80069d5fd8fSJohnny Huang prog_address |= 1 << 15; 80169d5fd8fSJohnny Huang if (bit_value) 80269d5fd8fSJohnny Huang prog_bit = ~(0x1 << j); 80369d5fd8fSJohnny Huang else 80469d5fd8fSJohnny Huang continue; 80569d5fd8fSJohnny Huang } else { 80669d5fd8fSJohnny Huang prog_address |= 1 << 15; 80769d5fd8fSJohnny Huang // printf("bit_value = %x\n", bit_value); 80869d5fd8fSJohnny Huang if (bit_value) 80969d5fd8fSJohnny Huang continue; 81069d5fd8fSJohnny Huang else 81169d5fd8fSJohnny Huang prog_bit = 0x1 << j; 81269d5fd8fSJohnny Huang } 81369d5fd8fSJohnny Huang pass = 0; 81469d5fd8fSJohnny Huang soak = 0; 8154b65a65dSJohnny Huang otp_write(0x3000, 0x4061); // Write MRA 8164b65a65dSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 8174b65a65dSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 8184b65a65dSJohnny Huang writel(0x04190760, 0x1e602008); //normal program 81969d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 82069d5fd8fSJohnny Huang if (!soak) { 82169d5fd8fSJohnny Huang // printf("prog_address = %x\n", prog_address); 82269d5fd8fSJohnny Huang // printf("prog_bit = %x\n", prog_bit); 82369d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 82469d5fd8fSJohnny Huang if (prog_verify(prog_address, j, bit_value) == 0) { 82569d5fd8fSJohnny Huang pass = 1; 82669d5fd8fSJohnny Huang break; 82769d5fd8fSJohnny Huang } 82869d5fd8fSJohnny Huang soak = 1; 8294b65a65dSJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 8304b65a65dSJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 8314b65a65dSJohnny Huang otp_write(0x1000, 0x4820); // Write MR 83269d5fd8fSJohnny Huang writel(0x041930d4, 0x1e602008); //soak program 8334b65a65dSJohnny Huang } 83469d5fd8fSJohnny Huang otp_prog(prog_address, prog_bit); 83569d5fd8fSJohnny Huang if (prog_verify(prog_address, j, bit_value) == 0) { 83669d5fd8fSJohnny Huang pass = 1; 83769d5fd8fSJohnny Huang break; 83869d5fd8fSJohnny Huang } 83969d5fd8fSJohnny Huang } 84069d5fd8fSJohnny Huang if (!pass) 84169d5fd8fSJohnny Huang return -1; 84269d5fd8fSJohnny Huang } 84369d5fd8fSJohnny Huang } 84469d5fd8fSJohnny Huang return 0; 84569d5fd8fSJohnny Huang } 84669d5fd8fSJohnny Huang 84769d5fd8fSJohnny Huang static int do_otp_prog(int mode, int addr, int otp_addr, int dw_count, int nconfirm) 84869d5fd8fSJohnny Huang { 84969d5fd8fSJohnny Huang int ret; 85069d5fd8fSJohnny Huang uint32_t *buf; 85169d5fd8fSJohnny Huang 85269d5fd8fSJohnny Huang buf = map_physmem(addr, dw_count * 4, MAP_WRBACK); 85369d5fd8fSJohnny Huang if (!buf) { 85469d5fd8fSJohnny Huang puts("Failed to map physical memory\n"); 85569d5fd8fSJohnny Huang return 1; 85669d5fd8fSJohnny Huang } 85769d5fd8fSJohnny Huang if (!nconfirm) { 85869d5fd8fSJohnny Huang if (mode == MODE_CONF) { 85969d5fd8fSJohnny Huang if (otp_conf_parse(buf) < 0) { 86069d5fd8fSJohnny Huang printf("OTP config error, please check.\n"); 86169d5fd8fSJohnny Huang return -1; 86269d5fd8fSJohnny Huang } 86369d5fd8fSJohnny Huang } else if (mode == MODE_DATA) { 86469d5fd8fSJohnny Huang if (otp_data_parse(buf, dw_count) < 0) { 86569d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 86669d5fd8fSJohnny Huang return -1; 86769d5fd8fSJohnny Huang } 86869d5fd8fSJohnny Huang } else if (mode == MODE_STRAP) { 86969d5fd8fSJohnny Huang if (otp_strap_parse(buf) < 0) { 87069d5fd8fSJohnny Huang printf("OTP strap error, please check.\n"); 87169d5fd8fSJohnny Huang return -1; 87269d5fd8fSJohnny Huang } 87369d5fd8fSJohnny Huang } else if (mode == MODE_ALL) { 87469d5fd8fSJohnny Huang if (otp_conf_parse(buf) < 0) { 87569d5fd8fSJohnny Huang printf("OTP config error, please check.\n"); 87669d5fd8fSJohnny Huang return -1; 87769d5fd8fSJohnny Huang } 87869d5fd8fSJohnny Huang if (otp_strap_parse(&buf[12]) < 0) { 87969d5fd8fSJohnny Huang printf("OTP strap error, please check.\n"); 88069d5fd8fSJohnny Huang return -1; 88169d5fd8fSJohnny Huang } 88269d5fd8fSJohnny Huang if (otp_data_parse(&buf[18], dw_count - 18) < 0) { 88369d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 88469d5fd8fSJohnny Huang return -1; 88569d5fd8fSJohnny Huang } 88669d5fd8fSJohnny Huang } 88769d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 88869d5fd8fSJohnny Huang if (!confirm_yesno()) { 88969d5fd8fSJohnny Huang printf(" Aborting\n"); 89069d5fd8fSJohnny Huang return 1; 89169d5fd8fSJohnny Huang } 89269d5fd8fSJohnny Huang } 89369d5fd8fSJohnny Huang if (mode == MODE_CONF) { 89469d5fd8fSJohnny Huang return otp_prog_conf(buf, otp_addr, dw_count); 89569d5fd8fSJohnny Huang } else if (mode == MODE_STRAP) { 89669d5fd8fSJohnny Huang return otp_prog_strap(buf); 89769d5fd8fSJohnny Huang } else if (mode == MODE_DATA) { 89869d5fd8fSJohnny Huang return otp_prog_data(buf, otp_addr, dw_count); 89969d5fd8fSJohnny Huang } else if (mode == MODE_ALL) { 90069d5fd8fSJohnny Huang printf("programing data region ... "); 90169d5fd8fSJohnny Huang ret = otp_prog_data(&buf[16], 0, dw_count - 18); 90269d5fd8fSJohnny Huang if (ret < 0) { 90369d5fd8fSJohnny Huang printf("Error\n"); 90469d5fd8fSJohnny Huang return ret; 90569d5fd8fSJohnny Huang } else { 90669d5fd8fSJohnny Huang printf("Done\n"); 90769d5fd8fSJohnny Huang } 90869d5fd8fSJohnny Huang printf("programing strap region ... "); 90969d5fd8fSJohnny Huang ret = otp_prog_strap(&buf[12]); 91069d5fd8fSJohnny Huang if (ret < 0) { 91169d5fd8fSJohnny Huang printf("Error\n"); 91269d5fd8fSJohnny Huang return ret; 91369d5fd8fSJohnny Huang } else { 91469d5fd8fSJohnny Huang printf("Done\n"); 91569d5fd8fSJohnny Huang } 91669d5fd8fSJohnny Huang printf("programing configuration region ... "); 91769d5fd8fSJohnny Huang ret = otp_prog_conf(buf, 0, 12); 91869d5fd8fSJohnny Huang if (ret < 0) { 91969d5fd8fSJohnny Huang printf("Error\n"); 92069d5fd8fSJohnny Huang return ret; 92169d5fd8fSJohnny Huang } 92269d5fd8fSJohnny Huang printf("Done\n"); 92369d5fd8fSJohnny Huang return ret; 92469d5fd8fSJohnny Huang } 92569d5fd8fSJohnny Huang return 0; 92669d5fd8fSJohnny Huang } 92769d5fd8fSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, 92869d5fd8fSJohnny Huang char *const argv[]) 92969d5fd8fSJohnny Huang { 93069d5fd8fSJohnny Huang char *cmd; 93169d5fd8fSJohnny Huang int mode = 0; 93269d5fd8fSJohnny Huang int nconfirm = 0; 93369d5fd8fSJohnny Huang uint32_t addr, dw_count, otp_addr; 93469d5fd8fSJohnny Huang 93569d5fd8fSJohnny Huang 93669d5fd8fSJohnny Huang 93769d5fd8fSJohnny Huang if (argc < 2) { 93869d5fd8fSJohnny Huang usage: 93969d5fd8fSJohnny Huang return CMD_RET_USAGE; 94069d5fd8fSJohnny Huang } 94169d5fd8fSJohnny Huang 94269d5fd8fSJohnny Huang cmd = argv[1]; 94369d5fd8fSJohnny Huang if (!strcmp(cmd, "read")) { 94469d5fd8fSJohnny Huang if (!strcmp(argv[2], "conf")) 94569d5fd8fSJohnny Huang mode = MODE_CONF; 94669d5fd8fSJohnny Huang else if (!strcmp(argv[2], "data")) 94769d5fd8fSJohnny Huang mode = MODE_DATA; 94869d5fd8fSJohnny Huang else if (!strcmp(argv[2], "strap")) 94969d5fd8fSJohnny Huang mode = MODE_STRAP; 95069d5fd8fSJohnny Huang else 95169d5fd8fSJohnny Huang goto usage; 95269d5fd8fSJohnny Huang 95369d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 95469d5fd8fSJohnny Huang otp_addr = simple_strtoul(argv[3], NULL, 16); 95569d5fd8fSJohnny Huang dw_count = simple_strtoul(argv[4], NULL, 16); 95669d5fd8fSJohnny Huang if (mode == MODE_CONF) { 95769d5fd8fSJohnny Huang otp_print_config(otp_addr, dw_count); 95869d5fd8fSJohnny Huang } else if (mode == MODE_DATA) { 95969d5fd8fSJohnny Huang otp_print_data(otp_addr, dw_count); 96069d5fd8fSJohnny Huang } else if (mode == MODE_STRAP) { 96169d5fd8fSJohnny Huang otp_print_strap(); 96269d5fd8fSJohnny Huang } 96369d5fd8fSJohnny Huang } else if (!strcmp(cmd, "prog")) { 96469d5fd8fSJohnny Huang if (!strcmp(argv[2], "conf")) 96569d5fd8fSJohnny Huang mode = MODE_CONF; 96669d5fd8fSJohnny Huang else if (!strcmp(argv[2], "strap")) 96769d5fd8fSJohnny Huang mode = MODE_STRAP; 96869d5fd8fSJohnny Huang else if (!strcmp(argv[2], "data")) 96969d5fd8fSJohnny Huang mode = MODE_DATA; 97069d5fd8fSJohnny Huang else if (!strcmp(argv[2], "all")) 97169d5fd8fSJohnny Huang mode = MODE_ALL; 97269d5fd8fSJohnny Huang else 97369d5fd8fSJohnny Huang goto usage; 97469d5fd8fSJohnny Huang 97569d5fd8fSJohnny Huang if (!strcmp(argv[3], "f")) 97669d5fd8fSJohnny Huang nconfirm = 1; 97769d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 97869d5fd8fSJohnny Huang addr = simple_strtoul(argv[3 + nconfirm], NULL, 16); 97969d5fd8fSJohnny Huang otp_addr = simple_strtoul(argv[4 + nconfirm], NULL, 16); 98069d5fd8fSJohnny Huang dw_count = simple_strtoul(argv[5 + nconfirm], NULL, 16); 98169d5fd8fSJohnny Huang return do_otp_prog(mode, addr, otp_addr, dw_count, nconfirm); 98269d5fd8fSJohnny Huang } else if (!strcmp(cmd, "comp")) { 98369d5fd8fSJohnny Huang writel(OTP_PASSWD, 0x1e6f2000); //password 98469d5fd8fSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 98569d5fd8fSJohnny Huang otp_addr = simple_strtoul(argv[3], NULL, 16); 98669d5fd8fSJohnny Huang if (otp_compare(otp_addr, addr) >= 0) { 98769d5fd8fSJohnny Huang printf("Compare pass\n"); 98869d5fd8fSJohnny Huang } else { 98969d5fd8fSJohnny Huang printf("Compare fail\n"); 99069d5fd8fSJohnny Huang } 99169d5fd8fSJohnny Huang } else { 99269d5fd8fSJohnny Huang goto usage; 99369d5fd8fSJohnny Huang } 99469d5fd8fSJohnny Huang 99569d5fd8fSJohnny Huang 99669d5fd8fSJohnny Huang return 0; 99769d5fd8fSJohnny Huang } 99869d5fd8fSJohnny Huang 99969d5fd8fSJohnny Huang 100069d5fd8fSJohnny Huang U_BOOT_CMD( 100169d5fd8fSJohnny Huang otp, 7, 0, do_ast_otp, 100269d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 100369d5fd8fSJohnny Huang "read conf|strap|data <otp_addr> <dw_count>\n" 100469d5fd8fSJohnny Huang "otp prog conf|strap|data|all [f] <addr> <otp_addr> <dw_count>\n" 100569d5fd8fSJohnny Huang "otp comp <addr> <otp_addr>" 100669d5fd8fSJohnny Huang ); 1007