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 * 1459829cc1SJean-Christophe PLAGNIOL-VILLARD * See file CREDITS for list of people who contributed to this 1559829cc1SJean-Christophe PLAGNIOL-VILLARD * project. 1659829cc1SJean-Christophe PLAGNIOL-VILLARD * 1759829cc1SJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or 1859829cc1SJean-Christophe PLAGNIOL-VILLARD * modify it under the terms of the GNU General Public License as 1959829cc1SJean-Christophe PLAGNIOL-VILLARD * published by the Free Software Foundation; either version 2 of 2059829cc1SJean-Christophe PLAGNIOL-VILLARD * the License, or (at your option) any later version. 2159829cc1SJean-Christophe PLAGNIOL-VILLARD * 2259829cc1SJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 2359829cc1SJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 2459829cc1SJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2559829cc1SJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 2659829cc1SJean-Christophe PLAGNIOL-VILLARD * 2759829cc1SJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 2859829cc1SJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 2959829cc1SJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 3059829cc1SJean-Christophe PLAGNIOL-VILLARD * MA 02111-1307 USA 3159829cc1SJean-Christophe PLAGNIOL-VILLARD * 3259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3359829cc1SJean-Christophe PLAGNIOL-VILLARD 3459829cc1SJean-Christophe PLAGNIOL-VILLARD /* The DEBUG define must be before common to enable debugging */ 3559829cc1SJean-Christophe PLAGNIOL-VILLARD /* #define DEBUG */ 3659829cc1SJean-Christophe PLAGNIOL-VILLARD 3759829cc1SJean-Christophe PLAGNIOL-VILLARD #include <common.h> 3859829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/processor.h> 3959829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h> 4059829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/byteorder.h> 4159829cc1SJean-Christophe PLAGNIOL-VILLARD #include <environment.h> 4259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_CFI_DRIVER 4359829cc1SJean-Christophe PLAGNIOL-VILLARD 4459829cc1SJean-Christophe PLAGNIOL-VILLARD /* 457e5b9b47SHaavard Skinnemoen * This file implements a Common Flash Interface (CFI) driver for 467e5b9b47SHaavard Skinnemoen * U-Boot. 477e5b9b47SHaavard Skinnemoen * 487e5b9b47SHaavard Skinnemoen * The width of the port and the width of the chips are determined at 497e5b9b47SHaavard Skinnemoen * initialization. These widths are used to calculate the address for 507e5b9b47SHaavard Skinnemoen * access CFI data structures. 5159829cc1SJean-Christophe PLAGNIOL-VILLARD * 5259829cc1SJean-Christophe PLAGNIOL-VILLARD * References 5359829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JESD68 - Common Flash Interface (CFI) 5459829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes 5559829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets 5659829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet 5759829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD CFI Specification, Release 2.0 December 1, 2001 5859829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD/Spansion Application Note: Migration from Single-byte to Three-byte 5959829cc1SJean-Christophe PLAGNIOL-VILLARD * Device IDs, Publication Number 25538 Revision A, November 8, 2001 6059829cc1SJean-Christophe PLAGNIOL-VILLARD * 617e5b9b47SHaavard Skinnemoen * Define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between 6259829cc1SJean-Christophe PLAGNIOL-VILLARD * reading and writing ... (yes there is such a Hardware). 6359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 6459829cc1SJean-Christophe PLAGNIOL-VILLARD 6559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_BANKS_LIST 6659829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE } 6759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 6859829cc1SJean-Christophe PLAGNIOL-VILLARD 6959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CFI 0x98 7059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_READ_ID 0x90 7159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_RESET 0xff 7259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_BLOCK_ERASE 0x20 7359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_ERASE_CONFIRM 0xD0 7459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE 0x40 7559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT 0x60 7659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_SET 0x01 7759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_CLEAR 0xD0 7859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CLEAR_STATUS 0x50 7959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_TO_BUFFER 0xE8 8059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0 8159829cc1SJean-Christophe PLAGNIOL-VILLARD 8259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DONE 0x80 8359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ESS 0x40 8459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ECLBS 0x20 8559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSLBS 0x10 8659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_VPENS 0x08 8759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSS 0x04 8859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DPS 0x02 8959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_R 0x01 9059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PROTECT 0x01 9159829cc1SJean-Christophe PLAGNIOL-VILLARD 9259829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_RESET 0xF0 9359829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE 0xA0 9459829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_START 0x80 9559829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_SECTOR 0x30 9659829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_START 0xAA 9759829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_ACK 0x55 9859829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_TO_BUFFER 0x25 9959829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29 10059829cc1SJean-Christophe PLAGNIOL-VILLARD 10159829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_TOGGLE 0x40 10259829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_ERROR 0x20 10359829cc1SJean-Christophe PLAGNIOL-VILLARD 10459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_MANUFACTURER_ID 0x00 10559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID 0x01 10659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID2 0x0E 10759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID3 0x0F 10859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI 0x55 10959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_ALT 0x555 11059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_RESP 0x10 11159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PRIMARY_VENDOR 0x13 1127e5b9b47SHaavard Skinnemoen /* extended query table primary address */ 1137e5b9b47SHaavard Skinnemoen #define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15 11459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WTOUT 0x1F 11559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBTOUT 0x20 11659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ETOUT 0x21 11759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CETOUT 0x22 11859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WMAX_TOUT 0x23 11959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBMAX_TOUT 0x24 12059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EMAX_TOUT 0x25 12159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CEMAX_TOUT 0x26 12259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_SIZE 0x27 12359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTERFACE 0x28 12459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_BUFFER_SIZE 0x2A 12559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C 12659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ERASE_REGIONS 0x2D 12759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PROTECT 0x02 12859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_USER_PROTECTION 0x85 12959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTEL_PROTECTION 0x81 13059829cc1SJean-Christophe PLAGNIOL-VILLARD 13159829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_NONE 0 13259829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_EXTENDED 1 13359829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_STANDARD 2 13459829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_STANDARD 3 13559829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_EXTENDED 4 13659829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_STANDARD 256 13759829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_EXTENDED 257 13859829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_SST 258 13959829cc1SJean-Christophe PLAGNIOL-VILLARD 14059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */ 14159829cc1SJean-Christophe PLAGNIOL-VILLARD # undef FLASH_CMD_RESET 14259829cc1SJean-Christophe PLAGNIOL-VILLARD # define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */ 14359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 14459829cc1SJean-Christophe PLAGNIOL-VILLARD 14559829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union { 14659829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned char c; 14759829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned short w; 14859829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long l; 14959829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long long ll; 15059829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiword_t; 15159829cc1SJean-Christophe PLAGNIOL-VILLARD 15259829cc1SJean-Christophe PLAGNIOL-VILLARD #define NUM_ERASE_REGIONS 4 /* max. number of erase regions */ 15359829cc1SJean-Christophe PLAGNIOL-VILLARD 15459829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT }; 15559829cc1SJean-Christophe PLAGNIOL-VILLARD 15659829cc1SJean-Christophe PLAGNIOL-VILLARD /* use CFG_MAX_FLASH_BANKS_DETECT if defined */ 15759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_MAX_FLASH_BANKS_DETECT 15859829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS_DETECT] = CFG_FLASH_BANKS_LIST; 15959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS_DETECT]; /* FLASH chips info */ 16059829cc1SJean-Christophe PLAGNIOL-VILLARD #else 16159829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST; 16259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */ 16359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 16459829cc1SJean-Christophe PLAGNIOL-VILLARD 16559829cc1SJean-Christophe PLAGNIOL-VILLARD /* 16659829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if chip width is defined. If not, start detecting with 8bit. 16759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 16859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_CFI_WIDTH 16959829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_CFI_WIDTH FLASH_CFI_8BIT 17059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 17159829cc1SJean-Christophe PLAGNIOL-VILLARD 17259829cc1SJean-Christophe PLAGNIOL-VILLARD typedef unsigned long flash_sect_t; 17359829cc1SJean-Christophe PLAGNIOL-VILLARD 174e23741f4SHaavard Skinnemoen /* CFI standard query structure */ 175e23741f4SHaavard Skinnemoen struct cfi_qry { 176e23741f4SHaavard Skinnemoen u8 qry[3]; 177e23741f4SHaavard Skinnemoen u16 p_id; 178e23741f4SHaavard Skinnemoen u16 p_adr; 179e23741f4SHaavard Skinnemoen u16 a_id; 180e23741f4SHaavard Skinnemoen u16 a_adr; 181e23741f4SHaavard Skinnemoen u8 vcc_min; 182e23741f4SHaavard Skinnemoen u8 vcc_max; 183e23741f4SHaavard Skinnemoen u8 vpp_min; 184e23741f4SHaavard Skinnemoen u8 vpp_max; 185e23741f4SHaavard Skinnemoen u8 word_write_timeout_typ; 186e23741f4SHaavard Skinnemoen u8 buf_write_timeout_typ; 187e23741f4SHaavard Skinnemoen u8 block_erase_timeout_typ; 188e23741f4SHaavard Skinnemoen u8 chip_erase_timeout_typ; 189e23741f4SHaavard Skinnemoen u8 word_write_timeout_max; 190e23741f4SHaavard Skinnemoen u8 buf_write_timeout_max; 191e23741f4SHaavard Skinnemoen u8 block_erase_timeout_max; 192e23741f4SHaavard Skinnemoen u8 chip_erase_timeout_max; 193e23741f4SHaavard Skinnemoen u8 dev_size; 194e23741f4SHaavard Skinnemoen u16 interface_desc; 195e23741f4SHaavard Skinnemoen u16 max_buf_write_size; 196e23741f4SHaavard Skinnemoen u8 num_erase_regions; 197e23741f4SHaavard Skinnemoen u32 erase_region_info[NUM_ERASE_REGIONS]; 198e23741f4SHaavard Skinnemoen } __attribute__((packed)); 199e23741f4SHaavard Skinnemoen 200e23741f4SHaavard Skinnemoen struct cfi_pri_hdr { 201e23741f4SHaavard Skinnemoen u8 pri[3]; 202e23741f4SHaavard Skinnemoen u8 major_version; 203e23741f4SHaavard Skinnemoen u8 minor_version; 204e23741f4SHaavard Skinnemoen } __attribute__((packed)); 205e23741f4SHaavard Skinnemoen 206cdbaefb5SHaavard Skinnemoen static void flash_write8(u8 value, void *addr) 207cdbaefb5SHaavard Skinnemoen { 208cdbaefb5SHaavard Skinnemoen __raw_writeb(value, addr); 209cdbaefb5SHaavard Skinnemoen } 210cdbaefb5SHaavard Skinnemoen 211cdbaefb5SHaavard Skinnemoen static void flash_write16(u16 value, void *addr) 212cdbaefb5SHaavard Skinnemoen { 213cdbaefb5SHaavard Skinnemoen __raw_writew(value, addr); 214cdbaefb5SHaavard Skinnemoen } 215cdbaefb5SHaavard Skinnemoen 216cdbaefb5SHaavard Skinnemoen static void flash_write32(u32 value, void *addr) 217cdbaefb5SHaavard Skinnemoen { 218cdbaefb5SHaavard Skinnemoen __raw_writel(value, addr); 219cdbaefb5SHaavard Skinnemoen } 220cdbaefb5SHaavard Skinnemoen 221cdbaefb5SHaavard Skinnemoen static void flash_write64(u64 value, void *addr) 222cdbaefb5SHaavard Skinnemoen { 223cdbaefb5SHaavard Skinnemoen /* No architectures currently implement __raw_writeq() */ 224cdbaefb5SHaavard Skinnemoen *(volatile u64 *)addr = value; 225cdbaefb5SHaavard Skinnemoen } 226cdbaefb5SHaavard Skinnemoen 227cdbaefb5SHaavard Skinnemoen static u8 flash_read8(void *addr) 228cdbaefb5SHaavard Skinnemoen { 229cdbaefb5SHaavard Skinnemoen return __raw_readb(addr); 230cdbaefb5SHaavard Skinnemoen } 231cdbaefb5SHaavard Skinnemoen 232cdbaefb5SHaavard Skinnemoen static u16 flash_read16(void *addr) 233cdbaefb5SHaavard Skinnemoen { 234cdbaefb5SHaavard Skinnemoen return __raw_readw(addr); 235cdbaefb5SHaavard Skinnemoen } 236cdbaefb5SHaavard Skinnemoen 237cdbaefb5SHaavard Skinnemoen static u32 flash_read32(void *addr) 238cdbaefb5SHaavard Skinnemoen { 239cdbaefb5SHaavard Skinnemoen return __raw_readl(addr); 240cdbaefb5SHaavard Skinnemoen } 241cdbaefb5SHaavard Skinnemoen 242cdbaefb5SHaavard Skinnemoen static u64 flash_read64(void *addr) 243cdbaefb5SHaavard Skinnemoen { 244cdbaefb5SHaavard Skinnemoen /* No architectures currently implement __raw_readq() */ 245cdbaefb5SHaavard Skinnemoen return *(volatile u64 *)addr; 246cdbaefb5SHaavard Skinnemoen } 247cdbaefb5SHaavard Skinnemoen 248be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 249be60a902SHaavard Skinnemoen */ 25059829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 251be60a902SHaavard Skinnemoen static flash_info_t *flash_get_info(ulong base) 252be60a902SHaavard Skinnemoen { 253be60a902SHaavard Skinnemoen int i; 254be60a902SHaavard Skinnemoen flash_info_t * info = 0; 255be60a902SHaavard Skinnemoen 256be60a902SHaavard Skinnemoen for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { 257be60a902SHaavard Skinnemoen info = & flash_info[i]; 258be60a902SHaavard Skinnemoen if (info->size && info->start[0] <= base && 259be60a902SHaavard Skinnemoen base <= info->start[0] + info->size - 1) 260be60a902SHaavard Skinnemoen break; 261be60a902SHaavard Skinnemoen } 262be60a902SHaavard Skinnemoen 263be60a902SHaavard Skinnemoen return i == CFG_MAX_FLASH_BANKS ? 0 : info; 264be60a902SHaavard Skinnemoen } 26559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 26659829cc1SJean-Christophe PLAGNIOL-VILLARD 26712d30aa7SHaavard Skinnemoen unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect) 26812d30aa7SHaavard Skinnemoen { 26912d30aa7SHaavard Skinnemoen if (sect != (info->sector_count - 1)) 27012d30aa7SHaavard Skinnemoen return info->start[sect + 1] - info->start[sect]; 27112d30aa7SHaavard Skinnemoen else 27212d30aa7SHaavard Skinnemoen return info->start[0] + info->size - info->start[sect]; 27312d30aa7SHaavard Skinnemoen } 27412d30aa7SHaavard Skinnemoen 27559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 27659829cc1SJean-Christophe PLAGNIOL-VILLARD * create an address based on the offset and the port width 27759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 27812d30aa7SHaavard Skinnemoen static inline void * 27912d30aa7SHaavard Skinnemoen flash_map (flash_info_t * info, flash_sect_t sect, uint offset) 28059829cc1SJean-Christophe PLAGNIOL-VILLARD { 28112d30aa7SHaavard Skinnemoen unsigned int byte_offset = offset * info->portwidth; 28212d30aa7SHaavard Skinnemoen 28312d30aa7SHaavard Skinnemoen return map_physmem(info->start[sect] + byte_offset, 28412d30aa7SHaavard Skinnemoen flash_sector_size(info, sect) - byte_offset, 28512d30aa7SHaavard Skinnemoen MAP_NOCACHE); 28612d30aa7SHaavard Skinnemoen } 28712d30aa7SHaavard Skinnemoen 28812d30aa7SHaavard Skinnemoen static inline void flash_unmap(flash_info_t *info, flash_sect_t sect, 28912d30aa7SHaavard Skinnemoen unsigned int offset, void *addr) 29012d30aa7SHaavard Skinnemoen { 29112d30aa7SHaavard Skinnemoen unsigned int byte_offset = offset * info->portwidth; 29212d30aa7SHaavard Skinnemoen 29312d30aa7SHaavard Skinnemoen unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset); 29459829cc1SJean-Christophe PLAGNIOL-VILLARD } 29559829cc1SJean-Christophe PLAGNIOL-VILLARD 296be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 297be60a902SHaavard Skinnemoen * make a proper sized command based on the port and chip widths 298be60a902SHaavard Skinnemoen */ 299be60a902SHaavard Skinnemoen static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf) 300be60a902SHaavard Skinnemoen { 301be60a902SHaavard Skinnemoen int i; 302be60a902SHaavard Skinnemoen uchar *cp = (uchar *) cmdbuf; 303be60a902SHaavard Skinnemoen 304be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 305be60a902SHaavard Skinnemoen for (i = info->portwidth; i > 0; i--) 306be60a902SHaavard Skinnemoen #else 307be60a902SHaavard Skinnemoen for (i = 1; i <= info->portwidth; i++) 308be60a902SHaavard Skinnemoen #endif 309be60a902SHaavard Skinnemoen *cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd; 310be60a902SHaavard Skinnemoen } 311be60a902SHaavard Skinnemoen 31259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 31359829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 31459829cc1SJean-Christophe PLAGNIOL-VILLARD * Debug support 31559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3163055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data) 31759829cc1SJean-Christophe PLAGNIOL-VILLARD { 31859829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 31959829cc1SJean-Christophe PLAGNIOL-VILLARD char *cp; 32059829cc1SJean-Christophe PLAGNIOL-VILLARD 32159829cc1SJean-Christophe PLAGNIOL-VILLARD cp = (unsigned char *) &data; 32259829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < 8; i++) 32359829cc1SJean-Christophe PLAGNIOL-VILLARD sprintf (&str[i * 2], "%2.2x", *cp++); 32459829cc1SJean-Christophe PLAGNIOL-VILLARD } 325be60a902SHaavard Skinnemoen 326e23741f4SHaavard Skinnemoen static void flash_printqry (struct cfi_qry *qry) 32759829cc1SJean-Christophe PLAGNIOL-VILLARD { 328e23741f4SHaavard Skinnemoen u8 *p = (u8 *)qry; 32959829cc1SJean-Christophe PLAGNIOL-VILLARD int x, y; 33059829cc1SJean-Christophe PLAGNIOL-VILLARD 331e23741f4SHaavard Skinnemoen for (x = 0; x < sizeof(struct cfi_qry); x += 16) { 332e23741f4SHaavard Skinnemoen debug("%02x : ", x); 333e23741f4SHaavard Skinnemoen for (y = 0; y < 16; y++) 334e23741f4SHaavard Skinnemoen debug("%2.2x ", p[x + y]); 33559829cc1SJean-Christophe PLAGNIOL-VILLARD debug(" "); 33659829cc1SJean-Christophe PLAGNIOL-VILLARD for (y = 0; y < 16; y++) { 337e23741f4SHaavard Skinnemoen unsigned char c = p[x + y]; 338e23741f4SHaavard Skinnemoen if (c >= 0x20 && c <= 0x7e) 339cdbaefb5SHaavard Skinnemoen debug("%c", c); 340e23741f4SHaavard Skinnemoen else 34159829cc1SJean-Christophe PLAGNIOL-VILLARD debug("."); 34259829cc1SJean-Christophe PLAGNIOL-VILLARD } 34359829cc1SJean-Christophe PLAGNIOL-VILLARD debug("\n"); 34459829cc1SJean-Christophe PLAGNIOL-VILLARD } 34559829cc1SJean-Christophe PLAGNIOL-VILLARD } 34659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 34759829cc1SJean-Christophe PLAGNIOL-VILLARD 34859829cc1SJean-Christophe PLAGNIOL-VILLARD 34959829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 35059829cc1SJean-Christophe PLAGNIOL-VILLARD * read a character at a port width address 35159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3523055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset) 35359829cc1SJean-Christophe PLAGNIOL-VILLARD { 35459829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *cp; 35512d30aa7SHaavard Skinnemoen uchar retval; 35659829cc1SJean-Christophe PLAGNIOL-VILLARD 35712d30aa7SHaavard Skinnemoen cp = flash_map (info, 0, offset); 35859829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 35912d30aa7SHaavard Skinnemoen retval = flash_read8(cp); 36059829cc1SJean-Christophe PLAGNIOL-VILLARD #else 36112d30aa7SHaavard Skinnemoen retval = flash_read8(cp + info->portwidth - 1); 36259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 36312d30aa7SHaavard Skinnemoen flash_unmap (info, 0, offset, cp); 36412d30aa7SHaavard Skinnemoen return retval; 36559829cc1SJean-Christophe PLAGNIOL-VILLARD } 36659829cc1SJean-Christophe PLAGNIOL-VILLARD 36759829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 36859829cc1SJean-Christophe PLAGNIOL-VILLARD * read a long word by picking the least significant byte of each maximum 36959829cc1SJean-Christophe PLAGNIOL-VILLARD * port size word. Swap for ppc format. 37059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3713055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect, 3723055793bSHaavard Skinnemoen uint offset) 37359829cc1SJean-Christophe PLAGNIOL-VILLARD { 37459829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *addr; 37559829cc1SJean-Christophe PLAGNIOL-VILLARD ulong retval; 37659829cc1SJean-Christophe PLAGNIOL-VILLARD 37759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 37859829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 37959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 38012d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 38159829cc1SJean-Christophe PLAGNIOL-VILLARD 38259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 38359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("long addr is at %p info->portwidth = %d\n", addr, 38459829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth); 38559829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 4 * info->portwidth; x++) { 38612d30aa7SHaavard Skinnemoen debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x)); 38759829cc1SJean-Christophe PLAGNIOL-VILLARD } 38859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 38959829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 39012d30aa7SHaavard Skinnemoen retval = ((flash_read8(addr) << 16) | 39112d30aa7SHaavard Skinnemoen (flash_read8(addr + info->portwidth) << 24) | 39212d30aa7SHaavard Skinnemoen (flash_read8(addr + 2 * info->portwidth)) | 39312d30aa7SHaavard Skinnemoen (flash_read8(addr + 3 * info->portwidth) << 8)); 39459829cc1SJean-Christophe PLAGNIOL-VILLARD #else 39512d30aa7SHaavard Skinnemoen retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) | 39612d30aa7SHaavard Skinnemoen (flash_read8(addr + info->portwidth - 1) << 16) | 39712d30aa7SHaavard Skinnemoen (flash_read8(addr + 4 * info->portwidth - 1) << 8) | 39812d30aa7SHaavard Skinnemoen (flash_read8(addr + 3 * info->portwidth - 1))); 39959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 40012d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 40112d30aa7SHaavard Skinnemoen 40259829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 40359829cc1SJean-Christophe PLAGNIOL-VILLARD } 40459829cc1SJean-Christophe PLAGNIOL-VILLARD 405be60a902SHaavard Skinnemoen /* 406be60a902SHaavard Skinnemoen * Write a proper sized command to the correct address 40781b20cccSMichael Schwingen */ 408be60a902SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, 409be60a902SHaavard Skinnemoen uint offset, uchar cmd) 41081b20cccSMichael Schwingen { 4117e5b9b47SHaavard Skinnemoen 412cdbaefb5SHaavard Skinnemoen void *addr; 413be60a902SHaavard Skinnemoen cfiword_t cword; 41481b20cccSMichael Schwingen 41512d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 416be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 417be60a902SHaavard Skinnemoen switch (info->portwidth) { 418be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 419cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd, 420be60a902SHaavard Skinnemoen cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 421cdbaefb5SHaavard Skinnemoen flash_write8(cword.c, addr); 422be60a902SHaavard Skinnemoen break; 423be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 424cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr, 425be60a902SHaavard Skinnemoen cmd, cword.w, 426be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 427cdbaefb5SHaavard Skinnemoen flash_write16(cword.w, addr); 428be60a902SHaavard Skinnemoen break; 429be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 430cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr, 431be60a902SHaavard Skinnemoen cmd, cword.l, 432be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 433cdbaefb5SHaavard Skinnemoen flash_write32(cword.l, addr); 434be60a902SHaavard Skinnemoen break; 435be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 436be60a902SHaavard Skinnemoen #ifdef DEBUG 437be60a902SHaavard Skinnemoen { 438be60a902SHaavard Skinnemoen char str[20]; 439be60a902SHaavard Skinnemoen 440be60a902SHaavard Skinnemoen print_longlong (str, cword.ll); 441be60a902SHaavard Skinnemoen 442be60a902SHaavard Skinnemoen debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n", 443cdbaefb5SHaavard Skinnemoen addr, cmd, str, 444be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 44581b20cccSMichael Schwingen } 446be60a902SHaavard Skinnemoen #endif 447cdbaefb5SHaavard Skinnemoen flash_write64(cword.ll, addr); 44881b20cccSMichael Schwingen break; 44981b20cccSMichael Schwingen } 450be60a902SHaavard Skinnemoen 451be60a902SHaavard Skinnemoen /* Ensure all the instructions are fully finished */ 452be60a902SHaavard Skinnemoen sync(); 45312d30aa7SHaavard Skinnemoen 45412d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 45581b20cccSMichael Schwingen } 4567e5b9b47SHaavard Skinnemoen 457be60a902SHaavard Skinnemoen static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect) 458be60a902SHaavard Skinnemoen { 459be60a902SHaavard Skinnemoen flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START); 460be60a902SHaavard Skinnemoen flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK); 461be60a902SHaavard Skinnemoen } 462be60a902SHaavard Skinnemoen 463be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 464be60a902SHaavard Skinnemoen */ 465be60a902SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect, 466be60a902SHaavard Skinnemoen uint offset, uchar cmd) 467be60a902SHaavard Skinnemoen { 468cdbaefb5SHaavard Skinnemoen void *addr; 469be60a902SHaavard Skinnemoen cfiword_t cword; 470be60a902SHaavard Skinnemoen int retval; 471be60a902SHaavard Skinnemoen 47212d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 473be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 474be60a902SHaavard Skinnemoen 475cdbaefb5SHaavard Skinnemoen debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr); 476be60a902SHaavard Skinnemoen switch (info->portwidth) { 477be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 478cdbaefb5SHaavard Skinnemoen debug ("is= %x %x\n", flash_read8(addr), cword.c); 479cdbaefb5SHaavard Skinnemoen retval = (flash_read8(addr) == cword.c); 480be60a902SHaavard Skinnemoen break; 481be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 482cdbaefb5SHaavard Skinnemoen debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w); 483cdbaefb5SHaavard Skinnemoen retval = (flash_read16(addr) == cword.w); 484be60a902SHaavard Skinnemoen break; 485be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 486cdbaefb5SHaavard Skinnemoen debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l); 487cdbaefb5SHaavard Skinnemoen retval = (flash_read32(addr) == cword.l); 488be60a902SHaavard Skinnemoen break; 489be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 490be60a902SHaavard Skinnemoen #ifdef DEBUG 491be60a902SHaavard Skinnemoen { 492be60a902SHaavard Skinnemoen char str1[20]; 493be60a902SHaavard Skinnemoen char str2[20]; 494be60a902SHaavard Skinnemoen 495cdbaefb5SHaavard Skinnemoen print_longlong (str1, flash_read64(addr)); 496be60a902SHaavard Skinnemoen print_longlong (str2, cword.ll); 497be60a902SHaavard Skinnemoen debug ("is= %s %s\n", str1, str2); 498be60a902SHaavard Skinnemoen } 499be60a902SHaavard Skinnemoen #endif 500cdbaefb5SHaavard Skinnemoen retval = (flash_read64(addr) == cword.ll); 501be60a902SHaavard Skinnemoen break; 502be60a902SHaavard Skinnemoen default: 503be60a902SHaavard Skinnemoen retval = 0; 504be60a902SHaavard Skinnemoen break; 505be60a902SHaavard Skinnemoen } 50612d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 50712d30aa7SHaavard Skinnemoen 508be60a902SHaavard Skinnemoen return retval; 509be60a902SHaavard Skinnemoen } 510be60a902SHaavard Skinnemoen 511be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 512be60a902SHaavard Skinnemoen */ 513be60a902SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect, 514be60a902SHaavard Skinnemoen uint offset, uchar cmd) 515be60a902SHaavard Skinnemoen { 516cdbaefb5SHaavard Skinnemoen void *addr; 517be60a902SHaavard Skinnemoen cfiword_t cword; 518be60a902SHaavard Skinnemoen int retval; 519be60a902SHaavard Skinnemoen 52012d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 521be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 522be60a902SHaavard Skinnemoen switch (info->portwidth) { 523be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 524cdbaefb5SHaavard Skinnemoen retval = ((flash_read8(addr) & cword.c) == cword.c); 525be60a902SHaavard Skinnemoen break; 526be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 527cdbaefb5SHaavard Skinnemoen retval = ((flash_read16(addr) & cword.w) == cword.w); 528be60a902SHaavard Skinnemoen break; 529be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 53047cc23cbSStefan Roese retval = ((flash_read32(addr) & cword.l) == cword.l); 531be60a902SHaavard Skinnemoen break; 532be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 533cdbaefb5SHaavard Skinnemoen retval = ((flash_read64(addr) & cword.ll) == cword.ll); 534be60a902SHaavard Skinnemoen break; 535be60a902SHaavard Skinnemoen default: 536be60a902SHaavard Skinnemoen retval = 0; 537be60a902SHaavard Skinnemoen break; 538be60a902SHaavard Skinnemoen } 53912d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 54012d30aa7SHaavard Skinnemoen 541be60a902SHaavard Skinnemoen return retval; 542be60a902SHaavard Skinnemoen } 543be60a902SHaavard Skinnemoen 544be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 545be60a902SHaavard Skinnemoen */ 546be60a902SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect, 547be60a902SHaavard Skinnemoen uint offset, uchar cmd) 548be60a902SHaavard Skinnemoen { 549cdbaefb5SHaavard Skinnemoen void *addr; 550be60a902SHaavard Skinnemoen cfiword_t cword; 551be60a902SHaavard Skinnemoen int retval; 552be60a902SHaavard Skinnemoen 55312d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 554be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 555be60a902SHaavard Skinnemoen switch (info->portwidth) { 556be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 557cdbaefb5SHaavard Skinnemoen retval = ((flash_read8(addr) & cword.c) != 558cdbaefb5SHaavard Skinnemoen (flash_read8(addr) & cword.c)); 559be60a902SHaavard Skinnemoen break; 560be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 561cdbaefb5SHaavard Skinnemoen retval = ((flash_read16(addr) & cword.w) != 562cdbaefb5SHaavard Skinnemoen (flash_read16(addr) & cword.w)); 563be60a902SHaavard Skinnemoen break; 564be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 565cdbaefb5SHaavard Skinnemoen retval = ((flash_read32(addr) & cword.l) != 566cdbaefb5SHaavard Skinnemoen (flash_read32(addr) & cword.l)); 567be60a902SHaavard Skinnemoen break; 568be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 569cdbaefb5SHaavard Skinnemoen retval = ((flash_read64(addr) & cword.ll) != 570cdbaefb5SHaavard Skinnemoen (flash_read64(addr) & cword.ll)); 571be60a902SHaavard Skinnemoen break; 572be60a902SHaavard Skinnemoen default: 573be60a902SHaavard Skinnemoen retval = 0; 574be60a902SHaavard Skinnemoen break; 575be60a902SHaavard Skinnemoen } 57612d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 57712d30aa7SHaavard Skinnemoen 578be60a902SHaavard Skinnemoen return retval; 579be60a902SHaavard Skinnemoen } 580be60a902SHaavard Skinnemoen 581be60a902SHaavard Skinnemoen /* 582be60a902SHaavard Skinnemoen * flash_is_busy - check to see if the flash is busy 583be60a902SHaavard Skinnemoen * 584be60a902SHaavard Skinnemoen * This routine checks the status of the chip and returns true if the 585be60a902SHaavard Skinnemoen * chip is busy. 586be60a902SHaavard Skinnemoen */ 587be60a902SHaavard Skinnemoen static int flash_is_busy (flash_info_t * info, flash_sect_t sect) 588be60a902SHaavard Skinnemoen { 589be60a902SHaavard Skinnemoen int retval; 590be60a902SHaavard Skinnemoen 59181b20cccSMichael Schwingen switch (info->vendor) { 59281b20cccSMichael Schwingen case CFI_CMDSET_INTEL_STANDARD: 59381b20cccSMichael Schwingen case CFI_CMDSET_INTEL_EXTENDED: 594be60a902SHaavard Skinnemoen retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); 59581b20cccSMichael Schwingen break; 59681b20cccSMichael Schwingen case CFI_CMDSET_AMD_STANDARD: 59781b20cccSMichael Schwingen case CFI_CMDSET_AMD_EXTENDED: 598be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 59981b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 600be60a902SHaavard Skinnemoen #endif 601be60a902SHaavard Skinnemoen retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); 602be60a902SHaavard Skinnemoen break; 603be60a902SHaavard Skinnemoen default: 604be60a902SHaavard Skinnemoen retval = 0; 605be60a902SHaavard Skinnemoen } 606be60a902SHaavard Skinnemoen debug ("flash_is_busy: %d\n", retval); 607be60a902SHaavard Skinnemoen return retval; 608be60a902SHaavard Skinnemoen } 609be60a902SHaavard Skinnemoen 610be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 611be60a902SHaavard Skinnemoen * wait for XSR.7 to be set. Time out with an error if it does not. 612be60a902SHaavard Skinnemoen * This routine does not set the flash to read-array mode. 613be60a902SHaavard Skinnemoen */ 614be60a902SHaavard Skinnemoen static int flash_status_check (flash_info_t * info, flash_sect_t sector, 615be60a902SHaavard Skinnemoen ulong tout, char *prompt) 616be60a902SHaavard Skinnemoen { 617be60a902SHaavard Skinnemoen ulong start; 618be60a902SHaavard Skinnemoen 619be60a902SHaavard Skinnemoen #if CFG_HZ != 1000 620be60a902SHaavard Skinnemoen tout *= CFG_HZ/1000; 621be60a902SHaavard Skinnemoen #endif 622be60a902SHaavard Skinnemoen 623be60a902SHaavard Skinnemoen /* Wait for command completion */ 624be60a902SHaavard Skinnemoen start = get_timer (0); 625be60a902SHaavard Skinnemoen while (flash_is_busy (info, sector)) { 626be60a902SHaavard Skinnemoen if (get_timer (start) > tout) { 627be60a902SHaavard Skinnemoen printf ("Flash %s timeout at address %lx data %lx\n", 628be60a902SHaavard Skinnemoen prompt, info->start[sector], 629be60a902SHaavard Skinnemoen flash_read_long (info, sector, 0)); 630be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, info->cmd_reset); 631be60a902SHaavard Skinnemoen return ERR_TIMOUT; 632be60a902SHaavard Skinnemoen } 633be60a902SHaavard Skinnemoen udelay (1); /* also triggers watchdog */ 634be60a902SHaavard Skinnemoen } 635be60a902SHaavard Skinnemoen return ERR_OK; 636be60a902SHaavard Skinnemoen } 637be60a902SHaavard Skinnemoen 638be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 639be60a902SHaavard Skinnemoen * Wait for XSR.7 to be set, if it times out print an error, otherwise 640be60a902SHaavard Skinnemoen * do a full status check. 641be60a902SHaavard Skinnemoen * 642be60a902SHaavard Skinnemoen * This routine sets the flash to read-array mode. 643be60a902SHaavard Skinnemoen */ 644be60a902SHaavard Skinnemoen static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, 645be60a902SHaavard Skinnemoen ulong tout, char *prompt) 646be60a902SHaavard Skinnemoen { 647be60a902SHaavard Skinnemoen int retcode; 648be60a902SHaavard Skinnemoen 649be60a902SHaavard Skinnemoen retcode = flash_status_check (info, sector, tout, prompt); 650be60a902SHaavard Skinnemoen switch (info->vendor) { 651be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 652be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 653be60a902SHaavard Skinnemoen if ((retcode == ERR_OK) 654be60a902SHaavard Skinnemoen && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { 655be60a902SHaavard Skinnemoen retcode = ERR_INVAL; 656be60a902SHaavard Skinnemoen printf ("Flash %s error at address %lx\n", prompt, 657be60a902SHaavard Skinnemoen info->start[sector]); 658be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | 659be60a902SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 660be60a902SHaavard Skinnemoen puts ("Command Sequence Error.\n"); 661be60a902SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 662be60a902SHaavard Skinnemoen FLASH_STATUS_ECLBS)) { 663be60a902SHaavard Skinnemoen puts ("Block Erase Error.\n"); 664be60a902SHaavard Skinnemoen retcode = ERR_NOT_ERASED; 665be60a902SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 666be60a902SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 667be60a902SHaavard Skinnemoen puts ("Locking Error\n"); 668be60a902SHaavard Skinnemoen } 669be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { 670be60a902SHaavard Skinnemoen puts ("Block locked.\n"); 671be60a902SHaavard Skinnemoen retcode = ERR_PROTECTED; 672be60a902SHaavard Skinnemoen } 673be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) 674be60a902SHaavard Skinnemoen puts ("Vpp Low Error.\n"); 675be60a902SHaavard Skinnemoen } 676be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, info->cmd_reset); 677be60a902SHaavard Skinnemoen break; 678be60a902SHaavard Skinnemoen default: 67981b20cccSMichael Schwingen break; 68081b20cccSMichael Schwingen } 681be60a902SHaavard Skinnemoen return retcode; 68281b20cccSMichael Schwingen } 683be60a902SHaavard Skinnemoen 684be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 685be60a902SHaavard Skinnemoen */ 686be60a902SHaavard Skinnemoen static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) 687be60a902SHaavard Skinnemoen { 688be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 689be60a902SHaavard Skinnemoen unsigned short w; 690be60a902SHaavard Skinnemoen unsigned int l; 691be60a902SHaavard Skinnemoen unsigned long long ll; 692be60a902SHaavard Skinnemoen #endif 693be60a902SHaavard Skinnemoen 694be60a902SHaavard Skinnemoen switch (info->portwidth) { 695be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 696be60a902SHaavard Skinnemoen cword->c = c; 697be60a902SHaavard Skinnemoen break; 698be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 699be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 700be60a902SHaavard Skinnemoen w = c; 701be60a902SHaavard Skinnemoen w <<= 8; 702be60a902SHaavard Skinnemoen cword->w = (cword->w >> 8) | w; 70381b20cccSMichael Schwingen #else 704be60a902SHaavard Skinnemoen cword->w = (cword->w << 8) | c; 705be60a902SHaavard Skinnemoen #endif 706be60a902SHaavard Skinnemoen break; 707be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 708be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 709be60a902SHaavard Skinnemoen l = c; 710be60a902SHaavard Skinnemoen l <<= 24; 711be60a902SHaavard Skinnemoen cword->l = (cword->l >> 8) | l; 712be60a902SHaavard Skinnemoen #else 713be60a902SHaavard Skinnemoen cword->l = (cword->l << 8) | c; 714be60a902SHaavard Skinnemoen #endif 715be60a902SHaavard Skinnemoen break; 716be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 717be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 718be60a902SHaavard Skinnemoen ll = c; 719be60a902SHaavard Skinnemoen ll <<= 56; 720be60a902SHaavard Skinnemoen cword->ll = (cword->ll >> 8) | ll; 721be60a902SHaavard Skinnemoen #else 722be60a902SHaavard Skinnemoen cword->ll = (cword->ll << 8) | c; 723be60a902SHaavard Skinnemoen #endif 724be60a902SHaavard Skinnemoen break; 725be60a902SHaavard Skinnemoen } 726be60a902SHaavard Skinnemoen } 727be60a902SHaavard Skinnemoen 728be60a902SHaavard Skinnemoen /* loop through the sectors from the highest address when the passed 729be60a902SHaavard Skinnemoen * address is greater or equal to the sector address we have a match 730be60a902SHaavard Skinnemoen */ 731be60a902SHaavard Skinnemoen static flash_sect_t find_sector (flash_info_t * info, ulong addr) 73281b20cccSMichael Schwingen { 733be60a902SHaavard Skinnemoen flash_sect_t sector; 734be60a902SHaavard Skinnemoen 735be60a902SHaavard Skinnemoen for (sector = info->sector_count - 1; sector >= 0; sector--) { 736be60a902SHaavard Skinnemoen if (addr >= info->start[sector]) 737be60a902SHaavard Skinnemoen break; 73881b20cccSMichael Schwingen } 739be60a902SHaavard Skinnemoen return sector; 74059829cc1SJean-Christophe PLAGNIOL-VILLARD } 74159829cc1SJean-Christophe PLAGNIOL-VILLARD 74259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 74359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 744be60a902SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest, 745be60a902SHaavard Skinnemoen cfiword_t cword) 74659829cc1SJean-Christophe PLAGNIOL-VILLARD { 747cdbaefb5SHaavard Skinnemoen void *dstaddr; 748be60a902SHaavard Skinnemoen int flag; 74959829cc1SJean-Christophe PLAGNIOL-VILLARD 75012d30aa7SHaavard Skinnemoen dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE); 751be60a902SHaavard Skinnemoen 752be60a902SHaavard Skinnemoen /* Check if Flash is (sufficiently) erased */ 753be60a902SHaavard Skinnemoen switch (info->portwidth) { 754be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 755cdbaefb5SHaavard Skinnemoen flag = ((flash_read8(dstaddr) & cword.c) == cword.c); 756be60a902SHaavard Skinnemoen break; 757be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 758cdbaefb5SHaavard Skinnemoen flag = ((flash_read16(dstaddr) & cword.w) == cword.w); 759be60a902SHaavard Skinnemoen break; 760be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 761cdbaefb5SHaavard Skinnemoen flag = ((flash_read32(dstaddr) & cword.l) == cword.l); 762be60a902SHaavard Skinnemoen break; 763be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 764cdbaefb5SHaavard Skinnemoen flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll); 765be60a902SHaavard Skinnemoen break; 766be60a902SHaavard Skinnemoen default: 76712d30aa7SHaavard Skinnemoen flag = 0; 76812d30aa7SHaavard Skinnemoen break; 76912d30aa7SHaavard Skinnemoen } 77012d30aa7SHaavard Skinnemoen if (!flag) { 77112d30aa7SHaavard Skinnemoen unmap_physmem(dstaddr, info->portwidth); 7720dc80e27SStefan Roese return ERR_NOT_ERASED; 773be60a902SHaavard Skinnemoen } 774be60a902SHaavard Skinnemoen 775be60a902SHaavard Skinnemoen /* Disable interrupts which might cause a timeout here */ 776be60a902SHaavard Skinnemoen flag = disable_interrupts (); 777be60a902SHaavard Skinnemoen 778be60a902SHaavard Skinnemoen switch (info->vendor) { 779be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 780be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 781be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); 782be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE); 783be60a902SHaavard Skinnemoen break; 784be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 785be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 786be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 787be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_LEGACY: 788be60a902SHaavard Skinnemoen #endif 789be60a902SHaavard Skinnemoen flash_unlock_seq (info, 0); 790be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE); 79159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 79259829cc1SJean-Christophe PLAGNIOL-VILLARD } 79359829cc1SJean-Christophe PLAGNIOL-VILLARD 794be60a902SHaavard Skinnemoen switch (info->portwidth) { 795be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 796cdbaefb5SHaavard Skinnemoen flash_write8(cword.c, dstaddr); 797be60a902SHaavard Skinnemoen break; 798be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 799cdbaefb5SHaavard Skinnemoen flash_write16(cword.w, dstaddr); 800be60a902SHaavard Skinnemoen break; 801be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 802cdbaefb5SHaavard Skinnemoen flash_write32(cword.l, dstaddr); 803be60a902SHaavard Skinnemoen break; 804be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 805cdbaefb5SHaavard Skinnemoen flash_write64(cword.ll, dstaddr); 806be60a902SHaavard Skinnemoen break; 80759829cc1SJean-Christophe PLAGNIOL-VILLARD } 808be60a902SHaavard Skinnemoen 809be60a902SHaavard Skinnemoen /* re-enable interrupts if necessary */ 810be60a902SHaavard Skinnemoen if (flag) 811be60a902SHaavard Skinnemoen enable_interrupts (); 812be60a902SHaavard Skinnemoen 81312d30aa7SHaavard Skinnemoen unmap_physmem(dstaddr, info->portwidth); 81412d30aa7SHaavard Skinnemoen 815be60a902SHaavard Skinnemoen return flash_full_status_check (info, find_sector (info, dest), 816be60a902SHaavard Skinnemoen info->write_tout, "write"); 817be60a902SHaavard Skinnemoen } 818be60a902SHaavard Skinnemoen 819be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_USE_BUFFER_WRITE 820be60a902SHaavard Skinnemoen 821be60a902SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, 822be60a902SHaavard Skinnemoen int len) 823be60a902SHaavard Skinnemoen { 824be60a902SHaavard Skinnemoen flash_sect_t sector; 825be60a902SHaavard Skinnemoen int cnt; 826be60a902SHaavard Skinnemoen int retcode; 827cdbaefb5SHaavard Skinnemoen void *src = cp; 82812d30aa7SHaavard Skinnemoen void *dst = map_physmem(dest, len, MAP_NOCACHE); 8290dc80e27SStefan Roese void *dst2 = dst; 8300dc80e27SStefan Roese int flag = 0; 831cdbaefb5SHaavard Skinnemoen 8320dc80e27SStefan Roese switch (info->portwidth) { 8330dc80e27SStefan Roese case FLASH_CFI_8BIT: 8340dc80e27SStefan Roese cnt = len; 8350dc80e27SStefan Roese break; 8360dc80e27SStefan Roese case FLASH_CFI_16BIT: 8370dc80e27SStefan Roese cnt = len >> 1; 8380dc80e27SStefan Roese break; 8390dc80e27SStefan Roese case FLASH_CFI_32BIT: 8400dc80e27SStefan Roese cnt = len >> 2; 8410dc80e27SStefan Roese break; 8420dc80e27SStefan Roese case FLASH_CFI_64BIT: 8430dc80e27SStefan Roese cnt = len >> 3; 8440dc80e27SStefan Roese break; 8450dc80e27SStefan Roese default: 8460dc80e27SStefan Roese retcode = ERR_INVAL; 8470dc80e27SStefan Roese goto out_unmap; 8480dc80e27SStefan Roese } 8490dc80e27SStefan Roese 8500dc80e27SStefan Roese while ((cnt-- > 0) && (flag == 0)) { 8510dc80e27SStefan Roese switch (info->portwidth) { 8520dc80e27SStefan Roese case FLASH_CFI_8BIT: 8530dc80e27SStefan Roese flag = ((flash_read8(dst2) & flash_read8(src)) == 8540dc80e27SStefan Roese flash_read8(src)); 8550dc80e27SStefan Roese src += 1, dst2 += 1; 8560dc80e27SStefan Roese break; 8570dc80e27SStefan Roese case FLASH_CFI_16BIT: 8580dc80e27SStefan Roese flag = ((flash_read16(dst2) & flash_read16(src)) == 8590dc80e27SStefan Roese flash_read16(src)); 8600dc80e27SStefan Roese src += 2, dst2 += 2; 8610dc80e27SStefan Roese break; 8620dc80e27SStefan Roese case FLASH_CFI_32BIT: 8630dc80e27SStefan Roese flag = ((flash_read32(dst2) & flash_read32(src)) == 8640dc80e27SStefan Roese flash_read32(src)); 8650dc80e27SStefan Roese src += 4, dst2 += 4; 8660dc80e27SStefan Roese break; 8670dc80e27SStefan Roese case FLASH_CFI_64BIT: 8680dc80e27SStefan Roese flag = ((flash_read64(dst2) & flash_read64(src)) == 8690dc80e27SStefan Roese flash_read64(src)); 8700dc80e27SStefan Roese src += 8, dst2 += 8; 8710dc80e27SStefan Roese break; 8720dc80e27SStefan Roese } 8730dc80e27SStefan Roese } 8740dc80e27SStefan Roese if (!flag) { 8750dc80e27SStefan Roese retcode = ERR_NOT_ERASED; 8760dc80e27SStefan Roese goto out_unmap; 8770dc80e27SStefan Roese } 8780dc80e27SStefan Roese 8790dc80e27SStefan Roese src = cp; 880cdbaefb5SHaavard Skinnemoen sector = find_sector (info, dest); 881be60a902SHaavard Skinnemoen 882be60a902SHaavard Skinnemoen switch (info->vendor) { 883be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 884be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 885be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 886be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); 887be60a902SHaavard Skinnemoen retcode = flash_status_check (info, sector, 888be60a902SHaavard Skinnemoen info->buffer_write_tout, 889be60a902SHaavard Skinnemoen "write to buffer"); 890be60a902SHaavard Skinnemoen if (retcode == ERR_OK) { 891be60a902SHaavard Skinnemoen /* reduce the number of loops by the width of 892be60a902SHaavard Skinnemoen * the port */ 893be60a902SHaavard Skinnemoen switch (info->portwidth) { 894be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 895be60a902SHaavard Skinnemoen cnt = len; 896be60a902SHaavard Skinnemoen break; 897be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 898be60a902SHaavard Skinnemoen cnt = len >> 1; 899be60a902SHaavard Skinnemoen break; 900be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 901be60a902SHaavard Skinnemoen cnt = len >> 2; 902be60a902SHaavard Skinnemoen break; 903be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 904be60a902SHaavard Skinnemoen cnt = len >> 3; 905be60a902SHaavard Skinnemoen break; 906be60a902SHaavard Skinnemoen default: 90712d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 90812d30aa7SHaavard Skinnemoen goto out_unmap; 909be60a902SHaavard Skinnemoen } 910be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 911be60a902SHaavard Skinnemoen while (cnt-- > 0) { 912be60a902SHaavard Skinnemoen switch (info->portwidth) { 913be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 914cdbaefb5SHaavard Skinnemoen flash_write8(flash_read8(src), dst); 915cdbaefb5SHaavard Skinnemoen src += 1, dst += 1; 916be60a902SHaavard Skinnemoen break; 917be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 918cdbaefb5SHaavard Skinnemoen flash_write16(flash_read16(src), dst); 919cdbaefb5SHaavard Skinnemoen src += 2, dst += 2; 920be60a902SHaavard Skinnemoen break; 921be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 922cdbaefb5SHaavard Skinnemoen flash_write32(flash_read32(src), dst); 923cdbaefb5SHaavard Skinnemoen src += 4, dst += 4; 924be60a902SHaavard Skinnemoen break; 925be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 926cdbaefb5SHaavard Skinnemoen flash_write64(flash_read64(src), dst); 927cdbaefb5SHaavard Skinnemoen src += 8, dst += 8; 928be60a902SHaavard Skinnemoen break; 929be60a902SHaavard Skinnemoen default: 93012d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 93112d30aa7SHaavard Skinnemoen goto out_unmap; 932be60a902SHaavard Skinnemoen } 933be60a902SHaavard Skinnemoen } 934be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, 935be60a902SHaavard Skinnemoen FLASH_CMD_WRITE_BUFFER_CONFIRM); 936be60a902SHaavard Skinnemoen retcode = flash_full_status_check ( 937be60a902SHaavard Skinnemoen info, sector, info->buffer_write_tout, 938be60a902SHaavard Skinnemoen "buffer write"); 939be60a902SHaavard Skinnemoen } 94012d30aa7SHaavard Skinnemoen 94112d30aa7SHaavard Skinnemoen break; 942be60a902SHaavard Skinnemoen 943be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 944be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 945be60a902SHaavard Skinnemoen flash_unlock_seq(info,0); 946be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER); 947be60a902SHaavard Skinnemoen 948be60a902SHaavard Skinnemoen switch (info->portwidth) { 949be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 950be60a902SHaavard Skinnemoen cnt = len; 951be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 952cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 953cdbaefb5SHaavard Skinnemoen flash_write8(flash_read8(src), dst); 954cdbaefb5SHaavard Skinnemoen src += 1, dst += 1; 955cdbaefb5SHaavard Skinnemoen } 956be60a902SHaavard Skinnemoen break; 957be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 958be60a902SHaavard Skinnemoen cnt = len >> 1; 959be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 960cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 961cdbaefb5SHaavard Skinnemoen flash_write16(flash_read16(src), dst); 962cdbaefb5SHaavard Skinnemoen src += 2, dst += 2; 963cdbaefb5SHaavard Skinnemoen } 964be60a902SHaavard Skinnemoen break; 965be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 966be60a902SHaavard Skinnemoen cnt = len >> 2; 967be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 968cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 969cdbaefb5SHaavard Skinnemoen flash_write32(flash_read32(src), dst); 970cdbaefb5SHaavard Skinnemoen src += 4, dst += 4; 971cdbaefb5SHaavard Skinnemoen } 972be60a902SHaavard Skinnemoen break; 973be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 974be60a902SHaavard Skinnemoen cnt = len >> 3; 975be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 976cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 977cdbaefb5SHaavard Skinnemoen flash_write64(flash_read64(src), dst); 978cdbaefb5SHaavard Skinnemoen src += 8, dst += 8; 979cdbaefb5SHaavard Skinnemoen } 980be60a902SHaavard Skinnemoen break; 981be60a902SHaavard Skinnemoen default: 98212d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 98312d30aa7SHaavard Skinnemoen goto out_unmap; 984be60a902SHaavard Skinnemoen } 985be60a902SHaavard Skinnemoen 986be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); 987be60a902SHaavard Skinnemoen retcode = flash_full_status_check (info, sector, 988be60a902SHaavard Skinnemoen info->buffer_write_tout, 989be60a902SHaavard Skinnemoen "buffer write"); 99012d30aa7SHaavard Skinnemoen break; 991be60a902SHaavard Skinnemoen 992be60a902SHaavard Skinnemoen default: 993be60a902SHaavard Skinnemoen debug ("Unknown Command Set\n"); 99412d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 99512d30aa7SHaavard Skinnemoen break; 996be60a902SHaavard Skinnemoen } 99712d30aa7SHaavard Skinnemoen 99812d30aa7SHaavard Skinnemoen out_unmap: 99912d30aa7SHaavard Skinnemoen unmap_physmem(dst, len); 100012d30aa7SHaavard Skinnemoen return retcode; 1001be60a902SHaavard Skinnemoen } 1002be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_USE_BUFFER_WRITE */ 1003be60a902SHaavard Skinnemoen 100459829cc1SJean-Christophe PLAGNIOL-VILLARD 100559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 100659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 100759829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last) 100859829cc1SJean-Christophe PLAGNIOL-VILLARD { 100959829cc1SJean-Christophe PLAGNIOL-VILLARD int rcode = 0; 101059829cc1SJean-Christophe PLAGNIOL-VILLARD int prot; 101159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect; 101259829cc1SJean-Christophe PLAGNIOL-VILLARD 101359829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 101459829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Can't erase unknown flash type - aborted\n"); 101559829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 101659829cc1SJean-Christophe PLAGNIOL-VILLARD } 101759829cc1SJean-Christophe PLAGNIOL-VILLARD if ((s_first < 0) || (s_first > s_last)) { 101859829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("- no sectors to erase\n"); 101959829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 102059829cc1SJean-Christophe PLAGNIOL-VILLARD } 102159829cc1SJean-Christophe PLAGNIOL-VILLARD 102259829cc1SJean-Christophe PLAGNIOL-VILLARD prot = 0; 102359829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; ++sect) { 102459829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect]) { 102559829cc1SJean-Christophe PLAGNIOL-VILLARD prot++; 102659829cc1SJean-Christophe PLAGNIOL-VILLARD } 102759829cc1SJean-Christophe PLAGNIOL-VILLARD } 102859829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) { 10297e5b9b47SHaavard Skinnemoen printf ("- Warning: %d protected sectors will not be erased!\n", 10307e5b9b47SHaavard Skinnemoen prot); 103159829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 103259829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 103359829cc1SJean-Christophe PLAGNIOL-VILLARD } 103459829cc1SJean-Christophe PLAGNIOL-VILLARD 103559829cc1SJean-Christophe PLAGNIOL-VILLARD 103659829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; sect++) { 103759829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect] == 0) { /* not protected */ 103859829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 103959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 104059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 10417e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10427e5b9b47SHaavard Skinnemoen FLASH_CMD_CLEAR_STATUS); 10437e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10447e5b9b47SHaavard Skinnemoen FLASH_CMD_BLOCK_ERASE); 10457e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10467e5b9b47SHaavard Skinnemoen FLASH_CMD_ERASE_CONFIRM); 104759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 104859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 104959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 105059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 10517e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 10527e5b9b47SHaavard Skinnemoen info->addr_unlock1, 10537e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 105459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 10557e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10567e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_SECTOR); 105759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 105881b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 105981b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 106081b20cccSMichael Schwingen flash_unlock_seq (info, 0); 10617e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, info->addr_unlock1, 10627e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 106381b20cccSMichael Schwingen flash_unlock_seq (info, 0); 10647e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10657e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_SECTOR); 106681b20cccSMichael Schwingen break; 106781b20cccSMichael Schwingen #endif 106859829cc1SJean-Christophe PLAGNIOL-VILLARD default: 106959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("Unkown flash vendor %d\n", 107059829cc1SJean-Christophe PLAGNIOL-VILLARD info->vendor); 107159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 107259829cc1SJean-Christophe PLAGNIOL-VILLARD } 107359829cc1SJean-Christophe PLAGNIOL-VILLARD 107459829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_full_status_check 107559829cc1SJean-Christophe PLAGNIOL-VILLARD (info, sect, info->erase_blk_tout, "erase")) { 107659829cc1SJean-Christophe PLAGNIOL-VILLARD rcode = 1; 107759829cc1SJean-Christophe PLAGNIOL-VILLARD } else 107859829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('.'); 107959829cc1SJean-Christophe PLAGNIOL-VILLARD } 108059829cc1SJean-Christophe PLAGNIOL-VILLARD } 108159829cc1SJean-Christophe PLAGNIOL-VILLARD puts (" done\n"); 108259829cc1SJean-Christophe PLAGNIOL-VILLARD return rcode; 108359829cc1SJean-Christophe PLAGNIOL-VILLARD } 108459829cc1SJean-Christophe PLAGNIOL-VILLARD 108559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 108659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 108759829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info) 108859829cc1SJean-Christophe PLAGNIOL-VILLARD { 108959829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 109059829cc1SJean-Christophe PLAGNIOL-VILLARD 109159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 109259829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("missing or unknown FLASH type\n"); 109359829cc1SJean-Christophe PLAGNIOL-VILLARD return; 109459829cc1SJean-Christophe PLAGNIOL-VILLARD } 109559829cc1SJean-Christophe PLAGNIOL-VILLARD 109681b20cccSMichael Schwingen printf ("%s FLASH (%d x %d)", 109781b20cccSMichael Schwingen info->name, 109859829cc1SJean-Christophe PLAGNIOL-VILLARD (info->portwidth << 3), (info->chipwidth << 3)); 109981b20cccSMichael Schwingen if (info->size < 1024*1024) 110081b20cccSMichael Schwingen printf (" Size: %ld kB in %d Sectors\n", 110181b20cccSMichael Schwingen info->size >> 10, info->sector_count); 110281b20cccSMichael Schwingen else 110359829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" Size: %ld MB in %d Sectors\n", 110459829cc1SJean-Christophe PLAGNIOL-VILLARD info->size >> 20, info->sector_count); 110559829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" "); 110659829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 110759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 110859829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Standard"); 110959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 111059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 111159829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Extended"); 111259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 111359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 111459829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Standard"); 111559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 111659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 111759829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Extended"); 111859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 111981b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 112081b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 112181b20cccSMichael Schwingen printf ("AMD Legacy"); 112281b20cccSMichael Schwingen break; 112381b20cccSMichael Schwingen #endif 112459829cc1SJean-Christophe PLAGNIOL-VILLARD default: 112559829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Unknown (%d)", info->vendor); 112659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 112759829cc1SJean-Christophe PLAGNIOL-VILLARD } 112859829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X", 112959829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id, info->device_id); 113059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 113159829cc1SJean-Christophe PLAGNIOL-VILLARD printf("%04X", info->device_id2); 113259829cc1SJean-Christophe PLAGNIOL-VILLARD } 113359829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n", 113459829cc1SJean-Christophe PLAGNIOL-VILLARD info->erase_blk_tout, 113559829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout); 113659829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size > 1) { 11377e5b9b47SHaavard Skinnemoen printf (" Buffer write timeout: %ld ms, " 11387e5b9b47SHaavard Skinnemoen "buffer size: %d bytes\n", 113959829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout, 114059829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_size); 114159829cc1SJean-Christophe PLAGNIOL-VILLARD } 114259829cc1SJean-Christophe PLAGNIOL-VILLARD 114359829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("\n Sector Start Addresses:"); 114459829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; ++i) { 114559829cc1SJean-Christophe PLAGNIOL-VILLARD if ((i % 5) == 0) 114659829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n"); 114759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_EMPTY_INFO 114859829cc1SJean-Christophe PLAGNIOL-VILLARD int k; 114959829cc1SJean-Christophe PLAGNIOL-VILLARD int size; 115059829cc1SJean-Christophe PLAGNIOL-VILLARD int erased; 115159829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long *flash; 115259829cc1SJean-Christophe PLAGNIOL-VILLARD 115359829cc1SJean-Christophe PLAGNIOL-VILLARD /* 115459829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if whole sector is erased 115559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 115612d30aa7SHaavard Skinnemoen size = flash_sector_size(info, i); 115759829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 1; 115859829cc1SJean-Christophe PLAGNIOL-VILLARD flash = (volatile unsigned long *) info->start[i]; 115959829cc1SJean-Christophe PLAGNIOL-VILLARD size = size >> 2; /* divide by 4 for longword access */ 116059829cc1SJean-Christophe PLAGNIOL-VILLARD for (k = 0; k < size; k++) { 116159829cc1SJean-Christophe PLAGNIOL-VILLARD if (*flash++ != 0xffffffff) { 116259829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 0; 116359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 116459829cc1SJean-Christophe PLAGNIOL-VILLARD } 116559829cc1SJean-Christophe PLAGNIOL-VILLARD } 116659829cc1SJean-Christophe PLAGNIOL-VILLARD 116759829cc1SJean-Christophe PLAGNIOL-VILLARD /* print empty and read-only info */ 116859829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %c %s ", 116959829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 117059829cc1SJean-Christophe PLAGNIOL-VILLARD erased ? 'E' : ' ', 117159829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 117259829cc1SJean-Christophe PLAGNIOL-VILLARD #else /* ! CFG_FLASH_EMPTY_INFO */ 117359829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %s ", 117459829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 117559829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 117659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 117759829cc1SJean-Christophe PLAGNIOL-VILLARD } 117859829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 117959829cc1SJean-Christophe PLAGNIOL-VILLARD return; 118059829cc1SJean-Christophe PLAGNIOL-VILLARD } 118159829cc1SJean-Christophe PLAGNIOL-VILLARD 118259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 1183*9a042e9cSJerry Van Baren * This is used in a few places in write_buf() to show programming 1184*9a042e9cSJerry Van Baren * progress. Making it a function is nasty because it needs to do side 1185*9a042e9cSJerry Van Baren * effect updates to digit and dots. Repeated code is nasty too, so 1186*9a042e9cSJerry Van Baren * we define it once here. 1187*9a042e9cSJerry Van Baren */ 1188*9a042e9cSJerry Van Baren #define FLASH_SHOW_PROGRESS(scale, dots, digit) \ 1189*9a042e9cSJerry Van Baren if ((scale > 0) && (dots <= 0)) { \ 1190*9a042e9cSJerry Van Baren if ((digit % 5) == 0) \ 1191*9a042e9cSJerry Van Baren printf ("%d", digit / 5); \ 1192*9a042e9cSJerry Van Baren else \ 1193*9a042e9cSJerry Van Baren putc ('.'); \ 1194*9a042e9cSJerry Van Baren digit--; \ 1195*9a042e9cSJerry Van Baren dots += scale; \ 1196*9a042e9cSJerry Van Baren } 1197*9a042e9cSJerry Van Baren 1198*9a042e9cSJerry Van Baren /*----------------------------------------------------------------------- 119959829cc1SJean-Christophe PLAGNIOL-VILLARD * Copy memory to flash, returns: 120059829cc1SJean-Christophe PLAGNIOL-VILLARD * 0 - OK 120159829cc1SJean-Christophe PLAGNIOL-VILLARD * 1 - write timeout 120259829cc1SJean-Christophe PLAGNIOL-VILLARD * 2 - Flash not erased 120359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 120459829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) 120559829cc1SJean-Christophe PLAGNIOL-VILLARD { 120659829cc1SJean-Christophe PLAGNIOL-VILLARD ulong wp; 120712d30aa7SHaavard Skinnemoen uchar *p; 120859829cc1SJean-Christophe PLAGNIOL-VILLARD int aln; 120959829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 121059829cc1SJean-Christophe PLAGNIOL-VILLARD int i, rc; 121159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 121259829cc1SJean-Christophe PLAGNIOL-VILLARD int buffered_size; 121359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 1214*9a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS 1215*9a042e9cSJerry Van Baren int digit = CONFIG_FLASH_SHOW_PROGRESS; 1216*9a042e9cSJerry Van Baren int scale = 0; 1217*9a042e9cSJerry Van Baren int dots = 0; 1218*9a042e9cSJerry Van Baren 1219*9a042e9cSJerry Van Baren /* 1220*9a042e9cSJerry Van Baren * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes. 1221*9a042e9cSJerry Van Baren */ 1222*9a042e9cSJerry Van Baren if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) { 1223*9a042e9cSJerry Van Baren scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) / 1224*9a042e9cSJerry Van Baren CONFIG_FLASH_SHOW_PROGRESS); 1225*9a042e9cSJerry Van Baren } 1226*9a042e9cSJerry Van Baren #endif 1227*9a042e9cSJerry Van Baren 122859829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 122959829cc1SJean-Christophe PLAGNIOL-VILLARD wp = (addr & ~(info->portwidth - 1)); 123059829cc1SJean-Christophe PLAGNIOL-VILLARD 123159829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle unaligned start */ 123259829cc1SJean-Christophe PLAGNIOL-VILLARD if ((aln = addr - wp) != 0) { 123359829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 123412d30aa7SHaavard Skinnemoen p = map_physmem(wp, info->portwidth, MAP_NOCACHE); 123512d30aa7SHaavard Skinnemoen for (i = 0; i < aln; ++i) 123612d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 123759829cc1SJean-Christophe PLAGNIOL-VILLARD 123859829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (i < info->portwidth) && (cnt > 0); i++) { 123959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 124059829cc1SJean-Christophe PLAGNIOL-VILLARD cnt--; 124159829cc1SJean-Christophe PLAGNIOL-VILLARD } 124212d30aa7SHaavard Skinnemoen for (; (cnt == 0) && (i < info->portwidth); ++i) 124312d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 124412d30aa7SHaavard Skinnemoen 124512d30aa7SHaavard Skinnemoen rc = flash_write_cfiword (info, wp, cword); 124612d30aa7SHaavard Skinnemoen unmap_physmem(p, info->portwidth); 124712d30aa7SHaavard Skinnemoen if (rc != 0) 124859829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 124912d30aa7SHaavard Skinnemoen 125012d30aa7SHaavard Skinnemoen wp += i; 1251*9a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS 1252*9a042e9cSJerry Van Baren dots -= i; 1253*9a042e9cSJerry Van Baren FLASH_SHOW_PROGRESS(scale, dots, digit); 1254*9a042e9cSJerry Van Baren #endif 125559829cc1SJean-Christophe PLAGNIOL-VILLARD } 125659829cc1SJean-Christophe PLAGNIOL-VILLARD 125759829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle the aligned part */ 125859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 125959829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size = (info->portwidth / info->chipwidth); 126059829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size *= info->buffer_size; 126159829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 126259829cc1SJean-Christophe PLAGNIOL-VILLARD /* prohibit buffer write when buffer_size is 1 */ 126359829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size == 1) { 126459829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 126559829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) 126659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 126759829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 126859829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 126959829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 127059829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 127159829cc1SJean-Christophe PLAGNIOL-VILLARD continue; 127259829cc1SJean-Christophe PLAGNIOL-VILLARD } 127359829cc1SJean-Christophe PLAGNIOL-VILLARD 127459829cc1SJean-Christophe PLAGNIOL-VILLARD /* write buffer until next buffered_size aligned boundary */ 127559829cc1SJean-Christophe PLAGNIOL-VILLARD i = buffered_size - (wp % buffered_size); 127659829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > cnt) 127759829cc1SJean-Christophe PLAGNIOL-VILLARD i = cnt; 127859829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) 127959829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 128059829cc1SJean-Christophe PLAGNIOL-VILLARD i -= i & (info->portwidth - 1); 128159829cc1SJean-Christophe PLAGNIOL-VILLARD wp += i; 128259829cc1SJean-Christophe PLAGNIOL-VILLARD src += i; 128359829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= i; 1284*9a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS 1285*9a042e9cSJerry Van Baren dots -= i; 1286*9a042e9cSJerry Van Baren FLASH_SHOW_PROGRESS(scale, dots, digit); 1287*9a042e9cSJerry Van Baren #endif 128859829cc1SJean-Christophe PLAGNIOL-VILLARD } 128959829cc1SJean-Christophe PLAGNIOL-VILLARD #else 129059829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 129159829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 129259829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) { 129359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 129459829cc1SJean-Christophe PLAGNIOL-VILLARD } 129559829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 129659829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 129759829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 129859829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 1299*9a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS 1300*9a042e9cSJerry Van Baren dots -= info->portwidth; 1301*9a042e9cSJerry Van Baren FLASH_SHOW_PROGRESS(scale, dots, digit); 1302*9a042e9cSJerry Van Baren #endif 130359829cc1SJean-Christophe PLAGNIOL-VILLARD } 130459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */ 1305*9a042e9cSJerry Van Baren 130659829cc1SJean-Christophe PLAGNIOL-VILLARD if (cnt == 0) { 130759829cc1SJean-Christophe PLAGNIOL-VILLARD return (0); 130859829cc1SJean-Christophe PLAGNIOL-VILLARD } 130959829cc1SJean-Christophe PLAGNIOL-VILLARD 131059829cc1SJean-Christophe PLAGNIOL-VILLARD /* 131159829cc1SJean-Christophe PLAGNIOL-VILLARD * handle unaligned tail bytes 131259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 131359829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 131412d30aa7SHaavard Skinnemoen p = map_physmem(wp, info->portwidth, MAP_NOCACHE); 131512d30aa7SHaavard Skinnemoen for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) { 131659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 131759829cc1SJean-Christophe PLAGNIOL-VILLARD --cnt; 131859829cc1SJean-Christophe PLAGNIOL-VILLARD } 131912d30aa7SHaavard Skinnemoen for (; i < info->portwidth; ++i) 132012d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 132112d30aa7SHaavard Skinnemoen unmap_physmem(p, info->portwidth); 132259829cc1SJean-Christophe PLAGNIOL-VILLARD 132359829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_write_cfiword (info, wp, cword); 132459829cc1SJean-Christophe PLAGNIOL-VILLARD } 132559829cc1SJean-Christophe PLAGNIOL-VILLARD 132659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 132759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 132859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 132959829cc1SJean-Christophe PLAGNIOL-VILLARD 133059829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot) 133159829cc1SJean-Christophe PLAGNIOL-VILLARD { 133259829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode = 0; 133359829cc1SJean-Christophe PLAGNIOL-VILLARD 133459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 133559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); 133659829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) 133759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); 133859829cc1SJean-Christophe PLAGNIOL-VILLARD else 133959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR); 134059829cc1SJean-Christophe PLAGNIOL-VILLARD 134159829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode = 134259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_full_status_check (info, sector, info->erase_blk_tout, 134359829cc1SJean-Christophe PLAGNIOL-VILLARD prot ? "protect" : "unprotect")) == 0) { 134459829cc1SJean-Christophe PLAGNIOL-VILLARD 134559829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sector] = prot; 134659829cc1SJean-Christophe PLAGNIOL-VILLARD 134759829cc1SJean-Christophe PLAGNIOL-VILLARD /* 134859829cc1SJean-Christophe PLAGNIOL-VILLARD * On some of Intel's flash chips (marked via legacy_unlock) 134959829cc1SJean-Christophe PLAGNIOL-VILLARD * unprotect unprotects all locking. 135059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 135159829cc1SJean-Christophe PLAGNIOL-VILLARD if ((prot == 0) && (info->legacy_unlock)) { 135259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t i; 135359829cc1SJean-Christophe PLAGNIOL-VILLARD 135459829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; i++) { 135559829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[i]) 135659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (info, i, 1); 135759829cc1SJean-Christophe PLAGNIOL-VILLARD } 135859829cc1SJean-Christophe PLAGNIOL-VILLARD } 135959829cc1SJean-Christophe PLAGNIOL-VILLARD } 136059829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 136159829cc1SJean-Christophe PLAGNIOL-VILLARD } 136259829cc1SJean-Christophe PLAGNIOL-VILLARD 136359829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 136459829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_user_serial - read the OneTimeProgramming cells 136559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 136659829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, 136759829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 136859829cc1SJean-Christophe PLAGNIOL-VILLARD { 136959829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 137059829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *dst; 137159829cc1SJean-Christophe PLAGNIOL-VILLARD 137259829cc1SJean-Christophe PLAGNIOL-VILLARD dst = buffer; 137312d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION); 137459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 137559829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (dst, src + offset, len); 137659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 137712d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src); 137859829cc1SJean-Christophe PLAGNIOL-VILLARD } 137959829cc1SJean-Christophe PLAGNIOL-VILLARD 138059829cc1SJean-Christophe PLAGNIOL-VILLARD /* 138159829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_factory_serial - read the device Id from the protection area 138259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 138359829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, 138459829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 138559829cc1SJean-Christophe PLAGNIOL-VILLARD { 138659829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 138759829cc1SJean-Christophe PLAGNIOL-VILLARD 138812d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION); 138959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 139059829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (buffer, src + offset, len); 139159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 139212d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src); 139359829cc1SJean-Christophe PLAGNIOL-VILLARD } 139459829cc1SJean-Christophe PLAGNIOL-VILLARD 139559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */ 139659829cc1SJean-Christophe PLAGNIOL-VILLARD 13970ddf06ddSHaavard Skinnemoen /*----------------------------------------------------------------------- 13980ddf06ddSHaavard Skinnemoen * Reverse the order of the erase regions in the CFI QRY structure. 13990ddf06ddSHaavard Skinnemoen * This is needed for chips that are either a) correctly detected as 14000ddf06ddSHaavard Skinnemoen * top-boot, or b) buggy. 14010ddf06ddSHaavard Skinnemoen */ 14020ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry) 14030ddf06ddSHaavard Skinnemoen { 14040ddf06ddSHaavard Skinnemoen unsigned int i, j; 14050ddf06ddSHaavard Skinnemoen u32 tmp; 14060ddf06ddSHaavard Skinnemoen 14070ddf06ddSHaavard Skinnemoen for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) { 14080ddf06ddSHaavard Skinnemoen tmp = qry->erase_region_info[i]; 14090ddf06ddSHaavard Skinnemoen qry->erase_region_info[i] = qry->erase_region_info[j]; 14100ddf06ddSHaavard Skinnemoen qry->erase_region_info[j] = tmp; 14110ddf06ddSHaavard Skinnemoen } 14120ddf06ddSHaavard Skinnemoen } 141359829cc1SJean-Christophe PLAGNIOL-VILLARD 141459829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 141559829cc1SJean-Christophe PLAGNIOL-VILLARD * read jedec ids from device and set corresponding fields in info struct 141659829cc1SJean-Christophe PLAGNIOL-VILLARD * 141759829cc1SJean-Christophe PLAGNIOL-VILLARD * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct 141859829cc1SJean-Christophe PLAGNIOL-VILLARD * 141959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 14200ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info) 142159829cc1SJean-Christophe PLAGNIOL-VILLARD { 142259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 142359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); 142459829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 142559829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 142659829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 142759829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 142859829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 142959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 14300ddf06ddSHaavard Skinnemoen } 14310ddf06ddSHaavard Skinnemoen 14320ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry) 14330ddf06ddSHaavard Skinnemoen { 14340ddf06ddSHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 14350ddf06ddSHaavard Skinnemoen 14360ddf06ddSHaavard Skinnemoen cmdset_intel_read_jedec_ids(info); 14370ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 14380ddf06ddSHaavard Skinnemoen 14390ddf06ddSHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION 14400ddf06ddSHaavard Skinnemoen /* read legacy lock/unlock bit from intel flash */ 14410ddf06ddSHaavard Skinnemoen if (info->ext_addr) { 14420ddf06ddSHaavard Skinnemoen info->legacy_unlock = flash_read_uchar (info, 14430ddf06ddSHaavard Skinnemoen info->ext_addr + 5) & 0x08; 14440ddf06ddSHaavard Skinnemoen } 14450ddf06ddSHaavard Skinnemoen #endif 14460ddf06ddSHaavard Skinnemoen 14470ddf06ddSHaavard Skinnemoen return 0; 14480ddf06ddSHaavard Skinnemoen } 14490ddf06ddSHaavard Skinnemoen 14500ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info) 14510ddf06ddSHaavard Skinnemoen { 145259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 145359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info, 0); 145481b20cccSMichael Schwingen flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); 145559829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 145659829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 145759829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 145859829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 145959829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 146059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 146159829cc1SJean-Christophe PLAGNIOL-VILLARD /* AMD 3-byte (expanded) device ids */ 146259829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = flash_read_uchar (info, 146359829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID2); 146459829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 <<= 8; 146559829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 |= flash_read_uchar (info, 146659829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID3); 146759829cc1SJean-Christophe PLAGNIOL-VILLARD } 146859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 14690ddf06ddSHaavard Skinnemoen } 14700ddf06ddSHaavard Skinnemoen 14710ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry) 14720ddf06ddSHaavard Skinnemoen { 14730ddf06ddSHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 14740ddf06ddSHaavard Skinnemoen 14750ddf06ddSHaavard Skinnemoen cmdset_amd_read_jedec_ids(info); 14760ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 14770ddf06ddSHaavard Skinnemoen 14780ddf06ddSHaavard Skinnemoen return 0; 14790ddf06ddSHaavard Skinnemoen } 14800ddf06ddSHaavard Skinnemoen 14810ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 14820ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info) 14830ddf06ddSHaavard Skinnemoen { 14840ddf06ddSHaavard Skinnemoen info->manufacturer_id = 0; 14850ddf06ddSHaavard Skinnemoen info->device_id = 0; 14860ddf06ddSHaavard Skinnemoen info->device_id2 = 0; 14870ddf06ddSHaavard Skinnemoen 14880ddf06ddSHaavard Skinnemoen switch (info->vendor) { 14890ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 14900ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 14918225d1e3SMichael Schwingen cmdset_intel_read_jedec_ids(info); 14920ddf06ddSHaavard Skinnemoen break; 14930ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 14940ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 14958225d1e3SMichael Schwingen cmdset_amd_read_jedec_ids(info); 149659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 149759829cc1SJean-Christophe PLAGNIOL-VILLARD default: 149859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 149959829cc1SJean-Christophe PLAGNIOL-VILLARD } 150059829cc1SJean-Christophe PLAGNIOL-VILLARD } 150159829cc1SJean-Christophe PLAGNIOL-VILLARD 1502be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 1503be60a902SHaavard Skinnemoen * Call board code to request info about non-CFI flash. 1504be60a902SHaavard Skinnemoen * board_flash_get_legacy needs to fill in at least: 1505be60a902SHaavard Skinnemoen * info->portwidth, info->chipwidth and info->interface for Jedec probing. 1506be60a902SHaavard Skinnemoen */ 1507be60a902SHaavard Skinnemoen static int flash_detect_legacy(ulong base, int banknum) 1508be60a902SHaavard Skinnemoen { 1509be60a902SHaavard Skinnemoen flash_info_t *info = &flash_info[banknum]; 1510be60a902SHaavard Skinnemoen 1511be60a902SHaavard Skinnemoen if (board_flash_get_legacy(base, banknum, info)) { 1512be60a902SHaavard Skinnemoen /* board code may have filled info completely. If not, we 1513be60a902SHaavard Skinnemoen use JEDEC ID probing. */ 1514be60a902SHaavard Skinnemoen if (!info->vendor) { 1515be60a902SHaavard Skinnemoen int modes[] = { 1516be60a902SHaavard Skinnemoen CFI_CMDSET_AMD_STANDARD, 1517be60a902SHaavard Skinnemoen CFI_CMDSET_INTEL_STANDARD 1518be60a902SHaavard Skinnemoen }; 1519be60a902SHaavard Skinnemoen int i; 1520be60a902SHaavard Skinnemoen 1521be60a902SHaavard Skinnemoen for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) { 1522be60a902SHaavard Skinnemoen info->vendor = modes[i]; 1523be60a902SHaavard Skinnemoen info->start[0] = base; 1524be60a902SHaavard Skinnemoen if (info->portwidth == FLASH_CFI_8BIT 1525be60a902SHaavard Skinnemoen && info->interface == FLASH_CFI_X8X16) { 1526be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x2AAA; 1527be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x5555; 1528be60a902SHaavard Skinnemoen } else { 1529be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x5555; 1530be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x2AAA; 1531be60a902SHaavard Skinnemoen } 1532be60a902SHaavard Skinnemoen flash_read_jedec_ids(info); 1533be60a902SHaavard Skinnemoen debug("JEDEC PROBE: ID %x %x %x\n", 1534be60a902SHaavard Skinnemoen info->manufacturer_id, 1535be60a902SHaavard Skinnemoen info->device_id, 1536be60a902SHaavard Skinnemoen info->device_id2); 1537be60a902SHaavard Skinnemoen if (jedec_flash_match(info, base)) 1538be60a902SHaavard Skinnemoen break; 1539be60a902SHaavard Skinnemoen } 1540be60a902SHaavard Skinnemoen } 1541be60a902SHaavard Skinnemoen 1542be60a902SHaavard Skinnemoen switch(info->vendor) { 1543be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 1544be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 1545be60a902SHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 1546be60a902SHaavard Skinnemoen break; 1547be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 1548be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 1549be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_LEGACY: 1550be60a902SHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 1551be60a902SHaavard Skinnemoen break; 1552be60a902SHaavard Skinnemoen } 1553be60a902SHaavard Skinnemoen info->flash_id = FLASH_MAN_CFI; 1554be60a902SHaavard Skinnemoen return 1; 1555be60a902SHaavard Skinnemoen } 1556be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1557be60a902SHaavard Skinnemoen } 1558be60a902SHaavard Skinnemoen #else 1559be60a902SHaavard Skinnemoen static inline int flash_detect_legacy(ulong base, int banknum) 1560be60a902SHaavard Skinnemoen { 1561be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1562be60a902SHaavard Skinnemoen } 1563be60a902SHaavard Skinnemoen #endif 1564be60a902SHaavard Skinnemoen 156559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 156659829cc1SJean-Christophe PLAGNIOL-VILLARD * detect if flash is compatible with the Common Flash Interface (CFI) 156759829cc1SJean-Christophe PLAGNIOL-VILLARD * http://www.jedec.org/download/search/jesd68.pdf 156859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1569e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf, 1570e23741f4SHaavard Skinnemoen unsigned int start, size_t len) 1571e23741f4SHaavard Skinnemoen { 1572e23741f4SHaavard Skinnemoen u8 *p = buf; 1573e23741f4SHaavard Skinnemoen unsigned int i; 1574e23741f4SHaavard Skinnemoen 1575e23741f4SHaavard Skinnemoen for (i = 0; i < len; i++) 1576e23741f4SHaavard Skinnemoen p[i] = flash_read_uchar(info, start + i); 1577e23741f4SHaavard Skinnemoen } 1578e23741f4SHaavard Skinnemoen 1579e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 158059829cc1SJean-Christophe PLAGNIOL-VILLARD { 158159829cc1SJean-Christophe PLAGNIOL-VILLARD int cfi_offset; 158259829cc1SJean-Christophe PLAGNIOL-VILLARD 15831ba639daSMichael Schwingen /* We do not yet know what kind of commandset to use, so we issue 15841ba639daSMichael Schwingen the reset command in both Intel and AMD variants, in the hope 15851ba639daSMichael Schwingen that AMD flash roms ignore the Intel command. */ 15861ba639daSMichael Schwingen flash_write_cmd (info, 0, 0, AMD_CMD_RESET); 15871ba639daSMichael Schwingen flash_write_cmd (info, 0, 0, FLASH_CMD_RESET); 15881ba639daSMichael Schwingen 15897e5b9b47SHaavard Skinnemoen for (cfi_offset=0; 15907e5b9b47SHaavard Skinnemoen cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint); 15917e5b9b47SHaavard Skinnemoen cfi_offset++) { 15927e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], 15937e5b9b47SHaavard Skinnemoen FLASH_CMD_CFI); 159459829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') 159559829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') 159659829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { 1597e23741f4SHaavard Skinnemoen flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP, 1598e23741f4SHaavard Skinnemoen sizeof(struct cfi_qry)); 1599e23741f4SHaavard Skinnemoen info->interface = le16_to_cpu(qry->interface_desc); 1600e23741f4SHaavard Skinnemoen 160159829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_offset = flash_offset_cfi[cfi_offset]; 160259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device interface is %d\n", 160359829cc1SJean-Christophe PLAGNIOL-VILLARD info->interface); 160459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found port %d chip %d ", 160559829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth, info->chipwidth); 160659829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("port %d bits chip %d bits\n", 160759829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth << CFI_FLASH_SHIFT_WIDTH, 160859829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 160942026c9cSBartlomiej Sieka 161042026c9cSBartlomiej Sieka /* calculate command offsets as in the Linux driver */ 161142026c9cSBartlomiej Sieka info->addr_unlock1 = 0x555; 161242026c9cSBartlomiej Sieka info->addr_unlock2 = 0x2aa; 161342026c9cSBartlomiej Sieka 161442026c9cSBartlomiej Sieka /* 161542026c9cSBartlomiej Sieka * modify the unlock address if we are 161642026c9cSBartlomiej Sieka * in compatibility mode 161742026c9cSBartlomiej Sieka */ 161842026c9cSBartlomiej Sieka if ( /* x8/x16 in x8 mode */ 161942026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY8) && 162042026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X8X16)) || 162142026c9cSBartlomiej Sieka /* x16/x32 in x16 mode */ 162242026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY16) && 162342026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X16X32))) 162442026c9cSBartlomiej Sieka { 162542026c9cSBartlomiej Sieka info->addr_unlock1 = 0xaaa; 162642026c9cSBartlomiej Sieka info->addr_unlock2 = 0x555; 162742026c9cSBartlomiej Sieka } 162842026c9cSBartlomiej Sieka 162981b20cccSMichael Schwingen info->name = "CFI conformant"; 163059829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 163159829cc1SJean-Christophe PLAGNIOL-VILLARD } 163259829cc1SJean-Christophe PLAGNIOL-VILLARD } 16337e5b9b47SHaavard Skinnemoen 16347e5b9b47SHaavard Skinnemoen return 0; 163559829cc1SJean-Christophe PLAGNIOL-VILLARD } 16367e5b9b47SHaavard Skinnemoen 1637e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 16387e5b9b47SHaavard Skinnemoen { 16397e5b9b47SHaavard Skinnemoen debug ("flash detect cfi\n"); 16407e5b9b47SHaavard Skinnemoen 16417e5b9b47SHaavard Skinnemoen for (info->portwidth = CFG_FLASH_CFI_WIDTH; 16427e5b9b47SHaavard Skinnemoen info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) { 16437e5b9b47SHaavard Skinnemoen for (info->chipwidth = FLASH_CFI_BY8; 16447e5b9b47SHaavard Skinnemoen info->chipwidth <= info->portwidth; 16457e5b9b47SHaavard Skinnemoen info->chipwidth <<= 1) 1646e23741f4SHaavard Skinnemoen if (__flash_detect_cfi(info, qry)) 16477e5b9b47SHaavard Skinnemoen return 1; 164859829cc1SJean-Christophe PLAGNIOL-VILLARD } 164959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("not found\n"); 165059829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 165159829cc1SJean-Christophe PLAGNIOL-VILLARD } 165259829cc1SJean-Christophe PLAGNIOL-VILLARD 165359829cc1SJean-Christophe PLAGNIOL-VILLARD /* 1654467bcee1SHaavard Skinnemoen * Manufacturer-specific quirks. Add workarounds for geometry 1655467bcee1SHaavard Skinnemoen * reversal, etc. here. 1656467bcee1SHaavard Skinnemoen */ 1657467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry) 1658467bcee1SHaavard Skinnemoen { 1659467bcee1SHaavard Skinnemoen /* check if flash geometry needs reversal */ 1660467bcee1SHaavard Skinnemoen if (qry->num_erase_regions > 1) { 1661467bcee1SHaavard Skinnemoen /* reverse geometry if top boot part */ 1662467bcee1SHaavard Skinnemoen if (info->cfi_version < 0x3131) { 1663467bcee1SHaavard Skinnemoen /* CFI < 1.1, try to guess from device id */ 1664467bcee1SHaavard Skinnemoen if ((info->device_id & 0x80) != 0) 1665467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1666467bcee1SHaavard Skinnemoen } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { 1667467bcee1SHaavard Skinnemoen /* CFI >= 1.1, deduct from top/bottom flag */ 1668467bcee1SHaavard Skinnemoen /* note: ext_addr is valid since cfi_version > 0 */ 1669467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1670467bcee1SHaavard Skinnemoen } 1671467bcee1SHaavard Skinnemoen } 1672467bcee1SHaavard Skinnemoen } 1673467bcee1SHaavard Skinnemoen 1674467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry) 1675467bcee1SHaavard Skinnemoen { 1676467bcee1SHaavard Skinnemoen int reverse_geometry = 0; 1677467bcee1SHaavard Skinnemoen 1678467bcee1SHaavard Skinnemoen /* Check the "top boot" bit in the PRI */ 1679467bcee1SHaavard Skinnemoen if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1)) 1680467bcee1SHaavard Skinnemoen reverse_geometry = 1; 1681467bcee1SHaavard Skinnemoen 1682467bcee1SHaavard Skinnemoen /* AT49BV6416(T) list the erase regions in the wrong order. 1683467bcee1SHaavard Skinnemoen * However, the device ID is identical with the non-broken 1684467bcee1SHaavard Skinnemoen * AT49BV642D since u-boot only reads the low byte (they 1685467bcee1SHaavard Skinnemoen * differ in the high byte.) So leave out this fixup for now. 1686467bcee1SHaavard Skinnemoen */ 1687467bcee1SHaavard Skinnemoen #if 0 1688467bcee1SHaavard Skinnemoen if (info->device_id == 0xd6 || info->device_id == 0xd2) 1689467bcee1SHaavard Skinnemoen reverse_geometry = !reverse_geometry; 1690467bcee1SHaavard Skinnemoen #endif 1691467bcee1SHaavard Skinnemoen 1692467bcee1SHaavard Skinnemoen if (reverse_geometry) 1693467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1694467bcee1SHaavard Skinnemoen } 1695467bcee1SHaavard Skinnemoen 1696467bcee1SHaavard Skinnemoen /* 169759829cc1SJean-Christophe PLAGNIOL-VILLARD * The following code cannot be run from FLASH! 169859829cc1SJean-Christophe PLAGNIOL-VILLARD * 169959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 170059829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum) 170159829cc1SJean-Christophe PLAGNIOL-VILLARD { 170259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t *info = &flash_info[banknum]; 170359829cc1SJean-Christophe PLAGNIOL-VILLARD int i, j; 170459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect_cnt; 170559829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long sector; 170659829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long tmp; 170759829cc1SJean-Christophe PLAGNIOL-VILLARD int size_ratio; 170859829cc1SJean-Christophe PLAGNIOL-VILLARD uchar num_erase_regions; 170959829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_size; 171059829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_count; 1711e23741f4SHaavard Skinnemoen struct cfi_qry qry; 171259829cc1SJean-Christophe PLAGNIOL-VILLARD 171359829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = 0; 171459829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = 0; 171559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 171659829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = 0; 171759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 171859829cc1SJean-Christophe PLAGNIOL-VILLARD 171959829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[0] = base; 172059829cc1SJean-Christophe PLAGNIOL-VILLARD 1721e23741f4SHaavard Skinnemoen if (flash_detect_cfi (info, &qry)) { 1722e23741f4SHaavard Skinnemoen info->vendor = le16_to_cpu(qry.p_id); 1723e23741f4SHaavard Skinnemoen info->ext_addr = le16_to_cpu(qry.p_adr); 1724e23741f4SHaavard Skinnemoen num_erase_regions = qry.num_erase_regions; 1725e23741f4SHaavard Skinnemoen 172659829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 172759829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = (ushort) flash_read_uchar (info, 172859829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 3) << 8; 172959829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version |= (ushort) flash_read_uchar (info, 173059829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 4); 173159829cc1SJean-Christophe PLAGNIOL-VILLARD } 17320ddf06ddSHaavard Skinnemoen 173359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 1734e23741f4SHaavard Skinnemoen flash_printqry (&qry); 173559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 17360ddf06ddSHaavard Skinnemoen 173759829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 173859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 173959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 17400ddf06ddSHaavard Skinnemoen cmdset_intel_init(info, &qry); 174159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 174259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 174359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 17440ddf06ddSHaavard Skinnemoen cmdset_amd_init(info, &qry); 174559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 17460ddf06ddSHaavard Skinnemoen default: 17470ddf06ddSHaavard Skinnemoen printf("CFI: Unknown command set 0x%x\n", 17480ddf06ddSHaavard Skinnemoen info->vendor); 17490ddf06ddSHaavard Skinnemoen /* 17500ddf06ddSHaavard Skinnemoen * Unfortunately, this means we don't know how 17510ddf06ddSHaavard Skinnemoen * to get the chip back to Read mode. Might 17520ddf06ddSHaavard Skinnemoen * as well try an Intel-style reset... 17530ddf06ddSHaavard Skinnemoen */ 17540ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 17550ddf06ddSHaavard Skinnemoen return 0; 175659829cc1SJean-Christophe PLAGNIOL-VILLARD } 175759829cc1SJean-Christophe PLAGNIOL-VILLARD 1758467bcee1SHaavard Skinnemoen /* Do manufacturer-specific fixups */ 1759467bcee1SHaavard Skinnemoen switch (info->manufacturer_id) { 1760467bcee1SHaavard Skinnemoen case 0x0001: 1761467bcee1SHaavard Skinnemoen flash_fixup_amd(info, &qry); 1762467bcee1SHaavard Skinnemoen break; 1763467bcee1SHaavard Skinnemoen case 0x001f: 1764467bcee1SHaavard Skinnemoen flash_fixup_atmel(info, &qry); 1765467bcee1SHaavard Skinnemoen break; 1766467bcee1SHaavard Skinnemoen } 1767467bcee1SHaavard Skinnemoen 176859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer is %d\n", info->vendor); 176959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer id is 0x%x\n", info->manufacturer_id); 177059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id is 0x%x\n", info->device_id); 177159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id2 is 0x%x\n", info->device_id2); 177259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("cfi version is 0x%04x\n", info->cfi_version); 177359829cc1SJean-Christophe PLAGNIOL-VILLARD 177459829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio = info->portwidth / info->chipwidth; 177559829cc1SJean-Christophe PLAGNIOL-VILLARD /* if the chip is x8/x16 reduce the ratio by half */ 177659829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->interface == FLASH_CFI_X8X16) 177759829cc1SJean-Christophe PLAGNIOL-VILLARD && (info->chipwidth == FLASH_CFI_BY8)) { 177859829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio >>= 1; 177959829cc1SJean-Christophe PLAGNIOL-VILLARD } 178059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("size_ratio %d port %d bits chip %d bits\n", 178159829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, 178259829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 178359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found %d erase regions\n", num_erase_regions); 178459829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt = 0; 178559829cc1SJean-Christophe PLAGNIOL-VILLARD sector = base; 178659829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < num_erase_regions; i++) { 178759829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > NUM_ERASE_REGIONS) { 178859829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("%d erase regions found, only %d used\n", 178959829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions, NUM_ERASE_REGIONS); 179059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 179159829cc1SJean-Christophe PLAGNIOL-VILLARD } 1792e23741f4SHaavard Skinnemoen 17930ddf06ddSHaavard Skinnemoen tmp = le32_to_cpu(qry.erase_region_info[i]); 17940ddf06ddSHaavard Skinnemoen debug("erase region %u: 0x%08lx\n", i, tmp); 1795e23741f4SHaavard Skinnemoen 1796e23741f4SHaavard Skinnemoen erase_region_count = (tmp & 0xffff) + 1; 1797e23741f4SHaavard Skinnemoen tmp >>= 16; 179859829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_size = 179959829cc1SJean-Christophe PLAGNIOL-VILLARD (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; 180059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("erase_region_count = %d erase_region_size = %d\n", 180159829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count, erase_region_size); 180259829cc1SJean-Christophe PLAGNIOL-VILLARD for (j = 0; j < erase_region_count; j++) { 180381b20cccSMichael Schwingen if (sect_cnt >= CFG_MAX_FLASH_SECT) { 180481b20cccSMichael Schwingen printf("ERROR: too many flash sectors\n"); 180581b20cccSMichael Schwingen break; 180681b20cccSMichael Schwingen } 180759829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[sect_cnt] = sector; 180859829cc1SJean-Christophe PLAGNIOL-VILLARD sector += (erase_region_size * size_ratio); 180959829cc1SJean-Christophe PLAGNIOL-VILLARD 181059829cc1SJean-Christophe PLAGNIOL-VILLARD /* 18117e5b9b47SHaavard Skinnemoen * Only read protection status from 18127e5b9b47SHaavard Skinnemoen * supported devices (intel...) 181359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 181459829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 181559829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 181659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 181759829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sect_cnt] = 181859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_isset (info, sect_cnt, 181959829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PROTECT, 182059829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_STATUS_PROTECT); 182159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 182259829cc1SJean-Christophe PLAGNIOL-VILLARD default: 18237e5b9b47SHaavard Skinnemoen /* default: not protected */ 18247e5b9b47SHaavard Skinnemoen info->protect[sect_cnt] = 0; 182559829cc1SJean-Christophe PLAGNIOL-VILLARD } 182659829cc1SJean-Christophe PLAGNIOL-VILLARD 182759829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt++; 182859829cc1SJean-Christophe PLAGNIOL-VILLARD } 182959829cc1SJean-Christophe PLAGNIOL-VILLARD } 183059829cc1SJean-Christophe PLAGNIOL-VILLARD 183159829cc1SJean-Christophe PLAGNIOL-VILLARD info->sector_count = sect_cnt; 1832e23741f4SHaavard Skinnemoen info->size = 1 << qry.dev_size; 183359829cc1SJean-Christophe PLAGNIOL-VILLARD /* multiply the size by the number of chips */ 18347e5b9b47SHaavard Skinnemoen info->size *= size_ratio; 1835e23741f4SHaavard Skinnemoen info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size); 1836e23741f4SHaavard Skinnemoen tmp = 1 << qry.block_erase_timeout_typ; 18377e5b9b47SHaavard Skinnemoen info->erase_blk_tout = tmp * 1838e23741f4SHaavard Skinnemoen (1 << qry.block_erase_timeout_max); 1839e23741f4SHaavard Skinnemoen tmp = (1 << qry.buf_write_timeout_typ) * 1840e23741f4SHaavard Skinnemoen (1 << qry.buf_write_timeout_max); 1841e23741f4SHaavard Skinnemoen 18427e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 1843e23741f4SHaavard Skinnemoen info->buffer_write_tout = (tmp + 999) / 1000; 1844e23741f4SHaavard Skinnemoen tmp = (1 << qry.word_write_timeout_typ) * 1845e23741f4SHaavard Skinnemoen (1 << qry.word_write_timeout_max); 18467e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 1847e23741f4SHaavard Skinnemoen info->write_tout = (tmp + 999) / 1000; 184859829cc1SJean-Christophe PLAGNIOL-VILLARD info->flash_id = FLASH_MAN_CFI; 18497e5b9b47SHaavard Skinnemoen if ((info->interface == FLASH_CFI_X8X16) && 18507e5b9b47SHaavard Skinnemoen (info->chipwidth == FLASH_CFI_BY8)) { 18517e5b9b47SHaavard Skinnemoen /* XXX - Need to test on x8/x16 in parallel. */ 18527e5b9b47SHaavard Skinnemoen info->portwidth >>= 1; 185359829cc1SJean-Christophe PLAGNIOL-VILLARD } 185459829cc1SJean-Christophe PLAGNIOL-VILLARD } 185559829cc1SJean-Christophe PLAGNIOL-VILLARD 185659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 185759829cc1SJean-Christophe PLAGNIOL-VILLARD return (info->size); 185859829cc1SJean-Christophe PLAGNIOL-VILLARD } 185959829cc1SJean-Christophe PLAGNIOL-VILLARD 186059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 186159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1862be60a902SHaavard Skinnemoen unsigned long flash_init (void) 186359829cc1SJean-Christophe PLAGNIOL-VILLARD { 1864be60a902SHaavard Skinnemoen unsigned long size = 0; 1865be60a902SHaavard Skinnemoen int i; 186659829cc1SJean-Christophe PLAGNIOL-VILLARD 1867be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION 1868be60a902SHaavard Skinnemoen char *s = getenv("unlock"); 186981b20cccSMichael Schwingen #endif 1870be60a902SHaavard Skinnemoen 1871be60a902SHaavard Skinnemoen /* Init: no FLASHes known */ 1872be60a902SHaavard Skinnemoen for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { 1873be60a902SHaavard Skinnemoen flash_info[i].flash_id = FLASH_UNKNOWN; 1874be60a902SHaavard Skinnemoen 1875be60a902SHaavard Skinnemoen if (!flash_detect_legacy (bank_base[i], i)) 1876be60a902SHaavard Skinnemoen flash_get_size (bank_base[i], i); 1877be60a902SHaavard Skinnemoen size += flash_info[i].size; 1878be60a902SHaavard Skinnemoen if (flash_info[i].flash_id == FLASH_UNKNOWN) { 1879be60a902SHaavard Skinnemoen #ifndef CFG_FLASH_QUIET_TEST 1880be60a902SHaavard Skinnemoen printf ("## Unknown FLASH on Bank %d " 1881be60a902SHaavard Skinnemoen "- Size = 0x%08lx = %ld MB\n", 1882be60a902SHaavard Skinnemoen i+1, flash_info[i].size, 1883be60a902SHaavard Skinnemoen flash_info[i].size << 20); 1884be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_QUIET_TEST */ 188559829cc1SJean-Christophe PLAGNIOL-VILLARD } 1886be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION 1887be60a902SHaavard Skinnemoen else if ((s != NULL) && (strcmp(s, "yes") == 0)) { 1888be60a902SHaavard Skinnemoen /* 1889be60a902SHaavard Skinnemoen * Only the U-Boot image and it's environment 1890be60a902SHaavard Skinnemoen * is protected, all other sectors are 1891be60a902SHaavard Skinnemoen * unprotected (unlocked) if flash hardware 1892be60a902SHaavard Skinnemoen * protection is used (CFG_FLASH_PROTECTION) 1893be60a902SHaavard Skinnemoen * and the environment variable "unlock" is 1894be60a902SHaavard Skinnemoen * set to "yes". 1895be60a902SHaavard Skinnemoen */ 1896be60a902SHaavard Skinnemoen if (flash_info[i].legacy_unlock) { 1897be60a902SHaavard Skinnemoen int k; 189859829cc1SJean-Christophe PLAGNIOL-VILLARD 1899be60a902SHaavard Skinnemoen /* 1900be60a902SHaavard Skinnemoen * Disable legacy_unlock temporarily, 1901be60a902SHaavard Skinnemoen * since flash_real_protect would 1902be60a902SHaavard Skinnemoen * relock all other sectors again 1903be60a902SHaavard Skinnemoen * otherwise. 1904be60a902SHaavard Skinnemoen */ 1905be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 0; 190659829cc1SJean-Christophe PLAGNIOL-VILLARD 1907be60a902SHaavard Skinnemoen /* 1908be60a902SHaavard Skinnemoen * Legacy unlocking (e.g. Intel J3) -> 1909be60a902SHaavard Skinnemoen * unlock only one sector. This will 1910be60a902SHaavard Skinnemoen * unlock all sectors. 1911be60a902SHaavard Skinnemoen */ 1912be60a902SHaavard Skinnemoen flash_real_protect (&flash_info[i], 0, 0); 191359829cc1SJean-Christophe PLAGNIOL-VILLARD 1914be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 1; 191559829cc1SJean-Christophe PLAGNIOL-VILLARD 1916be60a902SHaavard Skinnemoen /* 1917be60a902SHaavard Skinnemoen * Manually mark other sectors as 1918be60a902SHaavard Skinnemoen * unlocked (unprotected) 1919be60a902SHaavard Skinnemoen */ 1920be60a902SHaavard Skinnemoen for (k = 1; k < flash_info[i].sector_count; k++) 1921be60a902SHaavard Skinnemoen flash_info[i].protect[k] = 0; 1922be60a902SHaavard Skinnemoen } else { 1923be60a902SHaavard Skinnemoen /* 1924be60a902SHaavard Skinnemoen * No legancy unlocking -> unlock all sectors 1925be60a902SHaavard Skinnemoen */ 1926be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_CLEAR, 1927be60a902SHaavard Skinnemoen flash_info[i].start[0], 1928be60a902SHaavard Skinnemoen flash_info[i].start[0] 1929be60a902SHaavard Skinnemoen + flash_info[i].size - 1, 1930be60a902SHaavard Skinnemoen &flash_info[i]); 193159829cc1SJean-Christophe PLAGNIOL-VILLARD } 193259829cc1SJean-Christophe PLAGNIOL-VILLARD } 1933be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_PROTECTION */ 193459829cc1SJean-Christophe PLAGNIOL-VILLARD } 193559829cc1SJean-Christophe PLAGNIOL-VILLARD 1936be60a902SHaavard Skinnemoen /* Monitor protection ON by default */ 1937be60a902SHaavard Skinnemoen #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 1938be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 1939be60a902SHaavard Skinnemoen CFG_MONITOR_BASE, 1940be60a902SHaavard Skinnemoen CFG_MONITOR_BASE + monitor_flash_len - 1, 1941be60a902SHaavard Skinnemoen flash_get_info(CFG_MONITOR_BASE)); 1942be60a902SHaavard Skinnemoen #endif 194359829cc1SJean-Christophe PLAGNIOL-VILLARD 1944be60a902SHaavard Skinnemoen /* Environment protection ON by default */ 1945be60a902SHaavard Skinnemoen #ifdef CFG_ENV_IS_IN_FLASH 1946be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 1947be60a902SHaavard Skinnemoen CFG_ENV_ADDR, 1948be60a902SHaavard Skinnemoen CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, 1949be60a902SHaavard Skinnemoen flash_get_info(CFG_ENV_ADDR)); 1950be60a902SHaavard Skinnemoen #endif 1951be60a902SHaavard Skinnemoen 1952be60a902SHaavard Skinnemoen /* Redundant environment protection ON by default */ 1953be60a902SHaavard Skinnemoen #ifdef CFG_ENV_ADDR_REDUND 1954be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 1955be60a902SHaavard Skinnemoen CFG_ENV_ADDR_REDUND, 1956be60a902SHaavard Skinnemoen CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1, 1957be60a902SHaavard Skinnemoen flash_get_info(CFG_ENV_ADDR_REDUND)); 1958be60a902SHaavard Skinnemoen #endif 1959be60a902SHaavard Skinnemoen return (size); 196059829cc1SJean-Christophe PLAGNIOL-VILLARD } 196159829cc1SJean-Christophe PLAGNIOL-VILLARD 196259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_CFI */ 1963