blob: d032b001fd86580f1c3d68bfe5e4de569595f7fc [file] [log] [blame]
wdenkaffae2b2002-08-17 09:36:01 +00001/*
2 * (C) Copyright 2001
3 * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <common.h>
25#include <ppc4xx.h>
26#include <asm/processor.h>
27
28flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
29
30/*-----------------------------------------------------------------------
31 * Functions
32 */
33static int write_word (flash_info_t *info, ulong dest, ulong data);
34
35/*-----------------------------------------------------------------------
36 */
37static void flash_get_offsets (ulong base, flash_info_t *info)
38{
39 int i;
40 short n;
41
42 /* set up sector start address table */
wdenk8bde7f72003-06-27 21:31:46 +000043 if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
wdenkaffae2b2002-08-17 09:36:01 +000044 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U)) {
45 for (i = 0; i < info->sector_count; i++)
46 info->start[i] = base + (i * 0x00010000);
wdenk8bde7f72003-06-27 21:31:46 +000047 } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322B) ||
wdenkaffae2b2002-08-17 09:36:01 +000048 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323B) ||
49 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||
50 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324B)) {
51 /* set sector offsets for bottom boot block type */
52 for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
53 info->start[i] = base;
54 base += 8 << 10;
55 }
56 while (i < info->sector_count) { /* 64k regular sectors */
57 info->start[i] = base;
58 base += 64 << 10;
59 ++i;
60 }
wdenk8bde7f72003-06-27 21:31:46 +000061 } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322T) ||
wdenkaffae2b2002-08-17 09:36:01 +000062 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323T) ||
63 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||
64 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324T)) {
65 /* set sector offsets for top boot block type */
66 base += info->size;
67 i = info->sector_count;
68 for (n=0; n<8; ++n) { /* 8 x 8k boot sectors */
69 base -= 8 << 10;
70 --i;
71 info->start[i] = base;
72 }
73 while (i > 0) { /* 64k regular sectors */
74 base -= 64 << 10;
75 --i;
76 info->start[i] = base;
77 }
wdenk8bde7f72003-06-27 21:31:46 +000078 } else {
wdenkaffae2b2002-08-17 09:36:01 +000079 if (info->flash_id & FLASH_BTYPE) {
80 /* set sector offsets for bottom boot block type */
81 info->start[0] = base + 0x00000000;
82 info->start[1] = base + 0x00004000;
83 info->start[2] = base + 0x00006000;
84 info->start[3] = base + 0x00008000;
85 for (i = 4; i < info->sector_count; i++) {
86 info->start[i] = base + (i * 0x00010000) - 0x00030000;
87 }
88 } else {
89 /* set sector offsets for top boot block type */
90 i = info->sector_count - 1;
91 info->start[i--] = base + info->size - 0x00004000;
92 info->start[i--] = base + info->size - 0x00006000;
93 info->start[i--] = base + info->size - 0x00008000;
94 for (; i >= 0; i--) {
95 info->start[i] = base + i * 0x00010000;
96 }
97 }
98 }
99}
100
101/*-----------------------------------------------------------------------
102 */
103void flash_print_info (flash_info_t *info)
104{
105 int i;
wdenk8bde7f72003-06-27 21:31:46 +0000106 int k;
107 int size;
108 int erased;
109 volatile unsigned long *flash;
wdenkaffae2b2002-08-17 09:36:01 +0000110
111 if (info->flash_id == FLASH_UNKNOWN) {
112 printf ("missing or unknown FLASH type\n");
113 return;
114 }
115
116 switch (info->flash_id & FLASH_VENDMASK) {
117 case FLASH_MAN_AMD: printf ("AMD "); break;
118 case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
119 case FLASH_MAN_SST: printf ("SST "); break;
120 default: printf ("Unknown Vendor "); break;
121 }
122
123 switch (info->flash_id & FLASH_TYPEMASK) {
124 case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
125 break;
126 case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
127 break;
128 case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
129 break;
130 case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
131 break;
132 case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
133 break;
134 case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
135 break;
136 case FLASH_AM320T: printf ("AM29LV320T (32 M, top sector)\n");
137 break;
138 case FLASH_AM320B: printf ("AM29LV320B (32 M, bottom sector)\n");
139 break;
140 case FLASH_AMDL322T: printf ("AM29DL322T (32 M, top sector)\n");
141 break;
142 case FLASH_AMDL322B: printf ("AM29DL322B (32 M, bottom sector)\n");
143 break;
144 case FLASH_AMDL323T: printf ("AM29DL323T (32 M, top sector)\n");
145 break;
146 case FLASH_AMDL323B: printf ("AM29DL323B (32 M, bottom sector)\n");
147 break;
148 case FLASH_AM640U: printf ("AM29LV640D (64 M, uniform sector)\n");
149 break;
150 case FLASH_SST800A: printf ("SST39LF/VF800 (8 Mbit, uniform sector size)\n");
151 break;
152 case FLASH_SST160A: printf ("SST39LF/VF160 (16 Mbit, uniform sector size)\n");
153 break;
154 default: printf ("Unknown Chip Type\n");
155 break;
156 }
157
158 printf (" Size: %ld MB in %d Sectors\n",
159 info->size >> 20, info->sector_count);
160
161 printf (" Sector Start Addresses:");
162 for (i=0; i<info->sector_count; ++i) {
163#ifdef CFG_FLASH_EMPTY_INFO
wdenk8bde7f72003-06-27 21:31:46 +0000164 /*
165 * Check if whole sector is erased
166 */
167 if (i != (info->sector_count-1))
168 size = info->start[i+1] - info->start[i];
169 else
170 size = info->start[0] + info->size - info->start[i];
171 erased = 1;
172 flash = (volatile unsigned long *)info->start[i];
173 size = size >> 2; /* divide by 4 for longword access */
174 for (k=0; k<size; k++)
175 {
176 if (*flash++ != 0xffffffff)
177 {
178 erased = 0;
179 break;
180 }
181 }
wdenkaffae2b2002-08-17 09:36:01 +0000182
183 if ((i % 5) == 0)
184 printf ("\n ");
wdenk8bde7f72003-06-27 21:31:46 +0000185 /* print empty and read-only info */
wdenkaffae2b2002-08-17 09:36:01 +0000186 printf (" %08lX%s%s",
187 info->start[i],
188 erased ? " E" : " ",
189 info->protect[i] ? "RO " : " ");
190#else
191 if ((i % 5) == 0)
192 printf ("\n ");
193 printf (" %08lX%s",
194 info->start[i],
195 info->protect[i] ? " (RO)" : " ");
196#endif
197
198 }
199 printf ("\n");
200 return;
201}
202
203/*-----------------------------------------------------------------------
204 */
205
206
207/*-----------------------------------------------------------------------
208 */
209
210/*
211 * The following code cannot be run from FLASH!
212 */
213static ulong flash_get_size (vu_long *addr, flash_info_t *info)
214{
215 short i;
216 short n;
217 CFG_FLASH_WORD_SIZE value;
218 ulong base = (ulong)addr;
wdenk8bde7f72003-06-27 21:31:46 +0000219 volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *)addr;
wdenkaffae2b2002-08-17 09:36:01 +0000220
221 /* Write auto select command: read Manufacturer ID */
222 addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
223 addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
224 addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00900090;
225
226 value = addr2[CFG_FLASH_READ0];
227
228 switch (value) {
229 case (CFG_FLASH_WORD_SIZE)AMD_MANUFACT:
230 info->flash_id = FLASH_MAN_AMD;
231 break;
232 case (CFG_FLASH_WORD_SIZE)FUJ_MANUFACT:
233 info->flash_id = FLASH_MAN_FUJ;
234 break;
235 case (CFG_FLASH_WORD_SIZE)SST_MANUFACT:
236 info->flash_id = FLASH_MAN_SST;
237 break;
238 default:
239 info->flash_id = FLASH_UNKNOWN;
240 info->sector_count = 0;
241 info->size = 0;
242 return (0); /* no or unknown flash */
243 }
244
245 value = addr2[CFG_FLASH_READ1]; /* device ID */
246
247 switch (value) {
248 case (CFG_FLASH_WORD_SIZE)AMD_ID_LV400T:
249 info->flash_id += FLASH_AM400T;
250 info->sector_count = 11;
251 info->size = 0x00080000;
252 break; /* => 0.5 MB */
253
254 case (CFG_FLASH_WORD_SIZE)AMD_ID_LV400B:
255 info->flash_id += FLASH_AM400B;
256 info->sector_count = 11;
257 info->size = 0x00080000;
258 break; /* => 0.5 MB */
259
260 case (CFG_FLASH_WORD_SIZE)AMD_ID_LV800T:
261 info->flash_id += FLASH_AM800T;
262 info->sector_count = 19;
263 info->size = 0x00100000;
264 break; /* => 1 MB */
265
266 case (CFG_FLASH_WORD_SIZE)AMD_ID_LV800B:
267 info->flash_id += FLASH_AM800B;
268 info->sector_count = 19;
269 info->size = 0x00100000;
270 break; /* => 1 MB */
271
272 case (CFG_FLASH_WORD_SIZE)AMD_ID_LV160T:
273 info->flash_id += FLASH_AM160T;
274 info->sector_count = 35;
275 info->size = 0x00200000;
276 break; /* => 2 MB */
277
278 case (CFG_FLASH_WORD_SIZE)AMD_ID_LV160B:
279 info->flash_id += FLASH_AM160B;
280 info->sector_count = 35;
281 info->size = 0x00200000;
282 break; /* => 2 MB */
283
284 case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320T:
wdenk8bde7f72003-06-27 21:31:46 +0000285 info->flash_id += FLASH_AM320T;
286 info->sector_count = 71;
wdenkaffae2b2002-08-17 09:36:01 +0000287 info->size = 0x00400000; break; /* => 4 MB */
288
289 case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320B:
wdenk8bde7f72003-06-27 21:31:46 +0000290 info->flash_id += FLASH_AM320B;
wdenkaffae2b2002-08-17 09:36:01 +0000291 info->sector_count = 71;
292 info->size = 0x00400000; break; /* => 4 MB */
293
294 case (CFG_FLASH_WORD_SIZE)AMD_ID_DL322T:
wdenk8bde7f72003-06-27 21:31:46 +0000295 info->flash_id += FLASH_AMDL322T;
296 info->sector_count = 71;
wdenkaffae2b2002-08-17 09:36:01 +0000297 info->size = 0x00400000; break; /* => 4 MB */
298
299 case (CFG_FLASH_WORD_SIZE)AMD_ID_DL322B:
wdenk8bde7f72003-06-27 21:31:46 +0000300 info->flash_id += FLASH_AMDL322B;
wdenkaffae2b2002-08-17 09:36:01 +0000301 info->sector_count = 71;
302 info->size = 0x00400000; break; /* => 4 MB */
303
304 case (CFG_FLASH_WORD_SIZE)AMD_ID_DL323T:
wdenk8bde7f72003-06-27 21:31:46 +0000305 info->flash_id += FLASH_AMDL323T;
wdenkaffae2b2002-08-17 09:36:01 +0000306 info->sector_count = 71;
307 info->size = 0x00400000; break; /* => 4 MB */
308
309 case (CFG_FLASH_WORD_SIZE)AMD_ID_DL323B:
wdenk8bde7f72003-06-27 21:31:46 +0000310 info->flash_id += FLASH_AMDL323B;
wdenkaffae2b2002-08-17 09:36:01 +0000311 info->sector_count = 71;
312 info->size = 0x00400000; break; /* => 4 MB */
313
314 case (CFG_FLASH_WORD_SIZE)AMD_ID_LV640U:
wdenk8bde7f72003-06-27 21:31:46 +0000315 info->flash_id += FLASH_AM640U;
wdenkaffae2b2002-08-17 09:36:01 +0000316 info->sector_count = 128;
317 info->size = 0x00800000; break; /* => 8 MB */
318
319 case (CFG_FLASH_WORD_SIZE)SST_ID_xF800A:
320 info->flash_id += FLASH_SST800A;
321 info->sector_count = 16;
322 info->size = 0x00100000;
323 break; /* => 1 MB */
324
325 case (CFG_FLASH_WORD_SIZE)SST_ID_xF160A:
326 info->flash_id += FLASH_SST160A;
327 info->sector_count = 32;
328 info->size = 0x00200000;
329 break; /* => 2 MB */
330
331 default:
332 info->flash_id = FLASH_UNKNOWN;
333 return (0); /* => no or unknown flash */
334
335 }
336
337 /* set up sector start address table */
wdenk8bde7f72003-06-27 21:31:46 +0000338 if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
wdenkaffae2b2002-08-17 09:36:01 +0000339 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U)) {
340 for (i = 0; i < info->sector_count; i++)
341 info->start[i] = base + (i * 0x00010000);
wdenk8bde7f72003-06-27 21:31:46 +0000342 } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322B) ||
wdenkaffae2b2002-08-17 09:36:01 +0000343 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323B) ||
344 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||
345 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324B)) {
346 /* set sector offsets for bottom boot block type */
347 for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
348 info->start[i] = base;
349 base += 8 << 10;
350 }
351 while (i < info->sector_count) { /* 64k regular sectors */
352 info->start[i] = base;
353 base += 64 << 10;
354 ++i;
355 }
wdenk8bde7f72003-06-27 21:31:46 +0000356 } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322T) ||
wdenkaffae2b2002-08-17 09:36:01 +0000357 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323T) ||
358 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||
359 ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324T)) {
360 /* set sector offsets for top boot block type */
361 base += info->size;
362 i = info->sector_count;
363 for (n=0; n<8; ++n) { /* 8 x 8k boot sectors */
364 base -= 8 << 10;
365 --i;
366 info->start[i] = base;
367 }
368 while (i > 0) { /* 64k regular sectors */
369 base -= 64 << 10;
370 --i;
371 info->start[i] = base;
372 }
wdenk8bde7f72003-06-27 21:31:46 +0000373 } else {
wdenkaffae2b2002-08-17 09:36:01 +0000374 if (info->flash_id & FLASH_BTYPE) {
375 /* set sector offsets for bottom boot block type */
376 info->start[0] = base + 0x00000000;
377 info->start[1] = base + 0x00004000;
378 info->start[2] = base + 0x00006000;
379 info->start[3] = base + 0x00008000;
380 for (i = 4; i < info->sector_count; i++) {
381 info->start[i] = base + (i * 0x00010000) - 0x00030000;
382 }
383 } else {
384 /* set sector offsets for top boot block type */
385 i = info->sector_count - 1;
386 info->start[i--] = base + info->size - 0x00004000;
387 info->start[i--] = base + info->size - 0x00006000;
388 info->start[i--] = base + info->size - 0x00008000;
389 for (; i >= 0; i--) {
390 info->start[i] = base + i * 0x00010000;
391 }
392 }
393 }
394
395 /* check for protected sectors */
396 for (i = 0; i < info->sector_count; i++) {
397 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
398 /* D0 = 1 if protected */
399 addr2 = (volatile CFG_FLASH_WORD_SIZE *)(info->start[i]);
wdenk8bde7f72003-06-27 21:31:46 +0000400 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST)
401 info->protect[i] = 0;
402 else
403 info->protect[i] = addr2[CFG_FLASH_READ2] & 1;
wdenkaffae2b2002-08-17 09:36:01 +0000404 }
405
406 /*
407 * Prevent writes to uninitialized FLASH.
408 */
409 if (info->flash_id != FLASH_UNKNOWN) {
410 addr2 = (CFG_FLASH_WORD_SIZE *)info->start[0];
411 *addr2 = (CFG_FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
412 }
413
414 return (info->size);
415}
416
417
418/*-----------------------------------------------------------------------
419 */
420
421int flash_erase (flash_info_t *info, int s_first, int s_last)
422{
423 volatile CFG_FLASH_WORD_SIZE *addr = (CFG_FLASH_WORD_SIZE *)(info->start[0]);
424 volatile CFG_FLASH_WORD_SIZE *addr2;
425 int flag, prot, sect, l_sect;
426 ulong start, now, last;
wdenk8bde7f72003-06-27 21:31:46 +0000427 int i;
wdenkaffae2b2002-08-17 09:36:01 +0000428
429 if ((s_first < 0) || (s_first > s_last)) {
430 if (info->flash_id == FLASH_UNKNOWN) {
431 printf ("- missing\n");
432 } else {
433 printf ("- no sectors to erase\n");
434 }
435 return 1;
436 }
437
438 if (info->flash_id == FLASH_UNKNOWN) {
439 printf ("Can't erase unknown flash type - aborted\n");
440 return 1;
441 }
442
443 prot = 0;
444 for (sect=s_first; sect<=s_last; ++sect) {
445 if (info->protect[sect]) {
446 prot++;
447 }
448 }
449
450 if (prot) {
451 printf ("- Warning: %d protected sectors will not be erased!\n",
452 prot);
453 } else {
454 printf ("\n");
455 }
456
457 l_sect = -1;
458
459 /* Disable interrupts which might cause a timeout here */
460 flag = disable_interrupts();
461
462 /* Start erase on unprotected sectors */
463 for (sect = s_first; sect<=s_last; sect++) {
464 if (info->protect[sect] == 0) { /* not protected */
465 addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[sect]);
wdenk8bde7f72003-06-27 21:31:46 +0000466 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
467 addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
468 addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
469 addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;
470 addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
471 addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
472 addr2[0] = (CFG_FLASH_WORD_SIZE)0x00500050; /* block erase */
473 for (i=0; i<50; i++)
474 udelay(1000); /* wait 1 ms */
475 } else {
476 if (sect == s_first) {
477 addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
478 addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
479 addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;
480 addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
481 addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
482 }
483 addr2[0] = (CFG_FLASH_WORD_SIZE)0x00300030; /* sector erase */
484 }
wdenkaffae2b2002-08-17 09:36:01 +0000485 l_sect = sect;
486 }
487 }
488
489 /* re-enable interrupts if necessary */
490 if (flag)
491 enable_interrupts();
492
493 /* wait at least 80us - let's wait 1 ms */
494 udelay (1000);
495
496 /*
497 * We wait for the last triggered sector
498 */
499 if (l_sect < 0)
500 goto DONE;
501
502 start = get_timer (0);
503 last = start;
504 addr = (CFG_FLASH_WORD_SIZE *)(info->start[l_sect]);
505 while ((addr[0] & (CFG_FLASH_WORD_SIZE)0x00800080) != (CFG_FLASH_WORD_SIZE)0x00800080) {
506 if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
507 printf ("Timeout\n");
508 return 1;
509 }
510 /* show that we're waiting */
511 if ((now - last) > 1000) { /* every second */
512 putc ('.');
513 last = now;
514 }
515 }
516
517DONE:
518 /* reset to read mode */
519 addr = (CFG_FLASH_WORD_SIZE *)info->start[0];
520 addr[0] = (CFG_FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
521
522 printf (" done\n");
523 return 0;
524}
525
526/*-----------------------------------------------------------------------
527 * Copy memory to flash, returns:
528 * 0 - OK
529 * 1 - write timeout
530 * 2 - Flash not erased
531 */
532
533int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
534{
535 ulong cp, wp, data;
536 int i, l, rc;
537
538 wp = (addr & ~3); /* get lower word aligned address */
539
540 /*
541 * handle unaligned start bytes
542 */
543 if ((l = addr - wp) != 0) {
544 data = 0;
545 for (i=0, cp=wp; i<l; ++i, ++cp) {
546 data = (data << 8) | (*(uchar *)cp);
547 }
548 for (; i<4 && cnt>0; ++i) {
549 data = (data << 8) | *src++;
550 --cnt;
551 ++cp;
552 }
553 for (; cnt==0 && i<4; ++i, ++cp) {
554 data = (data << 8) | (*(uchar *)cp);
555 }
556
557 if ((rc = write_word(info, wp, data)) != 0) {
558 return (rc);
559 }
560 wp += 4;
561 }
562
563 /*
564 * handle word aligned part
565 */
566 while (cnt >= 4) {
567 data = 0;
568 for (i=0; i<4; ++i) {
569 data = (data << 8) | *src++;
570 }
571 if ((rc = write_word(info, wp, data)) != 0) {
572 return (rc);
573 }
574 wp += 4;
575 cnt -= 4;
576 }
577
578 if (cnt == 0) {
579 return (0);
580 }
581
582 /*
583 * handle unaligned tail bytes
584 */
585 data = 0;
586 for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
587 data = (data << 8) | *src++;
588 --cnt;
589 }
590 for (; i<4; ++i, ++cp) {
591 data = (data << 8) | (*(uchar *)cp);
592 }
593
594 return (write_word(info, wp, data));
595}
596
597/*-----------------------------------------------------------------------
598 * Write a word to Flash, returns:
599 * 0 - OK
600 * 1 - write timeout
601 * 2 - Flash not erased
602 */
603static int write_word (flash_info_t *info, ulong dest, ulong data)
604{
wdenk8bde7f72003-06-27 21:31:46 +0000605 volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[0]);
606 volatile CFG_FLASH_WORD_SIZE *dest2 = (CFG_FLASH_WORD_SIZE *)dest;
607 volatile CFG_FLASH_WORD_SIZE *data2 = (CFG_FLASH_WORD_SIZE *)&data;
wdenkaffae2b2002-08-17 09:36:01 +0000608 ulong start;
609 int flag;
wdenk8bde7f72003-06-27 21:31:46 +0000610 int i;
wdenkaffae2b2002-08-17 09:36:01 +0000611
612 /* Check if Flash is (sufficiently) erased */
613 if ((*((volatile CFG_FLASH_WORD_SIZE *)dest) &
wdenk8bde7f72003-06-27 21:31:46 +0000614 (CFG_FLASH_WORD_SIZE)data) != (CFG_FLASH_WORD_SIZE)data) {
wdenkaffae2b2002-08-17 09:36:01 +0000615 return (2);
616 }
617 /* Disable interrupts which might cause a timeout here */
618 flag = disable_interrupts();
619
wdenk8bde7f72003-06-27 21:31:46 +0000620 for (i=0; i<4/sizeof(CFG_FLASH_WORD_SIZE); i++)
621 {
622 addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
623 addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
624 addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00A000A0;
wdenkaffae2b2002-08-17 09:36:01 +0000625
wdenk8bde7f72003-06-27 21:31:46 +0000626 dest2[i] = data2[i];
wdenkaffae2b2002-08-17 09:36:01 +0000627
wdenk8bde7f72003-06-27 21:31:46 +0000628 /* re-enable interrupts if necessary */
629 if (flag)
630 enable_interrupts();
wdenkaffae2b2002-08-17 09:36:01 +0000631
wdenk8bde7f72003-06-27 21:31:46 +0000632 /* data polling for D7 */
633 start = get_timer (0);
634 while ((dest2[i] & (CFG_FLASH_WORD_SIZE)0x00800080) !=
635 (data2[i] & (CFG_FLASH_WORD_SIZE)0x00800080)) {
636 if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
637 return (1);
638 }
639 }
640 }
wdenkaffae2b2002-08-17 09:36:01 +0000641
642 return (0);
643}
644
645/*-----------------------------------------------------------------------
646 */