]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - board/emk/top860/flash.c
* Code cleanup:
[karo-tx-uboot.git] / board / emk / top860 / flash.c
1 /*
2  * (C) Copyright 2003
3  * EMK Elektronik GmbH <www.emk-elektronik.de>
4  * Reinhard Meyer <r.meyer@emk-elektronik.de>
5  *
6  * copied from the BMW Port - seems that its similiar enough
7  * to be easily adaped ;) --- Well, it turned out to become a
8  * merger between parts of the EMKstax Flash routines and the
9  * BMW funtion frames...
10  *
11  * (C) Copyright 2000
12  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
13  *
14  * See file CREDITS for list of people who contributed to this
15  * project.
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License as
19  * published by the Free Software Foundation; either version 2 of
20  * the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30  * MA 02111-1307 USA
31  */
32
33 #include <common.h>
34 #include <mpc8xx.h>
35
36 #define FLASH_WORD_SIZE         unsigned short
37 #define FLASH_WORD_WIDTH        (sizeof (FLASH_WORD_SIZE))
38
39 flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips    */
40
41 /*-----------------------------------------------------------------------
42  * Functions
43  */
44 static int write_word (flash_info_t *info, ulong dest, ulong data);
45
46
47 /*****************************************************************************
48  * software product ID entry/exit
49  *****************************************************************************/
50 static void FlashProductIdMode (
51         volatile FLASH_WORD_SIZE *b,
52         int on_off)
53 {
54         b[0x5555] = 0xaa;
55         b[0x2aaa] = 0x55;
56         b[0x5555] = on_off ? 0x90 : 0xf0;
57 }
58
59 /*****************************************************************************
60  * sector erase start
61  *****************************************************************************/
62 static void FlashSectorErase (
63         volatile FLASH_WORD_SIZE *b,
64         volatile FLASH_WORD_SIZE *a)
65 {
66         b[0x5555] = 0xaa;
67         b[0x2aaa] = 0x55;
68         b[0x5555] = 0x80;
69         b[0x5555] = 0xaa;
70         b[0x2aaa] = 0x55;
71         a[0] = 0x30;
72 }
73
74 /*****************************************************************************
75  * program a word
76  *****************************************************************************/
77 static void FlashProgWord (
78         volatile FLASH_WORD_SIZE *b,
79         volatile FLASH_WORD_SIZE *a,
80         FLASH_WORD_SIZE v)
81 {
82         b[0x5555] = 0xaa;
83         b[0x2aaa] = 0x55;
84         b[0x5555] = 0xa0;
85         a[0] = v;
86 }
87
88 /*****************************************************************************
89  * reset bank, back to read mode
90  *****************************************************************************/
91 static void FlashReset (volatile FLASH_WORD_SIZE *b)
92 {
93         b[0] = 0xf0;
94 }
95
96 /*****************************************************************************
97  * identify FLASH chip
98  * this code is a stripped version of the FlashGetType() function in EMKstax
99  *****************************************************************************/
100 unsigned long flash_init (void)
101 {
102         volatile FLASH_WORD_SIZE * const flash = (volatile FLASH_WORD_SIZE *) CFG_FLASH_BASE;
103         FLASH_WORD_SIZE manu, dev;
104         flash_info_t * const pflinfo = &flash_info[0];
105         int j;
106
107         /* get Id Bytes */
108         FlashProductIdMode (flash, 1);
109         manu = flash[0];
110         dev  = flash[1];
111         FlashProductIdMode (flash, 0);
112
113         pflinfo->size = 0;
114         pflinfo->sector_count = 0;
115         pflinfo->flash_id = 0xffffffff;
116         pflinfo->portwidth = FLASH_CFI_16BIT;
117         pflinfo->chipwidth = FLASH_CFI_BY16;
118
119         switch (manu&0xff)
120         {
121         case 0x01:      /* AMD */
122                 pflinfo->flash_id = FLASH_MAN_AMD;
123                 switch (dev&0xff)
124                 {
125                 case 0x49:
126                         pflinfo->size = 0x00200000;
127                         pflinfo->sector_count = 35;
128                         pflinfo->flash_id |= FLASH_AM160B;
129                         pflinfo->start[0] = CFG_FLASH_BASE;
130                         pflinfo->start[1] = CFG_FLASH_BASE + 0x4000;
131                         pflinfo->start[2] = CFG_FLASH_BASE + 0x6000;
132                         pflinfo->start[3] = CFG_FLASH_BASE + 0x8000;
133                         for (j = 4; j < 35; j++)
134                         {
135                                 pflinfo->start[j] = CFG_FLASH_BASE + 0x00010000 * (j-3);
136                         }
137                         break;
138
139                 case 0xf9:
140                         pflinfo->size = 0x00400000;
141                         pflinfo->sector_count = 71;
142                         pflinfo->flash_id |= FLASH_AM320B;
143                         pflinfo->start[0] = CFG_FLASH_BASE;
144                         pflinfo->start[1] = CFG_FLASH_BASE + 0x4000;
145                         pflinfo->start[2] = CFG_FLASH_BASE + 0x6000;
146                         pflinfo->start[3] = CFG_FLASH_BASE + 0x8000;
147                         for (j = 0; j < 8; j++)
148                         {
149                                 pflinfo->start[j] = CFG_FLASH_BASE + 0x00002000 * (j);
150                         }
151                         for (j = 8; j < 71; j++)
152                         {
153                                 pflinfo->start[j] = CFG_FLASH_BASE + 0x00010000 * (j-7);
154                         }
155                         break;
156
157                 default:
158                         printf ("unknown AMD dev=%x ", dev);
159                         pflinfo->flash_id |= FLASH_UNKNOWN;
160                 }
161                 break;
162
163         default:
164                 printf ("unknown manu=%x ", manu);
165         }
166         return pflinfo->size;
167 }
168
169 /*****************************************************************************
170  * print info about a FLASH
171  *****************************************************************************/
172 void flash_print_info (flash_info_t *info)
173 {
174         static const char       unk[] = "Unknown";
175         unsigned int            i;
176         const char                      *mfct=unk,
177                                                 *type=unk;
178
179         if(info->flash_id != FLASH_UNKNOWN)
180         {
181                 switch (info->flash_id & FLASH_VENDMASK)
182                 {
183                 case FLASH_MAN_AMD:
184                         mfct = "AMD";
185                         break;
186                 }
187
188                 switch (info->flash_id & FLASH_TYPEMASK)
189                 {
190                 case FLASH_AM160B:
191                         type = "AM29LV160B (16 Mbit, bottom boot sect)";
192                         break;
193                 case FLASH_AM320B:
194                         type = "AM29LV320B (32 Mbit, bottom boot sect)";
195                         break;
196                 }
197         }
198
199         printf (
200                 "\n  Brand: %s Type: %s\n"
201                 "  Size: %lu KB in %d Sectors\n",
202                 mfct,
203                 type,
204                 info->size >> 10,
205                 info->sector_count
206                 );
207
208         printf ("  Sector Start Addresses:");
209
210         for (i = 0; i < info->sector_count; i++)
211         {
212                 unsigned long   size;
213                 unsigned int    erased;
214                 unsigned long   *flash = (unsigned long *) info->start[i];
215
216                 /*
217                  * Check if whole sector is erased
218                  */
219                 size =
220                         (i != (info->sector_count - 1)) ?
221                         (info->start[i + 1] - info->start[i]) >> 2 :
222                 (info->start[0] + info->size - info->start[i]) >> 2;
223
224                 for (
225                         flash = (unsigned long *) info->start[i], erased = 1;
226                                 (flash != (unsigned long *) info->start[i] + size) && erased;
227                                         flash++
228                         )
229                         erased = *flash == ~0x0UL;
230
231                 printf (
232                         "%s %08lX %s %s",
233                         (i % 5) ? "" : "\n   ",
234                         info->start[i],
235                         erased ? "E" : " ",
236                         info->protect[i] ? "RO" : "  "
237                         );
238         }
239
240         puts ("\n");
241         return;
242 }
243
244 /*****************************************************************************
245  * erase one or more sectors
246  *****************************************************************************/
247 int     flash_erase (flash_info_t *info, int s_first, int s_last)
248 {
249         volatile FLASH_WORD_SIZE        *addr = (FLASH_WORD_SIZE *)(info->start[0]);
250         int                                                     flag,
251                                                                 prot,
252                                                                 sect,
253                                                                 l_sect;
254         ulong                                           start,
255                                                                 now,
256                                                                 last;
257
258         if ((s_first < 0) || (s_first > s_last))
259         {
260                 if (info->flash_id == FLASH_UNKNOWN)
261                 {
262                         printf ("- missing\n");
263                 }
264                 else
265                 {
266                         printf ("- no sectors to erase\n");
267                 }
268                 return 1;
269         }
270
271         if ((info->flash_id == FLASH_UNKNOWN) ||
272                 (info->flash_id > (FLASH_MAN_STM | FLASH_AMD_COMP)))
273         {
274                 printf ("Can't erase unknown flash type - aborted\n");
275                 return 1;
276         }
277
278         prot = 0;
279         for (sect=s_first; sect<=s_last; ++sect)
280         {
281                 if (info->protect[sect])
282                 {
283                         prot++;
284                 }
285         }
286
287         if (prot)
288         {
289                 printf ("- Warning: %d protected sectors will not be erased!\n",
290                         prot);
291         }
292         else
293         {
294                 printf ("\n");
295         }
296
297         l_sect = -1;
298
299         /* Disable interrupts which might cause a timeout here */
300         flag = disable_interrupts();
301
302         /* Start erase on unprotected sectors */
303         for (sect = s_first; sect<=s_last; sect++)
304         {
305                 if (info->protect[sect] == 0)
306                 { /* not protected */
307                         FlashSectorErase ((FLASH_WORD_SIZE *)info->start[0], (FLASH_WORD_SIZE *)info->start[sect]);
308                         l_sect = sect;
309                 }
310         }
311
312         /* re-enable interrupts if necessary */
313         if (flag)
314                 enable_interrupts();
315
316         /* wait at least 80us - let's wait 1 ms */
317         udelay (1000);
318
319         /*
320         * We wait for the last triggered sector
321         */
322         if (l_sect < 0)
323                 goto DONE;
324
325         start = get_timer (0);
326         last  = start;
327         addr = (FLASH_WORD_SIZE *)info->start[l_sect];
328         while ((addr[0] & 0x0080) != 0x0080)
329         {
330                 if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT)
331                 {
332                         printf ("Timeout\n");
333                         return 1;
334                 }
335                 /* show that we're waiting */
336                 if ((now - last) > 1000)
337                 {  /* every second */
338                         serial_putc ('.');
339                         last = now;
340                 }
341         }
342
343         DONE:
344         /* reset to read mode */
345         FlashReset ((FLASH_WORD_SIZE *)info->start[0]);
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 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
358 {
359         ulong           cp,
360                                 wp,
361                                 data;
362         int                     i,
363                                 l,
364                                 rc;
365
366         wp = (addr & ~(FLASH_WORD_WIDTH-1));   /* get lower word aligned address */
367
368         /*
369          * handle unaligned start bytes, if there are...
370          */
371         if ((l = addr - wp) != 0)
372         {
373                 data = 0;
374
375                 /* get the current before the new data into our data word */
376                 for (i=0, cp=wp; i<l; ++i, ++cp)
377                 {
378                         data = (data << 8) | (*(uchar *)cp);
379                 }
380
381                 /* now merge the to be programmed values */
382                 for (; i<4 && cnt>0; ++i, ++cp, --cnt)
383                 {
384                         data = (data << 8) | *src++;
385                 }
386
387                 /* get the current after the new data into our data word */
388                 for (; cnt==0 && i<FLASH_WORD_WIDTH; ++i, ++cp)
389                 {
390                         data = (data << 8) | (*(uchar *)cp);
391                 }
392
393                 /* now write the combined word */
394                 if ((rc = write_word (info, wp, data)) != 0)
395                 {
396                         return (rc);
397                 }
398                 wp += FLASH_WORD_WIDTH;
399         }
400
401         /*
402          * handle word aligned part
403          */
404         while (cnt >= FLASH_WORD_WIDTH)
405         {
406                 data = 0;
407                 for (i=0; i<FLASH_WORD_WIDTH; ++i)
408                 {
409                         data = (data << 8) | *src++;
410                 }
411                 if ((rc = write_word (info, wp, data)) != 0)
412                 {
413                         return (rc);
414                 }
415                 wp  += FLASH_WORD_WIDTH;
416                 cnt -= FLASH_WORD_WIDTH;
417         }
418
419         if (cnt == 0)
420         {
421                 return (0);
422         }
423
424         /*
425          * handle unaligned tail bytes, if there are...
426          */
427         data = 0;
428
429         /* now merge the to be programmed values */
430         for (i=0, cp=wp; i<FLASH_WORD_WIDTH && cnt>0; ++i, ++cp)
431         {
432                 data = (data << 8) | *src++;
433                 --cnt;
434         }
435
436         /* get the current after the new data into our data word */
437         for (; i<FLASH_WORD_WIDTH; ++i, ++cp)
438         {
439                 data = (data << 8) | (*(uchar *)cp);
440         }
441
442         /* now write the combined word */
443         return (write_word (info, wp, data));
444 }
445
446 /*****************************************************************************
447  * Write a word to Flash, returns:
448  * 0 - OK
449  * 1 - write timeout
450  * 2 - Flash not erased
451  *****************************************************************************/
452 static int write_word (flash_info_t *info, ulong dest, ulong data)
453 {
454         volatile FLASH_WORD_SIZE        *addr2 = (FLASH_WORD_SIZE *)info->start[0];
455         volatile FLASH_WORD_SIZE        *dest2 = (FLASH_WORD_SIZE *)dest;
456         FLASH_WORD_SIZE                         data2 = data;
457         ulong                                           start;
458         int                                                     flag;
459
460         /* Check if Flash is (sufficiently) erased */
461         if ((*dest2 & data2) != data2)
462         {
463                 return (2);
464         }
465
466         /* Disable interrupts which might cause a timeout here */
467         flag = disable_interrupts ();
468
469         FlashProgWord (addr2, dest2, data2);
470
471         /* re-enable interrupts if necessary */
472         if (flag)
473                 enable_interrupts ();
474
475         /* data polling for D7 */
476         start = get_timer (0);
477         while ((*dest2 & 0x0080) != (data2 & 0x0080))
478         {
479                 if (get_timer (start) > CFG_FLASH_WRITE_TOUT)
480                 {
481                         return (1);
482                 }
483         }
484
485         return (0);
486 }
487
488 /*-----------------------------------------------------------------------
489  */