/* * (C) Copyright 2000 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Hacked for the marvell db64360 eval board by * Ingo Assmus */ #include #include #include "../include/mv_gen_reg.h" #include "../include/memory.h" #include "intel_flash.h" /*----------------------------------------------------------------------- * Protection Flags: */ #define FLAG_PROTECT_SET 0x01 #define FLAG_PROTECT_CLEAR 0x02 static void bank_reset (flash_info_t * info, int sect) { bank_addr_t addrw, eaddrw; addrw = (bank_addr_t) info->start[sect]; eaddrw = BANK_ADDR_NEXT_WORD (addrw); while (addrw < eaddrw) { #ifdef FLASH_DEBUG printf (" writing reset cmd to addr 0x%08lx\n", (unsigned long) addrw); #endif *addrw = BANK_CMD_RST; addrw++; } } static void bank_erase_init (flash_info_t * info, int sect) { bank_addr_t addrw, saddrw, eaddrw; int flag; #ifdef FLASH_DEBUG printf ("0x%08x BANK_CMD_PROG\n", BANK_CMD_PROG); printf ("0x%08x BANK_CMD_ERASE1\n", BANK_CMD_ERASE1); printf ("0x%08x BANK_CMD_ERASE2\n", BANK_CMD_ERASE2); printf ("0x%08x BANK_CMD_CLR_STAT\n", BANK_CMD_CLR_STAT); printf ("0x%08x BANK_CMD_RST\n", BANK_CMD_RST); printf ("0x%08x BANK_STAT_RDY\n", BANK_STAT_RDY); printf ("0x%08x BANK_STAT_ERR\n", BANK_STAT_ERR); #endif saddrw = (bank_addr_t) info->start[sect]; eaddrw = BANK_ADDR_NEXT_WORD (saddrw); #ifdef FLASH_DEBUG printf ("erasing sector %d, start addr = 0x%08lx " "(bank next word addr = 0x%08lx)\n", sect, (unsigned long) saddrw, (unsigned long) eaddrw); #endif /* Disable intrs which might cause a timeout here */ flag = disable_interrupts (); for (addrw = saddrw; addrw < eaddrw; addrw++) { #ifdef FLASH_DEBUG printf (" writing erase cmd to addr 0x%08lx\n", (unsigned long) addrw); #endif *addrw = BANK_CMD_ERASE1; *addrw = BANK_CMD_ERASE2; } /* re-enable interrupts if necessary */ if (flag) enable_interrupts (); } static int bank_erase_poll (flash_info_t * info, int sect) { bank_addr_t addrw, saddrw, eaddrw; int sectdone, haderr; saddrw = (bank_addr_t) info->start[sect]; eaddrw = BANK_ADDR_NEXT_WORD (saddrw); sectdone = 1; haderr = 0; for (addrw = saddrw; addrw < eaddrw; addrw++) { bank_word_t stat = *addrw; #ifdef FLASH_DEBUG printf (" checking status at addr " "0x%08x [0x%08x]\n", (unsigned long) addrw, stat); #endif if ((stat & BANK_STAT_RDY) != BANK_STAT_RDY) sectdone = 0; else if ((stat & BANK_STAT_ERR) != 0) { printf (" failed on sector %d " "(stat = 0x%08x) at " "address 0x%p\n", sect, stat, addrw); *addrw = BANK_CMD_CLR_STAT; haderr = 1; } } if (haderr) return (-1); else return (sectdone); } int write_word_intel (bank_addr_t addr, bank_word_t value) { bank_word_t stat; ulong start; int flag, retval; /* Disable interrupts which might cause a timeout here */ flag = disable_interrupts (); *addr = BANK_CMD_PROG; *addr = value; /* re-enable interrupts if necessary */ if (flag) enable_interrupts (); retval = 0; /* data polling for D7 */ start = get_timer (0); do { if (get_timer (start) > CFG_FLASH_WRITE_TOUT) { retval = 1; goto done; } stat = *addr; } while ((stat & BANK_STAT_RDY) != BANK_STAT_RDY); if ((stat & BANK_STAT_ERR) != 0) { printf ("flash program failed (stat = 0x%08lx) " "at address 0x%08lx\n", (ulong) stat, (ulong) addr); *addr = BANK_CMD_CLR_STAT; retval = 3; } done: /* reset to read mode */ *addr = BANK_CMD_RST; return (retval); } /*----------------------------------------------------------------------- */ int flash_erase_intel (flash_info_t * info, int s_first, int s_last) { int prot, sect, haderr; ulong start, now, last; #ifdef FLASH_DEBUG printf ("\nflash_erase: erase %d sectors (%d to %d incl.) from\n" " Bank # %d: ", s_last - s_first + 1, s_first, s_last, (info - flash_info) + 1); flash_print_info (info); #endif if ((s_first < 0) || (s_first > s_last)) { if (info->flash_id == FLASH_UNKNOWN) { printf ("- missing\n"); } else { printf ("- no sectors to erase\n"); } return 1; } prot = 0; for (sect = s_first; sect <= s_last; ++sect) { if (info->protect[sect]) { prot++; } } if (prot) { printf ("- Warning: %d protected sector%s will not be erased!\n", prot, (prot > 1 ? "s" : "")); } start = get_timer (0); last = 0; haderr = 0; for (sect = s_first; sect <= s_last; sect++) { if (info->protect[sect] == 0) { /* not protected */ ulong estart; int sectdone; bank_erase_init (info, sect); /* wait at least 80us - let's wait 1 ms */ udelay (1000); estart = get_timer (start); do { now = get_timer (start); if (now - estart > CFG_FLASH_ERASE_TOUT) { printf ("Timeout (sect %d)\n", sect); haderr = 1; break; } #ifndef FLASH_DEBUG /* show that we're waiting */ if ((now - last) > 1000) { /* every second */ putc ('.'); last = now; } #endif sectdone = bank_erase_poll (info, sect); if (sectdone < 0) { haderr = 1; break; } } while (!sectdone); if (haderr) break; } } if (haderr > 0) printf (" failed\n"); else printf (" done\n"); /* reset to read mode */ for (sect = s_first; sect <= s_last; sect++) { if (info->protect[sect] == 0) { /* not protected */ bank_reset (info, sect); } } return haderr; }