]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/tqc/tqm8xx/flash.c
rename CFG_ENV_IS_IN_FLASH in CONFIG_ENV_IS_IN_FLASH
[karo-tx-uboot.git] / board / tqc / tqm8xx / flash.c
1 /*
2  * (C) Copyright 2000-2004
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 #if 0
25 #define DEBUG
26 #endif
27
28 #include <common.h>
29 #include <mpc8xx.h>
30 #include <environment.h>
31
32 #include <asm/processor.h>
33
34 DECLARE_GLOBAL_DATA_PTR;
35
36 #if !defined(CONFIG_FLASH_CFI_DRIVER) /* do not use if CFI driver is configured */
37
38 #if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) \
39     && !defined(CONFIG_TQM885D)
40 # ifndef CFG_OR_TIMING_FLASH_AT_50MHZ
41 #  define CFG_OR_TIMING_FLASH_AT_50MHZ  (OR_ACS_DIV1  | OR_TRLX | OR_CSNT_SAM | \
42                                          OR_SCY_2_CLK | OR_EHTR | OR_BI)
43 # endif
44 #endif /* CONFIG_TQM8xxL/M, !TQM866M, !TQM885D */
45
46 #ifndef CFG_ENV_ADDR
47 #define CFG_ENV_ADDR    (CFG_FLASH_BASE + CFG_ENV_OFFSET)
48 #endif
49
50 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
51
52 /*-----------------------------------------------------------------------
53  * Functions
54  */
55 static ulong flash_get_size (vu_long *addr, flash_info_t *info);
56 static int write_word (flash_info_t *info, ulong dest, ulong data);
57
58 /*-----------------------------------------------------------------------
59  */
60
61 unsigned long flash_init (void)
62 {
63         volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
64         volatile memctl8xx_t *memctl = &immap->im_memctl;
65         unsigned long size_b0, size_b1;
66         int i;
67
68 #ifdef  CFG_OR_TIMING_FLASH_AT_50MHZ
69         int scy, trlx, flash_or_timing, clk_diff;
70
71         scy = (CFG_OR_TIMING_FLASH_AT_50MHZ & OR_SCY_MSK) >> 4;
72         if (CFG_OR_TIMING_FLASH_AT_50MHZ & OR_TRLX) {
73                 trlx = OR_TRLX;
74                 scy *= 2;
75         } else
76                 trlx = 0;
77
78                 /* We assume that each 10MHz of bus clock require 1-clk SCY
79                  * adjustment.
80                  */
81         clk_diff = (gd->bus_clk / 1000000) - 50;
82
83                 /* We need proper rounding here. This is what the "+5" and "-5"
84                  * are here for.
85                  */
86         if (clk_diff >= 0)
87                 scy += (clk_diff + 5) / 10;
88         else
89                 scy += (clk_diff - 5) / 10;
90
91                 /* For bus frequencies above 50MHz, we want to use relaxed timing
92                  * (OR_TRLX).
93                  */
94         if (gd->bus_clk >= 50000000)
95                 trlx = OR_TRLX;
96         else
97                 trlx = 0;
98
99         if (trlx)
100                 scy /= 2;
101
102         if (scy > 0xf)
103                 scy = 0xf;
104         if (scy < 1)
105                 scy = 1;
106
107         flash_or_timing = (scy << 4) | trlx |
108                           (CFG_OR_TIMING_FLASH_AT_50MHZ & ~(OR_TRLX | OR_SCY_MSK));
109 #endif
110         /* Init: no FLASHes known */
111         for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
112                 flash_info[i].flash_id = FLASH_UNKNOWN;
113         }
114
115         /* Static FLASH Bank configuration here - FIXME XXX */
116
117         debug ("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
118
119         size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
120
121         debug ("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE1_PRELIM);
122
123         if (flash_info[0].flash_id == FLASH_UNKNOWN) {
124                 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
125                         size_b0, size_b0<<20);
126         }
127
128         size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
129
130         debug ("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
131
132         if (size_b1 > size_b0) {
133                 printf ("## ERROR: "
134                         "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
135                         size_b1, size_b1<<20,
136                         size_b0, size_b0<<20
137                 );
138                 flash_info[0].flash_id  = FLASH_UNKNOWN;
139                 flash_info[1].flash_id  = FLASH_UNKNOWN;
140                 flash_info[0].sector_count      = -1;
141                 flash_info[1].sector_count      = -1;
142                 flash_info[0].size              = 0;
143                 flash_info[1].size              = 0;
144                 return (0);
145         }
146
147         debug  ("## Before remap: "
148                 "BR0: 0x%08x    OR0: 0x%08x    "
149                 "BR1: 0x%08x    OR1: 0x%08x\n",
150                 memctl->memc_br0, memctl->memc_or0,
151                 memctl->memc_br1, memctl->memc_or1);
152
153         /* Remap FLASH according to real size */
154 #ifndef CFG_OR_TIMING_FLASH_AT_50MHZ
155         memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
156 #else
157         memctl->memc_or0 = flash_or_timing | (-size_b0 & OR_AM_MSK);
158 #endif
159         memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
160
161         debug ("## BR0: 0x%08x    OR0: 0x%08x\n",
162                 memctl->memc_br0, memctl->memc_or0);
163
164         /* Re-do sizing to get full correct info */
165         size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
166
167 #if CFG_MONITOR_BASE >= CFG_FLASH_BASE
168         /* monitor protection ON by default */
169         debug ("Protect monitor: %08lx ... %08lx\n",
170                 (ulong)CFG_MONITOR_BASE,
171                 (ulong)CFG_MONITOR_BASE + monitor_flash_len - 1);
172
173         flash_protect(FLAG_PROTECT_SET,
174                       CFG_MONITOR_BASE,
175                       CFG_MONITOR_BASE + monitor_flash_len - 1,
176                       &flash_info[0]);
177 #endif
178
179 #ifdef  CONFIG_ENV_IS_IN_FLASH
180         /* ENV protection ON by default */
181 # ifdef CFG_ENV_ADDR_REDUND
182         debug ("Protect primary   environment: %08lx ... %08lx\n",
183                 (ulong)CFG_ENV_ADDR,
184                 (ulong)CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1);
185 # else
186         debug ("Protect environment: %08lx ... %08lx\n",
187                 (ulong)CFG_ENV_ADDR,
188                 (ulong)CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1);
189 # endif
190
191         flash_protect(FLAG_PROTECT_SET,
192                       CFG_ENV_ADDR,
193                       CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
194                       &flash_info[0]);
195 #endif
196
197 #ifdef CFG_ENV_ADDR_REDUND
198         debug ("Protect redundand environment: %08lx ... %08lx\n",
199                 (ulong)CFG_ENV_ADDR_REDUND,
200                 (ulong)CFG_ENV_ADDR_REDUND + CFG_ENV_SECT_SIZE - 1);
201
202         flash_protect(FLAG_PROTECT_SET,
203                       CFG_ENV_ADDR_REDUND,
204                       CFG_ENV_ADDR_REDUND + CFG_ENV_SECT_SIZE - 1,
205                       &flash_info[0]);
206 #endif
207
208         if (size_b1) {
209 #ifndef CFG_OR_TIMING_FLASH_AT_50MHZ
210                 memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
211 #else
212                 memctl->memc_or1 = flash_or_timing | (-size_b1 & 0xFFFF8000);
213 #endif
214                 memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
215                                     BR_MS_GPCM | BR_V;
216
217                 debug ("## BR1: 0x%08x    OR1: 0x%08x\n",
218                         memctl->memc_br1, memctl->memc_or1);
219
220                 /* Re-do sizing to get full correct info */
221                 size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
222                                           &flash_info[1]);
223
224 #if CFG_MONITOR_BASE >= CFG_FLASH_BASE
225                 /* monitor protection ON by default */
226                 flash_protect(FLAG_PROTECT_SET,
227                               CFG_MONITOR_BASE,
228                               CFG_MONITOR_BASE+monitor_flash_len-1,
229                               &flash_info[1]);
230 #endif
231
232 #ifdef  CONFIG_ENV_IS_IN_FLASH
233                 /* ENV protection ON by default */
234                 flash_protect(FLAG_PROTECT_SET,
235                               CFG_ENV_ADDR,
236                               CFG_ENV_ADDR+CFG_ENV_SIZE-1,
237                               &flash_info[1]);
238 #endif
239         } else {
240                 memctl->memc_br1 = 0;           /* invalidate bank */
241
242                 flash_info[1].flash_id = FLASH_UNKNOWN;
243                 flash_info[1].sector_count = -1;
244                 flash_info[1].size = 0;
245
246                 debug ("## DISABLE BR1: 0x%08x    OR1: 0x%08x\n",
247                         memctl->memc_br1, memctl->memc_or1);
248         }
249
250         debug ("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
251
252         flash_info[0].size = size_b0;
253         flash_info[1].size = size_b1;
254
255         return (size_b0 + size_b1);
256 }
257
258 /*-----------------------------------------------------------------------
259  */
260 void flash_print_info  (flash_info_t *info)
261 {
262         int i;
263
264         if (info->flash_id == FLASH_UNKNOWN) {
265                 printf ("missing or unknown FLASH type\n");
266                 return;
267         }
268
269         switch (info->flash_id & FLASH_VENDMASK) {
270         case FLASH_MAN_AMD:     printf ("AMD ");                break;
271         case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
272         default:                printf ("Unknown Vendor ");     break;
273         }
274
275         switch (info->flash_id & FLASH_TYPEMASK) {
276 #ifdef CONFIG_TQM8xxM   /* mirror bit flash */
277         case FLASH_AMLV128U:    printf ("AM29LV128ML (128Mbit, uniform sector size)\n");
278                                 break;
279         case FLASH_AMLV320U:    printf ("AM29LV320ML (32Mbit, uniform sector size)\n");
280                                 break;
281         case FLASH_AMLV640U:    printf ("AM29LV640ML (64Mbit, uniform sector size)\n");
282                                 break;
283         case FLASH_AMLV320B:    printf ("AM29LV320MB (32Mbit, bottom boot sect)\n");
284                                 break;
285 # else  /* ! TQM8xxM */
286         case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
287                                 break;
288         case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
289                                 break;
290         case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
291                                 break;
292         case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
293                                 break;
294         case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
295                                 break;
296         case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
297                                 break;
298 #endif  /* TQM8xxM */
299         case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
300                                 break;
301         case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
302                                 break;
303         case FLASH_AMDL163B:    printf ("AM29DL163B (16 Mbit, bottom boot sect)\n");
304                                 break;
305         default:                printf ("Unknown Chip Type\n");
306                                 break;
307         }
308
309         printf ("  Size: %ld MB in %d Sectors\n",
310                 info->size >> 20, info->sector_count);
311
312         printf ("  Sector Start Addresses:");
313         for (i=0; i<info->sector_count; ++i) {
314                 if ((i % 5) == 0)
315                         printf ("\n   ");
316                 printf (" %08lX%s",
317                         info->start[i],
318                         info->protect[i] ? " (RO)" : "     "
319                 );
320         }
321         printf ("\n");
322         return;
323 }
324
325 /*-----------------------------------------------------------------------
326  */
327
328
329 /*-----------------------------------------------------------------------
330  */
331
332 /*
333  * The following code cannot be run from FLASH!
334  */
335
336 static ulong flash_get_size (vu_long *addr, flash_info_t *info)
337 {
338         short i;
339         ulong value;
340         ulong base = (ulong)addr;
341
342         /* Write auto select command: read Manufacturer ID */
343         addr[0x0555] = 0x00AA00AA;
344         addr[0x02AA] = 0x00550055;
345         addr[0x0555] = 0x00900090;
346
347         value = addr[0];
348
349         debug ("Manuf. ID @ 0x%08lx: 0x%08lx\n", (ulong)addr, value);
350
351         switch (value) {
352         case AMD_MANUFACT:
353                 debug ("Manufacturer: AMD\n");
354                 info->flash_id = FLASH_MAN_AMD;
355                 break;
356         case FUJ_MANUFACT:
357                 debug ("Manufacturer: FUJITSU\n");
358                 info->flash_id = FLASH_MAN_FUJ;
359                 break;
360         default:
361                 debug ("Manufacturer: *** unknown ***\n");
362                 info->flash_id = FLASH_UNKNOWN;
363                 info->sector_count = 0;
364                 info->size = 0;
365                 return (0);                     /* no or unknown flash  */
366         }
367
368         value = addr[1];                        /* device ID            */
369
370         debug ("Device ID @ 0x%08lx: 0x%08lx\n", (ulong)(&addr[1]), value);
371
372         switch (value) {
373 #ifdef CONFIG_TQM8xxM   /* mirror bit flash */
374         case AMD_ID_MIRROR:
375                 debug ("Mirror Bit flash: addr[14] = %08lX  addr[15] = %08lX\n",
376                         addr[14], addr[15]);
377                 /* Special case for AMLV320MH/L */
378                 if ((addr[14] & 0x00ff00ff) == 0x001d001d &&
379                     (addr[15] & 0x00ff00ff) == 0x00000000) {
380                         debug ("Chip: AMLV320MH/L\n");
381                         info->flash_id += FLASH_AMLV320U;
382                         info->sector_count = 64;
383                         info->size = 0x00800000;        /* => 8 MB */
384                         break;
385                 }
386                 switch(addr[14]) {
387                 case AMD_ID_LV128U_2:
388                         if (addr[15] != AMD_ID_LV128U_3) {
389                                 debug ("Chip: AMLV128U -> unknown\n");
390                                 info->flash_id = FLASH_UNKNOWN;
391                         } else {
392                                 debug ("Chip: AMLV128U\n");
393                                 info->flash_id += FLASH_AMLV128U;
394                                 info->sector_count = 256;
395                                 info->size = 0x02000000;
396                         }
397                         break;                          /* => 32 MB     */
398                 case AMD_ID_LV640U_2:
399                         if (addr[15] != AMD_ID_LV640U_3) {
400                                 debug ("Chip: AMLV640U -> unknown\n");
401                                 info->flash_id = FLASH_UNKNOWN;
402                         } else {
403                                 debug ("Chip: AMLV640U\n");
404                                 info->flash_id += FLASH_AMLV640U;
405                                 info->sector_count = 128;
406                                 info->size = 0x01000000;
407                         }
408                         break;                          /* => 16 MB     */
409                 case AMD_ID_LV320B_2:
410                         if (addr[15] != AMD_ID_LV320B_3) {
411                                 debug ("Chip: AMLV320B -> unknown\n");
412                                 info->flash_id = FLASH_UNKNOWN;
413                         } else {
414                                 debug ("Chip: AMLV320B\n");
415                                 info->flash_id += FLASH_AMLV320B;
416                                 info->sector_count = 71;
417                                 info->size = 0x00800000;
418                         }
419                         break;                          /* =>  8 MB     */
420                 default:
421                         debug ("Chip: *** unknown ***\n");
422                         info->flash_id = FLASH_UNKNOWN;
423                         break;
424                 }
425                 break;
426 # else  /* ! TQM8xxM */
427         case AMD_ID_LV400T:
428                 info->flash_id += FLASH_AM400T;
429                 info->sector_count = 11;
430                 info->size = 0x00100000;
431                 break;                                  /* => 1 MB              */
432
433         case AMD_ID_LV400B:
434                 info->flash_id += FLASH_AM400B;
435                 info->sector_count = 11;
436                 info->size = 0x00100000;
437                 break;                                  /* => 1 MB              */
438
439         case AMD_ID_LV800T:
440                 info->flash_id += FLASH_AM800T;
441                 info->sector_count = 19;
442                 info->size = 0x00200000;
443                 break;                                  /* => 2 MB      */
444
445         case AMD_ID_LV800B:
446                 info->flash_id += FLASH_AM800B;
447                 info->sector_count = 19;
448                 info->size = 0x00200000;
449                 break;                                  /* => 2 MB      */
450
451         case AMD_ID_LV320T:
452                 info->flash_id += FLASH_AM320T;
453                 info->sector_count = 71;
454                 info->size = 0x00800000;
455                 break;                                  /* => 8 MB      */
456
457         case AMD_ID_LV320B:
458                 info->flash_id += FLASH_AM320B;
459                 info->sector_count = 71;
460                 info->size = 0x00800000;
461                 break;                                  /* => 8 MB      */
462 #endif  /* TQM8xxM */
463
464         case AMD_ID_LV160T:
465                 info->flash_id += FLASH_AM160T;
466                 info->sector_count = 35;
467                 info->size = 0x00400000;
468                 break;                                  /* => 4 MB      */
469
470         case AMD_ID_LV160B:
471                 info->flash_id += FLASH_AM160B;
472                 info->sector_count = 35;
473                 info->size = 0x00400000;
474                 break;                                  /* => 4 MB      */
475
476         case AMD_ID_DL163B:
477                 info->flash_id += FLASH_AMDL163B;
478                 info->sector_count = 39;
479                 info->size = 0x00400000;
480                 break;                                  /* => 4 MB      */
481
482         default:
483                 info->flash_id = FLASH_UNKNOWN;
484                 return (0);                     /* => no or unknown flash */
485         }
486
487         /* set up sector start address table */
488         switch (value) {
489 #ifdef CONFIG_TQM8xxM   /* mirror bit flash */
490         case AMD_ID_MIRROR:
491                 switch (info->flash_id & FLASH_TYPEMASK) {
492                         /* only known types here - no default */
493                 case FLASH_AMLV128U:
494                 case FLASH_AMLV640U:
495                 case FLASH_AMLV320U:
496                         for (i = 0; i < info->sector_count; i++) {
497                                 info->start[i] = base;
498                                 base += 0x20000;
499                         }
500                         break;
501                 case FLASH_AMLV320B:
502                         for (i = 0; i < info->sector_count; i++) {
503                                 info->start[i] = base;
504                                 /*
505                                  * The first 8 sectors are 8 kB,
506                                  * all the other ones  are 64 kB
507                                  */
508                                 base += (i < 8)
509                                         ?  2 * ( 8 << 10)
510                                         :  2 * (64 << 10);
511                         }
512                         break;
513                 }
514                 break;
515 # else  /* ! TQM8xxM */
516         case AMD_ID_LV400B:
517         case AMD_ID_LV800B:
518                 /* set sector offsets for bottom boot block type        */
519                 info->start[0] = base + 0x00000000;
520                 info->start[1] = base + 0x00008000;
521                 info->start[2] = base + 0x0000C000;
522                 info->start[3] = base + 0x00010000;
523                 for (i = 4; i < info->sector_count; i++) {
524                         info->start[i] = base + (i * 0x00020000) - 0x00060000;
525                 }
526                 break;
527         case AMD_ID_LV400T:
528         case AMD_ID_LV800T:
529                 /* set sector offsets for top boot block type           */
530                 i = info->sector_count - 1;
531                 info->start[i--] = base + info->size - 0x00008000;
532                 info->start[i--] = base + info->size - 0x0000C000;
533                 info->start[i--] = base + info->size - 0x00010000;
534                 for (; i >= 0; i--) {
535                         info->start[i] = base + i * 0x00020000;
536                 }
537                 break;
538         case AMD_ID_LV320B:
539                 for (i = 0; i < info->sector_count; i++) {
540                         info->start[i] = base;
541                         /*
542                          * The first 8 sectors are 8 kB,
543                          * all the other ones  are 64 kB
544                          */
545                         base += (i < 8)
546                                 ?  2 * ( 8 << 10)
547                                 :  2 * (64 << 10);
548                 }
549                 break;
550         case AMD_ID_LV320T:
551                 for (i = 0; i < info->sector_count; i++) {
552                         info->start[i] = base;
553                         /*
554                          * The last 8 sectors are 8 kB,
555                          * all the other ones  are 64 kB
556                          */
557                         base += (i < (info->sector_count - 8))
558                                 ?  2 * (64 << 10)
559                                 :  2 * ( 8 << 10);
560                 }
561                 break;
562 #endif  /* TQM8xxM */
563         case AMD_ID_LV160B:
564                 /* set sector offsets for bottom boot block type        */
565                 info->start[0] = base + 0x00000000;
566                 info->start[1] = base + 0x00008000;
567                 info->start[2] = base + 0x0000C000;
568                 info->start[3] = base + 0x00010000;
569                 for (i = 4; i < info->sector_count; i++) {
570                         info->start[i] = base + (i * 0x00020000) - 0x00060000;
571                 }
572                 break;
573         case AMD_ID_LV160T:
574                 /* set sector offsets for top boot block type           */
575                 i = info->sector_count - 1;
576                 info->start[i--] = base + info->size - 0x00008000;
577                 info->start[i--] = base + info->size - 0x0000C000;
578                 info->start[i--] = base + info->size - 0x00010000;
579                 for (; i >= 0; i--) {
580                         info->start[i] = base + i * 0x00020000;
581                 }
582                 break;
583         case AMD_ID_DL163B:
584                 for (i = 0; i < info->sector_count; i++) {
585                         info->start[i] = base;
586                         /*
587                          * The first 8 sectors are 8 kB,
588                          * all the other ones  are 64 kB
589                          */
590                         base += (i < 8)
591                                 ?  2 * ( 8 << 10)
592                                 :  2 * (64 << 10);
593                 }
594                 break;
595         default:
596                 return (0);
597                 break;
598         }
599
600 #if 0
601         /* check for protected sectors */
602         for (i = 0; i < info->sector_count; i++) {
603                 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
604                 /* D0 = 1 if protected */
605                 addr = (volatile unsigned long *)(info->start[i]);
606                 info->protect[i] = addr[2] & 1;
607         }
608 #endif
609
610         /*
611          * Prevent writes to uninitialized FLASH.
612          */
613         if (info->flash_id != FLASH_UNKNOWN) {
614                 addr = (volatile unsigned long *)info->start[0];
615
616                 *addr = 0x00F000F0;     /* reset bank */
617         }
618
619         return (info->size);
620 }
621
622
623 /*-----------------------------------------------------------------------
624  */
625
626 int     flash_erase (flash_info_t *info, int s_first, int s_last)
627 {
628         vu_long *addr = (vu_long*)(info->start[0]);
629         int flag, prot, sect, l_sect;
630         ulong start, now, last;
631
632         debug ("flash_erase: first: %d last: %d\n", s_first, s_last);
633
634         if ((s_first < 0) || (s_first > s_last)) {
635                 if (info->flash_id == FLASH_UNKNOWN) {
636                         printf ("- missing\n");
637                 } else {
638                         printf ("- no sectors to erase\n");
639                 }
640                 return 1;
641         }
642
643         if ((info->flash_id == FLASH_UNKNOWN) ||
644             (info->flash_id > FLASH_AMD_COMP)) {
645                 printf ("Can't erase unknown flash type %08lx - aborted\n",
646                         info->flash_id);
647                 return 1;
648         }
649
650         prot = 0;
651         for (sect=s_first; sect<=s_last; ++sect) {
652                 if (info->protect[sect]) {
653                         prot++;
654                 }
655         }
656
657         if (prot) {
658                 printf ("- Warning: %d protected sectors will not be erased!\n",
659                         prot);
660         } else {
661                 printf ("\n");
662         }
663
664         l_sect = -1;
665
666         /* Disable interrupts which might cause a timeout here */
667         flag = disable_interrupts();
668
669         addr[0x0555] = 0x00AA00AA;
670         addr[0x02AA] = 0x00550055;
671         addr[0x0555] = 0x00800080;
672         addr[0x0555] = 0x00AA00AA;
673         addr[0x02AA] = 0x00550055;
674
675         /* Start erase on unprotected sectors */
676         for (sect = s_first; sect<=s_last; sect++) {
677                 if (info->protect[sect] == 0) { /* not protected */
678                         addr = (vu_long*)(info->start[sect]);
679                         addr[0] = 0x00300030;
680                         l_sect = sect;
681                 }
682         }
683
684         /* re-enable interrupts if necessary */
685         if (flag)
686                 enable_interrupts();
687
688         /* wait at least 80us - let's wait 1 ms */
689         udelay (1000);
690
691         /*
692          * We wait for the last triggered sector
693          */
694         if (l_sect < 0)
695                 goto DONE;
696
697         start = get_timer (0);
698         last  = start;
699         addr = (vu_long*)(info->start[l_sect]);
700         while ((addr[0] & 0x00800080) != 0x00800080) {
701                 if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
702                         printf ("Timeout\n");
703                         return 1;
704                 }
705                 /* show that we're waiting */
706                 if ((now - last) > 1000) {      /* every second */
707                         putc ('.');
708                         last = now;
709                 }
710         }
711
712 DONE:
713         /* reset to read mode */
714         addr = (volatile unsigned long *)info->start[0];
715         addr[0] = 0x00F000F0;   /* reset bank */
716
717         printf (" done\n");
718         return 0;
719 }
720
721 /*-----------------------------------------------------------------------
722  * Copy memory to flash, returns:
723  * 0 - OK
724  * 1 - write timeout
725  * 2 - Flash not erased
726  */
727
728 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
729 {
730         ulong cp, wp, data;
731         int i, l, rc;
732
733         wp = (addr & ~3);       /* get lower word aligned address */
734
735         /*
736          * handle unaligned start bytes
737          */
738         if ((l = addr - wp) != 0) {
739                 data = 0;
740                 for (i=0, cp=wp; i<l; ++i, ++cp) {
741                         data = (data << 8) | (*(uchar *)cp);
742                 }
743                 for (; i<4 && cnt>0; ++i) {
744                         data = (data << 8) | *src++;
745                         --cnt;
746                         ++cp;
747                 }
748                 for (; cnt==0 && i<4; ++i, ++cp) {
749                         data = (data << 8) | (*(uchar *)cp);
750                 }
751
752                 if ((rc = write_word(info, wp, data)) != 0) {
753                         return (rc);
754                 }
755                 wp += 4;
756         }
757
758         /*
759          * handle word aligned part
760          */
761         while (cnt >= 4) {
762                 data = 0;
763                 for (i=0; i<4; ++i) {
764                         data = (data << 8) | *src++;
765                 }
766                 if ((rc = write_word(info, wp, data)) != 0) {
767                         return (rc);
768                 }
769                 wp  += 4;
770                 cnt -= 4;
771         }
772
773         if (cnt == 0) {
774                 return (0);
775         }
776
777         /*
778          * handle unaligned tail bytes
779          */
780         data = 0;
781         for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
782                 data = (data << 8) | *src++;
783                 --cnt;
784         }
785         for (; i<4; ++i, ++cp) {
786                 data = (data << 8) | (*(uchar *)cp);
787         }
788
789         return (write_word(info, wp, data));
790 }
791
792 /*-----------------------------------------------------------------------
793  * Write a word to Flash, returns:
794  * 0 - OK
795  * 1 - write timeout
796  * 2 - Flash not erased
797  */
798 static int write_word (flash_info_t *info, ulong dest, ulong data)
799 {
800         vu_long *addr = (vu_long*)(info->start[0]);
801         ulong start;
802         int flag;
803
804         /* Check if Flash is (sufficiently) erased */
805         if ((*((vu_long *)dest) & data) != data) {
806                 return (2);
807         }
808         /* Disable interrupts which might cause a timeout here */
809         flag = disable_interrupts();
810
811         addr[0x0555] = 0x00AA00AA;
812         addr[0x02AA] = 0x00550055;
813         addr[0x0555] = 0x00A000A0;
814
815         *((vu_long *)dest) = data;
816
817         /* re-enable interrupts if necessary */
818         if (flag)
819                 enable_interrupts();
820
821         /* data polling for D7 */
822         start = get_timer (0);
823         while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
824                 if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
825                         return (1);
826                 }
827         }
828         return (0);
829 }
830
831 /*-----------------------------------------------------------------------
832  */
833
834 #endif /* !defined(CONFIG_FLASH_CFI_DRIVER) */