]> git.ipfire.org Git - people/ms/u-boot.git/blame - board/tqm8xx/flash.c
* Add support for NSCU board
[people/ms/u-boot.git] / board / tqm8xx / flash.c
CommitLineData
c609719b
WD
1/*
2 * (C) Copyright 2000-2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
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
73a8b27c
WD
24/* #define DEBUG */
25
c609719b
WD
26#include <common.h>
27#include <mpc8xx.h>
71f95118 28#include <environment.h>
c609719b
WD
29
30#ifndef CFG_ENV_ADDR
31#define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
32#endif
33
34flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
35
36/*-----------------------------------------------------------------------
37 * Functions
38 */
39static ulong flash_get_size (vu_long *addr, flash_info_t *info);
40static int write_word (flash_info_t *info, ulong dest, ulong data);
41
42/*-----------------------------------------------------------------------
43 */
44
45unsigned long flash_init (void)
46{
47 volatile immap_t *immap = (immap_t *)CFG_IMMR;
48 volatile memctl8xx_t *memctl = &immap->im_memctl;
49 unsigned long size_b0, size_b1;
50 int i;
51
52 /* Init: no FLASHes known */
53 for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
54 flash_info[i].flash_id = FLASH_UNKNOWN;
55 }
56
57 /* Static FLASH Bank configuration here - FIXME XXX */
58
73a8b27c
WD
59 debug ("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
60
c609719b
WD
61 size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
62
73a8b27c
WD
63 debug ("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE1_PRELIM);
64
c609719b
WD
65 if (flash_info[0].flash_id == FLASH_UNKNOWN) {
66 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
67 size_b0, size_b0<<20);
68 }
69
70 size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
71
73a8b27c
WD
72 debug ("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
73
c609719b
WD
74 if (size_b1 > size_b0) {
75 printf ("## ERROR: "
76 "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
77 size_b1, size_b1<<20,
78 size_b0, size_b0<<20
79 );
80 flash_info[0].flash_id = FLASH_UNKNOWN;
81 flash_info[1].flash_id = FLASH_UNKNOWN;
82 flash_info[0].sector_count = -1;
83 flash_info[1].sector_count = -1;
84 flash_info[0].size = 0;
85 flash_info[1].size = 0;
86 return (0);
87 }
88
73a8b27c
WD
89 debug ("## Before remap: "
90 "BR0: 0x%08x OR0: 0x%08x "
91 "BR1: 0x%08x OR1: 0x%08x\n",
92 memctl->memc_br0, memctl->memc_or0,
93 memctl->memc_br1, memctl->memc_or1);
94
c609719b
WD
95 /* Remap FLASH according to real size */
96 memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
97 memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
98
73a8b27c
WD
99 debug ("## BR0: 0x%08x OR0: 0x%08x\n",
100 memctl->memc_br0, memctl->memc_or0);
101
c609719b
WD
102 /* Re-do sizing to get full correct info */
103 size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
104
105#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
106 /* monitor protection ON by default */
71f95118
WD
107 debug ("Protect monitor: %08lx ... %08lx\n",
108 (ulong)CFG_MONITOR_BASE,
109 (ulong)CFG_MONITOR_BASE + monitor_flash_len - 1);
110
c609719b
WD
111 flash_protect(FLAG_PROTECT_SET,
112 CFG_MONITOR_BASE,
71f95118 113 CFG_MONITOR_BASE + monitor_flash_len - 1,
c609719b
WD
114 &flash_info[0]);
115#endif
116
117#ifdef CFG_ENV_IS_IN_FLASH
118 /* ENV protection ON by default */
71f95118
WD
119 debug ("Protect %senvironment: %08lx ... %08lx\n",
120# ifdef CFG_ENV_ADDR_REDUND
121 "primary ",
122# else
123 "",
124# endif
125 (ulong)CFG_ENV_ADDR,
126 (ulong)CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1);
127
c609719b
WD
128 flash_protect(FLAG_PROTECT_SET,
129 CFG_ENV_ADDR,
71f95118
WD
130 CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
131 &flash_info[0]);
132#endif
133
134#ifdef CFG_ENV_ADDR_REDUND
135 debug ("Protect redundand environment: %08lx ... %08lx\n",
136 (ulong)CFG_ENV_ADDR_REDUND,
137 (ulong)CFG_ENV_ADDR_REDUND + CFG_ENV_SECT_SIZE - 1);
138
139 flash_protect(FLAG_PROTECT_SET,
140 CFG_ENV_ADDR_REDUND,
141 CFG_ENV_ADDR_REDUND + CFG_ENV_SECT_SIZE - 1,
c609719b
WD
142 &flash_info[0]);
143#endif
144
145 if (size_b1) {
146 memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
147 memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
148 BR_MS_GPCM | BR_V;
149
73a8b27c
WD
150 debug ("## BR1: 0x%08x OR1: 0x%08x\n",
151 memctl->memc_br1, memctl->memc_or1);
152
c609719b
WD
153 /* Re-do sizing to get full correct info */
154 size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
155 &flash_info[1]);
156
157#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
158 /* monitor protection ON by default */
159 flash_protect(FLAG_PROTECT_SET,
160 CFG_MONITOR_BASE,
3b57fe0a 161 CFG_MONITOR_BASE+monitor_flash_len-1,
c609719b
WD
162 &flash_info[1]);
163#endif
164
165#ifdef CFG_ENV_IS_IN_FLASH
166 /* ENV protection ON by default */
167 flash_protect(FLAG_PROTECT_SET,
168 CFG_ENV_ADDR,
169 CFG_ENV_ADDR+CFG_ENV_SIZE-1,
170 &flash_info[1]);
171#endif
172 } else {
173 memctl->memc_br1 = 0; /* invalidate bank */
174
175 flash_info[1].flash_id = FLASH_UNKNOWN;
176 flash_info[1].sector_count = -1;
73a8b27c
WD
177 flash_info[1].size = 0;
178
179 debug ("## DISABLE BR1: 0x%08x OR1: 0x%08x\n",
180 memctl->memc_br1, memctl->memc_or1);
c609719b
WD
181 }
182
73a8b27c
WD
183 debug ("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
184
c609719b
WD
185 flash_info[0].size = size_b0;
186 flash_info[1].size = size_b1;
187
188 return (size_b0 + size_b1);
189}
190
191/*-----------------------------------------------------------------------
192 */
193void flash_print_info (flash_info_t *info)
194{
195 int i;
196
197 if (info->flash_id == FLASH_UNKNOWN) {
198 printf ("missing or unknown FLASH type\n");
199 return;
200 }
201
202 switch (info->flash_id & FLASH_VENDMASK) {
203 case FLASH_MAN_AMD: printf ("AMD "); break;
204 case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
205 default: printf ("Unknown Vendor "); break;
206 }
207
208 switch (info->flash_id & FLASH_TYPEMASK) {
71f95118
WD
209#ifdef CONFIG_TQM8xxM /* mirror bit flash */
210 case FLASH_AMLV128U: printf ("AM29LV128ML (128Mbit, uniform sector size)\n");
211 break;
f12e568c
WD
212 case FLASH_AMLV320U: printf ("AM29LV320ML (32Mbit, uniform sector size)\n");
213 break;
214 case FLASH_AMLV640U: printf ("AM29LV640ML (64Mbit, uniform sector size)\n");
215 break;
71f95118 216# else /* ! TQM8xxM */
c609719b
WD
217 case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
218 break;
219 case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
220 break;
221 case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
222 break;
223 case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
224 break;
c609719b
WD
225 case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
226 break;
227 case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
228 break;
71f95118 229#endif /* TQM8xxM */
f12e568c
WD
230 case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
231 break;
232 case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
233 break;
c609719b
WD
234 default: printf ("Unknown Chip Type\n");
235 break;
236 }
237
238 printf (" Size: %ld MB in %d Sectors\n",
239 info->size >> 20, info->sector_count);
240
241 printf (" Sector Start Addresses:");
242 for (i=0; i<info->sector_count; ++i) {
243 if ((i % 5) == 0)
244 printf ("\n ");
245 printf (" %08lX%s",
246 info->start[i],
247 info->protect[i] ? " (RO)" : " "
248 );
249 }
250 printf ("\n");
251 return;
252}
253
254/*-----------------------------------------------------------------------
255 */
256
257
258/*-----------------------------------------------------------------------
259 */
260
261/*
262 * The following code cannot be run from FLASH!
263 */
264
265static ulong flash_get_size (vu_long *addr, flash_info_t *info)
266{
267 short i;
268 ulong value;
269 ulong base = (ulong)addr;
270
271 /* Write auto select command: read Manufacturer ID */
272 addr[0x0555] = 0x00AA00AA;
273 addr[0x02AA] = 0x00550055;
274 addr[0x0555] = 0x00900090;
275
276 value = addr[0];
277
73a8b27c
WD
278 debug ("Manuf. ID @ 0x%08lx: 0x%08lx\n", (ulong)addr, value);
279
c609719b
WD
280 switch (value) {
281 case AMD_MANUFACT:
282 info->flash_id = FLASH_MAN_AMD;
283 break;
284 case FUJ_MANUFACT:
285 info->flash_id = FLASH_MAN_FUJ;
286 break;
287 default:
288 info->flash_id = FLASH_UNKNOWN;
289 info->sector_count = 0;
290 info->size = 0;
291 return (0); /* no or unknown flash */
292 }
293
294 value = addr[1]; /* device ID */
295
73a8b27c
WD
296 debug ("Device ID @ 0x%08lx: 0x%08lx\n", (ulong)(&addr[1]), value);
297
c609719b 298 switch (value) {
71f95118
WD
299#ifdef CONFIG_TQM8xxM /* mirror bit flash */
300 case AMD_ID_MIRROR:
f12e568c
WD
301 /* Special case for AMLV320MH/L */
302 if ((addr[14] & 0x00ff00ff) == 0x001d001d &&
303 (addr[15] & 0x00ff00ff) == 0x00000000) {
304 info->flash_id += FLASH_AMLV320U;
305 info->sector_count = 64;
306 info->size = 0x00800000; /* => 8 MB */
307 break;
308 }
71f95118
WD
309 switch(addr[14]) {
310 case AMD_ID_LV128U_2:
311 if (addr[15] != AMD_ID_LV128U_3) {
312 info->flash_id = FLASH_UNKNOWN;
313 }
314 else {
315 info->flash_id += FLASH_AMLV128U;
316 info->sector_count = 256;
317 info->size = 0x02000000;
318 }
319 break; /* => 32 MB */
f12e568c
WD
320 case AMD_ID_LV640U_2:
321 if (addr[15] != AMD_ID_LV640U_3) {
322 info->flash_id = FLASH_UNKNOWN;
323 }
324 else {
325 info->flash_id += FLASH_AMLV640U;
326 info->sector_count = 128;
327 info->size = 0x01000000;
328 }
329 break; /* => 16 MB */
71f95118
WD
330 default:
331 info->flash_id = FLASH_UNKNOWN;
332 break;
333 }
334 break;
335# else /* ! TQM8xxM */
c609719b
WD
336 case AMD_ID_LV400T:
337 info->flash_id += FLASH_AM400T;
338 info->sector_count = 11;
339 info->size = 0x00100000;
340 break; /* => 1 MB */
341
342 case AMD_ID_LV400B:
343 info->flash_id += FLASH_AM400B;
344 info->sector_count = 11;
345 info->size = 0x00100000;
346 break; /* => 1 MB */
347
348 case AMD_ID_LV800T:
349 info->flash_id += FLASH_AM800T;
350 info->sector_count = 19;
351 info->size = 0x00200000;
352 break; /* => 2 MB */
353
354 case AMD_ID_LV800B:
355 info->flash_id += FLASH_AM800B;
356 info->sector_count = 19;
357 info->size = 0x00200000;
358 break; /* => 2 MB */
359
c609719b
WD
360 case AMD_ID_LV320T:
361 info->flash_id += FLASH_AM320T;
362 info->sector_count = 71;
363 info->size = 0x00800000;
364 break; /* => 8 MB */
365
366 case AMD_ID_LV320B:
367 info->flash_id += FLASH_AM320B;
368 info->sector_count = 71;
369 info->size = 0x00800000;
370 break; /* => 8 MB */
71f95118 371#endif /* TQM8xxM */
f12e568c
WD
372
373 case AMD_ID_LV160T:
374 info->flash_id += FLASH_AM160T;
375 info->sector_count = 35;
376 info->size = 0x00400000;
377 break; /* => 4 MB */
378
379 case AMD_ID_LV160B:
380 info->flash_id += FLASH_AM160B;
381 info->sector_count = 35;
382 info->size = 0x00400000;
383 break; /* => 4 MB */
384
c609719b
WD
385 default:
386 info->flash_id = FLASH_UNKNOWN;
387 return (0); /* => no or unknown flash */
388 }
389
390 /* set up sector start address table */
391 switch (value) {
71f95118
WD
392#ifdef CONFIG_TQM8xxM /* mirror bit flash */
393 case AMD_ID_MIRROR:
394 switch (info->flash_id & FLASH_TYPEMASK) {
395 /* only known types here - no default */
396 case FLASH_AMLV128U:
f12e568c
WD
397 case FLASH_AMLV640U:
398 case FLASH_AMLV320U:
71f95118
WD
399 for (i = 0; i < info->sector_count; i++) {
400 info->start[i] = base;
401 base += 0x20000;
402 }
403 break;
404 }
405 break;
406# else /* ! TQM8xxM */
c609719b
WD
407 case AMD_ID_LV400B:
408 case AMD_ID_LV800B:
c609719b
WD
409 /* set sector offsets for bottom boot block type */
410 info->start[0] = base + 0x00000000;
411 info->start[1] = base + 0x00008000;
412 info->start[2] = base + 0x0000C000;
413 info->start[3] = base + 0x00010000;
414 for (i = 4; i < info->sector_count; i++) {
415 info->start[i] = base + (i * 0x00020000) - 0x00060000;
416 }
417 break;
418 case AMD_ID_LV400T:
419 case AMD_ID_LV800T:
c609719b
WD
420 /* set sector offsets for top boot block type */
421 i = info->sector_count - 1;
422 info->start[i--] = base + info->size - 0x00008000;
423 info->start[i--] = base + info->size - 0x0000C000;
424 info->start[i--] = base + info->size - 0x00010000;
425 for (; i >= 0; i--) {
426 info->start[i] = base + i * 0x00020000;
427 }
428 break;
429 case AMD_ID_LV320B:
430 for (i = 0; i < info->sector_count; i++) {
431 info->start[i] = base;
432 /*
433 * The first 8 sectors are 8 kB,
434 * all the other ones are 64 kB
435 */
436 base += (i < 8)
437 ? 2 * ( 8 << 10)
438 : 2 * (64 << 10);
439 }
440 break;
441 case AMD_ID_LV320T:
442 for (i = 0; i < info->sector_count; i++) {
443 info->start[i] = base;
444 /*
445 * The last 8 sectors are 8 kB,
446 * all the other ones are 64 kB
447 */
448 base += (i < (info->sector_count - 8))
449 ? 2 * (64 << 10)
450 : 2 * ( 8 << 10);
451 }
452 break;
71f95118 453#endif /* TQM8xxM */
f12e568c
WD
454 case AMD_ID_LV160B:
455 /* set sector offsets for bottom boot block type */
456 info->start[0] = base + 0x00000000;
457 info->start[1] = base + 0x00008000;
458 info->start[2] = base + 0x0000C000;
459 info->start[3] = base + 0x00010000;
460 for (i = 4; i < info->sector_count; i++) {
461 info->start[i] = base + (i * 0x00020000) - 0x00060000;
462 }
463 break;
464 case AMD_ID_LV160T:
465 /* set sector offsets for top boot block type */
466 i = info->sector_count - 1;
467 info->start[i--] = base + info->size - 0x00008000;
468 info->start[i--] = base + info->size - 0x0000C000;
469 info->start[i--] = base + info->size - 0x00010000;
470 for (; i >= 0; i--) {
471 info->start[i] = base + i * 0x00020000;
472 }
473 break;
c609719b
WD
474 default:
475 return (0);
476 break;
477 }
478
479 /* check for protected sectors */
480 for (i = 0; i < info->sector_count; i++) {
481 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
482 /* D0 = 1 if protected */
483 addr = (volatile unsigned long *)(info->start[i]);
484 info->protect[i] = addr[2] & 1;
485 }
486
487 /*
488 * Prevent writes to uninitialized FLASH.
489 */
490 if (info->flash_id != FLASH_UNKNOWN) {
491 addr = (volatile unsigned long *)info->start[0];
492
493 *addr = 0x00F000F0; /* reset bank */
494 }
495
496 return (info->size);
497}
498
499
500/*-----------------------------------------------------------------------
501 */
502
503int flash_erase (flash_info_t *info, int s_first, int s_last)
504{
505 vu_long *addr = (vu_long*)(info->start[0]);
506 int flag, prot, sect, l_sect;
507 ulong start, now, last;
508
73a8b27c
WD
509 debug ("flash_erase: first: %d last: %d\n", s_first, s_last);
510
c609719b
WD
511 if ((s_first < 0) || (s_first > s_last)) {
512 if (info->flash_id == FLASH_UNKNOWN) {
513 printf ("- missing\n");
514 } else {
515 printf ("- no sectors to erase\n");
516 }
517 return 1;
518 }
519
520 if ((info->flash_id == FLASH_UNKNOWN) ||
521 (info->flash_id > FLASH_AMD_COMP)) {
522 printf ("Can't erase unknown flash type %08lx - aborted\n",
523 info->flash_id);
524 return 1;
525 }
526
527 prot = 0;
528 for (sect=s_first; sect<=s_last; ++sect) {
529 if (info->protect[sect]) {
530 prot++;
531 }
532 }
533
534 if (prot) {
535 printf ("- Warning: %d protected sectors will not be erased!\n",
536 prot);
537 } else {
538 printf ("\n");
539 }
540
541 l_sect = -1;
542
543 /* Disable interrupts which might cause a timeout here */
544 flag = disable_interrupts();
545
546 addr[0x0555] = 0x00AA00AA;
547 addr[0x02AA] = 0x00550055;
548 addr[0x0555] = 0x00800080;
549 addr[0x0555] = 0x00AA00AA;
550 addr[0x02AA] = 0x00550055;
551
552 /* Start erase on unprotected sectors */
553 for (sect = s_first; sect<=s_last; sect++) {
554 if (info->protect[sect] == 0) { /* not protected */
555 addr = (vu_long*)(info->start[sect]);
556 addr[0] = 0x00300030;
557 l_sect = sect;
558 }
559 }
560
561 /* re-enable interrupts if necessary */
562 if (flag)
563 enable_interrupts();
564
565 /* wait at least 80us - let's wait 1 ms */
566 udelay (1000);
567
568 /*
569 * We wait for the last triggered sector
570 */
571 if (l_sect < 0)
572 goto DONE;
573
574 start = get_timer (0);
575 last = start;
576 addr = (vu_long*)(info->start[l_sect]);
577 while ((addr[0] & 0x00800080) != 0x00800080) {
578 if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
579 printf ("Timeout\n");
580 return 1;
581 }
582 /* show that we're waiting */
583 if ((now - last) > 1000) { /* every second */
584 putc ('.');
585 last = now;
586 }
587 }
588
589DONE:
590 /* reset to read mode */
591 addr = (volatile unsigned long *)info->start[0];
592 addr[0] = 0x00F000F0; /* reset bank */
593
594 printf (" done\n");
595 return 0;
596}
597
598/*-----------------------------------------------------------------------
599 * Copy memory to flash, returns:
600 * 0 - OK
601 * 1 - write timeout
602 * 2 - Flash not erased
603 */
604
605int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
606{
607 ulong cp, wp, data;
608 int i, l, rc;
609
610 wp = (addr & ~3); /* get lower word aligned address */
611
612 /*
613 * handle unaligned start bytes
614 */
615 if ((l = addr - wp) != 0) {
616 data = 0;
617 for (i=0, cp=wp; i<l; ++i, ++cp) {
618 data = (data << 8) | (*(uchar *)cp);
619 }
620 for (; i<4 && cnt>0; ++i) {
621 data = (data << 8) | *src++;
622 --cnt;
623 ++cp;
624 }
625 for (; cnt==0 && i<4; ++i, ++cp) {
626 data = (data << 8) | (*(uchar *)cp);
627 }
628
629 if ((rc = write_word(info, wp, data)) != 0) {
630 return (rc);
631 }
632 wp += 4;
633 }
634
635 /*
636 * handle word aligned part
637 */
638 while (cnt >= 4) {
639 data = 0;
640 for (i=0; i<4; ++i) {
641 data = (data << 8) | *src++;
642 }
643 if ((rc = write_word(info, wp, data)) != 0) {
644 return (rc);
645 }
646 wp += 4;
647 cnt -= 4;
648 }
649
650 if (cnt == 0) {
651 return (0);
652 }
653
654 /*
655 * handle unaligned tail bytes
656 */
657 data = 0;
658 for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
659 data = (data << 8) | *src++;
660 --cnt;
661 }
662 for (; i<4; ++i, ++cp) {
663 data = (data << 8) | (*(uchar *)cp);
664 }
665
666 return (write_word(info, wp, data));
667}
668
669/*-----------------------------------------------------------------------
670 * Write a word to Flash, returns:
671 * 0 - OK
672 * 1 - write timeout
673 * 2 - Flash not erased
674 */
675static int write_word (flash_info_t *info, ulong dest, ulong data)
676{
677 vu_long *addr = (vu_long*)(info->start[0]);
678 ulong start;
679 int flag;
680
681 /* Check if Flash is (sufficiently) erased */
682 if ((*((vu_long *)dest) & data) != data) {
683 return (2);
684 }
685 /* Disable interrupts which might cause a timeout here */
686 flag = disable_interrupts();
687
688 addr[0x0555] = 0x00AA00AA;
689 addr[0x02AA] = 0x00550055;
690 addr[0x0555] = 0x00A000A0;
691
692 *((vu_long *)dest) = data;
693
694 /* re-enable interrupts if necessary */
695 if (flag)
696 enable_interrupts();
697
698 /* data polling for D7 */
699 start = get_timer (0);
700 while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
701 if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
702 return (1);
703 }
704 }
705 return (0);
706}
707
708/*-----------------------------------------------------------------------
709 */