blob: 91bd968379e9cf677f9127a925044ba78fe4d6b6 [file] [log] [blame]
wdenk04a85b32004-04-15 18:22:41 +00001/*
2 * (C) Copyright 2000-2004
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenk04a85b32004-04-15 18:22:41 +00006 */
7
8#include <common.h>
9#include <mpc8xx.h>
10
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020011flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenk04a85b32004-04-15 18:22:41 +000012
13/*-----------------------------------------------------------------------
14 * Functions
15 */
16static ulong flash_get_size(vu_long * addr, flash_info_t * info);
17static int write_byte(flash_info_t * info, ulong dest, uchar data);
18static void flash_get_offsets(ulong base, flash_info_t * info);
19
20/*-----------------------------------------------------------------------
21 */
22
23unsigned long flash_init(void)
24{
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020025 volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
wdenk04a85b32004-04-15 18:22:41 +000026 volatile memctl8xx_t *memctl = &immap->im_memctl;
27 unsigned long size;
wdenkc26e4542004-04-18 10:13:26 +000028#if CONFIG_NETPHONE_VERSION == 2
29 unsigned long size1;
30#endif
wdenk04a85b32004-04-15 18:22:41 +000031 int i;
32
33 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020034 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i)
wdenk04a85b32004-04-15 18:22:41 +000035 flash_info[i].flash_id = FLASH_UNKNOWN;
36
37 size = flash_get_size((vu_long *) FLASH_BASE0_PRELIM, &flash_info[0]);
38
39 if (flash_info[0].flash_id == FLASH_UNKNOWN) {
40 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
41 size, size << 20);
42 }
43
44 /* Remap FLASH according to real size */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020045 memctl->memc_or0 = CONFIG_SYS_OR_TIMING_FLASH | (-size & 0xFFFF8000);
46 memctl->memc_br0 = (CONFIG_SYS_FLASH_BASE & BR_BA_MSK) | (memctl->memc_br0 & ~(BR_BA_MSK));
wdenk04a85b32004-04-15 18:22:41 +000047
48 /* Re-do sizing to get full correct info */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020049 size = flash_get_size((vu_long *) CONFIG_SYS_FLASH_BASE, &flash_info[0]);
wdenk04a85b32004-04-15 18:22:41 +000050
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020051 flash_get_offsets(CONFIG_SYS_FLASH_BASE, &flash_info[0]);
wdenk04a85b32004-04-15 18:22:41 +000052
53 /* monitor protection ON by default */
54 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020055 CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
wdenk04a85b32004-04-15 18:22:41 +000056 &flash_info[0]);
57
58 flash_protect ( FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020059 CONFIG_ENV_ADDR,
Wolfgang Denkdfcd7f22009-05-15 00:16:03 +020060 CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
wdenk04a85b32004-04-15 18:22:41 +000061 &flash_info[0]);
62
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020063#ifdef CONFIG_ENV_ADDR_REDUND
wdenk04a85b32004-04-15 18:22:41 +000064 flash_protect ( FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020065 CONFIG_ENV_ADDR_REDUND,
Wolfgang Denkdfcd7f22009-05-15 00:16:03 +020066 CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1,
wdenk04a85b32004-04-15 18:22:41 +000067 &flash_info[0]);
68#endif
69
70 flash_info[0].size = size;
71
wdenkc26e4542004-04-18 10:13:26 +000072#if CONFIG_NETPHONE_VERSION == 2
73 size1 = flash_get_size((vu_long *) FLASH_BASE4_PRELIM, &flash_info[1]);
wdenk79fa88f2004-06-07 23:46:25 +000074 if (size1 > 0) {
75 if (flash_info[1].flash_id == FLASH_UNKNOWN)
76 printf("## Unknown FLASH on Bank 1 - Size = 0x%08lx = %ld MB\n", size1, size1 << 20);
wdenkc26e4542004-04-18 10:13:26 +000077
wdenk79fa88f2004-06-07 23:46:25 +000078 /* Remap FLASH according to real size */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020079 memctl->memc_or4 = CONFIG_SYS_OR_TIMING_FLASH | (-size1 & 0xFFFF8000);
80 memctl->memc_br4 = (CONFIG_SYS_FLASH_BASE4 & BR_BA_MSK) | (memctl->memc_br4 & ~(BR_BA_MSK));
wdenkc26e4542004-04-18 10:13:26 +000081
wdenk79fa88f2004-06-07 23:46:25 +000082 /* Re-do sizing to get full correct info */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020083 size1 = flash_get_size((vu_long *) CONFIG_SYS_FLASH_BASE4, &flash_info[1]);
wdenkc26e4542004-04-18 10:13:26 +000084
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020085 flash_get_offsets(CONFIG_SYS_FLASH_BASE4, &flash_info[1]);
wdenkc26e4542004-04-18 10:13:26 +000086
wdenk79fa88f2004-06-07 23:46:25 +000087 size += size1;
88 } else
89 memctl->memc_br4 &= ~BR_V;
wdenkc26e4542004-04-18 10:13:26 +000090#endif
91
wdenk04a85b32004-04-15 18:22:41 +000092 return (size);
93}
94
95/*-----------------------------------------------------------------------
96 */
97static void flash_get_offsets(ulong base, flash_info_t * info)
98{
99 int i;
100
101 /* set up sector start address table */
102 if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
103 for (i = 0; i < info->sector_count; i++) {
104 info->start[i] = base + (i * 0x00010000);
105 }
106 } else if (info->flash_id & FLASH_BTYPE) {
107 /* set sector offsets for bottom boot block type */
108 info->start[0] = base + 0x00000000;
109 info->start[1] = base + 0x00004000;
110 info->start[2] = base + 0x00006000;
111 info->start[3] = base + 0x00008000;
112 for (i = 4; i < info->sector_count; i++) {
113 info->start[i] = base + (i * 0x00010000) - 0x00030000;
114 }
115 } else {
116 /* set sector offsets for top boot block type */
117 i = info->sector_count - 1;
118 info->start[i--] = base + info->size - 0x00004000;
119 info->start[i--] = base + info->size - 0x00006000;
120 info->start[i--] = base + info->size - 0x00008000;
121 for (; i >= 0; i--) {
122 info->start[i] = base + i * 0x00010000;
123 }
124 }
125}
126
127/*-----------------------------------------------------------------------
128 */
129void flash_print_info(flash_info_t * info)
130{
131 int i;
132
133 if (info->flash_id == FLASH_UNKNOWN) {
134 printf("missing or unknown FLASH type\n");
135 return;
136 }
137
138 switch (info->flash_id & FLASH_VENDMASK) {
139 case FLASH_MAN_AMD:
140 printf("AMD ");
141 break;
142 case FLASH_MAN_FUJ:
143 printf("FUJITSU ");
144 break;
145 case FLASH_MAN_MX:
146 printf("MXIC ");
147 break;
148 default:
149 printf("Unknown Vendor ");
150 break;
151 }
152
153 switch (info->flash_id & FLASH_TYPEMASK) {
154 case FLASH_AM040:
155 printf("AM29LV040B (4 Mbit, bottom boot sect)\n");
156 break;
157 case FLASH_AM400B:
158 printf("AM29LV400B (4 Mbit, bottom boot sect)\n");
159 break;
160 case FLASH_AM400T:
161 printf("AM29LV400T (4 Mbit, top boot sector)\n");
162 break;
163 case FLASH_AM800B:
164 printf("AM29LV800B (8 Mbit, bottom boot sect)\n");
165 break;
166 case FLASH_AM800T:
167 printf("AM29LV800T (8 Mbit, top boot sector)\n");
168 break;
169 case FLASH_AM160B:
170 printf("AM29LV160B (16 Mbit, bottom boot sect)\n");
171 break;
172 case FLASH_AM160T:
173 printf("AM29LV160T (16 Mbit, top boot sector)\n");
174 break;
175 case FLASH_AM320B:
176 printf("AM29LV320B (32 Mbit, bottom boot sect)\n");
177 break;
178 case FLASH_AM320T:
179 printf("AM29LV320T (32 Mbit, top boot sector)\n");
180 break;
181 default:
182 printf("Unknown Chip Type\n");
183 break;
184 }
185
186 printf(" Size: %ld MB in %d Sectors\n", info->size >> 20, info->sector_count);
187
188 printf(" Sector Start Addresses:");
189 for (i = 0; i < info->sector_count; ++i) {
190 if ((i % 5) == 0)
191 printf("\n ");
192 printf(" %08lX%s", info->start[i], info->protect[i] ? " (RO)" : " ");
193 }
194 printf("\n");
195}
196
197/*-----------------------------------------------------------------------
198 */
199
200
201/*-----------------------------------------------------------------------
202 */
203
204/*
205 * The following code cannot be run from FLASH!
206 */
207
208static ulong flash_get_size(vu_long * addr, flash_info_t * info)
209{
210 short i;
211 uchar mid;
212 uchar pid;
213 vu_char *caddr = (vu_char *) addr;
214 ulong base = (ulong) addr;
215
216 /* Write auto select command: read Manufacturer ID */
217 caddr[0x0555] = 0xAA;
218 caddr[0x02AA] = 0x55;
219 caddr[0x0555] = 0x90;
220
221 mid = caddr[0];
222 switch (mid) {
223 case (AMD_MANUFACT & 0xFF):
224 info->flash_id = FLASH_MAN_AMD;
225 break;
226 case (FUJ_MANUFACT & 0xFF):
227 info->flash_id = FLASH_MAN_FUJ;
228 break;
229 case (MX_MANUFACT & 0xFF):
230 info->flash_id = FLASH_MAN_MX;
231 break;
232 case (STM_MANUFACT & 0xFF):
233 info->flash_id = FLASH_MAN_STM;
234 break;
235 default:
236 info->flash_id = FLASH_UNKNOWN;
237 info->sector_count = 0;
238 info->size = 0;
239 return (0); /* no or unknown flash */
240 }
241
242 pid = caddr[1]; /* device ID */
243 switch (pid) {
244 case (AMD_ID_LV400T & 0xFF):
245 info->flash_id += FLASH_AM400T;
246 info->sector_count = 11;
247 info->size = 0x00080000;
248 break; /* => 512 kB */
249
250 case (AMD_ID_LV400B & 0xFF):
251 info->flash_id += FLASH_AM400B;
252 info->sector_count = 11;
253 info->size = 0x00080000;
254 break; /* => 512 kB */
255
256 case (AMD_ID_LV800T & 0xFF):
257 info->flash_id += FLASH_AM800T;
258 info->sector_count = 19;
259 info->size = 0x00100000;
260 break; /* => 1 MB */
261
262 case (AMD_ID_LV800B & 0xFF):
263 info->flash_id += FLASH_AM800B;
264 info->sector_count = 19;
265 info->size = 0x00100000;
266 break; /* => 1 MB */
267
268 case (AMD_ID_LV160T & 0xFF):
269 info->flash_id += FLASH_AM160T;
270 info->sector_count = 35;
271 info->size = 0x00200000;
272 break; /* => 2 MB */
273
274 case (AMD_ID_LV160B & 0xFF):
275 info->flash_id += FLASH_AM160B;
276 info->sector_count = 35;
277 info->size = 0x00200000;
278 break; /* => 2 MB */
279
280 case (AMD_ID_LV040B & 0xFF):
281 info->flash_id += FLASH_AM040;
282 info->sector_count = 8;
283 info->size = 0x00080000;
284 break;
285
286 case (STM_ID_M29W040B & 0xFF):
287 info->flash_id += FLASH_AM040;
288 info->sector_count = 8;
289 info->size = 0x00080000;
290 break;
291
292#if 0 /* enable when device IDs are available */
293 case (AMD_ID_LV320T & 0xFF):
294 info->flash_id += FLASH_AM320T;
295 info->sector_count = 67;
296 info->size = 0x00400000;
297 break; /* => 4 MB */
298
299 case (AMD_ID_LV320B & 0xFF):
300 info->flash_id += FLASH_AM320B;
301 info->sector_count = 67;
302 info->size = 0x00400000;
303 break; /* => 4 MB */
304#endif
305 default:
306 info->flash_id = FLASH_UNKNOWN;
307 return (0); /* => no or unknown flash */
308
309 }
310
311 printf(" ");
312 /* set up sector start address table */
313 if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
314 for (i = 0; i < info->sector_count; i++) {
315 info->start[i] = base + (i * 0x00010000);
316 }
317 } else if (info->flash_id & FLASH_BTYPE) {
318 /* set sector offsets for bottom boot block type */
319 info->start[0] = base + 0x00000000;
320 info->start[1] = base + 0x00004000;
321 info->start[2] = base + 0x00006000;
322 info->start[3] = base + 0x00008000;
323 for (i = 4; i < info->sector_count; i++) {
324 info->start[i] = base + (i * 0x00010000) - 0x00030000;
325 }
326 } else {
327 /* set sector offsets for top boot block type */
328 i = info->sector_count - 1;
329 info->start[i--] = base + info->size - 0x00004000;
330 info->start[i--] = base + info->size - 0x00006000;
331 info->start[i--] = base + info->size - 0x00008000;
332 for (; i >= 0; i--) {
333 info->start[i] = base + i * 0x00010000;
334 }
335 }
336
337 /* check for protected sectors */
338 for (i = 0; i < info->sector_count; i++) {
339 /* read sector protection: D0 = 1 if protected */
340 caddr = (volatile unsigned char *)(info->start[i]);
341 info->protect[i] = caddr[2] & 1;
342 }
343
344 /*
345 * Prevent writes to uninitialized FLASH.
346 */
347 if (info->flash_id != FLASH_UNKNOWN) {
348 caddr = (vu_char *) info->start[0];
349
350 caddr[0x0555] = 0xAA;
351 caddr[0x02AA] = 0x55;
352 caddr[0x0555] = 0xF0;
353
354 udelay(20000);
355 }
356
357 return (info->size);
358}
359
360
361/*-----------------------------------------------------------------------
362 */
363
364int flash_erase(flash_info_t * info, int s_first, int s_last)
365{
366 vu_char *addr = (vu_char *) (info->start[0]);
367 int flag, prot, sect, l_sect;
368 ulong start, now, last;
369
370 if ((s_first < 0) || (s_first > s_last)) {
371 if (info->flash_id == FLASH_UNKNOWN) {
372 printf("- missing\n");
373 } else {
374 printf("- no sectors to erase\n");
375 }
376 return 1;
377 }
378
379 if ((info->flash_id == FLASH_UNKNOWN) ||
380 (info->flash_id > FLASH_AMD_COMP)) {
381 printf("Can't erase unknown flash type %08lx - aborted\n", info->flash_id);
382 return 1;
383 }
384
385 prot = 0;
386 for (sect = s_first; sect <= s_last; ++sect) {
387 if (info->protect[sect]) {
388 prot++;
389 }
390 }
391
392 if (prot) {
393 printf("- Warning: %d protected sectors will not be erased!\n", prot);
394 } else {
395 printf("\n");
396 }
397
398 l_sect = -1;
399
400 /* Disable interrupts which might cause a timeout here */
401 flag = disable_interrupts();
402
403 addr[0x0555] = 0xAA;
404 addr[0x02AA] = 0x55;
405 addr[0x0555] = 0x80;
406 addr[0x0555] = 0xAA;
407 addr[0x02AA] = 0x55;
408
409 /* Start erase on unprotected sectors */
410 for (sect = s_first; sect <= s_last; sect++) {
411 if (info->protect[sect] == 0) { /* not protected */
412 addr = (vu_char *) (info->start[sect]);
413 addr[0] = 0x30;
414 l_sect = sect;
415 }
416 }
417
418 /* re-enable interrupts if necessary */
419 if (flag)
420 enable_interrupts();
421
422 /* wait at least 80us - let's wait 1 ms */
423 udelay(1000);
424
425 /*
426 * We wait for the last triggered sector
427 */
428 if (l_sect < 0)
429 goto DONE;
430
431 start = get_timer(0);
432 last = start;
433 addr = (vu_char *) (info->start[l_sect]);
434 while ((addr[0] & 0x80) != 0x80) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200435 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenk04a85b32004-04-15 18:22:41 +0000436 printf("Timeout\n");
437 return 1;
438 }
439 /* show that we're waiting */
440 if ((now - last) > 1000) { /* every second */
441 putc('.');
442 last = now;
443 }
444 }
445
446DONE:
447 /* reset to read mode */
448 addr = (vu_char *) info->start[0];
449 addr[0] = 0xF0; /* reset bank */
450
451 printf(" done\n");
452 return 0;
453}
454
455/*-----------------------------------------------------------------------
456 * Copy memory to flash, returns:
457 * 0 - OK
458 * 1 - write timeout
459 * 2 - Flash not erased
460 */
461
462int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
463{
464 int rc;
465
466 while (cnt > 0) {
467 if ((rc = write_byte(info, addr++, *src++)) != 0) {
468 return (rc);
469 }
470 --cnt;
471 }
472
473 return (0);
474}
475
476/*-----------------------------------------------------------------------
477 * Write a word to Flash, returns:
478 * 0 - OK
479 * 1 - write timeout
480 * 2 - Flash not erased
481 */
482static int write_byte(flash_info_t * info, ulong dest, uchar data)
483{
484 vu_char *addr = (vu_char *) (info->start[0]);
485 ulong start;
486 int flag;
487
488 /* Check if Flash is (sufficiently) erased */
489 if ((*((vu_char *) dest) & data) != data) {
490 return (2);
491 }
492 /* Disable interrupts which might cause a timeout here */
493 flag = disable_interrupts();
494
495 addr[0x0555] = 0xAA;
496 addr[0x02AA] = 0x55;
497 addr[0x0555] = 0xA0;
498
499 *((vu_char *) dest) = data;
500
501 /* re-enable interrupts if necessary */
502 if (flag)
503 enable_interrupts();
504
505 /* data polling for D7 */
506 start = get_timer(0);
507 while ((*((vu_char *) dest) & 0x80) != (data & 0x80)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200508 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenk04a85b32004-04-15 18:22:41 +0000509 return (1);
510 }
511 }
512 return (0);
513}