/* * blow one u32 to indexed fuse */ int imx_otp_blow_one_u32(u32 index, u32 data, u32 *pfused_value) { u32 ctrl_reg = 0; int ret = 0; if (otp_clk_enable()) { ret = -1; goto exit_nop; } if (otp_blow_prep()) { ret = -1; printf("ERROR: blow preparation failed\n"); goto exit_cleanup; } if (fuse_blow_addr(index, data)) { ret = -1; printf("ERROR: blow fuse failed\n"); goto exit_cleanup; } if (otp_blow_post()) { ret = -1; printf("ERROR: blow post operation failed\n"); goto exit_cleanup; } ctrl_reg = readl(IMX_OTP_BASE + HW_OCOTP_CTRL); if (ctrl_reg & BM_OCOTP_CTRL_ERROR) { ret = -1; goto exit_cleanup; } if (imx_otp_read_one_u32(index, pfused_value)) { ret = -1; goto exit_cleanup; } exit_cleanup: otp_clk_disable(); exit_nop: return ret; }
int do_imxotp(cmd_tbl_t *cmd_tbl, int flag, int argc, char * const argv[]) { u32 addr, value_read; #ifdef IMX_OTPWRITE_ENABLED u32 fused_value, value_to_fuse; int force_to_fuse = 0; #endif if (argc < 3) { usage: cmd_usage(cmd_tbl); return 1; } if (!strcmp(argv[1], "read")) { switch (argc) { case 3: addr = simple_strtoul(argv[2], NULL, 16); if ((addr == 0) && validate_zero_from_simple_strtoul(argv[2])) goto usage; break; default: goto usage; } printf("Reading fuse at index 0x%X\n", addr); if (imx_otp_read_one_u32(addr, &value_read)) return -1; printf("Fuse at index 0x%X has the value: 0x%08X\n", addr, value_read); #ifdef IMX_OTPWRITE_ENABLED } else if (!strcmp(argv[1], "blow")) { if (argc < 4 || argc > 5) goto usage; if (!strcmp(argv[2], "--force")) { force_to_fuse = 1; addr = simple_strtoul(argv[3], NULL, 16); if ((addr == 0) && validate_zero_from_simple_strtoul(argv[3])) goto usage; value_to_fuse = simple_strtoul(argv[4], NULL, 16); if ((value_to_fuse == 0) && validate_zero_from_simple_strtoul(argv[4])) goto usage; } else { addr = simple_strtoul(argv[2], NULL, 16); if ((addr == 0) && validate_zero_from_simple_strtoul(argv[2])) goto usage; value_to_fuse = simple_strtoul(argv[3], NULL, 16); if ((value_to_fuse == 0) && validate_zero_from_simple_strtoul(argv[3])) goto usage; } /* show the current value of specified address (fuse index) */ if (imx_otp_read_one_u32(addr, &value_read)) return -1; printf("Current fuse at index 0x%X has the value: 0x%08X\n", addr, value_read); if ((value_to_fuse & value_read) == value_to_fuse) printf("!! Fuse blow skipped:" " the bits have been already set.\n"); else if (force_to_fuse) { printf("Blowing fuse at index 0x%X, value: 0x%08X\n", addr, value_to_fuse); if (imx_otp_blow_one_u32(addr, value_to_fuse, &fused_value)) { printf("ERROR: failed to blow fuse" " at 0x%X with value of 0x%08X\n", addr, value_to_fuse); } else { printf("Operation %s fuse" " at index 0x%X value: 0x%08X\n", ((fused_value & value_to_fuse) == value_to_fuse) ? "succeeded" : "failed", addr, fused_value); } } else { printf("!! Fuse blow aborted." " if you do want to blow it." " Please use the command:\n" "%s blow --force %X %X\n", argv[0], addr, value_to_fuse); } #endif } else goto usage; return 0; }