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