blob: 947fbc3aa5e85c124311417d3ace285d68bf0409 [file] [log] [blame]
wdenkfe8c2802002-11-03 00:38:21 +00001/*
2 * (C) Copyright 2001
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * (C) Copyright 2002
6 * Gregory E. Allen, gallen@arlut.utexas.edu
7 * Matthew E. Karger, karger@arlut.utexas.edu
8 * Applied Research Laboratories, The University of Texas at Austin
9 *
10 * See file CREDITS for list of people who contributed to this
11 * project.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of
16 * the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26 * MA 02111-1307 USA
27 */
28
29#include <common.h>
30#include <mpc824x.h>
31#include <asm/processor.h>
32
33#define ROM_CS0_START 0xFF800000
34#define ROM_CS1_START 0xFF000000
35
36#if defined(CFG_ENV_IS_IN_FLASH)
37# ifndef CFG_ENV_ADDR
38# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
39# endif
40# ifndef CFG_ENV_SIZE
41# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
42# endif
43# ifndef CFG_ENV_SECT_SIZE
44# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
45# endif
46#endif
47
48#define FLASH_BANK_SIZE 0x200000
49#define MAIN_SECT_SIZE 0x10000
50#define SECT_SIZE_32KB 0x8000
51#define SECT_SIZE_8KB 0x2000
52
53flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
54
55static int write_word (flash_info_t *info, ulong dest, ulong data);
56
57static __inline__ unsigned long get_msr(void)
58{ unsigned long msr;
59 __asm__ __volatile__ ("mfmsr %0" : "=r" (msr) :);
60 return msr;
61}
62
63static __inline__ void set_msr(unsigned long msr)
64{
65 __asm__ __volatile__ ("mtmsr %0" : : "r" (msr));
66}
67
68/*flash command address offsets*/
69#define ADDR0 (0x555)
70#define ADDR1 (0xAAA)
71#define ADDR3 (0x001)
72
73#define FLASH_WORD_SIZE unsigned char
74
75/*---------------------------------------------------------------------*/
76/*#define DEBUG_FLASH 1 */
77
78/*---------------------------------------------------------------------*/
79
80unsigned long flash_init(void)
81{
82 int i, j;
83 ulong size = 0;
84 unsigned char manuf_id, device_id;
85
86 for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
87 {
88 vu_char *addr = (vu_char *)(CFG_FLASH_BASE + i * FLASH_BANK_SIZE);
89
90 addr[0x555] = 0xAA; /* 3 cycles to read device info. See */
91 addr[0x2AA] = 0x55; /* AM29LV116D datasheet for list of */
92 addr[0x555] = 0x90; /* available commands. */
93
94 manuf_id = addr[0];
95 device_id = addr[1];
96
97#if defined DEBUG_FLASH
98 printf("manuf_id = %x, device_id = %x\n", manuf_id, device_id);
99#endif
100
101 if ( (manuf_id == (uchar)(AMD_MANUFACT)) &&
102 ( device_id == AMD_ID_LV116DT))
103 {
104 flash_info[i].flash_id = ((FLASH_MAN_AMD & FLASH_VENDMASK) << 16) |
105 (AMD_ID_LV116DT & FLASH_TYPEMASK);
106 } else {
107 flash_info[i].flash_id = FLASH_UNKNOWN;
108 addr[0] = (long)0xFFFFFFFF;
109 goto Done;
110 }
111
112#if defined DEBUG_FLASH
113 printf ("flash_id = 0x%08lX\n", flash_info[i].flash_id);
114#endif
115
116 addr[0] = (long)0xFFFFFFFF;
117
118 flash_info[i].size = FLASH_BANK_SIZE;
119 flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
120 memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
121
122 for (j = 0; j < flash_info[i].sector_count; j++)
123 {
124
125 if (j < (CFG_MAX_FLASH_SECT - 3) )
126
127 flash_info[i].start[j] = CFG_FLASH_BASE + i * FLASH_BANK_SIZE +
128 j * MAIN_SECT_SIZE;
129
130 else if (j == (CFG_MAX_FLASH_SECT - 3) )
131
132 flash_info[i].start[j] = flash_info[i].start[j-1] + SECT_SIZE_32KB;
133
134
135 else
136
137 flash_info[i].start[j] = flash_info[i].start[j-1] + SECT_SIZE_8KB;
138
139 }
140
141 size += flash_info[i].size;
142 }
143
144 /* Protect monitor and environment sectors
145 */
146#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
147 flash_protect(FLAG_PROTECT_SET, CFG_MONITOR_BASE,
148 CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, &flash_info[0]);
149#endif
150
151#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
152 flash_protect(FLAG_PROTECT_SET, CFG_ENV_ADDR,
153 CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
154#endif
155
156Done:
157 return size;
158}
159
160/*-----------------------------------------------------------------------
161 */
162void flash_print_info(flash_info_t *info)
163{
164 static const char unk[] = "Unknown";
165 const char *mfct = unk, *type = unk;
166 unsigned int i;
167
168 if(info->flash_id != FLASH_UNKNOWN)
169 {
170 switch(info->flash_id & FLASH_VENDMASK)
171 {
172 case FLASH_MAN_AMD: mfct = "AMD"; break;
173 case FLASH_MAN_FUJ: mfct = "FUJITSU"; break;
174 case FLASH_MAN_STM: mfct = "STM"; break;
175 case FLASH_MAN_SST: mfct = "SST"; break;
176 case FLASH_MAN_BM: mfct = "Bright Microelectonics"; break;
177 case FLASH_MAN_INTEL: mfct = "Intel"; break;
178 }
179
180 switch(info->flash_id & FLASH_TYPEMASK)
181 {
182 case FLASH_AM040: type = "AM29F040B (512K * 8, uniform sector size)"; break;
183 case FLASH_AM400B: type = "AM29LV400B (4 Mbit, bottom boot sect)"; break;
184 case FLASH_AM400T: type = "AM29LV400T (4 Mbit, top boot sector)"; break;
185 case FLASH_AM800B: type = "AM29LV800B (8 Mbit, bottom boot sect)"; break;
186 case FLASH_AM800T: type = "AM29LV800T (8 Mbit, top boot sector)"; break;
187 case FLASH_AM160T: type = "AM29LV160T (16 Mbit, top boot sector)"; break;
188 case FLASH_AM320B: type = "AM29LV320B (32 Mbit, bottom boot sect)"; break;
189 case FLASH_AM320T: type = "AM29LV320T (32 Mbit, top boot sector)"; break;
190 case FLASH_STM800AB: type = "M29W800AB (8 Mbit, bottom boot sect)"; break;
191 case FLASH_SST800A: type = "SST39LF/VF800 (8 Mbit, uniform sector size)"; break;
192 case FLASH_SST160A: type = "SST39LF/VF160 (16 Mbit, uniform sector size)"; break;
193 }
194 }
195
196 printf(
197 "\n Brand: %s Type: %s\n"
198 " Size: %lu KB in %d Sectors\n",
199 mfct,
200 type,
201 info->size >> 10,
202 info->sector_count
203 );
204
205 printf (" Sector Start Addresses:");
206
207 for (i = 0; i < info->sector_count; i++)
208 {
209 unsigned long size;
210 unsigned int erased;
211 unsigned long * flash = (unsigned long *) info->start[i];
212
213 /*
214 * Check if whole sector is erased
215 */
216 size =
217 (i != (info->sector_count - 1)) ?
218 (info->start[i + 1] - info->start[i]) >> 2 :
219 (info->start[0] + info->size - info->start[i]) >> 2;
220
221 for(
222 flash = (unsigned long *) info->start[i], erased = 1;
223 (flash != (unsigned long *) info->start[i] + size) && erased;
224 flash++
225 )
226 erased = *flash == ~0x0UL;
227
228 printf(
229 "%s %08lX %s %s",
230 (i % 5) ? "" : "\n ",
231 info->start[i],
232 erased ? "E" : " ",
233 info->protect[i] ? "RO" : " "
234 );
235 }
236
237 puts("\n");
238 return;
239}
240
241/*-----------------------------------------------------------------------
242 */
243
244int flash_erase (flash_info_t *info, int s_first, int s_last)
245{
246 volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
247 int flag, prot, sect, l_sect;
248 ulong start, now, last;
249 unsigned char sh8b;
250
251 if ((s_first < 0) || (s_first > s_last)) {
252 if (info->flash_id == FLASH_UNKNOWN) {
253 printf ("- missing\n");
254 } else {
255 printf ("- no sectors to erase\n");
256 }
257 return 1;
258 }
259
260 if ((info->flash_id == FLASH_UNKNOWN) ||
261 (info->flash_id > (FLASH_MAN_STM | FLASH_AMD_COMP))) {
262 printf ("Can't erase unknown flash type - aborted\n");
263 return 1;
264 }
265
266 prot = 0;
267 for (sect=s_first; sect<=s_last; ++sect) {
268 if (info->protect[sect]) {
269 prot++;
270 }
271 }
272
273 if (prot) {
274 printf ("- Warning: %d protected sectors will not be erased!\n",
275 prot);
276 } else {
277 printf ("\n");
278 }
279
280 l_sect = -1;
281
282 /* Check the ROM CS */
283 if ((info->start[0] >= ROM_CS1_START) && (info->start[0] < ROM_CS0_START))
284 sh8b = 3;
285 else
286 sh8b = 0;
287
288 /* Disable interrupts which might cause a timeout here */
289 flag = disable_interrupts();
290
291 addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA;
292 addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055;
293 addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00800080;
294 addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA;
295 addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055;
296
297 /* Start erase on unprotected sectors */
298 for (sect = s_first; sect<=s_last; sect++)
299 {
300 if (info->protect[sect] == 0)
301 { /* not protected */
302 addr = (FLASH_WORD_SIZE *)(info->start[0] + (
303 (info->start[sect] - info->start[0]) << sh8b));
304
305 if (info->flash_id & FLASH_MAN_SST)
306 {
307 addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA;
308 addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055;
309 addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00800080;
310 addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA;
311 addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055;
312 addr[0] = (FLASH_WORD_SIZE)0x00500050; /* block erase */
313 udelay(30000); /* wait 30 ms */
314 }
315
316 else
317 addr[0] = (FLASH_WORD_SIZE)0x00300030; /* sector erase */
318
319 l_sect = sect;
320 }
321 }
322
323 /* re-enable interrupts if necessary */
324 if (flag)
325 enable_interrupts();
326
327 /* wait at least 80us - let's wait 1 ms */
328 udelay (1000);
329
330 /*
331 * We wait for the last triggered sector
332 */
333 if (l_sect < 0)
334 goto DONE;
335
336 start = get_timer (0);
337 last = start;
338 addr = (FLASH_WORD_SIZE *)(info->start[0] + (
339 (info->start[l_sect] - info->start[0]) << sh8b));
340 while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
341 if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
342 printf ("Timeout\n");
343 return 1;
344 }
345 /* show that we're waiting */
346 if ((now - last) > 1000) { /* every second */
347 serial_putc ('.');
348 last = now;
349 }
350 }
351
352DONE:
353 /* reset to read mode */
354 addr = (FLASH_WORD_SIZE *)info->start[0];
355 addr[0] = (FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
356
357 printf (" done\n");
358 return 0;
359}
360
361
362/*-----------------------------------------------------------------------
363 * Copy memory to flash, returns:
364 * 0 - OK
365 * 1 - write timeout
366 * 2 - Flash not erased
367 */
368
369int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
370{
371 ulong cp, wp, data;
372 int i, l, rc;
373
374 wp = (addr & ~3); /* get lower word aligned address */
375
376 /*
377 * handle unaligned start bytes
378 */
379 if ((l = addr - wp) != 0) {
380 data = 0;
381 for (i=0, cp=wp; i<l; ++i, ++cp) {
382 data = (data << 8) | (*(uchar *)cp);
383 }
384 for (; i<4 && cnt>0; ++i) {
385 data = (data << 8) | *src++;
386 --cnt;
387 ++cp;
388 }
389 for (; cnt==0 && i<4; ++i, ++cp) {
390 data = (data << 8) | (*(uchar *)cp);
391 }
392
393 if ((rc = write_word(info, wp, data)) != 0) {
394 return (rc);
395 }
396 wp += 4;
397 }
398
399 /*
400 * handle word aligned part
401 */
402 while (cnt >= 4) {
403 data = 0;
404 for (i=0; i<4; ++i) {
405 data = (data << 8) | *src++;
406 }
407 if ((rc = write_word(info, wp, data)) != 0) {
408 return (rc);
409 }
410 wp += 4;
411 cnt -= 4;
412 }
413
414 if (cnt == 0) {
415 return (0);
416 }
417
418 /*
419 * handle unaligned tail bytes
420 */
421 data = 0;
422 for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
423 data = (data << 8) | *src++;
424 --cnt;
425 }
426 for (; i<4; ++i, ++cp) {
427 data = (data << 8) | (*(uchar *)cp);
428 }
429
430 return (write_word(info, wp, data));
431}
432
433
434/*-----------------------------------------------------------------------
435 * Write a word to Flash, returns:
436 * 0 - OK
437 * 1 - write timeout
438 * 2 - Flash not erased
439 */
440static int write_word (flash_info_t *info, ulong dest, ulong data)
441{
442 volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)info->start[0];
443 volatile FLASH_WORD_SIZE *dest2;
444 volatile FLASH_WORD_SIZE *data2 = (FLASH_WORD_SIZE *)&data;
445 ulong start;
446 int flag;
447 int i;
448 unsigned char sh8b;
449
450 /* Check the ROM CS */
451 if ((info->start[0] >= ROM_CS1_START) && (info->start[0] < ROM_CS0_START))
452 sh8b = 3;
453 else
454 sh8b = 0;
455
456 dest2 = (FLASH_WORD_SIZE *)(((dest - info->start[0]) << sh8b) +
457 info->start[0]);
458
459 /* Check if Flash is (sufficiently) erased */
460 if ((*dest2 & (FLASH_WORD_SIZE)data) != (FLASH_WORD_SIZE)data) {
461 return (2);
462 }
463 /* Disable interrupts which might cause a timeout here */
464 flag = disable_interrupts();
465
466 for (i=0; i<4/sizeof(FLASH_WORD_SIZE); i++)
467 {
468 addr2[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA;
469 addr2[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055;
470 addr2[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00A000A0;
471
472 dest2[i << sh8b] = data2[i];
473
474 /* re-enable interrupts if necessary */
475 if (flag)
476 enable_interrupts();
477
478 /* data polling for D7 */
479 start = get_timer (0);
480 while ((dest2[i << sh8b] & (FLASH_WORD_SIZE)0x00800080) !=
481 (data2[i] & (FLASH_WORD_SIZE)0x00800080)) {
482 if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
483 return (1);
484 }
485 }
486 }
487
488 return (0);
489}
490/*-----------------------------------------------------------------------
491 */