blob: 3ce7bb329a62ab3d4bad741b80e21f2e266b18c3 [file] [log] [blame]
wdenkaffae2b2002-08-17 09:36:01 +00001/*
2 * (C) Copyright 2001
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
24#include <common.h>
25#include <mpc8xx.h>
26
Jean-Christophe PLAGNIOL-VILLARD5a1aceb2008-09-10 22:48:04 +020027#if defined(CONFIG_ENV_IS_IN_FLASH)
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020028# ifndef CONFIG_ENV_ADDR
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020029# define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
wdenkaffae2b2002-08-17 09:36:01 +000030# endif
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020031# ifndef CONFIG_ENV_SIZE
32# define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE
wdenkaffae2b2002-08-17 09:36:01 +000033# endif
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020034# ifndef CONFIG_ENV_SECT_SIZE
35# define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE
wdenkaffae2b2002-08-17 09:36:01 +000036# endif
37#endif
38
39/*---------------------------------------------------------------------*/
40#undef DEBUG_FLASH
41
42#ifdef DEBUG_FLASH
43#define DEBUGF(fmt,args...) printf(fmt ,##args)
44#else
45#define DEBUGF(fmt,args...)
46#endif
47/*---------------------------------------------------------------------*/
48
49
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020050flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenkaffae2b2002-08-17 09:36:01 +000051
52/*-----------------------------------------------------------------------
53 * Functions
54 */
55static ulong flash_get_size (vu_long *addr, flash_info_t *info);
56static int write_data (flash_info_t *info, ulong dest, ulong data);
57static void flash_get_offsets (ulong base, flash_info_t *info);
58
59/*-----------------------------------------------------------------------
60 *
61 * The PCU E uses an address map where flash banks are aligned top
62 * down, so that the "first" flash bank ends at top of memory, and
63 * the monitor entry point is at address (0xFFF00100). The second
64 * flash bank is mapped immediately below bank 0.
65 *
66 * This is NOT in conformance to the "official" memory map!
67 *
68 */
69
70#define PCU_MONITOR_BASE ( (flash_info[0].start[0] + flash_info[0].size - 1) \
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020071 - (0xFFFFFFFF - CONFIG_SYS_MONITOR_BASE) )
wdenkaffae2b2002-08-17 09:36:01 +000072
73/*-----------------------------------------------------------------------
74 */
75
76unsigned long flash_init (void)
77{
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020078 volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
wdenkaffae2b2002-08-17 09:36:01 +000079 volatile memctl8xx_t *memctl = &immap->im_memctl;
80 unsigned long base, size_b0, size_b1;
81 int i;
82
83 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020084 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenkaffae2b2002-08-17 09:36:01 +000085 flash_info[i].flash_id = FLASH_UNKNOWN;
86 }
87
88 /* Static FLASH Bank configuration here - FIXME XXX */
89
90 /*
91 * Warning:
92 *
93 * Since the PCU E memory map assigns flash banks top down,
94 * we swap the numbering later if both banks are equipped,
95 * so they look like a contiguous area of memory.
96 */
97 DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
98
99 size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
100
101 if (flash_info[0].flash_id == FLASH_UNKNOWN) {
102 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
103 size_b0, size_b0<<20);
104 }
105
106 DEBUGF("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE6_PRELIM);
107 size_b1 = flash_get_size((vu_long *)FLASH_BASE6_PRELIM, &flash_info[1]);
108
109 DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n", size_b0, size_b1);
110
111 if (size_b1 > size_b0) {
112 printf ("## ERROR: "
113 "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
114 size_b1, size_b1<<20,
115 size_b0, size_b0<<20
116 );
117 flash_info[0].flash_id = FLASH_UNKNOWN;
118 flash_info[1].flash_id = FLASH_UNKNOWN;
119 flash_info[0].sector_count = -1;
120 flash_info[1].sector_count = -1;
121 flash_info[0].size = 0;
122 flash_info[1].size = 0;
123 return (0);
124 }
125
126 DEBUGF ("## Before remap: "
127 "BR0: 0x%08x OR0: 0x%08x "
128 "BR6: 0x%08x OR6: 0x%08x\n",
129 memctl->memc_br0, memctl->memc_or0,
130 memctl->memc_br6, memctl->memc_or6);
131
132 /* Remap FLASH according to real size */
133 base = 0 - size_b0;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200134 memctl->memc_or0 = CONFIG_SYS_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
wdenkaffae2b2002-08-17 09:36:01 +0000135 memctl->memc_br0 = (base & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
136
137 DEBUGF("## BR0: 0x%08x OR0: 0x%08x\n",
138 memctl->memc_br0, memctl->memc_or0);
139
140 /* Re-do sizing to get full correct info */
141 size_b0 = flash_get_size((vu_long *)base, &flash_info[0]);
142 base = 0 - size_b0;
143
144 flash_info[0].size = size_b0;
145
146 flash_get_offsets (base, &flash_info[0]);
147
148 /* monitor protection ON by default */
149 flash_protect(FLAG_PROTECT_SET,
150 PCU_MONITOR_BASE,
wdenk3b57fe02003-05-30 12:48:29 +0000151 PCU_MONITOR_BASE+monitor_flash_len-1,
wdenkaffae2b2002-08-17 09:36:01 +0000152 &flash_info[0]);
153
Jean-Christophe PLAGNIOL-VILLARD5a1aceb2008-09-10 22:48:04 +0200154#ifdef CONFIG_ENV_IS_IN_FLASH
wdenkaffae2b2002-08-17 09:36:01 +0000155 /* ENV protection ON by default */
156 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200157 CONFIG_ENV_ADDR,
158 CONFIG_ENV_ADDR+CONFIG_ENV_SECT_SIZE-1,
wdenkaffae2b2002-08-17 09:36:01 +0000159 &flash_info[0]);
160#endif
161
162 if (size_b1) {
163 flash_info_t tmp_info;
164
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200165 memctl->memc_or6 = CONFIG_SYS_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
wdenkaffae2b2002-08-17 09:36:01 +0000166 memctl->memc_br6 = ((base - size_b1) & BR_BA_MSK) |
167 BR_PS_16 | BR_MS_GPCM | BR_V;
168
169 DEBUGF("## New BR6: 0x%08x OR6: 0x%08x\n",
170 memctl->memc_br6, memctl->memc_or6);
171
172 /* Re-do sizing to get full correct info */
173 size_b1 = flash_get_size((vu_long *)(base - size_b1),
174 &flash_info[1]);
175 base -= size_b1;
176
177 flash_get_offsets (base, &flash_info[1]);
178
179 flash_info[1].size = size_b1;
180
Jean-Christophe PLAGNIOL-VILLARD5a1aceb2008-09-10 22:48:04 +0200181#ifdef CONFIG_ENV_IS_IN_FLASH
wdenkaffae2b2002-08-17 09:36:01 +0000182 /* ENV protection ON by default */
183 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200184 CONFIG_ENV_ADDR,
185 CONFIG_ENV_ADDR+CONFIG_ENV_SECT_SIZE-1,
wdenkaffae2b2002-08-17 09:36:01 +0000186 &flash_info[1]);
187#endif
188 /*
189 * Swap bank numbers so that addresses are in ascending order
190 */
191 tmp_info = flash_info[0];
192 flash_info[0] = flash_info[1];
193 flash_info[1] = tmp_info;
194 } else {
195 memctl->memc_br1 = 0; /* invalidate bank */
196
197 flash_info[1].flash_id = FLASH_UNKNOWN;
198 flash_info[1].sector_count = -1;
199 }
200
201
202 DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
203
204 return (size_b0 + size_b1);
205}
206
207/*-----------------------------------------------------------------------
208 */
209static void flash_get_offsets (ulong base, flash_info_t *info)
210{
211 int i;
212 short n;
213
214 if (info->flash_id == FLASH_UNKNOWN) {
215 return;
216 }
217
218 if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_AMD) {
219 return;
220 }
221
222 switch (info->flash_id & FLASH_TYPEMASK) {
223 case FLASH_AMDL322T:
224 case FLASH_AMDL323T:
225 case FLASH_AMDL324T:
226 /* set sector offsets for top boot block type */
227
228 base += info->size;
229 i = info->sector_count;
230 for (n=0; n<8; ++n) { /* 8 x 8k boot sectors */
231 base -= 8 << 10;
232 --i;
233 info->start[i] = base;
234 }
235 while (i > 0) { /* 64k regular sectors */
236 base -= 64 << 10;
237 --i;
238 info->start[i] = base;
239 }
240 return;
241 case FLASH_AMDL322B:
242 case FLASH_AMDL323B:
243 case FLASH_AMDL324B:
244 /* set sector offsets for bottom boot block type */
245 for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
246 info->start[i] = base;
247 base += 8 << 10;
248 }
249 while (base < info->size) { /* 64k regular sectors */
250 info->start[i] = base;
251 base += 64 << 10;
252 ++i;
253 }
254 return;
255 case FLASH_AMDL640:
256 /* set sector offsets for dual boot block type */
257 for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
258 info->start[i] = base;
259 base += 8 << 10;
260 }
261 n = info->sector_count - 8;
262 while (i < n) { /* 64k regular sectors */
263 info->start[i] = base;
264 base += 64 << 10;
265 ++i;
266 }
267 while (i < info->sector_count) { /* 8 x 8k boot sectors */
268 info->start[i] = base;
269 base += 8 << 10;
270 ++i;
271 }
272 return;
273 default:
274 return;
275 }
276 /* NOTREACHED */
277}
278
279/*-----------------------------------------------------------------------
280 */
281void flash_print_info (flash_info_t *info)
282{
283 int i;
284
285 if (info->flash_id == FLASH_UNKNOWN) {
286 printf ("missing or unknown FLASH type\n");
287 return;
288 }
289
290 switch (info->flash_id & FLASH_VENDMASK) {
291 case FLASH_MAN_AMD: printf ("AMD "); break;
292 case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
293 default: printf ("Unknown Vendor "); break;
294 }
295
296 switch (info->flash_id & FLASH_TYPEMASK) {
297 case FLASH_AMDL322B: printf ("AM29DL322B (32 Mbit, bottom boot sect)\n");
298 break;
299 case FLASH_AMDL322T: printf ("AM29DL322T (32 Mbit, top boot sector)\n");
300 break;
301 case FLASH_AMDL323B: printf ("AM29DL323B (32 Mbit, bottom boot sect)\n");
302 break;
303 case FLASH_AMDL323T: printf ("AM29DL323T (32 Mbit, top boot sector)\n");
304 break;
305 case FLASH_AMDL324B: printf ("AM29DL324B (32 Mbit, bottom boot sect)\n");
306 break;
307 case FLASH_AMDL324T: printf ("AM29DL324T (32 Mbit, top boot sector)\n");
308 break;
309 case FLASH_AMDL640: printf ("AM29DL640D (64 Mbit, dual boot sector)\n");
310 break;
311 default: printf ("Unknown Chip Type 0x%lX\n",
312 info->flash_id);
313 break;
314 }
315
316 printf (" Size: %ld MB in %d Sectors\n",
317 info->size >> 20, info->sector_count);
318
319 printf (" Sector Start Addresses:");
320 for (i=0; i<info->sector_count; ++i) {
321 if ((i % 5) == 0)
322 printf ("\n ");
323 printf (" %08lX%s",
324 info->start[i],
325 info->protect[i] ? " (RO)" : " "
326 );
327 }
328 printf ("\n");
329 return;
330}
331
332/*-----------------------------------------------------------------------
333 */
334
335
336/*-----------------------------------------------------------------------
337 */
338
339/*
340 * The following code cannot be run from FLASH!
341 */
342
343static ulong flash_get_size (vu_long *addr, flash_info_t *info)
344{
345 short i;
346 ushort value;
347 vu_short *saddr = (vu_short *)addr;
348
349 /* Write auto select command: read Manufacturer ID */
350 saddr[0x0555] = 0x00AA;
351 saddr[0x02AA] = 0x0055;
352 saddr[0x0555] = 0x0090;
353
354 value = saddr[0];
355
356 DEBUGF("Manuf. ID @ 0x%08lx: 0x%04x\n", (ulong)addr, value);
357
358 switch (value) {
359 case (AMD_MANUFACT & 0xFFFF):
360 info->flash_id = FLASH_MAN_AMD;
361 break;
362 case (FUJ_MANUFACT & 0xFFFF):
363 info->flash_id = FLASH_MAN_FUJ;
364 break;
365 default:
366 DEBUGF("Unknown Manufacturer ID\n");
367 info->flash_id = FLASH_UNKNOWN;
368 info->sector_count = 0;
369 info->size = 0;
370 return (0); /* no or unknown flash */
371 }
372
373 value = saddr[1]; /* device ID */
374
375 DEBUGF("Device ID @ 0x%08lx: 0x%04x\n", (ulong)(&addr[1]), value);
376
377 switch (value) {
378
379 case (AMD_ID_DL322T & 0xFFFF):
380 info->flash_id += FLASH_AMDL322T;
381 info->sector_count = 71;
382 info->size = 0x00400000;
383 break; /* => 8 MB */
384
385 case (AMD_ID_DL322B & 0xFFFF):
386 info->flash_id += FLASH_AMDL322B;
387 info->sector_count = 71;
388 info->size = 0x00400000;
389 break; /* => 8 MB */
390
391 case (AMD_ID_DL323T & 0xFFFF):
392 info->flash_id += FLASH_AMDL323T;
393 info->sector_count = 71;
394 info->size = 0x00400000;
395 break; /* => 8 MB */
396
397 case (AMD_ID_DL323B & 0xFFFF):
398 info->flash_id += FLASH_AMDL323B;
399 info->sector_count = 71;
400 info->size = 0x00400000;
401 break; /* => 8 MB */
402
403 case (AMD_ID_DL324T & 0xFFFF):
404 info->flash_id += FLASH_AMDL324T;
405 info->sector_count = 71;
406 info->size = 0x00400000;
407 break; /* => 8 MB */
408
409 case (AMD_ID_DL324B & 0xFFFF):
410 info->flash_id += FLASH_AMDL324B;
411 info->sector_count = 71;
412 info->size = 0x00400000;
413 break; /* => 8 MB */
414 case (AMD_ID_DL640 & 0xFFFF):
415 info->flash_id += FLASH_AMDL640;
416 info->sector_count = 142;
417 info->size = 0x00800000;
418 break;
419 default:
420 DEBUGF("Unknown Device ID\n");
421 info->flash_id = FLASH_UNKNOWN;
422 return (0); /* => no or unknown flash */
423
424 }
425
426 flash_get_offsets ((ulong)addr, info);
427
428 /* check for protected sectors */
429 for (i = 0; i < info->sector_count; i++) {
430#if 0
431 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
432 /* D0 = 1 if protected */
433 saddr = (vu_short *)(info->start[i]);
434 info->protect[i] = saddr[2] & 1;
435#else
436 info->protect[i] =0;
437#endif
438 }
439
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200440 if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
wdenkaffae2b2002-08-17 09:36:01 +0000441 printf ("** ERROR: sector count %d > max (%d) **\n",
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200442 info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
443 info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
wdenkaffae2b2002-08-17 09:36:01 +0000444 }
445
446 saddr = (vu_short *)info->start[0];
447 *saddr = 0x00F0; /* restore read mode */
448
449 return (info->size);
450}
451
452
453/*-----------------------------------------------------------------------
454 */
455
456int flash_erase (flash_info_t *info, int s_first, int s_last)
457{
458 vu_short *addr = (vu_short*)(info->start[0]);
459 int flag, prot, sect, l_sect;
460 ulong start, now, last;
461
462 if ((s_first < 0) || (s_first > s_last)) {
463 if (info->flash_id == FLASH_UNKNOWN) {
464 printf ("- missing\n");
465 } else {
466 printf ("- no sectors to erase\n");
467 }
468 return 1;
469 }
470
471 if ((info->flash_id == FLASH_UNKNOWN) ||
472 (info->flash_id > FLASH_AMD_COMP)) {
473 printf ("Can't erase unknown flash type %08lx - aborted\n",
474 info->flash_id);
475 return 1;
476 }
477
478 prot = 0;
479 for (sect=s_first; sect<=s_last; ++sect) {
480 if (info->protect[sect]) {
481 prot++;
482 }
483 }
484
485 if (prot) {
486 printf ("- Warning: %d protected sectors will not be erased!\n",
487 prot);
488 } else {
489 printf ("\n");
490 }
491
492 l_sect = -1;
493
494 /* Disable interrupts which might cause a timeout here */
495 flag = disable_interrupts();
496
497 addr[0x0555] = 0x00AA;
498 addr[0x02AA] = 0x0055;
499 addr[0x0555] = 0x0080;
500 addr[0x0555] = 0x00AA;
501 addr[0x02AA] = 0x0055;
502
503 /* Start erase on unprotected sectors */
504 for (sect = s_first; sect<=s_last; sect++) {
505 if (info->protect[sect] == 0) { /* not protected */
506 addr = (vu_short*)(info->start[sect]);
507 addr[0] = 0x0030;
508 l_sect = sect;
509 }
510 }
511
512 /* re-enable interrupts if necessary */
513 if (flag)
514 enable_interrupts();
515
516 /* wait at least 80us - let's wait 1 ms */
517 udelay (1000);
518
519 /*
520 * We wait for the last triggered sector
521 */
522 if (l_sect < 0)
523 goto DONE;
524
525 start = get_timer (0);
526 last = start;
527 addr = (vu_short*)(info->start[l_sect]);
528 while ((addr[0] & 0x0080) != 0x0080) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200529 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenkaffae2b2002-08-17 09:36:01 +0000530 printf ("Timeout\n");
531 return 1;
532 }
533 /* show that we're waiting */
534 if ((now - last) > 1000) { /* every second */
535 putc ('.');
536 last = now;
537 }
538 }
539
540DONE:
541 /* reset to read mode */
542 addr = (vu_short *)info->start[0];
543 addr[0] = 0x00F0; /* reset bank */
544
545 printf (" done\n");
546 return 0;
547}
548
549/*-----------------------------------------------------------------------
550 * Copy memory to flash, returns:
551 * 0 - OK
552 * 1 - write timeout
553 * 2 - Flash not erased
554 */
555
556#define FLASH_WIDTH 2 /* flash bus width in bytes */
557
558int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
559{
560 ulong cp, wp, data;
561 int i, l, rc;
562
563 wp = (addr & ~(FLASH_WIDTH-1)); /* get lower FLASH_WIDTH aligned address */
564
565 /*
566 * handle unaligned start bytes
567 */
568 if ((l = addr - wp) != 0) {
569 data = 0;
570 for (i=0, cp=wp; i<l; ++i, ++cp) {
571 data = (data << 8) | (*(uchar *)cp);
572 }
573 for (; i<FLASH_WIDTH && cnt>0; ++i) {
574 data = (data << 8) | *src++;
575 --cnt;
576 ++cp;
577 }
578 for (; cnt==0 && i<FLASH_WIDTH; ++i, ++cp) {
579 data = (data << 8) | (*(uchar *)cp);
580 }
581
582 if ((rc = write_data(info, wp, data)) != 0) {
583 return (rc);
584 }
585 wp += FLASH_WIDTH;
586 }
587
588 /*
589 * handle FLASH_WIDTH aligned part
590 */
591 while (cnt >= FLASH_WIDTH) {
592 data = 0;
593 for (i=0; i<FLASH_WIDTH; ++i) {
594 data = (data << 8) | *src++;
595 }
596 if ((rc = write_data(info, wp, data)) != 0) {
597 return (rc);
598 }
599 wp += FLASH_WIDTH;
600 cnt -= FLASH_WIDTH;
601 }
602
603 if (cnt == 0) {
604 return (0);
605 }
606
607 /*
608 * handle unaligned tail bytes
609 */
610 data = 0;
611 for (i=0, cp=wp; i<FLASH_WIDTH && cnt>0; ++i, ++cp) {
612 data = (data << 8) | *src++;
613 --cnt;
614 }
615 for (; i<FLASH_WIDTH; ++i, ++cp) {
616 data = (data << 8) | (*(uchar *)cp);
617 }
618
619 return (write_data(info, wp, data));
620}
621
622/*-----------------------------------------------------------------------
623 * Write a word to Flash, returns:
624 * 0 - OK
625 * 1 - write timeout
626 * 2 - Flash not erased
627 */
628static int write_data (flash_info_t *info, ulong dest, ulong data)
629{
630 vu_short *addr = (vu_short*)(info->start[0]);
631 vu_short *sdest = (vu_short *)dest;
632 ushort sdata = (ushort)data;
633 ushort sval;
634 ulong start, passed;
635 int flag, rc;
636
637 /* Check if Flash is (sufficiently) erased */
638 if ((*sdest & sdata) != sdata) {
639 return (2);
640 }
641 /* Disable interrupts which might cause a timeout here */
642 flag = disable_interrupts();
643
644 addr[0x0555] = 0x00AA;
645 addr[0x02AA] = 0x0055;
646 addr[0x0555] = 0x00A0;
647
648#ifdef WORKAROUND_FOR_BROKEN_HARDWARE
649 /* work around the timeout bugs */
650 udelay(20);
651#endif
652
653 *sdest = sdata;
654
655 /* re-enable interrupts if necessary */
656 if (flag)
657 enable_interrupts();
658
659 rc = 0;
660 /* data polling for D7 */
661 start = get_timer (0);
662
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200663 for (passed=0; passed < CONFIG_SYS_FLASH_WRITE_TOUT; passed=get_timer(start)) {
wdenkaffae2b2002-08-17 09:36:01 +0000664
665 sval = *sdest;
666
667 if ((sval & 0x0080) == (sdata & 0x0080))
668 break;
669
670 if ((sval & 0x0020) == 0) /* DQ5: Timeout? */
671 continue;
672
673 sval = *sdest;
674
675 if ((sval & 0x0080) != (sdata & 0x0080))
676 rc = 1;
677
678 break;
679 }
680
681 if (rc) {
682 DEBUGF ("Program cycle failed @ addr 0x%08lX: val %04X data %04X\n",
683 dest, sval, sdata);
684 }
685
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200686 if (passed >= CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenkaffae2b2002-08-17 09:36:01 +0000687 DEBUGF ("Timeout @ addr 0x%08lX: val %04X data %04X\n",
688 dest, sval, sdata);
689 rc = 1;
690 }
691
692 /* reset to read mode */
693 addr = (vu_short *)info->start[0];
694 addr[0] = 0x00F0; /* reset bank */
695
696 return (rc);
697}
698
699/*-----------------------------------------------------------------------
700 */