blob: 4340b1b5c7b56c120a45eda19ba1051c80a1da30 [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;
309 uchar val;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200310 uchar *cp = (uchar *) cmdbuf;
311
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400312 for (i = info->portwidth; i > 0; i--){
313 cword_offset = (info->portwidth-i)%info->chipwidth;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200314#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400315 cp_offset = info->portwidth - i;
316 val = *((uchar*)&cmd + cword_offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200317#else
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400318 cp_offset = i - 1;
Sebastian Siewior7288f972008-07-15 13:35:23 +0200319 val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200320#endif
Sebastian Siewior7288f972008-07-15 13:35:23 +0200321 cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400322 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200323}
324
wdenkbf9e3b32004-02-12 00:47:09 +0000325#ifdef DEBUG
326/*-----------------------------------------------------------------------
327 * Debug support
328 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100329static void print_longlong (char *str, unsigned long long data)
wdenkbf9e3b32004-02-12 00:47:09 +0000330{
331 int i;
332 char *cp;
333
334 cp = (unsigned char *) &data;
335 for (i = 0; i < 8; i++)
336 sprintf (&str[i * 2], "%2.2x", *cp++);
337}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200338
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100339static void flash_printqry (struct cfi_qry *qry)
wdenkbf9e3b32004-02-12 00:47:09 +0000340{
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100341 u8 *p = (u8 *)qry;
wdenkbf9e3b32004-02-12 00:47:09 +0000342 int x, y;
343
Haavard Skinnemoene23741f2007-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(" ");
wdenkbf9e3b32004-02-12 00:47:09 +0000349 for (y = 0; y < 16; y++) {
Haavard Skinnemoene23741f2007-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(".");
wdenkbf9e3b32004-02-12 00:47:09 +0000355 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100356 debug("\n");
wdenkbf9e3b32004-02-12 00:47:09 +0000357 }
358}
wdenkbf9e3b32004-02-12 00:47:09 +0000359#endif
360
361
wdenk5653fc32004-02-08 22:55:38 +0000362/*-----------------------------------------------------------------------
363 * read a character at a port width address
364 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100365static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000366{
367 uchar *cp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100368 uchar retval;
wdenkbf9e3b32004-02-12 00:47:09 +0000369
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100370 cp = flash_map (info, 0, offset);
Heiko Schocherd0b6e142007-01-19 18:05:26 +0100371#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100372 retval = flash_read8(cp);
wdenkbf9e3b32004-02-12 00:47:09 +0000373#else
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100374 retval = flash_read8(cp + info->portwidth - 1);
wdenkbf9e3b32004-02-12 00:47:09 +0000375#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100376 flash_unmap (info, 0, offset, cp);
377 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000378}
379
380/*-----------------------------------------------------------------------
Tor Krill90447ec2008-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 Roese260421a2006-11-13 13:55:24 +0100395 * read a long word by picking the least significant byte of each maximum
wdenk5653fc32004-02-08 22:55:38 +0000396 * port size word. Swap for ppc format.
397 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100398static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
399 uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000400{
wdenkbf9e3b32004-02-12 00:47:09 +0000401 uchar *addr;
402 ulong retval;
wdenk5653fc32004-02-08 22:55:38 +0000403
wdenkbf9e3b32004-02-12 00:47:09 +0000404#ifdef DEBUG
405 int x;
406#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100407 addr = flash_map (info, sect, offset);
wdenkbf9e3b32004-02-12 00:47:09 +0000408
409#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 Skinnemoen12d30aa2007-12-13 12:56:34 +0100413 debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
wdenkbf9e3b32004-02-12 00:47:09 +0000414 }
415#endif
Heiko Schocherd0b6e142007-01-19 18:05:26 +0100416#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-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));
wdenkbf9e3b32004-02-12 00:47:09 +0000421#else
Haavard Skinnemoen12d30aa2007-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)));
wdenkbf9e3b32004-02-12 00:47:09 +0000426#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100427 flash_unmap(info, sect, offset, addr);
428
wdenkbf9e3b32004-02-12 00:47:09 +0000429 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000430}
431
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200432/*
433 * Write a proper sized command to the correct address
434 */
435static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
Sebastian Siewior7288f972008-07-15 13:35:23 +0200436 uint offset, u32 cmd)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200437{
Stefan Roese79b4cda2006-02-28 15:29:58 +0100438
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100439 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200440 cfiword_t cword;
441
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100442 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200443 flash_make_cmd (info, cmd, &cword);
444 switch (info->portwidth) {
445 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100446 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200447 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100448 flash_write8(cword.c, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200449 break;
450 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100451 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200452 cmd, cword.w,
453 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100454 flash_write16(cword.w, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200455 break;
456 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100457 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200458 cmd, cword.l,
459 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100460 flash_write32(cword.l, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200461 break;
462 case FLASH_CFI_64BIT:
463#ifdef DEBUG
464 {
465 char str[20];
466
467 print_longlong (str, cword.ll);
468
469 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100470 addr, cmd, str,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200471 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
472 }
473#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100474 flash_write64(cword.ll, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200475 break;
476 }
477
478 /* Ensure all the instructions are fully finished */
479 sync();
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100480
481 flash_unmap(info, sect, offset, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200482}
483
484static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
485{
486 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);
488}
489
490/*-----------------------------------------------------------------------
491 */
492static int flash_isequal (flash_info_t * info, flash_sect_t sect,
493 uint offset, uchar cmd)
494{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100495 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200496 cfiword_t cword;
497 int retval;
498
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100499 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200500 flash_make_cmd (info, cmd, &cword);
501
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100502 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200503 switch (info->portwidth) {
504 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100505 debug ("is= %x %x\n", flash_read8(addr), cword.c);
506 retval = (flash_read8(addr) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200507 break;
508 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-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 Skinnemoenbe60a902007-10-06 18:55:36 +0200511 break;
512 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-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 Skinnemoenbe60a902007-10-06 18:55:36 +0200515 break;
516 case FLASH_CFI_64BIT:
517#ifdef DEBUG
518 {
519 char str1[20];
520 char str2[20];
521
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100522 print_longlong (str1, flash_read64(addr));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200523 print_longlong (str2, cword.ll);
524 debug ("is= %s %s\n", str1, str2);
525 }
526#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100527 retval = (flash_read64(addr) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200528 break;
529 default:
530 retval = 0;
531 break;
532 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100533 flash_unmap(info, sect, offset, addr);
534
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200535 return retval;
536}
537
538/*-----------------------------------------------------------------------
539 */
540static int flash_isset (flash_info_t * info, flash_sect_t sect,
541 uint offset, uchar cmd)
542{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100543 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200544 cfiword_t cword;
545 int retval;
546
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100547 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200548 flash_make_cmd (info, cmd, &cword);
549 switch (info->portwidth) {
550 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100551 retval = ((flash_read8(addr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200552 break;
553 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100554 retval = ((flash_read16(addr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200555 break;
556 case FLASH_CFI_32BIT:
Stefan Roese47cc23c2008-01-02 14:05:37 +0100557 retval = ((flash_read32(addr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200558 break;
559 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100560 retval = ((flash_read64(addr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200561 break;
562 default:
563 retval = 0;
564 break;
565 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100566 flash_unmap(info, sect, offset, addr);
567
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200568 return retval;
569}
570
571/*-----------------------------------------------------------------------
572 */
573static int flash_toggle (flash_info_t * info, flash_sect_t sect,
574 uint offset, uchar cmd)
575{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100576 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200577 cfiword_t cword;
578 int retval;
579
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100580 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200581 flash_make_cmd (info, cmd, &cword);
582 switch (info->portwidth) {
583 case FLASH_CFI_8BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200584 retval = flash_read8(addr) != flash_read8(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200585 break;
586 case FLASH_CFI_16BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200587 retval = flash_read16(addr) != flash_read16(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200588 break;
589 case FLASH_CFI_32BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200590 retval = flash_read32(addr) != flash_read32(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200591 break;
592 case FLASH_CFI_64BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200593 retval = flash_read64(addr) != flash_read64(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200594 break;
595 default:
596 retval = 0;
597 break;
598 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100599 flash_unmap(info, sect, offset, addr);
600
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200601 return retval;
602}
603
604/*
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.
609 */
610static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
611{
612 int retval;
613
614 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400615 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-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:
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100622#ifdef CONFIG_FLASH_CFI_LEGACY
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200623 case CFI_CMDSET_AMD_LEGACY:
624#endif
625 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
626 break;
627 default:
628 retval = 0;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100629 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200630 debug ("flash_is_busy: %d\n", retval);
631 return retval;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100632}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200633
634/*-----------------------------------------------------------------------
635 * 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.
637 */
638static int flash_status_check (flash_info_t * info, flash_sect_t sector,
639 ulong tout, char *prompt)
640{
641 ulong start;
642
643#if CFG_HZ != 1000
644 tout *= CFG_HZ/1000;
645#endif
646
647 /* 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;
656 }
657 udelay (1); /* also triggers watchdog */
658 }
659 return ERR_OK;
660}
661
662/*-----------------------------------------------------------------------
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;
672
673 retcode = flash_status_check (info, sector, tout, prompt);
674 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400675 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-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");
693 }
694 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");
700 }
701 flash_write_cmd (info, sector, 0, info->cmd_reset);
702 break;
703 default:
704 break;
705 }
706 return retcode;
707}
708
709/*-----------------------------------------------------------------------
710 */
711static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
712{
713#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
714 unsigned short w;
715 unsigned int l;
716 unsigned long long ll;
717#endif
718
719 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;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100728#else
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200729 cword->w = (cword->w << 8) | c;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100730#endif
Haavard Skinnemoenbe60a902007-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;
Stefan Roese2662b402006-04-01 13:41:03 +0200739#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200740 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;
wdenk5653fc32004-02-08 22:55:38 +0000750 }
wdenk5653fc32004-02-08 22:55:38 +0000751}
752
Haavard Skinnemoenbe60a902007-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
wdenk5653fc32004-02-08 22:55:38 +0000755 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200756static flash_sect_t find_sector (flash_info_t * info, ulong addr)
wdenk7680c142005-05-16 15:23:22 +0000757{
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200758 flash_sect_t sector;
wdenk7680c142005-05-16 15:23:22 +0000759
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200760 for (sector = info->sector_count - 1; sector >= 0; sector--) {
761 if (addr >= info->start[sector])
wdenk7680c142005-05-16 15:23:22 +0000762 break;
763 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200764 return sector;
wdenk7680c142005-05-16 15:23:22 +0000765}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200766
767/*-----------------------------------------------------------------------
768 */
769static int flash_write_cfiword (flash_info_t * info, ulong dest,
770 cfiword_t cword)
771{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100772 void *dstaddr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200773 int flag;
774
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100775 dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200776
777 /* Check if Flash is (sufficiently) erased */
778 switch (info->portwidth) {
779 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100780 flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200781 break;
782 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100783 flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200784 break;
785 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100786 flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200787 break;
788 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100789 flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200790 break;
791 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100792 flag = 0;
793 break;
794 }
795 if (!flag) {
796 unmap_physmem(dstaddr, info->portwidth);
Stefan Roese0dc80e22007-12-27 07:50:54 +0100797 return ERR_NOT_ERASED;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200798 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200799
800 /* Disable interrupts which might cause a timeout here */
801 flag = disable_interrupts ();
802
803 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400804 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-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:
Wolfgang Denk080bdb72005-10-05 01:51:29 +0200814#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200815 flash_unlock_seq (info, 0);
816 flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
817 break;
818 }
819
820 switch (info->portwidth) {
821 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100822 flash_write8(cword.c, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200823 break;
824 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100825 flash_write16(cword.w, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200826 break;
827 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100828 flash_write32(cword.l, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200829 break;
830 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100831 flash_write64(cword.ll, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200832 break;
833 }
834
835 /* re-enable interrupts if necessary */
836 if (flag)
837 enable_interrupts ();
838
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100839 unmap_physmem(dstaddr, info->portwidth);
840
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200841 return flash_full_status_check (info, find_sector (info, dest),
842 info->write_tout, "write");
843}
844
845#ifdef CFG_FLASH_USE_BUFFER_WRITE
846
847static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
848 int len)
849{
850 flash_sect_t sector;
851 int cnt;
852 int retcode;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100853 void *src = cp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100854 void *dst = map_physmem(dest, len, MAP_NOCACHE);
Stefan Roese0dc80e22007-12-27 07:50:54 +0100855 void *dst2 = dst;
856 int flag = 0;
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200857 uint offset = 0;
858 unsigned int shift;
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400859 uchar write_cmd;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100860
Stefan Roese0dc80e22007-12-27 07:50:54 +0100861 switch (info->portwidth) {
862 case FLASH_CFI_8BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200863 shift = 0;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100864 break;
865 case FLASH_CFI_16BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200866 shift = 1;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100867 break;
868 case FLASH_CFI_32BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200869 shift = 2;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100870 break;
871 case FLASH_CFI_64BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200872 shift = 3;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100873 break;
874 default:
875 retcode = ERR_INVAL;
876 goto out_unmap;
877 }
878
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200879 cnt = len >> shift;
880
Stefan Roese0dc80e22007-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 }
909
910 src = cp;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100911 sector = find_sector (info, dest);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200912
913 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400914 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200915 case CFI_CMDSET_INTEL_STANDARD:
916 case CFI_CMDSET_INTEL_EXTENDED:
Vasiliy Leoenenko9c048b52008-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 Skinnemoenbe60a902007-10-06 18:55:36 +0200919 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
Vasiliy Leoenenko9c048b52008-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 Skinnemoenbe60a902007-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 Liakhovetski96ef8312008-04-03 13:36:02 +0200928 cnt = len >> shift;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400929 flash_write_cmd (info, sector, 0, cnt - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200930 while (cnt-- > 0) {
931 switch (info->portwidth) {
932 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100933 flash_write8(flash_read8(src), dst);
934 src += 1, dst += 1;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200935 break;
936 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100937 flash_write16(flash_read16(src), dst);
938 src += 2, dst += 2;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200939 break;
940 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100941 flash_write32(flash_read32(src), dst);
942 src += 4, dst += 4;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200943 break;
944 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100945 flash_write64(flash_read64(src), dst);
946 src += 8, dst += 8;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200947 break;
948 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100949 retcode = ERR_INVAL;
950 goto out_unmap;
Haavard Skinnemoenbe60a902007-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 Skinnemoen12d30aa2007-12-13 12:56:34 +0100959
960 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200961
962 case CFI_CMDSET_AMD_STANDARD:
963 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200964 flash_unlock_seq(info,0);
Guennadi Liakhovetski96ef8312008-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 Skinnemoenbe60a902007-10-06 18:55:36 +0200972
973 switch (info->portwidth) {
974 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100975 while (cnt-- > 0) {
976 flash_write8(flash_read8(src), dst);
977 src += 1, dst += 1;
978 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200979 break;
980 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100981 while (cnt-- > 0) {
982 flash_write16(flash_read16(src), dst);
983 src += 2, dst += 2;
984 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200985 break;
986 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100987 while (cnt-- > 0) {
988 flash_write32(flash_read32(src), dst);
989 src += 4, dst += 4;
990 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200991 break;
992 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100993 while (cnt-- > 0) {
994 flash_write64(flash_read64(src), dst);
995 src += 8, dst += 8;
996 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200997 break;
998 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100999 retcode = ERR_INVAL;
1000 goto out_unmap;
Haavard Skinnemoenbe60a902007-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 Skinnemoen12d30aa2007-12-13 12:56:34 +01001007 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001008
1009 default:
1010 debug ("Unknown Command Set\n");
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001011 retcode = ERR_INVAL;
1012 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001013 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001014
1015out_unmap:
1016 unmap_physmem(dst, len);
1017 return retcode;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001018}
1019#endif /* CFG_FLASH_USE_BUFFER_WRITE */
1020
wdenk7680c142005-05-16 15:23:22 +00001021
1022/*-----------------------------------------------------------------------
1023 */
wdenkbf9e3b32004-02-12 00:47:09 +00001024int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk5653fc32004-02-08 22:55:38 +00001025{
1026 int rcode = 0;
1027 int prot;
1028 flash_sect_t sect;
1029
wdenkbf9e3b32004-02-12 00:47:09 +00001030 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001031 puts ("Can't erase unknown flash type - aborted\n");
wdenk5653fc32004-02-08 22:55:38 +00001032 return 1;
1033 }
1034 if ((s_first < 0) || (s_first > s_last)) {
wdenk4b9206e2004-03-23 22:14:11 +00001035 puts ("- no sectors to erase\n");
wdenk5653fc32004-02-08 22:55:38 +00001036 return 1;
1037 }
1038
1039 prot = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001040 for (sect = s_first; sect <= s_last; ++sect) {
wdenk5653fc32004-02-08 22:55:38 +00001041 if (info->protect[sect]) {
1042 prot++;
1043 }
1044 }
1045 if (prot) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001046 printf ("- Warning: %d protected sectors will not be erased!\n",
1047 prot);
wdenk5653fc32004-02-08 22:55:38 +00001048 } else {
wdenk4b9206e2004-03-23 22:14:11 +00001049 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001050 }
1051
1052
wdenkbf9e3b32004-02-12 00:47:09 +00001053 for (sect = s_first; sect <= s_last; sect++) {
wdenk5653fc32004-02-08 22:55:38 +00001054 if (info->protect[sect] == 0) { /* not protected */
wdenkbf9e3b32004-02-12 00:47:09 +00001055 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001056 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk5653fc32004-02-08 22:55:38 +00001057 case CFI_CMDSET_INTEL_STANDARD:
1058 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001059 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);
wdenk5653fc32004-02-08 22:55:38 +00001065 break;
1066 case CFI_CMDSET_AMD_STANDARD:
1067 case CFI_CMDSET_AMD_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +00001068 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001069 flash_write_cmd (info, sect,
1070 info->addr_unlock1,
1071 AMD_CMD_ERASE_START);
wdenkbf9e3b32004-02-12 00:47:09 +00001072 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001073 flash_write_cmd (info, sect, 0,
1074 AMD_CMD_ERASE_SECTOR);
wdenk5653fc32004-02-08 22:55:38 +00001075 break;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001076#ifdef CONFIG_FLASH_CFI_LEGACY
1077 case CFI_CMDSET_AMD_LEGACY:
1078 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001079 flash_write_cmd (info, 0, info->addr_unlock1,
1080 AMD_CMD_ERASE_START);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001081 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001082 flash_write_cmd (info, sect, 0,
1083 AMD_CMD_ERASE_SECTOR);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001084 break;
1085#endif
wdenk5653fc32004-02-08 22:55:38 +00001086 default:
wdenkbf9e3b32004-02-12 00:47:09 +00001087 debug ("Unkown flash vendor %d\n",
1088 info->vendor);
wdenk5653fc32004-02-08 22:55:38 +00001089 break;
1090 }
1091
wdenkbf9e3b32004-02-12 00:47:09 +00001092 if (flash_full_status_check
1093 (info, sect, info->erase_blk_tout, "erase")) {
wdenk5653fc32004-02-08 22:55:38 +00001094 rcode = 1;
1095 } else
wdenk4b9206e2004-03-23 22:14:11 +00001096 putc ('.');
wdenk5653fc32004-02-08 22:55:38 +00001097 }
1098 }
wdenk4b9206e2004-03-23 22:14:11 +00001099 puts (" done\n");
wdenk5653fc32004-02-08 22:55:38 +00001100 return rcode;
1101}
1102
1103/*-----------------------------------------------------------------------
1104 */
wdenkbf9e3b32004-02-12 00:47:09 +00001105void flash_print_info (flash_info_t * info)
wdenk5653fc32004-02-08 22:55:38 +00001106{
1107 int i;
1108
1109 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001110 puts ("missing or unknown FLASH type\n");
wdenk5653fc32004-02-08 22:55:38 +00001111 return;
1112 }
1113
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001114 printf ("%s FLASH (%d x %d)",
1115 info->name,
wdenkbf9e3b32004-02-12 00:47:09 +00001116 (info->portwidth << 3), (info->chipwidth << 3));
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001117 if (info->size < 1024*1024)
1118 printf (" Size: %ld kB in %d Sectors\n",
1119 info->size >> 10, info->sector_count);
1120 else
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001121 printf (" Size: %ld MB in %d Sectors\n",
1122 info->size >> 20, info->sector_count);
Stefan Roese260421a2006-11-13 13:55:24 +01001123 printf (" ");
1124 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001125 case CFI_CMDSET_INTEL_PROG_REGIONS:
1126 printf ("Intel Prog Regions");
1127 break;
Stefan Roese260421a2006-11-13 13:55:24 +01001128 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;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001140#ifdef CONFIG_FLASH_CFI_LEGACY
1141 case CFI_CMDSET_AMD_LEGACY:
1142 printf ("AMD Legacy");
1143 break;
1144#endif
Stefan Roese260421a2006-11-13 13:55:24 +01001145 default:
1146 printf ("Unknown (%d)", info->vendor);
1147 break;
1148 }
1149 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",
wdenk028ab6b2004-02-23 23:54:43 +00001155 info->erase_blk_tout,
Stefan Roese260421a2006-11-13 13:55:24 +01001156 info->write_tout);
1157 if (info->buffer_size > 1) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001158 printf (" Buffer write timeout: %ld ms, "
1159 "buffer size: %d bytes\n",
wdenk028ab6b2004-02-23 23:54:43 +00001160 info->buffer_write_tout,
1161 info->buffer_size);
Stefan Roese260421a2006-11-13 13:55:24 +01001162 }
wdenk5653fc32004-02-08 22:55:38 +00001163
Stefan Roese260421a2006-11-13 13:55:24 +01001164 puts ("\n Sector Start Addresses:");
wdenkbf9e3b32004-02-12 00:47:09 +00001165 for (i = 0; i < info->sector_count; ++i) {
Stefan Roese260421a2006-11-13 13:55:24 +01001166 if ((i % 5) == 0)
1167 printf ("\n");
wdenk5653fc32004-02-08 22:55:38 +00001168#ifdef CFG_FLASH_EMPTY_INFO
1169 int k;
1170 int size;
1171 int erased;
1172 volatile unsigned long *flash;
1173
1174 /*
1175 * Check if whole sector is erased
1176 */
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001177 size = flash_sector_size(info, i);
wdenk5653fc32004-02-08 22:55:38 +00001178 erased = 1;
wdenkbf9e3b32004-02-12 00:47:09 +00001179 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 }
wdenk5653fc32004-02-08 22:55:38 +00001187
wdenk5653fc32004-02-08 22:55:38 +00001188 /* print empty and read-only info */
Stefan Roese260421a2006-11-13 13:55:24 +01001189 printf (" %08lX %c %s ",
wdenk5653fc32004-02-08 22:55:38 +00001190 info->start[i],
Stefan Roese260421a2006-11-13 13:55:24 +01001191 erased ? 'E' : ' ',
1192 info->protect[i] ? "RO" : " ");
Wolfgang Denkb63de2c2005-09-25 00:23:05 +02001193#else /* ! CFG_FLASH_EMPTY_INFO */
Stefan Roese260421a2006-11-13 13:55:24 +01001194 printf (" %08lX %s ",
1195 info->start[i],
1196 info->protect[i] ? "RO" : " ");
wdenk5653fc32004-02-08 22:55:38 +00001197#endif
1198 }
wdenk4b9206e2004-03-23 22:14:11 +00001199 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001200 return;
1201}
1202
1203/*-----------------------------------------------------------------------
Jerry Van Baren9a042e92008-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 Roesef0105722008-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 Baren9a042e92008-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 Roesef0105722008-03-19 07:09:26 +01001220#else
1221#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1222#endif
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001223
1224/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001225 * Copy memory to flash, returns:
1226 * 0 - OK
1227 * 1 - write timeout
1228 * 2 - Flash not erased
1229 */
wdenkbf9e3b32004-02-12 00:47:09 +00001230int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk5653fc32004-02-08 22:55:38 +00001231{
1232 ulong wp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001233 uchar *p;
wdenk5653fc32004-02-08 22:55:38 +00001234 int aln;
1235 cfiword_t cword;
1236 int i, rc;
wdenkbf9e3b32004-02-12 00:47:09 +00001237#ifdef CFG_FLASH_USE_BUFFER_WRITE
1238 int buffered_size;
1239#endif
Jerry Van Baren9a042e92008-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
wdenkbf9e3b32004-02-12 00:47:09 +00001254 /* get lower aligned address */
wdenk5653fc32004-02-08 22:55:38 +00001255 wp = (addr & ~(info->portwidth - 1));
1256
1257 /* handle unaligned start */
wdenkbf9e3b32004-02-12 00:47:09 +00001258 if ((aln = addr - wp) != 0) {
wdenk5653fc32004-02-08 22:55:38 +00001259 cword.l = 0;
Haavard Skinnemoen12d30aa2007-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));
wdenk5653fc32004-02-08 22:55:38 +00001263
wdenkbf9e3b32004-02-12 00:47:09 +00001264 for (; (i < info->portwidth) && (cnt > 0); i++) {
1265 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001266 cnt--;
wdenk5653fc32004-02-08 22:55:38 +00001267 }
Haavard Skinnemoen12d30aa2007-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)
wdenk5653fc32004-02-08 22:55:38 +00001274 return rc;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001275
1276 wp += i;
Stefan Roesef0105722008-03-19 07:09:26 +01001277 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001278 }
1279
wdenkbf9e3b32004-02-12 00:47:09 +00001280 /* handle the aligned part */
wdenk5653fc32004-02-08 22:55:38 +00001281#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenkbf9e3b32004-02-12 00:47:09 +00001282 buffered_size = (info->portwidth / info->chipwidth);
1283 buffered_size *= info->buffer_size;
1284 while (cnt >= info->portwidth) {
Stefan Roese79b4cda2006-02-28 15:29:58 +01001285 /* 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;
wdenkbf9e3b32004-02-12 00:47:09 +00001301 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
wdenk5653fc32004-02-08 22:55:38 +00001302 return rc;
Wolfgang Denk8d4ba3d2005-08-12 22:35:59 +02001303 i -= i & (info->portwidth - 1);
wdenk5653fc32004-02-08 22:55:38 +00001304 wp += i;
1305 src += i;
wdenkbf9e3b32004-02-12 00:47:09 +00001306 cnt -= i;
Stefan Roesef0105722008-03-19 07:09:26 +01001307 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001308 }
1309#else
wdenkbf9e3b32004-02-12 00:47:09 +00001310 while (cnt >= info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001311 cword.l = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001312 for (i = 0; i < info->portwidth; i++) {
1313 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001314 }
wdenkbf9e3b32004-02-12 00:47:09 +00001315 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk5653fc32004-02-08 22:55:38 +00001316 return rc;
1317 wp += info->portwidth;
1318 cnt -= info->portwidth;
Stefan Roesef0105722008-03-19 07:09:26 +01001319 FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
wdenk5653fc32004-02-08 22:55:38 +00001320 }
1321#endif /* CFG_FLASH_USE_BUFFER_WRITE */
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001322
wdenk5653fc32004-02-08 22:55:38 +00001323 if (cnt == 0) {
1324 return (0);
1325 }
1326
1327 /*
1328 * handle unaligned tail bytes
1329 */
1330 cword.l = 0;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001331 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1332 for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
wdenkbf9e3b32004-02-12 00:47:09 +00001333 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001334 --cnt;
1335 }
Haavard Skinnemoen12d30aa2007-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);
wdenk5653fc32004-02-08 22:55:38 +00001339
wdenkbf9e3b32004-02-12 00:47:09 +00001340 return flash_write_cfiword (info, wp, cword);
wdenk5653fc32004-02-08 22:55:38 +00001341}
1342
1343/*-----------------------------------------------------------------------
1344 */
1345#ifdef CFG_FLASH_PROTECTION
1346
wdenkbf9e3b32004-02-12 00:47:09 +00001347int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk5653fc32004-02-08 22:55:38 +00001348{
1349 int retcode = 0;
1350
wdenkbf9e3b32004-02-12 00:47:09 +00001351 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);
wdenk5653fc32004-02-08 22:55:38 +00001355 else
wdenkbf9e3b32004-02-12 00:47:09 +00001356 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
wdenk5653fc32004-02-08 22:55:38 +00001357
wdenkbf9e3b32004-02-12 00:47:09 +00001358 if ((retcode =
1359 flash_full_status_check (info, sector, info->erase_blk_tout,
1360 prot ? "protect" : "unprotect")) == 0) {
wdenk5653fc32004-02-08 22:55:38 +00001361
1362 info->protect[sector] = prot;
Stefan Roese2662b402006-04-01 13:41:03 +02001363
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)) {
wdenk5653fc32004-02-08 22:55:38 +00001369 flash_sect_t i;
wdenkbf9e3b32004-02-12 00:47:09 +00001370
1371 for (i = 0; i < info->sector_count; i++) {
1372 if (info->protect[i])
1373 flash_real_protect (info, i, 1);
wdenk5653fc32004-02-08 22:55:38 +00001374 }
1375 }
1376 }
wdenk5653fc32004-02-08 22:55:38 +00001377 return retcode;
wdenkbf9e3b32004-02-12 00:47:09 +00001378}
1379
wdenk5653fc32004-02-08 22:55:38 +00001380/*-----------------------------------------------------------------------
1381 * flash_read_user_serial - read the OneTimeProgramming cells
1382 */
wdenkbf9e3b32004-02-12 00:47:09 +00001383void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
1384 int len)
wdenk5653fc32004-02-08 22:55:38 +00001385{
wdenkbf9e3b32004-02-12 00:47:09 +00001386 uchar *src;
1387 uchar *dst;
wdenk5653fc32004-02-08 22:55:38 +00001388
1389 dst = buffer;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001390 src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001391 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1392 memcpy (dst, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001393 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001394 flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001395}
wdenkbf9e3b32004-02-12 00:47:09 +00001396
wdenk5653fc32004-02-08 22:55:38 +00001397/*
1398 * flash_read_factory_serial - read the device Id from the protection area
1399 */
wdenkbf9e3b32004-02-12 00:47:09 +00001400void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
1401 int len)
wdenk5653fc32004-02-08 22:55:38 +00001402{
wdenkbf9e3b32004-02-12 00:47:09 +00001403 uchar *src;
wdenkcd37d9e2004-02-10 00:03:41 +00001404
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001405 src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001406 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1407 memcpy (buffer, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001408 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001409 flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001410}
1411
1412#endif /* CFG_FLASH_PROTECTION */
1413
Haavard Skinnemoen0ddf06d2007-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}
wdenk5653fc32004-02-08 22:55:38 +00001430
1431/*-----------------------------------------------------------------------
Stefan Roese260421a2006-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 Skinnemoen0ddf06d2007-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 Krill90447ec2008-03-28 11:29:10 +01001473
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001474 info->manufacturer_id = flash_read_uchar (info,
1475 FLASH_OFFSET_MANUFACTURER_ID);
Tor Krill90447ec2008-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 Skinnemoen0ddf06d2007-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 Skinnemoen0ddf06d2007-12-14 15:36:17 +01001507 return 0;
1508}
1509
1510#ifdef CONFIG_FLASH_CFI_LEGACY
Stefan Roese260421a2006-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 Leoenenko9c048b52008-05-07 21:25:33 +04001518 case CFI_CMDSET_INTEL_PROG_REGIONS:
Stefan Roese260421a2006-11-13 13:55:24 +01001519 case CFI_CMDSET_INTEL_STANDARD:
1520 case CFI_CMDSET_INTEL_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001521 cmdset_intel_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001522 break;
1523 case CFI_CMDSET_AMD_STANDARD:
1524 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001525 cmdset_amd_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001526 break;
1527 default:
1528 break;
1529 }
1530}
1531
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001532/*-----------------------------------------------------------------------
1533 * 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.
1536 */
1537static int flash_detect_legacy(ulong base, int banknum)
1538{
1539 flash_info_t *info = &flash_info[banknum];
1540
1541 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;
1550
1551 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 Leoenenko9c048b52008-05-07 21:25:33 +04001573 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-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
Stefan Roese260421a2006-11-13 13:55:24 +01001596/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001597 * detect if flash is compatible with the Common Flash Interface (CFI)
1598 * http://www.jedec.org/download/search/jesd68.pdf
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001599 */
Haavard Skinnemoene23741f2007-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)
wdenk5653fc32004-02-08 22:55:38 +00001611{
Wolfgang Denk92eb7292006-12-27 01:26:13 +01001612 int cfi_offset;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001613
Michael Schwingen1ba639d2008-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 Skinnemoen7e5b9b42007-12-13 12:56:28 +01001620 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 Skinnemoene23741f2007-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 Skinnemoen7e5b9b42007-12-13 12:56:28 +01001632 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;
1643 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 Skinnemoene23741f2007-12-14 15:36:16 +01001668static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001669{
wdenkbf9e3b32004-02-12 00:47:09 +00001670 debug ("flash detect cfi\n");
wdenk5653fc32004-02-08 22:55:38 +00001671
Stefan Roese79b4cda2006-02-28 15:29:58 +01001672 for (info->portwidth = CFG_FLASH_CFI_WIDTH;
wdenkbf9e3b32004-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 Skinnemoen7e5b9b42007-12-13 12:56:28 +01001676 info->chipwidth <<= 1)
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001677 if (__flash_detect_cfi(info, qry))
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001678 return 1;
wdenk5653fc32004-02-08 22:55:38 +00001679 }
wdenkbf9e3b32004-02-12 00:47:09 +00001680 debug ("not found\n");
wdenk5653fc32004-02-08 22:55:38 +00001681 return 0;
1682}
wdenkbf9e3b32004-02-12 00:47:09 +00001683
wdenk5653fc32004-02-08 22:55:38 +00001684/*
Haavard Skinnemoen467bcee2007-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/*
wdenk5653fc32004-02-08 22:55:38 +00001728 * The following code cannot be run from FLASH!
1729 *
1730 */
Marian Balakowicze6f2e902005-10-11 19:09:42 +02001731ulong flash_get_size (ulong base, int banknum)
wdenk5653fc32004-02-08 22:55:38 +00001732{
wdenkbf9e3b32004-02-12 00:47:09 +00001733 flash_info_t *info = &flash_info[banknum];
wdenk5653fc32004-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;
wdenkbf9e3b32004-02-12 00:47:09 +00001740 int erase_region_size;
1741 int erase_region_count;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001742 struct cfi_qry qry;
Stefan Roese260421a2006-11-13 13:55:24 +01001743
Kumar Galaf9796902008-05-15 15:13:08 -05001744 memset(&qry, 0, sizeof(qry));
1745
Stefan Roese260421a2006-11-13 13:55:24 +01001746 info->ext_addr = 0;
1747 info->cfi_version = 0;
Stefan Roese2662b402006-04-01 13:41:03 +02001748#ifdef CFG_FLASH_PROTECTION
Stefan Roese2662b402006-04-01 13:41:03 +02001749 info->legacy_unlock = 0;
1750#endif
wdenk5653fc32004-02-08 22:55:38 +00001751
1752 info->start[0] = base;
1753
Haavard Skinnemoene23741f2007-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 Roese260421a2006-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 Skinnemoen0ddf06d2007-12-14 15:36:17 +01001765
wdenkbf9e3b32004-02-12 00:47:09 +00001766#ifdef DEBUG
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001767 flash_printqry (&qry);
wdenkbf9e3b32004-02-12 00:47:09 +00001768#endif
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001769
wdenkbf9e3b32004-02-12 00:47:09 +00001770 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001771 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk5653fc32004-02-08 22:55:38 +00001772 case CFI_CMDSET_INTEL_STANDARD:
1773 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001774 cmdset_intel_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001775 break;
1776 case CFI_CMDSET_AMD_STANDARD:
1777 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001778 cmdset_amd_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001779 break;
Haavard Skinnemoen0ddf06d2007-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;
wdenk5653fc32004-02-08 22:55:38 +00001790 }
wdenkcd37d9e2004-02-10 00:03:41 +00001791
Haavard Skinnemoen467bcee2007-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
wdenkbf9e3b32004-02-12 00:47:09 +00001802 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese260421a2006-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
wdenk5653fc32004-02-08 22:55:38 +00001808 size_ratio = info->portwidth / info->chipwidth;
wdenkbf9e3b32004-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 }
wdenkbf9e3b32004-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);
wdenk5653fc32004-02-08 22:55:38 +00001818 sect_cnt = 0;
1819 sector = base;
wdenkbf9e3b32004-02-12 00:47:09 +00001820 for (i = 0; i < num_erase_regions; i++) {
1821 if (i > NUM_ERASE_REGIONS) {
wdenk028ab6b2004-02-23 23:54:43 +00001822 printf ("%d erase regions found, only %d used\n",
1823 num_erase_regions, NUM_ERASE_REGIONS);
wdenk5653fc32004-02-08 22:55:38 +00001824 break;
1825 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001826
Haavard Skinnemoen0ddf06d2007-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 Skinnemoene23741f2007-12-14 15:36:16 +01001829
1830 erase_region_count = (tmp & 0xffff) + 1;
1831 tmp >>= 16;
wdenkbf9e3b32004-02-12 00:47:09 +00001832 erase_region_size =
1833 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenk4c0d4c32004-06-09 17:34:58 +00001834 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenk028ab6b2004-02-23 23:54:43 +00001835 erase_region_count, erase_region_size);
wdenkbf9e3b32004-02-12 00:47:09 +00001836 for (j = 0; j < erase_region_count; j++) {
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001837 if (sect_cnt >= CFG_MAX_FLASH_SECT) {
1838 printf("ERROR: too many flash sectors\n");
1839 break;
1840 }
wdenk5653fc32004-02-08 22:55:38 +00001841 info->start[sect_cnt] = sector;
1842 sector += (erase_region_size * size_ratio);
wdenka1191902005-01-09 17:12:27 +00001843
1844 /*
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001845 * Only read protection status from
1846 * supported devices (intel...)
wdenka1191902005-01-09 17:12:27 +00001847 */
1848 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001849 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenka1191902005-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 Skinnemoen7e5b9b42007-12-13 12:56:28 +01001858 /* default: not protected */
1859 info->protect[sect_cnt] = 0;
wdenka1191902005-01-09 17:12:27 +00001860 }
1861
wdenk5653fc32004-02-08 22:55:38 +00001862 sect_cnt++;
1863 }
1864 }
1865
1866 info->sector_count = sect_cnt;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001867 info->size = 1 << qry.dev_size;
wdenk5653fc32004-02-08 22:55:38 +00001868 /* multiply the size by the number of chips */
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001869 info->size *= size_ratio;
Haavard Skinnemoene23741f2007-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 Skinnemoen7e5b9b42007-12-13 12:56:28 +01001872 info->erase_blk_tout = tmp *
Haavard Skinnemoene23741f2007-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 Skinnemoen7e5b9b42007-12-13 12:56:28 +01001877 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-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 Skinnemoen7e5b9b42007-12-13 12:56:28 +01001881 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001882 info->write_tout = (tmp + 999) / 1000;
wdenk5653fc32004-02-08 22:55:38 +00001883 info->flash_id = FLASH_MAN_CFI;
Haavard Skinnemoen7e5b9b42007-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;
wdenk855a4962004-03-14 18:23:55 +00001888 }
wdenk5653fc32004-02-08 22:55:38 +00001889 }
1890
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001891 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenkbf9e3b32004-02-12 00:47:09 +00001892 return (info->size);
wdenk5653fc32004-02-08 22:55:38 +00001893}
1894
wdenk5653fc32004-02-08 22:55:38 +00001895/*-----------------------------------------------------------------------
1896 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001897unsigned long flash_init (void)
wdenk5653fc32004-02-08 22:55:38 +00001898{
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001899 unsigned long size = 0;
1900 int i;
Matthias Fuchsc63ad632008-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
wdenk5653fc32004-02-08 22:55:38 +00001907
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001908#ifdef CFG_FLASH_PROTECTION
1909 char *s = getenv("unlock");
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001910#endif
wdenk5653fc32004-02-08 22:55:38 +00001911
Haavard Skinnemoenbe60a902007-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;
wdenk5653fc32004-02-08 22:55:38 +00001915
Haavard Skinnemoenbe60a902007-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 */
wdenk5653fc32004-02-08 22:55:38 +00001926 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001927#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;
Stefan Roese79b4cda2006-02-28 15:29:58 +01001939
Haavard Skinnemoenbe60a902007-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;
Stefan Roese79b4cda2006-02-28 15:29:58 +01001947
Haavard Skinnemoenbe60a902007-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);
Stefan Roese79b4cda2006-02-28 15:29:58 +01001954
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001955 flash_info[i].legacy_unlock = 1;
1956
1957 /*
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]);
1972 }
Stefan Roese79b4cda2006-02-28 15:29:58 +01001973 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001974#endif /* CFG_FLASH_PROTECTION */
wdenk5653fc32004-02-08 22:55:38 +00001975 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001976
1977 /* 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
1984
1985 /* 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
1992
1993 /* 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 Fuchsc63ad632008-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 Skinnemoenbe60a902007-10-06 18:55:36 +02002011 return (size);
wdenk5653fc32004-02-08 22:55:38 +00002012}
Heiko Schocherca43ba12007-01-11 15:44:44 +01002013
wdenk5653fc32004-02-08 22:55:38 +00002014#endif /* CFG_FLASH_CFI */