📄 flash.c
字号:
/* * (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 <common.h>#include <mpc8260.h>#include <board/hymod/flash.h>flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips *//*----------------------------------------------------------------------- * Protection Flags: */#define FLAG_PROTECT_SET 0x01#define FLAG_PROTECT_CLEAR 0x02/*----------------------------------------------------------------------- * Functions */#if 0static ulong flash_get_size (vu_long *addr, flash_info_t *info);static void flash_get_offsets (ulong base, flash_info_t *info);#endifstatic int write_word (flash_info_t *info, ulong dest, ulong data);/*----------------------------------------------------------------------- *//* * probe for the existence of flash at bank word address "addr" * 0 = yes, 1 = bad Manufacturer's Id, 2 = bad Device Id */static intbank_probe_word(bank_addr_t addr){ int retval; /* reset the flash */ *addr = BANK_CMD_RST; /* check the manufacturer id */ *addr = BANK_CMD_RD_ID; if (*BANK_ADDR_REG_MAN(addr) != BANK_RD_ID_MAN) { retval = -1; goto out; } /* check the device id */ *addr = BANK_CMD_RD_ID; if (*BANK_ADDR_REG_DEV(addr) != BANK_RD_ID_DEV) { retval = -2; goto out; } retval = CFG_FLASH_TYPE;out: /* reset the flash again */ *addr = BANK_CMD_RST; return retval;}/* * probe for flash banks at address "base" and store info for any found * into flash_info entry "fip". Must find at least one bank. */static voidbank_probe(flash_info_t *fip, bank_addr_t base){ bank_addr_t addr, eaddr; int nbanks; fip->flash_id = FLASH_UNKNOWN; fip->size = 0L; fip->sector_count = 0; addr = base; eaddr = BANK_ADDR_BASE(addr, MAX_BANKS); nbanks = 0; while (addr < eaddr) { bank_addr_t addrw, eaddrw, addrb; int i, osc, nsc, curtype = -1; addrw = addr; eaddrw = BANK_ADDR_NEXT_WORD(addrw); while (addrw < eaddrw) { int thistype;#ifdef FLASH_DEBUG printf(" probing for flash at addr 0x%08lx\n", (unsigned long)addrw);#endif if ((thistype = bank_probe_word(addrw++)) < 0) goto out; if (curtype < 0) curtype = thistype; else { if (thistype != curtype) { printf("Differing flash type found!\n"); goto out; } } } if (curtype < 0) goto out; /* bank exists - append info for this bank to *fip */ fip->flash_id = FLASH_MAN_INTEL|curtype; fip->size += BANK_SIZE; osc = fip->sector_count; fip->sector_count += BANK_NBLOCKS; if ((nsc = fip->sector_count) >= CFG_MAX_FLASH_SECT) panic("Too many sectors in flash at address 0x%08lx\n", (unsigned long)base); addrb = addr; for (i = osc; i < nsc; i++) { fip->start[i] = (ulong)addrb; fip->protect[i] = 0; addrb = BANK_ADDR_NEXT_BLK(addrb); } addr = BANK_ADDR_NEXT_BANK(addr); nbanks++; }out: if (nbanks == 0) panic("ERROR: no flash found at address 0x%08lx\n", (unsigned long)base);}static voidbank_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 voidbank_erase_init(flash_info_t *info, int sect){ bank_addr_t addrw, saddrw, eaddrw; int flag;#ifdef FLASH_DEBUG printf("0x%08lx BANK_CMD_PROG\n", BANK_CMD_PROG); printf("0x%08lx BANK_CMD_ERASE1\n", BANK_CMD_ERASE1); printf("0x%08lx BANK_CMD_ERASE2\n", BANK_CMD_ERASE2); printf("0x%08lx BANK_CMD_CLR_STAT\n", BANK_CMD_CLR_STAT); printf("0x%08lx BANK_CMD_RST\n", BANK_CMD_RST); printf("0x%08lx BANK_STAT_RDY\n", BANK_STAT_RDY); printf("0x%08lx 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 intbank_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%08lx [0x%08lx]\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%08lx) at " "address 0x%08lx\n", sect, stat, (unsigned long)addrw); *addrw = BANK_CMD_CLR_STAT; haderr = 1; } } if (haderr) return (-1); else return (sectdone);}static intbank_write_word(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);}/*----------------------------------------------------------------------- */unsigned longflash_init(void){ int i; /* Init: no FLASHes known */ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) { flash_info[i].flash_id = FLASH_UNKNOWN; } bank_probe(&flash_info[0], (bank_addr_t)CFG_FLASH_BASE); /* * protect monitor and environment sectors */#if CFG_MONITOR_BASE == CFG_FLASH_BASE (void)flash_protect(FLAG_PROTECT_SET, CFG_MONITOR_BASE, CFG_MONITOR_BASE+monitor_flash_len-1, &flash_info[0]);#endif#if defined(CFG_FLASH_ENV_ADDR) (void)flash_protect(FLAG_PROTECT_SET, CFG_FLASH_ENV_ADDR,#if defined(CFG_FLASH_ENV_BUF) CFG_FLASH_ENV_ADDR + CFG_FLASH_ENV_BUF - 1,#else CFG_FLASH_ENV_ADDR + CFG_FLASH_ENV_SIZE - 1,#endif &flash_info[0]);#endif return flash_info[0].size;}/*----------------------------------------------------------------------- */#if 0static voidflash_get_offsets(ulong base, flash_info_t *info){ int i; /* set up sector start adress table */ if (info->flash_id & FLASH_BTYPE) { /* set sector offsets for bottom boot block type */ info->start[0] = base + 0x00000000; info->start[1] = base + 0x00008000; info->start[2] = base + 0x0000C000; info->start[3] = base + 0x00010000; for (i = 4; i < info->sector_count; i++) { info->start[i] = base + (i * 0x00020000) - 0x00060000; } } else { /* set sector offsets for top boot block type */ i = info->sector_count - 1; info->start[i--] = base + info->size - 0x00008000; info->start[i--] = base + info->size - 0x0000C000; info->start[i--] = base + info->size - 0x00010000; for (; i >= 0; i--) { info->start[i] = base + i * 0x00020000; } }}#endif /* 0 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -