blob: 8b30f50ccdca8844a56854267853edefff88fd0b [file] [log] [blame]
wdenkcc1c8a12002-11-02 22:58:18 +00001/*
2 * (C) Copyright 2001
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#include <common.h>
25#include <configs/sacsng.h>
26
27
28#undef DEBUG
29
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020030#ifndef CONFIG_ENV_ADDR
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020031#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
wdenkcc1c8a12002-11-02 22:58:18 +000032#endif
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020033#ifndef CONFIG_ENV_SIZE
34#define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE
wdenkcc1c8a12002-11-02 22:58:18 +000035#endif
36
37
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020038flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenkcc1c8a12002-11-02 22:58:18 +000039
40/*-----------------------------------------------------------------------
41 * Functions
42 */
43static ulong flash_get_size (vu_short *addr, flash_info_t *info);
44static int write_word (flash_info_t *info, ulong dest, ulong data);
45
46/*-----------------------------------------------------------------------
47 */
48
49unsigned long flash_init (void)
50{
51 unsigned long size_b0, size_b1;
52 int i;
53
54 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020055 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenkcc1c8a12002-11-02 22:58:18 +000056 flash_info[i].flash_id = FLASH_UNKNOWN;
57 }
58
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020059 size_b0 = flash_get_size((vu_short *)CONFIG_SYS_FLASH0_BASE, &flash_info[0]);
wdenkcc1c8a12002-11-02 22:58:18 +000060
61 if (flash_info[0].flash_id == FLASH_UNKNOWN) {
62 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
63 size_b0, size_b0<<20);
64 }
65
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020066 size_b1 = flash_get_size((vu_short *)CONFIG_SYS_FLASH1_BASE, &flash_info[1]);
wdenkcc1c8a12002-11-02 22:58:18 +000067
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020068#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
wdenkcc1c8a12002-11-02 22:58:18 +000069 /* monitor protection ON by default */
70 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020071 CONFIG_SYS_MONITOR_BASE,
72 CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
wdenkcc1c8a12002-11-02 22:58:18 +000073 &flash_info[0]);
74#endif
75
Jean-Christophe PLAGNIOL-VILLARD5a1aceb2008-09-10 22:48:04 +020076#ifdef CONFIG_ENV_IS_IN_FLASH
wdenkcc1c8a12002-11-02 22:58:18 +000077 /* ENV protection ON by default */
78 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020079 CONFIG_ENV_ADDR,
80 CONFIG_ENV_ADDR+CONFIG_ENV_SIZE-1,
wdenkcc1c8a12002-11-02 22:58:18 +000081 &flash_info[0]);
82#endif
83
84 if (size_b1) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020085#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
wdenkcc1c8a12002-11-02 22:58:18 +000086 /* monitor protection ON by default */
87 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020088 CONFIG_SYS_MONITOR_BASE,
89 CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
wdenkcc1c8a12002-11-02 22:58:18 +000090 &flash_info[1]);
91#endif
92
Jean-Christophe PLAGNIOL-VILLARD5a1aceb2008-09-10 22:48:04 +020093#ifdef CONFIG_ENV_IS_IN_FLASH
wdenkcc1c8a12002-11-02 22:58:18 +000094 /* ENV protection ON by default */
95 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020096 CONFIG_ENV_ADDR,
97 CONFIG_ENV_ADDR+CONFIG_ENV_SIZE-1,
wdenkcc1c8a12002-11-02 22:58:18 +000098 &flash_info[1]);
99#endif
100 } else {
101 flash_info[1].flash_id = FLASH_UNKNOWN;
102 flash_info[1].sector_count = -1;
103 }
104
105 flash_info[0].size = size_b0;
106 flash_info[1].size = size_b1;
107
108 /*
109 * We only report the primary flash for U-Boot's use.
110 */
111 return (size_b0);
112}
113
114/*-----------------------------------------------------------------------
115 */
116void flash_print_info (flash_info_t *info)
117{
118 int i;
119
120 if (info->flash_id == FLASH_UNKNOWN) {
121 printf ("missing or unknown FLASH type\n");
122 return;
123 }
124
125 switch (info->flash_id & FLASH_VENDMASK) {
126 case FLASH_MAN_AMD: printf ("AMD "); break;
127 case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
128 default: printf ("Unknown Vendor "); break;
129 }
130
131 switch (info->flash_id & FLASH_TYPEMASK) {
132 case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
133 break;
134 case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
135 break;
136 case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
137 break;
138 case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
139 break;
140 case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
141 break;
142 case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
143 break;
144 case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
145 break;
146 case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
147 break;
148 default: printf ("Unknown Chip Type\n");
149 break;
150 }
151
152 printf (" Size: %ld MB in %d Sectors\n",
153 info->size >> 20, info->sector_count);
154
155 printf (" Sector Start Addresses:");
156 for (i=0; i<info->sector_count; ++i) {
157 if ((i % 5) == 0)
158 printf ("\n ");
159 printf (" %08lX%s",
160 info->start[i],
161 info->protect[i] ? " (RO)" : " "
162 );
163 }
164 printf ("\n");
165 return;
166}
167
168/*-----------------------------------------------------------------------
169 */
170
171
172/*-----------------------------------------------------------------------
173 */
174
175/*
176 * The following code cannot be run from FLASH!
177 */
178
179static ulong flash_get_size (vu_short *addr, flash_info_t *info)
180{
181 short i;
182 ushort value;
183 ulong base = (ulong)addr;
184
185 /* Write auto select command: read Manufacturer ID */
186 addr[0x0555] = 0xAAAA;
187 addr[0x02AA] = 0x5555;
188 addr[0x0555] = 0x9090;
189 __asm__ __volatile__(" sync\n ");
190
191 value = addr[0];
192#ifdef DEBUG
193 printf("Flash manufacturer 0x%04X\n", value);
194#endif
195
196 if(value == (ushort)AMD_MANUFACT) {
197 info->flash_id = FLASH_MAN_AMD;
198 } else if (value == (ushort)FUJ_MANUFACT) {
199 info->flash_id = FLASH_MAN_FUJ;
200 } else {
201#ifdef DEBUG
202 printf("Unknown flash manufacturer 0x%04X\n", value);
203#endif
204 info->flash_id = FLASH_UNKNOWN;
205 info->sector_count = 0;
206 info->size = 0;
207 return (0); /* no or unknown flash */
208 }
209
210 value = addr[1]; /* device ID */
211#ifdef DEBUG
212 printf("Flash type 0x%04X\n", value);
213#endif
214
215 if(value == (ushort)AMD_ID_LV400T) {
216 info->flash_id += FLASH_AM400T;
217 info->sector_count = 11;
218 info->size = 0x00080000; /* => 0.5 MB */
219 } else if(value == (ushort)AMD_ID_LV400B) {
220 info->flash_id += FLASH_AM400B;
221 info->sector_count = 11;
222 info->size = 0x00080000; /* => 0.5 MB */
223 } else if(value == (ushort)AMD_ID_LV800T) {
224 info->flash_id += FLASH_AM800T;
225 info->sector_count = 19;
226 info->size = 0x00100000; /* => 1 MB */
227 } else if(value == (ushort)AMD_ID_LV800B) {
228 info->flash_id += FLASH_AM800B;
229 info->sector_count = 19;
230 info->size = 0x00100000; /* => 1 MB */
231 } else if(value == (ushort)AMD_ID_LV160T) {
232 info->flash_id += FLASH_AM160T;
233 info->sector_count = 35;
234 info->size = 0x00200000; /* => 2 MB */
235 } else if(value == (ushort)AMD_ID_LV160B) {
236 info->flash_id += FLASH_AM160B;
237 info->sector_count = 35;
238 info->size = 0x00200000; /* => 2 MB */
239 } else if(value == (ushort)AMD_ID_LV320T) {
240 info->flash_id += FLASH_AM320T;
241 info->sector_count = 67;
242 info->size = 0x00400000; /* => 4 MB */
243 } else if(value == (ushort)AMD_ID_LV320B) {
244 info->flash_id += FLASH_AM320B;
245 info->sector_count = 67;
246 info->size = 0x00400000; /* => 4 MB */
247 } else {
248#ifdef DEBUG
249 printf("Unknown flash type 0x%04X\n", value);
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200250 info->size = CONFIG_SYS_FLASH_SIZE;
wdenkcc1c8a12002-11-02 22:58:18 +0000251#else
252 info->flash_id = FLASH_UNKNOWN;
253 return (0); /* => no or unknown flash */
254#endif
255 }
256
257 /* set up sector start address table */
258 if (info->flash_id & FLASH_BTYPE) {
259 /* set sector offsets for bottom boot block type */
260 info->start[0] = base + 0x00000000;
261 info->start[1] = base + 0x00004000;
262 info->start[2] = base + 0x00006000;
263 info->start[3] = base + 0x00008000;
264 for (i = 4; i < info->sector_count; i++) {
265 info->start[i] = base + ((i - 3) * 0x00010000);
266 }
267 } else {
268 /* set sector offsets for top boot block type */
269 i = info->sector_count - 1;
270 info->start[i--] = base + info->size - 0x00004000;
271 info->start[i--] = base + info->size - 0x00006000;
272 info->start[i--] = base + info->size - 0x00008000;
273 for (; i >= 0; i--) {
274 info->start[i] = base + (i * 0x00010000);
275 }
276 }
277
278 /* check for protected sectors */
279 for (i = 0; i < info->sector_count; i++) {
280 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
281 /* D0 = 1 if protected */
282 addr = (volatile unsigned short *)(info->start[i]);
283 info->protect[i] = addr[2] & 1;
284 }
285
286 /*
287 * Prevent writes to uninitialized FLASH.
288 */
289 if (info->flash_id != FLASH_UNKNOWN) {
290 addr = (volatile unsigned short *)info->start[0];
291
292 }
293
294 addr[0] = 0xF0F0; /* reset bank */
295 __asm__ __volatile__(" sync\n ");
296 return (info->size);
297}
298
299
300/*-----------------------------------------------------------------------
301 */
302
303int flash_erase (flash_info_t *info, int s_first, int s_last)
304{
305 vu_short *addr = (vu_short*)(info->start[0]);
306 int flag, prot, sect, l_sect;
307 ulong start, now, last;
308
309 if ((s_first < 0) || (s_first > s_last)) {
310 if (info->flash_id == FLASH_UNKNOWN) {
311 printf ("- missing\n");
312 } else {
313 printf ("- no sectors to erase\n");
314 }
315 return 1;
316 }
317
318 if ((info->flash_id == FLASH_UNKNOWN) ||
319 (info->flash_id > FLASH_AMD_COMP)) {
320 printf ("Can't erase unknown flash type %08lx - aborted\n",
321 info->flash_id);
322 return 1;
323 }
324
325 prot = 0;
326 for (sect=s_first; sect<=s_last; ++sect) {
327 if (info->protect[sect]) {
328 prot++;
329 }
330 }
331
332 if (prot) {
333 printf ("- Warning: %d protected sectors will not be erased!\n",
334 prot);
335 } else {
336 printf ("\n");
337 }
338
339 l_sect = -1;
340
341 /* Disable interrupts which might cause a timeout here */
342 flag = disable_interrupts();
343
344 addr[0x0555] = 0xAAAA;
345 addr[0x02AA] = 0x5555;
346 addr[0x0555] = 0x8080;
347 addr[0x0555] = 0xAAAA;
348 addr[0x02AA] = 0x5555;
349 __asm__ __volatile__(" sync\n ");
350
351 /* Start erase on unprotected sectors */
352 for (sect = s_first; sect<=s_last; sect++) {
353 if (info->protect[sect] == 0) { /* not protected */
354 addr = (vu_short*)(info->start[sect]);
355 addr[0] = 0x3030;
356 l_sect = sect;
357 }
358 }
359
360 /* re-enable interrupts if necessary */
361 if (flag)
362 enable_interrupts();
363
364 /* wait at least 80us - let's wait 1 ms */
365 udelay (1000);
366
367 /*
368 * We wait for the last triggered sector
369 */
370 if (l_sect < 0)
371 goto DONE;
372
373 start = get_timer (0);
374 last = start;
375 addr = (vu_short*)(info->start[l_sect]);
376 while ((addr[0] & 0x0080) != 0x0080) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200377 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenkcc1c8a12002-11-02 22:58:18 +0000378 printf ("Timeout\n");
379 addr[0] = 0xF0F0; /* reset bank */
380 __asm__ __volatile__(" sync\n ");
381 return 1;
382 }
383 /* show that we're waiting */
384 if ((now - last) > 1000) { /* every second */
385 putc ('.');
386 last = now;
387 }
388 }
389
390DONE:
391 /* reset to read mode */
392 addr = (vu_short*)info->start[0];
393 addr[0] = 0xF0F0; /* reset bank */
394 __asm__ __volatile__(" sync\n ");
395
396 printf (" done\n");
397 return 0;
398}
399
400/*-----------------------------------------------------------------------
401 * Copy memory to flash, returns:
402 * 0 - OK
403 * 1 - write timeout
404 * 2 - Flash not erased
405 */
406
407int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
408{
409 ulong cp, wp, data;
410 int i, l, rc;
411
412 wp = (addr & ~3); /* get lower word aligned address */
413
414 /*
415 * handle unaligned start bytes
416 */
417 if ((l = addr - wp) != 0) {
418 data = 0;
419 for (i=0, cp=wp; i<l; ++i, ++cp) {
420 data = (data << 8) | (*(uchar *)cp);
421 }
422 for (; i<4 && cnt>0; ++i) {
423 data = (data << 8) | *src++;
424 --cnt;
425 ++cp;
426 }
427 for (; cnt==0 && i<4; ++i, ++cp) {
428 data = (data << 8) | (*(uchar *)cp);
429 }
430
431 if ((rc = write_word(info, wp, data)) != 0) {
432 return (rc);
433 }
434 wp += 4;
435 }
436
437 /*
438 * handle word aligned part
439 */
440 while (cnt >= 4) {
441 data = 0;
442 for (i=0; i<4; ++i) {
443 data = (data << 8) | *src++;
444 }
445 if ((rc = write_word(info, wp, data)) != 0) {
446 return (rc);
447 }
448 wp += 4;
449 cnt -= 4;
450 }
451
452 if (cnt == 0) {
453 return (0);
454 }
455
456 /*
457 * handle unaligned tail bytes
458 */
459 data = 0;
460 for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
461 data = (data << 8) | *src++;
462 --cnt;
463 }
464 for (; i<4; ++i, ++cp) {
465 data = (data << 8) | (*(uchar *)cp);
466 }
467
468 return (write_word(info, wp, data));
469}
470
471/*-----------------------------------------------------------------------
472 * Write a word to Flash, returns:
473 * 0 - OK
474 * 1 - write timeout
475 * 2 - Flash not erased
476 */
477static int write_word (flash_info_t *info, ulong dest, ulong data)
478{
479 vu_short *addr = (vu_short*)(info->start[0]);
480 ulong start;
481 int flag;
482 int j;
483
484 /* Check if Flash is (sufficiently) erased */
485 if (((*(vu_long *)dest) & data) != data) {
486 return (2);
487 }
488 /* Disable interrupts which might cause a timeout here */
489 flag = disable_interrupts();
490
491 /* The original routine was designed to write 32 bit words to
492 * 32 bit wide memory. We have 16 bit wide memory so we do
493 * two writes. We write the LSB first at dest+2 and then the
494 * MSB at dest (lousy big endian).
495 */
496 dest += 2;
497 for(j = 0; j < 2; j++) {
498 addr[0x0555] = 0xAAAA;
499 addr[0x02AA] = 0x5555;
500 addr[0x0555] = 0xA0A0;
501 __asm__ __volatile__(" sync\n ");
502
503 *((vu_short *)dest) = (ushort)data;
504
505 /* re-enable interrupts if necessary */
506 if (flag)
507 enable_interrupts();
508
509 /* data polling for D7 */
510 start = get_timer (0);
511 while (*(vu_short *)dest != (ushort)data) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200512 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenkcc1c8a12002-11-02 22:58:18 +0000513 return (1);
514 }
515 }
516 dest -= 2;
517 data >>= 16;
518 }
519 return (0);
520}
521
522/*-----------------------------------------------------------------------
523 */