static ssize_t fsl_otp_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { unsigned int index = attr - otp_kattr; u32 value; int ret; sscanf(buf, "0x%x", &value); ret = clk_prepare_enable(otp_clk); if (ret) return 0; mutex_lock(&otp_mutex); set_otp_timing(); ret = otp_wait_busy(0); if (ret) goto out; otp_write_bits(index, value, 0x3e77); /* Reload all the shadow registers */ __raw_writel(BM_OCOTP_CTRL_RELOAD_SHADOWS, otp_base + HW_OCOTP_CTRL_SET); udelay(1); otp_wait_busy(BM_OCOTP_CTRL_RELOAD_SHADOWS); out: mutex_unlock(&otp_mutex); clk_disable_unprepare(otp_clk); return ret ? 0 : count; }
static ssize_t fsl_otp_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { unsigned int index = attr - otp_kattr; u32 value = 0; int ret; ret = clk_prepare_enable(otp_clk); if (ret) return 0; mutex_lock(&otp_mutex); set_otp_timing(); ret = otp_wait_busy(0); if (ret) goto out; value = __raw_readl(otp_base + HW_OCOTP_CUST_N(index)); out: mutex_unlock(&otp_mutex); clk_disable_unprepare(otp_clk); return ret ? 0 : sprintf(buf, "0x%x\n", value); }
int fsl_otp_readl(unsigned long offset, u32 *value) { int ret = 0; ret = clk_prepare_enable(otp_clk); if (ret) return ret; mutex_lock(&otp_mutex); set_otp_timing(); ret = otp_wait_busy(0); if (ret) goto out; *value = __raw_readl(otp_base + offset); out: mutex_unlock(&otp_mutex); clk_disable_unprepare(otp_clk); return ret; }
int do_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { uint32_t ret, base_flags; bool prompt_user, force_read; uint32_t (*otp_func)(uint32_t page, uint32_t flags, uint64_t *page_content); if (argc < 4) { usage: cmd_usage(cmdtp); return 1; } prompt_user = false; base_flags = 0; if (!strcmp(argv[1], "read")) otp_func = bfrom_OtpRead; else if (!strcmp(argv[1], "dump")) { otp_func = bfrom_OtpRead; force_read = true; } else if (!strcmp(argv[1], "write")) { otp_func = bfrom_OtpWrite; base_flags = OTP_CHECK_FOR_PREV_WRITE; if (!strcmp(argv[2], "--force")) { argv[2] = argv[1]; argv++; --argc; } else prompt_user = false; } else if (!strcmp(argv[1], "lock")) { if (argc != 4) goto usage; otp_func = bfrom_OtpWrite; base_flags = OTP_LOCK; } else goto usage; uint64_t *addr = (uint64_t *)simple_strtoul(argv[2], NULL, 16); uint32_t page = simple_strtoul(argv[3], NULL, 16); uint32_t flags; size_t i, count; ulong half; if (argc > 4) count = simple_strtoul(argv[4], NULL, 16); else count = 2; if (argc > 5) { half = simple_strtoul(argv[5], NULL, 16); if (half != 0 && half != 1) { puts("Error: 'half' can only be '0' or '1'\n"); goto usage; } } else half = 0; /* "otp lock" has slightly different semantics */ if (base_flags & OTP_LOCK) { count = page; page = (uint32_t)addr; addr = NULL; } /* do to the nature of OTP, make sure users are sure */ if (prompt_user) { printf( "Writing one time programmable memory\n" "Make sure your operating voltages and temperature are within spec\n" " source address: 0x%p\n" " OTP destination: %s page 0x%03X - %s page 0x%03lX\n" " number to write: %lu halfpages\n" " type \"YES\" (no quotes) to confirm: ", addr, lowup(half), page, lowup(half + count - 1), page + (half + count - 1) / 2, half + count ); i = 0; while (1) { if (tstc()) { const char exp_ans[] = "YES\r"; char c; putc(c = getc()); if (exp_ans[i++] != c) { printf(" Aborting\n"); return 1; } else if (!exp_ans[i]) { puts("\n"); break; } } } } printf("OTP memory %s: addr 0x%p page 0x%03X count %zu ... ", argv[1], addr, page, count); set_otp_timing(otp_func == bfrom_OtpWrite); if (otp_func == bfrom_OtpWrite && check_voltage()) { puts("ERROR: VDDINT voltage is out of spec for writing\n"); return -1; } /* Do the actual reading/writing stuff */ ret = 0; for (i = half; i < count + half; ++i) { flags = base_flags | (i % 2 ? OTP_UPPER_HALF : OTP_LOWER_HALF); try_again: ret = otp_func(page, flags, addr); if (ret & OTP_MASTER_ERROR) { if (force_read) { if (flags & OTP_NO_ECC) break; else flags |= OTP_NO_ECC; puts("E"); goto try_again; } else break; } else if (ret) puts("W"); else puts("."); if (!(base_flags & OTP_LOCK)) { ++addr; if (i % 2) ++page; } else ++page; } if (ret & 0x1) printf("\nERROR at page 0x%03X (%s-halfpage): 0x%03X: %s\n", page, lowup(i), ret, otp_strerror(ret)); else puts(" done\n"); /* Make sure we disable writing */ set_otp_timing(false); bfrom_OtpCommand(OTP_CLOSE, 0); return ret; }
static int otp_blow_prep(void) { return (!set_otp_timing()) ? otp_wait_busy(0) : -1; }