]> git.ipfire.org Git - people/ms/u-boot.git/blame - board/evb64260/flash.c
Add GPL-2.0+ SPDX-License-Identifier to source files
[people/ms/u-boot.git] / board / evb64260 / flash.c
CommitLineData
7ebf7443
WD
1/*
2 * (C) Copyright 2001
3 * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
4 *
1a459660 5 * SPDX-License-Identifier: GPL-2.0+
7ebf7443
WD
6 */
7
8/*
9 * flash.c - flash support for the 512k, 8bit boot flash on the GEVB
10 * most of this file was based on the existing U-Boot
11 * flash drivers.
12 */
13
14#include <common.h>
15#include <mpc8xx.h>
16#include <galileo/gt64260R.h>
17#include <galileo/memory.h>
18#include "intel_flash.h"
19
20#define FLASH_ROM 0xFFFD /* unknown flash type */
21#define FLASH_RAM 0xFFFE /* unknown flash type */
22#define FLASH_MAN_UNKNOWN 0xFFFF0000
23
24/* #define DEBUG */
25/* #define FLASH_ID_OVERRIDE */ /* Hack to set type to 040B if ROM emulator is installed.
26 * Can be used to program a ROM in circuit if a programmer
27 * is not available by swapping the rom out. */
28
29/* Intel flash commands */
30int flash_erase_intel(flash_info_t *info, int s_first, int s_last);
31int write_word_intel(bank_addr_t addr, bank_word_t value);
32
6d0f6bcf 33flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
7ebf7443
WD
34
35/*-----------------------------------------------------------------------
36 * Functions
37 */
38static ulong flash_get_size (int portwidth, vu_long *addr, flash_info_t *info);
39static int write_word (flash_info_t *info, ulong dest, ulong data);
40static void flash_get_offsets (ulong base, flash_info_t *info);
41
42/*-----------------------------------------------------------------------
43 */
44
45unsigned long
46flash_init (void)
47{
48 unsigned int i;
49 unsigned long size_b0 = 0, size_b1 = 0;
50 unsigned long base, flash_size;
51
52 /* Init: no FLASHes known */
6d0f6bcf 53 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
7ebf7443
WD
54 flash_info[i].flash_id = FLASH_UNKNOWN;
55 }
56
57 /* the boot flash */
6d0f6bcf
JCPV
58 base = CONFIG_SYS_FLASH_BASE;
59#ifndef CONFIG_SYS_BOOT_FLASH_WIDTH
60#define CONFIG_SYS_BOOT_FLASH_WIDTH 1
12f34241 61#endif
6d0f6bcf 62 size_b0 = flash_get_size(CONFIG_SYS_BOOT_FLASH_WIDTH, (vu_long *)base,
12f34241 63 &flash_info[0]);
7ebf7443 64
2d5b561e
WD
65#ifndef CONFIG_P3G4
66 printf("[");
67 print_size (size_b0, "");
68 printf("@%08lX] ", base);
69#endif
7ebf7443
WD
70
71 if (flash_info[0].flash_id == FLASH_UNKNOWN) {
72 printf ("## Unknown FLASH at %08lx: Size = 0x%08lx = %ld MB\n",
73 base, size_b0, size_b0<<20);
74 }
75
6d0f6bcf
JCPV
76 base = memoryGetDeviceBaseAddress(CONFIG_SYS_EXTRA_FLASH_DEVICE);
77 for(i=1;i<CONFIG_SYS_MAX_FLASH_BANKS;i++) {
78 unsigned long size = flash_get_size(CONFIG_SYS_EXTRA_FLASH_WIDTH, (vu_long *)base, &flash_info[i]);
7ebf7443 79
2d5b561e
WD
80#ifndef CONFIG_P3G4
81 printf("[");
82 print_size (size, "");
5fa66df6 83 printf("@%08lX] ", base);
2d5b561e 84#endif
7ebf7443
WD
85
86 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
87 if(i==1) {
88 printf ("## Unknown FLASH at %08lx: Size = 0x%08lx = %ld MB\n",
89 base, size_b1, size_b1<<20);
90 }
91 break;
92 }
93 size_b1+=size;
94 base+=size;
95 }
96
6d0f6bcf 97#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
12f34241
WD
98 /* monitor protection ON by default */
99 flash_protect(FLAG_PROTECT_SET,
6d0f6bcf
JCPV
100 CONFIG_SYS_MONITOR_BASE,
101 CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
102 flash_get_info(CONFIG_SYS_MONITOR_BASE));
12f34241
WD
103#endif
104
5a1aceb0 105#ifdef CONFIG_ENV_IS_IN_FLASH
12f34241
WD
106 /* ENV protection ON by default */
107 flash_protect(FLAG_PROTECT_SET,
0e8d1586
JCPV
108 CONFIG_ENV_ADDR,
109 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
110 flash_get_info(CONFIG_ENV_ADDR));
12f34241
WD
111#endif
112
7ebf7443
WD
113 flash_size = size_b0 + size_b1;
114 return flash_size;
115}
116
117/*-----------------------------------------------------------------------
118 */
119static void
120flash_get_offsets (ulong base, flash_info_t *info)
121{
122 int i;
123 int sector_size;
124
125 if(!info->sector_count) return;
126
127 /* set up sector start address table */
128 switch(info->flash_id & FLASH_TYPEMASK) {
129 case FLASH_AM040:
130 case FLASH_28F128J3A:
131 case FLASH_28F640J3A:
132 case FLASH_RAM:
133 /* this chip has uniformly spaced sectors */
134 sector_size=info->size/info->sector_count;
135 for (i = 0; i < info->sector_count; i++)
136 info->start[i] = base + (i * sector_size);
137 break;
138 default:
139 if (info->flash_id & FLASH_BTYPE) {
140 /* set sector offsets for bottom boot block type */
141 info->start[0] = base + 0x00000000;
142 info->start[1] = base + 0x00008000;
143 info->start[2] = base + 0x0000C000;
144 info->start[3] = base + 0x00010000;
145 for (i = 4; i < info->sector_count; i++) {
146 info->start[i] = base + (i * 0x00020000) - 0x00060000;
147 }
148 } else {
149 /* set sector offsets for top boot block type */
150 i = info->sector_count - 1;
151 info->start[i--] = base + info->size - 0x00008000;
152 info->start[i--] = base + info->size - 0x0000C000;
153 info->start[i--] = base + info->size - 0x00010000;
154 for (; i >= 0; i--) {
155 info->start[i] = base + i * 0x00020000;
156 }
157 }
158 }
159}
160
12f34241
WD
161/*-----------------------------------------------------------------------
162 */
163
b8845abd 164flash_info_t *flash_get_info(ulong base)
12f34241
WD
165{
166 int i;
167 flash_info_t * info;
168
6d0f6bcf 169 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i ++) {
12f34241
WD
170 info = & flash_info[i];
171 if (info->start[0] <= base && base <= info->start[0] + info->size - 1)
172 break;
173 }
174
6d0f6bcf 175 return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
12f34241
WD
176}
177
7ebf7443
WD
178/*-----------------------------------------------------------------------
179 */
180void
181flash_print_info (flash_info_t *info)
182{
183 int i;
184
185 if (info->flash_id == FLASH_UNKNOWN) {
186 printf ("missing or unknown FLASH type\n");
187 return;
188 }
189
190 switch (info->flash_id & FLASH_VENDMASK) {
191 case FLASH_MAN_AMD: printf ("AMD "); break;
192 case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
193 case FLASH_MAN_INTEL: printf ("INTEL "); break;
194 default: printf ("Unknown Vendor "); break;
195 }
196
197 switch (info->flash_id & FLASH_TYPEMASK) {
198 case FLASH_AM040:
199 printf ("AM29LV040B (4 Mbit, bottom boot sect)\n");
200 break;
201 case FLASH_AM400B:
202 printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
203 break;
204 case FLASH_AM400T:
205 printf ("AM29LV400T (4 Mbit, top boot sector)\n");
206 break;
207 case FLASH_AM800B:
208 printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
209 break;
210 case FLASH_AM800T:
211 printf ("AM29LV800T (8 Mbit, top boot sector)\n");
212 break;
213 case FLASH_AM160B:
214 printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
215 break;
216 case FLASH_AM160T:
217 printf ("AM29LV160T (16 Mbit, top boot sector)\n");
218 break;
219 case FLASH_AM320B:
220 printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
221 break;
222 case FLASH_AM320T:
223 printf ("AM29LV320T (32 Mbit, top boot sector)\n");
224 break;
225 case FLASH_28F640J3A:
226 printf ("28F640J3A (64 Mbit)\n");
227 break;
228 case FLASH_28F128J3A:
229 printf ("28F128J3A (128 Mbit)\n");
230 break;
231 case FLASH_ROM:
232 printf ("ROM\n");
233 break;
234 case FLASH_RAM:
235 printf ("RAM\n");
236 break;
237 default:
238 printf ("Unknown Chip Type\n");
239 break;
240 }
241
242 puts (" Size: ");
243 print_size (info->size, "");
244 printf (" in %d Sectors\n", info->sector_count);
245
246 printf (" Sector Start Addresses:");
247 for (i=0; i<info->sector_count; ++i) {
248 if ((i % 5) == 0)
249 printf ("\n ");
250 printf (" %08lX%s",
251 info->start[i],
252 info->protect[i] ? " (RO)" : " "
253 );
254 }
255 printf ("\n");
256 return;
257}
258
259/*-----------------------------------------------------------------------
260 */
261
262
263/*-----------------------------------------------------------------------
264 */
265
266/*
267 * The following code cannot be run from FLASH!
268 */
269
270static inline void flash_cmd(int width, volatile unsigned char *addr, int offset, unsigned char cmd)
271{
8bde7f77
WD
272 /* supports 1x8, 1x16, and 2x16 */
273 /* 2x8 and 4x8 are not supported */
7ebf7443
WD
274 if(width==4) {
275 /* assuming chips are in 16 bit mode */
276 /* 2x16 */
277 unsigned long cmd32=(cmd<<16)|cmd;
278 *(volatile unsigned long *)(addr+offset*2)=cmd32;
12f34241
WD
279 } else if (width == 2) {
280 /* 1x16 */
281 *(volatile unsigned short *)((unsigned short*)addr+offset)=cmd;
7ebf7443 282 } else {
12f34241 283 /* 1x8 */
7ebf7443
WD
284 *(volatile unsigned char *)(addr+offset)=cmd;
285 }
286}
287
288static ulong
289flash_get_size (int portwidth, vu_long *addr, flash_info_t *info)
290{
291 short i;
292 volatile unsigned char *caddr = (unsigned char *)addr;
293 volatile unsigned short *saddr = (unsigned short *)addr;
294 volatile unsigned long *laddr = (unsigned long *)addr;
295 char old[2], save;
296 ulong id, manu, base = (ulong)addr;
297
298 info->portwidth=portwidth;
299
300 save = *caddr;
301
302 flash_cmd(portwidth,caddr,0,0xf0);
303 flash_cmd(portwidth,caddr,0,0xf0);
304
305 udelay(10);
306
307 old[0] = caddr[0];
308 old[1] = caddr[1];
309
310
311 if(old[0]!=0xf0) {
312 flash_cmd(portwidth,caddr,0,0xf0);
313 flash_cmd(portwidth,caddr,0,0xf0);
314
315 udelay(10);
316
317 if(*caddr==0xf0) {
318 /* this area is ROM */
319 *caddr=save;
320#ifndef FLASH_ID_OVERRIDE
321 info->flash_id = FLASH_ROM + FLASH_MAN_UNKNOWN;
322 info->sector_count = 8;
323 info->size = 0x80000;
324#else
325 info->flash_id = FLASH_MAN_AMD + FLASH_AM040;
326 info->sector_count = 8;
327 info->size = 0x80000;
328 info->chipwidth=1;
329#endif
330 flash_get_offsets(base, info);
331 return info->size;
332 }
333 } else {
334 *caddr=0;
335
336 udelay(10);
337
338 if(*caddr==0) {
339 /* this area is RAM */
340 *caddr=save;
341 info->flash_id = FLASH_RAM + FLASH_MAN_UNKNOWN;
342 info->sector_count = 8;
343 info->size = 0x80000;
344 flash_get_offsets(base, info);
345 return info->size;
346 }
347 flash_cmd(portwidth,caddr,0,0xf0);
348
349 udelay(10);
350 }
351
352 /* Write auto select command: read Manufacturer ID */
353 flash_cmd(portwidth,caddr,0x555,0xAA);
354 flash_cmd(portwidth,caddr,0x2AA,0x55);
355 flash_cmd(portwidth,caddr,0x555,0x90);
356
357 udelay(10);
358
359 if ((caddr[0] == old[0]) &&
360 (caddr[1] == old[1])) {
361
362 /* this area is ROM */
363#ifndef FLASH_ID_OVERRIDE
364 info->flash_id = FLASH_ROM + FLASH_MAN_UNKNOWN;
365 info->sector_count = 8;
366 info->size = 0x80000;
367#else
368 info->flash_id = FLASH_MAN_AMD + FLASH_AM040;
369 info->sector_count = 8;
370 info->size = 0x80000;
371 info->chipwidth=1;
372#endif
373 flash_get_offsets(base, info);
374 return info->size;
375#ifdef DEBUG
376 } else {
377 printf("%px%d: %02x:%02x -> %02x:%02x\n",
378 caddr, portwidth, old[0], old[1],
379 caddr[0], caddr[1]);
380#endif
381 }
382
383 switch(portwidth) {
384 case 1:
385 manu = caddr[0];
386 manu |= manu<<16;
387 id = caddr[1];
388 break;
389 case 2:
390 manu = saddr[0];
391 manu |= manu<<16;
392 id = saddr[1];
393 id |= id<<16;
394 break;
395 case 4:
396 manu = laddr[0];
397 id = laddr[1];
398 break;
399 default:
400 id = manu = -1;
401 break;
402 }
403
404#ifdef DEBUG
405 printf("\n%08lx:%08lx:%08lx\n", base, manu, id);
406 printf("%08lx %08lx %08lx %08lx\n",
407 laddr[0],laddr[1],laddr[2],laddr[3]);
408#endif
409
410 switch (manu) {
411 case AMD_MANUFACT:
412 info->flash_id = FLASH_MAN_AMD;
413 break;
414 case FUJ_MANUFACT:
415 info->flash_id = FLASH_MAN_FUJ;
416 break;
417 case INTEL_MANUFACT:
418 info->flash_id = FLASH_MAN_INTEL;
419 break;
420 default:
421 printf("Unknown Mfr [%08lx]:%08lx\n", manu, id);
422 info->flash_id = FLASH_UNKNOWN;
423 info->sector_count = 0;
424 info->size = 0;
425 return (0); /* no or unknown flash */
426 }
427
428 switch (id) {
429 case AMD_ID_LV400T:
430 info->flash_id += FLASH_AM400T;
431 info->sector_count = 11;
432 info->size = 0x00100000;
433 info->chipwidth=1;
434 break; /* => 1 MB */
435
436 case AMD_ID_LV400B:
437 info->flash_id += FLASH_AM400B;
438 info->sector_count = 11;
439 info->size = 0x00100000;
440 info->chipwidth=1;
441 break; /* => 1 MB */
442
443 case AMD_ID_LV800T:
444 info->flash_id += FLASH_AM800T;
445 info->sector_count = 19;
446 info->size = 0x00200000;
447 info->chipwidth=1;
448 break; /* => 2 MB */
449
450 case AMD_ID_LV800B:
451 info->flash_id += FLASH_AM800B;
452 info->sector_count = 19;
453 info->size = 0x00200000;
454 info->chipwidth=1;
455 break; /* => 2 MB */
456
457 case AMD_ID_LV160T:
458 info->flash_id += FLASH_AM160T;
459 info->sector_count = 35;
460 info->size = 0x00400000;
461 info->chipwidth=1;
462 break; /* => 4 MB */
463
464 case AMD_ID_LV160B:
465 info->flash_id += FLASH_AM160B;
466 info->sector_count = 35;
467 info->size = 0x00400000;
468 info->chipwidth=1;
469 break; /* => 4 MB */
470#if 0 /* enable when device IDs are available */
471 case AMD_ID_LV320T:
472 info->flash_id += FLASH_AM320T;
473 info->sector_count = 67;
474 info->size = 0x00800000;
475 break; /* => 8 MB */
476
477 case AMD_ID_LV320B:
478 info->flash_id += FLASH_AM320B;
479 info->sector_count = 67;
480 info->size = 0x00800000;
481 break; /* => 8 MB */
482#endif
483 case AMD_ID_LV040B:
484 info->flash_id += FLASH_AM040;
485 info->sector_count = 8;
486 info->size = 0x80000;
487 info->chipwidth=1;
488 break;
489
490 case INTEL_ID_28F640J3A:
491 info->flash_id += FLASH_28F640J3A;
492 info->sector_count = 64;
493 info->size = 128*1024 * 64; /* 128kbytes x 64 blocks */
494 info->chipwidth=2;
495 if(portwidth==4) info->size*=2; /* 2x16 */
496 break;
497
498 case INTEL_ID_28F128J3A:
499 info->flash_id += FLASH_28F128J3A;
500 info->sector_count = 128;
501 info->size = 128*1024 * 128; /* 128kbytes x 128 blocks */
502 info->chipwidth=2;
503 if(portwidth==4) info->size*=2; /* 2x16 */
504 break;
505
506 default:
507 printf("Unknown id %lx:[%lx]\n", manu, id);
508 info->flash_id = FLASH_UNKNOWN;
509 info->chipwidth=1;
510 return (0); /* => no or unknown flash */
511
512 }
513
514 flash_get_offsets(base, info);
515
516#if 0
517 /* set up sector start address table */
518 if (info->flash_id & FLASH_AM040) {
519 /* this chip has uniformly spaced sectors */
520 for (i = 0; i < info->sector_count; i++)
521 info->start[i] = base + (i * 0x00010000);
522
523 } else if (info->flash_id & FLASH_BTYPE) {
524 /* set sector offsets for bottom boot block type */
525 info->start[0] = base + 0x00000000;
526 info->start[1] = base + 0x00008000;
527 info->start[2] = base + 0x0000C000;
528 info->start[3] = base + 0x00010000;
529 for (i = 4; i < info->sector_count; i++) {
530 info->start[i] = base + (i * 0x00020000) - 0x00060000;
531 }
532 } else {
533 /* set sector offsets for top boot block type */
534 i = info->sector_count - 1;
535 info->start[i--] = base + info->size - 0x00008000;
536 info->start[i--] = base + info->size - 0x0000C000;
537 info->start[i--] = base + info->size - 0x00010000;
538 for (; i >= 0; i--) {
539 info->start[i] = base + i * 0x00020000;
540 }
541 }
542#endif
543
544 /* check for protected sectors */
545 for (i = 0; i < info->sector_count; i++) {
546 /* read sector protection at sector address, (A7 .. A0)=0x02 */
547 /* D0 = 1 if protected */
548 caddr = (volatile unsigned char *)(info->start[i]);
549 saddr = (volatile unsigned short *)(info->start[i]);
550 laddr = (volatile unsigned long *)(info->start[i]);
551 if(portwidth==1)
552 info->protect[i] = caddr[2] & 1;
553 else if(portwidth==2)
554 info->protect[i] = saddr[2] & 1;
555 else
556 info->protect[i] = laddr[2] & 1;
557 }
558
559 /*
560 * Prevent writes to uninitialized FLASH.
561 */
562 if (info->flash_id != FLASH_UNKNOWN) {
563 caddr = (volatile unsigned char *)info->start[0];
564
565 flash_cmd(portwidth,caddr,0,0xF0); /* reset bank */
566 }
567
568 return (info->size);
569}
570
571/* TODO: 2x16 unsupported */
572int
573flash_erase (flash_info_t *info, int s_first, int s_last)
574{
77ddac94 575 volatile unsigned char *addr = (uchar *)(info->start[0]);
7ebf7443
WD
576 int flag, prot, sect, l_sect;
577 ulong start, now, last;
578
579 /* TODO: 2x16 unsupported */
580 if(info->portwidth==4) return 1;
581
582 if((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) return 1;
583 if((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) {
584 for (sect = s_first; sect<=s_last; sect++) {
585 int sector_size=info->size/info->sector_count;
77ddac94 586 addr = (uchar *)(info->start[sect]);
7ebf7443
WD
587 memset((void *)addr, 0, sector_size);
588 }
589 return 0;
590 }
591
592 if ((s_first < 0) || (s_first > s_last)) {
593 if (info->flash_id == FLASH_UNKNOWN) {
594 printf ("- missing\n");
595 } else {
596 printf ("- no sectors to erase\n");
597 }
598 return 1;
599 }
600
601 if ((info->flash_id&FLASH_VENDMASK) == FLASH_MAN_INTEL) {
602 return flash_erase_intel(info,
603 (unsigned short)s_first,
604 (unsigned short)s_last);
605 }
606
607#if 0
608 if ((info->flash_id == FLASH_UNKNOWN) ||
609 (info->flash_id > FLASH_AMD_COMP)) {
610 printf ("Can't erase unknown flash type %08lx - aborted\n",
611 info->flash_id);
612 return 1;
613 }
614#endif
615
616 prot = 0;
617 for (sect=s_first; sect<=s_last; ++sect) {
618 if (info->protect[sect]) {
619 prot++;
620 }
621 }
622
623 if (prot) {
624 printf ("- Warning: %d protected sectors will not be erased!\n",
625 prot);
626 } else {
627 printf ("\n");
628 }
629
630 l_sect = -1;
631
632 /* Disable interrupts which might cause a timeout here */
633 flag = disable_interrupts();
634
635 flash_cmd(info->portwidth,addr,0x555,0xAA);
636 flash_cmd(info->portwidth,addr,0x2AA,0x55);
637 flash_cmd(info->portwidth,addr,0x555,0x80);
638 flash_cmd(info->portwidth,addr,0x555,0xAA);
639 flash_cmd(info->portwidth,addr,0x2AA,0x55);
640
641 /* Start erase on unprotected sectors */
642 for (sect = s_first; sect<=s_last; sect++) {
643 if (info->protect[sect] == 0) { /* not protected */
77ddac94 644 addr = (uchar *)(info->start[sect]);
7ebf7443
WD
645 flash_cmd(info->portwidth,addr,0,0x30);
646 l_sect = sect;
647 }
648 }
649
650 /* re-enable interrupts if necessary */
651 if (flag)
652 enable_interrupts();
653
654 /* wait at least 80us - let's wait 1 ms */
655 udelay (1000);
656
657 /*
658 * We wait for the last triggered sector
659 */
660 if (l_sect < 0)
661 goto DONE;
662
663 start = get_timer (0);
664 last = start;
665 addr = (volatile unsigned char *)(info->start[l_sect]);
666 /* broken for 2x16: TODO */
667 while ((addr[0] & 0x80) != 0x80) {
6d0f6bcf 668 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
7ebf7443
WD
669 printf ("Timeout\n");
670 return 1;
671 }
672 /* show that we're waiting */
673 if ((now - last) > 1000) { /* every second */
674 putc ('.');
675 last = now;
676 }
677 }
678
679DONE:
680 /* reset to read mode */
681 addr = (volatile unsigned char *)info->start[0];
682 flash_cmd(info->portwidth,addr,0,0xf0);
683 flash_cmd(info->portwidth,addr,0,0xf0);
684
685 printf (" done\n");
686 return 0;
687}
688
689/*-----------------------------------------------------------------------
690 * Copy memory to flash, returns:
691 * 0 - OK
692 * 1 - write timeout
693 * 2 - Flash not erased
694 */
695
696/* broken for 2x16: TODO */
697int
698write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
699{
700 ulong cp, wp, data;
701 int i, l, rc;
702
703 if(info->portwidth==4) return 1;
704
705 if((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) return 0;
706 if((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) {
707 memcpy((void *)addr, src, cnt);
708 return 0;
709 }
710
711 wp = (addr & ~3); /* get lower word aligned address */
712
713 /*
714 * handle unaligned start bytes
715 */
716 if ((l = addr - wp) != 0) {
717 data = 0;
718 for (i=0, cp=wp; i<l; ++i, ++cp) {
719 data = (data << 8) | (*(uchar *)cp);
720 }
721 for (; i<4 && cnt>0; ++i) {
722 data = (data << 8) | *src++;
723 --cnt;
724 ++cp;
725 }
726 for (; cnt==0 && i<4; ++i, ++cp) {
727 data = (data << 8) | (*(uchar *)cp);
728 }
729
730 if ((rc = write_word(info, wp, data)) != 0) {
731 return (rc);
732 }
733 wp += 4;
734 }
735
736 /*
737 * handle word aligned part
738 */
739 while (cnt >= 4) {
740 data = 0;
741 for (i=0; i<4; ++i) {
742 data = (data << 8) | *src++;
743 }
744 if ((rc = write_word(info, wp, data)) != 0) {
745 return (rc);
746 }
747 wp += 4;
748 cnt -= 4;
749 }
750
751 if (cnt == 0) {
752 return (0);
753 }
754
755 /*
756 * handle unaligned tail bytes
757 */
758 data = 0;
759 for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
760 data = (data << 8) | *src++;
761 --cnt;
762 }
763 for (; i<4; ++i, ++cp) {
764 data = (data << 8) | (*(uchar *)cp);
765 }
766
767 return (write_word(info, wp, data));
768}
769
770/*-----------------------------------------------------------------------
771 * Write a word to Flash, returns:
772 * 0 - OK
773 * 1 - write timeout
774 * 2 - Flash not erased
775 */
776/* broken for 2x16: TODO */
777static int
778write_word (flash_info_t *info, ulong dest, ulong data)
779{
77ddac94 780 volatile unsigned char *addr = (uchar *)(info->start[0]);
7ebf7443
WD
781 ulong start;
782 int flag, i;
783
784 if(info->portwidth==4) return 1;
785
786 if((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) return 1;
787 if((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) {
788 *(unsigned long *)dest=data;
789 return 0;
790 }
791 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
792 unsigned short low = data & 0xffff;
793 unsigned short hi = (data >> 16) & 0xffff;
794 int ret = write_word_intel((bank_addr_t)dest, hi);
795
796 if (!ret) ret = write_word_intel((bank_addr_t)(dest+2), low);
797
798 return ret;
799 }
800
801 /* Check if Flash is (sufficiently) erased */
802 if ((*((vu_long *)dest) & data) != data) {
803 return (2);
804 }
805 /* Disable interrupts which might cause a timeout here */
806 flag = disable_interrupts();
807
808 /* first, perform an unlock bypass command to speed up flash writes */
809 addr[0x555] = 0xAA;
810 addr[0x2AA] = 0x55;
811 addr[0x555] = 0x20;
812
813 /* write each byte out */
814 for (i = 0; i < 4; i++) {
815 char *data_ch = (char *)&data;
816 addr[0] = 0xA0;
817 *(((char *)dest)+i) = data_ch[i];
818 udelay(10); /* XXX */
819 }
820
821 /* we're done, now do an unlock bypass reset */
822 addr[0] = 0x90;
823 addr[0] = 0x00;
824
825 /* re-enable interrupts if necessary */
826 if (flag)
827 enable_interrupts();
828
829 /* data polling for D7 */
830 start = get_timer (0);
831 while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
6d0f6bcf 832 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
7ebf7443
WD
833 return (1);
834 }
835 }
836 return (0);
837}