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