]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/sc520_cdp/flash.c
* Patch by Daniel Engström, 13 Nov 2002:
[karo-tx-uboot.git] / board / sc520_cdp / flash.c
1 /*
2  * (C) Copyright 2002
3  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
4  * Alex Zuepke <azu@sysgo.de>
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24
25 #include <common.h>
26
27 ulong myflush(void);
28
29
30 #define FLASH_BANK_SIZE 0x400000        /* 4 MB */
31 #define MAIN_SECT_SIZE  0x20000         /* 128 KB */
32
33 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
34
35
36 #define CMD_READ_ARRAY          0x00F000F0
37 #define CMD_UNLOCK1             0x00AA00AA
38 #define CMD_UNLOCK2             0x00550055
39 #define CMD_ERASE_SETUP         0x00800080
40 #define CMD_ERASE_CONFIRM       0x00300030
41 #define CMD_PROGRAM             0x00A000A0
42 #define CMD_UNLOCK_BYPASS       0x00200020
43
44 #define MEM_FLASH_ADDR1         (*(volatile u32 *)(CFG_FLASH_BASE + (0x00000555 << 2)))
45 #define MEM_FLASH_ADDR2         (*(volatile u32 *)(CFG_FLASH_BASE + (0x000002AA << 2)))
46
47 #define BIT_ERASE_DONE          0x00800080
48 #define BIT_RDY_MASK            0x00800080
49 #define BIT_PROGRAM_ERROR       0x00200020
50 #define BIT_TIMEOUT             0x80000000 /* our flag */
51
52 #define READY 1
53 #define ERR   2
54 #define TMO   4
55
56 /*-----------------------------------------------------------------------
57  */
58
59 ulong flash_init(void)
60 {
61     int i, j;
62     ulong size = 0;
63
64     for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
65     {
66         ulong flashbase = 0;
67         flash_info[i].flash_id =
68           (AMD_MANUFACT & FLASH_VENDMASK) |
69           (AMD_ID_LV160B & FLASH_TYPEMASK);
70         flash_info[i].size = FLASH_BANK_SIZE;
71         flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
72         memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
73         if (i == 0)
74           flashbase = PHYS_FLASH_1;
75         else
76           panic("configured to many flash banks!\n");
77         for (j = 0; j < flash_info[i].sector_count; j++)
78         {
79
80             if (j <= 3)
81             {
82                 /* 1st one is 32 KB */
83                 if (j == 0)
84                 {
85                         flash_info[i].start[j] = flashbase + 0;
86                 }
87
88                 /* 2nd and 3rd are both 16 KB */
89                 if ((j == 1) || (j == 2))
90                 {
91                         flash_info[i].start[j] = flashbase + 0x8000 + (j-1)*0x4000;
92                 }
93
94                 /* 4th 64 KB */
95                 if (j == 3)
96                 {
97                         flash_info[i].start[j] = flashbase + 0x10000;
98                 }
99             }
100             else
101             {
102                 flash_info[i].start[j] = flashbase + (j - 3)*MAIN_SECT_SIZE;
103             }
104         }
105         size += flash_info[i].size;
106     }
107
108     /*
109      * Protect monitor and environment sectors
110      */
111     flash_protect(FLAG_PROTECT_SET,
112                   i386boot_start-CFG_FLASH_BASE,
113                   i386boot_end-CFG_FLASH_BASE,
114                   &flash_info[0]);
115
116     flash_protect(FLAG_PROTECT_SET,
117                   CFG_ENV_ADDR,
118                   CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
119                   &flash_info[0]);
120     return size;
121 }
122
123 /*-----------------------------------------------------------------------
124  */
125 void flash_print_info  (flash_info_t *info)
126 {
127     int i;
128
129     switch (info->flash_id & FLASH_VENDMASK)
130     {
131     case (AMD_MANUFACT & FLASH_VENDMASK):
132         printf("AMD: ");
133         break;
134     default:
135         printf("Unknown Vendor ");
136         break;
137     }
138
139     switch (info->flash_id & FLASH_TYPEMASK)
140     {
141     case (AMD_ID_LV160B & FLASH_TYPEMASK):
142         printf("2x Amd29F160BB (16Mbit)\n");
143         break;
144     default:
145         printf("Unknown Chip Type\n");
146         goto Done;
147         break;
148     }
149
150     printf("  Size: %ld MB in %d Sectors\n",
151            info->size >> 20, info->sector_count);
152
153     printf("  Sector Start Addresses:");
154     for (i = 0; i < info->sector_count; i++)
155     {
156         if ((i % 5) == 0)
157         {
158             printf ("\n   ");
159         }
160         printf (" %08lX%s", info->start[i],
161                 info->protect[i] ? " (RO)" : "     ");
162     }
163     printf ("\n");
164
165 Done:
166 }
167
168 /*-----------------------------------------------------------------------
169  */
170
171 int     flash_erase (flash_info_t *info, int s_first, int s_last)
172 {
173     ulong result;
174     int iflag, cflag, prot, sect;
175     int rc = ERR_OK;
176     int chip1, chip2;
177
178     /* first look for protection bits */
179
180     if (info->flash_id == FLASH_UNKNOWN)
181         return ERR_UNKNOWN_FLASH_TYPE;
182
183     if ((s_first < 0) || (s_first > s_last)) {
184         return ERR_INVAL;
185     }
186
187     if ((info->flash_id & FLASH_VENDMASK) !=
188         (AMD_MANUFACT & FLASH_VENDMASK)) {
189         return ERR_UNKNOWN_FLASH_VENDOR;
190     }
191
192     prot = 0;
193     for (sect=s_first; sect<=s_last; ++sect) {
194         if (info->protect[sect]) {
195             prot++;
196         }
197     }
198     if (prot)
199         return ERR_PROTECTED;
200
201     /*
202      * Disable interrupts which might cause a timeout
203      * here. Remember that our exception vectors are
204      * at address 0 in the flash, and we don't want a
205      * (ticker) exception to happen while the flash
206      * chip is in programming mode.
207      */
208     iflag = disable_interrupts();
209
210     /* Start erase on unprotected sectors */
211     for (sect = s_first; sect<=s_last && !ctrlc(); sect++)
212     {
213         printf("Erasing sector %2d ... ", sect);
214
215         /* arm simple, non interrupt dependent timer */
216         reset_timer();
217
218         if (info->protect[sect] == 0)
219         {       /* not protected */
220             vu_long *addr = (vu_long *)(info->start[sect]);
221
222             MEM_FLASH_ADDR1 = CMD_UNLOCK1;
223             MEM_FLASH_ADDR2 = CMD_UNLOCK2;
224             MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
225
226             MEM_FLASH_ADDR1 = CMD_UNLOCK1;
227             MEM_FLASH_ADDR2 = CMD_UNLOCK2;
228             *addr = CMD_ERASE_CONFIRM;
229
230             /* wait until flash is ready */
231             chip1 = chip2 = 0;
232
233             do
234             {
235                 result = *addr;
236
237                 /* check timeout */
238                 if (get_timer(0) > CFG_FLASH_ERASE_TOUT)
239                 {
240                     MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
241                     chip1 = TMO;
242                     break;
243                 }
244
245                 if (!chip1 && (result & 0xFFFF) & BIT_ERASE_DONE)
246                         chip1 = READY;
247
248                 if (!chip1 && (result & 0xFFFF) & BIT_PROGRAM_ERROR)
249                         chip1 = ERR;
250
251                 if (!chip2 && (result >> 16) & BIT_ERASE_DONE)
252                         chip2 = READY;
253
254                 if (!chip2 && (result >> 16) & BIT_PROGRAM_ERROR)
255                         chip2 = ERR;
256
257             }  while (!chip1 || !chip2);
258
259             MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
260
261             if (chip1 == ERR || chip2 == ERR)
262             {
263                 rc = ERR_PROG_ERROR;
264                 goto outahere;
265             }
266             if (chip1 == TMO)
267             {
268                 rc = ERR_TIMOUT;
269                 goto outahere;
270             }
271
272             printf("ok.\n");
273         }
274         else /* it was protected */
275         {
276             printf("protected!\n");
277         }
278     }
279
280     if (ctrlc())
281       printf("User Interrupt!\n");
282
283 outahere:
284     /* allow flash to settle - wait 10 ms */
285     udelay(10000);
286
287     if (iflag)
288       enable_interrupts();
289
290
291     return rc;
292 }
293
294 /*-----------------------------------------------------------------------
295  * Copy memory to flash
296  */
297
298 volatile static int write_word (flash_info_t *info, ulong dest, ulong data)
299 {
300     vu_long *addr = (vu_long *)dest;
301     ulong result;
302     int rc = ERR_OK;
303     int iflag;
304     int chip1, chip2;
305
306     /*
307      * Check if Flash is (sufficiently) erased
308      */
309     result = *addr;
310     if ((result & data) != data)
311         return ERR_NOT_ERASED;
312
313
314     /*
315      * Disable interrupts which might cause a timeout
316      * here. Remember that our exception vectors are
317      * at address 0 in the flash, and we don't want a
318      * (ticker) exception to happen while the flash
319      * chip is in programming mode.
320      */
321     iflag = disable_interrupts();
322
323     MEM_FLASH_ADDR1 = CMD_UNLOCK1;
324     MEM_FLASH_ADDR2 = CMD_UNLOCK2;
325     MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
326     *addr = CMD_PROGRAM;
327     *addr = data;
328
329     /* arm simple, non interrupt dependent timer */
330     reset_timer();
331
332     /* wait until flash is ready */
333     chip1 = chip2 = 0;
334     do
335     {
336         result = *addr;
337
338         /* check timeout */
339         if (get_timer(0) > CFG_FLASH_ERASE_TOUT)
340         {
341             chip1 = ERR | TMO;
342             break;
343         }
344         if (!chip1 && ((result & 0x80) == (data & 0x80)))
345                 chip1 = READY;
346
347         if (!chip1 && ((result & 0xFFFF) & BIT_PROGRAM_ERROR))
348         {
349                 result = *addr;
350
351                 if ((result & 0x80) == (data & 0x80))
352                         chip1 = READY;
353                 else
354                         chip1 = ERR;
355         }
356
357         if (!chip2 && ((result & (0x80 << 16)) == (data & (0x80 << 16))))
358                 chip2 = READY;
359
360         if (!chip2 && ((result >> 16) & BIT_PROGRAM_ERROR))
361         {
362                 result = *addr;
363
364                 if ((result & (0x80 << 16)) == (data & (0x80 << 16)))
365                         chip2 = READY;
366                 else
367                         chip2 = ERR;
368         }
369
370     }  while (!chip1 || !chip2);
371
372     *addr = CMD_READ_ARRAY;
373
374     if (chip1 == ERR || chip2 == ERR || *addr != data)
375         rc = ERR_PROG_ERROR;
376
377     if (iflag)
378       enable_interrupts();
379
380
381     return rc;
382 }
383
384 /*-----------------------------------------------------------------------
385  * Copy memory to flash.
386  */
387
388 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
389 {
390     ulong cp, wp, data;
391     int l;
392     int i, rc;
393
394     wp = (addr & ~3);   /* get lower word aligned address */
395
396     /*
397      * handle unaligned start bytes
398      */
399     if ((l = addr - wp) != 0) {
400         data = 0;
401         for (i=0, cp=wp; i<l; ++i, ++cp) {
402             data = (data >> 8) | (*(uchar *)cp << 24);
403         }
404         for (; i<4 && cnt>0; ++i) {
405             data = (data >> 8) | (*src++ << 24);
406             --cnt;
407             ++cp;
408         }
409         for (; cnt==0 && i<4; ++i, ++cp) {
410             data = (data >> 8) | (*(uchar *)cp << 24);
411         }
412
413         if ((rc = write_word(info, wp, data)) != 0) {
414             return (rc);
415         }
416         wp += 4;
417     }
418
419     /*
420      * handle word aligned part
421      */
422     while (cnt >= 4) {
423         data = *((vu_long*)src);
424         if ((rc = write_word(info, wp, data)) != 0) {
425             return (rc);
426         }
427         src += 4;
428         wp  += 4;
429         cnt -= 4;
430     }
431
432     if (cnt == 0) {
433         return ERR_OK;
434     }
435
436     /*
437      * handle unaligned tail bytes
438      */
439     data = 0;
440     for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
441         data = (data >> 8) | (*src++ << 24);
442         --cnt;
443     }
444     for (; i<4; ++i, ++cp) {
445         data = (data >> 8) | (*(uchar *)cp << 24);
446     }
447
448     return write_word(info, wp, data);
449 }