]> git.sur5r.net Git - u-boot/blob - board/emk/top5200/flash.c
b951b5f084576293b3aae4f59572ebf30435aab4
[u-boot] / board / emk / top5200 / flash.c
1 /*
2  * (C) Copyright 2003
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
26 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
27
28 typedef unsigned char FLASH_PORT_WIDTH;
29 typedef volatile unsigned char FLASH_PORT_WIDTHV;
30 #define FLASH_ID_MASK   0xFF
31
32 #define FPW     FLASH_PORT_WIDTH
33 #define FPWV    FLASH_PORT_WIDTHV
34
35 #define FLASH_CYCLE1    0x0aaa
36 #define FLASH_CYCLE2    0x0555
37
38 /*-----------------------------------------------------------------------
39  * Functions
40  */
41 static ulong flash_get_size(FPWV *addr, flash_info_t *info);
42 static void flash_reset(flash_info_t *info);
43 static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
44 static flash_info_t *flash_get_info(ulong base);
45
46 /*-----------------------------------------------------------------------
47  * flash_init()
48  *
49  * sets up flash_info and returns size of FLASH (bytes)
50  */
51 unsigned long flash_init (void)
52 {
53         unsigned long size = 0;
54         int i;
55         extern void flash_preinit(void);
56         extern void flash_afterinit(uint, ulong, ulong);
57         ulong flashbase = CFG_FLASH_BASE;
58
59         flash_preinit();
60
61         /* There is only ONE FLASH device */
62         memset(&flash_info[0], 0, sizeof(flash_info_t));
63         flash_info[0].size =
64                         flash_get_size((FPW *)flashbase, &flash_info[0]);
65         size += flash_info[0].size;
66
67 #if CFG_MONITOR_BASE >= CFG_FLASH_BASE
68         /* monitor protection ON by default */
69         flash_protect(FLAG_PROTECT_SET,
70                       CFG_MONITOR_BASE,
71                       CFG_MONITOR_BASE+monitor_flash_len-1,
72                       flash_get_info(CFG_MONITOR_BASE));
73 #endif
74
75 #ifdef  CFG_ENV_IS_IN_FLASH
76         /* ENV protection ON by default */
77         flash_protect(FLAG_PROTECT_SET,
78                       CFG_ENV_ADDR,
79                       CFG_ENV_ADDR+CFG_ENV_SIZE-1,
80                       flash_get_info(CFG_ENV_ADDR));
81 #endif
82
83
84         flash_afterinit(0, flash_info[0].start[0], flash_info[0].size);
85         return size ? size : 1;
86 }
87
88 /*-----------------------------------------------------------------------
89  */
90 static void flash_reset(flash_info_t *info)
91 {
92         FPWV *base = (FPWV *)(info->start[0]);
93
94         /* Put FLASH back in read mode */
95         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
96                 *base = (FPW)0x00FF00FF;        /* Intel Read Mode */
97         else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
98                 *base = (FPW)0x00F000F0;        /* AMD Read Mode */
99 }
100
101 /*-----------------------------------------------------------------------
102  */
103
104 static flash_info_t *flash_get_info(ulong base)
105 {
106         int i;
107         flash_info_t * info;
108
109         for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) {
110                 info = & flash_info[i];
111                 if (info->size &&
112                         info->start[0] <= base && base <= info->start[0] + info->size - 1)
113                         break;
114         }
115
116         return i == CFG_MAX_FLASH_BANKS ? 0 : info;
117 }
118
119 /*-----------------------------------------------------------------------
120  */
121
122 void flash_print_info (flash_info_t *info)
123 {
124         int i;
125         uchar *boottype;
126         uchar *bootletter;
127         uchar *fmt;
128         uchar botbootletter[] = "B";
129         uchar topbootletter[] = "T";
130         uchar botboottype[] = "bottom boot sector";
131         uchar topboottype[] = "top boot sector";
132
133         if (info->flash_id == FLASH_UNKNOWN) {
134                 printf ("missing or unknown FLASH type\n");
135                 return;
136         }
137
138         switch (info->flash_id & FLASH_VENDMASK) {
139         case FLASH_MAN_AMD:     printf ("AMD ");                break;
140 #if 0
141         case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
142         case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
143         case FLASH_MAN_SST:     printf ("SST ");                break;
144         case FLASH_MAN_STM:     printf ("STM ");                break;
145         case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
146 #endif
147         default:                printf ("Unknown Vendor ");     break;
148         }
149
150         /* check for top or bottom boot, if it applies */
151         if (info->flash_id & FLASH_BTYPE) {
152                 boottype = botboottype;
153                 bootletter = botbootletter;
154         } else {
155                 boottype = topboottype;
156                 bootletter = topbootletter;
157         }
158
159         switch (info->flash_id & FLASH_TYPEMASK) {
160         case FLASH_AM160T:
161         case FLASH_AM160B:
162                 fmt = "29LV160%s (16 Mbit, %s)\n";
163                 break;
164         case FLASH_AMDLV065D:
165                 fmt = "29LV065 (64 Mbit, uniform sectors)\n";
166                 break;
167         default:
168                 fmt = "Unknown Chip Type\n";
169                 break;
170         }
171
172         printf (fmt, bootletter, boottype);
173
174         printf ("  Size: %ld MB in %d Sectors\n",
175                 info->size >> 20,
176                 info->sector_count);
177
178         printf ("  Sector Start Addresses:");
179
180         for (i=0; i<info->sector_count; ++i) {
181                 if ((i % 5) == 0) {
182                         printf ("\n   ");
183                 }
184
185                 printf (" %08lX%s", info->start[i],
186                         info->protect[i] ? " (RO)" : "     ");
187         }
188
189         printf ("\n");
190 }
191
192 /*-----------------------------------------------------------------------
193  */
194
195 /*
196  * The following code cannot be run from FLASH!
197  */
198
199 ulong flash_get_size (FPWV *addr, flash_info_t *info)
200 {
201         int             i;
202         ulong   offset;
203
204         /* Write auto select command: read Manufacturer ID */
205         /* Write auto select command sequence and test FLASH answer */
206         addr[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* for AMD, Intel ignores this */
207         addr[FLASH_CYCLE2] = (FPW)0x00550055;   /* for AMD, Intel ignores this */
208         addr[FLASH_CYCLE1] = (FPW)0x00900090;   /* selects Intel or AMD */
209
210         /* The manufacturer codes are only 1 byte, so just use 1 byte.
211          * This works for any bus width and any FLASH device width.
212          */
213         udelay(100);
214         switch (addr[0] & 0xff) {
215
216         case (uchar)AMD_MANUFACT:
217                 info->flash_id = FLASH_MAN_AMD;
218                 break;
219
220 #if 0
221         case (uchar)INTEL_MANUFACT:
222                 info->flash_id = FLASH_MAN_INTEL;
223                 break;
224 #endif
225
226         default:
227                 printf ("unknown vendor=%x ", addr[0] & 0xff);
228                 info->flash_id = FLASH_UNKNOWN;
229                 info->sector_count = 0;
230                 info->size = 0;
231                 break;
232         }
233
234         /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
235         if (info->flash_id != FLASH_UNKNOWN) switch ((FPW)addr[2]) {
236
237         case (FPW)AMD_ID_LV160B:
238                 info->flash_id += FLASH_AM160B;
239                 info->sector_count = 35;
240                 info->size = 0x00200000;
241                 offset = 0x00e00000;
242                 info->start[0] = (ulong)addr + offset;
243                 info->start[1] = (ulong)addr + offset + 0x4000;
244                 info->start[2] = (ulong)addr + offset + 0x6000;
245                 info->start[3] = (ulong)addr + offset + 0x8000;
246                 for (i = 4; i < info->sector_count; i++) {
247                         info->start[i] = (ulong)addr + offset + 0x10000 * (i-3);
248                 }
249                 break;
250
251         case (FPW)AMD_ID_LV065D:
252                 info->flash_id += FLASH_AMDLV065D;
253                 info->sector_count = 128;
254                 info->size = 0x00800000;
255                 offset = 0x00800000;
256                 for (i = 0; i < info->sector_count; i++)
257                         info->start[i] = (ulong)addr + offset + (i * 0x10000);
258                 break;                          /* => 8 or 16 MB        */
259
260         default:
261                 printf ("unknown AMD device=%x ", (FPW)addr[2]);
262                 info->flash_id = FLASH_UNKNOWN;
263                 info->sector_count = 0;
264                 info->size = 0;
265                 return (0);                     /* => no or unknown flash */
266         }
267
268         /* Put FLASH back in read mode */
269         flash_reset(info);
270
271         return (info->size);
272 }
273
274 /*-----------------------------------------------------------------------
275  */
276
277 int     flash_erase (flash_info_t *info, int s_first, int s_last)
278 {
279         FPWV *addr;
280         int flag, prot, sect;
281         int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
282         ulong start, now, last;
283         int rcode = 0;
284
285         if ((s_first < 0) || (s_first > s_last)) {
286                 if (info->flash_id == FLASH_UNKNOWN) {
287                         printf ("- missing\n");
288                 } else {
289                         printf ("- no sectors to erase\n");
290                 }
291                 return 1;
292         }
293
294         switch (info->flash_id & FLASH_TYPEMASK) {
295         case FLASH_AMDLV065D:
296                 break;
297         case FLASH_UNKNOWN:
298         default:
299                 printf ("Can't erase unknown flash type %08lx - aborted\n",
300                         info->flash_id);
301                 return 1;
302         }
303
304         prot = 0;
305         for (sect=s_first; sect<=s_last; ++sect) {
306                 if (info->protect[sect]) {
307                         prot++;
308                 }
309         }
310
311         if (prot) {
312                 printf ("- Warning: %d protected sectors will not be erased!\n",
313                         prot);
314         } else {
315                 printf ("\n");
316         }
317
318         last  = get_timer(0);
319
320         /* Start erase on unprotected sectors */
321         for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
322
323                 if (info->protect[sect] != 0)   /* protected, skip it */
324                         continue;
325
326                 /* Disable interrupts which might cause a timeout here */
327                 flag = disable_interrupts();
328
329                 addr = (FPWV *)(info->start[sect]);
330                 if (intel) {
331                         *addr = (FPW)0x00500050; /* clear status register */
332                         *addr = (FPW)0x00200020; /* erase setup */
333                         *addr = (FPW)0x00D000D0; /* erase confirm */
334                 }
335                 else {
336                         /* must be AMD style if not Intel */
337                         FPWV *base;             /* first address in bank */
338
339                         base = (FPWV *)(info->start[0]);
340                         base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
341                         base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
342                         base[FLASH_CYCLE1] = (FPW)0x00800080;   /* erase mode */
343                         base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
344                         base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
345                         *addr = (FPW)0x00300030;        /* erase sector */
346                 }
347
348                 /* re-enable interrupts if necessary */
349                 if (flag)
350                         enable_interrupts();
351
352                 start = get_timer(0);
353
354                 /* wait at least 50us for AMD, 80us for Intel.
355                  * Let's wait 1 ms.
356                  */
357                 udelay (1000);
358
359                 while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
360                         if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
361                                 printf ("Timeout\n");
362
363                                 if (intel) {
364                                         /* suspend erase        */
365                                         *addr = (FPW)0x00B000B0;
366                                 }
367
368                                 flash_reset(info);      /* reset to read mode */
369                                 rcode = 1;              /* failed */
370                                 break;
371                         }
372
373                         /* show that we're waiting */
374                         if ((get_timer(last)) > CFG_HZ) {/* every second */
375                                 putc ('.');
376                                 last = get_timer(0);
377                         }
378                 }
379
380                 /* show that we're waiting */
381                 if ((get_timer(last)) > CFG_HZ) {       /* every second */
382                         putc ('.');
383                         last = get_timer(0);
384                 }
385
386                 flash_reset(info);      /* reset to read mode   */
387         }
388
389         printf (" done\n");
390         return rcode;
391 }
392
393 /*-----------------------------------------------------------------------
394  * Copy memory to flash, returns:
395  * 0 - OK
396  * 1 - write timeout
397  * 2 - Flash not erased
398  */
399 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
400 {
401         FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
402         int bytes;        /* number of bytes to program in current word         */
403         int left;         /* number of bytes left to program                    */
404         int i, res;
405
406         for (left = cnt, res = 0;
407                  left > 0 && res == 0;
408                  addr += sizeof(data), left -= sizeof(data) - bytes) {
409
410                 bytes = addr & (sizeof(data) - 1);
411                 addr &= ~(sizeof(data) - 1);
412
413                 /* combine source and destination data so can program
414                  * an entire word of 16 or 32 bits
415                  */
416                 for (i = 0; i < sizeof(data); i++) {
417                         data <<= 8;
418                         if (i < bytes || i - bytes >= left )
419                                 data += *((uchar *)addr + i);
420                         else
421                                 data += *src++;
422                 }
423
424                 /* write one word to the flash */
425                 switch (info->flash_id & FLASH_VENDMASK) {
426                 case FLASH_MAN_AMD:
427                         res = write_word_amd(info, (FPWV *)addr, data);
428                         break;
429                 default:
430                         /* unknown flash type, error! */
431                         printf ("missing or unknown FLASH type\n");
432                         res = 1;        /* not really a timeout, but gives error */
433                         break;
434                 }
435         }
436
437         return (res);
438 }
439
440 /*-----------------------------------------------------------------------
441  * Write a word to Flash for AMD FLASH
442  * A word is 16 or 32 bits, whichever the bus width of the flash bank
443  * (not an individual chip) is.
444  *
445  * returns:
446  * 0 - OK
447  * 1 - write timeout
448  * 2 - Flash not erased
449  */
450 static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
451 {
452         ulong start;
453         int flag;
454         int res = 0;    /* result, assume success       */
455         FPWV *base;             /* first address in flash bank  */
456
457         /* Check if Flash is (sufficiently) erased */
458         if ((*dest & data) != data) {
459                 return (2);
460         }
461
462
463         base = (FPWV *)(info->start[0]);
464
465         /* Disable interrupts which might cause a timeout here */
466         flag = disable_interrupts();
467
468         base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
469         base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
470         base[FLASH_CYCLE1] = (FPW)0x00A000A0;   /* selects program mode */
471
472         *dest = data;           /* start programming the data   */
473
474         /* re-enable interrupts if necessary */
475         if (flag)
476                 enable_interrupts();
477
478         start = get_timer (0);
479
480         /* data polling for D7 */
481         while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
482                 if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
483                         *dest = (FPW)0x00F000F0;        /* reset bank */
484                         res = 1;
485                 }
486         }
487
488         return (res);
489 }