]>
Commit | Line | Data |
---|---|---|
3a473b2a WD |
1 | /* |
2 | * (C) Copyright 2001 | |
3 | * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc. | |
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 | /* | |
25 | * flash.c - flash support for the 512k, 8bit boot flash | |
53677ef1 | 26 | and the 8MB 32bit extra flash on the DB64360 |
3a473b2a WD |
27 | * most of this file was based on the existing U-Boot |
28 | * flash drivers. | |
29 | * | |
30 | * written or collected and sometimes rewritten by | |
31 | * Ingo Assmus <ingo.assmus@keymile.com> | |
32 | * | |
33 | */ | |
34 | ||
35 | #include <common.h> | |
36 | #include <mpc8xx.h> | |
37 | #include "../include/mv_gen_reg.h" | |
38 | #include "../include/memory.h" | |
39 | #include "intel_flash.h" | |
40 | ||
41 | #define FLASH_ROM 0xFFFD /* unknown flash type */ | |
42 | #define FLASH_RAM 0xFFFE /* unknown flash type */ | |
43 | #define FLASH_MAN_UNKNOWN 0xFFFF0000 | |
44 | ||
45 | /* #define DEBUG */ | |
46 | ||
47 | /* Intel flash commands */ | |
48 | int flash_erase_intel (flash_info_t * info, int s_first, int s_last); | |
49 | int write_word_intel (bank_addr_t addr, bank_word_t value); | |
50 | ||
6d0f6bcf | 51 | flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */ |
3a473b2a WD |
52 | |
53 | /*----------------------------------------------------------------------- | |
54 | * Functions | |
55 | */ | |
56 | static ulong flash_get_size (int portwidth, vu_long * addr, | |
57 | 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 | ||
64 | unsigned long flash_init (void) | |
65 | { | |
66 | unsigned int i; | |
67 | unsigned long size_b0 = 0, size_b1 = 0; | |
68 | unsigned long base, flash_size; | |
69 | ||
70 | /* Init: no FLASHes known */ | |
6d0f6bcf | 71 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) { |
3a473b2a WD |
72 | flash_info[i].flash_id = FLASH_UNKNOWN; |
73 | } | |
74 | ||
75 | /* the boot flash */ | |
6d0f6bcf | 76 | base = CONFIG_SYS_FLASH_BASE; |
3a473b2a | 77 | size_b0 = |
6d0f6bcf | 78 | flash_get_size (CONFIG_SYS_BOOT_FLASH_WIDTH, (vu_long *) base, |
3a473b2a WD |
79 | &flash_info[0]); |
80 | ||
81 | printf ("[%ldkB@%lx] ", size_b0 / 1024, base); | |
82 | ||
83 | if (flash_info[0].flash_id == FLASH_UNKNOWN) { | |
84 | printf ("## Unknown FLASH at %08lx: Size = 0x%08lx = %ld MB\n", base, size_b0, size_b0 << 20); | |
85 | } | |
86 | ||
6d0f6bcf | 87 | base = memoryGetDeviceBaseAddress (CONFIG_SYS_EXTRA_FLASH_DEVICE); |
3a473b2a | 88 | /* base = memoryGetDeviceBaseAddress(DEV_CS3_BASE_ADDR);*/ |
6d0f6bcf | 89 | for (i = 1; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { |
3a473b2a | 90 | unsigned long size = |
6d0f6bcf | 91 | flash_get_size (CONFIG_SYS_EXTRA_FLASH_WIDTH, |
3a473b2a WD |
92 | (vu_long *) base, &flash_info[i]); |
93 | ||
94 | printf ("[%ldMB@%lx] ", size >> 20, base); | |
95 | ||
96 | if (flash_info[i].flash_id == FLASH_UNKNOWN) { | |
97 | if (i == 1) { | |
98 | printf ("## Unknown FLASH at %08lx: Size = 0x%08lx = %ld MB\n", base, size_b1, size_b1 << 20); | |
99 | } | |
100 | break; | |
101 | } | |
102 | size_b1 += size; | |
103 | base += size; | |
104 | } | |
105 | ||
106 | flash_size = size_b0 + size_b1; | |
107 | return flash_size; | |
108 | } | |
109 | ||
110 | /*----------------------------------------------------------------------- | |
111 | */ | |
112 | static void flash_get_offsets (ulong base, flash_info_t * info) | |
113 | { | |
114 | int i; | |
115 | int sector_size; | |
116 | ||
117 | if (!info->sector_count) | |
118 | return; | |
119 | ||
120 | /* set up sector start address table */ | |
121 | switch (info->flash_id & FLASH_TYPEMASK) { | |
122 | case FLASH_AM040: | |
123 | case FLASH_28F128J3A: | |
124 | case FLASH_28F640J3A: | |
125 | case FLASH_RAM: | |
126 | /* this chip has uniformly spaced sectors */ | |
127 | sector_size = info->size / info->sector_count; | |
128 | for (i = 0; i < info->sector_count; i++) | |
129 | info->start[i] = base + (i * sector_size); | |
130 | break; | |
131 | default: | |
132 | if (info->flash_id & FLASH_BTYPE) { | |
133 | /* set sector offsets for bottom boot block type */ | |
134 | info->start[0] = base + 0x00000000; | |
135 | info->start[1] = base + 0x00008000; | |
136 | info->start[2] = base + 0x0000C000; | |
137 | info->start[3] = base + 0x00010000; | |
138 | for (i = 4; i < info->sector_count; i++) { | |
139 | info->start[i] = | |
140 | base + (i * 0x00020000) - 0x00060000; | |
141 | } | |
142 | } else { | |
143 | /* set sector offsets for top boot block type */ | |
144 | i = info->sector_count - 1; | |
145 | info->start[i--] = base + info->size - 0x00008000; | |
146 | info->start[i--] = base + info->size - 0x0000C000; | |
147 | info->start[i--] = base + info->size - 0x00010000; | |
148 | for (; i >= 0; i--) { | |
149 | info->start[i] = base + i * 0x00020000; | |
150 | } | |
151 | } | |
152 | } | |
153 | } | |
154 | ||
155 | /*----------------------------------------------------------------------- | |
156 | */ | |
157 | void flash_print_info (flash_info_t * info) | |
158 | { | |
159 | int i; | |
160 | ||
161 | if (info->flash_id == FLASH_UNKNOWN) { | |
162 | printf ("missing or unknown FLASH type\n"); | |
163 | return; | |
164 | } | |
165 | ||
166 | switch (info->flash_id & FLASH_VENDMASK) { | |
167 | case FLASH_MAN_STM: | |
168 | printf ("STM "); | |
169 | break; | |
170 | case FLASH_MAN_AMD: | |
171 | printf ("AMD "); | |
172 | break; | |
173 | case FLASH_MAN_FUJ: | |
174 | printf ("FUJITSU "); | |
175 | break; | |
176 | case FLASH_MAN_INTEL: | |
177 | printf ("INTEL "); | |
178 | break; | |
179 | default: | |
180 | printf ("Unknown Vendor "); | |
181 | break; | |
182 | } | |
183 | ||
184 | switch (info->flash_id & FLASH_TYPEMASK) { | |
185 | case FLASH_AM040: | |
186 | printf ("AM29LV040B (4 Mbit, bottom boot sect)\n"); | |
187 | break; | |
188 | case FLASH_AM400B: | |
189 | printf ("AM29LV400B (4 Mbit, bottom boot sect)\n"); | |
190 | break; | |
191 | case FLASH_AM400T: | |
192 | printf ("AM29LV400T (4 Mbit, top boot sector)\n"); | |
193 | break; | |
194 | case FLASH_AM800B: | |
195 | printf ("AM29LV800B (8 Mbit, bottom boot sect)\n"); | |
196 | break; | |
197 | case FLASH_AM800T: | |
198 | printf ("AM29LV800T (8 Mbit, top boot sector)\n"); | |
199 | break; | |
200 | case FLASH_AM160B: | |
201 | printf ("AM29LV160B (16 Mbit, bottom boot sect)\n"); | |
202 | break; | |
203 | case FLASH_AM160T: | |
204 | printf ("AM29LV160T (16 Mbit, top boot sector)\n"); | |
205 | break; | |
206 | case FLASH_AM320B: | |
207 | printf ("AM29LV320B (32 Mbit, bottom boot sect)\n"); | |
208 | break; | |
209 | case FLASH_AM320T: | |
210 | printf ("AM29LV320T (32 Mbit, top boot sector)\n"); | |
211 | break; | |
212 | case FLASH_28F640J3A: | |
213 | printf ("28F640J3A (64 Mbit)\n"); | |
214 | break; | |
215 | case FLASH_28F128J3A: | |
216 | printf ("28F128J3A (128 Mbit)\n"); | |
217 | break; | |
218 | case FLASH_ROM: | |
219 | printf ("ROM\n"); | |
220 | break; | |
221 | case FLASH_RAM: | |
222 | printf ("RAM\n"); | |
223 | break; | |
224 | default: | |
225 | printf ("Unknown Chip Type\n"); | |
226 | break; | |
227 | } | |
228 | ||
229 | if ((info->size >> 20) > 0) { | |
230 | printf (" Size: %ld MB in %d Sectors\n", | |
231 | info->size >> 20, info->sector_count); | |
232 | } else { | |
233 | printf (" Size: %ld kB in %d Sectors\n", | |
234 | info->size >> 10, info->sector_count); | |
235 | } | |
236 | ||
237 | printf (" Sector Start Addresses:"); | |
238 | for (i = 0; i < info->sector_count; ++i) { | |
239 | if ((i % 5) == 0) | |
240 | printf ("\n "); | |
241 | printf (" %08lX%s", | |
242 | info->start[i], info->protect[i] ? " (RO)" : " "); | |
243 | } | |
244 | printf ("\n"); | |
245 | return; | |
246 | } | |
247 | ||
248 | /*----------------------------------------------------------------------- | |
249 | */ | |
250 | ||
251 | ||
252 | /*----------------------------------------------------------------------- | |
253 | */ | |
254 | ||
255 | /* | |
256 | * The following code cannot be run from FLASH! | |
257 | */ | |
258 | ||
259 | static inline void flash_cmd (int width, volatile unsigned char *addr, | |
260 | int offset, unsigned char cmd) | |
261 | { | |
262 | /* supports 1x8, 1x16, and 2x16 */ | |
263 | /* 2x8 and 4x8 are not supported */ | |
264 | if (width == 4) { | |
265 | /* assuming chips are in 16 bit mode */ | |
266 | /* 2x16 */ | |
267 | unsigned long cmd32 = (cmd << 16) | cmd; | |
268 | ||
269 | *(volatile unsigned long *) (addr + offset * 2) = cmd32; | |
270 | } else { | |
271 | /* 1x16 or 1x8 */ | |
272 | *(volatile unsigned char *) (addr + offset) = cmd; | |
273 | } | |
274 | } | |
275 | ||
276 | static ulong | |
277 | flash_get_size (int portwidth, vu_long * addr, flash_info_t * info) | |
278 | { | |
279 | short i; | |
280 | volatile unsigned char *caddr = (unsigned char *) addr; | |
281 | volatile unsigned short *saddr = (unsigned short *) addr; | |
282 | volatile unsigned long *laddr = (unsigned long *) addr; | |
283 | char old[2], save; | |
284 | ulong id = 0, manu = 0, base = (ulong) addr; | |
285 | ||
286 | #ifdef DEBUG | |
287 | printf ("%s: enter\n", __FUNCTION__); | |
288 | #endif | |
289 | info->portwidth = portwidth; | |
290 | ||
291 | save = *caddr; | |
292 | ||
293 | flash_cmd (portwidth, caddr, 0, 0xf0); | |
294 | flash_cmd (portwidth, caddr, 0, 0xf0); | |
295 | ||
296 | udelay (10); | |
297 | ||
298 | old[0] = caddr[0]; | |
299 | old[1] = caddr[1]; | |
300 | ||
301 | ||
302 | if (old[0] != 0xf0) { | |
303 | flash_cmd (portwidth, caddr, 0, 0xf0); | |
304 | flash_cmd (portwidth, caddr, 0, 0xf0); | |
305 | ||
306 | udelay (10); | |
307 | ||
308 | if (*caddr == 0xf0) { | |
309 | /* this area is ROM */ | |
310 | *caddr = save; | |
311 | info->flash_id = FLASH_ROM + FLASH_MAN_UNKNOWN; | |
312 | info->sector_count = 8; | |
313 | info->size = 0x80000; | |
314 | flash_get_offsets (base, info); | |
315 | return info->size; | |
316 | } | |
317 | } else { | |
318 | *caddr = 0; | |
319 | ||
320 | udelay (10); | |
321 | ||
322 | if (*caddr == 0) { | |
323 | /* this area is RAM */ | |
324 | *caddr = save; | |
325 | info->flash_id = FLASH_RAM + FLASH_MAN_UNKNOWN; | |
326 | info->sector_count = 8; | |
327 | info->size = 0x80000; | |
328 | flash_get_offsets (base, info); | |
329 | return info->size; | |
330 | } | |
331 | flash_cmd (portwidth, caddr, 0, 0xf0); | |
332 | ||
333 | udelay (10); | |
334 | } | |
335 | ||
336 | /* Write auto select command: read Manufacturer ID */ | |
337 | flash_cmd (portwidth, caddr, 0x555, 0xAA); | |
338 | flash_cmd (portwidth, caddr, 0x2AA, 0x55); | |
339 | flash_cmd (portwidth, caddr, 0x555, 0x90); | |
340 | ||
341 | udelay (10); | |
342 | ||
343 | if ((caddr[0] == old[0]) && (caddr[1] == old[1])) { | |
344 | ||
345 | /* this area is ROM */ | |
346 | info->flash_id = FLASH_ROM + FLASH_MAN_UNKNOWN; | |
347 | info->sector_count = 8; | |
348 | info->size = 0x80000; | |
349 | flash_get_offsets (base, info); | |
350 | return info->size; | |
351 | #ifdef DEBUG | |
352 | } else { | |
353 | printf ("%px%d: %02x:%02x -> %02x:%02x\n", | |
354 | caddr, portwidth, old[0], old[1], caddr[0], caddr[1]); | |
355 | #endif | |
356 | } | |
357 | ||
358 | switch (portwidth) { | |
359 | case 1: | |
360 | manu = caddr[0]; | |
361 | manu |= manu << 16; | |
362 | id = caddr[1]; | |
363 | break; | |
364 | case 2: | |
365 | manu = saddr[0]; | |
366 | manu |= manu << 16; | |
367 | id = saddr[1]; | |
368 | id |= id << 16; | |
369 | break; | |
370 | case 4: | |
371 | manu = laddr[0]; | |
372 | id = laddr[1]; | |
373 | break; | |
374 | } | |
375 | ||
376 | #ifdef DEBUG | |
377 | flash_cmd (portwidth, caddr, 0, 0xf0); | |
378 | ||
379 | printf ("\n%08lx:%08lx:%08lx\n", base, manu, id); | |
380 | printf ("%08lx %08lx %08lx %08lx\n", | |
381 | laddr[0], laddr[1], laddr[2], laddr[3]); | |
382 | #endif | |
383 | ||
384 | switch (manu) { | |
385 | case STM_MANUFACT: | |
386 | info->flash_id = FLASH_MAN_STM; | |
387 | break; | |
388 | case AMD_MANUFACT: | |
389 | info->flash_id = FLASH_MAN_AMD; | |
390 | break; | |
391 | case FUJ_MANUFACT: | |
392 | info->flash_id = FLASH_MAN_FUJ; | |
393 | break; | |
394 | case INTEL_MANUFACT: | |
395 | info->flash_id = FLASH_MAN_INTEL; | |
396 | break; | |
397 | default: | |
398 | flash_cmd (portwidth, caddr, 0, 0xf0); | |
399 | ||
400 | printf ("Unknown Mfr [%08lx]:%08lx\n", manu, id); | |
401 | info->flash_id = FLASH_UNKNOWN; | |
402 | info->sector_count = 0; | |
403 | info->size = 0; | |
404 | return (0); /* no or unknown flash */ | |
405 | } | |
406 | ||
407 | switch (id) { | |
408 | case AMD_ID_LV400T: | |
409 | info->flash_id += FLASH_AM400T; | |
410 | info->sector_count = 11; | |
411 | info->size = 0x00100000; | |
412 | info->chipwidth = 1; | |
413 | break; /* => 1 MB */ | |
414 | ||
415 | case AMD_ID_LV400B: | |
416 | info->flash_id += FLASH_AM400B; | |
417 | info->sector_count = 11; | |
418 | info->size = 0x00100000; | |
419 | info->chipwidth = 1; | |
420 | break; /* => 1 MB */ | |
421 | ||
422 | case AMD_ID_LV800T: | |
423 | info->flash_id += FLASH_AM800T; | |
424 | info->sector_count = 19; | |
425 | info->size = 0x00200000; | |
426 | info->chipwidth = 1; | |
427 | break; /* => 2 MB */ | |
428 | ||
429 | case AMD_ID_LV800B: | |
430 | info->flash_id += FLASH_AM800B; | |
431 | info->sector_count = 19; | |
432 | info->size = 0x00200000; | |
433 | info->chipwidth = 1; | |
434 | break; /* => 2 MB */ | |
435 | ||
436 | case AMD_ID_LV160T: | |
437 | info->flash_id += FLASH_AM160T; | |
438 | info->sector_count = 35; | |
439 | info->size = 0x00400000; | |
440 | info->chipwidth = 1; | |
441 | break; /* => 4 MB */ | |
442 | ||
443 | case AMD_ID_LV160B: | |
444 | info->flash_id += FLASH_AM160B; | |
445 | info->sector_count = 35; | |
446 | info->size = 0x00400000; | |
447 | info->chipwidth = 1; | |
448 | break; /* => 4 MB */ | |
449 | #if 0 /* enable when device IDs are available */ | |
450 | case AMD_ID_LV320T: | |
451 | info->flash_id += FLASH_AM320T; | |
452 | info->sector_count = 67; | |
453 | info->size = 0x00800000; | |
454 | break; /* => 8 MB */ | |
455 | ||
456 | case AMD_ID_LV320B: | |
457 | info->flash_id += FLASH_AM320B; | |
458 | info->sector_count = 67; | |
459 | info->size = 0x00800000; | |
460 | break; /* => 8 MB */ | |
461 | #endif | |
462 | case AMD_ID_LV040B: | |
463 | info->flash_id += FLASH_AM040; | |
464 | info->sector_count = 8; | |
465 | info->size = 0x80000; | |
466 | info->chipwidth = 1; | |
467 | break; /* => 512 kB */ | |
468 | ||
469 | case INTEL_ID_28F640J3A: | |
470 | info->flash_id += FLASH_28F640J3A; | |
471 | info->sector_count = 64; | |
472 | info->size = 128 * 1024 * 64; /* 128kbytes x 64 blocks */ | |
473 | info->chipwidth = 2; | |
474 | if (portwidth == 4) | |
475 | info->size *= 2; /* 2x16 */ | |
476 | break; | |
477 | ||
478 | case INTEL_ID_28F128J3A: | |
479 | info->flash_id += FLASH_28F128J3A; | |
480 | info->sector_count = 128; | |
481 | info->size = 128 * 1024 * 128; /* 128kbytes x 128 blocks */ | |
482 | info->chipwidth = 2; | |
483 | if (portwidth == 4) | |
484 | info->size *= 2; /* 2x16 */ | |
485 | break; | |
486 | ||
487 | default: | |
488 | flash_cmd (portwidth, caddr, 0, 0xf0); | |
489 | ||
490 | printf ("Unknown id %lx:[%lx]\n", manu, id); | |
491 | info->flash_id = FLASH_UNKNOWN; | |
492 | info->chipwidth = 1; | |
493 | return (0); /* => no or unknown flash */ | |
494 | ||
495 | } | |
496 | ||
497 | flash_get_offsets (base, info); | |
498 | ||
499 | ||
500 | /* check for protected sectors */ | |
501 | for (i = 0; i < info->sector_count; i++) { | |
502 | /* read sector protection at sector address, (A7 .. A0)=0x02 */ | |
503 | /* D0 = 1 if protected */ | |
504 | caddr = (volatile unsigned char *) (info->start[i]); | |
505 | saddr = (volatile unsigned short *) (info->start[i]); | |
506 | laddr = (volatile unsigned long *) (info->start[i]); | |
507 | if (portwidth == 1) | |
508 | info->protect[i] = caddr[2] & 1; | |
509 | else if (portwidth == 2) | |
510 | info->protect[i] = saddr[2] & 1; | |
511 | else | |
512 | info->protect[i] = laddr[2] & 1; | |
513 | } | |
514 | ||
515 | /* | |
516 | * Prevent writes to uninitialized FLASH. | |
517 | */ | |
518 | if (info->flash_id != FLASH_UNKNOWN) { | |
519 | caddr = (volatile unsigned char *) info->start[0]; | |
520 | ||
521 | flash_cmd (portwidth, caddr, 0, 0xF0); /* reset bank */ | |
522 | } | |
523 | ||
524 | return (info->size); | |
525 | } | |
526 | ||
527 | int flash_erase (flash_info_t * info, int s_first, int s_last) | |
528 | { | |
77ddac94 | 529 | volatile unsigned char *addr = (uchar *) (info->start[0]); |
3a473b2a WD |
530 | int flag, prot, sect, l_sect; |
531 | ulong start, now, last; | |
532 | ||
533 | /* modified to support 2x16 Intel flash */ | |
534 | /* Note that the code will not exit on a flash erasure error or timeout */ | |
535 | /* but will print and error message and continue processing sectors */ | |
536 | /* until they are all erased. */ | |
537 | /* 10-16-2002 P. Marchese */ | |
538 | ulong mask; | |
539 | int timeout; | |
540 | ||
541 | if (info->portwidth == 4) | |
542 | /* { | |
543 | printf ("- Warning: erasing of 32Bit (2*16Bit i.e. 2*28F640J3A) not supported yet !!!! \n"); | |
544 | return 1; | |
545 | }*/ | |
546 | { | |
547 | /* make sure it's Intel flash */ | |
548 | if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) { | |
549 | /* yup! it's an Intel flash */ | |
550 | /* is it 16-bits wide? */ | |
551 | if (info->chipwidth == 2) { | |
552 | /* yup! it's 16-bits wide */ | |
553 | /* are there any sectors to process? */ | |
554 | if ((s_first < 0) || (s_first > s_last)) { | |
555 | printf ("Error: There are no sectors to erase\n"); | |
556 | printf ("Either sector %d is less than zero\n", s_first); | |
557 | printf ("or sector %d is greater than sector %d\n", s_first, s_last); | |
558 | return 1; | |
559 | } | |
560 | /* check for protected sectors */ | |
561 | prot = 0; | |
562 | for (sect = s_first; sect <= s_last; ++sect) | |
563 | if (info->protect[sect]) | |
564 | prot++; | |
565 | /* if variable "prot" is nonzero, there are protected sectors */ | |
566 | if (prot) | |
567 | printf ("- Warning: %d protected sectors will not be erased!\n", prot); | |
568 | /* reset the flash */ | |
569 | flash_cmd (info->portwidth, addr, 0, | |
570 | CHIP_CMD_RST); | |
571 | /* Disable interrupts which might cause a timeout here */ | |
572 | flag = disable_interrupts (); | |
573 | /* Clear the status register */ | |
574 | flash_cmd (info->portwidth, addr, 0, | |
575 | CHIP_CMD_CLR_STAT); | |
576 | flash_cmd (info->portwidth, addr, 0, | |
577 | CHIP_CMD_RST); | |
578 | /* Start erase on unprotected sectors */ | |
579 | for (sect = s_first; sect <= s_last; sect++) { | |
580 | /* is the sector unprotected? */ | |
581 | if (info->protect[sect] == 0) { /* not protected */ | |
582 | /* issue the single block erase command, 0x20 */ | |
583 | flash_cmd (info->portwidth, | |
584 | (volatile unsigned | |
585 | char *) info-> | |
586 | start[sect], 0, | |
587 | CHIP_CMD_ERASE1); | |
588 | /* issue the erase confirm command, 0xD0 */ | |
589 | flash_cmd (info->portwidth, | |
590 | (volatile unsigned | |
591 | char *) info-> | |
592 | start[sect], 0, | |
593 | CHIP_CMD_ERASE2); | |
594 | l_sect = sect; | |
595 | /* re-enable interrupts if necessary */ | |
596 | if (flag) | |
597 | enable_interrupts (); | |
598 | /* poll for erasure completion */ | |
599 | /* put flash into read status mode by writing 0x70 to it */ | |
600 | flash_cmd (info->portwidth, | |
601 | addr, 0, | |
602 | CHIP_CMD_RD_STAT); | |
603 | /* setup the status register mask */ | |
604 | mask = CHIP_STAT_RDY | | |
605 | (CHIP_STAT_RDY << 16); | |
606 | /* init. the timeout counter */ | |
607 | start = get_timer (0); | |
608 | /* keep looping while the flash is not ready */ | |
609 | /* exit the loop by timing out or the flash */ | |
610 | /* becomes ready again */ | |
611 | timeout = 0; | |
612 | while ((* | |
613 | (volatile unsigned | |
614 | long *) info-> | |
615 | start[sect] & mask) != | |
616 | mask) { | |
617 | /* has the timeout limit been reached? */ | |
618 | if (get_timer (start) | |
619 | > | |
6d0f6bcf | 620 | CONFIG_SYS_FLASH_ERASE_TOUT) |
3a473b2a WD |
621 | { |
622 | /* timeout limit reached */ | |
623 | printf ("Time out limit reached erasing sector at address %08lx\n", info->start[sect]); | |
624 | printf ("Continuing with next sector\n"); | |
625 | timeout = 1; | |
626 | goto timed_out_error; | |
627 | } | |
628 | /* put flash into read status mode by writing 0x70 to it */ | |
629 | flash_cmd (info-> | |
630 | portwidth, | |
631 | addr, 0, | |
632 | CHIP_CMD_RD_STAT); | |
633 | } | |
634 | /* did we timeout? */ | |
635 | timed_out_error:if (timeout == 0) | |
636 | { | |
637 | /* didn't timeout, so check the status register */ | |
638 | /* create the status mask to check for errors */ | |
639 | mask = CHIP_STAT_ECLBS; | |
640 | mask = mask | (mask << | |
641 | 16); | |
642 | /* put flash into read status mode by writing 0x70 to it */ | |
643 | flash_cmd (info-> | |
644 | portwidth, | |
645 | addr, 0, | |
646 | CHIP_CMD_RD_STAT); | |
647 | /* are there any errors? */ | |
648 | if ((* | |
649 | (volatile | |
650 | unsigned long *) | |
651 | info-> | |
652 | start[sect] & | |
653 | mask) != 0) { | |
654 | /* We got an erasure error */ | |
655 | printf ("Flash erasure error at address 0x%08lx\n", info->start[sect]); | |
656 | printf ("Continuing with next sector\n"); | |
657 | /* reset the flash */ | |
658 | flash_cmd | |
659 | (info-> | |
660 | portwidth, | |
661 | addr, | |
662 | 0, | |
663 | CHIP_CMD_RST); | |
664 | } | |
665 | } | |
666 | /* erasure completed without errors */ | |
667 | /* reset the flash */ | |
668 | flash_cmd (info->portwidth, | |
669 | addr, 0, | |
670 | CHIP_CMD_RST); | |
671 | } /* end if not protected */ | |
672 | } /* end for loop */ | |
673 | printf ("Flash erasure done\n"); | |
674 | return 0; | |
675 | } else { | |
676 | /* The Intel flash is not 16-bit wide */ | |
677 | /* print and error message and return */ | |
678 | /* NOTE: you can add routines here to handle other size flash */ | |
679 | printf ("Error: Intel flash device is only %d-bits wide\n", info->chipwidth * 8); | |
680 | printf ("The erasure code only handles Intel 16-bit wide flash memory\n"); | |
681 | return 1; | |
682 | } | |
683 | } else { | |
684 | /* Not Intel flash so return an error as a write timeout */ | |
685 | /* NOTE: if it's another type flash, stick its routine here */ | |
686 | printf ("Error: The flash device is not Intel type\n"); | |
687 | printf ("The erasure code only supports Intel flash in a 32-bit port width\n"); | |
688 | return 1; | |
689 | } | |
690 | } | |
691 | ||
692 | /* end 32-bit wide flash code */ | |
693 | if ((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) | |
694 | return 1; /* Rom can not be erased */ | |
695 | if ((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) { /* RAM just copy 0s to RAM */ | |
696 | for (sect = s_first; sect <= s_last; sect++) { | |
697 | int sector_size = info->size / info->sector_count; | |
698 | ||
77ddac94 | 699 | addr = (uchar *) (info->start[sect]); |
3a473b2a WD |
700 | memset ((void *) addr, 0, sector_size); |
701 | } | |
702 | return 0; | |
703 | } | |
704 | ||
705 | if ((s_first < 0) || (s_first > s_last)) { | |
706 | if (info->flash_id == FLASH_UNKNOWN) { | |
707 | printf ("- missing\n"); | |
708 | } else { | |
709 | printf ("- no sectors to erase\n"); | |
710 | } | |
711 | return 1; | |
712 | } | |
713 | ||
714 | if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) { /* Intel works spezial */ | |
715 | return flash_erase_intel (info, | |
716 | (unsigned short) s_first, | |
717 | (unsigned short) s_last); | |
718 | } | |
719 | #if 0 | |
720 | if ((info->flash_id == FLASH_UNKNOWN) || /* Flash is unknown to PPCBoot */ | |
721 | (info->flash_id > FLASH_AMD_COMP)) { | |
722 | printf ("Can't erase unknown flash type %08lx - aborted\n", | |
723 | info->flash_id); | |
724 | return 1; | |
725 | } | |
726 | #endif | |
727 | ||
728 | prot = 0; | |
729 | for (sect = s_first; sect <= s_last; ++sect) { | |
730 | if (info->protect[sect]) { | |
731 | prot++; | |
732 | } | |
733 | } | |
734 | ||
735 | if (prot) { | |
736 | printf ("- Warning: %d protected sectors will not be erased!\n", prot); | |
737 | } else { | |
738 | printf ("\n"); | |
739 | } | |
740 | ||
741 | l_sect = -1; | |
742 | ||
743 | /* Disable interrupts which might cause a timeout here */ | |
744 | flag = disable_interrupts (); | |
745 | ||
746 | flash_cmd (info->portwidth, addr, 0x555, 0xAA); /* start erase routine */ | |
747 | flash_cmd (info->portwidth, addr, 0x2AA, 0x55); | |
748 | flash_cmd (info->portwidth, addr, 0x555, 0x80); | |
749 | flash_cmd (info->portwidth, addr, 0x555, 0xAA); | |
750 | flash_cmd (info->portwidth, addr, 0x2AA, 0x55); | |
751 | ||
752 | /* Start erase on unprotected sectors */ | |
753 | for (sect = s_first; sect <= s_last; sect++) { | |
754 | if (info->protect[sect] == 0) { /* not protected */ | |
77ddac94 | 755 | addr = (uchar *) (info->start[sect]); |
3a473b2a WD |
756 | flash_cmd (info->portwidth, addr, 0, 0x30); |
757 | l_sect = sect; | |
758 | } | |
759 | } | |
760 | ||
761 | /* re-enable interrupts if necessary */ | |
762 | if (flag) | |
763 | enable_interrupts (); | |
764 | ||
765 | /* wait at least 80us - let's wait 1 ms */ | |
766 | udelay (1000); | |
767 | ||
768 | /* | |
769 | * We wait for the last triggered sector | |
770 | */ | |
771 | if (l_sect < 0) | |
772 | goto DONE; | |
773 | ||
774 | start = get_timer (0); | |
775 | last = start; | |
776 | addr = (volatile unsigned char *) (info->start[l_sect]); | |
777 | /* broken for 2x16: TODO */ | |
778 | while ((addr[0] & 0x80) != 0x80) { | |
6d0f6bcf | 779 | if ((now = get_timer (start)) > CONFIG_SYS_FLASH_ERASE_TOUT) { |
3a473b2a WD |
780 | printf ("Timeout\n"); |
781 | return 1; | |
782 | } | |
783 | /* show that we're waiting */ | |
784 | if ((now - last) > 1000) { /* every second */ | |
785 | putc ('.'); | |
786 | last = now; | |
787 | } | |
788 | } | |
789 | ||
790 | DONE: | |
791 | /* reset to read mode */ | |
792 | addr = (volatile unsigned char *) info->start[0]; | |
793 | flash_cmd (info->portwidth, addr, 0, 0xf0); | |
794 | flash_cmd (info->portwidth, addr, 0, 0xf0); | |
795 | ||
796 | printf (" done\n"); | |
797 | return 0; | |
798 | } | |
799 | ||
800 | /*----------------------------------------------------------------------- | |
801 | * Copy memory to flash, returns: | |
802 | * 0 - OK | |
803 | * 1 - write timeout | |
804 | * 2 - Flash not erased | |
805 | */ | |
806 | ||
807 | /* broken for 2x16: TODO */ | |
808 | int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) | |
809 | { | |
810 | ulong cp, wp, data; | |
811 | int i, l, rc; | |
812 | ||
813 | /* Commented out since the below code should work for 32-bit(2x 16 flash) */ | |
814 | /* 10-16-2002 P. Marchese */ | |
815 | /* if(info->portwidth==4) return 1; */ | |
816 | /* if(info->portwidth==4) { | |
817 | printf ("- Warning: writting of 32Bit (2*16Bit i.e. 2*28F640J3A) not supported yet !!!! \n"); | |
818 | return 1; | |
819 | }*/ | |
820 | ||
821 | if ((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) | |
822 | return 0; | |
823 | if ((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) { | |
824 | memcpy ((void *) addr, src, cnt); | |
825 | return 0; | |
826 | } | |
827 | ||
828 | wp = (addr & ~3); /* get lower word aligned address */ | |
829 | ||
830 | /* | |
831 | * handle unaligned start bytes | |
832 | */ | |
833 | if ((l = addr - wp) != 0) { | |
834 | data = 0; | |
835 | for (i = 0, cp = wp; i < l; ++i, ++cp) { | |
836 | data = (data << 8) | (*(uchar *) cp); | |
837 | } | |
838 | for (; i < 4 && cnt > 0; ++i) { | |
839 | data = (data << 8) | *src++; | |
840 | --cnt; | |
841 | ++cp; | |
842 | } | |
843 | for (; cnt == 0 && i < 4; ++i, ++cp) { | |
844 | data = (data << 8) | (*(uchar *) cp); | |
845 | } | |
846 | ||
847 | if ((rc = write_word (info, wp, data)) != 0) { | |
848 | return (rc); | |
849 | } | |
850 | wp += 4; | |
851 | } | |
852 | ||
853 | /* | |
854 | * handle word aligned part | |
855 | */ | |
856 | while (cnt >= 4) { | |
857 | data = 0; | |
858 | for (i = 0; i < 4; ++i) { | |
859 | data = (data << 8) | *src++; | |
860 | } | |
861 | if ((rc = write_word (info, wp, data)) != 0) { | |
862 | return (rc); | |
863 | } | |
864 | wp += 4; | |
865 | cnt -= 4; | |
866 | } | |
867 | ||
868 | if (cnt == 0) { | |
869 | return (0); | |
870 | } | |
871 | ||
872 | /* | |
873 | * handle unaligned tail bytes | |
874 | */ | |
875 | data = 0; | |
876 | for (i = 0, cp = wp; i < 4 && cnt > 0; ++i, ++cp) { | |
877 | data = (data << 8) | *src++; | |
878 | --cnt; | |
879 | } | |
880 | for (; i < 4; ++i, ++cp) { | |
881 | data = (data << 8) | (*(uchar *) cp); | |
882 | } | |
883 | ||
884 | return (write_word (info, wp, data)); | |
885 | } | |
886 | ||
887 | /*----------------------------------------------------------------------- | |
888 | * Write a word to Flash, returns: | |
889 | * 0 - OK | |
890 | * 1 - write timeout | |
891 | * 2 - Flash not erased | |
892 | */ | |
893 | /* broken for 2x16: TODO */ | |
894 | static int write_word (flash_info_t * info, ulong dest, ulong data) | |
895 | { | |
77ddac94 | 896 | volatile unsigned char *addr = (uchar *) (info->start[0]); |
3a473b2a WD |
897 | ulong start; |
898 | int flag, i; | |
899 | ulong mask; | |
900 | ||
901 | /* modified so that it handles 32-bit(2x16 Intel flash programming */ | |
902 | /* 10-16-2002 P. Marchese */ | |
903 | ||
904 | if (info->portwidth == 4) | |
905 | /* { | |
906 | printf ("- Warning: writting of 32Bit (2*16Bit i.e. 2*28F640J3A) not supported yet !!!! \n"); | |
907 | return 1; | |
908 | }*/ | |
909 | { | |
910 | /* make sure it's Intel flash */ | |
911 | if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) { | |
912 | /* yup! it's an Intel flash */ | |
913 | /* is it 16-bits wide? */ | |
914 | if (info->chipwidth == 2) { | |
915 | /* yup! it's 16-bits wide */ | |
916 | /* so we know how to program it */ | |
917 | /* reset the flash */ | |
918 | flash_cmd (info->portwidth, addr, 0, | |
919 | CHIP_CMD_RST); | |
920 | /* Disable interrupts which might cause a timeout here */ | |
921 | flag = disable_interrupts (); | |
922 | /* Clear the status register */ | |
923 | flash_cmd (info->portwidth, addr, 0, | |
924 | CHIP_CMD_CLR_STAT); | |
925 | flash_cmd (info->portwidth, addr, 0, | |
926 | CHIP_CMD_RST); | |
927 | /* 1st cycle of word/byte program */ | |
928 | /* write 0x40 to the location to program */ | |
77ddac94 | 929 | flash_cmd (info->portwidth, (uchar *) dest, 0, |
3a473b2a WD |
930 | CHIP_CMD_PROG); |
931 | /* 2nd cycle of word/byte program */ | |
932 | /* write the data to the destination address */ | |
933 | *(ulong *) dest = data; | |
934 | /* re-enable interrupts if necessary */ | |
935 | if (flag) | |
936 | enable_interrupts (); | |
937 | /* setup the status register mask */ | |
938 | mask = CHIP_STAT_RDY | (CHIP_STAT_RDY << 16); | |
939 | /* put flash into read status mode by writing 0x70 to it */ | |
940 | flash_cmd (info->portwidth, addr, 0, | |
941 | CHIP_CMD_RD_STAT); | |
942 | /* init. the timeout counter */ | |
943 | start = get_timer (0); | |
944 | /* keep looping while the flash is not ready */ | |
945 | /* exit the loop by timing out or the flash */ | |
946 | /* becomes ready again */ | |
947 | /* 11-13-2002 Paul Marchese */ | |
948 | /* modified while loop conditional statement */ | |
949 | /* because we were always timing out. */ | |
950 | /* there is a type mismatch, "addr[0]" */ | |
951 | /* returns a byte but "mask" is a 32-bit value */ | |
952 | while ((*(volatile unsigned long *) info-> | |
953 | start[0] & mask) != mask) | |
954 | /* original code */ | |
955 | /* while (addr[0] & mask) != mask) */ | |
956 | { | |
957 | /* has the timeout limit been reached? */ | |
958 | if (get_timer (start) > | |
6d0f6bcf | 959 | CONFIG_SYS_FLASH_WRITE_TOUT) { |
3a473b2a WD |
960 | /* timeout limit reached */ |
961 | printf ("Time out limit reached programming address %08lx with data %08lx\n", dest, data); | |
962 | /* reset the flash */ | |
963 | flash_cmd (info->portwidth, | |
964 | addr, 0, | |
965 | CHIP_CMD_RST); | |
966 | return (1); | |
967 | } | |
968 | /* put flash into read status mode by writing 0x70 to it */ | |
969 | flash_cmd (info->portwidth, addr, 0, | |
970 | CHIP_CMD_RD_STAT); | |
971 | } | |
972 | /* flash is ready, so check the status */ | |
973 | /* create the status mask to check for errors */ | |
974 | mask = CHIP_STAT_DPS | CHIP_STAT_VPPS | | |
975 | CHIP_STAT_PSLBS; | |
976 | mask = mask | (mask << 16); | |
977 | /* put flash into read status mode by writing 0x70 to it */ | |
978 | flash_cmd (info->portwidth, addr, 0, | |
979 | CHIP_CMD_RD_STAT); | |
980 | /* are there any errors? */ | |
981 | if ((addr[0] & mask) != 0) { | |
982 | /* We got a one of the following errors: */ | |
983 | /* Voltage range, Device protect, or programming */ | |
984 | /* return the error as a device timeout */ | |
985 | /* put flash into read status mode by writing 0x70 to it */ | |
986 | flash_cmd (info->portwidth, addr, 0, | |
987 | CHIP_CMD_RD_STAT); | |
988 | printf ("Flash programming error at address 0x%08lx\n", dest); | |
989 | printf ("Flash status register contains 0x%08lx\n", (unsigned long) addr[0]); | |
990 | /* reset the flash */ | |
991 | flash_cmd (info->portwidth, addr, 0, | |
992 | CHIP_CMD_RST); | |
993 | return 1; | |
994 | } | |
995 | /* write completed without errors */ | |
996 | /* reset the flash */ | |
997 | flash_cmd (info->portwidth, addr, 0, | |
998 | CHIP_CMD_RST); | |
999 | return 0; | |
1000 | } else { | |
1001 | /* it's not 16-bits wide, so return an error as a write timeout */ | |
1002 | /* NOTE: you can add routines here to handle other size flash */ | |
1003 | printf ("Error: Intel flash device is only %d-bits wide\n", info->chipwidth * 8); | |
1004 | printf ("The write code only handles Intel 16-bit wide flash memory\n"); | |
1005 | return 1; | |
1006 | } | |
1007 | } else { | |
1008 | /* not Intel flash so return an error as a write timeout */ | |
1009 | /* NOTE: if it's another type flash, stick its routine here */ | |
1010 | printf ("Error: The flash device is not Intel type\n"); | |
1011 | printf ("The code only supports Intel flash in a 32-bit port width\n"); | |
1012 | return 1; | |
1013 | } | |
1014 | } | |
1015 | ||
1016 | /* end of 32-bit flash code */ | |
1017 | if ((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) | |
1018 | return 1; | |
1019 | if ((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) { | |
1020 | *(unsigned long *) dest = data; | |
1021 | return 0; | |
1022 | } | |
1023 | if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) { | |
1024 | unsigned short low = data & 0xffff; | |
1025 | unsigned short hi = (data >> 16) & 0xffff; | |
1026 | int ret = write_word_intel ((bank_addr_t) dest, hi); | |
1027 | ||
1028 | if (!ret) | |
1029 | ret = write_word_intel ((bank_addr_t) (dest + 2), | |
1030 | low); | |
1031 | ||
1032 | return ret; | |
1033 | } | |
1034 | ||
1035 | /* Check if Flash is (sufficiently) erased */ | |
1036 | if ((*((vu_long *) dest) & data) != data) { | |
1037 | return (2); | |
1038 | } | |
1039 | /* Disable interrupts which might cause a timeout here */ | |
1040 | flag = disable_interrupts (); | |
1041 | ||
1042 | /* first, perform an unlock bypass command to speed up flash writes */ | |
1043 | addr[0x555] = 0xAA; | |
1044 | addr[0x2AA] = 0x55; | |
1045 | addr[0x555] = 0x20; | |
1046 | ||
1047 | /* write each byte out */ | |
1048 | for (i = 0; i < 4; i++) { | |
1049 | char *data_ch = (char *) &data; | |
1050 | ||
1051 | addr[0] = 0xA0; | |
1052 | *(((char *) dest) + i) = data_ch[i]; | |
1053 | udelay (10); /* XXX */ | |
1054 | } | |
1055 | ||
1056 | /* we're done, now do an unlock bypass reset */ | |
1057 | addr[0] = 0x90; | |
1058 | addr[0] = 0x00; | |
1059 | ||
1060 | /* re-enable interrupts if necessary */ | |
1061 | if (flag) | |
1062 | enable_interrupts (); | |
1063 | ||
1064 | /* data polling for D7 */ | |
1065 | start = get_timer (0); | |
1066 | while ((*((vu_long *) dest) & 0x00800080) != (data & 0x00800080)) { | |
6d0f6bcf | 1067 | if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) { |
3a473b2a WD |
1068 | return (1); |
1069 | } | |
1070 | } | |
1071 | return (0); | |
1072 | } |