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: 530cdbaefb5SHaavard Skinnemoen retval = ((flash_read16(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); 772*0dc80e27SStefan 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); 829*0dc80e27SStefan Roese void *dst2 = dst; 830*0dc80e27SStefan Roese int flag = 0; 831cdbaefb5SHaavard Skinnemoen 832*0dc80e27SStefan Roese switch (info->portwidth) { 833*0dc80e27SStefan Roese case FLASH_CFI_8BIT: 834*0dc80e27SStefan Roese cnt = len; 835*0dc80e27SStefan Roese break; 836*0dc80e27SStefan Roese case FLASH_CFI_16BIT: 837*0dc80e27SStefan Roese cnt = len >> 1; 838*0dc80e27SStefan Roese break; 839*0dc80e27SStefan Roese case FLASH_CFI_32BIT: 840*0dc80e27SStefan Roese cnt = len >> 2; 841*0dc80e27SStefan Roese break; 842*0dc80e27SStefan Roese case FLASH_CFI_64BIT: 843*0dc80e27SStefan Roese cnt = len >> 3; 844*0dc80e27SStefan Roese break; 845*0dc80e27SStefan Roese default: 846*0dc80e27SStefan Roese retcode = ERR_INVAL; 847*0dc80e27SStefan Roese goto out_unmap; 848*0dc80e27SStefan Roese } 849*0dc80e27SStefan Roese 850*0dc80e27SStefan Roese while ((cnt-- > 0) && (flag == 0)) { 851*0dc80e27SStefan Roese switch (info->portwidth) { 852*0dc80e27SStefan Roese case FLASH_CFI_8BIT: 853*0dc80e27SStefan Roese flag = ((flash_read8(dst2) & flash_read8(src)) == 854*0dc80e27SStefan Roese flash_read8(src)); 855*0dc80e27SStefan Roese src += 1, dst2 += 1; 856*0dc80e27SStefan Roese break; 857*0dc80e27SStefan Roese case FLASH_CFI_16BIT: 858*0dc80e27SStefan Roese flag = ((flash_read16(dst2) & flash_read16(src)) == 859*0dc80e27SStefan Roese flash_read16(src)); 860*0dc80e27SStefan Roese src += 2, dst2 += 2; 861*0dc80e27SStefan Roese break; 862*0dc80e27SStefan Roese case FLASH_CFI_32BIT: 863*0dc80e27SStefan Roese flag = ((flash_read32(dst2) & flash_read32(src)) == 864*0dc80e27SStefan Roese flash_read32(src)); 865*0dc80e27SStefan Roese src += 4, dst2 += 4; 866*0dc80e27SStefan Roese break; 867*0dc80e27SStefan Roese case FLASH_CFI_64BIT: 868*0dc80e27SStefan Roese flag = ((flash_read64(dst2) & flash_read64(src)) == 869*0dc80e27SStefan Roese flash_read64(src)); 870*0dc80e27SStefan Roese src += 8, dst2 += 8; 871*0dc80e27SStefan Roese break; 872*0dc80e27SStefan Roese } 873*0dc80e27SStefan Roese } 874*0dc80e27SStefan Roese if (!flag) { 875*0dc80e27SStefan Roese retcode = ERR_NOT_ERASED; 876*0dc80e27SStefan Roese goto out_unmap; 877*0dc80e27SStefan Roese } 878*0dc80e27SStefan Roese 879*0dc80e27SStefan 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 /*----------------------------------------------------------------------- 118359829cc1SJean-Christophe PLAGNIOL-VILLARD * Copy memory to flash, returns: 118459829cc1SJean-Christophe PLAGNIOL-VILLARD * 0 - OK 118559829cc1SJean-Christophe PLAGNIOL-VILLARD * 1 - write timeout 118659829cc1SJean-Christophe PLAGNIOL-VILLARD * 2 - Flash not erased 118759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 118859829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) 118959829cc1SJean-Christophe PLAGNIOL-VILLARD { 119059829cc1SJean-Christophe PLAGNIOL-VILLARD ulong wp; 119112d30aa7SHaavard Skinnemoen uchar *p; 119259829cc1SJean-Christophe PLAGNIOL-VILLARD int aln; 119359829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 119459829cc1SJean-Christophe PLAGNIOL-VILLARD int i, rc; 119559829cc1SJean-Christophe PLAGNIOL-VILLARD 119659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 119759829cc1SJean-Christophe PLAGNIOL-VILLARD int buffered_size; 119859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 119959829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 120059829cc1SJean-Christophe PLAGNIOL-VILLARD wp = (addr & ~(info->portwidth - 1)); 120159829cc1SJean-Christophe PLAGNIOL-VILLARD 120259829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle unaligned start */ 120359829cc1SJean-Christophe PLAGNIOL-VILLARD if ((aln = addr - wp) != 0) { 120459829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 120512d30aa7SHaavard Skinnemoen p = map_physmem(wp, info->portwidth, MAP_NOCACHE); 120612d30aa7SHaavard Skinnemoen for (i = 0; i < aln; ++i) 120712d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 120859829cc1SJean-Christophe PLAGNIOL-VILLARD 120959829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (i < info->portwidth) && (cnt > 0); i++) { 121059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 121159829cc1SJean-Christophe PLAGNIOL-VILLARD cnt--; 121259829cc1SJean-Christophe PLAGNIOL-VILLARD } 121312d30aa7SHaavard Skinnemoen for (; (cnt == 0) && (i < info->portwidth); ++i) 121412d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 121512d30aa7SHaavard Skinnemoen 121612d30aa7SHaavard Skinnemoen rc = flash_write_cfiword (info, wp, cword); 121712d30aa7SHaavard Skinnemoen unmap_physmem(p, info->portwidth); 121812d30aa7SHaavard Skinnemoen if (rc != 0) 121959829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 122012d30aa7SHaavard Skinnemoen 122112d30aa7SHaavard Skinnemoen wp += i; 122259829cc1SJean-Christophe PLAGNIOL-VILLARD } 122359829cc1SJean-Christophe PLAGNIOL-VILLARD 122459829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle the aligned part */ 122559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 122659829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size = (info->portwidth / info->chipwidth); 122759829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size *= info->buffer_size; 122859829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 122959829cc1SJean-Christophe PLAGNIOL-VILLARD /* prohibit buffer write when buffer_size is 1 */ 123059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size == 1) { 123159829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 123259829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) 123359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 123459829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 123559829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 123659829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 123759829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 123859829cc1SJean-Christophe PLAGNIOL-VILLARD continue; 123959829cc1SJean-Christophe PLAGNIOL-VILLARD } 124059829cc1SJean-Christophe PLAGNIOL-VILLARD 124159829cc1SJean-Christophe PLAGNIOL-VILLARD /* write buffer until next buffered_size aligned boundary */ 124259829cc1SJean-Christophe PLAGNIOL-VILLARD i = buffered_size - (wp % buffered_size); 124359829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > cnt) 124459829cc1SJean-Christophe PLAGNIOL-VILLARD i = cnt; 124559829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) 124659829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 124759829cc1SJean-Christophe PLAGNIOL-VILLARD i -= i & (info->portwidth - 1); 124859829cc1SJean-Christophe PLAGNIOL-VILLARD wp += i; 124959829cc1SJean-Christophe PLAGNIOL-VILLARD src += i; 125059829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= i; 125159829cc1SJean-Christophe PLAGNIOL-VILLARD } 125259829cc1SJean-Christophe PLAGNIOL-VILLARD #else 125359829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 125459829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 125559829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) { 125659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 125759829cc1SJean-Christophe PLAGNIOL-VILLARD } 125859829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 125959829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 126059829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 126159829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 126259829cc1SJean-Christophe PLAGNIOL-VILLARD } 126359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */ 126459829cc1SJean-Christophe PLAGNIOL-VILLARD if (cnt == 0) { 126559829cc1SJean-Christophe PLAGNIOL-VILLARD return (0); 126659829cc1SJean-Christophe PLAGNIOL-VILLARD } 126759829cc1SJean-Christophe PLAGNIOL-VILLARD 126859829cc1SJean-Christophe PLAGNIOL-VILLARD /* 126959829cc1SJean-Christophe PLAGNIOL-VILLARD * handle unaligned tail bytes 127059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 127159829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 127212d30aa7SHaavard Skinnemoen p = map_physmem(wp, info->portwidth, MAP_NOCACHE); 127312d30aa7SHaavard Skinnemoen for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) { 127459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 127559829cc1SJean-Christophe PLAGNIOL-VILLARD --cnt; 127659829cc1SJean-Christophe PLAGNIOL-VILLARD } 127712d30aa7SHaavard Skinnemoen for (; i < info->portwidth; ++i) 127812d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 127912d30aa7SHaavard Skinnemoen unmap_physmem(p, info->portwidth); 128059829cc1SJean-Christophe PLAGNIOL-VILLARD 128159829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_write_cfiword (info, wp, cword); 128259829cc1SJean-Christophe PLAGNIOL-VILLARD } 128359829cc1SJean-Christophe PLAGNIOL-VILLARD 128459829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 128559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 128659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 128759829cc1SJean-Christophe PLAGNIOL-VILLARD 128859829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot) 128959829cc1SJean-Christophe PLAGNIOL-VILLARD { 129059829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode = 0; 129159829cc1SJean-Christophe PLAGNIOL-VILLARD 129259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 129359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); 129459829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) 129559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); 129659829cc1SJean-Christophe PLAGNIOL-VILLARD else 129759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR); 129859829cc1SJean-Christophe PLAGNIOL-VILLARD 129959829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode = 130059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_full_status_check (info, sector, info->erase_blk_tout, 130159829cc1SJean-Christophe PLAGNIOL-VILLARD prot ? "protect" : "unprotect")) == 0) { 130259829cc1SJean-Christophe PLAGNIOL-VILLARD 130359829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sector] = prot; 130459829cc1SJean-Christophe PLAGNIOL-VILLARD 130559829cc1SJean-Christophe PLAGNIOL-VILLARD /* 130659829cc1SJean-Christophe PLAGNIOL-VILLARD * On some of Intel's flash chips (marked via legacy_unlock) 130759829cc1SJean-Christophe PLAGNIOL-VILLARD * unprotect unprotects all locking. 130859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 130959829cc1SJean-Christophe PLAGNIOL-VILLARD if ((prot == 0) && (info->legacy_unlock)) { 131059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t i; 131159829cc1SJean-Christophe PLAGNIOL-VILLARD 131259829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; i++) { 131359829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[i]) 131459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (info, i, 1); 131559829cc1SJean-Christophe PLAGNIOL-VILLARD } 131659829cc1SJean-Christophe PLAGNIOL-VILLARD } 131759829cc1SJean-Christophe PLAGNIOL-VILLARD } 131859829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 131959829cc1SJean-Christophe PLAGNIOL-VILLARD } 132059829cc1SJean-Christophe PLAGNIOL-VILLARD 132159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 132259829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_user_serial - read the OneTimeProgramming cells 132359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 132459829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, 132559829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 132659829cc1SJean-Christophe PLAGNIOL-VILLARD { 132759829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 132859829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *dst; 132959829cc1SJean-Christophe PLAGNIOL-VILLARD 133059829cc1SJean-Christophe PLAGNIOL-VILLARD dst = buffer; 133112d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION); 133259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 133359829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (dst, src + offset, len); 133459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 133512d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src); 133659829cc1SJean-Christophe PLAGNIOL-VILLARD } 133759829cc1SJean-Christophe PLAGNIOL-VILLARD 133859829cc1SJean-Christophe PLAGNIOL-VILLARD /* 133959829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_factory_serial - read the device Id from the protection area 134059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 134159829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, 134259829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 134359829cc1SJean-Christophe PLAGNIOL-VILLARD { 134459829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 134559829cc1SJean-Christophe PLAGNIOL-VILLARD 134612d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION); 134759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 134859829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (buffer, src + offset, len); 134959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 135012d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src); 135159829cc1SJean-Christophe PLAGNIOL-VILLARD } 135259829cc1SJean-Christophe PLAGNIOL-VILLARD 135359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */ 135459829cc1SJean-Christophe PLAGNIOL-VILLARD 13550ddf06ddSHaavard Skinnemoen /*----------------------------------------------------------------------- 13560ddf06ddSHaavard Skinnemoen * Reverse the order of the erase regions in the CFI QRY structure. 13570ddf06ddSHaavard Skinnemoen * This is needed for chips that are either a) correctly detected as 13580ddf06ddSHaavard Skinnemoen * top-boot, or b) buggy. 13590ddf06ddSHaavard Skinnemoen */ 13600ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry) 13610ddf06ddSHaavard Skinnemoen { 13620ddf06ddSHaavard Skinnemoen unsigned int i, j; 13630ddf06ddSHaavard Skinnemoen u32 tmp; 13640ddf06ddSHaavard Skinnemoen 13650ddf06ddSHaavard Skinnemoen for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) { 13660ddf06ddSHaavard Skinnemoen tmp = qry->erase_region_info[i]; 13670ddf06ddSHaavard Skinnemoen qry->erase_region_info[i] = qry->erase_region_info[j]; 13680ddf06ddSHaavard Skinnemoen qry->erase_region_info[j] = tmp; 13690ddf06ddSHaavard Skinnemoen } 13700ddf06ddSHaavard Skinnemoen } 137159829cc1SJean-Christophe PLAGNIOL-VILLARD 137259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 137359829cc1SJean-Christophe PLAGNIOL-VILLARD * read jedec ids from device and set corresponding fields in info struct 137459829cc1SJean-Christophe PLAGNIOL-VILLARD * 137559829cc1SJean-Christophe PLAGNIOL-VILLARD * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct 137659829cc1SJean-Christophe PLAGNIOL-VILLARD * 137759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 13780ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info) 137959829cc1SJean-Christophe PLAGNIOL-VILLARD { 138059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 138159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); 138259829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 138359829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 138459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 138559829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 138659829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 138759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 13880ddf06ddSHaavard Skinnemoen } 13890ddf06ddSHaavard Skinnemoen 13900ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry) 13910ddf06ddSHaavard Skinnemoen { 13920ddf06ddSHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 13930ddf06ddSHaavard Skinnemoen 13940ddf06ddSHaavard Skinnemoen cmdset_intel_read_jedec_ids(info); 13950ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 13960ddf06ddSHaavard Skinnemoen 13970ddf06ddSHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION 13980ddf06ddSHaavard Skinnemoen /* read legacy lock/unlock bit from intel flash */ 13990ddf06ddSHaavard Skinnemoen if (info->ext_addr) { 14000ddf06ddSHaavard Skinnemoen info->legacy_unlock = flash_read_uchar (info, 14010ddf06ddSHaavard Skinnemoen info->ext_addr + 5) & 0x08; 14020ddf06ddSHaavard Skinnemoen } 14030ddf06ddSHaavard Skinnemoen #endif 14040ddf06ddSHaavard Skinnemoen 14050ddf06ddSHaavard Skinnemoen return 0; 14060ddf06ddSHaavard Skinnemoen } 14070ddf06ddSHaavard Skinnemoen 14080ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info) 14090ddf06ddSHaavard Skinnemoen { 141059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 141159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info, 0); 141281b20cccSMichael Schwingen flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); 141359829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 141459829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 141559829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 141659829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 141759829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 141859829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 141959829cc1SJean-Christophe PLAGNIOL-VILLARD /* AMD 3-byte (expanded) device ids */ 142059829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = flash_read_uchar (info, 142159829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID2); 142259829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 <<= 8; 142359829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 |= flash_read_uchar (info, 142459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID3); 142559829cc1SJean-Christophe PLAGNIOL-VILLARD } 142659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 14270ddf06ddSHaavard Skinnemoen } 14280ddf06ddSHaavard Skinnemoen 14290ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry) 14300ddf06ddSHaavard Skinnemoen { 14310ddf06ddSHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 14320ddf06ddSHaavard Skinnemoen 14330ddf06ddSHaavard Skinnemoen cmdset_amd_read_jedec_ids(info); 14340ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 14350ddf06ddSHaavard Skinnemoen 14360ddf06ddSHaavard Skinnemoen return 0; 14370ddf06ddSHaavard Skinnemoen } 14380ddf06ddSHaavard Skinnemoen 14390ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 14400ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info) 14410ddf06ddSHaavard Skinnemoen { 14420ddf06ddSHaavard Skinnemoen info->manufacturer_id = 0; 14430ddf06ddSHaavard Skinnemoen info->device_id = 0; 14440ddf06ddSHaavard Skinnemoen info->device_id2 = 0; 14450ddf06ddSHaavard Skinnemoen 14460ddf06ddSHaavard Skinnemoen switch (info->vendor) { 14470ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 14480ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 14490ddf06ddSHaavard Skinnemoen flash_read_jedec_ids_intel(info); 14500ddf06ddSHaavard Skinnemoen break; 14510ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 14520ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 14530ddf06ddSHaavard Skinnemoen flash_read_jedec_ids_amd(info); 145459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 145559829cc1SJean-Christophe PLAGNIOL-VILLARD default: 145659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 145759829cc1SJean-Christophe PLAGNIOL-VILLARD } 145859829cc1SJean-Christophe PLAGNIOL-VILLARD } 145959829cc1SJean-Christophe PLAGNIOL-VILLARD 1460be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 1461be60a902SHaavard Skinnemoen * Call board code to request info about non-CFI flash. 1462be60a902SHaavard Skinnemoen * board_flash_get_legacy needs to fill in at least: 1463be60a902SHaavard Skinnemoen * info->portwidth, info->chipwidth and info->interface for Jedec probing. 1464be60a902SHaavard Skinnemoen */ 1465be60a902SHaavard Skinnemoen static int flash_detect_legacy(ulong base, int banknum) 1466be60a902SHaavard Skinnemoen { 1467be60a902SHaavard Skinnemoen flash_info_t *info = &flash_info[banknum]; 1468be60a902SHaavard Skinnemoen 1469be60a902SHaavard Skinnemoen if (board_flash_get_legacy(base, banknum, info)) { 1470be60a902SHaavard Skinnemoen /* board code may have filled info completely. If not, we 1471be60a902SHaavard Skinnemoen use JEDEC ID probing. */ 1472be60a902SHaavard Skinnemoen if (!info->vendor) { 1473be60a902SHaavard Skinnemoen int modes[] = { 1474be60a902SHaavard Skinnemoen CFI_CMDSET_AMD_STANDARD, 1475be60a902SHaavard Skinnemoen CFI_CMDSET_INTEL_STANDARD 1476be60a902SHaavard Skinnemoen }; 1477be60a902SHaavard Skinnemoen int i; 1478be60a902SHaavard Skinnemoen 1479be60a902SHaavard Skinnemoen for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) { 1480be60a902SHaavard Skinnemoen info->vendor = modes[i]; 1481be60a902SHaavard Skinnemoen info->start[0] = base; 1482be60a902SHaavard Skinnemoen if (info->portwidth == FLASH_CFI_8BIT 1483be60a902SHaavard Skinnemoen && info->interface == FLASH_CFI_X8X16) { 1484be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x2AAA; 1485be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x5555; 1486be60a902SHaavard Skinnemoen } else { 1487be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x5555; 1488be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x2AAA; 1489be60a902SHaavard Skinnemoen } 1490be60a902SHaavard Skinnemoen flash_read_jedec_ids(info); 1491be60a902SHaavard Skinnemoen debug("JEDEC PROBE: ID %x %x %x\n", 1492be60a902SHaavard Skinnemoen info->manufacturer_id, 1493be60a902SHaavard Skinnemoen info->device_id, 1494be60a902SHaavard Skinnemoen info->device_id2); 1495be60a902SHaavard Skinnemoen if (jedec_flash_match(info, base)) 1496be60a902SHaavard Skinnemoen break; 1497be60a902SHaavard Skinnemoen } 1498be60a902SHaavard Skinnemoen } 1499be60a902SHaavard Skinnemoen 1500be60a902SHaavard Skinnemoen switch(info->vendor) { 1501be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 1502be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 1503be60a902SHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 1504be60a902SHaavard Skinnemoen break; 1505be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 1506be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 1507be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_LEGACY: 1508be60a902SHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 1509be60a902SHaavard Skinnemoen break; 1510be60a902SHaavard Skinnemoen } 1511be60a902SHaavard Skinnemoen info->flash_id = FLASH_MAN_CFI; 1512be60a902SHaavard Skinnemoen return 1; 1513be60a902SHaavard Skinnemoen } 1514be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1515be60a902SHaavard Skinnemoen } 1516be60a902SHaavard Skinnemoen #else 1517be60a902SHaavard Skinnemoen static inline int flash_detect_legacy(ulong base, int banknum) 1518be60a902SHaavard Skinnemoen { 1519be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1520be60a902SHaavard Skinnemoen } 1521be60a902SHaavard Skinnemoen #endif 1522be60a902SHaavard Skinnemoen 152359829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 152459829cc1SJean-Christophe PLAGNIOL-VILLARD * detect if flash is compatible with the Common Flash Interface (CFI) 152559829cc1SJean-Christophe PLAGNIOL-VILLARD * http://www.jedec.org/download/search/jesd68.pdf 152659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1527e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf, 1528e23741f4SHaavard Skinnemoen unsigned int start, size_t len) 1529e23741f4SHaavard Skinnemoen { 1530e23741f4SHaavard Skinnemoen u8 *p = buf; 1531e23741f4SHaavard Skinnemoen unsigned int i; 1532e23741f4SHaavard Skinnemoen 1533e23741f4SHaavard Skinnemoen for (i = 0; i < len; i++) 1534e23741f4SHaavard Skinnemoen p[i] = flash_read_uchar(info, start + i); 1535e23741f4SHaavard Skinnemoen } 1536e23741f4SHaavard Skinnemoen 1537e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 153859829cc1SJean-Christophe PLAGNIOL-VILLARD { 153959829cc1SJean-Christophe PLAGNIOL-VILLARD int cfi_offset; 154059829cc1SJean-Christophe PLAGNIOL-VILLARD 154159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 15427e5b9b47SHaavard Skinnemoen for (cfi_offset=0; 15437e5b9b47SHaavard Skinnemoen cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint); 15447e5b9b47SHaavard Skinnemoen cfi_offset++) { 15457e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], 15467e5b9b47SHaavard Skinnemoen FLASH_CMD_CFI); 154759829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') 154859829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') 154959829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { 1550e23741f4SHaavard Skinnemoen flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP, 1551e23741f4SHaavard Skinnemoen sizeof(struct cfi_qry)); 1552e23741f4SHaavard Skinnemoen info->interface = le16_to_cpu(qry->interface_desc); 1553e23741f4SHaavard Skinnemoen 155459829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_offset = flash_offset_cfi[cfi_offset]; 155559829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device interface is %d\n", 155659829cc1SJean-Christophe PLAGNIOL-VILLARD info->interface); 155759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found port %d chip %d ", 155859829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth, info->chipwidth); 155959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("port %d bits chip %d bits\n", 156059829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth << CFI_FLASH_SHIFT_WIDTH, 156159829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 156242026c9cSBartlomiej Sieka 156342026c9cSBartlomiej Sieka /* calculate command offsets as in the Linux driver */ 156442026c9cSBartlomiej Sieka info->addr_unlock1 = 0x555; 156542026c9cSBartlomiej Sieka info->addr_unlock2 = 0x2aa; 156642026c9cSBartlomiej Sieka 156742026c9cSBartlomiej Sieka /* 156842026c9cSBartlomiej Sieka * modify the unlock address if we are 156942026c9cSBartlomiej Sieka * in compatibility mode 157042026c9cSBartlomiej Sieka */ 157142026c9cSBartlomiej Sieka if ( /* x8/x16 in x8 mode */ 157242026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY8) && 157342026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X8X16)) || 157442026c9cSBartlomiej Sieka /* x16/x32 in x16 mode */ 157542026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY16) && 157642026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X16X32))) 157742026c9cSBartlomiej Sieka { 157842026c9cSBartlomiej Sieka info->addr_unlock1 = 0xaaa; 157942026c9cSBartlomiej Sieka info->addr_unlock2 = 0x555; 158042026c9cSBartlomiej Sieka } 158142026c9cSBartlomiej Sieka 158281b20cccSMichael Schwingen info->name = "CFI conformant"; 158359829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 158459829cc1SJean-Christophe PLAGNIOL-VILLARD } 158559829cc1SJean-Christophe PLAGNIOL-VILLARD } 15867e5b9b47SHaavard Skinnemoen 15877e5b9b47SHaavard Skinnemoen return 0; 158859829cc1SJean-Christophe PLAGNIOL-VILLARD } 15897e5b9b47SHaavard Skinnemoen 1590e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 15917e5b9b47SHaavard Skinnemoen { 15927e5b9b47SHaavard Skinnemoen debug ("flash detect cfi\n"); 15937e5b9b47SHaavard Skinnemoen 15947e5b9b47SHaavard Skinnemoen for (info->portwidth = CFG_FLASH_CFI_WIDTH; 15957e5b9b47SHaavard Skinnemoen info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) { 15967e5b9b47SHaavard Skinnemoen for (info->chipwidth = FLASH_CFI_BY8; 15977e5b9b47SHaavard Skinnemoen info->chipwidth <= info->portwidth; 15987e5b9b47SHaavard Skinnemoen info->chipwidth <<= 1) 1599e23741f4SHaavard Skinnemoen if (__flash_detect_cfi(info, qry)) 16007e5b9b47SHaavard Skinnemoen return 1; 160159829cc1SJean-Christophe PLAGNIOL-VILLARD } 160259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("not found\n"); 160359829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 160459829cc1SJean-Christophe PLAGNIOL-VILLARD } 160559829cc1SJean-Christophe PLAGNIOL-VILLARD 160659829cc1SJean-Christophe PLAGNIOL-VILLARD /* 1607467bcee1SHaavard Skinnemoen * Manufacturer-specific quirks. Add workarounds for geometry 1608467bcee1SHaavard Skinnemoen * reversal, etc. here. 1609467bcee1SHaavard Skinnemoen */ 1610467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry) 1611467bcee1SHaavard Skinnemoen { 1612467bcee1SHaavard Skinnemoen /* check if flash geometry needs reversal */ 1613467bcee1SHaavard Skinnemoen if (qry->num_erase_regions > 1) { 1614467bcee1SHaavard Skinnemoen /* reverse geometry if top boot part */ 1615467bcee1SHaavard Skinnemoen if (info->cfi_version < 0x3131) { 1616467bcee1SHaavard Skinnemoen /* CFI < 1.1, try to guess from device id */ 1617467bcee1SHaavard Skinnemoen if ((info->device_id & 0x80) != 0) 1618467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1619467bcee1SHaavard Skinnemoen } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { 1620467bcee1SHaavard Skinnemoen /* CFI >= 1.1, deduct from top/bottom flag */ 1621467bcee1SHaavard Skinnemoen /* note: ext_addr is valid since cfi_version > 0 */ 1622467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1623467bcee1SHaavard Skinnemoen } 1624467bcee1SHaavard Skinnemoen } 1625467bcee1SHaavard Skinnemoen } 1626467bcee1SHaavard Skinnemoen 1627467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry) 1628467bcee1SHaavard Skinnemoen { 1629467bcee1SHaavard Skinnemoen int reverse_geometry = 0; 1630467bcee1SHaavard Skinnemoen 1631467bcee1SHaavard Skinnemoen /* Check the "top boot" bit in the PRI */ 1632467bcee1SHaavard Skinnemoen if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1)) 1633467bcee1SHaavard Skinnemoen reverse_geometry = 1; 1634467bcee1SHaavard Skinnemoen 1635467bcee1SHaavard Skinnemoen /* AT49BV6416(T) list the erase regions in the wrong order. 1636467bcee1SHaavard Skinnemoen * However, the device ID is identical with the non-broken 1637467bcee1SHaavard Skinnemoen * AT49BV642D since u-boot only reads the low byte (they 1638467bcee1SHaavard Skinnemoen * differ in the high byte.) So leave out this fixup for now. 1639467bcee1SHaavard Skinnemoen */ 1640467bcee1SHaavard Skinnemoen #if 0 1641467bcee1SHaavard Skinnemoen if (info->device_id == 0xd6 || info->device_id == 0xd2) 1642467bcee1SHaavard Skinnemoen reverse_geometry = !reverse_geometry; 1643467bcee1SHaavard Skinnemoen #endif 1644467bcee1SHaavard Skinnemoen 1645467bcee1SHaavard Skinnemoen if (reverse_geometry) 1646467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1647467bcee1SHaavard Skinnemoen } 1648467bcee1SHaavard Skinnemoen 1649467bcee1SHaavard Skinnemoen /* 165059829cc1SJean-Christophe PLAGNIOL-VILLARD * The following code cannot be run from FLASH! 165159829cc1SJean-Christophe PLAGNIOL-VILLARD * 165259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 165359829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum) 165459829cc1SJean-Christophe PLAGNIOL-VILLARD { 165559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t *info = &flash_info[banknum]; 165659829cc1SJean-Christophe PLAGNIOL-VILLARD int i, j; 165759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect_cnt; 165859829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long sector; 165959829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long tmp; 166059829cc1SJean-Christophe PLAGNIOL-VILLARD int size_ratio; 166159829cc1SJean-Christophe PLAGNIOL-VILLARD uchar num_erase_regions; 166259829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_size; 166359829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_count; 1664e23741f4SHaavard Skinnemoen struct cfi_qry qry; 166559829cc1SJean-Christophe PLAGNIOL-VILLARD 166659829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = 0; 166759829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = 0; 166859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 166959829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = 0; 167059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 167159829cc1SJean-Christophe PLAGNIOL-VILLARD 167259829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[0] = base; 167359829cc1SJean-Christophe PLAGNIOL-VILLARD 1674e23741f4SHaavard Skinnemoen if (flash_detect_cfi (info, &qry)) { 1675e23741f4SHaavard Skinnemoen info->vendor = le16_to_cpu(qry.p_id); 1676e23741f4SHaavard Skinnemoen info->ext_addr = le16_to_cpu(qry.p_adr); 1677e23741f4SHaavard Skinnemoen num_erase_regions = qry.num_erase_regions; 1678e23741f4SHaavard Skinnemoen 167959829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 168059829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = (ushort) flash_read_uchar (info, 168159829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 3) << 8; 168259829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version |= (ushort) flash_read_uchar (info, 168359829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 4); 168459829cc1SJean-Christophe PLAGNIOL-VILLARD } 16850ddf06ddSHaavard Skinnemoen 168659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 1687e23741f4SHaavard Skinnemoen flash_printqry (&qry); 168859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 16890ddf06ddSHaavard Skinnemoen 169059829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 169159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 169259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 16930ddf06ddSHaavard Skinnemoen cmdset_intel_init(info, &qry); 169459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 169559829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 169659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 16970ddf06ddSHaavard Skinnemoen cmdset_amd_init(info, &qry); 169859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 16990ddf06ddSHaavard Skinnemoen default: 17000ddf06ddSHaavard Skinnemoen printf("CFI: Unknown command set 0x%x\n", 17010ddf06ddSHaavard Skinnemoen info->vendor); 17020ddf06ddSHaavard Skinnemoen /* 17030ddf06ddSHaavard Skinnemoen * Unfortunately, this means we don't know how 17040ddf06ddSHaavard Skinnemoen * to get the chip back to Read mode. Might 17050ddf06ddSHaavard Skinnemoen * as well try an Intel-style reset... 17060ddf06ddSHaavard Skinnemoen */ 17070ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 17080ddf06ddSHaavard Skinnemoen return 0; 170959829cc1SJean-Christophe PLAGNIOL-VILLARD } 171059829cc1SJean-Christophe PLAGNIOL-VILLARD 1711467bcee1SHaavard Skinnemoen /* Do manufacturer-specific fixups */ 1712467bcee1SHaavard Skinnemoen switch (info->manufacturer_id) { 1713467bcee1SHaavard Skinnemoen case 0x0001: 1714467bcee1SHaavard Skinnemoen flash_fixup_amd(info, &qry); 1715467bcee1SHaavard Skinnemoen break; 1716467bcee1SHaavard Skinnemoen case 0x001f: 1717467bcee1SHaavard Skinnemoen flash_fixup_atmel(info, &qry); 1718467bcee1SHaavard Skinnemoen break; 1719467bcee1SHaavard Skinnemoen } 1720467bcee1SHaavard Skinnemoen 172159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer is %d\n", info->vendor); 172259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer id is 0x%x\n", info->manufacturer_id); 172359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id is 0x%x\n", info->device_id); 172459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id2 is 0x%x\n", info->device_id2); 172559829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("cfi version is 0x%04x\n", info->cfi_version); 172659829cc1SJean-Christophe PLAGNIOL-VILLARD 172759829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio = info->portwidth / info->chipwidth; 172859829cc1SJean-Christophe PLAGNIOL-VILLARD /* if the chip is x8/x16 reduce the ratio by half */ 172959829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->interface == FLASH_CFI_X8X16) 173059829cc1SJean-Christophe PLAGNIOL-VILLARD && (info->chipwidth == FLASH_CFI_BY8)) { 173159829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio >>= 1; 173259829cc1SJean-Christophe PLAGNIOL-VILLARD } 173359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("size_ratio %d port %d bits chip %d bits\n", 173459829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, 173559829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 173659829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found %d erase regions\n", num_erase_regions); 173759829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt = 0; 173859829cc1SJean-Christophe PLAGNIOL-VILLARD sector = base; 173959829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < num_erase_regions; i++) { 174059829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > NUM_ERASE_REGIONS) { 174159829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("%d erase regions found, only %d used\n", 174259829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions, NUM_ERASE_REGIONS); 174359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 174459829cc1SJean-Christophe PLAGNIOL-VILLARD } 1745e23741f4SHaavard Skinnemoen 17460ddf06ddSHaavard Skinnemoen tmp = le32_to_cpu(qry.erase_region_info[i]); 17470ddf06ddSHaavard Skinnemoen debug("erase region %u: 0x%08lx\n", i, tmp); 1748e23741f4SHaavard Skinnemoen 1749e23741f4SHaavard Skinnemoen erase_region_count = (tmp & 0xffff) + 1; 1750e23741f4SHaavard Skinnemoen tmp >>= 16; 175159829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_size = 175259829cc1SJean-Christophe PLAGNIOL-VILLARD (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; 175359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("erase_region_count = %d erase_region_size = %d\n", 175459829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count, erase_region_size); 175559829cc1SJean-Christophe PLAGNIOL-VILLARD for (j = 0; j < erase_region_count; j++) { 175681b20cccSMichael Schwingen if (sect_cnt >= CFG_MAX_FLASH_SECT) { 175781b20cccSMichael Schwingen printf("ERROR: too many flash sectors\n"); 175881b20cccSMichael Schwingen break; 175981b20cccSMichael Schwingen } 176059829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[sect_cnt] = sector; 176159829cc1SJean-Christophe PLAGNIOL-VILLARD sector += (erase_region_size * size_ratio); 176259829cc1SJean-Christophe PLAGNIOL-VILLARD 176359829cc1SJean-Christophe PLAGNIOL-VILLARD /* 17647e5b9b47SHaavard Skinnemoen * Only read protection status from 17657e5b9b47SHaavard Skinnemoen * supported devices (intel...) 176659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 176759829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 176859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 176959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 177059829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sect_cnt] = 177159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_isset (info, sect_cnt, 177259829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PROTECT, 177359829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_STATUS_PROTECT); 177459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 177559829cc1SJean-Christophe PLAGNIOL-VILLARD default: 17767e5b9b47SHaavard Skinnemoen /* default: not protected */ 17777e5b9b47SHaavard Skinnemoen info->protect[sect_cnt] = 0; 177859829cc1SJean-Christophe PLAGNIOL-VILLARD } 177959829cc1SJean-Christophe PLAGNIOL-VILLARD 178059829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt++; 178159829cc1SJean-Christophe PLAGNIOL-VILLARD } 178259829cc1SJean-Christophe PLAGNIOL-VILLARD } 178359829cc1SJean-Christophe PLAGNIOL-VILLARD 178459829cc1SJean-Christophe PLAGNIOL-VILLARD info->sector_count = sect_cnt; 1785e23741f4SHaavard Skinnemoen info->size = 1 << qry.dev_size; 178659829cc1SJean-Christophe PLAGNIOL-VILLARD /* multiply the size by the number of chips */ 17877e5b9b47SHaavard Skinnemoen info->size *= size_ratio; 1788e23741f4SHaavard Skinnemoen info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size); 1789e23741f4SHaavard Skinnemoen tmp = 1 << qry.block_erase_timeout_typ; 17907e5b9b47SHaavard Skinnemoen info->erase_blk_tout = tmp * 1791e23741f4SHaavard Skinnemoen (1 << qry.block_erase_timeout_max); 1792e23741f4SHaavard Skinnemoen tmp = (1 << qry.buf_write_timeout_typ) * 1793e23741f4SHaavard Skinnemoen (1 << qry.buf_write_timeout_max); 1794e23741f4SHaavard Skinnemoen 17957e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 1796e23741f4SHaavard Skinnemoen info->buffer_write_tout = (tmp + 999) / 1000; 1797e23741f4SHaavard Skinnemoen tmp = (1 << qry.word_write_timeout_typ) * 1798e23741f4SHaavard Skinnemoen (1 << qry.word_write_timeout_max); 17997e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 1800e23741f4SHaavard Skinnemoen info->write_tout = (tmp + 999) / 1000; 180159829cc1SJean-Christophe PLAGNIOL-VILLARD info->flash_id = FLASH_MAN_CFI; 18027e5b9b47SHaavard Skinnemoen if ((info->interface == FLASH_CFI_X8X16) && 18037e5b9b47SHaavard Skinnemoen (info->chipwidth == FLASH_CFI_BY8)) { 18047e5b9b47SHaavard Skinnemoen /* XXX - Need to test on x8/x16 in parallel. */ 18057e5b9b47SHaavard Skinnemoen info->portwidth >>= 1; 180659829cc1SJean-Christophe PLAGNIOL-VILLARD } 180759829cc1SJean-Christophe PLAGNIOL-VILLARD } 180859829cc1SJean-Christophe PLAGNIOL-VILLARD 180959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 181059829cc1SJean-Christophe PLAGNIOL-VILLARD return (info->size); 181159829cc1SJean-Christophe PLAGNIOL-VILLARD } 181259829cc1SJean-Christophe PLAGNIOL-VILLARD 181359829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 181459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1815be60a902SHaavard Skinnemoen unsigned long flash_init (void) 181659829cc1SJean-Christophe PLAGNIOL-VILLARD { 1817be60a902SHaavard Skinnemoen unsigned long size = 0; 1818be60a902SHaavard Skinnemoen int i; 181959829cc1SJean-Christophe PLAGNIOL-VILLARD 1820be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION 1821be60a902SHaavard Skinnemoen char *s = getenv("unlock"); 182281b20cccSMichael Schwingen #endif 1823be60a902SHaavard Skinnemoen 1824be60a902SHaavard Skinnemoen /* Init: no FLASHes known */ 1825be60a902SHaavard Skinnemoen for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { 1826be60a902SHaavard Skinnemoen flash_info[i].flash_id = FLASH_UNKNOWN; 1827be60a902SHaavard Skinnemoen 1828be60a902SHaavard Skinnemoen if (!flash_detect_legacy (bank_base[i], i)) 1829be60a902SHaavard Skinnemoen flash_get_size (bank_base[i], i); 1830be60a902SHaavard Skinnemoen size += flash_info[i].size; 1831be60a902SHaavard Skinnemoen if (flash_info[i].flash_id == FLASH_UNKNOWN) { 1832be60a902SHaavard Skinnemoen #ifndef CFG_FLASH_QUIET_TEST 1833be60a902SHaavard Skinnemoen printf ("## Unknown FLASH on Bank %d " 1834be60a902SHaavard Skinnemoen "- Size = 0x%08lx = %ld MB\n", 1835be60a902SHaavard Skinnemoen i+1, flash_info[i].size, 1836be60a902SHaavard Skinnemoen flash_info[i].size << 20); 1837be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_QUIET_TEST */ 183859829cc1SJean-Christophe PLAGNIOL-VILLARD } 1839be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION 1840be60a902SHaavard Skinnemoen else if ((s != NULL) && (strcmp(s, "yes") == 0)) { 1841be60a902SHaavard Skinnemoen /* 1842be60a902SHaavard Skinnemoen * Only the U-Boot image and it's environment 1843be60a902SHaavard Skinnemoen * is protected, all other sectors are 1844be60a902SHaavard Skinnemoen * unprotected (unlocked) if flash hardware 1845be60a902SHaavard Skinnemoen * protection is used (CFG_FLASH_PROTECTION) 1846be60a902SHaavard Skinnemoen * and the environment variable "unlock" is 1847be60a902SHaavard Skinnemoen * set to "yes". 1848be60a902SHaavard Skinnemoen */ 1849be60a902SHaavard Skinnemoen if (flash_info[i].legacy_unlock) { 1850be60a902SHaavard Skinnemoen int k; 185159829cc1SJean-Christophe PLAGNIOL-VILLARD 1852be60a902SHaavard Skinnemoen /* 1853be60a902SHaavard Skinnemoen * Disable legacy_unlock temporarily, 1854be60a902SHaavard Skinnemoen * since flash_real_protect would 1855be60a902SHaavard Skinnemoen * relock all other sectors again 1856be60a902SHaavard Skinnemoen * otherwise. 1857be60a902SHaavard Skinnemoen */ 1858be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 0; 185959829cc1SJean-Christophe PLAGNIOL-VILLARD 1860be60a902SHaavard Skinnemoen /* 1861be60a902SHaavard Skinnemoen * Legacy unlocking (e.g. Intel J3) -> 1862be60a902SHaavard Skinnemoen * unlock only one sector. This will 1863be60a902SHaavard Skinnemoen * unlock all sectors. 1864be60a902SHaavard Skinnemoen */ 1865be60a902SHaavard Skinnemoen flash_real_protect (&flash_info[i], 0, 0); 186659829cc1SJean-Christophe PLAGNIOL-VILLARD 1867be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 1; 186859829cc1SJean-Christophe PLAGNIOL-VILLARD 1869be60a902SHaavard Skinnemoen /* 1870be60a902SHaavard Skinnemoen * Manually mark other sectors as 1871be60a902SHaavard Skinnemoen * unlocked (unprotected) 1872be60a902SHaavard Skinnemoen */ 1873be60a902SHaavard Skinnemoen for (k = 1; k < flash_info[i].sector_count; k++) 1874be60a902SHaavard Skinnemoen flash_info[i].protect[k] = 0; 1875be60a902SHaavard Skinnemoen } else { 1876be60a902SHaavard Skinnemoen /* 1877be60a902SHaavard Skinnemoen * No legancy unlocking -> unlock all sectors 1878be60a902SHaavard Skinnemoen */ 1879be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_CLEAR, 1880be60a902SHaavard Skinnemoen flash_info[i].start[0], 1881be60a902SHaavard Skinnemoen flash_info[i].start[0] 1882be60a902SHaavard Skinnemoen + flash_info[i].size - 1, 1883be60a902SHaavard Skinnemoen &flash_info[i]); 188459829cc1SJean-Christophe PLAGNIOL-VILLARD } 188559829cc1SJean-Christophe PLAGNIOL-VILLARD } 1886be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_PROTECTION */ 188759829cc1SJean-Christophe PLAGNIOL-VILLARD } 188859829cc1SJean-Christophe PLAGNIOL-VILLARD 1889be60a902SHaavard Skinnemoen /* Monitor protection ON by default */ 1890be60a902SHaavard Skinnemoen #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 1891be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 1892be60a902SHaavard Skinnemoen CFG_MONITOR_BASE, 1893be60a902SHaavard Skinnemoen CFG_MONITOR_BASE + monitor_flash_len - 1, 1894be60a902SHaavard Skinnemoen flash_get_info(CFG_MONITOR_BASE)); 1895be60a902SHaavard Skinnemoen #endif 189659829cc1SJean-Christophe PLAGNIOL-VILLARD 1897be60a902SHaavard Skinnemoen /* Environment protection ON by default */ 1898be60a902SHaavard Skinnemoen #ifdef CFG_ENV_IS_IN_FLASH 1899be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 1900be60a902SHaavard Skinnemoen CFG_ENV_ADDR, 1901be60a902SHaavard Skinnemoen CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, 1902be60a902SHaavard Skinnemoen flash_get_info(CFG_ENV_ADDR)); 1903be60a902SHaavard Skinnemoen #endif 1904be60a902SHaavard Skinnemoen 1905be60a902SHaavard Skinnemoen /* Redundant environment protection ON by default */ 1906be60a902SHaavard Skinnemoen #ifdef CFG_ENV_ADDR_REDUND 1907be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 1908be60a902SHaavard Skinnemoen CFG_ENV_ADDR_REDUND, 1909be60a902SHaavard Skinnemoen CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1, 1910be60a902SHaavard Skinnemoen flash_get_info(CFG_ENV_ADDR_REDUND)); 1911be60a902SHaavard Skinnemoen #endif 1912be60a902SHaavard Skinnemoen return (size); 191359829cc1SJean-Christophe PLAGNIOL-VILLARD } 191459829cc1SJean-Christophe PLAGNIOL-VILLARD 191559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_CFI */ 1916