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 4359829cc1SJean-Christophe PLAGNIOL-VILLARD /* 447e5b9b47SHaavard Skinnemoen * This file implements a Common Flash Interface (CFI) driver for 457e5b9b47SHaavard Skinnemoen * U-Boot. 467e5b9b47SHaavard Skinnemoen * 477e5b9b47SHaavard Skinnemoen * The width of the port and the width of the chips are determined at 487e5b9b47SHaavard Skinnemoen * initialization. These widths are used to calculate the address for 497e5b9b47SHaavard Skinnemoen * access CFI data structures. 5059829cc1SJean-Christophe PLAGNIOL-VILLARD * 5159829cc1SJean-Christophe PLAGNIOL-VILLARD * References 5259829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JESD68 - Common Flash Interface (CFI) 5359829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes 5459829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets 5559829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet 5659829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD CFI Specification, Release 2.0 December 1, 2001 5759829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD/Spansion Application Note: Migration from Single-byte to Three-byte 5859829cc1SJean-Christophe PLAGNIOL-VILLARD * Device IDs, Publication Number 25538 Revision A, November 8, 2001 5959829cc1SJean-Christophe PLAGNIOL-VILLARD * 606d0f6bcfSJean-Christophe PLAGNIOL-VILLARD * Define CONFIG_SYS_WRITE_SWAPPED_DATA, if you have to swap the Bytes between 6159829cc1SJean-Christophe PLAGNIOL-VILLARD * reading and writing ... (yes there is such a Hardware). 6259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 6359829cc1SJean-Christophe PLAGNIOL-VILLARD 646d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_BANKS_LIST 656d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_FLASH_BANKS_LIST { CONFIG_SYS_FLASH_BASE } 6659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 6759829cc1SJean-Christophe PLAGNIOL-VILLARD 6859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CFI 0x98 6959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_READ_ID 0x90 7059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_RESET 0xff 7159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_BLOCK_ERASE 0x20 7259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_ERASE_CONFIRM 0xD0 7359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE 0x40 7459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT 0x60 7559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_SET 0x01 7659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_CLEAR 0xD0 7759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CLEAR_STATUS 0x50 789c048b52SVasiliy Leoenenko #define FLASH_CMD_READ_STATUS 0x70 7959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_TO_BUFFER 0xE8 809c048b52SVasiliy Leoenenko #define FLASH_CMD_WRITE_BUFFER_PROG 0xE9 8159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0 8259829cc1SJean-Christophe PLAGNIOL-VILLARD 8359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DONE 0x80 8459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ESS 0x40 8559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ECLBS 0x20 8659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSLBS 0x10 8759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_VPENS 0x08 8859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSS 0x04 8959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DPS 0x02 9059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_R 0x01 9159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PROTECT 0x01 9259829cc1SJean-Christophe PLAGNIOL-VILLARD 9359829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_RESET 0xF0 9459829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE 0xA0 9559829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_START 0x80 9659829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_SECTOR 0x30 9759829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_START 0xAA 9859829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_ACK 0x55 9959829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_TO_BUFFER 0x25 10059829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29 10159829cc1SJean-Christophe PLAGNIOL-VILLARD 10259829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_TOGGLE 0x40 10359829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_ERROR 0x20 10459829cc1SJean-Christophe PLAGNIOL-VILLARD 105bc9019e1SRafael Campos #define ATM_CMD_UNLOCK_SECT 0x70 106bc9019e1SRafael Campos #define ATM_CMD_SOFTLOCK_START 0x80 107bc9019e1SRafael Campos #define ATM_CMD_LOCK_SECT 0x40 108bc9019e1SRafael Campos 10959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_MANUFACTURER_ID 0x00 11059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID 0x01 11159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID2 0x0E 11259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID3 0x0F 11359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI 0x55 11459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_ALT 0x555 11559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_RESP 0x10 11659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PRIMARY_VENDOR 0x13 1177e5b9b47SHaavard Skinnemoen /* extended query table primary address */ 1187e5b9b47SHaavard Skinnemoen #define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15 11959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WTOUT 0x1F 12059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBTOUT 0x20 12159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ETOUT 0x21 12259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CETOUT 0x22 12359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WMAX_TOUT 0x23 12459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBMAX_TOUT 0x24 12559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EMAX_TOUT 0x25 12659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CEMAX_TOUT 0x26 12759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_SIZE 0x27 12859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTERFACE 0x28 12959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_BUFFER_SIZE 0x2A 13059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C 13159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ERASE_REGIONS 0x2D 13259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PROTECT 0x02 13359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_USER_PROTECTION 0x85 13459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTEL_PROTECTION 0x81 13559829cc1SJean-Christophe PLAGNIOL-VILLARD 13659829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_NONE 0 13759829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_EXTENDED 1 13859829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_STANDARD 2 13959829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_STANDARD 3 14059829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_EXTENDED 4 14159829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_STANDARD 256 14259829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_EXTENDED 257 14359829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_SST 258 1449c048b52SVasiliy Leoenenko #define CFI_CMDSET_INTEL_PROG_REGIONS 512 14559829cc1SJean-Christophe PLAGNIOL-VILLARD 1466d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */ 14759829cc1SJean-Christophe PLAGNIOL-VILLARD # undef FLASH_CMD_RESET 14859829cc1SJean-Christophe PLAGNIOL-VILLARD # define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */ 14959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 15059829cc1SJean-Christophe PLAGNIOL-VILLARD 15159829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union { 15259829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned char c; 15359829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned short w; 15459829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long l; 15559829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long long ll; 15659829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiword_t; 15759829cc1SJean-Christophe PLAGNIOL-VILLARD 15859829cc1SJean-Christophe PLAGNIOL-VILLARD #define NUM_ERASE_REGIONS 4 /* max. number of erase regions */ 15959829cc1SJean-Christophe PLAGNIOL-VILLARD 16059829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT }; 1616ea808efSPiotr Ziecik static uint flash_verbose = 1; 16259829cc1SJean-Christophe PLAGNIOL-VILLARD 1636d0f6bcfSJean-Christophe PLAGNIOL-VILLARD /* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */ 1646d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT 1656d0f6bcfSJean-Christophe PLAGNIOL-VILLARD # define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS_DETECT 16659829cc1SJean-Christophe PLAGNIOL-VILLARD #else 1676d0f6bcfSJean-Christophe PLAGNIOL-VILLARD # define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS 16859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 16959829cc1SJean-Christophe PLAGNIOL-VILLARD 1702a112b23SWolfgang Denk flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */ 1712a112b23SWolfgang Denk 17259829cc1SJean-Christophe PLAGNIOL-VILLARD /* 17359829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if chip width is defined. If not, start detecting with 8bit. 17459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1756d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_CFI_WIDTH 1766d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_8BIT 17759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 17859829cc1SJean-Christophe PLAGNIOL-VILLARD 179e23741f4SHaavard Skinnemoen /* CFI standard query structure */ 180e23741f4SHaavard Skinnemoen struct cfi_qry { 181e23741f4SHaavard Skinnemoen u8 qry[3]; 182e23741f4SHaavard Skinnemoen u16 p_id; 183e23741f4SHaavard Skinnemoen u16 p_adr; 184e23741f4SHaavard Skinnemoen u16 a_id; 185e23741f4SHaavard Skinnemoen u16 a_adr; 186e23741f4SHaavard Skinnemoen u8 vcc_min; 187e23741f4SHaavard Skinnemoen u8 vcc_max; 188e23741f4SHaavard Skinnemoen u8 vpp_min; 189e23741f4SHaavard Skinnemoen u8 vpp_max; 190e23741f4SHaavard Skinnemoen u8 word_write_timeout_typ; 191e23741f4SHaavard Skinnemoen u8 buf_write_timeout_typ; 192e23741f4SHaavard Skinnemoen u8 block_erase_timeout_typ; 193e23741f4SHaavard Skinnemoen u8 chip_erase_timeout_typ; 194e23741f4SHaavard Skinnemoen u8 word_write_timeout_max; 195e23741f4SHaavard Skinnemoen u8 buf_write_timeout_max; 196e23741f4SHaavard Skinnemoen u8 block_erase_timeout_max; 197e23741f4SHaavard Skinnemoen u8 chip_erase_timeout_max; 198e23741f4SHaavard Skinnemoen u8 dev_size; 199e23741f4SHaavard Skinnemoen u16 interface_desc; 200e23741f4SHaavard Skinnemoen u16 max_buf_write_size; 201e23741f4SHaavard Skinnemoen u8 num_erase_regions; 202e23741f4SHaavard Skinnemoen u32 erase_region_info[NUM_ERASE_REGIONS]; 203e23741f4SHaavard Skinnemoen } __attribute__((packed)); 204e23741f4SHaavard Skinnemoen 205e23741f4SHaavard Skinnemoen struct cfi_pri_hdr { 206e23741f4SHaavard Skinnemoen u8 pri[3]; 207e23741f4SHaavard Skinnemoen u8 major_version; 208e23741f4SHaavard Skinnemoen u8 minor_version; 209e23741f4SHaavard Skinnemoen } __attribute__((packed)); 210e23741f4SHaavard Skinnemoen 21145aa5a7fSStefan Roese static void __flash_write8(u8 value, void *addr) 212cdbaefb5SHaavard Skinnemoen { 213cdbaefb5SHaavard Skinnemoen __raw_writeb(value, addr); 214cdbaefb5SHaavard Skinnemoen } 215cdbaefb5SHaavard Skinnemoen 21645aa5a7fSStefan Roese static void __flash_write16(u16 value, void *addr) 217cdbaefb5SHaavard Skinnemoen { 218cdbaefb5SHaavard Skinnemoen __raw_writew(value, addr); 219cdbaefb5SHaavard Skinnemoen } 220cdbaefb5SHaavard Skinnemoen 22145aa5a7fSStefan Roese static void __flash_write32(u32 value, void *addr) 222cdbaefb5SHaavard Skinnemoen { 223cdbaefb5SHaavard Skinnemoen __raw_writel(value, addr); 224cdbaefb5SHaavard Skinnemoen } 225cdbaefb5SHaavard Skinnemoen 22645aa5a7fSStefan Roese static void __flash_write64(u64 value, void *addr) 227cdbaefb5SHaavard Skinnemoen { 228cdbaefb5SHaavard Skinnemoen /* No architectures currently implement __raw_writeq() */ 229cdbaefb5SHaavard Skinnemoen *(volatile u64 *)addr = value; 230cdbaefb5SHaavard Skinnemoen } 231cdbaefb5SHaavard Skinnemoen 23245aa5a7fSStefan Roese static u8 __flash_read8(void *addr) 233cdbaefb5SHaavard Skinnemoen { 234cdbaefb5SHaavard Skinnemoen return __raw_readb(addr); 235cdbaefb5SHaavard Skinnemoen } 236cdbaefb5SHaavard Skinnemoen 23745aa5a7fSStefan Roese static u16 __flash_read16(void *addr) 238cdbaefb5SHaavard Skinnemoen { 239cdbaefb5SHaavard Skinnemoen return __raw_readw(addr); 240cdbaefb5SHaavard Skinnemoen } 241cdbaefb5SHaavard Skinnemoen 24245aa5a7fSStefan Roese static u32 __flash_read32(void *addr) 243cdbaefb5SHaavard Skinnemoen { 244cdbaefb5SHaavard Skinnemoen return __raw_readl(addr); 245cdbaefb5SHaavard Skinnemoen } 246cdbaefb5SHaavard Skinnemoen 24797bf85d7SDaniel Hellstrom static u64 __flash_read64(void *addr) 248cdbaefb5SHaavard Skinnemoen { 249cdbaefb5SHaavard Skinnemoen /* No architectures currently implement __raw_readq() */ 250cdbaefb5SHaavard Skinnemoen return *(volatile u64 *)addr; 251cdbaefb5SHaavard Skinnemoen } 252cdbaefb5SHaavard Skinnemoen 25345aa5a7fSStefan Roese #ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS 25445aa5a7fSStefan Roese void flash_write8(u8 value, void *addr)__attribute__((weak, alias("__flash_write8"))); 25545aa5a7fSStefan Roese void flash_write16(u16 value, void *addr)__attribute__((weak, alias("__flash_write16"))); 25645aa5a7fSStefan Roese void flash_write32(u32 value, void *addr)__attribute__((weak, alias("__flash_write32"))); 25745aa5a7fSStefan Roese void flash_write64(u64 value, void *addr)__attribute__((weak, alias("__flash_write64"))); 25845aa5a7fSStefan Roese u8 flash_read8(void *addr)__attribute__((weak, alias("__flash_read8"))); 25945aa5a7fSStefan Roese u16 flash_read16(void *addr)__attribute__((weak, alias("__flash_read16"))); 26045aa5a7fSStefan Roese u32 flash_read32(void *addr)__attribute__((weak, alias("__flash_read32"))); 26197bf85d7SDaniel Hellstrom u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64"))); 26245aa5a7fSStefan Roese #else 26345aa5a7fSStefan Roese #define flash_write8 __flash_write8 26445aa5a7fSStefan Roese #define flash_write16 __flash_write16 26545aa5a7fSStefan Roese #define flash_write32 __flash_write32 26645aa5a7fSStefan Roese #define flash_write64 __flash_write64 26745aa5a7fSStefan Roese #define flash_read8 __flash_read8 26845aa5a7fSStefan Roese #define flash_read16 __flash_read16 26945aa5a7fSStefan Roese #define flash_read32 __flash_read32 27045aa5a7fSStefan Roese #define flash_read64 __flash_read64 27145aa5a7fSStefan Roese #endif 27297bf85d7SDaniel Hellstrom 273be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 274be60a902SHaavard Skinnemoen */ 2756d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE) 276be60a902SHaavard Skinnemoen static flash_info_t *flash_get_info(ulong base) 277be60a902SHaavard Skinnemoen { 278be60a902SHaavard Skinnemoen int i; 279be60a902SHaavard Skinnemoen flash_info_t * info = 0; 280be60a902SHaavard Skinnemoen 2816d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { 282be60a902SHaavard Skinnemoen info = & flash_info[i]; 283be60a902SHaavard Skinnemoen if (info->size && info->start[0] <= base && 284be60a902SHaavard Skinnemoen base <= info->start[0] + info->size - 1) 285be60a902SHaavard Skinnemoen break; 286be60a902SHaavard Skinnemoen } 287be60a902SHaavard Skinnemoen 2886d0f6bcfSJean-Christophe PLAGNIOL-VILLARD return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info; 289be60a902SHaavard Skinnemoen } 29059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 29159829cc1SJean-Christophe PLAGNIOL-VILLARD 29212d30aa7SHaavard Skinnemoen unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect) 29312d30aa7SHaavard Skinnemoen { 29412d30aa7SHaavard Skinnemoen if (sect != (info->sector_count - 1)) 29512d30aa7SHaavard Skinnemoen return info->start[sect + 1] - info->start[sect]; 29612d30aa7SHaavard Skinnemoen else 29712d30aa7SHaavard Skinnemoen return info->start[0] + info->size - info->start[sect]; 29812d30aa7SHaavard Skinnemoen } 29912d30aa7SHaavard Skinnemoen 30059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 30159829cc1SJean-Christophe PLAGNIOL-VILLARD * create an address based on the offset and the port width 30259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 30312d30aa7SHaavard Skinnemoen static inline void * 30412d30aa7SHaavard Skinnemoen flash_map (flash_info_t * info, flash_sect_t sect, uint offset) 30559829cc1SJean-Christophe PLAGNIOL-VILLARD { 30612d30aa7SHaavard Skinnemoen unsigned int byte_offset = offset * info->portwidth; 30712d30aa7SHaavard Skinnemoen 30812d30aa7SHaavard Skinnemoen return map_physmem(info->start[sect] + byte_offset, 30912d30aa7SHaavard Skinnemoen flash_sector_size(info, sect) - byte_offset, 31012d30aa7SHaavard Skinnemoen MAP_NOCACHE); 31112d30aa7SHaavard Skinnemoen } 31212d30aa7SHaavard Skinnemoen 31312d30aa7SHaavard Skinnemoen static inline void flash_unmap(flash_info_t *info, flash_sect_t sect, 31412d30aa7SHaavard Skinnemoen unsigned int offset, void *addr) 31512d30aa7SHaavard Skinnemoen { 31612d30aa7SHaavard Skinnemoen unsigned int byte_offset = offset * info->portwidth; 31712d30aa7SHaavard Skinnemoen 31812d30aa7SHaavard Skinnemoen unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset); 31959829cc1SJean-Christophe PLAGNIOL-VILLARD } 32059829cc1SJean-Christophe PLAGNIOL-VILLARD 321be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 322be60a902SHaavard Skinnemoen * make a proper sized command based on the port and chip widths 323be60a902SHaavard Skinnemoen */ 3247288f972SSebastian Siewior static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf) 325be60a902SHaavard Skinnemoen { 326be60a902SHaavard Skinnemoen int i; 32793c56f21SVasiliy Leoenenko int cword_offset; 32893c56f21SVasiliy Leoenenko int cp_offset; 3296d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 330340ccb26SSebastian Siewior u32 cmd_le = cpu_to_le32(cmd); 331340ccb26SSebastian Siewior #endif 33293c56f21SVasiliy Leoenenko uchar val; 333be60a902SHaavard Skinnemoen uchar *cp = (uchar *) cmdbuf; 334be60a902SHaavard Skinnemoen 33593c56f21SVasiliy Leoenenko for (i = info->portwidth; i > 0; i--){ 33693c56f21SVasiliy Leoenenko cword_offset = (info->portwidth-i)%info->chipwidth; 3376d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 33893c56f21SVasiliy Leoenenko cp_offset = info->portwidth - i; 339340ccb26SSebastian Siewior val = *((uchar*)&cmd_le + cword_offset); 340be60a902SHaavard Skinnemoen #else 34193c56f21SVasiliy Leoenenko cp_offset = i - 1; 3427288f972SSebastian Siewior val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1); 343be60a902SHaavard Skinnemoen #endif 3447288f972SSebastian Siewior cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val; 34593c56f21SVasiliy Leoenenko } 346be60a902SHaavard Skinnemoen } 347be60a902SHaavard Skinnemoen 34859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 34959829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 35059829cc1SJean-Christophe PLAGNIOL-VILLARD * Debug support 35159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3523055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data) 35359829cc1SJean-Christophe PLAGNIOL-VILLARD { 35459829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 35559829cc1SJean-Christophe PLAGNIOL-VILLARD char *cp; 35659829cc1SJean-Christophe PLAGNIOL-VILLARD 35759829cc1SJean-Christophe PLAGNIOL-VILLARD cp = (unsigned char *) &data; 35859829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < 8; i++) 35959829cc1SJean-Christophe PLAGNIOL-VILLARD sprintf (&str[i * 2], "%2.2x", *cp++); 36059829cc1SJean-Christophe PLAGNIOL-VILLARD } 361be60a902SHaavard Skinnemoen 362e23741f4SHaavard Skinnemoen static void flash_printqry (struct cfi_qry *qry) 36359829cc1SJean-Christophe PLAGNIOL-VILLARD { 364e23741f4SHaavard Skinnemoen u8 *p = (u8 *)qry; 36559829cc1SJean-Christophe PLAGNIOL-VILLARD int x, y; 36659829cc1SJean-Christophe PLAGNIOL-VILLARD 367e23741f4SHaavard Skinnemoen for (x = 0; x < sizeof(struct cfi_qry); x += 16) { 368e23741f4SHaavard Skinnemoen debug("%02x : ", x); 369e23741f4SHaavard Skinnemoen for (y = 0; y < 16; y++) 370e23741f4SHaavard Skinnemoen debug("%2.2x ", p[x + y]); 37159829cc1SJean-Christophe PLAGNIOL-VILLARD debug(" "); 37259829cc1SJean-Christophe PLAGNIOL-VILLARD for (y = 0; y < 16; y++) { 373e23741f4SHaavard Skinnemoen unsigned char c = p[x + y]; 374e23741f4SHaavard Skinnemoen if (c >= 0x20 && c <= 0x7e) 375cdbaefb5SHaavard Skinnemoen debug("%c", c); 376e23741f4SHaavard Skinnemoen else 37759829cc1SJean-Christophe PLAGNIOL-VILLARD debug("."); 37859829cc1SJean-Christophe PLAGNIOL-VILLARD } 37959829cc1SJean-Christophe PLAGNIOL-VILLARD debug("\n"); 38059829cc1SJean-Christophe PLAGNIOL-VILLARD } 38159829cc1SJean-Christophe PLAGNIOL-VILLARD } 38259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 38359829cc1SJean-Christophe PLAGNIOL-VILLARD 38459829cc1SJean-Christophe PLAGNIOL-VILLARD 38559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 38659829cc1SJean-Christophe PLAGNIOL-VILLARD * read a character at a port width address 38759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3883055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset) 38959829cc1SJean-Christophe PLAGNIOL-VILLARD { 39059829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *cp; 39112d30aa7SHaavard Skinnemoen uchar retval; 39259829cc1SJean-Christophe PLAGNIOL-VILLARD 39312d30aa7SHaavard Skinnemoen cp = flash_map (info, 0, offset); 3946d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 39512d30aa7SHaavard Skinnemoen retval = flash_read8(cp); 39659829cc1SJean-Christophe PLAGNIOL-VILLARD #else 39712d30aa7SHaavard Skinnemoen retval = flash_read8(cp + info->portwidth - 1); 39859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 39912d30aa7SHaavard Skinnemoen flash_unmap (info, 0, offset, cp); 40012d30aa7SHaavard Skinnemoen return retval; 40159829cc1SJean-Christophe PLAGNIOL-VILLARD } 40259829cc1SJean-Christophe PLAGNIOL-VILLARD 40359829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 40490447ecbSTor Krill * read a word at a port width address, assume 16bit bus 40590447ecbSTor Krill */ 40690447ecbSTor Krill static inline ushort flash_read_word (flash_info_t * info, uint offset) 40790447ecbSTor Krill { 40890447ecbSTor Krill ushort *addr, retval; 40990447ecbSTor Krill 41090447ecbSTor Krill addr = flash_map (info, 0, offset); 41190447ecbSTor Krill retval = flash_read16 (addr); 41290447ecbSTor Krill flash_unmap (info, 0, offset, addr); 41390447ecbSTor Krill return retval; 41490447ecbSTor Krill } 41590447ecbSTor Krill 41690447ecbSTor Krill 41790447ecbSTor Krill /*----------------------------------------------------------------------- 41859829cc1SJean-Christophe PLAGNIOL-VILLARD * read a long word by picking the least significant byte of each maximum 41959829cc1SJean-Christophe PLAGNIOL-VILLARD * port size word. Swap for ppc format. 42059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 4213055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect, 4223055793bSHaavard Skinnemoen uint offset) 42359829cc1SJean-Christophe PLAGNIOL-VILLARD { 42459829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *addr; 42559829cc1SJean-Christophe PLAGNIOL-VILLARD ulong retval; 42659829cc1SJean-Christophe PLAGNIOL-VILLARD 42759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 42859829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 42959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 43012d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 43159829cc1SJean-Christophe PLAGNIOL-VILLARD 43259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 43359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("long addr is at %p info->portwidth = %d\n", addr, 43459829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth); 43559829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 4 * info->portwidth; x++) { 43612d30aa7SHaavard Skinnemoen debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x)); 43759829cc1SJean-Christophe PLAGNIOL-VILLARD } 43859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 4396d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 44012d30aa7SHaavard Skinnemoen retval = ((flash_read8(addr) << 16) | 44112d30aa7SHaavard Skinnemoen (flash_read8(addr + info->portwidth) << 24) | 44212d30aa7SHaavard Skinnemoen (flash_read8(addr + 2 * info->portwidth)) | 44312d30aa7SHaavard Skinnemoen (flash_read8(addr + 3 * info->portwidth) << 8)); 44459829cc1SJean-Christophe PLAGNIOL-VILLARD #else 44512d30aa7SHaavard Skinnemoen retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) | 44612d30aa7SHaavard Skinnemoen (flash_read8(addr + info->portwidth - 1) << 16) | 44712d30aa7SHaavard Skinnemoen (flash_read8(addr + 4 * info->portwidth - 1) << 8) | 44812d30aa7SHaavard Skinnemoen (flash_read8(addr + 3 * info->portwidth - 1))); 44959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 45012d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 45112d30aa7SHaavard Skinnemoen 45259829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 45359829cc1SJean-Christophe PLAGNIOL-VILLARD } 45459829cc1SJean-Christophe PLAGNIOL-VILLARD 455be60a902SHaavard Skinnemoen /* 456be60a902SHaavard Skinnemoen * Write a proper sized command to the correct address 45781b20cccSMichael Schwingen */ 458be60a902SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, 4597288f972SSebastian Siewior uint offset, u32 cmd) 46081b20cccSMichael Schwingen { 4617e5b9b47SHaavard Skinnemoen 462cdbaefb5SHaavard Skinnemoen void *addr; 463be60a902SHaavard Skinnemoen cfiword_t cword; 46481b20cccSMichael Schwingen 46512d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 466be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 467be60a902SHaavard Skinnemoen switch (info->portwidth) { 468be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 469cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd, 470be60a902SHaavard Skinnemoen cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 471cdbaefb5SHaavard Skinnemoen flash_write8(cword.c, addr); 472be60a902SHaavard Skinnemoen break; 473be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 474cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr, 475be60a902SHaavard Skinnemoen cmd, cword.w, 476be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 477cdbaefb5SHaavard Skinnemoen flash_write16(cword.w, addr); 478be60a902SHaavard Skinnemoen break; 479be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 480cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr, 481be60a902SHaavard Skinnemoen cmd, cword.l, 482be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 483cdbaefb5SHaavard Skinnemoen flash_write32(cword.l, addr); 484be60a902SHaavard Skinnemoen break; 485be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 486be60a902SHaavard Skinnemoen #ifdef DEBUG 487be60a902SHaavard Skinnemoen { 488be60a902SHaavard Skinnemoen char str[20]; 489be60a902SHaavard Skinnemoen 490be60a902SHaavard Skinnemoen print_longlong (str, cword.ll); 491be60a902SHaavard Skinnemoen 492be60a902SHaavard Skinnemoen debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n", 493cdbaefb5SHaavard Skinnemoen addr, cmd, str, 494be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 49581b20cccSMichael Schwingen } 496be60a902SHaavard Skinnemoen #endif 497cdbaefb5SHaavard Skinnemoen flash_write64(cword.ll, addr); 49881b20cccSMichael Schwingen break; 49981b20cccSMichael Schwingen } 500be60a902SHaavard Skinnemoen 501be60a902SHaavard Skinnemoen /* Ensure all the instructions are fully finished */ 502be60a902SHaavard Skinnemoen sync(); 50312d30aa7SHaavard Skinnemoen 50412d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 50581b20cccSMichael Schwingen } 5067e5b9b47SHaavard Skinnemoen 507be60a902SHaavard Skinnemoen static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect) 508be60a902SHaavard Skinnemoen { 509be60a902SHaavard Skinnemoen flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START); 510be60a902SHaavard Skinnemoen flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK); 511be60a902SHaavard Skinnemoen } 512be60a902SHaavard Skinnemoen 513be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 514be60a902SHaavard Skinnemoen */ 515be60a902SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect, 516be60a902SHaavard Skinnemoen uint offset, uchar cmd) 517be60a902SHaavard Skinnemoen { 518cdbaefb5SHaavard Skinnemoen void *addr; 519be60a902SHaavard Skinnemoen cfiword_t cword; 520be60a902SHaavard Skinnemoen int retval; 521be60a902SHaavard Skinnemoen 52212d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 523be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 524be60a902SHaavard Skinnemoen 525cdbaefb5SHaavard Skinnemoen debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr); 526be60a902SHaavard Skinnemoen switch (info->portwidth) { 527be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 528cdbaefb5SHaavard Skinnemoen debug ("is= %x %x\n", flash_read8(addr), cword.c); 529cdbaefb5SHaavard Skinnemoen retval = (flash_read8(addr) == cword.c); 530be60a902SHaavard Skinnemoen break; 531be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 532cdbaefb5SHaavard Skinnemoen debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w); 533cdbaefb5SHaavard Skinnemoen retval = (flash_read16(addr) == cword.w); 534be60a902SHaavard Skinnemoen break; 535be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 53652514699SAndrew Klossner debug ("is= %8.8x %8.8lx\n", flash_read32(addr), cword.l); 537cdbaefb5SHaavard Skinnemoen retval = (flash_read32(addr) == cword.l); 538be60a902SHaavard Skinnemoen break; 539be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 540be60a902SHaavard Skinnemoen #ifdef DEBUG 541be60a902SHaavard Skinnemoen { 542be60a902SHaavard Skinnemoen char str1[20]; 543be60a902SHaavard Skinnemoen char str2[20]; 544be60a902SHaavard Skinnemoen 545cdbaefb5SHaavard Skinnemoen print_longlong (str1, flash_read64(addr)); 546be60a902SHaavard Skinnemoen print_longlong (str2, cword.ll); 547be60a902SHaavard Skinnemoen debug ("is= %s %s\n", str1, str2); 548be60a902SHaavard Skinnemoen } 549be60a902SHaavard Skinnemoen #endif 550cdbaefb5SHaavard Skinnemoen retval = (flash_read64(addr) == cword.ll); 551be60a902SHaavard Skinnemoen break; 552be60a902SHaavard Skinnemoen default: 553be60a902SHaavard Skinnemoen retval = 0; 554be60a902SHaavard Skinnemoen break; 555be60a902SHaavard Skinnemoen } 55612d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 55712d30aa7SHaavard Skinnemoen 558be60a902SHaavard Skinnemoen return retval; 559be60a902SHaavard Skinnemoen } 560be60a902SHaavard Skinnemoen 561be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 562be60a902SHaavard Skinnemoen */ 563be60a902SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect, 564be60a902SHaavard Skinnemoen uint offset, uchar cmd) 565be60a902SHaavard Skinnemoen { 566cdbaefb5SHaavard Skinnemoen void *addr; 567be60a902SHaavard Skinnemoen cfiword_t cword; 568be60a902SHaavard Skinnemoen int retval; 569be60a902SHaavard Skinnemoen 57012d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 571be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 572be60a902SHaavard Skinnemoen switch (info->portwidth) { 573be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 574cdbaefb5SHaavard Skinnemoen retval = ((flash_read8(addr) & cword.c) == cword.c); 575be60a902SHaavard Skinnemoen break; 576be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 577cdbaefb5SHaavard Skinnemoen retval = ((flash_read16(addr) & cword.w) == cword.w); 578be60a902SHaavard Skinnemoen break; 579be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 58047cc23cbSStefan Roese retval = ((flash_read32(addr) & cword.l) == cword.l); 581be60a902SHaavard Skinnemoen break; 582be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 583cdbaefb5SHaavard Skinnemoen retval = ((flash_read64(addr) & cword.ll) == cword.ll); 584be60a902SHaavard Skinnemoen break; 585be60a902SHaavard Skinnemoen default: 586be60a902SHaavard Skinnemoen retval = 0; 587be60a902SHaavard Skinnemoen break; 588be60a902SHaavard Skinnemoen } 58912d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 59012d30aa7SHaavard Skinnemoen 591be60a902SHaavard Skinnemoen return retval; 592be60a902SHaavard Skinnemoen } 593be60a902SHaavard Skinnemoen 594be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 595be60a902SHaavard Skinnemoen */ 596be60a902SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect, 597be60a902SHaavard Skinnemoen uint offset, uchar cmd) 598be60a902SHaavard Skinnemoen { 599cdbaefb5SHaavard Skinnemoen void *addr; 600be60a902SHaavard Skinnemoen cfiword_t cword; 601be60a902SHaavard Skinnemoen int retval; 602be60a902SHaavard Skinnemoen 60312d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 604be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 605be60a902SHaavard Skinnemoen switch (info->portwidth) { 606be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 607fb8c061eSStefan Roese retval = flash_read8(addr) != flash_read8(addr); 608be60a902SHaavard Skinnemoen break; 609be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 610fb8c061eSStefan Roese retval = flash_read16(addr) != flash_read16(addr); 611be60a902SHaavard Skinnemoen break; 612be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 613fb8c061eSStefan Roese retval = flash_read32(addr) != flash_read32(addr); 614be60a902SHaavard Skinnemoen break; 615be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 6169abda6baSWolfgang Denk retval = ( (flash_read32( addr ) != flash_read32( addr )) || 6179abda6baSWolfgang Denk (flash_read32(addr+4) != flash_read32(addr+4)) ); 618be60a902SHaavard Skinnemoen break; 619be60a902SHaavard Skinnemoen default: 620be60a902SHaavard Skinnemoen retval = 0; 621be60a902SHaavard Skinnemoen break; 622be60a902SHaavard Skinnemoen } 62312d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 62412d30aa7SHaavard Skinnemoen 625be60a902SHaavard Skinnemoen return retval; 626be60a902SHaavard Skinnemoen } 627be60a902SHaavard Skinnemoen 628be60a902SHaavard Skinnemoen /* 629be60a902SHaavard Skinnemoen * flash_is_busy - check to see if the flash is busy 630be60a902SHaavard Skinnemoen * 631be60a902SHaavard Skinnemoen * This routine checks the status of the chip and returns true if the 632be60a902SHaavard Skinnemoen * chip is busy. 633be60a902SHaavard Skinnemoen */ 634be60a902SHaavard Skinnemoen static int flash_is_busy (flash_info_t * info, flash_sect_t sect) 635be60a902SHaavard Skinnemoen { 636be60a902SHaavard Skinnemoen int retval; 637be60a902SHaavard Skinnemoen 63881b20cccSMichael Schwingen switch (info->vendor) { 6399c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 64081b20cccSMichael Schwingen case CFI_CMDSET_INTEL_STANDARD: 64181b20cccSMichael Schwingen case CFI_CMDSET_INTEL_EXTENDED: 642be60a902SHaavard Skinnemoen retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); 64381b20cccSMichael Schwingen break; 64481b20cccSMichael Schwingen case CFI_CMDSET_AMD_STANDARD: 64581b20cccSMichael Schwingen case CFI_CMDSET_AMD_EXTENDED: 646be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 64781b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 648be60a902SHaavard Skinnemoen #endif 649be60a902SHaavard Skinnemoen retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); 650be60a902SHaavard Skinnemoen break; 651be60a902SHaavard Skinnemoen default: 652be60a902SHaavard Skinnemoen retval = 0; 653be60a902SHaavard Skinnemoen } 654be60a902SHaavard Skinnemoen debug ("flash_is_busy: %d\n", retval); 655be60a902SHaavard Skinnemoen return retval; 656be60a902SHaavard Skinnemoen } 657be60a902SHaavard Skinnemoen 658be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 659be60a902SHaavard Skinnemoen * wait for XSR.7 to be set. Time out with an error if it does not. 660be60a902SHaavard Skinnemoen * This routine does not set the flash to read-array mode. 661be60a902SHaavard Skinnemoen */ 662be60a902SHaavard Skinnemoen static int flash_status_check (flash_info_t * info, flash_sect_t sector, 663be60a902SHaavard Skinnemoen ulong tout, char *prompt) 664be60a902SHaavard Skinnemoen { 665be60a902SHaavard Skinnemoen ulong start; 666be60a902SHaavard Skinnemoen 6676d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if CONFIG_SYS_HZ != 1000 6686d0f6bcfSJean-Christophe PLAGNIOL-VILLARD tout *= CONFIG_SYS_HZ/1000; 669be60a902SHaavard Skinnemoen #endif 670be60a902SHaavard Skinnemoen 671be60a902SHaavard Skinnemoen /* Wait for command completion */ 672be60a902SHaavard Skinnemoen start = get_timer (0); 673be60a902SHaavard Skinnemoen while (flash_is_busy (info, sector)) { 674be60a902SHaavard Skinnemoen if (get_timer (start) > tout) { 675be60a902SHaavard Skinnemoen printf ("Flash %s timeout at address %lx data %lx\n", 676be60a902SHaavard Skinnemoen prompt, info->start[sector], 677be60a902SHaavard Skinnemoen flash_read_long (info, sector, 0)); 678be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, info->cmd_reset); 679be60a902SHaavard Skinnemoen return ERR_TIMOUT; 680be60a902SHaavard Skinnemoen } 681be60a902SHaavard Skinnemoen udelay (1); /* also triggers watchdog */ 682be60a902SHaavard Skinnemoen } 683be60a902SHaavard Skinnemoen return ERR_OK; 684be60a902SHaavard Skinnemoen } 685be60a902SHaavard Skinnemoen 686be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 687be60a902SHaavard Skinnemoen * Wait for XSR.7 to be set, if it times out print an error, otherwise 688be60a902SHaavard Skinnemoen * do a full status check. 689be60a902SHaavard Skinnemoen * 690be60a902SHaavard Skinnemoen * This routine sets the flash to read-array mode. 691be60a902SHaavard Skinnemoen */ 692be60a902SHaavard Skinnemoen static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, 693be60a902SHaavard Skinnemoen ulong tout, char *prompt) 694be60a902SHaavard Skinnemoen { 695be60a902SHaavard Skinnemoen int retcode; 696be60a902SHaavard Skinnemoen 697be60a902SHaavard Skinnemoen retcode = flash_status_check (info, sector, tout, prompt); 698be60a902SHaavard Skinnemoen switch (info->vendor) { 6999c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 700be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 701be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 7020d01f66dSEd Swarthout if ((retcode != ERR_OK) 703be60a902SHaavard Skinnemoen && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { 704be60a902SHaavard Skinnemoen retcode = ERR_INVAL; 705be60a902SHaavard Skinnemoen printf ("Flash %s error at address %lx\n", prompt, 706be60a902SHaavard Skinnemoen info->start[sector]); 707be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | 708be60a902SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 709be60a902SHaavard Skinnemoen puts ("Command Sequence Error.\n"); 710be60a902SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 711be60a902SHaavard Skinnemoen FLASH_STATUS_ECLBS)) { 712be60a902SHaavard Skinnemoen puts ("Block Erase Error.\n"); 713be60a902SHaavard Skinnemoen retcode = ERR_NOT_ERASED; 714be60a902SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 715be60a902SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 716be60a902SHaavard Skinnemoen puts ("Locking Error\n"); 717be60a902SHaavard Skinnemoen } 718be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { 719be60a902SHaavard Skinnemoen puts ("Block locked.\n"); 720be60a902SHaavard Skinnemoen retcode = ERR_PROTECTED; 721be60a902SHaavard Skinnemoen } 722be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) 723be60a902SHaavard Skinnemoen puts ("Vpp Low Error.\n"); 724be60a902SHaavard Skinnemoen } 725be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, info->cmd_reset); 726be60a902SHaavard Skinnemoen break; 727be60a902SHaavard Skinnemoen default: 72881b20cccSMichael Schwingen break; 72981b20cccSMichael Schwingen } 730be60a902SHaavard Skinnemoen return retcode; 73181b20cccSMichael Schwingen } 732be60a902SHaavard Skinnemoen 733be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 734be60a902SHaavard Skinnemoen */ 735be60a902SHaavard Skinnemoen static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) 736be60a902SHaavard Skinnemoen { 7376d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 738be60a902SHaavard Skinnemoen unsigned short w; 739be60a902SHaavard Skinnemoen unsigned int l; 740be60a902SHaavard Skinnemoen unsigned long long ll; 741be60a902SHaavard Skinnemoen #endif 742be60a902SHaavard Skinnemoen 743be60a902SHaavard Skinnemoen switch (info->portwidth) { 744be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 745be60a902SHaavard Skinnemoen cword->c = c; 746be60a902SHaavard Skinnemoen break; 747be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 7486d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 749be60a902SHaavard Skinnemoen w = c; 750be60a902SHaavard Skinnemoen w <<= 8; 751be60a902SHaavard Skinnemoen cword->w = (cword->w >> 8) | w; 75281b20cccSMichael Schwingen #else 753be60a902SHaavard Skinnemoen cword->w = (cword->w << 8) | c; 754be60a902SHaavard Skinnemoen #endif 755be60a902SHaavard Skinnemoen break; 756be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 7576d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 758be60a902SHaavard Skinnemoen l = c; 759be60a902SHaavard Skinnemoen l <<= 24; 760be60a902SHaavard Skinnemoen cword->l = (cword->l >> 8) | l; 761be60a902SHaavard Skinnemoen #else 762be60a902SHaavard Skinnemoen cword->l = (cword->l << 8) | c; 763be60a902SHaavard Skinnemoen #endif 764be60a902SHaavard Skinnemoen break; 765be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 7666d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 767be60a902SHaavard Skinnemoen ll = c; 768be60a902SHaavard Skinnemoen ll <<= 56; 769be60a902SHaavard Skinnemoen cword->ll = (cword->ll >> 8) | ll; 770be60a902SHaavard Skinnemoen #else 771be60a902SHaavard Skinnemoen cword->ll = (cword->ll << 8) | c; 772be60a902SHaavard Skinnemoen #endif 773be60a902SHaavard Skinnemoen break; 774be60a902SHaavard Skinnemoen } 775be60a902SHaavard Skinnemoen } 776be60a902SHaavard Skinnemoen 777be60a902SHaavard Skinnemoen /* loop through the sectors from the highest address when the passed 778be60a902SHaavard Skinnemoen * address is greater or equal to the sector address we have a match 779be60a902SHaavard Skinnemoen */ 780be60a902SHaavard Skinnemoen static flash_sect_t find_sector (flash_info_t * info, ulong addr) 78181b20cccSMichael Schwingen { 782be60a902SHaavard Skinnemoen flash_sect_t sector; 783be60a902SHaavard Skinnemoen 784be60a902SHaavard Skinnemoen for (sector = info->sector_count - 1; sector >= 0; sector--) { 785be60a902SHaavard Skinnemoen if (addr >= info->start[sector]) 786be60a902SHaavard Skinnemoen break; 78781b20cccSMichael Schwingen } 788be60a902SHaavard Skinnemoen return sector; 78959829cc1SJean-Christophe PLAGNIOL-VILLARD } 79059829cc1SJean-Christophe PLAGNIOL-VILLARD 79159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 79259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 793be60a902SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest, 794be60a902SHaavard Skinnemoen cfiword_t cword) 79559829cc1SJean-Christophe PLAGNIOL-VILLARD { 796cdbaefb5SHaavard Skinnemoen void *dstaddr; 797be60a902SHaavard Skinnemoen int flag; 798*a7292871SJens Gehrlein flash_sect_t sect = 0; 799*a7292871SJens Gehrlein char sect_found = 0; 80059829cc1SJean-Christophe PLAGNIOL-VILLARD 80112d30aa7SHaavard Skinnemoen dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE); 802be60a902SHaavard Skinnemoen 803be60a902SHaavard Skinnemoen /* Check if Flash is (sufficiently) erased */ 804be60a902SHaavard Skinnemoen switch (info->portwidth) { 805be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 806cdbaefb5SHaavard Skinnemoen flag = ((flash_read8(dstaddr) & cword.c) == cword.c); 807be60a902SHaavard Skinnemoen break; 808be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 809cdbaefb5SHaavard Skinnemoen flag = ((flash_read16(dstaddr) & cword.w) == cword.w); 810be60a902SHaavard Skinnemoen break; 811be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 812cdbaefb5SHaavard Skinnemoen flag = ((flash_read32(dstaddr) & cword.l) == cword.l); 813be60a902SHaavard Skinnemoen break; 814be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 815cdbaefb5SHaavard Skinnemoen flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll); 816be60a902SHaavard Skinnemoen break; 817be60a902SHaavard Skinnemoen default: 81812d30aa7SHaavard Skinnemoen flag = 0; 81912d30aa7SHaavard Skinnemoen break; 82012d30aa7SHaavard Skinnemoen } 82112d30aa7SHaavard Skinnemoen if (!flag) { 82212d30aa7SHaavard Skinnemoen unmap_physmem(dstaddr, info->portwidth); 8230dc80e27SStefan Roese return ERR_NOT_ERASED; 824be60a902SHaavard Skinnemoen } 825be60a902SHaavard Skinnemoen 826be60a902SHaavard Skinnemoen /* Disable interrupts which might cause a timeout here */ 827be60a902SHaavard Skinnemoen flag = disable_interrupts (); 828be60a902SHaavard Skinnemoen 829be60a902SHaavard Skinnemoen switch (info->vendor) { 8309c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 831be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 832be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 833be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); 834be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE); 835be60a902SHaavard Skinnemoen break; 836be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 837be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 838be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 839be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_LEGACY: 840be60a902SHaavard Skinnemoen #endif 8410d01f66dSEd Swarthout sect = find_sector(info, dest); 8420d01f66dSEd Swarthout flash_unlock_seq (info, sect); 8430d01f66dSEd Swarthout flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE); 844*a7292871SJens Gehrlein sect_found = 1; 84559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 84659829cc1SJean-Christophe PLAGNIOL-VILLARD } 84759829cc1SJean-Christophe PLAGNIOL-VILLARD 848be60a902SHaavard Skinnemoen switch (info->portwidth) { 849be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 850cdbaefb5SHaavard Skinnemoen flash_write8(cword.c, dstaddr); 851be60a902SHaavard Skinnemoen break; 852be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 853cdbaefb5SHaavard Skinnemoen flash_write16(cword.w, dstaddr); 854be60a902SHaavard Skinnemoen break; 855be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 856cdbaefb5SHaavard Skinnemoen flash_write32(cword.l, dstaddr); 857be60a902SHaavard Skinnemoen break; 858be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 859cdbaefb5SHaavard Skinnemoen flash_write64(cword.ll, dstaddr); 860be60a902SHaavard Skinnemoen break; 86159829cc1SJean-Christophe PLAGNIOL-VILLARD } 862be60a902SHaavard Skinnemoen 863be60a902SHaavard Skinnemoen /* re-enable interrupts if necessary */ 864be60a902SHaavard Skinnemoen if (flag) 865be60a902SHaavard Skinnemoen enable_interrupts (); 866be60a902SHaavard Skinnemoen 86712d30aa7SHaavard Skinnemoen unmap_physmem(dstaddr, info->portwidth); 86812d30aa7SHaavard Skinnemoen 869*a7292871SJens Gehrlein if (!sect_found) 870*a7292871SJens Gehrlein sect = find_sector (info, dest); 871*a7292871SJens Gehrlein 872*a7292871SJens Gehrlein return flash_full_status_check (info, sect, info->write_tout, "write"); 873be60a902SHaavard Skinnemoen } 874be60a902SHaavard Skinnemoen 8756d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE 876be60a902SHaavard Skinnemoen 877be60a902SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, 878be60a902SHaavard Skinnemoen int len) 879be60a902SHaavard Skinnemoen { 880be60a902SHaavard Skinnemoen flash_sect_t sector; 881be60a902SHaavard Skinnemoen int cnt; 882be60a902SHaavard Skinnemoen int retcode; 883cdbaefb5SHaavard Skinnemoen void *src = cp; 88412d30aa7SHaavard Skinnemoen void *dst = map_physmem(dest, len, MAP_NOCACHE); 8850dc80e27SStefan Roese void *dst2 = dst; 8860dc80e27SStefan Roese int flag = 0; 88796ef831fSGuennadi Liakhovetski uint offset = 0; 88896ef831fSGuennadi Liakhovetski unsigned int shift; 8899c048b52SVasiliy Leoenenko uchar write_cmd; 890cdbaefb5SHaavard Skinnemoen 8910dc80e27SStefan Roese switch (info->portwidth) { 8920dc80e27SStefan Roese case FLASH_CFI_8BIT: 89396ef831fSGuennadi Liakhovetski shift = 0; 8940dc80e27SStefan Roese break; 8950dc80e27SStefan Roese case FLASH_CFI_16BIT: 89696ef831fSGuennadi Liakhovetski shift = 1; 8970dc80e27SStefan Roese break; 8980dc80e27SStefan Roese case FLASH_CFI_32BIT: 89996ef831fSGuennadi Liakhovetski shift = 2; 9000dc80e27SStefan Roese break; 9010dc80e27SStefan Roese case FLASH_CFI_64BIT: 90296ef831fSGuennadi Liakhovetski shift = 3; 9030dc80e27SStefan Roese break; 9040dc80e27SStefan Roese default: 9050dc80e27SStefan Roese retcode = ERR_INVAL; 9060dc80e27SStefan Roese goto out_unmap; 9070dc80e27SStefan Roese } 9080dc80e27SStefan Roese 90996ef831fSGuennadi Liakhovetski cnt = len >> shift; 91096ef831fSGuennadi Liakhovetski 9110dc80e27SStefan Roese while ((cnt-- > 0) && (flag == 0)) { 9120dc80e27SStefan Roese switch (info->portwidth) { 9130dc80e27SStefan Roese case FLASH_CFI_8BIT: 9140dc80e27SStefan Roese flag = ((flash_read8(dst2) & flash_read8(src)) == 9150dc80e27SStefan Roese flash_read8(src)); 9160dc80e27SStefan Roese src += 1, dst2 += 1; 9170dc80e27SStefan Roese break; 9180dc80e27SStefan Roese case FLASH_CFI_16BIT: 9190dc80e27SStefan Roese flag = ((flash_read16(dst2) & flash_read16(src)) == 9200dc80e27SStefan Roese flash_read16(src)); 9210dc80e27SStefan Roese src += 2, dst2 += 2; 9220dc80e27SStefan Roese break; 9230dc80e27SStefan Roese case FLASH_CFI_32BIT: 9240dc80e27SStefan Roese flag = ((flash_read32(dst2) & flash_read32(src)) == 9250dc80e27SStefan Roese flash_read32(src)); 9260dc80e27SStefan Roese src += 4, dst2 += 4; 9270dc80e27SStefan Roese break; 9280dc80e27SStefan Roese case FLASH_CFI_64BIT: 9290dc80e27SStefan Roese flag = ((flash_read64(dst2) & flash_read64(src)) == 9300dc80e27SStefan Roese flash_read64(src)); 9310dc80e27SStefan Roese src += 8, dst2 += 8; 9320dc80e27SStefan Roese break; 9330dc80e27SStefan Roese } 9340dc80e27SStefan Roese } 9350dc80e27SStefan Roese if (!flag) { 9360dc80e27SStefan Roese retcode = ERR_NOT_ERASED; 9370dc80e27SStefan Roese goto out_unmap; 9380dc80e27SStefan Roese } 9390dc80e27SStefan Roese 9400dc80e27SStefan Roese src = cp; 941cdbaefb5SHaavard Skinnemoen sector = find_sector (info, dest); 942be60a902SHaavard Skinnemoen 943be60a902SHaavard Skinnemoen switch (info->vendor) { 9449c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 945be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 946be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 9479c048b52SVasiliy Leoenenko write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ? 9489c048b52SVasiliy Leoenenko FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER; 949be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 9509c048b52SVasiliy Leoenenko flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS); 9519c048b52SVasiliy Leoenenko flash_write_cmd (info, sector, 0, write_cmd); 952be60a902SHaavard Skinnemoen retcode = flash_status_check (info, sector, 953be60a902SHaavard Skinnemoen info->buffer_write_tout, 954be60a902SHaavard Skinnemoen "write to buffer"); 955be60a902SHaavard Skinnemoen if (retcode == ERR_OK) { 956be60a902SHaavard Skinnemoen /* reduce the number of loops by the width of 957be60a902SHaavard Skinnemoen * the port */ 95896ef831fSGuennadi Liakhovetski cnt = len >> shift; 95993c56f21SVasiliy Leoenenko flash_write_cmd (info, sector, 0, cnt - 1); 960be60a902SHaavard Skinnemoen while (cnt-- > 0) { 961be60a902SHaavard Skinnemoen switch (info->portwidth) { 962be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 963cdbaefb5SHaavard Skinnemoen flash_write8(flash_read8(src), dst); 964cdbaefb5SHaavard Skinnemoen src += 1, dst += 1; 965be60a902SHaavard Skinnemoen break; 966be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 967cdbaefb5SHaavard Skinnemoen flash_write16(flash_read16(src), dst); 968cdbaefb5SHaavard Skinnemoen src += 2, dst += 2; 969be60a902SHaavard Skinnemoen break; 970be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 971cdbaefb5SHaavard Skinnemoen flash_write32(flash_read32(src), dst); 972cdbaefb5SHaavard Skinnemoen src += 4, dst += 4; 973be60a902SHaavard Skinnemoen break; 974be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 975cdbaefb5SHaavard Skinnemoen flash_write64(flash_read64(src), dst); 976cdbaefb5SHaavard Skinnemoen src += 8, dst += 8; 977be60a902SHaavard Skinnemoen break; 978be60a902SHaavard Skinnemoen default: 97912d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 98012d30aa7SHaavard Skinnemoen goto out_unmap; 981be60a902SHaavard Skinnemoen } 982be60a902SHaavard Skinnemoen } 983be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, 984be60a902SHaavard Skinnemoen FLASH_CMD_WRITE_BUFFER_CONFIRM); 985be60a902SHaavard Skinnemoen retcode = flash_full_status_check ( 986be60a902SHaavard Skinnemoen info, sector, info->buffer_write_tout, 987be60a902SHaavard Skinnemoen "buffer write"); 988be60a902SHaavard Skinnemoen } 98912d30aa7SHaavard Skinnemoen 99012d30aa7SHaavard Skinnemoen break; 991be60a902SHaavard Skinnemoen 992be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 993be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 994be60a902SHaavard Skinnemoen flash_unlock_seq(info,0); 99596ef831fSGuennadi Liakhovetski 99696ef831fSGuennadi Liakhovetski #ifdef CONFIG_FLASH_SPANSION_S29WS_N 99796ef831fSGuennadi Liakhovetski offset = ((unsigned long)dst - info->start[sector]) >> shift; 99896ef831fSGuennadi Liakhovetski #endif 99996ef831fSGuennadi Liakhovetski flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER); 100096ef831fSGuennadi Liakhovetski cnt = len >> shift; 100196ef831fSGuennadi Liakhovetski flash_write_cmd(info, sector, offset, (uchar)cnt - 1); 1002be60a902SHaavard Skinnemoen 1003be60a902SHaavard Skinnemoen switch (info->portwidth) { 1004be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 1005cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 1006cdbaefb5SHaavard Skinnemoen flash_write8(flash_read8(src), dst); 1007cdbaefb5SHaavard Skinnemoen src += 1, dst += 1; 1008cdbaefb5SHaavard Skinnemoen } 1009be60a902SHaavard Skinnemoen break; 1010be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 1011cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 1012cdbaefb5SHaavard Skinnemoen flash_write16(flash_read16(src), dst); 1013cdbaefb5SHaavard Skinnemoen src += 2, dst += 2; 1014cdbaefb5SHaavard Skinnemoen } 1015be60a902SHaavard Skinnemoen break; 1016be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 1017cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 1018cdbaefb5SHaavard Skinnemoen flash_write32(flash_read32(src), dst); 1019cdbaefb5SHaavard Skinnemoen src += 4, dst += 4; 1020cdbaefb5SHaavard Skinnemoen } 1021be60a902SHaavard Skinnemoen break; 1022be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 1023cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 1024cdbaefb5SHaavard Skinnemoen flash_write64(flash_read64(src), dst); 1025cdbaefb5SHaavard Skinnemoen src += 8, dst += 8; 1026cdbaefb5SHaavard Skinnemoen } 1027be60a902SHaavard Skinnemoen break; 1028be60a902SHaavard Skinnemoen default: 102912d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 103012d30aa7SHaavard Skinnemoen goto out_unmap; 1031be60a902SHaavard Skinnemoen } 1032be60a902SHaavard Skinnemoen 1033be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); 1034be60a902SHaavard Skinnemoen retcode = flash_full_status_check (info, sector, 1035be60a902SHaavard Skinnemoen info->buffer_write_tout, 1036be60a902SHaavard Skinnemoen "buffer write"); 103712d30aa7SHaavard Skinnemoen break; 1038be60a902SHaavard Skinnemoen 1039be60a902SHaavard Skinnemoen default: 1040be60a902SHaavard Skinnemoen debug ("Unknown Command Set\n"); 104112d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 104212d30aa7SHaavard Skinnemoen break; 1043be60a902SHaavard Skinnemoen } 104412d30aa7SHaavard Skinnemoen 104512d30aa7SHaavard Skinnemoen out_unmap: 104612d30aa7SHaavard Skinnemoen unmap_physmem(dst, len); 104712d30aa7SHaavard Skinnemoen return retcode; 1048be60a902SHaavard Skinnemoen } 10496d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */ 1050be60a902SHaavard Skinnemoen 105159829cc1SJean-Christophe PLAGNIOL-VILLARD 105259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 105359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 105459829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last) 105559829cc1SJean-Christophe PLAGNIOL-VILLARD { 105659829cc1SJean-Christophe PLAGNIOL-VILLARD int rcode = 0; 105759829cc1SJean-Christophe PLAGNIOL-VILLARD int prot; 105859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect; 105959829cc1SJean-Christophe PLAGNIOL-VILLARD 106059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 106159829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Can't erase unknown flash type - aborted\n"); 106259829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 106359829cc1SJean-Christophe PLAGNIOL-VILLARD } 106459829cc1SJean-Christophe PLAGNIOL-VILLARD if ((s_first < 0) || (s_first > s_last)) { 106559829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("- no sectors to erase\n"); 106659829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 106759829cc1SJean-Christophe PLAGNIOL-VILLARD } 106859829cc1SJean-Christophe PLAGNIOL-VILLARD 106959829cc1SJean-Christophe PLAGNIOL-VILLARD prot = 0; 107059829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; ++sect) { 107159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect]) { 107259829cc1SJean-Christophe PLAGNIOL-VILLARD prot++; 107359829cc1SJean-Christophe PLAGNIOL-VILLARD } 107459829cc1SJean-Christophe PLAGNIOL-VILLARD } 107559829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) { 10767e5b9b47SHaavard Skinnemoen printf ("- Warning: %d protected sectors will not be erased!\n", 10777e5b9b47SHaavard Skinnemoen prot); 10786ea808efSPiotr Ziecik } else if (flash_verbose) { 107959829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 108059829cc1SJean-Christophe PLAGNIOL-VILLARD } 108159829cc1SJean-Christophe PLAGNIOL-VILLARD 108259829cc1SJean-Christophe PLAGNIOL-VILLARD 108359829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; sect++) { 108459829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect] == 0) { /* not protected */ 108559829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 10869c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 108759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 108859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 10897e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10907e5b9b47SHaavard Skinnemoen FLASH_CMD_CLEAR_STATUS); 10917e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10927e5b9b47SHaavard Skinnemoen FLASH_CMD_BLOCK_ERASE); 10937e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10947e5b9b47SHaavard Skinnemoen FLASH_CMD_ERASE_CONFIRM); 109559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 109659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 109759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 109859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 10997e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 11007e5b9b47SHaavard Skinnemoen info->addr_unlock1, 11017e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 110259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 11037e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 11047e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_SECTOR); 110559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 110681b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 110781b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 110881b20cccSMichael Schwingen flash_unlock_seq (info, 0); 11097e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, info->addr_unlock1, 11107e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 111181b20cccSMichael Schwingen flash_unlock_seq (info, 0); 11127e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 11137e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_SECTOR); 111481b20cccSMichael Schwingen break; 111581b20cccSMichael Schwingen #endif 111659829cc1SJean-Christophe PLAGNIOL-VILLARD default: 111759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("Unkown flash vendor %d\n", 111859829cc1SJean-Christophe PLAGNIOL-VILLARD info->vendor); 111959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 112059829cc1SJean-Christophe PLAGNIOL-VILLARD } 112159829cc1SJean-Christophe PLAGNIOL-VILLARD 112259829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_full_status_check 112359829cc1SJean-Christophe PLAGNIOL-VILLARD (info, sect, info->erase_blk_tout, "erase")) { 112459829cc1SJean-Christophe PLAGNIOL-VILLARD rcode = 1; 11256ea808efSPiotr Ziecik } else if (flash_verbose) 112659829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('.'); 112759829cc1SJean-Christophe PLAGNIOL-VILLARD } 112859829cc1SJean-Christophe PLAGNIOL-VILLARD } 11296ea808efSPiotr Ziecik 11306ea808efSPiotr Ziecik if (flash_verbose) 113159829cc1SJean-Christophe PLAGNIOL-VILLARD puts (" done\n"); 11326ea808efSPiotr Ziecik 113359829cc1SJean-Christophe PLAGNIOL-VILLARD return rcode; 113459829cc1SJean-Christophe PLAGNIOL-VILLARD } 113559829cc1SJean-Christophe PLAGNIOL-VILLARD 113659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 113759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 113859829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info) 113959829cc1SJean-Christophe PLAGNIOL-VILLARD { 114059829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 114159829cc1SJean-Christophe PLAGNIOL-VILLARD 114259829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 114359829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("missing or unknown FLASH type\n"); 114459829cc1SJean-Christophe PLAGNIOL-VILLARD return; 114559829cc1SJean-Christophe PLAGNIOL-VILLARD } 114659829cc1SJean-Christophe PLAGNIOL-VILLARD 114781b20cccSMichael Schwingen printf ("%s FLASH (%d x %d)", 114881b20cccSMichael Schwingen info->name, 114959829cc1SJean-Christophe PLAGNIOL-VILLARD (info->portwidth << 3), (info->chipwidth << 3)); 115081b20cccSMichael Schwingen if (info->size < 1024*1024) 115181b20cccSMichael Schwingen printf (" Size: %ld kB in %d Sectors\n", 115281b20cccSMichael Schwingen info->size >> 10, info->sector_count); 115381b20cccSMichael Schwingen else 115459829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" Size: %ld MB in %d Sectors\n", 115559829cc1SJean-Christophe PLAGNIOL-VILLARD info->size >> 20, info->sector_count); 115659829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" "); 115759829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 11589c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 11599c048b52SVasiliy Leoenenko printf ("Intel Prog Regions"); 11609c048b52SVasiliy Leoenenko break; 116159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 116259829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Standard"); 116359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 116459829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 116559829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Extended"); 116659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 116759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 116859829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Standard"); 116959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 117059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 117159829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Extended"); 117259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 117381b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 117481b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 117581b20cccSMichael Schwingen printf ("AMD Legacy"); 117681b20cccSMichael Schwingen break; 117781b20cccSMichael Schwingen #endif 117859829cc1SJean-Christophe PLAGNIOL-VILLARD default: 117959829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Unknown (%d)", info->vendor); 118059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 118159829cc1SJean-Christophe PLAGNIOL-VILLARD } 118259829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X", 118359829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id, info->device_id); 118459829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 118559829cc1SJean-Christophe PLAGNIOL-VILLARD printf("%04X", info->device_id2); 118659829cc1SJean-Christophe PLAGNIOL-VILLARD } 118759829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n", 118859829cc1SJean-Christophe PLAGNIOL-VILLARD info->erase_blk_tout, 118959829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout); 119059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size > 1) { 11917e5b9b47SHaavard Skinnemoen printf (" Buffer write timeout: %ld ms, " 11927e5b9b47SHaavard Skinnemoen "buffer size: %d bytes\n", 119359829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout, 119459829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_size); 119559829cc1SJean-Christophe PLAGNIOL-VILLARD } 119659829cc1SJean-Christophe PLAGNIOL-VILLARD 119759829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("\n Sector Start Addresses:"); 119859829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; ++i) { 119959829cc1SJean-Christophe PLAGNIOL-VILLARD if ((i % 5) == 0) 120059829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n"); 12016d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_EMPTY_INFO 120259829cc1SJean-Christophe PLAGNIOL-VILLARD int k; 120359829cc1SJean-Christophe PLAGNIOL-VILLARD int size; 120459829cc1SJean-Christophe PLAGNIOL-VILLARD int erased; 120559829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long *flash; 120659829cc1SJean-Christophe PLAGNIOL-VILLARD 120759829cc1SJean-Christophe PLAGNIOL-VILLARD /* 120859829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if whole sector is erased 120959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 121012d30aa7SHaavard Skinnemoen size = flash_sector_size(info, i); 121159829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 1; 121259829cc1SJean-Christophe PLAGNIOL-VILLARD flash = (volatile unsigned long *) info->start[i]; 121359829cc1SJean-Christophe PLAGNIOL-VILLARD size = size >> 2; /* divide by 4 for longword access */ 121459829cc1SJean-Christophe PLAGNIOL-VILLARD for (k = 0; k < size; k++) { 121559829cc1SJean-Christophe PLAGNIOL-VILLARD if (*flash++ != 0xffffffff) { 121659829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 0; 121759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 121859829cc1SJean-Christophe PLAGNIOL-VILLARD } 121959829cc1SJean-Christophe PLAGNIOL-VILLARD } 122059829cc1SJean-Christophe PLAGNIOL-VILLARD 122159829cc1SJean-Christophe PLAGNIOL-VILLARD /* print empty and read-only info */ 122259829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %c %s ", 122359829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 122459829cc1SJean-Christophe PLAGNIOL-VILLARD erased ? 'E' : ' ', 122559829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 12266d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #else /* ! CONFIG_SYS_FLASH_EMPTY_INFO */ 122759829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %s ", 122859829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 122959829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 123059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 123159829cc1SJean-Christophe PLAGNIOL-VILLARD } 123259829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 123359829cc1SJean-Christophe PLAGNIOL-VILLARD return; 123459829cc1SJean-Christophe PLAGNIOL-VILLARD } 123559829cc1SJean-Christophe PLAGNIOL-VILLARD 123659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 12379a042e9cSJerry Van Baren * This is used in a few places in write_buf() to show programming 12389a042e9cSJerry Van Baren * progress. Making it a function is nasty because it needs to do side 12399a042e9cSJerry Van Baren * effect updates to digit and dots. Repeated code is nasty too, so 12409a042e9cSJerry Van Baren * we define it once here. 12419a042e9cSJerry Van Baren */ 1242f0105727SStefan Roese #ifdef CONFIG_FLASH_SHOW_PROGRESS 1243f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \ 12446ea808efSPiotr Ziecik if (flash_verbose) { \ 1245f0105727SStefan Roese dots -= dots_sub; \ 12469a042e9cSJerry Van Baren if ((scale > 0) && (dots <= 0)) { \ 12479a042e9cSJerry Van Baren if ((digit % 5) == 0) \ 12489a042e9cSJerry Van Baren printf ("%d", digit / 5); \ 12499a042e9cSJerry Van Baren else \ 12509a042e9cSJerry Van Baren putc ('.'); \ 12519a042e9cSJerry Van Baren digit--; \ 12529a042e9cSJerry Van Baren dots += scale; \ 12536ea808efSPiotr Ziecik } \ 12549a042e9cSJerry Van Baren } 1255f0105727SStefan Roese #else 1256f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) 1257f0105727SStefan Roese #endif 12589a042e9cSJerry Van Baren 12599a042e9cSJerry Van Baren /*----------------------------------------------------------------------- 126059829cc1SJean-Christophe PLAGNIOL-VILLARD * Copy memory to flash, returns: 126159829cc1SJean-Christophe PLAGNIOL-VILLARD * 0 - OK 126259829cc1SJean-Christophe PLAGNIOL-VILLARD * 1 - write timeout 126359829cc1SJean-Christophe PLAGNIOL-VILLARD * 2 - Flash not erased 126459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 126559829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) 126659829cc1SJean-Christophe PLAGNIOL-VILLARD { 126759829cc1SJean-Christophe PLAGNIOL-VILLARD ulong wp; 126812d30aa7SHaavard Skinnemoen uchar *p; 126959829cc1SJean-Christophe PLAGNIOL-VILLARD int aln; 127059829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 127159829cc1SJean-Christophe PLAGNIOL-VILLARD int i, rc; 12726d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE 127359829cc1SJean-Christophe PLAGNIOL-VILLARD int buffered_size; 127459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 12759a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS 12769a042e9cSJerry Van Baren int digit = CONFIG_FLASH_SHOW_PROGRESS; 12779a042e9cSJerry Van Baren int scale = 0; 12789a042e9cSJerry Van Baren int dots = 0; 12799a042e9cSJerry Van Baren 12809a042e9cSJerry Van Baren /* 12819a042e9cSJerry Van Baren * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes. 12829a042e9cSJerry Van Baren */ 12839a042e9cSJerry Van Baren if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) { 12849a042e9cSJerry Van Baren scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) / 12859a042e9cSJerry Van Baren CONFIG_FLASH_SHOW_PROGRESS); 12869a042e9cSJerry Van Baren } 12879a042e9cSJerry Van Baren #endif 12889a042e9cSJerry Van Baren 128959829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 129059829cc1SJean-Christophe PLAGNIOL-VILLARD wp = (addr & ~(info->portwidth - 1)); 129159829cc1SJean-Christophe PLAGNIOL-VILLARD 129259829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle unaligned start */ 129359829cc1SJean-Christophe PLAGNIOL-VILLARD if ((aln = addr - wp) != 0) { 129459829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 129512d30aa7SHaavard Skinnemoen p = map_physmem(wp, info->portwidth, MAP_NOCACHE); 129612d30aa7SHaavard Skinnemoen for (i = 0; i < aln; ++i) 129712d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 129859829cc1SJean-Christophe PLAGNIOL-VILLARD 129959829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (i < info->portwidth) && (cnt > 0); i++) { 130059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 130159829cc1SJean-Christophe PLAGNIOL-VILLARD cnt--; 130259829cc1SJean-Christophe PLAGNIOL-VILLARD } 130312d30aa7SHaavard Skinnemoen for (; (cnt == 0) && (i < info->portwidth); ++i) 130412d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 130512d30aa7SHaavard Skinnemoen 130612d30aa7SHaavard Skinnemoen rc = flash_write_cfiword (info, wp, cword); 130712d30aa7SHaavard Skinnemoen unmap_physmem(p, info->portwidth); 130812d30aa7SHaavard Skinnemoen if (rc != 0) 130959829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 131012d30aa7SHaavard Skinnemoen 131112d30aa7SHaavard Skinnemoen wp += i; 1312f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, i); 131359829cc1SJean-Christophe PLAGNIOL-VILLARD } 131459829cc1SJean-Christophe PLAGNIOL-VILLARD 131559829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle the aligned part */ 13166d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE 131759829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size = (info->portwidth / info->chipwidth); 131859829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size *= info->buffer_size; 131959829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 132059829cc1SJean-Christophe PLAGNIOL-VILLARD /* prohibit buffer write when buffer_size is 1 */ 132159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size == 1) { 132259829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 132359829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) 132459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 132559829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 132659829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 132759829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 132859829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 132959829cc1SJean-Christophe PLAGNIOL-VILLARD continue; 133059829cc1SJean-Christophe PLAGNIOL-VILLARD } 133159829cc1SJean-Christophe PLAGNIOL-VILLARD 133259829cc1SJean-Christophe PLAGNIOL-VILLARD /* write buffer until next buffered_size aligned boundary */ 133359829cc1SJean-Christophe PLAGNIOL-VILLARD i = buffered_size - (wp % buffered_size); 133459829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > cnt) 133559829cc1SJean-Christophe PLAGNIOL-VILLARD i = cnt; 133659829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) 133759829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 133859829cc1SJean-Christophe PLAGNIOL-VILLARD i -= i & (info->portwidth - 1); 133959829cc1SJean-Christophe PLAGNIOL-VILLARD wp += i; 134059829cc1SJean-Christophe PLAGNIOL-VILLARD src += i; 134159829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= i; 1342f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, i); 134359829cc1SJean-Christophe PLAGNIOL-VILLARD } 134459829cc1SJean-Christophe PLAGNIOL-VILLARD #else 134559829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 134659829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 134759829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) { 134859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 134959829cc1SJean-Christophe PLAGNIOL-VILLARD } 135059829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 135159829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 135259829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 135359829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 1354f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth); 135559829cc1SJean-Christophe PLAGNIOL-VILLARD } 13566d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */ 13579a042e9cSJerry Van Baren 135859829cc1SJean-Christophe PLAGNIOL-VILLARD if (cnt == 0) { 135959829cc1SJean-Christophe PLAGNIOL-VILLARD return (0); 136059829cc1SJean-Christophe PLAGNIOL-VILLARD } 136159829cc1SJean-Christophe PLAGNIOL-VILLARD 136259829cc1SJean-Christophe PLAGNIOL-VILLARD /* 136359829cc1SJean-Christophe PLAGNIOL-VILLARD * handle unaligned tail bytes 136459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 136559829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 136612d30aa7SHaavard Skinnemoen p = map_physmem(wp, info->portwidth, MAP_NOCACHE); 136712d30aa7SHaavard Skinnemoen for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) { 136859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 136959829cc1SJean-Christophe PLAGNIOL-VILLARD --cnt; 137059829cc1SJean-Christophe PLAGNIOL-VILLARD } 137112d30aa7SHaavard Skinnemoen for (; i < info->portwidth; ++i) 137212d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 137312d30aa7SHaavard Skinnemoen unmap_physmem(p, info->portwidth); 137459829cc1SJean-Christophe PLAGNIOL-VILLARD 137559829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_write_cfiword (info, wp, cword); 137659829cc1SJean-Christophe PLAGNIOL-VILLARD } 137759829cc1SJean-Christophe PLAGNIOL-VILLARD 137859829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 137959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 13806d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 138159829cc1SJean-Christophe PLAGNIOL-VILLARD 138259829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot) 138359829cc1SJean-Christophe PLAGNIOL-VILLARD { 138459829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode = 0; 138559829cc1SJean-Christophe PLAGNIOL-VILLARD 1386bc9019e1SRafael Campos switch (info->vendor) { 1387bc9019e1SRafael Campos case CFI_CMDSET_INTEL_PROG_REGIONS: 1388bc9019e1SRafael Campos case CFI_CMDSET_INTEL_STANDARD: 13899e8e63ccSNick Spence case CFI_CMDSET_INTEL_EXTENDED: 1390bc9019e1SRafael Campos flash_write_cmd (info, sector, 0, 1391bc9019e1SRafael Campos FLASH_CMD_CLEAR_STATUS); 139259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); 139359829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) 1394bc9019e1SRafael Campos flash_write_cmd (info, sector, 0, 1395bc9019e1SRafael Campos FLASH_CMD_PROTECT_SET); 139659829cc1SJean-Christophe PLAGNIOL-VILLARD else 1397bc9019e1SRafael Campos flash_write_cmd (info, sector, 0, 1398bc9019e1SRafael Campos FLASH_CMD_PROTECT_CLEAR); 1399bc9019e1SRafael Campos break; 1400bc9019e1SRafael Campos case CFI_CMDSET_AMD_EXTENDED: 1401bc9019e1SRafael Campos case CFI_CMDSET_AMD_STANDARD: 1402bc9019e1SRafael Campos /* U-Boot only checks the first byte */ 1403bc9019e1SRafael Campos if (info->manufacturer_id == (uchar)ATM_MANUFACT) { 1404bc9019e1SRafael Campos if (prot) { 1405bc9019e1SRafael Campos flash_unlock_seq (info, 0); 1406bc9019e1SRafael Campos flash_write_cmd (info, 0, 1407bc9019e1SRafael Campos info->addr_unlock1, 1408bc9019e1SRafael Campos ATM_CMD_SOFTLOCK_START); 1409bc9019e1SRafael Campos flash_unlock_seq (info, 0); 1410bc9019e1SRafael Campos flash_write_cmd (info, sector, 0, 1411bc9019e1SRafael Campos ATM_CMD_LOCK_SECT); 1412bc9019e1SRafael Campos } else { 1413bc9019e1SRafael Campos flash_write_cmd (info, 0, 1414bc9019e1SRafael Campos info->addr_unlock1, 1415bc9019e1SRafael Campos AMD_CMD_UNLOCK_START); 1416bc9019e1SRafael Campos if (info->device_id == ATM_ID_BV6416) 1417bc9019e1SRafael Campos flash_write_cmd (info, sector, 1418bc9019e1SRafael Campos 0, ATM_CMD_UNLOCK_SECT); 1419bc9019e1SRafael Campos } 1420bc9019e1SRafael Campos } 1421bc9019e1SRafael Campos break; 14224e00acdeSTsiChung Liew #ifdef CONFIG_FLASH_CFI_LEGACY 14234e00acdeSTsiChung Liew case CFI_CMDSET_AMD_LEGACY: 14244e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 14254e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); 14264e00acdeSTsiChung Liew if (prot) 14274e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); 14284e00acdeSTsiChung Liew else 14294e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR); 14304e00acdeSTsiChung Liew #endif 1431bc9019e1SRafael Campos }; 143259829cc1SJean-Christophe PLAGNIOL-VILLARD 143359829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode = 143459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_full_status_check (info, sector, info->erase_blk_tout, 143559829cc1SJean-Christophe PLAGNIOL-VILLARD prot ? "protect" : "unprotect")) == 0) { 143659829cc1SJean-Christophe PLAGNIOL-VILLARD 143759829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sector] = prot; 143859829cc1SJean-Christophe PLAGNIOL-VILLARD 143959829cc1SJean-Christophe PLAGNIOL-VILLARD /* 144059829cc1SJean-Christophe PLAGNIOL-VILLARD * On some of Intel's flash chips (marked via legacy_unlock) 144159829cc1SJean-Christophe PLAGNIOL-VILLARD * unprotect unprotects all locking. 144259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 144359829cc1SJean-Christophe PLAGNIOL-VILLARD if ((prot == 0) && (info->legacy_unlock)) { 144459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t i; 144559829cc1SJean-Christophe PLAGNIOL-VILLARD 144659829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; i++) { 144759829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[i]) 144859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (info, i, 1); 144959829cc1SJean-Christophe PLAGNIOL-VILLARD } 145059829cc1SJean-Christophe PLAGNIOL-VILLARD } 145159829cc1SJean-Christophe PLAGNIOL-VILLARD } 145259829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 145359829cc1SJean-Christophe PLAGNIOL-VILLARD } 145459829cc1SJean-Christophe PLAGNIOL-VILLARD 145559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 145659829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_user_serial - read the OneTimeProgramming cells 145759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 145859829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, 145959829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 146059829cc1SJean-Christophe PLAGNIOL-VILLARD { 146159829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 146259829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *dst; 146359829cc1SJean-Christophe PLAGNIOL-VILLARD 146459829cc1SJean-Christophe PLAGNIOL-VILLARD dst = buffer; 146512d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION); 146659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 146759829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (dst, src + offset, len); 146859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 146912d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src); 147059829cc1SJean-Christophe PLAGNIOL-VILLARD } 147159829cc1SJean-Christophe PLAGNIOL-VILLARD 147259829cc1SJean-Christophe PLAGNIOL-VILLARD /* 147359829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_factory_serial - read the device Id from the protection area 147459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 147559829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, 147659829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 147759829cc1SJean-Christophe PLAGNIOL-VILLARD { 147859829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 147959829cc1SJean-Christophe PLAGNIOL-VILLARD 148012d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION); 148159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 148259829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (buffer, src + offset, len); 148359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 148412d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src); 148559829cc1SJean-Christophe PLAGNIOL-VILLARD } 148659829cc1SJean-Christophe PLAGNIOL-VILLARD 14876d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */ 148859829cc1SJean-Christophe PLAGNIOL-VILLARD 14890ddf06ddSHaavard Skinnemoen /*----------------------------------------------------------------------- 14900ddf06ddSHaavard Skinnemoen * Reverse the order of the erase regions in the CFI QRY structure. 14910ddf06ddSHaavard Skinnemoen * This is needed for chips that are either a) correctly detected as 14920ddf06ddSHaavard Skinnemoen * top-boot, or b) buggy. 14930ddf06ddSHaavard Skinnemoen */ 14940ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry) 14950ddf06ddSHaavard Skinnemoen { 14960ddf06ddSHaavard Skinnemoen unsigned int i, j; 14970ddf06ddSHaavard Skinnemoen u32 tmp; 14980ddf06ddSHaavard Skinnemoen 14990ddf06ddSHaavard Skinnemoen for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) { 15000ddf06ddSHaavard Skinnemoen tmp = qry->erase_region_info[i]; 15010ddf06ddSHaavard Skinnemoen qry->erase_region_info[i] = qry->erase_region_info[j]; 15020ddf06ddSHaavard Skinnemoen qry->erase_region_info[j] = tmp; 15030ddf06ddSHaavard Skinnemoen } 15040ddf06ddSHaavard Skinnemoen } 150559829cc1SJean-Christophe PLAGNIOL-VILLARD 150659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 150759829cc1SJean-Christophe PLAGNIOL-VILLARD * read jedec ids from device and set corresponding fields in info struct 150859829cc1SJean-Christophe PLAGNIOL-VILLARD * 150959829cc1SJean-Christophe PLAGNIOL-VILLARD * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct 151059829cc1SJean-Christophe PLAGNIOL-VILLARD * 151159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 15120ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info) 151359829cc1SJean-Christophe PLAGNIOL-VILLARD { 151459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 151559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); 151659829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 151759829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 151859829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 151959829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 152059829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 152159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 15220ddf06ddSHaavard Skinnemoen } 15230ddf06ddSHaavard Skinnemoen 15240ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry) 15250ddf06ddSHaavard Skinnemoen { 15260ddf06ddSHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 15270ddf06ddSHaavard Skinnemoen 15280ddf06ddSHaavard Skinnemoen cmdset_intel_read_jedec_ids(info); 15290ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 15300ddf06ddSHaavard Skinnemoen 15316d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 15320ddf06ddSHaavard Skinnemoen /* read legacy lock/unlock bit from intel flash */ 15330ddf06ddSHaavard Skinnemoen if (info->ext_addr) { 15340ddf06ddSHaavard Skinnemoen info->legacy_unlock = flash_read_uchar (info, 15350ddf06ddSHaavard Skinnemoen info->ext_addr + 5) & 0x08; 15360ddf06ddSHaavard Skinnemoen } 15370ddf06ddSHaavard Skinnemoen #endif 15380ddf06ddSHaavard Skinnemoen 15390ddf06ddSHaavard Skinnemoen return 0; 15400ddf06ddSHaavard Skinnemoen } 15410ddf06ddSHaavard Skinnemoen 15420ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info) 15430ddf06ddSHaavard Skinnemoen { 154459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 154559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info, 0); 154681b20cccSMichael Schwingen flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); 154759829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 154890447ecbSTor Krill 154959829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 155059829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 155190447ecbSTor Krill 155290447ecbSTor Krill switch (info->chipwidth){ 155390447ecbSTor Krill case FLASH_CFI_8BIT: 155459829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 155559829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 155659829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 155759829cc1SJean-Christophe PLAGNIOL-VILLARD /* AMD 3-byte (expanded) device ids */ 155859829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = flash_read_uchar (info, 155959829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID2); 156059829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 <<= 8; 156159829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 |= flash_read_uchar (info, 156259829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID3); 156359829cc1SJean-Christophe PLAGNIOL-VILLARD } 156490447ecbSTor Krill break; 156590447ecbSTor Krill case FLASH_CFI_16BIT: 156690447ecbSTor Krill info->device_id = flash_read_word (info, 156790447ecbSTor Krill FLASH_OFFSET_DEVICE_ID); 156890447ecbSTor Krill break; 156990447ecbSTor Krill default: 157090447ecbSTor Krill break; 157190447ecbSTor Krill } 157259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 15730ddf06ddSHaavard Skinnemoen } 15740ddf06ddSHaavard Skinnemoen 15750ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry) 15760ddf06ddSHaavard Skinnemoen { 15770ddf06ddSHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 15780ddf06ddSHaavard Skinnemoen 15790ddf06ddSHaavard Skinnemoen cmdset_amd_read_jedec_ids(info); 15800ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 15810ddf06ddSHaavard Skinnemoen 15820ddf06ddSHaavard Skinnemoen return 0; 15830ddf06ddSHaavard Skinnemoen } 15840ddf06ddSHaavard Skinnemoen 15850ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 15860ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info) 15870ddf06ddSHaavard Skinnemoen { 15880ddf06ddSHaavard Skinnemoen info->manufacturer_id = 0; 15890ddf06ddSHaavard Skinnemoen info->device_id = 0; 15900ddf06ddSHaavard Skinnemoen info->device_id2 = 0; 15910ddf06ddSHaavard Skinnemoen 15920ddf06ddSHaavard Skinnemoen switch (info->vendor) { 15939c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 15940ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 15950ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 15968225d1e3SMichael Schwingen cmdset_intel_read_jedec_ids(info); 15970ddf06ddSHaavard Skinnemoen break; 15980ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 15990ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 16008225d1e3SMichael Schwingen cmdset_amd_read_jedec_ids(info); 160159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 160259829cc1SJean-Christophe PLAGNIOL-VILLARD default: 160359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 160459829cc1SJean-Christophe PLAGNIOL-VILLARD } 160559829cc1SJean-Christophe PLAGNIOL-VILLARD } 160659829cc1SJean-Christophe PLAGNIOL-VILLARD 1607be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 1608be60a902SHaavard Skinnemoen * Call board code to request info about non-CFI flash. 1609be60a902SHaavard Skinnemoen * board_flash_get_legacy needs to fill in at least: 1610be60a902SHaavard Skinnemoen * info->portwidth, info->chipwidth and info->interface for Jedec probing. 1611be60a902SHaavard Skinnemoen */ 1612be60a902SHaavard Skinnemoen static int flash_detect_legacy(ulong base, int banknum) 1613be60a902SHaavard Skinnemoen { 1614be60a902SHaavard Skinnemoen flash_info_t *info = &flash_info[banknum]; 1615be60a902SHaavard Skinnemoen 1616be60a902SHaavard Skinnemoen if (board_flash_get_legacy(base, banknum, info)) { 1617be60a902SHaavard Skinnemoen /* board code may have filled info completely. If not, we 1618be60a902SHaavard Skinnemoen use JEDEC ID probing. */ 1619be60a902SHaavard Skinnemoen if (!info->vendor) { 1620be60a902SHaavard Skinnemoen int modes[] = { 1621be60a902SHaavard Skinnemoen CFI_CMDSET_AMD_STANDARD, 1622be60a902SHaavard Skinnemoen CFI_CMDSET_INTEL_STANDARD 1623be60a902SHaavard Skinnemoen }; 1624be60a902SHaavard Skinnemoen int i; 1625be60a902SHaavard Skinnemoen 1626be60a902SHaavard Skinnemoen for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) { 1627be60a902SHaavard Skinnemoen info->vendor = modes[i]; 1628be60a902SHaavard Skinnemoen info->start[0] = base; 1629be60a902SHaavard Skinnemoen if (info->portwidth == FLASH_CFI_8BIT 1630be60a902SHaavard Skinnemoen && info->interface == FLASH_CFI_X8X16) { 1631be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x2AAA; 1632be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x5555; 1633be60a902SHaavard Skinnemoen } else { 1634be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x5555; 1635be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x2AAA; 1636be60a902SHaavard Skinnemoen } 1637be60a902SHaavard Skinnemoen flash_read_jedec_ids(info); 1638be60a902SHaavard Skinnemoen debug("JEDEC PROBE: ID %x %x %x\n", 1639be60a902SHaavard Skinnemoen info->manufacturer_id, 1640be60a902SHaavard Skinnemoen info->device_id, 1641be60a902SHaavard Skinnemoen info->device_id2); 1642be60a902SHaavard Skinnemoen if (jedec_flash_match(info, base)) 1643be60a902SHaavard Skinnemoen break; 1644be60a902SHaavard Skinnemoen } 1645be60a902SHaavard Skinnemoen } 1646be60a902SHaavard Skinnemoen 1647be60a902SHaavard Skinnemoen switch(info->vendor) { 16489c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 1649be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 1650be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 1651be60a902SHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 1652be60a902SHaavard Skinnemoen break; 1653be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 1654be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 1655be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_LEGACY: 1656be60a902SHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 1657be60a902SHaavard Skinnemoen break; 1658be60a902SHaavard Skinnemoen } 1659be60a902SHaavard Skinnemoen info->flash_id = FLASH_MAN_CFI; 1660be60a902SHaavard Skinnemoen return 1; 1661be60a902SHaavard Skinnemoen } 1662be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1663be60a902SHaavard Skinnemoen } 1664be60a902SHaavard Skinnemoen #else 1665be60a902SHaavard Skinnemoen static inline int flash_detect_legacy(ulong base, int banknum) 1666be60a902SHaavard Skinnemoen { 1667be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1668be60a902SHaavard Skinnemoen } 1669be60a902SHaavard Skinnemoen #endif 1670be60a902SHaavard Skinnemoen 167159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 167259829cc1SJean-Christophe PLAGNIOL-VILLARD * detect if flash is compatible with the Common Flash Interface (CFI) 167359829cc1SJean-Christophe PLAGNIOL-VILLARD * http://www.jedec.org/download/search/jesd68.pdf 167459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1675e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf, 1676e23741f4SHaavard Skinnemoen unsigned int start, size_t len) 1677e23741f4SHaavard Skinnemoen { 1678e23741f4SHaavard Skinnemoen u8 *p = buf; 1679e23741f4SHaavard Skinnemoen unsigned int i; 1680e23741f4SHaavard Skinnemoen 1681e23741f4SHaavard Skinnemoen for (i = 0; i < len; i++) 1682e23741f4SHaavard Skinnemoen p[i] = flash_read_uchar(info, start + i); 1683e23741f4SHaavard Skinnemoen } 1684e23741f4SHaavard Skinnemoen 1685e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 168659829cc1SJean-Christophe PLAGNIOL-VILLARD { 168759829cc1SJean-Christophe PLAGNIOL-VILLARD int cfi_offset; 168859829cc1SJean-Christophe PLAGNIOL-VILLARD 16891ba639daSMichael Schwingen /* We do not yet know what kind of commandset to use, so we issue 16901ba639daSMichael Schwingen the reset command in both Intel and AMD variants, in the hope 16911ba639daSMichael Schwingen that AMD flash roms ignore the Intel command. */ 16921ba639daSMichael Schwingen flash_write_cmd (info, 0, 0, AMD_CMD_RESET); 16931ba639daSMichael Schwingen flash_write_cmd (info, 0, 0, FLASH_CMD_RESET); 16941ba639daSMichael Schwingen 16957e5b9b47SHaavard Skinnemoen for (cfi_offset=0; 16967e5b9b47SHaavard Skinnemoen cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint); 16977e5b9b47SHaavard Skinnemoen cfi_offset++) { 16987e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], 16997e5b9b47SHaavard Skinnemoen FLASH_CMD_CFI); 170059829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') 170159829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') 170259829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { 1703e23741f4SHaavard Skinnemoen flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP, 1704e23741f4SHaavard Skinnemoen sizeof(struct cfi_qry)); 1705e23741f4SHaavard Skinnemoen info->interface = le16_to_cpu(qry->interface_desc); 1706e23741f4SHaavard Skinnemoen 170759829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_offset = flash_offset_cfi[cfi_offset]; 170859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device interface is %d\n", 170959829cc1SJean-Christophe PLAGNIOL-VILLARD info->interface); 171059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found port %d chip %d ", 171159829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth, info->chipwidth); 171259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("port %d bits chip %d bits\n", 171359829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth << CFI_FLASH_SHIFT_WIDTH, 171459829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 171542026c9cSBartlomiej Sieka 171642026c9cSBartlomiej Sieka /* calculate command offsets as in the Linux driver */ 171742026c9cSBartlomiej Sieka info->addr_unlock1 = 0x555; 171842026c9cSBartlomiej Sieka info->addr_unlock2 = 0x2aa; 171942026c9cSBartlomiej Sieka 172042026c9cSBartlomiej Sieka /* 172142026c9cSBartlomiej Sieka * modify the unlock address if we are 172242026c9cSBartlomiej Sieka * in compatibility mode 172342026c9cSBartlomiej Sieka */ 172442026c9cSBartlomiej Sieka if ( /* x8/x16 in x8 mode */ 172542026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY8) && 172642026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X8X16)) || 172742026c9cSBartlomiej Sieka /* x16/x32 in x16 mode */ 172842026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY16) && 172942026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X16X32))) 173042026c9cSBartlomiej Sieka { 173142026c9cSBartlomiej Sieka info->addr_unlock1 = 0xaaa; 173242026c9cSBartlomiej Sieka info->addr_unlock2 = 0x555; 173342026c9cSBartlomiej Sieka } 173442026c9cSBartlomiej Sieka 173581b20cccSMichael Schwingen info->name = "CFI conformant"; 173659829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 173759829cc1SJean-Christophe PLAGNIOL-VILLARD } 173859829cc1SJean-Christophe PLAGNIOL-VILLARD } 17397e5b9b47SHaavard Skinnemoen 17407e5b9b47SHaavard Skinnemoen return 0; 174159829cc1SJean-Christophe PLAGNIOL-VILLARD } 17427e5b9b47SHaavard Skinnemoen 1743e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 17447e5b9b47SHaavard Skinnemoen { 17457e5b9b47SHaavard Skinnemoen debug ("flash detect cfi\n"); 17467e5b9b47SHaavard Skinnemoen 17476d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (info->portwidth = CONFIG_SYS_FLASH_CFI_WIDTH; 17487e5b9b47SHaavard Skinnemoen info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) { 17497e5b9b47SHaavard Skinnemoen for (info->chipwidth = FLASH_CFI_BY8; 17507e5b9b47SHaavard Skinnemoen info->chipwidth <= info->portwidth; 17517e5b9b47SHaavard Skinnemoen info->chipwidth <<= 1) 1752e23741f4SHaavard Skinnemoen if (__flash_detect_cfi(info, qry)) 17537e5b9b47SHaavard Skinnemoen return 1; 175459829cc1SJean-Christophe PLAGNIOL-VILLARD } 175559829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("not found\n"); 175659829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 175759829cc1SJean-Christophe PLAGNIOL-VILLARD } 175859829cc1SJean-Christophe PLAGNIOL-VILLARD 175959829cc1SJean-Christophe PLAGNIOL-VILLARD /* 1760467bcee1SHaavard Skinnemoen * Manufacturer-specific quirks. Add workarounds for geometry 1761467bcee1SHaavard Skinnemoen * reversal, etc. here. 1762467bcee1SHaavard Skinnemoen */ 1763467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry) 1764467bcee1SHaavard Skinnemoen { 1765467bcee1SHaavard Skinnemoen /* check if flash geometry needs reversal */ 1766467bcee1SHaavard Skinnemoen if (qry->num_erase_regions > 1) { 1767467bcee1SHaavard Skinnemoen /* reverse geometry if top boot part */ 1768467bcee1SHaavard Skinnemoen if (info->cfi_version < 0x3131) { 1769467bcee1SHaavard Skinnemoen /* CFI < 1.1, try to guess from device id */ 1770467bcee1SHaavard Skinnemoen if ((info->device_id & 0x80) != 0) 1771467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1772467bcee1SHaavard Skinnemoen } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { 1773467bcee1SHaavard Skinnemoen /* CFI >= 1.1, deduct from top/bottom flag */ 1774467bcee1SHaavard Skinnemoen /* note: ext_addr is valid since cfi_version > 0 */ 1775467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1776467bcee1SHaavard Skinnemoen } 1777467bcee1SHaavard Skinnemoen } 1778467bcee1SHaavard Skinnemoen } 1779467bcee1SHaavard Skinnemoen 1780467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry) 1781467bcee1SHaavard Skinnemoen { 1782467bcee1SHaavard Skinnemoen int reverse_geometry = 0; 1783467bcee1SHaavard Skinnemoen 1784467bcee1SHaavard Skinnemoen /* Check the "top boot" bit in the PRI */ 1785467bcee1SHaavard Skinnemoen if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1)) 1786467bcee1SHaavard Skinnemoen reverse_geometry = 1; 1787467bcee1SHaavard Skinnemoen 1788467bcee1SHaavard Skinnemoen /* AT49BV6416(T) list the erase regions in the wrong order. 1789467bcee1SHaavard Skinnemoen * However, the device ID is identical with the non-broken 1790467bcee1SHaavard Skinnemoen * AT49BV642D since u-boot only reads the low byte (they 1791467bcee1SHaavard Skinnemoen * differ in the high byte.) So leave out this fixup for now. 1792467bcee1SHaavard Skinnemoen */ 1793467bcee1SHaavard Skinnemoen #if 0 1794467bcee1SHaavard Skinnemoen if (info->device_id == 0xd6 || info->device_id == 0xd2) 1795467bcee1SHaavard Skinnemoen reverse_geometry = !reverse_geometry; 1796467bcee1SHaavard Skinnemoen #endif 1797467bcee1SHaavard Skinnemoen 1798467bcee1SHaavard Skinnemoen if (reverse_geometry) 1799467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1800467bcee1SHaavard Skinnemoen } 1801467bcee1SHaavard Skinnemoen 1802467bcee1SHaavard Skinnemoen /* 180359829cc1SJean-Christophe PLAGNIOL-VILLARD * The following code cannot be run from FLASH! 180459829cc1SJean-Christophe PLAGNIOL-VILLARD * 180559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 180659829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum) 180759829cc1SJean-Christophe PLAGNIOL-VILLARD { 180859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t *info = &flash_info[banknum]; 180959829cc1SJean-Christophe PLAGNIOL-VILLARD int i, j; 181059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect_cnt; 181159829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long sector; 181259829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long tmp; 181359829cc1SJean-Christophe PLAGNIOL-VILLARD int size_ratio; 181459829cc1SJean-Christophe PLAGNIOL-VILLARD uchar num_erase_regions; 181559829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_size; 181659829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_count; 1817e23741f4SHaavard Skinnemoen struct cfi_qry qry; 181859829cc1SJean-Christophe PLAGNIOL-VILLARD 1819f979690eSKumar Gala memset(&qry, 0, sizeof(qry)); 1820f979690eSKumar Gala 182159829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = 0; 182259829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = 0; 18236d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 182459829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = 0; 182559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 182659829cc1SJean-Christophe PLAGNIOL-VILLARD 182759829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[0] = base; 182859829cc1SJean-Christophe PLAGNIOL-VILLARD 1829e23741f4SHaavard Skinnemoen if (flash_detect_cfi (info, &qry)) { 1830e23741f4SHaavard Skinnemoen info->vendor = le16_to_cpu(qry.p_id); 1831e23741f4SHaavard Skinnemoen info->ext_addr = le16_to_cpu(qry.p_adr); 1832e23741f4SHaavard Skinnemoen num_erase_regions = qry.num_erase_regions; 1833e23741f4SHaavard Skinnemoen 183459829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 183559829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = (ushort) flash_read_uchar (info, 183659829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 3) << 8; 183759829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version |= (ushort) flash_read_uchar (info, 183859829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 4); 183959829cc1SJean-Christophe PLAGNIOL-VILLARD } 18400ddf06ddSHaavard Skinnemoen 184159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 1842e23741f4SHaavard Skinnemoen flash_printqry (&qry); 184359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 18440ddf06ddSHaavard Skinnemoen 184559829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 18469c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 184759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 184859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 18490ddf06ddSHaavard Skinnemoen cmdset_intel_init(info, &qry); 185059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 185159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 185259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 18530ddf06ddSHaavard Skinnemoen cmdset_amd_init(info, &qry); 185459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 18550ddf06ddSHaavard Skinnemoen default: 18560ddf06ddSHaavard Skinnemoen printf("CFI: Unknown command set 0x%x\n", 18570ddf06ddSHaavard Skinnemoen info->vendor); 18580ddf06ddSHaavard Skinnemoen /* 18590ddf06ddSHaavard Skinnemoen * Unfortunately, this means we don't know how 18600ddf06ddSHaavard Skinnemoen * to get the chip back to Read mode. Might 18610ddf06ddSHaavard Skinnemoen * as well try an Intel-style reset... 18620ddf06ddSHaavard Skinnemoen */ 18630ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 18640ddf06ddSHaavard Skinnemoen return 0; 186559829cc1SJean-Christophe PLAGNIOL-VILLARD } 186659829cc1SJean-Christophe PLAGNIOL-VILLARD 1867467bcee1SHaavard Skinnemoen /* Do manufacturer-specific fixups */ 1868467bcee1SHaavard Skinnemoen switch (info->manufacturer_id) { 1869467bcee1SHaavard Skinnemoen case 0x0001: 1870467bcee1SHaavard Skinnemoen flash_fixup_amd(info, &qry); 1871467bcee1SHaavard Skinnemoen break; 1872467bcee1SHaavard Skinnemoen case 0x001f: 1873467bcee1SHaavard Skinnemoen flash_fixup_atmel(info, &qry); 1874467bcee1SHaavard Skinnemoen break; 1875467bcee1SHaavard Skinnemoen } 1876467bcee1SHaavard Skinnemoen 187759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer is %d\n", info->vendor); 187859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer id is 0x%x\n", info->manufacturer_id); 187959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id is 0x%x\n", info->device_id); 188059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id2 is 0x%x\n", info->device_id2); 188159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("cfi version is 0x%04x\n", info->cfi_version); 188259829cc1SJean-Christophe PLAGNIOL-VILLARD 188359829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio = info->portwidth / info->chipwidth; 188459829cc1SJean-Christophe PLAGNIOL-VILLARD /* if the chip is x8/x16 reduce the ratio by half */ 188559829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->interface == FLASH_CFI_X8X16) 188659829cc1SJean-Christophe PLAGNIOL-VILLARD && (info->chipwidth == FLASH_CFI_BY8)) { 188759829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio >>= 1; 188859829cc1SJean-Christophe PLAGNIOL-VILLARD } 188959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("size_ratio %d port %d bits chip %d bits\n", 189059829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, 189159829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 189259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found %d erase regions\n", num_erase_regions); 189359829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt = 0; 189459829cc1SJean-Christophe PLAGNIOL-VILLARD sector = base; 189559829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < num_erase_regions; i++) { 189659829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > NUM_ERASE_REGIONS) { 189759829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("%d erase regions found, only %d used\n", 189859829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions, NUM_ERASE_REGIONS); 189959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 190059829cc1SJean-Christophe PLAGNIOL-VILLARD } 1901e23741f4SHaavard Skinnemoen 19020ddf06ddSHaavard Skinnemoen tmp = le32_to_cpu(qry.erase_region_info[i]); 19030ddf06ddSHaavard Skinnemoen debug("erase region %u: 0x%08lx\n", i, tmp); 1904e23741f4SHaavard Skinnemoen 1905e23741f4SHaavard Skinnemoen erase_region_count = (tmp & 0xffff) + 1; 1906e23741f4SHaavard Skinnemoen tmp >>= 16; 190759829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_size = 190859829cc1SJean-Christophe PLAGNIOL-VILLARD (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; 190959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("erase_region_count = %d erase_region_size = %d\n", 191059829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count, erase_region_size); 191159829cc1SJean-Christophe PLAGNIOL-VILLARD for (j = 0; j < erase_region_count; j++) { 19126d0f6bcfSJean-Christophe PLAGNIOL-VILLARD if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) { 191381b20cccSMichael Schwingen printf("ERROR: too many flash sectors\n"); 191481b20cccSMichael Schwingen break; 191581b20cccSMichael Schwingen } 191659829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[sect_cnt] = sector; 191759829cc1SJean-Christophe PLAGNIOL-VILLARD sector += (erase_region_size * size_ratio); 191859829cc1SJean-Christophe PLAGNIOL-VILLARD 191959829cc1SJean-Christophe PLAGNIOL-VILLARD /* 19207e5b9b47SHaavard Skinnemoen * Only read protection status from 19217e5b9b47SHaavard Skinnemoen * supported devices (intel...) 192259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 192359829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 19249c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 192559829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 192659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 192759829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sect_cnt] = 192859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_isset (info, sect_cnt, 192959829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PROTECT, 193059829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_STATUS_PROTECT); 193159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 193259829cc1SJean-Christophe PLAGNIOL-VILLARD default: 19337e5b9b47SHaavard Skinnemoen /* default: not protected */ 19347e5b9b47SHaavard Skinnemoen info->protect[sect_cnt] = 0; 193559829cc1SJean-Christophe PLAGNIOL-VILLARD } 193659829cc1SJean-Christophe PLAGNIOL-VILLARD 193759829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt++; 193859829cc1SJean-Christophe PLAGNIOL-VILLARD } 193959829cc1SJean-Christophe PLAGNIOL-VILLARD } 194059829cc1SJean-Christophe PLAGNIOL-VILLARD 194159829cc1SJean-Christophe PLAGNIOL-VILLARD info->sector_count = sect_cnt; 1942e23741f4SHaavard Skinnemoen info->size = 1 << qry.dev_size; 194359829cc1SJean-Christophe PLAGNIOL-VILLARD /* multiply the size by the number of chips */ 19447e5b9b47SHaavard Skinnemoen info->size *= size_ratio; 1945e23741f4SHaavard Skinnemoen info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size); 1946e23741f4SHaavard Skinnemoen tmp = 1 << qry.block_erase_timeout_typ; 19477e5b9b47SHaavard Skinnemoen info->erase_blk_tout = tmp * 1948e23741f4SHaavard Skinnemoen (1 << qry.block_erase_timeout_max); 1949e23741f4SHaavard Skinnemoen tmp = (1 << qry.buf_write_timeout_typ) * 1950e23741f4SHaavard Skinnemoen (1 << qry.buf_write_timeout_max); 1951e23741f4SHaavard Skinnemoen 19527e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 1953e23741f4SHaavard Skinnemoen info->buffer_write_tout = (tmp + 999) / 1000; 1954e23741f4SHaavard Skinnemoen tmp = (1 << qry.word_write_timeout_typ) * 1955e23741f4SHaavard Skinnemoen (1 << qry.word_write_timeout_max); 19567e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 1957e23741f4SHaavard Skinnemoen info->write_tout = (tmp + 999) / 1000; 195859829cc1SJean-Christophe PLAGNIOL-VILLARD info->flash_id = FLASH_MAN_CFI; 19597e5b9b47SHaavard Skinnemoen if ((info->interface == FLASH_CFI_X8X16) && 19607e5b9b47SHaavard Skinnemoen (info->chipwidth == FLASH_CFI_BY8)) { 19617e5b9b47SHaavard Skinnemoen /* XXX - Need to test on x8/x16 in parallel. */ 19627e5b9b47SHaavard Skinnemoen info->portwidth >>= 1; 196359829cc1SJean-Christophe PLAGNIOL-VILLARD } 196459829cc1SJean-Christophe PLAGNIOL-VILLARD 196559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 19662215987eSMike Frysinger } 19672215987eSMike Frysinger 196859829cc1SJean-Christophe PLAGNIOL-VILLARD return (info->size); 196959829cc1SJean-Christophe PLAGNIOL-VILLARD } 197059829cc1SJean-Christophe PLAGNIOL-VILLARD 19716ea808efSPiotr Ziecik void flash_set_verbose(uint v) 19726ea808efSPiotr Ziecik { 19736ea808efSPiotr Ziecik flash_verbose = v; 19746ea808efSPiotr Ziecik } 19756ea808efSPiotr Ziecik 197659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 197759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1978be60a902SHaavard Skinnemoen unsigned long flash_init (void) 197959829cc1SJean-Christophe PLAGNIOL-VILLARD { 1980be60a902SHaavard Skinnemoen unsigned long size = 0; 1981be60a902SHaavard Skinnemoen int i; 19826d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) 1983c63ad632SMatthias Fuchs struct apl_s { 1984c63ad632SMatthias Fuchs ulong start; 1985c63ad632SMatthias Fuchs ulong size; 19866d0f6bcfSJean-Christophe PLAGNIOL-VILLARD } apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST; 1987c63ad632SMatthias Fuchs #endif 198859829cc1SJean-Christophe PLAGNIOL-VILLARD 19896d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 1990be60a902SHaavard Skinnemoen char *s = getenv("unlock"); 199181b20cccSMichael Schwingen #endif 1992be60a902SHaavard Skinnemoen 19936d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define BANK_BASE(i) (((unsigned long [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i]) 19942a112b23SWolfgang Denk 1995be60a902SHaavard Skinnemoen /* Init: no FLASHes known */ 19966d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) { 1997be60a902SHaavard Skinnemoen flash_info[i].flash_id = FLASH_UNKNOWN; 1998be60a902SHaavard Skinnemoen 19992a112b23SWolfgang Denk if (!flash_detect_legacy (BANK_BASE(i), i)) 20002a112b23SWolfgang Denk flash_get_size (BANK_BASE(i), i); 2001be60a902SHaavard Skinnemoen size += flash_info[i].size; 2002be60a902SHaavard Skinnemoen if (flash_info[i].flash_id == FLASH_UNKNOWN) { 20036d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_QUIET_TEST 2004be60a902SHaavard Skinnemoen printf ("## Unknown FLASH on Bank %d " 2005be60a902SHaavard Skinnemoen "- Size = 0x%08lx = %ld MB\n", 2006be60a902SHaavard Skinnemoen i+1, flash_info[i].size, 2007be60a902SHaavard Skinnemoen flash_info[i].size << 20); 20086d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_QUIET_TEST */ 200959829cc1SJean-Christophe PLAGNIOL-VILLARD } 20106d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 2011be60a902SHaavard Skinnemoen else if ((s != NULL) && (strcmp(s, "yes") == 0)) { 2012be60a902SHaavard Skinnemoen /* 2013be60a902SHaavard Skinnemoen * Only the U-Boot image and it's environment 2014be60a902SHaavard Skinnemoen * is protected, all other sectors are 2015be60a902SHaavard Skinnemoen * unprotected (unlocked) if flash hardware 20166d0f6bcfSJean-Christophe PLAGNIOL-VILLARD * protection is used (CONFIG_SYS_FLASH_PROTECTION) 2017be60a902SHaavard Skinnemoen * and the environment variable "unlock" is 2018be60a902SHaavard Skinnemoen * set to "yes". 2019be60a902SHaavard Skinnemoen */ 2020be60a902SHaavard Skinnemoen if (flash_info[i].legacy_unlock) { 2021be60a902SHaavard Skinnemoen int k; 202259829cc1SJean-Christophe PLAGNIOL-VILLARD 2023be60a902SHaavard Skinnemoen /* 2024be60a902SHaavard Skinnemoen * Disable legacy_unlock temporarily, 2025be60a902SHaavard Skinnemoen * since flash_real_protect would 2026be60a902SHaavard Skinnemoen * relock all other sectors again 2027be60a902SHaavard Skinnemoen * otherwise. 2028be60a902SHaavard Skinnemoen */ 2029be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 0; 203059829cc1SJean-Christophe PLAGNIOL-VILLARD 2031be60a902SHaavard Skinnemoen /* 2032be60a902SHaavard Skinnemoen * Legacy unlocking (e.g. Intel J3) -> 2033be60a902SHaavard Skinnemoen * unlock only one sector. This will 2034be60a902SHaavard Skinnemoen * unlock all sectors. 2035be60a902SHaavard Skinnemoen */ 2036be60a902SHaavard Skinnemoen flash_real_protect (&flash_info[i], 0, 0); 203759829cc1SJean-Christophe PLAGNIOL-VILLARD 2038be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 1; 203959829cc1SJean-Christophe PLAGNIOL-VILLARD 2040be60a902SHaavard Skinnemoen /* 2041be60a902SHaavard Skinnemoen * Manually mark other sectors as 2042be60a902SHaavard Skinnemoen * unlocked (unprotected) 2043be60a902SHaavard Skinnemoen */ 2044be60a902SHaavard Skinnemoen for (k = 1; k < flash_info[i].sector_count; k++) 2045be60a902SHaavard Skinnemoen flash_info[i].protect[k] = 0; 2046be60a902SHaavard Skinnemoen } else { 2047be60a902SHaavard Skinnemoen /* 2048be60a902SHaavard Skinnemoen * No legancy unlocking -> unlock all sectors 2049be60a902SHaavard Skinnemoen */ 2050be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_CLEAR, 2051be60a902SHaavard Skinnemoen flash_info[i].start[0], 2052be60a902SHaavard Skinnemoen flash_info[i].start[0] 2053be60a902SHaavard Skinnemoen + flash_info[i].size - 1, 2054be60a902SHaavard Skinnemoen &flash_info[i]); 205559829cc1SJean-Christophe PLAGNIOL-VILLARD } 205659829cc1SJean-Christophe PLAGNIOL-VILLARD } 20576d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */ 205859829cc1SJean-Christophe PLAGNIOL-VILLARD } 205959829cc1SJean-Christophe PLAGNIOL-VILLARD 2060be60a902SHaavard Skinnemoen /* Monitor protection ON by default */ 20616d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE) 2062be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 20636d0f6bcfSJean-Christophe PLAGNIOL-VILLARD CONFIG_SYS_MONITOR_BASE, 20646d0f6bcfSJean-Christophe PLAGNIOL-VILLARD CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, 20656d0f6bcfSJean-Christophe PLAGNIOL-VILLARD flash_get_info(CONFIG_SYS_MONITOR_BASE)); 2066be60a902SHaavard Skinnemoen #endif 206759829cc1SJean-Christophe PLAGNIOL-VILLARD 2068be60a902SHaavard Skinnemoen /* Environment protection ON by default */ 20695a1aceb0SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_ENV_IS_IN_FLASH 2070be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 20710e8d1586SJean-Christophe PLAGNIOL-VILLARD CONFIG_ENV_ADDR, 20720e8d1586SJean-Christophe PLAGNIOL-VILLARD CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1, 20730e8d1586SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CONFIG_ENV_ADDR)); 2074be60a902SHaavard Skinnemoen #endif 2075be60a902SHaavard Skinnemoen 2076be60a902SHaavard Skinnemoen /* Redundant environment protection ON by default */ 20770e8d1586SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_ENV_ADDR_REDUND 2078be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 20790e8d1586SJean-Christophe PLAGNIOL-VILLARD CONFIG_ENV_ADDR_REDUND, 20800e8d1586SJean-Christophe PLAGNIOL-VILLARD CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SIZE_REDUND - 1, 20810e8d1586SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CONFIG_ENV_ADDR_REDUND)); 2082be60a902SHaavard Skinnemoen #endif 2083c63ad632SMatthias Fuchs 20846d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) 2085c63ad632SMatthias Fuchs for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) { 2086c63ad632SMatthias Fuchs debug("autoprotecting from %08x to %08x\n", 2087c63ad632SMatthias Fuchs apl[i].start, apl[i].start + apl[i].size - 1); 2088c63ad632SMatthias Fuchs flash_protect (FLAG_PROTECT_SET, 2089c63ad632SMatthias Fuchs apl[i].start, 2090c63ad632SMatthias Fuchs apl[i].start + apl[i].size - 1, 2091c63ad632SMatthias Fuchs flash_get_info(apl[i].start)); 2092c63ad632SMatthias Fuchs } 2093c63ad632SMatthias Fuchs #endif 209491809ed5SPiotr Ziecik 209591809ed5SPiotr Ziecik #ifdef CONFIG_FLASH_CFI_MTD 209691809ed5SPiotr Ziecik cfi_mtd_init(); 209791809ed5SPiotr Ziecik #endif 209891809ed5SPiotr Ziecik 2099be60a902SHaavard Skinnemoen return (size); 210059829cc1SJean-Christophe PLAGNIOL-VILLARD } 2101