]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/utx8245/flash.c
Initial revision
[karo-tx-uboot.git] / board / utx8245 / flash.c
1 /*
2  * (C) Copyright 2001
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * (C) Copyright 2002
6  * Gregory E. Allen, gallen@arlut.utexas.edu
7  * Matthew E. Karger, karger@arlut.utexas.edu
8  * Applied Research Laboratories, The University of Texas at Austin
9  *
10  * See file CREDITS for list of people who contributed to this
11  * project.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License as
15  * published by the Free Software Foundation; either version 2 of
16  * the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26  * MA 02111-1307 USA
27  */
28
29 #include <common.h>
30 #include <mpc824x.h>
31 #include <asm/processor.h>
32
33 #define ROM_CS0_START   0xFF800000
34 #define ROM_CS1_START   0xFF000000
35
36 #if defined(CFG_ENV_IS_IN_FLASH)
37 # ifndef  CFG_ENV_ADDR
38 #  define CFG_ENV_ADDR  (CFG_FLASH_BASE + CFG_ENV_OFFSET)
39 # endif
40 # ifndef  CFG_ENV_SIZE
41 #  define CFG_ENV_SIZE  CFG_ENV_SECT_SIZE
42 # endif
43 # ifndef  CFG_ENV_SECT_SIZE
44 #  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
45 # endif
46 #endif
47
48 #define FLASH_BANK_SIZE 0x200000
49 #define MAIN_SECT_SIZE  0x10000
50 #define SECT_SIZE_32KB  0x8000
51 #define SECT_SIZE_8KB   0x2000
52
53 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
54
55 static int write_word (flash_info_t *info, ulong dest, ulong data);
56
57 static __inline__ unsigned long get_msr(void)
58 {       unsigned long msr;
59         __asm__ __volatile__ ("mfmsr %0" : "=r" (msr) :);
60     return msr;
61 }
62
63 static __inline__ void set_msr(unsigned long msr)
64 {
65     __asm__ __volatile__ ("mtmsr %0" : : "r" (msr));
66 }
67
68 /*flash command address offsets*/
69 #define ADDR0           (0x555)
70 #define ADDR1           (0xAAA)
71 #define ADDR3           (0x001)
72
73 #define FLASH_WORD_SIZE unsigned char
74
75 /*---------------------------------------------------------------------*/
76 /*#define       DEBUG_FLASH     1 */
77
78 /*---------------------------------------------------------------------*/
79
80 unsigned long flash_init(void)
81 {
82     int i, j;
83     ulong size = 0;
84         unsigned char manuf_id, device_id;
85
86     for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
87         {
88         vu_char *addr = (vu_char *)(CFG_FLASH_BASE + i * FLASH_BANK_SIZE);
89
90         addr[0x555] = 0xAA;                     /* 3 cycles to read device info.  See */
91         addr[0x2AA] = 0x55;                     /* AM29LV116D datasheet for list of */
92         addr[0x555] = 0x90;                     /* available commands. */
93
94         manuf_id = addr[0];
95         device_id = addr[1];
96
97 #if defined DEBUG_FLASH
98         printf("manuf_id = %x, device_id = %x\n", manuf_id, device_id);
99 #endif
100
101                 if (  (manuf_id == (uchar)(AMD_MANUFACT)) &&
102                 ( device_id == AMD_ID_LV116DT))
103                 {
104                 flash_info[i].flash_id = ((FLASH_MAN_AMD & FLASH_VENDMASK) << 16) |
105                                      (AMD_ID_LV116DT & FLASH_TYPEMASK);
106                 } else {
107                 flash_info[i].flash_id = FLASH_UNKNOWN;
108                 addr[0] = (long)0xFFFFFFFF;
109                 goto Done;
110                 }
111
112 #if defined DEBUG_FLASH
113                 printf ("flash_id = 0x%08lX\n", flash_info[i].flash_id);
114 #endif
115
116                 addr[0] = (long)0xFFFFFFFF;
117
118                 flash_info[i].size = FLASH_BANK_SIZE;
119                 flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
120                 memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
121
122                 for (j = 0; j < flash_info[i].sector_count; j++)
123                 {
124
125                         if (j < (CFG_MAX_FLASH_SECT - 3) )
126
127                                 flash_info[i].start[j] = CFG_FLASH_BASE + i * FLASH_BANK_SIZE +
128                                                                 j * MAIN_SECT_SIZE;
129
130                         else if (j == (CFG_MAX_FLASH_SECT - 3) )
131
132                                 flash_info[i].start[j] =  flash_info[i].start[j-1] + SECT_SIZE_32KB;
133
134
135                         else
136
137                                 flash_info[i].start[j] =  flash_info[i].start[j-1] + SECT_SIZE_8KB;
138
139                 }
140
141         size += flash_info[i].size;
142     }
143
144     /* Protect monitor and environment sectors
145      */
146 #if CFG_MONITOR_BASE >= CFG_FLASH_BASE
147      flash_protect(FLAG_PROTECT_SET, CFG_MONITOR_BASE,
148               CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, &flash_info[0]);
149 #endif
150
151 #if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
152     flash_protect(FLAG_PROTECT_SET, CFG_ENV_ADDR,
153                                         CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
154 #endif
155
156 Done:
157     return size;
158 }
159
160 /*-----------------------------------------------------------------------
161  */
162 void flash_print_info(flash_info_t *info)
163 {
164   static const char unk[] = "Unknown";
165   const char *mfct = unk, *type = unk;
166   unsigned int i;
167
168   if(info->flash_id != FLASH_UNKNOWN)
169   {
170     switch(info->flash_id & FLASH_VENDMASK)
171     {
172       case FLASH_MAN_AMD:       mfct = "AMD";                           break;
173       case FLASH_MAN_FUJ:       mfct = "FUJITSU";                       break;
174       case FLASH_MAN_STM:       mfct = "STM";                           break;
175       case FLASH_MAN_SST:       mfct = "SST";                           break;
176       case FLASH_MAN_BM:        mfct = "Bright Microelectonics";        break;
177       case FLASH_MAN_INTEL:     mfct = "Intel";                         break;
178     }
179
180     switch(info->flash_id & FLASH_TYPEMASK)
181     {
182       case FLASH_AM040:         type = "AM29F040B (512K * 8, uniform sector size)";     break;
183       case FLASH_AM400B:        type = "AM29LV400B (4 Mbit, bottom boot sect)";         break;
184       case FLASH_AM400T:        type = "AM29LV400T (4 Mbit, top boot sector)";          break;
185       case FLASH_AM800B:        type = "AM29LV800B (8 Mbit, bottom boot sect)";         break;
186       case FLASH_AM800T:        type = "AM29LV800T (8 Mbit, top boot sector)";          break;
187       case FLASH_AM160T:        type = "AM29LV160T (16 Mbit, top boot sector)";         break;
188       case FLASH_AM320B:        type = "AM29LV320B (32 Mbit, bottom boot sect)";        break;
189       case FLASH_AM320T:        type = "AM29LV320T (32 Mbit, top boot sector)";         break;
190       case FLASH_STM800AB:      type = "M29W800AB (8 Mbit, bottom boot sect)";          break;
191       case FLASH_SST800A:       type = "SST39LF/VF800 (8 Mbit, uniform sector size)";   break;
192       case FLASH_SST160A:       type = "SST39LF/VF160 (16 Mbit, uniform sector size)";  break;
193     }
194   }
195
196   printf(
197     "\n  Brand: %s Type: %s\n"
198     "  Size: %lu KB in %d Sectors\n",
199     mfct,
200     type,
201     info->size >> 10,
202     info->sector_count
203   );
204
205   printf ("  Sector Start Addresses:");
206
207   for (i = 0; i < info->sector_count; i++)
208   {
209     unsigned long size;
210     unsigned int erased;
211     unsigned long * flash = (unsigned long *) info->start[i];
212
213     /*
214      * Check if whole sector is erased
215      */
216     size =
217       (i != (info->sector_count - 1)) ?
218       (info->start[i + 1] - info->start[i]) >> 2 :
219       (info->start[0] + info->size - info->start[i]) >> 2;
220
221     for(
222       flash = (unsigned long *) info->start[i], erased = 1;
223       (flash != (unsigned long *) info->start[i] + size) && erased;
224       flash++
225     )
226       erased = *flash == ~0x0UL;
227
228     printf(
229       "%s %08lX %s %s",
230       (i % 5) ? "" : "\n   ",
231       info->start[i],
232       erased ? "E" : " ",
233       info->protect[i] ? "RO" : "  "
234     );
235   }
236
237   puts("\n");
238   return;
239 }
240
241 /*-----------------------------------------------------------------------
242  */
243
244 int     flash_erase (flash_info_t *info, int s_first, int s_last)
245 {
246         volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
247     int flag, prot, sect, l_sect;
248     ulong start, now, last;
249     unsigned char sh8b;
250
251     if ((s_first < 0) || (s_first > s_last)) {
252         if (info->flash_id == FLASH_UNKNOWN) {
253             printf ("- missing\n");
254         } else {
255             printf ("- no sectors to erase\n");
256         }
257         return 1;
258     }
259
260     if ((info->flash_id == FLASH_UNKNOWN) ||
261         (info->flash_id > (FLASH_MAN_STM | FLASH_AMD_COMP))) {
262         printf ("Can't erase unknown flash type - aborted\n");
263         return 1;
264     }
265
266     prot = 0;
267     for (sect=s_first; sect<=s_last; ++sect) {
268         if (info->protect[sect]) {
269             prot++;
270         }
271     }
272
273     if (prot) {
274         printf ("- Warning: %d protected sectors will not be erased!\n",
275             prot);
276     } else {
277         printf ("\n");
278     }
279
280     l_sect = -1;
281
282     /* Check the ROM CS */
283     if ((info->start[0] >= ROM_CS1_START) && (info->start[0] < ROM_CS0_START))
284       sh8b = 3;
285     else
286       sh8b = 0;
287
288         /* Disable interrupts which might cause a timeout here */
289     flag = disable_interrupts();
290
291     addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA;
292     addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055;
293     addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00800080;
294     addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA;
295     addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055;
296
297     /* Start erase on unprotected sectors */
298     for (sect = s_first; sect<=s_last; sect++)
299         {
300         if (info->protect[sect] == 0)
301                 { /* not protected */
302             addr = (FLASH_WORD_SIZE *)(info->start[0] + (
303                                 (info->start[sect] - info->start[0]) << sh8b));
304
305                         if (info->flash_id & FLASH_MAN_SST)
306                         {
307                                 addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA;
308                                 addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055;
309                                 addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00800080;
310                                 addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA;
311                                 addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055;
312                                 addr[0] = (FLASH_WORD_SIZE)0x00500050;  /* block erase */
313                                 udelay(30000);  /* wait 30 ms */
314                         }
315
316                         else
317                                 addr[0] = (FLASH_WORD_SIZE)0x00300030;  /* sector erase */
318
319                         l_sect = sect;
320         }
321     }
322
323     /* re-enable interrupts if necessary */
324     if (flag)
325         enable_interrupts();
326
327     /* wait at least 80us - let's wait 1 ms */
328     udelay (1000);
329
330     /*
331      * We wait for the last triggered sector
332      */
333     if (l_sect < 0)
334         goto DONE;
335
336     start = get_timer (0);
337     last  = start;
338     addr = (FLASH_WORD_SIZE *)(info->start[0] + (
339                         (info->start[l_sect] - info->start[0]) << sh8b));
340     while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
341         if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
342             printf ("Timeout\n");
343             return 1;
344         }
345         /* show that we're waiting */
346         if ((now - last) > 1000) {  /* every second */
347             serial_putc ('.');
348             last = now;
349         }
350     }
351
352 DONE:
353     /* reset to read mode */
354     addr = (FLASH_WORD_SIZE *)info->start[0];
355     addr[0] = (FLASH_WORD_SIZE)0x00F000F0;  /* reset bank */
356
357     printf (" done\n");
358     return 0;
359 }
360
361
362 /*-----------------------------------------------------------------------
363  * Copy memory to flash, returns:
364  * 0 - OK
365  * 1 - write timeout
366  * 2 - Flash not erased
367  */
368
369 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
370 {
371     ulong cp, wp, data;
372     int i, l, rc;
373
374     wp = (addr & ~3);   /* get lower word aligned address */
375
376     /*
377      * handle unaligned start bytes
378      */
379     if ((l = addr - wp) != 0) {
380         data = 0;
381         for (i=0, cp=wp; i<l; ++i, ++cp) {
382             data = (data << 8) | (*(uchar *)cp);
383         }
384         for (; i<4 && cnt>0; ++i) {
385             data = (data << 8) | *src++;
386             --cnt;
387             ++cp;
388         }
389         for (; cnt==0 && i<4; ++i, ++cp) {
390             data = (data << 8) | (*(uchar *)cp);
391         }
392
393         if ((rc = write_word(info, wp, data)) != 0) {
394             return (rc);
395         }
396         wp += 4;
397     }
398
399     /*
400      * handle word aligned part
401      */
402     while (cnt >= 4) {
403         data = 0;
404         for (i=0; i<4; ++i) {
405             data = (data << 8) | *src++;
406         }
407         if ((rc = write_word(info, wp, data)) != 0) {
408             return (rc);
409         }
410         wp  += 4;
411         cnt -= 4;
412     }
413
414     if (cnt == 0) {
415         return (0);
416     }
417
418     /*
419      * handle unaligned tail bytes
420      */
421     data = 0;
422     for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
423         data = (data << 8) | *src++;
424         --cnt;
425     }
426     for (; i<4; ++i, ++cp) {
427         data = (data << 8) | (*(uchar *)cp);
428     }
429
430     return (write_word(info, wp, data));
431 }
432
433
434 /*-----------------------------------------------------------------------
435  * Write a word to Flash, returns:
436  * 0 - OK
437  * 1 - write timeout
438  * 2 - Flash not erased
439  */
440 static int write_word (flash_info_t *info, ulong dest, ulong data)
441 {
442         volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)info->start[0];
443         volatile FLASH_WORD_SIZE *dest2;
444         volatile FLASH_WORD_SIZE *data2 = (FLASH_WORD_SIZE *)&data;
445         ulong start;
446         int flag;
447         int i;
448         unsigned char sh8b;
449
450     /* Check the ROM CS */
451     if ((info->start[0] >= ROM_CS1_START) && (info->start[0] < ROM_CS0_START))
452       sh8b = 3;
453     else
454       sh8b = 0;
455
456     dest2 = (FLASH_WORD_SIZE *)(((dest - info->start[0]) << sh8b) +
457                                 info->start[0]);
458
459     /* Check if Flash is (sufficiently) erased */
460     if ((*dest2 & (FLASH_WORD_SIZE)data) != (FLASH_WORD_SIZE)data) {
461         return (2);
462     }
463     /* Disable interrupts which might cause a timeout here */
464     flag = disable_interrupts();
465
466         for (i=0; i<4/sizeof(FLASH_WORD_SIZE); i++)
467           {
468             addr2[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA;
469             addr2[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055;
470             addr2[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00A000A0;
471
472             dest2[i << sh8b] = data2[i];
473
474             /* re-enable interrupts if necessary */
475             if (flag)
476               enable_interrupts();
477
478             /* data polling for D7 */
479             start = get_timer (0);
480             while ((dest2[i << sh8b] & (FLASH_WORD_SIZE)0x00800080) !=
481                    (data2[i] & (FLASH_WORD_SIZE)0x00800080)) {
482               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
483                 return (1);
484               }
485             }
486           }
487
488     return (0);
489 }
490 /*-----------------------------------------------------------------------
491  */