1*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 2*59829cc1SJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2002-2004 3*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com 4*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 5*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2003 Arabella Software Ltd. 6*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Yuli Barcohen <yuli@arabellasw.com> 7*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 8*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2004 9*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Ed Okerson 10*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 11*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2006 12*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Tolunay Orkun <listmember@orkun.us> 13*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 14*59829cc1SJean-Christophe PLAGNIOL-VILLARD * See file CREDITS for list of people who contributed to this 15*59829cc1SJean-Christophe PLAGNIOL-VILLARD * project. 16*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 17*59829cc1SJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or 18*59829cc1SJean-Christophe PLAGNIOL-VILLARD * modify it under the terms of the GNU General Public License as 19*59829cc1SJean-Christophe PLAGNIOL-VILLARD * published by the Free Software Foundation; either version 2 of 20*59829cc1SJean-Christophe PLAGNIOL-VILLARD * the License, or (at your option) any later version. 21*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 22*59829cc1SJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 23*59829cc1SJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 24*59829cc1SJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25*59829cc1SJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 26*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 27*59829cc1SJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 28*59829cc1SJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 29*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 30*59829cc1SJean-Christophe PLAGNIOL-VILLARD * MA 02111-1307 USA 31*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 32*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 33*59829cc1SJean-Christophe PLAGNIOL-VILLARD 34*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* The DEBUG define must be before common to enable debugging */ 35*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* #define DEBUG */ 36*59829cc1SJean-Christophe PLAGNIOL-VILLARD 37*59829cc1SJean-Christophe PLAGNIOL-VILLARD #include <common.h> 38*59829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/processor.h> 39*59829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h> 40*59829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/byteorder.h> 41*59829cc1SJean-Christophe PLAGNIOL-VILLARD #include <environment.h> 42*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_CFI_DRIVER 43*59829cc1SJean-Christophe PLAGNIOL-VILLARD 44*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 45*59829cc1SJean-Christophe PLAGNIOL-VILLARD * This file implements a Common Flash Interface (CFI) driver for U-Boot. 46*59829cc1SJean-Christophe PLAGNIOL-VILLARD * The width of the port and the width of the chips are determined at initialization. 47*59829cc1SJean-Christophe PLAGNIOL-VILLARD * These widths are used to calculate the address for access CFI data structures. 48*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 49*59829cc1SJean-Christophe PLAGNIOL-VILLARD * References 50*59829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JESD68 - Common Flash Interface (CFI) 51*59829cc1SJean-Christophe PLAGNIOL-VILLARD * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes 52*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets 53*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet 54*59829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD CFI Specification, Release 2.0 December 1, 2001 55*59829cc1SJean-Christophe PLAGNIOL-VILLARD * AMD/Spansion Application Note: Migration from Single-byte to Three-byte 56*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Device IDs, Publication Number 25538 Revision A, November 8, 2001 57*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 58*59829cc1SJean-Christophe PLAGNIOL-VILLARD * define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between 59*59829cc1SJean-Christophe PLAGNIOL-VILLARD * reading and writing ... (yes there is such a Hardware). 60*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 61*59829cc1SJean-Christophe PLAGNIOL-VILLARD 62*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_BANKS_LIST 63*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE } 64*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 65*59829cc1SJean-Christophe PLAGNIOL-VILLARD 66*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CFI 0x98 67*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_READ_ID 0x90 68*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_RESET 0xff 69*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_BLOCK_ERASE 0x20 70*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_ERASE_CONFIRM 0xD0 71*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE 0x40 72*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT 0x60 73*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_SET 0x01 74*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_CLEAR 0xD0 75*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CLEAR_STATUS 0x50 76*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_TO_BUFFER 0xE8 77*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0 78*59829cc1SJean-Christophe PLAGNIOL-VILLARD 79*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DONE 0x80 80*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ESS 0x40 81*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ECLBS 0x20 82*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSLBS 0x10 83*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_VPENS 0x08 84*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSS 0x04 85*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DPS 0x02 86*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_R 0x01 87*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PROTECT 0x01 88*59829cc1SJean-Christophe PLAGNIOL-VILLARD 89*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_RESET 0xF0 90*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE 0xA0 91*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_START 0x80 92*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_SECTOR 0x30 93*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_START 0xAA 94*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_ACK 0x55 95*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_TO_BUFFER 0x25 96*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29 97*59829cc1SJean-Christophe PLAGNIOL-VILLARD 98*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_TOGGLE 0x40 99*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_ERROR 0x20 100*59829cc1SJean-Christophe PLAGNIOL-VILLARD 101*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_ADDR_ERASE_START ((info->portwidth == FLASH_CFI_8BIT) ? 0xAAA : 0x555) 102*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_ADDR_START ((info->portwidth == FLASH_CFI_8BIT) ? 0xAAA : 0x555) 103*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_ADDR_ACK ((info->portwidth == FLASH_CFI_8BIT) ? 0x555 : 0x2AA) 104*59829cc1SJean-Christophe PLAGNIOL-VILLARD 105*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_MANUFACTURER_ID 0x00 106*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID 0x01 107*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID2 0x0E 108*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID3 0x0F 109*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI 0x55 110*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_ALT 0x555 111*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_RESP 0x10 112*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PRIMARY_VENDOR 0x13 113*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15 /* extended query table primary addr */ 114*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WTOUT 0x1F 115*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBTOUT 0x20 116*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ETOUT 0x21 117*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CETOUT 0x22 118*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WMAX_TOUT 0x23 119*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBMAX_TOUT 0x24 120*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EMAX_TOUT 0x25 121*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CEMAX_TOUT 0x26 122*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_SIZE 0x27 123*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTERFACE 0x28 124*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_BUFFER_SIZE 0x2A 125*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C 126*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ERASE_REGIONS 0x2D 127*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PROTECT 0x02 128*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_USER_PROTECTION 0x85 129*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTEL_PROTECTION 0x81 130*59829cc1SJean-Christophe PLAGNIOL-VILLARD 131*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_NONE 0 132*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_EXTENDED 1 133*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_STANDARD 2 134*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_STANDARD 3 135*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_EXTENDED 4 136*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_STANDARD 256 137*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_EXTENDED 257 138*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_SST 258 139*59829cc1SJean-Christophe PLAGNIOL-VILLARD 140*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */ 141*59829cc1SJean-Christophe PLAGNIOL-VILLARD # undef FLASH_CMD_RESET 142*59829cc1SJean-Christophe PLAGNIOL-VILLARD # define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */ 143*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 144*59829cc1SJean-Christophe PLAGNIOL-VILLARD 145*59829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union { 146*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned char c; 147*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned short w; 148*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long l; 149*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long long ll; 150*59829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiword_t; 151*59829cc1SJean-Christophe PLAGNIOL-VILLARD 152*59829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union { 153*59829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned char *cp; 154*59829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned short *wp; 155*59829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long *lp; 156*59829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long long *llp; 157*59829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiptr_t; 158*59829cc1SJean-Christophe PLAGNIOL-VILLARD 159*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define NUM_ERASE_REGIONS 4 /* max. number of erase regions */ 160*59829cc1SJean-Christophe PLAGNIOL-VILLARD 161*59829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2]={FLASH_OFFSET_CFI,FLASH_OFFSET_CFI_ALT}; 162*59829cc1SJean-Christophe PLAGNIOL-VILLARD 163*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* use CFG_MAX_FLASH_BANKS_DETECT if defined */ 164*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_MAX_FLASH_BANKS_DETECT 165*59829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS_DETECT] = CFG_FLASH_BANKS_LIST; 166*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS_DETECT]; /* FLASH chips info */ 167*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else 168*59829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST; 169*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */ 170*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 171*59829cc1SJean-Christophe PLAGNIOL-VILLARD 172*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 173*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if chip width is defined. If not, start detecting with 8bit. 174*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 175*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_CFI_WIDTH 176*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_CFI_WIDTH FLASH_CFI_8BIT 177*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 178*59829cc1SJean-Christophe PLAGNIOL-VILLARD 179*59829cc1SJean-Christophe PLAGNIOL-VILLARD 180*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 181*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Functions 182*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 183*59829cc1SJean-Christophe PLAGNIOL-VILLARD 184*59829cc1SJean-Christophe PLAGNIOL-VILLARD typedef unsigned long flash_sect_t; 185*59829cc1SJean-Christophe PLAGNIOL-VILLARD 186*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c); 187*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf); 188*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); 189*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect); 190*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); 191*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); 192*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); 193*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_read_jedec_ids (flash_info_t * info); 194*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_detect_cfi (flash_info_t * info); 195*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfiword (flash_info_t * info, ulong dest, cfiword_t cword); 196*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, 197*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong tout, char *prompt); 198*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum); 199*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 200*59829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_info_t *flash_get_info(ulong base); 201*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 202*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 203*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, int len); 204*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 205*59829cc1SJean-Christophe PLAGNIOL-VILLARD 206*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 207*59829cc1SJean-Christophe PLAGNIOL-VILLARD * create an address based on the offset and the port width 208*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 209*59829cc1SJean-Christophe PLAGNIOL-VILLARD inline uchar *flash_make_addr (flash_info_t * info, flash_sect_t sect, uint offset) 210*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 211*59829cc1SJean-Christophe PLAGNIOL-VILLARD return ((uchar *) (info->start[sect] + (offset * info->portwidth))); 212*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 213*59829cc1SJean-Christophe PLAGNIOL-VILLARD 214*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 215*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 216*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Debug support 217*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 218*59829cc1SJean-Christophe PLAGNIOL-VILLARD void print_longlong (char *str, unsigned long long data) 219*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 220*59829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 221*59829cc1SJean-Christophe PLAGNIOL-VILLARD char *cp; 222*59829cc1SJean-Christophe PLAGNIOL-VILLARD 223*59829cc1SJean-Christophe PLAGNIOL-VILLARD cp = (unsigned char *) &data; 224*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < 8; i++) 225*59829cc1SJean-Christophe PLAGNIOL-VILLARD sprintf (&str[i * 2], "%2.2x", *cp++); 226*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 227*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_printqry (flash_info_t * info, flash_sect_t sect) 228*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 229*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 230*59829cc1SJean-Christophe PLAGNIOL-VILLARD int x, y; 231*59829cc1SJean-Christophe PLAGNIOL-VILLARD 232*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 0x40; x += 16U / info->portwidth) { 233*59829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = 234*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_addr (info, sect, 235*59829cc1SJean-Christophe PLAGNIOL-VILLARD x + FLASH_OFFSET_CFI_RESP); 236*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("%p : ", cptr.cp); 237*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (y = 0; y < 16; y++) { 238*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("%2.2x ", cptr.cp[y]); 239*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 240*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug (" "); 241*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (y = 0; y < 16; y++) { 242*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (cptr.cp[y] >= 0x20 && cptr.cp[y] <= 0x7e) { 243*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("%c", cptr.cp[y]); 244*59829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 245*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("."); 246*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 247*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 248*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("\n"); 249*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 250*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 251*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 252*59829cc1SJean-Christophe PLAGNIOL-VILLARD 253*59829cc1SJean-Christophe PLAGNIOL-VILLARD 254*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 255*59829cc1SJean-Christophe PLAGNIOL-VILLARD * read a character at a port width address 256*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 257*59829cc1SJean-Christophe PLAGNIOL-VILLARD inline uchar flash_read_uchar (flash_info_t * info, uint offset) 258*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 259*59829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *cp; 260*59829cc1SJean-Christophe PLAGNIOL-VILLARD 261*59829cc1SJean-Christophe PLAGNIOL-VILLARD cp = flash_make_addr (info, 0, offset); 262*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 263*59829cc1SJean-Christophe PLAGNIOL-VILLARD return (cp[0]); 264*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else 265*59829cc1SJean-Christophe PLAGNIOL-VILLARD return (cp[info->portwidth - 1]); 266*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 267*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 268*59829cc1SJean-Christophe PLAGNIOL-VILLARD 269*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 270*59829cc1SJean-Christophe PLAGNIOL-VILLARD * read a short word by swapping for ppc format. 271*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 272*59829cc1SJean-Christophe PLAGNIOL-VILLARD ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect, uint offset) 273*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 274*59829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *addr; 275*59829cc1SJean-Christophe PLAGNIOL-VILLARD ushort retval; 276*59829cc1SJean-Christophe PLAGNIOL-VILLARD 277*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 278*59829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 279*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 280*59829cc1SJean-Christophe PLAGNIOL-VILLARD addr = flash_make_addr (info, sect, offset); 281*59829cc1SJean-Christophe PLAGNIOL-VILLARD 282*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 283*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("ushort addr is at %p info->portwidth = %d\n", addr, 284*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth); 285*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 2 * info->portwidth; x++) { 286*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("addr[%x] = 0x%x\n", x, addr[x]); 287*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 288*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 289*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 290*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((addr[(info->portwidth)] << 8) | addr[0]); 291*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else 292*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((addr[(2 * info->portwidth) - 1] << 8) | 293*59829cc1SJean-Christophe PLAGNIOL-VILLARD addr[info->portwidth - 1]); 294*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 295*59829cc1SJean-Christophe PLAGNIOL-VILLARD 296*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("retval = 0x%x\n", retval); 297*59829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 298*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 299*59829cc1SJean-Christophe PLAGNIOL-VILLARD 300*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 301*59829cc1SJean-Christophe PLAGNIOL-VILLARD * read a long word by picking the least significant byte of each maximum 302*59829cc1SJean-Christophe PLAGNIOL-VILLARD * port size word. Swap for ppc format. 303*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 304*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_read_long (flash_info_t * info, flash_sect_t sect, uint offset) 305*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 306*59829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *addr; 307*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong retval; 308*59829cc1SJean-Christophe PLAGNIOL-VILLARD 309*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 310*59829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 311*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 312*59829cc1SJean-Christophe PLAGNIOL-VILLARD addr = flash_make_addr (info, sect, offset); 313*59829cc1SJean-Christophe PLAGNIOL-VILLARD 314*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 315*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("long addr is at %p info->portwidth = %d\n", addr, 316*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth); 317*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 4 * info->portwidth; x++) { 318*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("addr[%x] = 0x%x\n", x, addr[x]); 319*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 320*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 321*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 322*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (addr[0] << 16) | (addr[(info->portwidth)] << 24) | 323*59829cc1SJean-Christophe PLAGNIOL-VILLARD (addr[(2 * info->portwidth)]) | (addr[(3 * info->portwidth)] << 8); 324*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else 325*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (addr[(2 * info->portwidth) - 1] << 24) | 326*59829cc1SJean-Christophe PLAGNIOL-VILLARD (addr[(info->portwidth) - 1] << 16) | 327*59829cc1SJean-Christophe PLAGNIOL-VILLARD (addr[(4 * info->portwidth) - 1] << 8) | 328*59829cc1SJean-Christophe PLAGNIOL-VILLARD addr[(3 * info->portwidth) - 1]; 329*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 330*59829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 331*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 332*59829cc1SJean-Christophe PLAGNIOL-VILLARD 333*59829cc1SJean-Christophe PLAGNIOL-VILLARD 334*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 335*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 336*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long flash_init (void) 337*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 338*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long size = 0; 339*59829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 340*59829cc1SJean-Christophe PLAGNIOL-VILLARD 341*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 342*59829cc1SJean-Christophe PLAGNIOL-VILLARD char *s = getenv("unlock"); 343*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 344*59829cc1SJean-Christophe PLAGNIOL-VILLARD 345*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* Init: no FLASHes known */ 346*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { 347*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].flash_id = FLASH_UNKNOWN; 348*59829cc1SJean-Christophe PLAGNIOL-VILLARD size += flash_info[i].size = flash_get_size (bank_base[i], i); 349*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_info[i].flash_id == FLASH_UNKNOWN) { 350*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_QUIET_TEST 351*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", 352*59829cc1SJean-Christophe PLAGNIOL-VILLARD i+1, flash_info[i].size, flash_info[i].size << 20); 353*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_QUIET_TEST */ 354*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 355*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 356*59829cc1SJean-Christophe PLAGNIOL-VILLARD else if ((s != NULL) && (strcmp(s, "yes") == 0)) { 357*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 358*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Only the U-Boot image and it's environment is protected, 359*59829cc1SJean-Christophe PLAGNIOL-VILLARD * all other sectors are unprotected (unlocked) if flash 360*59829cc1SJean-Christophe PLAGNIOL-VILLARD * hardware protection is used (CFG_FLASH_PROTECTION) and 361*59829cc1SJean-Christophe PLAGNIOL-VILLARD * the environment variable "unlock" is set to "yes". 362*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 363*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_info[i].legacy_unlock) { 364*59829cc1SJean-Christophe PLAGNIOL-VILLARD int k; 365*59829cc1SJean-Christophe PLAGNIOL-VILLARD 366*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 367*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Disable legacy_unlock temporarily, since 368*59829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_real_protect would relock all other sectors 369*59829cc1SJean-Christophe PLAGNIOL-VILLARD * again otherwise. 370*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 371*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].legacy_unlock = 0; 372*59829cc1SJean-Christophe PLAGNIOL-VILLARD 373*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 374*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Legacy unlocking (e.g. Intel J3) -> unlock only one 375*59829cc1SJean-Christophe PLAGNIOL-VILLARD * sector. This will unlock all sectors. 376*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 377*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (&flash_info[i], 0, 0); 378*59829cc1SJean-Christophe PLAGNIOL-VILLARD 379*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].legacy_unlock = 1; 380*59829cc1SJean-Christophe PLAGNIOL-VILLARD 381*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 382*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Manually mark other sectors as unlocked (unprotected) 383*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 384*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (k = 1; k < flash_info[i].sector_count; k++) 385*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].protect[k] = 0; 386*59829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 387*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 388*59829cc1SJean-Christophe PLAGNIOL-VILLARD * No legancy unlocking -> unlock all sectors 389*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 390*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_CLEAR, 391*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].start[0], 392*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info[i].start[0] + flash_info[i].size - 1, 393*59829cc1SJean-Christophe PLAGNIOL-VILLARD &flash_info[i]); 394*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 395*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 396*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */ 397*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 398*59829cc1SJean-Christophe PLAGNIOL-VILLARD 399*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* Monitor protection ON by default */ 400*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 401*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_SET, 402*59829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_MONITOR_BASE, 403*59829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_MONITOR_BASE + monitor_flash_len - 1, 404*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CFG_MONITOR_BASE)); 405*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 406*59829cc1SJean-Christophe PLAGNIOL-VILLARD 407*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* Environment protection ON by default */ 408*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_ENV_IS_IN_FLASH 409*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_SET, 410*59829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR, 411*59829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, 412*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CFG_ENV_ADDR)); 413*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 414*59829cc1SJean-Christophe PLAGNIOL-VILLARD 415*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* Redundant environment protection ON by default */ 416*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_ENV_ADDR_REDUND 417*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_protect (FLAG_PROTECT_SET, 418*59829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR_REDUND, 419*59829cc1SJean-Christophe PLAGNIOL-VILLARD CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1, 420*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_get_info(CFG_ENV_ADDR_REDUND)); 421*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 422*59829cc1SJean-Christophe PLAGNIOL-VILLARD return (size); 423*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 424*59829cc1SJean-Christophe PLAGNIOL-VILLARD 425*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 426*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 427*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) 428*59829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_info_t *flash_get_info(ulong base) 429*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 430*59829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 431*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t * info = 0; 432*59829cc1SJean-Christophe PLAGNIOL-VILLARD 433*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) { 434*59829cc1SJean-Christophe PLAGNIOL-VILLARD info = & flash_info[i]; 435*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->size && info->start[0] <= base && 436*59829cc1SJean-Christophe PLAGNIOL-VILLARD base <= info->start[0] + info->size - 1) 437*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 438*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 439*59829cc1SJean-Christophe PLAGNIOL-VILLARD 440*59829cc1SJean-Christophe PLAGNIOL-VILLARD return i == CFG_MAX_FLASH_BANKS ? 0 : info; 441*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 442*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 443*59829cc1SJean-Christophe PLAGNIOL-VILLARD 444*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 445*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 446*59829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last) 447*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 448*59829cc1SJean-Christophe PLAGNIOL-VILLARD int rcode = 0; 449*59829cc1SJean-Christophe PLAGNIOL-VILLARD int prot; 450*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect; 451*59829cc1SJean-Christophe PLAGNIOL-VILLARD 452*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 453*59829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Can't erase unknown flash type - aborted\n"); 454*59829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 455*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 456*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((s_first < 0) || (s_first > s_last)) { 457*59829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("- no sectors to erase\n"); 458*59829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 459*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 460*59829cc1SJean-Christophe PLAGNIOL-VILLARD 461*59829cc1SJean-Christophe PLAGNIOL-VILLARD prot = 0; 462*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; ++sect) { 463*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect]) { 464*59829cc1SJean-Christophe PLAGNIOL-VILLARD prot++; 465*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 466*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 467*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) { 468*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("- Warning: %d protected sectors will not be erased!\n", prot); 469*59829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 470*59829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 471*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 472*59829cc1SJean-Christophe PLAGNIOL-VILLARD 473*59829cc1SJean-Christophe PLAGNIOL-VILLARD 474*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (sect = s_first; sect <= s_last; sect++) { 475*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[sect] == 0) { /* not protected */ 476*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 477*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 478*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 479*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS); 480*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE); 481*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sect, 0, FLASH_CMD_ERASE_CONFIRM); 482*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 483*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 484*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 485*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 486*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sect, AMD_ADDR_ERASE_START, 487*59829cc1SJean-Christophe PLAGNIOL-VILLARD AMD_CMD_ERASE_START); 488*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, sect); 489*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR); 490*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 491*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 492*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("Unkown flash vendor %d\n", 493*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->vendor); 494*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 495*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 496*59829cc1SJean-Christophe PLAGNIOL-VILLARD 497*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_full_status_check 498*59829cc1SJean-Christophe PLAGNIOL-VILLARD (info, sect, info->erase_blk_tout, "erase")) { 499*59829cc1SJean-Christophe PLAGNIOL-VILLARD rcode = 1; 500*59829cc1SJean-Christophe PLAGNIOL-VILLARD } else 501*59829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('.'); 502*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 503*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 504*59829cc1SJean-Christophe PLAGNIOL-VILLARD puts (" done\n"); 505*59829cc1SJean-Christophe PLAGNIOL-VILLARD return rcode; 506*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 507*59829cc1SJean-Christophe PLAGNIOL-VILLARD 508*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 509*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 510*59829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info) 511*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 512*59829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 513*59829cc1SJean-Christophe PLAGNIOL-VILLARD 514*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->flash_id != FLASH_MAN_CFI) { 515*59829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("missing or unknown FLASH type\n"); 516*59829cc1SJean-Christophe PLAGNIOL-VILLARD return; 517*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 518*59829cc1SJean-Christophe PLAGNIOL-VILLARD 519*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("CFI conformant FLASH (%d x %d)", 520*59829cc1SJean-Christophe PLAGNIOL-VILLARD (info->portwidth << 3), (info->chipwidth << 3)); 521*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" Size: %ld MB in %d Sectors\n", 522*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->size >> 20, info->sector_count); 523*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" "); 524*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 525*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 526*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Standard"); 527*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 528*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 529*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Intel Extended"); 530*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 531*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 532*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Standard"); 533*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 534*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 535*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("AMD Extended"); 536*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 537*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 538*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Unknown (%d)", info->vendor); 539*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 540*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 541*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X", 542*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id, info->device_id); 543*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 544*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf("%04X", info->device_id2); 545*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 546*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n", 547*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->erase_blk_tout, 548*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout); 549*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size > 1) { 550*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" Buffer write timeout: %ld ms, buffer size: %d bytes\n", 551*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout, 552*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_size); 553*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 554*59829cc1SJean-Christophe PLAGNIOL-VILLARD 555*59829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("\n Sector Start Addresses:"); 556*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; ++i) { 557*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((i % 5) == 0) 558*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("\n"); 559*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_EMPTY_INFO 560*59829cc1SJean-Christophe PLAGNIOL-VILLARD int k; 561*59829cc1SJean-Christophe PLAGNIOL-VILLARD int size; 562*59829cc1SJean-Christophe PLAGNIOL-VILLARD int erased; 563*59829cc1SJean-Christophe PLAGNIOL-VILLARD volatile unsigned long *flash; 564*59829cc1SJean-Christophe PLAGNIOL-VILLARD 565*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 566*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Check if whole sector is erased 567*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 568*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (i != (info->sector_count - 1)) 569*59829cc1SJean-Christophe PLAGNIOL-VILLARD size = info->start[i + 1] - info->start[i]; 570*59829cc1SJean-Christophe PLAGNIOL-VILLARD else 571*59829cc1SJean-Christophe PLAGNIOL-VILLARD size = info->start[0] + info->size - info->start[i]; 572*59829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 1; 573*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash = (volatile unsigned long *) info->start[i]; 574*59829cc1SJean-Christophe PLAGNIOL-VILLARD size = size >> 2; /* divide by 4 for longword access */ 575*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (k = 0; k < size; k++) { 576*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (*flash++ != 0xffffffff) { 577*59829cc1SJean-Christophe PLAGNIOL-VILLARD erased = 0; 578*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 579*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 580*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 581*59829cc1SJean-Christophe PLAGNIOL-VILLARD 582*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* print empty and read-only info */ 583*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %c %s ", 584*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 585*59829cc1SJean-Christophe PLAGNIOL-VILLARD erased ? 'E' : ' ', 586*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 587*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else /* ! CFG_FLASH_EMPTY_INFO */ 588*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf (" %08lX %s ", 589*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[i], 590*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[i] ? "RO" : " "); 591*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 592*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 593*59829cc1SJean-Christophe PLAGNIOL-VILLARD putc ('\n'); 594*59829cc1SJean-Christophe PLAGNIOL-VILLARD return; 595*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 596*59829cc1SJean-Christophe PLAGNIOL-VILLARD 597*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 598*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Copy memory to flash, returns: 599*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 0 - OK 600*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 1 - write timeout 601*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 2 - Flash not erased 602*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 603*59829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) 604*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 605*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong wp; 606*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong cp; 607*59829cc1SJean-Christophe PLAGNIOL-VILLARD int aln; 608*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 609*59829cc1SJean-Christophe PLAGNIOL-VILLARD int i, rc; 610*59829cc1SJean-Christophe PLAGNIOL-VILLARD 611*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 612*59829cc1SJean-Christophe PLAGNIOL-VILLARD int buffered_size; 613*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 614*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 615*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* get lower aligned address */ 616*59829cc1SJean-Christophe PLAGNIOL-VILLARD wp = (addr & ~(info->portwidth - 1)); 617*59829cc1SJean-Christophe PLAGNIOL-VILLARD 618*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle unaligned start */ 619*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((aln = addr - wp) != 0) { 620*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 621*59829cc1SJean-Christophe PLAGNIOL-VILLARD cp = wp; 622*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < aln; ++i, ++cp) 623*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, (*(uchar *) cp)); 624*59829cc1SJean-Christophe PLAGNIOL-VILLARD 625*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (i < info->portwidth) && (cnt > 0); i++) { 626*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 627*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt--; 628*59829cc1SJean-Christophe PLAGNIOL-VILLARD cp++; 629*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 630*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp) 631*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, (*(uchar *) cp)); 632*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 633*59829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 634*59829cc1SJean-Christophe PLAGNIOL-VILLARD wp = cp; 635*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 636*59829cc1SJean-Christophe PLAGNIOL-VILLARD 637*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* handle the aligned part */ 638*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 639*59829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size = (info->portwidth / info->chipwidth); 640*59829cc1SJean-Christophe PLAGNIOL-VILLARD buffered_size *= info->buffer_size; 641*59829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 642*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* prohibit buffer write when buffer_size is 1 */ 643*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->buffer_size == 1) { 644*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 645*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) 646*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 647*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 648*59829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 649*59829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 650*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 651*59829cc1SJean-Christophe PLAGNIOL-VILLARD continue; 652*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 653*59829cc1SJean-Christophe PLAGNIOL-VILLARD 654*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* write buffer until next buffered_size aligned boundary */ 655*59829cc1SJean-Christophe PLAGNIOL-VILLARD i = buffered_size - (wp % buffered_size); 656*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > cnt) 657*59829cc1SJean-Christophe PLAGNIOL-VILLARD i = cnt; 658*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) 659*59829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 660*59829cc1SJean-Christophe PLAGNIOL-VILLARD i -= i & (info->portwidth - 1); 661*59829cc1SJean-Christophe PLAGNIOL-VILLARD wp += i; 662*59829cc1SJean-Christophe PLAGNIOL-VILLARD src += i; 663*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= i; 664*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 665*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else 666*59829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt >= info->portwidth) { 667*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 668*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->portwidth; i++) { 669*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 670*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 671*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((rc = flash_write_cfiword (info, wp, cword)) != 0) 672*59829cc1SJean-Christophe PLAGNIOL-VILLARD return rc; 673*59829cc1SJean-Christophe PLAGNIOL-VILLARD wp += info->portwidth; 674*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt -= info->portwidth; 675*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 676*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */ 677*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (cnt == 0) { 678*59829cc1SJean-Christophe PLAGNIOL-VILLARD return (0); 679*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 680*59829cc1SJean-Christophe PLAGNIOL-VILLARD 681*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 682*59829cc1SJean-Christophe PLAGNIOL-VILLARD * handle unaligned tail bytes 683*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 684*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword.l = 0; 685*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) { 686*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, *src++); 687*59829cc1SJean-Christophe PLAGNIOL-VILLARD --cnt; 688*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 689*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (; i < info->portwidth; ++i, ++cp) { 690*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_add_byte (info, &cword, (*(uchar *) cp)); 691*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 692*59829cc1SJean-Christophe PLAGNIOL-VILLARD 693*59829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_write_cfiword (info, wp, cword); 694*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 695*59829cc1SJean-Christophe PLAGNIOL-VILLARD 696*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 697*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 698*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 699*59829cc1SJean-Christophe PLAGNIOL-VILLARD 700*59829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot) 701*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 702*59829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode = 0; 703*59829cc1SJean-Christophe PLAGNIOL-VILLARD 704*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 705*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); 706*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (prot) 707*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); 708*59829cc1SJean-Christophe PLAGNIOL-VILLARD else 709*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR); 710*59829cc1SJean-Christophe PLAGNIOL-VILLARD 711*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode = 712*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_full_status_check (info, sector, info->erase_blk_tout, 713*59829cc1SJean-Christophe PLAGNIOL-VILLARD prot ? "protect" : "unprotect")) == 0) { 714*59829cc1SJean-Christophe PLAGNIOL-VILLARD 715*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sector] = prot; 716*59829cc1SJean-Christophe PLAGNIOL-VILLARD 717*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 718*59829cc1SJean-Christophe PLAGNIOL-VILLARD * On some of Intel's flash chips (marked via legacy_unlock) 719*59829cc1SJean-Christophe PLAGNIOL-VILLARD * unprotect unprotects all locking. 720*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 721*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((prot == 0) && (info->legacy_unlock)) { 722*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t i; 723*59829cc1SJean-Christophe PLAGNIOL-VILLARD 724*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < info->sector_count; i++) { 725*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->protect[i]) 726*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_real_protect (info, i, 1); 727*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 728*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 729*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 730*59829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 731*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 732*59829cc1SJean-Christophe PLAGNIOL-VILLARD 733*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 734*59829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_user_serial - read the OneTimeProgramming cells 735*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 736*59829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, 737*59829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 738*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 739*59829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 740*59829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *dst; 741*59829cc1SJean-Christophe PLAGNIOL-VILLARD 742*59829cc1SJean-Christophe PLAGNIOL-VILLARD dst = buffer; 743*59829cc1SJean-Christophe PLAGNIOL-VILLARD src = flash_make_addr (info, 0, FLASH_OFFSET_USER_PROTECTION); 744*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 745*59829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (dst, src + offset, len); 746*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 747*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 748*59829cc1SJean-Christophe PLAGNIOL-VILLARD 749*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 750*59829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_read_factory_serial - read the device Id from the protection area 751*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 752*59829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, 753*59829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 754*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 755*59829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *src; 756*59829cc1SJean-Christophe PLAGNIOL-VILLARD 757*59829cc1SJean-Christophe PLAGNIOL-VILLARD src = flash_make_addr (info, 0, FLASH_OFFSET_INTEL_PROTECTION); 758*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); 759*59829cc1SJean-Christophe PLAGNIOL-VILLARD memcpy (buffer, src + offset, len); 760*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 761*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 762*59829cc1SJean-Christophe PLAGNIOL-VILLARD 763*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */ 764*59829cc1SJean-Christophe PLAGNIOL-VILLARD 765*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 766*59829cc1SJean-Christophe PLAGNIOL-VILLARD * flash_is_busy - check to see if the flash is busy 767*59829cc1SJean-Christophe PLAGNIOL-VILLARD * This routine checks the status of the chip and returns true if the chip is busy 768*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 769*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_is_busy (flash_info_t * info, flash_sect_t sect) 770*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 771*59829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 772*59829cc1SJean-Christophe PLAGNIOL-VILLARD 773*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 774*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 775*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 776*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); 777*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 778*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 779*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 780*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); 781*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 782*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 783*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 784*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 785*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("flash_is_busy: %d\n", retval); 786*59829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 787*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 788*59829cc1SJean-Christophe PLAGNIOL-VILLARD 789*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 790*59829cc1SJean-Christophe PLAGNIOL-VILLARD * wait for XSR.7 to be set. Time out with an error if it does not. 791*59829cc1SJean-Christophe PLAGNIOL-VILLARD * This routine does not set the flash to read-array mode. 792*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 793*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_status_check (flash_info_t * info, flash_sect_t sector, 794*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong tout, char *prompt) 795*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 796*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong start; 797*59829cc1SJean-Christophe PLAGNIOL-VILLARD 798*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if CFG_HZ != 1000 799*59829cc1SJean-Christophe PLAGNIOL-VILLARD tout *= CFG_HZ/1000; 800*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 801*59829cc1SJean-Christophe PLAGNIOL-VILLARD 802*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* Wait for command completion */ 803*59829cc1SJean-Christophe PLAGNIOL-VILLARD start = get_timer (0); 804*59829cc1SJean-Christophe PLAGNIOL-VILLARD while (flash_is_busy (info, sector)) { 805*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (get_timer (start) > tout) { 806*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Flash %s timeout at address %lx data %lx\n", 807*59829cc1SJean-Christophe PLAGNIOL-VILLARD prompt, info->start[sector], 808*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_read_long (info, sector, 0)); 809*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, info->cmd_reset); 810*59829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_TIMOUT; 811*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 812*59829cc1SJean-Christophe PLAGNIOL-VILLARD udelay (1); /* also triggers watchdog */ 813*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 814*59829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_OK; 815*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 816*59829cc1SJean-Christophe PLAGNIOL-VILLARD 817*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 818*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check. 819*59829cc1SJean-Christophe PLAGNIOL-VILLARD * This routine sets the flash to read-array mode. 820*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 821*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, 822*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong tout, char *prompt) 823*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 824*59829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode; 825*59829cc1SJean-Christophe PLAGNIOL-VILLARD 826*59829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = flash_status_check (info, sector, tout, prompt); 827*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 828*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 829*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 830*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode == ERR_OK) 831*59829cc1SJean-Christophe PLAGNIOL-VILLARD && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { 832*59829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = ERR_INVAL; 833*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("Flash %s error at address %lx\n", prompt, 834*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[sector]); 835*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) { 836*59829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Command Sequence Error.\n"); 837*59829cc1SJean-Christophe PLAGNIOL-VILLARD } else if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS)) { 838*59829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Block Erase Error.\n"); 839*59829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = ERR_NOT_ERASED; 840*59829cc1SJean-Christophe PLAGNIOL-VILLARD } else if (flash_isset (info, sector, 0, FLASH_STATUS_PSLBS)) { 841*59829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Locking Error\n"); 842*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 843*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { 844*59829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Block locked.\n"); 845*59829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = ERR_PROTECTED; 846*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 847*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) 848*59829cc1SJean-Christophe PLAGNIOL-VILLARD puts ("Vpp Low Error.\n"); 849*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 850*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, info->cmd_reset); 851*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 852*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 853*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 854*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 855*59829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 856*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 857*59829cc1SJean-Christophe PLAGNIOL-VILLARD 858*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 859*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 860*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) 861*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 862*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 863*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned short w; 864*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned int l; 865*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long long ll; 866*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 867*59829cc1SJean-Christophe PLAGNIOL-VILLARD 868*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 869*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 870*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword->c = c; 871*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 872*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 873*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 874*59829cc1SJean-Christophe PLAGNIOL-VILLARD w = c; 875*59829cc1SJean-Christophe PLAGNIOL-VILLARD w <<= 8; 876*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword->w = (cword->w >> 8) | w; 877*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else 878*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword->w = (cword->w << 8) | c; 879*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 880*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 881*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 882*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 883*59829cc1SJean-Christophe PLAGNIOL-VILLARD l = c; 884*59829cc1SJean-Christophe PLAGNIOL-VILLARD l <<= 24; 885*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword->l = (cword->l >> 8) | l; 886*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else 887*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword->l = (cword->l << 8) | c; 888*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 889*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 890*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 891*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) 892*59829cc1SJean-Christophe PLAGNIOL-VILLARD ll = c; 893*59829cc1SJean-Christophe PLAGNIOL-VILLARD ll <<= 56; 894*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword->ll = (cword->ll >> 8) | ll; 895*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else 896*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword->ll = (cword->ll << 8) | c; 897*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 898*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 899*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 900*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 901*59829cc1SJean-Christophe PLAGNIOL-VILLARD 902*59829cc1SJean-Christophe PLAGNIOL-VILLARD 903*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 904*59829cc1SJean-Christophe PLAGNIOL-VILLARD * make a proper sized command based on the port and chip widths 905*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 906*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf) 907*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 908*59829cc1SJean-Christophe PLAGNIOL-VILLARD int i; 909*59829cc1SJean-Christophe PLAGNIOL-VILLARD uchar *cp = (uchar *) cmdbuf; 910*59829cc1SJean-Christophe PLAGNIOL-VILLARD 911*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) 912*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = info->portwidth; i > 0; i--) 913*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else 914*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 1; i <= info->portwidth; i++) 915*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 916*59829cc1SJean-Christophe PLAGNIOL-VILLARD *cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd; 917*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 918*59829cc1SJean-Christophe PLAGNIOL-VILLARD 919*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 920*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Write a proper sized command to the correct address 921*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 922*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) 923*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 924*59829cc1SJean-Christophe PLAGNIOL-VILLARD 925*59829cc1SJean-Christophe PLAGNIOL-VILLARD volatile cfiptr_t addr; 926*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 927*59829cc1SJean-Christophe PLAGNIOL-VILLARD 928*59829cc1SJean-Christophe PLAGNIOL-VILLARD addr.cp = flash_make_addr (info, sect, offset); 929*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 930*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 931*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 932*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr.cp, cmd, 933*59829cc1SJean-Christophe PLAGNIOL-VILLARD cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 934*59829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.cp = cword.c; 935*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 936*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 937*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr.wp, 938*59829cc1SJean-Christophe PLAGNIOL-VILLARD cmd, cword.w, 939*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 940*59829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.wp = cword.w; 941*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 942*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 943*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr.lp, 944*59829cc1SJean-Christophe PLAGNIOL-VILLARD cmd, cword.l, 945*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 946*59829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.lp = cword.l; 947*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 948*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 949*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 950*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 951*59829cc1SJean-Christophe PLAGNIOL-VILLARD char str[20]; 952*59829cc1SJean-Christophe PLAGNIOL-VILLARD 953*59829cc1SJean-Christophe PLAGNIOL-VILLARD print_longlong (str, cword.ll); 954*59829cc1SJean-Christophe PLAGNIOL-VILLARD 955*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n", 956*59829cc1SJean-Christophe PLAGNIOL-VILLARD addr.llp, cmd, str, 957*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 958*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 959*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 960*59829cc1SJean-Christophe PLAGNIOL-VILLARD *addr.llp = cword.ll; 961*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 962*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 963*59829cc1SJean-Christophe PLAGNIOL-VILLARD 964*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* Ensure all the instructions are fully finished */ 965*59829cc1SJean-Christophe PLAGNIOL-VILLARD sync(); 966*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 967*59829cc1SJean-Christophe PLAGNIOL-VILLARD 968*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect) 969*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 970*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sect, AMD_ADDR_START, AMD_CMD_UNLOCK_START); 971*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sect, AMD_ADDR_ACK, AMD_CMD_UNLOCK_ACK); 972*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 973*59829cc1SJean-Christophe PLAGNIOL-VILLARD 974*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 975*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 976*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) 977*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 978*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 979*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 980*59829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 981*59829cc1SJean-Christophe PLAGNIOL-VILLARD 982*59829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = flash_make_addr (info, sect, offset); 983*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 984*59829cc1SJean-Christophe PLAGNIOL-VILLARD 985*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= cmd %x(%c) addr %p ", cmd, cmd, cptr.cp); 986*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 987*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 988*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %x %x\n", cptr.cp[0], cword.c); 989*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.cp[0] == cword.c); 990*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 991*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 992*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %4.4x %4.4x\n", cptr.wp[0], cword.w); 993*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.wp[0] == cword.w); 994*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 995*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 996*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %8.8lx %8.8lx\n", cptr.lp[0], cword.l); 997*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.lp[0] == cword.l); 998*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 999*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 1000*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 1001*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 1002*59829cc1SJean-Christophe PLAGNIOL-VILLARD char str1[20]; 1003*59829cc1SJean-Christophe PLAGNIOL-VILLARD char str2[20]; 1004*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1005*59829cc1SJean-Christophe PLAGNIOL-VILLARD print_longlong (str1, cptr.llp[0]); 1006*59829cc1SJean-Christophe PLAGNIOL-VILLARD print_longlong (str2, cword.ll); 1007*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("is= %s %s\n", str1, str2); 1008*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1009*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 1010*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = (cptr.llp[0] == cword.ll); 1011*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1012*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 1013*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 1014*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1015*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1016*59829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 1017*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1018*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1019*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 1020*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1021*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) 1022*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 1023*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 1024*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 1025*59829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 1026*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1027*59829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = flash_make_addr (info, sect, offset); 1028*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 1029*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 1030*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 1031*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.cp[0] & cword.c) == cword.c); 1032*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1033*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 1034*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.wp[0] & cword.w) == cword.w); 1035*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1036*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 1037*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.lp[0] & cword.l) == cword.l); 1038*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1039*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 1040*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.llp[0] & cword.ll) == cword.ll); 1041*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1042*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 1043*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 1044*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1045*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1046*59829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 1047*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1048*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1049*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 1050*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1051*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) 1052*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 1053*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 1054*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword; 1055*59829cc1SJean-Christophe PLAGNIOL-VILLARD int retval; 1056*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1057*59829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = flash_make_addr (info, sect, offset); 1058*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_make_cmd (info, cmd, &cword); 1059*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 1060*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 1061*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c)); 1062*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1063*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 1064*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w)); 1065*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1066*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 1067*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l)); 1068*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1069*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 1070*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = ((cptr.llp[0] & cword.ll) != 1071*59829cc1SJean-Christophe PLAGNIOL-VILLARD (cptr.llp[0] & cword.ll)); 1072*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1073*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 1074*59829cc1SJean-Christophe PLAGNIOL-VILLARD retval = 0; 1075*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1076*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1077*59829cc1SJean-Christophe PLAGNIOL-VILLARD return retval; 1078*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1079*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1080*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 1081*59829cc1SJean-Christophe PLAGNIOL-VILLARD * read jedec ids from device and set corresponding fields in info struct 1082*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 1083*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct 1084*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 1085*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1086*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_read_jedec_ids (flash_info_t * info) 1087*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 1088*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = 0; 1089*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = 0; 1090*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = 0; 1091*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1092*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 1093*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 1094*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 1095*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 1096*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); 1097*59829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 1098*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 1099*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 1100*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 1101*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 1102*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); 1103*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1104*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 1105*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 1106*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 1107*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info, 0); 1108*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, AMD_ADDR_START, FLASH_CMD_READ_ID); 1109*59829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1000); /* some flash are slow to respond */ 1110*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->manufacturer_id = flash_read_uchar (info, 1111*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_MANUFACTURER_ID); 1112*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id = flash_read_uchar (info, 1113*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID); 1114*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->device_id == 0x7E) { 1115*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* AMD 3-byte (expanded) device ids */ 1116*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 = flash_read_uchar (info, 1117*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID2); 1118*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 <<= 8; 1119*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->device_id2 |= flash_read_uchar (info, 1120*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_DEVICE_ID3); 1121*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1122*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd(info, 0, 0, AMD_CMD_RESET); 1123*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1124*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 1125*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1126*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1127*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1128*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1129*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 1130*59829cc1SJean-Christophe PLAGNIOL-VILLARD * detect if flash is compatible with the Common Flash Interface (CFI) 1131*59829cc1SJean-Christophe PLAGNIOL-VILLARD * http://www.jedec.org/download/search/jesd68.pdf 1132*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 1133*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1134*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_detect_cfi (flash_info_t * info) 1135*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 1136*59829cc1SJean-Christophe PLAGNIOL-VILLARD int cfi_offset; 1137*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("flash detect cfi\n"); 1138*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1139*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (info->portwidth = CFG_FLASH_CFI_WIDTH; 1140*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) { 1141*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (info->chipwidth = FLASH_CFI_BY8; 1142*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth <= info->portwidth; 1143*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth <<= 1) { 1144*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 1145*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (cfi_offset=0; cfi_offset < sizeof(flash_offset_cfi)/sizeof(uint); cfi_offset++) { 1146*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], FLASH_CMD_CFI); 1147*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') 1148*59829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') 1149*59829cc1SJean-Christophe PLAGNIOL-VILLARD && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { 1150*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->interface = flash_read_ushort (info, 0, FLASH_OFFSET_INTERFACE); 1151*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_offset=flash_offset_cfi[cfi_offset]; 1152*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device interface is %d\n", 1153*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->interface); 1154*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found port %d chip %d ", 1155*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth, info->chipwidth); 1156*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("port %d bits chip %d bits\n", 1157*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth << CFI_FLASH_SHIFT_WIDTH, 1158*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 1159*59829cc1SJean-Christophe PLAGNIOL-VILLARD return 1; 1160*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1161*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1162*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1163*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1164*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("not found\n"); 1165*59829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 1166*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1167*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1168*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 1169*59829cc1SJean-Christophe PLAGNIOL-VILLARD * The following code cannot be run from FLASH! 1170*59829cc1SJean-Christophe PLAGNIOL-VILLARD * 1171*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1172*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum) 1173*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 1174*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t *info = &flash_info[banknum]; 1175*59829cc1SJean-Christophe PLAGNIOL-VILLARD int i, j; 1176*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sect_cnt; 1177*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long sector; 1178*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long tmp; 1179*59829cc1SJean-Christophe PLAGNIOL-VILLARD int size_ratio; 1180*59829cc1SJean-Christophe PLAGNIOL-VILLARD uchar num_erase_regions; 1181*59829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_size; 1182*59829cc1SJean-Christophe PLAGNIOL-VILLARD int erase_region_count; 1183*59829cc1SJean-Christophe PLAGNIOL-VILLARD int geometry_reversed = 0; 1184*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1185*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = 0; 1186*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = 0; 1187*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 1188*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = 0; 1189*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 1190*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1191*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[0] = base; 1192*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1193*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_detect_cfi (info)) { 1194*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->vendor = flash_read_ushort (info, 0, 1195*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PRIMARY_VENDOR); 1196*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_read_jedec_ids (info); 1197*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, info->cfi_offset, FLASH_CMD_CFI); 1198*59829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions = flash_read_uchar (info, 1199*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_NUM_ERASE_REGIONS); 1200*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr = flash_read_ushort (info, 0, 1201*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_EXT_QUERY_T_P_ADDR); 1202*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 1203*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version = (ushort) flash_read_uchar (info, 1204*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 3) << 8; 1205*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->cfi_version |= (ushort) flash_read_uchar (info, 1206*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 4); 1207*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1208*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 1209*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_printqry (info, 0); 1210*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 1211*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 1212*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 1213*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 1214*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 1215*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->cmd_reset = FLASH_CMD_RESET; 1216*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION 1217*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* read legacy lock/unlock bit from intel flash */ 1218*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->ext_addr) { 1219*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->legacy_unlock = flash_read_uchar (info, 1220*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->ext_addr + 5) & 0x08; 1221*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1222*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif 1223*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1224*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 1225*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 1226*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->cmd_reset = AMD_CMD_RESET; 1227*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* check if flash geometry needs reversal */ 1228*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (num_erase_regions <= 1) 1229*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1230*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* reverse geometry if top boot part */ 1231*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (info->cfi_version < 0x3131) { 1232*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* CFI < 1.1, try to guess from device id */ 1233*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->device_id & 0x80) != 0) { 1234*59829cc1SJean-Christophe PLAGNIOL-VILLARD geometry_reversed = 1; 1235*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1236*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1237*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1238*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* CFI >= 1.1, deduct from top/bottom flag */ 1239*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* note: ext_addr is valid since cfi_version > 0 */ 1240*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { 1241*59829cc1SJean-Christophe PLAGNIOL-VILLARD geometry_reversed = 1; 1242*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1243*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1244*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1245*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1246*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer is %d\n", info->vendor); 1247*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("manufacturer id is 0x%x\n", info->manufacturer_id); 1248*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id is 0x%x\n", info->device_id); 1249*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("device id2 is 0x%x\n", info->device_id2); 1250*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("cfi version is 0x%04x\n", info->cfi_version); 1251*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1252*59829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio = info->portwidth / info->chipwidth; 1253*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* if the chip is x8/x16 reduce the ratio by half */ 1254*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->interface == FLASH_CFI_X8X16) 1255*59829cc1SJean-Christophe PLAGNIOL-VILLARD && (info->chipwidth == FLASH_CFI_BY8)) { 1256*59829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio >>= 1; 1257*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1258*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("size_ratio %d port %d bits chip %d bits\n", 1259*59829cc1SJean-Christophe PLAGNIOL-VILLARD size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, 1260*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->chipwidth << CFI_FLASH_SHIFT_WIDTH); 1261*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("found %d erase regions\n", num_erase_regions); 1262*59829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt = 0; 1263*59829cc1SJean-Christophe PLAGNIOL-VILLARD sector = base; 1264*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < num_erase_regions; i++) { 1265*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (i > NUM_ERASE_REGIONS) { 1266*59829cc1SJean-Christophe PLAGNIOL-VILLARD printf ("%d erase regions found, only %d used\n", 1267*59829cc1SJean-Christophe PLAGNIOL-VILLARD num_erase_regions, NUM_ERASE_REGIONS); 1268*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1269*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1270*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (geometry_reversed) 1271*59829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = flash_read_long (info, 0, 1272*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_ERASE_REGIONS + 1273*59829cc1SJean-Christophe PLAGNIOL-VILLARD (num_erase_regions - 1 - i) * 4); 1274*59829cc1SJean-Christophe PLAGNIOL-VILLARD else 1275*59829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = flash_read_long (info, 0, 1276*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_ERASE_REGIONS + 1277*59829cc1SJean-Christophe PLAGNIOL-VILLARD i * 4); 1278*59829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_size = 1279*59829cc1SJean-Christophe PLAGNIOL-VILLARD (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; 1280*59829cc1SJean-Christophe PLAGNIOL-VILLARD tmp >>= 16; 1281*59829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count = (tmp & 0xffff) + 1; 1282*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("erase_region_count = %d erase_region_size = %d\n", 1283*59829cc1SJean-Christophe PLAGNIOL-VILLARD erase_region_count, erase_region_size); 1284*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (j = 0; j < erase_region_count; j++) { 1285*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->start[sect_cnt] = sector; 1286*59829cc1SJean-Christophe PLAGNIOL-VILLARD sector += (erase_region_size * size_ratio); 1287*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1288*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* 1289*59829cc1SJean-Christophe PLAGNIOL-VILLARD * Only read protection status from supported devices (intel...) 1290*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1291*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 1292*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 1293*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 1294*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sect_cnt] = 1295*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_isset (info, sect_cnt, 1296*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_OFFSET_PROTECT, 1297*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_STATUS_PROTECT); 1298*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1299*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 1300*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->protect[sect_cnt] = 0; /* default: not protected */ 1301*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1302*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1303*59829cc1SJean-Christophe PLAGNIOL-VILLARD sect_cnt++; 1304*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1305*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1306*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1307*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->sector_count = sect_cnt; 1308*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* multiply the size by the number of chips */ 1309*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->size = (1 << flash_read_uchar (info, FLASH_OFFSET_SIZE)) * size_ratio; 1310*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_size = (1 << flash_read_ushort (info, 0, FLASH_OFFSET_BUFFER_SIZE)); 1311*59829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT); 1312*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->erase_blk_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_EMAX_TOUT))); 1313*59829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT)) * 1314*59829cc1SJean-Christophe PLAGNIOL-VILLARD (1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT)); 1315*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */ 1316*59829cc1SJean-Christophe PLAGNIOL-VILLARD tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT)) * 1317*59829cc1SJean-Christophe PLAGNIOL-VILLARD (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT)); 1318*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */ 1319*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->flash_id = FLASH_MAN_CFI; 1320*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) { 1321*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->portwidth >>= 1; /* XXX - Need to test on x8/x16 in parallel. */ 1322*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1323*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1324*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1325*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, info->cmd_reset); 1326*59829cc1SJean-Christophe PLAGNIOL-VILLARD return (info->size); 1327*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1328*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1329*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* loop through the sectors from the highest address 1330*59829cc1SJean-Christophe PLAGNIOL-VILLARD * when the passed address is greater or equal to the sector address 1331*59829cc1SJean-Christophe PLAGNIOL-VILLARD * we have a match 1332*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1333*59829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_sect_t find_sector (flash_info_t * info, ulong addr) 1334*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 1335*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sector; 1336*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1337*59829cc1SJean-Christophe PLAGNIOL-VILLARD for (sector = info->sector_count - 1; sector >= 0; sector--) { 1338*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (addr >= info->start[sector]) 1339*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1340*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1341*59829cc1SJean-Christophe PLAGNIOL-VILLARD return sector; 1342*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1343*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1344*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*----------------------------------------------------------------------- 1345*59829cc1SJean-Christophe PLAGNIOL-VILLARD */ 1346*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfiword (flash_info_t * info, ulong dest, 1347*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiword_t cword) 1348*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 1349*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t ctladdr; 1350*59829cc1SJean-Christophe PLAGNIOL-VILLARD cfiptr_t cptr; 1351*59829cc1SJean-Christophe PLAGNIOL-VILLARD int flag; 1352*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1353*59829cc1SJean-Christophe PLAGNIOL-VILLARD ctladdr.cp = flash_make_addr (info, 0, 0); 1354*59829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp = (uchar *) dest; 1355*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1356*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* Check if Flash is (sufficiently) erased */ 1357*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 1358*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 1359*59829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.cp[0] & cword.c) == cword.c); 1360*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1361*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 1362*59829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.wp[0] & cword.w) == cword.w); 1363*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1364*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 1365*59829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.lp[0] & cword.l) == cword.l); 1366*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1367*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 1368*59829cc1SJean-Christophe PLAGNIOL-VILLARD flag = ((cptr.llp[0] & cword.ll) == cword.ll); 1369*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1370*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 1371*59829cc1SJean-Christophe PLAGNIOL-VILLARD return 2; 1372*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1373*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (!flag) 1374*59829cc1SJean-Christophe PLAGNIOL-VILLARD return 2; 1375*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1376*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* Disable interrupts which might cause a timeout here */ 1377*59829cc1SJean-Christophe PLAGNIOL-VILLARD flag = disable_interrupts (); 1378*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1379*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 1380*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 1381*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 1382*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); 1383*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE); 1384*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1385*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 1386*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 1387*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq (info, 0); 1388*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, 0, AMD_ADDR_START, AMD_CMD_WRITE); 1389*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1390*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1391*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1392*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 1393*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 1394*59829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.cp[0] = cword.c; 1395*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1396*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 1397*59829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.wp[0] = cword.w; 1398*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1399*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 1400*59829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.lp[0] = cword.l; 1401*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1402*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 1403*59829cc1SJean-Christophe PLAGNIOL-VILLARD cptr.llp[0] = cword.ll; 1404*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1405*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1406*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1407*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* re-enable interrupts if necessary */ 1408*59829cc1SJean-Christophe PLAGNIOL-VILLARD if (flag) 1409*59829cc1SJean-Christophe PLAGNIOL-VILLARD enable_interrupts (); 1410*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1411*59829cc1SJean-Christophe PLAGNIOL-VILLARD return flash_full_status_check (info, find_sector (info, dest), 1412*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->write_tout, "write"); 1413*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1414*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1415*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE 1416*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1417*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, 1418*59829cc1SJean-Christophe PLAGNIOL-VILLARD int len) 1419*59829cc1SJean-Christophe PLAGNIOL-VILLARD { 1420*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_sect_t sector; 1421*59829cc1SJean-Christophe PLAGNIOL-VILLARD int cnt; 1422*59829cc1SJean-Christophe PLAGNIOL-VILLARD int retcode; 1423*59829cc1SJean-Christophe PLAGNIOL-VILLARD volatile cfiptr_t src; 1424*59829cc1SJean-Christophe PLAGNIOL-VILLARD volatile cfiptr_t dst; 1425*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1426*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->vendor) { 1427*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_STANDARD: 1428*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_INTEL_EXTENDED: 1429*59829cc1SJean-Christophe PLAGNIOL-VILLARD src.cp = cp; 1430*59829cc1SJean-Christophe PLAGNIOL-VILLARD dst.cp = (uchar *) dest; 1431*59829cc1SJean-Christophe PLAGNIOL-VILLARD sector = find_sector (info, dest); 1432*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); 1433*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); 1434*59829cc1SJean-Christophe PLAGNIOL-VILLARD if ((retcode = flash_status_check (info, sector, info->buffer_write_tout, 1435*59829cc1SJean-Christophe PLAGNIOL-VILLARD "write to buffer")) == ERR_OK) { 1436*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* reduce the number of loops by the width of the port */ 1437*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 1438*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 1439*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len; 1440*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1441*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 1442*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 1; 1443*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1444*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 1445*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 2; 1446*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1447*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 1448*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 3; 1449*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1450*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 1451*59829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 1452*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1453*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1454*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 1455*59829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) { 1456*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 1457*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 1458*59829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.cp++ = *src.cp++; 1459*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1460*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 1461*59829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.wp++ = *src.wp++; 1462*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1463*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 1464*59829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.lp++ = *src.lp++; 1465*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1466*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 1467*59829cc1SJean-Christophe PLAGNIOL-VILLARD *dst.llp++ = *src.llp++; 1468*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1469*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 1470*59829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 1471*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1472*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1473*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1474*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, 1475*59829cc1SJean-Christophe PLAGNIOL-VILLARD FLASH_CMD_WRITE_BUFFER_CONFIRM); 1476*59829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = flash_full_status_check (info, sector, 1477*59829cc1SJean-Christophe PLAGNIOL-VILLARD info->buffer_write_tout, 1478*59829cc1SJean-Christophe PLAGNIOL-VILLARD "buffer write"); 1479*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1480*59829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 1481*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1482*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_STANDARD: 1483*59829cc1SJean-Christophe PLAGNIOL-VILLARD case CFI_CMDSET_AMD_EXTENDED: 1484*59829cc1SJean-Christophe PLAGNIOL-VILLARD src.cp = cp; 1485*59829cc1SJean-Christophe PLAGNIOL-VILLARD dst.cp = (uchar *) dest; 1486*59829cc1SJean-Christophe PLAGNIOL-VILLARD sector = find_sector (info, dest); 1487*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1488*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_unlock_seq(info,0); 1489*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER); 1490*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1491*59829cc1SJean-Christophe PLAGNIOL-VILLARD switch (info->portwidth) { 1492*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_8BIT: 1493*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len; 1494*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 1495*59829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.cp++ = *src.cp++; 1496*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1497*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_16BIT: 1498*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 1; 1499*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 1500*59829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.wp++ = *src.wp++; 1501*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1502*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_32BIT: 1503*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 2; 1504*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 1505*59829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.lp++ = *src.lp++; 1506*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1507*59829cc1SJean-Christophe PLAGNIOL-VILLARD case FLASH_CFI_64BIT: 1508*59829cc1SJean-Christophe PLAGNIOL-VILLARD cnt = len >> 3; 1509*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, (uchar) cnt - 1); 1510*59829cc1SJean-Christophe PLAGNIOL-VILLARD while (cnt-- > 0) *dst.llp++ = *src.llp++; 1511*59829cc1SJean-Christophe PLAGNIOL-VILLARD break; 1512*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 1513*59829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 1514*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1515*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1516*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); 1517*59829cc1SJean-Christophe PLAGNIOL-VILLARD retcode = flash_full_status_check (info, sector, info->buffer_write_tout, 1518*59829cc1SJean-Christophe PLAGNIOL-VILLARD "buffer write"); 1519*59829cc1SJean-Christophe PLAGNIOL-VILLARD return retcode; 1520*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1521*59829cc1SJean-Christophe PLAGNIOL-VILLARD default: 1522*59829cc1SJean-Christophe PLAGNIOL-VILLARD debug ("Unknown Command Set\n"); 1523*59829cc1SJean-Christophe PLAGNIOL-VILLARD return ERR_INVAL; 1524*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1525*59829cc1SJean-Christophe PLAGNIOL-VILLARD } 1526*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */ 1527*59829cc1SJean-Christophe PLAGNIOL-VILLARD 1528*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_CFI */ 1529