blob: 4340b1b5c7b56c120a45eda19ba1051c80a1da30 [file] [log] [blame]
wdenk2cefd152004-02-08 22:55:38 +00001/*
wdenke65527f2004-02-12 00:47:09 +00002 * (C) Copyright 2002-2004
wdenk2cefd152004-02-08 22:55:38 +00003 * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com
4 *
5 * Copyright (C) 2003 Arabella Software Ltd.
6 * Yuli Barcohen <yuli@arabellasw.com>
wdenk2cefd152004-02-08 22:55:38 +00007 *
wdenke65527f2004-02-12 00:47:09 +00008 * Copyright (C) 2004
9 * Ed Okerson
Stefan Roese12797482006-11-13 13:55:24 +010010 *
11 * Copyright (C) 2006
12 * Tolunay Orkun <listmember@orkun.us>
wdenke65527f2004-02-12 00:47:09 +000013 *
wdenk2cefd152004-02-08 22:55:38 +000014 * See file CREDITS for list of people who contributed to this
15 * project.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30 * MA 02111-1307 USA
31 *
wdenk2cefd152004-02-08 22:55:38 +000032 */
33
34/* The DEBUG define must be before common to enable debugging */
wdenk2ebee312004-02-23 19:30:57 +000035/* #define DEBUG */
36
wdenk2cefd152004-02-08 22:55:38 +000037#include <common.h>
38#include <asm/processor.h>
Haiying Wangc123a382007-02-21 16:52:31 +010039#include <asm/io.h>
wdenkaeba06f2004-06-09 17:34:58 +000040#include <asm/byteorder.h>
wdenkd0245fc2005-04-13 10:02:42 +000041#include <environment.h>
wdenke65527f2004-02-12 00:47:09 +000042#ifdef CFG_FLASH_CFI_DRIVER
wdenke537b3b2004-02-23 23:54:43 +000043
wdenk2cefd152004-02-08 22:55:38 +000044/*
Haavard Skinnemoend523e392007-12-13 12:56:28 +010045 * This file implements a Common Flash Interface (CFI) driver for
46 * U-Boot.
47 *
48 * The width of the port and the width of the chips are determined at
49 * initialization. These widths are used to calculate the address for
50 * access CFI data structures.
wdenk2cefd152004-02-08 22:55:38 +000051 *
52 * References
53 * JEDEC Standard JESD68 - Common Flash Interface (CFI)
54 * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
55 * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
56 * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
Stefan Roese12797482006-11-13 13:55:24 +010057 * AMD CFI Specification, Release 2.0 December 1, 2001
58 * AMD/Spansion Application Note: Migration from Single-byte to Three-byte
59 * Device IDs, Publication Number 25538 Revision A, November 8, 2001
wdenk2cefd152004-02-08 22:55:38 +000060 *
Haavard Skinnemoend523e392007-12-13 12:56:28 +010061 * Define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
Heiko Schocher800db312007-01-19 18:05:26 +010062 * reading and writing ... (yes there is such a Hardware).
wdenk2cefd152004-02-08 22:55:38 +000063 */
64
wdenke65527f2004-02-12 00:47:09 +000065#ifndef CFG_FLASH_BANKS_LIST
66#define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE }
67#endif
68
wdenk2cefd152004-02-08 22:55:38 +000069#define FLASH_CMD_CFI 0x98
70#define FLASH_CMD_READ_ID 0x90
71#define FLASH_CMD_RESET 0xff
72#define FLASH_CMD_BLOCK_ERASE 0x20
73#define FLASH_CMD_ERASE_CONFIRM 0xD0
74#define FLASH_CMD_WRITE 0x40
75#define FLASH_CMD_PROTECT 0x60
76#define FLASH_CMD_PROTECT_SET 0x01
77#define FLASH_CMD_PROTECT_CLEAR 0xD0
78#define FLASH_CMD_CLEAR_STATUS 0x50
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +040079#define FLASH_CMD_READ_STATUS 0x70
wdenke65527f2004-02-12 00:47:09 +000080#define FLASH_CMD_WRITE_TO_BUFFER 0xE8
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +040081#define FLASH_CMD_WRITE_BUFFER_PROG 0xE9
wdenke65527f2004-02-12 00:47:09 +000082#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0
wdenk2cefd152004-02-08 22:55:38 +000083
84#define FLASH_STATUS_DONE 0x80
85#define FLASH_STATUS_ESS 0x40
86#define FLASH_STATUS_ECLBS 0x20
87#define FLASH_STATUS_PSLBS 0x10
88#define FLASH_STATUS_VPENS 0x08
89#define FLASH_STATUS_PSS 0x04
90#define FLASH_STATUS_DPS 0x02
91#define FLASH_STATUS_R 0x01
92#define FLASH_STATUS_PROTECT 0x01
93
94#define AMD_CMD_RESET 0xF0
95#define AMD_CMD_WRITE 0xA0
96#define AMD_CMD_ERASE_START 0x80
97#define AMD_CMD_ERASE_SECTOR 0x30
wdenked2ac4b2004-03-14 18:23:55 +000098#define AMD_CMD_UNLOCK_START 0xAA
99#define AMD_CMD_UNLOCK_ACK 0x55
Stefan Roesec865e6c2006-02-28 15:29:58 +0100100#define AMD_CMD_WRITE_TO_BUFFER 0x25
101#define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29
wdenk2cefd152004-02-08 22:55:38 +0000102
103#define AMD_STATUS_TOGGLE 0x40
104#define AMD_STATUS_ERROR 0x20
Stefan Roesec865e6c2006-02-28 15:29:58 +0100105
Stefan Roese12797482006-11-13 13:55:24 +0100106#define FLASH_OFFSET_MANUFACTURER_ID 0x00
107#define FLASH_OFFSET_DEVICE_ID 0x01
108#define FLASH_OFFSET_DEVICE_ID2 0x0E
109#define FLASH_OFFSET_DEVICE_ID3 0x0F
wdenk2cefd152004-02-08 22:55:38 +0000110#define FLASH_OFFSET_CFI 0x55
Wolfgang Denkafa0dd02006-12-27 01:26:13 +0100111#define FLASH_OFFSET_CFI_ALT 0x555
wdenk2cefd152004-02-08 22:55:38 +0000112#define FLASH_OFFSET_CFI_RESP 0x10
wdenke65527f2004-02-12 00:47:09 +0000113#define FLASH_OFFSET_PRIMARY_VENDOR 0x13
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100114/* extended query table primary address */
115#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15
wdenk2cefd152004-02-08 22:55:38 +0000116#define FLASH_OFFSET_WTOUT 0x1F
wdenke65527f2004-02-12 00:47:09 +0000117#define FLASH_OFFSET_WBTOUT 0x20
wdenk2cefd152004-02-08 22:55:38 +0000118#define FLASH_OFFSET_ETOUT 0x21
wdenke65527f2004-02-12 00:47:09 +0000119#define FLASH_OFFSET_CETOUT 0x22
wdenk2cefd152004-02-08 22:55:38 +0000120#define FLASH_OFFSET_WMAX_TOUT 0x23
wdenke65527f2004-02-12 00:47:09 +0000121#define FLASH_OFFSET_WBMAX_TOUT 0x24
wdenk2cefd152004-02-08 22:55:38 +0000122#define FLASH_OFFSET_EMAX_TOUT 0x25
wdenke65527f2004-02-12 00:47:09 +0000123#define FLASH_OFFSET_CEMAX_TOUT 0x26
wdenk2cefd152004-02-08 22:55:38 +0000124#define FLASH_OFFSET_SIZE 0x27
wdenke65527f2004-02-12 00:47:09 +0000125#define FLASH_OFFSET_INTERFACE 0x28
126#define FLASH_OFFSET_BUFFER_SIZE 0x2A
wdenk2cefd152004-02-08 22:55:38 +0000127#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C
128#define FLASH_OFFSET_ERASE_REGIONS 0x2D
129#define FLASH_OFFSET_PROTECT 0x02
wdenke65527f2004-02-12 00:47:09 +0000130#define FLASH_OFFSET_USER_PROTECTION 0x85
131#define FLASH_OFFSET_INTEL_PROTECTION 0x81
wdenk2cefd152004-02-08 22:55:38 +0000132
Stefan Roese12797482006-11-13 13:55:24 +0100133#define CFI_CMDSET_NONE 0
134#define CFI_CMDSET_INTEL_EXTENDED 1
135#define CFI_CMDSET_AMD_STANDARD 2
136#define CFI_CMDSET_INTEL_STANDARD 3
137#define CFI_CMDSET_AMD_EXTENDED 4
138#define CFI_CMDSET_MITSU_STANDARD 256
139#define CFI_CMDSET_MITSU_EXTENDED 257
140#define CFI_CMDSET_SST 258
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400141#define CFI_CMDSET_INTEL_PROG_REGIONS 512
wdenk2cefd152004-02-08 22:55:38 +0000142
wdenk51242782004-12-18 22:35:43 +0000143#ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
144# undef FLASH_CMD_RESET
Stefan Roese12797482006-11-13 13:55:24 +0100145# define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */
wdenk51242782004-12-18 22:35:43 +0000146#endif
147
wdenk2cefd152004-02-08 22:55:38 +0000148typedef union {
149 unsigned char c;
150 unsigned short w;
151 unsigned long l;
152 unsigned long long ll;
153} cfiword_t;
154
Stefan Roese12797482006-11-13 13:55:24 +0100155#define NUM_ERASE_REGIONS 4 /* max. number of erase regions */
wdenk2cefd152004-02-08 22:55:38 +0000156
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100157static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
Wolfgang Denkafa0dd02006-12-27 01:26:13 +0100158
Marian Balakowicz513b4a12005-10-11 19:09:42 +0200159/* use CFG_MAX_FLASH_BANKS_DETECT if defined */
160#ifdef CFG_MAX_FLASH_BANKS_DETECT
161static ulong bank_base[CFG_MAX_FLASH_BANKS_DETECT] = CFG_FLASH_BANKS_LIST;
162flash_info_t flash_info[CFG_MAX_FLASH_BANKS_DETECT]; /* FLASH chips info */
163#else
wdenk2cefd152004-02-08 22:55:38 +0000164static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST;
Marian Balakowicz513b4a12005-10-11 19:09:42 +0200165flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */
166#endif
wdenk2cefd152004-02-08 22:55:38 +0000167
Stefan Roesec865e6c2006-02-28 15:29:58 +0100168/*
169 * Check if chip width is defined. If not, start detecting with 8bit.
170 */
171#ifndef CFG_FLASH_CFI_WIDTH
172#define CFG_FLASH_CFI_WIDTH FLASH_CFI_8BIT
173#endif
174
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200175typedef unsigned long flash_sect_t;
wdenk2cefd152004-02-08 22:55:38 +0000176
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100177/* CFI standard query structure */
178struct cfi_qry {
179 u8 qry[3];
180 u16 p_id;
181 u16 p_adr;
182 u16 a_id;
183 u16 a_adr;
184 u8 vcc_min;
185 u8 vcc_max;
186 u8 vpp_min;
187 u8 vpp_max;
188 u8 word_write_timeout_typ;
189 u8 buf_write_timeout_typ;
190 u8 block_erase_timeout_typ;
191 u8 chip_erase_timeout_typ;
192 u8 word_write_timeout_max;
193 u8 buf_write_timeout_max;
194 u8 block_erase_timeout_max;
195 u8 chip_erase_timeout_max;
196 u8 dev_size;
197 u16 interface_desc;
198 u16 max_buf_write_size;
199 u8 num_erase_regions;
200 u32 erase_region_info[NUM_ERASE_REGIONS];
201} __attribute__((packed));
202
203struct cfi_pri_hdr {
204 u8 pri[3];
205 u8 major_version;
206 u8 minor_version;
207} __attribute__((packed));
208
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100209static void flash_write8(u8 value, void *addr)
210{
211 __raw_writeb(value, addr);
212}
213
214static void flash_write16(u16 value, void *addr)
215{
216 __raw_writew(value, addr);
217}
218
219static void flash_write32(u32 value, void *addr)
220{
221 __raw_writel(value, addr);
222}
223
224static void flash_write64(u64 value, void *addr)
225{
226 /* No architectures currently implement __raw_writeq() */
227 *(volatile u64 *)addr = value;
228}
229
230static u8 flash_read8(void *addr)
231{
232 return __raw_readb(addr);
233}
234
235static u16 flash_read16(void *addr)
236{
237 return __raw_readw(addr);
238}
239
240static u32 flash_read32(void *addr)
241{
242 return __raw_readl(addr);
243}
244
Daniel Hellstromcfd71382008-03-28 20:40:19 +0100245static u64 __flash_read64(void *addr)
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100246{
247 /* No architectures currently implement __raw_readq() */
248 return *(volatile u64 *)addr;
249}
250
Daniel Hellstromcfd71382008-03-28 20:40:19 +0100251u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
252
wdenk2cefd152004-02-08 22:55:38 +0000253/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000254 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200255#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
256static flash_info_t *flash_get_info(ulong base)
257{
258 int i;
259 flash_info_t * info = 0;
wdenk2cefd152004-02-08 22:55:38 +0000260
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200261 for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
262 info = & flash_info[i];
263 if (info->size && info->start[0] <= base &&
264 base <= info->start[0] + info->size - 1)
265 break;
266 }
wdenk2cefd152004-02-08 22:55:38 +0000267
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200268 return i == CFG_MAX_FLASH_BANKS ? 0 : info;
269}
wdenk2cefd152004-02-08 22:55:38 +0000270#endif
271
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100272unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
273{
274 if (sect != (info->sector_count - 1))
275 return info->start[sect + 1] - info->start[sect];
276 else
277 return info->start[0] + info->size - info->start[sect];
278}
279
wdenke65527f2004-02-12 00:47:09 +0000280/*-----------------------------------------------------------------------
281 * create an address based on the offset and the port width
282 */
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100283static inline void *
284flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
wdenke65527f2004-02-12 00:47:09 +0000285{
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100286 unsigned int byte_offset = offset * info->portwidth;
287
288 return map_physmem(info->start[sect] + byte_offset,
289 flash_sector_size(info, sect) - byte_offset,
290 MAP_NOCACHE);
291}
292
293static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
294 unsigned int offset, void *addr)
295{
296 unsigned int byte_offset = offset * info->portwidth;
297
298 unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset);
wdenke65527f2004-02-12 00:47:09 +0000299}
300
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200301/*-----------------------------------------------------------------------
302 * make a proper sized command based on the port and chip widths
303 */
Sebastian Siewior7746ed82008-07-15 13:35:23 +0200304static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200305{
306 int i;
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400307 int cword_offset;
308 int cp_offset;
309 uchar val;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200310 uchar *cp = (uchar *) cmdbuf;
311
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400312 for (i = info->portwidth; i > 0; i--){
313 cword_offset = (info->portwidth-i)%info->chipwidth;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200314#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400315 cp_offset = info->portwidth - i;
316 val = *((uchar*)&cmd + cword_offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200317#else
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400318 cp_offset = i - 1;
Sebastian Siewior7746ed82008-07-15 13:35:23 +0200319 val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200320#endif
Sebastian Siewior7746ed82008-07-15 13:35:23 +0200321 cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400322 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200323}
324
wdenk2cefd152004-02-08 22:55:38 +0000325#ifdef DEBUG
wdenke65527f2004-02-12 00:47:09 +0000326/*-----------------------------------------------------------------------
327 * Debug support
328 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100329static void print_longlong (char *str, unsigned long long data)
wdenk2cefd152004-02-08 22:55:38 +0000330{
331 int i;
332 char *cp;
wdenke65527f2004-02-12 00:47:09 +0000333
334 cp = (unsigned char *) &data;
335 for (i = 0; i < 8; i++)
336 sprintf (&str[i * 2], "%2.2x", *cp++);
wdenk2cefd152004-02-08 22:55:38 +0000337}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200338
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100339static void flash_printqry (struct cfi_qry *qry)
wdenke65527f2004-02-12 00:47:09 +0000340{
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100341 u8 *p = (u8 *)qry;
wdenke65527f2004-02-12 00:47:09 +0000342 int x, y;
343
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100344 for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
345 debug("%02x : ", x);
346 for (y = 0; y < 16; y++)
347 debug("%2.2x ", p[x + y]);
348 debug(" ");
wdenke65527f2004-02-12 00:47:09 +0000349 for (y = 0; y < 16; y++) {
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100350 unsigned char c = p[x + y];
351 if (c >= 0x20 && c <= 0x7e)
352 debug("%c", c);
353 else
354 debug(".");
wdenke65527f2004-02-12 00:47:09 +0000355 }
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100356 debug("\n");
wdenke65527f2004-02-12 00:47:09 +0000357 }
358}
wdenk2cefd152004-02-08 22:55:38 +0000359#endif
360
361
362/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000363 * read a character at a port width address
364 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100365static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000366{
367 uchar *cp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100368 uchar retval;
wdenke65527f2004-02-12 00:47:09 +0000369
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100370 cp = flash_map (info, 0, offset);
Heiko Schocher800db312007-01-19 18:05:26 +0100371#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100372 retval = flash_read8(cp);
wdenke65527f2004-02-12 00:47:09 +0000373#else
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100374 retval = flash_read8(cp + info->portwidth - 1);
wdenke65527f2004-02-12 00:47:09 +0000375#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100376 flash_unmap (info, 0, offset, cp);
377 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000378}
379
380/*-----------------------------------------------------------------------
Tor Krill7f2a3052008-03-28 11:29:10 +0100381 * read a word at a port width address, assume 16bit bus
382 */
383static inline ushort flash_read_word (flash_info_t * info, uint offset)
384{
385 ushort *addr, retval;
386
387 addr = flash_map (info, 0, offset);
388 retval = flash_read16 (addr);
389 flash_unmap (info, 0, offset, addr);
390 return retval;
391}
392
393
394/*-----------------------------------------------------------------------
Stefan Roese12797482006-11-13 13:55:24 +0100395 * read a long word by picking the least significant byte of each maximum
wdenk2cefd152004-02-08 22:55:38 +0000396 * port size word. Swap for ppc format.
397 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100398static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
399 uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000400{
wdenke65527f2004-02-12 00:47:09 +0000401 uchar *addr;
402 ulong retval;
403
404#ifdef DEBUG
405 int x;
406#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100407 addr = flash_map (info, sect, offset);
wdenk2cefd152004-02-08 22:55:38 +0000408
wdenke65527f2004-02-12 00:47:09 +0000409#ifdef DEBUG
410 debug ("long addr is at %p info->portwidth = %d\n", addr,
411 info->portwidth);
412 for (x = 0; x < 4 * info->portwidth; x++) {
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100413 debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
wdenke65527f2004-02-12 00:47:09 +0000414 }
415#endif
Heiko Schocher800db312007-01-19 18:05:26 +0100416#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100417 retval = ((flash_read8(addr) << 16) |
418 (flash_read8(addr + info->portwidth) << 24) |
419 (flash_read8(addr + 2 * info->portwidth)) |
420 (flash_read8(addr + 3 * info->portwidth) << 8));
wdenke65527f2004-02-12 00:47:09 +0000421#else
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100422 retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
423 (flash_read8(addr + info->portwidth - 1) << 16) |
424 (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
425 (flash_read8(addr + 3 * info->portwidth - 1)));
wdenke65527f2004-02-12 00:47:09 +0000426#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100427 flash_unmap(info, sect, offset, addr);
428
wdenke65527f2004-02-12 00:47:09 +0000429 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000430}
431
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200432/*
433 * Write a proper sized command to the correct address
Michael Schwingen73d044d2007-12-07 23:35:02 +0100434 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200435static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
Sebastian Siewior7746ed82008-07-15 13:35:23 +0200436 uint offset, u32 cmd)
Michael Schwingen73d044d2007-12-07 23:35:02 +0100437{
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100438
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100439 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200440 cfiword_t cword;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100441
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100442 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200443 flash_make_cmd (info, cmd, &cword);
444 switch (info->portwidth) {
445 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100446 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200447 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100448 flash_write8(cword.c, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200449 break;
450 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100451 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200452 cmd, cword.w,
453 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100454 flash_write16(cword.w, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200455 break;
456 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100457 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200458 cmd, cword.l,
459 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100460 flash_write32(cword.l, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200461 break;
462 case FLASH_CFI_64BIT:
463#ifdef DEBUG
464 {
465 char str[20];
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100466
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200467 print_longlong (str, cword.ll);
468
469 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100470 addr, cmd, str,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200471 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100472 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200473#endif
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100474 flash_write64(cword.ll, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200475 break;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100476 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200477
478 /* Ensure all the instructions are fully finished */
479 sync();
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100480
481 flash_unmap(info, sect, offset, addr);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100482}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200483
484static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
Michael Schwingen73d044d2007-12-07 23:35:02 +0100485{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200486 flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
487 flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100488}
Michael Schwingen73d044d2007-12-07 23:35:02 +0100489
490/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000491 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200492static int flash_isequal (flash_info_t * info, flash_sect_t sect,
493 uint offset, uchar cmd)
wdenk2cefd152004-02-08 22:55:38 +0000494{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100495 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200496 cfiword_t cword;
497 int retval;
wdenk2cefd152004-02-08 22:55:38 +0000498
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100499 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200500 flash_make_cmd (info, cmd, &cword);
Stefan Roeseefef95b2006-04-01 13:41:03 +0200501
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100502 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200503 switch (info->portwidth) {
504 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100505 debug ("is= %x %x\n", flash_read8(addr), cword.c);
506 retval = (flash_read8(addr) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200507 break;
508 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100509 debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
510 retval = (flash_read16(addr) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200511 break;
512 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100513 debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
514 retval = (flash_read32(addr) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200515 break;
516 case FLASH_CFI_64BIT:
517#ifdef DEBUG
518 {
519 char str1[20];
520 char str2[20];
Michael Schwingen73d044d2007-12-07 23:35:02 +0100521
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100522 print_longlong (str1, flash_read64(addr));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200523 print_longlong (str2, cword.ll);
524 debug ("is= %s %s\n", str1, str2);
wdenk2cefd152004-02-08 22:55:38 +0000525 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200526#endif
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100527 retval = (flash_read64(addr) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200528 break;
529 default:
530 retval = 0;
531 break;
532 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100533 flash_unmap(info, sect, offset, addr);
534
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200535 return retval;
536}
Stefan Roeseefef95b2006-04-01 13:41:03 +0200537
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200538/*-----------------------------------------------------------------------
539 */
540static int flash_isset (flash_info_t * info, flash_sect_t sect,
541 uint offset, uchar cmd)
542{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100543 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200544 cfiword_t cword;
545 int retval;
Stefan Roeseefef95b2006-04-01 13:41:03 +0200546
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100547 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200548 flash_make_cmd (info, cmd, &cword);
549 switch (info->portwidth) {
550 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100551 retval = ((flash_read8(addr) & cword.c) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200552 break;
553 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100554 retval = ((flash_read16(addr) & cword.w) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200555 break;
556 case FLASH_CFI_32BIT:
Stefan Roesed4e37c02008-01-02 14:05:37 +0100557 retval = ((flash_read32(addr) & cword.l) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200558 break;
559 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100560 retval = ((flash_read64(addr) & cword.ll) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200561 break;
562 default:
563 retval = 0;
564 break;
565 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100566 flash_unmap(info, sect, offset, addr);
567
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200568 return retval;
569}
Stefan Roeseefef95b2006-04-01 13:41:03 +0200570
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200571/*-----------------------------------------------------------------------
572 */
573static int flash_toggle (flash_info_t * info, flash_sect_t sect,
574 uint offset, uchar cmd)
575{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100576 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200577 cfiword_t cword;
578 int retval;
wdenke85b7a52004-10-10 22:16:06 +0000579
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100580 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200581 flash_make_cmd (info, cmd, &cword);
582 switch (info->portwidth) {
583 case FLASH_CFI_8BIT:
Stefan Roesecff2b492008-06-16 10:40:02 +0200584 retval = flash_read8(addr) != flash_read8(addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200585 break;
586 case FLASH_CFI_16BIT:
Stefan Roesecff2b492008-06-16 10:40:02 +0200587 retval = flash_read16(addr) != flash_read16(addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200588 break;
589 case FLASH_CFI_32BIT:
Stefan Roesecff2b492008-06-16 10:40:02 +0200590 retval = flash_read32(addr) != flash_read32(addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200591 break;
592 case FLASH_CFI_64BIT:
Stefan Roesecff2b492008-06-16 10:40:02 +0200593 retval = flash_read64(addr) != flash_read64(addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200594 break;
595 default:
596 retval = 0;
597 break;
598 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100599 flash_unmap(info, sect, offset, addr);
600
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200601 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000602}
603
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200604/*
605 * flash_is_busy - check to see if the flash is busy
606 *
607 * This routine checks the status of the chip and returns true if the
608 * chip is busy.
wdenk2cefd152004-02-08 22:55:38 +0000609 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200610static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
wdenk5c71a7a2005-05-16 15:23:22 +0000611{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200612 int retval;
wdenk5c71a7a2005-05-16 15:23:22 +0000613
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200614 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400615 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200616 case CFI_CMDSET_INTEL_STANDARD:
617 case CFI_CMDSET_INTEL_EXTENDED:
618 retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
619 break;
620 case CFI_CMDSET_AMD_STANDARD:
621 case CFI_CMDSET_AMD_EXTENDED:
622#ifdef CONFIG_FLASH_CFI_LEGACY
623 case CFI_CMDSET_AMD_LEGACY:
624#endif
625 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
626 break;
627 default:
628 retval = 0;
wdenk5c71a7a2005-05-16 15:23:22 +0000629 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200630 debug ("flash_is_busy: %d\n", retval);
631 return retval;
wdenk5c71a7a2005-05-16 15:23:22 +0000632}
633
634/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200635 * wait for XSR.7 to be set. Time out with an error if it does not.
636 * This routine does not set the flash to read-array mode.
wdenk5c71a7a2005-05-16 15:23:22 +0000637 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200638static int flash_status_check (flash_info_t * info, flash_sect_t sector,
639 ulong tout, char *prompt)
wdenk2cefd152004-02-08 22:55:38 +0000640{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200641 ulong start;
wdenk2cefd152004-02-08 22:55:38 +0000642
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200643#if CFG_HZ != 1000
644 tout *= CFG_HZ/1000;
645#endif
wdenk2cefd152004-02-08 22:55:38 +0000646
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200647 /* Wait for command completion */
648 start = get_timer (0);
649 while (flash_is_busy (info, sector)) {
650 if (get_timer (start) > tout) {
651 printf ("Flash %s timeout at address %lx data %lx\n",
652 prompt, info->start[sector],
653 flash_read_long (info, sector, 0));
654 flash_write_cmd (info, sector, 0, info->cmd_reset);
655 return ERR_TIMOUT;
wdenk2cefd152004-02-08 22:55:38 +0000656 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200657 udelay (1); /* also triggers watchdog */
wdenk2cefd152004-02-08 22:55:38 +0000658 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200659 return ERR_OK;
660}
wdenk2cefd152004-02-08 22:55:38 +0000661
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200662/*-----------------------------------------------------------------------
663 * Wait for XSR.7 to be set, if it times out print an error, otherwise
664 * do a full status check.
665 *
666 * This routine sets the flash to read-array mode.
667 */
668static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
669 ulong tout, char *prompt)
670{
671 int retcode;
wdenk2cefd152004-02-08 22:55:38 +0000672
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200673 retcode = flash_status_check (info, sector, tout, prompt);
674 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400675 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200676 case CFI_CMDSET_INTEL_EXTENDED:
677 case CFI_CMDSET_INTEL_STANDARD:
678 if ((retcode == ERR_OK)
679 && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
680 retcode = ERR_INVAL;
681 printf ("Flash %s error at address %lx\n", prompt,
682 info->start[sector]);
683 if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
684 FLASH_STATUS_PSLBS)) {
685 puts ("Command Sequence Error.\n");
686 } else if (flash_isset (info, sector, 0,
687 FLASH_STATUS_ECLBS)) {
688 puts ("Block Erase Error.\n");
689 retcode = ERR_NOT_ERASED;
690 } else if (flash_isset (info, sector, 0,
691 FLASH_STATUS_PSLBS)) {
692 puts ("Locking Error\n");
wdenk2cefd152004-02-08 22:55:38 +0000693 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200694 if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
695 puts ("Block locked.\n");
696 retcode = ERR_PROTECTED;
697 }
698 if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
699 puts ("Vpp Low Error.\n");
wdenk2cefd152004-02-08 22:55:38 +0000700 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200701 flash_write_cmd (info, sector, 0, info->cmd_reset);
702 break;
703 default:
704 break;
wdenk2cefd152004-02-08 22:55:38 +0000705 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200706 return retcode;
wdenk2cefd152004-02-08 22:55:38 +0000707}
708
709/*-----------------------------------------------------------------------
710 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200711static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
wdenk2cefd152004-02-08 22:55:38 +0000712{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200713#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
714 unsigned short w;
715 unsigned int l;
716 unsigned long long ll;
717#endif
wdenk2cefd152004-02-08 22:55:38 +0000718
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200719 switch (info->portwidth) {
720 case FLASH_CFI_8BIT:
721 cword->c = c;
722 break;
723 case FLASH_CFI_16BIT:
724#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
725 w = c;
726 w <<= 8;
727 cword->w = (cword->w >> 8) | w;
728#else
729 cword->w = (cword->w << 8) | c;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100730#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200731 break;
732 case FLASH_CFI_32BIT:
733#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
734 l = c;
735 l <<= 24;
736 cword->l = (cword->l >> 8) | l;
737#else
738 cword->l = (cword->l << 8) | c;
739#endif
740 break;
741 case FLASH_CFI_64BIT:
742#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
743 ll = c;
744 ll <<= 56;
745 cword->ll = (cword->ll >> 8) | ll;
746#else
747 cword->ll = (cword->ll << 8) | c;
748#endif
749 break;
Stefan Roese12797482006-11-13 13:55:24 +0100750 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200751}
wdenk2cefd152004-02-08 22:55:38 +0000752
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200753/* loop through the sectors from the highest address when the passed
754 * address is greater or equal to the sector address we have a match
755 */
756static flash_sect_t find_sector (flash_info_t * info, ulong addr)
757{
758 flash_sect_t sector;
wdenk2cefd152004-02-08 22:55:38 +0000759
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200760 for (sector = info->sector_count - 1; sector >= 0; sector--) {
761 if (addr >= info->start[sector])
762 break;
wdenk2cefd152004-02-08 22:55:38 +0000763 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200764 return sector;
wdenk2cefd152004-02-08 22:55:38 +0000765}
766
767/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000768 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200769static int flash_write_cfiword (flash_info_t * info, ulong dest,
770 cfiword_t cword)
wdenk2cefd152004-02-08 22:55:38 +0000771{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100772 void *dstaddr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200773 int flag;
wdenk2cefd152004-02-08 22:55:38 +0000774
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100775 dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
wdenk2cefd152004-02-08 22:55:38 +0000776
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200777 /* Check if Flash is (sufficiently) erased */
778 switch (info->portwidth) {
779 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100780 flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200781 break;
782 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100783 flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200784 break;
785 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100786 flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200787 break;
788 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100789 flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200790 break;
791 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100792 flag = 0;
793 break;
wdenk2cefd152004-02-08 22:55:38 +0000794 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100795 if (!flag) {
796 unmap_physmem(dstaddr, info->portwidth);
Stefan Roese707c1462007-12-27 07:50:54 +0100797 return ERR_NOT_ERASED;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100798 }
wdenk2cefd152004-02-08 22:55:38 +0000799
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200800 /* Disable interrupts which might cause a timeout here */
801 flag = disable_interrupts ();
Stefan Roesec865e6c2006-02-28 15:29:58 +0100802
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200803 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400804 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200805 case CFI_CMDSET_INTEL_EXTENDED:
806 case CFI_CMDSET_INTEL_STANDARD:
807 flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
808 flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
809 break;
810 case CFI_CMDSET_AMD_EXTENDED:
811 case CFI_CMDSET_AMD_STANDARD:
812#ifdef CONFIG_FLASH_CFI_LEGACY
813 case CFI_CMDSET_AMD_LEGACY:
814#endif
815 flash_unlock_seq (info, 0);
816 flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
817 break;
wdenk2cefd152004-02-08 22:55:38 +0000818 }
819
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200820 switch (info->portwidth) {
821 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100822 flash_write8(cword.c, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200823 break;
824 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100825 flash_write16(cword.w, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200826 break;
827 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100828 flash_write32(cword.l, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200829 break;
830 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100831 flash_write64(cword.ll, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200832 break;
wdenk2cefd152004-02-08 22:55:38 +0000833 }
834
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200835 /* re-enable interrupts if necessary */
836 if (flag)
837 enable_interrupts ();
wdenk2cefd152004-02-08 22:55:38 +0000838
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100839 unmap_physmem(dstaddr, info->portwidth);
840
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200841 return flash_full_status_check (info, find_sector (info, dest),
842 info->write_tout, "write");
wdenk2cefd152004-02-08 22:55:38 +0000843}
844
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200845#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenk2cefd152004-02-08 22:55:38 +0000846
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200847static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
848 int len)
wdenk2cefd152004-02-08 22:55:38 +0000849{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200850 flash_sect_t sector;
851 int cnt;
852 int retcode;
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100853 void *src = cp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100854 void *dst = map_physmem(dest, len, MAP_NOCACHE);
Stefan Roese707c1462007-12-27 07:50:54 +0100855 void *dst2 = dst;
856 int flag = 0;
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200857 uint offset = 0;
858 unsigned int shift;
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400859 uchar write_cmd;
Stefan Roese707c1462007-12-27 07:50:54 +0100860
861 switch (info->portwidth) {
862 case FLASH_CFI_8BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200863 shift = 0;
Stefan Roese707c1462007-12-27 07:50:54 +0100864 break;
865 case FLASH_CFI_16BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200866 shift = 1;
Stefan Roese707c1462007-12-27 07:50:54 +0100867 break;
868 case FLASH_CFI_32BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200869 shift = 2;
Stefan Roese707c1462007-12-27 07:50:54 +0100870 break;
871 case FLASH_CFI_64BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200872 shift = 3;
Stefan Roese707c1462007-12-27 07:50:54 +0100873 break;
874 default:
875 retcode = ERR_INVAL;
876 goto out_unmap;
877 }
878
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200879 cnt = len >> shift;
880
Stefan Roese707c1462007-12-27 07:50:54 +0100881 while ((cnt-- > 0) && (flag == 0)) {
882 switch (info->portwidth) {
883 case FLASH_CFI_8BIT:
884 flag = ((flash_read8(dst2) & flash_read8(src)) ==
885 flash_read8(src));
886 src += 1, dst2 += 1;
887 break;
888 case FLASH_CFI_16BIT:
889 flag = ((flash_read16(dst2) & flash_read16(src)) ==
890 flash_read16(src));
891 src += 2, dst2 += 2;
892 break;
893 case FLASH_CFI_32BIT:
894 flag = ((flash_read32(dst2) & flash_read32(src)) ==
895 flash_read32(src));
896 src += 4, dst2 += 4;
897 break;
898 case FLASH_CFI_64BIT:
899 flag = ((flash_read64(dst2) & flash_read64(src)) ==
900 flash_read64(src));
901 src += 8, dst2 += 8;
902 break;
903 }
904 }
905 if (!flag) {
906 retcode = ERR_NOT_ERASED;
907 goto out_unmap;
908 }
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100909
Stefan Roese707c1462007-12-27 07:50:54 +0100910 src = cp;
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100911 sector = find_sector (info, dest);
wdenke65527f2004-02-12 00:47:09 +0000912
913 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400914 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk2cefd152004-02-08 22:55:38 +0000915 case CFI_CMDSET_INTEL_STANDARD:
916 case CFI_CMDSET_INTEL_EXTENDED:
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400917 write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
918 FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200919 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400920 flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS);
921 flash_write_cmd (info, sector, 0, write_cmd);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200922 retcode = flash_status_check (info, sector,
923 info->buffer_write_tout,
924 "write to buffer");
925 if (retcode == ERR_OK) {
926 /* reduce the number of loops by the width of
927 * the port */
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200928 cnt = len >> shift;
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400929 flash_write_cmd (info, sector, 0, cnt - 1);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200930 while (cnt-- > 0) {
931 switch (info->portwidth) {
932 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100933 flash_write8(flash_read8(src), dst);
934 src += 1, dst += 1;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200935 break;
936 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100937 flash_write16(flash_read16(src), dst);
938 src += 2, dst += 2;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200939 break;
940 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100941 flash_write32(flash_read32(src), dst);
942 src += 4, dst += 4;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200943 break;
944 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100945 flash_write64(flash_read64(src), dst);
946 src += 8, dst += 8;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200947 break;
948 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100949 retcode = ERR_INVAL;
950 goto out_unmap;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200951 }
952 }
953 flash_write_cmd (info, sector, 0,
954 FLASH_CMD_WRITE_BUFFER_CONFIRM);
955 retcode = flash_full_status_check (
956 info, sector, info->buffer_write_tout,
957 "buffer write");
958 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100959
960 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200961
wdenk2cefd152004-02-08 22:55:38 +0000962 case CFI_CMDSET_AMD_STANDARD:
963 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200964 flash_unlock_seq(info,0);
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200965
966#ifdef CONFIG_FLASH_SPANSION_S29WS_N
967 offset = ((unsigned long)dst - info->start[sector]) >> shift;
968#endif
969 flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
970 cnt = len >> shift;
971 flash_write_cmd(info, sector, offset, (uchar)cnt - 1);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200972
973 switch (info->portwidth) {
974 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100975 while (cnt-- > 0) {
976 flash_write8(flash_read8(src), dst);
977 src += 1, dst += 1;
978 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200979 break;
980 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100981 while (cnt-- > 0) {
982 flash_write16(flash_read16(src), dst);
983 src += 2, dst += 2;
984 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200985 break;
986 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100987 while (cnt-- > 0) {
988 flash_write32(flash_read32(src), dst);
989 src += 4, dst += 4;
990 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200991 break;
992 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100993 while (cnt-- > 0) {
994 flash_write64(flash_read64(src), dst);
995 src += 8, dst += 8;
996 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200997 break;
998 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100999 retcode = ERR_INVAL;
1000 goto out_unmap;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001001 }
1002
1003 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1004 retcode = flash_full_status_check (info, sector,
1005 info->buffer_write_tout,
1006 "buffer write");
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001007 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001008
wdenk2cefd152004-02-08 22:55:38 +00001009 default:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001010 debug ("Unknown Command Set\n");
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001011 retcode = ERR_INVAL;
1012 break;
wdenk2cefd152004-02-08 22:55:38 +00001013 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001014
1015out_unmap:
1016 unmap_physmem(dst, len);
1017 return retcode;
wdenk2cefd152004-02-08 22:55:38 +00001018}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001019#endif /* CFG_FLASH_USE_BUFFER_WRITE */
1020
wdenke65527f2004-02-12 00:47:09 +00001021
wdenk2cefd152004-02-08 22:55:38 +00001022/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +00001023 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001024int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk2cefd152004-02-08 22:55:38 +00001025{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001026 int rcode = 0;
1027 int prot;
1028 flash_sect_t sect;
wdenk2cefd152004-02-08 22:55:38 +00001029
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001030 if (info->flash_id != FLASH_MAN_CFI) {
1031 puts ("Can't erase unknown flash type - aborted\n");
1032 return 1;
1033 }
1034 if ((s_first < 0) || (s_first > s_last)) {
1035 puts ("- no sectors to erase\n");
1036 return 1;
1037 }
Stefan Roeseefef95b2006-04-01 13:41:03 +02001038
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001039 prot = 0;
1040 for (sect = s_first; sect <= s_last; ++sect) {
1041 if (info->protect[sect]) {
1042 prot++;
wdenk2cefd152004-02-08 22:55:38 +00001043 }
1044 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001045 if (prot) {
1046 printf ("- Warning: %d protected sectors will not be erased!\n",
1047 prot);
1048 } else {
1049 putc ('\n');
1050 }
wdenke65527f2004-02-12 00:47:09 +00001051
wdenke65527f2004-02-12 00:47:09 +00001052
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001053 for (sect = s_first; sect <= s_last; sect++) {
1054 if (info->protect[sect] == 0) { /* not protected */
1055 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001056 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001057 case CFI_CMDSET_INTEL_STANDARD:
1058 case CFI_CMDSET_INTEL_EXTENDED:
1059 flash_write_cmd (info, sect, 0,
1060 FLASH_CMD_CLEAR_STATUS);
1061 flash_write_cmd (info, sect, 0,
1062 FLASH_CMD_BLOCK_ERASE);
1063 flash_write_cmd (info, sect, 0,
1064 FLASH_CMD_ERASE_CONFIRM);
1065 break;
1066 case CFI_CMDSET_AMD_STANDARD:
1067 case CFI_CMDSET_AMD_EXTENDED:
1068 flash_unlock_seq (info, sect);
1069 flash_write_cmd (info, sect,
1070 info->addr_unlock1,
1071 AMD_CMD_ERASE_START);
1072 flash_unlock_seq (info, sect);
1073 flash_write_cmd (info, sect, 0,
1074 AMD_CMD_ERASE_SECTOR);
1075 break;
1076#ifdef CONFIG_FLASH_CFI_LEGACY
1077 case CFI_CMDSET_AMD_LEGACY:
1078 flash_unlock_seq (info, 0);
1079 flash_write_cmd (info, 0, info->addr_unlock1,
1080 AMD_CMD_ERASE_START);
1081 flash_unlock_seq (info, 0);
1082 flash_write_cmd (info, sect, 0,
1083 AMD_CMD_ERASE_SECTOR);
1084 break;
1085#endif
1086 default:
1087 debug ("Unkown flash vendor %d\n",
1088 info->vendor);
1089 break;
wdenke65527f2004-02-12 00:47:09 +00001090 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001091
1092 if (flash_full_status_check
1093 (info, sect, info->erase_blk_tout, "erase")) {
1094 rcode = 1;
1095 } else
1096 putc ('.');
wdenk2cefd152004-02-08 22:55:38 +00001097 }
wdenk2cefd152004-02-08 22:55:38 +00001098 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001099 puts (" done\n");
1100 return rcode;
wdenk2cefd152004-02-08 22:55:38 +00001101}
wdenke65527f2004-02-12 00:47:09 +00001102
wdenk2cefd152004-02-08 22:55:38 +00001103/*-----------------------------------------------------------------------
1104 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001105void flash_print_info (flash_info_t * info)
wdenk2cefd152004-02-08 22:55:38 +00001106{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001107 int i;
wdenk369d43d2004-03-14 14:09:05 +00001108
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001109 if (info->flash_id != FLASH_MAN_CFI) {
1110 puts ("missing or unknown FLASH type\n");
1111 return;
1112 }
1113
1114 printf ("%s FLASH (%d x %d)",
1115 info->name,
1116 (info->portwidth << 3), (info->chipwidth << 3));
1117 if (info->size < 1024*1024)
1118 printf (" Size: %ld kB in %d Sectors\n",
1119 info->size >> 10, info->sector_count);
1120 else
1121 printf (" Size: %ld MB in %d Sectors\n",
1122 info->size >> 20, info->sector_count);
1123 printf (" ");
1124 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001125 case CFI_CMDSET_INTEL_PROG_REGIONS:
1126 printf ("Intel Prog Regions");
1127 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001128 case CFI_CMDSET_INTEL_STANDARD:
1129 printf ("Intel Standard");
1130 break;
1131 case CFI_CMDSET_INTEL_EXTENDED:
1132 printf ("Intel Extended");
1133 break;
1134 case CFI_CMDSET_AMD_STANDARD:
1135 printf ("AMD Standard");
1136 break;
1137 case CFI_CMDSET_AMD_EXTENDED:
1138 printf ("AMD Extended");
1139 break;
1140#ifdef CONFIG_FLASH_CFI_LEGACY
1141 case CFI_CMDSET_AMD_LEGACY:
1142 printf ("AMD Legacy");
1143 break;
wdenk369d43d2004-03-14 14:09:05 +00001144#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001145 default:
1146 printf ("Unknown (%d)", info->vendor);
1147 break;
wdenk2cefd152004-02-08 22:55:38 +00001148 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001149 printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
1150 info->manufacturer_id, info->device_id);
1151 if (info->device_id == 0x7E) {
1152 printf("%04X", info->device_id2);
1153 }
1154 printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n",
1155 info->erase_blk_tout,
1156 info->write_tout);
1157 if (info->buffer_size > 1) {
1158 printf (" Buffer write timeout: %ld ms, "
1159 "buffer size: %d bytes\n",
1160 info->buffer_write_tout,
1161 info->buffer_size);
1162 }
wdenk2cefd152004-02-08 22:55:38 +00001163
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001164 puts ("\n Sector Start Addresses:");
1165 for (i = 0; i < info->sector_count; ++i) {
1166 if ((i % 5) == 0)
1167 printf ("\n");
1168#ifdef CFG_FLASH_EMPTY_INFO
1169 int k;
1170 int size;
1171 int erased;
1172 volatile unsigned long *flash;
wdenk2cefd152004-02-08 22:55:38 +00001173
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001174 /*
1175 * Check if whole sector is erased
1176 */
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001177 size = flash_sector_size(info, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001178 erased = 1;
1179 flash = (volatile unsigned long *) info->start[i];
1180 size = size >> 2; /* divide by 4 for longword access */
1181 for (k = 0; k < size; k++) {
1182 if (*flash++ != 0xffffffff) {
1183 erased = 0;
1184 break;
1185 }
1186 }
wdenke65527f2004-02-12 00:47:09 +00001187
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001188 /* print empty and read-only info */
1189 printf (" %08lX %c %s ",
1190 info->start[i],
1191 erased ? 'E' : ' ',
1192 info->protect[i] ? "RO" : " ");
1193#else /* ! CFG_FLASH_EMPTY_INFO */
1194 printf (" %08lX %s ",
1195 info->start[i],
1196 info->protect[i] ? "RO" : " ");
wdenke65527f2004-02-12 00:47:09 +00001197#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001198 }
1199 putc ('\n');
1200 return;
wdenk2cefd152004-02-08 22:55:38 +00001201}
1202
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001203/*-----------------------------------------------------------------------
Jerry Van Barenaae73572008-03-08 13:48:01 -05001204 * This is used in a few places in write_buf() to show programming
1205 * progress. Making it a function is nasty because it needs to do side
1206 * effect updates to digit and dots. Repeated code is nasty too, so
1207 * we define it once here.
1208 */
Stefan Roese7758c162008-03-19 07:09:26 +01001209#ifdef CONFIG_FLASH_SHOW_PROGRESS
1210#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
1211 dots -= dots_sub; \
Jerry Van Barenaae73572008-03-08 13:48:01 -05001212 if ((scale > 0) && (dots <= 0)) { \
1213 if ((digit % 5) == 0) \
1214 printf ("%d", digit / 5); \
1215 else \
1216 putc ('.'); \
1217 digit--; \
1218 dots += scale; \
1219 }
Stefan Roese7758c162008-03-19 07:09:26 +01001220#else
1221#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1222#endif
Jerry Van Barenaae73572008-03-08 13:48:01 -05001223
1224/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001225 * Copy memory to flash, returns:
1226 * 0 - OK
1227 * 1 - write timeout
1228 * 2 - Flash not erased
wdenk2cefd152004-02-08 22:55:38 +00001229 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001230int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk2cefd152004-02-08 22:55:38 +00001231{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001232 ulong wp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001233 uchar *p;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001234 int aln;
wdenk2cefd152004-02-08 22:55:38 +00001235 cfiword_t cword;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001236 int i, rc;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001237#ifdef CFG_FLASH_USE_BUFFER_WRITE
1238 int buffered_size;
wdenk2cefd152004-02-08 22:55:38 +00001239#endif
Jerry Van Barenaae73572008-03-08 13:48:01 -05001240#ifdef CONFIG_FLASH_SHOW_PROGRESS
1241 int digit = CONFIG_FLASH_SHOW_PROGRESS;
1242 int scale = 0;
1243 int dots = 0;
1244
1245 /*
1246 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
1247 */
1248 if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
1249 scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
1250 CONFIG_FLASH_SHOW_PROGRESS);
1251 }
1252#endif
1253
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001254 /* get lower aligned address */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001255 wp = (addr & ~(info->portwidth - 1));
Haiying Wangc123a382007-02-21 16:52:31 +01001256
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001257 /* handle unaligned start */
1258 if ((aln = addr - wp) != 0) {
1259 cword.l = 0;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001260 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1261 for (i = 0; i < aln; ++i)
1262 flash_add_byte (info, &cword, flash_read8(p + i));
wdenk2cefd152004-02-08 22:55:38 +00001263
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001264 for (; (i < info->portwidth) && (cnt > 0); i++) {
1265 flash_add_byte (info, &cword, *src++);
1266 cnt--;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001267 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001268 for (; (cnt == 0) && (i < info->portwidth); ++i)
1269 flash_add_byte (info, &cword, flash_read8(p + i));
1270
1271 rc = flash_write_cfiword (info, wp, cword);
1272 unmap_physmem(p, info->portwidth);
1273 if (rc != 0)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001274 return rc;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001275
1276 wp += i;
Stefan Roese7758c162008-03-19 07:09:26 +01001277 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001278 }
1279
1280 /* handle the aligned part */
1281#ifdef CFG_FLASH_USE_BUFFER_WRITE
1282 buffered_size = (info->portwidth / info->chipwidth);
1283 buffered_size *= info->buffer_size;
1284 while (cnt >= info->portwidth) {
1285 /* prohibit buffer write when buffer_size is 1 */
1286 if (info->buffer_size == 1) {
1287 cword.l = 0;
1288 for (i = 0; i < info->portwidth; i++)
1289 flash_add_byte (info, &cword, *src++);
1290 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1291 return rc;
1292 wp += info->portwidth;
1293 cnt -= info->portwidth;
1294 continue;
1295 }
1296
1297 /* write buffer until next buffered_size aligned boundary */
1298 i = buffered_size - (wp % buffered_size);
1299 if (i > cnt)
1300 i = cnt;
1301 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
1302 return rc;
1303 i -= i & (info->portwidth - 1);
1304 wp += i;
1305 src += i;
1306 cnt -= i;
Stefan Roese7758c162008-03-19 07:09:26 +01001307 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001308 }
1309#else
1310 while (cnt >= info->portwidth) {
1311 cword.l = 0;
1312 for (i = 0; i < info->portwidth; i++) {
1313 flash_add_byte (info, &cword, *src++);
1314 }
1315 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1316 return rc;
1317 wp += info->portwidth;
1318 cnt -= info->portwidth;
Stefan Roese7758c162008-03-19 07:09:26 +01001319 FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001320 }
1321#endif /* CFG_FLASH_USE_BUFFER_WRITE */
Jerry Van Barenaae73572008-03-08 13:48:01 -05001322
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001323 if (cnt == 0) {
1324 return (0);
1325 }
1326
1327 /*
1328 * handle unaligned tail bytes
1329 */
1330 cword.l = 0;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001331 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1332 for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001333 flash_add_byte (info, &cword, *src++);
1334 --cnt;
1335 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001336 for (; i < info->portwidth; ++i)
1337 flash_add_byte (info, &cword, flash_read8(p + i));
1338 unmap_physmem(p, info->portwidth);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001339
1340 return flash_write_cfiword (info, wp, cword);
wdenk2cefd152004-02-08 22:55:38 +00001341}
wdenke65527f2004-02-12 00:47:09 +00001342
wdenk2cefd152004-02-08 22:55:38 +00001343/*-----------------------------------------------------------------------
1344 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001345#ifdef CFG_FLASH_PROTECTION
1346
1347int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk2cefd152004-02-08 22:55:38 +00001348{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001349 int retcode = 0;
wdenke65527f2004-02-12 00:47:09 +00001350
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001351 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1352 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1353 if (prot)
1354 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
1355 else
1356 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
wdenk2cefd152004-02-08 22:55:38 +00001357
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001358 if ((retcode =
1359 flash_full_status_check (info, sector, info->erase_blk_tout,
1360 prot ? "protect" : "unprotect")) == 0) {
wdenke65527f2004-02-12 00:47:09 +00001361
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001362 info->protect[sector] = prot;
1363
1364 /*
1365 * On some of Intel's flash chips (marked via legacy_unlock)
1366 * unprotect unprotects all locking.
1367 */
1368 if ((prot == 0) && (info->legacy_unlock)) {
1369 flash_sect_t i;
1370
1371 for (i = 0; i < info->sector_count; i++) {
1372 if (info->protect[i])
1373 flash_real_protect (info, i, 1);
1374 }
wdenk2cefd152004-02-08 22:55:38 +00001375 }
wdenk2cefd152004-02-08 22:55:38 +00001376 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001377 return retcode;
wdenk2cefd152004-02-08 22:55:38 +00001378}
wdenke65527f2004-02-12 00:47:09 +00001379
wdenk2cefd152004-02-08 22:55:38 +00001380/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001381 * flash_read_user_serial - read the OneTimeProgramming cells
wdenk2cefd152004-02-08 22:55:38 +00001382 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001383void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
1384 int len)
wdenk2cefd152004-02-08 22:55:38 +00001385{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001386 uchar *src;
1387 uchar *dst;
wdenke65527f2004-02-12 00:47:09 +00001388
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001389 dst = buffer;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001390 src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001391 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1392 memcpy (dst, src + offset, len);
1393 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001394 flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
wdenk2cefd152004-02-08 22:55:38 +00001395}
1396
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001397/*
1398 * flash_read_factory_serial - read the device Id from the protection area
wdenk2cefd152004-02-08 22:55:38 +00001399 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001400void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
1401 int len)
wdenk2cefd152004-02-08 22:55:38 +00001402{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001403 uchar *src;
wdenke65527f2004-02-12 00:47:09 +00001404
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001405 src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001406 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1407 memcpy (buffer, src + offset, len);
1408 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001409 flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
wdenk2cefd152004-02-08 22:55:38 +00001410}
1411
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001412#endif /* CFG_FLASH_PROTECTION */
1413
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001414/*-----------------------------------------------------------------------
1415 * Reverse the order of the erase regions in the CFI QRY structure.
1416 * This is needed for chips that are either a) correctly detected as
1417 * top-boot, or b) buggy.
1418 */
1419static void cfi_reverse_geometry(struct cfi_qry *qry)
1420{
1421 unsigned int i, j;
1422 u32 tmp;
1423
1424 for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
1425 tmp = qry->erase_region_info[i];
1426 qry->erase_region_info[i] = qry->erase_region_info[j];
1427 qry->erase_region_info[j] = tmp;
1428 }
1429}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001430
wdenk2cefd152004-02-08 22:55:38 +00001431/*-----------------------------------------------------------------------
Stefan Roese12797482006-11-13 13:55:24 +01001432 * read jedec ids from device and set corresponding fields in info struct
1433 *
1434 * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1435 *
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001436 */
1437static void cmdset_intel_read_jedec_ids(flash_info_t *info)
1438{
1439 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1440 flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1441 udelay(1000); /* some flash are slow to respond */
1442 info->manufacturer_id = flash_read_uchar (info,
1443 FLASH_OFFSET_MANUFACTURER_ID);
1444 info->device_id = flash_read_uchar (info,
1445 FLASH_OFFSET_DEVICE_ID);
1446 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1447}
1448
1449static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
1450{
1451 info->cmd_reset = FLASH_CMD_RESET;
1452
1453 cmdset_intel_read_jedec_ids(info);
1454 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1455
1456#ifdef CFG_FLASH_PROTECTION
1457 /* read legacy lock/unlock bit from intel flash */
1458 if (info->ext_addr) {
1459 info->legacy_unlock = flash_read_uchar (info,
1460 info->ext_addr + 5) & 0x08;
1461 }
1462#endif
1463
1464 return 0;
1465}
1466
1467static void cmdset_amd_read_jedec_ids(flash_info_t *info)
1468{
1469 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1470 flash_unlock_seq(info, 0);
1471 flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
1472 udelay(1000); /* some flash are slow to respond */
Tor Krill7f2a3052008-03-28 11:29:10 +01001473
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001474 info->manufacturer_id = flash_read_uchar (info,
1475 FLASH_OFFSET_MANUFACTURER_ID);
Tor Krill7f2a3052008-03-28 11:29:10 +01001476
1477 switch (info->chipwidth){
1478 case FLASH_CFI_8BIT:
1479 info->device_id = flash_read_uchar (info,
1480 FLASH_OFFSET_DEVICE_ID);
1481 if (info->device_id == 0x7E) {
1482 /* AMD 3-byte (expanded) device ids */
1483 info->device_id2 = flash_read_uchar (info,
1484 FLASH_OFFSET_DEVICE_ID2);
1485 info->device_id2 <<= 8;
1486 info->device_id2 |= flash_read_uchar (info,
1487 FLASH_OFFSET_DEVICE_ID3);
1488 }
1489 break;
1490 case FLASH_CFI_16BIT:
1491 info->device_id = flash_read_word (info,
1492 FLASH_OFFSET_DEVICE_ID);
1493 break;
1494 default:
1495 break;
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001496 }
1497 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1498}
1499
1500static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
1501{
1502 info->cmd_reset = AMD_CMD_RESET;
1503
1504 cmdset_amd_read_jedec_ids(info);
1505 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1506
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001507 return 0;
1508}
1509
1510#ifdef CONFIG_FLASH_CFI_LEGACY
Stefan Roese12797482006-11-13 13:55:24 +01001511static void flash_read_jedec_ids (flash_info_t * info)
1512{
1513 info->manufacturer_id = 0;
1514 info->device_id = 0;
1515 info->device_id2 = 0;
1516
1517 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001518 case CFI_CMDSET_INTEL_PROG_REGIONS:
Stefan Roese12797482006-11-13 13:55:24 +01001519 case CFI_CMDSET_INTEL_STANDARD:
1520 case CFI_CMDSET_INTEL_EXTENDED:
Michael Schwingen5fb0aa42008-01-12 20:29:47 +01001521 cmdset_intel_read_jedec_ids(info);
Stefan Roese12797482006-11-13 13:55:24 +01001522 break;
1523 case CFI_CMDSET_AMD_STANDARD:
1524 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen5fb0aa42008-01-12 20:29:47 +01001525 cmdset_amd_read_jedec_ids(info);
Stefan Roese12797482006-11-13 13:55:24 +01001526 break;
1527 default:
1528 break;
1529 }
1530}
1531
1532/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001533 * Call board code to request info about non-CFI flash.
1534 * board_flash_get_legacy needs to fill in at least:
1535 * info->portwidth, info->chipwidth and info->interface for Jedec probing.
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001536 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001537static int flash_detect_legacy(ulong base, int banknum)
wdenk2cefd152004-02-08 22:55:38 +00001538{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001539 flash_info_t *info = &flash_info[banknum];
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001540
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001541 if (board_flash_get_legacy(base, banknum, info)) {
1542 /* board code may have filled info completely. If not, we
1543 use JEDEC ID probing. */
1544 if (!info->vendor) {
1545 int modes[] = {
1546 CFI_CMDSET_AMD_STANDARD,
1547 CFI_CMDSET_INTEL_STANDARD
1548 };
1549 int i;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001550
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001551 for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1552 info->vendor = modes[i];
1553 info->start[0] = base;
1554 if (info->portwidth == FLASH_CFI_8BIT
1555 && info->interface == FLASH_CFI_X8X16) {
1556 info->addr_unlock1 = 0x2AAA;
1557 info->addr_unlock2 = 0x5555;
1558 } else {
1559 info->addr_unlock1 = 0x5555;
1560 info->addr_unlock2 = 0x2AAA;
1561 }
1562 flash_read_jedec_ids(info);
1563 debug("JEDEC PROBE: ID %x %x %x\n",
1564 info->manufacturer_id,
1565 info->device_id,
1566 info->device_id2);
1567 if (jedec_flash_match(info, base))
1568 break;
1569 }
1570 }
1571
1572 switch(info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001573 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001574 case CFI_CMDSET_INTEL_STANDARD:
1575 case CFI_CMDSET_INTEL_EXTENDED:
1576 info->cmd_reset = FLASH_CMD_RESET;
1577 break;
1578 case CFI_CMDSET_AMD_STANDARD:
1579 case CFI_CMDSET_AMD_EXTENDED:
1580 case CFI_CMDSET_AMD_LEGACY:
1581 info->cmd_reset = AMD_CMD_RESET;
1582 break;
1583 }
1584 info->flash_id = FLASH_MAN_CFI;
1585 return 1;
1586 }
1587 return 0; /* use CFI */
1588}
1589#else
1590static inline int flash_detect_legacy(ulong base, int banknum)
1591{
1592 return 0; /* use CFI */
1593}
1594#endif
1595
1596/*-----------------------------------------------------------------------
1597 * detect if flash is compatible with the Common Flash Interface (CFI)
1598 * http://www.jedec.org/download/search/jesd68.pdf
1599 */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001600static void flash_read_cfi (flash_info_t *info, void *buf,
1601 unsigned int start, size_t len)
1602{
1603 u8 *p = buf;
1604 unsigned int i;
1605
1606 for (i = 0; i < len; i++)
1607 p[i] = flash_read_uchar(info, start + i);
1608}
1609
1610static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001611{
1612 int cfi_offset;
1613
Michael Schwingen4661cf72008-02-18 23:16:35 +01001614 /* We do not yet know what kind of commandset to use, so we issue
1615 the reset command in both Intel and AMD variants, in the hope
1616 that AMD flash roms ignore the Intel command. */
1617 flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
1618 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
1619
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001620 for (cfi_offset=0;
1621 cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
1622 cfi_offset++) {
1623 flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
1624 FLASH_CMD_CFI);
1625 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1626 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1627 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001628 flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1629 sizeof(struct cfi_qry));
1630 info->interface = le16_to_cpu(qry->interface_desc);
1631
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001632 info->cfi_offset = flash_offset_cfi[cfi_offset];
1633 debug ("device interface is %d\n",
1634 info->interface);
1635 debug ("found port %d chip %d ",
1636 info->portwidth, info->chipwidth);
1637 debug ("port %d bits chip %d bits\n",
1638 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1639 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1640
1641 /* calculate command offsets as in the Linux driver */
1642 info->addr_unlock1 = 0x555;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001643 info->addr_unlock2 = 0x2aa;
1644
1645 /*
1646 * modify the unlock address if we are
1647 * in compatibility mode
1648 */
1649 if ( /* x8/x16 in x8 mode */
1650 ((info->chipwidth == FLASH_CFI_BY8) &&
1651 (info->interface == FLASH_CFI_X8X16)) ||
1652 /* x16/x32 in x16 mode */
1653 ((info->chipwidth == FLASH_CFI_BY16) &&
1654 (info->interface == FLASH_CFI_X16X32)))
1655 {
1656 info->addr_unlock1 = 0xaaa;
1657 info->addr_unlock2 = 0x555;
1658 }
1659
1660 info->name = "CFI conformant";
1661 return 1;
1662 }
1663 }
1664
1665 return 0;
1666}
1667
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001668static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001669{
wdenke65527f2004-02-12 00:47:09 +00001670 debug ("flash detect cfi\n");
wdenk2cefd152004-02-08 22:55:38 +00001671
Stefan Roesec865e6c2006-02-28 15:29:58 +01001672 for (info->portwidth = CFG_FLASH_CFI_WIDTH;
wdenke65527f2004-02-12 00:47:09 +00001673 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1674 for (info->chipwidth = FLASH_CFI_BY8;
1675 info->chipwidth <= info->portwidth;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001676 info->chipwidth <<= 1)
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001677 if (__flash_detect_cfi(info, qry))
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001678 return 1;
wdenk2cefd152004-02-08 22:55:38 +00001679 }
wdenke65527f2004-02-12 00:47:09 +00001680 debug ("not found\n");
wdenk2cefd152004-02-08 22:55:38 +00001681 return 0;
1682}
wdenke65527f2004-02-12 00:47:09 +00001683
wdenk2cefd152004-02-08 22:55:38 +00001684/*
Haavard Skinnemoen750ea7f2007-12-14 15:36:18 +01001685 * Manufacturer-specific quirks. Add workarounds for geometry
1686 * reversal, etc. here.
1687 */
1688static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1689{
1690 /* check if flash geometry needs reversal */
1691 if (qry->num_erase_regions > 1) {
1692 /* reverse geometry if top boot part */
1693 if (info->cfi_version < 0x3131) {
1694 /* CFI < 1.1, try to guess from device id */
1695 if ((info->device_id & 0x80) != 0)
1696 cfi_reverse_geometry(qry);
1697 } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1698 /* CFI >= 1.1, deduct from top/bottom flag */
1699 /* note: ext_addr is valid since cfi_version > 0 */
1700 cfi_reverse_geometry(qry);
1701 }
1702 }
1703}
1704
1705static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1706{
1707 int reverse_geometry = 0;
1708
1709 /* Check the "top boot" bit in the PRI */
1710 if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1711 reverse_geometry = 1;
1712
1713 /* AT49BV6416(T) list the erase regions in the wrong order.
1714 * However, the device ID is identical with the non-broken
1715 * AT49BV642D since u-boot only reads the low byte (they
1716 * differ in the high byte.) So leave out this fixup for now.
1717 */
1718#if 0
1719 if (info->device_id == 0xd6 || info->device_id == 0xd2)
1720 reverse_geometry = !reverse_geometry;
1721#endif
1722
1723 if (reverse_geometry)
1724 cfi_reverse_geometry(qry);
1725}
1726
1727/*
wdenk2cefd152004-02-08 22:55:38 +00001728 * The following code cannot be run from FLASH!
1729 *
1730 */
Marian Balakowicz513b4a12005-10-11 19:09:42 +02001731ulong flash_get_size (ulong base, int banknum)
wdenk2cefd152004-02-08 22:55:38 +00001732{
wdenke65527f2004-02-12 00:47:09 +00001733 flash_info_t *info = &flash_info[banknum];
wdenk2cefd152004-02-08 22:55:38 +00001734 int i, j;
1735 flash_sect_t sect_cnt;
1736 unsigned long sector;
1737 unsigned long tmp;
1738 int size_ratio;
1739 uchar num_erase_regions;
wdenke65527f2004-02-12 00:47:09 +00001740 int erase_region_size;
1741 int erase_region_count;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001742 struct cfi_qry qry;
Stefan Roese12797482006-11-13 13:55:24 +01001743
Kumar Gala899032b2008-05-15 15:13:08 -05001744 memset(&qry, 0, sizeof(qry));
1745
Stefan Roese12797482006-11-13 13:55:24 +01001746 info->ext_addr = 0;
1747 info->cfi_version = 0;
Stefan Roeseefef95b2006-04-01 13:41:03 +02001748#ifdef CFG_FLASH_PROTECTION
Stefan Roeseefef95b2006-04-01 13:41:03 +02001749 info->legacy_unlock = 0;
1750#endif
wdenk2cefd152004-02-08 22:55:38 +00001751
1752 info->start[0] = base;
1753
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001754 if (flash_detect_cfi (info, &qry)) {
1755 info->vendor = le16_to_cpu(qry.p_id);
1756 info->ext_addr = le16_to_cpu(qry.p_adr);
1757 num_erase_regions = qry.num_erase_regions;
1758
Stefan Roese12797482006-11-13 13:55:24 +01001759 if (info->ext_addr) {
1760 info->cfi_version = (ushort) flash_read_uchar (info,
1761 info->ext_addr + 3) << 8;
1762 info->cfi_version |= (ushort) flash_read_uchar (info,
1763 info->ext_addr + 4);
1764 }
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001765
wdenke65527f2004-02-12 00:47:09 +00001766#ifdef DEBUG
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001767 flash_printqry (&qry);
wdenke65527f2004-02-12 00:47:09 +00001768#endif
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001769
wdenke65527f2004-02-12 00:47:09 +00001770 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001771 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk2cefd152004-02-08 22:55:38 +00001772 case CFI_CMDSET_INTEL_STANDARD:
1773 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001774 cmdset_intel_init(info, &qry);
wdenk2cefd152004-02-08 22:55:38 +00001775 break;
1776 case CFI_CMDSET_AMD_STANDARD:
1777 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001778 cmdset_amd_init(info, &qry);
wdenk2cefd152004-02-08 22:55:38 +00001779 break;
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001780 default:
1781 printf("CFI: Unknown command set 0x%x\n",
1782 info->vendor);
1783 /*
1784 * Unfortunately, this means we don't know how
1785 * to get the chip back to Read mode. Might
1786 * as well try an Intel-style reset...
1787 */
1788 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1789 return 0;
wdenk2cefd152004-02-08 22:55:38 +00001790 }
wdenk6cfa84e2004-02-10 00:03:41 +00001791
Haavard Skinnemoen750ea7f2007-12-14 15:36:18 +01001792 /* Do manufacturer-specific fixups */
1793 switch (info->manufacturer_id) {
1794 case 0x0001:
1795 flash_fixup_amd(info, &qry);
1796 break;
1797 case 0x001f:
1798 flash_fixup_atmel(info, &qry);
1799 break;
1800 }
1801
wdenke65527f2004-02-12 00:47:09 +00001802 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese12797482006-11-13 13:55:24 +01001803 debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
1804 debug ("device id is 0x%x\n", info->device_id);
1805 debug ("device id2 is 0x%x\n", info->device_id2);
1806 debug ("cfi version is 0x%04x\n", info->cfi_version);
1807
wdenk2cefd152004-02-08 22:55:38 +00001808 size_ratio = info->portwidth / info->chipwidth;
wdenke65527f2004-02-12 00:47:09 +00001809 /* if the chip is x8/x16 reduce the ratio by half */
1810 if ((info->interface == FLASH_CFI_X8X16)
1811 && (info->chipwidth == FLASH_CFI_BY8)) {
1812 size_ratio >>= 1;
1813 }
wdenke65527f2004-02-12 00:47:09 +00001814 debug ("size_ratio %d port %d bits chip %d bits\n",
1815 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1816 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1817 debug ("found %d erase regions\n", num_erase_regions);
wdenk2cefd152004-02-08 22:55:38 +00001818 sect_cnt = 0;
1819 sector = base;
wdenke65527f2004-02-12 00:47:09 +00001820 for (i = 0; i < num_erase_regions; i++) {
1821 if (i > NUM_ERASE_REGIONS) {
wdenke537b3b2004-02-23 23:54:43 +00001822 printf ("%d erase regions found, only %d used\n",
1823 num_erase_regions, NUM_ERASE_REGIONS);
wdenk2cefd152004-02-08 22:55:38 +00001824 break;
1825 }
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001826
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001827 tmp = le32_to_cpu(qry.erase_region_info[i]);
1828 debug("erase region %u: 0x%08lx\n", i, tmp);
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001829
1830 erase_region_count = (tmp & 0xffff) + 1;
1831 tmp >>= 16;
wdenke65527f2004-02-12 00:47:09 +00001832 erase_region_size =
1833 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenkaeba06f2004-06-09 17:34:58 +00001834 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenke537b3b2004-02-23 23:54:43 +00001835 erase_region_count, erase_region_size);
wdenke65527f2004-02-12 00:47:09 +00001836 for (j = 0; j < erase_region_count; j++) {
Michael Schwingen73d044d2007-12-07 23:35:02 +01001837 if (sect_cnt >= CFG_MAX_FLASH_SECT) {
1838 printf("ERROR: too many flash sectors\n");
1839 break;
1840 }
wdenk2cefd152004-02-08 22:55:38 +00001841 info->start[sect_cnt] = sector;
1842 sector += (erase_region_size * size_ratio);
wdenk26c58432005-01-09 17:12:27 +00001843
1844 /*
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001845 * Only read protection status from
1846 * supported devices (intel...)
wdenk26c58432005-01-09 17:12:27 +00001847 */
1848 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001849 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk26c58432005-01-09 17:12:27 +00001850 case CFI_CMDSET_INTEL_EXTENDED:
1851 case CFI_CMDSET_INTEL_STANDARD:
1852 info->protect[sect_cnt] =
1853 flash_isset (info, sect_cnt,
1854 FLASH_OFFSET_PROTECT,
1855 FLASH_STATUS_PROTECT);
1856 break;
1857 default:
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001858 /* default: not protected */
1859 info->protect[sect_cnt] = 0;
wdenk26c58432005-01-09 17:12:27 +00001860 }
1861
wdenk2cefd152004-02-08 22:55:38 +00001862 sect_cnt++;
1863 }
1864 }
1865
1866 info->sector_count = sect_cnt;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001867 info->size = 1 << qry.dev_size;
wdenk2cefd152004-02-08 22:55:38 +00001868 /* multiply the size by the number of chips */
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001869 info->size *= size_ratio;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001870 info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1871 tmp = 1 << qry.block_erase_timeout_typ;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001872 info->erase_blk_tout = tmp *
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001873 (1 << qry.block_erase_timeout_max);
1874 tmp = (1 << qry.buf_write_timeout_typ) *
1875 (1 << qry.buf_write_timeout_max);
1876
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001877 /* round up when converting to ms */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001878 info->buffer_write_tout = (tmp + 999) / 1000;
1879 tmp = (1 << qry.word_write_timeout_typ) *
1880 (1 << qry.word_write_timeout_max);
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001881 /* round up when converting to ms */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001882 info->write_tout = (tmp + 999) / 1000;
wdenk2cefd152004-02-08 22:55:38 +00001883 info->flash_id = FLASH_MAN_CFI;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001884 if ((info->interface == FLASH_CFI_X8X16) &&
1885 (info->chipwidth == FLASH_CFI_BY8)) {
1886 /* XXX - Need to test on x8/x16 in parallel. */
1887 info->portwidth >>= 1;
wdenked2ac4b2004-03-14 18:23:55 +00001888 }
wdenk2cefd152004-02-08 22:55:38 +00001889 }
1890
Wolfgang Denka205a8f2005-09-25 16:41:22 +02001891 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenke65527f2004-02-12 00:47:09 +00001892 return (info->size);
wdenk2cefd152004-02-08 22:55:38 +00001893}
1894
wdenk2cefd152004-02-08 22:55:38 +00001895/*-----------------------------------------------------------------------
1896 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001897unsigned long flash_init (void)
wdenk2cefd152004-02-08 22:55:38 +00001898{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001899 unsigned long size = 0;
1900 int i;
Matthias Fuchs50431522008-04-18 16:29:40 +02001901#if defined(CFG_FLASH_AUTOPROTECT_LIST)
1902 struct apl_s {
1903 ulong start;
1904 ulong size;
1905 } apl[] = CFG_FLASH_AUTOPROTECT_LIST;
1906#endif
wdenk2cefd152004-02-08 22:55:38 +00001907
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001908#ifdef CFG_FLASH_PROTECTION
1909 char *s = getenv("unlock");
Michael Schwingen73d044d2007-12-07 23:35:02 +01001910#endif
wdenk2cefd152004-02-08 22:55:38 +00001911
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001912 /* Init: no FLASHes known */
1913 for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
1914 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenk2cefd152004-02-08 22:55:38 +00001915
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001916 if (!flash_detect_legacy (bank_base[i], i))
1917 flash_get_size (bank_base[i], i);
1918 size += flash_info[i].size;
1919 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
1920#ifndef CFG_FLASH_QUIET_TEST
1921 printf ("## Unknown FLASH on Bank %d "
1922 "- Size = 0x%08lx = %ld MB\n",
1923 i+1, flash_info[i].size,
1924 flash_info[i].size << 20);
1925#endif /* CFG_FLASH_QUIET_TEST */
1926 }
1927#ifdef CFG_FLASH_PROTECTION
1928 else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
1929 /*
1930 * Only the U-Boot image and it's environment
1931 * is protected, all other sectors are
1932 * unprotected (unlocked) if flash hardware
1933 * protection is used (CFG_FLASH_PROTECTION)
1934 * and the environment variable "unlock" is
1935 * set to "yes".
1936 */
1937 if (flash_info[i].legacy_unlock) {
1938 int k;
wdenk2cefd152004-02-08 22:55:38 +00001939
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001940 /*
1941 * Disable legacy_unlock temporarily,
1942 * since flash_real_protect would
1943 * relock all other sectors again
1944 * otherwise.
1945 */
1946 flash_info[i].legacy_unlock = 0;
wdenk2cefd152004-02-08 22:55:38 +00001947
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001948 /*
1949 * Legacy unlocking (e.g. Intel J3) ->
1950 * unlock only one sector. This will
1951 * unlock all sectors.
1952 */
1953 flash_real_protect (&flash_info[i], 0, 0);
wdenk2cefd152004-02-08 22:55:38 +00001954
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001955 flash_info[i].legacy_unlock = 1;
wdenk2cefd152004-02-08 22:55:38 +00001956
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001957 /*
1958 * Manually mark other sectors as
1959 * unlocked (unprotected)
1960 */
1961 for (k = 1; k < flash_info[i].sector_count; k++)
1962 flash_info[i].protect[k] = 0;
1963 } else {
1964 /*
1965 * No legancy unlocking -> unlock all sectors
1966 */
1967 flash_protect (FLAG_PROTECT_CLEAR,
1968 flash_info[i].start[0],
1969 flash_info[i].start[0]
1970 + flash_info[i].size - 1,
1971 &flash_info[i]);
Stefan Roesec865e6c2006-02-28 15:29:58 +01001972 }
Stefan Roesec865e6c2006-02-28 15:29:58 +01001973 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001974#endif /* CFG_FLASH_PROTECTION */
1975 }
Stefan Roesec865e6c2006-02-28 15:29:58 +01001976
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001977 /* Monitor protection ON by default */
1978#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
1979 flash_protect (FLAG_PROTECT_SET,
1980 CFG_MONITOR_BASE,
1981 CFG_MONITOR_BASE + monitor_flash_len - 1,
1982 flash_get_info(CFG_MONITOR_BASE));
1983#endif
Stefan Roesec865e6c2006-02-28 15:29:58 +01001984
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001985 /* Environment protection ON by default */
1986#ifdef CFG_ENV_IS_IN_FLASH
1987 flash_protect (FLAG_PROTECT_SET,
1988 CFG_ENV_ADDR,
1989 CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
1990 flash_get_info(CFG_ENV_ADDR));
1991#endif
Stefan Roesec865e6c2006-02-28 15:29:58 +01001992
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001993 /* Redundant environment protection ON by default */
1994#ifdef CFG_ENV_ADDR_REDUND
1995 flash_protect (FLAG_PROTECT_SET,
1996 CFG_ENV_ADDR_REDUND,
1997 CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
1998 flash_get_info(CFG_ENV_ADDR_REDUND));
1999#endif
Matthias Fuchs50431522008-04-18 16:29:40 +02002000
2001#if defined(CFG_FLASH_AUTOPROTECT_LIST)
2002 for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
2003 debug("autoprotecting from %08x to %08x\n",
2004 apl[i].start, apl[i].start + apl[i].size - 1);
2005 flash_protect (FLAG_PROTECT_SET,
2006 apl[i].start,
2007 apl[i].start + apl[i].size - 1,
2008 flash_get_info(apl[i].start));
2009 }
2010#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002011 return (size);
wdenk2cefd152004-02-08 22:55:38 +00002012}
Heiko Schocher3c58a992007-01-11 15:44:44 +01002013
wdenk2cefd152004-02-08 22:55:38 +00002014#endif /* CFG_FLASH_CFI */