]>
Commit | Line | Data |
---|---|---|
affae2bf WD |
1 | /* |
2 | * (C) Copyright 2000 | |
3 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
affae2bf | 6 | * |
6dd652fa | 7 | * Hacked for the Hymod board by [email protected], 20-Oct-00 |
affae2bf WD |
8 | */ |
9 | ||
10 | #include <common.h> | |
11 | #include <mpc8260.h> | |
12 | #include <board/hymod/flash.h> | |
13 | ||
6d0f6bcf | 14 | flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */ |
affae2bf WD |
15 | |
16 | /*----------------------------------------------------------------------- | |
17 | * Protection Flags: | |
18 | */ | |
19 | #define FLAG_PROTECT_SET 0x01 | |
20 | #define FLAG_PROTECT_CLEAR 0x02 | |
21 | ||
affae2bf WD |
22 | /*----------------------------------------------------------------------- |
23 | */ | |
24 | ||
25 | /* | |
6dd652fa WD |
26 | * probe for flash bank at address "base" and store info about it |
27 | * in the flash_info entry "fip". Fatal error if nothing there. | |
affae2bf | 28 | */ |
6dd652fa | 29 | static void |
592c5cab | 30 | bank_probe (flash_info_t *fip, volatile bank_addr_t base) |
affae2bf | 31 | { |
592c5cab | 32 | volatile bank_addr_t addr; |
6dd652fa WD |
33 | bank_word_t word; |
34 | int i; | |
affae2bf WD |
35 | |
36 | /* reset the flash */ | |
6dd652fa | 37 | *base = BANK_CMD_RST; |
affae2bf | 38 | |
592c5cab | 39 | /* put flash into read id mode */ |
6dd652fa | 40 | *base = BANK_CMD_RD_ID; |
affae2bf | 41 | |
592c5cab WD |
42 | /* check the manufacturer id - must be intel */ |
43 | word = *BANK_REG_MAN_CODE (base); | |
6dd652fa WD |
44 | if (word != BANK_FILL_WORD (INTEL_MANUFACT&0xff)) |
45 | panic ("\nbad manufacturer's code (0x%08lx) at addr 0x%08lx", | |
46 | (unsigned long)word, (unsigned long)base); | |
affae2bf | 47 | |
6dd652fa | 48 | /* check the device id */ |
6dd652fa | 49 | word = *BANK_REG_DEV_CODE (base); |
6dd652fa | 50 | switch (word) { |
affae2bf | 51 | |
6dd652fa WD |
52 | case BANK_FILL_WORD (INTEL_ID_28F320J5&0xff): |
53 | fip->flash_id = FLASH_MAN_INTEL | FLASH_28F320J5; | |
54 | fip->sector_count = 32; | |
55 | break; | |
affae2bf | 56 | |
6dd652fa WD |
57 | case BANK_FILL_WORD (INTEL_ID_28F640J5&0xff): |
58 | fip->flash_id = FLASH_MAN_INTEL | FLASH_28F640J5; | |
59 | fip->sector_count = 64; | |
60 | break; | |
affae2bf | 61 | |
6dd652fa WD |
62 | case BANK_FILL_WORD (INTEL_ID_28F320J3A&0xff): |
63 | fip->flash_id = FLASH_MAN_INTEL | FLASH_28F320J3A; | |
64 | fip->sector_count = 32; | |
65 | break; | |
affae2bf | 66 | |
6dd652fa WD |
67 | case BANK_FILL_WORD (INTEL_ID_28F640J3A&0xff): |
68 | fip->flash_id = FLASH_MAN_INTEL | FLASH_28F640J3A; | |
69 | fip->sector_count = 64; | |
70 | break; | |
affae2bf | 71 | |
6dd652fa WD |
72 | case BANK_FILL_WORD (INTEL_ID_28F128J3A&0xff): |
73 | fip->flash_id = FLASH_MAN_INTEL | FLASH_28F128J3A; | |
74 | fip->sector_count = 128; | |
75 | break; | |
affae2bf | 76 | |
6dd652fa WD |
77 | default: |
78 | panic ("\nbad device code (0x%08lx) at addr 0x%08lx", | |
79 | (unsigned long)word, (unsigned long)base); | |
80 | } | |
affae2bf | 81 | |
6d0f6bcf | 82 | if (fip->sector_count >= CONFIG_SYS_MAX_FLASH_SECT) |
6dd652fa WD |
83 | panic ("\ntoo many sectors (%d) in flash at address 0x%08lx", |
84 | fip->sector_count, (unsigned long)base); | |
affae2bf | 85 | |
6dd652fa WD |
86 | addr = base; |
87 | for (i = 0; i < fip->sector_count; i++) { | |
88 | fip->start[i] = (unsigned long)addr; | |
89 | fip->protect[i] = 0; | |
90 | addr = BANK_ADDR_NEXT_BLK (addr); | |
affae2bf WD |
91 | } |
92 | ||
6dd652fa | 93 | fip->size = (bank_size_t)addr - (bank_size_t)base; |
592c5cab WD |
94 | |
95 | /* reset the flash */ | |
96 | *base = BANK_CMD_RST; | |
affae2bf WD |
97 | } |
98 | ||
99 | static void | |
6dd652fa | 100 | bank_reset (flash_info_t *info, int sect) |
affae2bf | 101 | { |
592c5cab | 102 | volatile bank_addr_t addr = (bank_addr_t)info->start[sect]; |
affae2bf | 103 | |
affae2bf | 104 | #ifdef FLASH_DEBUG |
6dd652fa | 105 | printf ("writing reset cmd to addr 0x%08lx\n", (unsigned long)addr); |
affae2bf | 106 | #endif |
6dd652fa WD |
107 | |
108 | *addr = BANK_CMD_RST; | |
affae2bf WD |
109 | } |
110 | ||
111 | static void | |
6dd652fa | 112 | bank_erase_init (flash_info_t *info, int sect) |
affae2bf | 113 | { |
592c5cab | 114 | volatile bank_addr_t addr = (bank_addr_t)info->start[sect]; |
affae2bf WD |
115 | int flag; |
116 | ||
117 | #ifdef FLASH_DEBUG | |
6dd652fa WD |
118 | printf ("erasing sector %d, addr = 0x%08lx\n", |
119 | sect, (unsigned long)addr); | |
affae2bf WD |
120 | #endif |
121 | ||
122 | /* Disable intrs which might cause a timeout here */ | |
6dd652fa | 123 | flag = disable_interrupts (); |
affae2bf | 124 | |
affae2bf | 125 | #ifdef FLASH_DEBUG |
6dd652fa | 126 | printf ("writing erase cmd to addr 0x%08lx\n", (unsigned long)addr); |
affae2bf | 127 | #endif |
6dd652fa WD |
128 | *addr = BANK_CMD_ERASE1; |
129 | *addr = BANK_CMD_ERASE2; | |
affae2bf WD |
130 | |
131 | /* re-enable interrupts if necessary */ | |
132 | if (flag) | |
6dd652fa | 133 | enable_interrupts (); |
affae2bf WD |
134 | } |
135 | ||
136 | static int | |
6dd652fa | 137 | bank_erase_poll (flash_info_t *info, int sect) |
affae2bf | 138 | { |
592c5cab | 139 | volatile bank_addr_t addr = (bank_addr_t)info->start[sect]; |
6dd652fa | 140 | bank_word_t stat = *addr; |
affae2bf WD |
141 | |
142 | #ifdef FLASH_DEBUG | |
6dd652fa WD |
143 | printf ("checking status at addr 0x%08lx [0x%08lx]\n", |
144 | (unsigned long)addr, (unsigned long)stat); | |
affae2bf | 145 | #endif |
6dd652fa WD |
146 | |
147 | if ((stat & BANK_STAT_RDY) == BANK_STAT_RDY) { | |
148 | if ((stat & BANK_STAT_ERR) != 0) { | |
149 | printf ("failed on sector %d [0x%08lx] at " | |
150 | "address 0x%08lx\n", sect, | |
151 | (unsigned long)stat, (unsigned long)addr); | |
152 | *addr = BANK_CMD_CLR_STAT; | |
153 | return (-1); | |
affae2bf | 154 | } |
6dd652fa WD |
155 | else |
156 | return (1); | |
affae2bf | 157 | } |
affae2bf | 158 | else |
6dd652fa | 159 | return (0); |
affae2bf WD |
160 | } |
161 | ||
162 | static int | |
592c5cab | 163 | bank_write_word (volatile bank_addr_t addr, bank_word_t value) |
affae2bf WD |
164 | { |
165 | bank_word_t stat; | |
166 | ulong start; | |
167 | int flag, retval; | |
168 | ||
169 | /* Disable interrupts which might cause a timeout here */ | |
6dd652fa | 170 | flag = disable_interrupts (); |
affae2bf WD |
171 | |
172 | *addr = BANK_CMD_PROG; | |
173 | ||
174 | *addr = value; | |
175 | ||
176 | /* re-enable interrupts if necessary */ | |
177 | if (flag) | |
6dd652fa | 178 | enable_interrupts (); |
affae2bf WD |
179 | |
180 | retval = 0; | |
181 | ||
182 | /* data polling for D7 */ | |
183 | start = get_timer (0); | |
184 | do { | |
6d0f6bcf | 185 | if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) { |
affae2bf WD |
186 | retval = 1; |
187 | goto done; | |
188 | } | |
189 | stat = *addr; | |
190 | } while ((stat & BANK_STAT_RDY) != BANK_STAT_RDY); | |
191 | ||
192 | if ((stat & BANK_STAT_ERR) != 0) { | |
6dd652fa WD |
193 | printf ("flash program failed [0x%08lx] at address 0x%08lx\n", |
194 | (unsigned long)stat, (unsigned long)addr); | |
affae2bf WD |
195 | *addr = BANK_CMD_CLR_STAT; |
196 | retval = 3; | |
197 | } | |
198 | ||
199 | done: | |
200 | /* reset to read mode */ | |
201 | *addr = BANK_CMD_RST; | |
202 | ||
203 | return (retval); | |
204 | } | |
205 | ||
206 | /*----------------------------------------------------------------------- | |
207 | */ | |
208 | ||
209 | unsigned long | |
6dd652fa | 210 | flash_init (void) |
affae2bf WD |
211 | { |
212 | int i; | |
213 | ||
214 | /* Init: no FLASHes known */ | |
6d0f6bcf | 215 | for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) { |
affae2bf WD |
216 | flash_info[i].flash_id = FLASH_UNKNOWN; |
217 | } | |
218 | ||
6d0f6bcf | 219 | bank_probe (&flash_info[0], (bank_addr_t)CONFIG_SYS_FLASH_BASE); |
affae2bf WD |
220 | |
221 | /* | |
222 | * protect monitor and environment sectors | |
223 | */ | |
224 | ||
6d0f6bcf | 225 | #if CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE |
6dd652fa | 226 | (void)flash_protect (FLAG_PROTECT_SET, |
6d0f6bcf JCPV |
227 | CONFIG_SYS_MONITOR_BASE, |
228 | CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1, | |
affae2bf WD |
229 | &flash_info[0]); |
230 | #endif | |
231 | ||
6d0f6bcf | 232 | #if defined(CONFIG_SYS_FLASH_ENV_ADDR) |
6dd652fa | 233 | (void)flash_protect (FLAG_PROTECT_SET, |
6d0f6bcf JCPV |
234 | CONFIG_SYS_FLASH_ENV_ADDR, |
235 | #if defined(CONFIG_SYS_FLASH_ENV_BUF) | |
236 | CONFIG_SYS_FLASH_ENV_ADDR + CONFIG_SYS_FLASH_ENV_BUF - 1, | |
affae2bf | 237 | #else |
6d0f6bcf | 238 | CONFIG_SYS_FLASH_ENV_ADDR + CONFIG_SYS_FLASH_ENV_SIZE - 1, |
affae2bf WD |
239 | #endif |
240 | &flash_info[0]); | |
241 | #endif | |
242 | ||
243 | return flash_info[0].size; | |
244 | } | |
245 | ||
affae2bf WD |
246 | /*----------------------------------------------------------------------- |
247 | */ | |
248 | void | |
6dd652fa | 249 | flash_print_info (flash_info_t *info) |
affae2bf WD |
250 | { |
251 | int i; | |
252 | ||
253 | if (info->flash_id == FLASH_UNKNOWN) { | |
254 | printf ("missing or unknown FLASH type\n"); | |
255 | return; | |
256 | } | |
257 | ||
258 | switch (info->flash_id & FLASH_VENDMASK) { | |
259 | case FLASH_MAN_INTEL: printf ("INTEL "); break; | |
260 | default: printf ("Unknown Vendor "); break; | |
261 | } | |
262 | ||
263 | switch (info->flash_id & FLASH_TYPEMASK) { | |
264 | case FLASH_28F320J5: printf ("28F320J5 (32 Mbit, 2 x 16bit)\n"); | |
265 | break; | |
6dd652fa WD |
266 | case FLASH_28F640J5: printf ("28F640J5 (64 Mbit, 2 x 16bit)\n"); |
267 | break; | |
268 | case FLASH_28F320J3A: printf ("28F320J3A (32 Mbit, 2 x 16bit)\n"); | |
269 | break; | |
270 | case FLASH_28F640J3A: printf ("28F640J3A (64 Mbit, 2 x 16bit)\n"); | |
271 | break; | |
272 | case FLASH_28F128J3A: printf ("28F320J3A (128 Mbit, 2 x 16bit)\n"); | |
273 | break; | |
affae2bf WD |
274 | default: printf ("Unknown Chip Type\n"); |
275 | break; | |
276 | } | |
277 | ||
278 | printf (" Size: %ld MB in %d Sectors\n", | |
279 | info->size >> 20, info->sector_count); | |
280 | ||
281 | printf (" Sector Start Addresses:"); | |
282 | for (i=0; i<info->sector_count; ++i) { | |
283 | if ((i % 5) == 0) | |
284 | printf ("\n "); | |
285 | printf (" %08lX%s", | |
286 | info->start[i], | |
287 | info->protect[i] ? " (RO)" : " " | |
288 | ); | |
289 | } | |
290 | printf ("\n"); | |
291 | return; | |
292 | } | |
293 | ||
affae2bf WD |
294 | /* |
295 | * The following code cannot be run from FLASH! | |
296 | */ | |
affae2bf WD |
297 | |
298 | /*----------------------------------------------------------------------- | |
299 | */ | |
300 | ||
301 | int | |
6dd652fa | 302 | flash_erase (flash_info_t *info, int s_first, int s_last) |
affae2bf WD |
303 | { |
304 | int prot, sect, haderr; | |
305 | ulong start, now, last; | |
306 | int rcode = 0; | |
307 | ||
308 | #ifdef FLASH_DEBUG | |
6dd652fa | 309 | printf ("\nflash_erase: erase %d sectors (%d to %d incl.) from\n" |
affae2bf WD |
310 | " Bank # %d: ", s_last - s_first + 1, s_first, s_last, |
311 | (info - flash_info) + 1); | |
6dd652fa | 312 | flash_print_info (info); |
affae2bf WD |
313 | #endif |
314 | ||
315 | if ((s_first < 0) || (s_first > s_last)) { | |
316 | if (info->flash_id == FLASH_UNKNOWN) { | |
317 | printf ("- missing\n"); | |
318 | } else { | |
319 | printf ("- no sectors to erase\n"); | |
320 | } | |
321 | return 1; | |
322 | } | |
323 | ||
324 | prot = 0; | |
6dd652fa | 325 | for (sect = s_first; sect <= s_last; ++sect) { |
affae2bf WD |
326 | if (info->protect[sect]) { |
327 | prot++; | |
328 | } | |
329 | } | |
330 | ||
331 | if (prot) { | |
6dd652fa | 332 | printf ("- Warning: %d protected sector%s will not be erased\n", |
affae2bf WD |
333 | prot, (prot > 1 ? "s" : "")); |
334 | } | |
335 | ||
336 | start = get_timer (0); | |
337 | last = 0; | |
338 | haderr = 0; | |
339 | ||
340 | for (sect = s_first; sect <= s_last; sect++) { | |
341 | if (info->protect[sect] == 0) { /* not protected */ | |
342 | ulong estart; | |
343 | int sectdone; | |
344 | ||
6dd652fa | 345 | bank_erase_init (info, sect); |
affae2bf WD |
346 | |
347 | /* wait at least 80us - let's wait 1 ms */ | |
348 | udelay (1000); | |
349 | ||
6dd652fa | 350 | estart = get_timer (start); |
affae2bf WD |
351 | |
352 | do { | |
6dd652fa | 353 | now = get_timer (start); |
affae2bf | 354 | |
6d0f6bcf | 355 | if (now - estart > CONFIG_SYS_FLASH_ERASE_TOUT) { |
affae2bf WD |
356 | printf ("Timeout (sect %d)\n", sect); |
357 | haderr = 1; | |
358 | rcode = 1; | |
359 | break; | |
360 | } | |
361 | ||
362 | #ifndef FLASH_DEBUG | |
363 | /* show that we're waiting */ | |
364 | if ((now - last) > 1000) { /* every second */ | |
365 | putc ('.'); | |
366 | last = now; | |
367 | } | |
368 | #endif | |
369 | ||
6dd652fa | 370 | sectdone = bank_erase_poll (info, sect); |
affae2bf WD |
371 | |
372 | if (sectdone < 0) { | |
373 | haderr = 1; | |
374 | rcode = 1; | |
375 | break; | |
376 | } | |
377 | ||
378 | } while (!sectdone); | |
379 | ||
380 | if (haderr) | |
381 | break; | |
382 | } | |
383 | } | |
384 | ||
385 | if (haderr > 0) | |
386 | printf (" failed\n"); | |
387 | else | |
388 | printf (" done\n"); | |
389 | ||
390 | /* reset to read mode */ | |
391 | for (sect = s_first; sect <= s_last; sect++) { | |
392 | if (info->protect[sect] == 0) { /* not protected */ | |
6dd652fa | 393 | bank_reset (info, sect); |
affae2bf WD |
394 | } |
395 | } | |
396 | return rcode; | |
397 | } | |
398 | ||
6dd652fa WD |
399 | /*----------------------------------------------------------------------- |
400 | * Write a word to Flash, returns: | |
401 | * 0 - OK | |
402 | * 1 - write timeout | |
403 | * 2 - Flash not erased | |
404 | * 3 - Program failed | |
405 | */ | |
406 | static int | |
407 | write_word (flash_info_t *info, ulong dest, ulong data) | |
408 | { | |
409 | /* Check if Flash is (sufficiently) erased */ | |
410 | if ((*(ulong *)dest & data) != data) | |
411 | return (2); | |
412 | ||
413 | return (bank_write_word ((bank_addr_t)dest, (bank_word_t)data)); | |
414 | } | |
415 | ||
affae2bf WD |
416 | /*----------------------------------------------------------------------- |
417 | * Copy memory to flash, returns: | |
418 | * 0 - OK | |
419 | * 1 - write timeout | |
420 | * 2 - Flash not erased | |
6dd652fa | 421 | * 3 - Program failed |
affae2bf WD |
422 | */ |
423 | ||
424 | int | |
6dd652fa | 425 | write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) |
affae2bf WD |
426 | { |
427 | ulong cp, wp, data; | |
428 | int i, l, rc; | |
429 | ||
430 | wp = (addr & ~3); /* get lower word aligned address */ | |
431 | ||
432 | /* | |
433 | * handle unaligned start bytes | |
434 | */ | |
435 | if ((l = addr - wp) != 0) { | |
436 | data = 0; | |
437 | for (i=0, cp=wp; i<l; ++i, ++cp) { | |
438 | data = (data << 8) | (*(uchar *)cp); | |
439 | } | |
440 | for (; i<4 && cnt>0; ++i) { | |
441 | data = (data << 8) | *src++; | |
442 | --cnt; | |
443 | ++cp; | |
444 | } | |
445 | for (; cnt==0 && i<4; ++i, ++cp) { | |
446 | data = (data << 8) | (*(uchar *)cp); | |
447 | } | |
448 | ||
6dd652fa | 449 | if ((rc = write_word (info, wp, data)) != 0) { |
affae2bf WD |
450 | return (rc); |
451 | } | |
452 | wp += 4; | |
453 | } | |
454 | ||
455 | /* | |
456 | * handle word aligned part | |
457 | */ | |
458 | while (cnt >= 4) { | |
459 | data = 0; | |
460 | for (i=0; i<4; ++i) { | |
461 | data = (data << 8) | *src++; | |
462 | } | |
6dd652fa | 463 | if ((rc = write_word (info, wp, data)) != 0) { |
affae2bf WD |
464 | return (rc); |
465 | } | |
466 | wp += 4; | |
467 | cnt -= 4; | |
468 | } | |
469 | ||
470 | if (cnt == 0) { | |
471 | return (0); | |
472 | } | |
473 | ||
474 | /* | |
475 | * handle unaligned tail bytes | |
476 | */ | |
477 | data = 0; | |
478 | for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) { | |
479 | data = (data << 8) | *src++; | |
480 | --cnt; | |
481 | } | |
482 | for (; i<4; ++i, ++cp) { | |
483 | data = (data << 8) | (*(uchar *)cp); | |
484 | } | |
485 | ||
6dd652fa | 486 | return (write_word (info, wp, data)); |
affae2bf WD |
487 | } |
488 | ||
489 | /*----------------------------------------------------------------------- | |
490 | */ |