X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fmtd%2Fcfi_flash.c;h=35294bc8c53ff37ffb059ac66765c733d71eacef;hb=d8bd820935bb9b8bf2717a259eeab4376e9ccc9a;hp=c92c7a7a490cd8c7fa45fec2c7091ecbcdebb010;hpb=02cf8fd6fbef7ac015a234b09e7b55765aefcd4f;p=u-boot diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index c92c7a7a49..35294bc8c5 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -40,6 +40,7 @@ #include #include #include +#include /* * This file implements a Common Flash Interface (CFI) driver for @@ -63,7 +64,11 @@ */ static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT }; +#ifdef CONFIG_FLASH_CFI_MTD static uint flash_verbose = 1; +#else +#define flash_verbose 1 +#endif flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */ @@ -74,6 +79,20 @@ flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */ #define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_8BIT #endif +/* + * 0xffff is an undefined value for the configuration register. When + * this value is returned, the configuration register shall not be + * written at all (default mode). + */ +static u16 cfi_flash_config_reg(int i) +{ +#ifdef CONFIG_SYS_CFI_FLASH_CONFIG_REGS + return ((u16 [])CONFIG_SYS_CFI_FLASH_CONFIG_REGS)[i]; +#else + return 0xffff; +#endif +} + #if defined(CONFIG_SYS_MAX_FLASH_BANKS_DETECT) int cfi_flash_num_flash_banks = CONFIG_SYS_MAX_FLASH_BANKS_DETECT; #endif @@ -555,14 +574,18 @@ static int flash_status_check (flash_info_t * info, flash_sect_t sector, #endif /* Wait for command completion */ +#ifdef CONFIG_SYS_LOW_RES_TIMER reset_timer(); +#endif start = get_timer (0); + WATCHDOG_RESET(); while (flash_is_busy (info, sector)) { if (get_timer (start) > tout) { printf ("Flash %s timeout at address %lx data %lx\n", prompt, info->start[sector], flash_read_long (info, sector, 0)); flash_write_cmd (info, sector, 0, info->cmd_reset); + udelay(1); return ERR_TIMOUT; } udelay (1); /* also triggers watchdog */ @@ -610,6 +633,7 @@ static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, puts ("Vpp Low Error.\n"); } flash_write_cmd (info, sector, 0, info->cmd_reset); + udelay(1); break; default: break; @@ -642,8 +666,11 @@ static int flash_status_poll(flash_info_t *info, void *src, void *dst, #endif /* Wait for command completion */ +#ifdef CONFIG_SYS_LOW_RES_TIMER reset_timer(); +#endif start = get_timer(0); + WATCHDOG_RESET(); while (1) { switch (info->portwidth) { case FLASH_CFI_8BIT: @@ -726,8 +753,12 @@ static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) static flash_sect_t find_sector (flash_info_t * info, ulong addr) { static flash_sect_t saved_sector = 0; /* previously found sector */ + static flash_info_t *saved_info = 0; /* previously used flash bank */ flash_sect_t sector = saved_sector; + if ((info != saved_info) || (sector >= info->sector_count)) + sector = 0; + while ((info->start[sector] < addr) && (sector < info->sector_count - 1)) sector++; @@ -739,6 +770,7 @@ static flash_sect_t find_sector (flash_info_t * info, ulong addr) sector--; saved_sector = sector; + saved_info = info; return sector; } @@ -841,7 +873,7 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, void *src = cp; void *dst = (void *)dest; void *dst2 = dst; - int flag = 0; + int flag = 1; uint offset = 0; unsigned int shift; uchar write_cmd; @@ -866,7 +898,7 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, cnt = len >> shift; - while ((cnt-- > 0) && (flag == 0)) { + while ((cnt-- > 0) && (flag == 1)) { switch (info->portwidth) { case FLASH_CFI_8BIT: flag = ((flash_read8(dst2) & flash_read8(src)) == @@ -1112,18 +1144,18 @@ static int sector_erased(flash_info_t *info, int i) { int k; int size; - volatile unsigned long *flash; + u32 *flash; /* * Check if whole sector is erased */ size = flash_sector_size(info, i); - flash = (volatile unsigned long *) info->start[i]; + flash = (u32 *)info->start[i]; /* divide by 4 for longword access */ size = size >> 2; for (k = 0; k < size; k++) { - if (*flash++ != 0xffffffff) + if (flash_read32(flash++) != 0xffffffff) return 0; /* not erased */ } @@ -1140,7 +1172,7 @@ void flash_print_info (flash_info_t * info) return; } - printf ("%s FLASH (%d x %d)", + printf ("%s flash (%d x %d)", info->name, (info->portwidth << 3), (info->chipwidth << 3)); if (info->size < 1024*1024) @@ -1179,8 +1211,9 @@ void flash_print_info (flash_info_t * info) info->manufacturer_id); printf (info->chipwidth == FLASH_CFI_16BIT ? "%04X" : "%02X", info->device_id); - if (info->device_id == 0x7E) { - printf("%04X", info->device_id2); + if ((info->device_id & 0xff) == 0x7E) { + printf(info->chipwidth == FLASH_CFI_16BIT ? "%04X" : "%02X", + info->device_id2); } printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n", info->erase_blk_tout, @@ -1426,6 +1459,11 @@ int flash_real_protect (flash_info_t * info, long sector, int prot) #endif }; + /* + * Flash needs to be in status register read mode for + * flash_full_status_check() to work correctly + */ + flash_write_cmd(info, sector, 0, FLASH_CMD_READ_STATUS); if ((retcode = flash_full_status_check (info, sector, info->erase_blk_tout, prot ? "protect" : "unprotect")) == 0) { @@ -1462,6 +1500,7 @@ void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); memcpy (dst, src + offset, len); flash_write_cmd (info, 0, 0, info->cmd_reset); + udelay(1); flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src); } @@ -1477,6 +1516,7 @@ void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); memcpy (buffer, src + offset, len); flash_write_cmd (info, 0, 0, info->cmd_reset); + udelay(1); flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src); } @@ -1508,6 +1548,7 @@ static void cfi_reverse_geometry(struct cfi_qry *qry) static void cmdset_intel_read_jedec_ids(flash_info_t *info) { flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); + udelay(1); flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); udelay(1000); /* some flash are slow to respond */ info->manufacturer_id = flash_read_uchar (info, @@ -1571,11 +1612,20 @@ static void cmdset_amd_read_jedec_ids(flash_info_t *info) case FLASH_CFI_16BIT: info->device_id = flash_read_word (info, FLASH_OFFSET_DEVICE_ID); + if ((info->device_id & 0xff) == 0x7E) { + /* AMD 3-byte (expanded) device ids */ + info->device_id2 = flash_read_uchar (info, + FLASH_OFFSET_DEVICE_ID2); + info->device_id2 <<= 8; + info->device_id2 |= flash_read_uchar (info, + FLASH_OFFSET_DEVICE_ID3); + } break; default: break; } flash_write_cmd(info, 0, 0, AMD_CMD_RESET); + udelay(1); } static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry) @@ -1702,6 +1752,7 @@ void __flash_cmd_reset(flash_info_t *info) * that AMD flash roms ignore the Intel command. */ flash_write_cmd(info, 0, 0, AMD_CMD_RESET); + udelay(1); flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); } void flash_cmd_reset(flash_info_t *info) @@ -1824,11 +1875,16 @@ static void flash_fixup_stm(flash_info_t *info, struct cfi_qry *qry) if (qry->num_erase_regions > 1) { /* reverse geometry if top boot part */ if (info->cfi_version < 0x3131) { - /* CFI < 1.1, guess by device id (M29W320{DT,ET} only) */ - if (info->device_id == 0x22CA || - info->device_id == 0x2256) { + /* CFI < 1.1, guess by device id */ + if (info->device_id == 0x22CA || /* M29W320DT */ + info->device_id == 0x2256 || /* M29W320ET */ + info->device_id == 0x22D7) { /* M29W800DT */ cfi_reverse_geometry(qry); } + } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { + /* CFI >= 1.1, deduct from top/bottom flag */ + /* note: ext_addr is valid since cfi_version > 0 */ + cfi_reverse_geometry(qry); } } } @@ -1837,7 +1893,7 @@ static void flash_fixup_stm(flash_info_t *info, struct cfi_qry *qry) * The following code cannot be run from FLASH! * */ -ulong flash_get_size (phys_addr_t base, int banknum, unsigned long max_size) +ulong flash_get_size (phys_addr_t base, int banknum) { flash_info_t *info = &flash_info[banknum]; int i, j; @@ -1849,6 +1905,7 @@ ulong flash_get_size (phys_addr_t base, int banknum, unsigned long max_size) int erase_region_size; int erase_region_count; struct cfi_qry qry; + unsigned long max_size; memset(&qry, 0, sizeof(qry)); @@ -1900,7 +1957,8 @@ ulong flash_get_size (phys_addr_t base, int banknum, unsigned long max_size) /* Do manufacturer-specific fixups */ switch (info->manufacturer_id) { - case 0x0001: + case 0x0001: /* AMD */ + case 0x0037: /* AMIC */ flash_fixup_amd(info, &qry); break; case 0x001f: @@ -1929,6 +1987,7 @@ ulong flash_get_size (phys_addr_t base, int banknum, unsigned long max_size) info->size = 1 << qry.dev_size; /* multiply the size by the number of chips */ info->size *= size_ratio; + max_size = cfi_flash_bank_size(banknum); if (max_size && (info->size > max_size)) { debug("[truncated from %ldMiB]", info->size >> 20); info->size = max_size; @@ -1973,6 +2032,13 @@ ulong flash_get_size (phys_addr_t base, int banknum, unsigned long max_size) case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_EXTENDED: case CFI_CMDSET_INTEL_STANDARD: + /* + * Set flash to read-id mode. Otherwise + * reading protected status is not + * guaranteed. + */ + flash_write_cmd(info, sect_cnt, 0, + FLASH_CMD_READ_ID); info->protect[sect_cnt] = flash_isset (info, sect_cnt, FLASH_OFFSET_PROTECT, @@ -2014,24 +2080,93 @@ ulong flash_get_size (phys_addr_t base, int banknum, unsigned long max_size) return (info->size); } +#ifdef CONFIG_FLASH_CFI_MTD void flash_set_verbose(uint v) { flash_verbose = v; } +#endif + +static void cfi_flash_set_config_reg(u32 base, u16 val) +{ +#ifdef CONFIG_SYS_CFI_FLASH_CONFIG_REGS + /* + * Only set this config register if really defined + * to a valid value (0xffff is invalid) + */ + if (val == 0xffff) + return; + + /* + * Set configuration register. Data is "encrypted" in the 16 lower + * address bits. + */ + flash_write16(FLASH_CMD_SETUP, (void *)(base + (val << 1))); + flash_write16(FLASH_CMD_SET_CR_CONFIRM, (void *)(base + (val << 1))); + + /* + * Finally issue reset-command to bring device back to + * read-array mode + */ + flash_write16(FLASH_CMD_RESET, (void *)base); +#endif +} /*----------------------------------------------------------------------- */ -unsigned long flash_init (void) + +void flash_protect_default(void) { - unsigned long size = 0; - int i; #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) + int i; struct apl_s { ulong start; ulong size; } apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST; #endif + /* Monitor protection ON by default */ +#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE) && \ + (!defined(CONFIG_MONITOR_IS_IN_RAM)) + flash_protect(FLAG_PROTECT_SET, + CONFIG_SYS_MONITOR_BASE, + CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, + flash_get_info(CONFIG_SYS_MONITOR_BASE)); +#endif + + /* Environment protection ON by default */ +#ifdef CONFIG_ENV_IS_IN_FLASH + flash_protect(FLAG_PROTECT_SET, + CONFIG_ENV_ADDR, + CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1, + flash_get_info(CONFIG_ENV_ADDR)); +#endif + + /* Redundant environment protection ON by default */ +#ifdef CONFIG_ENV_ADDR_REDUND + flash_protect(FLAG_PROTECT_SET, + CONFIG_ENV_ADDR_REDUND, + CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1, + flash_get_info(CONFIG_ENV_ADDR_REDUND)); +#endif + +#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) + for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) { + debug("autoprotecting from %08lx to %08lx\n", + apl[i].start, apl[i].start + apl[i].size - 1); + flash_protect(FLAG_PROTECT_SET, + apl[i].start, + apl[i].start + apl[i].size - 1, + flash_get_info(apl[i].start)); + } +#endif +} + +unsigned long flash_init (void) +{ + unsigned long size = 0; + int i; + #ifdef CONFIG_SYS_FLASH_PROTECTION /* read environment from EEPROM */ char s[64]; @@ -2042,13 +2177,16 @@ unsigned long flash_init (void) for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) { flash_info[i].flash_id = FLASH_UNKNOWN; + /* Optionally write flash configuration register */ + cfi_flash_set_config_reg(cfi_flash_bank_addr(i), + cfi_flash_config_reg(i)); + if (!flash_detect_legacy(cfi_flash_bank_addr(i), i)) - flash_get_size(cfi_flash_bank_addr(i), i, - cfi_flash_bank_size(i)); + flash_get_size(cfi_flash_bank_addr(i), i); size += flash_info[i].size; if (flash_info[i].flash_id == FLASH_UNKNOWN) { #ifndef CONFIG_SYS_FLASH_QUIET_TEST - printf ("## Unknown FLASH on Bank %d " + printf ("## Unknown flash on Bank %d " "- Size = 0x%08lx = %ld MB\n", i+1, flash_info[i].size, flash_info[i].size >> 20); @@ -2104,42 +2242,7 @@ unsigned long flash_init (void) #endif /* CONFIG_SYS_FLASH_PROTECTION */ } - /* Monitor protection ON by default */ -#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE) && \ - (!defined(CONFIG_MONITOR_IS_IN_RAM)) - flash_protect (FLAG_PROTECT_SET, - CONFIG_SYS_MONITOR_BASE, - CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, - flash_get_info(CONFIG_SYS_MONITOR_BASE)); -#endif - - /* Environment protection ON by default */ -#ifdef CONFIG_ENV_IS_IN_FLASH - flash_protect (FLAG_PROTECT_SET, - CONFIG_ENV_ADDR, - CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1, - flash_get_info(CONFIG_ENV_ADDR)); -#endif - - /* Redundant environment protection ON by default */ -#ifdef CONFIG_ENV_ADDR_REDUND - flash_protect (FLAG_PROTECT_SET, - CONFIG_ENV_ADDR_REDUND, - CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1, - flash_get_info(CONFIG_ENV_ADDR_REDUND)); -#endif - -#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) - for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) { - debug("autoprotecting from %08x to %08x\n", - apl[i].start, apl[i].start + apl[i].size - 1); - flash_protect (FLAG_PROTECT_SET, - apl[i].start, - apl[i].start + apl[i].size - 1, - flash_get_info(apl[i].start)); - } -#endif - + flash_protect_default(); #ifdef CONFIG_FLASH_CFI_MTD cfi_mtd_init(); #endif