* Patches by David Müller, 31 Jan 2003:
[platform/kernel/u-boot.git] / board / trab / flash.c
1 /*
2  * (C) Copyright 2002
3  * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /* #define DEBUG */
25
26 #include <common.h>
27 #include <environment.h>
28
29 static ulong flash_get_size (vu_long *addr, flash_info_t *info);
30
31 flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
32
33
34 #define CMD_READ_ARRAY          0x00F000F0
35 #define CMD_UNLOCK1             0x00AA00AA
36 #define CMD_UNLOCK2             0x00550055
37 #define CMD_ERASE_SETUP         0x00800080
38 #define CMD_ERASE_CONFIRM       0x00300030
39 #define CMD_PROGRAM             0x00A000A0
40 #define CMD_UNLOCK_BYPASS       0x00200020
41 #define CMD_READ_MANF_ID        0x00900090
42
43 #define MEM_FLASH_ADDR1         (*(volatile u32 *)(CFG_FLASH_BASE + (0x00000555 << 2)))
44 #define MEM_FLASH_ADDR2         (*(volatile u32 *)(CFG_FLASH_BASE + (0x000002AA << 2)))
45
46 #define BIT_ERASE_DONE          0x00800080
47 #define BIT_RDY_MASK            0x00800080
48 #define BIT_PROGRAM_ERROR       0x00200020
49 #define BIT_TIMEOUT             0x80000000      /* our flag */
50
51 #define READY 1
52 #define ERR   2
53 #define TMO   4
54
55 /*-----------------------------------------------------------------------
56  */
57
58 ulong flash_init (void)
59 {
60         int i, j;
61         ulong size = 0;
62
63         for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
64                 ulong flashbase = 0;
65                 flash_info_t *info = &flash_info[i];
66
67                 /* Init: no FLASHes known */
68                 info->flash_id = FLASH_UNKNOWN;
69
70                 size += flash_get_size (CFG_FLASH_BASE, info);
71
72                 if (i == 0)
73                         flashbase = CFG_FLASH_BASE;
74                 else
75                         panic ("configured too many flash banks!\n");
76                 for (j = 0; j < info->sector_count; j++) {
77
78                         info->protect[j] = 0;
79                         info->start[j] = flashbase;
80
81                         switch (info->flash_id & FLASH_TYPEMASK) {
82                         case (FLASH_AM320B & FLASH_TYPEMASK):
83                                 /* Boot sector type: 8 x 8 + N x 128 kB */
84                                 flashbase += (j < 8) ? 0x4000 : 0x20000;
85                                 break;
86                         case (FLASH_AM640U & FLASH_TYPEMASK):
87                                 /* Uniform sector type: 128 kB */
88                                 flashbase += 0x20000;
89                                 break;
90                         default:
91                                 printf ("## Bad flash chip type 0x%04lX\n",
92                                         info->flash_id & FLASH_TYPEMASK);
93                         }
94                 }
95         }
96
97         /*
98          * Protect monitor and environment sectors
99          */
100         flash_protect ( FLAG_PROTECT_SET,
101                         CFG_FLASH_BASE,
102                         CFG_FLASH_BASE + _armboot_end_data - _armboot_start,
103                         &flash_info[0]);
104
105         flash_protect ( FLAG_PROTECT_SET,
106                         CFG_ENV_ADDR,
107                         CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
108
109 #ifdef CFG_ENV_ADDR_REDUND
110         flash_protect ( FLAG_PROTECT_SET,
111                         CFG_ENV_ADDR_REDUND,
112                         CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
113                         &flash_info[0]);
114 #endif
115
116         return size;
117 }
118
119 /*-----------------------------------------------------------------------
120  */
121 void flash_print_info (flash_info_t * info)
122 {
123         int i;
124
125         switch (info->flash_id & FLASH_VENDMASK) {
126         case (FLASH_MAN_AMD & FLASH_VENDMASK):
127                         printf ("AMD ");                break;
128         case (FLASH_MAN_FUJ & FLASH_VENDMASK):
129                         printf ("FUJITSU ");            break;
130         default:        printf ("Unknown Vendor ");     break;
131         }
132
133         switch (info->flash_id & FLASH_TYPEMASK) {
134         case (FLASH_AM320B & FLASH_TYPEMASK):
135                 printf ("2x Am29LV320DB (32Mbit)\n");
136                 break;
137         case (FLASH_AM640U & FLASH_TYPEMASK):
138                 printf ("2x Am29LV640D (64Mbit)\n");
139                 break;
140         default:
141                 printf ("Unknown Chip Type\n");
142                 goto Done;
143                 break;
144         }
145
146         printf ("  Size: %ld MB in %d Sectors\n",
147                         info->size >> 20, info->sector_count);
148
149         printf ("  Sector Start Addresses:");
150         for (i = 0; i < info->sector_count; i++) {
151                 if ((i % 5) == 0) {
152                         printf ("\n   ");
153                 }
154                 printf (" %08lX%s",
155                         info->start[i],
156                         info->protect[i] ? " (RO)" : "     ");
157         }
158         printf ("\n");
159
160   Done:
161 }
162
163 /*-----------------------------------------------------------------------
164  */
165
166 int flash_erase (flash_info_t * info, int s_first, int s_last)
167 {
168         ulong result;
169
170 #if 0
171         int cflag;
172 #endif
173         int iflag, prot, sect;
174         int rc = ERR_OK;
175         int chip1, chip2;
176
177         debug ("flash_erase: s_first %d  s_last %d\n", s_first, s_last);
178
179         /* first look for protection bits */
180
181         if (info->flash_id == FLASH_UNKNOWN)
182                 return ERR_UNKNOWN_FLASH_TYPE;
183
184         if ((s_first < 0) || (s_first > s_last)) {
185                 return ERR_INVAL;
186         }
187
188         if ((info->flash_id & FLASH_VENDMASK) !=
189                 (FLASH_MAN_AMD & FLASH_VENDMASK)) {
190                 return ERR_UNKNOWN_FLASH_VENDOR;
191         }
192
193         prot = 0;
194         for (sect = s_first; sect <= s_last; ++sect) {
195                 if (info->protect[sect]) {
196                         prot++;
197                 }
198         }
199
200         if (prot) {
201                 printf ("- Warning: %d protected sectors will not be erased!\n",
202                         prot);
203         } else {
204                 printf ("\n");
205         }
206
207         /*
208          * Disable interrupts which might cause a timeout
209          * here. Remember that our exception vectors are
210          * at address 0 in the flash, and we don't want a
211          * (ticker) exception to happen while the flash
212          * chip is in programming mode.
213          */
214 #if 0
215         cflag = icache_status ();
216         icache_disable ();
217 #endif
218         iflag = disable_interrupts ();
219
220         /* Start erase on unprotected sectors */
221         for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
222
223                 debug ("Erasing sector %2d @ %08lX... ",
224                         sect, info->start[sect]);
225
226                 /* arm simple, non interrupt dependent timer */
227                 reset_timer_masked ();
228
229                 if (info->protect[sect] == 0) { /* not protected */
230                         vu_long *addr = (vu_long *) (info->start[sect]);
231
232                         MEM_FLASH_ADDR1 = CMD_UNLOCK1;
233                         MEM_FLASH_ADDR2 = CMD_UNLOCK2;
234                         MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
235
236                         MEM_FLASH_ADDR1 = CMD_UNLOCK1;
237                         MEM_FLASH_ADDR2 = CMD_UNLOCK2;
238                         *addr = CMD_ERASE_CONFIRM;
239
240                         /* wait until flash is ready */
241                         chip1 = chip2 = 0;
242
243                         do {
244                                 result = *addr;
245
246                                 /* check timeout */
247                                 if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) {
248                                         MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
249                                         chip1 = TMO;
250                                         break;
251                                 }
252
253                                 if (!chip1 && (result & 0xFFFF) & BIT_ERASE_DONE)
254                                         chip1 = READY;
255
256                                 if (!chip1 && (result & 0xFFFF) & BIT_PROGRAM_ERROR)
257                                         chip1 = ERR;
258
259                                 if (!chip2 && (result >> 16) & BIT_ERASE_DONE)
260                                         chip2 = READY;
261
262                                 if (!chip2 && (result >> 16) & BIT_PROGRAM_ERROR)
263                                         chip2 = ERR;
264
265                         } while (!chip1 || !chip2);
266
267                         MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
268
269                         if (chip1 == ERR || chip2 == ERR) {
270                                 rc = ERR_PROG_ERROR;
271                                 goto outahere;
272                         }
273                         if (chip1 == TMO) {
274                                 rc = ERR_TIMOUT;
275                                 goto outahere;
276                         }
277                 }
278         }
279
280 outahere:
281         /* allow flash to settle - wait 10 ms */
282         udelay_masked (10000);
283
284         if (iflag)
285                 enable_interrupts ();
286
287 #if 0
288         if (cflag)
289                 icache_enable ();
290 #endif
291         return rc;
292 }
293
294 /*-----------------------------------------------------------------------
295  * Copy memory to flash
296  */
297
298 volatile static int write_word (flash_info_t * info, ulong dest,
299                                                                 ulong data)
300 {
301         vu_long *addr = (vu_long *) dest;
302         ulong result;
303         int rc = ERR_OK;
304
305 #if 0
306         int cflag;
307 #endif
308         int iflag;
309         int chip1, chip2;
310
311         /*
312          * Check if Flash is (sufficiently) erased
313          */
314         result = *addr;
315         if ((result & data) != data)
316                 return ERR_NOT_ERASED;
317
318         /*
319          * Disable interrupts which might cause a timeout
320          * here. Remember that our exception vectors are
321          * at address 0 in the flash, and we don't want a
322          * (ticker) exception to happen while the flash
323          * chip is in programming mode.
324          */
325 #if 0
326         cflag = icache_status ();
327         icache_disable ();
328 #endif
329         iflag = disable_interrupts ();
330
331         MEM_FLASH_ADDR1 = CMD_UNLOCK1;
332         MEM_FLASH_ADDR2 = CMD_UNLOCK2;
333         MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
334         *addr = CMD_PROGRAM;
335         *addr = data;
336
337         /* arm simple, non interrupt dependent timer */
338         reset_timer_masked ();
339
340         /* wait until flash is ready */
341         chip1 = chip2 = 0;
342         do {
343                 result = *addr;
344
345                 /* check timeout */
346                 if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) {
347                         chip1 = ERR | TMO;
348                         break;
349                 }
350                 if (!chip1 && ((result & 0x80) == (data & 0x80)))
351                         chip1 = READY;
352
353                 if (!chip1 && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) {
354                         result = *addr;
355
356                         if ((result & 0x80) == (data & 0x80))
357                                 chip1 = READY;
358                         else
359                                 chip1 = ERR;
360                 }
361
362                 if (!chip2 && ((result & (0x80 << 16)) == (data & (0x80 << 16))))
363                         chip2 = READY;
364
365                 if (!chip2 && ((result >> 16) & BIT_PROGRAM_ERROR)) {
366                         result = *addr;
367
368                         if ((result & (0x80 << 16)) == (data & (0x80 << 16)))
369                                 chip2 = READY;
370                         else
371                                 chip2 = ERR;
372                 }
373
374         } while (!chip1 || !chip2);
375
376         *addr = CMD_READ_ARRAY;
377
378         if (chip1 == ERR || chip2 == ERR || *addr != data)
379                 rc = ERR_PROG_ERROR;
380
381         if (iflag)
382                 enable_interrupts ();
383
384 #if 0
385         if (cflag)
386                 icache_enable ();
387 #endif
388
389         return rc;
390 }
391
392 /*-----------------------------------------------------------------------
393  * Copy memory to flash.
394  */
395
396 int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
397 {
398         ulong cp, wp, data;
399         int l;
400         int i, rc;
401
402         wp = (addr & ~3);       /* get lower word aligned address */
403
404         /*
405          * handle unaligned start bytes
406          */
407         if ((l = addr - wp) != 0) {
408                 data = 0;
409                 for (i = 0, cp = wp; i < l; ++i, ++cp) {
410                         data = (data >> 8) | (*(uchar *) cp << 24);
411                 }
412                 for (; i < 4 && cnt > 0; ++i) {
413                         data = (data >> 8) | (*src++ << 24);
414                         --cnt;
415                         ++cp;
416                 }
417                 for (; cnt == 0 && i < 4; ++i, ++cp) {
418                         data = (data >> 8) | (*(uchar *) cp << 24);
419                 }
420
421                 if ((rc = write_word (info, wp, data)) != 0) {
422                         return (rc);
423                 }
424                 wp += 4;
425         }
426
427         /*
428          * handle word aligned part
429          */
430         while (cnt >= 4) {
431                 data = *((vu_long *) src);
432                 if ((rc = write_word (info, wp, data)) != 0) {
433                         return (rc);
434                 }
435                 src += 4;
436                 wp += 4;
437                 cnt -= 4;
438         }
439
440         if (cnt == 0) {
441                 return ERR_OK;
442         }
443
444         /*
445          * handle unaligned tail bytes
446          */
447         data = 0;
448         for (i = 0, cp = wp; i < 4 && cnt > 0; ++i, ++cp) {
449                 data = (data >> 8) | (*src++ << 24);
450                 --cnt;
451         }
452         for (; i < 4; ++i, ++cp) {
453                 data = (data >> 8) | (*(uchar *) cp << 24);
454         }
455
456         return write_word (info, wp, data);
457 }
458
459 /*-----------------------------------------------------------------------
460  */
461
462 static ulong flash_get_size (vu_long *addr, flash_info_t *info)
463 {
464         ulong value;
465
466         /* Write auto select command sequence and read Manufacturer ID */
467         addr[0x0555] = CMD_UNLOCK1;
468         addr[0x02AA] = CMD_UNLOCK2;
469         addr[0x0555] = CMD_READ_MANF_ID;
470
471         value = addr[0];
472
473         debug ("Manuf. ID @ 0x%08lx: 0x%08lx\n", (ulong)addr, value);
474
475         switch (value) {
476         case AMD_MANUFACT:
477                 info->flash_id = FLASH_MAN_AMD;
478                 break;
479         case FUJ_MANUFACT:
480                 info->flash_id = FLASH_MAN_FUJ;
481                 break;
482         default:
483                 info->flash_id = FLASH_UNKNOWN;
484                 info->sector_count = 0;
485                 info->size = 0;
486                 addr[0] = 0x00FF00FF;           /* restore read mode */
487                 debug ("## flash_init: unknown manufacturer\n");
488                 return (0);                     /* no or unknown flash  */
489         }
490
491         value = addr[1];                        /* device ID            */
492
493         debug ("Device ID @ 0x%08lx: 0x%08lx\n", (ulong)(&addr[1]), value);
494
495         switch (value) {
496         case AMD_ID_LV320B:
497                 info->flash_id += FLASH_AM320B;
498                 info->sector_count = 71;
499                 info->size = 0x00800000;
500
501                 addr[0] = 0x00FF00FF;           /* restore read mode */
502                 break;                          /* =>  8 MB             */
503
504         case AMD_ID_LV640U:
505                 info->flash_id += FLASH_AM640U;
506                 info->sector_count = 128;
507                 info->size = 0x01000000;
508
509                 addr[0] = 0x00F000F0;           /* restore read mode */
510                 break;                          /* => 16 MB             */
511
512         default:
513                 debug ("## flash_init: unknown flash chip\n");
514                 info->flash_id = FLASH_UNKNOWN;
515                 addr[0] = 0x00FF00FF;           /* restore read mode */
516                 return (0);                     /* => no or unknown flash */
517
518         }
519
520         if (info->sector_count > CFG_MAX_FLASH_SECT) {
521                 printf ("** ERROR: sector count %d > max (%d) **\n",
522                         info->sector_count, CFG_MAX_FLASH_SECT);
523                 info->sector_count = CFG_MAX_FLASH_SECT;
524         }
525
526         return (info->size);
527 }