]> git.ipfire.org Git - people/ms/u-boot.git/blame - board/siemens/IAD210/flash.c
rename CFG_ macros to CONFIG_SYS
[people/ms/u-boot.git] / board / siemens / IAD210 / flash.c
CommitLineData
affae2bf
WD
1/*
2 * (C) Copyright 2000, 2001, 2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
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#include <common.h>
25#include <mpc8xx.h>
26
6d0f6bcf 27flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
affae2bf
WD
28
29/*-----------------------------------------------------------------------
30 * Functions
31 */
32static ulong flash_get_size (vu_long *addr, flash_info_t *info);
33static int write_word (flash_info_t *info, ulong dest, ulong data);
34static void flash_get_offsets (ulong base, flash_info_t *info);
35
36/*-----------------------------------------------------------------------
37 */
38
39unsigned long flash_init (void)
40{
6d0f6bcf 41 volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
affae2bf
WD
42 volatile memctl8xx_t *memctl = &immap->im_memctl;
43 unsigned long size;
44 int i;
45
46 /* Init: no FLASHes known */
6d0f6bcf 47 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
affae2bf
WD
48 flash_info[i].flash_id = FLASH_UNKNOWN;
49 }
50
51 /* Static FLASH Bank configuration here - FIXME XXX */
52
53 size = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
54
55 if (flash_info[0].flash_id == FLASH_UNKNOWN) {
56 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
57 size, size<<20);
58 }
59
60
61 /* Remap FLASH according to real size */
6d0f6bcf
JCPV
62 memctl->memc_or0 = CONFIG_SYS_OR_TIMING_FLASH | (-size & 0xFFFF8000);
63 memctl->memc_br0 = (CONFIG_SYS_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
affae2bf
WD
64
65 /* Re-do sizing to get full correct info */
6d0f6bcf 66 size = flash_get_size((vu_long *)CONFIG_SYS_FLASH_BASE, &flash_info[0]);
affae2bf 67
6d0f6bcf 68 flash_get_offsets (CONFIG_SYS_FLASH_BASE, &flash_info[0]);
affae2bf
WD
69
70 flash_info[0].size = size;
71
72 return (size);
73}
74
75/*-----------------------------------------------------------------------
76 */
77static void flash_get_offsets (ulong base, flash_info_t *info)
78{
79 int i;
80
81 /* set up sector start address table */
82 if (info->flash_id & FLASH_BTYPE) {
83 /* set sector offsets for bottom boot block type */
84 info->start[0] = base + 0x00000000;
85 info->start[1] = base + 0x00008000;
86 info->start[2] = base + 0x0000C000;
87 info->start[3] = base + 0x00010000;
88 for (i = 4; i < info->sector_count; i++) {
89 info->start[i] = base + (i * 0x00020000) - 0x00060000;
90 }
91 } else {
92 /* set sector offsets for top boot block type */
93 i = info->sector_count - 1;
94 info->start[i--] = base + info->size - 0x00008000;
95 info->start[i--] = base + info->size - 0x0000C000;
96 info->start[i--] = base + info->size - 0x00010000;
97 for (; i >= 0; i--) {
98 info->start[i] = base + i * 0x00020000;
99 }
100 }
101
102}
103
104/*-----------------------------------------------------------------------
105 */
106void flash_print_info (flash_info_t *info)
107{
108 int i;
109
110 if (info->flash_id == FLASH_UNKNOWN) {
111 printf ("missing or unknown FLASH type\n");
112 return;
113 }
114
115 switch (info->flash_id & FLASH_VENDMASK) {
116 case FLASH_MAN_AMD: printf ("AMD "); break;
117 case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
118 default: printf ("Unknown Vendor "); break;
119 }
120
121 switch (info->flash_id & FLASH_TYPEMASK) {
122 case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
123 break;
124 case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
125 break;
126 case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
127 break;
128 case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
129 break;
130 case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
131 break;
132 case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
133 break;
134 case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
135 break;
136 case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
137 break;
138 default: printf ("Unknown Chip Type\n");
139 break;
140 }
141
142 printf (" Size: %ld MB in %d Sectors\n",
8bde7f77 143 info->size >> 20, info->sector_count);
affae2bf
WD
144
145 printf (" Sector Start Addresses:");
146 for (i=0; i<info->sector_count; ++i) {
147 if ((i % 5) == 0)
148 printf ("\n ");
149 printf (" %08lX%s",
150 info->start[i],
151 info->protect[i] ? " (RO)" : " "
8bde7f77 152 );
affae2bf
WD
153 }
154 printf ("\n");
155}
156
157/*-----------------------------------------------------------------------
158 */
159
160
161/*-----------------------------------------------------------------------
162 */
163
164/*
165 * The following code cannot be run from FLASH!
166 */
167
168static ulong flash_get_size (vu_long *addr, flash_info_t *info)
169{
170 short i;
171 ulong value;
172 ulong base = (ulong)addr;
173
174
175 /* Write auto select command: read Manufacturer ID */
176 addr[0x0555] = 0x00AA00AA;
177 addr[0x02AA] = 0x00550055;
178 addr[0x0555] = 0x00900090;
179
180 value = addr[0];
181
182 switch (value) {
183 case AMD_MANUFACT:
184 info->flash_id = FLASH_MAN_AMD;
185 break;
186 case FUJ_MANUFACT:
187 info->flash_id = FLASH_MAN_FUJ;
188 break;
189 default:
190 info->flash_id = FLASH_UNKNOWN;
191 info->sector_count = 0;
192 info->size = 0;
193 return (0); /* no or unknown flash */
194 }
195
196 value = addr[1]; /* device ID */
197
198 switch (value) {
199 case AMD_ID_LV400T:
200 info->flash_id += FLASH_AM400T;
201 info->sector_count = 11;
202 info->size = 0x00100000;
203 break; /* => 1 MB */
204
205 case AMD_ID_LV400B:
206 info->flash_id += FLASH_AM400B;
207 info->sector_count = 11;
208 info->size = 0x00100000;
209 break; /* => 1 MB */
210
211 case AMD_ID_LV800T:
212 info->flash_id += FLASH_AM800T;
213 info->sector_count = 19;
214 info->size = 0x00200000;
215 break; /* => 2 MB */
216
217 case AMD_ID_LV800B:
218 info->flash_id += FLASH_AM800B;
219 info->sector_count = 19;
220 info->size = 0x00200000;
221 break; /* => 2 MB */
222
223 case AMD_ID_LV160T:
224 info->flash_id += FLASH_AM160T;
225 info->sector_count = 35;
226 info->size = 0x00400000;
227 break; /* => 4 MB */
228
229 case AMD_ID_LV160B:
230 info->flash_id += FLASH_AM160B;
231 info->sector_count = 35;
232 info->size = 0x00400000;
233 break; /* => 4 MB */
234#if 0 /* enable when device IDs are available */
235 case AMD_ID_LV320T:
236 info->flash_id += FLASH_AM320T;
237 info->sector_count = 67;
238 info->size = 0x00800000;
239 break; /* => 8 MB */
240
241 case AMD_ID_LV320B:
242 info->flash_id += FLASH_AM320B;
243 info->sector_count = 67;
244 info->size = 0x00800000;
245 break; /* => 8 MB */
246#endif
247 default:
248 info->flash_id = FLASH_UNKNOWN;
249 return (0); /* => no or unknown flash */
250
251 }
252
253 /* set up sector start address table */
254 if (info->flash_id & FLASH_BTYPE) {
255 /* set sector offsets for bottom boot block type */
256 info->start[0] = base + 0x00000000;
257 info->start[1] = base + 0x00008000;
258 info->start[2] = base + 0x0000C000;
259 info->start[3] = base + 0x00010000;
260 for (i = 4; i < info->sector_count; i++) {
261 info->start[i] = base + (i * 0x00020000) - 0x00060000;
262 }
263 } else {
264 /* set sector offsets for top boot block type */
265 i = info->sector_count - 1;
266 info->start[i--] = base + info->size - 0x00008000;
267 info->start[i--] = base + info->size - 0x0000C000;
268 info->start[i--] = base + info->size - 0x00010000;
269 for (; i >= 0; i--) {
270 info->start[i] = base + i * 0x00020000;
271 }
272 }
273
274 /* check for protected sectors */
275 for (i = 0; i < info->sector_count; i++) {
276 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
277 /* D0 = 1 if protected */
278 addr = (volatile unsigned long *)(info->start[i]);
279 info->protect[i] = addr[2] & 1;
280 }
281
282 /*
283 * Prevent writes to uninitialized FLASH.
284 */
285 if (info->flash_id != FLASH_UNKNOWN) {
286 addr = (volatile unsigned long *)info->start[0];
287
288 *addr = 0x00F000F0; /* reset bank */
289 }
290
291 return (info->size);
292}
293
294
295/*-----------------------------------------------------------------------
296 */
297
298int flash_erase (flash_info_t *info, int s_first, int s_last)
299{
300 vu_long *addr = (vu_long*)(info->start[0]);
301 int flag, prot, sect, l_sect;
302 ulong start, now, last;
303
304 if ((s_first < 0) || (s_first > s_last)) {
305 if (info->flash_id == FLASH_UNKNOWN) {
306 printf ("- missing\n");
307 } else {
308 printf ("- no sectors to erase\n");
309 }
310 return 1;
311 }
312
313 if ((info->flash_id == FLASH_UNKNOWN) ||
314 (info->flash_id > FLASH_AMD_COMP)) {
315 printf ("Can't erase unknown flash type %08lx - aborted\n",
316 info->flash_id);
317 return 1;
318 }
319
320 prot = 0;
321 for (sect=s_first; sect<=s_last; ++sect) {
322 if (info->protect[sect]) {
323 prot++;
324 }
325 }
326
327 if (prot) {
328 printf ("- Warning: %d protected sectors will not be erased!\n",
329 prot);
330 } else {
331 printf ("\n");
332 }
333
334 l_sect = -1;
335
336 /* Disable interrupts which might cause a timeout here */
337 flag = disable_interrupts();
338
339 addr[0x0555] = 0x00AA00AA;
340 addr[0x02AA] = 0x00550055;
341 addr[0x0555] = 0x00800080;
342 addr[0x0555] = 0x00AA00AA;
343 addr[0x02AA] = 0x00550055;
344
345 /* Start erase on unprotected sectors */
346 for (sect = s_first; sect<=s_last; sect++) {
347 if (info->protect[sect] == 0) { /* not protected */
348 addr = (vu_long*)(info->start[sect]);
349 addr[0] = 0x00300030;
350 l_sect = sect;
351 }
352 }
353
354 /* re-enable interrupts if necessary */
355 if (flag)
356 enable_interrupts();
357
358 /* wait at least 80us - let's wait 1 ms */
359 udelay (1000);
360
361 /*
362 * We wait for the last triggered sector
363 */
364 if (l_sect < 0)
365 goto DONE;
366
367 start = get_timer (0);
368 last = start;
369 addr = (vu_long*)(info->start[l_sect]);
370 while ((addr[0] & 0x00800080) != 0x00800080) {
6d0f6bcf 371 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
affae2bf
WD
372 printf ("Timeout\n");
373 return 1;
374 }
375 /* show that we're waiting */
376 if ((now - last) > 1000) { /* every second */
377 putc ('.');
378 last = now;
379 }
380 }
381
382 DONE:
383 /* reset to read mode */
384 addr = (volatile unsigned long *)info->start[0];
385 addr[0] = 0x00F000F0; /* reset bank */
386
387 printf (" done\n");
388 return 0;
389}
390
391/*-----------------------------------------------------------------------
392 * Copy memory to flash, returns:
393 * 0 - OK
394 * 1 - write timeout
395 * 2 - Flash not erased
396 */
397
398int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
399{
400 ulong cp, wp, data;
401 int i, l, rc;
402
403 wp = (addr & ~3); /* get lower word aligned address */
404
405 /*
406 * handle unaligned start bytes
407 */
408 if ((l = addr - wp) != 0) {
409 data = 0;
410 for (i=0, cp=wp; i<l; ++i, ++cp) {
411 data = (data << 8) | (*(uchar *)cp);
412 }
413 for (; i<4 && cnt>0; ++i) {
414 data = (data << 8) | *src++;
415 --cnt;
416 ++cp;
417 }
418 for (; cnt==0 && i<4; ++i, ++cp) {
419 data = (data << 8) | (*(uchar *)cp);
420 }
421
422 if ((rc = write_word(info, wp, data)) != 0) {
423 return (rc);
424 }
425 wp += 4;
426 }
427
428 /*
429 * handle word aligned part
430 */
431 while (cnt >= 4) {
432 data = 0;
433 for (i=0; i<4; ++i) {
434 data = (data << 8) | *src++;
435 }
436 if ((rc = write_word(info, wp, data)) != 0) {
437 return (rc);
438 }
439 wp += 4;
440 cnt -= 4;
441 }
442
443 if (cnt == 0) {
444 return (0);
445 }
446
447 /*
448 * handle unaligned tail bytes
449 */
450 data = 0;
451 for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
452 data = (data << 8) | *src++;
453 --cnt;
454 }
455 for (; i<4; ++i, ++cp) {
456 data = (data << 8) | (*(uchar *)cp);
457 }
458
459 return (write_word(info, wp, data));
460}
461
462/*-----------------------------------------------------------------------
463 * Write a word to Flash, returns:
464 * 0 - OK
465 * 1 - write timeout
466 * 2 - Flash not erased
467 */
468static int write_word (flash_info_t *info, ulong dest, ulong data)
469{
470 vu_long *addr = (vu_long*)(info->start[0]);
471 ulong start;
472 int flag;
473
474 /* Check if Flash is (sufficiently) erased */
475 if ((*((vu_long *)dest) & data) != data) {
476 return (2);
477 }
478 /* Disable interrupts which might cause a timeout here */
479 flag = disable_interrupts();
480
481 addr[0x0555] = 0x00AA00AA;
482 addr[0x02AA] = 0x00550055;
483 addr[0x0555] = 0x00A000A0;
484
485 *((vu_long *)dest) = data;
486
487 /* re-enable interrupts if necessary */
488 if (flag)
489 enable_interrupts();
490
491 /* data polling for D7 */
492 start = get_timer (0);
493 while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
6d0f6bcf 494 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
affae2bf
WD
495 return (1);
496 }
497 }
498 return (0);
499}
500
501/*-----------------------------------------------------------------------
502 */