]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - board/csb226/flash.c
* Patch by Robert Schwebel, 04 Nov 2002:
[karo-tx-uboot.git] / board / csb226 / flash.c
1 /*
2  * (C) Copyright 2002
3  * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
4  *
5  * (C) Copyright 2002
6  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
7  * Marius Groeger <mgroeger@sysgo.de>
8  *
9  * (C) Copyright 2002
10  * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de> 
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/pxa-regs.h>
33
34 #define FLASH_BANK_SIZE 0x02000000
35 #define MAIN_SECT_SIZE  0x40000         /* 2x16 = 256k per sector */
36
37 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
38
39
40 /**
41  * flash_init: - initialize data structures for flash chips
42  *
43  * @return: size of the flash
44  */
45
46 ulong flash_init(void)
47 {
48     int i, j;
49     ulong size = 0;
50
51         for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
52         ulong flashbase = 0;
53         flash_info[i].flash_id =
54           (INTEL_MANUFACT & FLASH_VENDMASK) |
55           (INTEL_ID_28F128J3 & FLASH_TYPEMASK);
56         flash_info[i].size = FLASH_BANK_SIZE;
57         flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
58         memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
59
60                 switch (i) {
61            case 0:
62                 flashbase = PHYS_FLASH_1;
63                 break;
64            default:
65                 panic("configured to many flash banks!\n");
66                 break;
67         }
68                 for (j = 0; j < flash_info[i].sector_count; j++) {
69             flash_info[i].start[j] = flashbase + j*MAIN_SECT_SIZE;
70         }
71         size += flash_info[i].size;
72     }
73
74         /* Protect monitor and environment sectors */
75     flash_protect(FLAG_PROTECT_SET,
76                   CFG_FLASH_BASE,
77                   CFG_FLASH_BASE + _armboot_end_data - _armboot_start,
78                   &flash_info[0]);
79
80     flash_protect(FLAG_PROTECT_SET,
81                   CFG_ENV_ADDR,
82                   CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
83                   &flash_info[0]);
84
85     return size;
86 }
87
88
89 /**
90  * flash_print_info: - print information about the flash situation
91  *
92  * @param info: 
93  */
94
95 void flash_print_info  (flash_info_t *info)
96 {
97     int i, j;
98
99         for (j=0; j<CFG_MAX_FLASH_BANKS; j++) {
100
101                 switch (info->flash_id & FLASH_VENDMASK) {
102
103         case (INTEL_MANUFACT & FLASH_VENDMASK):
104                 printf("Intel: ");
105                 break;
106         default:
107                 printf("Unknown Vendor ");
108                 break;
109         }
110
111                 switch (info->flash_id & FLASH_TYPEMASK) {
112
113         case (INTEL_ID_28F128J3 & FLASH_TYPEMASK):
114                 printf("28F128J3 (128Mbit)\n");
115                 break;
116         default:
117                 printf("Unknown Chip Type\n");
118                                 return;
119         }
120
121         printf("  Size: %ld MB in %d Sectors\n",
122                 info->size >> 20, info->sector_count);
123
124         printf("  Sector Start Addresses:");
125                 for (i = 0; i < info->sector_count; i++) {
126                         if ((i % 5) == 0) printf ("\n   ");
127                 
128                 printf (" %08lX%s", info->start[i],
129                         info->protect[i] ? " (RO)" : "     ");
130         }
131         printf ("\n");
132         info++;
133     }
134 }
135
136
137 /**
138  * flash_erase: - erase flash sectors
139  *
140  */
141
142 int     flash_erase (flash_info_t *info, int s_first, int s_last)
143 {
144     int flag, prot, sect;
145     int rc = ERR_OK;
146
147     if (info->flash_id == FLASH_UNKNOWN)
148         return ERR_UNKNOWN_FLASH_TYPE;
149
150     if ((s_first < 0) || (s_first > s_last)) {
151         return ERR_INVAL;
152     }
153
154         if ((info->flash_id & FLASH_VENDMASK) != (INTEL_MANUFACT & FLASH_VENDMASK))
155         return ERR_UNKNOWN_FLASH_VENDOR;
156
157     prot = 0;
158     for (sect=s_first; sect<=s_last; ++sect) {
159                 if (info->protect[sect]) prot++;
160         }
161
162         if (prot) return ERR_PROTECTED;
163
164     /*
165      * Disable interrupts which might cause a timeout
166      * here. Remember that our exception vectors are
167      * at address 0 in the flash, and we don't want a
168      * (ticker) exception to happen while the flash
169      * chip is in programming mode.
170      */
171     flag = disable_interrupts();
172
173     /* Start erase on unprotected sectors */
174     for (sect = s_first; sect<=s_last && !ctrlc(); sect++) {
175
176         printf("Erasing sector %2d ... ", sect);
177
178         /* arm simple, non interrupt dependent timer */
179         reset_timer_masked();
180
181         if (info->protect[sect] == 0) { /* not protected */
182                         u32 * volatile addr = (u32 * volatile)(info->start[sect]);
183
184                         /* erase sector:                                    */
185                         /* The strata flashs are aligned side by side on    */
186                         /* the data bus, so we have to write the commands   */
187                         /* to both chips here:                              */
188
189                         *addr = 0x00200020;     /* erase setup */
190                         *addr = 0x00D000D0;     /* erase confirm */
191
192                         while ((*addr & 0x00800080) != 0x00800080) {
193                 if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) {
194                                         *addr = 0x00B000B0; /* suspend erase*/
195                                         *addr = 0x00FF00FF; /* read mode    */
196                     rc = ERR_TIMOUT;
197                     goto outahere;
198                 }
199             }
200
201                         *addr = 0x00500050; /* clear status register cmd.   */
202                         *addr = 0x00FF00FF; /* resest to read mode          */
203
204         }
205                 
206         printf("ok.\n");
207     }
208
209         if (ctrlc()) printf("User Interrupt!\n");
210
211 outahere:
212
213     /* allow flash to settle - wait 10 ms */
214     udelay_masked(10000);
215
216         if (flag) enable_interrupts();
217
218     return rc;
219 }
220
221
222 /**
223  * write_word: - copy memory to flash
224  * 
225  * @param info:
226  * @param dest:
227  * @param data: 
228  * @return:
229  */
230
231 static int write_word (flash_info_t *info, ulong dest, ushort data)
232 {
233     ushort *addr = (ushort *)dest, val;
234     int rc = ERR_OK;
235     int flag;
236
237         /* Check if Flash is (sufficiently) erased */
238         if ((*addr & data) != data) return ERR_NOT_ERASED;
239
240     /*
241      * Disable interrupts which might cause a timeout
242      * here. Remember that our exception vectors are
243      * at address 0 in the flash, and we don't want a
244      * (ticker) exception to happen while the flash
245      * chip is in programming mode.
246      */
247     flag = disable_interrupts();
248
249     /* clear status register command */
250     *addr = 0x50;
251
252     /* program set-up command */
253     *addr = 0x40;
254
255     /* latch address/data */
256     *addr = data;
257
258     /* arm simple, non interrupt dependent timer */
259     reset_timer_masked();
260
261     /* wait while polling the status register */
262         while(((val = *addr) & 0x80) != 0x80) {
263         if (get_timer_masked() > CFG_FLASH_WRITE_TOUT) {
264             rc = ERR_TIMOUT;
265                         *addr = 0xB0; /* suspend program command */
266             goto outahere;
267         }
268     }
269
270     if(val & 0x1A) {    /* check for error */
271         printf("\nFlash write error %02x at address %08lx\n",
272            (int)val, (unsigned long)dest);
273         if(val & (1<<3)) {
274             printf("Voltage range error.\n");
275             rc = ERR_PROG_ERROR;
276             goto outahere;
277         }
278         if(val & (1<<1)) {
279             printf("Device protect error.\n");
280             rc = ERR_PROTECTED;
281             goto outahere;
282         }
283         if(val & (1<<4)) {
284             printf("Programming error.\n");
285             rc = ERR_PROG_ERROR;
286             goto outahere;
287         }
288         rc = ERR_PROG_ERROR;
289         goto outahere;
290     }
291
292 outahere:
293
294         *addr = 0xFF; /* read array command */
295         if (flag) enable_interrupts();
296
297     return rc;
298 }
299
300
301 /**
302  * write_buf: - Copy memory to flash.
303  * 
304  * @param info:  
305  * @param src:  source of copy transaction
306  * @param addr: where to copy to
307  * @param cnt:  number of bytes to copy
308  *
309  * @return      error code
310  */
311
312 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
313 {
314     ulong cp, wp;
315     ushort data;
316     int l;
317     int i, rc;
318
319     wp = (addr & ~1);   /* get lower word aligned address */
320
321     /*
322      * handle unaligned start bytes
323      */
324     if ((l = addr - wp) != 0) {
325         data = 0;
326         for (i=0, cp=wp; i<l; ++i, ++cp) {
327             data = (data >> 8) | (*(uchar *)cp << 8);
328         }
329         for (; i<2 && cnt>0; ++i) {
330             data = (data >> 8) | (*src++ << 8);
331             --cnt;
332             ++cp;
333         }
334         for (; cnt==0 && i<2; ++i, ++cp) {
335             data = (data >> 8) | (*(uchar *)cp << 8);
336         }
337
338         if ((rc = write_word(info, wp, data)) != 0) {
339             return (rc);
340         }
341         wp += 2;
342     }
343
344     /*
345      * handle word aligned part
346      */
347     while (cnt >= 2) {
348         /* data = *((vushort*)src); */
349         data = *((ushort*)src);
350         if ((rc = write_word(info, wp, data)) != 0) {
351             return (rc);
352         }
353         src += 2;
354         wp  += 2;
355         cnt -= 2;
356     }
357
358         if (cnt == 0) return ERR_OK;
359
360     /*
361      * handle unaligned tail bytes
362      */
363     data = 0;
364     for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) {
365         data = (data >> 8) | (*src++ << 8);
366         --cnt;
367     }
368     for (; i<2; ++i, ++cp) {
369         data = (data >> 8) | (*(uchar *)cp << 8);
370     }
371
372     return write_word(info, wp, data);
373 }