blob: 6cdc422594926a525c1bf0b81ae6e4956dfbbdc7 [file] [log] [blame]
Martha Marx5d3e23f2009-01-26 10:45:07 -07001/*
2 * Copyright 2008 Silicon Turnkey Express, Inc.
3 * Martha Marx <mmarx@silicontkx.com>
4 *
5 * ADS5121 IIM (Fusebox) Interface
6 *
7 * See file CREDITS for list of people who contributed to this
8 * project.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23 * MA 02111-1307 USA
24 */
25
26#include <common.h>
27#include <command.h>
28#include <asm/io.h>
29
30#ifdef CONFIG_CMD_FUSE
31
32DECLARE_GLOBAL_DATA_PTR;
33
34static char cur_bank = '1';
35
36char *iim_err_msg(u32 err)
37{
38 static char *IIM_errs[] = {
39 "Parity Error in cache",
40 "Explicit Sense Cycle Error",
41 "Write to Locked Register Error",
42 "Read Protect Error",
43 "Override Protect Error",
44 "Write Protect Error"};
45
46 int i;
47
48 if (!err)
49 return "";
50 for (i = 1; i < 8; i++)
51 if (err & (1 << i))
52 printf("IIM - %s\n", IIM_errs[i-1]);
53 return "";
54}
55
56int in_range(int n, int min, int max, char *err, char *usg)
57{
58 if (n > max || n < min) {
59 printf(err);
60 printf("Usage:\n%s\n", usg);
61 return 0;
62 }
63 return 1;
64}
65
66int ads5121_fuse_read(int bank, int fstart, int num)
67{
68 iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
69 u32 *iim_fb, dummy;
70 int f, ctr;
71
72 out_be32(&iim->err, in_be32(&iim->err));
73 if (bank == 0)
74 iim_fb = (u32 *)&(iim->fbac0);
75 else
76 iim_fb = (u32 *)&(iim->fbac1);
77/* try a read to see if Read Protect is set */
78 dummy = in_be32(&iim_fb[0]);
79 if (in_be32(&iim->err) & IIM_ERR_RPE) {
80 printf("\tRead protect fuse is set\n");
81 out_be32(&iim->err, IIM_ERR_RPE);
82 return 0;
83 }
84 printf("Reading Bank %d cache\n", bank);
85 for (f = fstart, ctr = 0; num > 0; ctr++, num--, f++) {
86 if (ctr % 4 == 0)
87 printf("F%2d:", f);
88 printf("\t%#04x", (u8)(iim_fb[f]));
89 if (ctr % 4 == 3)
90 printf("\n");
91 }
92 if (ctr % 4 != 0)
93 printf("\n");
94}
95
96int ads5121_fuse_override(int bank, int f, u8 val)
97{
98 iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
99 u32 *iim_fb;
100 u32 iim_stat;
101 int i;
102
103 out_be32(&iim->err, in_be32(&iim->err));
104 if (bank == 0)
105 iim_fb = (u32 *)&(iim->fbac0);
106 else
107 iim_fb = (u32 *)&(iim->fbac1);
108/* try a read to see if Read Protect is set */
109 iim_stat = in_be32(&iim_fb[0]);
110 if (in_be32(&iim->err) & IIM_ERR_RPE) {
111 printf("Read protect fuse is set on bank %d;"
112 "Override protect may also be set\n", bank);
113 printf("An attempt will be made to override\n");
114 out_be32(&iim->err, IIM_ERR_RPE);
115 }
116 if (iim_stat & IIM_FBAC_FBOP) {
117 printf("Override protect fuse is set on bank %d\n", bank);
118 return 1;
119 }
120 if (f > IIM_FMAX) /* reset the entire bank */
121 for (i = 0; i < IIM_FMAX + 1; i++)
122 out_be32(&iim_fb[i], 0);
123 else
124 out_be32(&iim_fb[f], val);
125 return 0;
126}
127
128int ads5121_fuse_prog(cmd_tbl_t *cmdtp, int bank, char *fuseno_bitno)
129{
130 iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
131 int f, i, bitno;
132 u32 stat, err;
133
134 f = simple_strtol(fuseno_bitno, NULL, 10);
135 if (f == 0 && fuseno_bitno[0] != '0')
136 f = -1;
137 if (!in_range(f, 0, IIM_FMAX,
138 "<frow> must be between 0-31\n\n", cmdtp->usage))
139 return 1;
140 bitno = -1;
141 for (i = 0; i < 6; i++) {
142 if (fuseno_bitno[i] == '_') {
143 bitno = simple_strtol(&(fuseno_bitno[i+1]), NULL, 10);
144 if (bitno == 0 && fuseno_bitno[i+1] != '0')
145 bitno = -1;
146 break;
147 }
148 }
149 if (!in_range(bitno, 0, 7, "Bit number ranges from 0-7\n"
150 "Example of <frow_bitno>: \"18_4\" sets bit 4 of row 18\n",
151 cmdtp->usage))
152 return 1;
153 out_be32(&iim->err, in_be32(&iim->err));
154 out_be32(&iim->prg_p, IIM_PRG_P_SET);
155 out_be32(&iim->ua, IIM_SET_UA(bank, f));
156 out_be32(&iim->la, IIM_SET_LA(f, bitno));
157#ifdef DEBUG
158 printf("Programming disabled with DEBUG defined \n");
159 printf(""Set up to pro
160 printf("iim.ua = %x; iim.la = %x\n", iim->ua, iim->la);
161#else
162 out_be32(&iim->fctl, IIM_FCTL_PROG_PULSE | IIM_FCTL_PROG);
163 do
164 udelay(20);
165 while ((stat = in_be32(&iim->stat)) & IIM_STAT_BUSY);
166 out_be32(&iim->prg_p, 0);
167 err = in_be32(&iim->err);
168 if (stat & IIM_STAT_PRGD) {
169 if (!(err & (IIM_ERR_WPE | IIM_ERR_WPE))) {
170 printf("Fuse is successfully set");
171 if (err)
172 printf(" - however there are other errors");
173 printf("\n");
174 }
175 iim->stat = 0;
176 }
177 if (err) {
178 iim_err_msg(err);
179 out_be32(&iim->err, in_be32(&iim->err));
180 }
181#endif
182}
183
184int ads5121_fuse_sense(int bank, int fstart, int num)
185{
186 iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
187 u32 iim_fbac;
188 u32 stat, err, err_hold = 0;
189 int f, ctr;
190
191 out_be32(&iim->err, in_be32(&iim->err));
192 if (bank == 0)
193 iim_fbac = in_be32(&iim->fbac0);
194 else
195 iim_fbac = in_be32(&iim->fbac1);
196 if (iim_fbac & IIM_FBAC_FBESP) {
197 printf("\tSense Protect disallows this operation\n");
198 out_be32(&iim->err, IIM_FBAC_FBESP);
199 return 1;
200 }
201 err = in_be32(&iim->err);
202 if (err) {
203 iim_err_msg(err);
204 err_hold |= err;
205 }
206 if (err & IIM_ERR_RPE)
207 printf("\tRead protect fuse is set; "
208 "Sense Protect may be set but will be attempted\n");
209 if (err)
210 out_be32(&iim->err, err);
211 printf("Sensing fuse(s) on Bank %d\n", bank);
212 for (f = fstart, ctr = 0; num > 0; ctr++, f++, num--) {
213 out_be32(&iim->ua, IIM_SET_UA(bank, f));
214 out_be32(&iim->la, IIM_SET_LA(f, 0));
215 out_be32(&iim->fctl, IIM_FCTL_ESNS_N);
216 do
217 udelay(20);
218 while ((stat = in_be32(&iim->stat)) & IIM_STAT_BUSY);
219 err = in_be32(&iim->err);
220 if (err & IIM_ERR_SNSE) {
221 iim_err_msg(err);
222 out_be32(&iim->err, IIM_ERR_SNSE);
223 return 1;
224 }
225 if (stat & IIM_STAT_SNSD) {
226 out_be32(&iim->stat, 0);
227 if (ctr % 4 == 0)
228 printf("F%2d:", f);
229 printf("\t%#04x", (u8)iim->sdat);
230 if (ctr % 4 == 3)
231 printf("\n");
232 }
233 if (err) {
234 err_hold |= err;
235 out_be32(&iim->err, err);
236 }
237 }
238 if (ctr % 4 != 0)
239 printf("\n");
240 if (err_hold)
241 iim_err_msg(err_hold);
242
243 return 0;
244}
245
246int ads5121_fuse_stat(int bank)
247{
248 iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
249 u32 iim_fbac;
250 u32 err;
251
252 out_be32(&iim->err, in_be32(&iim->err));
253 if (bank == 0)
254 iim_fbac = in_be32(&iim->fbac0);
255 else
256 iim_fbac = in_be32(&iim->fbac1);
257 err = in_be32(&iim->err);
258 if (err)
259 iim_err_msg(err);
260 if (err & IIM_ERR_RPE || iim_fbac & IIM_FBAC_FBRP) {
261 if (iim_fbac == 0)
262 printf("Since protection settings can't be read - "
263 "try sensing fuse row 0;\n");
264 return 0;
265 }
266 if (iim_fbac & IIM_PROTECTION)
267 printf("Protection Fuses Bank %d = %#04x:\n", bank, iim_fbac);
268 else if (!(err & IIM_ERR_RPE))
269 printf("No Protection fuses are set\n");
270 if (iim_fbac & IIM_FBAC_FBWP)
271 printf("\tWrite Protect fuse is set\n");
272 if (iim_fbac & IIM_FBAC_FBOP)
273 printf("\tOverride Protect fuse is set\n");
274 if (iim_fbac & IIM_FBAC_FBESP)
275 printf("\tSense Protect Fuse is set\n");
276 out_be32(&iim->err, in_be32(&iim->err));
277
278 return 0;
279}
280
281int do_ads5121_fuse(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
282{
283 int frow, n, v, bank;
284
285 if (cur_bank == '0')
286 bank = 0;
287 else
288 bank = 1;
289
290 switch (argc) {
291 case 0:
292 case 1:
293 printf("Usage:\n%s\n", cmdtp->usage);
294 return 1;
295 case 2:
296 if (strncmp(argv[1], "stat", 4) == 0)
297 return ads5121_fuse_stat(bank);
298 if (strncmp(argv[1], "read", 4) == 0)
299 return ads5121_fuse_read(bank, 0, IIM_FMAX + 1);
300 if (strncmp(argv[1], "sense", 5) == 0)
301 return ads5121_fuse_sense(bank, 0, IIM_FMAX + 1);
302 if (strncmp(argv[1], "ovride", 6) == 0)
303 return ads5121_fuse_override(bank, IIM_FMAX + 1, 0);
304 if (strncmp(argv[1], "bank", 4) == 0) {
305 printf("Active Fuse Bank is %c\n", cur_bank);
306 return 0;
307 }
308 printf("Usage:\n%s\n", cmdtp->usage);
309 return 1;
310 case 3:
311 if (strncmp(argv[1], "bank", 4) == 0) {
312 if (argv[2][0] == '0')
313 cur_bank = '0';
314 else if (argv[2][0] == '1')
315 cur_bank = '1';
316 else {
317 printf("Usage:\n%s\n", cmdtp->usage);
318 return 1;
319 }
320
321 printf("Setting Active Fuse Bank to %c\n", cur_bank);
322 return 0;
323 }
324 if (strncmp(argv[1], "prog", 4) == 0)
325 return ads5121_fuse_prog(cmdtp, bank, argv[2]);
326
327 frow = (int)simple_strtol(argv[2], NULL, 10);
328 if (frow == 0 && argv[2][0] != '0')
329 frow = -1;
330 if (!in_range(frow, 0, IIM_FMAX,
331 "<frow> must be between 0-31\n\n", cmdtp->usage))
332 return 1;
333 if (strncmp(argv[1], "read", 4) == 0)
334 return ads5121_fuse_read(bank, frow, 1);
335 if (strncmp(argv[1], "ovride", 6) == 0)
336 return ads5121_fuse_override(bank, frow, 0);
337 if (strncmp(argv[1], "sense", 5) == 0)
338 return ads5121_fuse_sense(bank, frow, 1);
339 printf("Usage:\n%s\n", cmdtp->usage);
340 return 1;
341 case 4:
342 frow = (int)simple_strtol(argv[2], NULL, 10);
343 if (frow == 0 && argv[2][0] != '0')
344 frow = -1;
345 if (!in_range(frow, 0, IIM_FMAX,
346 "<frow> must be between 0-31\n\n", cmdtp->usage))
347 return 1;
348 if (strncmp(argv[1], "read", 4) == 0) {
349 n = (int)simple_strtol(argv[3], NULL, 10);
350 if (!in_range(frow + n, frow + 1, IIM_FMAX + 1,
351 "<frow>+<n> must be between 1-32\n\n",
352 cmdtp->usage))
353 return 1;
354 return ads5121_fuse_read(bank, frow, n);
355 }
356 if (strncmp(argv[1], "ovride", 6) == 0) {
357 v = (int)simple_strtol(argv[3], NULL, 10);
358 return ads5121_fuse_override(bank, frow, v);
359 }
360 if (strncmp(argv[1], "sense", 5) == 0) {
361 n = (int)simple_strtol(argv[3], NULL, 10);
362 if (!in_range(frow + n, frow + 1, IIM_FMAX + 1,
363 "<frow>+<n> must be between 1-32\n\n",
364 cmdtp->usage))
365 return 1;
366 return ads5121_fuse_sense(bank, frow, n);
367 }
368 printf("Usage:\n%s\n", cmdtp->usage);
369 return 1;
370 default: /* at least 5 args */
371 printf("Usage:\n%s\n", cmdtp->usage);
372 return 1;
373 }
374}
375
376U_BOOT_CMD(
377 fuse, CONFIG_SYS_MAXARGS, 0, do_ads5121_fuse,
378 " - Read, Sense, Override or Program Fuses\n",
379 "bank <n> - sets active Fuse Bank to 0 or 1\n"
380 " no args shows current active bank\n"
381 "fuse stat - print active fuse bank's protection status\n"
382 "fuse read [<frow> [<n>]] - print <n> fuse rows starting at <frow>\n"
383 " no args to print entire bank's fuses\n"
384 "fuse ovride [<frow> [<v>]]- override fuses at <frow> with <v>\n"
385 " no <v> defaults to 0 for the row\n"
386 " no args resets entire bank to 0\n"
387 " NOTE - settings persist until hard reset\n"
388 "fuse sense [<frow>] - senses current fuse at <frow>\n"
389 " no args for entire bank\n"
390 "fuse prog <frow_bit> - program fuse at row <frow>, bit <_bit>\n"
391 " <frow> is 0-31, <bit> is 0-7; eg. 13_2 \n"
392 " WARNING - this is permanent\n"
393 );
394#endif /* CONFIG_CMD_FUSE */