blob: 0f827df06da2aa6a55b84682f79c2029c357bed6 [file] [log] [blame]
wdenkdb2f721f2003-03-06 00:58:30 +00001/*
2 * (C) Copyright 2003
3 * EMK Elektronik GmbH <www.emk-elektronik.de>
4 * Reinhard Meyer <r.meyer@emk-elektronik.de>
wdenk8bde7f72003-06-27 21:31:46 +00005 *
6 * copied from the BMW Port - seems that its similiar enough
7 * to be easily adaped ;) --- Well, it turned out to become a
8 * merger between parts of the EMKstax Flash routines and the
9 * BMW funtion frames...
wdenkdb2f721f2003-03-06 00:58:30 +000010 *
11 * (C) Copyright 2000
12 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
13 *
14 * See file CREDITS for list of people who contributed to this
15 * project.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30 * MA 02111-1307 USA
31 */
32
33#include <common.h>
34#include <mpc8xx.h>
35
36#define FLASH_WORD_SIZE unsigned short
wdenk8bde7f72003-06-27 21:31:46 +000037#define FLASH_WORD_WIDTH (sizeof (FLASH_WORD_SIZE))
38
wdenkdb2f721f2003-03-06 00:58:30 +000039flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenk8bde7f72003-06-27 21:31:46 +000040
wdenkdb2f721f2003-03-06 00:58:30 +000041/*-----------------------------------------------------------------------
42 * Functions
43 */
44static int write_word (flash_info_t *info, ulong dest, ulong data);
45
46
wdenk8bde7f72003-06-27 21:31:46 +000047/*****************************************************************************
48 * software product ID entry/exit
49 *****************************************************************************/
50static void FlashProductIdMode (
51 volatile FLASH_WORD_SIZE *b,
52 int on_off)
53{
54 b[0x5555] = 0xaa;
55 b[0x2aaa] = 0x55;
56 b[0x5555] = on_off ? 0x90 : 0xf0;
57}
58
59/*****************************************************************************
60 * sector erase start
61 *****************************************************************************/
62static void FlashSectorErase (
63 volatile FLASH_WORD_SIZE *b,
64 volatile FLASH_WORD_SIZE *a)
65{
66 b[0x5555] = 0xaa;
67 b[0x2aaa] = 0x55;
68 b[0x5555] = 0x80;
69 b[0x5555] = 0xaa;
70 b[0x2aaa] = 0x55;
71 a[0] = 0x30;
72}
73
74/*****************************************************************************
75 * program a word
76 *****************************************************************************/
77static void FlashProgWord (
78 volatile FLASH_WORD_SIZE *b,
79 volatile FLASH_WORD_SIZE *a,
80 FLASH_WORD_SIZE v)
81{
82 b[0x5555] = 0xaa;
83 b[0x2aaa] = 0x55;
84 b[0x5555] = 0xa0;
85 a[0] = v;
86}
87
88/*****************************************************************************
89 * reset bank, back to read mode
90 *****************************************************************************/
91static void FlashReset (volatile FLASH_WORD_SIZE *b)
92{
93 b[0] = 0xf0;
94}
95
96/*****************************************************************************
97 * identify FLASH chip
98 * this code is a stripped version of the FlashGetType() function in EMKstax
99 *****************************************************************************/
wdenkdb2f721f2003-03-06 00:58:30 +0000100unsigned long flash_init (void)
wdenk8bde7f72003-06-27 21:31:46 +0000101{
102 volatile FLASH_WORD_SIZE * const flash = (volatile FLASH_WORD_SIZE *) CFG_FLASH_BASE;
103 FLASH_WORD_SIZE manu, dev;
104 flash_info_t * const pflinfo = &flash_info[0];
105 int j;
106
107 /* get Id Bytes */
108 FlashProductIdMode (flash, 1);
109 manu = flash[0];
110 dev = flash[1];
111 FlashProductIdMode (flash, 0);
112
113 pflinfo->size = 0;
114 pflinfo->sector_count = 0;
115 pflinfo->flash_id = 0xffffffff;
116 pflinfo->portwidth = FLASH_CFI_16BIT;
117 pflinfo->chipwidth = FLASH_CFI_BY16;
118
119 switch (manu&0xff)
120 {
121 case 0x01: /* AMD */
122 pflinfo->flash_id = FLASH_MAN_AMD;
123 switch (dev&0xff)
124 {
125 case 0x49:
126 pflinfo->size = 0x00200000;
127 pflinfo->sector_count = 35;
128 pflinfo->flash_id |= FLASH_AM160B;
129 pflinfo->start[0] = CFG_FLASH_BASE;
130 pflinfo->start[1] = CFG_FLASH_BASE + 0x4000;
131 pflinfo->start[2] = CFG_FLASH_BASE + 0x6000;
132 pflinfo->start[3] = CFG_FLASH_BASE + 0x8000;
133 for (j = 4; j < 35; j++)
134 {
135 pflinfo->start[j] = CFG_FLASH_BASE + 0x00010000 * (j-3);
136 }
137 break;
138
139 case 0xf9:
140 pflinfo->size = 0x00400000;
141 pflinfo->sector_count = 71;
142 pflinfo->flash_id |= FLASH_AM320B;
143 pflinfo->start[0] = CFG_FLASH_BASE;
144 pflinfo->start[1] = CFG_FLASH_BASE + 0x4000;
145 pflinfo->start[2] = CFG_FLASH_BASE + 0x6000;
146 pflinfo->start[3] = CFG_FLASH_BASE + 0x8000;
147 for (j = 0; j < 8; j++)
148 {
149 pflinfo->start[j] = CFG_FLASH_BASE + 0x00002000 * (j);
150 }
151 for (j = 8; j < 71; j++)
152 {
153 pflinfo->start[j] = CFG_FLASH_BASE + 0x00010000 * (j-7);
154 }
155 break;
156
157 default:
158 printf ("unknown AMD dev=%x ", dev);
159 pflinfo->flash_id |= FLASH_UNKNOWN;
160 }
161 break;
162
163 default:
164 printf ("unknown manu=%x ", manu);
165 }
166 return pflinfo->size;
wdenkdb2f721f2003-03-06 00:58:30 +0000167}
168
wdenk8bde7f72003-06-27 21:31:46 +0000169/*****************************************************************************
170 * print info about a FLASH
171 *****************************************************************************/
wdenkdb2f721f2003-03-06 00:58:30 +0000172void flash_print_info (flash_info_t *info)
wdenk8bde7f72003-06-27 21:31:46 +0000173{
174 static const char unk[] = "Unknown";
175 unsigned int i;
176 const char *mfct=unk,
177 *type=unk;
178
179 if(info->flash_id != FLASH_UNKNOWN)
180 {
181 switch (info->flash_id & FLASH_VENDMASK)
182 {
183 case FLASH_MAN_AMD:
184 mfct = "AMD";
185 break;
186 }
187
188 switch (info->flash_id & FLASH_TYPEMASK)
189 {
190 case FLASH_AM160B:
191 type = "AM29LV160B (16 Mbit, bottom boot sect)";
192 break;
193 case FLASH_AM320B:
194 type = "AM29LV320B (32 Mbit, bottom boot sect)";
195 break;
196 }
197 }
198
199 printf (
200 "\n Brand: %s Type: %s\n"
201 " Size: %lu KB in %d Sectors\n",
202 mfct,
203 type,
204 info->size >> 10,
205 info->sector_count
206 );
207
208 printf (" Sector Start Addresses:");
209
210 for (i = 0; i < info->sector_count; i++)
211 {
212 unsigned long size;
213 unsigned int erased;
214 unsigned long *flash = (unsigned long *) info->start[i];
215
216 /*
217 * Check if whole sector is erased
218 */
219 size =
220 (i != (info->sector_count - 1)) ?
221 (info->start[i + 1] - info->start[i]) >> 2 :
222 (info->start[0] + info->size - info->start[i]) >> 2;
223
224 for (
225 flash = (unsigned long *) info->start[i], erased = 1;
226 (flash != (unsigned long *) info->start[i] + size) && erased;
227 flash++
228 )
229 erased = *flash == ~0x0UL;
230
231 printf (
232 "%s %08lX %s %s",
233 (i % 5) ? "" : "\n ",
234 info->start[i],
235 erased ? "E" : " ",
236 info->protect[i] ? "RO" : " "
237 );
238 }
239
240 puts ("\n");
241 return;
wdenkdb2f721f2003-03-06 00:58:30 +0000242}
243
wdenk8bde7f72003-06-27 21:31:46 +0000244/*****************************************************************************
245 * erase one or more sectors
246 *****************************************************************************/
wdenkdb2f721f2003-03-06 00:58:30 +0000247int flash_erase (flash_info_t *info, int s_first, int s_last)
wdenk8bde7f72003-06-27 21:31:46 +0000248{
249 volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
250 int flag,
251 prot,
252 sect,
253 l_sect;
254 ulong start,
255 now,
256 last;
257
258 if ((s_first < 0) || (s_first > s_last))
259 {
260 if (info->flash_id == FLASH_UNKNOWN)
261 {
262 printf ("- missing\n");
263 }
264 else
265 {
266 printf ("- no sectors to erase\n");
267 }
268 return 1;
269 }
270
271 if ((info->flash_id == FLASH_UNKNOWN) ||
272 (info->flash_id > (FLASH_MAN_STM | FLASH_AMD_COMP)))
273 {
274 printf ("Can't erase unknown flash type - aborted\n");
275 return 1;
276 }
277
278 prot = 0;
279 for (sect=s_first; sect<=s_last; ++sect)
280 {
281 if (info->protect[sect])
282 {
283 prot++;
284 }
285 }
286
287 if (prot)
288 {
289 printf ("- Warning: %d protected sectors will not be erased!\n",
290 prot);
291 }
292 else
293 {
294 printf ("\n");
295 }
296
297 l_sect = -1;
298
299 /* Disable interrupts which might cause a timeout here */
300 flag = disable_interrupts();
301
302 /* Start erase on unprotected sectors */
303 for (sect = s_first; sect<=s_last; sect++)
304 {
305 if (info->protect[sect] == 0)
306 { /* not protected */
307 FlashSectorErase ((FLASH_WORD_SIZE *)info->start[0], (FLASH_WORD_SIZE *)info->start[sect]);
308 l_sect = sect;
309 }
310 }
311
312 /* re-enable interrupts if necessary */
313 if (flag)
314 enable_interrupts();
315
316 /* wait at least 80us - let's wait 1 ms */
317 udelay (1000);
318
319 /*
320 * We wait for the last triggered sector
321 */
322 if (l_sect < 0)
323 goto DONE;
324
325 start = get_timer (0);
326 last = start;
327 addr = (FLASH_WORD_SIZE *)info->start[l_sect];
328 while ((addr[0] & 0x0080) != 0x0080)
329 {
330 if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT)
331 {
332 printf ("Timeout\n");
333 return 1;
334 }
335 /* show that we're waiting */
336 if ((now - last) > 1000)
337 { /* every second */
338 serial_putc ('.');
339 last = now;
340 }
341 }
342
343 DONE:
344 /* reset to read mode */
345 FlashReset ((FLASH_WORD_SIZE *)info->start[0]);
346
347 printf (" done\n");
348 return 0;
wdenkdb2f721f2003-03-06 00:58:30 +0000349}
350
wdenk8bde7f72003-06-27 21:31:46 +0000351/*****************************************************************************
wdenkdb2f721f2003-03-06 00:58:30 +0000352 * Copy memory to flash, returns:
353 * 0 - OK
354 * 1 - write timeout
355 * 2 - Flash not erased
wdenk8bde7f72003-06-27 21:31:46 +0000356 *****************************************************************************/
wdenkdb2f721f2003-03-06 00:58:30 +0000357int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
wdenk8bde7f72003-06-27 21:31:46 +0000358{
359 ulong cp,
360 wp,
361 data;
362 int i,
363 l,
364 rc;
365
366 wp = (addr & ~(FLASH_WORD_WIDTH-1)); /* get lower word aligned address */
367
368 /*
369 * handle unaligned start bytes, if there are...
370 */
371 if ((l = addr - wp) != 0)
372 {
373 data = 0;
374
375 /* get the current before the new data into our data word */
376 for (i=0, cp=wp; i<l; ++i, ++cp)
377 {
378 data = (data << 8) | (*(uchar *)cp);
379 }
380
381 /* now merge the to be programmed values */
382 for (; i<4 && cnt>0; ++i, ++cp, --cnt)
383 {
384 data = (data << 8) | *src++;
385 }
386
387 /* get the current after the new data into our data word */
388 for (; cnt==0 && i<FLASH_WORD_WIDTH; ++i, ++cp)
389 {
390 data = (data << 8) | (*(uchar *)cp);
391 }
392
393 /* now write the combined word */
394 if ((rc = write_word (info, wp, data)) != 0)
395 {
396 return (rc);
397 }
398 wp += FLASH_WORD_WIDTH;
399 }
400
401 /*
402 * handle word aligned part
403 */
404 while (cnt >= FLASH_WORD_WIDTH)
405 {
406 data = 0;
407 for (i=0; i<FLASH_WORD_WIDTH; ++i)
408 {
409 data = (data << 8) | *src++;
410 }
411 if ((rc = write_word (info, wp, data)) != 0)
412 {
413 return (rc);
414 }
415 wp += FLASH_WORD_WIDTH;
416 cnt -= FLASH_WORD_WIDTH;
417 }
418
419 if (cnt == 0)
420 {
421 return (0);
422 }
423
424 /*
425 * handle unaligned tail bytes, if there are...
426 */
427 data = 0;
428
429 /* now merge the to be programmed values */
430 for (i=0, cp=wp; i<FLASH_WORD_WIDTH && cnt>0; ++i, ++cp)
431 {
432 data = (data << 8) | *src++;
433 --cnt;
434 }
435
436 /* get the current after the new data into our data word */
437 for (; i<FLASH_WORD_WIDTH; ++i, ++cp)
438 {
439 data = (data << 8) | (*(uchar *)cp);
440 }
441
442 /* now write the combined word */
443 return (write_word (info, wp, data));
wdenkdb2f721f2003-03-06 00:58:30 +0000444}
445
wdenk8bde7f72003-06-27 21:31:46 +0000446/*****************************************************************************
wdenkdb2f721f2003-03-06 00:58:30 +0000447 * Write a word to Flash, returns:
448 * 0 - OK
449 * 1 - write timeout
450 * 2 - Flash not erased
wdenk8bde7f72003-06-27 21:31:46 +0000451 *****************************************************************************/
wdenkdb2f721f2003-03-06 00:58:30 +0000452static int write_word (flash_info_t *info, ulong dest, ulong data)
wdenk8bde7f72003-06-27 21:31:46 +0000453{
454 volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)info->start[0];
455 volatile FLASH_WORD_SIZE *dest2 = (FLASH_WORD_SIZE *)dest;
456 FLASH_WORD_SIZE data2 = data;
457 ulong start;
458 int flag;
459
460 /* Check if Flash is (sufficiently) erased */
461 if ((*dest2 & data2) != data2)
462 {
463 return (2);
464 }
465
466 /* Disable interrupts which might cause a timeout here */
467 flag = disable_interrupts ();
468
469 FlashProgWord (addr2, dest2, data2);
470
471 /* re-enable interrupts if necessary */
472 if (flag)
473 enable_interrupts ();
474
475 /* data polling for D7 */
476 start = get_timer (0);
477 while ((*dest2 & 0x0080) != (data2 & 0x0080))
478 {
479 if (get_timer (start) > CFG_FLASH_WRITE_TOUT)
480 {
481 return (1);
482 }
483 }
484
485 return (0);
wdenkdb2f721f2003-03-06 00:58:30 +0000486}
487
488/*-----------------------------------------------------------------------
489 */