xref: /OK3568_Linux_fs/u-boot/drivers/mtd/cfi_flash.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2002-2004
3*4882a593Smuzhiyun  * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2003 Arabella Software Ltd.
6*4882a593Smuzhiyun  * Yuli Barcohen <yuli@arabellasw.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Copyright (C) 2004
9*4882a593Smuzhiyun  * Ed Okerson
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * Copyright (C) 2006
12*4882a593Smuzhiyun  * Tolunay Orkun <listmember@orkun.us>
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
15*4882a593Smuzhiyun  */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun /* The DEBUG define must be before common to enable debugging */
18*4882a593Smuzhiyun /* #define DEBUG	*/
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <common.h>
21*4882a593Smuzhiyun #include <console.h>
22*4882a593Smuzhiyun #include <dm.h>
23*4882a593Smuzhiyun #include <errno.h>
24*4882a593Smuzhiyun #include <fdt_support.h>
25*4882a593Smuzhiyun #include <asm/processor.h>
26*4882a593Smuzhiyun #include <asm/io.h>
27*4882a593Smuzhiyun #include <asm/byteorder.h>
28*4882a593Smuzhiyun #include <asm/unaligned.h>
29*4882a593Smuzhiyun #include <environment.h>
30*4882a593Smuzhiyun #include <mtd/cfi_flash.h>
31*4882a593Smuzhiyun #include <watchdog.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun  * This file implements a Common Flash Interface (CFI) driver for
35*4882a593Smuzhiyun  * U-Boot.
36*4882a593Smuzhiyun  *
37*4882a593Smuzhiyun  * The width of the port and the width of the chips are determined at
38*4882a593Smuzhiyun  * initialization.  These widths are used to calculate the address for
39*4882a593Smuzhiyun  * access CFI data structures.
40*4882a593Smuzhiyun  *
41*4882a593Smuzhiyun  * References
42*4882a593Smuzhiyun  * JEDEC Standard JESD68 - Common Flash Interface (CFI)
43*4882a593Smuzhiyun  * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
44*4882a593Smuzhiyun  * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
45*4882a593Smuzhiyun  * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
46*4882a593Smuzhiyun  * AMD CFI Specification, Release 2.0 December 1, 2001
47*4882a593Smuzhiyun  * AMD/Spansion Application Note: Migration from Single-byte to Three-byte
48*4882a593Smuzhiyun  *   Device IDs, Publication Number 25538 Revision A, November 8, 2001
49*4882a593Smuzhiyun  *
50*4882a593Smuzhiyun  * Define CONFIG_SYS_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
51*4882a593Smuzhiyun  * reading and writing ... (yes there is such a Hardware).
52*4882a593Smuzhiyun  */
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
57*4882a593Smuzhiyun #ifdef CONFIG_FLASH_CFI_MTD
58*4882a593Smuzhiyun static uint flash_verbose = 1;
59*4882a593Smuzhiyun #else
60*4882a593Smuzhiyun #define flash_verbose 1
61*4882a593Smuzhiyun #endif
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun flash_info_t flash_info[CFI_MAX_FLASH_BANKS];	/* FLASH chips info */
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun  * Check if chip width is defined. If not, start detecting with 8bit.
67*4882a593Smuzhiyun  */
68*4882a593Smuzhiyun #ifndef CONFIG_SYS_FLASH_CFI_WIDTH
69*4882a593Smuzhiyun #define CONFIG_SYS_FLASH_CFI_WIDTH	FLASH_CFI_8BIT
70*4882a593Smuzhiyun #endif
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
73*4882a593Smuzhiyun #define __maybe_weak __weak
74*4882a593Smuzhiyun #else
75*4882a593Smuzhiyun #define __maybe_weak static
76*4882a593Smuzhiyun #endif
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun /*
79*4882a593Smuzhiyun  * 0xffff is an undefined value for the configuration register. When
80*4882a593Smuzhiyun  * this value is returned, the configuration register shall not be
81*4882a593Smuzhiyun  * written at all (default mode).
82*4882a593Smuzhiyun  */
cfi_flash_config_reg(int i)83*4882a593Smuzhiyun static u16 cfi_flash_config_reg(int i)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun #ifdef CONFIG_SYS_CFI_FLASH_CONFIG_REGS
86*4882a593Smuzhiyun 	return ((u16 [])CONFIG_SYS_CFI_FLASH_CONFIG_REGS)[i];
87*4882a593Smuzhiyun #else
88*4882a593Smuzhiyun 	return 0xffff;
89*4882a593Smuzhiyun #endif
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun #if defined(CONFIG_SYS_MAX_FLASH_BANKS_DETECT)
93*4882a593Smuzhiyun int cfi_flash_num_flash_banks = CONFIG_SYS_MAX_FLASH_BANKS_DETECT;
94*4882a593Smuzhiyun #else
95*4882a593Smuzhiyun int cfi_flash_num_flash_banks;
96*4882a593Smuzhiyun #endif
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun #ifdef CONFIG_CFI_FLASH /* for driver model */
cfi_flash_init_dm(void)99*4882a593Smuzhiyun static void cfi_flash_init_dm(void)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	struct udevice *dev;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	cfi_flash_num_flash_banks = 0;
104*4882a593Smuzhiyun 	/*
105*4882a593Smuzhiyun 	 * The uclass_first_device() will probe the first device and
106*4882a593Smuzhiyun 	 * uclass_next_device() will probe the rest if they exist. So
107*4882a593Smuzhiyun 	 * that cfi_flash_probe() will get called assigning the base
108*4882a593Smuzhiyun 	 * addresses that are available.
109*4882a593Smuzhiyun 	 */
110*4882a593Smuzhiyun 	for (uclass_first_device(UCLASS_MTD, &dev);
111*4882a593Smuzhiyun 	     dev;
112*4882a593Smuzhiyun 	     uclass_next_device(&dev)) {
113*4882a593Smuzhiyun 	}
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
cfi_flash_bank_addr(int i)116*4882a593Smuzhiyun phys_addr_t cfi_flash_bank_addr(int i)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	return flash_info[i].base;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun #else
cfi_flash_bank_addr(int i)121*4882a593Smuzhiyun __weak phys_addr_t cfi_flash_bank_addr(int i)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	return ((phys_addr_t [])CONFIG_SYS_FLASH_BANKS_LIST)[i];
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun #endif
126*4882a593Smuzhiyun 
cfi_flash_bank_size(int i)127*4882a593Smuzhiyun __weak unsigned long cfi_flash_bank_size(int i)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_BANKS_SIZES
130*4882a593Smuzhiyun 	return ((unsigned long [])CONFIG_SYS_FLASH_BANKS_SIZES)[i];
131*4882a593Smuzhiyun #else
132*4882a593Smuzhiyun 	return 0;
133*4882a593Smuzhiyun #endif
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
flash_write8(u8 value,void * addr)136*4882a593Smuzhiyun __maybe_weak void flash_write8(u8 value, void *addr)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	__raw_writeb(value, addr);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
flash_write16(u16 value,void * addr)141*4882a593Smuzhiyun __maybe_weak void flash_write16(u16 value, void *addr)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	__raw_writew(value, addr);
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
flash_write32(u32 value,void * addr)146*4882a593Smuzhiyun __maybe_weak void flash_write32(u32 value, void *addr)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	__raw_writel(value, addr);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
flash_write64(u64 value,void * addr)151*4882a593Smuzhiyun __maybe_weak void flash_write64(u64 value, void *addr)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	/* No architectures currently implement __raw_writeq() */
154*4882a593Smuzhiyun 	*(volatile u64 *)addr = value;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun 
flash_read8(void * addr)157*4882a593Smuzhiyun __maybe_weak u8 flash_read8(void *addr)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	return __raw_readb(addr);
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
flash_read16(void * addr)162*4882a593Smuzhiyun __maybe_weak u16 flash_read16(void *addr)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	return __raw_readw(addr);
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
flash_read32(void * addr)167*4882a593Smuzhiyun __maybe_weak u32 flash_read32(void *addr)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	return __raw_readl(addr);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
flash_read64(void * addr)172*4882a593Smuzhiyun __maybe_weak u64 flash_read64(void *addr)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	/* No architectures currently implement __raw_readq() */
175*4882a593Smuzhiyun 	return *(volatile u64 *)addr;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun /*-----------------------------------------------------------------------
179*4882a593Smuzhiyun  */
180*4882a593Smuzhiyun #if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || \
181*4882a593Smuzhiyun 	(CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
flash_get_info(ulong base)182*4882a593Smuzhiyun static flash_info_t *flash_get_info(ulong base)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun 	int i;
185*4882a593Smuzhiyun 	flash_info_t *info;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
188*4882a593Smuzhiyun 		info = &flash_info[i];
189*4882a593Smuzhiyun 		if (info->size && info->start[0] <= base &&
190*4882a593Smuzhiyun 		    base <= info->start[0] + info->size - 1)
191*4882a593Smuzhiyun 			return info;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	return NULL;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun #endif
197*4882a593Smuzhiyun 
flash_sector_size(flash_info_t * info,flash_sect_t sect)198*4882a593Smuzhiyun unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun 	if (sect != (info->sector_count - 1))
201*4882a593Smuzhiyun 		return info->start[sect + 1] - info->start[sect];
202*4882a593Smuzhiyun 	else
203*4882a593Smuzhiyun 		return info->start[0] + info->size - info->start[sect];
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun /*-----------------------------------------------------------------------
207*4882a593Smuzhiyun  * create an address based on the offset and the port width
208*4882a593Smuzhiyun  */
209*4882a593Smuzhiyun static inline void *
flash_map(flash_info_t * info,flash_sect_t sect,uint offset)210*4882a593Smuzhiyun flash_map(flash_info_t *info, flash_sect_t sect, uint offset)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	unsigned int byte_offset = offset * info->portwidth;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	return (void *)(info->start[sect] + byte_offset);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
flash_unmap(flash_info_t * info,flash_sect_t sect,unsigned int offset,void * addr)217*4882a593Smuzhiyun static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
218*4882a593Smuzhiyun 			       unsigned int offset, void *addr)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun /*-----------------------------------------------------------------------
223*4882a593Smuzhiyun  * make a proper sized command based on the port and chip widths
224*4882a593Smuzhiyun  */
flash_make_cmd(flash_info_t * info,u32 cmd,void * cmdbuf)225*4882a593Smuzhiyun static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	int i;
228*4882a593Smuzhiyun 	int cword_offset;
229*4882a593Smuzhiyun 	int cp_offset;
230*4882a593Smuzhiyun #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
231*4882a593Smuzhiyun 	u32 cmd_le = cpu_to_le32(cmd);
232*4882a593Smuzhiyun #endif
233*4882a593Smuzhiyun 	uchar val;
234*4882a593Smuzhiyun 	uchar *cp = (uchar *) cmdbuf;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	for (i = info->portwidth; i > 0; i--) {
237*4882a593Smuzhiyun 		cword_offset = (info->portwidth - i) % info->chipwidth;
238*4882a593Smuzhiyun #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
239*4882a593Smuzhiyun 		cp_offset = info->portwidth - i;
240*4882a593Smuzhiyun 		val = *((uchar *)&cmd_le + cword_offset);
241*4882a593Smuzhiyun #else
242*4882a593Smuzhiyun 		cp_offset = i - 1;
243*4882a593Smuzhiyun 		val = *((uchar *)&cmd + sizeof(u32) - cword_offset - 1);
244*4882a593Smuzhiyun #endif
245*4882a593Smuzhiyun 		cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun #ifdef DEBUG
250*4882a593Smuzhiyun /*-----------------------------------------------------------------------
251*4882a593Smuzhiyun  * Debug support
252*4882a593Smuzhiyun  */
print_longlong(char * str,unsigned long long data)253*4882a593Smuzhiyun static void print_longlong(char *str, unsigned long long data)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun 	int i;
256*4882a593Smuzhiyun 	char *cp;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	cp = (char *)&data;
259*4882a593Smuzhiyun 	for (i = 0; i < 8; i++)
260*4882a593Smuzhiyun 		sprintf(&str[i * 2], "%2.2x", *cp++);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
flash_printqry(struct cfi_qry * qry)263*4882a593Smuzhiyun static void flash_printqry(struct cfi_qry *qry)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	u8 *p = (u8 *)qry;
266*4882a593Smuzhiyun 	int x, y;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
269*4882a593Smuzhiyun 		debug("%02x : ", x);
270*4882a593Smuzhiyun 		for (y = 0; y < 16; y++)
271*4882a593Smuzhiyun 			debug("%2.2x ", p[x + y]);
272*4882a593Smuzhiyun 		debug(" ");
273*4882a593Smuzhiyun 		for (y = 0; y < 16; y++) {
274*4882a593Smuzhiyun 			unsigned char c = p[x + y];
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 			if (c >= 0x20 && c <= 0x7e)
277*4882a593Smuzhiyun 				debug("%c", c);
278*4882a593Smuzhiyun 			else
279*4882a593Smuzhiyun 				debug(".");
280*4882a593Smuzhiyun 		}
281*4882a593Smuzhiyun 		debug("\n");
282*4882a593Smuzhiyun 	}
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun #endif
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun /*-----------------------------------------------------------------------
287*4882a593Smuzhiyun  * read a character at a port width address
288*4882a593Smuzhiyun  */
flash_read_uchar(flash_info_t * info,uint offset)289*4882a593Smuzhiyun static inline uchar flash_read_uchar(flash_info_t *info, uint offset)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	uchar *cp;
292*4882a593Smuzhiyun 	uchar retval;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	cp = flash_map(info, 0, offset);
295*4882a593Smuzhiyun #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
296*4882a593Smuzhiyun 	retval = flash_read8(cp);
297*4882a593Smuzhiyun #else
298*4882a593Smuzhiyun 	retval = flash_read8(cp + info->portwidth - 1);
299*4882a593Smuzhiyun #endif
300*4882a593Smuzhiyun 	flash_unmap(info, 0, offset, cp);
301*4882a593Smuzhiyun 	return retval;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun /*-----------------------------------------------------------------------
305*4882a593Smuzhiyun  * read a word at a port width address, assume 16bit bus
306*4882a593Smuzhiyun  */
flash_read_word(flash_info_t * info,uint offset)307*4882a593Smuzhiyun static inline ushort flash_read_word(flash_info_t *info, uint offset)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	ushort *addr, retval;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	addr = flash_map(info, 0, offset);
312*4882a593Smuzhiyun 	retval = flash_read16(addr);
313*4882a593Smuzhiyun 	flash_unmap(info, 0, offset, addr);
314*4882a593Smuzhiyun 	return retval;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun /*-----------------------------------------------------------------------
318*4882a593Smuzhiyun  * read a long word by picking the least significant byte of each maximum
319*4882a593Smuzhiyun  * port size word. Swap for ppc format.
320*4882a593Smuzhiyun  */
flash_read_long(flash_info_t * info,flash_sect_t sect,uint offset)321*4882a593Smuzhiyun static ulong flash_read_long (flash_info_t *info, flash_sect_t sect,
322*4882a593Smuzhiyun 			      uint offset)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	uchar *addr;
325*4882a593Smuzhiyun 	ulong retval;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun #ifdef DEBUG
328*4882a593Smuzhiyun 	int x;
329*4882a593Smuzhiyun #endif
330*4882a593Smuzhiyun 	addr = flash_map(info, sect, offset);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun #ifdef DEBUG
333*4882a593Smuzhiyun 	debug("long addr is at %p info->portwidth = %d\n", addr,
334*4882a593Smuzhiyun 	      info->portwidth);
335*4882a593Smuzhiyun 	for (x = 0; x < 4 * info->portwidth; x++)
336*4882a593Smuzhiyun 		debug("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
337*4882a593Smuzhiyun #endif
338*4882a593Smuzhiyun #if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
339*4882a593Smuzhiyun 	retval = ((flash_read8(addr) << 16) |
340*4882a593Smuzhiyun 		  (flash_read8(addr + info->portwidth) << 24) |
341*4882a593Smuzhiyun 		  (flash_read8(addr + 2 * info->portwidth)) |
342*4882a593Smuzhiyun 		  (flash_read8(addr + 3 * info->portwidth) << 8));
343*4882a593Smuzhiyun #else
344*4882a593Smuzhiyun 	retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
345*4882a593Smuzhiyun 		  (flash_read8(addr + info->portwidth - 1) << 16) |
346*4882a593Smuzhiyun 		  (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
347*4882a593Smuzhiyun 		  (flash_read8(addr + 3 * info->portwidth - 1)));
348*4882a593Smuzhiyun #endif
349*4882a593Smuzhiyun 	flash_unmap(info, sect, offset, addr);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	return retval;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun /*
355*4882a593Smuzhiyun  * Write a proper sized command to the correct address
356*4882a593Smuzhiyun  */
flash_write_cmd(flash_info_t * info,flash_sect_t sect,uint offset,u32 cmd)357*4882a593Smuzhiyun static void flash_write_cmd(flash_info_t *info, flash_sect_t sect,
358*4882a593Smuzhiyun 			    uint offset, u32 cmd)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun 	void *addr;
361*4882a593Smuzhiyun 	cfiword_t cword;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	addr = flash_map(info, sect, offset);
364*4882a593Smuzhiyun 	flash_make_cmd(info, cmd, &cword);
365*4882a593Smuzhiyun 	switch (info->portwidth) {
366*4882a593Smuzhiyun 	case FLASH_CFI_8BIT:
367*4882a593Smuzhiyun 		debug("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
368*4882a593Smuzhiyun 		      cword.w8, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
369*4882a593Smuzhiyun 		flash_write8(cword.w8, addr);
370*4882a593Smuzhiyun 		break;
371*4882a593Smuzhiyun 	case FLASH_CFI_16BIT:
372*4882a593Smuzhiyun 		debug("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
373*4882a593Smuzhiyun 		      cmd, cword.w16,
374*4882a593Smuzhiyun 		      info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
375*4882a593Smuzhiyun 		flash_write16(cword.w16, addr);
376*4882a593Smuzhiyun 		break;
377*4882a593Smuzhiyun 	case FLASH_CFI_32BIT:
378*4882a593Smuzhiyun 		debug("fwc addr %p cmd %x %8.8x 32bit x %d bit\n", addr,
379*4882a593Smuzhiyun 		      cmd, cword.w32,
380*4882a593Smuzhiyun 		      info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
381*4882a593Smuzhiyun 		flash_write32(cword.w32, addr);
382*4882a593Smuzhiyun 		break;
383*4882a593Smuzhiyun 	case FLASH_CFI_64BIT:
384*4882a593Smuzhiyun #ifdef DEBUG
385*4882a593Smuzhiyun 		{
386*4882a593Smuzhiyun 			char str[20];
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 			print_longlong(str, cword.w64);
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 			debug("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
391*4882a593Smuzhiyun 			      addr, cmd, str,
392*4882a593Smuzhiyun 			      info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
393*4882a593Smuzhiyun 		}
394*4882a593Smuzhiyun #endif
395*4882a593Smuzhiyun 		flash_write64(cword.w64, addr);
396*4882a593Smuzhiyun 		break;
397*4882a593Smuzhiyun 	}
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/* Ensure all the instructions are fully finished */
400*4882a593Smuzhiyun 	sync();
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	flash_unmap(info, sect, offset, addr);
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun 
flash_unlock_seq(flash_info_t * info,flash_sect_t sect)405*4882a593Smuzhiyun static void flash_unlock_seq(flash_info_t *info, flash_sect_t sect)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	flash_write_cmd(info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
408*4882a593Smuzhiyun 	flash_write_cmd(info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun /*-----------------------------------------------------------------------
412*4882a593Smuzhiyun  */
flash_isequal(flash_info_t * info,flash_sect_t sect,uint offset,uchar cmd)413*4882a593Smuzhiyun static int flash_isequal(flash_info_t *info, flash_sect_t sect, uint offset,
414*4882a593Smuzhiyun 			 uchar cmd)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun 	void *addr;
417*4882a593Smuzhiyun 	cfiword_t cword;
418*4882a593Smuzhiyun 	int retval;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	addr = flash_map(info, sect, offset);
421*4882a593Smuzhiyun 	flash_make_cmd(info, cmd, &cword);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	debug("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
424*4882a593Smuzhiyun 	switch (info->portwidth) {
425*4882a593Smuzhiyun 	case FLASH_CFI_8BIT:
426*4882a593Smuzhiyun 		debug("is= %x %x\n", flash_read8(addr), cword.w8);
427*4882a593Smuzhiyun 		retval = (flash_read8(addr) == cword.w8);
428*4882a593Smuzhiyun 		break;
429*4882a593Smuzhiyun 	case FLASH_CFI_16BIT:
430*4882a593Smuzhiyun 		debug("is= %4.4x %4.4x\n", flash_read16(addr), cword.w16);
431*4882a593Smuzhiyun 		retval = (flash_read16(addr) == cword.w16);
432*4882a593Smuzhiyun 		break;
433*4882a593Smuzhiyun 	case FLASH_CFI_32BIT:
434*4882a593Smuzhiyun 		debug("is= %8.8x %8.8x\n", flash_read32(addr), cword.w32);
435*4882a593Smuzhiyun 		retval = (flash_read32(addr) == cword.w32);
436*4882a593Smuzhiyun 		break;
437*4882a593Smuzhiyun 	case FLASH_CFI_64BIT:
438*4882a593Smuzhiyun #ifdef DEBUG
439*4882a593Smuzhiyun 		{
440*4882a593Smuzhiyun 			char str1[20];
441*4882a593Smuzhiyun 			char str2[20];
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 			print_longlong(str1, flash_read64(addr));
444*4882a593Smuzhiyun 			print_longlong(str2, cword.w64);
445*4882a593Smuzhiyun 			debug("is= %s %s\n", str1, str2);
446*4882a593Smuzhiyun 		}
447*4882a593Smuzhiyun #endif
448*4882a593Smuzhiyun 		retval = (flash_read64(addr) == cword.w64);
449*4882a593Smuzhiyun 		break;
450*4882a593Smuzhiyun 	default:
451*4882a593Smuzhiyun 		retval = 0;
452*4882a593Smuzhiyun 		break;
453*4882a593Smuzhiyun 	}
454*4882a593Smuzhiyun 	flash_unmap(info, sect, offset, addr);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	return retval;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun /*-----------------------------------------------------------------------
460*4882a593Smuzhiyun  */
flash_isset(flash_info_t * info,flash_sect_t sect,uint offset,uchar cmd)461*4882a593Smuzhiyun static int flash_isset(flash_info_t *info, flash_sect_t sect, uint offset,
462*4882a593Smuzhiyun 		       uchar cmd)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun 	void *addr;
465*4882a593Smuzhiyun 	cfiword_t cword;
466*4882a593Smuzhiyun 	int retval;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	addr = flash_map(info, sect, offset);
469*4882a593Smuzhiyun 	flash_make_cmd(info, cmd, &cword);
470*4882a593Smuzhiyun 	switch (info->portwidth) {
471*4882a593Smuzhiyun 	case FLASH_CFI_8BIT:
472*4882a593Smuzhiyun 		retval = ((flash_read8(addr) & cword.w8) == cword.w8);
473*4882a593Smuzhiyun 		break;
474*4882a593Smuzhiyun 	case FLASH_CFI_16BIT:
475*4882a593Smuzhiyun 		retval = ((flash_read16(addr) & cword.w16) == cword.w16);
476*4882a593Smuzhiyun 		break;
477*4882a593Smuzhiyun 	case FLASH_CFI_32BIT:
478*4882a593Smuzhiyun 		retval = ((flash_read32(addr) & cword.w32) == cword.w32);
479*4882a593Smuzhiyun 		break;
480*4882a593Smuzhiyun 	case FLASH_CFI_64BIT:
481*4882a593Smuzhiyun 		retval = ((flash_read64(addr) & cword.w64) == cword.w64);
482*4882a593Smuzhiyun 		break;
483*4882a593Smuzhiyun 	default:
484*4882a593Smuzhiyun 		retval = 0;
485*4882a593Smuzhiyun 		break;
486*4882a593Smuzhiyun 	}
487*4882a593Smuzhiyun 	flash_unmap(info, sect, offset, addr);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	return retval;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun /*-----------------------------------------------------------------------
493*4882a593Smuzhiyun  */
flash_toggle(flash_info_t * info,flash_sect_t sect,uint offset,uchar cmd)494*4882a593Smuzhiyun static int flash_toggle(flash_info_t *info, flash_sect_t sect, uint offset,
495*4882a593Smuzhiyun 			uchar cmd)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun 	u8 *addr;
498*4882a593Smuzhiyun 	cfiword_t cword;
499*4882a593Smuzhiyun 	int retval;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	addr = flash_map(info, sect, offset);
502*4882a593Smuzhiyun 	flash_make_cmd(info, cmd, &cword);
503*4882a593Smuzhiyun 	switch (info->portwidth) {
504*4882a593Smuzhiyun 	case FLASH_CFI_8BIT:
505*4882a593Smuzhiyun 		retval = flash_read8(addr) != flash_read8(addr);
506*4882a593Smuzhiyun 		break;
507*4882a593Smuzhiyun 	case FLASH_CFI_16BIT:
508*4882a593Smuzhiyun 		retval = flash_read16(addr) != flash_read16(addr);
509*4882a593Smuzhiyun 		break;
510*4882a593Smuzhiyun 	case FLASH_CFI_32BIT:
511*4882a593Smuzhiyun 		retval = flash_read32(addr) != flash_read32(addr);
512*4882a593Smuzhiyun 		break;
513*4882a593Smuzhiyun 	case FLASH_CFI_64BIT:
514*4882a593Smuzhiyun 		retval = ((flash_read32(addr) != flash_read32(addr)) ||
515*4882a593Smuzhiyun 			   (flash_read32(addr + 4) != flash_read32(addr + 4)));
516*4882a593Smuzhiyun 		break;
517*4882a593Smuzhiyun 	default:
518*4882a593Smuzhiyun 		retval = 0;
519*4882a593Smuzhiyun 		break;
520*4882a593Smuzhiyun 	}
521*4882a593Smuzhiyun 	flash_unmap(info, sect, offset, addr);
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	return retval;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun /*
527*4882a593Smuzhiyun  * flash_is_busy - check to see if the flash is busy
528*4882a593Smuzhiyun  *
529*4882a593Smuzhiyun  * This routine checks the status of the chip and returns true if the
530*4882a593Smuzhiyun  * chip is busy.
531*4882a593Smuzhiyun  */
flash_is_busy(flash_info_t * info,flash_sect_t sect)532*4882a593Smuzhiyun static int flash_is_busy(flash_info_t *info, flash_sect_t sect)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun 	int retval;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	switch (info->vendor) {
537*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_PROG_REGIONS:
538*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_STANDARD:
539*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_EXTENDED:
540*4882a593Smuzhiyun 		retval = !flash_isset(info, sect, 0, FLASH_STATUS_DONE);
541*4882a593Smuzhiyun 		break;
542*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_STANDARD:
543*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_EXTENDED:
544*4882a593Smuzhiyun #ifdef CONFIG_FLASH_CFI_LEGACY
545*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_LEGACY:
546*4882a593Smuzhiyun #endif
547*4882a593Smuzhiyun 		if (info->sr_supported) {
548*4882a593Smuzhiyun 			flash_write_cmd(info, sect, info->addr_unlock1,
549*4882a593Smuzhiyun 					FLASH_CMD_READ_STATUS);
550*4882a593Smuzhiyun 			retval = !flash_isset(info, sect, 0,
551*4882a593Smuzhiyun 					      FLASH_STATUS_DONE);
552*4882a593Smuzhiyun 		} else {
553*4882a593Smuzhiyun 			retval = flash_toggle(info, sect, 0,
554*4882a593Smuzhiyun 					      AMD_STATUS_TOGGLE);
555*4882a593Smuzhiyun 		}
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 		break;
558*4882a593Smuzhiyun 	default:
559*4882a593Smuzhiyun 		retval = 0;
560*4882a593Smuzhiyun 	}
561*4882a593Smuzhiyun 	debug("%s: %d\n", __func__, retval);
562*4882a593Smuzhiyun 	return retval;
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun /*-----------------------------------------------------------------------
566*4882a593Smuzhiyun  *  wait for XSR.7 to be set. Time out with an error if it does not.
567*4882a593Smuzhiyun  *  This routine does not set the flash to read-array mode.
568*4882a593Smuzhiyun  */
flash_status_check(flash_info_t * info,flash_sect_t sector,ulong tout,char * prompt)569*4882a593Smuzhiyun static int flash_status_check(flash_info_t *info, flash_sect_t sector,
570*4882a593Smuzhiyun 			      ulong tout, char *prompt)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun 	ulong start;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun #if CONFIG_SYS_HZ != 1000
575*4882a593Smuzhiyun 	/* Avoid overflow for large HZ */
576*4882a593Smuzhiyun 	if ((ulong)CONFIG_SYS_HZ > 100000)
577*4882a593Smuzhiyun 		tout *= (ulong)CONFIG_SYS_HZ / 1000;
578*4882a593Smuzhiyun 	else
579*4882a593Smuzhiyun 		tout = DIV_ROUND_UP(tout * (ulong)CONFIG_SYS_HZ, 1000);
580*4882a593Smuzhiyun #endif
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	/* Wait for command completion */
583*4882a593Smuzhiyun #ifdef CONFIG_SYS_LOW_RES_TIMER
584*4882a593Smuzhiyun 	reset_timer();
585*4882a593Smuzhiyun #endif
586*4882a593Smuzhiyun 	start = get_timer(0);
587*4882a593Smuzhiyun 	WATCHDOG_RESET();
588*4882a593Smuzhiyun 	while (flash_is_busy(info, sector)) {
589*4882a593Smuzhiyun 		if (get_timer(start) > tout) {
590*4882a593Smuzhiyun 			printf("Flash %s timeout at address %lx data %lx\n",
591*4882a593Smuzhiyun 			       prompt, info->start[sector],
592*4882a593Smuzhiyun 			       flash_read_long(info, sector, 0));
593*4882a593Smuzhiyun 			flash_write_cmd(info, sector, 0, info->cmd_reset);
594*4882a593Smuzhiyun 			udelay(1);
595*4882a593Smuzhiyun 			return ERR_TIMEOUT;
596*4882a593Smuzhiyun 		}
597*4882a593Smuzhiyun 		udelay(1);		/* also triggers watchdog */
598*4882a593Smuzhiyun 	}
599*4882a593Smuzhiyun 	return ERR_OK;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun /*-----------------------------------------------------------------------
603*4882a593Smuzhiyun  * Wait for XSR.7 to be set, if it times out print an error, otherwise
604*4882a593Smuzhiyun  * do a full status check.
605*4882a593Smuzhiyun  *
606*4882a593Smuzhiyun  * This routine sets the flash to read-array mode.
607*4882a593Smuzhiyun  */
flash_full_status_check(flash_info_t * info,flash_sect_t sector,ulong tout,char * prompt)608*4882a593Smuzhiyun static int flash_full_status_check(flash_info_t *info, flash_sect_t sector,
609*4882a593Smuzhiyun 				   ulong tout, char *prompt)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun 	int retcode;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	retcode = flash_status_check(info, sector, tout, prompt);
614*4882a593Smuzhiyun 	switch (info->vendor) {
615*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_PROG_REGIONS:
616*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_EXTENDED:
617*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_STANDARD:
618*4882a593Smuzhiyun 		if (retcode == ERR_OK &&
619*4882a593Smuzhiyun 		    !flash_isset(info, sector, 0, FLASH_STATUS_DONE)) {
620*4882a593Smuzhiyun 			retcode = ERR_INVAL;
621*4882a593Smuzhiyun 			printf("Flash %s error at address %lx\n", prompt,
622*4882a593Smuzhiyun 			       info->start[sector]);
623*4882a593Smuzhiyun 			if (flash_isset(info, sector, 0, FLASH_STATUS_ECLBS |
624*4882a593Smuzhiyun 					 FLASH_STATUS_PSLBS)) {
625*4882a593Smuzhiyun 				puts("Command Sequence Error.\n");
626*4882a593Smuzhiyun 			} else if (flash_isset(info, sector, 0,
627*4882a593Smuzhiyun 						FLASH_STATUS_ECLBS)) {
628*4882a593Smuzhiyun 				puts("Block Erase Error.\n");
629*4882a593Smuzhiyun 				retcode = ERR_NOT_ERASED;
630*4882a593Smuzhiyun 			} else if (flash_isset(info, sector, 0,
631*4882a593Smuzhiyun 						FLASH_STATUS_PSLBS)) {
632*4882a593Smuzhiyun 				puts("Locking Error\n");
633*4882a593Smuzhiyun 			}
634*4882a593Smuzhiyun 			if (flash_isset(info, sector, 0, FLASH_STATUS_DPS)) {
635*4882a593Smuzhiyun 				puts("Block locked.\n");
636*4882a593Smuzhiyun 				retcode = ERR_PROTECTED;
637*4882a593Smuzhiyun 			}
638*4882a593Smuzhiyun 			if (flash_isset(info, sector, 0, FLASH_STATUS_VPENS))
639*4882a593Smuzhiyun 				puts("Vpp Low Error.\n");
640*4882a593Smuzhiyun 		}
641*4882a593Smuzhiyun 		flash_write_cmd(info, sector, 0, info->cmd_reset);
642*4882a593Smuzhiyun 		udelay(1);
643*4882a593Smuzhiyun 		break;
644*4882a593Smuzhiyun 	default:
645*4882a593Smuzhiyun 		break;
646*4882a593Smuzhiyun 	}
647*4882a593Smuzhiyun 	return retcode;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun 
use_flash_status_poll(flash_info_t * info)650*4882a593Smuzhiyun static int use_flash_status_poll(flash_info_t *info)
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun #ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL
653*4882a593Smuzhiyun 	if (info->vendor == CFI_CMDSET_AMD_EXTENDED ||
654*4882a593Smuzhiyun 	    info->vendor == CFI_CMDSET_AMD_STANDARD)
655*4882a593Smuzhiyun 		return 1;
656*4882a593Smuzhiyun #endif
657*4882a593Smuzhiyun 	return 0;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun 
flash_status_poll(flash_info_t * info,void * src,void * dst,ulong tout,char * prompt)660*4882a593Smuzhiyun static int flash_status_poll(flash_info_t *info, void *src, void *dst,
661*4882a593Smuzhiyun 			     ulong tout, char *prompt)
662*4882a593Smuzhiyun {
663*4882a593Smuzhiyun #ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL
664*4882a593Smuzhiyun 	ulong start;
665*4882a593Smuzhiyun 	int ready;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun #if CONFIG_SYS_HZ != 1000
668*4882a593Smuzhiyun 	/* Avoid overflow for large HZ */
669*4882a593Smuzhiyun 	if ((ulong)CONFIG_SYS_HZ > 100000)
670*4882a593Smuzhiyun 		tout *= (ulong)CONFIG_SYS_HZ / 1000;
671*4882a593Smuzhiyun 	else
672*4882a593Smuzhiyun 		tout = DIV_ROUND_UP(tout * (ulong)CONFIG_SYS_HZ, 1000);
673*4882a593Smuzhiyun #endif
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 	/* Wait for command completion */
676*4882a593Smuzhiyun #ifdef CONFIG_SYS_LOW_RES_TIMER
677*4882a593Smuzhiyun 	reset_timer();
678*4882a593Smuzhiyun #endif
679*4882a593Smuzhiyun 	start = get_timer(0);
680*4882a593Smuzhiyun 	WATCHDOG_RESET();
681*4882a593Smuzhiyun 	while (1) {
682*4882a593Smuzhiyun 		switch (info->portwidth) {
683*4882a593Smuzhiyun 		case FLASH_CFI_8BIT:
684*4882a593Smuzhiyun 			ready = flash_read8(dst) == flash_read8(src);
685*4882a593Smuzhiyun 			break;
686*4882a593Smuzhiyun 		case FLASH_CFI_16BIT:
687*4882a593Smuzhiyun 			ready = flash_read16(dst) == flash_read16(src);
688*4882a593Smuzhiyun 			break;
689*4882a593Smuzhiyun 		case FLASH_CFI_32BIT:
690*4882a593Smuzhiyun 			ready = flash_read32(dst) == flash_read32(src);
691*4882a593Smuzhiyun 			break;
692*4882a593Smuzhiyun 		case FLASH_CFI_64BIT:
693*4882a593Smuzhiyun 			ready = flash_read64(dst) == flash_read64(src);
694*4882a593Smuzhiyun 			break;
695*4882a593Smuzhiyun 		default:
696*4882a593Smuzhiyun 			ready = 0;
697*4882a593Smuzhiyun 			break;
698*4882a593Smuzhiyun 		}
699*4882a593Smuzhiyun 		if (ready)
700*4882a593Smuzhiyun 			break;
701*4882a593Smuzhiyun 		if (get_timer(start) > tout) {
702*4882a593Smuzhiyun 			printf("Flash %s timeout at address %lx data %lx\n",
703*4882a593Smuzhiyun 			       prompt, (ulong)dst, (ulong)flash_read8(dst));
704*4882a593Smuzhiyun 			return ERR_TIMEOUT;
705*4882a593Smuzhiyun 		}
706*4882a593Smuzhiyun 		udelay(1);		/* also triggers watchdog */
707*4882a593Smuzhiyun 	}
708*4882a593Smuzhiyun #endif /* CONFIG_SYS_CFI_FLASH_STATUS_POLL */
709*4882a593Smuzhiyun 	return ERR_OK;
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun /*-----------------------------------------------------------------------
713*4882a593Smuzhiyun  */
flash_add_byte(flash_info_t * info,cfiword_t * cword,uchar c)714*4882a593Smuzhiyun static void flash_add_byte(flash_info_t *info, cfiword_t *cword, uchar c)
715*4882a593Smuzhiyun {
716*4882a593Smuzhiyun #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
717*4882a593Smuzhiyun 	unsigned short	w;
718*4882a593Smuzhiyun 	unsigned int	l;
719*4882a593Smuzhiyun 	unsigned long long ll;
720*4882a593Smuzhiyun #endif
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	switch (info->portwidth) {
723*4882a593Smuzhiyun 	case FLASH_CFI_8BIT:
724*4882a593Smuzhiyun 		cword->w8 = c;
725*4882a593Smuzhiyun 		break;
726*4882a593Smuzhiyun 	case FLASH_CFI_16BIT:
727*4882a593Smuzhiyun #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
728*4882a593Smuzhiyun 		w = c;
729*4882a593Smuzhiyun 		w <<= 8;
730*4882a593Smuzhiyun 		cword->w16 = (cword->w16 >> 8) | w;
731*4882a593Smuzhiyun #else
732*4882a593Smuzhiyun 		cword->w16 = (cword->w16 << 8) | c;
733*4882a593Smuzhiyun #endif
734*4882a593Smuzhiyun 		break;
735*4882a593Smuzhiyun 	case FLASH_CFI_32BIT:
736*4882a593Smuzhiyun #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
737*4882a593Smuzhiyun 		l = c;
738*4882a593Smuzhiyun 		l <<= 24;
739*4882a593Smuzhiyun 		cword->w32 = (cword->w32 >> 8) | l;
740*4882a593Smuzhiyun #else
741*4882a593Smuzhiyun 		cword->w32 = (cword->w32 << 8) | c;
742*4882a593Smuzhiyun #endif
743*4882a593Smuzhiyun 		break;
744*4882a593Smuzhiyun 	case FLASH_CFI_64BIT:
745*4882a593Smuzhiyun #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
746*4882a593Smuzhiyun 		ll = c;
747*4882a593Smuzhiyun 		ll <<= 56;
748*4882a593Smuzhiyun 		cword->w64 = (cword->w64 >> 8) | ll;
749*4882a593Smuzhiyun #else
750*4882a593Smuzhiyun 		cword->w64 = (cword->w64 << 8) | c;
751*4882a593Smuzhiyun #endif
752*4882a593Smuzhiyun 		break;
753*4882a593Smuzhiyun 	}
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun /*
757*4882a593Smuzhiyun  * Loop through the sector table starting from the previously found sector.
758*4882a593Smuzhiyun  * Searches forwards or backwards, dependent on the passed address.
759*4882a593Smuzhiyun  */
find_sector(flash_info_t * info,ulong addr)760*4882a593Smuzhiyun static flash_sect_t find_sector(flash_info_t *info, ulong addr)
761*4882a593Smuzhiyun {
762*4882a593Smuzhiyun 	static flash_sect_t saved_sector; /* previously found sector */
763*4882a593Smuzhiyun 	static flash_info_t *saved_info; /* previously used flash bank */
764*4882a593Smuzhiyun 	flash_sect_t sector = saved_sector;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	if (info != saved_info || sector >= info->sector_count)
767*4882a593Smuzhiyun 		sector = 0;
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	while ((sector < info->sector_count - 1) &&
770*4882a593Smuzhiyun 	       (info->start[sector] < addr))
771*4882a593Smuzhiyun 		sector++;
772*4882a593Smuzhiyun 	while ((info->start[sector] > addr) && (sector > 0))
773*4882a593Smuzhiyun 		/*
774*4882a593Smuzhiyun 		 * also decrements the sector in case of an overshot
775*4882a593Smuzhiyun 		 * in the first loop
776*4882a593Smuzhiyun 		 */
777*4882a593Smuzhiyun 		sector--;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	saved_sector = sector;
780*4882a593Smuzhiyun 	saved_info = info;
781*4882a593Smuzhiyun 	return sector;
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun /*-----------------------------------------------------------------------
785*4882a593Smuzhiyun  */
flash_write_cfiword(flash_info_t * info,ulong dest,cfiword_t cword)786*4882a593Smuzhiyun static int flash_write_cfiword(flash_info_t *info, ulong dest, cfiword_t cword)
787*4882a593Smuzhiyun {
788*4882a593Smuzhiyun 	void *dstaddr = (void *)dest;
789*4882a593Smuzhiyun 	int flag;
790*4882a593Smuzhiyun 	flash_sect_t sect = 0;
791*4882a593Smuzhiyun 	char sect_found = 0;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	/* Check if Flash is (sufficiently) erased */
794*4882a593Smuzhiyun 	switch (info->portwidth) {
795*4882a593Smuzhiyun 	case FLASH_CFI_8BIT:
796*4882a593Smuzhiyun 		flag = ((flash_read8(dstaddr) & cword.w8) == cword.w8);
797*4882a593Smuzhiyun 		break;
798*4882a593Smuzhiyun 	case FLASH_CFI_16BIT:
799*4882a593Smuzhiyun 		flag = ((flash_read16(dstaddr) & cword.w16) == cword.w16);
800*4882a593Smuzhiyun 		break;
801*4882a593Smuzhiyun 	case FLASH_CFI_32BIT:
802*4882a593Smuzhiyun 		flag = ((flash_read32(dstaddr) & cword.w32) == cword.w32);
803*4882a593Smuzhiyun 		break;
804*4882a593Smuzhiyun 	case FLASH_CFI_64BIT:
805*4882a593Smuzhiyun 		flag = ((flash_read64(dstaddr) & cword.w64) == cword.w64);
806*4882a593Smuzhiyun 		break;
807*4882a593Smuzhiyun 	default:
808*4882a593Smuzhiyun 		flag = 0;
809*4882a593Smuzhiyun 		break;
810*4882a593Smuzhiyun 	}
811*4882a593Smuzhiyun 	if (!flag)
812*4882a593Smuzhiyun 		return ERR_NOT_ERASED;
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 	/* Disable interrupts which might cause a timeout here */
815*4882a593Smuzhiyun 	flag = disable_interrupts();
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	switch (info->vendor) {
818*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_PROG_REGIONS:
819*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_EXTENDED:
820*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_STANDARD:
821*4882a593Smuzhiyun 		flash_write_cmd(info, 0, 0, FLASH_CMD_CLEAR_STATUS);
822*4882a593Smuzhiyun 		flash_write_cmd(info, 0, 0, FLASH_CMD_WRITE);
823*4882a593Smuzhiyun 		break;
824*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_EXTENDED:
825*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_STANDARD:
826*4882a593Smuzhiyun 		sect = find_sector(info, dest);
827*4882a593Smuzhiyun 		flash_unlock_seq(info, sect);
828*4882a593Smuzhiyun 		flash_write_cmd(info, sect, info->addr_unlock1, AMD_CMD_WRITE);
829*4882a593Smuzhiyun 		sect_found = 1;
830*4882a593Smuzhiyun 		break;
831*4882a593Smuzhiyun #ifdef CONFIG_FLASH_CFI_LEGACY
832*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_LEGACY:
833*4882a593Smuzhiyun 		sect = find_sector(info, dest);
834*4882a593Smuzhiyun 		flash_unlock_seq(info, 0);
835*4882a593Smuzhiyun 		flash_write_cmd(info, 0, info->addr_unlock1, AMD_CMD_WRITE);
836*4882a593Smuzhiyun 		sect_found = 1;
837*4882a593Smuzhiyun 		break;
838*4882a593Smuzhiyun #endif
839*4882a593Smuzhiyun 	}
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	switch (info->portwidth) {
842*4882a593Smuzhiyun 	case FLASH_CFI_8BIT:
843*4882a593Smuzhiyun 		flash_write8(cword.w8, dstaddr);
844*4882a593Smuzhiyun 		break;
845*4882a593Smuzhiyun 	case FLASH_CFI_16BIT:
846*4882a593Smuzhiyun 		flash_write16(cword.w16, dstaddr);
847*4882a593Smuzhiyun 		break;
848*4882a593Smuzhiyun 	case FLASH_CFI_32BIT:
849*4882a593Smuzhiyun 		flash_write32(cword.w32, dstaddr);
850*4882a593Smuzhiyun 		break;
851*4882a593Smuzhiyun 	case FLASH_CFI_64BIT:
852*4882a593Smuzhiyun 		flash_write64(cword.w64, dstaddr);
853*4882a593Smuzhiyun 		break;
854*4882a593Smuzhiyun 	}
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	/* re-enable interrupts if necessary */
857*4882a593Smuzhiyun 	if (flag)
858*4882a593Smuzhiyun 		enable_interrupts();
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	if (!sect_found)
861*4882a593Smuzhiyun 		sect = find_sector(info, dest);
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	if (use_flash_status_poll(info))
864*4882a593Smuzhiyun 		return flash_status_poll(info, &cword, dstaddr,
865*4882a593Smuzhiyun 					 info->write_tout, "write");
866*4882a593Smuzhiyun 	else
867*4882a593Smuzhiyun 		return flash_full_status_check(info, sect,
868*4882a593Smuzhiyun 					       info->write_tout, "write");
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
872*4882a593Smuzhiyun 
flash_write_cfibuffer(flash_info_t * info,ulong dest,uchar * cp,int len)873*4882a593Smuzhiyun static int flash_write_cfibuffer(flash_info_t *info, ulong dest, uchar *cp,
874*4882a593Smuzhiyun 				 int len)
875*4882a593Smuzhiyun {
876*4882a593Smuzhiyun 	flash_sect_t sector;
877*4882a593Smuzhiyun 	int cnt;
878*4882a593Smuzhiyun 	int retcode;
879*4882a593Smuzhiyun 	u8 *src = cp;
880*4882a593Smuzhiyun 	u8 *dst = (u8 *)dest;
881*4882a593Smuzhiyun 	u8 *dst2 = dst;
882*4882a593Smuzhiyun 	int flag = 1;
883*4882a593Smuzhiyun 	uint offset = 0;
884*4882a593Smuzhiyun 	unsigned int shift;
885*4882a593Smuzhiyun 	uchar write_cmd;
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 	switch (info->portwidth) {
888*4882a593Smuzhiyun 	case FLASH_CFI_8BIT:
889*4882a593Smuzhiyun 		shift = 0;
890*4882a593Smuzhiyun 		break;
891*4882a593Smuzhiyun 	case FLASH_CFI_16BIT:
892*4882a593Smuzhiyun 		shift = 1;
893*4882a593Smuzhiyun 		break;
894*4882a593Smuzhiyun 	case FLASH_CFI_32BIT:
895*4882a593Smuzhiyun 		shift = 2;
896*4882a593Smuzhiyun 		break;
897*4882a593Smuzhiyun 	case FLASH_CFI_64BIT:
898*4882a593Smuzhiyun 		shift = 3;
899*4882a593Smuzhiyun 		break;
900*4882a593Smuzhiyun 	default:
901*4882a593Smuzhiyun 		retcode = ERR_INVAL;
902*4882a593Smuzhiyun 		goto out_unmap;
903*4882a593Smuzhiyun 	}
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	cnt = len >> shift;
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	while ((cnt-- > 0) && (flag == 1)) {
908*4882a593Smuzhiyun 		switch (info->portwidth) {
909*4882a593Smuzhiyun 		case FLASH_CFI_8BIT:
910*4882a593Smuzhiyun 			flag = ((flash_read8(dst2) & flash_read8(src)) ==
911*4882a593Smuzhiyun 				flash_read8(src));
912*4882a593Smuzhiyun 			src += 1, dst2 += 1;
913*4882a593Smuzhiyun 			break;
914*4882a593Smuzhiyun 		case FLASH_CFI_16BIT:
915*4882a593Smuzhiyun 			flag = ((flash_read16(dst2) & flash_read16(src)) ==
916*4882a593Smuzhiyun 				flash_read16(src));
917*4882a593Smuzhiyun 			src += 2, dst2 += 2;
918*4882a593Smuzhiyun 			break;
919*4882a593Smuzhiyun 		case FLASH_CFI_32BIT:
920*4882a593Smuzhiyun 			flag = ((flash_read32(dst2) & flash_read32(src)) ==
921*4882a593Smuzhiyun 				flash_read32(src));
922*4882a593Smuzhiyun 			src += 4, dst2 += 4;
923*4882a593Smuzhiyun 			break;
924*4882a593Smuzhiyun 		case FLASH_CFI_64BIT:
925*4882a593Smuzhiyun 			flag = ((flash_read64(dst2) & flash_read64(src)) ==
926*4882a593Smuzhiyun 				flash_read64(src));
927*4882a593Smuzhiyun 			src += 8, dst2 += 8;
928*4882a593Smuzhiyun 			break;
929*4882a593Smuzhiyun 		}
930*4882a593Smuzhiyun 	}
931*4882a593Smuzhiyun 	if (!flag) {
932*4882a593Smuzhiyun 		retcode = ERR_NOT_ERASED;
933*4882a593Smuzhiyun 		goto out_unmap;
934*4882a593Smuzhiyun 	}
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	src = cp;
937*4882a593Smuzhiyun 	sector = find_sector(info, dest);
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 	switch (info->vendor) {
940*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_PROG_REGIONS:
941*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_STANDARD:
942*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_EXTENDED:
943*4882a593Smuzhiyun 		write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
944*4882a593Smuzhiyun 			    FLASH_CMD_WRITE_BUFFER_PROG :
945*4882a593Smuzhiyun 			    FLASH_CMD_WRITE_TO_BUFFER;
946*4882a593Smuzhiyun 		flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS);
947*4882a593Smuzhiyun 		flash_write_cmd(info, sector, 0, FLASH_CMD_READ_STATUS);
948*4882a593Smuzhiyun 		flash_write_cmd(info, sector, 0, write_cmd);
949*4882a593Smuzhiyun 		retcode = flash_status_check(info, sector,
950*4882a593Smuzhiyun 					     info->buffer_write_tout,
951*4882a593Smuzhiyun 					     "write to buffer");
952*4882a593Smuzhiyun 		if (retcode == ERR_OK) {
953*4882a593Smuzhiyun 			/* reduce the number of loops by the width of
954*4882a593Smuzhiyun 			 * the port
955*4882a593Smuzhiyun 			 */
956*4882a593Smuzhiyun 			cnt = len >> shift;
957*4882a593Smuzhiyun 			flash_write_cmd(info, sector, 0, cnt - 1);
958*4882a593Smuzhiyun 			while (cnt-- > 0) {
959*4882a593Smuzhiyun 				switch (info->portwidth) {
960*4882a593Smuzhiyun 				case FLASH_CFI_8BIT:
961*4882a593Smuzhiyun 					flash_write8(flash_read8(src), dst);
962*4882a593Smuzhiyun 					src += 1, dst += 1;
963*4882a593Smuzhiyun 					break;
964*4882a593Smuzhiyun 				case FLASH_CFI_16BIT:
965*4882a593Smuzhiyun 					flash_write16(flash_read16(src), dst);
966*4882a593Smuzhiyun 					src += 2, dst += 2;
967*4882a593Smuzhiyun 					break;
968*4882a593Smuzhiyun 				case FLASH_CFI_32BIT:
969*4882a593Smuzhiyun 					flash_write32(flash_read32(src), dst);
970*4882a593Smuzhiyun 					src += 4, dst += 4;
971*4882a593Smuzhiyun 					break;
972*4882a593Smuzhiyun 				case FLASH_CFI_64BIT:
973*4882a593Smuzhiyun 					flash_write64(flash_read64(src), dst);
974*4882a593Smuzhiyun 					src += 8, dst += 8;
975*4882a593Smuzhiyun 					break;
976*4882a593Smuzhiyun 				default:
977*4882a593Smuzhiyun 					retcode = ERR_INVAL;
978*4882a593Smuzhiyun 					goto out_unmap;
979*4882a593Smuzhiyun 				}
980*4882a593Smuzhiyun 			}
981*4882a593Smuzhiyun 			flash_write_cmd(info, sector, 0,
982*4882a593Smuzhiyun 					FLASH_CMD_WRITE_BUFFER_CONFIRM);
983*4882a593Smuzhiyun 			retcode = flash_full_status_check(
984*4882a593Smuzhiyun 				info, sector, info->buffer_write_tout,
985*4882a593Smuzhiyun 				"buffer write");
986*4882a593Smuzhiyun 		}
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 		break;
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_STANDARD:
991*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_EXTENDED:
992*4882a593Smuzhiyun 		flash_unlock_seq(info, sector);
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun #ifdef CONFIG_FLASH_SPANSION_S29WS_N
995*4882a593Smuzhiyun 		offset = ((unsigned long)dst - info->start[sector]) >> shift;
996*4882a593Smuzhiyun #endif
997*4882a593Smuzhiyun 		flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
998*4882a593Smuzhiyun 		cnt = len >> shift;
999*4882a593Smuzhiyun 		flash_write_cmd(info, sector, offset, cnt - 1);
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 		switch (info->portwidth) {
1002*4882a593Smuzhiyun 		case FLASH_CFI_8BIT:
1003*4882a593Smuzhiyun 			while (cnt-- > 0) {
1004*4882a593Smuzhiyun 				flash_write8(flash_read8(src), dst);
1005*4882a593Smuzhiyun 				src += 1, dst += 1;
1006*4882a593Smuzhiyun 			}
1007*4882a593Smuzhiyun 			break;
1008*4882a593Smuzhiyun 		case FLASH_CFI_16BIT:
1009*4882a593Smuzhiyun 			while (cnt-- > 0) {
1010*4882a593Smuzhiyun 				flash_write16(flash_read16(src), dst);
1011*4882a593Smuzhiyun 				src += 2, dst += 2;
1012*4882a593Smuzhiyun 			}
1013*4882a593Smuzhiyun 			break;
1014*4882a593Smuzhiyun 		case FLASH_CFI_32BIT:
1015*4882a593Smuzhiyun 			while (cnt-- > 0) {
1016*4882a593Smuzhiyun 				flash_write32(flash_read32(src), dst);
1017*4882a593Smuzhiyun 				src += 4, dst += 4;
1018*4882a593Smuzhiyun 			}
1019*4882a593Smuzhiyun 			break;
1020*4882a593Smuzhiyun 		case FLASH_CFI_64BIT:
1021*4882a593Smuzhiyun 			while (cnt-- > 0) {
1022*4882a593Smuzhiyun 				flash_write64(flash_read64(src), dst);
1023*4882a593Smuzhiyun 				src += 8, dst += 8;
1024*4882a593Smuzhiyun 			}
1025*4882a593Smuzhiyun 			break;
1026*4882a593Smuzhiyun 		default:
1027*4882a593Smuzhiyun 			retcode = ERR_INVAL;
1028*4882a593Smuzhiyun 			goto out_unmap;
1029*4882a593Smuzhiyun 		}
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 		flash_write_cmd(info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1032*4882a593Smuzhiyun 		if (use_flash_status_poll(info))
1033*4882a593Smuzhiyun 			retcode = flash_status_poll(info, src - (1 << shift),
1034*4882a593Smuzhiyun 						    dst - (1 << shift),
1035*4882a593Smuzhiyun 						    info->buffer_write_tout,
1036*4882a593Smuzhiyun 						    "buffer write");
1037*4882a593Smuzhiyun 		else
1038*4882a593Smuzhiyun 			retcode = flash_full_status_check(info, sector,
1039*4882a593Smuzhiyun 							  info->buffer_write_tout,
1040*4882a593Smuzhiyun 							  "buffer write");
1041*4882a593Smuzhiyun 		break;
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 	default:
1044*4882a593Smuzhiyun 		debug("Unknown Command Set\n");
1045*4882a593Smuzhiyun 		retcode = ERR_INVAL;
1046*4882a593Smuzhiyun 		break;
1047*4882a593Smuzhiyun 	}
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun out_unmap:
1050*4882a593Smuzhiyun 	return retcode;
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun /*-----------------------------------------------------------------------
1055*4882a593Smuzhiyun  */
flash_erase(flash_info_t * info,int s_first,int s_last)1056*4882a593Smuzhiyun int flash_erase(flash_info_t *info, int s_first, int s_last)
1057*4882a593Smuzhiyun {
1058*4882a593Smuzhiyun 	int rcode = 0;
1059*4882a593Smuzhiyun 	int prot;
1060*4882a593Smuzhiyun 	flash_sect_t sect;
1061*4882a593Smuzhiyun 	int st;
1062*4882a593Smuzhiyun 
1063*4882a593Smuzhiyun 	if (info->flash_id != FLASH_MAN_CFI) {
1064*4882a593Smuzhiyun 		puts("Can't erase unknown flash type - aborted\n");
1065*4882a593Smuzhiyun 		return 1;
1066*4882a593Smuzhiyun 	}
1067*4882a593Smuzhiyun 	if (s_first < 0 || s_first > s_last) {
1068*4882a593Smuzhiyun 		puts("- no sectors to erase\n");
1069*4882a593Smuzhiyun 		return 1;
1070*4882a593Smuzhiyun 	}
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun 	prot = 0;
1073*4882a593Smuzhiyun 	for (sect = s_first; sect <= s_last; ++sect)
1074*4882a593Smuzhiyun 		if (info->protect[sect])
1075*4882a593Smuzhiyun 			prot++;
1076*4882a593Smuzhiyun 	if (prot) {
1077*4882a593Smuzhiyun 		printf("- Warning: %d protected sectors will not be erased!\n",
1078*4882a593Smuzhiyun 		       prot);
1079*4882a593Smuzhiyun 	} else if (flash_verbose) {
1080*4882a593Smuzhiyun 		putc('\n');
1081*4882a593Smuzhiyun 	}
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	for (sect = s_first; sect <= s_last; sect++) {
1084*4882a593Smuzhiyun 		if (ctrlc()) {
1085*4882a593Smuzhiyun 			printf("\n");
1086*4882a593Smuzhiyun 			return 1;
1087*4882a593Smuzhiyun 		}
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 		if (info->protect[sect] == 0) { /* not protected */
1090*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_CHECK_BLANK_BEFORE_ERASE
1091*4882a593Smuzhiyun 			int k;
1092*4882a593Smuzhiyun 			int size;
1093*4882a593Smuzhiyun 			int erased;
1094*4882a593Smuzhiyun 			u32 *flash;
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun 			/*
1097*4882a593Smuzhiyun 			 * Check if whole sector is erased
1098*4882a593Smuzhiyun 			 */
1099*4882a593Smuzhiyun 			size = flash_sector_size(info, sect);
1100*4882a593Smuzhiyun 			erased = 1;
1101*4882a593Smuzhiyun 			flash = (u32 *)info->start[sect];
1102*4882a593Smuzhiyun 			/* divide by 4 for longword access */
1103*4882a593Smuzhiyun 			size = size >> 2;
1104*4882a593Smuzhiyun 			for (k = 0; k < size; k++) {
1105*4882a593Smuzhiyun 				if (flash_read32(flash++) != 0xffffffff) {
1106*4882a593Smuzhiyun 					erased = 0;
1107*4882a593Smuzhiyun 					break;
1108*4882a593Smuzhiyun 				}
1109*4882a593Smuzhiyun 			}
1110*4882a593Smuzhiyun 			if (erased) {
1111*4882a593Smuzhiyun 				if (flash_verbose)
1112*4882a593Smuzhiyun 					putc(',');
1113*4882a593Smuzhiyun 				continue;
1114*4882a593Smuzhiyun 			}
1115*4882a593Smuzhiyun #endif
1116*4882a593Smuzhiyun 			switch (info->vendor) {
1117*4882a593Smuzhiyun 			case CFI_CMDSET_INTEL_PROG_REGIONS:
1118*4882a593Smuzhiyun 			case CFI_CMDSET_INTEL_STANDARD:
1119*4882a593Smuzhiyun 			case CFI_CMDSET_INTEL_EXTENDED:
1120*4882a593Smuzhiyun 				flash_write_cmd(info, sect, 0,
1121*4882a593Smuzhiyun 						FLASH_CMD_CLEAR_STATUS);
1122*4882a593Smuzhiyun 				flash_write_cmd(info, sect, 0,
1123*4882a593Smuzhiyun 						FLASH_CMD_BLOCK_ERASE);
1124*4882a593Smuzhiyun 				flash_write_cmd(info, sect, 0,
1125*4882a593Smuzhiyun 						FLASH_CMD_ERASE_CONFIRM);
1126*4882a593Smuzhiyun 				break;
1127*4882a593Smuzhiyun 			case CFI_CMDSET_AMD_STANDARD:
1128*4882a593Smuzhiyun 			case CFI_CMDSET_AMD_EXTENDED:
1129*4882a593Smuzhiyun 				flash_unlock_seq(info, sect);
1130*4882a593Smuzhiyun 				flash_write_cmd(info, sect,
1131*4882a593Smuzhiyun 						info->addr_unlock1,
1132*4882a593Smuzhiyun 						AMD_CMD_ERASE_START);
1133*4882a593Smuzhiyun 				flash_unlock_seq(info, sect);
1134*4882a593Smuzhiyun 				flash_write_cmd(info, sect, 0,
1135*4882a593Smuzhiyun 						info->cmd_erase_sector);
1136*4882a593Smuzhiyun 				break;
1137*4882a593Smuzhiyun #ifdef CONFIG_FLASH_CFI_LEGACY
1138*4882a593Smuzhiyun 			case CFI_CMDSET_AMD_LEGACY:
1139*4882a593Smuzhiyun 				flash_unlock_seq(info, 0);
1140*4882a593Smuzhiyun 				flash_write_cmd(info, 0, info->addr_unlock1,
1141*4882a593Smuzhiyun 						AMD_CMD_ERASE_START);
1142*4882a593Smuzhiyun 				flash_unlock_seq(info, 0);
1143*4882a593Smuzhiyun 				flash_write_cmd(info, sect, 0,
1144*4882a593Smuzhiyun 						AMD_CMD_ERASE_SECTOR);
1145*4882a593Smuzhiyun 				break;
1146*4882a593Smuzhiyun #endif
1147*4882a593Smuzhiyun 			default:
1148*4882a593Smuzhiyun 				debug("Unknown flash vendor %d\n",
1149*4882a593Smuzhiyun 				      info->vendor);
1150*4882a593Smuzhiyun 				break;
1151*4882a593Smuzhiyun 			}
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 			if (use_flash_status_poll(info)) {
1154*4882a593Smuzhiyun 				cfiword_t cword;
1155*4882a593Smuzhiyun 				void *dest;
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun 				cword.w64 = 0xffffffffffffffffULL;
1158*4882a593Smuzhiyun 				dest = flash_map(info, sect, 0);
1159*4882a593Smuzhiyun 				st = flash_status_poll(info, &cword, dest,
1160*4882a593Smuzhiyun 						       info->erase_blk_tout,
1161*4882a593Smuzhiyun 						       "erase");
1162*4882a593Smuzhiyun 				flash_unmap(info, sect, 0, dest);
1163*4882a593Smuzhiyun 			} else {
1164*4882a593Smuzhiyun 				st = flash_full_status_check(info, sect,
1165*4882a593Smuzhiyun 							     info->erase_blk_tout,
1166*4882a593Smuzhiyun 							     "erase");
1167*4882a593Smuzhiyun 			}
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun 			if (st)
1170*4882a593Smuzhiyun 				rcode = 1;
1171*4882a593Smuzhiyun 			else if (flash_verbose)
1172*4882a593Smuzhiyun 				putc('.');
1173*4882a593Smuzhiyun 		}
1174*4882a593Smuzhiyun 	}
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	if (flash_verbose)
1177*4882a593Smuzhiyun 		puts(" done\n");
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 	return rcode;
1180*4882a593Smuzhiyun }
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_EMPTY_INFO
sector_erased(flash_info_t * info,int i)1183*4882a593Smuzhiyun static int sector_erased(flash_info_t *info, int i)
1184*4882a593Smuzhiyun {
1185*4882a593Smuzhiyun 	int k;
1186*4882a593Smuzhiyun 	int size;
1187*4882a593Smuzhiyun 	u32 *flash;
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 	/*
1190*4882a593Smuzhiyun 	 * Check if whole sector is erased
1191*4882a593Smuzhiyun 	 */
1192*4882a593Smuzhiyun 	size = flash_sector_size(info, i);
1193*4882a593Smuzhiyun 	flash = (u32 *)info->start[i];
1194*4882a593Smuzhiyun 	/* divide by 4 for longword access */
1195*4882a593Smuzhiyun 	size = size >> 2;
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	for (k = 0; k < size; k++) {
1198*4882a593Smuzhiyun 		if (flash_read32(flash++) != 0xffffffff)
1199*4882a593Smuzhiyun 			return 0;	/* not erased */
1200*4882a593Smuzhiyun 	}
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	return 1;			/* erased */
1203*4882a593Smuzhiyun }
1204*4882a593Smuzhiyun #endif /* CONFIG_SYS_FLASH_EMPTY_INFO */
1205*4882a593Smuzhiyun 
flash_print_info(flash_info_t * info)1206*4882a593Smuzhiyun void flash_print_info(flash_info_t *info)
1207*4882a593Smuzhiyun {
1208*4882a593Smuzhiyun 	int i;
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 	if (info->flash_id != FLASH_MAN_CFI) {
1211*4882a593Smuzhiyun 		puts("missing or unknown FLASH type\n");
1212*4882a593Smuzhiyun 		return;
1213*4882a593Smuzhiyun 	}
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun 	printf("%s flash (%d x %d)",
1216*4882a593Smuzhiyun 	       info->name,
1217*4882a593Smuzhiyun 	       (info->portwidth << 3), (info->chipwidth << 3));
1218*4882a593Smuzhiyun 	if (info->size < 1024 * 1024)
1219*4882a593Smuzhiyun 		printf("  Size: %ld kB in %d Sectors\n",
1220*4882a593Smuzhiyun 		       info->size >> 10, info->sector_count);
1221*4882a593Smuzhiyun 	else
1222*4882a593Smuzhiyun 		printf("  Size: %ld MB in %d Sectors\n",
1223*4882a593Smuzhiyun 		       info->size >> 20, info->sector_count);
1224*4882a593Smuzhiyun 	printf("  ");
1225*4882a593Smuzhiyun 	switch (info->vendor) {
1226*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_PROG_REGIONS:
1227*4882a593Smuzhiyun 		printf("Intel Prog Regions");
1228*4882a593Smuzhiyun 		break;
1229*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_STANDARD:
1230*4882a593Smuzhiyun 		printf("Intel Standard");
1231*4882a593Smuzhiyun 		break;
1232*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_EXTENDED:
1233*4882a593Smuzhiyun 		printf("Intel Extended");
1234*4882a593Smuzhiyun 		break;
1235*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_STANDARD:
1236*4882a593Smuzhiyun 		printf("AMD Standard");
1237*4882a593Smuzhiyun 		break;
1238*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_EXTENDED:
1239*4882a593Smuzhiyun 		printf("AMD Extended");
1240*4882a593Smuzhiyun 		break;
1241*4882a593Smuzhiyun #ifdef CONFIG_FLASH_CFI_LEGACY
1242*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_LEGACY:
1243*4882a593Smuzhiyun 		printf("AMD Legacy");
1244*4882a593Smuzhiyun 		break;
1245*4882a593Smuzhiyun #endif
1246*4882a593Smuzhiyun 	default:
1247*4882a593Smuzhiyun 		printf("Unknown (%d)", info->vendor);
1248*4882a593Smuzhiyun 		break;
1249*4882a593Smuzhiyun 	}
1250*4882a593Smuzhiyun 	printf(" command set, Manufacturer ID: 0x%02X, Device ID: 0x",
1251*4882a593Smuzhiyun 	       info->manufacturer_id);
1252*4882a593Smuzhiyun 	printf(info->chipwidth == FLASH_CFI_16BIT ? "%04X" : "%02X",
1253*4882a593Smuzhiyun 	       info->device_id);
1254*4882a593Smuzhiyun 	if ((info->device_id & 0xff) == 0x7E) {
1255*4882a593Smuzhiyun 		printf(info->chipwidth == FLASH_CFI_16BIT ? "%04X" : "%02X",
1256*4882a593Smuzhiyun 		       info->device_id2);
1257*4882a593Smuzhiyun 	}
1258*4882a593Smuzhiyun 	if (info->vendor == CFI_CMDSET_AMD_STANDARD && info->legacy_unlock)
1259*4882a593Smuzhiyun 		printf("\n  Advanced Sector Protection (PPB) enabled");
1260*4882a593Smuzhiyun 	printf("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
1261*4882a593Smuzhiyun 	       info->erase_blk_tout, info->write_tout);
1262*4882a593Smuzhiyun 	if (info->buffer_size > 1) {
1263*4882a593Smuzhiyun 		printf("  Buffer write timeout: %ld ms, ",
1264*4882a593Smuzhiyun 		       info->buffer_write_tout);
1265*4882a593Smuzhiyun 		printf("buffer size: %d bytes\n", info->buffer_size);
1266*4882a593Smuzhiyun 	}
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	puts("\n  Sector Start Addresses:");
1269*4882a593Smuzhiyun 	for (i = 0; i < info->sector_count; ++i) {
1270*4882a593Smuzhiyun 		if (ctrlc())
1271*4882a593Smuzhiyun 			break;
1272*4882a593Smuzhiyun 		if ((i % 5) == 0)
1273*4882a593Smuzhiyun 			putc('\n');
1274*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_EMPTY_INFO
1275*4882a593Smuzhiyun 		/* print empty and read-only info */
1276*4882a593Smuzhiyun 		printf("  %08lX %c %s ",
1277*4882a593Smuzhiyun 		       info->start[i],
1278*4882a593Smuzhiyun 		       sector_erased(info, i) ? 'E' : ' ',
1279*4882a593Smuzhiyun 		       info->protect[i] ? "RO" : "  ");
1280*4882a593Smuzhiyun #else	/* ! CONFIG_SYS_FLASH_EMPTY_INFO */
1281*4882a593Smuzhiyun 		printf("  %08lX   %s ",
1282*4882a593Smuzhiyun 		       info->start[i],
1283*4882a593Smuzhiyun 		       info->protect[i] ? "RO" : "  ");
1284*4882a593Smuzhiyun #endif
1285*4882a593Smuzhiyun 	}
1286*4882a593Smuzhiyun 	putc('\n');
1287*4882a593Smuzhiyun }
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun /*-----------------------------------------------------------------------
1290*4882a593Smuzhiyun  * This is used in a few places in write_buf() to show programming
1291*4882a593Smuzhiyun  * progress.  Making it a function is nasty because it needs to do side
1292*4882a593Smuzhiyun  * effect updates to digit and dots.  Repeated code is nasty too, so
1293*4882a593Smuzhiyun  * we define it once here.
1294*4882a593Smuzhiyun  */
1295*4882a593Smuzhiyun #ifdef CONFIG_FLASH_SHOW_PROGRESS
1296*4882a593Smuzhiyun #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
1297*4882a593Smuzhiyun 	if (flash_verbose) { \
1298*4882a593Smuzhiyun 		dots -= dots_sub; \
1299*4882a593Smuzhiyun 		if (scale > 0 && dots <= 0) { \
1300*4882a593Smuzhiyun 			if ((digit % 5) == 0) \
1301*4882a593Smuzhiyun 				printf("%d", digit / 5); \
1302*4882a593Smuzhiyun 			else \
1303*4882a593Smuzhiyun 				putc('.'); \
1304*4882a593Smuzhiyun 			digit--; \
1305*4882a593Smuzhiyun 			dots += scale; \
1306*4882a593Smuzhiyun 		} \
1307*4882a593Smuzhiyun 	}
1308*4882a593Smuzhiyun #else
1309*4882a593Smuzhiyun #define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1310*4882a593Smuzhiyun #endif
1311*4882a593Smuzhiyun 
1312*4882a593Smuzhiyun /*-----------------------------------------------------------------------
1313*4882a593Smuzhiyun  * Copy memory to flash, returns:
1314*4882a593Smuzhiyun  * 0 - OK
1315*4882a593Smuzhiyun  * 1 - write timeout
1316*4882a593Smuzhiyun  * 2 - Flash not erased
1317*4882a593Smuzhiyun  */
write_buff(flash_info_t * info,uchar * src,ulong addr,ulong cnt)1318*4882a593Smuzhiyun int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
1319*4882a593Smuzhiyun {
1320*4882a593Smuzhiyun 	ulong wp;
1321*4882a593Smuzhiyun 	uchar *p;
1322*4882a593Smuzhiyun 	int aln;
1323*4882a593Smuzhiyun 	cfiword_t cword;
1324*4882a593Smuzhiyun 	int i, rc;
1325*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
1326*4882a593Smuzhiyun 	int buffered_size;
1327*4882a593Smuzhiyun #endif
1328*4882a593Smuzhiyun #ifdef CONFIG_FLASH_SHOW_PROGRESS
1329*4882a593Smuzhiyun 	int digit = CONFIG_FLASH_SHOW_PROGRESS;
1330*4882a593Smuzhiyun 	int scale = 0;
1331*4882a593Smuzhiyun 	int dots  = 0;
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun 	/*
1334*4882a593Smuzhiyun 	 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
1335*4882a593Smuzhiyun 	 */
1336*4882a593Smuzhiyun 	if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
1337*4882a593Smuzhiyun 		scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
1338*4882a593Smuzhiyun 			CONFIG_FLASH_SHOW_PROGRESS);
1339*4882a593Smuzhiyun 	}
1340*4882a593Smuzhiyun #endif
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun 	/* get lower aligned address */
1343*4882a593Smuzhiyun 	wp = (addr & ~(info->portwidth - 1));
1344*4882a593Smuzhiyun 
1345*4882a593Smuzhiyun 	/* handle unaligned start */
1346*4882a593Smuzhiyun 	aln = addr - wp;
1347*4882a593Smuzhiyun 	if (aln != 0) {
1348*4882a593Smuzhiyun 		cword.w32 = 0;
1349*4882a593Smuzhiyun 		p = (uchar *)wp;
1350*4882a593Smuzhiyun 		for (i = 0; i < aln; ++i)
1351*4882a593Smuzhiyun 			flash_add_byte(info, &cword, flash_read8(p + i));
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun 		for (; (i < info->portwidth) && (cnt > 0); i++) {
1354*4882a593Smuzhiyun 			flash_add_byte(info, &cword, *src++);
1355*4882a593Smuzhiyun 			cnt--;
1356*4882a593Smuzhiyun 		}
1357*4882a593Smuzhiyun 		for (; (cnt == 0) && (i < info->portwidth); ++i)
1358*4882a593Smuzhiyun 			flash_add_byte(info, &cword, flash_read8(p + i));
1359*4882a593Smuzhiyun 
1360*4882a593Smuzhiyun 		rc = flash_write_cfiword(info, wp, cword);
1361*4882a593Smuzhiyun 		if (rc != 0)
1362*4882a593Smuzhiyun 			return rc;
1363*4882a593Smuzhiyun 
1364*4882a593Smuzhiyun 		wp += i;
1365*4882a593Smuzhiyun 		FLASH_SHOW_PROGRESS(scale, dots, digit, i);
1366*4882a593Smuzhiyun 	}
1367*4882a593Smuzhiyun 
1368*4882a593Smuzhiyun 	/* handle the aligned part */
1369*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
1370*4882a593Smuzhiyun 	buffered_size = (info->portwidth / info->chipwidth);
1371*4882a593Smuzhiyun 	buffered_size *= info->buffer_size;
1372*4882a593Smuzhiyun 	while (cnt >= info->portwidth) {
1373*4882a593Smuzhiyun 		/* prohibit buffer write when buffer_size is 1 */
1374*4882a593Smuzhiyun 		if (info->buffer_size == 1) {
1375*4882a593Smuzhiyun 			cword.w32 = 0;
1376*4882a593Smuzhiyun 			for (i = 0; i < info->portwidth; i++)
1377*4882a593Smuzhiyun 				flash_add_byte(info, &cword, *src++);
1378*4882a593Smuzhiyun 			rc = flash_write_cfiword(info, wp, cword);
1379*4882a593Smuzhiyun 			if (rc != 0)
1380*4882a593Smuzhiyun 				return rc;
1381*4882a593Smuzhiyun 			wp += info->portwidth;
1382*4882a593Smuzhiyun 			cnt -= info->portwidth;
1383*4882a593Smuzhiyun 			continue;
1384*4882a593Smuzhiyun 		}
1385*4882a593Smuzhiyun 
1386*4882a593Smuzhiyun 		/* write buffer until next buffered_size aligned boundary */
1387*4882a593Smuzhiyun 		i = buffered_size - (wp % buffered_size);
1388*4882a593Smuzhiyun 		if (i > cnt)
1389*4882a593Smuzhiyun 			i = cnt;
1390*4882a593Smuzhiyun 		rc = flash_write_cfibuffer(info, wp, src, i);
1391*4882a593Smuzhiyun 		if (rc != ERR_OK)
1392*4882a593Smuzhiyun 			return rc;
1393*4882a593Smuzhiyun 		i -= i & (info->portwidth - 1);
1394*4882a593Smuzhiyun 		wp += i;
1395*4882a593Smuzhiyun 		src += i;
1396*4882a593Smuzhiyun 		cnt -= i;
1397*4882a593Smuzhiyun 		FLASH_SHOW_PROGRESS(scale, dots, digit, i);
1398*4882a593Smuzhiyun 		/* Only check every once in a while */
1399*4882a593Smuzhiyun 		if ((cnt & 0xFFFF) < buffered_size && ctrlc())
1400*4882a593Smuzhiyun 			return ERR_ABORTED;
1401*4882a593Smuzhiyun 	}
1402*4882a593Smuzhiyun #else
1403*4882a593Smuzhiyun 	while (cnt >= info->portwidth) {
1404*4882a593Smuzhiyun 		cword.w32 = 0;
1405*4882a593Smuzhiyun 		for (i = 0; i < info->portwidth; i++)
1406*4882a593Smuzhiyun 			flash_add_byte(info, &cword, *src++);
1407*4882a593Smuzhiyun 		rc = flash_write_cfiword(info, wp, cword);
1408*4882a593Smuzhiyun 		if (rc != 0)
1409*4882a593Smuzhiyun 			return rc;
1410*4882a593Smuzhiyun 		wp += info->portwidth;
1411*4882a593Smuzhiyun 		cnt -= info->portwidth;
1412*4882a593Smuzhiyun 		FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
1413*4882a593Smuzhiyun 		/* Only check every once in a while */
1414*4882a593Smuzhiyun 		if ((cnt & 0xFFFF) < info->portwidth && ctrlc())
1415*4882a593Smuzhiyun 			return ERR_ABORTED;
1416*4882a593Smuzhiyun 	}
1417*4882a593Smuzhiyun #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
1418*4882a593Smuzhiyun 
1419*4882a593Smuzhiyun 	if (cnt == 0)
1420*4882a593Smuzhiyun 		return (0);
1421*4882a593Smuzhiyun 
1422*4882a593Smuzhiyun 	/*
1423*4882a593Smuzhiyun 	 * handle unaligned tail bytes
1424*4882a593Smuzhiyun 	 */
1425*4882a593Smuzhiyun 	cword.w32 = 0;
1426*4882a593Smuzhiyun 	p = (uchar *)wp;
1427*4882a593Smuzhiyun 	for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
1428*4882a593Smuzhiyun 		flash_add_byte(info, &cword, *src++);
1429*4882a593Smuzhiyun 		--cnt;
1430*4882a593Smuzhiyun 	}
1431*4882a593Smuzhiyun 	for (; i < info->portwidth; ++i)
1432*4882a593Smuzhiyun 		flash_add_byte(info, &cword, flash_read8(p + i));
1433*4882a593Smuzhiyun 
1434*4882a593Smuzhiyun 	return flash_write_cfiword(info, wp, cword);
1435*4882a593Smuzhiyun }
1436*4882a593Smuzhiyun 
manufact_match(flash_info_t * info,u32 manu)1437*4882a593Smuzhiyun static inline int manufact_match(flash_info_t *info, u32 manu)
1438*4882a593Smuzhiyun {
1439*4882a593Smuzhiyun 	return info->manufacturer_id == ((manu & FLASH_VENDMASK) >> 16);
1440*4882a593Smuzhiyun }
1441*4882a593Smuzhiyun 
1442*4882a593Smuzhiyun /*-----------------------------------------------------------------------
1443*4882a593Smuzhiyun  */
1444*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_PROTECTION
1445*4882a593Smuzhiyun 
cfi_protect_bugfix(flash_info_t * info,long sector,int prot)1446*4882a593Smuzhiyun static int cfi_protect_bugfix(flash_info_t *info, long sector, int prot)
1447*4882a593Smuzhiyun {
1448*4882a593Smuzhiyun 	if (manufact_match(info, INTEL_MANUFACT) &&
1449*4882a593Smuzhiyun 	    info->device_id == NUMONYX_256MBIT) {
1450*4882a593Smuzhiyun 		/*
1451*4882a593Smuzhiyun 		 * see errata called
1452*4882a593Smuzhiyun 		 * "Numonyx Axcell P33/P30 Specification Update" :)
1453*4882a593Smuzhiyun 		 */
1454*4882a593Smuzhiyun 		flash_write_cmd(info, sector, 0, FLASH_CMD_READ_ID);
1455*4882a593Smuzhiyun 		if (!flash_isequal(info, sector, FLASH_OFFSET_PROTECT,
1456*4882a593Smuzhiyun 				   prot)) {
1457*4882a593Smuzhiyun 			/*
1458*4882a593Smuzhiyun 			 * cmd must come before FLASH_CMD_PROTECT + 20us
1459*4882a593Smuzhiyun 			 * Disable interrupts which might cause a timeout here.
1460*4882a593Smuzhiyun 			 */
1461*4882a593Smuzhiyun 			int flag = disable_interrupts();
1462*4882a593Smuzhiyun 			unsigned short cmd;
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun 			if (prot)
1465*4882a593Smuzhiyun 				cmd = FLASH_CMD_PROTECT_SET;
1466*4882a593Smuzhiyun 			else
1467*4882a593Smuzhiyun 				cmd = FLASH_CMD_PROTECT_CLEAR;
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 			flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT);
1470*4882a593Smuzhiyun 			flash_write_cmd(info, sector, 0, cmd);
1471*4882a593Smuzhiyun 			/* re-enable interrupts if necessary */
1472*4882a593Smuzhiyun 			if (flag)
1473*4882a593Smuzhiyun 				enable_interrupts();
1474*4882a593Smuzhiyun 		}
1475*4882a593Smuzhiyun 		return 1;
1476*4882a593Smuzhiyun 	}
1477*4882a593Smuzhiyun 	return 0;
1478*4882a593Smuzhiyun }
1479*4882a593Smuzhiyun 
flash_real_protect(flash_info_t * info,long sector,int prot)1480*4882a593Smuzhiyun int flash_real_protect(flash_info_t *info, long sector, int prot)
1481*4882a593Smuzhiyun {
1482*4882a593Smuzhiyun 	int retcode = 0;
1483*4882a593Smuzhiyun 
1484*4882a593Smuzhiyun 	switch (info->vendor) {
1485*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_PROG_REGIONS:
1486*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_STANDARD:
1487*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_EXTENDED:
1488*4882a593Smuzhiyun 		if (!cfi_protect_bugfix(info, sector, prot)) {
1489*4882a593Smuzhiyun 			flash_write_cmd(info, sector, 0,
1490*4882a593Smuzhiyun 					FLASH_CMD_CLEAR_STATUS);
1491*4882a593Smuzhiyun 			flash_write_cmd(info, sector, 0,
1492*4882a593Smuzhiyun 					FLASH_CMD_PROTECT);
1493*4882a593Smuzhiyun 			if (prot)
1494*4882a593Smuzhiyun 				flash_write_cmd(info, sector, 0,
1495*4882a593Smuzhiyun 						FLASH_CMD_PROTECT_SET);
1496*4882a593Smuzhiyun 			else
1497*4882a593Smuzhiyun 				flash_write_cmd(info, sector, 0,
1498*4882a593Smuzhiyun 						FLASH_CMD_PROTECT_CLEAR);
1499*4882a593Smuzhiyun 		}
1500*4882a593Smuzhiyun 		break;
1501*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_EXTENDED:
1502*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_STANDARD:
1503*4882a593Smuzhiyun 		/* U-Boot only checks the first byte */
1504*4882a593Smuzhiyun 		if (manufact_match(info, ATM_MANUFACT)) {
1505*4882a593Smuzhiyun 			if (prot) {
1506*4882a593Smuzhiyun 				flash_unlock_seq(info, 0);
1507*4882a593Smuzhiyun 				flash_write_cmd(info, 0,
1508*4882a593Smuzhiyun 						info->addr_unlock1,
1509*4882a593Smuzhiyun 						ATM_CMD_SOFTLOCK_START);
1510*4882a593Smuzhiyun 				flash_unlock_seq(info, 0);
1511*4882a593Smuzhiyun 				flash_write_cmd(info, sector, 0,
1512*4882a593Smuzhiyun 						ATM_CMD_LOCK_SECT);
1513*4882a593Smuzhiyun 			} else {
1514*4882a593Smuzhiyun 				flash_write_cmd(info, 0,
1515*4882a593Smuzhiyun 						info->addr_unlock1,
1516*4882a593Smuzhiyun 						AMD_CMD_UNLOCK_START);
1517*4882a593Smuzhiyun 				if (info->device_id == ATM_ID_BV6416)
1518*4882a593Smuzhiyun 					flash_write_cmd(info, sector,
1519*4882a593Smuzhiyun 							0, ATM_CMD_UNLOCK_SECT);
1520*4882a593Smuzhiyun 			}
1521*4882a593Smuzhiyun 		}
1522*4882a593Smuzhiyun 		if (info->legacy_unlock) {
1523*4882a593Smuzhiyun 			int flag = disable_interrupts();
1524*4882a593Smuzhiyun 			int lock_flag;
1525*4882a593Smuzhiyun 
1526*4882a593Smuzhiyun 			flash_unlock_seq(info, 0);
1527*4882a593Smuzhiyun 			flash_write_cmd(info, 0, info->addr_unlock1,
1528*4882a593Smuzhiyun 					AMD_CMD_SET_PPB_ENTRY);
1529*4882a593Smuzhiyun 			lock_flag = flash_isset(info, sector, 0, 0x01);
1530*4882a593Smuzhiyun 			if (prot) {
1531*4882a593Smuzhiyun 				if (lock_flag) {
1532*4882a593Smuzhiyun 					flash_write_cmd(info, sector, 0,
1533*4882a593Smuzhiyun 							AMD_CMD_PPB_LOCK_BC1);
1534*4882a593Smuzhiyun 					flash_write_cmd(info, sector, 0,
1535*4882a593Smuzhiyun 							AMD_CMD_PPB_LOCK_BC2);
1536*4882a593Smuzhiyun 				}
1537*4882a593Smuzhiyun 				debug("sector %ld %slocked\n", sector,
1538*4882a593Smuzhiyun 				      lock_flag ? "" : "already ");
1539*4882a593Smuzhiyun 			} else {
1540*4882a593Smuzhiyun 				if (!lock_flag) {
1541*4882a593Smuzhiyun 					debug("unlock %ld\n", sector);
1542*4882a593Smuzhiyun 					flash_write_cmd(info, 0, 0,
1543*4882a593Smuzhiyun 							AMD_CMD_PPB_UNLOCK_BC1);
1544*4882a593Smuzhiyun 					flash_write_cmd(info, 0, 0,
1545*4882a593Smuzhiyun 							AMD_CMD_PPB_UNLOCK_BC2);
1546*4882a593Smuzhiyun 				}
1547*4882a593Smuzhiyun 				debug("sector %ld %sunlocked\n", sector,
1548*4882a593Smuzhiyun 				      !lock_flag ? "" : "already ");
1549*4882a593Smuzhiyun 			}
1550*4882a593Smuzhiyun 			if (flag)
1551*4882a593Smuzhiyun 				enable_interrupts();
1552*4882a593Smuzhiyun 
1553*4882a593Smuzhiyun 			if (flash_status_check(info, sector,
1554*4882a593Smuzhiyun 					       info->erase_blk_tout,
1555*4882a593Smuzhiyun 					       prot ? "protect" : "unprotect"))
1556*4882a593Smuzhiyun 				printf("status check error\n");
1557*4882a593Smuzhiyun 
1558*4882a593Smuzhiyun 			flash_write_cmd(info, 0, 0,
1559*4882a593Smuzhiyun 					AMD_CMD_SET_PPB_EXIT_BC1);
1560*4882a593Smuzhiyun 			flash_write_cmd(info, 0, 0,
1561*4882a593Smuzhiyun 					AMD_CMD_SET_PPB_EXIT_BC2);
1562*4882a593Smuzhiyun 		}
1563*4882a593Smuzhiyun 		break;
1564*4882a593Smuzhiyun #ifdef CONFIG_FLASH_CFI_LEGACY
1565*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_LEGACY:
1566*4882a593Smuzhiyun 		flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1567*4882a593Smuzhiyun 		flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT);
1568*4882a593Smuzhiyun 		if (prot)
1569*4882a593Smuzhiyun 			flash_write_cmd(info, sector, 0,
1570*4882a593Smuzhiyun 					FLASH_CMD_PROTECT_SET);
1571*4882a593Smuzhiyun 		else
1572*4882a593Smuzhiyun 			flash_write_cmd(info, sector, 0,
1573*4882a593Smuzhiyun 					FLASH_CMD_PROTECT_CLEAR);
1574*4882a593Smuzhiyun #endif
1575*4882a593Smuzhiyun 	};
1576*4882a593Smuzhiyun 
1577*4882a593Smuzhiyun 	/*
1578*4882a593Smuzhiyun 	 * Flash needs to be in status register read mode for
1579*4882a593Smuzhiyun 	 * flash_full_status_check() to work correctly
1580*4882a593Smuzhiyun 	 */
1581*4882a593Smuzhiyun 	flash_write_cmd(info, sector, 0, FLASH_CMD_READ_STATUS);
1582*4882a593Smuzhiyun 	retcode = flash_full_status_check(info, sector, info->erase_blk_tout,
1583*4882a593Smuzhiyun 					  prot ? "protect" : "unprotect");
1584*4882a593Smuzhiyun 	if (retcode == 0) {
1585*4882a593Smuzhiyun 		info->protect[sector] = prot;
1586*4882a593Smuzhiyun 
1587*4882a593Smuzhiyun 		/*
1588*4882a593Smuzhiyun 		 * On some of Intel's flash chips (marked via legacy_unlock)
1589*4882a593Smuzhiyun 		 * unprotect unprotects all locking.
1590*4882a593Smuzhiyun 		 */
1591*4882a593Smuzhiyun 		if (prot == 0 && info->legacy_unlock) {
1592*4882a593Smuzhiyun 			flash_sect_t i;
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun 			for (i = 0; i < info->sector_count; i++) {
1595*4882a593Smuzhiyun 				if (info->protect[i])
1596*4882a593Smuzhiyun 					flash_real_protect(info, i, 1);
1597*4882a593Smuzhiyun 			}
1598*4882a593Smuzhiyun 		}
1599*4882a593Smuzhiyun 	}
1600*4882a593Smuzhiyun 	return retcode;
1601*4882a593Smuzhiyun }
1602*4882a593Smuzhiyun 
1603*4882a593Smuzhiyun /*-----------------------------------------------------------------------
1604*4882a593Smuzhiyun  * flash_read_user_serial - read the OneTimeProgramming cells
1605*4882a593Smuzhiyun  */
flash_read_user_serial(flash_info_t * info,void * buffer,int offset,int len)1606*4882a593Smuzhiyun void flash_read_user_serial(flash_info_t *info, void *buffer, int offset,
1607*4882a593Smuzhiyun 			    int len)
1608*4882a593Smuzhiyun {
1609*4882a593Smuzhiyun 	uchar *src;
1610*4882a593Smuzhiyun 	uchar *dst;
1611*4882a593Smuzhiyun 
1612*4882a593Smuzhiyun 	dst = buffer;
1613*4882a593Smuzhiyun 	src = flash_map(info, 0, FLASH_OFFSET_USER_PROTECTION);
1614*4882a593Smuzhiyun 	flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1615*4882a593Smuzhiyun 	memcpy(dst, src + offset, len);
1616*4882a593Smuzhiyun 	flash_write_cmd(info, 0, 0, info->cmd_reset);
1617*4882a593Smuzhiyun 	udelay(1);
1618*4882a593Smuzhiyun 	flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
1619*4882a593Smuzhiyun }
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun /*
1622*4882a593Smuzhiyun  * flash_read_factory_serial - read the device Id from the protection area
1623*4882a593Smuzhiyun  */
flash_read_factory_serial(flash_info_t * info,void * buffer,int offset,int len)1624*4882a593Smuzhiyun void flash_read_factory_serial(flash_info_t *info, void *buffer, int offset,
1625*4882a593Smuzhiyun 			       int len)
1626*4882a593Smuzhiyun {
1627*4882a593Smuzhiyun 	uchar *src;
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun 	src = flash_map(info, 0, FLASH_OFFSET_INTEL_PROTECTION);
1630*4882a593Smuzhiyun 	flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1631*4882a593Smuzhiyun 	memcpy(buffer, src + offset, len);
1632*4882a593Smuzhiyun 	flash_write_cmd(info, 0, 0, info->cmd_reset);
1633*4882a593Smuzhiyun 	udelay(1);
1634*4882a593Smuzhiyun 	flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
1635*4882a593Smuzhiyun }
1636*4882a593Smuzhiyun 
1637*4882a593Smuzhiyun #endif /* CONFIG_SYS_FLASH_PROTECTION */
1638*4882a593Smuzhiyun 
1639*4882a593Smuzhiyun /*-----------------------------------------------------------------------
1640*4882a593Smuzhiyun  * Reverse the order of the erase regions in the CFI QRY structure.
1641*4882a593Smuzhiyun  * This is needed for chips that are either a) correctly detected as
1642*4882a593Smuzhiyun  * top-boot, or b) buggy.
1643*4882a593Smuzhiyun  */
cfi_reverse_geometry(struct cfi_qry * qry)1644*4882a593Smuzhiyun static void cfi_reverse_geometry(struct cfi_qry *qry)
1645*4882a593Smuzhiyun {
1646*4882a593Smuzhiyun 	unsigned int i, j;
1647*4882a593Smuzhiyun 	u32 tmp;
1648*4882a593Smuzhiyun 
1649*4882a593Smuzhiyun 	for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
1650*4882a593Smuzhiyun 		tmp = get_unaligned(&qry->erase_region_info[i]);
1651*4882a593Smuzhiyun 		put_unaligned(get_unaligned(&qry->erase_region_info[j]),
1652*4882a593Smuzhiyun 			      &qry->erase_region_info[i]);
1653*4882a593Smuzhiyun 		put_unaligned(tmp, &qry->erase_region_info[j]);
1654*4882a593Smuzhiyun 	}
1655*4882a593Smuzhiyun }
1656*4882a593Smuzhiyun 
1657*4882a593Smuzhiyun /*-----------------------------------------------------------------------
1658*4882a593Smuzhiyun  * read jedec ids from device and set corresponding fields in info struct
1659*4882a593Smuzhiyun  *
1660*4882a593Smuzhiyun  * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1661*4882a593Smuzhiyun  *
1662*4882a593Smuzhiyun  */
cmdset_intel_read_jedec_ids(flash_info_t * info)1663*4882a593Smuzhiyun static void cmdset_intel_read_jedec_ids(flash_info_t *info)
1664*4882a593Smuzhiyun {
1665*4882a593Smuzhiyun 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1666*4882a593Smuzhiyun 	udelay(1);
1667*4882a593Smuzhiyun 	flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1668*4882a593Smuzhiyun 	udelay(1000); /* some flash are slow to respond */
1669*4882a593Smuzhiyun 	info->manufacturer_id = flash_read_uchar(info,
1670*4882a593Smuzhiyun 						 FLASH_OFFSET_MANUFACTURER_ID);
1671*4882a593Smuzhiyun 	info->device_id = (info->chipwidth == FLASH_CFI_16BIT) ?
1672*4882a593Smuzhiyun 			flash_read_word(info, FLASH_OFFSET_DEVICE_ID) :
1673*4882a593Smuzhiyun 			flash_read_uchar(info, FLASH_OFFSET_DEVICE_ID);
1674*4882a593Smuzhiyun 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1675*4882a593Smuzhiyun }
1676*4882a593Smuzhiyun 
cmdset_intel_init(flash_info_t * info,struct cfi_qry * qry)1677*4882a593Smuzhiyun static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
1678*4882a593Smuzhiyun {
1679*4882a593Smuzhiyun 	info->cmd_reset = FLASH_CMD_RESET;
1680*4882a593Smuzhiyun 
1681*4882a593Smuzhiyun 	cmdset_intel_read_jedec_ids(info);
1682*4882a593Smuzhiyun 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1683*4882a593Smuzhiyun 
1684*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_PROTECTION
1685*4882a593Smuzhiyun 	/* read legacy lock/unlock bit from intel flash */
1686*4882a593Smuzhiyun 	if (info->ext_addr) {
1687*4882a593Smuzhiyun 		info->legacy_unlock =
1688*4882a593Smuzhiyun 			flash_read_uchar(info, info->ext_addr + 5) & 0x08;
1689*4882a593Smuzhiyun 	}
1690*4882a593Smuzhiyun #endif
1691*4882a593Smuzhiyun 
1692*4882a593Smuzhiyun 	return 0;
1693*4882a593Smuzhiyun }
1694*4882a593Smuzhiyun 
cmdset_amd_read_jedec_ids(flash_info_t * info)1695*4882a593Smuzhiyun static void cmdset_amd_read_jedec_ids(flash_info_t *info)
1696*4882a593Smuzhiyun {
1697*4882a593Smuzhiyun 	ushort bank_id = 0;
1698*4882a593Smuzhiyun 	uchar  manu_id;
1699*4882a593Smuzhiyun 	uchar  feature;
1700*4882a593Smuzhiyun 
1701*4882a593Smuzhiyun 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1702*4882a593Smuzhiyun 	flash_unlock_seq(info, 0);
1703*4882a593Smuzhiyun 	flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
1704*4882a593Smuzhiyun 	udelay(1000); /* some flash are slow to respond */
1705*4882a593Smuzhiyun 
1706*4882a593Smuzhiyun 	manu_id = flash_read_uchar(info, FLASH_OFFSET_MANUFACTURER_ID);
1707*4882a593Smuzhiyun 	/* JEDEC JEP106Z specifies ID codes up to bank 7 */
1708*4882a593Smuzhiyun 	while (manu_id == FLASH_CONTINUATION_CODE && bank_id < 0x800) {
1709*4882a593Smuzhiyun 		bank_id += 0x100;
1710*4882a593Smuzhiyun 		manu_id = flash_read_uchar(info,
1711*4882a593Smuzhiyun 					   bank_id | FLASH_OFFSET_MANUFACTURER_ID);
1712*4882a593Smuzhiyun 	}
1713*4882a593Smuzhiyun 	info->manufacturer_id = manu_id;
1714*4882a593Smuzhiyun 
1715*4882a593Smuzhiyun 	debug("info->ext_addr = 0x%x, cfi_version = 0x%x\n",
1716*4882a593Smuzhiyun 	      info->ext_addr, info->cfi_version);
1717*4882a593Smuzhiyun 	if (info->ext_addr && info->cfi_version >= 0x3134) {
1718*4882a593Smuzhiyun 		/* read software feature (at 0x53) */
1719*4882a593Smuzhiyun 		feature = flash_read_uchar(info, info->ext_addr + 0x13);
1720*4882a593Smuzhiyun 		debug("feature = 0x%x\n", feature);
1721*4882a593Smuzhiyun 		info->sr_supported = feature & 0x1;
1722*4882a593Smuzhiyun 	}
1723*4882a593Smuzhiyun 
1724*4882a593Smuzhiyun 	switch (info->chipwidth) {
1725*4882a593Smuzhiyun 	case FLASH_CFI_8BIT:
1726*4882a593Smuzhiyun 		info->device_id = flash_read_uchar(info,
1727*4882a593Smuzhiyun 						   FLASH_OFFSET_DEVICE_ID);
1728*4882a593Smuzhiyun 		if (info->device_id == 0x7E) {
1729*4882a593Smuzhiyun 			/* AMD 3-byte (expanded) device ids */
1730*4882a593Smuzhiyun 			info->device_id2 = flash_read_uchar(info,
1731*4882a593Smuzhiyun 							    FLASH_OFFSET_DEVICE_ID2);
1732*4882a593Smuzhiyun 			info->device_id2 <<= 8;
1733*4882a593Smuzhiyun 			info->device_id2 |= flash_read_uchar(info,
1734*4882a593Smuzhiyun 						FLASH_OFFSET_DEVICE_ID3);
1735*4882a593Smuzhiyun 		}
1736*4882a593Smuzhiyun 		break;
1737*4882a593Smuzhiyun 	case FLASH_CFI_16BIT:
1738*4882a593Smuzhiyun 		info->device_id = flash_read_word(info,
1739*4882a593Smuzhiyun 						  FLASH_OFFSET_DEVICE_ID);
1740*4882a593Smuzhiyun 		if ((info->device_id & 0xff) == 0x7E) {
1741*4882a593Smuzhiyun 			/* AMD 3-byte (expanded) device ids */
1742*4882a593Smuzhiyun 			info->device_id2 = flash_read_uchar(info,
1743*4882a593Smuzhiyun 							    FLASH_OFFSET_DEVICE_ID2);
1744*4882a593Smuzhiyun 			info->device_id2 <<= 8;
1745*4882a593Smuzhiyun 			info->device_id2 |= flash_read_uchar(info,
1746*4882a593Smuzhiyun 						FLASH_OFFSET_DEVICE_ID3);
1747*4882a593Smuzhiyun 		}
1748*4882a593Smuzhiyun 		break;
1749*4882a593Smuzhiyun 	default:
1750*4882a593Smuzhiyun 		break;
1751*4882a593Smuzhiyun 	}
1752*4882a593Smuzhiyun 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1753*4882a593Smuzhiyun 	udelay(1);
1754*4882a593Smuzhiyun }
1755*4882a593Smuzhiyun 
cmdset_amd_init(flash_info_t * info,struct cfi_qry * qry)1756*4882a593Smuzhiyun static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
1757*4882a593Smuzhiyun {
1758*4882a593Smuzhiyun 	info->cmd_reset = AMD_CMD_RESET;
1759*4882a593Smuzhiyun 	info->cmd_erase_sector = AMD_CMD_ERASE_SECTOR;
1760*4882a593Smuzhiyun 
1761*4882a593Smuzhiyun 	cmdset_amd_read_jedec_ids(info);
1762*4882a593Smuzhiyun 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1763*4882a593Smuzhiyun 
1764*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_PROTECTION
1765*4882a593Smuzhiyun 	if (info->ext_addr) {
1766*4882a593Smuzhiyun 		/* read sector protect/unprotect scheme (at 0x49) */
1767*4882a593Smuzhiyun 		if (flash_read_uchar(info, info->ext_addr + 9) == 0x8)
1768*4882a593Smuzhiyun 			info->legacy_unlock = 1;
1769*4882a593Smuzhiyun 	}
1770*4882a593Smuzhiyun #endif
1771*4882a593Smuzhiyun 
1772*4882a593Smuzhiyun 	return 0;
1773*4882a593Smuzhiyun }
1774*4882a593Smuzhiyun 
1775*4882a593Smuzhiyun #ifdef CONFIG_FLASH_CFI_LEGACY
flash_read_jedec_ids(flash_info_t * info)1776*4882a593Smuzhiyun static void flash_read_jedec_ids(flash_info_t *info)
1777*4882a593Smuzhiyun {
1778*4882a593Smuzhiyun 	info->manufacturer_id = 0;
1779*4882a593Smuzhiyun 	info->device_id       = 0;
1780*4882a593Smuzhiyun 	info->device_id2      = 0;
1781*4882a593Smuzhiyun 
1782*4882a593Smuzhiyun 	switch (info->vendor) {
1783*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_PROG_REGIONS:
1784*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_STANDARD:
1785*4882a593Smuzhiyun 	case CFI_CMDSET_INTEL_EXTENDED:
1786*4882a593Smuzhiyun 		cmdset_intel_read_jedec_ids(info);
1787*4882a593Smuzhiyun 		break;
1788*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_STANDARD:
1789*4882a593Smuzhiyun 	case CFI_CMDSET_AMD_EXTENDED:
1790*4882a593Smuzhiyun 		cmdset_amd_read_jedec_ids(info);
1791*4882a593Smuzhiyun 		break;
1792*4882a593Smuzhiyun 	default:
1793*4882a593Smuzhiyun 		break;
1794*4882a593Smuzhiyun 	}
1795*4882a593Smuzhiyun }
1796*4882a593Smuzhiyun 
1797*4882a593Smuzhiyun /*-----------------------------------------------------------------------
1798*4882a593Smuzhiyun  * Call board code to request info about non-CFI flash.
1799*4882a593Smuzhiyun  * board_flash_get_legacy needs to fill in at least:
1800*4882a593Smuzhiyun  * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1801*4882a593Smuzhiyun  */
flash_detect_legacy(phys_addr_t base,int banknum)1802*4882a593Smuzhiyun static int flash_detect_legacy(phys_addr_t base, int banknum)
1803*4882a593Smuzhiyun {
1804*4882a593Smuzhiyun 	flash_info_t *info = &flash_info[banknum];
1805*4882a593Smuzhiyun 
1806*4882a593Smuzhiyun 	if (board_flash_get_legacy(base, banknum, info)) {
1807*4882a593Smuzhiyun 		/* board code may have filled info completely. If not, we
1808*4882a593Smuzhiyun 		 * use JEDEC ID probing.
1809*4882a593Smuzhiyun 		 */
1810*4882a593Smuzhiyun 		if (!info->vendor) {
1811*4882a593Smuzhiyun 			int modes[] = {
1812*4882a593Smuzhiyun 				CFI_CMDSET_AMD_STANDARD,
1813*4882a593Smuzhiyun 				CFI_CMDSET_INTEL_STANDARD
1814*4882a593Smuzhiyun 			};
1815*4882a593Smuzhiyun 			int i;
1816*4882a593Smuzhiyun 
1817*4882a593Smuzhiyun 			for (i = 0; i < ARRAY_SIZE(modes); i++) {
1818*4882a593Smuzhiyun 				info->vendor = modes[i];
1819*4882a593Smuzhiyun 				info->start[0] =
1820*4882a593Smuzhiyun 					(ulong)map_physmem(base,
1821*4882a593Smuzhiyun 							   info->portwidth,
1822*4882a593Smuzhiyun 							   MAP_NOCACHE);
1823*4882a593Smuzhiyun 				if (info->portwidth == FLASH_CFI_8BIT &&
1824*4882a593Smuzhiyun 				    info->interface == FLASH_CFI_X8X16) {
1825*4882a593Smuzhiyun 					info->addr_unlock1 = 0x2AAA;
1826*4882a593Smuzhiyun 					info->addr_unlock2 = 0x5555;
1827*4882a593Smuzhiyun 				} else {
1828*4882a593Smuzhiyun 					info->addr_unlock1 = 0x5555;
1829*4882a593Smuzhiyun 					info->addr_unlock2 = 0x2AAA;
1830*4882a593Smuzhiyun 				}
1831*4882a593Smuzhiyun 				flash_read_jedec_ids(info);
1832*4882a593Smuzhiyun 				debug("JEDEC PROBE: ID %x %x %x\n",
1833*4882a593Smuzhiyun 				      info->manufacturer_id,
1834*4882a593Smuzhiyun 				      info->device_id,
1835*4882a593Smuzhiyun 				      info->device_id2);
1836*4882a593Smuzhiyun 				if (jedec_flash_match(info, info->start[0]))
1837*4882a593Smuzhiyun 					break;
1838*4882a593Smuzhiyun 
1839*4882a593Smuzhiyun 				unmap_physmem((void *)info->start[0],
1840*4882a593Smuzhiyun 					      info->portwidth);
1841*4882a593Smuzhiyun 			}
1842*4882a593Smuzhiyun 		}
1843*4882a593Smuzhiyun 
1844*4882a593Smuzhiyun 		switch (info->vendor) {
1845*4882a593Smuzhiyun 		case CFI_CMDSET_INTEL_PROG_REGIONS:
1846*4882a593Smuzhiyun 		case CFI_CMDSET_INTEL_STANDARD:
1847*4882a593Smuzhiyun 		case CFI_CMDSET_INTEL_EXTENDED:
1848*4882a593Smuzhiyun 			info->cmd_reset = FLASH_CMD_RESET;
1849*4882a593Smuzhiyun 			break;
1850*4882a593Smuzhiyun 		case CFI_CMDSET_AMD_STANDARD:
1851*4882a593Smuzhiyun 		case CFI_CMDSET_AMD_EXTENDED:
1852*4882a593Smuzhiyun 		case CFI_CMDSET_AMD_LEGACY:
1853*4882a593Smuzhiyun 			info->cmd_reset = AMD_CMD_RESET;
1854*4882a593Smuzhiyun 			break;
1855*4882a593Smuzhiyun 		}
1856*4882a593Smuzhiyun 		info->flash_id = FLASH_MAN_CFI;
1857*4882a593Smuzhiyun 		return 1;
1858*4882a593Smuzhiyun 	}
1859*4882a593Smuzhiyun 	return 0; /* use CFI */
1860*4882a593Smuzhiyun }
1861*4882a593Smuzhiyun #else
flash_detect_legacy(phys_addr_t base,int banknum)1862*4882a593Smuzhiyun static inline int flash_detect_legacy(phys_addr_t base, int banknum)
1863*4882a593Smuzhiyun {
1864*4882a593Smuzhiyun 	return 0; /* use CFI */
1865*4882a593Smuzhiyun }
1866*4882a593Smuzhiyun #endif
1867*4882a593Smuzhiyun 
1868*4882a593Smuzhiyun /*-----------------------------------------------------------------------
1869*4882a593Smuzhiyun  * detect if flash is compatible with the Common Flash Interface (CFI)
1870*4882a593Smuzhiyun  * http://www.jedec.org/download/search/jesd68.pdf
1871*4882a593Smuzhiyun  */
flash_read_cfi(flash_info_t * info,void * buf,unsigned int start,size_t len)1872*4882a593Smuzhiyun static void flash_read_cfi(flash_info_t *info, void *buf, unsigned int start,
1873*4882a593Smuzhiyun 			   size_t len)
1874*4882a593Smuzhiyun {
1875*4882a593Smuzhiyun 	u8 *p = buf;
1876*4882a593Smuzhiyun 	unsigned int i;
1877*4882a593Smuzhiyun 
1878*4882a593Smuzhiyun 	for (i = 0; i < len; i++)
1879*4882a593Smuzhiyun 		p[i] = flash_read_uchar(info, start + i);
1880*4882a593Smuzhiyun }
1881*4882a593Smuzhiyun 
__flash_cmd_reset(flash_info_t * info)1882*4882a593Smuzhiyun static void __flash_cmd_reset(flash_info_t *info)
1883*4882a593Smuzhiyun {
1884*4882a593Smuzhiyun 	/*
1885*4882a593Smuzhiyun 	 * We do not yet know what kind of commandset to use, so we issue
1886*4882a593Smuzhiyun 	 * the reset command in both Intel and AMD variants, in the hope
1887*4882a593Smuzhiyun 	 * that AMD flash roms ignore the Intel command.
1888*4882a593Smuzhiyun 	 */
1889*4882a593Smuzhiyun 	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1890*4882a593Smuzhiyun 	udelay(1);
1891*4882a593Smuzhiyun 	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1892*4882a593Smuzhiyun }
1893*4882a593Smuzhiyun 
1894*4882a593Smuzhiyun void flash_cmd_reset(flash_info_t *info)
1895*4882a593Smuzhiyun 	__attribute__((weak, alias("__flash_cmd_reset")));
1896*4882a593Smuzhiyun 
__flash_detect_cfi(flash_info_t * info,struct cfi_qry * qry)1897*4882a593Smuzhiyun static int __flash_detect_cfi(flash_info_t *info, struct cfi_qry *qry)
1898*4882a593Smuzhiyun {
1899*4882a593Smuzhiyun 	int cfi_offset;
1900*4882a593Smuzhiyun 
1901*4882a593Smuzhiyun 	/* Issue FLASH reset command */
1902*4882a593Smuzhiyun 	flash_cmd_reset(info);
1903*4882a593Smuzhiyun 
1904*4882a593Smuzhiyun 	for (cfi_offset = 0; cfi_offset < ARRAY_SIZE(flash_offset_cfi);
1905*4882a593Smuzhiyun 	     cfi_offset++) {
1906*4882a593Smuzhiyun 		flash_write_cmd(info, 0, flash_offset_cfi[cfi_offset],
1907*4882a593Smuzhiyun 				FLASH_CMD_CFI);
1908*4882a593Smuzhiyun 		if (flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP, 'Q') &&
1909*4882a593Smuzhiyun 		    flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') &&
1910*4882a593Smuzhiyun 		    flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
1911*4882a593Smuzhiyun 			flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1912*4882a593Smuzhiyun 				       sizeof(struct cfi_qry));
1913*4882a593Smuzhiyun 			info->interface	= le16_to_cpu(qry->interface_desc);
1914*4882a593Smuzhiyun 
1915*4882a593Smuzhiyun 			info->cfi_offset = flash_offset_cfi[cfi_offset];
1916*4882a593Smuzhiyun 			debug("device interface is %d\n",
1917*4882a593Smuzhiyun 			      info->interface);
1918*4882a593Smuzhiyun 			debug("found port %d chip %d ",
1919*4882a593Smuzhiyun 			      info->portwidth, info->chipwidth);
1920*4882a593Smuzhiyun 			debug("port %d bits chip %d bits\n",
1921*4882a593Smuzhiyun 			      info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1922*4882a593Smuzhiyun 			      info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1923*4882a593Smuzhiyun 
1924*4882a593Smuzhiyun 			/* calculate command offsets as in the Linux driver */
1925*4882a593Smuzhiyun 			info->addr_unlock1 = 0x555;
1926*4882a593Smuzhiyun 			info->addr_unlock2 = 0x2aa;
1927*4882a593Smuzhiyun 
1928*4882a593Smuzhiyun 			/*
1929*4882a593Smuzhiyun 			 * modify the unlock address if we are
1930*4882a593Smuzhiyun 			 * in compatibility mode
1931*4882a593Smuzhiyun 			 */
1932*4882a593Smuzhiyun 			if (/* x8/x16 in x8 mode */
1933*4882a593Smuzhiyun 			    (info->chipwidth == FLASH_CFI_BY8 &&
1934*4882a593Smuzhiyun 				info->interface == FLASH_CFI_X8X16) ||
1935*4882a593Smuzhiyun 			    /* x16/x32 in x16 mode */
1936*4882a593Smuzhiyun 			    (info->chipwidth == FLASH_CFI_BY16 &&
1937*4882a593Smuzhiyun 				info->interface == FLASH_CFI_X16X32)) {
1938*4882a593Smuzhiyun 				info->addr_unlock1 = 0xaaa;
1939*4882a593Smuzhiyun 				info->addr_unlock2 = 0x555;
1940*4882a593Smuzhiyun 			}
1941*4882a593Smuzhiyun 
1942*4882a593Smuzhiyun 			info->name = "CFI conformant";
1943*4882a593Smuzhiyun 			return 1;
1944*4882a593Smuzhiyun 		}
1945*4882a593Smuzhiyun 	}
1946*4882a593Smuzhiyun 
1947*4882a593Smuzhiyun 	return 0;
1948*4882a593Smuzhiyun }
1949*4882a593Smuzhiyun 
flash_detect_cfi(flash_info_t * info,struct cfi_qry * qry)1950*4882a593Smuzhiyun static int flash_detect_cfi(flash_info_t *info, struct cfi_qry *qry)
1951*4882a593Smuzhiyun {
1952*4882a593Smuzhiyun 	debug("flash detect cfi\n");
1953*4882a593Smuzhiyun 
1954*4882a593Smuzhiyun 	for (info->portwidth = CONFIG_SYS_FLASH_CFI_WIDTH;
1955*4882a593Smuzhiyun 	     info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1956*4882a593Smuzhiyun 		for (info->chipwidth = FLASH_CFI_BY8;
1957*4882a593Smuzhiyun 		     info->chipwidth <= info->portwidth;
1958*4882a593Smuzhiyun 		     info->chipwidth <<= 1)
1959*4882a593Smuzhiyun 			if (__flash_detect_cfi(info, qry))
1960*4882a593Smuzhiyun 				return 1;
1961*4882a593Smuzhiyun 	}
1962*4882a593Smuzhiyun 	debug("not found\n");
1963*4882a593Smuzhiyun 	return 0;
1964*4882a593Smuzhiyun }
1965*4882a593Smuzhiyun 
1966*4882a593Smuzhiyun /*
1967*4882a593Smuzhiyun  * Manufacturer-specific quirks. Add workarounds for geometry
1968*4882a593Smuzhiyun  * reversal, etc. here.
1969*4882a593Smuzhiyun  */
flash_fixup_amd(flash_info_t * info,struct cfi_qry * qry)1970*4882a593Smuzhiyun static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1971*4882a593Smuzhiyun {
1972*4882a593Smuzhiyun 	/* check if flash geometry needs reversal */
1973*4882a593Smuzhiyun 	if (qry->num_erase_regions > 1) {
1974*4882a593Smuzhiyun 		/* reverse geometry if top boot part */
1975*4882a593Smuzhiyun 		if (info->cfi_version < 0x3131) {
1976*4882a593Smuzhiyun 			/* CFI < 1.1, try to guess from device id */
1977*4882a593Smuzhiyun 			if ((info->device_id & 0x80) != 0)
1978*4882a593Smuzhiyun 				cfi_reverse_geometry(qry);
1979*4882a593Smuzhiyun 		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1980*4882a593Smuzhiyun 			/* CFI >= 1.1, deduct from top/bottom flag */
1981*4882a593Smuzhiyun 			/* note: ext_addr is valid since cfi_version > 0 */
1982*4882a593Smuzhiyun 			cfi_reverse_geometry(qry);
1983*4882a593Smuzhiyun 		}
1984*4882a593Smuzhiyun 	}
1985*4882a593Smuzhiyun }
1986*4882a593Smuzhiyun 
flash_fixup_atmel(flash_info_t * info,struct cfi_qry * qry)1987*4882a593Smuzhiyun static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1988*4882a593Smuzhiyun {
1989*4882a593Smuzhiyun 	int reverse_geometry = 0;
1990*4882a593Smuzhiyun 
1991*4882a593Smuzhiyun 	/* Check the "top boot" bit in the PRI */
1992*4882a593Smuzhiyun 	if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1993*4882a593Smuzhiyun 		reverse_geometry = 1;
1994*4882a593Smuzhiyun 
1995*4882a593Smuzhiyun 	/* AT49BV6416(T) list the erase regions in the wrong order.
1996*4882a593Smuzhiyun 	 * However, the device ID is identical with the non-broken
1997*4882a593Smuzhiyun 	 * AT49BV642D they differ in the high byte.
1998*4882a593Smuzhiyun 	 */
1999*4882a593Smuzhiyun 	if (info->device_id == 0xd6 || info->device_id == 0xd2)
2000*4882a593Smuzhiyun 		reverse_geometry = !reverse_geometry;
2001*4882a593Smuzhiyun 
2002*4882a593Smuzhiyun 	if (reverse_geometry)
2003*4882a593Smuzhiyun 		cfi_reverse_geometry(qry);
2004*4882a593Smuzhiyun }
2005*4882a593Smuzhiyun 
flash_fixup_stm(flash_info_t * info,struct cfi_qry * qry)2006*4882a593Smuzhiyun static void flash_fixup_stm(flash_info_t *info, struct cfi_qry *qry)
2007*4882a593Smuzhiyun {
2008*4882a593Smuzhiyun 	/* check if flash geometry needs reversal */
2009*4882a593Smuzhiyun 	if (qry->num_erase_regions > 1) {
2010*4882a593Smuzhiyun 		/* reverse geometry if top boot part */
2011*4882a593Smuzhiyun 		if (info->cfi_version < 0x3131) {
2012*4882a593Smuzhiyun 			/* CFI < 1.1, guess by device id */
2013*4882a593Smuzhiyun 			if (info->device_id == 0x22CA || /* M29W320DT */
2014*4882a593Smuzhiyun 			    info->device_id == 0x2256 || /* M29W320ET */
2015*4882a593Smuzhiyun 			    info->device_id == 0x22D7) { /* M29W800DT */
2016*4882a593Smuzhiyun 				cfi_reverse_geometry(qry);
2017*4882a593Smuzhiyun 			}
2018*4882a593Smuzhiyun 		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
2019*4882a593Smuzhiyun 			/* CFI >= 1.1, deduct from top/bottom flag */
2020*4882a593Smuzhiyun 			/* note: ext_addr is valid since cfi_version > 0 */
2021*4882a593Smuzhiyun 			cfi_reverse_geometry(qry);
2022*4882a593Smuzhiyun 		}
2023*4882a593Smuzhiyun 	}
2024*4882a593Smuzhiyun }
2025*4882a593Smuzhiyun 
flash_fixup_sst(flash_info_t * info,struct cfi_qry * qry)2026*4882a593Smuzhiyun static void flash_fixup_sst(flash_info_t *info, struct cfi_qry *qry)
2027*4882a593Smuzhiyun {
2028*4882a593Smuzhiyun 	/*
2029*4882a593Smuzhiyun 	 * SST, for many recent nor parallel flashes, says they are
2030*4882a593Smuzhiyun 	 * CFI-conformant. This is not true, since qry struct.
2031*4882a593Smuzhiyun 	 * reports a std. AMD command set (0x0002), while SST allows to
2032*4882a593Smuzhiyun 	 * erase two different sector sizes for the same memory.
2033*4882a593Smuzhiyun 	 * 64KB sector (SST call it block)  needs 0x30 to be erased.
2034*4882a593Smuzhiyun 	 * 4KB  sector (SST call it sector) needs 0x50 to be erased.
2035*4882a593Smuzhiyun 	 * Since CFI query detect the 4KB number of sectors, users expects
2036*4882a593Smuzhiyun 	 * a sector granularity of 4KB, and it is here set.
2037*4882a593Smuzhiyun 	 */
2038*4882a593Smuzhiyun 	if (info->device_id == 0x5D23 || /* SST39VF3201B */
2039*4882a593Smuzhiyun 	    info->device_id == 0x5C23) { /* SST39VF3202B */
2040*4882a593Smuzhiyun 		/* set sector granularity to 4KB */
2041*4882a593Smuzhiyun 		info->cmd_erase_sector = 0x50;
2042*4882a593Smuzhiyun 	}
2043*4882a593Smuzhiyun }
2044*4882a593Smuzhiyun 
flash_fixup_num(flash_info_t * info,struct cfi_qry * qry)2045*4882a593Smuzhiyun static void flash_fixup_num(flash_info_t *info, struct cfi_qry *qry)
2046*4882a593Smuzhiyun {
2047*4882a593Smuzhiyun 	/*
2048*4882a593Smuzhiyun 	 * The M29EW devices seem to report the CFI information wrong
2049*4882a593Smuzhiyun 	 * when it's in 8 bit mode.
2050*4882a593Smuzhiyun 	 * There's an app note from Numonyx on this issue.
2051*4882a593Smuzhiyun 	 * So adjust the buffer size for M29EW while operating in 8-bit mode
2052*4882a593Smuzhiyun 	 */
2053*4882a593Smuzhiyun 	if (qry->max_buf_write_size > 0x8 &&
2054*4882a593Smuzhiyun 	    info->device_id == 0x7E &&
2055*4882a593Smuzhiyun 	    (info->device_id2 == 0x2201 ||
2056*4882a593Smuzhiyun 	     info->device_id2 == 0x2301 ||
2057*4882a593Smuzhiyun 	     info->device_id2 == 0x2801 ||
2058*4882a593Smuzhiyun 	     info->device_id2 == 0x4801)) {
2059*4882a593Smuzhiyun 		debug("Adjusted buffer size on Numonyx flash");
2060*4882a593Smuzhiyun 		debug(" M29EW family in 8 bit mode\n");
2061*4882a593Smuzhiyun 		qry->max_buf_write_size = 0x8;
2062*4882a593Smuzhiyun 	}
2063*4882a593Smuzhiyun }
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun /*
2066*4882a593Smuzhiyun  * The following code cannot be run from FLASH!
2067*4882a593Smuzhiyun  *
2068*4882a593Smuzhiyun  */
flash_get_size(phys_addr_t base,int banknum)2069*4882a593Smuzhiyun ulong flash_get_size(phys_addr_t base, int banknum)
2070*4882a593Smuzhiyun {
2071*4882a593Smuzhiyun 	flash_info_t *info = &flash_info[banknum];
2072*4882a593Smuzhiyun 	int i, j;
2073*4882a593Smuzhiyun 	flash_sect_t sect_cnt;
2074*4882a593Smuzhiyun 	phys_addr_t sector;
2075*4882a593Smuzhiyun 	unsigned long tmp;
2076*4882a593Smuzhiyun 	int size_ratio;
2077*4882a593Smuzhiyun 	uchar num_erase_regions;
2078*4882a593Smuzhiyun 	int erase_region_size;
2079*4882a593Smuzhiyun 	int erase_region_count;
2080*4882a593Smuzhiyun 	struct cfi_qry qry;
2081*4882a593Smuzhiyun 	unsigned long max_size;
2082*4882a593Smuzhiyun 
2083*4882a593Smuzhiyun 	memset(&qry, 0, sizeof(qry));
2084*4882a593Smuzhiyun 
2085*4882a593Smuzhiyun 	info->ext_addr = 0;
2086*4882a593Smuzhiyun 	info->cfi_version = 0;
2087*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_PROTECTION
2088*4882a593Smuzhiyun 	info->legacy_unlock = 0;
2089*4882a593Smuzhiyun #endif
2090*4882a593Smuzhiyun 
2091*4882a593Smuzhiyun 	info->start[0] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE);
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun 	if (flash_detect_cfi(info, &qry)) {
2094*4882a593Smuzhiyun 		info->vendor = le16_to_cpu(get_unaligned(&qry.p_id));
2095*4882a593Smuzhiyun 		info->ext_addr = le16_to_cpu(get_unaligned(&qry.p_adr));
2096*4882a593Smuzhiyun 		num_erase_regions = qry.num_erase_regions;
2097*4882a593Smuzhiyun 
2098*4882a593Smuzhiyun 		if (info->ext_addr) {
2099*4882a593Smuzhiyun 			info->cfi_version = (ushort)flash_read_uchar(info,
2100*4882a593Smuzhiyun 						info->ext_addr + 3) << 8;
2101*4882a593Smuzhiyun 			info->cfi_version |= (ushort)flash_read_uchar(info,
2102*4882a593Smuzhiyun 						info->ext_addr + 4);
2103*4882a593Smuzhiyun 		}
2104*4882a593Smuzhiyun 
2105*4882a593Smuzhiyun #ifdef DEBUG
2106*4882a593Smuzhiyun 		flash_printqry(&qry);
2107*4882a593Smuzhiyun #endif
2108*4882a593Smuzhiyun 
2109*4882a593Smuzhiyun 		switch (info->vendor) {
2110*4882a593Smuzhiyun 		case CFI_CMDSET_INTEL_PROG_REGIONS:
2111*4882a593Smuzhiyun 		case CFI_CMDSET_INTEL_STANDARD:
2112*4882a593Smuzhiyun 		case CFI_CMDSET_INTEL_EXTENDED:
2113*4882a593Smuzhiyun 			cmdset_intel_init(info, &qry);
2114*4882a593Smuzhiyun 			break;
2115*4882a593Smuzhiyun 		case CFI_CMDSET_AMD_STANDARD:
2116*4882a593Smuzhiyun 		case CFI_CMDSET_AMD_EXTENDED:
2117*4882a593Smuzhiyun 			cmdset_amd_init(info, &qry);
2118*4882a593Smuzhiyun 			break;
2119*4882a593Smuzhiyun 		default:
2120*4882a593Smuzhiyun 			printf("CFI: Unknown command set 0x%x\n",
2121*4882a593Smuzhiyun 			       info->vendor);
2122*4882a593Smuzhiyun 			/*
2123*4882a593Smuzhiyun 			 * Unfortunately, this means we don't know how
2124*4882a593Smuzhiyun 			 * to get the chip back to Read mode. Might
2125*4882a593Smuzhiyun 			 * as well try an Intel-style reset...
2126*4882a593Smuzhiyun 			 */
2127*4882a593Smuzhiyun 			flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
2128*4882a593Smuzhiyun 			return 0;
2129*4882a593Smuzhiyun 		}
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun 		/* Do manufacturer-specific fixups */
2132*4882a593Smuzhiyun 		switch (info->manufacturer_id) {
2133*4882a593Smuzhiyun 		case 0x0001: /* AMD */
2134*4882a593Smuzhiyun 		case 0x0037: /* AMIC */
2135*4882a593Smuzhiyun 			flash_fixup_amd(info, &qry);
2136*4882a593Smuzhiyun 			break;
2137*4882a593Smuzhiyun 		case 0x001f:
2138*4882a593Smuzhiyun 			flash_fixup_atmel(info, &qry);
2139*4882a593Smuzhiyun 			break;
2140*4882a593Smuzhiyun 		case 0x0020:
2141*4882a593Smuzhiyun 			flash_fixup_stm(info, &qry);
2142*4882a593Smuzhiyun 			break;
2143*4882a593Smuzhiyun 		case 0x00bf: /* SST */
2144*4882a593Smuzhiyun 			flash_fixup_sst(info, &qry);
2145*4882a593Smuzhiyun 			break;
2146*4882a593Smuzhiyun 		case 0x0089: /* Numonyx */
2147*4882a593Smuzhiyun 			flash_fixup_num(info, &qry);
2148*4882a593Smuzhiyun 			break;
2149*4882a593Smuzhiyun 		}
2150*4882a593Smuzhiyun 
2151*4882a593Smuzhiyun 		debug("manufacturer is %d\n", info->vendor);
2152*4882a593Smuzhiyun 		debug("manufacturer id is 0x%x\n", info->manufacturer_id);
2153*4882a593Smuzhiyun 		debug("device id is 0x%x\n", info->device_id);
2154*4882a593Smuzhiyun 		debug("device id2 is 0x%x\n", info->device_id2);
2155*4882a593Smuzhiyun 		debug("cfi version is 0x%04x\n", info->cfi_version);
2156*4882a593Smuzhiyun 
2157*4882a593Smuzhiyun 		size_ratio = info->portwidth / info->chipwidth;
2158*4882a593Smuzhiyun 		/* if the chip is x8/x16 reduce the ratio by half */
2159*4882a593Smuzhiyun 		if (info->interface == FLASH_CFI_X8X16 &&
2160*4882a593Smuzhiyun 		    info->chipwidth == FLASH_CFI_BY8) {
2161*4882a593Smuzhiyun 			size_ratio >>= 1;
2162*4882a593Smuzhiyun 		}
2163*4882a593Smuzhiyun 		debug("size_ratio %d port %d bits chip %d bits\n",
2164*4882a593Smuzhiyun 		      size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
2165*4882a593Smuzhiyun 		      info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
2166*4882a593Smuzhiyun 		info->size = 1 << qry.dev_size;
2167*4882a593Smuzhiyun 		/* multiply the size by the number of chips */
2168*4882a593Smuzhiyun 		info->size *= size_ratio;
2169*4882a593Smuzhiyun 		max_size = cfi_flash_bank_size(banknum);
2170*4882a593Smuzhiyun 		if (max_size && info->size > max_size) {
2171*4882a593Smuzhiyun 			debug("[truncated from %ldMiB]", info->size >> 20);
2172*4882a593Smuzhiyun 			info->size = max_size;
2173*4882a593Smuzhiyun 		}
2174*4882a593Smuzhiyun 		debug("found %d erase regions\n", num_erase_regions);
2175*4882a593Smuzhiyun 		sect_cnt = 0;
2176*4882a593Smuzhiyun 		sector = base;
2177*4882a593Smuzhiyun 		for (i = 0; i < num_erase_regions; i++) {
2178*4882a593Smuzhiyun 			if (i > NUM_ERASE_REGIONS) {
2179*4882a593Smuzhiyun 				printf("%d erase regions found, only %d used\n",
2180*4882a593Smuzhiyun 				       num_erase_regions, NUM_ERASE_REGIONS);
2181*4882a593Smuzhiyun 				break;
2182*4882a593Smuzhiyun 			}
2183*4882a593Smuzhiyun 
2184*4882a593Smuzhiyun 			tmp = le32_to_cpu(get_unaligned(
2185*4882a593Smuzhiyun 						&qry.erase_region_info[i]));
2186*4882a593Smuzhiyun 			debug("erase region %u: 0x%08lx\n", i, tmp);
2187*4882a593Smuzhiyun 
2188*4882a593Smuzhiyun 			erase_region_count = (tmp & 0xffff) + 1;
2189*4882a593Smuzhiyun 			tmp >>= 16;
2190*4882a593Smuzhiyun 			erase_region_size =
2191*4882a593Smuzhiyun 				(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
2192*4882a593Smuzhiyun 			debug("erase_region_count = %d ", erase_region_count);
2193*4882a593Smuzhiyun 			debug("erase_region_size = %d\n", erase_region_size);
2194*4882a593Smuzhiyun 			for (j = 0; j < erase_region_count; j++) {
2195*4882a593Smuzhiyun 				if (sector - base >= info->size)
2196*4882a593Smuzhiyun 					break;
2197*4882a593Smuzhiyun 				if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
2198*4882a593Smuzhiyun 					printf("ERROR: too many flash sectors\n");
2199*4882a593Smuzhiyun 					break;
2200*4882a593Smuzhiyun 				}
2201*4882a593Smuzhiyun 				info->start[sect_cnt] =
2202*4882a593Smuzhiyun 					(ulong)map_physmem(sector,
2203*4882a593Smuzhiyun 							   info->portwidth,
2204*4882a593Smuzhiyun 							   MAP_NOCACHE);
2205*4882a593Smuzhiyun 				sector += (erase_region_size * size_ratio);
2206*4882a593Smuzhiyun 
2207*4882a593Smuzhiyun 				/*
2208*4882a593Smuzhiyun 				 * Only read protection status from
2209*4882a593Smuzhiyun 				 * supported devices (intel...)
2210*4882a593Smuzhiyun 				 */
2211*4882a593Smuzhiyun 				switch (info->vendor) {
2212*4882a593Smuzhiyun 				case CFI_CMDSET_INTEL_PROG_REGIONS:
2213*4882a593Smuzhiyun 				case CFI_CMDSET_INTEL_EXTENDED:
2214*4882a593Smuzhiyun 				case CFI_CMDSET_INTEL_STANDARD:
2215*4882a593Smuzhiyun 					/*
2216*4882a593Smuzhiyun 					 * Set flash to read-id mode. Otherwise
2217*4882a593Smuzhiyun 					 * reading protected status is not
2218*4882a593Smuzhiyun 					 * guaranteed.
2219*4882a593Smuzhiyun 					 */
2220*4882a593Smuzhiyun 					flash_write_cmd(info, sect_cnt, 0,
2221*4882a593Smuzhiyun 							FLASH_CMD_READ_ID);
2222*4882a593Smuzhiyun 					info->protect[sect_cnt] =
2223*4882a593Smuzhiyun 						flash_isset(info, sect_cnt,
2224*4882a593Smuzhiyun 							    FLASH_OFFSET_PROTECT,
2225*4882a593Smuzhiyun 							    FLASH_STATUS_PROTECT);
2226*4882a593Smuzhiyun 					flash_write_cmd(info, sect_cnt, 0,
2227*4882a593Smuzhiyun 							FLASH_CMD_RESET);
2228*4882a593Smuzhiyun 					break;
2229*4882a593Smuzhiyun 				case CFI_CMDSET_AMD_EXTENDED:
2230*4882a593Smuzhiyun 				case CFI_CMDSET_AMD_STANDARD:
2231*4882a593Smuzhiyun 					if (!info->legacy_unlock) {
2232*4882a593Smuzhiyun 						/* default: not protected */
2233*4882a593Smuzhiyun 						info->protect[sect_cnt] = 0;
2234*4882a593Smuzhiyun 						break;
2235*4882a593Smuzhiyun 					}
2236*4882a593Smuzhiyun 
2237*4882a593Smuzhiyun 					/* Read protection (PPB) from sector */
2238*4882a593Smuzhiyun 					flash_write_cmd(info, 0, 0,
2239*4882a593Smuzhiyun 							info->cmd_reset);
2240*4882a593Smuzhiyun 					flash_unlock_seq(info, 0);
2241*4882a593Smuzhiyun 					flash_write_cmd(info, 0,
2242*4882a593Smuzhiyun 							info->addr_unlock1,
2243*4882a593Smuzhiyun 							FLASH_CMD_READ_ID);
2244*4882a593Smuzhiyun 					info->protect[sect_cnt] =
2245*4882a593Smuzhiyun 						flash_isset(
2246*4882a593Smuzhiyun 							info, sect_cnt,
2247*4882a593Smuzhiyun 							FLASH_OFFSET_PROTECT,
2248*4882a593Smuzhiyun 							FLASH_STATUS_PROTECT);
2249*4882a593Smuzhiyun 					break;
2250*4882a593Smuzhiyun 				default:
2251*4882a593Smuzhiyun 					/* default: not protected */
2252*4882a593Smuzhiyun 					info->protect[sect_cnt] = 0;
2253*4882a593Smuzhiyun 				}
2254*4882a593Smuzhiyun 
2255*4882a593Smuzhiyun 				sect_cnt++;
2256*4882a593Smuzhiyun 			}
2257*4882a593Smuzhiyun 		}
2258*4882a593Smuzhiyun 
2259*4882a593Smuzhiyun 		info->sector_count = sect_cnt;
2260*4882a593Smuzhiyun 		info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
2261*4882a593Smuzhiyun 		tmp = 1 << qry.block_erase_timeout_typ;
2262*4882a593Smuzhiyun 		info->erase_blk_tout = tmp *
2263*4882a593Smuzhiyun 			(1 << qry.block_erase_timeout_max);
2264*4882a593Smuzhiyun 		tmp = (1 << qry.buf_write_timeout_typ) *
2265*4882a593Smuzhiyun 			(1 << qry.buf_write_timeout_max);
2266*4882a593Smuzhiyun 
2267*4882a593Smuzhiyun 		/* round up when converting to ms */
2268*4882a593Smuzhiyun 		info->buffer_write_tout = (tmp + 999) / 1000;
2269*4882a593Smuzhiyun 		tmp = (1 << qry.word_write_timeout_typ) *
2270*4882a593Smuzhiyun 			(1 << qry.word_write_timeout_max);
2271*4882a593Smuzhiyun 		/* round up when converting to ms */
2272*4882a593Smuzhiyun 		info->write_tout = (tmp + 999) / 1000;
2273*4882a593Smuzhiyun 		info->flash_id = FLASH_MAN_CFI;
2274*4882a593Smuzhiyun 		if (info->interface == FLASH_CFI_X8X16 &&
2275*4882a593Smuzhiyun 		    info->chipwidth == FLASH_CFI_BY8) {
2276*4882a593Smuzhiyun 			/* XXX - Need to test on x8/x16 in parallel. */
2277*4882a593Smuzhiyun 			info->portwidth >>= 1;
2278*4882a593Smuzhiyun 		}
2279*4882a593Smuzhiyun 
2280*4882a593Smuzhiyun 		flash_write_cmd(info, 0, 0, info->cmd_reset);
2281*4882a593Smuzhiyun 	}
2282*4882a593Smuzhiyun 
2283*4882a593Smuzhiyun 	return (info->size);
2284*4882a593Smuzhiyun }
2285*4882a593Smuzhiyun 
2286*4882a593Smuzhiyun #ifdef CONFIG_FLASH_CFI_MTD
flash_set_verbose(uint v)2287*4882a593Smuzhiyun void flash_set_verbose(uint v)
2288*4882a593Smuzhiyun {
2289*4882a593Smuzhiyun 	flash_verbose = v;
2290*4882a593Smuzhiyun }
2291*4882a593Smuzhiyun #endif
2292*4882a593Smuzhiyun 
cfi_flash_set_config_reg(u32 base,u16 val)2293*4882a593Smuzhiyun static void cfi_flash_set_config_reg(u32 base, u16 val)
2294*4882a593Smuzhiyun {
2295*4882a593Smuzhiyun #ifdef CONFIG_SYS_CFI_FLASH_CONFIG_REGS
2296*4882a593Smuzhiyun 	/*
2297*4882a593Smuzhiyun 	 * Only set this config register if really defined
2298*4882a593Smuzhiyun 	 * to a valid value (0xffff is invalid)
2299*4882a593Smuzhiyun 	 */
2300*4882a593Smuzhiyun 	if (val == 0xffff)
2301*4882a593Smuzhiyun 		return;
2302*4882a593Smuzhiyun 
2303*4882a593Smuzhiyun 	/*
2304*4882a593Smuzhiyun 	 * Set configuration register. Data is "encrypted" in the 16 lower
2305*4882a593Smuzhiyun 	 * address bits.
2306*4882a593Smuzhiyun 	 */
2307*4882a593Smuzhiyun 	flash_write16(FLASH_CMD_SETUP, (void *)(base + (val << 1)));
2308*4882a593Smuzhiyun 	flash_write16(FLASH_CMD_SET_CR_CONFIRM, (void *)(base + (val << 1)));
2309*4882a593Smuzhiyun 
2310*4882a593Smuzhiyun 	/*
2311*4882a593Smuzhiyun 	 * Finally issue reset-command to bring device back to
2312*4882a593Smuzhiyun 	 * read-array mode
2313*4882a593Smuzhiyun 	 */
2314*4882a593Smuzhiyun 	flash_write16(FLASH_CMD_RESET, (void *)base);
2315*4882a593Smuzhiyun #endif
2316*4882a593Smuzhiyun }
2317*4882a593Smuzhiyun 
2318*4882a593Smuzhiyun /*-----------------------------------------------------------------------
2319*4882a593Smuzhiyun  */
2320*4882a593Smuzhiyun 
flash_protect_default(void)2321*4882a593Smuzhiyun static void flash_protect_default(void)
2322*4882a593Smuzhiyun {
2323*4882a593Smuzhiyun #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
2324*4882a593Smuzhiyun 	int i;
2325*4882a593Smuzhiyun 	struct apl_s {
2326*4882a593Smuzhiyun 		ulong start;
2327*4882a593Smuzhiyun 		ulong size;
2328*4882a593Smuzhiyun 	} apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST;
2329*4882a593Smuzhiyun #endif
2330*4882a593Smuzhiyun 
2331*4882a593Smuzhiyun 	/* Monitor protection ON by default */
2332*4882a593Smuzhiyun #if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE) && \
2333*4882a593Smuzhiyun 	(!defined(CONFIG_MONITOR_IS_IN_RAM))
2334*4882a593Smuzhiyun 	flash_protect(FLAG_PROTECT_SET,
2335*4882a593Smuzhiyun 		      CONFIG_SYS_MONITOR_BASE,
2336*4882a593Smuzhiyun 		      CONFIG_SYS_MONITOR_BASE + monitor_flash_len  - 1,
2337*4882a593Smuzhiyun 		      flash_get_info(CONFIG_SYS_MONITOR_BASE));
2338*4882a593Smuzhiyun #endif
2339*4882a593Smuzhiyun 
2340*4882a593Smuzhiyun 	/* Environment protection ON by default */
2341*4882a593Smuzhiyun #ifdef CONFIG_ENV_IS_IN_FLASH
2342*4882a593Smuzhiyun 	flash_protect(FLAG_PROTECT_SET,
2343*4882a593Smuzhiyun 		      CONFIG_ENV_ADDR,
2344*4882a593Smuzhiyun 		      CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
2345*4882a593Smuzhiyun 		      flash_get_info(CONFIG_ENV_ADDR));
2346*4882a593Smuzhiyun #endif
2347*4882a593Smuzhiyun 
2348*4882a593Smuzhiyun 	/* Redundant environment protection ON by default */
2349*4882a593Smuzhiyun #ifdef CONFIG_ENV_ADDR_REDUND
2350*4882a593Smuzhiyun 	flash_protect(FLAG_PROTECT_SET,
2351*4882a593Smuzhiyun 		      CONFIG_ENV_ADDR_REDUND,
2352*4882a593Smuzhiyun 		      CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1,
2353*4882a593Smuzhiyun 		      flash_get_info(CONFIG_ENV_ADDR_REDUND));
2354*4882a593Smuzhiyun #endif
2355*4882a593Smuzhiyun 
2356*4882a593Smuzhiyun #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
2357*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(apl); i++) {
2358*4882a593Smuzhiyun 		debug("autoprotecting from %08lx to %08lx\n",
2359*4882a593Smuzhiyun 		      apl[i].start, apl[i].start + apl[i].size - 1);
2360*4882a593Smuzhiyun 		flash_protect(FLAG_PROTECT_SET,
2361*4882a593Smuzhiyun 			      apl[i].start,
2362*4882a593Smuzhiyun 			      apl[i].start + apl[i].size - 1,
2363*4882a593Smuzhiyun 			      flash_get_info(apl[i].start));
2364*4882a593Smuzhiyun 	}
2365*4882a593Smuzhiyun #endif
2366*4882a593Smuzhiyun }
2367*4882a593Smuzhiyun 
flash_init(void)2368*4882a593Smuzhiyun unsigned long flash_init(void)
2369*4882a593Smuzhiyun {
2370*4882a593Smuzhiyun 	unsigned long size = 0;
2371*4882a593Smuzhiyun 	int i;
2372*4882a593Smuzhiyun 
2373*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_PROTECTION
2374*4882a593Smuzhiyun 	/* read environment from EEPROM */
2375*4882a593Smuzhiyun 	char s[64];
2376*4882a593Smuzhiyun 
2377*4882a593Smuzhiyun 	env_get_f("unlock", s, sizeof(s));
2378*4882a593Smuzhiyun #endif
2379*4882a593Smuzhiyun 
2380*4882a593Smuzhiyun #ifdef CONFIG_CFI_FLASH /* for driver model */
2381*4882a593Smuzhiyun 	cfi_flash_init_dm();
2382*4882a593Smuzhiyun #endif
2383*4882a593Smuzhiyun 
2384*4882a593Smuzhiyun 	/* Init: no FLASHes known */
2385*4882a593Smuzhiyun 	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
2386*4882a593Smuzhiyun 		flash_info[i].flash_id = FLASH_UNKNOWN;
2387*4882a593Smuzhiyun 
2388*4882a593Smuzhiyun 		/* Optionally write flash configuration register */
2389*4882a593Smuzhiyun 		cfi_flash_set_config_reg(cfi_flash_bank_addr(i),
2390*4882a593Smuzhiyun 					 cfi_flash_config_reg(i));
2391*4882a593Smuzhiyun 
2392*4882a593Smuzhiyun 		if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
2393*4882a593Smuzhiyun 			flash_get_size(cfi_flash_bank_addr(i), i);
2394*4882a593Smuzhiyun 		size += flash_info[i].size;
2395*4882a593Smuzhiyun 		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
2396*4882a593Smuzhiyun #ifndef CONFIG_SYS_FLASH_QUIET_TEST
2397*4882a593Smuzhiyun 			printf("## Unknown flash on Bank %d ", i + 1);
2398*4882a593Smuzhiyun 			printf("- Size = 0x%08lx = %ld MB\n",
2399*4882a593Smuzhiyun 			       flash_info[i].size,
2400*4882a593Smuzhiyun 			       flash_info[i].size >> 20);
2401*4882a593Smuzhiyun #endif /* CONFIG_SYS_FLASH_QUIET_TEST */
2402*4882a593Smuzhiyun 		}
2403*4882a593Smuzhiyun #ifdef CONFIG_SYS_FLASH_PROTECTION
2404*4882a593Smuzhiyun 		else if (strcmp(s, "yes") == 0) {
2405*4882a593Smuzhiyun 			/*
2406*4882a593Smuzhiyun 			 * Only the U-Boot image and it's environment
2407*4882a593Smuzhiyun 			 * is protected, all other sectors are
2408*4882a593Smuzhiyun 			 * unprotected (unlocked) if flash hardware
2409*4882a593Smuzhiyun 			 * protection is used (CONFIG_SYS_FLASH_PROTECTION)
2410*4882a593Smuzhiyun 			 * and the environment variable "unlock" is
2411*4882a593Smuzhiyun 			 * set to "yes".
2412*4882a593Smuzhiyun 			 */
2413*4882a593Smuzhiyun 			if (flash_info[i].legacy_unlock) {
2414*4882a593Smuzhiyun 				int k;
2415*4882a593Smuzhiyun 
2416*4882a593Smuzhiyun 				/*
2417*4882a593Smuzhiyun 				 * Disable legacy_unlock temporarily,
2418*4882a593Smuzhiyun 				 * since flash_real_protect would
2419*4882a593Smuzhiyun 				 * relock all other sectors again
2420*4882a593Smuzhiyun 				 * otherwise.
2421*4882a593Smuzhiyun 				 */
2422*4882a593Smuzhiyun 				flash_info[i].legacy_unlock = 0;
2423*4882a593Smuzhiyun 
2424*4882a593Smuzhiyun 				/*
2425*4882a593Smuzhiyun 				 * Legacy unlocking (e.g. Intel J3) ->
2426*4882a593Smuzhiyun 				 * unlock only one sector. This will
2427*4882a593Smuzhiyun 				 * unlock all sectors.
2428*4882a593Smuzhiyun 				 */
2429*4882a593Smuzhiyun 				flash_real_protect(&flash_info[i], 0, 0);
2430*4882a593Smuzhiyun 
2431*4882a593Smuzhiyun 				flash_info[i].legacy_unlock = 1;
2432*4882a593Smuzhiyun 
2433*4882a593Smuzhiyun 				/*
2434*4882a593Smuzhiyun 				 * Manually mark other sectors as
2435*4882a593Smuzhiyun 				 * unlocked (unprotected)
2436*4882a593Smuzhiyun 				 */
2437*4882a593Smuzhiyun 				for (k = 1; k < flash_info[i].sector_count; k++)
2438*4882a593Smuzhiyun 					flash_info[i].protect[k] = 0;
2439*4882a593Smuzhiyun 			} else {
2440*4882a593Smuzhiyun 				/*
2441*4882a593Smuzhiyun 				 * No legancy unlocking -> unlock all sectors
2442*4882a593Smuzhiyun 				 */
2443*4882a593Smuzhiyun 				flash_protect(FLAG_PROTECT_CLEAR,
2444*4882a593Smuzhiyun 					      flash_info[i].start[0],
2445*4882a593Smuzhiyun 					      flash_info[i].start[0]
2446*4882a593Smuzhiyun 					      + flash_info[i].size - 1,
2447*4882a593Smuzhiyun 					      &flash_info[i]);
2448*4882a593Smuzhiyun 			}
2449*4882a593Smuzhiyun 		}
2450*4882a593Smuzhiyun #endif /* CONFIG_SYS_FLASH_PROTECTION */
2451*4882a593Smuzhiyun 	}
2452*4882a593Smuzhiyun 
2453*4882a593Smuzhiyun 	flash_protect_default();
2454*4882a593Smuzhiyun #ifdef CONFIG_FLASH_CFI_MTD
2455*4882a593Smuzhiyun 	cfi_mtd_init();
2456*4882a593Smuzhiyun #endif
2457*4882a593Smuzhiyun 
2458*4882a593Smuzhiyun 	return (size);
2459*4882a593Smuzhiyun }
2460*4882a593Smuzhiyun 
2461*4882a593Smuzhiyun #ifdef CONFIG_CFI_FLASH /* for driver model */
cfi_flash_probe(struct udevice * dev)2462*4882a593Smuzhiyun static int cfi_flash_probe(struct udevice *dev)
2463*4882a593Smuzhiyun {
2464*4882a593Smuzhiyun 	const fdt32_t *cell;
2465*4882a593Smuzhiyun 	int addrc, sizec;
2466*4882a593Smuzhiyun 	int len, idx;
2467*4882a593Smuzhiyun 
2468*4882a593Smuzhiyun 	addrc = dev_read_addr_cells(dev);
2469*4882a593Smuzhiyun 	sizec = dev_read_size_cells(dev);
2470*4882a593Smuzhiyun 
2471*4882a593Smuzhiyun 	/* decode regs; there may be multiple reg tuples. */
2472*4882a593Smuzhiyun 	cell = dev_read_prop(dev, "reg", &len);
2473*4882a593Smuzhiyun 	if (!cell)
2474*4882a593Smuzhiyun 		return -ENOENT;
2475*4882a593Smuzhiyun 	idx = 0;
2476*4882a593Smuzhiyun 	len /= sizeof(fdt32_t);
2477*4882a593Smuzhiyun 	while (idx < len) {
2478*4882a593Smuzhiyun 		phys_addr_t addr;
2479*4882a593Smuzhiyun 
2480*4882a593Smuzhiyun 		addr = dev_translate_address(dev, cell + idx);
2481*4882a593Smuzhiyun 
2482*4882a593Smuzhiyun 		flash_info[cfi_flash_num_flash_banks].dev = dev;
2483*4882a593Smuzhiyun 		flash_info[cfi_flash_num_flash_banks].base = addr;
2484*4882a593Smuzhiyun 		cfi_flash_num_flash_banks++;
2485*4882a593Smuzhiyun 
2486*4882a593Smuzhiyun 		idx += addrc + sizec;
2487*4882a593Smuzhiyun 	}
2488*4882a593Smuzhiyun 	gd->bd->bi_flashstart = flash_info[0].base;
2489*4882a593Smuzhiyun 
2490*4882a593Smuzhiyun 	return 0;
2491*4882a593Smuzhiyun }
2492*4882a593Smuzhiyun 
2493*4882a593Smuzhiyun static const struct udevice_id cfi_flash_ids[] = {
2494*4882a593Smuzhiyun 	{ .compatible = "cfi-flash" },
2495*4882a593Smuzhiyun 	{ .compatible = "jedec-flash" },
2496*4882a593Smuzhiyun 	{}
2497*4882a593Smuzhiyun };
2498*4882a593Smuzhiyun 
2499*4882a593Smuzhiyun U_BOOT_DRIVER(cfi_flash) = {
2500*4882a593Smuzhiyun 	.name	= "cfi_flash",
2501*4882a593Smuzhiyun 	.id	= UCLASS_MTD,
2502*4882a593Smuzhiyun 	.of_match = cfi_flash_ids,
2503*4882a593Smuzhiyun 	.probe = cfi_flash_probe,
2504*4882a593Smuzhiyun };
2505*4882a593Smuzhiyun #endif /* CONFIG_CFI_FLASH */
2506