blob: 2406c5f4c037e2d720ba42c5a7ba48c0cd8cf0b4 [file] [log] [blame]
wdenk6310eb92005-01-09 21:28:15 +00001/*
2 * (C) Copyright 2000
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 <mpc8xx.h>
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020026/* environment.h defines the various CONFIG_ENV_... values in terms
wdenk6310eb92005-01-09 21:28:15 +000027 * of whichever ones are given in the configuration file.
28 */
29#include <environment.h>
30
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020031flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenk6310eb92005-01-09 21:28:15 +000032
33/* NOTE - CONFIG_FLASH_16BIT means the CPU interface is 16-bit, it
34 * has nothing to do with the flash chip being 8-bit or 16-bit.
35 */
36#ifdef CONFIG_FLASH_16BIT
37typedef unsigned short FLASH_PORT_WIDTH;
38typedef volatile unsigned short FLASH_PORT_WIDTHV;
39
40#define FLASH_ID_MASK 0xFFFF
41#else
42typedef unsigned long FLASH_PORT_WIDTH;
43typedef volatile unsigned long FLASH_PORT_WIDTHV;
44
45#define FLASH_ID_MASK 0xFFFFFFFF
46#endif
47
48#define FPW FLASH_PORT_WIDTH
49#define FPWV FLASH_PORT_WIDTHV
50
51#define ORMASK(size) ((-size) & OR_AM_MSK)
52
53/*-----------------------------------------------------------------------
54 * Functions
55 */
56static ulong flash_get_size (FPWV * addr, flash_info_t * info);
57static void flash_reset (flash_info_t * info);
58static int write_word_intel (flash_info_t * info, FPWV * dest, FPW data);
59static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data);
60static void flash_get_offsets (ulong base, flash_info_t * info);
61
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020062#ifdef CONFIG_SYS_FLASH_PROTECTION
wdenk6310eb92005-01-09 21:28:15 +000063static void flash_sync_real_protect (flash_info_t * info);
64#endif
65
66/*-----------------------------------------------------------------------
67 * flash_init()
68 *
69 * sets up flash_info and returns size of FLASH (bytes)
70 */
71unsigned long flash_init (void)
72{
73 unsigned long size_b;
74 int i;
75
76 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020077 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenk6310eb92005-01-09 21:28:15 +000078 flash_info[i].flash_id = FLASH_UNKNOWN;
79 }
80
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020081 size_b = flash_get_size ((FPW *) CONFIG_SYS_FLASH_BASE, &flash_info[0]);
wdenk6310eb92005-01-09 21:28:15 +000082
83 flash_info[0].size = size_b;
84
85 if (flash_info[0].flash_id == FLASH_UNKNOWN) {
86 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx\n",
87 size_b);
88 }
89
90 /* Do this again (was done already in flast_get_size), just
91 * in case we move it when remap the FLASH.
92 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020093 flash_get_offsets (CONFIG_SYS_FLASH_BASE, &flash_info[0]);
wdenk6310eb92005-01-09 21:28:15 +000094
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020095#ifdef CONFIG_SYS_FLASH_PROTECTION
wdenk6310eb92005-01-09 21:28:15 +000096 /* read the hardware protection status (if any) into the
97 * protection array in flash_info.
98 */
99 flash_sync_real_protect (&flash_info[0]);
100#endif
101
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200102#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
wdenk6310eb92005-01-09 21:28:15 +0000103 /* monitor protection ON by default */
104 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200105 CONFIG_SYS_MONITOR_BASE,
106 CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
wdenk6310eb92005-01-09 21:28:15 +0000107 &flash_info[0]);
108#endif
109
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200110#ifdef CONFIG_ENV_ADDR
wdenk6310eb92005-01-09 21:28:15 +0000111 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200112 CONFIG_ENV_ADDR,
Wolfgang Denkdfcd7f22009-05-15 00:16:03 +0200113 CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1, &flash_info[0]);
wdenk6310eb92005-01-09 21:28:15 +0000114#endif
115
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200116#ifdef CONFIG_ENV_ADDR_REDUND
wdenk6310eb92005-01-09 21:28:15 +0000117 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200118 CONFIG_ENV_ADDR_REDUND,
Wolfgang Denkdfcd7f22009-05-15 00:16:03 +0200119 CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1,
wdenk6310eb92005-01-09 21:28:15 +0000120 &flash_info[0]);
121#endif
122
123 return (size_b);
124}
125
126/*-----------------------------------------------------------------------
127 */
128static void flash_reset (flash_info_t * info)
129{
130 FPWV *base = (FPWV *) (info->start[0]);
131
132 /* Put FLASH back in read mode */
133 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
134 *base = (FPW) 0x00FF00FF; /* Intel Read Mode */
135 else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
136 *base = (FPW) 0x00F000F0; /* AMD Read Mode */
137}
138
139/*-----------------------------------------------------------------------
140 */
141static void flash_get_offsets (ulong base, flash_info_t * info)
142{
143 int i;
144
145 /* set up sector start address table */
146 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL
147 && (info->flash_id & FLASH_BTYPE)) {
148 int bootsect_size; /* number of bytes/boot sector */
149 int sect_size; /* number of bytes/regular sector */
150
151 bootsect_size = 0x00002000 * (sizeof (FPW) / 2);
152 sect_size = 0x00010000 * (sizeof (FPW) / 2);
153
154 /* set sector offsets for bottom boot block type */
155 for (i = 0; i < 8; ++i) {
156 info->start[i] = base + (i * bootsect_size);
157 }
158 for (i = 8; i < info->sector_count; i++) {
159 info->start[i] = base + ((i - 7) * sect_size);
160 }
161 } else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD
162 && (info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U) {
163
164 int sect_size; /* number of bytes/sector */
165
166 sect_size = 0x00010000 * (sizeof (FPW) / 2);
167
168 /* set up sector start address table (uniform sector type) */
169 for (i = 0; i < info->sector_count; i++)
170 info->start[i] = base + (i * sect_size);
171 } else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD
172 && (info->flash_id & FLASH_TYPEMASK) == FLASH_AM800T) {
173
174 int sect_size; /* number of bytes/sector */
175
176 sect_size = 0x00010000 * (sizeof (FPW) / 2);
177
178 /* set up sector start address table (top boot sector type) */
179 for (i = 0; i < info->sector_count - 3; i++)
180 info->start[i] = base + (i * sect_size);
181 i = info->sector_count - 1;
182 info->start[i--] =
183 base + (info->size - 0x00004000) * (sizeof (FPW) / 2);
184 info->start[i--] =
185 base + (info->size - 0x00006000) * (sizeof (FPW) / 2);
186 info->start[i--] =
187 base + (info->size - 0x00008000) * (sizeof (FPW) / 2);
188 }
189}
190
191/*-----------------------------------------------------------------------
192 */
193
194void flash_print_info (flash_info_t * info)
195{
196 int i;
197 uchar *boottype;
198 uchar *bootletter;
Wolfgang Denk8412d812007-11-18 17:11:09 +0100199 char *fmt;
wdenk6310eb92005-01-09 21:28:15 +0000200 uchar botbootletter[] = "B";
201 uchar topbootletter[] = "T";
202 uchar botboottype[] = "bottom boot sector";
203 uchar topboottype[] = "top boot sector";
204
205 if (info->flash_id == FLASH_UNKNOWN) {
206 printf ("missing or unknown FLASH type\n");
207 return;
208 }
209
210 switch (info->flash_id & FLASH_VENDMASK) {
211 case FLASH_MAN_AMD:
212 printf ("AMD ");
213 break;
214 case FLASH_MAN_BM:
215 printf ("BRIGHT MICRO ");
216 break;
217 case FLASH_MAN_FUJ:
218 printf ("FUJITSU ");
219 break;
220 case FLASH_MAN_SST:
221 printf ("SST ");
222 break;
223 case FLASH_MAN_STM:
224 printf ("STM ");
225 break;
226 case FLASH_MAN_INTEL:
227 printf ("INTEL ");
228 break;
229 default:
230 printf ("Unknown Vendor ");
231 break;
232 }
233
234 /* check for top or bottom boot, if it applies */
235 if (info->flash_id & FLASH_BTYPE) {
236 boottype = botboottype;
237 bootletter = botbootletter;
238 } else {
239 boottype = topboottype;
240 bootletter = topbootletter;
241 }
242
243 switch (info->flash_id & FLASH_TYPEMASK) {
244 case FLASH_AM800T:
245 fmt = "29LV800B%s (8 Mbit, %s)\n";
246 break;
247 case FLASH_AM640U:
248 fmt = "29LV641D (64 Mbit, uniform sectors)\n";
249 break;
250 case FLASH_28F800C3B:
251 case FLASH_28F800C3T:
252 fmt = "28F800C3%s (8 Mbit, %s)\n";
253 break;
254 case FLASH_INTEL800B:
255 case FLASH_INTEL800T:
256 fmt = "28F800B3%s (8 Mbit, %s)\n";
257 break;
258 case FLASH_28F160C3B:
259 case FLASH_28F160C3T:
260 fmt = "28F160C3%s (16 Mbit, %s)\n";
261 break;
262 case FLASH_INTEL160B:
263 case FLASH_INTEL160T:
264 fmt = "28F160B3%s (16 Mbit, %s)\n";
265 break;
266 case FLASH_28F320C3B:
267 case FLASH_28F320C3T:
268 fmt = "28F320C3%s (32 Mbit, %s)\n";
269 break;
270 case FLASH_INTEL320B:
271 case FLASH_INTEL320T:
272 fmt = "28F320B3%s (32 Mbit, %s)\n";
273 break;
274 case FLASH_28F640C3B:
275 case FLASH_28F640C3T:
276 fmt = "28F640C3%s (64 Mbit, %s)\n";
277 break;
278 case FLASH_INTEL640B:
279 case FLASH_INTEL640T:
280 fmt = "28F640B3%s (64 Mbit, %s)\n";
281 break;
282 default:
283 fmt = "Unknown Chip Type\n";
284 break;
285 }
286
287 printf (fmt, bootletter, boottype);
288
289 printf (" Size: %ld MB in %d Sectors\n",
290 info->size >> 20, info->sector_count);
291
292 printf (" Sector Start Addresses:");
293
294 for (i = 0; i < info->sector_count; ++i) {
295 if ((i % 5) == 0) {
296 printf ("\n ");
297 }
298
299 printf (" %08lX%s", info->start[i],
300 info->protect[i] ? " (RO)" : " ");
301 }
302
303 printf ("\n");
304}
305
306/*-----------------------------------------------------------------------
307 */
308
309/*
310 * The following code cannot be run from FLASH!
311 */
312
313ulong flash_get_size (FPWV * addr, flash_info_t * info)
314{
315 /* Write auto select command: read Manufacturer ID */
316
317 /* Write auto select command sequence and test FLASH answer */
318 addr[0x0555] = (FPW) 0x00AA00AA; /* for AMD, Intel ignores this */
319 addr[0x02AA] = (FPW) 0x00550055; /* for AMD, Intel ignores this */
320 addr[0x0555] = (FPW) 0x00900090; /* selects Intel or AMD */
321
322 /* The manufacturer codes are only 1 byte, so just use 1 byte.
323 * This works for any bus width and any FLASH device width.
324 */
325 switch (addr[0] & 0xff) {
326
327 case (uchar) AMD_MANUFACT:
328 info->flash_id = FLASH_MAN_AMD;
329 break;
330
331 case (uchar) INTEL_MANUFACT:
332 info->flash_id = FLASH_MAN_INTEL;
333 break;
334
335 default:
336 info->flash_id = FLASH_UNKNOWN;
337 info->sector_count = 0;
338 info->size = 0;
339 break;
340 }
341
342 /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
343 if (info->flash_id != FLASH_UNKNOWN)
344 switch (addr[1]) {
345
346 case (FPW) AMD_ID_LV800T:
347 info->flash_id += FLASH_AM800T;
348 info->sector_count = 19;
349 info->size = 0x00100000 * (sizeof (FPW) / 2);
350 break; /* => 1 or 2 MiB */
351
352 case (FPW) AMD_ID_LV640U: /* 29LV640 and 29LV641 have same ID */
353 info->flash_id += FLASH_AM640U;
354 info->sector_count = 128;
355 info->size = 0x00800000 * (sizeof (FPW) / 2);
356 break; /* => 8 or 16 MB */
357
358 case (FPW) INTEL_ID_28F800C3B:
359 info->flash_id += FLASH_28F800C3B;
360 info->sector_count = 23;
361 info->size = 0x00100000 * (sizeof (FPW) / 2);
362 break; /* => 1 or 2 MB */
363
364 case (FPW) INTEL_ID_28F800B3B:
365 info->flash_id += FLASH_INTEL800B;
366 info->sector_count = 23;
367 info->size = 0x00100000 * (sizeof (FPW) / 2);
368 break; /* => 1 or 2 MB */
369
370 case (FPW) INTEL_ID_28F160C3B:
371 info->flash_id += FLASH_28F160C3B;
372 info->sector_count = 39;
373 info->size = 0x00200000 * (sizeof (FPW) / 2);
374 break; /* => 2 or 4 MB */
375
376 case (FPW) INTEL_ID_28F160B3B:
377 info->flash_id += FLASH_INTEL160B;
378 info->sector_count = 39;
379 info->size = 0x00200000 * (sizeof (FPW) / 2);
380 break; /* => 2 or 4 MB */
381
382 case (FPW) INTEL_ID_28F320C3B:
383 info->flash_id += FLASH_28F320C3B;
384 info->sector_count = 71;
385 info->size = 0x00400000 * (sizeof (FPW) / 2);
386 break; /* => 4 or 8 MB */
387
388 case (FPW) INTEL_ID_28F320B3B:
389 info->flash_id += FLASH_INTEL320B;
390 info->sector_count = 71;
391 info->size = 0x00400000 * (sizeof (FPW) / 2);
392 break; /* => 4 or 8 MB */
393
394 case (FPW) INTEL_ID_28F640C3B:
395 info->flash_id += FLASH_28F640C3B;
396 info->sector_count = 135;
397 info->size = 0x00800000 * (sizeof (FPW) / 2);
398 break; /* => 8 or 16 MB */
399
400 case (FPW) INTEL_ID_28F640B3B:
401 info->flash_id += FLASH_INTEL640B;
402 info->sector_count = 135;
403 info->size = 0x00800000 * (sizeof (FPW) / 2);
404 break; /* => 8 or 16 MB */
405
406 default:
407 info->flash_id = FLASH_UNKNOWN;
408 info->sector_count = 0;
409 info->size = 0;
410 return (0); /* => no or unknown flash */
411 }
412
413 flash_get_offsets ((ulong) addr, info);
414
415 /* Put FLASH back in read mode */
416 flash_reset (info);
417
418 return (info->size);
419}
420
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200421#ifdef CONFIG_SYS_FLASH_PROTECTION
wdenk6310eb92005-01-09 21:28:15 +0000422/*-----------------------------------------------------------------------
423 */
424
425static void flash_sync_real_protect (flash_info_t * info)
426{
427 FPWV *addr = (FPWV *) (info->start[0]);
428 FPWV *sect;
429 int i;
430
431 switch (info->flash_id & FLASH_TYPEMASK) {
432 case FLASH_28F800C3B:
433 case FLASH_28F800C3T:
434 case FLASH_28F160C3B:
435 case FLASH_28F160C3T:
436 case FLASH_28F320C3B:
437 case FLASH_28F320C3T:
438 case FLASH_28F640C3B:
439 case FLASH_28F640C3T:
440 /* check for protected sectors */
441 *addr = (FPW) 0x00900090;
442 for (i = 0; i < info->sector_count; i++) {
443 /* read sector protection at sector address, (A7 .. A0) = 0x02.
444 * D0 = 1 for each device if protected.
445 * If at least one device is protected the sector is marked
446 * protected, but mixed protected and unprotected devices
447 * within a sector should never happen.
448 */
449 sect = (FPWV *) (info->start[i]);
450 info->protect[i] =
451 (sect[2] & (FPW) (0x00010001)) ? 1 : 0;
452 }
453
454 /* Put FLASH back in read mode */
455 flash_reset (info);
456 break;
457
458 case FLASH_AM640U:
459 case FLASH_AM800T:
460 default:
461 /* no hardware protect that we support */
462 break;
463 }
464}
465#endif
466
467/*-----------------------------------------------------------------------
468 */
469
470int flash_erase (flash_info_t * info, int s_first, int s_last)
471{
472 FPWV *addr;
473 int flag, prot, sect;
474 int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
Graeme Russa60d1e52011-07-15 23:31:37 +0000475 ulong start, now, last;
wdenk6310eb92005-01-09 21:28:15 +0000476 int rcode = 0;
477
478 if ((s_first < 0) || (s_first > s_last)) {
479 if (info->flash_id == FLASH_UNKNOWN) {
480 printf ("- missing\n");
481 } else {
482 printf ("- no sectors to erase\n");
483 }
484 return 1;
485 }
486
487 switch (info->flash_id & FLASH_TYPEMASK) {
488 case FLASH_INTEL800B:
489 case FLASH_INTEL160B:
490 case FLASH_INTEL320B:
491 case FLASH_INTEL640B:
492 case FLASH_28F800C3B:
493 case FLASH_28F160C3B:
494 case FLASH_28F320C3B:
495 case FLASH_28F640C3B:
496 case FLASH_AM640U:
497 case FLASH_AM800T:
498 break;
499 case FLASH_UNKNOWN:
500 default:
501 printf ("Can't erase unknown flash type %08lx - aborted\n",
502 info->flash_id);
503 return 1;
504 }
505
506 prot = 0;
507 for (sect = s_first; sect <= s_last; ++sect) {
508 if (info->protect[sect]) {
509 prot++;
510 }
511 }
512
513 if (prot) {
514 printf ("- Warning: %d protected sectors will not be erased!\n", prot);
515 } else {
516 printf ("\n");
517 }
518
wdenk6310eb92005-01-09 21:28:15 +0000519 /* Start erase on unprotected sectors */
520 for (sect = s_first; sect <= s_last && rcode == 0; sect++) {
521
522 if (info->protect[sect] != 0) /* protected, skip it */
523 continue;
524
525 /* Disable interrupts which might cause a timeout here */
526 flag = disable_interrupts ();
527
Graeme Russa60d1e52011-07-15 23:31:37 +0000528 start = get_timer(0);
wdenk6310eb92005-01-09 21:28:15 +0000529 last = 0;
530
531 addr = (FPWV *) (info->start[sect]);
532 if (intel) {
533 *addr = (FPW) 0x00500050; /* clear status register */
534 *addr = (FPW) 0x00200020; /* erase setup */
535 *addr = (FPW) 0x00D000D0; /* erase confirm */
536 } else {
537 /* must be AMD style if not Intel */
538 FPWV *base; /* first address in bank */
539
540 base = (FPWV *) (info->start[0]);
541 base[0x0555] = (FPW) 0x00AA00AA; /* unlock */
542 base[0x02AA] = (FPW) 0x00550055; /* unlock */
543 base[0x0555] = (FPW) 0x00800080; /* erase mode */
544 base[0x0555] = (FPW) 0x00AA00AA; /* unlock */
545 base[0x02AA] = (FPW) 0x00550055; /* unlock */
546 *addr = (FPW) 0x00300030; /* erase sector */
547 }
548
549 /* re-enable interrupts if necessary */
550 if (flag)
551 enable_interrupts ();
552
553 /* wait at least 50us for AMD, 80us for Intel.
554 * Let's wait 1 ms.
555 */
556 udelay (1000);
557
558 while ((*addr & (FPW) 0x00800080) != (FPW) 0x00800080) {
559 if ((now =
Graeme Russa60d1e52011-07-15 23:31:37 +0000560 get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenk6310eb92005-01-09 21:28:15 +0000561 printf ("Timeout\n");
562
563 if (intel) {
564 /* suspend erase */
565 *addr = (FPW) 0x00B000B0;
566 }
567
568 flash_reset (info); /* reset to read mode */
569 rcode = 1; /* failed */
570 break;
571 }
572
573 /* show that we're waiting */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200574 if ((now - last) > 1 * CONFIG_SYS_HZ) { /* every second */
wdenk6310eb92005-01-09 21:28:15 +0000575 putc ('.');
576 last = now;
577 }
578 }
579
580 flash_reset (info); /* reset to read mode */
581 }
582
583 printf (" done\n");
584 return rcode;
585}
586
587/*-----------------------------------------------------------------------
588 * Copy memory to flash, returns:
589 * 0 - OK
590 * 1 - write timeout
591 * 2 - Flash not erased
592 */
593int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
594{
595 FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
596 int bytes; /* number of bytes to program in current word */
597 int left; /* number of bytes left to program */
598 int i, res;
599
600 for (left = cnt, res = 0;
601 left > 0 && res == 0;
602 addr += sizeof (data), left -= sizeof (data) - bytes) {
603
604 bytes = addr & (sizeof (data) - 1);
605 addr &= ~(sizeof (data) - 1);
606
607 /* combine source and destination data so can program
608 * an entire word of 16 or 32 bits
609 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200610#ifdef CONFIG_SYS_LITTLE_ENDIAN
wdenk6310eb92005-01-09 21:28:15 +0000611 for (i = 0; i < sizeof (data); i++) {
612 data >>= 8;
613 if (i < bytes || i - bytes >= left)
614 data += (*((uchar *) addr + i)) << 24;
615 else
616 data += (*src++) << 24;
617 }
618#else
619 for (i = 0; i < sizeof (data); i++) {
620 data <<= 8;
621 if (i < bytes || i - bytes >= left)
622 data += *((uchar *) addr + i);
623 else
624 data += *src++;
625 }
626#endif
627
628 /* write one word to the flash */
629 switch (info->flash_id & FLASH_VENDMASK) {
630 case FLASH_MAN_AMD:
631 res = write_word_amd (info, (FPWV *) addr, data);
632 break;
633 case FLASH_MAN_INTEL:
634 res = write_word_intel (info, (FPWV *) addr, data);
635 break;
636 default:
637 /* unknown flash type, error! */
638 printf ("missing or unknown FLASH type\n");
639 res = 1; /* not really a timeout, but gives error */
640 break;
641 }
642 }
643
644 return (res);
645}
646
647/*-----------------------------------------------------------------------
648 * Write a word to Flash for AMD FLASH
649 * A word is 16 or 32 bits, whichever the bus width of the flash bank
650 * (not an individual chip) is.
651 *
652 * returns:
653 * 0 - OK
654 * 1 - write timeout
655 * 2 - Flash not erased
656 */
657static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data)
658{
659 int flag;
660 int res = 0; /* result, assume success */
661 FPWV *base; /* first address in flash bank */
Graeme Russa60d1e52011-07-15 23:31:37 +0000662 ulong start;
wdenk6310eb92005-01-09 21:28:15 +0000663
664 /* Check if Flash is (sufficiently) erased */
665 if ((*dest & data) != data) {
666 return (2);
667 }
668
669
670 base = (FPWV *) (info->start[0]);
671
672 /* Disable interrupts which might cause a timeout here */
673 flag = disable_interrupts ();
674
675 base[0x0555] = (FPW) 0x00AA00AA; /* unlock */
676 base[0x02AA] = (FPW) 0x00550055; /* unlock */
677 base[0x0555] = (FPW) 0x00A000A0; /* selects program mode */
678
679 *dest = data; /* start programming the data */
680
681 /* re-enable interrupts if necessary */
682 if (flag)
683 enable_interrupts ();
684
Graeme Russa60d1e52011-07-15 23:31:37 +0000685 start = get_timer(0);
wdenk6310eb92005-01-09 21:28:15 +0000686
687 /* data polling for D7 */
688 while (res == 0
689 && (*dest & (FPW) 0x00800080) != (data & (FPW) 0x00800080)) {
Graeme Russa60d1e52011-07-15 23:31:37 +0000690 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenk6310eb92005-01-09 21:28:15 +0000691 *dest = (FPW) 0x00F000F0; /* reset bank */
692 res = 1;
693 }
694 }
695
696 return (res);
697}
698
699/*-----------------------------------------------------------------------
700 * Write a word to Flash for Intel FLASH
701 * A word is 16 or 32 bits, whichever the bus width of the flash bank
702 * (not an individual chip) is.
703 *
704 * returns:
705 * 0 - OK
706 * 1 - write timeout
707 * 2 - Flash not erased
708 */
709static int write_word_intel (flash_info_t * info, FPWV * dest, FPW data)
710{
711 int flag;
712 int res = 0; /* result, assume success */
Graeme Russa60d1e52011-07-15 23:31:37 +0000713 ulong start;
wdenk6310eb92005-01-09 21:28:15 +0000714
715 /* Check if Flash is (sufficiently) erased */
716 if ((*dest & data) != data) {
717 return (2);
718 }
719
720 /* Disable interrupts which might cause a timeout here */
721 flag = disable_interrupts ();
722
723 *dest = (FPW) 0x00500050; /* clear status register */
724 *dest = (FPW) 0x00FF00FF; /* make sure in read mode */
725 *dest = (FPW) 0x00400040; /* program setup */
726
727 *dest = data; /* start programming the data */
728
729 /* re-enable interrupts if necessary */
730 if (flag)
731 enable_interrupts ();
732
Graeme Russa60d1e52011-07-15 23:31:37 +0000733 start = get_timer(0);
wdenk6310eb92005-01-09 21:28:15 +0000734
735 while (res == 0 && (*dest & (FPW) 0x00800080) != (FPW) 0x00800080) {
Graeme Russa60d1e52011-07-15 23:31:37 +0000736 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenk6310eb92005-01-09 21:28:15 +0000737 *dest = (FPW) 0x00B000B0; /* Suspend program */
738 res = 1;
739 }
740 }
741
742 if (res == 0 && (*dest & (FPW) 0x00100010))
743 res = 1; /* write failed, time out error is close enough */
744
745 *dest = (FPW) 0x00500050; /* clear status register */
746 *dest = (FPW) 0x00FF00FF; /* make sure in read mode */
747
748 return (res);
749}
750
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200751#ifdef CONFIG_SYS_FLASH_PROTECTION
wdenk6310eb92005-01-09 21:28:15 +0000752/*-----------------------------------------------------------------------
753 */
754int flash_real_protect (flash_info_t * info, long sector, int prot)
755{
756 int rcode = 0; /* assume success */
757 FPWV *addr; /* address of sector */
758 FPW value;
759
760 addr = (FPWV *) (info->start[sector]);
761
762 switch (info->flash_id & FLASH_TYPEMASK) {
763 case FLASH_28F800C3B:
764 case FLASH_28F800C3T:
765 case FLASH_28F160C3B:
766 case FLASH_28F160C3T:
767 case FLASH_28F320C3B:
768 case FLASH_28F320C3T:
769 case FLASH_28F640C3B:
770 case FLASH_28F640C3T:
771 flash_reset (info); /* make sure in read mode */
772 *addr = (FPW) 0x00600060L; /* lock command setup */
773 if (prot)
774 *addr = (FPW) 0x00010001L; /* lock sector */
775 else
776 *addr = (FPW) 0x00D000D0L; /* unlock sector */
777 flash_reset (info); /* reset to read mode */
778
779 /* now see if it really is locked/unlocked as requested */
780 *addr = (FPW) 0x00900090;
781 /* read sector protection at sector address, (A7 .. A0) = 0x02.
782 * D0 = 1 for each device if protected.
783 * If at least one device is protected the sector is marked
784 * protected, but return failure. Mixed protected and
785 * unprotected devices within a sector should never happen.
786 */
787 value = addr[2] & (FPW) 0x00010001;
788 if (value == 0)
789 info->protect[sector] = 0;
790 else if (value == (FPW) 0x00010001)
791 info->protect[sector] = 1;
792 else {
793 /* error, mixed protected and unprotected */
794 rcode = 1;
795 info->protect[sector] = 1;
796 }
797 if (info->protect[sector] != prot)
798 rcode = 1; /* failed to protect/unprotect as requested */
799
800 /* reload all protection bits from hardware for now */
801 flash_sync_real_protect (info);
802 break;
803
804 case FLASH_AM640U:
805 case FLASH_AM800T:
806 default:
807 /* no hardware protect that we support */
808 info->protect[sector] = prot;
809 break;
810 }
811
812 return rcode;
813}
814#endif