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