169d5fd8fSJohnny Huang /* 269d5fd8fSJohnny Huang * This program is distributed in the hope that it will be useful, 369d5fd8fSJohnny Huang * but WITHOUT ANY WARRANTY; without even the implied warranty of 469d5fd8fSJohnny Huang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 569d5fd8fSJohnny Huang * GNU General Public License for more details. 669d5fd8fSJohnny Huang * 769d5fd8fSJohnny Huang * You should have received a copy of the GNU General Public License 869d5fd8fSJohnny Huang * along with this program; if not, write to the Free Software 969d5fd8fSJohnny Huang * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1069d5fd8fSJohnny Huang */ 114c1c9b35SJohnny Huang #include <stdlib.h> 1269d5fd8fSJohnny Huang #include <common.h> 1369d5fd8fSJohnny Huang #include <console.h> 1469d5fd8fSJohnny Huang #include <bootretry.h> 1569d5fd8fSJohnny Huang #include <cli.h> 1669d5fd8fSJohnny Huang #include <command.h> 1769d5fd8fSJohnny Huang #include <console.h> 184c1c9b35SJohnny Huang #include <malloc.h> 1969d5fd8fSJohnny Huang #include <inttypes.h> 2069d5fd8fSJohnny Huang #include <mapmem.h> 2169d5fd8fSJohnny Huang #include <asm/io.h> 2269d5fd8fSJohnny Huang #include <linux/compiler.h> 23696656c6SJohnny Huang #include <u-boot/sha256.h> 240cee9a95SJohnny Huang #include "otp_info.h" 2569d5fd8fSJohnny Huang 2669d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR; 2769d5fd8fSJohnny Huang 2864b66712SJohnny Huang #define OTP_VER "1.0.3" 29f67375f7SJohnny Huang 3069d5fd8fSJohnny Huang #define OTP_PASSWD 0x349fe38a 31dacbba92SJohnny Huang #define RETRY 20 327332532cSJohnny Huang #define OTP_REGION_STRAP BIT(0) 337332532cSJohnny Huang #define OTP_REGION_CONF BIT(1) 347332532cSJohnny Huang #define OTP_REGION_DATA BIT(2) 3569d5fd8fSJohnny Huang 362a856b9aSJohnny Huang #define OTP_USAGE -1 372a856b9aSJohnny Huang #define OTP_FAILURE -2 382a856b9aSJohnny Huang #define OTP_SUCCESS 0 392a856b9aSJohnny Huang 40a6af4a17SJohnny Huang #define OTP_PROG_SKIP 1 41a6af4a17SJohnny Huang 42*181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB 1 43*181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV 2 44*181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES 3 45*181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT 4 46*181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC 5 479a4fe690SJohnny Huang 484c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" 494c1c9b35SJohnny Huang #define PBWIDTH 60 504c1c9b35SJohnny Huang 513d3688adSJohnny Huang #define OTP_BASE 0x1e6f2000 523d3688adSJohnny Huang #define OTP_PROTECT_KEY OTP_BASE 533d3688adSJohnny Huang #define OTP_COMMAND OTP_BASE + 0x4 543d3688adSJohnny Huang #define OTP_TIMING OTP_BASE + 0x8 553d3688adSJohnny Huang #define OTP_ADDR OTP_BASE + 0x10 563d3688adSJohnny Huang #define OTP_STATUS OTP_BASE + 0x14 573d3688adSJohnny Huang #define OTP_COMPARE_1 OTP_BASE + 0x20 583d3688adSJohnny Huang #define OTP_COMPARE_2 OTP_BASE + 0x24 593d3688adSJohnny Huang #define OTP_COMPARE_3 OTP_BASE + 0x28 603d3688adSJohnny Huang #define OTP_COMPARE_4 OTP_BASE + 0x2c 613d3688adSJohnny Huang 62696656c6SJohnny Huang #define OTP_MAGIC "SOCOTP" 63696656c6SJohnny Huang #define CHECKSUM_LEN 32 64696656c6SJohnny Huang #define OTP_INC_DATA (1 << 31) 65696656c6SJohnny Huang #define OTP_INC_CONFIG (1 << 30) 66696656c6SJohnny Huang #define OTP_INC_STRAP (1 << 29) 67696656c6SJohnny Huang #define OTP_ECC_EN (1 << 28) 68696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff) 69696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff) 70696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff) 71696656c6SJohnny Huang 72696656c6SJohnny Huang #define OTP_AST2600A0 0 73696656c6SJohnny Huang #define OTP_AST2600A1 1 740dae9d52SJohnny Huang #define OTP_AST2600A2 2 7564b66712SJohnny Huang #define OTP_AST2600A3 3 76696656c6SJohnny Huang 77696656c6SJohnny Huang struct otp_header { 78696656c6SJohnny Huang u8 otp_magic[8]; 79696656c6SJohnny Huang u8 otp_version[8]; 80696656c6SJohnny Huang u32 image_info; 81696656c6SJohnny Huang u32 data_info; 82696656c6SJohnny Huang u32 config_info; 83696656c6SJohnny Huang u32 strap_info; 84696656c6SJohnny Huang u32 checksum_offset; 85696656c6SJohnny Huang } __attribute__((packed)); 86696656c6SJohnny Huang 8766f2f8e5SJohnny Huang struct otpstrap_status { 8869d5fd8fSJohnny Huang int value; 8969d5fd8fSJohnny Huang int option_array[7]; 9069d5fd8fSJohnny Huang int remain_times; 9169d5fd8fSJohnny Huang int writeable_option; 925010032bSJohnny Huang int reg_protected; 9369d5fd8fSJohnny Huang int protected; 9469d5fd8fSJohnny Huang }; 9569d5fd8fSJohnny Huang 9666f2f8e5SJohnny Huang struct otpconf_parse { 9766f2f8e5SJohnny Huang int dw_offset; 9866f2f8e5SJohnny Huang int bit; 9966f2f8e5SJohnny Huang int length; 10066f2f8e5SJohnny Huang int value; 101696656c6SJohnny Huang int ignore; 10266f2f8e5SJohnny Huang char status[80]; 10366f2f8e5SJohnny Huang }; 10466f2f8e5SJohnny Huang 1059a4fe690SJohnny Huang struct otpkey_type { 1069a4fe690SJohnny Huang int value; 1079a4fe690SJohnny Huang int key_type; 1089a4fe690SJohnny Huang int need_id; 1099a4fe690SJohnny Huang char information[110]; 1109a4fe690SJohnny Huang }; 1119a4fe690SJohnny Huang 1129a4fe690SJohnny Huang struct otp_info_cb { 1139a4fe690SJohnny Huang int version; 11479e42a59SJoel Stanley const struct otpstrap_info *strap_info; 1159a4fe690SJohnny Huang int strap_info_len; 11679e42a59SJoel Stanley const struct otpconf_info *conf_info; 1179a4fe690SJohnny Huang int conf_info_len; 11879e42a59SJoel Stanley const struct otpkey_type *key_info; 1199a4fe690SJohnny Huang int key_info_len; 1205010032bSJohnny Huang 1219a4fe690SJohnny Huang }; 1229a4fe690SJohnny Huang 123696656c6SJohnny Huang struct otp_image_layout { 1245010032bSJohnny Huang int data_length; 1255010032bSJohnny Huang int conf_length; 1265010032bSJohnny Huang int strap_length; 127696656c6SJohnny Huang uint8_t *data; 128696656c6SJohnny Huang uint8_t *data_ignore; 129696656c6SJohnny Huang uint8_t *conf; 130696656c6SJohnny Huang uint8_t *conf_ignore; 131696656c6SJohnny Huang uint8_t *strap; 132696656c6SJohnny Huang uint8_t *strap_reg_pro; 133696656c6SJohnny Huang uint8_t *strap_pro; 134696656c6SJohnny Huang uint8_t *strap_ignore; 135696656c6SJohnny Huang }; 136696656c6SJohnny Huang 1379a4fe690SJohnny Huang static struct otp_info_cb info_cb; 1389a4fe690SJohnny Huang 13979e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 1409a4fe690SJohnny Huang {0, OTP_KEY_TYPE_AES, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 1419a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1429a4fe690SJohnny Huang {4, OTP_KEY_TYPE_HMAC, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 143*181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 144*181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as SOC public key"}, 145*181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 146*181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as SOC private key"}, 147*181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1489a4fe690SJohnny Huang }; 1499a4fe690SJohnny Huang 15079e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = { 1519a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1529a4fe690SJohnny Huang {2, OTP_KEY_TYPE_AES, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"}, 153*181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 154*181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 155*181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1569a4fe690SJohnny Huang }; 1579a4fe690SJohnny Huang 1585fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = { 1595fdde29fSJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1605fdde29fSJohnny Huang {2, OTP_KEY_TYPE_AES, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"}, 161*181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 162*181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 163*181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 164*181f72d8SJohnny Huang }; 165*181f72d8SJohnny Huang 166*181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = { 167*181f72d8SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 168*181f72d8SJohnny Huang {2, OTP_KEY_TYPE_AES, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"}, 169*181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 170*181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"}, 171*181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 172*181f72d8SJohnny Huang {11, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key(big endian)"}, 173*181f72d8SJohnny Huang {12, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 174*181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key(big endian)"}, 1755fdde29fSJohnny Huang }; 1765fdde29fSJohnny Huang 1779a4fe690SJohnny Huang static uint32_t chip_version(void) 1789a4fe690SJohnny Huang { 179badd21c2SJohnny Huang u64 rev_id; 1809a4fe690SJohnny Huang 181badd21c2SJohnny Huang rev_id = readl(ASPEED_REVISION_ID0); 182badd21c2SJohnny Huang rev_id = ((u64)readl(ASPEED_REVISION_ID1) << 32) | rev_id; 1839a4fe690SJohnny Huang 184badd21c2SJohnny Huang if (rev_id == 0x0500030305000303) { 185badd21c2SJohnny Huang /* AST2600-A0 */ 1860dae9d52SJohnny Huang return OTP_AST2600A0; 187badd21c2SJohnny Huang } else if (rev_id == 0x0501030305010303) { 188badd21c2SJohnny Huang /* AST2600-A1 */ 1890dae9d52SJohnny Huang return OTP_AST2600A1; 190badd21c2SJohnny Huang } else if (rev_id == 0x0501020305010203) { 191badd21c2SJohnny Huang /* AST2620-A1 */ 192badd21c2SJohnny Huang return OTP_AST2600A1; 193badd21c2SJohnny Huang } else if (rev_id == 0x0502030305010303) { 194badd21c2SJohnny Huang /* AST2600-A2 */ 1950dae9d52SJohnny Huang return OTP_AST2600A2; 196badd21c2SJohnny Huang } else if (rev_id == 0x0502020305010203) { 197badd21c2SJohnny Huang /* AST2620-A2 */ 198badd21c2SJohnny Huang return OTP_AST2600A2; 199badd21c2SJohnny Huang } else if (rev_id == 0x0502010305010103) { 200badd21c2SJohnny Huang /* AST2605-A2 */ 2010dae9d52SJohnny Huang return OTP_AST2600A2; 20264b66712SJohnny Huang } else if (rev_id == 0x0503030305030303) { 20364b66712SJohnny Huang /* AST2600-A3 */ 20464b66712SJohnny Huang return OTP_AST2600A3; 20564b66712SJohnny Huang } else if (rev_id == 0x0503020305030203) { 20664b66712SJohnny Huang /* AST2620-A3 */ 20764b66712SJohnny Huang return OTP_AST2600A3; 2080dae9d52SJohnny Huang } 2090dae9d52SJohnny Huang 2105fdde29fSJohnny Huang return -1; 2119a4fe690SJohnny Huang } 2129a4fe690SJohnny Huang 2133d3688adSJohnny Huang static void wait_complete(void) 2143d3688adSJohnny Huang { 2153d3688adSJohnny Huang int reg; 2163d3688adSJohnny Huang 2173d3688adSJohnny Huang do { 2183d3688adSJohnny Huang reg = readl(OTP_STATUS); 2193d3688adSJohnny Huang } while ((reg & 0x6) != 0x6); 2203d3688adSJohnny Huang } 2213d3688adSJohnny Huang 222dacbba92SJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data) 223dacbba92SJohnny Huang { 224dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 225dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 226dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 227dacbba92SJohnny Huang wait_complete(); 228dacbba92SJohnny Huang } 229dacbba92SJohnny Huang 230dacbba92SJohnny Huang static void otp_soak(int soak) 231dacbba92SJohnny Huang { 23264b66712SJohnny Huang if (info_cb.version == OTP_AST2600A2 || info_cb.version == OTP_AST2600A3) { 233dacbba92SJohnny Huang switch (soak) { 234dacbba92SJohnny Huang case 0: //default 235dacbba92SJohnny Huang otp_write(0x3000, 0x0210); // Write MRA 236dacbba92SJohnny Huang otp_write(0x5000, 0x2000); // Write MRB 237dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 238dacbba92SJohnny Huang break; 239dacbba92SJohnny Huang case 1: //normal program 240dacbba92SJohnny Huang otp_write(0x3000, 0x1200); // Write MRA 241feea3fdfSJohnny Huang otp_write(0x5000, 0x107F); // Write MRB 242dacbba92SJohnny Huang otp_write(0x1000, 0x1024); // Write MR 243feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 244dacbba92SJohnny Huang break; 245dacbba92SJohnny Huang case 2: //soak program 246dacbba92SJohnny Huang otp_write(0x3000, 0x1220); // Write MRA 247feea3fdfSJohnny Huang otp_write(0x5000, 0x2074); // Write MRB 248dacbba92SJohnny Huang otp_write(0x1000, 0x08a4); // Write MR 249feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 250dacbba92SJohnny Huang break; 251dacbba92SJohnny Huang } 252dacbba92SJohnny Huang } else { 253dacbba92SJohnny Huang switch (soak) { 254dacbba92SJohnny Huang case 0: //default 255dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 256dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 257dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 258dacbba92SJohnny Huang break; 259dacbba92SJohnny Huang case 1: //normal program 260dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 261dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 262dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 263feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 264dacbba92SJohnny Huang break; 265dacbba92SJohnny Huang case 2: //soak program 266dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 267dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 268dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 269feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 270dacbba92SJohnny Huang break; 271dacbba92SJohnny Huang } 272dacbba92SJohnny Huang } 273dacbba92SJohnny Huang 274dacbba92SJohnny Huang wait_complete(); 275dacbba92SJohnny Huang } 276dacbba92SJohnny Huang 2772a856b9aSJohnny Huang static void otp_read_data(uint32_t offset, uint32_t *data) 27869d5fd8fSJohnny Huang { 2793d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 2803d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 2813d3688adSJohnny Huang wait_complete(); 2823d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 2833d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 28469d5fd8fSJohnny Huang } 28569d5fd8fSJohnny Huang 2862a856b9aSJohnny Huang static void otp_read_config(uint32_t offset, uint32_t *data) 28769d5fd8fSJohnny Huang { 28869d5fd8fSJohnny Huang int config_offset; 28969d5fd8fSJohnny Huang 29069d5fd8fSJohnny Huang config_offset = 0x800; 29169d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 29269d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 29369d5fd8fSJohnny Huang 2943d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 2953d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 2963d3688adSJohnny Huang wait_complete(); 2973d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 29869d5fd8fSJohnny Huang } 29969d5fd8fSJohnny Huang 30069d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count) 30169d5fd8fSJohnny Huang { 30269d5fd8fSJohnny Huang int i; 30369d5fd8fSJohnny Huang uint32_t ret[1]; 30469d5fd8fSJohnny Huang 30569d5fd8fSJohnny Huang if (offset + dw_count > 32) 3062a856b9aSJohnny Huang return OTP_USAGE; 307dacbba92SJohnny Huang otp_soak(0); 30869d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i ++) { 30969d5fd8fSJohnny Huang otp_read_config(i, ret); 310a6af4a17SJohnny Huang printf("OTPCFG%X: %08X\n", i, ret[0]); 31169d5fd8fSJohnny Huang } 31269d5fd8fSJohnny Huang printf("\n"); 3132a856b9aSJohnny Huang return OTP_SUCCESS; 31469d5fd8fSJohnny Huang } 31569d5fd8fSJohnny Huang 31669d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count) 31769d5fd8fSJohnny Huang { 31869d5fd8fSJohnny Huang int i; 31969d5fd8fSJohnny Huang uint32_t ret[2]; 32069d5fd8fSJohnny Huang 32169d5fd8fSJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 3222a856b9aSJohnny Huang return OTP_USAGE; 323dacbba92SJohnny Huang otp_soak(0); 32469d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 32569d5fd8fSJohnny Huang otp_read_data(i, ret); 32669d5fd8fSJohnny Huang if (i % 4 == 0) 32769d5fd8fSJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 32869d5fd8fSJohnny Huang else 32969d5fd8fSJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 33069d5fd8fSJohnny Huang 33169d5fd8fSJohnny Huang } 33269d5fd8fSJohnny Huang printf("\n"); 3332a856b9aSJohnny Huang return OTP_SUCCESS; 33469d5fd8fSJohnny Huang } 33569d5fd8fSJohnny Huang 33669d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr) 33769d5fd8fSJohnny Huang { 33869d5fd8fSJohnny Huang uint32_t ret; 33969d5fd8fSJohnny Huang uint32_t *buf; 34069d5fd8fSJohnny Huang 34169d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 34269d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 34369d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 34469d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 34569d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 3463d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 3473d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 3483d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 3493d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 3503d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 3513d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 3523d3688adSJohnny Huang wait_complete(); 3533d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 35469d5fd8fSJohnny Huang if (ret & 0x1) 35569d5fd8fSJohnny Huang return 0; 35669d5fd8fSJohnny Huang else 35769d5fd8fSJohnny Huang return -1; 35869d5fd8fSJohnny Huang } 35969d5fd8fSJohnny Huang 360a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value) 36169d5fd8fSJohnny Huang { 36230a8c590SJohnny Huang uint32_t ret[2]; 36369d5fd8fSJohnny Huang 36430a8c590SJohnny Huang if (otp_addr % 2 == 0) 3653d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 36630a8c590SJohnny Huang else 3673d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 36830a8c590SJohnny Huang 3693d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3703d3688adSJohnny Huang wait_complete(); 3713d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 3723d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 37383655e91SJohnny Huang 37430a8c590SJohnny Huang if (otp_addr % 2 == 0) { 37530a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 37669d5fd8fSJohnny Huang return 0; 37769d5fd8fSJohnny Huang else 37869d5fd8fSJohnny Huang return -1; 37930a8c590SJohnny Huang } else { 38030a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 38130a8c590SJohnny Huang return 0; 38230a8c590SJohnny Huang else 38330a8c590SJohnny Huang return -1; 38430a8c590SJohnny Huang } 38530a8c590SJohnny Huang 38669d5fd8fSJohnny Huang } 38769d5fd8fSJohnny Huang 388696656c6SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *ignore, uint32_t *compare, int size) 3894c1c9b35SJohnny Huang { 3904c1c9b35SJohnny Huang uint32_t ret[2]; 3914c1c9b35SJohnny Huang 3924c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 3934c1c9b35SJohnny Huang 3944c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 3953d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 3964c1c9b35SJohnny Huang else 3973d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 3983d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3993d3688adSJohnny Huang wait_complete(); 4003d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4013d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 4024c1c9b35SJohnny Huang if (size == 1) { 4034c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 4044c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 405696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 4064c1c9b35SJohnny Huang compare[0] = 0; 4074c1c9b35SJohnny Huang return 0; 4084c1c9b35SJohnny Huang } else { 4094c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4104c1c9b35SJohnny Huang return -1; 4114c1c9b35SJohnny Huang } 4124c1c9b35SJohnny Huang 4134c1c9b35SJohnny Huang } else { 4144c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 415696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 4164c1c9b35SJohnny Huang compare[0] = ~0; 4174c1c9b35SJohnny Huang return 0; 4184c1c9b35SJohnny Huang } else { 419d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 4204c1c9b35SJohnny Huang return -1; 4214c1c9b35SJohnny Huang } 4224c1c9b35SJohnny Huang } 4234c1c9b35SJohnny Huang } else if (size == 2) { 4244c1c9b35SJohnny Huang // otp_addr should be even 425696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 4264c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4274c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4284c1c9b35SJohnny Huang compare[0] = 0; 4294c1c9b35SJohnny Huang compare[1] = ~0; 4304c1c9b35SJohnny Huang return 0; 4314c1c9b35SJohnny Huang } else { 4324c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4334c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4344c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4354c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 4364c1c9b35SJohnny Huang return -1; 4374c1c9b35SJohnny Huang } 4384c1c9b35SJohnny Huang } else { 4394c1c9b35SJohnny Huang return -1; 4404c1c9b35SJohnny Huang } 4414c1c9b35SJohnny Huang } 4424c1c9b35SJohnny Huang 44383655e91SJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit) 44483655e91SJohnny Huang { 44590965bb3SJohnny Huang otp_write(0x0, prog_bit); 44683655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 44783655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 44883655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 44983655e91SJohnny Huang wait_complete(); 45083655e91SJohnny Huang } 45183655e91SJohnny Huang 45283655e91SJohnny Huang static void _otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset) 45383655e91SJohnny Huang { 45483655e91SJohnny Huang int prog_bit; 45583655e91SJohnny Huang 45683655e91SJohnny Huang if (prog_address % 2 == 0) { 45783655e91SJohnny Huang if (value) 45883655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 45983655e91SJohnny Huang else 46083655e91SJohnny Huang return; 46183655e91SJohnny Huang } else { 46264b66712SJohnny Huang if (info_cb.version != OTP_AST2600A3) 46383655e91SJohnny Huang prog_address |= 1 << 15; 46483655e91SJohnny Huang if (!value) 46583655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 46683655e91SJohnny Huang else 46783655e91SJohnny Huang return; 46883655e91SJohnny Huang } 46983655e91SJohnny Huang otp_prog(prog_address, prog_bit); 47083655e91SJohnny Huang } 47183655e91SJohnny Huang 47283655e91SJohnny Huang static int otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset) 47383655e91SJohnny Huang { 47483655e91SJohnny Huang int pass; 47583655e91SJohnny Huang int i; 47683655e91SJohnny Huang 47783655e91SJohnny Huang otp_soak(1); 47883655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 47983655e91SJohnny Huang pass = 0; 48083655e91SJohnny Huang 48183655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 48283655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 48383655e91SJohnny Huang otp_soak(2); 48483655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 48583655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 48683655e91SJohnny Huang otp_soak(1); 48783655e91SJohnny Huang } else { 48883655e91SJohnny Huang pass = 1; 48983655e91SJohnny Huang break; 49083655e91SJohnny Huang } 49183655e91SJohnny Huang } else { 49283655e91SJohnny Huang pass = 1; 49383655e91SJohnny Huang break; 49483655e91SJohnny Huang } 49583655e91SJohnny Huang } 49683655e91SJohnny Huang 49783655e91SJohnny Huang return pass; 49883655e91SJohnny Huang } 49983655e91SJohnny Huang 500696656c6SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t ignore, uint32_t prog_address) 501d90825e2SJohnny Huang { 502d90825e2SJohnny Huang int j, bit_value, prog_bit; 503d90825e2SJohnny Huang 504d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 505696656c6SJohnny Huang if ((ignore >> j) & 0x1) 506d90825e2SJohnny Huang continue; 507d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 508d90825e2SJohnny Huang if (prog_address % 2 == 0) { 509d90825e2SJohnny Huang if (bit_value) 510d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 511d90825e2SJohnny Huang else 512d90825e2SJohnny Huang continue; 513d90825e2SJohnny Huang } else { 51464b66712SJohnny Huang if (info_cb.version != OTP_AST2600A3) 515d90825e2SJohnny Huang prog_address |= 1 << 15; 516d90825e2SJohnny Huang if (bit_value) 517d90825e2SJohnny Huang continue; 518d90825e2SJohnny Huang else 519d90825e2SJohnny Huang prog_bit = 0x1 << j; 520d90825e2SJohnny Huang } 521d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 522d90825e2SJohnny Huang } 523d90825e2SJohnny Huang } 524d90825e2SJohnny Huang 52554552c69SJohnny Huang static int otp_prog_verify_2dw(uint32_t *data, uint32_t *buf, uint32_t *ignore_mask, uint32_t prog_address) 52654552c69SJohnny Huang { 52754552c69SJohnny Huang int pass; 52854552c69SJohnny Huang int i; 52954552c69SJohnny Huang uint32_t data0_masked; 53054552c69SJohnny Huang uint32_t data1_masked; 53154552c69SJohnny Huang uint32_t buf0_masked; 53254552c69SJohnny Huang uint32_t buf1_masked; 53354552c69SJohnny Huang uint32_t compare[2]; 53454552c69SJohnny Huang 53554552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 53654552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 53754552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 53854552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 53954552c69SJohnny Huang if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked)) 54054552c69SJohnny Huang return 0; 54154552c69SJohnny Huang 54254552c69SJohnny Huang otp_soak(1); 54354552c69SJohnny Huang if (data0_masked != buf0_masked) 54454552c69SJohnny Huang otp_prog_dw(buf[0], ignore_mask[0], prog_address); 54554552c69SJohnny Huang if (data1_masked != buf1_masked) 54654552c69SJohnny Huang otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 54754552c69SJohnny Huang 54854552c69SJohnny Huang pass = 0; 54954552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 55054552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 55154552c69SJohnny Huang otp_soak(2); 55254552c69SJohnny Huang if (compare[0] != 0) { 55354552c69SJohnny Huang otp_prog_dw(compare[0], ignore_mask[0], prog_address); 55454552c69SJohnny Huang } 55554552c69SJohnny Huang if (compare[1] != ~0) { 5565537bc72SJohnny Huang otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 55754552c69SJohnny Huang } 55854552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 55954552c69SJohnny Huang otp_soak(1); 56054552c69SJohnny Huang } else { 56154552c69SJohnny Huang pass = 1; 56254552c69SJohnny Huang break; 56354552c69SJohnny Huang } 56454552c69SJohnny Huang } else { 56554552c69SJohnny Huang pass = 1; 56654552c69SJohnny Huang break; 56754552c69SJohnny Huang } 56854552c69SJohnny Huang } 56954552c69SJohnny Huang 57054552c69SJohnny Huang if (!pass) { 57154552c69SJohnny Huang otp_soak(0); 57254552c69SJohnny Huang return OTP_FAILURE; 57354552c69SJohnny Huang } 57454552c69SJohnny Huang return OTP_SUCCESS; 57554552c69SJohnny Huang } 57654552c69SJohnny Huang 577541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 57876d13988SJohnny Huang { 57976d13988SJohnny Huang uint32_t OTPSTRAP_RAW[2]; 5805010032bSJohnny Huang int strap_end; 58176d13988SJohnny Huang int i, j; 58276d13988SJohnny Huang 5835010032bSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 58476d13988SJohnny Huang for (j = 0; j < 64; j++) { 58576d13988SJohnny Huang otpstrap[j].value = 0; 58676d13988SJohnny Huang otpstrap[j].remain_times = 7; 58776d13988SJohnny Huang otpstrap[j].writeable_option = -1; 58876d13988SJohnny Huang otpstrap[j].protected = 0; 58976d13988SJohnny Huang } 5905010032bSJohnny Huang strap_end = 30; 5915010032bSJohnny Huang } else { 5925010032bSJohnny Huang for (j = 0; j < 64; j++) { 5935010032bSJohnny Huang otpstrap[j].value = 0; 5945010032bSJohnny Huang otpstrap[j].remain_times = 6; 5955010032bSJohnny Huang otpstrap[j].writeable_option = -1; 5965010032bSJohnny Huang otpstrap[j].reg_protected = 0; 5975010032bSJohnny Huang otpstrap[j].protected = 0; 5985010032bSJohnny Huang } 5995010032bSJohnny Huang strap_end = 28; 6005010032bSJohnny Huang } 60176d13988SJohnny Huang 602dacbba92SJohnny Huang otp_soak(0); 6035010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 60476d13988SJohnny Huang int option = (i - 16) / 2; 60576d13988SJohnny Huang otp_read_config(i, &OTPSTRAP_RAW[0]); 60676d13988SJohnny Huang otp_read_config(i + 1, &OTPSTRAP_RAW[1]); 60776d13988SJohnny Huang for (j = 0; j < 32; j++) { 60876d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 60976d13988SJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 61076d13988SJohnny Huang otpstrap[j].writeable_option = option; 61176d13988SJohnny Huang } 61276d13988SJohnny Huang if (bit_value == 1) 61376d13988SJohnny Huang otpstrap[j].remain_times --; 61476d13988SJohnny Huang otpstrap[j].value ^= bit_value; 61576d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 61676d13988SJohnny Huang } 61776d13988SJohnny Huang for (j = 32; j < 64; j++) { 61876d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 61976d13988SJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 62076d13988SJohnny Huang otpstrap[j].writeable_option = option; 62176d13988SJohnny Huang } 62276d13988SJohnny Huang if (bit_value == 1) 62376d13988SJohnny Huang otpstrap[j].remain_times --; 62476d13988SJohnny Huang otpstrap[j].value ^= bit_value; 62576d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 62676d13988SJohnny Huang } 62776d13988SJohnny Huang } 6285010032bSJohnny Huang 6295010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 6305010032bSJohnny Huang otp_read_config(28, &OTPSTRAP_RAW[0]); 6315010032bSJohnny Huang otp_read_config(29, &OTPSTRAP_RAW[1]); 6325010032bSJohnny Huang for (j = 0; j < 32; j++) { 6335010032bSJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 6345010032bSJohnny Huang otpstrap[j].reg_protected = 1; 6355010032bSJohnny Huang } 6365010032bSJohnny Huang for (j = 32; j < 64; j++) { 6375010032bSJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 6385010032bSJohnny Huang otpstrap[j].reg_protected = 1; 6395010032bSJohnny Huang } 6405010032bSJohnny Huang 6415010032bSJohnny Huang } 6425010032bSJohnny Huang 64376d13988SJohnny Huang otp_read_config(30, &OTPSTRAP_RAW[0]); 64476d13988SJohnny Huang otp_read_config(31, &OTPSTRAP_RAW[1]); 64576d13988SJohnny Huang for (j = 0; j < 32; j++) { 64676d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 64776d13988SJohnny Huang otpstrap[j].protected = 1; 64876d13988SJohnny Huang } 64976d13988SJohnny Huang for (j = 32; j < 64; j++) { 65076d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 65176d13988SJohnny Huang otpstrap[j].protected = 1; 65276d13988SJohnny Huang } 65376d13988SJohnny Huang } 65476d13988SJohnny Huang 655696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 65669d5fd8fSJohnny Huang { 65779e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 658696656c6SJohnny Huang uint32_t *OTPCFG = (uint32_t *)image_layout->conf; 659696656c6SJohnny Huang uint32_t *OTPCFG_IGNORE = (uint32_t *)image_layout->conf_ignore; 660b458cd62SJohnny Huang uint32_t mask; 661b458cd62SJohnny Huang uint32_t dw_offset; 662b458cd62SJohnny Huang uint32_t bit_offset; 663b458cd62SJohnny Huang uint32_t otp_value; 664696656c6SJohnny Huang uint32_t otp_ignore; 665b458cd62SJohnny Huang int fail = 0; 66673f11549SJohnny Huang char valid_bit[20]; 66766f2f8e5SJohnny Huang int i; 66873f11549SJohnny Huang int j; 66966f2f8e5SJohnny Huang 670737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 67166f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 6723cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 6733cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 6743cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 6753cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 676b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 677696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 678b458cd62SJohnny Huang 679696656c6SJohnny Huang if (otp_ignore == mask) { 680b458cd62SJohnny Huang continue; 681696656c6SJohnny Huang } else if (otp_ignore != 0) { 682b458cd62SJohnny Huang fail = 1; 683b458cd62SJohnny Huang } 684b458cd62SJohnny Huang 6853cb28812SJohnny Huang if ((otp_value != conf_info[i].value) && 6863cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 6873cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 6883cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 689b458cd62SJohnny Huang continue; 690b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 691b458cd62SJohnny Huang 6923cb28812SJohnny Huang if (conf_info[i].length == 1) { 6933cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 69466f2f8e5SJohnny Huang } else { 695b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 6963cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 6973cb28812SJohnny Huang conf_info[i].bit_offset); 69866f2f8e5SJohnny Huang } 699b458cd62SJohnny Huang printf("0x%-10x", otp_value); 700b458cd62SJohnny Huang 701b458cd62SJohnny Huang if (fail) { 702696656c6SJohnny Huang printf("Ignore mask error\n"); 703b458cd62SJohnny Huang } else { 7043cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 705b458cd62SJohnny Huang printf("Reserved\n"); 7063cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 7073cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 708b458cd62SJohnny Huang printf("\n"); 7093cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 710b458cd62SJohnny Huang if (otp_value != 0) { 71173f11549SJohnny Huang for (j = 0; j < 7; j++) { 71273f11549SJohnny Huang if (otp_value == (1 << j)) { 71373f11549SJohnny Huang valid_bit[j * 2] = '1'; 714b458cd62SJohnny Huang } else { 71573f11549SJohnny Huang valid_bit[j * 2] = '0'; 71673f11549SJohnny Huang } 71773f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 71873f11549SJohnny Huang } 71973f11549SJohnny Huang valid_bit[15] = 0; 72073f11549SJohnny Huang } else { 72173f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 722b458cd62SJohnny Huang } 7233cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 724b458cd62SJohnny Huang printf("\n"); 725b458cd62SJohnny Huang } else { 7263cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 727b458cd62SJohnny Huang } 728b458cd62SJohnny Huang } 729b458cd62SJohnny Huang } 730b458cd62SJohnny Huang 731b458cd62SJohnny Huang if (fail) 732b458cd62SJohnny Huang return OTP_FAILURE; 733b458cd62SJohnny Huang 73466f2f8e5SJohnny Huang return OTP_SUCCESS; 73566f2f8e5SJohnny Huang } 73666f2f8e5SJohnny Huang 7372d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 73866f2f8e5SJohnny Huang { 73979e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 740bb34a7bfSJohnny Huang uint32_t OTPCFG[16]; 741b458cd62SJohnny Huang uint32_t mask; 742b458cd62SJohnny Huang uint32_t dw_offset; 743b458cd62SJohnny Huang uint32_t bit_offset; 744b458cd62SJohnny Huang uint32_t otp_value; 74573f11549SJohnny Huang char valid_bit[20]; 74666f2f8e5SJohnny Huang int i; 74773f11549SJohnny Huang int j; 74866f2f8e5SJohnny Huang 749dacbba92SJohnny Huang otp_soak(0); 750bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 75166f2f8e5SJohnny Huang otp_read_config(i, &OTPCFG[i]); 75266f2f8e5SJohnny Huang 75366f2f8e5SJohnny Huang 754b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 755b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 7563cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 7573cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 7582d4b0742SJohnny Huang continue; 7593cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 7603cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 7613cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 762b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 763b458cd62SJohnny Huang 7643cb28812SJohnny Huang if ((otp_value != conf_info[i].value) && 7653cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 7663cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 7673cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 768b458cd62SJohnny Huang continue; 769b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 770b458cd62SJohnny Huang 7713cb28812SJohnny Huang if (conf_info[i].length == 1) { 7723cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 773b458cd62SJohnny Huang } else { 774b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 7753cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 7763cb28812SJohnny Huang conf_info[i].bit_offset); 777b458cd62SJohnny Huang } 778b458cd62SJohnny Huang printf("0x%-10x", otp_value); 779b458cd62SJohnny Huang 7803cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 781b458cd62SJohnny Huang printf("Reserved\n"); 7823cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 7833cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 784b458cd62SJohnny Huang printf("\n"); 7853cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 786b458cd62SJohnny Huang if (otp_value != 0) { 78773f11549SJohnny Huang for (j = 0; j < 7; j++) { 78873f11549SJohnny Huang if (otp_value == (1 << j)) { 78973f11549SJohnny Huang valid_bit[j * 2] = '1'; 790b458cd62SJohnny Huang } else { 79173f11549SJohnny Huang valid_bit[j * 2] = '0'; 79273f11549SJohnny Huang } 79373f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 79473f11549SJohnny Huang } 79573f11549SJohnny Huang valid_bit[15] = 0; 79673f11549SJohnny Huang } else { 79773f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 798b458cd62SJohnny Huang } 7993cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 800b458cd62SJohnny Huang printf("\n"); 801b458cd62SJohnny Huang } else { 8023cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 803b458cd62SJohnny Huang } 804b458cd62SJohnny Huang } 805b458cd62SJohnny Huang return OTP_SUCCESS; 80666f2f8e5SJohnny Huang } 80766f2f8e5SJohnny Huang 8085010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 80976d13988SJohnny Huang { 81079e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 811696656c6SJohnny Huang uint32_t *OTPSTRAP; 812696656c6SJohnny Huang uint32_t *OTPSTRAP_REG_PRO; 813696656c6SJohnny Huang uint32_t *OTPSTRAP_PRO; 814696656c6SJohnny Huang uint32_t *OTPSTRAP_IGNORE; 81576d13988SJohnny Huang int i; 816a8bd6d8cSJohnny Huang int fail = 0; 817a8bd6d8cSJohnny Huang uint32_t bit_offset; 818a8bd6d8cSJohnny Huang uint32_t dw_offset; 819a8bd6d8cSJohnny Huang uint32_t mask; 820a8bd6d8cSJohnny Huang uint32_t otp_value; 821696656c6SJohnny Huang uint32_t otp_reg_protect; 822a8bd6d8cSJohnny Huang uint32_t otp_protect; 823696656c6SJohnny Huang uint32_t otp_ignore; 82476d13988SJohnny Huang 825696656c6SJohnny Huang OTPSTRAP = (uint32_t *)image_layout->strap; 826696656c6SJohnny Huang OTPSTRAP_PRO = (uint32_t *)image_layout->strap_pro; 827696656c6SJohnny Huang OTPSTRAP_IGNORE = (uint32_t *)image_layout->strap_ignore; 8285010032bSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 829696656c6SJohnny Huang OTPSTRAP_REG_PRO = NULL; 830a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 831696656c6SJohnny Huang } else { 832696656c6SJohnny Huang OTPSTRAP_REG_PRO = (uint32_t *)image_layout->strap_reg_pro; 833de6b0cc4SJohnny Huang printf("BIT(hex) Value Reg_Protect Protect Description\n"); 834696656c6SJohnny Huang } 835de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 836b458cd62SJohnny Huang 8373cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 838696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 839a8bd6d8cSJohnny Huang dw_offset = 1; 8403cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 841a8bd6d8cSJohnny Huang } else { 842a8bd6d8cSJohnny Huang dw_offset = 0; 8433cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 844a8bd6d8cSJohnny Huang } 84576d13988SJohnny Huang 8463cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 847a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 848a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 849696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 850a8bd6d8cSJohnny Huang 8515010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) 852696656c6SJohnny Huang otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask; 8535010032bSJohnny Huang else 8545010032bSJohnny Huang otp_reg_protect = 0; 855696656c6SJohnny Huang 856696656c6SJohnny Huang if (otp_ignore == mask) { 857a8bd6d8cSJohnny Huang continue; 858696656c6SJohnny Huang } else if (otp_ignore != 0) { 859a8bd6d8cSJohnny Huang fail = 1; 860a8bd6d8cSJohnny Huang } 861a8bd6d8cSJohnny Huang 8623cb28812SJohnny Huang if ((otp_value != strap_info[i].value) && 8633cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 864a8bd6d8cSJohnny Huang continue; 865a8bd6d8cSJohnny Huang 8663cb28812SJohnny Huang if (strap_info[i].length == 1) { 8673cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 868a8bd6d8cSJohnny Huang } else { 869b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 8703cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 8713cb28812SJohnny Huang strap_info[i].bit_offset); 872a8bd6d8cSJohnny Huang } 873a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 8745010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) 875696656c6SJohnny Huang printf("0x%-10x", otp_reg_protect); 876a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 877a8bd6d8cSJohnny Huang 878a8bd6d8cSJohnny Huang if (fail) { 879696656c6SJohnny Huang printf("Ignore mask error\n"); 880a8bd6d8cSJohnny Huang } else { 8813cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 8823cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 883a8bd6d8cSJohnny Huang else 884a8bd6d8cSJohnny Huang printf("Reserved\n"); 885a8bd6d8cSJohnny Huang } 886a8bd6d8cSJohnny Huang } 887a8bd6d8cSJohnny Huang 888a8bd6d8cSJohnny Huang if (fail) 88976d13988SJohnny Huang return OTP_FAILURE; 89076d13988SJohnny Huang 89176d13988SJohnny Huang return OTP_SUCCESS; 89276d13988SJohnny Huang } 89376d13988SJohnny Huang 894b458cd62SJohnny Huang static int otp_print_strap_info(int view) 89576d13988SJohnny Huang { 89679e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 89776d13988SJohnny Huang struct otpstrap_status strap_status[64]; 89807baa4e8SJohnny Huang int i, j; 899b458cd62SJohnny Huang int fail = 0; 900b458cd62SJohnny Huang uint32_t bit_offset; 901b458cd62SJohnny Huang uint32_t length; 902b458cd62SJohnny Huang uint32_t otp_value; 903b458cd62SJohnny Huang uint32_t otp_protect; 90476d13988SJohnny Huang 905541eb887SJohnny Huang otp_strap_status(strap_status); 90676d13988SJohnny Huang 907b458cd62SJohnny Huang if (view) { 90883655e91SJohnny Huang if (info_cb.version == OTP_AST2600A0) 90907baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 91083655e91SJohnny Huang else 91183655e91SJohnny Huang printf("BIT(hex) Value Remains Reg_Protect Protect Description\n"); 91207baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 913b458cd62SJohnny Huang } else { 914b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 915b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 91676d13988SJohnny Huang } 9173cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 918b458cd62SJohnny Huang otp_value = 0; 9193cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 9203cb28812SJohnny Huang length = strap_info[i].length; 921b458cd62SJohnny Huang for (j = 0; j < length; j++) { 922c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 923c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 924b458cd62SJohnny Huang } 9253cb28812SJohnny Huang if ((otp_value != strap_info[i].value) && 9263cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 927b458cd62SJohnny Huang continue; 928b458cd62SJohnny Huang if (view) { 929b458cd62SJohnny Huang for (j = 0; j < length; j++) { 9303cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 931b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 93207baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 93383655e91SJohnny Huang if (info_cb.version != OTP_AST2600A0) 934e1a7245eSJohnny Huang printf("0x%-10X", strap_status[bit_offset + j].reg_protected); 935e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 9363cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 937b458cd62SJohnny Huang printf(" Reserved\n"); 938b458cd62SJohnny Huang continue; 939b458cd62SJohnny Huang } 940b458cd62SJohnny Huang if (length == 1) { 9413cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 942b458cd62SJohnny Huang continue; 94376d13988SJohnny Huang } 94476d13988SJohnny Huang 945b458cd62SJohnny Huang if (j == 0) 9463cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 947b458cd62SJohnny Huang else if (j == length - 1) 948b458cd62SJohnny Huang printf("\\ \"\n"); 949b458cd62SJohnny Huang else 950b458cd62SJohnny Huang printf("| \"\n"); 95176d13988SJohnny Huang } 952b458cd62SJohnny Huang } else { 953c947ef08SJohnny Huang if (length == 1) { 9543cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 955b458cd62SJohnny Huang } else { 956b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 957b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 958b458cd62SJohnny Huang } 959b458cd62SJohnny Huang 960b458cd62SJohnny Huang printf("0x%-10X", otp_value); 961b458cd62SJohnny Huang 9623cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 9633cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 964b458cd62SJohnny Huang else 965b458cd62SJohnny Huang printf("Reserved\n"); 966b458cd62SJohnny Huang } 967b458cd62SJohnny Huang } 968b458cd62SJohnny Huang 969b458cd62SJohnny Huang if (fail) 970b458cd62SJohnny Huang return OTP_FAILURE; 971b458cd62SJohnny Huang 972b458cd62SJohnny Huang return OTP_SUCCESS; 973b458cd62SJohnny Huang } 974b458cd62SJohnny Huang 975696656c6SJohnny Huang static void buf_print(uint8_t *buf, int len) 97669d5fd8fSJohnny Huang { 97769d5fd8fSJohnny Huang int i; 97869d5fd8fSJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 97969d5fd8fSJohnny Huang for (i = 0; i < len; i++) { 98069d5fd8fSJohnny Huang if (i % 16 == 0) { 98169d5fd8fSJohnny Huang printf("%04X: ", i); 98269d5fd8fSJohnny Huang } 98369d5fd8fSJohnny Huang printf("%02X ", buf[i]); 98469d5fd8fSJohnny Huang if ((i + 1) % 16 == 0) { 98569d5fd8fSJohnny Huang printf("\n"); 98669d5fd8fSJohnny Huang } 98769d5fd8fSJohnny Huang } 98869d5fd8fSJohnny Huang } 98969d5fd8fSJohnny Huang 990696656c6SJohnny Huang static int otp_print_data_info(struct otp_image_layout *image_layout) 99169d5fd8fSJohnny Huang { 99269d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 99379e42a59SJoel Stanley const struct otpkey_type *key_info_array = info_cb.key_info; 9949a4fe690SJohnny Huang struct otpkey_type key_info; 995696656c6SJohnny Huang uint32_t *buf; 996696656c6SJohnny Huang uint8_t *byte_buf; 9979d998018SJohnny Huang char empty = 1; 99869d5fd8fSJohnny Huang int i = 0, len = 0; 9999a4fe690SJohnny Huang int j; 100054552c69SJohnny Huang 1001696656c6SJohnny Huang byte_buf = image_layout->data; 1002696656c6SJohnny Huang buf = (uint32_t *)byte_buf; 10039d998018SJohnny Huang 10049d998018SJohnny Huang for (i = 0; i < 16; i++) { 10059d998018SJohnny Huang if (buf[i] != 0) { 10069d998018SJohnny Huang empty = 0; 10079d998018SJohnny Huang } 10089d998018SJohnny Huang } 10099d998018SJohnny Huang if (empty) 10109d998018SJohnny Huang return 0; 10119d998018SJohnny Huang 10129d998018SJohnny Huang i = 0; 101369d5fd8fSJohnny Huang while (1) { 101469d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 101569d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 101669d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 101769d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 101869d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 101969d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 10209a4fe690SJohnny Huang 10219a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 10229a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 10239a4fe690SJohnny Huang key_info = key_info_array[j]; 10249a4fe690SJohnny Huang break; 10259a4fe690SJohnny Huang } 10269a4fe690SJohnny Huang } 10279a4fe690SJohnny Huang 10287f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 102969d5fd8fSJohnny Huang printf("Key Type: "); 10309a4fe690SJohnny Huang printf("%s\n", key_info.information); 10319a4fe690SJohnny Huang 10329a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 103369d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 103469d5fd8fSJohnny Huang switch (key_length) { 103569d5fd8fSJohnny Huang case 0: 103669d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 103769d5fd8fSJohnny Huang break; 103869d5fd8fSJohnny Huang case 1: 103969d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 104069d5fd8fSJohnny Huang break; 104169d5fd8fSJohnny Huang case 2: 104269d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 104369d5fd8fSJohnny Huang break; 104469d5fd8fSJohnny Huang case 3: 104569d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 104669d5fd8fSJohnny Huang break; 104769d5fd8fSJohnny Huang } 1048*181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1049*181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 105069d5fd8fSJohnny Huang printf("RSA SHA Type: "); 105169d5fd8fSJohnny Huang switch (key_length) { 105269d5fd8fSJohnny Huang case 0: 105369d5fd8fSJohnny Huang printf("RSA1024\n"); 105469d5fd8fSJohnny Huang len = 0x100; 105569d5fd8fSJohnny Huang break; 105669d5fd8fSJohnny Huang case 1: 105769d5fd8fSJohnny Huang printf("RSA2048\n"); 105869d5fd8fSJohnny Huang len = 0x200; 105969d5fd8fSJohnny Huang break; 106069d5fd8fSJohnny Huang case 2: 106169d5fd8fSJohnny Huang printf("RSA3072\n"); 106269d5fd8fSJohnny Huang len = 0x300; 106369d5fd8fSJohnny Huang break; 106469d5fd8fSJohnny Huang case 3: 106569d5fd8fSJohnny Huang printf("RSA4096\n"); 106669d5fd8fSJohnny Huang len = 0x400; 106769d5fd8fSJohnny Huang break; 106869d5fd8fSJohnny Huang } 106969d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 107069d5fd8fSJohnny Huang } 10719a4fe690SJohnny Huang if (key_info.need_id) 107269d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 107369d5fd8fSJohnny Huang printf("Key Value:\n"); 10749a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 107569d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 10769a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 10779a4fe690SJohnny Huang printf("AES Key:\n"); 10789a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 10795fdde29fSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 10809a4fe690SJohnny Huang printf("AES IV:\n"); 10819a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 10829a4fe690SJohnny Huang } 10839a4fe690SJohnny Huang 10849a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 10855fdde29fSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 108669d5fd8fSJohnny Huang printf("AES Key:\n"); 108769d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 108869d5fd8fSJohnny Huang printf("AES IV:\n"); 108969d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 10905fdde29fSJohnny Huang } else { 10919a4fe690SJohnny Huang printf("AES Key 1:\n"); 10929a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 10939a4fe690SJohnny Huang printf("AES Key 2:\n"); 10949a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 10959a4fe690SJohnny Huang } 1096*181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 109769d5fd8fSJohnny Huang printf("RSA mod:\n"); 109869d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 109969d5fd8fSJohnny Huang printf("RSA exp:\n"); 110069d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 1101*181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1102*181f72d8SJohnny Huang printf("RSA mod:\n"); 1103*181f72d8SJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 1104*181f72d8SJohnny Huang printf("RSA exp:\n"); 1105*181f72d8SJohnny Huang buf_print((uint8_t *)"\x01\x00\x01", 3); 110669d5fd8fSJohnny Huang } 110769d5fd8fSJohnny Huang if (last) 110869d5fd8fSJohnny Huang break; 110969d5fd8fSJohnny Huang i++; 111069d5fd8fSJohnny Huang } 111169d5fd8fSJohnny Huang return 0; 111269d5fd8fSJohnny Huang } 111369d5fd8fSJohnny Huang 11145010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout) 111569d5fd8fSJohnny Huang { 1116a6d0d645SJohnny Huang int i, k; 1117d90825e2SJohnny Huang int pass = 0; 1118a6d0d645SJohnny Huang uint32_t prog_address; 1119bb34a7bfSJohnny Huang uint32_t data[16]; 1120a6d0d645SJohnny Huang uint32_t compare[2]; 11215010032bSJohnny Huang uint32_t *conf = (uint32_t *)image_layout->conf; 11225010032bSJohnny Huang uint32_t *conf_ignore = (uint32_t *)image_layout->conf_ignore; 1123d90825e2SJohnny Huang uint32_t data_masked; 1124d90825e2SJohnny Huang uint32_t buf_masked; 112569d5fd8fSJohnny Huang 1126a6d0d645SJohnny Huang printf("Read OTP Config Region:\n"); 1127a6d0d645SJohnny Huang 1128bb34a7bfSJohnny Huang for (i = 0; i < 16 ; i ++) { 112969d5fd8fSJohnny Huang prog_address = 0x800; 1130a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1131a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1132a6d0d645SJohnny Huang otp_read_data(prog_address, &data[i]); 1133a6d0d645SJohnny Huang } 1134a6d0d645SJohnny Huang 1135a6d0d645SJohnny Huang printf("Check writable...\n"); 1136bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 11375010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 11385010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1139d90825e2SJohnny Huang if (data_masked == buf_masked) 114069d5fd8fSJohnny Huang continue; 1141d90825e2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1142a6d0d645SJohnny Huang continue; 1143a6d0d645SJohnny Huang } else { 1144a6d0d645SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1145a6af4a17SJohnny Huang printf("OTPCFG[%X] = %x\n", i, data[i]); 11465010032bSJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 11475010032bSJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 11482a856b9aSJohnny Huang return OTP_FAILURE; 1149a6d0d645SJohnny Huang } 1150a6d0d645SJohnny Huang } 1151a6d0d645SJohnny Huang 1152a6d0d645SJohnny Huang printf("Start Programing...\n"); 1153d90825e2SJohnny Huang otp_soak(0); 1154bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 11555010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 11565010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1157a6d0d645SJohnny Huang prog_address = 0x800; 1158a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1159a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1160bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1161bb34a7bfSJohnny Huang pass = 1; 1162a6d0d645SJohnny Huang continue; 1163bb34a7bfSJohnny Huang } 1164de6fbf1cSJohnny Huang 1165a6d0d645SJohnny Huang 1166de6fbf1cSJohnny Huang otp_soak(1); 11675010032bSJohnny Huang otp_prog_dw(conf[i], conf_ignore[i], prog_address); 1168a6d0d645SJohnny Huang 116969d5fd8fSJohnny Huang pass = 0; 117069d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 11715010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1172de6fbf1cSJohnny Huang otp_soak(2); 1173feea3fdfSJohnny Huang otp_prog_dw(compare[0], conf_ignore[i], prog_address); 11745010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1175de6fbf1cSJohnny Huang otp_soak(1); 1176de6fbf1cSJohnny Huang } else { 1177de6fbf1cSJohnny Huang pass = 1; 1178de6fbf1cSJohnny Huang break; 1179de6fbf1cSJohnny Huang } 1180a6d0d645SJohnny Huang } else { 118169d5fd8fSJohnny Huang pass = 1; 118269d5fd8fSJohnny Huang break; 118369d5fd8fSJohnny Huang } 118469d5fd8fSJohnny Huang } 1185bb34a7bfSJohnny Huang if (pass == 0) { 1186bb34a7bfSJohnny Huang printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n", 11875010032bSJohnny Huang i, data[i], conf[i], conf_ignore[i]); 1188bb34a7bfSJohnny Huang break; 1189bb34a7bfSJohnny Huang } 1190a6d0d645SJohnny Huang } 1191a6d0d645SJohnny Huang 1192de6fbf1cSJohnny Huang otp_soak(0); 119369d5fd8fSJohnny Huang if (!pass) 11942a856b9aSJohnny Huang return OTP_FAILURE; 1195a6d0d645SJohnny Huang 11962a856b9aSJohnny Huang return OTP_SUCCESS; 1197d90825e2SJohnny Huang 119869d5fd8fSJohnny Huang } 119969d5fd8fSJohnny Huang 1200eda10d61SJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit) 1201eda10d61SJohnny Huang { 1202eda10d61SJohnny Huang if (ibit == 1) { 1203eda10d61SJohnny Huang return OTP_SUCCESS; 1204eda10d61SJohnny Huang } else { 1205eda10d61SJohnny Huang printf("OTPSTRAP[%X]:\n", offset); 1206eda10d61SJohnny Huang } 1207eda10d61SJohnny Huang if (bit == otpstrap->value) { 1208eda10d61SJohnny Huang printf(" The value is same as before, skip it.\n"); 1209eda10d61SJohnny Huang return OTP_PROG_SKIP; 1210eda10d61SJohnny Huang } 1211eda10d61SJohnny Huang if (otpstrap->protected == 1) { 1212eda10d61SJohnny Huang printf(" This bit is protected and is not writable\n"); 1213eda10d61SJohnny Huang return OTP_FAILURE; 1214eda10d61SJohnny Huang } 1215eda10d61SJohnny Huang if (otpstrap->remain_times == 0) { 1216eda10d61SJohnny Huang printf(" This bit is no remaining times to write.\n"); 1217eda10d61SJohnny Huang return OTP_FAILURE; 1218eda10d61SJohnny Huang } 1219eda10d61SJohnny Huang if (pbit == 1) { 1220eda10d61SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 1221eda10d61SJohnny Huang } 1222eda10d61SJohnny Huang if (rpbit == 1 && info_cb.version != OTP_AST2600A0) { 1223eda10d61SJohnny Huang printf(" The relative register will be protected.\n"); 1224eda10d61SJohnny Huang } 1225eda10d61SJohnny Huang printf(" Write 1 to OTPSTRAP[%X] OPTION[%X], that value becomes from %d to %d.\n", offset, otpstrap->writeable_option + 1, otpstrap->value, otpstrap->value ^ 1); 1226eda10d61SJohnny Huang return OTP_SUCCESS; 1227eda10d61SJohnny Huang } 1228eda10d61SJohnny Huang 12295010032bSJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout) 123069d5fd8fSJohnny Huang { 123169d5fd8fSJohnny Huang int i; 12325010032bSJohnny Huang uint32_t *strap; 12335010032bSJohnny Huang uint32_t *strap_ignore; 12345010032bSJohnny Huang uint32_t *strap_reg_protect; 12355010032bSJohnny Huang uint32_t *strap_pro; 1236eda10d61SJohnny Huang int bit, pbit, ibit, rpbit; 123769d5fd8fSJohnny Huang int fail = 0; 1238a6af4a17SJohnny Huang int skip = -1; 1239eda10d61SJohnny Huang int ret; 124066f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 124169d5fd8fSJohnny Huang 12425010032bSJohnny Huang strap = (uint32_t *)image_layout->strap; 12435010032bSJohnny Huang strap_pro = (uint32_t *)image_layout->strap_pro; 12445010032bSJohnny Huang strap_ignore = (uint32_t *)image_layout->strap_ignore; 12455010032bSJohnny Huang strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro; 12465010032bSJohnny Huang 1247541eb887SJohnny Huang otp_strap_status(otpstrap); 124869d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 124969d5fd8fSJohnny Huang if (i < 32) { 12505010032bSJohnny Huang bit = (strap[0] >> i) & 0x1; 1251eda10d61SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 12525010032bSJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 125369d5fd8fSJohnny Huang } else { 12545010032bSJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1255eda10d61SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 12565010032bSJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 12575010032bSJohnny Huang } 12585010032bSJohnny Huang 12595010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 12605010032bSJohnny Huang if (i < 32) { 12615010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 12625010032bSJohnny Huang } else { 12635010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 12645010032bSJohnny Huang } 12655010032bSJohnny Huang } else { 12665010032bSJohnny Huang rpbit = 0; 126769d5fd8fSJohnny Huang } 1268eda10d61SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit, rpbit); 1269eda10d61SJohnny Huang if (ret == OTP_PROG_SKIP) { 1270a6af4a17SJohnny Huang if (skip == -1) 1271a6af4a17SJohnny Huang skip = 1; 127269d5fd8fSJohnny Huang continue; 1273a6af4a17SJohnny Huang } else { 1274eda10d61SJohnny Huang skip = 1; 127569d5fd8fSJohnny Huang } 1276eda10d61SJohnny Huang 1277eda10d61SJohnny Huang if (ret == OTP_FAILURE) 127869d5fd8fSJohnny Huang fail = 1; 127969d5fd8fSJohnny Huang } 128069d5fd8fSJohnny Huang if (fail == 1) 1281a6af4a17SJohnny Huang return OTP_FAILURE; 1282a6af4a17SJohnny Huang else if (skip == 1) 1283a6af4a17SJohnny Huang return OTP_PROG_SKIP; 12847e22f42dSJohnny Huang 1285eda10d61SJohnny Huang return OTP_SUCCESS; 128669d5fd8fSJohnny Huang } 128769d5fd8fSJohnny Huang 12882a856b9aSJohnny Huang static int otp_print_strap(int start, int count) 128969d5fd8fSJohnny Huang { 129069d5fd8fSJohnny Huang int i, j; 1291de6b0cc4SJohnny Huang int remains; 129266f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 129369d5fd8fSJohnny Huang 12942a856b9aSJohnny Huang if (start < 0 || start > 64) 12952a856b9aSJohnny Huang return OTP_USAGE; 12962a856b9aSJohnny Huang 12972a856b9aSJohnny Huang if ((start + count) < 0 || (start + count) > 64) 12982a856b9aSJohnny Huang return OTP_USAGE; 12992a856b9aSJohnny Huang 1300541eb887SJohnny Huang otp_strap_status(otpstrap); 130169d5fd8fSJohnny Huang 1302de6b0cc4SJohnny Huang if (info_cb.version == OTP_AST2600A0) { 1303de6b0cc4SJohnny Huang remains = 7; 130407baa4e8SJohnny Huang printf("BIT(hex) Value Option Status\n"); 1305de6b0cc4SJohnny Huang } else { 1306de6b0cc4SJohnny Huang remains = 6; 1307de6b0cc4SJohnny Huang printf("BIT(hex) Value Option Reg_Protect Status\n"); 1308de6b0cc4SJohnny Huang } 1309de6b0cc4SJohnny Huang printf("______________________________________________________________________________\n"); 1310737ed20bSJohnny Huang 1311cd1610b4SJohnny Huang for (i = start; i < start + count; i++) { 131207baa4e8SJohnny Huang printf("0x%-8X", i); 1313737ed20bSJohnny Huang printf("%-7d", otpstrap[i].value); 1314de6b0cc4SJohnny Huang for (j = 0; j < remains; j++) 1315737ed20bSJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 1316737ed20bSJohnny Huang printf(" "); 1317de6b0cc4SJohnny Huang if (info_cb.version != OTP_AST2600A0) { 1318de6b0cc4SJohnny Huang printf("%d ", otpstrap[i].reg_protected); 1319de6b0cc4SJohnny Huang } 132069d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 1321737ed20bSJohnny Huang printf("protected and not writable"); 132269d5fd8fSJohnny Huang } else { 1323737ed20bSJohnny Huang printf("not protected "); 132469d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 1325737ed20bSJohnny Huang printf("and no remaining times to write."); 132669d5fd8fSJohnny Huang } else { 1327737ed20bSJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 132869d5fd8fSJohnny Huang } 132969d5fd8fSJohnny Huang } 1330737ed20bSJohnny Huang printf("\n"); 133169d5fd8fSJohnny Huang } 13322a856b9aSJohnny Huang 13332a856b9aSJohnny Huang return OTP_SUCCESS; 133469d5fd8fSJohnny Huang } 133569d5fd8fSJohnny Huang 13368848d5dcSJohnny Huang static int otp_prog_strap_bit(int bit_offset, int value) 13378848d5dcSJohnny Huang { 13388848d5dcSJohnny Huang struct otpstrap_status otpstrap[64]; 133983655e91SJohnny Huang uint32_t prog_address; 13408848d5dcSJohnny Huang int offset; 13418848d5dcSJohnny Huang int ret; 13428848d5dcSJohnny Huang 13438848d5dcSJohnny Huang 13448848d5dcSJohnny Huang otp_strap_status(otpstrap); 13458848d5dcSJohnny Huang 13468848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 13478848d5dcSJohnny Huang 13488848d5dcSJohnny Huang if (ret != OTP_SUCCESS) { 13498848d5dcSJohnny Huang return ret; 13508848d5dcSJohnny Huang } 13518848d5dcSJohnny Huang 13528848d5dcSJohnny Huang prog_address = 0x800; 13538848d5dcSJohnny Huang if (bit_offset < 32) { 13548848d5dcSJohnny Huang offset = bit_offset; 13558848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 13568848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 13578848d5dcSJohnny Huang 13588848d5dcSJohnny Huang } else { 13598848d5dcSJohnny Huang offset = (bit_offset - 32); 13608848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 13618848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 13628848d5dcSJohnny Huang } 13638848d5dcSJohnny Huang 13648848d5dcSJohnny Huang 136583655e91SJohnny Huang return otp_prog_bit(1, prog_address, offset); 13668848d5dcSJohnny Huang } 13678848d5dcSJohnny Huang 13685010032bSJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout) 136969d5fd8fSJohnny Huang { 13705010032bSJohnny Huang uint32_t *strap; 13715010032bSJohnny Huang uint32_t *strap_ignore; 13725010032bSJohnny Huang uint32_t *strap_pro; 13735010032bSJohnny Huang uint32_t *strap_reg_protect; 137483655e91SJohnny Huang uint32_t prog_address; 137583655e91SJohnny Huang int i; 1376eda10d61SJohnny Huang int bit, pbit, ibit, offset, rpbit; 137769d5fd8fSJohnny Huang int fail = 0; 137883655e91SJohnny Huang int ret; 137966f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 138069d5fd8fSJohnny Huang 13815010032bSJohnny Huang strap = (uint32_t *)image_layout->strap; 13825010032bSJohnny Huang strap_pro = (uint32_t *)image_layout->strap_pro; 13835010032bSJohnny Huang strap_ignore = (uint32_t *)image_layout->strap_ignore; 13845010032bSJohnny Huang strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro; 13855010032bSJohnny Huang 13867f795e57SJohnny Huang printf("Read OTP Strap Region:\n"); 1387541eb887SJohnny Huang otp_strap_status(otpstrap); 138869d5fd8fSJohnny Huang 13897f795e57SJohnny Huang printf("Check writable...\n"); 13905010032bSJohnny Huang if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) { 13917f795e57SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 13927f795e57SJohnny Huang return OTP_FAILURE; 13937f795e57SJohnny Huang } 13947e22f42dSJohnny Huang 139569d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 139669d5fd8fSJohnny Huang prog_address = 0x800; 139769d5fd8fSJohnny Huang if (i < 32) { 139869d5fd8fSJohnny Huang offset = i; 13995010032bSJohnny Huang bit = (strap[0] >> offset) & 0x1; 1400eda10d61SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 14015010032bSJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 140269d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 140369d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 140469d5fd8fSJohnny Huang 140569d5fd8fSJohnny Huang } else { 140669d5fd8fSJohnny Huang offset = (i - 32); 14075010032bSJohnny Huang bit = (strap[1] >> offset) & 0x1; 1408eda10d61SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 14095010032bSJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 141069d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 141169d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 141269d5fd8fSJohnny Huang } 14135010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 14145010032bSJohnny Huang if (i < 32) { 14155010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 14165010032bSJohnny Huang } else { 14175010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 14185010032bSJohnny Huang } 14195010032bSJohnny Huang } else { 14205010032bSJohnny Huang rpbit = 0; 14215010032bSJohnny Huang } 142269d5fd8fSJohnny Huang 1423eda10d61SJohnny Huang if (ibit == 1) { 142469d5fd8fSJohnny Huang continue; 142569d5fd8fSJohnny Huang } 142669d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 142769d5fd8fSJohnny Huang continue; 142869d5fd8fSJohnny Huang } 142969d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 143069d5fd8fSJohnny Huang fail = 1; 143169d5fd8fSJohnny Huang continue; 143269d5fd8fSJohnny Huang } 143369d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 143469d5fd8fSJohnny Huang fail = 1; 143569d5fd8fSJohnny Huang continue; 143669d5fd8fSJohnny Huang } 14377e22f42dSJohnny Huang 143883655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 143983655e91SJohnny Huang if (!ret) 14402a856b9aSJohnny Huang return OTP_FAILURE; 144169d5fd8fSJohnny Huang 14425010032bSJohnny Huang if (rpbit == 1 && info_cb.version != OTP_AST2600A0) { 144369d5fd8fSJohnny Huang prog_address = 0x800; 144469d5fd8fSJohnny Huang if (i < 32) 14455010032bSJohnny Huang prog_address |= 0x608; 144669d5fd8fSJohnny Huang else 14475010032bSJohnny Huang prog_address |= 0x60a; 14487e22f42dSJohnny Huang 144983655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 145083655e91SJohnny Huang if (!ret) 14512a856b9aSJohnny Huang return OTP_FAILURE; 14525010032bSJohnny Huang } 14535010032bSJohnny Huang 14545010032bSJohnny Huang if (pbit != 0) { 14555010032bSJohnny Huang prog_address = 0x800; 14565010032bSJohnny Huang if (i < 32) 14575010032bSJohnny Huang prog_address |= 0x60c; 14585010032bSJohnny Huang else 14595010032bSJohnny Huang prog_address |= 0x60e; 14605010032bSJohnny Huang 146183655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 146283655e91SJohnny Huang if (!ret) 14635010032bSJohnny Huang return OTP_FAILURE; 14645010032bSJohnny Huang } 146569d5fd8fSJohnny Huang 146669d5fd8fSJohnny Huang } 1467de6fbf1cSJohnny Huang otp_soak(0); 146869d5fd8fSJohnny Huang if (fail == 1) 14692a856b9aSJohnny Huang return OTP_FAILURE; 147069d5fd8fSJohnny Huang else 14712a856b9aSJohnny Huang return OTP_SUCCESS; 147269d5fd8fSJohnny Huang 147369d5fd8fSJohnny Huang } 147469d5fd8fSJohnny Huang 14755010032bSJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout) 14764c1c9b35SJohnny Huang { 147754552c69SJohnny Huang int i; 147854552c69SJohnny Huang int ret; 14795010032bSJohnny Huang int data_dw; 1480d90825e2SJohnny Huang uint32_t data[2048]; 14815010032bSJohnny Huang uint32_t *buf; 14825010032bSJohnny Huang uint32_t *buf_ignore; 14834c1c9b35SJohnny Huang 148454552c69SJohnny Huang uint32_t data_masked; 148554552c69SJohnny Huang uint32_t buf_masked; 14864c1c9b35SJohnny Huang 14875010032bSJohnny Huang buf = (uint32_t *)image_layout->data; 14885010032bSJohnny Huang buf_ignore = (uint32_t *)image_layout->data_ignore; 14895010032bSJohnny Huang 14905010032bSJohnny Huang data_dw = image_layout->data_length / 4; 14915010032bSJohnny Huang 14924c1c9b35SJohnny Huang printf("Read OTP Data:\n"); 14934c1c9b35SJohnny Huang 14945010032bSJohnny Huang for (i = 0; i < data_dw - 2 ; i += 2) { 1495d90825e2SJohnny Huang otp_read_data(i, &data[i]); 14964c1c9b35SJohnny Huang } 1497d90825e2SJohnny Huang 14984c1c9b35SJohnny Huang printf("Check writable...\n"); 149954552c69SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 15005010032bSJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1501696656c6SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1502696656c6SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 150354552c69SJohnny Huang if (data_masked == buf_masked) 15044c1c9b35SJohnny Huang continue; 1505d90825e2SJohnny Huang if (i % 2 == 0) { 150654552c69SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 15074c1c9b35SJohnny Huang continue; 15084c1c9b35SJohnny Huang } else { 15094c1c9b35SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1510d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 15114c1c9b35SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1512696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 15132a856b9aSJohnny Huang return OTP_FAILURE; 151469d5fd8fSJohnny Huang } 1515d90825e2SJohnny Huang } else { 151654552c69SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1517d90825e2SJohnny Huang continue; 1518d90825e2SJohnny Huang } else { 1519d90825e2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1520d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1521d90825e2SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1522696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 15232a856b9aSJohnny Huang return OTP_FAILURE; 1524d90825e2SJohnny Huang } 1525d90825e2SJohnny Huang } 1526d90825e2SJohnny Huang } 152769d5fd8fSJohnny Huang 1528d90825e2SJohnny Huang printf("Start Programing...\n"); 1529d90825e2SJohnny Huang 153054552c69SJohnny Huang // programing ecc region first 153154552c69SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1532696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 153354552c69SJohnny Huang if (ret != OTP_SUCCESS) { 153454552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1535696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 153654552c69SJohnny Huang return ret; 1537d90825e2SJohnny Huang } 1538d90825e2SJohnny Huang } 1539d90825e2SJohnny Huang 154054552c69SJohnny Huang for (i = 0; i < 1792; i += 2) { 1541696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 154254552c69SJohnny Huang if (ret != OTP_SUCCESS) { 154354552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1544696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 154554552c69SJohnny Huang return ret; 1546d90825e2SJohnny Huang } 1547de6fbf1cSJohnny Huang } 1548de6fbf1cSJohnny Huang otp_soak(0); 15492a856b9aSJohnny Huang return OTP_SUCCESS; 1550d90825e2SJohnny Huang 1551d90825e2SJohnny Huang } 1552d90825e2SJohnny Huang 1553696656c6SJohnny Huang static int otp_image_verify(uint8_t *src_buf, uint32_t length, uint8_t *digest_buf) 1554696656c6SJohnny Huang { 1555696656c6SJohnny Huang sha256_context ctx; 1556696656c6SJohnny Huang u8 digest_ret[CHECKSUM_LEN]; 1557696656c6SJohnny Huang 1558696656c6SJohnny Huang sha256_starts(&ctx); 1559696656c6SJohnny Huang sha256_update(&ctx, src_buf, length); 1560696656c6SJohnny Huang sha256_finish(&ctx, digest_ret); 1561696656c6SJohnny Huang 1562696656c6SJohnny Huang if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN)) 1563696656c6SJohnny Huang return 0; 1564696656c6SJohnny Huang else 1565696656c6SJohnny Huang return -1; 1566696656c6SJohnny Huang 1567696656c6SJohnny Huang } 1568696656c6SJohnny Huang 1569de6b0cc4SJohnny Huang static int do_otp_prog(int addr, int nconfirm) 157069d5fd8fSJohnny Huang { 157169d5fd8fSJohnny Huang int ret; 15729a4fe690SJohnny Huang int image_version = 0; 1573696656c6SJohnny Huang struct otp_header *otp_header; 1574696656c6SJohnny Huang struct otp_image_layout image_layout; 1575696656c6SJohnny Huang int image_size; 1576696656c6SJohnny Huang uint8_t *buf; 1577696656c6SJohnny Huang uint8_t *checksum; 157869d5fd8fSJohnny Huang 1579696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1580696656c6SJohnny Huang if (!otp_header) { 158169d5fd8fSJohnny Huang puts("Failed to map physical memory\n"); 15822a856b9aSJohnny Huang return OTP_FAILURE; 158369d5fd8fSJohnny Huang } 1584d90825e2SJohnny Huang 1585696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1586696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1587696656c6SJohnny Huang 1588696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1589696656c6SJohnny Huang 1590696656c6SJohnny Huang if (!buf) { 1591696656c6SJohnny Huang puts("Failed to map physical memory\n"); 1592696656c6SJohnny Huang return OTP_FAILURE; 1593696656c6SJohnny Huang } 1594696656c6SJohnny Huang otp_header = (struct otp_header *) buf; 1595696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1596696656c6SJohnny Huang 1597696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1598696656c6SJohnny Huang puts("Image is invalid\n"); 1599696656c6SJohnny Huang return OTP_FAILURE; 1600696656c6SJohnny Huang } 1601696656c6SJohnny Huang 1602696656c6SJohnny Huang 16035010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 16045010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 16055010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 16065010032bSJohnny Huang 16075010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1608696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 16095010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1610696656c6SJohnny Huang 1611696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 1612696656c6SJohnny Huang 1613696656c6SJohnny Huang if (!strcmp("A0", (char *)otp_header->otp_version)) { 1614696656c6SJohnny Huang image_version = OTP_AST2600A0; 16155010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 16165010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 16175010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 1618696656c6SJohnny Huang } else if (!strcmp("A1", (char *)otp_header->otp_version)) { 1619696656c6SJohnny Huang image_version = OTP_AST2600A1; 16205010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 16215010032bSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 16225010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 16235010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 16245fdde29fSJohnny Huang } else if (!strcmp("A2", (char *)otp_header->otp_version)) { 16255fdde29fSJohnny Huang image_version = OTP_AST2600A2; 16265fdde29fSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 16275fdde29fSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 16285fdde29fSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 16295fdde29fSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 163064b66712SJohnny Huang } else if (!strcmp("A3", (char *)otp_header->otp_version)) { 163164b66712SJohnny Huang image_version = OTP_AST2600A3; 163264b66712SJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 163364b66712SJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 163464b66712SJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 163564b66712SJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 1636696656c6SJohnny Huang } else { 1637696656c6SJohnny Huang puts("Version is not supported\n"); 1638696656c6SJohnny Huang return OTP_FAILURE; 1639696656c6SJohnny Huang } 1640696656c6SJohnny Huang 16419a4fe690SJohnny Huang if (image_version != info_cb.version) { 16429a4fe690SJohnny Huang puts("Version is not match\n"); 16439a4fe690SJohnny Huang return OTP_FAILURE; 16449a4fe690SJohnny Huang } 16459a4fe690SJohnny Huang 1646696656c6SJohnny Huang if (otp_image_verify(buf, image_size, checksum)) { 1647696656c6SJohnny Huang puts("checksum is invalid\n"); 1648696656c6SJohnny Huang return OTP_FAILURE; 1649d90825e2SJohnny Huang } 16507332532cSJohnny Huang 165169d5fd8fSJohnny Huang if (!nconfirm) { 1652696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 16537f795e57SJohnny Huang printf("\nOTP data region :\n"); 1654696656c6SJohnny Huang if (otp_print_data_info(&image_layout) < 0) { 165569d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 16562a856b9aSJohnny Huang return OTP_FAILURE; 165769d5fd8fSJohnny Huang } 165869d5fd8fSJohnny Huang } 1659696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 16607332532cSJohnny Huang printf("\nOTP strap region :\n"); 16615010032bSJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 16627332532cSJohnny Huang printf("OTP strap error, please check.\n"); 16637332532cSJohnny Huang return OTP_FAILURE; 16647332532cSJohnny Huang } 16657332532cSJohnny Huang } 1666696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 16677332532cSJohnny Huang printf("\nOTP configuration region :\n"); 1668696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 16697332532cSJohnny Huang printf("OTP config error, please check.\n"); 16707332532cSJohnny Huang return OTP_FAILURE; 16717332532cSJohnny Huang } 16727332532cSJohnny Huang } 16737332532cSJohnny Huang 167469d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 167569d5fd8fSJohnny Huang if (!confirm_yesno()) { 167669d5fd8fSJohnny Huang printf(" Aborting\n"); 16772a856b9aSJohnny Huang return OTP_FAILURE; 167869d5fd8fSJohnny Huang } 167969d5fd8fSJohnny Huang } 16807332532cSJohnny Huang 16815010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 16825010032bSJohnny Huang printf("programing data region ...\n"); 16835010032bSJohnny Huang ret = otp_prog_data(&image_layout); 16845010032bSJohnny Huang if (ret != 0) { 16855010032bSJohnny Huang printf("Error\n"); 16865010032bSJohnny Huang return ret; 16875010032bSJohnny Huang } else { 16885010032bSJohnny Huang printf("Done\n"); 16895010032bSJohnny Huang } 16905010032bSJohnny Huang } 16915010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 16925010032bSJohnny Huang printf("programing strap region ...\n"); 16935010032bSJohnny Huang ret = otp_prog_strap(&image_layout); 16945010032bSJohnny Huang if (ret != 0) { 16955010032bSJohnny Huang printf("Error\n"); 16965010032bSJohnny Huang return ret; 16975010032bSJohnny Huang } else { 16985010032bSJohnny Huang printf("Done\n"); 16995010032bSJohnny Huang } 17005010032bSJohnny Huang } 17015010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 17025010032bSJohnny Huang printf("programing configuration region ...\n"); 17035010032bSJohnny Huang ret = otp_prog_conf(&image_layout); 17045010032bSJohnny Huang if (ret != 0) { 17055010032bSJohnny Huang printf("Error\n"); 17065010032bSJohnny Huang return ret; 17075010032bSJohnny Huang } 17085010032bSJohnny Huang printf("Done\n"); 17095010032bSJohnny Huang } 1710cd1610b4SJohnny Huang 17117332532cSJohnny Huang return OTP_SUCCESS; 17122a856b9aSJohnny Huang } 17132a856b9aSJohnny Huang 17142a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 1715cd1610b4SJohnny Huang { 1716a6af4a17SJohnny Huang uint32_t read[2]; 1717d90825e2SJohnny Huang uint32_t prog_address = 0; 171866f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 1719cd1610b4SJohnny Huang int otp_bit; 172083655e91SJohnny Huang int ret = 0; 1721cd1610b4SJohnny Huang 1722dacbba92SJohnny Huang otp_soak(0); 1723cd1610b4SJohnny Huang switch (mode) { 1724a6d0d645SJohnny Huang case OTP_REGION_CONF: 1725a6af4a17SJohnny Huang otp_read_config(otp_dw_offset, read); 1726cd1610b4SJohnny Huang prog_address = 0x800; 1727cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 1728cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 1729a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1730cd1610b4SJohnny Huang if (otp_bit == value) { 1731a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1732cd1610b4SJohnny Huang printf("No need to program\n"); 17332a856b9aSJohnny Huang return OTP_SUCCESS; 1734cd1610b4SJohnny Huang } 1735cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1736a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset); 1737cd1610b4SJohnny Huang printf("OTP is programed, which can't be clean\n"); 17382a856b9aSJohnny Huang return OTP_FAILURE; 1739cd1610b4SJohnny Huang } 1740a6af4a17SJohnny Huang printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset); 1741cd1610b4SJohnny Huang break; 1742a6d0d645SJohnny Huang case OTP_REGION_DATA: 1743cd1610b4SJohnny Huang prog_address = otp_dw_offset; 1744cd1610b4SJohnny Huang 1745cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 1746a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 1747a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1748643b9cfdSJohnny Huang 1749643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 1750643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1751643b9cfdSJohnny Huang printf("OTP is programed, which can't be cleaned\n"); 1752643b9cfdSJohnny Huang return OTP_FAILURE; 1753643b9cfdSJohnny Huang } 1754cd1610b4SJohnny Huang } else { 1755a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 1756a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 1757643b9cfdSJohnny Huang 1758643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 1759643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1760643b9cfdSJohnny Huang printf("OTP is programed, which can't be writen\n"); 1761643b9cfdSJohnny Huang return OTP_FAILURE; 1762643b9cfdSJohnny Huang } 1763cd1610b4SJohnny Huang } 1764cd1610b4SJohnny Huang if (otp_bit == value) { 1765a6af4a17SJohnny Huang printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1766cd1610b4SJohnny Huang printf("No need to program\n"); 17672a856b9aSJohnny Huang return OTP_SUCCESS; 1768cd1610b4SJohnny Huang } 1769643b9cfdSJohnny Huang 1770a6af4a17SJohnny Huang printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset); 1771cd1610b4SJohnny Huang break; 1772a6d0d645SJohnny Huang case OTP_REGION_STRAP: 17738848d5dcSJohnny Huang otp_strap_status(otpstrap); 17748848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 17758848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 17768848d5dcSJohnny Huang if (ret == OTP_FAILURE) 17778848d5dcSJohnny Huang return OTP_FAILURE; 17788848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 17798848d5dcSJohnny Huang return OTP_SUCCESS; 1780a6af4a17SJohnny Huang 1781cd1610b4SJohnny Huang break; 1782cd1610b4SJohnny Huang } 1783cd1610b4SJohnny Huang 1784cd1610b4SJohnny Huang if (!nconfirm) { 1785cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1786cd1610b4SJohnny Huang if (!confirm_yesno()) { 1787cd1610b4SJohnny Huang printf(" Aborting\n"); 17882a856b9aSJohnny Huang return OTP_FAILURE; 1789cd1610b4SJohnny Huang } 1790cd1610b4SJohnny Huang } 1791cd1610b4SJohnny Huang 1792cd1610b4SJohnny Huang switch (mode) { 1793a6d0d645SJohnny Huang case OTP_REGION_STRAP: 179483655e91SJohnny Huang ret = otp_prog_strap_bit(bit_offset, value); 179583655e91SJohnny Huang break; 1796a6d0d645SJohnny Huang case OTP_REGION_CONF: 1797a6d0d645SJohnny Huang case OTP_REGION_DATA: 179883655e91SJohnny Huang ret = otp_prog_bit(value, prog_address, bit_offset); 1799de6fbf1cSJohnny Huang break; 1800de6fbf1cSJohnny Huang } 1801de6fbf1cSJohnny Huang otp_soak(0); 180283655e91SJohnny Huang if (ret) { 18039009c25dSJohnny Huang printf("SUCCESS\n"); 18042a856b9aSJohnny Huang return OTP_SUCCESS; 18059009c25dSJohnny Huang } else { 18069009c25dSJohnny Huang printf("OTP cannot be programed\n"); 18079009c25dSJohnny Huang printf("FAILED\n"); 18089009c25dSJohnny Huang return OTP_FAILURE; 18099009c25dSJohnny Huang } 1810cd1610b4SJohnny Huang 18112a856b9aSJohnny Huang return OTP_USAGE; 1812cd1610b4SJohnny Huang } 1813cd1610b4SJohnny Huang 18142a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 181569d5fd8fSJohnny Huang { 18162a856b9aSJohnny Huang uint32_t offset, count; 18172a856b9aSJohnny Huang int ret; 181869d5fd8fSJohnny Huang 18192a856b9aSJohnny Huang if (argc == 4) { 18202a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 18212a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 18222a856b9aSJohnny Huang } else if (argc == 3) { 18232a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 18242a856b9aSJohnny Huang count = 1; 18252a856b9aSJohnny Huang } else { 182669d5fd8fSJohnny Huang return CMD_RET_USAGE; 182769d5fd8fSJohnny Huang } 182869d5fd8fSJohnny Huang 182969d5fd8fSJohnny Huang 18302a856b9aSJohnny Huang if (!strcmp(argv[1], "conf")) { 18313d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 18322a856b9aSJohnny Huang ret = otp_print_config(offset, count); 18332a856b9aSJohnny Huang } else if (!strcmp(argv[1], "data")) { 18343d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 18352a856b9aSJohnny Huang ret = otp_print_data(offset, count); 18362a856b9aSJohnny Huang } else if (!strcmp(argv[1], "strap")) { 18373d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 18382a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 18392a856b9aSJohnny Huang } else { 18402a856b9aSJohnny Huang return CMD_RET_USAGE; 184169d5fd8fSJohnny Huang } 184269d5fd8fSJohnny Huang 18432a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18442a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18452a856b9aSJohnny Huang else 18462a856b9aSJohnny Huang return CMD_RET_USAGE; 18472a856b9aSJohnny Huang 18482a856b9aSJohnny Huang } 18492a856b9aSJohnny Huang 18502a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 18512a856b9aSJohnny Huang { 18522a856b9aSJohnny Huang phys_addr_t addr; 18532a856b9aSJohnny Huang int ret; 18542a856b9aSJohnny Huang 1855de6b0cc4SJohnny Huang if (argc == 3) { 1856ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 18572a856b9aSJohnny Huang return CMD_RET_USAGE; 18582a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 18593d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1860de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 1); 1861de6b0cc4SJohnny Huang } else if (argc == 2) { 18622a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 18633d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1864de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 0); 18652a856b9aSJohnny Huang } else { 18662a856b9aSJohnny Huang return CMD_RET_USAGE; 18672a856b9aSJohnny Huang } 18682a856b9aSJohnny Huang 18692a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18702a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18712a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 18722a856b9aSJohnny Huang return CMD_RET_FAILURE; 18732a856b9aSJohnny Huang else 18742a856b9aSJohnny Huang return CMD_RET_USAGE; 18752a856b9aSJohnny Huang } 18762a856b9aSJohnny Huang 18772a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 18782a856b9aSJohnny Huang { 18792a856b9aSJohnny Huang int mode = 0; 18802a856b9aSJohnny Huang int nconfirm = 0; 18812a856b9aSJohnny Huang int otp_addr = 0; 18822a856b9aSJohnny Huang int bit_offset; 18832a856b9aSJohnny Huang int value; 18842a856b9aSJohnny Huang int ret; 18852a856b9aSJohnny Huang 18862a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 18872a856b9aSJohnny Huang return CMD_RET_USAGE; 18882a856b9aSJohnny Huang 18892a856b9aSJohnny Huang /* Drop the pb cmd */ 18902a856b9aSJohnny Huang argc--; 18912a856b9aSJohnny Huang argv++; 18922a856b9aSJohnny Huang 18932a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 1894a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 18952a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 1896a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 18972a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 1898a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 1899cd1610b4SJohnny Huang else 19002a856b9aSJohnny Huang return CMD_RET_USAGE; 19012a856b9aSJohnny Huang 19022a856b9aSJohnny Huang /* Drop the region cmd */ 19032a856b9aSJohnny Huang argc--; 19042a856b9aSJohnny Huang argv++; 19052a856b9aSJohnny Huang 1906ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 1907cd1610b4SJohnny Huang nconfirm = 1; 19082a856b9aSJohnny Huang /* Drop the force option */ 19092a856b9aSJohnny Huang argc--; 19102a856b9aSJohnny Huang argv++; 19112a856b9aSJohnny Huang } 1912cd1610b4SJohnny Huang 1913a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 19142a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 19152a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 19160808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 19172a856b9aSJohnny Huang return CMD_RET_USAGE; 1918cd1610b4SJohnny Huang } else { 19192a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 19202a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 19212a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 19220808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 19232a856b9aSJohnny Huang return CMD_RET_USAGE; 19240808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 192578855207SJohnny Huang if (otp_addr >= 0x800) 19260808cc55SJohnny Huang return CMD_RET_USAGE; 19270808cc55SJohnny Huang } else { 192878855207SJohnny Huang if (otp_addr >= 0x20) 19290808cc55SJohnny Huang return CMD_RET_USAGE; 19300808cc55SJohnny Huang } 1931cd1610b4SJohnny Huang } 1932cd1610b4SJohnny Huang if (value != 0 && value != 1) 19332a856b9aSJohnny Huang return CMD_RET_USAGE; 1934cd1610b4SJohnny Huang 19353d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19362a856b9aSJohnny Huang ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 19372a856b9aSJohnny Huang 19382a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 19392a856b9aSJohnny Huang return CMD_RET_SUCCESS; 19402a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 19412a856b9aSJohnny Huang return CMD_RET_FAILURE; 19422a856b9aSJohnny Huang else 19432a856b9aSJohnny Huang return CMD_RET_USAGE; 19442a856b9aSJohnny Huang } 19452a856b9aSJohnny Huang 19462a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 19472a856b9aSJohnny Huang { 19482a856b9aSJohnny Huang phys_addr_t addr; 19492a856b9aSJohnny Huang int otp_addr = 0; 19502a856b9aSJohnny Huang 19512a856b9aSJohnny Huang if (argc != 3) 19522a856b9aSJohnny Huang return CMD_RET_USAGE; 19532a856b9aSJohnny Huang 19543d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19552a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 19562a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 19572a856b9aSJohnny Huang if (otp_compare(otp_addr, addr) == 0) { 195869d5fd8fSJohnny Huang printf("Compare pass\n"); 19592a856b9aSJohnny Huang return CMD_RET_SUCCESS; 196069d5fd8fSJohnny Huang } else { 196169d5fd8fSJohnny Huang printf("Compare fail\n"); 19622a856b9aSJohnny Huang return CMD_RET_FAILURE; 196369d5fd8fSJohnny Huang } 196469d5fd8fSJohnny Huang } 196569d5fd8fSJohnny Huang 196666f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 196766f2f8e5SJohnny Huang { 1968a8bd6d8cSJohnny Huang int view = 0; 19692d4b0742SJohnny Huang int input; 1970a8bd6d8cSJohnny Huang 1971a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 197266f2f8e5SJohnny Huang return CMD_RET_USAGE; 197366f2f8e5SJohnny Huang 19742d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 197566f2f8e5SJohnny Huang 19763d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19772d4b0742SJohnny Huang if (argc == 3) { 19782d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 19792d4b0742SJohnny Huang otp_print_conf_info(input); 19802d4b0742SJohnny Huang } else { 19812d4b0742SJohnny Huang otp_print_conf_info(-1); 19822d4b0742SJohnny Huang } 19832d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 19842d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 1985a8bd6d8cSJohnny Huang view = 1; 1986a8bd6d8cSJohnny Huang /* Drop the view option */ 1987a8bd6d8cSJohnny Huang argc--; 1988a8bd6d8cSJohnny Huang argv++; 1989a8bd6d8cSJohnny Huang } 19903d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1991b458cd62SJohnny Huang otp_print_strap_info(view); 199266f2f8e5SJohnny Huang } else { 199366f2f8e5SJohnny Huang return CMD_RET_USAGE; 199466f2f8e5SJohnny Huang } 19952d4b0742SJohnny Huang 199666f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 199766f2f8e5SJohnny Huang } 199866f2f8e5SJohnny Huang 1999737ed20bSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2000737ed20bSJohnny Huang { 2001737ed20bSJohnny Huang int input; 2002737ed20bSJohnny Huang int bit_offset; 2003737ed20bSJohnny Huang int prog_address; 200483655e91SJohnny Huang int ret; 2005737ed20bSJohnny Huang if (argc != 3 && argc != 2) 2006737ed20bSJohnny Huang return CMD_RET_USAGE; 2007737ed20bSJohnny Huang 2008ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2009737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 2010737ed20bSJohnny Huang } else { 2011737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 2012737ed20bSJohnny Huang printf("OTPSTRAP[%d] will be protected\n", input); 2013737ed20bSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2014737ed20bSJohnny Huang if (!confirm_yesno()) { 2015737ed20bSJohnny Huang printf(" Aborting\n"); 2016737ed20bSJohnny Huang return CMD_RET_FAILURE; 2017737ed20bSJohnny Huang } 2018737ed20bSJohnny Huang } 2019737ed20bSJohnny Huang 2020737ed20bSJohnny Huang prog_address = 0x800; 2021737ed20bSJohnny Huang if (input < 32) { 2022737ed20bSJohnny Huang bit_offset = input; 2023737ed20bSJohnny Huang prog_address |= 0x60c; 2024737ed20bSJohnny Huang } else if (input < 64) { 2025737ed20bSJohnny Huang bit_offset = input - 32; 2026737ed20bSJohnny Huang prog_address |= 0x60e; 2027737ed20bSJohnny Huang } else { 2028737ed20bSJohnny Huang return CMD_RET_USAGE; 2029737ed20bSJohnny Huang } 2030737ed20bSJohnny Huang 2031737ed20bSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2032737ed20bSJohnny Huang printf("OTPSTRAP[%d] already protected\n", input); 2033737ed20bSJohnny Huang } 2034de6fbf1cSJohnny Huang 203583655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, bit_offset); 2036de6fbf1cSJohnny Huang otp_soak(0); 203783655e91SJohnny Huang 203883655e91SJohnny Huang if (ret) { 2039737ed20bSJohnny Huang printf("OTPSTRAP[%d] is protected\n", input); 2040737ed20bSJohnny Huang return CMD_RET_SUCCESS; 2041737ed20bSJohnny Huang } 2042737ed20bSJohnny Huang 2043737ed20bSJohnny Huang printf("Protect OTPSTRAP[%d] fail\n", input); 2044737ed20bSJohnny Huang return CMD_RET_FAILURE; 2045737ed20bSJohnny Huang 2046737ed20bSJohnny Huang } 20479a4fe690SJohnny Huang 2048f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2049f67375f7SJohnny Huang { 2050f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 2051f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 2052f67375f7SJohnny Huang 2053f67375f7SJohnny Huang return CMD_RET_SUCCESS; 2054f67375f7SJohnny Huang } 2055f67375f7SJohnny Huang 20562a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 2057f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 20582a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 2059a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 2060de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 20612a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 2062737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 20632a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 20642a856b9aSJohnny Huang }; 20652a856b9aSJohnny Huang 20662a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 20672a856b9aSJohnny Huang { 20682a856b9aSJohnny Huang cmd_tbl_t *cp; 20690dae9d52SJohnny Huang uint32_t ver; 20702a856b9aSJohnny Huang 20712a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 20722a856b9aSJohnny Huang 2073737ed20bSJohnny Huang /* Drop the otp command */ 20742a856b9aSJohnny Huang argc--; 20752a856b9aSJohnny Huang argv++; 20762a856b9aSJohnny Huang 20772a856b9aSJohnny Huang if (cp == NULL || argc > cp->maxargs) 20782a856b9aSJohnny Huang return CMD_RET_USAGE; 20792a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 20802a856b9aSJohnny Huang return CMD_RET_SUCCESS; 20812a856b9aSJohnny Huang 20820dae9d52SJohnny Huang ver = chip_version(); 20830dae9d52SJohnny Huang switch (ver) { 20840dae9d52SJohnny Huang case OTP_AST2600A0: 2085696656c6SJohnny Huang info_cb.version = OTP_AST2600A0; 20869a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 20879a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 20889a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 20899a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 20909a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 20919a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 20920dae9d52SJohnny Huang break; 20930dae9d52SJohnny Huang case OTP_AST2600A1: 2094696656c6SJohnny Huang info_cb.version = OTP_AST2600A1; 20953cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 20963cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 20973cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 20983cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 20999a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 21009a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 21010dae9d52SJohnny Huang break; 21020dae9d52SJohnny Huang case OTP_AST2600A2: 21035fdde29fSJohnny Huang info_cb.version = OTP_AST2600A2; 21045fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 21055fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 21065fdde29fSJohnny Huang info_cb.strap_info = a2_strap_info; 21075fdde29fSJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info); 21085fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 21095fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 21100dae9d52SJohnny Huang break; 211164b66712SJohnny Huang case OTP_AST2600A3: 211264b66712SJohnny Huang info_cb.version = OTP_AST2600A3; 211364b66712SJohnny Huang info_cb.conf_info = a2_conf_info; 211464b66712SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 211564b66712SJohnny Huang info_cb.strap_info = a2_strap_info; 211664b66712SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info); 2117*181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 2118*181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 211964b66712SJohnny Huang break; 21200dae9d52SJohnny Huang default: 2121f1be5099SJohnny Huang printf("SOC is not supported\n"); 21220dae9d52SJohnny Huang return CMD_RET_FAILURE; 21239a4fe690SJohnny Huang } 21249a4fe690SJohnny Huang 21252a856b9aSJohnny Huang return cp->cmd(cmdtp, flag, argc, argv); 212669d5fd8fSJohnny Huang } 212769d5fd8fSJohnny Huang 212869d5fd8fSJohnny Huang U_BOOT_CMD( 212969d5fd8fSJohnny Huang otp, 7, 0, do_ast_otp, 213069d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 2131f67375f7SJohnny Huang "version\n" 2132f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 21332a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 21342d4b0742SJohnny Huang "otp info strap [v]\n" 21352d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 2136de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2137ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2138ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2139ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 21402a856b9aSJohnny Huang "otp cmp <addr> <otp_dw_offset>\n" 214169d5fd8fSJohnny Huang ); 2142