blob: a786ac9327d1d2d731dcc8f4db00fe1b53ec61bb [file] [log] [blame]
wdenkc0218802003-03-27 12:09:35 +00001/*
2 * (C) Copyright 2003
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenkc0218802003-03-27 12:09:35 +00006 */
7
8#include <common.h>
9#include <asm/inca-ip.h>
10
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020011flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenkc0218802003-03-27 12:09:35 +000012
13/* NOTE - CONFIG_FLASH_16BIT means the CPU interface is 16-bit, it
14 * has nothing to do with the flash chip being 8-bit or 16-bit.
15 */
16#ifdef CONFIG_FLASH_16BIT
17typedef unsigned short FLASH_PORT_WIDTH;
18typedef volatile unsigned short FLASH_PORT_WIDTHV;
19#define FLASH_ID_MASK 0xFFFF
20#else
21typedef unsigned long FLASH_PORT_WIDTH;
22typedef volatile unsigned long FLASH_PORT_WIDTHV;
23#define FLASH_ID_MASK 0xFFFFFFFF
24#endif
25
26#define FPW FLASH_PORT_WIDTH
27#define FPWV FLASH_PORT_WIDTHV
28
29#define ORMASK(size) ((-size) & OR_AM_MSK)
30
31#if 0
32#define FLASH_CYCLE1 0x0555
33#define FLASH_CYCLE2 0x02aa
34#else
35#define FLASH_CYCLE1 0x0554
36#define FLASH_CYCLE2 0x02ab
37#endif
38
39/*-----------------------------------------------------------------------
40 * Functions
41 */
42static ulong flash_get_size(FPWV *addr, flash_info_t *info);
43static void flash_reset(flash_info_t *info);
44static int write_word_intel(flash_info_t *info, FPWV *dest, FPW data);
45static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
46static void flash_get_offsets(ulong base, flash_info_t *info);
47static flash_info_t *flash_get_info(ulong base);
48
49/*-----------------------------------------------------------------------
50 * flash_init()
51 *
52 * sets up flash_info and returns size of FLASH (bytes)
53 */
54unsigned long flash_init (void)
55{
56 unsigned long size = 0;
57 int i;
58
59 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020060 for (i=0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenkc0218802003-03-27 12:09:35 +000061 ulong flashbase = (i == 0) ? PHYS_FLASH_1 : PHYS_FLASH_2;
62 ulong * buscon = (ulong *)
63 ((i == 0) ? INCA_IP_EBU_EBU_BUSCON0 : INCA_IP_EBU_EBU_BUSCON2);
64
65 /* Disable write protection */
66 *buscon &= ~INCA_IP_EBU_EBU_BUSCON1_WRDIS;
67
68#if 1
69 memset(&flash_info[i], 0, sizeof(flash_info_t));
70#endif
71
wdenk8bde7f72003-06-27 21:31:46 +000072 flash_info[i].size =
wdenkc0218802003-03-27 12:09:35 +000073 flash_get_size((FPW *)flashbase, &flash_info[i]);
74
75 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
76 printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx\n",
77 i, flash_info[i].size);
78 }
wdenk8bde7f72003-06-27 21:31:46 +000079
wdenkc0218802003-03-27 12:09:35 +000080 size += flash_info[i].size;
81 }
82
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020083#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
wdenkc0218802003-03-27 12:09:35 +000084 /* monitor protection ON by default */
85 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020086 CONFIG_SYS_MONITOR_BASE,
87 CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
88 flash_get_info(CONFIG_SYS_MONITOR_BASE));
wdenkc0218802003-03-27 12:09:35 +000089#endif
90
Jean-Christophe PLAGNIOL-VILLARD5a1aceb2008-09-10 22:48:04 +020091#ifdef CONFIG_ENV_IS_IN_FLASH
wdenkc0218802003-03-27 12:09:35 +000092 /* ENV protection ON by default */
93 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020094 CONFIG_ENV_ADDR,
95 CONFIG_ENV_ADDR+CONFIG_ENV_SIZE-1,
96 flash_get_info(CONFIG_ENV_ADDR));
wdenkc0218802003-03-27 12:09:35 +000097#endif
98
99
100 return size;
101}
102
103/*-----------------------------------------------------------------------
104 */
105static void flash_reset(flash_info_t *info)
106{
107 FPWV *base = (FPWV *)(info->start[0]);
108
109 /* Put FLASH back in read mode */
110 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
111 *base = (FPW)0x00FF00FF; /* Intel Read Mode */
112 else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
113 *base = (FPW)0x00F000F0; /* AMD Read Mode */
114}
115
116/*-----------------------------------------------------------------------
117 */
118static void flash_get_offsets (ulong base, flash_info_t *info)
119{
120 int i;
121
122 /* set up sector start address table */
123 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL
124 && (info->flash_id & FLASH_BTYPE)) {
125 int bootsect_size; /* number of bytes/boot sector */
126 int sect_size; /* number of bytes/regular sector */
127
128 bootsect_size = 0x00002000 * (sizeof(FPW)/2);
129 sect_size = 0x00010000 * (sizeof(FPW)/2);
130
131 /* set sector offsets for bottom boot block type */
132 for (i = 0; i < 8; ++i) {
133 info->start[i] = base + (i * bootsect_size);
134 }
135 for (i = 8; i < info->sector_count; i++) {
136 info->start[i] = base + ((i - 7) * sect_size);
137 }
138 }
139 else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD
140 && (info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U) {
141
142 int sect_size; /* number of bytes/sector */
143
144 sect_size = 0x00010000 * (sizeof(FPW)/2);
145
146 /* set up sector start address table (uniform sector type) */
147 for( i = 0; i < info->sector_count; i++ )
148 info->start[i] = base + (i * sect_size);
149 }
150}
151
152/*-----------------------------------------------------------------------
153 */
154
155static flash_info_t *flash_get_info(ulong base)
156{
157 int i;
158 flash_info_t * info;
wdenk8bde7f72003-06-27 21:31:46 +0000159
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200160 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i ++) {
wdenkc0218802003-03-27 12:09:35 +0000161 info = & flash_info[i];
162 if (info->start[0] <= base && base < info->start[0] + info->size)
163 break;
164 }
wdenk8bde7f72003-06-27 21:31:46 +0000165
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200166 return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
wdenkc0218802003-03-27 12:09:35 +0000167}
168
169/*-----------------------------------------------------------------------
170 */
171
172void flash_print_info (flash_info_t *info)
173{
174 int i;
175 uchar *boottype;
176 uchar *bootletter;
Wolfgang Denkf013dac2005-12-04 00:40:34 +0100177 char *fmt;
wdenkc0218802003-03-27 12:09:35 +0000178 uchar botbootletter[] = "B";
179 uchar topbootletter[] = "T";
180 uchar botboottype[] = "bottom boot sector";
181 uchar topboottype[] = "top boot sector";
182
183 if (info->flash_id == FLASH_UNKNOWN) {
184 printf ("missing or unknown FLASH type\n");
185 return;
186 }
187
188 switch (info->flash_id & FLASH_VENDMASK) {
189 case FLASH_MAN_AMD: printf ("AMD "); break;
190 case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
191 case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
192 case FLASH_MAN_SST: printf ("SST "); break;
193 case FLASH_MAN_STM: printf ("STM "); break;
194 case FLASH_MAN_INTEL: printf ("INTEL "); break;
195 default: printf ("Unknown Vendor "); break;
196 }
197
198 /* check for top or bottom boot, if it applies */
199 if (info->flash_id & FLASH_BTYPE) {
200 boottype = botboottype;
201 bootletter = botbootletter;
202 }
203 else {
204 boottype = topboottype;
205 bootletter = topbootletter;
206 }
207
208 switch (info->flash_id & FLASH_TYPEMASK) {
209 case FLASH_AM640U:
210 fmt = "29LV641D (64 Mbit, uniform sectors)\n";
211 break;
wdenk8bde7f72003-06-27 21:31:46 +0000212 case FLASH_28F800C3B:
213 case FLASH_28F800C3T:
wdenkc0218802003-03-27 12:09:35 +0000214 fmt = "28F800C3%s (8 Mbit, %s)\n";
215 break;
216 case FLASH_INTEL800B:
217 case FLASH_INTEL800T:
218 fmt = "28F800B3%s (8 Mbit, %s)\n";
219 break;
wdenk8bde7f72003-06-27 21:31:46 +0000220 case FLASH_28F160C3B:
221 case FLASH_28F160C3T:
wdenkc0218802003-03-27 12:09:35 +0000222 fmt = "28F160C3%s (16 Mbit, %s)\n";
223 break;
224 case FLASH_INTEL160B:
225 case FLASH_INTEL160T:
226 fmt = "28F160B3%s (16 Mbit, %s)\n";
227 break;
wdenk8bde7f72003-06-27 21:31:46 +0000228 case FLASH_28F320C3B:
229 case FLASH_28F320C3T:
wdenkc0218802003-03-27 12:09:35 +0000230 fmt = "28F320C3%s (32 Mbit, %s)\n";
231 break;
232 case FLASH_INTEL320B:
233 case FLASH_INTEL320T:
234 fmt = "28F320B3%s (32 Mbit, %s)\n";
235 break;
wdenk8bde7f72003-06-27 21:31:46 +0000236 case FLASH_28F640C3B:
237 case FLASH_28F640C3T:
wdenkc0218802003-03-27 12:09:35 +0000238 fmt = "28F640C3%s (64 Mbit, %s)\n";
239 break;
240 case FLASH_INTEL640B:
241 case FLASH_INTEL640T:
242 fmt = "28F640B3%s (64 Mbit, %s)\n";
243 break;
244 default:
245 fmt = "Unknown Chip Type\n";
246 break;
247 }
248
249 printf (fmt, bootletter, boottype);
250
251 printf (" Size: %ld MB in %d Sectors\n",
252 info->size >> 20,
253 info->sector_count);
254
255 printf (" Sector Start Addresses:");
256
257 for (i=0; i<info->sector_count; ++i) {
258 if ((i % 5) == 0) {
259 printf ("\n ");
260 }
261
262 printf (" %08lX%s", info->start[i],
263 info->protect[i] ? " (RO)" : " ");
264 }
265
266 printf ("\n");
267}
268
269/*-----------------------------------------------------------------------
270 */
271
272/*
273 * The following code cannot be run from FLASH!
274 */
275
276ulong flash_get_size (FPWV *addr, flash_info_t *info)
277{
278 /* Write auto select command: read Manufacturer ID */
279
280 /* Write auto select command sequence and test FLASH answer */
281 addr[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */
282 addr[FLASH_CYCLE2] = (FPW)0x00550055; /* for AMD, Intel ignores this */
283 addr[FLASH_CYCLE1] = (FPW)0x00900090; /* selects Intel or AMD */
284
285 /* The manufacturer codes are only 1 byte, so just use 1 byte.
286 * This works for any bus width and any FLASH device width.
287 */
288 switch (addr[1] & 0xff) {
289
290 case (uchar)AMD_MANUFACT:
291 info->flash_id = FLASH_MAN_AMD;
292 break;
293
294 case (uchar)INTEL_MANUFACT:
295 info->flash_id = FLASH_MAN_INTEL;
296 break;
297
298 default:
299 info->flash_id = FLASH_UNKNOWN;
300 info->sector_count = 0;
301 info->size = 0;
302 break;
303 }
304
305 /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
306 if (info->flash_id != FLASH_UNKNOWN) switch (addr[0]) {
307
308 case (FPW)AMD_ID_LV640U: /* 29LV640 and 29LV641 have same ID */
309 info->flash_id += FLASH_AM640U;
310 info->sector_count = 128;
311 info->size = 0x00800000 * (sizeof(FPW)/2);
312 break; /* => 8 or 16 MB */
313
314 case (FPW)INTEL_ID_28F800C3B:
315 info->flash_id += FLASH_28F800C3B;
316 info->sector_count = 23;
317 info->size = 0x00100000 * (sizeof(FPW)/2);
318 break; /* => 1 or 2 MB */
319
320 case (FPW)INTEL_ID_28F800B3B:
321 info->flash_id += FLASH_INTEL800B;
322 info->sector_count = 23;
323 info->size = 0x00100000 * (sizeof(FPW)/2);
324 break; /* => 1 or 2 MB */
325
326 case (FPW)INTEL_ID_28F160C3B:
327 info->flash_id += FLASH_28F160C3B;
328 info->sector_count = 39;
329 info->size = 0x00200000 * (sizeof(FPW)/2);
330 break; /* => 2 or 4 MB */
331
332 case (FPW)INTEL_ID_28F160B3B:
333 info->flash_id += FLASH_INTEL160B;
334 info->sector_count = 39;
335 info->size = 0x00200000 * (sizeof(FPW)/2);
336 break; /* => 2 or 4 MB */
337
338 case (FPW)INTEL_ID_28F320C3B:
339 info->flash_id += FLASH_28F320C3B;
340 info->sector_count = 71;
341 info->size = 0x00400000 * (sizeof(FPW)/2);
342 break; /* => 4 or 8 MB */
343
344 case (FPW)INTEL_ID_28F320B3B:
345 info->flash_id += FLASH_INTEL320B;
346 info->sector_count = 71;
347 info->size = 0x00400000 * (sizeof(FPW)/2);
348 break; /* => 4 or 8 MB */
349
350 case (FPW)INTEL_ID_28F640C3B:
351 info->flash_id += FLASH_28F640C3B;
352 info->sector_count = 135;
353 info->size = 0x00800000 * (sizeof(FPW)/2);
354 break; /* => 8 or 16 MB */
355
356 case (FPW)INTEL_ID_28F640B3B:
357 info->flash_id += FLASH_INTEL640B;
358 info->sector_count = 135;
359 info->size = 0x00800000 * (sizeof(FPW)/2);
360 break; /* => 8 or 16 MB */
361
362 default:
363 info->flash_id = FLASH_UNKNOWN;
364 info->sector_count = 0;
365 info->size = 0;
366 return (0); /* => no or unknown flash */
367 }
368
369 flash_get_offsets((ulong)addr, info);
370
371 /* Put FLASH back in read mode */
372 flash_reset(info);
373
374 return (info->size);
375}
376
377/*-----------------------------------------------------------------------
378 */
379
380int flash_erase (flash_info_t *info, int s_first, int s_last)
381{
382 FPWV *addr;
383 int flag, prot, sect;
384 int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
385 ulong start, now, last;
386 int rcode = 0;
387
388 if ((s_first < 0) || (s_first > s_last)) {
389 if (info->flash_id == FLASH_UNKNOWN) {
390 printf ("- missing\n");
391 } else {
392 printf ("- no sectors to erase\n");
393 }
394 return 1;
395 }
396
397 switch (info->flash_id & FLASH_TYPEMASK) {
398 case FLASH_INTEL800B:
399 case FLASH_INTEL160B:
400 case FLASH_INTEL320B:
401 case FLASH_INTEL640B:
402 case FLASH_28F800C3B:
403 case FLASH_28F160C3B:
404 case FLASH_28F320C3B:
405 case FLASH_28F640C3B:
406 case FLASH_AM640U:
407 break;
408 case FLASH_UNKNOWN:
409 default:
410 printf ("Can't erase unknown flash type %08lx - aborted\n",
411 info->flash_id);
412 return 1;
413 }
414
415 prot = 0;
416 for (sect=s_first; sect<=s_last; ++sect) {
417 if (info->protect[sect]) {
418 prot++;
419 }
420 }
421
422 if (prot) {
423 printf ("- Warning: %d protected sectors will not be erased!\n",
424 prot);
425 } else {
426 printf ("\n");
427 }
428
429 last = get_timer(0);
430
431 /* Start erase on unprotected sectors */
432 for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
433
434 if (info->protect[sect] != 0) /* protected, skip it */
435 continue;
436
437 /* Disable interrupts which might cause a timeout here */
438 flag = disable_interrupts();
439
440 addr = (FPWV *)(info->start[sect]);
441 if (intel) {
442 *addr = (FPW)0x00500050; /* clear status register */
443 *addr = (FPW)0x00200020; /* erase setup */
444 *addr = (FPW)0x00D000D0; /* erase confirm */
445 }
446 else {
447 /* must be AMD style if not Intel */
448 FPWV *base; /* first address in bank */
449
450 base = (FPWV *)(info->start[0]);
451 base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
452 base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
453 base[FLASH_CYCLE1] = (FPW)0x00800080; /* erase mode */
454 base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
455 base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
456 *addr = (FPW)0x00300030; /* erase sector */
457 }
458
459 /* re-enable interrupts if necessary */
460 if (flag)
461 enable_interrupts();
462
463 start = get_timer(0);
464
465 /* wait at least 50us for AMD, 80us for Intel.
466 * Let's wait 1 ms.
467 */
468 udelay (1000);
469
470 while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200471 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenkc0218802003-03-27 12:09:35 +0000472 printf ("Timeout\n");
473
474 if (intel) {
475 /* suspend erase */
476 *addr = (FPW)0x00B000B0;
477 }
478
479 flash_reset(info); /* reset to read mode */
480 rcode = 1; /* failed */
481 break;
482 }
483
484 /* show that we're waiting */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200485 if ((get_timer(last)) > CONFIG_SYS_HZ) {/* every second */
wdenkc0218802003-03-27 12:09:35 +0000486 putc ('.');
487 last = get_timer(0);
488 }
489 }
490
491 /* show that we're waiting */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200492 if ((get_timer(last)) > CONFIG_SYS_HZ) { /* every second */
wdenkc0218802003-03-27 12:09:35 +0000493 putc ('.');
494 last = get_timer(0);
495 }
496
497 flash_reset(info); /* reset to read mode */
498 }
499
500 printf (" done\n");
501 return rcode;
502}
503
504/*-----------------------------------------------------------------------
505 * Copy memory to flash, returns:
506 * 0 - OK
507 * 1 - write timeout
508 * 2 - Flash not erased
509 */
510int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
511{
512 FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
513 int bytes; /* number of bytes to program in current word */
514 int left; /* number of bytes left to program */
515 int i, res;
516
517 for (left = cnt, res = 0;
518 left > 0 && res == 0;
519 addr += sizeof(data), left -= sizeof(data) - bytes) {
520
wdenk8bde7f72003-06-27 21:31:46 +0000521 bytes = addr & (sizeof(data) - 1);
522 addr &= ~(sizeof(data) - 1);
wdenkc0218802003-03-27 12:09:35 +0000523
524 /* combine source and destination data so can program
525 * an entire word of 16 or 32 bits
526 */
wdenk8bde7f72003-06-27 21:31:46 +0000527 for (i = 0; i < sizeof(data); i++) {
528 data <<= 8;
529 if (i < bytes || i - bytes >= left )
wdenkc0218802003-03-27 12:09:35 +0000530 data += *((uchar *)addr + i);
531 else
532 data += *src++;
533 }
534
535 /* write one word to the flash */
536 switch (info->flash_id & FLASH_VENDMASK) {
537 case FLASH_MAN_AMD:
538 res = write_word_amd(info, (FPWV *)addr, data);
539 break;
540 case FLASH_MAN_INTEL:
541 res = write_word_intel(info, (FPWV *)addr, data);
542 break;
543 default:
544 /* unknown flash type, error! */
545 printf ("missing or unknown FLASH type\n");
546 res = 1; /* not really a timeout, but gives error */
547 break;
548 }
549 }
550
551 return (res);
552}
553
554/*-----------------------------------------------------------------------
555 * Write a word to Flash for AMD FLASH
556 * A word is 16 or 32 bits, whichever the bus width of the flash bank
557 * (not an individual chip) is.
558 *
559 * returns:
560 * 0 - OK
561 * 1 - write timeout
562 * 2 - Flash not erased
563 */
564static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
565{
566 ulong start;
567 int flag;
568 int res = 0; /* result, assume success */
569 FPWV *base; /* first address in flash bank */
570
571 /* Check if Flash is (sufficiently) erased */
572 if ((*dest & data) != data) {
573 return (2);
574 }
575
576
577 base = (FPWV *)(info->start[0]);
578
579 /* Disable interrupts which might cause a timeout here */
580 flag = disable_interrupts();
581
582 base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
583 base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
584 base[FLASH_CYCLE1] = (FPW)0x00A000A0; /* selects program mode */
585
586 *dest = data; /* start programming the data */
587
588 /* re-enable interrupts if necessary */
589 if (flag)
590 enable_interrupts();
591
592 start = get_timer (0);
593
594 /* data polling for D7 */
595 while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200596 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenkc0218802003-03-27 12:09:35 +0000597 *dest = (FPW)0x00F000F0; /* reset bank */
598 res = 1;
599 }
600 }
601
602 return (res);
603}
604
605/*-----------------------------------------------------------------------
606 * Write a word to Flash for Intel FLASH
607 * A word is 16 or 32 bits, whichever the bus width of the flash bank
608 * (not an individual chip) is.
609 *
610 * returns:
611 * 0 - OK
612 * 1 - write timeout
613 * 2 - Flash not erased
614 */
615static int write_word_intel (flash_info_t *info, FPWV *dest, FPW data)
616{
617 ulong start;
618 int flag;
619 int res = 0; /* result, assume success */
620
621 /* Check if Flash is (sufficiently) erased */
622 if ((*dest & data) != data) {
623 return (2);
624 }
625
626 /* Disable interrupts which might cause a timeout here */
627 flag = disable_interrupts();
628
629 *dest = (FPW)0x00500050; /* clear status register */
630 *dest = (FPW)0x00FF00FF; /* make sure in read mode */
631 *dest = (FPW)0x00400040; /* program setup */
632
633 *dest = data; /* start programming the data */
634
635 /* re-enable interrupts if necessary */
636 if (flag)
637 enable_interrupts();
638
639 start = get_timer (0);
640
641 while (res == 0 && (*dest & (FPW)0x00800080) != (FPW)0x00800080) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200642 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenkc0218802003-03-27 12:09:35 +0000643 *dest = (FPW)0x00B000B0; /* Suspend program */
644 res = 1;
645 }
646 }
647
648 if (res == 0 && (*dest & (FPW)0x00100010))
649 res = 1; /* write failed, time out error is close enough */
650
651 *dest = (FPW)0x00500050; /* clear status register */
652 *dest = (FPW)0x00FF00FF; /* make sure in read mode */
653
654 return (res);
655}