159829cc1SJean-Christophe PLAGNIOL-VILLARD /* 259829cc1SJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2002-2004 359829cc1SJean-Christophe PLAGNIOL-VILLARD * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com 459829cc1SJean-Christophe PLAGNIOL-VILLARD * 559829cc1SJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2003 Arabella Software Ltd. 659829cc1SJean-Christophe PLAGNIOL-VILLARD * Yuli Barcohen <yuli@arabellasw.com> 759829cc1SJean-Christophe PLAGNIOL-VILLARD * 859829cc1SJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2004 959829cc1SJean-Christophe PLAGNIOL-VILLARD * Ed Okerson 1059829cc1SJean-Christophe PLAGNIOL-VILLARD * 1159829cc1SJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2006 1259829cc1SJean-Christophe PLAGNIOL-VILLARD * Tolunay Orkun <listmember@orkun.us> 1359829cc1SJean-Christophe PLAGNIOL-VILLARD * 141a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 1559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1659829cc1SJean-Christophe PLAGNIOL-VILLARD 1759829cc1SJean-Christophe PLAGNIOL-VILLARD /* The DEBUG define must be before common to enable debugging */ 1859829cc1SJean-Christophe PLAGNIOL-VILLARD /* #define DEBUG */ 1959829cc1SJean-Christophe PLAGNIOL-VILLARD 2059829cc1SJean-Christophe PLAGNIOL-VILLARD #include <common.h> 2159829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/processor.h> 2259829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h> 2359829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/byteorder.h> 24aedadf10SAndrew Gabbasov #include <asm/unaligned.h> 2559829cc1SJean-Christophe PLAGNIOL-VILLARD #include <environment.h> 26fa36ae79SStefan Roese #include <mtd/cfi_flash.h> 27a9f5fabaSJens Scharsig (BuS Elektronik) #include <watchdog.h> 2859829cc1SJean-Christophe PLAGNIOL-VILLARD 2959829cc1SJean-Christophe PLAGNIOL-VILLARD /* 307e5b9b47SHaavard Skinnemoen * This file implements a Common Flash Interface (CFI) driver for 317e5b9b47SHaavard Skinnemoen * U-Boot. 327e5b9b47SHaavard Skinnemoen * 337e5b9b47SHaavard Skinnemoen * The width of the port and the width of the chips are determined at 347e5b9b47SHaavard Skinnemoen * initialization. These widths are used to calculate the address for 357e5b9b47SHaavard Skinnemoen * access CFI data structures. 3659829cc1SJean-Christophe PLAGNIOL-VILLARD * 3759829cc1SJean-Christophe PLAGNIOL-VILLARD * References 3859829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JESD68 - Common Flash Interface (CFI) 3959829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes 4059829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets 4159829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet 4259829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD CFI Specification, Release 2.0 December 1, 2001 4359829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD/Spansion Application Note: Migration from Single-byte to Three-byte 4459829cc1SJean-Christophe PLAGNIOL-VILLARD * Device IDs, Publication Number 25538 Revision A, November 8, 2001 4559829cc1SJean-Christophe PLAGNIOL-VILLARD * 466d0f6bcfSJean-Christophe PLAGNIOL-VILLARD * Define CONFIG_SYS_WRITE_SWAPPED_DATA, if you have to swap the Bytes between 4759829cc1SJean-Christophe PLAGNIOL-VILLARD * reading and writing ... (yes there is such a Hardware). 4859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 4959829cc1SJean-Christophe PLAGNIOL-VILLARD 5059829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT }; 514ffeab2cSMike Frysinger #ifdef CONFIG_FLASH_CFI_MTD 526ea808efSPiotr Ziecik static uint flash_verbose = 1; 534ffeab2cSMike Frysinger #else 544ffeab2cSMike Frysinger #define flash_verbose 1 554ffeab2cSMike Frysinger #endif 5659829cc1SJean-Christophe PLAGNIOL-VILLARD 572a112b23SWolfgang Denk flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */ 582a112b23SWolfgang Denk 5959829cc1SJean-Christophe PLAGNIOL-VILLARD /* 6059829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if chip width is defined. If not, start detecting with 8bit. 6159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 626d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_CFI_WIDTH 636d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_8BIT 6459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 6559829cc1SJean-Christophe PLAGNIOL-VILLARD 666f726f95SStefan Roese /* 676f726f95SStefan Roese * 0xffff is an undefined value for the configuration register. When 686f726f95SStefan Roese * this value is returned, the configuration register shall not be 696f726f95SStefan Roese * written at all (default mode). 706f726f95SStefan Roese */ 716f726f95SStefan Roese static u16 cfi_flash_config_reg(int i) 726f726f95SStefan Roese { 736f726f95SStefan Roese #ifdef CONFIG_SYS_CFI_FLASH_CONFIG_REGS 746f726f95SStefan Roese return ((u16 [])CONFIG_SYS_CFI_FLASH_CONFIG_REGS)[i]; 756f726f95SStefan Roese #else 766f726f95SStefan Roese return 0xffff; 776f726f95SStefan Roese #endif 786f726f95SStefan Roese } 796f726f95SStefan Roese 80ca5def3fSStefan Roese #if defined(CONFIG_SYS_MAX_FLASH_BANKS_DETECT) 81ca5def3fSStefan Roese int cfi_flash_num_flash_banks = CONFIG_SYS_MAX_FLASH_BANKS_DETECT; 82ca5def3fSStefan Roese #endif 83ca5def3fSStefan Roese 84b00e19ccSStefan Roese static phys_addr_t __cfi_flash_bank_addr(int i) 85b00e19ccSStefan Roese { 86b00e19ccSStefan Roese return ((phys_addr_t [])CONFIG_SYS_FLASH_BANKS_LIST)[i]; 87b00e19ccSStefan Roese } 88b00e19ccSStefan Roese phys_addr_t cfi_flash_bank_addr(int i) 89b00e19ccSStefan Roese __attribute__((weak, alias("__cfi_flash_bank_addr"))); 90b00e19ccSStefan Roese 91ec50a8e3SIlya Yanok static unsigned long __cfi_flash_bank_size(int i) 92ec50a8e3SIlya Yanok { 93ec50a8e3SIlya Yanok #ifdef CONFIG_SYS_FLASH_BANKS_SIZES 94ec50a8e3SIlya Yanok return ((unsigned long [])CONFIG_SYS_FLASH_BANKS_SIZES)[i]; 95ec50a8e3SIlya Yanok #else 96ec50a8e3SIlya Yanok return 0; 97ec50a8e3SIlya Yanok #endif 98ec50a8e3SIlya Yanok } 99ec50a8e3SIlya Yanok unsigned long cfi_flash_bank_size(int i) 100ec50a8e3SIlya Yanok __attribute__((weak, alias("__cfi_flash_bank_size"))); 101ec50a8e3SIlya Yanok 10245aa5a7fSStefan Roese static void __flash_write8(u8 value, void *addr) 103cdbaefb5SHaavard Skinnemoen { 104cdbaefb5SHaavard Skinnemoen __raw_writeb(value, addr); 105cdbaefb5SHaavard Skinnemoen } 106cdbaefb5SHaavard Skinnemoen 10745aa5a7fSStefan Roese static void __flash_write16(u16 value, void *addr) 108cdbaefb5SHaavard Skinnemoen { 109cdbaefb5SHaavard Skinnemoen __raw_writew(value, addr); 110cdbaefb5SHaavard Skinnemoen } 111cdbaefb5SHaavard Skinnemoen 11245aa5a7fSStefan Roese static void __flash_write32(u32 value, void *addr) 113cdbaefb5SHaavard Skinnemoen { 114cdbaefb5SHaavard Skinnemoen __raw_writel(value, addr); 115cdbaefb5SHaavard Skinnemoen } 116cdbaefb5SHaavard Skinnemoen 11745aa5a7fSStefan Roese static void __flash_write64(u64 value, void *addr) 118cdbaefb5SHaavard Skinnemoen { 119cdbaefb5SHaavard Skinnemoen /* No architectures currently implement __raw_writeq() */ 120cdbaefb5SHaavard Skinnemoen *(volatile u64 *)addr = value; 121cdbaefb5SHaavard Skinnemoen } 122cdbaefb5SHaavard Skinnemoen 12345aa5a7fSStefan Roese static u8 __flash_read8(void *addr) 124cdbaefb5SHaavard Skinnemoen { 125cdbaefb5SHaavard Skinnemoen return __raw_readb(addr); 126cdbaefb5SHaavard Skinnemoen } 127cdbaefb5SHaavard Skinnemoen 12845aa5a7fSStefan Roese static u16 __flash_read16(void *addr) 129cdbaefb5SHaavard Skinnemoen { 130cdbaefb5SHaavard Skinnemoen return __raw_readw(addr); 131cdbaefb5SHaavard Skinnemoen } 132cdbaefb5SHaavard Skinnemoen 13345aa5a7fSStefan Roese static u32 __flash_read32(void *addr) 134cdbaefb5SHaavard Skinnemoen { 135cdbaefb5SHaavard Skinnemoen return __raw_readl(addr); 136cdbaefb5SHaavard Skinnemoen } 137cdbaefb5SHaavard Skinnemoen 13897bf85d7SDaniel Hellstrom static u64 __flash_read64(void *addr) 139cdbaefb5SHaavard Skinnemoen { 140cdbaefb5SHaavard Skinnemoen /* No architectures currently implement __raw_readq() */ 141cdbaefb5SHaavard Skinnemoen return *(volatile u64 *)addr; 142cdbaefb5SHaavard Skinnemoen } 143cdbaefb5SHaavard Skinnemoen 14445aa5a7fSStefan Roese #ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS 14545aa5a7fSStefan Roese void flash_write8(u8 value, void *addr)__attribute__((weak, alias("__flash_write8"))); 14645aa5a7fSStefan Roese void flash_write16(u16 value, void *addr)__attribute__((weak, alias("__flash_write16"))); 14745aa5a7fSStefan Roese void flash_write32(u32 value, void *addr)__attribute__((weak, alias("__flash_write32"))); 14845aa5a7fSStefan Roese void flash_write64(u64 value, void *addr)__attribute__((weak, alias("__flash_write64"))); 14945aa5a7fSStefan Roese u8 flash_read8(void *addr)__attribute__((weak, alias("__flash_read8"))); 15045aa5a7fSStefan Roese u16 flash_read16(void *addr)__attribute__((weak, alias("__flash_read16"))); 15145aa5a7fSStefan Roese u32 flash_read32(void *addr)__attribute__((weak, alias("__flash_read32"))); 15297bf85d7SDaniel Hellstrom u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64"))); 15345aa5a7fSStefan Roese #else 15445aa5a7fSStefan Roese #define flash_write8 __flash_write8 15545aa5a7fSStefan Roese #define flash_write16 __flash_write16 15645aa5a7fSStefan Roese #define flash_write32 __flash_write32 15745aa5a7fSStefan Roese #define flash_write64 __flash_write64 15845aa5a7fSStefan Roese #define flash_read8 __flash_read8 15945aa5a7fSStefan Roese #define flash_read16 __flash_read16 16045aa5a7fSStefan Roese #define flash_read32 __flash_read32 16145aa5a7fSStefan Roese #define flash_read64 __flash_read64 16245aa5a7fSStefan Roese #endif 16397bf85d7SDaniel Hellstrom 164be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 165be60a902SHaavard Skinnemoen */ 1666d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE) 1674f975678SHeiko Schocher flash_info_t *flash_get_info(ulong base) 168be60a902SHaavard Skinnemoen { 169be60a902SHaavard Skinnemoen int i; 17024c185cfSMasahiro Yamada flash_info_t *info; 171be60a902SHaavard Skinnemoen 1726d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { 173be60a902SHaavard Skinnemoen info = &flash_info[i]; 174be60a902SHaavard Skinnemoen if (info->size && info->start[0] <= base && 175be60a902SHaavard Skinnemoen base <= info->start[0] + info->size - 1) 17624c185cfSMasahiro Yamada return info; 177be60a902SHaavard Skinnemoen } 178be60a902SHaavard Skinnemoen 17924c185cfSMasahiro Yamada return NULL; 180be60a902SHaavard Skinnemoen } 18159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 18259829cc1SJean-Christophe PLAGNIOL-VILLARD 18312d30aa7SHaavard Skinnemoen unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect) 18412d30aa7SHaavard Skinnemoen { 18512d30aa7SHaavard Skinnemoen if (sect != (info->sector_count - 1)) 18612d30aa7SHaavard Skinnemoen return info->start[sect + 1] - info->start[sect]; 18712d30aa7SHaavard Skinnemoen else 18812d30aa7SHaavard Skinnemoen return info->start[0] + info->size - info->start[sect]; 18912d30aa7SHaavard Skinnemoen } 19012d30aa7SHaavard Skinnemoen 19159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 19259829cc1SJean-Christophe PLAGNIOL-VILLARD * create an address based on the offset and the port width 19359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 19412d30aa7SHaavard Skinnemoen static inline void * 19512d30aa7SHaavard Skinnemoen flash_map (flash_info_t * info, flash_sect_t sect, uint offset) 19659829cc1SJean-Christophe PLAGNIOL-VILLARD { 197e303be2dSStefan Roese unsigned int byte_offset = offset * info->portwidth; 19812d30aa7SHaavard Skinnemoen 199e303be2dSStefan Roese return (void *)(info->start[sect] + byte_offset); 20012d30aa7SHaavard Skinnemoen } 20112d30aa7SHaavard Skinnemoen 20212d30aa7SHaavard Skinnemoen static inline void flash_unmap(flash_info_t *info, flash_sect_t sect, 20312d30aa7SHaavard Skinnemoen unsigned int offset, void *addr) 20412d30aa7SHaavard Skinnemoen { 20559829cc1SJean-Christophe PLAGNIOL-VILLARD } 20659829cc1SJean-Christophe PLAGNIOL-VILLARD 207be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 208be60a902SHaavard Skinnemoen * make a proper sized command based on the port and chip widths 209be60a902SHaavard Skinnemoen */ 2107288f972SSebastian Siewior static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf) 211be60a902SHaavard Skinnemoen { 212be60a902SHaavard Skinnemoen int i; 21393c56f21SVasiliy Leoenenko int cword_offset; 21493c56f21SVasiliy Leoenenko int cp_offset; 2156d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 216340ccb26SSebastian Siewior u32 cmd_le = cpu_to_le32(cmd); 217340ccb26SSebastian Siewior #endif 21893c56f21SVasiliy Leoenenko uchar val; 219be60a902SHaavard Skinnemoen uchar *cp = (uchar *) cmdbuf; 220be60a902SHaavard Skinnemoen 22193c56f21SVasiliy Leoenenko for (i = info->portwidth; i > 0; i--){ 22293c56f21SVasiliy Leoenenko cword_offset = (info->portwidth-i)%info->chipwidth; 2236d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 22493c56f21SVasiliy Leoenenko cp_offset = info->portwidth - i; 225340ccb26SSebastian Siewior val = *((uchar*)&cmd_le + cword_offset); 226be60a902SHaavard Skinnemoen #else 22793c56f21SVasiliy Leoenenko cp_offset = i - 1; 2287288f972SSebastian Siewior val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1); 229be60a902SHaavard Skinnemoen #endif 2307288f972SSebastian Siewior cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val; 23193c56f21SVasiliy Leoenenko } 232be60a902SHaavard Skinnemoen } 233be60a902SHaavard Skinnemoen 23459829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 23559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 23659829cc1SJean-Christophe PLAGNIOL-VILLARD * Debug support 23759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 2383055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data) 23959829cc1SJean-Christophe PLAGNIOL-VILLARD { 24059829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 24159829cc1SJean-Christophe PLAGNIOL-VILLARD char *cp; 24259829cc1SJean-Christophe PLAGNIOL-VILLARD 243657f2062SWolfgang Denk cp = (char *) &data; 24459829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < 8; i++) 24559829cc1SJean-Christophe PLAGNIOL-VILLARD sprintf (&str[i * 2], "%2.2x", *cp++); 24659829cc1SJean-Christophe PLAGNIOL-VILLARD } 247be60a902SHaavard Skinnemoen 248e23741f4SHaavard Skinnemoen static void flash_printqry (struct cfi_qry *qry) 24959829cc1SJean-Christophe PLAGNIOL-VILLARD { 250e23741f4SHaavard Skinnemoen u8 *p = (u8 *)qry; 25159829cc1SJean-Christophe PLAGNIOL-VILLARD int x, y; 25259829cc1SJean-Christophe PLAGNIOL-VILLARD 253e23741f4SHaavard Skinnemoen for (x = 0; x < sizeof(struct cfi_qry); x += 16) { 254e23741f4SHaavard Skinnemoen debug("%02x : ", x); 255e23741f4SHaavard Skinnemoen for (y = 0; y < 16; y++) 256e23741f4SHaavard Skinnemoen debug("%2.2x ", p[x + y]); 25759829cc1SJean-Christophe PLAGNIOL-VILLARD debug(" "); 25859829cc1SJean-Christophe PLAGNIOL-VILLARD for (y = 0; y < 16; y++) { 259e23741f4SHaavard Skinnemoen unsigned char c = p[x + y]; 260e23741f4SHaavard Skinnemoen if (c >= 0x20 && c <= 0x7e) 261cdbaefb5SHaavard Skinnemoen debug("%c", c); 262e23741f4SHaavard Skinnemoen else 26359829cc1SJean-Christophe PLAGNIOL-VILLARD debug("."); 26459829cc1SJean-Christophe PLAGNIOL-VILLARD } 26559829cc1SJean-Christophe PLAGNIOL-VILLARD debug("\n"); 26659829cc1SJean-Christophe PLAGNIOL-VILLARD } 26759829cc1SJean-Christophe PLAGNIOL-VILLARD } 26859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 26959829cc1SJean-Christophe PLAGNIOL-VILLARD 27059829cc1SJean-Christophe PLAGNIOL-VILLARD 27159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 27259829cc1SJean-Christophe PLAGNIOL-VILLARD * read a character at a port width address 27359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 2743055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset) 27559829cc1SJean-Christophe PLAGNIOL-VILLARD { 27659829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *cp; 27712d30aa7SHaavard Skinnemoen uchar retval; 27859829cc1SJean-Christophe PLAGNIOL-VILLARD 27912d30aa7SHaavard Skinnemoen cp = flash_map (info, 0, offset); 2806d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 28112d30aa7SHaavard Skinnemoen retval = flash_read8(cp); 28259829cc1SJean-Christophe PLAGNIOL-VILLARD #else 28312d30aa7SHaavard Skinnemoen retval = flash_read8(cp + info->portwidth - 1); 28459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 28512d30aa7SHaavard Skinnemoen flash_unmap (info, 0, offset, cp); 28612d30aa7SHaavard Skinnemoen return retval; 28759829cc1SJean-Christophe PLAGNIOL-VILLARD } 28859829cc1SJean-Christophe PLAGNIOL-VILLARD 28959829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 29090447ecbSTor Krill * read a word at a port width address, assume 16bit bus 29190447ecbSTor Krill */ 29290447ecbSTor Krill static inline ushort flash_read_word (flash_info_t * info, uint offset) 29390447ecbSTor Krill { 29490447ecbSTor Krill ushort *addr, retval; 29590447ecbSTor Krill 29690447ecbSTor Krill addr = flash_map (info, 0, offset); 29790447ecbSTor Krill retval = flash_read16 (addr); 29890447ecbSTor Krill flash_unmap (info, 0, offset, addr); 29990447ecbSTor Krill return retval; 30090447ecbSTor Krill } 30190447ecbSTor Krill 30290447ecbSTor Krill 30390447ecbSTor Krill /*----------------------------------------------------------------------- 30459829cc1SJean-Christophe PLAGNIOL-VILLARD * read a long word by picking the least significant byte of each maximum 30559829cc1SJean-Christophe PLAGNIOL-VILLARD * port size word. Swap for ppc format. 30659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3073055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect, 3083055793bSHaavard Skinnemoen uint offset) 30959829cc1SJean-Christophe PLAGNIOL-VILLARD { 31059829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *addr; 31159829cc1SJean-Christophe PLAGNIOL-VILLARD ulong retval; 31259829cc1SJean-Christophe PLAGNIOL-VILLARD 31359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 31459829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 31559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 31612d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 31759829cc1SJean-Christophe PLAGNIOL-VILLARD 31859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 31959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("long addr is at %p info->portwidth = %d\n", addr, 32059829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth); 32159829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 4 * info->portwidth; x++) { 32212d30aa7SHaavard Skinnemoen debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x)); 32359829cc1SJean-Christophe PLAGNIOL-VILLARD } 32459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 3256d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 32612d30aa7SHaavard Skinnemoen retval = ((flash_read8(addr) << 16) | 32712d30aa7SHaavard Skinnemoen (flash_read8(addr + info->portwidth) << 24) | 32812d30aa7SHaavard Skinnemoen (flash_read8(addr + 2 * info->portwidth)) | 32912d30aa7SHaavard Skinnemoen (flash_read8(addr + 3 * info->portwidth) << 8)); 33059829cc1SJean-Christophe PLAGNIOL-VILLARD #else 33112d30aa7SHaavard Skinnemoen retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) | 33212d30aa7SHaavard Skinnemoen (flash_read8(addr + info->portwidth - 1) << 16) | 33312d30aa7SHaavard Skinnemoen (flash_read8(addr + 4 * info->portwidth - 1) << 8) | 33412d30aa7SHaavard Skinnemoen (flash_read8(addr + 3 * info->portwidth - 1))); 33559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 33612d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 33712d30aa7SHaavard Skinnemoen 33859829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 33959829cc1SJean-Christophe PLAGNIOL-VILLARD } 34059829cc1SJean-Christophe PLAGNIOL-VILLARD 341be60a902SHaavard Skinnemoen /* 342be60a902SHaavard Skinnemoen * Write a proper sized command to the correct address 34381b20cccSMichael Schwingen */ 344fa36ae79SStefan Roese void flash_write_cmd (flash_info_t * info, flash_sect_t sect, 3457288f972SSebastian Siewior uint offset, u32 cmd) 34681b20cccSMichael Schwingen { 3477e5b9b47SHaavard Skinnemoen 348cdbaefb5SHaavard Skinnemoen void *addr; 349be60a902SHaavard Skinnemoen cfiword_t cword; 35081b20cccSMichael Schwingen 35112d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 352be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 353be60a902SHaavard Skinnemoen switch (info->portwidth) { 354be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 355cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd, 356be60a902SHaavard Skinnemoen cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 357cdbaefb5SHaavard Skinnemoen flash_write8(cword.c, addr); 358be60a902SHaavard Skinnemoen break; 359be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 360cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr, 361be60a902SHaavard Skinnemoen cmd, cword.w, 362be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 363cdbaefb5SHaavard Skinnemoen flash_write16(cword.w, addr); 364be60a902SHaavard Skinnemoen break; 365be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 366cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr, 367be60a902SHaavard Skinnemoen cmd, cword.l, 368be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 369cdbaefb5SHaavard Skinnemoen flash_write32(cword.l, addr); 370be60a902SHaavard Skinnemoen break; 371be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 372be60a902SHaavard Skinnemoen #ifdef DEBUG 373be60a902SHaavard Skinnemoen { 374be60a902SHaavard Skinnemoen char str[20]; 375be60a902SHaavard Skinnemoen 376be60a902SHaavard Skinnemoen print_longlong (str, cword.ll); 377be60a902SHaavard Skinnemoen 378be60a902SHaavard Skinnemoen debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n", 379cdbaefb5SHaavard Skinnemoen addr, cmd, str, 380be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 38181b20cccSMichael Schwingen } 382be60a902SHaavard Skinnemoen #endif 383cdbaefb5SHaavard Skinnemoen flash_write64(cword.ll, addr); 38481b20cccSMichael Schwingen break; 38581b20cccSMichael Schwingen } 386be60a902SHaavard Skinnemoen 387be60a902SHaavard Skinnemoen /* Ensure all the instructions are fully finished */ 388be60a902SHaavard Skinnemoen sync(); 38912d30aa7SHaavard Skinnemoen 39012d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 39181b20cccSMichael Schwingen } 3927e5b9b47SHaavard Skinnemoen 393be60a902SHaavard Skinnemoen static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect) 394be60a902SHaavard Skinnemoen { 395be60a902SHaavard Skinnemoen flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START); 396be60a902SHaavard Skinnemoen flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK); 397be60a902SHaavard Skinnemoen } 398be60a902SHaavard Skinnemoen 399be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 400be60a902SHaavard Skinnemoen */ 401be60a902SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect, 402be60a902SHaavard Skinnemoen uint offset, uchar cmd) 403be60a902SHaavard Skinnemoen { 404cdbaefb5SHaavard Skinnemoen void *addr; 405be60a902SHaavard Skinnemoen cfiword_t cword; 406be60a902SHaavard Skinnemoen int retval; 407be60a902SHaavard Skinnemoen 40812d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 409be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 410be60a902SHaavard Skinnemoen 411cdbaefb5SHaavard Skinnemoen debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr); 412be60a902SHaavard Skinnemoen switch (info->portwidth) { 413be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 414cdbaefb5SHaavard Skinnemoen debug ("is= %x %x\n", flash_read8(addr), cword.c); 415cdbaefb5SHaavard Skinnemoen retval = (flash_read8(addr) == cword.c); 416be60a902SHaavard Skinnemoen break; 417be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 418cdbaefb5SHaavard Skinnemoen debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w); 419cdbaefb5SHaavard Skinnemoen retval = (flash_read16(addr) == cword.w); 420be60a902SHaavard Skinnemoen break; 421be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 42252514699SAndrew Klossner debug ("is= %8.8x %8.8lx\n", flash_read32(addr), cword.l); 423cdbaefb5SHaavard Skinnemoen retval = (flash_read32(addr) == cword.l); 424be60a902SHaavard Skinnemoen break; 425be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 426be60a902SHaavard Skinnemoen #ifdef DEBUG 427be60a902SHaavard Skinnemoen { 428be60a902SHaavard Skinnemoen char str1[20]; 429be60a902SHaavard Skinnemoen char str2[20]; 430be60a902SHaavard Skinnemoen 431cdbaefb5SHaavard Skinnemoen print_longlong (str1, flash_read64(addr)); 432be60a902SHaavard Skinnemoen print_longlong (str2, cword.ll); 433be60a902SHaavard Skinnemoen debug ("is= %s %s\n", str1, str2); 434be60a902SHaavard Skinnemoen } 435be60a902SHaavard Skinnemoen #endif 436cdbaefb5SHaavard Skinnemoen retval = (flash_read64(addr) == cword.ll); 437be60a902SHaavard Skinnemoen break; 438be60a902SHaavard Skinnemoen default: 439be60a902SHaavard Skinnemoen retval = 0; 440be60a902SHaavard Skinnemoen break; 441be60a902SHaavard Skinnemoen } 44212d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 44312d30aa7SHaavard Skinnemoen 444be60a902SHaavard Skinnemoen return retval; 445be60a902SHaavard Skinnemoen } 446be60a902SHaavard Skinnemoen 447be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 448be60a902SHaavard Skinnemoen */ 449be60a902SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect, 450be60a902SHaavard Skinnemoen uint offset, uchar cmd) 451be60a902SHaavard Skinnemoen { 452cdbaefb5SHaavard Skinnemoen void *addr; 453be60a902SHaavard Skinnemoen cfiword_t cword; 454be60a902SHaavard Skinnemoen int retval; 455be60a902SHaavard Skinnemoen 45612d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 457be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 458be60a902SHaavard Skinnemoen switch (info->portwidth) { 459be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 460cdbaefb5SHaavard Skinnemoen retval = ((flash_read8(addr) & cword.c) == cword.c); 461be60a902SHaavard Skinnemoen break; 462be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 463cdbaefb5SHaavard Skinnemoen retval = ((flash_read16(addr) & cword.w) == cword.w); 464be60a902SHaavard Skinnemoen break; 465be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 46647cc23cbSStefan Roese retval = ((flash_read32(addr) & cword.l) == cword.l); 467be60a902SHaavard Skinnemoen break; 468be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 469cdbaefb5SHaavard Skinnemoen retval = ((flash_read64(addr) & cword.ll) == cword.ll); 470be60a902SHaavard Skinnemoen break; 471be60a902SHaavard Skinnemoen default: 472be60a902SHaavard Skinnemoen retval = 0; 473be60a902SHaavard Skinnemoen break; 474be60a902SHaavard Skinnemoen } 47512d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 47612d30aa7SHaavard Skinnemoen 477be60a902SHaavard Skinnemoen return retval; 478be60a902SHaavard Skinnemoen } 479be60a902SHaavard Skinnemoen 480be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 481be60a902SHaavard Skinnemoen */ 482be60a902SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect, 483be60a902SHaavard Skinnemoen uint offset, uchar cmd) 484be60a902SHaavard Skinnemoen { 485cdbaefb5SHaavard Skinnemoen void *addr; 486be60a902SHaavard Skinnemoen cfiword_t cword; 487be60a902SHaavard Skinnemoen int retval; 488be60a902SHaavard Skinnemoen 48912d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 490be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 491be60a902SHaavard Skinnemoen switch (info->portwidth) { 492be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 493fb8c061eSStefan Roese retval = flash_read8(addr) != flash_read8(addr); 494be60a902SHaavard Skinnemoen break; 495be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 496fb8c061eSStefan Roese retval = flash_read16(addr) != flash_read16(addr); 497be60a902SHaavard Skinnemoen break; 498be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 499fb8c061eSStefan Roese retval = flash_read32(addr) != flash_read32(addr); 500be60a902SHaavard Skinnemoen break; 501be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 5029abda6baSWolfgang Denk retval = ( (flash_read32( addr ) != flash_read32( addr )) || 5039abda6baSWolfgang Denk (flash_read32(addr+4) != flash_read32(addr+4)) ); 504be60a902SHaavard Skinnemoen break; 505be60a902SHaavard Skinnemoen default: 506be60a902SHaavard Skinnemoen retval = 0; 507be60a902SHaavard Skinnemoen break; 508be60a902SHaavard Skinnemoen } 50912d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 51012d30aa7SHaavard Skinnemoen 511be60a902SHaavard Skinnemoen return retval; 512be60a902SHaavard Skinnemoen } 513be60a902SHaavard Skinnemoen 514be60a902SHaavard Skinnemoen /* 515be60a902SHaavard Skinnemoen * flash_is_busy - check to see if the flash is busy 516be60a902SHaavard Skinnemoen * 517be60a902SHaavard Skinnemoen * This routine checks the status of the chip and returns true if the 518be60a902SHaavard Skinnemoen * chip is busy. 519be60a902SHaavard Skinnemoen */ 520be60a902SHaavard Skinnemoen static int flash_is_busy (flash_info_t * info, flash_sect_t sect) 521be60a902SHaavard Skinnemoen { 522be60a902SHaavard Skinnemoen int retval; 523be60a902SHaavard Skinnemoen 52481b20cccSMichael Schwingen switch (info->vendor) { 5259c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 52681b20cccSMichael Schwingen case CFI_CMDSET_INTEL_STANDARD: 52781b20cccSMichael Schwingen case CFI_CMDSET_INTEL_EXTENDED: 528be60a902SHaavard Skinnemoen retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); 52981b20cccSMichael Schwingen break; 53081b20cccSMichael Schwingen case CFI_CMDSET_AMD_STANDARD: 53181b20cccSMichael Schwingen case CFI_CMDSET_AMD_EXTENDED: 532be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 53381b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 534be60a902SHaavard Skinnemoen #endif 535be60a902SHaavard Skinnemoen retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); 536be60a902SHaavard Skinnemoen break; 537be60a902SHaavard Skinnemoen default: 538be60a902SHaavard Skinnemoen retval = 0; 539be60a902SHaavard Skinnemoen } 540be60a902SHaavard Skinnemoen debug ("flash_is_busy: %d\n", retval); 541be60a902SHaavard Skinnemoen return retval; 542be60a902SHaavard Skinnemoen } 543be60a902SHaavard Skinnemoen 544be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 545be60a902SHaavard Skinnemoen * wait for XSR.7 to be set. Time out with an error if it does not. 546be60a902SHaavard Skinnemoen * This routine does not set the flash to read-array mode. 547be60a902SHaavard Skinnemoen */ 548be60a902SHaavard Skinnemoen static int flash_status_check (flash_info_t * info, flash_sect_t sector, 549be60a902SHaavard Skinnemoen ulong tout, char *prompt) 550be60a902SHaavard Skinnemoen { 551be60a902SHaavard Skinnemoen ulong start; 552be60a902SHaavard Skinnemoen 5536d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if CONFIG_SYS_HZ != 1000 554c40c94a3SRenato Andreola if ((ulong)CONFIG_SYS_HZ > 100000) 555c40c94a3SRenato Andreola tout *= (ulong)CONFIG_SYS_HZ / 1000; /* for a big HZ, avoid overflow */ 556c40c94a3SRenato Andreola else 557c40c94a3SRenato Andreola tout = DIV_ROUND_UP(tout * (ulong)CONFIG_SYS_HZ, 1000); 558be60a902SHaavard Skinnemoen #endif 559be60a902SHaavard Skinnemoen 560be60a902SHaavard Skinnemoen /* Wait for command completion */ 561e110c4feSGraeme Russ #ifdef CONFIG_SYS_LOW_RES_TIMER 56222d6c8faSThomas Chou reset_timer(); 563e110c4feSGraeme Russ #endif 564be60a902SHaavard Skinnemoen start = get_timer (0); 565a9f5fabaSJens Scharsig (BuS Elektronik) WATCHDOG_RESET(); 566be60a902SHaavard Skinnemoen while (flash_is_busy (info, sector)) { 567be60a902SHaavard Skinnemoen if (get_timer (start) > tout) { 568be60a902SHaavard Skinnemoen printf ("Flash %s timeout at address %lx data %lx\n", 569be60a902SHaavard Skinnemoen prompt, info->start[sector], 570be60a902SHaavard Skinnemoen flash_read_long (info, sector, 0)); 571be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, info->cmd_reset); 572e303be2dSStefan Roese udelay(1); 573be60a902SHaavard Skinnemoen return ERR_TIMOUT; 574be60a902SHaavard Skinnemoen } 575be60a902SHaavard Skinnemoen udelay (1); /* also triggers watchdog */ 576be60a902SHaavard Skinnemoen } 577be60a902SHaavard Skinnemoen return ERR_OK; 578be60a902SHaavard Skinnemoen } 579be60a902SHaavard Skinnemoen 580be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 581be60a902SHaavard Skinnemoen * Wait for XSR.7 to be set, if it times out print an error, otherwise 582be60a902SHaavard Skinnemoen * do a full status check. 583be60a902SHaavard Skinnemoen * 584be60a902SHaavard Skinnemoen * This routine sets the flash to read-array mode. 585be60a902SHaavard Skinnemoen */ 586be60a902SHaavard Skinnemoen static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, 587be60a902SHaavard Skinnemoen ulong tout, char *prompt) 588be60a902SHaavard Skinnemoen { 589be60a902SHaavard Skinnemoen int retcode; 590be60a902SHaavard Skinnemoen 591be60a902SHaavard Skinnemoen retcode = flash_status_check (info, sector, tout, prompt); 592be60a902SHaavard Skinnemoen switch (info->vendor) { 5939c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 594be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 595be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 5960d01f66dSEd Swarthout if ((retcode != ERR_OK) 597be60a902SHaavard Skinnemoen && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { 598be60a902SHaavard Skinnemoen retcode = ERR_INVAL; 599be60a902SHaavard Skinnemoen printf ("Flash %s error at address %lx\n", prompt, 600be60a902SHaavard Skinnemoen info->start[sector]); 601be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | 602be60a902SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 603be60a902SHaavard Skinnemoen puts ("Command Sequence Error.\n"); 604be60a902SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 605be60a902SHaavard Skinnemoen FLASH_STATUS_ECLBS)) { 606be60a902SHaavard Skinnemoen puts ("Block Erase Error.\n"); 607be60a902SHaavard Skinnemoen retcode = ERR_NOT_ERASED; 608be60a902SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 609be60a902SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 610be60a902SHaavard Skinnemoen puts ("Locking Error\n"); 611be60a902SHaavard Skinnemoen } 612be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { 613be60a902SHaavard Skinnemoen puts ("Block locked.\n"); 614be60a902SHaavard Skinnemoen retcode = ERR_PROTECTED; 615be60a902SHaavard Skinnemoen } 616be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) 617be60a902SHaavard Skinnemoen puts ("Vpp Low Error.\n"); 618be60a902SHaavard Skinnemoen } 619be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, info->cmd_reset); 620a90b9575SAaron Williams udelay(1); 621be60a902SHaavard Skinnemoen break; 622be60a902SHaavard Skinnemoen default: 62381b20cccSMichael Schwingen break; 62481b20cccSMichael Schwingen } 625be60a902SHaavard Skinnemoen return retcode; 62681b20cccSMichael Schwingen } 627be60a902SHaavard Skinnemoen 628e5720823SThomas Chou static int use_flash_status_poll(flash_info_t *info) 629e5720823SThomas Chou { 630e5720823SThomas Chou #ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL 631e5720823SThomas Chou if (info->vendor == CFI_CMDSET_AMD_EXTENDED || 632e5720823SThomas Chou info->vendor == CFI_CMDSET_AMD_STANDARD) 633e5720823SThomas Chou return 1; 634e5720823SThomas Chou #endif 635e5720823SThomas Chou return 0; 636e5720823SThomas Chou } 637e5720823SThomas Chou 638e5720823SThomas Chou static int flash_status_poll(flash_info_t *info, void *src, void *dst, 639e5720823SThomas Chou ulong tout, char *prompt) 640e5720823SThomas Chou { 641e5720823SThomas Chou #ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL 642e5720823SThomas Chou ulong start; 643e5720823SThomas Chou int ready; 644e5720823SThomas Chou 645e5720823SThomas Chou #if CONFIG_SYS_HZ != 1000 646e5720823SThomas Chou if ((ulong)CONFIG_SYS_HZ > 100000) 647e5720823SThomas Chou tout *= (ulong)CONFIG_SYS_HZ / 1000; /* for a big HZ, avoid overflow */ 648e5720823SThomas Chou else 649e5720823SThomas Chou tout = DIV_ROUND_UP(tout * (ulong)CONFIG_SYS_HZ, 1000); 650e5720823SThomas Chou #endif 651e5720823SThomas Chou 652e5720823SThomas Chou /* Wait for command completion */ 653e110c4feSGraeme Russ #ifdef CONFIG_SYS_LOW_RES_TIMER 65422d6c8faSThomas Chou reset_timer(); 655e110c4feSGraeme Russ #endif 656e5720823SThomas Chou start = get_timer(0); 657a9f5fabaSJens Scharsig (BuS Elektronik) WATCHDOG_RESET(); 658e5720823SThomas Chou while (1) { 659e5720823SThomas Chou switch (info->portwidth) { 660e5720823SThomas Chou case FLASH_CFI_8BIT: 661e5720823SThomas Chou ready = flash_read8(dst) == flash_read8(src); 662e5720823SThomas Chou break; 663e5720823SThomas Chou case FLASH_CFI_16BIT: 664e5720823SThomas Chou ready = flash_read16(dst) == flash_read16(src); 665e5720823SThomas Chou break; 666e5720823SThomas Chou case FLASH_CFI_32BIT: 667e5720823SThomas Chou ready = flash_read32(dst) == flash_read32(src); 668e5720823SThomas Chou break; 669e5720823SThomas Chou case FLASH_CFI_64BIT: 670e5720823SThomas Chou ready = flash_read64(dst) == flash_read64(src); 671e5720823SThomas Chou break; 672e5720823SThomas Chou default: 673e5720823SThomas Chou ready = 0; 674e5720823SThomas Chou break; 675e5720823SThomas Chou } 676e5720823SThomas Chou if (ready) 677e5720823SThomas Chou break; 678e5720823SThomas Chou if (get_timer(start) > tout) { 679e5720823SThomas Chou printf("Flash %s timeout at address %lx data %lx\n", 680e5720823SThomas Chou prompt, (ulong)dst, (ulong)flash_read8(dst)); 681e5720823SThomas Chou return ERR_TIMOUT; 682e5720823SThomas Chou } 683e5720823SThomas Chou udelay(1); /* also triggers watchdog */ 684e5720823SThomas Chou } 685e5720823SThomas Chou #endif /* CONFIG_SYS_CFI_FLASH_STATUS_POLL */ 686e5720823SThomas Chou return ERR_OK; 687e5720823SThomas Chou } 688e5720823SThomas Chou 689be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 690be60a902SHaavard Skinnemoen */ 691be60a902SHaavard Skinnemoen static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) 692be60a902SHaavard Skinnemoen { 6936d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 694be60a902SHaavard Skinnemoen unsigned short w; 695be60a902SHaavard Skinnemoen unsigned int l; 696be60a902SHaavard Skinnemoen unsigned long long ll; 697be60a902SHaavard Skinnemoen #endif 698be60a902SHaavard Skinnemoen 699be60a902SHaavard Skinnemoen switch (info->portwidth) { 700be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 701be60a902SHaavard Skinnemoen cword->c = c; 702be60a902SHaavard Skinnemoen break; 703be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 7046d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 705be60a902SHaavard Skinnemoen w = c; 706be60a902SHaavard Skinnemoen w <<= 8; 707be60a902SHaavard Skinnemoen cword->w = (cword->w >> 8) | w; 70881b20cccSMichael Schwingen #else 709be60a902SHaavard Skinnemoen cword->w = (cword->w << 8) | c; 710be60a902SHaavard Skinnemoen #endif 711be60a902SHaavard Skinnemoen break; 712be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 7136d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 714be60a902SHaavard Skinnemoen l = c; 715be60a902SHaavard Skinnemoen l <<= 24; 716be60a902SHaavard Skinnemoen cword->l = (cword->l >> 8) | l; 717be60a902SHaavard Skinnemoen #else 718be60a902SHaavard Skinnemoen cword->l = (cword->l << 8) | c; 719be60a902SHaavard Skinnemoen #endif 720be60a902SHaavard Skinnemoen break; 721be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 7226d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 723be60a902SHaavard Skinnemoen ll = c; 724be60a902SHaavard Skinnemoen ll <<= 56; 725be60a902SHaavard Skinnemoen cword->ll = (cword->ll >> 8) | ll; 726be60a902SHaavard Skinnemoen #else 727be60a902SHaavard Skinnemoen cword->ll = (cword->ll << 8) | c; 728be60a902SHaavard Skinnemoen #endif 729be60a902SHaavard Skinnemoen break; 730be60a902SHaavard Skinnemoen } 731be60a902SHaavard Skinnemoen } 732be60a902SHaavard Skinnemoen 7330f8e851eSJens Gehrlein /* 7340f8e851eSJens Gehrlein * Loop through the sector table starting from the previously found sector. 7350f8e851eSJens Gehrlein * Searches forwards or backwards, dependent on the passed address. 736be60a902SHaavard Skinnemoen */ 737be60a902SHaavard Skinnemoen static flash_sect_t find_sector (flash_info_t * info, ulong addr) 73881b20cccSMichael Schwingen { 73911dc4010SKim Phillips static flash_sect_t saved_sector; /* previously found sector */ 740e303be2dSStefan Roese static flash_info_t *saved_info; /* previously used flash bank */ 7410f8e851eSJens Gehrlein flash_sect_t sector = saved_sector; 742be60a902SHaavard Skinnemoen 743e303be2dSStefan Roese if ((info != saved_info) || (sector >= info->sector_count)) 744e303be2dSStefan Roese sector = 0; 745e303be2dSStefan Roese 7460f8e851eSJens Gehrlein while ((info->start[sector] < addr) 7470f8e851eSJens Gehrlein && (sector < info->sector_count - 1)) 7480f8e851eSJens Gehrlein sector++; 7490f8e851eSJens Gehrlein while ((info->start[sector] > addr) && (sector > 0)) 7500f8e851eSJens Gehrlein /* 7510f8e851eSJens Gehrlein * also decrements the sector in case of an overshot 7520f8e851eSJens Gehrlein * in the first loop 7530f8e851eSJens Gehrlein */ 7540f8e851eSJens Gehrlein sector--; 7550f8e851eSJens Gehrlein 7560f8e851eSJens Gehrlein saved_sector = sector; 757e303be2dSStefan Roese saved_info = info; 758be60a902SHaavard Skinnemoen return sector; 75959829cc1SJean-Christophe PLAGNIOL-VILLARD } 76059829cc1SJean-Christophe PLAGNIOL-VILLARD 76159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 76259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 763be60a902SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest, 764be60a902SHaavard Skinnemoen cfiword_t cword) 76559829cc1SJean-Christophe PLAGNIOL-VILLARD { 76609ce9921SBecky Bruce void *dstaddr = (void *)dest; 767be60a902SHaavard Skinnemoen int flag; 768a7292871SJens Gehrlein flash_sect_t sect = 0; 769a7292871SJens Gehrlein char sect_found = 0; 77059829cc1SJean-Christophe PLAGNIOL-VILLARD 771be60a902SHaavard Skinnemoen /* Check if Flash is (sufficiently) erased */ 772be60a902SHaavard Skinnemoen switch (info->portwidth) { 773be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 774cdbaefb5SHaavard Skinnemoen flag = ((flash_read8(dstaddr) & cword.c) == cword.c); 775be60a902SHaavard Skinnemoen break; 776be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 777cdbaefb5SHaavard Skinnemoen flag = ((flash_read16(dstaddr) & cword.w) == cword.w); 778be60a902SHaavard Skinnemoen break; 779be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 780cdbaefb5SHaavard Skinnemoen flag = ((flash_read32(dstaddr) & cword.l) == cword.l); 781be60a902SHaavard Skinnemoen break; 782be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 783cdbaefb5SHaavard Skinnemoen flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll); 784be60a902SHaavard Skinnemoen break; 785be60a902SHaavard Skinnemoen default: 78612d30aa7SHaavard Skinnemoen flag = 0; 78712d30aa7SHaavard Skinnemoen break; 78812d30aa7SHaavard Skinnemoen } 78909ce9921SBecky Bruce if (!flag) 7900dc80e27SStefan Roese return ERR_NOT_ERASED; 791be60a902SHaavard Skinnemoen 792be60a902SHaavard Skinnemoen /* Disable interrupts which might cause a timeout here */ 793be60a902SHaavard Skinnemoen flag = disable_interrupts (); 794be60a902SHaavard Skinnemoen 795be60a902SHaavard Skinnemoen switch (info->vendor) { 7969c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 797be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 798be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 799be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); 800be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE); 801be60a902SHaavard Skinnemoen break; 802be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 803be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 8040d01f66dSEd Swarthout sect = find_sector(info, dest); 8050d01f66dSEd Swarthout flash_unlock_seq (info, sect); 8060d01f66dSEd Swarthout flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE); 807a7292871SJens Gehrlein sect_found = 1; 80859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 809b4db4a76SPo-Yu Chuang #ifdef CONFIG_FLASH_CFI_LEGACY 810b4db4a76SPo-Yu Chuang case CFI_CMDSET_AMD_LEGACY: 811b4db4a76SPo-Yu Chuang sect = find_sector(info, dest); 812b4db4a76SPo-Yu Chuang flash_unlock_seq (info, 0); 813b4db4a76SPo-Yu Chuang flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE); 814b4db4a76SPo-Yu Chuang sect_found = 1; 815b4db4a76SPo-Yu Chuang break; 816b4db4a76SPo-Yu Chuang #endif 81759829cc1SJean-Christophe PLAGNIOL-VILLARD } 81859829cc1SJean-Christophe PLAGNIOL-VILLARD 819be60a902SHaavard Skinnemoen switch (info->portwidth) { 820be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 821cdbaefb5SHaavard Skinnemoen flash_write8(cword.c, dstaddr); 822be60a902SHaavard Skinnemoen break; 823be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 824cdbaefb5SHaavard Skinnemoen flash_write16(cword.w, dstaddr); 825be60a902SHaavard Skinnemoen break; 826be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 827cdbaefb5SHaavard Skinnemoen flash_write32(cword.l, dstaddr); 828be60a902SHaavard Skinnemoen break; 829be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 830cdbaefb5SHaavard Skinnemoen flash_write64(cword.ll, dstaddr); 831be60a902SHaavard Skinnemoen break; 83259829cc1SJean-Christophe PLAGNIOL-VILLARD } 833be60a902SHaavard Skinnemoen 834be60a902SHaavard Skinnemoen /* re-enable interrupts if necessary */ 835be60a902SHaavard Skinnemoen if (flag) 836be60a902SHaavard Skinnemoen enable_interrupts (); 837be60a902SHaavard Skinnemoen 838a7292871SJens Gehrlein if (!sect_found) 839a7292871SJens Gehrlein sect = find_sector (info, dest); 840a7292871SJens Gehrlein 841e5720823SThomas Chou if (use_flash_status_poll(info)) 842e5720823SThomas Chou return flash_status_poll(info, &cword, dstaddr, 843e5720823SThomas Chou info->write_tout, "write"); 844e5720823SThomas Chou else 845e5720823SThomas Chou return flash_full_status_check(info, sect, 846e5720823SThomas Chou info->write_tout, "write"); 847be60a902SHaavard Skinnemoen } 848be60a902SHaavard Skinnemoen 8496d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE 850be60a902SHaavard Skinnemoen 851be60a902SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, 852be60a902SHaavard Skinnemoen int len) 853be60a902SHaavard Skinnemoen { 854be60a902SHaavard Skinnemoen flash_sect_t sector; 855be60a902SHaavard Skinnemoen int cnt; 856be60a902SHaavard Skinnemoen int retcode; 857cdbaefb5SHaavard Skinnemoen void *src = cp; 858ec21d5cfSStefan Roese void *dst = (void *)dest; 8590dc80e27SStefan Roese void *dst2 = dst; 86085c344e5STao Hou int flag = 1; 86196ef831fSGuennadi Liakhovetski uint offset = 0; 86296ef831fSGuennadi Liakhovetski unsigned int shift; 8639c048b52SVasiliy Leoenenko uchar write_cmd; 864cdbaefb5SHaavard Skinnemoen 8650dc80e27SStefan Roese switch (info->portwidth) { 8660dc80e27SStefan Roese case FLASH_CFI_8BIT: 86796ef831fSGuennadi Liakhovetski shift = 0; 8680dc80e27SStefan Roese break; 8690dc80e27SStefan Roese case FLASH_CFI_16BIT: 87096ef831fSGuennadi Liakhovetski shift = 1; 8710dc80e27SStefan Roese break; 8720dc80e27SStefan Roese case FLASH_CFI_32BIT: 87396ef831fSGuennadi Liakhovetski shift = 2; 8740dc80e27SStefan Roese break; 8750dc80e27SStefan Roese case FLASH_CFI_64BIT: 87696ef831fSGuennadi Liakhovetski shift = 3; 8770dc80e27SStefan Roese break; 8780dc80e27SStefan Roese default: 8790dc80e27SStefan Roese retcode = ERR_INVAL; 8800dc80e27SStefan Roese goto out_unmap; 8810dc80e27SStefan Roese } 8820dc80e27SStefan Roese 88396ef831fSGuennadi Liakhovetski cnt = len >> shift; 88496ef831fSGuennadi Liakhovetski 88585c344e5STao Hou while ((cnt-- > 0) && (flag == 1)) { 8860dc80e27SStefan Roese switch (info->portwidth) { 8870dc80e27SStefan Roese case FLASH_CFI_8BIT: 8880dc80e27SStefan Roese flag = ((flash_read8(dst2) & flash_read8(src)) == 8890dc80e27SStefan Roese flash_read8(src)); 8900dc80e27SStefan Roese src += 1, dst2 += 1; 8910dc80e27SStefan Roese break; 8920dc80e27SStefan Roese case FLASH_CFI_16BIT: 8930dc80e27SStefan Roese flag = ((flash_read16(dst2) & flash_read16(src)) == 8940dc80e27SStefan Roese flash_read16(src)); 8950dc80e27SStefan Roese src += 2, dst2 += 2; 8960dc80e27SStefan Roese break; 8970dc80e27SStefan Roese case FLASH_CFI_32BIT: 8980dc80e27SStefan Roese flag = ((flash_read32(dst2) & flash_read32(src)) == 8990dc80e27SStefan Roese flash_read32(src)); 9000dc80e27SStefan Roese src += 4, dst2 += 4; 9010dc80e27SStefan Roese break; 9020dc80e27SStefan Roese case FLASH_CFI_64BIT: 9030dc80e27SStefan Roese flag = ((flash_read64(dst2) & flash_read64(src)) == 9040dc80e27SStefan Roese flash_read64(src)); 9050dc80e27SStefan Roese src += 8, dst2 += 8; 9060dc80e27SStefan Roese break; 9070dc80e27SStefan Roese } 9080dc80e27SStefan Roese } 9090dc80e27SStefan Roese if (!flag) { 9100dc80e27SStefan Roese retcode = ERR_NOT_ERASED; 9110dc80e27SStefan Roese goto out_unmap; 9120dc80e27SStefan Roese } 9130dc80e27SStefan Roese 9140dc80e27SStefan Roese src = cp; 915cdbaefb5SHaavard Skinnemoen sector = find_sector (info, dest); 916be60a902SHaavard Skinnemoen 917be60a902SHaavard Skinnemoen switch (info->vendor) { 9189c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 919be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 920be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 9219c048b52SVasiliy Leoenenko write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ? 9229c048b52SVasiliy Leoenenko FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER; 923be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 9249c048b52SVasiliy Leoenenko flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS); 9259c048b52SVasiliy Leoenenko flash_write_cmd (info, sector, 0, write_cmd); 926be60a902SHaavard Skinnemoen retcode = flash_status_check (info, sector, 927be60a902SHaavard Skinnemoen info->buffer_write_tout, 928be60a902SHaavard Skinnemoen "write to buffer"); 929be60a902SHaavard Skinnemoen if (retcode == ERR_OK) { 930be60a902SHaavard Skinnemoen /* reduce the number of loops by the width of 931be60a902SHaavard Skinnemoen * the port */ 93296ef831fSGuennadi Liakhovetski cnt = len >> shift; 93393c56f21SVasiliy Leoenenko flash_write_cmd (info, sector, 0, cnt - 1); 934be60a902SHaavard Skinnemoen while (cnt-- > 0) { 935be60a902SHaavard Skinnemoen switch (info->portwidth) { 936be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 937cdbaefb5SHaavard Skinnemoen flash_write8(flash_read8(src), dst); 938cdbaefb5SHaavard Skinnemoen src += 1, dst += 1; 939be60a902SHaavard Skinnemoen break; 940be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 941cdbaefb5SHaavard Skinnemoen flash_write16(flash_read16(src), dst); 942cdbaefb5SHaavard Skinnemoen src += 2, dst += 2; 943be60a902SHaavard Skinnemoen break; 944be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 945cdbaefb5SHaavard Skinnemoen flash_write32(flash_read32(src), dst); 946cdbaefb5SHaavard Skinnemoen src += 4, dst += 4; 947be60a902SHaavard Skinnemoen break; 948be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 949cdbaefb5SHaavard Skinnemoen flash_write64(flash_read64(src), dst); 950cdbaefb5SHaavard Skinnemoen src += 8, dst += 8; 951be60a902SHaavard Skinnemoen break; 952be60a902SHaavard Skinnemoen default: 95312d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 95412d30aa7SHaavard Skinnemoen goto out_unmap; 955be60a902SHaavard Skinnemoen } 956be60a902SHaavard Skinnemoen } 957be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, 958be60a902SHaavard Skinnemoen FLASH_CMD_WRITE_BUFFER_CONFIRM); 959be60a902SHaavard Skinnemoen retcode = flash_full_status_check ( 960be60a902SHaavard Skinnemoen info, sector, info->buffer_write_tout, 961be60a902SHaavard Skinnemoen "buffer write"); 962be60a902SHaavard Skinnemoen } 96312d30aa7SHaavard Skinnemoen 96412d30aa7SHaavard Skinnemoen break; 965be60a902SHaavard Skinnemoen 966be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 967be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 968be60a902SHaavard Skinnemoen flash_unlock_seq(info,0); 96996ef831fSGuennadi Liakhovetski 97096ef831fSGuennadi Liakhovetski #ifdef CONFIG_FLASH_SPANSION_S29WS_N 97196ef831fSGuennadi Liakhovetski offset = ((unsigned long)dst - info->start[sector]) >> shift; 97296ef831fSGuennadi Liakhovetski #endif 97396ef831fSGuennadi Liakhovetski flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER); 97496ef831fSGuennadi Liakhovetski cnt = len >> shift; 9757dedefdfSJohn Schmoller flash_write_cmd(info, sector, offset, cnt - 1); 976be60a902SHaavard Skinnemoen 977be60a902SHaavard Skinnemoen switch (info->portwidth) { 978be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 979cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 980cdbaefb5SHaavard Skinnemoen flash_write8(flash_read8(src), dst); 981cdbaefb5SHaavard Skinnemoen src += 1, dst += 1; 982cdbaefb5SHaavard Skinnemoen } 983be60a902SHaavard Skinnemoen break; 984be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 985cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 986cdbaefb5SHaavard Skinnemoen flash_write16(flash_read16(src), dst); 987cdbaefb5SHaavard Skinnemoen src += 2, dst += 2; 988cdbaefb5SHaavard Skinnemoen } 989be60a902SHaavard Skinnemoen break; 990be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 991cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 992cdbaefb5SHaavard Skinnemoen flash_write32(flash_read32(src), dst); 993cdbaefb5SHaavard Skinnemoen src += 4, dst += 4; 994cdbaefb5SHaavard Skinnemoen } 995be60a902SHaavard Skinnemoen break; 996be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 997cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 998cdbaefb5SHaavard Skinnemoen flash_write64(flash_read64(src), dst); 999cdbaefb5SHaavard Skinnemoen src += 8, dst += 8; 1000cdbaefb5SHaavard Skinnemoen } 1001be60a902SHaavard Skinnemoen break; 1002be60a902SHaavard Skinnemoen default: 100312d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 100412d30aa7SHaavard Skinnemoen goto out_unmap; 1005be60a902SHaavard Skinnemoen } 1006be60a902SHaavard Skinnemoen 1007be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); 1008e5720823SThomas Chou if (use_flash_status_poll(info)) 1009e5720823SThomas Chou retcode = flash_status_poll(info, src - (1 << shift), 1010e5720823SThomas Chou dst - (1 << shift), 1011e5720823SThomas Chou info->buffer_write_tout, 1012e5720823SThomas Chou "buffer write"); 1013e5720823SThomas Chou else 1014be60a902SHaavard Skinnemoen retcode = flash_full_status_check(info, sector, 1015be60a902SHaavard Skinnemoen info->buffer_write_tout, 1016be60a902SHaavard Skinnemoen "buffer write"); 101712d30aa7SHaavard Skinnemoen break; 1018be60a902SHaavard Skinnemoen 1019be60a902SHaavard Skinnemoen default: 1020be60a902SHaavard Skinnemoen debug ("Unknown Command Set\n"); 102112d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 102212d30aa7SHaavard Skinnemoen break; 1023be60a902SHaavard Skinnemoen } 102412d30aa7SHaavard Skinnemoen 102512d30aa7SHaavard Skinnemoen out_unmap: 102612d30aa7SHaavard Skinnemoen return retcode; 1027be60a902SHaavard Skinnemoen } 10286d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */ 1029be60a902SHaavard Skinnemoen 103059829cc1SJean-Christophe PLAGNIOL-VILLARD 103159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 103259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 103359829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last) 103459829cc1SJean-Christophe PLAGNIOL-VILLARD { 103559829cc1SJean-Christophe PLAGNIOL-VILLARD int rcode = 0; 103659829cc1SJean-Christophe PLAGNIOL-VILLARD int prot; 103759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect; 1038e5720823SThomas Chou int st; 103959829cc1SJean-Christophe PLAGNIOL-VILLARD 104059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 104159829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Can't erase unknown flash type - aborted\n"); 104259829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 104359829cc1SJean-Christophe PLAGNIOL-VILLARD } 104459829cc1SJean-Christophe PLAGNIOL-VILLARD if ((s_first < 0) || (s_first > s_last)) { 104559829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("- no sectors to erase\n"); 104659829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 104759829cc1SJean-Christophe PLAGNIOL-VILLARD } 104859829cc1SJean-Christophe PLAGNIOL-VILLARD 104959829cc1SJean-Christophe PLAGNIOL-VILLARD prot = 0; 105059829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; ++sect) { 105159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect]) { 105259829cc1SJean-Christophe PLAGNIOL-VILLARD prot++; 105359829cc1SJean-Christophe PLAGNIOL-VILLARD } 105459829cc1SJean-Christophe PLAGNIOL-VILLARD } 105559829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) { 10567e5b9b47SHaavard Skinnemoen printf ("- Warning: %d protected sectors will not be erased!\n", 10577e5b9b47SHaavard Skinnemoen prot); 10586ea808efSPiotr Ziecik } else if (flash_verbose) { 105959829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 106059829cc1SJean-Christophe PLAGNIOL-VILLARD } 106159829cc1SJean-Christophe PLAGNIOL-VILLARD 106259829cc1SJean-Christophe PLAGNIOL-VILLARD 106359829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; sect++) { 1064de15a06aSJoe Hershberger if (ctrlc()) { 1065de15a06aSJoe Hershberger printf("\n"); 1066de15a06aSJoe Hershberger return 1; 1067de15a06aSJoe Hershberger } 1068de15a06aSJoe Hershberger 106959829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect] == 0) { /* not protected */ 10706822a647SJoe Hershberger #ifdef CONFIG_SYS_FLASH_CHECK_BLANK_BEFORE_ERASE 10716822a647SJoe Hershberger int k; 10726822a647SJoe Hershberger int size; 10736822a647SJoe Hershberger int erased; 10746822a647SJoe Hershberger u32 *flash; 10756822a647SJoe Hershberger 10766822a647SJoe Hershberger /* 10776822a647SJoe Hershberger * Check if whole sector is erased 10786822a647SJoe Hershberger */ 10796822a647SJoe Hershberger size = flash_sector_size(info, sect); 10806822a647SJoe Hershberger erased = 1; 10816822a647SJoe Hershberger flash = (u32 *)info->start[sect]; 10826822a647SJoe Hershberger /* divide by 4 for longword access */ 10836822a647SJoe Hershberger size = size >> 2; 10846822a647SJoe Hershberger for (k = 0; k < size; k++) { 10856822a647SJoe Hershberger if (flash_read32(flash++) != 0xffffffff) { 10866822a647SJoe Hershberger erased = 0; 10876822a647SJoe Hershberger break; 10886822a647SJoe Hershberger } 10896822a647SJoe Hershberger } 10906822a647SJoe Hershberger if (erased) { 10916822a647SJoe Hershberger if (flash_verbose) 10926822a647SJoe Hershberger putc(','); 10936822a647SJoe Hershberger continue; 10946822a647SJoe Hershberger } 10956822a647SJoe Hershberger #endif 109659829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 10979c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 109859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 109959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 11007e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 11017e5b9b47SHaavard Skinnemoen FLASH_CMD_CLEAR_STATUS); 11027e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 11037e5b9b47SHaavard Skinnemoen FLASH_CMD_BLOCK_ERASE); 11047e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 11057e5b9b47SHaavard Skinnemoen FLASH_CMD_ERASE_CONFIRM); 110659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 110759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 110859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 110959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 11107e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 11117e5b9b47SHaavard Skinnemoen info->addr_unlock1, 11127e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 111359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 11147e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 111507b2c5c0SAngelo Dureghello info->cmd_erase_sector); 111659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 111781b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 111881b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 111981b20cccSMichael Schwingen flash_unlock_seq (info, 0); 11207e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, info->addr_unlock1, 11217e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 112281b20cccSMichael Schwingen flash_unlock_seq (info, 0); 11237e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 11247e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_SECTOR); 112581b20cccSMichael Schwingen break; 112681b20cccSMichael Schwingen #endif 112759829cc1SJean-Christophe PLAGNIOL-VILLARD default: 112859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("Unkown flash vendor %d\n", 112959829cc1SJean-Christophe PLAGNIOL-VILLARD info->vendor); 113059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 113159829cc1SJean-Christophe PLAGNIOL-VILLARD } 113259829cc1SJean-Christophe PLAGNIOL-VILLARD 1133e5720823SThomas Chou if (use_flash_status_poll(info)) { 113411dc4010SKim Phillips cfiword_t cword; 1135e5720823SThomas Chou void *dest; 113611dc4010SKim Phillips cword.ll = 0xffffffffffffffffULL; 1137e5720823SThomas Chou dest = flash_map(info, sect, 0); 1138e5720823SThomas Chou st = flash_status_poll(info, &cword, dest, 1139e5720823SThomas Chou info->erase_blk_tout, "erase"); 1140e5720823SThomas Chou flash_unmap(info, sect, 0, dest); 1141e5720823SThomas Chou } else 1142e5720823SThomas Chou st = flash_full_status_check(info, sect, 1143e5720823SThomas Chou info->erase_blk_tout, 1144e5720823SThomas Chou "erase"); 1145e5720823SThomas Chou if (st) 114659829cc1SJean-Christophe PLAGNIOL-VILLARD rcode = 1; 1147e5720823SThomas Chou else if (flash_verbose) 114859829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('.'); 114959829cc1SJean-Christophe PLAGNIOL-VILLARD } 115059829cc1SJean-Christophe PLAGNIOL-VILLARD } 11516ea808efSPiotr Ziecik 11526ea808efSPiotr Ziecik if (flash_verbose) 115359829cc1SJean-Christophe PLAGNIOL-VILLARD puts (" done\n"); 11546ea808efSPiotr Ziecik 115559829cc1SJean-Christophe PLAGNIOL-VILLARD return rcode; 115659829cc1SJean-Christophe PLAGNIOL-VILLARD } 115759829cc1SJean-Christophe PLAGNIOL-VILLARD 115870084df7SStefan Roese #ifdef CONFIG_SYS_FLASH_EMPTY_INFO 115970084df7SStefan Roese static int sector_erased(flash_info_t *info, int i) 116070084df7SStefan Roese { 116170084df7SStefan Roese int k; 116270084df7SStefan Roese int size; 11634d2ca9d6SStefan Roese u32 *flash; 116470084df7SStefan Roese 116570084df7SStefan Roese /* 116670084df7SStefan Roese * Check if whole sector is erased 116759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 116870084df7SStefan Roese size = flash_sector_size(info, i); 11694d2ca9d6SStefan Roese flash = (u32 *)info->start[i]; 117070084df7SStefan Roese /* divide by 4 for longword access */ 117170084df7SStefan Roese size = size >> 2; 117270084df7SStefan Roese 117370084df7SStefan Roese for (k = 0; k < size; k++) { 11744d2ca9d6SStefan Roese if (flash_read32(flash++) != 0xffffffff) 117570084df7SStefan Roese return 0; /* not erased */ 117670084df7SStefan Roese } 117770084df7SStefan Roese 117870084df7SStefan Roese return 1; /* erased */ 117970084df7SStefan Roese } 118070084df7SStefan Roese #endif /* CONFIG_SYS_FLASH_EMPTY_INFO */ 118170084df7SStefan Roese 118259829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info) 118359829cc1SJean-Christophe PLAGNIOL-VILLARD { 118459829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 118559829cc1SJean-Christophe PLAGNIOL-VILLARD 118659829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 118759829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("missing or unknown FLASH type\n"); 118859829cc1SJean-Christophe PLAGNIOL-VILLARD return; 118959829cc1SJean-Christophe PLAGNIOL-VILLARD } 119059829cc1SJean-Christophe PLAGNIOL-VILLARD 1191eddf52b5SPeter Tyser printf ("%s flash (%d x %d)", 119281b20cccSMichael Schwingen info->name, 119359829cc1SJean-Christophe PLAGNIOL-VILLARD (info->portwidth << 3), (info->chipwidth << 3)); 119481b20cccSMichael Schwingen if (info->size < 1024*1024) 119581b20cccSMichael Schwingen printf (" Size: %ld kB in %d Sectors\n", 119681b20cccSMichael Schwingen info->size >> 10, info->sector_count); 119781b20cccSMichael Schwingen else 119859829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" Size: %ld MB in %d Sectors\n", 119959829cc1SJean-Christophe PLAGNIOL-VILLARD info->size >> 20, info->sector_count); 120059829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" "); 120159829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 12029c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 12039c048b52SVasiliy Leoenenko printf ("Intel Prog Regions"); 12049c048b52SVasiliy Leoenenko break; 120559829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 120659829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Standard"); 120759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 120859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 120959829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Extended"); 121059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 121159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 121259829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Standard"); 121359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 121459829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 121559829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Extended"); 121659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 121781b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 121881b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 121981b20cccSMichael Schwingen printf ("AMD Legacy"); 122081b20cccSMichael Schwingen break; 122181b20cccSMichael Schwingen #endif 122259829cc1SJean-Christophe PLAGNIOL-VILLARD default: 122359829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Unknown (%d)", info->vendor); 122459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 122559829cc1SJean-Christophe PLAGNIOL-VILLARD } 1226d77c7ac4SPhilippe De Muyter printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x", 1227d77c7ac4SPhilippe De Muyter info->manufacturer_id); 1228d77c7ac4SPhilippe De Muyter printf (info->chipwidth == FLASH_CFI_16BIT ? "%04X" : "%02X", 1229d77c7ac4SPhilippe De Muyter info->device_id); 12305b448adbSHeiko Schocher if ((info->device_id & 0xff) == 0x7E) { 12315b448adbSHeiko Schocher printf(info->chipwidth == FLASH_CFI_16BIT ? "%04X" : "%02X", 12325b448adbSHeiko Schocher info->device_id2); 123359829cc1SJean-Christophe PLAGNIOL-VILLARD } 1234d2af028dSStefan Roese if ((info->vendor == CFI_CMDSET_AMD_STANDARD) && (info->legacy_unlock)) 1235d2af028dSStefan Roese printf("\n Advanced Sector Protection (PPB) enabled"); 123659829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n", 123759829cc1SJean-Christophe PLAGNIOL-VILLARD info->erase_blk_tout, 123859829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout); 123959829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size > 1) { 12407e5b9b47SHaavard Skinnemoen printf (" Buffer write timeout: %ld ms, " 12417e5b9b47SHaavard Skinnemoen "buffer size: %d bytes\n", 124259829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout, 124359829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_size); 124459829cc1SJean-Christophe PLAGNIOL-VILLARD } 124559829cc1SJean-Christophe PLAGNIOL-VILLARD 124659829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("\n Sector Start Addresses:"); 124759829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; ++i) { 12482e97394aSKim Phillips if (ctrlc()) 124959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 125070084df7SStefan Roese if ((i % 5) == 0) 125170084df7SStefan Roese putc('\n'); 125270084df7SStefan Roese #ifdef CONFIG_SYS_FLASH_EMPTY_INFO 125359829cc1SJean-Christophe PLAGNIOL-VILLARD /* print empty and read-only info */ 125459829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %c %s ", 125559829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 125670084df7SStefan Roese sector_erased(info, i) ? 'E' : ' ', 125759829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 12586d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #else /* ! CONFIG_SYS_FLASH_EMPTY_INFO */ 125959829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %s ", 126059829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 126159829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 126259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 126359829cc1SJean-Christophe PLAGNIOL-VILLARD } 126459829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 126559829cc1SJean-Christophe PLAGNIOL-VILLARD return; 126659829cc1SJean-Christophe PLAGNIOL-VILLARD } 126759829cc1SJean-Christophe PLAGNIOL-VILLARD 126859829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 12699a042e9cSJerry Van Baren * This is used in a few places in write_buf() to show programming 12709a042e9cSJerry Van Baren * progress. Making it a function is nasty because it needs to do side 12719a042e9cSJerry Van Baren * effect updates to digit and dots. Repeated code is nasty too, so 12729a042e9cSJerry Van Baren * we define it once here. 12739a042e9cSJerry Van Baren */ 1274f0105727SStefan Roese #ifdef CONFIG_FLASH_SHOW_PROGRESS 1275f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \ 12766ea808efSPiotr Ziecik if (flash_verbose) { \ 1277f0105727SStefan Roese dots -= dots_sub; \ 12789a042e9cSJerry Van Baren if ((scale > 0) && (dots <= 0)) { \ 12799a042e9cSJerry Van Baren if ((digit % 5) == 0) \ 12809a042e9cSJerry Van Baren printf ("%d", digit / 5); \ 12819a042e9cSJerry Van Baren else \ 12829a042e9cSJerry Van Baren putc ('.'); \ 12839a042e9cSJerry Van Baren digit--; \ 12849a042e9cSJerry Van Baren dots += scale; \ 12856ea808efSPiotr Ziecik } \ 12869a042e9cSJerry Van Baren } 1287f0105727SStefan Roese #else 1288f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) 1289f0105727SStefan Roese #endif 12909a042e9cSJerry Van Baren 12919a042e9cSJerry Van Baren /*----------------------------------------------------------------------- 129259829cc1SJean-Christophe PLAGNIOL-VILLARD * Copy memory to flash, returns: 129359829cc1SJean-Christophe PLAGNIOL-VILLARD * 0 - OK 129459829cc1SJean-Christophe PLAGNIOL-VILLARD * 1 - write timeout 129559829cc1SJean-Christophe PLAGNIOL-VILLARD * 2 - Flash not erased 129659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 129759829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) 129859829cc1SJean-Christophe PLAGNIOL-VILLARD { 129959829cc1SJean-Christophe PLAGNIOL-VILLARD ulong wp; 130012d30aa7SHaavard Skinnemoen uchar *p; 130159829cc1SJean-Christophe PLAGNIOL-VILLARD int aln; 130259829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 130359829cc1SJean-Christophe PLAGNIOL-VILLARD int i, rc; 13046d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE 130559829cc1SJean-Christophe PLAGNIOL-VILLARD int buffered_size; 130659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 13079a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS 13089a042e9cSJerry Van Baren int digit = CONFIG_FLASH_SHOW_PROGRESS; 13099a042e9cSJerry Van Baren int scale = 0; 13109a042e9cSJerry Van Baren int dots = 0; 13119a042e9cSJerry Van Baren 13129a042e9cSJerry Van Baren /* 13139a042e9cSJerry Van Baren * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes. 13149a042e9cSJerry Van Baren */ 13159a042e9cSJerry Van Baren if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) { 13169a042e9cSJerry Van Baren scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) / 13179a042e9cSJerry Van Baren CONFIG_FLASH_SHOW_PROGRESS); 13189a042e9cSJerry Van Baren } 13199a042e9cSJerry Van Baren #endif 13209a042e9cSJerry Van Baren 132159829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 132259829cc1SJean-Christophe PLAGNIOL-VILLARD wp = (addr & ~(info->portwidth - 1)); 132359829cc1SJean-Christophe PLAGNIOL-VILLARD 132459829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle unaligned start */ 132559829cc1SJean-Christophe PLAGNIOL-VILLARD if ((aln = addr - wp) != 0) { 132659829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 132709ce9921SBecky Bruce p = (uchar *)wp; 132812d30aa7SHaavard Skinnemoen for (i = 0; i < aln; ++i) 132912d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 133059829cc1SJean-Christophe PLAGNIOL-VILLARD 133159829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (i < info->portwidth) && (cnt > 0); i++) { 133259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 133359829cc1SJean-Christophe PLAGNIOL-VILLARD cnt--; 133459829cc1SJean-Christophe PLAGNIOL-VILLARD } 133512d30aa7SHaavard Skinnemoen for (; (cnt == 0) && (i < info->portwidth); ++i) 133612d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 133712d30aa7SHaavard Skinnemoen 133812d30aa7SHaavard Skinnemoen rc = flash_write_cfiword (info, wp, cword); 133912d30aa7SHaavard Skinnemoen if (rc != 0) 134059829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 134112d30aa7SHaavard Skinnemoen 134212d30aa7SHaavard Skinnemoen wp += i; 1343f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, i); 134459829cc1SJean-Christophe PLAGNIOL-VILLARD } 134559829cc1SJean-Christophe PLAGNIOL-VILLARD 134659829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle the aligned part */ 13476d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE 134859829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size = (info->portwidth / info->chipwidth); 134959829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size *= info->buffer_size; 135059829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 135159829cc1SJean-Christophe PLAGNIOL-VILLARD /* prohibit buffer write when buffer_size is 1 */ 135259829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size == 1) { 135359829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 135459829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) 135559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 135659829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 135759829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 135859829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 135959829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 136059829cc1SJean-Christophe PLAGNIOL-VILLARD continue; 136159829cc1SJean-Christophe PLAGNIOL-VILLARD } 136259829cc1SJean-Christophe PLAGNIOL-VILLARD 136359829cc1SJean-Christophe PLAGNIOL-VILLARD /* write buffer until next buffered_size aligned boundary */ 136459829cc1SJean-Christophe PLAGNIOL-VILLARD i = buffered_size - (wp % buffered_size); 136559829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > cnt) 136659829cc1SJean-Christophe PLAGNIOL-VILLARD i = cnt; 136759829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) 136859829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 136959829cc1SJean-Christophe PLAGNIOL-VILLARD i -= i & (info->portwidth - 1); 137059829cc1SJean-Christophe PLAGNIOL-VILLARD wp += i; 137159829cc1SJean-Christophe PLAGNIOL-VILLARD src += i; 137259829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= i; 1373f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, i); 1374de15a06aSJoe Hershberger /* Only check every once in a while */ 1375de15a06aSJoe Hershberger if ((cnt & 0xFFFF) < buffered_size && ctrlc()) 1376de15a06aSJoe Hershberger return ERR_ABORTED; 137759829cc1SJean-Christophe PLAGNIOL-VILLARD } 137859829cc1SJean-Christophe PLAGNIOL-VILLARD #else 137959829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 138059829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 138159829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) { 138259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 138359829cc1SJean-Christophe PLAGNIOL-VILLARD } 138459829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 138559829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 138659829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 138759829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 1388f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth); 1389de15a06aSJoe Hershberger /* Only check every once in a while */ 1390de15a06aSJoe Hershberger if ((cnt & 0xFFFF) < info->portwidth && ctrlc()) 1391de15a06aSJoe Hershberger return ERR_ABORTED; 139259829cc1SJean-Christophe PLAGNIOL-VILLARD } 13936d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */ 13949a042e9cSJerry Van Baren 139559829cc1SJean-Christophe PLAGNIOL-VILLARD if (cnt == 0) { 139659829cc1SJean-Christophe PLAGNIOL-VILLARD return (0); 139759829cc1SJean-Christophe PLAGNIOL-VILLARD } 139859829cc1SJean-Christophe PLAGNIOL-VILLARD 139959829cc1SJean-Christophe PLAGNIOL-VILLARD /* 140059829cc1SJean-Christophe PLAGNIOL-VILLARD * handle unaligned tail bytes 140159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 140259829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 140309ce9921SBecky Bruce p = (uchar *)wp; 140412d30aa7SHaavard Skinnemoen for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) { 140559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 140659829cc1SJean-Christophe PLAGNIOL-VILLARD --cnt; 140759829cc1SJean-Christophe PLAGNIOL-VILLARD } 140812d30aa7SHaavard Skinnemoen for (; i < info->portwidth; ++i) 140912d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 141059829cc1SJean-Christophe PLAGNIOL-VILLARD 141159829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_write_cfiword (info, wp, cword); 141259829cc1SJean-Christophe PLAGNIOL-VILLARD } 141359829cc1SJean-Christophe PLAGNIOL-VILLARD 141420043a4cSStefan Roese static inline int manufact_match(flash_info_t *info, u32 manu) 141520043a4cSStefan Roese { 141620043a4cSStefan Roese return info->manufacturer_id == ((manu & FLASH_VENDMASK) >> 16); 141720043a4cSStefan Roese } 141820043a4cSStefan Roese 141959829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 142059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 14216d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 142259829cc1SJean-Christophe PLAGNIOL-VILLARD 142381316a90SHolger Brunck static int cfi_protect_bugfix(flash_info_t *info, long sector, int prot) 142459829cc1SJean-Christophe PLAGNIOL-VILLARD { 142520043a4cSStefan Roese if (manufact_match(info, INTEL_MANUFACT) 142611dc4010SKim Phillips && info->device_id == NUMONYX_256MBIT) { 142754652991SPhilippe De Muyter /* 142854652991SPhilippe De Muyter * see errata called 142954652991SPhilippe De Muyter * "Numonyx Axcell P33/P30 Specification Update" :) 143054652991SPhilippe De Muyter */ 143154652991SPhilippe De Muyter flash_write_cmd(info, sector, 0, FLASH_CMD_READ_ID); 143254652991SPhilippe De Muyter if (!flash_isequal(info, sector, FLASH_OFFSET_PROTECT, 143354652991SPhilippe De Muyter prot)) { 143454652991SPhilippe De Muyter /* 143554652991SPhilippe De Muyter * cmd must come before FLASH_CMD_PROTECT + 20us 143654652991SPhilippe De Muyter * Disable interrupts which might cause a timeout here. 143754652991SPhilippe De Muyter */ 143854652991SPhilippe De Muyter int flag = disable_interrupts(); 143954652991SPhilippe De Muyter unsigned short cmd; 144054652991SPhilippe De Muyter 144159829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) 144254652991SPhilippe De Muyter cmd = FLASH_CMD_PROTECT_SET; 144359829cc1SJean-Christophe PLAGNIOL-VILLARD else 144454652991SPhilippe De Muyter cmd = FLASH_CMD_PROTECT_CLEAR; 1445bc9019e1SRafael Campos flash_write_cmd(info, sector, 0, 144654652991SPhilippe De Muyter FLASH_CMD_PROTECT); 144754652991SPhilippe De Muyter flash_write_cmd(info, sector, 0, cmd); 144854652991SPhilippe De Muyter /* re-enable interrupts if necessary */ 144954652991SPhilippe De Muyter if (flag) 145054652991SPhilippe De Muyter enable_interrupts(); 145154652991SPhilippe De Muyter } 145281316a90SHolger Brunck return 1; 145381316a90SHolger Brunck } 145481316a90SHolger Brunck return 0; 145581316a90SHolger Brunck } 145681316a90SHolger Brunck 145781316a90SHolger Brunck int flash_real_protect (flash_info_t * info, long sector, int prot) 145881316a90SHolger Brunck { 145981316a90SHolger Brunck int retcode = 0; 146081316a90SHolger Brunck 146181316a90SHolger Brunck switch (info->vendor) { 146281316a90SHolger Brunck case CFI_CMDSET_INTEL_PROG_REGIONS: 146381316a90SHolger Brunck case CFI_CMDSET_INTEL_STANDARD: 146481316a90SHolger Brunck case CFI_CMDSET_INTEL_EXTENDED: 146581316a90SHolger Brunck if (!cfi_protect_bugfix(info, sector, prot)) { 146681316a90SHolger Brunck flash_write_cmd(info, sector, 0, 146781316a90SHolger Brunck FLASH_CMD_CLEAR_STATUS); 146881316a90SHolger Brunck flash_write_cmd(info, sector, 0, 146981316a90SHolger Brunck FLASH_CMD_PROTECT); 147081316a90SHolger Brunck if (prot) 147181316a90SHolger Brunck flash_write_cmd(info, sector, 0, 147281316a90SHolger Brunck FLASH_CMD_PROTECT_SET); 147381316a90SHolger Brunck else 147481316a90SHolger Brunck flash_write_cmd(info, sector, 0, 147581316a90SHolger Brunck FLASH_CMD_PROTECT_CLEAR); 147681316a90SHolger Brunck 147781316a90SHolger Brunck } 1478bc9019e1SRafael Campos break; 1479bc9019e1SRafael Campos case CFI_CMDSET_AMD_EXTENDED: 1480bc9019e1SRafael Campos case CFI_CMDSET_AMD_STANDARD: 1481bc9019e1SRafael Campos /* U-Boot only checks the first byte */ 148220043a4cSStefan Roese if (manufact_match(info, ATM_MANUFACT)) { 1483bc9019e1SRafael Campos if (prot) { 1484bc9019e1SRafael Campos flash_unlock_seq (info, 0); 1485bc9019e1SRafael Campos flash_write_cmd (info, 0, 1486bc9019e1SRafael Campos info->addr_unlock1, 1487bc9019e1SRafael Campos ATM_CMD_SOFTLOCK_START); 1488bc9019e1SRafael Campos flash_unlock_seq (info, 0); 1489bc9019e1SRafael Campos flash_write_cmd (info, sector, 0, 1490bc9019e1SRafael Campos ATM_CMD_LOCK_SECT); 1491bc9019e1SRafael Campos } else { 1492bc9019e1SRafael Campos flash_write_cmd (info, 0, 1493bc9019e1SRafael Campos info->addr_unlock1, 1494bc9019e1SRafael Campos AMD_CMD_UNLOCK_START); 1495bc9019e1SRafael Campos if (info->device_id == ATM_ID_BV6416) 1496bc9019e1SRafael Campos flash_write_cmd (info, sector, 1497bc9019e1SRafael Campos 0, ATM_CMD_UNLOCK_SECT); 1498bc9019e1SRafael Campos } 1499bc9019e1SRafael Campos } 1500ac6b9115SStefan Roese if (info->legacy_unlock) { 150166863b05SAnatolij Gustschin int flag = disable_interrupts(); 150266863b05SAnatolij Gustschin int lock_flag; 150366863b05SAnatolij Gustschin 150466863b05SAnatolij Gustschin flash_unlock_seq(info, 0); 150566863b05SAnatolij Gustschin flash_write_cmd(info, 0, info->addr_unlock1, 150666863b05SAnatolij Gustschin AMD_CMD_SET_PPB_ENTRY); 150766863b05SAnatolij Gustschin lock_flag = flash_isset(info, sector, 0, 0x01); 150866863b05SAnatolij Gustschin if (prot) { 150966863b05SAnatolij Gustschin if (lock_flag) { 151066863b05SAnatolij Gustschin flash_write_cmd(info, sector, 0, 151166863b05SAnatolij Gustschin AMD_CMD_PPB_LOCK_BC1); 151266863b05SAnatolij Gustschin flash_write_cmd(info, sector, 0, 151366863b05SAnatolij Gustschin AMD_CMD_PPB_LOCK_BC2); 151466863b05SAnatolij Gustschin } 151566863b05SAnatolij Gustschin debug("sector %ld %slocked\n", sector, 151666863b05SAnatolij Gustschin lock_flag ? "" : "already "); 151766863b05SAnatolij Gustschin } else { 151866863b05SAnatolij Gustschin if (!lock_flag) { 151966863b05SAnatolij Gustschin debug("unlock %ld\n", sector); 152066863b05SAnatolij Gustschin flash_write_cmd(info, 0, 0, 152166863b05SAnatolij Gustschin AMD_CMD_PPB_UNLOCK_BC1); 152266863b05SAnatolij Gustschin flash_write_cmd(info, 0, 0, 152366863b05SAnatolij Gustschin AMD_CMD_PPB_UNLOCK_BC2); 152466863b05SAnatolij Gustschin } 152566863b05SAnatolij Gustschin debug("sector %ld %sunlocked\n", sector, 152666863b05SAnatolij Gustschin !lock_flag ? "" : "already "); 152766863b05SAnatolij Gustschin } 152866863b05SAnatolij Gustschin if (flag) 152966863b05SAnatolij Gustschin enable_interrupts(); 153066863b05SAnatolij Gustschin 153166863b05SAnatolij Gustschin if (flash_status_check(info, sector, 153266863b05SAnatolij Gustschin info->erase_blk_tout, 153366863b05SAnatolij Gustschin prot ? "protect" : "unprotect")) 153466863b05SAnatolij Gustschin printf("status check error\n"); 153566863b05SAnatolij Gustschin 153666863b05SAnatolij Gustschin flash_write_cmd(info, 0, 0, 153766863b05SAnatolij Gustschin AMD_CMD_SET_PPB_EXIT_BC1); 153866863b05SAnatolij Gustschin flash_write_cmd(info, 0, 0, 153966863b05SAnatolij Gustschin AMD_CMD_SET_PPB_EXIT_BC2); 154066863b05SAnatolij Gustschin } 1541bc9019e1SRafael Campos break; 15424e00acdeSTsiChung Liew #ifdef CONFIG_FLASH_CFI_LEGACY 15434e00acdeSTsiChung Liew case CFI_CMDSET_AMD_LEGACY: 15444e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 15454e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); 15464e00acdeSTsiChung Liew if (prot) 15474e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); 15484e00acdeSTsiChung Liew else 15494e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR); 15504e00acdeSTsiChung Liew #endif 1551bc9019e1SRafael Campos }; 155259829cc1SJean-Christophe PLAGNIOL-VILLARD 1553df4e813bSStefan Roese /* 1554df4e813bSStefan Roese * Flash needs to be in status register read mode for 1555df4e813bSStefan Roese * flash_full_status_check() to work correctly 1556df4e813bSStefan Roese */ 1557df4e813bSStefan Roese flash_write_cmd(info, sector, 0, FLASH_CMD_READ_STATUS); 155859829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode = 155959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_full_status_check (info, sector, info->erase_blk_tout, 156059829cc1SJean-Christophe PLAGNIOL-VILLARD prot ? "protect" : "unprotect")) == 0) { 156159829cc1SJean-Christophe PLAGNIOL-VILLARD 156259829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sector] = prot; 156359829cc1SJean-Christophe PLAGNIOL-VILLARD 156459829cc1SJean-Christophe PLAGNIOL-VILLARD /* 156559829cc1SJean-Christophe PLAGNIOL-VILLARD * On some of Intel's flash chips (marked via legacy_unlock) 156659829cc1SJean-Christophe PLAGNIOL-VILLARD * unprotect unprotects all locking. 156759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 156859829cc1SJean-Christophe PLAGNIOL-VILLARD if ((prot == 0) && (info->legacy_unlock)) { 156959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t i; 157059829cc1SJean-Christophe PLAGNIOL-VILLARD 157159829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; i++) { 157259829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[i]) 157359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (info, i, 1); 157459829cc1SJean-Christophe PLAGNIOL-VILLARD } 157559829cc1SJean-Christophe PLAGNIOL-VILLARD } 157659829cc1SJean-Christophe PLAGNIOL-VILLARD } 157759829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 157859829cc1SJean-Christophe PLAGNIOL-VILLARD } 157959829cc1SJean-Christophe PLAGNIOL-VILLARD 158059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 158159829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_user_serial - read the OneTimeProgramming cells 158259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 158359829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, 158459829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 158559829cc1SJean-Christophe PLAGNIOL-VILLARD { 158659829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 158759829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *dst; 158859829cc1SJean-Christophe PLAGNIOL-VILLARD 158959829cc1SJean-Christophe PLAGNIOL-VILLARD dst = buffer; 159012d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION); 159159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 159259829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (dst, src + offset, len); 159359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 1594a90b9575SAaron Williams udelay(1); 159512d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src); 159659829cc1SJean-Christophe PLAGNIOL-VILLARD } 159759829cc1SJean-Christophe PLAGNIOL-VILLARD 159859829cc1SJean-Christophe PLAGNIOL-VILLARD /* 159959829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_factory_serial - read the device Id from the protection area 160059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 160159829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, 160259829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 160359829cc1SJean-Christophe PLAGNIOL-VILLARD { 160459829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 160559829cc1SJean-Christophe PLAGNIOL-VILLARD 160612d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION); 160759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 160859829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (buffer, src + offset, len); 160959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 1610a90b9575SAaron Williams udelay(1); 161112d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src); 161259829cc1SJean-Christophe PLAGNIOL-VILLARD } 161359829cc1SJean-Christophe PLAGNIOL-VILLARD 16146d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */ 161559829cc1SJean-Christophe PLAGNIOL-VILLARD 16160ddf06ddSHaavard Skinnemoen /*----------------------------------------------------------------------- 16170ddf06ddSHaavard Skinnemoen * Reverse the order of the erase regions in the CFI QRY structure. 16180ddf06ddSHaavard Skinnemoen * This is needed for chips that are either a) correctly detected as 16190ddf06ddSHaavard Skinnemoen * top-boot, or b) buggy. 16200ddf06ddSHaavard Skinnemoen */ 16210ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry) 16220ddf06ddSHaavard Skinnemoen { 16230ddf06ddSHaavard Skinnemoen unsigned int i, j; 16240ddf06ddSHaavard Skinnemoen u32 tmp; 16250ddf06ddSHaavard Skinnemoen 16260ddf06ddSHaavard Skinnemoen for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) { 1627aedadf10SAndrew Gabbasov tmp = get_unaligned(&(qry->erase_region_info[i])); 1628aedadf10SAndrew Gabbasov put_unaligned(get_unaligned(&(qry->erase_region_info[j])), 1629aedadf10SAndrew Gabbasov &(qry->erase_region_info[i])); 1630aedadf10SAndrew Gabbasov put_unaligned(tmp, &(qry->erase_region_info[j])); 16310ddf06ddSHaavard Skinnemoen } 16320ddf06ddSHaavard Skinnemoen } 163359829cc1SJean-Christophe PLAGNIOL-VILLARD 163459829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 163559829cc1SJean-Christophe PLAGNIOL-VILLARD * read jedec ids from device and set corresponding fields in info struct 163659829cc1SJean-Christophe PLAGNIOL-VILLARD * 163759829cc1SJean-Christophe PLAGNIOL-VILLARD * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct 163859829cc1SJean-Christophe PLAGNIOL-VILLARD * 163959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 16400ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info) 164159829cc1SJean-Christophe PLAGNIOL-VILLARD { 164259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 1643a90b9575SAaron Williams udelay(1); 164459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); 164559829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 164659829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 164759829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 1648d77c7ac4SPhilippe De Muyter info->device_id = (info->chipwidth == FLASH_CFI_16BIT) ? 1649d77c7ac4SPhilippe De Muyter flash_read_word (info, FLASH_OFFSET_DEVICE_ID) : 1650d77c7ac4SPhilippe De Muyter flash_read_uchar (info, FLASH_OFFSET_DEVICE_ID); 165159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 16520ddf06ddSHaavard Skinnemoen } 16530ddf06ddSHaavard Skinnemoen 16540ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry) 16550ddf06ddSHaavard Skinnemoen { 16560ddf06ddSHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 16570ddf06ddSHaavard Skinnemoen 16580ddf06ddSHaavard Skinnemoen cmdset_intel_read_jedec_ids(info); 16590ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 16600ddf06ddSHaavard Skinnemoen 16616d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 16620ddf06ddSHaavard Skinnemoen /* read legacy lock/unlock bit from intel flash */ 16630ddf06ddSHaavard Skinnemoen if (info->ext_addr) { 16640ddf06ddSHaavard Skinnemoen info->legacy_unlock = flash_read_uchar (info, 16650ddf06ddSHaavard Skinnemoen info->ext_addr + 5) & 0x08; 16660ddf06ddSHaavard Skinnemoen } 16670ddf06ddSHaavard Skinnemoen #endif 16680ddf06ddSHaavard Skinnemoen 16690ddf06ddSHaavard Skinnemoen return 0; 16700ddf06ddSHaavard Skinnemoen } 16710ddf06ddSHaavard Skinnemoen 16720ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info) 16730ddf06ddSHaavard Skinnemoen { 16743a7b2c21SNiklaus Giger ushort bankId = 0; 16753a7b2c21SNiklaus Giger uchar manuId; 16763a7b2c21SNiklaus Giger 167759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 167859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info, 0); 167981b20cccSMichael Schwingen flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); 168059829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 168190447ecbSTor Krill 16823a7b2c21SNiklaus Giger manuId = flash_read_uchar (info, FLASH_OFFSET_MANUFACTURER_ID); 16833a7b2c21SNiklaus Giger /* JEDEC JEP106Z specifies ID codes up to bank 7 */ 16843a7b2c21SNiklaus Giger while (manuId == FLASH_CONTINUATION_CODE && bankId < 0x800) { 16853a7b2c21SNiklaus Giger bankId += 0x100; 16863a7b2c21SNiklaus Giger manuId = flash_read_uchar (info, 16873a7b2c21SNiklaus Giger bankId | FLASH_OFFSET_MANUFACTURER_ID); 16883a7b2c21SNiklaus Giger } 16893a7b2c21SNiklaus Giger info->manufacturer_id = manuId; 169090447ecbSTor Krill 169190447ecbSTor Krill switch (info->chipwidth){ 169290447ecbSTor Krill case FLASH_CFI_8BIT: 169359829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 169459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 169559829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 169659829cc1SJean-Christophe PLAGNIOL-VILLARD /* AMD 3-byte (expanded) device ids */ 169759829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = flash_read_uchar (info, 169859829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID2); 169959829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 <<= 8; 170059829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 |= flash_read_uchar (info, 170159829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID3); 170259829cc1SJean-Christophe PLAGNIOL-VILLARD } 170390447ecbSTor Krill break; 170490447ecbSTor Krill case FLASH_CFI_16BIT: 170590447ecbSTor Krill info->device_id = flash_read_word (info, 170690447ecbSTor Krill FLASH_OFFSET_DEVICE_ID); 17075b448adbSHeiko Schocher if ((info->device_id & 0xff) == 0x7E) { 17085b448adbSHeiko Schocher /* AMD 3-byte (expanded) device ids */ 17095b448adbSHeiko Schocher info->device_id2 = flash_read_uchar (info, 17105b448adbSHeiko Schocher FLASH_OFFSET_DEVICE_ID2); 17115b448adbSHeiko Schocher info->device_id2 <<= 8; 17125b448adbSHeiko Schocher info->device_id2 |= flash_read_uchar (info, 17135b448adbSHeiko Schocher FLASH_OFFSET_DEVICE_ID3); 17145b448adbSHeiko Schocher } 171590447ecbSTor Krill break; 171690447ecbSTor Krill default: 171790447ecbSTor Krill break; 171890447ecbSTor Krill } 171959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 1720a90b9575SAaron Williams udelay(1); 17210ddf06ddSHaavard Skinnemoen } 17220ddf06ddSHaavard Skinnemoen 17230ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry) 17240ddf06ddSHaavard Skinnemoen { 17250ddf06ddSHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 172607b2c5c0SAngelo Dureghello info->cmd_erase_sector = AMD_CMD_ERASE_SECTOR; 17270ddf06ddSHaavard Skinnemoen 17280ddf06ddSHaavard Skinnemoen cmdset_amd_read_jedec_ids(info); 17290ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 17300ddf06ddSHaavard Skinnemoen 173166863b05SAnatolij Gustschin #ifdef CONFIG_SYS_FLASH_PROTECTION 1732ac6b9115SStefan Roese if (info->ext_addr) { 1733ac6b9115SStefan Roese /* read sector protect/unprotect scheme (at 0x49) */ 1734ac6b9115SStefan Roese if (flash_read_uchar(info, info->ext_addr + 9) == 0x8) 173566863b05SAnatolij Gustschin info->legacy_unlock = 1; 173666863b05SAnatolij Gustschin } 173766863b05SAnatolij Gustschin #endif 173866863b05SAnatolij Gustschin 17390ddf06ddSHaavard Skinnemoen return 0; 17400ddf06ddSHaavard Skinnemoen } 17410ddf06ddSHaavard Skinnemoen 17420ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 17430ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info) 17440ddf06ddSHaavard Skinnemoen { 17450ddf06ddSHaavard Skinnemoen info->manufacturer_id = 0; 17460ddf06ddSHaavard Skinnemoen info->device_id = 0; 17470ddf06ddSHaavard Skinnemoen info->device_id2 = 0; 17480ddf06ddSHaavard Skinnemoen 17490ddf06ddSHaavard Skinnemoen switch (info->vendor) { 17509c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 17510ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 17520ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 17538225d1e3SMichael Schwingen cmdset_intel_read_jedec_ids(info); 17540ddf06ddSHaavard Skinnemoen break; 17550ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 17560ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 17578225d1e3SMichael Schwingen cmdset_amd_read_jedec_ids(info); 175859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 175959829cc1SJean-Christophe PLAGNIOL-VILLARD default: 176059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 176159829cc1SJean-Christophe PLAGNIOL-VILLARD } 176259829cc1SJean-Christophe PLAGNIOL-VILLARD } 176359829cc1SJean-Christophe PLAGNIOL-VILLARD 1764be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 1765be60a902SHaavard Skinnemoen * Call board code to request info about non-CFI flash. 1766be60a902SHaavard Skinnemoen * board_flash_get_legacy needs to fill in at least: 1767be60a902SHaavard Skinnemoen * info->portwidth, info->chipwidth and info->interface for Jedec probing. 1768be60a902SHaavard Skinnemoen */ 176909ce9921SBecky Bruce static int flash_detect_legacy(phys_addr_t base, int banknum) 1770be60a902SHaavard Skinnemoen { 1771be60a902SHaavard Skinnemoen flash_info_t *info = &flash_info[banknum]; 1772be60a902SHaavard Skinnemoen 1773be60a902SHaavard Skinnemoen if (board_flash_get_legacy(base, banknum, info)) { 1774be60a902SHaavard Skinnemoen /* board code may have filled info completely. If not, we 1775be60a902SHaavard Skinnemoen use JEDEC ID probing. */ 1776be60a902SHaavard Skinnemoen if (!info->vendor) { 1777be60a902SHaavard Skinnemoen int modes[] = { 1778be60a902SHaavard Skinnemoen CFI_CMDSET_AMD_STANDARD, 1779be60a902SHaavard Skinnemoen CFI_CMDSET_INTEL_STANDARD 1780be60a902SHaavard Skinnemoen }; 1781be60a902SHaavard Skinnemoen int i; 1782be60a902SHaavard Skinnemoen 178331bf0f57SAxel Lin for (i = 0; i < ARRAY_SIZE(modes); i++) { 1784be60a902SHaavard Skinnemoen info->vendor = modes[i]; 178509ce9921SBecky Bruce info->start[0] = 178609ce9921SBecky Bruce (ulong)map_physmem(base, 1787e1fb6d0dSStefan Roese info->portwidth, 178809ce9921SBecky Bruce MAP_NOCACHE); 1789be60a902SHaavard Skinnemoen if (info->portwidth == FLASH_CFI_8BIT 1790be60a902SHaavard Skinnemoen && info->interface == FLASH_CFI_X8X16) { 1791be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x2AAA; 1792be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x5555; 1793be60a902SHaavard Skinnemoen } else { 1794be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x5555; 1795be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x2AAA; 1796be60a902SHaavard Skinnemoen } 1797be60a902SHaavard Skinnemoen flash_read_jedec_ids(info); 1798be60a902SHaavard Skinnemoen debug("JEDEC PROBE: ID %x %x %x\n", 1799be60a902SHaavard Skinnemoen info->manufacturer_id, 1800be60a902SHaavard Skinnemoen info->device_id, 1801be60a902SHaavard Skinnemoen info->device_id2); 180209ce9921SBecky Bruce if (jedec_flash_match(info, info->start[0])) 1803be60a902SHaavard Skinnemoen break; 180409ce9921SBecky Bruce else 1805e1fb6d0dSStefan Roese unmap_physmem((void *)info->start[0], 1806d8b57c0aSKuo-Jung Su info->portwidth); 1807be60a902SHaavard Skinnemoen } 1808be60a902SHaavard Skinnemoen } 1809be60a902SHaavard Skinnemoen 1810be60a902SHaavard Skinnemoen switch(info->vendor) { 18119c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 1812be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 1813be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 1814be60a902SHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 1815be60a902SHaavard Skinnemoen break; 1816be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 1817be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 1818be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_LEGACY: 1819be60a902SHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 1820be60a902SHaavard Skinnemoen break; 1821be60a902SHaavard Skinnemoen } 1822be60a902SHaavard Skinnemoen info->flash_id = FLASH_MAN_CFI; 1823be60a902SHaavard Skinnemoen return 1; 1824be60a902SHaavard Skinnemoen } 1825be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1826be60a902SHaavard Skinnemoen } 1827be60a902SHaavard Skinnemoen #else 182809ce9921SBecky Bruce static inline int flash_detect_legacy(phys_addr_t base, int banknum) 1829be60a902SHaavard Skinnemoen { 1830be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1831be60a902SHaavard Skinnemoen } 1832be60a902SHaavard Skinnemoen #endif 1833be60a902SHaavard Skinnemoen 183459829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 183559829cc1SJean-Christophe PLAGNIOL-VILLARD * detect if flash is compatible with the Common Flash Interface (CFI) 183659829cc1SJean-Christophe PLAGNIOL-VILLARD * http://www.jedec.org/download/search/jesd68.pdf 183759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1838e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf, 1839e23741f4SHaavard Skinnemoen unsigned int start, size_t len) 1840e23741f4SHaavard Skinnemoen { 1841e23741f4SHaavard Skinnemoen u8 *p = buf; 1842e23741f4SHaavard Skinnemoen unsigned int i; 1843e23741f4SHaavard Skinnemoen 1844e23741f4SHaavard Skinnemoen for (i = 0; i < len; i++) 1845e303be2dSStefan Roese p[i] = flash_read_uchar(info, start + i); 1846e23741f4SHaavard Skinnemoen } 1847e23741f4SHaavard Skinnemoen 184811dc4010SKim Phillips static void __flash_cmd_reset(flash_info_t *info) 1849fa36ae79SStefan Roese { 1850fa36ae79SStefan Roese /* 1851fa36ae79SStefan Roese * We do not yet know what kind of commandset to use, so we issue 1852fa36ae79SStefan Roese * the reset command in both Intel and AMD variants, in the hope 1853fa36ae79SStefan Roese * that AMD flash roms ignore the Intel command. 1854fa36ae79SStefan Roese */ 1855fa36ae79SStefan Roese flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 1856a90b9575SAaron Williams udelay(1); 1857fa36ae79SStefan Roese flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 1858fa36ae79SStefan Roese } 1859fa36ae79SStefan Roese void flash_cmd_reset(flash_info_t *info) 1860fa36ae79SStefan Roese __attribute__((weak,alias("__flash_cmd_reset"))); 1861fa36ae79SStefan Roese 1862e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 186359829cc1SJean-Christophe PLAGNIOL-VILLARD { 186459829cc1SJean-Christophe PLAGNIOL-VILLARD int cfi_offset; 186559829cc1SJean-Christophe PLAGNIOL-VILLARD 1866e303be2dSStefan Roese /* Issue FLASH reset command */ 1867e303be2dSStefan Roese flash_cmd_reset(info); 1868e303be2dSStefan Roese 186931bf0f57SAxel Lin for (cfi_offset = 0; cfi_offset < ARRAY_SIZE(flash_offset_cfi); 18707e5b9b47SHaavard Skinnemoen cfi_offset++) { 18717e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], 18727e5b9b47SHaavard Skinnemoen FLASH_CMD_CFI); 1873e303be2dSStefan Roese if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') 1874e303be2dSStefan Roese && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') 1875e303be2dSStefan Roese && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { 1876e23741f4SHaavard Skinnemoen flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP, 1877e23741f4SHaavard Skinnemoen sizeof(struct cfi_qry)); 1878e23741f4SHaavard Skinnemoen info->interface = le16_to_cpu(qry->interface_desc); 1879e303be2dSStefan Roese 188059829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_offset = flash_offset_cfi[cfi_offset]; 188159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device interface is %d\n", 188259829cc1SJean-Christophe PLAGNIOL-VILLARD info->interface); 188359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found port %d chip %d ", 188459829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth, info->chipwidth); 188559829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("port %d bits chip %d bits\n", 188659829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth << CFI_FLASH_SHIFT_WIDTH, 188759829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 188842026c9cSBartlomiej Sieka 188942026c9cSBartlomiej Sieka /* calculate command offsets as in the Linux driver */ 1890e303be2dSStefan Roese info->addr_unlock1 = 0x555; 1891e303be2dSStefan Roese info->addr_unlock2 = 0x2aa; 189242026c9cSBartlomiej Sieka 189342026c9cSBartlomiej Sieka /* 189442026c9cSBartlomiej Sieka * modify the unlock address if we are 189542026c9cSBartlomiej Sieka * in compatibility mode 189642026c9cSBartlomiej Sieka */ 189742026c9cSBartlomiej Sieka if ( /* x8/x16 in x8 mode */ 189842026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY8) && 189942026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X8X16)) || 190042026c9cSBartlomiej Sieka /* x16/x32 in x16 mode */ 190142026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY16) && 190242026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X16X32))) 190342026c9cSBartlomiej Sieka { 190442026c9cSBartlomiej Sieka info->addr_unlock1 = 0xaaa; 190542026c9cSBartlomiej Sieka info->addr_unlock2 = 0x555; 190642026c9cSBartlomiej Sieka } 190742026c9cSBartlomiej Sieka 190881b20cccSMichael Schwingen info->name = "CFI conformant"; 190959829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 191059829cc1SJean-Christophe PLAGNIOL-VILLARD } 191159829cc1SJean-Christophe PLAGNIOL-VILLARD } 19127e5b9b47SHaavard Skinnemoen 19137e5b9b47SHaavard Skinnemoen return 0; 191459829cc1SJean-Christophe PLAGNIOL-VILLARD } 19157e5b9b47SHaavard Skinnemoen 1916e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 19177e5b9b47SHaavard Skinnemoen { 19187e5b9b47SHaavard Skinnemoen debug ("flash detect cfi\n"); 19197e5b9b47SHaavard Skinnemoen 19206d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (info->portwidth = CONFIG_SYS_FLASH_CFI_WIDTH; 19217e5b9b47SHaavard Skinnemoen info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) { 19227e5b9b47SHaavard Skinnemoen for (info->chipwidth = FLASH_CFI_BY8; 19237e5b9b47SHaavard Skinnemoen info->chipwidth <= info->portwidth; 19247e5b9b47SHaavard Skinnemoen info->chipwidth <<= 1) 1925e303be2dSStefan Roese if (__flash_detect_cfi(info, qry)) 19267e5b9b47SHaavard Skinnemoen return 1; 192759829cc1SJean-Christophe PLAGNIOL-VILLARD } 192859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("not found\n"); 192959829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 193059829cc1SJean-Christophe PLAGNIOL-VILLARD } 193159829cc1SJean-Christophe PLAGNIOL-VILLARD 193259829cc1SJean-Christophe PLAGNIOL-VILLARD /* 1933467bcee1SHaavard Skinnemoen * Manufacturer-specific quirks. Add workarounds for geometry 1934467bcee1SHaavard Skinnemoen * reversal, etc. here. 1935467bcee1SHaavard Skinnemoen */ 1936467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry) 1937467bcee1SHaavard Skinnemoen { 1938467bcee1SHaavard Skinnemoen /* check if flash geometry needs reversal */ 1939467bcee1SHaavard Skinnemoen if (qry->num_erase_regions > 1) { 1940467bcee1SHaavard Skinnemoen /* reverse geometry if top boot part */ 1941467bcee1SHaavard Skinnemoen if (info->cfi_version < 0x3131) { 1942467bcee1SHaavard Skinnemoen /* CFI < 1.1, try to guess from device id */ 1943467bcee1SHaavard Skinnemoen if ((info->device_id & 0x80) != 0) 1944467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1945e303be2dSStefan Roese } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { 1946467bcee1SHaavard Skinnemoen /* CFI >= 1.1, deduct from top/bottom flag */ 1947467bcee1SHaavard Skinnemoen /* note: ext_addr is valid since cfi_version > 0 */ 1948467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1949467bcee1SHaavard Skinnemoen } 1950467bcee1SHaavard Skinnemoen } 1951467bcee1SHaavard Skinnemoen } 1952467bcee1SHaavard Skinnemoen 1953467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry) 1954467bcee1SHaavard Skinnemoen { 1955467bcee1SHaavard Skinnemoen int reverse_geometry = 0; 1956467bcee1SHaavard Skinnemoen 1957467bcee1SHaavard Skinnemoen /* Check the "top boot" bit in the PRI */ 1958467bcee1SHaavard Skinnemoen if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1)) 1959467bcee1SHaavard Skinnemoen reverse_geometry = 1; 1960467bcee1SHaavard Skinnemoen 1961467bcee1SHaavard Skinnemoen /* AT49BV6416(T) list the erase regions in the wrong order. 1962467bcee1SHaavard Skinnemoen * However, the device ID is identical with the non-broken 1963cb82a532SUlf Samuelsson * AT49BV642D they differ in the high byte. 1964467bcee1SHaavard Skinnemoen */ 1965467bcee1SHaavard Skinnemoen if (info->device_id == 0xd6 || info->device_id == 0xd2) 1966467bcee1SHaavard Skinnemoen reverse_geometry = !reverse_geometry; 1967467bcee1SHaavard Skinnemoen 1968467bcee1SHaavard Skinnemoen if (reverse_geometry) 1969467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1970467bcee1SHaavard Skinnemoen } 1971467bcee1SHaavard Skinnemoen 1972e8eac437SRichard Retanubun static void flash_fixup_stm(flash_info_t *info, struct cfi_qry *qry) 1973e8eac437SRichard Retanubun { 1974e8eac437SRichard Retanubun /* check if flash geometry needs reversal */ 1975e8eac437SRichard Retanubun if (qry->num_erase_regions > 1) { 1976e8eac437SRichard Retanubun /* reverse geometry if top boot part */ 1977e8eac437SRichard Retanubun if (info->cfi_version < 0x3131) { 19786a011ce8SMike Frysinger /* CFI < 1.1, guess by device id */ 19796a011ce8SMike Frysinger if (info->device_id == 0x22CA || /* M29W320DT */ 19806a011ce8SMike Frysinger info->device_id == 0x2256 || /* M29W320ET */ 19816a011ce8SMike Frysinger info->device_id == 0x22D7) { /* M29W800DT */ 1982e8eac437SRichard Retanubun cfi_reverse_geometry(qry); 1983e8eac437SRichard Retanubun } 19844c2105cbSMike Frysinger } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { 19854c2105cbSMike Frysinger /* CFI >= 1.1, deduct from top/bottom flag */ 19864c2105cbSMike Frysinger /* note: ext_addr is valid since cfi_version > 0 */ 19874c2105cbSMike Frysinger cfi_reverse_geometry(qry); 1988e8eac437SRichard Retanubun } 1989e8eac437SRichard Retanubun } 1990e8eac437SRichard Retanubun } 1991e8eac437SRichard Retanubun 199207b2c5c0SAngelo Dureghello static void flash_fixup_sst(flash_info_t *info, struct cfi_qry *qry) 199307b2c5c0SAngelo Dureghello { 199407b2c5c0SAngelo Dureghello /* 199507b2c5c0SAngelo Dureghello * SST, for many recent nor parallel flashes, says they are 199607b2c5c0SAngelo Dureghello * CFI-conformant. This is not true, since qry struct. 199707b2c5c0SAngelo Dureghello * reports a std. AMD command set (0x0002), while SST allows to 199807b2c5c0SAngelo Dureghello * erase two different sector sizes for the same memory. 199907b2c5c0SAngelo Dureghello * 64KB sector (SST call it block) needs 0x30 to be erased. 200007b2c5c0SAngelo Dureghello * 4KB sector (SST call it sector) needs 0x50 to be erased. 200107b2c5c0SAngelo Dureghello * Since CFI query detect the 4KB number of sectors, users expects 200207b2c5c0SAngelo Dureghello * a sector granularity of 4KB, and it is here set. 200307b2c5c0SAngelo Dureghello */ 200407b2c5c0SAngelo Dureghello if (info->device_id == 0x5D23 || /* SST39VF3201B */ 200507b2c5c0SAngelo Dureghello info->device_id == 0x5C23) { /* SST39VF3202B */ 200607b2c5c0SAngelo Dureghello /* set sector granularity to 4KB */ 200707b2c5c0SAngelo Dureghello info->cmd_erase_sector=0x50; 200807b2c5c0SAngelo Dureghello } 200907b2c5c0SAngelo Dureghello } 201007b2c5c0SAngelo Dureghello 2011c502321cSJagannadha Sutradharudu Teki static void flash_fixup_num(flash_info_t *info, struct cfi_qry *qry) 2012c502321cSJagannadha Sutradharudu Teki { 2013c502321cSJagannadha Sutradharudu Teki /* 2014c502321cSJagannadha Sutradharudu Teki * The M29EW devices seem to report the CFI information wrong 2015c502321cSJagannadha Sutradharudu Teki * when it's in 8 bit mode. 2016c502321cSJagannadha Sutradharudu Teki * There's an app note from Numonyx on this issue. 2017c502321cSJagannadha Sutradharudu Teki * So adjust the buffer size for M29EW while operating in 8-bit mode 2018c502321cSJagannadha Sutradharudu Teki */ 2019c502321cSJagannadha Sutradharudu Teki if (((qry->max_buf_write_size) > 0x8) && 2020c502321cSJagannadha Sutradharudu Teki (info->device_id == 0x7E) && 2021c502321cSJagannadha Sutradharudu Teki (info->device_id2 == 0x2201 || 2022c502321cSJagannadha Sutradharudu Teki info->device_id2 == 0x2301 || 2023c502321cSJagannadha Sutradharudu Teki info->device_id2 == 0x2801 || 2024c502321cSJagannadha Sutradharudu Teki info->device_id2 == 0x4801)) { 2025c502321cSJagannadha Sutradharudu Teki debug("Adjusted buffer size on Numonyx flash" 2026c502321cSJagannadha Sutradharudu Teki " M29EW family in 8 bit mode\n"); 2027c502321cSJagannadha Sutradharudu Teki qry->max_buf_write_size = 0x8; 2028c502321cSJagannadha Sutradharudu Teki } 2029c502321cSJagannadha Sutradharudu Teki } 2030c502321cSJagannadha Sutradharudu Teki 2031467bcee1SHaavard Skinnemoen /* 203259829cc1SJean-Christophe PLAGNIOL-VILLARD * The following code cannot be run from FLASH! 203359829cc1SJean-Christophe PLAGNIOL-VILLARD * 203459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 203534bbb8fbSAnatolij Gustschin ulong flash_get_size (phys_addr_t base, int banknum) 203659829cc1SJean-Christophe PLAGNIOL-VILLARD { 203759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t *info = &flash_info[banknum]; 203859829cc1SJean-Christophe PLAGNIOL-VILLARD int i, j; 203959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect_cnt; 204009ce9921SBecky Bruce phys_addr_t sector; 204159829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long tmp; 204259829cc1SJean-Christophe PLAGNIOL-VILLARD int size_ratio; 204359829cc1SJean-Christophe PLAGNIOL-VILLARD uchar num_erase_regions; 204459829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_size; 204559829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_count; 2046e23741f4SHaavard Skinnemoen struct cfi_qry qry; 204734bbb8fbSAnatolij Gustschin unsigned long max_size; 204859829cc1SJean-Christophe PLAGNIOL-VILLARD 2049f979690eSKumar Gala memset(&qry, 0, sizeof(qry)); 2050f979690eSKumar Gala 205159829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = 0; 205259829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = 0; 20536d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 205459829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = 0; 205559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 205659829cc1SJean-Christophe PLAGNIOL-VILLARD 205709ce9921SBecky Bruce info->start[0] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE); 205859829cc1SJean-Christophe PLAGNIOL-VILLARD 2059e23741f4SHaavard Skinnemoen if (flash_detect_cfi (info, &qry)) { 2060aedadf10SAndrew Gabbasov info->vendor = le16_to_cpu(get_unaligned(&(qry.p_id))); 2061aedadf10SAndrew Gabbasov info->ext_addr = le16_to_cpu(get_unaligned(&(qry.p_adr))); 2062e23741f4SHaavard Skinnemoen num_erase_regions = qry.num_erase_regions; 2063e23741f4SHaavard Skinnemoen 206459829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 206559829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = (ushort) flash_read_uchar (info, 2066e303be2dSStefan Roese info->ext_addr + 3) << 8; 206759829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version |= (ushort) flash_read_uchar (info, 2068e303be2dSStefan Roese info->ext_addr + 4); 206959829cc1SJean-Christophe PLAGNIOL-VILLARD } 20700ddf06ddSHaavard Skinnemoen 207159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 2072e23741f4SHaavard Skinnemoen flash_printqry (&qry); 207359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 20740ddf06ddSHaavard Skinnemoen 207559829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 20769c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 207759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 207859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 20790ddf06ddSHaavard Skinnemoen cmdset_intel_init(info, &qry); 208059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 208159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 208259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 20830ddf06ddSHaavard Skinnemoen cmdset_amd_init(info, &qry); 208459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 20850ddf06ddSHaavard Skinnemoen default: 20860ddf06ddSHaavard Skinnemoen printf("CFI: Unknown command set 0x%x\n", 20870ddf06ddSHaavard Skinnemoen info->vendor); 20880ddf06ddSHaavard Skinnemoen /* 20890ddf06ddSHaavard Skinnemoen * Unfortunately, this means we don't know how 20900ddf06ddSHaavard Skinnemoen * to get the chip back to Read mode. Might 20910ddf06ddSHaavard Skinnemoen * as well try an Intel-style reset... 20920ddf06ddSHaavard Skinnemoen */ 20930ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 20940ddf06ddSHaavard Skinnemoen return 0; 209559829cc1SJean-Christophe PLAGNIOL-VILLARD } 209659829cc1SJean-Christophe PLAGNIOL-VILLARD 2097467bcee1SHaavard Skinnemoen /* Do manufacturer-specific fixups */ 2098467bcee1SHaavard Skinnemoen switch (info->manufacturer_id) { 20992c9f48afSMario Schuknecht case 0x0001: /* AMD */ 21002c9f48afSMario Schuknecht case 0x0037: /* AMIC */ 2101467bcee1SHaavard Skinnemoen flash_fixup_amd(info, &qry); 2102467bcee1SHaavard Skinnemoen break; 2103467bcee1SHaavard Skinnemoen case 0x001f: 2104467bcee1SHaavard Skinnemoen flash_fixup_atmel(info, &qry); 2105467bcee1SHaavard Skinnemoen break; 2106e8eac437SRichard Retanubun case 0x0020: 2107e8eac437SRichard Retanubun flash_fixup_stm(info, &qry); 2108e8eac437SRichard Retanubun break; 210907b2c5c0SAngelo Dureghello case 0x00bf: /* SST */ 211007b2c5c0SAngelo Dureghello flash_fixup_sst(info, &qry); 211107b2c5c0SAngelo Dureghello break; 2112c502321cSJagannadha Sutradharudu Teki case 0x0089: /* Numonyx */ 2113c502321cSJagannadha Sutradharudu Teki flash_fixup_num(info, &qry); 2114c502321cSJagannadha Sutradharudu Teki break; 2115467bcee1SHaavard Skinnemoen } 2116467bcee1SHaavard Skinnemoen 211759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer is %d\n", info->vendor); 211859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer id is 0x%x\n", info->manufacturer_id); 211959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id is 0x%x\n", info->device_id); 212059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id2 is 0x%x\n", info->device_id2); 212159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("cfi version is 0x%04x\n", info->cfi_version); 212259829cc1SJean-Christophe PLAGNIOL-VILLARD 212359829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio = info->portwidth / info->chipwidth; 212459829cc1SJean-Christophe PLAGNIOL-VILLARD /* if the chip is x8/x16 reduce the ratio by half */ 212559829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->interface == FLASH_CFI_X8X16) 212659829cc1SJean-Christophe PLAGNIOL-VILLARD && (info->chipwidth == FLASH_CFI_BY8)) { 212759829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio >>= 1; 212859829cc1SJean-Christophe PLAGNIOL-VILLARD } 212959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("size_ratio %d port %d bits chip %d bits\n", 213059829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, 213159829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 2132ec50a8e3SIlya Yanok info->size = 1 << qry.dev_size; 2133ec50a8e3SIlya Yanok /* multiply the size by the number of chips */ 2134ec50a8e3SIlya Yanok info->size *= size_ratio; 213534bbb8fbSAnatolij Gustschin max_size = cfi_flash_bank_size(banknum); 2136ec50a8e3SIlya Yanok if (max_size && (info->size > max_size)) { 2137ec50a8e3SIlya Yanok debug("[truncated from %ldMiB]", info->size >> 20); 2138ec50a8e3SIlya Yanok info->size = max_size; 2139ec50a8e3SIlya Yanok } 214059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found %d erase regions\n", num_erase_regions); 214159829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt = 0; 214259829cc1SJean-Christophe PLAGNIOL-VILLARD sector = base; 214359829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < num_erase_regions; i++) { 214459829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > NUM_ERASE_REGIONS) { 214559829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("%d erase regions found, only %d used\n", 214659829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions, NUM_ERASE_REGIONS); 214759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 214859829cc1SJean-Christophe PLAGNIOL-VILLARD } 2149e23741f4SHaavard Skinnemoen 2150aedadf10SAndrew Gabbasov tmp = le32_to_cpu(get_unaligned( 2151aedadf10SAndrew Gabbasov &(qry.erase_region_info[i]))); 21520ddf06ddSHaavard Skinnemoen debug("erase region %u: 0x%08lx\n", i, tmp); 2153e23741f4SHaavard Skinnemoen 2154e23741f4SHaavard Skinnemoen erase_region_count = (tmp & 0xffff) + 1; 2155e23741f4SHaavard Skinnemoen tmp >>= 16; 215659829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_size = 215759829cc1SJean-Christophe PLAGNIOL-VILLARD (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; 215859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("erase_region_count = %d erase_region_size = %d\n", 215959829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count, erase_region_size); 216059829cc1SJean-Christophe PLAGNIOL-VILLARD for (j = 0; j < erase_region_count; j++) { 2161ec50a8e3SIlya Yanok if (sector - base >= info->size) 2162ec50a8e3SIlya Yanok break; 21636d0f6bcfSJean-Christophe PLAGNIOL-VILLARD if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) { 216481b20cccSMichael Schwingen printf("ERROR: too many flash sectors\n"); 216581b20cccSMichael Schwingen break; 216681b20cccSMichael Schwingen } 216709ce9921SBecky Bruce info->start[sect_cnt] = 216809ce9921SBecky Bruce (ulong)map_physmem(sector, 216909ce9921SBecky Bruce info->portwidth, 217009ce9921SBecky Bruce MAP_NOCACHE); 217159829cc1SJean-Christophe PLAGNIOL-VILLARD sector += (erase_region_size * size_ratio); 217259829cc1SJean-Christophe PLAGNIOL-VILLARD 217359829cc1SJean-Christophe PLAGNIOL-VILLARD /* 21747e5b9b47SHaavard Skinnemoen * Only read protection status from 21757e5b9b47SHaavard Skinnemoen * supported devices (intel...) 217659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 217759829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 21789c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 217959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 218059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 2181df4e813bSStefan Roese /* 2182df4e813bSStefan Roese * Set flash to read-id mode. Otherwise 2183df4e813bSStefan Roese * reading protected status is not 2184df4e813bSStefan Roese * guaranteed. 2185df4e813bSStefan Roese */ 2186df4e813bSStefan Roese flash_write_cmd(info, sect_cnt, 0, 2187df4e813bSStefan Roese FLASH_CMD_READ_ID); 218859829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sect_cnt] = 218959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_isset (info, sect_cnt, 219059829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PROTECT, 219159829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_STATUS_PROTECT); 219259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 219303deff43SStefan Roese case CFI_CMDSET_AMD_EXTENDED: 219403deff43SStefan Roese case CFI_CMDSET_AMD_STANDARD: 2195ac6b9115SStefan Roese if (!info->legacy_unlock) { 219603deff43SStefan Roese /* default: not protected */ 219703deff43SStefan Roese info->protect[sect_cnt] = 0; 219803deff43SStefan Roese break; 219903deff43SStefan Roese } 220003deff43SStefan Roese 220103deff43SStefan Roese /* Read protection (PPB) from sector */ 220203deff43SStefan Roese flash_write_cmd(info, 0, 0, 220303deff43SStefan Roese info->cmd_reset); 220403deff43SStefan Roese flash_unlock_seq(info, 0); 220503deff43SStefan Roese flash_write_cmd(info, 0, 220603deff43SStefan Roese info->addr_unlock1, 220703deff43SStefan Roese FLASH_CMD_READ_ID); 220803deff43SStefan Roese info->protect[sect_cnt] = 220903deff43SStefan Roese flash_isset( 221003deff43SStefan Roese info, sect_cnt, 221103deff43SStefan Roese FLASH_OFFSET_PROTECT, 221203deff43SStefan Roese FLASH_STATUS_PROTECT); 221303deff43SStefan Roese break; 221459829cc1SJean-Christophe PLAGNIOL-VILLARD default: 22157e5b9b47SHaavard Skinnemoen /* default: not protected */ 22167e5b9b47SHaavard Skinnemoen info->protect[sect_cnt] = 0; 221759829cc1SJean-Christophe PLAGNIOL-VILLARD } 221859829cc1SJean-Christophe PLAGNIOL-VILLARD 221959829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt++; 222059829cc1SJean-Christophe PLAGNIOL-VILLARD } 222159829cc1SJean-Christophe PLAGNIOL-VILLARD } 222259829cc1SJean-Christophe PLAGNIOL-VILLARD 222359829cc1SJean-Christophe PLAGNIOL-VILLARD info->sector_count = sect_cnt; 2224e23741f4SHaavard Skinnemoen info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size); 2225e23741f4SHaavard Skinnemoen tmp = 1 << qry.block_erase_timeout_typ; 22267e5b9b47SHaavard Skinnemoen info->erase_blk_tout = tmp * 2227e23741f4SHaavard Skinnemoen (1 << qry.block_erase_timeout_max); 2228e23741f4SHaavard Skinnemoen tmp = (1 << qry.buf_write_timeout_typ) * 2229e23741f4SHaavard Skinnemoen (1 << qry.buf_write_timeout_max); 2230e23741f4SHaavard Skinnemoen 22317e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 2232e23741f4SHaavard Skinnemoen info->buffer_write_tout = (tmp + 999) / 1000; 2233e23741f4SHaavard Skinnemoen tmp = (1 << qry.word_write_timeout_typ) * 2234e23741f4SHaavard Skinnemoen (1 << qry.word_write_timeout_max); 22357e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 2236e23741f4SHaavard Skinnemoen info->write_tout = (tmp + 999) / 1000; 223759829cc1SJean-Christophe PLAGNIOL-VILLARD info->flash_id = FLASH_MAN_CFI; 22387e5b9b47SHaavard Skinnemoen if ((info->interface == FLASH_CFI_X8X16) && 22397e5b9b47SHaavard Skinnemoen (info->chipwidth == FLASH_CFI_BY8)) { 22407e5b9b47SHaavard Skinnemoen /* XXX - Need to test on x8/x16 in parallel. */ 22417e5b9b47SHaavard Skinnemoen info->portwidth >>= 1; 224259829cc1SJean-Christophe PLAGNIOL-VILLARD } 224359829cc1SJean-Christophe PLAGNIOL-VILLARD 224459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 22452215987eSMike Frysinger } 22462215987eSMike Frysinger 224759829cc1SJean-Christophe PLAGNIOL-VILLARD return (info->size); 224859829cc1SJean-Christophe PLAGNIOL-VILLARD } 224959829cc1SJean-Christophe PLAGNIOL-VILLARD 22504ffeab2cSMike Frysinger #ifdef CONFIG_FLASH_CFI_MTD 22516ea808efSPiotr Ziecik void flash_set_verbose(uint v) 22526ea808efSPiotr Ziecik { 22536ea808efSPiotr Ziecik flash_verbose = v; 22546ea808efSPiotr Ziecik } 22554ffeab2cSMike Frysinger #endif 22566ea808efSPiotr Ziecik 22576f726f95SStefan Roese static void cfi_flash_set_config_reg(u32 base, u16 val) 22586f726f95SStefan Roese { 22596f726f95SStefan Roese #ifdef CONFIG_SYS_CFI_FLASH_CONFIG_REGS 22606f726f95SStefan Roese /* 22616f726f95SStefan Roese * Only set this config register if really defined 22626f726f95SStefan Roese * to a valid value (0xffff is invalid) 22636f726f95SStefan Roese */ 22646f726f95SStefan Roese if (val == 0xffff) 22656f726f95SStefan Roese return; 22666f726f95SStefan Roese 22676f726f95SStefan Roese /* 22686f726f95SStefan Roese * Set configuration register. Data is "encrypted" in the 16 lower 22696f726f95SStefan Roese * address bits. 22706f726f95SStefan Roese */ 22716f726f95SStefan Roese flash_write16(FLASH_CMD_SETUP, (void *)(base + (val << 1))); 22726f726f95SStefan Roese flash_write16(FLASH_CMD_SET_CR_CONFIRM, (void *)(base + (val << 1))); 22736f726f95SStefan Roese 22746f726f95SStefan Roese /* 22756f726f95SStefan Roese * Finally issue reset-command to bring device back to 22766f726f95SStefan Roese * read-array mode 22776f726f95SStefan Roese */ 22786f726f95SStefan Roese flash_write16(FLASH_CMD_RESET, (void *)base); 22796f726f95SStefan Roese #endif 22806f726f95SStefan Roese } 22816f726f95SStefan Roese 228259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 228359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 22846ee1416eSHeiko Schocher 22856ee1416eSHeiko Schocher void flash_protect_default(void) 22866ee1416eSHeiko Schocher { 22872c51983bSPeter Tyser #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) 22882c51983bSPeter Tyser int i; 22892c51983bSPeter Tyser struct apl_s { 22902c51983bSPeter Tyser ulong start; 22912c51983bSPeter Tyser ulong size; 22922c51983bSPeter Tyser } apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST; 22932c51983bSPeter Tyser #endif 22942c51983bSPeter Tyser 22956ee1416eSHeiko Schocher /* Monitor protection ON by default */ 22966ee1416eSHeiko Schocher #if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE) && \ 22976ee1416eSHeiko Schocher (!defined(CONFIG_MONITOR_IS_IN_RAM)) 22986ee1416eSHeiko Schocher flash_protect(FLAG_PROTECT_SET, 22996ee1416eSHeiko Schocher CONFIG_SYS_MONITOR_BASE, 23006ee1416eSHeiko Schocher CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, 23016ee1416eSHeiko Schocher flash_get_info(CONFIG_SYS_MONITOR_BASE)); 23026ee1416eSHeiko Schocher #endif 23036ee1416eSHeiko Schocher 23046ee1416eSHeiko Schocher /* Environment protection ON by default */ 23056ee1416eSHeiko Schocher #ifdef CONFIG_ENV_IS_IN_FLASH 23066ee1416eSHeiko Schocher flash_protect(FLAG_PROTECT_SET, 23076ee1416eSHeiko Schocher CONFIG_ENV_ADDR, 23086ee1416eSHeiko Schocher CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1, 23096ee1416eSHeiko Schocher flash_get_info(CONFIG_ENV_ADDR)); 23106ee1416eSHeiko Schocher #endif 23116ee1416eSHeiko Schocher 23126ee1416eSHeiko Schocher /* Redundant environment protection ON by default */ 23136ee1416eSHeiko Schocher #ifdef CONFIG_ENV_ADDR_REDUND 23146ee1416eSHeiko Schocher flash_protect(FLAG_PROTECT_SET, 23156ee1416eSHeiko Schocher CONFIG_ENV_ADDR_REDUND, 23166ee1416eSHeiko Schocher CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1, 23176ee1416eSHeiko Schocher flash_get_info(CONFIG_ENV_ADDR_REDUND)); 23186ee1416eSHeiko Schocher #endif 23196ee1416eSHeiko Schocher 23206ee1416eSHeiko Schocher #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) 232131bf0f57SAxel Lin for (i = 0; i < ARRAY_SIZE(apl); i++) { 232231d34143SMarek Vasut debug("autoprotecting from %08lx to %08lx\n", 23236ee1416eSHeiko Schocher apl[i].start, apl[i].start + apl[i].size - 1); 23246ee1416eSHeiko Schocher flash_protect(FLAG_PROTECT_SET, 23256ee1416eSHeiko Schocher apl[i].start, 23266ee1416eSHeiko Schocher apl[i].start + apl[i].size - 1, 23276ee1416eSHeiko Schocher flash_get_info(apl[i].start)); 23286ee1416eSHeiko Schocher } 23296ee1416eSHeiko Schocher #endif 23306ee1416eSHeiko Schocher } 23316ee1416eSHeiko Schocher 2332be60a902SHaavard Skinnemoen unsigned long flash_init (void) 233359829cc1SJean-Christophe PLAGNIOL-VILLARD { 2334be60a902SHaavard Skinnemoen unsigned long size = 0; 2335be60a902SHaavard Skinnemoen int i; 233659829cc1SJean-Christophe PLAGNIOL-VILLARD 23376d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 23383a3baf3eSEric Schumann /* read environment from EEPROM */ 23393a3baf3eSEric Schumann char s[64]; 2340cdb74977SWolfgang Denk getenv_f("unlock", s, sizeof(s)); 234181b20cccSMichael Schwingen #endif 2342be60a902SHaavard Skinnemoen 2343be60a902SHaavard Skinnemoen /* Init: no FLASHes known */ 23446d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) { 2345be60a902SHaavard Skinnemoen flash_info[i].flash_id = FLASH_UNKNOWN; 2346be60a902SHaavard Skinnemoen 23476f726f95SStefan Roese /* Optionally write flash configuration register */ 23486f726f95SStefan Roese cfi_flash_set_config_reg(cfi_flash_bank_addr(i), 23496f726f95SStefan Roese cfi_flash_config_reg(i)); 23506f726f95SStefan Roese 2351b00e19ccSStefan Roese if (!flash_detect_legacy(cfi_flash_bank_addr(i), i)) 235234bbb8fbSAnatolij Gustschin flash_get_size(cfi_flash_bank_addr(i), i); 2353be60a902SHaavard Skinnemoen size += flash_info[i].size; 2354be60a902SHaavard Skinnemoen if (flash_info[i].flash_id == FLASH_UNKNOWN) { 23556d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_QUIET_TEST 2356eddf52b5SPeter Tyser printf ("## Unknown flash on Bank %d " 2357be60a902SHaavard Skinnemoen "- Size = 0x%08lx = %ld MB\n", 2358be60a902SHaavard Skinnemoen i+1, flash_info[i].size, 23590e3fa01aSJohn Schmoller flash_info[i].size >> 20); 23606d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_QUIET_TEST */ 236159829cc1SJean-Christophe PLAGNIOL-VILLARD } 23626d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 2363*c15df21fSJeroen Hofstee else if (strcmp(s, "yes") == 0) { 2364be60a902SHaavard Skinnemoen /* 2365be60a902SHaavard Skinnemoen * Only the U-Boot image and it's environment 2366be60a902SHaavard Skinnemoen * is protected, all other sectors are 2367be60a902SHaavard Skinnemoen * unprotected (unlocked) if flash hardware 23686d0f6bcfSJean-Christophe PLAGNIOL-VILLARD * protection is used (CONFIG_SYS_FLASH_PROTECTION) 2369be60a902SHaavard Skinnemoen * and the environment variable "unlock" is 2370be60a902SHaavard Skinnemoen * set to "yes". 2371be60a902SHaavard Skinnemoen */ 2372be60a902SHaavard Skinnemoen if (flash_info[i].legacy_unlock) { 2373be60a902SHaavard Skinnemoen int k; 237459829cc1SJean-Christophe PLAGNIOL-VILLARD 2375be60a902SHaavard Skinnemoen /* 2376be60a902SHaavard Skinnemoen * Disable legacy_unlock temporarily, 2377be60a902SHaavard Skinnemoen * since flash_real_protect would 2378be60a902SHaavard Skinnemoen * relock all other sectors again 2379be60a902SHaavard Skinnemoen * otherwise. 2380be60a902SHaavard Skinnemoen */ 2381be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 0; 238259829cc1SJean-Christophe PLAGNIOL-VILLARD 2383be60a902SHaavard Skinnemoen /* 2384be60a902SHaavard Skinnemoen * Legacy unlocking (e.g. Intel J3) -> 2385be60a902SHaavard Skinnemoen * unlock only one sector. This will 2386be60a902SHaavard Skinnemoen * unlock all sectors. 2387be60a902SHaavard Skinnemoen */ 2388be60a902SHaavard Skinnemoen flash_real_protect (&flash_info[i], 0, 0); 238959829cc1SJean-Christophe PLAGNIOL-VILLARD 2390be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 1; 239159829cc1SJean-Christophe PLAGNIOL-VILLARD 2392be60a902SHaavard Skinnemoen /* 2393be60a902SHaavard Skinnemoen * Manually mark other sectors as 2394be60a902SHaavard Skinnemoen * unlocked (unprotected) 2395be60a902SHaavard Skinnemoen */ 2396be60a902SHaavard Skinnemoen for (k = 1; k < flash_info[i].sector_count; k++) 2397be60a902SHaavard Skinnemoen flash_info[i].protect[k] = 0; 2398be60a902SHaavard Skinnemoen } else { 2399be60a902SHaavard Skinnemoen /* 2400be60a902SHaavard Skinnemoen * No legancy unlocking -> unlock all sectors 2401be60a902SHaavard Skinnemoen */ 2402be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_CLEAR, 2403be60a902SHaavard Skinnemoen flash_info[i].start[0], 2404be60a902SHaavard Skinnemoen flash_info[i].start[0] 2405be60a902SHaavard Skinnemoen + flash_info[i].size - 1, 2406be60a902SHaavard Skinnemoen &flash_info[i]); 240759829cc1SJean-Christophe PLAGNIOL-VILLARD } 240859829cc1SJean-Christophe PLAGNIOL-VILLARD } 24096d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */ 241059829cc1SJean-Christophe PLAGNIOL-VILLARD } 241159829cc1SJean-Christophe PLAGNIOL-VILLARD 24126ee1416eSHeiko Schocher flash_protect_default(); 241391809ed5SPiotr Ziecik #ifdef CONFIG_FLASH_CFI_MTD 241491809ed5SPiotr Ziecik cfi_mtd_init(); 241591809ed5SPiotr Ziecik #endif 241691809ed5SPiotr Ziecik 2417be60a902SHaavard Skinnemoen return (size); 241859829cc1SJean-Christophe PLAGNIOL-VILLARD } 2419