]>
Commit | Line | Data |
---|---|---|
3bac3513 WD |
1 | /* |
2 | * (C) Copyright 2001-2003 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
3bac3513 WD |
6 | */ |
7 | ||
8 | #include <common.h> | |
9 | #include <mpc824x.h> | |
10 | #include <asm/processor.h> | |
11 | ||
5a1aceb0 | 12 | #if defined(CONFIG_ENV_IS_IN_FLASH) |
0e8d1586 | 13 | # ifndef CONFIG_ENV_ADDR |
6d0f6bcf | 14 | # define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET) |
3bac3513 | 15 | # endif |
0e8d1586 JCPV |
16 | # ifndef CONFIG_ENV_SIZE |
17 | # define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE | |
3bac3513 | 18 | # endif |
0e8d1586 JCPV |
19 | # ifndef CONFIG_ENV_SECT_SIZE |
20 | # define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE | |
3bac3513 WD |
21 | # endif |
22 | #endif | |
23 | ||
24 | #define FLASH_BANK_SIZE 0x800000 | |
25 | #define MAIN_SECT_SIZE 0x40000 | |
26 | #define PARAM_SECT_SIZE 0x8000 | |
27 | ||
6d0f6bcf | 28 | flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; |
3bac3513 | 29 | |
49822e23 WD |
30 | static int write_data (flash_info_t * info, ulong dest, ulong * data); |
31 | static void write_via_fpu (vu_long * addr, ulong * data); | |
32 | static __inline__ unsigned long get_msr (void); | |
33 | static __inline__ void set_msr (unsigned long msr); | |
3bac3513 WD |
34 | |
35 | /*---------------------------------------------------------------------*/ | |
36 | #undef DEBUG_FLASH | |
37 | ||
38 | /*---------------------------------------------------------------------*/ | |
39 | #ifdef DEBUG_FLASH | |
40 | #define DEBUGF(fmt,args...) printf(fmt ,##args) | |
41 | #else | |
42 | #define DEBUGF(fmt,args...) | |
43 | #endif | |
44 | /*---------------------------------------------------------------------*/ | |
45 | ||
46 | /*----------------------------------------------------------------------- | |
47 | */ | |
48 | ||
49822e23 | 49 | unsigned long flash_init (void) |
3bac3513 | 50 | { |
49822e23 WD |
51 | int i, j; |
52 | ulong size = 0; | |
53 | uchar tempChar; | |
54 | vu_long *tmpaddr; | |
3bac3513 | 55 | |
49822e23 | 56 | /* Enable flash writes on CPC45 */ |
3bac3513 | 57 | |
49822e23 | 58 | tempChar = BOARD_CTRL; |
3bac3513 | 59 | |
49822e23 | 60 | tempChar |= (B_CTRL_FWPT_1 | B_CTRL_FWRE_1); |
3bac3513 | 61 | |
49822e23 | 62 | tempChar &= ~(B_CTRL_FWPT_0 | B_CTRL_FWRE_0); |
3bac3513 | 63 | |
49822e23 | 64 | BOARD_CTRL = tempChar; |
3bac3513 | 65 | |
49822e23 | 66 | __asm__ volatile ("sync\n eieio"); |
3bac3513 | 67 | |
6d0f6bcf JCPV |
68 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { |
69 | vu_long *addr = (vu_long *) (CONFIG_SYS_FLASH_BASE + i * FLASH_BANK_SIZE); | |
3bac3513 | 70 | |
49822e23 | 71 | addr[0] = 0x00900090; |
3bac3513 | 72 | |
49822e23 | 73 | __asm__ volatile ("sync\n eieio"); |
3bac3513 | 74 | |
49822e23 | 75 | udelay (100); |
3bac3513 | 76 | |
49822e23 WD |
77 | DEBUGF ("Flash bank # %d:\n" |
78 | "\tManuf. ID @ 0x%08lX: 0x%08lX\n" | |
79 | "\tDevice ID @ 0x%08lX: 0x%08lX\n", | |
80 | i, | |
81 | (ulong) (&addr[0]), addr[0], | |
82 | (ulong) (&addr[2]), addr[2]); | |
3bac3513 | 83 | |
3bac3513 | 84 | |
49822e23 WD |
85 | if ((addr[0] == addr[1]) && (addr[0] == INTEL_MANUFACT) && |
86 | (addr[2] == addr[3]) && (addr[2] == INTEL_ID_28F160F3T)) { | |
3bac3513 | 87 | |
49822e23 WD |
88 | flash_info[i].flash_id = |
89 | (FLASH_MAN_INTEL & FLASH_VENDMASK) | | |
90 | (INTEL_ID_28F160F3T & FLASH_TYPEMASK); | |
3bac3513 | 91 | |
49822e23 WD |
92 | } else if ((addr[0] == addr[1]) && (addr[0] == INTEL_MANUFACT) |
93 | && (addr[2] == addr[3]) | |
94 | && (addr[2] == INTEL_ID_28F160C3T)) { | |
95 | ||
96 | flash_info[i].flash_id = | |
97 | (FLASH_MAN_INTEL & FLASH_VENDMASK) | | |
98 | (INTEL_ID_28F160C3T & FLASH_TYPEMASK); | |
3bac3513 | 99 | |
3bac3513 | 100 | } else { |
49822e23 WD |
101 | flash_info[i].flash_id = FLASH_UNKNOWN; |
102 | addr[0] = 0xFFFFFFFF; | |
103 | goto Done; | |
104 | } | |
105 | ||
106 | DEBUGF ("flash_id = 0x%08lX\n", flash_info[i].flash_id); | |
107 | ||
108 | addr[0] = 0xFFFFFFFF; | |
109 | ||
110 | flash_info[i].size = FLASH_BANK_SIZE; | |
6d0f6bcf JCPV |
111 | flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT; |
112 | memset (flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT); | |
49822e23 WD |
113 | for (j = 0; j < flash_info[i].sector_count; j++) { |
114 | if (j > 30) { | |
6d0f6bcf | 115 | flash_info[i].start[j] = CONFIG_SYS_FLASH_BASE + |
49822e23 WD |
116 | i * FLASH_BANK_SIZE + |
117 | (MAIN_SECT_SIZE * 31) + (j - | |
118 | 31) * | |
119 | PARAM_SECT_SIZE; | |
120 | } else { | |
6d0f6bcf | 121 | flash_info[i].start[j] = CONFIG_SYS_FLASH_BASE + |
49822e23 WD |
122 | i * FLASH_BANK_SIZE + |
123 | j * MAIN_SECT_SIZE; | |
124 | } | |
125 | } | |
126 | ||
127 | /* unlock sectors, if 160C3T */ | |
128 | ||
129 | for (j = 0; j < flash_info[i].sector_count; j++) { | |
130 | tmpaddr = (vu_long *) flash_info[i].start[j]; | |
131 | ||
132 | if ((flash_info[i].flash_id & FLASH_TYPEMASK) == | |
133 | (INTEL_ID_28F160C3T & FLASH_TYPEMASK)) { | |
134 | tmpaddr[0] = 0x00600060; | |
135 | tmpaddr[0] = 0x00D000D0; | |
136 | tmpaddr[1] = 0x00600060; | |
137 | tmpaddr[1] = 0x00D000D0; | |
138 | } | |
3bac3513 | 139 | } |
49822e23 WD |
140 | |
141 | size += flash_info[i].size; | |
142 | ||
143 | addr[0] = 0x00FF00FF; | |
144 | addr[1] = 0x00FF00FF; | |
3bac3513 | 145 | } |
3bac3513 | 146 | |
49822e23 WD |
147 | /* Protect monitor and environment sectors |
148 | */ | |
6d0f6bcf | 149 | #if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE + FLASH_BANK_SIZE |
49822e23 | 150 | flash_protect (FLAG_PROTECT_SET, |
6d0f6bcf JCPV |
151 | CONFIG_SYS_MONITOR_BASE, |
152 | CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, | |
49822e23 | 153 | &flash_info[1]); |
3bac3513 | 154 | #else |
49822e23 | 155 | flash_protect (FLAG_PROTECT_SET, |
6d0f6bcf JCPV |
156 | CONFIG_SYS_MONITOR_BASE, |
157 | CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, | |
49822e23 | 158 | &flash_info[0]); |
3bac3513 WD |
159 | #endif |
160 | ||
0e8d1586 | 161 | #if defined(CONFIG_ENV_IS_IN_FLASH) && defined(CONFIG_ENV_ADDR) |
6d0f6bcf | 162 | #if CONFIG_ENV_ADDR >= CONFIG_SYS_FLASH_BASE + FLASH_BANK_SIZE |
49822e23 | 163 | flash_protect (FLAG_PROTECT_SET, |
0e8d1586 JCPV |
164 | CONFIG_ENV_ADDR, |
165 | CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[1]); | |
3bac3513 | 166 | #else |
49822e23 | 167 | flash_protect (FLAG_PROTECT_SET, |
0e8d1586 JCPV |
168 | CONFIG_ENV_ADDR, |
169 | CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]); | |
3bac3513 WD |
170 | #endif |
171 | #endif | |
172 | ||
173 | Done: | |
49822e23 | 174 | return size; |
3bac3513 WD |
175 | } |
176 | ||
177 | /*----------------------------------------------------------------------- | |
178 | */ | |
179 | void flash_print_info (flash_info_t * info) | |
180 | { | |
181 | int i; | |
182 | ||
183 | switch ((i = info->flash_id & FLASH_VENDMASK)) { | |
184 | case (FLASH_MAN_INTEL & FLASH_VENDMASK): | |
185 | printf ("Intel: "); | |
186 | break; | |
187 | default: | |
188 | printf ("Unknown Vendor 0x%04x ", i); | |
189 | break; | |
190 | } | |
191 | ||
192 | switch ((i = info->flash_id & FLASH_TYPEMASK)) { | |
193 | case (INTEL_ID_28F160F3T & FLASH_TYPEMASK): | |
194 | printf ("28F160F3T (16Mbit)\n"); | |
195 | break; | |
49822e23 WD |
196 | |
197 | case (INTEL_ID_28F160C3T & FLASH_TYPEMASK): | |
198 | printf ("28F160C3T (16Mbit)\n"); | |
199 | break; | |
200 | ||
3bac3513 WD |
201 | default: |
202 | printf ("Unknown Chip Type 0x%04x\n", i); | |
203 | goto Done; | |
204 | break; | |
205 | } | |
206 | ||
207 | printf (" Size: %ld MB in %d Sectors\n", | |
49822e23 | 208 | info->size >> 20, info->sector_count); |
3bac3513 WD |
209 | |
210 | printf (" Sector Start Addresses:"); | |
211 | for (i = 0; i < info->sector_count; i++) { | |
212 | if ((i % 5) == 0) { | |
213 | printf ("\n "); | |
214 | } | |
215 | printf (" %08lX%s", info->start[i], | |
49822e23 | 216 | info->protect[i] ? " (RO)" : " "); |
3bac3513 WD |
217 | } |
218 | printf ("\n"); | |
219 | ||
220 | Done: | |
221 | return; | |
222 | } | |
223 | ||
224 | /*----------------------------------------------------------------------- | |
225 | */ | |
226 | ||
49822e23 | 227 | int flash_erase (flash_info_t * info, int s_first, int s_last) |
3bac3513 WD |
228 | { |
229 | int flag, prot, sect; | |
230 | ulong start, now, last; | |
231 | ||
232 | DEBUGF ("Erase flash bank %d sect %d ... %d\n", | |
233 | info - &flash_info[0], s_first, s_last); | |
234 | ||
235 | if ((s_first < 0) || (s_first > s_last)) { | |
236 | if (info->flash_id == FLASH_UNKNOWN) { | |
237 | printf ("- missing\n"); | |
238 | } else { | |
239 | printf ("- no sectors to erase\n"); | |
240 | } | |
241 | return 1; | |
242 | } | |
243 | ||
244 | if ((info->flash_id & FLASH_VENDMASK) != | |
245 | (FLASH_MAN_INTEL & FLASH_VENDMASK)) { | |
246 | printf ("Can erase only Intel flash types - aborted\n"); | |
247 | return 1; | |
248 | } | |
249 | ||
250 | prot = 0; | |
49822e23 | 251 | for (sect = s_first; sect <= s_last; ++sect) { |
3bac3513 WD |
252 | if (info->protect[sect]) { |
253 | prot++; | |
254 | } | |
255 | } | |
256 | ||
257 | if (prot) { | |
49822e23 | 258 | printf ("- Warning: %d protected sectors will not be erased!\n", prot); |
3bac3513 WD |
259 | } else { |
260 | printf ("\n"); | |
261 | } | |
262 | ||
263 | start = get_timer (0); | |
49822e23 | 264 | last = start; |
3bac3513 | 265 | /* Start erase on unprotected sectors */ |
49822e23 | 266 | for (sect = s_first; sect <= s_last; sect++) { |
3bac3513 | 267 | if (info->protect[sect] == 0) { /* not protected */ |
49822e23 | 268 | vu_long *addr = (vu_long *) (info->start[sect]); |
3bac3513 WD |
269 | |
270 | DEBUGF ("Erase sect %d @ 0x%08lX\n", | |
49822e23 | 271 | sect, (ulong) addr); |
3bac3513 WD |
272 | |
273 | /* Disable interrupts which might cause a timeout | |
274 | * here. | |
275 | */ | |
49822e23 | 276 | flag = disable_interrupts (); |
3bac3513 WD |
277 | |
278 | addr[0] = 0x00500050; /* clear status register */ | |
279 | addr[0] = 0x00200020; /* erase setup */ | |
280 | addr[0] = 0x00D000D0; /* erase confirm */ | |
281 | ||
282 | addr[1] = 0x00500050; /* clear status register */ | |
283 | addr[1] = 0x00200020; /* erase setup */ | |
284 | addr[1] = 0x00D000D0; /* erase confirm */ | |
285 | ||
286 | /* re-enable interrupts if necessary */ | |
287 | if (flag) | |
49822e23 | 288 | enable_interrupts (); |
3bac3513 WD |
289 | |
290 | /* wait at least 80us - let's wait 1 ms */ | |
291 | udelay (1000); | |
292 | ||
293 | while (((addr[0] & 0x00800080) != 0x00800080) || | |
49822e23 WD |
294 | ((addr[1] & 0x00800080) != 0x00800080)) { |
295 | if ((now = get_timer (start)) > | |
6d0f6bcf | 296 | CONFIG_SYS_FLASH_ERASE_TOUT) { |
3bac3513 | 297 | printf ("Timeout\n"); |
49822e23 WD |
298 | addr[0] = 0x00B000B0; /* suspend erase */ |
299 | addr[0] = 0x00FF00FF; /* to read mode */ | |
3bac3513 WD |
300 | return 1; |
301 | } | |
302 | ||
303 | /* show that we're waiting */ | |
49822e23 | 304 | if ((now - last) > 1000) { /* every second */ |
3bac3513 WD |
305 | putc ('.'); |
306 | last = now; | |
307 | } | |
308 | } | |
309 | ||
310 | addr[0] = 0x00FF00FF; | |
311 | } | |
312 | } | |
313 | printf (" done\n"); | |
314 | return 0; | |
315 | } | |
316 | ||
317 | /*----------------------------------------------------------------------- | |
318 | * Copy memory to flash, returns: | |
319 | * 0 - OK | |
320 | * 1 - write timeout | |
321 | * 2 - Flash not erased | |
322 | * 4 - Flash not identified | |
323 | */ | |
324 | ||
325 | #define FLASH_WIDTH 8 /* flash bus width in bytes */ | |
326 | ||
49822e23 | 327 | int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) |
3bac3513 WD |
328 | { |
329 | ulong wp, cp, msr; | |
330 | int l, rc, i; | |
331 | ulong data[2]; | |
332 | ulong *datah = &data[0]; | |
333 | ulong *datal = &data[1]; | |
334 | ||
335 | DEBUGF ("Flash write_buff: @ 0x%08lx, src 0x%08lx len %ld\n", | |
49822e23 | 336 | addr, (ulong) src, cnt); |
3bac3513 WD |
337 | |
338 | if (info->flash_id == FLASH_UNKNOWN) { | |
339 | return 4; | |
340 | } | |
341 | ||
49822e23 WD |
342 | msr = get_msr (); |
343 | set_msr (msr | MSR_FP); | |
3bac3513 | 344 | |
49822e23 | 345 | wp = (addr & ~(FLASH_WIDTH - 1)); /* get lower aligned address */ |
3bac3513 WD |
346 | |
347 | /* | |
348 | * handle unaligned start bytes | |
349 | */ | |
350 | if ((l = addr - wp) != 0) { | |
351 | *datah = *datal = 0; | |
352 | ||
353 | for (i = 0, cp = wp; i < l; i++, cp++) { | |
354 | if (i >= 4) { | |
355 | *datah = (*datah << 8) | | |
49822e23 | 356 | ((*datal & 0xFF000000) >> 24); |
3bac3513 WD |
357 | } |
358 | ||
49822e23 | 359 | *datal = (*datal << 8) | (*(uchar *) cp); |
3bac3513 WD |
360 | } |
361 | for (; i < FLASH_WIDTH && cnt > 0; ++i) { | |
49822e23 | 362 | char tmp = *src++; |
3bac3513 WD |
363 | |
364 | if (i >= 4) { | |
365 | *datah = (*datah << 8) | | |
49822e23 | 366 | ((*datal & 0xFF000000) >> 24); |
3bac3513 WD |
367 | } |
368 | ||
369 | *datal = (*datal << 8) | tmp; | |
49822e23 WD |
370 | --cnt; |
371 | ++cp; | |
3bac3513 WD |
372 | } |
373 | ||
374 | for (; cnt == 0 && i < FLASH_WIDTH; ++i, ++cp) { | |
375 | if (i >= 4) { | |
376 | *datah = (*datah << 8) | | |
49822e23 | 377 | ((*datal & 0xFF000000) >> 24); |
3bac3513 WD |
378 | } |
379 | ||
49822e23 | 380 | *datal = (*datah << 8) | (*(uchar *) cp); |
3bac3513 WD |
381 | } |
382 | ||
49822e23 WD |
383 | if ((rc = write_data (info, wp, data)) != 0) { |
384 | set_msr (msr); | |
3bac3513 WD |
385 | return (rc); |
386 | } | |
387 | ||
388 | wp += FLASH_WIDTH; | |
389 | } | |
390 | ||
391 | /* | |
392 | * handle FLASH_WIDTH aligned part | |
393 | */ | |
394 | while (cnt >= FLASH_WIDTH) { | |
49822e23 WD |
395 | *datah = *(ulong *) src; |
396 | *datal = *(ulong *) (src + 4); | |
397 | if ((rc = write_data (info, wp, data)) != 0) { | |
398 | set_msr (msr); | |
3bac3513 WD |
399 | return (rc); |
400 | } | |
49822e23 | 401 | wp += FLASH_WIDTH; |
3bac3513 WD |
402 | cnt -= FLASH_WIDTH; |
403 | src += FLASH_WIDTH; | |
404 | } | |
405 | ||
406 | if (cnt == 0) { | |
49822e23 | 407 | set_msr (msr); |
3bac3513 WD |
408 | return (0); |
409 | } | |
410 | ||
411 | /* | |
412 | * handle unaligned tail bytes | |
413 | */ | |
414 | *datah = *datal = 0; | |
415 | for (i = 0, cp = wp; i < FLASH_WIDTH && cnt > 0; ++i, ++cp) { | |
49822e23 | 416 | char tmp = *src++; |
3bac3513 WD |
417 | |
418 | if (i >= 4) { | |
49822e23 WD |
419 | *datah = (*datah << 8) | ((*datal & 0xFF000000) >> |
420 | 24); | |
3bac3513 WD |
421 | } |
422 | ||
423 | *datal = (*datal << 8) | tmp; | |
3bac3513 WD |
424 | --cnt; |
425 | } | |
426 | ||
427 | for (; i < FLASH_WIDTH; ++i, ++cp) { | |
428 | if (i >= 4) { | |
49822e23 WD |
429 | *datah = (*datah << 8) | ((*datal & 0xFF000000) >> |
430 | 24); | |
3bac3513 WD |
431 | } |
432 | ||
49822e23 | 433 | *datal = (*datal << 8) | (*(uchar *) cp); |
3bac3513 WD |
434 | } |
435 | ||
49822e23 WD |
436 | rc = write_data (info, wp, data); |
437 | set_msr (msr); | |
3bac3513 WD |
438 | |
439 | return (rc); | |
440 | } | |
441 | ||
442 | /*----------------------------------------------------------------------- | |
443 | * Write a word to Flash, returns: | |
444 | * 0 - OK | |
445 | * 1 - write timeout | |
446 | * 2 - Flash not erased | |
447 | */ | |
49822e23 | 448 | static int write_data (flash_info_t * info, ulong dest, ulong * data) |
3bac3513 | 449 | { |
49822e23 | 450 | vu_long *addr = (vu_long *) dest; |
3bac3513 WD |
451 | ulong start; |
452 | int flag; | |
453 | ||
454 | /* Check if Flash is (sufficiently) erased */ | |
455 | if (((addr[0] & data[0]) != data[0]) || | |
49822e23 | 456 | ((addr[1] & data[1]) != data[1])) { |
3bac3513 WD |
457 | return (2); |
458 | } | |
459 | /* Disable interrupts which might cause a timeout here */ | |
49822e23 | 460 | flag = disable_interrupts (); |
3bac3513 | 461 | |
49822e23 WD |
462 | addr[0] = 0x00400040; /* write setup */ |
463 | write_via_fpu (addr, data); | |
3bac3513 WD |
464 | |
465 | /* re-enable interrupts if necessary */ | |
466 | if (flag) | |
49822e23 | 467 | enable_interrupts (); |
3bac3513 WD |
468 | |
469 | start = get_timer (0); | |
470 | ||
471 | while (((addr[0] & 0x00800080) != 0x00800080) || | |
49822e23 | 472 | ((addr[1] & 0x00800080) != 0x00800080)) { |
6d0f6bcf | 473 | if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) { |
3bac3513 WD |
474 | addr[0] = 0x00FF00FF; /* restore read mode */ |
475 | return (1); | |
476 | } | |
477 | } | |
478 | ||
479 | addr[0] = 0x00FF00FF; /* restore read mode */ | |
480 | ||
481 | return (0); | |
482 | } | |
483 | ||
484 | /*----------------------------------------------------------------------- | |
485 | */ | |
49822e23 | 486 | static void write_via_fpu (vu_long * addr, ulong * data) |
3bac3513 | 487 | { |
49822e23 WD |
488 | __asm__ __volatile__ ("lfd 1, 0(%0)"::"r" (data)); |
489 | __asm__ __volatile__ ("stfd 1, 0(%0)"::"r" (addr)); | |
3bac3513 | 490 | } |
49822e23 | 491 | |
3bac3513 WD |
492 | /*----------------------------------------------------------------------- |
493 | */ | |
49822e23 | 494 | static __inline__ unsigned long get_msr (void) |
3bac3513 | 495 | { |
49822e23 WD |
496 | unsigned long msr; |
497 | ||
498 | __asm__ __volatile__ ("mfmsr %0":"=r" (msr):); | |
3bac3513 | 499 | |
49822e23 | 500 | return msr; |
3bac3513 WD |
501 | } |
502 | ||
49822e23 | 503 | static __inline__ void set_msr (unsigned long msr) |
3bac3513 | 504 | { |
49822e23 | 505 | __asm__ __volatile__ ("mtmsr %0"::"r" (msr)); |
3bac3513 | 506 | } |