xref: /rk3399_rockchip-uboot/drivers/mtd/cfi_flash.c (revision 6d0f6bcf337c5261c08fabe12982178c2c489d76)
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  *
60*6d0f6bcfSJean-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 
64*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_BANKS_LIST
65*6d0f6bcfSJean-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 
146*6d0f6bcfSJean-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 };
16159829cc1SJean-Christophe PLAGNIOL-VILLARD 
162*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD /* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */
163*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT
164*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD # define CFI_MAX_FLASH_BANKS	CONFIG_SYS_MAX_FLASH_BANKS_DETECT
16559829cc1SJean-Christophe PLAGNIOL-VILLARD #else
166*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD # define CFI_MAX_FLASH_BANKS	CONFIG_SYS_MAX_FLASH_BANKS
16759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
16859829cc1SJean-Christophe PLAGNIOL-VILLARD 
1692a112b23SWolfgang Denk flash_info_t flash_info[CFI_MAX_FLASH_BANKS];	/* FLASH chips info */
1702a112b23SWolfgang Denk 
17159829cc1SJean-Christophe PLAGNIOL-VILLARD /*
17259829cc1SJean-Christophe PLAGNIOL-VILLARD  * Check if chip width is defined. If not, start detecting with 8bit.
17359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
174*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_CFI_WIDTH
175*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_FLASH_CFI_WIDTH	FLASH_CFI_8BIT
17659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
17759829cc1SJean-Christophe PLAGNIOL-VILLARD 
17859829cc1SJean-Christophe PLAGNIOL-VILLARD typedef unsigned long flash_sect_t;
17959829cc1SJean-Christophe PLAGNIOL-VILLARD 
180e23741f4SHaavard Skinnemoen /* CFI standard query structure */
181e23741f4SHaavard Skinnemoen struct cfi_qry {
182e23741f4SHaavard Skinnemoen 	u8	qry[3];
183e23741f4SHaavard Skinnemoen 	u16	p_id;
184e23741f4SHaavard Skinnemoen 	u16	p_adr;
185e23741f4SHaavard Skinnemoen 	u16	a_id;
186e23741f4SHaavard Skinnemoen 	u16	a_adr;
187e23741f4SHaavard Skinnemoen 	u8	vcc_min;
188e23741f4SHaavard Skinnemoen 	u8	vcc_max;
189e23741f4SHaavard Skinnemoen 	u8	vpp_min;
190e23741f4SHaavard Skinnemoen 	u8	vpp_max;
191e23741f4SHaavard Skinnemoen 	u8	word_write_timeout_typ;
192e23741f4SHaavard Skinnemoen 	u8	buf_write_timeout_typ;
193e23741f4SHaavard Skinnemoen 	u8	block_erase_timeout_typ;
194e23741f4SHaavard Skinnemoen 	u8	chip_erase_timeout_typ;
195e23741f4SHaavard Skinnemoen 	u8	word_write_timeout_max;
196e23741f4SHaavard Skinnemoen 	u8	buf_write_timeout_max;
197e23741f4SHaavard Skinnemoen 	u8	block_erase_timeout_max;
198e23741f4SHaavard Skinnemoen 	u8	chip_erase_timeout_max;
199e23741f4SHaavard Skinnemoen 	u8	dev_size;
200e23741f4SHaavard Skinnemoen 	u16	interface_desc;
201e23741f4SHaavard Skinnemoen 	u16	max_buf_write_size;
202e23741f4SHaavard Skinnemoen 	u8	num_erase_regions;
203e23741f4SHaavard Skinnemoen 	u32	erase_region_info[NUM_ERASE_REGIONS];
204e23741f4SHaavard Skinnemoen } __attribute__((packed));
205e23741f4SHaavard Skinnemoen 
206e23741f4SHaavard Skinnemoen struct cfi_pri_hdr {
207e23741f4SHaavard Skinnemoen 	u8	pri[3];
208e23741f4SHaavard Skinnemoen 	u8	major_version;
209e23741f4SHaavard Skinnemoen 	u8	minor_version;
210e23741f4SHaavard Skinnemoen } __attribute__((packed));
211e23741f4SHaavard Skinnemoen 
212cdbaefb5SHaavard Skinnemoen static void flash_write8(u8 value, void *addr)
213cdbaefb5SHaavard Skinnemoen {
214cdbaefb5SHaavard Skinnemoen 	__raw_writeb(value, addr);
215cdbaefb5SHaavard Skinnemoen }
216cdbaefb5SHaavard Skinnemoen 
217cdbaefb5SHaavard Skinnemoen static void flash_write16(u16 value, void *addr)
218cdbaefb5SHaavard Skinnemoen {
219cdbaefb5SHaavard Skinnemoen 	__raw_writew(value, addr);
220cdbaefb5SHaavard Skinnemoen }
221cdbaefb5SHaavard Skinnemoen 
222cdbaefb5SHaavard Skinnemoen static void flash_write32(u32 value, void *addr)
223cdbaefb5SHaavard Skinnemoen {
224cdbaefb5SHaavard Skinnemoen 	__raw_writel(value, addr);
225cdbaefb5SHaavard Skinnemoen }
226cdbaefb5SHaavard Skinnemoen 
227cdbaefb5SHaavard Skinnemoen static void flash_write64(u64 value, void *addr)
228cdbaefb5SHaavard Skinnemoen {
229cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_writeq() */
230cdbaefb5SHaavard Skinnemoen 	*(volatile u64 *)addr = value;
231cdbaefb5SHaavard Skinnemoen }
232cdbaefb5SHaavard Skinnemoen 
233cdbaefb5SHaavard Skinnemoen static u8 flash_read8(void *addr)
234cdbaefb5SHaavard Skinnemoen {
235cdbaefb5SHaavard Skinnemoen 	return __raw_readb(addr);
236cdbaefb5SHaavard Skinnemoen }
237cdbaefb5SHaavard Skinnemoen 
238cdbaefb5SHaavard Skinnemoen static u16 flash_read16(void *addr)
239cdbaefb5SHaavard Skinnemoen {
240cdbaefb5SHaavard Skinnemoen 	return __raw_readw(addr);
241cdbaefb5SHaavard Skinnemoen }
242cdbaefb5SHaavard Skinnemoen 
243cdbaefb5SHaavard Skinnemoen static u32 flash_read32(void *addr)
244cdbaefb5SHaavard Skinnemoen {
245cdbaefb5SHaavard Skinnemoen 	return __raw_readl(addr);
246cdbaefb5SHaavard Skinnemoen }
247cdbaefb5SHaavard Skinnemoen 
24897bf85d7SDaniel Hellstrom static u64 __flash_read64(void *addr)
249cdbaefb5SHaavard Skinnemoen {
250cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_readq() */
251cdbaefb5SHaavard Skinnemoen 	return *(volatile u64 *)addr;
252cdbaefb5SHaavard Skinnemoen }
253cdbaefb5SHaavard Skinnemoen 
25497bf85d7SDaniel Hellstrom u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
25597bf85d7SDaniel Hellstrom 
256be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
257be60a902SHaavard Skinnemoen  */
258*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
259be60a902SHaavard Skinnemoen static flash_info_t *flash_get_info(ulong base)
260be60a902SHaavard Skinnemoen {
261be60a902SHaavard Skinnemoen 	int i;
262be60a902SHaavard Skinnemoen 	flash_info_t * info = 0;
263be60a902SHaavard Skinnemoen 
264*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
265be60a902SHaavard Skinnemoen 		info = & flash_info[i];
266be60a902SHaavard Skinnemoen 		if (info->size && info->start[0] <= base &&
267be60a902SHaavard Skinnemoen 		    base <= info->start[0] + info->size - 1)
268be60a902SHaavard Skinnemoen 			break;
269be60a902SHaavard Skinnemoen 	}
270be60a902SHaavard Skinnemoen 
271*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
272be60a902SHaavard Skinnemoen }
27359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
27459829cc1SJean-Christophe PLAGNIOL-VILLARD 
27512d30aa7SHaavard Skinnemoen unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
27612d30aa7SHaavard Skinnemoen {
27712d30aa7SHaavard Skinnemoen 	if (sect != (info->sector_count - 1))
27812d30aa7SHaavard Skinnemoen 		return info->start[sect + 1] - info->start[sect];
27912d30aa7SHaavard Skinnemoen 	else
28012d30aa7SHaavard Skinnemoen 		return info->start[0] + info->size - info->start[sect];
28112d30aa7SHaavard Skinnemoen }
28212d30aa7SHaavard Skinnemoen 
28359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
28459829cc1SJean-Christophe PLAGNIOL-VILLARD  * create an address based on the offset and the port width
28559829cc1SJean-Christophe PLAGNIOL-VILLARD  */
28612d30aa7SHaavard Skinnemoen static inline void *
28712d30aa7SHaavard Skinnemoen flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
28859829cc1SJean-Christophe PLAGNIOL-VILLARD {
28912d30aa7SHaavard Skinnemoen 	unsigned int byte_offset = offset * info->portwidth;
29012d30aa7SHaavard Skinnemoen 
29112d30aa7SHaavard Skinnemoen 	return map_physmem(info->start[sect] + byte_offset,
29212d30aa7SHaavard Skinnemoen 			flash_sector_size(info, sect) - byte_offset,
29312d30aa7SHaavard Skinnemoen 			MAP_NOCACHE);
29412d30aa7SHaavard Skinnemoen }
29512d30aa7SHaavard Skinnemoen 
29612d30aa7SHaavard Skinnemoen static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
29712d30aa7SHaavard Skinnemoen 		unsigned int offset, void *addr)
29812d30aa7SHaavard Skinnemoen {
29912d30aa7SHaavard Skinnemoen 	unsigned int byte_offset = offset * info->portwidth;
30012d30aa7SHaavard Skinnemoen 
30112d30aa7SHaavard Skinnemoen 	unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset);
30259829cc1SJean-Christophe PLAGNIOL-VILLARD }
30359829cc1SJean-Christophe PLAGNIOL-VILLARD 
304be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
305be60a902SHaavard Skinnemoen  * make a proper sized command based on the port and chip widths
306be60a902SHaavard Skinnemoen  */
3077288f972SSebastian Siewior static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
308be60a902SHaavard Skinnemoen {
309be60a902SHaavard Skinnemoen 	int i;
31093c56f21SVasiliy Leoenenko 	int cword_offset;
31193c56f21SVasiliy Leoenenko 	int cp_offset;
312*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
313340ccb26SSebastian Siewior 	u32 cmd_le = cpu_to_le32(cmd);
314340ccb26SSebastian Siewior #endif
31593c56f21SVasiliy Leoenenko 	uchar val;
316be60a902SHaavard Skinnemoen 	uchar *cp = (uchar *) cmdbuf;
317be60a902SHaavard Skinnemoen 
31893c56f21SVasiliy Leoenenko 	for (i = info->portwidth; i > 0; i--){
31993c56f21SVasiliy Leoenenko 		cword_offset = (info->portwidth-i)%info->chipwidth;
320*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
32193c56f21SVasiliy Leoenenko 		cp_offset = info->portwidth - i;
322340ccb26SSebastian Siewior 		val = *((uchar*)&cmd_le + cword_offset);
323be60a902SHaavard Skinnemoen #else
32493c56f21SVasiliy Leoenenko 		cp_offset = i - 1;
3257288f972SSebastian Siewior 		val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1);
326be60a902SHaavard Skinnemoen #endif
3277288f972SSebastian Siewior 		cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
32893c56f21SVasiliy Leoenenko 	}
329be60a902SHaavard Skinnemoen }
330be60a902SHaavard Skinnemoen 
33159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
33259829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
33359829cc1SJean-Christophe PLAGNIOL-VILLARD  * Debug support
33459829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3353055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data)
33659829cc1SJean-Christophe PLAGNIOL-VILLARD {
33759829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
33859829cc1SJean-Christophe PLAGNIOL-VILLARD 	char *cp;
33959829cc1SJean-Christophe PLAGNIOL-VILLARD 
34059829cc1SJean-Christophe PLAGNIOL-VILLARD 	cp = (unsigned char *) &data;
34159829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 8; i++)
34259829cc1SJean-Christophe PLAGNIOL-VILLARD 		sprintf (&str[i * 2], "%2.2x", *cp++);
34359829cc1SJean-Christophe PLAGNIOL-VILLARD }
344be60a902SHaavard Skinnemoen 
345e23741f4SHaavard Skinnemoen static void flash_printqry (struct cfi_qry *qry)
34659829cc1SJean-Christophe PLAGNIOL-VILLARD {
347e23741f4SHaavard Skinnemoen 	u8 *p = (u8 *)qry;
34859829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x, y;
34959829cc1SJean-Christophe PLAGNIOL-VILLARD 
350e23741f4SHaavard Skinnemoen 	for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
351e23741f4SHaavard Skinnemoen 		debug("%02x : ", x);
352e23741f4SHaavard Skinnemoen 		for (y = 0; y < 16; y++)
353e23741f4SHaavard Skinnemoen 			debug("%2.2x ", p[x + y]);
35459829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug(" ");
35559829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (y = 0; y < 16; y++) {
356e23741f4SHaavard Skinnemoen 			unsigned char c = p[x + y];
357e23741f4SHaavard Skinnemoen 			if (c >= 0x20 && c <= 0x7e)
358cdbaefb5SHaavard Skinnemoen 				debug("%c", c);
359e23741f4SHaavard Skinnemoen 			else
36059829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug(".");
36159829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
36259829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug("\n");
36359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
36459829cc1SJean-Christophe PLAGNIOL-VILLARD }
36559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
36659829cc1SJean-Christophe PLAGNIOL-VILLARD 
36759829cc1SJean-Christophe PLAGNIOL-VILLARD 
36859829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
36959829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a character at a port width address
37059829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3713055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
37259829cc1SJean-Christophe PLAGNIOL-VILLARD {
37359829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *cp;
37412d30aa7SHaavard Skinnemoen 	uchar retval;
37559829cc1SJean-Christophe PLAGNIOL-VILLARD 
37612d30aa7SHaavard Skinnemoen 	cp = flash_map (info, 0, offset);
377*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
37812d30aa7SHaavard Skinnemoen 	retval = flash_read8(cp);
37959829cc1SJean-Christophe PLAGNIOL-VILLARD #else
38012d30aa7SHaavard Skinnemoen 	retval = flash_read8(cp + info->portwidth - 1);
38159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
38212d30aa7SHaavard Skinnemoen 	flash_unmap (info, 0, offset, cp);
38312d30aa7SHaavard Skinnemoen 	return retval;
38459829cc1SJean-Christophe PLAGNIOL-VILLARD }
38559829cc1SJean-Christophe PLAGNIOL-VILLARD 
38659829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
38790447ecbSTor Krill  * read a word at a port width address, assume 16bit bus
38890447ecbSTor Krill  */
38990447ecbSTor Krill static inline ushort flash_read_word (flash_info_t * info, uint offset)
39090447ecbSTor Krill {
39190447ecbSTor Krill 	ushort *addr, retval;
39290447ecbSTor Krill 
39390447ecbSTor Krill 	addr = flash_map (info, 0, offset);
39490447ecbSTor Krill 	retval = flash_read16 (addr);
39590447ecbSTor Krill 	flash_unmap (info, 0, offset, addr);
39690447ecbSTor Krill 	return retval;
39790447ecbSTor Krill }
39890447ecbSTor Krill 
39990447ecbSTor Krill 
40090447ecbSTor Krill /*-----------------------------------------------------------------------
40159829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a long word by picking the least significant byte of each maximum
40259829cc1SJean-Christophe PLAGNIOL-VILLARD  * port size word. Swap for ppc format.
40359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
4043055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
4053055793bSHaavard Skinnemoen 			      uint offset)
40659829cc1SJean-Christophe PLAGNIOL-VILLARD {
40759829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *addr;
40859829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong retval;
40959829cc1SJean-Christophe PLAGNIOL-VILLARD 
41059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
41159829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x;
41259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
41312d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
41459829cc1SJean-Christophe PLAGNIOL-VILLARD 
41559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
41659829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("long addr is at %p info->portwidth = %d\n", addr,
41759829cc1SJean-Christophe PLAGNIOL-VILLARD 	       info->portwidth);
41859829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (x = 0; x < 4 * info->portwidth; x++) {
41912d30aa7SHaavard Skinnemoen 		debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
42059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
42159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
422*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
42312d30aa7SHaavard Skinnemoen 	retval = ((flash_read8(addr) << 16) |
42412d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + info->portwidth) << 24) |
42512d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 2 * info->portwidth)) |
42612d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 3 * info->portwidth) << 8));
42759829cc1SJean-Christophe PLAGNIOL-VILLARD #else
42812d30aa7SHaavard Skinnemoen 	retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
42912d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + info->portwidth - 1) << 16) |
43012d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
43112d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 3 * info->portwidth - 1)));
43259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
43312d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
43412d30aa7SHaavard Skinnemoen 
43559829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
43659829cc1SJean-Christophe PLAGNIOL-VILLARD }
43759829cc1SJean-Christophe PLAGNIOL-VILLARD 
438be60a902SHaavard Skinnemoen /*
439be60a902SHaavard Skinnemoen  * Write a proper sized command to the correct address
44081b20cccSMichael Schwingen  */
441be60a902SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
4427288f972SSebastian Siewior 			     uint offset, u32 cmd)
44381b20cccSMichael Schwingen {
4447e5b9b47SHaavard Skinnemoen 
445cdbaefb5SHaavard Skinnemoen 	void *addr;
446be60a902SHaavard Skinnemoen 	cfiword_t cword;
44781b20cccSMichael Schwingen 
44812d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
449be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
450be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
451be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
452cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
453be60a902SHaavard Skinnemoen 		       cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
454cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, addr);
455be60a902SHaavard Skinnemoen 		break;
456be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
457cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
458be60a902SHaavard Skinnemoen 		       cmd, cword.w,
459be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
460cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, addr);
461be60a902SHaavard Skinnemoen 		break;
462be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
463cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
464be60a902SHaavard Skinnemoen 		       cmd, cword.l,
465be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
466cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, addr);
467be60a902SHaavard Skinnemoen 		break;
468be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
469be60a902SHaavard Skinnemoen #ifdef DEBUG
470be60a902SHaavard Skinnemoen 		{
471be60a902SHaavard Skinnemoen 			char str[20];
472be60a902SHaavard Skinnemoen 
473be60a902SHaavard Skinnemoen 			print_longlong (str, cword.ll);
474be60a902SHaavard Skinnemoen 
475be60a902SHaavard Skinnemoen 			debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
476cdbaefb5SHaavard Skinnemoen 			       addr, cmd, str,
477be60a902SHaavard Skinnemoen 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
47881b20cccSMichael Schwingen 		}
479be60a902SHaavard Skinnemoen #endif
480cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, addr);
48181b20cccSMichael Schwingen 		break;
48281b20cccSMichael Schwingen 	}
483be60a902SHaavard Skinnemoen 
484be60a902SHaavard Skinnemoen 	/* Ensure all the instructions are fully finished */
485be60a902SHaavard Skinnemoen 	sync();
48612d30aa7SHaavard Skinnemoen 
48712d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
48881b20cccSMichael Schwingen }
4897e5b9b47SHaavard Skinnemoen 
490be60a902SHaavard Skinnemoen static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
491be60a902SHaavard Skinnemoen {
492be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
493be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
494be60a902SHaavard Skinnemoen }
495be60a902SHaavard Skinnemoen 
496be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
497be60a902SHaavard Skinnemoen  */
498be60a902SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect,
499be60a902SHaavard Skinnemoen 			  uint offset, uchar cmd)
500be60a902SHaavard Skinnemoen {
501cdbaefb5SHaavard Skinnemoen 	void *addr;
502be60a902SHaavard Skinnemoen 	cfiword_t cword;
503be60a902SHaavard Skinnemoen 	int retval;
504be60a902SHaavard Skinnemoen 
50512d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
506be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
507be60a902SHaavard Skinnemoen 
508cdbaefb5SHaavard Skinnemoen 	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
509be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
510be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
511cdbaefb5SHaavard Skinnemoen 		debug ("is= %x %x\n", flash_read8(addr), cword.c);
512cdbaefb5SHaavard Skinnemoen 		retval = (flash_read8(addr) == cword.c);
513be60a902SHaavard Skinnemoen 		break;
514be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
515cdbaefb5SHaavard Skinnemoen 		debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
516cdbaefb5SHaavard Skinnemoen 		retval = (flash_read16(addr) == cword.w);
517be60a902SHaavard Skinnemoen 		break;
518be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
51952514699SAndrew Klossner 		debug ("is= %8.8x %8.8lx\n", flash_read32(addr), cword.l);
520cdbaefb5SHaavard Skinnemoen 		retval = (flash_read32(addr) == cword.l);
521be60a902SHaavard Skinnemoen 		break;
522be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
523be60a902SHaavard Skinnemoen #ifdef DEBUG
524be60a902SHaavard Skinnemoen 		{
525be60a902SHaavard Skinnemoen 			char str1[20];
526be60a902SHaavard Skinnemoen 			char str2[20];
527be60a902SHaavard Skinnemoen 
528cdbaefb5SHaavard Skinnemoen 			print_longlong (str1, flash_read64(addr));
529be60a902SHaavard Skinnemoen 			print_longlong (str2, cword.ll);
530be60a902SHaavard Skinnemoen 			debug ("is= %s %s\n", str1, str2);
531be60a902SHaavard Skinnemoen 		}
532be60a902SHaavard Skinnemoen #endif
533cdbaefb5SHaavard Skinnemoen 		retval = (flash_read64(addr) == cword.ll);
534be60a902SHaavard Skinnemoen 		break;
535be60a902SHaavard Skinnemoen 	default:
536be60a902SHaavard Skinnemoen 		retval = 0;
537be60a902SHaavard Skinnemoen 		break;
538be60a902SHaavard Skinnemoen 	}
53912d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
54012d30aa7SHaavard Skinnemoen 
541be60a902SHaavard Skinnemoen 	return retval;
542be60a902SHaavard Skinnemoen }
543be60a902SHaavard Skinnemoen 
544be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
545be60a902SHaavard Skinnemoen  */
546be60a902SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect,
547be60a902SHaavard Skinnemoen 			uint offset, uchar cmd)
548be60a902SHaavard Skinnemoen {
549cdbaefb5SHaavard Skinnemoen 	void *addr;
550be60a902SHaavard Skinnemoen 	cfiword_t cword;
551be60a902SHaavard Skinnemoen 	int retval;
552be60a902SHaavard Skinnemoen 
55312d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
554be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
555be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
556be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
557cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read8(addr) & cword.c) == cword.c);
558be60a902SHaavard Skinnemoen 		break;
559be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
560cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read16(addr) & cword.w) == cword.w);
561be60a902SHaavard Skinnemoen 		break;
562be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
56347cc23cbSStefan Roese 		retval = ((flash_read32(addr) & cword.l) == cword.l);
564be60a902SHaavard Skinnemoen 		break;
565be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
566cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read64(addr) & cword.ll) == cword.ll);
567be60a902SHaavard Skinnemoen 		break;
568be60a902SHaavard Skinnemoen 	default:
569be60a902SHaavard Skinnemoen 		retval = 0;
570be60a902SHaavard Skinnemoen 		break;
571be60a902SHaavard Skinnemoen 	}
57212d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
57312d30aa7SHaavard Skinnemoen 
574be60a902SHaavard Skinnemoen 	return retval;
575be60a902SHaavard Skinnemoen }
576be60a902SHaavard Skinnemoen 
577be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
578be60a902SHaavard Skinnemoen  */
579be60a902SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect,
580be60a902SHaavard Skinnemoen 			 uint offset, uchar cmd)
581be60a902SHaavard Skinnemoen {
582cdbaefb5SHaavard Skinnemoen 	void *addr;
583be60a902SHaavard Skinnemoen 	cfiword_t cword;
584be60a902SHaavard Skinnemoen 	int retval;
585be60a902SHaavard Skinnemoen 
58612d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
587be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
588be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
589be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
590fb8c061eSStefan Roese 		retval = flash_read8(addr) != flash_read8(addr);
591be60a902SHaavard Skinnemoen 		break;
592be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
593fb8c061eSStefan Roese 		retval = flash_read16(addr) != flash_read16(addr);
594be60a902SHaavard Skinnemoen 		break;
595be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
596fb8c061eSStefan Roese 		retval = flash_read32(addr) != flash_read32(addr);
597be60a902SHaavard Skinnemoen 		break;
598be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
599fb8c061eSStefan Roese 		retval = flash_read64(addr) != flash_read64(addr);
600be60a902SHaavard Skinnemoen 		break;
601be60a902SHaavard Skinnemoen 	default:
602be60a902SHaavard Skinnemoen 		retval = 0;
603be60a902SHaavard Skinnemoen 		break;
604be60a902SHaavard Skinnemoen 	}
60512d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
60612d30aa7SHaavard Skinnemoen 
607be60a902SHaavard Skinnemoen 	return retval;
608be60a902SHaavard Skinnemoen }
609be60a902SHaavard Skinnemoen 
610be60a902SHaavard Skinnemoen /*
611be60a902SHaavard Skinnemoen  * flash_is_busy - check to see if the flash is busy
612be60a902SHaavard Skinnemoen  *
613be60a902SHaavard Skinnemoen  * This routine checks the status of the chip and returns true if the
614be60a902SHaavard Skinnemoen  * chip is busy.
615be60a902SHaavard Skinnemoen  */
616be60a902SHaavard Skinnemoen static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
617be60a902SHaavard Skinnemoen {
618be60a902SHaavard Skinnemoen 	int retval;
619be60a902SHaavard Skinnemoen 
62081b20cccSMichael Schwingen 	switch (info->vendor) {
6219c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
62281b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_STANDARD:
62381b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_EXTENDED:
624be60a902SHaavard Skinnemoen 		retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
62581b20cccSMichael Schwingen 		break;
62681b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_STANDARD:
62781b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_EXTENDED:
628be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
62981b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_LEGACY:
630be60a902SHaavard Skinnemoen #endif
631be60a902SHaavard Skinnemoen 		retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
632be60a902SHaavard Skinnemoen 		break;
633be60a902SHaavard Skinnemoen 	default:
634be60a902SHaavard Skinnemoen 		retval = 0;
635be60a902SHaavard Skinnemoen 	}
636be60a902SHaavard Skinnemoen 	debug ("flash_is_busy: %d\n", retval);
637be60a902SHaavard Skinnemoen 	return retval;
638be60a902SHaavard Skinnemoen }
639be60a902SHaavard Skinnemoen 
640be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
641be60a902SHaavard Skinnemoen  *  wait for XSR.7 to be set. Time out with an error if it does not.
642be60a902SHaavard Skinnemoen  *  This routine does not set the flash to read-array mode.
643be60a902SHaavard Skinnemoen  */
644be60a902SHaavard Skinnemoen static int flash_status_check (flash_info_t * info, flash_sect_t sector,
645be60a902SHaavard Skinnemoen 			       ulong tout, char *prompt)
646be60a902SHaavard Skinnemoen {
647be60a902SHaavard Skinnemoen 	ulong start;
648be60a902SHaavard Skinnemoen 
649*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if CONFIG_SYS_HZ != 1000
650*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	tout *= CONFIG_SYS_HZ/1000;
651be60a902SHaavard Skinnemoen #endif
652be60a902SHaavard Skinnemoen 
653be60a902SHaavard Skinnemoen 	/* Wait for command completion */
654be60a902SHaavard Skinnemoen 	start = get_timer (0);
655be60a902SHaavard Skinnemoen 	while (flash_is_busy (info, sector)) {
656be60a902SHaavard Skinnemoen 		if (get_timer (start) > tout) {
657be60a902SHaavard Skinnemoen 			printf ("Flash %s timeout at address %lx data %lx\n",
658be60a902SHaavard Skinnemoen 				prompt, info->start[sector],
659be60a902SHaavard Skinnemoen 				flash_read_long (info, sector, 0));
660be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0, info->cmd_reset);
661be60a902SHaavard Skinnemoen 			return ERR_TIMOUT;
662be60a902SHaavard Skinnemoen 		}
663be60a902SHaavard Skinnemoen 		udelay (1);		/* also triggers watchdog */
664be60a902SHaavard Skinnemoen 	}
665be60a902SHaavard Skinnemoen 	return ERR_OK;
666be60a902SHaavard Skinnemoen }
667be60a902SHaavard Skinnemoen 
668be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
669be60a902SHaavard Skinnemoen  * Wait for XSR.7 to be set, if it times out print an error, otherwise
670be60a902SHaavard Skinnemoen  * do a full status check.
671be60a902SHaavard Skinnemoen  *
672be60a902SHaavard Skinnemoen  * This routine sets the flash to read-array mode.
673be60a902SHaavard Skinnemoen  */
674be60a902SHaavard Skinnemoen static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
675be60a902SHaavard Skinnemoen 				    ulong tout, char *prompt)
676be60a902SHaavard Skinnemoen {
677be60a902SHaavard Skinnemoen 	int retcode;
678be60a902SHaavard Skinnemoen 
679be60a902SHaavard Skinnemoen 	retcode = flash_status_check (info, sector, tout, prompt);
680be60a902SHaavard Skinnemoen 	switch (info->vendor) {
6819c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
682be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
683be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
6840d01f66dSEd Swarthout 		if ((retcode != ERR_OK)
685be60a902SHaavard Skinnemoen 		    && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
686be60a902SHaavard Skinnemoen 			retcode = ERR_INVAL;
687be60a902SHaavard Skinnemoen 			printf ("Flash %s error at address %lx\n", prompt,
688be60a902SHaavard Skinnemoen 				info->start[sector]);
689be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
690be60a902SHaavard Skinnemoen 					 FLASH_STATUS_PSLBS)) {
691be60a902SHaavard Skinnemoen 				puts ("Command Sequence Error.\n");
692be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
693be60a902SHaavard Skinnemoen 						FLASH_STATUS_ECLBS)) {
694be60a902SHaavard Skinnemoen 				puts ("Block Erase Error.\n");
695be60a902SHaavard Skinnemoen 				retcode = ERR_NOT_ERASED;
696be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
697be60a902SHaavard Skinnemoen 						FLASH_STATUS_PSLBS)) {
698be60a902SHaavard Skinnemoen 				puts ("Locking Error\n");
699be60a902SHaavard Skinnemoen 			}
700be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
701be60a902SHaavard Skinnemoen 				puts ("Block locked.\n");
702be60a902SHaavard Skinnemoen 				retcode = ERR_PROTECTED;
703be60a902SHaavard Skinnemoen 			}
704be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
705be60a902SHaavard Skinnemoen 				puts ("Vpp Low Error.\n");
706be60a902SHaavard Skinnemoen 		}
707be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, info->cmd_reset);
708be60a902SHaavard Skinnemoen 		break;
709be60a902SHaavard Skinnemoen 	default:
71081b20cccSMichael Schwingen 		break;
71181b20cccSMichael Schwingen 	}
712be60a902SHaavard Skinnemoen 	return retcode;
71381b20cccSMichael Schwingen }
714be60a902SHaavard Skinnemoen 
715be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
716be60a902SHaavard Skinnemoen  */
717be60a902SHaavard Skinnemoen static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
718be60a902SHaavard Skinnemoen {
719*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
720be60a902SHaavard Skinnemoen 	unsigned short	w;
721be60a902SHaavard Skinnemoen 	unsigned int	l;
722be60a902SHaavard Skinnemoen 	unsigned long long ll;
723be60a902SHaavard Skinnemoen #endif
724be60a902SHaavard Skinnemoen 
725be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
726be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
727be60a902SHaavard Skinnemoen 		cword->c = c;
728be60a902SHaavard Skinnemoen 		break;
729be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
730*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
731be60a902SHaavard Skinnemoen 		w = c;
732be60a902SHaavard Skinnemoen 		w <<= 8;
733be60a902SHaavard Skinnemoen 		cword->w = (cword->w >> 8) | w;
73481b20cccSMichael Schwingen #else
735be60a902SHaavard Skinnemoen 		cword->w = (cword->w << 8) | c;
736be60a902SHaavard Skinnemoen #endif
737be60a902SHaavard Skinnemoen 		break;
738be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
739*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
740be60a902SHaavard Skinnemoen 		l = c;
741be60a902SHaavard Skinnemoen 		l <<= 24;
742be60a902SHaavard Skinnemoen 		cword->l = (cword->l >> 8) | l;
743be60a902SHaavard Skinnemoen #else
744be60a902SHaavard Skinnemoen 		cword->l = (cword->l << 8) | c;
745be60a902SHaavard Skinnemoen #endif
746be60a902SHaavard Skinnemoen 		break;
747be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
748*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
749be60a902SHaavard Skinnemoen 		ll = c;
750be60a902SHaavard Skinnemoen 		ll <<= 56;
751be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll >> 8) | ll;
752be60a902SHaavard Skinnemoen #else
753be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll << 8) | c;
754be60a902SHaavard Skinnemoen #endif
755be60a902SHaavard Skinnemoen 		break;
756be60a902SHaavard Skinnemoen 	}
757be60a902SHaavard Skinnemoen }
758be60a902SHaavard Skinnemoen 
759be60a902SHaavard Skinnemoen /* loop through the sectors from the highest address when the passed
760be60a902SHaavard Skinnemoen  * address is greater or equal to the sector address we have a match
761be60a902SHaavard Skinnemoen  */
762be60a902SHaavard Skinnemoen static flash_sect_t find_sector (flash_info_t * info, ulong addr)
76381b20cccSMichael Schwingen {
764be60a902SHaavard Skinnemoen 	flash_sect_t sector;
765be60a902SHaavard Skinnemoen 
766be60a902SHaavard Skinnemoen 	for (sector = info->sector_count - 1; sector >= 0; sector--) {
767be60a902SHaavard Skinnemoen 		if (addr >= info->start[sector])
768be60a902SHaavard Skinnemoen 			break;
76981b20cccSMichael Schwingen 	}
770be60a902SHaavard Skinnemoen 	return sector;
77159829cc1SJean-Christophe PLAGNIOL-VILLARD }
77259829cc1SJean-Christophe PLAGNIOL-VILLARD 
77359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
77459829cc1SJean-Christophe PLAGNIOL-VILLARD  */
775be60a902SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest,
776be60a902SHaavard Skinnemoen 				cfiword_t cword)
77759829cc1SJean-Christophe PLAGNIOL-VILLARD {
778cdbaefb5SHaavard Skinnemoen 	void *dstaddr;
779be60a902SHaavard Skinnemoen 	int flag;
7800d01f66dSEd Swarthout 	flash_sect_t sect;
78159829cc1SJean-Christophe PLAGNIOL-VILLARD 
78212d30aa7SHaavard Skinnemoen 	dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
783be60a902SHaavard Skinnemoen 
784be60a902SHaavard Skinnemoen 	/* Check if Flash is (sufficiently) erased */
785be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
786be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
787cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
788be60a902SHaavard Skinnemoen 		break;
789be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
790cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
791be60a902SHaavard Skinnemoen 		break;
792be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
793cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
794be60a902SHaavard Skinnemoen 		break;
795be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
796cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
797be60a902SHaavard Skinnemoen 		break;
798be60a902SHaavard Skinnemoen 	default:
79912d30aa7SHaavard Skinnemoen 		flag = 0;
80012d30aa7SHaavard Skinnemoen 		break;
80112d30aa7SHaavard Skinnemoen 	}
80212d30aa7SHaavard Skinnemoen 	if (!flag) {
80312d30aa7SHaavard Skinnemoen 		unmap_physmem(dstaddr, info->portwidth);
8040dc80e27SStefan Roese 		return ERR_NOT_ERASED;
805be60a902SHaavard Skinnemoen 	}
806be60a902SHaavard Skinnemoen 
807be60a902SHaavard Skinnemoen 	/* Disable interrupts which might cause a timeout here */
808be60a902SHaavard Skinnemoen 	flag = disable_interrupts ();
809be60a902SHaavard Skinnemoen 
810be60a902SHaavard Skinnemoen 	switch (info->vendor) {
8119c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
812be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
813be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
814be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
815be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
816be60a902SHaavard Skinnemoen 		break;
817be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
818be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
819be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
820be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_LEGACY:
821be60a902SHaavard Skinnemoen #endif
8220d01f66dSEd Swarthout 		sect = find_sector(info, dest);
8230d01f66dSEd Swarthout 		flash_unlock_seq (info, sect);
8240d01f66dSEd Swarthout 		flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE);
82559829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
82659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
82759829cc1SJean-Christophe PLAGNIOL-VILLARD 
828be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
829be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
830cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, dstaddr);
831be60a902SHaavard Skinnemoen 		break;
832be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
833cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, dstaddr);
834be60a902SHaavard Skinnemoen 		break;
835be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
836cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, dstaddr);
837be60a902SHaavard Skinnemoen 		break;
838be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
839cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, dstaddr);
840be60a902SHaavard Skinnemoen 		break;
84159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
842be60a902SHaavard Skinnemoen 
843be60a902SHaavard Skinnemoen 	/* re-enable interrupts if necessary */
844be60a902SHaavard Skinnemoen 	if (flag)
845be60a902SHaavard Skinnemoen 		enable_interrupts ();
846be60a902SHaavard Skinnemoen 
84712d30aa7SHaavard Skinnemoen 	unmap_physmem(dstaddr, info->portwidth);
84812d30aa7SHaavard Skinnemoen 
849be60a902SHaavard Skinnemoen 	return flash_full_status_check (info, find_sector (info, dest),
850be60a902SHaavard Skinnemoen 					info->write_tout, "write");
851be60a902SHaavard Skinnemoen }
852be60a902SHaavard Skinnemoen 
853*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
854be60a902SHaavard Skinnemoen 
855be60a902SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
856be60a902SHaavard Skinnemoen 				  int len)
857be60a902SHaavard Skinnemoen {
858be60a902SHaavard Skinnemoen 	flash_sect_t sector;
859be60a902SHaavard Skinnemoen 	int cnt;
860be60a902SHaavard Skinnemoen 	int retcode;
861cdbaefb5SHaavard Skinnemoen 	void *src = cp;
86212d30aa7SHaavard Skinnemoen 	void *dst = map_physmem(dest, len, MAP_NOCACHE);
8630dc80e27SStefan Roese 	void *dst2 = dst;
8640dc80e27SStefan Roese 	int flag = 0;
86596ef831fSGuennadi Liakhovetski 	uint offset = 0;
86696ef831fSGuennadi Liakhovetski 	unsigned int shift;
8679c048b52SVasiliy Leoenenko 	uchar write_cmd;
868cdbaefb5SHaavard Skinnemoen 
8690dc80e27SStefan Roese 	switch (info->portwidth) {
8700dc80e27SStefan Roese 	case FLASH_CFI_8BIT:
87196ef831fSGuennadi Liakhovetski 		shift = 0;
8720dc80e27SStefan Roese 		break;
8730dc80e27SStefan Roese 	case FLASH_CFI_16BIT:
87496ef831fSGuennadi Liakhovetski 		shift = 1;
8750dc80e27SStefan Roese 		break;
8760dc80e27SStefan Roese 	case FLASH_CFI_32BIT:
87796ef831fSGuennadi Liakhovetski 		shift = 2;
8780dc80e27SStefan Roese 		break;
8790dc80e27SStefan Roese 	case FLASH_CFI_64BIT:
88096ef831fSGuennadi Liakhovetski 		shift = 3;
8810dc80e27SStefan Roese 		break;
8820dc80e27SStefan Roese 	default:
8830dc80e27SStefan Roese 		retcode = ERR_INVAL;
8840dc80e27SStefan Roese 		goto out_unmap;
8850dc80e27SStefan Roese 	}
8860dc80e27SStefan Roese 
88796ef831fSGuennadi Liakhovetski 	cnt = len >> shift;
88896ef831fSGuennadi Liakhovetski 
8890dc80e27SStefan Roese 	while ((cnt-- > 0) && (flag == 0)) {
8900dc80e27SStefan Roese 		switch (info->portwidth) {
8910dc80e27SStefan Roese 		case FLASH_CFI_8BIT:
8920dc80e27SStefan Roese 			flag = ((flash_read8(dst2) & flash_read8(src)) ==
8930dc80e27SStefan Roese 				flash_read8(src));
8940dc80e27SStefan Roese 			src += 1, dst2 += 1;
8950dc80e27SStefan Roese 			break;
8960dc80e27SStefan Roese 		case FLASH_CFI_16BIT:
8970dc80e27SStefan Roese 			flag = ((flash_read16(dst2) & flash_read16(src)) ==
8980dc80e27SStefan Roese 				flash_read16(src));
8990dc80e27SStefan Roese 			src += 2, dst2 += 2;
9000dc80e27SStefan Roese 			break;
9010dc80e27SStefan Roese 		case FLASH_CFI_32BIT:
9020dc80e27SStefan Roese 			flag = ((flash_read32(dst2) & flash_read32(src)) ==
9030dc80e27SStefan Roese 				flash_read32(src));
9040dc80e27SStefan Roese 			src += 4, dst2 += 4;
9050dc80e27SStefan Roese 			break;
9060dc80e27SStefan Roese 		case FLASH_CFI_64BIT:
9070dc80e27SStefan Roese 			flag = ((flash_read64(dst2) & flash_read64(src)) ==
9080dc80e27SStefan Roese 				flash_read64(src));
9090dc80e27SStefan Roese 			src += 8, dst2 += 8;
9100dc80e27SStefan Roese 			break;
9110dc80e27SStefan Roese 		}
9120dc80e27SStefan Roese 	}
9130dc80e27SStefan Roese 	if (!flag) {
9140dc80e27SStefan Roese 		retcode = ERR_NOT_ERASED;
9150dc80e27SStefan Roese 		goto out_unmap;
9160dc80e27SStefan Roese 	}
9170dc80e27SStefan Roese 
9180dc80e27SStefan Roese 	src = cp;
919cdbaefb5SHaavard Skinnemoen 	sector = find_sector (info, dest);
920be60a902SHaavard Skinnemoen 
921be60a902SHaavard Skinnemoen 	switch (info->vendor) {
9229c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
923be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
924be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
9259c048b52SVasiliy Leoenenko 		write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
9269c048b52SVasiliy Leoenenko 					FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER;
927be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
9289c048b52SVasiliy Leoenenko 		flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS);
9299c048b52SVasiliy Leoenenko 		flash_write_cmd (info, sector, 0, write_cmd);
930be60a902SHaavard Skinnemoen 		retcode = flash_status_check (info, sector,
931be60a902SHaavard Skinnemoen 					      info->buffer_write_tout,
932be60a902SHaavard Skinnemoen 					      "write to buffer");
933be60a902SHaavard Skinnemoen 		if (retcode == ERR_OK) {
934be60a902SHaavard Skinnemoen 			/* reduce the number of loops by the width of
935be60a902SHaavard Skinnemoen 			 * the port */
93696ef831fSGuennadi Liakhovetski 			cnt = len >> shift;
93793c56f21SVasiliy Leoenenko 			flash_write_cmd (info, sector, 0, cnt - 1);
938be60a902SHaavard Skinnemoen 			while (cnt-- > 0) {
939be60a902SHaavard Skinnemoen 				switch (info->portwidth) {
940be60a902SHaavard Skinnemoen 				case FLASH_CFI_8BIT:
941cdbaefb5SHaavard Skinnemoen 					flash_write8(flash_read8(src), dst);
942cdbaefb5SHaavard Skinnemoen 					src += 1, dst += 1;
943be60a902SHaavard Skinnemoen 					break;
944be60a902SHaavard Skinnemoen 				case FLASH_CFI_16BIT:
945cdbaefb5SHaavard Skinnemoen 					flash_write16(flash_read16(src), dst);
946cdbaefb5SHaavard Skinnemoen 					src += 2, dst += 2;
947be60a902SHaavard Skinnemoen 					break;
948be60a902SHaavard Skinnemoen 				case FLASH_CFI_32BIT:
949cdbaefb5SHaavard Skinnemoen 					flash_write32(flash_read32(src), dst);
950cdbaefb5SHaavard Skinnemoen 					src += 4, dst += 4;
951be60a902SHaavard Skinnemoen 					break;
952be60a902SHaavard Skinnemoen 				case FLASH_CFI_64BIT:
953cdbaefb5SHaavard Skinnemoen 					flash_write64(flash_read64(src), dst);
954cdbaefb5SHaavard Skinnemoen 					src += 8, dst += 8;
955be60a902SHaavard Skinnemoen 					break;
956be60a902SHaavard Skinnemoen 				default:
95712d30aa7SHaavard Skinnemoen 					retcode = ERR_INVAL;
95812d30aa7SHaavard Skinnemoen 					goto out_unmap;
959be60a902SHaavard Skinnemoen 				}
960be60a902SHaavard Skinnemoen 			}
961be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,
962be60a902SHaavard Skinnemoen 					 FLASH_CMD_WRITE_BUFFER_CONFIRM);
963be60a902SHaavard Skinnemoen 			retcode = flash_full_status_check (
964be60a902SHaavard Skinnemoen 				info, sector, info->buffer_write_tout,
965be60a902SHaavard Skinnemoen 				"buffer write");
966be60a902SHaavard Skinnemoen 		}
96712d30aa7SHaavard Skinnemoen 
96812d30aa7SHaavard Skinnemoen 		break;
969be60a902SHaavard Skinnemoen 
970be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
971be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
972be60a902SHaavard Skinnemoen 		flash_unlock_seq(info,0);
97396ef831fSGuennadi Liakhovetski 
97496ef831fSGuennadi Liakhovetski #ifdef CONFIG_FLASH_SPANSION_S29WS_N
97596ef831fSGuennadi Liakhovetski 		offset = ((unsigned long)dst - info->start[sector]) >> shift;
97696ef831fSGuennadi Liakhovetski #endif
97796ef831fSGuennadi Liakhovetski 		flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
97896ef831fSGuennadi Liakhovetski 		cnt = len >> shift;
97996ef831fSGuennadi Liakhovetski 		flash_write_cmd(info, sector, offset, (uchar)cnt - 1);
980be60a902SHaavard Skinnemoen 
981be60a902SHaavard Skinnemoen 		switch (info->portwidth) {
982be60a902SHaavard Skinnemoen 		case FLASH_CFI_8BIT:
983cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
984cdbaefb5SHaavard Skinnemoen 				flash_write8(flash_read8(src), dst);
985cdbaefb5SHaavard Skinnemoen 				src += 1, dst += 1;
986cdbaefb5SHaavard Skinnemoen 			}
987be60a902SHaavard Skinnemoen 			break;
988be60a902SHaavard Skinnemoen 		case FLASH_CFI_16BIT:
989cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
990cdbaefb5SHaavard Skinnemoen 				flash_write16(flash_read16(src), dst);
991cdbaefb5SHaavard Skinnemoen 				src += 2, dst += 2;
992cdbaefb5SHaavard Skinnemoen 			}
993be60a902SHaavard Skinnemoen 			break;
994be60a902SHaavard Skinnemoen 		case FLASH_CFI_32BIT:
995cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
996cdbaefb5SHaavard Skinnemoen 				flash_write32(flash_read32(src), dst);
997cdbaefb5SHaavard Skinnemoen 				src += 4, dst += 4;
998cdbaefb5SHaavard Skinnemoen 			}
999be60a902SHaavard Skinnemoen 			break;
1000be60a902SHaavard Skinnemoen 		case FLASH_CFI_64BIT:
1001cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
1002cdbaefb5SHaavard Skinnemoen 				flash_write64(flash_read64(src), dst);
1003cdbaefb5SHaavard Skinnemoen 				src += 8, dst += 8;
1004cdbaefb5SHaavard Skinnemoen 			}
1005be60a902SHaavard Skinnemoen 			break;
1006be60a902SHaavard Skinnemoen 		default:
100712d30aa7SHaavard Skinnemoen 			retcode = ERR_INVAL;
100812d30aa7SHaavard Skinnemoen 			goto out_unmap;
1009be60a902SHaavard Skinnemoen 		}
1010be60a902SHaavard Skinnemoen 
1011be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1012be60a902SHaavard Skinnemoen 		retcode = flash_full_status_check (info, sector,
1013be60a902SHaavard Skinnemoen 						   info->buffer_write_tout,
1014be60a902SHaavard Skinnemoen 						   "buffer write");
101512d30aa7SHaavard Skinnemoen 		break;
1016be60a902SHaavard Skinnemoen 
1017be60a902SHaavard Skinnemoen 	default:
1018be60a902SHaavard Skinnemoen 		debug ("Unknown Command Set\n");
101912d30aa7SHaavard Skinnemoen 		retcode = ERR_INVAL;
102012d30aa7SHaavard Skinnemoen 		break;
1021be60a902SHaavard Skinnemoen 	}
102212d30aa7SHaavard Skinnemoen 
102312d30aa7SHaavard Skinnemoen out_unmap:
102412d30aa7SHaavard Skinnemoen 	unmap_physmem(dst, len);
102512d30aa7SHaavard Skinnemoen 	return retcode;
1026be60a902SHaavard Skinnemoen }
1027*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
1028be60a902SHaavard Skinnemoen 
102959829cc1SJean-Christophe PLAGNIOL-VILLARD 
103059829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
103159829cc1SJean-Christophe PLAGNIOL-VILLARD  */
103259829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last)
103359829cc1SJean-Christophe PLAGNIOL-VILLARD {
103459829cc1SJean-Christophe PLAGNIOL-VILLARD 	int rcode = 0;
103559829cc1SJean-Christophe PLAGNIOL-VILLARD 	int prot;
103659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect;
103759829cc1SJean-Christophe PLAGNIOL-VILLARD 
103859829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
103959829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("Can't erase unknown flash type - aborted\n");
104059829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
104159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
104259829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((s_first < 0) || (s_first > s_last)) {
104359829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("- no sectors to erase\n");
104459829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
104559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
104659829cc1SJean-Christophe PLAGNIOL-VILLARD 
104759829cc1SJean-Christophe PLAGNIOL-VILLARD 	prot = 0;
104859829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; ++sect) {
104959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect]) {
105059829cc1SJean-Christophe PLAGNIOL-VILLARD 			prot++;
105159829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
105259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
105359829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot) {
10547e5b9b47SHaavard Skinnemoen 		printf ("- Warning: %d protected sectors will not be erased!\n",
10557e5b9b47SHaavard Skinnemoen 			prot);
105659829cc1SJean-Christophe PLAGNIOL-VILLARD 	} else {
105759829cc1SJean-Christophe PLAGNIOL-VILLARD 		putc ('\n');
105859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
105959829cc1SJean-Christophe PLAGNIOL-VILLARD 
106059829cc1SJean-Christophe PLAGNIOL-VILLARD 
106159829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; sect++) {
106259829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect] == 0) { /* not protected */
106359829cc1SJean-Christophe PLAGNIOL-VILLARD 			switch (info->vendor) {
10649c048b52SVasiliy Leoenenko 			case CFI_CMDSET_INTEL_PROG_REGIONS:
106559829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_STANDARD:
106659829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_EXTENDED:
10677e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10687e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_CLEAR_STATUS);
10697e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10707e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_BLOCK_ERASE);
10717e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10727e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_ERASE_CONFIRM);
107359829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
107459829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_STANDARD:
107559829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_EXTENDED:
107659829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
10777e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect,
10787e5b9b47SHaavard Skinnemoen 						info->addr_unlock1,
10797e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
108059829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
10817e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10827e5b9b47SHaavard Skinnemoen 						 AMD_CMD_ERASE_SECTOR);
108359829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
108481b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
108581b20cccSMichael Schwingen 			case CFI_CMDSET_AMD_LEGACY:
108681b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
10877e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, 0, info->addr_unlock1,
10887e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
108981b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
10907e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10917e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_SECTOR);
109281b20cccSMichael Schwingen 				break;
109381b20cccSMichael Schwingen #endif
109459829cc1SJean-Christophe PLAGNIOL-VILLARD 			default:
109559829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug ("Unkown flash vendor %d\n",
109659829cc1SJean-Christophe PLAGNIOL-VILLARD 				       info->vendor);
109759829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
109859829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
109959829cc1SJean-Christophe PLAGNIOL-VILLARD 
110059829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_full_status_check
110159829cc1SJean-Christophe PLAGNIOL-VILLARD 			    (info, sect, info->erase_blk_tout, "erase")) {
110259829cc1SJean-Christophe PLAGNIOL-VILLARD 				rcode = 1;
110359829cc1SJean-Christophe PLAGNIOL-VILLARD 			} else
110459829cc1SJean-Christophe PLAGNIOL-VILLARD 				putc ('.');
110559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
110659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
110759829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts (" done\n");
110859829cc1SJean-Christophe PLAGNIOL-VILLARD 	return rcode;
110959829cc1SJean-Christophe PLAGNIOL-VILLARD }
111059829cc1SJean-Christophe PLAGNIOL-VILLARD 
111159829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
111259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
111359829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info)
111459829cc1SJean-Christophe PLAGNIOL-VILLARD {
111559829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
111659829cc1SJean-Christophe PLAGNIOL-VILLARD 
111759829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
111859829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("missing or unknown FLASH type\n");
111959829cc1SJean-Christophe PLAGNIOL-VILLARD 		return;
112059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
112159829cc1SJean-Christophe PLAGNIOL-VILLARD 
112281b20cccSMichael Schwingen 	printf ("%s FLASH (%d x %d)",
112381b20cccSMichael Schwingen 		info->name,
112459829cc1SJean-Christophe PLAGNIOL-VILLARD 		(info->portwidth << 3), (info->chipwidth << 3));
112581b20cccSMichael Schwingen 	if (info->size < 1024*1024)
112681b20cccSMichael Schwingen 		printf ("  Size: %ld kB in %d Sectors\n",
112781b20cccSMichael Schwingen 			info->size >> 10, info->sector_count);
112881b20cccSMichael Schwingen 	else
112959829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  Size: %ld MB in %d Sectors\n",
113059829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->size >> 20, info->sector_count);
113159829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("  ");
113259829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
11339c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
11349c048b52SVasiliy Leoenenko 			printf ("Intel Prog Regions");
11359c048b52SVasiliy Leoenenko 			break;
113659829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
113759829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Standard");
113859829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
113959829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
114059829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Extended");
114159829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
114259829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
114359829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Standard");
114459829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
114559829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
114659829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Extended");
114759829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
114881b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
114981b20cccSMichael Schwingen 		case CFI_CMDSET_AMD_LEGACY:
115081b20cccSMichael Schwingen 			printf ("AMD Legacy");
115181b20cccSMichael Schwingen 			break;
115281b20cccSMichael Schwingen #endif
115359829cc1SJean-Christophe PLAGNIOL-VILLARD 		default:
115459829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Unknown (%d)", info->vendor);
115559829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
115659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
115759829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
115859829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->manufacturer_id, info->device_id);
115959829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->device_id == 0x7E) {
116059829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf("%04X", info->device_id2);
116159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
116259829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
116359829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->erase_blk_tout,
116459829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->write_tout);
116559829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->buffer_size > 1) {
11667e5b9b47SHaavard Skinnemoen 		printf ("  Buffer write timeout: %ld ms, "
11677e5b9b47SHaavard Skinnemoen 			"buffer size: %d bytes\n",
116859829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_write_tout,
116959829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_size);
117059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
117159829cc1SJean-Christophe PLAGNIOL-VILLARD 
117259829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts ("\n  Sector Start Addresses:");
117359829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < info->sector_count; ++i) {
117459829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((i % 5) == 0)
117559829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("\n");
1176*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_EMPTY_INFO
117759829cc1SJean-Christophe PLAGNIOL-VILLARD 		int k;
117859829cc1SJean-Christophe PLAGNIOL-VILLARD 		int size;
117959829cc1SJean-Christophe PLAGNIOL-VILLARD 		int erased;
118059829cc1SJean-Christophe PLAGNIOL-VILLARD 		volatile unsigned long *flash;
118159829cc1SJean-Christophe PLAGNIOL-VILLARD 
118259829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
118359829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * Check if whole sector is erased
118459829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
118512d30aa7SHaavard Skinnemoen 		size = flash_sector_size(info, i);
118659829cc1SJean-Christophe PLAGNIOL-VILLARD 		erased = 1;
118759829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash = (volatile unsigned long *) info->start[i];
118859829cc1SJean-Christophe PLAGNIOL-VILLARD 		size = size >> 2;	/* divide by 4 for longword access */
118959829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (k = 0; k < size; k++) {
119059829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (*flash++ != 0xffffffff) {
119159829cc1SJean-Christophe PLAGNIOL-VILLARD 				erased = 0;
119259829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
119359829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
119459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
119559829cc1SJean-Christophe PLAGNIOL-VILLARD 
119659829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* print empty and read-only info */
119759829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX %c %s ",
119859829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
119959829cc1SJean-Christophe PLAGNIOL-VILLARD 			erased ? 'E' : ' ',
120059829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
1201*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #else	/* ! CONFIG_SYS_FLASH_EMPTY_INFO */
120259829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX   %s ",
120359829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
120459829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
120559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
120659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
120759829cc1SJean-Christophe PLAGNIOL-VILLARD 	putc ('\n');
120859829cc1SJean-Christophe PLAGNIOL-VILLARD 	return;
120959829cc1SJean-Christophe PLAGNIOL-VILLARD }
121059829cc1SJean-Christophe PLAGNIOL-VILLARD 
121159829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
12129a042e9cSJerry Van Baren  * This is used in a few places in write_buf() to show programming
12139a042e9cSJerry Van Baren  * progress.  Making it a function is nasty because it needs to do side
12149a042e9cSJerry Van Baren  * effect updates to digit and dots.  Repeated code is nasty too, so
12159a042e9cSJerry Van Baren  * we define it once here.
12169a042e9cSJerry Van Baren  */
1217f0105727SStefan Roese #ifdef CONFIG_FLASH_SHOW_PROGRESS
1218f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
1219f0105727SStefan Roese 	dots -= dots_sub; \
12209a042e9cSJerry Van Baren 	if ((scale > 0) && (dots <= 0)) { \
12219a042e9cSJerry Van Baren 		if ((digit % 5) == 0) \
12229a042e9cSJerry Van Baren 			printf ("%d", digit / 5); \
12239a042e9cSJerry Van Baren 		else \
12249a042e9cSJerry Van Baren 			putc ('.'); \
12259a042e9cSJerry Van Baren 		digit--; \
12269a042e9cSJerry Van Baren 		dots += scale; \
12279a042e9cSJerry Van Baren 	}
1228f0105727SStefan Roese #else
1229f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1230f0105727SStefan Roese #endif
12319a042e9cSJerry Van Baren 
12329a042e9cSJerry Van Baren /*-----------------------------------------------------------------------
123359829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copy memory to flash, returns:
123459829cc1SJean-Christophe PLAGNIOL-VILLARD  * 0 - OK
123559829cc1SJean-Christophe PLAGNIOL-VILLARD  * 1 - write timeout
123659829cc1SJean-Christophe PLAGNIOL-VILLARD  * 2 - Flash not erased
123759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
123859829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
123959829cc1SJean-Christophe PLAGNIOL-VILLARD {
124059829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong wp;
124112d30aa7SHaavard Skinnemoen 	uchar *p;
124259829cc1SJean-Christophe PLAGNIOL-VILLARD 	int aln;
124359829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
124459829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, rc;
1245*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
124659829cc1SJean-Christophe PLAGNIOL-VILLARD 	int buffered_size;
124759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
12489a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS
12499a042e9cSJerry Van Baren 	int digit = CONFIG_FLASH_SHOW_PROGRESS;
12509a042e9cSJerry Van Baren 	int scale = 0;
12519a042e9cSJerry Van Baren 	int dots  = 0;
12529a042e9cSJerry Van Baren 
12539a042e9cSJerry Van Baren 	/*
12549a042e9cSJerry Van Baren 	 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
12559a042e9cSJerry Van Baren 	 */
12569a042e9cSJerry Van Baren 	if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
12579a042e9cSJerry Van Baren 		scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
12589a042e9cSJerry Van Baren 			CONFIG_FLASH_SHOW_PROGRESS);
12599a042e9cSJerry Van Baren 	}
12609a042e9cSJerry Van Baren #endif
12619a042e9cSJerry Van Baren 
126259829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* get lower aligned address */
126359829cc1SJean-Christophe PLAGNIOL-VILLARD 	wp = (addr & ~(info->portwidth - 1));
126459829cc1SJean-Christophe PLAGNIOL-VILLARD 
126559829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle unaligned start */
126659829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((aln = addr - wp) != 0) {
126759829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
126812d30aa7SHaavard Skinnemoen 		p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
126912d30aa7SHaavard Skinnemoen 		for (i = 0; i < aln; ++i)
127012d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
127159829cc1SJean-Christophe PLAGNIOL-VILLARD 
127259829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (; (i < info->portwidth) && (cnt > 0); i++) {
127359829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
127459829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt--;
127559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
127612d30aa7SHaavard Skinnemoen 		for (; (cnt == 0) && (i < info->portwidth); ++i)
127712d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
127812d30aa7SHaavard Skinnemoen 
127912d30aa7SHaavard Skinnemoen 		rc = flash_write_cfiword (info, wp, cword);
128012d30aa7SHaavard Skinnemoen 		unmap_physmem(p, info->portwidth);
128112d30aa7SHaavard Skinnemoen 		if (rc != 0)
128259829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
128312d30aa7SHaavard Skinnemoen 
128412d30aa7SHaavard Skinnemoen 		wp += i;
1285f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, i);
128659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
128759829cc1SJean-Christophe PLAGNIOL-VILLARD 
128859829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle the aligned part */
1289*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
129059829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size = (info->portwidth / info->chipwidth);
129159829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size *= info->buffer_size;
129259829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
129359829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* prohibit buffer write when buffer_size is 1 */
129459829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->buffer_size == 1) {
129559829cc1SJean-Christophe PLAGNIOL-VILLARD 			cword.l = 0;
129659829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->portwidth; i++)
129759829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_add_byte (info, &cword, *src++);
129859829cc1SJean-Christophe PLAGNIOL-VILLARD 			if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
129959829cc1SJean-Christophe PLAGNIOL-VILLARD 				return rc;
130059829cc1SJean-Christophe PLAGNIOL-VILLARD 			wp += info->portwidth;
130159829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt -= info->portwidth;
130259829cc1SJean-Christophe PLAGNIOL-VILLARD 			continue;
130359829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
130459829cc1SJean-Christophe PLAGNIOL-VILLARD 
130559829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* write buffer until next buffered_size aligned boundary */
130659829cc1SJean-Christophe PLAGNIOL-VILLARD 		i = buffered_size - (wp % buffered_size);
130759829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (i > cnt)
130859829cc1SJean-Christophe PLAGNIOL-VILLARD 			i = cnt;
130959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
131059829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
131159829cc1SJean-Christophe PLAGNIOL-VILLARD 		i -= i & (info->portwidth - 1);
131259829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += i;
131359829cc1SJean-Christophe PLAGNIOL-VILLARD 		src += i;
131459829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= i;
1315f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, i);
131659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
131759829cc1SJean-Christophe PLAGNIOL-VILLARD #else
131859829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
131959829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
132059829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < info->portwidth; i++) {
132159829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
132259829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
132359829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
132459829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
132559829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += info->portwidth;
132659829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= info->portwidth;
1327f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
132859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1329*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
13309a042e9cSJerry Van Baren 
133159829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (cnt == 0) {
133259829cc1SJean-Christophe PLAGNIOL-VILLARD 		return (0);
133359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
133459829cc1SJean-Christophe PLAGNIOL-VILLARD 
133559829cc1SJean-Christophe PLAGNIOL-VILLARD 	/*
133659829cc1SJean-Christophe PLAGNIOL-VILLARD 	 * handle unaligned tail bytes
133759829cc1SJean-Christophe PLAGNIOL-VILLARD 	 */
133859829cc1SJean-Christophe PLAGNIOL-VILLARD 	cword.l = 0;
133912d30aa7SHaavard Skinnemoen 	p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
134012d30aa7SHaavard Skinnemoen 	for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
134159829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_add_byte (info, &cword, *src++);
134259829cc1SJean-Christophe PLAGNIOL-VILLARD 		--cnt;
134359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
134412d30aa7SHaavard Skinnemoen 	for (; i < info->portwidth; ++i)
134512d30aa7SHaavard Skinnemoen 		flash_add_byte (info, &cword, flash_read8(p + i));
134612d30aa7SHaavard Skinnemoen 	unmap_physmem(p, info->portwidth);
134759829cc1SJean-Christophe PLAGNIOL-VILLARD 
134859829cc1SJean-Christophe PLAGNIOL-VILLARD 	return flash_write_cfiword (info, wp, cword);
134959829cc1SJean-Christophe PLAGNIOL-VILLARD }
135059829cc1SJean-Christophe PLAGNIOL-VILLARD 
135159829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
135259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1353*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
135459829cc1SJean-Christophe PLAGNIOL-VILLARD 
135559829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot)
135659829cc1SJean-Christophe PLAGNIOL-VILLARD {
135759829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retcode = 0;
135859829cc1SJean-Christophe PLAGNIOL-VILLARD 
1359bc9019e1SRafael Campos 	switch (info->vendor) {
1360bc9019e1SRafael Campos 		case CFI_CMDSET_INTEL_PROG_REGIONS:
1361bc9019e1SRafael Campos 		case CFI_CMDSET_INTEL_STANDARD:
13629e8e63ccSNick Spence 		case CFI_CMDSET_INTEL_EXTENDED:
1363bc9019e1SRafael Campos 			flash_write_cmd (info, sector, 0,
1364bc9019e1SRafael Campos 					 FLASH_CMD_CLEAR_STATUS);
136559829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
136659829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (prot)
1367bc9019e1SRafael Campos 				flash_write_cmd (info, sector, 0,
1368bc9019e1SRafael Campos 					FLASH_CMD_PROTECT_SET);
136959829cc1SJean-Christophe PLAGNIOL-VILLARD 			else
1370bc9019e1SRafael Campos 				flash_write_cmd (info, sector, 0,
1371bc9019e1SRafael Campos 					FLASH_CMD_PROTECT_CLEAR);
1372bc9019e1SRafael Campos 			break;
1373bc9019e1SRafael Campos 		case CFI_CMDSET_AMD_EXTENDED:
1374bc9019e1SRafael Campos 		case CFI_CMDSET_AMD_STANDARD:
1375bc9019e1SRafael Campos 			/* U-Boot only checks the first byte */
1376bc9019e1SRafael Campos 			if (info->manufacturer_id == (uchar)ATM_MANUFACT) {
1377bc9019e1SRafael Campos 				if (prot) {
1378bc9019e1SRafael Campos 					flash_unlock_seq (info, 0);
1379bc9019e1SRafael Campos 					flash_write_cmd (info, 0,
1380bc9019e1SRafael Campos 							info->addr_unlock1,
1381bc9019e1SRafael Campos 							ATM_CMD_SOFTLOCK_START);
1382bc9019e1SRafael Campos 					flash_unlock_seq (info, 0);
1383bc9019e1SRafael Campos 					flash_write_cmd (info, sector, 0,
1384bc9019e1SRafael Campos 							ATM_CMD_LOCK_SECT);
1385bc9019e1SRafael Campos 				} else {
1386bc9019e1SRafael Campos 					flash_write_cmd (info, 0,
1387bc9019e1SRafael Campos 							info->addr_unlock1,
1388bc9019e1SRafael Campos 							AMD_CMD_UNLOCK_START);
1389bc9019e1SRafael Campos 					if (info->device_id == ATM_ID_BV6416)
1390bc9019e1SRafael Campos 						flash_write_cmd (info, sector,
1391bc9019e1SRafael Campos 							0, ATM_CMD_UNLOCK_SECT);
1392bc9019e1SRafael Campos 				}
1393bc9019e1SRafael Campos 			}
1394bc9019e1SRafael Campos 			break;
13954e00acdeSTsiChung Liew #ifdef CONFIG_FLASH_CFI_LEGACY
13964e00acdeSTsiChung Liew 		case CFI_CMDSET_AMD_LEGACY:
13974e00acdeSTsiChung Liew 			flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
13984e00acdeSTsiChung Liew 			flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
13994e00acdeSTsiChung Liew 			if (prot)
14004e00acdeSTsiChung Liew 				flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
14014e00acdeSTsiChung Liew 			else
14024e00acdeSTsiChung Liew 				flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
14034e00acdeSTsiChung Liew #endif
1404bc9019e1SRafael Campos 	};
140559829cc1SJean-Christophe PLAGNIOL-VILLARD 
140659829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((retcode =
140759829cc1SJean-Christophe PLAGNIOL-VILLARD 	     flash_full_status_check (info, sector, info->erase_blk_tout,
140859829cc1SJean-Christophe PLAGNIOL-VILLARD 				      prot ? "protect" : "unprotect")) == 0) {
140959829cc1SJean-Christophe PLAGNIOL-VILLARD 
141059829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->protect[sector] = prot;
141159829cc1SJean-Christophe PLAGNIOL-VILLARD 
141259829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
141359829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * On some of Intel's flash chips (marked via legacy_unlock)
141459829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * unprotect unprotects all locking.
141559829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
141659829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((prot == 0) && (info->legacy_unlock)) {
141759829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_sect_t i;
141859829cc1SJean-Christophe PLAGNIOL-VILLARD 
141959829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->sector_count; i++) {
142059829cc1SJean-Christophe PLAGNIOL-VILLARD 				if (info->protect[i])
142159829cc1SJean-Christophe PLAGNIOL-VILLARD 					flash_real_protect (info, i, 1);
142259829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
142359829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
142459829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
142559829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retcode;
142659829cc1SJean-Christophe PLAGNIOL-VILLARD }
142759829cc1SJean-Christophe PLAGNIOL-VILLARD 
142859829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
142959829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_user_serial - read the OneTimeProgramming cells
143059829cc1SJean-Christophe PLAGNIOL-VILLARD  */
143159829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
143259829cc1SJean-Christophe PLAGNIOL-VILLARD 			     int len)
143359829cc1SJean-Christophe PLAGNIOL-VILLARD {
143459829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
143559829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *dst;
143659829cc1SJean-Christophe PLAGNIOL-VILLARD 
143759829cc1SJean-Christophe PLAGNIOL-VILLARD 	dst = buffer;
143812d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
143959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
144059829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (dst, src + offset, len);
144159829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
144212d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
144359829cc1SJean-Christophe PLAGNIOL-VILLARD }
144459829cc1SJean-Christophe PLAGNIOL-VILLARD 
144559829cc1SJean-Christophe PLAGNIOL-VILLARD /*
144659829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_factory_serial - read the device Id from the protection area
144759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
144859829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
144959829cc1SJean-Christophe PLAGNIOL-VILLARD 				int len)
145059829cc1SJean-Christophe PLAGNIOL-VILLARD {
145159829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
145259829cc1SJean-Christophe PLAGNIOL-VILLARD 
145312d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
145459829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
145559829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (buffer, src + offset, len);
145659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
145712d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
145859829cc1SJean-Christophe PLAGNIOL-VILLARD }
145959829cc1SJean-Christophe PLAGNIOL-VILLARD 
1460*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */
146159829cc1SJean-Christophe PLAGNIOL-VILLARD 
14620ddf06ddSHaavard Skinnemoen /*-----------------------------------------------------------------------
14630ddf06ddSHaavard Skinnemoen  * Reverse the order of the erase regions in the CFI QRY structure.
14640ddf06ddSHaavard Skinnemoen  * This is needed for chips that are either a) correctly detected as
14650ddf06ddSHaavard Skinnemoen  * top-boot, or b) buggy.
14660ddf06ddSHaavard Skinnemoen  */
14670ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry)
14680ddf06ddSHaavard Skinnemoen {
14690ddf06ddSHaavard Skinnemoen 	unsigned int i, j;
14700ddf06ddSHaavard Skinnemoen 	u32 tmp;
14710ddf06ddSHaavard Skinnemoen 
14720ddf06ddSHaavard Skinnemoen 	for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
14730ddf06ddSHaavard Skinnemoen 		tmp = qry->erase_region_info[i];
14740ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[i] = qry->erase_region_info[j];
14750ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[j] = tmp;
14760ddf06ddSHaavard Skinnemoen 	}
14770ddf06ddSHaavard Skinnemoen }
147859829cc1SJean-Christophe PLAGNIOL-VILLARD 
147959829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
148059829cc1SJean-Christophe PLAGNIOL-VILLARD  * read jedec ids from device and set corresponding fields in info struct
148159829cc1SJean-Christophe PLAGNIOL-VILLARD  *
148259829cc1SJean-Christophe PLAGNIOL-VILLARD  * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
148359829cc1SJean-Christophe PLAGNIOL-VILLARD  *
148459829cc1SJean-Christophe PLAGNIOL-VILLARD  */
14850ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info)
148659829cc1SJean-Christophe PLAGNIOL-VILLARD {
148759829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
148859829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
148959829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
149059829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = flash_read_uchar (info,
149159829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_MANUFACTURER_ID);
149259829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id = flash_read_uchar (info,
149359829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID);
149459829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
14950ddf06ddSHaavard Skinnemoen }
14960ddf06ddSHaavard Skinnemoen 
14970ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
14980ddf06ddSHaavard Skinnemoen {
14990ddf06ddSHaavard Skinnemoen 	info->cmd_reset = FLASH_CMD_RESET;
15000ddf06ddSHaavard Skinnemoen 
15010ddf06ddSHaavard Skinnemoen 	cmdset_intel_read_jedec_ids(info);
15020ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
15030ddf06ddSHaavard Skinnemoen 
1504*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
15050ddf06ddSHaavard Skinnemoen 	/* read legacy lock/unlock bit from intel flash */
15060ddf06ddSHaavard Skinnemoen 	if (info->ext_addr) {
15070ddf06ddSHaavard Skinnemoen 		info->legacy_unlock = flash_read_uchar (info,
15080ddf06ddSHaavard Skinnemoen 				info->ext_addr + 5) & 0x08;
15090ddf06ddSHaavard Skinnemoen 	}
15100ddf06ddSHaavard Skinnemoen #endif
15110ddf06ddSHaavard Skinnemoen 
15120ddf06ddSHaavard Skinnemoen 	return 0;
15130ddf06ddSHaavard Skinnemoen }
15140ddf06ddSHaavard Skinnemoen 
15150ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info)
15160ddf06ddSHaavard Skinnemoen {
151759829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
151859829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_unlock_seq(info, 0);
151981b20cccSMichael Schwingen 	flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
152059829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
152190447ecbSTor Krill 
152259829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = flash_read_uchar (info,
152359829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_MANUFACTURER_ID);
152490447ecbSTor Krill 
152590447ecbSTor Krill 	switch (info->chipwidth){
152690447ecbSTor Krill 	case FLASH_CFI_8BIT:
152759829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id = flash_read_uchar (info,
152859829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID);
152959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->device_id == 0x7E) {
153059829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* AMD 3-byte (expanded) device ids */
153159829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 = flash_read_uchar (info,
153259829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID2);
153359829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 <<= 8;
153459829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 |= flash_read_uchar (info,
153559829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID3);
153659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
153790447ecbSTor Krill 		break;
153890447ecbSTor Krill 	case FLASH_CFI_16BIT:
153990447ecbSTor Krill 		info->device_id = flash_read_word (info,
154090447ecbSTor Krill 						FLASH_OFFSET_DEVICE_ID);
154190447ecbSTor Krill 		break;
154290447ecbSTor Krill 	default:
154390447ecbSTor Krill 		break;
154490447ecbSTor Krill 	}
154559829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
15460ddf06ddSHaavard Skinnemoen }
15470ddf06ddSHaavard Skinnemoen 
15480ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
15490ddf06ddSHaavard Skinnemoen {
15500ddf06ddSHaavard Skinnemoen 	info->cmd_reset = AMD_CMD_RESET;
15510ddf06ddSHaavard Skinnemoen 
15520ddf06ddSHaavard Skinnemoen 	cmdset_amd_read_jedec_ids(info);
15530ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
15540ddf06ddSHaavard Skinnemoen 
15550ddf06ddSHaavard Skinnemoen 	return 0;
15560ddf06ddSHaavard Skinnemoen }
15570ddf06ddSHaavard Skinnemoen 
15580ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
15590ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info)
15600ddf06ddSHaavard Skinnemoen {
15610ddf06ddSHaavard Skinnemoen 	info->manufacturer_id = 0;
15620ddf06ddSHaavard Skinnemoen 	info->device_id       = 0;
15630ddf06ddSHaavard Skinnemoen 	info->device_id2      = 0;
15640ddf06ddSHaavard Skinnemoen 
15650ddf06ddSHaavard Skinnemoen 	switch (info->vendor) {
15669c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
15670ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
15680ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
15698225d1e3SMichael Schwingen 		cmdset_intel_read_jedec_ids(info);
15700ddf06ddSHaavard Skinnemoen 		break;
15710ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
15720ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
15738225d1e3SMichael Schwingen 		cmdset_amd_read_jedec_ids(info);
157459829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
157559829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
157659829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
157759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
157859829cc1SJean-Christophe PLAGNIOL-VILLARD }
157959829cc1SJean-Christophe PLAGNIOL-VILLARD 
1580be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
1581be60a902SHaavard Skinnemoen  * Call board code to request info about non-CFI flash.
1582be60a902SHaavard Skinnemoen  * board_flash_get_legacy needs to fill in at least:
1583be60a902SHaavard Skinnemoen  * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1584be60a902SHaavard Skinnemoen  */
1585be60a902SHaavard Skinnemoen static int flash_detect_legacy(ulong base, int banknum)
1586be60a902SHaavard Skinnemoen {
1587be60a902SHaavard Skinnemoen 	flash_info_t *info = &flash_info[banknum];
1588be60a902SHaavard Skinnemoen 
1589be60a902SHaavard Skinnemoen 	if (board_flash_get_legacy(base, banknum, info)) {
1590be60a902SHaavard Skinnemoen 		/* board code may have filled info completely. If not, we
1591be60a902SHaavard Skinnemoen 		   use JEDEC ID probing. */
1592be60a902SHaavard Skinnemoen 		if (!info->vendor) {
1593be60a902SHaavard Skinnemoen 			int modes[] = {
1594be60a902SHaavard Skinnemoen 				CFI_CMDSET_AMD_STANDARD,
1595be60a902SHaavard Skinnemoen 				CFI_CMDSET_INTEL_STANDARD
1596be60a902SHaavard Skinnemoen 			};
1597be60a902SHaavard Skinnemoen 			int i;
1598be60a902SHaavard Skinnemoen 
1599be60a902SHaavard Skinnemoen 			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1600be60a902SHaavard Skinnemoen 				info->vendor = modes[i];
1601be60a902SHaavard Skinnemoen 				info->start[0] = base;
1602be60a902SHaavard Skinnemoen 				if (info->portwidth == FLASH_CFI_8BIT
1603be60a902SHaavard Skinnemoen 					&& info->interface == FLASH_CFI_X8X16) {
1604be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x2AAA;
1605be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x5555;
1606be60a902SHaavard Skinnemoen 				} else {
1607be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x5555;
1608be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x2AAA;
1609be60a902SHaavard Skinnemoen 				}
1610be60a902SHaavard Skinnemoen 				flash_read_jedec_ids(info);
1611be60a902SHaavard Skinnemoen 				debug("JEDEC PROBE: ID %x %x %x\n",
1612be60a902SHaavard Skinnemoen 						info->manufacturer_id,
1613be60a902SHaavard Skinnemoen 						info->device_id,
1614be60a902SHaavard Skinnemoen 						info->device_id2);
1615be60a902SHaavard Skinnemoen 				if (jedec_flash_match(info, base))
1616be60a902SHaavard Skinnemoen 					break;
1617be60a902SHaavard Skinnemoen 			}
1618be60a902SHaavard Skinnemoen 		}
1619be60a902SHaavard Skinnemoen 
1620be60a902SHaavard Skinnemoen 		switch(info->vendor) {
16219c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
1622be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_STANDARD:
1623be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_EXTENDED:
1624be60a902SHaavard Skinnemoen 			info->cmd_reset = FLASH_CMD_RESET;
1625be60a902SHaavard Skinnemoen 			break;
1626be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_STANDARD:
1627be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_EXTENDED:
1628be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_LEGACY:
1629be60a902SHaavard Skinnemoen 			info->cmd_reset = AMD_CMD_RESET;
1630be60a902SHaavard Skinnemoen 			break;
1631be60a902SHaavard Skinnemoen 		}
1632be60a902SHaavard Skinnemoen 		info->flash_id = FLASH_MAN_CFI;
1633be60a902SHaavard Skinnemoen 		return 1;
1634be60a902SHaavard Skinnemoen 	}
1635be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1636be60a902SHaavard Skinnemoen }
1637be60a902SHaavard Skinnemoen #else
1638be60a902SHaavard Skinnemoen static inline int flash_detect_legacy(ulong base, int banknum)
1639be60a902SHaavard Skinnemoen {
1640be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1641be60a902SHaavard Skinnemoen }
1642be60a902SHaavard Skinnemoen #endif
1643be60a902SHaavard Skinnemoen 
164459829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
164559829cc1SJean-Christophe PLAGNIOL-VILLARD  * detect if flash is compatible with the Common Flash Interface (CFI)
164659829cc1SJean-Christophe PLAGNIOL-VILLARD  * http://www.jedec.org/download/search/jesd68.pdf
164759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1648e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf,
1649e23741f4SHaavard Skinnemoen 		unsigned int start, size_t len)
1650e23741f4SHaavard Skinnemoen {
1651e23741f4SHaavard Skinnemoen 	u8 *p = buf;
1652e23741f4SHaavard Skinnemoen 	unsigned int i;
1653e23741f4SHaavard Skinnemoen 
1654e23741f4SHaavard Skinnemoen 	for (i = 0; i < len; i++)
1655e23741f4SHaavard Skinnemoen 		p[i] = flash_read_uchar(info, start + i);
1656e23741f4SHaavard Skinnemoen }
1657e23741f4SHaavard Skinnemoen 
1658e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
165959829cc1SJean-Christophe PLAGNIOL-VILLARD {
166059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int cfi_offset;
166159829cc1SJean-Christophe PLAGNIOL-VILLARD 
16621ba639daSMichael Schwingen 	/* We do not yet know what kind of commandset to use, so we issue
16631ba639daSMichael Schwingen 	   the reset command in both Intel and AMD variants, in the hope
16641ba639daSMichael Schwingen 	   that AMD flash roms ignore the Intel command. */
16651ba639daSMichael Schwingen 	flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
16661ba639daSMichael Schwingen 	flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
16671ba639daSMichael Schwingen 
16687e5b9b47SHaavard Skinnemoen 	for (cfi_offset=0;
16697e5b9b47SHaavard Skinnemoen 	     cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
16707e5b9b47SHaavard Skinnemoen 	     cfi_offset++) {
16717e5b9b47SHaavard Skinnemoen 		flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
16727e5b9b47SHaavard Skinnemoen 				 FLASH_CMD_CFI);
167359829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
167459829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
167559829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
1676e23741f4SHaavard Skinnemoen 			flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1677e23741f4SHaavard Skinnemoen 					sizeof(struct cfi_qry));
1678e23741f4SHaavard Skinnemoen 			info->interface	= le16_to_cpu(qry->interface_desc);
1679e23741f4SHaavard Skinnemoen 
168059829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_offset = flash_offset_cfi[cfi_offset];
168159829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("device interface is %d\n",
168259829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->interface);
168359829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("found port %d chip %d ",
168459829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth, info->chipwidth);
168559829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("port %d bits chip %d bits\n",
168659829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth << CFI_FLASH_SHIFT_WIDTH,
168759829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
168842026c9cSBartlomiej Sieka 
168942026c9cSBartlomiej Sieka 			/* calculate command offsets as in the Linux driver */
169042026c9cSBartlomiej Sieka 			info->addr_unlock1 = 0x555;
169142026c9cSBartlomiej Sieka 			info->addr_unlock2 = 0x2aa;
169242026c9cSBartlomiej Sieka 
169342026c9cSBartlomiej Sieka 			/*
169442026c9cSBartlomiej Sieka 			 * modify the unlock address if we are
169542026c9cSBartlomiej Sieka 			 * in compatibility mode
169642026c9cSBartlomiej Sieka 			 */
169742026c9cSBartlomiej Sieka 			if (	/* x8/x16 in x8 mode */
169842026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY8) &&
169942026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X8X16)) ||
170042026c9cSBartlomiej Sieka 				/* x16/x32 in x16 mode */
170142026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY16) &&
170242026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X16X32)))
170342026c9cSBartlomiej Sieka 			{
170442026c9cSBartlomiej Sieka 				info->addr_unlock1 = 0xaaa;
170542026c9cSBartlomiej Sieka 				info->addr_unlock2 = 0x555;
170642026c9cSBartlomiej Sieka 			}
170742026c9cSBartlomiej Sieka 
170881b20cccSMichael Schwingen 			info->name = "CFI conformant";
170959829cc1SJean-Christophe PLAGNIOL-VILLARD 			return 1;
171059829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
171159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
17127e5b9b47SHaavard Skinnemoen 
17137e5b9b47SHaavard Skinnemoen 	return 0;
171459829cc1SJean-Christophe PLAGNIOL-VILLARD }
17157e5b9b47SHaavard Skinnemoen 
1716e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
17177e5b9b47SHaavard Skinnemoen {
17187e5b9b47SHaavard Skinnemoen 	debug ("flash detect cfi\n");
17197e5b9b47SHaavard Skinnemoen 
1720*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	for (info->portwidth = CONFIG_SYS_FLASH_CFI_WIDTH;
17217e5b9b47SHaavard Skinnemoen 	     info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
17227e5b9b47SHaavard Skinnemoen 		for (info->chipwidth = FLASH_CFI_BY8;
17237e5b9b47SHaavard Skinnemoen 		     info->chipwidth <= info->portwidth;
17247e5b9b47SHaavard Skinnemoen 		     info->chipwidth <<= 1)
1725e23741f4SHaavard Skinnemoen 			if (__flash_detect_cfi(info, qry))
17267e5b9b47SHaavard Skinnemoen 				return 1;
172759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
172859829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("not found\n");
172959829cc1SJean-Christophe PLAGNIOL-VILLARD 	return 0;
173059829cc1SJean-Christophe PLAGNIOL-VILLARD }
173159829cc1SJean-Christophe PLAGNIOL-VILLARD 
173259829cc1SJean-Christophe PLAGNIOL-VILLARD /*
1733467bcee1SHaavard Skinnemoen  * Manufacturer-specific quirks. Add workarounds for geometry
1734467bcee1SHaavard Skinnemoen  * reversal, etc. here.
1735467bcee1SHaavard Skinnemoen  */
1736467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1737467bcee1SHaavard Skinnemoen {
1738467bcee1SHaavard Skinnemoen 	/* check if flash geometry needs reversal */
1739467bcee1SHaavard Skinnemoen 	if (qry->num_erase_regions > 1) {
1740467bcee1SHaavard Skinnemoen 		/* reverse geometry if top boot part */
1741467bcee1SHaavard Skinnemoen 		if (info->cfi_version < 0x3131) {
1742467bcee1SHaavard Skinnemoen 			/* CFI < 1.1, try to guess from device id */
1743467bcee1SHaavard Skinnemoen 			if ((info->device_id & 0x80) != 0)
1744467bcee1SHaavard Skinnemoen 				cfi_reverse_geometry(qry);
1745467bcee1SHaavard Skinnemoen 		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1746467bcee1SHaavard Skinnemoen 			/* CFI >= 1.1, deduct from top/bottom flag */
1747467bcee1SHaavard Skinnemoen 			/* note: ext_addr is valid since cfi_version > 0 */
1748467bcee1SHaavard Skinnemoen 			cfi_reverse_geometry(qry);
1749467bcee1SHaavard Skinnemoen 		}
1750467bcee1SHaavard Skinnemoen 	}
1751467bcee1SHaavard Skinnemoen }
1752467bcee1SHaavard Skinnemoen 
1753467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1754467bcee1SHaavard Skinnemoen {
1755467bcee1SHaavard Skinnemoen 	int reverse_geometry = 0;
1756467bcee1SHaavard Skinnemoen 
1757467bcee1SHaavard Skinnemoen 	/* Check the "top boot" bit in the PRI */
1758467bcee1SHaavard Skinnemoen 	if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1759467bcee1SHaavard Skinnemoen 		reverse_geometry = 1;
1760467bcee1SHaavard Skinnemoen 
1761467bcee1SHaavard Skinnemoen 	/* AT49BV6416(T) list the erase regions in the wrong order.
1762467bcee1SHaavard Skinnemoen 	 * However, the device ID is identical with the non-broken
1763467bcee1SHaavard Skinnemoen 	 * AT49BV642D since u-boot only reads the low byte (they
1764467bcee1SHaavard Skinnemoen 	 * differ in the high byte.) So leave out this fixup for now.
1765467bcee1SHaavard Skinnemoen 	 */
1766467bcee1SHaavard Skinnemoen #if 0
1767467bcee1SHaavard Skinnemoen 	if (info->device_id == 0xd6 || info->device_id == 0xd2)
1768467bcee1SHaavard Skinnemoen 		reverse_geometry = !reverse_geometry;
1769467bcee1SHaavard Skinnemoen #endif
1770467bcee1SHaavard Skinnemoen 
1771467bcee1SHaavard Skinnemoen 	if (reverse_geometry)
1772467bcee1SHaavard Skinnemoen 		cfi_reverse_geometry(qry);
1773467bcee1SHaavard Skinnemoen }
1774467bcee1SHaavard Skinnemoen 
1775467bcee1SHaavard Skinnemoen /*
177659829cc1SJean-Christophe PLAGNIOL-VILLARD  * The following code cannot be run from FLASH!
177759829cc1SJean-Christophe PLAGNIOL-VILLARD  *
177859829cc1SJean-Christophe PLAGNIOL-VILLARD  */
177959829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum)
178059829cc1SJean-Christophe PLAGNIOL-VILLARD {
178159829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_info_t *info = &flash_info[banknum];
178259829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, j;
178359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect_cnt;
178459829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long sector;
178559829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long tmp;
178659829cc1SJean-Christophe PLAGNIOL-VILLARD 	int size_ratio;
178759829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar num_erase_regions;
178859829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_size;
178959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_count;
1790e23741f4SHaavard Skinnemoen 	struct cfi_qry qry;
179159829cc1SJean-Christophe PLAGNIOL-VILLARD 
1792f979690eSKumar Gala 	memset(&qry, 0, sizeof(qry));
1793f979690eSKumar Gala 
179459829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->ext_addr = 0;
179559829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->cfi_version = 0;
1796*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
179759829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->legacy_unlock = 0;
179859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
179959829cc1SJean-Christophe PLAGNIOL-VILLARD 
180059829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->start[0] = base;
180159829cc1SJean-Christophe PLAGNIOL-VILLARD 
1802e23741f4SHaavard Skinnemoen 	if (flash_detect_cfi (info, &qry)) {
1803e23741f4SHaavard Skinnemoen 		info->vendor = le16_to_cpu(qry.p_id);
1804e23741f4SHaavard Skinnemoen 		info->ext_addr = le16_to_cpu(qry.p_adr);
1805e23741f4SHaavard Skinnemoen 		num_erase_regions = qry.num_erase_regions;
1806e23741f4SHaavard Skinnemoen 
180759829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->ext_addr) {
180859829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version = (ushort) flash_read_uchar (info,
180959829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 3) << 8;
181059829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version |= (ushort) flash_read_uchar (info,
181159829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 4);
181259829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
18130ddf06ddSHaavard Skinnemoen 
181459829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
1815e23741f4SHaavard Skinnemoen 		flash_printqry (&qry);
181659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
18170ddf06ddSHaavard Skinnemoen 
181859829cc1SJean-Christophe PLAGNIOL-VILLARD 		switch (info->vendor) {
18199c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
182059829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
182159829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
18220ddf06ddSHaavard Skinnemoen 			cmdset_intel_init(info, &qry);
182359829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
182459829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
182559829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
18260ddf06ddSHaavard Skinnemoen 			cmdset_amd_init(info, &qry);
182759829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
18280ddf06ddSHaavard Skinnemoen 		default:
18290ddf06ddSHaavard Skinnemoen 			printf("CFI: Unknown command set 0x%x\n",
18300ddf06ddSHaavard Skinnemoen 					info->vendor);
18310ddf06ddSHaavard Skinnemoen 			/*
18320ddf06ddSHaavard Skinnemoen 			 * Unfortunately, this means we don't know how
18330ddf06ddSHaavard Skinnemoen 			 * to get the chip back to Read mode. Might
18340ddf06ddSHaavard Skinnemoen 			 * as well try an Intel-style reset...
18350ddf06ddSHaavard Skinnemoen 			 */
18360ddf06ddSHaavard Skinnemoen 			flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
18370ddf06ddSHaavard Skinnemoen 			return 0;
183859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
183959829cc1SJean-Christophe PLAGNIOL-VILLARD 
1840467bcee1SHaavard Skinnemoen 		/* Do manufacturer-specific fixups */
1841467bcee1SHaavard Skinnemoen 		switch (info->manufacturer_id) {
1842467bcee1SHaavard Skinnemoen 		case 0x0001:
1843467bcee1SHaavard Skinnemoen 			flash_fixup_amd(info, &qry);
1844467bcee1SHaavard Skinnemoen 			break;
1845467bcee1SHaavard Skinnemoen 		case 0x001f:
1846467bcee1SHaavard Skinnemoen 			flash_fixup_atmel(info, &qry);
1847467bcee1SHaavard Skinnemoen 			break;
1848467bcee1SHaavard Skinnemoen 		}
1849467bcee1SHaavard Skinnemoen 
185059829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer is %d\n", info->vendor);
185159829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
185259829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id is 0x%x\n", info->device_id);
185359829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id2 is 0x%x\n", info->device_id2);
185459829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("cfi version is 0x%04x\n", info->cfi_version);
185559829cc1SJean-Christophe PLAGNIOL-VILLARD 
185659829cc1SJean-Christophe PLAGNIOL-VILLARD 		size_ratio = info->portwidth / info->chipwidth;
185759829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* if the chip is x8/x16 reduce the ratio by half */
185859829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((info->interface == FLASH_CFI_X8X16)
185959829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && (info->chipwidth == FLASH_CFI_BY8)) {
186059829cc1SJean-Christophe PLAGNIOL-VILLARD 			size_ratio >>= 1;
186159829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
186259829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("size_ratio %d port %d bits chip %d bits\n",
186359829cc1SJean-Christophe PLAGNIOL-VILLARD 		       size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
186459829cc1SJean-Christophe PLAGNIOL-VILLARD 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
186559829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("found %d erase regions\n", num_erase_regions);
186659829cc1SJean-Christophe PLAGNIOL-VILLARD 		sect_cnt = 0;
186759829cc1SJean-Christophe PLAGNIOL-VILLARD 		sector = base;
186859829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < num_erase_regions; i++) {
186959829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (i > NUM_ERASE_REGIONS) {
187059829cc1SJean-Christophe PLAGNIOL-VILLARD 				printf ("%d erase regions found, only %d used\n",
187159829cc1SJean-Christophe PLAGNIOL-VILLARD 					num_erase_regions, NUM_ERASE_REGIONS);
187259829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
187359829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1874e23741f4SHaavard Skinnemoen 
18750ddf06ddSHaavard Skinnemoen 			tmp = le32_to_cpu(qry.erase_region_info[i]);
18760ddf06ddSHaavard Skinnemoen 			debug("erase region %u: 0x%08lx\n", i, tmp);
1877e23741f4SHaavard Skinnemoen 
1878e23741f4SHaavard Skinnemoen 			erase_region_count = (tmp & 0xffff) + 1;
1879e23741f4SHaavard Skinnemoen 			tmp >>= 16;
188059829cc1SJean-Christophe PLAGNIOL-VILLARD 			erase_region_size =
188159829cc1SJean-Christophe PLAGNIOL-VILLARD 				(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
188259829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("erase_region_count = %d erase_region_size = %d\n",
188359829cc1SJean-Christophe PLAGNIOL-VILLARD 				erase_region_count, erase_region_size);
188459829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (j = 0; j < erase_region_count; j++) {
1885*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 				if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
188681b20cccSMichael Schwingen 					printf("ERROR: too many flash sectors\n");
188781b20cccSMichael Schwingen 					break;
188881b20cccSMichael Schwingen 				}
188959829cc1SJean-Christophe PLAGNIOL-VILLARD 				info->start[sect_cnt] = sector;
189059829cc1SJean-Christophe PLAGNIOL-VILLARD 				sector += (erase_region_size * size_ratio);
189159829cc1SJean-Christophe PLAGNIOL-VILLARD 
189259829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
18937e5b9b47SHaavard Skinnemoen 				 * Only read protection status from
18947e5b9b47SHaavard Skinnemoen 				 * supported devices (intel...)
189559829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
189659829cc1SJean-Christophe PLAGNIOL-VILLARD 				switch (info->vendor) {
18979c048b52SVasiliy Leoenenko 				case CFI_CMDSET_INTEL_PROG_REGIONS:
189859829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_EXTENDED:
189959829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_STANDARD:
190059829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->protect[sect_cnt] =
190159829cc1SJean-Christophe PLAGNIOL-VILLARD 						flash_isset (info, sect_cnt,
190259829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_OFFSET_PROTECT,
190359829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_STATUS_PROTECT);
190459829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
190559829cc1SJean-Christophe PLAGNIOL-VILLARD 				default:
19067e5b9b47SHaavard Skinnemoen 					/* default: not protected */
19077e5b9b47SHaavard Skinnemoen 					info->protect[sect_cnt] = 0;
190859829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
190959829cc1SJean-Christophe PLAGNIOL-VILLARD 
191059829cc1SJean-Christophe PLAGNIOL-VILLARD 				sect_cnt++;
191159829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
191259829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
191359829cc1SJean-Christophe PLAGNIOL-VILLARD 
191459829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->sector_count = sect_cnt;
1915e23741f4SHaavard Skinnemoen 		info->size = 1 << qry.dev_size;
191659829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* multiply the size by the number of chips */
19177e5b9b47SHaavard Skinnemoen 		info->size *= size_ratio;
1918e23741f4SHaavard Skinnemoen 		info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1919e23741f4SHaavard Skinnemoen 		tmp = 1 << qry.block_erase_timeout_typ;
19207e5b9b47SHaavard Skinnemoen 		info->erase_blk_tout = tmp *
1921e23741f4SHaavard Skinnemoen 			(1 << qry.block_erase_timeout_max);
1922e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.buf_write_timeout_typ) *
1923e23741f4SHaavard Skinnemoen 			(1 << qry.buf_write_timeout_max);
1924e23741f4SHaavard Skinnemoen 
19257e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1926e23741f4SHaavard Skinnemoen 		info->buffer_write_tout = (tmp + 999) / 1000;
1927e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.word_write_timeout_typ) *
1928e23741f4SHaavard Skinnemoen 			(1 << qry.word_write_timeout_max);
19297e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1930e23741f4SHaavard Skinnemoen 		info->write_tout = (tmp + 999) / 1000;
193159829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->flash_id = FLASH_MAN_CFI;
19327e5b9b47SHaavard Skinnemoen 		if ((info->interface == FLASH_CFI_X8X16) &&
19337e5b9b47SHaavard Skinnemoen 		    (info->chipwidth == FLASH_CFI_BY8)) {
19347e5b9b47SHaavard Skinnemoen 			/* XXX - Need to test on x8/x16 in parallel. */
19357e5b9b47SHaavard Skinnemoen 			info->portwidth >>= 1;
193659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
193759829cc1SJean-Christophe PLAGNIOL-VILLARD 
193859829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, 0, 0, info->cmd_reset);
19392215987eSMike Frysinger 	}
19402215987eSMike Frysinger 
194159829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (info->size);
194259829cc1SJean-Christophe PLAGNIOL-VILLARD }
194359829cc1SJean-Christophe PLAGNIOL-VILLARD 
194459829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
194559829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1946be60a902SHaavard Skinnemoen unsigned long flash_init (void)
194759829cc1SJean-Christophe PLAGNIOL-VILLARD {
1948be60a902SHaavard Skinnemoen 	unsigned long size = 0;
1949be60a902SHaavard Skinnemoen 	int i;
1950*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
1951c63ad632SMatthias Fuchs 	struct apl_s {
1952c63ad632SMatthias Fuchs 		ulong start;
1953c63ad632SMatthias Fuchs 		ulong size;
1954*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	} apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST;
1955c63ad632SMatthias Fuchs #endif
195659829cc1SJean-Christophe PLAGNIOL-VILLARD 
1957*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
1958be60a902SHaavard Skinnemoen 	char *s = getenv("unlock");
195981b20cccSMichael Schwingen #endif
1960be60a902SHaavard Skinnemoen 
1961*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define BANK_BASE(i)	(((unsigned long [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i])
19622a112b23SWolfgang Denk 
1963be60a902SHaavard Skinnemoen 	/* Init: no FLASHes known */
1964*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
1965be60a902SHaavard Skinnemoen 		flash_info[i].flash_id = FLASH_UNKNOWN;
1966be60a902SHaavard Skinnemoen 
19672a112b23SWolfgang Denk 		if (!flash_detect_legacy (BANK_BASE(i), i))
19682a112b23SWolfgang Denk 			flash_get_size (BANK_BASE(i), i);
1969be60a902SHaavard Skinnemoen 		size += flash_info[i].size;
1970be60a902SHaavard Skinnemoen 		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
1971*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_QUIET_TEST
1972be60a902SHaavard Skinnemoen 			printf ("## Unknown FLASH on Bank %d "
1973be60a902SHaavard Skinnemoen 				"- Size = 0x%08lx = %ld MB\n",
1974be60a902SHaavard Skinnemoen 				i+1, flash_info[i].size,
1975be60a902SHaavard Skinnemoen 				flash_info[i].size << 20);
1976*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_QUIET_TEST */
197759829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1978*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FLASH_PROTECTION
1979be60a902SHaavard Skinnemoen 		else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
1980be60a902SHaavard Skinnemoen 			/*
1981be60a902SHaavard Skinnemoen 			 * Only the U-Boot image and it's environment
1982be60a902SHaavard Skinnemoen 			 * is protected, all other sectors are
1983be60a902SHaavard Skinnemoen 			 * unprotected (unlocked) if flash hardware
1984*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 			 * protection is used (CONFIG_SYS_FLASH_PROTECTION)
1985be60a902SHaavard Skinnemoen 			 * and the environment variable "unlock" is
1986be60a902SHaavard Skinnemoen 			 * set to "yes".
1987be60a902SHaavard Skinnemoen 			 */
1988be60a902SHaavard Skinnemoen 			if (flash_info[i].legacy_unlock) {
1989be60a902SHaavard Skinnemoen 				int k;
199059829cc1SJean-Christophe PLAGNIOL-VILLARD 
1991be60a902SHaavard Skinnemoen 				/*
1992be60a902SHaavard Skinnemoen 				 * Disable legacy_unlock temporarily,
1993be60a902SHaavard Skinnemoen 				 * since flash_real_protect would
1994be60a902SHaavard Skinnemoen 				 * relock all other sectors again
1995be60a902SHaavard Skinnemoen 				 * otherwise.
1996be60a902SHaavard Skinnemoen 				 */
1997be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 0;
199859829cc1SJean-Christophe PLAGNIOL-VILLARD 
1999be60a902SHaavard Skinnemoen 				/*
2000be60a902SHaavard Skinnemoen 				 * Legacy unlocking (e.g. Intel J3) ->
2001be60a902SHaavard Skinnemoen 				 * unlock only one sector. This will
2002be60a902SHaavard Skinnemoen 				 * unlock all sectors.
2003be60a902SHaavard Skinnemoen 				 */
2004be60a902SHaavard Skinnemoen 				flash_real_protect (&flash_info[i], 0, 0);
200559829cc1SJean-Christophe PLAGNIOL-VILLARD 
2006be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 1;
200759829cc1SJean-Christophe PLAGNIOL-VILLARD 
2008be60a902SHaavard Skinnemoen 				/*
2009be60a902SHaavard Skinnemoen 				 * Manually mark other sectors as
2010be60a902SHaavard Skinnemoen 				 * unlocked (unprotected)
2011be60a902SHaavard Skinnemoen 				 */
2012be60a902SHaavard Skinnemoen 				for (k = 1; k < flash_info[i].sector_count; k++)
2013be60a902SHaavard Skinnemoen 					flash_info[i].protect[k] = 0;
2014be60a902SHaavard Skinnemoen 			} else {
2015be60a902SHaavard Skinnemoen 				/*
2016be60a902SHaavard Skinnemoen 				 * No legancy unlocking -> unlock all sectors
2017be60a902SHaavard Skinnemoen 				 */
2018be60a902SHaavard Skinnemoen 				flash_protect (FLAG_PROTECT_CLEAR,
2019be60a902SHaavard Skinnemoen 					       flash_info[i].start[0],
2020be60a902SHaavard Skinnemoen 					       flash_info[i].start[0]
2021be60a902SHaavard Skinnemoen 					       + flash_info[i].size - 1,
2022be60a902SHaavard Skinnemoen 					       &flash_info[i]);
202359829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
202459829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
2025*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FLASH_PROTECTION */
202659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
202759829cc1SJean-Christophe PLAGNIOL-VILLARD 
2028be60a902SHaavard Skinnemoen 	/* Monitor protection ON by default */
2029*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
2030be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
2031*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_SYS_MONITOR_BASE,
2032*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_SYS_MONITOR_BASE + monitor_flash_len  - 1,
2033*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CONFIG_SYS_MONITOR_BASE));
2034be60a902SHaavard Skinnemoen #endif
203559829cc1SJean-Christophe PLAGNIOL-VILLARD 
2036be60a902SHaavard Skinnemoen 	/* Environment protection ON by default */
20375a1aceb0SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_ENV_IS_IN_FLASH
2038be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
20390e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_ENV_ADDR,
20400e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
20410e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CONFIG_ENV_ADDR));
2042be60a902SHaavard Skinnemoen #endif
2043be60a902SHaavard Skinnemoen 
2044be60a902SHaavard Skinnemoen 	/* Redundant environment protection ON by default */
20450e8d1586SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_ENV_ADDR_REDUND
2046be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
20470e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_ENV_ADDR_REDUND,
20480e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SIZE_REDUND - 1,
20490e8d1586SJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CONFIG_ENV_ADDR_REDUND));
2050be60a902SHaavard Skinnemoen #endif
2051c63ad632SMatthias Fuchs 
2052*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
2053c63ad632SMatthias Fuchs 	for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
2054c63ad632SMatthias Fuchs 		debug("autoprotecting from %08x to %08x\n",
2055c63ad632SMatthias Fuchs 		      apl[i].start, apl[i].start + apl[i].size - 1);
2056c63ad632SMatthias Fuchs 		flash_protect (FLAG_PROTECT_SET,
2057c63ad632SMatthias Fuchs 			       apl[i].start,
2058c63ad632SMatthias Fuchs 			       apl[i].start + apl[i].size - 1,
2059c63ad632SMatthias Fuchs 			       flash_get_info(apl[i].start));
2060c63ad632SMatthias Fuchs 	}
2061c63ad632SMatthias Fuchs #endif
2062be60a902SHaavard Skinnemoen 	return (size);
206359829cc1SJean-Christophe PLAGNIOL-VILLARD }
2064