xref: /rk3399_rockchip-uboot/drivers/mtd/cfi_flash.c (revision 2a112b234d879f6390503a5f4e38246acce9d0b0)
159829cc1SJean-Christophe PLAGNIOL-VILLARD /*
259829cc1SJean-Christophe PLAGNIOL-VILLARD  * (C) Copyright 2002-2004
359829cc1SJean-Christophe PLAGNIOL-VILLARD  * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com
459829cc1SJean-Christophe PLAGNIOL-VILLARD  *
559829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copyright (C) 2003 Arabella Software Ltd.
659829cc1SJean-Christophe PLAGNIOL-VILLARD  * Yuli Barcohen <yuli@arabellasw.com>
759829cc1SJean-Christophe PLAGNIOL-VILLARD  *
859829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copyright (C) 2004
959829cc1SJean-Christophe PLAGNIOL-VILLARD  * Ed Okerson
1059829cc1SJean-Christophe PLAGNIOL-VILLARD  *
1159829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copyright (C) 2006
1259829cc1SJean-Christophe PLAGNIOL-VILLARD  * Tolunay Orkun <listmember@orkun.us>
1359829cc1SJean-Christophe PLAGNIOL-VILLARD  *
1459829cc1SJean-Christophe PLAGNIOL-VILLARD  * See file CREDITS for list of people who contributed to this
1559829cc1SJean-Christophe PLAGNIOL-VILLARD  * project.
1659829cc1SJean-Christophe PLAGNIOL-VILLARD  *
1759829cc1SJean-Christophe PLAGNIOL-VILLARD  * This program is free software; you can redistribute it and/or
1859829cc1SJean-Christophe PLAGNIOL-VILLARD  * modify it under the terms of the GNU General Public License as
1959829cc1SJean-Christophe PLAGNIOL-VILLARD  * published by the Free Software Foundation; either version 2 of
2059829cc1SJean-Christophe PLAGNIOL-VILLARD  * the License, or (at your option) any later version.
2159829cc1SJean-Christophe PLAGNIOL-VILLARD  *
2259829cc1SJean-Christophe PLAGNIOL-VILLARD  * This program is distributed in the hope that it will be useful,
2359829cc1SJean-Christophe PLAGNIOL-VILLARD  * but WITHOUT ANY WARRANTY; without even the implied warranty of
2459829cc1SJean-Christophe PLAGNIOL-VILLARD  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
2559829cc1SJean-Christophe PLAGNIOL-VILLARD  * GNU General Public License for more details.
2659829cc1SJean-Christophe PLAGNIOL-VILLARD  *
2759829cc1SJean-Christophe PLAGNIOL-VILLARD  * You should have received a copy of the GNU General Public License
2859829cc1SJean-Christophe PLAGNIOL-VILLARD  * along with this program; if not, write to the Free Software
2959829cc1SJean-Christophe PLAGNIOL-VILLARD  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
3059829cc1SJean-Christophe PLAGNIOL-VILLARD  * MA 02111-1307 USA
3159829cc1SJean-Christophe PLAGNIOL-VILLARD  *
3259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3359829cc1SJean-Christophe PLAGNIOL-VILLARD 
3459829cc1SJean-Christophe PLAGNIOL-VILLARD /* The DEBUG define must be before common to enable debugging */
3559829cc1SJean-Christophe PLAGNIOL-VILLARD /* #define DEBUG	*/
3659829cc1SJean-Christophe PLAGNIOL-VILLARD 
3759829cc1SJean-Christophe PLAGNIOL-VILLARD #include <common.h>
3859829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/processor.h>
3959829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h>
4059829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/byteorder.h>
4159829cc1SJean-Christophe PLAGNIOL-VILLARD #include <environment.h>
4259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef	CFG_FLASH_CFI_DRIVER
4359829cc1SJean-Christophe PLAGNIOL-VILLARD 
4459829cc1SJean-Christophe PLAGNIOL-VILLARD /*
457e5b9b47SHaavard Skinnemoen  * This file implements a Common Flash Interface (CFI) driver for
467e5b9b47SHaavard Skinnemoen  * U-Boot.
477e5b9b47SHaavard Skinnemoen  *
487e5b9b47SHaavard Skinnemoen  * The width of the port and the width of the chips are determined at
497e5b9b47SHaavard Skinnemoen  * initialization.  These widths are used to calculate the address for
507e5b9b47SHaavard Skinnemoen  * access CFI data structures.
5159829cc1SJean-Christophe PLAGNIOL-VILLARD  *
5259829cc1SJean-Christophe PLAGNIOL-VILLARD  * References
5359829cc1SJean-Christophe PLAGNIOL-VILLARD  * JEDEC Standard JESD68 - Common Flash Interface (CFI)
5459829cc1SJean-Christophe PLAGNIOL-VILLARD  * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
5559829cc1SJean-Christophe PLAGNIOL-VILLARD  * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
5659829cc1SJean-Christophe PLAGNIOL-VILLARD  * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
5759829cc1SJean-Christophe PLAGNIOL-VILLARD  * AMD CFI Specification, Release 2.0 December 1, 2001
5859829cc1SJean-Christophe PLAGNIOL-VILLARD  * AMD/Spansion Application Note: Migration from Single-byte to Three-byte
5959829cc1SJean-Christophe PLAGNIOL-VILLARD  *   Device IDs, Publication Number 25538 Revision A, November 8, 2001
6059829cc1SJean-Christophe PLAGNIOL-VILLARD  *
617e5b9b47SHaavard Skinnemoen  * Define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
6259829cc1SJean-Christophe PLAGNIOL-VILLARD  * reading and writing ... (yes there is such a Hardware).
6359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
6459829cc1SJean-Christophe PLAGNIOL-VILLARD 
6559829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_BANKS_LIST
6659829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE }
6759829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
6859829cc1SJean-Christophe PLAGNIOL-VILLARD 
6959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CFI			0x98
7059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_READ_ID		0x90
7159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_RESET			0xff
7259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_BLOCK_ERASE		0x20
7359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_ERASE_CONFIRM		0xD0
7459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE			0x40
7559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT		0x60
7659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_SET		0x01
7759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_CLEAR		0xD0
7859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CLEAR_STATUS		0x50
799c048b52SVasiliy Leoenenko #define FLASH_CMD_READ_STATUS		0x70
8059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_TO_BUFFER	0xE8
819c048b52SVasiliy Leoenenko #define FLASH_CMD_WRITE_BUFFER_PROG	0xE9
8259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_BUFFER_CONFIRM	0xD0
8359829cc1SJean-Christophe PLAGNIOL-VILLARD 
8459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DONE		0x80
8559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ESS		0x40
8659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ECLBS		0x20
8759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSLBS		0x10
8859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_VPENS		0x08
8959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSS		0x04
9059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DPS		0x02
9159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_R			0x01
9259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PROTECT		0x01
9359829cc1SJean-Christophe PLAGNIOL-VILLARD 
9459829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_RESET			0xF0
9559829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE			0xA0
9659829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_START		0x80
9759829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_SECTOR		0x30
9859829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_START		0xAA
9959829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_ACK		0x55
10059829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_TO_BUFFER		0x25
10159829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_BUFFER_CONFIRM	0x29
10259829cc1SJean-Christophe PLAGNIOL-VILLARD 
10359829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_TOGGLE		0x40
10459829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_ERROR		0x20
10559829cc1SJean-Christophe PLAGNIOL-VILLARD 
10659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_MANUFACTURER_ID	0x00
10759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID		0x01
10859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID2		0x0E
10959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID3		0x0F
11059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI		0x55
11159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_ALT		0x555
11259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_RESP		0x10
11359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PRIMARY_VENDOR	0x13
1147e5b9b47SHaavard Skinnemoen /* extended query table primary address */
1157e5b9b47SHaavard Skinnemoen #define FLASH_OFFSET_EXT_QUERY_T_P_ADDR	0x15
11659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WTOUT		0x1F
11759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBTOUT		0x20
11859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ETOUT		0x21
11959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CETOUT		0x22
12059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WMAX_TOUT		0x23
12159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBMAX_TOUT		0x24
12259829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EMAX_TOUT		0x25
12359829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CEMAX_TOUT		0x26
12459829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_SIZE		0x27
12559829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTERFACE		0x28
12659829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_BUFFER_SIZE	0x2A
12759829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_NUM_ERASE_REGIONS	0x2C
12859829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ERASE_REGIONS	0x2D
12959829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PROTECT		0x02
13059829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_USER_PROTECTION	0x85
13159829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTEL_PROTECTION	0x81
13259829cc1SJean-Christophe PLAGNIOL-VILLARD 
13359829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_NONE			0
13459829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_EXTENDED	1
13559829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_STANDARD		2
13659829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_STANDARD	3
13759829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_EXTENDED		4
13859829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_STANDARD	256
13959829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_EXTENDED	257
14059829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_SST			258
1419c048b52SVasiliy Leoenenko #define CFI_CMDSET_INTEL_PROG_REGIONS	512
14259829cc1SJean-Christophe PLAGNIOL-VILLARD 
14359829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
14459829cc1SJean-Christophe PLAGNIOL-VILLARD # undef  FLASH_CMD_RESET
14559829cc1SJean-Christophe PLAGNIOL-VILLARD # define FLASH_CMD_RESET	AMD_CMD_RESET /* use AMD-Reset instead */
14659829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
14759829cc1SJean-Christophe PLAGNIOL-VILLARD 
14859829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union {
14959829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned char c;
15059829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned short w;
15159829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long l;
15259829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long long ll;
15359829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiword_t;
15459829cc1SJean-Christophe PLAGNIOL-VILLARD 
15559829cc1SJean-Christophe PLAGNIOL-VILLARD #define NUM_ERASE_REGIONS	4 /* max. number of erase regions */
15659829cc1SJean-Christophe PLAGNIOL-VILLARD 
15759829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
15859829cc1SJean-Christophe PLAGNIOL-VILLARD 
15959829cc1SJean-Christophe PLAGNIOL-VILLARD /* use CFG_MAX_FLASH_BANKS_DETECT if defined */
16059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_MAX_FLASH_BANKS_DETECT
161*2a112b23SWolfgang Denk # define CFI_MAX_FLASH_BANKS	CFG_MAX_FLASH_BANKS_DETECT
16259829cc1SJean-Christophe PLAGNIOL-VILLARD #else
163*2a112b23SWolfgang Denk # define CFI_MAX_FLASH_BANKS	CFG_MAX_FLASH_BANKS
16459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
16559829cc1SJean-Christophe PLAGNIOL-VILLARD 
166*2a112b23SWolfgang Denk flash_info_t flash_info[CFI_MAX_FLASH_BANKS];	/* FLASH chips info */
167*2a112b23SWolfgang Denk 
16859829cc1SJean-Christophe PLAGNIOL-VILLARD /*
16959829cc1SJean-Christophe PLAGNIOL-VILLARD  * Check if chip width is defined. If not, start detecting with 8bit.
17059829cc1SJean-Christophe PLAGNIOL-VILLARD  */
17159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_CFI_WIDTH
17259829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_CFI_WIDTH	FLASH_CFI_8BIT
17359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
17459829cc1SJean-Christophe PLAGNIOL-VILLARD 
17559829cc1SJean-Christophe PLAGNIOL-VILLARD typedef unsigned long flash_sect_t;
17659829cc1SJean-Christophe PLAGNIOL-VILLARD 
177e23741f4SHaavard Skinnemoen /* CFI standard query structure */
178e23741f4SHaavard Skinnemoen struct cfi_qry {
179e23741f4SHaavard Skinnemoen 	u8	qry[3];
180e23741f4SHaavard Skinnemoen 	u16	p_id;
181e23741f4SHaavard Skinnemoen 	u16	p_adr;
182e23741f4SHaavard Skinnemoen 	u16	a_id;
183e23741f4SHaavard Skinnemoen 	u16	a_adr;
184e23741f4SHaavard Skinnemoen 	u8	vcc_min;
185e23741f4SHaavard Skinnemoen 	u8	vcc_max;
186e23741f4SHaavard Skinnemoen 	u8	vpp_min;
187e23741f4SHaavard Skinnemoen 	u8	vpp_max;
188e23741f4SHaavard Skinnemoen 	u8	word_write_timeout_typ;
189e23741f4SHaavard Skinnemoen 	u8	buf_write_timeout_typ;
190e23741f4SHaavard Skinnemoen 	u8	block_erase_timeout_typ;
191e23741f4SHaavard Skinnemoen 	u8	chip_erase_timeout_typ;
192e23741f4SHaavard Skinnemoen 	u8	word_write_timeout_max;
193e23741f4SHaavard Skinnemoen 	u8	buf_write_timeout_max;
194e23741f4SHaavard Skinnemoen 	u8	block_erase_timeout_max;
195e23741f4SHaavard Skinnemoen 	u8	chip_erase_timeout_max;
196e23741f4SHaavard Skinnemoen 	u8	dev_size;
197e23741f4SHaavard Skinnemoen 	u16	interface_desc;
198e23741f4SHaavard Skinnemoen 	u16	max_buf_write_size;
199e23741f4SHaavard Skinnemoen 	u8	num_erase_regions;
200e23741f4SHaavard Skinnemoen 	u32	erase_region_info[NUM_ERASE_REGIONS];
201e23741f4SHaavard Skinnemoen } __attribute__((packed));
202e23741f4SHaavard Skinnemoen 
203e23741f4SHaavard Skinnemoen struct cfi_pri_hdr {
204e23741f4SHaavard Skinnemoen 	u8	pri[3];
205e23741f4SHaavard Skinnemoen 	u8	major_version;
206e23741f4SHaavard Skinnemoen 	u8	minor_version;
207e23741f4SHaavard Skinnemoen } __attribute__((packed));
208e23741f4SHaavard Skinnemoen 
209cdbaefb5SHaavard Skinnemoen static void flash_write8(u8 value, void *addr)
210cdbaefb5SHaavard Skinnemoen {
211cdbaefb5SHaavard Skinnemoen 	__raw_writeb(value, addr);
212cdbaefb5SHaavard Skinnemoen }
213cdbaefb5SHaavard Skinnemoen 
214cdbaefb5SHaavard Skinnemoen static void flash_write16(u16 value, void *addr)
215cdbaefb5SHaavard Skinnemoen {
216cdbaefb5SHaavard Skinnemoen 	__raw_writew(value, addr);
217cdbaefb5SHaavard Skinnemoen }
218cdbaefb5SHaavard Skinnemoen 
219cdbaefb5SHaavard Skinnemoen static void flash_write32(u32 value, void *addr)
220cdbaefb5SHaavard Skinnemoen {
221cdbaefb5SHaavard Skinnemoen 	__raw_writel(value, addr);
222cdbaefb5SHaavard Skinnemoen }
223cdbaefb5SHaavard Skinnemoen 
224cdbaefb5SHaavard Skinnemoen static void flash_write64(u64 value, void *addr)
225cdbaefb5SHaavard Skinnemoen {
226cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_writeq() */
227cdbaefb5SHaavard Skinnemoen 	*(volatile u64 *)addr = value;
228cdbaefb5SHaavard Skinnemoen }
229cdbaefb5SHaavard Skinnemoen 
230cdbaefb5SHaavard Skinnemoen static u8 flash_read8(void *addr)
231cdbaefb5SHaavard Skinnemoen {
232cdbaefb5SHaavard Skinnemoen 	return __raw_readb(addr);
233cdbaefb5SHaavard Skinnemoen }
234cdbaefb5SHaavard Skinnemoen 
235cdbaefb5SHaavard Skinnemoen static u16 flash_read16(void *addr)
236cdbaefb5SHaavard Skinnemoen {
237cdbaefb5SHaavard Skinnemoen 	return __raw_readw(addr);
238cdbaefb5SHaavard Skinnemoen }
239cdbaefb5SHaavard Skinnemoen 
240cdbaefb5SHaavard Skinnemoen static u32 flash_read32(void *addr)
241cdbaefb5SHaavard Skinnemoen {
242cdbaefb5SHaavard Skinnemoen 	return __raw_readl(addr);
243cdbaefb5SHaavard Skinnemoen }
244cdbaefb5SHaavard Skinnemoen 
24597bf85d7SDaniel Hellstrom static u64 __flash_read64(void *addr)
246cdbaefb5SHaavard Skinnemoen {
247cdbaefb5SHaavard Skinnemoen 	/* No architectures currently implement __raw_readq() */
248cdbaefb5SHaavard Skinnemoen 	return *(volatile u64 *)addr;
249cdbaefb5SHaavard Skinnemoen }
250cdbaefb5SHaavard Skinnemoen 
25197bf85d7SDaniel Hellstrom u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
25297bf85d7SDaniel Hellstrom 
253be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
254be60a902SHaavard Skinnemoen  */
25559829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
256be60a902SHaavard Skinnemoen static flash_info_t *flash_get_info(ulong base)
257be60a902SHaavard Skinnemoen {
258be60a902SHaavard Skinnemoen 	int i;
259be60a902SHaavard Skinnemoen 	flash_info_t * info = 0;
260be60a902SHaavard Skinnemoen 
261be60a902SHaavard Skinnemoen 	for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
262be60a902SHaavard Skinnemoen 		info = & flash_info[i];
263be60a902SHaavard Skinnemoen 		if (info->size && info->start[0] <= base &&
264be60a902SHaavard Skinnemoen 		    base <= info->start[0] + info->size - 1)
265be60a902SHaavard Skinnemoen 			break;
266be60a902SHaavard Skinnemoen 	}
267be60a902SHaavard Skinnemoen 
268be60a902SHaavard Skinnemoen 	return i == CFG_MAX_FLASH_BANKS ? 0 : info;
269be60a902SHaavard Skinnemoen }
27059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
27159829cc1SJean-Christophe PLAGNIOL-VILLARD 
27212d30aa7SHaavard Skinnemoen unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
27312d30aa7SHaavard Skinnemoen {
27412d30aa7SHaavard Skinnemoen 	if (sect != (info->sector_count - 1))
27512d30aa7SHaavard Skinnemoen 		return info->start[sect + 1] - info->start[sect];
27612d30aa7SHaavard Skinnemoen 	else
27712d30aa7SHaavard Skinnemoen 		return info->start[0] + info->size - info->start[sect];
27812d30aa7SHaavard Skinnemoen }
27912d30aa7SHaavard Skinnemoen 
28059829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
28159829cc1SJean-Christophe PLAGNIOL-VILLARD  * create an address based on the offset and the port width
28259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
28312d30aa7SHaavard Skinnemoen static inline void *
28412d30aa7SHaavard Skinnemoen flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
28559829cc1SJean-Christophe PLAGNIOL-VILLARD {
28612d30aa7SHaavard Skinnemoen 	unsigned int byte_offset = offset * info->portwidth;
28712d30aa7SHaavard Skinnemoen 
28812d30aa7SHaavard Skinnemoen 	return map_physmem(info->start[sect] + byte_offset,
28912d30aa7SHaavard Skinnemoen 			flash_sector_size(info, sect) - byte_offset,
29012d30aa7SHaavard Skinnemoen 			MAP_NOCACHE);
29112d30aa7SHaavard Skinnemoen }
29212d30aa7SHaavard Skinnemoen 
29312d30aa7SHaavard Skinnemoen static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
29412d30aa7SHaavard Skinnemoen 		unsigned int offset, void *addr)
29512d30aa7SHaavard Skinnemoen {
29612d30aa7SHaavard Skinnemoen 	unsigned int byte_offset = offset * info->portwidth;
29712d30aa7SHaavard Skinnemoen 
29812d30aa7SHaavard Skinnemoen 	unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset);
29959829cc1SJean-Christophe PLAGNIOL-VILLARD }
30059829cc1SJean-Christophe PLAGNIOL-VILLARD 
301be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
302be60a902SHaavard Skinnemoen  * make a proper sized command based on the port and chip widths
303be60a902SHaavard Skinnemoen  */
3047288f972SSebastian Siewior static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
305be60a902SHaavard Skinnemoen {
306be60a902SHaavard Skinnemoen 	int i;
30793c56f21SVasiliy Leoenenko 	int cword_offset;
30893c56f21SVasiliy Leoenenko 	int cp_offset;
309340ccb26SSebastian Siewior #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
310340ccb26SSebastian Siewior 	u32 cmd_le = cpu_to_le32(cmd);
311340ccb26SSebastian Siewior #endif
31293c56f21SVasiliy Leoenenko 	uchar val;
313be60a902SHaavard Skinnemoen 	uchar *cp = (uchar *) cmdbuf;
314be60a902SHaavard Skinnemoen 
31593c56f21SVasiliy Leoenenko 	for (i = info->portwidth; i > 0; i--){
31693c56f21SVasiliy Leoenenko 		cword_offset = (info->portwidth-i)%info->chipwidth;
317be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
31893c56f21SVasiliy Leoenenko 		cp_offset = info->portwidth - i;
319340ccb26SSebastian Siewior 		val = *((uchar*)&cmd_le + cword_offset);
320be60a902SHaavard Skinnemoen #else
32193c56f21SVasiliy Leoenenko 		cp_offset = i - 1;
3227288f972SSebastian Siewior 		val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1);
323be60a902SHaavard Skinnemoen #endif
3247288f972SSebastian Siewior 		cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
32593c56f21SVasiliy Leoenenko 	}
326be60a902SHaavard Skinnemoen }
327be60a902SHaavard Skinnemoen 
32859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
32959829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
33059829cc1SJean-Christophe PLAGNIOL-VILLARD  * Debug support
33159829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3323055793bSHaavard Skinnemoen static void print_longlong (char *str, unsigned long long data)
33359829cc1SJean-Christophe PLAGNIOL-VILLARD {
33459829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
33559829cc1SJean-Christophe PLAGNIOL-VILLARD 	char *cp;
33659829cc1SJean-Christophe PLAGNIOL-VILLARD 
33759829cc1SJean-Christophe PLAGNIOL-VILLARD 	cp = (unsigned char *) &data;
33859829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 8; i++)
33959829cc1SJean-Christophe PLAGNIOL-VILLARD 		sprintf (&str[i * 2], "%2.2x", *cp++);
34059829cc1SJean-Christophe PLAGNIOL-VILLARD }
341be60a902SHaavard Skinnemoen 
342e23741f4SHaavard Skinnemoen static void flash_printqry (struct cfi_qry *qry)
34359829cc1SJean-Christophe PLAGNIOL-VILLARD {
344e23741f4SHaavard Skinnemoen 	u8 *p = (u8 *)qry;
34559829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x, y;
34659829cc1SJean-Christophe PLAGNIOL-VILLARD 
347e23741f4SHaavard Skinnemoen 	for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
348e23741f4SHaavard Skinnemoen 		debug("%02x : ", x);
349e23741f4SHaavard Skinnemoen 		for (y = 0; y < 16; y++)
350e23741f4SHaavard Skinnemoen 			debug("%2.2x ", p[x + y]);
35159829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug(" ");
35259829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (y = 0; y < 16; y++) {
353e23741f4SHaavard Skinnemoen 			unsigned char c = p[x + y];
354e23741f4SHaavard Skinnemoen 			if (c >= 0x20 && c <= 0x7e)
355cdbaefb5SHaavard Skinnemoen 				debug("%c", c);
356e23741f4SHaavard Skinnemoen 			else
35759829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug(".");
35859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
35959829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug("\n");
36059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
36159829cc1SJean-Christophe PLAGNIOL-VILLARD }
36259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
36359829cc1SJean-Christophe PLAGNIOL-VILLARD 
36459829cc1SJean-Christophe PLAGNIOL-VILLARD 
36559829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
36659829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a character at a port width address
36759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
3683055793bSHaavard Skinnemoen static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
36959829cc1SJean-Christophe PLAGNIOL-VILLARD {
37059829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *cp;
37112d30aa7SHaavard Skinnemoen 	uchar retval;
37259829cc1SJean-Christophe PLAGNIOL-VILLARD 
37312d30aa7SHaavard Skinnemoen 	cp = flash_map (info, 0, offset);
37459829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
37512d30aa7SHaavard Skinnemoen 	retval = flash_read8(cp);
37659829cc1SJean-Christophe PLAGNIOL-VILLARD #else
37712d30aa7SHaavard Skinnemoen 	retval = flash_read8(cp + info->portwidth - 1);
37859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
37912d30aa7SHaavard Skinnemoen 	flash_unmap (info, 0, offset, cp);
38012d30aa7SHaavard Skinnemoen 	return retval;
38159829cc1SJean-Christophe PLAGNIOL-VILLARD }
38259829cc1SJean-Christophe PLAGNIOL-VILLARD 
38359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
38490447ecbSTor Krill  * read a word at a port width address, assume 16bit bus
38590447ecbSTor Krill  */
38690447ecbSTor Krill static inline ushort flash_read_word (flash_info_t * info, uint offset)
38790447ecbSTor Krill {
38890447ecbSTor Krill 	ushort *addr, retval;
38990447ecbSTor Krill 
39090447ecbSTor Krill 	addr = flash_map (info, 0, offset);
39190447ecbSTor Krill 	retval = flash_read16 (addr);
39290447ecbSTor Krill 	flash_unmap (info, 0, offset, addr);
39390447ecbSTor Krill 	return retval;
39490447ecbSTor Krill }
39590447ecbSTor Krill 
39690447ecbSTor Krill 
39790447ecbSTor Krill /*-----------------------------------------------------------------------
39859829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a long word by picking the least significant byte of each maximum
39959829cc1SJean-Christophe PLAGNIOL-VILLARD  * port size word. Swap for ppc format.
40059829cc1SJean-Christophe PLAGNIOL-VILLARD  */
4013055793bSHaavard Skinnemoen static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
4023055793bSHaavard Skinnemoen 			      uint offset)
40359829cc1SJean-Christophe PLAGNIOL-VILLARD {
40459829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *addr;
40559829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong retval;
40659829cc1SJean-Christophe PLAGNIOL-VILLARD 
40759829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
40859829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x;
40959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
41012d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
41159829cc1SJean-Christophe PLAGNIOL-VILLARD 
41259829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
41359829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("long addr is at %p info->portwidth = %d\n", addr,
41459829cc1SJean-Christophe PLAGNIOL-VILLARD 	       info->portwidth);
41559829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (x = 0; x < 4 * info->portwidth; x++) {
41612d30aa7SHaavard Skinnemoen 		debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
41759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
41859829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
41959829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
42012d30aa7SHaavard Skinnemoen 	retval = ((flash_read8(addr) << 16) |
42112d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + info->portwidth) << 24) |
42212d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 2 * info->portwidth)) |
42312d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 3 * info->portwidth) << 8));
42459829cc1SJean-Christophe PLAGNIOL-VILLARD #else
42512d30aa7SHaavard Skinnemoen 	retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
42612d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + info->portwidth - 1) << 16) |
42712d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
42812d30aa7SHaavard Skinnemoen 		  (flash_read8(addr + 3 * info->portwidth - 1)));
42959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
43012d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
43112d30aa7SHaavard Skinnemoen 
43259829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
43359829cc1SJean-Christophe PLAGNIOL-VILLARD }
43459829cc1SJean-Christophe PLAGNIOL-VILLARD 
435be60a902SHaavard Skinnemoen /*
436be60a902SHaavard Skinnemoen  * Write a proper sized command to the correct address
43781b20cccSMichael Schwingen  */
438be60a902SHaavard Skinnemoen static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
4397288f972SSebastian Siewior 			     uint offset, u32 cmd)
44081b20cccSMichael Schwingen {
4417e5b9b47SHaavard Skinnemoen 
442cdbaefb5SHaavard Skinnemoen 	void *addr;
443be60a902SHaavard Skinnemoen 	cfiword_t cword;
44481b20cccSMichael Schwingen 
44512d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
446be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
447be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
448be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
449cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
450be60a902SHaavard Skinnemoen 		       cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
451cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, addr);
452be60a902SHaavard Skinnemoen 		break;
453be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
454cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
455be60a902SHaavard Skinnemoen 		       cmd, cword.w,
456be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
457cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, addr);
458be60a902SHaavard Skinnemoen 		break;
459be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
460cdbaefb5SHaavard Skinnemoen 		debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
461be60a902SHaavard Skinnemoen 		       cmd, cword.l,
462be60a902SHaavard Skinnemoen 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
463cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, addr);
464be60a902SHaavard Skinnemoen 		break;
465be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
466be60a902SHaavard Skinnemoen #ifdef DEBUG
467be60a902SHaavard Skinnemoen 		{
468be60a902SHaavard Skinnemoen 			char str[20];
469be60a902SHaavard Skinnemoen 
470be60a902SHaavard Skinnemoen 			print_longlong (str, cword.ll);
471be60a902SHaavard Skinnemoen 
472be60a902SHaavard Skinnemoen 			debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
473cdbaefb5SHaavard Skinnemoen 			       addr, cmd, str,
474be60a902SHaavard Skinnemoen 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
47581b20cccSMichael Schwingen 		}
476be60a902SHaavard Skinnemoen #endif
477cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, addr);
47881b20cccSMichael Schwingen 		break;
47981b20cccSMichael Schwingen 	}
480be60a902SHaavard Skinnemoen 
481be60a902SHaavard Skinnemoen 	/* Ensure all the instructions are fully finished */
482be60a902SHaavard Skinnemoen 	sync();
48312d30aa7SHaavard Skinnemoen 
48412d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
48581b20cccSMichael Schwingen }
4867e5b9b47SHaavard Skinnemoen 
487be60a902SHaavard Skinnemoen static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
488be60a902SHaavard Skinnemoen {
489be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
490be60a902SHaavard Skinnemoen 	flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
491be60a902SHaavard Skinnemoen }
492be60a902SHaavard Skinnemoen 
493be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
494be60a902SHaavard Skinnemoen  */
495be60a902SHaavard Skinnemoen static int flash_isequal (flash_info_t * info, flash_sect_t sect,
496be60a902SHaavard Skinnemoen 			  uint offset, uchar cmd)
497be60a902SHaavard Skinnemoen {
498cdbaefb5SHaavard Skinnemoen 	void *addr;
499be60a902SHaavard Skinnemoen 	cfiword_t cword;
500be60a902SHaavard Skinnemoen 	int retval;
501be60a902SHaavard Skinnemoen 
50212d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
503be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
504be60a902SHaavard Skinnemoen 
505cdbaefb5SHaavard Skinnemoen 	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
506be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
507be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
508cdbaefb5SHaavard Skinnemoen 		debug ("is= %x %x\n", flash_read8(addr), cword.c);
509cdbaefb5SHaavard Skinnemoen 		retval = (flash_read8(addr) == cword.c);
510be60a902SHaavard Skinnemoen 		break;
511be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
512cdbaefb5SHaavard Skinnemoen 		debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
513cdbaefb5SHaavard Skinnemoen 		retval = (flash_read16(addr) == cword.w);
514be60a902SHaavard Skinnemoen 		break;
515be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
516cdbaefb5SHaavard Skinnemoen 		debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
517cdbaefb5SHaavard Skinnemoen 		retval = (flash_read32(addr) == cword.l);
518be60a902SHaavard Skinnemoen 		break;
519be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
520be60a902SHaavard Skinnemoen #ifdef DEBUG
521be60a902SHaavard Skinnemoen 		{
522be60a902SHaavard Skinnemoen 			char str1[20];
523be60a902SHaavard Skinnemoen 			char str2[20];
524be60a902SHaavard Skinnemoen 
525cdbaefb5SHaavard Skinnemoen 			print_longlong (str1, flash_read64(addr));
526be60a902SHaavard Skinnemoen 			print_longlong (str2, cword.ll);
527be60a902SHaavard Skinnemoen 			debug ("is= %s %s\n", str1, str2);
528be60a902SHaavard Skinnemoen 		}
529be60a902SHaavard Skinnemoen #endif
530cdbaefb5SHaavard Skinnemoen 		retval = (flash_read64(addr) == cword.ll);
531be60a902SHaavard Skinnemoen 		break;
532be60a902SHaavard Skinnemoen 	default:
533be60a902SHaavard Skinnemoen 		retval = 0;
534be60a902SHaavard Skinnemoen 		break;
535be60a902SHaavard Skinnemoen 	}
53612d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
53712d30aa7SHaavard Skinnemoen 
538be60a902SHaavard Skinnemoen 	return retval;
539be60a902SHaavard Skinnemoen }
540be60a902SHaavard Skinnemoen 
541be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
542be60a902SHaavard Skinnemoen  */
543be60a902SHaavard Skinnemoen static int flash_isset (flash_info_t * info, flash_sect_t sect,
544be60a902SHaavard Skinnemoen 			uint offset, uchar cmd)
545be60a902SHaavard Skinnemoen {
546cdbaefb5SHaavard Skinnemoen 	void *addr;
547be60a902SHaavard Skinnemoen 	cfiword_t cword;
548be60a902SHaavard Skinnemoen 	int retval;
549be60a902SHaavard Skinnemoen 
55012d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
551be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
552be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
553be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
554cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read8(addr) & cword.c) == cword.c);
555be60a902SHaavard Skinnemoen 		break;
556be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
557cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read16(addr) & cword.w) == cword.w);
558be60a902SHaavard Skinnemoen 		break;
559be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
56047cc23cbSStefan Roese 		retval = ((flash_read32(addr) & cword.l) == cword.l);
561be60a902SHaavard Skinnemoen 		break;
562be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
563cdbaefb5SHaavard Skinnemoen 		retval = ((flash_read64(addr) & cword.ll) == cword.ll);
564be60a902SHaavard Skinnemoen 		break;
565be60a902SHaavard Skinnemoen 	default:
566be60a902SHaavard Skinnemoen 		retval = 0;
567be60a902SHaavard Skinnemoen 		break;
568be60a902SHaavard Skinnemoen 	}
56912d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
57012d30aa7SHaavard Skinnemoen 
571be60a902SHaavard Skinnemoen 	return retval;
572be60a902SHaavard Skinnemoen }
573be60a902SHaavard Skinnemoen 
574be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
575be60a902SHaavard Skinnemoen  */
576be60a902SHaavard Skinnemoen static int flash_toggle (flash_info_t * info, flash_sect_t sect,
577be60a902SHaavard Skinnemoen 			 uint offset, uchar cmd)
578be60a902SHaavard Skinnemoen {
579cdbaefb5SHaavard Skinnemoen 	void *addr;
580be60a902SHaavard Skinnemoen 	cfiword_t cword;
581be60a902SHaavard Skinnemoen 	int retval;
582be60a902SHaavard Skinnemoen 
58312d30aa7SHaavard Skinnemoen 	addr = flash_map (info, sect, offset);
584be60a902SHaavard Skinnemoen 	flash_make_cmd (info, cmd, &cword);
585be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
586be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
587fb8c061eSStefan Roese 		retval = flash_read8(addr) != flash_read8(addr);
588be60a902SHaavard Skinnemoen 		break;
589be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
590fb8c061eSStefan Roese 		retval = flash_read16(addr) != flash_read16(addr);
591be60a902SHaavard Skinnemoen 		break;
592be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
593fb8c061eSStefan Roese 		retval = flash_read32(addr) != flash_read32(addr);
594be60a902SHaavard Skinnemoen 		break;
595be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
596fb8c061eSStefan Roese 		retval = flash_read64(addr) != flash_read64(addr);
597be60a902SHaavard Skinnemoen 		break;
598be60a902SHaavard Skinnemoen 	default:
599be60a902SHaavard Skinnemoen 		retval = 0;
600be60a902SHaavard Skinnemoen 		break;
601be60a902SHaavard Skinnemoen 	}
60212d30aa7SHaavard Skinnemoen 	flash_unmap(info, sect, offset, addr);
60312d30aa7SHaavard Skinnemoen 
604be60a902SHaavard Skinnemoen 	return retval;
605be60a902SHaavard Skinnemoen }
606be60a902SHaavard Skinnemoen 
607be60a902SHaavard Skinnemoen /*
608be60a902SHaavard Skinnemoen  * flash_is_busy - check to see if the flash is busy
609be60a902SHaavard Skinnemoen  *
610be60a902SHaavard Skinnemoen  * This routine checks the status of the chip and returns true if the
611be60a902SHaavard Skinnemoen  * chip is busy.
612be60a902SHaavard Skinnemoen  */
613be60a902SHaavard Skinnemoen static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
614be60a902SHaavard Skinnemoen {
615be60a902SHaavard Skinnemoen 	int retval;
616be60a902SHaavard Skinnemoen 
61781b20cccSMichael Schwingen 	switch (info->vendor) {
6189c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
61981b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_STANDARD:
62081b20cccSMichael Schwingen 	case CFI_CMDSET_INTEL_EXTENDED:
621be60a902SHaavard Skinnemoen 		retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
62281b20cccSMichael Schwingen 		break;
62381b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_STANDARD:
62481b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_EXTENDED:
625be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
62681b20cccSMichael Schwingen 	case CFI_CMDSET_AMD_LEGACY:
627be60a902SHaavard Skinnemoen #endif
628be60a902SHaavard Skinnemoen 		retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
629be60a902SHaavard Skinnemoen 		break;
630be60a902SHaavard Skinnemoen 	default:
631be60a902SHaavard Skinnemoen 		retval = 0;
632be60a902SHaavard Skinnemoen 	}
633be60a902SHaavard Skinnemoen 	debug ("flash_is_busy: %d\n", retval);
634be60a902SHaavard Skinnemoen 	return retval;
635be60a902SHaavard Skinnemoen }
636be60a902SHaavard Skinnemoen 
637be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
638be60a902SHaavard Skinnemoen  *  wait for XSR.7 to be set. Time out with an error if it does not.
639be60a902SHaavard Skinnemoen  *  This routine does not set the flash to read-array mode.
640be60a902SHaavard Skinnemoen  */
641be60a902SHaavard Skinnemoen static int flash_status_check (flash_info_t * info, flash_sect_t sector,
642be60a902SHaavard Skinnemoen 			       ulong tout, char *prompt)
643be60a902SHaavard Skinnemoen {
644be60a902SHaavard Skinnemoen 	ulong start;
645be60a902SHaavard Skinnemoen 
646be60a902SHaavard Skinnemoen #if CFG_HZ != 1000
647be60a902SHaavard Skinnemoen 	tout *= CFG_HZ/1000;
648be60a902SHaavard Skinnemoen #endif
649be60a902SHaavard Skinnemoen 
650be60a902SHaavard Skinnemoen 	/* Wait for command completion */
651be60a902SHaavard Skinnemoen 	start = get_timer (0);
652be60a902SHaavard Skinnemoen 	while (flash_is_busy (info, sector)) {
653be60a902SHaavard Skinnemoen 		if (get_timer (start) > tout) {
654be60a902SHaavard Skinnemoen 			printf ("Flash %s timeout at address %lx data %lx\n",
655be60a902SHaavard Skinnemoen 				prompt, info->start[sector],
656be60a902SHaavard Skinnemoen 				flash_read_long (info, sector, 0));
657be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0, info->cmd_reset);
658be60a902SHaavard Skinnemoen 			return ERR_TIMOUT;
659be60a902SHaavard Skinnemoen 		}
660be60a902SHaavard Skinnemoen 		udelay (1);		/* also triggers watchdog */
661be60a902SHaavard Skinnemoen 	}
662be60a902SHaavard Skinnemoen 	return ERR_OK;
663be60a902SHaavard Skinnemoen }
664be60a902SHaavard Skinnemoen 
665be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
666be60a902SHaavard Skinnemoen  * Wait for XSR.7 to be set, if it times out print an error, otherwise
667be60a902SHaavard Skinnemoen  * do a full status check.
668be60a902SHaavard Skinnemoen  *
669be60a902SHaavard Skinnemoen  * This routine sets the flash to read-array mode.
670be60a902SHaavard Skinnemoen  */
671be60a902SHaavard Skinnemoen static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
672be60a902SHaavard Skinnemoen 				    ulong tout, char *prompt)
673be60a902SHaavard Skinnemoen {
674be60a902SHaavard Skinnemoen 	int retcode;
675be60a902SHaavard Skinnemoen 
676be60a902SHaavard Skinnemoen 	retcode = flash_status_check (info, sector, tout, prompt);
677be60a902SHaavard Skinnemoen 	switch (info->vendor) {
6789c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
679be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
680be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
681be60a902SHaavard Skinnemoen 		if ((retcode == ERR_OK)
682be60a902SHaavard Skinnemoen 		    && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
683be60a902SHaavard Skinnemoen 			retcode = ERR_INVAL;
684be60a902SHaavard Skinnemoen 			printf ("Flash %s error at address %lx\n", prompt,
685be60a902SHaavard Skinnemoen 				info->start[sector]);
686be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
687be60a902SHaavard Skinnemoen 					 FLASH_STATUS_PSLBS)) {
688be60a902SHaavard Skinnemoen 				puts ("Command Sequence Error.\n");
689be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
690be60a902SHaavard Skinnemoen 						FLASH_STATUS_ECLBS)) {
691be60a902SHaavard Skinnemoen 				puts ("Block Erase Error.\n");
692be60a902SHaavard Skinnemoen 				retcode = ERR_NOT_ERASED;
693be60a902SHaavard Skinnemoen 			} else if (flash_isset (info, sector, 0,
694be60a902SHaavard Skinnemoen 						FLASH_STATUS_PSLBS)) {
695be60a902SHaavard Skinnemoen 				puts ("Locking Error\n");
696be60a902SHaavard Skinnemoen 			}
697be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
698be60a902SHaavard Skinnemoen 				puts ("Block locked.\n");
699be60a902SHaavard Skinnemoen 				retcode = ERR_PROTECTED;
700be60a902SHaavard Skinnemoen 			}
701be60a902SHaavard Skinnemoen 			if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
702be60a902SHaavard Skinnemoen 				puts ("Vpp Low Error.\n");
703be60a902SHaavard Skinnemoen 		}
704be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, info->cmd_reset);
705be60a902SHaavard Skinnemoen 		break;
706be60a902SHaavard Skinnemoen 	default:
70781b20cccSMichael Schwingen 		break;
70881b20cccSMichael Schwingen 	}
709be60a902SHaavard Skinnemoen 	return retcode;
71081b20cccSMichael Schwingen }
711be60a902SHaavard Skinnemoen 
712be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
713be60a902SHaavard Skinnemoen  */
714be60a902SHaavard Skinnemoen static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
715be60a902SHaavard Skinnemoen {
716be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
717be60a902SHaavard Skinnemoen 	unsigned short	w;
718be60a902SHaavard Skinnemoen 	unsigned int	l;
719be60a902SHaavard Skinnemoen 	unsigned long long ll;
720be60a902SHaavard Skinnemoen #endif
721be60a902SHaavard Skinnemoen 
722be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
723be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
724be60a902SHaavard Skinnemoen 		cword->c = c;
725be60a902SHaavard Skinnemoen 		break;
726be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
727be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
728be60a902SHaavard Skinnemoen 		w = c;
729be60a902SHaavard Skinnemoen 		w <<= 8;
730be60a902SHaavard Skinnemoen 		cword->w = (cword->w >> 8) | w;
73181b20cccSMichael Schwingen #else
732be60a902SHaavard Skinnemoen 		cword->w = (cword->w << 8) | c;
733be60a902SHaavard Skinnemoen #endif
734be60a902SHaavard Skinnemoen 		break;
735be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
736be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
737be60a902SHaavard Skinnemoen 		l = c;
738be60a902SHaavard Skinnemoen 		l <<= 24;
739be60a902SHaavard Skinnemoen 		cword->l = (cword->l >> 8) | l;
740be60a902SHaavard Skinnemoen #else
741be60a902SHaavard Skinnemoen 		cword->l = (cword->l << 8) | c;
742be60a902SHaavard Skinnemoen #endif
743be60a902SHaavard Skinnemoen 		break;
744be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
745be60a902SHaavard Skinnemoen #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
746be60a902SHaavard Skinnemoen 		ll = c;
747be60a902SHaavard Skinnemoen 		ll <<= 56;
748be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll >> 8) | ll;
749be60a902SHaavard Skinnemoen #else
750be60a902SHaavard Skinnemoen 		cword->ll = (cword->ll << 8) | c;
751be60a902SHaavard Skinnemoen #endif
752be60a902SHaavard Skinnemoen 		break;
753be60a902SHaavard Skinnemoen 	}
754be60a902SHaavard Skinnemoen }
755be60a902SHaavard Skinnemoen 
756be60a902SHaavard Skinnemoen /* loop through the sectors from the highest address when the passed
757be60a902SHaavard Skinnemoen  * address is greater or equal to the sector address we have a match
758be60a902SHaavard Skinnemoen  */
759be60a902SHaavard Skinnemoen static flash_sect_t find_sector (flash_info_t * info, ulong addr)
76081b20cccSMichael Schwingen {
761be60a902SHaavard Skinnemoen 	flash_sect_t sector;
762be60a902SHaavard Skinnemoen 
763be60a902SHaavard Skinnemoen 	for (sector = info->sector_count - 1; sector >= 0; sector--) {
764be60a902SHaavard Skinnemoen 		if (addr >= info->start[sector])
765be60a902SHaavard Skinnemoen 			break;
76681b20cccSMichael Schwingen 	}
767be60a902SHaavard Skinnemoen 	return sector;
76859829cc1SJean-Christophe PLAGNIOL-VILLARD }
76959829cc1SJean-Christophe PLAGNIOL-VILLARD 
77059829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
77159829cc1SJean-Christophe PLAGNIOL-VILLARD  */
772be60a902SHaavard Skinnemoen static int flash_write_cfiword (flash_info_t * info, ulong dest,
773be60a902SHaavard Skinnemoen 				cfiword_t cword)
77459829cc1SJean-Christophe PLAGNIOL-VILLARD {
775cdbaefb5SHaavard Skinnemoen 	void *dstaddr;
776be60a902SHaavard Skinnemoen 	int flag;
77759829cc1SJean-Christophe PLAGNIOL-VILLARD 
77812d30aa7SHaavard Skinnemoen 	dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
779be60a902SHaavard Skinnemoen 
780be60a902SHaavard Skinnemoen 	/* Check if Flash is (sufficiently) erased */
781be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
782be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
783cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
784be60a902SHaavard Skinnemoen 		break;
785be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
786cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
787be60a902SHaavard Skinnemoen 		break;
788be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
789cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
790be60a902SHaavard Skinnemoen 		break;
791be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
792cdbaefb5SHaavard Skinnemoen 		flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
793be60a902SHaavard Skinnemoen 		break;
794be60a902SHaavard Skinnemoen 	default:
79512d30aa7SHaavard Skinnemoen 		flag = 0;
79612d30aa7SHaavard Skinnemoen 		break;
79712d30aa7SHaavard Skinnemoen 	}
79812d30aa7SHaavard Skinnemoen 	if (!flag) {
79912d30aa7SHaavard Skinnemoen 		unmap_physmem(dstaddr, info->portwidth);
8000dc80e27SStefan Roese 		return ERR_NOT_ERASED;
801be60a902SHaavard Skinnemoen 	}
802be60a902SHaavard Skinnemoen 
803be60a902SHaavard Skinnemoen 	/* Disable interrupts which might cause a timeout here */
804be60a902SHaavard Skinnemoen 	flag = disable_interrupts ();
805be60a902SHaavard Skinnemoen 
806be60a902SHaavard Skinnemoen 	switch (info->vendor) {
8079c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
808be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
809be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
810be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
811be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
812be60a902SHaavard Skinnemoen 		break;
813be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
814be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
815be60a902SHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
816be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_LEGACY:
817be60a902SHaavard Skinnemoen #endif
818be60a902SHaavard Skinnemoen 		flash_unlock_seq (info, 0);
819be60a902SHaavard Skinnemoen 		flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
82059829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
82159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
82259829cc1SJean-Christophe PLAGNIOL-VILLARD 
823be60a902SHaavard Skinnemoen 	switch (info->portwidth) {
824be60a902SHaavard Skinnemoen 	case FLASH_CFI_8BIT:
825cdbaefb5SHaavard Skinnemoen 		flash_write8(cword.c, dstaddr);
826be60a902SHaavard Skinnemoen 		break;
827be60a902SHaavard Skinnemoen 	case FLASH_CFI_16BIT:
828cdbaefb5SHaavard Skinnemoen 		flash_write16(cword.w, dstaddr);
829be60a902SHaavard Skinnemoen 		break;
830be60a902SHaavard Skinnemoen 	case FLASH_CFI_32BIT:
831cdbaefb5SHaavard Skinnemoen 		flash_write32(cword.l, dstaddr);
832be60a902SHaavard Skinnemoen 		break;
833be60a902SHaavard Skinnemoen 	case FLASH_CFI_64BIT:
834cdbaefb5SHaavard Skinnemoen 		flash_write64(cword.ll, dstaddr);
835be60a902SHaavard Skinnemoen 		break;
83659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
837be60a902SHaavard Skinnemoen 
838be60a902SHaavard Skinnemoen 	/* re-enable interrupts if necessary */
839be60a902SHaavard Skinnemoen 	if (flag)
840be60a902SHaavard Skinnemoen 		enable_interrupts ();
841be60a902SHaavard Skinnemoen 
84212d30aa7SHaavard Skinnemoen 	unmap_physmem(dstaddr, info->portwidth);
84312d30aa7SHaavard Skinnemoen 
844be60a902SHaavard Skinnemoen 	return flash_full_status_check (info, find_sector (info, dest),
845be60a902SHaavard Skinnemoen 					info->write_tout, "write");
846be60a902SHaavard Skinnemoen }
847be60a902SHaavard Skinnemoen 
848be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_USE_BUFFER_WRITE
849be60a902SHaavard Skinnemoen 
850be60a902SHaavard Skinnemoen static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
851be60a902SHaavard Skinnemoen 				  int len)
852be60a902SHaavard Skinnemoen {
853be60a902SHaavard Skinnemoen 	flash_sect_t sector;
854be60a902SHaavard Skinnemoen 	int cnt;
855be60a902SHaavard Skinnemoen 	int retcode;
856cdbaefb5SHaavard Skinnemoen 	void *src = cp;
85712d30aa7SHaavard Skinnemoen 	void *dst = map_physmem(dest, len, MAP_NOCACHE);
8580dc80e27SStefan Roese 	void *dst2 = dst;
8590dc80e27SStefan Roese 	int flag = 0;
86096ef831fSGuennadi Liakhovetski 	uint offset = 0;
86196ef831fSGuennadi Liakhovetski 	unsigned int shift;
8629c048b52SVasiliy Leoenenko 	uchar write_cmd;
863cdbaefb5SHaavard Skinnemoen 
8640dc80e27SStefan Roese 	switch (info->portwidth) {
8650dc80e27SStefan Roese 	case FLASH_CFI_8BIT:
86696ef831fSGuennadi Liakhovetski 		shift = 0;
8670dc80e27SStefan Roese 		break;
8680dc80e27SStefan Roese 	case FLASH_CFI_16BIT:
86996ef831fSGuennadi Liakhovetski 		shift = 1;
8700dc80e27SStefan Roese 		break;
8710dc80e27SStefan Roese 	case FLASH_CFI_32BIT:
87296ef831fSGuennadi Liakhovetski 		shift = 2;
8730dc80e27SStefan Roese 		break;
8740dc80e27SStefan Roese 	case FLASH_CFI_64BIT:
87596ef831fSGuennadi Liakhovetski 		shift = 3;
8760dc80e27SStefan Roese 		break;
8770dc80e27SStefan Roese 	default:
8780dc80e27SStefan Roese 		retcode = ERR_INVAL;
8790dc80e27SStefan Roese 		goto out_unmap;
8800dc80e27SStefan Roese 	}
8810dc80e27SStefan Roese 
88296ef831fSGuennadi Liakhovetski 	cnt = len >> shift;
88396ef831fSGuennadi Liakhovetski 
8840dc80e27SStefan Roese 	while ((cnt-- > 0) && (flag == 0)) {
8850dc80e27SStefan Roese 		switch (info->portwidth) {
8860dc80e27SStefan Roese 		case FLASH_CFI_8BIT:
8870dc80e27SStefan Roese 			flag = ((flash_read8(dst2) & flash_read8(src)) ==
8880dc80e27SStefan Roese 				flash_read8(src));
8890dc80e27SStefan Roese 			src += 1, dst2 += 1;
8900dc80e27SStefan Roese 			break;
8910dc80e27SStefan Roese 		case FLASH_CFI_16BIT:
8920dc80e27SStefan Roese 			flag = ((flash_read16(dst2) & flash_read16(src)) ==
8930dc80e27SStefan Roese 				flash_read16(src));
8940dc80e27SStefan Roese 			src += 2, dst2 += 2;
8950dc80e27SStefan Roese 			break;
8960dc80e27SStefan Roese 		case FLASH_CFI_32BIT:
8970dc80e27SStefan Roese 			flag = ((flash_read32(dst2) & flash_read32(src)) ==
8980dc80e27SStefan Roese 				flash_read32(src));
8990dc80e27SStefan Roese 			src += 4, dst2 += 4;
9000dc80e27SStefan Roese 			break;
9010dc80e27SStefan Roese 		case FLASH_CFI_64BIT:
9020dc80e27SStefan Roese 			flag = ((flash_read64(dst2) & flash_read64(src)) ==
9030dc80e27SStefan Roese 				flash_read64(src));
9040dc80e27SStefan Roese 			src += 8, dst2 += 8;
9050dc80e27SStefan Roese 			break;
9060dc80e27SStefan Roese 		}
9070dc80e27SStefan Roese 	}
9080dc80e27SStefan Roese 	if (!flag) {
9090dc80e27SStefan Roese 		retcode = ERR_NOT_ERASED;
9100dc80e27SStefan Roese 		goto out_unmap;
9110dc80e27SStefan Roese 	}
9120dc80e27SStefan Roese 
9130dc80e27SStefan Roese 	src = cp;
914cdbaefb5SHaavard Skinnemoen 	sector = find_sector (info, dest);
915be60a902SHaavard Skinnemoen 
916be60a902SHaavard Skinnemoen 	switch (info->vendor) {
9179c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
918be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
919be60a902SHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
9209c048b52SVasiliy Leoenenko 		write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
9219c048b52SVasiliy Leoenenko 					FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER;
922be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
9239c048b52SVasiliy Leoenenko 		flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS);
9249c048b52SVasiliy Leoenenko 		flash_write_cmd (info, sector, 0, write_cmd);
925be60a902SHaavard Skinnemoen 		retcode = flash_status_check (info, sector,
926be60a902SHaavard Skinnemoen 					      info->buffer_write_tout,
927be60a902SHaavard Skinnemoen 					      "write to buffer");
928be60a902SHaavard Skinnemoen 		if (retcode == ERR_OK) {
929be60a902SHaavard Skinnemoen 			/* reduce the number of loops by the width of
930be60a902SHaavard Skinnemoen 			 * the port */
93196ef831fSGuennadi Liakhovetski 			cnt = len >> shift;
93293c56f21SVasiliy Leoenenko 			flash_write_cmd (info, sector, 0, cnt - 1);
933be60a902SHaavard Skinnemoen 			while (cnt-- > 0) {
934be60a902SHaavard Skinnemoen 				switch (info->portwidth) {
935be60a902SHaavard Skinnemoen 				case FLASH_CFI_8BIT:
936cdbaefb5SHaavard Skinnemoen 					flash_write8(flash_read8(src), dst);
937cdbaefb5SHaavard Skinnemoen 					src += 1, dst += 1;
938be60a902SHaavard Skinnemoen 					break;
939be60a902SHaavard Skinnemoen 				case FLASH_CFI_16BIT:
940cdbaefb5SHaavard Skinnemoen 					flash_write16(flash_read16(src), dst);
941cdbaefb5SHaavard Skinnemoen 					src += 2, dst += 2;
942be60a902SHaavard Skinnemoen 					break;
943be60a902SHaavard Skinnemoen 				case FLASH_CFI_32BIT:
944cdbaefb5SHaavard Skinnemoen 					flash_write32(flash_read32(src), dst);
945cdbaefb5SHaavard Skinnemoen 					src += 4, dst += 4;
946be60a902SHaavard Skinnemoen 					break;
947be60a902SHaavard Skinnemoen 				case FLASH_CFI_64BIT:
948cdbaefb5SHaavard Skinnemoen 					flash_write64(flash_read64(src), dst);
949cdbaefb5SHaavard Skinnemoen 					src += 8, dst += 8;
950be60a902SHaavard Skinnemoen 					break;
951be60a902SHaavard Skinnemoen 				default:
95212d30aa7SHaavard Skinnemoen 					retcode = ERR_INVAL;
95312d30aa7SHaavard Skinnemoen 					goto out_unmap;
954be60a902SHaavard Skinnemoen 				}
955be60a902SHaavard Skinnemoen 			}
956be60a902SHaavard Skinnemoen 			flash_write_cmd (info, sector, 0,
957be60a902SHaavard Skinnemoen 					 FLASH_CMD_WRITE_BUFFER_CONFIRM);
958be60a902SHaavard Skinnemoen 			retcode = flash_full_status_check (
959be60a902SHaavard Skinnemoen 				info, sector, info->buffer_write_tout,
960be60a902SHaavard Skinnemoen 				"buffer write");
961be60a902SHaavard Skinnemoen 		}
96212d30aa7SHaavard Skinnemoen 
96312d30aa7SHaavard Skinnemoen 		break;
964be60a902SHaavard Skinnemoen 
965be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
966be60a902SHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
967be60a902SHaavard Skinnemoen 		flash_unlock_seq(info,0);
96896ef831fSGuennadi Liakhovetski 
96996ef831fSGuennadi Liakhovetski #ifdef CONFIG_FLASH_SPANSION_S29WS_N
97096ef831fSGuennadi Liakhovetski 		offset = ((unsigned long)dst - info->start[sector]) >> shift;
97196ef831fSGuennadi Liakhovetski #endif
97296ef831fSGuennadi Liakhovetski 		flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
97396ef831fSGuennadi Liakhovetski 		cnt = len >> shift;
97496ef831fSGuennadi Liakhovetski 		flash_write_cmd(info, sector, offset, (uchar)cnt - 1);
975be60a902SHaavard Skinnemoen 
976be60a902SHaavard Skinnemoen 		switch (info->portwidth) {
977be60a902SHaavard Skinnemoen 		case FLASH_CFI_8BIT:
978cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
979cdbaefb5SHaavard Skinnemoen 				flash_write8(flash_read8(src), dst);
980cdbaefb5SHaavard Skinnemoen 				src += 1, dst += 1;
981cdbaefb5SHaavard Skinnemoen 			}
982be60a902SHaavard Skinnemoen 			break;
983be60a902SHaavard Skinnemoen 		case FLASH_CFI_16BIT:
984cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
985cdbaefb5SHaavard Skinnemoen 				flash_write16(flash_read16(src), dst);
986cdbaefb5SHaavard Skinnemoen 				src += 2, dst += 2;
987cdbaefb5SHaavard Skinnemoen 			}
988be60a902SHaavard Skinnemoen 			break;
989be60a902SHaavard Skinnemoen 		case FLASH_CFI_32BIT:
990cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
991cdbaefb5SHaavard Skinnemoen 				flash_write32(flash_read32(src), dst);
992cdbaefb5SHaavard Skinnemoen 				src += 4, dst += 4;
993cdbaefb5SHaavard Skinnemoen 			}
994be60a902SHaavard Skinnemoen 			break;
995be60a902SHaavard Skinnemoen 		case FLASH_CFI_64BIT:
996cdbaefb5SHaavard Skinnemoen 			while (cnt-- > 0) {
997cdbaefb5SHaavard Skinnemoen 				flash_write64(flash_read64(src), dst);
998cdbaefb5SHaavard Skinnemoen 				src += 8, dst += 8;
999cdbaefb5SHaavard Skinnemoen 			}
1000be60a902SHaavard Skinnemoen 			break;
1001be60a902SHaavard Skinnemoen 		default:
100212d30aa7SHaavard Skinnemoen 			retcode = ERR_INVAL;
100312d30aa7SHaavard Skinnemoen 			goto out_unmap;
1004be60a902SHaavard Skinnemoen 		}
1005be60a902SHaavard Skinnemoen 
1006be60a902SHaavard Skinnemoen 		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1007be60a902SHaavard Skinnemoen 		retcode = flash_full_status_check (info, sector,
1008be60a902SHaavard Skinnemoen 						   info->buffer_write_tout,
1009be60a902SHaavard Skinnemoen 						   "buffer write");
101012d30aa7SHaavard Skinnemoen 		break;
1011be60a902SHaavard Skinnemoen 
1012be60a902SHaavard Skinnemoen 	default:
1013be60a902SHaavard Skinnemoen 		debug ("Unknown Command Set\n");
101412d30aa7SHaavard Skinnemoen 		retcode = ERR_INVAL;
101512d30aa7SHaavard Skinnemoen 		break;
1016be60a902SHaavard Skinnemoen 	}
101712d30aa7SHaavard Skinnemoen 
101812d30aa7SHaavard Skinnemoen out_unmap:
101912d30aa7SHaavard Skinnemoen 	unmap_physmem(dst, len);
102012d30aa7SHaavard Skinnemoen 	return retcode;
1021be60a902SHaavard Skinnemoen }
1022be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_USE_BUFFER_WRITE */
1023be60a902SHaavard Skinnemoen 
102459829cc1SJean-Christophe PLAGNIOL-VILLARD 
102559829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
102659829cc1SJean-Christophe PLAGNIOL-VILLARD  */
102759829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last)
102859829cc1SJean-Christophe PLAGNIOL-VILLARD {
102959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int rcode = 0;
103059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int prot;
103159829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect;
103259829cc1SJean-Christophe PLAGNIOL-VILLARD 
103359829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
103459829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("Can't erase unknown flash type - aborted\n");
103559829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
103659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
103759829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((s_first < 0) || (s_first > s_last)) {
103859829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("- no sectors to erase\n");
103959829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
104059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
104159829cc1SJean-Christophe PLAGNIOL-VILLARD 
104259829cc1SJean-Christophe PLAGNIOL-VILLARD 	prot = 0;
104359829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; ++sect) {
104459829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect]) {
104559829cc1SJean-Christophe PLAGNIOL-VILLARD 			prot++;
104659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
104759829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
104859829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot) {
10497e5b9b47SHaavard Skinnemoen 		printf ("- Warning: %d protected sectors will not be erased!\n",
10507e5b9b47SHaavard Skinnemoen 			prot);
105159829cc1SJean-Christophe PLAGNIOL-VILLARD 	} else {
105259829cc1SJean-Christophe PLAGNIOL-VILLARD 		putc ('\n');
105359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
105459829cc1SJean-Christophe PLAGNIOL-VILLARD 
105559829cc1SJean-Christophe PLAGNIOL-VILLARD 
105659829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; sect++) {
105759829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect] == 0) { /* not protected */
105859829cc1SJean-Christophe PLAGNIOL-VILLARD 			switch (info->vendor) {
10599c048b52SVasiliy Leoenenko 			case CFI_CMDSET_INTEL_PROG_REGIONS:
106059829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_STANDARD:
106159829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_EXTENDED:
10627e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10637e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_CLEAR_STATUS);
10647e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10657e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_BLOCK_ERASE);
10667e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10677e5b9b47SHaavard Skinnemoen 						 FLASH_CMD_ERASE_CONFIRM);
106859829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
106959829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_STANDARD:
107059829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_EXTENDED:
107159829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
10727e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect,
10737e5b9b47SHaavard Skinnemoen 						info->addr_unlock1,
10747e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
107559829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
10767e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10777e5b9b47SHaavard Skinnemoen 						 AMD_CMD_ERASE_SECTOR);
107859829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
107981b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
108081b20cccSMichael Schwingen 			case CFI_CMDSET_AMD_LEGACY:
108181b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
10827e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, 0, info->addr_unlock1,
10837e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_START);
108481b20cccSMichael Schwingen 				flash_unlock_seq (info, 0);
10857e5b9b47SHaavard Skinnemoen 				flash_write_cmd (info, sect, 0,
10867e5b9b47SHaavard Skinnemoen 						AMD_CMD_ERASE_SECTOR);
108781b20cccSMichael Schwingen 				break;
108881b20cccSMichael Schwingen #endif
108959829cc1SJean-Christophe PLAGNIOL-VILLARD 			default:
109059829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug ("Unkown flash vendor %d\n",
109159829cc1SJean-Christophe PLAGNIOL-VILLARD 				       info->vendor);
109259829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
109359829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
109459829cc1SJean-Christophe PLAGNIOL-VILLARD 
109559829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_full_status_check
109659829cc1SJean-Christophe PLAGNIOL-VILLARD 			    (info, sect, info->erase_blk_tout, "erase")) {
109759829cc1SJean-Christophe PLAGNIOL-VILLARD 				rcode = 1;
109859829cc1SJean-Christophe PLAGNIOL-VILLARD 			} else
109959829cc1SJean-Christophe PLAGNIOL-VILLARD 				putc ('.');
110059829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
110159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
110259829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts (" done\n");
110359829cc1SJean-Christophe PLAGNIOL-VILLARD 	return rcode;
110459829cc1SJean-Christophe PLAGNIOL-VILLARD }
110559829cc1SJean-Christophe PLAGNIOL-VILLARD 
110659829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
110759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
110859829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info)
110959829cc1SJean-Christophe PLAGNIOL-VILLARD {
111059829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
111159829cc1SJean-Christophe PLAGNIOL-VILLARD 
111259829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
111359829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("missing or unknown FLASH type\n");
111459829cc1SJean-Christophe PLAGNIOL-VILLARD 		return;
111559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
111659829cc1SJean-Christophe PLAGNIOL-VILLARD 
111781b20cccSMichael Schwingen 	printf ("%s FLASH (%d x %d)",
111881b20cccSMichael Schwingen 		info->name,
111959829cc1SJean-Christophe PLAGNIOL-VILLARD 		(info->portwidth << 3), (info->chipwidth << 3));
112081b20cccSMichael Schwingen 	if (info->size < 1024*1024)
112181b20cccSMichael Schwingen 		printf ("  Size: %ld kB in %d Sectors\n",
112281b20cccSMichael Schwingen 			info->size >> 10, info->sector_count);
112381b20cccSMichael Schwingen 	else
112459829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  Size: %ld MB in %d Sectors\n",
112559829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->size >> 20, info->sector_count);
112659829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("  ");
112759829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
11289c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
11299c048b52SVasiliy Leoenenko 			printf ("Intel Prog Regions");
11309c048b52SVasiliy Leoenenko 			break;
113159829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
113259829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Standard");
113359829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
113459829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
113559829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Extended");
113659829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
113759829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
113859829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Standard");
113959829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
114059829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
114159829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Extended");
114259829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
114381b20cccSMichael Schwingen #ifdef CONFIG_FLASH_CFI_LEGACY
114481b20cccSMichael Schwingen 		case CFI_CMDSET_AMD_LEGACY:
114581b20cccSMichael Schwingen 			printf ("AMD Legacy");
114681b20cccSMichael Schwingen 			break;
114781b20cccSMichael Schwingen #endif
114859829cc1SJean-Christophe PLAGNIOL-VILLARD 		default:
114959829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Unknown (%d)", info->vendor);
115059829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
115159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
115259829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
115359829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->manufacturer_id, info->device_id);
115459829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->device_id == 0x7E) {
115559829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf("%04X", info->device_id2);
115659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
115759829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
115859829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->erase_blk_tout,
115959829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->write_tout);
116059829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->buffer_size > 1) {
11617e5b9b47SHaavard Skinnemoen 		printf ("  Buffer write timeout: %ld ms, "
11627e5b9b47SHaavard Skinnemoen 			"buffer size: %d bytes\n",
116359829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_write_tout,
116459829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_size);
116559829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
116659829cc1SJean-Christophe PLAGNIOL-VILLARD 
116759829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts ("\n  Sector Start Addresses:");
116859829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < info->sector_count; ++i) {
116959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((i % 5) == 0)
117059829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("\n");
117159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_EMPTY_INFO
117259829cc1SJean-Christophe PLAGNIOL-VILLARD 		int k;
117359829cc1SJean-Christophe PLAGNIOL-VILLARD 		int size;
117459829cc1SJean-Christophe PLAGNIOL-VILLARD 		int erased;
117559829cc1SJean-Christophe PLAGNIOL-VILLARD 		volatile unsigned long *flash;
117659829cc1SJean-Christophe PLAGNIOL-VILLARD 
117759829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
117859829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * Check if whole sector is erased
117959829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
118012d30aa7SHaavard Skinnemoen 		size = flash_sector_size(info, i);
118159829cc1SJean-Christophe PLAGNIOL-VILLARD 		erased = 1;
118259829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash = (volatile unsigned long *) info->start[i];
118359829cc1SJean-Christophe PLAGNIOL-VILLARD 		size = size >> 2;	/* divide by 4 for longword access */
118459829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (k = 0; k < size; k++) {
118559829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (*flash++ != 0xffffffff) {
118659829cc1SJean-Christophe PLAGNIOL-VILLARD 				erased = 0;
118759829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
118859829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
118959829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
119059829cc1SJean-Christophe PLAGNIOL-VILLARD 
119159829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* print empty and read-only info */
119259829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX %c %s ",
119359829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
119459829cc1SJean-Christophe PLAGNIOL-VILLARD 			erased ? 'E' : ' ',
119559829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
119659829cc1SJean-Christophe PLAGNIOL-VILLARD #else	/* ! CFG_FLASH_EMPTY_INFO */
119759829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX   %s ",
119859829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
119959829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
120059829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
120159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
120259829cc1SJean-Christophe PLAGNIOL-VILLARD 	putc ('\n');
120359829cc1SJean-Christophe PLAGNIOL-VILLARD 	return;
120459829cc1SJean-Christophe PLAGNIOL-VILLARD }
120559829cc1SJean-Christophe PLAGNIOL-VILLARD 
120659829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
12079a042e9cSJerry Van Baren  * This is used in a few places in write_buf() to show programming
12089a042e9cSJerry Van Baren  * progress.  Making it a function is nasty because it needs to do side
12099a042e9cSJerry Van Baren  * effect updates to digit and dots.  Repeated code is nasty too, so
12109a042e9cSJerry Van Baren  * we define it once here.
12119a042e9cSJerry Van Baren  */
1212f0105727SStefan Roese #ifdef CONFIG_FLASH_SHOW_PROGRESS
1213f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
1214f0105727SStefan Roese 	dots -= dots_sub; \
12159a042e9cSJerry Van Baren 	if ((scale > 0) && (dots <= 0)) { \
12169a042e9cSJerry Van Baren 		if ((digit % 5) == 0) \
12179a042e9cSJerry Van Baren 			printf ("%d", digit / 5); \
12189a042e9cSJerry Van Baren 		else \
12199a042e9cSJerry Van Baren 			putc ('.'); \
12209a042e9cSJerry Van Baren 		digit--; \
12219a042e9cSJerry Van Baren 		dots += scale; \
12229a042e9cSJerry Van Baren 	}
1223f0105727SStefan Roese #else
1224f0105727SStefan Roese #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1225f0105727SStefan Roese #endif
12269a042e9cSJerry Van Baren 
12279a042e9cSJerry Van Baren /*-----------------------------------------------------------------------
122859829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copy memory to flash, returns:
122959829cc1SJean-Christophe PLAGNIOL-VILLARD  * 0 - OK
123059829cc1SJean-Christophe PLAGNIOL-VILLARD  * 1 - write timeout
123159829cc1SJean-Christophe PLAGNIOL-VILLARD  * 2 - Flash not erased
123259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
123359829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
123459829cc1SJean-Christophe PLAGNIOL-VILLARD {
123559829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong wp;
123612d30aa7SHaavard Skinnemoen 	uchar *p;
123759829cc1SJean-Christophe PLAGNIOL-VILLARD 	int aln;
123859829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
123959829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, rc;
124059829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
124159829cc1SJean-Christophe PLAGNIOL-VILLARD 	int buffered_size;
124259829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
12439a042e9cSJerry Van Baren #ifdef CONFIG_FLASH_SHOW_PROGRESS
12449a042e9cSJerry Van Baren 	int digit = CONFIG_FLASH_SHOW_PROGRESS;
12459a042e9cSJerry Van Baren 	int scale = 0;
12469a042e9cSJerry Van Baren 	int dots  = 0;
12479a042e9cSJerry Van Baren 
12489a042e9cSJerry Van Baren 	/*
12499a042e9cSJerry Van Baren 	 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
12509a042e9cSJerry Van Baren 	 */
12519a042e9cSJerry Van Baren 	if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
12529a042e9cSJerry Van Baren 		scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
12539a042e9cSJerry Van Baren 			CONFIG_FLASH_SHOW_PROGRESS);
12549a042e9cSJerry Van Baren 	}
12559a042e9cSJerry Van Baren #endif
12569a042e9cSJerry Van Baren 
125759829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* get lower aligned address */
125859829cc1SJean-Christophe PLAGNIOL-VILLARD 	wp = (addr & ~(info->portwidth - 1));
125959829cc1SJean-Christophe PLAGNIOL-VILLARD 
126059829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle unaligned start */
126159829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((aln = addr - wp) != 0) {
126259829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
126312d30aa7SHaavard Skinnemoen 		p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
126412d30aa7SHaavard Skinnemoen 		for (i = 0; i < aln; ++i)
126512d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
126659829cc1SJean-Christophe PLAGNIOL-VILLARD 
126759829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (; (i < info->portwidth) && (cnt > 0); i++) {
126859829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
126959829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt--;
127059829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
127112d30aa7SHaavard Skinnemoen 		for (; (cnt == 0) && (i < info->portwidth); ++i)
127212d30aa7SHaavard Skinnemoen 			flash_add_byte (info, &cword, flash_read8(p + i));
127312d30aa7SHaavard Skinnemoen 
127412d30aa7SHaavard Skinnemoen 		rc = flash_write_cfiword (info, wp, cword);
127512d30aa7SHaavard Skinnemoen 		unmap_physmem(p, info->portwidth);
127612d30aa7SHaavard Skinnemoen 		if (rc != 0)
127759829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
127812d30aa7SHaavard Skinnemoen 
127912d30aa7SHaavard Skinnemoen 		wp += i;
1280f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, i);
128159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
128259829cc1SJean-Christophe PLAGNIOL-VILLARD 
128359829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle the aligned part */
128459829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
128559829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size = (info->portwidth / info->chipwidth);
128659829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size *= info->buffer_size;
128759829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
128859829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* prohibit buffer write when buffer_size is 1 */
128959829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->buffer_size == 1) {
129059829cc1SJean-Christophe PLAGNIOL-VILLARD 			cword.l = 0;
129159829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->portwidth; i++)
129259829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_add_byte (info, &cword, *src++);
129359829cc1SJean-Christophe PLAGNIOL-VILLARD 			if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
129459829cc1SJean-Christophe PLAGNIOL-VILLARD 				return rc;
129559829cc1SJean-Christophe PLAGNIOL-VILLARD 			wp += info->portwidth;
129659829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt -= info->portwidth;
129759829cc1SJean-Christophe PLAGNIOL-VILLARD 			continue;
129859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
129959829cc1SJean-Christophe PLAGNIOL-VILLARD 
130059829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* write buffer until next buffered_size aligned boundary */
130159829cc1SJean-Christophe PLAGNIOL-VILLARD 		i = buffered_size - (wp % buffered_size);
130259829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (i > cnt)
130359829cc1SJean-Christophe PLAGNIOL-VILLARD 			i = cnt;
130459829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
130559829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
130659829cc1SJean-Christophe PLAGNIOL-VILLARD 		i -= i & (info->portwidth - 1);
130759829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += i;
130859829cc1SJean-Christophe PLAGNIOL-VILLARD 		src += i;
130959829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= i;
1310f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, i);
131159829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
131259829cc1SJean-Christophe PLAGNIOL-VILLARD #else
131359829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
131459829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
131559829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < info->portwidth; i++) {
131659829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
131759829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
131859829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
131959829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
132059829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += info->portwidth;
132159829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= info->portwidth;
1322f0105727SStefan Roese 		FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
132359829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
132459829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */
13259a042e9cSJerry Van Baren 
132659829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (cnt == 0) {
132759829cc1SJean-Christophe PLAGNIOL-VILLARD 		return (0);
132859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
132959829cc1SJean-Christophe PLAGNIOL-VILLARD 
133059829cc1SJean-Christophe PLAGNIOL-VILLARD 	/*
133159829cc1SJean-Christophe PLAGNIOL-VILLARD 	 * handle unaligned tail bytes
133259829cc1SJean-Christophe PLAGNIOL-VILLARD 	 */
133359829cc1SJean-Christophe PLAGNIOL-VILLARD 	cword.l = 0;
133412d30aa7SHaavard Skinnemoen 	p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
133512d30aa7SHaavard Skinnemoen 	for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
133659829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_add_byte (info, &cword, *src++);
133759829cc1SJean-Christophe PLAGNIOL-VILLARD 		--cnt;
133859829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
133912d30aa7SHaavard Skinnemoen 	for (; i < info->portwidth; ++i)
134012d30aa7SHaavard Skinnemoen 		flash_add_byte (info, &cword, flash_read8(p + i));
134112d30aa7SHaavard Skinnemoen 	unmap_physmem(p, info->portwidth);
134259829cc1SJean-Christophe PLAGNIOL-VILLARD 
134359829cc1SJean-Christophe PLAGNIOL-VILLARD 	return flash_write_cfiword (info, wp, cword);
134459829cc1SJean-Christophe PLAGNIOL-VILLARD }
134559829cc1SJean-Christophe PLAGNIOL-VILLARD 
134659829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
134759829cc1SJean-Christophe PLAGNIOL-VILLARD  */
134859829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
134959829cc1SJean-Christophe PLAGNIOL-VILLARD 
135059829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot)
135159829cc1SJean-Christophe PLAGNIOL-VILLARD {
135259829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retcode = 0;
135359829cc1SJean-Christophe PLAGNIOL-VILLARD 
135459829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
135559829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
135659829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot)
135759829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
135859829cc1SJean-Christophe PLAGNIOL-VILLARD 	else
135959829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
136059829cc1SJean-Christophe PLAGNIOL-VILLARD 
136159829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((retcode =
136259829cc1SJean-Christophe PLAGNIOL-VILLARD 	     flash_full_status_check (info, sector, info->erase_blk_tout,
136359829cc1SJean-Christophe PLAGNIOL-VILLARD 				      prot ? "protect" : "unprotect")) == 0) {
136459829cc1SJean-Christophe PLAGNIOL-VILLARD 
136559829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->protect[sector] = prot;
136659829cc1SJean-Christophe PLAGNIOL-VILLARD 
136759829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
136859829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * On some of Intel's flash chips (marked via legacy_unlock)
136959829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * unprotect unprotects all locking.
137059829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
137159829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((prot == 0) && (info->legacy_unlock)) {
137259829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_sect_t i;
137359829cc1SJean-Christophe PLAGNIOL-VILLARD 
137459829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->sector_count; i++) {
137559829cc1SJean-Christophe PLAGNIOL-VILLARD 				if (info->protect[i])
137659829cc1SJean-Christophe PLAGNIOL-VILLARD 					flash_real_protect (info, i, 1);
137759829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
137859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
137959829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
138059829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retcode;
138159829cc1SJean-Christophe PLAGNIOL-VILLARD }
138259829cc1SJean-Christophe PLAGNIOL-VILLARD 
138359829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
138459829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_user_serial - read the OneTimeProgramming cells
138559829cc1SJean-Christophe PLAGNIOL-VILLARD  */
138659829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
138759829cc1SJean-Christophe PLAGNIOL-VILLARD 			     int len)
138859829cc1SJean-Christophe PLAGNIOL-VILLARD {
138959829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
139059829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *dst;
139159829cc1SJean-Christophe PLAGNIOL-VILLARD 
139259829cc1SJean-Christophe PLAGNIOL-VILLARD 	dst = buffer;
139312d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
139459829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
139559829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (dst, src + offset, len);
139659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
139712d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
139859829cc1SJean-Christophe PLAGNIOL-VILLARD }
139959829cc1SJean-Christophe PLAGNIOL-VILLARD 
140059829cc1SJean-Christophe PLAGNIOL-VILLARD /*
140159829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_factory_serial - read the device Id from the protection area
140259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
140359829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
140459829cc1SJean-Christophe PLAGNIOL-VILLARD 				int len)
140559829cc1SJean-Christophe PLAGNIOL-VILLARD {
140659829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
140759829cc1SJean-Christophe PLAGNIOL-VILLARD 
140812d30aa7SHaavard Skinnemoen 	src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
140959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
141059829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (buffer, src + offset, len);
141159829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
141212d30aa7SHaavard Skinnemoen 	flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
141359829cc1SJean-Christophe PLAGNIOL-VILLARD }
141459829cc1SJean-Christophe PLAGNIOL-VILLARD 
141559829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */
141659829cc1SJean-Christophe PLAGNIOL-VILLARD 
14170ddf06ddSHaavard Skinnemoen /*-----------------------------------------------------------------------
14180ddf06ddSHaavard Skinnemoen  * Reverse the order of the erase regions in the CFI QRY structure.
14190ddf06ddSHaavard Skinnemoen  * This is needed for chips that are either a) correctly detected as
14200ddf06ddSHaavard Skinnemoen  * top-boot, or b) buggy.
14210ddf06ddSHaavard Skinnemoen  */
14220ddf06ddSHaavard Skinnemoen static void cfi_reverse_geometry(struct cfi_qry *qry)
14230ddf06ddSHaavard Skinnemoen {
14240ddf06ddSHaavard Skinnemoen 	unsigned int i, j;
14250ddf06ddSHaavard Skinnemoen 	u32 tmp;
14260ddf06ddSHaavard Skinnemoen 
14270ddf06ddSHaavard Skinnemoen 	for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
14280ddf06ddSHaavard Skinnemoen 		tmp = qry->erase_region_info[i];
14290ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[i] = qry->erase_region_info[j];
14300ddf06ddSHaavard Skinnemoen 		qry->erase_region_info[j] = tmp;
14310ddf06ddSHaavard Skinnemoen 	}
14320ddf06ddSHaavard Skinnemoen }
143359829cc1SJean-Christophe PLAGNIOL-VILLARD 
143459829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
143559829cc1SJean-Christophe PLAGNIOL-VILLARD  * read jedec ids from device and set corresponding fields in info struct
143659829cc1SJean-Christophe PLAGNIOL-VILLARD  *
143759829cc1SJean-Christophe PLAGNIOL-VILLARD  * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
143859829cc1SJean-Christophe PLAGNIOL-VILLARD  *
143959829cc1SJean-Christophe PLAGNIOL-VILLARD  */
14400ddf06ddSHaavard Skinnemoen static void cmdset_intel_read_jedec_ids(flash_info_t *info)
144159829cc1SJean-Christophe PLAGNIOL-VILLARD {
144259829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
144359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
144459829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
144559829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = flash_read_uchar (info,
144659829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_MANUFACTURER_ID);
144759829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id = flash_read_uchar (info,
144859829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_DEVICE_ID);
144959829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
14500ddf06ddSHaavard Skinnemoen }
14510ddf06ddSHaavard Skinnemoen 
14520ddf06ddSHaavard Skinnemoen static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
14530ddf06ddSHaavard Skinnemoen {
14540ddf06ddSHaavard Skinnemoen 	info->cmd_reset = FLASH_CMD_RESET;
14550ddf06ddSHaavard Skinnemoen 
14560ddf06ddSHaavard Skinnemoen 	cmdset_intel_read_jedec_ids(info);
14570ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
14580ddf06ddSHaavard Skinnemoen 
14590ddf06ddSHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION
14600ddf06ddSHaavard Skinnemoen 	/* read legacy lock/unlock bit from intel flash */
14610ddf06ddSHaavard Skinnemoen 	if (info->ext_addr) {
14620ddf06ddSHaavard Skinnemoen 		info->legacy_unlock = flash_read_uchar (info,
14630ddf06ddSHaavard Skinnemoen 				info->ext_addr + 5) & 0x08;
14640ddf06ddSHaavard Skinnemoen 	}
14650ddf06ddSHaavard Skinnemoen #endif
14660ddf06ddSHaavard Skinnemoen 
14670ddf06ddSHaavard Skinnemoen 	return 0;
14680ddf06ddSHaavard Skinnemoen }
14690ddf06ddSHaavard Skinnemoen 
14700ddf06ddSHaavard Skinnemoen static void cmdset_amd_read_jedec_ids(flash_info_t *info)
14710ddf06ddSHaavard Skinnemoen {
147259829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
147359829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_unlock_seq(info, 0);
147481b20cccSMichael Schwingen 	flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
147559829cc1SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000); /* some flash are slow to respond */
147690447ecbSTor Krill 
147759829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = flash_read_uchar (info,
147859829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_MANUFACTURER_ID);
147990447ecbSTor Krill 
148090447ecbSTor Krill 	switch (info->chipwidth){
148190447ecbSTor Krill 	case FLASH_CFI_8BIT:
148259829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id = flash_read_uchar (info,
148359829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID);
148459829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->device_id == 0x7E) {
148559829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* AMD 3-byte (expanded) device ids */
148659829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 = flash_read_uchar (info,
148759829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID2);
148859829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 <<= 8;
148959829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 |= flash_read_uchar (info,
149059829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID3);
149159829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
149290447ecbSTor Krill 		break;
149390447ecbSTor Krill 	case FLASH_CFI_16BIT:
149490447ecbSTor Krill 		info->device_id = flash_read_word (info,
149590447ecbSTor Krill 						FLASH_OFFSET_DEVICE_ID);
149690447ecbSTor Krill 		break;
149790447ecbSTor Krill 	default:
149890447ecbSTor Krill 		break;
149990447ecbSTor Krill 	}
150059829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
15010ddf06ddSHaavard Skinnemoen }
15020ddf06ddSHaavard Skinnemoen 
15030ddf06ddSHaavard Skinnemoen static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
15040ddf06ddSHaavard Skinnemoen {
15050ddf06ddSHaavard Skinnemoen 	info->cmd_reset = AMD_CMD_RESET;
15060ddf06ddSHaavard Skinnemoen 
15070ddf06ddSHaavard Skinnemoen 	cmdset_amd_read_jedec_ids(info);
15080ddf06ddSHaavard Skinnemoen 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
15090ddf06ddSHaavard Skinnemoen 
15100ddf06ddSHaavard Skinnemoen 	return 0;
15110ddf06ddSHaavard Skinnemoen }
15120ddf06ddSHaavard Skinnemoen 
15130ddf06ddSHaavard Skinnemoen #ifdef CONFIG_FLASH_CFI_LEGACY
15140ddf06ddSHaavard Skinnemoen static void flash_read_jedec_ids (flash_info_t * info)
15150ddf06ddSHaavard Skinnemoen {
15160ddf06ddSHaavard Skinnemoen 	info->manufacturer_id = 0;
15170ddf06ddSHaavard Skinnemoen 	info->device_id       = 0;
15180ddf06ddSHaavard Skinnemoen 	info->device_id2      = 0;
15190ddf06ddSHaavard Skinnemoen 
15200ddf06ddSHaavard Skinnemoen 	switch (info->vendor) {
15219c048b52SVasiliy Leoenenko 	case CFI_CMDSET_INTEL_PROG_REGIONS:
15220ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_STANDARD:
15230ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_INTEL_EXTENDED:
15248225d1e3SMichael Schwingen 		cmdset_intel_read_jedec_ids(info);
15250ddf06ddSHaavard Skinnemoen 		break;
15260ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_STANDARD:
15270ddf06ddSHaavard Skinnemoen 	case CFI_CMDSET_AMD_EXTENDED:
15288225d1e3SMichael Schwingen 		cmdset_amd_read_jedec_ids(info);
152959829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
153059829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
153159829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
153259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
153359829cc1SJean-Christophe PLAGNIOL-VILLARD }
153459829cc1SJean-Christophe PLAGNIOL-VILLARD 
1535be60a902SHaavard Skinnemoen /*-----------------------------------------------------------------------
1536be60a902SHaavard Skinnemoen  * Call board code to request info about non-CFI flash.
1537be60a902SHaavard Skinnemoen  * board_flash_get_legacy needs to fill in at least:
1538be60a902SHaavard Skinnemoen  * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1539be60a902SHaavard Skinnemoen  */
1540be60a902SHaavard Skinnemoen static int flash_detect_legacy(ulong base, int banknum)
1541be60a902SHaavard Skinnemoen {
1542be60a902SHaavard Skinnemoen 	flash_info_t *info = &flash_info[banknum];
1543be60a902SHaavard Skinnemoen 
1544be60a902SHaavard Skinnemoen 	if (board_flash_get_legacy(base, banknum, info)) {
1545be60a902SHaavard Skinnemoen 		/* board code may have filled info completely. If not, we
1546be60a902SHaavard Skinnemoen 		   use JEDEC ID probing. */
1547be60a902SHaavard Skinnemoen 		if (!info->vendor) {
1548be60a902SHaavard Skinnemoen 			int modes[] = {
1549be60a902SHaavard Skinnemoen 				CFI_CMDSET_AMD_STANDARD,
1550be60a902SHaavard Skinnemoen 				CFI_CMDSET_INTEL_STANDARD
1551be60a902SHaavard Skinnemoen 			};
1552be60a902SHaavard Skinnemoen 			int i;
1553be60a902SHaavard Skinnemoen 
1554be60a902SHaavard Skinnemoen 			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1555be60a902SHaavard Skinnemoen 				info->vendor = modes[i];
1556be60a902SHaavard Skinnemoen 				info->start[0] = base;
1557be60a902SHaavard Skinnemoen 				if (info->portwidth == FLASH_CFI_8BIT
1558be60a902SHaavard Skinnemoen 					&& info->interface == FLASH_CFI_X8X16) {
1559be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x2AAA;
1560be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x5555;
1561be60a902SHaavard Skinnemoen 				} else {
1562be60a902SHaavard Skinnemoen 					info->addr_unlock1 = 0x5555;
1563be60a902SHaavard Skinnemoen 					info->addr_unlock2 = 0x2AAA;
1564be60a902SHaavard Skinnemoen 				}
1565be60a902SHaavard Skinnemoen 				flash_read_jedec_ids(info);
1566be60a902SHaavard Skinnemoen 				debug("JEDEC PROBE: ID %x %x %x\n",
1567be60a902SHaavard Skinnemoen 						info->manufacturer_id,
1568be60a902SHaavard Skinnemoen 						info->device_id,
1569be60a902SHaavard Skinnemoen 						info->device_id2);
1570be60a902SHaavard Skinnemoen 				if (jedec_flash_match(info, base))
1571be60a902SHaavard Skinnemoen 					break;
1572be60a902SHaavard Skinnemoen 			}
1573be60a902SHaavard Skinnemoen 		}
1574be60a902SHaavard Skinnemoen 
1575be60a902SHaavard Skinnemoen 		switch(info->vendor) {
15769c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
1577be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_STANDARD:
1578be60a902SHaavard Skinnemoen 		case CFI_CMDSET_INTEL_EXTENDED:
1579be60a902SHaavard Skinnemoen 			info->cmd_reset = FLASH_CMD_RESET;
1580be60a902SHaavard Skinnemoen 			break;
1581be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_STANDARD:
1582be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_EXTENDED:
1583be60a902SHaavard Skinnemoen 		case CFI_CMDSET_AMD_LEGACY:
1584be60a902SHaavard Skinnemoen 			info->cmd_reset = AMD_CMD_RESET;
1585be60a902SHaavard Skinnemoen 			break;
1586be60a902SHaavard Skinnemoen 		}
1587be60a902SHaavard Skinnemoen 		info->flash_id = FLASH_MAN_CFI;
1588be60a902SHaavard Skinnemoen 		return 1;
1589be60a902SHaavard Skinnemoen 	}
1590be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1591be60a902SHaavard Skinnemoen }
1592be60a902SHaavard Skinnemoen #else
1593be60a902SHaavard Skinnemoen static inline int flash_detect_legacy(ulong base, int banknum)
1594be60a902SHaavard Skinnemoen {
1595be60a902SHaavard Skinnemoen 	return 0; /* use CFI */
1596be60a902SHaavard Skinnemoen }
1597be60a902SHaavard Skinnemoen #endif
1598be60a902SHaavard Skinnemoen 
159959829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
160059829cc1SJean-Christophe PLAGNIOL-VILLARD  * detect if flash is compatible with the Common Flash Interface (CFI)
160159829cc1SJean-Christophe PLAGNIOL-VILLARD  * http://www.jedec.org/download/search/jesd68.pdf
160259829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1603e23741f4SHaavard Skinnemoen static void flash_read_cfi (flash_info_t *info, void *buf,
1604e23741f4SHaavard Skinnemoen 		unsigned int start, size_t len)
1605e23741f4SHaavard Skinnemoen {
1606e23741f4SHaavard Skinnemoen 	u8 *p = buf;
1607e23741f4SHaavard Skinnemoen 	unsigned int i;
1608e23741f4SHaavard Skinnemoen 
1609e23741f4SHaavard Skinnemoen 	for (i = 0; i < len; i++)
1610e23741f4SHaavard Skinnemoen 		p[i] = flash_read_uchar(info, start + i);
1611e23741f4SHaavard Skinnemoen }
1612e23741f4SHaavard Skinnemoen 
1613e23741f4SHaavard Skinnemoen static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
161459829cc1SJean-Christophe PLAGNIOL-VILLARD {
161559829cc1SJean-Christophe PLAGNIOL-VILLARD 	int cfi_offset;
161659829cc1SJean-Christophe PLAGNIOL-VILLARD 
16171ba639daSMichael Schwingen 	/* We do not yet know what kind of commandset to use, so we issue
16181ba639daSMichael Schwingen 	   the reset command in both Intel and AMD variants, in the hope
16191ba639daSMichael Schwingen 	   that AMD flash roms ignore the Intel command. */
16201ba639daSMichael Schwingen 	flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
16211ba639daSMichael Schwingen 	flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
16221ba639daSMichael Schwingen 
16237e5b9b47SHaavard Skinnemoen 	for (cfi_offset=0;
16247e5b9b47SHaavard Skinnemoen 	     cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
16257e5b9b47SHaavard Skinnemoen 	     cfi_offset++) {
16267e5b9b47SHaavard Skinnemoen 		flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
16277e5b9b47SHaavard Skinnemoen 				 FLASH_CMD_CFI);
162859829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
162959829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
163059829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
1631e23741f4SHaavard Skinnemoen 			flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1632e23741f4SHaavard Skinnemoen 					sizeof(struct cfi_qry));
1633e23741f4SHaavard Skinnemoen 			info->interface	= le16_to_cpu(qry->interface_desc);
1634e23741f4SHaavard Skinnemoen 
163559829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_offset = flash_offset_cfi[cfi_offset];
163659829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("device interface is %d\n",
163759829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->interface);
163859829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("found port %d chip %d ",
163959829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth, info->chipwidth);
164059829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("port %d bits chip %d bits\n",
164159829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->portwidth << CFI_FLASH_SHIFT_WIDTH,
164259829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
164342026c9cSBartlomiej Sieka 
164442026c9cSBartlomiej Sieka 			/* calculate command offsets as in the Linux driver */
164542026c9cSBartlomiej Sieka 			info->addr_unlock1 = 0x555;
164642026c9cSBartlomiej Sieka 			info->addr_unlock2 = 0x2aa;
164742026c9cSBartlomiej Sieka 
164842026c9cSBartlomiej Sieka 			/*
164942026c9cSBartlomiej Sieka 			 * modify the unlock address if we are
165042026c9cSBartlomiej Sieka 			 * in compatibility mode
165142026c9cSBartlomiej Sieka 			 */
165242026c9cSBartlomiej Sieka 			if (	/* x8/x16 in x8 mode */
165342026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY8) &&
165442026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X8X16)) ||
165542026c9cSBartlomiej Sieka 				/* x16/x32 in x16 mode */
165642026c9cSBartlomiej Sieka 				((info->chipwidth == FLASH_CFI_BY16) &&
165742026c9cSBartlomiej Sieka 					(info->interface == FLASH_CFI_X16X32)))
165842026c9cSBartlomiej Sieka 			{
165942026c9cSBartlomiej Sieka 				info->addr_unlock1 = 0xaaa;
166042026c9cSBartlomiej Sieka 				info->addr_unlock2 = 0x555;
166142026c9cSBartlomiej Sieka 			}
166242026c9cSBartlomiej Sieka 
166381b20cccSMichael Schwingen 			info->name = "CFI conformant";
166459829cc1SJean-Christophe PLAGNIOL-VILLARD 			return 1;
166559829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
166659829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
16677e5b9b47SHaavard Skinnemoen 
16687e5b9b47SHaavard Skinnemoen 	return 0;
166959829cc1SJean-Christophe PLAGNIOL-VILLARD }
16707e5b9b47SHaavard Skinnemoen 
1671e23741f4SHaavard Skinnemoen static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
16727e5b9b47SHaavard Skinnemoen {
16737e5b9b47SHaavard Skinnemoen 	debug ("flash detect cfi\n");
16747e5b9b47SHaavard Skinnemoen 
16757e5b9b47SHaavard Skinnemoen 	for (info->portwidth = CFG_FLASH_CFI_WIDTH;
16767e5b9b47SHaavard Skinnemoen 	     info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
16777e5b9b47SHaavard Skinnemoen 		for (info->chipwidth = FLASH_CFI_BY8;
16787e5b9b47SHaavard Skinnemoen 		     info->chipwidth <= info->portwidth;
16797e5b9b47SHaavard Skinnemoen 		     info->chipwidth <<= 1)
1680e23741f4SHaavard Skinnemoen 			if (__flash_detect_cfi(info, qry))
16817e5b9b47SHaavard Skinnemoen 				return 1;
168259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
168359829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("not found\n");
168459829cc1SJean-Christophe PLAGNIOL-VILLARD 	return 0;
168559829cc1SJean-Christophe PLAGNIOL-VILLARD }
168659829cc1SJean-Christophe PLAGNIOL-VILLARD 
168759829cc1SJean-Christophe PLAGNIOL-VILLARD /*
1688467bcee1SHaavard Skinnemoen  * Manufacturer-specific quirks. Add workarounds for geometry
1689467bcee1SHaavard Skinnemoen  * reversal, etc. here.
1690467bcee1SHaavard Skinnemoen  */
1691467bcee1SHaavard Skinnemoen static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1692467bcee1SHaavard Skinnemoen {
1693467bcee1SHaavard Skinnemoen 	/* check if flash geometry needs reversal */
1694467bcee1SHaavard Skinnemoen 	if (qry->num_erase_regions > 1) {
1695467bcee1SHaavard Skinnemoen 		/* reverse geometry if top boot part */
1696467bcee1SHaavard Skinnemoen 		if (info->cfi_version < 0x3131) {
1697467bcee1SHaavard Skinnemoen 			/* CFI < 1.1, try to guess from device id */
1698467bcee1SHaavard Skinnemoen 			if ((info->device_id & 0x80) != 0)
1699467bcee1SHaavard Skinnemoen 				cfi_reverse_geometry(qry);
1700467bcee1SHaavard Skinnemoen 		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1701467bcee1SHaavard Skinnemoen 			/* CFI >= 1.1, deduct from top/bottom flag */
1702467bcee1SHaavard Skinnemoen 			/* note: ext_addr is valid since cfi_version > 0 */
1703467bcee1SHaavard Skinnemoen 			cfi_reverse_geometry(qry);
1704467bcee1SHaavard Skinnemoen 		}
1705467bcee1SHaavard Skinnemoen 	}
1706467bcee1SHaavard Skinnemoen }
1707467bcee1SHaavard Skinnemoen 
1708467bcee1SHaavard Skinnemoen static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1709467bcee1SHaavard Skinnemoen {
1710467bcee1SHaavard Skinnemoen 	int reverse_geometry = 0;
1711467bcee1SHaavard Skinnemoen 
1712467bcee1SHaavard Skinnemoen 	/* Check the "top boot" bit in the PRI */
1713467bcee1SHaavard Skinnemoen 	if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1714467bcee1SHaavard Skinnemoen 		reverse_geometry = 1;
1715467bcee1SHaavard Skinnemoen 
1716467bcee1SHaavard Skinnemoen 	/* AT49BV6416(T) list the erase regions in the wrong order.
1717467bcee1SHaavard Skinnemoen 	 * However, the device ID is identical with the non-broken
1718467bcee1SHaavard Skinnemoen 	 * AT49BV642D since u-boot only reads the low byte (they
1719467bcee1SHaavard Skinnemoen 	 * differ in the high byte.) So leave out this fixup for now.
1720467bcee1SHaavard Skinnemoen 	 */
1721467bcee1SHaavard Skinnemoen #if 0
1722467bcee1SHaavard Skinnemoen 	if (info->device_id == 0xd6 || info->device_id == 0xd2)
1723467bcee1SHaavard Skinnemoen 		reverse_geometry = !reverse_geometry;
1724467bcee1SHaavard Skinnemoen #endif
1725467bcee1SHaavard Skinnemoen 
1726467bcee1SHaavard Skinnemoen 	if (reverse_geometry)
1727467bcee1SHaavard Skinnemoen 		cfi_reverse_geometry(qry);
1728467bcee1SHaavard Skinnemoen }
1729467bcee1SHaavard Skinnemoen 
1730467bcee1SHaavard Skinnemoen /*
173159829cc1SJean-Christophe PLAGNIOL-VILLARD  * The following code cannot be run from FLASH!
173259829cc1SJean-Christophe PLAGNIOL-VILLARD  *
173359829cc1SJean-Christophe PLAGNIOL-VILLARD  */
173459829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum)
173559829cc1SJean-Christophe PLAGNIOL-VILLARD {
173659829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_info_t *info = &flash_info[banknum];
173759829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, j;
173859829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect_cnt;
173959829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long sector;
174059829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long tmp;
174159829cc1SJean-Christophe PLAGNIOL-VILLARD 	int size_ratio;
174259829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar num_erase_regions;
174359829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_size;
174459829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_count;
1745e23741f4SHaavard Skinnemoen 	struct cfi_qry qry;
174659829cc1SJean-Christophe PLAGNIOL-VILLARD 
1747f979690eSKumar Gala 	memset(&qry, 0, sizeof(qry));
1748f979690eSKumar Gala 
174959829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->ext_addr = 0;
175059829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->cfi_version = 0;
175159829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
175259829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->legacy_unlock = 0;
175359829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
175459829cc1SJean-Christophe PLAGNIOL-VILLARD 
175559829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->start[0] = base;
175659829cc1SJean-Christophe PLAGNIOL-VILLARD 
1757e23741f4SHaavard Skinnemoen 	if (flash_detect_cfi (info, &qry)) {
1758e23741f4SHaavard Skinnemoen 		info->vendor = le16_to_cpu(qry.p_id);
1759e23741f4SHaavard Skinnemoen 		info->ext_addr = le16_to_cpu(qry.p_adr);
1760e23741f4SHaavard Skinnemoen 		num_erase_regions = qry.num_erase_regions;
1761e23741f4SHaavard Skinnemoen 
176259829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->ext_addr) {
176359829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version = (ushort) flash_read_uchar (info,
176459829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 3) << 8;
176559829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version |= (ushort) flash_read_uchar (info,
176659829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 4);
176759829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
17680ddf06ddSHaavard Skinnemoen 
176959829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
1770e23741f4SHaavard Skinnemoen 		flash_printqry (&qry);
177159829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
17720ddf06ddSHaavard Skinnemoen 
177359829cc1SJean-Christophe PLAGNIOL-VILLARD 		switch (info->vendor) {
17749c048b52SVasiliy Leoenenko 		case CFI_CMDSET_INTEL_PROG_REGIONS:
177559829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
177659829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
17770ddf06ddSHaavard Skinnemoen 			cmdset_intel_init(info, &qry);
177859829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
177959829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
178059829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
17810ddf06ddSHaavard Skinnemoen 			cmdset_amd_init(info, &qry);
178259829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
17830ddf06ddSHaavard Skinnemoen 		default:
17840ddf06ddSHaavard Skinnemoen 			printf("CFI: Unknown command set 0x%x\n",
17850ddf06ddSHaavard Skinnemoen 					info->vendor);
17860ddf06ddSHaavard Skinnemoen 			/*
17870ddf06ddSHaavard Skinnemoen 			 * Unfortunately, this means we don't know how
17880ddf06ddSHaavard Skinnemoen 			 * to get the chip back to Read mode. Might
17890ddf06ddSHaavard Skinnemoen 			 * as well try an Intel-style reset...
17900ddf06ddSHaavard Skinnemoen 			 */
17910ddf06ddSHaavard Skinnemoen 			flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
17920ddf06ddSHaavard Skinnemoen 			return 0;
179359829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
179459829cc1SJean-Christophe PLAGNIOL-VILLARD 
1795467bcee1SHaavard Skinnemoen 		/* Do manufacturer-specific fixups */
1796467bcee1SHaavard Skinnemoen 		switch (info->manufacturer_id) {
1797467bcee1SHaavard Skinnemoen 		case 0x0001:
1798467bcee1SHaavard Skinnemoen 			flash_fixup_amd(info, &qry);
1799467bcee1SHaavard Skinnemoen 			break;
1800467bcee1SHaavard Skinnemoen 		case 0x001f:
1801467bcee1SHaavard Skinnemoen 			flash_fixup_atmel(info, &qry);
1802467bcee1SHaavard Skinnemoen 			break;
1803467bcee1SHaavard Skinnemoen 		}
1804467bcee1SHaavard Skinnemoen 
180559829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer is %d\n", info->vendor);
180659829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
180759829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id is 0x%x\n", info->device_id);
180859829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id2 is 0x%x\n", info->device_id2);
180959829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("cfi version is 0x%04x\n", info->cfi_version);
181059829cc1SJean-Christophe PLAGNIOL-VILLARD 
181159829cc1SJean-Christophe PLAGNIOL-VILLARD 		size_ratio = info->portwidth / info->chipwidth;
181259829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* if the chip is x8/x16 reduce the ratio by half */
181359829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((info->interface == FLASH_CFI_X8X16)
181459829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && (info->chipwidth == FLASH_CFI_BY8)) {
181559829cc1SJean-Christophe PLAGNIOL-VILLARD 			size_ratio >>= 1;
181659829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
181759829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("size_ratio %d port %d bits chip %d bits\n",
181859829cc1SJean-Christophe PLAGNIOL-VILLARD 		       size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
181959829cc1SJean-Christophe PLAGNIOL-VILLARD 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
182059829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("found %d erase regions\n", num_erase_regions);
182159829cc1SJean-Christophe PLAGNIOL-VILLARD 		sect_cnt = 0;
182259829cc1SJean-Christophe PLAGNIOL-VILLARD 		sector = base;
182359829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < num_erase_regions; i++) {
182459829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (i > NUM_ERASE_REGIONS) {
182559829cc1SJean-Christophe PLAGNIOL-VILLARD 				printf ("%d erase regions found, only %d used\n",
182659829cc1SJean-Christophe PLAGNIOL-VILLARD 					num_erase_regions, NUM_ERASE_REGIONS);
182759829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
182859829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1829e23741f4SHaavard Skinnemoen 
18300ddf06ddSHaavard Skinnemoen 			tmp = le32_to_cpu(qry.erase_region_info[i]);
18310ddf06ddSHaavard Skinnemoen 			debug("erase region %u: 0x%08lx\n", i, tmp);
1832e23741f4SHaavard Skinnemoen 
1833e23741f4SHaavard Skinnemoen 			erase_region_count = (tmp & 0xffff) + 1;
1834e23741f4SHaavard Skinnemoen 			tmp >>= 16;
183559829cc1SJean-Christophe PLAGNIOL-VILLARD 			erase_region_size =
183659829cc1SJean-Christophe PLAGNIOL-VILLARD 				(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
183759829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("erase_region_count = %d erase_region_size = %d\n",
183859829cc1SJean-Christophe PLAGNIOL-VILLARD 				erase_region_count, erase_region_size);
183959829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (j = 0; j < erase_region_count; j++) {
184081b20cccSMichael Schwingen 				if (sect_cnt >= CFG_MAX_FLASH_SECT) {
184181b20cccSMichael Schwingen 					printf("ERROR: too many flash sectors\n");
184281b20cccSMichael Schwingen 					break;
184381b20cccSMichael Schwingen 				}
184459829cc1SJean-Christophe PLAGNIOL-VILLARD 				info->start[sect_cnt] = sector;
184559829cc1SJean-Christophe PLAGNIOL-VILLARD 				sector += (erase_region_size * size_ratio);
184659829cc1SJean-Christophe PLAGNIOL-VILLARD 
184759829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
18487e5b9b47SHaavard Skinnemoen 				 * Only read protection status from
18497e5b9b47SHaavard Skinnemoen 				 * supported devices (intel...)
185059829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
185159829cc1SJean-Christophe PLAGNIOL-VILLARD 				switch (info->vendor) {
18529c048b52SVasiliy Leoenenko 				case CFI_CMDSET_INTEL_PROG_REGIONS:
185359829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_EXTENDED:
185459829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_STANDARD:
185559829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->protect[sect_cnt] =
185659829cc1SJean-Christophe PLAGNIOL-VILLARD 						flash_isset (info, sect_cnt,
185759829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_OFFSET_PROTECT,
185859829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_STATUS_PROTECT);
185959829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
186059829cc1SJean-Christophe PLAGNIOL-VILLARD 				default:
18617e5b9b47SHaavard Skinnemoen 					/* default: not protected */
18627e5b9b47SHaavard Skinnemoen 					info->protect[sect_cnt] = 0;
186359829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
186459829cc1SJean-Christophe PLAGNIOL-VILLARD 
186559829cc1SJean-Christophe PLAGNIOL-VILLARD 				sect_cnt++;
186659829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
186759829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
186859829cc1SJean-Christophe PLAGNIOL-VILLARD 
186959829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->sector_count = sect_cnt;
1870e23741f4SHaavard Skinnemoen 		info->size = 1 << qry.dev_size;
187159829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* multiply the size by the number of chips */
18727e5b9b47SHaavard Skinnemoen 		info->size *= size_ratio;
1873e23741f4SHaavard Skinnemoen 		info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1874e23741f4SHaavard Skinnemoen 		tmp = 1 << qry.block_erase_timeout_typ;
18757e5b9b47SHaavard Skinnemoen 		info->erase_blk_tout = tmp *
1876e23741f4SHaavard Skinnemoen 			(1 << qry.block_erase_timeout_max);
1877e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.buf_write_timeout_typ) *
1878e23741f4SHaavard Skinnemoen 			(1 << qry.buf_write_timeout_max);
1879e23741f4SHaavard Skinnemoen 
18807e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1881e23741f4SHaavard Skinnemoen 		info->buffer_write_tout = (tmp + 999) / 1000;
1882e23741f4SHaavard Skinnemoen 		tmp = (1 << qry.word_write_timeout_typ) *
1883e23741f4SHaavard Skinnemoen 			(1 << qry.word_write_timeout_max);
18847e5b9b47SHaavard Skinnemoen 		/* round up when converting to ms */
1885e23741f4SHaavard Skinnemoen 		info->write_tout = (tmp + 999) / 1000;
188659829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->flash_id = FLASH_MAN_CFI;
18877e5b9b47SHaavard Skinnemoen 		if ((info->interface == FLASH_CFI_X8X16) &&
18887e5b9b47SHaavard Skinnemoen 		    (info->chipwidth == FLASH_CFI_BY8)) {
18897e5b9b47SHaavard Skinnemoen 			/* XXX - Need to test on x8/x16 in parallel. */
18907e5b9b47SHaavard Skinnemoen 			info->portwidth >>= 1;
189159829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
189259829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
189359829cc1SJean-Christophe PLAGNIOL-VILLARD 
189459829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
189559829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (info->size);
189659829cc1SJean-Christophe PLAGNIOL-VILLARD }
189759829cc1SJean-Christophe PLAGNIOL-VILLARD 
189859829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
189959829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1900be60a902SHaavard Skinnemoen unsigned long flash_init (void)
190159829cc1SJean-Christophe PLAGNIOL-VILLARD {
1902be60a902SHaavard Skinnemoen 	unsigned long size = 0;
1903be60a902SHaavard Skinnemoen 	int i;
1904c63ad632SMatthias Fuchs #if defined(CFG_FLASH_AUTOPROTECT_LIST)
1905c63ad632SMatthias Fuchs 	struct apl_s {
1906c63ad632SMatthias Fuchs 		ulong start;
1907c63ad632SMatthias Fuchs 		ulong size;
1908c63ad632SMatthias Fuchs 	} apl[] = CFG_FLASH_AUTOPROTECT_LIST;
1909c63ad632SMatthias Fuchs #endif
191059829cc1SJean-Christophe PLAGNIOL-VILLARD 
1911be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION
1912be60a902SHaavard Skinnemoen 	char *s = getenv("unlock");
191381b20cccSMichael Schwingen #endif
1914be60a902SHaavard Skinnemoen 
1915*2a112b23SWolfgang Denk #define BANK_BASE(i)	(((unsigned long [CFI_MAX_FLASH_BANKS])CFG_FLASH_BANKS_LIST)[i])
1916*2a112b23SWolfgang Denk 
1917be60a902SHaavard Skinnemoen 	/* Init: no FLASHes known */
1918be60a902SHaavard Skinnemoen 	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
1919be60a902SHaavard Skinnemoen 		flash_info[i].flash_id = FLASH_UNKNOWN;
1920be60a902SHaavard Skinnemoen 
1921*2a112b23SWolfgang Denk 		if (!flash_detect_legacy (BANK_BASE(i), i))
1922*2a112b23SWolfgang Denk 			flash_get_size (BANK_BASE(i), i);
1923be60a902SHaavard Skinnemoen 		size += flash_info[i].size;
1924be60a902SHaavard Skinnemoen 		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
1925be60a902SHaavard Skinnemoen #ifndef CFG_FLASH_QUIET_TEST
1926be60a902SHaavard Skinnemoen 			printf ("## Unknown FLASH on Bank %d "
1927be60a902SHaavard Skinnemoen 				"- Size = 0x%08lx = %ld MB\n",
1928be60a902SHaavard Skinnemoen 				i+1, flash_info[i].size,
1929be60a902SHaavard Skinnemoen 				flash_info[i].size << 20);
1930be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_QUIET_TEST */
193159829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1932be60a902SHaavard Skinnemoen #ifdef CFG_FLASH_PROTECTION
1933be60a902SHaavard Skinnemoen 		else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
1934be60a902SHaavard Skinnemoen 			/*
1935be60a902SHaavard Skinnemoen 			 * Only the U-Boot image and it's environment
1936be60a902SHaavard Skinnemoen 			 * is protected, all other sectors are
1937be60a902SHaavard Skinnemoen 			 * unprotected (unlocked) if flash hardware
1938be60a902SHaavard Skinnemoen 			 * protection is used (CFG_FLASH_PROTECTION)
1939be60a902SHaavard Skinnemoen 			 * and the environment variable "unlock" is
1940be60a902SHaavard Skinnemoen 			 * set to "yes".
1941be60a902SHaavard Skinnemoen 			 */
1942be60a902SHaavard Skinnemoen 			if (flash_info[i].legacy_unlock) {
1943be60a902SHaavard Skinnemoen 				int k;
194459829cc1SJean-Christophe PLAGNIOL-VILLARD 
1945be60a902SHaavard Skinnemoen 				/*
1946be60a902SHaavard Skinnemoen 				 * Disable legacy_unlock temporarily,
1947be60a902SHaavard Skinnemoen 				 * since flash_real_protect would
1948be60a902SHaavard Skinnemoen 				 * relock all other sectors again
1949be60a902SHaavard Skinnemoen 				 * otherwise.
1950be60a902SHaavard Skinnemoen 				 */
1951be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 0;
195259829cc1SJean-Christophe PLAGNIOL-VILLARD 
1953be60a902SHaavard Skinnemoen 				/*
1954be60a902SHaavard Skinnemoen 				 * Legacy unlocking (e.g. Intel J3) ->
1955be60a902SHaavard Skinnemoen 				 * unlock only one sector. This will
1956be60a902SHaavard Skinnemoen 				 * unlock all sectors.
1957be60a902SHaavard Skinnemoen 				 */
1958be60a902SHaavard Skinnemoen 				flash_real_protect (&flash_info[i], 0, 0);
195959829cc1SJean-Christophe PLAGNIOL-VILLARD 
1960be60a902SHaavard Skinnemoen 				flash_info[i].legacy_unlock = 1;
196159829cc1SJean-Christophe PLAGNIOL-VILLARD 
1962be60a902SHaavard Skinnemoen 				/*
1963be60a902SHaavard Skinnemoen 				 * Manually mark other sectors as
1964be60a902SHaavard Skinnemoen 				 * unlocked (unprotected)
1965be60a902SHaavard Skinnemoen 				 */
1966be60a902SHaavard Skinnemoen 				for (k = 1; k < flash_info[i].sector_count; k++)
1967be60a902SHaavard Skinnemoen 					flash_info[i].protect[k] = 0;
1968be60a902SHaavard Skinnemoen 			} else {
1969be60a902SHaavard Skinnemoen 				/*
1970be60a902SHaavard Skinnemoen 				 * No legancy unlocking -> unlock all sectors
1971be60a902SHaavard Skinnemoen 				 */
1972be60a902SHaavard Skinnemoen 				flash_protect (FLAG_PROTECT_CLEAR,
1973be60a902SHaavard Skinnemoen 					       flash_info[i].start[0],
1974be60a902SHaavard Skinnemoen 					       flash_info[i].start[0]
1975be60a902SHaavard Skinnemoen 					       + flash_info[i].size - 1,
1976be60a902SHaavard Skinnemoen 					       &flash_info[i]);
197759829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
197859829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1979be60a902SHaavard Skinnemoen #endif /* CFG_FLASH_PROTECTION */
198059829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
198159829cc1SJean-Christophe PLAGNIOL-VILLARD 
1982be60a902SHaavard Skinnemoen 	/* Monitor protection ON by default */
1983be60a902SHaavard Skinnemoen #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
1984be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
1985be60a902SHaavard Skinnemoen 		       CFG_MONITOR_BASE,
1986be60a902SHaavard Skinnemoen 		       CFG_MONITOR_BASE + monitor_flash_len  - 1,
1987be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_MONITOR_BASE));
1988be60a902SHaavard Skinnemoen #endif
198959829cc1SJean-Christophe PLAGNIOL-VILLARD 
1990be60a902SHaavard Skinnemoen 	/* Environment protection ON by default */
1991be60a902SHaavard Skinnemoen #ifdef CFG_ENV_IS_IN_FLASH
1992be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
1993be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR,
1994be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
1995be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_ENV_ADDR));
1996be60a902SHaavard Skinnemoen #endif
1997be60a902SHaavard Skinnemoen 
1998be60a902SHaavard Skinnemoen 	/* Redundant environment protection ON by default */
1999be60a902SHaavard Skinnemoen #ifdef CFG_ENV_ADDR_REDUND
2000be60a902SHaavard Skinnemoen 	flash_protect (FLAG_PROTECT_SET,
2001be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR_REDUND,
2002be60a902SHaavard Skinnemoen 		       CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
2003be60a902SHaavard Skinnemoen 		       flash_get_info(CFG_ENV_ADDR_REDUND));
2004be60a902SHaavard Skinnemoen #endif
2005c63ad632SMatthias Fuchs 
2006c63ad632SMatthias Fuchs #if defined(CFG_FLASH_AUTOPROTECT_LIST)
2007c63ad632SMatthias Fuchs 	for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
2008c63ad632SMatthias Fuchs 		debug("autoprotecting from %08x to %08x\n",
2009c63ad632SMatthias Fuchs 		      apl[i].start, apl[i].start + apl[i].size - 1);
2010c63ad632SMatthias Fuchs 		flash_protect (FLAG_PROTECT_SET,
2011c63ad632SMatthias Fuchs 			       apl[i].start,
2012c63ad632SMatthias Fuchs 			       apl[i].start + apl[i].size - 1,
2013c63ad632SMatthias Fuchs 			       flash_get_info(apl[i].start));
2014c63ad632SMatthias Fuchs 	}
2015c63ad632SMatthias Fuchs #endif
2016be60a902SHaavard Skinnemoen 	return (size);
201759829cc1SJean-Christophe PLAGNIOL-VILLARD }
201859829cc1SJean-Christophe PLAGNIOL-VILLARD 
201959829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_CFI */
2020