blob: 5a9c510c49cc90bd002bf6b64607ac56eaaa1fe2 [file] [log] [blame]
wdenk541a76d2003-05-03 15:50:43 +00001/*
2 * (C) Copyright 2003
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenk541a76d2003-05-03 15:50:43 +00006 */
7
8#include <common.h>
9
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020010flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenk541a76d2003-05-03 15:50:43 +000011
12/* NOTE - CONFIG_FLASH_16BIT means the CPU interface is 16-bit, it
13 * has nothing to do with the flash chip being 8-bit or 16-bit.
14 */
15#ifdef CONFIG_FLASH_16BIT
16typedef unsigned short FLASH_PORT_WIDTH;
17typedef volatile unsigned short FLASH_PORT_WIDTHV;
18#define FLASH_ID_MASK 0xFFFF
19#else
20typedef unsigned long FLASH_PORT_WIDTH;
21typedef volatile unsigned long FLASH_PORT_WIDTHV;
22#define FLASH_ID_MASK 0xFFFFFFFF
23#endif
24
25#define FPW FLASH_PORT_WIDTH
26#define FPWV FLASH_PORT_WIDTHV
27
28#define ORMASK(size) ((-size) & OR_AM_MSK)
29
30#define FLASH_CYCLE1 0x0555
31#define FLASH_CYCLE2 0x02aa
32
33/*-----------------------------------------------------------------------
34 * Functions
35 */
36static ulong flash_get_size(FPWV *addr, flash_info_t *info);
37static void flash_reset(flash_info_t *info);
38static int write_word_intel(flash_info_t *info, FPWV *dest, FPW data);
39static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
40static void flash_get_offsets(ulong base, flash_info_t *info);
41static flash_info_t *flash_get_info(ulong base);
42
43/*-----------------------------------------------------------------------
44 * flash_init()
45 *
46 * sets up flash_info and returns size of FLASH (bytes)
47 */
48unsigned long flash_init (void)
49{
50 unsigned long size = 0;
51 int i;
52
53 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020054 for (i=0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenk541a76d2003-05-03 15:50:43 +000055#if 0
56 ulong flashbase = (i == 0) ? PHYS_FLASH_1 : PHYS_FLASH_2;
57#else
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020058 ulong flashbase = CONFIG_SYS_FLASH_BASE;
wdenk541a76d2003-05-03 15:50:43 +000059#endif
60
61 memset(&flash_info[i], 0, sizeof(flash_info_t));
62
wdenk57b2d802003-06-27 21:31:46 +000063 flash_info[i].size =
wdenk541a76d2003-05-03 15:50:43 +000064 flash_get_size((FPW *)flashbase, &flash_info[i]);
65
66 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
67 printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx\n",
68 i, flash_info[i].size);
69 }
wdenk57b2d802003-06-27 21:31:46 +000070
wdenk541a76d2003-05-03 15:50:43 +000071 size += flash_info[i].size;
72 }
73
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020074#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
wdenk541a76d2003-05-03 15:50:43 +000075 /* monitor protection ON by default */
76 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020077 CONFIG_SYS_MONITOR_BASE,
78 CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
79 flash_get_info(CONFIG_SYS_MONITOR_BASE));
wdenk541a76d2003-05-03 15:50:43 +000080#endif
81
Jean-Christophe PLAGNIOL-VILLARD53db4cd2008-09-10 22:48:04 +020082#ifdef CONFIG_ENV_IS_IN_FLASH
wdenk541a76d2003-05-03 15:50:43 +000083 /* ENV protection ON by default */
84 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020085 CONFIG_ENV_ADDR,
86 CONFIG_ENV_ADDR+CONFIG_ENV_SIZE-1,
87 flash_get_info(CONFIG_ENV_ADDR));
wdenk541a76d2003-05-03 15:50:43 +000088#endif
89
90
91 return size ? size : 1;
92}
93
94/*-----------------------------------------------------------------------
95 */
96static void flash_reset(flash_info_t *info)
97{
98 FPWV *base = (FPWV *)(info->start[0]);
99
100 /* Put FLASH back in read mode */
101 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
102 *base = (FPW)0x00FF00FF; /* Intel Read Mode */
103 else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
104 *base = (FPW)0x00F000F0; /* AMD Read Mode */
105}
106
107/*-----------------------------------------------------------------------
108 */
109static void flash_get_offsets (ulong base, flash_info_t *info)
110{
111 int i;
112
113 /* set up sector start address table */
114 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL
115 && (info->flash_id & FLASH_BTYPE)) {
116 int bootsect_size; /* number of bytes/boot sector */
117 int sect_size; /* number of bytes/regular sector */
118
119 bootsect_size = 0x00002000 * (sizeof(FPW)/2);
120 sect_size = 0x00010000 * (sizeof(FPW)/2);
121
122 /* set sector offsets for bottom boot block type */
123 for (i = 0; i < 8; ++i) {
124 info->start[i] = base + (i * bootsect_size);
125 }
126 for (i = 8; i < info->sector_count; i++) {
127 info->start[i] = base + ((i - 7) * sect_size);
128 }
129 }
130 else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD
131 && (info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U) {
132
133 int sect_size; /* number of bytes/sector */
134
135 sect_size = 0x00010000 * (sizeof(FPW)/2);
136
137 /* set up sector start address table (uniform sector type) */
138 for( i = 0; i < info->sector_count; i++ )
139 info->start[i] = base + (i * sect_size);
140 }
141}
142
143/*-----------------------------------------------------------------------
144 */
145
146static flash_info_t *flash_get_info(ulong base)
147{
148 int i;
149 flash_info_t * info;
wdenk57b2d802003-06-27 21:31:46 +0000150
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200151 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i ++) {
wdenk541a76d2003-05-03 15:50:43 +0000152 info = & flash_info[i];
153 if (info->start[0] <= base && base < info->start[0] + info->size)
154 break;
155 }
wdenk57b2d802003-06-27 21:31:46 +0000156
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200157 return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
wdenk541a76d2003-05-03 15:50:43 +0000158}
159
160/*-----------------------------------------------------------------------
161 */
162
163void flash_print_info (flash_info_t *info)
164{
165 int i;
166 uchar *boottype;
167 uchar *bootletter;
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200168 char *fmt;
wdenk541a76d2003-05-03 15:50:43 +0000169 uchar botbootletter[] = "B";
170 uchar topbootletter[] = "T";
171 uchar botboottype[] = "bottom boot sector";
172 uchar topboottype[] = "top boot sector";
173
174 if (info->flash_id == FLASH_UNKNOWN) {
175 printf ("missing or unknown FLASH type\n");
176 return;
177 }
178
179 switch (info->flash_id & FLASH_VENDMASK) {
180 case FLASH_MAN_AMD: printf ("AMD "); break;
181 case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
182 case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
183 case FLASH_MAN_SST: printf ("SST "); break;
184 case FLASH_MAN_STM: printf ("STM "); break;
185 case FLASH_MAN_INTEL: printf ("INTEL "); break;
186 default: printf ("Unknown Vendor "); break;
187 }
188
189 /* check for top or bottom boot, if it applies */
190 if (info->flash_id & FLASH_BTYPE) {
191 boottype = botboottype;
192 bootletter = botbootletter;
193 }
194 else {
195 boottype = topboottype;
196 bootletter = topbootletter;
197 }
198
199 switch (info->flash_id & FLASH_TYPEMASK) {
200 case FLASH_AM640U:
201 fmt = "29LV641D (64 Mbit, uniform sectors)\n";
202 break;
wdenk57b2d802003-06-27 21:31:46 +0000203 case FLASH_28F800C3B:
204 case FLASH_28F800C3T:
wdenk541a76d2003-05-03 15:50:43 +0000205 fmt = "28F800C3%s (8 Mbit, %s)\n";
206 break;
207 case FLASH_INTEL800B:
208 case FLASH_INTEL800T:
209 fmt = "28F800B3%s (8 Mbit, %s)\n";
210 break;
wdenk57b2d802003-06-27 21:31:46 +0000211 case FLASH_28F160C3B:
212 case FLASH_28F160C3T:
wdenk541a76d2003-05-03 15:50:43 +0000213 fmt = "28F160C3%s (16 Mbit, %s)\n";
214 break;
215 case FLASH_INTEL160B:
216 case FLASH_INTEL160T:
217 fmt = "28F160B3%s (16 Mbit, %s)\n";
218 break;
wdenk57b2d802003-06-27 21:31:46 +0000219 case FLASH_28F320C3B:
220 case FLASH_28F320C3T:
wdenk541a76d2003-05-03 15:50:43 +0000221 fmt = "28F320C3%s (32 Mbit, %s)\n";
222 break;
223 case FLASH_INTEL320B:
224 case FLASH_INTEL320T:
225 fmt = "28F320B3%s (32 Mbit, %s)\n";
226 break;
wdenk57b2d802003-06-27 21:31:46 +0000227 case FLASH_28F640C3B:
228 case FLASH_28F640C3T:
wdenk541a76d2003-05-03 15:50:43 +0000229 fmt = "28F640C3%s (64 Mbit, %s)\n";
230 break;
231 case FLASH_INTEL640B:
232 case FLASH_INTEL640T:
233 fmt = "28F640B3%s (64 Mbit, %s)\n";
234 break;
235 default:
236 fmt = "Unknown Chip Type\n";
237 break;
238 }
239
240 printf (fmt, bootletter, boottype);
241
242 printf (" Size: %ld MB in %d Sectors\n",
243 info->size >> 20,
244 info->sector_count);
245
246 printf (" Sector Start Addresses:");
247
248 for (i=0; i<info->sector_count; ++i) {
249 if ((i % 5) == 0) {
250 printf ("\n ");
251 }
252
253 printf (" %08lX%s", info->start[i],
254 info->protect[i] ? " (RO)" : " ");
255 }
256
257 printf ("\n");
258}
259
260/*-----------------------------------------------------------------------
261 */
262
263/*
264 * The following code cannot be run from FLASH!
265 */
266
267ulong flash_get_size (FPWV *addr, flash_info_t *info)
268{
269 /* Write auto select command: read Manufacturer ID */
270
271 /* Write auto select command sequence and test FLASH answer */
272 addr[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */
273 addr[FLASH_CYCLE2] = (FPW)0x00550055; /* for AMD, Intel ignores this */
274 addr[FLASH_CYCLE1] = (FPW)0x00900090; /* selects Intel or AMD */
275
276 /* The manufacturer codes are only 1 byte, so just use 1 byte.
277 * This works for any bus width and any FLASH device width.
278 */
wdenk6912c392003-05-05 17:09:41 +0000279 udelay(100);
280 switch (addr[0] & 0xff) {
wdenk541a76d2003-05-03 15:50:43 +0000281
282 case (uchar)AMD_MANUFACT:
283 info->flash_id = FLASH_MAN_AMD;
284 break;
285
286 case (uchar)INTEL_MANUFACT:
287 info->flash_id = FLASH_MAN_INTEL;
288 break;
289
290 default:
291 info->flash_id = FLASH_UNKNOWN;
292 info->sector_count = 0;
293 info->size = 0;
294 break;
295 }
296
297 /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
wdenk541a76d2003-05-03 15:50:43 +0000298 if (info->flash_id != FLASH_UNKNOWN) switch (addr[1]) {
299
300 case (FPW)AMD_ID_LV640U: /* 29LV640 and 29LV641 have same ID */
301 info->flash_id += FLASH_AM640U;
302 info->sector_count = 128;
303 info->size = 0x00800000 * (sizeof(FPW)/2);
304 break; /* => 8 or 16 MB */
305
306 case (FPW)INTEL_ID_28F800C3B:
307 info->flash_id += FLASH_28F800C3B;
308 info->sector_count = 23;
309 info->size = 0x00100000 * (sizeof(FPW)/2);
310 break; /* => 1 or 2 MB */
311
312 case (FPW)INTEL_ID_28F800B3B:
313 info->flash_id += FLASH_INTEL800B;
314 info->sector_count = 23;
315 info->size = 0x00100000 * (sizeof(FPW)/2);
316 break; /* => 1 or 2 MB */
317
318 case (FPW)INTEL_ID_28F160C3B:
319 info->flash_id += FLASH_28F160C3B;
320 info->sector_count = 39;
321 info->size = 0x00200000 * (sizeof(FPW)/2);
322 break; /* => 2 or 4 MB */
323
324 case (FPW)INTEL_ID_28F160B3B:
325 info->flash_id += FLASH_INTEL160B;
326 info->sector_count = 39;
327 info->size = 0x00200000 * (sizeof(FPW)/2);
328 break; /* => 2 or 4 MB */
329
330 case (FPW)INTEL_ID_28F320C3B:
331 info->flash_id += FLASH_28F320C3B;
332 info->sector_count = 71;
333 info->size = 0x00400000 * (sizeof(FPW)/2);
334 break; /* => 4 or 8 MB */
335
336 case (FPW)INTEL_ID_28F320B3B:
337 info->flash_id += FLASH_INTEL320B;
338 info->sector_count = 71;
339 info->size = 0x00400000 * (sizeof(FPW)/2);
340 break; /* => 4 or 8 MB */
341
342 case (FPW)INTEL_ID_28F640C3B:
343 info->flash_id += FLASH_28F640C3B;
344 info->sector_count = 135;
345 info->size = 0x00800000 * (sizeof(FPW)/2);
346 break; /* => 8 or 16 MB */
347
348 case (FPW)INTEL_ID_28F640B3B:
349 info->flash_id += FLASH_INTEL640B;
350 info->sector_count = 135;
351 info->size = 0x00800000 * (sizeof(FPW)/2);
352 break; /* => 8 or 16 MB */
353
354 default:
355 info->flash_id = FLASH_UNKNOWN;
356 info->sector_count = 0;
357 info->size = 0;
358 return (0); /* => no or unknown flash */
359 }
360
361 flash_get_offsets((ulong)addr, info);
362
363 /* Put FLASH back in read mode */
364 flash_reset(info);
365
366 return (info->size);
367}
368
369/*-----------------------------------------------------------------------
370 */
371
372int flash_erase (flash_info_t *info, int s_first, int s_last)
373{
374 FPWV *addr;
375 int flag, prot, sect;
376 int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
377 ulong start, now, last;
378 int rcode = 0;
379
380 if ((s_first < 0) || (s_first > s_last)) {
381 if (info->flash_id == FLASH_UNKNOWN) {
382 printf ("- missing\n");
383 } else {
384 printf ("- no sectors to erase\n");
385 }
386 return 1;
387 }
388
389 switch (info->flash_id & FLASH_TYPEMASK) {
390 case FLASH_INTEL800B:
391 case FLASH_INTEL160B:
392 case FLASH_INTEL320B:
393 case FLASH_INTEL640B:
394 case FLASH_28F800C3B:
395 case FLASH_28F160C3B:
396 case FLASH_28F320C3B:
397 case FLASH_28F640C3B:
398 case FLASH_AM640U:
399 break;
400 case FLASH_UNKNOWN:
401 default:
402 printf ("Can't erase unknown flash type %08lx - aborted\n",
403 info->flash_id);
404 return 1;
405 }
406
407 prot = 0;
408 for (sect=s_first; sect<=s_last; ++sect) {
409 if (info->protect[sect]) {
410 prot++;
411 }
412 }
413
414 if (prot) {
415 printf ("- Warning: %d protected sectors will not be erased!\n",
416 prot);
417 } else {
418 printf ("\n");
419 }
420
421 last = get_timer(0);
422
423 /* Start erase on unprotected sectors */
424 for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
425
426 if (info->protect[sect] != 0) /* protected, skip it */
427 continue;
428
429 /* Disable interrupts which might cause a timeout here */
430 flag = disable_interrupts();
431
432 addr = (FPWV *)(info->start[sect]);
433 if (intel) {
434 *addr = (FPW)0x00500050; /* clear status register */
435 *addr = (FPW)0x00200020; /* erase setup */
436 *addr = (FPW)0x00D000D0; /* erase confirm */
437 }
438 else {
439 /* must be AMD style if not Intel */
440 FPWV *base; /* first address in bank */
441
442 base = (FPWV *)(info->start[0]);
443 base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
444 base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
445 base[FLASH_CYCLE1] = (FPW)0x00800080; /* erase mode */
446 base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
447 base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
448 *addr = (FPW)0x00300030; /* erase sector */
449 }
450
451 /* re-enable interrupts if necessary */
452 if (flag)
453 enable_interrupts();
454
455 start = get_timer(0);
456
457 /* wait at least 50us for AMD, 80us for Intel.
458 * Let's wait 1 ms.
459 */
460 udelay (1000);
461
462 while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200463 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenk541a76d2003-05-03 15:50:43 +0000464 printf ("Timeout\n");
465
466 if (intel) {
467 /* suspend erase */
468 *addr = (FPW)0x00B000B0;
469 }
470
471 flash_reset(info); /* reset to read mode */
472 rcode = 1; /* failed */
473 break;
474 }
475
476 /* show that we're waiting */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200477 if ((get_timer(last)) > CONFIG_SYS_HZ) {/* every second */
wdenk541a76d2003-05-03 15:50:43 +0000478 putc ('.');
479 last = get_timer(0);
480 }
481 }
482
483 /* show that we're waiting */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200484 if ((get_timer(last)) > CONFIG_SYS_HZ) { /* every second */
wdenk541a76d2003-05-03 15:50:43 +0000485 putc ('.');
486 last = get_timer(0);
487 }
488
489 flash_reset(info); /* reset to read mode */
490 }
491
492 printf (" done\n");
493 return rcode;
494}
495
496/*-----------------------------------------------------------------------
497 * Copy memory to flash, returns:
498 * 0 - OK
499 * 1 - write timeout
500 * 2 - Flash not erased
501 */
502int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
503{
wdenk6912c392003-05-05 17:09:41 +0000504 FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
505 int bytes; /* number of bytes to program in current word */
506 int left; /* number of bytes left to program */
507 int i, res;
wdenk541a76d2003-05-03 15:50:43 +0000508
wdenk6912c392003-05-05 17:09:41 +0000509 for (left = cnt, res = 0;
510 left > 0 && res == 0;
511 addr += sizeof(data), left -= sizeof(data) - bytes) {
wdenk541a76d2003-05-03 15:50:43 +0000512
wdenk6912c392003-05-05 17:09:41 +0000513 bytes = addr & (sizeof(data) - 1);
514 addr &= ~(sizeof(data) - 1);
wdenk541a76d2003-05-03 15:50:43 +0000515
wdenk6912c392003-05-05 17:09:41 +0000516 /* combine source and destination data so can program
517 * an entire word of 16 or 32 bits
518 */
519 for (i = 0; i < sizeof(data); i++) {
520 data <<= 8;
521 if (i < bytes || i - bytes >= left )
522 data += *((uchar *)addr + i);
523 else
524 data += *src++;
525 }
wdenk541a76d2003-05-03 15:50:43 +0000526
wdenk6912c392003-05-05 17:09:41 +0000527 /* write one word to the flash */
528 switch (info->flash_id & FLASH_VENDMASK) {
529 case FLASH_MAN_AMD:
530 res = write_word_amd(info, (FPWV *)addr, data);
531 break;
532 case FLASH_MAN_INTEL:
533 res = write_word_intel(info, (FPWV *)addr, data);
534 break;
535 default:
536 /* unknown flash type, error! */
537 printf ("missing or unknown FLASH type\n");
538 res = 1; /* not really a timeout, but gives error */
539 break;
540 }
wdenk541a76d2003-05-03 15:50:43 +0000541 }
wdenk541a76d2003-05-03 15:50:43 +0000542
wdenk6912c392003-05-05 17:09:41 +0000543 return (res);
wdenk541a76d2003-05-03 15:50:43 +0000544}
545
546/*-----------------------------------------------------------------------
547 * Write a word to Flash for AMD FLASH
548 * A word is 16 or 32 bits, whichever the bus width of the flash bank
549 * (not an individual chip) is.
550 *
551 * returns:
552 * 0 - OK
553 * 1 - write timeout
554 * 2 - Flash not erased
555 */
556static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
557{
wdenk6912c392003-05-05 17:09:41 +0000558 ulong start;
559 int flag;
560 int res = 0; /* result, assume success */
561 FPWV *base; /* first address in flash bank */
wdenk541a76d2003-05-03 15:50:43 +0000562
wdenk6912c392003-05-05 17:09:41 +0000563 /* Check if Flash is (sufficiently) erased */
564 if ((*dest & data) != data) {
565 return (2);
566 }
wdenk541a76d2003-05-03 15:50:43 +0000567
568
wdenk6912c392003-05-05 17:09:41 +0000569 base = (FPWV *)(info->start[0]);
wdenk541a76d2003-05-03 15:50:43 +0000570
wdenk6912c392003-05-05 17:09:41 +0000571 /* Disable interrupts which might cause a timeout here */
572 flag = disable_interrupts();
wdenk541a76d2003-05-03 15:50:43 +0000573
wdenk6912c392003-05-05 17:09:41 +0000574 base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
575 base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
576 base[FLASH_CYCLE1] = (FPW)0x00A000A0; /* selects program mode */
wdenk541a76d2003-05-03 15:50:43 +0000577
wdenk6912c392003-05-05 17:09:41 +0000578 *dest = data; /* start programming the data */
wdenk541a76d2003-05-03 15:50:43 +0000579
wdenk6912c392003-05-05 17:09:41 +0000580 /* re-enable interrupts if necessary */
581 if (flag)
582 enable_interrupts();
wdenk541a76d2003-05-03 15:50:43 +0000583
wdenk6912c392003-05-05 17:09:41 +0000584 start = get_timer (0);
wdenk541a76d2003-05-03 15:50:43 +0000585
wdenk6912c392003-05-05 17:09:41 +0000586 /* data polling for D7 */
587 while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200588 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenk6912c392003-05-05 17:09:41 +0000589 *dest = (FPW)0x00F000F0; /* reset bank */
590 res = 1;
591 }
wdenk541a76d2003-05-03 15:50:43 +0000592 }
wdenk541a76d2003-05-03 15:50:43 +0000593
wdenk6912c392003-05-05 17:09:41 +0000594 return (res);
wdenk541a76d2003-05-03 15:50:43 +0000595}
596
597/*-----------------------------------------------------------------------
598 * Write a word to Flash for Intel FLASH
599 * A word is 16 or 32 bits, whichever the bus width of the flash bank
600 * (not an individual chip) is.
601 *
602 * returns:
603 * 0 - OK
604 * 1 - write timeout
605 * 2 - Flash not erased
606 */
607static int write_word_intel (flash_info_t *info, FPWV *dest, FPW data)
608{
wdenk6912c392003-05-05 17:09:41 +0000609 ulong start;
610 int flag;
611 int res = 0; /* result, assume success */
wdenk541a76d2003-05-03 15:50:43 +0000612
wdenk6912c392003-05-05 17:09:41 +0000613 /* Check if Flash is (sufficiently) erased */
614 if ((*dest & data) != data) {
615 return (2);
616 }
wdenk541a76d2003-05-03 15:50:43 +0000617
wdenk6912c392003-05-05 17:09:41 +0000618 /* Disable interrupts which might cause a timeout here */
619 flag = disable_interrupts();
wdenk541a76d2003-05-03 15:50:43 +0000620
wdenk6912c392003-05-05 17:09:41 +0000621 *dest = (FPW)0x00500050; /* clear status register */
622 *dest = (FPW)0x00FF00FF; /* make sure in read mode */
623 *dest = (FPW)0x00400040; /* program setup */
wdenk541a76d2003-05-03 15:50:43 +0000624
wdenk6912c392003-05-05 17:09:41 +0000625 *dest = data; /* start programming the data */
wdenk541a76d2003-05-03 15:50:43 +0000626
wdenk6912c392003-05-05 17:09:41 +0000627 /* re-enable interrupts if necessary */
628 if (flag)
629 enable_interrupts();
wdenk541a76d2003-05-03 15:50:43 +0000630
wdenk6912c392003-05-05 17:09:41 +0000631 start = get_timer (0);
wdenk541a76d2003-05-03 15:50:43 +0000632
wdenk6912c392003-05-05 17:09:41 +0000633 while (res == 0 && (*dest & (FPW)0x00800080) != (FPW)0x00800080) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200634 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenk6912c392003-05-05 17:09:41 +0000635 *dest = (FPW)0x00B000B0; /* Suspend program */
636 res = 1;
637 }
wdenk541a76d2003-05-03 15:50:43 +0000638 }
wdenk541a76d2003-05-03 15:50:43 +0000639
wdenk6912c392003-05-05 17:09:41 +0000640 if (res == 0 && (*dest & (FPW)0x00100010))
641 res = 1; /* write failed, time out error is close enough */
wdenk541a76d2003-05-03 15:50:43 +0000642
wdenk6912c392003-05-05 17:09:41 +0000643 *dest = (FPW)0x00500050; /* clear status register */
644 *dest = (FPW)0x00FF00FF; /* make sure in read mode */
wdenk541a76d2003-05-03 15:50:43 +0000645
wdenk6912c392003-05-05 17:09:41 +0000646 return (res);
wdenk541a76d2003-05-03 15:50:43 +0000647}