xref: /rk3399_rockchip-uboot/drivers/mtd/cfi_flash.c (revision ec21d5cfcb6b4e7fcdd5c6e926e1a824900706f2)
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 
10959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_MANUFACTURER_ID	0x00
11059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID		0x01
11159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID2		0x0E
11259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID3		0x0F
11359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI		0x55
11459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_ALT		0x555
11559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_RESP		0x10
11659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PRIMARY_VENDOR	0x13
1177e5b9b47SHaavard Skinnemoen /* extended query table primary address */
1187e5b9b47SHaavard Skinnemoen #define FLASH_OFFSET_EXT_QUERY_T_P_ADDR	0x15
11959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WTOUT		0x1F
12059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBTOUT		0x20
12159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ETOUT		0x21
12259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CETOUT		0x22
12359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WMAX_TOUT		0x23
12459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBMAX_TOUT		0x24
12559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EMAX_TOUT		0x25
12659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CEMAX_TOUT		0x26
12759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_SIZE		0x27
12859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTERFACE		0x28
12959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_BUFFER_SIZE	0x2A
13059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_NUM_ERASE_REGIONS	0x2C
13159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ERASE_REGIONS	0x2D
13259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PROTECT		0x02
13359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_USER_PROTECTION	0x85
13459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTEL_PROTECTION	0x81
13559829cc1SJean-Christophe PLAGNIOL-VILLARD 
13659829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_NONE			0
13759829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_EXTENDED	1
13859829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_STANDARD		2
13959829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_STANDARD	3
14059829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_EXTENDED		4
14159829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_STANDARD	256
14259829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_EXTENDED	257
14359829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_SST			258
1449c048b52SVasiliy Leoenenko #define CFI_CMDSET_INTEL_PROG_REGIONS	512
14559829cc1SJean-Christophe PLAGNIOL-VILLARD 
1466d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
14759829cc1SJean-Christophe PLAGNIOL-VILLARD # undef  FLASH_CMD_RESET
14859829cc1SJean-Christophe PLAGNIOL-VILLARD # define FLASH_CMD_RESET	AMD_CMD_RESET /* use AMD-Reset instead */
14959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
15059829cc1SJean-Christophe PLAGNIOL-VILLARD 
15159829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union {
15259829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned char c;
15359829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned short w;
15459829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long l;
15559829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long long ll;
15659829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiword_t;
15759829cc1SJean-Christophe PLAGNIOL-VILLARD 
15859829cc1SJean-Christophe PLAGNIOL-VILLARD #define NUM_ERASE_REGIONS	4 /* max. number of erase regions */
15959829cc1SJean-Christophe PLAGNIOL-VILLARD 
16059829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
1616ea808efSPiotr Ziecik static uint flash_verbose = 1;
16259829cc1SJean-Christophe PLAGNIOL-VILLARD 
1636d0f6bcfSJean-Christophe PLAGNIOL-VILLARD /* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */
1646d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT
1656d0f6bcfSJean-Christophe PLAGNIOL-VILLARD # define CFI_MAX_FLASH_BANKS	CONFIG_SYS_MAX_FLASH_BANKS_DETECT
16659829cc1SJean-Christophe PLAGNIOL-VILLARD #else
1676d0f6bcfSJean-Christophe PLAGNIOL-VILLARD # define CFI_MAX_FLASH_BANKS	CONFIG_SYS_MAX_FLASH_BANKS
16859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
16959829cc1SJean-Christophe PLAGNIOL-VILLARD 
1702a112b23SWolfgang Denk flash_info_t flash_info[CFI_MAX_FLASH_BANKS];	/* FLASH chips info */
1712a112b23SWolfgang Denk 
17259829cc1SJean-Christophe PLAGNIOL-VILLARD /*
17359829cc1SJean-Christophe PLAGNIOL-VILLARD  * Check if chip width is defined. If not, start detecting with 8bit.
17459829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1756d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_CFI_WIDTH
1766d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_FLASH_CFI_WIDTH	FLASH_CFI_8BIT
17759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
17859829cc1SJean-Christophe PLAGNIOL-VILLARD 
179e23741f4SHaavard Skinnemoen /* CFI standard query structure */
180e23741f4SHaavard Skinnemoen struct cfi_qry {
181e23741f4SHaavard Skinnemoen 	u8	qry[3];
182e23741f4SHaavard Skinnemoen 	u16	p_id;
183e23741f4SHaavard Skinnemoen 	u16	p_adr;
184e23741f4SHaavard Skinnemoen 	u16	a_id;
185e23741f4SHaavard Skinnemoen 	u16	a_adr;
186e23741f4SHaavard Skinnemoen 	u8	vcc_min;
187e23741f4SHaavard Skinnemoen 	u8	vcc_max;
188e23741f4SHaavard Skinnemoen 	u8	vpp_min;
189e23741f4SHaavard Skinnemoen 	u8	vpp_max;
190e23741f4SHaavard Skinnemoen 	u8	word_write_timeout_typ;
191e23741f4SHaavard Skinnemoen 	u8	buf_write_timeout_typ;
192e23741f4SHaavard Skinnemoen 	u8	block_erase_timeout_typ;
193e23741f4SHaavard Skinnemoen 	u8	chip_erase_timeout_typ;
194e23741f4SHaavard Skinnemoen 	u8	word_write_timeout_max;
195e23741f4SHaavard Skinnemoen 	u8	buf_write_timeout_max;
196e23741f4SHaavard Skinnemoen 	u8	block_erase_timeout_max;
197e23741f4SHaavard Skinnemoen 	u8	chip_erase_timeout_max;
198e23741f4SHaavard Skinnemoen 	u8	dev_size;
199e23741f4SHaavard Skinnemoen 	u16	interface_desc;
200e23741f4SHaavard Skinnemoen 	u16	max_buf_write_size;
201e23741f4SHaavard Skinnemoen 	u8	num_erase_regions;
202e23741f4SHaavard Skinnemoen 	u32	erase_region_info[NUM_ERASE_REGIONS];
203e23741f4SHaavard Skinnemoen } __attribute__((packed));
204e23741f4SHaavard Skinnemoen 
205e23741f4SHaavard Skinnemoen struct cfi_pri_hdr {
206e23741f4SHaavard Skinnemoen 	u8	pri[3];
207e23741f4SHaavard Skinnemoen 	u8	major_version;
208e23741f4SHaavard Skinnemoen 	u8	minor_version;
209e23741f4SHaavard Skinnemoen } __attribute__((packed));
210e23741f4SHaavard Skinnemoen 
21145aa5a7fSStefan Roese static void __flash_write8(u8 value, void *addr)
212cdbaefb5SHaavard Skinnemoen {
213cdbaefb5SHaavard Skinnemoen 	__raw_writeb(value, addr);
214cdbaefb5SHaavard Skinnemoen }
215cdbaefb5SHaavard Skinnemoen 
21645aa5a7fSStefan Roese static void __flash_write16(u16 value, void *addr)
217cdbaefb5SHaavard Skinnemoen {
218cdbaefb5SHaavard Skinnemoen 	__raw_writew(value, addr);
219cdbaefb5SHaavard Skinnemoen }
220cdbaefb5SHaavard Skinnemoen 
22145aa5a7fSStefan Roese static void __flash_write32(u32 value, void *addr)
222cdbaefb5SHaavard Skinnemoen {
223cdbaefb5SHaavard Skinnemoen 	__raw_writel(value, addr);
224cdbaefb5SHaavard Skinnemoen }
225cdbaefb5SHaavard Skinnemoen 
22645aa5a7fSStefan Roese static void __flash_write64(u64 value, void *addr)
227cdbaefb5SHaavard Skinnemoen {
228cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_writeq() */
229cdbaefb5SHaavard Skinnemoen 	*(volatile u64 *)addr = value;
230cdbaefb5SHaavard Skinnemoen }
231cdbaefb5SHaavard Skinnemoen 
23245aa5a7fSStefan Roese static u8 __flash_read8(void *addr)
233cdbaefb5SHaavard Skinnemoen {
234cdbaefb5SHaavard Skinnemoen 	return __raw_readb(addr);
235cdbaefb5SHaavard Skinnemoen }
236cdbaefb5SHaavard Skinnemoen 
23745aa5a7fSStefan Roese static u16 __flash_read16(void *addr)
238cdbaefb5SHaavard Skinnemoen {
239cdbaefb5SHaavard Skinnemoen 	return __raw_readw(addr);
240cdbaefb5SHaavard Skinnemoen }
241cdbaefb5SHaavard Skinnemoen 
24245aa5a7fSStefan Roese static u32 __flash_read32(void *addr)
243cdbaefb5SHaavard Skinnemoen {
244cdbaefb5SHaavard Skinnemoen 	return __raw_readl(addr);
245cdbaefb5SHaavard Skinnemoen }
246cdbaefb5SHaavard Skinnemoen 
24797bf85d7SDaniel Hellstrom static u64 __flash_read64(void *addr)
248cdbaefb5SHaavard Skinnemoen {
249cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_readq() */
250cdbaefb5SHaavard Skinnemoen 	return *(volatile u64 *)addr;
251cdbaefb5SHaavard Skinnemoen }
252cdbaefb5SHaavard Skinnemoen 
25345aa5a7fSStefan Roese #ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
25445aa5a7fSStefan Roese void flash_write8(u8 value, void *addr)__attribute__((weak, alias("__flash_write8")));
25545aa5a7fSStefan Roese void flash_write16(u16 value, void *addr)__attribute__((weak, alias("__flash_write16")));
25645aa5a7fSStefan Roese void flash_write32(u32 value, void *addr)__attribute__((weak, alias("__flash_write32")));
25745aa5a7fSStefan Roese void flash_write64(u64 value, void *addr)__attribute__((weak, alias("__flash_write64")));
25845aa5a7fSStefan Roese u8 flash_read8(void *addr)__attribute__((weak, alias("__flash_read8")));
25945aa5a7fSStefan Roese u16 flash_read16(void *addr)__attribute__((weak, alias("__flash_read16")));
26045aa5a7fSStefan Roese u32 flash_read32(void *addr)__attribute__((weak, alias("__flash_read32")));
26197bf85d7SDaniel Hellstrom u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
26245aa5a7fSStefan Roese #else
26345aa5a7fSStefan Roese #define flash_write8	__flash_write8
26445aa5a7fSStefan Roese #define flash_write16	__flash_write16
26545aa5a7fSStefan Roese #define flash_write32	__flash_write32
26645aa5a7fSStefan Roese #define flash_write64	__flash_write64
26745aa5a7fSStefan Roese #define flash_read8	__flash_read8
26845aa5a7fSStefan Roese #define flash_read16	__flash_read16
26945aa5a7fSStefan Roese #define flash_read32	__flash_read32
27045aa5a7fSStefan Roese #define flash_read64	__flash_read64
27145aa5a7fSStefan Roese #endif
27297bf85d7SDaniel Hellstrom 
273be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
274be60a902SHaavard Skinnemoen  */
2756d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
276be60a902SHaavard Skinnemoen static flash_info_t *flash_get_info(ulong base)
277be60a902SHaavard Skinnemoen {
278be60a902SHaavard Skinnemoen 	int i;
279be60a902SHaavard Skinnemoen 	flash_info_t * info = 0;
280be60a902SHaavard Skinnemoen 
2816d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
282be60a902SHaavard Skinnemoen 		info = & flash_info[i];
283be60a902SHaavard Skinnemoen 		if (info->size && info->start[0] <= base &&
284be60a902SHaavard Skinnemoen 		    base <= info->start[0] + info->size - 1)
285be60a902SHaavard Skinnemoen 			break;
286be60a902SHaavard Skinnemoen 	}
287be60a902SHaavard Skinnemoen 
2886d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
289be60a902SHaavard Skinnemoen }
29059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
29159829cc1SJean-Christophe PLAGNIOL-VILLARD 
29212d30aa7SHaavard Skinnemoen unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
29312d30aa7SHaavard Skinnemoen {
29412d30aa7SHaavard Skinnemoen 	if (sect != (info->sector_count - 1))
29512d30aa7SHaavard Skinnemoen 		return info->start[sect + 1] - info->start[sect];
29612d30aa7SHaavard Skinnemoen 	else
29712d30aa7SHaavard Skinnemoen 		return info->start[0] + info->size - info->start[sect];
29812d30aa7SHaavard Skinnemoen }
29912d30aa7SHaavard Skinnemoen 
30059829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
30159829cc1SJean-Christophe PLAGNIOL-VILLARD  * create an address based on the offset and the port width
30259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
30312d30aa7SHaavard Skinnemoen static inline void *
30412d30aa7SHaavard Skinnemoen flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
30559829cc1SJean-Christophe PLAGNIOL-VILLARD {
30612d30aa7SHaavard Skinnemoen 	unsigned int byte_offset = offset * info->portwidth;
30712d30aa7SHaavard Skinnemoen 
30809ce9921SBecky Bruce 	return (void *)(info->start[sect] + byte_offset);
30912d30aa7SHaavard Skinnemoen }
31012d30aa7SHaavard Skinnemoen 
31112d30aa7SHaavard Skinnemoen static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
31212d30aa7SHaavard Skinnemoen 		unsigned int offset, void *addr)
31312d30aa7SHaavard Skinnemoen {
31459829cc1SJean-Christophe PLAGNIOL-VILLARD }
31559829cc1SJean-Christophe PLAGNIOL-VILLARD 
316be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
317be60a902SHaavard Skinnemoen  * make a proper sized command based on the port and chip widths
318be60a902SHaavard Skinnemoen  */
3197288f972SSebastian Siewior static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
320be60a902SHaavard Skinnemoen {
321be60a902SHaavard Skinnemoen 	int i;
32293c56f21SVasiliy Leoenenko 	int cword_offset;
32393c56f21SVasiliy Leoenenko 	int cp_offset;
3246d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
325340ccb26SSebastian Siewior 	u32 cmd_le = cpu_to_le32(cmd);
326340ccb26SSebastian Siewior #endif
32793c56f21SVasiliy Leoenenko 	uchar val;
328be60a902SHaavard Skinnemoen 	uchar *cp = (uchar *) cmdbuf;
329be60a902SHaavard Skinnemoen 
33093c56f21SVasiliy Leoenenko 	for (i = info->portwidth; i > 0; i--){
33193c56f21SVasiliy Leoenenko 		cword_offset = (info->portwidth-i)%info->chipwidth;
3326d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
33393c56f21SVasiliy Leoenenko 		cp_offset = info->portwidth - i;
334340ccb26SSebastian Siewior 		val = *((uchar*)&cmd_le + cword_offset);
335be60a902SHaavard Skinnemoen #else
33693c56f21SVasiliy Leoenenko 		cp_offset = i - 1;
3377288f972SSebastian Siewior 		val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1);
338be60a902SHaavard Skinnemoen #endif
3397288f972SSebastian Siewior 		cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
34093c56f21SVasiliy Leoenenko 	}
341be60a902SHaavard Skinnemoen }
342be60a902SHaavard Skinnemoen 
34359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
34459829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
34559829cc1SJean-Christophe PLAGNIOL-VILLARD  * Debug support
34659829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3473055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data)
34859829cc1SJean-Christophe PLAGNIOL-VILLARD {
34959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
35059829cc1SJean-Christophe PLAGNIOL-VILLARD 	char *cp;
35159829cc1SJean-Christophe PLAGNIOL-VILLARD 
35259829cc1SJean-Christophe PLAGNIOL-VILLARD 	cp = (unsigned char *) &data;
35359829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 8; i++)
35459829cc1SJean-Christophe PLAGNIOL-VILLARD 		sprintf (&str[i * 2], "%2.2x", *cp++);
35559829cc1SJean-Christophe PLAGNIOL-VILLARD }
356be60a902SHaavard Skinnemoen 
357e23741f4SHaavard Skinnemoen static void flash_printqry (struct cfi_qry *qry)
35859829cc1SJean-Christophe PLAGNIOL-VILLARD {
359e23741f4SHaavard Skinnemoen 	u8 *p = (u8 *)qry;
36059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x, y;
36159829cc1SJean-Christophe PLAGNIOL-VILLARD 
362e23741f4SHaavard Skinnemoen 	for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
363e23741f4SHaavard Skinnemoen 		debug("%02x : ", x);
364e23741f4SHaavard Skinnemoen 		for (y = 0; y < 16; y++)
365e23741f4SHaavard Skinnemoen 			debug("%2.2x ", p[x + y]);
36659829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug(" ");
36759829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (y = 0; y < 16; y++) {
368e23741f4SHaavard Skinnemoen 			unsigned char c = p[x + y];
369e23741f4SHaavard Skinnemoen 			if (c >= 0x20 && c <= 0x7e)
370cdbaefb5SHaavard Skinnemoen 				debug("%c", c);
371e23741f4SHaavard Skinnemoen 			else
37259829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug(".");
37359829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
37459829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug("\n");
37559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
37659829cc1SJean-Christophe PLAGNIOL-VILLARD }
37759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
37859829cc1SJean-Christophe PLAGNIOL-VILLARD 
37959829cc1SJean-Christophe PLAGNIOL-VILLARD 
38059829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
38159829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a character at a port width address
38259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3833055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
38459829cc1SJean-Christophe PLAGNIOL-VILLARD {
38559829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *cp;
38612d30aa7SHaavard Skinnemoen 	uchar retval;
38759829cc1SJean-Christophe PLAGNIOL-VILLARD 
38812d30aa7SHaavard Skinnemoen 	cp = flash_map (info, 0, offset);
3896d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
39012d30aa7SHaavard Skinnemoen 	retval = flash_read8(cp);
39159829cc1SJean-Christophe PLAGNIOL-VILLARD #else
39212d30aa7SHaavard Skinnemoen 	retval = flash_read8(cp + info->portwidth - 1);
39359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
39412d30aa7SHaavard Skinnemoen 	flash_unmap (info, 0, offset, cp);
39512d30aa7SHaavard Skinnemoen 	return retval;
39659829cc1SJean-Christophe PLAGNIOL-VILLARD }
39759829cc1SJean-Christophe PLAGNIOL-VILLARD 
39859829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
39990447ecbSTor Krill  * read a word at a port width address, assume 16bit bus
40090447ecbSTor Krill  */
40190447ecbSTor Krill static inline ushort flash_read_word (flash_info_t * info, uint offset)
40290447ecbSTor Krill {
40390447ecbSTor Krill 	ushort *addr, retval;
40490447ecbSTor Krill 
40590447ecbSTor Krill 	addr = flash_map (info, 0, offset);
40690447ecbSTor Krill 	retval = flash_read16 (addr);
40790447ecbSTor Krill 	flash_unmap (info, 0, offset, addr);
40890447ecbSTor Krill 	return retval;
40990447ecbSTor Krill }
41090447ecbSTor Krill 
41190447ecbSTor Krill 
41290447ecbSTor Krill /*-----------------------------------------------------------------------
41359829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a long word by picking the least significant byte of each maximum
41459829cc1SJean-Christophe PLAGNIOL-VILLARD  * port size word. Swap for ppc format.
41559829cc1SJean-Christophe PLAGNIOL-VILLARD  */
4163055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
4173055793bSHaavard Skinnemoen 			      uint offset)
41859829cc1SJean-Christophe PLAGNIOL-VILLARD {
41959829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *addr;
42059829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong retval;
42159829cc1SJean-Christophe PLAGNIOL-VILLARD 
42259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
42359829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x;
42459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
42512d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
42659829cc1SJean-Christophe PLAGNIOL-VILLARD 
42759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
42859829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("long addr is at %p info->portwidth = %d\n", addr,
42959829cc1SJean-Christophe PLAGNIOL-VILLARD 	       info->portwidth);
43059829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (x = 0; x < 4 * info->portwidth; x++) {
43112d30aa7SHaavard Skinnemoen 		debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
43259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
43359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
4346d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
43512d30aa7SHaavard Skinnemoen 	retval = ((flash_read8(addr) << 16) |
43612d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + info->portwidth) << 24) |
43712d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 2 * info->portwidth)) |
43812d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 3 * info->portwidth) << 8));
43959829cc1SJean-Christophe PLAGNIOL-VILLARD #else
44012d30aa7SHaavard Skinnemoen 	retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
44112d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + info->portwidth - 1) << 16) |
44212d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
44312d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 3 * info->portwidth - 1)));
44459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
44512d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
44612d30aa7SHaavard Skinnemoen 
44759829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
44859829cc1SJean-Christophe PLAGNIOL-VILLARD }
44959829cc1SJean-Christophe PLAGNIOL-VILLARD 
450be60a902SHaavard Skinnemoen /*
451be60a902SHaavard Skinnemoen  * Write a proper sized command to the correct address
45281b20cccSMichael Schwingen  */
453be60a902SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
4547288f972SSebastian Siewior 			     uint offset, u32 cmd)
45581b20cccSMichael Schwingen {
4567e5b9b47SHaavard Skinnemoen 
457cdbaefb5SHaavard Skinnemoen 	void *addr;
458be60a902SHaavard Skinnemoen 	cfiword_t cword;
45981b20cccSMichael Schwingen 
46012d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
461be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
462be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
463be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
464cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
465be60a902SHaavard Skinnemoen 		       cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
466cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, addr);
467be60a902SHaavard Skinnemoen 		break;
468be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
469cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
470be60a902SHaavard Skinnemoen 		       cmd, cword.w,
471be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
472cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, addr);
473be60a902SHaavard Skinnemoen 		break;
474be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
475cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
476be60a902SHaavard Skinnemoen 		       cmd, cword.l,
477be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
478cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, addr);
479be60a902SHaavard Skinnemoen 		break;
480be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
481be60a902SHaavard Skinnemoen #ifdef DEBUG
482be60a902SHaavard Skinnemoen 		{
483be60a902SHaavard Skinnemoen 			char str[20];
484be60a902SHaavard Skinnemoen 
485be60a902SHaavard Skinnemoen 			print_longlong (str, cword.ll);
486be60a902SHaavard Skinnemoen 
487be60a902SHaavard Skinnemoen 			debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
488cdbaefb5SHaavard Skinnemoen 			       addr, cmd, str,
489be60a902SHaavard Skinnemoen 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
49081b20cccSMichael Schwingen 		}
491be60a902SHaavard Skinnemoen #endif
492cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, addr);
49381b20cccSMichael Schwingen 		break;
49481b20cccSMichael Schwingen 	}
495be60a902SHaavard Skinnemoen 
496be60a902SHaavard Skinnemoen 	/* Ensure all the instructions are fully finished */
497be60a902SHaavard Skinnemoen 	sync();
49812d30aa7SHaavard Skinnemoen 
49912d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
50081b20cccSMichael Schwingen }
5017e5b9b47SHaavard Skinnemoen 
502be60a902SHaavard Skinnemoen static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
503be60a902SHaavard Skinnemoen {
504be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
505be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
506be60a902SHaavard Skinnemoen }
507be60a902SHaavard Skinnemoen 
508be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
509be60a902SHaavard Skinnemoen  */
510be60a902SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect,
511be60a902SHaavard Skinnemoen 			  uint offset, uchar cmd)
512be60a902SHaavard Skinnemoen {
513cdbaefb5SHaavard Skinnemoen 	void *addr;
514be60a902SHaavard Skinnemoen 	cfiword_t cword;
515be60a902SHaavard Skinnemoen 	int retval;
516be60a902SHaavard Skinnemoen 
51712d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
518be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
519be60a902SHaavard Skinnemoen 
520cdbaefb5SHaavard Skinnemoen 	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
521be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
522be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
523cdbaefb5SHaavard Skinnemoen 		debug ("is= %x %x\n", flash_read8(addr), cword.c);
524cdbaefb5SHaavard Skinnemoen 		retval = (flash_read8(addr) == cword.c);
525be60a902SHaavard Skinnemoen 		break;
526be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
527cdbaefb5SHaavard Skinnemoen 		debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
528cdbaefb5SHaavard Skinnemoen 		retval = (flash_read16(addr) == cword.w);
529be60a902SHaavard Skinnemoen 		break;
530be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
53152514699SAndrew Klossner 		debug ("is= %8.8x %8.8lx\n", flash_read32(addr), cword.l);
532cdbaefb5SHaavard Skinnemoen 		retval = (flash_read32(addr) == cword.l);
533be60a902SHaavard Skinnemoen 		break;
534be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
535be60a902SHaavard Skinnemoen #ifdef DEBUG
536be60a902SHaavard Skinnemoen 		{
537be60a902SHaavard Skinnemoen 			char str1[20];
538be60a902SHaavard Skinnemoen 			char str2[20];
539be60a902SHaavard Skinnemoen 
540cdbaefb5SHaavard Skinnemoen 			print_longlong (str1, flash_read64(addr));
541be60a902SHaavard Skinnemoen 			print_longlong (str2, cword.ll);
542be60a902SHaavard Skinnemoen 			debug ("is= %s %s\n", str1, str2);
543be60a902SHaavard Skinnemoen 		}
544be60a902SHaavard Skinnemoen #endif
545cdbaefb5SHaavard Skinnemoen 		retval = (flash_read64(addr) == cword.ll);
546be60a902SHaavard Skinnemoen 		break;
547be60a902SHaavard Skinnemoen 	default:
548be60a902SHaavard Skinnemoen 		retval = 0;
549be60a902SHaavard Skinnemoen 		break;
550be60a902SHaavard Skinnemoen 	}
55112d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
55212d30aa7SHaavard Skinnemoen 
553be60a902SHaavard Skinnemoen 	return retval;
554be60a902SHaavard Skinnemoen }
555be60a902SHaavard Skinnemoen 
556be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
557be60a902SHaavard Skinnemoen  */
558be60a902SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect,
559be60a902SHaavard Skinnemoen 			uint offset, uchar cmd)
560be60a902SHaavard Skinnemoen {
561cdbaefb5SHaavard Skinnemoen 	void *addr;
562be60a902SHaavard Skinnemoen 	cfiword_t cword;
563be60a902SHaavard Skinnemoen 	int retval;
564be60a902SHaavard Skinnemoen 
56512d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
566be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
567be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
568be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
569cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read8(addr) & cword.c) == cword.c);
570be60a902SHaavard Skinnemoen 		break;
571be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
572cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read16(addr) & cword.w) == cword.w);
573be60a902SHaavard Skinnemoen 		break;
574be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
57547cc23cbSStefan Roese 		retval = ((flash_read32(addr) & cword.l) == cword.l);
576be60a902SHaavard Skinnemoen 		break;
577be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
578cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read64(addr) & cword.ll) == cword.ll);
579be60a902SHaavard Skinnemoen 		break;
580be60a902SHaavard Skinnemoen 	default:
581be60a902SHaavard Skinnemoen 		retval = 0;
582be60a902SHaavard Skinnemoen 		break;
583be60a902SHaavard Skinnemoen 	}
58412d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
58512d30aa7SHaavard Skinnemoen 
586be60a902SHaavard Skinnemoen 	return retval;
587be60a902SHaavard Skinnemoen }
588be60a902SHaavard Skinnemoen 
589be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
590be60a902SHaavard Skinnemoen  */
591be60a902SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect,
592be60a902SHaavard Skinnemoen 			 uint offset, uchar cmd)
593be60a902SHaavard Skinnemoen {
594cdbaefb5SHaavard Skinnemoen 	void *addr;
595be60a902SHaavard Skinnemoen 	cfiword_t cword;
596be60a902SHaavard Skinnemoen 	int retval;
597be60a902SHaavard Skinnemoen 
59812d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
599be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
600be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
601be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
602fb8c061eSStefan Roese 		retval = flash_read8(addr) != flash_read8(addr);
603be60a902SHaavard Skinnemoen 		break;
604be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
605fb8c061eSStefan Roese 		retval = flash_read16(addr) != flash_read16(addr);
606be60a902SHaavard Skinnemoen 		break;
607be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
608fb8c061eSStefan Roese 		retval = flash_read32(addr) != flash_read32(addr);
609be60a902SHaavard Skinnemoen 		break;
610be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
6119abda6baSWolfgang Denk 		retval = ( (flash_read32( addr ) != flash_read32( addr )) ||
6129abda6baSWolfgang Denk 			   (flash_read32(addr+4) != flash_read32(addr+4)) );
613be60a902SHaavard Skinnemoen 		break;
614be60a902SHaavard Skinnemoen 	default:
615be60a902SHaavard Skinnemoen 		retval = 0;
616be60a902SHaavard Skinnemoen 		break;
617be60a902SHaavard Skinnemoen 	}
61812d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
61912d30aa7SHaavard Skinnemoen 
620be60a902SHaavard Skinnemoen 	return retval;
621be60a902SHaavard Skinnemoen }
622be60a902SHaavard Skinnemoen 
623be60a902SHaavard Skinnemoen /*
624be60a902SHaavard Skinnemoen  * flash_is_busy - check to see if the flash is busy
625be60a902SHaavard Skinnemoen  *
626be60a902SHaavard Skinnemoen  * This routine checks the status of the chip and returns true if the
627be60a902SHaavard Skinnemoen  * chip is busy.
628be60a902SHaavard Skinnemoen  */
629be60a902SHaavard Skinnemoen static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
630be60a902SHaavard Skinnemoen {
631be60a902SHaavard Skinnemoen 	int retval;
632be60a902SHaavard Skinnemoen 
63381b20cccSMichael Schwingen 	switch (info->vendor) {
6349c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
63581b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_STANDARD:
63681b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_EXTENDED:
637be60a902SHaavard Skinnemoen 		retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
63881b20cccSMichael Schwingen 		break;
63981b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_STANDARD:
64081b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_EXTENDED:
641be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
64281b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_LEGACY:
643be60a902SHaavard Skinnemoen #endif
644be60a902SHaavard Skinnemoen 		retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
645be60a902SHaavard Skinnemoen 		break;
646be60a902SHaavard Skinnemoen 	default:
647be60a902SHaavard Skinnemoen 		retval = 0;
648be60a902SHaavard Skinnemoen 	}
649be60a902SHaavard Skinnemoen 	debug ("flash_is_busy: %d\n", retval);
650be60a902SHaavard Skinnemoen 	return retval;
651be60a902SHaavard Skinnemoen }
652be60a902SHaavard Skinnemoen 
653be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
654be60a902SHaavard Skinnemoen  *  wait for XSR.7 to be set. Time out with an error if it does not.
655be60a902SHaavard Skinnemoen  *  This routine does not set the flash to read-array mode.
656be60a902SHaavard Skinnemoen  */
657be60a902SHaavard Skinnemoen static int flash_status_check (flash_info_t * info, flash_sect_t sector,
658be60a902SHaavard Skinnemoen 			       ulong tout, char *prompt)
659be60a902SHaavard Skinnemoen {
660be60a902SHaavard Skinnemoen 	ulong start;
661be60a902SHaavard Skinnemoen 
6626d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if CONFIG_SYS_HZ != 1000
6636d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	tout *= CONFIG_SYS_HZ/1000;
664be60a902SHaavard Skinnemoen #endif
665be60a902SHaavard Skinnemoen 
666be60a902SHaavard Skinnemoen 	/* Wait for command completion */
667be60a902SHaavard Skinnemoen 	start = get_timer (0);
668be60a902SHaavard Skinnemoen 	while (flash_is_busy (info, sector)) {
669be60a902SHaavard Skinnemoen 		if (get_timer (start) > tout) {
670be60a902SHaavard Skinnemoen 			printf ("Flash %s timeout at address %lx data %lx\n",
671be60a902SHaavard Skinnemoen 				prompt, info->start[sector],
672be60a902SHaavard Skinnemoen 				flash_read_long (info, sector, 0));
673be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0, info->cmd_reset);
674be60a902SHaavard Skinnemoen 			return ERR_TIMOUT;
675be60a902SHaavard Skinnemoen 		}
676be60a902SHaavard Skinnemoen 		udelay (1);		/* also triggers watchdog */
677be60a902SHaavard Skinnemoen 	}
678be60a902SHaavard Skinnemoen 	return ERR_OK;
679be60a902SHaavard Skinnemoen }
680be60a902SHaavard Skinnemoen 
681be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
682be60a902SHaavard Skinnemoen  * Wait for XSR.7 to be set, if it times out print an error, otherwise
683be60a902SHaavard Skinnemoen  * do a full status check.
684be60a902SHaavard Skinnemoen  *
685be60a902SHaavard Skinnemoen  * This routine sets the flash to read-array mode.
686be60a902SHaavard Skinnemoen  */
687be60a902SHaavard Skinnemoen static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
688be60a902SHaavard Skinnemoen 				    ulong tout, char *prompt)
689be60a902SHaavard Skinnemoen {
690be60a902SHaavard Skinnemoen 	int retcode;
691be60a902SHaavard Skinnemoen 
692be60a902SHaavard Skinnemoen 	retcode = flash_status_check (info, sector, tout, prompt);
693be60a902SHaavard Skinnemoen 	switch (info->vendor) {
6949c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
695be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
696be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
6970d01f66dSEd Swarthout 		if ((retcode != ERR_OK)
698be60a902SHaavard Skinnemoen 		    && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
699be60a902SHaavard Skinnemoen 			retcode = ERR_INVAL;
700be60a902SHaavard Skinnemoen 			printf ("Flash %s error at address %lx\n", prompt,
701be60a902SHaavard Skinnemoen 				info->start[sector]);
702be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
703be60a902SHaavard Skinnemoen 					 FLASH_STATUS_PSLBS)) {
704be60a902SHaavard Skinnemoen 				puts ("Command Sequence Error.\n");
705be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
706be60a902SHaavard Skinnemoen 						FLASH_STATUS_ECLBS)) {
707be60a902SHaavard Skinnemoen 				puts ("Block Erase Error.\n");
708be60a902SHaavard Skinnemoen 				retcode = ERR_NOT_ERASED;
709be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
710be60a902SHaavard Skinnemoen 						FLASH_STATUS_PSLBS)) {
711be60a902SHaavard Skinnemoen 				puts ("Locking Error\n");
712be60a902SHaavard Skinnemoen 			}
713be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
714be60a902SHaavard Skinnemoen 				puts ("Block locked.\n");
715be60a902SHaavard Skinnemoen 				retcode = ERR_PROTECTED;
716be60a902SHaavard Skinnemoen 			}
717be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
718be60a902SHaavard Skinnemoen 				puts ("Vpp Low Error.\n");
719be60a902SHaavard Skinnemoen 		}
720be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, info->cmd_reset);
721be60a902SHaavard Skinnemoen 		break;
722be60a902SHaavard Skinnemoen 	default:
72381b20cccSMichael Schwingen 		break;
72481b20cccSMichael Schwingen 	}
725be60a902SHaavard Skinnemoen 	return retcode;
72681b20cccSMichael Schwingen }
727be60a902SHaavard Skinnemoen 
728be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
729be60a902SHaavard Skinnemoen  */
730be60a902SHaavard Skinnemoen static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
731be60a902SHaavard Skinnemoen {
7326d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
733be60a902SHaavard Skinnemoen 	unsigned short	w;
734be60a902SHaavard Skinnemoen 	unsigned int	l;
735be60a902SHaavard Skinnemoen 	unsigned long long ll;
736be60a902SHaavard Skinnemoen #endif
737be60a902SHaavard Skinnemoen 
738be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
739be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
740be60a902SHaavard Skinnemoen 		cword->c = c;
741be60a902SHaavard Skinnemoen 		break;
742be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
7436d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
744be60a902SHaavard Skinnemoen 		w = c;
745be60a902SHaavard Skinnemoen 		w <<= 8;
746be60a902SHaavard Skinnemoen 		cword->w = (cword->w >> 8) | w;
74781b20cccSMichael Schwingen #else
748be60a902SHaavard Skinnemoen 		cword->w = (cword->w << 8) | c;
749be60a902SHaavard Skinnemoen #endif
750be60a902SHaavard Skinnemoen 		break;
751be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
7526d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
753be60a902SHaavard Skinnemoen 		l = c;
754be60a902SHaavard Skinnemoen 		l <<= 24;
755be60a902SHaavard Skinnemoen 		cword->l = (cword->l >> 8) | l;
756be60a902SHaavard Skinnemoen #else
757be60a902SHaavard Skinnemoen 		cword->l = (cword->l << 8) | c;
758be60a902SHaavard Skinnemoen #endif
759be60a902SHaavard Skinnemoen 		break;
760be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
7616d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
762be60a902SHaavard Skinnemoen 		ll = c;
763be60a902SHaavard Skinnemoen 		ll <<= 56;
764be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll >> 8) | ll;
765be60a902SHaavard Skinnemoen #else
766be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll << 8) | c;
767be60a902SHaavard Skinnemoen #endif
768be60a902SHaavard Skinnemoen 		break;
769be60a902SHaavard Skinnemoen 	}
770be60a902SHaavard Skinnemoen }
771be60a902SHaavard Skinnemoen 
7720f8e851eSJens Gehrlein /*
7730f8e851eSJens Gehrlein  * Loop through the sector table starting from the previously found sector.
7740f8e851eSJens Gehrlein  * Searches forwards or backwards, dependent on the passed address.
775be60a902SHaavard Skinnemoen  */
776be60a902SHaavard Skinnemoen static flash_sect_t find_sector (flash_info_t * info, ulong addr)
77781b20cccSMichael Schwingen {
7780f8e851eSJens Gehrlein 	static flash_sect_t saved_sector = 0; /* previously found sector */
7790f8e851eSJens Gehrlein 	flash_sect_t sector = saved_sector;
780be60a902SHaavard Skinnemoen 
7810f8e851eSJens Gehrlein 	while ((info->start[sector] < addr)
7820f8e851eSJens Gehrlein 			&& (sector < info->sector_count - 1))
7830f8e851eSJens Gehrlein 		sector++;
7840f8e851eSJens Gehrlein 	while ((info->start[sector] > addr) && (sector > 0))
7850f8e851eSJens Gehrlein 		/*
7860f8e851eSJens Gehrlein 		 * also decrements the sector in case of an overshot
7870f8e851eSJens Gehrlein 		 * in the first loop
7880f8e851eSJens Gehrlein 		 */
7890f8e851eSJens Gehrlein 		sector--;
7900f8e851eSJens Gehrlein 
7910f8e851eSJens Gehrlein 	saved_sector = sector;
792be60a902SHaavard Skinnemoen 	return sector;
79359829cc1SJean-Christophe PLAGNIOL-VILLARD }
79459829cc1SJean-Christophe PLAGNIOL-VILLARD 
79559829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
79659829cc1SJean-Christophe PLAGNIOL-VILLARD  */
797be60a902SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest,
798be60a902SHaavard Skinnemoen 				cfiword_t cword)
79959829cc1SJean-Christophe PLAGNIOL-VILLARD {
80009ce9921SBecky Bruce 	void *dstaddr = (void *)dest;
801be60a902SHaavard Skinnemoen 	int flag;
802a7292871SJens Gehrlein 	flash_sect_t sect = 0;
803a7292871SJens Gehrlein 	char sect_found = 0;
80459829cc1SJean-Christophe PLAGNIOL-VILLARD 
805be60a902SHaavard Skinnemoen 	/* Check if Flash is (sufficiently) erased */
806be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
807be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
808cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
809be60a902SHaavard Skinnemoen 		break;
810be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
811cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
812be60a902SHaavard Skinnemoen 		break;
813be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
814cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
815be60a902SHaavard Skinnemoen 		break;
816be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
817cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
818be60a902SHaavard Skinnemoen 		break;
819be60a902SHaavard Skinnemoen 	default:
82012d30aa7SHaavard Skinnemoen 		flag = 0;
82112d30aa7SHaavard Skinnemoen 		break;
82212d30aa7SHaavard Skinnemoen 	}
82309ce9921SBecky Bruce 	if (!flag)
8240dc80e27SStefan Roese 		return ERR_NOT_ERASED;
825be60a902SHaavard Skinnemoen 
826be60a902SHaavard Skinnemoen 	/* Disable interrupts which might cause a timeout here */
827be60a902SHaavard Skinnemoen 	flag = disable_interrupts ();
828be60a902SHaavard Skinnemoen 
829be60a902SHaavard Skinnemoen 	switch (info->vendor) {
8309c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
831be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
832be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
833be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
834be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
835be60a902SHaavard Skinnemoen 		break;
836be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
837be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
838be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
839be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_LEGACY:
840be60a902SHaavard Skinnemoen #endif
8410d01f66dSEd Swarthout 		sect = find_sector(info, dest);
8420d01f66dSEd Swarthout 		flash_unlock_seq (info, sect);
8430d01f66dSEd Swarthout 		flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE);
844a7292871SJens Gehrlein 		sect_found = 1;
84559829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
84659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
84759829cc1SJean-Christophe PLAGNIOL-VILLARD 
848be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
849be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
850cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, dstaddr);
851be60a902SHaavard Skinnemoen 		break;
852be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
853cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, dstaddr);
854be60a902SHaavard Skinnemoen 		break;
855be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
856cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, dstaddr);
857be60a902SHaavard Skinnemoen 		break;
858be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
859cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, dstaddr);
860be60a902SHaavard Skinnemoen 		break;
86159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
862be60a902SHaavard Skinnemoen 
863be60a902SHaavard Skinnemoen 	/* re-enable interrupts if necessary */
864be60a902SHaavard Skinnemoen 	if (flag)
865be60a902SHaavard Skinnemoen 		enable_interrupts ();
866be60a902SHaavard Skinnemoen 
867a7292871SJens Gehrlein 	if (!sect_found)
868a7292871SJens Gehrlein 		sect = find_sector (info, dest);
869a7292871SJens Gehrlein 
870a7292871SJens Gehrlein 	return flash_full_status_check (info, sect, info->write_tout, "write");
871be60a902SHaavard Skinnemoen }
872be60a902SHaavard Skinnemoen 
8736d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
874be60a902SHaavard Skinnemoen 
875be60a902SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
876be60a902SHaavard Skinnemoen 				  int len)
877be60a902SHaavard Skinnemoen {
878be60a902SHaavard Skinnemoen 	flash_sect_t sector;
879be60a902SHaavard Skinnemoen 	int cnt;
880be60a902SHaavard Skinnemoen 	int retcode;
881cdbaefb5SHaavard Skinnemoen 	void *src = cp;
882*ec21d5cfSStefan Roese 	void *dst = (void *)dest;
8830dc80e27SStefan Roese 	void *dst2 = dst;
8840dc80e27SStefan Roese 	int flag = 0;
88596ef831fSGuennadi Liakhovetski 	uint offset = 0;
88696ef831fSGuennadi Liakhovetski 	unsigned int shift;
8879c048b52SVasiliy Leoenenko 	uchar write_cmd;
888cdbaefb5SHaavard Skinnemoen 
8890dc80e27SStefan Roese 	switch (info->portwidth) {
8900dc80e27SStefan Roese 	case FLASH_CFI_8BIT:
89196ef831fSGuennadi Liakhovetski 		shift = 0;
8920dc80e27SStefan Roese 		break;
8930dc80e27SStefan Roese 	case FLASH_CFI_16BIT:
89496ef831fSGuennadi Liakhovetski 		shift = 1;
8950dc80e27SStefan Roese 		break;
8960dc80e27SStefan Roese 	case FLASH_CFI_32BIT:
89796ef831fSGuennadi Liakhovetski 		shift = 2;
8980dc80e27SStefan Roese 		break;
8990dc80e27SStefan Roese 	case FLASH_CFI_64BIT:
90096ef831fSGuennadi Liakhovetski 		shift = 3;
9010dc80e27SStefan Roese 		break;
9020dc80e27SStefan Roese 	default:
9030dc80e27SStefan Roese 		retcode = ERR_INVAL;
9040dc80e27SStefan Roese 		goto out_unmap;
9050dc80e27SStefan Roese 	}
9060dc80e27SStefan Roese 
90796ef831fSGuennadi Liakhovetski 	cnt = len >> shift;
90896ef831fSGuennadi Liakhovetski 
9090dc80e27SStefan Roese 	while ((cnt-- > 0) && (flag == 0)) {
9100dc80e27SStefan Roese 		switch (info->portwidth) {
9110dc80e27SStefan Roese 		case FLASH_CFI_8BIT:
9120dc80e27SStefan Roese 			flag = ((flash_read8(dst2) & flash_read8(src)) ==
9130dc80e27SStefan Roese 				flash_read8(src));
9140dc80e27SStefan Roese 			src += 1, dst2 += 1;
9150dc80e27SStefan Roese 			break;
9160dc80e27SStefan Roese 		case FLASH_CFI_16BIT:
9170dc80e27SStefan Roese 			flag = ((flash_read16(dst2) & flash_read16(src)) ==
9180dc80e27SStefan Roese 				flash_read16(src));
9190dc80e27SStefan Roese 			src += 2, dst2 += 2;
9200dc80e27SStefan Roese 			break;
9210dc80e27SStefan Roese 		case FLASH_CFI_32BIT:
9220dc80e27SStefan Roese 			flag = ((flash_read32(dst2) & flash_read32(src)) ==
9230dc80e27SStefan Roese 				flash_read32(src));
9240dc80e27SStefan Roese 			src += 4, dst2 += 4;
9250dc80e27SStefan Roese 			break;
9260dc80e27SStefan Roese 		case FLASH_CFI_64BIT:
9270dc80e27SStefan Roese 			flag = ((flash_read64(dst2) & flash_read64(src)) ==
9280dc80e27SStefan Roese 				flash_read64(src));
9290dc80e27SStefan Roese 			src += 8, dst2 += 8;
9300dc80e27SStefan Roese 			break;
9310dc80e27SStefan Roese 		}
9320dc80e27SStefan Roese 	}
9330dc80e27SStefan Roese 	if (!flag) {
9340dc80e27SStefan Roese 		retcode = ERR_NOT_ERASED;
9350dc80e27SStefan Roese 		goto out_unmap;
9360dc80e27SStefan Roese 	}
9370dc80e27SStefan Roese 
9380dc80e27SStefan Roese 	src = cp;
939cdbaefb5SHaavard Skinnemoen 	sector = find_sector (info, dest);
940be60a902SHaavard Skinnemoen 
941be60a902SHaavard Skinnemoen 	switch (info->vendor) {
9429c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
943be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
944be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
9459c048b52SVasiliy Leoenenko 		write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
9469c048b52SVasiliy Leoenenko 					FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER;
947be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
9489c048b52SVasiliy Leoenenko 		flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS);
9499c048b52SVasiliy Leoenenko 		flash_write_cmd (info, sector, 0, write_cmd);
950be60a902SHaavard Skinnemoen 		retcode = flash_status_check (info, sector,
951be60a902SHaavard Skinnemoen 					      info->buffer_write_tout,
952be60a902SHaavard Skinnemoen 					      "write to buffer");
953be60a902SHaavard Skinnemoen 		if (retcode == ERR_OK) {
954be60a902SHaavard Skinnemoen 			/* reduce the number of loops by the width of
955be60a902SHaavard Skinnemoen 			 * the port */
95696ef831fSGuennadi Liakhovetski 			cnt = len >> shift;
95793c56f21SVasiliy Leoenenko 			flash_write_cmd (info, sector, 0, cnt - 1);
958be60a902SHaavard Skinnemoen 			while (cnt-- > 0) {
959be60a902SHaavard Skinnemoen 				switch (info->portwidth) {
960be60a902SHaavard Skinnemoen 				case FLASH_CFI_8BIT:
961cdbaefb5SHaavard Skinnemoen 					flash_write8(flash_read8(src), dst);
962cdbaefb5SHaavard Skinnemoen 					src += 1, dst += 1;
963be60a902SHaavard Skinnemoen 					break;
964be60a902SHaavard Skinnemoen 				case FLASH_CFI_16BIT:
965cdbaefb5SHaavard Skinnemoen 					flash_write16(flash_read16(src), dst);
966cdbaefb5SHaavard Skinnemoen 					src += 2, dst += 2;
967be60a902SHaavard Skinnemoen 					break;
968be60a902SHaavard Skinnemoen 				case FLASH_CFI_32BIT:
969cdbaefb5SHaavard Skinnemoen 					flash_write32(flash_read32(src), dst);
970cdbaefb5SHaavard Skinnemoen 					src += 4, dst += 4;
971be60a902SHaavard Skinnemoen 					break;
972be60a902SHaavard Skinnemoen 				case FLASH_CFI_64BIT:
973cdbaefb5SHaavard Skinnemoen 					flash_write64(flash_read64(src), dst);
974cdbaefb5SHaavard Skinnemoen 					src += 8, dst += 8;
975be60a902SHaavard Skinnemoen 					break;
976be60a902SHaavard Skinnemoen 				default:
97712d30aa7SHaavard Skinnemoen 					retcode = ERR_INVAL;
97812d30aa7SHaavard Skinnemoen 					goto out_unmap;
979be60a902SHaavard Skinnemoen 				}
980be60a902SHaavard Skinnemoen 			}
981be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,
982be60a902SHaavard Skinnemoen 					 FLASH_CMD_WRITE_BUFFER_CONFIRM);
983be60a902SHaavard Skinnemoen 			retcode = flash_full_status_check (
984be60a902SHaavard Skinnemoen 				info, sector, info->buffer_write_tout,
985be60a902SHaavard Skinnemoen 				"buffer write");
986be60a902SHaavard Skinnemoen 		}
98712d30aa7SHaavard Skinnemoen 
98812d30aa7SHaavard Skinnemoen 		break;
989be60a902SHaavard Skinnemoen 
990be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
991be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
992be60a902SHaavard Skinnemoen 		flash_unlock_seq(info,0);
99396ef831fSGuennadi Liakhovetski 
99496ef831fSGuennadi Liakhovetski #ifdef CONFIG_FLASH_SPANSION_S29WS_N
99596ef831fSGuennadi Liakhovetski 		offset = ((unsigned long)dst - info->start[sector]) >> shift;
99696ef831fSGuennadi Liakhovetski #endif
99796ef831fSGuennadi Liakhovetski 		flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
99896ef831fSGuennadi Liakhovetski 		cnt = len >> shift;
99996ef831fSGuennadi Liakhovetski 		flash_write_cmd(info, sector, offset, (uchar)cnt - 1);
1000be60a902SHaavard Skinnemoen 
1001be60a902SHaavard Skinnemoen 		switch (info->portwidth) {
1002be60a902SHaavard Skinnemoen 		case FLASH_CFI_8BIT:
1003cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
1004cdbaefb5SHaavard Skinnemoen 				flash_write8(flash_read8(src), dst);
1005cdbaefb5SHaavard Skinnemoen 				src += 1, dst += 1;
1006cdbaefb5SHaavard Skinnemoen 			}
1007be60a902SHaavard Skinnemoen 			break;
1008be60a902SHaavard Skinnemoen 		case FLASH_CFI_16BIT:
1009cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
1010cdbaefb5SHaavard Skinnemoen 				flash_write16(flash_read16(src), dst);
1011cdbaefb5SHaavard Skinnemoen 				src += 2, dst += 2;
1012cdbaefb5SHaavard Skinnemoen 			}
1013be60a902SHaavard Skinnemoen 			break;
1014be60a902SHaavard Skinnemoen 		case FLASH_CFI_32BIT:
1015cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
1016cdbaefb5SHaavard Skinnemoen 				flash_write32(flash_read32(src), dst);
1017cdbaefb5SHaavard Skinnemoen 				src += 4, dst += 4;
1018cdbaefb5SHaavard Skinnemoen 			}
1019be60a902SHaavard Skinnemoen 			break;
1020be60a902SHaavard Skinnemoen 		case FLASH_CFI_64BIT:
1021cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
1022cdbaefb5SHaavard Skinnemoen 				flash_write64(flash_read64(src), dst);
1023cdbaefb5SHaavard Skinnemoen 				src += 8, dst += 8;
1024cdbaefb5SHaavard Skinnemoen 			}
1025be60a902SHaavard Skinnemoen 			break;
1026be60a902SHaavard Skinnemoen 		default:
102712d30aa7SHaavard Skinnemoen 			retcode = ERR_INVAL;
102812d30aa7SHaavard Skinnemoen 			goto out_unmap;
1029be60a902SHaavard Skinnemoen 		}
1030be60a902SHaavard Skinnemoen 
1031be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1032be60a902SHaavard Skinnemoen 		retcode = flash_full_status_check (info, sector,
1033be60a902SHaavard Skinnemoen 						   info->buffer_write_tout,
1034be60a902SHaavard Skinnemoen 						   "buffer write");
103512d30aa7SHaavard Skinnemoen 		break;
1036be60a902SHaavard Skinnemoen 
1037be60a902SHaavard Skinnemoen 	default:
1038be60a902SHaavard Skinnemoen 		debug ("Unknown Command Set\n");
103912d30aa7SHaavard Skinnemoen 		retcode = ERR_INVAL;
104012d30aa7SHaavard Skinnemoen 		break;
1041be60a902SHaavard Skinnemoen 	}
104212d30aa7SHaavard Skinnemoen 
104312d30aa7SHaavard Skinnemoen out_unmap:
104412d30aa7SHaavard Skinnemoen 	return retcode;
1045be60a902SHaavard Skinnemoen }
10466d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
1047be60a902SHaavard Skinnemoen 
104859829cc1SJean-Christophe PLAGNIOL-VILLARD 
104959829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
105059829cc1SJean-Christophe PLAGNIOL-VILLARD  */
105159829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last)
105259829cc1SJean-Christophe PLAGNIOL-VILLARD {
105359829cc1SJean-Christophe PLAGNIOL-VILLARD 	int rcode = 0;
105459829cc1SJean-Christophe PLAGNIOL-VILLARD 	int prot;
105559829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect;
105659829cc1SJean-Christophe PLAGNIOL-VILLARD 
105759829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
105859829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("Can't erase unknown flash type - aborted\n");
105959829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
106059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
106159829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((s_first < 0) || (s_first > s_last)) {
106259829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("- no sectors to erase\n");
106359829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
106459829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
106559829cc1SJean-Christophe PLAGNIOL-VILLARD 
106659829cc1SJean-Christophe PLAGNIOL-VILLARD 	prot = 0;
106759829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; ++sect) {
106859829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect]) {
106959829cc1SJean-Christophe PLAGNIOL-VILLARD 			prot++;
107059829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
107159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
107259829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot) {
10737e5b9b47SHaavard Skinnemoen 		printf ("- Warning: %d protected sectors will not be erased!\n",
10747e5b9b47SHaavard Skinnemoen 			prot);
10756ea808efSPiotr Ziecik 	} else if (flash_verbose) {
107659829cc1SJean-Christophe PLAGNIOL-VILLARD 		putc ('\n');
107759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
107859829cc1SJean-Christophe PLAGNIOL-VILLARD 
107959829cc1SJean-Christophe PLAGNIOL-VILLARD 
108059829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; sect++) {
108159829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect] == 0) { /* not protected */
108259829cc1SJean-Christophe PLAGNIOL-VILLARD 			switch (info->vendor) {
10839c048b52SVasiliy Leoenenko 			case CFI_CMDSET_INTEL_PROG_REGIONS:
108459829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_STANDARD:
108559829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_EXTENDED:
10867e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10877e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_CLEAR_STATUS);
10887e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10897e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_BLOCK_ERASE);
10907e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10917e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_ERASE_CONFIRM);
109259829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
109359829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_STANDARD:
109459829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_EXTENDED:
109559829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
10967e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect,
10977e5b9b47SHaavard Skinnemoen 						info->addr_unlock1,
10987e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
109959829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
11007e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
11017e5b9b47SHaavard Skinnemoen 						 AMD_CMD_ERASE_SECTOR);
110259829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
110381b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
110481b20cccSMichael Schwingen 			case CFI_CMDSET_AMD_LEGACY:
110581b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
11067e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, 0, info->addr_unlock1,
11077e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
110881b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
11097e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
11107e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_SECTOR);
111181b20cccSMichael Schwingen 				break;
111281b20cccSMichael Schwingen #endif
111359829cc1SJean-Christophe PLAGNIOL-VILLARD 			default:
111459829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug ("Unkown flash vendor %d\n",
111559829cc1SJean-Christophe PLAGNIOL-VILLARD 				       info->vendor);
111659829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
111759829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
111859829cc1SJean-Christophe PLAGNIOL-VILLARD 
111959829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_full_status_check
112059829cc1SJean-Christophe PLAGNIOL-VILLARD 			    (info, sect, info->erase_blk_tout, "erase")) {
112159829cc1SJean-Christophe PLAGNIOL-VILLARD 				rcode = 1;
11226ea808efSPiotr Ziecik 			} else if (flash_verbose)
112359829cc1SJean-Christophe PLAGNIOL-VILLARD 				putc ('.');
112459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
112559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
11266ea808efSPiotr Ziecik 
11276ea808efSPiotr Ziecik 	if (flash_verbose)
112859829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts (" done\n");
11296ea808efSPiotr Ziecik 
113059829cc1SJean-Christophe PLAGNIOL-VILLARD 	return rcode;
113159829cc1SJean-Christophe PLAGNIOL-VILLARD }
113259829cc1SJean-Christophe PLAGNIOL-VILLARD 
113359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
113459829cc1SJean-Christophe PLAGNIOL-VILLARD  */
113559829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info)
113659829cc1SJean-Christophe PLAGNIOL-VILLARD {
113759829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
113859829cc1SJean-Christophe PLAGNIOL-VILLARD 
113959829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
114059829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("missing or unknown FLASH type\n");
114159829cc1SJean-Christophe PLAGNIOL-VILLARD 		return;
114259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
114359829cc1SJean-Christophe PLAGNIOL-VILLARD 
114481b20cccSMichael Schwingen 	printf ("%s FLASH (%d x %d)",
114581b20cccSMichael Schwingen 		info->name,
114659829cc1SJean-Christophe PLAGNIOL-VILLARD 		(info->portwidth << 3), (info->chipwidth << 3));
114781b20cccSMichael Schwingen 	if (info->size < 1024*1024)
114881b20cccSMichael Schwingen 		printf ("  Size: %ld kB in %d Sectors\n",
114981b20cccSMichael Schwingen 			info->size >> 10, info->sector_count);
115081b20cccSMichael Schwingen 	else
115159829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  Size: %ld MB in %d Sectors\n",
115259829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->size >> 20, info->sector_count);
115359829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("  ");
115459829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
11559c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
11569c048b52SVasiliy Leoenenko 			printf ("Intel Prog Regions");
11579c048b52SVasiliy Leoenenko 			break;
115859829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
115959829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Standard");
116059829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
116159829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
116259829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Extended");
116359829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
116459829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
116559829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Standard");
116659829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
116759829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
116859829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Extended");
116959829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
117081b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
117181b20cccSMichael Schwingen 		case CFI_CMDSET_AMD_LEGACY:
117281b20cccSMichael Schwingen 			printf ("AMD Legacy");
117381b20cccSMichael Schwingen 			break;
117481b20cccSMichael Schwingen #endif
117559829cc1SJean-Christophe PLAGNIOL-VILLARD 		default:
117659829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Unknown (%d)", info->vendor);
117759829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
117859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
117959829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
118059829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->manufacturer_id, info->device_id);
118159829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->device_id == 0x7E) {
118259829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf("%04X", info->device_id2);
118359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
118459829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
118559829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->erase_blk_tout,
118659829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->write_tout);
118759829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->buffer_size > 1) {
11887e5b9b47SHaavard Skinnemoen 		printf ("  Buffer write timeout: %ld ms, "
11897e5b9b47SHaavard Skinnemoen 			"buffer size: %d bytes\n",
119059829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_write_tout,
119159829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_size);
119259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
119359829cc1SJean-Christophe PLAGNIOL-VILLARD 
119459829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts ("\n  Sector Start Addresses:");
119559829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < info->sector_count; ++i) {
119659829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((i % 5) == 0)
119759829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("\n");
11986d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_EMPTY_INFO
119959829cc1SJean-Christophe PLAGNIOL-VILLARD 		int k;
120059829cc1SJean-Christophe PLAGNIOL-VILLARD 		int size;
120159829cc1SJean-Christophe PLAGNIOL-VILLARD 		int erased;
120259829cc1SJean-Christophe PLAGNIOL-VILLARD 		volatile unsigned long *flash;
120359829cc1SJean-Christophe PLAGNIOL-VILLARD 
120459829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
120559829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * Check if whole sector is erased
120659829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
120712d30aa7SHaavard Skinnemoen 		size = flash_sector_size(info, i);
120859829cc1SJean-Christophe PLAGNIOL-VILLARD 		erased = 1;
120959829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash = (volatile unsigned long *) info->start[i];
121059829cc1SJean-Christophe PLAGNIOL-VILLARD 		size = size >> 2;	/* divide by 4 for longword access */
121159829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (k = 0; k < size; k++) {
121259829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (*flash++ != 0xffffffff) {
121359829cc1SJean-Christophe PLAGNIOL-VILLARD 				erased = 0;
121459829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
121559829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
121659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
121759829cc1SJean-Christophe PLAGNIOL-VILLARD 
121859829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* print empty and read-only info */
121959829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX %c %s ",
122059829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
122159829cc1SJean-Christophe PLAGNIOL-VILLARD 			erased ? 'E' : ' ',
122259829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
12236d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #else	/* ! CONFIG_SYS_FLASH_EMPTY_INFO */
122459829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX   %s ",
122559829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
122659829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
122759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
122859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
122959829cc1SJean-Christophe PLAGNIOL-VILLARD 	putc ('\n');
123059829cc1SJean-Christophe PLAGNIOL-VILLARD 	return;
123159829cc1SJean-Christophe PLAGNIOL-VILLARD }
123259829cc1SJean-Christophe PLAGNIOL-VILLARD 
123359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
12349a042e9cSJerry Van Baren  * This is used in a few places in write_buf() to show programming
12359a042e9cSJerry Van Baren  * progress.  Making it a function is nasty because it needs to do side
12369a042e9cSJerry Van Baren  * effect updates to digit and dots.  Repeated code is nasty too, so
12379a042e9cSJerry Van Baren  * we define it once here.
12389a042e9cSJerry Van Baren  */
1239f0105727SStefan Roese #ifdef CONFIG_FLASH_SHOW_PROGRESS
1240f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
12416ea808efSPiotr Ziecik 	if (flash_verbose) { \
1242f0105727SStefan Roese 		dots -= dots_sub; \
12439a042e9cSJerry Van Baren 		if ((scale > 0) && (dots <= 0)) { \
12449a042e9cSJerry Van Baren 			if ((digit % 5) == 0) \
12459a042e9cSJerry Van Baren 				printf ("%d", digit / 5); \
12469a042e9cSJerry Van Baren 			else \
12479a042e9cSJerry Van Baren 				putc ('.'); \
12489a042e9cSJerry Van Baren 			digit--; \
12499a042e9cSJerry Van Baren 			dots += scale; \
12506ea808efSPiotr Ziecik 		} \
12519a042e9cSJerry Van Baren 	}
1252f0105727SStefan Roese #else
1253f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1254f0105727SStefan Roese #endif
12559a042e9cSJerry Van Baren 
12569a042e9cSJerry Van Baren /*-----------------------------------------------------------------------
125759829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copy memory to flash, returns:
125859829cc1SJean-Christophe PLAGNIOL-VILLARD  * 0 - OK
125959829cc1SJean-Christophe PLAGNIOL-VILLARD  * 1 - write timeout
126059829cc1SJean-Christophe PLAGNIOL-VILLARD  * 2 - Flash not erased
126159829cc1SJean-Christophe PLAGNIOL-VILLARD  */
126259829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
126359829cc1SJean-Christophe PLAGNIOL-VILLARD {
126459829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong wp;
126512d30aa7SHaavard Skinnemoen 	uchar *p;
126659829cc1SJean-Christophe PLAGNIOL-VILLARD 	int aln;
126759829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
126859829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, rc;
12696d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
127059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int buffered_size;
127159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
12729a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS
12739a042e9cSJerry Van Baren 	int digit = CONFIG_FLASH_SHOW_PROGRESS;
12749a042e9cSJerry Van Baren 	int scale = 0;
12759a042e9cSJerry Van Baren 	int dots  = 0;
12769a042e9cSJerry Van Baren 
12779a042e9cSJerry Van Baren 	/*
12789a042e9cSJerry Van Baren 	 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
12799a042e9cSJerry Van Baren 	 */
12809a042e9cSJerry Van Baren 	if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
12819a042e9cSJerry Van Baren 		scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
12829a042e9cSJerry Van Baren 			CONFIG_FLASH_SHOW_PROGRESS);
12839a042e9cSJerry Van Baren 	}
12849a042e9cSJerry Van Baren #endif
12859a042e9cSJerry Van Baren 
128659829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* get lower aligned address */
128759829cc1SJean-Christophe PLAGNIOL-VILLARD 	wp = (addr & ~(info->portwidth - 1));
128859829cc1SJean-Christophe PLAGNIOL-VILLARD 
128959829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle unaligned start */
129059829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((aln = addr - wp) != 0) {
129159829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
129209ce9921SBecky Bruce 		p = (uchar *)wp;
129312d30aa7SHaavard Skinnemoen 		for (i = 0; i < aln; ++i)
129412d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
129559829cc1SJean-Christophe PLAGNIOL-VILLARD 
129659829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (; (i < info->portwidth) && (cnt > 0); i++) {
129759829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
129859829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt--;
129959829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
130012d30aa7SHaavard Skinnemoen 		for (; (cnt == 0) && (i < info->portwidth); ++i)
130112d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
130212d30aa7SHaavard Skinnemoen 
130312d30aa7SHaavard Skinnemoen 		rc = flash_write_cfiword (info, wp, cword);
130412d30aa7SHaavard Skinnemoen 		if (rc != 0)
130559829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
130612d30aa7SHaavard Skinnemoen 
130712d30aa7SHaavard Skinnemoen 		wp += i;
1308f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, i);
130959829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
131059829cc1SJean-Christophe PLAGNIOL-VILLARD 
131159829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle the aligned part */
13126d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
131359829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size = (info->portwidth / info->chipwidth);
131459829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size *= info->buffer_size;
131559829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
131659829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* prohibit buffer write when buffer_size is 1 */
131759829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->buffer_size == 1) {
131859829cc1SJean-Christophe PLAGNIOL-VILLARD 			cword.l = 0;
131959829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->portwidth; i++)
132059829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_add_byte (info, &cword, *src++);
132159829cc1SJean-Christophe PLAGNIOL-VILLARD 			if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
132259829cc1SJean-Christophe PLAGNIOL-VILLARD 				return rc;
132359829cc1SJean-Christophe PLAGNIOL-VILLARD 			wp += info->portwidth;
132459829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt -= info->portwidth;
132559829cc1SJean-Christophe PLAGNIOL-VILLARD 			continue;
132659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
132759829cc1SJean-Christophe PLAGNIOL-VILLARD 
132859829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* write buffer until next buffered_size aligned boundary */
132959829cc1SJean-Christophe PLAGNIOL-VILLARD 		i = buffered_size - (wp % buffered_size);
133059829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (i > cnt)
133159829cc1SJean-Christophe PLAGNIOL-VILLARD 			i = cnt;
133259829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
133359829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
133459829cc1SJean-Christophe PLAGNIOL-VILLARD 		i -= i & (info->portwidth - 1);
133559829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += i;
133659829cc1SJean-Christophe PLAGNIOL-VILLARD 		src += i;
133759829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= i;
1338f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, i);
133959829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
134059829cc1SJean-Christophe PLAGNIOL-VILLARD #else
134159829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
134259829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
134359829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < info->portwidth; i++) {
134459829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
134559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
134659829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
134759829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
134859829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += info->portwidth;
134959829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= info->portwidth;
1350f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
135159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
13526d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
13539a042e9cSJerry Van Baren 
135459829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (cnt == 0) {
135559829cc1SJean-Christophe PLAGNIOL-VILLARD 		return (0);
135659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
135759829cc1SJean-Christophe PLAGNIOL-VILLARD 
135859829cc1SJean-Christophe PLAGNIOL-VILLARD 	/*
135959829cc1SJean-Christophe PLAGNIOL-VILLARD 	 * handle unaligned tail bytes
136059829cc1SJean-Christophe PLAGNIOL-VILLARD 	 */
136159829cc1SJean-Christophe PLAGNIOL-VILLARD 	cword.l = 0;
136209ce9921SBecky Bruce 	p = (uchar *)wp;
136312d30aa7SHaavard Skinnemoen 	for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
136459829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_add_byte (info, &cword, *src++);
136559829cc1SJean-Christophe PLAGNIOL-VILLARD 		--cnt;
136659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
136712d30aa7SHaavard Skinnemoen 	for (; i < info->portwidth; ++i)
136812d30aa7SHaavard Skinnemoen 		flash_add_byte (info, &cword, flash_read8(p + i));
136959829cc1SJean-Christophe PLAGNIOL-VILLARD 
137059829cc1SJean-Christophe PLAGNIOL-VILLARD 	return flash_write_cfiword (info, wp, cword);
137159829cc1SJean-Christophe PLAGNIOL-VILLARD }
137259829cc1SJean-Christophe PLAGNIOL-VILLARD 
137359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
137459829cc1SJean-Christophe PLAGNIOL-VILLARD  */
13756d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
137659829cc1SJean-Christophe PLAGNIOL-VILLARD 
137759829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot)
137859829cc1SJean-Christophe PLAGNIOL-VILLARD {
137959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retcode = 0;
138059829cc1SJean-Christophe PLAGNIOL-VILLARD 
1381bc9019e1SRafael Campos 	switch (info->vendor) {
1382bc9019e1SRafael Campos 		case CFI_CMDSET_INTEL_PROG_REGIONS:
1383bc9019e1SRafael Campos 		case CFI_CMDSET_INTEL_STANDARD:
13849e8e63ccSNick Spence 		case CFI_CMDSET_INTEL_EXTENDED:
1385bc9019e1SRafael Campos 			flash_write_cmd (info, sector, 0,
1386bc9019e1SRafael Campos 					 FLASH_CMD_CLEAR_STATUS);
138759829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
138859829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (prot)
1389bc9019e1SRafael Campos 				flash_write_cmd (info, sector, 0,
1390bc9019e1SRafael Campos 					FLASH_CMD_PROTECT_SET);
139159829cc1SJean-Christophe PLAGNIOL-VILLARD 			else
1392bc9019e1SRafael Campos 				flash_write_cmd (info, sector, 0,
1393bc9019e1SRafael Campos 					FLASH_CMD_PROTECT_CLEAR);
1394bc9019e1SRafael Campos 			break;
1395bc9019e1SRafael Campos 		case CFI_CMDSET_AMD_EXTENDED:
1396bc9019e1SRafael Campos 		case CFI_CMDSET_AMD_STANDARD:
1397bc9019e1SRafael Campos 			/* U-Boot only checks the first byte */
1398bc9019e1SRafael Campos 			if (info->manufacturer_id == (uchar)ATM_MANUFACT) {
1399bc9019e1SRafael Campos 				if (prot) {
1400bc9019e1SRafael Campos 					flash_unlock_seq (info, 0);
1401bc9019e1SRafael Campos 					flash_write_cmd (info, 0,
1402bc9019e1SRafael Campos 							info->addr_unlock1,
1403bc9019e1SRafael Campos 							ATM_CMD_SOFTLOCK_START);
1404bc9019e1SRafael Campos 					flash_unlock_seq (info, 0);
1405bc9019e1SRafael Campos 					flash_write_cmd (info, sector, 0,
1406bc9019e1SRafael Campos 							ATM_CMD_LOCK_SECT);
1407bc9019e1SRafael Campos 				} else {
1408bc9019e1SRafael Campos 					flash_write_cmd (info, 0,
1409bc9019e1SRafael Campos 							info->addr_unlock1,
1410bc9019e1SRafael Campos 							AMD_CMD_UNLOCK_START);
1411bc9019e1SRafael Campos 					if (info->device_id == ATM_ID_BV6416)
1412bc9019e1SRafael Campos 						flash_write_cmd (info, sector,
1413bc9019e1SRafael Campos 							0, ATM_CMD_UNLOCK_SECT);
1414bc9019e1SRafael Campos 				}
1415bc9019e1SRafael Campos 			}
1416bc9019e1SRafael Campos 			break;
14174e00acdeSTsiChung Liew #ifdef CONFIG_FLASH_CFI_LEGACY
14184e00acdeSTsiChung Liew 		case CFI_CMDSET_AMD_LEGACY:
14194e00acdeSTsiChung Liew 			flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
14204e00acdeSTsiChung Liew 			flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
14214e00acdeSTsiChung Liew 			if (prot)
14224e00acdeSTsiChung Liew 				flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
14234e00acdeSTsiChung Liew 			else
14244e00acdeSTsiChung Liew 				flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
14254e00acdeSTsiChung Liew #endif
1426bc9019e1SRafael Campos 	};
142759829cc1SJean-Christophe PLAGNIOL-VILLARD 
142859829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((retcode =
142959829cc1SJean-Christophe PLAGNIOL-VILLARD 	     flash_full_status_check (info, sector, info->erase_blk_tout,
143059829cc1SJean-Christophe PLAGNIOL-VILLARD 				      prot ? "protect" : "unprotect")) == 0) {
143159829cc1SJean-Christophe PLAGNIOL-VILLARD 
143259829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->protect[sector] = prot;
143359829cc1SJean-Christophe PLAGNIOL-VILLARD 
143459829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
143559829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * On some of Intel's flash chips (marked via legacy_unlock)
143659829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * unprotect unprotects all locking.
143759829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
143859829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((prot == 0) && (info->legacy_unlock)) {
143959829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_sect_t i;
144059829cc1SJean-Christophe PLAGNIOL-VILLARD 
144159829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->sector_count; i++) {
144259829cc1SJean-Christophe PLAGNIOL-VILLARD 				if (info->protect[i])
144359829cc1SJean-Christophe PLAGNIOL-VILLARD 					flash_real_protect (info, i, 1);
144459829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
144559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
144659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
144759829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retcode;
144859829cc1SJean-Christophe PLAGNIOL-VILLARD }
144959829cc1SJean-Christophe PLAGNIOL-VILLARD 
145059829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
145159829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_user_serial - read the OneTimeProgramming cells
145259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
145359829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
145459829cc1SJean-Christophe PLAGNIOL-VILLARD 			     int len)
145559829cc1SJean-Christophe PLAGNIOL-VILLARD {
145659829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
145759829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *dst;
145859829cc1SJean-Christophe PLAGNIOL-VILLARD 
145959829cc1SJean-Christophe PLAGNIOL-VILLARD 	dst = buffer;
146012d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
146159829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
146259829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (dst, src + offset, len);
146359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
146412d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
146559829cc1SJean-Christophe PLAGNIOL-VILLARD }
146659829cc1SJean-Christophe PLAGNIOL-VILLARD 
146759829cc1SJean-Christophe PLAGNIOL-VILLARD /*
146859829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_factory_serial - read the device Id from the protection area
146959829cc1SJean-Christophe PLAGNIOL-VILLARD  */
147059829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
147159829cc1SJean-Christophe PLAGNIOL-VILLARD 				int len)
147259829cc1SJean-Christophe PLAGNIOL-VILLARD {
147359829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
147459829cc1SJean-Christophe PLAGNIOL-VILLARD 
147512d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
147659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
147759829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (buffer, src + offset, len);
147859829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
147912d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
148059829cc1SJean-Christophe PLAGNIOL-VILLARD }
148159829cc1SJean-Christophe PLAGNIOL-VILLARD 
14826d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */
148359829cc1SJean-Christophe PLAGNIOL-VILLARD 
14840ddf06ddSHaavard Skinnemoen /*-----------------------------------------------------------------------
14850ddf06ddSHaavard Skinnemoen  * Reverse the order of the erase regions in the CFI QRY structure.
14860ddf06ddSHaavard Skinnemoen  * This is needed for chips that are either a) correctly detected as
14870ddf06ddSHaavard Skinnemoen  * top-boot, or b) buggy.
14880ddf06ddSHaavard Skinnemoen  */
14890ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry)
14900ddf06ddSHaavard Skinnemoen {
14910ddf06ddSHaavard Skinnemoen 	unsigned int i, j;
14920ddf06ddSHaavard Skinnemoen 	u32 tmp;
14930ddf06ddSHaavard Skinnemoen 
14940ddf06ddSHaavard Skinnemoen 	for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
14950ddf06ddSHaavard Skinnemoen 		tmp = qry->erase_region_info[i];
14960ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[i] = qry->erase_region_info[j];
14970ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[j] = tmp;
14980ddf06ddSHaavard Skinnemoen 	}
14990ddf06ddSHaavard Skinnemoen }
150059829cc1SJean-Christophe PLAGNIOL-VILLARD 
150159829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
150259829cc1SJean-Christophe PLAGNIOL-VILLARD  * read jedec ids from device and set corresponding fields in info struct
150359829cc1SJean-Christophe PLAGNIOL-VILLARD  *
150459829cc1SJean-Christophe PLAGNIOL-VILLARD  * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
150559829cc1SJean-Christophe PLAGNIOL-VILLARD  *
150659829cc1SJean-Christophe PLAGNIOL-VILLARD  */
15070ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info)
150859829cc1SJean-Christophe PLAGNIOL-VILLARD {
150959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
151059829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
151159829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
151259829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = flash_read_uchar (info,
151359829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_MANUFACTURER_ID);
151459829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id = flash_read_uchar (info,
151559829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID);
151659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
15170ddf06ddSHaavard Skinnemoen }
15180ddf06ddSHaavard Skinnemoen 
15190ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
15200ddf06ddSHaavard Skinnemoen {
15210ddf06ddSHaavard Skinnemoen 	info->cmd_reset = FLASH_CMD_RESET;
15220ddf06ddSHaavard Skinnemoen 
15230ddf06ddSHaavard Skinnemoen 	cmdset_intel_read_jedec_ids(info);
15240ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
15250ddf06ddSHaavard Skinnemoen 
15266d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
15270ddf06ddSHaavard Skinnemoen 	/* read legacy lock/unlock bit from intel flash */
15280ddf06ddSHaavard Skinnemoen 	if (info->ext_addr) {
15290ddf06ddSHaavard Skinnemoen 		info->legacy_unlock = flash_read_uchar (info,
15300ddf06ddSHaavard Skinnemoen 				info->ext_addr + 5) & 0x08;
15310ddf06ddSHaavard Skinnemoen 	}
15320ddf06ddSHaavard Skinnemoen #endif
15330ddf06ddSHaavard Skinnemoen 
15340ddf06ddSHaavard Skinnemoen 	return 0;
15350ddf06ddSHaavard Skinnemoen }
15360ddf06ddSHaavard Skinnemoen 
15370ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info)
15380ddf06ddSHaavard Skinnemoen {
153959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
154059829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_unlock_seq(info, 0);
154181b20cccSMichael Schwingen 	flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
154259829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
154390447ecbSTor Krill 
154459829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = flash_read_uchar (info,
154559829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_MANUFACTURER_ID);
154690447ecbSTor Krill 
154790447ecbSTor Krill 	switch (info->chipwidth){
154890447ecbSTor Krill 	case FLASH_CFI_8BIT:
154959829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id = flash_read_uchar (info,
155059829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID);
155159829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->device_id == 0x7E) {
155259829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* AMD 3-byte (expanded) device ids */
155359829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 = flash_read_uchar (info,
155459829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID2);
155559829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 <<= 8;
155659829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 |= flash_read_uchar (info,
155759829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID3);
155859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
155990447ecbSTor Krill 		break;
156090447ecbSTor Krill 	case FLASH_CFI_16BIT:
156190447ecbSTor Krill 		info->device_id = flash_read_word (info,
156290447ecbSTor Krill 						FLASH_OFFSET_DEVICE_ID);
156390447ecbSTor Krill 		break;
156490447ecbSTor Krill 	default:
156590447ecbSTor Krill 		break;
156690447ecbSTor Krill 	}
156759829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
15680ddf06ddSHaavard Skinnemoen }
15690ddf06ddSHaavard Skinnemoen 
15700ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
15710ddf06ddSHaavard Skinnemoen {
15720ddf06ddSHaavard Skinnemoen 	info->cmd_reset = AMD_CMD_RESET;
15730ddf06ddSHaavard Skinnemoen 
15740ddf06ddSHaavard Skinnemoen 	cmdset_amd_read_jedec_ids(info);
15750ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
15760ddf06ddSHaavard Skinnemoen 
15770ddf06ddSHaavard Skinnemoen 	return 0;
15780ddf06ddSHaavard Skinnemoen }
15790ddf06ddSHaavard Skinnemoen 
15800ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
15810ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info)
15820ddf06ddSHaavard Skinnemoen {
15830ddf06ddSHaavard Skinnemoen 	info->manufacturer_id = 0;
15840ddf06ddSHaavard Skinnemoen 	info->device_id       = 0;
15850ddf06ddSHaavard Skinnemoen 	info->device_id2      = 0;
15860ddf06ddSHaavard Skinnemoen 
15870ddf06ddSHaavard Skinnemoen 	switch (info->vendor) {
15889c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
15890ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
15900ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
15918225d1e3SMichael Schwingen 		cmdset_intel_read_jedec_ids(info);
15920ddf06ddSHaavard Skinnemoen 		break;
15930ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
15940ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
15958225d1e3SMichael Schwingen 		cmdset_amd_read_jedec_ids(info);
159659829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
159759829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
159859829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
159959829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
160059829cc1SJean-Christophe PLAGNIOL-VILLARD }
160159829cc1SJean-Christophe PLAGNIOL-VILLARD 
1602be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
1603be60a902SHaavard Skinnemoen  * Call board code to request info about non-CFI flash.
1604be60a902SHaavard Skinnemoen  * board_flash_get_legacy needs to fill in at least:
1605be60a902SHaavard Skinnemoen  * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1606be60a902SHaavard Skinnemoen  */
160709ce9921SBecky Bruce static int flash_detect_legacy(phys_addr_t base, int banknum)
1608be60a902SHaavard Skinnemoen {
1609be60a902SHaavard Skinnemoen 	flash_info_t *info = &flash_info[banknum];
1610be60a902SHaavard Skinnemoen 
1611be60a902SHaavard Skinnemoen 	if (board_flash_get_legacy(base, banknum, info)) {
1612be60a902SHaavard Skinnemoen 		/* board code may have filled info completely. If not, we
1613be60a902SHaavard Skinnemoen 		   use JEDEC ID probing. */
1614be60a902SHaavard Skinnemoen 		if (!info->vendor) {
1615be60a902SHaavard Skinnemoen 			int modes[] = {
1616be60a902SHaavard Skinnemoen 				CFI_CMDSET_AMD_STANDARD,
1617be60a902SHaavard Skinnemoen 				CFI_CMDSET_INTEL_STANDARD
1618be60a902SHaavard Skinnemoen 			};
1619be60a902SHaavard Skinnemoen 			int i;
1620be60a902SHaavard Skinnemoen 
1621be60a902SHaavard Skinnemoen 			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1622be60a902SHaavard Skinnemoen 				info->vendor = modes[i];
162309ce9921SBecky Bruce 				info->start[0] =
162409ce9921SBecky Bruce 					(ulong)map_physmem(base,
162509ce9921SBecky Bruce 							   info->portwith,
162609ce9921SBecky Bruce 							   MAP_NOCACHE);
1627be60a902SHaavard Skinnemoen 				if (info->portwidth == FLASH_CFI_8BIT
1628be60a902SHaavard Skinnemoen 					&& info->interface == FLASH_CFI_X8X16) {
1629be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x2AAA;
1630be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x5555;
1631be60a902SHaavard Skinnemoen 				} else {
1632be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x5555;
1633be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x2AAA;
1634be60a902SHaavard Skinnemoen 				}
1635be60a902SHaavard Skinnemoen 				flash_read_jedec_ids(info);
1636be60a902SHaavard Skinnemoen 				debug("JEDEC PROBE: ID %x %x %x\n",
1637be60a902SHaavard Skinnemoen 						info->manufacturer_id,
1638be60a902SHaavard Skinnemoen 						info->device_id,
1639be60a902SHaavard Skinnemoen 						info->device_id2);
164009ce9921SBecky Bruce 				if (jedec_flash_match(info, info->start[0]))
1641be60a902SHaavard Skinnemoen 					break;
164209ce9921SBecky Bruce 				else
164309ce9921SBecky Bruce 					unmap_physmem(info->start[0],
164409ce9921SBecky Bruce 						      MAP_NOCACHE);
1645be60a902SHaavard Skinnemoen 			}
1646be60a902SHaavard Skinnemoen 		}
1647be60a902SHaavard Skinnemoen 
1648be60a902SHaavard Skinnemoen 		switch(info->vendor) {
16499c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
1650be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_STANDARD:
1651be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_EXTENDED:
1652be60a902SHaavard Skinnemoen 			info->cmd_reset = FLASH_CMD_RESET;
1653be60a902SHaavard Skinnemoen 			break;
1654be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_STANDARD:
1655be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_EXTENDED:
1656be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_LEGACY:
1657be60a902SHaavard Skinnemoen 			info->cmd_reset = AMD_CMD_RESET;
1658be60a902SHaavard Skinnemoen 			break;
1659be60a902SHaavard Skinnemoen 		}
1660be60a902SHaavard Skinnemoen 		info->flash_id = FLASH_MAN_CFI;
1661be60a902SHaavard Skinnemoen 		return 1;
1662be60a902SHaavard Skinnemoen 	}
1663be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1664be60a902SHaavard Skinnemoen }
1665be60a902SHaavard Skinnemoen #else
166609ce9921SBecky Bruce static inline int flash_detect_legacy(phys_addr_t base, int banknum)
1667be60a902SHaavard Skinnemoen {
1668be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1669be60a902SHaavard Skinnemoen }
1670be60a902SHaavard Skinnemoen #endif
1671be60a902SHaavard Skinnemoen 
167259829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
167359829cc1SJean-Christophe PLAGNIOL-VILLARD  * detect if flash is compatible with the Common Flash Interface (CFI)
167459829cc1SJean-Christophe PLAGNIOL-VILLARD  * http://www.jedec.org/download/search/jesd68.pdf
167559829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1676e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf,
1677e23741f4SHaavard Skinnemoen 		unsigned int start, size_t len)
1678e23741f4SHaavard Skinnemoen {
1679e23741f4SHaavard Skinnemoen 	u8 *p = buf;
1680e23741f4SHaavard Skinnemoen 	unsigned int i;
1681e23741f4SHaavard Skinnemoen 
1682e23741f4SHaavard Skinnemoen 	for (i = 0; i < len; i++)
1683e23741f4SHaavard Skinnemoen 		p[i] = flash_read_uchar(info, start + i);
1684e23741f4SHaavard Skinnemoen }
1685e23741f4SHaavard Skinnemoen 
1686e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
168759829cc1SJean-Christophe PLAGNIOL-VILLARD {
168859829cc1SJean-Christophe PLAGNIOL-VILLARD 	int cfi_offset;
168959829cc1SJean-Christophe PLAGNIOL-VILLARD 
16901ba639daSMichael Schwingen 	/* We do not yet know what kind of commandset to use, so we issue
16911ba639daSMichael Schwingen 	   the reset command in both Intel and AMD variants, in the hope
16921ba639daSMichael Schwingen 	   that AMD flash roms ignore the Intel command. */
16931ba639daSMichael Schwingen 	flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
16941ba639daSMichael Schwingen 	flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
16951ba639daSMichael Schwingen 
16967e5b9b47SHaavard Skinnemoen 	for (cfi_offset=0;
16977e5b9b47SHaavard Skinnemoen 	     cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
16987e5b9b47SHaavard Skinnemoen 	     cfi_offset++) {
16997e5b9b47SHaavard Skinnemoen 		flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
17007e5b9b47SHaavard Skinnemoen 				 FLASH_CMD_CFI);
170159829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
170259829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
170359829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
1704e23741f4SHaavard Skinnemoen 			flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1705e23741f4SHaavard Skinnemoen 					sizeof(struct cfi_qry));
1706e23741f4SHaavard Skinnemoen 			info->interface	= le16_to_cpu(qry->interface_desc);
1707e23741f4SHaavard Skinnemoen 
170859829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_offset = flash_offset_cfi[cfi_offset];
170959829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("device interface is %d\n",
171059829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->interface);
171159829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("found port %d chip %d ",
171259829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth, info->chipwidth);
171359829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("port %d bits chip %d bits\n",
171459829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth << CFI_FLASH_SHIFT_WIDTH,
171559829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
171642026c9cSBartlomiej Sieka 
171742026c9cSBartlomiej Sieka 			/* calculate command offsets as in the Linux driver */
171842026c9cSBartlomiej Sieka 			info->addr_unlock1 = 0x555;
171942026c9cSBartlomiej Sieka 			info->addr_unlock2 = 0x2aa;
172042026c9cSBartlomiej Sieka 
172142026c9cSBartlomiej Sieka 			/*
172242026c9cSBartlomiej Sieka 			 * modify the unlock address if we are
172342026c9cSBartlomiej Sieka 			 * in compatibility mode
172442026c9cSBartlomiej Sieka 			 */
172542026c9cSBartlomiej Sieka 			if (	/* x8/x16 in x8 mode */
172642026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY8) &&
172742026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X8X16)) ||
172842026c9cSBartlomiej Sieka 				/* x16/x32 in x16 mode */
172942026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY16) &&
173042026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X16X32)))
173142026c9cSBartlomiej Sieka 			{
173242026c9cSBartlomiej Sieka 				info->addr_unlock1 = 0xaaa;
173342026c9cSBartlomiej Sieka 				info->addr_unlock2 = 0x555;
173442026c9cSBartlomiej Sieka 			}
173542026c9cSBartlomiej Sieka 
173681b20cccSMichael Schwingen 			info->name = "CFI conformant";
173759829cc1SJean-Christophe PLAGNIOL-VILLARD 			return 1;
173859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
173959829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
17407e5b9b47SHaavard Skinnemoen 
17417e5b9b47SHaavard Skinnemoen 	return 0;
174259829cc1SJean-Christophe PLAGNIOL-VILLARD }
17437e5b9b47SHaavard Skinnemoen 
1744e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
17457e5b9b47SHaavard Skinnemoen {
17467e5b9b47SHaavard Skinnemoen 	debug ("flash detect cfi\n");
17477e5b9b47SHaavard Skinnemoen 
17486d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	for (info->portwidth = CONFIG_SYS_FLASH_CFI_WIDTH;
17497e5b9b47SHaavard Skinnemoen 	     info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
17507e5b9b47SHaavard Skinnemoen 		for (info->chipwidth = FLASH_CFI_BY8;
17517e5b9b47SHaavard Skinnemoen 		     info->chipwidth <= info->portwidth;
17527e5b9b47SHaavard Skinnemoen 		     info->chipwidth <<= 1)
1753e23741f4SHaavard Skinnemoen 			if (__flash_detect_cfi(info, qry))
17547e5b9b47SHaavard Skinnemoen 				return 1;
175559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
175659829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("not found\n");
175759829cc1SJean-Christophe PLAGNIOL-VILLARD 	return 0;
175859829cc1SJean-Christophe PLAGNIOL-VILLARD }
175959829cc1SJean-Christophe PLAGNIOL-VILLARD 
176059829cc1SJean-Christophe PLAGNIOL-VILLARD /*
1761467bcee1SHaavard Skinnemoen  * Manufacturer-specific quirks. Add workarounds for geometry
1762467bcee1SHaavard Skinnemoen  * reversal, etc. here.
1763467bcee1SHaavard Skinnemoen  */
1764467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1765467bcee1SHaavard Skinnemoen {
1766467bcee1SHaavard Skinnemoen 	/* check if flash geometry needs reversal */
1767467bcee1SHaavard Skinnemoen 	if (qry->num_erase_regions > 1) {
1768467bcee1SHaavard Skinnemoen 		/* reverse geometry if top boot part */
1769467bcee1SHaavard Skinnemoen 		if (info->cfi_version < 0x3131) {
1770467bcee1SHaavard Skinnemoen 			/* CFI < 1.1, try to guess from device id */
1771467bcee1SHaavard Skinnemoen 			if ((info->device_id & 0x80) != 0)
1772467bcee1SHaavard Skinnemoen 				cfi_reverse_geometry(qry);
1773467bcee1SHaavard Skinnemoen 		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1774467bcee1SHaavard Skinnemoen 			/* CFI >= 1.1, deduct from top/bottom flag */
1775467bcee1SHaavard Skinnemoen 			/* note: ext_addr is valid since cfi_version > 0 */
1776467bcee1SHaavard Skinnemoen 			cfi_reverse_geometry(qry);
1777467bcee1SHaavard Skinnemoen 		}
1778467bcee1SHaavard Skinnemoen 	}
1779467bcee1SHaavard Skinnemoen }
1780467bcee1SHaavard Skinnemoen 
1781467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1782467bcee1SHaavard Skinnemoen {
1783467bcee1SHaavard Skinnemoen 	int reverse_geometry = 0;
1784467bcee1SHaavard Skinnemoen 
1785467bcee1SHaavard Skinnemoen 	/* Check the "top boot" bit in the PRI */
1786467bcee1SHaavard Skinnemoen 	if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1787467bcee1SHaavard Skinnemoen 		reverse_geometry = 1;
1788467bcee1SHaavard Skinnemoen 
1789467bcee1SHaavard Skinnemoen 	/* AT49BV6416(T) list the erase regions in the wrong order.
1790467bcee1SHaavard Skinnemoen 	 * However, the device ID is identical with the non-broken
1791467bcee1SHaavard Skinnemoen 	 * AT49BV642D since u-boot only reads the low byte (they
1792467bcee1SHaavard Skinnemoen 	 * differ in the high byte.) So leave out this fixup for now.
1793467bcee1SHaavard Skinnemoen 	 */
1794467bcee1SHaavard Skinnemoen #if 0
1795467bcee1SHaavard Skinnemoen 	if (info->device_id == 0xd6 || info->device_id == 0xd2)
1796467bcee1SHaavard Skinnemoen 		reverse_geometry = !reverse_geometry;
1797467bcee1SHaavard Skinnemoen #endif
1798467bcee1SHaavard Skinnemoen 
1799467bcee1SHaavard Skinnemoen 	if (reverse_geometry)
1800467bcee1SHaavard Skinnemoen 		cfi_reverse_geometry(qry);
1801467bcee1SHaavard Skinnemoen }
1802467bcee1SHaavard Skinnemoen 
1803e8eac437SRichard Retanubun static void flash_fixup_stm(flash_info_t *info, struct cfi_qry *qry)
1804e8eac437SRichard Retanubun {
1805e8eac437SRichard Retanubun 	/* check if flash geometry needs reversal */
1806e8eac437SRichard Retanubun 	if (qry->num_erase_regions > 1) {
1807e8eac437SRichard Retanubun 		/* reverse geometry if top boot part */
1808e8eac437SRichard Retanubun 		if (info->cfi_version < 0x3131) {
1809e8eac437SRichard Retanubun 			/* CFI < 1.1, guess by device id (only M29W320ET now) */
1810e8eac437SRichard Retanubun 			if (info->device_id == 0x2256) {
1811e8eac437SRichard Retanubun 				cfi_reverse_geometry(qry);
1812e8eac437SRichard Retanubun 			}
1813e8eac437SRichard Retanubun 		}
1814e8eac437SRichard Retanubun 	}
1815e8eac437SRichard Retanubun }
1816e8eac437SRichard Retanubun 
1817467bcee1SHaavard Skinnemoen /*
181859829cc1SJean-Christophe PLAGNIOL-VILLARD  * The following code cannot be run from FLASH!
181959829cc1SJean-Christophe PLAGNIOL-VILLARD  *
182059829cc1SJean-Christophe PLAGNIOL-VILLARD  */
182109ce9921SBecky Bruce ulong flash_get_size (phys_addr_t base, int banknum)
182259829cc1SJean-Christophe PLAGNIOL-VILLARD {
182359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_info_t *info = &flash_info[banknum];
182459829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, j;
182559829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect_cnt;
182609ce9921SBecky Bruce 	phys_addr_t sector;
182759829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long tmp;
182859829cc1SJean-Christophe PLAGNIOL-VILLARD 	int size_ratio;
182959829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar num_erase_regions;
183059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_size;
183159829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_count;
1832e23741f4SHaavard Skinnemoen 	struct cfi_qry qry;
183359829cc1SJean-Christophe PLAGNIOL-VILLARD 
1834f979690eSKumar Gala 	memset(&qry, 0, sizeof(qry));
1835f979690eSKumar Gala 
183659829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->ext_addr = 0;
183759829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->cfi_version = 0;
18386d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
183959829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->legacy_unlock = 0;
184059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
184159829cc1SJean-Christophe PLAGNIOL-VILLARD 
184209ce9921SBecky Bruce 	info->start[0] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE);
184359829cc1SJean-Christophe PLAGNIOL-VILLARD 
1844e23741f4SHaavard Skinnemoen 	if (flash_detect_cfi (info, &qry)) {
1845e23741f4SHaavard Skinnemoen 		info->vendor = le16_to_cpu(qry.p_id);
1846e23741f4SHaavard Skinnemoen 		info->ext_addr = le16_to_cpu(qry.p_adr);
1847e23741f4SHaavard Skinnemoen 		num_erase_regions = qry.num_erase_regions;
1848e23741f4SHaavard Skinnemoen 
184959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->ext_addr) {
185059829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version = (ushort) flash_read_uchar (info,
185159829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 3) << 8;
185259829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version |= (ushort) flash_read_uchar (info,
185359829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 4);
185459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
18550ddf06ddSHaavard Skinnemoen 
185659829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
1857e23741f4SHaavard Skinnemoen 		flash_printqry (&qry);
185859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
18590ddf06ddSHaavard Skinnemoen 
186059829cc1SJean-Christophe PLAGNIOL-VILLARD 		switch (info->vendor) {
18619c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
186259829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
186359829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
18640ddf06ddSHaavard Skinnemoen 			cmdset_intel_init(info, &qry);
186559829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
186659829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
186759829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
18680ddf06ddSHaavard Skinnemoen 			cmdset_amd_init(info, &qry);
186959829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
18700ddf06ddSHaavard Skinnemoen 		default:
18710ddf06ddSHaavard Skinnemoen 			printf("CFI: Unknown command set 0x%x\n",
18720ddf06ddSHaavard Skinnemoen 					info->vendor);
18730ddf06ddSHaavard Skinnemoen 			/*
18740ddf06ddSHaavard Skinnemoen 			 * Unfortunately, this means we don't know how
18750ddf06ddSHaavard Skinnemoen 			 * to get the chip back to Read mode. Might
18760ddf06ddSHaavard Skinnemoen 			 * as well try an Intel-style reset...
18770ddf06ddSHaavard Skinnemoen 			 */
18780ddf06ddSHaavard Skinnemoen 			flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
18790ddf06ddSHaavard Skinnemoen 			return 0;
188059829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
188159829cc1SJean-Christophe PLAGNIOL-VILLARD 
1882467bcee1SHaavard Skinnemoen 		/* Do manufacturer-specific fixups */
1883467bcee1SHaavard Skinnemoen 		switch (info->manufacturer_id) {
1884467bcee1SHaavard Skinnemoen 		case 0x0001:
1885467bcee1SHaavard Skinnemoen 			flash_fixup_amd(info, &qry);
1886467bcee1SHaavard Skinnemoen 			break;
1887467bcee1SHaavard Skinnemoen 		case 0x001f:
1888467bcee1SHaavard Skinnemoen 			flash_fixup_atmel(info, &qry);
1889467bcee1SHaavard Skinnemoen 			break;
1890e8eac437SRichard Retanubun 		case 0x0020:
1891e8eac437SRichard Retanubun 			flash_fixup_stm(info, &qry);
1892e8eac437SRichard Retanubun 			break;
1893467bcee1SHaavard Skinnemoen 		}
1894467bcee1SHaavard Skinnemoen 
189559829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer is %d\n", info->vendor);
189659829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
189759829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id is 0x%x\n", info->device_id);
189859829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id2 is 0x%x\n", info->device_id2);
189959829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("cfi version is 0x%04x\n", info->cfi_version);
190059829cc1SJean-Christophe PLAGNIOL-VILLARD 
190159829cc1SJean-Christophe PLAGNIOL-VILLARD 		size_ratio = info->portwidth / info->chipwidth;
190259829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* if the chip is x8/x16 reduce the ratio by half */
190359829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((info->interface == FLASH_CFI_X8X16)
190459829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && (info->chipwidth == FLASH_CFI_BY8)) {
190559829cc1SJean-Christophe PLAGNIOL-VILLARD 			size_ratio >>= 1;
190659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
190759829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("size_ratio %d port %d bits chip %d bits\n",
190859829cc1SJean-Christophe PLAGNIOL-VILLARD 		       size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
190959829cc1SJean-Christophe PLAGNIOL-VILLARD 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
191059829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("found %d erase regions\n", num_erase_regions);
191159829cc1SJean-Christophe PLAGNIOL-VILLARD 		sect_cnt = 0;
191259829cc1SJean-Christophe PLAGNIOL-VILLARD 		sector = base;
191359829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < num_erase_regions; i++) {
191459829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (i > NUM_ERASE_REGIONS) {
191559829cc1SJean-Christophe PLAGNIOL-VILLARD 				printf ("%d erase regions found, only %d used\n",
191659829cc1SJean-Christophe PLAGNIOL-VILLARD 					num_erase_regions, NUM_ERASE_REGIONS);
191759829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
191859829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1919e23741f4SHaavard Skinnemoen 
19200ddf06ddSHaavard Skinnemoen 			tmp = le32_to_cpu(qry.erase_region_info[i]);
19210ddf06ddSHaavard Skinnemoen 			debug("erase region %u: 0x%08lx\n", i, tmp);
1922e23741f4SHaavard Skinnemoen 
1923e23741f4SHaavard Skinnemoen 			erase_region_count = (tmp & 0xffff) + 1;
1924e23741f4SHaavard Skinnemoen 			tmp >>= 16;
192559829cc1SJean-Christophe PLAGNIOL-VILLARD 			erase_region_size =
192659829cc1SJean-Christophe PLAGNIOL-VILLARD 				(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
192759829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("erase_region_count = %d erase_region_size = %d\n",
192859829cc1SJean-Christophe PLAGNIOL-VILLARD 				erase_region_count, erase_region_size);
192959829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (j = 0; j < erase_region_count; j++) {
19306d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 				if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
193181b20cccSMichael Schwingen 					printf("ERROR: too many flash sectors\n");
193281b20cccSMichael Schwingen 					break;
193381b20cccSMichael Schwingen 				}
193409ce9921SBecky Bruce 				info->start[sect_cnt] =
193509ce9921SBecky Bruce 					(ulong)map_physmem(sector,
193609ce9921SBecky Bruce 							   info->portwidth,
193709ce9921SBecky Bruce 							   MAP_NOCACHE);
193859829cc1SJean-Christophe PLAGNIOL-VILLARD 				sector += (erase_region_size * size_ratio);
193959829cc1SJean-Christophe PLAGNIOL-VILLARD 
194059829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
19417e5b9b47SHaavard Skinnemoen 				 * Only read protection status from
19427e5b9b47SHaavard Skinnemoen 				 * supported devices (intel...)
194359829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
194459829cc1SJean-Christophe PLAGNIOL-VILLARD 				switch (info->vendor) {
19459c048b52SVasiliy Leoenenko 				case CFI_CMDSET_INTEL_PROG_REGIONS:
194659829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_EXTENDED:
194759829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_STANDARD:
194859829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->protect[sect_cnt] =
194959829cc1SJean-Christophe PLAGNIOL-VILLARD 						flash_isset (info, sect_cnt,
195059829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_OFFSET_PROTECT,
195159829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_STATUS_PROTECT);
195259829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
195359829cc1SJean-Christophe PLAGNIOL-VILLARD 				default:
19547e5b9b47SHaavard Skinnemoen 					/* default: not protected */
19557e5b9b47SHaavard Skinnemoen 					info->protect[sect_cnt] = 0;
195659829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
195759829cc1SJean-Christophe PLAGNIOL-VILLARD 
195859829cc1SJean-Christophe PLAGNIOL-VILLARD 				sect_cnt++;
195959829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
196059829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
196159829cc1SJean-Christophe PLAGNIOL-VILLARD 
196259829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->sector_count = sect_cnt;
1963e23741f4SHaavard Skinnemoen 		info->size = 1 << qry.dev_size;
196459829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* multiply the size by the number of chips */
19657e5b9b47SHaavard Skinnemoen 		info->size *= size_ratio;
1966e23741f4SHaavard Skinnemoen 		info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1967e23741f4SHaavard Skinnemoen 		tmp = 1 << qry.block_erase_timeout_typ;
19687e5b9b47SHaavard Skinnemoen 		info->erase_blk_tout = tmp *
1969e23741f4SHaavard Skinnemoen 			(1 << qry.block_erase_timeout_max);
1970e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.buf_write_timeout_typ) *
1971e23741f4SHaavard Skinnemoen 			(1 << qry.buf_write_timeout_max);
1972e23741f4SHaavard Skinnemoen 
19737e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1974e23741f4SHaavard Skinnemoen 		info->buffer_write_tout = (tmp + 999) / 1000;
1975e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.word_write_timeout_typ) *
1976e23741f4SHaavard Skinnemoen 			(1 << qry.word_write_timeout_max);
19777e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1978e23741f4SHaavard Skinnemoen 		info->write_tout = (tmp + 999) / 1000;
197959829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->flash_id = FLASH_MAN_CFI;
19807e5b9b47SHaavard Skinnemoen 		if ((info->interface == FLASH_CFI_X8X16) &&
19817e5b9b47SHaavard Skinnemoen 		    (info->chipwidth == FLASH_CFI_BY8)) {
19827e5b9b47SHaavard Skinnemoen 			/* XXX - Need to test on x8/x16 in parallel. */
19837e5b9b47SHaavard Skinnemoen 			info->portwidth >>= 1;
198459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
198559829cc1SJean-Christophe PLAGNIOL-VILLARD 
198659829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, 0, 0, info->cmd_reset);
19872215987eSMike Frysinger 	}
19882215987eSMike Frysinger 
198959829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (info->size);
199059829cc1SJean-Christophe PLAGNIOL-VILLARD }
199159829cc1SJean-Christophe PLAGNIOL-VILLARD 
19926ea808efSPiotr Ziecik void flash_set_verbose(uint v)
19936ea808efSPiotr Ziecik {
19946ea808efSPiotr Ziecik 	flash_verbose = v;
19956ea808efSPiotr Ziecik }
19966ea808efSPiotr Ziecik 
199759829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
199859829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1999be60a902SHaavard Skinnemoen unsigned long flash_init (void)
200059829cc1SJean-Christophe PLAGNIOL-VILLARD {
2001be60a902SHaavard Skinnemoen 	unsigned long size = 0;
2002be60a902SHaavard Skinnemoen 	int i;
20036d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
2004c63ad632SMatthias Fuchs 	struct apl_s {
2005c63ad632SMatthias Fuchs 		ulong start;
2006c63ad632SMatthias Fuchs 		ulong size;
20076d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	} apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST;
2008c63ad632SMatthias Fuchs #endif
200959829cc1SJean-Christophe PLAGNIOL-VILLARD 
20106d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
2011be60a902SHaavard Skinnemoen 	char *s = getenv("unlock");
201281b20cccSMichael Schwingen #endif
2013be60a902SHaavard Skinnemoen 
201409ce9921SBecky Bruce #define BANK_BASE(i)	(((phys_addr_t [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i])
20152a112b23SWolfgang Denk 
2016be60a902SHaavard Skinnemoen 	/* Init: no FLASHes known */
20176d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
2018be60a902SHaavard Skinnemoen 		flash_info[i].flash_id = FLASH_UNKNOWN;
2019be60a902SHaavard Skinnemoen 
20202a112b23SWolfgang Denk 		if (!flash_detect_legacy (BANK_BASE(i), i))
20212a112b23SWolfgang Denk 			flash_get_size (BANK_BASE(i), i);
2022be60a902SHaavard Skinnemoen 		size += flash_info[i].size;
2023be60a902SHaavard Skinnemoen 		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
20246d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_QUIET_TEST
2025be60a902SHaavard Skinnemoen 			printf ("## Unknown FLASH on Bank %d "
2026be60a902SHaavard Skinnemoen 				"- Size = 0x%08lx = %ld MB\n",
2027be60a902SHaavard Skinnemoen 				i+1, flash_info[i].size,
2028be60a902SHaavard Skinnemoen 				flash_info[i].size << 20);
20296d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_QUIET_TEST */
203059829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
20316d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
2032be60a902SHaavard Skinnemoen 		else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
2033be60a902SHaavard Skinnemoen 			/*
2034be60a902SHaavard Skinnemoen 			 * Only the U-Boot image and it's environment
2035be60a902SHaavard Skinnemoen 			 * is protected, all other sectors are
2036be60a902SHaavard Skinnemoen 			 * unprotected (unlocked) if flash hardware
20376d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 			 * protection is used (CONFIG_SYS_FLASH_PROTECTION)
2038be60a902SHaavard Skinnemoen 			 * and the environment variable "unlock" is
2039be60a902SHaavard Skinnemoen 			 * set to "yes".
2040be60a902SHaavard Skinnemoen 			 */
2041be60a902SHaavard Skinnemoen 			if (flash_info[i].legacy_unlock) {
2042be60a902SHaavard Skinnemoen 				int k;
204359829cc1SJean-Christophe PLAGNIOL-VILLARD 
2044be60a902SHaavard Skinnemoen 				/*
2045be60a902SHaavard Skinnemoen 				 * Disable legacy_unlock temporarily,
2046be60a902SHaavard Skinnemoen 				 * since flash_real_protect would
2047be60a902SHaavard Skinnemoen 				 * relock all other sectors again
2048be60a902SHaavard Skinnemoen 				 * otherwise.
2049be60a902SHaavard Skinnemoen 				 */
2050be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 0;
205159829cc1SJean-Christophe PLAGNIOL-VILLARD 
2052be60a902SHaavard Skinnemoen 				/*
2053be60a902SHaavard Skinnemoen 				 * Legacy unlocking (e.g. Intel J3) ->
2054be60a902SHaavard Skinnemoen 				 * unlock only one sector. This will
2055be60a902SHaavard Skinnemoen 				 * unlock all sectors.
2056be60a902SHaavard Skinnemoen 				 */
2057be60a902SHaavard Skinnemoen 				flash_real_protect (&flash_info[i], 0, 0);
205859829cc1SJean-Christophe PLAGNIOL-VILLARD 
2059be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 1;
206059829cc1SJean-Christophe PLAGNIOL-VILLARD 
2061be60a902SHaavard Skinnemoen 				/*
2062be60a902SHaavard Skinnemoen 				 * Manually mark other sectors as
2063be60a902SHaavard Skinnemoen 				 * unlocked (unprotected)
2064be60a902SHaavard Skinnemoen 				 */
2065be60a902SHaavard Skinnemoen 				for (k = 1; k < flash_info[i].sector_count; k++)
2066be60a902SHaavard Skinnemoen 					flash_info[i].protect[k] = 0;
2067be60a902SHaavard Skinnemoen 			} else {
2068be60a902SHaavard Skinnemoen 				/*
2069be60a902SHaavard Skinnemoen 				 * No legancy unlocking -> unlock all sectors
2070be60a902SHaavard Skinnemoen 				 */
2071be60a902SHaavard Skinnemoen 				flash_protect (FLAG_PROTECT_CLEAR,
2072be60a902SHaavard Skinnemoen 					       flash_info[i].start[0],
2073be60a902SHaavard Skinnemoen 					       flash_info[i].start[0]
2074be60a902SHaavard Skinnemoen 					       + flash_info[i].size - 1,
2075be60a902SHaavard Skinnemoen 					       &flash_info[i]);
207659829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
207759829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
20786d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */
207959829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
208059829cc1SJean-Christophe PLAGNIOL-VILLARD 
2081be60a902SHaavard Skinnemoen 	/* Monitor protection ON by default */
20826d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
2083be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
20846d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_SYS_MONITOR_BASE,
20856d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_SYS_MONITOR_BASE + monitor_flash_len  - 1,
20866d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CONFIG_SYS_MONITOR_BASE));
2087be60a902SHaavard Skinnemoen #endif
208859829cc1SJean-Christophe PLAGNIOL-VILLARD 
2089be60a902SHaavard Skinnemoen 	/* Environment protection ON by default */
20905a1aceb0SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_ENV_IS_IN_FLASH
2091be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
20920e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_ENV_ADDR,
20930e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
20940e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CONFIG_ENV_ADDR));
2095be60a902SHaavard Skinnemoen #endif
2096be60a902SHaavard Skinnemoen 
2097be60a902SHaavard Skinnemoen 	/* Redundant environment protection ON by default */
20980e8d1586SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_ENV_ADDR_REDUND
2099be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
21000e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_ENV_ADDR_REDUND,
21010e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SIZE_REDUND - 1,
21020e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CONFIG_ENV_ADDR_REDUND));
2103be60a902SHaavard Skinnemoen #endif
2104c63ad632SMatthias Fuchs 
21056d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
2106c63ad632SMatthias Fuchs 	for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
2107c63ad632SMatthias Fuchs 		debug("autoprotecting from %08x to %08x\n",
2108c63ad632SMatthias Fuchs 		      apl[i].start, apl[i].start + apl[i].size - 1);
2109c63ad632SMatthias Fuchs 		flash_protect (FLAG_PROTECT_SET,
2110c63ad632SMatthias Fuchs 			       apl[i].start,
2111c63ad632SMatthias Fuchs 			       apl[i].start + apl[i].size - 1,
2112c63ad632SMatthias Fuchs 			       flash_get_info(apl[i].start));
2113c63ad632SMatthias Fuchs 	}
2114c63ad632SMatthias Fuchs #endif
211591809ed5SPiotr Ziecik 
211691809ed5SPiotr Ziecik #ifdef CONFIG_FLASH_CFI_MTD
211791809ed5SPiotr Ziecik 	cfi_mtd_init();
211891809ed5SPiotr Ziecik #endif
211991809ed5SPiotr Ziecik 
2120be60a902SHaavard Skinnemoen 	return (size);
212159829cc1SJean-Christophe PLAGNIOL-VILLARD }
2122