/* * (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 Hymod board by Murray.Jensen@cmst.csiro.au, 20-Oct-00 */ #include #include #include #include #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) > CONFIG_SYS_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 > CONFIG_SYS_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; }