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