]>
Commit | Line | Data |
---|---|---|
b4676a25 WD |
1 | /* |
2 | * (C) Copyright 2000 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * (C) Copyright 2001-2003 | |
5 | * | |
6 | * Changes for MATRIX Vision mvBLUE devices | |
7 | * MATRIX Vision GmbH / hg,as info@matrix-vision.de | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU General Public License as | |
11 | * published by the Free Software Foundation; either version 2 of | |
12 | * the License, or (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
22 | * MA 02111-1307 USA | |
23 | */ | |
24 | ||
25 | #include <common.h> | |
26 | #include <mpc824x.h> | |
27 | ||
28 | #if 0 | |
29 | #define mvdebug(p) printf ##p | |
30 | #else | |
31 | #define mvdebug(p) | |
32 | #endif | |
33 | ||
34 | flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; | |
35 | ||
36 | #define FLASH_BUS_WIDTH 8 | |
37 | ||
38 | #if (FLASH_BUS_WIDTH==32) | |
39 | #define FLASH_DATA_MASK 0xffffffff | |
40 | #define FLASH_SHIFT 1 | |
41 | #define FDT vu_long | |
42 | #elif (FLASH_BUS_WIDTH==16) | |
43 | #define FLASH_DATA_MASK 0xff | |
44 | #define FLASH_SHIFT 0 | |
45 | #define FDT vu_short | |
46 | #elif (FLASH_BUS_WIDTH==8) | |
47 | #define FLASH_DATA_MASK 0xff | |
48 | #define FLASH_SHIFT 0 | |
49 | #define FDT vu_char | |
50 | #else | |
51 | #error FLASH_BUS_WIDTH undefined | |
52 | #endif | |
53 | ||
54 | /*----------------------------------------------------------------------- | |
55 | * Functions | |
56 | */ | |
57 | static ulong flash_get_size (vu_long *address, flash_info_t *info); | |
58 | static int write_word (flash_info_t *info, ulong dest, ulong data); | |
59 | static void flash_get_offsets (ulong base, flash_info_t *info); | |
60 | ||
61 | /*----------------------------------------------------------------------- | |
62 | */ | |
63 | unsigned long flash_init (void) | |
64 | { | |
65 | unsigned long size_b0; | |
66 | int i; | |
67 | ||
68 | for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) { | |
69 | flash_info[i].flash_id = FLASH_UNKNOWN; | |
70 | } | |
71 | ||
72 | size_b0 = flash_get_size((vu_long *)0xffc00000, &flash_info[0]); | |
73 | ||
74 | if (flash_info[0].flash_id == FLASH_UNKNOWN) { | |
75 | printf ("## Unknown FLASH : Size = 0x%08lx = %ld MB\n", | |
76 | size_b0, size_b0<<20); | |
77 | } | |
78 | ||
79 | flash_get_offsets (0xffc00000, &flash_info[0]); | |
80 | flash_info[0].size = size_b0; | |
81 | ||
82 | /* monitor protection OFF by default */ | |
83 | flash_protect ( FLAG_PROTECT_CLEAR, 0xffc00000, 0x2000, flash_info ); | |
84 | ||
85 | return size_b0; | |
86 | } | |
87 | ||
88 | /*----------------------------------------------------------------------- | |
89 | */ | |
90 | static void flash_get_offsets (ulong base, flash_info_t *info) | |
91 | { | |
92 | int i; | |
93 | ||
94 | /* set up sector start address table */ | |
95 | if (info->flash_id & FLASH_BTYPE) | |
96 | { /* bottom boot sector types - these are the useful ones! */ | |
97 | /* set sector offsets for bottom boot block type */ | |
98 | if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) | |
99 | { /* AMDLV320B has 8 x 8k bottom boot sectors */ | |
100 | for (i = 0; i < 8; i++) /* +8k */ | |
101 | info->start[i] = base + (i * (0x00002000 << FLASH_SHIFT)); | |
102 | for (; i < info->sector_count; i++) /* +64k */ | |
103 | info->start[i] = base + (i * (0x00010000 << FLASH_SHIFT)) - (0x00070000 << FLASH_SHIFT); | |
104 | } | |
105 | else | |
106 | { /* other types have 4 bottom boot sectors (16,8,8,32) */ | |
107 | i = 0; | |
108 | info->start[i++] = base + 0x00000000; /* - */ | |
109 | info->start[i++] = base + (0x00004000 << FLASH_SHIFT); /* +16k */ | |
110 | info->start[i++] = base + (0x00006000 << FLASH_SHIFT); /* +8k */ | |
111 | info->start[i++] = base + (0x00008000 << FLASH_SHIFT); /* +8k */ | |
112 | info->start[i++] = base + (0x00010000 << FLASH_SHIFT); /* +32k */ | |
113 | for (; i < info->sector_count; i++) /* +64k */ | |
114 | info->start[i] = base + (i * (0x00010000 << FLASH_SHIFT)) - (0x00030000 << FLASH_SHIFT); | |
115 | } | |
116 | } | |
117 | else | |
118 | { /* top boot sector types - not so useful */ | |
119 | /* set sector offsets for top boot block type */ | |
120 | if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) | |
121 | { /* AMDLV320T has 8 x 8k top boot sectors */ | |
122 | for (i = 0; i < info->sector_count - 8; i++) /* +64k */ | |
123 | info->start[i] = base + (i * (0x00010000 << FLASH_SHIFT)); | |
124 | for (; i < info->sector_count; i++) /* +8k */ | |
125 | info->start[i] = base + (i * (0x00002000 << FLASH_SHIFT)); | |
126 | } | |
127 | else | |
128 | { /* other types have 4 top boot sectors (32,8,8,16) */ | |
129 | for (i = 0; i < info->sector_count - 4; i++) /* +64k */ | |
130 | info->start[i] = base + (i * (0x00010000 << FLASH_SHIFT)); | |
131 | ||
132 | info->start[i++] = base + info->size - (0x00010000 << FLASH_SHIFT); /* -32k */ | |
133 | info->start[i++] = base + info->size - (0x00008000 << FLASH_SHIFT); /* -8k */ | |
134 | info->start[i++] = base + info->size - (0x00006000 << FLASH_SHIFT); /* -8k */ | |
135 | info->start[i] = base + info->size - (0x00004000 << FLASH_SHIFT); /* -16k */ | |
136 | } | |
137 | } | |
138 | } | |
139 | ||
140 | /*----------------------------------------------------------------------- | |
141 | */ | |
142 | void flash_print_info (flash_info_t *info) | |
143 | { | |
144 | int i; | |
145 | ||
146 | if (info->flash_id == FLASH_UNKNOWN) { | |
147 | printf ("missing or unknown FLASH type\n"); | |
148 | return; | |
149 | } | |
150 | ||
151 | switch (info->flash_id & FLASH_VENDMASK) { | |
152 | case FLASH_MAN_AMD: printf ("AMD "); break; | |
153 | case FLASH_MAN_FUJ: printf ("FUJITSU "); break; | |
154 | case FLASH_MAN_STM: printf ("ST "); break; | |
155 | default: printf ("Unknown Vendor "); break; | |
156 | } | |
157 | ||
158 | switch (info->flash_id & FLASH_TYPEMASK) { | |
159 | case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n"); | |
160 | break; | |
161 | case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n"); | |
162 | break; | |
163 | case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n"); | |
164 | break; | |
165 | case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n"); | |
166 | break; | |
167 | case FLASH_STMW320DB: printf ("M29W320B (32 Mbit, bottom boot sect)\n"); | |
168 | break; | |
169 | case FLASH_STMW320DT: printf ("M29W320T (32 Mbit, top boot sector)\n"); | |
170 | break; | |
171 | default: printf ("Unknown Chip Type\n"); | |
172 | break; | |
173 | } | |
174 | ||
175 | printf (" Size: %ld MB in %d Sectors\n", info->size >> 20, info->sector_count); | |
176 | ||
177 | printf (" Sector Start Addresses:"); | |
178 | for (i=0; i<info->sector_count; ++i) { | |
179 | if ((i % 5) == 0) | |
180 | printf ("\n "); | |
181 | printf (" %08lX%s", info->start[i], info->protect[i] ? " (RO)" : " "); | |
182 | } | |
183 | printf ("\n"); | |
184 | } | |
185 | ||
186 | /* | |
187 | * The following code cannot be run from FLASH! | |
188 | */ | |
189 | ||
190 | #define AMD_ID_LV160T_MVS (AMD_ID_LV160T & FLASH_DATA_MASK) | |
191 | #define AMD_ID_LV160B_MVS (AMD_ID_LV160B & FLASH_DATA_MASK) | |
192 | #define AMD_ID_LV320T_MVS (AMD_ID_LV320T & FLASH_DATA_MASK) | |
193 | #define AMD_ID_LV320B_MVS (AMD_ID_LV320B & FLASH_DATA_MASK) | |
194 | #define STM_ID_W320DT_MVS (STM_ID_29W320DT & FLASH_DATA_MASK) | |
195 | #define STM_ID_W320DB_MVS (STM_ID_29W320DB & FLASH_DATA_MASK) | |
196 | #define AMD_MANUFACT_MVS (AMD_MANUFACT & FLASH_DATA_MASK) | |
197 | #define FUJ_MANUFACT_MVS (FUJ_MANUFACT & FLASH_DATA_MASK) | |
198 | #define STM_MANUFACT_MVS (STM_MANUFACT & FLASH_DATA_MASK) | |
199 | ||
200 | #if (FLASH_BUS_WIDTH >= 16) | |
201 | #define AUTOSELECT_ADDR1 0x0555 | |
202 | #define AUTOSELECT_ADDR2 0x02AA | |
203 | #define AUTOSELECT_ADDR3 AUTOSELECT_ADDR1 | |
204 | #else | |
205 | #define AUTOSELECT_ADDR1 0x0AAA | |
206 | #define AUTOSELECT_ADDR2 0x0555 | |
207 | #define AUTOSELECT_ADDR3 AUTOSELECT_ADDR1 | |
208 | #endif | |
209 | ||
210 | #define AUTOSELECT_DATA1 (0x00AA00AA & FLASH_DATA_MASK) | |
211 | #define AUTOSELECT_DATA2 (0x00550055 & FLASH_DATA_MASK) | |
212 | #define AUTOSELECT_DATA3 (0x00900090 & FLASH_DATA_MASK) | |
213 | ||
214 | #define RESET_BANK_DATA (0x00F000F0 & FLASH_DATA_MASK) | |
215 | ||
216 | ||
217 | static ulong flash_get_size (vu_long *address, flash_info_t *info) | |
218 | { | |
219 | short i; | |
220 | FDT value; | |
221 | FDT *addr = (FDT *)address; | |
222 | ||
223 | ulong base = (ulong)address; | |
224 | addr[AUTOSELECT_ADDR1] = AUTOSELECT_DATA1; | |
225 | addr[AUTOSELECT_ADDR2] = AUTOSELECT_DATA2; | |
226 | addr[AUTOSELECT_ADDR3] = AUTOSELECT_DATA3; | |
227 | __asm__ __volatile__("sync"); | |
228 | ||
229 | udelay(180); | |
230 | ||
231 | value = addr[0]; /* manufacturer ID */ | |
232 | switch (value) { | |
233 | case AMD_MANUFACT_MVS: | |
234 | info->flash_id = FLASH_MAN_AMD; | |
235 | break; | |
236 | case FUJ_MANUFACT_MVS: | |
237 | info->flash_id = FLASH_MAN_FUJ; | |
238 | break; | |
239 | case STM_MANUFACT_MVS: | |
240 | info->flash_id = FLASH_MAN_STM; | |
241 | break; | |
242 | default: | |
243 | info->flash_id = FLASH_UNKNOWN; | |
244 | info->sector_count = 0; | |
245 | info->size = 0; | |
246 | return (0); /* no or unknown flash */ | |
247 | } | |
248 | #if (FLASH_BUS_WIDTH >= 16) | |
249 | value = addr[1]; /* device ID */ | |
250 | #else | |
251 | value = addr[2]; /* device ID */ | |
252 | #endif | |
253 | ||
254 | switch (value) { | |
255 | case AMD_ID_LV160T_MVS: | |
256 | info->flash_id += FLASH_AM160T; | |
257 | info->sector_count = 37; | |
258 | info->size = (0x00200000 << FLASH_SHIFT); | |
259 | break; /* => 2 or 4 MB */ | |
260 | ||
261 | case AMD_ID_LV160B_MVS: | |
262 | info->flash_id += FLASH_AM160B; | |
263 | info->sector_count = 37; | |
264 | info->size = (0x00200000 << FLASH_SHIFT); | |
265 | break; /* => 2 or 4 MB */ | |
266 | ||
267 | case AMD_ID_LV320T_MVS: | |
268 | info->flash_id += FLASH_AM320T; | |
269 | info->sector_count = 71; | |
270 | info->size = (0x00400000 << FLASH_SHIFT); | |
271 | break; /* => 4 or 8 MB */ | |
272 | ||
273 | case AMD_ID_LV320B_MVS: | |
274 | info->flash_id += FLASH_AM320B; | |
275 | info->sector_count = 71; | |
276 | info->size = (0x00400000 << FLASH_SHIFT); | |
277 | break; /* => 4 or 8MB */ | |
278 | ||
279 | case STM_ID_W320DT_MVS: | |
280 | info->flash_id += FLASH_STMW320DT; | |
281 | info->sector_count = 67; | |
282 | info->size = (0x00400000 << FLASH_SHIFT); | |
283 | break; /* => 4 or 8 MB */ | |
284 | ||
285 | case STM_ID_W320DB_MVS: | |
286 | info->flash_id += FLASH_STMW320DB; | |
287 | info->sector_count = 67; | |
288 | info->size = (0x00400000 << FLASH_SHIFT); | |
289 | break; /* => 4 or 8MB */ | |
290 | ||
291 | default: | |
292 | info->flash_id = FLASH_UNKNOWN; | |
293 | return (0); /* => no or unknown flash */ | |
294 | ||
295 | } | |
296 | ||
297 | /* set up sector start address table */ | |
298 | flash_get_offsets (base, info); | |
299 | ||
300 | /* check for protected sectors */ | |
301 | for (i = 0; i < info->sector_count; i++) { | |
302 | /* read sector protection at sector address, (A7 .. A0) = 0x02 */ | |
303 | /* D0 = 1 if protected */ | |
304 | addr = (FDT *)(info->start[i]); | |
305 | info->protect[i] = addr[2] & 1; | |
306 | } | |
307 | ||
308 | /* | |
309 | * Prevent writes to uninitialized FLASH. | |
310 | */ | |
311 | if (info->flash_id != FLASH_UNKNOWN) { | |
312 | addr = (FDT *)info->start[0]; | |
313 | *addr = RESET_BANK_DATA; /* reset bank */ | |
314 | } | |
315 | return (info->size); | |
316 | } | |
317 | ||
318 | ||
319 | /*----------------------------------------------------------------------- | |
320 | */ | |
321 | ||
322 | #if (FLASH_BUS_WIDTH >= 16) | |
323 | #define ERASE_ADDR1 0x0555 | |
324 | #define ERASE_ADDR2 0x02AA | |
325 | #else | |
326 | #define ERASE_ADDR1 0x0AAA | |
327 | #define ERASE_ADDR2 0x0555 | |
328 | #endif | |
329 | ||
330 | #define ERASE_ADDR3 ERASE_ADDR1 | |
331 | #define ERASE_ADDR4 ERASE_ADDR1 | |
332 | #define ERASE_ADDR5 ERASE_ADDR2 | |
333 | ||
334 | #define ERASE_DATA1 (0x00AA00AA & FLASH_DATA_MASK) | |
335 | #define ERASE_DATA2 (0x00550055 & FLASH_DATA_MASK) | |
336 | #define ERASE_DATA3 (0x00800080 & FLASH_DATA_MASK) | |
337 | #define ERASE_DATA4 ERASE_DATA1 | |
338 | #define ERASE_DATA5 ERASE_DATA2 | |
339 | ||
53677ef1 WD |
340 | #define ERASE_SECTOR_DATA (0x00300030 & FLASH_DATA_MASK) |
341 | #define ERASE_CHIP_DATA (0x00100010 & FLASH_DATA_MASK) | |
342 | #define ERASE_CONFIRM_DATA (0x00800080 & FLASH_DATA_MASK) | |
b4676a25 WD |
343 | |
344 | int flash_erase (flash_info_t *info, int s_first, int s_last) | |
345 | { | |
346 | FDT *addr = (FDT *)(info->start[0]); | |
347 | ||
348 | int prot, sect, l_sect, flag; | |
349 | ulong start, now, last; | |
350 | ||
351 | __asm__ __volatile__ ("sync"); | |
352 | addr[0] = 0xf0; | |
353 | udelay(1000); | |
354 | ||
355 | printf("\nflash_erase: first = %d @ 0x%08lx\n", s_first, info->start[s_first] ); | |
356 | printf(" last = %d @ 0x%08lx\n", s_last , info->start[s_last ] ); | |
357 | ||
358 | if ((s_first < 0) || (s_first > s_last)) { | |
359 | if (info->flash_id == FLASH_UNKNOWN) { | |
360 | printf ("- missing\n"); | |
361 | } else { | |
362 | printf ("- no sectors to erase\n"); | |
363 | } | |
364 | return 1; | |
365 | } | |
366 | ||
367 | if ((info->flash_id == FLASH_UNKNOWN) || (info->flash_id > FLASH_AMD_COMP)) { | |
368 | printf ("Can't erase unknown flash type %08lx - aborted\n", info->flash_id); | |
369 | return 1; | |
370 | } | |
371 | ||
372 | prot = 0; | |
373 | for (sect=s_first; sect<=s_last; ++sect) { | |
374 | if (info->protect[sect]) { | |
375 | prot++; | |
376 | } | |
377 | } | |
378 | ||
379 | if (prot) { | |
380 | printf ("- Warning: %d protected sectors will not be erased!\n", | |
381 | prot); | |
382 | } else { | |
383 | printf ("\n"); | |
384 | } | |
385 | ||
386 | l_sect = -1; | |
387 | ||
388 | /* Disable interrupts which might cause a timeout here */ | |
389 | flag = disable_interrupts(); | |
390 | ||
391 | addr[ERASE_ADDR1] = ERASE_DATA1; | |
392 | addr[ERASE_ADDR2] = ERASE_DATA2; | |
393 | addr[ERASE_ADDR3] = ERASE_DATA3; | |
394 | addr[ERASE_ADDR4] = ERASE_DATA4; | |
395 | addr[ERASE_ADDR5] = ERASE_DATA5; | |
396 | ||
397 | for (sect = s_first; sect <= s_last; sect++) { | |
398 | if (info->protect[sect] == 0) { | |
399 | addr = (FDT *)(info->start[sect]); | |
400 | addr[0] = ERASE_SECTOR_DATA; | |
401 | l_sect = sect; | |
402 | } | |
403 | } | |
404 | ||
405 | if (flag) | |
406 | enable_interrupts(); | |
407 | ||
408 | /* | |
409 | * We wait for the last triggered sector | |
410 | */ | |
411 | if (l_sect < 0) | |
412 | goto DONE; | |
413 | ||
414 | start = get_timer (0); | |
415 | last = start; | |
416 | addr = (FDT *)(info->start[l_sect]); | |
417 | ||
418 | while ((addr[0] & ERASE_CONFIRM_DATA) != ERASE_CONFIRM_DATA) { | |
419 | if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) { | |
420 | printf ("Timeout\n"); | |
421 | return 1; | |
422 | } | |
423 | /* show that we're waiting */ | |
424 | if ((now - last) > 1000) { /* every second */ | |
425 | putc ('.'); | |
426 | last = now; | |
427 | } | |
428 | } | |
429 | ||
430 | DONE: | |
431 | printf (" done\n"); | |
432 | return 0; | |
433 | } | |
434 | ||
435 | /*----------------------------------------------------------------------- | |
436 | * Copy memory to flash, returns: | |
437 | * 0 - OK | |
438 | * 1 - write timeout | |
439 | * 2 - Flash not erased | |
440 | */ | |
441 | ||
442 | int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
443 | { | |
444 | #define BUFF_INC 4 | |
445 | ulong cp, wp, data; | |
446 | int i, l, rc; | |
447 | ||
448 | mvdebug (("+write_buff %p ==> 0x%08lx, count = 0x%08lx\n", src, addr, cnt)); | |
449 | ||
450 | wp = (addr & ~3); /* get lower word aligned address */ | |
451 | /* | |
452 | * handle unaligned start bytes | |
453 | */ | |
454 | if ((l = addr - wp) != 0) { | |
455 | mvdebug ((" handle unaligned start bytes (cnt = 0x%08lx)\n", cnt)); | |
456 | data = 0; | |
457 | for (i=0, cp=wp; i<l; ++i, ++cp) { | |
458 | data = (data << 8) | (*(uchar *)cp); | |
459 | } | |
460 | for (; i<BUFF_INC && cnt>0; ++i) { | |
461 | data = (data << 8) | *src++; | |
462 | --cnt; | |
463 | ++cp; | |
464 | } | |
465 | for (; cnt==0 && i<BUFF_INC; ++i, ++cp) { | |
466 | data = (data << 8) | (*(uchar *)cp); | |
467 | } | |
468 | ||
469 | if ((rc = write_word(info, wp, data)) != 0) { | |
470 | return (rc); | |
471 | } | |
472 | wp += BUFF_INC; | |
473 | } | |
474 | ||
475 | /* | |
476 | * handle (half)word aligned part | |
477 | */ | |
478 | mvdebug ((" handle word aligned part (cnt = 0x%08lx)\n", cnt)); | |
479 | while (cnt >= BUFF_INC) { | |
480 | data = 0; | |
481 | for (i=0; i<BUFF_INC; ++i) { | |
482 | data = (data << 8) | *src++; | |
483 | } | |
484 | if ((rc = write_word(info, wp, data)) != 0) { | |
485 | return (rc); | |
486 | } | |
487 | wp += BUFF_INC; | |
488 | cnt -= BUFF_INC; | |
489 | } | |
490 | ||
491 | if (cnt == 0) { | |
492 | return (0); | |
493 | } | |
494 | ||
495 | /* | |
496 | * handle unaligned tail bytes | |
497 | */ | |
498 | mvdebug ((" handle unaligned tail bytes (cnt = 0x%08lx)\n", cnt)); | |
499 | data = 0; | |
500 | for (i=0, cp=wp; i<BUFF_INC && cnt>0; ++i, ++cp) { | |
501 | data = (data << 8) | *src++; | |
502 | --cnt; | |
503 | } | |
504 | for (; i<BUFF_INC; ++i, ++cp) { | |
505 | data = (data << 8) | (*(uchar *)cp); | |
506 | } | |
507 | ||
508 | return (write_word(info, wp, data)); | |
509 | } | |
510 | ||
511 | #if (FLASH_BUS_WIDTH >= 16) | |
512 | #define WRITE_ADDR1 0x0555 | |
513 | #define WRITE_ADDR2 0x02AA | |
514 | #else | |
515 | #define WRITE_ADDR1 0x0AAA | |
516 | #define WRITE_ADDR2 0x0555 | |
517 | #define WRITE_ADDR3 WRITE_ADDR1 | |
518 | #endif | |
519 | ||
520 | #define WRITE_DATA1 (0x00AA00AA & FLASH_DATA_MASK) | |
521 | #define WRITE_DATA2 (0x00550055 & FLASH_DATA_MASK) | |
522 | #define WRITE_DATA3 (0x00A000A0 & FLASH_DATA_MASK) | |
523 | ||
524 | #define WRITE_CONFIRM_DATA ERASE_CONFIRM_DATA | |
525 | ||
526 | /*----------------------------------------------------------------------- | |
527 | * Write a byte to Flash, returns: | |
528 | * 0 - OK | |
529 | * 1 - write timeout | |
530 | * 2 - Flash not erased | |
531 | */ | |
532 | static int write_char (flash_info_t *info, ulong dest, uchar data) | |
533 | { | |
534 | vu_char *addr = (vu_char *)(info->start[0]); | |
535 | ulong start; | |
536 | int flag; | |
537 | ||
538 | /* Check if Flash is (sufficiently) erased */ | |
539 | if ((*((vu_char *)dest) & data) != data) { | |
540 | printf(" *** ERROR: Flash not erased !\n"); | |
541 | return (2); | |
542 | } | |
543 | flag = disable_interrupts(); | |
544 | ||
545 | addr[WRITE_ADDR1] = WRITE_DATA1; | |
546 | addr[WRITE_ADDR2] = WRITE_DATA2; | |
547 | addr[WRITE_ADDR3] = WRITE_DATA3; | |
548 | *((vu_char *)dest) = data; | |
549 | ||
550 | if (flag) | |
551 | enable_interrupts(); | |
552 | ||
553 | /* data polling for D7 */ | |
554 | start = get_timer (0); | |
555 | addr = (vu_char *)dest; | |
556 | while (( (*addr) & WRITE_CONFIRM_DATA) != (data & WRITE_CONFIRM_DATA)) { | |
557 | if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { | |
558 | printf(" *** ERROR: Flash write timeout !"); | |
559 | return (1); | |
560 | } | |
561 | } | |
53677ef1 | 562 | mvdebug (("-write_byte\n")); |
b4676a25 WD |
563 | return (0); |
564 | } | |
565 | ||
566 | /*----------------------------------------------------------------------- | |
567 | * Write a word to Flash, returns: | |
568 | * 0 - OK | |
569 | * 1 - write timeout | |
570 | * 2 - Flash not erased | |
571 | */ | |
572 | static int write_word (flash_info_t *info, ulong dest, ulong data) | |
573 | { | |
574 | int i, | |
575 | result = 0; | |
576 | ||
577 | mvdebug (("+write_word : 0x%08lx @ 0x%08lx\n", data, dest)); | |
578 | for ( i=0; (i < 4) && (result == 0); i++, dest+=1 ) | |
579 | result = write_char (info, dest, (data >> (8*(3-i))) & 0xff ); | |
53677ef1 | 580 | mvdebug (("-write_word\n")); |
b4676a25 WD |
581 | return result; |
582 | } | |
583 | /*---------------------------------------------------------------- */ |