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