📄 flash.c
字号:
/* * (C) Copyright 2003 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * (C) Copyright 2006 * Johnny Yip, Hisilicon , yebucai@huawei.com. * * 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 */#include <common.h>#include <watchdog.h>flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */#ifdef FLASH_PORT_WIDTH8#define FLASH_PORT_WIDTH uchar#define FLASH_PORT_WIDTHV vu_char#define FLASH_ADDR_SHIFT_BITS 0#endif#ifdef FLASH_PORT_WIDTH16#define FLASH_PORT_WIDTH ushort#define FLASH_PORT_WIDTHV vu_short#define FLASH_ADDR_SHIFT_BITS 1 #endif#ifdef FLASH_PORT_WIDTH32#define FLASH_PORT_WIDTH ulong#define FLASH_PORT_WIDTHV vu_long#define FLASH_ADDR_SHIFT_BITS 2 #endif#define FPW FLASH_PORT_WIDTH#define FPWV FLASH_PORT_WIDTHV#define MEM_FLASH_ADDR1 (*(FPWV *)(CFG_FLASH_BASE + (0x00000555 << FLASH_ADDR_SHIFT_BITS)))#define MEM_FLASH_ADDR2 (*(FPWV *)(CFG_FLASH_BASE + (0x000002AA << FLASH_ADDR_SHIFT_BITS)))/*----------------------------------------------------------------------- * Functions */static ulong flash_get_size(FPWV *addr, flash_info_t *info);static void flash_reset(flash_info_t *info);static int write_word_intel(flash_info_t *info, FPWV *dest, FPW data);static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);static void flash_get_offsets(ulong base, flash_info_t *info);static flash_info_t *flash_get_info(ulong base);/*----------------------------------------------------------------------- * flash_init() * * sets up flash_info and returns size of FLASH (bytes) */unsigned long flash_init (void){ unsigned long size = 0; int i; for (i=0; i < CFG_MAX_FLASH_BANKS; ++i) { ulong flashbase = CFG_FLASH_BASE; memset(&flash_info[i], 0, sizeof(flash_info_t)); flash_info[i].size = flash_get_size((FPW *)flashbase, &flash_info[i]); if (flash_info[i].flash_id == FLASH_UNKNOWN) { printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx\n", i, flash_info[i].size); } size += flash_info[i].size; } /* monitor protection ON by default */ flash_protect(FLAG_PROTECT_SET, CFG_FLASH_BASE, CFG_FLASH_BASE+monitor_flash_len-1, flash_get_info(CFG_FLASH_BASE));#ifdef CFG_ENV_IS_IN_FLASH /* ENV protection ON by default */ flash_protect(FLAG_PROTECT_SET, CFG_ENV_ADDR, CFG_ENV_ADDR+CFG_ENV_SIZE-1, flash_get_info(CFG_ENV_ADDR));#endif return size ? size : 1;}/*----------------------------------------------------------------------- */ulong flash_get_size (FPWV *addr, flash_info_t *info){ volatile FPW value; MEM_FLASH_ADDR1 = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */ MEM_FLASH_ADDR2 = (FPW)0x00550055; /* for AMD, Intel ignores this */ MEM_FLASH_ADDR1 = (FPW)0x00900090; /* selects Intel or AMD */ /* The manufacturer codes are only 1 byte, so just use 1 byte. * This works for any bus width and any FLASH device width. */ udelay(100); switch (addr[0] & 0xff) { case (uchar)AMD_MANUFACT: info->flash_id = FLASH_MAN_AMD; break; case (uchar)INTEL_MANUFACT: info->flash_id = FLASH_MAN_INTEL; break; default: info->flash_id = FLASH_UNKNOWN; info->sector_count = 0; info->size = 0; return (0); }#ifdef FLASH_PORT_WIDTH8 value = addr[2];#else value = addr[1];#endif switch (value) { case (FPW)AMD_ID_S29GL256N: info->flash_id += FLASH_AMDS29GL256N; info->sector_count = 256; info->size = 0x02000000; break; case (FPW)(INTEL_ID_28F256J3): info->flash_id += FLASH_28F256J3; info->sector_count = 256; info->size = 0x02000000; break; default: info->flash_id = FLASH_UNKNOWN; info->sector_count = 0; info->size = 0; return (0); } flash_get_offsets((ulong)addr, info); /* Put FLASH back in read mode */ flash_reset(info); return (info->size);}/*----------------------------------------------------------------------- */static void flash_get_offsets (ulong base, flash_info_t *info){ int i; /* set up sector start address table */ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL && (info->flash_id & FLASH_TYPEMASK) == FLASH_28F256J3) { // int bootsect_size; /* number of bytes/boot sector */ int sect_size; /* number of bytes/regular sector */ // bootsect_size = 0x00002000 * (sizeof(FPW)/2); sect_size = 0x00020000 * (sizeof(FPW)/2); /* set sector offsets for bottom boot block type */ /* * for (i = 0; i < 8; ++i) { info->start[i] = base + (i * bootsect_size); } */ for (i = 0; i < info->sector_count; i++) { info->start[i] = base + (i * sect_size); } } else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD && (info->flash_id & FLASH_TYPEMASK) == FLASH_AMDS29GL256N) { int sect_size; /* number of bytes/sector */ sect_size = 0x00020000 * (sizeof(FPW)/2); /* set up sector start address table (uniform sector type) */ for( i = 0; i < info->sector_count; i++ ) info->start[i] = base + (i * sect_size); }}/*----------------------------------------------------------------------- */void flash_print_info (flash_info_t *info){ int i; uchar *boottype; uchar *bootletter; char *fmt; uchar botbootletter[] = "B"; uchar topbootletter[] = "T"; uchar botboottype[] = "bottom boot sector"; uchar topboottype[] = "top boot sector"; if (info->flash_id == FLASH_UNKNOWN) { printf ("missing or unknown FLASH type\n"); return; } switch (info->flash_id & FLASH_VENDMASK) { case FLASH_MAN_INTEL: printf ("INTEL "); break; case FLASH_MAN_AMD: printf ("AMD "); break; default: printf ("Unknown Vendor "); break; } /* check for top or bottom boot, if it applies */ if (info->flash_id & FLASH_BTYPE) { boottype = botboottype; bootletter = botbootletter; } else { boottype = topboottype; bootletter = topbootletter; } switch (info->flash_id & FLASH_TYPEMASK) { case FLASH_28F256J3: fmt = "28F256J3 (32 Mbit, uniform sectors)\n"; break; case FLASH_AMDS29GL256N: fmt = "S29GL256N(32 Mbit, uniform sectors)\n"; break; case FLASH_INTEL640T: fmt = "28F640B3%s (64 Mbit, %s)\n"; break; default: fmt = "Unknown Chip Type\n"; break; } printf (fmt, bootletter, boottype); printf (" Size: %ld MB in %d Sectors\n", info->size >> 20, info->sector_count); printf (" Sector Start Addresses:"); for (i=0; i<info->sector_count; ++i) { if ((i % 5) == 0) { printf ("\n "); } printf (" %08lX%s", info->start[i], info->protect[i] ? " (RO)" : " "); } printf ("\n");}/*----------------------------------------------------------------------- */static flash_info_t *flash_get_info(ulong base){ int i; flash_info_t * info; for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) { info = & flash_info[i]; if (info->start[0] <= base && base < info->start[0] + info->size) break; } return i == CFG_MAX_FLASH_BANKS ? 0 : info;}/*----------------------------------------------------------------------- */static void flash_reset(flash_info_t *info){ FPWV *base = (FPWV *)(info->start[0]); if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) *base = (FPW)0x00FF00FF; else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD) *base = (FPW)0x00F000F0; }/*----------------------------------------------------------------------- */int flash_get_sect(flash_info_t *info, ulong addr){ int i; if (info->start[info->sector_count-1] <= addr && addr < CFG_FLASH_BASE + info->size) return info->sector_count-1; for (i = 0; i < info->sector_count-1; i++) { if (info->start[i] <= addr && addr < info->start[i+1]) return i; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -