159829cc1SJean-Christophe PLAGNIOL-VILLARD /* 259829cc1SJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2002-2004 359829cc1SJean-Christophe PLAGNIOL-VILLARD * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com 459829cc1SJean-Christophe PLAGNIOL-VILLARD * 559829cc1SJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2003 Arabella Software Ltd. 659829cc1SJean-Christophe PLAGNIOL-VILLARD * Yuli Barcohen <yuli@arabellasw.com> 759829cc1SJean-Christophe PLAGNIOL-VILLARD * 859829cc1SJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2004 959829cc1SJean-Christophe PLAGNIOL-VILLARD * Ed Okerson 1059829cc1SJean-Christophe PLAGNIOL-VILLARD * 1159829cc1SJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2006 1259829cc1SJean-Christophe PLAGNIOL-VILLARD * Tolunay Orkun <listmember@orkun.us> 1359829cc1SJean-Christophe PLAGNIOL-VILLARD * 1459829cc1SJean-Christophe PLAGNIOL-VILLARD * See file CREDITS for list of people who contributed to this 1559829cc1SJean-Christophe PLAGNIOL-VILLARD * project. 1659829cc1SJean-Christophe PLAGNIOL-VILLARD * 1759829cc1SJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or 1859829cc1SJean-Christophe PLAGNIOL-VILLARD * modify it under the terms of the GNU General Public License as 1959829cc1SJean-Christophe PLAGNIOL-VILLARD * published by the Free Software Foundation; either version 2 of 2059829cc1SJean-Christophe PLAGNIOL-VILLARD * the License, or (at your option) any later version. 2159829cc1SJean-Christophe PLAGNIOL-VILLARD * 2259829cc1SJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 2359829cc1SJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 2459829cc1SJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2559829cc1SJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 2659829cc1SJean-Christophe PLAGNIOL-VILLARD * 2759829cc1SJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 2859829cc1SJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 2959829cc1SJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 3059829cc1SJean-Christophe PLAGNIOL-VILLARD * MA 02111-1307 USA 3159829cc1SJean-Christophe PLAGNIOL-VILLARD * 3259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 3359829cc1SJean-Christophe PLAGNIOL-VILLARD 3459829cc1SJean-Christophe PLAGNIOL-VILLARD /* The DEBUG define must be before common to enable debugging */ 3559829cc1SJean-Christophe PLAGNIOL-VILLARD /* #define DEBUG */ 3659829cc1SJean-Christophe PLAGNIOL-VILLARD 3759829cc1SJean-Christophe PLAGNIOL-VILLARD #include <common.h> 3859829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/processor.h> 3959829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h> 4059829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/byteorder.h> 4159829cc1SJean-Christophe PLAGNIOL-VILLARD #include <environment.h> 4259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_CFI_DRIVER 4359829cc1SJean-Christophe PLAGNIOL-VILLARD 4459829cc1SJean-Christophe PLAGNIOL-VILLARD /* 457e5b9b47SHaavard Skinnemoen * This file implements a Common Flash Interface (CFI) driver for 467e5b9b47SHaavard Skinnemoen * U-Boot. 477e5b9b47SHaavard Skinnemoen * 487e5b9b47SHaavard Skinnemoen * The width of the port and the width of the chips are determined at 497e5b9b47SHaavard Skinnemoen * initialization. These widths are used to calculate the address for 507e5b9b47SHaavard Skinnemoen * access CFI data structures. 5159829cc1SJean-Christophe PLAGNIOL-VILLARD * 5259829cc1SJean-Christophe PLAGNIOL-VILLARD * References 5359829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JESD68 - Common Flash Interface (CFI) 5459829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes 5559829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets 5659829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet 5759829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD CFI Specification, Release 2.0 December 1, 2001 5859829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD/Spansion Application Note: Migration from Single-byte to Three-byte 5959829cc1SJean-Christophe PLAGNIOL-VILLARD * Device IDs, Publication Number 25538 Revision A, November 8, 2001 6059829cc1SJean-Christophe PLAGNIOL-VILLARD * 617e5b9b47SHaavard Skinnemoen * Define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between 6259829cc1SJean-Christophe PLAGNIOL-VILLARD * reading and writing ... (yes there is such a Hardware). 6359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 6459829cc1SJean-Christophe PLAGNIOL-VILLARD 6559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_BANKS_LIST 6659829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE } 6759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 6859829cc1SJean-Christophe PLAGNIOL-VILLARD 6959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CFI 0x98 7059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_READ_ID 0x90 7159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_RESET 0xff 7259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_BLOCK_ERASE 0x20 7359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_ERASE_CONFIRM 0xD0 7459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE 0x40 7559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT 0x60 7659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_SET 0x01 7759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_CLEAR 0xD0 7859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CLEAR_STATUS 0x50 7959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_TO_BUFFER 0xE8 8059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0 8159829cc1SJean-Christophe PLAGNIOL-VILLARD 8259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DONE 0x80 8359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ESS 0x40 8459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ECLBS 0x20 8559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSLBS 0x10 8659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_VPENS 0x08 8759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSS 0x04 8859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DPS 0x02 8959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_R 0x01 9059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PROTECT 0x01 9159829cc1SJean-Christophe PLAGNIOL-VILLARD 9259829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_RESET 0xF0 9359829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE 0xA0 9459829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_START 0x80 9559829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_SECTOR 0x30 9659829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_START 0xAA 9759829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_ACK 0x55 9859829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_TO_BUFFER 0x25 9959829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29 10059829cc1SJean-Christophe PLAGNIOL-VILLARD 10159829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_TOGGLE 0x40 10259829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_ERROR 0x20 10359829cc1SJean-Christophe PLAGNIOL-VILLARD 10459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_MANUFACTURER_ID 0x00 10559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID 0x01 10659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID2 0x0E 10759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID3 0x0F 10859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI 0x55 10959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_ALT 0x555 11059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_RESP 0x10 11159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PRIMARY_VENDOR 0x13 1127e5b9b47SHaavard Skinnemoen /* extended query table primary address */ 1137e5b9b47SHaavard Skinnemoen #define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15 11459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WTOUT 0x1F 11559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBTOUT 0x20 11659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ETOUT 0x21 11759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CETOUT 0x22 11859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WMAX_TOUT 0x23 11959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBMAX_TOUT 0x24 12059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EMAX_TOUT 0x25 12159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CEMAX_TOUT 0x26 12259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_SIZE 0x27 12359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTERFACE 0x28 12459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_BUFFER_SIZE 0x2A 12559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C 12659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ERASE_REGIONS 0x2D 12759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PROTECT 0x02 12859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_USER_PROTECTION 0x85 12959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTEL_PROTECTION 0x81 13059829cc1SJean-Christophe PLAGNIOL-VILLARD 13159829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_NONE 0 13259829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_EXTENDED 1 13359829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_STANDARD 2 13459829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_STANDARD 3 13559829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_EXTENDED 4 13659829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_STANDARD 256 13759829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_EXTENDED 257 13859829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_SST 258 13959829cc1SJean-Christophe PLAGNIOL-VILLARD 14059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */ 14159829cc1SJean-Christophe PLAGNIOL-VILLARD # undef FLASH_CMD_RESET 14259829cc1SJean-Christophe PLAGNIOL-VILLARD # define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */ 14359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 14459829cc1SJean-Christophe PLAGNIOL-VILLARD 14559829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union { 14659829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned char c; 14759829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned short w; 14859829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long l; 14959829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long long ll; 15059829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiword_t; 15159829cc1SJean-Christophe PLAGNIOL-VILLARD 15259829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union { 15359829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned char *cp; 15459829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned short *wp; 15559829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long *lp; 15659829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long long *llp; 15759829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiptr_t; 15859829cc1SJean-Christophe PLAGNIOL-VILLARD 15959829cc1SJean-Christophe PLAGNIOL-VILLARD #define NUM_ERASE_REGIONS 4 /* max. number of erase regions */ 16059829cc1SJean-Christophe PLAGNIOL-VILLARD 16159829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT }; 16259829cc1SJean-Christophe PLAGNIOL-VILLARD 16359829cc1SJean-Christophe PLAGNIOL-VILLARD /* use CFG_MAX_FLASH_BANKS_DETECT if defined */ 16459829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_MAX_FLASH_BANKS_DETECT 16559829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS_DETECT] = CFG_FLASH_BANKS_LIST; 16659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS_DETECT]; /* FLASH chips info */ 16759829cc1SJean-Christophe PLAGNIOL-VILLARD #else 16859829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST; 16959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */ 17059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 17159829cc1SJean-Christophe PLAGNIOL-VILLARD 17259829cc1SJean-Christophe PLAGNIOL-VILLARD /* 17359829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if chip width is defined. If not, start detecting with 8bit. 17459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 17559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_CFI_WIDTH 17659829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_CFI_WIDTH FLASH_CFI_8BIT 17759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 17859829cc1SJean-Christophe PLAGNIOL-VILLARD 17959829cc1SJean-Christophe PLAGNIOL-VILLARD 18059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 18159829cc1SJean-Christophe PLAGNIOL-VILLARD * Functions 18259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 18359829cc1SJean-Christophe PLAGNIOL-VILLARD 18459829cc1SJean-Christophe PLAGNIOL-VILLARD typedef unsigned long flash_sect_t; 18559829cc1SJean-Christophe PLAGNIOL-VILLARD 18659829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c); 18759829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf); 1887e5b9b47SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, 1897e5b9b47SHaavard Skinnemoen uint offset, uchar cmd); 19059829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect); 1917e5b9b47SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect, 1927e5b9b47SHaavard Skinnemoen uint offset, uchar cmd); 1937e5b9b47SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect, 1947e5b9b47SHaavard Skinnemoen uint offset, uchar cmd); 1957e5b9b47SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect, 1967e5b9b47SHaavard Skinnemoen uint offset, uchar cmd); 19759829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_read_jedec_ids (flash_info_t * info); 19859829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_detect_cfi (flash_info_t * info); 1997e5b9b47SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest, 2007e5b9b47SHaavard Skinnemoen cfiword_t cword); 20159829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, 20259829cc1SJean-Christophe PLAGNIOL-VILLARD ulong tout, char *prompt); 20359829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum); 20459829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 20559829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_info_t *flash_get_info(ulong base); 20659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 20759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 2087e5b9b47SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, 2097e5b9b47SHaavard Skinnemoen uchar * cp, int len); 21059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 21159829cc1SJean-Christophe PLAGNIOL-VILLARD 21259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 21359829cc1SJean-Christophe PLAGNIOL-VILLARD * create an address based on the offset and the port width 21459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 215*3055793bSHaavard Skinnemoen static inline uchar * 2167e5b9b47SHaavard Skinnemoen flash_make_addr (flash_info_t * info, flash_sect_t sect, uint offset) 21759829cc1SJean-Christophe PLAGNIOL-VILLARD { 21859829cc1SJean-Christophe PLAGNIOL-VILLARD return ((uchar *) (info->start[sect] + (offset * info->portwidth))); 21959829cc1SJean-Christophe PLAGNIOL-VILLARD } 22059829cc1SJean-Christophe PLAGNIOL-VILLARD 22159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 22259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 22359829cc1SJean-Christophe PLAGNIOL-VILLARD * Debug support 22459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 225*3055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data) 22659829cc1SJean-Christophe PLAGNIOL-VILLARD { 22759829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 22859829cc1SJean-Christophe PLAGNIOL-VILLARD char *cp; 22959829cc1SJean-Christophe PLAGNIOL-VILLARD 23059829cc1SJean-Christophe PLAGNIOL-VILLARD cp = (unsigned char *) &data; 23159829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < 8; i++) 23259829cc1SJean-Christophe PLAGNIOL-VILLARD sprintf (&str[i * 2], "%2.2x", *cp++); 23359829cc1SJean-Christophe PLAGNIOL-VILLARD } 23459829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_printqry (flash_info_t * info, flash_sect_t sect) 23559829cc1SJean-Christophe PLAGNIOL-VILLARD { 23659829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 23759829cc1SJean-Christophe PLAGNIOL-VILLARD int x, y; 23859829cc1SJean-Christophe PLAGNIOL-VILLARD 23959829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 0x40; x += 16U / info->portwidth) { 24059829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = 24159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_addr (info, sect, 24259829cc1SJean-Christophe PLAGNIOL-VILLARD x + FLASH_OFFSET_CFI_RESP); 24359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("%p : ", cptr.cp); 24459829cc1SJean-Christophe PLAGNIOL-VILLARD for (y = 0; y < 16; y++) { 24559829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("%2.2x ", cptr.cp[y]); 24659829cc1SJean-Christophe PLAGNIOL-VILLARD } 24759829cc1SJean-Christophe PLAGNIOL-VILLARD debug (" "); 24859829cc1SJean-Christophe PLAGNIOL-VILLARD for (y = 0; y < 16; y++) { 24959829cc1SJean-Christophe PLAGNIOL-VILLARD if (cptr.cp[y] >= 0x20 && cptr.cp[y] <= 0x7e) { 25059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("%c", cptr.cp[y]); 25159829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 25259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("."); 25359829cc1SJean-Christophe PLAGNIOL-VILLARD } 25459829cc1SJean-Christophe PLAGNIOL-VILLARD } 25559829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("\n"); 25659829cc1SJean-Christophe PLAGNIOL-VILLARD } 25759829cc1SJean-Christophe PLAGNIOL-VILLARD } 25859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 25959829cc1SJean-Christophe PLAGNIOL-VILLARD 26059829cc1SJean-Christophe PLAGNIOL-VILLARD 26159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 26259829cc1SJean-Christophe PLAGNIOL-VILLARD * read a character at a port width address 26359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 264*3055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset) 26559829cc1SJean-Christophe PLAGNIOL-VILLARD { 26659829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *cp; 26759829cc1SJean-Christophe PLAGNIOL-VILLARD 26859829cc1SJean-Christophe PLAGNIOL-VILLARD cp = flash_make_addr (info, 0, offset); 26959829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 27059829cc1SJean-Christophe PLAGNIOL-VILLARD return (cp[0]); 27159829cc1SJean-Christophe PLAGNIOL-VILLARD #else 27259829cc1SJean-Christophe PLAGNIOL-VILLARD return (cp[info->portwidth - 1]); 27359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 27459829cc1SJean-Christophe PLAGNIOL-VILLARD } 27559829cc1SJean-Christophe PLAGNIOL-VILLARD 27659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 27759829cc1SJean-Christophe PLAGNIOL-VILLARD * read a short word by swapping for ppc format. 27859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 279*3055793bSHaavard Skinnemoen static ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect, 280*3055793bSHaavard Skinnemoen uint offset) 28159829cc1SJean-Christophe PLAGNIOL-VILLARD { 28259829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *addr; 28359829cc1SJean-Christophe PLAGNIOL-VILLARD ushort retval; 28459829cc1SJean-Christophe PLAGNIOL-VILLARD 28559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 28659829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 28759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 28859829cc1SJean-Christophe PLAGNIOL-VILLARD addr = flash_make_addr (info, sect, offset); 28959829cc1SJean-Christophe PLAGNIOL-VILLARD 29059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 29159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("ushort addr is at %p info->portwidth = %d\n", addr, 29259829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth); 29359829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 2 * info->portwidth; x++) { 29459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("addr[%x] = 0x%x\n", x, addr[x]); 29559829cc1SJean-Christophe PLAGNIOL-VILLARD } 29659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 29759829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 29859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((addr[(info->portwidth)] << 8) | addr[0]); 29959829cc1SJean-Christophe PLAGNIOL-VILLARD #else 30059829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((addr[(2 * info->portwidth) - 1] << 8) | 30159829cc1SJean-Christophe PLAGNIOL-VILLARD addr[info->portwidth - 1]); 30259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 30359829cc1SJean-Christophe PLAGNIOL-VILLARD 30459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("retval = 0x%x\n", retval); 30559829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 30659829cc1SJean-Christophe PLAGNIOL-VILLARD } 30759829cc1SJean-Christophe PLAGNIOL-VILLARD 30859829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 30959829cc1SJean-Christophe PLAGNIOL-VILLARD * read a long word by picking the least significant byte of each maximum 31059829cc1SJean-Christophe PLAGNIOL-VILLARD * port size word. Swap for ppc format. 31159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 312*3055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect, 313*3055793bSHaavard Skinnemoen uint offset) 31459829cc1SJean-Christophe PLAGNIOL-VILLARD { 31559829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *addr; 31659829cc1SJean-Christophe PLAGNIOL-VILLARD ulong retval; 31759829cc1SJean-Christophe PLAGNIOL-VILLARD 31859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 31959829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 32059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 32159829cc1SJean-Christophe PLAGNIOL-VILLARD addr = flash_make_addr (info, sect, offset); 32259829cc1SJean-Christophe PLAGNIOL-VILLARD 32359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 32459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("long addr is at %p info->portwidth = %d\n", addr, 32559829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth); 32659829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 4 * info->portwidth; x++) { 32759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("addr[%x] = 0x%x\n", x, addr[x]); 32859829cc1SJean-Christophe PLAGNIOL-VILLARD } 32959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 33059829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 33159829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (addr[0] << 16) | (addr[(info->portwidth)] << 24) | 3327e5b9b47SHaavard Skinnemoen (addr[(2 * info->portwidth)]) | 3337e5b9b47SHaavard Skinnemoen (addr[(3 * info->portwidth)] << 8); 33459829cc1SJean-Christophe PLAGNIOL-VILLARD #else 33559829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (addr[(2 * info->portwidth) - 1] << 24) | 33659829cc1SJean-Christophe PLAGNIOL-VILLARD (addr[(info->portwidth) - 1] << 16) | 33759829cc1SJean-Christophe PLAGNIOL-VILLARD (addr[(4 * info->portwidth) - 1] << 8) | 33859829cc1SJean-Christophe PLAGNIOL-VILLARD addr[(3 * info->portwidth) - 1]; 33959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 34059829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 34159829cc1SJean-Christophe PLAGNIOL-VILLARD } 34259829cc1SJean-Christophe PLAGNIOL-VILLARD 34359829cc1SJean-Christophe PLAGNIOL-VILLARD 34481b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 34581b20cccSMichael Schwingen /*----------------------------------------------------------------------- 34681b20cccSMichael Schwingen * Call board code to request info about non-CFI flash. 34781b20cccSMichael Schwingen * board_flash_get_legacy needs to fill in at least: 34881b20cccSMichael Schwingen * info->portwidth, info->chipwidth and info->interface for Jedec probing. 34981b20cccSMichael Schwingen */ 350*3055793bSHaavard Skinnemoen static int flash_detect_legacy(ulong base, int banknum) 35181b20cccSMichael Schwingen { 35281b20cccSMichael Schwingen flash_info_t *info = &flash_info[banknum]; 3537e5b9b47SHaavard Skinnemoen 35481b20cccSMichael Schwingen if (board_flash_get_legacy(base, banknum, info)) { 35581b20cccSMichael Schwingen /* board code may have filled info completely. If not, we 35681b20cccSMichael Schwingen use JEDEC ID probing. */ 35781b20cccSMichael Schwingen if (!info->vendor) { 3587e5b9b47SHaavard Skinnemoen int modes[] = { 3597e5b9b47SHaavard Skinnemoen CFI_CMDSET_AMD_STANDARD, 3607e5b9b47SHaavard Skinnemoen CFI_CMDSET_INTEL_STANDARD 3617e5b9b47SHaavard Skinnemoen }; 36281b20cccSMichael Schwingen int i; 36381b20cccSMichael Schwingen 36481b20cccSMichael Schwingen for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) { 36581b20cccSMichael Schwingen info->vendor = modes[i]; 36681b20cccSMichael Schwingen info->start[0] = base; 3677e5b9b47SHaavard Skinnemoen if (info->portwidth == FLASH_CFI_8BIT 3687e5b9b47SHaavard Skinnemoen && info->interface == FLASH_CFI_X8X16) { 36981b20cccSMichael Schwingen info->addr_unlock1 = 0x2AAA; 37081b20cccSMichael Schwingen info->addr_unlock2 = 0x5555; 37181b20cccSMichael Schwingen } else { 37281b20cccSMichael Schwingen info->addr_unlock1 = 0x5555; 37381b20cccSMichael Schwingen info->addr_unlock2 = 0x2AAA; 37481b20cccSMichael Schwingen } 37581b20cccSMichael Schwingen flash_read_jedec_ids(info); 3767e5b9b47SHaavard Skinnemoen debug("JEDEC PROBE: ID %x %x %x\n", 3777e5b9b47SHaavard Skinnemoen info->manufacturer_id, 3787e5b9b47SHaavard Skinnemoen info->device_id, 3797e5b9b47SHaavard Skinnemoen info->device_id2); 38081b20cccSMichael Schwingen if (jedec_flash_match(info, base)) 38181b20cccSMichael Schwingen break; 38281b20cccSMichael Schwingen } 38381b20cccSMichael Schwingen } 3847e5b9b47SHaavard Skinnemoen 38581b20cccSMichael Schwingen switch(info->vendor) { 38681b20cccSMichael Schwingen case CFI_CMDSET_INTEL_STANDARD: 38781b20cccSMichael Schwingen case CFI_CMDSET_INTEL_EXTENDED: 38881b20cccSMichael Schwingen info->cmd_reset = FLASH_CMD_RESET; 38981b20cccSMichael Schwingen break; 39081b20cccSMichael Schwingen case CFI_CMDSET_AMD_STANDARD: 39181b20cccSMichael Schwingen case CFI_CMDSET_AMD_EXTENDED: 39281b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 39381b20cccSMichael Schwingen info->cmd_reset = AMD_CMD_RESET; 39481b20cccSMichael Schwingen break; 39581b20cccSMichael Schwingen } 39681b20cccSMichael Schwingen info->flash_id = FLASH_MAN_CFI; 39781b20cccSMichael Schwingen return 1; 39881b20cccSMichael Schwingen } 39981b20cccSMichael Schwingen return 0; /* use CFI */ 40081b20cccSMichael Schwingen } 40181b20cccSMichael Schwingen #else 402*3055793bSHaavard Skinnemoen static inline int flash_detect_legacy(ulong base, int banknum) 40381b20cccSMichael Schwingen { 40481b20cccSMichael Schwingen return 0; /* use CFI */ 40581b20cccSMichael Schwingen } 40681b20cccSMichael Schwingen #endif 40781b20cccSMichael Schwingen 40881b20cccSMichael Schwingen 40959829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 41059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 41159829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long flash_init (void) 41259829cc1SJean-Christophe PLAGNIOL-VILLARD { 41359829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long size = 0; 41459829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 41559829cc1SJean-Christophe PLAGNIOL-VILLARD 41659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 41759829cc1SJean-Christophe PLAGNIOL-VILLARD char *s = getenv("unlock"); 41859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 41959829cc1SJean-Christophe PLAGNIOL-VILLARD 42059829cc1SJean-Christophe PLAGNIOL-VILLARD /* Init: no FLASHes known */ 42159829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { 42259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].flash_id = FLASH_UNKNOWN; 42381b20cccSMichael Schwingen 42481b20cccSMichael Schwingen if (!flash_detect_legacy (bank_base[i], i)) 42581b20cccSMichael Schwingen flash_get_size (bank_base[i], i); 42681b20cccSMichael Schwingen size += flash_info[i].size; 42759829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_info[i].flash_id == FLASH_UNKNOWN) { 42859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_QUIET_TEST 4297e5b9b47SHaavard Skinnemoen printf ("## Unknown FLASH on Bank %d " 4307e5b9b47SHaavard Skinnemoen "- Size = 0x%08lx = %ld MB\n", 4317e5b9b47SHaavard Skinnemoen i+1, flash_info[i].size, 4327e5b9b47SHaavard Skinnemoen flash_info[i].size << 20); 43359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_QUIET_TEST */ 43459829cc1SJean-Christophe PLAGNIOL-VILLARD } 43559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 43659829cc1SJean-Christophe PLAGNIOL-VILLARD else if ((s != NULL) && (strcmp(s, "yes") == 0)) { 43759829cc1SJean-Christophe PLAGNIOL-VILLARD /* 4387e5b9b47SHaavard Skinnemoen * Only the U-Boot image and it's environment 4397e5b9b47SHaavard Skinnemoen * is protected, all other sectors are 4407e5b9b47SHaavard Skinnemoen * unprotected (unlocked) if flash hardware 4417e5b9b47SHaavard Skinnemoen * protection is used (CFG_FLASH_PROTECTION) 4427e5b9b47SHaavard Skinnemoen * and the environment variable "unlock" is 4437e5b9b47SHaavard Skinnemoen * set to "yes". 44459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 44559829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_info[i].legacy_unlock) { 44659829cc1SJean-Christophe PLAGNIOL-VILLARD int k; 44759829cc1SJean-Christophe PLAGNIOL-VILLARD 44859829cc1SJean-Christophe PLAGNIOL-VILLARD /* 4497e5b9b47SHaavard Skinnemoen * Disable legacy_unlock temporarily, 4507e5b9b47SHaavard Skinnemoen * since flash_real_protect would 4517e5b9b47SHaavard Skinnemoen * relock all other sectors again 4527e5b9b47SHaavard Skinnemoen * otherwise. 45359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 45459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].legacy_unlock = 0; 45559829cc1SJean-Christophe PLAGNIOL-VILLARD 45659829cc1SJean-Christophe PLAGNIOL-VILLARD /* 4577e5b9b47SHaavard Skinnemoen * Legacy unlocking (e.g. Intel J3) -> 4587e5b9b47SHaavard Skinnemoen * unlock only one sector. This will 4597e5b9b47SHaavard Skinnemoen * unlock all sectors. 46059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 46159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (&flash_info[i], 0, 0); 46259829cc1SJean-Christophe PLAGNIOL-VILLARD 46359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].legacy_unlock = 1; 46459829cc1SJean-Christophe PLAGNIOL-VILLARD 46559829cc1SJean-Christophe PLAGNIOL-VILLARD /* 4667e5b9b47SHaavard Skinnemoen * Manually mark other sectors as 4677e5b9b47SHaavard Skinnemoen * unlocked (unprotected) 46859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 46959829cc1SJean-Christophe PLAGNIOL-VILLARD for (k = 1; k < flash_info[i].sector_count; k++) 47059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].protect[k] = 0; 47159829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 47259829cc1SJean-Christophe PLAGNIOL-VILLARD /* 47359829cc1SJean-Christophe PLAGNIOL-VILLARD * No legancy unlocking -> unlock all sectors 47459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 47559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_CLEAR, 47659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].start[0], 4777e5b9b47SHaavard Skinnemoen flash_info[i].start[0] 4787e5b9b47SHaavard Skinnemoen + flash_info[i].size - 1, 47959829cc1SJean-Christophe PLAGNIOL-VILLARD &flash_info[i]); 48059829cc1SJean-Christophe PLAGNIOL-VILLARD } 48159829cc1SJean-Christophe PLAGNIOL-VILLARD } 48259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */ 48359829cc1SJean-Christophe PLAGNIOL-VILLARD } 48459829cc1SJean-Christophe PLAGNIOL-VILLARD 48559829cc1SJean-Christophe PLAGNIOL-VILLARD /* Monitor protection ON by default */ 48659829cc1SJean-Christophe PLAGNIOL-VILLARD #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 48759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_SET, 48859829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_MONITOR_BASE, 48959829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_MONITOR_BASE + monitor_flash_len - 1, 49059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CFG_MONITOR_BASE)); 49159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 49259829cc1SJean-Christophe PLAGNIOL-VILLARD 49359829cc1SJean-Christophe PLAGNIOL-VILLARD /* Environment protection ON by default */ 49459829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_ENV_IS_IN_FLASH 49559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_SET, 49659829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR, 49759829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, 49859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CFG_ENV_ADDR)); 49959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 50059829cc1SJean-Christophe PLAGNIOL-VILLARD 50159829cc1SJean-Christophe PLAGNIOL-VILLARD /* Redundant environment protection ON by default */ 50259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_ENV_ADDR_REDUND 50359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_SET, 50459829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR_REDUND, 50559829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1, 50659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CFG_ENV_ADDR_REDUND)); 50759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 50859829cc1SJean-Christophe PLAGNIOL-VILLARD return (size); 50959829cc1SJean-Christophe PLAGNIOL-VILLARD } 51059829cc1SJean-Christophe PLAGNIOL-VILLARD 51159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 51259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 51359829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 51459829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_info_t *flash_get_info(ulong base) 51559829cc1SJean-Christophe PLAGNIOL-VILLARD { 51659829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 51759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t * info = 0; 51859829cc1SJean-Christophe PLAGNIOL-VILLARD 51959829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { 52059829cc1SJean-Christophe PLAGNIOL-VILLARD info = & flash_info[i]; 52159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->size && info->start[0] <= base && 52259829cc1SJean-Christophe PLAGNIOL-VILLARD base <= info->start[0] + info->size - 1) 52359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 52459829cc1SJean-Christophe PLAGNIOL-VILLARD } 52559829cc1SJean-Christophe PLAGNIOL-VILLARD 52659829cc1SJean-Christophe PLAGNIOL-VILLARD return i == CFG_MAX_FLASH_BANKS ? 0 : info; 52759829cc1SJean-Christophe PLAGNIOL-VILLARD } 52859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 52959829cc1SJean-Christophe PLAGNIOL-VILLARD 53059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 53159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 53259829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last) 53359829cc1SJean-Christophe PLAGNIOL-VILLARD { 53459829cc1SJean-Christophe PLAGNIOL-VILLARD int rcode = 0; 53559829cc1SJean-Christophe PLAGNIOL-VILLARD int prot; 53659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect; 53759829cc1SJean-Christophe PLAGNIOL-VILLARD 53859829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 53959829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Can't erase unknown flash type - aborted\n"); 54059829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 54159829cc1SJean-Christophe PLAGNIOL-VILLARD } 54259829cc1SJean-Christophe PLAGNIOL-VILLARD if ((s_first < 0) || (s_first > s_last)) { 54359829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("- no sectors to erase\n"); 54459829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 54559829cc1SJean-Christophe PLAGNIOL-VILLARD } 54659829cc1SJean-Christophe PLAGNIOL-VILLARD 54759829cc1SJean-Christophe PLAGNIOL-VILLARD prot = 0; 54859829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; ++sect) { 54959829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect]) { 55059829cc1SJean-Christophe PLAGNIOL-VILLARD prot++; 55159829cc1SJean-Christophe PLAGNIOL-VILLARD } 55259829cc1SJean-Christophe PLAGNIOL-VILLARD } 55359829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) { 5547e5b9b47SHaavard Skinnemoen printf ("- Warning: %d protected sectors will not be erased!\n", 5557e5b9b47SHaavard Skinnemoen prot); 55659829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 55759829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 55859829cc1SJean-Christophe PLAGNIOL-VILLARD } 55959829cc1SJean-Christophe PLAGNIOL-VILLARD 56059829cc1SJean-Christophe PLAGNIOL-VILLARD 56159829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; sect++) { 56259829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect] == 0) { /* not protected */ 56359829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 56459829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 56559829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 5667e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 5677e5b9b47SHaavard Skinnemoen FLASH_CMD_CLEAR_STATUS); 5687e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 5697e5b9b47SHaavard Skinnemoen FLASH_CMD_BLOCK_ERASE); 5707e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 5717e5b9b47SHaavard Skinnemoen FLASH_CMD_ERASE_CONFIRM); 57259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 57359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 57459829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 57559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 5767e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 5777e5b9b47SHaavard Skinnemoen info->addr_unlock1, 5787e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 57959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 5807e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 5817e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_SECTOR); 58259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 58381b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 58481b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 58581b20cccSMichael Schwingen flash_unlock_seq (info, 0); 5867e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, info->addr_unlock1, 5877e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_START); 58881b20cccSMichael Schwingen flash_unlock_seq (info, 0); 5897e5b9b47SHaavard Skinnemoen flash_write_cmd (info, sect, 0, 5907e5b9b47SHaavard Skinnemoen AMD_CMD_ERASE_SECTOR); 59181b20cccSMichael Schwingen break; 59281b20cccSMichael Schwingen #endif 59359829cc1SJean-Christophe PLAGNIOL-VILLARD default: 59459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("Unkown flash vendor %d\n", 59559829cc1SJean-Christophe PLAGNIOL-VILLARD info->vendor); 59659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 59759829cc1SJean-Christophe PLAGNIOL-VILLARD } 59859829cc1SJean-Christophe PLAGNIOL-VILLARD 59959829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_full_status_check 60059829cc1SJean-Christophe PLAGNIOL-VILLARD (info, sect, info->erase_blk_tout, "erase")) { 60159829cc1SJean-Christophe PLAGNIOL-VILLARD rcode = 1; 60259829cc1SJean-Christophe PLAGNIOL-VILLARD } else 60359829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('.'); 60459829cc1SJean-Christophe PLAGNIOL-VILLARD } 60559829cc1SJean-Christophe PLAGNIOL-VILLARD } 60659829cc1SJean-Christophe PLAGNIOL-VILLARD puts (" done\n"); 60759829cc1SJean-Christophe PLAGNIOL-VILLARD return rcode; 60859829cc1SJean-Christophe PLAGNIOL-VILLARD } 60959829cc1SJean-Christophe PLAGNIOL-VILLARD 61059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 61159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 61259829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info) 61359829cc1SJean-Christophe PLAGNIOL-VILLARD { 61459829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 61559829cc1SJean-Christophe PLAGNIOL-VILLARD 61659829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 61759829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("missing or unknown FLASH type\n"); 61859829cc1SJean-Christophe PLAGNIOL-VILLARD return; 61959829cc1SJean-Christophe PLAGNIOL-VILLARD } 62059829cc1SJean-Christophe PLAGNIOL-VILLARD 62181b20cccSMichael Schwingen printf ("%s FLASH (%d x %d)", 62281b20cccSMichael Schwingen info->name, 62359829cc1SJean-Christophe PLAGNIOL-VILLARD (info->portwidth << 3), (info->chipwidth << 3)); 62481b20cccSMichael Schwingen if (info->size < 1024*1024) 62581b20cccSMichael Schwingen printf (" Size: %ld kB in %d Sectors\n", 62681b20cccSMichael Schwingen info->size >> 10, info->sector_count); 62781b20cccSMichael Schwingen else 62859829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" Size: %ld MB in %d Sectors\n", 62959829cc1SJean-Christophe PLAGNIOL-VILLARD info->size >> 20, info->sector_count); 63059829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" "); 63159829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 63259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 63359829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Standard"); 63459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 63559829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 63659829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Extended"); 63759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 63859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 63959829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Standard"); 64059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 64159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 64259829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Extended"); 64359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 64481b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 64581b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 64681b20cccSMichael Schwingen printf ("AMD Legacy"); 64781b20cccSMichael Schwingen break; 64881b20cccSMichael Schwingen #endif 64959829cc1SJean-Christophe PLAGNIOL-VILLARD default: 65059829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Unknown (%d)", info->vendor); 65159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 65259829cc1SJean-Christophe PLAGNIOL-VILLARD } 65359829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X", 65459829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id, info->device_id); 65559829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 65659829cc1SJean-Christophe PLAGNIOL-VILLARD printf("%04X", info->device_id2); 65759829cc1SJean-Christophe PLAGNIOL-VILLARD } 65859829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n", 65959829cc1SJean-Christophe PLAGNIOL-VILLARD info->erase_blk_tout, 66059829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout); 66159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size > 1) { 6627e5b9b47SHaavard Skinnemoen printf (" Buffer write timeout: %ld ms, " 6637e5b9b47SHaavard Skinnemoen "buffer size: %d bytes\n", 66459829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout, 66559829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_size); 66659829cc1SJean-Christophe PLAGNIOL-VILLARD } 66759829cc1SJean-Christophe PLAGNIOL-VILLARD 66859829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("\n Sector Start Addresses:"); 66959829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; ++i) { 67059829cc1SJean-Christophe PLAGNIOL-VILLARD if ((i % 5) == 0) 67159829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n"); 67259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_EMPTY_INFO 67359829cc1SJean-Christophe PLAGNIOL-VILLARD int k; 67459829cc1SJean-Christophe PLAGNIOL-VILLARD int size; 67559829cc1SJean-Christophe PLAGNIOL-VILLARD int erased; 67659829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long *flash; 67759829cc1SJean-Christophe PLAGNIOL-VILLARD 67859829cc1SJean-Christophe PLAGNIOL-VILLARD /* 67959829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if whole sector is erased 68059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 68159829cc1SJean-Christophe PLAGNIOL-VILLARD if (i != (info->sector_count - 1)) 68259829cc1SJean-Christophe PLAGNIOL-VILLARD size = info->start[i + 1] - info->start[i]; 68359829cc1SJean-Christophe PLAGNIOL-VILLARD else 68459829cc1SJean-Christophe PLAGNIOL-VILLARD size = info->start[0] + info->size - info->start[i]; 68559829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 1; 68659829cc1SJean-Christophe PLAGNIOL-VILLARD flash = (volatile unsigned long *) info->start[i]; 68759829cc1SJean-Christophe PLAGNIOL-VILLARD size = size >> 2; /* divide by 4 for longword access */ 68859829cc1SJean-Christophe PLAGNIOL-VILLARD for (k = 0; k < size; k++) { 68959829cc1SJean-Christophe PLAGNIOL-VILLARD if (*flash++ != 0xffffffff) { 69059829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 0; 69159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 69259829cc1SJean-Christophe PLAGNIOL-VILLARD } 69359829cc1SJean-Christophe PLAGNIOL-VILLARD } 69459829cc1SJean-Christophe PLAGNIOL-VILLARD 69559829cc1SJean-Christophe PLAGNIOL-VILLARD /* print empty and read-only info */ 69659829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %c %s ", 69759829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 69859829cc1SJean-Christophe PLAGNIOL-VILLARD erased ? 'E' : ' ', 69959829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 70059829cc1SJean-Christophe PLAGNIOL-VILLARD #else /* ! CFG_FLASH_EMPTY_INFO */ 70159829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %s ", 70259829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 70359829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 70459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 70559829cc1SJean-Christophe PLAGNIOL-VILLARD } 70659829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 70759829cc1SJean-Christophe PLAGNIOL-VILLARD return; 70859829cc1SJean-Christophe PLAGNIOL-VILLARD } 70959829cc1SJean-Christophe PLAGNIOL-VILLARD 71059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 71159829cc1SJean-Christophe PLAGNIOL-VILLARD * Copy memory to flash, returns: 71259829cc1SJean-Christophe PLAGNIOL-VILLARD * 0 - OK 71359829cc1SJean-Christophe PLAGNIOL-VILLARD * 1 - write timeout 71459829cc1SJean-Christophe PLAGNIOL-VILLARD * 2 - Flash not erased 71559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 71659829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) 71759829cc1SJean-Christophe PLAGNIOL-VILLARD { 71859829cc1SJean-Christophe PLAGNIOL-VILLARD ulong wp; 71959829cc1SJean-Christophe PLAGNIOL-VILLARD ulong cp; 72059829cc1SJean-Christophe PLAGNIOL-VILLARD int aln; 72159829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 72259829cc1SJean-Christophe PLAGNIOL-VILLARD int i, rc; 72359829cc1SJean-Christophe PLAGNIOL-VILLARD 72459829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 72559829cc1SJean-Christophe PLAGNIOL-VILLARD int buffered_size; 72659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 72759829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 72859829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 72959829cc1SJean-Christophe PLAGNIOL-VILLARD wp = (addr & ~(info->portwidth - 1)); 73059829cc1SJean-Christophe PLAGNIOL-VILLARD 73159829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle unaligned start */ 73259829cc1SJean-Christophe PLAGNIOL-VILLARD if ((aln = addr - wp) != 0) { 73359829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 73459829cc1SJean-Christophe PLAGNIOL-VILLARD cp = wp; 73559829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < aln; ++i, ++cp) 73659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, (*(uchar *) cp)); 73759829cc1SJean-Christophe PLAGNIOL-VILLARD 73859829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (i < info->portwidth) && (cnt > 0); i++) { 73959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 74059829cc1SJean-Christophe PLAGNIOL-VILLARD cnt--; 74159829cc1SJean-Christophe PLAGNIOL-VILLARD cp++; 74259829cc1SJean-Christophe PLAGNIOL-VILLARD } 74359829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp) 74459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, (*(uchar *) cp)); 74559829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 74659829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 74759829cc1SJean-Christophe PLAGNIOL-VILLARD wp = cp; 74859829cc1SJean-Christophe PLAGNIOL-VILLARD } 74959829cc1SJean-Christophe PLAGNIOL-VILLARD 75059829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle the aligned part */ 75159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 75259829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size = (info->portwidth / info->chipwidth); 75359829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size *= info->buffer_size; 75459829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 75559829cc1SJean-Christophe PLAGNIOL-VILLARD /* prohibit buffer write when buffer_size is 1 */ 75659829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size == 1) { 75759829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 75859829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) 75959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 76059829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 76159829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 76259829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 76359829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 76459829cc1SJean-Christophe PLAGNIOL-VILLARD continue; 76559829cc1SJean-Christophe PLAGNIOL-VILLARD } 76659829cc1SJean-Christophe PLAGNIOL-VILLARD 76759829cc1SJean-Christophe PLAGNIOL-VILLARD /* write buffer until next buffered_size aligned boundary */ 76859829cc1SJean-Christophe PLAGNIOL-VILLARD i = buffered_size - (wp % buffered_size); 76959829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > cnt) 77059829cc1SJean-Christophe PLAGNIOL-VILLARD i = cnt; 77159829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) 77259829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 77359829cc1SJean-Christophe PLAGNIOL-VILLARD i -= i & (info->portwidth - 1); 77459829cc1SJean-Christophe PLAGNIOL-VILLARD wp += i; 77559829cc1SJean-Christophe PLAGNIOL-VILLARD src += i; 77659829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= i; 77759829cc1SJean-Christophe PLAGNIOL-VILLARD } 77859829cc1SJean-Christophe PLAGNIOL-VILLARD #else 77959829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 78059829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 78159829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) { 78259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 78359829cc1SJean-Christophe PLAGNIOL-VILLARD } 78459829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 78559829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 78659829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 78759829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 78859829cc1SJean-Christophe PLAGNIOL-VILLARD } 78959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */ 79059829cc1SJean-Christophe PLAGNIOL-VILLARD if (cnt == 0) { 79159829cc1SJean-Christophe PLAGNIOL-VILLARD return (0); 79259829cc1SJean-Christophe PLAGNIOL-VILLARD } 79359829cc1SJean-Christophe PLAGNIOL-VILLARD 79459829cc1SJean-Christophe PLAGNIOL-VILLARD /* 79559829cc1SJean-Christophe PLAGNIOL-VILLARD * handle unaligned tail bytes 79659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 79759829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 79859829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) { 79959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 80059829cc1SJean-Christophe PLAGNIOL-VILLARD --cnt; 80159829cc1SJean-Christophe PLAGNIOL-VILLARD } 80259829cc1SJean-Christophe PLAGNIOL-VILLARD for (; i < info->portwidth; ++i, ++cp) { 80359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, (*(uchar *) cp)); 80459829cc1SJean-Christophe PLAGNIOL-VILLARD } 80559829cc1SJean-Christophe PLAGNIOL-VILLARD 80659829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_write_cfiword (info, wp, cword); 80759829cc1SJean-Christophe PLAGNIOL-VILLARD } 80859829cc1SJean-Christophe PLAGNIOL-VILLARD 80959829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 81059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 81159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 81259829cc1SJean-Christophe PLAGNIOL-VILLARD 81359829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot) 81459829cc1SJean-Christophe PLAGNIOL-VILLARD { 81559829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode = 0; 81659829cc1SJean-Christophe PLAGNIOL-VILLARD 81759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 81859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); 81959829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) 82059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); 82159829cc1SJean-Christophe PLAGNIOL-VILLARD else 82259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR); 82359829cc1SJean-Christophe PLAGNIOL-VILLARD 82459829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode = 82559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_full_status_check (info, sector, info->erase_blk_tout, 82659829cc1SJean-Christophe PLAGNIOL-VILLARD prot ? "protect" : "unprotect")) == 0) { 82759829cc1SJean-Christophe PLAGNIOL-VILLARD 82859829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sector] = prot; 82959829cc1SJean-Christophe PLAGNIOL-VILLARD 83059829cc1SJean-Christophe PLAGNIOL-VILLARD /* 83159829cc1SJean-Christophe PLAGNIOL-VILLARD * On some of Intel's flash chips (marked via legacy_unlock) 83259829cc1SJean-Christophe PLAGNIOL-VILLARD * unprotect unprotects all locking. 83359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 83459829cc1SJean-Christophe PLAGNIOL-VILLARD if ((prot == 0) && (info->legacy_unlock)) { 83559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t i; 83659829cc1SJean-Christophe PLAGNIOL-VILLARD 83759829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; i++) { 83859829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[i]) 83959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (info, i, 1); 84059829cc1SJean-Christophe PLAGNIOL-VILLARD } 84159829cc1SJean-Christophe PLAGNIOL-VILLARD } 84259829cc1SJean-Christophe PLAGNIOL-VILLARD } 84359829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 84459829cc1SJean-Christophe PLAGNIOL-VILLARD } 84559829cc1SJean-Christophe PLAGNIOL-VILLARD 84659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 84759829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_user_serial - read the OneTimeProgramming cells 84859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 84959829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, 85059829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 85159829cc1SJean-Christophe PLAGNIOL-VILLARD { 85259829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 85359829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *dst; 85459829cc1SJean-Christophe PLAGNIOL-VILLARD 85559829cc1SJean-Christophe PLAGNIOL-VILLARD dst = buffer; 85659829cc1SJean-Christophe PLAGNIOL-VILLARD src = flash_make_addr (info, 0, FLASH_OFFSET_USER_PROTECTION); 85759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 85859829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (dst, src + offset, len); 85959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 86059829cc1SJean-Christophe PLAGNIOL-VILLARD } 86159829cc1SJean-Christophe PLAGNIOL-VILLARD 86259829cc1SJean-Christophe PLAGNIOL-VILLARD /* 86359829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_factory_serial - read the device Id from the protection area 86459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 86559829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, 86659829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 86759829cc1SJean-Christophe PLAGNIOL-VILLARD { 86859829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 86959829cc1SJean-Christophe PLAGNIOL-VILLARD 87059829cc1SJean-Christophe PLAGNIOL-VILLARD src = flash_make_addr (info, 0, FLASH_OFFSET_INTEL_PROTECTION); 87159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 87259829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (buffer, src + offset, len); 87359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 87459829cc1SJean-Christophe PLAGNIOL-VILLARD } 87559829cc1SJean-Christophe PLAGNIOL-VILLARD 87659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */ 87759829cc1SJean-Christophe PLAGNIOL-VILLARD 87859829cc1SJean-Christophe PLAGNIOL-VILLARD /* 87959829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_is_busy - check to see if the flash is busy 8807e5b9b47SHaavard Skinnemoen * 8817e5b9b47SHaavard Skinnemoen * This routine checks the status of the chip and returns true if the 8827e5b9b47SHaavard Skinnemoen * chip is busy. 88359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 88459829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_is_busy (flash_info_t * info, flash_sect_t sect) 88559829cc1SJean-Christophe PLAGNIOL-VILLARD { 88659829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 88759829cc1SJean-Christophe PLAGNIOL-VILLARD 88859829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 88959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 89059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 89159829cc1SJean-Christophe PLAGNIOL-VILLARD retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); 89259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 89359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 89459829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 89581b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 89681b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 89781b20cccSMichael Schwingen #endif 89859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); 89959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 90059829cc1SJean-Christophe PLAGNIOL-VILLARD default: 90159829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 90259829cc1SJean-Christophe PLAGNIOL-VILLARD } 90359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("flash_is_busy: %d\n", retval); 90459829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 90559829cc1SJean-Christophe PLAGNIOL-VILLARD } 90659829cc1SJean-Christophe PLAGNIOL-VILLARD 90759829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 90859829cc1SJean-Christophe PLAGNIOL-VILLARD * wait for XSR.7 to be set. Time out with an error if it does not. 90959829cc1SJean-Christophe PLAGNIOL-VILLARD * This routine does not set the flash to read-array mode. 91059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 91159829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_status_check (flash_info_t * info, flash_sect_t sector, 91259829cc1SJean-Christophe PLAGNIOL-VILLARD ulong tout, char *prompt) 91359829cc1SJean-Christophe PLAGNIOL-VILLARD { 91459829cc1SJean-Christophe PLAGNIOL-VILLARD ulong start; 91559829cc1SJean-Christophe PLAGNIOL-VILLARD 91659829cc1SJean-Christophe PLAGNIOL-VILLARD #if CFG_HZ != 1000 91759829cc1SJean-Christophe PLAGNIOL-VILLARD tout *= CFG_HZ/1000; 91859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 91959829cc1SJean-Christophe PLAGNIOL-VILLARD 92059829cc1SJean-Christophe PLAGNIOL-VILLARD /* Wait for command completion */ 92159829cc1SJean-Christophe PLAGNIOL-VILLARD start = get_timer (0); 92259829cc1SJean-Christophe PLAGNIOL-VILLARD while (flash_is_busy (info, sector)) { 92359829cc1SJean-Christophe PLAGNIOL-VILLARD if (get_timer (start) > tout) { 92459829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Flash %s timeout at address %lx data %lx\n", 92559829cc1SJean-Christophe PLAGNIOL-VILLARD prompt, info->start[sector], 92659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_read_long (info, sector, 0)); 92759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, info->cmd_reset); 92859829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_TIMOUT; 92959829cc1SJean-Christophe PLAGNIOL-VILLARD } 93059829cc1SJean-Christophe PLAGNIOL-VILLARD udelay (1); /* also triggers watchdog */ 93159829cc1SJean-Christophe PLAGNIOL-VILLARD } 93259829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_OK; 93359829cc1SJean-Christophe PLAGNIOL-VILLARD } 93459829cc1SJean-Christophe PLAGNIOL-VILLARD 93559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 9367e5b9b47SHaavard Skinnemoen * Wait for XSR.7 to be set, if it times out print an error, otherwise 9377e5b9b47SHaavard Skinnemoen * do a full status check. 9387e5b9b47SHaavard Skinnemoen * 93959829cc1SJean-Christophe PLAGNIOL-VILLARD * This routine sets the flash to read-array mode. 94059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 94159829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, 94259829cc1SJean-Christophe PLAGNIOL-VILLARD ulong tout, char *prompt) 94359829cc1SJean-Christophe PLAGNIOL-VILLARD { 94459829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode; 94559829cc1SJean-Christophe PLAGNIOL-VILLARD 94659829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = flash_status_check (info, sector, tout, prompt); 94759829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 94859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 94959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 95059829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode == ERR_OK) 95159829cc1SJean-Christophe PLAGNIOL-VILLARD && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { 95259829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = ERR_INVAL; 95359829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Flash %s error at address %lx\n", prompt, 95459829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[sector]); 9557e5b9b47SHaavard Skinnemoen if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | 9567e5b9b47SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 95759829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Command Sequence Error.\n"); 9587e5b9b47SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 9597e5b9b47SHaavard Skinnemoen FLASH_STATUS_ECLBS)) { 96059829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Block Erase Error.\n"); 96159829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = ERR_NOT_ERASED; 9627e5b9b47SHaavard Skinnemoen } else if (flash_isset (info, sector, 0, 9637e5b9b47SHaavard Skinnemoen FLASH_STATUS_PSLBS)) { 96459829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Locking Error\n"); 96559829cc1SJean-Christophe PLAGNIOL-VILLARD } 96659829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { 96759829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Block locked.\n"); 96859829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = ERR_PROTECTED; 96959829cc1SJean-Christophe PLAGNIOL-VILLARD } 97059829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) 97159829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Vpp Low Error.\n"); 97259829cc1SJean-Christophe PLAGNIOL-VILLARD } 97359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, info->cmd_reset); 97459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 97559829cc1SJean-Christophe PLAGNIOL-VILLARD default: 97659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 97759829cc1SJean-Christophe PLAGNIOL-VILLARD } 97859829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 97959829cc1SJean-Christophe PLAGNIOL-VILLARD } 98059829cc1SJean-Christophe PLAGNIOL-VILLARD 98159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 98259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 98359829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) 98459829cc1SJean-Christophe PLAGNIOL-VILLARD { 98559829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 98659829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned short w; 98759829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned int l; 98859829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long long ll; 98959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 99059829cc1SJean-Christophe PLAGNIOL-VILLARD 99159829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 99259829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 99359829cc1SJean-Christophe PLAGNIOL-VILLARD cword->c = c; 99459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 99559829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 99659829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 99759829cc1SJean-Christophe PLAGNIOL-VILLARD w = c; 99859829cc1SJean-Christophe PLAGNIOL-VILLARD w <<= 8; 99959829cc1SJean-Christophe PLAGNIOL-VILLARD cword->w = (cword->w >> 8) | w; 100059829cc1SJean-Christophe PLAGNIOL-VILLARD #else 100159829cc1SJean-Christophe PLAGNIOL-VILLARD cword->w = (cword->w << 8) | c; 100259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 100359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 100459829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 100559829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 100659829cc1SJean-Christophe PLAGNIOL-VILLARD l = c; 100759829cc1SJean-Christophe PLAGNIOL-VILLARD l <<= 24; 100859829cc1SJean-Christophe PLAGNIOL-VILLARD cword->l = (cword->l >> 8) | l; 100959829cc1SJean-Christophe PLAGNIOL-VILLARD #else 101059829cc1SJean-Christophe PLAGNIOL-VILLARD cword->l = (cword->l << 8) | c; 101159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 101259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 101359829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 101459829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 101559829cc1SJean-Christophe PLAGNIOL-VILLARD ll = c; 101659829cc1SJean-Christophe PLAGNIOL-VILLARD ll <<= 56; 101759829cc1SJean-Christophe PLAGNIOL-VILLARD cword->ll = (cword->ll >> 8) | ll; 101859829cc1SJean-Christophe PLAGNIOL-VILLARD #else 101959829cc1SJean-Christophe PLAGNIOL-VILLARD cword->ll = (cword->ll << 8) | c; 102059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 102159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 102259829cc1SJean-Christophe PLAGNIOL-VILLARD } 102359829cc1SJean-Christophe PLAGNIOL-VILLARD } 102459829cc1SJean-Christophe PLAGNIOL-VILLARD 102559829cc1SJean-Christophe PLAGNIOL-VILLARD 102659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 102759829cc1SJean-Christophe PLAGNIOL-VILLARD * make a proper sized command based on the port and chip widths 102859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 102959829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf) 103059829cc1SJean-Christophe PLAGNIOL-VILLARD { 103159829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 103259829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *cp = (uchar *) cmdbuf; 103359829cc1SJean-Christophe PLAGNIOL-VILLARD 103459829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 103559829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = info->portwidth; i > 0; i--) 103659829cc1SJean-Christophe PLAGNIOL-VILLARD #else 103759829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 1; i <= info->portwidth; i++) 103859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 103959829cc1SJean-Christophe PLAGNIOL-VILLARD *cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd; 104059829cc1SJean-Christophe PLAGNIOL-VILLARD } 104159829cc1SJean-Christophe PLAGNIOL-VILLARD 104259829cc1SJean-Christophe PLAGNIOL-VILLARD /* 104359829cc1SJean-Christophe PLAGNIOL-VILLARD * Write a proper sized command to the correct address 104459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 10457e5b9b47SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, 10467e5b9b47SHaavard Skinnemoen uint offset, uchar cmd) 104759829cc1SJean-Christophe PLAGNIOL-VILLARD { 104859829cc1SJean-Christophe PLAGNIOL-VILLARD 104959829cc1SJean-Christophe PLAGNIOL-VILLARD volatile cfiptr_t addr; 105059829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 105159829cc1SJean-Christophe PLAGNIOL-VILLARD 105259829cc1SJean-Christophe PLAGNIOL-VILLARD addr.cp = flash_make_addr (info, sect, offset); 105359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 105459829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 105559829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 105659829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr.cp, cmd, 105759829cc1SJean-Christophe PLAGNIOL-VILLARD cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 105859829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.cp = cword.c; 105959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 106059829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 106159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr.wp, 106259829cc1SJean-Christophe PLAGNIOL-VILLARD cmd, cword.w, 106359829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 106459829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.wp = cword.w; 106559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 106659829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 106759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr.lp, 106859829cc1SJean-Christophe PLAGNIOL-VILLARD cmd, cword.l, 106959829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 107059829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.lp = cword.l; 107159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 107259829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 107359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 107459829cc1SJean-Christophe PLAGNIOL-VILLARD { 107559829cc1SJean-Christophe PLAGNIOL-VILLARD char str[20]; 107659829cc1SJean-Christophe PLAGNIOL-VILLARD 107759829cc1SJean-Christophe PLAGNIOL-VILLARD print_longlong (str, cword.ll); 107859829cc1SJean-Christophe PLAGNIOL-VILLARD 107959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n", 108059829cc1SJean-Christophe PLAGNIOL-VILLARD addr.llp, cmd, str, 108159829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 108259829cc1SJean-Christophe PLAGNIOL-VILLARD } 108359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 108459829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.llp = cword.ll; 108559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 108659829cc1SJean-Christophe PLAGNIOL-VILLARD } 108759829cc1SJean-Christophe PLAGNIOL-VILLARD 108859829cc1SJean-Christophe PLAGNIOL-VILLARD /* Ensure all the instructions are fully finished */ 108959829cc1SJean-Christophe PLAGNIOL-VILLARD sync(); 109059829cc1SJean-Christophe PLAGNIOL-VILLARD } 109159829cc1SJean-Christophe PLAGNIOL-VILLARD 109259829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect) 109359829cc1SJean-Christophe PLAGNIOL-VILLARD { 109481b20cccSMichael Schwingen flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START); 109581b20cccSMichael Schwingen flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK); 109659829cc1SJean-Christophe PLAGNIOL-VILLARD } 109759829cc1SJean-Christophe PLAGNIOL-VILLARD 109859829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 109959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 11007e5b9b47SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect, 11017e5b9b47SHaavard Skinnemoen uint offset, uchar cmd) 110259829cc1SJean-Christophe PLAGNIOL-VILLARD { 110359829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 110459829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 110559829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 110659829cc1SJean-Christophe PLAGNIOL-VILLARD 110759829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = flash_make_addr (info, sect, offset); 110859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 110959829cc1SJean-Christophe PLAGNIOL-VILLARD 111059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= cmd %x(%c) addr %p ", cmd, cmd, cptr.cp); 111159829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 111259829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 111359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %x %x\n", cptr.cp[0], cword.c); 111459829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.cp[0] == cword.c); 111559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 111659829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 111759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %4.4x %4.4x\n", cptr.wp[0], cword.w); 111859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.wp[0] == cword.w); 111959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 112059829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 112159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %8.8lx %8.8lx\n", cptr.lp[0], cword.l); 112259829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.lp[0] == cword.l); 112359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 112459829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 112559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 112659829cc1SJean-Christophe PLAGNIOL-VILLARD { 112759829cc1SJean-Christophe PLAGNIOL-VILLARD char str1[20]; 112859829cc1SJean-Christophe PLAGNIOL-VILLARD char str2[20]; 112959829cc1SJean-Christophe PLAGNIOL-VILLARD 113059829cc1SJean-Christophe PLAGNIOL-VILLARD print_longlong (str1, cptr.llp[0]); 113159829cc1SJean-Christophe PLAGNIOL-VILLARD print_longlong (str2, cword.ll); 113259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %s %s\n", str1, str2); 113359829cc1SJean-Christophe PLAGNIOL-VILLARD } 113459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 113559829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.llp[0] == cword.ll); 113659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 113759829cc1SJean-Christophe PLAGNIOL-VILLARD default: 113859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 113959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 114059829cc1SJean-Christophe PLAGNIOL-VILLARD } 114159829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 114259829cc1SJean-Christophe PLAGNIOL-VILLARD } 114359829cc1SJean-Christophe PLAGNIOL-VILLARD 114459829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 114559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 11467e5b9b47SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect, 11477e5b9b47SHaavard Skinnemoen uint offset, uchar cmd) 114859829cc1SJean-Christophe PLAGNIOL-VILLARD { 114959829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 115059829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 115159829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 115259829cc1SJean-Christophe PLAGNIOL-VILLARD 115359829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = flash_make_addr (info, sect, offset); 115459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 115559829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 115659829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 115759829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.cp[0] & cword.c) == cword.c); 115859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 115959829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 116059829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.wp[0] & cword.w) == cword.w); 116159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 116259829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 116359829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.lp[0] & cword.l) == cword.l); 116459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 116559829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 116659829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.llp[0] & cword.ll) == cword.ll); 116759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 116859829cc1SJean-Christophe PLAGNIOL-VILLARD default: 116959829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 117059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 117159829cc1SJean-Christophe PLAGNIOL-VILLARD } 117259829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 117359829cc1SJean-Christophe PLAGNIOL-VILLARD } 117459829cc1SJean-Christophe PLAGNIOL-VILLARD 117559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 117659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 11777e5b9b47SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect, 11787e5b9b47SHaavard Skinnemoen uint offset, uchar cmd) 117959829cc1SJean-Christophe PLAGNIOL-VILLARD { 118059829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 118159829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 118259829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 118359829cc1SJean-Christophe PLAGNIOL-VILLARD 118459829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = flash_make_addr (info, sect, offset); 118559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 118659829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 118759829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 118859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c)); 118959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 119059829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 119159829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w)); 119259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 119359829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 119459829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l)); 119559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 119659829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 119759829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.llp[0] & cword.ll) != 119859829cc1SJean-Christophe PLAGNIOL-VILLARD (cptr.llp[0] & cword.ll)); 119959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 120059829cc1SJean-Christophe PLAGNIOL-VILLARD default: 120159829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 120259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 120359829cc1SJean-Christophe PLAGNIOL-VILLARD } 120459829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 120559829cc1SJean-Christophe PLAGNIOL-VILLARD } 120659829cc1SJean-Christophe PLAGNIOL-VILLARD 120759829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 120859829cc1SJean-Christophe PLAGNIOL-VILLARD * read jedec ids from device and set corresponding fields in info struct 120959829cc1SJean-Christophe PLAGNIOL-VILLARD * 121059829cc1SJean-Christophe PLAGNIOL-VILLARD * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct 121159829cc1SJean-Christophe PLAGNIOL-VILLARD * 121259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 121359829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_read_jedec_ids (flash_info_t * info) 121459829cc1SJean-Christophe PLAGNIOL-VILLARD { 121559829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = 0; 121659829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = 0; 121759829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = 0; 121859829cc1SJean-Christophe PLAGNIOL-VILLARD 121959829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 122059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 122159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 122259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 122359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); 122459829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 122559829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 122659829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 122759829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 122859829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 122959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 123059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 123159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 123259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 123359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 123459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info, 0); 123581b20cccSMichael Schwingen flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); 123659829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 123759829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 123859829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 123959829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 124059829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 124159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 124259829cc1SJean-Christophe PLAGNIOL-VILLARD /* AMD 3-byte (expanded) device ids */ 124359829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = flash_read_uchar (info, 124459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID2); 124559829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 <<= 8; 124659829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 |= flash_read_uchar (info, 124759829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID3); 124859829cc1SJean-Christophe PLAGNIOL-VILLARD } 124959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 125059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 125159829cc1SJean-Christophe PLAGNIOL-VILLARD default: 125259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 125359829cc1SJean-Christophe PLAGNIOL-VILLARD } 125459829cc1SJean-Christophe PLAGNIOL-VILLARD } 125559829cc1SJean-Christophe PLAGNIOL-VILLARD 125659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 125759829cc1SJean-Christophe PLAGNIOL-VILLARD * detect if flash is compatible with the Common Flash Interface (CFI) 125859829cc1SJean-Christophe PLAGNIOL-VILLARD * http://www.jedec.org/download/search/jesd68.pdf 125959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 12607e5b9b47SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info) 126159829cc1SJean-Christophe PLAGNIOL-VILLARD { 126259829cc1SJean-Christophe PLAGNIOL-VILLARD int cfi_offset; 126359829cc1SJean-Christophe PLAGNIOL-VILLARD 126459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 12657e5b9b47SHaavard Skinnemoen for (cfi_offset=0; 12667e5b9b47SHaavard Skinnemoen cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint); 12677e5b9b47SHaavard Skinnemoen cfi_offset++) { 12687e5b9b47SHaavard Skinnemoen flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], 12697e5b9b47SHaavard Skinnemoen FLASH_CMD_CFI); 127059829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') 127159829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') 127259829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { 12737e5b9b47SHaavard Skinnemoen info->interface = flash_read_ushort (info, 0, 12747e5b9b47SHaavard Skinnemoen FLASH_OFFSET_INTERFACE); 127559829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_offset = flash_offset_cfi[cfi_offset]; 127659829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device interface is %d\n", 127759829cc1SJean-Christophe PLAGNIOL-VILLARD info->interface); 127859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found port %d chip %d ", 127959829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth, info->chipwidth); 128059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("port %d bits chip %d bits\n", 128159829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth << CFI_FLASH_SHIFT_WIDTH, 128259829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 128342026c9cSBartlomiej Sieka 128442026c9cSBartlomiej Sieka /* calculate command offsets as in the Linux driver */ 128542026c9cSBartlomiej Sieka info->addr_unlock1 = 0x555; 128642026c9cSBartlomiej Sieka info->addr_unlock2 = 0x2aa; 128742026c9cSBartlomiej Sieka 128842026c9cSBartlomiej Sieka /* 128942026c9cSBartlomiej Sieka * modify the unlock address if we are 129042026c9cSBartlomiej Sieka * in compatibility mode 129142026c9cSBartlomiej Sieka */ 129242026c9cSBartlomiej Sieka if ( /* x8/x16 in x8 mode */ 129342026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY8) && 129442026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X8X16)) || 129542026c9cSBartlomiej Sieka /* x16/x32 in x16 mode */ 129642026c9cSBartlomiej Sieka ((info->chipwidth == FLASH_CFI_BY16) && 129742026c9cSBartlomiej Sieka (info->interface == FLASH_CFI_X16X32))) 129842026c9cSBartlomiej Sieka { 129942026c9cSBartlomiej Sieka info->addr_unlock1 = 0xaaa; 130042026c9cSBartlomiej Sieka info->addr_unlock2 = 0x555; 130142026c9cSBartlomiej Sieka } 130242026c9cSBartlomiej Sieka 130381b20cccSMichael Schwingen info->name = "CFI conformant"; 130459829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 130559829cc1SJean-Christophe PLAGNIOL-VILLARD } 130659829cc1SJean-Christophe PLAGNIOL-VILLARD } 13077e5b9b47SHaavard Skinnemoen 13087e5b9b47SHaavard Skinnemoen return 0; 130959829cc1SJean-Christophe PLAGNIOL-VILLARD } 13107e5b9b47SHaavard Skinnemoen 13117e5b9b47SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info) 13127e5b9b47SHaavard Skinnemoen { 13137e5b9b47SHaavard Skinnemoen debug ("flash detect cfi\n"); 13147e5b9b47SHaavard Skinnemoen 13157e5b9b47SHaavard Skinnemoen for (info->portwidth = CFG_FLASH_CFI_WIDTH; 13167e5b9b47SHaavard Skinnemoen info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) { 13177e5b9b47SHaavard Skinnemoen for (info->chipwidth = FLASH_CFI_BY8; 13187e5b9b47SHaavard Skinnemoen info->chipwidth <= info->portwidth; 13197e5b9b47SHaavard Skinnemoen info->chipwidth <<= 1) 13207e5b9b47SHaavard Skinnemoen if (__flash_detect_cfi(info)) 13217e5b9b47SHaavard Skinnemoen return 1; 132259829cc1SJean-Christophe PLAGNIOL-VILLARD } 132359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("not found\n"); 132459829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 132559829cc1SJean-Christophe PLAGNIOL-VILLARD } 132659829cc1SJean-Christophe PLAGNIOL-VILLARD 132759829cc1SJean-Christophe PLAGNIOL-VILLARD /* 132859829cc1SJean-Christophe PLAGNIOL-VILLARD * The following code cannot be run from FLASH! 132959829cc1SJean-Christophe PLAGNIOL-VILLARD * 133059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 133159829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum) 133259829cc1SJean-Christophe PLAGNIOL-VILLARD { 133359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t *info = &flash_info[banknum]; 133459829cc1SJean-Christophe PLAGNIOL-VILLARD int i, j; 133559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect_cnt; 133659829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long sector; 133759829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long tmp; 133859829cc1SJean-Christophe PLAGNIOL-VILLARD int size_ratio; 133959829cc1SJean-Christophe PLAGNIOL-VILLARD uchar num_erase_regions; 134059829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_size; 134159829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_count; 134259829cc1SJean-Christophe PLAGNIOL-VILLARD int geometry_reversed = 0; 134359829cc1SJean-Christophe PLAGNIOL-VILLARD 134459829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = 0; 134559829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = 0; 134659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 134759829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = 0; 134859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 134959829cc1SJean-Christophe PLAGNIOL-VILLARD 135059829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[0] = base; 135159829cc1SJean-Christophe PLAGNIOL-VILLARD 135259829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_detect_cfi (info)) { 135359829cc1SJean-Christophe PLAGNIOL-VILLARD info->vendor = flash_read_ushort (info, 0, 135459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PRIMARY_VENDOR); 135559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_read_jedec_ids (info); 135659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, info->cfi_offset, FLASH_CMD_CFI); 135759829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions = flash_read_uchar (info, 135859829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_NUM_ERASE_REGIONS); 135959829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = flash_read_ushort (info, 0, 136059829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_EXT_QUERY_T_P_ADDR); 136159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 136259829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = (ushort) flash_read_uchar (info, 136359829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 3) << 8; 136459829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version |= (ushort) flash_read_uchar (info, 136559829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 4); 136659829cc1SJean-Christophe PLAGNIOL-VILLARD } 136759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 136859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_printqry (info, 0); 136959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 137059829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 137159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 137259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 137359829cc1SJean-Christophe PLAGNIOL-VILLARD default: 137459829cc1SJean-Christophe PLAGNIOL-VILLARD info->cmd_reset = FLASH_CMD_RESET; 137559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 137659829cc1SJean-Christophe PLAGNIOL-VILLARD /* read legacy lock/unlock bit from intel flash */ 137759829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 137859829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = flash_read_uchar (info, 137959829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 5) & 0x08; 138059829cc1SJean-Christophe PLAGNIOL-VILLARD } 138159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 138259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 138359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 138459829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 138559829cc1SJean-Christophe PLAGNIOL-VILLARD info->cmd_reset = AMD_CMD_RESET; 138659829cc1SJean-Christophe PLAGNIOL-VILLARD /* check if flash geometry needs reversal */ 138759829cc1SJean-Christophe PLAGNIOL-VILLARD if (num_erase_regions <= 1) 138859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 138959829cc1SJean-Christophe PLAGNIOL-VILLARD /* reverse geometry if top boot part */ 139059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->cfi_version < 0x3131) { 139159829cc1SJean-Christophe PLAGNIOL-VILLARD /* CFI < 1.1, try to guess from device id */ 139259829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->device_id & 0x80) != 0) { 139359829cc1SJean-Christophe PLAGNIOL-VILLARD geometry_reversed = 1; 139459829cc1SJean-Christophe PLAGNIOL-VILLARD } 139559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 139659829cc1SJean-Christophe PLAGNIOL-VILLARD } 139759829cc1SJean-Christophe PLAGNIOL-VILLARD /* CFI >= 1.1, deduct from top/bottom flag */ 139859829cc1SJean-Christophe PLAGNIOL-VILLARD /* note: ext_addr is valid since cfi_version > 0 */ 139959829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { 140059829cc1SJean-Christophe PLAGNIOL-VILLARD geometry_reversed = 1; 140159829cc1SJean-Christophe PLAGNIOL-VILLARD } 140259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 140359829cc1SJean-Christophe PLAGNIOL-VILLARD } 140459829cc1SJean-Christophe PLAGNIOL-VILLARD 140559829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer is %d\n", info->vendor); 140659829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer id is 0x%x\n", info->manufacturer_id); 140759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id is 0x%x\n", info->device_id); 140859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id2 is 0x%x\n", info->device_id2); 140959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("cfi version is 0x%04x\n", info->cfi_version); 141059829cc1SJean-Christophe PLAGNIOL-VILLARD 141159829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio = info->portwidth / info->chipwidth; 141259829cc1SJean-Christophe PLAGNIOL-VILLARD /* if the chip is x8/x16 reduce the ratio by half */ 141359829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->interface == FLASH_CFI_X8X16) 141459829cc1SJean-Christophe PLAGNIOL-VILLARD && (info->chipwidth == FLASH_CFI_BY8)) { 141559829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio >>= 1; 141659829cc1SJean-Christophe PLAGNIOL-VILLARD } 141759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("size_ratio %d port %d bits chip %d bits\n", 141859829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, 141959829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 142059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found %d erase regions\n", num_erase_regions); 142159829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt = 0; 142259829cc1SJean-Christophe PLAGNIOL-VILLARD sector = base; 142359829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < num_erase_regions; i++) { 142459829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > NUM_ERASE_REGIONS) { 142559829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("%d erase regions found, only %d used\n", 142659829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions, NUM_ERASE_REGIONS); 142759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 142859829cc1SJean-Christophe PLAGNIOL-VILLARD } 142959829cc1SJean-Christophe PLAGNIOL-VILLARD if (geometry_reversed) 143059829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = flash_read_long (info, 0, 143159829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_ERASE_REGIONS + 143259829cc1SJean-Christophe PLAGNIOL-VILLARD (num_erase_regions - 1 - i) * 4); 143359829cc1SJean-Christophe PLAGNIOL-VILLARD else 143459829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = flash_read_long (info, 0, 143559829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_ERASE_REGIONS + 143659829cc1SJean-Christophe PLAGNIOL-VILLARD i * 4); 143759829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_size = 143859829cc1SJean-Christophe PLAGNIOL-VILLARD (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; 143959829cc1SJean-Christophe PLAGNIOL-VILLARD tmp >>= 16; 144059829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count = (tmp & 0xffff) + 1; 144159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("erase_region_count = %d erase_region_size = %d\n", 144259829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count, erase_region_size); 144359829cc1SJean-Christophe PLAGNIOL-VILLARD for (j = 0; j < erase_region_count; j++) { 144481b20cccSMichael Schwingen if (sect_cnt >= CFG_MAX_FLASH_SECT) { 144581b20cccSMichael Schwingen printf("ERROR: too many flash sectors\n"); 144681b20cccSMichael Schwingen break; 144781b20cccSMichael Schwingen } 144859829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[sect_cnt] = sector; 144959829cc1SJean-Christophe PLAGNIOL-VILLARD sector += (erase_region_size * size_ratio); 145059829cc1SJean-Christophe PLAGNIOL-VILLARD 145159829cc1SJean-Christophe PLAGNIOL-VILLARD /* 14527e5b9b47SHaavard Skinnemoen * Only read protection status from 14537e5b9b47SHaavard Skinnemoen * supported devices (intel...) 145459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 145559829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 145659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 145759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 145859829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sect_cnt] = 145959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_isset (info, sect_cnt, 146059829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PROTECT, 146159829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_STATUS_PROTECT); 146259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 146359829cc1SJean-Christophe PLAGNIOL-VILLARD default: 14647e5b9b47SHaavard Skinnemoen /* default: not protected */ 14657e5b9b47SHaavard Skinnemoen info->protect[sect_cnt] = 0; 146659829cc1SJean-Christophe PLAGNIOL-VILLARD } 146759829cc1SJean-Christophe PLAGNIOL-VILLARD 146859829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt++; 146959829cc1SJean-Christophe PLAGNIOL-VILLARD } 147059829cc1SJean-Christophe PLAGNIOL-VILLARD } 147159829cc1SJean-Christophe PLAGNIOL-VILLARD 147259829cc1SJean-Christophe PLAGNIOL-VILLARD info->sector_count = sect_cnt; 14737e5b9b47SHaavard Skinnemoen info->size = 1 << flash_read_uchar (info, FLASH_OFFSET_SIZE); 147459829cc1SJean-Christophe PLAGNIOL-VILLARD /* multiply the size by the number of chips */ 14757e5b9b47SHaavard Skinnemoen info->size *= size_ratio; 14767e5b9b47SHaavard Skinnemoen info->buffer_size = 1 << flash_read_ushort (info, 0, 14777e5b9b47SHaavard Skinnemoen FLASH_OFFSET_BUFFER_SIZE); 147859829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT); 14797e5b9b47SHaavard Skinnemoen info->erase_blk_tout = tmp * 14807e5b9b47SHaavard Skinnemoen (1 << flash_read_uchar ( 14817e5b9b47SHaavard Skinnemoen info, FLASH_OFFSET_EMAX_TOUT)); 148259829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT)) * 148359829cc1SJean-Christophe PLAGNIOL-VILLARD (1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT)); 14847e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 14857e5b9b47SHaavard Skinnemoen info->buffer_write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); 148659829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT)) * 148759829cc1SJean-Christophe PLAGNIOL-VILLARD (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT)); 14887e5b9b47SHaavard Skinnemoen /* round up when converting to ms */ 14897e5b9b47SHaavard Skinnemoen info->write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); 149059829cc1SJean-Christophe PLAGNIOL-VILLARD info->flash_id = FLASH_MAN_CFI; 14917e5b9b47SHaavard Skinnemoen if ((info->interface == FLASH_CFI_X8X16) && 14927e5b9b47SHaavard Skinnemoen (info->chipwidth == FLASH_CFI_BY8)) { 14937e5b9b47SHaavard Skinnemoen /* XXX - Need to test on x8/x16 in parallel. */ 14947e5b9b47SHaavard Skinnemoen info->portwidth >>= 1; 149559829cc1SJean-Christophe PLAGNIOL-VILLARD } 149659829cc1SJean-Christophe PLAGNIOL-VILLARD } 149759829cc1SJean-Christophe PLAGNIOL-VILLARD 149859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 149959829cc1SJean-Christophe PLAGNIOL-VILLARD return (info->size); 150059829cc1SJean-Christophe PLAGNIOL-VILLARD } 150159829cc1SJean-Christophe PLAGNIOL-VILLARD 15027e5b9b47SHaavard Skinnemoen /* loop through the sectors from the highest address when the passed 15037e5b9b47SHaavard Skinnemoen * address is greater or equal to the sector address we have a match 150459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 150559829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_sect_t find_sector (flash_info_t * info, ulong addr) 150659829cc1SJean-Christophe PLAGNIOL-VILLARD { 150759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sector; 150859829cc1SJean-Christophe PLAGNIOL-VILLARD 150959829cc1SJean-Christophe PLAGNIOL-VILLARD for (sector = info->sector_count - 1; sector >= 0; sector--) { 151059829cc1SJean-Christophe PLAGNIOL-VILLARD if (addr >= info->start[sector]) 151159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 151259829cc1SJean-Christophe PLAGNIOL-VILLARD } 151359829cc1SJean-Christophe PLAGNIOL-VILLARD return sector; 151459829cc1SJean-Christophe PLAGNIOL-VILLARD } 151559829cc1SJean-Christophe PLAGNIOL-VILLARD 151659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 151759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 151859829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfiword (flash_info_t * info, ulong dest, 151959829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword) 152059829cc1SJean-Christophe PLAGNIOL-VILLARD { 152159829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t ctladdr; 152259829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 152359829cc1SJean-Christophe PLAGNIOL-VILLARD int flag; 152459829cc1SJean-Christophe PLAGNIOL-VILLARD 152559829cc1SJean-Christophe PLAGNIOL-VILLARD ctladdr.cp = flash_make_addr (info, 0, 0); 152659829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = (uchar *) dest; 152759829cc1SJean-Christophe PLAGNIOL-VILLARD 152859829cc1SJean-Christophe PLAGNIOL-VILLARD /* Check if Flash is (sufficiently) erased */ 152959829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 153059829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 153159829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.cp[0] & cword.c) == cword.c); 153259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 153359829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 153459829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.wp[0] & cword.w) == cword.w); 153559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 153659829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 153759829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.lp[0] & cword.l) == cword.l); 153859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 153959829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 154059829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.llp[0] & cword.ll) == cword.ll); 154159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 154259829cc1SJean-Christophe PLAGNIOL-VILLARD default: 154359829cc1SJean-Christophe PLAGNIOL-VILLARD return 2; 154459829cc1SJean-Christophe PLAGNIOL-VILLARD } 154559829cc1SJean-Christophe PLAGNIOL-VILLARD if (!flag) 154659829cc1SJean-Christophe PLAGNIOL-VILLARD return 2; 154759829cc1SJean-Christophe PLAGNIOL-VILLARD 154859829cc1SJean-Christophe PLAGNIOL-VILLARD /* Disable interrupts which might cause a timeout here */ 154959829cc1SJean-Christophe PLAGNIOL-VILLARD flag = disable_interrupts (); 155059829cc1SJean-Christophe PLAGNIOL-VILLARD 155159829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 155259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 155359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 155459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); 155559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE); 155659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 155759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 155859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 155981b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 156081b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 156181b20cccSMichael Schwingen #endif 156259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, 0); 156381b20cccSMichael Schwingen flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE); 156459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 156559829cc1SJean-Christophe PLAGNIOL-VILLARD } 156659829cc1SJean-Christophe PLAGNIOL-VILLARD 156759829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 156859829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 156959829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp[0] = cword.c; 157059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 157159829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 157259829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.wp[0] = cword.w; 157359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 157459829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 157559829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.lp[0] = cword.l; 157659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 157759829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 157859829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.llp[0] = cword.ll; 157959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 158059829cc1SJean-Christophe PLAGNIOL-VILLARD } 158159829cc1SJean-Christophe PLAGNIOL-VILLARD 158259829cc1SJean-Christophe PLAGNIOL-VILLARD /* re-enable interrupts if necessary */ 158359829cc1SJean-Christophe PLAGNIOL-VILLARD if (flag) 158459829cc1SJean-Christophe PLAGNIOL-VILLARD enable_interrupts (); 158559829cc1SJean-Christophe PLAGNIOL-VILLARD 158659829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_full_status_check (info, find_sector (info, dest), 158759829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout, "write"); 158859829cc1SJean-Christophe PLAGNIOL-VILLARD } 158959829cc1SJean-Christophe PLAGNIOL-VILLARD 159059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 159159829cc1SJean-Christophe PLAGNIOL-VILLARD 159259829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, 159359829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 159459829cc1SJean-Christophe PLAGNIOL-VILLARD { 159559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sector; 159659829cc1SJean-Christophe PLAGNIOL-VILLARD int cnt; 159759829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode; 159859829cc1SJean-Christophe PLAGNIOL-VILLARD volatile cfiptr_t src; 159959829cc1SJean-Christophe PLAGNIOL-VILLARD volatile cfiptr_t dst; 160059829cc1SJean-Christophe PLAGNIOL-VILLARD 160159829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 160259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 160359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 160459829cc1SJean-Christophe PLAGNIOL-VILLARD src.cp = cp; 160559829cc1SJean-Christophe PLAGNIOL-VILLARD dst.cp = (uchar *) dest; 160659829cc1SJean-Christophe PLAGNIOL-VILLARD sector = find_sector (info, dest); 160759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 160859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); 16097e5b9b47SHaavard Skinnemoen retcode = flash_status_check (info, sector, 16107e5b9b47SHaavard Skinnemoen info->buffer_write_tout, 16117e5b9b47SHaavard Skinnemoen "write to buffer"); 16127e5b9b47SHaavard Skinnemoen if (retcode == ERR_OK) { 16137e5b9b47SHaavard Skinnemoen /* reduce the number of loops by the width of 16147e5b9b47SHaavard Skinnemoen * the port */ 161559829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 161659829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 161759829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len; 161859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 161959829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 162059829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 1; 162159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 162259829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 162359829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 2; 162459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 162559829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 162659829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 3; 162759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 162859829cc1SJean-Christophe PLAGNIOL-VILLARD default: 162959829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 163059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 163159829cc1SJean-Christophe PLAGNIOL-VILLARD } 163259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 163359829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) { 163459829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 163559829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 163659829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.cp++ = *src.cp++; 163759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 163859829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 163959829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.wp++ = *src.wp++; 164059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 164159829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 164259829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.lp++ = *src.lp++; 164359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 164459829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 164559829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.llp++ = *src.llp++; 164659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 164759829cc1SJean-Christophe PLAGNIOL-VILLARD default: 164859829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 164959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 165059829cc1SJean-Christophe PLAGNIOL-VILLARD } 165159829cc1SJean-Christophe PLAGNIOL-VILLARD } 165259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, 165359829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_CMD_WRITE_BUFFER_CONFIRM); 16547e5b9b47SHaavard Skinnemoen retcode = flash_full_status_check ( 16557e5b9b47SHaavard Skinnemoen info, sector, info->buffer_write_tout, 165659829cc1SJean-Christophe PLAGNIOL-VILLARD "buffer write"); 165759829cc1SJean-Christophe PLAGNIOL-VILLARD } 165859829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 165959829cc1SJean-Christophe PLAGNIOL-VILLARD 166059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 166159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 166259829cc1SJean-Christophe PLAGNIOL-VILLARD src.cp = cp; 166359829cc1SJean-Christophe PLAGNIOL-VILLARD dst.cp = (uchar *) dest; 166459829cc1SJean-Christophe PLAGNIOL-VILLARD sector = find_sector (info, dest); 166559829cc1SJean-Christophe PLAGNIOL-VILLARD 166659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info,0); 166759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER); 166859829cc1SJean-Christophe PLAGNIOL-VILLARD 166959829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 167059829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 167159829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len; 167259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 167359829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.cp++ = *src.cp++; 167459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 167559829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 167659829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 1; 167759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 167859829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.wp++ = *src.wp++; 167959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 168059829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 168159829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 2; 168259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 168359829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.lp++ = *src.lp++; 168459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 168559829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 168659829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 3; 168759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 168859829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.llp++ = *src.llp++; 168959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 169059829cc1SJean-Christophe PLAGNIOL-VILLARD default: 169159829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 169259829cc1SJean-Christophe PLAGNIOL-VILLARD } 169359829cc1SJean-Christophe PLAGNIOL-VILLARD 169459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); 16957e5b9b47SHaavard Skinnemoen retcode = flash_full_status_check (info, sector, 16967e5b9b47SHaavard Skinnemoen info->buffer_write_tout, 169759829cc1SJean-Christophe PLAGNIOL-VILLARD "buffer write"); 169859829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 169959829cc1SJean-Christophe PLAGNIOL-VILLARD 170059829cc1SJean-Christophe PLAGNIOL-VILLARD default: 170159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("Unknown Command Set\n"); 170259829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 170359829cc1SJean-Christophe PLAGNIOL-VILLARD } 170459829cc1SJean-Christophe PLAGNIOL-VILLARD } 170559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */ 170659829cc1SJean-Christophe PLAGNIOL-VILLARD 170759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_CFI */ 1708