xref: /rk3399_rockchip-uboot/drivers/mtd/cfi_flash.c (revision 3a7b2c21fb08b022e3e624cd071002b4aaed1606)
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 
4359829cc1SJean-Christophe PLAGNIOL-VILLARD /*
447e5b9b47SHaavard Skinnemoen  * This file implements a Common Flash Interface (CFI) driver for
457e5b9b47SHaavard Skinnemoen  * U-Boot.
467e5b9b47SHaavard Skinnemoen  *
477e5b9b47SHaavard Skinnemoen  * The width of the port and the width of the chips are determined at
487e5b9b47SHaavard Skinnemoen  * initialization.  These widths are used to calculate the address for
497e5b9b47SHaavard Skinnemoen  * access CFI data structures.
5059829cc1SJean-Christophe PLAGNIOL-VILLARD  *
5159829cc1SJean-Christophe PLAGNIOL-VILLARD  * References
5259829cc1SJean-Christophe PLAGNIOL-VILLARD  * JEDEC Standard JESD68 - Common Flash Interface (CFI)
5359829cc1SJean-Christophe PLAGNIOL-VILLARD  * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
5459829cc1SJean-Christophe PLAGNIOL-VILLARD  * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
5559829cc1SJean-Christophe PLAGNIOL-VILLARD  * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
5659829cc1SJean-Christophe PLAGNIOL-VILLARD  * AMD CFI Specification, Release 2.0 December 1, 2001
5759829cc1SJean-Christophe PLAGNIOL-VILLARD  * AMD/Spansion Application Note: Migration from Single-byte to Three-byte
5859829cc1SJean-Christophe PLAGNIOL-VILLARD  *   Device IDs, Publication Number 25538 Revision A, November 8, 2001
5959829cc1SJean-Christophe PLAGNIOL-VILLARD  *
606d0f6bcfSJean-Christophe PLAGNIOL-VILLARD  * Define CONFIG_SYS_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
6159829cc1SJean-Christophe PLAGNIOL-VILLARD  * reading and writing ... (yes there is such a Hardware).
6259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
6359829cc1SJean-Christophe PLAGNIOL-VILLARD 
646d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_BANKS_LIST
656d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_FLASH_BANKS_LIST { CONFIG_SYS_FLASH_BASE }
6659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
6759829cc1SJean-Christophe PLAGNIOL-VILLARD 
6859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CFI			0x98
6959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_READ_ID		0x90
7059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_RESET			0xff
7159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_BLOCK_ERASE		0x20
7259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_ERASE_CONFIRM		0xD0
7359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE			0x40
7459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT		0x60
7559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_SET		0x01
7659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_CLEAR		0xD0
7759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CLEAR_STATUS		0x50
789c048b52SVasiliy Leoenenko #define FLASH_CMD_READ_STATUS		0x70
7959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_TO_BUFFER	0xE8
809c048b52SVasiliy Leoenenko #define FLASH_CMD_WRITE_BUFFER_PROG	0xE9
8159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_BUFFER_CONFIRM	0xD0
8259829cc1SJean-Christophe PLAGNIOL-VILLARD 
8359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DONE		0x80
8459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ESS		0x40
8559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ECLBS		0x20
8659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSLBS		0x10
8759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_VPENS		0x08
8859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSS		0x04
8959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DPS		0x02
9059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_R			0x01
9159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PROTECT		0x01
9259829cc1SJean-Christophe PLAGNIOL-VILLARD 
9359829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_RESET			0xF0
9459829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE			0xA0
9559829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_START		0x80
9659829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_SECTOR		0x30
9759829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_START		0xAA
9859829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_ACK		0x55
9959829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_TO_BUFFER		0x25
10059829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_BUFFER_CONFIRM	0x29
10159829cc1SJean-Christophe PLAGNIOL-VILLARD 
10259829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_TOGGLE		0x40
10359829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_ERROR		0x20
10459829cc1SJean-Christophe PLAGNIOL-VILLARD 
105bc9019e1SRafael Campos #define ATM_CMD_UNLOCK_SECT		0x70
106bc9019e1SRafael Campos #define ATM_CMD_SOFTLOCK_START		0x80
107bc9019e1SRafael Campos #define ATM_CMD_LOCK_SECT		0x40
108bc9019e1SRafael Campos 
109*3a7b2c21SNiklaus Giger #define FLASH_CONTINUATION_CODE		0x7F
110*3a7b2c21SNiklaus Giger 
11159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_MANUFACTURER_ID	0x00
11259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID		0x01
11359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID2		0x0E
11459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID3		0x0F
11559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI		0x55
11659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_ALT		0x555
11759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_RESP		0x10
11859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PRIMARY_VENDOR	0x13
1197e5b9b47SHaavard Skinnemoen /* extended query table primary address */
1207e5b9b47SHaavard Skinnemoen #define FLASH_OFFSET_EXT_QUERY_T_P_ADDR	0x15
12159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WTOUT		0x1F
12259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBTOUT		0x20
12359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ETOUT		0x21
12459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CETOUT		0x22
12559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WMAX_TOUT		0x23
12659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBMAX_TOUT		0x24
12759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EMAX_TOUT		0x25
12859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CEMAX_TOUT		0x26
12959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_SIZE		0x27
13059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTERFACE		0x28
13159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_BUFFER_SIZE	0x2A
13259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_NUM_ERASE_REGIONS	0x2C
13359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ERASE_REGIONS	0x2D
13459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PROTECT		0x02
13559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_USER_PROTECTION	0x85
13659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTEL_PROTECTION	0x81
13759829cc1SJean-Christophe PLAGNIOL-VILLARD 
13859829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_NONE			0
13959829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_EXTENDED	1
14059829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_STANDARD		2
14159829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_STANDARD	3
14259829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_EXTENDED		4
14359829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_STANDARD	256
14459829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_EXTENDED	257
14559829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_SST			258
1469c048b52SVasiliy Leoenenko #define CFI_CMDSET_INTEL_PROG_REGIONS	512
14759829cc1SJean-Christophe PLAGNIOL-VILLARD 
1486d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
14959829cc1SJean-Christophe PLAGNIOL-VILLARD # undef  FLASH_CMD_RESET
15059829cc1SJean-Christophe PLAGNIOL-VILLARD # define FLASH_CMD_RESET	AMD_CMD_RESET /* use AMD-Reset instead */
15159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
15259829cc1SJean-Christophe PLAGNIOL-VILLARD 
15359829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union {
15459829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned char c;
15559829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned short w;
15659829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long l;
15759829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long long ll;
15859829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiword_t;
15959829cc1SJean-Christophe PLAGNIOL-VILLARD 
16059829cc1SJean-Christophe PLAGNIOL-VILLARD #define NUM_ERASE_REGIONS	4 /* max. number of erase regions */
16159829cc1SJean-Christophe PLAGNIOL-VILLARD 
16259829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
1636ea808efSPiotr Ziecik static uint flash_verbose = 1;
16459829cc1SJean-Christophe PLAGNIOL-VILLARD 
1656d0f6bcfSJean-Christophe PLAGNIOL-VILLARD /* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */
1666d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT
1676d0f6bcfSJean-Christophe PLAGNIOL-VILLARD # define CFI_MAX_FLASH_BANKS	CONFIG_SYS_MAX_FLASH_BANKS_DETECT
16859829cc1SJean-Christophe PLAGNIOL-VILLARD #else
1696d0f6bcfSJean-Christophe PLAGNIOL-VILLARD # define CFI_MAX_FLASH_BANKS	CONFIG_SYS_MAX_FLASH_BANKS
17059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
17159829cc1SJean-Christophe PLAGNIOL-VILLARD 
1722a112b23SWolfgang Denk flash_info_t flash_info[CFI_MAX_FLASH_BANKS];	/* FLASH chips info */
1732a112b23SWolfgang Denk 
17459829cc1SJean-Christophe PLAGNIOL-VILLARD /*
17559829cc1SJean-Christophe PLAGNIOL-VILLARD  * Check if chip width is defined. If not, start detecting with 8bit.
17659829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1776d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_CFI_WIDTH
1786d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_FLASH_CFI_WIDTH	FLASH_CFI_8BIT
17959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
18059829cc1SJean-Christophe PLAGNIOL-VILLARD 
181e23741f4SHaavard Skinnemoen /* CFI standard query structure */
182e23741f4SHaavard Skinnemoen struct cfi_qry {
183e23741f4SHaavard Skinnemoen 	u8	qry[3];
184e23741f4SHaavard Skinnemoen 	u16	p_id;
185e23741f4SHaavard Skinnemoen 	u16	p_adr;
186e23741f4SHaavard Skinnemoen 	u16	a_id;
187e23741f4SHaavard Skinnemoen 	u16	a_adr;
188e23741f4SHaavard Skinnemoen 	u8	vcc_min;
189e23741f4SHaavard Skinnemoen 	u8	vcc_max;
190e23741f4SHaavard Skinnemoen 	u8	vpp_min;
191e23741f4SHaavard Skinnemoen 	u8	vpp_max;
192e23741f4SHaavard Skinnemoen 	u8	word_write_timeout_typ;
193e23741f4SHaavard Skinnemoen 	u8	buf_write_timeout_typ;
194e23741f4SHaavard Skinnemoen 	u8	block_erase_timeout_typ;
195e23741f4SHaavard Skinnemoen 	u8	chip_erase_timeout_typ;
196e23741f4SHaavard Skinnemoen 	u8	word_write_timeout_max;
197e23741f4SHaavard Skinnemoen 	u8	buf_write_timeout_max;
198e23741f4SHaavard Skinnemoen 	u8	block_erase_timeout_max;
199e23741f4SHaavard Skinnemoen 	u8	chip_erase_timeout_max;
200e23741f4SHaavard Skinnemoen 	u8	dev_size;
201e23741f4SHaavard Skinnemoen 	u16	interface_desc;
202e23741f4SHaavard Skinnemoen 	u16	max_buf_write_size;
203e23741f4SHaavard Skinnemoen 	u8	num_erase_regions;
204e23741f4SHaavard Skinnemoen 	u32	erase_region_info[NUM_ERASE_REGIONS];
205e23741f4SHaavard Skinnemoen } __attribute__((packed));
206e23741f4SHaavard Skinnemoen 
207e23741f4SHaavard Skinnemoen struct cfi_pri_hdr {
208e23741f4SHaavard Skinnemoen 	u8	pri[3];
209e23741f4SHaavard Skinnemoen 	u8	major_version;
210e23741f4SHaavard Skinnemoen 	u8	minor_version;
211e23741f4SHaavard Skinnemoen } __attribute__((packed));
212e23741f4SHaavard Skinnemoen 
21345aa5a7fSStefan Roese static void __flash_write8(u8 value, void *addr)
214cdbaefb5SHaavard Skinnemoen {
215cdbaefb5SHaavard Skinnemoen 	__raw_writeb(value, addr);
216cdbaefb5SHaavard Skinnemoen }
217cdbaefb5SHaavard Skinnemoen 
21845aa5a7fSStefan Roese static void __flash_write16(u16 value, void *addr)
219cdbaefb5SHaavard Skinnemoen {
220cdbaefb5SHaavard Skinnemoen 	__raw_writew(value, addr);
221cdbaefb5SHaavard Skinnemoen }
222cdbaefb5SHaavard Skinnemoen 
22345aa5a7fSStefan Roese static void __flash_write32(u32 value, void *addr)
224cdbaefb5SHaavard Skinnemoen {
225cdbaefb5SHaavard Skinnemoen 	__raw_writel(value, addr);
226cdbaefb5SHaavard Skinnemoen }
227cdbaefb5SHaavard Skinnemoen 
22845aa5a7fSStefan Roese static void __flash_write64(u64 value, void *addr)
229cdbaefb5SHaavard Skinnemoen {
230cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_writeq() */
231cdbaefb5SHaavard Skinnemoen 	*(volatile u64 *)addr = value;
232cdbaefb5SHaavard Skinnemoen }
233cdbaefb5SHaavard Skinnemoen 
23445aa5a7fSStefan Roese static u8 __flash_read8(void *addr)
235cdbaefb5SHaavard Skinnemoen {
236cdbaefb5SHaavard Skinnemoen 	return __raw_readb(addr);
237cdbaefb5SHaavard Skinnemoen }
238cdbaefb5SHaavard Skinnemoen 
23945aa5a7fSStefan Roese static u16 __flash_read16(void *addr)
240cdbaefb5SHaavard Skinnemoen {
241cdbaefb5SHaavard Skinnemoen 	return __raw_readw(addr);
242cdbaefb5SHaavard Skinnemoen }
243cdbaefb5SHaavard Skinnemoen 
24445aa5a7fSStefan Roese static u32 __flash_read32(void *addr)
245cdbaefb5SHaavard Skinnemoen {
246cdbaefb5SHaavard Skinnemoen 	return __raw_readl(addr);
247cdbaefb5SHaavard Skinnemoen }
248cdbaefb5SHaavard Skinnemoen 
24997bf85d7SDaniel Hellstrom static u64 __flash_read64(void *addr)
250cdbaefb5SHaavard Skinnemoen {
251cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_readq() */
252cdbaefb5SHaavard Skinnemoen 	return *(volatile u64 *)addr;
253cdbaefb5SHaavard Skinnemoen }
254cdbaefb5SHaavard Skinnemoen 
25545aa5a7fSStefan Roese #ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
25645aa5a7fSStefan Roese void flash_write8(u8 value, void *addr)__attribute__((weak, alias("__flash_write8")));
25745aa5a7fSStefan Roese void flash_write16(u16 value, void *addr)__attribute__((weak, alias("__flash_write16")));
25845aa5a7fSStefan Roese void flash_write32(u32 value, void *addr)__attribute__((weak, alias("__flash_write32")));
25945aa5a7fSStefan Roese void flash_write64(u64 value, void *addr)__attribute__((weak, alias("__flash_write64")));
26045aa5a7fSStefan Roese u8 flash_read8(void *addr)__attribute__((weak, alias("__flash_read8")));
26145aa5a7fSStefan Roese u16 flash_read16(void *addr)__attribute__((weak, alias("__flash_read16")));
26245aa5a7fSStefan Roese u32 flash_read32(void *addr)__attribute__((weak, alias("__flash_read32")));
26397bf85d7SDaniel Hellstrom u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
26445aa5a7fSStefan Roese #else
26545aa5a7fSStefan Roese #define flash_write8	__flash_write8
26645aa5a7fSStefan Roese #define flash_write16	__flash_write16
26745aa5a7fSStefan Roese #define flash_write32	__flash_write32
26845aa5a7fSStefan Roese #define flash_write64	__flash_write64
26945aa5a7fSStefan Roese #define flash_read8	__flash_read8
27045aa5a7fSStefan Roese #define flash_read16	__flash_read16
27145aa5a7fSStefan Roese #define flash_read32	__flash_read32
27245aa5a7fSStefan Roese #define flash_read64	__flash_read64
27345aa5a7fSStefan Roese #endif
27497bf85d7SDaniel Hellstrom 
275be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
276be60a902SHaavard Skinnemoen  */
2776d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
2784f975678SHeiko Schocher flash_info_t *flash_get_info(ulong base)
279be60a902SHaavard Skinnemoen {
280be60a902SHaavard Skinnemoen 	int i;
281be60a902SHaavard Skinnemoen 	flash_info_t * info = 0;
282be60a902SHaavard Skinnemoen 
2836d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
284be60a902SHaavard Skinnemoen 		info = & flash_info[i];
285be60a902SHaavard Skinnemoen 		if (info->size && info->start[0] <= base &&
286be60a902SHaavard Skinnemoen 		    base <= info->start[0] + info->size - 1)
287be60a902SHaavard Skinnemoen 			break;
288be60a902SHaavard Skinnemoen 	}
289be60a902SHaavard Skinnemoen 
2906d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
291be60a902SHaavard Skinnemoen }
29259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
29359829cc1SJean-Christophe PLAGNIOL-VILLARD 
29412d30aa7SHaavard Skinnemoen unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
29512d30aa7SHaavard Skinnemoen {
29612d30aa7SHaavard Skinnemoen 	if (sect != (info->sector_count - 1))
29712d30aa7SHaavard Skinnemoen 		return info->start[sect + 1] - info->start[sect];
29812d30aa7SHaavard Skinnemoen 	else
29912d30aa7SHaavard Skinnemoen 		return info->start[0] + info->size - info->start[sect];
30012d30aa7SHaavard Skinnemoen }
30112d30aa7SHaavard Skinnemoen 
30259829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
30359829cc1SJean-Christophe PLAGNIOL-VILLARD  * create an address based on the offset and the port width
30459829cc1SJean-Christophe PLAGNIOL-VILLARD  */
30512d30aa7SHaavard Skinnemoen static inline void *
30612d30aa7SHaavard Skinnemoen flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
30759829cc1SJean-Christophe PLAGNIOL-VILLARD {
30812d30aa7SHaavard Skinnemoen 	unsigned int byte_offset = offset * info->portwidth;
30912d30aa7SHaavard Skinnemoen 
31009ce9921SBecky Bruce 	return (void *)(info->start[sect] + byte_offset);
31112d30aa7SHaavard Skinnemoen }
31212d30aa7SHaavard Skinnemoen 
31312d30aa7SHaavard Skinnemoen static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
31412d30aa7SHaavard Skinnemoen 		unsigned int offset, void *addr)
31512d30aa7SHaavard Skinnemoen {
31659829cc1SJean-Christophe PLAGNIOL-VILLARD }
31759829cc1SJean-Christophe PLAGNIOL-VILLARD 
318be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
319be60a902SHaavard Skinnemoen  * make a proper sized command based on the port and chip widths
320be60a902SHaavard Skinnemoen  */
3217288f972SSebastian Siewior static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
322be60a902SHaavard Skinnemoen {
323be60a902SHaavard Skinnemoen 	int i;
32493c56f21SVasiliy Leoenenko 	int cword_offset;
32593c56f21SVasiliy Leoenenko 	int cp_offset;
3266d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
327340ccb26SSebastian Siewior 	u32 cmd_le = cpu_to_le32(cmd);
328340ccb26SSebastian Siewior #endif
32993c56f21SVasiliy Leoenenko 	uchar val;
330be60a902SHaavard Skinnemoen 	uchar *cp = (uchar *) cmdbuf;
331be60a902SHaavard Skinnemoen 
33293c56f21SVasiliy Leoenenko 	for (i = info->portwidth; i > 0; i--){
33393c56f21SVasiliy Leoenenko 		cword_offset = (info->portwidth-i)%info->chipwidth;
3346d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
33593c56f21SVasiliy Leoenenko 		cp_offset = info->portwidth - i;
336340ccb26SSebastian Siewior 		val = *((uchar*)&cmd_le + cword_offset);
337be60a902SHaavard Skinnemoen #else
33893c56f21SVasiliy Leoenenko 		cp_offset = i - 1;
3397288f972SSebastian Siewior 		val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1);
340be60a902SHaavard Skinnemoen #endif
3417288f972SSebastian Siewior 		cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
34293c56f21SVasiliy Leoenenko 	}
343be60a902SHaavard Skinnemoen }
344be60a902SHaavard Skinnemoen 
34559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
34659829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
34759829cc1SJean-Christophe PLAGNIOL-VILLARD  * Debug support
34859829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3493055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data)
35059829cc1SJean-Christophe PLAGNIOL-VILLARD {
35159829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
35259829cc1SJean-Christophe PLAGNIOL-VILLARD 	char *cp;
35359829cc1SJean-Christophe PLAGNIOL-VILLARD 
354657f2062SWolfgang Denk 	cp = (char *) &data;
35559829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 8; i++)
35659829cc1SJean-Christophe PLAGNIOL-VILLARD 		sprintf (&str[i * 2], "%2.2x", *cp++);
35759829cc1SJean-Christophe PLAGNIOL-VILLARD }
358be60a902SHaavard Skinnemoen 
359e23741f4SHaavard Skinnemoen static void flash_printqry (struct cfi_qry *qry)
36059829cc1SJean-Christophe PLAGNIOL-VILLARD {
361e23741f4SHaavard Skinnemoen 	u8 *p = (u8 *)qry;
36259829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x, y;
36359829cc1SJean-Christophe PLAGNIOL-VILLARD 
364e23741f4SHaavard Skinnemoen 	for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
365e23741f4SHaavard Skinnemoen 		debug("%02x : ", x);
366e23741f4SHaavard Skinnemoen 		for (y = 0; y < 16; y++)
367e23741f4SHaavard Skinnemoen 			debug("%2.2x ", p[x + y]);
36859829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug(" ");
36959829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (y = 0; y < 16; y++) {
370e23741f4SHaavard Skinnemoen 			unsigned char c = p[x + y];
371e23741f4SHaavard Skinnemoen 			if (c >= 0x20 && c <= 0x7e)
372cdbaefb5SHaavard Skinnemoen 				debug("%c", c);
373e23741f4SHaavard Skinnemoen 			else
37459829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug(".");
37559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
37659829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug("\n");
37759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
37859829cc1SJean-Christophe PLAGNIOL-VILLARD }
37959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
38059829cc1SJean-Christophe PLAGNIOL-VILLARD 
38159829cc1SJean-Christophe PLAGNIOL-VILLARD 
38259829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
38359829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a character at a port width address
38459829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3853055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
38659829cc1SJean-Christophe PLAGNIOL-VILLARD {
38759829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *cp;
38812d30aa7SHaavard Skinnemoen 	uchar retval;
38959829cc1SJean-Christophe PLAGNIOL-VILLARD 
39012d30aa7SHaavard Skinnemoen 	cp = flash_map (info, 0, offset);
3916d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
39212d30aa7SHaavard Skinnemoen 	retval = flash_read8(cp);
39359829cc1SJean-Christophe PLAGNIOL-VILLARD #else
39412d30aa7SHaavard Skinnemoen 	retval = flash_read8(cp + info->portwidth - 1);
39559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
39612d30aa7SHaavard Skinnemoen 	flash_unmap (info, 0, offset, cp);
39712d30aa7SHaavard Skinnemoen 	return retval;
39859829cc1SJean-Christophe PLAGNIOL-VILLARD }
39959829cc1SJean-Christophe PLAGNIOL-VILLARD 
40059829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
40190447ecbSTor Krill  * read a word at a port width address, assume 16bit bus
40290447ecbSTor Krill  */
40390447ecbSTor Krill static inline ushort flash_read_word (flash_info_t * info, uint offset)
40490447ecbSTor Krill {
40590447ecbSTor Krill 	ushort *addr, retval;
40690447ecbSTor Krill 
40790447ecbSTor Krill 	addr = flash_map (info, 0, offset);
40890447ecbSTor Krill 	retval = flash_read16 (addr);
40990447ecbSTor Krill 	flash_unmap (info, 0, offset, addr);
41090447ecbSTor Krill 	return retval;
41190447ecbSTor Krill }
41290447ecbSTor Krill 
41390447ecbSTor Krill 
41490447ecbSTor Krill /*-----------------------------------------------------------------------
41559829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a long word by picking the least significant byte of each maximum
41659829cc1SJean-Christophe PLAGNIOL-VILLARD  * port size word. Swap for ppc format.
41759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
4183055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
4193055793bSHaavard Skinnemoen 			      uint offset)
42059829cc1SJean-Christophe PLAGNIOL-VILLARD {
42159829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *addr;
42259829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong retval;
42359829cc1SJean-Christophe PLAGNIOL-VILLARD 
42459829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
42559829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x;
42659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
42712d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
42859829cc1SJean-Christophe PLAGNIOL-VILLARD 
42959829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
43059829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("long addr is at %p info->portwidth = %d\n", addr,
43159829cc1SJean-Christophe PLAGNIOL-VILLARD 	       info->portwidth);
43259829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (x = 0; x < 4 * info->portwidth; x++) {
43312d30aa7SHaavard Skinnemoen 		debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
43459829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
43559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
4366d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
43712d30aa7SHaavard Skinnemoen 	retval = ((flash_read8(addr) << 16) |
43812d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + info->portwidth) << 24) |
43912d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 2 * info->portwidth)) |
44012d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 3 * info->portwidth) << 8));
44159829cc1SJean-Christophe PLAGNIOL-VILLARD #else
44212d30aa7SHaavard Skinnemoen 	retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
44312d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + info->portwidth - 1) << 16) |
44412d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
44512d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 3 * info->portwidth - 1)));
44659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
44712d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
44812d30aa7SHaavard Skinnemoen 
44959829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
45059829cc1SJean-Christophe PLAGNIOL-VILLARD }
45159829cc1SJean-Christophe PLAGNIOL-VILLARD 
452be60a902SHaavard Skinnemoen /*
453be60a902SHaavard Skinnemoen  * Write a proper sized command to the correct address
45481b20cccSMichael Schwingen  */
455be60a902SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
4567288f972SSebastian Siewior 			     uint offset, u32 cmd)
45781b20cccSMichael Schwingen {
4587e5b9b47SHaavard Skinnemoen 
459cdbaefb5SHaavard Skinnemoen 	void *addr;
460be60a902SHaavard Skinnemoen 	cfiword_t cword;
46181b20cccSMichael Schwingen 
46212d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
463be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
464be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
465be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
466cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
467be60a902SHaavard Skinnemoen 		       cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
468cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, addr);
469be60a902SHaavard Skinnemoen 		break;
470be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
471cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
472be60a902SHaavard Skinnemoen 		       cmd, cword.w,
473be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
474cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, addr);
475be60a902SHaavard Skinnemoen 		break;
476be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
477cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
478be60a902SHaavard Skinnemoen 		       cmd, cword.l,
479be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
480cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, addr);
481be60a902SHaavard Skinnemoen 		break;
482be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
483be60a902SHaavard Skinnemoen #ifdef DEBUG
484be60a902SHaavard Skinnemoen 		{
485be60a902SHaavard Skinnemoen 			char str[20];
486be60a902SHaavard Skinnemoen 
487be60a902SHaavard Skinnemoen 			print_longlong (str, cword.ll);
488be60a902SHaavard Skinnemoen 
489be60a902SHaavard Skinnemoen 			debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
490cdbaefb5SHaavard Skinnemoen 			       addr, cmd, str,
491be60a902SHaavard Skinnemoen 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
49281b20cccSMichael Schwingen 		}
493be60a902SHaavard Skinnemoen #endif
494cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, addr);
49581b20cccSMichael Schwingen 		break;
49681b20cccSMichael Schwingen 	}
497be60a902SHaavard Skinnemoen 
498be60a902SHaavard Skinnemoen 	/* Ensure all the instructions are fully finished */
499be60a902SHaavard Skinnemoen 	sync();
50012d30aa7SHaavard Skinnemoen 
50112d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
50281b20cccSMichael Schwingen }
5037e5b9b47SHaavard Skinnemoen 
504be60a902SHaavard Skinnemoen static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
505be60a902SHaavard Skinnemoen {
506be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
507be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
508be60a902SHaavard Skinnemoen }
509be60a902SHaavard Skinnemoen 
510be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
511be60a902SHaavard Skinnemoen  */
512be60a902SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect,
513be60a902SHaavard Skinnemoen 			  uint offset, uchar cmd)
514be60a902SHaavard Skinnemoen {
515cdbaefb5SHaavard Skinnemoen 	void *addr;
516be60a902SHaavard Skinnemoen 	cfiword_t cword;
517be60a902SHaavard Skinnemoen 	int retval;
518be60a902SHaavard Skinnemoen 
51912d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
520be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
521be60a902SHaavard Skinnemoen 
522cdbaefb5SHaavard Skinnemoen 	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
523be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
524be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
525cdbaefb5SHaavard Skinnemoen 		debug ("is= %x %x\n", flash_read8(addr), cword.c);
526cdbaefb5SHaavard Skinnemoen 		retval = (flash_read8(addr) == cword.c);
527be60a902SHaavard Skinnemoen 		break;
528be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
529cdbaefb5SHaavard Skinnemoen 		debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
530cdbaefb5SHaavard Skinnemoen 		retval = (flash_read16(addr) == cword.w);
531be60a902SHaavard Skinnemoen 		break;
532be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
53352514699SAndrew Klossner 		debug ("is= %8.8x %8.8lx\n", flash_read32(addr), cword.l);
534cdbaefb5SHaavard Skinnemoen 		retval = (flash_read32(addr) == cword.l);
535be60a902SHaavard Skinnemoen 		break;
536be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
537be60a902SHaavard Skinnemoen #ifdef DEBUG
538be60a902SHaavard Skinnemoen 		{
539be60a902SHaavard Skinnemoen 			char str1[20];
540be60a902SHaavard Skinnemoen 			char str2[20];
541be60a902SHaavard Skinnemoen 
542cdbaefb5SHaavard Skinnemoen 			print_longlong (str1, flash_read64(addr));
543be60a902SHaavard Skinnemoen 			print_longlong (str2, cword.ll);
544be60a902SHaavard Skinnemoen 			debug ("is= %s %s\n", str1, str2);
545be60a902SHaavard Skinnemoen 		}
546be60a902SHaavard Skinnemoen #endif
547cdbaefb5SHaavard Skinnemoen 		retval = (flash_read64(addr) == cword.ll);
548be60a902SHaavard Skinnemoen 		break;
549be60a902SHaavard Skinnemoen 	default:
550be60a902SHaavard Skinnemoen 		retval = 0;
551be60a902SHaavard Skinnemoen 		break;
552be60a902SHaavard Skinnemoen 	}
55312d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
55412d30aa7SHaavard Skinnemoen 
555be60a902SHaavard Skinnemoen 	return retval;
556be60a902SHaavard Skinnemoen }
557be60a902SHaavard Skinnemoen 
558be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
559be60a902SHaavard Skinnemoen  */
560be60a902SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect,
561be60a902SHaavard Skinnemoen 			uint offset, uchar cmd)
562be60a902SHaavard Skinnemoen {
563cdbaefb5SHaavard Skinnemoen 	void *addr;
564be60a902SHaavard Skinnemoen 	cfiword_t cword;
565be60a902SHaavard Skinnemoen 	int retval;
566be60a902SHaavard Skinnemoen 
56712d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
568be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
569be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
570be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
571cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read8(addr) & cword.c) == cword.c);
572be60a902SHaavard Skinnemoen 		break;
573be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
574cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read16(addr) & cword.w) == cword.w);
575be60a902SHaavard Skinnemoen 		break;
576be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
57747cc23cbSStefan Roese 		retval = ((flash_read32(addr) & cword.l) == cword.l);
578be60a902SHaavard Skinnemoen 		break;
579be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
580cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read64(addr) & cword.ll) == cword.ll);
581be60a902SHaavard Skinnemoen 		break;
582be60a902SHaavard Skinnemoen 	default:
583be60a902SHaavard Skinnemoen 		retval = 0;
584be60a902SHaavard Skinnemoen 		break;
585be60a902SHaavard Skinnemoen 	}
58612d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
58712d30aa7SHaavard Skinnemoen 
588be60a902SHaavard Skinnemoen 	return retval;
589be60a902SHaavard Skinnemoen }
590be60a902SHaavard Skinnemoen 
591be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
592be60a902SHaavard Skinnemoen  */
593be60a902SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect,
594be60a902SHaavard Skinnemoen 			 uint offset, uchar cmd)
595be60a902SHaavard Skinnemoen {
596cdbaefb5SHaavard Skinnemoen 	void *addr;
597be60a902SHaavard Skinnemoen 	cfiword_t cword;
598be60a902SHaavard Skinnemoen 	int retval;
599be60a902SHaavard Skinnemoen 
60012d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
601be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
602be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
603be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
604fb8c061eSStefan Roese 		retval = flash_read8(addr) != flash_read8(addr);
605be60a902SHaavard Skinnemoen 		break;
606be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
607fb8c061eSStefan Roese 		retval = flash_read16(addr) != flash_read16(addr);
608be60a902SHaavard Skinnemoen 		break;
609be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
610fb8c061eSStefan Roese 		retval = flash_read32(addr) != flash_read32(addr);
611be60a902SHaavard Skinnemoen 		break;
612be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
6139abda6baSWolfgang Denk 		retval = ( (flash_read32( addr ) != flash_read32( addr )) ||
6149abda6baSWolfgang Denk 			   (flash_read32(addr+4) != flash_read32(addr+4)) );
615be60a902SHaavard Skinnemoen 		break;
616be60a902SHaavard Skinnemoen 	default:
617be60a902SHaavard Skinnemoen 		retval = 0;
618be60a902SHaavard Skinnemoen 		break;
619be60a902SHaavard Skinnemoen 	}
62012d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
62112d30aa7SHaavard Skinnemoen 
622be60a902SHaavard Skinnemoen 	return retval;
623be60a902SHaavard Skinnemoen }
624be60a902SHaavard Skinnemoen 
625be60a902SHaavard Skinnemoen /*
626be60a902SHaavard Skinnemoen  * flash_is_busy - check to see if the flash is busy
627be60a902SHaavard Skinnemoen  *
628be60a902SHaavard Skinnemoen  * This routine checks the status of the chip and returns true if the
629be60a902SHaavard Skinnemoen  * chip is busy.
630be60a902SHaavard Skinnemoen  */
631be60a902SHaavard Skinnemoen static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
632be60a902SHaavard Skinnemoen {
633be60a902SHaavard Skinnemoen 	int retval;
634be60a902SHaavard Skinnemoen 
63581b20cccSMichael Schwingen 	switch (info->vendor) {
6369c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
63781b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_STANDARD:
63881b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_EXTENDED:
639be60a902SHaavard Skinnemoen 		retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
64081b20cccSMichael Schwingen 		break;
64181b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_STANDARD:
64281b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_EXTENDED:
643be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
64481b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_LEGACY:
645be60a902SHaavard Skinnemoen #endif
646be60a902SHaavard Skinnemoen 		retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
647be60a902SHaavard Skinnemoen 		break;
648be60a902SHaavard Skinnemoen 	default:
649be60a902SHaavard Skinnemoen 		retval = 0;
650be60a902SHaavard Skinnemoen 	}
651be60a902SHaavard Skinnemoen 	debug ("flash_is_busy: %d\n", retval);
652be60a902SHaavard Skinnemoen 	return retval;
653be60a902SHaavard Skinnemoen }
654be60a902SHaavard Skinnemoen 
655be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
656be60a902SHaavard Skinnemoen  *  wait for XSR.7 to be set. Time out with an error if it does not.
657be60a902SHaavard Skinnemoen  *  This routine does not set the flash to read-array mode.
658be60a902SHaavard Skinnemoen  */
659be60a902SHaavard Skinnemoen static int flash_status_check (flash_info_t * info, flash_sect_t sector,
660be60a902SHaavard Skinnemoen 			       ulong tout, char *prompt)
661be60a902SHaavard Skinnemoen {
662be60a902SHaavard Skinnemoen 	ulong start;
663be60a902SHaavard Skinnemoen 
6646d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if CONFIG_SYS_HZ != 1000
6656d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	tout *= CONFIG_SYS_HZ/1000;
666be60a902SHaavard Skinnemoen #endif
667be60a902SHaavard Skinnemoen 
668be60a902SHaavard Skinnemoen 	/* Wait for command completion */
669be60a902SHaavard Skinnemoen 	start = get_timer (0);
670be60a902SHaavard Skinnemoen 	while (flash_is_busy (info, sector)) {
671be60a902SHaavard Skinnemoen 		if (get_timer (start) > tout) {
672be60a902SHaavard Skinnemoen 			printf ("Flash %s timeout at address %lx data %lx\n",
673be60a902SHaavard Skinnemoen 				prompt, info->start[sector],
674be60a902SHaavard Skinnemoen 				flash_read_long (info, sector, 0));
675be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0, info->cmd_reset);
676be60a902SHaavard Skinnemoen 			return ERR_TIMOUT;
677be60a902SHaavard Skinnemoen 		}
678be60a902SHaavard Skinnemoen 		udelay (1);		/* also triggers watchdog */
679be60a902SHaavard Skinnemoen 	}
680be60a902SHaavard Skinnemoen 	return ERR_OK;
681be60a902SHaavard Skinnemoen }
682be60a902SHaavard Skinnemoen 
683be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
684be60a902SHaavard Skinnemoen  * Wait for XSR.7 to be set, if it times out print an error, otherwise
685be60a902SHaavard Skinnemoen  * do a full status check.
686be60a902SHaavard Skinnemoen  *
687be60a902SHaavard Skinnemoen  * This routine sets the flash to read-array mode.
688be60a902SHaavard Skinnemoen  */
689be60a902SHaavard Skinnemoen static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
690be60a902SHaavard Skinnemoen 				    ulong tout, char *prompt)
691be60a902SHaavard Skinnemoen {
692be60a902SHaavard Skinnemoen 	int retcode;
693be60a902SHaavard Skinnemoen 
694be60a902SHaavard Skinnemoen 	retcode = flash_status_check (info, sector, tout, prompt);
695be60a902SHaavard Skinnemoen 	switch (info->vendor) {
6969c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
697be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
698be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
6990d01f66dSEd Swarthout 		if ((retcode != ERR_OK)
700be60a902SHaavard Skinnemoen 		    && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
701be60a902SHaavard Skinnemoen 			retcode = ERR_INVAL;
702be60a902SHaavard Skinnemoen 			printf ("Flash %s error at address %lx\n", prompt,
703be60a902SHaavard Skinnemoen 				info->start[sector]);
704be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
705be60a902SHaavard Skinnemoen 					 FLASH_STATUS_PSLBS)) {
706be60a902SHaavard Skinnemoen 				puts ("Command Sequence Error.\n");
707be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
708be60a902SHaavard Skinnemoen 						FLASH_STATUS_ECLBS)) {
709be60a902SHaavard Skinnemoen 				puts ("Block Erase Error.\n");
710be60a902SHaavard Skinnemoen 				retcode = ERR_NOT_ERASED;
711be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
712be60a902SHaavard Skinnemoen 						FLASH_STATUS_PSLBS)) {
713be60a902SHaavard Skinnemoen 				puts ("Locking Error\n");
714be60a902SHaavard Skinnemoen 			}
715be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
716be60a902SHaavard Skinnemoen 				puts ("Block locked.\n");
717be60a902SHaavard Skinnemoen 				retcode = ERR_PROTECTED;
718be60a902SHaavard Skinnemoen 			}
719be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
720be60a902SHaavard Skinnemoen 				puts ("Vpp Low Error.\n");
721be60a902SHaavard Skinnemoen 		}
722be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, info->cmd_reset);
723be60a902SHaavard Skinnemoen 		break;
724be60a902SHaavard Skinnemoen 	default:
72581b20cccSMichael Schwingen 		break;
72681b20cccSMichael Schwingen 	}
727be60a902SHaavard Skinnemoen 	return retcode;
72881b20cccSMichael Schwingen }
729be60a902SHaavard Skinnemoen 
730be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
731be60a902SHaavard Skinnemoen  */
732be60a902SHaavard Skinnemoen static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
733be60a902SHaavard Skinnemoen {
7346d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
735be60a902SHaavard Skinnemoen 	unsigned short	w;
736be60a902SHaavard Skinnemoen 	unsigned int	l;
737be60a902SHaavard Skinnemoen 	unsigned long long ll;
738be60a902SHaavard Skinnemoen #endif
739be60a902SHaavard Skinnemoen 
740be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
741be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
742be60a902SHaavard Skinnemoen 		cword->c = c;
743be60a902SHaavard Skinnemoen 		break;
744be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
7456d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
746be60a902SHaavard Skinnemoen 		w = c;
747be60a902SHaavard Skinnemoen 		w <<= 8;
748be60a902SHaavard Skinnemoen 		cword->w = (cword->w >> 8) | w;
74981b20cccSMichael Schwingen #else
750be60a902SHaavard Skinnemoen 		cword->w = (cword->w << 8) | c;
751be60a902SHaavard Skinnemoen #endif
752be60a902SHaavard Skinnemoen 		break;
753be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
7546d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
755be60a902SHaavard Skinnemoen 		l = c;
756be60a902SHaavard Skinnemoen 		l <<= 24;
757be60a902SHaavard Skinnemoen 		cword->l = (cword->l >> 8) | l;
758be60a902SHaavard Skinnemoen #else
759be60a902SHaavard Skinnemoen 		cword->l = (cword->l << 8) | c;
760be60a902SHaavard Skinnemoen #endif
761be60a902SHaavard Skinnemoen 		break;
762be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
7636d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
764be60a902SHaavard Skinnemoen 		ll = c;
765be60a902SHaavard Skinnemoen 		ll <<= 56;
766be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll >> 8) | ll;
767be60a902SHaavard Skinnemoen #else
768be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll << 8) | c;
769be60a902SHaavard Skinnemoen #endif
770be60a902SHaavard Skinnemoen 		break;
771be60a902SHaavard Skinnemoen 	}
772be60a902SHaavard Skinnemoen }
773be60a902SHaavard Skinnemoen 
7740f8e851eSJens Gehrlein /*
7750f8e851eSJens Gehrlein  * Loop through the sector table starting from the previously found sector.
7760f8e851eSJens Gehrlein  * Searches forwards or backwards, dependent on the passed address.
777be60a902SHaavard Skinnemoen  */
778be60a902SHaavard Skinnemoen static flash_sect_t find_sector (flash_info_t * info, ulong addr)
77981b20cccSMichael Schwingen {
7800f8e851eSJens Gehrlein 	static flash_sect_t saved_sector = 0; /* previously found sector */
7810f8e851eSJens Gehrlein 	flash_sect_t sector = saved_sector;
782be60a902SHaavard Skinnemoen 
7830f8e851eSJens Gehrlein 	while ((info->start[sector] < addr)
7840f8e851eSJens Gehrlein 			&& (sector < info->sector_count - 1))
7850f8e851eSJens Gehrlein 		sector++;
7860f8e851eSJens Gehrlein 	while ((info->start[sector] > addr) && (sector > 0))
7870f8e851eSJens Gehrlein 		/*
7880f8e851eSJens Gehrlein 		 * also decrements the sector in case of an overshot
7890f8e851eSJens Gehrlein 		 * in the first loop
7900f8e851eSJens Gehrlein 		 */
7910f8e851eSJens Gehrlein 		sector--;
7920f8e851eSJens Gehrlein 
7930f8e851eSJens Gehrlein 	saved_sector = sector;
794be60a902SHaavard Skinnemoen 	return sector;
79559829cc1SJean-Christophe PLAGNIOL-VILLARD }
79659829cc1SJean-Christophe PLAGNIOL-VILLARD 
79759829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
79859829cc1SJean-Christophe PLAGNIOL-VILLARD  */
799be60a902SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest,
800be60a902SHaavard Skinnemoen 				cfiword_t cword)
80159829cc1SJean-Christophe PLAGNIOL-VILLARD {
80209ce9921SBecky Bruce 	void *dstaddr = (void *)dest;
803be60a902SHaavard Skinnemoen 	int flag;
804a7292871SJens Gehrlein 	flash_sect_t sect = 0;
805a7292871SJens Gehrlein 	char sect_found = 0;
80659829cc1SJean-Christophe PLAGNIOL-VILLARD 
807be60a902SHaavard Skinnemoen 	/* Check if Flash is (sufficiently) erased */
808be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
809be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
810cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
811be60a902SHaavard Skinnemoen 		break;
812be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
813cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
814be60a902SHaavard Skinnemoen 		break;
815be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
816cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
817be60a902SHaavard Skinnemoen 		break;
818be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
819cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
820be60a902SHaavard Skinnemoen 		break;
821be60a902SHaavard Skinnemoen 	default:
82212d30aa7SHaavard Skinnemoen 		flag = 0;
82312d30aa7SHaavard Skinnemoen 		break;
82412d30aa7SHaavard Skinnemoen 	}
82509ce9921SBecky Bruce 	if (!flag)
8260dc80e27SStefan Roese 		return ERR_NOT_ERASED;
827be60a902SHaavard Skinnemoen 
828be60a902SHaavard Skinnemoen 	/* Disable interrupts which might cause a timeout here */
829be60a902SHaavard Skinnemoen 	flag = disable_interrupts ();
830be60a902SHaavard Skinnemoen 
831be60a902SHaavard Skinnemoen 	switch (info->vendor) {
8329c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
833be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
834be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
835be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
836be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
837be60a902SHaavard Skinnemoen 		break;
838be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
839be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
8400d01f66dSEd Swarthout 		sect = find_sector(info, dest);
8410d01f66dSEd Swarthout 		flash_unlock_seq (info, sect);
8420d01f66dSEd Swarthout 		flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE);
843a7292871SJens Gehrlein 		sect_found = 1;
84459829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
845b4db4a76SPo-Yu Chuang #ifdef CONFIG_FLASH_CFI_LEGACY
846b4db4a76SPo-Yu Chuang 	case CFI_CMDSET_AMD_LEGACY:
847b4db4a76SPo-Yu Chuang 		sect = find_sector(info, dest);
848b4db4a76SPo-Yu Chuang 		flash_unlock_seq (info, 0);
849b4db4a76SPo-Yu Chuang 		flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
850b4db4a76SPo-Yu Chuang 		sect_found = 1;
851b4db4a76SPo-Yu Chuang 		break;
852b4db4a76SPo-Yu Chuang #endif
85359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
85459829cc1SJean-Christophe PLAGNIOL-VILLARD 
855be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
856be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
857cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, dstaddr);
858be60a902SHaavard Skinnemoen 		break;
859be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
860cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, dstaddr);
861be60a902SHaavard Skinnemoen 		break;
862be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
863cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, dstaddr);
864be60a902SHaavard Skinnemoen 		break;
865be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
866cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, dstaddr);
867be60a902SHaavard Skinnemoen 		break;
86859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
869be60a902SHaavard Skinnemoen 
870be60a902SHaavard Skinnemoen 	/* re-enable interrupts if necessary */
871be60a902SHaavard Skinnemoen 	if (flag)
872be60a902SHaavard Skinnemoen 		enable_interrupts ();
873be60a902SHaavard Skinnemoen 
874a7292871SJens Gehrlein 	if (!sect_found)
875a7292871SJens Gehrlein 		sect = find_sector (info, dest);
876a7292871SJens Gehrlein 
877a7292871SJens Gehrlein 	return flash_full_status_check (info, sect, info->write_tout, "write");
878be60a902SHaavard Skinnemoen }
879be60a902SHaavard Skinnemoen 
8806d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
881be60a902SHaavard Skinnemoen 
882be60a902SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
883be60a902SHaavard Skinnemoen 				  int len)
884be60a902SHaavard Skinnemoen {
885be60a902SHaavard Skinnemoen 	flash_sect_t sector;
886be60a902SHaavard Skinnemoen 	int cnt;
887be60a902SHaavard Skinnemoen 	int retcode;
888cdbaefb5SHaavard Skinnemoen 	void *src = cp;
889ec21d5cfSStefan Roese 	void *dst = (void *)dest;
8900dc80e27SStefan Roese 	void *dst2 = dst;
8910dc80e27SStefan Roese 	int flag = 0;
89296ef831fSGuennadi Liakhovetski 	uint offset = 0;
89396ef831fSGuennadi Liakhovetski 	unsigned int shift;
8949c048b52SVasiliy Leoenenko 	uchar write_cmd;
895cdbaefb5SHaavard Skinnemoen 
8960dc80e27SStefan Roese 	switch (info->portwidth) {
8970dc80e27SStefan Roese 	case FLASH_CFI_8BIT:
89896ef831fSGuennadi Liakhovetski 		shift = 0;
8990dc80e27SStefan Roese 		break;
9000dc80e27SStefan Roese 	case FLASH_CFI_16BIT:
90196ef831fSGuennadi Liakhovetski 		shift = 1;
9020dc80e27SStefan Roese 		break;
9030dc80e27SStefan Roese 	case FLASH_CFI_32BIT:
90496ef831fSGuennadi Liakhovetski 		shift = 2;
9050dc80e27SStefan Roese 		break;
9060dc80e27SStefan Roese 	case FLASH_CFI_64BIT:
90796ef831fSGuennadi Liakhovetski 		shift = 3;
9080dc80e27SStefan Roese 		break;
9090dc80e27SStefan Roese 	default:
9100dc80e27SStefan Roese 		retcode = ERR_INVAL;
9110dc80e27SStefan Roese 		goto out_unmap;
9120dc80e27SStefan Roese 	}
9130dc80e27SStefan Roese 
91496ef831fSGuennadi Liakhovetski 	cnt = len >> shift;
91596ef831fSGuennadi Liakhovetski 
9160dc80e27SStefan Roese 	while ((cnt-- > 0) && (flag == 0)) {
9170dc80e27SStefan Roese 		switch (info->portwidth) {
9180dc80e27SStefan Roese 		case FLASH_CFI_8BIT:
9190dc80e27SStefan Roese 			flag = ((flash_read8(dst2) & flash_read8(src)) ==
9200dc80e27SStefan Roese 				flash_read8(src));
9210dc80e27SStefan Roese 			src += 1, dst2 += 1;
9220dc80e27SStefan Roese 			break;
9230dc80e27SStefan Roese 		case FLASH_CFI_16BIT:
9240dc80e27SStefan Roese 			flag = ((flash_read16(dst2) & flash_read16(src)) ==
9250dc80e27SStefan Roese 				flash_read16(src));
9260dc80e27SStefan Roese 			src += 2, dst2 += 2;
9270dc80e27SStefan Roese 			break;
9280dc80e27SStefan Roese 		case FLASH_CFI_32BIT:
9290dc80e27SStefan Roese 			flag = ((flash_read32(dst2) & flash_read32(src)) ==
9300dc80e27SStefan Roese 				flash_read32(src));
9310dc80e27SStefan Roese 			src += 4, dst2 += 4;
9320dc80e27SStefan Roese 			break;
9330dc80e27SStefan Roese 		case FLASH_CFI_64BIT:
9340dc80e27SStefan Roese 			flag = ((flash_read64(dst2) & flash_read64(src)) ==
9350dc80e27SStefan Roese 				flash_read64(src));
9360dc80e27SStefan Roese 			src += 8, dst2 += 8;
9370dc80e27SStefan Roese 			break;
9380dc80e27SStefan Roese 		}
9390dc80e27SStefan Roese 	}
9400dc80e27SStefan Roese 	if (!flag) {
9410dc80e27SStefan Roese 		retcode = ERR_NOT_ERASED;
9420dc80e27SStefan Roese 		goto out_unmap;
9430dc80e27SStefan Roese 	}
9440dc80e27SStefan Roese 
9450dc80e27SStefan Roese 	src = cp;
946cdbaefb5SHaavard Skinnemoen 	sector = find_sector (info, dest);
947be60a902SHaavard Skinnemoen 
948be60a902SHaavard Skinnemoen 	switch (info->vendor) {
9499c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
950be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
951be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
9529c048b52SVasiliy Leoenenko 		write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
9539c048b52SVasiliy Leoenenko 					FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER;
954be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
9559c048b52SVasiliy Leoenenko 		flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS);
9569c048b52SVasiliy Leoenenko 		flash_write_cmd (info, sector, 0, write_cmd);
957be60a902SHaavard Skinnemoen 		retcode = flash_status_check (info, sector,
958be60a902SHaavard Skinnemoen 					      info->buffer_write_tout,
959be60a902SHaavard Skinnemoen 					      "write to buffer");
960be60a902SHaavard Skinnemoen 		if (retcode == ERR_OK) {
961be60a902SHaavard Skinnemoen 			/* reduce the number of loops by the width of
962be60a902SHaavard Skinnemoen 			 * the port */
96396ef831fSGuennadi Liakhovetski 			cnt = len >> shift;
96493c56f21SVasiliy Leoenenko 			flash_write_cmd (info, sector, 0, cnt - 1);
965be60a902SHaavard Skinnemoen 			while (cnt-- > 0) {
966be60a902SHaavard Skinnemoen 				switch (info->portwidth) {
967be60a902SHaavard Skinnemoen 				case FLASH_CFI_8BIT:
968cdbaefb5SHaavard Skinnemoen 					flash_write8(flash_read8(src), dst);
969cdbaefb5SHaavard Skinnemoen 					src += 1, dst += 1;
970be60a902SHaavard Skinnemoen 					break;
971be60a902SHaavard Skinnemoen 				case FLASH_CFI_16BIT:
972cdbaefb5SHaavard Skinnemoen 					flash_write16(flash_read16(src), dst);
973cdbaefb5SHaavard Skinnemoen 					src += 2, dst += 2;
974be60a902SHaavard Skinnemoen 					break;
975be60a902SHaavard Skinnemoen 				case FLASH_CFI_32BIT:
976cdbaefb5SHaavard Skinnemoen 					flash_write32(flash_read32(src), dst);
977cdbaefb5SHaavard Skinnemoen 					src += 4, dst += 4;
978be60a902SHaavard Skinnemoen 					break;
979be60a902SHaavard Skinnemoen 				case FLASH_CFI_64BIT:
980cdbaefb5SHaavard Skinnemoen 					flash_write64(flash_read64(src), dst);
981cdbaefb5SHaavard Skinnemoen 					src += 8, dst += 8;
982be60a902SHaavard Skinnemoen 					break;
983be60a902SHaavard Skinnemoen 				default:
98412d30aa7SHaavard Skinnemoen 					retcode = ERR_INVAL;
98512d30aa7SHaavard Skinnemoen 					goto out_unmap;
986be60a902SHaavard Skinnemoen 				}
987be60a902SHaavard Skinnemoen 			}
988be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,
989be60a902SHaavard Skinnemoen 					 FLASH_CMD_WRITE_BUFFER_CONFIRM);
990be60a902SHaavard Skinnemoen 			retcode = flash_full_status_check (
991be60a902SHaavard Skinnemoen 				info, sector, info->buffer_write_tout,
992be60a902SHaavard Skinnemoen 				"buffer write");
993be60a902SHaavard Skinnemoen 		}
99412d30aa7SHaavard Skinnemoen 
99512d30aa7SHaavard Skinnemoen 		break;
996be60a902SHaavard Skinnemoen 
997be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
998be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
999be60a902SHaavard Skinnemoen 		flash_unlock_seq(info,0);
100096ef831fSGuennadi Liakhovetski 
100196ef831fSGuennadi Liakhovetski #ifdef CONFIG_FLASH_SPANSION_S29WS_N
100296ef831fSGuennadi Liakhovetski 		offset = ((unsigned long)dst - info->start[sector]) >> shift;
100396ef831fSGuennadi Liakhovetski #endif
100496ef831fSGuennadi Liakhovetski 		flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
100596ef831fSGuennadi Liakhovetski 		cnt = len >> shift;
10067dedefdfSJohn Schmoller 		flash_write_cmd(info, sector, offset, cnt - 1);
1007be60a902SHaavard Skinnemoen 
1008be60a902SHaavard Skinnemoen 		switch (info->portwidth) {
1009be60a902SHaavard Skinnemoen 		case FLASH_CFI_8BIT:
1010cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
1011cdbaefb5SHaavard Skinnemoen 				flash_write8(flash_read8(src), dst);
1012cdbaefb5SHaavard Skinnemoen 				src += 1, dst += 1;
1013cdbaefb5SHaavard Skinnemoen 			}
1014be60a902SHaavard Skinnemoen 			break;
1015be60a902SHaavard Skinnemoen 		case FLASH_CFI_16BIT:
1016cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
1017cdbaefb5SHaavard Skinnemoen 				flash_write16(flash_read16(src), dst);
1018cdbaefb5SHaavard Skinnemoen 				src += 2, dst += 2;
1019cdbaefb5SHaavard Skinnemoen 			}
1020be60a902SHaavard Skinnemoen 			break;
1021be60a902SHaavard Skinnemoen 		case FLASH_CFI_32BIT:
1022cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
1023cdbaefb5SHaavard Skinnemoen 				flash_write32(flash_read32(src), dst);
1024cdbaefb5SHaavard Skinnemoen 				src += 4, dst += 4;
1025cdbaefb5SHaavard Skinnemoen 			}
1026be60a902SHaavard Skinnemoen 			break;
1027be60a902SHaavard Skinnemoen 		case FLASH_CFI_64BIT:
1028cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
1029cdbaefb5SHaavard Skinnemoen 				flash_write64(flash_read64(src), dst);
1030cdbaefb5SHaavard Skinnemoen 				src += 8, dst += 8;
1031cdbaefb5SHaavard Skinnemoen 			}
1032be60a902SHaavard Skinnemoen 			break;
1033be60a902SHaavard Skinnemoen 		default:
103412d30aa7SHaavard Skinnemoen 			retcode = ERR_INVAL;
103512d30aa7SHaavard Skinnemoen 			goto out_unmap;
1036be60a902SHaavard Skinnemoen 		}
1037be60a902SHaavard Skinnemoen 
1038be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1039be60a902SHaavard Skinnemoen 		retcode = flash_full_status_check (info, sector,
1040be60a902SHaavard Skinnemoen 						   info->buffer_write_tout,
1041be60a902SHaavard Skinnemoen 						   "buffer write");
104212d30aa7SHaavard Skinnemoen 		break;
1043be60a902SHaavard Skinnemoen 
1044be60a902SHaavard Skinnemoen 	default:
1045be60a902SHaavard Skinnemoen 		debug ("Unknown Command Set\n");
104612d30aa7SHaavard Skinnemoen 		retcode = ERR_INVAL;
104712d30aa7SHaavard Skinnemoen 		break;
1048be60a902SHaavard Skinnemoen 	}
104912d30aa7SHaavard Skinnemoen 
105012d30aa7SHaavard Skinnemoen out_unmap:
105112d30aa7SHaavard Skinnemoen 	return retcode;
1052be60a902SHaavard Skinnemoen }
10536d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
1054be60a902SHaavard Skinnemoen 
105559829cc1SJean-Christophe PLAGNIOL-VILLARD 
105659829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
105759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
105859829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last)
105959829cc1SJean-Christophe PLAGNIOL-VILLARD {
106059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int rcode = 0;
106159829cc1SJean-Christophe PLAGNIOL-VILLARD 	int prot;
106259829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect;
106359829cc1SJean-Christophe PLAGNIOL-VILLARD 
106459829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
106559829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("Can't erase unknown flash type - aborted\n");
106659829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
106759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
106859829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((s_first < 0) || (s_first > s_last)) {
106959829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("- no sectors to erase\n");
107059829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
107159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
107259829cc1SJean-Christophe PLAGNIOL-VILLARD 
107359829cc1SJean-Christophe PLAGNIOL-VILLARD 	prot = 0;
107459829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; ++sect) {
107559829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect]) {
107659829cc1SJean-Christophe PLAGNIOL-VILLARD 			prot++;
107759829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
107859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
107959829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot) {
10807e5b9b47SHaavard Skinnemoen 		printf ("- Warning: %d protected sectors will not be erased!\n",
10817e5b9b47SHaavard Skinnemoen 			prot);
10826ea808efSPiotr Ziecik 	} else if (flash_verbose) {
108359829cc1SJean-Christophe PLAGNIOL-VILLARD 		putc ('\n');
108459829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
108559829cc1SJean-Christophe PLAGNIOL-VILLARD 
108659829cc1SJean-Christophe PLAGNIOL-VILLARD 
108759829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; sect++) {
108859829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect] == 0) { /* not protected */
108959829cc1SJean-Christophe PLAGNIOL-VILLARD 			switch (info->vendor) {
10909c048b52SVasiliy Leoenenko 			case CFI_CMDSET_INTEL_PROG_REGIONS:
109159829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_STANDARD:
109259829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_EXTENDED:
10937e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10947e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_CLEAR_STATUS);
10957e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10967e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_BLOCK_ERASE);
10977e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10987e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_ERASE_CONFIRM);
109959829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
110059829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_STANDARD:
110159829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_EXTENDED:
110259829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
11037e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect,
11047e5b9b47SHaavard Skinnemoen 						info->addr_unlock1,
11057e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
110659829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
11077e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
11087e5b9b47SHaavard Skinnemoen 						 AMD_CMD_ERASE_SECTOR);
110959829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
111081b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
111181b20cccSMichael Schwingen 			case CFI_CMDSET_AMD_LEGACY:
111281b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
11137e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, 0, info->addr_unlock1,
11147e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
111581b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
11167e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
11177e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_SECTOR);
111881b20cccSMichael Schwingen 				break;
111981b20cccSMichael Schwingen #endif
112059829cc1SJean-Christophe PLAGNIOL-VILLARD 			default:
112159829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug ("Unkown flash vendor %d\n",
112259829cc1SJean-Christophe PLAGNIOL-VILLARD 				       info->vendor);
112359829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
112459829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
112559829cc1SJean-Christophe PLAGNIOL-VILLARD 
112659829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_full_status_check
112759829cc1SJean-Christophe PLAGNIOL-VILLARD 			    (info, sect, info->erase_blk_tout, "erase")) {
112859829cc1SJean-Christophe PLAGNIOL-VILLARD 				rcode = 1;
11296ea808efSPiotr Ziecik 			} else if (flash_verbose)
113059829cc1SJean-Christophe PLAGNIOL-VILLARD 				putc ('.');
113159829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
113259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
11336ea808efSPiotr Ziecik 
11346ea808efSPiotr Ziecik 	if (flash_verbose)
113559829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts (" done\n");
11366ea808efSPiotr Ziecik 
113759829cc1SJean-Christophe PLAGNIOL-VILLARD 	return rcode;
113859829cc1SJean-Christophe PLAGNIOL-VILLARD }
113959829cc1SJean-Christophe PLAGNIOL-VILLARD 
114059829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
114159829cc1SJean-Christophe PLAGNIOL-VILLARD  */
114259829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info)
114359829cc1SJean-Christophe PLAGNIOL-VILLARD {
114459829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
114559829cc1SJean-Christophe PLAGNIOL-VILLARD 
114659829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
114759829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("missing or unknown FLASH type\n");
114859829cc1SJean-Christophe PLAGNIOL-VILLARD 		return;
114959829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
115059829cc1SJean-Christophe PLAGNIOL-VILLARD 
115181b20cccSMichael Schwingen 	printf ("%s FLASH (%d x %d)",
115281b20cccSMichael Schwingen 		info->name,
115359829cc1SJean-Christophe PLAGNIOL-VILLARD 		(info->portwidth << 3), (info->chipwidth << 3));
115481b20cccSMichael Schwingen 	if (info->size < 1024*1024)
115581b20cccSMichael Schwingen 		printf ("  Size: %ld kB in %d Sectors\n",
115681b20cccSMichael Schwingen 			info->size >> 10, info->sector_count);
115781b20cccSMichael Schwingen 	else
115859829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  Size: %ld MB in %d Sectors\n",
115959829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->size >> 20, info->sector_count);
116059829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("  ");
116159829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
11629c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
11639c048b52SVasiliy Leoenenko 			printf ("Intel Prog Regions");
11649c048b52SVasiliy Leoenenko 			break;
116559829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
116659829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Standard");
116759829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
116859829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
116959829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Extended");
117059829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
117159829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
117259829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Standard");
117359829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
117459829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
117559829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Extended");
117659829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
117781b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
117881b20cccSMichael Schwingen 		case CFI_CMDSET_AMD_LEGACY:
117981b20cccSMichael Schwingen 			printf ("AMD Legacy");
118081b20cccSMichael Schwingen 			break;
118181b20cccSMichael Schwingen #endif
118259829cc1SJean-Christophe PLAGNIOL-VILLARD 		default:
118359829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Unknown (%d)", info->vendor);
118459829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
118559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
118659829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
118759829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->manufacturer_id, info->device_id);
118859829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->device_id == 0x7E) {
118959829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf("%04X", info->device_id2);
119059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
119159829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
119259829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->erase_blk_tout,
119359829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->write_tout);
119459829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->buffer_size > 1) {
11957e5b9b47SHaavard Skinnemoen 		printf ("  Buffer write timeout: %ld ms, "
11967e5b9b47SHaavard Skinnemoen 			"buffer size: %d bytes\n",
119759829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_write_tout,
119859829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_size);
119959829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
120059829cc1SJean-Christophe PLAGNIOL-VILLARD 
120159829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts ("\n  Sector Start Addresses:");
120259829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < info->sector_count; ++i) {
120359829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((i % 5) == 0)
120459829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("\n");
12056d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_EMPTY_INFO
120659829cc1SJean-Christophe PLAGNIOL-VILLARD 		int k;
120759829cc1SJean-Christophe PLAGNIOL-VILLARD 		int size;
120859829cc1SJean-Christophe PLAGNIOL-VILLARD 		int erased;
120959829cc1SJean-Christophe PLAGNIOL-VILLARD 		volatile unsigned long *flash;
121059829cc1SJean-Christophe PLAGNIOL-VILLARD 
121159829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
121259829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * Check if whole sector is erased
121359829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
121412d30aa7SHaavard Skinnemoen 		size = flash_sector_size(info, i);
121559829cc1SJean-Christophe PLAGNIOL-VILLARD 		erased = 1;
121659829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash = (volatile unsigned long *) info->start[i];
121759829cc1SJean-Christophe PLAGNIOL-VILLARD 		size = size >> 2;	/* divide by 4 for longword access */
121859829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (k = 0; k < size; k++) {
121959829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (*flash++ != 0xffffffff) {
122059829cc1SJean-Christophe PLAGNIOL-VILLARD 				erased = 0;
122159829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
122259829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
122359829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
122459829cc1SJean-Christophe PLAGNIOL-VILLARD 
122559829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* print empty and read-only info */
122659829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX %c %s ",
122759829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
122859829cc1SJean-Christophe PLAGNIOL-VILLARD 			erased ? 'E' : ' ',
122959829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
12306d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #else	/* ! CONFIG_SYS_FLASH_EMPTY_INFO */
123159829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX   %s ",
123259829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
123359829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
123459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
123559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
123659829cc1SJean-Christophe PLAGNIOL-VILLARD 	putc ('\n');
123759829cc1SJean-Christophe PLAGNIOL-VILLARD 	return;
123859829cc1SJean-Christophe PLAGNIOL-VILLARD }
123959829cc1SJean-Christophe PLAGNIOL-VILLARD 
124059829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
12419a042e9cSJerry Van Baren  * This is used in a few places in write_buf() to show programming
12429a042e9cSJerry Van Baren  * progress.  Making it a function is nasty because it needs to do side
12439a042e9cSJerry Van Baren  * effect updates to digit and dots.  Repeated code is nasty too, so
12449a042e9cSJerry Van Baren  * we define it once here.
12459a042e9cSJerry Van Baren  */
1246f0105727SStefan Roese #ifdef CONFIG_FLASH_SHOW_PROGRESS
1247f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
12486ea808efSPiotr Ziecik 	if (flash_verbose) { \
1249f0105727SStefan Roese 		dots -= dots_sub; \
12509a042e9cSJerry Van Baren 		if ((scale > 0) && (dots <= 0)) { \
12519a042e9cSJerry Van Baren 			if ((digit % 5) == 0) \
12529a042e9cSJerry Van Baren 				printf ("%d", digit / 5); \
12539a042e9cSJerry Van Baren 			else \
12549a042e9cSJerry Van Baren 				putc ('.'); \
12559a042e9cSJerry Van Baren 			digit--; \
12569a042e9cSJerry Van Baren 			dots += scale; \
12576ea808efSPiotr Ziecik 		} \
12589a042e9cSJerry Van Baren 	}
1259f0105727SStefan Roese #else
1260f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1261f0105727SStefan Roese #endif
12629a042e9cSJerry Van Baren 
12639a042e9cSJerry Van Baren /*-----------------------------------------------------------------------
126459829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copy memory to flash, returns:
126559829cc1SJean-Christophe PLAGNIOL-VILLARD  * 0 - OK
126659829cc1SJean-Christophe PLAGNIOL-VILLARD  * 1 - write timeout
126759829cc1SJean-Christophe PLAGNIOL-VILLARD  * 2 - Flash not erased
126859829cc1SJean-Christophe PLAGNIOL-VILLARD  */
126959829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
127059829cc1SJean-Christophe PLAGNIOL-VILLARD {
127159829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong wp;
127212d30aa7SHaavard Skinnemoen 	uchar *p;
127359829cc1SJean-Christophe PLAGNIOL-VILLARD 	int aln;
127459829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
127559829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, rc;
12766d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
127759829cc1SJean-Christophe PLAGNIOL-VILLARD 	int buffered_size;
127859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
12799a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS
12809a042e9cSJerry Van Baren 	int digit = CONFIG_FLASH_SHOW_PROGRESS;
12819a042e9cSJerry Van Baren 	int scale = 0;
12829a042e9cSJerry Van Baren 	int dots  = 0;
12839a042e9cSJerry Van Baren 
12849a042e9cSJerry Van Baren 	/*
12859a042e9cSJerry Van Baren 	 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
12869a042e9cSJerry Van Baren 	 */
12879a042e9cSJerry Van Baren 	if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
12889a042e9cSJerry Van Baren 		scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
12899a042e9cSJerry Van Baren 			CONFIG_FLASH_SHOW_PROGRESS);
12909a042e9cSJerry Van Baren 	}
12919a042e9cSJerry Van Baren #endif
12929a042e9cSJerry Van Baren 
129359829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* get lower aligned address */
129459829cc1SJean-Christophe PLAGNIOL-VILLARD 	wp = (addr & ~(info->portwidth - 1));
129559829cc1SJean-Christophe PLAGNIOL-VILLARD 
129659829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle unaligned start */
129759829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((aln = addr - wp) != 0) {
129859829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
129909ce9921SBecky Bruce 		p = (uchar *)wp;
130012d30aa7SHaavard Skinnemoen 		for (i = 0; i < aln; ++i)
130112d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
130259829cc1SJean-Christophe PLAGNIOL-VILLARD 
130359829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (; (i < info->portwidth) && (cnt > 0); i++) {
130459829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
130559829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt--;
130659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
130712d30aa7SHaavard Skinnemoen 		for (; (cnt == 0) && (i < info->portwidth); ++i)
130812d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
130912d30aa7SHaavard Skinnemoen 
131012d30aa7SHaavard Skinnemoen 		rc = flash_write_cfiword (info, wp, cword);
131112d30aa7SHaavard Skinnemoen 		if (rc != 0)
131259829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
131312d30aa7SHaavard Skinnemoen 
131412d30aa7SHaavard Skinnemoen 		wp += i;
1315f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, i);
131659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
131759829cc1SJean-Christophe PLAGNIOL-VILLARD 
131859829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle the aligned part */
13196d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
132059829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size = (info->portwidth / info->chipwidth);
132159829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size *= info->buffer_size;
132259829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
132359829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* prohibit buffer write when buffer_size is 1 */
132459829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->buffer_size == 1) {
132559829cc1SJean-Christophe PLAGNIOL-VILLARD 			cword.l = 0;
132659829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->portwidth; i++)
132759829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_add_byte (info, &cword, *src++);
132859829cc1SJean-Christophe PLAGNIOL-VILLARD 			if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
132959829cc1SJean-Christophe PLAGNIOL-VILLARD 				return rc;
133059829cc1SJean-Christophe PLAGNIOL-VILLARD 			wp += info->portwidth;
133159829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt -= info->portwidth;
133259829cc1SJean-Christophe PLAGNIOL-VILLARD 			continue;
133359829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
133459829cc1SJean-Christophe PLAGNIOL-VILLARD 
133559829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* write buffer until next buffered_size aligned boundary */
133659829cc1SJean-Christophe PLAGNIOL-VILLARD 		i = buffered_size - (wp % buffered_size);
133759829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (i > cnt)
133859829cc1SJean-Christophe PLAGNIOL-VILLARD 			i = cnt;
133959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
134059829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
134159829cc1SJean-Christophe PLAGNIOL-VILLARD 		i -= i & (info->portwidth - 1);
134259829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += i;
134359829cc1SJean-Christophe PLAGNIOL-VILLARD 		src += i;
134459829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= i;
1345f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, i);
134659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
134759829cc1SJean-Christophe PLAGNIOL-VILLARD #else
134859829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
134959829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
135059829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < info->portwidth; i++) {
135159829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
135259829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
135359829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
135459829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
135559829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += info->portwidth;
135659829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= info->portwidth;
1357f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
135859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
13596d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
13609a042e9cSJerry Van Baren 
136159829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (cnt == 0) {
136259829cc1SJean-Christophe PLAGNIOL-VILLARD 		return (0);
136359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
136459829cc1SJean-Christophe PLAGNIOL-VILLARD 
136559829cc1SJean-Christophe PLAGNIOL-VILLARD 	/*
136659829cc1SJean-Christophe PLAGNIOL-VILLARD 	 * handle unaligned tail bytes
136759829cc1SJean-Christophe PLAGNIOL-VILLARD 	 */
136859829cc1SJean-Christophe PLAGNIOL-VILLARD 	cword.l = 0;
136909ce9921SBecky Bruce 	p = (uchar *)wp;
137012d30aa7SHaavard Skinnemoen 	for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
137159829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_add_byte (info, &cword, *src++);
137259829cc1SJean-Christophe PLAGNIOL-VILLARD 		--cnt;
137359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
137412d30aa7SHaavard Skinnemoen 	for (; i < info->portwidth; ++i)
137512d30aa7SHaavard Skinnemoen 		flash_add_byte (info, &cword, flash_read8(p + i));
137659829cc1SJean-Christophe PLAGNIOL-VILLARD 
137759829cc1SJean-Christophe PLAGNIOL-VILLARD 	return flash_write_cfiword (info, wp, cword);
137859829cc1SJean-Christophe PLAGNIOL-VILLARD }
137959829cc1SJean-Christophe PLAGNIOL-VILLARD 
138059829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
138159829cc1SJean-Christophe PLAGNIOL-VILLARD  */
13826d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
138359829cc1SJean-Christophe PLAGNIOL-VILLARD 
138459829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot)
138559829cc1SJean-Christophe PLAGNIOL-VILLARD {
138659829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retcode = 0;
138759829cc1SJean-Christophe PLAGNIOL-VILLARD 
1388bc9019e1SRafael Campos 	switch (info->vendor) {
1389bc9019e1SRafael Campos 		case CFI_CMDSET_INTEL_PROG_REGIONS:
1390bc9019e1SRafael Campos 		case CFI_CMDSET_INTEL_STANDARD:
13919e8e63ccSNick Spence 		case CFI_CMDSET_INTEL_EXTENDED:
1392bc9019e1SRafael Campos 			flash_write_cmd (info, sector, 0,
1393bc9019e1SRafael Campos 					 FLASH_CMD_CLEAR_STATUS);
139459829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
139559829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (prot)
1396bc9019e1SRafael Campos 				flash_write_cmd (info, sector, 0,
1397bc9019e1SRafael Campos 					FLASH_CMD_PROTECT_SET);
139859829cc1SJean-Christophe PLAGNIOL-VILLARD 			else
1399bc9019e1SRafael Campos 				flash_write_cmd (info, sector, 0,
1400bc9019e1SRafael Campos 					FLASH_CMD_PROTECT_CLEAR);
1401bc9019e1SRafael Campos 			break;
1402bc9019e1SRafael Campos 		case CFI_CMDSET_AMD_EXTENDED:
1403bc9019e1SRafael Campos 		case CFI_CMDSET_AMD_STANDARD:
1404bc9019e1SRafael Campos 			/* U-Boot only checks the first byte */
1405bc9019e1SRafael Campos 			if (info->manufacturer_id == (uchar)ATM_MANUFACT) {
1406bc9019e1SRafael Campos 				if (prot) {
1407bc9019e1SRafael Campos 					flash_unlock_seq (info, 0);
1408bc9019e1SRafael Campos 					flash_write_cmd (info, 0,
1409bc9019e1SRafael Campos 							info->addr_unlock1,
1410bc9019e1SRafael Campos 							ATM_CMD_SOFTLOCK_START);
1411bc9019e1SRafael Campos 					flash_unlock_seq (info, 0);
1412bc9019e1SRafael Campos 					flash_write_cmd (info, sector, 0,
1413bc9019e1SRafael Campos 							ATM_CMD_LOCK_SECT);
1414bc9019e1SRafael Campos 				} else {
1415bc9019e1SRafael Campos 					flash_write_cmd (info, 0,
1416bc9019e1SRafael Campos 							info->addr_unlock1,
1417bc9019e1SRafael Campos 							AMD_CMD_UNLOCK_START);
1418bc9019e1SRafael Campos 					if (info->device_id == ATM_ID_BV6416)
1419bc9019e1SRafael Campos 						flash_write_cmd (info, sector,
1420bc9019e1SRafael Campos 							0, ATM_CMD_UNLOCK_SECT);
1421bc9019e1SRafael Campos 				}
1422bc9019e1SRafael Campos 			}
1423bc9019e1SRafael Campos 			break;
14244e00acdeSTsiChung Liew #ifdef CONFIG_FLASH_CFI_LEGACY
14254e00acdeSTsiChung Liew 		case CFI_CMDSET_AMD_LEGACY:
14264e00acdeSTsiChung Liew 			flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
14274e00acdeSTsiChung Liew 			flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
14284e00acdeSTsiChung Liew 			if (prot)
14294e00acdeSTsiChung Liew 				flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
14304e00acdeSTsiChung Liew 			else
14314e00acdeSTsiChung Liew 				flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
14324e00acdeSTsiChung Liew #endif
1433bc9019e1SRafael Campos 	};
143459829cc1SJean-Christophe PLAGNIOL-VILLARD 
143559829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((retcode =
143659829cc1SJean-Christophe PLAGNIOL-VILLARD 	     flash_full_status_check (info, sector, info->erase_blk_tout,
143759829cc1SJean-Christophe PLAGNIOL-VILLARD 				      prot ? "protect" : "unprotect")) == 0) {
143859829cc1SJean-Christophe PLAGNIOL-VILLARD 
143959829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->protect[sector] = prot;
144059829cc1SJean-Christophe PLAGNIOL-VILLARD 
144159829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
144259829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * On some of Intel's flash chips (marked via legacy_unlock)
144359829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * unprotect unprotects all locking.
144459829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
144559829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((prot == 0) && (info->legacy_unlock)) {
144659829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_sect_t i;
144759829cc1SJean-Christophe PLAGNIOL-VILLARD 
144859829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->sector_count; i++) {
144959829cc1SJean-Christophe PLAGNIOL-VILLARD 				if (info->protect[i])
145059829cc1SJean-Christophe PLAGNIOL-VILLARD 					flash_real_protect (info, i, 1);
145159829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
145259829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
145359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
145459829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retcode;
145559829cc1SJean-Christophe PLAGNIOL-VILLARD }
145659829cc1SJean-Christophe PLAGNIOL-VILLARD 
145759829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
145859829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_user_serial - read the OneTimeProgramming cells
145959829cc1SJean-Christophe PLAGNIOL-VILLARD  */
146059829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
146159829cc1SJean-Christophe PLAGNIOL-VILLARD 			     int len)
146259829cc1SJean-Christophe PLAGNIOL-VILLARD {
146359829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
146459829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *dst;
146559829cc1SJean-Christophe PLAGNIOL-VILLARD 
146659829cc1SJean-Christophe PLAGNIOL-VILLARD 	dst = buffer;
146712d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
146859829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
146959829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (dst, src + offset, len);
147059829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
147112d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
147259829cc1SJean-Christophe PLAGNIOL-VILLARD }
147359829cc1SJean-Christophe PLAGNIOL-VILLARD 
147459829cc1SJean-Christophe PLAGNIOL-VILLARD /*
147559829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_factory_serial - read the device Id from the protection area
147659829cc1SJean-Christophe PLAGNIOL-VILLARD  */
147759829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
147859829cc1SJean-Christophe PLAGNIOL-VILLARD 				int len)
147959829cc1SJean-Christophe PLAGNIOL-VILLARD {
148059829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
148159829cc1SJean-Christophe PLAGNIOL-VILLARD 
148212d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
148359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
148459829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (buffer, src + offset, len);
148559829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
148612d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
148759829cc1SJean-Christophe PLAGNIOL-VILLARD }
148859829cc1SJean-Christophe PLAGNIOL-VILLARD 
14896d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */
149059829cc1SJean-Christophe PLAGNIOL-VILLARD 
14910ddf06ddSHaavard Skinnemoen /*-----------------------------------------------------------------------
14920ddf06ddSHaavard Skinnemoen  * Reverse the order of the erase regions in the CFI QRY structure.
14930ddf06ddSHaavard Skinnemoen  * This is needed for chips that are either a) correctly detected as
14940ddf06ddSHaavard Skinnemoen  * top-boot, or b) buggy.
14950ddf06ddSHaavard Skinnemoen  */
14960ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry)
14970ddf06ddSHaavard Skinnemoen {
14980ddf06ddSHaavard Skinnemoen 	unsigned int i, j;
14990ddf06ddSHaavard Skinnemoen 	u32 tmp;
15000ddf06ddSHaavard Skinnemoen 
15010ddf06ddSHaavard Skinnemoen 	for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
15020ddf06ddSHaavard Skinnemoen 		tmp = qry->erase_region_info[i];
15030ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[i] = qry->erase_region_info[j];
15040ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[j] = tmp;
15050ddf06ddSHaavard Skinnemoen 	}
15060ddf06ddSHaavard Skinnemoen }
150759829cc1SJean-Christophe PLAGNIOL-VILLARD 
150859829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
150959829cc1SJean-Christophe PLAGNIOL-VILLARD  * read jedec ids from device and set corresponding fields in info struct
151059829cc1SJean-Christophe PLAGNIOL-VILLARD  *
151159829cc1SJean-Christophe PLAGNIOL-VILLARD  * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
151259829cc1SJean-Christophe PLAGNIOL-VILLARD  *
151359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
15140ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info)
151559829cc1SJean-Christophe PLAGNIOL-VILLARD {
151659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
151759829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
151859829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
151959829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = flash_read_uchar (info,
152059829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_MANUFACTURER_ID);
152159829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id = flash_read_uchar (info,
152259829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID);
152359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
15240ddf06ddSHaavard Skinnemoen }
15250ddf06ddSHaavard Skinnemoen 
15260ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
15270ddf06ddSHaavard Skinnemoen {
15280ddf06ddSHaavard Skinnemoen 	info->cmd_reset = FLASH_CMD_RESET;
15290ddf06ddSHaavard Skinnemoen 
15300ddf06ddSHaavard Skinnemoen 	cmdset_intel_read_jedec_ids(info);
15310ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
15320ddf06ddSHaavard Skinnemoen 
15336d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
15340ddf06ddSHaavard Skinnemoen 	/* read legacy lock/unlock bit from intel flash */
15350ddf06ddSHaavard Skinnemoen 	if (info->ext_addr) {
15360ddf06ddSHaavard Skinnemoen 		info->legacy_unlock = flash_read_uchar (info,
15370ddf06ddSHaavard Skinnemoen 				info->ext_addr + 5) & 0x08;
15380ddf06ddSHaavard Skinnemoen 	}
15390ddf06ddSHaavard Skinnemoen #endif
15400ddf06ddSHaavard Skinnemoen 
15410ddf06ddSHaavard Skinnemoen 	return 0;
15420ddf06ddSHaavard Skinnemoen }
15430ddf06ddSHaavard Skinnemoen 
15440ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info)
15450ddf06ddSHaavard Skinnemoen {
1546*3a7b2c21SNiklaus Giger 	ushort bankId = 0;
1547*3a7b2c21SNiklaus Giger 	uchar  manuId;
1548*3a7b2c21SNiklaus Giger 
154959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
155059829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_unlock_seq(info, 0);
155181b20cccSMichael Schwingen 	flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
155259829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
155390447ecbSTor Krill 
1554*3a7b2c21SNiklaus Giger 	manuId = flash_read_uchar (info, FLASH_OFFSET_MANUFACTURER_ID);
1555*3a7b2c21SNiklaus Giger 	/* JEDEC JEP106Z specifies ID codes up to bank 7 */
1556*3a7b2c21SNiklaus Giger 	while (manuId == FLASH_CONTINUATION_CODE && bankId < 0x800) {
1557*3a7b2c21SNiklaus Giger 		bankId += 0x100;
1558*3a7b2c21SNiklaus Giger 		manuId = flash_read_uchar (info,
1559*3a7b2c21SNiklaus Giger 			bankId | FLASH_OFFSET_MANUFACTURER_ID);
1560*3a7b2c21SNiklaus Giger 	}
1561*3a7b2c21SNiklaus Giger 	info->manufacturer_id = manuId;
156290447ecbSTor Krill 
156390447ecbSTor Krill 	switch (info->chipwidth){
156490447ecbSTor Krill 	case FLASH_CFI_8BIT:
156559829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id = flash_read_uchar (info,
156659829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID);
156759829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->device_id == 0x7E) {
156859829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* AMD 3-byte (expanded) device ids */
156959829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 = flash_read_uchar (info,
157059829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID2);
157159829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 <<= 8;
157259829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 |= flash_read_uchar (info,
157359829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID3);
157459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
157590447ecbSTor Krill 		break;
157690447ecbSTor Krill 	case FLASH_CFI_16BIT:
157790447ecbSTor Krill 		info->device_id = flash_read_word (info,
157890447ecbSTor Krill 						FLASH_OFFSET_DEVICE_ID);
157990447ecbSTor Krill 		break;
158090447ecbSTor Krill 	default:
158190447ecbSTor Krill 		break;
158290447ecbSTor Krill 	}
158359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
15840ddf06ddSHaavard Skinnemoen }
15850ddf06ddSHaavard Skinnemoen 
15860ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
15870ddf06ddSHaavard Skinnemoen {
15880ddf06ddSHaavard Skinnemoen 	info->cmd_reset = AMD_CMD_RESET;
15890ddf06ddSHaavard Skinnemoen 
15900ddf06ddSHaavard Skinnemoen 	cmdset_amd_read_jedec_ids(info);
15910ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
15920ddf06ddSHaavard Skinnemoen 
15930ddf06ddSHaavard Skinnemoen 	return 0;
15940ddf06ddSHaavard Skinnemoen }
15950ddf06ddSHaavard Skinnemoen 
15960ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
15970ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info)
15980ddf06ddSHaavard Skinnemoen {
15990ddf06ddSHaavard Skinnemoen 	info->manufacturer_id = 0;
16000ddf06ddSHaavard Skinnemoen 	info->device_id       = 0;
16010ddf06ddSHaavard Skinnemoen 	info->device_id2      = 0;
16020ddf06ddSHaavard Skinnemoen 
16030ddf06ddSHaavard Skinnemoen 	switch (info->vendor) {
16049c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
16050ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
16060ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
16078225d1e3SMichael Schwingen 		cmdset_intel_read_jedec_ids(info);
16080ddf06ddSHaavard Skinnemoen 		break;
16090ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
16100ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
16118225d1e3SMichael Schwingen 		cmdset_amd_read_jedec_ids(info);
161259829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
161359829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
161459829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
161559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
161659829cc1SJean-Christophe PLAGNIOL-VILLARD }
161759829cc1SJean-Christophe PLAGNIOL-VILLARD 
1618be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
1619be60a902SHaavard Skinnemoen  * Call board code to request info about non-CFI flash.
1620be60a902SHaavard Skinnemoen  * board_flash_get_legacy needs to fill in at least:
1621be60a902SHaavard Skinnemoen  * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1622be60a902SHaavard Skinnemoen  */
162309ce9921SBecky Bruce static int flash_detect_legacy(phys_addr_t base, int banknum)
1624be60a902SHaavard Skinnemoen {
1625be60a902SHaavard Skinnemoen 	flash_info_t *info = &flash_info[banknum];
1626be60a902SHaavard Skinnemoen 
1627be60a902SHaavard Skinnemoen 	if (board_flash_get_legacy(base, banknum, info)) {
1628be60a902SHaavard Skinnemoen 		/* board code may have filled info completely. If not, we
1629be60a902SHaavard Skinnemoen 		   use JEDEC ID probing. */
1630be60a902SHaavard Skinnemoen 		if (!info->vendor) {
1631be60a902SHaavard Skinnemoen 			int modes[] = {
1632be60a902SHaavard Skinnemoen 				CFI_CMDSET_AMD_STANDARD,
1633be60a902SHaavard Skinnemoen 				CFI_CMDSET_INTEL_STANDARD
1634be60a902SHaavard Skinnemoen 			};
1635be60a902SHaavard Skinnemoen 			int i;
1636be60a902SHaavard Skinnemoen 
1637be60a902SHaavard Skinnemoen 			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1638be60a902SHaavard Skinnemoen 				info->vendor = modes[i];
163909ce9921SBecky Bruce 				info->start[0] =
164009ce9921SBecky Bruce 					(ulong)map_physmem(base,
1641e1fb6d0dSStefan Roese 							   info->portwidth,
164209ce9921SBecky Bruce 							   MAP_NOCACHE);
1643be60a902SHaavard Skinnemoen 				if (info->portwidth == FLASH_CFI_8BIT
1644be60a902SHaavard Skinnemoen 					&& info->interface == FLASH_CFI_X8X16) {
1645be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x2AAA;
1646be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x5555;
1647be60a902SHaavard Skinnemoen 				} else {
1648be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x5555;
1649be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x2AAA;
1650be60a902SHaavard Skinnemoen 				}
1651be60a902SHaavard Skinnemoen 				flash_read_jedec_ids(info);
1652be60a902SHaavard Skinnemoen 				debug("JEDEC PROBE: ID %x %x %x\n",
1653be60a902SHaavard Skinnemoen 						info->manufacturer_id,
1654be60a902SHaavard Skinnemoen 						info->device_id,
1655be60a902SHaavard Skinnemoen 						info->device_id2);
165609ce9921SBecky Bruce 				if (jedec_flash_match(info, info->start[0]))
1657be60a902SHaavard Skinnemoen 					break;
165809ce9921SBecky Bruce 				else
1659e1fb6d0dSStefan Roese 					unmap_physmem((void *)info->start[0],
166009ce9921SBecky Bruce 						      MAP_NOCACHE);
1661be60a902SHaavard Skinnemoen 			}
1662be60a902SHaavard Skinnemoen 		}
1663be60a902SHaavard Skinnemoen 
1664be60a902SHaavard Skinnemoen 		switch(info->vendor) {
16659c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
1666be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_STANDARD:
1667be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_EXTENDED:
1668be60a902SHaavard Skinnemoen 			info->cmd_reset = FLASH_CMD_RESET;
1669be60a902SHaavard Skinnemoen 			break;
1670be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_STANDARD:
1671be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_EXTENDED:
1672be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_LEGACY:
1673be60a902SHaavard Skinnemoen 			info->cmd_reset = AMD_CMD_RESET;
1674be60a902SHaavard Skinnemoen 			break;
1675be60a902SHaavard Skinnemoen 		}
1676be60a902SHaavard Skinnemoen 		info->flash_id = FLASH_MAN_CFI;
1677be60a902SHaavard Skinnemoen 		return 1;
1678be60a902SHaavard Skinnemoen 	}
1679be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1680be60a902SHaavard Skinnemoen }
1681be60a902SHaavard Skinnemoen #else
168209ce9921SBecky Bruce static inline int flash_detect_legacy(phys_addr_t base, int banknum)
1683be60a902SHaavard Skinnemoen {
1684be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1685be60a902SHaavard Skinnemoen }
1686be60a902SHaavard Skinnemoen #endif
1687be60a902SHaavard Skinnemoen 
168859829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
168959829cc1SJean-Christophe PLAGNIOL-VILLARD  * detect if flash is compatible with the Common Flash Interface (CFI)
169059829cc1SJean-Christophe PLAGNIOL-VILLARD  * http://www.jedec.org/download/search/jesd68.pdf
169159829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1692e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf,
1693e23741f4SHaavard Skinnemoen 		unsigned int start, size_t len)
1694e23741f4SHaavard Skinnemoen {
1695e23741f4SHaavard Skinnemoen 	u8 *p = buf;
1696e23741f4SHaavard Skinnemoen 	unsigned int i;
1697e23741f4SHaavard Skinnemoen 
1698e23741f4SHaavard Skinnemoen 	for (i = 0; i < len; i++)
1699e23741f4SHaavard Skinnemoen 		p[i] = flash_read_uchar(info, start + i);
1700e23741f4SHaavard Skinnemoen }
1701e23741f4SHaavard Skinnemoen 
1702e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
170359829cc1SJean-Christophe PLAGNIOL-VILLARD {
170459829cc1SJean-Christophe PLAGNIOL-VILLARD 	int cfi_offset;
170559829cc1SJean-Christophe PLAGNIOL-VILLARD 
17061ba639daSMichael Schwingen 	/* We do not yet know what kind of commandset to use, so we issue
17071ba639daSMichael Schwingen 	   the reset command in both Intel and AMD variants, in the hope
17081ba639daSMichael Schwingen 	   that AMD flash roms ignore the Intel command. */
17091ba639daSMichael Schwingen 	flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
17101ba639daSMichael Schwingen 	flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
17111ba639daSMichael Schwingen 
17127e5b9b47SHaavard Skinnemoen 	for (cfi_offset=0;
17137e5b9b47SHaavard Skinnemoen 	     cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
17147e5b9b47SHaavard Skinnemoen 	     cfi_offset++) {
17157e5b9b47SHaavard Skinnemoen 		flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
17167e5b9b47SHaavard Skinnemoen 				 FLASH_CMD_CFI);
171759829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
171859829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
171959829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
1720e23741f4SHaavard Skinnemoen 			flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1721e23741f4SHaavard Skinnemoen 					sizeof(struct cfi_qry));
1722e23741f4SHaavard Skinnemoen 			info->interface	= le16_to_cpu(qry->interface_desc);
1723e23741f4SHaavard Skinnemoen 
172459829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_offset = flash_offset_cfi[cfi_offset];
172559829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("device interface is %d\n",
172659829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->interface);
172759829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("found port %d chip %d ",
172859829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth, info->chipwidth);
172959829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("port %d bits chip %d bits\n",
173059829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth << CFI_FLASH_SHIFT_WIDTH,
173159829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
173242026c9cSBartlomiej Sieka 
173342026c9cSBartlomiej Sieka 			/* calculate command offsets as in the Linux driver */
173442026c9cSBartlomiej Sieka 			info->addr_unlock1 = 0x555;
173542026c9cSBartlomiej Sieka 			info->addr_unlock2 = 0x2aa;
173642026c9cSBartlomiej Sieka 
173742026c9cSBartlomiej Sieka 			/*
173842026c9cSBartlomiej Sieka 			 * modify the unlock address if we are
173942026c9cSBartlomiej Sieka 			 * in compatibility mode
174042026c9cSBartlomiej Sieka 			 */
174142026c9cSBartlomiej Sieka 			if (	/* x8/x16 in x8 mode */
174242026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY8) &&
174342026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X8X16)) ||
174442026c9cSBartlomiej Sieka 				/* x16/x32 in x16 mode */
174542026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY16) &&
174642026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X16X32)))
174742026c9cSBartlomiej Sieka 			{
174842026c9cSBartlomiej Sieka 				info->addr_unlock1 = 0xaaa;
174942026c9cSBartlomiej Sieka 				info->addr_unlock2 = 0x555;
175042026c9cSBartlomiej Sieka 			}
175142026c9cSBartlomiej Sieka 
175281b20cccSMichael Schwingen 			info->name = "CFI conformant";
175359829cc1SJean-Christophe PLAGNIOL-VILLARD 			return 1;
175459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
175559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
17567e5b9b47SHaavard Skinnemoen 
17577e5b9b47SHaavard Skinnemoen 	return 0;
175859829cc1SJean-Christophe PLAGNIOL-VILLARD }
17597e5b9b47SHaavard Skinnemoen 
1760e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
17617e5b9b47SHaavard Skinnemoen {
17627e5b9b47SHaavard Skinnemoen 	debug ("flash detect cfi\n");
17637e5b9b47SHaavard Skinnemoen 
17646d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	for (info->portwidth = CONFIG_SYS_FLASH_CFI_WIDTH;
17657e5b9b47SHaavard Skinnemoen 	     info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
17667e5b9b47SHaavard Skinnemoen 		for (info->chipwidth = FLASH_CFI_BY8;
17677e5b9b47SHaavard Skinnemoen 		     info->chipwidth <= info->portwidth;
17687e5b9b47SHaavard Skinnemoen 		     info->chipwidth <<= 1)
1769e23741f4SHaavard Skinnemoen 			if (__flash_detect_cfi(info, qry))
17707e5b9b47SHaavard Skinnemoen 				return 1;
177159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
177259829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("not found\n");
177359829cc1SJean-Christophe PLAGNIOL-VILLARD 	return 0;
177459829cc1SJean-Christophe PLAGNIOL-VILLARD }
177559829cc1SJean-Christophe PLAGNIOL-VILLARD 
177659829cc1SJean-Christophe PLAGNIOL-VILLARD /*
1777467bcee1SHaavard Skinnemoen  * Manufacturer-specific quirks. Add workarounds for geometry
1778467bcee1SHaavard Skinnemoen  * reversal, etc. here.
1779467bcee1SHaavard Skinnemoen  */
1780467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1781467bcee1SHaavard Skinnemoen {
1782467bcee1SHaavard Skinnemoen 	/* check if flash geometry needs reversal */
1783467bcee1SHaavard Skinnemoen 	if (qry->num_erase_regions > 1) {
1784467bcee1SHaavard Skinnemoen 		/* reverse geometry if top boot part */
1785467bcee1SHaavard Skinnemoen 		if (info->cfi_version < 0x3131) {
1786467bcee1SHaavard Skinnemoen 			/* CFI < 1.1, try to guess from device id */
1787467bcee1SHaavard Skinnemoen 			if ((info->device_id & 0x80) != 0)
1788467bcee1SHaavard Skinnemoen 				cfi_reverse_geometry(qry);
1789467bcee1SHaavard Skinnemoen 		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1790467bcee1SHaavard Skinnemoen 			/* CFI >= 1.1, deduct from top/bottom flag */
1791467bcee1SHaavard Skinnemoen 			/* note: ext_addr is valid since cfi_version > 0 */
1792467bcee1SHaavard Skinnemoen 			cfi_reverse_geometry(qry);
1793467bcee1SHaavard Skinnemoen 		}
1794467bcee1SHaavard Skinnemoen 	}
1795467bcee1SHaavard Skinnemoen }
1796467bcee1SHaavard Skinnemoen 
1797467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1798467bcee1SHaavard Skinnemoen {
1799467bcee1SHaavard Skinnemoen 	int reverse_geometry = 0;
1800467bcee1SHaavard Skinnemoen 
1801467bcee1SHaavard Skinnemoen 	/* Check the "top boot" bit in the PRI */
1802467bcee1SHaavard Skinnemoen 	if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1803467bcee1SHaavard Skinnemoen 		reverse_geometry = 1;
1804467bcee1SHaavard Skinnemoen 
1805467bcee1SHaavard Skinnemoen 	/* AT49BV6416(T) list the erase regions in the wrong order.
1806467bcee1SHaavard Skinnemoen 	 * However, the device ID is identical with the non-broken
1807cb82a532SUlf Samuelsson 	 * AT49BV642D they differ in the high byte.
1808467bcee1SHaavard Skinnemoen 	 */
1809467bcee1SHaavard Skinnemoen 	if (info->device_id == 0xd6 || info->device_id == 0xd2)
1810467bcee1SHaavard Skinnemoen 		reverse_geometry = !reverse_geometry;
1811467bcee1SHaavard Skinnemoen 
1812467bcee1SHaavard Skinnemoen 	if (reverse_geometry)
1813467bcee1SHaavard Skinnemoen 		cfi_reverse_geometry(qry);
1814467bcee1SHaavard Skinnemoen }
1815467bcee1SHaavard Skinnemoen 
1816e8eac437SRichard Retanubun static void flash_fixup_stm(flash_info_t *info, struct cfi_qry *qry)
1817e8eac437SRichard Retanubun {
1818e8eac437SRichard Retanubun 	/* check if flash geometry needs reversal */
1819e8eac437SRichard Retanubun 	if (qry->num_erase_regions > 1) {
1820e8eac437SRichard Retanubun 		/* reverse geometry if top boot part */
1821e8eac437SRichard Retanubun 		if (info->cfi_version < 0x3131) {
18227a88601aSRichard Retanubun 			/* CFI < 1.1, guess by device id (M29W320{DT,ET} only) */
18237a88601aSRichard Retanubun 			if (info->device_id == 0x22CA ||
18247a88601aSRichard Retanubun 			    info->device_id == 0x2256) {
1825e8eac437SRichard Retanubun 				cfi_reverse_geometry(qry);
1826e8eac437SRichard Retanubun 			}
1827e8eac437SRichard Retanubun 		}
1828e8eac437SRichard Retanubun 	}
1829e8eac437SRichard Retanubun }
1830e8eac437SRichard Retanubun 
1831467bcee1SHaavard Skinnemoen /*
183259829cc1SJean-Christophe PLAGNIOL-VILLARD  * The following code cannot be run from FLASH!
183359829cc1SJean-Christophe PLAGNIOL-VILLARD  *
183459829cc1SJean-Christophe PLAGNIOL-VILLARD  */
183509ce9921SBecky Bruce ulong flash_get_size (phys_addr_t base, int banknum)
183659829cc1SJean-Christophe PLAGNIOL-VILLARD {
183759829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_info_t *info = &flash_info[banknum];
183859829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, j;
183959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect_cnt;
184009ce9921SBecky Bruce 	phys_addr_t sector;
184159829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long tmp;
184259829cc1SJean-Christophe PLAGNIOL-VILLARD 	int size_ratio;
184359829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar num_erase_regions;
184459829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_size;
184559829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_count;
1846e23741f4SHaavard Skinnemoen 	struct cfi_qry qry;
184759829cc1SJean-Christophe PLAGNIOL-VILLARD 
1848f979690eSKumar Gala 	memset(&qry, 0, sizeof(qry));
1849f979690eSKumar Gala 
185059829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->ext_addr = 0;
185159829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->cfi_version = 0;
18526d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
185359829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->legacy_unlock = 0;
185459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
185559829cc1SJean-Christophe PLAGNIOL-VILLARD 
185609ce9921SBecky Bruce 	info->start[0] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE);
185759829cc1SJean-Christophe PLAGNIOL-VILLARD 
1858e23741f4SHaavard Skinnemoen 	if (flash_detect_cfi (info, &qry)) {
1859e23741f4SHaavard Skinnemoen 		info->vendor = le16_to_cpu(qry.p_id);
1860e23741f4SHaavard Skinnemoen 		info->ext_addr = le16_to_cpu(qry.p_adr);
1861e23741f4SHaavard Skinnemoen 		num_erase_regions = qry.num_erase_regions;
1862e23741f4SHaavard Skinnemoen 
186359829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->ext_addr) {
186459829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version = (ushort) flash_read_uchar (info,
186559829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 3) << 8;
186659829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version |= (ushort) flash_read_uchar (info,
186759829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 4);
186859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
18690ddf06ddSHaavard Skinnemoen 
187059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
1871e23741f4SHaavard Skinnemoen 		flash_printqry (&qry);
187259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
18730ddf06ddSHaavard Skinnemoen 
187459829cc1SJean-Christophe PLAGNIOL-VILLARD 		switch (info->vendor) {
18759c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
187659829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
187759829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
18780ddf06ddSHaavard Skinnemoen 			cmdset_intel_init(info, &qry);
187959829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
188059829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
188159829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
18820ddf06ddSHaavard Skinnemoen 			cmdset_amd_init(info, &qry);
188359829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
18840ddf06ddSHaavard Skinnemoen 		default:
18850ddf06ddSHaavard Skinnemoen 			printf("CFI: Unknown command set 0x%x\n",
18860ddf06ddSHaavard Skinnemoen 					info->vendor);
18870ddf06ddSHaavard Skinnemoen 			/*
18880ddf06ddSHaavard Skinnemoen 			 * Unfortunately, this means we don't know how
18890ddf06ddSHaavard Skinnemoen 			 * to get the chip back to Read mode. Might
18900ddf06ddSHaavard Skinnemoen 			 * as well try an Intel-style reset...
18910ddf06ddSHaavard Skinnemoen 			 */
18920ddf06ddSHaavard Skinnemoen 			flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
18930ddf06ddSHaavard Skinnemoen 			return 0;
189459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
189559829cc1SJean-Christophe PLAGNIOL-VILLARD 
1896467bcee1SHaavard Skinnemoen 		/* Do manufacturer-specific fixups */
1897467bcee1SHaavard Skinnemoen 		switch (info->manufacturer_id) {
1898467bcee1SHaavard Skinnemoen 		case 0x0001:
1899467bcee1SHaavard Skinnemoen 			flash_fixup_amd(info, &qry);
1900467bcee1SHaavard Skinnemoen 			break;
1901467bcee1SHaavard Skinnemoen 		case 0x001f:
1902467bcee1SHaavard Skinnemoen 			flash_fixup_atmel(info, &qry);
1903467bcee1SHaavard Skinnemoen 			break;
1904e8eac437SRichard Retanubun 		case 0x0020:
1905e8eac437SRichard Retanubun 			flash_fixup_stm(info, &qry);
1906e8eac437SRichard Retanubun 			break;
1907467bcee1SHaavard Skinnemoen 		}
1908467bcee1SHaavard Skinnemoen 
190959829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer is %d\n", info->vendor);
191059829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
191159829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id is 0x%x\n", info->device_id);
191259829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id2 is 0x%x\n", info->device_id2);
191359829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("cfi version is 0x%04x\n", info->cfi_version);
191459829cc1SJean-Christophe PLAGNIOL-VILLARD 
191559829cc1SJean-Christophe PLAGNIOL-VILLARD 		size_ratio = info->portwidth / info->chipwidth;
191659829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* if the chip is x8/x16 reduce the ratio by half */
191759829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((info->interface == FLASH_CFI_X8X16)
191859829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && (info->chipwidth == FLASH_CFI_BY8)) {
191959829cc1SJean-Christophe PLAGNIOL-VILLARD 			size_ratio >>= 1;
192059829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
192159829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("size_ratio %d port %d bits chip %d bits\n",
192259829cc1SJean-Christophe PLAGNIOL-VILLARD 		       size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
192359829cc1SJean-Christophe PLAGNIOL-VILLARD 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
192459829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("found %d erase regions\n", num_erase_regions);
192559829cc1SJean-Christophe PLAGNIOL-VILLARD 		sect_cnt = 0;
192659829cc1SJean-Christophe PLAGNIOL-VILLARD 		sector = base;
192759829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < num_erase_regions; i++) {
192859829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (i > NUM_ERASE_REGIONS) {
192959829cc1SJean-Christophe PLAGNIOL-VILLARD 				printf ("%d erase regions found, only %d used\n",
193059829cc1SJean-Christophe PLAGNIOL-VILLARD 					num_erase_regions, NUM_ERASE_REGIONS);
193159829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
193259829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1933e23741f4SHaavard Skinnemoen 
19340ddf06ddSHaavard Skinnemoen 			tmp = le32_to_cpu(qry.erase_region_info[i]);
19350ddf06ddSHaavard Skinnemoen 			debug("erase region %u: 0x%08lx\n", i, tmp);
1936e23741f4SHaavard Skinnemoen 
1937e23741f4SHaavard Skinnemoen 			erase_region_count = (tmp & 0xffff) + 1;
1938e23741f4SHaavard Skinnemoen 			tmp >>= 16;
193959829cc1SJean-Christophe PLAGNIOL-VILLARD 			erase_region_size =
194059829cc1SJean-Christophe PLAGNIOL-VILLARD 				(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
194159829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("erase_region_count = %d erase_region_size = %d\n",
194259829cc1SJean-Christophe PLAGNIOL-VILLARD 				erase_region_count, erase_region_size);
194359829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (j = 0; j < erase_region_count; j++) {
19446d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 				if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
194581b20cccSMichael Schwingen 					printf("ERROR: too many flash sectors\n");
194681b20cccSMichael Schwingen 					break;
194781b20cccSMichael Schwingen 				}
194809ce9921SBecky Bruce 				info->start[sect_cnt] =
194909ce9921SBecky Bruce 					(ulong)map_physmem(sector,
195009ce9921SBecky Bruce 							   info->portwidth,
195109ce9921SBecky Bruce 							   MAP_NOCACHE);
195259829cc1SJean-Christophe PLAGNIOL-VILLARD 				sector += (erase_region_size * size_ratio);
195359829cc1SJean-Christophe PLAGNIOL-VILLARD 
195459829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
19557e5b9b47SHaavard Skinnemoen 				 * Only read protection status from
19567e5b9b47SHaavard Skinnemoen 				 * supported devices (intel...)
195759829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
195859829cc1SJean-Christophe PLAGNIOL-VILLARD 				switch (info->vendor) {
19599c048b52SVasiliy Leoenenko 				case CFI_CMDSET_INTEL_PROG_REGIONS:
196059829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_EXTENDED:
196159829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_STANDARD:
196259829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->protect[sect_cnt] =
196359829cc1SJean-Christophe PLAGNIOL-VILLARD 						flash_isset (info, sect_cnt,
196459829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_OFFSET_PROTECT,
196559829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_STATUS_PROTECT);
196659829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
196759829cc1SJean-Christophe PLAGNIOL-VILLARD 				default:
19687e5b9b47SHaavard Skinnemoen 					/* default: not protected */
19697e5b9b47SHaavard Skinnemoen 					info->protect[sect_cnt] = 0;
197059829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
197159829cc1SJean-Christophe PLAGNIOL-VILLARD 
197259829cc1SJean-Christophe PLAGNIOL-VILLARD 				sect_cnt++;
197359829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
197459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
197559829cc1SJean-Christophe PLAGNIOL-VILLARD 
197659829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->sector_count = sect_cnt;
1977e23741f4SHaavard Skinnemoen 		info->size = 1 << qry.dev_size;
197859829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* multiply the size by the number of chips */
19797e5b9b47SHaavard Skinnemoen 		info->size *= size_ratio;
1980e23741f4SHaavard Skinnemoen 		info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1981e23741f4SHaavard Skinnemoen 		tmp = 1 << qry.block_erase_timeout_typ;
19827e5b9b47SHaavard Skinnemoen 		info->erase_blk_tout = tmp *
1983e23741f4SHaavard Skinnemoen 			(1 << qry.block_erase_timeout_max);
1984e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.buf_write_timeout_typ) *
1985e23741f4SHaavard Skinnemoen 			(1 << qry.buf_write_timeout_max);
1986e23741f4SHaavard Skinnemoen 
19877e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1988e23741f4SHaavard Skinnemoen 		info->buffer_write_tout = (tmp + 999) / 1000;
1989e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.word_write_timeout_typ) *
1990e23741f4SHaavard Skinnemoen 			(1 << qry.word_write_timeout_max);
19917e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1992e23741f4SHaavard Skinnemoen 		info->write_tout = (tmp + 999) / 1000;
199359829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->flash_id = FLASH_MAN_CFI;
19947e5b9b47SHaavard Skinnemoen 		if ((info->interface == FLASH_CFI_X8X16) &&
19957e5b9b47SHaavard Skinnemoen 		    (info->chipwidth == FLASH_CFI_BY8)) {
19967e5b9b47SHaavard Skinnemoen 			/* XXX - Need to test on x8/x16 in parallel. */
19977e5b9b47SHaavard Skinnemoen 			info->portwidth >>= 1;
199859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
199959829cc1SJean-Christophe PLAGNIOL-VILLARD 
200059829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, 0, 0, info->cmd_reset);
20012215987eSMike Frysinger 	}
20022215987eSMike Frysinger 
200359829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (info->size);
200459829cc1SJean-Christophe PLAGNIOL-VILLARD }
200559829cc1SJean-Christophe PLAGNIOL-VILLARD 
20066ea808efSPiotr Ziecik void flash_set_verbose(uint v)
20076ea808efSPiotr Ziecik {
20086ea808efSPiotr Ziecik 	flash_verbose = v;
20096ea808efSPiotr Ziecik }
20106ea808efSPiotr Ziecik 
201159829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
201259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
2013be60a902SHaavard Skinnemoen unsigned long flash_init (void)
201459829cc1SJean-Christophe PLAGNIOL-VILLARD {
2015be60a902SHaavard Skinnemoen 	unsigned long size = 0;
2016be60a902SHaavard Skinnemoen 	int i;
20176d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
2018c63ad632SMatthias Fuchs 	struct apl_s {
2019c63ad632SMatthias Fuchs 		ulong start;
2020c63ad632SMatthias Fuchs 		ulong size;
20216d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	} apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST;
2022c63ad632SMatthias Fuchs #endif
202359829cc1SJean-Christophe PLAGNIOL-VILLARD 
20246d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
20253a3baf3eSEric Schumann 	/* read environment from EEPROM */
20263a3baf3eSEric Schumann 	char s[64];
20273a3baf3eSEric Schumann 	getenv_r ("unlock", s, sizeof(s));
202881b20cccSMichael Schwingen #endif
2029be60a902SHaavard Skinnemoen 
203009ce9921SBecky Bruce #define BANK_BASE(i)	(((phys_addr_t [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i])
20312a112b23SWolfgang Denk 
2032be60a902SHaavard Skinnemoen 	/* Init: no FLASHes known */
20336d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
2034be60a902SHaavard Skinnemoen 		flash_info[i].flash_id = FLASH_UNKNOWN;
2035be60a902SHaavard Skinnemoen 
20362a112b23SWolfgang Denk 		if (!flash_detect_legacy (BANK_BASE(i), i))
20372a112b23SWolfgang Denk 			flash_get_size (BANK_BASE(i), i);
2038be60a902SHaavard Skinnemoen 		size += flash_info[i].size;
2039be60a902SHaavard Skinnemoen 		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
20406d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_QUIET_TEST
2041be60a902SHaavard Skinnemoen 			printf ("## Unknown FLASH on Bank %d "
2042be60a902SHaavard Skinnemoen 				"- Size = 0x%08lx = %ld MB\n",
2043be60a902SHaavard Skinnemoen 				i+1, flash_info[i].size,
2044be60a902SHaavard Skinnemoen 				flash_info[i].size << 20);
20456d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_QUIET_TEST */
204659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
20476d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
2048be60a902SHaavard Skinnemoen 		else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
2049be60a902SHaavard Skinnemoen 			/*
2050be60a902SHaavard Skinnemoen 			 * Only the U-Boot image and it's environment
2051be60a902SHaavard Skinnemoen 			 * is protected, all other sectors are
2052be60a902SHaavard Skinnemoen 			 * unprotected (unlocked) if flash hardware
20536d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 			 * protection is used (CONFIG_SYS_FLASH_PROTECTION)
2054be60a902SHaavard Skinnemoen 			 * and the environment variable "unlock" is
2055be60a902SHaavard Skinnemoen 			 * set to "yes".
2056be60a902SHaavard Skinnemoen 			 */
2057be60a902SHaavard Skinnemoen 			if (flash_info[i].legacy_unlock) {
2058be60a902SHaavard Skinnemoen 				int k;
205959829cc1SJean-Christophe PLAGNIOL-VILLARD 
2060be60a902SHaavard Skinnemoen 				/*
2061be60a902SHaavard Skinnemoen 				 * Disable legacy_unlock temporarily,
2062be60a902SHaavard Skinnemoen 				 * since flash_real_protect would
2063be60a902SHaavard Skinnemoen 				 * relock all other sectors again
2064be60a902SHaavard Skinnemoen 				 * otherwise.
2065be60a902SHaavard Skinnemoen 				 */
2066be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 0;
206759829cc1SJean-Christophe PLAGNIOL-VILLARD 
2068be60a902SHaavard Skinnemoen 				/*
2069be60a902SHaavard Skinnemoen 				 * Legacy unlocking (e.g. Intel J3) ->
2070be60a902SHaavard Skinnemoen 				 * unlock only one sector. This will
2071be60a902SHaavard Skinnemoen 				 * unlock all sectors.
2072be60a902SHaavard Skinnemoen 				 */
2073be60a902SHaavard Skinnemoen 				flash_real_protect (&flash_info[i], 0, 0);
207459829cc1SJean-Christophe PLAGNIOL-VILLARD 
2075be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 1;
207659829cc1SJean-Christophe PLAGNIOL-VILLARD 
2077be60a902SHaavard Skinnemoen 				/*
2078be60a902SHaavard Skinnemoen 				 * Manually mark other sectors as
2079be60a902SHaavard Skinnemoen 				 * unlocked (unprotected)
2080be60a902SHaavard Skinnemoen 				 */
2081be60a902SHaavard Skinnemoen 				for (k = 1; k < flash_info[i].sector_count; k++)
2082be60a902SHaavard Skinnemoen 					flash_info[i].protect[k] = 0;
2083be60a902SHaavard Skinnemoen 			} else {
2084be60a902SHaavard Skinnemoen 				/*
2085be60a902SHaavard Skinnemoen 				 * No legancy unlocking -> unlock all sectors
2086be60a902SHaavard Skinnemoen 				 */
2087be60a902SHaavard Skinnemoen 				flash_protect (FLAG_PROTECT_CLEAR,
2088be60a902SHaavard Skinnemoen 					       flash_info[i].start[0],
2089be60a902SHaavard Skinnemoen 					       flash_info[i].start[0]
2090be60a902SHaavard Skinnemoen 					       + flash_info[i].size - 1,
2091be60a902SHaavard Skinnemoen 					       &flash_info[i]);
209259829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
209359829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
20946d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */
209559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
209659829cc1SJean-Christophe PLAGNIOL-VILLARD 
2097be60a902SHaavard Skinnemoen 	/* Monitor protection ON by default */
20986d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
2099be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
21006d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_SYS_MONITOR_BASE,
21016d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_SYS_MONITOR_BASE + monitor_flash_len  - 1,
21026d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CONFIG_SYS_MONITOR_BASE));
2103be60a902SHaavard Skinnemoen #endif
210459829cc1SJean-Christophe PLAGNIOL-VILLARD 
2105be60a902SHaavard Skinnemoen 	/* Environment protection ON by default */
21065a1aceb0SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_ENV_IS_IN_FLASH
2107be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
21080e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_ENV_ADDR,
21090e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
21100e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CONFIG_ENV_ADDR));
2111be60a902SHaavard Skinnemoen #endif
2112be60a902SHaavard Skinnemoen 
2113be60a902SHaavard Skinnemoen 	/* Redundant environment protection ON by default */
21140e8d1586SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_ENV_ADDR_REDUND
2115be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
21160e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_ENV_ADDR_REDUND,
2117dfcd7f21SWolfgang Denk 		       CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1,
21180e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CONFIG_ENV_ADDR_REDUND));
2119be60a902SHaavard Skinnemoen #endif
2120c63ad632SMatthias Fuchs 
21216d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
2122c63ad632SMatthias Fuchs 	for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
2123c63ad632SMatthias Fuchs 		debug("autoprotecting from %08x to %08x\n",
2124c63ad632SMatthias Fuchs 		      apl[i].start, apl[i].start + apl[i].size - 1);
2125c63ad632SMatthias Fuchs 		flash_protect (FLAG_PROTECT_SET,
2126c63ad632SMatthias Fuchs 			       apl[i].start,
2127c63ad632SMatthias Fuchs 			       apl[i].start + apl[i].size - 1,
2128c63ad632SMatthias Fuchs 			       flash_get_info(apl[i].start));
2129c63ad632SMatthias Fuchs 	}
2130c63ad632SMatthias Fuchs #endif
213191809ed5SPiotr Ziecik 
213291809ed5SPiotr Ziecik #ifdef CONFIG_FLASH_CFI_MTD
213391809ed5SPiotr Ziecik 	cfi_mtd_init();
213491809ed5SPiotr Ziecik #endif
213591809ed5SPiotr Ziecik 
2136be60a902SHaavard Skinnemoen 	return (size);
213759829cc1SJean-Christophe PLAGNIOL-VILLARD }
2138