]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/fads/flash.c
imported Freescale specific U-Boot additions for i.MX28,... release L2.6.31_10.08.01
[karo-tx-uboot.git] / board / fads / flash.c
1 /*
2  * (C) Copyright 2000
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
27 flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];    /* info for FLASH chips */
28
29 #if defined(CONFIG_ENV_IS_IN_FLASH)
30 # ifndef  CONFIG_ENV_ADDR
31 #  define CONFIG_ENV_ADDR       (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
32 # endif
33 # ifndef  CONFIG_ENV_SIZE
34 #  define CONFIG_ENV_SIZE       CONFIG_ENV_SECT_SIZE
35 # endif
36 # ifndef  CONFIG_ENV_SECT_SIZE
37 #  define CONFIG_ENV_SECT_SIZE  CONFIG_ENV_SIZE
38 # endif
39 #endif
40
41 #define QUAD_ID(id)     ((((ulong)(id) & 0xFF) << 24) | \
42                          (((ulong)(id) & 0xFF) << 16) | \
43                          (((ulong)(id) & 0xFF) << 8)  | \
44                          (((ulong)(id) & 0xFF) << 0)    \
45                         )
46
47 /*-----------------------------------------------------------------------
48  * Functions
49  */
50 static ulong flash_get_size (vu_long * addr, flash_info_t * info);
51 static int write_word (flash_info_t * info, ulong dest, ulong data);
52
53 /*-----------------------------------------------------------------------
54  */
55 unsigned long flash_init (void)
56 {
57         volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
58         volatile memctl8xx_t *memctl = &immap->im_memctl;
59         vu_long *bcsr = (vu_long *)BCSR_ADDR;
60         unsigned long pd_size, total_size, bsize, or_am;
61         int i;
62
63         /* Init: no FLASHes known */
64         for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
65                 flash_info[i].flash_id = FLASH_UNKNOWN;
66                 flash_info[i].size = 0;
67                 flash_info[i].sector_count = 0;
68                 flash_info[i].start[0] = 0xFFFFFFFF; /* For TFTP */
69         }
70
71         switch ((bcsr[2] & BCSR2_FLASH_PD_MASK) >> BCSR2_FLASH_PD_SHIFT) {
72         case 2:
73         case 4:
74         case 6:
75                 pd_size = 0x800000;
76                 or_am = 0xFF800000;
77                 break;
78
79         case 5:
80         case 7:
81                 pd_size = 0x400000;
82                 or_am = 0xFFC00000;
83                 break;
84
85         case 8:
86                 pd_size = 0x200000;
87                 or_am = 0xFFE00000;
88                 break;
89
90         default:
91                 pd_size = 0;
92                 or_am = 0xFFE00000;
93                 printf("## Unsupported flash detected by BCSR: 0x%08lX\n", bcsr[2]);
94         }
95
96         total_size = 0;
97         for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS && total_size < pd_size; ++i) {
98                 bsize = flash_get_size((vu_long *)(CONFIG_SYS_FLASH_BASE + total_size),
99                                        &flash_info[i]);
100
101                 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
102                         printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
103                                 i, bsize, bsize >> 20);
104                 }
105
106                 total_size += bsize;
107         }
108
109         if (total_size != pd_size) {
110                 printf("## Detected flash size %lu conflicts with PD data %lu\n",
111                        total_size, pd_size);
112         }
113
114         /* Remap FLASH according to real size */
115         memctl->memc_or0 = or_am | CONFIG_SYS_OR_TIMING_FLASH;
116
117         for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS && flash_info[i].size != 0; ++i) {
118 #if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
119                 /* monitor protection ON by default */
120                 if (CONFIG_SYS_MONITOR_BASE >= flash_info[i].start[0])
121                         flash_protect (FLAG_PROTECT_SET,
122                                        CONFIG_SYS_MONITOR_BASE,
123                                        CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
124                                        &flash_info[i]);
125 #endif
126
127 #ifdef  CONFIG_ENV_IS_IN_FLASH
128                 /* ENV protection ON by default */
129                 if (CONFIG_ENV_ADDR >= flash_info[i].start[0])
130                         flash_protect (FLAG_PROTECT_SET,
131                                        CONFIG_ENV_ADDR,
132                                        CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
133                                        &flash_info[i]);
134 #endif
135         }
136
137         return total_size;
138 }
139
140 /*-----------------------------------------------------------------------
141  */
142 void flash_print_info (flash_info_t * info)
143 {
144         int i;
145
146         if (info->flash_id == FLASH_UNKNOWN) {
147                 printf ("missing or unknown FLASH type\n");
148                 return;
149         }
150
151         switch (info->flash_id & FLASH_VENDMASK) {
152         case FLASH_MAN_AMD:
153                 printf ("AMD ");
154                 break;
155         case FLASH_MAN_FUJ:
156                 printf ("FUJITSU ");
157                 break;
158         case FLASH_MAN_BM:
159                 printf ("BRIGHT MICRO ");
160                 break;
161         default:
162                 printf ("Unknown Vendor ");
163                 break;
164         }
165
166         switch (info->flash_id & FLASH_TYPEMASK) {
167         case FLASH_AM040:
168                 printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
169                 break;
170         case FLASH_AM080:
171                 printf ("29F080 or 29LV080 (8 Mbit, uniform sectors)\n");
172                 break;
173         case FLASH_AM400B:
174                 printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
175                 break;
176         case FLASH_AM400T:
177                 printf ("AM29LV400T (4 Mbit, top boot sector)\n");
178                 break;
179         case FLASH_AM800B:
180                 printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
181                 break;
182         case FLASH_AM800T:
183                 printf ("AM29LV800T (8 Mbit, top boot sector)\n");
184                 break;
185         case FLASH_AM160B:
186                 printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
187                 break;
188         case FLASH_AM160T:
189                 printf ("AM29LV160T (16 Mbit, top boot sector)\n");
190                 break;
191         case FLASH_AM320B:
192                 printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
193                 break;
194         case FLASH_AM320T:
195                 printf ("AM29LV320T (32 Mbit, top boot sector)\n");
196                 break;
197         default:
198                 printf ("Unknown Chip Type\n");
199                 break;
200         }
201
202         printf ("  Size: %ld MB in %d Sectors\n", info->size >> 20,
203                 info->sector_count);
204
205         printf ("  Sector Start Addresses:");
206
207         for (i = 0; i < info->sector_count; ++i) {
208                 if ((i % 5) == 0) {
209                         printf ("\n   ");
210                 }
211
212                 printf (" %08lX%s",
213                         info->start[i], info->protect[i] ? " (RO)" : "     ");
214         }
215
216         printf ("\n");
217 }
218
219 /*-----------------------------------------------------------------------
220  * The following code can not run from flash!
221  */
222 static ulong flash_get_size (vu_long * addr, flash_info_t * info)
223 {
224         short i;
225
226         /* Write auto select command: read Manufacturer ID */
227         addr[0x0555] = 0xAAAAAAAA;
228         addr[0x02AA] = 0x55555555;
229         addr[0x0555] = 0x90909090;
230
231         switch (addr[0]) {
232         case QUAD_ID(AMD_MANUFACT):
233                 info->flash_id = FLASH_MAN_AMD;
234                 break;
235
236         case QUAD_ID(FUJ_MANUFACT):
237                 info->flash_id = FLASH_MAN_FUJ;
238                 break;
239
240         default:
241                 info->flash_id = FLASH_UNKNOWN;
242                 info->sector_count = 0;
243                 info->size = 0;
244                 break;
245         }
246
247         switch (addr[1]) {      /* device ID            */
248         case QUAD_ID(AMD_ID_F040B):
249         case QUAD_ID(AMD_ID_LV040B):
250                 info->flash_id += FLASH_AM040;
251                 info->sector_count = 8;
252                 info->size = 0x00200000;
253                 break;          /* => 2 MB              */
254
255         case QUAD_ID(AMD_ID_F080B):
256                 info->flash_id += FLASH_AM080;
257                 info->sector_count = 16;
258                 info->size = 0x00400000;
259                 break;          /* => 4 MB              */
260 #if 0
261         case AMD_ID_LV400T:
262                 info->flash_id += FLASH_AM400T;
263                 info->sector_count = 11;
264                 info->size = 0x00100000;
265                 break;          /* => 1 MB              */
266
267         case AMD_ID_LV400B:
268                 info->flash_id += FLASH_AM400B;
269                 info->sector_count = 11;
270                 info->size = 0x00100000;
271                 break;          /* => 1 MB              */
272
273         case AMD_ID_LV800T:
274                 info->flash_id += FLASH_AM800T;
275                 info->sector_count = 19;
276                 info->size = 0x00200000;
277                 break;          /* => 2 MB              */
278
279         case AMD_ID_LV800B:
280                 info->flash_id += FLASH_AM800B;
281                 info->sector_count = 19;
282                 info->size = 0x00200000;
283                 break;          /* => 2 MB              */
284
285         case AMD_ID_LV160T:
286                 info->flash_id += FLASH_AM160T;
287                 info->sector_count = 35;
288                 info->size = 0x00400000;
289                 break;          /* => 4 MB              */
290
291         case AMD_ID_LV160B:
292                 info->flash_id += FLASH_AM160B;
293                 info->sector_count = 35;
294                 info->size = 0x00400000;
295                 break;          /* => 4 MB              */
296
297         case AMD_ID_LV320T:
298                 info->flash_id += FLASH_AM320T;
299                 info->sector_count = 67;
300                 info->size = 0x00800000;
301                 break;          /* => 8 MB              */
302
303         case AMD_ID_LV320B:
304                 info->flash_id += FLASH_AM320B;
305                 info->sector_count = 67;
306                 info->size = 0x00800000;
307                 break;          /* => 8 MB              */
308 #endif /* 0 */
309         default:
310                 info->flash_id = FLASH_UNKNOWN;
311                 return (0);     /* => no or unknown flash */
312         }
313
314 #if 0
315         /* set up sector start address table */
316         if (info->flash_id & FLASH_BTYPE) {
317                 /* set sector offsets for bottom boot block type        */
318                 info->start[0] = base + 0x00000000;
319                 info->start[1] = base + 0x00008000;
320                 info->start[2] = base + 0x0000C000;
321                 info->start[3] = base + 0x00010000;
322                 for (i = 4; i < info->sector_count; i++) {
323                         info->start[i] = base + (i * 0x00020000) - 0x00060000;
324                 }
325         } else {
326                 /* set sector offsets for top boot block type           */
327                 i = info->sector_count - 1;
328                 info->start[i--] = base + info->size - 0x00008000;
329                 info->start[i--] = base + info->size - 0x0000C000;
330                 info->start[i--] = base + info->size - 0x00010000;
331                 for (; i >= 0; i--) {
332                         info->start[i] = base + i * 0x00020000;
333                 }
334         }
335 #else
336         /* set sector offsets for uniform sector type */
337         for (i = 0; i < info->sector_count; i++)
338                 info->start[i] = (ulong)addr + (i * 0x00040000);
339 #endif
340
341         /* check for protected sectors */
342         for (i = 0; i < info->sector_count; i++) {
343                 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
344                 /* D0 = 1 if protected */
345                 addr = (volatile unsigned long *) (info->start[i]);
346                 info->protect[i] = addr[2] & 1;
347         }
348
349         if (info->flash_id != FLASH_UNKNOWN) {
350                 addr = (volatile unsigned long *) info->start[0];
351                 *addr = 0xF0F0F0F0;     /* reset bank */
352         }
353
354         return (info->size);
355 }
356
357 /*-----------------------------------------------------------------------
358  */
359 int flash_erase (flash_info_t * info, int s_first, int s_last)
360 {
361         vu_long *addr = (vu_long *) (info->start[0]);
362         int flag, prot, sect, l_sect;
363         ulong start, now, last;
364
365         if ((s_first < 0) || (s_first > s_last)) {
366                 if (info->flash_id == FLASH_UNKNOWN) {
367                         printf ("- missing\n");
368                 } else {
369                         printf ("- no sectors to erase\n");
370                 }
371                 return ERR_INVAL;
372         }
373
374         if ((info->flash_id == FLASH_UNKNOWN) ||
375             (info->flash_id > FLASH_AMD_COMP)) {
376                 printf ("Can't erase unknown flash type - aborted\n");
377                 return ERR_UNKNOWN_FLASH_TYPE;
378         }
379
380         prot = 0;
381         for (sect = s_first; sect <= s_last; ++sect) {
382                 if (info->protect[sect]) {
383                         prot++;
384                 }
385         }
386
387         if (prot) {
388                 printf ("- Warning: %d protected sectors will not be erased!\n", prot);
389         } else {
390                 printf ("\n");
391         }
392
393         l_sect = -1;
394
395         /* Disable interrupts which might cause a timeout here */
396         flag = disable_interrupts ();
397
398         addr[0x0555] = 0xAAAAAAAA;
399         addr[0x02AA] = 0x55555555;
400         addr[0x0555] = 0x80808080;
401         addr[0x0555] = 0xAAAAAAAA;
402         addr[0x02AA] = 0x55555555;
403
404         /* Start erase on unprotected sectors */
405         for (sect = s_first; sect <= s_last; sect++) {
406                 if (info->protect[sect] == 0) { /* not protected */
407                         addr = (vu_long *) (info->start[sect]);
408                         addr[0] = 0x30303030;
409                         l_sect = sect;
410                 }
411         }
412
413         /* re-enable interrupts if necessary */
414         if (flag)
415                 enable_interrupts ();
416
417         /* wait at least 80us - let's wait 1 ms */
418         udelay (1000);
419
420         /*
421          * We wait for the last triggered sector
422          */
423         if (l_sect < 0)
424                 goto DONE;
425
426         start = get_timer (0);
427         last = start;
428         addr = (vu_long *) (info->start[l_sect]);
429         while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF)
430         {
431                 if ((now = get_timer (start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
432                         printf ("Timeout\n");
433                         return ERR_TIMOUT;
434                 }
435                 /* show that we're waiting */
436                 if ((now - last) > 1000) {      /* every second */
437                         putc ('.');
438                         last = now;
439                 }
440         }
441
442       DONE:
443         /* reset to read mode */
444         addr = (volatile unsigned long *) info->start[0];
445         addr[0] = 0xF0F0F0F0;   /* reset bank */
446
447         printf (" done\n");
448
449         return 0;
450 }
451
452 /*-----------------------------------------------------------------------
453  * Copy memory to flash, returns:
454  * 0 - OK
455  * 1 - write timeout
456  * 2 - Flash not erased
457  */
458 int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
459 {
460         ulong cp, wp, data;
461         int i, l, rc;
462
463         wp = (addr & ~3);       /* get lower word aligned address */
464
465         /*
466          * handle unaligned start bytes
467          */
468         if ((l = addr - wp) != 0) {
469                 data = 0;
470                 for (i = 0, cp = wp; i < l; ++i, ++cp) {
471                         data = (data << 8) | (*(uchar *) cp);
472                 }
473                 for (; i < 4 && cnt > 0; ++i) {
474                         data = (data << 8) | *src++;
475                         --cnt;
476                         ++cp;
477                 }
478                 for (; cnt == 0 && i < 4; ++i, ++cp) {
479                         data = (data << 8) | (*(uchar *) cp);
480                 }
481
482                 if ((rc = write_word (info, wp, data)) != 0) {
483                         return (rc);
484                 }
485                 wp += 4;
486         }
487
488         /*
489          * handle word aligned part
490          */
491         while (cnt >= 4) {
492                 data = 0;
493                 for (i = 0; i < 4; ++i) {
494                         data = (data << 8) | *src++;
495                 }
496                 if ((rc = write_word (info, wp, data)) != 0) {
497                         return (rc);
498                 }
499                 wp += 4;
500                 cnt -= 4;
501         }
502
503         if (cnt == 0) {
504                 return (0);
505         }
506
507         /*
508          * handle unaligned tail bytes
509          */
510         data = 0;
511         for (i = 0, cp = wp; i < 4 && cnt > 0; ++i, ++cp) {
512                 data = (data << 8) | *src++;
513                 --cnt;
514         }
515         for (; i < 4; ++i, ++cp) {
516                 data = (data << 8) | (*(uchar *) cp);
517         }
518
519         return (write_word (info, wp, data));
520 }
521
522 /*-----------------------------------------------------------------------
523  * Write a word to Flash, returns:
524  * 0 - OK
525  * 1 - write timeout
526  * 2 - Flash not erased
527  */
528 static int write_word (flash_info_t * info, ulong dest, ulong data)
529 {
530         vu_long *addr = (vu_long *) (info->start[0]);
531         ulong start;
532         int flag;
533
534         /* Check if Flash is (sufficiently) erased */
535         if ((*((vu_long *) dest) & data) != data) {
536                 return ERR_NOT_ERASED;
537         }
538         /* Disable interrupts which might cause a timeout here */
539         flag = disable_interrupts ();
540
541         addr[0x0555] = 0xAAAAAAAA;
542         addr[0x02AA] = 0x55555555;
543         addr[0x0555] = 0xA0A0A0A0;
544
545         *((vu_long *) dest) = data;
546
547         /* re-enable interrupts if necessary */
548         if (flag)
549                 enable_interrupts ();
550
551         /* data polling for D7 */
552         start = get_timer (0);
553         while ((*((vu_long *) dest) & 0x80808080) != (data & 0x80808080))
554         {
555                 if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
556                         return ERR_TIMOUT;
557                 }
558         }
559         return (0);
560 }