]> git.sur5r.net Git - u-boot/blob - board/rpxsuper/flash.c
board/rpxsuper/flash.c: minimal CodingStyle cleanup
[u-boot] / 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         /* for now, only support the 4 MB Flash SIMM */
60         size = flash_get_size((vu_long *) CONFIG_SYS_FLASH0_BASE,
61                               &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, &flash_info[0]);
81 #endif
82
83         return /*size */ (CONFIG_SYS_FLASH0_SIZE * 1024 * 1024);
84 }
85
86 /*-----------------------------------------------------------------------
87  */
88 void flash_print_info  (flash_info_t *info)
89 {
90     int i;
91
92     if (info->flash_id == FLASH_UNKNOWN) {
93         printf ("missing or unknown FLASH type\n");
94         return;
95     }
96
97     switch (info->flash_id & FLASH_VENDMASK) {
98     case (AMD_MANUFACT & FLASH_VENDMASK):
99         printf ("AMD ");
100         break;
101     case (FUJ_MANUFACT & FLASH_VENDMASK):
102         printf ("FUJITSU ");
103         break;
104     case (SST_MANUFACT & FLASH_VENDMASK):
105         printf ("SST ");
106         break;
107     default:
108         printf ("Unknown Vendor ");
109         break;
110     }
111
112     switch (info->flash_id & FLASH_TYPEMASK) {
113     case (AMD_ID_DL323B & FLASH_TYPEMASK):
114         printf("AM29DL323B (32 MBit)\n");
115         break;
116     default:
117         printf ("Unknown Chip Type\n");
118         break;
119     }
120
121     printf ("  Size: %ld MB in %d Sectors\n",
122             info->size >> 20, info->sector_count);
123
124     printf ("  Sector Start Addresses:");
125     for (i = 0; i < info->sector_count; ++i) {
126         if ((i % 5) == 0) printf ("\n   ");
127         printf (" %08lX%s",
128                 info->start[i],
129                 info->protect[i] ? " (RO)" : "     "
130                 );
131     }
132     printf ("\n");
133     return;
134 }
135
136 /*
137  * The following code cannot be run from FLASH!
138  */
139
140 static ulong flash_get_size (vu_long *addr, flash_info_t *info)
141 {
142     short i;
143     vu_long vendor[2], devid[2];
144     ulong base = (ulong)addr;
145
146     /* Reset and Write auto select command: read Manufacturer ID */
147     addr[0] = 0xf0f0f0f0;
148     addr[2 * 0x0555] = 0xAAAAAAAA;
149     addr[2 * 0x02AA] = 0x55555555;
150     addr[2 * 0x0555] = 0x90909090;
151     addr[1] = 0xf0f0f0f0;
152     addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
153     addr[2 * 0x02AA + 1] = 0x55555555;
154     addr[2 * 0x0555 + 1] = 0x90909090;
155     udelay (1000);
156
157     vendor[0] = RD_SWP32(&addr[0]);
158     vendor[1] = RD_SWP32(&addr[1]);
159     if (vendor[0] != vendor[1] || vendor[0] != AMD_MANUFACT) {
160         info->size = 0;
161         goto out;
162     }
163
164     devid[0] = RD_SWP32(&addr[2]);
165     devid[1] = RD_SWP32(&addr[3]);
166
167     if (devid[0] == AMD_ID_DL323B) {
168         /*
169         * we have 2 Banks
170         * Bank 1 (23 Sectors): 0-7=8kbyte, 8-22=64kbyte
171         * Bank 2 (48 Sectors): 23-70=64kbyte
172         */
173         info->flash_id     = (AMD_MANUFACT & FLASH_VENDMASK) |
174                              (AMD_ID_DL323B & FLASH_TYPEMASK);
175         info->sector_count = 71;
176         info->size         = 4 * (8 * 8 + 63 * 64) * 1024;
177     }
178     else {
179         info->size = 0;
180         goto out;
181     }
182
183     /* set up sector start address table */
184     for (i = 0; i < 8; i++) {
185         info->start[i] = base + (i * 0x8000);
186     }
187     for (i = 8; i < info->sector_count; i++) {
188         info->start[i] = base + (i * 0x40000) + 8 * 0x8000 - 8 * 0x40000;
189     }
190
191     /* check for protected sectors */
192     for (i = 0; i < info->sector_count; i++) {
193         /* read sector protection at sector address */
194         addr = (volatile unsigned long *)(info->start[i]);
195         addr[2 * 0x0555] = 0xAAAAAAAA;
196         addr[2 * 0x02AA] = 0x55555555;
197         addr[2 * 0x0555] = 0x90909090;
198         addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
199         addr[2 * 0x02AA + 1] = 0x55555555;
200         addr[2 * 0x0555 + 1] = 0x90909090;
201         udelay (1000);
202         base = RD_SWP32(&addr[4]);
203         base |= RD_SWP32(&addr[5]);
204         info->protect[i] = base & 0x00010001 ? 1 : 0;
205     }
206     addr = (vu_long*)info->start[0];
207
208 out:
209     /* reset command */
210     addr[0] = 0xf0f0f0f0;
211     addr[1] = 0xf0f0f0f0;
212
213     return info->size;
214 }
215
216
217 /*-----------------------------------------------------------------------
218  */
219
220 int flash_erase (flash_info_t *info, int s_first, int s_last)
221 {
222     vu_long *addr = (vu_long*)(info->start[0]);
223     int flag, prot, sect, l_sect;
224     ulong start, now, last;
225
226     if ((s_first < 0) || (s_first > s_last)) {
227         if (info->flash_id == FLASH_UNKNOWN) {
228             printf ("- missing\n");
229         } else {
230             printf ("- no sectors to erase\n");
231         }
232         return 1;
233     }
234
235     prot = 0;
236     for (sect = s_first; sect <= s_last; sect++) {
237         if (info->protect[sect]) {
238             prot++;
239         }
240     }
241
242     if (prot) {
243         printf ("- Warning: %d protected sectors will not be erased!\n",
244                 prot);
245     } else {
246         printf ("\n");
247     }
248
249     l_sect = -1;
250
251     /* Disable interrupts which might cause a timeout here */
252     flag = disable_interrupts();
253
254     addr[2 * 0x0555] = 0xAAAAAAAA;
255     addr[2 * 0x02AA] = 0x55555555;
256     addr[2 * 0x0555] = 0x80808080;
257     addr[2 * 0x0555] = 0xAAAAAAAA;
258     addr[2 * 0x02AA] = 0x55555555;
259     addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
260     addr[2 * 0x02AA + 1] = 0x55555555;
261     addr[2 * 0x0555 + 1] = 0x80808080;
262     addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
263     addr[2 * 0x02AA + 1] = 0x55555555;
264     udelay (100);
265
266     /* Start erase on unprotected sectors */
267     for (sect = s_first; sect<=s_last; sect++) {
268         if (info->protect[sect] == 0) { /* not protected */
269             addr = (vu_long*)(info->start[sect]);
270             addr[0] = 0x30303030;
271             addr[1] = 0x30303030;
272             l_sect = sect;
273         }
274     }
275
276     /* re-enable interrupts if necessary */
277     if (flag)
278       enable_interrupts();
279
280     /* wait at least 80us - let's wait 1 ms */
281     udelay (1000);
282
283     /*
284      * We wait for the last triggered sector
285      */
286     if (l_sect < 0)
287       goto DONE;
288
289     start = get_timer (0);
290     last  = start;
291     addr = (vu_long*)(info->start[l_sect]);
292     while (     (addr[0] & 0x80808080) != 0x80808080 ||
293                 (addr[1] & 0x80808080) != 0x80808080) {
294         if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
295             printf ("Timeout\n");
296             return 1;
297         }
298         /* show that we're waiting */
299         if ((now - last) > 1000) {      /* every second */
300             serial_putc ('.');
301             last = now;
302         }
303     }
304
305     DONE:
306     /* reset to read mode */
307     addr = (volatile unsigned long *)info->start[0];
308     addr[0] = 0xF0F0F0F0;       /* reset bank */
309     addr[1] = 0xF0F0F0F0;       /* reset bank */
310
311     printf (" done\n");
312     return 0;
313 }
314
315 /*-----------------------------------------------------------------------
316  * Copy memory to flash, returns:
317  * 0 - OK
318  * 1 - write timeout
319  * 2 - Flash not erased
320  */
321
322 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
323 {
324     ulong cp, wp, data;
325     int i, l, rc;
326
327     wp = (addr & ~3);   /* get lower word aligned address */
328
329     /*
330      * handle unaligned start bytes
331      */
332     if ((l = addr - wp) != 0) {
333         data = 0;
334         for (i=0, cp=wp; i<l; ++i, ++cp) {
335             data = (data << 8) | (*(uchar *)cp);
336         }
337         for (; i<4 && cnt>0; ++i) {
338             data = (data << 8) | *src++;
339             --cnt;
340             ++cp;
341         }
342         for (; cnt==0 && i<4; ++i, ++cp) {
343             data = (data << 8) | (*(uchar *)cp);
344         }
345
346         if ((rc = write_word(info, wp, data)) != 0) {
347             return (rc);
348         }
349         wp += 4;
350     }
351
352     /*
353      * handle word aligned part
354      */
355     while (cnt >= 4) {
356         data = 0;
357         for (i=0; i<4; ++i) {
358             data = (data << 8) | *src++;
359         }
360         if ((rc = write_word(info, wp, data)) != 0) {
361             return (rc);
362         }
363         wp  += 4;
364         cnt -= 4;
365     }
366
367     if (cnt == 0) {
368         return (0);
369     }
370
371     /*
372      * handle unaligned tail bytes
373      */
374     data = 0;
375     for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
376         data = (data << 8) | *src++;
377         --cnt;
378     }
379     for (; i<4; ++i, ++cp) {
380         data = (data << 8) | (*(uchar *)cp);
381     }
382
383     return (write_word(info, wp, data));
384 }
385
386 /*-----------------------------------------------------------------------
387  * Write a word to Flash, returns:
388  * 0 - OK
389  * 1 - write timeout
390  * 2 - Flash not erased
391  */
392 static int write_word (flash_info_t *info, ulong dest, ulong data)
393 {
394     vu_long *addr = (vu_long*)(info->start[0]);
395     ulong start;
396     int flag;
397
398     /* Check if Flash is (sufficiently) erased */
399     if ((*((vu_long *)dest) & data) != data) {
400         return (2);
401     }
402     /* Disable interrupts which might cause a timeout here */
403     flag = disable_interrupts();
404
405     if ((dest & 0x00000004) == 0) {
406         addr[2 * 0x0555] = 0xAAAAAAAA;
407         addr[2 * 0x02AA] = 0x55555555;
408         addr[2 * 0x0555] = 0xA0A0A0A0;
409     }
410     else {
411         addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
412         addr[2 * 0x02AA + 1] = 0x55555555;
413         addr[2 * 0x0555 + 1] = 0xA0A0A0A0;
414     }
415
416     *((vu_long *)dest) = data;
417
418     /* re-enable interrupts if necessary */
419     if (flag)
420       enable_interrupts();
421
422     /* data polling for D7 */
423     start = get_timer (0);
424     while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
425         if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
426             return (1);
427         }
428     }
429     return (0);
430 }
431
432 /*-----------------------------------------------------------------------
433  */