blob: 12647ef98613ff818be19e53fd33e65eaf90c445 [file] [log] [blame]
wdenk5653fc32004-02-08 22:55:38 +00001/*
wdenkbf9e3b32004-02-12 00:47:09 +00002 * (C) Copyright 2002-2004
wdenk5653fc32004-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>
wdenk5653fc32004-02-08 22:55:38 +00007 *
wdenkbf9e3b32004-02-12 00:47:09 +00008 * Copyright (C) 2004
9 * Ed Okerson
Stefan Roese260421a2006-11-13 13:55:24 +010010 *
11 * Copyright (C) 2006
12 * Tolunay Orkun <listmember@orkun.us>
wdenkbf9e3b32004-02-12 00:47:09 +000013 *
wdenk5653fc32004-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 *
wdenk5653fc32004-02-08 22:55:38 +000032 */
33
34/* The DEBUG define must be before common to enable debugging */
wdenk2d1a5372004-02-23 19:30:57 +000035/* #define DEBUG */
36
wdenk5653fc32004-02-08 22:55:38 +000037#include <common.h>
38#include <asm/processor.h>
Haiying Wang3a197b22007-02-21 16:52:31 +010039#include <asm/io.h>
wdenk4c0d4c32004-06-09 17:34:58 +000040#include <asm/byteorder.h>
wdenk2a8af182005-04-13 10:02:42 +000041#include <environment.h>
wdenkbf9e3b32004-02-12 00:47:09 +000042#ifdef CFG_FLASH_CFI_DRIVER
wdenk028ab6b2004-02-23 23:54:43 +000043
wdenk5653fc32004-02-08 22:55:38 +000044/*
Haavard Skinnemoen7e5b9b42007-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.
wdenk5653fc32004-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 Roese260421a2006-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
wdenk5653fc32004-02-08 22:55:38 +000060 *
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +010061 * Define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
Heiko Schocherd0b6e142007-01-19 18:05:26 +010062 * reading and writing ... (yes there is such a Hardware).
wdenk5653fc32004-02-08 22:55:38 +000063 */
64
wdenkbf9e3b32004-02-12 00:47:09 +000065#ifndef CFG_FLASH_BANKS_LIST
66#define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE }
67#endif
68
wdenk5653fc32004-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 Leoenenko9c048b52008-05-07 21:25:33 +040079#define FLASH_CMD_READ_STATUS 0x70
wdenkbf9e3b32004-02-12 00:47:09 +000080#define FLASH_CMD_WRITE_TO_BUFFER 0xE8
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +040081#define FLASH_CMD_WRITE_BUFFER_PROG 0xE9
wdenkbf9e3b32004-02-12 00:47:09 +000082#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0
wdenk5653fc32004-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
wdenk855a4962004-03-14 18:23:55 +000098#define AMD_CMD_UNLOCK_START 0xAA
99#define AMD_CMD_UNLOCK_ACK 0x55
Stefan Roese79b4cda2006-02-28 15:29:58 +0100100#define AMD_CMD_WRITE_TO_BUFFER 0x25
101#define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29
wdenk5653fc32004-02-08 22:55:38 +0000102
103#define AMD_STATUS_TOGGLE 0x40
104#define AMD_STATUS_ERROR 0x20
Stefan Roese79b4cda2006-02-28 15:29:58 +0100105
Stefan Roese260421a2006-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
wdenk5653fc32004-02-08 22:55:38 +0000110#define FLASH_OFFSET_CFI 0x55
Wolfgang Denk92eb7292006-12-27 01:26:13 +0100111#define FLASH_OFFSET_CFI_ALT 0x555
wdenk5653fc32004-02-08 22:55:38 +0000112#define FLASH_OFFSET_CFI_RESP 0x10
wdenkbf9e3b32004-02-12 00:47:09 +0000113#define FLASH_OFFSET_PRIMARY_VENDOR 0x13
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +0100114/* extended query table primary address */
115#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15
wdenk5653fc32004-02-08 22:55:38 +0000116#define FLASH_OFFSET_WTOUT 0x1F
wdenkbf9e3b32004-02-12 00:47:09 +0000117#define FLASH_OFFSET_WBTOUT 0x20
wdenk5653fc32004-02-08 22:55:38 +0000118#define FLASH_OFFSET_ETOUT 0x21
wdenkbf9e3b32004-02-12 00:47:09 +0000119#define FLASH_OFFSET_CETOUT 0x22
wdenk5653fc32004-02-08 22:55:38 +0000120#define FLASH_OFFSET_WMAX_TOUT 0x23
wdenkbf9e3b32004-02-12 00:47:09 +0000121#define FLASH_OFFSET_WBMAX_TOUT 0x24
wdenk5653fc32004-02-08 22:55:38 +0000122#define FLASH_OFFSET_EMAX_TOUT 0x25
wdenkbf9e3b32004-02-12 00:47:09 +0000123#define FLASH_OFFSET_CEMAX_TOUT 0x26
wdenk5653fc32004-02-08 22:55:38 +0000124#define FLASH_OFFSET_SIZE 0x27
wdenkbf9e3b32004-02-12 00:47:09 +0000125#define FLASH_OFFSET_INTERFACE 0x28
126#define FLASH_OFFSET_BUFFER_SIZE 0x2A
wdenk5653fc32004-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
wdenkbf9e3b32004-02-12 00:47:09 +0000130#define FLASH_OFFSET_USER_PROTECTION 0x85
131#define FLASH_OFFSET_INTEL_PROTECTION 0x81
wdenk5653fc32004-02-08 22:55:38 +0000132
Stefan Roese260421a2006-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 Leoenenko9c048b52008-05-07 21:25:33 +0400141#define CFI_CMDSET_INTEL_PROG_REGIONS 512
wdenk5653fc32004-02-08 22:55:38 +0000142
wdenkf7d15722004-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 Roese260421a2006-11-13 13:55:24 +0100145# define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */
wdenkf7d15722004-12-18 22:35:43 +0000146#endif
147
wdenk5653fc32004-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 Roese260421a2006-11-13 13:55:24 +0100155#define NUM_ERASE_REGIONS 4 /* max. number of erase regions */
wdenk5653fc32004-02-08 22:55:38 +0000156
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +0100157static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
Wolfgang Denk92eb7292006-12-27 01:26:13 +0100158
Marian Balakowicze6f2e902005-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
wdenk5653fc32004-02-08 22:55:38 +0000164static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST;
Marian Balakowicze6f2e902005-10-11 19:09:42 +0200165flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */
166#endif
wdenk5653fc32004-02-08 22:55:38 +0000167
Stefan Roese79b4cda2006-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
wdenk5653fc32004-02-08 22:55:38 +0000175typedef unsigned long flash_sect_t;
176
Haavard Skinnemoene23741f2007-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 Skinnemoencdbaefb2007-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 Hellstrom97bf85d2008-03-28 20:40:19 +0100245static u64 __flash_read64(void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100246{
247 /* No architectures currently implement __raw_readq() */
248 return *(volatile u64 *)addr;
249}
250
Daniel Hellstrom97bf85d2008-03-28 20:40:19 +0100251u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
252
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200253/*-----------------------------------------------------------------------
254 */
Wolfgang Denk080bdb72005-10-05 01:51:29 +0200255#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200256static flash_info_t *flash_get_info(ulong base)
257{
258 int i;
259 flash_info_t * info = 0;
260
261 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 }
267
268 return i == CFG_MAX_FLASH_BANKS ? 0 : info;
269}
wdenk5653fc32004-02-08 22:55:38 +0000270#endif
271
Haavard Skinnemoen12d30aa2007-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
wdenk5653fc32004-02-08 22:55:38 +0000280/*-----------------------------------------------------------------------
281 * create an address based on the offset and the port width
282 */
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100283static inline void *
284flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000285{
Haavard Skinnemoen12d30aa2007-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);
wdenk5653fc32004-02-08 22:55:38 +0000299}
wdenkbf9e3b32004-02-12 00:47:09 +0000300
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200301/*-----------------------------------------------------------------------
302 * make a proper sized command based on the port and chip widths
303 */
Sebastian Siewior7288f972008-07-15 13:35:23 +0200304static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200305{
306 int i;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400307 int cword_offset;
308 int cp_offset;
Sebastian Siewior340ccb22008-07-16 20:04:49 +0200309#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
310 u32 cmd_le = cpu_to_le32(cmd);
311#endif
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400312 uchar val;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200313 uchar *cp = (uchar *) cmdbuf;
314
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400315 for (i = info->portwidth; i > 0; i--){
316 cword_offset = (info->portwidth-i)%info->chipwidth;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200317#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400318 cp_offset = info->portwidth - i;
Sebastian Siewior340ccb22008-07-16 20:04:49 +0200319 val = *((uchar*)&cmd_le + cword_offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200320#else
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400321 cp_offset = i - 1;
Sebastian Siewior7288f972008-07-15 13:35:23 +0200322 val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200323#endif
Sebastian Siewior7288f972008-07-15 13:35:23 +0200324 cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400325 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200326}
327
wdenkbf9e3b32004-02-12 00:47:09 +0000328#ifdef DEBUG
329/*-----------------------------------------------------------------------
330 * Debug support
331 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100332static void print_longlong (char *str, unsigned long long data)
wdenkbf9e3b32004-02-12 00:47:09 +0000333{
334 int i;
335 char *cp;
336
337 cp = (unsigned char *) &data;
338 for (i = 0; i < 8; i++)
339 sprintf (&str[i * 2], "%2.2x", *cp++);
340}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200341
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100342static void flash_printqry (struct cfi_qry *qry)
wdenkbf9e3b32004-02-12 00:47:09 +0000343{
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100344 u8 *p = (u8 *)qry;
wdenkbf9e3b32004-02-12 00:47:09 +0000345 int x, y;
346
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100347 for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
348 debug("%02x : ", x);
349 for (y = 0; y < 16; y++)
350 debug("%2.2x ", p[x + y]);
351 debug(" ");
wdenkbf9e3b32004-02-12 00:47:09 +0000352 for (y = 0; y < 16; y++) {
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100353 unsigned char c = p[x + y];
354 if (c >= 0x20 && c <= 0x7e)
355 debug("%c", c);
356 else
357 debug(".");
wdenkbf9e3b32004-02-12 00:47:09 +0000358 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100359 debug("\n");
wdenkbf9e3b32004-02-12 00:47:09 +0000360 }
361}
wdenkbf9e3b32004-02-12 00:47:09 +0000362#endif
363
364
wdenk5653fc32004-02-08 22:55:38 +0000365/*-----------------------------------------------------------------------
366 * read a character at a port width address
367 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100368static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000369{
370 uchar *cp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100371 uchar retval;
wdenkbf9e3b32004-02-12 00:47:09 +0000372
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100373 cp = flash_map (info, 0, offset);
Heiko Schocherd0b6e142007-01-19 18:05:26 +0100374#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100375 retval = flash_read8(cp);
wdenkbf9e3b32004-02-12 00:47:09 +0000376#else
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100377 retval = flash_read8(cp + info->portwidth - 1);
wdenkbf9e3b32004-02-12 00:47:09 +0000378#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100379 flash_unmap (info, 0, offset, cp);
380 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000381}
382
383/*-----------------------------------------------------------------------
Tor Krill90447ec2008-03-28 11:29:10 +0100384 * read a word at a port width address, assume 16bit bus
385 */
386static inline ushort flash_read_word (flash_info_t * info, uint offset)
387{
388 ushort *addr, retval;
389
390 addr = flash_map (info, 0, offset);
391 retval = flash_read16 (addr);
392 flash_unmap (info, 0, offset, addr);
393 return retval;
394}
395
396
397/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +0100398 * read a long word by picking the least significant byte of each maximum
wdenk5653fc32004-02-08 22:55:38 +0000399 * port size word. Swap for ppc format.
400 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100401static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
402 uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000403{
wdenkbf9e3b32004-02-12 00:47:09 +0000404 uchar *addr;
405 ulong retval;
wdenk5653fc32004-02-08 22:55:38 +0000406
wdenkbf9e3b32004-02-12 00:47:09 +0000407#ifdef DEBUG
408 int x;
409#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100410 addr = flash_map (info, sect, offset);
wdenkbf9e3b32004-02-12 00:47:09 +0000411
412#ifdef DEBUG
413 debug ("long addr is at %p info->portwidth = %d\n", addr,
414 info->portwidth);
415 for (x = 0; x < 4 * info->portwidth; x++) {
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100416 debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
wdenkbf9e3b32004-02-12 00:47:09 +0000417 }
418#endif
Heiko Schocherd0b6e142007-01-19 18:05:26 +0100419#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100420 retval = ((flash_read8(addr) << 16) |
421 (flash_read8(addr + info->portwidth) << 24) |
422 (flash_read8(addr + 2 * info->portwidth)) |
423 (flash_read8(addr + 3 * info->portwidth) << 8));
wdenkbf9e3b32004-02-12 00:47:09 +0000424#else
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100425 retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
426 (flash_read8(addr + info->portwidth - 1) << 16) |
427 (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
428 (flash_read8(addr + 3 * info->portwidth - 1)));
wdenkbf9e3b32004-02-12 00:47:09 +0000429#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100430 flash_unmap(info, sect, offset, addr);
431
wdenkbf9e3b32004-02-12 00:47:09 +0000432 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000433}
434
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200435/*
436 * Write a proper sized command to the correct address
437 */
438static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
Sebastian Siewior7288f972008-07-15 13:35:23 +0200439 uint offset, u32 cmd)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200440{
Stefan Roese79b4cda2006-02-28 15:29:58 +0100441
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100442 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200443 cfiword_t cword;
444
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100445 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200446 flash_make_cmd (info, cmd, &cword);
447 switch (info->portwidth) {
448 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100449 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200450 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100451 flash_write8(cword.c, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200452 break;
453 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100454 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200455 cmd, cword.w,
456 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100457 flash_write16(cword.w, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200458 break;
459 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100460 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200461 cmd, cword.l,
462 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100463 flash_write32(cword.l, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200464 break;
465 case FLASH_CFI_64BIT:
466#ifdef DEBUG
467 {
468 char str[20];
469
470 print_longlong (str, cword.ll);
471
472 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100473 addr, cmd, str,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200474 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
475 }
476#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100477 flash_write64(cword.ll, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200478 break;
479 }
480
481 /* Ensure all the instructions are fully finished */
482 sync();
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100483
484 flash_unmap(info, sect, offset, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200485}
486
487static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
488{
489 flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
490 flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
491}
492
493/*-----------------------------------------------------------------------
494 */
495static int flash_isequal (flash_info_t * info, flash_sect_t sect,
496 uint offset, uchar cmd)
497{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100498 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200499 cfiword_t cword;
500 int retval;
501
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100502 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200503 flash_make_cmd (info, cmd, &cword);
504
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100505 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200506 switch (info->portwidth) {
507 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100508 debug ("is= %x %x\n", flash_read8(addr), cword.c);
509 retval = (flash_read8(addr) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200510 break;
511 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100512 debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
513 retval = (flash_read16(addr) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200514 break;
515 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100516 debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
517 retval = (flash_read32(addr) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200518 break;
519 case FLASH_CFI_64BIT:
520#ifdef DEBUG
521 {
522 char str1[20];
523 char str2[20];
524
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100525 print_longlong (str1, flash_read64(addr));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200526 print_longlong (str2, cword.ll);
527 debug ("is= %s %s\n", str1, str2);
528 }
529#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100530 retval = (flash_read64(addr) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200531 break;
532 default:
533 retval = 0;
534 break;
535 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100536 flash_unmap(info, sect, offset, addr);
537
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200538 return retval;
539}
540
541/*-----------------------------------------------------------------------
542 */
543static int flash_isset (flash_info_t * info, flash_sect_t sect,
544 uint offset, uchar cmd)
545{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100546 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200547 cfiword_t cword;
548 int retval;
549
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100550 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200551 flash_make_cmd (info, cmd, &cword);
552 switch (info->portwidth) {
553 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100554 retval = ((flash_read8(addr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200555 break;
556 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100557 retval = ((flash_read16(addr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200558 break;
559 case FLASH_CFI_32BIT:
Stefan Roese47cc23c2008-01-02 14:05:37 +0100560 retval = ((flash_read32(addr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200561 break;
562 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100563 retval = ((flash_read64(addr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200564 break;
565 default:
566 retval = 0;
567 break;
568 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100569 flash_unmap(info, sect, offset, addr);
570
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200571 return retval;
572}
573
574/*-----------------------------------------------------------------------
575 */
576static int flash_toggle (flash_info_t * info, flash_sect_t sect,
577 uint offset, uchar cmd)
578{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100579 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200580 cfiword_t cword;
581 int retval;
582
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100583 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200584 flash_make_cmd (info, cmd, &cword);
585 switch (info->portwidth) {
586 case FLASH_CFI_8BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200587 retval = flash_read8(addr) != flash_read8(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200588 break;
589 case FLASH_CFI_16BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200590 retval = flash_read16(addr) != flash_read16(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200591 break;
592 case FLASH_CFI_32BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200593 retval = flash_read32(addr) != flash_read32(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200594 break;
595 case FLASH_CFI_64BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200596 retval = flash_read64(addr) != flash_read64(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200597 break;
598 default:
599 retval = 0;
600 break;
601 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100602 flash_unmap(info, sect, offset, addr);
603
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200604 return retval;
605}
606
607/*
608 * flash_is_busy - check to see if the flash is busy
609 *
610 * This routine checks the status of the chip and returns true if the
611 * chip is busy.
612 */
613static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
614{
615 int retval;
616
617 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400618 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200619 case CFI_CMDSET_INTEL_STANDARD:
620 case CFI_CMDSET_INTEL_EXTENDED:
621 retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
622 break;
623 case CFI_CMDSET_AMD_STANDARD:
624 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100625#ifdef CONFIG_FLASH_CFI_LEGACY
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200626 case CFI_CMDSET_AMD_LEGACY:
627#endif
628 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
629 break;
630 default:
631 retval = 0;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100632 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200633 debug ("flash_is_busy: %d\n", retval);
634 return retval;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100635}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200636
637/*-----------------------------------------------------------------------
638 * wait for XSR.7 to be set. Time out with an error if it does not.
639 * This routine does not set the flash to read-array mode.
640 */
641static int flash_status_check (flash_info_t * info, flash_sect_t sector,
642 ulong tout, char *prompt)
643{
644 ulong start;
645
646#if CFG_HZ != 1000
647 tout *= CFG_HZ/1000;
648#endif
649
650 /* Wait for command completion */
651 start = get_timer (0);
652 while (flash_is_busy (info, sector)) {
653 if (get_timer (start) > tout) {
654 printf ("Flash %s timeout at address %lx data %lx\n",
655 prompt, info->start[sector],
656 flash_read_long (info, sector, 0));
657 flash_write_cmd (info, sector, 0, info->cmd_reset);
658 return ERR_TIMOUT;
659 }
660 udelay (1); /* also triggers watchdog */
661 }
662 return ERR_OK;
663}
664
665/*-----------------------------------------------------------------------
666 * Wait for XSR.7 to be set, if it times out print an error, otherwise
667 * do a full status check.
668 *
669 * This routine sets the flash to read-array mode.
670 */
671static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
672 ulong tout, char *prompt)
673{
674 int retcode;
675
676 retcode = flash_status_check (info, sector, tout, prompt);
677 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400678 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200679 case CFI_CMDSET_INTEL_EXTENDED:
680 case CFI_CMDSET_INTEL_STANDARD:
681 if ((retcode == ERR_OK)
682 && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
683 retcode = ERR_INVAL;
684 printf ("Flash %s error at address %lx\n", prompt,
685 info->start[sector]);
686 if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
687 FLASH_STATUS_PSLBS)) {
688 puts ("Command Sequence Error.\n");
689 } else if (flash_isset (info, sector, 0,
690 FLASH_STATUS_ECLBS)) {
691 puts ("Block Erase Error.\n");
692 retcode = ERR_NOT_ERASED;
693 } else if (flash_isset (info, sector, 0,
694 FLASH_STATUS_PSLBS)) {
695 puts ("Locking Error\n");
696 }
697 if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
698 puts ("Block locked.\n");
699 retcode = ERR_PROTECTED;
700 }
701 if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
702 puts ("Vpp Low Error.\n");
703 }
704 flash_write_cmd (info, sector, 0, info->cmd_reset);
705 break;
706 default:
707 break;
708 }
709 return retcode;
710}
711
712/*-----------------------------------------------------------------------
713 */
714static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
715{
716#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
717 unsigned short w;
718 unsigned int l;
719 unsigned long long ll;
720#endif
721
722 switch (info->portwidth) {
723 case FLASH_CFI_8BIT:
724 cword->c = c;
725 break;
726 case FLASH_CFI_16BIT:
727#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
728 w = c;
729 w <<= 8;
730 cword->w = (cword->w >> 8) | w;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100731#else
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200732 cword->w = (cword->w << 8) | c;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100733#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200734 break;
735 case FLASH_CFI_32BIT:
736#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
737 l = c;
738 l <<= 24;
739 cword->l = (cword->l >> 8) | l;
740#else
741 cword->l = (cword->l << 8) | c;
Stefan Roese2662b402006-04-01 13:41:03 +0200742#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200743 break;
744 case FLASH_CFI_64BIT:
745#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
746 ll = c;
747 ll <<= 56;
748 cword->ll = (cword->ll >> 8) | ll;
749#else
750 cword->ll = (cword->ll << 8) | c;
751#endif
752 break;
wdenk5653fc32004-02-08 22:55:38 +0000753 }
wdenk5653fc32004-02-08 22:55:38 +0000754}
755
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200756/* loop through the sectors from the highest address when the passed
757 * address is greater or equal to the sector address we have a match
wdenk5653fc32004-02-08 22:55:38 +0000758 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200759static flash_sect_t find_sector (flash_info_t * info, ulong addr)
wdenk7680c142005-05-16 15:23:22 +0000760{
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200761 flash_sect_t sector;
wdenk7680c142005-05-16 15:23:22 +0000762
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200763 for (sector = info->sector_count - 1; sector >= 0; sector--) {
764 if (addr >= info->start[sector])
wdenk7680c142005-05-16 15:23:22 +0000765 break;
766 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200767 return sector;
wdenk7680c142005-05-16 15:23:22 +0000768}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200769
770/*-----------------------------------------------------------------------
771 */
772static int flash_write_cfiword (flash_info_t * info, ulong dest,
773 cfiword_t cword)
774{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100775 void *dstaddr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200776 int flag;
777
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100778 dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200779
780 /* Check if Flash is (sufficiently) erased */
781 switch (info->portwidth) {
782 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100783 flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200784 break;
785 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100786 flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200787 break;
788 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100789 flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200790 break;
791 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100792 flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200793 break;
794 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100795 flag = 0;
796 break;
797 }
798 if (!flag) {
799 unmap_physmem(dstaddr, info->portwidth);
Stefan Roese0dc80e22007-12-27 07:50:54 +0100800 return ERR_NOT_ERASED;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200801 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200802
803 /* Disable interrupts which might cause a timeout here */
804 flag = disable_interrupts ();
805
806 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400807 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200808 case CFI_CMDSET_INTEL_EXTENDED:
809 case CFI_CMDSET_INTEL_STANDARD:
810 flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
811 flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
812 break;
813 case CFI_CMDSET_AMD_EXTENDED:
814 case CFI_CMDSET_AMD_STANDARD:
815#ifdef CONFIG_FLASH_CFI_LEGACY
816 case CFI_CMDSET_AMD_LEGACY:
Wolfgang Denk080bdb72005-10-05 01:51:29 +0200817#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200818 flash_unlock_seq (info, 0);
819 flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
820 break;
821 }
822
823 switch (info->portwidth) {
824 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100825 flash_write8(cword.c, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200826 break;
827 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100828 flash_write16(cword.w, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200829 break;
830 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100831 flash_write32(cword.l, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200832 break;
833 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100834 flash_write64(cword.ll, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200835 break;
836 }
837
838 /* re-enable interrupts if necessary */
839 if (flag)
840 enable_interrupts ();
841
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100842 unmap_physmem(dstaddr, info->portwidth);
843
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200844 return flash_full_status_check (info, find_sector (info, dest),
845 info->write_tout, "write");
846}
847
848#ifdef CFG_FLASH_USE_BUFFER_WRITE
849
850static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
851 int len)
852{
853 flash_sect_t sector;
854 int cnt;
855 int retcode;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100856 void *src = cp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100857 void *dst = map_physmem(dest, len, MAP_NOCACHE);
Stefan Roese0dc80e22007-12-27 07:50:54 +0100858 void *dst2 = dst;
859 int flag = 0;
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200860 uint offset = 0;
861 unsigned int shift;
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400862 uchar write_cmd;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100863
Stefan Roese0dc80e22007-12-27 07:50:54 +0100864 switch (info->portwidth) {
865 case FLASH_CFI_8BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200866 shift = 0;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100867 break;
868 case FLASH_CFI_16BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200869 shift = 1;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100870 break;
871 case FLASH_CFI_32BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200872 shift = 2;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100873 break;
874 case FLASH_CFI_64BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200875 shift = 3;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100876 break;
877 default:
878 retcode = ERR_INVAL;
879 goto out_unmap;
880 }
881
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200882 cnt = len >> shift;
883
Stefan Roese0dc80e22007-12-27 07:50:54 +0100884 while ((cnt-- > 0) && (flag == 0)) {
885 switch (info->portwidth) {
886 case FLASH_CFI_8BIT:
887 flag = ((flash_read8(dst2) & flash_read8(src)) ==
888 flash_read8(src));
889 src += 1, dst2 += 1;
890 break;
891 case FLASH_CFI_16BIT:
892 flag = ((flash_read16(dst2) & flash_read16(src)) ==
893 flash_read16(src));
894 src += 2, dst2 += 2;
895 break;
896 case FLASH_CFI_32BIT:
897 flag = ((flash_read32(dst2) & flash_read32(src)) ==
898 flash_read32(src));
899 src += 4, dst2 += 4;
900 break;
901 case FLASH_CFI_64BIT:
902 flag = ((flash_read64(dst2) & flash_read64(src)) ==
903 flash_read64(src));
904 src += 8, dst2 += 8;
905 break;
906 }
907 }
908 if (!flag) {
909 retcode = ERR_NOT_ERASED;
910 goto out_unmap;
911 }
912
913 src = cp;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100914 sector = find_sector (info, dest);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200915
916 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400917 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200918 case CFI_CMDSET_INTEL_STANDARD:
919 case CFI_CMDSET_INTEL_EXTENDED:
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400920 write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
921 FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200922 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400923 flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS);
924 flash_write_cmd (info, sector, 0, write_cmd);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200925 retcode = flash_status_check (info, sector,
926 info->buffer_write_tout,
927 "write to buffer");
928 if (retcode == ERR_OK) {
929 /* reduce the number of loops by the width of
930 * the port */
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200931 cnt = len >> shift;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400932 flash_write_cmd (info, sector, 0, cnt - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200933 while (cnt-- > 0) {
934 switch (info->portwidth) {
935 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100936 flash_write8(flash_read8(src), dst);
937 src += 1, dst += 1;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200938 break;
939 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100940 flash_write16(flash_read16(src), dst);
941 src += 2, dst += 2;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200942 break;
943 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100944 flash_write32(flash_read32(src), dst);
945 src += 4, dst += 4;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200946 break;
947 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100948 flash_write64(flash_read64(src), dst);
949 src += 8, dst += 8;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200950 break;
951 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100952 retcode = ERR_INVAL;
953 goto out_unmap;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200954 }
955 }
956 flash_write_cmd (info, sector, 0,
957 FLASH_CMD_WRITE_BUFFER_CONFIRM);
958 retcode = flash_full_status_check (
959 info, sector, info->buffer_write_tout,
960 "buffer write");
961 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100962
963 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200964
965 case CFI_CMDSET_AMD_STANDARD:
966 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200967 flash_unlock_seq(info,0);
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200968
969#ifdef CONFIG_FLASH_SPANSION_S29WS_N
970 offset = ((unsigned long)dst - info->start[sector]) >> shift;
971#endif
972 flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
973 cnt = len >> shift;
974 flash_write_cmd(info, sector, offset, (uchar)cnt - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200975
976 switch (info->portwidth) {
977 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100978 while (cnt-- > 0) {
979 flash_write8(flash_read8(src), dst);
980 src += 1, dst += 1;
981 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200982 break;
983 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100984 while (cnt-- > 0) {
985 flash_write16(flash_read16(src), dst);
986 src += 2, dst += 2;
987 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200988 break;
989 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100990 while (cnt-- > 0) {
991 flash_write32(flash_read32(src), dst);
992 src += 4, dst += 4;
993 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200994 break;
995 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100996 while (cnt-- > 0) {
997 flash_write64(flash_read64(src), dst);
998 src += 8, dst += 8;
999 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001000 break;
1001 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001002 retcode = ERR_INVAL;
1003 goto out_unmap;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001004 }
1005
1006 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1007 retcode = flash_full_status_check (info, sector,
1008 info->buffer_write_tout,
1009 "buffer write");
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001010 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001011
1012 default:
1013 debug ("Unknown Command Set\n");
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001014 retcode = ERR_INVAL;
1015 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001016 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001017
1018out_unmap:
1019 unmap_physmem(dst, len);
1020 return retcode;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001021}
1022#endif /* CFG_FLASH_USE_BUFFER_WRITE */
1023
wdenk7680c142005-05-16 15:23:22 +00001024
1025/*-----------------------------------------------------------------------
1026 */
wdenkbf9e3b32004-02-12 00:47:09 +00001027int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk5653fc32004-02-08 22:55:38 +00001028{
1029 int rcode = 0;
1030 int prot;
1031 flash_sect_t sect;
1032
wdenkbf9e3b32004-02-12 00:47:09 +00001033 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001034 puts ("Can't erase unknown flash type - aborted\n");
wdenk5653fc32004-02-08 22:55:38 +00001035 return 1;
1036 }
1037 if ((s_first < 0) || (s_first > s_last)) {
wdenk4b9206e2004-03-23 22:14:11 +00001038 puts ("- no sectors to erase\n");
wdenk5653fc32004-02-08 22:55:38 +00001039 return 1;
1040 }
1041
1042 prot = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001043 for (sect = s_first; sect <= s_last; ++sect) {
wdenk5653fc32004-02-08 22:55:38 +00001044 if (info->protect[sect]) {
1045 prot++;
1046 }
1047 }
1048 if (prot) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001049 printf ("- Warning: %d protected sectors will not be erased!\n",
1050 prot);
wdenk5653fc32004-02-08 22:55:38 +00001051 } else {
wdenk4b9206e2004-03-23 22:14:11 +00001052 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001053 }
1054
1055
wdenkbf9e3b32004-02-12 00:47:09 +00001056 for (sect = s_first; sect <= s_last; sect++) {
wdenk5653fc32004-02-08 22:55:38 +00001057 if (info->protect[sect] == 0) { /* not protected */
wdenkbf9e3b32004-02-12 00:47:09 +00001058 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001059 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk5653fc32004-02-08 22:55:38 +00001060 case CFI_CMDSET_INTEL_STANDARD:
1061 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001062 flash_write_cmd (info, sect, 0,
1063 FLASH_CMD_CLEAR_STATUS);
1064 flash_write_cmd (info, sect, 0,
1065 FLASH_CMD_BLOCK_ERASE);
1066 flash_write_cmd (info, sect, 0,
1067 FLASH_CMD_ERASE_CONFIRM);
wdenk5653fc32004-02-08 22:55:38 +00001068 break;
1069 case CFI_CMDSET_AMD_STANDARD:
1070 case CFI_CMDSET_AMD_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +00001071 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001072 flash_write_cmd (info, sect,
1073 info->addr_unlock1,
1074 AMD_CMD_ERASE_START);
wdenkbf9e3b32004-02-12 00:47:09 +00001075 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001076 flash_write_cmd (info, sect, 0,
1077 AMD_CMD_ERASE_SECTOR);
wdenk5653fc32004-02-08 22:55:38 +00001078 break;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001079#ifdef CONFIG_FLASH_CFI_LEGACY
1080 case CFI_CMDSET_AMD_LEGACY:
1081 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001082 flash_write_cmd (info, 0, info->addr_unlock1,
1083 AMD_CMD_ERASE_START);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001084 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001085 flash_write_cmd (info, sect, 0,
1086 AMD_CMD_ERASE_SECTOR);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001087 break;
1088#endif
wdenk5653fc32004-02-08 22:55:38 +00001089 default:
wdenkbf9e3b32004-02-12 00:47:09 +00001090 debug ("Unkown flash vendor %d\n",
1091 info->vendor);
wdenk5653fc32004-02-08 22:55:38 +00001092 break;
1093 }
1094
wdenkbf9e3b32004-02-12 00:47:09 +00001095 if (flash_full_status_check
1096 (info, sect, info->erase_blk_tout, "erase")) {
wdenk5653fc32004-02-08 22:55:38 +00001097 rcode = 1;
1098 } else
wdenk4b9206e2004-03-23 22:14:11 +00001099 putc ('.');
wdenk5653fc32004-02-08 22:55:38 +00001100 }
1101 }
wdenk4b9206e2004-03-23 22:14:11 +00001102 puts (" done\n");
wdenk5653fc32004-02-08 22:55:38 +00001103 return rcode;
1104}
1105
1106/*-----------------------------------------------------------------------
1107 */
wdenkbf9e3b32004-02-12 00:47:09 +00001108void flash_print_info (flash_info_t * info)
wdenk5653fc32004-02-08 22:55:38 +00001109{
1110 int i;
1111
1112 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001113 puts ("missing or unknown FLASH type\n");
wdenk5653fc32004-02-08 22:55:38 +00001114 return;
1115 }
1116
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001117 printf ("%s FLASH (%d x %d)",
1118 info->name,
wdenkbf9e3b32004-02-12 00:47:09 +00001119 (info->portwidth << 3), (info->chipwidth << 3));
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001120 if (info->size < 1024*1024)
1121 printf (" Size: %ld kB in %d Sectors\n",
1122 info->size >> 10, info->sector_count);
1123 else
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001124 printf (" Size: %ld MB in %d Sectors\n",
1125 info->size >> 20, info->sector_count);
Stefan Roese260421a2006-11-13 13:55:24 +01001126 printf (" ");
1127 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001128 case CFI_CMDSET_INTEL_PROG_REGIONS:
1129 printf ("Intel Prog Regions");
1130 break;
Stefan Roese260421a2006-11-13 13:55:24 +01001131 case CFI_CMDSET_INTEL_STANDARD:
1132 printf ("Intel Standard");
1133 break;
1134 case CFI_CMDSET_INTEL_EXTENDED:
1135 printf ("Intel Extended");
1136 break;
1137 case CFI_CMDSET_AMD_STANDARD:
1138 printf ("AMD Standard");
1139 break;
1140 case CFI_CMDSET_AMD_EXTENDED:
1141 printf ("AMD Extended");
1142 break;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001143#ifdef CONFIG_FLASH_CFI_LEGACY
1144 case CFI_CMDSET_AMD_LEGACY:
1145 printf ("AMD Legacy");
1146 break;
1147#endif
Stefan Roese260421a2006-11-13 13:55:24 +01001148 default:
1149 printf ("Unknown (%d)", info->vendor);
1150 break;
1151 }
1152 printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
1153 info->manufacturer_id, info->device_id);
1154 if (info->device_id == 0x7E) {
1155 printf("%04X", info->device_id2);
1156 }
1157 printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n",
wdenk028ab6b2004-02-23 23:54:43 +00001158 info->erase_blk_tout,
Stefan Roese260421a2006-11-13 13:55:24 +01001159 info->write_tout);
1160 if (info->buffer_size > 1) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001161 printf (" Buffer write timeout: %ld ms, "
1162 "buffer size: %d bytes\n",
wdenk028ab6b2004-02-23 23:54:43 +00001163 info->buffer_write_tout,
1164 info->buffer_size);
Stefan Roese260421a2006-11-13 13:55:24 +01001165 }
wdenk5653fc32004-02-08 22:55:38 +00001166
Stefan Roese260421a2006-11-13 13:55:24 +01001167 puts ("\n Sector Start Addresses:");
wdenkbf9e3b32004-02-12 00:47:09 +00001168 for (i = 0; i < info->sector_count; ++i) {
Stefan Roese260421a2006-11-13 13:55:24 +01001169 if ((i % 5) == 0)
1170 printf ("\n");
wdenk5653fc32004-02-08 22:55:38 +00001171#ifdef CFG_FLASH_EMPTY_INFO
1172 int k;
1173 int size;
1174 int erased;
1175 volatile unsigned long *flash;
1176
1177 /*
1178 * Check if whole sector is erased
1179 */
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001180 size = flash_sector_size(info, i);
wdenk5653fc32004-02-08 22:55:38 +00001181 erased = 1;
wdenkbf9e3b32004-02-12 00:47:09 +00001182 flash = (volatile unsigned long *) info->start[i];
1183 size = size >> 2; /* divide by 4 for longword access */
1184 for (k = 0; k < size; k++) {
1185 if (*flash++ != 0xffffffff) {
1186 erased = 0;
1187 break;
1188 }
1189 }
wdenk5653fc32004-02-08 22:55:38 +00001190
wdenk5653fc32004-02-08 22:55:38 +00001191 /* print empty and read-only info */
Stefan Roese260421a2006-11-13 13:55:24 +01001192 printf (" %08lX %c %s ",
wdenk5653fc32004-02-08 22:55:38 +00001193 info->start[i],
Stefan Roese260421a2006-11-13 13:55:24 +01001194 erased ? 'E' : ' ',
1195 info->protect[i] ? "RO" : " ");
Wolfgang Denkb63de2c2005-09-25 00:23:05 +02001196#else /* ! CFG_FLASH_EMPTY_INFO */
Stefan Roese260421a2006-11-13 13:55:24 +01001197 printf (" %08lX %s ",
1198 info->start[i],
1199 info->protect[i] ? "RO" : " ");
wdenk5653fc32004-02-08 22:55:38 +00001200#endif
1201 }
wdenk4b9206e2004-03-23 22:14:11 +00001202 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001203 return;
1204}
1205
1206/*-----------------------------------------------------------------------
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001207 * This is used in a few places in write_buf() to show programming
1208 * progress. Making it a function is nasty because it needs to do side
1209 * effect updates to digit and dots. Repeated code is nasty too, so
1210 * we define it once here.
1211 */
Stefan Roesef0105722008-03-19 07:09:26 +01001212#ifdef CONFIG_FLASH_SHOW_PROGRESS
1213#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
1214 dots -= dots_sub; \
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001215 if ((scale > 0) && (dots <= 0)) { \
1216 if ((digit % 5) == 0) \
1217 printf ("%d", digit / 5); \
1218 else \
1219 putc ('.'); \
1220 digit--; \
1221 dots += scale; \
1222 }
Stefan Roesef0105722008-03-19 07:09:26 +01001223#else
1224#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1225#endif
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001226
1227/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001228 * Copy memory to flash, returns:
1229 * 0 - OK
1230 * 1 - write timeout
1231 * 2 - Flash not erased
1232 */
wdenkbf9e3b32004-02-12 00:47:09 +00001233int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk5653fc32004-02-08 22:55:38 +00001234{
1235 ulong wp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001236 uchar *p;
wdenk5653fc32004-02-08 22:55:38 +00001237 int aln;
1238 cfiword_t cword;
1239 int i, rc;
wdenkbf9e3b32004-02-12 00:47:09 +00001240#ifdef CFG_FLASH_USE_BUFFER_WRITE
1241 int buffered_size;
1242#endif
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001243#ifdef CONFIG_FLASH_SHOW_PROGRESS
1244 int digit = CONFIG_FLASH_SHOW_PROGRESS;
1245 int scale = 0;
1246 int dots = 0;
1247
1248 /*
1249 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
1250 */
1251 if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
1252 scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
1253 CONFIG_FLASH_SHOW_PROGRESS);
1254 }
1255#endif
1256
wdenkbf9e3b32004-02-12 00:47:09 +00001257 /* get lower aligned address */
wdenk5653fc32004-02-08 22:55:38 +00001258 wp = (addr & ~(info->portwidth - 1));
1259
1260 /* handle unaligned start */
wdenkbf9e3b32004-02-12 00:47:09 +00001261 if ((aln = addr - wp) != 0) {
wdenk5653fc32004-02-08 22:55:38 +00001262 cword.l = 0;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001263 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1264 for (i = 0; i < aln; ++i)
1265 flash_add_byte (info, &cword, flash_read8(p + i));
wdenk5653fc32004-02-08 22:55:38 +00001266
wdenkbf9e3b32004-02-12 00:47:09 +00001267 for (; (i < info->portwidth) && (cnt > 0); i++) {
1268 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001269 cnt--;
wdenk5653fc32004-02-08 22:55:38 +00001270 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001271 for (; (cnt == 0) && (i < info->portwidth); ++i)
1272 flash_add_byte (info, &cword, flash_read8(p + i));
1273
1274 rc = flash_write_cfiword (info, wp, cword);
1275 unmap_physmem(p, info->portwidth);
1276 if (rc != 0)
wdenk5653fc32004-02-08 22:55:38 +00001277 return rc;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001278
1279 wp += i;
Stefan Roesef0105722008-03-19 07:09:26 +01001280 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001281 }
1282
wdenkbf9e3b32004-02-12 00:47:09 +00001283 /* handle the aligned part */
wdenk5653fc32004-02-08 22:55:38 +00001284#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenkbf9e3b32004-02-12 00:47:09 +00001285 buffered_size = (info->portwidth / info->chipwidth);
1286 buffered_size *= info->buffer_size;
1287 while (cnt >= info->portwidth) {
Stefan Roese79b4cda2006-02-28 15:29:58 +01001288 /* prohibit buffer write when buffer_size is 1 */
1289 if (info->buffer_size == 1) {
1290 cword.l = 0;
1291 for (i = 0; i < info->portwidth; i++)
1292 flash_add_byte (info, &cword, *src++);
1293 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1294 return rc;
1295 wp += info->portwidth;
1296 cnt -= info->portwidth;
1297 continue;
1298 }
1299
1300 /* write buffer until next buffered_size aligned boundary */
1301 i = buffered_size - (wp % buffered_size);
1302 if (i > cnt)
1303 i = cnt;
wdenkbf9e3b32004-02-12 00:47:09 +00001304 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
wdenk5653fc32004-02-08 22:55:38 +00001305 return rc;
Wolfgang Denk8d4ba3d2005-08-12 22:35:59 +02001306 i -= i & (info->portwidth - 1);
wdenk5653fc32004-02-08 22:55:38 +00001307 wp += i;
1308 src += i;
wdenkbf9e3b32004-02-12 00:47:09 +00001309 cnt -= i;
Stefan Roesef0105722008-03-19 07:09:26 +01001310 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001311 }
1312#else
wdenkbf9e3b32004-02-12 00:47:09 +00001313 while (cnt >= info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001314 cword.l = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001315 for (i = 0; i < info->portwidth; i++) {
1316 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001317 }
wdenkbf9e3b32004-02-12 00:47:09 +00001318 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk5653fc32004-02-08 22:55:38 +00001319 return rc;
1320 wp += info->portwidth;
1321 cnt -= info->portwidth;
Stefan Roesef0105722008-03-19 07:09:26 +01001322 FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
wdenk5653fc32004-02-08 22:55:38 +00001323 }
1324#endif /* CFG_FLASH_USE_BUFFER_WRITE */
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001325
wdenk5653fc32004-02-08 22:55:38 +00001326 if (cnt == 0) {
1327 return (0);
1328 }
1329
1330 /*
1331 * handle unaligned tail bytes
1332 */
1333 cword.l = 0;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001334 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1335 for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
wdenkbf9e3b32004-02-12 00:47:09 +00001336 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001337 --cnt;
1338 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001339 for (; i < info->portwidth; ++i)
1340 flash_add_byte (info, &cword, flash_read8(p + i));
1341 unmap_physmem(p, info->portwidth);
wdenk5653fc32004-02-08 22:55:38 +00001342
wdenkbf9e3b32004-02-12 00:47:09 +00001343 return flash_write_cfiword (info, wp, cword);
wdenk5653fc32004-02-08 22:55:38 +00001344}
1345
1346/*-----------------------------------------------------------------------
1347 */
1348#ifdef CFG_FLASH_PROTECTION
1349
wdenkbf9e3b32004-02-12 00:47:09 +00001350int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk5653fc32004-02-08 22:55:38 +00001351{
1352 int retcode = 0;
1353
wdenkbf9e3b32004-02-12 00:47:09 +00001354 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1355 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1356 if (prot)
1357 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
wdenk5653fc32004-02-08 22:55:38 +00001358 else
wdenkbf9e3b32004-02-12 00:47:09 +00001359 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
wdenk5653fc32004-02-08 22:55:38 +00001360
wdenkbf9e3b32004-02-12 00:47:09 +00001361 if ((retcode =
1362 flash_full_status_check (info, sector, info->erase_blk_tout,
1363 prot ? "protect" : "unprotect")) == 0) {
wdenk5653fc32004-02-08 22:55:38 +00001364
1365 info->protect[sector] = prot;
Stefan Roese2662b402006-04-01 13:41:03 +02001366
1367 /*
1368 * On some of Intel's flash chips (marked via legacy_unlock)
1369 * unprotect unprotects all locking.
1370 */
1371 if ((prot == 0) && (info->legacy_unlock)) {
wdenk5653fc32004-02-08 22:55:38 +00001372 flash_sect_t i;
wdenkbf9e3b32004-02-12 00:47:09 +00001373
1374 for (i = 0; i < info->sector_count; i++) {
1375 if (info->protect[i])
1376 flash_real_protect (info, i, 1);
wdenk5653fc32004-02-08 22:55:38 +00001377 }
1378 }
1379 }
wdenk5653fc32004-02-08 22:55:38 +00001380 return retcode;
wdenkbf9e3b32004-02-12 00:47:09 +00001381}
1382
wdenk5653fc32004-02-08 22:55:38 +00001383/*-----------------------------------------------------------------------
1384 * flash_read_user_serial - read the OneTimeProgramming cells
1385 */
wdenkbf9e3b32004-02-12 00:47:09 +00001386void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
1387 int len)
wdenk5653fc32004-02-08 22:55:38 +00001388{
wdenkbf9e3b32004-02-12 00:47:09 +00001389 uchar *src;
1390 uchar *dst;
wdenk5653fc32004-02-08 22:55:38 +00001391
1392 dst = buffer;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001393 src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001394 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1395 memcpy (dst, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001396 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001397 flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001398}
wdenkbf9e3b32004-02-12 00:47:09 +00001399
wdenk5653fc32004-02-08 22:55:38 +00001400/*
1401 * flash_read_factory_serial - read the device Id from the protection area
1402 */
wdenkbf9e3b32004-02-12 00:47:09 +00001403void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
1404 int len)
wdenk5653fc32004-02-08 22:55:38 +00001405{
wdenkbf9e3b32004-02-12 00:47:09 +00001406 uchar *src;
wdenkcd37d9e2004-02-10 00:03:41 +00001407
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001408 src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001409 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1410 memcpy (buffer, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001411 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001412 flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001413}
1414
1415#endif /* CFG_FLASH_PROTECTION */
1416
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001417/*-----------------------------------------------------------------------
1418 * Reverse the order of the erase regions in the CFI QRY structure.
1419 * This is needed for chips that are either a) correctly detected as
1420 * top-boot, or b) buggy.
1421 */
1422static void cfi_reverse_geometry(struct cfi_qry *qry)
1423{
1424 unsigned int i, j;
1425 u32 tmp;
1426
1427 for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
1428 tmp = qry->erase_region_info[i];
1429 qry->erase_region_info[i] = qry->erase_region_info[j];
1430 qry->erase_region_info[j] = tmp;
1431 }
1432}
wdenk5653fc32004-02-08 22:55:38 +00001433
1434/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +01001435 * read jedec ids from device and set corresponding fields in info struct
1436 *
1437 * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1438 *
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001439 */
1440static void cmdset_intel_read_jedec_ids(flash_info_t *info)
1441{
1442 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1443 flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1444 udelay(1000); /* some flash are slow to respond */
1445 info->manufacturer_id = flash_read_uchar (info,
1446 FLASH_OFFSET_MANUFACTURER_ID);
1447 info->device_id = flash_read_uchar (info,
1448 FLASH_OFFSET_DEVICE_ID);
1449 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1450}
1451
1452static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
1453{
1454 info->cmd_reset = FLASH_CMD_RESET;
1455
1456 cmdset_intel_read_jedec_ids(info);
1457 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1458
1459#ifdef CFG_FLASH_PROTECTION
1460 /* read legacy lock/unlock bit from intel flash */
1461 if (info->ext_addr) {
1462 info->legacy_unlock = flash_read_uchar (info,
1463 info->ext_addr + 5) & 0x08;
1464 }
1465#endif
1466
1467 return 0;
1468}
1469
1470static void cmdset_amd_read_jedec_ids(flash_info_t *info)
1471{
1472 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1473 flash_unlock_seq(info, 0);
1474 flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
1475 udelay(1000); /* some flash are slow to respond */
Tor Krill90447ec2008-03-28 11:29:10 +01001476
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001477 info->manufacturer_id = flash_read_uchar (info,
1478 FLASH_OFFSET_MANUFACTURER_ID);
Tor Krill90447ec2008-03-28 11:29:10 +01001479
1480 switch (info->chipwidth){
1481 case FLASH_CFI_8BIT:
1482 info->device_id = flash_read_uchar (info,
1483 FLASH_OFFSET_DEVICE_ID);
1484 if (info->device_id == 0x7E) {
1485 /* AMD 3-byte (expanded) device ids */
1486 info->device_id2 = flash_read_uchar (info,
1487 FLASH_OFFSET_DEVICE_ID2);
1488 info->device_id2 <<= 8;
1489 info->device_id2 |= flash_read_uchar (info,
1490 FLASH_OFFSET_DEVICE_ID3);
1491 }
1492 break;
1493 case FLASH_CFI_16BIT:
1494 info->device_id = flash_read_word (info,
1495 FLASH_OFFSET_DEVICE_ID);
1496 break;
1497 default:
1498 break;
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001499 }
1500 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1501}
1502
1503static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
1504{
1505 info->cmd_reset = AMD_CMD_RESET;
1506
1507 cmdset_amd_read_jedec_ids(info);
1508 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1509
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001510 return 0;
1511}
1512
1513#ifdef CONFIG_FLASH_CFI_LEGACY
Stefan Roese260421a2006-11-13 13:55:24 +01001514static void flash_read_jedec_ids (flash_info_t * info)
1515{
1516 info->manufacturer_id = 0;
1517 info->device_id = 0;
1518 info->device_id2 = 0;
1519
1520 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001521 case CFI_CMDSET_INTEL_PROG_REGIONS:
Stefan Roese260421a2006-11-13 13:55:24 +01001522 case CFI_CMDSET_INTEL_STANDARD:
1523 case CFI_CMDSET_INTEL_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001524 cmdset_intel_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001525 break;
1526 case CFI_CMDSET_AMD_STANDARD:
1527 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001528 cmdset_amd_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001529 break;
1530 default:
1531 break;
1532 }
1533}
1534
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001535/*-----------------------------------------------------------------------
1536 * Call board code to request info about non-CFI flash.
1537 * board_flash_get_legacy needs to fill in at least:
1538 * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1539 */
1540static int flash_detect_legacy(ulong base, int banknum)
1541{
1542 flash_info_t *info = &flash_info[banknum];
1543
1544 if (board_flash_get_legacy(base, banknum, info)) {
1545 /* board code may have filled info completely. If not, we
1546 use JEDEC ID probing. */
1547 if (!info->vendor) {
1548 int modes[] = {
1549 CFI_CMDSET_AMD_STANDARD,
1550 CFI_CMDSET_INTEL_STANDARD
1551 };
1552 int i;
1553
1554 for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1555 info->vendor = modes[i];
1556 info->start[0] = base;
1557 if (info->portwidth == FLASH_CFI_8BIT
1558 && info->interface == FLASH_CFI_X8X16) {
1559 info->addr_unlock1 = 0x2AAA;
1560 info->addr_unlock2 = 0x5555;
1561 } else {
1562 info->addr_unlock1 = 0x5555;
1563 info->addr_unlock2 = 0x2AAA;
1564 }
1565 flash_read_jedec_ids(info);
1566 debug("JEDEC PROBE: ID %x %x %x\n",
1567 info->manufacturer_id,
1568 info->device_id,
1569 info->device_id2);
1570 if (jedec_flash_match(info, base))
1571 break;
1572 }
1573 }
1574
1575 switch(info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001576 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001577 case CFI_CMDSET_INTEL_STANDARD:
1578 case CFI_CMDSET_INTEL_EXTENDED:
1579 info->cmd_reset = FLASH_CMD_RESET;
1580 break;
1581 case CFI_CMDSET_AMD_STANDARD:
1582 case CFI_CMDSET_AMD_EXTENDED:
1583 case CFI_CMDSET_AMD_LEGACY:
1584 info->cmd_reset = AMD_CMD_RESET;
1585 break;
1586 }
1587 info->flash_id = FLASH_MAN_CFI;
1588 return 1;
1589 }
1590 return 0; /* use CFI */
1591}
1592#else
1593static inline int flash_detect_legacy(ulong base, int banknum)
1594{
1595 return 0; /* use CFI */
1596}
1597#endif
1598
Stefan Roese260421a2006-11-13 13:55:24 +01001599/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001600 * detect if flash is compatible with the Common Flash Interface (CFI)
1601 * http://www.jedec.org/download/search/jesd68.pdf
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001602 */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001603static void flash_read_cfi (flash_info_t *info, void *buf,
1604 unsigned int start, size_t len)
1605{
1606 u8 *p = buf;
1607 unsigned int i;
1608
1609 for (i = 0; i < len; i++)
1610 p[i] = flash_read_uchar(info, start + i);
1611}
1612
1613static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
wdenk5653fc32004-02-08 22:55:38 +00001614{
Wolfgang Denk92eb7292006-12-27 01:26:13 +01001615 int cfi_offset;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001616
Michael Schwingen1ba639d2008-02-18 23:16:35 +01001617 /* We do not yet know what kind of commandset to use, so we issue
1618 the reset command in both Intel and AMD variants, in the hope
1619 that AMD flash roms ignore the Intel command. */
1620 flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
1621 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
1622
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001623 for (cfi_offset=0;
1624 cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
1625 cfi_offset++) {
1626 flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
1627 FLASH_CMD_CFI);
1628 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1629 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1630 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001631 flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1632 sizeof(struct cfi_qry));
1633 info->interface = le16_to_cpu(qry->interface_desc);
1634
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001635 info->cfi_offset = flash_offset_cfi[cfi_offset];
1636 debug ("device interface is %d\n",
1637 info->interface);
1638 debug ("found port %d chip %d ",
1639 info->portwidth, info->chipwidth);
1640 debug ("port %d bits chip %d bits\n",
1641 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1642 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1643
1644 /* calculate command offsets as in the Linux driver */
1645 info->addr_unlock1 = 0x555;
1646 info->addr_unlock2 = 0x2aa;
1647
1648 /*
1649 * modify the unlock address if we are
1650 * in compatibility mode
1651 */
1652 if ( /* x8/x16 in x8 mode */
1653 ((info->chipwidth == FLASH_CFI_BY8) &&
1654 (info->interface == FLASH_CFI_X8X16)) ||
1655 /* x16/x32 in x16 mode */
1656 ((info->chipwidth == FLASH_CFI_BY16) &&
1657 (info->interface == FLASH_CFI_X16X32)))
1658 {
1659 info->addr_unlock1 = 0xaaa;
1660 info->addr_unlock2 = 0x555;
1661 }
1662
1663 info->name = "CFI conformant";
1664 return 1;
1665 }
1666 }
1667
1668 return 0;
1669}
1670
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001671static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001672{
wdenkbf9e3b32004-02-12 00:47:09 +00001673 debug ("flash detect cfi\n");
wdenk5653fc32004-02-08 22:55:38 +00001674
Stefan Roese79b4cda2006-02-28 15:29:58 +01001675 for (info->portwidth = CFG_FLASH_CFI_WIDTH;
wdenkbf9e3b32004-02-12 00:47:09 +00001676 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1677 for (info->chipwidth = FLASH_CFI_BY8;
1678 info->chipwidth <= info->portwidth;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001679 info->chipwidth <<= 1)
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001680 if (__flash_detect_cfi(info, qry))
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001681 return 1;
wdenk5653fc32004-02-08 22:55:38 +00001682 }
wdenkbf9e3b32004-02-12 00:47:09 +00001683 debug ("not found\n");
wdenk5653fc32004-02-08 22:55:38 +00001684 return 0;
1685}
wdenkbf9e3b32004-02-12 00:47:09 +00001686
wdenk5653fc32004-02-08 22:55:38 +00001687/*
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001688 * Manufacturer-specific quirks. Add workarounds for geometry
1689 * reversal, etc. here.
1690 */
1691static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1692{
1693 /* check if flash geometry needs reversal */
1694 if (qry->num_erase_regions > 1) {
1695 /* reverse geometry if top boot part */
1696 if (info->cfi_version < 0x3131) {
1697 /* CFI < 1.1, try to guess from device id */
1698 if ((info->device_id & 0x80) != 0)
1699 cfi_reverse_geometry(qry);
1700 } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1701 /* CFI >= 1.1, deduct from top/bottom flag */
1702 /* note: ext_addr is valid since cfi_version > 0 */
1703 cfi_reverse_geometry(qry);
1704 }
1705 }
1706}
1707
1708static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1709{
1710 int reverse_geometry = 0;
1711
1712 /* Check the "top boot" bit in the PRI */
1713 if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1714 reverse_geometry = 1;
1715
1716 /* AT49BV6416(T) list the erase regions in the wrong order.
1717 * However, the device ID is identical with the non-broken
1718 * AT49BV642D since u-boot only reads the low byte (they
1719 * differ in the high byte.) So leave out this fixup for now.
1720 */
1721#if 0
1722 if (info->device_id == 0xd6 || info->device_id == 0xd2)
1723 reverse_geometry = !reverse_geometry;
1724#endif
1725
1726 if (reverse_geometry)
1727 cfi_reverse_geometry(qry);
1728}
1729
1730/*
wdenk5653fc32004-02-08 22:55:38 +00001731 * The following code cannot be run from FLASH!
1732 *
1733 */
Marian Balakowicze6f2e902005-10-11 19:09:42 +02001734ulong flash_get_size (ulong base, int banknum)
wdenk5653fc32004-02-08 22:55:38 +00001735{
wdenkbf9e3b32004-02-12 00:47:09 +00001736 flash_info_t *info = &flash_info[banknum];
wdenk5653fc32004-02-08 22:55:38 +00001737 int i, j;
1738 flash_sect_t sect_cnt;
1739 unsigned long sector;
1740 unsigned long tmp;
1741 int size_ratio;
1742 uchar num_erase_regions;
wdenkbf9e3b32004-02-12 00:47:09 +00001743 int erase_region_size;
1744 int erase_region_count;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001745 struct cfi_qry qry;
Stefan Roese260421a2006-11-13 13:55:24 +01001746
Kumar Galaf9796902008-05-15 15:13:08 -05001747 memset(&qry, 0, sizeof(qry));
1748
Stefan Roese260421a2006-11-13 13:55:24 +01001749 info->ext_addr = 0;
1750 info->cfi_version = 0;
Stefan Roese2662b402006-04-01 13:41:03 +02001751#ifdef CFG_FLASH_PROTECTION
Stefan Roese2662b402006-04-01 13:41:03 +02001752 info->legacy_unlock = 0;
1753#endif
wdenk5653fc32004-02-08 22:55:38 +00001754
1755 info->start[0] = base;
1756
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001757 if (flash_detect_cfi (info, &qry)) {
1758 info->vendor = le16_to_cpu(qry.p_id);
1759 info->ext_addr = le16_to_cpu(qry.p_adr);
1760 num_erase_regions = qry.num_erase_regions;
1761
Stefan Roese260421a2006-11-13 13:55:24 +01001762 if (info->ext_addr) {
1763 info->cfi_version = (ushort) flash_read_uchar (info,
1764 info->ext_addr + 3) << 8;
1765 info->cfi_version |= (ushort) flash_read_uchar (info,
1766 info->ext_addr + 4);
1767 }
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001768
wdenkbf9e3b32004-02-12 00:47:09 +00001769#ifdef DEBUG
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001770 flash_printqry (&qry);
wdenkbf9e3b32004-02-12 00:47:09 +00001771#endif
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001772
wdenkbf9e3b32004-02-12 00:47:09 +00001773 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001774 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk5653fc32004-02-08 22:55:38 +00001775 case CFI_CMDSET_INTEL_STANDARD:
1776 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001777 cmdset_intel_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001778 break;
1779 case CFI_CMDSET_AMD_STANDARD:
1780 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001781 cmdset_amd_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001782 break;
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001783 default:
1784 printf("CFI: Unknown command set 0x%x\n",
1785 info->vendor);
1786 /*
1787 * Unfortunately, this means we don't know how
1788 * to get the chip back to Read mode. Might
1789 * as well try an Intel-style reset...
1790 */
1791 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1792 return 0;
wdenk5653fc32004-02-08 22:55:38 +00001793 }
wdenkcd37d9e2004-02-10 00:03:41 +00001794
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001795 /* Do manufacturer-specific fixups */
1796 switch (info->manufacturer_id) {
1797 case 0x0001:
1798 flash_fixup_amd(info, &qry);
1799 break;
1800 case 0x001f:
1801 flash_fixup_atmel(info, &qry);
1802 break;
1803 }
1804
wdenkbf9e3b32004-02-12 00:47:09 +00001805 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese260421a2006-11-13 13:55:24 +01001806 debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
1807 debug ("device id is 0x%x\n", info->device_id);
1808 debug ("device id2 is 0x%x\n", info->device_id2);
1809 debug ("cfi version is 0x%04x\n", info->cfi_version);
1810
wdenk5653fc32004-02-08 22:55:38 +00001811 size_ratio = info->portwidth / info->chipwidth;
wdenkbf9e3b32004-02-12 00:47:09 +00001812 /* if the chip is x8/x16 reduce the ratio by half */
1813 if ((info->interface == FLASH_CFI_X8X16)
1814 && (info->chipwidth == FLASH_CFI_BY8)) {
1815 size_ratio >>= 1;
1816 }
wdenkbf9e3b32004-02-12 00:47:09 +00001817 debug ("size_ratio %d port %d bits chip %d bits\n",
1818 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1819 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1820 debug ("found %d erase regions\n", num_erase_regions);
wdenk5653fc32004-02-08 22:55:38 +00001821 sect_cnt = 0;
1822 sector = base;
wdenkbf9e3b32004-02-12 00:47:09 +00001823 for (i = 0; i < num_erase_regions; i++) {
1824 if (i > NUM_ERASE_REGIONS) {
wdenk028ab6b2004-02-23 23:54:43 +00001825 printf ("%d erase regions found, only %d used\n",
1826 num_erase_regions, NUM_ERASE_REGIONS);
wdenk5653fc32004-02-08 22:55:38 +00001827 break;
1828 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001829
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001830 tmp = le32_to_cpu(qry.erase_region_info[i]);
1831 debug("erase region %u: 0x%08lx\n", i, tmp);
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001832
1833 erase_region_count = (tmp & 0xffff) + 1;
1834 tmp >>= 16;
wdenkbf9e3b32004-02-12 00:47:09 +00001835 erase_region_size =
1836 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenk4c0d4c32004-06-09 17:34:58 +00001837 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenk028ab6b2004-02-23 23:54:43 +00001838 erase_region_count, erase_region_size);
wdenkbf9e3b32004-02-12 00:47:09 +00001839 for (j = 0; j < erase_region_count; j++) {
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001840 if (sect_cnt >= CFG_MAX_FLASH_SECT) {
1841 printf("ERROR: too many flash sectors\n");
1842 break;
1843 }
wdenk5653fc32004-02-08 22:55:38 +00001844 info->start[sect_cnt] = sector;
1845 sector += (erase_region_size * size_ratio);
wdenka1191902005-01-09 17:12:27 +00001846
1847 /*
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001848 * Only read protection status from
1849 * supported devices (intel...)
wdenka1191902005-01-09 17:12:27 +00001850 */
1851 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001852 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenka1191902005-01-09 17:12:27 +00001853 case CFI_CMDSET_INTEL_EXTENDED:
1854 case CFI_CMDSET_INTEL_STANDARD:
1855 info->protect[sect_cnt] =
1856 flash_isset (info, sect_cnt,
1857 FLASH_OFFSET_PROTECT,
1858 FLASH_STATUS_PROTECT);
1859 break;
1860 default:
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001861 /* default: not protected */
1862 info->protect[sect_cnt] = 0;
wdenka1191902005-01-09 17:12:27 +00001863 }
1864
wdenk5653fc32004-02-08 22:55:38 +00001865 sect_cnt++;
1866 }
1867 }
1868
1869 info->sector_count = sect_cnt;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001870 info->size = 1 << qry.dev_size;
wdenk5653fc32004-02-08 22:55:38 +00001871 /* multiply the size by the number of chips */
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001872 info->size *= size_ratio;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001873 info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1874 tmp = 1 << qry.block_erase_timeout_typ;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001875 info->erase_blk_tout = tmp *
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001876 (1 << qry.block_erase_timeout_max);
1877 tmp = (1 << qry.buf_write_timeout_typ) *
1878 (1 << qry.buf_write_timeout_max);
1879
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001880 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001881 info->buffer_write_tout = (tmp + 999) / 1000;
1882 tmp = (1 << qry.word_write_timeout_typ) *
1883 (1 << qry.word_write_timeout_max);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001884 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001885 info->write_tout = (tmp + 999) / 1000;
wdenk5653fc32004-02-08 22:55:38 +00001886 info->flash_id = FLASH_MAN_CFI;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001887 if ((info->interface == FLASH_CFI_X8X16) &&
1888 (info->chipwidth == FLASH_CFI_BY8)) {
1889 /* XXX - Need to test on x8/x16 in parallel. */
1890 info->portwidth >>= 1;
wdenk855a4962004-03-14 18:23:55 +00001891 }
wdenk5653fc32004-02-08 22:55:38 +00001892 }
1893
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001894 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenkbf9e3b32004-02-12 00:47:09 +00001895 return (info->size);
wdenk5653fc32004-02-08 22:55:38 +00001896}
1897
wdenk5653fc32004-02-08 22:55:38 +00001898/*-----------------------------------------------------------------------
1899 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001900unsigned long flash_init (void)
wdenk5653fc32004-02-08 22:55:38 +00001901{
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001902 unsigned long size = 0;
1903 int i;
Matthias Fuchsc63ad632008-04-18 16:29:40 +02001904#if defined(CFG_FLASH_AUTOPROTECT_LIST)
1905 struct apl_s {
1906 ulong start;
1907 ulong size;
1908 } apl[] = CFG_FLASH_AUTOPROTECT_LIST;
1909#endif
wdenk5653fc32004-02-08 22:55:38 +00001910
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001911#ifdef CFG_FLASH_PROTECTION
1912 char *s = getenv("unlock");
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001913#endif
wdenk5653fc32004-02-08 22:55:38 +00001914
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001915 /* Init: no FLASHes known */
1916 for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
1917 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenk5653fc32004-02-08 22:55:38 +00001918
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001919 if (!flash_detect_legacy (bank_base[i], i))
1920 flash_get_size (bank_base[i], i);
1921 size += flash_info[i].size;
1922 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
1923#ifndef CFG_FLASH_QUIET_TEST
1924 printf ("## Unknown FLASH on Bank %d "
1925 "- Size = 0x%08lx = %ld MB\n",
1926 i+1, flash_info[i].size,
1927 flash_info[i].size << 20);
1928#endif /* CFG_FLASH_QUIET_TEST */
wdenk5653fc32004-02-08 22:55:38 +00001929 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001930#ifdef CFG_FLASH_PROTECTION
1931 else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
1932 /*
1933 * Only the U-Boot image and it's environment
1934 * is protected, all other sectors are
1935 * unprotected (unlocked) if flash hardware
1936 * protection is used (CFG_FLASH_PROTECTION)
1937 * and the environment variable "unlock" is
1938 * set to "yes".
1939 */
1940 if (flash_info[i].legacy_unlock) {
1941 int k;
Stefan Roese79b4cda2006-02-28 15:29:58 +01001942
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001943 /*
1944 * Disable legacy_unlock temporarily,
1945 * since flash_real_protect would
1946 * relock all other sectors again
1947 * otherwise.
1948 */
1949 flash_info[i].legacy_unlock = 0;
Stefan Roese79b4cda2006-02-28 15:29:58 +01001950
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001951 /*
1952 * Legacy unlocking (e.g. Intel J3) ->
1953 * unlock only one sector. This will
1954 * unlock all sectors.
1955 */
1956 flash_real_protect (&flash_info[i], 0, 0);
Stefan Roese79b4cda2006-02-28 15:29:58 +01001957
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001958 flash_info[i].legacy_unlock = 1;
1959
1960 /*
1961 * Manually mark other sectors as
1962 * unlocked (unprotected)
1963 */
1964 for (k = 1; k < flash_info[i].sector_count; k++)
1965 flash_info[i].protect[k] = 0;
1966 } else {
1967 /*
1968 * No legancy unlocking -> unlock all sectors
1969 */
1970 flash_protect (FLAG_PROTECT_CLEAR,
1971 flash_info[i].start[0],
1972 flash_info[i].start[0]
1973 + flash_info[i].size - 1,
1974 &flash_info[i]);
1975 }
Stefan Roese79b4cda2006-02-28 15:29:58 +01001976 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001977#endif /* CFG_FLASH_PROTECTION */
wdenk5653fc32004-02-08 22:55:38 +00001978 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001979
1980 /* Monitor protection ON by default */
1981#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
1982 flash_protect (FLAG_PROTECT_SET,
1983 CFG_MONITOR_BASE,
1984 CFG_MONITOR_BASE + monitor_flash_len - 1,
1985 flash_get_info(CFG_MONITOR_BASE));
1986#endif
1987
1988 /* Environment protection ON by default */
1989#ifdef CFG_ENV_IS_IN_FLASH
1990 flash_protect (FLAG_PROTECT_SET,
1991 CFG_ENV_ADDR,
1992 CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
1993 flash_get_info(CFG_ENV_ADDR));
1994#endif
1995
1996 /* Redundant environment protection ON by default */
1997#ifdef CFG_ENV_ADDR_REDUND
1998 flash_protect (FLAG_PROTECT_SET,
1999 CFG_ENV_ADDR_REDUND,
2000 CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
2001 flash_get_info(CFG_ENV_ADDR_REDUND));
2002#endif
Matthias Fuchsc63ad632008-04-18 16:29:40 +02002003
2004#if defined(CFG_FLASH_AUTOPROTECT_LIST)
2005 for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
2006 debug("autoprotecting from %08x to %08x\n",
2007 apl[i].start, apl[i].start + apl[i].size - 1);
2008 flash_protect (FLAG_PROTECT_SET,
2009 apl[i].start,
2010 apl[i].start + apl[i].size - 1,
2011 flash_get_info(apl[i].start));
2012 }
2013#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002014 return (size);
wdenk5653fc32004-02-08 22:55:38 +00002015}
Heiko Schocherca43ba12007-01-11 15:44:44 +01002016
wdenk5653fc32004-02-08 22:55:38 +00002017#endif /* CFG_FLASH_CFI */