xref: /rk3399_rockchip-uboot/drivers/mtd/cfi_flash.c (revision 9a042e9ca512beaaa2cb450274313fc477141241)
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 
174e23741f4SHaavard Skinnemoen /* CFI standard query structure */
175e23741f4SHaavard Skinnemoen struct cfi_qry {
176e23741f4SHaavard Skinnemoen 	u8	qry[3];
177e23741f4SHaavard Skinnemoen 	u16	p_id;
178e23741f4SHaavard Skinnemoen 	u16	p_adr;
179e23741f4SHaavard Skinnemoen 	u16	a_id;
180e23741f4SHaavard Skinnemoen 	u16	a_adr;
181e23741f4SHaavard Skinnemoen 	u8	vcc_min;
182e23741f4SHaavard Skinnemoen 	u8	vcc_max;
183e23741f4SHaavard Skinnemoen 	u8	vpp_min;
184e23741f4SHaavard Skinnemoen 	u8	vpp_max;
185e23741f4SHaavard Skinnemoen 	u8	word_write_timeout_typ;
186e23741f4SHaavard Skinnemoen 	u8	buf_write_timeout_typ;
187e23741f4SHaavard Skinnemoen 	u8	block_erase_timeout_typ;
188e23741f4SHaavard Skinnemoen 	u8	chip_erase_timeout_typ;
189e23741f4SHaavard Skinnemoen 	u8	word_write_timeout_max;
190e23741f4SHaavard Skinnemoen 	u8	buf_write_timeout_max;
191e23741f4SHaavard Skinnemoen 	u8	block_erase_timeout_max;
192e23741f4SHaavard Skinnemoen 	u8	chip_erase_timeout_max;
193e23741f4SHaavard Skinnemoen 	u8	dev_size;
194e23741f4SHaavard Skinnemoen 	u16	interface_desc;
195e23741f4SHaavard Skinnemoen 	u16	max_buf_write_size;
196e23741f4SHaavard Skinnemoen 	u8	num_erase_regions;
197e23741f4SHaavard Skinnemoen 	u32	erase_region_info[NUM_ERASE_REGIONS];
198e23741f4SHaavard Skinnemoen } __attribute__((packed));
199e23741f4SHaavard Skinnemoen 
200e23741f4SHaavard Skinnemoen struct cfi_pri_hdr {
201e23741f4SHaavard Skinnemoen 	u8	pri[3];
202e23741f4SHaavard Skinnemoen 	u8	major_version;
203e23741f4SHaavard Skinnemoen 	u8	minor_version;
204e23741f4SHaavard Skinnemoen } __attribute__((packed));
205e23741f4SHaavard Skinnemoen 
206cdbaefb5SHaavard Skinnemoen static void flash_write8(u8 value, void *addr)
207cdbaefb5SHaavard Skinnemoen {
208cdbaefb5SHaavard Skinnemoen 	__raw_writeb(value, addr);
209cdbaefb5SHaavard Skinnemoen }
210cdbaefb5SHaavard Skinnemoen 
211cdbaefb5SHaavard Skinnemoen static void flash_write16(u16 value, void *addr)
212cdbaefb5SHaavard Skinnemoen {
213cdbaefb5SHaavard Skinnemoen 	__raw_writew(value, addr);
214cdbaefb5SHaavard Skinnemoen }
215cdbaefb5SHaavard Skinnemoen 
216cdbaefb5SHaavard Skinnemoen static void flash_write32(u32 value, void *addr)
217cdbaefb5SHaavard Skinnemoen {
218cdbaefb5SHaavard Skinnemoen 	__raw_writel(value, addr);
219cdbaefb5SHaavard Skinnemoen }
220cdbaefb5SHaavard Skinnemoen 
221cdbaefb5SHaavard Skinnemoen static void flash_write64(u64 value, void *addr)
222cdbaefb5SHaavard Skinnemoen {
223cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_writeq() */
224cdbaefb5SHaavard Skinnemoen 	*(volatile u64 *)addr = value;
225cdbaefb5SHaavard Skinnemoen }
226cdbaefb5SHaavard Skinnemoen 
227cdbaefb5SHaavard Skinnemoen static u8 flash_read8(void *addr)
228cdbaefb5SHaavard Skinnemoen {
229cdbaefb5SHaavard Skinnemoen 	return __raw_readb(addr);
230cdbaefb5SHaavard Skinnemoen }
231cdbaefb5SHaavard Skinnemoen 
232cdbaefb5SHaavard Skinnemoen static u16 flash_read16(void *addr)
233cdbaefb5SHaavard Skinnemoen {
234cdbaefb5SHaavard Skinnemoen 	return __raw_readw(addr);
235cdbaefb5SHaavard Skinnemoen }
236cdbaefb5SHaavard Skinnemoen 
237cdbaefb5SHaavard Skinnemoen static u32 flash_read32(void *addr)
238cdbaefb5SHaavard Skinnemoen {
239cdbaefb5SHaavard Skinnemoen 	return __raw_readl(addr);
240cdbaefb5SHaavard Skinnemoen }
241cdbaefb5SHaavard Skinnemoen 
242cdbaefb5SHaavard Skinnemoen static u64 flash_read64(void *addr)
243cdbaefb5SHaavard Skinnemoen {
244cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_readq() */
245cdbaefb5SHaavard Skinnemoen 	return *(volatile u64 *)addr;
246cdbaefb5SHaavard Skinnemoen }
247cdbaefb5SHaavard Skinnemoen 
248be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
249be60a902SHaavard Skinnemoen  */
25059829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
251be60a902SHaavard Skinnemoen static flash_info_t *flash_get_info(ulong base)
252be60a902SHaavard Skinnemoen {
253be60a902SHaavard Skinnemoen 	int i;
254be60a902SHaavard Skinnemoen 	flash_info_t * info = 0;
255be60a902SHaavard Skinnemoen 
256be60a902SHaavard Skinnemoen 	for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
257be60a902SHaavard Skinnemoen 		info = & flash_info[i];
258be60a902SHaavard Skinnemoen 		if (info->size && info->start[0] <= base &&
259be60a902SHaavard Skinnemoen 		    base <= info->start[0] + info->size - 1)
260be60a902SHaavard Skinnemoen 			break;
261be60a902SHaavard Skinnemoen 	}
262be60a902SHaavard Skinnemoen 
263be60a902SHaavard Skinnemoen 	return i == CFG_MAX_FLASH_BANKS ? 0 : info;
264be60a902SHaavard Skinnemoen }
26559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
26659829cc1SJean-Christophe PLAGNIOL-VILLARD 
26712d30aa7SHaavard Skinnemoen unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
26812d30aa7SHaavard Skinnemoen {
26912d30aa7SHaavard Skinnemoen 	if (sect != (info->sector_count - 1))
27012d30aa7SHaavard Skinnemoen 		return info->start[sect + 1] - info->start[sect];
27112d30aa7SHaavard Skinnemoen 	else
27212d30aa7SHaavard Skinnemoen 		return info->start[0] + info->size - info->start[sect];
27312d30aa7SHaavard Skinnemoen }
27412d30aa7SHaavard Skinnemoen 
27559829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
27659829cc1SJean-Christophe PLAGNIOL-VILLARD  * create an address based on the offset and the port width
27759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
27812d30aa7SHaavard Skinnemoen static inline void *
27912d30aa7SHaavard Skinnemoen flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
28059829cc1SJean-Christophe PLAGNIOL-VILLARD {
28112d30aa7SHaavard Skinnemoen 	unsigned int byte_offset = offset * info->portwidth;
28212d30aa7SHaavard Skinnemoen 
28312d30aa7SHaavard Skinnemoen 	return map_physmem(info->start[sect] + byte_offset,
28412d30aa7SHaavard Skinnemoen 			flash_sector_size(info, sect) - byte_offset,
28512d30aa7SHaavard Skinnemoen 			MAP_NOCACHE);
28612d30aa7SHaavard Skinnemoen }
28712d30aa7SHaavard Skinnemoen 
28812d30aa7SHaavard Skinnemoen static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
28912d30aa7SHaavard Skinnemoen 		unsigned int offset, void *addr)
29012d30aa7SHaavard Skinnemoen {
29112d30aa7SHaavard Skinnemoen 	unsigned int byte_offset = offset * info->portwidth;
29212d30aa7SHaavard Skinnemoen 
29312d30aa7SHaavard Skinnemoen 	unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset);
29459829cc1SJean-Christophe PLAGNIOL-VILLARD }
29559829cc1SJean-Christophe PLAGNIOL-VILLARD 
296be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
297be60a902SHaavard Skinnemoen  * make a proper sized command based on the port and chip widths
298be60a902SHaavard Skinnemoen  */
299be60a902SHaavard Skinnemoen static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
300be60a902SHaavard Skinnemoen {
301be60a902SHaavard Skinnemoen 	int i;
302be60a902SHaavard Skinnemoen 	uchar *cp = (uchar *) cmdbuf;
303be60a902SHaavard Skinnemoen 
304be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
305be60a902SHaavard Skinnemoen 	for (i = info->portwidth; i > 0; i--)
306be60a902SHaavard Skinnemoen #else
307be60a902SHaavard Skinnemoen 	for (i = 1; i <= info->portwidth; i++)
308be60a902SHaavard Skinnemoen #endif
309be60a902SHaavard Skinnemoen 		*cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;
310be60a902SHaavard Skinnemoen }
311be60a902SHaavard Skinnemoen 
31259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
31359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
31459829cc1SJean-Christophe PLAGNIOL-VILLARD  * Debug support
31559829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3163055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data)
31759829cc1SJean-Christophe PLAGNIOL-VILLARD {
31859829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
31959829cc1SJean-Christophe PLAGNIOL-VILLARD 	char *cp;
32059829cc1SJean-Christophe PLAGNIOL-VILLARD 
32159829cc1SJean-Christophe PLAGNIOL-VILLARD 	cp = (unsigned char *) &data;
32259829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 8; i++)
32359829cc1SJean-Christophe PLAGNIOL-VILLARD 		sprintf (&str[i * 2], "%2.2x", *cp++);
32459829cc1SJean-Christophe PLAGNIOL-VILLARD }
325be60a902SHaavard Skinnemoen 
326e23741f4SHaavard Skinnemoen static void flash_printqry (struct cfi_qry *qry)
32759829cc1SJean-Christophe PLAGNIOL-VILLARD {
328e23741f4SHaavard Skinnemoen 	u8 *p = (u8 *)qry;
32959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x, y;
33059829cc1SJean-Christophe PLAGNIOL-VILLARD 
331e23741f4SHaavard Skinnemoen 	for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
332e23741f4SHaavard Skinnemoen 		debug("%02x : ", x);
333e23741f4SHaavard Skinnemoen 		for (y = 0; y < 16; y++)
334e23741f4SHaavard Skinnemoen 			debug("%2.2x ", p[x + y]);
33559829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug(" ");
33659829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (y = 0; y < 16; y++) {
337e23741f4SHaavard Skinnemoen 			unsigned char c = p[x + y];
338e23741f4SHaavard Skinnemoen 			if (c >= 0x20 && c <= 0x7e)
339cdbaefb5SHaavard Skinnemoen 				debug("%c", c);
340e23741f4SHaavard Skinnemoen 			else
34159829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug(".");
34259829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
34359829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug("\n");
34459829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
34559829cc1SJean-Christophe PLAGNIOL-VILLARD }
34659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
34759829cc1SJean-Christophe PLAGNIOL-VILLARD 
34859829cc1SJean-Christophe PLAGNIOL-VILLARD 
34959829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
35059829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a character at a port width address
35159829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3523055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
35359829cc1SJean-Christophe PLAGNIOL-VILLARD {
35459829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *cp;
35512d30aa7SHaavard Skinnemoen 	uchar retval;
35659829cc1SJean-Christophe PLAGNIOL-VILLARD 
35712d30aa7SHaavard Skinnemoen 	cp = flash_map (info, 0, offset);
35859829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
35912d30aa7SHaavard Skinnemoen 	retval = flash_read8(cp);
36059829cc1SJean-Christophe PLAGNIOL-VILLARD #else
36112d30aa7SHaavard Skinnemoen 	retval = flash_read8(cp + info->portwidth - 1);
36259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
36312d30aa7SHaavard Skinnemoen 	flash_unmap (info, 0, offset, cp);
36412d30aa7SHaavard Skinnemoen 	return retval;
36559829cc1SJean-Christophe PLAGNIOL-VILLARD }
36659829cc1SJean-Christophe PLAGNIOL-VILLARD 
36759829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
36859829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a long word by picking the least significant byte of each maximum
36959829cc1SJean-Christophe PLAGNIOL-VILLARD  * port size word. Swap for ppc format.
37059829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3713055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
3723055793bSHaavard Skinnemoen 			      uint offset)
37359829cc1SJean-Christophe PLAGNIOL-VILLARD {
37459829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *addr;
37559829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong retval;
37659829cc1SJean-Christophe PLAGNIOL-VILLARD 
37759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
37859829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x;
37959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
38012d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
38159829cc1SJean-Christophe PLAGNIOL-VILLARD 
38259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
38359829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("long addr is at %p info->portwidth = %d\n", addr,
38459829cc1SJean-Christophe PLAGNIOL-VILLARD 	       info->portwidth);
38559829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (x = 0; x < 4 * info->portwidth; x++) {
38612d30aa7SHaavard Skinnemoen 		debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
38759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
38859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
38959829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
39012d30aa7SHaavard Skinnemoen 	retval = ((flash_read8(addr) << 16) |
39112d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + info->portwidth) << 24) |
39212d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 2 * info->portwidth)) |
39312d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 3 * info->portwidth) << 8));
39459829cc1SJean-Christophe PLAGNIOL-VILLARD #else
39512d30aa7SHaavard Skinnemoen 	retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
39612d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + info->portwidth - 1) << 16) |
39712d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
39812d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 3 * info->portwidth - 1)));
39959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
40012d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
40112d30aa7SHaavard Skinnemoen 
40259829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
40359829cc1SJean-Christophe PLAGNIOL-VILLARD }
40459829cc1SJean-Christophe PLAGNIOL-VILLARD 
405be60a902SHaavard Skinnemoen /*
406be60a902SHaavard Skinnemoen  * Write a proper sized command to the correct address
40781b20cccSMichael Schwingen  */
408be60a902SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
409be60a902SHaavard Skinnemoen 			     uint offset, uchar cmd)
41081b20cccSMichael Schwingen {
4117e5b9b47SHaavard Skinnemoen 
412cdbaefb5SHaavard Skinnemoen 	void *addr;
413be60a902SHaavard Skinnemoen 	cfiword_t cword;
41481b20cccSMichael Schwingen 
41512d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
416be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
417be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
418be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
419cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
420be60a902SHaavard Skinnemoen 		       cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
421cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, addr);
422be60a902SHaavard Skinnemoen 		break;
423be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
424cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
425be60a902SHaavard Skinnemoen 		       cmd, cword.w,
426be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
427cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, addr);
428be60a902SHaavard Skinnemoen 		break;
429be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
430cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
431be60a902SHaavard Skinnemoen 		       cmd, cword.l,
432be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
433cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, addr);
434be60a902SHaavard Skinnemoen 		break;
435be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
436be60a902SHaavard Skinnemoen #ifdef DEBUG
437be60a902SHaavard Skinnemoen 		{
438be60a902SHaavard Skinnemoen 			char str[20];
439be60a902SHaavard Skinnemoen 
440be60a902SHaavard Skinnemoen 			print_longlong (str, cword.ll);
441be60a902SHaavard Skinnemoen 
442be60a902SHaavard Skinnemoen 			debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
443cdbaefb5SHaavard Skinnemoen 			       addr, cmd, str,
444be60a902SHaavard Skinnemoen 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
44581b20cccSMichael Schwingen 		}
446be60a902SHaavard Skinnemoen #endif
447cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, addr);
44881b20cccSMichael Schwingen 		break;
44981b20cccSMichael Schwingen 	}
450be60a902SHaavard Skinnemoen 
451be60a902SHaavard Skinnemoen 	/* Ensure all the instructions are fully finished */
452be60a902SHaavard Skinnemoen 	sync();
45312d30aa7SHaavard Skinnemoen 
45412d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
45581b20cccSMichael Schwingen }
4567e5b9b47SHaavard Skinnemoen 
457be60a902SHaavard Skinnemoen static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
458be60a902SHaavard Skinnemoen {
459be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
460be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
461be60a902SHaavard Skinnemoen }
462be60a902SHaavard Skinnemoen 
463be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
464be60a902SHaavard Skinnemoen  */
465be60a902SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect,
466be60a902SHaavard Skinnemoen 			  uint offset, uchar cmd)
467be60a902SHaavard Skinnemoen {
468cdbaefb5SHaavard Skinnemoen 	void *addr;
469be60a902SHaavard Skinnemoen 	cfiword_t cword;
470be60a902SHaavard Skinnemoen 	int retval;
471be60a902SHaavard Skinnemoen 
47212d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
473be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
474be60a902SHaavard Skinnemoen 
475cdbaefb5SHaavard Skinnemoen 	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
476be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
477be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
478cdbaefb5SHaavard Skinnemoen 		debug ("is= %x %x\n", flash_read8(addr), cword.c);
479cdbaefb5SHaavard Skinnemoen 		retval = (flash_read8(addr) == cword.c);
480be60a902SHaavard Skinnemoen 		break;
481be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
482cdbaefb5SHaavard Skinnemoen 		debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
483cdbaefb5SHaavard Skinnemoen 		retval = (flash_read16(addr) == cword.w);
484be60a902SHaavard Skinnemoen 		break;
485be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
486cdbaefb5SHaavard Skinnemoen 		debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
487cdbaefb5SHaavard Skinnemoen 		retval = (flash_read32(addr) == cword.l);
488be60a902SHaavard Skinnemoen 		break;
489be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
490be60a902SHaavard Skinnemoen #ifdef DEBUG
491be60a902SHaavard Skinnemoen 		{
492be60a902SHaavard Skinnemoen 			char str1[20];
493be60a902SHaavard Skinnemoen 			char str2[20];
494be60a902SHaavard Skinnemoen 
495cdbaefb5SHaavard Skinnemoen 			print_longlong (str1, flash_read64(addr));
496be60a902SHaavard Skinnemoen 			print_longlong (str2, cword.ll);
497be60a902SHaavard Skinnemoen 			debug ("is= %s %s\n", str1, str2);
498be60a902SHaavard Skinnemoen 		}
499be60a902SHaavard Skinnemoen #endif
500cdbaefb5SHaavard Skinnemoen 		retval = (flash_read64(addr) == cword.ll);
501be60a902SHaavard Skinnemoen 		break;
502be60a902SHaavard Skinnemoen 	default:
503be60a902SHaavard Skinnemoen 		retval = 0;
504be60a902SHaavard Skinnemoen 		break;
505be60a902SHaavard Skinnemoen 	}
50612d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
50712d30aa7SHaavard Skinnemoen 
508be60a902SHaavard Skinnemoen 	return retval;
509be60a902SHaavard Skinnemoen }
510be60a902SHaavard Skinnemoen 
511be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
512be60a902SHaavard Skinnemoen  */
513be60a902SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect,
514be60a902SHaavard Skinnemoen 			uint offset, uchar cmd)
515be60a902SHaavard Skinnemoen {
516cdbaefb5SHaavard Skinnemoen 	void *addr;
517be60a902SHaavard Skinnemoen 	cfiword_t cword;
518be60a902SHaavard Skinnemoen 	int retval;
519be60a902SHaavard Skinnemoen 
52012d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
521be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
522be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
523be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
524cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read8(addr) & cword.c) == cword.c);
525be60a902SHaavard Skinnemoen 		break;
526be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
527cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read16(addr) & cword.w) == cword.w);
528be60a902SHaavard Skinnemoen 		break;
529be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
53047cc23cbSStefan Roese 		retval = ((flash_read32(addr) & cword.l) == cword.l);
531be60a902SHaavard Skinnemoen 		break;
532be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
533cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read64(addr) & cword.ll) == cword.ll);
534be60a902SHaavard Skinnemoen 		break;
535be60a902SHaavard Skinnemoen 	default:
536be60a902SHaavard Skinnemoen 		retval = 0;
537be60a902SHaavard Skinnemoen 		break;
538be60a902SHaavard Skinnemoen 	}
53912d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
54012d30aa7SHaavard Skinnemoen 
541be60a902SHaavard Skinnemoen 	return retval;
542be60a902SHaavard Skinnemoen }
543be60a902SHaavard Skinnemoen 
544be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
545be60a902SHaavard Skinnemoen  */
546be60a902SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect,
547be60a902SHaavard Skinnemoen 			 uint offset, uchar cmd)
548be60a902SHaavard Skinnemoen {
549cdbaefb5SHaavard Skinnemoen 	void *addr;
550be60a902SHaavard Skinnemoen 	cfiword_t cword;
551be60a902SHaavard Skinnemoen 	int retval;
552be60a902SHaavard Skinnemoen 
55312d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
554be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
555be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
556be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
557cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read8(addr) & cword.c) !=
558cdbaefb5SHaavard Skinnemoen 			  (flash_read8(addr) & cword.c));
559be60a902SHaavard Skinnemoen 		break;
560be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
561cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read16(addr) & cword.w) !=
562cdbaefb5SHaavard Skinnemoen 			  (flash_read16(addr) & cword.w));
563be60a902SHaavard Skinnemoen 		break;
564be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
565cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read32(addr) & cword.l) !=
566cdbaefb5SHaavard Skinnemoen 			  (flash_read32(addr) & cword.l));
567be60a902SHaavard Skinnemoen 		break;
568be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
569cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read64(addr) & cword.ll) !=
570cdbaefb5SHaavard Skinnemoen 			  (flash_read64(addr) & cword.ll));
571be60a902SHaavard Skinnemoen 		break;
572be60a902SHaavard Skinnemoen 	default:
573be60a902SHaavard Skinnemoen 		retval = 0;
574be60a902SHaavard Skinnemoen 		break;
575be60a902SHaavard Skinnemoen 	}
57612d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
57712d30aa7SHaavard Skinnemoen 
578be60a902SHaavard Skinnemoen 	return retval;
579be60a902SHaavard Skinnemoen }
580be60a902SHaavard Skinnemoen 
581be60a902SHaavard Skinnemoen /*
582be60a902SHaavard Skinnemoen  * flash_is_busy - check to see if the flash is busy
583be60a902SHaavard Skinnemoen  *
584be60a902SHaavard Skinnemoen  * This routine checks the status of the chip and returns true if the
585be60a902SHaavard Skinnemoen  * chip is busy.
586be60a902SHaavard Skinnemoen  */
587be60a902SHaavard Skinnemoen static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
588be60a902SHaavard Skinnemoen {
589be60a902SHaavard Skinnemoen 	int retval;
590be60a902SHaavard Skinnemoen 
59181b20cccSMichael Schwingen 	switch (info->vendor) {
59281b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_STANDARD:
59381b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_EXTENDED:
594be60a902SHaavard Skinnemoen 		retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
59581b20cccSMichael Schwingen 		break;
59681b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_STANDARD:
59781b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_EXTENDED:
598be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
59981b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_LEGACY:
600be60a902SHaavard Skinnemoen #endif
601be60a902SHaavard Skinnemoen 		retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
602be60a902SHaavard Skinnemoen 		break;
603be60a902SHaavard Skinnemoen 	default:
604be60a902SHaavard Skinnemoen 		retval = 0;
605be60a902SHaavard Skinnemoen 	}
606be60a902SHaavard Skinnemoen 	debug ("flash_is_busy: %d\n", retval);
607be60a902SHaavard Skinnemoen 	return retval;
608be60a902SHaavard Skinnemoen }
609be60a902SHaavard Skinnemoen 
610be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
611be60a902SHaavard Skinnemoen  *  wait for XSR.7 to be set. Time out with an error if it does not.
612be60a902SHaavard Skinnemoen  *  This routine does not set the flash to read-array mode.
613be60a902SHaavard Skinnemoen  */
614be60a902SHaavard Skinnemoen static int flash_status_check (flash_info_t * info, flash_sect_t sector,
615be60a902SHaavard Skinnemoen 			       ulong tout, char *prompt)
616be60a902SHaavard Skinnemoen {
617be60a902SHaavard Skinnemoen 	ulong start;
618be60a902SHaavard Skinnemoen 
619be60a902SHaavard Skinnemoen #if CFG_HZ != 1000
620be60a902SHaavard Skinnemoen 	tout *= CFG_HZ/1000;
621be60a902SHaavard Skinnemoen #endif
622be60a902SHaavard Skinnemoen 
623be60a902SHaavard Skinnemoen 	/* Wait for command completion */
624be60a902SHaavard Skinnemoen 	start = get_timer (0);
625be60a902SHaavard Skinnemoen 	while (flash_is_busy (info, sector)) {
626be60a902SHaavard Skinnemoen 		if (get_timer (start) > tout) {
627be60a902SHaavard Skinnemoen 			printf ("Flash %s timeout at address %lx data %lx\n",
628be60a902SHaavard Skinnemoen 				prompt, info->start[sector],
629be60a902SHaavard Skinnemoen 				flash_read_long (info, sector, 0));
630be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0, info->cmd_reset);
631be60a902SHaavard Skinnemoen 			return ERR_TIMOUT;
632be60a902SHaavard Skinnemoen 		}
633be60a902SHaavard Skinnemoen 		udelay (1);		/* also triggers watchdog */
634be60a902SHaavard Skinnemoen 	}
635be60a902SHaavard Skinnemoen 	return ERR_OK;
636be60a902SHaavard Skinnemoen }
637be60a902SHaavard Skinnemoen 
638be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
639be60a902SHaavard Skinnemoen  * Wait for XSR.7 to be set, if it times out print an error, otherwise
640be60a902SHaavard Skinnemoen  * do a full status check.
641be60a902SHaavard Skinnemoen  *
642be60a902SHaavard Skinnemoen  * This routine sets the flash to read-array mode.
643be60a902SHaavard Skinnemoen  */
644be60a902SHaavard Skinnemoen static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
645be60a902SHaavard Skinnemoen 				    ulong tout, char *prompt)
646be60a902SHaavard Skinnemoen {
647be60a902SHaavard Skinnemoen 	int retcode;
648be60a902SHaavard Skinnemoen 
649be60a902SHaavard Skinnemoen 	retcode = flash_status_check (info, sector, tout, prompt);
650be60a902SHaavard Skinnemoen 	switch (info->vendor) {
651be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
652be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
653be60a902SHaavard Skinnemoen 		if ((retcode == ERR_OK)
654be60a902SHaavard Skinnemoen 		    && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
655be60a902SHaavard Skinnemoen 			retcode = ERR_INVAL;
656be60a902SHaavard Skinnemoen 			printf ("Flash %s error at address %lx\n", prompt,
657be60a902SHaavard Skinnemoen 				info->start[sector]);
658be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
659be60a902SHaavard Skinnemoen 					 FLASH_STATUS_PSLBS)) {
660be60a902SHaavard Skinnemoen 				puts ("Command Sequence Error.\n");
661be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
662be60a902SHaavard Skinnemoen 						FLASH_STATUS_ECLBS)) {
663be60a902SHaavard Skinnemoen 				puts ("Block Erase Error.\n");
664be60a902SHaavard Skinnemoen 				retcode = ERR_NOT_ERASED;
665be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
666be60a902SHaavard Skinnemoen 						FLASH_STATUS_PSLBS)) {
667be60a902SHaavard Skinnemoen 				puts ("Locking Error\n");
668be60a902SHaavard Skinnemoen 			}
669be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
670be60a902SHaavard Skinnemoen 				puts ("Block locked.\n");
671be60a902SHaavard Skinnemoen 				retcode = ERR_PROTECTED;
672be60a902SHaavard Skinnemoen 			}
673be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
674be60a902SHaavard Skinnemoen 				puts ("Vpp Low Error.\n");
675be60a902SHaavard Skinnemoen 		}
676be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, info->cmd_reset);
677be60a902SHaavard Skinnemoen 		break;
678be60a902SHaavard Skinnemoen 	default:
67981b20cccSMichael Schwingen 		break;
68081b20cccSMichael Schwingen 	}
681be60a902SHaavard Skinnemoen 	return retcode;
68281b20cccSMichael Schwingen }
683be60a902SHaavard Skinnemoen 
684be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
685be60a902SHaavard Skinnemoen  */
686be60a902SHaavard Skinnemoen static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
687be60a902SHaavard Skinnemoen {
688be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
689be60a902SHaavard Skinnemoen 	unsigned short	w;
690be60a902SHaavard Skinnemoen 	unsigned int	l;
691be60a902SHaavard Skinnemoen 	unsigned long long ll;
692be60a902SHaavard Skinnemoen #endif
693be60a902SHaavard Skinnemoen 
694be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
695be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
696be60a902SHaavard Skinnemoen 		cword->c = c;
697be60a902SHaavard Skinnemoen 		break;
698be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
699be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
700be60a902SHaavard Skinnemoen 		w = c;
701be60a902SHaavard Skinnemoen 		w <<= 8;
702be60a902SHaavard Skinnemoen 		cword->w = (cword->w >> 8) | w;
70381b20cccSMichael Schwingen #else
704be60a902SHaavard Skinnemoen 		cword->w = (cword->w << 8) | c;
705be60a902SHaavard Skinnemoen #endif
706be60a902SHaavard Skinnemoen 		break;
707be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
708be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
709be60a902SHaavard Skinnemoen 		l = c;
710be60a902SHaavard Skinnemoen 		l <<= 24;
711be60a902SHaavard Skinnemoen 		cword->l = (cword->l >> 8) | l;
712be60a902SHaavard Skinnemoen #else
713be60a902SHaavard Skinnemoen 		cword->l = (cword->l << 8) | c;
714be60a902SHaavard Skinnemoen #endif
715be60a902SHaavard Skinnemoen 		break;
716be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
717be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
718be60a902SHaavard Skinnemoen 		ll = c;
719be60a902SHaavard Skinnemoen 		ll <<= 56;
720be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll >> 8) | ll;
721be60a902SHaavard Skinnemoen #else
722be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll << 8) | c;
723be60a902SHaavard Skinnemoen #endif
724be60a902SHaavard Skinnemoen 		break;
725be60a902SHaavard Skinnemoen 	}
726be60a902SHaavard Skinnemoen }
727be60a902SHaavard Skinnemoen 
728be60a902SHaavard Skinnemoen /* loop through the sectors from the highest address when the passed
729be60a902SHaavard Skinnemoen  * address is greater or equal to the sector address we have a match
730be60a902SHaavard Skinnemoen  */
731be60a902SHaavard Skinnemoen static flash_sect_t find_sector (flash_info_t * info, ulong addr)
73281b20cccSMichael Schwingen {
733be60a902SHaavard Skinnemoen 	flash_sect_t sector;
734be60a902SHaavard Skinnemoen 
735be60a902SHaavard Skinnemoen 	for (sector = info->sector_count - 1; sector >= 0; sector--) {
736be60a902SHaavard Skinnemoen 		if (addr >= info->start[sector])
737be60a902SHaavard Skinnemoen 			break;
73881b20cccSMichael Schwingen 	}
739be60a902SHaavard Skinnemoen 	return sector;
74059829cc1SJean-Christophe PLAGNIOL-VILLARD }
74159829cc1SJean-Christophe PLAGNIOL-VILLARD 
74259829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
74359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
744be60a902SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest,
745be60a902SHaavard Skinnemoen 				cfiword_t cword)
74659829cc1SJean-Christophe PLAGNIOL-VILLARD {
747cdbaefb5SHaavard Skinnemoen 	void *dstaddr;
748be60a902SHaavard Skinnemoen 	int flag;
74959829cc1SJean-Christophe PLAGNIOL-VILLARD 
75012d30aa7SHaavard Skinnemoen 	dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
751be60a902SHaavard Skinnemoen 
752be60a902SHaavard Skinnemoen 	/* Check if Flash is (sufficiently) erased */
753be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
754be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
755cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
756be60a902SHaavard Skinnemoen 		break;
757be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
758cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
759be60a902SHaavard Skinnemoen 		break;
760be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
761cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
762be60a902SHaavard Skinnemoen 		break;
763be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
764cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
765be60a902SHaavard Skinnemoen 		break;
766be60a902SHaavard Skinnemoen 	default:
76712d30aa7SHaavard Skinnemoen 		flag = 0;
76812d30aa7SHaavard Skinnemoen 		break;
76912d30aa7SHaavard Skinnemoen 	}
77012d30aa7SHaavard Skinnemoen 	if (!flag) {
77112d30aa7SHaavard Skinnemoen 		unmap_physmem(dstaddr, info->portwidth);
7720dc80e27SStefan Roese 		return ERR_NOT_ERASED;
773be60a902SHaavard Skinnemoen 	}
774be60a902SHaavard Skinnemoen 
775be60a902SHaavard Skinnemoen 	/* Disable interrupts which might cause a timeout here */
776be60a902SHaavard Skinnemoen 	flag = disable_interrupts ();
777be60a902SHaavard Skinnemoen 
778be60a902SHaavard Skinnemoen 	switch (info->vendor) {
779be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
780be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
781be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
782be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
783be60a902SHaavard Skinnemoen 		break;
784be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
785be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
786be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
787be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_LEGACY:
788be60a902SHaavard Skinnemoen #endif
789be60a902SHaavard Skinnemoen 		flash_unlock_seq (info, 0);
790be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
79159829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
79259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
79359829cc1SJean-Christophe PLAGNIOL-VILLARD 
794be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
795be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
796cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, dstaddr);
797be60a902SHaavard Skinnemoen 		break;
798be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
799cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, dstaddr);
800be60a902SHaavard Skinnemoen 		break;
801be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
802cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, dstaddr);
803be60a902SHaavard Skinnemoen 		break;
804be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
805cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, dstaddr);
806be60a902SHaavard Skinnemoen 		break;
80759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
808be60a902SHaavard Skinnemoen 
809be60a902SHaavard Skinnemoen 	/* re-enable interrupts if necessary */
810be60a902SHaavard Skinnemoen 	if (flag)
811be60a902SHaavard Skinnemoen 		enable_interrupts ();
812be60a902SHaavard Skinnemoen 
81312d30aa7SHaavard Skinnemoen 	unmap_physmem(dstaddr, info->portwidth);
81412d30aa7SHaavard Skinnemoen 
815be60a902SHaavard Skinnemoen 	return flash_full_status_check (info, find_sector (info, dest),
816be60a902SHaavard Skinnemoen 					info->write_tout, "write");
817be60a902SHaavard Skinnemoen }
818be60a902SHaavard Skinnemoen 
819be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_USE_BUFFER_WRITE
820be60a902SHaavard Skinnemoen 
821be60a902SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
822be60a902SHaavard Skinnemoen 				  int len)
823be60a902SHaavard Skinnemoen {
824be60a902SHaavard Skinnemoen 	flash_sect_t sector;
825be60a902SHaavard Skinnemoen 	int cnt;
826be60a902SHaavard Skinnemoen 	int retcode;
827cdbaefb5SHaavard Skinnemoen 	void *src = cp;
82812d30aa7SHaavard Skinnemoen 	void *dst = map_physmem(dest, len, MAP_NOCACHE);
8290dc80e27SStefan Roese 	void *dst2 = dst;
8300dc80e27SStefan Roese 	int flag = 0;
831cdbaefb5SHaavard Skinnemoen 
8320dc80e27SStefan Roese 	switch (info->portwidth) {
8330dc80e27SStefan Roese 	case FLASH_CFI_8BIT:
8340dc80e27SStefan Roese 		cnt = len;
8350dc80e27SStefan Roese 		break;
8360dc80e27SStefan Roese 	case FLASH_CFI_16BIT:
8370dc80e27SStefan Roese 		cnt = len >> 1;
8380dc80e27SStefan Roese 		break;
8390dc80e27SStefan Roese 	case FLASH_CFI_32BIT:
8400dc80e27SStefan Roese 		cnt = len >> 2;
8410dc80e27SStefan Roese 		break;
8420dc80e27SStefan Roese 	case FLASH_CFI_64BIT:
8430dc80e27SStefan Roese 		cnt = len >> 3;
8440dc80e27SStefan Roese 		break;
8450dc80e27SStefan Roese 	default:
8460dc80e27SStefan Roese 		retcode = ERR_INVAL;
8470dc80e27SStefan Roese 		goto out_unmap;
8480dc80e27SStefan Roese 	}
8490dc80e27SStefan Roese 
8500dc80e27SStefan Roese 	while ((cnt-- > 0) && (flag == 0)) {
8510dc80e27SStefan Roese 		switch (info->portwidth) {
8520dc80e27SStefan Roese 		case FLASH_CFI_8BIT:
8530dc80e27SStefan Roese 			flag = ((flash_read8(dst2) & flash_read8(src)) ==
8540dc80e27SStefan Roese 				flash_read8(src));
8550dc80e27SStefan Roese 			src += 1, dst2 += 1;
8560dc80e27SStefan Roese 			break;
8570dc80e27SStefan Roese 		case FLASH_CFI_16BIT:
8580dc80e27SStefan Roese 			flag = ((flash_read16(dst2) & flash_read16(src)) ==
8590dc80e27SStefan Roese 				flash_read16(src));
8600dc80e27SStefan Roese 			src += 2, dst2 += 2;
8610dc80e27SStefan Roese 			break;
8620dc80e27SStefan Roese 		case FLASH_CFI_32BIT:
8630dc80e27SStefan Roese 			flag = ((flash_read32(dst2) & flash_read32(src)) ==
8640dc80e27SStefan Roese 				flash_read32(src));
8650dc80e27SStefan Roese 			src += 4, dst2 += 4;
8660dc80e27SStefan Roese 			break;
8670dc80e27SStefan Roese 		case FLASH_CFI_64BIT:
8680dc80e27SStefan Roese 			flag = ((flash_read64(dst2) & flash_read64(src)) ==
8690dc80e27SStefan Roese 				flash_read64(src));
8700dc80e27SStefan Roese 			src += 8, dst2 += 8;
8710dc80e27SStefan Roese 			break;
8720dc80e27SStefan Roese 		}
8730dc80e27SStefan Roese 	}
8740dc80e27SStefan Roese 	if (!flag) {
8750dc80e27SStefan Roese 		retcode = ERR_NOT_ERASED;
8760dc80e27SStefan Roese 		goto out_unmap;
8770dc80e27SStefan Roese 	}
8780dc80e27SStefan Roese 
8790dc80e27SStefan Roese 	src = cp;
880cdbaefb5SHaavard Skinnemoen 	sector = find_sector (info, dest);
881be60a902SHaavard Skinnemoen 
882be60a902SHaavard Skinnemoen 	switch (info->vendor) {
883be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
884be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
885be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
886be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
887be60a902SHaavard Skinnemoen 		retcode = flash_status_check (info, sector,
888be60a902SHaavard Skinnemoen 					      info->buffer_write_tout,
889be60a902SHaavard Skinnemoen 					      "write to buffer");
890be60a902SHaavard Skinnemoen 		if (retcode == ERR_OK) {
891be60a902SHaavard Skinnemoen 			/* reduce the number of loops by the width of
892be60a902SHaavard Skinnemoen 			 * the port */
893be60a902SHaavard Skinnemoen 			switch (info->portwidth) {
894be60a902SHaavard Skinnemoen 			case FLASH_CFI_8BIT:
895be60a902SHaavard Skinnemoen 				cnt = len;
896be60a902SHaavard Skinnemoen 				break;
897be60a902SHaavard Skinnemoen 			case FLASH_CFI_16BIT:
898be60a902SHaavard Skinnemoen 				cnt = len >> 1;
899be60a902SHaavard Skinnemoen 				break;
900be60a902SHaavard Skinnemoen 			case FLASH_CFI_32BIT:
901be60a902SHaavard Skinnemoen 				cnt = len >> 2;
902be60a902SHaavard Skinnemoen 				break;
903be60a902SHaavard Skinnemoen 			case FLASH_CFI_64BIT:
904be60a902SHaavard Skinnemoen 				cnt = len >> 3;
905be60a902SHaavard Skinnemoen 				break;
906be60a902SHaavard Skinnemoen 			default:
90712d30aa7SHaavard Skinnemoen 				retcode = ERR_INVAL;
90812d30aa7SHaavard Skinnemoen 				goto out_unmap;
909be60a902SHaavard Skinnemoen 			}
910be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
911be60a902SHaavard Skinnemoen 			while (cnt-- > 0) {
912be60a902SHaavard Skinnemoen 				switch (info->portwidth) {
913be60a902SHaavard Skinnemoen 				case FLASH_CFI_8BIT:
914cdbaefb5SHaavard Skinnemoen 					flash_write8(flash_read8(src), dst);
915cdbaefb5SHaavard Skinnemoen 					src += 1, dst += 1;
916be60a902SHaavard Skinnemoen 					break;
917be60a902SHaavard Skinnemoen 				case FLASH_CFI_16BIT:
918cdbaefb5SHaavard Skinnemoen 					flash_write16(flash_read16(src), dst);
919cdbaefb5SHaavard Skinnemoen 					src += 2, dst += 2;
920be60a902SHaavard Skinnemoen 					break;
921be60a902SHaavard Skinnemoen 				case FLASH_CFI_32BIT:
922cdbaefb5SHaavard Skinnemoen 					flash_write32(flash_read32(src), dst);
923cdbaefb5SHaavard Skinnemoen 					src += 4, dst += 4;
924be60a902SHaavard Skinnemoen 					break;
925be60a902SHaavard Skinnemoen 				case FLASH_CFI_64BIT:
926cdbaefb5SHaavard Skinnemoen 					flash_write64(flash_read64(src), dst);
927cdbaefb5SHaavard Skinnemoen 					src += 8, dst += 8;
928be60a902SHaavard Skinnemoen 					break;
929be60a902SHaavard Skinnemoen 				default:
93012d30aa7SHaavard Skinnemoen 					retcode = ERR_INVAL;
93112d30aa7SHaavard Skinnemoen 					goto out_unmap;
932be60a902SHaavard Skinnemoen 				}
933be60a902SHaavard Skinnemoen 			}
934be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,
935be60a902SHaavard Skinnemoen 					 FLASH_CMD_WRITE_BUFFER_CONFIRM);
936be60a902SHaavard Skinnemoen 			retcode = flash_full_status_check (
937be60a902SHaavard Skinnemoen 				info, sector, info->buffer_write_tout,
938be60a902SHaavard Skinnemoen 				"buffer write");
939be60a902SHaavard Skinnemoen 		}
94012d30aa7SHaavard Skinnemoen 
94112d30aa7SHaavard Skinnemoen 		break;
942be60a902SHaavard Skinnemoen 
943be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
944be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
945be60a902SHaavard Skinnemoen 		flash_unlock_seq(info,0);
946be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER);
947be60a902SHaavard Skinnemoen 
948be60a902SHaavard Skinnemoen 		switch (info->portwidth) {
949be60a902SHaavard Skinnemoen 		case FLASH_CFI_8BIT:
950be60a902SHaavard Skinnemoen 			cnt = len;
951be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
952cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
953cdbaefb5SHaavard Skinnemoen 				flash_write8(flash_read8(src), dst);
954cdbaefb5SHaavard Skinnemoen 				src += 1, dst += 1;
955cdbaefb5SHaavard Skinnemoen 			}
956be60a902SHaavard Skinnemoen 			break;
957be60a902SHaavard Skinnemoen 		case FLASH_CFI_16BIT:
958be60a902SHaavard Skinnemoen 			cnt = len >> 1;
959be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
960cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
961cdbaefb5SHaavard Skinnemoen 				flash_write16(flash_read16(src), dst);
962cdbaefb5SHaavard Skinnemoen 				src += 2, dst += 2;
963cdbaefb5SHaavard Skinnemoen 			}
964be60a902SHaavard Skinnemoen 			break;
965be60a902SHaavard Skinnemoen 		case FLASH_CFI_32BIT:
966be60a902SHaavard Skinnemoen 			cnt = len >> 2;
967be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
968cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
969cdbaefb5SHaavard Skinnemoen 				flash_write32(flash_read32(src), dst);
970cdbaefb5SHaavard Skinnemoen 				src += 4, dst += 4;
971cdbaefb5SHaavard Skinnemoen 			}
972be60a902SHaavard Skinnemoen 			break;
973be60a902SHaavard Skinnemoen 		case FLASH_CFI_64BIT:
974be60a902SHaavard Skinnemoen 			cnt = len >> 3;
975be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
976cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
977cdbaefb5SHaavard Skinnemoen 				flash_write64(flash_read64(src), dst);
978cdbaefb5SHaavard Skinnemoen 				src += 8, dst += 8;
979cdbaefb5SHaavard Skinnemoen 			}
980be60a902SHaavard Skinnemoen 			break;
981be60a902SHaavard Skinnemoen 		default:
98212d30aa7SHaavard Skinnemoen 			retcode = ERR_INVAL;
98312d30aa7SHaavard Skinnemoen 			goto out_unmap;
984be60a902SHaavard Skinnemoen 		}
985be60a902SHaavard Skinnemoen 
986be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
987be60a902SHaavard Skinnemoen 		retcode = flash_full_status_check (info, sector,
988be60a902SHaavard Skinnemoen 						   info->buffer_write_tout,
989be60a902SHaavard Skinnemoen 						   "buffer write");
99012d30aa7SHaavard Skinnemoen 		break;
991be60a902SHaavard Skinnemoen 
992be60a902SHaavard Skinnemoen 	default:
993be60a902SHaavard Skinnemoen 		debug ("Unknown Command Set\n");
99412d30aa7SHaavard Skinnemoen 		retcode = ERR_INVAL;
99512d30aa7SHaavard Skinnemoen 		break;
996be60a902SHaavard Skinnemoen 	}
99712d30aa7SHaavard Skinnemoen 
99812d30aa7SHaavard Skinnemoen out_unmap:
99912d30aa7SHaavard Skinnemoen 	unmap_physmem(dst, len);
100012d30aa7SHaavard Skinnemoen 	return retcode;
1001be60a902SHaavard Skinnemoen }
1002be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_USE_BUFFER_WRITE */
1003be60a902SHaavard Skinnemoen 
100459829cc1SJean-Christophe PLAGNIOL-VILLARD 
100559829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
100659829cc1SJean-Christophe PLAGNIOL-VILLARD  */
100759829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last)
100859829cc1SJean-Christophe PLAGNIOL-VILLARD {
100959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int rcode = 0;
101059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int prot;
101159829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect;
101259829cc1SJean-Christophe PLAGNIOL-VILLARD 
101359829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
101459829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("Can't erase unknown flash type - aborted\n");
101559829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
101659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
101759829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((s_first < 0) || (s_first > s_last)) {
101859829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("- no sectors to erase\n");
101959829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
102059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
102159829cc1SJean-Christophe PLAGNIOL-VILLARD 
102259829cc1SJean-Christophe PLAGNIOL-VILLARD 	prot = 0;
102359829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; ++sect) {
102459829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect]) {
102559829cc1SJean-Christophe PLAGNIOL-VILLARD 			prot++;
102659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
102759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
102859829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot) {
10297e5b9b47SHaavard Skinnemoen 		printf ("- Warning: %d protected sectors will not be erased!\n",
10307e5b9b47SHaavard Skinnemoen 			prot);
103159829cc1SJean-Christophe PLAGNIOL-VILLARD 	} else {
103259829cc1SJean-Christophe PLAGNIOL-VILLARD 		putc ('\n');
103359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
103459829cc1SJean-Christophe PLAGNIOL-VILLARD 
103559829cc1SJean-Christophe PLAGNIOL-VILLARD 
103659829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; sect++) {
103759829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect] == 0) { /* not protected */
103859829cc1SJean-Christophe PLAGNIOL-VILLARD 			switch (info->vendor) {
103959829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_STANDARD:
104059829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_EXTENDED:
10417e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10427e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_CLEAR_STATUS);
10437e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10447e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_BLOCK_ERASE);
10457e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10467e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_ERASE_CONFIRM);
104759829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
104859829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_STANDARD:
104959829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_EXTENDED:
105059829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
10517e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect,
10527e5b9b47SHaavard Skinnemoen 						info->addr_unlock1,
10537e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
105459829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
10557e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10567e5b9b47SHaavard Skinnemoen 						 AMD_CMD_ERASE_SECTOR);
105759829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
105881b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
105981b20cccSMichael Schwingen 			case CFI_CMDSET_AMD_LEGACY:
106081b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
10617e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, 0, info->addr_unlock1,
10627e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
106381b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
10647e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10657e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_SECTOR);
106681b20cccSMichael Schwingen 				break;
106781b20cccSMichael Schwingen #endif
106859829cc1SJean-Christophe PLAGNIOL-VILLARD 			default:
106959829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug ("Unkown flash vendor %d\n",
107059829cc1SJean-Christophe PLAGNIOL-VILLARD 				       info->vendor);
107159829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
107259829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
107359829cc1SJean-Christophe PLAGNIOL-VILLARD 
107459829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_full_status_check
107559829cc1SJean-Christophe PLAGNIOL-VILLARD 			    (info, sect, info->erase_blk_tout, "erase")) {
107659829cc1SJean-Christophe PLAGNIOL-VILLARD 				rcode = 1;
107759829cc1SJean-Christophe PLAGNIOL-VILLARD 			} else
107859829cc1SJean-Christophe PLAGNIOL-VILLARD 				putc ('.');
107959829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
108059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
108159829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts (" done\n");
108259829cc1SJean-Christophe PLAGNIOL-VILLARD 	return rcode;
108359829cc1SJean-Christophe PLAGNIOL-VILLARD }
108459829cc1SJean-Christophe PLAGNIOL-VILLARD 
108559829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
108659829cc1SJean-Christophe PLAGNIOL-VILLARD  */
108759829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info)
108859829cc1SJean-Christophe PLAGNIOL-VILLARD {
108959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
109059829cc1SJean-Christophe PLAGNIOL-VILLARD 
109159829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
109259829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("missing or unknown FLASH type\n");
109359829cc1SJean-Christophe PLAGNIOL-VILLARD 		return;
109459829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
109559829cc1SJean-Christophe PLAGNIOL-VILLARD 
109681b20cccSMichael Schwingen 	printf ("%s FLASH (%d x %d)",
109781b20cccSMichael Schwingen 		info->name,
109859829cc1SJean-Christophe PLAGNIOL-VILLARD 		(info->portwidth << 3), (info->chipwidth << 3));
109981b20cccSMichael Schwingen 	if (info->size < 1024*1024)
110081b20cccSMichael Schwingen 		printf ("  Size: %ld kB in %d Sectors\n",
110181b20cccSMichael Schwingen 			info->size >> 10, info->sector_count);
110281b20cccSMichael Schwingen 	else
110359829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  Size: %ld MB in %d Sectors\n",
110459829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->size >> 20, info->sector_count);
110559829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("  ");
110659829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
110759829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
110859829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Standard");
110959829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
111059829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
111159829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Extended");
111259829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
111359829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
111459829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Standard");
111559829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
111659829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
111759829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Extended");
111859829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
111981b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
112081b20cccSMichael Schwingen 		case CFI_CMDSET_AMD_LEGACY:
112181b20cccSMichael Schwingen 			printf ("AMD Legacy");
112281b20cccSMichael Schwingen 			break;
112381b20cccSMichael Schwingen #endif
112459829cc1SJean-Christophe PLAGNIOL-VILLARD 		default:
112559829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Unknown (%d)", info->vendor);
112659829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
112759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
112859829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
112959829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->manufacturer_id, info->device_id);
113059829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->device_id == 0x7E) {
113159829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf("%04X", info->device_id2);
113259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
113359829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
113459829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->erase_blk_tout,
113559829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->write_tout);
113659829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->buffer_size > 1) {
11377e5b9b47SHaavard Skinnemoen 		printf ("  Buffer write timeout: %ld ms, "
11387e5b9b47SHaavard Skinnemoen 			"buffer size: %d bytes\n",
113959829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_write_tout,
114059829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_size);
114159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
114259829cc1SJean-Christophe PLAGNIOL-VILLARD 
114359829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts ("\n  Sector Start Addresses:");
114459829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < info->sector_count; ++i) {
114559829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((i % 5) == 0)
114659829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("\n");
114759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_EMPTY_INFO
114859829cc1SJean-Christophe PLAGNIOL-VILLARD 		int k;
114959829cc1SJean-Christophe PLAGNIOL-VILLARD 		int size;
115059829cc1SJean-Christophe PLAGNIOL-VILLARD 		int erased;
115159829cc1SJean-Christophe PLAGNIOL-VILLARD 		volatile unsigned long *flash;
115259829cc1SJean-Christophe PLAGNIOL-VILLARD 
115359829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
115459829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * Check if whole sector is erased
115559829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
115612d30aa7SHaavard Skinnemoen 		size = flash_sector_size(info, i);
115759829cc1SJean-Christophe PLAGNIOL-VILLARD 		erased = 1;
115859829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash = (volatile unsigned long *) info->start[i];
115959829cc1SJean-Christophe PLAGNIOL-VILLARD 		size = size >> 2;	/* divide by 4 for longword access */
116059829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (k = 0; k < size; k++) {
116159829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (*flash++ != 0xffffffff) {
116259829cc1SJean-Christophe PLAGNIOL-VILLARD 				erased = 0;
116359829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
116459829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
116559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
116659829cc1SJean-Christophe PLAGNIOL-VILLARD 
116759829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* print empty and read-only info */
116859829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX %c %s ",
116959829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
117059829cc1SJean-Christophe PLAGNIOL-VILLARD 			erased ? 'E' : ' ',
117159829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
117259829cc1SJean-Christophe PLAGNIOL-VILLARD #else	/* ! CFG_FLASH_EMPTY_INFO */
117359829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX   %s ",
117459829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
117559829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
117659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
117759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
117859829cc1SJean-Christophe PLAGNIOL-VILLARD 	putc ('\n');
117959829cc1SJean-Christophe PLAGNIOL-VILLARD 	return;
118059829cc1SJean-Christophe PLAGNIOL-VILLARD }
118159829cc1SJean-Christophe PLAGNIOL-VILLARD 
118259829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
1183*9a042e9cSJerry Van Baren  * This is used in a few places in write_buf() to show programming
1184*9a042e9cSJerry Van Baren  * progress.  Making it a function is nasty because it needs to do side
1185*9a042e9cSJerry Van Baren  * effect updates to digit and dots.  Repeated code is nasty too, so
1186*9a042e9cSJerry Van Baren  * we define it once here.
1187*9a042e9cSJerry Van Baren  */
1188*9a042e9cSJerry Van Baren #define FLASH_SHOW_PROGRESS(scale, dots, digit) \
1189*9a042e9cSJerry Van Baren 	if ((scale > 0) && (dots <= 0)) { \
1190*9a042e9cSJerry Van Baren 		if ((digit % 5) == 0) \
1191*9a042e9cSJerry Van Baren 			printf ("%d", digit / 5); \
1192*9a042e9cSJerry Van Baren 		else \
1193*9a042e9cSJerry Van Baren 			putc ('.'); \
1194*9a042e9cSJerry Van Baren 		digit--; \
1195*9a042e9cSJerry Van Baren 		dots += scale; \
1196*9a042e9cSJerry Van Baren 	}
1197*9a042e9cSJerry Van Baren 
1198*9a042e9cSJerry Van Baren /*-----------------------------------------------------------------------
119959829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copy memory to flash, returns:
120059829cc1SJean-Christophe PLAGNIOL-VILLARD  * 0 - OK
120159829cc1SJean-Christophe PLAGNIOL-VILLARD  * 1 - write timeout
120259829cc1SJean-Christophe PLAGNIOL-VILLARD  * 2 - Flash not erased
120359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
120459829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
120559829cc1SJean-Christophe PLAGNIOL-VILLARD {
120659829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong wp;
120712d30aa7SHaavard Skinnemoen 	uchar *p;
120859829cc1SJean-Christophe PLAGNIOL-VILLARD 	int aln;
120959829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
121059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, rc;
121159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
121259829cc1SJean-Christophe PLAGNIOL-VILLARD 	int buffered_size;
121359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
1214*9a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS
1215*9a042e9cSJerry Van Baren 	int digit = CONFIG_FLASH_SHOW_PROGRESS;
1216*9a042e9cSJerry Van Baren 	int scale = 0;
1217*9a042e9cSJerry Van Baren 	int dots  = 0;
1218*9a042e9cSJerry Van Baren 
1219*9a042e9cSJerry Van Baren 	/*
1220*9a042e9cSJerry Van Baren 	 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
1221*9a042e9cSJerry Van Baren 	 */
1222*9a042e9cSJerry Van Baren 	if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
1223*9a042e9cSJerry Van Baren 		scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
1224*9a042e9cSJerry Van Baren 			CONFIG_FLASH_SHOW_PROGRESS);
1225*9a042e9cSJerry Van Baren 	}
1226*9a042e9cSJerry Van Baren #endif
1227*9a042e9cSJerry Van Baren 
122859829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* get lower aligned address */
122959829cc1SJean-Christophe PLAGNIOL-VILLARD 	wp = (addr & ~(info->portwidth - 1));
123059829cc1SJean-Christophe PLAGNIOL-VILLARD 
123159829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle unaligned start */
123259829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((aln = addr - wp) != 0) {
123359829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
123412d30aa7SHaavard Skinnemoen 		p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
123512d30aa7SHaavard Skinnemoen 		for (i = 0; i < aln; ++i)
123612d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
123759829cc1SJean-Christophe PLAGNIOL-VILLARD 
123859829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (; (i < info->portwidth) && (cnt > 0); i++) {
123959829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
124059829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt--;
124159829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
124212d30aa7SHaavard Skinnemoen 		for (; (cnt == 0) && (i < info->portwidth); ++i)
124312d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
124412d30aa7SHaavard Skinnemoen 
124512d30aa7SHaavard Skinnemoen 		rc = flash_write_cfiword (info, wp, cword);
124612d30aa7SHaavard Skinnemoen 		unmap_physmem(p, info->portwidth);
124712d30aa7SHaavard Skinnemoen 		if (rc != 0)
124859829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
124912d30aa7SHaavard Skinnemoen 
125012d30aa7SHaavard Skinnemoen 		wp += i;
1251*9a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS
1252*9a042e9cSJerry Van Baren 		dots -= i;
1253*9a042e9cSJerry Van Baren 		FLASH_SHOW_PROGRESS(scale, dots, digit);
1254*9a042e9cSJerry Van Baren #endif
125559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
125659829cc1SJean-Christophe PLAGNIOL-VILLARD 
125759829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle the aligned part */
125859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
125959829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size = (info->portwidth / info->chipwidth);
126059829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size *= info->buffer_size;
126159829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
126259829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* prohibit buffer write when buffer_size is 1 */
126359829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->buffer_size == 1) {
126459829cc1SJean-Christophe PLAGNIOL-VILLARD 			cword.l = 0;
126559829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->portwidth; i++)
126659829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_add_byte (info, &cword, *src++);
126759829cc1SJean-Christophe PLAGNIOL-VILLARD 			if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
126859829cc1SJean-Christophe PLAGNIOL-VILLARD 				return rc;
126959829cc1SJean-Christophe PLAGNIOL-VILLARD 			wp += info->portwidth;
127059829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt -= info->portwidth;
127159829cc1SJean-Christophe PLAGNIOL-VILLARD 			continue;
127259829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
127359829cc1SJean-Christophe PLAGNIOL-VILLARD 
127459829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* write buffer until next buffered_size aligned boundary */
127559829cc1SJean-Christophe PLAGNIOL-VILLARD 		i = buffered_size - (wp % buffered_size);
127659829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (i > cnt)
127759829cc1SJean-Christophe PLAGNIOL-VILLARD 			i = cnt;
127859829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
127959829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
128059829cc1SJean-Christophe PLAGNIOL-VILLARD 		i -= i & (info->portwidth - 1);
128159829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += i;
128259829cc1SJean-Christophe PLAGNIOL-VILLARD 		src += i;
128359829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= i;
1284*9a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS
1285*9a042e9cSJerry Van Baren 		dots -= i;
1286*9a042e9cSJerry Van Baren 		FLASH_SHOW_PROGRESS(scale, dots, digit);
1287*9a042e9cSJerry Van Baren #endif
128859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
128959829cc1SJean-Christophe PLAGNIOL-VILLARD #else
129059829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
129159829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
129259829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < info->portwidth; i++) {
129359829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
129459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
129559829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
129659829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
129759829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += info->portwidth;
129859829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= info->portwidth;
1299*9a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS
1300*9a042e9cSJerry Van Baren 		dots -= info->portwidth;
1301*9a042e9cSJerry Van Baren 		FLASH_SHOW_PROGRESS(scale, dots, digit);
1302*9a042e9cSJerry Van Baren #endif
130359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
130459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */
1305*9a042e9cSJerry Van Baren 
130659829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (cnt == 0) {
130759829cc1SJean-Christophe PLAGNIOL-VILLARD 		return (0);
130859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
130959829cc1SJean-Christophe PLAGNIOL-VILLARD 
131059829cc1SJean-Christophe PLAGNIOL-VILLARD 	/*
131159829cc1SJean-Christophe PLAGNIOL-VILLARD 	 * handle unaligned tail bytes
131259829cc1SJean-Christophe PLAGNIOL-VILLARD 	 */
131359829cc1SJean-Christophe PLAGNIOL-VILLARD 	cword.l = 0;
131412d30aa7SHaavard Skinnemoen 	p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
131512d30aa7SHaavard Skinnemoen 	for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
131659829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_add_byte (info, &cword, *src++);
131759829cc1SJean-Christophe PLAGNIOL-VILLARD 		--cnt;
131859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
131912d30aa7SHaavard Skinnemoen 	for (; i < info->portwidth; ++i)
132012d30aa7SHaavard Skinnemoen 		flash_add_byte (info, &cword, flash_read8(p + i));
132112d30aa7SHaavard Skinnemoen 	unmap_physmem(p, info->portwidth);
132259829cc1SJean-Christophe PLAGNIOL-VILLARD 
132359829cc1SJean-Christophe PLAGNIOL-VILLARD 	return flash_write_cfiword (info, wp, cword);
132459829cc1SJean-Christophe PLAGNIOL-VILLARD }
132559829cc1SJean-Christophe PLAGNIOL-VILLARD 
132659829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
132759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
132859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
132959829cc1SJean-Christophe PLAGNIOL-VILLARD 
133059829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot)
133159829cc1SJean-Christophe PLAGNIOL-VILLARD {
133259829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retcode = 0;
133359829cc1SJean-Christophe PLAGNIOL-VILLARD 
133459829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
133559829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
133659829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot)
133759829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
133859829cc1SJean-Christophe PLAGNIOL-VILLARD 	else
133959829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
134059829cc1SJean-Christophe PLAGNIOL-VILLARD 
134159829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((retcode =
134259829cc1SJean-Christophe PLAGNIOL-VILLARD 	     flash_full_status_check (info, sector, info->erase_blk_tout,
134359829cc1SJean-Christophe PLAGNIOL-VILLARD 				      prot ? "protect" : "unprotect")) == 0) {
134459829cc1SJean-Christophe PLAGNIOL-VILLARD 
134559829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->protect[sector] = prot;
134659829cc1SJean-Christophe PLAGNIOL-VILLARD 
134759829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
134859829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * On some of Intel's flash chips (marked via legacy_unlock)
134959829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * unprotect unprotects all locking.
135059829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
135159829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((prot == 0) && (info->legacy_unlock)) {
135259829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_sect_t i;
135359829cc1SJean-Christophe PLAGNIOL-VILLARD 
135459829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->sector_count; i++) {
135559829cc1SJean-Christophe PLAGNIOL-VILLARD 				if (info->protect[i])
135659829cc1SJean-Christophe PLAGNIOL-VILLARD 					flash_real_protect (info, i, 1);
135759829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
135859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
135959829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
136059829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retcode;
136159829cc1SJean-Christophe PLAGNIOL-VILLARD }
136259829cc1SJean-Christophe PLAGNIOL-VILLARD 
136359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
136459829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_user_serial - read the OneTimeProgramming cells
136559829cc1SJean-Christophe PLAGNIOL-VILLARD  */
136659829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
136759829cc1SJean-Christophe PLAGNIOL-VILLARD 			     int len)
136859829cc1SJean-Christophe PLAGNIOL-VILLARD {
136959829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
137059829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *dst;
137159829cc1SJean-Christophe PLAGNIOL-VILLARD 
137259829cc1SJean-Christophe PLAGNIOL-VILLARD 	dst = buffer;
137312d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
137459829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
137559829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (dst, src + offset, len);
137659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
137712d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
137859829cc1SJean-Christophe PLAGNIOL-VILLARD }
137959829cc1SJean-Christophe PLAGNIOL-VILLARD 
138059829cc1SJean-Christophe PLAGNIOL-VILLARD /*
138159829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_factory_serial - read the device Id from the protection area
138259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
138359829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
138459829cc1SJean-Christophe PLAGNIOL-VILLARD 				int len)
138559829cc1SJean-Christophe PLAGNIOL-VILLARD {
138659829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
138759829cc1SJean-Christophe PLAGNIOL-VILLARD 
138812d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
138959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
139059829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (buffer, src + offset, len);
139159829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
139212d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
139359829cc1SJean-Christophe PLAGNIOL-VILLARD }
139459829cc1SJean-Christophe PLAGNIOL-VILLARD 
139559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */
139659829cc1SJean-Christophe PLAGNIOL-VILLARD 
13970ddf06ddSHaavard Skinnemoen /*-----------------------------------------------------------------------
13980ddf06ddSHaavard Skinnemoen  * Reverse the order of the erase regions in the CFI QRY structure.
13990ddf06ddSHaavard Skinnemoen  * This is needed for chips that are either a) correctly detected as
14000ddf06ddSHaavard Skinnemoen  * top-boot, or b) buggy.
14010ddf06ddSHaavard Skinnemoen  */
14020ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry)
14030ddf06ddSHaavard Skinnemoen {
14040ddf06ddSHaavard Skinnemoen 	unsigned int i, j;
14050ddf06ddSHaavard Skinnemoen 	u32 tmp;
14060ddf06ddSHaavard Skinnemoen 
14070ddf06ddSHaavard Skinnemoen 	for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
14080ddf06ddSHaavard Skinnemoen 		tmp = qry->erase_region_info[i];
14090ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[i] = qry->erase_region_info[j];
14100ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[j] = tmp;
14110ddf06ddSHaavard Skinnemoen 	}
14120ddf06ddSHaavard Skinnemoen }
141359829cc1SJean-Christophe PLAGNIOL-VILLARD 
141459829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
141559829cc1SJean-Christophe PLAGNIOL-VILLARD  * read jedec ids from device and set corresponding fields in info struct
141659829cc1SJean-Christophe PLAGNIOL-VILLARD  *
141759829cc1SJean-Christophe PLAGNIOL-VILLARD  * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
141859829cc1SJean-Christophe PLAGNIOL-VILLARD  *
141959829cc1SJean-Christophe PLAGNIOL-VILLARD  */
14200ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info)
142159829cc1SJean-Christophe PLAGNIOL-VILLARD {
142259829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
142359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
142459829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
142559829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = flash_read_uchar (info,
142659829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_MANUFACTURER_ID);
142759829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id = flash_read_uchar (info,
142859829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID);
142959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
14300ddf06ddSHaavard Skinnemoen }
14310ddf06ddSHaavard Skinnemoen 
14320ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
14330ddf06ddSHaavard Skinnemoen {
14340ddf06ddSHaavard Skinnemoen 	info->cmd_reset = FLASH_CMD_RESET;
14350ddf06ddSHaavard Skinnemoen 
14360ddf06ddSHaavard Skinnemoen 	cmdset_intel_read_jedec_ids(info);
14370ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
14380ddf06ddSHaavard Skinnemoen 
14390ddf06ddSHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION
14400ddf06ddSHaavard Skinnemoen 	/* read legacy lock/unlock bit from intel flash */
14410ddf06ddSHaavard Skinnemoen 	if (info->ext_addr) {
14420ddf06ddSHaavard Skinnemoen 		info->legacy_unlock = flash_read_uchar (info,
14430ddf06ddSHaavard Skinnemoen 				info->ext_addr + 5) & 0x08;
14440ddf06ddSHaavard Skinnemoen 	}
14450ddf06ddSHaavard Skinnemoen #endif
14460ddf06ddSHaavard Skinnemoen 
14470ddf06ddSHaavard Skinnemoen 	return 0;
14480ddf06ddSHaavard Skinnemoen }
14490ddf06ddSHaavard Skinnemoen 
14500ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info)
14510ddf06ddSHaavard Skinnemoen {
145259829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
145359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_unlock_seq(info, 0);
145481b20cccSMichael Schwingen 	flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
145559829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
145659829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = flash_read_uchar (info,
145759829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_MANUFACTURER_ID);
145859829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id = flash_read_uchar (info,
145959829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID);
146059829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->device_id == 0x7E) {
146159829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* AMD 3-byte (expanded) device ids */
146259829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id2 = flash_read_uchar (info,
146359829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID2);
146459829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id2 <<= 8;
146559829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id2 |= flash_read_uchar (info,
146659829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID3);
146759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
146859829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
14690ddf06ddSHaavard Skinnemoen }
14700ddf06ddSHaavard Skinnemoen 
14710ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
14720ddf06ddSHaavard Skinnemoen {
14730ddf06ddSHaavard Skinnemoen 	info->cmd_reset = AMD_CMD_RESET;
14740ddf06ddSHaavard Skinnemoen 
14750ddf06ddSHaavard Skinnemoen 	cmdset_amd_read_jedec_ids(info);
14760ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
14770ddf06ddSHaavard Skinnemoen 
14780ddf06ddSHaavard Skinnemoen 	return 0;
14790ddf06ddSHaavard Skinnemoen }
14800ddf06ddSHaavard Skinnemoen 
14810ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
14820ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info)
14830ddf06ddSHaavard Skinnemoen {
14840ddf06ddSHaavard Skinnemoen 	info->manufacturer_id = 0;
14850ddf06ddSHaavard Skinnemoen 	info->device_id       = 0;
14860ddf06ddSHaavard Skinnemoen 	info->device_id2      = 0;
14870ddf06ddSHaavard Skinnemoen 
14880ddf06ddSHaavard Skinnemoen 	switch (info->vendor) {
14890ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
14900ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
14918225d1e3SMichael Schwingen 		cmdset_intel_read_jedec_ids(info);
14920ddf06ddSHaavard Skinnemoen 		break;
14930ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
14940ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
14958225d1e3SMichael Schwingen 		cmdset_amd_read_jedec_ids(info);
149659829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
149759829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
149859829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
149959829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
150059829cc1SJean-Christophe PLAGNIOL-VILLARD }
150159829cc1SJean-Christophe PLAGNIOL-VILLARD 
1502be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
1503be60a902SHaavard Skinnemoen  * Call board code to request info about non-CFI flash.
1504be60a902SHaavard Skinnemoen  * board_flash_get_legacy needs to fill in at least:
1505be60a902SHaavard Skinnemoen  * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1506be60a902SHaavard Skinnemoen  */
1507be60a902SHaavard Skinnemoen static int flash_detect_legacy(ulong base, int banknum)
1508be60a902SHaavard Skinnemoen {
1509be60a902SHaavard Skinnemoen 	flash_info_t *info = &flash_info[banknum];
1510be60a902SHaavard Skinnemoen 
1511be60a902SHaavard Skinnemoen 	if (board_flash_get_legacy(base, banknum, info)) {
1512be60a902SHaavard Skinnemoen 		/* board code may have filled info completely. If not, we
1513be60a902SHaavard Skinnemoen 		   use JEDEC ID probing. */
1514be60a902SHaavard Skinnemoen 		if (!info->vendor) {
1515be60a902SHaavard Skinnemoen 			int modes[] = {
1516be60a902SHaavard Skinnemoen 				CFI_CMDSET_AMD_STANDARD,
1517be60a902SHaavard Skinnemoen 				CFI_CMDSET_INTEL_STANDARD
1518be60a902SHaavard Skinnemoen 			};
1519be60a902SHaavard Skinnemoen 			int i;
1520be60a902SHaavard Skinnemoen 
1521be60a902SHaavard Skinnemoen 			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1522be60a902SHaavard Skinnemoen 				info->vendor = modes[i];
1523be60a902SHaavard Skinnemoen 				info->start[0] = base;
1524be60a902SHaavard Skinnemoen 				if (info->portwidth == FLASH_CFI_8BIT
1525be60a902SHaavard Skinnemoen 					&& info->interface == FLASH_CFI_X8X16) {
1526be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x2AAA;
1527be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x5555;
1528be60a902SHaavard Skinnemoen 				} else {
1529be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x5555;
1530be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x2AAA;
1531be60a902SHaavard Skinnemoen 				}
1532be60a902SHaavard Skinnemoen 				flash_read_jedec_ids(info);
1533be60a902SHaavard Skinnemoen 				debug("JEDEC PROBE: ID %x %x %x\n",
1534be60a902SHaavard Skinnemoen 						info->manufacturer_id,
1535be60a902SHaavard Skinnemoen 						info->device_id,
1536be60a902SHaavard Skinnemoen 						info->device_id2);
1537be60a902SHaavard Skinnemoen 				if (jedec_flash_match(info, base))
1538be60a902SHaavard Skinnemoen 					break;
1539be60a902SHaavard Skinnemoen 			}
1540be60a902SHaavard Skinnemoen 		}
1541be60a902SHaavard Skinnemoen 
1542be60a902SHaavard Skinnemoen 		switch(info->vendor) {
1543be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_STANDARD:
1544be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_EXTENDED:
1545be60a902SHaavard Skinnemoen 			info->cmd_reset = FLASH_CMD_RESET;
1546be60a902SHaavard Skinnemoen 			break;
1547be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_STANDARD:
1548be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_EXTENDED:
1549be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_LEGACY:
1550be60a902SHaavard Skinnemoen 			info->cmd_reset = AMD_CMD_RESET;
1551be60a902SHaavard Skinnemoen 			break;
1552be60a902SHaavard Skinnemoen 		}
1553be60a902SHaavard Skinnemoen 		info->flash_id = FLASH_MAN_CFI;
1554be60a902SHaavard Skinnemoen 		return 1;
1555be60a902SHaavard Skinnemoen 	}
1556be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1557be60a902SHaavard Skinnemoen }
1558be60a902SHaavard Skinnemoen #else
1559be60a902SHaavard Skinnemoen static inline int flash_detect_legacy(ulong base, int banknum)
1560be60a902SHaavard Skinnemoen {
1561be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1562be60a902SHaavard Skinnemoen }
1563be60a902SHaavard Skinnemoen #endif
1564be60a902SHaavard Skinnemoen 
156559829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
156659829cc1SJean-Christophe PLAGNIOL-VILLARD  * detect if flash is compatible with the Common Flash Interface (CFI)
156759829cc1SJean-Christophe PLAGNIOL-VILLARD  * http://www.jedec.org/download/search/jesd68.pdf
156859829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1569e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf,
1570e23741f4SHaavard Skinnemoen 		unsigned int start, size_t len)
1571e23741f4SHaavard Skinnemoen {
1572e23741f4SHaavard Skinnemoen 	u8 *p = buf;
1573e23741f4SHaavard Skinnemoen 	unsigned int i;
1574e23741f4SHaavard Skinnemoen 
1575e23741f4SHaavard Skinnemoen 	for (i = 0; i < len; i++)
1576e23741f4SHaavard Skinnemoen 		p[i] = flash_read_uchar(info, start + i);
1577e23741f4SHaavard Skinnemoen }
1578e23741f4SHaavard Skinnemoen 
1579e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
158059829cc1SJean-Christophe PLAGNIOL-VILLARD {
158159829cc1SJean-Christophe PLAGNIOL-VILLARD 	int cfi_offset;
158259829cc1SJean-Christophe PLAGNIOL-VILLARD 
15831ba639daSMichael Schwingen 	/* We do not yet know what kind of commandset to use, so we issue
15841ba639daSMichael Schwingen 	   the reset command in both Intel and AMD variants, in the hope
15851ba639daSMichael Schwingen 	   that AMD flash roms ignore the Intel command. */
15861ba639daSMichael Schwingen 	flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
15871ba639daSMichael Schwingen 	flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
15881ba639daSMichael Schwingen 
15897e5b9b47SHaavard Skinnemoen 	for (cfi_offset=0;
15907e5b9b47SHaavard Skinnemoen 	     cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
15917e5b9b47SHaavard Skinnemoen 	     cfi_offset++) {
15927e5b9b47SHaavard Skinnemoen 		flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
15937e5b9b47SHaavard Skinnemoen 				 FLASH_CMD_CFI);
159459829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
159559829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
159659829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
1597e23741f4SHaavard Skinnemoen 			flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1598e23741f4SHaavard Skinnemoen 					sizeof(struct cfi_qry));
1599e23741f4SHaavard Skinnemoen 			info->interface	= le16_to_cpu(qry->interface_desc);
1600e23741f4SHaavard Skinnemoen 
160159829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_offset = flash_offset_cfi[cfi_offset];
160259829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("device interface is %d\n",
160359829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->interface);
160459829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("found port %d chip %d ",
160559829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth, info->chipwidth);
160659829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("port %d bits chip %d bits\n",
160759829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth << CFI_FLASH_SHIFT_WIDTH,
160859829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
160942026c9cSBartlomiej Sieka 
161042026c9cSBartlomiej Sieka 			/* calculate command offsets as in the Linux driver */
161142026c9cSBartlomiej Sieka 			info->addr_unlock1 = 0x555;
161242026c9cSBartlomiej Sieka 			info->addr_unlock2 = 0x2aa;
161342026c9cSBartlomiej Sieka 
161442026c9cSBartlomiej Sieka 			/*
161542026c9cSBartlomiej Sieka 			 * modify the unlock address if we are
161642026c9cSBartlomiej Sieka 			 * in compatibility mode
161742026c9cSBartlomiej Sieka 			 */
161842026c9cSBartlomiej Sieka 			if (	/* x8/x16 in x8 mode */
161942026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY8) &&
162042026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X8X16)) ||
162142026c9cSBartlomiej Sieka 				/* x16/x32 in x16 mode */
162242026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY16) &&
162342026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X16X32)))
162442026c9cSBartlomiej Sieka 			{
162542026c9cSBartlomiej Sieka 				info->addr_unlock1 = 0xaaa;
162642026c9cSBartlomiej Sieka 				info->addr_unlock2 = 0x555;
162742026c9cSBartlomiej Sieka 			}
162842026c9cSBartlomiej Sieka 
162981b20cccSMichael Schwingen 			info->name = "CFI conformant";
163059829cc1SJean-Christophe PLAGNIOL-VILLARD 			return 1;
163159829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
163259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
16337e5b9b47SHaavard Skinnemoen 
16347e5b9b47SHaavard Skinnemoen 	return 0;
163559829cc1SJean-Christophe PLAGNIOL-VILLARD }
16367e5b9b47SHaavard Skinnemoen 
1637e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
16387e5b9b47SHaavard Skinnemoen {
16397e5b9b47SHaavard Skinnemoen 	debug ("flash detect cfi\n");
16407e5b9b47SHaavard Skinnemoen 
16417e5b9b47SHaavard Skinnemoen 	for (info->portwidth = CFG_FLASH_CFI_WIDTH;
16427e5b9b47SHaavard Skinnemoen 	     info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
16437e5b9b47SHaavard Skinnemoen 		for (info->chipwidth = FLASH_CFI_BY8;
16447e5b9b47SHaavard Skinnemoen 		     info->chipwidth <= info->portwidth;
16457e5b9b47SHaavard Skinnemoen 		     info->chipwidth <<= 1)
1646e23741f4SHaavard Skinnemoen 			if (__flash_detect_cfi(info, qry))
16477e5b9b47SHaavard Skinnemoen 				return 1;
164859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
164959829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("not found\n");
165059829cc1SJean-Christophe PLAGNIOL-VILLARD 	return 0;
165159829cc1SJean-Christophe PLAGNIOL-VILLARD }
165259829cc1SJean-Christophe PLAGNIOL-VILLARD 
165359829cc1SJean-Christophe PLAGNIOL-VILLARD /*
1654467bcee1SHaavard Skinnemoen  * Manufacturer-specific quirks. Add workarounds for geometry
1655467bcee1SHaavard Skinnemoen  * reversal, etc. here.
1656467bcee1SHaavard Skinnemoen  */
1657467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1658467bcee1SHaavard Skinnemoen {
1659467bcee1SHaavard Skinnemoen 	/* check if flash geometry needs reversal */
1660467bcee1SHaavard Skinnemoen 	if (qry->num_erase_regions > 1) {
1661467bcee1SHaavard Skinnemoen 		/* reverse geometry if top boot part */
1662467bcee1SHaavard Skinnemoen 		if (info->cfi_version < 0x3131) {
1663467bcee1SHaavard Skinnemoen 			/* CFI < 1.1, try to guess from device id */
1664467bcee1SHaavard Skinnemoen 			if ((info->device_id & 0x80) != 0)
1665467bcee1SHaavard Skinnemoen 				cfi_reverse_geometry(qry);
1666467bcee1SHaavard Skinnemoen 		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1667467bcee1SHaavard Skinnemoen 			/* CFI >= 1.1, deduct from top/bottom flag */
1668467bcee1SHaavard Skinnemoen 			/* note: ext_addr is valid since cfi_version > 0 */
1669467bcee1SHaavard Skinnemoen 			cfi_reverse_geometry(qry);
1670467bcee1SHaavard Skinnemoen 		}
1671467bcee1SHaavard Skinnemoen 	}
1672467bcee1SHaavard Skinnemoen }
1673467bcee1SHaavard Skinnemoen 
1674467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1675467bcee1SHaavard Skinnemoen {
1676467bcee1SHaavard Skinnemoen 	int reverse_geometry = 0;
1677467bcee1SHaavard Skinnemoen 
1678467bcee1SHaavard Skinnemoen 	/* Check the "top boot" bit in the PRI */
1679467bcee1SHaavard Skinnemoen 	if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1680467bcee1SHaavard Skinnemoen 		reverse_geometry = 1;
1681467bcee1SHaavard Skinnemoen 
1682467bcee1SHaavard Skinnemoen 	/* AT49BV6416(T) list the erase regions in the wrong order.
1683467bcee1SHaavard Skinnemoen 	 * However, the device ID is identical with the non-broken
1684467bcee1SHaavard Skinnemoen 	 * AT49BV642D since u-boot only reads the low byte (they
1685467bcee1SHaavard Skinnemoen 	 * differ in the high byte.) So leave out this fixup for now.
1686467bcee1SHaavard Skinnemoen 	 */
1687467bcee1SHaavard Skinnemoen #if 0
1688467bcee1SHaavard Skinnemoen 	if (info->device_id == 0xd6 || info->device_id == 0xd2)
1689467bcee1SHaavard Skinnemoen 		reverse_geometry = !reverse_geometry;
1690467bcee1SHaavard Skinnemoen #endif
1691467bcee1SHaavard Skinnemoen 
1692467bcee1SHaavard Skinnemoen 	if (reverse_geometry)
1693467bcee1SHaavard Skinnemoen 		cfi_reverse_geometry(qry);
1694467bcee1SHaavard Skinnemoen }
1695467bcee1SHaavard Skinnemoen 
1696467bcee1SHaavard Skinnemoen /*
169759829cc1SJean-Christophe PLAGNIOL-VILLARD  * The following code cannot be run from FLASH!
169859829cc1SJean-Christophe PLAGNIOL-VILLARD  *
169959829cc1SJean-Christophe PLAGNIOL-VILLARD  */
170059829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum)
170159829cc1SJean-Christophe PLAGNIOL-VILLARD {
170259829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_info_t *info = &flash_info[banknum];
170359829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, j;
170459829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect_cnt;
170559829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long sector;
170659829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long tmp;
170759829cc1SJean-Christophe PLAGNIOL-VILLARD 	int size_ratio;
170859829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar num_erase_regions;
170959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_size;
171059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_count;
1711e23741f4SHaavard Skinnemoen 	struct cfi_qry qry;
171259829cc1SJean-Christophe PLAGNIOL-VILLARD 
171359829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->ext_addr = 0;
171459829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->cfi_version = 0;
171559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
171659829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->legacy_unlock = 0;
171759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
171859829cc1SJean-Christophe PLAGNIOL-VILLARD 
171959829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->start[0] = base;
172059829cc1SJean-Christophe PLAGNIOL-VILLARD 
1721e23741f4SHaavard Skinnemoen 	if (flash_detect_cfi (info, &qry)) {
1722e23741f4SHaavard Skinnemoen 		info->vendor = le16_to_cpu(qry.p_id);
1723e23741f4SHaavard Skinnemoen 		info->ext_addr = le16_to_cpu(qry.p_adr);
1724e23741f4SHaavard Skinnemoen 		num_erase_regions = qry.num_erase_regions;
1725e23741f4SHaavard Skinnemoen 
172659829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->ext_addr) {
172759829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version = (ushort) flash_read_uchar (info,
172859829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 3) << 8;
172959829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version |= (ushort) flash_read_uchar (info,
173059829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 4);
173159829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
17320ddf06ddSHaavard Skinnemoen 
173359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
1734e23741f4SHaavard Skinnemoen 		flash_printqry (&qry);
173559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
17360ddf06ddSHaavard Skinnemoen 
173759829cc1SJean-Christophe PLAGNIOL-VILLARD 		switch (info->vendor) {
173859829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
173959829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
17400ddf06ddSHaavard Skinnemoen 			cmdset_intel_init(info, &qry);
174159829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
174259829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
174359829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
17440ddf06ddSHaavard Skinnemoen 			cmdset_amd_init(info, &qry);
174559829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
17460ddf06ddSHaavard Skinnemoen 		default:
17470ddf06ddSHaavard Skinnemoen 			printf("CFI: Unknown command set 0x%x\n",
17480ddf06ddSHaavard Skinnemoen 					info->vendor);
17490ddf06ddSHaavard Skinnemoen 			/*
17500ddf06ddSHaavard Skinnemoen 			 * Unfortunately, this means we don't know how
17510ddf06ddSHaavard Skinnemoen 			 * to get the chip back to Read mode. Might
17520ddf06ddSHaavard Skinnemoen 			 * as well try an Intel-style reset...
17530ddf06ddSHaavard Skinnemoen 			 */
17540ddf06ddSHaavard Skinnemoen 			flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
17550ddf06ddSHaavard Skinnemoen 			return 0;
175659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
175759829cc1SJean-Christophe PLAGNIOL-VILLARD 
1758467bcee1SHaavard Skinnemoen 		/* Do manufacturer-specific fixups */
1759467bcee1SHaavard Skinnemoen 		switch (info->manufacturer_id) {
1760467bcee1SHaavard Skinnemoen 		case 0x0001:
1761467bcee1SHaavard Skinnemoen 			flash_fixup_amd(info, &qry);
1762467bcee1SHaavard Skinnemoen 			break;
1763467bcee1SHaavard Skinnemoen 		case 0x001f:
1764467bcee1SHaavard Skinnemoen 			flash_fixup_atmel(info, &qry);
1765467bcee1SHaavard Skinnemoen 			break;
1766467bcee1SHaavard Skinnemoen 		}
1767467bcee1SHaavard Skinnemoen 
176859829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer is %d\n", info->vendor);
176959829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
177059829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id is 0x%x\n", info->device_id);
177159829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id2 is 0x%x\n", info->device_id2);
177259829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("cfi version is 0x%04x\n", info->cfi_version);
177359829cc1SJean-Christophe PLAGNIOL-VILLARD 
177459829cc1SJean-Christophe PLAGNIOL-VILLARD 		size_ratio = info->portwidth / info->chipwidth;
177559829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* if the chip is x8/x16 reduce the ratio by half */
177659829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((info->interface == FLASH_CFI_X8X16)
177759829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && (info->chipwidth == FLASH_CFI_BY8)) {
177859829cc1SJean-Christophe PLAGNIOL-VILLARD 			size_ratio >>= 1;
177959829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
178059829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("size_ratio %d port %d bits chip %d bits\n",
178159829cc1SJean-Christophe PLAGNIOL-VILLARD 		       size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
178259829cc1SJean-Christophe PLAGNIOL-VILLARD 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
178359829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("found %d erase regions\n", num_erase_regions);
178459829cc1SJean-Christophe PLAGNIOL-VILLARD 		sect_cnt = 0;
178559829cc1SJean-Christophe PLAGNIOL-VILLARD 		sector = base;
178659829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < num_erase_regions; i++) {
178759829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (i > NUM_ERASE_REGIONS) {
178859829cc1SJean-Christophe PLAGNIOL-VILLARD 				printf ("%d erase regions found, only %d used\n",
178959829cc1SJean-Christophe PLAGNIOL-VILLARD 					num_erase_regions, NUM_ERASE_REGIONS);
179059829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
179159829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1792e23741f4SHaavard Skinnemoen 
17930ddf06ddSHaavard Skinnemoen 			tmp = le32_to_cpu(qry.erase_region_info[i]);
17940ddf06ddSHaavard Skinnemoen 			debug("erase region %u: 0x%08lx\n", i, tmp);
1795e23741f4SHaavard Skinnemoen 
1796e23741f4SHaavard Skinnemoen 			erase_region_count = (tmp & 0xffff) + 1;
1797e23741f4SHaavard Skinnemoen 			tmp >>= 16;
179859829cc1SJean-Christophe PLAGNIOL-VILLARD 			erase_region_size =
179959829cc1SJean-Christophe PLAGNIOL-VILLARD 				(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
180059829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("erase_region_count = %d erase_region_size = %d\n",
180159829cc1SJean-Christophe PLAGNIOL-VILLARD 				erase_region_count, erase_region_size);
180259829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (j = 0; j < erase_region_count; j++) {
180381b20cccSMichael Schwingen 				if (sect_cnt >= CFG_MAX_FLASH_SECT) {
180481b20cccSMichael Schwingen 					printf("ERROR: too many flash sectors\n");
180581b20cccSMichael Schwingen 					break;
180681b20cccSMichael Schwingen 				}
180759829cc1SJean-Christophe PLAGNIOL-VILLARD 				info->start[sect_cnt] = sector;
180859829cc1SJean-Christophe PLAGNIOL-VILLARD 				sector += (erase_region_size * size_ratio);
180959829cc1SJean-Christophe PLAGNIOL-VILLARD 
181059829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
18117e5b9b47SHaavard Skinnemoen 				 * Only read protection status from
18127e5b9b47SHaavard Skinnemoen 				 * supported devices (intel...)
181359829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
181459829cc1SJean-Christophe PLAGNIOL-VILLARD 				switch (info->vendor) {
181559829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_EXTENDED:
181659829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_STANDARD:
181759829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->protect[sect_cnt] =
181859829cc1SJean-Christophe PLAGNIOL-VILLARD 						flash_isset (info, sect_cnt,
181959829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_OFFSET_PROTECT,
182059829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_STATUS_PROTECT);
182159829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
182259829cc1SJean-Christophe PLAGNIOL-VILLARD 				default:
18237e5b9b47SHaavard Skinnemoen 					/* default: not protected */
18247e5b9b47SHaavard Skinnemoen 					info->protect[sect_cnt] = 0;
182559829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
182659829cc1SJean-Christophe PLAGNIOL-VILLARD 
182759829cc1SJean-Christophe PLAGNIOL-VILLARD 				sect_cnt++;
182859829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
182959829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
183059829cc1SJean-Christophe PLAGNIOL-VILLARD 
183159829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->sector_count = sect_cnt;
1832e23741f4SHaavard Skinnemoen 		info->size = 1 << qry.dev_size;
183359829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* multiply the size by the number of chips */
18347e5b9b47SHaavard Skinnemoen 		info->size *= size_ratio;
1835e23741f4SHaavard Skinnemoen 		info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1836e23741f4SHaavard Skinnemoen 		tmp = 1 << qry.block_erase_timeout_typ;
18377e5b9b47SHaavard Skinnemoen 		info->erase_blk_tout = tmp *
1838e23741f4SHaavard Skinnemoen 			(1 << qry.block_erase_timeout_max);
1839e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.buf_write_timeout_typ) *
1840e23741f4SHaavard Skinnemoen 			(1 << qry.buf_write_timeout_max);
1841e23741f4SHaavard Skinnemoen 
18427e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1843e23741f4SHaavard Skinnemoen 		info->buffer_write_tout = (tmp + 999) / 1000;
1844e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.word_write_timeout_typ) *
1845e23741f4SHaavard Skinnemoen 			(1 << qry.word_write_timeout_max);
18467e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1847e23741f4SHaavard Skinnemoen 		info->write_tout = (tmp + 999) / 1000;
184859829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->flash_id = FLASH_MAN_CFI;
18497e5b9b47SHaavard Skinnemoen 		if ((info->interface == FLASH_CFI_X8X16) &&
18507e5b9b47SHaavard Skinnemoen 		    (info->chipwidth == FLASH_CFI_BY8)) {
18517e5b9b47SHaavard Skinnemoen 			/* XXX - Need to test on x8/x16 in parallel. */
18527e5b9b47SHaavard Skinnemoen 			info->portwidth >>= 1;
185359829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
185459829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
185559829cc1SJean-Christophe PLAGNIOL-VILLARD 
185659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
185759829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (info->size);
185859829cc1SJean-Christophe PLAGNIOL-VILLARD }
185959829cc1SJean-Christophe PLAGNIOL-VILLARD 
186059829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
186159829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1862be60a902SHaavard Skinnemoen unsigned long flash_init (void)
186359829cc1SJean-Christophe PLAGNIOL-VILLARD {
1864be60a902SHaavard Skinnemoen 	unsigned long size = 0;
1865be60a902SHaavard Skinnemoen 	int i;
186659829cc1SJean-Christophe PLAGNIOL-VILLARD 
1867be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION
1868be60a902SHaavard Skinnemoen 	char *s = getenv("unlock");
186981b20cccSMichael Schwingen #endif
1870be60a902SHaavard Skinnemoen 
1871be60a902SHaavard Skinnemoen 	/* Init: no FLASHes known */
1872be60a902SHaavard Skinnemoen 	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
1873be60a902SHaavard Skinnemoen 		flash_info[i].flash_id = FLASH_UNKNOWN;
1874be60a902SHaavard Skinnemoen 
1875be60a902SHaavard Skinnemoen 		if (!flash_detect_legacy (bank_base[i], i))
1876be60a902SHaavard Skinnemoen 			flash_get_size (bank_base[i], i);
1877be60a902SHaavard Skinnemoen 		size += flash_info[i].size;
1878be60a902SHaavard Skinnemoen 		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
1879be60a902SHaavard Skinnemoen #ifndef CFG_FLASH_QUIET_TEST
1880be60a902SHaavard Skinnemoen 			printf ("## Unknown FLASH on Bank %d "
1881be60a902SHaavard Skinnemoen 				"- Size = 0x%08lx = %ld MB\n",
1882be60a902SHaavard Skinnemoen 				i+1, flash_info[i].size,
1883be60a902SHaavard Skinnemoen 				flash_info[i].size << 20);
1884be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_QUIET_TEST */
188559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1886be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION
1887be60a902SHaavard Skinnemoen 		else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
1888be60a902SHaavard Skinnemoen 			/*
1889be60a902SHaavard Skinnemoen 			 * Only the U-Boot image and it's environment
1890be60a902SHaavard Skinnemoen 			 * is protected, all other sectors are
1891be60a902SHaavard Skinnemoen 			 * unprotected (unlocked) if flash hardware
1892be60a902SHaavard Skinnemoen 			 * protection is used (CFG_FLASH_PROTECTION)
1893be60a902SHaavard Skinnemoen 			 * and the environment variable "unlock" is
1894be60a902SHaavard Skinnemoen 			 * set to "yes".
1895be60a902SHaavard Skinnemoen 			 */
1896be60a902SHaavard Skinnemoen 			if (flash_info[i].legacy_unlock) {
1897be60a902SHaavard Skinnemoen 				int k;
189859829cc1SJean-Christophe PLAGNIOL-VILLARD 
1899be60a902SHaavard Skinnemoen 				/*
1900be60a902SHaavard Skinnemoen 				 * Disable legacy_unlock temporarily,
1901be60a902SHaavard Skinnemoen 				 * since flash_real_protect would
1902be60a902SHaavard Skinnemoen 				 * relock all other sectors again
1903be60a902SHaavard Skinnemoen 				 * otherwise.
1904be60a902SHaavard Skinnemoen 				 */
1905be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 0;
190659829cc1SJean-Christophe PLAGNIOL-VILLARD 
1907be60a902SHaavard Skinnemoen 				/*
1908be60a902SHaavard Skinnemoen 				 * Legacy unlocking (e.g. Intel J3) ->
1909be60a902SHaavard Skinnemoen 				 * unlock only one sector. This will
1910be60a902SHaavard Skinnemoen 				 * unlock all sectors.
1911be60a902SHaavard Skinnemoen 				 */
1912be60a902SHaavard Skinnemoen 				flash_real_protect (&flash_info[i], 0, 0);
191359829cc1SJean-Christophe PLAGNIOL-VILLARD 
1914be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 1;
191559829cc1SJean-Christophe PLAGNIOL-VILLARD 
1916be60a902SHaavard Skinnemoen 				/*
1917be60a902SHaavard Skinnemoen 				 * Manually mark other sectors as
1918be60a902SHaavard Skinnemoen 				 * unlocked (unprotected)
1919be60a902SHaavard Skinnemoen 				 */
1920be60a902SHaavard Skinnemoen 				for (k = 1; k < flash_info[i].sector_count; k++)
1921be60a902SHaavard Skinnemoen 					flash_info[i].protect[k] = 0;
1922be60a902SHaavard Skinnemoen 			} else {
1923be60a902SHaavard Skinnemoen 				/*
1924be60a902SHaavard Skinnemoen 				 * No legancy unlocking -> unlock all sectors
1925be60a902SHaavard Skinnemoen 				 */
1926be60a902SHaavard Skinnemoen 				flash_protect (FLAG_PROTECT_CLEAR,
1927be60a902SHaavard Skinnemoen 					       flash_info[i].start[0],
1928be60a902SHaavard Skinnemoen 					       flash_info[i].start[0]
1929be60a902SHaavard Skinnemoen 					       + flash_info[i].size - 1,
1930be60a902SHaavard Skinnemoen 					       &flash_info[i]);
193159829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
193259829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1933be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_PROTECTION */
193459829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
193559829cc1SJean-Christophe PLAGNIOL-VILLARD 
1936be60a902SHaavard Skinnemoen 	/* Monitor protection ON by default */
1937be60a902SHaavard Skinnemoen #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
1938be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
1939be60a902SHaavard Skinnemoen 		       CFG_MONITOR_BASE,
1940be60a902SHaavard Skinnemoen 		       CFG_MONITOR_BASE + monitor_flash_len  - 1,
1941be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_MONITOR_BASE));
1942be60a902SHaavard Skinnemoen #endif
194359829cc1SJean-Christophe PLAGNIOL-VILLARD 
1944be60a902SHaavard Skinnemoen 	/* Environment protection ON by default */
1945be60a902SHaavard Skinnemoen #ifdef CFG_ENV_IS_IN_FLASH
1946be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
1947be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR,
1948be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
1949be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_ENV_ADDR));
1950be60a902SHaavard Skinnemoen #endif
1951be60a902SHaavard Skinnemoen 
1952be60a902SHaavard Skinnemoen 	/* Redundant environment protection ON by default */
1953be60a902SHaavard Skinnemoen #ifdef CFG_ENV_ADDR_REDUND
1954be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
1955be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR_REDUND,
1956be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
1957be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_ENV_ADDR_REDUND));
1958be60a902SHaavard Skinnemoen #endif
1959be60a902SHaavard Skinnemoen 	return (size);
196059829cc1SJean-Christophe PLAGNIOL-VILLARD }
196159829cc1SJean-Christophe PLAGNIOL-VILLARD 
196259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_CFI */
1963