]> git.sur5r.net Git - u-boot/blob - board/omap2420h4/flash.c
Merge with git://www.denx.de/git/u-boot.git
[u-boot] / board / omap2420h4 / flash.c
1 /*
2  * (C) Copyright 2001
3  * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
4  *
5  * (C) Copyright 2001-2004
6  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7  *
8  * (C) Copyright 2003
9  * Texas Instruments, <www.ti.com>
10  * Kshitij Gupta <Kshitij@ti.com>
11  *
12  * See file CREDITS for list of people who contributed to this
13  * project.
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License as
17  * published by the Free Software Foundation; either version 2 of
18  * the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28  * MA 02111-1307 USA
29  */
30
31 #include <common.h>
32 #include <asm/arch/sizes.h>
33 #include <linux/byteorder/swab.h>
34
35 #define PHYS_FLASH_SECT_SIZE    SZ_128K
36 flash_info_t flash_info[CFG_MAX_FLASH_BANKS];   /* info for FLASH chips    */
37
38 /* Board support for 1 or 2 flash devices */
39 #undef FLASH_PORT_WIDTH32
40 #define FLASH_PORT_WIDTH16
41
42 #ifdef FLASH_PORT_WIDTH16
43 # define FLASH_PORT_WIDTH               ushort
44 # define FLASH_PORT_WIDTHV              vu_short
45 # define SWAP(x)                        __swab16(x)
46 #else
47 # define FLASH_PORT_WIDTH               ulong
48 # define FLASH_PORT_WIDTHV              vu_long
49 # define SWAP(x)                        __swab32(x)
50 #endif
51
52 #define FPW     FLASH_PORT_WIDTH
53 #define FPWV    FLASH_PORT_WIDTHV
54
55 #define mb() __asm__ __volatile__ ("" : : : "memory")
56
57
58 /* Flash Organization Structure */
59 typedef struct OrgDef {
60         unsigned int sector_number;
61         unsigned int sector_size;
62 } OrgDef;
63
64
65 /* Flash Organizations */
66 OrgDef OrgIntel_28F256L18T[] = {
67         {4, SZ_32K},            /* 4 * 32kBytes sectors */
68         {255, SZ_128K},         /* 255 * 128kBytes sectors */
69 };
70
71
72 /*-----------------------------------------------------------------------
73  * Functions
74  */
75 unsigned long flash_init (void);
76 static ulong flash_get_size (FPW * addr, flash_info_t * info);
77 static int write_data (flash_info_t * info, ulong dest, FPW data);
78 static void flash_get_offsets (ulong base, flash_info_t * info);
79 void inline spin_wheel (void);
80 void flash_print_info (flash_info_t * info);
81 void flash_unprotect_sectors (FPWV * addr);
82 int flash_erase (flash_info_t * info, int s_first, int s_last);
83 int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt);
84 void flash_unlock(flash_info_t * info, int bank);
85 int flash_probe(void);
86
87 /*-----------------------------------------------------------------------
88  */
89
90 /* see if flash is ok */
91 int flash_probe(void)
92 {
93         return(flash_get_size ((FPW *) PHYS_FLASH_1, &flash_info[0]));
94 }
95
96 unsigned long flash_init (void)
97 {
98         int i;
99         ulong size = 0;
100         for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
101                 switch (i) {
102                 case 0:
103                         flash_get_size ((FPW *) PHYS_FLASH_1, &flash_info[i]);
104                         flash_get_offsets (PHYS_FLASH_1, &flash_info[i]);
105                         /* to reset the lock bit */
106                         flash_unlock(&flash_info[i],i);
107                         break;
108                 case 1:
109                         flash_get_size ((FPW *) PHYS_FLASH_2, &flash_info[i]);
110                         flash_get_offsets (PHYS_FLASH_2, &flash_info[i]);
111                         /* to reset the lock bit */
112                         flash_unlock(&flash_info[i],i);
113                         break;
114
115                 default:
116                         panic ("configured too many flash banks!\n");
117                         break;
118                 }
119                 size += flash_info[i].size;
120         }
121
122 #ifdef CFG_ENV_IS_IN_FLASH
123         /* Protect monitor and environment sectors
124          */
125         flash_protect (FLAG_PROTECT_SET,
126                                    CFG_FLASH_BASE,
127                                    CFG_FLASH_BASE + monitor_flash_len - 1, &flash_info[0]);
128
129         flash_protect (FLAG_PROTECT_SET,
130                                    CFG_ENV_ADDR,
131                                    CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
132 #endif
133         return size;
134 }
135
136 /*-----------------------------------------------------------------------
137  */
138 void flash_unlock(flash_info_t * info, int bank)
139 {
140         int j;
141         if (!bank)
142                 j=2;    /* leave 0,1 locked for boot bank */
143         else
144                 j=0;    /* get the whole bank for #2 */
145
146         for (;j<CFG_MAX_FLASH_SECT;j++) {
147                 FPWV *addr = (FPWV *) (info->start[j]);
148                 if (addr == NULL) {
149                         printf("Warning Flash probe failed\n");
150                         break;
151                 }
152                 flash_unprotect_sectors (addr);
153                 *addr = (FPW) 0x00500050;/* clear status register */
154                 *addr = (FPW) 0x00FF00FF;/* resest to read mode */
155         }
156 }
157
158 /*-----------------------------------------------------------------------
159  */
160 static void flash_get_offsets (ulong base, flash_info_t * info)
161 {
162         int i;
163         volatile int r;  /* gcc 3.4.0-1 strangeness, need to follow up.*/
164
165         if (info->flash_id == FLASH_UNKNOWN) {
166                 return;
167         }
168
169         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
170                 for (i = 0; i < info->sector_count; i++) {
171                         if (i > 254) { /* 255,256,257,258 */
172                                 r=i;
173                                 info->start[i] = base + (((r-(int)255) * SZ_32K) + (255*PHYS_FLASH_SECT_SIZE));
174                                 info->protect[i] = 0;
175                         } else {
176                                 info->start[i] = base + (i * PHYS_FLASH_SECT_SIZE);
177                                 info->protect[i] = 0;
178                         }
179                 }
180         }
181 }
182
183 /*-----------------------------------------------------------------------
184  */
185 void flash_print_info (flash_info_t * info)
186 {
187         int i;
188
189         if (info->flash_id == FLASH_UNKNOWN) {
190                 printf ("missing or unknown FLASH type\n");
191                 return;
192         }
193
194         switch (info->flash_id & FLASH_VENDMASK) {
195         case FLASH_MAN_INTEL:
196                 printf ("INTEL ");
197                 break;
198         default:
199                 printf ("Unknown Vendor ");
200                 break;
201         }
202
203         switch (info->flash_id & FLASH_TYPEMASK) {
204         case FLASH_28F256L18T:
205                 printf ("FLASH 28F256L18T\n");
206                 break;
207         default:
208                 printf ("Unknown Chip Type\n");
209                 break;
210         }
211
212         printf ("  Size: %ld MB in %d Sectors\n",
213                         info->size >> 20, info->sector_count);
214
215         printf ("  Sector Start Addresses:");
216         for (i = 0; i < info->sector_count; ++i) {
217                 if ((i % 5) == 0)
218                         printf ("\n   ");
219                 printf (" %08lX%s",
220                                 info->start[i], info->protect[i] ? " (RO)" : "     ");
221         }
222         printf ("\n");
223         return;
224 }
225
226 /*
227  * The following code cannot be run from FLASH!
228  */
229 static ulong flash_get_size (FPW * addr, flash_info_t * info)
230 {
231         volatile FPW value;
232         /* mb();  this one makes ARM11 err go away, but I want it :) as a guide to problems */
233
234         /* Write auto select command: read Manufacturer ID */
235         addr[0x5555] = (FPW) 0x00AA00AA;
236         addr[0x2AAA] = (FPW) 0x00550055;
237         addr[0x5555] = (FPW) 0x00900090;
238
239         mb ();
240         value = addr[0] & 0xFF; /* just looking for 89 (8989 is hw pat)*/
241
242         switch (value) {
243
244         case (FPW) INTEL_MANUFACT:
245                 info->flash_id = FLASH_MAN_INTEL;
246                 break;
247
248         default:
249                 info->flash_id = FLASH_UNKNOWN;
250                 info->sector_count = 0;
251                 info->size = 0;
252                 addr[0] = (FPW) 0x00FF00FF;     /* restore read mode */
253                 return(0);                 /* no or unknown flash       */
254         }
255
256         mb ();
257         value = addr[1];        /* device ID */
258         switch (value) {
259
260         case (FPW) (INTEL_ID_28F256L18T):        /* 880D */
261                 info->flash_id += FLASH_28F256L18T;
262                 info->sector_count = 259;       /*0-258*/
263                 info->size = SZ_32M;
264                 break;                  /* => 32 MB     */
265
266         default:
267                 info->flash_id = FLASH_UNKNOWN;
268                 break;
269         }
270
271         if (info->sector_count > CFG_MAX_FLASH_SECT) {
272                 printf ("** ERROR: sector count %d > max (%d) **\n",
273                                 info->sector_count, CFG_MAX_FLASH_SECT);
274                 info->sector_count = CFG_MAX_FLASH_SECT;
275         }
276
277         addr[0] = (FPW) 0x00FF00FF;     /* restore read mode */
278
279         return(info->size);
280 }
281
282
283 /* unprotects a sector for write and erase
284  * on some intel parts, this unprotects the entire chip, but it
285  * wont hurt to call this additional times per sector...
286  */
287 void flash_unprotect_sectors (FPWV * addr)
288 {
289 #define PD_FINTEL_WSMS_READY_MASK    0x0080
290
291         *addr = (FPW) 0x00500050;       /* clear status register */
292
293         /* this sends the clear lock bit command */
294         *addr = (FPW) 0x00600060;
295         *addr = (FPW) 0x00D000D0;
296 }
297
298
299 /*-----------------------------------------------------------------------
300  */
301
302 int flash_erase (flash_info_t * info, int s_first, int s_last)
303 {
304         int prot, sect;
305         ulong type, start, last;
306         int rcode = 0;
307 #ifdef CONFIG_USE_IRQ
308         int iflag;
309 #endif
310
311         if ((s_first < 0) || (s_first > s_last)) {
312                 if (info->flash_id == FLASH_UNKNOWN) {
313                         printf ("- missing\n");
314                 } else {
315                         printf ("- no sectors to erase\n");
316                 }
317                 return 1;
318         }
319
320         type = (info->flash_id & FLASH_VENDMASK);
321         if ((type != FLASH_MAN_INTEL)) {
322                 printf ("Can't erase unknown flash type %08lx - aborted\n",
323                                 info->flash_id);
324                 return 1;
325         }
326
327         prot = 0;
328         for (sect = s_first; sect <= s_last; ++sect) {
329                 if (info->protect[sect]) {
330                         prot++;
331                 }
332         }
333
334         if (prot) {
335                 printf ("- Warning: %d protected sectors will not be erased!\n",
336                                 prot);
337         } else {
338                 printf ("\n");
339         }
340
341
342         start = get_timer (0);
343         last = start;
344
345 #ifdef CONFIG_USE_IRQ
346         /* Disable interrupts which might cause a timeout here */
347         iflag = disable_interrupts ();
348 #endif
349
350         /* Start erase on unprotected sectors */
351         for (sect = s_first; sect <= s_last; sect++) {
352                 if (info->protect[sect] == 0) { /* not protected */
353                         FPWV *addr = (FPWV *) (info->start[sect]);
354                         FPW status;
355
356                         printf ("Erasing sector %2d ... ", sect);
357
358                         flash_unprotect_sectors (addr);
359
360                         /* arm simple, non interrupt dependent timer */
361                         reset_timer_masked ();
362
363                         *addr = (FPW) 0x00500050;/* clear status register */
364                         *addr = (FPW) 0x00200020;/* erase setup */
365                         *addr = (FPW) 0x00D000D0;/* erase confirm */
366
367                         while (((status =
368                                          *addr) & (FPW) 0x00800080) !=
369                                    (FPW) 0x00800080) {
370                                 if (get_timer_masked () >
371                                         CFG_FLASH_ERASE_TOUT) {
372                                         printf ("Timeout\n");
373                                         /* suspend erase     */
374                                         *addr = (FPW) 0x00B000B0;
375                                         /* reset to read mode */
376                                         *addr = (FPW) 0x00FF00FF;
377                                         rcode = 1;
378                                         break;
379                                 }
380                         }
381
382                         /* clear status register cmd.   */
383                         *addr = (FPW) 0x00500050;
384                         *addr = (FPW) 0x00FF00FF;/* resest to read mode */
385                         printf (" done\n");
386                 }
387         }
388 #ifdef CONFIG_USE_IRQ
389         if (iflag)
390                 enable_interrupts();
391 #endif
392
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  * 4 - Flash not identified
402  */
403
404 int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
405 {
406         ulong cp, wp;
407         FPW data;
408         int count, i, l, rc, port_width;
409
410         if (info->flash_id == FLASH_UNKNOWN) {
411                 return 4;
412         }
413 /* get lower word aligned address */
414 #ifdef FLASH_PORT_WIDTH16
415         wp = (addr & ~1);
416         port_width = 2;
417 #else
418         wp = (addr & ~3);
419         port_width = 4;
420 #endif
421
422         /*
423          * handle unaligned start bytes
424          */
425         if ((l = addr - wp) != 0) {
426                 data = 0;
427                 for (i = 0, cp = wp; i < l; ++i, ++cp) {
428                         data = (data << 8) | (*(uchar *) cp);
429                 }
430                 for (; i < port_width && cnt > 0; ++i) {
431                         data = (data << 8) | *src++;
432                         --cnt;
433                         ++cp;
434                 }
435                 for (; cnt == 0 && i < port_width; ++i, ++cp) {
436                         data = (data << 8) | (*(uchar *) cp);
437                 }
438
439                 if ((rc = write_data (info, wp, SWAP (data))) != 0) {
440                         return(rc);
441                 }
442                 wp += port_width;
443         }
444
445         /*
446          * handle word aligned part
447          */
448         count = 0;
449         while (cnt >= port_width) {
450                 data = 0;
451                 for (i = 0; i < port_width; ++i) {
452                         data = (data << 8) | *src++;
453                 }
454                 if ((rc = write_data (info, wp, SWAP (data))) != 0) {
455                         return(rc);
456                 }
457                 wp += port_width;
458                 cnt -= port_width;
459                 if (count++ > 0x800) {
460                         spin_wheel ();
461                         count = 0;
462                 }
463         }
464
465         if (cnt == 0) {
466                 return(0);
467         }
468
469         /*
470          * handle unaligned tail bytes
471          */
472         data = 0;
473         for (i = 0, cp = wp; i < port_width && cnt > 0; ++i, ++cp) {
474                 data = (data << 8) | *src++;
475                 --cnt;
476         }
477         for (; i < port_width; ++i, ++cp) {
478                 data = (data << 8) | (*(uchar *) cp);
479         }
480
481         return(write_data (info, wp, SWAP (data)));
482 }
483
484 /*-----------------------------------------------------------------------
485  * Write a word or halfword to Flash, returns:
486  * 0 - OK
487  * 1 - write timeout
488  * 2 - Flash not erased
489  */
490 static int write_data (flash_info_t * info, ulong dest, FPW data)
491 {
492         FPWV *addr = (FPWV *) dest;
493         ulong status;
494 #ifdef CONFIG_USE_IRQ
495         int iflag;
496 #endif
497
498         /* Check if Flash is (sufficiently) erased */
499         if ((*addr & data) != data) {
500                 printf ("not erased at %08lx (%x)\n", (ulong) addr, *addr);
501                 return(2);
502         }
503         /* Disable interrupts which might cause a timeout here */
504 #ifdef CONFIG_USE_IRQ
505         iflag = disable_interrupts ();
506 #endif
507         *addr = (FPW) 0x00400040;       /* write setup */
508         *addr = data;
509
510         /* arm simple, non interrupt dependent timer */
511         reset_timer_masked ();
512
513         /* wait while polling the status register */
514         while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) {
515                 if (get_timer_masked () > CFG_FLASH_WRITE_TOUT) {
516                         *addr = (FPW) 0x00FF00FF;       /* restore read mode */
517                         return(1);
518                 }
519         }
520         *addr = (FPW) 0x00FF00FF;       /* restore read mode */
521
522 #ifdef CONFIG_USE_IRQ
523         if (iflag)
524                 enable_interrupts();
525 #endif
526
527         return(0);
528 }
529
530 void inline spin_wheel (void)
531 {
532         static int p = 0;
533         static char w[] = "\\/-";
534
535         printf ("\010%c", w[p]);
536         (++p == 3) ? (p = 0) : 0;
537 }