]>
Commit | Line | Data |
---|---|---|
1c43771b WD |
1 | /* |
2 | * (C) Copyright 2003 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * (C) Copyright 2003 | |
6 | * Reinhard Meyer, EMK Elektronik GmbH, r.meyer@emk-elektronik.de | |
7 | * | |
1a459660 | 8 | * SPDX-License-Identifier: GPL-2.0+ |
1c43771b WD |
9 | */ |
10 | ||
11 | #include <common.h> | |
12 | ||
6d0f6bcf | 13 | flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */ |
1c43771b | 14 | |
63e73c9a WD |
15 | #if defined (CONFIG_TOP860) |
16 | typedef unsigned short FLASH_PORT_WIDTH; | |
17 | typedef volatile unsigned short FLASH_PORT_WIDTHV; | |
18 | #define FLASH_ID_MASK 0xFF | |
19 | ||
20 | #define FPW FLASH_PORT_WIDTH | |
21 | #define FPWV FLASH_PORT_WIDTHV | |
22 | ||
23 | #define FLASH_CYCLE1 0x0555 | |
24 | #define FLASH_CYCLE2 0x02aa | |
25 | #define FLASH_ID1 0 | |
26 | #define FLASH_ID2 1 | |
4d13cbad WD |
27 | #define FLASH_ID3 0x0e |
28 | #define FLASH_ID4 0x0F | |
63e73c9a WD |
29 | #endif |
30 | ||
4d13cbad | 31 | #if defined (CONFIG_TOP5200) && !defined (CONFIG_LITE5200) |
63e73c9a WD |
32 | typedef unsigned char FLASH_PORT_WIDTH; |
33 | typedef volatile unsigned char FLASH_PORT_WIDTHV; | |
34 | #define FLASH_ID_MASK 0xFF | |
1c43771b | 35 | |
63e73c9a WD |
36 | #define FPW FLASH_PORT_WIDTH |
37 | #define FPWV FLASH_PORT_WIDTHV | |
1c43771b | 38 | |
63e73c9a WD |
39 | #define FLASH_CYCLE1 0x0aaa |
40 | #define FLASH_CYCLE2 0x0555 | |
41 | #define FLASH_ID1 0 | |
42 | #define FLASH_ID2 2 | |
4d13cbad WD |
43 | #define FLASH_ID3 0x1c |
44 | #define FLASH_ID4 0x1E | |
45 | #endif | |
46 | ||
47 | #if defined (CONFIG_TOP5200) && defined (CONFIG_LITE5200) | |
48 | typedef unsigned char FLASH_PORT_WIDTH; | |
49 | typedef volatile unsigned char FLASH_PORT_WIDTHV; | |
50 | #define FLASH_ID_MASK 0xFF | |
51 | ||
52 | #define FPW FLASH_PORT_WIDTH | |
53 | #define FPWV FLASH_PORT_WIDTHV | |
54 | ||
55 | #define FLASH_CYCLE1 0x0555 | |
56 | #define FLASH_CYCLE2 0x02aa | |
57 | #define FLASH_ID1 0 | |
58 | #define FLASH_ID2 1 | |
59 | #define FLASH_ID3 0x0E | |
60 | #define FLASH_ID4 0x0F | |
63e73c9a | 61 | #endif |
1c43771b WD |
62 | |
63 | /*----------------------------------------------------------------------- | |
64 | * Functions | |
65 | */ | |
66 | static ulong flash_get_size(FPWV *addr, flash_info_t *info); | |
67 | static void flash_reset(flash_info_t *info); | |
68 | static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data); | |
b8845abd | 69 | flash_info_t *flash_get_info(ulong base); |
1c43771b WD |
70 | |
71 | /*----------------------------------------------------------------------- | |
72 | * flash_init() | |
73 | * | |
74 | * sets up flash_info and returns size of FLASH (bytes) | |
75 | */ | |
76 | unsigned long flash_init (void) | |
77 | { | |
78 | unsigned long size = 0; | |
79 | int i = 0; | |
80 | extern void flash_preinit(void); | |
81 | extern void flash_afterinit(uint, ulong, ulong); | |
6d0f6bcf | 82 | ulong flashbase = CONFIG_SYS_FLASH_BASE; |
1c43771b WD |
83 | |
84 | flash_preinit(); | |
85 | ||
86 | /* There is only ONE FLASH device */ | |
87 | memset(&flash_info[i], 0, sizeof(flash_info_t)); | |
88 | flash_info[i].size = | |
89 | flash_get_size((FPW *)flashbase, &flash_info[i]); | |
90 | size += flash_info[i].size; | |
91 | ||
6d0f6bcf | 92 | #if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE |
1c43771b WD |
93 | /* monitor protection ON by default */ |
94 | flash_protect(FLAG_PROTECT_SET, | |
6d0f6bcf JCPV |
95 | CONFIG_SYS_MONITOR_BASE, |
96 | CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1, | |
97 | flash_get_info(CONFIG_SYS_MONITOR_BASE)); | |
1c43771b WD |
98 | #endif |
99 | ||
5a1aceb0 | 100 | #ifdef CONFIG_ENV_IS_IN_FLASH |
1c43771b WD |
101 | /* ENV protection ON by default */ |
102 | flash_protect(FLAG_PROTECT_SET, | |
0e8d1586 JCPV |
103 | CONFIG_ENV_ADDR, |
104 | CONFIG_ENV_ADDR+CONFIG_ENV_SIZE-1, | |
105 | flash_get_info(CONFIG_ENV_ADDR)); | |
1c43771b WD |
106 | #endif |
107 | ||
108 | ||
109 | flash_afterinit(i, flash_info[i].start[0], flash_info[i].size); | |
110 | return size ? size : 1; | |
111 | } | |
112 | ||
113 | /*----------------------------------------------------------------------- | |
114 | */ | |
115 | static void flash_reset(flash_info_t *info) | |
116 | { | |
117 | FPWV *base = (FPWV *)(info->start[0]); | |
118 | ||
119 | /* Put FLASH back in read mode */ | |
120 | if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) | |
121 | *base = (FPW)0x00FF00FF; /* Intel Read Mode */ | |
122 | else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD) | |
123 | *base = (FPW)0x00F000F0; /* AMD Read Mode */ | |
124 | } | |
125 | ||
126 | /*----------------------------------------------------------------------- | |
127 | */ | |
128 | ||
b8845abd | 129 | flash_info_t *flash_get_info(ulong base) |
1c43771b WD |
130 | { |
131 | int i; | |
132 | flash_info_t * info; | |
133 | ||
6d0f6bcf | 134 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i ++) { |
1c43771b WD |
135 | info = & flash_info[i]; |
136 | if (info->size && | |
137 | info->start[0] <= base && base <= info->start[0] + info->size - 1) | |
138 | break; | |
139 | } | |
140 | ||
6d0f6bcf | 141 | return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info; |
1c43771b WD |
142 | } |
143 | ||
144 | /*----------------------------------------------------------------------- | |
145 | */ | |
146 | ||
147 | void flash_print_info (flash_info_t *info) | |
148 | { | |
149 | int i; | |
150 | uchar *boottype; | |
151 | uchar *bootletter; | |
77ddac94 | 152 | char *fmt; |
1c43771b WD |
153 | uchar botbootletter[] = "B"; |
154 | uchar topbootletter[] = "T"; | |
155 | uchar botboottype[] = "bottom boot sector"; | |
156 | uchar topboottype[] = "top boot sector"; | |
157 | ||
158 | if (info->flash_id == FLASH_UNKNOWN) { | |
159 | printf ("missing or unknown FLASH type\n"); | |
160 | return; | |
161 | } | |
162 | ||
163 | switch (info->flash_id & FLASH_VENDMASK) { | |
164 | case FLASH_MAN_AMD: printf ("AMD "); break; | |
165 | #if 0 | |
166 | case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break; | |
167 | case FLASH_MAN_FUJ: printf ("FUJITSU "); break; | |
168 | case FLASH_MAN_SST: printf ("SST "); break; | |
169 | case FLASH_MAN_STM: printf ("STM "); break; | |
170 | case FLASH_MAN_INTEL: printf ("INTEL "); break; | |
171 | #endif | |
172 | default: printf ("Unknown Vendor "); break; | |
173 | } | |
174 | ||
175 | /* check for top or bottom boot, if it applies */ | |
176 | if (info->flash_id & FLASH_BTYPE) { | |
177 | boottype = botboottype; | |
178 | bootletter = botbootletter; | |
179 | } | |
180 | else { | |
181 | boottype = topboottype; | |
182 | bootletter = topbootletter; | |
183 | } | |
184 | ||
185 | switch (info->flash_id & FLASH_TYPEMASK) { | |
186 | case FLASH_AM160T: | |
187 | case FLASH_AM160B: | |
188 | fmt = "29LV160%s (16 Mbit, %s)\n"; | |
189 | break; | |
4d13cbad WD |
190 | case FLASH_AMLV640U: |
191 | fmt = "29LV640M (64 Mbit)\n"; | |
192 | break; | |
193 | case FLASH_AMDLV065D: | |
194 | fmt = "29LV065D (64 Mbit)\n"; | |
195 | break; | |
196 | case FLASH_AMLV256U: | |
197 | fmt = "29LV256M (256 Mbit)\n"; | |
198 | break; | |
1c43771b WD |
199 | default: |
200 | fmt = "Unknown Chip Type\n"; | |
201 | break; | |
202 | } | |
203 | ||
204 | printf (fmt, bootletter, boottype); | |
205 | ||
206 | printf (" Size: %ld MB in %d Sectors\n", | |
207 | info->size >> 20, | |
208 | info->sector_count); | |
209 | ||
210 | printf (" Sector Start Addresses:"); | |
211 | ||
212 | for (i=0; i<info->sector_count; ++i) { | |
63e73c9a WD |
213 | ulong size; |
214 | int erased; | |
215 | ulong *flash = (unsigned long *) info->start[i]; | |
216 | ||
1c43771b WD |
217 | if ((i % 5) == 0) { |
218 | printf ("\n "); | |
219 | } | |
220 | ||
63e73c9a WD |
221 | /* |
222 | * Check if whole sector is erased | |
223 | */ | |
224 | size = | |
225 | (i != (info->sector_count - 1)) ? | |
226 | (info->start[i + 1] - info->start[i]) >> 2 : | |
227 | (info->start[0] + info->size - info->start[i]) >> 2; | |
228 | ||
229 | for ( | |
230 | flash = (unsigned long *) info->start[i], erased = 1; | |
231 | (flash != (unsigned long *) info->start[i] + size) && erased; | |
232 | flash++ | |
233 | ) | |
234 | erased = *flash == ~0x0UL; | |
235 | ||
236 | printf (" %08lX %s %s", | |
237 | info->start[i], | |
238 | erased ? "E": " ", | |
239 | info->protect[i] ? "(RO)" : " "); | |
1c43771b WD |
240 | } |
241 | ||
242 | printf ("\n"); | |
243 | } | |
244 | ||
245 | /*----------------------------------------------------------------------- | |
246 | */ | |
247 | ||
248 | /* | |
249 | * The following code cannot be run from FLASH! | |
250 | */ | |
251 | ||
252 | ulong flash_get_size (FPWV *addr, flash_info_t *info) | |
253 | { | |
254 | int i; | |
1c43771b WD |
255 | |
256 | /* Write auto select command: read Manufacturer ID */ | |
257 | /* Write auto select command sequence and test FLASH answer */ | |
258 | addr[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */ | |
259 | addr[FLASH_CYCLE2] = (FPW)0x00550055; /* for AMD, Intel ignores this */ | |
260 | addr[FLASH_CYCLE1] = (FPW)0x00900090; /* selects Intel or AMD */ | |
261 | ||
262 | /* The manufacturer codes are only 1 byte, so just use 1 byte. | |
263 | * This works for any bus width and any FLASH device width. | |
264 | */ | |
265 | udelay(100); | |
63e73c9a | 266 | switch (addr[FLASH_ID1] & 0xff) { |
1c43771b WD |
267 | |
268 | case (uchar)AMD_MANUFACT: | |
269 | info->flash_id = FLASH_MAN_AMD; | |
270 | break; | |
271 | ||
272 | #if 0 | |
273 | case (uchar)INTEL_MANUFACT: | |
274 | info->flash_id = FLASH_MAN_INTEL; | |
275 | break; | |
276 | #endif | |
277 | ||
278 | default: | |
63e73c9a | 279 | printf ("unknown vendor=%x ", addr[FLASH_ID1] & 0xff); |
1c43771b WD |
280 | info->flash_id = FLASH_UNKNOWN; |
281 | info->sector_count = 0; | |
282 | info->size = 0; | |
283 | break; | |
284 | } | |
285 | ||
286 | /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */ | |
63e73c9a | 287 | if (info->flash_id != FLASH_UNKNOWN) switch ((FPW)addr[FLASH_ID2]) { |
1c43771b WD |
288 | |
289 | case (FPW)AMD_ID_LV160B: | |
290 | info->flash_id += FLASH_AM160B; | |
291 | info->sector_count = 35; | |
292 | info->size = 0x00200000; | |
4d13cbad WD |
293 | info->start[0] = (ulong)addr; |
294 | info->start[1] = (ulong)addr + 0x4000; | |
295 | info->start[2] = (ulong)addr + 0x6000; | |
296 | info->start[3] = (ulong)addr + 0x8000; | |
1c43771b WD |
297 | for (i = 4; i < info->sector_count; i++) |
298 | { | |
4d13cbad | 299 | info->start[i] = (ulong)addr + 0x10000 * (i-3); |
1c43771b WD |
300 | } |
301 | break; | |
302 | ||
4d13cbad WD |
303 | case (FPW)AMD_ID_LV065D: |
304 | info->flash_id += FLASH_AMDLV065D; | |
305 | info->sector_count = 128; | |
306 | info->size = 0x00800000; | |
307 | for (i = 0; i < info->sector_count; i++) | |
308 | { | |
309 | info->start[i] = (ulong)addr + 0x10000 * i; | |
310 | } | |
311 | break; | |
312 | ||
313 | case (FPW)AMD_ID_MIRROR: | |
314 | /* MIRROR BIT FLASH, read more ID bytes */ | |
315 | if ((FPW)addr[FLASH_ID3] == (FPW)AMD_ID_LV640U_2 && | |
316 | (FPW)addr[FLASH_ID4] == (FPW)AMD_ID_LV640U_3) | |
317 | { | |
318 | info->flash_id += FLASH_AMLV640U; | |
319 | info->sector_count = 128; | |
320 | info->size = 0x00800000; | |
321 | for (i = 0; i < info->sector_count; i++) | |
322 | { | |
323 | info->start[i] = (ulong)addr + 0x10000 * i; | |
324 | } | |
325 | break; | |
326 | } | |
327 | if ((FPW)addr[FLASH_ID3] == (FPW)AMD_ID_LV256U_2 && | |
328 | (FPW)addr[FLASH_ID4] == (FPW)AMD_ID_LV256U_3) | |
329 | { | |
330 | /* attention: only the first 16 MB will be used in u-boot */ | |
331 | info->flash_id += FLASH_AMLV256U; | |
332 | info->sector_count = 256; | |
333 | info->size = 0x01000000; | |
334 | for (i = 0; i < info->sector_count; i++) | |
335 | { | |
336 | info->start[i] = (ulong)addr + 0x10000 * i; | |
337 | } | |
338 | break; | |
339 | } | |
42dfe7a1 | 340 | |
4d13cbad | 341 | /* fall thru to here ! */ |
1c43771b | 342 | default: |
4d13cbad WD |
343 | printf ("unknown AMD device=%x %x %x", |
344 | (FPW)addr[FLASH_ID2], | |
345 | (FPW)addr[FLASH_ID3], | |
346 | (FPW)addr[FLASH_ID4]); | |
1c43771b WD |
347 | info->flash_id = FLASH_UNKNOWN; |
348 | info->sector_count = 0; | |
4d13cbad WD |
349 | info->size = 0x800000; |
350 | break; | |
1c43771b WD |
351 | } |
352 | ||
353 | /* Put FLASH back in read mode */ | |
354 | flash_reset(info); | |
355 | ||
356 | return (info->size); | |
357 | } | |
358 | ||
359 | /*----------------------------------------------------------------------- | |
360 | */ | |
361 | ||
362 | int flash_erase (flash_info_t *info, int s_first, int s_last) | |
363 | { | |
364 | FPWV *addr; | |
365 | int flag, prot, sect; | |
366 | int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL; | |
367 | ulong start, now, last; | |
368 | int rcode = 0; | |
369 | ||
370 | if ((s_first < 0) || (s_first > s_last)) { | |
371 | if (info->flash_id == FLASH_UNKNOWN) { | |
372 | printf ("- missing\n"); | |
373 | } else { | |
374 | printf ("- no sectors to erase\n"); | |
375 | } | |
376 | return 1; | |
377 | } | |
378 | ||
379 | switch (info->flash_id & FLASH_TYPEMASK) { | |
380 | case FLASH_AM160B: | |
4d13cbad | 381 | case FLASH_AMLV640U: |
1c43771b WD |
382 | break; |
383 | case FLASH_UNKNOWN: | |
384 | default: | |
385 | printf ("Can't erase unknown flash type %08lx - aborted\n", | |
386 | info->flash_id); | |
387 | return 1; | |
388 | } | |
389 | ||
390 | prot = 0; | |
391 | for (sect=s_first; sect<=s_last; ++sect) { | |
392 | if (info->protect[sect]) { | |
393 | prot++; | |
394 | } | |
395 | } | |
396 | ||
397 | if (prot) { | |
398 | printf ("- Warning: %d protected sectors will not be erased!\n", | |
399 | prot); | |
400 | } else { | |
401 | printf ("\n"); | |
402 | } | |
403 | ||
404 | last = get_timer(0); | |
405 | ||
406 | /* Start erase on unprotected sectors */ | |
407 | for (sect = s_first; sect<=s_last && rcode == 0; sect++) { | |
408 | ||
409 | if (info->protect[sect] != 0) /* protected, skip it */ | |
410 | continue; | |
411 | ||
412 | /* Disable interrupts which might cause a timeout here */ | |
413 | flag = disable_interrupts(); | |
414 | ||
415 | addr = (FPWV *)(info->start[sect]); | |
416 | if (intel) { | |
417 | *addr = (FPW)0x00500050; /* clear status register */ | |
418 | *addr = (FPW)0x00200020; /* erase setup */ | |
419 | *addr = (FPW)0x00D000D0; /* erase confirm */ | |
420 | } | |
421 | else { | |
422 | /* must be AMD style if not Intel */ | |
423 | FPWV *base; /* first address in bank */ | |
424 | ||
425 | base = (FPWV *)(info->start[0]); | |
426 | base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */ | |
427 | base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */ | |
428 | base[FLASH_CYCLE1] = (FPW)0x00800080; /* erase mode */ | |
429 | base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */ | |
430 | base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */ | |
431 | *addr = (FPW)0x00300030; /* erase sector */ | |
432 | } | |
433 | ||
434 | /* re-enable interrupts if necessary */ | |
435 | if (flag) | |
436 | enable_interrupts(); | |
437 | ||
438 | start = get_timer(0); | |
439 | ||
440 | /* wait at least 50us for AMD, 80us for Intel. | |
441 | * Let's wait 1 ms. | |
442 | */ | |
443 | udelay (1000); | |
444 | ||
445 | while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) { | |
6d0f6bcf | 446 | if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) { |
1c43771b WD |
447 | printf ("Timeout\n"); |
448 | ||
449 | if (intel) { | |
450 | /* suspend erase */ | |
451 | *addr = (FPW)0x00B000B0; | |
452 | } | |
453 | ||
454 | flash_reset(info); /* reset to read mode */ | |
455 | rcode = 1; /* failed */ | |
456 | break; | |
457 | } | |
458 | ||
459 | /* show that we're waiting */ | |
6d0f6bcf | 460 | if ((get_timer(last)) > CONFIG_SYS_HZ) {/* every second */ |
1c43771b WD |
461 | putc ('.'); |
462 | last = get_timer(0); | |
463 | } | |
464 | } | |
465 | ||
466 | /* show that we're waiting */ | |
6d0f6bcf | 467 | if ((get_timer(last)) > CONFIG_SYS_HZ) { /* every second */ |
1c43771b WD |
468 | putc ('.'); |
469 | last = get_timer(0); | |
470 | } | |
471 | ||
472 | flash_reset(info); /* reset to read mode */ | |
473 | } | |
474 | ||
475 | printf (" done\n"); | |
476 | return rcode; | |
477 | } | |
478 | ||
479 | /*----------------------------------------------------------------------- | |
480 | * Copy memory to flash, returns: | |
481 | * 0 - OK | |
482 | * 1 - write timeout | |
483 | * 2 - Flash not erased | |
484 | */ | |
485 | int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
486 | { | |
487 | FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */ | |
488 | int bytes; /* number of bytes to program in current word */ | |
489 | int left; /* number of bytes left to program */ | |
490 | int i, res; | |
491 | ||
492 | for (left = cnt, res = 0; | |
493 | left > 0 && res == 0; | |
494 | addr += sizeof(data), left -= sizeof(data) - bytes) { | |
495 | ||
496 | bytes = addr & (sizeof(data) - 1); | |
497 | addr &= ~(sizeof(data) - 1); | |
498 | ||
499 | /* combine source and destination data so can program | |
500 | * an entire word of 16 or 32 bits | |
501 | */ | |
502 | for (i = 0; i < sizeof(data); i++) { | |
503 | data <<= 8; | |
504 | if (i < bytes || i - bytes >= left ) | |
505 | data += *((uchar *)addr + i); | |
506 | else | |
507 | data += *src++; | |
508 | } | |
509 | ||
510 | /* write one word to the flash */ | |
511 | switch (info->flash_id & FLASH_VENDMASK) { | |
512 | case FLASH_MAN_AMD: | |
513 | res = write_word_amd(info, (FPWV *)addr, data); | |
514 | break; | |
515 | default: | |
516 | /* unknown flash type, error! */ | |
517 | printf ("missing or unknown FLASH type\n"); | |
518 | res = 1; /* not really a timeout, but gives error */ | |
519 | break; | |
520 | } | |
521 | } | |
522 | ||
523 | return (res); | |
524 | } | |
525 | ||
526 | /*----------------------------------------------------------------------- | |
527 | * Write a word to Flash for AMD FLASH | |
528 | * A word is 16 or 32 bits, whichever the bus width of the flash bank | |
529 | * (not an individual chip) is. | |
530 | * | |
531 | * returns: | |
532 | * 0 - OK | |
533 | * 1 - write timeout | |
534 | * 2 - Flash not erased | |
535 | */ | |
536 | static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data) | |
537 | { | |
538 | ulong start; | |
539 | int flag; | |
540 | int res = 0; /* result, assume success */ | |
541 | FPWV *base; /* first address in flash bank */ | |
542 | ||
543 | /* Check if Flash is (sufficiently) erased */ | |
544 | if ((*dest & data) != data) { | |
545 | return (2); | |
546 | } | |
547 | ||
548 | ||
549 | base = (FPWV *)(info->start[0]); | |
550 | ||
551 | /* Disable interrupts which might cause a timeout here */ | |
552 | flag = disable_interrupts(); | |
553 | ||
554 | base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */ | |
555 | base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */ | |
556 | base[FLASH_CYCLE1] = (FPW)0x00A000A0; /* selects program mode */ | |
557 | ||
558 | *dest = data; /* start programming the data */ | |
559 | ||
560 | /* re-enable interrupts if necessary */ | |
561 | if (flag) | |
562 | enable_interrupts(); | |
563 | ||
564 | start = get_timer (0); | |
565 | ||
566 | /* data polling for D7 */ | |
567 | while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) { | |
6d0f6bcf | 568 | if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) { |
1c43771b WD |
569 | *dest = (FPW)0x00F000F0; /* reset bank */ |
570 | res = 1; | |
571 | } | |
572 | } | |
573 | ||
574 | return (res); | |
575 | } |