xref: /rk3399_rockchip-uboot/drivers/mtd/cfi_flash.c (revision 0dc80e2759fba859ccc4cdadc633577ca2971f3e)
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:
530cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read16(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);
772*0dc80e27SStefan 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);
829*0dc80e27SStefan Roese 	void *dst2 = dst;
830*0dc80e27SStefan Roese 	int flag = 0;
831cdbaefb5SHaavard Skinnemoen 
832*0dc80e27SStefan Roese 	switch (info->portwidth) {
833*0dc80e27SStefan Roese 	case FLASH_CFI_8BIT:
834*0dc80e27SStefan Roese 		cnt = len;
835*0dc80e27SStefan Roese 		break;
836*0dc80e27SStefan Roese 	case FLASH_CFI_16BIT:
837*0dc80e27SStefan Roese 		cnt = len >> 1;
838*0dc80e27SStefan Roese 		break;
839*0dc80e27SStefan Roese 	case FLASH_CFI_32BIT:
840*0dc80e27SStefan Roese 		cnt = len >> 2;
841*0dc80e27SStefan Roese 		break;
842*0dc80e27SStefan Roese 	case FLASH_CFI_64BIT:
843*0dc80e27SStefan Roese 		cnt = len >> 3;
844*0dc80e27SStefan Roese 		break;
845*0dc80e27SStefan Roese 	default:
846*0dc80e27SStefan Roese 		retcode = ERR_INVAL;
847*0dc80e27SStefan Roese 		goto out_unmap;
848*0dc80e27SStefan Roese 	}
849*0dc80e27SStefan Roese 
850*0dc80e27SStefan Roese 	while ((cnt-- > 0) && (flag == 0)) {
851*0dc80e27SStefan Roese 		switch (info->portwidth) {
852*0dc80e27SStefan Roese 		case FLASH_CFI_8BIT:
853*0dc80e27SStefan Roese 			flag = ((flash_read8(dst2) & flash_read8(src)) ==
854*0dc80e27SStefan Roese 				flash_read8(src));
855*0dc80e27SStefan Roese 			src += 1, dst2 += 1;
856*0dc80e27SStefan Roese 			break;
857*0dc80e27SStefan Roese 		case FLASH_CFI_16BIT:
858*0dc80e27SStefan Roese 			flag = ((flash_read16(dst2) & flash_read16(src)) ==
859*0dc80e27SStefan Roese 				flash_read16(src));
860*0dc80e27SStefan Roese 			src += 2, dst2 += 2;
861*0dc80e27SStefan Roese 			break;
862*0dc80e27SStefan Roese 		case FLASH_CFI_32BIT:
863*0dc80e27SStefan Roese 			flag = ((flash_read32(dst2) & flash_read32(src)) ==
864*0dc80e27SStefan Roese 				flash_read32(src));
865*0dc80e27SStefan Roese 			src += 4, dst2 += 4;
866*0dc80e27SStefan Roese 			break;
867*0dc80e27SStefan Roese 		case FLASH_CFI_64BIT:
868*0dc80e27SStefan Roese 			flag = ((flash_read64(dst2) & flash_read64(src)) ==
869*0dc80e27SStefan Roese 				flash_read64(src));
870*0dc80e27SStefan Roese 			src += 8, dst2 += 8;
871*0dc80e27SStefan Roese 			break;
872*0dc80e27SStefan Roese 		}
873*0dc80e27SStefan Roese 	}
874*0dc80e27SStefan Roese 	if (!flag) {
875*0dc80e27SStefan Roese 		retcode = ERR_NOT_ERASED;
876*0dc80e27SStefan Roese 		goto out_unmap;
877*0dc80e27SStefan Roese 	}
878*0dc80e27SStefan Roese 
879*0dc80e27SStefan 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 /*-----------------------------------------------------------------------
118359829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copy memory to flash, returns:
118459829cc1SJean-Christophe PLAGNIOL-VILLARD  * 0 - OK
118559829cc1SJean-Christophe PLAGNIOL-VILLARD  * 1 - write timeout
118659829cc1SJean-Christophe PLAGNIOL-VILLARD  * 2 - Flash not erased
118759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
118859829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
118959829cc1SJean-Christophe PLAGNIOL-VILLARD {
119059829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong wp;
119112d30aa7SHaavard Skinnemoen 	uchar *p;
119259829cc1SJean-Christophe PLAGNIOL-VILLARD 	int aln;
119359829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
119459829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, rc;
119559829cc1SJean-Christophe PLAGNIOL-VILLARD 
119659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
119759829cc1SJean-Christophe PLAGNIOL-VILLARD 	int buffered_size;
119859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
119959829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* get lower aligned address */
120059829cc1SJean-Christophe PLAGNIOL-VILLARD 	wp = (addr & ~(info->portwidth - 1));
120159829cc1SJean-Christophe PLAGNIOL-VILLARD 
120259829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle unaligned start */
120359829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((aln = addr - wp) != 0) {
120459829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
120512d30aa7SHaavard Skinnemoen 		p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
120612d30aa7SHaavard Skinnemoen 		for (i = 0; i < aln; ++i)
120712d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
120859829cc1SJean-Christophe PLAGNIOL-VILLARD 
120959829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (; (i < info->portwidth) && (cnt > 0); i++) {
121059829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
121159829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt--;
121259829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
121312d30aa7SHaavard Skinnemoen 		for (; (cnt == 0) && (i < info->portwidth); ++i)
121412d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
121512d30aa7SHaavard Skinnemoen 
121612d30aa7SHaavard Skinnemoen 		rc = flash_write_cfiword (info, wp, cword);
121712d30aa7SHaavard Skinnemoen 		unmap_physmem(p, info->portwidth);
121812d30aa7SHaavard Skinnemoen 		if (rc != 0)
121959829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
122012d30aa7SHaavard Skinnemoen 
122112d30aa7SHaavard Skinnemoen 		wp += i;
122259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
122359829cc1SJean-Christophe PLAGNIOL-VILLARD 
122459829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle the aligned part */
122559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
122659829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size = (info->portwidth / info->chipwidth);
122759829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size *= info->buffer_size;
122859829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
122959829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* prohibit buffer write when buffer_size is 1 */
123059829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->buffer_size == 1) {
123159829cc1SJean-Christophe PLAGNIOL-VILLARD 			cword.l = 0;
123259829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->portwidth; i++)
123359829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_add_byte (info, &cword, *src++);
123459829cc1SJean-Christophe PLAGNIOL-VILLARD 			if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
123559829cc1SJean-Christophe PLAGNIOL-VILLARD 				return rc;
123659829cc1SJean-Christophe PLAGNIOL-VILLARD 			wp += info->portwidth;
123759829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt -= info->portwidth;
123859829cc1SJean-Christophe PLAGNIOL-VILLARD 			continue;
123959829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
124059829cc1SJean-Christophe PLAGNIOL-VILLARD 
124159829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* write buffer until next buffered_size aligned boundary */
124259829cc1SJean-Christophe PLAGNIOL-VILLARD 		i = buffered_size - (wp % buffered_size);
124359829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (i > cnt)
124459829cc1SJean-Christophe PLAGNIOL-VILLARD 			i = cnt;
124559829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
124659829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
124759829cc1SJean-Christophe PLAGNIOL-VILLARD 		i -= i & (info->portwidth - 1);
124859829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += i;
124959829cc1SJean-Christophe PLAGNIOL-VILLARD 		src += i;
125059829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= i;
125159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
125259829cc1SJean-Christophe PLAGNIOL-VILLARD #else
125359829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
125459829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
125559829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < info->portwidth; i++) {
125659829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
125759829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
125859829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
125959829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
126059829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += info->portwidth;
126159829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= info->portwidth;
126259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
126359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */
126459829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (cnt == 0) {
126559829cc1SJean-Christophe PLAGNIOL-VILLARD 		return (0);
126659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
126759829cc1SJean-Christophe PLAGNIOL-VILLARD 
126859829cc1SJean-Christophe PLAGNIOL-VILLARD 	/*
126959829cc1SJean-Christophe PLAGNIOL-VILLARD 	 * handle unaligned tail bytes
127059829cc1SJean-Christophe PLAGNIOL-VILLARD 	 */
127159829cc1SJean-Christophe PLAGNIOL-VILLARD 	cword.l = 0;
127212d30aa7SHaavard Skinnemoen 	p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
127312d30aa7SHaavard Skinnemoen 	for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
127459829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_add_byte (info, &cword, *src++);
127559829cc1SJean-Christophe PLAGNIOL-VILLARD 		--cnt;
127659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
127712d30aa7SHaavard Skinnemoen 	for (; i < info->portwidth; ++i)
127812d30aa7SHaavard Skinnemoen 		flash_add_byte (info, &cword, flash_read8(p + i));
127912d30aa7SHaavard Skinnemoen 	unmap_physmem(p, info->portwidth);
128059829cc1SJean-Christophe PLAGNIOL-VILLARD 
128159829cc1SJean-Christophe PLAGNIOL-VILLARD 	return flash_write_cfiword (info, wp, cword);
128259829cc1SJean-Christophe PLAGNIOL-VILLARD }
128359829cc1SJean-Christophe PLAGNIOL-VILLARD 
128459829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
128559829cc1SJean-Christophe PLAGNIOL-VILLARD  */
128659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
128759829cc1SJean-Christophe PLAGNIOL-VILLARD 
128859829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot)
128959829cc1SJean-Christophe PLAGNIOL-VILLARD {
129059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retcode = 0;
129159829cc1SJean-Christophe PLAGNIOL-VILLARD 
129259829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
129359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
129459829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot)
129559829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
129659829cc1SJean-Christophe PLAGNIOL-VILLARD 	else
129759829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
129859829cc1SJean-Christophe PLAGNIOL-VILLARD 
129959829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((retcode =
130059829cc1SJean-Christophe PLAGNIOL-VILLARD 	     flash_full_status_check (info, sector, info->erase_blk_tout,
130159829cc1SJean-Christophe PLAGNIOL-VILLARD 				      prot ? "protect" : "unprotect")) == 0) {
130259829cc1SJean-Christophe PLAGNIOL-VILLARD 
130359829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->protect[sector] = prot;
130459829cc1SJean-Christophe PLAGNIOL-VILLARD 
130559829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
130659829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * On some of Intel's flash chips (marked via legacy_unlock)
130759829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * unprotect unprotects all locking.
130859829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
130959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((prot == 0) && (info->legacy_unlock)) {
131059829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_sect_t i;
131159829cc1SJean-Christophe PLAGNIOL-VILLARD 
131259829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->sector_count; i++) {
131359829cc1SJean-Christophe PLAGNIOL-VILLARD 				if (info->protect[i])
131459829cc1SJean-Christophe PLAGNIOL-VILLARD 					flash_real_protect (info, i, 1);
131559829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
131659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
131759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
131859829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retcode;
131959829cc1SJean-Christophe PLAGNIOL-VILLARD }
132059829cc1SJean-Christophe PLAGNIOL-VILLARD 
132159829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
132259829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_user_serial - read the OneTimeProgramming cells
132359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
132459829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
132559829cc1SJean-Christophe PLAGNIOL-VILLARD 			     int len)
132659829cc1SJean-Christophe PLAGNIOL-VILLARD {
132759829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
132859829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *dst;
132959829cc1SJean-Christophe PLAGNIOL-VILLARD 
133059829cc1SJean-Christophe PLAGNIOL-VILLARD 	dst = buffer;
133112d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
133259829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
133359829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (dst, src + offset, len);
133459829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
133512d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
133659829cc1SJean-Christophe PLAGNIOL-VILLARD }
133759829cc1SJean-Christophe PLAGNIOL-VILLARD 
133859829cc1SJean-Christophe PLAGNIOL-VILLARD /*
133959829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_factory_serial - read the device Id from the protection area
134059829cc1SJean-Christophe PLAGNIOL-VILLARD  */
134159829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
134259829cc1SJean-Christophe PLAGNIOL-VILLARD 				int len)
134359829cc1SJean-Christophe PLAGNIOL-VILLARD {
134459829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
134559829cc1SJean-Christophe PLAGNIOL-VILLARD 
134612d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
134759829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
134859829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (buffer, src + offset, len);
134959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
135012d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
135159829cc1SJean-Christophe PLAGNIOL-VILLARD }
135259829cc1SJean-Christophe PLAGNIOL-VILLARD 
135359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */
135459829cc1SJean-Christophe PLAGNIOL-VILLARD 
13550ddf06ddSHaavard Skinnemoen /*-----------------------------------------------------------------------
13560ddf06ddSHaavard Skinnemoen  * Reverse the order of the erase regions in the CFI QRY structure.
13570ddf06ddSHaavard Skinnemoen  * This is needed for chips that are either a) correctly detected as
13580ddf06ddSHaavard Skinnemoen  * top-boot, or b) buggy.
13590ddf06ddSHaavard Skinnemoen  */
13600ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry)
13610ddf06ddSHaavard Skinnemoen {
13620ddf06ddSHaavard Skinnemoen 	unsigned int i, j;
13630ddf06ddSHaavard Skinnemoen 	u32 tmp;
13640ddf06ddSHaavard Skinnemoen 
13650ddf06ddSHaavard Skinnemoen 	for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
13660ddf06ddSHaavard Skinnemoen 		tmp = qry->erase_region_info[i];
13670ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[i] = qry->erase_region_info[j];
13680ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[j] = tmp;
13690ddf06ddSHaavard Skinnemoen 	}
13700ddf06ddSHaavard Skinnemoen }
137159829cc1SJean-Christophe PLAGNIOL-VILLARD 
137259829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
137359829cc1SJean-Christophe PLAGNIOL-VILLARD  * read jedec ids from device and set corresponding fields in info struct
137459829cc1SJean-Christophe PLAGNIOL-VILLARD  *
137559829cc1SJean-Christophe PLAGNIOL-VILLARD  * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
137659829cc1SJean-Christophe PLAGNIOL-VILLARD  *
137759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
13780ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info)
137959829cc1SJean-Christophe PLAGNIOL-VILLARD {
138059829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
138159829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
138259829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
138359829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = flash_read_uchar (info,
138459829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_MANUFACTURER_ID);
138559829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id = flash_read_uchar (info,
138659829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID);
138759829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
13880ddf06ddSHaavard Skinnemoen }
13890ddf06ddSHaavard Skinnemoen 
13900ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
13910ddf06ddSHaavard Skinnemoen {
13920ddf06ddSHaavard Skinnemoen 	info->cmd_reset = FLASH_CMD_RESET;
13930ddf06ddSHaavard Skinnemoen 
13940ddf06ddSHaavard Skinnemoen 	cmdset_intel_read_jedec_ids(info);
13950ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
13960ddf06ddSHaavard Skinnemoen 
13970ddf06ddSHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION
13980ddf06ddSHaavard Skinnemoen 	/* read legacy lock/unlock bit from intel flash */
13990ddf06ddSHaavard Skinnemoen 	if (info->ext_addr) {
14000ddf06ddSHaavard Skinnemoen 		info->legacy_unlock = flash_read_uchar (info,
14010ddf06ddSHaavard Skinnemoen 				info->ext_addr + 5) & 0x08;
14020ddf06ddSHaavard Skinnemoen 	}
14030ddf06ddSHaavard Skinnemoen #endif
14040ddf06ddSHaavard Skinnemoen 
14050ddf06ddSHaavard Skinnemoen 	return 0;
14060ddf06ddSHaavard Skinnemoen }
14070ddf06ddSHaavard Skinnemoen 
14080ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info)
14090ddf06ddSHaavard Skinnemoen {
141059829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
141159829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_unlock_seq(info, 0);
141281b20cccSMichael Schwingen 	flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
141359829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
141459829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = flash_read_uchar (info,
141559829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_MANUFACTURER_ID);
141659829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id = flash_read_uchar (info,
141759829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID);
141859829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->device_id == 0x7E) {
141959829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* AMD 3-byte (expanded) device ids */
142059829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id2 = flash_read_uchar (info,
142159829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID2);
142259829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id2 <<= 8;
142359829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id2 |= flash_read_uchar (info,
142459829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID3);
142559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
142659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
14270ddf06ddSHaavard Skinnemoen }
14280ddf06ddSHaavard Skinnemoen 
14290ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
14300ddf06ddSHaavard Skinnemoen {
14310ddf06ddSHaavard Skinnemoen 	info->cmd_reset = AMD_CMD_RESET;
14320ddf06ddSHaavard Skinnemoen 
14330ddf06ddSHaavard Skinnemoen 	cmdset_amd_read_jedec_ids(info);
14340ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
14350ddf06ddSHaavard Skinnemoen 
14360ddf06ddSHaavard Skinnemoen 	return 0;
14370ddf06ddSHaavard Skinnemoen }
14380ddf06ddSHaavard Skinnemoen 
14390ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
14400ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info)
14410ddf06ddSHaavard Skinnemoen {
14420ddf06ddSHaavard Skinnemoen 	info->manufacturer_id = 0;
14430ddf06ddSHaavard Skinnemoen 	info->device_id       = 0;
14440ddf06ddSHaavard Skinnemoen 	info->device_id2      = 0;
14450ddf06ddSHaavard Skinnemoen 
14460ddf06ddSHaavard Skinnemoen 	switch (info->vendor) {
14470ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
14480ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
14490ddf06ddSHaavard Skinnemoen 		flash_read_jedec_ids_intel(info);
14500ddf06ddSHaavard Skinnemoen 		break;
14510ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
14520ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
14530ddf06ddSHaavard Skinnemoen 		flash_read_jedec_ids_amd(info);
145459829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
145559829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
145659829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
145759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
145859829cc1SJean-Christophe PLAGNIOL-VILLARD }
145959829cc1SJean-Christophe PLAGNIOL-VILLARD 
1460be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
1461be60a902SHaavard Skinnemoen  * Call board code to request info about non-CFI flash.
1462be60a902SHaavard Skinnemoen  * board_flash_get_legacy needs to fill in at least:
1463be60a902SHaavard Skinnemoen  * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1464be60a902SHaavard Skinnemoen  */
1465be60a902SHaavard Skinnemoen static int flash_detect_legacy(ulong base, int banknum)
1466be60a902SHaavard Skinnemoen {
1467be60a902SHaavard Skinnemoen 	flash_info_t *info = &flash_info[banknum];
1468be60a902SHaavard Skinnemoen 
1469be60a902SHaavard Skinnemoen 	if (board_flash_get_legacy(base, banknum, info)) {
1470be60a902SHaavard Skinnemoen 		/* board code may have filled info completely. If not, we
1471be60a902SHaavard Skinnemoen 		   use JEDEC ID probing. */
1472be60a902SHaavard Skinnemoen 		if (!info->vendor) {
1473be60a902SHaavard Skinnemoen 			int modes[] = {
1474be60a902SHaavard Skinnemoen 				CFI_CMDSET_AMD_STANDARD,
1475be60a902SHaavard Skinnemoen 				CFI_CMDSET_INTEL_STANDARD
1476be60a902SHaavard Skinnemoen 			};
1477be60a902SHaavard Skinnemoen 			int i;
1478be60a902SHaavard Skinnemoen 
1479be60a902SHaavard Skinnemoen 			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1480be60a902SHaavard Skinnemoen 				info->vendor = modes[i];
1481be60a902SHaavard Skinnemoen 				info->start[0] = base;
1482be60a902SHaavard Skinnemoen 				if (info->portwidth == FLASH_CFI_8BIT
1483be60a902SHaavard Skinnemoen 					&& info->interface == FLASH_CFI_X8X16) {
1484be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x2AAA;
1485be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x5555;
1486be60a902SHaavard Skinnemoen 				} else {
1487be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x5555;
1488be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x2AAA;
1489be60a902SHaavard Skinnemoen 				}
1490be60a902SHaavard Skinnemoen 				flash_read_jedec_ids(info);
1491be60a902SHaavard Skinnemoen 				debug("JEDEC PROBE: ID %x %x %x\n",
1492be60a902SHaavard Skinnemoen 						info->manufacturer_id,
1493be60a902SHaavard Skinnemoen 						info->device_id,
1494be60a902SHaavard Skinnemoen 						info->device_id2);
1495be60a902SHaavard Skinnemoen 				if (jedec_flash_match(info, base))
1496be60a902SHaavard Skinnemoen 					break;
1497be60a902SHaavard Skinnemoen 			}
1498be60a902SHaavard Skinnemoen 		}
1499be60a902SHaavard Skinnemoen 
1500be60a902SHaavard Skinnemoen 		switch(info->vendor) {
1501be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_STANDARD:
1502be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_EXTENDED:
1503be60a902SHaavard Skinnemoen 			info->cmd_reset = FLASH_CMD_RESET;
1504be60a902SHaavard Skinnemoen 			break;
1505be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_STANDARD:
1506be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_EXTENDED:
1507be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_LEGACY:
1508be60a902SHaavard Skinnemoen 			info->cmd_reset = AMD_CMD_RESET;
1509be60a902SHaavard Skinnemoen 			break;
1510be60a902SHaavard Skinnemoen 		}
1511be60a902SHaavard Skinnemoen 		info->flash_id = FLASH_MAN_CFI;
1512be60a902SHaavard Skinnemoen 		return 1;
1513be60a902SHaavard Skinnemoen 	}
1514be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1515be60a902SHaavard Skinnemoen }
1516be60a902SHaavard Skinnemoen #else
1517be60a902SHaavard Skinnemoen static inline int flash_detect_legacy(ulong base, int banknum)
1518be60a902SHaavard Skinnemoen {
1519be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1520be60a902SHaavard Skinnemoen }
1521be60a902SHaavard Skinnemoen #endif
1522be60a902SHaavard Skinnemoen 
152359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
152459829cc1SJean-Christophe PLAGNIOL-VILLARD  * detect if flash is compatible with the Common Flash Interface (CFI)
152559829cc1SJean-Christophe PLAGNIOL-VILLARD  * http://www.jedec.org/download/search/jesd68.pdf
152659829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1527e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf,
1528e23741f4SHaavard Skinnemoen 		unsigned int start, size_t len)
1529e23741f4SHaavard Skinnemoen {
1530e23741f4SHaavard Skinnemoen 	u8 *p = buf;
1531e23741f4SHaavard Skinnemoen 	unsigned int i;
1532e23741f4SHaavard Skinnemoen 
1533e23741f4SHaavard Skinnemoen 	for (i = 0; i < len; i++)
1534e23741f4SHaavard Skinnemoen 		p[i] = flash_read_uchar(info, start + i);
1535e23741f4SHaavard Skinnemoen }
1536e23741f4SHaavard Skinnemoen 
1537e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
153859829cc1SJean-Christophe PLAGNIOL-VILLARD {
153959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int cfi_offset;
154059829cc1SJean-Christophe PLAGNIOL-VILLARD 
154159829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
15427e5b9b47SHaavard Skinnemoen 	for (cfi_offset=0;
15437e5b9b47SHaavard Skinnemoen 	     cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
15447e5b9b47SHaavard Skinnemoen 	     cfi_offset++) {
15457e5b9b47SHaavard Skinnemoen 		flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
15467e5b9b47SHaavard Skinnemoen 				 FLASH_CMD_CFI);
154759829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
154859829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
154959829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
1550e23741f4SHaavard Skinnemoen 			flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1551e23741f4SHaavard Skinnemoen 					sizeof(struct cfi_qry));
1552e23741f4SHaavard Skinnemoen 			info->interface	= le16_to_cpu(qry->interface_desc);
1553e23741f4SHaavard Skinnemoen 
155459829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_offset = flash_offset_cfi[cfi_offset];
155559829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("device interface is %d\n",
155659829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->interface);
155759829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("found port %d chip %d ",
155859829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth, info->chipwidth);
155959829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("port %d bits chip %d bits\n",
156059829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth << CFI_FLASH_SHIFT_WIDTH,
156159829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
156242026c9cSBartlomiej Sieka 
156342026c9cSBartlomiej Sieka 			/* calculate command offsets as in the Linux driver */
156442026c9cSBartlomiej Sieka 			info->addr_unlock1 = 0x555;
156542026c9cSBartlomiej Sieka 			info->addr_unlock2 = 0x2aa;
156642026c9cSBartlomiej Sieka 
156742026c9cSBartlomiej Sieka 			/*
156842026c9cSBartlomiej Sieka 			 * modify the unlock address if we are
156942026c9cSBartlomiej Sieka 			 * in compatibility mode
157042026c9cSBartlomiej Sieka 			 */
157142026c9cSBartlomiej Sieka 			if (	/* x8/x16 in x8 mode */
157242026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY8) &&
157342026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X8X16)) ||
157442026c9cSBartlomiej Sieka 				/* x16/x32 in x16 mode */
157542026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY16) &&
157642026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X16X32)))
157742026c9cSBartlomiej Sieka 			{
157842026c9cSBartlomiej Sieka 				info->addr_unlock1 = 0xaaa;
157942026c9cSBartlomiej Sieka 				info->addr_unlock2 = 0x555;
158042026c9cSBartlomiej Sieka 			}
158142026c9cSBartlomiej Sieka 
158281b20cccSMichael Schwingen 			info->name = "CFI conformant";
158359829cc1SJean-Christophe PLAGNIOL-VILLARD 			return 1;
158459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
158559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
15867e5b9b47SHaavard Skinnemoen 
15877e5b9b47SHaavard Skinnemoen 	return 0;
158859829cc1SJean-Christophe PLAGNIOL-VILLARD }
15897e5b9b47SHaavard Skinnemoen 
1590e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
15917e5b9b47SHaavard Skinnemoen {
15927e5b9b47SHaavard Skinnemoen 	debug ("flash detect cfi\n");
15937e5b9b47SHaavard Skinnemoen 
15947e5b9b47SHaavard Skinnemoen 	for (info->portwidth = CFG_FLASH_CFI_WIDTH;
15957e5b9b47SHaavard Skinnemoen 	     info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
15967e5b9b47SHaavard Skinnemoen 		for (info->chipwidth = FLASH_CFI_BY8;
15977e5b9b47SHaavard Skinnemoen 		     info->chipwidth <= info->portwidth;
15987e5b9b47SHaavard Skinnemoen 		     info->chipwidth <<= 1)
1599e23741f4SHaavard Skinnemoen 			if (__flash_detect_cfi(info, qry))
16007e5b9b47SHaavard Skinnemoen 				return 1;
160159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
160259829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("not found\n");
160359829cc1SJean-Christophe PLAGNIOL-VILLARD 	return 0;
160459829cc1SJean-Christophe PLAGNIOL-VILLARD }
160559829cc1SJean-Christophe PLAGNIOL-VILLARD 
160659829cc1SJean-Christophe PLAGNIOL-VILLARD /*
1607467bcee1SHaavard Skinnemoen  * Manufacturer-specific quirks. Add workarounds for geometry
1608467bcee1SHaavard Skinnemoen  * reversal, etc. here.
1609467bcee1SHaavard Skinnemoen  */
1610467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1611467bcee1SHaavard Skinnemoen {
1612467bcee1SHaavard Skinnemoen 	/* check if flash geometry needs reversal */
1613467bcee1SHaavard Skinnemoen 	if (qry->num_erase_regions > 1) {
1614467bcee1SHaavard Skinnemoen 		/* reverse geometry if top boot part */
1615467bcee1SHaavard Skinnemoen 		if (info->cfi_version < 0x3131) {
1616467bcee1SHaavard Skinnemoen 			/* CFI < 1.1, try to guess from device id */
1617467bcee1SHaavard Skinnemoen 			if ((info->device_id & 0x80) != 0)
1618467bcee1SHaavard Skinnemoen 				cfi_reverse_geometry(qry);
1619467bcee1SHaavard Skinnemoen 		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1620467bcee1SHaavard Skinnemoen 			/* CFI >= 1.1, deduct from top/bottom flag */
1621467bcee1SHaavard Skinnemoen 			/* note: ext_addr is valid since cfi_version > 0 */
1622467bcee1SHaavard Skinnemoen 			cfi_reverse_geometry(qry);
1623467bcee1SHaavard Skinnemoen 		}
1624467bcee1SHaavard Skinnemoen 	}
1625467bcee1SHaavard Skinnemoen }
1626467bcee1SHaavard Skinnemoen 
1627467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1628467bcee1SHaavard Skinnemoen {
1629467bcee1SHaavard Skinnemoen 	int reverse_geometry = 0;
1630467bcee1SHaavard Skinnemoen 
1631467bcee1SHaavard Skinnemoen 	/* Check the "top boot" bit in the PRI */
1632467bcee1SHaavard Skinnemoen 	if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1633467bcee1SHaavard Skinnemoen 		reverse_geometry = 1;
1634467bcee1SHaavard Skinnemoen 
1635467bcee1SHaavard Skinnemoen 	/* AT49BV6416(T) list the erase regions in the wrong order.
1636467bcee1SHaavard Skinnemoen 	 * However, the device ID is identical with the non-broken
1637467bcee1SHaavard Skinnemoen 	 * AT49BV642D since u-boot only reads the low byte (they
1638467bcee1SHaavard Skinnemoen 	 * differ in the high byte.) So leave out this fixup for now.
1639467bcee1SHaavard Skinnemoen 	 */
1640467bcee1SHaavard Skinnemoen #if 0
1641467bcee1SHaavard Skinnemoen 	if (info->device_id == 0xd6 || info->device_id == 0xd2)
1642467bcee1SHaavard Skinnemoen 		reverse_geometry = !reverse_geometry;
1643467bcee1SHaavard Skinnemoen #endif
1644467bcee1SHaavard Skinnemoen 
1645467bcee1SHaavard Skinnemoen 	if (reverse_geometry)
1646467bcee1SHaavard Skinnemoen 		cfi_reverse_geometry(qry);
1647467bcee1SHaavard Skinnemoen }
1648467bcee1SHaavard Skinnemoen 
1649467bcee1SHaavard Skinnemoen /*
165059829cc1SJean-Christophe PLAGNIOL-VILLARD  * The following code cannot be run from FLASH!
165159829cc1SJean-Christophe PLAGNIOL-VILLARD  *
165259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
165359829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum)
165459829cc1SJean-Christophe PLAGNIOL-VILLARD {
165559829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_info_t *info = &flash_info[banknum];
165659829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, j;
165759829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect_cnt;
165859829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long sector;
165959829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long tmp;
166059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int size_ratio;
166159829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar num_erase_regions;
166259829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_size;
166359829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_count;
1664e23741f4SHaavard Skinnemoen 	struct cfi_qry qry;
166559829cc1SJean-Christophe PLAGNIOL-VILLARD 
166659829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->ext_addr = 0;
166759829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->cfi_version = 0;
166859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
166959829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->legacy_unlock = 0;
167059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
167159829cc1SJean-Christophe PLAGNIOL-VILLARD 
167259829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->start[0] = base;
167359829cc1SJean-Christophe PLAGNIOL-VILLARD 
1674e23741f4SHaavard Skinnemoen 	if (flash_detect_cfi (info, &qry)) {
1675e23741f4SHaavard Skinnemoen 		info->vendor = le16_to_cpu(qry.p_id);
1676e23741f4SHaavard Skinnemoen 		info->ext_addr = le16_to_cpu(qry.p_adr);
1677e23741f4SHaavard Skinnemoen 		num_erase_regions = qry.num_erase_regions;
1678e23741f4SHaavard Skinnemoen 
167959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->ext_addr) {
168059829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version = (ushort) flash_read_uchar (info,
168159829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 3) << 8;
168259829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version |= (ushort) flash_read_uchar (info,
168359829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 4);
168459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
16850ddf06ddSHaavard Skinnemoen 
168659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
1687e23741f4SHaavard Skinnemoen 		flash_printqry (&qry);
168859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
16890ddf06ddSHaavard Skinnemoen 
169059829cc1SJean-Christophe PLAGNIOL-VILLARD 		switch (info->vendor) {
169159829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
169259829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
16930ddf06ddSHaavard Skinnemoen 			cmdset_intel_init(info, &qry);
169459829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
169559829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
169659829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
16970ddf06ddSHaavard Skinnemoen 			cmdset_amd_init(info, &qry);
169859829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
16990ddf06ddSHaavard Skinnemoen 		default:
17000ddf06ddSHaavard Skinnemoen 			printf("CFI: Unknown command set 0x%x\n",
17010ddf06ddSHaavard Skinnemoen 					info->vendor);
17020ddf06ddSHaavard Skinnemoen 			/*
17030ddf06ddSHaavard Skinnemoen 			 * Unfortunately, this means we don't know how
17040ddf06ddSHaavard Skinnemoen 			 * to get the chip back to Read mode. Might
17050ddf06ddSHaavard Skinnemoen 			 * as well try an Intel-style reset...
17060ddf06ddSHaavard Skinnemoen 			 */
17070ddf06ddSHaavard Skinnemoen 			flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
17080ddf06ddSHaavard Skinnemoen 			return 0;
170959829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
171059829cc1SJean-Christophe PLAGNIOL-VILLARD 
1711467bcee1SHaavard Skinnemoen 		/* Do manufacturer-specific fixups */
1712467bcee1SHaavard Skinnemoen 		switch (info->manufacturer_id) {
1713467bcee1SHaavard Skinnemoen 		case 0x0001:
1714467bcee1SHaavard Skinnemoen 			flash_fixup_amd(info, &qry);
1715467bcee1SHaavard Skinnemoen 			break;
1716467bcee1SHaavard Skinnemoen 		case 0x001f:
1717467bcee1SHaavard Skinnemoen 			flash_fixup_atmel(info, &qry);
1718467bcee1SHaavard Skinnemoen 			break;
1719467bcee1SHaavard Skinnemoen 		}
1720467bcee1SHaavard Skinnemoen 
172159829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer is %d\n", info->vendor);
172259829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
172359829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id is 0x%x\n", info->device_id);
172459829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id2 is 0x%x\n", info->device_id2);
172559829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("cfi version is 0x%04x\n", info->cfi_version);
172659829cc1SJean-Christophe PLAGNIOL-VILLARD 
172759829cc1SJean-Christophe PLAGNIOL-VILLARD 		size_ratio = info->portwidth / info->chipwidth;
172859829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* if the chip is x8/x16 reduce the ratio by half */
172959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((info->interface == FLASH_CFI_X8X16)
173059829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && (info->chipwidth == FLASH_CFI_BY8)) {
173159829cc1SJean-Christophe PLAGNIOL-VILLARD 			size_ratio >>= 1;
173259829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
173359829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("size_ratio %d port %d bits chip %d bits\n",
173459829cc1SJean-Christophe PLAGNIOL-VILLARD 		       size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
173559829cc1SJean-Christophe PLAGNIOL-VILLARD 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
173659829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("found %d erase regions\n", num_erase_regions);
173759829cc1SJean-Christophe PLAGNIOL-VILLARD 		sect_cnt = 0;
173859829cc1SJean-Christophe PLAGNIOL-VILLARD 		sector = base;
173959829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < num_erase_regions; i++) {
174059829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (i > NUM_ERASE_REGIONS) {
174159829cc1SJean-Christophe PLAGNIOL-VILLARD 				printf ("%d erase regions found, only %d used\n",
174259829cc1SJean-Christophe PLAGNIOL-VILLARD 					num_erase_regions, NUM_ERASE_REGIONS);
174359829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
174459829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1745e23741f4SHaavard Skinnemoen 
17460ddf06ddSHaavard Skinnemoen 			tmp = le32_to_cpu(qry.erase_region_info[i]);
17470ddf06ddSHaavard Skinnemoen 			debug("erase region %u: 0x%08lx\n", i, tmp);
1748e23741f4SHaavard Skinnemoen 
1749e23741f4SHaavard Skinnemoen 			erase_region_count = (tmp & 0xffff) + 1;
1750e23741f4SHaavard Skinnemoen 			tmp >>= 16;
175159829cc1SJean-Christophe PLAGNIOL-VILLARD 			erase_region_size =
175259829cc1SJean-Christophe PLAGNIOL-VILLARD 				(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
175359829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("erase_region_count = %d erase_region_size = %d\n",
175459829cc1SJean-Christophe PLAGNIOL-VILLARD 				erase_region_count, erase_region_size);
175559829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (j = 0; j < erase_region_count; j++) {
175681b20cccSMichael Schwingen 				if (sect_cnt >= CFG_MAX_FLASH_SECT) {
175781b20cccSMichael Schwingen 					printf("ERROR: too many flash sectors\n");
175881b20cccSMichael Schwingen 					break;
175981b20cccSMichael Schwingen 				}
176059829cc1SJean-Christophe PLAGNIOL-VILLARD 				info->start[sect_cnt] = sector;
176159829cc1SJean-Christophe PLAGNIOL-VILLARD 				sector += (erase_region_size * size_ratio);
176259829cc1SJean-Christophe PLAGNIOL-VILLARD 
176359829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
17647e5b9b47SHaavard Skinnemoen 				 * Only read protection status from
17657e5b9b47SHaavard Skinnemoen 				 * supported devices (intel...)
176659829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
176759829cc1SJean-Christophe PLAGNIOL-VILLARD 				switch (info->vendor) {
176859829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_EXTENDED:
176959829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_STANDARD:
177059829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->protect[sect_cnt] =
177159829cc1SJean-Christophe PLAGNIOL-VILLARD 						flash_isset (info, sect_cnt,
177259829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_OFFSET_PROTECT,
177359829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_STATUS_PROTECT);
177459829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
177559829cc1SJean-Christophe PLAGNIOL-VILLARD 				default:
17767e5b9b47SHaavard Skinnemoen 					/* default: not protected */
17777e5b9b47SHaavard Skinnemoen 					info->protect[sect_cnt] = 0;
177859829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
177959829cc1SJean-Christophe PLAGNIOL-VILLARD 
178059829cc1SJean-Christophe PLAGNIOL-VILLARD 				sect_cnt++;
178159829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
178259829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
178359829cc1SJean-Christophe PLAGNIOL-VILLARD 
178459829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->sector_count = sect_cnt;
1785e23741f4SHaavard Skinnemoen 		info->size = 1 << qry.dev_size;
178659829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* multiply the size by the number of chips */
17877e5b9b47SHaavard Skinnemoen 		info->size *= size_ratio;
1788e23741f4SHaavard Skinnemoen 		info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1789e23741f4SHaavard Skinnemoen 		tmp = 1 << qry.block_erase_timeout_typ;
17907e5b9b47SHaavard Skinnemoen 		info->erase_blk_tout = tmp *
1791e23741f4SHaavard Skinnemoen 			(1 << qry.block_erase_timeout_max);
1792e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.buf_write_timeout_typ) *
1793e23741f4SHaavard Skinnemoen 			(1 << qry.buf_write_timeout_max);
1794e23741f4SHaavard Skinnemoen 
17957e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1796e23741f4SHaavard Skinnemoen 		info->buffer_write_tout = (tmp + 999) / 1000;
1797e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.word_write_timeout_typ) *
1798e23741f4SHaavard Skinnemoen 			(1 << qry.word_write_timeout_max);
17997e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1800e23741f4SHaavard Skinnemoen 		info->write_tout = (tmp + 999) / 1000;
180159829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->flash_id = FLASH_MAN_CFI;
18027e5b9b47SHaavard Skinnemoen 		if ((info->interface == FLASH_CFI_X8X16) &&
18037e5b9b47SHaavard Skinnemoen 		    (info->chipwidth == FLASH_CFI_BY8)) {
18047e5b9b47SHaavard Skinnemoen 			/* XXX - Need to test on x8/x16 in parallel. */
18057e5b9b47SHaavard Skinnemoen 			info->portwidth >>= 1;
180659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
180759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
180859829cc1SJean-Christophe PLAGNIOL-VILLARD 
180959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
181059829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (info->size);
181159829cc1SJean-Christophe PLAGNIOL-VILLARD }
181259829cc1SJean-Christophe PLAGNIOL-VILLARD 
181359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
181459829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1815be60a902SHaavard Skinnemoen unsigned long flash_init (void)
181659829cc1SJean-Christophe PLAGNIOL-VILLARD {
1817be60a902SHaavard Skinnemoen 	unsigned long size = 0;
1818be60a902SHaavard Skinnemoen 	int i;
181959829cc1SJean-Christophe PLAGNIOL-VILLARD 
1820be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION
1821be60a902SHaavard Skinnemoen 	char *s = getenv("unlock");
182281b20cccSMichael Schwingen #endif
1823be60a902SHaavard Skinnemoen 
1824be60a902SHaavard Skinnemoen 	/* Init: no FLASHes known */
1825be60a902SHaavard Skinnemoen 	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
1826be60a902SHaavard Skinnemoen 		flash_info[i].flash_id = FLASH_UNKNOWN;
1827be60a902SHaavard Skinnemoen 
1828be60a902SHaavard Skinnemoen 		if (!flash_detect_legacy (bank_base[i], i))
1829be60a902SHaavard Skinnemoen 			flash_get_size (bank_base[i], i);
1830be60a902SHaavard Skinnemoen 		size += flash_info[i].size;
1831be60a902SHaavard Skinnemoen 		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
1832be60a902SHaavard Skinnemoen #ifndef CFG_FLASH_QUIET_TEST
1833be60a902SHaavard Skinnemoen 			printf ("## Unknown FLASH on Bank %d "
1834be60a902SHaavard Skinnemoen 				"- Size = 0x%08lx = %ld MB\n",
1835be60a902SHaavard Skinnemoen 				i+1, flash_info[i].size,
1836be60a902SHaavard Skinnemoen 				flash_info[i].size << 20);
1837be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_QUIET_TEST */
183859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1839be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION
1840be60a902SHaavard Skinnemoen 		else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
1841be60a902SHaavard Skinnemoen 			/*
1842be60a902SHaavard Skinnemoen 			 * Only the U-Boot image and it's environment
1843be60a902SHaavard Skinnemoen 			 * is protected, all other sectors are
1844be60a902SHaavard Skinnemoen 			 * unprotected (unlocked) if flash hardware
1845be60a902SHaavard Skinnemoen 			 * protection is used (CFG_FLASH_PROTECTION)
1846be60a902SHaavard Skinnemoen 			 * and the environment variable "unlock" is
1847be60a902SHaavard Skinnemoen 			 * set to "yes".
1848be60a902SHaavard Skinnemoen 			 */
1849be60a902SHaavard Skinnemoen 			if (flash_info[i].legacy_unlock) {
1850be60a902SHaavard Skinnemoen 				int k;
185159829cc1SJean-Christophe PLAGNIOL-VILLARD 
1852be60a902SHaavard Skinnemoen 				/*
1853be60a902SHaavard Skinnemoen 				 * Disable legacy_unlock temporarily,
1854be60a902SHaavard Skinnemoen 				 * since flash_real_protect would
1855be60a902SHaavard Skinnemoen 				 * relock all other sectors again
1856be60a902SHaavard Skinnemoen 				 * otherwise.
1857be60a902SHaavard Skinnemoen 				 */
1858be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 0;
185959829cc1SJean-Christophe PLAGNIOL-VILLARD 
1860be60a902SHaavard Skinnemoen 				/*
1861be60a902SHaavard Skinnemoen 				 * Legacy unlocking (e.g. Intel J3) ->
1862be60a902SHaavard Skinnemoen 				 * unlock only one sector. This will
1863be60a902SHaavard Skinnemoen 				 * unlock all sectors.
1864be60a902SHaavard Skinnemoen 				 */
1865be60a902SHaavard Skinnemoen 				flash_real_protect (&flash_info[i], 0, 0);
186659829cc1SJean-Christophe PLAGNIOL-VILLARD 
1867be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 1;
186859829cc1SJean-Christophe PLAGNIOL-VILLARD 
1869be60a902SHaavard Skinnemoen 				/*
1870be60a902SHaavard Skinnemoen 				 * Manually mark other sectors as
1871be60a902SHaavard Skinnemoen 				 * unlocked (unprotected)
1872be60a902SHaavard Skinnemoen 				 */
1873be60a902SHaavard Skinnemoen 				for (k = 1; k < flash_info[i].sector_count; k++)
1874be60a902SHaavard Skinnemoen 					flash_info[i].protect[k] = 0;
1875be60a902SHaavard Skinnemoen 			} else {
1876be60a902SHaavard Skinnemoen 				/*
1877be60a902SHaavard Skinnemoen 				 * No legancy unlocking -> unlock all sectors
1878be60a902SHaavard Skinnemoen 				 */
1879be60a902SHaavard Skinnemoen 				flash_protect (FLAG_PROTECT_CLEAR,
1880be60a902SHaavard Skinnemoen 					       flash_info[i].start[0],
1881be60a902SHaavard Skinnemoen 					       flash_info[i].start[0]
1882be60a902SHaavard Skinnemoen 					       + flash_info[i].size - 1,
1883be60a902SHaavard Skinnemoen 					       &flash_info[i]);
188459829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
188559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1886be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_PROTECTION */
188759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
188859829cc1SJean-Christophe PLAGNIOL-VILLARD 
1889be60a902SHaavard Skinnemoen 	/* Monitor protection ON by default */
1890be60a902SHaavard Skinnemoen #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
1891be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
1892be60a902SHaavard Skinnemoen 		       CFG_MONITOR_BASE,
1893be60a902SHaavard Skinnemoen 		       CFG_MONITOR_BASE + monitor_flash_len  - 1,
1894be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_MONITOR_BASE));
1895be60a902SHaavard Skinnemoen #endif
189659829cc1SJean-Christophe PLAGNIOL-VILLARD 
1897be60a902SHaavard Skinnemoen 	/* Environment protection ON by default */
1898be60a902SHaavard Skinnemoen #ifdef CFG_ENV_IS_IN_FLASH
1899be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
1900be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR,
1901be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
1902be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_ENV_ADDR));
1903be60a902SHaavard Skinnemoen #endif
1904be60a902SHaavard Skinnemoen 
1905be60a902SHaavard Skinnemoen 	/* Redundant environment protection ON by default */
1906be60a902SHaavard Skinnemoen #ifdef CFG_ENV_ADDR_REDUND
1907be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
1908be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR_REDUND,
1909be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
1910be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_ENV_ADDR_REDUND));
1911be60a902SHaavard Skinnemoen #endif
1912be60a902SHaavard Skinnemoen 	return (size);
191359829cc1SJean-Christophe PLAGNIOL-VILLARD }
191459829cc1SJean-Christophe PLAGNIOL-VILLARD 
191559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_CFI */
1916