blob: 8135780c54dbfce5be3be45decce9138d835574a [file] [log] [blame]
wdenkcc1c8a12002-11-02 22:58:18 +00001/*
2 * (C) Copyright 2001, 2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * Flash Routines for Intel devices
6 *
7 *--------------------------------------------------------------------
8 * See file CREDITS for list of people who contributed to this
9 * project.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
25 */
26
27#include <common.h>
28#include <mpc8xx.h>
29#include "cpu86.h"
30
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020031flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
wdenkcc1c8a12002-11-02 22:58:18 +000032
33/*-----------------------------------------------------------------------
34 */
35ulong flash_int_get_size (volatile unsigned long *baseaddr,
36 flash_info_t * info)
37{
38 short i;
39 unsigned long flashtest_h, flashtest_l;
40
41 info->sector_count = info->size = 0;
42 info->flash_id = FLASH_UNKNOWN;
43
wdenkefa329c2004-03-23 20:18:25 +000044 /* Write identify command sequence and test FLASH answer
wdenkcc1c8a12002-11-02 22:58:18 +000045 */
wdenkefa329c2004-03-23 20:18:25 +000046 baseaddr[0] = 0x00900090;
47 baseaddr[1] = 0x00900090;
wdenkcc1c8a12002-11-02 22:58:18 +000048
49 flashtest_h = baseaddr[0]; /* manufacturer ID */
50 flashtest_l = baseaddr[1];
51
52 if (flashtest_h != INTEL_MANUFACT || flashtest_l != INTEL_MANUFACT)
53 return (0); /* no or unknown flash */
54
55 flashtest_h = baseaddr[2]; /* device ID */
56 flashtest_l = baseaddr[3];
57
58 if (flashtest_h != flashtest_l)
59 return (0);
60
61 switch (flashtest_h) {
62 case INTEL_ID_28F160C3B:
63 info->flash_id = FLASH_28F160C3B;
64 info->sector_count = 39;
65 info->size = 0x00800000; /* 4 * 2 MB = 8 MB */
66 break;
67 case INTEL_ID_28F160F3B:
68 info->flash_id = FLASH_28F160F3B;
69 info->sector_count = 39;
70 info->size = 0x00800000; /* 4 * 2 MB = 8 MB */
71 break;
72 default:
73 return (0); /* no or unknown flash */
74 }
75
76 info->flash_id |= INTEL_MANUFACT << 16; /* set manufacturer offset */
77
78 if (info->flash_id & FLASH_BTYPE) {
79 volatile unsigned long *tmp = baseaddr;
80
81 /* set up sector start adress table (bottom sector type)
82 * AND unlock the sectors (if our chip is 160C3)
83 */
84 for (i = 0; i < info->sector_count; i++) {
85 if ((info->flash_id & FLASH_TYPEMASK) == FLASH_28F160C3B) {
86 tmp[0] = 0x00600060;
87 tmp[1] = 0x00600060;
88 tmp[0] = 0x00D000D0;
89 tmp[1] = 0x00D000D0;
90 }
91 info->start[i] = (uint) tmp;
92 tmp += i < 8 ? 0x2000 : 0x10000; /* pointer arith */
93 }
94 }
95
96 memset (info->protect, 0, info->sector_count);
97
98 baseaddr[0] = 0x00FF00FF;
99 baseaddr[1] = 0x00FF00FF;
100
101 return (info->size);
102}
103
104static ulong flash_amd_get_size (vu_char *addr, flash_info_t *info)
105{
106 short i;
107 uchar vendor, devid;
108 ulong base = (ulong)addr;
109
110 /* Write auto select command: read Manufacturer ID */
111 addr[0x0555] = 0xAA;
112 addr[0x02AA] = 0x55;
113 addr[0x0555] = 0x90;
114
115 udelay(1000);
116
117 vendor = addr[0];
118 devid = addr[1] & 0xff;
119
120 /* only support AMD */
121 if (vendor != 0x01) {
122 return 0;
123 }
124
125 vendor &= 0xf;
126 devid &= 0xff;
127
128 if (devid == AMD_ID_F040B) {
129 info->flash_id = vendor << 16 | devid;
130 info->sector_count = 8;
131 info->size = info->sector_count * 0x10000;
132 }
133 else if (devid == AMD_ID_F080B) {
134 info->flash_id = vendor << 16 | devid;
135 info->sector_count = 16;
136 info->size = 4 * info->sector_count * 0x10000;
137 }
138 else if (devid == AMD_ID_F016D) {
139 info->flash_id = vendor << 16 | devid;
140 info->sector_count = 32;
141 info->size = 4 * info->sector_count * 0x10000;
142 }
143 else {
144 printf ("## Unknown Flash Type: %02x\n", devid);
145 return 0;
146 }
147
148 /* check for protected sectors */
149 for (i = 0; i < info->sector_count; i++) {
150 /* sector base address */
151 info->start[i] = base + i * (info->size / info->sector_count);
152 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
153 /* D0 = 1 if protected */
154 addr = (volatile unsigned char *)(info->start[i]);
155 info->protect[i] = addr[2] & 1;
156 }
157
158 /*
159 * Prevent writes to uninitialized FLASH.
160 */
161 if (info->flash_id != FLASH_UNKNOWN) {
162 addr = (vu_char *)info->start[0];
163 addr[0] = 0xF0; /* reset bank */
164 }
165
166 return (info->size);
167}
168
169
170/*-----------------------------------------------------------------------
171 */
172unsigned long flash_init (void)
173{
174 unsigned long size_b0 = 0;
175 unsigned long size_b1 = 0;
176 int i;
177
178 /* Init: no FLASHes known
179 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200180 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenkcc1c8a12002-11-02 22:58:18 +0000181 flash_info[i].flash_id = FLASH_UNKNOWN;
182 }
183
184 /* Disable flash protection */
185 CPU86_BCR |= (CPU86_BCR_FWPT | CPU86_BCR_FWRE);
186
187 /* Static FLASH Bank configuration here (only one bank) */
188
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200189 size_b0 = flash_int_get_size ((ulong *) CONFIG_SYS_FLASH_BASE, &flash_info[0]);
190 size_b1 = flash_amd_get_size ((uchar *) CONFIG_SYS_BOOTROM_BASE, &flash_info[1]);
wdenkcc1c8a12002-11-02 22:58:18 +0000191
192 if (size_b0 > 0 || size_b1 > 0) {
193
194 printf("(");
195
196 if (size_b0 > 0) {
197 puts ("Bank#1 - ");
198 print_size (size_b0, (size_b1 > 0) ? ", " : ") ");
199 }
200
201 if (size_b1 > 0) {
202 puts ("Bank#2 - ");
203 print_size (size_b1, ") ");
204 }
205 }
206 else {
207 printf ("## No FLASH found.\n");
208 return 0;
209 }
210 /* protect monitor and environment sectors
211 */
212
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200213#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_BOOTROM_BASE
wdenkcc1c8a12002-11-02 22:58:18 +0000214 if (size_b1) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200215 /* If U-Boot is booted from ROM the CONFIG_SYS_MONITOR_BASE > CONFIG_SYS_FLASH_BASE
wdenkcc1c8a12002-11-02 22:58:18 +0000216 * but we shouldn't protect it.
217 */
218
219 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200220 CONFIG_SYS_MONITOR_BASE,
221 CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, &flash_info[1]
wdenkcc1c8a12002-11-02 22:58:18 +0000222 );
223 }
224#else
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200225#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
wdenkcc1c8a12002-11-02 22:58:18 +0000226 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200227 CONFIG_SYS_MONITOR_BASE,
228 CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, &flash_info[0]
wdenkcc1c8a12002-11-02 22:58:18 +0000229 );
230#endif
231#endif
232
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200233#if defined(CONFIG_ENV_IS_IN_FLASH) && defined(CONFIG_ENV_ADDR)
234# ifndef CONFIG_ENV_SIZE
235# define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE
wdenkcc1c8a12002-11-02 22:58:18 +0000236# endif
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200237# if CONFIG_ENV_ADDR >= CONFIG_SYS_BOOTROM_BASE
wdenkcc1c8a12002-11-02 22:58:18 +0000238 if (size_b1) {
239 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200240 CONFIG_ENV_ADDR,
241 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[1]);
wdenkcc1c8a12002-11-02 22:58:18 +0000242 }
243# else
244 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200245 CONFIG_ENV_ADDR,
246 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
wdenkcc1c8a12002-11-02 22:58:18 +0000247# endif
248#endif
249
250 return (size_b0 + size_b1);
251}
252
253/*-----------------------------------------------------------------------
254 */
255void flash_print_info (flash_info_t * info)
256{
257 int i;
258
259 if (info->flash_id == FLASH_UNKNOWN) {
260 printf ("missing or unknown FLASH type\n");
261 return;
262 }
263
264 switch ((info->flash_id >> 16) & 0xff) {
265 case 0x89:
266 printf ("INTEL ");
267 break;
268 case 0x1:
269 printf ("AMD ");
270 break;
271 default:
272 printf ("Unknown Vendor ");
273 break;
274 }
275
276 switch (info->flash_id & FLASH_TYPEMASK) {
277 case FLASH_28F160C3B:
278 printf ("28F160C3B (16 Mbit, bottom sector)\n");
279 break;
280 case FLASH_28F160F3B:
281 printf ("28F160F3B (16 Mbit, bottom sector)\n");
282 break;
283 case AMD_ID_F040B:
284 printf ("AM29F040B (4 Mbit)\n");
285 break;
286 default:
287 printf ("Unknown Chip Type\n");
288 break;
289 }
290
291 if (info->size < 0x100000)
292 printf (" Size: %ld KB in %d Sectors\n",
293 info->size >> 10, info->sector_count);
294 else
295 printf (" Size: %ld MB in %d Sectors\n",
296 info->size >> 20, info->sector_count);
297
298 printf (" Sector Start Addresses:");
299 for (i = 0; i < info->sector_count; ++i) {
300 if ((i % 5) == 0)
301 printf ("\n ");
302 printf (" %08lX%s",
303 info->start[i],
304 info->protect[i] ? " (RO)" : " "
305 );
306 }
307 printf ("\n");
308}
309
310/*-----------------------------------------------------------------------
311 */
312int flash_erase (flash_info_t * info, int s_first, int s_last)
313{
314 vu_char *addr = (vu_char *)(info->start[0]);
315 int flag, prot, sect, l_sect;
316 ulong start, now, last;
317
318 if ((s_first < 0) || (s_first > s_last)) {
319 if (info->flash_id == FLASH_UNKNOWN) {
320 printf ("- missing\n");
321 } else {
322 printf ("- no sectors to erase\n");
323 }
324 return 1;
325 }
326
327 prot = 0;
328 for (sect = s_first; sect <= s_last; sect++) {
329 if (info->protect[sect])
330 prot++;
331 }
332
333 if (prot) {
334 printf ("- Warning: %d protected sectors will not be erased!\n",
335 prot);
336 } else {
337 printf ("\n");
338 }
339
340 /* Check the type of erased flash
341 */
342 if (info->flash_id >> 16 == 0x1) {
343 /* Erase AMD flash
344 */
345 l_sect = -1;
346
347 /* Disable interrupts which might cause a timeout here */
348 flag = disable_interrupts();
349
350 addr[0x0555] = 0xAA;
351 addr[0x02AA] = 0x55;
352 addr[0x0555] = 0x80;
353 addr[0x0555] = 0xAA;
354 addr[0x02AA] = 0x55;
355
356 /* wait at least 80us - let's wait 1 ms */
357 udelay (1000);
358
359 /* Start erase on unprotected sectors */
360 for (sect = s_first; sect<=s_last; sect++) {
361 if (info->protect[sect] == 0) { /* not protected */
362 addr = (vu_char *)(info->start[sect]);
363 addr[0] = 0x30;
364 l_sect = sect;
365 }
366 }
367
368 /* re-enable interrupts if necessary */
369 if (flag)
370 enable_interrupts();
371
372 /* wait at least 80us - let's wait 1 ms */
373 udelay (1000);
374
375 /*
376 * We wait for the last triggered sector
377 */
378 if (l_sect < 0)
379 goto AMD_DONE;
380
381 start = get_timer (0);
382 last = start;
383 addr = (vu_char *)(info->start[l_sect]);
384 while ((addr[0] & 0x80) != 0x80) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200385 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenkcc1c8a12002-11-02 22:58:18 +0000386 printf ("Timeout\n");
387 return 1;
388 }
389 /* show that we're waiting */
390 if ((now - last) > 1000) { /* every second */
391 serial_putc ('.');
392 last = now;
393 }
394 }
395
396AMD_DONE:
397 /* reset to read mode */
398 addr = (volatile unsigned char *)info->start[0];
399 addr[0] = 0xF0; /* reset bank */
400
401 } else {
402 /* Erase Intel flash
403 */
404
405 /* Start erase on unprotected sectors
406 */
407 for (sect = s_first; sect <= s_last; sect++) {
408 volatile ulong *addr =
409 (volatile unsigned long *) info->start[sect];
410
411 start = get_timer (0);
412 last = start;
413 if (info->protect[sect] == 0) {
414 /* Disable interrupts which might cause a timeout here
415 */
416 flag = disable_interrupts ();
417
418 /* Erase the block
419 */
420 addr[0] = 0x00200020;
421 addr[1] = 0x00200020;
422 addr[0] = 0x00D000D0;
423 addr[1] = 0x00D000D0;
424
425 /* re-enable interrupts if necessary
426 */
427 if (flag)
428 enable_interrupts ();
429
430 /* wait at least 80us - let's wait 1 ms
431 */
432 udelay (1000);
433
434 last = start;
435 while ((addr[0] & 0x00800080) != 0x00800080 ||
436 (addr[1] & 0x00800080) != 0x00800080) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200437 if ((now = get_timer (start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenkcc1c8a12002-11-02 22:58:18 +0000438 printf ("Timeout (erase suspended!)\n");
439 /* Suspend erase
440 */
441 addr[0] = 0x00B000B0;
442 addr[1] = 0x00B000B0;
443 goto DONE;
444 }
445 /* show that we're waiting
446 */
447 if ((now - last) > 1000) { /* every second */
448 serial_putc ('.');
449 last = now;
450 }
451 }
452 if (addr[0] & 0x00220022 || addr[1] & 0x00220022) {
453 printf ("*** ERROR: erase failed!\n");
454 goto DONE;
455 }
456 }
457 /* Clear status register and reset to read mode
458 */
459 addr[0] = 0x00500050;
460 addr[1] = 0x00500050;
461 addr[0] = 0x00FF00FF;
462 addr[1] = 0x00FF00FF;
463 }
464 }
465
466 printf (" done\n");
467
468DONE:
469 return 0;
470}
471
472static int write_word (flash_info_t *, volatile unsigned long *, ulong);
473static int write_byte (flash_info_t *info, ulong dest, uchar data);
474
475/*-----------------------------------------------------------------------
476 * Copy memory to flash, returns:
477 * 0 - OK
478 * 1 - write timeout
479 * 2 - Flash not erased
480 */
481int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
482{
483 ulong v;
484 int i, l, rc, cc = cnt, res = 0;
485
486 if (info->flash_id >> 16 == 0x1) {
487
488 /* Write to AMD 8-bit flash
489 */
490 while (cnt > 0) {
491 if ((rc = write_byte(info, addr, *src)) != 0) {
492 return (rc);
493 }
494 addr++;
495 src++;
496 cnt--;
497 }
498
499 return (0);
500 } else {
501
502 /* Write to Intel 64-bit flash
503 */
504 for (v=0; cc > 0; addr += 4, cc -= 4 - l) {
505 l = (addr & 3);
506 addr &= ~3;
507
508 for (i = 0; i < 4; i++) {
509 v = (v << 8) + (i < l || i - l >= cc ?
510 *((unsigned char *) addr + i) : *src++);
511 }
512
513 if ((res = write_word (info, (volatile unsigned long *) addr, v)) != 0)
514 break;
515 }
516 }
517
518 return (res);
519}
520
521/*-----------------------------------------------------------------------
522 * Write a word to Flash, returns:
523 * 0 - OK
524 * 1 - write timeout
525 * 2 - Flash not erased
526 */
527static int write_word (flash_info_t * info, volatile unsigned long *addr,
528 ulong data)
529{
530 int flag, res = 0;
531 ulong start;
532
533 /* Check if Flash is (sufficiently) erased
534 */
535 if ((*addr & data) != data)
536 return (2);
537
538 /* Disable interrupts which might cause a timeout here
539 */
540 flag = disable_interrupts ();
541
542 *addr = 0x00400040;
543 *addr = data;
544
545 /* re-enable interrupts if necessary
546 */
547 if (flag)
548 enable_interrupts ();
549
550 start = get_timer (0);
551 while ((*addr & 0x00800080) != 0x00800080) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200552 if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenkcc1c8a12002-11-02 22:58:18 +0000553 /* Suspend program
554 */
555 *addr = 0x00B000B0;
556 res = 1;
557 goto OUT;
558 }
559 }
560
561 if (*addr & 0x00220022) {
562 printf ("*** ERROR: program failed!\n");
563 res = 1;
564 }
565
566OUT:
567 /* Clear status register and reset to read mode
568 */
569 *addr = 0x00500050;
570 *addr = 0x00FF00FF;
571
572 return (res);
573}
574
575/*-----------------------------------------------------------------------
576 * Write a byte to Flash, returns:
577 * 0 - OK
578 * 1 - write timeout
579 * 2 - Flash not erased
580 */
581static int write_byte (flash_info_t *info, ulong dest, uchar data)
582{
583 vu_char *addr = (vu_char *)(info->start[0]);
584 ulong start;
585 int flag;
586
587 /* Check if Flash is (sufficiently) erased */
588 if ((*((vu_char *)dest) & data) != data) {
589 return (2);
590 }
591 /* Disable interrupts which might cause a timeout here */
592 flag = disable_interrupts();
593
594 addr[0x0555] = 0xAA;
595 addr[0x02AA] = 0x55;
596 addr[0x0555] = 0xA0;
597
598 *((vu_char *)dest) = data;
599
600 /* re-enable interrupts if necessary */
601 if (flag)
602 enable_interrupts();
603
604 /* data polling for D7 */
605 start = get_timer (0);
606 while ((*((vu_char *)dest) & 0x80) != (data & 0x80)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200607 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenkcc1c8a12002-11-02 22:58:18 +0000608 return (1);
609 }
610 }
611 return (0);
612}
613
614/*-----------------------------------------------------------------------
615 */