xref: /rk3399_rockchip-uboot/drivers/mtd/cfi_flash.c (revision cdbaefb5f5f03e54455d0439dcf6dbd97ead1f9d)
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 #define NUM_ERASE_REGIONS	4 /* max. number of erase regions */
15359829cc1SJean-Christophe PLAGNIOL-VILLARD 
15459829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
15559829cc1SJean-Christophe PLAGNIOL-VILLARD 
15659829cc1SJean-Christophe PLAGNIOL-VILLARD /* use CFG_MAX_FLASH_BANKS_DETECT if defined */
15759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_MAX_FLASH_BANKS_DETECT
15859829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS_DETECT] = CFG_FLASH_BANKS_LIST;
15959829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS_DETECT];	/* FLASH chips info */
16059829cc1SJean-Christophe PLAGNIOL-VILLARD #else
16159829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST;
16259829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS];		/* FLASH chips info */
16359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
16459829cc1SJean-Christophe PLAGNIOL-VILLARD 
16559829cc1SJean-Christophe PLAGNIOL-VILLARD /*
16659829cc1SJean-Christophe PLAGNIOL-VILLARD  * Check if chip width is defined. If not, start detecting with 8bit.
16759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
16859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_CFI_WIDTH
16959829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_CFI_WIDTH	FLASH_CFI_8BIT
17059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
17159829cc1SJean-Christophe PLAGNIOL-VILLARD 
17259829cc1SJean-Christophe PLAGNIOL-VILLARD typedef unsigned long flash_sect_t;
17359829cc1SJean-Christophe PLAGNIOL-VILLARD 
174*cdbaefb5SHaavard Skinnemoen static void flash_write8(u8 value, void *addr)
175*cdbaefb5SHaavard Skinnemoen {
176*cdbaefb5SHaavard Skinnemoen 	__raw_writeb(value, addr);
177*cdbaefb5SHaavard Skinnemoen }
178*cdbaefb5SHaavard Skinnemoen 
179*cdbaefb5SHaavard Skinnemoen static void flash_write16(u16 value, void *addr)
180*cdbaefb5SHaavard Skinnemoen {
181*cdbaefb5SHaavard Skinnemoen 	__raw_writew(value, addr);
182*cdbaefb5SHaavard Skinnemoen }
183*cdbaefb5SHaavard Skinnemoen 
184*cdbaefb5SHaavard Skinnemoen static void flash_write32(u32 value, void *addr)
185*cdbaefb5SHaavard Skinnemoen {
186*cdbaefb5SHaavard Skinnemoen 	__raw_writel(value, addr);
187*cdbaefb5SHaavard Skinnemoen }
188*cdbaefb5SHaavard Skinnemoen 
189*cdbaefb5SHaavard Skinnemoen static void flash_write64(u64 value, void *addr)
190*cdbaefb5SHaavard Skinnemoen {
191*cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_writeq() */
192*cdbaefb5SHaavard Skinnemoen 	*(volatile u64 *)addr = value;
193*cdbaefb5SHaavard Skinnemoen }
194*cdbaefb5SHaavard Skinnemoen 
195*cdbaefb5SHaavard Skinnemoen static u8 flash_read8(void *addr)
196*cdbaefb5SHaavard Skinnemoen {
197*cdbaefb5SHaavard Skinnemoen 	return __raw_readb(addr);
198*cdbaefb5SHaavard Skinnemoen }
199*cdbaefb5SHaavard Skinnemoen 
200*cdbaefb5SHaavard Skinnemoen static u16 flash_read16(void *addr)
201*cdbaefb5SHaavard Skinnemoen {
202*cdbaefb5SHaavard Skinnemoen 	return __raw_readw(addr);
203*cdbaefb5SHaavard Skinnemoen }
204*cdbaefb5SHaavard Skinnemoen 
205*cdbaefb5SHaavard Skinnemoen static u32 flash_read32(void *addr)
206*cdbaefb5SHaavard Skinnemoen {
207*cdbaefb5SHaavard Skinnemoen 	return __raw_readl(addr);
208*cdbaefb5SHaavard Skinnemoen }
209*cdbaefb5SHaavard Skinnemoen 
210*cdbaefb5SHaavard Skinnemoen static u64 flash_read64(void *addr)
211*cdbaefb5SHaavard Skinnemoen {
212*cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_readq() */
213*cdbaefb5SHaavard Skinnemoen 	return *(volatile u64 *)addr;
214*cdbaefb5SHaavard Skinnemoen }
215*cdbaefb5SHaavard Skinnemoen 
216be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
217be60a902SHaavard Skinnemoen  */
21859829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
219be60a902SHaavard Skinnemoen static flash_info_t *flash_get_info(ulong base)
220be60a902SHaavard Skinnemoen {
221be60a902SHaavard Skinnemoen 	int i;
222be60a902SHaavard Skinnemoen 	flash_info_t * info = 0;
223be60a902SHaavard Skinnemoen 
224be60a902SHaavard Skinnemoen 	for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
225be60a902SHaavard Skinnemoen 		info = & flash_info[i];
226be60a902SHaavard Skinnemoen 		if (info->size && info->start[0] <= base &&
227be60a902SHaavard Skinnemoen 		    base <= info->start[0] + info->size - 1)
228be60a902SHaavard Skinnemoen 			break;
229be60a902SHaavard Skinnemoen 	}
230be60a902SHaavard Skinnemoen 
231be60a902SHaavard Skinnemoen 	return i == CFG_MAX_FLASH_BANKS ? 0 : info;
232be60a902SHaavard Skinnemoen }
23359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
23459829cc1SJean-Christophe PLAGNIOL-VILLARD 
23559829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
23659829cc1SJean-Christophe PLAGNIOL-VILLARD  * create an address based on the offset and the port width
23759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
2383055793bSHaavard Skinnemoen static inline uchar *
2397e5b9b47SHaavard Skinnemoen flash_make_addr (flash_info_t * info, flash_sect_t sect, uint offset)
24059829cc1SJean-Christophe PLAGNIOL-VILLARD {
24159829cc1SJean-Christophe PLAGNIOL-VILLARD 	return ((uchar *) (info->start[sect] + (offset * info->portwidth)));
24259829cc1SJean-Christophe PLAGNIOL-VILLARD }
24359829cc1SJean-Christophe PLAGNIOL-VILLARD 
244be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
245be60a902SHaavard Skinnemoen  * make a proper sized command based on the port and chip widths
246be60a902SHaavard Skinnemoen  */
247be60a902SHaavard Skinnemoen static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
248be60a902SHaavard Skinnemoen {
249be60a902SHaavard Skinnemoen 	int i;
250be60a902SHaavard Skinnemoen 	uchar *cp = (uchar *) cmdbuf;
251be60a902SHaavard Skinnemoen 
252be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
253be60a902SHaavard Skinnemoen 	for (i = info->portwidth; i > 0; i--)
254be60a902SHaavard Skinnemoen #else
255be60a902SHaavard Skinnemoen 	for (i = 1; i <= info->portwidth; i++)
256be60a902SHaavard Skinnemoen #endif
257be60a902SHaavard Skinnemoen 		*cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;
258be60a902SHaavard Skinnemoen }
259be60a902SHaavard Skinnemoen 
26059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
26159829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
26259829cc1SJean-Christophe PLAGNIOL-VILLARD  * Debug support
26359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
2643055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data)
26559829cc1SJean-Christophe PLAGNIOL-VILLARD {
26659829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
26759829cc1SJean-Christophe PLAGNIOL-VILLARD 	char *cp;
26859829cc1SJean-Christophe PLAGNIOL-VILLARD 
26959829cc1SJean-Christophe PLAGNIOL-VILLARD 	cp = (unsigned char *) &data;
27059829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 8; i++)
27159829cc1SJean-Christophe PLAGNIOL-VILLARD 		sprintf (&str[i * 2], "%2.2x", *cp++);
27259829cc1SJean-Christophe PLAGNIOL-VILLARD }
273be60a902SHaavard Skinnemoen 
27459829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_printqry (flash_info_t * info, flash_sect_t sect)
27559829cc1SJean-Christophe PLAGNIOL-VILLARD {
276*cdbaefb5SHaavard Skinnemoen 	void *addr;
27759829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x, y;
27859829cc1SJean-Christophe PLAGNIOL-VILLARD 
27959829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (x = 0; x < 0x40; x += 16U / info->portwidth) {
280*cdbaefb5SHaavard Skinnemoen 		addr = flash_make_addr (info, sect,
28159829cc1SJean-Christophe PLAGNIOL-VILLARD 					x + FLASH_OFFSET_CFI_RESP);
282*cdbaefb5SHaavard Skinnemoen 		debug ("%p : ", addr);
28359829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (y = 0; y < 16; y++) {
284*cdbaefb5SHaavard Skinnemoen 			debug ("%2.2x ", flash_read8(addr + y));
28559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
28659829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug (" ");
28759829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (y = 0; y < 16; y++) {
288*cdbaefb5SHaavard Skinnemoen 			unsigned char c = flash_read8(addr + y);
289*cdbaefb5SHaavard Skinnemoen 			if (c >= 0x20 && c <= 0x7e) {
290*cdbaefb5SHaavard Skinnemoen 				debug ("%c", c);
29159829cc1SJean-Christophe PLAGNIOL-VILLARD 			} else {
29259829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug (".");
29359829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
29459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
29559829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("\n");
29659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
29759829cc1SJean-Christophe PLAGNIOL-VILLARD }
29859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
29959829cc1SJean-Christophe PLAGNIOL-VILLARD 
30059829cc1SJean-Christophe PLAGNIOL-VILLARD 
30159829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
30259829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a character at a port width address
30359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3043055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
30559829cc1SJean-Christophe PLAGNIOL-VILLARD {
30659829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *cp;
30759829cc1SJean-Christophe PLAGNIOL-VILLARD 
30859829cc1SJean-Christophe PLAGNIOL-VILLARD 	cp = flash_make_addr (info, 0, offset);
30959829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
31059829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (cp[0]);
31159829cc1SJean-Christophe PLAGNIOL-VILLARD #else
31259829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (cp[info->portwidth - 1]);
31359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
31459829cc1SJean-Christophe PLAGNIOL-VILLARD }
31559829cc1SJean-Christophe PLAGNIOL-VILLARD 
31659829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
31759829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a short word by swapping for ppc format.
31859829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3193055793bSHaavard Skinnemoen static ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect,
3203055793bSHaavard Skinnemoen 				 uint offset)
32159829cc1SJean-Christophe PLAGNIOL-VILLARD {
32259829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *addr;
32359829cc1SJean-Christophe PLAGNIOL-VILLARD 	ushort retval;
32459829cc1SJean-Christophe PLAGNIOL-VILLARD 
32559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
32659829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x;
32759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
32859829cc1SJean-Christophe PLAGNIOL-VILLARD 	addr = flash_make_addr (info, sect, offset);
32959829cc1SJean-Christophe PLAGNIOL-VILLARD 
33059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
33159829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("ushort addr is at %p info->portwidth = %d\n", addr,
33259829cc1SJean-Christophe PLAGNIOL-VILLARD 	       info->portwidth);
33359829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (x = 0; x < 2 * info->portwidth; x++) {
33459829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("addr[%x] = 0x%x\n", x, addr[x]);
33559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
33659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
33759829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
33859829cc1SJean-Christophe PLAGNIOL-VILLARD 	retval = ((addr[(info->portwidth)] << 8) | addr[0]);
33959829cc1SJean-Christophe PLAGNIOL-VILLARD #else
34059829cc1SJean-Christophe PLAGNIOL-VILLARD 	retval = ((addr[(2 * info->portwidth) - 1] << 8) |
34159829cc1SJean-Christophe PLAGNIOL-VILLARD 		  addr[info->portwidth - 1]);
34259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
34359829cc1SJean-Christophe PLAGNIOL-VILLARD 
34459829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("retval = 0x%x\n", retval);
34559829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
34659829cc1SJean-Christophe PLAGNIOL-VILLARD }
34759829cc1SJean-Christophe PLAGNIOL-VILLARD 
34859829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
34959829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a long word by picking the least significant byte of each maximum
35059829cc1SJean-Christophe PLAGNIOL-VILLARD  * port size word. Swap for ppc format.
35159829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3523055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
3533055793bSHaavard Skinnemoen 			      uint offset)
35459829cc1SJean-Christophe PLAGNIOL-VILLARD {
35559829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *addr;
35659829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong retval;
35759829cc1SJean-Christophe PLAGNIOL-VILLARD 
35859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
35959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x;
36059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
36159829cc1SJean-Christophe PLAGNIOL-VILLARD 	addr = flash_make_addr (info, sect, offset);
36259829cc1SJean-Christophe PLAGNIOL-VILLARD 
36359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
36459829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("long addr is at %p info->portwidth = %d\n", addr,
36559829cc1SJean-Christophe PLAGNIOL-VILLARD 	       info->portwidth);
36659829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (x = 0; x < 4 * info->portwidth; x++) {
36759829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("addr[%x] = 0x%x\n", x, addr[x]);
36859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
36959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
37059829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
37159829cc1SJean-Christophe PLAGNIOL-VILLARD 	retval = (addr[0] << 16) | (addr[(info->portwidth)] << 24) |
3727e5b9b47SHaavard Skinnemoen 		(addr[(2 * info->portwidth)]) |
3737e5b9b47SHaavard Skinnemoen 		(addr[(3 * info->portwidth)] << 8);
37459829cc1SJean-Christophe PLAGNIOL-VILLARD #else
37559829cc1SJean-Christophe PLAGNIOL-VILLARD 	retval = (addr[(2 * info->portwidth) - 1] << 24) |
37659829cc1SJean-Christophe PLAGNIOL-VILLARD 		(addr[(info->portwidth) - 1] << 16) |
37759829cc1SJean-Christophe PLAGNIOL-VILLARD 		(addr[(4 * info->portwidth) - 1] << 8) |
37859829cc1SJean-Christophe PLAGNIOL-VILLARD 		addr[(3 * info->portwidth) - 1];
37959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
38059829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
38159829cc1SJean-Christophe PLAGNIOL-VILLARD }
38259829cc1SJean-Christophe PLAGNIOL-VILLARD 
383be60a902SHaavard Skinnemoen /*
384be60a902SHaavard Skinnemoen  * Write a proper sized command to the correct address
38581b20cccSMichael Schwingen  */
386be60a902SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
387be60a902SHaavard Skinnemoen 			     uint offset, uchar cmd)
38881b20cccSMichael Schwingen {
3897e5b9b47SHaavard Skinnemoen 
390*cdbaefb5SHaavard Skinnemoen 	void *addr;
391be60a902SHaavard Skinnemoen 	cfiword_t cword;
39281b20cccSMichael Schwingen 
393*cdbaefb5SHaavard Skinnemoen 	addr = flash_make_addr (info, sect, offset);
394be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
395be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
396be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
397*cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
398be60a902SHaavard Skinnemoen 		       cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
399*cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, addr);
400be60a902SHaavard Skinnemoen 		break;
401be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
402*cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
403be60a902SHaavard Skinnemoen 		       cmd, cword.w,
404be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
405*cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, addr);
406be60a902SHaavard Skinnemoen 		break;
407be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
408*cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
409be60a902SHaavard Skinnemoen 		       cmd, cword.l,
410be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
411*cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, addr);
412be60a902SHaavard Skinnemoen 		break;
413be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
414be60a902SHaavard Skinnemoen #ifdef DEBUG
415be60a902SHaavard Skinnemoen 		{
416be60a902SHaavard Skinnemoen 			char str[20];
417be60a902SHaavard Skinnemoen 
418be60a902SHaavard Skinnemoen 			print_longlong (str, cword.ll);
419be60a902SHaavard Skinnemoen 
420be60a902SHaavard Skinnemoen 			debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
421*cdbaefb5SHaavard Skinnemoen 			       addr, cmd, str,
422be60a902SHaavard Skinnemoen 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
42381b20cccSMichael Schwingen 		}
424be60a902SHaavard Skinnemoen #endif
425*cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, addr);
42681b20cccSMichael Schwingen 		break;
42781b20cccSMichael Schwingen 	}
428be60a902SHaavard Skinnemoen 
429be60a902SHaavard Skinnemoen 	/* Ensure all the instructions are fully finished */
430be60a902SHaavard Skinnemoen 	sync();
43181b20cccSMichael Schwingen }
4327e5b9b47SHaavard Skinnemoen 
433be60a902SHaavard Skinnemoen static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
434be60a902SHaavard Skinnemoen {
435be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
436be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
437be60a902SHaavard Skinnemoen }
438be60a902SHaavard Skinnemoen 
439be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
440be60a902SHaavard Skinnemoen  */
441be60a902SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect,
442be60a902SHaavard Skinnemoen 			  uint offset, uchar cmd)
443be60a902SHaavard Skinnemoen {
444*cdbaefb5SHaavard Skinnemoen 	void *addr;
445be60a902SHaavard Skinnemoen 	cfiword_t cword;
446be60a902SHaavard Skinnemoen 	int retval;
447be60a902SHaavard Skinnemoen 
448*cdbaefb5SHaavard Skinnemoen 	addr = flash_make_addr (info, sect, offset);
449be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
450be60a902SHaavard Skinnemoen 
451*cdbaefb5SHaavard Skinnemoen 	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
452be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
453be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
454*cdbaefb5SHaavard Skinnemoen 		debug ("is= %x %x\n", flash_read8(addr), cword.c);
455*cdbaefb5SHaavard Skinnemoen 		retval = (flash_read8(addr) == cword.c);
456be60a902SHaavard Skinnemoen 		break;
457be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
458*cdbaefb5SHaavard Skinnemoen 		debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
459*cdbaefb5SHaavard Skinnemoen 		retval = (flash_read16(addr) == cword.w);
460be60a902SHaavard Skinnemoen 		break;
461be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
462*cdbaefb5SHaavard Skinnemoen 		debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
463*cdbaefb5SHaavard Skinnemoen 		retval = (flash_read32(addr) == cword.l);
464be60a902SHaavard Skinnemoen 		break;
465be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
466be60a902SHaavard Skinnemoen #ifdef DEBUG
467be60a902SHaavard Skinnemoen 		{
468be60a902SHaavard Skinnemoen 			char str1[20];
469be60a902SHaavard Skinnemoen 			char str2[20];
470be60a902SHaavard Skinnemoen 
471*cdbaefb5SHaavard Skinnemoen 			print_longlong (str1, flash_read64(addr));
472be60a902SHaavard Skinnemoen 			print_longlong (str2, cword.ll);
473be60a902SHaavard Skinnemoen 			debug ("is= %s %s\n", str1, str2);
474be60a902SHaavard Skinnemoen 		}
475be60a902SHaavard Skinnemoen #endif
476*cdbaefb5SHaavard Skinnemoen 		retval = (flash_read64(addr) == cword.ll);
477be60a902SHaavard Skinnemoen 		break;
478be60a902SHaavard Skinnemoen 	default:
479be60a902SHaavard Skinnemoen 		retval = 0;
480be60a902SHaavard Skinnemoen 		break;
481be60a902SHaavard Skinnemoen 	}
482be60a902SHaavard Skinnemoen 	return retval;
483be60a902SHaavard Skinnemoen }
484be60a902SHaavard Skinnemoen 
485be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
486be60a902SHaavard Skinnemoen  */
487be60a902SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect,
488be60a902SHaavard Skinnemoen 			uint offset, uchar cmd)
489be60a902SHaavard Skinnemoen {
490*cdbaefb5SHaavard Skinnemoen 	void *addr;
491be60a902SHaavard Skinnemoen 	cfiword_t cword;
492be60a902SHaavard Skinnemoen 	int retval;
493be60a902SHaavard Skinnemoen 
494*cdbaefb5SHaavard Skinnemoen 	addr = flash_make_addr (info, sect, offset);
495be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
496be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
497be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
498*cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read8(addr) & cword.c) == cword.c);
499be60a902SHaavard Skinnemoen 		break;
500be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
501*cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read16(addr) & cword.w) == cword.w);
502be60a902SHaavard Skinnemoen 		break;
503be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
504*cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read16(addr) & cword.l) == cword.l);
505be60a902SHaavard Skinnemoen 		break;
506be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
507*cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read64(addr) & cword.ll) == cword.ll);
508be60a902SHaavard Skinnemoen 		break;
509be60a902SHaavard Skinnemoen 	default:
510be60a902SHaavard Skinnemoen 		retval = 0;
511be60a902SHaavard Skinnemoen 		break;
512be60a902SHaavard Skinnemoen 	}
513be60a902SHaavard Skinnemoen 	return retval;
514be60a902SHaavard Skinnemoen }
515be60a902SHaavard Skinnemoen 
516be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
517be60a902SHaavard Skinnemoen  */
518be60a902SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect,
519be60a902SHaavard Skinnemoen 			 uint offset, uchar cmd)
520be60a902SHaavard Skinnemoen {
521*cdbaefb5SHaavard Skinnemoen 	void *addr;
522be60a902SHaavard Skinnemoen 	cfiword_t cword;
523be60a902SHaavard Skinnemoen 	int retval;
524be60a902SHaavard Skinnemoen 
525*cdbaefb5SHaavard Skinnemoen 	addr = flash_make_addr (info, sect, offset);
526be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
527be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
528be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
529*cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read8(addr) & cword.c) !=
530*cdbaefb5SHaavard Skinnemoen 			  (flash_read8(addr) & cword.c));
531be60a902SHaavard Skinnemoen 		break;
532be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
533*cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read16(addr) & cword.w) !=
534*cdbaefb5SHaavard Skinnemoen 			  (flash_read16(addr) & cword.w));
535be60a902SHaavard Skinnemoen 		break;
536be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
537*cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read32(addr) & cword.l) !=
538*cdbaefb5SHaavard Skinnemoen 			  (flash_read32(addr) & cword.l));
539be60a902SHaavard Skinnemoen 		break;
540be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
541*cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read64(addr) & cword.ll) !=
542*cdbaefb5SHaavard Skinnemoen 			  (flash_read64(addr) & cword.ll));
543be60a902SHaavard Skinnemoen 		break;
544be60a902SHaavard Skinnemoen 	default:
545be60a902SHaavard Skinnemoen 		retval = 0;
546be60a902SHaavard Skinnemoen 		break;
547be60a902SHaavard Skinnemoen 	}
548be60a902SHaavard Skinnemoen 	return retval;
549be60a902SHaavard Skinnemoen }
550be60a902SHaavard Skinnemoen 
551be60a902SHaavard Skinnemoen /*
552be60a902SHaavard Skinnemoen  * flash_is_busy - check to see if the flash is busy
553be60a902SHaavard Skinnemoen  *
554be60a902SHaavard Skinnemoen  * This routine checks the status of the chip and returns true if the
555be60a902SHaavard Skinnemoen  * chip is busy.
556be60a902SHaavard Skinnemoen  */
557be60a902SHaavard Skinnemoen static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
558be60a902SHaavard Skinnemoen {
559be60a902SHaavard Skinnemoen 	int retval;
560be60a902SHaavard Skinnemoen 
56181b20cccSMichael Schwingen 	switch (info->vendor) {
56281b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_STANDARD:
56381b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_EXTENDED:
564be60a902SHaavard Skinnemoen 		retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
56581b20cccSMichael Schwingen 		break;
56681b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_STANDARD:
56781b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_EXTENDED:
568be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
56981b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_LEGACY:
570be60a902SHaavard Skinnemoen #endif
571be60a902SHaavard Skinnemoen 		retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
572be60a902SHaavard Skinnemoen 		break;
573be60a902SHaavard Skinnemoen 	default:
574be60a902SHaavard Skinnemoen 		retval = 0;
575be60a902SHaavard Skinnemoen 	}
576be60a902SHaavard Skinnemoen 	debug ("flash_is_busy: %d\n", retval);
577be60a902SHaavard Skinnemoen 	return retval;
578be60a902SHaavard Skinnemoen }
579be60a902SHaavard Skinnemoen 
580be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
581be60a902SHaavard Skinnemoen  *  wait for XSR.7 to be set. Time out with an error if it does not.
582be60a902SHaavard Skinnemoen  *  This routine does not set the flash to read-array mode.
583be60a902SHaavard Skinnemoen  */
584be60a902SHaavard Skinnemoen static int flash_status_check (flash_info_t * info, flash_sect_t sector,
585be60a902SHaavard Skinnemoen 			       ulong tout, char *prompt)
586be60a902SHaavard Skinnemoen {
587be60a902SHaavard Skinnemoen 	ulong start;
588be60a902SHaavard Skinnemoen 
589be60a902SHaavard Skinnemoen #if CFG_HZ != 1000
590be60a902SHaavard Skinnemoen 	tout *= CFG_HZ/1000;
591be60a902SHaavard Skinnemoen #endif
592be60a902SHaavard Skinnemoen 
593be60a902SHaavard Skinnemoen 	/* Wait for command completion */
594be60a902SHaavard Skinnemoen 	start = get_timer (0);
595be60a902SHaavard Skinnemoen 	while (flash_is_busy (info, sector)) {
596be60a902SHaavard Skinnemoen 		if (get_timer (start) > tout) {
597be60a902SHaavard Skinnemoen 			printf ("Flash %s timeout at address %lx data %lx\n",
598be60a902SHaavard Skinnemoen 				prompt, info->start[sector],
599be60a902SHaavard Skinnemoen 				flash_read_long (info, sector, 0));
600be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0, info->cmd_reset);
601be60a902SHaavard Skinnemoen 			return ERR_TIMOUT;
602be60a902SHaavard Skinnemoen 		}
603be60a902SHaavard Skinnemoen 		udelay (1);		/* also triggers watchdog */
604be60a902SHaavard Skinnemoen 	}
605be60a902SHaavard Skinnemoen 	return ERR_OK;
606be60a902SHaavard Skinnemoen }
607be60a902SHaavard Skinnemoen 
608be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
609be60a902SHaavard Skinnemoen  * Wait for XSR.7 to be set, if it times out print an error, otherwise
610be60a902SHaavard Skinnemoen  * do a full status check.
611be60a902SHaavard Skinnemoen  *
612be60a902SHaavard Skinnemoen  * This routine sets the flash to read-array mode.
613be60a902SHaavard Skinnemoen  */
614be60a902SHaavard Skinnemoen static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
615be60a902SHaavard Skinnemoen 				    ulong tout, char *prompt)
616be60a902SHaavard Skinnemoen {
617be60a902SHaavard Skinnemoen 	int retcode;
618be60a902SHaavard Skinnemoen 
619be60a902SHaavard Skinnemoen 	retcode = flash_status_check (info, sector, tout, prompt);
620be60a902SHaavard Skinnemoen 	switch (info->vendor) {
621be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
622be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
623be60a902SHaavard Skinnemoen 		if ((retcode == ERR_OK)
624be60a902SHaavard Skinnemoen 		    && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
625be60a902SHaavard Skinnemoen 			retcode = ERR_INVAL;
626be60a902SHaavard Skinnemoen 			printf ("Flash %s error at address %lx\n", prompt,
627be60a902SHaavard Skinnemoen 				info->start[sector]);
628be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
629be60a902SHaavard Skinnemoen 					 FLASH_STATUS_PSLBS)) {
630be60a902SHaavard Skinnemoen 				puts ("Command Sequence Error.\n");
631be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
632be60a902SHaavard Skinnemoen 						FLASH_STATUS_ECLBS)) {
633be60a902SHaavard Skinnemoen 				puts ("Block Erase Error.\n");
634be60a902SHaavard Skinnemoen 				retcode = ERR_NOT_ERASED;
635be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
636be60a902SHaavard Skinnemoen 						FLASH_STATUS_PSLBS)) {
637be60a902SHaavard Skinnemoen 				puts ("Locking Error\n");
638be60a902SHaavard Skinnemoen 			}
639be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
640be60a902SHaavard Skinnemoen 				puts ("Block locked.\n");
641be60a902SHaavard Skinnemoen 				retcode = ERR_PROTECTED;
642be60a902SHaavard Skinnemoen 			}
643be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
644be60a902SHaavard Skinnemoen 				puts ("Vpp Low Error.\n");
645be60a902SHaavard Skinnemoen 		}
646be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, info->cmd_reset);
647be60a902SHaavard Skinnemoen 		break;
648be60a902SHaavard Skinnemoen 	default:
64981b20cccSMichael Schwingen 		break;
65081b20cccSMichael Schwingen 	}
651be60a902SHaavard Skinnemoen 	return retcode;
65281b20cccSMichael Schwingen }
653be60a902SHaavard Skinnemoen 
654be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
655be60a902SHaavard Skinnemoen  */
656be60a902SHaavard Skinnemoen static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
657be60a902SHaavard Skinnemoen {
658be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
659be60a902SHaavard Skinnemoen 	unsigned short	w;
660be60a902SHaavard Skinnemoen 	unsigned int	l;
661be60a902SHaavard Skinnemoen 	unsigned long long ll;
662be60a902SHaavard Skinnemoen #endif
663be60a902SHaavard Skinnemoen 
664be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
665be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
666be60a902SHaavard Skinnemoen 		cword->c = c;
667be60a902SHaavard Skinnemoen 		break;
668be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
669be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
670be60a902SHaavard Skinnemoen 		w = c;
671be60a902SHaavard Skinnemoen 		w <<= 8;
672be60a902SHaavard Skinnemoen 		cword->w = (cword->w >> 8) | w;
67381b20cccSMichael Schwingen #else
674be60a902SHaavard Skinnemoen 		cword->w = (cword->w << 8) | c;
675be60a902SHaavard Skinnemoen #endif
676be60a902SHaavard Skinnemoen 		break;
677be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
678be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
679be60a902SHaavard Skinnemoen 		l = c;
680be60a902SHaavard Skinnemoen 		l <<= 24;
681be60a902SHaavard Skinnemoen 		cword->l = (cword->l >> 8) | l;
682be60a902SHaavard Skinnemoen #else
683be60a902SHaavard Skinnemoen 		cword->l = (cword->l << 8) | c;
684be60a902SHaavard Skinnemoen #endif
685be60a902SHaavard Skinnemoen 		break;
686be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
687be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
688be60a902SHaavard Skinnemoen 		ll = c;
689be60a902SHaavard Skinnemoen 		ll <<= 56;
690be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll >> 8) | ll;
691be60a902SHaavard Skinnemoen #else
692be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll << 8) | c;
693be60a902SHaavard Skinnemoen #endif
694be60a902SHaavard Skinnemoen 		break;
695be60a902SHaavard Skinnemoen 	}
696be60a902SHaavard Skinnemoen }
697be60a902SHaavard Skinnemoen 
698be60a902SHaavard Skinnemoen /* loop through the sectors from the highest address when the passed
699be60a902SHaavard Skinnemoen  * address is greater or equal to the sector address we have a match
700be60a902SHaavard Skinnemoen  */
701be60a902SHaavard Skinnemoen static flash_sect_t find_sector (flash_info_t * info, ulong addr)
70281b20cccSMichael Schwingen {
703be60a902SHaavard Skinnemoen 	flash_sect_t sector;
704be60a902SHaavard Skinnemoen 
705be60a902SHaavard Skinnemoen 	for (sector = info->sector_count - 1; sector >= 0; sector--) {
706be60a902SHaavard Skinnemoen 		if (addr >= info->start[sector])
707be60a902SHaavard Skinnemoen 			break;
70881b20cccSMichael Schwingen 	}
709be60a902SHaavard Skinnemoen 	return sector;
71059829cc1SJean-Christophe PLAGNIOL-VILLARD }
71159829cc1SJean-Christophe PLAGNIOL-VILLARD 
71259829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
71359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
714be60a902SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest,
715be60a902SHaavard Skinnemoen 				cfiword_t cword)
71659829cc1SJean-Christophe PLAGNIOL-VILLARD {
717*cdbaefb5SHaavard Skinnemoen 	void *ctladdr;
718*cdbaefb5SHaavard Skinnemoen 	void *dstaddr;
719be60a902SHaavard Skinnemoen 	int flag;
72059829cc1SJean-Christophe PLAGNIOL-VILLARD 
721*cdbaefb5SHaavard Skinnemoen 	ctladdr = flash_make_addr (info, 0, 0);
722*cdbaefb5SHaavard Skinnemoen 	dstaddr = (uchar *)dest;
723be60a902SHaavard Skinnemoen 
724be60a902SHaavard Skinnemoen 	/* Check if Flash is (sufficiently) erased */
725be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
726be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
727*cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
728be60a902SHaavard Skinnemoen 		break;
729be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
730*cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
731be60a902SHaavard Skinnemoen 		break;
732be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
733*cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
734be60a902SHaavard Skinnemoen 		break;
735be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
736*cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
737be60a902SHaavard Skinnemoen 		break;
738be60a902SHaavard Skinnemoen 	default:
739be60a902SHaavard Skinnemoen 		return 2;
740be60a902SHaavard Skinnemoen 	}
741be60a902SHaavard Skinnemoen 	if (!flag)
742be60a902SHaavard Skinnemoen 		return 2;
743be60a902SHaavard Skinnemoen 
744be60a902SHaavard Skinnemoen 	/* Disable interrupts which might cause a timeout here */
745be60a902SHaavard Skinnemoen 	flag = disable_interrupts ();
746be60a902SHaavard Skinnemoen 
747be60a902SHaavard Skinnemoen 	switch (info->vendor) {
748be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
749be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
750be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
751be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
752be60a902SHaavard Skinnemoen 		break;
753be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
754be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
755be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
756be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_LEGACY:
757be60a902SHaavard Skinnemoen #endif
758be60a902SHaavard Skinnemoen 		flash_unlock_seq (info, 0);
759be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
76059829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
76159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
76259829cc1SJean-Christophe PLAGNIOL-VILLARD 
763be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
764be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
765*cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, dstaddr);
766be60a902SHaavard Skinnemoen 		break;
767be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
768*cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, dstaddr);
769be60a902SHaavard Skinnemoen 		break;
770be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
771*cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, dstaddr);
772be60a902SHaavard Skinnemoen 		break;
773be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
774*cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, dstaddr);
775be60a902SHaavard Skinnemoen 		break;
77659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
777be60a902SHaavard Skinnemoen 
778be60a902SHaavard Skinnemoen 	/* re-enable interrupts if necessary */
779be60a902SHaavard Skinnemoen 	if (flag)
780be60a902SHaavard Skinnemoen 		enable_interrupts ();
781be60a902SHaavard Skinnemoen 
782be60a902SHaavard Skinnemoen 	return flash_full_status_check (info, find_sector (info, dest),
783be60a902SHaavard Skinnemoen 					info->write_tout, "write");
784be60a902SHaavard Skinnemoen }
785be60a902SHaavard Skinnemoen 
786be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_USE_BUFFER_WRITE
787be60a902SHaavard Skinnemoen 
788be60a902SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
789be60a902SHaavard Skinnemoen 				  int len)
790be60a902SHaavard Skinnemoen {
791be60a902SHaavard Skinnemoen 	flash_sect_t sector;
792be60a902SHaavard Skinnemoen 	int cnt;
793be60a902SHaavard Skinnemoen 	int retcode;
794*cdbaefb5SHaavard Skinnemoen 	void *src = cp;
795*cdbaefb5SHaavard Skinnemoen 	void *dst = (void *)dest;
796*cdbaefb5SHaavard Skinnemoen 
797*cdbaefb5SHaavard Skinnemoen 	sector = find_sector (info, dest);
798be60a902SHaavard Skinnemoen 
799be60a902SHaavard Skinnemoen 	switch (info->vendor) {
800be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
801be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
802be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
803be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
804be60a902SHaavard Skinnemoen 		retcode = flash_status_check (info, sector,
805be60a902SHaavard Skinnemoen 					      info->buffer_write_tout,
806be60a902SHaavard Skinnemoen 					      "write to buffer");
807be60a902SHaavard Skinnemoen 		if (retcode == ERR_OK) {
808be60a902SHaavard Skinnemoen 			/* reduce the number of loops by the width of
809be60a902SHaavard Skinnemoen 			 * the port */
810be60a902SHaavard Skinnemoen 			switch (info->portwidth) {
811be60a902SHaavard Skinnemoen 			case FLASH_CFI_8BIT:
812be60a902SHaavard Skinnemoen 				cnt = len;
813be60a902SHaavard Skinnemoen 				break;
814be60a902SHaavard Skinnemoen 			case FLASH_CFI_16BIT:
815be60a902SHaavard Skinnemoen 				cnt = len >> 1;
816be60a902SHaavard Skinnemoen 				break;
817be60a902SHaavard Skinnemoen 			case FLASH_CFI_32BIT:
818be60a902SHaavard Skinnemoen 				cnt = len >> 2;
819be60a902SHaavard Skinnemoen 				break;
820be60a902SHaavard Skinnemoen 			case FLASH_CFI_64BIT:
821be60a902SHaavard Skinnemoen 				cnt = len >> 3;
822be60a902SHaavard Skinnemoen 				break;
823be60a902SHaavard Skinnemoen 			default:
824be60a902SHaavard Skinnemoen 				return ERR_INVAL;
825be60a902SHaavard Skinnemoen 				break;
826be60a902SHaavard Skinnemoen 			}
827be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
828be60a902SHaavard Skinnemoen 			while (cnt-- > 0) {
829be60a902SHaavard Skinnemoen 				switch (info->portwidth) {
830be60a902SHaavard Skinnemoen 				case FLASH_CFI_8BIT:
831*cdbaefb5SHaavard Skinnemoen 					flash_write8(flash_read8(src), dst);
832*cdbaefb5SHaavard Skinnemoen 					src += 1, dst += 1;
833be60a902SHaavard Skinnemoen 					break;
834be60a902SHaavard Skinnemoen 				case FLASH_CFI_16BIT:
835*cdbaefb5SHaavard Skinnemoen 					flash_write16(flash_read16(src), dst);
836*cdbaefb5SHaavard Skinnemoen 					src += 2, dst += 2;
837be60a902SHaavard Skinnemoen 					break;
838be60a902SHaavard Skinnemoen 				case FLASH_CFI_32BIT:
839*cdbaefb5SHaavard Skinnemoen 					flash_write32(flash_read32(src), dst);
840*cdbaefb5SHaavard Skinnemoen 					src += 4, dst += 4;
841be60a902SHaavard Skinnemoen 					break;
842be60a902SHaavard Skinnemoen 				case FLASH_CFI_64BIT:
843*cdbaefb5SHaavard Skinnemoen 					flash_write64(flash_read64(src), dst);
844*cdbaefb5SHaavard Skinnemoen 					src += 8, dst += 8;
845be60a902SHaavard Skinnemoen 					break;
846be60a902SHaavard Skinnemoen 				default:
847be60a902SHaavard Skinnemoen 					return ERR_INVAL;
848be60a902SHaavard Skinnemoen 					break;
849be60a902SHaavard Skinnemoen 				}
850be60a902SHaavard Skinnemoen 			}
851be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,
852be60a902SHaavard Skinnemoen 					 FLASH_CMD_WRITE_BUFFER_CONFIRM);
853be60a902SHaavard Skinnemoen 			retcode = flash_full_status_check (
854be60a902SHaavard Skinnemoen 				info, sector, info->buffer_write_tout,
855be60a902SHaavard Skinnemoen 				"buffer write");
856be60a902SHaavard Skinnemoen 		}
857be60a902SHaavard Skinnemoen 		return retcode;
858be60a902SHaavard Skinnemoen 
859be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
860be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
861be60a902SHaavard Skinnemoen 		flash_unlock_seq(info,0);
862be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER);
863be60a902SHaavard Skinnemoen 
864be60a902SHaavard Skinnemoen 		switch (info->portwidth) {
865be60a902SHaavard Skinnemoen 		case FLASH_CFI_8BIT:
866be60a902SHaavard Skinnemoen 			cnt = len;
867be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
868*cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
869*cdbaefb5SHaavard Skinnemoen 				flash_write8(flash_read8(src), dst);
870*cdbaefb5SHaavard Skinnemoen 				src += 1, dst += 1;
871*cdbaefb5SHaavard Skinnemoen 			}
872be60a902SHaavard Skinnemoen 			break;
873be60a902SHaavard Skinnemoen 		case FLASH_CFI_16BIT:
874be60a902SHaavard Skinnemoen 			cnt = len >> 1;
875be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
876*cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
877*cdbaefb5SHaavard Skinnemoen 				flash_write16(flash_read16(src), dst);
878*cdbaefb5SHaavard Skinnemoen 				src += 2, dst += 2;
879*cdbaefb5SHaavard Skinnemoen 			}
880be60a902SHaavard Skinnemoen 			break;
881be60a902SHaavard Skinnemoen 		case FLASH_CFI_32BIT:
882be60a902SHaavard Skinnemoen 			cnt = len >> 2;
883be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
884*cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
885*cdbaefb5SHaavard Skinnemoen 				flash_write32(flash_read32(src), dst);
886*cdbaefb5SHaavard Skinnemoen 				src += 4, dst += 4;
887*cdbaefb5SHaavard Skinnemoen 			}
888be60a902SHaavard Skinnemoen 			break;
889be60a902SHaavard Skinnemoen 		case FLASH_CFI_64BIT:
890be60a902SHaavard Skinnemoen 			cnt = len >> 3;
891be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
892*cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
893*cdbaefb5SHaavard Skinnemoen 				flash_write64(flash_read64(src), dst);
894*cdbaefb5SHaavard Skinnemoen 				src += 8, dst += 8;
895*cdbaefb5SHaavard Skinnemoen 			}
896be60a902SHaavard Skinnemoen 			break;
897be60a902SHaavard Skinnemoen 		default:
898be60a902SHaavard Skinnemoen 			return ERR_INVAL;
899be60a902SHaavard Skinnemoen 		}
900be60a902SHaavard Skinnemoen 
901be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
902be60a902SHaavard Skinnemoen 		retcode = flash_full_status_check (info, sector,
903be60a902SHaavard Skinnemoen 						   info->buffer_write_tout,
904be60a902SHaavard Skinnemoen 						   "buffer write");
905be60a902SHaavard Skinnemoen 		return retcode;
906be60a902SHaavard Skinnemoen 
907be60a902SHaavard Skinnemoen 	default:
908be60a902SHaavard Skinnemoen 		debug ("Unknown Command Set\n");
909be60a902SHaavard Skinnemoen 		return ERR_INVAL;
910be60a902SHaavard Skinnemoen 	}
911be60a902SHaavard Skinnemoen }
912be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_USE_BUFFER_WRITE */
913be60a902SHaavard Skinnemoen 
91459829cc1SJean-Christophe PLAGNIOL-VILLARD 
91559829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
91659829cc1SJean-Christophe PLAGNIOL-VILLARD  */
91759829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last)
91859829cc1SJean-Christophe PLAGNIOL-VILLARD {
91959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int rcode = 0;
92059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int prot;
92159829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect;
92259829cc1SJean-Christophe PLAGNIOL-VILLARD 
92359829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
92459829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("Can't erase unknown flash type - aborted\n");
92559829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
92659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
92759829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((s_first < 0) || (s_first > s_last)) {
92859829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("- no sectors to erase\n");
92959829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
93059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
93159829cc1SJean-Christophe PLAGNIOL-VILLARD 
93259829cc1SJean-Christophe PLAGNIOL-VILLARD 	prot = 0;
93359829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; ++sect) {
93459829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect]) {
93559829cc1SJean-Christophe PLAGNIOL-VILLARD 			prot++;
93659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
93759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
93859829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot) {
9397e5b9b47SHaavard Skinnemoen 		printf ("- Warning: %d protected sectors will not be erased!\n",
9407e5b9b47SHaavard Skinnemoen 			prot);
94159829cc1SJean-Christophe PLAGNIOL-VILLARD 	} else {
94259829cc1SJean-Christophe PLAGNIOL-VILLARD 		putc ('\n');
94359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
94459829cc1SJean-Christophe PLAGNIOL-VILLARD 
94559829cc1SJean-Christophe PLAGNIOL-VILLARD 
94659829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; sect++) {
94759829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect] == 0) { /* not protected */
94859829cc1SJean-Christophe PLAGNIOL-VILLARD 			switch (info->vendor) {
94959829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_STANDARD:
95059829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_EXTENDED:
9517e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
9527e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_CLEAR_STATUS);
9537e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
9547e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_BLOCK_ERASE);
9557e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
9567e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_ERASE_CONFIRM);
95759829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
95859829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_STANDARD:
95959829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_EXTENDED:
96059829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
9617e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect,
9627e5b9b47SHaavard Skinnemoen 						info->addr_unlock1,
9637e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
96459829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
9657e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
9667e5b9b47SHaavard Skinnemoen 						 AMD_CMD_ERASE_SECTOR);
96759829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
96881b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
96981b20cccSMichael Schwingen 			case CFI_CMDSET_AMD_LEGACY:
97081b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
9717e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, 0, info->addr_unlock1,
9727e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
97381b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
9747e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
9757e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_SECTOR);
97681b20cccSMichael Schwingen 				break;
97781b20cccSMichael Schwingen #endif
97859829cc1SJean-Christophe PLAGNIOL-VILLARD 			default:
97959829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug ("Unkown flash vendor %d\n",
98059829cc1SJean-Christophe PLAGNIOL-VILLARD 				       info->vendor);
98159829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
98259829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
98359829cc1SJean-Christophe PLAGNIOL-VILLARD 
98459829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_full_status_check
98559829cc1SJean-Christophe PLAGNIOL-VILLARD 			    (info, sect, info->erase_blk_tout, "erase")) {
98659829cc1SJean-Christophe PLAGNIOL-VILLARD 				rcode = 1;
98759829cc1SJean-Christophe PLAGNIOL-VILLARD 			} else
98859829cc1SJean-Christophe PLAGNIOL-VILLARD 				putc ('.');
98959829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
99059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
99159829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts (" done\n");
99259829cc1SJean-Christophe PLAGNIOL-VILLARD 	return rcode;
99359829cc1SJean-Christophe PLAGNIOL-VILLARD }
99459829cc1SJean-Christophe PLAGNIOL-VILLARD 
99559829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
99659829cc1SJean-Christophe PLAGNIOL-VILLARD  */
99759829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info)
99859829cc1SJean-Christophe PLAGNIOL-VILLARD {
99959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
100059829cc1SJean-Christophe PLAGNIOL-VILLARD 
100159829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
100259829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("missing or unknown FLASH type\n");
100359829cc1SJean-Christophe PLAGNIOL-VILLARD 		return;
100459829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
100559829cc1SJean-Christophe PLAGNIOL-VILLARD 
100681b20cccSMichael Schwingen 	printf ("%s FLASH (%d x %d)",
100781b20cccSMichael Schwingen 		info->name,
100859829cc1SJean-Christophe PLAGNIOL-VILLARD 		(info->portwidth << 3), (info->chipwidth << 3));
100981b20cccSMichael Schwingen 	if (info->size < 1024*1024)
101081b20cccSMichael Schwingen 		printf ("  Size: %ld kB in %d Sectors\n",
101181b20cccSMichael Schwingen 			info->size >> 10, info->sector_count);
101281b20cccSMichael Schwingen 	else
101359829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  Size: %ld MB in %d Sectors\n",
101459829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->size >> 20, info->sector_count);
101559829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("  ");
101659829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
101759829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
101859829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Standard");
101959829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
102059829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
102159829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Extended");
102259829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
102359829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
102459829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Standard");
102559829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
102659829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
102759829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Extended");
102859829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
102981b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
103081b20cccSMichael Schwingen 		case CFI_CMDSET_AMD_LEGACY:
103181b20cccSMichael Schwingen 			printf ("AMD Legacy");
103281b20cccSMichael Schwingen 			break;
103381b20cccSMichael Schwingen #endif
103459829cc1SJean-Christophe PLAGNIOL-VILLARD 		default:
103559829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Unknown (%d)", info->vendor);
103659829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
103759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
103859829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
103959829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->manufacturer_id, info->device_id);
104059829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->device_id == 0x7E) {
104159829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf("%04X", info->device_id2);
104259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
104359829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
104459829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->erase_blk_tout,
104559829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->write_tout);
104659829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->buffer_size > 1) {
10477e5b9b47SHaavard Skinnemoen 		printf ("  Buffer write timeout: %ld ms, "
10487e5b9b47SHaavard Skinnemoen 			"buffer size: %d bytes\n",
104959829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_write_tout,
105059829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_size);
105159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
105259829cc1SJean-Christophe PLAGNIOL-VILLARD 
105359829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts ("\n  Sector Start Addresses:");
105459829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < info->sector_count; ++i) {
105559829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((i % 5) == 0)
105659829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("\n");
105759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_EMPTY_INFO
105859829cc1SJean-Christophe PLAGNIOL-VILLARD 		int k;
105959829cc1SJean-Christophe PLAGNIOL-VILLARD 		int size;
106059829cc1SJean-Christophe PLAGNIOL-VILLARD 		int erased;
106159829cc1SJean-Christophe PLAGNIOL-VILLARD 		volatile unsigned long *flash;
106259829cc1SJean-Christophe PLAGNIOL-VILLARD 
106359829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
106459829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * Check if whole sector is erased
106559829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
106659829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (i != (info->sector_count - 1))
106759829cc1SJean-Christophe PLAGNIOL-VILLARD 			size = info->start[i + 1] - info->start[i];
106859829cc1SJean-Christophe PLAGNIOL-VILLARD 		else
106959829cc1SJean-Christophe PLAGNIOL-VILLARD 			size = info->start[0] + info->size - info->start[i];
107059829cc1SJean-Christophe PLAGNIOL-VILLARD 		erased = 1;
107159829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash = (volatile unsigned long *) info->start[i];
107259829cc1SJean-Christophe PLAGNIOL-VILLARD 		size = size >> 2;	/* divide by 4 for longword access */
107359829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (k = 0; k < size; k++) {
107459829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (*flash++ != 0xffffffff) {
107559829cc1SJean-Christophe PLAGNIOL-VILLARD 				erased = 0;
107659829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
107759829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
107859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
107959829cc1SJean-Christophe PLAGNIOL-VILLARD 
108059829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* print empty and read-only info */
108159829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX %c %s ",
108259829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
108359829cc1SJean-Christophe PLAGNIOL-VILLARD 			erased ? 'E' : ' ',
108459829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
108559829cc1SJean-Christophe PLAGNIOL-VILLARD #else	/* ! CFG_FLASH_EMPTY_INFO */
108659829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX   %s ",
108759829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
108859829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
108959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
109059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
109159829cc1SJean-Christophe PLAGNIOL-VILLARD 	putc ('\n');
109259829cc1SJean-Christophe PLAGNIOL-VILLARD 	return;
109359829cc1SJean-Christophe PLAGNIOL-VILLARD }
109459829cc1SJean-Christophe PLAGNIOL-VILLARD 
109559829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
109659829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copy memory to flash, returns:
109759829cc1SJean-Christophe PLAGNIOL-VILLARD  * 0 - OK
109859829cc1SJean-Christophe PLAGNIOL-VILLARD  * 1 - write timeout
109959829cc1SJean-Christophe PLAGNIOL-VILLARD  * 2 - Flash not erased
110059829cc1SJean-Christophe PLAGNIOL-VILLARD  */
110159829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
110259829cc1SJean-Christophe PLAGNIOL-VILLARD {
110359829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong wp;
110459829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong cp;
110559829cc1SJean-Christophe PLAGNIOL-VILLARD 	int aln;
110659829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
110759829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, rc;
110859829cc1SJean-Christophe PLAGNIOL-VILLARD 
110959829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
111059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int buffered_size;
111159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
111259829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* get lower aligned address */
111359829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* get lower aligned address */
111459829cc1SJean-Christophe PLAGNIOL-VILLARD 	wp = (addr & ~(info->portwidth - 1));
111559829cc1SJean-Christophe PLAGNIOL-VILLARD 
111659829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle unaligned start */
111759829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((aln = addr - wp) != 0) {
111859829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
111959829cc1SJean-Christophe PLAGNIOL-VILLARD 		cp = wp;
112059829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < aln; ++i, ++cp)
112159829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, (*(uchar *) cp));
112259829cc1SJean-Christophe PLAGNIOL-VILLARD 
112359829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (; (i < info->portwidth) && (cnt > 0); i++) {
112459829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
112559829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt--;
112659829cc1SJean-Christophe PLAGNIOL-VILLARD 			cp++;
112759829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
112859829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp)
112959829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, (*(uchar *) cp));
113059829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
113159829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
113259829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp = cp;
113359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
113459829cc1SJean-Christophe PLAGNIOL-VILLARD 
113559829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle the aligned part */
113659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
113759829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size = (info->portwidth / info->chipwidth);
113859829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size *= info->buffer_size;
113959829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
114059829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* prohibit buffer write when buffer_size is 1 */
114159829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->buffer_size == 1) {
114259829cc1SJean-Christophe PLAGNIOL-VILLARD 			cword.l = 0;
114359829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->portwidth; i++)
114459829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_add_byte (info, &cword, *src++);
114559829cc1SJean-Christophe PLAGNIOL-VILLARD 			if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
114659829cc1SJean-Christophe PLAGNIOL-VILLARD 				return rc;
114759829cc1SJean-Christophe PLAGNIOL-VILLARD 			wp += info->portwidth;
114859829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt -= info->portwidth;
114959829cc1SJean-Christophe PLAGNIOL-VILLARD 			continue;
115059829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
115159829cc1SJean-Christophe PLAGNIOL-VILLARD 
115259829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* write buffer until next buffered_size aligned boundary */
115359829cc1SJean-Christophe PLAGNIOL-VILLARD 		i = buffered_size - (wp % buffered_size);
115459829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (i > cnt)
115559829cc1SJean-Christophe PLAGNIOL-VILLARD 			i = cnt;
115659829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
115759829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
115859829cc1SJean-Christophe PLAGNIOL-VILLARD 		i -= i & (info->portwidth - 1);
115959829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += i;
116059829cc1SJean-Christophe PLAGNIOL-VILLARD 		src += i;
116159829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= i;
116259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
116359829cc1SJean-Christophe PLAGNIOL-VILLARD #else
116459829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
116559829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
116659829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < info->portwidth; i++) {
116759829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
116859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
116959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
117059829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
117159829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += info->portwidth;
117259829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= info->portwidth;
117359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
117459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */
117559829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (cnt == 0) {
117659829cc1SJean-Christophe PLAGNIOL-VILLARD 		return (0);
117759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
117859829cc1SJean-Christophe PLAGNIOL-VILLARD 
117959829cc1SJean-Christophe PLAGNIOL-VILLARD 	/*
118059829cc1SJean-Christophe PLAGNIOL-VILLARD 	 * handle unaligned tail bytes
118159829cc1SJean-Christophe PLAGNIOL-VILLARD 	 */
118259829cc1SJean-Christophe PLAGNIOL-VILLARD 	cword.l = 0;
118359829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) {
118459829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_add_byte (info, &cword, *src++);
118559829cc1SJean-Christophe PLAGNIOL-VILLARD 		--cnt;
118659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
118759829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (; i < info->portwidth; ++i, ++cp) {
118859829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_add_byte (info, &cword, (*(uchar *) cp));
118959829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
119059829cc1SJean-Christophe PLAGNIOL-VILLARD 
119159829cc1SJean-Christophe PLAGNIOL-VILLARD 	return flash_write_cfiword (info, wp, cword);
119259829cc1SJean-Christophe PLAGNIOL-VILLARD }
119359829cc1SJean-Christophe PLAGNIOL-VILLARD 
119459829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
119559829cc1SJean-Christophe PLAGNIOL-VILLARD  */
119659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
119759829cc1SJean-Christophe PLAGNIOL-VILLARD 
119859829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot)
119959829cc1SJean-Christophe PLAGNIOL-VILLARD {
120059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retcode = 0;
120159829cc1SJean-Christophe PLAGNIOL-VILLARD 
120259829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
120359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
120459829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot)
120559829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
120659829cc1SJean-Christophe PLAGNIOL-VILLARD 	else
120759829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
120859829cc1SJean-Christophe PLAGNIOL-VILLARD 
120959829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((retcode =
121059829cc1SJean-Christophe PLAGNIOL-VILLARD 	     flash_full_status_check (info, sector, info->erase_blk_tout,
121159829cc1SJean-Christophe PLAGNIOL-VILLARD 				      prot ? "protect" : "unprotect")) == 0) {
121259829cc1SJean-Christophe PLAGNIOL-VILLARD 
121359829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->protect[sector] = prot;
121459829cc1SJean-Christophe PLAGNIOL-VILLARD 
121559829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
121659829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * On some of Intel's flash chips (marked via legacy_unlock)
121759829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * unprotect unprotects all locking.
121859829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
121959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((prot == 0) && (info->legacy_unlock)) {
122059829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_sect_t i;
122159829cc1SJean-Christophe PLAGNIOL-VILLARD 
122259829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->sector_count; i++) {
122359829cc1SJean-Christophe PLAGNIOL-VILLARD 				if (info->protect[i])
122459829cc1SJean-Christophe PLAGNIOL-VILLARD 					flash_real_protect (info, i, 1);
122559829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
122659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
122759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
122859829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retcode;
122959829cc1SJean-Christophe PLAGNIOL-VILLARD }
123059829cc1SJean-Christophe PLAGNIOL-VILLARD 
123159829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
123259829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_user_serial - read the OneTimeProgramming cells
123359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
123459829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
123559829cc1SJean-Christophe PLAGNIOL-VILLARD 			     int len)
123659829cc1SJean-Christophe PLAGNIOL-VILLARD {
123759829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
123859829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *dst;
123959829cc1SJean-Christophe PLAGNIOL-VILLARD 
124059829cc1SJean-Christophe PLAGNIOL-VILLARD 	dst = buffer;
124159829cc1SJean-Christophe PLAGNIOL-VILLARD 	src = flash_make_addr (info, 0, FLASH_OFFSET_USER_PROTECTION);
124259829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
124359829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (dst, src + offset, len);
124459829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
124559829cc1SJean-Christophe PLAGNIOL-VILLARD }
124659829cc1SJean-Christophe PLAGNIOL-VILLARD 
124759829cc1SJean-Christophe PLAGNIOL-VILLARD /*
124859829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_factory_serial - read the device Id from the protection area
124959829cc1SJean-Christophe PLAGNIOL-VILLARD  */
125059829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
125159829cc1SJean-Christophe PLAGNIOL-VILLARD 				int len)
125259829cc1SJean-Christophe PLAGNIOL-VILLARD {
125359829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
125459829cc1SJean-Christophe PLAGNIOL-VILLARD 
125559829cc1SJean-Christophe PLAGNIOL-VILLARD 	src = flash_make_addr (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
125659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
125759829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (buffer, src + offset, len);
125859829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
125959829cc1SJean-Christophe PLAGNIOL-VILLARD }
126059829cc1SJean-Christophe PLAGNIOL-VILLARD 
126159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */
126259829cc1SJean-Christophe PLAGNIOL-VILLARD 
126359829cc1SJean-Christophe PLAGNIOL-VILLARD 
126459829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
126559829cc1SJean-Christophe PLAGNIOL-VILLARD  * read jedec ids from device and set corresponding fields in info struct
126659829cc1SJean-Christophe PLAGNIOL-VILLARD  *
126759829cc1SJean-Christophe PLAGNIOL-VILLARD  * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
126859829cc1SJean-Christophe PLAGNIOL-VILLARD  *
126959829cc1SJean-Christophe PLAGNIOL-VILLARD */
127059829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_read_jedec_ids (flash_info_t * info)
127159829cc1SJean-Christophe PLAGNIOL-VILLARD {
127259829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = 0;
127359829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id       = 0;
127459829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id2      = 0;
127559829cc1SJean-Christophe PLAGNIOL-VILLARD 
127659829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
127759829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_STANDARD:
127859829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_EXTENDED:
127959829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
128059829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
128159829cc1SJean-Christophe PLAGNIOL-VILLARD 		udelay(1000); /* some flash are slow to respond */
128259829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->manufacturer_id = flash_read_uchar (info,
128359829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_MANUFACTURER_ID);
128459829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id = flash_read_uchar (info,
128559829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID);
128659829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
128759829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
128859829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_AMD_STANDARD:
128959829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_AMD_EXTENDED:
129059829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
129159829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_unlock_seq(info, 0);
129281b20cccSMichael Schwingen 		flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
129359829cc1SJean-Christophe PLAGNIOL-VILLARD 		udelay(1000); /* some flash are slow to respond */
129459829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->manufacturer_id = flash_read_uchar (info,
129559829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_MANUFACTURER_ID);
129659829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id = flash_read_uchar (info,
129759829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID);
129859829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->device_id == 0x7E) {
129959829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* AMD 3-byte (expanded) device ids */
130059829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 = flash_read_uchar (info,
130159829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID2);
130259829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 <<= 8;
130359829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 |= flash_read_uchar (info,
130459829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID3);
130559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
130659829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
130759829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
130859829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
130959829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
131059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
131159829cc1SJean-Christophe PLAGNIOL-VILLARD }
131259829cc1SJean-Christophe PLAGNIOL-VILLARD 
1313be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
1314be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
1315be60a902SHaavard Skinnemoen  * Call board code to request info about non-CFI flash.
1316be60a902SHaavard Skinnemoen  * board_flash_get_legacy needs to fill in at least:
1317be60a902SHaavard Skinnemoen  * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1318be60a902SHaavard Skinnemoen  */
1319be60a902SHaavard Skinnemoen static int flash_detect_legacy(ulong base, int banknum)
1320be60a902SHaavard Skinnemoen {
1321be60a902SHaavard Skinnemoen 	flash_info_t *info = &flash_info[banknum];
1322be60a902SHaavard Skinnemoen 
1323be60a902SHaavard Skinnemoen 	if (board_flash_get_legacy(base, banknum, info)) {
1324be60a902SHaavard Skinnemoen 		/* board code may have filled info completely. If not, we
1325be60a902SHaavard Skinnemoen 		   use JEDEC ID probing. */
1326be60a902SHaavard Skinnemoen 		if (!info->vendor) {
1327be60a902SHaavard Skinnemoen 			int modes[] = {
1328be60a902SHaavard Skinnemoen 				CFI_CMDSET_AMD_STANDARD,
1329be60a902SHaavard Skinnemoen 				CFI_CMDSET_INTEL_STANDARD
1330be60a902SHaavard Skinnemoen 			};
1331be60a902SHaavard Skinnemoen 			int i;
1332be60a902SHaavard Skinnemoen 
1333be60a902SHaavard Skinnemoen 			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1334be60a902SHaavard Skinnemoen 				info->vendor = modes[i];
1335be60a902SHaavard Skinnemoen 				info->start[0] = base;
1336be60a902SHaavard Skinnemoen 				if (info->portwidth == FLASH_CFI_8BIT
1337be60a902SHaavard Skinnemoen 					&& info->interface == FLASH_CFI_X8X16) {
1338be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x2AAA;
1339be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x5555;
1340be60a902SHaavard Skinnemoen 				} else {
1341be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x5555;
1342be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x2AAA;
1343be60a902SHaavard Skinnemoen 				}
1344be60a902SHaavard Skinnemoen 				flash_read_jedec_ids(info);
1345be60a902SHaavard Skinnemoen 				debug("JEDEC PROBE: ID %x %x %x\n",
1346be60a902SHaavard Skinnemoen 						info->manufacturer_id,
1347be60a902SHaavard Skinnemoen 						info->device_id,
1348be60a902SHaavard Skinnemoen 						info->device_id2);
1349be60a902SHaavard Skinnemoen 				if (jedec_flash_match(info, base))
1350be60a902SHaavard Skinnemoen 					break;
1351be60a902SHaavard Skinnemoen 			}
1352be60a902SHaavard Skinnemoen 		}
1353be60a902SHaavard Skinnemoen 
1354be60a902SHaavard Skinnemoen 		switch(info->vendor) {
1355be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_STANDARD:
1356be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_EXTENDED:
1357be60a902SHaavard Skinnemoen 			info->cmd_reset = FLASH_CMD_RESET;
1358be60a902SHaavard Skinnemoen 			break;
1359be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_STANDARD:
1360be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_EXTENDED:
1361be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_LEGACY:
1362be60a902SHaavard Skinnemoen 			info->cmd_reset = AMD_CMD_RESET;
1363be60a902SHaavard Skinnemoen 			break;
1364be60a902SHaavard Skinnemoen 		}
1365be60a902SHaavard Skinnemoen 		info->flash_id = FLASH_MAN_CFI;
1366be60a902SHaavard Skinnemoen 		return 1;
1367be60a902SHaavard Skinnemoen 	}
1368be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1369be60a902SHaavard Skinnemoen }
1370be60a902SHaavard Skinnemoen #else
1371be60a902SHaavard Skinnemoen static inline int flash_detect_legacy(ulong base, int banknum)
1372be60a902SHaavard Skinnemoen {
1373be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1374be60a902SHaavard Skinnemoen }
1375be60a902SHaavard Skinnemoen #endif
1376be60a902SHaavard Skinnemoen 
137759829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
137859829cc1SJean-Christophe PLAGNIOL-VILLARD  * detect if flash is compatible with the Common Flash Interface (CFI)
137959829cc1SJean-Christophe PLAGNIOL-VILLARD  * http://www.jedec.org/download/search/jesd68.pdf
138059829cc1SJean-Christophe PLAGNIOL-VILLARD  */
13817e5b9b47SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info)
138259829cc1SJean-Christophe PLAGNIOL-VILLARD {
138359829cc1SJean-Christophe PLAGNIOL-VILLARD 	int cfi_offset;
138459829cc1SJean-Christophe PLAGNIOL-VILLARD 
138559829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
13867e5b9b47SHaavard Skinnemoen 	for (cfi_offset=0;
13877e5b9b47SHaavard Skinnemoen 	     cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
13887e5b9b47SHaavard Skinnemoen 	     cfi_offset++) {
13897e5b9b47SHaavard Skinnemoen 		flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
13907e5b9b47SHaavard Skinnemoen 				 FLASH_CMD_CFI);
139159829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
139259829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
139359829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
13947e5b9b47SHaavard Skinnemoen 			info->interface	= flash_read_ushort (info, 0,
13957e5b9b47SHaavard Skinnemoen 						FLASH_OFFSET_INTERFACE);
139659829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_offset = flash_offset_cfi[cfi_offset];
139759829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("device interface is %d\n",
139859829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->interface);
139959829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("found port %d chip %d ",
140059829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth, info->chipwidth);
140159829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("port %d bits chip %d bits\n",
140259829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth << CFI_FLASH_SHIFT_WIDTH,
140359829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
140442026c9cSBartlomiej Sieka 
140542026c9cSBartlomiej Sieka 			/* calculate command offsets as in the Linux driver */
140642026c9cSBartlomiej Sieka 			info->addr_unlock1 = 0x555;
140742026c9cSBartlomiej Sieka 			info->addr_unlock2 = 0x2aa;
140842026c9cSBartlomiej Sieka 
140942026c9cSBartlomiej Sieka 			/*
141042026c9cSBartlomiej Sieka 			 * modify the unlock address if we are
141142026c9cSBartlomiej Sieka 			 * in compatibility mode
141242026c9cSBartlomiej Sieka 			 */
141342026c9cSBartlomiej Sieka 			if (	/* x8/x16 in x8 mode */
141442026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY8) &&
141542026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X8X16)) ||
141642026c9cSBartlomiej Sieka 				/* x16/x32 in x16 mode */
141742026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY16) &&
141842026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X16X32)))
141942026c9cSBartlomiej Sieka 			{
142042026c9cSBartlomiej Sieka 				info->addr_unlock1 = 0xaaa;
142142026c9cSBartlomiej Sieka 				info->addr_unlock2 = 0x555;
142242026c9cSBartlomiej Sieka 			}
142342026c9cSBartlomiej Sieka 
142481b20cccSMichael Schwingen 			info->name = "CFI conformant";
142559829cc1SJean-Christophe PLAGNIOL-VILLARD 			return 1;
142659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
142759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
14287e5b9b47SHaavard Skinnemoen 
14297e5b9b47SHaavard Skinnemoen 	return 0;
143059829cc1SJean-Christophe PLAGNIOL-VILLARD }
14317e5b9b47SHaavard Skinnemoen 
14327e5b9b47SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info)
14337e5b9b47SHaavard Skinnemoen {
14347e5b9b47SHaavard Skinnemoen 	debug ("flash detect cfi\n");
14357e5b9b47SHaavard Skinnemoen 
14367e5b9b47SHaavard Skinnemoen 	for (info->portwidth = CFG_FLASH_CFI_WIDTH;
14377e5b9b47SHaavard Skinnemoen 	     info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
14387e5b9b47SHaavard Skinnemoen 		for (info->chipwidth = FLASH_CFI_BY8;
14397e5b9b47SHaavard Skinnemoen 		     info->chipwidth <= info->portwidth;
14407e5b9b47SHaavard Skinnemoen 		     info->chipwidth <<= 1)
14417e5b9b47SHaavard Skinnemoen 			if (__flash_detect_cfi(info))
14427e5b9b47SHaavard Skinnemoen 				return 1;
144359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
144459829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("not found\n");
144559829cc1SJean-Christophe PLAGNIOL-VILLARD 	return 0;
144659829cc1SJean-Christophe PLAGNIOL-VILLARD }
144759829cc1SJean-Christophe PLAGNIOL-VILLARD 
144859829cc1SJean-Christophe PLAGNIOL-VILLARD /*
144959829cc1SJean-Christophe PLAGNIOL-VILLARD  * The following code cannot be run from FLASH!
145059829cc1SJean-Christophe PLAGNIOL-VILLARD  *
145159829cc1SJean-Christophe PLAGNIOL-VILLARD  */
145259829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum)
145359829cc1SJean-Christophe PLAGNIOL-VILLARD {
145459829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_info_t *info = &flash_info[banknum];
145559829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, j;
145659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect_cnt;
145759829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long sector;
145859829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long tmp;
145959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int size_ratio;
146059829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar num_erase_regions;
146159829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_size;
146259829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_count;
146359829cc1SJean-Christophe PLAGNIOL-VILLARD 	int geometry_reversed = 0;
146459829cc1SJean-Christophe PLAGNIOL-VILLARD 
146559829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->ext_addr = 0;
146659829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->cfi_version = 0;
146759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
146859829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->legacy_unlock = 0;
146959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
147059829cc1SJean-Christophe PLAGNIOL-VILLARD 
147159829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->start[0] = base;
147259829cc1SJean-Christophe PLAGNIOL-VILLARD 
147359829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (flash_detect_cfi (info)) {
147459829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->vendor = flash_read_ushort (info, 0,
147559829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_PRIMARY_VENDOR);
147659829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_read_jedec_ids (info);
147759829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, 0, info->cfi_offset, FLASH_CMD_CFI);
147859829cc1SJean-Christophe PLAGNIOL-VILLARD 		num_erase_regions = flash_read_uchar (info,
147959829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_NUM_ERASE_REGIONS);
148059829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->ext_addr = flash_read_ushort (info, 0,
148159829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_EXT_QUERY_T_P_ADDR);
148259829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->ext_addr) {
148359829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version = (ushort) flash_read_uchar (info,
148459829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 3) << 8;
148559829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version |= (ushort) flash_read_uchar (info,
148659829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 4);
148759829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
148859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
148959829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_printqry (info, 0);
149059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
149159829cc1SJean-Christophe PLAGNIOL-VILLARD 		switch (info->vendor) {
149259829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
149359829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
149459829cc1SJean-Christophe PLAGNIOL-VILLARD 		default:
149559829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cmd_reset = FLASH_CMD_RESET;
149659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
149759829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* read legacy lock/unlock bit from intel flash */
149859829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (info->ext_addr) {
149959829cc1SJean-Christophe PLAGNIOL-VILLARD 				info->legacy_unlock = flash_read_uchar (info,
150059829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 5) & 0x08;
150159829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
150259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
150359829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
150459829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
150559829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
150659829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cmd_reset = AMD_CMD_RESET;
150759829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* check if flash geometry needs reversal */
150859829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (num_erase_regions <= 1)
150959829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
151059829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* reverse geometry if top boot part */
151159829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (info->cfi_version < 0x3131) {
151259829cc1SJean-Christophe PLAGNIOL-VILLARD 				/* CFI < 1.1, try to guess from device id */
151359829cc1SJean-Christophe PLAGNIOL-VILLARD 				if ((info->device_id & 0x80) != 0) {
151459829cc1SJean-Christophe PLAGNIOL-VILLARD 					geometry_reversed = 1;
151559829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
151659829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
151759829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
151859829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* CFI >= 1.1, deduct from top/bottom flag */
151959829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* note: ext_addr is valid since cfi_version > 0 */
152059829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
152159829cc1SJean-Christophe PLAGNIOL-VILLARD 				geometry_reversed = 1;
152259829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
152359829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
152459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
152559829cc1SJean-Christophe PLAGNIOL-VILLARD 
152659829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer is %d\n", info->vendor);
152759829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
152859829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id is 0x%x\n", info->device_id);
152959829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id2 is 0x%x\n", info->device_id2);
153059829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("cfi version is 0x%04x\n", info->cfi_version);
153159829cc1SJean-Christophe PLAGNIOL-VILLARD 
153259829cc1SJean-Christophe PLAGNIOL-VILLARD 		size_ratio = info->portwidth / info->chipwidth;
153359829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* if the chip is x8/x16 reduce the ratio by half */
153459829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((info->interface == FLASH_CFI_X8X16)
153559829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && (info->chipwidth == FLASH_CFI_BY8)) {
153659829cc1SJean-Christophe PLAGNIOL-VILLARD 			size_ratio >>= 1;
153759829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
153859829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("size_ratio %d port %d bits chip %d bits\n",
153959829cc1SJean-Christophe PLAGNIOL-VILLARD 		       size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
154059829cc1SJean-Christophe PLAGNIOL-VILLARD 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
154159829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("found %d erase regions\n", num_erase_regions);
154259829cc1SJean-Christophe PLAGNIOL-VILLARD 		sect_cnt = 0;
154359829cc1SJean-Christophe PLAGNIOL-VILLARD 		sector = base;
154459829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < num_erase_regions; i++) {
154559829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (i > NUM_ERASE_REGIONS) {
154659829cc1SJean-Christophe PLAGNIOL-VILLARD 				printf ("%d erase regions found, only %d used\n",
154759829cc1SJean-Christophe PLAGNIOL-VILLARD 					num_erase_regions, NUM_ERASE_REGIONS);
154859829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
154959829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
155059829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (geometry_reversed)
155159829cc1SJean-Christophe PLAGNIOL-VILLARD 				tmp = flash_read_long (info, 0,
155259829cc1SJean-Christophe PLAGNIOL-VILLARD 					       FLASH_OFFSET_ERASE_REGIONS +
155359829cc1SJean-Christophe PLAGNIOL-VILLARD 					       (num_erase_regions - 1 - i) * 4);
155459829cc1SJean-Christophe PLAGNIOL-VILLARD 			else
155559829cc1SJean-Christophe PLAGNIOL-VILLARD 				tmp = flash_read_long (info, 0,
155659829cc1SJean-Christophe PLAGNIOL-VILLARD 					       FLASH_OFFSET_ERASE_REGIONS +
155759829cc1SJean-Christophe PLAGNIOL-VILLARD 					       i * 4);
155859829cc1SJean-Christophe PLAGNIOL-VILLARD 			erase_region_size =
155959829cc1SJean-Christophe PLAGNIOL-VILLARD 				(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
156059829cc1SJean-Christophe PLAGNIOL-VILLARD 			tmp >>= 16;
156159829cc1SJean-Christophe PLAGNIOL-VILLARD 			erase_region_count = (tmp & 0xffff) + 1;
156259829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("erase_region_count = %d erase_region_size = %d\n",
156359829cc1SJean-Christophe PLAGNIOL-VILLARD 				erase_region_count, erase_region_size);
156459829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (j = 0; j < erase_region_count; j++) {
156581b20cccSMichael Schwingen 				if (sect_cnt >= CFG_MAX_FLASH_SECT) {
156681b20cccSMichael Schwingen 					printf("ERROR: too many flash sectors\n");
156781b20cccSMichael Schwingen 					break;
156881b20cccSMichael Schwingen 				}
156959829cc1SJean-Christophe PLAGNIOL-VILLARD 				info->start[sect_cnt] = sector;
157059829cc1SJean-Christophe PLAGNIOL-VILLARD 				sector += (erase_region_size * size_ratio);
157159829cc1SJean-Christophe PLAGNIOL-VILLARD 
157259829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
15737e5b9b47SHaavard Skinnemoen 				 * Only read protection status from
15747e5b9b47SHaavard Skinnemoen 				 * supported devices (intel...)
157559829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
157659829cc1SJean-Christophe PLAGNIOL-VILLARD 				switch (info->vendor) {
157759829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_EXTENDED:
157859829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_STANDARD:
157959829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->protect[sect_cnt] =
158059829cc1SJean-Christophe PLAGNIOL-VILLARD 						flash_isset (info, sect_cnt,
158159829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_OFFSET_PROTECT,
158259829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_STATUS_PROTECT);
158359829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
158459829cc1SJean-Christophe PLAGNIOL-VILLARD 				default:
15857e5b9b47SHaavard Skinnemoen 					/* default: not protected */
15867e5b9b47SHaavard Skinnemoen 					info->protect[sect_cnt] = 0;
158759829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
158859829cc1SJean-Christophe PLAGNIOL-VILLARD 
158959829cc1SJean-Christophe PLAGNIOL-VILLARD 				sect_cnt++;
159059829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
159159829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
159259829cc1SJean-Christophe PLAGNIOL-VILLARD 
159359829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->sector_count = sect_cnt;
15947e5b9b47SHaavard Skinnemoen 		info->size = 1 << flash_read_uchar (info, FLASH_OFFSET_SIZE);
159559829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* multiply the size by the number of chips */
15967e5b9b47SHaavard Skinnemoen 		info->size *= size_ratio;
15977e5b9b47SHaavard Skinnemoen 		info->buffer_size = 1 << flash_read_ushort (info, 0,
15987e5b9b47SHaavard Skinnemoen 						FLASH_OFFSET_BUFFER_SIZE);
159959829cc1SJean-Christophe PLAGNIOL-VILLARD 		tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT);
16007e5b9b47SHaavard Skinnemoen 		info->erase_blk_tout = tmp *
16017e5b9b47SHaavard Skinnemoen 			(1 << flash_read_uchar (
16027e5b9b47SHaavard Skinnemoen 				 info, FLASH_OFFSET_EMAX_TOUT));
160359829cc1SJean-Christophe PLAGNIOL-VILLARD 		tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT)) *
160459829cc1SJean-Christophe PLAGNIOL-VILLARD 			(1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT));
16057e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
16067e5b9b47SHaavard Skinnemoen 		info->buffer_write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0);
160759829cc1SJean-Christophe PLAGNIOL-VILLARD 		tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT)) *
160859829cc1SJean-Christophe PLAGNIOL-VILLARD 		      (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT));
16097e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
16107e5b9b47SHaavard Skinnemoen 		info->write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0);
161159829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->flash_id = FLASH_MAN_CFI;
16127e5b9b47SHaavard Skinnemoen 		if ((info->interface == FLASH_CFI_X8X16) &&
16137e5b9b47SHaavard Skinnemoen 		    (info->chipwidth == FLASH_CFI_BY8)) {
16147e5b9b47SHaavard Skinnemoen 			/* XXX - Need to test on x8/x16 in parallel. */
16157e5b9b47SHaavard Skinnemoen 			info->portwidth >>= 1;
161659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
161759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
161859829cc1SJean-Christophe PLAGNIOL-VILLARD 
161959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
162059829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (info->size);
162159829cc1SJean-Christophe PLAGNIOL-VILLARD }
162259829cc1SJean-Christophe PLAGNIOL-VILLARD 
162359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
162459829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1625be60a902SHaavard Skinnemoen unsigned long flash_init (void)
162659829cc1SJean-Christophe PLAGNIOL-VILLARD {
1627be60a902SHaavard Skinnemoen 	unsigned long size = 0;
1628be60a902SHaavard Skinnemoen 	int i;
162959829cc1SJean-Christophe PLAGNIOL-VILLARD 
1630be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION
1631be60a902SHaavard Skinnemoen 	char *s = getenv("unlock");
163281b20cccSMichael Schwingen #endif
1633be60a902SHaavard Skinnemoen 
1634be60a902SHaavard Skinnemoen 	/* Init: no FLASHes known */
1635be60a902SHaavard Skinnemoen 	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
1636be60a902SHaavard Skinnemoen 		flash_info[i].flash_id = FLASH_UNKNOWN;
1637be60a902SHaavard Skinnemoen 
1638be60a902SHaavard Skinnemoen 		if (!flash_detect_legacy (bank_base[i], i))
1639be60a902SHaavard Skinnemoen 			flash_get_size (bank_base[i], i);
1640be60a902SHaavard Skinnemoen 		size += flash_info[i].size;
1641be60a902SHaavard Skinnemoen 		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
1642be60a902SHaavard Skinnemoen #ifndef CFG_FLASH_QUIET_TEST
1643be60a902SHaavard Skinnemoen 			printf ("## Unknown FLASH on Bank %d "
1644be60a902SHaavard Skinnemoen 				"- Size = 0x%08lx = %ld MB\n",
1645be60a902SHaavard Skinnemoen 				i+1, flash_info[i].size,
1646be60a902SHaavard Skinnemoen 				flash_info[i].size << 20);
1647be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_QUIET_TEST */
164859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1649be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION
1650be60a902SHaavard Skinnemoen 		else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
1651be60a902SHaavard Skinnemoen 			/*
1652be60a902SHaavard Skinnemoen 			 * Only the U-Boot image and it's environment
1653be60a902SHaavard Skinnemoen 			 * is protected, all other sectors are
1654be60a902SHaavard Skinnemoen 			 * unprotected (unlocked) if flash hardware
1655be60a902SHaavard Skinnemoen 			 * protection is used (CFG_FLASH_PROTECTION)
1656be60a902SHaavard Skinnemoen 			 * and the environment variable "unlock" is
1657be60a902SHaavard Skinnemoen 			 * set to "yes".
1658be60a902SHaavard Skinnemoen 			 */
1659be60a902SHaavard Skinnemoen 			if (flash_info[i].legacy_unlock) {
1660be60a902SHaavard Skinnemoen 				int k;
166159829cc1SJean-Christophe PLAGNIOL-VILLARD 
1662be60a902SHaavard Skinnemoen 				/*
1663be60a902SHaavard Skinnemoen 				 * Disable legacy_unlock temporarily,
1664be60a902SHaavard Skinnemoen 				 * since flash_real_protect would
1665be60a902SHaavard Skinnemoen 				 * relock all other sectors again
1666be60a902SHaavard Skinnemoen 				 * otherwise.
1667be60a902SHaavard Skinnemoen 				 */
1668be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 0;
166959829cc1SJean-Christophe PLAGNIOL-VILLARD 
1670be60a902SHaavard Skinnemoen 				/*
1671be60a902SHaavard Skinnemoen 				 * Legacy unlocking (e.g. Intel J3) ->
1672be60a902SHaavard Skinnemoen 				 * unlock only one sector. This will
1673be60a902SHaavard Skinnemoen 				 * unlock all sectors.
1674be60a902SHaavard Skinnemoen 				 */
1675be60a902SHaavard Skinnemoen 				flash_real_protect (&flash_info[i], 0, 0);
167659829cc1SJean-Christophe PLAGNIOL-VILLARD 
1677be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 1;
167859829cc1SJean-Christophe PLAGNIOL-VILLARD 
1679be60a902SHaavard Skinnemoen 				/*
1680be60a902SHaavard Skinnemoen 				 * Manually mark other sectors as
1681be60a902SHaavard Skinnemoen 				 * unlocked (unprotected)
1682be60a902SHaavard Skinnemoen 				 */
1683be60a902SHaavard Skinnemoen 				for (k = 1; k < flash_info[i].sector_count; k++)
1684be60a902SHaavard Skinnemoen 					flash_info[i].protect[k] = 0;
1685be60a902SHaavard Skinnemoen 			} else {
1686be60a902SHaavard Skinnemoen 				/*
1687be60a902SHaavard Skinnemoen 				 * No legancy unlocking -> unlock all sectors
1688be60a902SHaavard Skinnemoen 				 */
1689be60a902SHaavard Skinnemoen 				flash_protect (FLAG_PROTECT_CLEAR,
1690be60a902SHaavard Skinnemoen 					       flash_info[i].start[0],
1691be60a902SHaavard Skinnemoen 					       flash_info[i].start[0]
1692be60a902SHaavard Skinnemoen 					       + flash_info[i].size - 1,
1693be60a902SHaavard Skinnemoen 					       &flash_info[i]);
169459829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
169559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1696be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_PROTECTION */
169759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
169859829cc1SJean-Christophe PLAGNIOL-VILLARD 
1699be60a902SHaavard Skinnemoen 	/* Monitor protection ON by default */
1700be60a902SHaavard Skinnemoen #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
1701be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
1702be60a902SHaavard Skinnemoen 		       CFG_MONITOR_BASE,
1703be60a902SHaavard Skinnemoen 		       CFG_MONITOR_BASE + monitor_flash_len  - 1,
1704be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_MONITOR_BASE));
1705be60a902SHaavard Skinnemoen #endif
170659829cc1SJean-Christophe PLAGNIOL-VILLARD 
1707be60a902SHaavard Skinnemoen 	/* Environment protection ON by default */
1708be60a902SHaavard Skinnemoen #ifdef CFG_ENV_IS_IN_FLASH
1709be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
1710be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR,
1711be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
1712be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_ENV_ADDR));
1713be60a902SHaavard Skinnemoen #endif
1714be60a902SHaavard Skinnemoen 
1715be60a902SHaavard Skinnemoen 	/* Redundant environment protection ON by default */
1716be60a902SHaavard Skinnemoen #ifdef CFG_ENV_ADDR_REDUND
1717be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
1718be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR_REDUND,
1719be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
1720be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_ENV_ADDR_REDUND));
1721be60a902SHaavard Skinnemoen #endif
1722be60a902SHaavard Skinnemoen 	return (size);
172359829cc1SJean-Christophe PLAGNIOL-VILLARD }
172459829cc1SJean-Christophe PLAGNIOL-VILLARD 
172559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_CFI */
1726