1 /* 2 * cmd_otp.c - interface to Blackfin on-chip One-Time-Programmable memory 3 * 4 * Copyright (c) 2007-2008 Analog Devices Inc. 5 * 6 * Licensed under the GPL-2 or later. 7 */ 8 9 /* There are 512 128-bit "pages" (0x000 through 0x1FF). 10 * The pages are accessable as 64-bit "halfpages" (an upper and lower half). 11 * The pages are not part of the memory map. There is an OTP controller which 12 * handles scanning in/out of bits. While access is done through OTP MMRs, 13 * the bootrom provides C-callable helper functions to handle the interaction. 14 */ 15 16 #include <config.h> 17 #include <common.h> 18 #include <command.h> 19 #include <console.h> 20 21 #include <asm/blackfin.h> 22 #include <asm/clock.h> 23 #include <asm/mach-common/bits/otp.h> 24 25 static const char *otp_strerror(uint32_t err) 26 { 27 switch (err) { 28 case 0: return "no error"; 29 case OTP_WRITE_ERROR: return "OTP fuse write error"; 30 case OTP_READ_ERROR: return "OTP fuse read error"; 31 case OTP_ACC_VIO_ERROR: return "invalid OTP address"; 32 case OTP_DATA_MULT_ERROR: return "multiple bad bits detected"; 33 case OTP_ECC_MULT_ERROR: return "error in ECC bits"; 34 case OTP_PREV_WR_ERROR: return "space already written"; 35 case OTP_DATA_SB_WARN: return "single bad bit in half page"; 36 case OTP_ECC_SB_WARN: return "single bad bit in ECC"; 37 default: return "unknown error"; 38 } 39 } 40 41 #define lowup(x) ((x) % 2 ? "upper" : "lower") 42 43 static int check_voltage(void) 44 { 45 /* Make sure voltage limits are within datasheet spec */ 46 uint16_t vr_ctl = bfin_read_VR_CTL(); 47 48 #ifdef __ADSPBF54x__ 49 /* 0.9V <= VDDINT <= 1.1V */ 50 if ((vr_ctl & 0xc) && (vr_ctl & 0xc0) == 0xc0) 51 return 1; 52 #else 53 /* for the parts w/out qualification yet */ 54 (void)vr_ctl; 55 #endif 56 57 return 0; 58 } 59 60 static void set_otp_timing(bool write) 61 { 62 static uint32_t timing; 63 if (!timing) { 64 uint32_t tp1, tp2, tp3; 65 /* OTP_TP1 = 1000 / sclk_period (in nanoseconds) 66 * OTP_TP1 = 1000 / (1 / get_sclk() * 10^9) 67 * OTP_TP1 = (1000 * get_sclk()) / 10^9 68 * OTP_TP1 = get_sclk() / 10^6 69 */ 70 tp1 = get_sclk() / 1000000; 71 /* OTP_TP2 = 400 / (2 * sclk_period) 72 * OTP_TP2 = 400 / (2 * 1 / get_sclk() * 10^9) 73 * OTP_TP2 = (400 * get_sclk()) / (2 * 10^9) 74 * OTP_TP2 = (2 * get_sclk()) / 10^7 75 */ 76 tp2 = (2 * get_sclk() / 10000000) << 8; 77 /* OTP_TP3 = magic constant */ 78 tp3 = (0x1401) << 15; 79 timing = tp1 | tp2 | tp3; 80 } 81 82 bfrom_OtpCommand(OTP_INIT, write ? timing : timing & ~(-1 << 15)); 83 } 84 85 int do_otp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 86 { 87 char *cmd; 88 uint32_t ret, base_flags; 89 bool prompt_user, force_read; 90 uint32_t (*otp_func)(uint32_t page, uint32_t flags, uint64_t *page_content); 91 92 if (argc < 4) { 93 usage: 94 return CMD_RET_USAGE; 95 } 96 97 prompt_user = false; 98 base_flags = 0; 99 cmd = argv[1]; 100 if (!strcmp(cmd, "read")) 101 otp_func = bfrom_OtpRead; 102 else if (!strcmp(cmd, "dump")) { 103 otp_func = bfrom_OtpRead; 104 force_read = true; 105 } else if (!strcmp(cmd, "write")) { 106 otp_func = bfrom_OtpWrite; 107 base_flags = OTP_CHECK_FOR_PREV_WRITE; 108 if (!strcmp(argv[2], "--force")) { 109 argv++; 110 --argc; 111 } else 112 prompt_user = false; 113 } else if (!strcmp(cmd, "lock")) { 114 if (argc != 4) 115 goto usage; 116 otp_func = bfrom_OtpWrite; 117 base_flags = OTP_LOCK; 118 } else 119 goto usage; 120 121 uint64_t *addr = (uint64_t *)simple_strtoul(argv[2], NULL, 16); 122 uint32_t page = simple_strtoul(argv[3], NULL, 16); 123 uint32_t flags; 124 size_t i, count; 125 ulong half; 126 127 if (argc > 4) 128 count = simple_strtoul(argv[4], NULL, 16); 129 else 130 count = 2; 131 132 if (argc > 5) { 133 half = simple_strtoul(argv[5], NULL, 16); 134 if (half != 0 && half != 1) { 135 puts("Error: 'half' can only be '0' or '1'\n"); 136 goto usage; 137 } 138 } else 139 half = 0; 140 141 /* "otp lock" has slightly different semantics */ 142 if (base_flags & OTP_LOCK) { 143 count = page; 144 page = (uint32_t)addr; 145 addr = NULL; 146 } 147 148 /* do to the nature of OTP, make sure users are sure */ 149 if (prompt_user) { 150 printf( 151 "Writing one time programmable memory\n" 152 "Make sure your operating voltages and temperature are within spec\n" 153 " source address: 0x%p\n" 154 " OTP destination: %s page 0x%03X - %s page 0x%03lX\n" 155 " number to write: %lu halfpages\n" 156 " type \"YES\" (no quotes) to confirm: ", 157 addr, 158 lowup(half), page, 159 lowup(half + count - 1), page + (half + count - 1) / 2, 160 half + count 161 ); 162 if (!confirm_yesno()) { 163 printf(" Aborting\n"); 164 return 1; 165 } 166 } 167 168 printf("OTP memory %s: addr 0x%p page 0x%03X count %zu ... ", 169 cmd, addr, page, count); 170 171 set_otp_timing(otp_func == bfrom_OtpWrite); 172 if (otp_func == bfrom_OtpWrite && check_voltage()) { 173 puts("ERROR: VDDINT voltage is out of spec for writing\n"); 174 return -1; 175 } 176 177 /* Do the actual reading/writing stuff */ 178 ret = 0; 179 for (i = half; i < count + half; ++i) { 180 flags = base_flags | (i % 2 ? OTP_UPPER_HALF : OTP_LOWER_HALF); 181 try_again: 182 ret = otp_func(page, flags, addr); 183 if (ret & OTP_MASTER_ERROR) { 184 if (force_read) { 185 if (flags & OTP_NO_ECC) 186 break; 187 else 188 flags |= OTP_NO_ECC; 189 puts("E"); 190 goto try_again; 191 } else 192 break; 193 } else if (ret) 194 puts("W"); 195 else 196 puts("."); 197 if (!(base_flags & OTP_LOCK)) { 198 ++addr; 199 if (i % 2) 200 ++page; 201 } else 202 ++page; 203 } 204 if (ret & 0x1) 205 printf("\nERROR at page 0x%03X (%s-halfpage): 0x%03X: %s\n", 206 page, lowup(i), ret, otp_strerror(ret)); 207 else 208 puts(" done\n"); 209 210 /* Make sure we disable writing */ 211 set_otp_timing(false); 212 bfrom_OtpCommand(OTP_CLOSE, 0); 213 214 return ret; 215 } 216 217 U_BOOT_CMD( 218 otp, 7, 0, do_otp, 219 "One-Time-Programmable sub-system", 220 "read <addr> <page> [count] [half]\n" 221 " - read 'count' half-pages starting at 'page' (offset 'half') to 'addr'\n" 222 "otp dump <addr> <page> [count] [half]\n" 223 " - like 'otp read', but skip read errors\n" 224 "otp write [--force] <addr> <page> [count] [half]\n" 225 " - write 'count' half-pages starting at 'page' (offset 'half') from 'addr'\n" 226 "otp lock <page> <count>\n" 227 " - lock 'count' pages starting at 'page'" 228 ); 229