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