]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/mbx8xx/flash.c
imported Freescale specific U-Boot additions for i.MX28,... release L2.6.31_10.08.01
[karo-tx-uboot.git] / board / mbx8xx / flash.c
1 /*
2  * (C) Copyright 2000
3  * Marius Groeger <mgroeger@sysgo.de>
4  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
5  *
6  * (C) Copyright 2000
7  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
8  *
9  * Flash Routines for AM290[48]0B devices
10  *
11  *--------------------------------------------------------------------
12  * See file CREDITS for list of people who contributed to this
13  * project.
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License as
17  * published by the Free Software Foundation; either version 2 of
18  * the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28  * MA 02111-1307 USA
29  */
30
31 #include <common.h>
32 #include <mpc8xx.h>
33 #include "vpd.h"
34
35 flash_info_t    flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
36
37 /*-----------------------------------------------------------------------
38  * Functions
39  */
40
41 static ulong flash_get_size (vu_long *addr, flash_info_t *info);
42 static int write_word (flash_info_t *info, ulong dest, ulong data);
43
44 /*-----------------------------------------------------------------------
45  */
46
47 unsigned long flash_init (void)
48 {
49     unsigned long size, totsize;
50     int i;
51     ulong addr;
52
53     /* Init: no FLASHes known */
54     for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
55         flash_info[i].flash_id = FLASH_UNKNOWN;
56     }
57
58     totsize = 0;
59     addr = 0xfc000000;
60     for(i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
61         size = flash_get_size((vu_long *)addr, &flash_info[i]);
62         if (flash_info[i].flash_id == FLASH_UNKNOWN)
63           break;
64         totsize += size;
65         addr += size;
66     }
67
68     addr = 0xfe000000;
69     for(i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
70
71         size = flash_get_size((vu_long *)addr, &flash_info[i]);
72         if (flash_info[i].flash_id == FLASH_UNKNOWN)
73           break;
74         totsize += size;
75         addr += size;
76     }
77
78 #if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
79     /* monitor protection ON by default */
80     flash_protect(FLAG_PROTECT_SET,
81                   CONFIG_SYS_MONITOR_BASE,
82                   CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
83                   &flash_info[0]);
84 #endif
85
86     return (totsize);
87 }
88
89 /*-----------------------------------------------------------------------
90  */
91 void flash_print_info  (flash_info_t *info)
92 {
93     int i;
94
95     if (info->flash_id == FLASH_UNKNOWN) {
96         printf ("missing or unknown FLASH type\n");
97         return;
98     }
99
100     switch (info->flash_id >> 16) {
101     case 0x1:
102         printf ("AMD ");
103         break;
104     default:
105         printf ("Unknown Vendor ");
106         break;
107     }
108
109     switch (info->flash_id & FLASH_TYPEMASK) {
110     case AMD_ID_F040B:
111         printf ("AM29F040B (4 Mbit)\n");
112         break;
113     case AMD_ID_F080B:
114         printf ("AM29F080B (8 Mbit)\n");
115         break;
116     case AMD_ID_F016D:
117         printf ("AM29F016D (16 Mbit)\n");
118         break;
119     default:
120         printf ("Unknown Chip Type\n");
121         break;
122     }
123
124     printf ("  Size: %ld MB in %d Sectors\n",
125             info->size >> 20, info->sector_count);
126
127     printf ("  Sector Start Addresses:");
128     for (i=0; i<info->sector_count; ++i) {
129         if ((i % 5) == 0)
130           printf ("\n   ");
131         printf (" %08lX%s",
132                 info->start[i],
133                 info->protect[i] ? " (RO)" : "     "
134                 );
135     }
136     printf ("\n");
137     return;
138 }
139
140 /*
141  * The following code cannot be run from FLASH!
142  */
143
144 static ulong flash_get_size (vu_long *addr, flash_info_t *info)
145 {
146     short i;
147     ulong vendor, devid;
148     ulong base = (ulong)addr;
149
150     /* Write auto select command: read Manufacturer ID */
151     addr[0x0555] = 0xAAAAAAAA;
152     addr[0x02AA] = 0x55555555;
153     addr[0x0555] = 0x90909090;
154
155     vendor = addr[0];
156     devid = addr[1] & 0xff;
157
158     /* only support AMD */
159     if (vendor != 0x01010101) {
160         return 0;
161     }
162
163     vendor &= 0xf;
164     devid &= 0xff;
165
166     if (devid == AMD_ID_F040B) {
167         info->flash_id     = vendor << 16 | devid;
168         info->sector_count = 8;
169         info->size         = info->sector_count * 0x10000;
170     }
171     else if (devid == AMD_ID_F080B) {
172         info->flash_id     = vendor << 16 | devid;
173         info->sector_count = 16;
174         info->size         = 4 * info->sector_count * 0x10000;
175     }
176     else if (devid == AMD_ID_F016D) {
177         info->flash_id     = vendor << 16 | devid;
178         info->sector_count = 32;
179         info->size         = 4 * info->sector_count * 0x10000;
180     }
181     else {
182         printf ("## Unknown Flash Type: %08lx\n", devid);
183         return 0;
184     }
185
186     /* check for protected sectors */
187     for (i = 0; i < info->sector_count; i++) {
188         /* sector base address */
189         info->start[i] = base + i * (info->size / info->sector_count);
190         /* read sector protection at sector address, (A7 .. A0) = 0x02 */
191         /* D0 = 1 if protected */
192         addr = (volatile unsigned long *)(info->start[i]);
193         info->protect[i] = addr[2] & 1;
194     }
195
196     /*
197      * Prevent writes to uninitialized FLASH.
198      */
199     if (info->flash_id != FLASH_UNKNOWN) {
200         addr = (vu_long *)info->start[0];
201         addr[0] = 0xF0; /* reset bank */
202     }
203
204     return (info->size);
205 }
206
207
208 /*-----------------------------------------------------------------------
209  */
210
211 int     flash_erase (flash_info_t *info, int s_first, int s_last)
212 {
213     vu_long *addr = (vu_long*)(info->start[0]);
214     int flag, prot, sect, l_sect;
215     ulong start, now, last;
216
217     if ((s_first < 0) || (s_first > s_last)) {
218         if (info->flash_id == FLASH_UNKNOWN) {
219             printf ("- missing\n");
220         } else {
221             printf ("- no sectors to erase\n");
222         }
223         return 1;
224     }
225
226     prot = 0;
227     for (sect = s_first; sect <= s_last; sect++) {
228         if (info->protect[sect]) {
229             prot++;
230         }
231     }
232
233     if (prot) {
234         printf ("- Warning: %d protected sectors will not be erased!\n",
235                 prot);
236     } else {
237         printf ("\n");
238     }
239
240     l_sect = -1;
241
242     /* Disable interrupts which might cause a timeout here */
243     flag = disable_interrupts();
244
245     addr[0x0555] = 0XAAAAAAAA;
246     addr[0x02AA] = 0x55555555;
247     addr[0x0555] = 0x80808080;
248     addr[0x0555] = 0XAAAAAAAA;
249     addr[0x02AA] = 0x55555555;
250
251     /* Start erase on unprotected sectors */
252     for (sect = s_first; sect<=s_last; sect++) {
253         if (info->protect[sect] == 0) { /* not protected */
254             addr = (vu_long*)(info->start[sect]);
255             addr[0] = 0x30303030;
256             l_sect = sect;
257         }
258     }
259
260     /* re-enable interrupts if necessary */
261     if (flag)
262       enable_interrupts();
263
264     /* wait at least 80us - let's wait 1 ms */
265     udelay (1000);
266
267     /*
268      * We wait for the last triggered sector
269      */
270     if (l_sect < 0)
271       goto DONE;
272
273     start = get_timer (0);
274     last  = start;
275     addr = (vu_long*)(info->start[l_sect]);
276     while ((addr[0] & 0x80808080) != 0x80808080) {
277         if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
278             printf ("Timeout\n");
279             return 1;
280         }
281         /* show that we're waiting */
282         if ((now - last) > 1000) {      /* every second */
283             serial_putc ('.');
284             last = now;
285         }
286     }
287
288     DONE:
289     /* reset to read mode */
290     addr = (volatile unsigned long *)info->start[0];
291     addr[0] = 0xF0F0F0F0;       /* reset bank */
292
293     printf (" done\n");
294     return 0;
295 }
296
297 /*-----------------------------------------------------------------------
298  * Copy memory to flash, returns:
299  * 0 - OK
300  * 1 - write timeout
301  * 2 - Flash not erased
302  */
303
304 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
305 {
306     ulong cp, wp, data;
307     int i, l, rc;
308
309     wp = (addr & ~3);   /* get lower word aligned address */
310
311     /*
312      * handle unaligned start bytes
313      */
314     if ((l = addr - wp) != 0) {
315         data = 0;
316         for (i=0, cp=wp; i<l; ++i, ++cp) {
317             data = (data << 8) | (*(uchar *)cp);
318         }
319         for (; i<4 && cnt>0; ++i) {
320             data = (data << 8) | *src++;
321             --cnt;
322             ++cp;
323         }
324         for (; cnt==0 && i<4; ++i, ++cp) {
325             data = (data << 8) | (*(uchar *)cp);
326         }
327
328         if ((rc = write_word(info, wp, data)) != 0) {
329             return (rc);
330         }
331         wp += 4;
332     }
333
334     /*
335      * handle word aligned part
336      */
337     while (cnt >= 4) {
338         data = 0;
339         for (i=0; i<4; ++i) {
340             data = (data << 8) | *src++;
341         }
342         if ((rc = write_word(info, wp, data)) != 0) {
343             return (rc);
344         }
345         wp  += 4;
346         cnt -= 4;
347     }
348
349     if (cnt == 0) {
350         return (0);
351     }
352
353     /*
354      * handle unaligned tail bytes
355      */
356     data = 0;
357     for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
358         data = (data << 8) | *src++;
359         --cnt;
360     }
361     for (; i<4; ++i, ++cp) {
362         data = (data << 8) | (*(uchar *)cp);
363     }
364
365     return (write_word(info, wp, data));
366 }
367
368 /*-----------------------------------------------------------------------
369  * Write a word to Flash, returns:
370  * 0 - OK
371  * 1 - write timeout
372  * 2 - Flash not erased
373  */
374 static int write_word (flash_info_t *info, ulong dest, ulong data)
375 {
376     vu_long *addr = (vu_long*)(info->start[0]);
377     ulong start;
378     int flag;
379
380     /* Check if Flash is (sufficiently) erased */
381     if ((*((vu_long *)dest) & data) != data) {
382         return (2);
383     }
384     /* Disable interrupts which might cause a timeout here */
385     flag = disable_interrupts();
386
387     addr[0x0555] = 0xAAAAAAAA;
388     addr[0x02AA] = 0x55555555;
389     addr[0x0555] = 0xA0A0A0A0;
390
391     *((vu_long *)dest) = data;
392
393     /* re-enable interrupts if necessary */
394     if (flag)
395       enable_interrupts();
396
397     /* data polling for D7 */
398     start = get_timer (0);
399     while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
400         if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
401             return (1);
402         }
403     }
404     return (0);
405 }
406
407 /*-----------------------------------------------------------------------
408  */