]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/cmc_pu2/flash.c
Cleanup for CMC_PU2 board
[karo-tx-uboot.git] / board / cmc_pu2 / flash.c
1 /*
2  * (C) Copyright 2003-2004
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * (C) Copyright 2004
6  * Martin Krause, TQ-Systems GmbH, martin.krause@tqs.de
7  *
8  * Modified for the CMC PU2 by (C) Copyright 2004 Gary Jennejohn
9  * garyj@denx.de
10  *
11  * See file CREDITS for list of people who contributed to this
12  * project.
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License as
16  * published by the Free Software Foundation; either version 2 of
17  * the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27  * MA 02111-1307 USA
28  */
29
30 #include <common.h>
31
32 #ifndef CFG_ENV_ADDR
33 #define CFG_ENV_ADDR    (CFG_FLASH_BASE + CFG_ENV_OFFSET)
34 #endif
35
36 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
37
38 /*
39  * CPU to flash interface is 32-bit, so make declaration accordingly
40  */
41 typedef unsigned short FLASH_PORT_WIDTH;
42 typedef volatile unsigned short FLASH_PORT_WIDTHV;
43
44 #define FPW  FLASH_PORT_WIDTH
45 #define FPWV FLASH_PORT_WIDTHV
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         ulong flashbase = CFG_FLASH_BASE;
67
68         /* Init: no FLASHes known */
69         memset(&flash_info[0], 0, sizeof(flash_info_t));
70
71         flash_info[0].size =
72                 flash_get_size((FPW *)flashbase, &flash_info[0]);
73
74         size = flash_info[0].size;
75
76 #if CFG_MONITOR_BASE >= CFG_FLASH_BASE
77         /* monitor protection ON by default */
78         flash_protect(FLAG_PROTECT_SET,
79                       CFG_MONITOR_BASE,
80                       CFG_MONITOR_BASE+monitor_flash_len-1,
81                       flash_get_info(CFG_MONITOR_BASE));
82 #endif
83
84 #ifdef  CFG_ENV_IS_IN_FLASH
85         /* ENV protection ON by default */
86         flash_protect(FLAG_PROTECT_SET,
87                       CFG_ENV_ADDR,
88                       CFG_ENV_ADDR+CFG_ENV_SIZE-1,
89                       flash_get_info(CFG_ENV_ADDR));
90 #endif
91
92         return size ? size : 1;
93 }
94
95 /*-----------------------------------------------------------------------
96  */
97 static void flash_reset(flash_info_t *info)
98 {
99         FPWV *base = (FPWV *)(info->start[0]);
100
101         /* Put FLASH back in read mode */
102         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
103                 *base = (FPW)0x00FF;    /* Intel Read Mode */
104         else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
105                 *base = (FPW)0x00F0;    /* AMD Read Mode */
106 }
107
108 /*-----------------------------------------------------------------------
109  */
110
111 static flash_info_t *flash_get_info(ulong base)
112 {
113         int i;
114         flash_info_t * info;
115
116         info = NULL;
117         for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) {
118                 info = & flash_info[i];
119                 if (info->size && info->start[0] <= base &&
120                     base <= info->start[0] + info->size - 1)
121                         break;
122         }
123
124         return i == CFG_MAX_FLASH_BANKS ? 0 : info;
125 }
126
127 /*-----------------------------------------------------------------------
128  */
129
130 void flash_print_info (flash_info_t *info)
131 {
132         int i;
133
134         if (info->flash_id == FLASH_UNKNOWN) {
135                 printf ("missing or unknown FLASH type\n");
136                 return;
137         }
138
139         switch (info->flash_id & FLASH_VENDMASK) {
140         case FLASH_MAN_AMD:     printf ("AMD ");                break;
141         case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
142         case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
143         case FLASH_MAN_SST:     printf ("SST ");                break;
144         case FLASH_MAN_STM:     printf ("STM ");                break;
145         case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
146         default:                printf ("Unknown Vendor ");     break;
147         }
148
149         switch (info->flash_id & FLASH_TYPEMASK) {
150         case FLASH_S29GL064M:
151                 printf ("S29GL064M-R6 (64Mbit, uniform sector size)\n");
152                 break;
153         default:
154                 printf ("Unknown Chip Type\n");
155                 break;
156         }
157
158         printf ("  Size: %ld MB in %d Sectors\n",
159                 info->size >> 20,
160                 info->sector_count);
161
162         printf ("  Sector Start Addresses:");
163
164         for (i=0; i<info->sector_count; ++i) {
165                 if ((i % 5) == 0) {
166                         printf ("\n   ");
167                 }
168                 printf (" %08lX%s",
169                         info->start[i],
170                         info->protect[i] ? " (RO)" : "     ");
171         }
172         printf ("\n");
173         return;
174 }
175
176 /*-----------------------------------------------------------------------
177  */
178
179 /*
180  * The following code cannot be run from FLASH!
181  */
182
183 ulong flash_get_size (FPWV *addr, flash_info_t *info)
184 {
185         int i;
186         ulong base = (ulong)addr;
187
188         /* Write auto select command: read Manufacturer ID */
189         /* Write auto select command sequence and test FLASH answer */
190         addr[FLASH_CYCLE1] = (FPW)0x00AA;       /* for AMD, Intel ignores this */
191         addr[FLASH_CYCLE2] = (FPW)0x0055;       /* for AMD, Intel ignores this */
192         addr[FLASH_CYCLE1] = (FPW)0x0090;       /* selects Intel or AMD */
193
194         /* The manufacturer codes are only 1 byte, so just use 1 byte.
195          * This works for any bus width and any FLASH device width.
196          */
197         udelay(100);
198         switch (addr[0] & 0xff) {
199
200         case (uchar)AMD_MANUFACT:
201                 debug ("Manufacturer: AMD (Spansion)\n");
202                 info->flash_id = FLASH_MAN_AMD;
203                 break;
204
205         case (uchar)INTEL_MANUFACT:
206                 debug ("Manufacturer: Intel (not supported yet)\n");
207                 info->flash_id = FLASH_MAN_INTEL;
208                 break;
209
210         default:
211                 info->flash_id = FLASH_UNKNOWN;
212                 info->sector_count = 0;
213                 info->size = 0;
214                 break;
215         }
216
217         /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
218         if (info->flash_id != FLASH_UNKNOWN) switch ((FPW)addr[1]) {
219
220         case AMD_ID_MIRROR:
221                 debug ("Mirror Bit flash: addr[14] = %08X  addr[15] = %08X\n",
222                         addr[14], addr[15]);
223
224                 switch(addr[14] & 0xffff) {
225                 case (AMD_ID_GL064M_2 & 0xffff):
226                         if (addr[15] != (AMD_ID_GL064M_3 & 0xffff)) {
227                                 printf ("Chip: S29GLxxxM -> unknown\n");
228                                 info->flash_id = FLASH_UNKNOWN;
229                                 info->sector_count = 0;
230                                 info->size = 0;
231                         } else {
232                                 debug ("Chip: S29GL064M-R6\n");
233                                 info->flash_id += FLASH_S29GL064M;
234                                 info->sector_count = 128;
235                                 info->size = 0x00800000;
236                                 for (i = 0; i < info->sector_count; i++) {
237                                         info->start[i] = base;
238                                         base += 0x10000;
239                                 }
240                         }
241                         break;  /* => 16 MB     */
242                 default:
243                         printf ("Chip: *** unknown ***\n");
244                         info->flash_id = FLASH_UNKNOWN;
245                         info->sector_count = 0;
246                         info->size = 0;
247                         break;
248                 }
249                 break;
250
251         default:
252                 info->flash_id = FLASH_UNKNOWN;
253                 info->sector_count = 0;
254                 info->size = 0;
255         }
256
257         /* Put FLASH back in read mode */
258         flash_reset(info);
259
260         return (info->size);
261 }
262
263 /*-----------------------------------------------------------------------
264  */
265
266 int     flash_erase (flash_info_t *info, int s_first, int s_last)
267 {
268         FPWV *addr = (FPWV *)(info->start[0]);
269         int flag, prot, sect, ssect, l_sect;
270         ulong start, now, last;
271
272         debug ("flash_erase: first: %d last: %d\n", s_first, s_last);
273
274         if ((s_first < 0) || (s_first > s_last)) {
275                 if (info->flash_id == FLASH_UNKNOWN) {
276                         printf ("- missing\n");
277                 } else {
278                         printf ("- no sectors to erase\n");
279                 }
280                 return 1;
281         }
282
283         if ((info->flash_id == FLASH_UNKNOWN) ||
284             (info->flash_id > FLASH_AMD_COMP)) {
285                 printf ("Can't erase unknown flash type %08lx - aborted\n",
286                         info->flash_id);
287                 return 1;
288         }
289
290         prot = 0;
291         for (sect=s_first; sect<=s_last; ++sect) {
292                 if (info->protect[sect]) {
293                         prot++;
294                 }
295         }
296
297         if (prot) {
298                 printf ("- Warning: %d protected sectors will not be erased!\n",
299                         prot);
300         } else {
301                 printf ("\n");
302         }
303
304         /* Disable interrupts which might cause a timeout here */
305         flag = disable_interrupts();
306
307         /*
308          * Start erase on unprotected sectors.
309          * Since the flash can erase multiple sectors with one command
310          * we take advantage of that by doing the erase in chunks of
311          * 3 sectors.
312          */
313         for (sect = s_first; sect <= s_last; ) {
314                 l_sect = -1;
315
316                 addr[FLASH_CYCLE1] = 0x00AA;
317                 addr[FLASH_CYCLE2] = 0x0055;
318                 addr[FLASH_CYCLE1] = 0x0080;
319                 addr[FLASH_CYCLE1] = 0x00AA;
320                 addr[FLASH_CYCLE2] = 0x0055;
321
322                 /* do the erase in chunks of at most 3 sectors */
323                 for (ssect = 0; ssect < 3; ssect++) {
324                         if ((sect + ssect) > s_last)
325                                 break;
326                         if (info->protect[sect + ssect] == 0) { /* not protected */
327                                 addr = (FPWV *)(info->start[sect + ssect]);
328                                 addr[0] = 0x0030;
329                                 l_sect = sect + ssect;
330                         }
331                 }
332                 /* wait at least 80us - let's wait 1 ms */
333                 udelay (1000);
334
335                 /*
336                  * We wait for the last triggered sector
337                  */
338                 if (l_sect < 0)
339                         goto DONE;
340
341                 start = get_timer (0);
342                 last  = start;
343                 addr = (FPWV *)(info->start[l_sect]);
344                 while ((addr[0] & 0x0080) != 0x0080) {
345                         if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
346                                 printf ("Timeout\n");
347                                 return 1;
348                         }
349                         /* show that we're waiting */
350                         if ((now - last) > 1000) {      /* every second */
351                                 putc ('.');
352                                 last = now;
353                         }
354                 }
355                 addr = (FPWV *)info->start[0];
356                 addr[0] = 0x00F0;       /* reset bank */
357                 sect += ssect;
358         }
359
360         /* re-enable interrupts if necessary */
361         if (flag)
362                 enable_interrupts();
363
364 DONE:
365         /* reset to read mode */
366         addr = (FPWV *)info->start[0];
367         addr[0] = 0x00F0;       /* reset bank */
368
369         printf (" done\n");
370         return 0;
371 }
372
373 /*-----------------------------------------------------------------------
374  * Copy memory to flash, returns:
375  * 0 - OK
376  * 1 - write timeout
377  * 2 - Flash not erased
378  */
379
380 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
381 {
382         ulong wp, data;
383         int rc;
384
385         if (addr & 1) {
386                 printf ("unaligned destination not supported\n");
387                 return ERR_ALIGN;
388         };
389
390         if ((int) src & 1) {
391                 printf ("unaligned source not supported\n");
392                 return ERR_ALIGN;
393         };
394
395         wp = addr;
396
397         while (cnt >= 2) {
398                 data = *((FPWV *)src);
399                 if ((rc = write_word_amd(info, (FPW *)wp, data)) != 0) {
400                         return (rc);
401                 }
402                 src += 2;
403                 wp += 2;
404                 cnt -= 2;
405         }
406
407         if (cnt == 0) {
408                 return (0);
409         }
410
411         if (cnt == 1) {
412                 data = (*((volatile u8 *) src)) | (*((volatile u8 *) (wp + 1))
413                                 << 8);
414                 if ((rc = write_word_amd(info, (FPW *)wp, data)) != 0) {
415                         return (rc);
416                 }
417                 src += 1;
418                 wp += 1;
419                 cnt -= 1;
420         }
421
422         return ERR_OK;
423 }
424
425 /*-----------------------------------------------------------------------
426  * Write a word to Flash for AMD FLASH
427  * A word is 16 or 32 bits, whichever the bus width of the flash bank
428  * (not an individual chip) is.
429  *
430  * returns:
431  * 0 - OK
432  * 1 - write timeout
433  * 2 - Flash not erased
434  */
435 static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
436 {
437         ulong start;
438         int flag;
439         FPWV *base;             /* first address in flash bank  */
440
441         /* Check if Flash is (sufficiently) erased */
442         if ((*dest & data) != data) {
443                 return (2);
444         }
445
446         base = (FPWV *)(info->start[0]);
447
448         /* Disable interrupts which might cause a timeout here */
449         flag = disable_interrupts();
450
451         base[FLASH_CYCLE1] = (FPW)0x00AA;       /* unlock */
452         base[FLASH_CYCLE2] = (FPW)0x0055;       /* unlock */
453         base[FLASH_CYCLE1] = (FPW)0x00A0;       /* selects program mode */
454
455         *dest = data;           /* start programming the data   */
456
457         /* re-enable interrupts if necessary */
458         if (flag)
459                 enable_interrupts();
460
461         start = get_timer (0);
462
463         /* data polling for D7 */
464         while ((*dest & (FPW)0x0080) != (data & (FPW)0x0080)) {
465                 if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
466                         *dest = (FPW)0x00F0;    /* reset bank */
467                         return (1);
468                 }
469         }
470         return (0);
471 }