]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/emk/common/flash.c
rename CFG_ macros to CONFIG_SYS
[karo-tx-uboot.git] / board / emk / common / flash.c
1 /*
2  * (C) Copyright 2003
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * (C) Copyright 2003
6  * Reinhard Meyer, EMK Elektronik GmbH, r.meyer@emk-elektronik.de
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
29 flash_info_t    flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
30
31 #if defined (CONFIG_TOP860)
32   typedef unsigned short FLASH_PORT_WIDTH;
33   typedef volatile unsigned short FLASH_PORT_WIDTHV;
34   #define       FLASH_ID_MASK   0xFF
35
36   #define FPW   FLASH_PORT_WIDTH
37   #define FPWV  FLASH_PORT_WIDTHV
38
39   #define FLASH_CYCLE1  0x0555
40   #define FLASH_CYCLE2  0x02aa
41   #define FLASH_ID1             0
42   #define FLASH_ID2             1
43   #define FLASH_ID3             0x0e
44   #define FLASH_ID4             0x0F
45 #endif
46
47 #if defined (CONFIG_TOP5200) && !defined (CONFIG_LITE5200)
48   typedef unsigned char FLASH_PORT_WIDTH;
49   typedef volatile unsigned char FLASH_PORT_WIDTHV;
50   #define       FLASH_ID_MASK   0xFF
51
52   #define FPW   FLASH_PORT_WIDTH
53   #define FPWV  FLASH_PORT_WIDTHV
54
55   #define FLASH_CYCLE1  0x0aaa
56   #define FLASH_CYCLE2  0x0555
57   #define FLASH_ID1             0
58   #define FLASH_ID2             2
59   #define FLASH_ID3             0x1c
60   #define FLASH_ID4             0x1E
61 #endif
62
63 #if defined (CONFIG_TOP5200) && defined (CONFIG_LITE5200)
64   typedef unsigned char FLASH_PORT_WIDTH;
65   typedef volatile unsigned char FLASH_PORT_WIDTHV;
66   #define       FLASH_ID_MASK   0xFF
67
68   #define FPW   FLASH_PORT_WIDTH
69   #define FPWV  FLASH_PORT_WIDTHV
70
71   #define FLASH_CYCLE1  0x0555
72   #define FLASH_CYCLE2  0x02aa
73   #define FLASH_ID1             0
74   #define FLASH_ID2             1
75   #define FLASH_ID3             0x0E
76   #define FLASH_ID4             0x0F
77 #endif
78
79 /*-----------------------------------------------------------------------
80  * Functions
81  */
82 static ulong flash_get_size(FPWV *addr, flash_info_t *info);
83 static void flash_reset(flash_info_t *info);
84 static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
85 static flash_info_t *flash_get_info(ulong base);
86
87 /*-----------------------------------------------------------------------
88  * flash_init()
89  *
90  * sets up flash_info and returns size of FLASH (bytes)
91  */
92 unsigned long flash_init (void)
93 {
94         unsigned long size = 0;
95         int i = 0;
96         extern void flash_preinit(void);
97         extern void flash_afterinit(uint, ulong, ulong);
98         ulong flashbase = CONFIG_SYS_FLASH_BASE;
99
100         flash_preinit();
101
102         /* There is only ONE FLASH device */
103         memset(&flash_info[i], 0, sizeof(flash_info_t));
104         flash_info[i].size =
105                         flash_get_size((FPW *)flashbase, &flash_info[i]);
106         size += flash_info[i].size;
107
108 #if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
109         /* monitor protection ON by default */
110         flash_protect(FLAG_PROTECT_SET,
111                       CONFIG_SYS_MONITOR_BASE,
112                       CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
113                       flash_get_info(CONFIG_SYS_MONITOR_BASE));
114 #endif
115
116 #ifdef  CONFIG_ENV_IS_IN_FLASH
117         /* ENV protection ON by default */
118         flash_protect(FLAG_PROTECT_SET,
119                       CONFIG_ENV_ADDR,
120                       CONFIG_ENV_ADDR+CONFIG_ENV_SIZE-1,
121                       flash_get_info(CONFIG_ENV_ADDR));
122 #endif
123
124
125         flash_afterinit(i, flash_info[i].start[0], flash_info[i].size);
126         return size ? size : 1;
127 }
128
129 /*-----------------------------------------------------------------------
130  */
131 static void flash_reset(flash_info_t *info)
132 {
133         FPWV *base = (FPWV *)(info->start[0]);
134
135         /* Put FLASH back in read mode */
136         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
137                 *base = (FPW)0x00FF00FF;        /* Intel Read Mode */
138         else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
139                 *base = (FPW)0x00F000F0;        /* AMD Read Mode */
140 }
141
142 /*-----------------------------------------------------------------------
143  */
144
145 static flash_info_t *flash_get_info(ulong base)
146 {
147         int i;
148         flash_info_t * info;
149
150         for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i ++) {
151                 info = & flash_info[i];
152                 if (info->size &&
153                         info->start[0] <= base && base <= info->start[0] + info->size - 1)
154                         break;
155         }
156
157         return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
158 }
159
160 /*-----------------------------------------------------------------------
161  */
162
163 void flash_print_info (flash_info_t *info)
164 {
165         int i;
166         uchar *boottype;
167         uchar *bootletter;
168         char *fmt;
169         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 #if 0
182         case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
183         case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
184         case FLASH_MAN_SST:     printf ("SST ");                break;
185         case FLASH_MAN_STM:     printf ("STM ");                break;
186         case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
187 #endif
188         default:                printf ("Unknown Vendor ");     break;
189         }
190
191         /* check for top or bottom boot, if it applies */
192         if (info->flash_id & FLASH_BTYPE) {
193                 boottype = botboottype;
194                 bootletter = botbootletter;
195         }
196         else {
197                 boottype = topboottype;
198                 bootletter = topbootletter;
199         }
200
201         switch (info->flash_id & FLASH_TYPEMASK) {
202         case FLASH_AM160T:
203         case FLASH_AM160B:
204                 fmt = "29LV160%s (16 Mbit, %s)\n";
205                 break;
206         case FLASH_AMLV640U:
207                 fmt = "29LV640M (64 Mbit)\n";
208                 break;
209         case FLASH_AMDLV065D:
210                 fmt = "29LV065D (64 Mbit)\n";
211                 break;
212         case FLASH_AMLV256U:
213                 fmt = "29LV256M (256 Mbit)\n";
214                 break;
215         default:
216                 fmt = "Unknown Chip Type\n";
217                 break;
218         }
219
220         printf (fmt, bootletter, boottype);
221
222         printf ("  Size: %ld MB in %d Sectors\n",
223                 info->size >> 20,
224                 info->sector_count);
225
226         printf ("  Sector Start Addresses:");
227
228         for (i=0; i<info->sector_count; ++i) {
229                 ulong   size;
230                 int             erased;
231                 ulong   *flash = (unsigned long *) info->start[i];
232
233                 if ((i % 5) == 0) {
234                         printf ("\n   ");
235                 }
236
237                 /*
238                  * Check if whole sector is erased
239                  */
240                 size =
241                         (i != (info->sector_count - 1)) ?
242                         (info->start[i + 1] - info->start[i]) >> 2 :
243                 (info->start[0] + info->size - info->start[i]) >> 2;
244
245                 for (
246                         flash = (unsigned long *) info->start[i], erased = 1;
247                                 (flash != (unsigned long *) info->start[i] + size) && erased;
248                                         flash++
249                         )
250                         erased = *flash == ~0x0UL;
251
252                 printf (" %08lX %s %s",
253                         info->start[i],
254                         erased ? "E": " ",
255                         info->protect[i] ? "(RO)" : "    ");
256         }
257
258         printf ("\n");
259 }
260
261 /*-----------------------------------------------------------------------
262  */
263
264 /*
265  * The following code cannot be run from FLASH!
266  */
267
268 ulong flash_get_size (FPWV *addr, flash_info_t *info)
269 {
270         int             i;
271
272         /* Write auto select command: read Manufacturer ID */
273         /* Write auto select command sequence and test FLASH answer */
274         addr[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* for AMD, Intel ignores this */
275         addr[FLASH_CYCLE2] = (FPW)0x00550055;   /* for AMD, Intel ignores this */
276         addr[FLASH_CYCLE1] = (FPW)0x00900090;   /* selects Intel or AMD */
277
278         /* The manufacturer codes are only 1 byte, so just use 1 byte.
279          * This works for any bus width and any FLASH device width.
280          */
281         udelay(100);
282         switch (addr[FLASH_ID1] & 0xff) {
283
284         case (uchar)AMD_MANUFACT:
285                 info->flash_id = FLASH_MAN_AMD;
286                 break;
287
288 #if 0
289         case (uchar)INTEL_MANUFACT:
290                 info->flash_id = FLASH_MAN_INTEL;
291                 break;
292 #endif
293
294         default:
295                 printf ("unknown vendor=%x ", addr[FLASH_ID1] & 0xff);
296                 info->flash_id = FLASH_UNKNOWN;
297                 info->sector_count = 0;
298                 info->size = 0;
299                 break;
300         }
301
302         /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
303         if (info->flash_id != FLASH_UNKNOWN) switch ((FPW)addr[FLASH_ID2]) {
304
305         case (FPW)AMD_ID_LV160B:
306                 info->flash_id += FLASH_AM160B;
307                 info->sector_count = 35;
308                 info->size = 0x00200000;
309                 info->start[0] = (ulong)addr;
310                 info->start[1] = (ulong)addr + 0x4000;
311                 info->start[2] = (ulong)addr + 0x6000;
312                 info->start[3] = (ulong)addr + 0x8000;
313                 for (i = 4; i < info->sector_count; i++)
314                 {
315                         info->start[i] = (ulong)addr + 0x10000 * (i-3);
316                 }
317                 break;
318
319         case (FPW)AMD_ID_LV065D:
320                 info->flash_id += FLASH_AMDLV065D;
321                 info->sector_count = 128;
322                 info->size = 0x00800000;
323                 for (i = 0; i < info->sector_count; i++)
324                 {
325                         info->start[i] = (ulong)addr + 0x10000 * i;
326                 }
327                 break;
328
329         case (FPW)AMD_ID_MIRROR:
330                 /* MIRROR BIT FLASH, read more ID bytes */
331                 if ((FPW)addr[FLASH_ID3] == (FPW)AMD_ID_LV640U_2 &&
332                         (FPW)addr[FLASH_ID4] == (FPW)AMD_ID_LV640U_3)
333                 {
334                         info->flash_id += FLASH_AMLV640U;
335                         info->sector_count = 128;
336                         info->size = 0x00800000;
337                         for (i = 0; i < info->sector_count; i++)
338                         {
339                                 info->start[i] = (ulong)addr + 0x10000 * i;
340                         }
341                         break;
342                 }
343                 if ((FPW)addr[FLASH_ID3] == (FPW)AMD_ID_LV256U_2 &&
344                         (FPW)addr[FLASH_ID4] == (FPW)AMD_ID_LV256U_3)
345                 {
346                         /* attention: only the first 16 MB will be used in u-boot */
347                         info->flash_id += FLASH_AMLV256U;
348                         info->sector_count = 256;
349                         info->size = 0x01000000;
350                         for (i = 0; i < info->sector_count; i++)
351                         {
352                                 info->start[i] = (ulong)addr + 0x10000 * i;
353                         }
354                         break;
355                 }
356
357                 /* fall thru to here ! */
358         default:
359                 printf ("unknown AMD device=%x %x %x",
360                         (FPW)addr[FLASH_ID2],
361                         (FPW)addr[FLASH_ID3],
362                         (FPW)addr[FLASH_ID4]);
363                 info->flash_id = FLASH_UNKNOWN;
364                 info->sector_count = 0;
365                 info->size = 0x800000;
366                 break;
367         }
368
369         /* Put FLASH back in read mode */
370         flash_reset(info);
371
372         return (info->size);
373 }
374
375 /*-----------------------------------------------------------------------
376  */
377
378 int     flash_erase (flash_info_t *info, int s_first, int s_last)
379 {
380         FPWV *addr;
381         int flag, prot, sect;
382         int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
383         ulong start, now, last;
384         int rcode = 0;
385
386         if ((s_first < 0) || (s_first > s_last)) {
387                 if (info->flash_id == FLASH_UNKNOWN) {
388                         printf ("- missing\n");
389                 } else {
390                         printf ("- no sectors to erase\n");
391                 }
392                 return 1;
393         }
394
395         switch (info->flash_id & FLASH_TYPEMASK) {
396         case FLASH_AM160B:
397         case FLASH_AMLV640U:
398                 break;
399         case FLASH_UNKNOWN:
400         default:
401                 printf ("Can't erase unknown flash type %08lx - aborted\n",
402                         info->flash_id);
403                 return 1;
404         }
405
406         prot = 0;
407         for (sect=s_first; sect<=s_last; ++sect) {
408                 if (info->protect[sect]) {
409                         prot++;
410                 }
411         }
412
413         if (prot) {
414                 printf ("- Warning: %d protected sectors will not be erased!\n",
415                         prot);
416         } else {
417                 printf ("\n");
418         }
419
420         last  = get_timer(0);
421
422         /* Start erase on unprotected sectors */
423         for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
424
425                 if (info->protect[sect] != 0)   /* protected, skip it */
426                         continue;
427
428                 /* Disable interrupts which might cause a timeout here */
429                 flag = disable_interrupts();
430
431                 addr = (FPWV *)(info->start[sect]);
432                 if (intel) {
433                         *addr = (FPW)0x00500050; /* clear status register */
434                         *addr = (FPW)0x00200020; /* erase setup */
435                         *addr = (FPW)0x00D000D0; /* erase confirm */
436                 }
437                 else {
438                         /* must be AMD style if not Intel */
439                         FPWV *base;             /* first address in bank */
440
441                         base = (FPWV *)(info->start[0]);
442                         base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
443                         base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
444                         base[FLASH_CYCLE1] = (FPW)0x00800080;   /* erase mode */
445                         base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
446                         base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
447                         *addr = (FPW)0x00300030;        /* erase sector */
448                 }
449
450                 /* re-enable interrupts if necessary */
451                 if (flag)
452                         enable_interrupts();
453
454                 start = get_timer(0);
455
456                 /* wait at least 50us for AMD, 80us for Intel.
457                  * Let's wait 1 ms.
458                  */
459                 udelay (1000);
460
461                 while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
462                         if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
463                                 printf ("Timeout\n");
464
465                                 if (intel) {
466                                         /* suspend erase        */
467                                         *addr = (FPW)0x00B000B0;
468                                 }
469
470                                 flash_reset(info);      /* reset to read mode */
471                                 rcode = 1;              /* failed */
472                                 break;
473                         }
474
475                         /* show that we're waiting */
476                         if ((get_timer(last)) > CONFIG_SYS_HZ) {/* every second */
477                                 putc ('.');
478                                 last = get_timer(0);
479                         }
480                 }
481
482                 /* show that we're waiting */
483                 if ((get_timer(last)) > CONFIG_SYS_HZ) {        /* every second */
484                         putc ('.');
485                         last = get_timer(0);
486                 }
487
488                 flash_reset(info);      /* reset to read mode */
489         }
490
491         printf (" done\n");
492         return rcode;
493 }
494
495 /*-----------------------------------------------------------------------
496  * Copy memory to flash, returns:
497  * 0 - OK
498  * 1 - write timeout
499  * 2 - Flash not erased
500  */
501 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
502 {
503         FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
504         int bytes;        /* number of bytes to program in current word         */
505         int left;         /* number of bytes left to program                    */
506         int i, res;
507
508         for (left = cnt, res = 0;
509                  left > 0 && res == 0;
510                  addr += sizeof(data), left -= sizeof(data) - bytes) {
511
512                 bytes = addr & (sizeof(data) - 1);
513                 addr &= ~(sizeof(data) - 1);
514
515                 /* combine source and destination data so can program
516                  * an entire word of 16 or 32 bits
517                  */
518                 for (i = 0; i < sizeof(data); i++) {
519                         data <<= 8;
520                         if (i < bytes || i - bytes >= left )
521                                 data += *((uchar *)addr + i);
522                         else
523                                 data += *src++;
524                 }
525
526                 /* write one word to the flash */
527                 switch (info->flash_id & FLASH_VENDMASK) {
528                 case FLASH_MAN_AMD:
529                         res = write_word_amd(info, (FPWV *)addr, data);
530                         break;
531                 default:
532                         /* unknown flash type, error! */
533                         printf ("missing or unknown FLASH type\n");
534                         res = 1;        /* not really a timeout, but gives error */
535                         break;
536                 }
537         }
538
539         return (res);
540 }
541
542 /*-----------------------------------------------------------------------
543  * Write a word to Flash for AMD FLASH
544  * A word is 16 or 32 bits, whichever the bus width of the flash bank
545  * (not an individual chip) is.
546  *
547  * returns:
548  * 0 - OK
549  * 1 - write timeout
550  * 2 - Flash not erased
551  */
552 static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
553 {
554         ulong start;
555         int flag;
556         int res = 0;    /* result, assume success       */
557         FPWV *base;             /* first address in flash bank  */
558
559         /* Check if Flash is (sufficiently) erased */
560         if ((*dest & data) != data) {
561                 return (2);
562         }
563
564
565         base = (FPWV *)(info->start[0]);
566
567         /* Disable interrupts which might cause a timeout here */
568         flag = disable_interrupts();
569
570         base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
571         base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
572         base[FLASH_CYCLE1] = (FPW)0x00A000A0;   /* selects program mode */
573
574         *dest = data;           /* start programming the data   */
575
576         /* re-enable interrupts if necessary */
577         if (flag)
578                 enable_interrupts();
579
580         start = get_timer (0);
581
582         /* data polling for D7 */
583         while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
584                 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
585                         *dest = (FPW)0x00F000F0;        /* reset bank */
586                         res = 1;
587                 }
588         }
589
590         return (res);
591 }