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 }; 16159829cc1SJean-Christophe PLAGNIOL-VILLARD 1626d0f6bcfSJean-Christophe PLAGNIOL-VILLARD /* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */ 1636d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT 1646d0f6bcfSJean-Christophe PLAGNIOL-VILLARD # define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS_DETECT 16559829cc1SJean-Christophe PLAGNIOL-VILLARD #else 1666d0f6bcfSJean-Christophe PLAGNIOL-VILLARD # define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS 16759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 16859829cc1SJean-Christophe PLAGNIOL-VILLARD 1692a112b23SWolfgang Denk flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */ 1702a112b23SWolfgang Denk 17159829cc1SJean-Christophe PLAGNIOL-VILLARD /* 17259829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if chip width is defined. If not, start detecting with 8bit. 17359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1746d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_CFI_WIDTH 1756d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_8BIT 17659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 17759829cc1SJean-Christophe PLAGNIOL-VILLARD 17859829cc1SJean-Christophe PLAGNIOL-VILLARD typedef unsigned long flash_sect_t; 17959829cc1SJean-Christophe PLAGNIOL-VILLARD 180e23741f4SHaavard Skinnemoen /* CFI standard query structure */ 181e23741f4SHaavard Skinnemoen struct cfi_qry { 182e23741f4SHaavard Skinnemoen u8 qry[3]; 183e23741f4SHaavard Skinnemoen u16 p_id; 184e23741f4SHaavard Skinnemoen u16 p_adr; 185e23741f4SHaavard Skinnemoen u16 a_id; 186e23741f4SHaavard Skinnemoen u16 a_adr; 187e23741f4SHaavard Skinnemoen u8 vcc_min; 188e23741f4SHaavard Skinnemoen u8 vcc_max; 189e23741f4SHaavard Skinnemoen u8 vpp_min; 190e23741f4SHaavard Skinnemoen u8 vpp_max; 191e23741f4SHaavard Skinnemoen u8 word_write_timeout_typ; 192e23741f4SHaavard Skinnemoen u8 buf_write_timeout_typ; 193e23741f4SHaavard Skinnemoen u8 block_erase_timeout_typ; 194e23741f4SHaavard Skinnemoen u8 chip_erase_timeout_typ; 195e23741f4SHaavard Skinnemoen u8 word_write_timeout_max; 196e23741f4SHaavard Skinnemoen u8 buf_write_timeout_max; 197e23741f4SHaavard Skinnemoen u8 block_erase_timeout_max; 198e23741f4SHaavard Skinnemoen u8 chip_erase_timeout_max; 199e23741f4SHaavard Skinnemoen u8 dev_size; 200e23741f4SHaavard Skinnemoen u16 interface_desc; 201e23741f4SHaavard Skinnemoen u16 max_buf_write_size; 202e23741f4SHaavard Skinnemoen u8 num_erase_regions; 203e23741f4SHaavard Skinnemoen u32 erase_region_info[NUM_ERASE_REGIONS]; 204e23741f4SHaavard Skinnemoen } __attribute__((packed)); 205e23741f4SHaavard Skinnemoen 206e23741f4SHaavard Skinnemoen struct cfi_pri_hdr { 207e23741f4SHaavard Skinnemoen u8 pri[3]; 208e23741f4SHaavard Skinnemoen u8 major_version; 209e23741f4SHaavard Skinnemoen u8 minor_version; 210e23741f4SHaavard Skinnemoen } __attribute__((packed)); 211e23741f4SHaavard Skinnemoen 212cdbaefb5SHaavard Skinnemoen static void flash_write8(u8 value, void *addr) 213cdbaefb5SHaavard Skinnemoen { 214cdbaefb5SHaavard Skinnemoen __raw_writeb(value, addr); 215cdbaefb5SHaavard Skinnemoen } 216cdbaefb5SHaavard Skinnemoen 217cdbaefb5SHaavard Skinnemoen static void flash_write16(u16 value, void *addr) 218cdbaefb5SHaavard Skinnemoen { 219cdbaefb5SHaavard Skinnemoen __raw_writew(value, addr); 220cdbaefb5SHaavard Skinnemoen } 221cdbaefb5SHaavard Skinnemoen 222cdbaefb5SHaavard Skinnemoen static void flash_write32(u32 value, void *addr) 223cdbaefb5SHaavard Skinnemoen { 224cdbaefb5SHaavard Skinnemoen __raw_writel(value, addr); 225cdbaefb5SHaavard Skinnemoen } 226cdbaefb5SHaavard Skinnemoen 227cdbaefb5SHaavard Skinnemoen static void flash_write64(u64 value, void *addr) 228cdbaefb5SHaavard Skinnemoen { 229cdbaefb5SHaavard Skinnemoen /* No architectures currently implement __raw_writeq() */ 230cdbaefb5SHaavard Skinnemoen *(volatile u64 *)addr = value; 231cdbaefb5SHaavard Skinnemoen } 232cdbaefb5SHaavard Skinnemoen 233cdbaefb5SHaavard Skinnemoen static u8 flash_read8(void *addr) 234cdbaefb5SHaavard Skinnemoen { 235cdbaefb5SHaavard Skinnemoen return __raw_readb(addr); 236cdbaefb5SHaavard Skinnemoen } 237cdbaefb5SHaavard Skinnemoen 238cdbaefb5SHaavard Skinnemoen static u16 flash_read16(void *addr) 239cdbaefb5SHaavard Skinnemoen { 240cdbaefb5SHaavard Skinnemoen return __raw_readw(addr); 241cdbaefb5SHaavard Skinnemoen } 242cdbaefb5SHaavard Skinnemoen 243cdbaefb5SHaavard Skinnemoen static u32 flash_read32(void *addr) 244cdbaefb5SHaavard Skinnemoen { 245cdbaefb5SHaavard Skinnemoen return __raw_readl(addr); 246cdbaefb5SHaavard Skinnemoen } 247cdbaefb5SHaavard Skinnemoen 24897bf85d7SDaniel Hellstrom static u64 __flash_read64(void *addr) 249cdbaefb5SHaavard Skinnemoen { 250cdbaefb5SHaavard Skinnemoen /* No architectures currently implement __raw_readq() */ 251cdbaefb5SHaavard Skinnemoen return *(volatile u64 *)addr; 252cdbaefb5SHaavard Skinnemoen } 253cdbaefb5SHaavard Skinnemoen 25497bf85d7SDaniel Hellstrom u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64"))); 25597bf85d7SDaniel Hellstrom 256be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 257be60a902SHaavard Skinnemoen */ 2586d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE) 259be60a902SHaavard Skinnemoen static flash_info_t *flash_get_info(ulong base) 260be60a902SHaavard Skinnemoen { 261be60a902SHaavard Skinnemoen int i; 262be60a902SHaavard Skinnemoen flash_info_t * info = 0; 263be60a902SHaavard Skinnemoen 2646d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { 265be60a902SHaavard Skinnemoen info = & flash_info[i]; 266be60a902SHaavard Skinnemoen if (info->size && info->start[0] <= base && 267be60a902SHaavard Skinnemoen base <= info->start[0] + info->size - 1) 268be60a902SHaavard Skinnemoen break; 269be60a902SHaavard Skinnemoen } 270be60a902SHaavard Skinnemoen 2716d0f6bcfSJean-Christophe PLAGNIOL-VILLARD return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info; 272be60a902SHaavard Skinnemoen } 27359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 27459829cc1SJean-Christophe PLAGNIOL-VILLARD 27512d30aa7SHaavard Skinnemoen unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect) 27612d30aa7SHaavard Skinnemoen { 27712d30aa7SHaavard Skinnemoen if (sect != (info->sector_count - 1)) 27812d30aa7SHaavard Skinnemoen return info->start[sect + 1] - info->start[sect]; 27912d30aa7SHaavard Skinnemoen else 28012d30aa7SHaavard Skinnemoen return info->start[0] + info->size - info->start[sect]; 28112d30aa7SHaavard Skinnemoen } 28212d30aa7SHaavard Skinnemoen 28359829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 28459829cc1SJean-Christophe PLAGNIOL-VILLARD * create an address based on the offset and the port width 28559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 28612d30aa7SHaavard Skinnemoen static inline void * 28712d30aa7SHaavard Skinnemoen flash_map (flash_info_t * info, flash_sect_t sect, uint offset) 28859829cc1SJean-Christophe PLAGNIOL-VILLARD { 28912d30aa7SHaavard Skinnemoen unsigned int byte_offset = offset * info->portwidth; 29012d30aa7SHaavard Skinnemoen 29112d30aa7SHaavard Skinnemoen return map_physmem(info->start[sect] + byte_offset, 29212d30aa7SHaavard Skinnemoen flash_sector_size(info, sect) - byte_offset, 29312d30aa7SHaavard Skinnemoen MAP_NOCACHE); 29412d30aa7SHaavard Skinnemoen } 29512d30aa7SHaavard Skinnemoen 29612d30aa7SHaavard Skinnemoen static inline void flash_unmap(flash_info_t *info, flash_sect_t sect, 29712d30aa7SHaavard Skinnemoen unsigned int offset, void *addr) 29812d30aa7SHaavard Skinnemoen { 29912d30aa7SHaavard Skinnemoen unsigned int byte_offset = offset * info->portwidth; 30012d30aa7SHaavard Skinnemoen 30112d30aa7SHaavard Skinnemoen unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset); 30259829cc1SJean-Christophe PLAGNIOL-VILLARD } 30359829cc1SJean-Christophe PLAGNIOL-VILLARD 304be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 305be60a902SHaavard Skinnemoen * make a proper sized command based on the port and chip widths 306be60a902SHaavard Skinnemoen */ 3077288f972SSebastian Siewior static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf) 308be60a902SHaavard Skinnemoen { 309be60a902SHaavard Skinnemoen int i; 31093c56f21SVasiliy Leoenenko int cword_offset; 31193c56f21SVasiliy Leoenenko int cp_offset; 3126d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 313340ccb26SSebastian Siewior u32 cmd_le = cpu_to_le32(cmd); 314340ccb26SSebastian Siewior #endif 31593c56f21SVasiliy Leoenenko uchar val; 316be60a902SHaavard Skinnemoen uchar *cp = (uchar *) cmdbuf; 317be60a902SHaavard Skinnemoen 31893c56f21SVasiliy Leoenenko for (i = info->portwidth; i > 0; i--){ 31993c56f21SVasiliy Leoenenko cword_offset = (info->portwidth-i)%info->chipwidth; 3206d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 32193c56f21SVasiliy Leoenenko cp_offset = info->portwidth - i; 322340ccb26SSebastian Siewior val = *((uchar*)&cmd_le + cword_offset); 323be60a902SHaavard Skinnemoen #else 32493c56f21SVasiliy Leoenenko cp_offset = i - 1; 3257288f972SSebastian Siewior val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1); 326be60a902SHaavard Skinnemoen #endif 3277288f972SSebastian Siewior cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val; 32893c56f21SVasiliy Leoenenko } 329be60a902SHaavard Skinnemoen } 330be60a902SHaavard Skinnemoen 33159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 33259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 33359829cc1SJean-Christophe PLAGNIOL-VILLARD * Debug support 33459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3353055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data) 33659829cc1SJean-Christophe PLAGNIOL-VILLARD { 33759829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 33859829cc1SJean-Christophe PLAGNIOL-VILLARD char *cp; 33959829cc1SJean-Christophe PLAGNIOL-VILLARD 34059829cc1SJean-Christophe PLAGNIOL-VILLARD cp = (unsigned char *) &data; 34159829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < 8; i++) 34259829cc1SJean-Christophe PLAGNIOL-VILLARD sprintf (&str[i * 2], "%2.2x", *cp++); 34359829cc1SJean-Christophe PLAGNIOL-VILLARD } 344be60a902SHaavard Skinnemoen 345e23741f4SHaavard Skinnemoen static void flash_printqry (struct cfi_qry *qry) 34659829cc1SJean-Christophe PLAGNIOL-VILLARD { 347e23741f4SHaavard Skinnemoen u8 *p = (u8 *)qry; 34859829cc1SJean-Christophe PLAGNIOL-VILLARD int x, y; 34959829cc1SJean-Christophe PLAGNIOL-VILLARD 350e23741f4SHaavard Skinnemoen for (x = 0; x < sizeof(struct cfi_qry); x += 16) { 351e23741f4SHaavard Skinnemoen debug("%02x : ", x); 352e23741f4SHaavard Skinnemoen for (y = 0; y < 16; y++) 353e23741f4SHaavard Skinnemoen debug("%2.2x ", p[x + y]); 35459829cc1SJean-Christophe PLAGNIOL-VILLARD debug(" "); 35559829cc1SJean-Christophe PLAGNIOL-VILLARD for (y = 0; y < 16; y++) { 356e23741f4SHaavard Skinnemoen unsigned char c = p[x + y]; 357e23741f4SHaavard Skinnemoen if (c >= 0x20 && c <= 0x7e) 358cdbaefb5SHaavard Skinnemoen debug("%c", c); 359e23741f4SHaavard Skinnemoen else 36059829cc1SJean-Christophe PLAGNIOL-VILLARD debug("."); 36159829cc1SJean-Christophe PLAGNIOL-VILLARD } 36259829cc1SJean-Christophe PLAGNIOL-VILLARD debug("\n"); 36359829cc1SJean-Christophe PLAGNIOL-VILLARD } 36459829cc1SJean-Christophe PLAGNIOL-VILLARD } 36559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 36659829cc1SJean-Christophe PLAGNIOL-VILLARD 36759829cc1SJean-Christophe PLAGNIOL-VILLARD 36859829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 36959829cc1SJean-Christophe PLAGNIOL-VILLARD * read a character at a port width address 37059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3713055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset) 37259829cc1SJean-Christophe PLAGNIOL-VILLARD { 37359829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *cp; 37412d30aa7SHaavard Skinnemoen uchar retval; 37559829cc1SJean-Christophe PLAGNIOL-VILLARD 37612d30aa7SHaavard Skinnemoen cp = flash_map (info, 0, offset); 3776d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 37812d30aa7SHaavard Skinnemoen retval = flash_read8(cp); 37959829cc1SJean-Christophe PLAGNIOL-VILLARD #else 38012d30aa7SHaavard Skinnemoen retval = flash_read8(cp + info->portwidth - 1); 38159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 38212d30aa7SHaavard Skinnemoen flash_unmap (info, 0, offset, cp); 38312d30aa7SHaavard Skinnemoen return retval; 38459829cc1SJean-Christophe PLAGNIOL-VILLARD } 38559829cc1SJean-Christophe PLAGNIOL-VILLARD 38659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 38790447ecbSTor Krill * read a word at a port width address, assume 16bit bus 38890447ecbSTor Krill */ 38990447ecbSTor Krill static inline ushort flash_read_word (flash_info_t * info, uint offset) 39090447ecbSTor Krill { 39190447ecbSTor Krill ushort *addr, retval; 39290447ecbSTor Krill 39390447ecbSTor Krill addr = flash_map (info, 0, offset); 39490447ecbSTor Krill retval = flash_read16 (addr); 39590447ecbSTor Krill flash_unmap (info, 0, offset, addr); 39690447ecbSTor Krill return retval; 39790447ecbSTor Krill } 39890447ecbSTor Krill 39990447ecbSTor Krill 40090447ecbSTor Krill /*----------------------------------------------------------------------- 40159829cc1SJean-Christophe PLAGNIOL-VILLARD * read a long word by picking the least significant byte of each maximum 40259829cc1SJean-Christophe PLAGNIOL-VILLARD * port size word. Swap for ppc format. 40359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 4043055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect, 4053055793bSHaavard Skinnemoen uint offset) 40659829cc1SJean-Christophe PLAGNIOL-VILLARD { 40759829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *addr; 40859829cc1SJean-Christophe PLAGNIOL-VILLARD ulong retval; 40959829cc1SJean-Christophe PLAGNIOL-VILLARD 41059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 41159829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 41259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 41312d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 41459829cc1SJean-Christophe PLAGNIOL-VILLARD 41559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 41659829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("long addr is at %p info->portwidth = %d\n", addr, 41759829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth); 41859829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 4 * info->portwidth; x++) { 41912d30aa7SHaavard Skinnemoen debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x)); 42059829cc1SJean-Christophe PLAGNIOL-VILLARD } 42159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 4226d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 42312d30aa7SHaavard Skinnemoen retval = ((flash_read8(addr) << 16) | 42412d30aa7SHaavard Skinnemoen (flash_read8(addr + info->portwidth) << 24) | 42512d30aa7SHaavard Skinnemoen (flash_read8(addr + 2 * info->portwidth)) | 42612d30aa7SHaavard Skinnemoen (flash_read8(addr + 3 * info->portwidth) << 8)); 42759829cc1SJean-Christophe PLAGNIOL-VILLARD #else 42812d30aa7SHaavard Skinnemoen retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) | 42912d30aa7SHaavard Skinnemoen (flash_read8(addr + info->portwidth - 1) << 16) | 43012d30aa7SHaavard Skinnemoen (flash_read8(addr + 4 * info->portwidth - 1) << 8) | 43112d30aa7SHaavard Skinnemoen (flash_read8(addr + 3 * info->portwidth - 1))); 43259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 43312d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 43412d30aa7SHaavard Skinnemoen 43559829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 43659829cc1SJean-Christophe PLAGNIOL-VILLARD } 43759829cc1SJean-Christophe PLAGNIOL-VILLARD 438be60a902SHaavard Skinnemoen /* 439be60a902SHaavard Skinnemoen * Write a proper sized command to the correct address 44081b20cccSMichael Schwingen */ 441be60a902SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, 4427288f972SSebastian Siewior uint offset, u32 cmd) 44381b20cccSMichael Schwingen { 4447e5b9b47SHaavard Skinnemoen 445cdbaefb5SHaavard Skinnemoen void *addr; 446be60a902SHaavard Skinnemoen cfiword_t cword; 44781b20cccSMichael Schwingen 44812d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 449be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 450be60a902SHaavard Skinnemoen switch (info->portwidth) { 451be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 452cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd, 453be60a902SHaavard Skinnemoen cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 454cdbaefb5SHaavard Skinnemoen flash_write8(cword.c, addr); 455be60a902SHaavard Skinnemoen break; 456be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 457cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr, 458be60a902SHaavard Skinnemoen cmd, cword.w, 459be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 460cdbaefb5SHaavard Skinnemoen flash_write16(cword.w, addr); 461be60a902SHaavard Skinnemoen break; 462be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 463cdbaefb5SHaavard Skinnemoen debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr, 464be60a902SHaavard Skinnemoen cmd, cword.l, 465be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 466cdbaefb5SHaavard Skinnemoen flash_write32(cword.l, addr); 467be60a902SHaavard Skinnemoen break; 468be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 469be60a902SHaavard Skinnemoen #ifdef DEBUG 470be60a902SHaavard Skinnemoen { 471be60a902SHaavard Skinnemoen char str[20]; 472be60a902SHaavard Skinnemoen 473be60a902SHaavard Skinnemoen print_longlong (str, cword.ll); 474be60a902SHaavard Skinnemoen 475be60a902SHaavard Skinnemoen debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n", 476cdbaefb5SHaavard Skinnemoen addr, cmd, str, 477be60a902SHaavard Skinnemoen info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 47881b20cccSMichael Schwingen } 479be60a902SHaavard Skinnemoen #endif 480cdbaefb5SHaavard Skinnemoen flash_write64(cword.ll, addr); 48181b20cccSMichael Schwingen break; 48281b20cccSMichael Schwingen } 483be60a902SHaavard Skinnemoen 484be60a902SHaavard Skinnemoen /* Ensure all the instructions are fully finished */ 485be60a902SHaavard Skinnemoen sync(); 48612d30aa7SHaavard Skinnemoen 48712d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 48881b20cccSMichael Schwingen } 4897e5b9b47SHaavard Skinnemoen 490be60a902SHaavard Skinnemoen static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect) 491be60a902SHaavard Skinnemoen { 492be60a902SHaavard Skinnemoen flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START); 493be60a902SHaavard Skinnemoen flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK); 494be60a902SHaavard Skinnemoen } 495be60a902SHaavard Skinnemoen 496be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 497be60a902SHaavard Skinnemoen */ 498be60a902SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect, 499be60a902SHaavard Skinnemoen uint offset, uchar cmd) 500be60a902SHaavard Skinnemoen { 501cdbaefb5SHaavard Skinnemoen void *addr; 502be60a902SHaavard Skinnemoen cfiword_t cword; 503be60a902SHaavard Skinnemoen int retval; 504be60a902SHaavard Skinnemoen 50512d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 506be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 507be60a902SHaavard Skinnemoen 508cdbaefb5SHaavard Skinnemoen debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr); 509be60a902SHaavard Skinnemoen switch (info->portwidth) { 510be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 511cdbaefb5SHaavard Skinnemoen debug ("is= %x %x\n", flash_read8(addr), cword.c); 512cdbaefb5SHaavard Skinnemoen retval = (flash_read8(addr) == cword.c); 513be60a902SHaavard Skinnemoen break; 514be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 515cdbaefb5SHaavard Skinnemoen debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w); 516cdbaefb5SHaavard Skinnemoen retval = (flash_read16(addr) == cword.w); 517be60a902SHaavard Skinnemoen break; 518be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 51952514699SAndrew Klossner debug ("is= %8.8x %8.8lx\n", flash_read32(addr), cword.l); 520cdbaefb5SHaavard Skinnemoen retval = (flash_read32(addr) == cword.l); 521be60a902SHaavard Skinnemoen break; 522be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 523be60a902SHaavard Skinnemoen #ifdef DEBUG 524be60a902SHaavard Skinnemoen { 525be60a902SHaavard Skinnemoen char str1[20]; 526be60a902SHaavard Skinnemoen char str2[20]; 527be60a902SHaavard Skinnemoen 528cdbaefb5SHaavard Skinnemoen print_longlong (str1, flash_read64(addr)); 529be60a902SHaavard Skinnemoen print_longlong (str2, cword.ll); 530be60a902SHaavard Skinnemoen debug ("is= %s %s\n", str1, str2); 531be60a902SHaavard Skinnemoen } 532be60a902SHaavard Skinnemoen #endif 533cdbaefb5SHaavard Skinnemoen retval = (flash_read64(addr) == cword.ll); 534be60a902SHaavard Skinnemoen break; 535be60a902SHaavard Skinnemoen default: 536be60a902SHaavard Skinnemoen retval = 0; 537be60a902SHaavard Skinnemoen break; 538be60a902SHaavard Skinnemoen } 53912d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 54012d30aa7SHaavard Skinnemoen 541be60a902SHaavard Skinnemoen return retval; 542be60a902SHaavard Skinnemoen } 543be60a902SHaavard Skinnemoen 544be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 545be60a902SHaavard Skinnemoen */ 546be60a902SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect, 547be60a902SHaavard Skinnemoen uint offset, uchar cmd) 548be60a902SHaavard Skinnemoen { 549cdbaefb5SHaavard Skinnemoen void *addr; 550be60a902SHaavard Skinnemoen cfiword_t cword; 551be60a902SHaavard Skinnemoen int retval; 552be60a902SHaavard Skinnemoen 55312d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 554be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 555be60a902SHaavard Skinnemoen switch (info->portwidth) { 556be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 557cdbaefb5SHaavard Skinnemoen retval = ((flash_read8(addr) & cword.c) == cword.c); 558be60a902SHaavard Skinnemoen break; 559be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 560cdbaefb5SHaavard Skinnemoen retval = ((flash_read16(addr) & cword.w) == cword.w); 561be60a902SHaavard Skinnemoen break; 562be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 56347cc23cbSStefan Roese retval = ((flash_read32(addr) & cword.l) == cword.l); 564be60a902SHaavard Skinnemoen break; 565be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 566cdbaefb5SHaavard Skinnemoen retval = ((flash_read64(addr) & cword.ll) == cword.ll); 567be60a902SHaavard Skinnemoen break; 568be60a902SHaavard Skinnemoen default: 569be60a902SHaavard Skinnemoen retval = 0; 570be60a902SHaavard Skinnemoen break; 571be60a902SHaavard Skinnemoen } 57212d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 57312d30aa7SHaavard Skinnemoen 574be60a902SHaavard Skinnemoen return retval; 575be60a902SHaavard Skinnemoen } 576be60a902SHaavard Skinnemoen 577be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 578be60a902SHaavard Skinnemoen */ 579be60a902SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect, 580be60a902SHaavard Skinnemoen uint offset, uchar cmd) 581be60a902SHaavard Skinnemoen { 582cdbaefb5SHaavard Skinnemoen void *addr; 583be60a902SHaavard Skinnemoen cfiword_t cword; 584be60a902SHaavard Skinnemoen int retval; 585be60a902SHaavard Skinnemoen 58612d30aa7SHaavard Skinnemoen addr = flash_map (info, sect, offset); 587be60a902SHaavard Skinnemoen flash_make_cmd (info, cmd, &cword); 588be60a902SHaavard Skinnemoen switch (info->portwidth) { 589be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 590fb8c061eSStefan Roese retval = flash_read8(addr) != flash_read8(addr); 591be60a902SHaavard Skinnemoen break; 592be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 593fb8c061eSStefan Roese retval = flash_read16(addr) != flash_read16(addr); 594be60a902SHaavard Skinnemoen break; 595be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 596fb8c061eSStefan Roese retval = flash_read32(addr) != flash_read32(addr); 597be60a902SHaavard Skinnemoen break; 598be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 599*9abda6baSWolfgang Denk retval = ( (flash_read32( addr ) != flash_read32( addr )) || 600*9abda6baSWolfgang Denk (flash_read32(addr+4) != flash_read32(addr+4)) ); 601be60a902SHaavard Skinnemoen break; 602be60a902SHaavard Skinnemoen default: 603be60a902SHaavard Skinnemoen retval = 0; 604be60a902SHaavard Skinnemoen break; 605be60a902SHaavard Skinnemoen } 60612d30aa7SHaavard Skinnemoen flash_unmap(info, sect, offset, addr); 60712d30aa7SHaavard Skinnemoen 608be60a902SHaavard Skinnemoen return retval; 609be60a902SHaavard Skinnemoen } 610be60a902SHaavard Skinnemoen 611be60a902SHaavard Skinnemoen /* 612be60a902SHaavard Skinnemoen * flash_is_busy - check to see if the flash is busy 613be60a902SHaavard Skinnemoen * 614be60a902SHaavard Skinnemoen * This routine checks the status of the chip and returns true if the 615be60a902SHaavard Skinnemoen * chip is busy. 616be60a902SHaavard Skinnemoen */ 617be60a902SHaavard Skinnemoen static int flash_is_busy (flash_info_t * info, flash_sect_t sect) 618be60a902SHaavard Skinnemoen { 619be60a902SHaavard Skinnemoen int retval; 620be60a902SHaavard Skinnemoen 62181b20cccSMichael Schwingen switch (info->vendor) { 6229c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 62381b20cccSMichael Schwingen case CFI_CMDSET_INTEL_STANDARD: 62481b20cccSMichael Schwingen case CFI_CMDSET_INTEL_EXTENDED: 625be60a902SHaavard Skinnemoen retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); 62681b20cccSMichael Schwingen break; 62781b20cccSMichael Schwingen case CFI_CMDSET_AMD_STANDARD: 62881b20cccSMichael Schwingen case CFI_CMDSET_AMD_EXTENDED: 629be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 63081b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 631be60a902SHaavard Skinnemoen #endif 632be60a902SHaavard Skinnemoen retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); 633be60a902SHaavard Skinnemoen break; 634be60a902SHaavard Skinnemoen default: 635be60a902SHaavard Skinnemoen retval = 0; 636be60a902SHaavard Skinnemoen } 637be60a902SHaavard Skinnemoen debug ("flash_is_busy: %d\n", retval); 638be60a902SHaavard Skinnemoen return retval; 639be60a902SHaavard Skinnemoen } 640be60a902SHaavard Skinnemoen 641be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 642be60a902SHaavard Skinnemoen * wait for XSR.7 to be set. Time out with an error if it does not. 643be60a902SHaavard Skinnemoen * This routine does not set the flash to read-array mode. 644be60a902SHaavard Skinnemoen */ 645be60a902SHaavard Skinnemoen static int flash_status_check (flash_info_t * info, flash_sect_t sector, 646be60a902SHaavard Skinnemoen ulong tout, char *prompt) 647be60a902SHaavard Skinnemoen { 648be60a902SHaavard Skinnemoen ulong start; 649be60a902SHaavard Skinnemoen 6506d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if CONFIG_SYS_HZ != 1000 6516d0f6bcfSJean-Christophe PLAGNIOL-VILLARD tout *= CONFIG_SYS_HZ/1000; 652be60a902SHaavard Skinnemoen #endif 653be60a902SHaavard Skinnemoen 654be60a902SHaavard Skinnemoen /* Wait for command completion */ 655be60a902SHaavard Skinnemoen start = get_timer (0); 656be60a902SHaavard Skinnemoen while (flash_is_busy (info, sector)) { 657be60a902SHaavard Skinnemoen if (get_timer (start) > tout) { 658be60a902SHaavard Skinnemoen printf ("Flash %s timeout at address %lx data %lx\n", 659be60a902SHaavard Skinnemoen prompt, info->start[sector], 660be60a902SHaavard Skinnemoen flash_read_long (info, sector, 0)); 661be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, info->cmd_reset); 662be60a902SHaavard Skinnemoen return ERR_TIMOUT; 663be60a902SHaavard Skinnemoen } 664be60a902SHaavard Skinnemoen udelay (1); /* also triggers watchdog */ 665be60a902SHaavard Skinnemoen } 666be60a902SHaavard Skinnemoen return ERR_OK; 667be60a902SHaavard Skinnemoen } 668be60a902SHaavard Skinnemoen 669be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 670be60a902SHaavard Skinnemoen * Wait for XSR.7 to be set, if it times out print an error, otherwise 671be60a902SHaavard Skinnemoen * do a full status check. 672be60a902SHaavard Skinnemoen * 673be60a902SHaavard Skinnemoen * This routine sets the flash to read-array mode. 674be60a902SHaavard Skinnemoen */ 675be60a902SHaavard Skinnemoen static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, 676be60a902SHaavard Skinnemoen ulong tout, char *prompt) 677be60a902SHaavard Skinnemoen { 678be60a902SHaavard Skinnemoen int retcode; 679be60a902SHaavard Skinnemoen 680be60a902SHaavard Skinnemoen retcode = flash_status_check (info, sector, tout, prompt); 681be60a902SHaavard Skinnemoen switch (info->vendor) { 6829c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 683be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 684be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 6850d01f66dSEd Swarthout if ((retcode != ERR_OK) 686be60a902SHaavard Skinnemoen && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { 687be60a902SHaavard Skinnemoen retcode = ERR_INVAL; 688be60a902SHaavard Skinnemoen printf ("Flash %s error at address %lx\n", prompt, 689be60a902SHaavard Skinnemoen info->start[sector]); 690be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | 691be60a902SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 692be60a902SHaavard Skinnemoen puts ("Command Sequence Error.\n"); 693be60a902SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 694be60a902SHaavard Skinnemoen FLASH_STATUS_ECLBS)) { 695be60a902SHaavard Skinnemoen puts ("Block Erase Error.\n"); 696be60a902SHaavard Skinnemoen retcode = ERR_NOT_ERASED; 697be60a902SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 698be60a902SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 699be60a902SHaavard Skinnemoen puts ("Locking Error\n"); 700be60a902SHaavard Skinnemoen } 701be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { 702be60a902SHaavard Skinnemoen puts ("Block locked.\n"); 703be60a902SHaavard Skinnemoen retcode = ERR_PROTECTED; 704be60a902SHaavard Skinnemoen } 705be60a902SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) 706be60a902SHaavard Skinnemoen puts ("Vpp Low Error.\n"); 707be60a902SHaavard Skinnemoen } 708be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, info->cmd_reset); 709be60a902SHaavard Skinnemoen break; 710be60a902SHaavard Skinnemoen default: 71181b20cccSMichael Schwingen break; 71281b20cccSMichael Schwingen } 713be60a902SHaavard Skinnemoen return retcode; 71481b20cccSMichael Schwingen } 715be60a902SHaavard Skinnemoen 716be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 717be60a902SHaavard Skinnemoen */ 718be60a902SHaavard Skinnemoen static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) 719be60a902SHaavard Skinnemoen { 7206d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 721be60a902SHaavard Skinnemoen unsigned short w; 722be60a902SHaavard Skinnemoen unsigned int l; 723be60a902SHaavard Skinnemoen unsigned long long ll; 724be60a902SHaavard Skinnemoen #endif 725be60a902SHaavard Skinnemoen 726be60a902SHaavard Skinnemoen switch (info->portwidth) { 727be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 728be60a902SHaavard Skinnemoen cword->c = c; 729be60a902SHaavard Skinnemoen break; 730be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 7316d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 732be60a902SHaavard Skinnemoen w = c; 733be60a902SHaavard Skinnemoen w <<= 8; 734be60a902SHaavard Skinnemoen cword->w = (cword->w >> 8) | w; 73581b20cccSMichael Schwingen #else 736be60a902SHaavard Skinnemoen cword->w = (cword->w << 8) | c; 737be60a902SHaavard Skinnemoen #endif 738be60a902SHaavard Skinnemoen break; 739be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 7406d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 741be60a902SHaavard Skinnemoen l = c; 742be60a902SHaavard Skinnemoen l <<= 24; 743be60a902SHaavard Skinnemoen cword->l = (cword->l >> 8) | l; 744be60a902SHaavard Skinnemoen #else 745be60a902SHaavard Skinnemoen cword->l = (cword->l << 8) | c; 746be60a902SHaavard Skinnemoen #endif 747be60a902SHaavard Skinnemoen break; 748be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 7496d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA) 750be60a902SHaavard Skinnemoen ll = c; 751be60a902SHaavard Skinnemoen ll <<= 56; 752be60a902SHaavard Skinnemoen cword->ll = (cword->ll >> 8) | ll; 753be60a902SHaavard Skinnemoen #else 754be60a902SHaavard Skinnemoen cword->ll = (cword->ll << 8) | c; 755be60a902SHaavard Skinnemoen #endif 756be60a902SHaavard Skinnemoen break; 757be60a902SHaavard Skinnemoen } 758be60a902SHaavard Skinnemoen } 759be60a902SHaavard Skinnemoen 760be60a902SHaavard Skinnemoen /* loop through the sectors from the highest address when the passed 761be60a902SHaavard Skinnemoen * address is greater or equal to the sector address we have a match 762be60a902SHaavard Skinnemoen */ 763be60a902SHaavard Skinnemoen static flash_sect_t find_sector (flash_info_t * info, ulong addr) 76481b20cccSMichael Schwingen { 765be60a902SHaavard Skinnemoen flash_sect_t sector; 766be60a902SHaavard Skinnemoen 767be60a902SHaavard Skinnemoen for (sector = info->sector_count - 1; sector >= 0; sector--) { 768be60a902SHaavard Skinnemoen if (addr >= info->start[sector]) 769be60a902SHaavard Skinnemoen break; 77081b20cccSMichael Schwingen } 771be60a902SHaavard Skinnemoen return sector; 77259829cc1SJean-Christophe PLAGNIOL-VILLARD } 77359829cc1SJean-Christophe PLAGNIOL-VILLARD 77459829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 77559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 776be60a902SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest, 777be60a902SHaavard Skinnemoen cfiword_t cword) 77859829cc1SJean-Christophe PLAGNIOL-VILLARD { 779cdbaefb5SHaavard Skinnemoen void *dstaddr; 780be60a902SHaavard Skinnemoen int flag; 7810d01f66dSEd Swarthout flash_sect_t sect; 78259829cc1SJean-Christophe PLAGNIOL-VILLARD 78312d30aa7SHaavard Skinnemoen dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE); 784be60a902SHaavard Skinnemoen 785be60a902SHaavard Skinnemoen /* Check if Flash is (sufficiently) erased */ 786be60a902SHaavard Skinnemoen switch (info->portwidth) { 787be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 788cdbaefb5SHaavard Skinnemoen flag = ((flash_read8(dstaddr) & cword.c) == cword.c); 789be60a902SHaavard Skinnemoen break; 790be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 791cdbaefb5SHaavard Skinnemoen flag = ((flash_read16(dstaddr) & cword.w) == cword.w); 792be60a902SHaavard Skinnemoen break; 793be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 794cdbaefb5SHaavard Skinnemoen flag = ((flash_read32(dstaddr) & cword.l) == cword.l); 795be60a902SHaavard Skinnemoen break; 796be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 797cdbaefb5SHaavard Skinnemoen flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll); 798be60a902SHaavard Skinnemoen break; 799be60a902SHaavard Skinnemoen default: 80012d30aa7SHaavard Skinnemoen flag = 0; 80112d30aa7SHaavard Skinnemoen break; 80212d30aa7SHaavard Skinnemoen } 80312d30aa7SHaavard Skinnemoen if (!flag) { 80412d30aa7SHaavard Skinnemoen unmap_physmem(dstaddr, info->portwidth); 8050dc80e27SStefan Roese return ERR_NOT_ERASED; 806be60a902SHaavard Skinnemoen } 807be60a902SHaavard Skinnemoen 808be60a902SHaavard Skinnemoen /* Disable interrupts which might cause a timeout here */ 809be60a902SHaavard Skinnemoen flag = disable_interrupts (); 810be60a902SHaavard Skinnemoen 811be60a902SHaavard Skinnemoen switch (info->vendor) { 8129c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 813be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 814be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 815be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); 816be60a902SHaavard Skinnemoen flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE); 817be60a902SHaavard Skinnemoen break; 818be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 819be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 820be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 821be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_LEGACY: 822be60a902SHaavard Skinnemoen #endif 8230d01f66dSEd Swarthout sect = find_sector(info, dest); 8240d01f66dSEd Swarthout flash_unlock_seq (info, sect); 8250d01f66dSEd Swarthout flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE); 82659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 82759829cc1SJean-Christophe PLAGNIOL-VILLARD } 82859829cc1SJean-Christophe PLAGNIOL-VILLARD 829be60a902SHaavard Skinnemoen switch (info->portwidth) { 830be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 831cdbaefb5SHaavard Skinnemoen flash_write8(cword.c, dstaddr); 832be60a902SHaavard Skinnemoen break; 833be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 834cdbaefb5SHaavard Skinnemoen flash_write16(cword.w, dstaddr); 835be60a902SHaavard Skinnemoen break; 836be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 837cdbaefb5SHaavard Skinnemoen flash_write32(cword.l, dstaddr); 838be60a902SHaavard Skinnemoen break; 839be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 840cdbaefb5SHaavard Skinnemoen flash_write64(cword.ll, dstaddr); 841be60a902SHaavard Skinnemoen break; 84259829cc1SJean-Christophe PLAGNIOL-VILLARD } 843be60a902SHaavard Skinnemoen 844be60a902SHaavard Skinnemoen /* re-enable interrupts if necessary */ 845be60a902SHaavard Skinnemoen if (flag) 846be60a902SHaavard Skinnemoen enable_interrupts (); 847be60a902SHaavard Skinnemoen 84812d30aa7SHaavard Skinnemoen unmap_physmem(dstaddr, info->portwidth); 84912d30aa7SHaavard Skinnemoen 850be60a902SHaavard Skinnemoen return flash_full_status_check (info, find_sector (info, dest), 851be60a902SHaavard Skinnemoen info->write_tout, "write"); 852be60a902SHaavard Skinnemoen } 853be60a902SHaavard Skinnemoen 8546d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE 855be60a902SHaavard Skinnemoen 856be60a902SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, 857be60a902SHaavard Skinnemoen int len) 858be60a902SHaavard Skinnemoen { 859be60a902SHaavard Skinnemoen flash_sect_t sector; 860be60a902SHaavard Skinnemoen int cnt; 861be60a902SHaavard Skinnemoen int retcode; 862cdbaefb5SHaavard Skinnemoen void *src = cp; 86312d30aa7SHaavard Skinnemoen void *dst = map_physmem(dest, len, MAP_NOCACHE); 8640dc80e27SStefan Roese void *dst2 = dst; 8650dc80e27SStefan Roese int flag = 0; 86696ef831fSGuennadi Liakhovetski uint offset = 0; 86796ef831fSGuennadi Liakhovetski unsigned int shift; 8689c048b52SVasiliy Leoenenko uchar write_cmd; 869cdbaefb5SHaavard Skinnemoen 8700dc80e27SStefan Roese switch (info->portwidth) { 8710dc80e27SStefan Roese case FLASH_CFI_8BIT: 87296ef831fSGuennadi Liakhovetski shift = 0; 8730dc80e27SStefan Roese break; 8740dc80e27SStefan Roese case FLASH_CFI_16BIT: 87596ef831fSGuennadi Liakhovetski shift = 1; 8760dc80e27SStefan Roese break; 8770dc80e27SStefan Roese case FLASH_CFI_32BIT: 87896ef831fSGuennadi Liakhovetski shift = 2; 8790dc80e27SStefan Roese break; 8800dc80e27SStefan Roese case FLASH_CFI_64BIT: 88196ef831fSGuennadi Liakhovetski shift = 3; 8820dc80e27SStefan Roese break; 8830dc80e27SStefan Roese default: 8840dc80e27SStefan Roese retcode = ERR_INVAL; 8850dc80e27SStefan Roese goto out_unmap; 8860dc80e27SStefan Roese } 8870dc80e27SStefan Roese 88896ef831fSGuennadi Liakhovetski cnt = len >> shift; 88996ef831fSGuennadi Liakhovetski 8900dc80e27SStefan Roese while ((cnt-- > 0) && (flag == 0)) { 8910dc80e27SStefan Roese switch (info->portwidth) { 8920dc80e27SStefan Roese case FLASH_CFI_8BIT: 8930dc80e27SStefan Roese flag = ((flash_read8(dst2) & flash_read8(src)) == 8940dc80e27SStefan Roese flash_read8(src)); 8950dc80e27SStefan Roese src += 1, dst2 += 1; 8960dc80e27SStefan Roese break; 8970dc80e27SStefan Roese case FLASH_CFI_16BIT: 8980dc80e27SStefan Roese flag = ((flash_read16(dst2) & flash_read16(src)) == 8990dc80e27SStefan Roese flash_read16(src)); 9000dc80e27SStefan Roese src += 2, dst2 += 2; 9010dc80e27SStefan Roese break; 9020dc80e27SStefan Roese case FLASH_CFI_32BIT: 9030dc80e27SStefan Roese flag = ((flash_read32(dst2) & flash_read32(src)) == 9040dc80e27SStefan Roese flash_read32(src)); 9050dc80e27SStefan Roese src += 4, dst2 += 4; 9060dc80e27SStefan Roese break; 9070dc80e27SStefan Roese case FLASH_CFI_64BIT: 9080dc80e27SStefan Roese flag = ((flash_read64(dst2) & flash_read64(src)) == 9090dc80e27SStefan Roese flash_read64(src)); 9100dc80e27SStefan Roese src += 8, dst2 += 8; 9110dc80e27SStefan Roese break; 9120dc80e27SStefan Roese } 9130dc80e27SStefan Roese } 9140dc80e27SStefan Roese if (!flag) { 9150dc80e27SStefan Roese retcode = ERR_NOT_ERASED; 9160dc80e27SStefan Roese goto out_unmap; 9170dc80e27SStefan Roese } 9180dc80e27SStefan Roese 9190dc80e27SStefan Roese src = cp; 920cdbaefb5SHaavard Skinnemoen sector = find_sector (info, dest); 921be60a902SHaavard Skinnemoen 922be60a902SHaavard Skinnemoen switch (info->vendor) { 9239c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 924be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 925be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 9269c048b52SVasiliy Leoenenko write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ? 9279c048b52SVasiliy Leoenenko FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER; 928be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 9299c048b52SVasiliy Leoenenko flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS); 9309c048b52SVasiliy Leoenenko flash_write_cmd (info, sector, 0, write_cmd); 931be60a902SHaavard Skinnemoen retcode = flash_status_check (info, sector, 932be60a902SHaavard Skinnemoen info->buffer_write_tout, 933be60a902SHaavard Skinnemoen "write to buffer"); 934be60a902SHaavard Skinnemoen if (retcode == ERR_OK) { 935be60a902SHaavard Skinnemoen /* reduce the number of loops by the width of 936be60a902SHaavard Skinnemoen * the port */ 93796ef831fSGuennadi Liakhovetski cnt = len >> shift; 93893c56f21SVasiliy Leoenenko flash_write_cmd (info, sector, 0, cnt - 1); 939be60a902SHaavard Skinnemoen while (cnt-- > 0) { 940be60a902SHaavard Skinnemoen switch (info->portwidth) { 941be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 942cdbaefb5SHaavard Skinnemoen flash_write8(flash_read8(src), dst); 943cdbaefb5SHaavard Skinnemoen src += 1, dst += 1; 944be60a902SHaavard Skinnemoen break; 945be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 946cdbaefb5SHaavard Skinnemoen flash_write16(flash_read16(src), dst); 947cdbaefb5SHaavard Skinnemoen src += 2, dst += 2; 948be60a902SHaavard Skinnemoen break; 949be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 950cdbaefb5SHaavard Skinnemoen flash_write32(flash_read32(src), dst); 951cdbaefb5SHaavard Skinnemoen src += 4, dst += 4; 952be60a902SHaavard Skinnemoen break; 953be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 954cdbaefb5SHaavard Skinnemoen flash_write64(flash_read64(src), dst); 955cdbaefb5SHaavard Skinnemoen src += 8, dst += 8; 956be60a902SHaavard Skinnemoen break; 957be60a902SHaavard Skinnemoen default: 95812d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 95912d30aa7SHaavard Skinnemoen goto out_unmap; 960be60a902SHaavard Skinnemoen } 961be60a902SHaavard Skinnemoen } 962be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, 963be60a902SHaavard Skinnemoen FLASH_CMD_WRITE_BUFFER_CONFIRM); 964be60a902SHaavard Skinnemoen retcode = flash_full_status_check ( 965be60a902SHaavard Skinnemoen info, sector, info->buffer_write_tout, 966be60a902SHaavard Skinnemoen "buffer write"); 967be60a902SHaavard Skinnemoen } 96812d30aa7SHaavard Skinnemoen 96912d30aa7SHaavard Skinnemoen break; 970be60a902SHaavard Skinnemoen 971be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 972be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 973be60a902SHaavard Skinnemoen flash_unlock_seq(info,0); 97496ef831fSGuennadi Liakhovetski 97596ef831fSGuennadi Liakhovetski #ifdef CONFIG_FLASH_SPANSION_S29WS_N 97696ef831fSGuennadi Liakhovetski offset = ((unsigned long)dst - info->start[sector]) >> shift; 97796ef831fSGuennadi Liakhovetski #endif 97896ef831fSGuennadi Liakhovetski flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER); 97996ef831fSGuennadi Liakhovetski cnt = len >> shift; 98096ef831fSGuennadi Liakhovetski flash_write_cmd(info, sector, offset, (uchar)cnt - 1); 981be60a902SHaavard Skinnemoen 982be60a902SHaavard Skinnemoen switch (info->portwidth) { 983be60a902SHaavard Skinnemoen case FLASH_CFI_8BIT: 984cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 985cdbaefb5SHaavard Skinnemoen flash_write8(flash_read8(src), dst); 986cdbaefb5SHaavard Skinnemoen src += 1, dst += 1; 987cdbaefb5SHaavard Skinnemoen } 988be60a902SHaavard Skinnemoen break; 989be60a902SHaavard Skinnemoen case FLASH_CFI_16BIT: 990cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 991cdbaefb5SHaavard Skinnemoen flash_write16(flash_read16(src), dst); 992cdbaefb5SHaavard Skinnemoen src += 2, dst += 2; 993cdbaefb5SHaavard Skinnemoen } 994be60a902SHaavard Skinnemoen break; 995be60a902SHaavard Skinnemoen case FLASH_CFI_32BIT: 996cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 997cdbaefb5SHaavard Skinnemoen flash_write32(flash_read32(src), dst); 998cdbaefb5SHaavard Skinnemoen src += 4, dst += 4; 999cdbaefb5SHaavard Skinnemoen } 1000be60a902SHaavard Skinnemoen break; 1001be60a902SHaavard Skinnemoen case FLASH_CFI_64BIT: 1002cdbaefb5SHaavard Skinnemoen while (cnt-- > 0) { 1003cdbaefb5SHaavard Skinnemoen flash_write64(flash_read64(src), dst); 1004cdbaefb5SHaavard Skinnemoen src += 8, dst += 8; 1005cdbaefb5SHaavard Skinnemoen } 1006be60a902SHaavard Skinnemoen break; 1007be60a902SHaavard Skinnemoen default: 100812d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 100912d30aa7SHaavard Skinnemoen goto out_unmap; 1010be60a902SHaavard Skinnemoen } 1011be60a902SHaavard Skinnemoen 1012be60a902SHaavard Skinnemoen flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); 1013be60a902SHaavard Skinnemoen retcode = flash_full_status_check (info, sector, 1014be60a902SHaavard Skinnemoen info->buffer_write_tout, 1015be60a902SHaavard Skinnemoen "buffer write"); 101612d30aa7SHaavard Skinnemoen break; 1017be60a902SHaavard Skinnemoen 1018be60a902SHaavard Skinnemoen default: 1019be60a902SHaavard Skinnemoen debug ("Unknown Command Set\n"); 102012d30aa7SHaavard Skinnemoen retcode = ERR_INVAL; 102112d30aa7SHaavard Skinnemoen break; 1022be60a902SHaavard Skinnemoen } 102312d30aa7SHaavard Skinnemoen 102412d30aa7SHaavard Skinnemoen out_unmap: 102512d30aa7SHaavard Skinnemoen unmap_physmem(dst, len); 102612d30aa7SHaavard Skinnemoen return retcode; 1027be60a902SHaavard Skinnemoen } 10286d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */ 1029be60a902SHaavard Skinnemoen 103059829cc1SJean-Christophe PLAGNIOL-VILLARD 103159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 103259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 103359829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last) 103459829cc1SJean-Christophe PLAGNIOL-VILLARD { 103559829cc1SJean-Christophe PLAGNIOL-VILLARD int rcode = 0; 103659829cc1SJean-Christophe PLAGNIOL-VILLARD int prot; 103759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect; 103859829cc1SJean-Christophe PLAGNIOL-VILLARD 103959829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 104059829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Can't erase unknown flash type - aborted\n"); 104159829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 104259829cc1SJean-Christophe PLAGNIOL-VILLARD } 104359829cc1SJean-Christophe PLAGNIOL-VILLARD if ((s_first < 0) || (s_first > s_last)) { 104459829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("- no sectors to erase\n"); 104559829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 104659829cc1SJean-Christophe PLAGNIOL-VILLARD } 104759829cc1SJean-Christophe PLAGNIOL-VILLARD 104859829cc1SJean-Christophe PLAGNIOL-VILLARD prot = 0; 104959829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; ++sect) { 105059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect]) { 105159829cc1SJean-Christophe PLAGNIOL-VILLARD prot++; 105259829cc1SJean-Christophe PLAGNIOL-VILLARD } 105359829cc1SJean-Christophe PLAGNIOL-VILLARD } 105459829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) { 10557e5b9b47SHaavard Skinnemoen printf ("- Warning: %d protected sectors will not be erased!\n", 10567e5b9b47SHaavard Skinnemoen prot); 105759829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 105859829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 105959829cc1SJean-Christophe PLAGNIOL-VILLARD } 106059829cc1SJean-Christophe PLAGNIOL-VILLARD 106159829cc1SJean-Christophe PLAGNIOL-VILLARD 106259829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; sect++) { 106359829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect] == 0) { /* not protected */ 106459829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 10659c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 106659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 106759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 10687e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10697e5b9b47SHaavard Skinnemoen FLASH_CMD_CLEAR_STATUS); 10707e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10717e5b9b47SHaavard Skinnemoen FLASH_CMD_BLOCK_ERASE); 10727e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10737e5b9b47SHaavard Skinnemoen FLASH_CMD_ERASE_CONFIRM); 107459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 107559829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 107659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 107759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 10787e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 10797e5b9b47SHaavard Skinnemoen info->addr_unlock1, 10807e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 108159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 10827e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10837e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_SECTOR); 108459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 108581b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 108681b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 108781b20cccSMichael Schwingen flash_unlock_seq (info, 0); 10887e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, info->addr_unlock1, 10897e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 109081b20cccSMichael Schwingen flash_unlock_seq (info, 0); 10917e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 10927e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_SECTOR); 109381b20cccSMichael Schwingen break; 109481b20cccSMichael Schwingen #endif 109559829cc1SJean-Christophe PLAGNIOL-VILLARD default: 109659829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("Unkown flash vendor %d\n", 109759829cc1SJean-Christophe PLAGNIOL-VILLARD info->vendor); 109859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 109959829cc1SJean-Christophe PLAGNIOL-VILLARD } 110059829cc1SJean-Christophe PLAGNIOL-VILLARD 110159829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_full_status_check 110259829cc1SJean-Christophe PLAGNIOL-VILLARD (info, sect, info->erase_blk_tout, "erase")) { 110359829cc1SJean-Christophe PLAGNIOL-VILLARD rcode = 1; 110459829cc1SJean-Christophe PLAGNIOL-VILLARD } else 110559829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('.'); 110659829cc1SJean-Christophe PLAGNIOL-VILLARD } 110759829cc1SJean-Christophe PLAGNIOL-VILLARD } 110859829cc1SJean-Christophe PLAGNIOL-VILLARD puts (" done\n"); 110959829cc1SJean-Christophe PLAGNIOL-VILLARD return rcode; 111059829cc1SJean-Christophe PLAGNIOL-VILLARD } 111159829cc1SJean-Christophe PLAGNIOL-VILLARD 111259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 111359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 111459829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info) 111559829cc1SJean-Christophe PLAGNIOL-VILLARD { 111659829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 111759829cc1SJean-Christophe PLAGNIOL-VILLARD 111859829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 111959829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("missing or unknown FLASH type\n"); 112059829cc1SJean-Christophe PLAGNIOL-VILLARD return; 112159829cc1SJean-Christophe PLAGNIOL-VILLARD } 112259829cc1SJean-Christophe PLAGNIOL-VILLARD 112381b20cccSMichael Schwingen printf ("%s FLASH (%d x %d)", 112481b20cccSMichael Schwingen info->name, 112559829cc1SJean-Christophe PLAGNIOL-VILLARD (info->portwidth << 3), (info->chipwidth << 3)); 112681b20cccSMichael Schwingen if (info->size < 1024*1024) 112781b20cccSMichael Schwingen printf (" Size: %ld kB in %d Sectors\n", 112881b20cccSMichael Schwingen info->size >> 10, info->sector_count); 112981b20cccSMichael Schwingen else 113059829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" Size: %ld MB in %d Sectors\n", 113159829cc1SJean-Christophe PLAGNIOL-VILLARD info->size >> 20, info->sector_count); 113259829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" "); 113359829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 11349c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 11359c048b52SVasiliy Leoenenko printf ("Intel Prog Regions"); 11369c048b52SVasiliy Leoenenko break; 113759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 113859829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Standard"); 113959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 114059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 114159829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Extended"); 114259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 114359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 114459829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Standard"); 114559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 114659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 114759829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Extended"); 114859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 114981b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 115081b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 115181b20cccSMichael Schwingen printf ("AMD Legacy"); 115281b20cccSMichael Schwingen break; 115381b20cccSMichael Schwingen #endif 115459829cc1SJean-Christophe PLAGNIOL-VILLARD default: 115559829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Unknown (%d)", info->vendor); 115659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 115759829cc1SJean-Christophe PLAGNIOL-VILLARD } 115859829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X", 115959829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id, info->device_id); 116059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 116159829cc1SJean-Christophe PLAGNIOL-VILLARD printf("%04X", info->device_id2); 116259829cc1SJean-Christophe PLAGNIOL-VILLARD } 116359829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n", 116459829cc1SJean-Christophe PLAGNIOL-VILLARD info->erase_blk_tout, 116559829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout); 116659829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size > 1) { 11677e5b9b47SHaavard Skinnemoen printf (" Buffer write timeout: %ld ms, " 11687e5b9b47SHaavard Skinnemoen "buffer size: %d bytes\n", 116959829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout, 117059829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_size); 117159829cc1SJean-Christophe PLAGNIOL-VILLARD } 117259829cc1SJean-Christophe PLAGNIOL-VILLARD 117359829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("\n Sector Start Addresses:"); 117459829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; ++i) { 117559829cc1SJean-Christophe PLAGNIOL-VILLARD if ((i % 5) == 0) 117659829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n"); 11776d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_EMPTY_INFO 117859829cc1SJean-Christophe PLAGNIOL-VILLARD int k; 117959829cc1SJean-Christophe PLAGNIOL-VILLARD int size; 118059829cc1SJean-Christophe PLAGNIOL-VILLARD int erased; 118159829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long *flash; 118259829cc1SJean-Christophe PLAGNIOL-VILLARD 118359829cc1SJean-Christophe PLAGNIOL-VILLARD /* 118459829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if whole sector is erased 118559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 118612d30aa7SHaavard Skinnemoen size = flash_sector_size(info, i); 118759829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 1; 118859829cc1SJean-Christophe PLAGNIOL-VILLARD flash = (volatile unsigned long *) info->start[i]; 118959829cc1SJean-Christophe PLAGNIOL-VILLARD size = size >> 2; /* divide by 4 for longword access */ 119059829cc1SJean-Christophe PLAGNIOL-VILLARD for (k = 0; k < size; k++) { 119159829cc1SJean-Christophe PLAGNIOL-VILLARD if (*flash++ != 0xffffffff) { 119259829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 0; 119359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 119459829cc1SJean-Christophe PLAGNIOL-VILLARD } 119559829cc1SJean-Christophe PLAGNIOL-VILLARD } 119659829cc1SJean-Christophe PLAGNIOL-VILLARD 119759829cc1SJean-Christophe PLAGNIOL-VILLARD /* print empty and read-only info */ 119859829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %c %s ", 119959829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 120059829cc1SJean-Christophe PLAGNIOL-VILLARD erased ? 'E' : ' ', 120159829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 12026d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #else /* ! CONFIG_SYS_FLASH_EMPTY_INFO */ 120359829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %s ", 120459829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 120559829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 120659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 120759829cc1SJean-Christophe PLAGNIOL-VILLARD } 120859829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 120959829cc1SJean-Christophe PLAGNIOL-VILLARD return; 121059829cc1SJean-Christophe PLAGNIOL-VILLARD } 121159829cc1SJean-Christophe PLAGNIOL-VILLARD 121259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 12139a042e9cSJerry Van Baren * This is used in a few places in write_buf() to show programming 12149a042e9cSJerry Van Baren * progress. Making it a function is nasty because it needs to do side 12159a042e9cSJerry Van Baren * effect updates to digit and dots. Repeated code is nasty too, so 12169a042e9cSJerry Van Baren * we define it once here. 12179a042e9cSJerry Van Baren */ 1218f0105727SStefan Roese #ifdef CONFIG_FLASH_SHOW_PROGRESS 1219f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \ 1220f0105727SStefan Roese dots -= dots_sub; \ 12219a042e9cSJerry Van Baren if ((scale > 0) && (dots <= 0)) { \ 12229a042e9cSJerry Van Baren if ((digit % 5) == 0) \ 12239a042e9cSJerry Van Baren printf ("%d", digit / 5); \ 12249a042e9cSJerry Van Baren else \ 12259a042e9cSJerry Van Baren putc ('.'); \ 12269a042e9cSJerry Van Baren digit--; \ 12279a042e9cSJerry Van Baren dots += scale; \ 12289a042e9cSJerry Van Baren } 1229f0105727SStefan Roese #else 1230f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) 1231f0105727SStefan Roese #endif 12329a042e9cSJerry Van Baren 12339a042e9cSJerry Van Baren /*----------------------------------------------------------------------- 123459829cc1SJean-Christophe PLAGNIOL-VILLARD * Copy memory to flash, returns: 123559829cc1SJean-Christophe PLAGNIOL-VILLARD * 0 - OK 123659829cc1SJean-Christophe PLAGNIOL-VILLARD * 1 - write timeout 123759829cc1SJean-Christophe PLAGNIOL-VILLARD * 2 - Flash not erased 123859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 123959829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) 124059829cc1SJean-Christophe PLAGNIOL-VILLARD { 124159829cc1SJean-Christophe PLAGNIOL-VILLARD ulong wp; 124212d30aa7SHaavard Skinnemoen uchar *p; 124359829cc1SJean-Christophe PLAGNIOL-VILLARD int aln; 124459829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 124559829cc1SJean-Christophe PLAGNIOL-VILLARD int i, rc; 12466d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE 124759829cc1SJean-Christophe PLAGNIOL-VILLARD int buffered_size; 124859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 12499a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS 12509a042e9cSJerry Van Baren int digit = CONFIG_FLASH_SHOW_PROGRESS; 12519a042e9cSJerry Van Baren int scale = 0; 12529a042e9cSJerry Van Baren int dots = 0; 12539a042e9cSJerry Van Baren 12549a042e9cSJerry Van Baren /* 12559a042e9cSJerry Van Baren * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes. 12569a042e9cSJerry Van Baren */ 12579a042e9cSJerry Van Baren if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) { 12589a042e9cSJerry Van Baren scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) / 12599a042e9cSJerry Van Baren CONFIG_FLASH_SHOW_PROGRESS); 12609a042e9cSJerry Van Baren } 12619a042e9cSJerry Van Baren #endif 12629a042e9cSJerry Van Baren 126359829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 126459829cc1SJean-Christophe PLAGNIOL-VILLARD wp = (addr & ~(info->portwidth - 1)); 126559829cc1SJean-Christophe PLAGNIOL-VILLARD 126659829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle unaligned start */ 126759829cc1SJean-Christophe PLAGNIOL-VILLARD if ((aln = addr - wp) != 0) { 126859829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 126912d30aa7SHaavard Skinnemoen p = map_physmem(wp, info->portwidth, MAP_NOCACHE); 127012d30aa7SHaavard Skinnemoen for (i = 0; i < aln; ++i) 127112d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 127259829cc1SJean-Christophe PLAGNIOL-VILLARD 127359829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (i < info->portwidth) && (cnt > 0); i++) { 127459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 127559829cc1SJean-Christophe PLAGNIOL-VILLARD cnt--; 127659829cc1SJean-Christophe PLAGNIOL-VILLARD } 127712d30aa7SHaavard Skinnemoen for (; (cnt == 0) && (i < info->portwidth); ++i) 127812d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 127912d30aa7SHaavard Skinnemoen 128012d30aa7SHaavard Skinnemoen rc = flash_write_cfiword (info, wp, cword); 128112d30aa7SHaavard Skinnemoen unmap_physmem(p, info->portwidth); 128212d30aa7SHaavard Skinnemoen if (rc != 0) 128359829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 128412d30aa7SHaavard Skinnemoen 128512d30aa7SHaavard Skinnemoen wp += i; 1286f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, i); 128759829cc1SJean-Christophe PLAGNIOL-VILLARD } 128859829cc1SJean-Christophe PLAGNIOL-VILLARD 128959829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle the aligned part */ 12906d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE 129159829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size = (info->portwidth / info->chipwidth); 129259829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size *= info->buffer_size; 129359829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 129459829cc1SJean-Christophe PLAGNIOL-VILLARD /* prohibit buffer write when buffer_size is 1 */ 129559829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size == 1) { 129659829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 129759829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) 129859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 129959829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 130059829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 130159829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 130259829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 130359829cc1SJean-Christophe PLAGNIOL-VILLARD continue; 130459829cc1SJean-Christophe PLAGNIOL-VILLARD } 130559829cc1SJean-Christophe PLAGNIOL-VILLARD 130659829cc1SJean-Christophe PLAGNIOL-VILLARD /* write buffer until next buffered_size aligned boundary */ 130759829cc1SJean-Christophe PLAGNIOL-VILLARD i = buffered_size - (wp % buffered_size); 130859829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > cnt) 130959829cc1SJean-Christophe PLAGNIOL-VILLARD i = cnt; 131059829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) 131159829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 131259829cc1SJean-Christophe PLAGNIOL-VILLARD i -= i & (info->portwidth - 1); 131359829cc1SJean-Christophe PLAGNIOL-VILLARD wp += i; 131459829cc1SJean-Christophe PLAGNIOL-VILLARD src += i; 131559829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= i; 1316f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, i); 131759829cc1SJean-Christophe PLAGNIOL-VILLARD } 131859829cc1SJean-Christophe PLAGNIOL-VILLARD #else 131959829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 132059829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 132159829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) { 132259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 132359829cc1SJean-Christophe PLAGNIOL-VILLARD } 132459829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 132559829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 132659829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 132759829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 1328f0105727SStefan Roese FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth); 132959829cc1SJean-Christophe PLAGNIOL-VILLARD } 13306d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */ 13319a042e9cSJerry Van Baren 133259829cc1SJean-Christophe PLAGNIOL-VILLARD if (cnt == 0) { 133359829cc1SJean-Christophe PLAGNIOL-VILLARD return (0); 133459829cc1SJean-Christophe PLAGNIOL-VILLARD } 133559829cc1SJean-Christophe PLAGNIOL-VILLARD 133659829cc1SJean-Christophe PLAGNIOL-VILLARD /* 133759829cc1SJean-Christophe PLAGNIOL-VILLARD * handle unaligned tail bytes 133859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 133959829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 134012d30aa7SHaavard Skinnemoen p = map_physmem(wp, info->portwidth, MAP_NOCACHE); 134112d30aa7SHaavard Skinnemoen for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) { 134259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 134359829cc1SJean-Christophe PLAGNIOL-VILLARD --cnt; 134459829cc1SJean-Christophe PLAGNIOL-VILLARD } 134512d30aa7SHaavard Skinnemoen for (; i < info->portwidth; ++i) 134612d30aa7SHaavard Skinnemoen flash_add_byte (info, &cword, flash_read8(p + i)); 134712d30aa7SHaavard Skinnemoen unmap_physmem(p, info->portwidth); 134859829cc1SJean-Christophe PLAGNIOL-VILLARD 134959829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_write_cfiword (info, wp, cword); 135059829cc1SJean-Christophe PLAGNIOL-VILLARD } 135159829cc1SJean-Christophe PLAGNIOL-VILLARD 135259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 135359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 13546d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 135559829cc1SJean-Christophe PLAGNIOL-VILLARD 135659829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot) 135759829cc1SJean-Christophe PLAGNIOL-VILLARD { 135859829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode = 0; 135959829cc1SJean-Christophe PLAGNIOL-VILLARD 1360bc9019e1SRafael Campos switch (info->vendor) { 1361bc9019e1SRafael Campos case CFI_CMDSET_INTEL_PROG_REGIONS: 1362bc9019e1SRafael Campos case CFI_CMDSET_INTEL_STANDARD: 13639e8e63ccSNick Spence case CFI_CMDSET_INTEL_EXTENDED: 1364bc9019e1SRafael Campos flash_write_cmd (info, sector, 0, 1365bc9019e1SRafael Campos FLASH_CMD_CLEAR_STATUS); 136659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); 136759829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) 1368bc9019e1SRafael Campos flash_write_cmd (info, sector, 0, 1369bc9019e1SRafael Campos FLASH_CMD_PROTECT_SET); 137059829cc1SJean-Christophe PLAGNIOL-VILLARD else 1371bc9019e1SRafael Campos flash_write_cmd (info, sector, 0, 1372bc9019e1SRafael Campos FLASH_CMD_PROTECT_CLEAR); 1373bc9019e1SRafael Campos break; 1374bc9019e1SRafael Campos case CFI_CMDSET_AMD_EXTENDED: 1375bc9019e1SRafael Campos case CFI_CMDSET_AMD_STANDARD: 1376bc9019e1SRafael Campos /* U-Boot only checks the first byte */ 1377bc9019e1SRafael Campos if (info->manufacturer_id == (uchar)ATM_MANUFACT) { 1378bc9019e1SRafael Campos if (prot) { 1379bc9019e1SRafael Campos flash_unlock_seq (info, 0); 1380bc9019e1SRafael Campos flash_write_cmd (info, 0, 1381bc9019e1SRafael Campos info->addr_unlock1, 1382bc9019e1SRafael Campos ATM_CMD_SOFTLOCK_START); 1383bc9019e1SRafael Campos flash_unlock_seq (info, 0); 1384bc9019e1SRafael Campos flash_write_cmd (info, sector, 0, 1385bc9019e1SRafael Campos ATM_CMD_LOCK_SECT); 1386bc9019e1SRafael Campos } else { 1387bc9019e1SRafael Campos flash_write_cmd (info, 0, 1388bc9019e1SRafael Campos info->addr_unlock1, 1389bc9019e1SRafael Campos AMD_CMD_UNLOCK_START); 1390bc9019e1SRafael Campos if (info->device_id == ATM_ID_BV6416) 1391bc9019e1SRafael Campos flash_write_cmd (info, sector, 1392bc9019e1SRafael Campos 0, ATM_CMD_UNLOCK_SECT); 1393bc9019e1SRafael Campos } 1394bc9019e1SRafael Campos } 1395bc9019e1SRafael Campos break; 13964e00acdeSTsiChung Liew #ifdef CONFIG_FLASH_CFI_LEGACY 13974e00acdeSTsiChung Liew case CFI_CMDSET_AMD_LEGACY: 13984e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 13994e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); 14004e00acdeSTsiChung Liew if (prot) 14014e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); 14024e00acdeSTsiChung Liew else 14034e00acdeSTsiChung Liew flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR); 14044e00acdeSTsiChung Liew #endif 1405bc9019e1SRafael Campos }; 140659829cc1SJean-Christophe PLAGNIOL-VILLARD 140759829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode = 140859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_full_status_check (info, sector, info->erase_blk_tout, 140959829cc1SJean-Christophe PLAGNIOL-VILLARD prot ? "protect" : "unprotect")) == 0) { 141059829cc1SJean-Christophe PLAGNIOL-VILLARD 141159829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sector] = prot; 141259829cc1SJean-Christophe PLAGNIOL-VILLARD 141359829cc1SJean-Christophe PLAGNIOL-VILLARD /* 141459829cc1SJean-Christophe PLAGNIOL-VILLARD * On some of Intel's flash chips (marked via legacy_unlock) 141559829cc1SJean-Christophe PLAGNIOL-VILLARD * unprotect unprotects all locking. 141659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 141759829cc1SJean-Christophe PLAGNIOL-VILLARD if ((prot == 0) && (info->legacy_unlock)) { 141859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t i; 141959829cc1SJean-Christophe PLAGNIOL-VILLARD 142059829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; i++) { 142159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[i]) 142259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (info, i, 1); 142359829cc1SJean-Christophe PLAGNIOL-VILLARD } 142459829cc1SJean-Christophe PLAGNIOL-VILLARD } 142559829cc1SJean-Christophe PLAGNIOL-VILLARD } 142659829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 142759829cc1SJean-Christophe PLAGNIOL-VILLARD } 142859829cc1SJean-Christophe PLAGNIOL-VILLARD 142959829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 143059829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_user_serial - read the OneTimeProgramming cells 143159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 143259829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, 143359829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 143459829cc1SJean-Christophe PLAGNIOL-VILLARD { 143559829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 143659829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *dst; 143759829cc1SJean-Christophe PLAGNIOL-VILLARD 143859829cc1SJean-Christophe PLAGNIOL-VILLARD dst = buffer; 143912d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION); 144059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 144159829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (dst, src + offset, len); 144259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 144312d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src); 144459829cc1SJean-Christophe PLAGNIOL-VILLARD } 144559829cc1SJean-Christophe PLAGNIOL-VILLARD 144659829cc1SJean-Christophe PLAGNIOL-VILLARD /* 144759829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_factory_serial - read the device Id from the protection area 144859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 144959829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, 145059829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 145159829cc1SJean-Christophe PLAGNIOL-VILLARD { 145259829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 145359829cc1SJean-Christophe PLAGNIOL-VILLARD 145412d30aa7SHaavard Skinnemoen src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION); 145559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 145659829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (buffer, src + offset, len); 145759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 145812d30aa7SHaavard Skinnemoen flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src); 145959829cc1SJean-Christophe PLAGNIOL-VILLARD } 146059829cc1SJean-Christophe PLAGNIOL-VILLARD 14616d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */ 146259829cc1SJean-Christophe PLAGNIOL-VILLARD 14630ddf06ddSHaavard Skinnemoen /*----------------------------------------------------------------------- 14640ddf06ddSHaavard Skinnemoen * Reverse the order of the erase regions in the CFI QRY structure. 14650ddf06ddSHaavard Skinnemoen * This is needed for chips that are either a) correctly detected as 14660ddf06ddSHaavard Skinnemoen * top-boot, or b) buggy. 14670ddf06ddSHaavard Skinnemoen */ 14680ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry) 14690ddf06ddSHaavard Skinnemoen { 14700ddf06ddSHaavard Skinnemoen unsigned int i, j; 14710ddf06ddSHaavard Skinnemoen u32 tmp; 14720ddf06ddSHaavard Skinnemoen 14730ddf06ddSHaavard Skinnemoen for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) { 14740ddf06ddSHaavard Skinnemoen tmp = qry->erase_region_info[i]; 14750ddf06ddSHaavard Skinnemoen qry->erase_region_info[i] = qry->erase_region_info[j]; 14760ddf06ddSHaavard Skinnemoen qry->erase_region_info[j] = tmp; 14770ddf06ddSHaavard Skinnemoen } 14780ddf06ddSHaavard Skinnemoen } 147959829cc1SJean-Christophe PLAGNIOL-VILLARD 148059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 148159829cc1SJean-Christophe PLAGNIOL-VILLARD * read jedec ids from device and set corresponding fields in info struct 148259829cc1SJean-Christophe PLAGNIOL-VILLARD * 148359829cc1SJean-Christophe PLAGNIOL-VILLARD * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct 148459829cc1SJean-Christophe PLAGNIOL-VILLARD * 148559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 14860ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info) 148759829cc1SJean-Christophe PLAGNIOL-VILLARD { 148859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 148959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); 149059829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 149159829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 149259829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 149359829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 149459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 149559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 14960ddf06ddSHaavard Skinnemoen } 14970ddf06ddSHaavard Skinnemoen 14980ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry) 14990ddf06ddSHaavard Skinnemoen { 15000ddf06ddSHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 15010ddf06ddSHaavard Skinnemoen 15020ddf06ddSHaavard Skinnemoen cmdset_intel_read_jedec_ids(info); 15030ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 15040ddf06ddSHaavard Skinnemoen 15056d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 15060ddf06ddSHaavard Skinnemoen /* read legacy lock/unlock bit from intel flash */ 15070ddf06ddSHaavard Skinnemoen if (info->ext_addr) { 15080ddf06ddSHaavard Skinnemoen info->legacy_unlock = flash_read_uchar (info, 15090ddf06ddSHaavard Skinnemoen info->ext_addr + 5) & 0x08; 15100ddf06ddSHaavard Skinnemoen } 15110ddf06ddSHaavard Skinnemoen #endif 15120ddf06ddSHaavard Skinnemoen 15130ddf06ddSHaavard Skinnemoen return 0; 15140ddf06ddSHaavard Skinnemoen } 15150ddf06ddSHaavard Skinnemoen 15160ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info) 15170ddf06ddSHaavard Skinnemoen { 151859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 151959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info, 0); 152081b20cccSMichael Schwingen flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); 152159829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 152290447ecbSTor Krill 152359829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 152459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 152590447ecbSTor Krill 152690447ecbSTor Krill switch (info->chipwidth){ 152790447ecbSTor Krill case FLASH_CFI_8BIT: 152859829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 152959829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 153059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 153159829cc1SJean-Christophe PLAGNIOL-VILLARD /* AMD 3-byte (expanded) device ids */ 153259829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = flash_read_uchar (info, 153359829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID2); 153459829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 <<= 8; 153559829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 |= flash_read_uchar (info, 153659829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID3); 153759829cc1SJean-Christophe PLAGNIOL-VILLARD } 153890447ecbSTor Krill break; 153990447ecbSTor Krill case FLASH_CFI_16BIT: 154090447ecbSTor Krill info->device_id = flash_read_word (info, 154190447ecbSTor Krill FLASH_OFFSET_DEVICE_ID); 154290447ecbSTor Krill break; 154390447ecbSTor Krill default: 154490447ecbSTor Krill break; 154590447ecbSTor Krill } 154659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 15470ddf06ddSHaavard Skinnemoen } 15480ddf06ddSHaavard Skinnemoen 15490ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry) 15500ddf06ddSHaavard Skinnemoen { 15510ddf06ddSHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 15520ddf06ddSHaavard Skinnemoen 15530ddf06ddSHaavard Skinnemoen cmdset_amd_read_jedec_ids(info); 15540ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); 15550ddf06ddSHaavard Skinnemoen 15560ddf06ddSHaavard Skinnemoen return 0; 15570ddf06ddSHaavard Skinnemoen } 15580ddf06ddSHaavard Skinnemoen 15590ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY 15600ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info) 15610ddf06ddSHaavard Skinnemoen { 15620ddf06ddSHaavard Skinnemoen info->manufacturer_id = 0; 15630ddf06ddSHaavard Skinnemoen info->device_id = 0; 15640ddf06ddSHaavard Skinnemoen info->device_id2 = 0; 15650ddf06ddSHaavard Skinnemoen 15660ddf06ddSHaavard Skinnemoen switch (info->vendor) { 15679c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 15680ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 15690ddf06ddSHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 15708225d1e3SMichael Schwingen cmdset_intel_read_jedec_ids(info); 15710ddf06ddSHaavard Skinnemoen break; 15720ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 15730ddf06ddSHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 15748225d1e3SMichael Schwingen cmdset_amd_read_jedec_ids(info); 157559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 157659829cc1SJean-Christophe PLAGNIOL-VILLARD default: 157759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 157859829cc1SJean-Christophe PLAGNIOL-VILLARD } 157959829cc1SJean-Christophe PLAGNIOL-VILLARD } 158059829cc1SJean-Christophe PLAGNIOL-VILLARD 1581be60a902SHaavard Skinnemoen /*----------------------------------------------------------------------- 1582be60a902SHaavard Skinnemoen * Call board code to request info about non-CFI flash. 1583be60a902SHaavard Skinnemoen * board_flash_get_legacy needs to fill in at least: 1584be60a902SHaavard Skinnemoen * info->portwidth, info->chipwidth and info->interface for Jedec probing. 1585be60a902SHaavard Skinnemoen */ 1586be60a902SHaavard Skinnemoen static int flash_detect_legacy(ulong base, int banknum) 1587be60a902SHaavard Skinnemoen { 1588be60a902SHaavard Skinnemoen flash_info_t *info = &flash_info[banknum]; 1589be60a902SHaavard Skinnemoen 1590be60a902SHaavard Skinnemoen if (board_flash_get_legacy(base, banknum, info)) { 1591be60a902SHaavard Skinnemoen /* board code may have filled info completely. If not, we 1592be60a902SHaavard Skinnemoen use JEDEC ID probing. */ 1593be60a902SHaavard Skinnemoen if (!info->vendor) { 1594be60a902SHaavard Skinnemoen int modes[] = { 1595be60a902SHaavard Skinnemoen CFI_CMDSET_AMD_STANDARD, 1596be60a902SHaavard Skinnemoen CFI_CMDSET_INTEL_STANDARD 1597be60a902SHaavard Skinnemoen }; 1598be60a902SHaavard Skinnemoen int i; 1599be60a902SHaavard Skinnemoen 1600be60a902SHaavard Skinnemoen for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) { 1601be60a902SHaavard Skinnemoen info->vendor = modes[i]; 1602be60a902SHaavard Skinnemoen info->start[0] = base; 1603be60a902SHaavard Skinnemoen if (info->portwidth == FLASH_CFI_8BIT 1604be60a902SHaavard Skinnemoen && info->interface == FLASH_CFI_X8X16) { 1605be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x2AAA; 1606be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x5555; 1607be60a902SHaavard Skinnemoen } else { 1608be60a902SHaavard Skinnemoen info->addr_unlock1 = 0x5555; 1609be60a902SHaavard Skinnemoen info->addr_unlock2 = 0x2AAA; 1610be60a902SHaavard Skinnemoen } 1611be60a902SHaavard Skinnemoen flash_read_jedec_ids(info); 1612be60a902SHaavard Skinnemoen debug("JEDEC PROBE: ID %x %x %x\n", 1613be60a902SHaavard Skinnemoen info->manufacturer_id, 1614be60a902SHaavard Skinnemoen info->device_id, 1615be60a902SHaavard Skinnemoen info->device_id2); 1616be60a902SHaavard Skinnemoen if (jedec_flash_match(info, base)) 1617be60a902SHaavard Skinnemoen break; 1618be60a902SHaavard Skinnemoen } 1619be60a902SHaavard Skinnemoen } 1620be60a902SHaavard Skinnemoen 1621be60a902SHaavard Skinnemoen switch(info->vendor) { 16229c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 1623be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_STANDARD: 1624be60a902SHaavard Skinnemoen case CFI_CMDSET_INTEL_EXTENDED: 1625be60a902SHaavard Skinnemoen info->cmd_reset = FLASH_CMD_RESET; 1626be60a902SHaavard Skinnemoen break; 1627be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_STANDARD: 1628be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_EXTENDED: 1629be60a902SHaavard Skinnemoen case CFI_CMDSET_AMD_LEGACY: 1630be60a902SHaavard Skinnemoen info->cmd_reset = AMD_CMD_RESET; 1631be60a902SHaavard Skinnemoen break; 1632be60a902SHaavard Skinnemoen } 1633be60a902SHaavard Skinnemoen info->flash_id = FLASH_MAN_CFI; 1634be60a902SHaavard Skinnemoen return 1; 1635be60a902SHaavard Skinnemoen } 1636be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1637be60a902SHaavard Skinnemoen } 1638be60a902SHaavard Skinnemoen #else 1639be60a902SHaavard Skinnemoen static inline int flash_detect_legacy(ulong base, int banknum) 1640be60a902SHaavard Skinnemoen { 1641be60a902SHaavard Skinnemoen return 0; /* use CFI */ 1642be60a902SHaavard Skinnemoen } 1643be60a902SHaavard Skinnemoen #endif 1644be60a902SHaavard Skinnemoen 164559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 164659829cc1SJean-Christophe PLAGNIOL-VILLARD * detect if flash is compatible with the Common Flash Interface (CFI) 164759829cc1SJean-Christophe PLAGNIOL-VILLARD * http://www.jedec.org/download/search/jesd68.pdf 164859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1649e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf, 1650e23741f4SHaavard Skinnemoen unsigned int start, size_t len) 1651e23741f4SHaavard Skinnemoen { 1652e23741f4SHaavard Skinnemoen u8 *p = buf; 1653e23741f4SHaavard Skinnemoen unsigned int i; 1654e23741f4SHaavard Skinnemoen 1655e23741f4SHaavard Skinnemoen for (i = 0; i < len; i++) 1656e23741f4SHaavard Skinnemoen p[i] = flash_read_uchar(info, start + i); 1657e23741f4SHaavard Skinnemoen } 1658e23741f4SHaavard Skinnemoen 1659e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 166059829cc1SJean-Christophe PLAGNIOL-VILLARD { 166159829cc1SJean-Christophe PLAGNIOL-VILLARD int cfi_offset; 166259829cc1SJean-Christophe PLAGNIOL-VILLARD 16631ba639daSMichael Schwingen /* We do not yet know what kind of commandset to use, so we issue 16641ba639daSMichael Schwingen the reset command in both Intel and AMD variants, in the hope 16651ba639daSMichael Schwingen that AMD flash roms ignore the Intel command. */ 16661ba639daSMichael Schwingen flash_write_cmd (info, 0, 0, AMD_CMD_RESET); 16671ba639daSMichael Schwingen flash_write_cmd (info, 0, 0, FLASH_CMD_RESET); 16681ba639daSMichael Schwingen 16697e5b9b47SHaavard Skinnemoen for (cfi_offset=0; 16707e5b9b47SHaavard Skinnemoen cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint); 16717e5b9b47SHaavard Skinnemoen cfi_offset++) { 16727e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], 16737e5b9b47SHaavard Skinnemoen FLASH_CMD_CFI); 167459829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') 167559829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') 167659829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { 1677e23741f4SHaavard Skinnemoen flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP, 1678e23741f4SHaavard Skinnemoen sizeof(struct cfi_qry)); 1679e23741f4SHaavard Skinnemoen info->interface = le16_to_cpu(qry->interface_desc); 1680e23741f4SHaavard Skinnemoen 168159829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_offset = flash_offset_cfi[cfi_offset]; 168259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device interface is %d\n", 168359829cc1SJean-Christophe PLAGNIOL-VILLARD info->interface); 168459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found port %d chip %d ", 168559829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth, info->chipwidth); 168659829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("port %d bits chip %d bits\n", 168759829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth << CFI_FLASH_SHIFT_WIDTH, 168859829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 168942026c9cSBartlomiej Sieka 169042026c9cSBartlomiej Sieka /* calculate command offsets as in the Linux driver */ 169142026c9cSBartlomiej Sieka info->addr_unlock1 = 0x555; 169242026c9cSBartlomiej Sieka info->addr_unlock2 = 0x2aa; 169342026c9cSBartlomiej Sieka 169442026c9cSBartlomiej Sieka /* 169542026c9cSBartlomiej Sieka * modify the unlock address if we are 169642026c9cSBartlomiej Sieka * in compatibility mode 169742026c9cSBartlomiej Sieka */ 169842026c9cSBartlomiej Sieka if ( /* x8/x16 in x8 mode */ 169942026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY8) && 170042026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X8X16)) || 170142026c9cSBartlomiej Sieka /* x16/x32 in x16 mode */ 170242026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY16) && 170342026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X16X32))) 170442026c9cSBartlomiej Sieka { 170542026c9cSBartlomiej Sieka info->addr_unlock1 = 0xaaa; 170642026c9cSBartlomiej Sieka info->addr_unlock2 = 0x555; 170742026c9cSBartlomiej Sieka } 170842026c9cSBartlomiej Sieka 170981b20cccSMichael Schwingen info->name = "CFI conformant"; 171059829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 171159829cc1SJean-Christophe PLAGNIOL-VILLARD } 171259829cc1SJean-Christophe PLAGNIOL-VILLARD } 17137e5b9b47SHaavard Skinnemoen 17147e5b9b47SHaavard Skinnemoen return 0; 171559829cc1SJean-Christophe PLAGNIOL-VILLARD } 17167e5b9b47SHaavard Skinnemoen 1717e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) 17187e5b9b47SHaavard Skinnemoen { 17197e5b9b47SHaavard Skinnemoen debug ("flash detect cfi\n"); 17207e5b9b47SHaavard Skinnemoen 17216d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (info->portwidth = CONFIG_SYS_FLASH_CFI_WIDTH; 17227e5b9b47SHaavard Skinnemoen info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) { 17237e5b9b47SHaavard Skinnemoen for (info->chipwidth = FLASH_CFI_BY8; 17247e5b9b47SHaavard Skinnemoen info->chipwidth <= info->portwidth; 17257e5b9b47SHaavard Skinnemoen info->chipwidth <<= 1) 1726e23741f4SHaavard Skinnemoen if (__flash_detect_cfi(info, qry)) 17277e5b9b47SHaavard Skinnemoen return 1; 172859829cc1SJean-Christophe PLAGNIOL-VILLARD } 172959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("not found\n"); 173059829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 173159829cc1SJean-Christophe PLAGNIOL-VILLARD } 173259829cc1SJean-Christophe PLAGNIOL-VILLARD 173359829cc1SJean-Christophe PLAGNIOL-VILLARD /* 1734467bcee1SHaavard Skinnemoen * Manufacturer-specific quirks. Add workarounds for geometry 1735467bcee1SHaavard Skinnemoen * reversal, etc. here. 1736467bcee1SHaavard Skinnemoen */ 1737467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry) 1738467bcee1SHaavard Skinnemoen { 1739467bcee1SHaavard Skinnemoen /* check if flash geometry needs reversal */ 1740467bcee1SHaavard Skinnemoen if (qry->num_erase_regions > 1) { 1741467bcee1SHaavard Skinnemoen /* reverse geometry if top boot part */ 1742467bcee1SHaavard Skinnemoen if (info->cfi_version < 0x3131) { 1743467bcee1SHaavard Skinnemoen /* CFI < 1.1, try to guess from device id */ 1744467bcee1SHaavard Skinnemoen if ((info->device_id & 0x80) != 0) 1745467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1746467bcee1SHaavard Skinnemoen } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { 1747467bcee1SHaavard Skinnemoen /* CFI >= 1.1, deduct from top/bottom flag */ 1748467bcee1SHaavard Skinnemoen /* note: ext_addr is valid since cfi_version > 0 */ 1749467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1750467bcee1SHaavard Skinnemoen } 1751467bcee1SHaavard Skinnemoen } 1752467bcee1SHaavard Skinnemoen } 1753467bcee1SHaavard Skinnemoen 1754467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry) 1755467bcee1SHaavard Skinnemoen { 1756467bcee1SHaavard Skinnemoen int reverse_geometry = 0; 1757467bcee1SHaavard Skinnemoen 1758467bcee1SHaavard Skinnemoen /* Check the "top boot" bit in the PRI */ 1759467bcee1SHaavard Skinnemoen if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1)) 1760467bcee1SHaavard Skinnemoen reverse_geometry = 1; 1761467bcee1SHaavard Skinnemoen 1762467bcee1SHaavard Skinnemoen /* AT49BV6416(T) list the erase regions in the wrong order. 1763467bcee1SHaavard Skinnemoen * However, the device ID is identical with the non-broken 1764467bcee1SHaavard Skinnemoen * AT49BV642D since u-boot only reads the low byte (they 1765467bcee1SHaavard Skinnemoen * differ in the high byte.) So leave out this fixup for now. 1766467bcee1SHaavard Skinnemoen */ 1767467bcee1SHaavard Skinnemoen #if 0 1768467bcee1SHaavard Skinnemoen if (info->device_id == 0xd6 || info->device_id == 0xd2) 1769467bcee1SHaavard Skinnemoen reverse_geometry = !reverse_geometry; 1770467bcee1SHaavard Skinnemoen #endif 1771467bcee1SHaavard Skinnemoen 1772467bcee1SHaavard Skinnemoen if (reverse_geometry) 1773467bcee1SHaavard Skinnemoen cfi_reverse_geometry(qry); 1774467bcee1SHaavard Skinnemoen } 1775467bcee1SHaavard Skinnemoen 1776467bcee1SHaavard Skinnemoen /* 177759829cc1SJean-Christophe PLAGNIOL-VILLARD * The following code cannot be run from FLASH! 177859829cc1SJean-Christophe PLAGNIOL-VILLARD * 177959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 178059829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum) 178159829cc1SJean-Christophe PLAGNIOL-VILLARD { 178259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t *info = &flash_info[banknum]; 178359829cc1SJean-Christophe PLAGNIOL-VILLARD int i, j; 178459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect_cnt; 178559829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long sector; 178659829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long tmp; 178759829cc1SJean-Christophe PLAGNIOL-VILLARD int size_ratio; 178859829cc1SJean-Christophe PLAGNIOL-VILLARD uchar num_erase_regions; 178959829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_size; 179059829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_count; 1791e23741f4SHaavard Skinnemoen struct cfi_qry qry; 179259829cc1SJean-Christophe PLAGNIOL-VILLARD 1793f979690eSKumar Gala memset(&qry, 0, sizeof(qry)); 1794f979690eSKumar Gala 179559829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = 0; 179659829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = 0; 17976d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 179859829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = 0; 179959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 180059829cc1SJean-Christophe PLAGNIOL-VILLARD 180159829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[0] = base; 180259829cc1SJean-Christophe PLAGNIOL-VILLARD 1803e23741f4SHaavard Skinnemoen if (flash_detect_cfi (info, &qry)) { 1804e23741f4SHaavard Skinnemoen info->vendor = le16_to_cpu(qry.p_id); 1805e23741f4SHaavard Skinnemoen info->ext_addr = le16_to_cpu(qry.p_adr); 1806e23741f4SHaavard Skinnemoen num_erase_regions = qry.num_erase_regions; 1807e23741f4SHaavard Skinnemoen 180859829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 180959829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = (ushort) flash_read_uchar (info, 181059829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 3) << 8; 181159829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version |= (ushort) flash_read_uchar (info, 181259829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 4); 181359829cc1SJean-Christophe PLAGNIOL-VILLARD } 18140ddf06ddSHaavard Skinnemoen 181559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 1816e23741f4SHaavard Skinnemoen flash_printqry (&qry); 181759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 18180ddf06ddSHaavard Skinnemoen 181959829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 18209c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 182159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 182259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 18230ddf06ddSHaavard Skinnemoen cmdset_intel_init(info, &qry); 182459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 182559829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 182659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 18270ddf06ddSHaavard Skinnemoen cmdset_amd_init(info, &qry); 182859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 18290ddf06ddSHaavard Skinnemoen default: 18300ddf06ddSHaavard Skinnemoen printf("CFI: Unknown command set 0x%x\n", 18310ddf06ddSHaavard Skinnemoen info->vendor); 18320ddf06ddSHaavard Skinnemoen /* 18330ddf06ddSHaavard Skinnemoen * Unfortunately, this means we don't know how 18340ddf06ddSHaavard Skinnemoen * to get the chip back to Read mode. Might 18350ddf06ddSHaavard Skinnemoen * as well try an Intel-style reset... 18360ddf06ddSHaavard Skinnemoen */ 18370ddf06ddSHaavard Skinnemoen flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 18380ddf06ddSHaavard Skinnemoen return 0; 183959829cc1SJean-Christophe PLAGNIOL-VILLARD } 184059829cc1SJean-Christophe PLAGNIOL-VILLARD 1841467bcee1SHaavard Skinnemoen /* Do manufacturer-specific fixups */ 1842467bcee1SHaavard Skinnemoen switch (info->manufacturer_id) { 1843467bcee1SHaavard Skinnemoen case 0x0001: 1844467bcee1SHaavard Skinnemoen flash_fixup_amd(info, &qry); 1845467bcee1SHaavard Skinnemoen break; 1846467bcee1SHaavard Skinnemoen case 0x001f: 1847467bcee1SHaavard Skinnemoen flash_fixup_atmel(info, &qry); 1848467bcee1SHaavard Skinnemoen break; 1849467bcee1SHaavard Skinnemoen } 1850467bcee1SHaavard Skinnemoen 185159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer is %d\n", info->vendor); 185259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer id is 0x%x\n", info->manufacturer_id); 185359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id is 0x%x\n", info->device_id); 185459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id2 is 0x%x\n", info->device_id2); 185559829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("cfi version is 0x%04x\n", info->cfi_version); 185659829cc1SJean-Christophe PLAGNIOL-VILLARD 185759829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio = info->portwidth / info->chipwidth; 185859829cc1SJean-Christophe PLAGNIOL-VILLARD /* if the chip is x8/x16 reduce the ratio by half */ 185959829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->interface == FLASH_CFI_X8X16) 186059829cc1SJean-Christophe PLAGNIOL-VILLARD && (info->chipwidth == FLASH_CFI_BY8)) { 186159829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio >>= 1; 186259829cc1SJean-Christophe PLAGNIOL-VILLARD } 186359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("size_ratio %d port %d bits chip %d bits\n", 186459829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, 186559829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 186659829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found %d erase regions\n", num_erase_regions); 186759829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt = 0; 186859829cc1SJean-Christophe PLAGNIOL-VILLARD sector = base; 186959829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < num_erase_regions; i++) { 187059829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > NUM_ERASE_REGIONS) { 187159829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("%d erase regions found, only %d used\n", 187259829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions, NUM_ERASE_REGIONS); 187359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 187459829cc1SJean-Christophe PLAGNIOL-VILLARD } 1875e23741f4SHaavard Skinnemoen 18760ddf06ddSHaavard Skinnemoen tmp = le32_to_cpu(qry.erase_region_info[i]); 18770ddf06ddSHaavard Skinnemoen debug("erase region %u: 0x%08lx\n", i, tmp); 1878e23741f4SHaavard Skinnemoen 1879e23741f4SHaavard Skinnemoen erase_region_count = (tmp & 0xffff) + 1; 1880e23741f4SHaavard Skinnemoen tmp >>= 16; 188159829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_size = 188259829cc1SJean-Christophe PLAGNIOL-VILLARD (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; 188359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("erase_region_count = %d erase_region_size = %d\n", 188459829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count, erase_region_size); 188559829cc1SJean-Christophe PLAGNIOL-VILLARD for (j = 0; j < erase_region_count; j++) { 18866d0f6bcfSJean-Christophe PLAGNIOL-VILLARD if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) { 188781b20cccSMichael Schwingen printf("ERROR: too many flash sectors\n"); 188881b20cccSMichael Schwingen break; 188981b20cccSMichael Schwingen } 189059829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[sect_cnt] = sector; 189159829cc1SJean-Christophe PLAGNIOL-VILLARD sector += (erase_region_size * size_ratio); 189259829cc1SJean-Christophe PLAGNIOL-VILLARD 189359829cc1SJean-Christophe PLAGNIOL-VILLARD /* 18947e5b9b47SHaavard Skinnemoen * Only read protection status from 18957e5b9b47SHaavard Skinnemoen * supported devices (intel...) 189659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 189759829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 18989c048b52SVasiliy Leoenenko case CFI_CMDSET_INTEL_PROG_REGIONS: 189959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 190059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 190159829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sect_cnt] = 190259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_isset (info, sect_cnt, 190359829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PROTECT, 190459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_STATUS_PROTECT); 190559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 190659829cc1SJean-Christophe PLAGNIOL-VILLARD default: 19077e5b9b47SHaavard Skinnemoen /* default: not protected */ 19087e5b9b47SHaavard Skinnemoen info->protect[sect_cnt] = 0; 190959829cc1SJean-Christophe PLAGNIOL-VILLARD } 191059829cc1SJean-Christophe PLAGNIOL-VILLARD 191159829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt++; 191259829cc1SJean-Christophe PLAGNIOL-VILLARD } 191359829cc1SJean-Christophe PLAGNIOL-VILLARD } 191459829cc1SJean-Christophe PLAGNIOL-VILLARD 191559829cc1SJean-Christophe PLAGNIOL-VILLARD info->sector_count = sect_cnt; 1916e23741f4SHaavard Skinnemoen info->size = 1 << qry.dev_size; 191759829cc1SJean-Christophe PLAGNIOL-VILLARD /* multiply the size by the number of chips */ 19187e5b9b47SHaavard Skinnemoen info->size *= size_ratio; 1919e23741f4SHaavard Skinnemoen info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size); 1920e23741f4SHaavard Skinnemoen tmp = 1 << qry.block_erase_timeout_typ; 19217e5b9b47SHaavard Skinnemoen info->erase_blk_tout = tmp * 1922e23741f4SHaavard Skinnemoen (1 << qry.block_erase_timeout_max); 1923e23741f4SHaavard Skinnemoen tmp = (1 << qry.buf_write_timeout_typ) * 1924e23741f4SHaavard Skinnemoen (1 << qry.buf_write_timeout_max); 1925e23741f4SHaavard Skinnemoen 19267e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 1927e23741f4SHaavard Skinnemoen info->buffer_write_tout = (tmp + 999) / 1000; 1928e23741f4SHaavard Skinnemoen tmp = (1 << qry.word_write_timeout_typ) * 1929e23741f4SHaavard Skinnemoen (1 << qry.word_write_timeout_max); 19307e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 1931e23741f4SHaavard Skinnemoen info->write_tout = (tmp + 999) / 1000; 193259829cc1SJean-Christophe PLAGNIOL-VILLARD info->flash_id = FLASH_MAN_CFI; 19337e5b9b47SHaavard Skinnemoen if ((info->interface == FLASH_CFI_X8X16) && 19347e5b9b47SHaavard Skinnemoen (info->chipwidth == FLASH_CFI_BY8)) { 19357e5b9b47SHaavard Skinnemoen /* XXX - Need to test on x8/x16 in parallel. */ 19367e5b9b47SHaavard Skinnemoen info->portwidth >>= 1; 193759829cc1SJean-Christophe PLAGNIOL-VILLARD } 193859829cc1SJean-Christophe PLAGNIOL-VILLARD 193959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 19402215987eSMike Frysinger } 19412215987eSMike Frysinger 194259829cc1SJean-Christophe PLAGNIOL-VILLARD return (info->size); 194359829cc1SJean-Christophe PLAGNIOL-VILLARD } 194459829cc1SJean-Christophe PLAGNIOL-VILLARD 194559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 194659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1947be60a902SHaavard Skinnemoen unsigned long flash_init (void) 194859829cc1SJean-Christophe PLAGNIOL-VILLARD { 1949be60a902SHaavard Skinnemoen unsigned long size = 0; 1950be60a902SHaavard Skinnemoen int i; 19516d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) 1952c63ad632SMatthias Fuchs struct apl_s { 1953c63ad632SMatthias Fuchs ulong start; 1954c63ad632SMatthias Fuchs ulong size; 19556d0f6bcfSJean-Christophe PLAGNIOL-VILLARD } apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST; 1956c63ad632SMatthias Fuchs #endif 195759829cc1SJean-Christophe PLAGNIOL-VILLARD 19586d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 1959be60a902SHaavard Skinnemoen char *s = getenv("unlock"); 196081b20cccSMichael Schwingen #endif 1961be60a902SHaavard Skinnemoen 19626d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define BANK_BASE(i) (((unsigned long [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i]) 19632a112b23SWolfgang Denk 1964be60a902SHaavard Skinnemoen /* Init: no FLASHes known */ 19656d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) { 1966be60a902SHaavard Skinnemoen flash_info[i].flash_id = FLASH_UNKNOWN; 1967be60a902SHaavard Skinnemoen 19682a112b23SWolfgang Denk if (!flash_detect_legacy (BANK_BASE(i), i)) 19692a112b23SWolfgang Denk flash_get_size (BANK_BASE(i), i); 1970be60a902SHaavard Skinnemoen size += flash_info[i].size; 1971be60a902SHaavard Skinnemoen if (flash_info[i].flash_id == FLASH_UNKNOWN) { 19726d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_QUIET_TEST 1973be60a902SHaavard Skinnemoen printf ("## Unknown FLASH on Bank %d " 1974be60a902SHaavard Skinnemoen "- Size = 0x%08lx = %ld MB\n", 1975be60a902SHaavard Skinnemoen i+1, flash_info[i].size, 1976be60a902SHaavard Skinnemoen flash_info[i].size << 20); 19776d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_QUIET_TEST */ 197859829cc1SJean-Christophe PLAGNIOL-VILLARD } 19796d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION 1980be60a902SHaavard Skinnemoen else if ((s != NULL) && (strcmp(s, "yes") == 0)) { 1981be60a902SHaavard Skinnemoen /* 1982be60a902SHaavard Skinnemoen * Only the U-Boot image and it's environment 1983be60a902SHaavard Skinnemoen * is protected, all other sectors are 1984be60a902SHaavard Skinnemoen * unprotected (unlocked) if flash hardware 19856d0f6bcfSJean-Christophe PLAGNIOL-VILLARD * protection is used (CONFIG_SYS_FLASH_PROTECTION) 1986be60a902SHaavard Skinnemoen * and the environment variable "unlock" is 1987be60a902SHaavard Skinnemoen * set to "yes". 1988be60a902SHaavard Skinnemoen */ 1989be60a902SHaavard Skinnemoen if (flash_info[i].legacy_unlock) { 1990be60a902SHaavard Skinnemoen int k; 199159829cc1SJean-Christophe PLAGNIOL-VILLARD 1992be60a902SHaavard Skinnemoen /* 1993be60a902SHaavard Skinnemoen * Disable legacy_unlock temporarily, 1994be60a902SHaavard Skinnemoen * since flash_real_protect would 1995be60a902SHaavard Skinnemoen * relock all other sectors again 1996be60a902SHaavard Skinnemoen * otherwise. 1997be60a902SHaavard Skinnemoen */ 1998be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 0; 199959829cc1SJean-Christophe PLAGNIOL-VILLARD 2000be60a902SHaavard Skinnemoen /* 2001be60a902SHaavard Skinnemoen * Legacy unlocking (e.g. Intel J3) -> 2002be60a902SHaavard Skinnemoen * unlock only one sector. This will 2003be60a902SHaavard Skinnemoen * unlock all sectors. 2004be60a902SHaavard Skinnemoen */ 2005be60a902SHaavard Skinnemoen flash_real_protect (&flash_info[i], 0, 0); 200659829cc1SJean-Christophe PLAGNIOL-VILLARD 2007be60a902SHaavard Skinnemoen flash_info[i].legacy_unlock = 1; 200859829cc1SJean-Christophe PLAGNIOL-VILLARD 2009be60a902SHaavard Skinnemoen /* 2010be60a902SHaavard Skinnemoen * Manually mark other sectors as 2011be60a902SHaavard Skinnemoen * unlocked (unprotected) 2012be60a902SHaavard Skinnemoen */ 2013be60a902SHaavard Skinnemoen for (k = 1; k < flash_info[i].sector_count; k++) 2014be60a902SHaavard Skinnemoen flash_info[i].protect[k] = 0; 2015be60a902SHaavard Skinnemoen } else { 2016be60a902SHaavard Skinnemoen /* 2017be60a902SHaavard Skinnemoen * No legancy unlocking -> unlock all sectors 2018be60a902SHaavard Skinnemoen */ 2019be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_CLEAR, 2020be60a902SHaavard Skinnemoen flash_info[i].start[0], 2021be60a902SHaavard Skinnemoen flash_info[i].start[0] 2022be60a902SHaavard Skinnemoen + flash_info[i].size - 1, 2023be60a902SHaavard Skinnemoen &flash_info[i]); 202459829cc1SJean-Christophe PLAGNIOL-VILLARD } 202559829cc1SJean-Christophe PLAGNIOL-VILLARD } 20266d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */ 202759829cc1SJean-Christophe PLAGNIOL-VILLARD } 202859829cc1SJean-Christophe PLAGNIOL-VILLARD 2029be60a902SHaavard Skinnemoen /* Monitor protection ON by default */ 20306d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE) 2031be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 20326d0f6bcfSJean-Christophe PLAGNIOL-VILLARD CONFIG_SYS_MONITOR_BASE, 20336d0f6bcfSJean-Christophe PLAGNIOL-VILLARD CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, 20346d0f6bcfSJean-Christophe PLAGNIOL-VILLARD flash_get_info(CONFIG_SYS_MONITOR_BASE)); 2035be60a902SHaavard Skinnemoen #endif 203659829cc1SJean-Christophe PLAGNIOL-VILLARD 2037be60a902SHaavard Skinnemoen /* Environment protection ON by default */ 20385a1aceb0SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_ENV_IS_IN_FLASH 2039be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 20400e8d1586SJean-Christophe PLAGNIOL-VILLARD CONFIG_ENV_ADDR, 20410e8d1586SJean-Christophe PLAGNIOL-VILLARD CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1, 20420e8d1586SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CONFIG_ENV_ADDR)); 2043be60a902SHaavard Skinnemoen #endif 2044be60a902SHaavard Skinnemoen 2045be60a902SHaavard Skinnemoen /* Redundant environment protection ON by default */ 20460e8d1586SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_ENV_ADDR_REDUND 2047be60a902SHaavard Skinnemoen flash_protect (FLAG_PROTECT_SET, 20480e8d1586SJean-Christophe PLAGNIOL-VILLARD CONFIG_ENV_ADDR_REDUND, 20490e8d1586SJean-Christophe PLAGNIOL-VILLARD CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SIZE_REDUND - 1, 20500e8d1586SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CONFIG_ENV_ADDR_REDUND)); 2051be60a902SHaavard Skinnemoen #endif 2052c63ad632SMatthias Fuchs 20536d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) 2054c63ad632SMatthias Fuchs for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) { 2055c63ad632SMatthias Fuchs debug("autoprotecting from %08x to %08x\n", 2056c63ad632SMatthias Fuchs apl[i].start, apl[i].start + apl[i].size - 1); 2057c63ad632SMatthias Fuchs flash_protect (FLAG_PROTECT_SET, 2058c63ad632SMatthias Fuchs apl[i].start, 2059c63ad632SMatthias Fuchs apl[i].start + apl[i].size - 1, 2060c63ad632SMatthias Fuchs flash_get_info(apl[i].start)); 2061c63ad632SMatthias Fuchs } 2062c63ad632SMatthias Fuchs #endif 2063be60a902SHaavard Skinnemoen return (size); 206459829cc1SJean-Christophe PLAGNIOL-VILLARD } 2065