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 799c048b52SVasiliy Leoenenko #define FLASH_CMD_READ_STATUS 0x70 8059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_TO_BUFFER 0xE8 819c048b52SVasiliy Leoenenko #define FLASH_CMD_WRITE_BUFFER_PROG 0xE9 8259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0 8359829cc1SJean-Christophe PLAGNIOL-VILLARD 8459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DONE 0x80 8559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ESS 0x40 8659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ECLBS 0x20 8759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSLBS 0x10 8859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_VPENS 0x08 8959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSS 0x04 9059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DPS 0x02 9159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_R 0x01 9259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PROTECT 0x01 9359829cc1SJean-Christophe PLAGNIOL-VILLARD 9459829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_RESET 0xF0 9559829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE 0xA0 9659829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_START 0x80 9759829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_SECTOR 0x30 9859829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_START 0xAA 9959829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_ACK 0x55 10059829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_TO_BUFFER 0x25 10159829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29 10259829cc1SJean-Christophe PLAGNIOL-VILLARD 10359829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_TOGGLE 0x40 10459829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_ERROR 0x20 10559829cc1SJean-Christophe PLAGNIOL-VILLARD 10659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_MANUFACTURER_ID 0x00 10759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID 0x01 10859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID2 0x0E 10959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID3 0x0F 11059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI 0x55 11159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_ALT 0x555 11259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_RESP 0x10 11359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PRIMARY_VENDOR 0x13 1147e5b9b47SHaavard Skinnemoen /* extended query table primary address */ 1157e5b9b47SHaavard Skinnemoen #define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15 11659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WTOUT 0x1F 11759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBTOUT 0x20 11859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ETOUT 0x21 11959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CETOUT 0x22 12059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WMAX_TOUT 0x23 12159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBMAX_TOUT 0x24 12259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EMAX_TOUT 0x25 12359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CEMAX_TOUT 0x26 12459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_SIZE 0x27 12559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTERFACE 0x28 12659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_BUFFER_SIZE 0x2A 12759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C 12859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ERASE_REGIONS 0x2D 12959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PROTECT 0x02 13059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_USER_PROTECTION 0x85 13159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTEL_PROTECTION 0x81 13259829cc1SJean-Christophe PLAGNIOL-VILLARD 13359829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_NONE 0 13459829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_EXTENDED 1 13559829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_STANDARD 2 13659829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_STANDARD 3 13759829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_EXTENDED 4 13859829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_STANDARD 256 13959829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_EXTENDED 257 14059829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_SST 258 1419c048b52SVasiliy Leoenenko #define CFI_CMDSET_INTEL_PROG_REGIONS 512 14259829cc1SJean-Christophe PLAGNIOL-VILLARD 14359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */ 14459829cc1SJean-Christophe PLAGNIOL-VILLARD # undef FLASH_CMD_RESET 14559829cc1SJean-Christophe PLAGNIOL-VILLARD # define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */ 14659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 14759829cc1SJean-Christophe PLAGNIOL-VILLARD 14859829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union { 14959829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned char c; 15059829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned short w; 15159829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long l; 15259829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long long ll; 15359829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiword_t; 15459829cc1SJean-Christophe PLAGNIOL-VILLARD 15559829cc1SJean-Christophe PLAGNIOL-VILLARD #define NUM_ERASE_REGIONS 4 /* max. number of erase regions */ 15659829cc1SJean-Christophe PLAGNIOL-VILLARD 15759829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT }; 15859829cc1SJean-Christophe PLAGNIOL-VILLARD 15959829cc1SJean-Christophe PLAGNIOL-VILLARD /* use CFG_MAX_FLASH_BANKS_DETECT if defined */ 16059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_MAX_FLASH_BANKS_DETECT 16159829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS_DETECT] = CFG_FLASH_BANKS_LIST; 16259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS_DETECT]; /* FLASH chips info */ 16359829cc1SJean-Christophe PLAGNIOL-VILLARD #else 16459829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST; 16559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */ 16659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 16759829cc1SJean-Christophe PLAGNIOL-VILLARD 16859829cc1SJean-Christophe PLAGNIOL-VILLARD /* 16959829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if chip width is defined. If not, start detecting with 8bit. 17059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 17159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_CFI_WIDTH 17259829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_CFI_WIDTH FLASH_CFI_8BIT 17359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 17459829cc1SJean-Christophe PLAGNIOL-VILLARD 17559829cc1SJean-Christophe PLAGNIOL-VILLARD typedef unsigned long flash_sect_t; 17659829cc1SJean-Christophe PLAGNIOL-VILLARD 177e23741f4SHaavard Skinnemoen /* CFI standard query structure */ 178e23741f4SHaavard Skinnemoen struct cfi_qry { 179e23741f4SHaavard Skinnemoen u8 qry[3]; 180e23741f4SHaavard Skinnemoen u16 p_id; 181e23741f4SHaavard Skinnemoen u16 p_adr; 182e23741f4SHaavard Skinnemoen u16 a_id; 183e23741f4SHaavard Skinnemoen u16 a_adr; 184e23741f4SHaavard Skinnemoen u8 vcc_min; 185e23741f4SHaavard Skinnemoen u8 vcc_max; 186e23741f4SHaavard Skinnemoen u8 vpp_min; 187e23741f4SHaavard Skinnemoen u8 vpp_max; 188e23741f4SHaavard Skinnemoen u8 word_write_timeout_typ; 189e23741f4SHaavard Skinnemoen u8 buf_write_timeout_typ; 190e23741f4SHaavard Skinnemoen u8 block_erase_timeout_typ; 191e23741f4SHaavard Skinnemoen u8 chip_erase_timeout_typ; 192e23741f4SHaavard Skinnemoen u8 word_write_timeout_max; 193e23741f4SHaavard Skinnemoen u8 buf_write_timeout_max; 194e23741f4SHaavard Skinnemoen u8 block_erase_timeout_max; 195e23741f4SHaavard Skinnemoen u8 chip_erase_timeout_max; 196e23741f4SHaavard Skinnemoen u8 dev_size; 197e23741f4SHaavard Skinnemoen u16 interface_desc; 198e23741f4SHaavard Skinnemoen u16 max_buf_write_size; 199e23741f4SHaavard Skinnemoen u8 num_erase_regions; 200e23741f4SHaavard Skinnemoen u32 erase_region_info[NUM_ERASE_REGIONS]; 201e23741f4SHaavard Skinnemoen } __attribute__((packed)); 202e23741f4SHaavard Skinnemoen 203e23741f4SHaavard Skinnemoen struct cfi_pri_hdr { 204e23741f4SHaavard Skinnemoen u8 pri[3]; 205e23741f4SHaavard Skinnemoen u8 major_version; 206e23741f4SHaavard Skinnemoen u8 minor_version; 207e23741f4SHaavard Skinnemoen } __attribute__((packed)); 208e23741f4SHaavard Skinnemoen 209cdbaefb5SHaavard Skinnemoen static void flash_write8(u8 value, void *addr) 210cdbaefb5SHaavard Skinnemoen { 211cdbaefb5SHaavard Skinnemoen __raw_writeb(value, addr); 212cdbaefb5SHaavard Skinnemoen } 213cdbaefb5SHaavard Skinnemoen 214cdbaefb5SHaavard Skinnemoen static void flash_write16(u16 value, void *addr) 215cdbaefb5SHaavard Skinnemoen { 216cdbaefb5SHaavard Skinnemoen __raw_writew(value, addr); 217cdbaefb5SHaavard Skinnemoen } 218cdbaefb5SHaavard Skinnemoen 219cdbaefb5SHaavard Skinnemoen static void flash_write32(u32 value, void *addr) 220cdbaefb5SHaavard Skinnemoen { 221cdbaefb5SHaavard Skinnemoen __raw_writel(value, addr); 222cdbaefb5SHaavard Skinnemoen } 223cdbaefb5SHaavard Skinnemoen 224cdbaefb5SHaavard Skinnemoen static void flash_write64(u64 value, void *addr) 225cdbaefb5SHaavard Skinnemoen { 226cdbaefb5SHaavard Skinnemoen /* No architectures currently implement __raw_writeq() */ 227cdbaefb5SHaavard Skinnemoen *(volatile u64 *)addr = value; 228cdbaefb5SHaavard Skinnemoen } 229cdbaefb5SHaavard Skinnemoen 230cdbaefb5SHaavard Skinnemoen static u8 flash_read8(void *addr) 231cdbaefb5SHaavard Skinnemoen { 232cdbaefb5SHaavard Skinnemoen return __raw_readb(addr); 233cdbaefb5SHaavard Skinnemoen } 234cdbaefb5SHaavard Skinnemoen 235cdbaefb5SHaavard Skinnemoen static u16 flash_read16(void *addr) 236cdbaefb5SHaavard Skinnemoen { 237cdbaefb5SHaavard Skinnemoen return __raw_readw(addr); 238cdbaefb5SHaavard Skinnemoen } 239cdbaefb5SHaavard Skinnemoen 240cdbaefb5SHaavard Skinnemoen static u32 flash_read32(void *addr) 241cdbaefb5SHaavard Skinnemoen { 242cdbaefb5SHaavard Skinnemoen return __raw_readl(addr); 243cdbaefb5SHaavard Skinnemoen } 244cdbaefb5SHaavard Skinnemoen 24597bf85d7SDaniel Hellstrom static u64 __flash_read64(void *addr) 246cdbaefb5SHaavard Skinnemoen { 247cdbaefb5SHaavard Skinnemoen /* No architectures currently implement __raw_readq() */ 248cdbaefb5SHaavard Skinnemoen return *(volatile u64 *)addr; 249cdbaefb5SHaavard Skinnemoen } 250cdbaefb5SHaavard Skinnemoen 25197bf85d7SDaniel Hellstrom u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64"))); 25297bf85d7SDaniel Hellstrom 253be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 254be60a902SHaavard Skinnemoen */ 25559829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 256be60a902SHaavard Skinnemoen static flash_info_t *flash_get_info(ulong base) 257be60a902SHaavard Skinnemoen { 258be60a902SHaavard Skinnemoen int i; 259be60a902SHaavard Skinnemoen flash_info_t * info = 0; 260be60a902SHaavard Skinnemoen 261be60a902SHaavard Skinnemoen for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { 262be60a902SHaavard Skinnemoen info = & flash_info[i]; 263be60a902SHaavard Skinnemoen if (info->size && info->start[0] <= base && 264be60a902SHaavard Skinnemoen base <= info->start[0] + info->size - 1) 265be60a902SHaavard Skinnemoen break; 266be60a902SHaavard Skinnemoen } 267be60a902SHaavard Skinnemoen 268be60a902SHaavard Skinnemoen return i == CFG_MAX_FLASH_BANKS ? 0 : info; 269be60a902SHaavard Skinnemoen } 27059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 27159829cc1SJean-Christophe PLAGNIOL-VILLARD 27212d30aa7SHaavard Skinnemoen unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect) 27312d30aa7SHaavard Skinnemoen { 27412d30aa7SHaavard Skinnemoen if (sect != (info->sector_count - 1)) 27512d30aa7SHaavard Skinnemoen return info->start[sect + 1] - info->start[sect]; 27612d30aa7SHaavard Skinnemoen else 27712d30aa7SHaavard Skinnemoen return info->start[0] + info->size - info->start[sect]; 27812d30aa7SHaavard Skinnemoen } 27912d30aa7SHaavard Skinnemoen 28059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 28159829cc1SJean-Christophe PLAGNIOL-VILLARD * create an address based on the offset and the port width 28259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 28312d30aa7SHaavard Skinnemoen static inline void * 28412d30aa7SHaavard Skinnemoen flash_map (flash_info_t * info, flash_sect_t sect, uint offset) 28559829cc1SJean-Christophe PLAGNIOL-VILLARD { 28612d30aa7SHaavard Skinnemoen unsigned int byte_offset = offset * info->portwidth; 28712d30aa7SHaavard Skinnemoen 28812d30aa7SHaavard Skinnemoen return map_physmem(info->start[sect] + byte_offset, 28912d30aa7SHaavard Skinnemoen flash_sector_size(info, sect) - byte_offset, 29012d30aa7SHaavard Skinnemoen MAP_NOCACHE); 29112d30aa7SHaavard Skinnemoen } 29212d30aa7SHaavard Skinnemoen 29312d30aa7SHaavard Skinnemoen static inline void flash_unmap(flash_info_t *info, flash_sect_t sect, 29412d30aa7SHaavard Skinnemoen unsigned int offset, void *addr) 29512d30aa7SHaavard Skinnemoen { 29612d30aa7SHaavard Skinnemoen unsigned int byte_offset = offset * info->portwidth; 29712d30aa7SHaavard Skinnemoen 29812d30aa7SHaavard Skinnemoen unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset); 29959829cc1SJean-Christophe PLAGNIOL-VILLARD } 30059829cc1SJean-Christophe PLAGNIOL-VILLARD 301be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 302be60a902SHaavard Skinnemoen * make a proper sized command based on the port and chip widths 303be60a902SHaavard Skinnemoen */ 30493c56f21SVasiliy Leoenenko static void flash_make_cmd (flash_info_t * info, ulong cmd, void *cmdbuf) 305be60a902SHaavard Skinnemoen { 306be60a902SHaavard Skinnemoen int i; 30793c56f21SVasiliy Leoenenko int cword_offset; 30893c56f21SVasiliy Leoenenko int cp_offset; 30993c56f21SVasiliy Leoenenko uchar val; 310be60a902SHaavard Skinnemoen uchar *cp = (uchar *) cmdbuf; 311be60a902SHaavard Skinnemoen 31293c56f21SVasiliy Leoenenko for (i = info->portwidth; i > 0; i--){ 31393c56f21SVasiliy Leoenenko cword_offset = (info->portwidth-i)%info->chipwidth; 314be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 31593c56f21SVasiliy Leoenenko cp_offset = info->portwidth - i; 31693c56f21SVasiliy Leoenenko val = *((uchar*)&cmd + cword_offset); 317be60a902SHaavard Skinnemoen #else 31893c56f21SVasiliy Leoenenko cp_offset = i - 1; 31993c56f21SVasiliy Leoenenko val = *((uchar*)&cmd + sizeof(ulong) - cword_offset - 1); 320be60a902SHaavard Skinnemoen #endif 32193c56f21SVasiliy Leoenenko cp[cp_offset] = (cword_offset >= sizeof(ulong)) ? 0x00 : val; 32293c56f21SVasiliy Leoenenko } 323be60a902SHaavard Skinnemoen } 324be60a902SHaavard Skinnemoen 32559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 32659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 32759829cc1SJean-Christophe PLAGNIOL-VILLARD * Debug support 32859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3293055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data) 33059829cc1SJean-Christophe PLAGNIOL-VILLARD { 33159829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 33259829cc1SJean-Christophe PLAGNIOL-VILLARD char *cp; 33359829cc1SJean-Christophe PLAGNIOL-VILLARD 33459829cc1SJean-Christophe PLAGNIOL-VILLARD cp = (unsigned char *) &data; 33559829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < 8; i++) 33659829cc1SJean-Christophe PLAGNIOL-VILLARD sprintf (&str[i * 2], "%2.2x", *cp++); 33759829cc1SJean-Christophe PLAGNIOL-VILLARD } 338be60a902SHaavard Skinnemoen 339e23741f4SHaavard Skinnemoen static void flash_printqry (struct cfi_qry *qry) 34059829cc1SJean-Christophe PLAGNIOL-VILLARD { 341e23741f4SHaavard Skinnemoen u8 *p = (u8 *)qry; 34259829cc1SJean-Christophe PLAGNIOL-VILLARD int x, y; 34359829cc1SJean-Christophe PLAGNIOL-VILLARD 344e23741f4SHaavard Skinnemoen for (x = 0; x < sizeof(struct cfi_qry); x += 16) { 345e23741f4SHaavard Skinnemoen debug("%02x : ", x); 346e23741f4SHaavard Skinnemoen for (y = 0; y < 16; y++) 347e23741f4SHaavard Skinnemoen debug("%2.2x ", p[x + y]); 34859829cc1SJean-Christophe PLAGNIOL-VILLARD debug(" "); 34959829cc1SJean-Christophe PLAGNIOL-VILLARD for (y = 0; y < 16; y++) { 350e23741f4SHaavard Skinnemoen unsigned char c = p[x + y]; 351e23741f4SHaavard Skinnemoen if (c >= 0x20 && c <= 0x7e) 352cdbaefb5SHaavard Skinnemoen debug("%c", c); 353e23741f4SHaavard Skinnemoen else 35459829cc1SJean-Christophe PLAGNIOL-VILLARD debug("."); 35559829cc1SJean-Christophe PLAGNIOL-VILLARD } 35659829cc1SJean-Christophe PLAGNIOL-VILLARD debug("\n"); 35759829cc1SJean-Christophe PLAGNIOL-VILLARD } 35859829cc1SJean-Christophe PLAGNIOL-VILLARD } 35959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 36059829cc1SJean-Christophe PLAGNIOL-VILLARD 36159829cc1SJean-Christophe PLAGNIOL-VILLARD 36259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 36359829cc1SJean-Christophe PLAGNIOL-VILLARD * read a character at a port width address 36459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3653055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset) 36659829cc1SJean-Christophe PLAGNIOL-VILLARD { 36759829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *cp; 36812d30aa7SHaavard Skinnemoen uchar retval; 36959829cc1SJean-Christophe PLAGNIOL-VILLARD 37012d30aa7SHaavard Skinnemoen cp = flash_map (info, 0, offset); 37159829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 37212d30aa7SHaavard Skinnemoen retval = flash_read8(cp); 37359829cc1SJean-Christophe PLAGNIOL-VILLARD #else 37412d30aa7SHaavard Skinnemoen retval = flash_read8(cp + info->portwidth - 1); 37559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 37612d30aa7SHaavard Skinnemoen flash_unmap (info, 0, offset, cp); 37712d30aa7SHaavard Skinnemoen return retval; 37859829cc1SJean-Christophe PLAGNIOL-VILLARD } 37959829cc1SJean-Christophe PLAGNIOL-VILLARD 38059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 38190447ecbSTor Krill * read a word at a port width address, assume 16bit bus 38290447ecbSTor Krill */ 38390447ecbSTor Krill static inline ushort flash_read_word (flash_info_t * info, uint offset) 38490447ecbSTor Krill { 38590447ecbSTor Krill ushort *addr, retval; 38690447ecbSTor Krill 38790447ecbSTor Krill addr = flash_map (info, 0, offset); 38890447ecbSTor Krill retval = flash_read16 (addr); 38990447ecbSTor Krill flash_unmap (info, 0, offset, addr); 39090447ecbSTor Krill return retval; 39190447ecbSTor Krill } 39290447ecbSTor Krill 39390447ecbSTor Krill 39490447ecbSTor Krill /*----------------------------------------------------------------------- 39559829cc1SJean-Christophe PLAGNIOL-VILLARD * read a long word by picking the least significant byte of each maximum 39659829cc1SJean-Christophe PLAGNIOL-VILLARD * port size word. Swap for ppc format. 39759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3983055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect, 3993055793bSHaavard Skinnemoen uint offset) 40059829cc1SJean-Christophe PLAGNIOL-VILLARD { 40159829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *addr; 40259829cc1SJean-Christophe PLAGNIOL-VILLARD ulong retval; 40359829cc1SJean-Christophe PLAGNIOL-VILLARD 40459829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 40559829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 40659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 40712d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 40859829cc1SJean-Christophe PLAGNIOL-VILLARD 40959829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 41059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("long addr is at %p info->portwidth = %d\n", addr, 41159829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth); 41259829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 4 * info->portwidth; x++) { 41312d30aa7SHaavard Skinnemoen debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x)); 41459829cc1SJean-Christophe PLAGNIOL-VILLARD } 41559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 41659829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 41712d30aa7SHaavard Skinnemoen retval = ((flash_read8(addr) << 16) | 41812d30aa7SHaavard Skinnemoen (flash_read8(addr + info->portwidth) << 24) | 41912d30aa7SHaavard Skinnemoen (flash_read8(addr + 2 * info->portwidth)) | 42012d30aa7SHaavard Skinnemoen (flash_read8(addr + 3 * info->portwidth) << 8)); 42159829cc1SJean-Christophe PLAGNIOL-VILLARD #else 42212d30aa7SHaavard Skinnemoen retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) | 42312d30aa7SHaavard Skinnemoen (flash_read8(addr + info->portwidth - 1) << 16) | 42412d30aa7SHaavard Skinnemoen (flash_read8(addr + 4 * info->portwidth - 1) << 8) | 42512d30aa7SHaavard Skinnemoen (flash_read8(addr + 3 * info->portwidth - 1))); 42659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 42712d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 42812d30aa7SHaavard Skinnemoen 42959829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 43059829cc1SJean-Christophe PLAGNIOL-VILLARD } 43159829cc1SJean-Christophe PLAGNIOL-VILLARD 432be60a902SHaavard Skinnemoen /* 433be60a902SHaavard Skinnemoen * Write a proper sized command to the correct address 43481b20cccSMichael Schwingen */ 435be60a902SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, 43693c56f21SVasiliy Leoenenko uint offset, ulong cmd) 43781b20cccSMichael Schwingen { 4387e5b9b47SHaavard Skinnemoen 439cdbaefb5SHaavard Skinnemoen void *addr; 440be60a902SHaavard Skinnemoen cfiword_t cword; 44181b20cccSMichael Schwingen 44212d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 443be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 444be60a902SHaavard Skinnemoen switch (info->portwidth) { 445be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 446cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd, 447be60a902SHaavard Skinnemoen cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 448cdbaefb5SHaavard Skinnemoen flash_write8(cword.c, addr); 449be60a902SHaavard Skinnemoen break; 450be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 451cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr, 452be60a902SHaavard Skinnemoen cmd, cword.w, 453be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 454cdbaefb5SHaavard Skinnemoen flash_write16(cword.w, addr); 455be60a902SHaavard Skinnemoen break; 456be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 457cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr, 458be60a902SHaavard Skinnemoen cmd, cword.l, 459be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 460cdbaefb5SHaavard Skinnemoen flash_write32(cword.l, addr); 461be60a902SHaavard Skinnemoen break; 462be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 463be60a902SHaavard Skinnemoen #ifdef DEBUG 464be60a902SHaavard Skinnemoen { 465be60a902SHaavard Skinnemoen char str[20]; 466be60a902SHaavard Skinnemoen 467be60a902SHaavard Skinnemoen print_longlong (str, cword.ll); 468be60a902SHaavard Skinnemoen 469be60a902SHaavard Skinnemoen debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n", 470cdbaefb5SHaavard Skinnemoen addr, cmd, str, 471be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 47281b20cccSMichael Schwingen } 473be60a902SHaavard Skinnemoen #endif 474cdbaefb5SHaavard Skinnemoen flash_write64(cword.ll, addr); 47581b20cccSMichael Schwingen break; 47681b20cccSMichael Schwingen } 477be60a902SHaavard Skinnemoen 478be60a902SHaavard Skinnemoen /* Ensure all the instructions are fully finished */ 479be60a902SHaavard Skinnemoen sync(); 48012d30aa7SHaavard Skinnemoen 48112d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 48281b20cccSMichael Schwingen } 4837e5b9b47SHaavard Skinnemoen 484be60a902SHaavard Skinnemoen static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect) 485be60a902SHaavard Skinnemoen { 486be60a902SHaavard Skinnemoen flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START); 487be60a902SHaavard Skinnemoen flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK); 488be60a902SHaavard Skinnemoen } 489be60a902SHaavard Skinnemoen 490be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 491be60a902SHaavard Skinnemoen */ 492be60a902SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect, 493be60a902SHaavard Skinnemoen uint offset, uchar cmd) 494be60a902SHaavard Skinnemoen { 495cdbaefb5SHaavard Skinnemoen void *addr; 496be60a902SHaavard Skinnemoen cfiword_t cword; 497be60a902SHaavard Skinnemoen int retval; 498be60a902SHaavard Skinnemoen 49912d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 500be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 501be60a902SHaavard Skinnemoen 502cdbaefb5SHaavard Skinnemoen debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr); 503be60a902SHaavard Skinnemoen switch (info->portwidth) { 504be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 505cdbaefb5SHaavard Skinnemoen debug ("is= %x %x\n", flash_read8(addr), cword.c); 506cdbaefb5SHaavard Skinnemoen retval = (flash_read8(addr) == cword.c); 507be60a902SHaavard Skinnemoen break; 508be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 509cdbaefb5SHaavard Skinnemoen debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w); 510cdbaefb5SHaavard Skinnemoen retval = (flash_read16(addr) == cword.w); 511be60a902SHaavard Skinnemoen break; 512be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 513cdbaefb5SHaavard Skinnemoen debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l); 514cdbaefb5SHaavard Skinnemoen retval = (flash_read32(addr) == cword.l); 515be60a902SHaavard Skinnemoen break; 516be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 517be60a902SHaavard Skinnemoen #ifdef DEBUG 518be60a902SHaavard Skinnemoen { 519be60a902SHaavard Skinnemoen char str1[20]; 520be60a902SHaavard Skinnemoen char str2[20]; 521be60a902SHaavard Skinnemoen 522cdbaefb5SHaavard Skinnemoen print_longlong (str1, flash_read64(addr)); 523be60a902SHaavard Skinnemoen print_longlong (str2, cword.ll); 524be60a902SHaavard Skinnemoen debug ("is= %s %s\n", str1, str2); 525be60a902SHaavard Skinnemoen } 526be60a902SHaavard Skinnemoen #endif 527cdbaefb5SHaavard Skinnemoen retval = (flash_read64(addr) == cword.ll); 528be60a902SHaavard Skinnemoen break; 529be60a902SHaavard Skinnemoen default: 530be60a902SHaavard Skinnemoen retval = 0; 531be60a902SHaavard Skinnemoen break; 532be60a902SHaavard Skinnemoen } 53312d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 53412d30aa7SHaavard Skinnemoen 535be60a902SHaavard Skinnemoen return retval; 536be60a902SHaavard Skinnemoen } 537be60a902SHaavard Skinnemoen 538be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 539be60a902SHaavard Skinnemoen */ 540be60a902SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect, 541be60a902SHaavard Skinnemoen uint offset, uchar cmd) 542be60a902SHaavard Skinnemoen { 543cdbaefb5SHaavard Skinnemoen void *addr; 544be60a902SHaavard Skinnemoen cfiword_t cword; 545be60a902SHaavard Skinnemoen int retval; 546be60a902SHaavard Skinnemoen 54712d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 548be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 549be60a902SHaavard Skinnemoen switch (info->portwidth) { 550be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 551cdbaefb5SHaavard Skinnemoen retval = ((flash_read8(addr) & cword.c) == cword.c); 552be60a902SHaavard Skinnemoen break; 553be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 554cdbaefb5SHaavard Skinnemoen retval = ((flash_read16(addr) & cword.w) == cword.w); 555be60a902SHaavard Skinnemoen break; 556be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 55747cc23cbSStefan Roese retval = ((flash_read32(addr) & cword.l) == cword.l); 558be60a902SHaavard Skinnemoen break; 559be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 560cdbaefb5SHaavard Skinnemoen retval = ((flash_read64(addr) & cword.ll) == cword.ll); 561be60a902SHaavard Skinnemoen break; 562be60a902SHaavard Skinnemoen default: 563be60a902SHaavard Skinnemoen retval = 0; 564be60a902SHaavard Skinnemoen break; 565be60a902SHaavard Skinnemoen } 56612d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 56712d30aa7SHaavard Skinnemoen 568be60a902SHaavard Skinnemoen return retval; 569be60a902SHaavard Skinnemoen } 570be60a902SHaavard Skinnemoen 571be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 572be60a902SHaavard Skinnemoen */ 573be60a902SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect, 574be60a902SHaavard Skinnemoen uint offset, uchar cmd) 575be60a902SHaavard Skinnemoen { 576cdbaefb5SHaavard Skinnemoen void *addr; 577be60a902SHaavard Skinnemoen cfiword_t cword; 578be60a902SHaavard Skinnemoen int retval; 579be60a902SHaavard Skinnemoen 58012d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 581be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 582be60a902SHaavard Skinnemoen switch (info->portwidth) { 583be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 584*fb8c061eSStefan Roese retval = flash_read8(addr) != flash_read8(addr); 585be60a902SHaavard Skinnemoen break; 586be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 587*fb8c061eSStefan Roese retval = flash_read16(addr) != flash_read16(addr); 588be60a902SHaavard Skinnemoen break; 589be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 590*fb8c061eSStefan Roese retval = flash_read32(addr) != flash_read32(addr); 591be60a902SHaavard Skinnemoen break; 592be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 593*fb8c061eSStefan Roese retval = flash_read64(addr) != flash_read64(addr); 594be60a902SHaavard Skinnemoen break; 595be60a902SHaavard Skinnemoen default: 596be60a902SHaavard Skinnemoen retval = 0; 597be60a902SHaavard Skinnemoen break; 598be60a902SHaavard Skinnemoen } 59912d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 60012d30aa7SHaavard Skinnemoen 601be60a902SHaavard Skinnemoen return retval; 602be60a902SHaavard Skinnemoen } 603be60a902SHaavard Skinnemoen 604be60a902SHaavard Skinnemoen /* 605be60a902SHaavard Skinnemoen * flash_is_busy - check to see if the flash is busy 606be60a902SHaavard Skinnemoen * 607be60a902SHaavard Skinnemoen * This routine checks the status of the chip and returns true if the 608be60a902SHaavard Skinnemoen * chip is busy. 609be60a902SHaavard Skinnemoen */ 610be60a902SHaavard Skinnemoen static int flash_is_busy (flash_info_t * info, flash_sect_t sect) 611be60a902SHaavard Skinnemoen { 612be60a902SHaavard Skinnemoen int retval; 613be60a902SHaavard Skinnemoen 61481b20cccSMichael Schwingen switch (info->vendor) { 6159c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 61681b20cccSMichael Schwingen case CFI_CMDSET_INTEL_STANDARD: 61781b20cccSMichael Schwingen case CFI_CMDSET_INTEL_EXTENDED: 618be60a902SHaavard Skinnemoen retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); 61981b20cccSMichael Schwingen break; 62081b20cccSMichael Schwingen case CFI_CMDSET_AMD_STANDARD: 62181b20cccSMichael Schwingen case CFI_CMDSET_AMD_EXTENDED: 622be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 62381b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 624be60a902SHaavard Skinnemoen #endif 625be60a902SHaavard Skinnemoen retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); 626be60a902SHaavard Skinnemoen break; 627be60a902SHaavard Skinnemoen default: 628be60a902SHaavard Skinnemoen retval = 0; 629be60a902SHaavard Skinnemoen } 630be60a902SHaavard Skinnemoen debug ("flash_is_busy: %d\n", retval); 631be60a902SHaavard Skinnemoen return retval; 632be60a902SHaavard Skinnemoen } 633be60a902SHaavard Skinnemoen 634be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 635be60a902SHaavard Skinnemoen * wait for XSR.7 to be set. Time out with an error if it does not. 636be60a902SHaavard Skinnemoen * This routine does not set the flash to read-array mode. 637be60a902SHaavard Skinnemoen */ 638be60a902SHaavard Skinnemoen static int flash_status_check (flash_info_t * info, flash_sect_t sector, 639be60a902SHaavard Skinnemoen ulong tout, char *prompt) 640be60a902SHaavard Skinnemoen { 641be60a902SHaavard Skinnemoen ulong start; 642be60a902SHaavard Skinnemoen 643be60a902SHaavard Skinnemoen #if CFG_HZ != 1000 644be60a902SHaavard Skinnemoen tout *= CFG_HZ/1000; 645be60a902SHaavard Skinnemoen #endif 646be60a902SHaavard Skinnemoen 647be60a902SHaavard Skinnemoen /* Wait for command completion */ 648be60a902SHaavard Skinnemoen start = get_timer (0); 649be60a902SHaavard Skinnemoen while (flash_is_busy (info, sector)) { 650be60a902SHaavard Skinnemoen if (get_timer (start) > tout) { 651be60a902SHaavard Skinnemoen printf ("Flash %s timeout at address %lx data %lx\n", 652be60a902SHaavard Skinnemoen prompt, info->start[sector], 653be60a902SHaavard Skinnemoen flash_read_long (info, sector, 0)); 654be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, info->cmd_reset); 655be60a902SHaavard Skinnemoen return ERR_TIMOUT; 656be60a902SHaavard Skinnemoen } 657be60a902SHaavard Skinnemoen udelay (1); /* also triggers watchdog */ 658be60a902SHaavard Skinnemoen } 659be60a902SHaavard Skinnemoen return ERR_OK; 660be60a902SHaavard Skinnemoen } 661be60a902SHaavard Skinnemoen 662be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 663be60a902SHaavard Skinnemoen * Wait for XSR.7 to be set, if it times out print an error, otherwise 664be60a902SHaavard Skinnemoen * do a full status check. 665be60a902SHaavard Skinnemoen * 666be60a902SHaavard Skinnemoen * This routine sets the flash to read-array mode. 667be60a902SHaavard Skinnemoen */ 668be60a902SHaavard Skinnemoen static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, 669be60a902SHaavard Skinnemoen ulong tout, char *prompt) 670be60a902SHaavard Skinnemoen { 671be60a902SHaavard Skinnemoen int retcode; 672be60a902SHaavard Skinnemoen 673be60a902SHaavard Skinnemoen retcode = flash_status_check (info, sector, tout, prompt); 674be60a902SHaavard Skinnemoen switch (info->vendor) { 6759c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 676be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 677be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 678be60a902SHaavard Skinnemoen if ((retcode == ERR_OK) 679be60a902SHaavard Skinnemoen && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { 680be60a902SHaavard Skinnemoen retcode = ERR_INVAL; 681be60a902SHaavard Skinnemoen printf ("Flash %s error at address %lx\n", prompt, 682be60a902SHaavard Skinnemoen info->start[sector]); 683be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | 684be60a902SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 685be60a902SHaavard Skinnemoen puts ("Command Sequence Error.\n"); 686be60a902SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 687be60a902SHaavard Skinnemoen FLASH_STATUS_ECLBS)) { 688be60a902SHaavard Skinnemoen puts ("Block Erase Error.\n"); 689be60a902SHaavard Skinnemoen retcode = ERR_NOT_ERASED; 690be60a902SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 691be60a902SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 692be60a902SHaavard Skinnemoen puts ("Locking Error\n"); 693be60a902SHaavard Skinnemoen } 694be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { 695be60a902SHaavard Skinnemoen puts ("Block locked.\n"); 696be60a902SHaavard Skinnemoen retcode = ERR_PROTECTED; 697be60a902SHaavard Skinnemoen } 698be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) 699be60a902SHaavard Skinnemoen puts ("Vpp Low Error.\n"); 700be60a902SHaavard Skinnemoen } 701be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, info->cmd_reset); 702be60a902SHaavard Skinnemoen break; 703be60a902SHaavard Skinnemoen default: 70481b20cccSMichael Schwingen break; 70581b20cccSMichael Schwingen } 706be60a902SHaavard Skinnemoen return retcode; 70781b20cccSMichael Schwingen } 708be60a902SHaavard Skinnemoen 709be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 710be60a902SHaavard Skinnemoen */ 711be60a902SHaavard Skinnemoen static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) 712be60a902SHaavard Skinnemoen { 713be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 714be60a902SHaavard Skinnemoen unsigned short w; 715be60a902SHaavard Skinnemoen unsigned int l; 716be60a902SHaavard Skinnemoen unsigned long long ll; 717be60a902SHaavard Skinnemoen #endif 718be60a902SHaavard Skinnemoen 719be60a902SHaavard Skinnemoen switch (info->portwidth) { 720be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 721be60a902SHaavard Skinnemoen cword->c = c; 722be60a902SHaavard Skinnemoen break; 723be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 724be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 725be60a902SHaavard Skinnemoen w = c; 726be60a902SHaavard Skinnemoen w <<= 8; 727be60a902SHaavard Skinnemoen cword->w = (cword->w >> 8) | w; 72881b20cccSMichael Schwingen #else 729be60a902SHaavard Skinnemoen cword->w = (cword->w << 8) | c; 730be60a902SHaavard Skinnemoen #endif 731be60a902SHaavard Skinnemoen break; 732be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 733be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 734be60a902SHaavard Skinnemoen l = c; 735be60a902SHaavard Skinnemoen l <<= 24; 736be60a902SHaavard Skinnemoen cword->l = (cword->l >> 8) | l; 737be60a902SHaavard Skinnemoen #else 738be60a902SHaavard Skinnemoen cword->l = (cword->l << 8) | c; 739be60a902SHaavard Skinnemoen #endif 740be60a902SHaavard Skinnemoen break; 741be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 742be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 743be60a902SHaavard Skinnemoen ll = c; 744be60a902SHaavard Skinnemoen ll <<= 56; 745be60a902SHaavard Skinnemoen cword->ll = (cword->ll >> 8) | ll; 746be60a902SHaavard Skinnemoen #else 747be60a902SHaavard Skinnemoen cword->ll = (cword->ll << 8) | c; 748be60a902SHaavard Skinnemoen #endif 749be60a902SHaavard Skinnemoen break; 750be60a902SHaavard Skinnemoen } 751be60a902SHaavard Skinnemoen } 752be60a902SHaavard Skinnemoen 753be60a902SHaavard Skinnemoen /* loop through the sectors from the highest address when the passed 754be60a902SHaavard Skinnemoen * address is greater or equal to the sector address we have a match 755be60a902SHaavard Skinnemoen */ 756be60a902SHaavard Skinnemoen static flash_sect_t find_sector (flash_info_t * info, ulong addr) 75781b20cccSMichael Schwingen { 758be60a902SHaavard Skinnemoen flash_sect_t sector; 759be60a902SHaavard Skinnemoen 760be60a902SHaavard Skinnemoen for (sector = info->sector_count - 1; sector >= 0; sector--) { 761be60a902SHaavard Skinnemoen if (addr >= info->start[sector]) 762be60a902SHaavard Skinnemoen break; 76381b20cccSMichael Schwingen } 764be60a902SHaavard Skinnemoen return sector; 76559829cc1SJean-Christophe PLAGNIOL-VILLARD } 76659829cc1SJean-Christophe PLAGNIOL-VILLARD 76759829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 76859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 769be60a902SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest, 770be60a902SHaavard Skinnemoen cfiword_t cword) 77159829cc1SJean-Christophe PLAGNIOL-VILLARD { 772cdbaefb5SHaavard Skinnemoen void *dstaddr; 773be60a902SHaavard Skinnemoen int flag; 77459829cc1SJean-Christophe PLAGNIOL-VILLARD 77512d30aa7SHaavard Skinnemoen dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE); 776be60a902SHaavard Skinnemoen 777be60a902SHaavard Skinnemoen /* Check if Flash is (sufficiently) erased */ 778be60a902SHaavard Skinnemoen switch (info->portwidth) { 779be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 780cdbaefb5SHaavard Skinnemoen flag = ((flash_read8(dstaddr) & cword.c) == cword.c); 781be60a902SHaavard Skinnemoen break; 782be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 783cdbaefb5SHaavard Skinnemoen flag = ((flash_read16(dstaddr) & cword.w) == cword.w); 784be60a902SHaavard Skinnemoen break; 785be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 786cdbaefb5SHaavard Skinnemoen flag = ((flash_read32(dstaddr) & cword.l) == cword.l); 787be60a902SHaavard Skinnemoen break; 788be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 789cdbaefb5SHaavard Skinnemoen flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll); 790be60a902SHaavard Skinnemoen break; 791be60a902SHaavard Skinnemoen default: 79212d30aa7SHaavard Skinnemoen flag = 0; 79312d30aa7SHaavard Skinnemoen break; 79412d30aa7SHaavard Skinnemoen } 79512d30aa7SHaavard Skinnemoen if (!flag) { 79612d30aa7SHaavard Skinnemoen unmap_physmem(dstaddr, info->portwidth); 7970dc80e27SStefan Roese return ERR_NOT_ERASED; 798be60a902SHaavard Skinnemoen } 799be60a902SHaavard Skinnemoen 800be60a902SHaavard Skinnemoen /* Disable interrupts which might cause a timeout here */ 801be60a902SHaavard Skinnemoen flag = disable_interrupts (); 802be60a902SHaavard Skinnemoen 803be60a902SHaavard Skinnemoen switch (info->vendor) { 8049c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 805be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 806be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 807be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); 808be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE); 809be60a902SHaavard Skinnemoen break; 810be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 811be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 812be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 813be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_LEGACY: 814be60a902SHaavard Skinnemoen #endif 815be60a902SHaavard Skinnemoen flash_unlock_seq (info, 0); 816be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE); 81759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 81859829cc1SJean-Christophe PLAGNIOL-VILLARD } 81959829cc1SJean-Christophe PLAGNIOL-VILLARD 820be60a902SHaavard Skinnemoen switch (info->portwidth) { 821be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 822cdbaefb5SHaavard Skinnemoen flash_write8(cword.c, dstaddr); 823be60a902SHaavard Skinnemoen break; 824be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 825cdbaefb5SHaavard Skinnemoen flash_write16(cword.w, dstaddr); 826be60a902SHaavard Skinnemoen break; 827be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 828cdbaefb5SHaavard Skinnemoen flash_write32(cword.l, dstaddr); 829be60a902SHaavard Skinnemoen break; 830be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 831cdbaefb5SHaavard Skinnemoen flash_write64(cword.ll, dstaddr); 832be60a902SHaavard Skinnemoen break; 83359829cc1SJean-Christophe PLAGNIOL-VILLARD } 834be60a902SHaavard Skinnemoen 835be60a902SHaavard Skinnemoen /* re-enable interrupts if necessary */ 836be60a902SHaavard Skinnemoen if (flag) 837be60a902SHaavard Skinnemoen enable_interrupts (); 838be60a902SHaavard Skinnemoen 83912d30aa7SHaavard Skinnemoen unmap_physmem(dstaddr, info->portwidth); 84012d30aa7SHaavard Skinnemoen 841be60a902SHaavard Skinnemoen return flash_full_status_check (info, find_sector (info, dest), 842be60a902SHaavard Skinnemoen info->write_tout, "write"); 843be60a902SHaavard Skinnemoen } 844be60a902SHaavard Skinnemoen 845be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_USE_BUFFER_WRITE 846be60a902SHaavard Skinnemoen 847be60a902SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, 848be60a902SHaavard Skinnemoen int len) 849be60a902SHaavard Skinnemoen { 850be60a902SHaavard Skinnemoen flash_sect_t sector; 851be60a902SHaavard Skinnemoen int cnt; 852be60a902SHaavard Skinnemoen int retcode; 853cdbaefb5SHaavard Skinnemoen void *src = cp; 85412d30aa7SHaavard Skinnemoen void *dst = map_physmem(dest, len, MAP_NOCACHE); 8550dc80e27SStefan Roese void *dst2 = dst; 8560dc80e27SStefan Roese int flag = 0; 85796ef831fSGuennadi Liakhovetski uint offset = 0; 85896ef831fSGuennadi Liakhovetski unsigned int shift; 8599c048b52SVasiliy Leoenenko uchar write_cmd; 860cdbaefb5SHaavard Skinnemoen 8610dc80e27SStefan Roese switch (info->portwidth) { 8620dc80e27SStefan Roese case FLASH_CFI_8BIT: 86396ef831fSGuennadi Liakhovetski shift = 0; 8640dc80e27SStefan Roese break; 8650dc80e27SStefan Roese case FLASH_CFI_16BIT: 86696ef831fSGuennadi Liakhovetski shift = 1; 8670dc80e27SStefan Roese break; 8680dc80e27SStefan Roese case FLASH_CFI_32BIT: 86996ef831fSGuennadi Liakhovetski shift = 2; 8700dc80e27SStefan Roese break; 8710dc80e27SStefan Roese case FLASH_CFI_64BIT: 87296ef831fSGuennadi Liakhovetski shift = 3; 8730dc80e27SStefan Roese break; 8740dc80e27SStefan Roese default: 8750dc80e27SStefan Roese retcode = ERR_INVAL; 8760dc80e27SStefan Roese goto out_unmap; 8770dc80e27SStefan Roese } 8780dc80e27SStefan Roese 87996ef831fSGuennadi Liakhovetski cnt = len >> shift; 88096ef831fSGuennadi Liakhovetski 8810dc80e27SStefan Roese while ((cnt-- > 0) && (flag == 0)) { 8820dc80e27SStefan Roese switch (info->portwidth) { 8830dc80e27SStefan Roese case FLASH_CFI_8BIT: 8840dc80e27SStefan Roese flag = ((flash_read8(dst2) & flash_read8(src)) == 8850dc80e27SStefan Roese flash_read8(src)); 8860dc80e27SStefan Roese src += 1, dst2 += 1; 8870dc80e27SStefan Roese break; 8880dc80e27SStefan Roese case FLASH_CFI_16BIT: 8890dc80e27SStefan Roese flag = ((flash_read16(dst2) & flash_read16(src)) == 8900dc80e27SStefan Roese flash_read16(src)); 8910dc80e27SStefan Roese src += 2, dst2 += 2; 8920dc80e27SStefan Roese break; 8930dc80e27SStefan Roese case FLASH_CFI_32BIT: 8940dc80e27SStefan Roese flag = ((flash_read32(dst2) & flash_read32(src)) == 8950dc80e27SStefan Roese flash_read32(src)); 8960dc80e27SStefan Roese src += 4, dst2 += 4; 8970dc80e27SStefan Roese break; 8980dc80e27SStefan Roese case FLASH_CFI_64BIT: 8990dc80e27SStefan Roese flag = ((flash_read64(dst2) & flash_read64(src)) == 9000dc80e27SStefan Roese flash_read64(src)); 9010dc80e27SStefan Roese src += 8, dst2 += 8; 9020dc80e27SStefan Roese break; 9030dc80e27SStefan Roese } 9040dc80e27SStefan Roese } 9050dc80e27SStefan Roese if (!flag) { 9060dc80e27SStefan Roese retcode = ERR_NOT_ERASED; 9070dc80e27SStefan Roese goto out_unmap; 9080dc80e27SStefan Roese } 9090dc80e27SStefan Roese 9100dc80e27SStefan Roese src = cp; 911cdbaefb5SHaavard Skinnemoen sector = find_sector (info, dest); 912be60a902SHaavard Skinnemoen 913be60a902SHaavard Skinnemoen switch (info->vendor) { 9149c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 915be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 916be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 9179c048b52SVasiliy Leoenenko write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ? 9189c048b52SVasiliy Leoenenko FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER; 919be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 9209c048b52SVasiliy Leoenenko flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS); 9219c048b52SVasiliy Leoenenko flash_write_cmd (info, sector, 0, write_cmd); 922be60a902SHaavard Skinnemoen retcode = flash_status_check (info, sector, 923be60a902SHaavard Skinnemoen info->buffer_write_tout, 924be60a902SHaavard Skinnemoen "write to buffer"); 925be60a902SHaavard Skinnemoen if (retcode == ERR_OK) { 926be60a902SHaavard Skinnemoen /* reduce the number of loops by the width of 927be60a902SHaavard Skinnemoen * the port */ 92896ef831fSGuennadi Liakhovetski cnt = len >> shift; 92993c56f21SVasiliy Leoenenko flash_write_cmd (info, sector, 0, cnt - 1); 930be60a902SHaavard Skinnemoen while (cnt-- > 0) { 931be60a902SHaavard Skinnemoen switch (info->portwidth) { 932be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 933cdbaefb5SHaavard Skinnemoen flash_write8(flash_read8(src), dst); 934cdbaefb5SHaavard Skinnemoen src += 1, dst += 1; 935be60a902SHaavard Skinnemoen break; 936be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 937cdbaefb5SHaavard Skinnemoen flash_write16(flash_read16(src), dst); 938cdbaefb5SHaavard Skinnemoen src += 2, dst += 2; 939be60a902SHaavard Skinnemoen break; 940be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 941cdbaefb5SHaavard Skinnemoen flash_write32(flash_read32(src), dst); 942cdbaefb5SHaavard Skinnemoen src += 4, dst += 4; 943be60a902SHaavard Skinnemoen break; 944be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 945cdbaefb5SHaavard Skinnemoen flash_write64(flash_read64(src), dst); 946cdbaefb5SHaavard Skinnemoen src += 8, dst += 8; 947be60a902SHaavard Skinnemoen break; 948be60a902SHaavard Skinnemoen default: 94912d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 95012d30aa7SHaavard Skinnemoen goto out_unmap; 951be60a902SHaavard Skinnemoen } 952be60a902SHaavard Skinnemoen } 953be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, 954be60a902SHaavard Skinnemoen FLASH_CMD_WRITE_BUFFER_CONFIRM); 955be60a902SHaavard Skinnemoen retcode = flash_full_status_check ( 956be60a902SHaavard Skinnemoen info, sector, info->buffer_write_tout, 957be60a902SHaavard Skinnemoen "buffer write"); 958be60a902SHaavard Skinnemoen } 95912d30aa7SHaavard Skinnemoen 96012d30aa7SHaavard Skinnemoen break; 961be60a902SHaavard Skinnemoen 962be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 963be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 964be60a902SHaavard Skinnemoen flash_unlock_seq(info,0); 96596ef831fSGuennadi Liakhovetski 96696ef831fSGuennadi Liakhovetski #ifdef CONFIG_FLASH_SPANSION_S29WS_N 96796ef831fSGuennadi Liakhovetski offset = ((unsigned long)dst - info->start[sector]) >> shift; 96896ef831fSGuennadi Liakhovetski #endif 96996ef831fSGuennadi Liakhovetski flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER); 97096ef831fSGuennadi Liakhovetski cnt = len >> shift; 97196ef831fSGuennadi Liakhovetski flash_write_cmd(info, sector, offset, (uchar)cnt - 1); 972be60a902SHaavard Skinnemoen 973be60a902SHaavard Skinnemoen switch (info->portwidth) { 974be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 975cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 976cdbaefb5SHaavard Skinnemoen flash_write8(flash_read8(src), dst); 977cdbaefb5SHaavard Skinnemoen src += 1, dst += 1; 978cdbaefb5SHaavard Skinnemoen } 979be60a902SHaavard Skinnemoen break; 980be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 981cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 982cdbaefb5SHaavard Skinnemoen flash_write16(flash_read16(src), dst); 983cdbaefb5SHaavard Skinnemoen src += 2, dst += 2; 984cdbaefb5SHaavard Skinnemoen } 985be60a902SHaavard Skinnemoen break; 986be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 987cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 988cdbaefb5SHaavard Skinnemoen flash_write32(flash_read32(src), dst); 989cdbaefb5SHaavard Skinnemoen src += 4, dst += 4; 990cdbaefb5SHaavard Skinnemoen } 991be60a902SHaavard Skinnemoen break; 992be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 993cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 994cdbaefb5SHaavard Skinnemoen flash_write64(flash_read64(src), dst); 995cdbaefb5SHaavard Skinnemoen src += 8, dst += 8; 996cdbaefb5SHaavard Skinnemoen } 997be60a902SHaavard Skinnemoen break; 998be60a902SHaavard Skinnemoen default: 99912d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 100012d30aa7SHaavard Skinnemoen goto out_unmap; 1001be60a902SHaavard Skinnemoen } 1002be60a902SHaavard Skinnemoen 1003be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); 1004be60a902SHaavard Skinnemoen retcode = flash_full_status_check (info, sector, 1005be60a902SHaavard Skinnemoen info->buffer_write_tout, 1006be60a902SHaavard Skinnemoen "buffer write"); 100712d30aa7SHaavard Skinnemoen break; 1008be60a902SHaavard Skinnemoen 1009be60a902SHaavard Skinnemoen default: 1010be60a902SHaavard Skinnemoen debug ("Unknown Command Set\n"); 101112d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 101212d30aa7SHaavard Skinnemoen break; 1013be60a902SHaavard Skinnemoen } 101412d30aa7SHaavard Skinnemoen 101512d30aa7SHaavard Skinnemoen out_unmap: 101612d30aa7SHaavard Skinnemoen unmap_physmem(dst, len); 101712d30aa7SHaavard Skinnemoen return retcode; 1018be60a902SHaavard Skinnemoen } 1019be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_USE_BUFFER_WRITE */ 1020be60a902SHaavard Skinnemoen 102159829cc1SJean-Christophe PLAGNIOL-VILLARD 102259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 102359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 102459829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last) 102559829cc1SJean-Christophe PLAGNIOL-VILLARD { 102659829cc1SJean-Christophe PLAGNIOL-VILLARD int rcode = 0; 102759829cc1SJean-Christophe PLAGNIOL-VILLARD int prot; 102859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect; 102959829cc1SJean-Christophe PLAGNIOL-VILLARD 103059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 103159829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Can't erase unknown flash type - aborted\n"); 103259829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 103359829cc1SJean-Christophe PLAGNIOL-VILLARD } 103459829cc1SJean-Christophe PLAGNIOL-VILLARD if ((s_first < 0) || (s_first > s_last)) { 103559829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("- no sectors to erase\n"); 103659829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 103759829cc1SJean-Christophe PLAGNIOL-VILLARD } 103859829cc1SJean-Christophe PLAGNIOL-VILLARD 103959829cc1SJean-Christophe PLAGNIOL-VILLARD prot = 0; 104059829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; ++sect) { 104159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect]) { 104259829cc1SJean-Christophe PLAGNIOL-VILLARD prot++; 104359829cc1SJean-Christophe PLAGNIOL-VILLARD } 104459829cc1SJean-Christophe PLAGNIOL-VILLARD } 104559829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) { 10467e5b9b47SHaavard Skinnemoen printf ("- Warning: %d protected sectors will not be erased!\n", 10477e5b9b47SHaavard Skinnemoen prot); 104859829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 104959829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 105059829cc1SJean-Christophe PLAGNIOL-VILLARD } 105159829cc1SJean-Christophe PLAGNIOL-VILLARD 105259829cc1SJean-Christophe PLAGNIOL-VILLARD 105359829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; sect++) { 105459829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect] == 0) { /* not protected */ 105559829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 10569c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 105759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 105859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 10597e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10607e5b9b47SHaavard Skinnemoen FLASH_CMD_CLEAR_STATUS); 10617e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10627e5b9b47SHaavard Skinnemoen FLASH_CMD_BLOCK_ERASE); 10637e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10647e5b9b47SHaavard Skinnemoen FLASH_CMD_ERASE_CONFIRM); 106559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 106659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 106759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 106859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 10697e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 10707e5b9b47SHaavard Skinnemoen info->addr_unlock1, 10717e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 107259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 10737e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10747e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_SECTOR); 107559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 107681b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 107781b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 107881b20cccSMichael Schwingen flash_unlock_seq (info, 0); 10797e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, info->addr_unlock1, 10807e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 108181b20cccSMichael Schwingen flash_unlock_seq (info, 0); 10827e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10837e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_SECTOR); 108481b20cccSMichael Schwingen break; 108581b20cccSMichael Schwingen #endif 108659829cc1SJean-Christophe PLAGNIOL-VILLARD default: 108759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("Unkown flash vendor %d\n", 108859829cc1SJean-Christophe PLAGNIOL-VILLARD info->vendor); 108959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 109059829cc1SJean-Christophe PLAGNIOL-VILLARD } 109159829cc1SJean-Christophe PLAGNIOL-VILLARD 109259829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_full_status_check 109359829cc1SJean-Christophe PLAGNIOL-VILLARD (info, sect, info->erase_blk_tout, "erase")) { 109459829cc1SJean-Christophe PLAGNIOL-VILLARD rcode = 1; 109559829cc1SJean-Christophe PLAGNIOL-VILLARD } else 109659829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('.'); 109759829cc1SJean-Christophe PLAGNIOL-VILLARD } 109859829cc1SJean-Christophe PLAGNIOL-VILLARD } 109959829cc1SJean-Christophe PLAGNIOL-VILLARD puts (" done\n"); 110059829cc1SJean-Christophe PLAGNIOL-VILLARD return rcode; 110159829cc1SJean-Christophe PLAGNIOL-VILLARD } 110259829cc1SJean-Christophe PLAGNIOL-VILLARD 110359829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 110459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 110559829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info) 110659829cc1SJean-Christophe PLAGNIOL-VILLARD { 110759829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 110859829cc1SJean-Christophe PLAGNIOL-VILLARD 110959829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 111059829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("missing or unknown FLASH type\n"); 111159829cc1SJean-Christophe PLAGNIOL-VILLARD return; 111259829cc1SJean-Christophe PLAGNIOL-VILLARD } 111359829cc1SJean-Christophe PLAGNIOL-VILLARD 111481b20cccSMichael Schwingen printf ("%s FLASH (%d x %d)", 111581b20cccSMichael Schwingen info->name, 111659829cc1SJean-Christophe PLAGNIOL-VILLARD (info->portwidth << 3), (info->chipwidth << 3)); 111781b20cccSMichael Schwingen if (info->size < 1024*1024) 111881b20cccSMichael Schwingen printf (" Size: %ld kB in %d Sectors\n", 111981b20cccSMichael Schwingen info->size >> 10, info->sector_count); 112081b20cccSMichael Schwingen else 112159829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" Size: %ld MB in %d Sectors\n", 112259829cc1SJean-Christophe PLAGNIOL-VILLARD info->size >> 20, info->sector_count); 112359829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" "); 112459829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 11259c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 11269c048b52SVasiliy Leoenenko printf ("Intel Prog Regions"); 11279c048b52SVasiliy Leoenenko break; 112859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 112959829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Standard"); 113059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 113159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 113259829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Extended"); 113359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 113459829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 113559829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Standard"); 113659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 113759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 113859829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Extended"); 113959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 114081b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 114181b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 114281b20cccSMichael Schwingen printf ("AMD Legacy"); 114381b20cccSMichael Schwingen break; 114481b20cccSMichael Schwingen #endif 114559829cc1SJean-Christophe PLAGNIOL-VILLARD default: 114659829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Unknown (%d)", info->vendor); 114759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 114859829cc1SJean-Christophe PLAGNIOL-VILLARD } 114959829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X", 115059829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id, info->device_id); 115159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 115259829cc1SJean-Christophe PLAGNIOL-VILLARD printf("%04X", info->device_id2); 115359829cc1SJean-Christophe PLAGNIOL-VILLARD } 115459829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n", 115559829cc1SJean-Christophe PLAGNIOL-VILLARD info->erase_blk_tout, 115659829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout); 115759829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size > 1) { 11587e5b9b47SHaavard Skinnemoen printf (" Buffer write timeout: %ld ms, " 11597e5b9b47SHaavard Skinnemoen "buffer size: %d bytes\n", 116059829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout, 116159829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_size); 116259829cc1SJean-Christophe PLAGNIOL-VILLARD } 116359829cc1SJean-Christophe PLAGNIOL-VILLARD 116459829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("\n Sector Start Addresses:"); 116559829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; ++i) { 116659829cc1SJean-Christophe PLAGNIOL-VILLARD if ((i % 5) == 0) 116759829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n"); 116859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_EMPTY_INFO 116959829cc1SJean-Christophe PLAGNIOL-VILLARD int k; 117059829cc1SJean-Christophe PLAGNIOL-VILLARD int size; 117159829cc1SJean-Christophe PLAGNIOL-VILLARD int erased; 117259829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long *flash; 117359829cc1SJean-Christophe PLAGNIOL-VILLARD 117459829cc1SJean-Christophe PLAGNIOL-VILLARD /* 117559829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if whole sector is erased 117659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 117712d30aa7SHaavard Skinnemoen size = flash_sector_size(info, i); 117859829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 1; 117959829cc1SJean-Christophe PLAGNIOL-VILLARD flash = (volatile unsigned long *) info->start[i]; 118059829cc1SJean-Christophe PLAGNIOL-VILLARD size = size >> 2; /* divide by 4 for longword access */ 118159829cc1SJean-Christophe PLAGNIOL-VILLARD for (k = 0; k < size; k++) { 118259829cc1SJean-Christophe PLAGNIOL-VILLARD if (*flash++ != 0xffffffff) { 118359829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 0; 118459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 118559829cc1SJean-Christophe PLAGNIOL-VILLARD } 118659829cc1SJean-Christophe PLAGNIOL-VILLARD } 118759829cc1SJean-Christophe PLAGNIOL-VILLARD 118859829cc1SJean-Christophe PLAGNIOL-VILLARD /* print empty and read-only info */ 118959829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %c %s ", 119059829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 119159829cc1SJean-Christophe PLAGNIOL-VILLARD erased ? 'E' : ' ', 119259829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 119359829cc1SJean-Christophe PLAGNIOL-VILLARD #else /* ! CFG_FLASH_EMPTY_INFO */ 119459829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %s ", 119559829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 119659829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 119759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 119859829cc1SJean-Christophe PLAGNIOL-VILLARD } 119959829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 120059829cc1SJean-Christophe PLAGNIOL-VILLARD return; 120159829cc1SJean-Christophe PLAGNIOL-VILLARD } 120259829cc1SJean-Christophe PLAGNIOL-VILLARD 120359829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 12049a042e9cSJerry Van Baren * This is used in a few places in write_buf() to show programming 12059a042e9cSJerry Van Baren * progress. Making it a function is nasty because it needs to do side 12069a042e9cSJerry Van Baren * effect updates to digit and dots. Repeated code is nasty too, so 12079a042e9cSJerry Van Baren * we define it once here. 12089a042e9cSJerry Van Baren */ 1209f0105727SStefan Roese #ifdef CONFIG_FLASH_SHOW_PROGRESS 1210f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \ 1211f0105727SStefan Roese dots -= dots_sub; \ 12129a042e9cSJerry Van Baren if ((scale > 0) && (dots <= 0)) { \ 12139a042e9cSJerry Van Baren if ((digit % 5) == 0) \ 12149a042e9cSJerry Van Baren printf ("%d", digit / 5); \ 12159a042e9cSJerry Van Baren else \ 12169a042e9cSJerry Van Baren putc ('.'); \ 12179a042e9cSJerry Van Baren digit--; \ 12189a042e9cSJerry Van Baren dots += scale; \ 12199a042e9cSJerry Van Baren } 1220f0105727SStefan Roese #else 1221f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) 1222f0105727SStefan Roese #endif 12239a042e9cSJerry Van Baren 12249a042e9cSJerry Van Baren /*----------------------------------------------------------------------- 122559829cc1SJean-Christophe PLAGNIOL-VILLARD * Copy memory to flash, returns: 122659829cc1SJean-Christophe PLAGNIOL-VILLARD * 0 - OK 122759829cc1SJean-Christophe PLAGNIOL-VILLARD * 1 - write timeout 122859829cc1SJean-Christophe PLAGNIOL-VILLARD * 2 - Flash not erased 122959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 123059829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) 123159829cc1SJean-Christophe PLAGNIOL-VILLARD { 123259829cc1SJean-Christophe PLAGNIOL-VILLARD ulong wp; 123312d30aa7SHaavard Skinnemoen uchar *p; 123459829cc1SJean-Christophe PLAGNIOL-VILLARD int aln; 123559829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 123659829cc1SJean-Christophe PLAGNIOL-VILLARD int i, rc; 123759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 123859829cc1SJean-Christophe PLAGNIOL-VILLARD int buffered_size; 123959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 12409a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS 12419a042e9cSJerry Van Baren int digit = CONFIG_FLASH_SHOW_PROGRESS; 12429a042e9cSJerry Van Baren int scale = 0; 12439a042e9cSJerry Van Baren int dots = 0; 12449a042e9cSJerry Van Baren 12459a042e9cSJerry Van Baren /* 12469a042e9cSJerry Van Baren * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes. 12479a042e9cSJerry Van Baren */ 12489a042e9cSJerry Van Baren if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) { 12499a042e9cSJerry Van Baren scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) / 12509a042e9cSJerry Van Baren CONFIG_FLASH_SHOW_PROGRESS); 12519a042e9cSJerry Van Baren } 12529a042e9cSJerry Van Baren #endif 12539a042e9cSJerry Van Baren 125459829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 125559829cc1SJean-Christophe PLAGNIOL-VILLARD wp = (addr & ~(info->portwidth - 1)); 125659829cc1SJean-Christophe PLAGNIOL-VILLARD 125759829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle unaligned start */ 125859829cc1SJean-Christophe PLAGNIOL-VILLARD if ((aln = addr - wp) != 0) { 125959829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 126012d30aa7SHaavard Skinnemoen p = map_physmem(wp, info->portwidth, MAP_NOCACHE); 126112d30aa7SHaavard Skinnemoen for (i = 0; i < aln; ++i) 126212d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 126359829cc1SJean-Christophe PLAGNIOL-VILLARD 126459829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (i < info->portwidth) && (cnt > 0); i++) { 126559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 126659829cc1SJean-Christophe PLAGNIOL-VILLARD cnt--; 126759829cc1SJean-Christophe PLAGNIOL-VILLARD } 126812d30aa7SHaavard Skinnemoen for (; (cnt == 0) && (i < info->portwidth); ++i) 126912d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 127012d30aa7SHaavard Skinnemoen 127112d30aa7SHaavard Skinnemoen rc = flash_write_cfiword (info, wp, cword); 127212d30aa7SHaavard Skinnemoen unmap_physmem(p, info->portwidth); 127312d30aa7SHaavard Skinnemoen if (rc != 0) 127459829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 127512d30aa7SHaavard Skinnemoen 127612d30aa7SHaavard Skinnemoen wp += i; 1277f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, i); 127859829cc1SJean-Christophe PLAGNIOL-VILLARD } 127959829cc1SJean-Christophe PLAGNIOL-VILLARD 128059829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle the aligned part */ 128159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 128259829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size = (info->portwidth / info->chipwidth); 128359829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size *= info->buffer_size; 128459829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 128559829cc1SJean-Christophe PLAGNIOL-VILLARD /* prohibit buffer write when buffer_size is 1 */ 128659829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size == 1) { 128759829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 128859829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) 128959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 129059829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 129159829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 129259829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 129359829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 129459829cc1SJean-Christophe PLAGNIOL-VILLARD continue; 129559829cc1SJean-Christophe PLAGNIOL-VILLARD } 129659829cc1SJean-Christophe PLAGNIOL-VILLARD 129759829cc1SJean-Christophe PLAGNIOL-VILLARD /* write buffer until next buffered_size aligned boundary */ 129859829cc1SJean-Christophe PLAGNIOL-VILLARD i = buffered_size - (wp % buffered_size); 129959829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > cnt) 130059829cc1SJean-Christophe PLAGNIOL-VILLARD i = cnt; 130159829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) 130259829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 130359829cc1SJean-Christophe PLAGNIOL-VILLARD i -= i & (info->portwidth - 1); 130459829cc1SJean-Christophe PLAGNIOL-VILLARD wp += i; 130559829cc1SJean-Christophe PLAGNIOL-VILLARD src += i; 130659829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= i; 1307f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, i); 130859829cc1SJean-Christophe PLAGNIOL-VILLARD } 130959829cc1SJean-Christophe PLAGNIOL-VILLARD #else 131059829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 131159829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 131259829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) { 131359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 131459829cc1SJean-Christophe PLAGNIOL-VILLARD } 131559829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 131659829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 131759829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 131859829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 1319f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth); 132059829cc1SJean-Christophe PLAGNIOL-VILLARD } 132159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */ 13229a042e9cSJerry Van Baren 132359829cc1SJean-Christophe PLAGNIOL-VILLARD if (cnt == 0) { 132459829cc1SJean-Christophe PLAGNIOL-VILLARD return (0); 132559829cc1SJean-Christophe PLAGNIOL-VILLARD } 132659829cc1SJean-Christophe PLAGNIOL-VILLARD 132759829cc1SJean-Christophe PLAGNIOL-VILLARD /* 132859829cc1SJean-Christophe PLAGNIOL-VILLARD * handle unaligned tail bytes 132959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 133059829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 133112d30aa7SHaavard Skinnemoen p = map_physmem(wp, info->portwidth, MAP_NOCACHE); 133212d30aa7SHaavard Skinnemoen for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) { 133359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 133459829cc1SJean-Christophe PLAGNIOL-VILLARD --cnt; 133559829cc1SJean-Christophe PLAGNIOL-VILLARD } 133612d30aa7SHaavard Skinnemoen for (; i < info->portwidth; ++i) 133712d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 133812d30aa7SHaavard Skinnemoen unmap_physmem(p, info->portwidth); 133959829cc1SJean-Christophe PLAGNIOL-VILLARD 134059829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_write_cfiword (info, wp, cword); 134159829cc1SJean-Christophe PLAGNIOL-VILLARD } 134259829cc1SJean-Christophe PLAGNIOL-VILLARD 134359829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 134459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 134559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 134659829cc1SJean-Christophe PLAGNIOL-VILLARD 134759829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot) 134859829cc1SJean-Christophe PLAGNIOL-VILLARD { 134959829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode = 0; 135059829cc1SJean-Christophe PLAGNIOL-VILLARD 135159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 135259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); 135359829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) 135459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); 135559829cc1SJean-Christophe PLAGNIOL-VILLARD else 135659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR); 135759829cc1SJean-Christophe PLAGNIOL-VILLARD 135859829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode = 135959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_full_status_check (info, sector, info->erase_blk_tout, 136059829cc1SJean-Christophe PLAGNIOL-VILLARD prot ? "protect" : "unprotect")) == 0) { 136159829cc1SJean-Christophe PLAGNIOL-VILLARD 136259829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sector] = prot; 136359829cc1SJean-Christophe PLAGNIOL-VILLARD 136459829cc1SJean-Christophe PLAGNIOL-VILLARD /* 136559829cc1SJean-Christophe PLAGNIOL-VILLARD * On some of Intel's flash chips (marked via legacy_unlock) 136659829cc1SJean-Christophe PLAGNIOL-VILLARD * unprotect unprotects all locking. 136759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 136859829cc1SJean-Christophe PLAGNIOL-VILLARD if ((prot == 0) && (info->legacy_unlock)) { 136959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t i; 137059829cc1SJean-Christophe PLAGNIOL-VILLARD 137159829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; i++) { 137259829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[i]) 137359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (info, i, 1); 137459829cc1SJean-Christophe PLAGNIOL-VILLARD } 137559829cc1SJean-Christophe PLAGNIOL-VILLARD } 137659829cc1SJean-Christophe PLAGNIOL-VILLARD } 137759829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 137859829cc1SJean-Christophe PLAGNIOL-VILLARD } 137959829cc1SJean-Christophe PLAGNIOL-VILLARD 138059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 138159829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_user_serial - read the OneTimeProgramming cells 138259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 138359829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, 138459829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 138559829cc1SJean-Christophe PLAGNIOL-VILLARD { 138659829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 138759829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *dst; 138859829cc1SJean-Christophe PLAGNIOL-VILLARD 138959829cc1SJean-Christophe PLAGNIOL-VILLARD dst = buffer; 139012d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION); 139159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 139259829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (dst, src + offset, len); 139359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 139412d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src); 139559829cc1SJean-Christophe PLAGNIOL-VILLARD } 139659829cc1SJean-Christophe PLAGNIOL-VILLARD 139759829cc1SJean-Christophe PLAGNIOL-VILLARD /* 139859829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_factory_serial - read the device Id from the protection area 139959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 140059829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, 140159829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 140259829cc1SJean-Christophe PLAGNIOL-VILLARD { 140359829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 140459829cc1SJean-Christophe PLAGNIOL-VILLARD 140512d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION); 140659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 140759829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (buffer, src + offset, len); 140859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 140912d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src); 141059829cc1SJean-Christophe PLAGNIOL-VILLARD } 141159829cc1SJean-Christophe PLAGNIOL-VILLARD 141259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */ 141359829cc1SJean-Christophe PLAGNIOL-VILLARD 14140ddf06ddSHaavard Skinnemoen /*----------------------------------------------------------------------- 14150ddf06ddSHaavard Skinnemoen * Reverse the order of the erase regions in the CFI QRY structure. 14160ddf06ddSHaavard Skinnemoen * This is needed for chips that are either a) correctly detected as 14170ddf06ddSHaavard Skinnemoen * top-boot, or b) buggy. 14180ddf06ddSHaavard Skinnemoen */ 14190ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry) 14200ddf06ddSHaavard Skinnemoen { 14210ddf06ddSHaavard Skinnemoen unsigned int i, j; 14220ddf06ddSHaavard Skinnemoen u32 tmp; 14230ddf06ddSHaavard Skinnemoen 14240ddf06ddSHaavard Skinnemoen for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) { 14250ddf06ddSHaavard Skinnemoen tmp = qry->erase_region_info[i]; 14260ddf06ddSHaavard Skinnemoen qry->erase_region_info[i] = qry->erase_region_info[j]; 14270ddf06ddSHaavard Skinnemoen qry->erase_region_info[j] = tmp; 14280ddf06ddSHaavard Skinnemoen } 14290ddf06ddSHaavard Skinnemoen } 143059829cc1SJean-Christophe PLAGNIOL-VILLARD 143159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 143259829cc1SJean-Christophe PLAGNIOL-VILLARD * read jedec ids from device and set corresponding fields in info struct 143359829cc1SJean-Christophe PLAGNIOL-VILLARD * 143459829cc1SJean-Christophe PLAGNIOL-VILLARD * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct 143559829cc1SJean-Christophe PLAGNIOL-VILLARD * 143659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 14370ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info) 143859829cc1SJean-Christophe PLAGNIOL-VILLARD { 143959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 144059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); 144159829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 144259829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 144359829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 144459829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 144559829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 144659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 14470ddf06ddSHaavard Skinnemoen } 14480ddf06ddSHaavard Skinnemoen 14490ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry) 14500ddf06ddSHaavard Skinnemoen { 14510ddf06ddSHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 14520ddf06ddSHaavard Skinnemoen 14530ddf06ddSHaavard Skinnemoen cmdset_intel_read_jedec_ids(info); 14540ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 14550ddf06ddSHaavard Skinnemoen 14560ddf06ddSHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION 14570ddf06ddSHaavard Skinnemoen /* read legacy lock/unlock bit from intel flash */ 14580ddf06ddSHaavard Skinnemoen if (info->ext_addr) { 14590ddf06ddSHaavard Skinnemoen info->legacy_unlock = flash_read_uchar (info, 14600ddf06ddSHaavard Skinnemoen info->ext_addr + 5) & 0x08; 14610ddf06ddSHaavard Skinnemoen } 14620ddf06ddSHaavard Skinnemoen #endif 14630ddf06ddSHaavard Skinnemoen 14640ddf06ddSHaavard Skinnemoen return 0; 14650ddf06ddSHaavard Skinnemoen } 14660ddf06ddSHaavard Skinnemoen 14670ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info) 14680ddf06ddSHaavard Skinnemoen { 146959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 147059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info, 0); 147181b20cccSMichael Schwingen flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); 147259829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 147390447ecbSTor Krill 147459829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 147559829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 147690447ecbSTor Krill 147790447ecbSTor Krill switch (info->chipwidth){ 147890447ecbSTor Krill case FLASH_CFI_8BIT: 147959829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 148059829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 148159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 148259829cc1SJean-Christophe PLAGNIOL-VILLARD /* AMD 3-byte (expanded) device ids */ 148359829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = flash_read_uchar (info, 148459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID2); 148559829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 <<= 8; 148659829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 |= flash_read_uchar (info, 148759829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID3); 148859829cc1SJean-Christophe PLAGNIOL-VILLARD } 148990447ecbSTor Krill break; 149090447ecbSTor Krill case FLASH_CFI_16BIT: 149190447ecbSTor Krill info->device_id = flash_read_word (info, 149290447ecbSTor Krill FLASH_OFFSET_DEVICE_ID); 149390447ecbSTor Krill break; 149490447ecbSTor Krill default: 149590447ecbSTor Krill break; 149690447ecbSTor Krill } 149759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 14980ddf06ddSHaavard Skinnemoen } 14990ddf06ddSHaavard Skinnemoen 15000ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry) 15010ddf06ddSHaavard Skinnemoen { 15020ddf06ddSHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 15030ddf06ddSHaavard Skinnemoen 15040ddf06ddSHaavard Skinnemoen cmdset_amd_read_jedec_ids(info); 15050ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 15060ddf06ddSHaavard Skinnemoen 15070ddf06ddSHaavard Skinnemoen return 0; 15080ddf06ddSHaavard Skinnemoen } 15090ddf06ddSHaavard Skinnemoen 15100ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 15110ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info) 15120ddf06ddSHaavard Skinnemoen { 15130ddf06ddSHaavard Skinnemoen info->manufacturer_id = 0; 15140ddf06ddSHaavard Skinnemoen info->device_id = 0; 15150ddf06ddSHaavard Skinnemoen info->device_id2 = 0; 15160ddf06ddSHaavard Skinnemoen 15170ddf06ddSHaavard Skinnemoen switch (info->vendor) { 15189c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 15190ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 15200ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 15218225d1e3SMichael Schwingen cmdset_intel_read_jedec_ids(info); 15220ddf06ddSHaavard Skinnemoen break; 15230ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 15240ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 15258225d1e3SMichael Schwingen cmdset_amd_read_jedec_ids(info); 152659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 152759829cc1SJean-Christophe PLAGNIOL-VILLARD default: 152859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 152959829cc1SJean-Christophe PLAGNIOL-VILLARD } 153059829cc1SJean-Christophe PLAGNIOL-VILLARD } 153159829cc1SJean-Christophe PLAGNIOL-VILLARD 1532be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 1533be60a902SHaavard Skinnemoen * Call board code to request info about non-CFI flash. 1534be60a902SHaavard Skinnemoen * board_flash_get_legacy needs to fill in at least: 1535be60a902SHaavard Skinnemoen * info->portwidth, info->chipwidth and info->interface for Jedec probing. 1536be60a902SHaavard Skinnemoen */ 1537be60a902SHaavard Skinnemoen static int flash_detect_legacy(ulong base, int banknum) 1538be60a902SHaavard Skinnemoen { 1539be60a902SHaavard Skinnemoen flash_info_t *info = &flash_info[banknum]; 1540be60a902SHaavard Skinnemoen 1541be60a902SHaavard Skinnemoen if (board_flash_get_legacy(base, banknum, info)) { 1542be60a902SHaavard Skinnemoen /* board code may have filled info completely. If not, we 1543be60a902SHaavard Skinnemoen use JEDEC ID probing. */ 1544be60a902SHaavard Skinnemoen if (!info->vendor) { 1545be60a902SHaavard Skinnemoen int modes[] = { 1546be60a902SHaavard Skinnemoen CFI_CMDSET_AMD_STANDARD, 1547be60a902SHaavard Skinnemoen CFI_CMDSET_INTEL_STANDARD 1548be60a902SHaavard Skinnemoen }; 1549be60a902SHaavard Skinnemoen int i; 1550be60a902SHaavard Skinnemoen 1551be60a902SHaavard Skinnemoen for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) { 1552be60a902SHaavard Skinnemoen info->vendor = modes[i]; 1553be60a902SHaavard Skinnemoen info->start[0] = base; 1554be60a902SHaavard Skinnemoen if (info->portwidth == FLASH_CFI_8BIT 1555be60a902SHaavard Skinnemoen && info->interface == FLASH_CFI_X8X16) { 1556be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x2AAA; 1557be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x5555; 1558be60a902SHaavard Skinnemoen } else { 1559be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x5555; 1560be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x2AAA; 1561be60a902SHaavard Skinnemoen } 1562be60a902SHaavard Skinnemoen flash_read_jedec_ids(info); 1563be60a902SHaavard Skinnemoen debug("JEDEC PROBE: ID %x %x %x\n", 1564be60a902SHaavard Skinnemoen info->manufacturer_id, 1565be60a902SHaavard Skinnemoen info->device_id, 1566be60a902SHaavard Skinnemoen info->device_id2); 1567be60a902SHaavard Skinnemoen if (jedec_flash_match(info, base)) 1568be60a902SHaavard Skinnemoen break; 1569be60a902SHaavard Skinnemoen } 1570be60a902SHaavard Skinnemoen } 1571be60a902SHaavard Skinnemoen 1572be60a902SHaavard Skinnemoen switch(info->vendor) { 15739c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 1574be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 1575be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 1576be60a902SHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 1577be60a902SHaavard Skinnemoen break; 1578be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 1579be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 1580be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_LEGACY: 1581be60a902SHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 1582be60a902SHaavard Skinnemoen break; 1583be60a902SHaavard Skinnemoen } 1584be60a902SHaavard Skinnemoen info->flash_id = FLASH_MAN_CFI; 1585be60a902SHaavard Skinnemoen return 1; 1586be60a902SHaavard Skinnemoen } 1587be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1588be60a902SHaavard Skinnemoen } 1589be60a902SHaavard Skinnemoen #else 1590be60a902SHaavard Skinnemoen static inline int flash_detect_legacy(ulong base, int banknum) 1591be60a902SHaavard Skinnemoen { 1592be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1593be60a902SHaavard Skinnemoen } 1594be60a902SHaavard Skinnemoen #endif 1595be60a902SHaavard Skinnemoen 159659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 159759829cc1SJean-Christophe PLAGNIOL-VILLARD * detect if flash is compatible with the Common Flash Interface (CFI) 159859829cc1SJean-Christophe PLAGNIOL-VILLARD * http://www.jedec.org/download/search/jesd68.pdf 159959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1600e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf, 1601e23741f4SHaavard Skinnemoen unsigned int start, size_t len) 1602e23741f4SHaavard Skinnemoen { 1603e23741f4SHaavard Skinnemoen u8 *p = buf; 1604e23741f4SHaavard Skinnemoen unsigned int i; 1605e23741f4SHaavard Skinnemoen 1606e23741f4SHaavard Skinnemoen for (i = 0; i < len; i++) 1607e23741f4SHaavard Skinnemoen p[i] = flash_read_uchar(info, start + i); 1608e23741f4SHaavard Skinnemoen } 1609e23741f4SHaavard Skinnemoen 1610e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 161159829cc1SJean-Christophe PLAGNIOL-VILLARD { 161259829cc1SJean-Christophe PLAGNIOL-VILLARD int cfi_offset; 161359829cc1SJean-Christophe PLAGNIOL-VILLARD 16141ba639daSMichael Schwingen /* We do not yet know what kind of commandset to use, so we issue 16151ba639daSMichael Schwingen the reset command in both Intel and AMD variants, in the hope 16161ba639daSMichael Schwingen that AMD flash roms ignore the Intel command. */ 16171ba639daSMichael Schwingen flash_write_cmd (info, 0, 0, AMD_CMD_RESET); 16181ba639daSMichael Schwingen flash_write_cmd (info, 0, 0, FLASH_CMD_RESET); 16191ba639daSMichael Schwingen 16207e5b9b47SHaavard Skinnemoen for (cfi_offset=0; 16217e5b9b47SHaavard Skinnemoen cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint); 16227e5b9b47SHaavard Skinnemoen cfi_offset++) { 16237e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], 16247e5b9b47SHaavard Skinnemoen FLASH_CMD_CFI); 162559829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') 162659829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') 162759829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { 1628e23741f4SHaavard Skinnemoen flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP, 1629e23741f4SHaavard Skinnemoen sizeof(struct cfi_qry)); 1630e23741f4SHaavard Skinnemoen info->interface = le16_to_cpu(qry->interface_desc); 1631e23741f4SHaavard Skinnemoen 163259829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_offset = flash_offset_cfi[cfi_offset]; 163359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device interface is %d\n", 163459829cc1SJean-Christophe PLAGNIOL-VILLARD info->interface); 163559829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found port %d chip %d ", 163659829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth, info->chipwidth); 163759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("port %d bits chip %d bits\n", 163859829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth << CFI_FLASH_SHIFT_WIDTH, 163959829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 164042026c9cSBartlomiej Sieka 164142026c9cSBartlomiej Sieka /* calculate command offsets as in the Linux driver */ 164242026c9cSBartlomiej Sieka info->addr_unlock1 = 0x555; 164342026c9cSBartlomiej Sieka info->addr_unlock2 = 0x2aa; 164442026c9cSBartlomiej Sieka 164542026c9cSBartlomiej Sieka /* 164642026c9cSBartlomiej Sieka * modify the unlock address if we are 164742026c9cSBartlomiej Sieka * in compatibility mode 164842026c9cSBartlomiej Sieka */ 164942026c9cSBartlomiej Sieka if ( /* x8/x16 in x8 mode */ 165042026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY8) && 165142026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X8X16)) || 165242026c9cSBartlomiej Sieka /* x16/x32 in x16 mode */ 165342026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY16) && 165442026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X16X32))) 165542026c9cSBartlomiej Sieka { 165642026c9cSBartlomiej Sieka info->addr_unlock1 = 0xaaa; 165742026c9cSBartlomiej Sieka info->addr_unlock2 = 0x555; 165842026c9cSBartlomiej Sieka } 165942026c9cSBartlomiej Sieka 166081b20cccSMichael Schwingen info->name = "CFI conformant"; 166159829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 166259829cc1SJean-Christophe PLAGNIOL-VILLARD } 166359829cc1SJean-Christophe PLAGNIOL-VILLARD } 16647e5b9b47SHaavard Skinnemoen 16657e5b9b47SHaavard Skinnemoen return 0; 166659829cc1SJean-Christophe PLAGNIOL-VILLARD } 16677e5b9b47SHaavard Skinnemoen 1668e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 16697e5b9b47SHaavard Skinnemoen { 16707e5b9b47SHaavard Skinnemoen debug ("flash detect cfi\n"); 16717e5b9b47SHaavard Skinnemoen 16727e5b9b47SHaavard Skinnemoen for (info->portwidth = CFG_FLASH_CFI_WIDTH; 16737e5b9b47SHaavard Skinnemoen info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) { 16747e5b9b47SHaavard Skinnemoen for (info->chipwidth = FLASH_CFI_BY8; 16757e5b9b47SHaavard Skinnemoen info->chipwidth <= info->portwidth; 16767e5b9b47SHaavard Skinnemoen info->chipwidth <<= 1) 1677e23741f4SHaavard Skinnemoen if (__flash_detect_cfi(info, qry)) 16787e5b9b47SHaavard Skinnemoen return 1; 167959829cc1SJean-Christophe PLAGNIOL-VILLARD } 168059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("not found\n"); 168159829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 168259829cc1SJean-Christophe PLAGNIOL-VILLARD } 168359829cc1SJean-Christophe PLAGNIOL-VILLARD 168459829cc1SJean-Christophe PLAGNIOL-VILLARD /* 1685467bcee1SHaavard Skinnemoen * Manufacturer-specific quirks. Add workarounds for geometry 1686467bcee1SHaavard Skinnemoen * reversal, etc. here. 1687467bcee1SHaavard Skinnemoen */ 1688467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry) 1689467bcee1SHaavard Skinnemoen { 1690467bcee1SHaavard Skinnemoen /* check if flash geometry needs reversal */ 1691467bcee1SHaavard Skinnemoen if (qry->num_erase_regions > 1) { 1692467bcee1SHaavard Skinnemoen /* reverse geometry if top boot part */ 1693467bcee1SHaavard Skinnemoen if (info->cfi_version < 0x3131) { 1694467bcee1SHaavard Skinnemoen /* CFI < 1.1, try to guess from device id */ 1695467bcee1SHaavard Skinnemoen if ((info->device_id & 0x80) != 0) 1696467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1697467bcee1SHaavard Skinnemoen } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { 1698467bcee1SHaavard Skinnemoen /* CFI >= 1.1, deduct from top/bottom flag */ 1699467bcee1SHaavard Skinnemoen /* note: ext_addr is valid since cfi_version > 0 */ 1700467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1701467bcee1SHaavard Skinnemoen } 1702467bcee1SHaavard Skinnemoen } 1703467bcee1SHaavard Skinnemoen } 1704467bcee1SHaavard Skinnemoen 1705467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry) 1706467bcee1SHaavard Skinnemoen { 1707467bcee1SHaavard Skinnemoen int reverse_geometry = 0; 1708467bcee1SHaavard Skinnemoen 1709467bcee1SHaavard Skinnemoen /* Check the "top boot" bit in the PRI */ 1710467bcee1SHaavard Skinnemoen if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1)) 1711467bcee1SHaavard Skinnemoen reverse_geometry = 1; 1712467bcee1SHaavard Skinnemoen 1713467bcee1SHaavard Skinnemoen /* AT49BV6416(T) list the erase regions in the wrong order. 1714467bcee1SHaavard Skinnemoen * However, the device ID is identical with the non-broken 1715467bcee1SHaavard Skinnemoen * AT49BV642D since u-boot only reads the low byte (they 1716467bcee1SHaavard Skinnemoen * differ in the high byte.) So leave out this fixup for now. 1717467bcee1SHaavard Skinnemoen */ 1718467bcee1SHaavard Skinnemoen #if 0 1719467bcee1SHaavard Skinnemoen if (info->device_id == 0xd6 || info->device_id == 0xd2) 1720467bcee1SHaavard Skinnemoen reverse_geometry = !reverse_geometry; 1721467bcee1SHaavard Skinnemoen #endif 1722467bcee1SHaavard Skinnemoen 1723467bcee1SHaavard Skinnemoen if (reverse_geometry) 1724467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1725467bcee1SHaavard Skinnemoen } 1726467bcee1SHaavard Skinnemoen 1727467bcee1SHaavard Skinnemoen /* 172859829cc1SJean-Christophe PLAGNIOL-VILLARD * The following code cannot be run from FLASH! 172959829cc1SJean-Christophe PLAGNIOL-VILLARD * 173059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 173159829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum) 173259829cc1SJean-Christophe PLAGNIOL-VILLARD { 173359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t *info = &flash_info[banknum]; 173459829cc1SJean-Christophe PLAGNIOL-VILLARD int i, j; 173559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect_cnt; 173659829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long sector; 173759829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long tmp; 173859829cc1SJean-Christophe PLAGNIOL-VILLARD int size_ratio; 173959829cc1SJean-Christophe PLAGNIOL-VILLARD uchar num_erase_regions; 174059829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_size; 174159829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_count; 1742e23741f4SHaavard Skinnemoen struct cfi_qry qry; 174359829cc1SJean-Christophe PLAGNIOL-VILLARD 1744f979690eSKumar Gala memset(&qry, 0, sizeof(qry)); 1745f979690eSKumar Gala 174659829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = 0; 174759829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = 0; 174859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 174959829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = 0; 175059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 175159829cc1SJean-Christophe PLAGNIOL-VILLARD 175259829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[0] = base; 175359829cc1SJean-Christophe PLAGNIOL-VILLARD 1754e23741f4SHaavard Skinnemoen if (flash_detect_cfi (info, &qry)) { 1755e23741f4SHaavard Skinnemoen info->vendor = le16_to_cpu(qry.p_id); 1756e23741f4SHaavard Skinnemoen info->ext_addr = le16_to_cpu(qry.p_adr); 1757e23741f4SHaavard Skinnemoen num_erase_regions = qry.num_erase_regions; 1758e23741f4SHaavard Skinnemoen 175959829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 176059829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = (ushort) flash_read_uchar (info, 176159829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 3) << 8; 176259829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version |= (ushort) flash_read_uchar (info, 176359829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 4); 176459829cc1SJean-Christophe PLAGNIOL-VILLARD } 17650ddf06ddSHaavard Skinnemoen 176659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 1767e23741f4SHaavard Skinnemoen flash_printqry (&qry); 176859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 17690ddf06ddSHaavard Skinnemoen 177059829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 17719c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 177259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 177359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 17740ddf06ddSHaavard Skinnemoen cmdset_intel_init(info, &qry); 177559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 177659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 177759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 17780ddf06ddSHaavard Skinnemoen cmdset_amd_init(info, &qry); 177959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 17800ddf06ddSHaavard Skinnemoen default: 17810ddf06ddSHaavard Skinnemoen printf("CFI: Unknown command set 0x%x\n", 17820ddf06ddSHaavard Skinnemoen info->vendor); 17830ddf06ddSHaavard Skinnemoen /* 17840ddf06ddSHaavard Skinnemoen * Unfortunately, this means we don't know how 17850ddf06ddSHaavard Skinnemoen * to get the chip back to Read mode. Might 17860ddf06ddSHaavard Skinnemoen * as well try an Intel-style reset... 17870ddf06ddSHaavard Skinnemoen */ 17880ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 17890ddf06ddSHaavard Skinnemoen return 0; 179059829cc1SJean-Christophe PLAGNIOL-VILLARD } 179159829cc1SJean-Christophe PLAGNIOL-VILLARD 1792467bcee1SHaavard Skinnemoen /* Do manufacturer-specific fixups */ 1793467bcee1SHaavard Skinnemoen switch (info->manufacturer_id) { 1794467bcee1SHaavard Skinnemoen case 0x0001: 1795467bcee1SHaavard Skinnemoen flash_fixup_amd(info, &qry); 1796467bcee1SHaavard Skinnemoen break; 1797467bcee1SHaavard Skinnemoen case 0x001f: 1798467bcee1SHaavard Skinnemoen flash_fixup_atmel(info, &qry); 1799467bcee1SHaavard Skinnemoen break; 1800467bcee1SHaavard Skinnemoen } 1801467bcee1SHaavard Skinnemoen 180259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer is %d\n", info->vendor); 180359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer id is 0x%x\n", info->manufacturer_id); 180459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id is 0x%x\n", info->device_id); 180559829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id2 is 0x%x\n", info->device_id2); 180659829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("cfi version is 0x%04x\n", info->cfi_version); 180759829cc1SJean-Christophe PLAGNIOL-VILLARD 180859829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio = info->portwidth / info->chipwidth; 180959829cc1SJean-Christophe PLAGNIOL-VILLARD /* if the chip is x8/x16 reduce the ratio by half */ 181059829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->interface == FLASH_CFI_X8X16) 181159829cc1SJean-Christophe PLAGNIOL-VILLARD && (info->chipwidth == FLASH_CFI_BY8)) { 181259829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio >>= 1; 181359829cc1SJean-Christophe PLAGNIOL-VILLARD } 181459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("size_ratio %d port %d bits chip %d bits\n", 181559829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, 181659829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 181759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found %d erase regions\n", num_erase_regions); 181859829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt = 0; 181959829cc1SJean-Christophe PLAGNIOL-VILLARD sector = base; 182059829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < num_erase_regions; i++) { 182159829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > NUM_ERASE_REGIONS) { 182259829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("%d erase regions found, only %d used\n", 182359829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions, NUM_ERASE_REGIONS); 182459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 182559829cc1SJean-Christophe PLAGNIOL-VILLARD } 1826e23741f4SHaavard Skinnemoen 18270ddf06ddSHaavard Skinnemoen tmp = le32_to_cpu(qry.erase_region_info[i]); 18280ddf06ddSHaavard Skinnemoen debug("erase region %u: 0x%08lx\n", i, tmp); 1829e23741f4SHaavard Skinnemoen 1830e23741f4SHaavard Skinnemoen erase_region_count = (tmp & 0xffff) + 1; 1831e23741f4SHaavard Skinnemoen tmp >>= 16; 183259829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_size = 183359829cc1SJean-Christophe PLAGNIOL-VILLARD (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; 183459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("erase_region_count = %d erase_region_size = %d\n", 183559829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count, erase_region_size); 183659829cc1SJean-Christophe PLAGNIOL-VILLARD for (j = 0; j < erase_region_count; j++) { 183781b20cccSMichael Schwingen if (sect_cnt >= CFG_MAX_FLASH_SECT) { 183881b20cccSMichael Schwingen printf("ERROR: too many flash sectors\n"); 183981b20cccSMichael Schwingen break; 184081b20cccSMichael Schwingen } 184159829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[sect_cnt] = sector; 184259829cc1SJean-Christophe PLAGNIOL-VILLARD sector += (erase_region_size * size_ratio); 184359829cc1SJean-Christophe PLAGNIOL-VILLARD 184459829cc1SJean-Christophe PLAGNIOL-VILLARD /* 18457e5b9b47SHaavard Skinnemoen * Only read protection status from 18467e5b9b47SHaavard Skinnemoen * supported devices (intel...) 184759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 184859829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 18499c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 185059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 185159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 185259829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sect_cnt] = 185359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_isset (info, sect_cnt, 185459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PROTECT, 185559829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_STATUS_PROTECT); 185659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 185759829cc1SJean-Christophe PLAGNIOL-VILLARD default: 18587e5b9b47SHaavard Skinnemoen /* default: not protected */ 18597e5b9b47SHaavard Skinnemoen info->protect[sect_cnt] = 0; 186059829cc1SJean-Christophe PLAGNIOL-VILLARD } 186159829cc1SJean-Christophe PLAGNIOL-VILLARD 186259829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt++; 186359829cc1SJean-Christophe PLAGNIOL-VILLARD } 186459829cc1SJean-Christophe PLAGNIOL-VILLARD } 186559829cc1SJean-Christophe PLAGNIOL-VILLARD 186659829cc1SJean-Christophe PLAGNIOL-VILLARD info->sector_count = sect_cnt; 1867e23741f4SHaavard Skinnemoen info->size = 1 << qry.dev_size; 186859829cc1SJean-Christophe PLAGNIOL-VILLARD /* multiply the size by the number of chips */ 18697e5b9b47SHaavard Skinnemoen info->size *= size_ratio; 1870e23741f4SHaavard Skinnemoen info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size); 1871e23741f4SHaavard Skinnemoen tmp = 1 << qry.block_erase_timeout_typ; 18727e5b9b47SHaavard Skinnemoen info->erase_blk_tout = tmp * 1873e23741f4SHaavard Skinnemoen (1 << qry.block_erase_timeout_max); 1874e23741f4SHaavard Skinnemoen tmp = (1 << qry.buf_write_timeout_typ) * 1875e23741f4SHaavard Skinnemoen (1 << qry.buf_write_timeout_max); 1876e23741f4SHaavard Skinnemoen 18777e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 1878e23741f4SHaavard Skinnemoen info->buffer_write_tout = (tmp + 999) / 1000; 1879e23741f4SHaavard Skinnemoen tmp = (1 << qry.word_write_timeout_typ) * 1880e23741f4SHaavard Skinnemoen (1 << qry.word_write_timeout_max); 18817e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 1882e23741f4SHaavard Skinnemoen info->write_tout = (tmp + 999) / 1000; 188359829cc1SJean-Christophe PLAGNIOL-VILLARD info->flash_id = FLASH_MAN_CFI; 18847e5b9b47SHaavard Skinnemoen if ((info->interface == FLASH_CFI_X8X16) && 18857e5b9b47SHaavard Skinnemoen (info->chipwidth == FLASH_CFI_BY8)) { 18867e5b9b47SHaavard Skinnemoen /* XXX - Need to test on x8/x16 in parallel. */ 18877e5b9b47SHaavard Skinnemoen info->portwidth >>= 1; 188859829cc1SJean-Christophe PLAGNIOL-VILLARD } 188959829cc1SJean-Christophe PLAGNIOL-VILLARD } 189059829cc1SJean-Christophe PLAGNIOL-VILLARD 189159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 189259829cc1SJean-Christophe PLAGNIOL-VILLARD return (info->size); 189359829cc1SJean-Christophe PLAGNIOL-VILLARD } 189459829cc1SJean-Christophe PLAGNIOL-VILLARD 189559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 189659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1897be60a902SHaavard Skinnemoen unsigned long flash_init (void) 189859829cc1SJean-Christophe PLAGNIOL-VILLARD { 1899be60a902SHaavard Skinnemoen unsigned long size = 0; 1900be60a902SHaavard Skinnemoen int i; 1901c63ad632SMatthias Fuchs #if defined(CFG_FLASH_AUTOPROTECT_LIST) 1902c63ad632SMatthias Fuchs struct apl_s { 1903c63ad632SMatthias Fuchs ulong start; 1904c63ad632SMatthias Fuchs ulong size; 1905c63ad632SMatthias Fuchs } apl[] = CFG_FLASH_AUTOPROTECT_LIST; 1906c63ad632SMatthias Fuchs #endif 190759829cc1SJean-Christophe PLAGNIOL-VILLARD 1908be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION 1909be60a902SHaavard Skinnemoen char *s = getenv("unlock"); 191081b20cccSMichael Schwingen #endif 1911be60a902SHaavard Skinnemoen 1912be60a902SHaavard Skinnemoen /* Init: no FLASHes known */ 1913be60a902SHaavard Skinnemoen for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { 1914be60a902SHaavard Skinnemoen flash_info[i].flash_id = FLASH_UNKNOWN; 1915be60a902SHaavard Skinnemoen 1916be60a902SHaavard Skinnemoen if (!flash_detect_legacy (bank_base[i], i)) 1917be60a902SHaavard Skinnemoen flash_get_size (bank_base[i], i); 1918be60a902SHaavard Skinnemoen size += flash_info[i].size; 1919be60a902SHaavard Skinnemoen if (flash_info[i].flash_id == FLASH_UNKNOWN) { 1920be60a902SHaavard Skinnemoen #ifndef CFG_FLASH_QUIET_TEST 1921be60a902SHaavard Skinnemoen printf ("## Unknown FLASH on Bank %d " 1922be60a902SHaavard Skinnemoen "- Size = 0x%08lx = %ld MB\n", 1923be60a902SHaavard Skinnemoen i+1, flash_info[i].size, 1924be60a902SHaavard Skinnemoen flash_info[i].size << 20); 1925be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_QUIET_TEST */ 192659829cc1SJean-Christophe PLAGNIOL-VILLARD } 1927be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION 1928be60a902SHaavard Skinnemoen else if ((s != NULL) && (strcmp(s, "yes") == 0)) { 1929be60a902SHaavard Skinnemoen /* 1930be60a902SHaavard Skinnemoen * Only the U-Boot image and it's environment 1931be60a902SHaavard Skinnemoen * is protected, all other sectors are 1932be60a902SHaavard Skinnemoen * unprotected (unlocked) if flash hardware 1933be60a902SHaavard Skinnemoen * protection is used (CFG_FLASH_PROTECTION) 1934be60a902SHaavard Skinnemoen * and the environment variable "unlock" is 1935be60a902SHaavard Skinnemoen * set to "yes". 1936be60a902SHaavard Skinnemoen */ 1937be60a902SHaavard Skinnemoen if (flash_info[i].legacy_unlock) { 1938be60a902SHaavard Skinnemoen int k; 193959829cc1SJean-Christophe PLAGNIOL-VILLARD 1940be60a902SHaavard Skinnemoen /* 1941be60a902SHaavard Skinnemoen * Disable legacy_unlock temporarily, 1942be60a902SHaavard Skinnemoen * since flash_real_protect would 1943be60a902SHaavard Skinnemoen * relock all other sectors again 1944be60a902SHaavard Skinnemoen * otherwise. 1945be60a902SHaavard Skinnemoen */ 1946be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 0; 194759829cc1SJean-Christophe PLAGNIOL-VILLARD 1948be60a902SHaavard Skinnemoen /* 1949be60a902SHaavard Skinnemoen * Legacy unlocking (e.g. Intel J3) -> 1950be60a902SHaavard Skinnemoen * unlock only one sector. This will 1951be60a902SHaavard Skinnemoen * unlock all sectors. 1952be60a902SHaavard Skinnemoen */ 1953be60a902SHaavard Skinnemoen flash_real_protect (&flash_info[i], 0, 0); 195459829cc1SJean-Christophe PLAGNIOL-VILLARD 1955be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 1; 195659829cc1SJean-Christophe PLAGNIOL-VILLARD 1957be60a902SHaavard Skinnemoen /* 1958be60a902SHaavard Skinnemoen * Manually mark other sectors as 1959be60a902SHaavard Skinnemoen * unlocked (unprotected) 1960be60a902SHaavard Skinnemoen */ 1961be60a902SHaavard Skinnemoen for (k = 1; k < flash_info[i].sector_count; k++) 1962be60a902SHaavard Skinnemoen flash_info[i].protect[k] = 0; 1963be60a902SHaavard Skinnemoen } else { 1964be60a902SHaavard Skinnemoen /* 1965be60a902SHaavard Skinnemoen * No legancy unlocking -> unlock all sectors 1966be60a902SHaavard Skinnemoen */ 1967be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_CLEAR, 1968be60a902SHaavard Skinnemoen flash_info[i].start[0], 1969be60a902SHaavard Skinnemoen flash_info[i].start[0] 1970be60a902SHaavard Skinnemoen + flash_info[i].size - 1, 1971be60a902SHaavard Skinnemoen &flash_info[i]); 197259829cc1SJean-Christophe PLAGNIOL-VILLARD } 197359829cc1SJean-Christophe PLAGNIOL-VILLARD } 1974be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_PROTECTION */ 197559829cc1SJean-Christophe PLAGNIOL-VILLARD } 197659829cc1SJean-Christophe PLAGNIOL-VILLARD 1977be60a902SHaavard Skinnemoen /* Monitor protection ON by default */ 1978be60a902SHaavard Skinnemoen #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 1979be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 1980be60a902SHaavard Skinnemoen CFG_MONITOR_BASE, 1981be60a902SHaavard Skinnemoen CFG_MONITOR_BASE + monitor_flash_len - 1, 1982be60a902SHaavard Skinnemoen flash_get_info(CFG_MONITOR_BASE)); 1983be60a902SHaavard Skinnemoen #endif 198459829cc1SJean-Christophe PLAGNIOL-VILLARD 1985be60a902SHaavard Skinnemoen /* Environment protection ON by default */ 1986be60a902SHaavard Skinnemoen #ifdef CFG_ENV_IS_IN_FLASH 1987be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 1988be60a902SHaavard Skinnemoen CFG_ENV_ADDR, 1989be60a902SHaavard Skinnemoen CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, 1990be60a902SHaavard Skinnemoen flash_get_info(CFG_ENV_ADDR)); 1991be60a902SHaavard Skinnemoen #endif 1992be60a902SHaavard Skinnemoen 1993be60a902SHaavard Skinnemoen /* Redundant environment protection ON by default */ 1994be60a902SHaavard Skinnemoen #ifdef CFG_ENV_ADDR_REDUND 1995be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 1996be60a902SHaavard Skinnemoen CFG_ENV_ADDR_REDUND, 1997be60a902SHaavard Skinnemoen CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1, 1998be60a902SHaavard Skinnemoen flash_get_info(CFG_ENV_ADDR_REDUND)); 1999be60a902SHaavard Skinnemoen #endif 2000c63ad632SMatthias Fuchs 2001c63ad632SMatthias Fuchs #if defined(CFG_FLASH_AUTOPROTECT_LIST) 2002c63ad632SMatthias Fuchs for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) { 2003c63ad632SMatthias Fuchs debug("autoprotecting from %08x to %08x\n", 2004c63ad632SMatthias Fuchs apl[i].start, apl[i].start + apl[i].size - 1); 2005c63ad632SMatthias Fuchs flash_protect (FLAG_PROTECT_SET, 2006c63ad632SMatthias Fuchs apl[i].start, 2007c63ad632SMatthias Fuchs apl[i].start + apl[i].size - 1, 2008c63ad632SMatthias Fuchs flash_get_info(apl[i].start)); 2009c63ad632SMatthias Fuchs } 2010c63ad632SMatthias Fuchs #endif 2011be60a902SHaavard Skinnemoen return (size); 201259829cc1SJean-Christophe PLAGNIOL-VILLARD } 201359829cc1SJean-Christophe PLAGNIOL-VILLARD 201459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_CFI */ 2015