blob: 90cb966775d489841939aaa0c0ea8bc7f5f2a37a [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
wdenkbf9e3b32004-02-12 00:47:09 +000079#define FLASH_CMD_WRITE_TO_BUFFER 0xE8
80#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0
wdenk5653fc32004-02-08 22:55:38 +000081
82#define FLASH_STATUS_DONE 0x80
83#define FLASH_STATUS_ESS 0x40
84#define FLASH_STATUS_ECLBS 0x20
85#define FLASH_STATUS_PSLBS 0x10
86#define FLASH_STATUS_VPENS 0x08
87#define FLASH_STATUS_PSS 0x04
88#define FLASH_STATUS_DPS 0x02
89#define FLASH_STATUS_R 0x01
90#define FLASH_STATUS_PROTECT 0x01
91
92#define AMD_CMD_RESET 0xF0
93#define AMD_CMD_WRITE 0xA0
94#define AMD_CMD_ERASE_START 0x80
95#define AMD_CMD_ERASE_SECTOR 0x30
wdenk855a4962004-03-14 18:23:55 +000096#define AMD_CMD_UNLOCK_START 0xAA
97#define AMD_CMD_UNLOCK_ACK 0x55
Stefan Roese79b4cda2006-02-28 15:29:58 +010098#define AMD_CMD_WRITE_TO_BUFFER 0x25
99#define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29
wdenk5653fc32004-02-08 22:55:38 +0000100
101#define AMD_STATUS_TOGGLE 0x40
102#define AMD_STATUS_ERROR 0x20
Stefan Roese79b4cda2006-02-28 15:29:58 +0100103
Stefan Roese260421a2006-11-13 13:55:24 +0100104#define FLASH_OFFSET_MANUFACTURER_ID 0x00
105#define FLASH_OFFSET_DEVICE_ID 0x01
106#define FLASH_OFFSET_DEVICE_ID2 0x0E
107#define FLASH_OFFSET_DEVICE_ID3 0x0F
wdenk5653fc32004-02-08 22:55:38 +0000108#define FLASH_OFFSET_CFI 0x55
Wolfgang Denk92eb7292006-12-27 01:26:13 +0100109#define FLASH_OFFSET_CFI_ALT 0x555
wdenk5653fc32004-02-08 22:55:38 +0000110#define FLASH_OFFSET_CFI_RESP 0x10
wdenkbf9e3b32004-02-12 00:47:09 +0000111#define FLASH_OFFSET_PRIMARY_VENDOR 0x13
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +0100112/* extended query table primary address */
113#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15
wdenk5653fc32004-02-08 22:55:38 +0000114#define FLASH_OFFSET_WTOUT 0x1F
wdenkbf9e3b32004-02-12 00:47:09 +0000115#define FLASH_OFFSET_WBTOUT 0x20
wdenk5653fc32004-02-08 22:55:38 +0000116#define FLASH_OFFSET_ETOUT 0x21
wdenkbf9e3b32004-02-12 00:47:09 +0000117#define FLASH_OFFSET_CETOUT 0x22
wdenk5653fc32004-02-08 22:55:38 +0000118#define FLASH_OFFSET_WMAX_TOUT 0x23
wdenkbf9e3b32004-02-12 00:47:09 +0000119#define FLASH_OFFSET_WBMAX_TOUT 0x24
wdenk5653fc32004-02-08 22:55:38 +0000120#define FLASH_OFFSET_EMAX_TOUT 0x25
wdenkbf9e3b32004-02-12 00:47:09 +0000121#define FLASH_OFFSET_CEMAX_TOUT 0x26
wdenk5653fc32004-02-08 22:55:38 +0000122#define FLASH_OFFSET_SIZE 0x27
wdenkbf9e3b32004-02-12 00:47:09 +0000123#define FLASH_OFFSET_INTERFACE 0x28
124#define FLASH_OFFSET_BUFFER_SIZE 0x2A
wdenk5653fc32004-02-08 22:55:38 +0000125#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C
126#define FLASH_OFFSET_ERASE_REGIONS 0x2D
127#define FLASH_OFFSET_PROTECT 0x02
wdenkbf9e3b32004-02-12 00:47:09 +0000128#define FLASH_OFFSET_USER_PROTECTION 0x85
129#define FLASH_OFFSET_INTEL_PROTECTION 0x81
wdenk5653fc32004-02-08 22:55:38 +0000130
Stefan Roese260421a2006-11-13 13:55:24 +0100131#define CFI_CMDSET_NONE 0
132#define CFI_CMDSET_INTEL_EXTENDED 1
133#define CFI_CMDSET_AMD_STANDARD 2
134#define CFI_CMDSET_INTEL_STANDARD 3
135#define CFI_CMDSET_AMD_EXTENDED 4
136#define CFI_CMDSET_MITSU_STANDARD 256
137#define CFI_CMDSET_MITSU_EXTENDED 257
138#define CFI_CMDSET_SST 258
wdenk5653fc32004-02-08 22:55:38 +0000139
wdenkf7d15722004-12-18 22:35:43 +0000140#ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
141# undef FLASH_CMD_RESET
Stefan Roese260421a2006-11-13 13:55:24 +0100142# define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */
wdenkf7d15722004-12-18 22:35:43 +0000143#endif
144
wdenk5653fc32004-02-08 22:55:38 +0000145typedef union {
146 unsigned char c;
147 unsigned short w;
148 unsigned long l;
149 unsigned long long ll;
150} cfiword_t;
151
Stefan Roese260421a2006-11-13 13:55:24 +0100152#define NUM_ERASE_REGIONS 4 /* max. number of erase regions */
wdenk5653fc32004-02-08 22:55:38 +0000153
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +0100154static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
Wolfgang Denk92eb7292006-12-27 01:26:13 +0100155
Marian Balakowicze6f2e902005-10-11 19:09:42 +0200156/* use CFG_MAX_FLASH_BANKS_DETECT if defined */
157#ifdef CFG_MAX_FLASH_BANKS_DETECT
158static ulong bank_base[CFG_MAX_FLASH_BANKS_DETECT] = CFG_FLASH_BANKS_LIST;
159flash_info_t flash_info[CFG_MAX_FLASH_BANKS_DETECT]; /* FLASH chips info */
160#else
wdenk5653fc32004-02-08 22:55:38 +0000161static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST;
Marian Balakowicze6f2e902005-10-11 19:09:42 +0200162flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */
163#endif
wdenk5653fc32004-02-08 22:55:38 +0000164
Stefan Roese79b4cda2006-02-28 15:29:58 +0100165/*
166 * Check if chip width is defined. If not, start detecting with 8bit.
167 */
168#ifndef CFG_FLASH_CFI_WIDTH
169#define CFG_FLASH_CFI_WIDTH FLASH_CFI_8BIT
170#endif
171
wdenk5653fc32004-02-08 22:55:38 +0000172typedef unsigned long flash_sect_t;
173
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100174/* CFI standard query structure */
175struct cfi_qry {
176 u8 qry[3];
177 u16 p_id;
178 u16 p_adr;
179 u16 a_id;
180 u16 a_adr;
181 u8 vcc_min;
182 u8 vcc_max;
183 u8 vpp_min;
184 u8 vpp_max;
185 u8 word_write_timeout_typ;
186 u8 buf_write_timeout_typ;
187 u8 block_erase_timeout_typ;
188 u8 chip_erase_timeout_typ;
189 u8 word_write_timeout_max;
190 u8 buf_write_timeout_max;
191 u8 block_erase_timeout_max;
192 u8 chip_erase_timeout_max;
193 u8 dev_size;
194 u16 interface_desc;
195 u16 max_buf_write_size;
196 u8 num_erase_regions;
197 u32 erase_region_info[NUM_ERASE_REGIONS];
198} __attribute__((packed));
199
200struct cfi_pri_hdr {
201 u8 pri[3];
202 u8 major_version;
203 u8 minor_version;
204} __attribute__((packed));
205
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100206static void flash_write8(u8 value, void *addr)
207{
208 __raw_writeb(value, addr);
209}
210
211static void flash_write16(u16 value, void *addr)
212{
213 __raw_writew(value, addr);
214}
215
216static void flash_write32(u32 value, void *addr)
217{
218 __raw_writel(value, addr);
219}
220
221static void flash_write64(u64 value, void *addr)
222{
223 /* No architectures currently implement __raw_writeq() */
224 *(volatile u64 *)addr = value;
225}
226
227static u8 flash_read8(void *addr)
228{
229 return __raw_readb(addr);
230}
231
232static u16 flash_read16(void *addr)
233{
234 return __raw_readw(addr);
235}
236
237static u32 flash_read32(void *addr)
238{
239 return __raw_readl(addr);
240}
241
Daniel Hellstrom97bf85d2008-03-28 20:40:19 +0100242static u64 __flash_read64(void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100243{
244 /* No architectures currently implement __raw_readq() */
245 return *(volatile u64 *)addr;
246}
247
Daniel Hellstrom97bf85d2008-03-28 20:40:19 +0100248u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
249
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200250/*-----------------------------------------------------------------------
251 */
Wolfgang Denk080bdb72005-10-05 01:51:29 +0200252#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 +0200253static flash_info_t *flash_get_info(ulong base)
254{
255 int i;
256 flash_info_t * info = 0;
257
258 for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
259 info = & flash_info[i];
260 if (info->size && info->start[0] <= base &&
261 base <= info->start[0] + info->size - 1)
262 break;
263 }
264
265 return i == CFG_MAX_FLASH_BANKS ? 0 : info;
266}
wdenk5653fc32004-02-08 22:55:38 +0000267#endif
268
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100269unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
270{
271 if (sect != (info->sector_count - 1))
272 return info->start[sect + 1] - info->start[sect];
273 else
274 return info->start[0] + info->size - info->start[sect];
275}
276
wdenk5653fc32004-02-08 22:55:38 +0000277/*-----------------------------------------------------------------------
278 * create an address based on the offset and the port width
279 */
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100280static inline void *
281flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000282{
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100283 unsigned int byte_offset = offset * info->portwidth;
284
285 return map_physmem(info->start[sect] + byte_offset,
286 flash_sector_size(info, sect) - byte_offset,
287 MAP_NOCACHE);
288}
289
290static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
291 unsigned int offset, void *addr)
292{
293 unsigned int byte_offset = offset * info->portwidth;
294
295 unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset);
wdenk5653fc32004-02-08 22:55:38 +0000296}
wdenkbf9e3b32004-02-12 00:47:09 +0000297
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200298/*-----------------------------------------------------------------------
299 * make a proper sized command based on the port and chip widths
300 */
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400301static void flash_make_cmd (flash_info_t * info, ulong cmd, void *cmdbuf)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200302{
303 int i;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400304 int cword_offset;
305 int cp_offset;
306 uchar val;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200307 uchar *cp = (uchar *) cmdbuf;
308
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400309 for (i = info->portwidth; i > 0; i--){
310 cword_offset = (info->portwidth-i)%info->chipwidth;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200311#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400312 cp_offset = info->portwidth - i;
313 val = *((uchar*)&cmd + cword_offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200314#else
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400315 cp_offset = i - 1;
316 val = *((uchar*)&cmd + sizeof(ulong) - cword_offset - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200317#endif
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400318 cp[cp_offset] = (cword_offset >= sizeof(ulong)) ? 0x00 : val;
319 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200320}
321
wdenkbf9e3b32004-02-12 00:47:09 +0000322#ifdef DEBUG
323/*-----------------------------------------------------------------------
324 * Debug support
325 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100326static void print_longlong (char *str, unsigned long long data)
wdenkbf9e3b32004-02-12 00:47:09 +0000327{
328 int i;
329 char *cp;
330
331 cp = (unsigned char *) &data;
332 for (i = 0; i < 8; i++)
333 sprintf (&str[i * 2], "%2.2x", *cp++);
334}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200335
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100336static void flash_printqry (struct cfi_qry *qry)
wdenkbf9e3b32004-02-12 00:47:09 +0000337{
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100338 u8 *p = (u8 *)qry;
wdenkbf9e3b32004-02-12 00:47:09 +0000339 int x, y;
340
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100341 for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
342 debug("%02x : ", x);
343 for (y = 0; y < 16; y++)
344 debug("%2.2x ", p[x + y]);
345 debug(" ");
wdenkbf9e3b32004-02-12 00:47:09 +0000346 for (y = 0; y < 16; y++) {
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100347 unsigned char c = p[x + y];
348 if (c >= 0x20 && c <= 0x7e)
349 debug("%c", c);
350 else
351 debug(".");
wdenkbf9e3b32004-02-12 00:47:09 +0000352 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100353 debug("\n");
wdenkbf9e3b32004-02-12 00:47:09 +0000354 }
355}
wdenkbf9e3b32004-02-12 00:47:09 +0000356#endif
357
358
wdenk5653fc32004-02-08 22:55:38 +0000359/*-----------------------------------------------------------------------
360 * read a character at a port width address
361 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100362static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000363{
364 uchar *cp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100365 uchar retval;
wdenkbf9e3b32004-02-12 00:47:09 +0000366
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100367 cp = flash_map (info, 0, offset);
Heiko Schocherd0b6e142007-01-19 18:05:26 +0100368#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100369 retval = flash_read8(cp);
wdenkbf9e3b32004-02-12 00:47:09 +0000370#else
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100371 retval = flash_read8(cp + info->portwidth - 1);
wdenkbf9e3b32004-02-12 00:47:09 +0000372#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100373 flash_unmap (info, 0, offset, cp);
374 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000375}
376
377/*-----------------------------------------------------------------------
Tor Krill90447ec2008-03-28 11:29:10 +0100378 * read a word at a port width address, assume 16bit bus
379 */
380static inline ushort flash_read_word (flash_info_t * info, uint offset)
381{
382 ushort *addr, retval;
383
384 addr = flash_map (info, 0, offset);
385 retval = flash_read16 (addr);
386 flash_unmap (info, 0, offset, addr);
387 return retval;
388}
389
390
391/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +0100392 * read a long word by picking the least significant byte of each maximum
wdenk5653fc32004-02-08 22:55:38 +0000393 * port size word. Swap for ppc format.
394 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100395static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
396 uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000397{
wdenkbf9e3b32004-02-12 00:47:09 +0000398 uchar *addr;
399 ulong retval;
wdenk5653fc32004-02-08 22:55:38 +0000400
wdenkbf9e3b32004-02-12 00:47:09 +0000401#ifdef DEBUG
402 int x;
403#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100404 addr = flash_map (info, sect, offset);
wdenkbf9e3b32004-02-12 00:47:09 +0000405
406#ifdef DEBUG
407 debug ("long addr is at %p info->portwidth = %d\n", addr,
408 info->portwidth);
409 for (x = 0; x < 4 * info->portwidth; x++) {
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100410 debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
wdenkbf9e3b32004-02-12 00:47:09 +0000411 }
412#endif
Heiko Schocherd0b6e142007-01-19 18:05:26 +0100413#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100414 retval = ((flash_read8(addr) << 16) |
415 (flash_read8(addr + info->portwidth) << 24) |
416 (flash_read8(addr + 2 * info->portwidth)) |
417 (flash_read8(addr + 3 * info->portwidth) << 8));
wdenkbf9e3b32004-02-12 00:47:09 +0000418#else
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100419 retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
420 (flash_read8(addr + info->portwidth - 1) << 16) |
421 (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
422 (flash_read8(addr + 3 * info->portwidth - 1)));
wdenkbf9e3b32004-02-12 00:47:09 +0000423#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100424 flash_unmap(info, sect, offset, addr);
425
wdenkbf9e3b32004-02-12 00:47:09 +0000426 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000427}
428
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200429/*
430 * Write a proper sized command to the correct address
431 */
432static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400433 uint offset, ulong cmd)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200434{
Stefan Roese79b4cda2006-02-28 15:29:58 +0100435
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100436 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200437 cfiword_t cword;
438
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100439 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200440 flash_make_cmd (info, cmd, &cword);
441 switch (info->portwidth) {
442 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100443 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200444 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100445 flash_write8(cword.c, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200446 break;
447 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100448 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200449 cmd, cword.w,
450 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100451 flash_write16(cword.w, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200452 break;
453 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100454 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200455 cmd, cword.l,
456 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100457 flash_write32(cword.l, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200458 break;
459 case FLASH_CFI_64BIT:
460#ifdef DEBUG
461 {
462 char str[20];
463
464 print_longlong (str, cword.ll);
465
466 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100467 addr, cmd, str,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200468 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
469 }
470#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100471 flash_write64(cword.ll, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200472 break;
473 }
474
475 /* Ensure all the instructions are fully finished */
476 sync();
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100477
478 flash_unmap(info, sect, offset, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200479}
480
481static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
482{
483 flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
484 flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
485}
486
487/*-----------------------------------------------------------------------
488 */
489static int flash_isequal (flash_info_t * info, flash_sect_t sect,
490 uint offset, uchar cmd)
491{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100492 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200493 cfiword_t cword;
494 int retval;
495
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100496 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200497 flash_make_cmd (info, cmd, &cword);
498
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100499 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200500 switch (info->portwidth) {
501 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100502 debug ("is= %x %x\n", flash_read8(addr), cword.c);
503 retval = (flash_read8(addr) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200504 break;
505 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100506 debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
507 retval = (flash_read16(addr) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200508 break;
509 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100510 debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
511 retval = (flash_read32(addr) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200512 break;
513 case FLASH_CFI_64BIT:
514#ifdef DEBUG
515 {
516 char str1[20];
517 char str2[20];
518
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100519 print_longlong (str1, flash_read64(addr));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200520 print_longlong (str2, cword.ll);
521 debug ("is= %s %s\n", str1, str2);
522 }
523#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100524 retval = (flash_read64(addr) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200525 break;
526 default:
527 retval = 0;
528 break;
529 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100530 flash_unmap(info, sect, offset, addr);
531
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200532 return retval;
533}
534
535/*-----------------------------------------------------------------------
536 */
537static int flash_isset (flash_info_t * info, flash_sect_t sect,
538 uint offset, uchar cmd)
539{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100540 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200541 cfiword_t cword;
542 int retval;
543
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100544 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200545 flash_make_cmd (info, cmd, &cword);
546 switch (info->portwidth) {
547 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100548 retval = ((flash_read8(addr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200549 break;
550 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100551 retval = ((flash_read16(addr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200552 break;
553 case FLASH_CFI_32BIT:
Stefan Roese47cc23c2008-01-02 14:05:37 +0100554 retval = ((flash_read32(addr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200555 break;
556 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100557 retval = ((flash_read64(addr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200558 break;
559 default:
560 retval = 0;
561 break;
562 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100563 flash_unmap(info, sect, offset, addr);
564
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200565 return retval;
566}
567
568/*-----------------------------------------------------------------------
569 */
570static int flash_toggle (flash_info_t * info, flash_sect_t sect,
571 uint offset, uchar cmd)
572{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100573 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200574 cfiword_t cword;
575 int retval;
576
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100577 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200578 flash_make_cmd (info, cmd, &cword);
579 switch (info->portwidth) {
580 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100581 retval = ((flash_read8(addr) & cword.c) !=
582 (flash_read8(addr) & cword.c));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200583 break;
584 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100585 retval = ((flash_read16(addr) & cword.w) !=
586 (flash_read16(addr) & cword.w));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200587 break;
588 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100589 retval = ((flash_read32(addr) & cword.l) !=
590 (flash_read32(addr) & cword.l));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200591 break;
592 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100593 retval = ((flash_read64(addr) & cword.ll) !=
594 (flash_read64(addr) & cword.ll));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200595 break;
596 default:
597 retval = 0;
598 break;
599 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100600 flash_unmap(info, sect, offset, addr);
601
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200602 return retval;
603}
604
605/*
606 * flash_is_busy - check to see if the flash is busy
607 *
608 * This routine checks the status of the chip and returns true if the
609 * chip is busy.
610 */
611static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
612{
613 int retval;
614
615 switch (info->vendor) {
616 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) {
675 case CFI_CMDSET_INTEL_EXTENDED:
676 case CFI_CMDSET_INTEL_STANDARD:
677 if ((retcode == ERR_OK)
678 && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
679 retcode = ERR_INVAL;
680 printf ("Flash %s error at address %lx\n", prompt,
681 info->start[sector]);
682 if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
683 FLASH_STATUS_PSLBS)) {
684 puts ("Command Sequence Error.\n");
685 } else if (flash_isset (info, sector, 0,
686 FLASH_STATUS_ECLBS)) {
687 puts ("Block Erase Error.\n");
688 retcode = ERR_NOT_ERASED;
689 } else if (flash_isset (info, sector, 0,
690 FLASH_STATUS_PSLBS)) {
691 puts ("Locking Error\n");
692 }
693 if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
694 puts ("Block locked.\n");
695 retcode = ERR_PROTECTED;
696 }
697 if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
698 puts ("Vpp Low Error.\n");
699 }
700 flash_write_cmd (info, sector, 0, info->cmd_reset);
701 break;
702 default:
703 break;
704 }
705 return retcode;
706}
707
708/*-----------------------------------------------------------------------
709 */
710static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
711{
712#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
713 unsigned short w;
714 unsigned int l;
715 unsigned long long ll;
716#endif
717
718 switch (info->portwidth) {
719 case FLASH_CFI_8BIT:
720 cword->c = c;
721 break;
722 case FLASH_CFI_16BIT:
723#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
724 w = c;
725 w <<= 8;
726 cword->w = (cword->w >> 8) | w;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100727#else
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200728 cword->w = (cword->w << 8) | c;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100729#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200730 break;
731 case FLASH_CFI_32BIT:
732#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
733 l = c;
734 l <<= 24;
735 cword->l = (cword->l >> 8) | l;
736#else
737 cword->l = (cword->l << 8) | c;
Stefan Roese2662b402006-04-01 13:41:03 +0200738#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200739 break;
740 case FLASH_CFI_64BIT:
741#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
742 ll = c;
743 ll <<= 56;
744 cword->ll = (cword->ll >> 8) | ll;
745#else
746 cword->ll = (cword->ll << 8) | c;
747#endif
748 break;
wdenk5653fc32004-02-08 22:55:38 +0000749 }
wdenk5653fc32004-02-08 22:55:38 +0000750}
751
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200752/* loop through the sectors from the highest address when the passed
753 * address is greater or equal to the sector address we have a match
wdenk5653fc32004-02-08 22:55:38 +0000754 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200755static flash_sect_t find_sector (flash_info_t * info, ulong addr)
wdenk7680c142005-05-16 15:23:22 +0000756{
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200757 flash_sect_t sector;
wdenk7680c142005-05-16 15:23:22 +0000758
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200759 for (sector = info->sector_count - 1; sector >= 0; sector--) {
760 if (addr >= info->start[sector])
wdenk7680c142005-05-16 15:23:22 +0000761 break;
762 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200763 return sector;
wdenk7680c142005-05-16 15:23:22 +0000764}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200765
766/*-----------------------------------------------------------------------
767 */
768static int flash_write_cfiword (flash_info_t * info, ulong dest,
769 cfiword_t cword)
770{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100771 void *dstaddr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200772 int flag;
773
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100774 dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200775
776 /* Check if Flash is (sufficiently) erased */
777 switch (info->portwidth) {
778 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100779 flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200780 break;
781 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100782 flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200783 break;
784 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100785 flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200786 break;
787 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100788 flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200789 break;
790 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100791 flag = 0;
792 break;
793 }
794 if (!flag) {
795 unmap_physmem(dstaddr, info->portwidth);
Stefan Roese0dc80e22007-12-27 07:50:54 +0100796 return ERR_NOT_ERASED;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200797 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200798
799 /* Disable interrupts which might cause a timeout here */
800 flag = disable_interrupts ();
801
802 switch (info->vendor) {
803 case CFI_CMDSET_INTEL_EXTENDED:
804 case CFI_CMDSET_INTEL_STANDARD:
805 flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
806 flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
807 break;
808 case CFI_CMDSET_AMD_EXTENDED:
809 case CFI_CMDSET_AMD_STANDARD:
810#ifdef CONFIG_FLASH_CFI_LEGACY
811 case CFI_CMDSET_AMD_LEGACY:
Wolfgang Denk080bdb72005-10-05 01:51:29 +0200812#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200813 flash_unlock_seq (info, 0);
814 flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
815 break;
816 }
817
818 switch (info->portwidth) {
819 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100820 flash_write8(cword.c, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200821 break;
822 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100823 flash_write16(cword.w, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200824 break;
825 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100826 flash_write32(cword.l, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200827 break;
828 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100829 flash_write64(cword.ll, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200830 break;
831 }
832
833 /* re-enable interrupts if necessary */
834 if (flag)
835 enable_interrupts ();
836
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100837 unmap_physmem(dstaddr, info->portwidth);
838
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200839 return flash_full_status_check (info, find_sector (info, dest),
840 info->write_tout, "write");
841}
842
843#ifdef CFG_FLASH_USE_BUFFER_WRITE
844
845static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
846 int len)
847{
848 flash_sect_t sector;
849 int cnt;
850 int retcode;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100851 void *src = cp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100852 void *dst = map_physmem(dest, len, MAP_NOCACHE);
Stefan Roese0dc80e22007-12-27 07:50:54 +0100853 void *dst2 = dst;
854 int flag = 0;
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200855 uint offset = 0;
856 unsigned int shift;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100857
Stefan Roese0dc80e22007-12-27 07:50:54 +0100858 switch (info->portwidth) {
859 case FLASH_CFI_8BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200860 shift = 0;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100861 break;
862 case FLASH_CFI_16BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200863 shift = 1;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100864 break;
865 case FLASH_CFI_32BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200866 shift = 2;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100867 break;
868 case FLASH_CFI_64BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200869 shift = 3;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100870 break;
871 default:
872 retcode = ERR_INVAL;
873 goto out_unmap;
874 }
875
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200876 cnt = len >> shift;
877
Stefan Roese0dc80e22007-12-27 07:50:54 +0100878 while ((cnt-- > 0) && (flag == 0)) {
879 switch (info->portwidth) {
880 case FLASH_CFI_8BIT:
881 flag = ((flash_read8(dst2) & flash_read8(src)) ==
882 flash_read8(src));
883 src += 1, dst2 += 1;
884 break;
885 case FLASH_CFI_16BIT:
886 flag = ((flash_read16(dst2) & flash_read16(src)) ==
887 flash_read16(src));
888 src += 2, dst2 += 2;
889 break;
890 case FLASH_CFI_32BIT:
891 flag = ((flash_read32(dst2) & flash_read32(src)) ==
892 flash_read32(src));
893 src += 4, dst2 += 4;
894 break;
895 case FLASH_CFI_64BIT:
896 flag = ((flash_read64(dst2) & flash_read64(src)) ==
897 flash_read64(src));
898 src += 8, dst2 += 8;
899 break;
900 }
901 }
902 if (!flag) {
903 retcode = ERR_NOT_ERASED;
904 goto out_unmap;
905 }
906
907 src = cp;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100908 sector = find_sector (info, dest);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200909
910 switch (info->vendor) {
911 case CFI_CMDSET_INTEL_STANDARD:
912 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200913 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
914 flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
915 retcode = flash_status_check (info, sector,
916 info->buffer_write_tout,
917 "write to buffer");
918 if (retcode == ERR_OK) {
919 /* reduce the number of loops by the width of
920 * the port */
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200921 cnt = len >> shift;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400922 flash_write_cmd (info, sector, 0, cnt - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200923 while (cnt-- > 0) {
924 switch (info->portwidth) {
925 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100926 flash_write8(flash_read8(src), dst);
927 src += 1, dst += 1;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200928 break;
929 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100930 flash_write16(flash_read16(src), dst);
931 src += 2, dst += 2;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200932 break;
933 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100934 flash_write32(flash_read32(src), dst);
935 src += 4, dst += 4;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200936 break;
937 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100938 flash_write64(flash_read64(src), dst);
939 src += 8, dst += 8;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200940 break;
941 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100942 retcode = ERR_INVAL;
943 goto out_unmap;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200944 }
945 }
946 flash_write_cmd (info, sector, 0,
947 FLASH_CMD_WRITE_BUFFER_CONFIRM);
948 retcode = flash_full_status_check (
949 info, sector, info->buffer_write_tout,
950 "buffer write");
951 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100952
953 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200954
955 case CFI_CMDSET_AMD_STANDARD:
956 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200957 flash_unlock_seq(info,0);
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200958
959#ifdef CONFIG_FLASH_SPANSION_S29WS_N
960 offset = ((unsigned long)dst - info->start[sector]) >> shift;
961#endif
962 flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
963 cnt = len >> shift;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400964 flash_write_cmd(info, sector, offset, cnt - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200965
966 switch (info->portwidth) {
967 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100968 while (cnt-- > 0) {
969 flash_write8(flash_read8(src), dst);
970 src += 1, dst += 1;
971 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200972 break;
973 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100974 while (cnt-- > 0) {
975 flash_write16(flash_read16(src), dst);
976 src += 2, dst += 2;
977 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200978 break;
979 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100980 while (cnt-- > 0) {
981 flash_write32(flash_read32(src), dst);
982 src += 4, dst += 4;
983 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200984 break;
985 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100986 while (cnt-- > 0) {
987 flash_write64(flash_read64(src), dst);
988 src += 8, dst += 8;
989 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200990 break;
991 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100992 retcode = ERR_INVAL;
993 goto out_unmap;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200994 }
995
996 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
997 retcode = flash_full_status_check (info, sector,
998 info->buffer_write_tout,
999 "buffer write");
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001000 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001001
1002 default:
1003 debug ("Unknown Command Set\n");
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001004 retcode = ERR_INVAL;
1005 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001006 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001007
1008out_unmap:
1009 unmap_physmem(dst, len);
1010 return retcode;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001011}
1012#endif /* CFG_FLASH_USE_BUFFER_WRITE */
1013
wdenk7680c142005-05-16 15:23:22 +00001014
1015/*-----------------------------------------------------------------------
1016 */
wdenkbf9e3b32004-02-12 00:47:09 +00001017int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk5653fc32004-02-08 22:55:38 +00001018{
1019 int rcode = 0;
1020 int prot;
1021 flash_sect_t sect;
1022
wdenkbf9e3b32004-02-12 00:47:09 +00001023 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001024 puts ("Can't erase unknown flash type - aborted\n");
wdenk5653fc32004-02-08 22:55:38 +00001025 return 1;
1026 }
1027 if ((s_first < 0) || (s_first > s_last)) {
wdenk4b9206e2004-03-23 22:14:11 +00001028 puts ("- no sectors to erase\n");
wdenk5653fc32004-02-08 22:55:38 +00001029 return 1;
1030 }
1031
1032 prot = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001033 for (sect = s_first; sect <= s_last; ++sect) {
wdenk5653fc32004-02-08 22:55:38 +00001034 if (info->protect[sect]) {
1035 prot++;
1036 }
1037 }
1038 if (prot) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001039 printf ("- Warning: %d protected sectors will not be erased!\n",
1040 prot);
wdenk5653fc32004-02-08 22:55:38 +00001041 } else {
wdenk4b9206e2004-03-23 22:14:11 +00001042 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001043 }
1044
1045
wdenkbf9e3b32004-02-12 00:47:09 +00001046 for (sect = s_first; sect <= s_last; sect++) {
wdenk5653fc32004-02-08 22:55:38 +00001047 if (info->protect[sect] == 0) { /* not protected */
wdenkbf9e3b32004-02-12 00:47:09 +00001048 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +00001049 case CFI_CMDSET_INTEL_STANDARD:
1050 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001051 flash_write_cmd (info, sect, 0,
1052 FLASH_CMD_CLEAR_STATUS);
1053 flash_write_cmd (info, sect, 0,
1054 FLASH_CMD_BLOCK_ERASE);
1055 flash_write_cmd (info, sect, 0,
1056 FLASH_CMD_ERASE_CONFIRM);
wdenk5653fc32004-02-08 22:55:38 +00001057 break;
1058 case CFI_CMDSET_AMD_STANDARD:
1059 case CFI_CMDSET_AMD_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +00001060 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001061 flash_write_cmd (info, sect,
1062 info->addr_unlock1,
1063 AMD_CMD_ERASE_START);
wdenkbf9e3b32004-02-12 00:47:09 +00001064 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001065 flash_write_cmd (info, sect, 0,
1066 AMD_CMD_ERASE_SECTOR);
wdenk5653fc32004-02-08 22:55:38 +00001067 break;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001068#ifdef CONFIG_FLASH_CFI_LEGACY
1069 case CFI_CMDSET_AMD_LEGACY:
1070 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001071 flash_write_cmd (info, 0, info->addr_unlock1,
1072 AMD_CMD_ERASE_START);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001073 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001074 flash_write_cmd (info, sect, 0,
1075 AMD_CMD_ERASE_SECTOR);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001076 break;
1077#endif
wdenk5653fc32004-02-08 22:55:38 +00001078 default:
wdenkbf9e3b32004-02-12 00:47:09 +00001079 debug ("Unkown flash vendor %d\n",
1080 info->vendor);
wdenk5653fc32004-02-08 22:55:38 +00001081 break;
1082 }
1083
wdenkbf9e3b32004-02-12 00:47:09 +00001084 if (flash_full_status_check
1085 (info, sect, info->erase_blk_tout, "erase")) {
wdenk5653fc32004-02-08 22:55:38 +00001086 rcode = 1;
1087 } else
wdenk4b9206e2004-03-23 22:14:11 +00001088 putc ('.');
wdenk5653fc32004-02-08 22:55:38 +00001089 }
1090 }
wdenk4b9206e2004-03-23 22:14:11 +00001091 puts (" done\n");
wdenk5653fc32004-02-08 22:55:38 +00001092 return rcode;
1093}
1094
1095/*-----------------------------------------------------------------------
1096 */
wdenkbf9e3b32004-02-12 00:47:09 +00001097void flash_print_info (flash_info_t * info)
wdenk5653fc32004-02-08 22:55:38 +00001098{
1099 int i;
1100
1101 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001102 puts ("missing or unknown FLASH type\n");
wdenk5653fc32004-02-08 22:55:38 +00001103 return;
1104 }
1105
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001106 printf ("%s FLASH (%d x %d)",
1107 info->name,
wdenkbf9e3b32004-02-12 00:47:09 +00001108 (info->portwidth << 3), (info->chipwidth << 3));
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001109 if (info->size < 1024*1024)
1110 printf (" Size: %ld kB in %d Sectors\n",
1111 info->size >> 10, info->sector_count);
1112 else
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001113 printf (" Size: %ld MB in %d Sectors\n",
1114 info->size >> 20, info->sector_count);
Stefan Roese260421a2006-11-13 13:55:24 +01001115 printf (" ");
1116 switch (info->vendor) {
1117 case CFI_CMDSET_INTEL_STANDARD:
1118 printf ("Intel Standard");
1119 break;
1120 case CFI_CMDSET_INTEL_EXTENDED:
1121 printf ("Intel Extended");
1122 break;
1123 case CFI_CMDSET_AMD_STANDARD:
1124 printf ("AMD Standard");
1125 break;
1126 case CFI_CMDSET_AMD_EXTENDED:
1127 printf ("AMD Extended");
1128 break;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001129#ifdef CONFIG_FLASH_CFI_LEGACY
1130 case CFI_CMDSET_AMD_LEGACY:
1131 printf ("AMD Legacy");
1132 break;
1133#endif
Stefan Roese260421a2006-11-13 13:55:24 +01001134 default:
1135 printf ("Unknown (%d)", info->vendor);
1136 break;
1137 }
1138 printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
1139 info->manufacturer_id, info->device_id);
1140 if (info->device_id == 0x7E) {
1141 printf("%04X", info->device_id2);
1142 }
1143 printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n",
wdenk028ab6b2004-02-23 23:54:43 +00001144 info->erase_blk_tout,
Stefan Roese260421a2006-11-13 13:55:24 +01001145 info->write_tout);
1146 if (info->buffer_size > 1) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001147 printf (" Buffer write timeout: %ld ms, "
1148 "buffer size: %d bytes\n",
wdenk028ab6b2004-02-23 23:54:43 +00001149 info->buffer_write_tout,
1150 info->buffer_size);
Stefan Roese260421a2006-11-13 13:55:24 +01001151 }
wdenk5653fc32004-02-08 22:55:38 +00001152
Stefan Roese260421a2006-11-13 13:55:24 +01001153 puts ("\n Sector Start Addresses:");
wdenkbf9e3b32004-02-12 00:47:09 +00001154 for (i = 0; i < info->sector_count; ++i) {
Stefan Roese260421a2006-11-13 13:55:24 +01001155 if ((i % 5) == 0)
1156 printf ("\n");
wdenk5653fc32004-02-08 22:55:38 +00001157#ifdef CFG_FLASH_EMPTY_INFO
1158 int k;
1159 int size;
1160 int erased;
1161 volatile unsigned long *flash;
1162
1163 /*
1164 * Check if whole sector is erased
1165 */
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001166 size = flash_sector_size(info, i);
wdenk5653fc32004-02-08 22:55:38 +00001167 erased = 1;
wdenkbf9e3b32004-02-12 00:47:09 +00001168 flash = (volatile unsigned long *) info->start[i];
1169 size = size >> 2; /* divide by 4 for longword access */
1170 for (k = 0; k < size; k++) {
1171 if (*flash++ != 0xffffffff) {
1172 erased = 0;
1173 break;
1174 }
1175 }
wdenk5653fc32004-02-08 22:55:38 +00001176
wdenk5653fc32004-02-08 22:55:38 +00001177 /* print empty and read-only info */
Stefan Roese260421a2006-11-13 13:55:24 +01001178 printf (" %08lX %c %s ",
wdenk5653fc32004-02-08 22:55:38 +00001179 info->start[i],
Stefan Roese260421a2006-11-13 13:55:24 +01001180 erased ? 'E' : ' ',
1181 info->protect[i] ? "RO" : " ");
Wolfgang Denkb63de2c2005-09-25 00:23:05 +02001182#else /* ! CFG_FLASH_EMPTY_INFO */
Stefan Roese260421a2006-11-13 13:55:24 +01001183 printf (" %08lX %s ",
1184 info->start[i],
1185 info->protect[i] ? "RO" : " ");
wdenk5653fc32004-02-08 22:55:38 +00001186#endif
1187 }
wdenk4b9206e2004-03-23 22:14:11 +00001188 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001189 return;
1190}
1191
1192/*-----------------------------------------------------------------------
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001193 * This is used in a few places in write_buf() to show programming
1194 * progress. Making it a function is nasty because it needs to do side
1195 * effect updates to digit and dots. Repeated code is nasty too, so
1196 * we define it once here.
1197 */
Stefan Roesef0105722008-03-19 07:09:26 +01001198#ifdef CONFIG_FLASH_SHOW_PROGRESS
1199#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
1200 dots -= dots_sub; \
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001201 if ((scale > 0) && (dots <= 0)) { \
1202 if ((digit % 5) == 0) \
1203 printf ("%d", digit / 5); \
1204 else \
1205 putc ('.'); \
1206 digit--; \
1207 dots += scale; \
1208 }
Stefan Roesef0105722008-03-19 07:09:26 +01001209#else
1210#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1211#endif
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001212
1213/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001214 * Copy memory to flash, returns:
1215 * 0 - OK
1216 * 1 - write timeout
1217 * 2 - Flash not erased
1218 */
wdenkbf9e3b32004-02-12 00:47:09 +00001219int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk5653fc32004-02-08 22:55:38 +00001220{
1221 ulong wp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001222 uchar *p;
wdenk5653fc32004-02-08 22:55:38 +00001223 int aln;
1224 cfiword_t cword;
1225 int i, rc;
wdenkbf9e3b32004-02-12 00:47:09 +00001226#ifdef CFG_FLASH_USE_BUFFER_WRITE
1227 int buffered_size;
1228#endif
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001229#ifdef CONFIG_FLASH_SHOW_PROGRESS
1230 int digit = CONFIG_FLASH_SHOW_PROGRESS;
1231 int scale = 0;
1232 int dots = 0;
1233
1234 /*
1235 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
1236 */
1237 if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
1238 scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
1239 CONFIG_FLASH_SHOW_PROGRESS);
1240 }
1241#endif
1242
wdenkbf9e3b32004-02-12 00:47:09 +00001243 /* get lower aligned address */
wdenk5653fc32004-02-08 22:55:38 +00001244 wp = (addr & ~(info->portwidth - 1));
1245
1246 /* handle unaligned start */
wdenkbf9e3b32004-02-12 00:47:09 +00001247 if ((aln = addr - wp) != 0) {
wdenk5653fc32004-02-08 22:55:38 +00001248 cword.l = 0;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001249 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1250 for (i = 0; i < aln; ++i)
1251 flash_add_byte (info, &cword, flash_read8(p + i));
wdenk5653fc32004-02-08 22:55:38 +00001252
wdenkbf9e3b32004-02-12 00:47:09 +00001253 for (; (i < info->portwidth) && (cnt > 0); i++) {
1254 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001255 cnt--;
wdenk5653fc32004-02-08 22:55:38 +00001256 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001257 for (; (cnt == 0) && (i < info->portwidth); ++i)
1258 flash_add_byte (info, &cword, flash_read8(p + i));
1259
1260 rc = flash_write_cfiword (info, wp, cword);
1261 unmap_physmem(p, info->portwidth);
1262 if (rc != 0)
wdenk5653fc32004-02-08 22:55:38 +00001263 return rc;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001264
1265 wp += i;
Stefan Roesef0105722008-03-19 07:09:26 +01001266 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001267 }
1268
wdenkbf9e3b32004-02-12 00:47:09 +00001269 /* handle the aligned part */
wdenk5653fc32004-02-08 22:55:38 +00001270#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenkbf9e3b32004-02-12 00:47:09 +00001271 buffered_size = (info->portwidth / info->chipwidth);
1272 buffered_size *= info->buffer_size;
1273 while (cnt >= info->portwidth) {
Stefan Roese79b4cda2006-02-28 15:29:58 +01001274 /* prohibit buffer write when buffer_size is 1 */
1275 if (info->buffer_size == 1) {
1276 cword.l = 0;
1277 for (i = 0; i < info->portwidth; i++)
1278 flash_add_byte (info, &cword, *src++);
1279 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1280 return rc;
1281 wp += info->portwidth;
1282 cnt -= info->portwidth;
1283 continue;
1284 }
1285
1286 /* write buffer until next buffered_size aligned boundary */
1287 i = buffered_size - (wp % buffered_size);
1288 if (i > cnt)
1289 i = cnt;
wdenkbf9e3b32004-02-12 00:47:09 +00001290 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
wdenk5653fc32004-02-08 22:55:38 +00001291 return rc;
Wolfgang Denk8d4ba3d2005-08-12 22:35:59 +02001292 i -= i & (info->portwidth - 1);
wdenk5653fc32004-02-08 22:55:38 +00001293 wp += i;
1294 src += i;
wdenkbf9e3b32004-02-12 00:47:09 +00001295 cnt -= i;
Stefan Roesef0105722008-03-19 07:09:26 +01001296 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001297 }
1298#else
wdenkbf9e3b32004-02-12 00:47:09 +00001299 while (cnt >= info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001300 cword.l = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001301 for (i = 0; i < info->portwidth; i++) {
1302 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001303 }
wdenkbf9e3b32004-02-12 00:47:09 +00001304 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk5653fc32004-02-08 22:55:38 +00001305 return rc;
1306 wp += info->portwidth;
1307 cnt -= info->portwidth;
Stefan Roesef0105722008-03-19 07:09:26 +01001308 FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
wdenk5653fc32004-02-08 22:55:38 +00001309 }
1310#endif /* CFG_FLASH_USE_BUFFER_WRITE */
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001311
wdenk5653fc32004-02-08 22:55:38 +00001312 if (cnt == 0) {
1313 return (0);
1314 }
1315
1316 /*
1317 * handle unaligned tail bytes
1318 */
1319 cword.l = 0;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001320 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1321 for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
wdenkbf9e3b32004-02-12 00:47:09 +00001322 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001323 --cnt;
1324 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001325 for (; i < info->portwidth; ++i)
1326 flash_add_byte (info, &cword, flash_read8(p + i));
1327 unmap_physmem(p, info->portwidth);
wdenk5653fc32004-02-08 22:55:38 +00001328
wdenkbf9e3b32004-02-12 00:47:09 +00001329 return flash_write_cfiword (info, wp, cword);
wdenk5653fc32004-02-08 22:55:38 +00001330}
1331
1332/*-----------------------------------------------------------------------
1333 */
1334#ifdef CFG_FLASH_PROTECTION
1335
wdenkbf9e3b32004-02-12 00:47:09 +00001336int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk5653fc32004-02-08 22:55:38 +00001337{
1338 int retcode = 0;
1339
wdenkbf9e3b32004-02-12 00:47:09 +00001340 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1341 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1342 if (prot)
1343 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
wdenk5653fc32004-02-08 22:55:38 +00001344 else
wdenkbf9e3b32004-02-12 00:47:09 +00001345 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
wdenk5653fc32004-02-08 22:55:38 +00001346
wdenkbf9e3b32004-02-12 00:47:09 +00001347 if ((retcode =
1348 flash_full_status_check (info, sector, info->erase_blk_tout,
1349 prot ? "protect" : "unprotect")) == 0) {
wdenk5653fc32004-02-08 22:55:38 +00001350
1351 info->protect[sector] = prot;
Stefan Roese2662b402006-04-01 13:41:03 +02001352
1353 /*
1354 * On some of Intel's flash chips (marked via legacy_unlock)
1355 * unprotect unprotects all locking.
1356 */
1357 if ((prot == 0) && (info->legacy_unlock)) {
wdenk5653fc32004-02-08 22:55:38 +00001358 flash_sect_t i;
wdenkbf9e3b32004-02-12 00:47:09 +00001359
1360 for (i = 0; i < info->sector_count; i++) {
1361 if (info->protect[i])
1362 flash_real_protect (info, i, 1);
wdenk5653fc32004-02-08 22:55:38 +00001363 }
1364 }
1365 }
wdenk5653fc32004-02-08 22:55:38 +00001366 return retcode;
wdenkbf9e3b32004-02-12 00:47:09 +00001367}
1368
wdenk5653fc32004-02-08 22:55:38 +00001369/*-----------------------------------------------------------------------
1370 * flash_read_user_serial - read the OneTimeProgramming cells
1371 */
wdenkbf9e3b32004-02-12 00:47:09 +00001372void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
1373 int len)
wdenk5653fc32004-02-08 22:55:38 +00001374{
wdenkbf9e3b32004-02-12 00:47:09 +00001375 uchar *src;
1376 uchar *dst;
wdenk5653fc32004-02-08 22:55:38 +00001377
1378 dst = buffer;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001379 src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001380 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1381 memcpy (dst, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001382 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001383 flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001384}
wdenkbf9e3b32004-02-12 00:47:09 +00001385
wdenk5653fc32004-02-08 22:55:38 +00001386/*
1387 * flash_read_factory_serial - read the device Id from the protection area
1388 */
wdenkbf9e3b32004-02-12 00:47:09 +00001389void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
1390 int len)
wdenk5653fc32004-02-08 22:55:38 +00001391{
wdenkbf9e3b32004-02-12 00:47:09 +00001392 uchar *src;
wdenkcd37d9e2004-02-10 00:03:41 +00001393
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001394 src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001395 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1396 memcpy (buffer, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001397 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001398 flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001399}
1400
1401#endif /* CFG_FLASH_PROTECTION */
1402
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001403/*-----------------------------------------------------------------------
1404 * Reverse the order of the erase regions in the CFI QRY structure.
1405 * This is needed for chips that are either a) correctly detected as
1406 * top-boot, or b) buggy.
1407 */
1408static void cfi_reverse_geometry(struct cfi_qry *qry)
1409{
1410 unsigned int i, j;
1411 u32 tmp;
1412
1413 for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
1414 tmp = qry->erase_region_info[i];
1415 qry->erase_region_info[i] = qry->erase_region_info[j];
1416 qry->erase_region_info[j] = tmp;
1417 }
1418}
wdenk5653fc32004-02-08 22:55:38 +00001419
1420/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +01001421 * read jedec ids from device and set corresponding fields in info struct
1422 *
1423 * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1424 *
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001425 */
1426static void cmdset_intel_read_jedec_ids(flash_info_t *info)
1427{
1428 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1429 flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1430 udelay(1000); /* some flash are slow to respond */
1431 info->manufacturer_id = flash_read_uchar (info,
1432 FLASH_OFFSET_MANUFACTURER_ID);
1433 info->device_id = flash_read_uchar (info,
1434 FLASH_OFFSET_DEVICE_ID);
1435 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1436}
1437
1438static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
1439{
1440 info->cmd_reset = FLASH_CMD_RESET;
1441
1442 cmdset_intel_read_jedec_ids(info);
1443 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1444
1445#ifdef CFG_FLASH_PROTECTION
1446 /* read legacy lock/unlock bit from intel flash */
1447 if (info->ext_addr) {
1448 info->legacy_unlock = flash_read_uchar (info,
1449 info->ext_addr + 5) & 0x08;
1450 }
1451#endif
1452
1453 return 0;
1454}
1455
1456static void cmdset_amd_read_jedec_ids(flash_info_t *info)
1457{
1458 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1459 flash_unlock_seq(info, 0);
1460 flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
1461 udelay(1000); /* some flash are slow to respond */
Tor Krill90447ec2008-03-28 11:29:10 +01001462
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001463 info->manufacturer_id = flash_read_uchar (info,
1464 FLASH_OFFSET_MANUFACTURER_ID);
Tor Krill90447ec2008-03-28 11:29:10 +01001465
1466 switch (info->chipwidth){
1467 case FLASH_CFI_8BIT:
1468 info->device_id = flash_read_uchar (info,
1469 FLASH_OFFSET_DEVICE_ID);
1470 if (info->device_id == 0x7E) {
1471 /* AMD 3-byte (expanded) device ids */
1472 info->device_id2 = flash_read_uchar (info,
1473 FLASH_OFFSET_DEVICE_ID2);
1474 info->device_id2 <<= 8;
1475 info->device_id2 |= flash_read_uchar (info,
1476 FLASH_OFFSET_DEVICE_ID3);
1477 }
1478 break;
1479 case FLASH_CFI_16BIT:
1480 info->device_id = flash_read_word (info,
1481 FLASH_OFFSET_DEVICE_ID);
1482 break;
1483 default:
1484 break;
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001485 }
1486 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1487}
1488
1489static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
1490{
1491 info->cmd_reset = AMD_CMD_RESET;
1492
1493 cmdset_amd_read_jedec_ids(info);
1494 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1495
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001496 return 0;
1497}
1498
1499#ifdef CONFIG_FLASH_CFI_LEGACY
Stefan Roese260421a2006-11-13 13:55:24 +01001500static void flash_read_jedec_ids (flash_info_t * info)
1501{
1502 info->manufacturer_id = 0;
1503 info->device_id = 0;
1504 info->device_id2 = 0;
1505
1506 switch (info->vendor) {
1507 case CFI_CMDSET_INTEL_STANDARD:
1508 case CFI_CMDSET_INTEL_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001509 cmdset_intel_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001510 break;
1511 case CFI_CMDSET_AMD_STANDARD:
1512 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001513 cmdset_amd_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001514 break;
1515 default:
1516 break;
1517 }
1518}
1519
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001520/*-----------------------------------------------------------------------
1521 * Call board code to request info about non-CFI flash.
1522 * board_flash_get_legacy needs to fill in at least:
1523 * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1524 */
1525static int flash_detect_legacy(ulong base, int banknum)
1526{
1527 flash_info_t *info = &flash_info[banknum];
1528
1529 if (board_flash_get_legacy(base, banknum, info)) {
1530 /* board code may have filled info completely. If not, we
1531 use JEDEC ID probing. */
1532 if (!info->vendor) {
1533 int modes[] = {
1534 CFI_CMDSET_AMD_STANDARD,
1535 CFI_CMDSET_INTEL_STANDARD
1536 };
1537 int i;
1538
1539 for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1540 info->vendor = modes[i];
1541 info->start[0] = base;
1542 if (info->portwidth == FLASH_CFI_8BIT
1543 && info->interface == FLASH_CFI_X8X16) {
1544 info->addr_unlock1 = 0x2AAA;
1545 info->addr_unlock2 = 0x5555;
1546 } else {
1547 info->addr_unlock1 = 0x5555;
1548 info->addr_unlock2 = 0x2AAA;
1549 }
1550 flash_read_jedec_ids(info);
1551 debug("JEDEC PROBE: ID %x %x %x\n",
1552 info->manufacturer_id,
1553 info->device_id,
1554 info->device_id2);
1555 if (jedec_flash_match(info, base))
1556 break;
1557 }
1558 }
1559
1560 switch(info->vendor) {
1561 case CFI_CMDSET_INTEL_STANDARD:
1562 case CFI_CMDSET_INTEL_EXTENDED:
1563 info->cmd_reset = FLASH_CMD_RESET;
1564 break;
1565 case CFI_CMDSET_AMD_STANDARD:
1566 case CFI_CMDSET_AMD_EXTENDED:
1567 case CFI_CMDSET_AMD_LEGACY:
1568 info->cmd_reset = AMD_CMD_RESET;
1569 break;
1570 }
1571 info->flash_id = FLASH_MAN_CFI;
1572 return 1;
1573 }
1574 return 0; /* use CFI */
1575}
1576#else
1577static inline int flash_detect_legacy(ulong base, int banknum)
1578{
1579 return 0; /* use CFI */
1580}
1581#endif
1582
Stefan Roese260421a2006-11-13 13:55:24 +01001583/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001584 * detect if flash is compatible with the Common Flash Interface (CFI)
1585 * http://www.jedec.org/download/search/jesd68.pdf
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001586 */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001587static void flash_read_cfi (flash_info_t *info, void *buf,
1588 unsigned int start, size_t len)
1589{
1590 u8 *p = buf;
1591 unsigned int i;
1592
1593 for (i = 0; i < len; i++)
1594 p[i] = flash_read_uchar(info, start + i);
1595}
1596
1597static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
wdenk5653fc32004-02-08 22:55:38 +00001598{
Wolfgang Denk92eb7292006-12-27 01:26:13 +01001599 int cfi_offset;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001600
Michael Schwingen1ba639d2008-02-18 23:16:35 +01001601 /* We do not yet know what kind of commandset to use, so we issue
1602 the reset command in both Intel and AMD variants, in the hope
1603 that AMD flash roms ignore the Intel command. */
1604 flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
1605 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
1606
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001607 for (cfi_offset=0;
1608 cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
1609 cfi_offset++) {
1610 flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
1611 FLASH_CMD_CFI);
1612 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1613 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1614 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001615 flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1616 sizeof(struct cfi_qry));
1617 info->interface = le16_to_cpu(qry->interface_desc);
1618
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001619 info->cfi_offset = flash_offset_cfi[cfi_offset];
1620 debug ("device interface is %d\n",
1621 info->interface);
1622 debug ("found port %d chip %d ",
1623 info->portwidth, info->chipwidth);
1624 debug ("port %d bits chip %d bits\n",
1625 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1626 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1627
1628 /* calculate command offsets as in the Linux driver */
1629 info->addr_unlock1 = 0x555;
1630 info->addr_unlock2 = 0x2aa;
1631
1632 /*
1633 * modify the unlock address if we are
1634 * in compatibility mode
1635 */
1636 if ( /* x8/x16 in x8 mode */
1637 ((info->chipwidth == FLASH_CFI_BY8) &&
1638 (info->interface == FLASH_CFI_X8X16)) ||
1639 /* x16/x32 in x16 mode */
1640 ((info->chipwidth == FLASH_CFI_BY16) &&
1641 (info->interface == FLASH_CFI_X16X32)))
1642 {
1643 info->addr_unlock1 = 0xaaa;
1644 info->addr_unlock2 = 0x555;
1645 }
1646
1647 info->name = "CFI conformant";
1648 return 1;
1649 }
1650 }
1651
1652 return 0;
1653}
1654
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001655static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001656{
wdenkbf9e3b32004-02-12 00:47:09 +00001657 debug ("flash detect cfi\n");
wdenk5653fc32004-02-08 22:55:38 +00001658
Stefan Roese79b4cda2006-02-28 15:29:58 +01001659 for (info->portwidth = CFG_FLASH_CFI_WIDTH;
wdenkbf9e3b32004-02-12 00:47:09 +00001660 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1661 for (info->chipwidth = FLASH_CFI_BY8;
1662 info->chipwidth <= info->portwidth;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001663 info->chipwidth <<= 1)
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001664 if (__flash_detect_cfi(info, qry))
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001665 return 1;
wdenk5653fc32004-02-08 22:55:38 +00001666 }
wdenkbf9e3b32004-02-12 00:47:09 +00001667 debug ("not found\n");
wdenk5653fc32004-02-08 22:55:38 +00001668 return 0;
1669}
wdenkbf9e3b32004-02-12 00:47:09 +00001670
wdenk5653fc32004-02-08 22:55:38 +00001671/*
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001672 * Manufacturer-specific quirks. Add workarounds for geometry
1673 * reversal, etc. here.
1674 */
1675static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1676{
1677 /* check if flash geometry needs reversal */
1678 if (qry->num_erase_regions > 1) {
1679 /* reverse geometry if top boot part */
1680 if (info->cfi_version < 0x3131) {
1681 /* CFI < 1.1, try to guess from device id */
1682 if ((info->device_id & 0x80) != 0)
1683 cfi_reverse_geometry(qry);
1684 } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1685 /* CFI >= 1.1, deduct from top/bottom flag */
1686 /* note: ext_addr is valid since cfi_version > 0 */
1687 cfi_reverse_geometry(qry);
1688 }
1689 }
1690}
1691
1692static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1693{
1694 int reverse_geometry = 0;
1695
1696 /* Check the "top boot" bit in the PRI */
1697 if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1698 reverse_geometry = 1;
1699
1700 /* AT49BV6416(T) list the erase regions in the wrong order.
1701 * However, the device ID is identical with the non-broken
1702 * AT49BV642D since u-boot only reads the low byte (they
1703 * differ in the high byte.) So leave out this fixup for now.
1704 */
1705#if 0
1706 if (info->device_id == 0xd6 || info->device_id == 0xd2)
1707 reverse_geometry = !reverse_geometry;
1708#endif
1709
1710 if (reverse_geometry)
1711 cfi_reverse_geometry(qry);
1712}
1713
1714/*
wdenk5653fc32004-02-08 22:55:38 +00001715 * The following code cannot be run from FLASH!
1716 *
1717 */
Marian Balakowicze6f2e902005-10-11 19:09:42 +02001718ulong flash_get_size (ulong base, int banknum)
wdenk5653fc32004-02-08 22:55:38 +00001719{
wdenkbf9e3b32004-02-12 00:47:09 +00001720 flash_info_t *info = &flash_info[banknum];
wdenk5653fc32004-02-08 22:55:38 +00001721 int i, j;
1722 flash_sect_t sect_cnt;
1723 unsigned long sector;
1724 unsigned long tmp;
1725 int size_ratio;
1726 uchar num_erase_regions;
wdenkbf9e3b32004-02-12 00:47:09 +00001727 int erase_region_size;
1728 int erase_region_count;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001729 struct cfi_qry qry;
Stefan Roese260421a2006-11-13 13:55:24 +01001730
1731 info->ext_addr = 0;
1732 info->cfi_version = 0;
Stefan Roese2662b402006-04-01 13:41:03 +02001733#ifdef CFG_FLASH_PROTECTION
Stefan Roese2662b402006-04-01 13:41:03 +02001734 info->legacy_unlock = 0;
1735#endif
wdenk5653fc32004-02-08 22:55:38 +00001736
1737 info->start[0] = base;
1738
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001739 if (flash_detect_cfi (info, &qry)) {
1740 info->vendor = le16_to_cpu(qry.p_id);
1741 info->ext_addr = le16_to_cpu(qry.p_adr);
1742 num_erase_regions = qry.num_erase_regions;
1743
Stefan Roese260421a2006-11-13 13:55:24 +01001744 if (info->ext_addr) {
1745 info->cfi_version = (ushort) flash_read_uchar (info,
1746 info->ext_addr + 3) << 8;
1747 info->cfi_version |= (ushort) flash_read_uchar (info,
1748 info->ext_addr + 4);
1749 }
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001750
wdenkbf9e3b32004-02-12 00:47:09 +00001751#ifdef DEBUG
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001752 flash_printqry (&qry);
wdenkbf9e3b32004-02-12 00:47:09 +00001753#endif
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001754
wdenkbf9e3b32004-02-12 00:47:09 +00001755 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +00001756 case CFI_CMDSET_INTEL_STANDARD:
1757 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001758 cmdset_intel_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001759 break;
1760 case CFI_CMDSET_AMD_STANDARD:
1761 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001762 cmdset_amd_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001763 break;
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001764 default:
1765 printf("CFI: Unknown command set 0x%x\n",
1766 info->vendor);
1767 /*
1768 * Unfortunately, this means we don't know how
1769 * to get the chip back to Read mode. Might
1770 * as well try an Intel-style reset...
1771 */
1772 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1773 return 0;
wdenk5653fc32004-02-08 22:55:38 +00001774 }
wdenkcd37d9e2004-02-10 00:03:41 +00001775
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001776 /* Do manufacturer-specific fixups */
1777 switch (info->manufacturer_id) {
1778 case 0x0001:
1779 flash_fixup_amd(info, &qry);
1780 break;
1781 case 0x001f:
1782 flash_fixup_atmel(info, &qry);
1783 break;
1784 }
1785
wdenkbf9e3b32004-02-12 00:47:09 +00001786 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese260421a2006-11-13 13:55:24 +01001787 debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
1788 debug ("device id is 0x%x\n", info->device_id);
1789 debug ("device id2 is 0x%x\n", info->device_id2);
1790 debug ("cfi version is 0x%04x\n", info->cfi_version);
1791
wdenk5653fc32004-02-08 22:55:38 +00001792 size_ratio = info->portwidth / info->chipwidth;
wdenkbf9e3b32004-02-12 00:47:09 +00001793 /* if the chip is x8/x16 reduce the ratio by half */
1794 if ((info->interface == FLASH_CFI_X8X16)
1795 && (info->chipwidth == FLASH_CFI_BY8)) {
1796 size_ratio >>= 1;
1797 }
wdenkbf9e3b32004-02-12 00:47:09 +00001798 debug ("size_ratio %d port %d bits chip %d bits\n",
1799 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1800 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1801 debug ("found %d erase regions\n", num_erase_regions);
wdenk5653fc32004-02-08 22:55:38 +00001802 sect_cnt = 0;
1803 sector = base;
wdenkbf9e3b32004-02-12 00:47:09 +00001804 for (i = 0; i < num_erase_regions; i++) {
1805 if (i > NUM_ERASE_REGIONS) {
wdenk028ab6b2004-02-23 23:54:43 +00001806 printf ("%d erase regions found, only %d used\n",
1807 num_erase_regions, NUM_ERASE_REGIONS);
wdenk5653fc32004-02-08 22:55:38 +00001808 break;
1809 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001810
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001811 tmp = le32_to_cpu(qry.erase_region_info[i]);
1812 debug("erase region %u: 0x%08lx\n", i, tmp);
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001813
1814 erase_region_count = (tmp & 0xffff) + 1;
1815 tmp >>= 16;
wdenkbf9e3b32004-02-12 00:47:09 +00001816 erase_region_size =
1817 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenk4c0d4c32004-06-09 17:34:58 +00001818 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenk028ab6b2004-02-23 23:54:43 +00001819 erase_region_count, erase_region_size);
wdenkbf9e3b32004-02-12 00:47:09 +00001820 for (j = 0; j < erase_region_count; j++) {
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001821 if (sect_cnt >= CFG_MAX_FLASH_SECT) {
1822 printf("ERROR: too many flash sectors\n");
1823 break;
1824 }
wdenk5653fc32004-02-08 22:55:38 +00001825 info->start[sect_cnt] = sector;
1826 sector += (erase_region_size * size_ratio);
wdenka1191902005-01-09 17:12:27 +00001827
1828 /*
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001829 * Only read protection status from
1830 * supported devices (intel...)
wdenka1191902005-01-09 17:12:27 +00001831 */
1832 switch (info->vendor) {
1833 case CFI_CMDSET_INTEL_EXTENDED:
1834 case CFI_CMDSET_INTEL_STANDARD:
1835 info->protect[sect_cnt] =
1836 flash_isset (info, sect_cnt,
1837 FLASH_OFFSET_PROTECT,
1838 FLASH_STATUS_PROTECT);
1839 break;
1840 default:
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001841 /* default: not protected */
1842 info->protect[sect_cnt] = 0;
wdenka1191902005-01-09 17:12:27 +00001843 }
1844
wdenk5653fc32004-02-08 22:55:38 +00001845 sect_cnt++;
1846 }
1847 }
1848
1849 info->sector_count = sect_cnt;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001850 info->size = 1 << qry.dev_size;
wdenk5653fc32004-02-08 22:55:38 +00001851 /* multiply the size by the number of chips */
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001852 info->size *= size_ratio;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001853 info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1854 tmp = 1 << qry.block_erase_timeout_typ;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001855 info->erase_blk_tout = tmp *
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001856 (1 << qry.block_erase_timeout_max);
1857 tmp = (1 << qry.buf_write_timeout_typ) *
1858 (1 << qry.buf_write_timeout_max);
1859
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001860 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001861 info->buffer_write_tout = (tmp + 999) / 1000;
1862 tmp = (1 << qry.word_write_timeout_typ) *
1863 (1 << qry.word_write_timeout_max);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001864 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001865 info->write_tout = (tmp + 999) / 1000;
wdenk5653fc32004-02-08 22:55:38 +00001866 info->flash_id = FLASH_MAN_CFI;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001867 if ((info->interface == FLASH_CFI_X8X16) &&
1868 (info->chipwidth == FLASH_CFI_BY8)) {
1869 /* XXX - Need to test on x8/x16 in parallel. */
1870 info->portwidth >>= 1;
wdenk855a4962004-03-14 18:23:55 +00001871 }
wdenk5653fc32004-02-08 22:55:38 +00001872 }
1873
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001874 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenkbf9e3b32004-02-12 00:47:09 +00001875 return (info->size);
wdenk5653fc32004-02-08 22:55:38 +00001876}
1877
wdenk5653fc32004-02-08 22:55:38 +00001878/*-----------------------------------------------------------------------
1879 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001880unsigned long flash_init (void)
wdenk5653fc32004-02-08 22:55:38 +00001881{
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001882 unsigned long size = 0;
1883 int i;
Matthias Fuchsc63ad632008-04-18 16:29:40 +02001884#if defined(CFG_FLASH_AUTOPROTECT_LIST)
1885 struct apl_s {
1886 ulong start;
1887 ulong size;
1888 } apl[] = CFG_FLASH_AUTOPROTECT_LIST;
1889#endif
wdenk5653fc32004-02-08 22:55:38 +00001890
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001891#ifdef CFG_FLASH_PROTECTION
1892 char *s = getenv("unlock");
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001893#endif
wdenk5653fc32004-02-08 22:55:38 +00001894
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001895 /* Init: no FLASHes known */
1896 for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
1897 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenk5653fc32004-02-08 22:55:38 +00001898
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001899 if (!flash_detect_legacy (bank_base[i], i))
1900 flash_get_size (bank_base[i], i);
1901 size += flash_info[i].size;
1902 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
1903#ifndef CFG_FLASH_QUIET_TEST
1904 printf ("## Unknown FLASH on Bank %d "
1905 "- Size = 0x%08lx = %ld MB\n",
1906 i+1, flash_info[i].size,
1907 flash_info[i].size << 20);
1908#endif /* CFG_FLASH_QUIET_TEST */
wdenk5653fc32004-02-08 22:55:38 +00001909 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001910#ifdef CFG_FLASH_PROTECTION
1911 else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
1912 /*
1913 * Only the U-Boot image and it's environment
1914 * is protected, all other sectors are
1915 * unprotected (unlocked) if flash hardware
1916 * protection is used (CFG_FLASH_PROTECTION)
1917 * and the environment variable "unlock" is
1918 * set to "yes".
1919 */
1920 if (flash_info[i].legacy_unlock) {
1921 int k;
Stefan Roese79b4cda2006-02-28 15:29:58 +01001922
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001923 /*
1924 * Disable legacy_unlock temporarily,
1925 * since flash_real_protect would
1926 * relock all other sectors again
1927 * otherwise.
1928 */
1929 flash_info[i].legacy_unlock = 0;
Stefan Roese79b4cda2006-02-28 15:29:58 +01001930
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001931 /*
1932 * Legacy unlocking (e.g. Intel J3) ->
1933 * unlock only one sector. This will
1934 * unlock all sectors.
1935 */
1936 flash_real_protect (&flash_info[i], 0, 0);
Stefan Roese79b4cda2006-02-28 15:29:58 +01001937
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001938 flash_info[i].legacy_unlock = 1;
1939
1940 /*
1941 * Manually mark other sectors as
1942 * unlocked (unprotected)
1943 */
1944 for (k = 1; k < flash_info[i].sector_count; k++)
1945 flash_info[i].protect[k] = 0;
1946 } else {
1947 /*
1948 * No legancy unlocking -> unlock all sectors
1949 */
1950 flash_protect (FLAG_PROTECT_CLEAR,
1951 flash_info[i].start[0],
1952 flash_info[i].start[0]
1953 + flash_info[i].size - 1,
1954 &flash_info[i]);
1955 }
Stefan Roese79b4cda2006-02-28 15:29:58 +01001956 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001957#endif /* CFG_FLASH_PROTECTION */
wdenk5653fc32004-02-08 22:55:38 +00001958 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001959
1960 /* Monitor protection ON by default */
1961#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
1962 flash_protect (FLAG_PROTECT_SET,
1963 CFG_MONITOR_BASE,
1964 CFG_MONITOR_BASE + monitor_flash_len - 1,
1965 flash_get_info(CFG_MONITOR_BASE));
1966#endif
1967
1968 /* Environment protection ON by default */
1969#ifdef CFG_ENV_IS_IN_FLASH
1970 flash_protect (FLAG_PROTECT_SET,
1971 CFG_ENV_ADDR,
1972 CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
1973 flash_get_info(CFG_ENV_ADDR));
1974#endif
1975
1976 /* Redundant environment protection ON by default */
1977#ifdef CFG_ENV_ADDR_REDUND
1978 flash_protect (FLAG_PROTECT_SET,
1979 CFG_ENV_ADDR_REDUND,
1980 CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
1981 flash_get_info(CFG_ENV_ADDR_REDUND));
1982#endif
Matthias Fuchsc63ad632008-04-18 16:29:40 +02001983
1984#if defined(CFG_FLASH_AUTOPROTECT_LIST)
1985 for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
1986 debug("autoprotecting from %08x to %08x\n",
1987 apl[i].start, apl[i].start + apl[i].size - 1);
1988 flash_protect (FLAG_PROTECT_SET,
1989 apl[i].start,
1990 apl[i].start + apl[i].size - 1,
1991 flash_get_info(apl[i].start));
1992 }
1993#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001994 return (size);
wdenk5653fc32004-02-08 22:55:38 +00001995}
Heiko Schocherca43ba12007-01-11 15:44:44 +01001996
wdenk5653fc32004-02-08 22:55:38 +00001997#endif /* CFG_FLASH_CFI */