3 * EMK Elektronik GmbH <www.emk-elektronik.de>
4 * Reinhard Meyer <r.meyer@emk-elektronik.de>
6 * copied from the BMW Port - seems that its similiar enough
\r
7 * to be easily adaped ;) --- Well, it turned out to become a
\r
8 * merger between parts of the EMKstax Flash routines and the
\r
9 * BMW funtion frames...
\r
12 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
14 * See file CREDITS for list of people who contributed to this
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.
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.
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,
36 #define FLASH_WORD_SIZE unsigned short
37 #define FLASH_WORD_WIDTH (sizeof (FLASH_WORD_SIZE))
\r
39 flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
41 /*-----------------------------------------------------------------------
44 static int write_word (flash_info_t *info, ulong dest, ulong data);
47 /*****************************************************************************
\r
48 * software product ID entry/exit
\r
49 *****************************************************************************/
\r
50 static void FlashProductIdMode (
\r
51 volatile FLASH_WORD_SIZE *b,
\r
56 b[0x5555] = on_off ? 0x90 : 0xf0;
\r
59 /*****************************************************************************
\r
60 * sector erase start
\r
61 *****************************************************************************/
\r
62 static void FlashSectorErase (
\r
63 volatile FLASH_WORD_SIZE *b,
\r
64 volatile FLASH_WORD_SIZE *a)
\r
74 /*****************************************************************************
\r
76 *****************************************************************************/
\r
77 static void FlashProgWord (
\r
78 volatile FLASH_WORD_SIZE *b,
\r
79 volatile FLASH_WORD_SIZE *a,
\r
88 /*****************************************************************************
\r
89 * reset bank, back to read mode
\r
90 *****************************************************************************/
\r
91 static void FlashReset (volatile FLASH_WORD_SIZE *b)
\r
96 /*****************************************************************************
\r
97 * identify FLASH chip
\r
98 * this code is a stripped version of the FlashGetType() function in EMKstax
\r
99 *****************************************************************************/
\r
100 unsigned long flash_init (void)
102 volatile FLASH_WORD_SIZE * const flash = (volatile FLASH_WORD_SIZE *) CFG_FLASH_BASE;
\r
103 FLASH_WORD_SIZE manu, dev;
\r
104 flash_info_t * const pflinfo = &flash_info[0];
\r
108 FlashProductIdMode (flash, 1);
\r
111 FlashProductIdMode (flash, 0);
\r
114 pflinfo->sector_count = 0;
\r
115 pflinfo->flash_id = 0xffffffff;
\r
116 pflinfo->portwidth = FLASH_CFI_16BIT;
\r
117 pflinfo->chipwidth = FLASH_CFI_BY16;
\r
121 case 0x01: /* AMD */
\r
122 pflinfo->flash_id = FLASH_MAN_AMD;
\r
126 pflinfo->size = 0x00200000;
\r
127 pflinfo->sector_count = 35;
\r
128 pflinfo->flash_id |= FLASH_AM160B;
\r
129 pflinfo->start[0] = CFG_FLASH_BASE;
\r
130 pflinfo->start[1] = CFG_FLASH_BASE + 0x4000;
\r
131 pflinfo->start[2] = CFG_FLASH_BASE + 0x6000;
\r
132 pflinfo->start[3] = CFG_FLASH_BASE + 0x8000;
\r
133 for (j = 4; j < 35; j++)
\r
135 pflinfo->start[j] = CFG_FLASH_BASE + 0x00010000 * (j-3);
\r
140 pflinfo->size = 0x00400000;
\r
141 pflinfo->sector_count = 71;
\r
142 pflinfo->flash_id |= FLASH_AM320B;
\r
143 pflinfo->start[0] = CFG_FLASH_BASE;
\r
144 pflinfo->start[1] = CFG_FLASH_BASE + 0x4000;
\r
145 pflinfo->start[2] = CFG_FLASH_BASE + 0x6000;
\r
146 pflinfo->start[3] = CFG_FLASH_BASE + 0x8000;
\r
147 for (j = 0; j < 8; j++)
\r
149 pflinfo->start[j] = CFG_FLASH_BASE + 0x00002000 * (j);
\r
151 for (j = 8; j < 71; j++)
\r
153 pflinfo->start[j] = CFG_FLASH_BASE + 0x00010000 * (j-7);
\r
158 printf ("unknown AMD dev=%x ", dev);
\r
159 pflinfo->flash_id |= FLASH_UNKNOWN;
\r
164 printf ("unknown manu=%x ", manu);
\r
166 return pflinfo->size;
\r
169 /*****************************************************************************
\r
170 * print info about a FLASH
\r
171 *****************************************************************************/
\r
172 void flash_print_info (flash_info_t *info)
174 static const char unk[] = "Unknown";
\r
176 const char *mfct=unk,
\r
179 if(info->flash_id != FLASH_UNKNOWN)
\r
181 switch (info->flash_id & FLASH_VENDMASK)
\r
183 case FLASH_MAN_AMD:
\r
188 switch (info->flash_id & FLASH_TYPEMASK)
\r
191 type = "AM29LV160B (16 Mbit, bottom boot sect)";
\r
194 type = "AM29LV320B (32 Mbit, bottom boot sect)";
\r
200 "\n Brand: %s Type: %s\n"
\r
201 " Size: %lu KB in %d Sectors\n",
\r
208 printf (" Sector Start Addresses:");
\r
210 for (i = 0; i < info->sector_count; i++)
\r
212 unsigned long size;
\r
213 unsigned int erased;
\r
214 unsigned long *flash = (unsigned long *) info->start[i];
\r
217 * Check if whole sector is erased
\r
220 (i != (info->sector_count - 1)) ?
\r
221 (info->start[i + 1] - info->start[i]) >> 2 :
\r
222 (info->start[0] + info->size - info->start[i]) >> 2;
\r
225 flash = (unsigned long *) info->start[i], erased = 1;
\r
226 (flash != (unsigned long *) info->start[i] + size) && erased;
\r
229 erased = *flash == ~0x0UL;
\r
233 (i % 5) ? "" : "\n ",
\r
235 erased ? "E" : " ",
\r
236 info->protect[i] ? "RO" : " "
\r
244 /*****************************************************************************
\r
245 * erase one or more sectors
\r
246 *****************************************************************************/
\r
247 int flash_erase (flash_info_t *info, int s_first, int s_last)
249 volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
\r
258 if ((s_first < 0) || (s_first > s_last))
\r
260 if (info->flash_id == FLASH_UNKNOWN)
\r
262 printf ("- missing\n");
\r
266 printf ("- no sectors to erase\n");
\r
271 if ((info->flash_id == FLASH_UNKNOWN) ||
\r
272 (info->flash_id > (FLASH_MAN_STM | FLASH_AMD_COMP)))
\r
274 printf ("Can't erase unknown flash type - aborted\n");
\r
279 for (sect=s_first; sect<=s_last; ++sect)
\r
281 if (info->protect[sect])
\r
289 printf ("- Warning: %d protected sectors will not be erased!\n",
\r
299 /* Disable interrupts which might cause a timeout here */
\r
300 flag = disable_interrupts();
\r
302 /* Start erase on unprotected sectors */
\r
303 for (sect = s_first; sect<=s_last; sect++)
\r
305 if (info->protect[sect] == 0)
\r
306 { /* not protected */
\r
307 FlashSectorErase ((FLASH_WORD_SIZE *)info->start[0], (FLASH_WORD_SIZE *)info->start[sect]);
\r
312 /* re-enable interrupts if necessary */
\r
314 enable_interrupts();
\r
316 /* wait at least 80us - let's wait 1 ms */
\r
320 * We wait for the last triggered sector
\r
325 start = get_timer (0);
\r
327 addr = (FLASH_WORD_SIZE *)info->start[l_sect];
\r
328 while ((addr[0] & 0x0080) != 0x0080)
\r
330 if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT)
\r
332 printf ("Timeout\n");
\r
335 /* show that we're waiting */
\r
336 if ((now - last) > 1000)
\r
337 { /* every second */
\r
344 /* reset to read mode */
\r
345 FlashReset ((FLASH_WORD_SIZE *)info->start[0]);
\r
347 printf (" done\n");
\r
351 /*****************************************************************************
\r
352 * Copy memory to flash, returns:
355 * 2 - Flash not erased
356 *****************************************************************************/
\r
357 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
366 wp = (addr & ~(FLASH_WORD_WIDTH-1)); /* get lower word aligned address */
\r
369 * handle unaligned start bytes, if there are...
\r
371 if ((l = addr - wp) != 0)
\r
375 /* get the current before the new data into our data word */
\r
376 for (i=0, cp=wp; i<l; ++i, ++cp)
\r
378 data = (data << 8) | (*(uchar *)cp);
\r
381 /* now merge the to be programmed values */
\r
382 for (; i<4 && cnt>0; ++i, ++cp, --cnt)
\r
384 data = (data << 8) | *src++;
\r
387 /* get the current after the new data into our data word */
\r
388 for (; cnt==0 && i<FLASH_WORD_WIDTH; ++i, ++cp)
\r
390 data = (data << 8) | (*(uchar *)cp);
\r
393 /* now write the combined word */
\r
394 if ((rc = write_word (info, wp, data)) != 0)
\r
398 wp += FLASH_WORD_WIDTH;
\r
402 * handle word aligned part
\r
404 while (cnt >= FLASH_WORD_WIDTH)
\r
407 for (i=0; i<FLASH_WORD_WIDTH; ++i)
\r
409 data = (data << 8) | *src++;
\r
411 if ((rc = write_word (info, wp, data)) != 0)
\r
415 wp += FLASH_WORD_WIDTH;
\r
416 cnt -= FLASH_WORD_WIDTH;
\r
425 * handle unaligned tail bytes, if there are...
\r
429 /* now merge the to be programmed values */
\r
430 for (i=0, cp=wp; i<FLASH_WORD_WIDTH && cnt>0; ++i, ++cp)
\r
432 data = (data << 8) | *src++;
\r
436 /* get the current after the new data into our data word */
\r
437 for (; i<FLASH_WORD_WIDTH; ++i, ++cp)
\r
439 data = (data << 8) | (*(uchar *)cp);
\r
442 /* now write the combined word */
\r
443 return (write_word (info, wp, data));
\r
446 /*****************************************************************************
\r
447 * Write a word to Flash, returns:
450 * 2 - Flash not erased
451 *****************************************************************************/
\r
452 static int write_word (flash_info_t *info, ulong dest, ulong data)
454 volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)info->start[0];
\r
455 volatile FLASH_WORD_SIZE *dest2 = (FLASH_WORD_SIZE *)dest;
\r
456 FLASH_WORD_SIZE data2 = data;
\r
460 /* Check if Flash is (sufficiently) erased */
\r
461 if ((*dest2 & data2) != data2)
\r
466 /* Disable interrupts which might cause a timeout here */
\r
467 flag = disable_interrupts ();
\r
469 FlashProgWord (addr2, dest2, data2);
\r
471 /* re-enable interrupts if necessary */
\r
473 enable_interrupts ();
\r
475 /* data polling for D7 */
\r
476 start = get_timer (0);
\r
477 while ((*dest2 & 0x0080) != (data2 & 0x0080))
\r
479 if (get_timer (start) > CFG_FLASH_WRITE_TOUT)
\r
488 /*-----------------------------------------------------------------------