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 /* 4559829cc1SJean-Christophe PLAGNIOL-VILLARD * This file implements a Common Flash Interface (CFI) driver for U-Boot. 4659829cc1SJean-Christophe PLAGNIOL-VILLARD * The width of the port and the width of the chips are determined at initialization. 4759829cc1SJean-Christophe PLAGNIOL-VILLARD * These widths are used to calculate the address for access CFI data structures. 4859829cc1SJean-Christophe PLAGNIOL-VILLARD * 4959829cc1SJean-Christophe PLAGNIOL-VILLARD * References 5059829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JESD68 - Common Flash Interface (CFI) 5159829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes 5259829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets 5359829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet 5459829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD CFI Specification, Release 2.0 December 1, 2001 5559829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD/Spansion Application Note: Migration from Single-byte to Three-byte 5659829cc1SJean-Christophe PLAGNIOL-VILLARD * Device IDs, Publication Number 25538 Revision A, November 8, 2001 5759829cc1SJean-Christophe PLAGNIOL-VILLARD * 5859829cc1SJean-Christophe PLAGNIOL-VILLARD * define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between 5959829cc1SJean-Christophe PLAGNIOL-VILLARD * reading and writing ... (yes there is such a Hardware). 6059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 6159829cc1SJean-Christophe PLAGNIOL-VILLARD 6259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_BANKS_LIST 6359829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE } 6459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 6559829cc1SJean-Christophe PLAGNIOL-VILLARD 6659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CFI 0x98 6759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_READ_ID 0x90 6859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_RESET 0xff 6959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_BLOCK_ERASE 0x20 7059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_ERASE_CONFIRM 0xD0 7159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE 0x40 7259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT 0x60 7359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_SET 0x01 7459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_CLEAR 0xD0 7559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CLEAR_STATUS 0x50 7659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_TO_BUFFER 0xE8 7759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0 7859829cc1SJean-Christophe PLAGNIOL-VILLARD 7959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DONE 0x80 8059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ESS 0x40 8159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ECLBS 0x20 8259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSLBS 0x10 8359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_VPENS 0x08 8459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSS 0x04 8559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DPS 0x02 8659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_R 0x01 8759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PROTECT 0x01 8859829cc1SJean-Christophe PLAGNIOL-VILLARD 8959829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_RESET 0xF0 9059829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE 0xA0 9159829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_START 0x80 9259829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_SECTOR 0x30 9359829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_START 0xAA 9459829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_ACK 0x55 9559829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_TO_BUFFER 0x25 9659829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29 9759829cc1SJean-Christophe PLAGNIOL-VILLARD 9859829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_TOGGLE 0x40 9959829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_ERROR 0x20 10059829cc1SJean-Christophe PLAGNIOL-VILLARD 10159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_MANUFACTURER_ID 0x00 10259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID 0x01 10359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID2 0x0E 10459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID3 0x0F 10559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI 0x55 10659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_ALT 0x555 10759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_RESP 0x10 10859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PRIMARY_VENDOR 0x13 10959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15 /* extended query table primary addr */ 11059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WTOUT 0x1F 11159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBTOUT 0x20 11259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ETOUT 0x21 11359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CETOUT 0x22 11459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WMAX_TOUT 0x23 11559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBMAX_TOUT 0x24 11659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EMAX_TOUT 0x25 11759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CEMAX_TOUT 0x26 11859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_SIZE 0x27 11959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTERFACE 0x28 12059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_BUFFER_SIZE 0x2A 12159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C 12259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ERASE_REGIONS 0x2D 12359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PROTECT 0x02 12459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_USER_PROTECTION 0x85 12559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTEL_PROTECTION 0x81 12659829cc1SJean-Christophe PLAGNIOL-VILLARD 12759829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_NONE 0 12859829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_EXTENDED 1 12959829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_STANDARD 2 13059829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_STANDARD 3 13159829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_EXTENDED 4 13259829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_STANDARD 256 13359829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_EXTENDED 257 13459829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_SST 258 13559829cc1SJean-Christophe PLAGNIOL-VILLARD 13659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */ 13759829cc1SJean-Christophe PLAGNIOL-VILLARD # undef FLASH_CMD_RESET 13859829cc1SJean-Christophe PLAGNIOL-VILLARD # define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */ 13959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 14059829cc1SJean-Christophe PLAGNIOL-VILLARD 14159829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union { 14259829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned char c; 14359829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned short w; 14459829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long l; 14559829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long long ll; 14659829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiword_t; 14759829cc1SJean-Christophe PLAGNIOL-VILLARD 14859829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union { 14959829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned char *cp; 15059829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned short *wp; 15159829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long *lp; 15259829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long long *llp; 15359829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiptr_t; 15459829cc1SJean-Christophe PLAGNIOL-VILLARD 15559829cc1SJean-Christophe PLAGNIOL-VILLARD #define NUM_ERASE_REGIONS 4 /* max. number of erase regions */ 15659829cc1SJean-Christophe PLAGNIOL-VILLARD 15759829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2]={FLASH_OFFSET_CFI,FLASH_OFFSET_CFI_ALT}; 15859829cc1SJean-Christophe PLAGNIOL-VILLARD 15959829cc1SJean-Christophe PLAGNIOL-VILLARD /* use CFG_MAX_FLASH_BANKS_DETECT if defined */ 16059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_MAX_FLASH_BANKS_DETECT 16159829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS_DETECT] = CFG_FLASH_BANKS_LIST; 16259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS_DETECT]; /* FLASH chips info */ 16359829cc1SJean-Christophe PLAGNIOL-VILLARD #else 16459829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST; 16559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */ 16659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 16759829cc1SJean-Christophe PLAGNIOL-VILLARD 16859829cc1SJean-Christophe PLAGNIOL-VILLARD /* 16959829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if chip width is defined. If not, start detecting with 8bit. 17059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 17159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_CFI_WIDTH 17259829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_CFI_WIDTH FLASH_CFI_8BIT 17359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 17459829cc1SJean-Christophe PLAGNIOL-VILLARD 17559829cc1SJean-Christophe PLAGNIOL-VILLARD 17659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 17759829cc1SJean-Christophe PLAGNIOL-VILLARD * Functions 17859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 17959829cc1SJean-Christophe PLAGNIOL-VILLARD 18059829cc1SJean-Christophe PLAGNIOL-VILLARD typedef unsigned long flash_sect_t; 18159829cc1SJean-Christophe PLAGNIOL-VILLARD 18259829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c); 18359829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf); 18459829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); 18559829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect); 18659829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); 18759829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); 18859829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); 18959829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_read_jedec_ids (flash_info_t * info); 19059829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_detect_cfi (flash_info_t * info); 19159829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfiword (flash_info_t * info, ulong dest, cfiword_t cword); 19259829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, 19359829cc1SJean-Christophe PLAGNIOL-VILLARD ulong tout, char *prompt); 19459829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum); 19559829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 19659829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_info_t *flash_get_info(ulong base); 19759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 19859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 19959829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, int len); 20059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 20159829cc1SJean-Christophe PLAGNIOL-VILLARD 20259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 20359829cc1SJean-Christophe PLAGNIOL-VILLARD * create an address based on the offset and the port width 20459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 20559829cc1SJean-Christophe PLAGNIOL-VILLARD inline uchar *flash_make_addr (flash_info_t * info, flash_sect_t sect, uint offset) 20659829cc1SJean-Christophe PLAGNIOL-VILLARD { 20759829cc1SJean-Christophe PLAGNIOL-VILLARD return ((uchar *) (info->start[sect] + (offset * info->portwidth))); 20859829cc1SJean-Christophe PLAGNIOL-VILLARD } 20959829cc1SJean-Christophe PLAGNIOL-VILLARD 21059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 21159829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 21259829cc1SJean-Christophe PLAGNIOL-VILLARD * Debug support 21359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 21459829cc1SJean-Christophe PLAGNIOL-VILLARD void print_longlong (char *str, unsigned long long data) 21559829cc1SJean-Christophe PLAGNIOL-VILLARD { 21659829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 21759829cc1SJean-Christophe PLAGNIOL-VILLARD char *cp; 21859829cc1SJean-Christophe PLAGNIOL-VILLARD 21959829cc1SJean-Christophe PLAGNIOL-VILLARD cp = (unsigned char *) &data; 22059829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < 8; i++) 22159829cc1SJean-Christophe PLAGNIOL-VILLARD sprintf (&str[i * 2], "%2.2x", *cp++); 22259829cc1SJean-Christophe PLAGNIOL-VILLARD } 22359829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_printqry (flash_info_t * info, flash_sect_t sect) 22459829cc1SJean-Christophe PLAGNIOL-VILLARD { 22559829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 22659829cc1SJean-Christophe PLAGNIOL-VILLARD int x, y; 22759829cc1SJean-Christophe PLAGNIOL-VILLARD 22859829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 0x40; x += 16U / info->portwidth) { 22959829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = 23059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_addr (info, sect, 23159829cc1SJean-Christophe PLAGNIOL-VILLARD x + FLASH_OFFSET_CFI_RESP); 23259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("%p : ", cptr.cp); 23359829cc1SJean-Christophe PLAGNIOL-VILLARD for (y = 0; y < 16; y++) { 23459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("%2.2x ", cptr.cp[y]); 23559829cc1SJean-Christophe PLAGNIOL-VILLARD } 23659829cc1SJean-Christophe PLAGNIOL-VILLARD debug (" "); 23759829cc1SJean-Christophe PLAGNIOL-VILLARD for (y = 0; y < 16; y++) { 23859829cc1SJean-Christophe PLAGNIOL-VILLARD if (cptr.cp[y] >= 0x20 && cptr.cp[y] <= 0x7e) { 23959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("%c", cptr.cp[y]); 24059829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 24159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("."); 24259829cc1SJean-Christophe PLAGNIOL-VILLARD } 24359829cc1SJean-Christophe PLAGNIOL-VILLARD } 24459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("\n"); 24559829cc1SJean-Christophe PLAGNIOL-VILLARD } 24659829cc1SJean-Christophe PLAGNIOL-VILLARD } 24759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 24859829cc1SJean-Christophe PLAGNIOL-VILLARD 24959829cc1SJean-Christophe PLAGNIOL-VILLARD 25059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 25159829cc1SJean-Christophe PLAGNIOL-VILLARD * read a character at a port width address 25259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 25359829cc1SJean-Christophe PLAGNIOL-VILLARD inline uchar flash_read_uchar (flash_info_t * info, uint offset) 25459829cc1SJean-Christophe PLAGNIOL-VILLARD { 25559829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *cp; 25659829cc1SJean-Christophe PLAGNIOL-VILLARD 25759829cc1SJean-Christophe PLAGNIOL-VILLARD cp = flash_make_addr (info, 0, offset); 25859829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 25959829cc1SJean-Christophe PLAGNIOL-VILLARD return (cp[0]); 26059829cc1SJean-Christophe PLAGNIOL-VILLARD #else 26159829cc1SJean-Christophe PLAGNIOL-VILLARD return (cp[info->portwidth - 1]); 26259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 26359829cc1SJean-Christophe PLAGNIOL-VILLARD } 26459829cc1SJean-Christophe PLAGNIOL-VILLARD 26559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 26659829cc1SJean-Christophe PLAGNIOL-VILLARD * read a short word by swapping for ppc format. 26759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 26859829cc1SJean-Christophe PLAGNIOL-VILLARD ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect, uint offset) 26959829cc1SJean-Christophe PLAGNIOL-VILLARD { 27059829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *addr; 27159829cc1SJean-Christophe PLAGNIOL-VILLARD ushort retval; 27259829cc1SJean-Christophe PLAGNIOL-VILLARD 27359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 27459829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 27559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 27659829cc1SJean-Christophe PLAGNIOL-VILLARD addr = flash_make_addr (info, sect, offset); 27759829cc1SJean-Christophe PLAGNIOL-VILLARD 27859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 27959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("ushort addr is at %p info->portwidth = %d\n", addr, 28059829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth); 28159829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 2 * info->portwidth; x++) { 28259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("addr[%x] = 0x%x\n", x, addr[x]); 28359829cc1SJean-Christophe PLAGNIOL-VILLARD } 28459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 28559829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 28659829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((addr[(info->portwidth)] << 8) | addr[0]); 28759829cc1SJean-Christophe PLAGNIOL-VILLARD #else 28859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((addr[(2 * info->portwidth) - 1] << 8) | 28959829cc1SJean-Christophe PLAGNIOL-VILLARD addr[info->portwidth - 1]); 29059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 29159829cc1SJean-Christophe PLAGNIOL-VILLARD 29259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("retval = 0x%x\n", retval); 29359829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 29459829cc1SJean-Christophe PLAGNIOL-VILLARD } 29559829cc1SJean-Christophe PLAGNIOL-VILLARD 29659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 29759829cc1SJean-Christophe PLAGNIOL-VILLARD * read a long word by picking the least significant byte of each maximum 29859829cc1SJean-Christophe PLAGNIOL-VILLARD * port size word. Swap for ppc format. 29959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 30059829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_read_long (flash_info_t * info, flash_sect_t sect, uint offset) 30159829cc1SJean-Christophe PLAGNIOL-VILLARD { 30259829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *addr; 30359829cc1SJean-Christophe PLAGNIOL-VILLARD ulong retval; 30459829cc1SJean-Christophe PLAGNIOL-VILLARD 30559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 30659829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 30759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 30859829cc1SJean-Christophe PLAGNIOL-VILLARD addr = flash_make_addr (info, sect, offset); 30959829cc1SJean-Christophe PLAGNIOL-VILLARD 31059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 31159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("long addr is at %p info->portwidth = %d\n", addr, 31259829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth); 31359829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 4 * info->portwidth; x++) { 31459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("addr[%x] = 0x%x\n", x, addr[x]); 31559829cc1SJean-Christophe PLAGNIOL-VILLARD } 31659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 31759829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 31859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (addr[0] << 16) | (addr[(info->portwidth)] << 24) | 31959829cc1SJean-Christophe PLAGNIOL-VILLARD (addr[(2 * info->portwidth)]) | (addr[(3 * info->portwidth)] << 8); 32059829cc1SJean-Christophe PLAGNIOL-VILLARD #else 32159829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (addr[(2 * info->portwidth) - 1] << 24) | 32259829cc1SJean-Christophe PLAGNIOL-VILLARD (addr[(info->portwidth) - 1] << 16) | 32359829cc1SJean-Christophe PLAGNIOL-VILLARD (addr[(4 * info->portwidth) - 1] << 8) | 32459829cc1SJean-Christophe PLAGNIOL-VILLARD addr[(3 * info->portwidth) - 1]; 32559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 32659829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 32759829cc1SJean-Christophe PLAGNIOL-VILLARD } 32859829cc1SJean-Christophe PLAGNIOL-VILLARD 32959829cc1SJean-Christophe PLAGNIOL-VILLARD 330*81b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 331*81b20cccSMichael Schwingen /*----------------------------------------------------------------------- 332*81b20cccSMichael Schwingen * Call board code to request info about non-CFI flash. 333*81b20cccSMichael Schwingen * board_flash_get_legacy needs to fill in at least: 334*81b20cccSMichael Schwingen * info->portwidth, info->chipwidth and info->interface for Jedec probing. 335*81b20cccSMichael Schwingen */ 336*81b20cccSMichael Schwingen int flash_detect_legacy(ulong base, int banknum) 337*81b20cccSMichael Schwingen { 338*81b20cccSMichael Schwingen flash_info_t *info = &flash_info[banknum]; 339*81b20cccSMichael Schwingen if (board_flash_get_legacy(base, banknum, info)) { 340*81b20cccSMichael Schwingen /* board code may have filled info completely. If not, we 341*81b20cccSMichael Schwingen use JEDEC ID probing. */ 342*81b20cccSMichael Schwingen if (!info->vendor) { 343*81b20cccSMichael Schwingen int modes[] = { CFI_CMDSET_AMD_STANDARD, CFI_CMDSET_INTEL_STANDARD }; 344*81b20cccSMichael Schwingen int i; 345*81b20cccSMichael Schwingen 346*81b20cccSMichael Schwingen for(i=0; i<sizeof(modes)/sizeof(modes[0]); i++) { 347*81b20cccSMichael Schwingen info->vendor = modes[i]; 348*81b20cccSMichael Schwingen info->start[0] = base; 349*81b20cccSMichael Schwingen if (info->portwidth == FLASH_CFI_8BIT && info->interface == FLASH_CFI_X8X16) { 350*81b20cccSMichael Schwingen info->addr_unlock1 = 0x2AAA; 351*81b20cccSMichael Schwingen info->addr_unlock2 = 0x5555; 352*81b20cccSMichael Schwingen } else { 353*81b20cccSMichael Schwingen info->addr_unlock1 = 0x5555; 354*81b20cccSMichael Schwingen info->addr_unlock2 = 0x2AAA; 355*81b20cccSMichael Schwingen } 356*81b20cccSMichael Schwingen flash_read_jedec_ids(info); 357*81b20cccSMichael Schwingen debug("JEDEC PROBE: ID %x %x %x\n", info->manufacturer_id, info->device_id, info->device_id2); 358*81b20cccSMichael Schwingen if (jedec_flash_match(info, base)) 359*81b20cccSMichael Schwingen break; 360*81b20cccSMichael Schwingen } 361*81b20cccSMichael Schwingen } 362*81b20cccSMichael Schwingen switch(info->vendor) { 363*81b20cccSMichael Schwingen case CFI_CMDSET_INTEL_STANDARD: 364*81b20cccSMichael Schwingen case CFI_CMDSET_INTEL_EXTENDED: 365*81b20cccSMichael Schwingen info->cmd_reset = FLASH_CMD_RESET; 366*81b20cccSMichael Schwingen break; 367*81b20cccSMichael Schwingen case CFI_CMDSET_AMD_STANDARD: 368*81b20cccSMichael Schwingen case CFI_CMDSET_AMD_EXTENDED: 369*81b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 370*81b20cccSMichael Schwingen info->cmd_reset = AMD_CMD_RESET; 371*81b20cccSMichael Schwingen break; 372*81b20cccSMichael Schwingen } 373*81b20cccSMichael Schwingen info->flash_id = FLASH_MAN_CFI; 374*81b20cccSMichael Schwingen return 1; 375*81b20cccSMichael Schwingen } 376*81b20cccSMichael Schwingen return 0; /* use CFI */ 377*81b20cccSMichael Schwingen } 378*81b20cccSMichael Schwingen #else 379*81b20cccSMichael Schwingen int inline flash_detect_legacy(ulong base, int banknum) 380*81b20cccSMichael Schwingen { 381*81b20cccSMichael Schwingen return 0; /* use CFI */ 382*81b20cccSMichael Schwingen } 383*81b20cccSMichael Schwingen #endif 384*81b20cccSMichael Schwingen 385*81b20cccSMichael Schwingen 38659829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 38759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 38859829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long flash_init (void) 38959829cc1SJean-Christophe PLAGNIOL-VILLARD { 39059829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long size = 0; 39159829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 39259829cc1SJean-Christophe PLAGNIOL-VILLARD 39359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 39459829cc1SJean-Christophe PLAGNIOL-VILLARD char *s = getenv("unlock"); 39559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 39659829cc1SJean-Christophe PLAGNIOL-VILLARD 39759829cc1SJean-Christophe PLAGNIOL-VILLARD /* Init: no FLASHes known */ 39859829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { 39959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].flash_id = FLASH_UNKNOWN; 400*81b20cccSMichael Schwingen 401*81b20cccSMichael Schwingen if (!flash_detect_legacy (bank_base[i], i)) 402*81b20cccSMichael Schwingen flash_get_size (bank_base[i], i); 403*81b20cccSMichael Schwingen size += flash_info[i].size; 40459829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_info[i].flash_id == FLASH_UNKNOWN) { 40559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_QUIET_TEST 40659829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", 40759829cc1SJean-Christophe PLAGNIOL-VILLARD i+1, flash_info[i].size, flash_info[i].size << 20); 40859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_QUIET_TEST */ 40959829cc1SJean-Christophe PLAGNIOL-VILLARD } 41059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 41159829cc1SJean-Christophe PLAGNIOL-VILLARD else if ((s != NULL) && (strcmp(s, "yes") == 0)) { 41259829cc1SJean-Christophe PLAGNIOL-VILLARD /* 41359829cc1SJean-Christophe PLAGNIOL-VILLARD * Only the U-Boot image and it's environment is protected, 41459829cc1SJean-Christophe PLAGNIOL-VILLARD * all other sectors are unprotected (unlocked) if flash 41559829cc1SJean-Christophe PLAGNIOL-VILLARD * hardware protection is used (CFG_FLASH_PROTECTION) and 41659829cc1SJean-Christophe PLAGNIOL-VILLARD * the environment variable "unlock" is set to "yes". 41759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 41859829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_info[i].legacy_unlock) { 41959829cc1SJean-Christophe PLAGNIOL-VILLARD int k; 42059829cc1SJean-Christophe PLAGNIOL-VILLARD 42159829cc1SJean-Christophe PLAGNIOL-VILLARD /* 42259829cc1SJean-Christophe PLAGNIOL-VILLARD * Disable legacy_unlock temporarily, since 42359829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_real_protect would relock all other sectors 42459829cc1SJean-Christophe PLAGNIOL-VILLARD * again otherwise. 42559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 42659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].legacy_unlock = 0; 42759829cc1SJean-Christophe PLAGNIOL-VILLARD 42859829cc1SJean-Christophe PLAGNIOL-VILLARD /* 42959829cc1SJean-Christophe PLAGNIOL-VILLARD * Legacy unlocking (e.g. Intel J3) -> unlock only one 43059829cc1SJean-Christophe PLAGNIOL-VILLARD * sector. This will unlock all sectors. 43159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 43259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (&flash_info[i], 0, 0); 43359829cc1SJean-Christophe PLAGNIOL-VILLARD 43459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].legacy_unlock = 1; 43559829cc1SJean-Christophe PLAGNIOL-VILLARD 43659829cc1SJean-Christophe PLAGNIOL-VILLARD /* 43759829cc1SJean-Christophe PLAGNIOL-VILLARD * Manually mark other sectors as unlocked (unprotected) 43859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 43959829cc1SJean-Christophe PLAGNIOL-VILLARD for (k = 1; k < flash_info[i].sector_count; k++) 44059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].protect[k] = 0; 44159829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 44259829cc1SJean-Christophe PLAGNIOL-VILLARD /* 44359829cc1SJean-Christophe PLAGNIOL-VILLARD * No legancy unlocking -> unlock all sectors 44459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 44559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_CLEAR, 44659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].start[0], 44759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].start[0] + flash_info[i].size - 1, 44859829cc1SJean-Christophe PLAGNIOL-VILLARD &flash_info[i]); 44959829cc1SJean-Christophe PLAGNIOL-VILLARD } 45059829cc1SJean-Christophe PLAGNIOL-VILLARD } 45159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */ 45259829cc1SJean-Christophe PLAGNIOL-VILLARD } 45359829cc1SJean-Christophe PLAGNIOL-VILLARD 45459829cc1SJean-Christophe PLAGNIOL-VILLARD /* Monitor protection ON by default */ 45559829cc1SJean-Christophe PLAGNIOL-VILLARD #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 45659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_SET, 45759829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_MONITOR_BASE, 45859829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_MONITOR_BASE + monitor_flash_len - 1, 45959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CFG_MONITOR_BASE)); 46059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 46159829cc1SJean-Christophe PLAGNIOL-VILLARD 46259829cc1SJean-Christophe PLAGNIOL-VILLARD /* Environment protection ON by default */ 46359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_ENV_IS_IN_FLASH 46459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_SET, 46559829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR, 46659829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, 46759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CFG_ENV_ADDR)); 46859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 46959829cc1SJean-Christophe PLAGNIOL-VILLARD 47059829cc1SJean-Christophe PLAGNIOL-VILLARD /* Redundant environment protection ON by default */ 47159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_ENV_ADDR_REDUND 47259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_SET, 47359829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR_REDUND, 47459829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1, 47559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CFG_ENV_ADDR_REDUND)); 47659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 47759829cc1SJean-Christophe PLAGNIOL-VILLARD return (size); 47859829cc1SJean-Christophe PLAGNIOL-VILLARD } 47959829cc1SJean-Christophe PLAGNIOL-VILLARD 48059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 48159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 48259829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 48359829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_info_t *flash_get_info(ulong base) 48459829cc1SJean-Christophe PLAGNIOL-VILLARD { 48559829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 48659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t * info = 0; 48759829cc1SJean-Christophe PLAGNIOL-VILLARD 48859829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) { 48959829cc1SJean-Christophe PLAGNIOL-VILLARD info = & flash_info[i]; 49059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->size && info->start[0] <= base && 49159829cc1SJean-Christophe PLAGNIOL-VILLARD base <= info->start[0] + info->size - 1) 49259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 49359829cc1SJean-Christophe PLAGNIOL-VILLARD } 49459829cc1SJean-Christophe PLAGNIOL-VILLARD 49559829cc1SJean-Christophe PLAGNIOL-VILLARD return i == CFG_MAX_FLASH_BANKS ? 0 : info; 49659829cc1SJean-Christophe PLAGNIOL-VILLARD } 49759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 49859829cc1SJean-Christophe PLAGNIOL-VILLARD 49959829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 50059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 50159829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last) 50259829cc1SJean-Christophe PLAGNIOL-VILLARD { 50359829cc1SJean-Christophe PLAGNIOL-VILLARD int rcode = 0; 50459829cc1SJean-Christophe PLAGNIOL-VILLARD int prot; 50559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect; 50659829cc1SJean-Christophe PLAGNIOL-VILLARD 50759829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 50859829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Can't erase unknown flash type - aborted\n"); 50959829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 51059829cc1SJean-Christophe PLAGNIOL-VILLARD } 51159829cc1SJean-Christophe PLAGNIOL-VILLARD if ((s_first < 0) || (s_first > s_last)) { 51259829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("- no sectors to erase\n"); 51359829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 51459829cc1SJean-Christophe PLAGNIOL-VILLARD } 51559829cc1SJean-Christophe PLAGNIOL-VILLARD 51659829cc1SJean-Christophe PLAGNIOL-VILLARD prot = 0; 51759829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; ++sect) { 51859829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect]) { 51959829cc1SJean-Christophe PLAGNIOL-VILLARD prot++; 52059829cc1SJean-Christophe PLAGNIOL-VILLARD } 52159829cc1SJean-Christophe PLAGNIOL-VILLARD } 52259829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) { 52359829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("- Warning: %d protected sectors will not be erased!\n", prot); 52459829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 52559829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 52659829cc1SJean-Christophe PLAGNIOL-VILLARD } 52759829cc1SJean-Christophe PLAGNIOL-VILLARD 52859829cc1SJean-Christophe PLAGNIOL-VILLARD 52959829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; sect++) { 53059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect] == 0) { /* not protected */ 53159829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 53259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 53359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 53459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS); 53559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE); 53659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sect, 0, FLASH_CMD_ERASE_CONFIRM); 53759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 53859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 53959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 54059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 541*81b20cccSMichael Schwingen flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_ERASE_START); 54259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 54359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR); 54459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 545*81b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 546*81b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 547*81b20cccSMichael Schwingen flash_unlock_seq (info, 0); 548*81b20cccSMichael Schwingen flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_ERASE_START); 549*81b20cccSMichael Schwingen flash_unlock_seq (info, 0); 550*81b20cccSMichael Schwingen flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR); 551*81b20cccSMichael Schwingen break; 552*81b20cccSMichael Schwingen #endif 55359829cc1SJean-Christophe PLAGNIOL-VILLARD default: 55459829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("Unkown flash vendor %d\n", 55559829cc1SJean-Christophe PLAGNIOL-VILLARD info->vendor); 55659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 55759829cc1SJean-Christophe PLAGNIOL-VILLARD } 55859829cc1SJean-Christophe PLAGNIOL-VILLARD 55959829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_full_status_check 56059829cc1SJean-Christophe PLAGNIOL-VILLARD (info, sect, info->erase_blk_tout, "erase")) { 56159829cc1SJean-Christophe PLAGNIOL-VILLARD rcode = 1; 56259829cc1SJean-Christophe PLAGNIOL-VILLARD } else 56359829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('.'); 56459829cc1SJean-Christophe PLAGNIOL-VILLARD } 56559829cc1SJean-Christophe PLAGNIOL-VILLARD } 56659829cc1SJean-Christophe PLAGNIOL-VILLARD puts (" done\n"); 56759829cc1SJean-Christophe PLAGNIOL-VILLARD return rcode; 56859829cc1SJean-Christophe PLAGNIOL-VILLARD } 56959829cc1SJean-Christophe PLAGNIOL-VILLARD 57059829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 57159829cc1SJean-Christophe PLAGNIOL-VILLARD */ 57259829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info) 57359829cc1SJean-Christophe PLAGNIOL-VILLARD { 57459829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 57559829cc1SJean-Christophe PLAGNIOL-VILLARD 57659829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 57759829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("missing or unknown FLASH type\n"); 57859829cc1SJean-Christophe PLAGNIOL-VILLARD return; 57959829cc1SJean-Christophe PLAGNIOL-VILLARD } 58059829cc1SJean-Christophe PLAGNIOL-VILLARD 581*81b20cccSMichael Schwingen printf ("%s FLASH (%d x %d)", 582*81b20cccSMichael Schwingen info->name, 58359829cc1SJean-Christophe PLAGNIOL-VILLARD (info->portwidth << 3), (info->chipwidth << 3)); 584*81b20cccSMichael Schwingen if (info->size < 1024*1024) 585*81b20cccSMichael Schwingen printf (" Size: %ld kB in %d Sectors\n", 586*81b20cccSMichael Schwingen info->size >> 10, info->sector_count); 587*81b20cccSMichael Schwingen else 58859829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" Size: %ld MB in %d Sectors\n", 58959829cc1SJean-Christophe PLAGNIOL-VILLARD info->size >> 20, info->sector_count); 59059829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" "); 59159829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 59259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 59359829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Standard"); 59459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 59559829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 59659829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Extended"); 59759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 59859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 59959829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Standard"); 60059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 60159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 60259829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Extended"); 60359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 604*81b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 605*81b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 606*81b20cccSMichael Schwingen printf ("AMD Legacy"); 607*81b20cccSMichael Schwingen break; 608*81b20cccSMichael Schwingen #endif 60959829cc1SJean-Christophe PLAGNIOL-VILLARD default: 61059829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Unknown (%d)", info->vendor); 61159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 61259829cc1SJean-Christophe PLAGNIOL-VILLARD } 61359829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X", 61459829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id, info->device_id); 61559829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 61659829cc1SJean-Christophe PLAGNIOL-VILLARD printf("%04X", info->device_id2); 61759829cc1SJean-Christophe PLAGNIOL-VILLARD } 61859829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n", 61959829cc1SJean-Christophe PLAGNIOL-VILLARD info->erase_blk_tout, 62059829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout); 62159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size > 1) { 62259829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" Buffer write timeout: %ld ms, buffer size: %d bytes\n", 62359829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout, 62459829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_size); 62559829cc1SJean-Christophe PLAGNIOL-VILLARD } 62659829cc1SJean-Christophe PLAGNIOL-VILLARD 62759829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("\n Sector Start Addresses:"); 62859829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; ++i) { 62959829cc1SJean-Christophe PLAGNIOL-VILLARD if ((i % 5) == 0) 63059829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n"); 63159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_EMPTY_INFO 63259829cc1SJean-Christophe PLAGNIOL-VILLARD int k; 63359829cc1SJean-Christophe PLAGNIOL-VILLARD int size; 63459829cc1SJean-Christophe PLAGNIOL-VILLARD int erased; 63559829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long *flash; 63659829cc1SJean-Christophe PLAGNIOL-VILLARD 63759829cc1SJean-Christophe PLAGNIOL-VILLARD /* 63859829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if whole sector is erased 63959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 64059829cc1SJean-Christophe PLAGNIOL-VILLARD if (i != (info->sector_count - 1)) 64159829cc1SJean-Christophe PLAGNIOL-VILLARD size = info->start[i + 1] - info->start[i]; 64259829cc1SJean-Christophe PLAGNIOL-VILLARD else 64359829cc1SJean-Christophe PLAGNIOL-VILLARD size = info->start[0] + info->size - info->start[i]; 64459829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 1; 64559829cc1SJean-Christophe PLAGNIOL-VILLARD flash = (volatile unsigned long *) info->start[i]; 64659829cc1SJean-Christophe PLAGNIOL-VILLARD size = size >> 2; /* divide by 4 for longword access */ 64759829cc1SJean-Christophe PLAGNIOL-VILLARD for (k = 0; k < size; k++) { 64859829cc1SJean-Christophe PLAGNIOL-VILLARD if (*flash++ != 0xffffffff) { 64959829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 0; 65059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 65159829cc1SJean-Christophe PLAGNIOL-VILLARD } 65259829cc1SJean-Christophe PLAGNIOL-VILLARD } 65359829cc1SJean-Christophe PLAGNIOL-VILLARD 65459829cc1SJean-Christophe PLAGNIOL-VILLARD /* print empty and read-only info */ 65559829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %c %s ", 65659829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 65759829cc1SJean-Christophe PLAGNIOL-VILLARD erased ? 'E' : ' ', 65859829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 65959829cc1SJean-Christophe PLAGNIOL-VILLARD #else /* ! CFG_FLASH_EMPTY_INFO */ 66059829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %s ", 66159829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 66259829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 66359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 66459829cc1SJean-Christophe PLAGNIOL-VILLARD } 66559829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 66659829cc1SJean-Christophe PLAGNIOL-VILLARD return; 66759829cc1SJean-Christophe PLAGNIOL-VILLARD } 66859829cc1SJean-Christophe PLAGNIOL-VILLARD 66959829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 67059829cc1SJean-Christophe PLAGNIOL-VILLARD * Copy memory to flash, returns: 67159829cc1SJean-Christophe PLAGNIOL-VILLARD * 0 - OK 67259829cc1SJean-Christophe PLAGNIOL-VILLARD * 1 - write timeout 67359829cc1SJean-Christophe PLAGNIOL-VILLARD * 2 - Flash not erased 67459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 67559829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) 67659829cc1SJean-Christophe PLAGNIOL-VILLARD { 67759829cc1SJean-Christophe PLAGNIOL-VILLARD ulong wp; 67859829cc1SJean-Christophe PLAGNIOL-VILLARD ulong cp; 67959829cc1SJean-Christophe PLAGNIOL-VILLARD int aln; 68059829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 68159829cc1SJean-Christophe PLAGNIOL-VILLARD int i, rc; 68259829cc1SJean-Christophe PLAGNIOL-VILLARD 68359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 68459829cc1SJean-Christophe PLAGNIOL-VILLARD int buffered_size; 68559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 68659829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 68759829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 68859829cc1SJean-Christophe PLAGNIOL-VILLARD wp = (addr & ~(info->portwidth - 1)); 68959829cc1SJean-Christophe PLAGNIOL-VILLARD 69059829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle unaligned start */ 69159829cc1SJean-Christophe PLAGNIOL-VILLARD if ((aln = addr - wp) != 0) { 69259829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 69359829cc1SJean-Christophe PLAGNIOL-VILLARD cp = wp; 69459829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < aln; ++i, ++cp) 69559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, (*(uchar *) cp)); 69659829cc1SJean-Christophe PLAGNIOL-VILLARD 69759829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (i < info->portwidth) && (cnt > 0); i++) { 69859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 69959829cc1SJean-Christophe PLAGNIOL-VILLARD cnt--; 70059829cc1SJean-Christophe PLAGNIOL-VILLARD cp++; 70159829cc1SJean-Christophe PLAGNIOL-VILLARD } 70259829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp) 70359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, (*(uchar *) cp)); 70459829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 70559829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 70659829cc1SJean-Christophe PLAGNIOL-VILLARD wp = cp; 70759829cc1SJean-Christophe PLAGNIOL-VILLARD } 70859829cc1SJean-Christophe PLAGNIOL-VILLARD 70959829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle the aligned part */ 71059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 71159829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size = (info->portwidth / info->chipwidth); 71259829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size *= info->buffer_size; 71359829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 71459829cc1SJean-Christophe PLAGNIOL-VILLARD /* prohibit buffer write when buffer_size is 1 */ 71559829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size == 1) { 71659829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 71759829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) 71859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 71959829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 72059829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 72159829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 72259829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 72359829cc1SJean-Christophe PLAGNIOL-VILLARD continue; 72459829cc1SJean-Christophe PLAGNIOL-VILLARD } 72559829cc1SJean-Christophe PLAGNIOL-VILLARD 72659829cc1SJean-Christophe PLAGNIOL-VILLARD /* write buffer until next buffered_size aligned boundary */ 72759829cc1SJean-Christophe PLAGNIOL-VILLARD i = buffered_size - (wp % buffered_size); 72859829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > cnt) 72959829cc1SJean-Christophe PLAGNIOL-VILLARD i = cnt; 73059829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) 73159829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 73259829cc1SJean-Christophe PLAGNIOL-VILLARD i -= i & (info->portwidth - 1); 73359829cc1SJean-Christophe PLAGNIOL-VILLARD wp += i; 73459829cc1SJean-Christophe PLAGNIOL-VILLARD src += i; 73559829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= i; 73659829cc1SJean-Christophe PLAGNIOL-VILLARD } 73759829cc1SJean-Christophe PLAGNIOL-VILLARD #else 73859829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 73959829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 74059829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) { 74159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 74259829cc1SJean-Christophe PLAGNIOL-VILLARD } 74359829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 74459829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 74559829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 74659829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 74759829cc1SJean-Christophe PLAGNIOL-VILLARD } 74859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */ 74959829cc1SJean-Christophe PLAGNIOL-VILLARD if (cnt == 0) { 75059829cc1SJean-Christophe PLAGNIOL-VILLARD return (0); 75159829cc1SJean-Christophe PLAGNIOL-VILLARD } 75259829cc1SJean-Christophe PLAGNIOL-VILLARD 75359829cc1SJean-Christophe PLAGNIOL-VILLARD /* 75459829cc1SJean-Christophe PLAGNIOL-VILLARD * handle unaligned tail bytes 75559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 75659829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 75759829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) { 75859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 75959829cc1SJean-Christophe PLAGNIOL-VILLARD --cnt; 76059829cc1SJean-Christophe PLAGNIOL-VILLARD } 76159829cc1SJean-Christophe PLAGNIOL-VILLARD for (; i < info->portwidth; ++i, ++cp) { 76259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, (*(uchar *) cp)); 76359829cc1SJean-Christophe PLAGNIOL-VILLARD } 76459829cc1SJean-Christophe PLAGNIOL-VILLARD 76559829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_write_cfiword (info, wp, cword); 76659829cc1SJean-Christophe PLAGNIOL-VILLARD } 76759829cc1SJean-Christophe PLAGNIOL-VILLARD 76859829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 76959829cc1SJean-Christophe PLAGNIOL-VILLARD */ 77059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 77159829cc1SJean-Christophe PLAGNIOL-VILLARD 77259829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot) 77359829cc1SJean-Christophe PLAGNIOL-VILLARD { 77459829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode = 0; 77559829cc1SJean-Christophe PLAGNIOL-VILLARD 77659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 77759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); 77859829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) 77959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); 78059829cc1SJean-Christophe PLAGNIOL-VILLARD else 78159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR); 78259829cc1SJean-Christophe PLAGNIOL-VILLARD 78359829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode = 78459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_full_status_check (info, sector, info->erase_blk_tout, 78559829cc1SJean-Christophe PLAGNIOL-VILLARD prot ? "protect" : "unprotect")) == 0) { 78659829cc1SJean-Christophe PLAGNIOL-VILLARD 78759829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sector] = prot; 78859829cc1SJean-Christophe PLAGNIOL-VILLARD 78959829cc1SJean-Christophe PLAGNIOL-VILLARD /* 79059829cc1SJean-Christophe PLAGNIOL-VILLARD * On some of Intel's flash chips (marked via legacy_unlock) 79159829cc1SJean-Christophe PLAGNIOL-VILLARD * unprotect unprotects all locking. 79259829cc1SJean-Christophe PLAGNIOL-VILLARD */ 79359829cc1SJean-Christophe PLAGNIOL-VILLARD if ((prot == 0) && (info->legacy_unlock)) { 79459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t i; 79559829cc1SJean-Christophe PLAGNIOL-VILLARD 79659829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; i++) { 79759829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[i]) 79859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (info, i, 1); 79959829cc1SJean-Christophe PLAGNIOL-VILLARD } 80059829cc1SJean-Christophe PLAGNIOL-VILLARD } 80159829cc1SJean-Christophe PLAGNIOL-VILLARD } 80259829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 80359829cc1SJean-Christophe PLAGNIOL-VILLARD } 80459829cc1SJean-Christophe PLAGNIOL-VILLARD 80559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 80659829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_user_serial - read the OneTimeProgramming cells 80759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 80859829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, 80959829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 81059829cc1SJean-Christophe PLAGNIOL-VILLARD { 81159829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 81259829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *dst; 81359829cc1SJean-Christophe PLAGNIOL-VILLARD 81459829cc1SJean-Christophe PLAGNIOL-VILLARD dst = buffer; 81559829cc1SJean-Christophe PLAGNIOL-VILLARD src = flash_make_addr (info, 0, FLASH_OFFSET_USER_PROTECTION); 81659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 81759829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (dst, src + offset, len); 81859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 81959829cc1SJean-Christophe PLAGNIOL-VILLARD } 82059829cc1SJean-Christophe PLAGNIOL-VILLARD 82159829cc1SJean-Christophe PLAGNIOL-VILLARD /* 82259829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_factory_serial - read the device Id from the protection area 82359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 82459829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, 82559829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 82659829cc1SJean-Christophe PLAGNIOL-VILLARD { 82759829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 82859829cc1SJean-Christophe PLAGNIOL-VILLARD 82959829cc1SJean-Christophe PLAGNIOL-VILLARD src = flash_make_addr (info, 0, FLASH_OFFSET_INTEL_PROTECTION); 83059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 83159829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (buffer, src + offset, len); 83259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 83359829cc1SJean-Christophe PLAGNIOL-VILLARD } 83459829cc1SJean-Christophe PLAGNIOL-VILLARD 83559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */ 83659829cc1SJean-Christophe PLAGNIOL-VILLARD 83759829cc1SJean-Christophe PLAGNIOL-VILLARD /* 83859829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_is_busy - check to see if the flash is busy 83959829cc1SJean-Christophe PLAGNIOL-VILLARD * This routine checks the status of the chip and returns true if the chip is busy 84059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 84159829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_is_busy (flash_info_t * info, flash_sect_t sect) 84259829cc1SJean-Christophe PLAGNIOL-VILLARD { 84359829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 84459829cc1SJean-Christophe PLAGNIOL-VILLARD 84559829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 84659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 84759829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 84859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); 84959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 85059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 85159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 852*81b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 853*81b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 854*81b20cccSMichael Schwingen #endif 85559829cc1SJean-Christophe PLAGNIOL-VILLARD retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); 85659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 85759829cc1SJean-Christophe PLAGNIOL-VILLARD default: 85859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 85959829cc1SJean-Christophe PLAGNIOL-VILLARD } 86059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("flash_is_busy: %d\n", retval); 86159829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 86259829cc1SJean-Christophe PLAGNIOL-VILLARD } 86359829cc1SJean-Christophe PLAGNIOL-VILLARD 86459829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 86559829cc1SJean-Christophe PLAGNIOL-VILLARD * wait for XSR.7 to be set. Time out with an error if it does not. 86659829cc1SJean-Christophe PLAGNIOL-VILLARD * This routine does not set the flash to read-array mode. 86759829cc1SJean-Christophe PLAGNIOL-VILLARD */ 86859829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_status_check (flash_info_t * info, flash_sect_t sector, 86959829cc1SJean-Christophe PLAGNIOL-VILLARD ulong tout, char *prompt) 87059829cc1SJean-Christophe PLAGNIOL-VILLARD { 87159829cc1SJean-Christophe PLAGNIOL-VILLARD ulong start; 87259829cc1SJean-Christophe PLAGNIOL-VILLARD 87359829cc1SJean-Christophe PLAGNIOL-VILLARD #if CFG_HZ != 1000 87459829cc1SJean-Christophe PLAGNIOL-VILLARD tout *= CFG_HZ/1000; 87559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 87659829cc1SJean-Christophe PLAGNIOL-VILLARD 87759829cc1SJean-Christophe PLAGNIOL-VILLARD /* Wait for command completion */ 87859829cc1SJean-Christophe PLAGNIOL-VILLARD start = get_timer (0); 87959829cc1SJean-Christophe PLAGNIOL-VILLARD while (flash_is_busy (info, sector)) { 88059829cc1SJean-Christophe PLAGNIOL-VILLARD if (get_timer (start) > tout) { 88159829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Flash %s timeout at address %lx data %lx\n", 88259829cc1SJean-Christophe PLAGNIOL-VILLARD prompt, info->start[sector], 88359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_read_long (info, sector, 0)); 88459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, info->cmd_reset); 88559829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_TIMOUT; 88659829cc1SJean-Christophe PLAGNIOL-VILLARD } 88759829cc1SJean-Christophe PLAGNIOL-VILLARD udelay (1); /* also triggers watchdog */ 88859829cc1SJean-Christophe PLAGNIOL-VILLARD } 88959829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_OK; 89059829cc1SJean-Christophe PLAGNIOL-VILLARD } 89159829cc1SJean-Christophe PLAGNIOL-VILLARD 89259829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 89359829cc1SJean-Christophe PLAGNIOL-VILLARD * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check. 89459829cc1SJean-Christophe PLAGNIOL-VILLARD * This routine sets the flash to read-array mode. 89559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 89659829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, 89759829cc1SJean-Christophe PLAGNIOL-VILLARD ulong tout, char *prompt) 89859829cc1SJean-Christophe PLAGNIOL-VILLARD { 89959829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode; 90059829cc1SJean-Christophe PLAGNIOL-VILLARD 90159829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = flash_status_check (info, sector, tout, prompt); 90259829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 90359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 90459829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 90559829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode == ERR_OK) 90659829cc1SJean-Christophe PLAGNIOL-VILLARD && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { 90759829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = ERR_INVAL; 90859829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Flash %s error at address %lx\n", prompt, 90959829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[sector]); 91059829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) { 91159829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Command Sequence Error.\n"); 91259829cc1SJean-Christophe PLAGNIOL-VILLARD } else if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS)) { 91359829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Block Erase Error.\n"); 91459829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = ERR_NOT_ERASED; 91559829cc1SJean-Christophe PLAGNIOL-VILLARD } else if (flash_isset (info, sector, 0, FLASH_STATUS_PSLBS)) { 91659829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Locking Error\n"); 91759829cc1SJean-Christophe PLAGNIOL-VILLARD } 91859829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { 91959829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Block locked.\n"); 92059829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = ERR_PROTECTED; 92159829cc1SJean-Christophe PLAGNIOL-VILLARD } 92259829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) 92359829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Vpp Low Error.\n"); 92459829cc1SJean-Christophe PLAGNIOL-VILLARD } 92559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, info->cmd_reset); 92659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 92759829cc1SJean-Christophe PLAGNIOL-VILLARD default: 92859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 92959829cc1SJean-Christophe PLAGNIOL-VILLARD } 93059829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 93159829cc1SJean-Christophe PLAGNIOL-VILLARD } 93259829cc1SJean-Christophe PLAGNIOL-VILLARD 93359829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 93459829cc1SJean-Christophe PLAGNIOL-VILLARD */ 93559829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) 93659829cc1SJean-Christophe PLAGNIOL-VILLARD { 93759829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 93859829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned short w; 93959829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned int l; 94059829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long long ll; 94159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 94259829cc1SJean-Christophe PLAGNIOL-VILLARD 94359829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 94459829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 94559829cc1SJean-Christophe PLAGNIOL-VILLARD cword->c = c; 94659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 94759829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 94859829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 94959829cc1SJean-Christophe PLAGNIOL-VILLARD w = c; 95059829cc1SJean-Christophe PLAGNIOL-VILLARD w <<= 8; 95159829cc1SJean-Christophe PLAGNIOL-VILLARD cword->w = (cword->w >> 8) | w; 95259829cc1SJean-Christophe PLAGNIOL-VILLARD #else 95359829cc1SJean-Christophe PLAGNIOL-VILLARD cword->w = (cword->w << 8) | c; 95459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 95559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 95659829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 95759829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 95859829cc1SJean-Christophe PLAGNIOL-VILLARD l = c; 95959829cc1SJean-Christophe PLAGNIOL-VILLARD l <<= 24; 96059829cc1SJean-Christophe PLAGNIOL-VILLARD cword->l = (cword->l >> 8) | l; 96159829cc1SJean-Christophe PLAGNIOL-VILLARD #else 96259829cc1SJean-Christophe PLAGNIOL-VILLARD cword->l = (cword->l << 8) | c; 96359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 96459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 96559829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 96659829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 96759829cc1SJean-Christophe PLAGNIOL-VILLARD ll = c; 96859829cc1SJean-Christophe PLAGNIOL-VILLARD ll <<= 56; 96959829cc1SJean-Christophe PLAGNIOL-VILLARD cword->ll = (cword->ll >> 8) | ll; 97059829cc1SJean-Christophe PLAGNIOL-VILLARD #else 97159829cc1SJean-Christophe PLAGNIOL-VILLARD cword->ll = (cword->ll << 8) | c; 97259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 97359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 97459829cc1SJean-Christophe PLAGNIOL-VILLARD } 97559829cc1SJean-Christophe PLAGNIOL-VILLARD } 97659829cc1SJean-Christophe PLAGNIOL-VILLARD 97759829cc1SJean-Christophe PLAGNIOL-VILLARD 97859829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 97959829cc1SJean-Christophe PLAGNIOL-VILLARD * make a proper sized command based on the port and chip widths 98059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 98159829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf) 98259829cc1SJean-Christophe PLAGNIOL-VILLARD { 98359829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 98459829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *cp = (uchar *) cmdbuf; 98559829cc1SJean-Christophe PLAGNIOL-VILLARD 98659829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 98759829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = info->portwidth; i > 0; i--) 98859829cc1SJean-Christophe PLAGNIOL-VILLARD #else 98959829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 1; i <= info->portwidth; i++) 99059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 99159829cc1SJean-Christophe PLAGNIOL-VILLARD *cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd; 99259829cc1SJean-Christophe PLAGNIOL-VILLARD } 99359829cc1SJean-Christophe PLAGNIOL-VILLARD 99459829cc1SJean-Christophe PLAGNIOL-VILLARD /* 99559829cc1SJean-Christophe PLAGNIOL-VILLARD * Write a proper sized command to the correct address 99659829cc1SJean-Christophe PLAGNIOL-VILLARD */ 99759829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) 99859829cc1SJean-Christophe PLAGNIOL-VILLARD { 99959829cc1SJean-Christophe PLAGNIOL-VILLARD 100059829cc1SJean-Christophe PLAGNIOL-VILLARD volatile cfiptr_t addr; 100159829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 100259829cc1SJean-Christophe PLAGNIOL-VILLARD 100359829cc1SJean-Christophe PLAGNIOL-VILLARD addr.cp = flash_make_addr (info, sect, offset); 100459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 100559829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 100659829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 100759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr.cp, cmd, 100859829cc1SJean-Christophe PLAGNIOL-VILLARD cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 100959829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.cp = cword.c; 101059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 101159829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 101259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr.wp, 101359829cc1SJean-Christophe PLAGNIOL-VILLARD cmd, cword.w, 101459829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 101559829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.wp = cword.w; 101659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 101759829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 101859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr.lp, 101959829cc1SJean-Christophe PLAGNIOL-VILLARD cmd, cword.l, 102059829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 102159829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.lp = cword.l; 102259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 102359829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 102459829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 102559829cc1SJean-Christophe PLAGNIOL-VILLARD { 102659829cc1SJean-Christophe PLAGNIOL-VILLARD char str[20]; 102759829cc1SJean-Christophe PLAGNIOL-VILLARD 102859829cc1SJean-Christophe PLAGNIOL-VILLARD print_longlong (str, cword.ll); 102959829cc1SJean-Christophe PLAGNIOL-VILLARD 103059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n", 103159829cc1SJean-Christophe PLAGNIOL-VILLARD addr.llp, cmd, str, 103259829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 103359829cc1SJean-Christophe PLAGNIOL-VILLARD } 103459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 103559829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.llp = cword.ll; 103659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 103759829cc1SJean-Christophe PLAGNIOL-VILLARD } 103859829cc1SJean-Christophe PLAGNIOL-VILLARD 103959829cc1SJean-Christophe PLAGNIOL-VILLARD /* Ensure all the instructions are fully finished */ 104059829cc1SJean-Christophe PLAGNIOL-VILLARD sync(); 104159829cc1SJean-Christophe PLAGNIOL-VILLARD } 104259829cc1SJean-Christophe PLAGNIOL-VILLARD 104359829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect) 104459829cc1SJean-Christophe PLAGNIOL-VILLARD { 1045*81b20cccSMichael Schwingen flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START); 1046*81b20cccSMichael Schwingen flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK); 104759829cc1SJean-Christophe PLAGNIOL-VILLARD } 104859829cc1SJean-Christophe PLAGNIOL-VILLARD 104959829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 105059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 105159829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) 105259829cc1SJean-Christophe PLAGNIOL-VILLARD { 105359829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 105459829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 105559829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 105659829cc1SJean-Christophe PLAGNIOL-VILLARD 105759829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = flash_make_addr (info, sect, offset); 105859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 105959829cc1SJean-Christophe PLAGNIOL-VILLARD 106059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= cmd %x(%c) addr %p ", cmd, cmd, cptr.cp); 106159829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 106259829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 106359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %x %x\n", cptr.cp[0], cword.c); 106459829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.cp[0] == cword.c); 106559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 106659829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 106759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %4.4x %4.4x\n", cptr.wp[0], cword.w); 106859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.wp[0] == cword.w); 106959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 107059829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 107159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %8.8lx %8.8lx\n", cptr.lp[0], cword.l); 107259829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.lp[0] == cword.l); 107359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 107459829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 107559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 107659829cc1SJean-Christophe PLAGNIOL-VILLARD { 107759829cc1SJean-Christophe PLAGNIOL-VILLARD char str1[20]; 107859829cc1SJean-Christophe PLAGNIOL-VILLARD char str2[20]; 107959829cc1SJean-Christophe PLAGNIOL-VILLARD 108059829cc1SJean-Christophe PLAGNIOL-VILLARD print_longlong (str1, cptr.llp[0]); 108159829cc1SJean-Christophe PLAGNIOL-VILLARD print_longlong (str2, cword.ll); 108259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %s %s\n", str1, str2); 108359829cc1SJean-Christophe PLAGNIOL-VILLARD } 108459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 108559829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.llp[0] == cword.ll); 108659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 108759829cc1SJean-Christophe PLAGNIOL-VILLARD default: 108859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 108959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 109059829cc1SJean-Christophe PLAGNIOL-VILLARD } 109159829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 109259829cc1SJean-Christophe PLAGNIOL-VILLARD } 109359829cc1SJean-Christophe PLAGNIOL-VILLARD 109459829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 109559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 109659829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) 109759829cc1SJean-Christophe PLAGNIOL-VILLARD { 109859829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 109959829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 110059829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 110159829cc1SJean-Christophe PLAGNIOL-VILLARD 110259829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = flash_make_addr (info, sect, offset); 110359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 110459829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 110559829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 110659829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.cp[0] & cword.c) == cword.c); 110759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 110859829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 110959829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.wp[0] & cword.w) == cword.w); 111059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 111159829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 111259829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.lp[0] & cword.l) == cword.l); 111359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 111459829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 111559829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.llp[0] & cword.ll) == cword.ll); 111659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 111759829cc1SJean-Christophe PLAGNIOL-VILLARD default: 111859829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 111959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 112059829cc1SJean-Christophe PLAGNIOL-VILLARD } 112159829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 112259829cc1SJean-Christophe PLAGNIOL-VILLARD } 112359829cc1SJean-Christophe PLAGNIOL-VILLARD 112459829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 112559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 112659829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) 112759829cc1SJean-Christophe PLAGNIOL-VILLARD { 112859829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 112959829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 113059829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 113159829cc1SJean-Christophe PLAGNIOL-VILLARD 113259829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = flash_make_addr (info, sect, offset); 113359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 113459829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 113559829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 113659829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c)); 113759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 113859829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 113959829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w)); 114059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 114159829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 114259829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l)); 114359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 114459829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 114559829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.llp[0] & cword.ll) != 114659829cc1SJean-Christophe PLAGNIOL-VILLARD (cptr.llp[0] & cword.ll)); 114759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 114859829cc1SJean-Christophe PLAGNIOL-VILLARD default: 114959829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 115059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 115159829cc1SJean-Christophe PLAGNIOL-VILLARD } 115259829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 115359829cc1SJean-Christophe PLAGNIOL-VILLARD } 115459829cc1SJean-Christophe PLAGNIOL-VILLARD 115559829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 115659829cc1SJean-Christophe PLAGNIOL-VILLARD * read jedec ids from device and set corresponding fields in info struct 115759829cc1SJean-Christophe PLAGNIOL-VILLARD * 115859829cc1SJean-Christophe PLAGNIOL-VILLARD * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct 115959829cc1SJean-Christophe PLAGNIOL-VILLARD * 116059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 116159829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_read_jedec_ids (flash_info_t * info) 116259829cc1SJean-Christophe PLAGNIOL-VILLARD { 116359829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = 0; 116459829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = 0; 116559829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = 0; 116659829cc1SJean-Christophe PLAGNIOL-VILLARD 116759829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 116859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 116959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 117059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 117159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); 117259829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 117359829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 117459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 117559829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 117659829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 117759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 117859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 117959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 118059829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 118159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 118259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info, 0); 1183*81b20cccSMichael Schwingen flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); 118459829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 118559829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 118659829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 118759829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 118859829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 118959829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 119059829cc1SJean-Christophe PLAGNIOL-VILLARD /* AMD 3-byte (expanded) device ids */ 119159829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = flash_read_uchar (info, 119259829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID2); 119359829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 <<= 8; 119459829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 |= flash_read_uchar (info, 119559829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID3); 119659829cc1SJean-Christophe PLAGNIOL-VILLARD } 119759829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 119859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 119959829cc1SJean-Christophe PLAGNIOL-VILLARD default: 120059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 120159829cc1SJean-Christophe PLAGNIOL-VILLARD } 120259829cc1SJean-Christophe PLAGNIOL-VILLARD } 120359829cc1SJean-Christophe PLAGNIOL-VILLARD 120459829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 120559829cc1SJean-Christophe PLAGNIOL-VILLARD * detect if flash is compatible with the Common Flash Interface (CFI) 120659829cc1SJean-Christophe PLAGNIOL-VILLARD * http://www.jedec.org/download/search/jesd68.pdf 120759829cc1SJean-Christophe PLAGNIOL-VILLARD * 120859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 120959829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_detect_cfi (flash_info_t * info) 121059829cc1SJean-Christophe PLAGNIOL-VILLARD { 121159829cc1SJean-Christophe PLAGNIOL-VILLARD int cfi_offset; 121259829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("flash detect cfi\n"); 121359829cc1SJean-Christophe PLAGNIOL-VILLARD 121459829cc1SJean-Christophe PLAGNIOL-VILLARD for (info->portwidth = CFG_FLASH_CFI_WIDTH; 121559829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) { 121659829cc1SJean-Christophe PLAGNIOL-VILLARD for (info->chipwidth = FLASH_CFI_BY8; 121759829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth <= info->portwidth; 121859829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth <<= 1) { 121959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 122059829cc1SJean-Christophe PLAGNIOL-VILLARD for (cfi_offset=0; cfi_offset < sizeof(flash_offset_cfi)/sizeof(uint); cfi_offset++) { 122159829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], FLASH_CMD_CFI); 122259829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') 122359829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') 122459829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { 122559829cc1SJean-Christophe PLAGNIOL-VILLARD info->interface = flash_read_ushort (info, 0, FLASH_OFFSET_INTERFACE); 122659829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_offset=flash_offset_cfi[cfi_offset]; 122759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device interface is %d\n", 122859829cc1SJean-Christophe PLAGNIOL-VILLARD info->interface); 122959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found port %d chip %d ", 123059829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth, info->chipwidth); 123159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("port %d bits chip %d bits\n", 123259829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth << CFI_FLASH_SHIFT_WIDTH, 123359829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 1234*81b20cccSMichael Schwingen /* this probably only works if info->interface == FLASH_CFI_X8X16 */ 1235*81b20cccSMichael Schwingen info->addr_unlock1 = (info->portwidth == FLASH_CFI_8BIT) ? 0xAAA : 0x555; 1236*81b20cccSMichael Schwingen info->addr_unlock2 = (info->portwidth == FLASH_CFI_8BIT) ? 0x555 : 0x2AA; 1237*81b20cccSMichael Schwingen info->name = "CFI conformant"; 123859829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 123959829cc1SJean-Christophe PLAGNIOL-VILLARD } 124059829cc1SJean-Christophe PLAGNIOL-VILLARD } 124159829cc1SJean-Christophe PLAGNIOL-VILLARD } 124259829cc1SJean-Christophe PLAGNIOL-VILLARD } 124359829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("not found\n"); 124459829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 124559829cc1SJean-Christophe PLAGNIOL-VILLARD } 124659829cc1SJean-Christophe PLAGNIOL-VILLARD 124759829cc1SJean-Christophe PLAGNIOL-VILLARD /* 124859829cc1SJean-Christophe PLAGNIOL-VILLARD * The following code cannot be run from FLASH! 124959829cc1SJean-Christophe PLAGNIOL-VILLARD * 125059829cc1SJean-Christophe PLAGNIOL-VILLARD */ 125159829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum) 125259829cc1SJean-Christophe PLAGNIOL-VILLARD { 125359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t *info = &flash_info[banknum]; 125459829cc1SJean-Christophe PLAGNIOL-VILLARD int i, j; 125559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect_cnt; 125659829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long sector; 125759829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long tmp; 125859829cc1SJean-Christophe PLAGNIOL-VILLARD int size_ratio; 125959829cc1SJean-Christophe PLAGNIOL-VILLARD uchar num_erase_regions; 126059829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_size; 126159829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_count; 126259829cc1SJean-Christophe PLAGNIOL-VILLARD int geometry_reversed = 0; 126359829cc1SJean-Christophe PLAGNIOL-VILLARD 126459829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = 0; 126559829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = 0; 126659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 126759829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = 0; 126859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 126959829cc1SJean-Christophe PLAGNIOL-VILLARD 127059829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[0] = base; 127159829cc1SJean-Christophe PLAGNIOL-VILLARD 127259829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_detect_cfi (info)) { 127359829cc1SJean-Christophe PLAGNIOL-VILLARD info->vendor = flash_read_ushort (info, 0, 127459829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PRIMARY_VENDOR); 127559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_read_jedec_ids (info); 127659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, info->cfi_offset, FLASH_CMD_CFI); 127759829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions = flash_read_uchar (info, 127859829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_NUM_ERASE_REGIONS); 127959829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = flash_read_ushort (info, 0, 128059829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_EXT_QUERY_T_P_ADDR); 128159829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 128259829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = (ushort) flash_read_uchar (info, 128359829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 3) << 8; 128459829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version |= (ushort) flash_read_uchar (info, 128559829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 4); 128659829cc1SJean-Christophe PLAGNIOL-VILLARD } 128759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 128859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_printqry (info, 0); 128959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 129059829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 129159829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 129259829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 129359829cc1SJean-Christophe PLAGNIOL-VILLARD default: 129459829cc1SJean-Christophe PLAGNIOL-VILLARD info->cmd_reset = FLASH_CMD_RESET; 129559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 129659829cc1SJean-Christophe PLAGNIOL-VILLARD /* read legacy lock/unlock bit from intel flash */ 129759829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 129859829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = flash_read_uchar (info, 129959829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 5) & 0x08; 130059829cc1SJean-Christophe PLAGNIOL-VILLARD } 130159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 130259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 130359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 130459829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 130559829cc1SJean-Christophe PLAGNIOL-VILLARD info->cmd_reset = AMD_CMD_RESET; 130659829cc1SJean-Christophe PLAGNIOL-VILLARD /* check if flash geometry needs reversal */ 130759829cc1SJean-Christophe PLAGNIOL-VILLARD if (num_erase_regions <= 1) 130859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 130959829cc1SJean-Christophe PLAGNIOL-VILLARD /* reverse geometry if top boot part */ 131059829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->cfi_version < 0x3131) { 131159829cc1SJean-Christophe PLAGNIOL-VILLARD /* CFI < 1.1, try to guess from device id */ 131259829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->device_id & 0x80) != 0) { 131359829cc1SJean-Christophe PLAGNIOL-VILLARD geometry_reversed = 1; 131459829cc1SJean-Christophe PLAGNIOL-VILLARD } 131559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 131659829cc1SJean-Christophe PLAGNIOL-VILLARD } 131759829cc1SJean-Christophe PLAGNIOL-VILLARD /* CFI >= 1.1, deduct from top/bottom flag */ 131859829cc1SJean-Christophe PLAGNIOL-VILLARD /* note: ext_addr is valid since cfi_version > 0 */ 131959829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { 132059829cc1SJean-Christophe PLAGNIOL-VILLARD geometry_reversed = 1; 132159829cc1SJean-Christophe PLAGNIOL-VILLARD } 132259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 132359829cc1SJean-Christophe PLAGNIOL-VILLARD } 132459829cc1SJean-Christophe PLAGNIOL-VILLARD 132559829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer is %d\n", info->vendor); 132659829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer id is 0x%x\n", info->manufacturer_id); 132759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id is 0x%x\n", info->device_id); 132859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id2 is 0x%x\n", info->device_id2); 132959829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("cfi version is 0x%04x\n", info->cfi_version); 133059829cc1SJean-Christophe PLAGNIOL-VILLARD 133159829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio = info->portwidth / info->chipwidth; 133259829cc1SJean-Christophe PLAGNIOL-VILLARD /* if the chip is x8/x16 reduce the ratio by half */ 133359829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->interface == FLASH_CFI_X8X16) 133459829cc1SJean-Christophe PLAGNIOL-VILLARD && (info->chipwidth == FLASH_CFI_BY8)) { 133559829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio >>= 1; 133659829cc1SJean-Christophe PLAGNIOL-VILLARD } 133759829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("size_ratio %d port %d bits chip %d bits\n", 133859829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, 133959829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 134059829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found %d erase regions\n", num_erase_regions); 134159829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt = 0; 134259829cc1SJean-Christophe PLAGNIOL-VILLARD sector = base; 134359829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < num_erase_regions; i++) { 134459829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > NUM_ERASE_REGIONS) { 134559829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("%d erase regions found, only %d used\n", 134659829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions, NUM_ERASE_REGIONS); 134759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 134859829cc1SJean-Christophe PLAGNIOL-VILLARD } 134959829cc1SJean-Christophe PLAGNIOL-VILLARD if (geometry_reversed) 135059829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = flash_read_long (info, 0, 135159829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_ERASE_REGIONS + 135259829cc1SJean-Christophe PLAGNIOL-VILLARD (num_erase_regions - 1 - i) * 4); 135359829cc1SJean-Christophe PLAGNIOL-VILLARD else 135459829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = flash_read_long (info, 0, 135559829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_ERASE_REGIONS + 135659829cc1SJean-Christophe PLAGNIOL-VILLARD i * 4); 135759829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_size = 135859829cc1SJean-Christophe PLAGNIOL-VILLARD (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; 135959829cc1SJean-Christophe PLAGNIOL-VILLARD tmp >>= 16; 136059829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count = (tmp & 0xffff) + 1; 136159829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("erase_region_count = %d erase_region_size = %d\n", 136259829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count, erase_region_size); 136359829cc1SJean-Christophe PLAGNIOL-VILLARD for (j = 0; j < erase_region_count; j++) { 1364*81b20cccSMichael Schwingen if (sect_cnt >= CFG_MAX_FLASH_SECT) { 1365*81b20cccSMichael Schwingen printf("ERROR: too many flash sectors\n"); 1366*81b20cccSMichael Schwingen break; 1367*81b20cccSMichael Schwingen } 136859829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[sect_cnt] = sector; 136959829cc1SJean-Christophe PLAGNIOL-VILLARD sector += (erase_region_size * size_ratio); 137059829cc1SJean-Christophe PLAGNIOL-VILLARD 137159829cc1SJean-Christophe PLAGNIOL-VILLARD /* 137259829cc1SJean-Christophe PLAGNIOL-VILLARD * Only read protection status from supported devices (intel...) 137359829cc1SJean-Christophe PLAGNIOL-VILLARD */ 137459829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 137559829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 137659829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 137759829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sect_cnt] = 137859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_isset (info, sect_cnt, 137959829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PROTECT, 138059829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_STATUS_PROTECT); 138159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 138259829cc1SJean-Christophe PLAGNIOL-VILLARD default: 138359829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sect_cnt] = 0; /* default: not protected */ 138459829cc1SJean-Christophe PLAGNIOL-VILLARD } 138559829cc1SJean-Christophe PLAGNIOL-VILLARD 138659829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt++; 138759829cc1SJean-Christophe PLAGNIOL-VILLARD } 138859829cc1SJean-Christophe PLAGNIOL-VILLARD } 138959829cc1SJean-Christophe PLAGNIOL-VILLARD 139059829cc1SJean-Christophe PLAGNIOL-VILLARD info->sector_count = sect_cnt; 139159829cc1SJean-Christophe PLAGNIOL-VILLARD /* multiply the size by the number of chips */ 139259829cc1SJean-Christophe PLAGNIOL-VILLARD info->size = (1 << flash_read_uchar (info, FLASH_OFFSET_SIZE)) * size_ratio; 139359829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_size = (1 << flash_read_ushort (info, 0, FLASH_OFFSET_BUFFER_SIZE)); 139459829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT); 139559829cc1SJean-Christophe PLAGNIOL-VILLARD info->erase_blk_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_EMAX_TOUT))); 139659829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT)) * 139759829cc1SJean-Christophe PLAGNIOL-VILLARD (1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT)); 139859829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */ 139959829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT)) * 140059829cc1SJean-Christophe PLAGNIOL-VILLARD (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT)); 140159829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */ 140259829cc1SJean-Christophe PLAGNIOL-VILLARD info->flash_id = FLASH_MAN_CFI; 140359829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) { 140459829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth >>= 1; /* XXX - Need to test on x8/x16 in parallel. */ 140559829cc1SJean-Christophe PLAGNIOL-VILLARD } 140659829cc1SJean-Christophe PLAGNIOL-VILLARD } 140759829cc1SJean-Christophe PLAGNIOL-VILLARD 140859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 140959829cc1SJean-Christophe PLAGNIOL-VILLARD return (info->size); 141059829cc1SJean-Christophe PLAGNIOL-VILLARD } 141159829cc1SJean-Christophe PLAGNIOL-VILLARD 141259829cc1SJean-Christophe PLAGNIOL-VILLARD /* loop through the sectors from the highest address 141359829cc1SJean-Christophe PLAGNIOL-VILLARD * when the passed address is greater or equal to the sector address 141459829cc1SJean-Christophe PLAGNIOL-VILLARD * we have a match 141559829cc1SJean-Christophe PLAGNIOL-VILLARD */ 141659829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_sect_t find_sector (flash_info_t * info, ulong addr) 141759829cc1SJean-Christophe PLAGNIOL-VILLARD { 141859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sector; 141959829cc1SJean-Christophe PLAGNIOL-VILLARD 142059829cc1SJean-Christophe PLAGNIOL-VILLARD for (sector = info->sector_count - 1; sector >= 0; sector--) { 142159829cc1SJean-Christophe PLAGNIOL-VILLARD if (addr >= info->start[sector]) 142259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 142359829cc1SJean-Christophe PLAGNIOL-VILLARD } 142459829cc1SJean-Christophe PLAGNIOL-VILLARD return sector; 142559829cc1SJean-Christophe PLAGNIOL-VILLARD } 142659829cc1SJean-Christophe PLAGNIOL-VILLARD 142759829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 142859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 142959829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfiword (flash_info_t * info, ulong dest, 143059829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword) 143159829cc1SJean-Christophe PLAGNIOL-VILLARD { 143259829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t ctladdr; 143359829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 143459829cc1SJean-Christophe PLAGNIOL-VILLARD int flag; 143559829cc1SJean-Christophe PLAGNIOL-VILLARD 143659829cc1SJean-Christophe PLAGNIOL-VILLARD ctladdr.cp = flash_make_addr (info, 0, 0); 143759829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = (uchar *) dest; 143859829cc1SJean-Christophe PLAGNIOL-VILLARD 143959829cc1SJean-Christophe PLAGNIOL-VILLARD /* Check if Flash is (sufficiently) erased */ 144059829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 144159829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 144259829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.cp[0] & cword.c) == cword.c); 144359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 144459829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 144559829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.wp[0] & cword.w) == cword.w); 144659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 144759829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 144859829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.lp[0] & cword.l) == cword.l); 144959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 145059829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 145159829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.llp[0] & cword.ll) == cword.ll); 145259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 145359829cc1SJean-Christophe PLAGNIOL-VILLARD default: 145459829cc1SJean-Christophe PLAGNIOL-VILLARD return 2; 145559829cc1SJean-Christophe PLAGNIOL-VILLARD } 145659829cc1SJean-Christophe PLAGNIOL-VILLARD if (!flag) 145759829cc1SJean-Christophe PLAGNIOL-VILLARD return 2; 145859829cc1SJean-Christophe PLAGNIOL-VILLARD 145959829cc1SJean-Christophe PLAGNIOL-VILLARD /* Disable interrupts which might cause a timeout here */ 146059829cc1SJean-Christophe PLAGNIOL-VILLARD flag = disable_interrupts (); 146159829cc1SJean-Christophe PLAGNIOL-VILLARD 146259829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 146359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 146459829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 146559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); 146659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE); 146759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 146859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 146959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 1470*81b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY 1471*81b20cccSMichael Schwingen case CFI_CMDSET_AMD_LEGACY: 1472*81b20cccSMichael Schwingen #endif 147359829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, 0); 1474*81b20cccSMichael Schwingen flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE); 147559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 147659829cc1SJean-Christophe PLAGNIOL-VILLARD } 147759829cc1SJean-Christophe PLAGNIOL-VILLARD 147859829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 147959829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 148059829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp[0] = cword.c; 148159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 148259829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 148359829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.wp[0] = cword.w; 148459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 148559829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 148659829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.lp[0] = cword.l; 148759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 148859829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 148959829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.llp[0] = cword.ll; 149059829cc1SJean-Christophe PLAGNIOL-VILLARD break; 149159829cc1SJean-Christophe PLAGNIOL-VILLARD } 149259829cc1SJean-Christophe PLAGNIOL-VILLARD 149359829cc1SJean-Christophe PLAGNIOL-VILLARD /* re-enable interrupts if necessary */ 149459829cc1SJean-Christophe PLAGNIOL-VILLARD if (flag) 149559829cc1SJean-Christophe PLAGNIOL-VILLARD enable_interrupts (); 149659829cc1SJean-Christophe PLAGNIOL-VILLARD 149759829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_full_status_check (info, find_sector (info, dest), 149859829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout, "write"); 149959829cc1SJean-Christophe PLAGNIOL-VILLARD } 150059829cc1SJean-Christophe PLAGNIOL-VILLARD 150159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 150259829cc1SJean-Christophe PLAGNIOL-VILLARD 150359829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, 150459829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 150559829cc1SJean-Christophe PLAGNIOL-VILLARD { 150659829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sector; 150759829cc1SJean-Christophe PLAGNIOL-VILLARD int cnt; 150859829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode; 150959829cc1SJean-Christophe PLAGNIOL-VILLARD volatile cfiptr_t src; 151059829cc1SJean-Christophe PLAGNIOL-VILLARD volatile cfiptr_t dst; 151159829cc1SJean-Christophe PLAGNIOL-VILLARD 151259829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 151359829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 151459829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 151559829cc1SJean-Christophe PLAGNIOL-VILLARD src.cp = cp; 151659829cc1SJean-Christophe PLAGNIOL-VILLARD dst.cp = (uchar *) dest; 151759829cc1SJean-Christophe PLAGNIOL-VILLARD sector = find_sector (info, dest); 151859829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 151959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); 152059829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode = flash_status_check (info, sector, info->buffer_write_tout, 152159829cc1SJean-Christophe PLAGNIOL-VILLARD "write to buffer")) == ERR_OK) { 152259829cc1SJean-Christophe PLAGNIOL-VILLARD /* reduce the number of loops by the width of the port */ 152359829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 152459829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 152559829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len; 152659829cc1SJean-Christophe PLAGNIOL-VILLARD break; 152759829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 152859829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 1; 152959829cc1SJean-Christophe PLAGNIOL-VILLARD break; 153059829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 153159829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 2; 153259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 153359829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 153459829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 3; 153559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 153659829cc1SJean-Christophe PLAGNIOL-VILLARD default: 153759829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 153859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 153959829cc1SJean-Christophe PLAGNIOL-VILLARD } 154059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 154159829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) { 154259829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 154359829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 154459829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.cp++ = *src.cp++; 154559829cc1SJean-Christophe PLAGNIOL-VILLARD break; 154659829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 154759829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.wp++ = *src.wp++; 154859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 154959829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 155059829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.lp++ = *src.lp++; 155159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 155259829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 155359829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.llp++ = *src.llp++; 155459829cc1SJean-Christophe PLAGNIOL-VILLARD break; 155559829cc1SJean-Christophe PLAGNIOL-VILLARD default: 155659829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 155759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 155859829cc1SJean-Christophe PLAGNIOL-VILLARD } 155959829cc1SJean-Christophe PLAGNIOL-VILLARD } 156059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, 156159829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_CMD_WRITE_BUFFER_CONFIRM); 156259829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = flash_full_status_check (info, sector, 156359829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout, 156459829cc1SJean-Christophe PLAGNIOL-VILLARD "buffer write"); 156559829cc1SJean-Christophe PLAGNIOL-VILLARD } 156659829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 156759829cc1SJean-Christophe PLAGNIOL-VILLARD 156859829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 156959829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 157059829cc1SJean-Christophe PLAGNIOL-VILLARD src.cp = cp; 157159829cc1SJean-Christophe PLAGNIOL-VILLARD dst.cp = (uchar *) dest; 157259829cc1SJean-Christophe PLAGNIOL-VILLARD sector = find_sector (info, dest); 157359829cc1SJean-Christophe PLAGNIOL-VILLARD 157459829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info,0); 157559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER); 157659829cc1SJean-Christophe PLAGNIOL-VILLARD 157759829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 157859829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 157959829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len; 158059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 158159829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.cp++ = *src.cp++; 158259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 158359829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 158459829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 1; 158559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 158659829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.wp++ = *src.wp++; 158759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 158859829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 158959829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 2; 159059829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 159159829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.lp++ = *src.lp++; 159259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 159359829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 159459829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 3; 159559829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 159659829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.llp++ = *src.llp++; 159759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 159859829cc1SJean-Christophe PLAGNIOL-VILLARD default: 159959829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 160059829cc1SJean-Christophe PLAGNIOL-VILLARD } 160159829cc1SJean-Christophe PLAGNIOL-VILLARD 160259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); 160359829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = flash_full_status_check (info, sector, info->buffer_write_tout, 160459829cc1SJean-Christophe PLAGNIOL-VILLARD "buffer write"); 160559829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 160659829cc1SJean-Christophe PLAGNIOL-VILLARD 160759829cc1SJean-Christophe PLAGNIOL-VILLARD default: 160859829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("Unknown Command Set\n"); 160959829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 161059829cc1SJean-Christophe PLAGNIOL-VILLARD } 161159829cc1SJean-Christophe PLAGNIOL-VILLARD } 161259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */ 161359829cc1SJean-Christophe PLAGNIOL-VILLARD 161459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_CFI */ 1615