blob: 2cb8dcb9d803ddad27b15549ac05957f18e883a5 [file] [log] [blame]
wdenk3bbc8992003-12-07 22:27:15 +00001/*
2 * (C) Copyright 2003
3 * MuLogic B.V.
4 *
5 * (C) Copyright 2001
6 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7 *
8 * See file CREDITS for list of people who contributed to this
9 * project.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
25 */
26
27#include <common.h>
28#include <ppc4xx.h>
29#include <asm/u-boot.h>
30#include <asm/processor.h>
31
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020032flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenk3bbc8992003-12-07 22:27:15 +000033
34
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020035#ifdef CONFIG_SYS_FLASH_16BIT
wdenk3bbc8992003-12-07 22:27:15 +000036#define FLASH_WORD_SIZE unsigned short
37#define FLASH_ID_MASK 0xFFFF
38#else
39#define FLASH_WORD_SIZE unsigned long
40#define FLASH_ID_MASK 0xFFFFFFFF
41#endif
42
43/*-----------------------------------------------------------------------
44 * Functions
45 */
46/* stolen from esteem192e/flash.c */
47ulong flash_get_size (volatile FLASH_WORD_SIZE *addr, flash_info_t *info);
48
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020049#ifndef CONFIG_SYS_FLASH_16BIT
wdenk3bbc8992003-12-07 22:27:15 +000050static int write_word (flash_info_t *info, ulong dest, ulong data);
51#else
52static int write_short (flash_info_t *info, ulong dest, ushort data);
53#endif
54static void flash_get_offsets (ulong base, flash_info_t *info);
55
56
57/*-----------------------------------------------------------------------
58 */
59
60unsigned long flash_init (void)
61{
62 unsigned long size_b0, size_b1;
63 int i;
64 uint pbcr;
65 unsigned long base_b0, base_b1;
66
67 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020068 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenk3bbc8992003-12-07 22:27:15 +000069 flash_info[i].flash_id = FLASH_UNKNOWN;
70 }
71
72 /* Static FLASH Bank configuration here - FIXME XXX */
73
74 size_b0 = flash_get_size((volatile FLASH_WORD_SIZE *)FLASH_BASE1_PRELIM, &flash_info[0]);
75
76 if (flash_info[0].flash_id == FLASH_UNKNOWN) {
77 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
78 size_b0, size_b0<<20);
79 }
80
81 /* Only one bank */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020082 if (CONFIG_SYS_MAX_FLASH_BANKS == 1) {
wdenk3bbc8992003-12-07 22:27:15 +000083 /* Setup offsets */
84 flash_get_offsets (FLASH_BASE1_PRELIM, &flash_info[0]);
85
86 /* Monitor protection ON by default */
87#if 0 /* sand: */
88 (void)flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020089 FLASH_BASE1_PRELIM-CONFIG_SYS_MONITOR_LEN+size_b0,
wdenk3bbc8992003-12-07 22:27:15 +000090 FLASH_BASE1_PRELIM-1+size_b0,
91 &flash_info[0]);
92#else
93 (void)flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020094 CONFIG_SYS_MONITOR_BASE,
95 CONFIG_SYS_MONITOR_BASE+CONFIG_SYS_MONITOR_LEN-1,
wdenk3bbc8992003-12-07 22:27:15 +000096 &flash_info[0]);
97#endif
98 size_b1 = 0 ;
99 flash_info[0].size = size_b0;
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200100 } else { /* 2 banks */
wdenk3bbc8992003-12-07 22:27:15 +0000101 size_b1 = flash_get_size((volatile FLASH_WORD_SIZE *)FLASH_BASE1_PRELIM, &flash_info[1]);
102
103 /* Re-do sizing to get full correct info */
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200104 if (size_b1) {
wdenk3bbc8992003-12-07 22:27:15 +0000105 mtdcr(ebccfga, pb0cr);
106 pbcr = mfdcr(ebccfgd);
107 mtdcr(ebccfga, pb0cr);
108 base_b1 = -size_b1;
109 pbcr = (pbcr & 0x0001ffff) | base_b1 | (((size_b1/1024/1024)-1)<<17);
110 mtdcr(ebccfgd, pbcr);
111 }
112
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200113 if (size_b0) {
wdenk3bbc8992003-12-07 22:27:15 +0000114 mtdcr(ebccfga, pb1cr);
115 pbcr = mfdcr(ebccfgd);
116 mtdcr(ebccfga, pb1cr);
117 base_b0 = base_b1 - size_b0;
118 pbcr = (pbcr & 0x0001ffff) | base_b0 | (((size_b0/1024/1024)-1)<<17);
119 mtdcr(ebccfgd, pbcr);
120 }
121
122 size_b0 = flash_get_size((volatile FLASH_WORD_SIZE *)base_b0, &flash_info[0]);
123
124 flash_get_offsets (base_b0, &flash_info[0]);
125
126 /* monitor protection ON by default */
127#if 0 /* sand: */
128 (void)flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200129 FLASH_BASE1_PRELIM-CONFIG_SYS_MONITOR_LEN+size_b0,
wdenk3bbc8992003-12-07 22:27:15 +0000130 FLASH_BASE1_PRELIM-1+size_b0,
131 &flash_info[0]);
132#else
133 (void)flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200134 CONFIG_SYS_MONITOR_BASE,
135 CONFIG_SYS_MONITOR_BASE+CONFIG_SYS_MONITOR_LEN-1,
wdenk3bbc8992003-12-07 22:27:15 +0000136 &flash_info[0]);
137#endif
138
139 if (size_b1) {
140 /* Re-do sizing to get full correct info */
141 size_b1 = flash_get_size((volatile FLASH_WORD_SIZE *)base_b1, &flash_info[1]);
142
143 flash_get_offsets (base_b1, &flash_info[1]);
144
145 /* monitor protection ON by default */
146 (void)flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200147 base_b1+size_b1-CONFIG_SYS_MONITOR_LEN,
wdenk3bbc8992003-12-07 22:27:15 +0000148 base_b1+size_b1-1,
149 &flash_info[1]);
150 /* monitor protection OFF by default (one is enough) */
151 (void)flash_protect(FLAG_PROTECT_CLEAR,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200152 base_b0+size_b0-CONFIG_SYS_MONITOR_LEN,
wdenk3bbc8992003-12-07 22:27:15 +0000153 base_b0+size_b0-1,
154 &flash_info[0]);
155 } else {
156 flash_info[1].flash_id = FLASH_UNKNOWN;
157 flash_info[1].sector_count = -1;
158 }
159
160 flash_info[0].size = size_b0;
161 flash_info[1].size = size_b1;
162 }/* else 2 banks */
163 return (size_b0 + size_b1);
164}
165
166
wdenk3bbc8992003-12-07 22:27:15 +0000167/*-----------------------------------------------------------------------
168 */
169
170static void flash_get_offsets (ulong base, flash_info_t *info)
171{
172 int i;
173
174 /* set up sector start adress table */
175 if ((info->flash_id & FLASH_TYPEMASK) == INTEL_ID_28F320J3A ||
176 (info->flash_id & FLASH_TYPEMASK) == INTEL_ID_28F640J3A ||
177 (info->flash_id & FLASH_TYPEMASK) == INTEL_ID_28F128J3A) {
178 for (i = 0; i < info->sector_count; i++) {
179 info->start[i] = base + (i * info->size/info->sector_count);
180 }
181 }
182 else if (info->flash_id & FLASH_BTYPE) {
183 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
184
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200185#ifndef CONFIG_SYS_FLASH_16BIT
wdenk3bbc8992003-12-07 22:27:15 +0000186 /* set sector offsets for bottom boot block type */
187 info->start[0] = base + 0x00000000;
188 info->start[1] = base + 0x00004000;
189 info->start[2] = base + 0x00008000;
190 info->start[3] = base + 0x0000C000;
191 info->start[4] = base + 0x00010000;
192 info->start[5] = base + 0x00014000;
193 info->start[6] = base + 0x00018000;
194 info->start[7] = base + 0x0001C000;
195 for (i = 8; i < info->sector_count; i++) {
196 info->start[i] = base + (i * 0x00020000) - 0x000E0000;
197 }
198 } else {
199 /* set sector offsets for bottom boot block type */
200 info->start[0] = base + 0x00000000;
201 info->start[1] = base + 0x00008000;
202 info->start[2] = base + 0x0000C000;
203 info->start[3] = base + 0x00010000;
204 for (i = 4; i < info->sector_count; i++) {
205 info->start[i] = base + (i * 0x00020000) - 0x00060000;
206 }
207 }
208#else
209 /* set sector offsets for bottom boot block type */
210 info->start[0] = base + 0x00000000;
211 info->start[1] = base + 0x00002000;
212 info->start[2] = base + 0x00004000;
213 info->start[3] = base + 0x00006000;
214 info->start[4] = base + 0x00008000;
215 info->start[5] = base + 0x0000A000;
216 info->start[6] = base + 0x0000C000;
217 info->start[7] = base + 0x0000E000;
218 for (i = 8; i < info->sector_count; i++) {
219 info->start[i] = base + (i * 0x00010000) - 0x00070000;
220 }
221 } else {
222 /* set sector offsets for bottom boot block type */
223 info->start[0] = base + 0x00000000;
224 info->start[1] = base + 0x00004000;
225 info->start[2] = base + 0x00006000;
226 info->start[3] = base + 0x00008000;
227 for (i = 4; i < info->sector_count; i++) {
228 info->start[i] = base + (i * 0x00010000) - 0x00030000;
229 }
230 }
231#endif
232 } else {
233 /* set sector offsets for top boot block type */
234 i = info->sector_count - 1;
235 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
236
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200237#ifndef CONFIG_SYS_FLASH_16BIT
wdenk3bbc8992003-12-07 22:27:15 +0000238 info->start[i--] = base + info->size - 0x00004000;
239 info->start[i--] = base + info->size - 0x00008000;
240 info->start[i--] = base + info->size - 0x0000C000;
241 info->start[i--] = base + info->size - 0x00010000;
242 info->start[i--] = base + info->size - 0x00014000;
243 info->start[i--] = base + info->size - 0x00018000;
244 info->start[i--] = base + info->size - 0x0001C000;
245 for (; i >= 0; i--) {
246 info->start[i] = base + i * 0x00020000;
247 }
248 } else {
249
250 info->start[i--] = base + info->size - 0x00008000;
251 info->start[i--] = base + info->size - 0x0000C000;
252 info->start[i--] = base + info->size - 0x00010000;
253 for (; i >= 0; i--) {
254 info->start[i] = base + i * 0x00020000;
255 }
256 }
257#else
258 info->start[i--] = base + info->size - 0x00002000;
259 info->start[i--] = base + info->size - 0x00004000;
260 info->start[i--] = base + info->size - 0x00006000;
261 info->start[i--] = base + info->size - 0x00008000;
262 info->start[i--] = base + info->size - 0x0000A000;
263 info->start[i--] = base + info->size - 0x0000C000;
264 info->start[i--] = base + info->size - 0x0000E000;
265 for (; i >= 0; i--) {
266 info->start[i] = base + i * 0x00010000;
267 }
268 } else {
269 info->start[i--] = base + info->size - 0x00004000;
270 info->start[i--] = base + info->size - 0x00006000;
271 info->start[i--] = base + info->size - 0x00008000;
272 for (; i >= 0; i--) {
273 info->start[i] = base + i * 0x00010000;
274 }
275 }
276#endif
277 }
278}
279
280/*-----------------------------------------------------------------------
281 */
282
283void flash_print_info (flash_info_t *info)
284{
285 int i;
286 uchar *boottype;
287 uchar botboot[]=", bottom boot sect)\n";
288 uchar topboot[]=", top boot sector)\n";
289
290 if (info->flash_id == FLASH_UNKNOWN) {
291 printf ("missing or unknown FLASH type\n");
292 return;
293 }
294
295 switch (info->flash_id & FLASH_VENDMASK) {
296 case FLASH_MAN_AMD: printf ("AMD "); break;
297 case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
298 case FLASH_MAN_SST: printf ("SST "); break;
299 case FLASH_MAN_STM: printf ("STM "); break;
300 case FLASH_MAN_INTEL: printf ("INTEL "); break;
301 default: printf ("Unknown Vendor "); break;
302 }
303
304 if (info->flash_id & 0x0001 ) {
305 boottype = botboot;
306 } else {
307 boottype = topboot;
308 }
309
310 switch (info->flash_id & FLASH_TYPEMASK) {
311 case FLASH_AM400B: printf ("AM29LV400B (4 Mbit%s",boottype);
312 break;
313 case FLASH_AM400T: printf ("AM29LV400T (4 Mbit%s",boottype);
314 break;
315 case FLASH_AM800B: printf ("AM29LV800B (8 Mbit%s",boottype);
316 break;
317 case FLASH_AM800T: printf ("AM29LV800T (8 Mbit%s",boottype);
318 break;
319 case FLASH_AM160B: printf ("AM29LV160B (16 Mbit%s",boottype);
320 break;
321 case FLASH_AM160T: printf ("AM29LV160T (16 Mbit%s",boottype);
322 break;
323 case FLASH_AM320B: printf ("AM29LV320B (32 Mbit%s",boottype);
324 break;
325 case FLASH_AM320T: printf ("AM29LV320T (32 Mbit%s",boottype);
326 break;
327 case FLASH_INTEL800B: printf ("INTEL28F800B (8 Mbit%s",boottype);
328 break;
329 case FLASH_INTEL800T: printf ("INTEL28F800T (8 Mbit%s",boottype);
330 break;
331 case FLASH_INTEL160B: printf ("INTEL28F160B (16 Mbit%s",boottype);
332 break;
333 case FLASH_INTEL160T: printf ("INTEL28F160T (16 Mbit%s",boottype);
334 break;
335 case FLASH_INTEL320B: printf ("INTEL28F320B (32 Mbit%s",boottype);
336 break;
337 case FLASH_INTEL320T: printf ("INTEL28F320T (32 Mbit%s",boottype);
338 break;
339 case FLASH_AMDL322T: printf ("AM29DL322T (32 Mbit%s",boottype);
340 break;
341
342#if 0 /* enable when devices are available */
343
344 case FLASH_INTEL640B: printf ("INTEL28F640B (64 Mbit%s",boottype);
345 break;
346 case FLASH_INTEL640T: printf ("INTEL28F640T (64 Mbit%s",boottype);
347 break;
348#endif
349 case INTEL_ID_28F320J3A: printf ("INTEL28F320JA3 (32 Mbit%s",boottype);
350 break;
351 case INTEL_ID_28F640J3A: printf ("INTEL28F640JA3 (64 Mbit%s",boottype);
352 break;
353 case INTEL_ID_28F128J3A: printf ("INTEL28F128JA3 (128 Mbit%s",boottype);
354 break;
355
356 default: printf ("Unknown Chip Type\n");
357 break;
358 }
359
360 printf (" Size: %ld MB in %d Sectors\n",
361 info->size >> 20, info->sector_count);
362
363 printf (" Sector Start Addresses:");
364 for (i=0; i<info->sector_count; ++i) {
365 if ((i % 5) == 0)
366 printf ("\n ");
367 printf (" %08lX%s",
368 info->start[i],
369 info->protect[i] ? " (RO)" : " "
370 );
371 }
372 printf ("\n");
373 return;
374}
375
376
377/*-----------------------------------------------------------------------
378 */
379
380
381/*-----------------------------------------------------------------------
382 */
383
384/*
385 * The following code cannot be run from FLASH!
386 */
387ulong flash_get_size (volatile FLASH_WORD_SIZE *addr, flash_info_t *info)
388{
389 short i;
390 ulong base = (ulong)addr;
391 FLASH_WORD_SIZE value;
392
393 /* Write auto select command: read Manufacturer ID */
394
395
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200396#ifndef CONFIG_SYS_FLASH_16BIT
wdenk3bbc8992003-12-07 22:27:15 +0000397
398 /*
399 * Note: if it is an AMD flash and the word at addr[0000]
400 * is 0x00890089 this routine will think it is an Intel
401 * flash device and may(most likely) cause trouble.
402 */
403
404 addr[0x0000] = 0x00900090;
405 if(addr[0x0000] != 0x00890089){
406 addr[0x0555] = 0x00AA00AA;
407 addr[0x02AA] = 0x00550055;
408 addr[0x0555] = 0x00900090;
409#else
410
411 /*
412 * Note: if it is an AMD flash and the word at addr[0000]
413 * is 0x0089 this routine will think it is an Intel
414 * flash device and may(most likely) cause trouble.
415 */
416
417 addr[0x0000] = 0x0090;
418
419 if(addr[0x0000] != 0x0089){
420 addr[0x0555] = 0x00AA;
421 addr[0x02AA] = 0x0055;
422 addr[0x0555] = 0x0090;
423#endif
424 }
425 value = addr[0];
426
427 switch (value) {
428 case (AMD_MANUFACT & FLASH_ID_MASK):
429 info->flash_id = FLASH_MAN_AMD;
430 break;
431 case (FUJ_MANUFACT & FLASH_ID_MASK):
432 info->flash_id = FLASH_MAN_FUJ;
433 break;
434 case (STM_MANUFACT & FLASH_ID_MASK):
435 info->flash_id = FLASH_MAN_STM;
436 break;
437 case (SST_MANUFACT & FLASH_ID_MASK):
438 info->flash_id = FLASH_MAN_SST;
439 break;
440 case (INTEL_MANUFACT & FLASH_ID_MASK):
441 info->flash_id = FLASH_MAN_INTEL;
442 break;
443 default:
444 info->flash_id = FLASH_UNKNOWN;
445 info->sector_count = 0;
446 info->size = 0;
447 return (0); /* no or unknown flash */
448
449 }
450
451 value = addr[1]; /* device ID */
452
453 switch (value) {
454
455 case (AMD_ID_LV400T & FLASH_ID_MASK):
456 info->flash_id += FLASH_AM400T;
457 info->sector_count = 11;
458 info->size = 0x00100000;
459 break; /* => 1 MB */
460
461 case (AMD_ID_LV400B & FLASH_ID_MASK):
462 info->flash_id += FLASH_AM400B;
463 info->sector_count = 11;
464 info->size = 0x00100000;
465 break; /* => 1 MB */
466
467 case (AMD_ID_LV800T & FLASH_ID_MASK):
468 info->flash_id += FLASH_AM800T;
469 info->sector_count = 19;
470 info->size = 0x00200000;
471 break; /* => 2 MB */
472
473 case (AMD_ID_LV800B & FLASH_ID_MASK):
474 info->flash_id += FLASH_AM800B;
475 info->sector_count = 19;
476 info->size = 0x00200000;
477 break; /* => 2 MB */
478
479 case (AMD_ID_LV160T & FLASH_ID_MASK):
480 info->flash_id += FLASH_AM160T;
481 info->sector_count = 35;
482 info->size = 0x00400000;
483 break; /* => 4 MB */
484
485 case (AMD_ID_LV160B & FLASH_ID_MASK):
486 info->flash_id += FLASH_AM160B;
487 info->sector_count = 35;
488 info->size = 0x00400000;
489 break; /* => 4 MB */
490#if 0 /* enable when device IDs are available */
491 case (AMD_ID_LV320T & FLASH_ID_MASK):
492 info->flash_id += FLASH_AM320T;
493 info->sector_count = 67;
494 info->size = 0x00800000;
495 break; /* => 8 MB */
496
497 case (AMD_ID_LV320B & FLASH_ID_MASK):
498 info->flash_id += FLASH_AM320B;
499 info->sector_count = 67;
500 info->size = 0x00800000;
501 break; /* => 8 MB */
502#endif
503
504 case (AMD_ID_DL322T & FLASH_ID_MASK):
505 info->flash_id += FLASH_AMDL322T;
506 info->sector_count = 71;
507 info->size = 0x00800000;
508 break; /* => 8 MB */
509
510 case (INTEL_ID_28F800B3T & FLASH_ID_MASK):
511 info->flash_id += FLASH_INTEL800T;
512 info->sector_count = 23;
513 info->size = 0x00200000;
514 break; /* => 2 MB */
515
516 case (INTEL_ID_28F800B3B & FLASH_ID_MASK):
517 info->flash_id += FLASH_INTEL800B;
518 info->sector_count = 23;
519 info->size = 0x00200000;
520 break; /* => 2 MB */
521
522 case (INTEL_ID_28F160B3T & FLASH_ID_MASK):
523 info->flash_id += FLASH_INTEL160T;
524 info->sector_count = 39;
525 info->size = 0x00400000;
526 break; /* => 4 MB */
527
528 case (INTEL_ID_28F160B3B & FLASH_ID_MASK):
529 info->flash_id += FLASH_INTEL160B;
530 info->sector_count = 39;
531 info->size = 0x00400000;
532 break; /* => 4 MB */
533
534 case (INTEL_ID_28F320B3T & FLASH_ID_MASK):
535 info->flash_id += FLASH_INTEL320T;
536 info->sector_count = 71;
537 info->size = 0x00800000;
538 break; /* => 8 MB */
539
540 case (INTEL_ID_28F320B3B & FLASH_ID_MASK):
541 info->flash_id += FLASH_AM320B;
542 info->sector_count = 71;
543 info->size = 0x00800000;
544 break; /* => 8 MB */
545
546#if 0 /* enable when devices are available */
547 case (INTEL_ID_28F320B3T & FLASH_ID_MASK):
548 info->flash_id += FLASH_INTEL320T;
549 info->sector_count = 135;
550 info->size = 0x01000000;
551 break; /* => 16 MB */
552
553 case (INTEL_ID_28F320B3B & FLASH_ID_MASK):
554 info->flash_id += FLASH_AM320B;
555 info->sector_count = 135;
556 info->size = 0x01000000;
557 break; /* => 16 MB */
558#endif
559 case (INTEL_ID_28F320J3A & FLASH_ID_MASK):
560 info->flash_id += FLASH_28F320J3A;
561 info->sector_count = 32;
562 info->size = 0x00400000;
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200563 break; /* => 32 MBit */
wdenk3bbc8992003-12-07 22:27:15 +0000564 case (INTEL_ID_28F640J3A & FLASH_ID_MASK):
565 info->flash_id += FLASH_28F640J3A;
566 info->sector_count = 64;
567 info->size = 0x00800000;
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200568 break; /* => 64 MBit */
wdenk3bbc8992003-12-07 22:27:15 +0000569 case (INTEL_ID_28F128J3A & FLASH_ID_MASK):
570 info->flash_id += FLASH_28F128J3A;
571 info->sector_count = 128;
572 info->size = 0x01000000;
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200573 break; /* => 128 MBit */
wdenk3bbc8992003-12-07 22:27:15 +0000574
575 default:
576 /* FIXME*/
577 info->flash_id = FLASH_UNKNOWN;
578 return (0); /* => no or unknown flash */
579 }
580
581 flash_get_offsets(base, info);
582
583 /* check for protected sectors */
584 for (i = 0; i < info->sector_count; i++) {
585 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
586 /* D0 = 1 if protected */
587 addr = (volatile FLASH_WORD_SIZE *)(info->start[i]);
588 info->protect[i] = addr[2] & 1;
589 }
590
591 /*
592 * Prevent writes to uninitialized FLASH.
593 */
594 if (info->flash_id != FLASH_UNKNOWN) {
595 addr = (volatile FLASH_WORD_SIZE *)info->start[0];
596 if( (info->flash_id & 0xFF00) == FLASH_MAN_INTEL){
597 *addr = (0x00F000F0 & FLASH_ID_MASK); /* reset bank */
598 } else {
599 *addr = (0x00FF00FF & FLASH_ID_MASK); /* reset bank */
600 }
601 }
602
603 return (info->size);
604}
605
606
607/*-----------------------------------------------------------------------
608 */
609
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200610int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk3bbc8992003-12-07 22:27:15 +0000611{
612
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200613 volatile FLASH_WORD_SIZE *addr =
614 (volatile FLASH_WORD_SIZE *) (info->start[0]);
wdenk3bbc8992003-12-07 22:27:15 +0000615 int flag, prot, sect, l_sect, barf;
616 ulong start, now, last;
617 int rcode = 0;
618
619 if ((s_first < 0) || (s_first > s_last)) {
620 if (info->flash_id == FLASH_UNKNOWN) {
621 printf ("- missing\n");
622 } else {
623 printf ("- no sectors to erase\n");
624 }
625 return 1;
626 }
627
628 if ((info->flash_id == FLASH_UNKNOWN) ||
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200629 ((info->flash_id > FLASH_AMD_COMP) &&
630 ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL))) {
wdenk3bbc8992003-12-07 22:27:15 +0000631 printf ("Can't erase unknown flash type - aborted\n");
632 return 1;
633 }
634
635 prot = 0;
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200636 for (sect = s_first; sect <= s_last; ++sect) {
wdenk3bbc8992003-12-07 22:27:15 +0000637 if (info->protect[sect]) {
638 prot++;
639 }
640 }
641
642 if (prot) {
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200643 printf ("- Warning: %d protected sectors will not be erased!\n", prot);
wdenk3bbc8992003-12-07 22:27:15 +0000644 } else {
645 printf ("\n");
646 }
647
648 l_sect = -1;
649
650 /* Disable interrupts which might cause a timeout here */
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200651 flag = disable_interrupts ();
652 if (info->flash_id < FLASH_AMD_COMP) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200653#ifndef CONFIG_SYS_FLASH_16BIT
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200654 addr[0x0555] = 0x00AA00AA;
655 addr[0x02AA] = 0x00550055;
656 addr[0x0555] = 0x00800080;
657 addr[0x0555] = 0x00AA00AA;
658 addr[0x02AA] = 0x00550055;
wdenk3bbc8992003-12-07 22:27:15 +0000659#else
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200660 addr[0x0555] = 0x00AA;
661 addr[0x02AA] = 0x0055;
662 addr[0x0555] = 0x0080;
663 addr[0x0555] = 0x00AA;
664 addr[0x02AA] = 0x0055;
wdenk3bbc8992003-12-07 22:27:15 +0000665#endif
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200666 /* Start erase on unprotected sectors */
667 for (sect = s_first; sect <= s_last; sect++) {
668 if (info->protect[sect] == 0) { /* not protected */
669 addr = (volatile FLASH_WORD_SIZE *) (info->start[sect]);
670 addr[0] = (0x00300030 & FLASH_ID_MASK);
671 l_sect = sect;
wdenk3bbc8992003-12-07 22:27:15 +0000672 }
wdenk3bbc8992003-12-07 22:27:15 +0000673 }
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200674
675 /* re-enable interrupts if necessary */
676 if (flag)
677 enable_interrupts ();
678
679 /* wait at least 80us - let's wait 1 ms */
680 udelay (1000);
681
682 /*
683 * We wait for the last triggered sector
684 */
685 if (l_sect < 0)
686 goto DONE;
687
688 start = get_timer (0);
689 last = start;
690 addr = (volatile FLASH_WORD_SIZE *) (info->start[l_sect]);
691 while ((addr[0] & (0x00800080 & FLASH_ID_MASK)) !=
692 (0x00800080 & FLASH_ID_MASK)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200693 if ((now = get_timer (start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200694 printf ("Timeout\n");
695 return 1;
696 }
697 /* show that we're waiting */
698 if ((now - last) > 1000) { /* every second */
699 serial_putc ('.');
700 last = now;
701 }
702 }
703
704 DONE:
705 /* reset to read mode */
706 addr = (volatile FLASH_WORD_SIZE *) info->start[0];
707 addr[0] = (0x00F000F0 & FLASH_ID_MASK); /* reset bank */
708 } else {
709
710
711 for (sect = s_first; sect <= s_last; sect++) {
712 if (info->protect[sect] == 0) { /* not protected */
713 barf = 0;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200714#ifndef CONFIG_SYS_FLASH_16BIT
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200715 addr = (vu_long *) (info->start[sect]);
716 addr[0] = 0x00200020;
717 addr[0] = 0x00D000D0;
718 while (!(addr[0] & 0x00800080)); /* wait for error or finish */
719 if (addr[0] & 0x003A003A) { /* check for error */
720 barf = addr[0] & 0x003A0000;
721 if (barf) {
722 barf >>= 16;
723 } else {
724 barf = addr[0] & 0x0000003A;
725 }
726 }
727#else
728 addr = (vu_short *) (info->start[sect]);
729 addr[0] = 0x0020;
730 addr[0] = 0x00D0;
731 while (!(addr[0] & 0x0080)); /* wait for error or finish */
732 if (addr[0] & 0x003A) /* check for error */
733 barf = addr[0] & 0x003A;
734#endif
735 if (barf) {
736 printf ("\nFlash error in sector at %lx\n",
737 (unsigned long) addr);
738 if (barf & 0x0002)
739 printf ("Block locked, not erased.\n");
740 if ((barf & 0x0030) == 0x0030)
741 printf ("Command Sequence error.\n");
742 if ((barf & 0x0030) == 0x0020)
743 printf ("Block Erase error.\n");
744 if (barf & 0x0008)
745 printf ("Vpp Low error.\n");
746 rcode = 1;
747 } else
748 printf (".");
749 l_sect = sect;
750 }
751 addr = (volatile FLASH_WORD_SIZE *) info->start[0];
752 addr[0] = (0x00FF00FF & FLASH_ID_MASK); /* reset bank */
753
754 }
wdenk3bbc8992003-12-07 22:27:15 +0000755
756 }
wdenk3bbc8992003-12-07 22:27:15 +0000757 printf (" done\n");
758 return rcode;
759}
760
761/*-----------------------------------------------------------------------
762 */
763
764/*flash_info_t *addr2info (ulong addr)
765{
766 flash_info_t *info;
767 int i;
768
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200769 for (i=0, info=&flash_info[0]; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
wdenk3bbc8992003-12-07 22:27:15 +0000770 if ((addr >= info->start[0]) &&
771 (addr < (info->start[0] + info->size)) ) {
772 return (info);
773 }
774 }
775
776 return (NULL);
777}
778*/
779/*-----------------------------------------------------------------------
780 * Copy memory to flash.
781 * Make sure all target addresses are within Flash bounds,
782 * and no protected sectors are hit.
783 * Returns:
784 * 0 - OK
785 * 1 - write timeout
786 * 2 - Flash not erased
787 * 4 - target range includes protected sectors
788 * 8 - target address not in Flash memory
789 */
790
791/*int flash_write (uchar *src, ulong addr, ulong cnt)
792{
793 int i;
794 ulong end = addr + cnt - 1;
795 flash_info_t *info_first = addr2info (addr);
796 flash_info_t *info_last = addr2info (end );
797 flash_info_t *info;
798
799 if (cnt == 0) {
800 return (0);
801 }
802
803 if (!info_first || !info_last) {
804 return (8);
805 }
806
807 for (info = info_first; info <= info_last; ++info) {
808 ulong b_end = info->start[0] + info->size;*/ /* bank end addr */
809/* short s_end = info->sector_count - 1;
810 for (i=0; i<info->sector_count; ++i) {
811 ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
812
813 if ((end >= info->start[i]) && (addr < e_addr) &&
814 (info->protect[i] != 0) ) {
815 return (4);
816 }
817 }
818 }
819
820*/ /* finally write data to flash */
821/* for (info = info_first; info <= info_last && cnt>0; ++info) {
822 ulong len;
823
824 len = info->start[0] + info->size - addr;
825 if (len > cnt)
826 len = cnt;
827 if ((i = write_buff(info, src, addr, len)) != 0) {
828 return (i);
829 }
830 cnt -= len;
831 addr += len;
832 src += len;
833 }
834 return (0);
835}
836*/
837/*-----------------------------------------------------------------------
838 * Copy memory to flash, returns:
839 * 0 - OK
840 * 1 - write timeout
841 * 2 - Flash not erased
842 */
843
844int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
845{
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200846#ifndef CONFIG_SYS_FLASH_16BIT
wdenk3bbc8992003-12-07 22:27:15 +0000847 ulong cp, wp, data;
848 int l;
849#else
850 ulong cp, wp;
851 ushort data;
852#endif
853 int i, rc;
854
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200855#ifndef CONFIG_SYS_FLASH_16BIT
wdenk3bbc8992003-12-07 22:27:15 +0000856
857
858 wp = (addr & ~3); /* get lower word aligned address */
859
860 /*
861 * handle unaligned start bytes
862 */
863 if ((l = addr - wp) != 0) {
864 data = 0;
865 for (i=0, cp=wp; i<l; ++i, ++cp) {
866 data = (data << 8) | (*(uchar *)cp);
867 }
868 for (; i<4 && cnt>0; ++i) {
869 data = (data << 8) | *src++;
870 --cnt;
871 ++cp;
872 }
873 for (; cnt==0 && i<4; ++i, ++cp) {
874 data = (data << 8) | (*(uchar *)cp);
875 }
876
877 if ((rc = write_word(info, wp, data)) != 0) {
878 return (rc);
879 }
880 wp += 4;
881 }
882
883 /*
884 * handle word aligned part
885 */
886 while (cnt >= 4) {
887 data = 0;
888 for (i=0; i<4; ++i) {
889 data = (data << 8) | *src++;
890 }
891 if ((rc = write_word(info, wp, data)) != 0) {
892 return (rc);
893 }
894 wp += 4;
895 cnt -= 4;
896 }
897
898 if (cnt == 0) {
899 return (0);
900 }
901
902 /*
903 * handle unaligned tail bytes
904 */
905 data = 0;
906 for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
907 data = (data << 8) | *src++;
908 --cnt;
909 }
910 for (; i<4; ++i, ++cp) {
911 data = (data << 8) | (*(uchar *)cp);
912 }
913
914 return (write_word(info, wp, data));
915
916#else
917 wp = (addr & ~1); /* get lower word aligned address */
918
919 /*
920 * handle unaligned start byte
921 */
922 if (addr - wp) {
923 data = 0;
924 data = (data << 8) | *src++;
925 --cnt;
926 if ((rc = write_short(info, wp, data)) != 0) {
927 return (rc);
928 }
929 wp += 2;
930 }
931
932 /*
933 * handle word aligned part
934 */
935/* l = 0; used for debuging */
936 while (cnt >= 2) {
937 data = 0;
938 for (i=0; i<2; ++i) {
939 data = (data << 8) | *src++;
940 }
941
942/* if(!l){
943 printf("%x",data);
944 l = 1;
945 } used for debuging */
946
947 if ((rc = write_short(info, wp, data)) != 0) {
948 return (rc);
949 }
950 wp += 2;
951 cnt -= 2;
952 }
953
954 if (cnt == 0) {
955 return (0);
956 }
957
958 /*
959 * handle unaligned tail bytes
960 */
961 data = 0;
962 for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) {
963 data = (data << 8) | *src++;
964 --cnt;
965 }
966 for (; i<2; ++i, ++cp) {
967 data = (data << 8) | (*(uchar *)cp);
968 }
969
970 return (write_short(info, wp, data));
971
972
973#endif
974}
975
976/*-----------------------------------------------------------------------
977 * Write a word to Flash, returns:
978 * 0 - OK
979 * 1 - write timeout
980 * 2 - Flash not erased
981 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200982#ifndef CONFIG_SYS_FLASH_16BIT
wdenk3bbc8992003-12-07 22:27:15 +0000983static int write_word (flash_info_t *info, ulong dest, ulong data)
984{
985 vu_long *addr = (vu_long*)(info->start[0]);
986 ulong start,barf;
987 int flag;
988
989
990 /* Check if Flash is (sufficiently) erased */
991 if ((*((vu_long *)dest) & data) != data) {
992 return (2);
993 }
994
995 /* Disable interrupts which might cause a timeout here */
996 flag = disable_interrupts();
997
998 if(info->flash_id > FLASH_AMD_COMP) {
999 /* AMD stuff */
1000 addr[0x0555] = 0x00AA00AA;
1001 addr[0x02AA] = 0x00550055;
1002 addr[0x0555] = 0x00A000A0;
1003 } else {
1004 /* intel stuff */
1005 *addr = 0x00400040;
1006 }
1007 *((vu_long *)dest) = data;
1008
1009 /* re-enable interrupts if necessary */
1010 if (flag)
1011 enable_interrupts();
1012
1013 /* data polling for D7 */
1014 start = get_timer (0);
1015
1016 if(info->flash_id > FLASH_AMD_COMP) {
1017 while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001018 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenk3bbc8992003-12-07 22:27:15 +00001019 return (1);
1020 }
1021 }
1022 } else {
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001023 while(!(addr[0] & 0x00800080)) { /* wait for error or finish */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001024 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenk3bbc8992003-12-07 22:27:15 +00001025 return (1);
1026 }
1027
1028 if( addr[0] & 0x003A003A) { /* check for error */
1029 barf = addr[0] & 0x003A0000;
1030 if( barf ) {
1031 barf >>=16;
1032 } else {
1033 barf = addr[0] & 0x0000003A;
1034 }
1035 printf("\nFlash write error at address %lx\n",(unsigned long)dest);
1036 if(barf & 0x0002) printf("Block locked, not erased.\n");
1037 if(barf & 0x0010) printf("Programming error.\n");
1038 if(barf & 0x0008) printf("Vpp Low error.\n");
1039 return(2);
1040 }
1041 }
1042
1043 return (0);
1044}
1045
1046#else
1047
1048static int write_short (flash_info_t *info, ulong dest, ushort data)
1049{
1050 vu_short *addr = (vu_short*)(info->start[0]);
1051 ulong start,barf;
1052 int flag;
1053
1054 /* Check if Flash is (sufficiently) erased */
1055 if ((*((vu_short *)dest) & data) != data) {
1056 return (2);
1057 }
1058
1059 /* Disable interrupts which might cause a timeout here */
1060 flag = disable_interrupts();
1061
1062 if(info->flash_id < FLASH_AMD_COMP) {
1063 /* AMD stuff */
1064 addr[0x0555] = 0x00AA;
1065 addr[0x02AA] = 0x0055;
1066 addr[0x0555] = 0x00A0;
1067 } else {
1068 /* intel stuff */
1069 *addr = 0x00D0;
1070 *addr = 0x0040;
1071 }
1072 *((vu_short *)dest) = data;
1073
1074 /* re-enable interrupts if necessary */
1075 if (flag)
1076 enable_interrupts();
1077
1078 /* data polling for D7 */
1079 start = get_timer (0);
1080
1081 if(info->flash_id < FLASH_AMD_COMP) {
1082 /* AMD stuff */
1083 while ((*((vu_short *)dest) & 0x0080) != (data & 0x0080)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001084 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenk3bbc8992003-12-07 22:27:15 +00001085 return (1);
1086 }
1087 }
1088
1089 } else {
1090 /* intel stuff */
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001091 while(!(addr[0] & 0x0080)){ /* wait for error or finish */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001092 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) return (1);
wdenk3bbc8992003-12-07 22:27:15 +00001093 }
1094
1095 if( addr[0] & 0x003A) { /* check for error */
1096 barf = addr[0] & 0x003A;
1097 printf("\nFlash write error at address %lx\n",(unsigned long)dest);
1098 if(barf & 0x0002) printf("Block locked, not erased.\n");
1099 if(barf & 0x0010) printf("Programming error.\n");
1100 if(barf & 0x0008) printf("Vpp Low error.\n");
1101 return(2);
1102 }
1103 *addr = 0x00B0;
1104 *addr = 0x0070;
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001105 while(!(addr[0] & 0x0080)){ /* wait for error or finish */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001106 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) return (1);
wdenk3bbc8992003-12-07 22:27:15 +00001107 }
1108 *addr = 0x00FF;
1109 }
1110 return (0);
1111}
1112
wdenk3bbc8992003-12-07 22:27:15 +00001113#endif
1114
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001115/*-----------------------------------------------------------------------*/