]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/cray/L1/flash.c
Initial revision
[karo-tx-uboot.git] / board / cray / L1 / 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 /*
25  * Modified 4/5/2001
26  * Wait for completion of each sector erase command issued
27  * 4/5/2001
28  * Chris Hallinan - DS4.COM, Inc. - clh@net1plus.com
29  */
30
31 /*
32  * Modified July 20, 2001
33  * Strip down to support ONLY the AMD29F032B.
34  * Dave Updegraff - Cray, Inc. dave@cray.com
35  */
36
37 #include <common.h>
38 #include <ppc4xx.h>
39 #include <asm/processor.h>
40
41 /* The flash chip we use... */
42 #define AMD_ID_F032B    0x41    /* 29F032B ID  32 Mbit,64 64Kx8 sectors */
43 #define FLASH_AM320B    0x0009
44
45
46 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
47
48 /*-----------------------------------------------------------------------
49  * Functions
50  */
51 static ulong flash_get_size (vu_long *addr, flash_info_t *info);
52 static int write_word (flash_info_t *info, ulong dest, ulong data);
53 static void flash_get_offsets (ulong base, flash_info_t *info);
54
55 #define ADDR0           0x5555
56 #define ADDR1           0x2aaa
57 #define FLASH_WORD_SIZE unsigned char
58
59 /*-----------------------------------------------------------------------
60  */
61
62 unsigned long flash_init (void)
63 {
64         unsigned long size_b0, size_b1;
65         int i;
66
67         /* Init: no FLASHes known */
68         for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
69                 flash_info[i].flash_id = FLASH_UNKNOWN;
70         }
71
72         /* Static FLASH Bank configuration here - FIXME XXX */
73
74         size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
75
76         if (flash_info[0].flash_id == FLASH_UNKNOWN) {
77                 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
78                         size_b0, size_b0<<20);
79         }
80
81         /* Only one bank */
82         if (CFG_MAX_FLASH_BANKS == 1)
83           {
84             /* Setup offsets */
85             flash_get_offsets (FLASH_BASE0_PRELIM, &flash_info[0]);
86
87 #if 0
88             /* Monitor protection ON by default */
89             (void)flash_protect(FLAG_PROTECT_SET,
90                                 FLASH_BASE0_PRELIM,
91                                 FLASH_BASE0_PRELIM+CFG_MONITOR_LEN-1,
92                                 &flash_info[0]);
93 #endif
94             size_b1 = 0 ;
95             flash_info[0].size = size_b0;
96           }
97
98         return (size_b0 + size_b1);
99 }
100
101
102
103 /*-----------------------------------------------------------------------
104  */
105 static void flash_get_offsets (ulong base, flash_info_t *info)
106 {
107         int i;
108
109         /* set up sector start address table */
110         for (i = 0; i < info->sector_count; i++)
111                 info->start[i] = base + (i * 0x00010000);
112 }
113
114 /*-----------------------------------------------------------------------
115  */
116 void flash_print_info  (flash_info_t *info)
117 {
118         int i;
119         int k;
120         int size;
121         int erased;
122         volatile unsigned long *flash;
123
124         if (info->flash_id == FLASH_UNKNOWN) {
125                 printf ("missing or unknown FLASH type\n");
126                 return;
127         }
128
129         switch (info->flash_id & FLASH_VENDMASK) {
130         case FLASH_MAN_AMD:     printf ("AMD ");                break;
131         default:                printf ("Unknown Vendor ");     break;
132         }
133
134         switch (info->flash_id & FLASH_TYPEMASK) {
135         case FLASH_AM320B:printf ("AM29F032B (32 Mbit 64x64KB uniform sectors)\n");
136                                 break;
137         default:                printf ("Unknown Chip Type\n");
138                                 break;
139         }
140
141         printf ("  Size: %ld KB in %d Sectors\n",
142                 info->size >> 10, info->sector_count);
143
144         printf ("  Sector Start Addresses:");
145         for (i=0; i<info->sector_count; ++i) {
146                 /*
147                  * Check if whole sector is erased
148                  */
149                 if (i != (info->sector_count-1))
150                   size = info->start[i+1] - info->start[i];
151                 else
152                   size = info->start[0] + info->size - info->start[i];
153                 erased = 1;
154                 flash = (volatile unsigned long *)info->start[i];
155                 size = size >> 2;        /* divide by 4 for longword access */
156                 for (k=0; k<size; k++)
157                   {
158                     if (*flash++ != 0xffffffff)
159                       {
160                         erased = 0;
161                         break;
162                       }
163                   }
164
165                 if ((i % 5) == 0)
166                         printf ("\n   ");
167
168                 printf (" %08lX%s%s",
169                         info->start[i],
170                         erased ? " E" : "  ",
171                         info->protect[i] ? "RO " : "   "
172                 );
173         }
174         printf ("\n");
175 }
176
177 /*-----------------------------------------------------------------------
178  */
179
180
181 /*-----------------------------------------------------------------------
182  */
183
184 /*
185  * The following code cannot be run from FLASH!
186  */
187 static ulong flash_get_size (vu_long *addr, flash_info_t *info)
188 {
189         short i;
190         FLASH_WORD_SIZE value;
191         ulong base = (ulong)addr;
192         volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)addr;
193
194         /* Write auto select command: read Manufacturer ID */
195         addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
196         addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
197         addr2[ADDR0] = (FLASH_WORD_SIZE)0x00900090;
198
199         value = addr2[0];
200
201         switch (value) {
202         case (FLASH_WORD_SIZE)AMD_MANUFACT:
203                 info->flash_id = FLASH_MAN_AMD;
204                 break;
205         default:
206                 info->flash_id = FLASH_UNKNOWN;
207                 info->sector_count = 0;
208                 info->size = 0;
209                 return (0);                     /* no or unknown flash  */
210         }
211
212         value = addr2[1];                       /* device ID            */
213
214         switch (value) {
215         case (FLASH_WORD_SIZE)AMD_ID_F032B:
216                 info->flash_id += FLASH_AM320B;
217                 info->sector_count = 64;
218                 info->size = 0x0400000; /* => 4 MB */
219                 break;
220         default:
221                 info->flash_id = FLASH_UNKNOWN;
222                 return (0);                     /* => no or unknown flash */
223
224         }
225
226         /* set up sector start address table */
227         for (i = 0; i < info->sector_count; i++)
228                 info->start[i] = base + (i * 0x00010000);
229
230         /* check for protected sectors */
231         for (i = 0; i < info->sector_count; i++) {
232                 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
233                 /* D0 = 1 if protected */
234                 addr2 = (volatile FLASH_WORD_SIZE *)(info->start[i]);
235         info->protect[i] = addr2[2] & 1;
236         }
237
238         /*
239          * Prevent writes to uninitialized FLASH.
240          */
241         if (info->flash_id != FLASH_UNKNOWN) {
242                 addr2 = (FLASH_WORD_SIZE *)info->start[0];
243                 *addr2 = (FLASH_WORD_SIZE)0x00F000F0;   /* reset bank */
244         }
245
246         return (info->size);
247 }
248
249 int wait_for_DQ7(flash_info_t *info, int sect)
250 {
251         ulong start, now, last;
252         volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[sect]);
253
254         start = get_timer (0);
255     last  = start;
256     while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
257         if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
258             printf ("Timeout\n");
259             return -1;
260         }
261         /* show that we're waiting */
262         if ((now - last) > 1000) {  /* every second */
263             putc ('.');
264             last = now;
265         }
266     }
267         return 0;
268 }
269
270 /*-----------------------------------------------------------------------
271  */
272
273 int     flash_erase (flash_info_t *info, int s_first, int s_last)
274 {
275         volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
276         volatile FLASH_WORD_SIZE *addr2;
277         int flag, prot, sect, l_sect;
278
279         if ((s_first < 0) || (s_first > s_last)) {
280                 if (info->flash_id == FLASH_UNKNOWN) {
281                         printf ("- missing\n");
282                 } else {
283                         printf ("- no sectors to erase\n");
284                 }
285                 return 1;
286         }
287
288         if (info->flash_id == FLASH_UNKNOWN) {
289                 printf ("Can't erase unknown flash type - aborted\n");
290                 return 1;
291         }
292
293         prot = 0;
294         for (sect=s_first; sect<=s_last; ++sect) {
295                 if (info->protect[sect]) {
296                         prot++;
297                 }
298         }
299
300         if (prot) {
301                 printf ("- Warning: %d protected sectors will not be erased!\n",
302                         prot);
303         } else {
304                 printf ("\n");
305         }
306
307         l_sect = -1;
308
309         /* Disable interrupts which might cause a timeout here */
310         flag = disable_interrupts();
311
312         /* Start erase on unprotected sectors */
313         for (sect = s_first; sect<=s_last; sect++) {
314                 if (info->protect[sect] == 0) { /* not protected */
315                     addr2 = (FLASH_WORD_SIZE *)(info->start[sect]);
316                     printf("Erasing sector %p\n", addr2);
317
318                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
319                         addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
320                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
321                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
322                         addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
323                         addr2[0] = (FLASH_WORD_SIZE)0x00300030;  /* sector erase */
324                     l_sect = sect;
325                     /*
326                      * Wait for each sector to complete, it's more
327                      * reliable.  According to AMD Spec, you must
328                      * issue all erase commands within a specified
329                      * timeout.  This has been seen to fail, especially
330                      * if printf()s are included (for debug)!!
331                      */
332                     wait_for_DQ7(info, sect);
333                 }
334         }
335
336         /* re-enable interrupts if necessary */
337         if (flag)
338                 enable_interrupts();
339
340         /* wait at least 80us - let's wait 1 ms */
341         udelay (1000);
342
343         /* reset to read mode */
344         addr = (FLASH_WORD_SIZE *)info->start[0];
345         addr[0] = (FLASH_WORD_SIZE)0x00F000F0;  /* reset bank */
346
347         printf (" done\n");
348         return 0;
349 }
350
351 /*-----------------------------------------------------------------------
352  * Copy memory to flash, returns:
353  * 0 - OK
354  * 1 - write timeout
355  * 2 - Flash not erased
356  */
357
358 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
359 {
360         ulong cp, wp, data;
361         int i, l, rc;
362
363         wp = (addr & ~3);       /* get lower word aligned address */
364
365         /*
366          * handle unaligned start bytes
367          */
368         if ((l = addr - wp) != 0) {
369                 data = 0;
370                 for (i=0, cp=wp; i<l; ++i, ++cp) {
371                         data = (data << 8) | (*(uchar *)cp);
372                 }
373                 for (; i<4 && cnt>0; ++i) {
374                         data = (data << 8) | *src++;
375                         --cnt;
376                         ++cp;
377                 }
378                 for (; cnt==0 && i<4; ++i, ++cp) {
379                         data = (data << 8) | (*(uchar *)cp);
380                 }
381
382                 if ((rc = write_word(info, wp, data)) != 0) {
383                         return (rc);
384                 }
385                 wp += 4;
386         }
387
388         /*
389          * handle word aligned part
390          */
391         while (cnt >= 4) {
392                 data = 0;
393                 for (i=0; i<4; ++i) {
394                         data = (data << 8) | *src++;
395                 }
396                 if ((rc = write_word(info, wp, data)) != 0) {
397                         return (rc);
398                 }
399                 wp  += 4;
400                 cnt -= 4;
401         }
402
403         if (cnt == 0) {
404                 return (0);
405         }
406
407         /*
408          * handle unaligned tail bytes
409          */
410         data = 0;
411         for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
412                 data = (data << 8) | *src++;
413                 --cnt;
414         }
415         for (; i<4; ++i, ++cp) {
416                 data = (data << 8) | (*(uchar *)cp);
417         }
418
419         return (write_word(info, wp, data));
420 }
421
422 /*-----------------------------------------------------------------------
423  * Write a word to Flash, returns:
424  * 0 - OK
425  * 1 - write timeout
426  * 2 - Flash not erased
427  */
428 static int write_word (flash_info_t *info, ulong dest, ulong data)
429 {
430         volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)(info->start[0]);
431         volatile FLASH_WORD_SIZE *dest2 = (FLASH_WORD_SIZE *)dest;
432         volatile FLASH_WORD_SIZE *data2 = (FLASH_WORD_SIZE *)&data;
433         ulong start;
434         int flag;
435         int i;
436
437         /* Check if Flash is (sufficiently) erased */
438         if ((*((volatile FLASH_WORD_SIZE *)dest) &
439              (FLASH_WORD_SIZE)data) != (FLASH_WORD_SIZE)data) {
440                 return (2);
441         }
442         /* Disable interrupts which might cause a timeout here */
443         flag = disable_interrupts();
444
445         for (i=0; i<4/sizeof(FLASH_WORD_SIZE); i++)
446           {
447             addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
448             addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
449             addr2[ADDR0] = (FLASH_WORD_SIZE)0x00A000A0;
450
451             dest2[i] = data2[i];
452
453             /* re-enable interrupts if necessary */
454             if (flag)
455               enable_interrupts();
456
457             /* data polling for D7 */
458             start = get_timer (0);
459             while ((dest2[i] & (FLASH_WORD_SIZE)0x00800080) !=
460                    (data2[i] & (FLASH_WORD_SIZE)0x00800080)) {
461               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
462                 return (1);
463               }
464             }
465           }
466
467         return (0);
468 }
469
470 /*-----------------------------------------------------------------------
471  */