]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/ep8260/flash.c
* Get (mostly) rid of CFG_MONITOR_LEN definition; compute real length
[karo-tx-uboot.git] / board / ep8260 / flash.c
1 /*
2  * (C) Copyright 2001, 2002
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * (C) Copyright 2002
6  * Frank Panno <fpanno@delphintech.com>, Delphin Technology AG
7  *
8  * Flash Routines for AMD device AM29DL323DB on the EP8260 board.
9  *
10  * This file is based on board/tqm8260/flash.c.
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 <mpc8xx.h>
33
34 #define V_ULONG(a)      (*(volatile unsigned long *)( a ))
35 #define V_BYTE(a)       (*(volatile unsigned char *)( a ))
36
37
38 flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
39
40
41 /*-----------------------------------------------------------------------
42  */
43 void flash_reset(void)
44 {
45   if( flash_info[0].flash_id != FLASH_UNKNOWN ) {
46     V_ULONG( flash_info[0].start[0] ) = 0x00F000F0;
47     V_ULONG( flash_info[0].start[0] + 4 ) = 0x00F000F0;
48   }
49 }
50
51 /*-----------------------------------------------------------------------
52  */
53 ulong flash_get_size( ulong baseaddr, flash_info_t *info )
54 {
55   short i;
56   unsigned long flashtest_h, flashtest_l;
57
58   /* Write auto select command sequence and test FLASH answer */
59   V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00AA00AA;
60   V_ULONG(baseaddr + ((ulong)0x02AA << 3)) = 0x00550055;
61   V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00900090;
62   V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00AA00AA;
63   V_ULONG(baseaddr + 4 + ((ulong)0x02AA << 3)) = 0x00550055;
64   V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00900090;
65
66   flashtest_h = V_ULONG(baseaddr);              /* manufacturer ID         */
67   flashtest_l = V_ULONG(baseaddr + 4);
68
69   if ((int)flashtest_h == AMD_MANUFACT) {
70         info->flash_id = FLASH_MAN_AMD;
71   } else {
72         info->flash_id = FLASH_UNKNOWN;
73         info->sector_count = 0;
74         info->size = 0;
75         return (0);                             /* no or unknown flash     */
76   }
77
78   flashtest_h = V_ULONG(baseaddr + 8);          /* device ID               */
79   flashtest_l = V_ULONG(baseaddr + 12);
80   if (flashtest_h != flashtest_l) {
81     info->flash_id = FLASH_UNKNOWN;
82     return(0);
83   }
84   if (flashtest_h == AMD_ID_DL323B) {
85     info->flash_id += FLASH_AMDL323B;
86     info->sector_count = 71;
87     info->size = 0x01000000;                    /* 4 * 4 MB = 16 MB     */
88   } else {
89     info->flash_id = FLASH_UNKNOWN;
90     return(0);                                  /* no or unknown flash     */
91   }
92
93   /* set up sector start adress table (bottom sector type) */
94   for (i = 0; i < 8; i++) {
95     info->start[i] = baseaddr + (i * 0x00008000);
96   }
97   for (i = 8; i < info->sector_count; i++) {
98     info->start[i] = baseaddr + (i * 0x00040000) - 0x001C0000;
99   }
100
101   /* check for protected sectors */
102   for (i = 0; i < info->sector_count; i++) {
103     /* read sector protection at sector address, (A7 .. A0) = 0x02 */
104     if ((V_ULONG( info->start[i] + 16 ) & 0x00010001) ||
105         (V_ULONG( info->start[i] + 20 ) & 0x00010001)) {
106         info->protect[i] = 1;           /* D0 = 1 if protected */
107     } else {
108         info->protect[i] = 0;
109     }
110   }
111
112   flash_reset();
113   return(info->size);
114 }
115
116 /*-----------------------------------------------------------------------
117  */
118 unsigned long flash_init (void)
119 {
120     unsigned long size_b0 = 0;
121     int i;
122
123     /* Init: no FLASHes known */
124     for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
125         flash_info[i].flash_id = FLASH_UNKNOWN;
126     }
127
128     /* Static FLASH Bank configuration here (only one bank) */
129
130     size_b0 = flash_get_size(CFG_FLASH0_BASE, &flash_info[0]);
131     if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b0 == 0) {
132         printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
133                 size_b0, size_b0>>20);
134     }
135
136     /*
137      * protect monitor and environment sectors
138      */
139
140 #if CFG_MONITOR_BASE >= CFG_FLASH0_BASE
141     flash_protect(FLAG_PROTECT_SET,
142                   CFG_MONITOR_BASE,
143                   CFG_MONITOR_BASE+monitor_flash_len-1,
144                   &flash_info[0]);
145 #endif
146
147 #if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
148 # ifndef  CFG_ENV_SIZE
149 #  define CFG_ENV_SIZE  CFG_ENV_SECT_SIZE
150 # endif
151     flash_protect(FLAG_PROTECT_SET,
152                   CFG_ENV_ADDR,
153                   CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
154                   &flash_info[0]);
155 #endif
156
157     return (size_b0);
158 }
159
160 /*-----------------------------------------------------------------------
161  */
162 void flash_print_info  (flash_info_t *info)
163 {
164     int i;
165
166     if (info->flash_id == FLASH_UNKNOWN) {
167         printf ("missing or unknown FLASH type\n");
168         return;
169     }
170
171     switch ((info->flash_id >> 16) & 0xff) {
172     case FLASH_MAN_AMD:     printf ("AMD ");                break;
173     default:                printf ("Unknown Vendor ");     break;
174     }
175
176     switch (info->flash_id & FLASH_TYPEMASK) {
177     case FLASH_AMDL323B:        printf ("29DL323B (32 M, bottom sector)\n");
178                                 break;
179     default:                    printf ("Unknown Chip Type\n");
180                                 break;
181     }
182
183     printf ("  Size: %ld MB in %d Sectors\n",
184             info->size >> 20, info->sector_count);
185
186     printf ("  Sector Start Addresses:");
187     for (i=0; i<info->sector_count; ++i) {
188         if ((i % 5) == 0)
189           printf ("\n   ");
190         printf (" %08lX%s",
191                 info->start[i],
192                 info->protect[i] ? " (RO)" : "     "
193                 );
194     }
195     printf ("\n");
196     return;
197 }
198
199 /*-----------------------------------------------------------------------
200  */
201 int flash_erase (flash_info_t *info, int s_first, int s_last)
202 {
203     int flag, prot, sect, l_sect;
204     ulong start, now, last;
205
206     if ((s_first < 0) || (s_first > s_last)) {
207         if (info->flash_id == FLASH_UNKNOWN) {
208             printf ("- missing\n");
209         } else {
210             printf ("- no sectors to erase\n");
211         }
212         return 1;
213     }
214
215     prot = 0;
216     for (sect = s_first; sect <= s_last; sect++) {
217         if (info->protect[sect])
218             prot++;
219     }
220
221     if (prot) {
222         printf ("- Warning: %d protected sectors will not be erased!\n",
223                 prot);
224     } else {
225         printf ("\n");
226     }
227
228     l_sect = -1;
229
230     /* Disable interrupts which might cause a timeout here */
231     flag = disable_interrupts();
232
233     V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
234     V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
235     V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00800080;
236     V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
237     V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
238     V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
239     V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
240     V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00800080;
241     V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
242     V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
243     udelay (1000);
244
245     /* Start erase on unprotected sectors */
246     for (sect = s_first; sect<=s_last; sect++) {
247         if (info->protect[sect] == 0) { /* not protected */
248             V_ULONG( info->start[sect] ) = 0x00300030;
249             V_ULONG( info->start[sect] + 4 ) = 0x00300030;
250             l_sect = sect;
251         }
252     }
253
254     /* re-enable interrupts if necessary */
255     if (flag)
256       enable_interrupts();
257
258     /* wait at least 80us - let's wait 1 ms */
259     udelay (1000);
260
261     /*
262      * We wait for the last triggered sector
263      */
264     if (l_sect < 0)
265       goto DONE;
266
267     start = get_timer (0);
268     last  = start;
269     while ((V_ULONG( info->start[l_sect] ) & 0x00800080) != 0x00800080 ||
270            (V_ULONG( info->start[l_sect] + 4 ) & 0x00800080) != 0x00800080)
271     {
272         if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
273             printf ("Timeout\n");
274             return 1;
275         }
276         /* show that we're waiting */
277         if ((now - last) > 1000) {      /* every second */
278             serial_putc ('.');
279             last = now;
280         }
281     }
282
283     DONE:
284     /* reset to read mode */
285     flash_reset ();
286
287     printf (" done\n");
288     return 0;
289 }
290
291 static int write_dword (flash_info_t *, ulong, unsigned char *);
292
293 /*-----------------------------------------------------------------------
294  * Copy memory to flash, returns:
295  * 0 - OK
296  * 1 - write timeout
297  * 2 - Flash not erased
298  */
299
300 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
301 {
302     ulong dp;
303     static unsigned char bb[8];
304     int i, l, rc, cc = cnt;
305
306     dp = (addr & ~7);   /* get lower dword aligned address */
307
308     /*
309      * handle unaligned start bytes
310      */
311     if ((l = addr - dp) != 0) {
312         for (i = 0; i < 8; i++)
313             bb[i] = (i < l || (i-l) >= cc) ? V_BYTE(dp+i) : *src++;
314         if ((rc = write_dword(info, dp, bb)) != 0)
315         {
316             return (rc);
317         }
318         dp += 8;
319         cc -= 8 - l;
320     }
321
322     /*
323      * handle word aligned part
324      */
325     while (cc >= 8) {
326         if ((rc = write_dword(info, dp, src)) != 0) {
327             return (rc);
328         }
329         dp  += 8;
330         src += 8;
331         cc -= 8;
332     }
333
334     if (cc <= 0) {
335         return (0);
336     }
337
338     /*
339      * handle unaligned tail bytes
340      */
341     for (i = 0; i < 8; i++) {
342         bb[i] = (i < cc) ? *src++ : V_BYTE(dp+i);
343     }
344     return (write_dword(info, dp, bb));
345 }
346
347 /*-----------------------------------------------------------------------
348  * Write a dword to Flash, returns:
349  * 0 - OK
350  * 1 - write timeout
351  * 2 - Flash not erased
352  */
353 static int write_dword (flash_info_t *info, ulong dest, unsigned char * pdata)
354 {
355     ulong start;
356     ulong cl = 0, ch =0;
357     int flag, i;
358
359     for (ch=0, i=0; i < 4; i++)
360         ch = (ch << 8) + *pdata++;      /* high word    */
361     for (cl=0, i=0; i < 4; i++)
362         cl = (cl << 8) + *pdata++;      /* low word     */
363
364     /* Check if Flash is (sufficiently) erased */
365     if ((*((vu_long *)dest) & ch)       != ch
366       ||(*((vu_long *)(dest + 4)) & cl) != cl)
367     {
368         return (2);
369     }
370
371     /* Disable interrupts which might cause a timeout here */
372     flag = disable_interrupts();
373
374     V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
375     V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
376     V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00A000A0;
377     V_ULONG( dest ) = ch;
378     V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
379     V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
380     V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00A000A0;
381     V_ULONG( dest + 4 ) = cl;
382
383     /* re-enable interrupts if necessary */
384     if (flag)
385       enable_interrupts();
386
387     /* data polling for D7 */
388     start = get_timer (0);
389     while (((V_ULONG( dest ) & 0x00800080) != (ch & 0x00800080)) ||
390            ((V_ULONG( dest + 4 ) & 0x00800080) != (cl & 0x00800080))) {
391         if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
392             return (1);
393         }
394     }
395     return (0);
396 }