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