xref: /rk3399_rockchip-uboot/drivers/mtd/cfi_flash.c (revision 59829cc189378c142c13d2aa8d9a897d8bef3961)
1*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*
2*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * (C) Copyright 2002-2004
3*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com
4*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
5*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copyright (C) 2003 Arabella Software Ltd.
6*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Yuli Barcohen <yuli@arabellasw.com>
7*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
8*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copyright (C) 2004
9*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Ed Okerson
10*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
11*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copyright (C) 2006
12*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Tolunay Orkun <listmember@orkun.us>
13*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
14*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * See file CREDITS for list of people who contributed to this
15*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * project.
16*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
17*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * This program is free software; you can redistribute it and/or
18*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * modify it under the terms of the GNU General Public License as
19*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * published by the Free Software Foundation; either version 2 of
20*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * the License, or (at your option) any later version.
21*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
22*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * This program is distributed in the hope that it will be useful,
23*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
25*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * GNU General Public License for more details.
26*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
27*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * You should have received a copy of the GNU General Public License
28*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * along with this program; if not, write to the Free Software
29*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * MA 02111-1307 USA
31*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
32*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
33*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
34*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* The DEBUG define must be before common to enable debugging */
35*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* #define DEBUG	*/
36*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
37*59829cc1SJean-Christophe PLAGNIOL-VILLARD #include <common.h>
38*59829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/processor.h>
39*59829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h>
40*59829cc1SJean-Christophe PLAGNIOL-VILLARD #include <asm/byteorder.h>
41*59829cc1SJean-Christophe PLAGNIOL-VILLARD #include <environment.h>
42*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef	CFG_FLASH_CFI_DRIVER
43*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
44*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*
45*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * This file implements a Common Flash Interface (CFI) driver for U-Boot.
46*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * The width of the port and the width of the chips are determined at initialization.
47*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * These widths are used to calculate the address for access CFI data structures.
48*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
49*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * References
50*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * JEDEC Standard JESD68 - Common Flash Interface (CFI)
51*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
52*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
53*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
54*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * AMD CFI Specification, Release 2.0 December 1, 2001
55*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * AMD/Spansion Application Note: Migration from Single-byte to Three-byte
56*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *   Device IDs, Publication Number 25538 Revision A, November 8, 2001
57*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
58*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
59*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * reading and writing ... (yes there is such a Hardware).
60*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
61*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
62*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_BANKS_LIST
63*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE }
64*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
65*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
66*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CFI			0x98
67*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_READ_ID		0x90
68*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_RESET			0xff
69*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_BLOCK_ERASE		0x20
70*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_ERASE_CONFIRM		0xD0
71*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE			0x40
72*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT		0x60
73*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_SET		0x01
74*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_PROTECT_CLEAR		0xD0
75*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_CLEAR_STATUS		0x50
76*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_TO_BUFFER	0xE8
77*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_CMD_WRITE_BUFFER_CONFIRM	0xD0
78*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
79*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DONE		0x80
80*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ESS		0x40
81*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_ECLBS		0x20
82*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSLBS		0x10
83*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_VPENS		0x08
84*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PSS		0x04
85*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_DPS		0x02
86*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_R			0x01
87*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_STATUS_PROTECT		0x01
88*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
89*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_RESET			0xF0
90*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE			0xA0
91*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_START		0x80
92*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_ERASE_SECTOR		0x30
93*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_START		0xAA
94*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_UNLOCK_ACK		0x55
95*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_TO_BUFFER		0x25
96*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_CMD_WRITE_BUFFER_CONFIRM	0x29
97*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
98*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_TOGGLE		0x40
99*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_STATUS_ERROR		0x20
100*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
101*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_ADDR_ERASE_START	((info->portwidth == FLASH_CFI_8BIT) ? 0xAAA : 0x555)
102*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_ADDR_START		((info->portwidth == FLASH_CFI_8BIT) ? 0xAAA : 0x555)
103*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define AMD_ADDR_ACK		((info->portwidth == FLASH_CFI_8BIT) ? 0x555 : 0x2AA)
104*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
105*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_MANUFACTURER_ID	0x00
106*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID		0x01
107*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID2		0x0E
108*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_DEVICE_ID3		0x0F
109*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI		0x55
110*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_ALT		0x555
111*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CFI_RESP		0x10
112*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PRIMARY_VENDOR	0x13
113*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EXT_QUERY_T_P_ADDR	0x15	/* extended query table primary addr */
114*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WTOUT		0x1F
115*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBTOUT		0x20
116*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ETOUT		0x21
117*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CETOUT		0x22
118*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WMAX_TOUT		0x23
119*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_WBMAX_TOUT		0x24
120*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_EMAX_TOUT		0x25
121*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_CEMAX_TOUT		0x26
122*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_SIZE		0x27
123*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTERFACE		0x28
124*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_BUFFER_SIZE	0x2A
125*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_NUM_ERASE_REGIONS	0x2C
126*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_ERASE_REGIONS	0x2D
127*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_PROTECT		0x02
128*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_USER_PROTECTION	0x85
129*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define FLASH_OFFSET_INTEL_PROTECTION	0x81
130*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
131*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_NONE			0
132*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_EXTENDED	1
133*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_STANDARD		2
134*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_INTEL_STANDARD	3
135*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_AMD_EXTENDED		4
136*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_STANDARD	256
137*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_MITSU_EXTENDED	257
138*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFI_CMDSET_SST			258
139*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
140*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
141*59829cc1SJean-Christophe PLAGNIOL-VILLARD # undef  FLASH_CMD_RESET
142*59829cc1SJean-Christophe PLAGNIOL-VILLARD # define FLASH_CMD_RESET	AMD_CMD_RESET /* use AMD-Reset instead */
143*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
144*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
145*59829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union {
146*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned char c;
147*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned short w;
148*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long l;
149*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long long ll;
150*59829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiword_t;
151*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
152*59829cc1SJean-Christophe PLAGNIOL-VILLARD typedef union {
153*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	volatile unsigned char *cp;
154*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	volatile unsigned short *wp;
155*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	volatile unsigned long *lp;
156*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	volatile unsigned long long *llp;
157*59829cc1SJean-Christophe PLAGNIOL-VILLARD } cfiptr_t;
158*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
159*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define NUM_ERASE_REGIONS	4 /* max. number of erase regions */
160*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
161*59829cc1SJean-Christophe PLAGNIOL-VILLARD static uint flash_offset_cfi[2]={FLASH_OFFSET_CFI,FLASH_OFFSET_CFI_ALT};
162*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
163*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* use CFG_MAX_FLASH_BANKS_DETECT if defined */
164*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_MAX_FLASH_BANKS_DETECT
165*59829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS_DETECT] = CFG_FLASH_BANKS_LIST;
166*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS_DETECT];	/* FLASH chips info */
167*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else
168*59829cc1SJean-Christophe PLAGNIOL-VILLARD static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST;
169*59829cc1SJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CFG_MAX_FLASH_BANKS];		/* FLASH chips info */
170*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
171*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
172*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*
173*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Check if chip width is defined. If not, start detecting with 8bit.
174*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
175*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_CFI_WIDTH
176*59829cc1SJean-Christophe PLAGNIOL-VILLARD #define CFG_FLASH_CFI_WIDTH	FLASH_CFI_8BIT
177*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
178*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
179*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
180*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
181*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Functions
182*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
183*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
184*59829cc1SJean-Christophe PLAGNIOL-VILLARD typedef unsigned long flash_sect_t;
185*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
186*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c);
187*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf);
188*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
189*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect);
190*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
191*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
192*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
193*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_read_jedec_ids (flash_info_t * info);
194*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_detect_cfi (flash_info_t * info);
195*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfiword (flash_info_t * info, ulong dest, cfiword_t cword);
196*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
197*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				    ulong tout, char *prompt);
198*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum);
199*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
200*59829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_info_t *flash_get_info(ulong base);
201*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
202*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
203*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, int len);
204*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
205*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
206*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
207*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * create an address based on the offset and the port width
208*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
209*59829cc1SJean-Christophe PLAGNIOL-VILLARD inline uchar *flash_make_addr (flash_info_t * info, flash_sect_t sect, uint offset)
210*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
211*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return ((uchar *) (info->start[sect] + (offset * info->portwidth)));
212*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
213*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
214*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
215*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
216*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Debug support
217*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
218*59829cc1SJean-Christophe PLAGNIOL-VILLARD void print_longlong (char *str, unsigned long long data)
219*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
220*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
221*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	char *cp;
222*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
223*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cp = (unsigned char *) &data;
224*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 8; i++)
225*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		sprintf (&str[i * 2], "%2.2x", *cp++);
226*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
227*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_printqry (flash_info_t * info, flash_sect_t sect)
228*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
229*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiptr_t cptr;
230*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x, y;
231*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
232*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (x = 0; x < 0x40; x += 16U / info->portwidth) {
233*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cptr.cp =
234*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_make_addr (info, sect,
235*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					 x + FLASH_OFFSET_CFI_RESP);
236*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("%p : ", cptr.cp);
237*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (y = 0; y < 16; y++) {
238*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("%2.2x ", cptr.cp[y]);
239*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
240*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug (" ");
241*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (y = 0; y < 16; y++) {
242*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (cptr.cp[y] >= 0x20 && cptr.cp[y] <= 0x7e) {
243*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug ("%c", cptr.cp[y]);
244*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			} else {
245*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug (".");
246*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
247*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
248*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("\n");
249*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
250*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
251*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
252*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
253*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
254*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
255*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a character at a port width address
256*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
257*59829cc1SJean-Christophe PLAGNIOL-VILLARD inline uchar flash_read_uchar (flash_info_t * info, uint offset)
258*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
259*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *cp;
260*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
261*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cp = flash_make_addr (info, 0, offset);
262*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
263*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (cp[0]);
264*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else
265*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (cp[info->portwidth - 1]);
266*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
267*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
268*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
269*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
270*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a short word by swapping for ppc format.
271*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
272*59829cc1SJean-Christophe PLAGNIOL-VILLARD ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect, uint offset)
273*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
274*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *addr;
275*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	ushort retval;
276*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
277*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
278*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x;
279*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
280*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	addr = flash_make_addr (info, sect, offset);
281*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
282*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
283*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("ushort addr is at %p info->portwidth = %d\n", addr,
284*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	       info->portwidth);
285*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (x = 0; x < 2 * info->portwidth; x++) {
286*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("addr[%x] = 0x%x\n", x, addr[x]);
287*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
288*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
289*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
290*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	retval = ((addr[(info->portwidth)] << 8) | addr[0]);
291*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else
292*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	retval = ((addr[(2 * info->portwidth) - 1] << 8) |
293*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		  addr[info->portwidth - 1]);
294*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
295*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
296*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("retval = 0x%x\n", retval);
297*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
298*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
299*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
300*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
301*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * read a long word by picking the least significant byte of each maximum
302*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * port size word. Swap for ppc format.
303*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
304*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_read_long (flash_info_t * info, flash_sect_t sect, uint offset)
305*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
306*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *addr;
307*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong retval;
308*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
309*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
310*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int x;
311*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
312*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	addr = flash_make_addr (info, sect, offset);
313*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
314*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
315*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("long addr is at %p info->portwidth = %d\n", addr,
316*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	       info->portwidth);
317*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (x = 0; x < 4 * info->portwidth; x++) {
318*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("addr[%x] = 0x%x\n", x, addr[x]);
319*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
320*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
321*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
322*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	retval = (addr[0] << 16) | (addr[(info->portwidth)] << 24) |
323*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		(addr[(2 * info->portwidth)]) | (addr[(3 * info->portwidth)] << 8);
324*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else
325*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	retval = (addr[(2 * info->portwidth) - 1] << 24) |
326*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		(addr[(info->portwidth) - 1] << 16) |
327*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		(addr[(4 * info->portwidth) - 1] << 8) |
328*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		addr[(3 * info->portwidth) - 1];
329*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
330*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
331*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
332*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
333*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
334*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
335*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
336*59829cc1SJean-Christophe PLAGNIOL-VILLARD unsigned long flash_init (void)
337*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
338*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long size = 0;
339*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
340*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
341*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
342*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	char *s = getenv("unlock");
343*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
344*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
345*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* Init: no FLASHes known */
346*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
347*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_info[i].flash_id = FLASH_UNKNOWN;
348*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		size += flash_info[i].size = flash_get_size (bank_base[i], i);
349*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
350*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifndef CFG_FLASH_QUIET_TEST
351*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
352*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				i+1, flash_info[i].size, flash_info[i].size << 20);
353*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_QUIET_TEST */
354*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
355*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
356*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
357*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			/*
358*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			 * Only the U-Boot image and it's environment is protected,
359*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			 * all other sectors are unprotected (unlocked) if flash
360*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			 * hardware protection is used (CFG_FLASH_PROTECTION) and
361*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			 * the environment variable "unlock" is set to "yes".
362*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			 */
363*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_info[i].legacy_unlock) {
364*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				int k;
365*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
366*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
367*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 * Disable legacy_unlock temporarily, since
368*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 * flash_real_protect would relock all other sectors
369*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 * again otherwise.
370*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
371*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_info[i].legacy_unlock = 0;
372*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
373*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
374*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 * Legacy unlocking (e.g. Intel J3) -> unlock only one
375*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 * sector. This will unlock all sectors.
376*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
377*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_real_protect (&flash_info[i], 0, 0);
378*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
379*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_info[i].legacy_unlock = 1;
380*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
381*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
382*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 * Manually mark other sectors as unlocked (unprotected)
383*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
384*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				for (k = 1; k < flash_info[i].sector_count; k++)
385*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					flash_info[i].protect[k] = 0;
386*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			} else {
387*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
388*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 * No legancy unlocking -> unlock all sectors
389*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
390*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_protect (FLAG_PROTECT_CLEAR,
391*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					       flash_info[i].start[0],
392*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					       flash_info[i].start[0] + flash_info[i].size - 1,
393*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					       &flash_info[i]);
394*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
395*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
396*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */
397*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
398*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
399*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* Monitor protection ON by default */
400*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
401*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_protect (FLAG_PROTECT_SET,
402*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       CFG_MONITOR_BASE,
403*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       CFG_MONITOR_BASE + monitor_flash_len  - 1,
404*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CFG_MONITOR_BASE));
405*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
406*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
407*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* Environment protection ON by default */
408*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_ENV_IS_IN_FLASH
409*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_protect (FLAG_PROTECT_SET,
410*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       CFG_ENV_ADDR,
411*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
412*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CFG_ENV_ADDR));
413*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
414*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
415*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* Redundant environment protection ON by default */
416*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_ENV_ADDR_REDUND
417*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_protect (FLAG_PROTECT_SET,
418*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       CFG_ENV_ADDR_REDUND,
419*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
420*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       flash_get_info(CFG_ENV_ADDR_REDUND));
421*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
422*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (size);
423*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
424*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
425*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
426*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
427*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
428*59829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_info_t *flash_get_info(ulong base)
429*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
430*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
431*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_info_t * info = 0;
432*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
433*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) {
434*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info = & flash_info[i];
435*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->size && info->start[0] <= base &&
436*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		    base <= info->start[0] + info->size - 1)
437*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
438*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
439*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
440*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return i == CFG_MAX_FLASH_BANKS ? 0 : info;
441*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
442*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
443*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
444*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
445*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
446*59829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_erase (flash_info_t * info, int s_first, int s_last)
447*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
448*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int rcode = 0;
449*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int prot;
450*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect;
451*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
452*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
453*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("Can't erase unknown flash type - aborted\n");
454*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
455*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
456*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((s_first < 0) || (s_first > s_last)) {
457*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("- no sectors to erase\n");
458*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 1;
459*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
460*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
461*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	prot = 0;
462*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; ++sect) {
463*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect]) {
464*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			prot++;
465*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
466*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
467*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot) {
468*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("- Warning: %d protected sectors will not be erased!\n", prot);
469*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	} else {
470*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		putc ('\n');
471*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
472*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
473*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
474*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sect = s_first; sect <= s_last; sect++) {
475*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->protect[sect] == 0) { /* not protected */
476*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			switch (info->vendor) {
477*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_STANDARD:
478*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_INTEL_EXTENDED:
479*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS);
480*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE);
481*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_write_cmd (info, sect, 0, FLASH_CMD_ERASE_CONFIRM);
482*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
483*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_STANDARD:
484*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			case CFI_CMDSET_AMD_EXTENDED:
485*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
486*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_write_cmd (info, sect, AMD_ADDR_ERASE_START,
487*59829cc1SJean-Christophe PLAGNIOL-VILLARD 							AMD_CMD_ERASE_START);
488*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_unlock_seq (info, sect);
489*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR);
490*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
491*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			default:
492*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				debug ("Unkown flash vendor %d\n",
493*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				       info->vendor);
494*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
495*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
496*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
497*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_full_status_check
498*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			    (info, sect, info->erase_blk_tout, "erase")) {
499*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				rcode = 1;
500*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			} else
501*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				putc ('.');
502*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
503*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
504*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts (" done\n");
505*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return rcode;
506*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
507*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
508*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
509*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
510*59829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_print_info (flash_info_t * info)
511*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
512*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
513*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
514*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->flash_id != FLASH_MAN_CFI) {
515*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		puts ("missing or unknown FLASH type\n");
516*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		return;
517*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
518*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
519*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("CFI conformant FLASH (%d x %d)",
520*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		(info->portwidth << 3), (info->chipwidth << 3));
521*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("  Size: %ld MB in %d Sectors\n",
522*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->size >> 20, info->sector_count);
523*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("  ");
524*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
525*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
526*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Standard");
527*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
528*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
529*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Intel Extended");
530*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
531*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
532*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Standard");
533*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
534*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
535*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("AMD Extended");
536*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
537*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		default:
538*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Unknown (%d)", info->vendor);
539*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
540*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
541*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
542*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->manufacturer_id, info->device_id);
543*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->device_id == 0x7E) {
544*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf("%04X", info->device_id2);
545*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
546*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	printf ("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
547*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->erase_blk_tout,
548*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->write_tout);
549*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (info->buffer_size > 1) {
550*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  Buffer write timeout: %ld ms, buffer size: %d bytes\n",
551*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_write_tout,
552*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_size);
553*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
554*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
555*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	puts ("\n  Sector Start Addresses:");
556*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < info->sector_count; ++i) {
557*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((i % 5) == 0)
558*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("\n");
559*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_EMPTY_INFO
560*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		int k;
561*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		int size;
562*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		int erased;
563*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		volatile unsigned long *flash;
564*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
565*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
566*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * Check if whole sector is erased
567*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
568*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (i != (info->sector_count - 1))
569*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			size = info->start[i + 1] - info->start[i];
570*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		else
571*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			size = info->start[0] + info->size - info->start[i];
572*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		erased = 1;
573*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash = (volatile unsigned long *) info->start[i];
574*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		size = size >> 2;	/* divide by 4 for longword access */
575*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (k = 0; k < size; k++) {
576*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (*flash++ != 0xffffffff) {
577*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				erased = 0;
578*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
579*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
580*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
581*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
582*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* print empty and read-only info */
583*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX %c %s ",
584*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
585*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			erased ? 'E' : ' ',
586*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
587*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else	/* ! CFG_FLASH_EMPTY_INFO */
588*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		printf ("  %08lX   %s ",
589*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->start[i],
590*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->protect[i] ? "RO" : "  ");
591*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
592*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
593*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	putc ('\n');
594*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return;
595*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
596*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
597*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
598*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Copy memory to flash, returns:
599*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * 0 - OK
600*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * 1 - write timeout
601*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * 2 - Flash not erased
602*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
603*59829cc1SJean-Christophe PLAGNIOL-VILLARD int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
604*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
605*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong wp;
606*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong cp;
607*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int aln;
608*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
609*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, rc;
610*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
611*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
612*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int buffered_size;
613*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
614*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* get lower aligned address */
615*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* get lower aligned address */
616*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	wp = (addr & ~(info->portwidth - 1));
617*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
618*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle unaligned start */
619*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((aln = addr - wp) != 0) {
620*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
621*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cp = wp;
622*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < aln; ++i, ++cp)
623*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, (*(uchar *) cp));
624*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
625*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (; (i < info->portwidth) && (cnt > 0); i++) {
626*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
627*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt--;
628*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			cp++;
629*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
630*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp)
631*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, (*(uchar *) cp));
632*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
633*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
634*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp = cp;
635*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
636*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
637*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* handle the aligned part */
638*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
639*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size = (info->portwidth / info->chipwidth);
640*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	buffered_size *= info->buffer_size;
641*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
642*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* prohibit buffer write when buffer_size is 1 */
643*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->buffer_size == 1) {
644*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			cword.l = 0;
645*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->portwidth; i++)
646*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_add_byte (info, &cword, *src++);
647*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
648*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				return rc;
649*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			wp += info->portwidth;
650*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt -= info->portwidth;
651*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			continue;
652*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
653*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
654*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* write buffer until next buffered_size aligned boundary */
655*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		i = buffered_size - (wp % buffered_size);
656*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (i > cnt)
657*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			i = cnt;
658*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
659*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
660*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		i -= i & (info->portwidth - 1);
661*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += i;
662*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		src += i;
663*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= i;
664*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
665*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else
666*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (cnt >= info->portwidth) {
667*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword.l = 0;
668*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < info->portwidth; i++) {
669*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_add_byte (info, &cword, *src++);
670*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
671*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
672*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			return rc;
673*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		wp += info->portwidth;
674*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cnt -= info->portwidth;
675*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
676*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */
677*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (cnt == 0) {
678*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		return (0);
679*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
680*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
681*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/*
682*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	 * handle unaligned tail bytes
683*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	 */
684*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cword.l = 0;
685*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) {
686*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_add_byte (info, &cword, *src++);
687*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		--cnt;
688*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
689*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (; i < info->portwidth; ++i, ++cp) {
690*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_add_byte (info, &cword, (*(uchar *) cp));
691*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
692*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
693*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return flash_write_cfiword (info, wp, cword);
694*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
695*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
696*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
697*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
698*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
699*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
700*59829cc1SJean-Christophe PLAGNIOL-VILLARD int flash_real_protect (flash_info_t * info, long sector, int prot)
701*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
702*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retcode = 0;
703*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
704*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
705*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
706*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (prot)
707*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
708*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	else
709*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
710*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
711*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if ((retcode =
712*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	     flash_full_status_check (info, sector, info->erase_blk_tout,
713*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				      prot ? "protect" : "unprotect")) == 0) {
714*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
715*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->protect[sector] = prot;
716*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
717*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		/*
718*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * On some of Intel's flash chips (marked via legacy_unlock)
719*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		 * unprotect unprotects all locking.
720*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		 */
721*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((prot == 0) && (info->legacy_unlock)) {
722*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_sect_t i;
723*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
724*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (i = 0; i < info->sector_count; i++) {
725*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				if (info->protect[i])
726*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					flash_real_protect (info, i, 1);
727*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
728*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
729*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
730*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retcode;
731*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
732*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
733*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
734*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_user_serial - read the OneTimeProgramming cells
735*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
736*59829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
737*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			     int len)
738*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
739*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
740*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *dst;
741*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
742*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	dst = buffer;
743*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	src = flash_make_addr (info, 0, FLASH_OFFSET_USER_PROTECTION);
744*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
745*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (dst, src + offset, len);
746*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
747*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
748*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
749*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*
750*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_read_factory_serial - read the device Id from the protection area
751*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
752*59829cc1SJean-Christophe PLAGNIOL-VILLARD void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
753*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				int len)
754*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
755*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *src;
756*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
757*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	src = flash_make_addr (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
758*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
759*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	memcpy (buffer, src + offset, len);
760*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
761*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
762*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
763*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_PROTECTION */
764*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
765*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*
766*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * flash_is_busy - check to see if the flash is busy
767*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * This routine checks the status of the chip and returns true if the chip is busy
768*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
769*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
770*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
771*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retval;
772*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
773*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
774*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_STANDARD:
775*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_EXTENDED:
776*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
777*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
778*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_AMD_STANDARD:
779*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_AMD_EXTENDED:
780*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
781*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
782*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
783*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = 0;
784*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
785*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("flash_is_busy: %d\n", retval);
786*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
787*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
788*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
789*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
790*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *  wait for XSR.7 to be set. Time out with an error if it does not.
791*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *  This routine does not set the flash to read-array mode.
792*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
793*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_status_check (flash_info_t * info, flash_sect_t sector,
794*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			       ulong tout, char *prompt)
795*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
796*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	ulong start;
797*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
798*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if CFG_HZ != 1000
799*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	tout *= CFG_HZ/1000;
800*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
801*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
802*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* Wait for command completion */
803*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	start = get_timer (0);
804*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	while (flash_is_busy (info, sector)) {
805*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (get_timer (start) > tout) {
806*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Flash %s timeout at address %lx data %lx\n",
807*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				prompt, info->start[sector],
808*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_read_long (info, sector, 0));
809*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_write_cmd (info, sector, 0, info->cmd_reset);
810*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			return ERR_TIMOUT;
811*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
812*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		udelay (1);		/* also triggers watchdog */
813*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
814*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return ERR_OK;
815*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
816*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
817*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
818*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check.
819*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * This routine sets the flash to read-array mode.
820*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
821*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
822*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				    ulong tout, char *prompt)
823*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
824*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retcode;
825*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
826*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	retcode = flash_status_check (info, sector, tout, prompt);
827*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
828*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_EXTENDED:
829*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_STANDARD:
830*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((retcode == ERR_OK)
831*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
832*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			retcode = ERR_INVAL;
833*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			printf ("Flash %s error at address %lx\n", prompt,
834*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				info->start[sector]);
835*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) {
836*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				puts ("Command Sequence Error.\n");
837*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			} else if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS)) {
838*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				puts ("Block Erase Error.\n");
839*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				retcode = ERR_NOT_ERASED;
840*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			} else if (flash_isset (info, sector, 0, FLASH_STATUS_PSLBS)) {
841*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				puts ("Locking Error\n");
842*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
843*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
844*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				puts ("Block locked.\n");
845*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				retcode = ERR_PROTECTED;
846*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
847*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
848*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				puts ("Vpp Low Error.\n");
849*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
850*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, info->cmd_reset);
851*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
852*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
853*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
854*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
855*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retcode;
856*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
857*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
858*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
859*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
860*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
861*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
862*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
863*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned short	w;
864*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned int	l;
865*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long long ll;
866*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
867*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
868*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->portwidth) {
869*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_8BIT:
870*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword->c = c;
871*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
872*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_16BIT:
873*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
874*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		w = c;
875*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		w <<= 8;
876*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword->w = (cword->w >> 8) | w;
877*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else
878*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword->w = (cword->w << 8) | c;
879*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
880*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
881*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_32BIT:
882*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
883*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		l = c;
884*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		l <<= 24;
885*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword->l = (cword->l >> 8) | l;
886*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else
887*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword->l = (cword->l << 8) | c;
888*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
889*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
890*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_64BIT:
891*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
892*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		ll = c;
893*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		ll <<= 56;
894*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword->ll = (cword->ll >> 8) | ll;
895*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else
896*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cword->ll = (cword->ll << 8) | c;
897*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
898*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
899*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
900*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
901*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
902*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
903*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
904*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * make a proper sized command based on the port and chip widths
905*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
906*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
907*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
908*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i;
909*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar *cp = (uchar *) cmdbuf;
910*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
911*59829cc1SJean-Christophe PLAGNIOL-VILLARD #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
912*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = info->portwidth; i > 0; i--)
913*59829cc1SJean-Christophe PLAGNIOL-VILLARD #else
914*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (i = 1; i <= info->portwidth; i++)
915*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
916*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		*cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;
917*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
918*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
919*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*
920*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Write a proper sized command to the correct address
921*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
922*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
923*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
924*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
925*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	volatile cfiptr_t addr;
926*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
927*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
928*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	addr.cp = flash_make_addr (info, sect, offset);
929*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_make_cmd (info, cmd, &cword);
930*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->portwidth) {
931*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_8BIT:
932*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr.cp, cmd,
933*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
934*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		*addr.cp = cword.c;
935*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
936*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_16BIT:
937*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr.wp,
938*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       cmd, cword.w,
939*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
940*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		*addr.wp = cword.w;
941*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
942*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_32BIT:
943*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr.lp,
944*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       cmd, cword.l,
945*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
946*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		*addr.lp = cword.l;
947*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
948*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_64BIT:
949*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
950*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		{
951*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			char str[20];
952*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
953*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			print_longlong (str, cword.ll);
954*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
955*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
956*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			       addr.llp, cmd, str,
957*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
958*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
959*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
960*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		*addr.llp = cword.ll;
961*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
962*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
963*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
964*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* Ensure all the instructions are fully finished */
965*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	sync();
966*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
967*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
968*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
969*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
970*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sect, AMD_ADDR_START, AMD_CMD_UNLOCK_START);
971*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, sect, AMD_ADDR_ACK, AMD_CMD_UNLOCK_ACK);
972*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
973*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
974*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
975*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
976*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
977*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
978*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiptr_t cptr;
979*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
980*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retval;
981*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
982*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cptr.cp = flash_make_addr (info, sect, offset);
983*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_make_cmd (info, cmd, &cword);
984*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
985*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, cptr.cp);
986*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->portwidth) {
987*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_8BIT:
988*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("is= %x %x\n", cptr.cp[0], cword.c);
989*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = (cptr.cp[0] == cword.c);
990*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
991*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_16BIT:
992*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("is= %4.4x %4.4x\n", cptr.wp[0], cword.w);
993*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = (cptr.wp[0] == cword.w);
994*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
995*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_32BIT:
996*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("is= %8.8lx %8.8lx\n", cptr.lp[0], cword.l);
997*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = (cptr.lp[0] == cword.l);
998*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
999*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_64BIT:
1000*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
1001*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		{
1002*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			char str1[20];
1003*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			char str2[20];
1004*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1005*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			print_longlong (str1, cptr.llp[0]);
1006*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			print_longlong (str2, cword.ll);
1007*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("is= %s %s\n", str1, str2);
1008*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1009*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
1010*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = (cptr.llp[0] == cword.ll);
1011*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1012*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
1013*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = 0;
1014*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1015*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1016*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
1017*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
1018*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1019*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
1020*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1021*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
1022*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
1023*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiptr_t cptr;
1024*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
1025*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retval;
1026*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1027*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cptr.cp = flash_make_addr (info, sect, offset);
1028*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_make_cmd (info, cmd, &cword);
1029*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->portwidth) {
1030*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_8BIT:
1031*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = ((cptr.cp[0] & cword.c) == cword.c);
1032*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1033*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_16BIT:
1034*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = ((cptr.wp[0] & cword.w) == cword.w);
1035*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1036*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_32BIT:
1037*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = ((cptr.lp[0] & cword.l) == cword.l);
1038*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1039*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_64BIT:
1040*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = ((cptr.llp[0] & cword.ll) == cword.ll);
1041*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1042*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
1043*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = 0;
1044*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1045*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1046*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
1047*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
1048*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1049*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
1050*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1051*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
1052*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
1053*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiptr_t cptr;
1054*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiword_t cword;
1055*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retval;
1056*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1057*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cptr.cp = flash_make_addr (info, sect, offset);
1058*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_make_cmd (info, cmd, &cword);
1059*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->portwidth) {
1060*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_8BIT:
1061*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c));
1062*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1063*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_16BIT:
1064*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w));
1065*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1066*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_32BIT:
1067*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l));
1068*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1069*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_64BIT:
1070*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = ((cptr.llp[0] & cword.ll) !=
1071*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			  (cptr.llp[0] & cword.ll));
1072*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1073*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
1074*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retval = 0;
1075*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1076*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1077*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return retval;
1078*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
1079*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1080*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
1081*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * read jedec ids from device and set corresponding fields in info struct
1082*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
1083*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1084*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
1085*59829cc1SJean-Christophe PLAGNIOL-VILLARD */
1086*59829cc1SJean-Christophe PLAGNIOL-VILLARD static void flash_read_jedec_ids (flash_info_t * info)
1087*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
1088*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->manufacturer_id = 0;
1089*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id       = 0;
1090*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->device_id2      = 0;
1091*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1092*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
1093*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_STANDARD:
1094*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_EXTENDED:
1095*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1096*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1097*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		udelay(1000); /* some flash are slow to respond */
1098*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->manufacturer_id = flash_read_uchar (info,
1099*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_MANUFACTURER_ID);
1100*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id = flash_read_uchar (info,
1101*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID);
1102*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1103*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1104*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_AMD_STANDARD:
1105*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_AMD_EXTENDED:
1106*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1107*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_unlock_seq(info, 0);
1108*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd(info, 0, AMD_ADDR_START, FLASH_CMD_READ_ID);
1109*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		udelay(1000); /* some flash are slow to respond */
1110*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->manufacturer_id = flash_read_uchar (info,
1111*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_MANUFACTURER_ID);
1112*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->device_id = flash_read_uchar (info,
1113*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID);
1114*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->device_id == 0x7E) {
1115*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* AMD 3-byte (expanded) device ids */
1116*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 = flash_read_uchar (info,
1117*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID2);
1118*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 <<= 8;
1119*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->device_id2 |= flash_read_uchar (info,
1120*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						FLASH_OFFSET_DEVICE_ID3);
1121*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1122*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1123*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1124*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
1125*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1126*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1127*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
1128*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1129*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
1130*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * detect if flash is compatible with the Common Flash Interface (CFI)
1131*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * http://www.jedec.org/download/search/jesd68.pdf
1132*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
1133*59829cc1SJean-Christophe PLAGNIOL-VILLARD */
1134*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_detect_cfi (flash_info_t * info)
1135*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
1136*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int cfi_offset;
1137*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("flash detect cfi\n");
1138*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1139*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (info->portwidth = CFG_FLASH_CFI_WIDTH;
1140*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	     info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1141*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (info->chipwidth = FLASH_CFI_BY8;
1142*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		     info->chipwidth <= info->portwidth;
1143*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		     info->chipwidth <<= 1) {
1144*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_write_cmd (info, 0, 0, info->cmd_reset);
1145*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (cfi_offset=0; cfi_offset < sizeof(flash_offset_cfi)/sizeof(uint); cfi_offset++) {
1146*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], FLASH_CMD_CFI);
1147*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1148*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1149*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
1150*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->interface = flash_read_ushort (info, 0, FLASH_OFFSET_INTERFACE);
1151*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->cfi_offset=flash_offset_cfi[cfi_offset];
1152*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					debug ("device interface is %d\n",
1153*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->interface);
1154*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					debug ("found port %d chip %d ",
1155*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->portwidth, info->chipwidth);
1156*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					debug ("port %d bits chip %d bits\n",
1157*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1158*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1159*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					return 1;
1160*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
1161*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1162*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1163*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1164*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	debug ("not found\n");
1165*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return 0;
1166*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
1167*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1168*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*
1169*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * The following code cannot be run from FLASH!
1170*59829cc1SJean-Christophe PLAGNIOL-VILLARD  *
1171*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1172*59829cc1SJean-Christophe PLAGNIOL-VILLARD ulong flash_get_size (ulong base, int banknum)
1173*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
1174*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_info_t *info = &flash_info[banknum];
1175*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int i, j;
1176*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sect_cnt;
1177*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long sector;
1178*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	unsigned long tmp;
1179*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int size_ratio;
1180*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	uchar num_erase_regions;
1181*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_size;
1182*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int erase_region_count;
1183*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int geometry_reversed = 0;
1184*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1185*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->ext_addr = 0;
1186*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->cfi_version = 0;
1187*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
1188*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->legacy_unlock = 0;
1189*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
1190*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1191*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	info->start[0] = base;
1192*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1193*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (flash_detect_cfi (info)) {
1194*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->vendor = flash_read_ushort (info, 0,
1195*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_PRIMARY_VENDOR);
1196*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_read_jedec_ids (info);
1197*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, 0, info->cfi_offset, FLASH_CMD_CFI);
1198*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		num_erase_regions = flash_read_uchar (info,
1199*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_NUM_ERASE_REGIONS);
1200*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->ext_addr = flash_read_ushort (info, 0,
1201*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					FLASH_OFFSET_EXT_QUERY_T_P_ADDR);
1202*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (info->ext_addr) {
1203*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version = (ushort) flash_read_uchar (info,
1204*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 3) << 8;
1205*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cfi_version |= (ushort) flash_read_uchar (info,
1206*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 4);
1207*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1208*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
1209*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_printqry (info, 0);
1210*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
1211*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		switch (info->vendor) {
1212*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_STANDARD:
1213*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_INTEL_EXTENDED:
1214*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		default:
1215*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cmd_reset = FLASH_CMD_RESET;
1216*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_PROTECTION
1217*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* read legacy lock/unlock bit from intel flash */
1218*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (info->ext_addr) {
1219*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				info->legacy_unlock = flash_read_uchar (info,
1220*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						info->ext_addr + 5) & 0x08;
1221*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1222*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif
1223*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
1224*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_STANDARD:
1225*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case CFI_CMDSET_AMD_EXTENDED:
1226*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->cmd_reset = AMD_CMD_RESET;
1227*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* check if flash geometry needs reversal */
1228*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (num_erase_regions <= 1)
1229*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
1230*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* reverse geometry if top boot part */
1231*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (info->cfi_version < 0x3131) {
1232*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				/* CFI < 1.1, try to guess from device id */
1233*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				if ((info->device_id & 0x80) != 0) {
1234*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					geometry_reversed = 1;
1235*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
1236*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
1237*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1238*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* CFI >= 1.1, deduct from top/bottom flag */
1239*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* note: ext_addr is valid since cfi_version > 0 */
1240*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1241*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				geometry_reversed = 1;
1242*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1243*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
1244*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1245*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1246*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer is %d\n", info->vendor);
1247*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
1248*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id is 0x%x\n", info->device_id);
1249*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("device id2 is 0x%x\n", info->device_id2);
1250*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("cfi version is 0x%04x\n", info->cfi_version);
1251*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1252*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		size_ratio = info->portwidth / info->chipwidth;
1253*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* if the chip is x8/x16 reduce the ratio by half */
1254*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((info->interface == FLASH_CFI_X8X16)
1255*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		    && (info->chipwidth == FLASH_CFI_BY8)) {
1256*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			size_ratio >>= 1;
1257*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1258*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("size_ratio %d port %d bits chip %d bits\n",
1259*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1260*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1261*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("found %d erase regions\n", num_erase_regions);
1262*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		sect_cnt = 0;
1263*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		sector = base;
1264*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < num_erase_regions; i++) {
1265*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (i > NUM_ERASE_REGIONS) {
1266*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				printf ("%d erase regions found, only %d used\n",
1267*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					num_erase_regions, NUM_ERASE_REGIONS);
1268*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
1269*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1270*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			if (geometry_reversed)
1271*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				tmp = flash_read_long (info, 0,
1272*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					       FLASH_OFFSET_ERASE_REGIONS +
1273*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					       (num_erase_regions - 1 - i) * 4);
1274*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			else
1275*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				tmp = flash_read_long (info, 0,
1276*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					       FLASH_OFFSET_ERASE_REGIONS +
1277*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					       i * 4);
1278*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			erase_region_size =
1279*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
1280*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			tmp >>= 16;
1281*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			erase_region_count = (tmp & 0xffff) + 1;
1282*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			debug ("erase_region_count = %d erase_region_size = %d\n",
1283*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				erase_region_count, erase_region_size);
1284*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			for (j = 0; j < erase_region_count; j++) {
1285*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				info->start[sect_cnt] = sector;
1286*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				sector += (erase_region_size * size_ratio);
1287*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1288*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				/*
1289*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 * Only read protection status from supported devices (intel...)
1290*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				 */
1291*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				switch (info->vendor) {
1292*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_EXTENDED:
1293*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				case CFI_CMDSET_INTEL_STANDARD:
1294*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->protect[sect_cnt] =
1295*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						flash_isset (info, sect_cnt,
1296*59829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_OFFSET_PROTECT,
1297*59829cc1SJean-Christophe PLAGNIOL-VILLARD 							     FLASH_STATUS_PROTECT);
1298*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
1299*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				default:
1300*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->protect[sect_cnt] = 0; /* default: not protected */
1301*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
1302*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1303*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				sect_cnt++;
1304*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1305*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1306*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1307*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->sector_count = sect_cnt;
1308*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		/* multiply the size by the number of chips */
1309*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->size = (1 << flash_read_uchar (info, FLASH_OFFSET_SIZE)) * size_ratio;
1310*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_size = (1 << flash_read_ushort (info, 0, FLASH_OFFSET_BUFFER_SIZE));
1311*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT);
1312*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->erase_blk_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_EMAX_TOUT)));
1313*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT)) *
1314*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			(1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT));
1315*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->buffer_write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */
1316*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT)) *
1317*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		      (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT));
1318*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */
1319*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		info->flash_id = FLASH_MAN_CFI;
1320*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) {
1321*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			info->portwidth >>= 1;	/* XXX - Need to test on x8/x16 in parallel. */
1322*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1323*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1324*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1325*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_write_cmd (info, 0, 0, info->cmd_reset);
1326*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return (info->size);
1327*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
1328*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1329*59829cc1SJean-Christophe PLAGNIOL-VILLARD /* loop through the sectors from the highest address
1330*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * when the passed address is greater or equal to the sector address
1331*59829cc1SJean-Christophe PLAGNIOL-VILLARD  * we have a match
1332*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1333*59829cc1SJean-Christophe PLAGNIOL-VILLARD static flash_sect_t find_sector (flash_info_t * info, ulong addr)
1334*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
1335*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sector;
1336*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1337*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	for (sector = info->sector_count - 1; sector >= 0; sector--) {
1338*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if (addr >= info->start[sector])
1339*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
1340*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1341*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return sector;
1342*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
1343*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1344*59829cc1SJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
1345*59829cc1SJean-Christophe PLAGNIOL-VILLARD  */
1346*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfiword (flash_info_t * info, ulong dest,
1347*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				cfiword_t cword)
1348*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
1349*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiptr_t ctladdr;
1350*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cfiptr_t cptr;
1351*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int flag;
1352*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1353*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	ctladdr.cp = flash_make_addr (info, 0, 0);
1354*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	cptr.cp = (uchar *) dest;
1355*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1356*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* Check if Flash is (sufficiently) erased */
1357*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->portwidth) {
1358*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_8BIT:
1359*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flag = ((cptr.cp[0] & cword.c) == cword.c);
1360*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1361*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_16BIT:
1362*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flag = ((cptr.wp[0] & cword.w) == cword.w);
1363*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1364*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_32BIT:
1365*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flag = ((cptr.lp[0] & cword.l) == cword.l);
1366*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1367*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_64BIT:
1368*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flag = ((cptr.llp[0] & cword.ll) == cword.ll);
1369*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1370*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
1371*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 2;
1372*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1373*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (!flag)
1374*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		return 2;
1375*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1376*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* Disable interrupts which might cause a timeout here */
1377*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flag = disable_interrupts ();
1378*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1379*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
1380*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_EXTENDED:
1381*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_STANDARD:
1382*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
1383*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
1384*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1385*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_AMD_EXTENDED:
1386*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_AMD_STANDARD:
1387*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_unlock_seq (info, 0);
1388*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, 0, AMD_ADDR_START, AMD_CMD_WRITE);
1389*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1390*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1391*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1392*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->portwidth) {
1393*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_8BIT:
1394*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cptr.cp[0] = cword.c;
1395*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1396*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_16BIT:
1397*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cptr.wp[0] = cword.w;
1398*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1399*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_32BIT:
1400*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cptr.lp[0] = cword.l;
1401*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1402*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case FLASH_CFI_64BIT:
1403*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		cptr.llp[0] = cword.ll;
1404*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		break;
1405*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1406*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1407*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	/* re-enable interrupts if necessary */
1408*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	if (flag)
1409*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		enable_interrupts ();
1410*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1411*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	return flash_full_status_check (info, find_sector (info, dest),
1412*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					info->write_tout, "write");
1413*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
1414*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1415*59829cc1SJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_FLASH_USE_BUFFER_WRITE
1416*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1417*59829cc1SJean-Christophe PLAGNIOL-VILLARD static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
1418*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				  int len)
1419*59829cc1SJean-Christophe PLAGNIOL-VILLARD {
1420*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	flash_sect_t sector;
1421*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int cnt;
1422*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	int retcode;
1423*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	volatile cfiptr_t src;
1424*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	volatile cfiptr_t dst;
1425*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1426*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	switch (info->vendor) {
1427*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_STANDARD:
1428*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_INTEL_EXTENDED:
1429*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		src.cp = cp;
1430*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		dst.cp = (uchar *) dest;
1431*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		sector = find_sector (info, dest);
1432*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1433*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
1434*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		if ((retcode = flash_status_check (info, sector, info->buffer_write_tout,
1435*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						   "write to buffer")) == ERR_OK) {
1436*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			/* reduce the number of loops by the width of the port	*/
1437*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			switch (info->portwidth) {
1438*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			case FLASH_CFI_8BIT:
1439*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				cnt = len;
1440*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
1441*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			case FLASH_CFI_16BIT:
1442*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				cnt = len >> 1;
1443*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
1444*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			case FLASH_CFI_32BIT:
1445*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				cnt = len >> 2;
1446*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
1447*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			case FLASH_CFI_64BIT:
1448*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				cnt = len >> 3;
1449*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
1450*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			default:
1451*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				return ERR_INVAL;
1452*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				break;
1453*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1454*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
1455*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			while (cnt-- > 0) {
1456*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				switch (info->portwidth) {
1457*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				case FLASH_CFI_8BIT:
1458*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					*dst.cp++ = *src.cp++;
1459*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
1460*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				case FLASH_CFI_16BIT:
1461*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					*dst.wp++ = *src.wp++;
1462*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
1463*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				case FLASH_CFI_32BIT:
1464*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					*dst.lp++ = *src.lp++;
1465*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
1466*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				case FLASH_CFI_64BIT:
1467*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					*dst.llp++ = *src.llp++;
1468*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
1469*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				default:
1470*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					return ERR_INVAL;
1471*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					break;
1472*59829cc1SJean-Christophe PLAGNIOL-VILLARD 				}
1473*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			}
1474*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_write_cmd (info, sector, 0,
1475*59829cc1SJean-Christophe PLAGNIOL-VILLARD 					 FLASH_CMD_WRITE_BUFFER_CONFIRM);
1476*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			retcode = flash_full_status_check (info, sector,
1477*59829cc1SJean-Christophe PLAGNIOL-VILLARD 							   info->buffer_write_tout,
1478*59829cc1SJean-Christophe PLAGNIOL-VILLARD 							   "buffer write");
1479*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1480*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		return retcode;
1481*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1482*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_AMD_STANDARD:
1483*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	case CFI_CMDSET_AMD_EXTENDED:
1484*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		src.cp = cp;
1485*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		dst.cp = (uchar *) dest;
1486*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		sector = find_sector (info, dest);
1487*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1488*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_unlock_seq(info,0);
1489*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER);
1490*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1491*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		switch (info->portwidth) {
1492*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case FLASH_CFI_8BIT:
1493*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt = len;
1494*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
1495*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			while (cnt-- > 0) *dst.cp++ = *src.cp++;
1496*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
1497*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case FLASH_CFI_16BIT:
1498*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt = len >> 1;
1499*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
1500*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			while (cnt-- > 0) *dst.wp++ = *src.wp++;
1501*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
1502*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case FLASH_CFI_32BIT:
1503*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt = len >> 2;
1504*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
1505*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			while (cnt-- > 0) *dst.lp++ = *src.lp++;
1506*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
1507*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		case FLASH_CFI_64BIT:
1508*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			cnt = len >> 3;
1509*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
1510*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			while (cnt-- > 0) *dst.llp++ = *src.llp++;
1511*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			break;
1512*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		default:
1513*59829cc1SJean-Christophe PLAGNIOL-VILLARD 			return ERR_INVAL;
1514*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		}
1515*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1516*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1517*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		retcode = flash_full_status_check (info, sector, info->buffer_write_tout,
1518*59829cc1SJean-Christophe PLAGNIOL-VILLARD 						   "buffer write");
1519*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		return retcode;
1520*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1521*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	default:
1522*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		debug ("Unknown Command Set\n");
1523*59829cc1SJean-Christophe PLAGNIOL-VILLARD 		return ERR_INVAL;
1524*59829cc1SJean-Christophe PLAGNIOL-VILLARD 	}
1525*59829cc1SJean-Christophe PLAGNIOL-VILLARD }
1526*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_USE_BUFFER_WRITE */
1527*59829cc1SJean-Christophe PLAGNIOL-VILLARD 
1528*59829cc1SJean-Christophe PLAGNIOL-VILLARD #endif /* CFG_FLASH_CFI */
1529