Merge with git://www.denx.de/git/u-boot.git
[platform/kernel/u-boot.git] / board / icecube / flash.c
1 /*
2  * (C) Copyright 2003
3  * Wolfgang Denk, DENX Software Engineering, wd@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 #include <common.h>
25
26 #ifndef CFG_FLASH_CFI_DRIVER
27 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
28
29 /* NOTE - CONFIG_FLASH_16BIT means the CPU interface is 16-bit, it
30  *        has nothing to do with the flash chip being 8-bit or 16-bit.
31  */
32 #ifdef CONFIG_FLASH_16BIT
33 typedef unsigned short FLASH_PORT_WIDTH;
34 typedef volatile unsigned short FLASH_PORT_WIDTHV;
35 #define FLASH_ID_MASK   0xFFFF
36 #else
37 typedef unsigned char FLASH_PORT_WIDTH;
38 typedef volatile unsigned char FLASH_PORT_WIDTHV;
39 #define FLASH_ID_MASK   0xFF
40 #endif
41
42 #define FPW     FLASH_PORT_WIDTH
43 #define FPWV    FLASH_PORT_WIDTHV
44
45 #define ORMASK(size) ((-size) & OR_AM_MSK)
46
47 #define FLASH_CYCLE1    0x0555
48 #define FLASH_CYCLE2    0x02aa
49
50 /*-----------------------------------------------------------------------
51  * Functions
52  */
53 static ulong flash_get_size(FPWV *addr, flash_info_t *info);
54 static void flash_reset(flash_info_t *info);
55 static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
56 static flash_info_t *flash_get_info(ulong base);
57
58 /*-----------------------------------------------------------------------
59  * flash_init()
60  *
61  * sets up flash_info and returns size of FLASH (bytes)
62  */
63 unsigned long flash_init (void)
64 {
65         unsigned long size = 0;
66         int i;
67         extern void flash_preinit(void);
68         extern void flash_afterinit(ulong);
69         ulong flashbase = CFG_FLASH_BASE;
70
71         flash_preinit();
72
73         /* Init: no FLASHes known */
74         for (i=0; i < CFG_MAX_FLASH_BANKS; ++i) {
75                 memset(&flash_info[i], 0, sizeof(flash_info_t));
76
77                 flash_info[i].size =
78                         flash_get_size((FPW *)flashbase, &flash_info[i]);
79
80                 size += flash_info[i].size;
81                 flashbase += 0x800000;
82         }
83 #if CFG_MONITOR_BASE >= CFG_FLASH_BASE
84         /* monitor protection ON by default */
85         flash_protect(FLAG_PROTECT_SET,
86                       CFG_MONITOR_BASE,
87                       CFG_MONITOR_BASE+monitor_flash_len-1,
88                       flash_get_info(CFG_MONITOR_BASE));
89 #endif
90
91 #ifdef  CFG_ENV_IS_IN_FLASH
92         /* ENV protection ON by default */
93         flash_protect(FLAG_PROTECT_SET,
94                       CFG_ENV_ADDR,
95                       CFG_ENV_ADDR+CFG_ENV_SIZE-1,
96                       flash_get_info(CFG_ENV_ADDR));
97 #endif
98
99
100         flash_afterinit(size);
101         return size ? size : 1;
102 }
103
104 /*-----------------------------------------------------------------------
105  */
106 static void flash_reset(flash_info_t *info)
107 {
108         FPWV *base = (FPWV *)(info->start[0]);
109
110         /* Put FLASH back in read mode */
111         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
112                 *base = (FPW)0x00FF00FF;        /* Intel Read Mode */
113         else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
114                 *base = (FPW)0x00F000F0;        /* AMD Read Mode */
115 }
116
117 /*-----------------------------------------------------------------------
118  */
119
120 static flash_info_t *flash_get_info(ulong base)
121 {
122         int i;
123         flash_info_t * info;
124
125         for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) {
126                 info = & flash_info[i];
127                 if (info->size &&
128                         info->start[0] <= base && base <= info->start[0] + info->size - 1)
129                         break;
130         }
131
132         return i == CFG_MAX_FLASH_BANKS ? 0 : info;
133 }
134
135 /*-----------------------------------------------------------------------
136  */
137
138 void flash_print_info (flash_info_t *info)
139 {
140         int i;
141         uchar *boottype;
142         uchar *bootletter;
143         char *fmt;
144         uchar botbootletter[] = "B";
145         uchar topbootletter[] = "T";
146         uchar botboottype[] = "bottom boot sector";
147         uchar topboottype[] = "top boot sector";
148
149         if (info->flash_id == FLASH_UNKNOWN) {
150                 printf ("missing or unknown FLASH type\n");
151                 return;
152         }
153
154         switch (info->flash_id & FLASH_VENDMASK) {
155         case FLASH_MAN_AMD:     printf ("AMD ");                break;
156         case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
157         case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
158         case FLASH_MAN_SST:     printf ("SST ");                break;
159         case FLASH_MAN_STM:     printf ("STM ");                break;
160         case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
161         default:                printf ("Unknown Vendor ");     break;
162         }
163
164         /* check for top or bottom boot, if it applies */
165         if (info->flash_id & FLASH_BTYPE) {
166                 boottype = botboottype;
167                 bootletter = botbootletter;
168         }
169         else {
170                 boottype = topboottype;
171                 bootletter = topbootletter;
172         }
173
174         switch (info->flash_id & FLASH_TYPEMASK) {
175         case FLASH_AMDLV065D:
176                 fmt = "29LV065 (64 Mbit, uniform sectors)\n";
177                 break;
178         default:
179                 fmt = "Unknown Chip Type\n";
180                 break;
181         }
182
183         printf (fmt, bootletter, boottype);
184
185         printf ("  Size: %ld MB in %d Sectors\n",
186                 info->size >> 20,
187                 info->sector_count);
188
189         printf ("  Sector Start Addresses:");
190
191         for (i=0; i<info->sector_count; ++i) {
192                 if ((i % 5) == 0) {
193                         printf ("\n   ");
194                 }
195
196                 printf (" %08lX%s", info->start[i],
197                         info->protect[i] ? " (RO)" : "     ");
198         }
199
200         printf ("\n");
201 }
202
203 /*-----------------------------------------------------------------------
204  */
205
206 /*
207  * The following code cannot be run from FLASH!
208  */
209
210 ulong flash_get_size (FPWV *addr, flash_info_t *info)
211 {
212         int i;
213         FPWV* addr2;
214
215         /* Write auto select command: read Manufacturer ID */
216         /* Write auto select command sequence and test FLASH answer */
217         addr[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* for AMD, Intel ignores this */
218         addr[FLASH_CYCLE2] = (FPW)0x00550055;   /* for AMD, Intel ignores this */
219         addr[FLASH_CYCLE1] = (FPW)0x00900090;   /* selects Intel or AMD */
220
221         /* The manufacturer codes are only 1 byte, so just use 1 byte.
222          * This works for any bus width and any FLASH device width.
223          */
224         udelay(100);
225         switch (addr[0] & 0xff) {
226
227         case (uchar)AMD_MANUFACT:
228                 info->flash_id = FLASH_MAN_AMD;
229                 break;
230
231         case (uchar)INTEL_MANUFACT:
232                 info->flash_id = FLASH_MAN_INTEL;
233                 break;
234
235         default:
236                 info->flash_id = FLASH_UNKNOWN;
237                 info->sector_count = 0;
238                 info->size = 0;
239                 break;
240         }
241
242         /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
243         if (info->flash_id != FLASH_UNKNOWN) switch ((FPW)addr[1]) {
244
245         case (FPW)AMD_ID_LV065D:
246                 info->flash_id += FLASH_AMDLV065D;
247                 info->sector_count = 128;
248                 info->size = 0x00800000;
249                 for( i = 0; i < info->sector_count; i++ )
250                         info->start[i] = (ulong)addr + (i * 0x10000);
251                 break;                          /* => 8 or 16 MB        */
252
253         default:
254                 info->flash_id = FLASH_UNKNOWN;
255                 info->sector_count = 0;
256                 info->size = 0;
257                 return (0);                     /* => no or unknown flash */
258         }
259
260         /* test for real flash at bank 1 */
261         addr2 = (FPW *)((ulong)addr | 0x800000);
262         if (addr2 != addr &&
263                 ((addr2[0] & 0xff) == (addr[0] & 0xff)) && ((FPW)addr2[1] == (FPW)addr[1])) {
264                 /* Seems 2 banks are the same space (8Mb chip is installed,
265                  * J24 in default position (CS0)). Disable this (first) bank.
266                  */
267                 info->flash_id = FLASH_UNKNOWN;
268                 info->sector_count = 0;
269                 info->size = 0;
270         }
271         /* Put FLASH back in read mode */
272         flash_reset(info);
273
274         return (info->size);
275 }
276
277 /*-----------------------------------------------------------------------
278  */
279
280 int     flash_erase (flash_info_t *info, int s_first, int s_last)
281 {
282         FPWV *addr;
283         int flag, prot, sect;
284         int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
285         ulong start, now, last;
286         int rcode = 0;
287
288         if ((s_first < 0) || (s_first > s_last)) {
289                 if (info->flash_id == FLASH_UNKNOWN) {
290                         printf ("- missing\n");
291                 } else {
292                         printf ("- no sectors to erase\n");
293                 }
294                 return 1;
295         }
296
297         switch (info->flash_id & FLASH_TYPEMASK) {
298         case FLASH_AMDLV065D:
299                 break;
300         case FLASH_UNKNOWN:
301         default:
302                 printf ("Can't erase unknown flash type %08lx - aborted\n",
303                         info->flash_id);
304                 return 1;
305         }
306
307         prot = 0;
308         for (sect=s_first; sect<=s_last; ++sect) {
309                 if (info->protect[sect]) {
310                         prot++;
311                 }
312         }
313
314         if (prot) {
315                 printf ("- Warning: %d protected sectors will not be erased!\n",
316                         prot);
317         } else {
318                 printf ("\n");
319         }
320
321         last  = get_timer(0);
322
323         /* Start erase on unprotected sectors */
324         for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
325
326                 if (info->protect[sect] != 0)   /* protected, skip it */
327                         continue;
328
329                 /* Disable interrupts which might cause a timeout here */
330                 flag = disable_interrupts();
331
332                 addr = (FPWV *)(info->start[sect]);
333                 if (intel) {
334                         *addr = (FPW)0x00500050; /* clear status register */
335                         *addr = (FPW)0x00200020; /* erase setup */
336                         *addr = (FPW)0x00D000D0; /* erase confirm */
337                 }
338                 else {
339                         /* must be AMD style if not Intel */
340                         FPWV *base;             /* first address in bank */
341
342                         base = (FPWV *)(info->start[0]);
343                         base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
344                         base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
345                         base[FLASH_CYCLE1] = (FPW)0x00800080;   /* erase mode */
346                         base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
347                         base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
348                         *addr = (FPW)0x00300030;        /* erase sector */
349                 }
350
351                 /* re-enable interrupts if necessary */
352                 if (flag)
353                         enable_interrupts();
354
355                 start = get_timer(0);
356
357                 /* wait at least 50us for AMD, 80us for Intel.
358                  * Let's wait 1 ms.
359                  */
360                 udelay (1000);
361
362                 while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
363                         if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
364                                 printf ("Timeout\n");
365
366                                 if (intel) {
367                                         /* suspend erase        */
368                                         *addr = (FPW)0x00B000B0;
369                                 }
370
371                                 flash_reset(info);      /* reset to read mode */
372                                 rcode = 1;              /* failed */
373                                 break;
374                         }
375
376                         /* show that we're waiting */
377                         if ((get_timer(last)) > CFG_HZ) {/* every second */
378                                 putc ('.');
379                                 last = get_timer(0);
380                         }
381                 }
382
383                 /* show that we're waiting */
384                 if ((get_timer(last)) > CFG_HZ) {       /* every second */
385                         putc ('.');
386                         last = get_timer(0);
387                 }
388
389                 flash_reset(info);      /* reset to read mode   */
390         }
391
392         printf (" done\n");
393         return rcode;
394 }
395
396 /*-----------------------------------------------------------------------
397  * Copy memory to flash, returns:
398  * 0 - OK
399  * 1 - write timeout
400  * 2 - Flash not erased
401  */
402 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
403 {
404         FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
405         int bytes;        /* number of bytes to program in current word         */
406         int left;         /* number of bytes left to program                    */
407         int i, res;
408
409         for (left = cnt, res = 0;
410                  left > 0 && res == 0;
411                  addr += sizeof(data), left -= sizeof(data) - bytes) {
412
413                 bytes = addr & (sizeof(data) - 1);
414                 addr &= ~(sizeof(data) - 1);
415
416                 /* combine source and destination data so can program
417                  * an entire word of 16 or 32 bits
418                  */
419                 for (i = 0; i < sizeof(data); i++) {
420                         data <<= 8;
421                         if (i < bytes || i - bytes >= left )
422                                 data += *((uchar *)addr + i);
423                         else
424                                 data += *src++;
425                 }
426
427                 /* write one word to the flash */
428                 switch (info->flash_id & FLASH_VENDMASK) {
429                 case FLASH_MAN_AMD:
430                         res = write_word_amd(info, (FPWV *)addr, data);
431                         break;
432                 default:
433                         /* unknown flash type, error! */
434                         printf ("missing or unknown FLASH type\n");
435                         res = 1;        /* not really a timeout, but gives error */
436                         break;
437                 }
438         }
439
440         return (res);
441 }
442
443 /*-----------------------------------------------------------------------
444  * Write a word to Flash for AMD FLASH
445  * A word is 16 or 32 bits, whichever the bus width of the flash bank
446  * (not an individual chip) is.
447  *
448  * returns:
449  * 0 - OK
450  * 1 - write timeout
451  * 2 - Flash not erased
452  */
453 static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
454 {
455         ulong start;
456         int flag;
457         int res = 0;    /* result, assume success       */
458         FPWV *base;             /* first address in flash bank  */
459
460         /* Check if Flash is (sufficiently) erased */
461         if ((*dest & data) != data) {
462                 return (2);
463         }
464
465
466         base = (FPWV *)(info->start[0]);
467
468         /* Disable interrupts which might cause a timeout here */
469         flag = disable_interrupts();
470
471         base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
472         base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
473         base[FLASH_CYCLE1] = (FPW)0x00A000A0;   /* selects program mode */
474
475         *dest = data;           /* start programming the data   */
476
477         /* re-enable interrupts if necessary */
478         if (flag)
479                 enable_interrupts();
480
481         start = get_timer (0);
482
483         /* data polling for D7 */
484         while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
485                 if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
486                         *dest = (FPW)0x00F000F0;        /* reset bank */
487                         res = 1;
488                 }
489         }
490
491         return (res);
492 }
493 #endif /*CFG_FLASH_CFI_DRIVER*/