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