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