blob: 40fddcddad5aa0b9edd3b270da059b87e9eba085 [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 */
301static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
302{
303 int i;
304 uchar *cp = (uchar *) cmdbuf;
305
306#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
307 for (i = info->portwidth; i > 0; i--)
308#else
309 for (i = 1; i <= info->portwidth; i++)
310#endif
311 *cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;
312}
313
wdenkbf9e3b32004-02-12 00:47:09 +0000314#ifdef DEBUG
315/*-----------------------------------------------------------------------
316 * Debug support
317 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100318static void print_longlong (char *str, unsigned long long data)
wdenkbf9e3b32004-02-12 00:47:09 +0000319{
320 int i;
321 char *cp;
322
323 cp = (unsigned char *) &data;
324 for (i = 0; i < 8; i++)
325 sprintf (&str[i * 2], "%2.2x", *cp++);
326}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200327
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100328static void flash_printqry (struct cfi_qry *qry)
wdenkbf9e3b32004-02-12 00:47:09 +0000329{
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100330 u8 *p = (u8 *)qry;
wdenkbf9e3b32004-02-12 00:47:09 +0000331 int x, y;
332
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100333 for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
334 debug("%02x : ", x);
335 for (y = 0; y < 16; y++)
336 debug("%2.2x ", p[x + y]);
337 debug(" ");
wdenkbf9e3b32004-02-12 00:47:09 +0000338 for (y = 0; y < 16; y++) {
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100339 unsigned char c = p[x + y];
340 if (c >= 0x20 && c <= 0x7e)
341 debug("%c", c);
342 else
343 debug(".");
wdenkbf9e3b32004-02-12 00:47:09 +0000344 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100345 debug("\n");
wdenkbf9e3b32004-02-12 00:47:09 +0000346 }
347}
wdenkbf9e3b32004-02-12 00:47:09 +0000348#endif
349
350
wdenk5653fc32004-02-08 22:55:38 +0000351/*-----------------------------------------------------------------------
352 * read a character at a port width address
353 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100354static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000355{
356 uchar *cp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100357 uchar retval;
wdenkbf9e3b32004-02-12 00:47:09 +0000358
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100359 cp = flash_map (info, 0, offset);
Heiko Schocherd0b6e142007-01-19 18:05:26 +0100360#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100361 retval = flash_read8(cp);
wdenkbf9e3b32004-02-12 00:47:09 +0000362#else
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100363 retval = flash_read8(cp + info->portwidth - 1);
wdenkbf9e3b32004-02-12 00:47:09 +0000364#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100365 flash_unmap (info, 0, offset, cp);
366 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000367}
368
369/*-----------------------------------------------------------------------
Tor Krill90447ec2008-03-28 11:29:10 +0100370 * read a word at a port width address, assume 16bit bus
371 */
372static inline ushort flash_read_word (flash_info_t * info, uint offset)
373{
374 ushort *addr, retval;
375
376 addr = flash_map (info, 0, offset);
377 retval = flash_read16 (addr);
378 flash_unmap (info, 0, offset, addr);
379 return retval;
380}
381
382
383/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +0100384 * read a long word by picking the least significant byte of each maximum
wdenk5653fc32004-02-08 22:55:38 +0000385 * port size word. Swap for ppc format.
386 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100387static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
388 uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000389{
wdenkbf9e3b32004-02-12 00:47:09 +0000390 uchar *addr;
391 ulong retval;
wdenk5653fc32004-02-08 22:55:38 +0000392
wdenkbf9e3b32004-02-12 00:47:09 +0000393#ifdef DEBUG
394 int x;
395#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100396 addr = flash_map (info, sect, offset);
wdenkbf9e3b32004-02-12 00:47:09 +0000397
398#ifdef DEBUG
399 debug ("long addr is at %p info->portwidth = %d\n", addr,
400 info->portwidth);
401 for (x = 0; x < 4 * info->portwidth; x++) {
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100402 debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
wdenkbf9e3b32004-02-12 00:47:09 +0000403 }
404#endif
Heiko Schocherd0b6e142007-01-19 18:05:26 +0100405#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100406 retval = ((flash_read8(addr) << 16) |
407 (flash_read8(addr + info->portwidth) << 24) |
408 (flash_read8(addr + 2 * info->portwidth)) |
409 (flash_read8(addr + 3 * info->portwidth) << 8));
wdenkbf9e3b32004-02-12 00:47:09 +0000410#else
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100411 retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
412 (flash_read8(addr + info->portwidth - 1) << 16) |
413 (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
414 (flash_read8(addr + 3 * info->portwidth - 1)));
wdenkbf9e3b32004-02-12 00:47:09 +0000415#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100416 flash_unmap(info, sect, offset, addr);
417
wdenkbf9e3b32004-02-12 00:47:09 +0000418 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000419}
420
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200421/*
422 * Write a proper sized command to the correct address
423 */
424static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
425 uint offset, uchar cmd)
426{
Stefan Roese79b4cda2006-02-28 15:29:58 +0100427
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100428 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200429 cfiword_t cword;
430
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100431 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200432 flash_make_cmd (info, cmd, &cword);
433 switch (info->portwidth) {
434 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100435 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200436 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100437 flash_write8(cword.c, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200438 break;
439 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100440 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200441 cmd, cword.w,
442 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100443 flash_write16(cword.w, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200444 break;
445 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100446 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200447 cmd, cword.l,
448 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100449 flash_write32(cword.l, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200450 break;
451 case FLASH_CFI_64BIT:
452#ifdef DEBUG
453 {
454 char str[20];
455
456 print_longlong (str, cword.ll);
457
458 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100459 addr, cmd, str,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200460 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
461 }
462#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100463 flash_write64(cword.ll, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200464 break;
465 }
466
467 /* Ensure all the instructions are fully finished */
468 sync();
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100469
470 flash_unmap(info, sect, offset, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200471}
472
473static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
474{
475 flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
476 flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
477}
478
479/*-----------------------------------------------------------------------
480 */
481static int flash_isequal (flash_info_t * info, flash_sect_t sect,
482 uint offset, uchar cmd)
483{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100484 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200485 cfiword_t cword;
486 int retval;
487
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100488 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200489 flash_make_cmd (info, cmd, &cword);
490
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100491 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200492 switch (info->portwidth) {
493 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100494 debug ("is= %x %x\n", flash_read8(addr), cword.c);
495 retval = (flash_read8(addr) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200496 break;
497 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100498 debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
499 retval = (flash_read16(addr) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200500 break;
501 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100502 debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
503 retval = (flash_read32(addr) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200504 break;
505 case FLASH_CFI_64BIT:
506#ifdef DEBUG
507 {
508 char str1[20];
509 char str2[20];
510
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100511 print_longlong (str1, flash_read64(addr));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200512 print_longlong (str2, cword.ll);
513 debug ("is= %s %s\n", str1, str2);
514 }
515#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100516 retval = (flash_read64(addr) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200517 break;
518 default:
519 retval = 0;
520 break;
521 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100522 flash_unmap(info, sect, offset, addr);
523
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200524 return retval;
525}
526
527/*-----------------------------------------------------------------------
528 */
529static int flash_isset (flash_info_t * info, flash_sect_t sect,
530 uint offset, uchar cmd)
531{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100532 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200533 cfiword_t cword;
534 int retval;
535
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100536 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200537 flash_make_cmd (info, cmd, &cword);
538 switch (info->portwidth) {
539 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100540 retval = ((flash_read8(addr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200541 break;
542 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100543 retval = ((flash_read16(addr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200544 break;
545 case FLASH_CFI_32BIT:
Stefan Roese47cc23c2008-01-02 14:05:37 +0100546 retval = ((flash_read32(addr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200547 break;
548 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100549 retval = ((flash_read64(addr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200550 break;
551 default:
552 retval = 0;
553 break;
554 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100555 flash_unmap(info, sect, offset, addr);
556
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200557 return retval;
558}
559
560/*-----------------------------------------------------------------------
561 */
562static int flash_toggle (flash_info_t * info, flash_sect_t sect,
563 uint offset, uchar cmd)
564{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100565 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200566 cfiword_t cword;
567 int retval;
568
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100569 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200570 flash_make_cmd (info, cmd, &cword);
571 switch (info->portwidth) {
572 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100573 retval = ((flash_read8(addr) & cword.c) !=
574 (flash_read8(addr) & cword.c));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200575 break;
576 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100577 retval = ((flash_read16(addr) & cword.w) !=
578 (flash_read16(addr) & cword.w));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200579 break;
580 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100581 retval = ((flash_read32(addr) & cword.l) !=
582 (flash_read32(addr) & cword.l));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200583 break;
584 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100585 retval = ((flash_read64(addr) & cword.ll) !=
586 (flash_read64(addr) & cword.ll));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200587 break;
588 default:
589 retval = 0;
590 break;
591 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100592 flash_unmap(info, sect, offset, addr);
593
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200594 return retval;
595}
596
597/*
598 * flash_is_busy - check to see if the flash is busy
599 *
600 * This routine checks the status of the chip and returns true if the
601 * chip is busy.
602 */
603static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
604{
605 int retval;
606
607 switch (info->vendor) {
608 case CFI_CMDSET_INTEL_STANDARD:
609 case CFI_CMDSET_INTEL_EXTENDED:
610 retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
611 break;
612 case CFI_CMDSET_AMD_STANDARD:
613 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100614#ifdef CONFIG_FLASH_CFI_LEGACY
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200615 case CFI_CMDSET_AMD_LEGACY:
616#endif
617 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
618 break;
619 default:
620 retval = 0;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100621 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200622 debug ("flash_is_busy: %d\n", retval);
623 return retval;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100624}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200625
626/*-----------------------------------------------------------------------
627 * wait for XSR.7 to be set. Time out with an error if it does not.
628 * This routine does not set the flash to read-array mode.
629 */
630static int flash_status_check (flash_info_t * info, flash_sect_t sector,
631 ulong tout, char *prompt)
632{
633 ulong start;
634
635#if CFG_HZ != 1000
636 tout *= CFG_HZ/1000;
637#endif
638
639 /* Wait for command completion */
640 start = get_timer (0);
641 while (flash_is_busy (info, sector)) {
642 if (get_timer (start) > tout) {
643 printf ("Flash %s timeout at address %lx data %lx\n",
644 prompt, info->start[sector],
645 flash_read_long (info, sector, 0));
646 flash_write_cmd (info, sector, 0, info->cmd_reset);
647 return ERR_TIMOUT;
648 }
649 udelay (1); /* also triggers watchdog */
650 }
651 return ERR_OK;
652}
653
654/*-----------------------------------------------------------------------
655 * Wait for XSR.7 to be set, if it times out print an error, otherwise
656 * do a full status check.
657 *
658 * This routine sets the flash to read-array mode.
659 */
660static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
661 ulong tout, char *prompt)
662{
663 int retcode;
664
665 retcode = flash_status_check (info, sector, tout, prompt);
666 switch (info->vendor) {
667 case CFI_CMDSET_INTEL_EXTENDED:
668 case CFI_CMDSET_INTEL_STANDARD:
669 if ((retcode == ERR_OK)
670 && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
671 retcode = ERR_INVAL;
672 printf ("Flash %s error at address %lx\n", prompt,
673 info->start[sector]);
674 if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
675 FLASH_STATUS_PSLBS)) {
676 puts ("Command Sequence Error.\n");
677 } else if (flash_isset (info, sector, 0,
678 FLASH_STATUS_ECLBS)) {
679 puts ("Block Erase Error.\n");
680 retcode = ERR_NOT_ERASED;
681 } else if (flash_isset (info, sector, 0,
682 FLASH_STATUS_PSLBS)) {
683 puts ("Locking Error\n");
684 }
685 if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
686 puts ("Block locked.\n");
687 retcode = ERR_PROTECTED;
688 }
689 if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
690 puts ("Vpp Low Error.\n");
691 }
692 flash_write_cmd (info, sector, 0, info->cmd_reset);
693 break;
694 default:
695 break;
696 }
697 return retcode;
698}
699
700/*-----------------------------------------------------------------------
701 */
702static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
703{
704#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
705 unsigned short w;
706 unsigned int l;
707 unsigned long long ll;
708#endif
709
710 switch (info->portwidth) {
711 case FLASH_CFI_8BIT:
712 cword->c = c;
713 break;
714 case FLASH_CFI_16BIT:
715#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
716 w = c;
717 w <<= 8;
718 cword->w = (cword->w >> 8) | w;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100719#else
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200720 cword->w = (cword->w << 8) | c;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100721#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200722 break;
723 case FLASH_CFI_32BIT:
724#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
725 l = c;
726 l <<= 24;
727 cword->l = (cword->l >> 8) | l;
728#else
729 cword->l = (cword->l << 8) | c;
Stefan Roese2662b402006-04-01 13:41:03 +0200730#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200731 break;
732 case FLASH_CFI_64BIT:
733#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
734 ll = c;
735 ll <<= 56;
736 cword->ll = (cword->ll >> 8) | ll;
737#else
738 cword->ll = (cword->ll << 8) | c;
739#endif
740 break;
wdenk5653fc32004-02-08 22:55:38 +0000741 }
wdenk5653fc32004-02-08 22:55:38 +0000742}
743
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200744/* loop through the sectors from the highest address when the passed
745 * address is greater or equal to the sector address we have a match
wdenk5653fc32004-02-08 22:55:38 +0000746 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200747static flash_sect_t find_sector (flash_info_t * info, ulong addr)
wdenk7680c142005-05-16 15:23:22 +0000748{
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200749 flash_sect_t sector;
wdenk7680c142005-05-16 15:23:22 +0000750
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200751 for (sector = info->sector_count - 1; sector >= 0; sector--) {
752 if (addr >= info->start[sector])
wdenk7680c142005-05-16 15:23:22 +0000753 break;
754 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200755 return sector;
wdenk7680c142005-05-16 15:23:22 +0000756}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200757
758/*-----------------------------------------------------------------------
759 */
760static int flash_write_cfiword (flash_info_t * info, ulong dest,
761 cfiword_t cword)
762{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100763 void *dstaddr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200764 int flag;
765
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100766 dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200767
768 /* Check if Flash is (sufficiently) erased */
769 switch (info->portwidth) {
770 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100771 flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200772 break;
773 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100774 flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200775 break;
776 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100777 flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200778 break;
779 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100780 flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200781 break;
782 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100783 flag = 0;
784 break;
785 }
786 if (!flag) {
787 unmap_physmem(dstaddr, info->portwidth);
Stefan Roese0dc80e22007-12-27 07:50:54 +0100788 return ERR_NOT_ERASED;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200789 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200790
791 /* Disable interrupts which might cause a timeout here */
792 flag = disable_interrupts ();
793
794 switch (info->vendor) {
795 case CFI_CMDSET_INTEL_EXTENDED:
796 case CFI_CMDSET_INTEL_STANDARD:
797 flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
798 flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
799 break;
800 case CFI_CMDSET_AMD_EXTENDED:
801 case CFI_CMDSET_AMD_STANDARD:
802#ifdef CONFIG_FLASH_CFI_LEGACY
803 case CFI_CMDSET_AMD_LEGACY:
Wolfgang Denk080bdb72005-10-05 01:51:29 +0200804#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200805 flash_unlock_seq (info, 0);
806 flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
807 break;
808 }
809
810 switch (info->portwidth) {
811 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100812 flash_write8(cword.c, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200813 break;
814 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100815 flash_write16(cword.w, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200816 break;
817 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100818 flash_write32(cword.l, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200819 break;
820 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100821 flash_write64(cword.ll, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200822 break;
823 }
824
825 /* re-enable interrupts if necessary */
826 if (flag)
827 enable_interrupts ();
828
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100829 unmap_physmem(dstaddr, info->portwidth);
830
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200831 return flash_full_status_check (info, find_sector (info, dest),
832 info->write_tout, "write");
833}
834
835#ifdef CFG_FLASH_USE_BUFFER_WRITE
836
837static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
838 int len)
839{
840 flash_sect_t sector;
841 int cnt;
842 int retcode;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100843 void *src = cp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100844 void *dst = map_physmem(dest, len, MAP_NOCACHE);
Stefan Roese0dc80e22007-12-27 07:50:54 +0100845 void *dst2 = dst;
846 int flag = 0;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100847
Stefan Roese0dc80e22007-12-27 07:50:54 +0100848 switch (info->portwidth) {
849 case FLASH_CFI_8BIT:
850 cnt = len;
851 break;
852 case FLASH_CFI_16BIT:
853 cnt = len >> 1;
854 break;
855 case FLASH_CFI_32BIT:
856 cnt = len >> 2;
857 break;
858 case FLASH_CFI_64BIT:
859 cnt = len >> 3;
860 break;
861 default:
862 retcode = ERR_INVAL;
863 goto out_unmap;
864 }
865
866 while ((cnt-- > 0) && (flag == 0)) {
867 switch (info->portwidth) {
868 case FLASH_CFI_8BIT:
869 flag = ((flash_read8(dst2) & flash_read8(src)) ==
870 flash_read8(src));
871 src += 1, dst2 += 1;
872 break;
873 case FLASH_CFI_16BIT:
874 flag = ((flash_read16(dst2) & flash_read16(src)) ==
875 flash_read16(src));
876 src += 2, dst2 += 2;
877 break;
878 case FLASH_CFI_32BIT:
879 flag = ((flash_read32(dst2) & flash_read32(src)) ==
880 flash_read32(src));
881 src += 4, dst2 += 4;
882 break;
883 case FLASH_CFI_64BIT:
884 flag = ((flash_read64(dst2) & flash_read64(src)) ==
885 flash_read64(src));
886 src += 8, dst2 += 8;
887 break;
888 }
889 }
890 if (!flag) {
891 retcode = ERR_NOT_ERASED;
892 goto out_unmap;
893 }
894
895 src = cp;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100896 sector = find_sector (info, dest);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200897
898 switch (info->vendor) {
899 case CFI_CMDSET_INTEL_STANDARD:
900 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200901 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
902 flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
903 retcode = flash_status_check (info, sector,
904 info->buffer_write_tout,
905 "write to buffer");
906 if (retcode == ERR_OK) {
907 /* reduce the number of loops by the width of
908 * the port */
909 switch (info->portwidth) {
910 case FLASH_CFI_8BIT:
911 cnt = len;
912 break;
913 case FLASH_CFI_16BIT:
914 cnt = len >> 1;
915 break;
916 case FLASH_CFI_32BIT:
917 cnt = len >> 2;
918 break;
919 case FLASH_CFI_64BIT:
920 cnt = len >> 3;
921 break;
922 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100923 retcode = ERR_INVAL;
924 goto out_unmap;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200925 }
926 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
927 while (cnt-- > 0) {
928 switch (info->portwidth) {
929 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100930 flash_write8(flash_read8(src), dst);
931 src += 1, dst += 1;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200932 break;
933 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100934 flash_write16(flash_read16(src), dst);
935 src += 2, dst += 2;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200936 break;
937 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100938 flash_write32(flash_read32(src), dst);
939 src += 4, dst += 4;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200940 break;
941 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100942 flash_write64(flash_read64(src), dst);
943 src += 8, dst += 8;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200944 break;
945 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100946 retcode = ERR_INVAL;
947 goto out_unmap;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200948 }
949 }
950 flash_write_cmd (info, sector, 0,
951 FLASH_CMD_WRITE_BUFFER_CONFIRM);
952 retcode = flash_full_status_check (
953 info, sector, info->buffer_write_tout,
954 "buffer write");
955 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100956
957 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200958
959 case CFI_CMDSET_AMD_STANDARD:
960 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200961 flash_unlock_seq(info,0);
962 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER);
963
964 switch (info->portwidth) {
965 case FLASH_CFI_8BIT:
966 cnt = len;
967 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
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:
974 cnt = len >> 1;
975 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100976 while (cnt-- > 0) {
977 flash_write16(flash_read16(src), dst);
978 src += 2, dst += 2;
979 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200980 break;
981 case FLASH_CFI_32BIT:
982 cnt = len >> 2;
983 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100984 while (cnt-- > 0) {
985 flash_write32(flash_read32(src), dst);
986 src += 4, dst += 4;
987 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200988 break;
989 case FLASH_CFI_64BIT:
990 cnt = len >> 3;
991 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100992 while (cnt-- > 0) {
993 flash_write64(flash_read64(src), dst);
994 src += 8, dst += 8;
995 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200996 break;
997 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100998 retcode = ERR_INVAL;
999 goto out_unmap;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001000 }
1001
1002 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1003 retcode = flash_full_status_check (info, sector,
1004 info->buffer_write_tout,
1005 "buffer write");
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001006 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001007
1008 default:
1009 debug ("Unknown Command Set\n");
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001010 retcode = ERR_INVAL;
1011 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001012 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001013
1014out_unmap:
1015 unmap_physmem(dst, len);
1016 return retcode;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001017}
1018#endif /* CFG_FLASH_USE_BUFFER_WRITE */
1019
wdenk7680c142005-05-16 15:23:22 +00001020
1021/*-----------------------------------------------------------------------
1022 */
wdenkbf9e3b32004-02-12 00:47:09 +00001023int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk5653fc32004-02-08 22:55:38 +00001024{
1025 int rcode = 0;
1026 int prot;
1027 flash_sect_t sect;
1028
wdenkbf9e3b32004-02-12 00:47:09 +00001029 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001030 puts ("Can't erase unknown flash type - aborted\n");
wdenk5653fc32004-02-08 22:55:38 +00001031 return 1;
1032 }
1033 if ((s_first < 0) || (s_first > s_last)) {
wdenk4b9206e2004-03-23 22:14:11 +00001034 puts ("- no sectors to erase\n");
wdenk5653fc32004-02-08 22:55:38 +00001035 return 1;
1036 }
1037
1038 prot = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001039 for (sect = s_first; sect <= s_last; ++sect) {
wdenk5653fc32004-02-08 22:55:38 +00001040 if (info->protect[sect]) {
1041 prot++;
1042 }
1043 }
1044 if (prot) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001045 printf ("- Warning: %d protected sectors will not be erased!\n",
1046 prot);
wdenk5653fc32004-02-08 22:55:38 +00001047 } else {
wdenk4b9206e2004-03-23 22:14:11 +00001048 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001049 }
1050
1051
wdenkbf9e3b32004-02-12 00:47:09 +00001052 for (sect = s_first; sect <= s_last; sect++) {
wdenk5653fc32004-02-08 22:55:38 +00001053 if (info->protect[sect] == 0) { /* not protected */
wdenkbf9e3b32004-02-12 00:47:09 +00001054 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +00001055 case CFI_CMDSET_INTEL_STANDARD:
1056 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001057 flash_write_cmd (info, sect, 0,
1058 FLASH_CMD_CLEAR_STATUS);
1059 flash_write_cmd (info, sect, 0,
1060 FLASH_CMD_BLOCK_ERASE);
1061 flash_write_cmd (info, sect, 0,
1062 FLASH_CMD_ERASE_CONFIRM);
wdenk5653fc32004-02-08 22:55:38 +00001063 break;
1064 case CFI_CMDSET_AMD_STANDARD:
1065 case CFI_CMDSET_AMD_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +00001066 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001067 flash_write_cmd (info, sect,
1068 info->addr_unlock1,
1069 AMD_CMD_ERASE_START);
wdenkbf9e3b32004-02-12 00:47:09 +00001070 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001071 flash_write_cmd (info, sect, 0,
1072 AMD_CMD_ERASE_SECTOR);
wdenk5653fc32004-02-08 22:55:38 +00001073 break;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001074#ifdef CONFIG_FLASH_CFI_LEGACY
1075 case CFI_CMDSET_AMD_LEGACY:
1076 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001077 flash_write_cmd (info, 0, info->addr_unlock1,
1078 AMD_CMD_ERASE_START);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001079 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001080 flash_write_cmd (info, sect, 0,
1081 AMD_CMD_ERASE_SECTOR);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001082 break;
1083#endif
wdenk5653fc32004-02-08 22:55:38 +00001084 default:
wdenkbf9e3b32004-02-12 00:47:09 +00001085 debug ("Unkown flash vendor %d\n",
1086 info->vendor);
wdenk5653fc32004-02-08 22:55:38 +00001087 break;
1088 }
1089
wdenkbf9e3b32004-02-12 00:47:09 +00001090 if (flash_full_status_check
1091 (info, sect, info->erase_blk_tout, "erase")) {
wdenk5653fc32004-02-08 22:55:38 +00001092 rcode = 1;
1093 } else
wdenk4b9206e2004-03-23 22:14:11 +00001094 putc ('.');
wdenk5653fc32004-02-08 22:55:38 +00001095 }
1096 }
wdenk4b9206e2004-03-23 22:14:11 +00001097 puts (" done\n");
wdenk5653fc32004-02-08 22:55:38 +00001098 return rcode;
1099}
1100
1101/*-----------------------------------------------------------------------
1102 */
wdenkbf9e3b32004-02-12 00:47:09 +00001103void flash_print_info (flash_info_t * info)
wdenk5653fc32004-02-08 22:55:38 +00001104{
1105 int i;
1106
1107 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001108 puts ("missing or unknown FLASH type\n");
wdenk5653fc32004-02-08 22:55:38 +00001109 return;
1110 }
1111
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001112 printf ("%s FLASH (%d x %d)",
1113 info->name,
wdenkbf9e3b32004-02-12 00:47:09 +00001114 (info->portwidth << 3), (info->chipwidth << 3));
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001115 if (info->size < 1024*1024)
1116 printf (" Size: %ld kB in %d Sectors\n",
1117 info->size >> 10, info->sector_count);
1118 else
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001119 printf (" Size: %ld MB in %d Sectors\n",
1120 info->size >> 20, info->sector_count);
Stefan Roese260421a2006-11-13 13:55:24 +01001121 printf (" ");
1122 switch (info->vendor) {
1123 case CFI_CMDSET_INTEL_STANDARD:
1124 printf ("Intel Standard");
1125 break;
1126 case CFI_CMDSET_INTEL_EXTENDED:
1127 printf ("Intel Extended");
1128 break;
1129 case CFI_CMDSET_AMD_STANDARD:
1130 printf ("AMD Standard");
1131 break;
1132 case CFI_CMDSET_AMD_EXTENDED:
1133 printf ("AMD Extended");
1134 break;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001135#ifdef CONFIG_FLASH_CFI_LEGACY
1136 case CFI_CMDSET_AMD_LEGACY:
1137 printf ("AMD Legacy");
1138 break;
1139#endif
Stefan Roese260421a2006-11-13 13:55:24 +01001140 default:
1141 printf ("Unknown (%d)", info->vendor);
1142 break;
1143 }
1144 printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
1145 info->manufacturer_id, info->device_id);
1146 if (info->device_id == 0x7E) {
1147 printf("%04X", info->device_id2);
1148 }
1149 printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n",
wdenk028ab6b2004-02-23 23:54:43 +00001150 info->erase_blk_tout,
Stefan Roese260421a2006-11-13 13:55:24 +01001151 info->write_tout);
1152 if (info->buffer_size > 1) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001153 printf (" Buffer write timeout: %ld ms, "
1154 "buffer size: %d bytes\n",
wdenk028ab6b2004-02-23 23:54:43 +00001155 info->buffer_write_tout,
1156 info->buffer_size);
Stefan Roese260421a2006-11-13 13:55:24 +01001157 }
wdenk5653fc32004-02-08 22:55:38 +00001158
Stefan Roese260421a2006-11-13 13:55:24 +01001159 puts ("\n Sector Start Addresses:");
wdenkbf9e3b32004-02-12 00:47:09 +00001160 for (i = 0; i < info->sector_count; ++i) {
Stefan Roese260421a2006-11-13 13:55:24 +01001161 if ((i % 5) == 0)
1162 printf ("\n");
wdenk5653fc32004-02-08 22:55:38 +00001163#ifdef CFG_FLASH_EMPTY_INFO
1164 int k;
1165 int size;
1166 int erased;
1167 volatile unsigned long *flash;
1168
1169 /*
1170 * Check if whole sector is erased
1171 */
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001172 size = flash_sector_size(info, i);
wdenk5653fc32004-02-08 22:55:38 +00001173 erased = 1;
wdenkbf9e3b32004-02-12 00:47:09 +00001174 flash = (volatile unsigned long *) info->start[i];
1175 size = size >> 2; /* divide by 4 for longword access */
1176 for (k = 0; k < size; k++) {
1177 if (*flash++ != 0xffffffff) {
1178 erased = 0;
1179 break;
1180 }
1181 }
wdenk5653fc32004-02-08 22:55:38 +00001182
wdenk5653fc32004-02-08 22:55:38 +00001183 /* print empty and read-only info */
Stefan Roese260421a2006-11-13 13:55:24 +01001184 printf (" %08lX %c %s ",
wdenk5653fc32004-02-08 22:55:38 +00001185 info->start[i],
Stefan Roese260421a2006-11-13 13:55:24 +01001186 erased ? 'E' : ' ',
1187 info->protect[i] ? "RO" : " ");
Wolfgang Denkb63de2c2005-09-25 00:23:05 +02001188#else /* ! CFG_FLASH_EMPTY_INFO */
Stefan Roese260421a2006-11-13 13:55:24 +01001189 printf (" %08lX %s ",
1190 info->start[i],
1191 info->protect[i] ? "RO" : " ");
wdenk5653fc32004-02-08 22:55:38 +00001192#endif
1193 }
wdenk4b9206e2004-03-23 22:14:11 +00001194 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001195 return;
1196}
1197
1198/*-----------------------------------------------------------------------
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001199 * This is used in a few places in write_buf() to show programming
1200 * progress. Making it a function is nasty because it needs to do side
1201 * effect updates to digit and dots. Repeated code is nasty too, so
1202 * we define it once here.
1203 */
Stefan Roesef0105722008-03-19 07:09:26 +01001204#ifdef CONFIG_FLASH_SHOW_PROGRESS
1205#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
1206 dots -= dots_sub; \
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001207 if ((scale > 0) && (dots <= 0)) { \
1208 if ((digit % 5) == 0) \
1209 printf ("%d", digit / 5); \
1210 else \
1211 putc ('.'); \
1212 digit--; \
1213 dots += scale; \
1214 }
Stefan Roesef0105722008-03-19 07:09:26 +01001215#else
1216#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1217#endif
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001218
1219/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001220 * Copy memory to flash, returns:
1221 * 0 - OK
1222 * 1 - write timeout
1223 * 2 - Flash not erased
1224 */
wdenkbf9e3b32004-02-12 00:47:09 +00001225int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk5653fc32004-02-08 22:55:38 +00001226{
1227 ulong wp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001228 uchar *p;
wdenk5653fc32004-02-08 22:55:38 +00001229 int aln;
1230 cfiword_t cword;
1231 int i, rc;
wdenkbf9e3b32004-02-12 00:47:09 +00001232#ifdef CFG_FLASH_USE_BUFFER_WRITE
1233 int buffered_size;
1234#endif
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001235#ifdef CONFIG_FLASH_SHOW_PROGRESS
1236 int digit = CONFIG_FLASH_SHOW_PROGRESS;
1237 int scale = 0;
1238 int dots = 0;
1239
1240 /*
1241 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
1242 */
1243 if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
1244 scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
1245 CONFIG_FLASH_SHOW_PROGRESS);
1246 }
1247#endif
1248
wdenkbf9e3b32004-02-12 00:47:09 +00001249 /* get lower aligned address */
wdenk5653fc32004-02-08 22:55:38 +00001250 wp = (addr & ~(info->portwidth - 1));
1251
1252 /* handle unaligned start */
wdenkbf9e3b32004-02-12 00:47:09 +00001253 if ((aln = addr - wp) != 0) {
wdenk5653fc32004-02-08 22:55:38 +00001254 cword.l = 0;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001255 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1256 for (i = 0; i < aln; ++i)
1257 flash_add_byte (info, &cword, flash_read8(p + i));
wdenk5653fc32004-02-08 22:55:38 +00001258
wdenkbf9e3b32004-02-12 00:47:09 +00001259 for (; (i < info->portwidth) && (cnt > 0); i++) {
1260 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001261 cnt--;
wdenk5653fc32004-02-08 22:55:38 +00001262 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001263 for (; (cnt == 0) && (i < info->portwidth); ++i)
1264 flash_add_byte (info, &cword, flash_read8(p + i));
1265
1266 rc = flash_write_cfiword (info, wp, cword);
1267 unmap_physmem(p, info->portwidth);
1268 if (rc != 0)
wdenk5653fc32004-02-08 22:55:38 +00001269 return rc;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001270
1271 wp += i;
Stefan Roesef0105722008-03-19 07:09:26 +01001272 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001273 }
1274
wdenkbf9e3b32004-02-12 00:47:09 +00001275 /* handle the aligned part */
wdenk5653fc32004-02-08 22:55:38 +00001276#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenkbf9e3b32004-02-12 00:47:09 +00001277 buffered_size = (info->portwidth / info->chipwidth);
1278 buffered_size *= info->buffer_size;
1279 while (cnt >= info->portwidth) {
Stefan Roese79b4cda2006-02-28 15:29:58 +01001280 /* prohibit buffer write when buffer_size is 1 */
1281 if (info->buffer_size == 1) {
1282 cword.l = 0;
1283 for (i = 0; i < info->portwidth; i++)
1284 flash_add_byte (info, &cword, *src++);
1285 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1286 return rc;
1287 wp += info->portwidth;
1288 cnt -= info->portwidth;
1289 continue;
1290 }
1291
1292 /* write buffer until next buffered_size aligned boundary */
1293 i = buffered_size - (wp % buffered_size);
1294 if (i > cnt)
1295 i = cnt;
wdenkbf9e3b32004-02-12 00:47:09 +00001296 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
wdenk5653fc32004-02-08 22:55:38 +00001297 return rc;
Wolfgang Denk8d4ba3d2005-08-12 22:35:59 +02001298 i -= i & (info->portwidth - 1);
wdenk5653fc32004-02-08 22:55:38 +00001299 wp += i;
1300 src += i;
wdenkbf9e3b32004-02-12 00:47:09 +00001301 cnt -= i;
Stefan Roesef0105722008-03-19 07:09:26 +01001302 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001303 }
1304#else
wdenkbf9e3b32004-02-12 00:47:09 +00001305 while (cnt >= info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001306 cword.l = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001307 for (i = 0; i < info->portwidth; i++) {
1308 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001309 }
wdenkbf9e3b32004-02-12 00:47:09 +00001310 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk5653fc32004-02-08 22:55:38 +00001311 return rc;
1312 wp += info->portwidth;
1313 cnt -= info->portwidth;
Stefan Roesef0105722008-03-19 07:09:26 +01001314 FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
wdenk5653fc32004-02-08 22:55:38 +00001315 }
1316#endif /* CFG_FLASH_USE_BUFFER_WRITE */
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001317
wdenk5653fc32004-02-08 22:55:38 +00001318 if (cnt == 0) {
1319 return (0);
1320 }
1321
1322 /*
1323 * handle unaligned tail bytes
1324 */
1325 cword.l = 0;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001326 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1327 for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
wdenkbf9e3b32004-02-12 00:47:09 +00001328 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001329 --cnt;
1330 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001331 for (; i < info->portwidth; ++i)
1332 flash_add_byte (info, &cword, flash_read8(p + i));
1333 unmap_physmem(p, info->portwidth);
wdenk5653fc32004-02-08 22:55:38 +00001334
wdenkbf9e3b32004-02-12 00:47:09 +00001335 return flash_write_cfiword (info, wp, cword);
wdenk5653fc32004-02-08 22:55:38 +00001336}
1337
1338/*-----------------------------------------------------------------------
1339 */
1340#ifdef CFG_FLASH_PROTECTION
1341
wdenkbf9e3b32004-02-12 00:47:09 +00001342int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk5653fc32004-02-08 22:55:38 +00001343{
1344 int retcode = 0;
1345
wdenkbf9e3b32004-02-12 00:47:09 +00001346 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1347 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1348 if (prot)
1349 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
wdenk5653fc32004-02-08 22:55:38 +00001350 else
wdenkbf9e3b32004-02-12 00:47:09 +00001351 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
wdenk5653fc32004-02-08 22:55:38 +00001352
wdenkbf9e3b32004-02-12 00:47:09 +00001353 if ((retcode =
1354 flash_full_status_check (info, sector, info->erase_blk_tout,
1355 prot ? "protect" : "unprotect")) == 0) {
wdenk5653fc32004-02-08 22:55:38 +00001356
1357 info->protect[sector] = prot;
Stefan Roese2662b402006-04-01 13:41:03 +02001358
1359 /*
1360 * On some of Intel's flash chips (marked via legacy_unlock)
1361 * unprotect unprotects all locking.
1362 */
1363 if ((prot == 0) && (info->legacy_unlock)) {
wdenk5653fc32004-02-08 22:55:38 +00001364 flash_sect_t i;
wdenkbf9e3b32004-02-12 00:47:09 +00001365
1366 for (i = 0; i < info->sector_count; i++) {
1367 if (info->protect[i])
1368 flash_real_protect (info, i, 1);
wdenk5653fc32004-02-08 22:55:38 +00001369 }
1370 }
1371 }
wdenk5653fc32004-02-08 22:55:38 +00001372 return retcode;
wdenkbf9e3b32004-02-12 00:47:09 +00001373}
1374
wdenk5653fc32004-02-08 22:55:38 +00001375/*-----------------------------------------------------------------------
1376 * flash_read_user_serial - read the OneTimeProgramming cells
1377 */
wdenkbf9e3b32004-02-12 00:47:09 +00001378void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
1379 int len)
wdenk5653fc32004-02-08 22:55:38 +00001380{
wdenkbf9e3b32004-02-12 00:47:09 +00001381 uchar *src;
1382 uchar *dst;
wdenk5653fc32004-02-08 22:55:38 +00001383
1384 dst = buffer;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001385 src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001386 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1387 memcpy (dst, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001388 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001389 flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001390}
wdenkbf9e3b32004-02-12 00:47:09 +00001391
wdenk5653fc32004-02-08 22:55:38 +00001392/*
1393 * flash_read_factory_serial - read the device Id from the protection area
1394 */
wdenkbf9e3b32004-02-12 00:47:09 +00001395void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
1396 int len)
wdenk5653fc32004-02-08 22:55:38 +00001397{
wdenkbf9e3b32004-02-12 00:47:09 +00001398 uchar *src;
wdenkcd37d9e2004-02-10 00:03:41 +00001399
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001400 src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001401 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1402 memcpy (buffer, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001403 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001404 flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001405}
1406
1407#endif /* CFG_FLASH_PROTECTION */
1408
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001409/*-----------------------------------------------------------------------
1410 * Reverse the order of the erase regions in the CFI QRY structure.
1411 * This is needed for chips that are either a) correctly detected as
1412 * top-boot, or b) buggy.
1413 */
1414static void cfi_reverse_geometry(struct cfi_qry *qry)
1415{
1416 unsigned int i, j;
1417 u32 tmp;
1418
1419 for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
1420 tmp = qry->erase_region_info[i];
1421 qry->erase_region_info[i] = qry->erase_region_info[j];
1422 qry->erase_region_info[j] = tmp;
1423 }
1424}
wdenk5653fc32004-02-08 22:55:38 +00001425
1426/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +01001427 * read jedec ids from device and set corresponding fields in info struct
1428 *
1429 * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1430 *
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001431 */
1432static void cmdset_intel_read_jedec_ids(flash_info_t *info)
1433{
1434 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1435 flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1436 udelay(1000); /* some flash are slow to respond */
1437 info->manufacturer_id = flash_read_uchar (info,
1438 FLASH_OFFSET_MANUFACTURER_ID);
1439 info->device_id = flash_read_uchar (info,
1440 FLASH_OFFSET_DEVICE_ID);
1441 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1442}
1443
1444static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
1445{
1446 info->cmd_reset = FLASH_CMD_RESET;
1447
1448 cmdset_intel_read_jedec_ids(info);
1449 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1450
1451#ifdef CFG_FLASH_PROTECTION
1452 /* read legacy lock/unlock bit from intel flash */
1453 if (info->ext_addr) {
1454 info->legacy_unlock = flash_read_uchar (info,
1455 info->ext_addr + 5) & 0x08;
1456 }
1457#endif
1458
1459 return 0;
1460}
1461
1462static void cmdset_amd_read_jedec_ids(flash_info_t *info)
1463{
1464 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1465 flash_unlock_seq(info, 0);
1466 flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
1467 udelay(1000); /* some flash are slow to respond */
Tor Krill90447ec2008-03-28 11:29:10 +01001468
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001469 info->manufacturer_id = flash_read_uchar (info,
1470 FLASH_OFFSET_MANUFACTURER_ID);
Tor Krill90447ec2008-03-28 11:29:10 +01001471
1472 switch (info->chipwidth){
1473 case FLASH_CFI_8BIT:
1474 info->device_id = flash_read_uchar (info,
1475 FLASH_OFFSET_DEVICE_ID);
1476 if (info->device_id == 0x7E) {
1477 /* AMD 3-byte (expanded) device ids */
1478 info->device_id2 = flash_read_uchar (info,
1479 FLASH_OFFSET_DEVICE_ID2);
1480 info->device_id2 <<= 8;
1481 info->device_id2 |= flash_read_uchar (info,
1482 FLASH_OFFSET_DEVICE_ID3);
1483 }
1484 break;
1485 case FLASH_CFI_16BIT:
1486 info->device_id = flash_read_word (info,
1487 FLASH_OFFSET_DEVICE_ID);
1488 break;
1489 default:
1490 break;
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001491 }
1492 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1493}
1494
1495static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
1496{
1497 info->cmd_reset = AMD_CMD_RESET;
1498
1499 cmdset_amd_read_jedec_ids(info);
1500 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1501
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001502 return 0;
1503}
1504
1505#ifdef CONFIG_FLASH_CFI_LEGACY
Stefan Roese260421a2006-11-13 13:55:24 +01001506static void flash_read_jedec_ids (flash_info_t * info)
1507{
1508 info->manufacturer_id = 0;
1509 info->device_id = 0;
1510 info->device_id2 = 0;
1511
1512 switch (info->vendor) {
1513 case CFI_CMDSET_INTEL_STANDARD:
1514 case CFI_CMDSET_INTEL_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001515 cmdset_intel_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001516 break;
1517 case CFI_CMDSET_AMD_STANDARD:
1518 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001519 cmdset_amd_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001520 break;
1521 default:
1522 break;
1523 }
1524}
1525
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001526/*-----------------------------------------------------------------------
1527 * Call board code to request info about non-CFI flash.
1528 * board_flash_get_legacy needs to fill in at least:
1529 * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1530 */
1531static int flash_detect_legacy(ulong base, int banknum)
1532{
1533 flash_info_t *info = &flash_info[banknum];
1534
1535 if (board_flash_get_legacy(base, banknum, info)) {
1536 /* board code may have filled info completely. If not, we
1537 use JEDEC ID probing. */
1538 if (!info->vendor) {
1539 int modes[] = {
1540 CFI_CMDSET_AMD_STANDARD,
1541 CFI_CMDSET_INTEL_STANDARD
1542 };
1543 int i;
1544
1545 for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1546 info->vendor = modes[i];
1547 info->start[0] = base;
1548 if (info->portwidth == FLASH_CFI_8BIT
1549 && info->interface == FLASH_CFI_X8X16) {
1550 info->addr_unlock1 = 0x2AAA;
1551 info->addr_unlock2 = 0x5555;
1552 } else {
1553 info->addr_unlock1 = 0x5555;
1554 info->addr_unlock2 = 0x2AAA;
1555 }
1556 flash_read_jedec_ids(info);
1557 debug("JEDEC PROBE: ID %x %x %x\n",
1558 info->manufacturer_id,
1559 info->device_id,
1560 info->device_id2);
1561 if (jedec_flash_match(info, base))
1562 break;
1563 }
1564 }
1565
1566 switch(info->vendor) {
1567 case CFI_CMDSET_INTEL_STANDARD:
1568 case CFI_CMDSET_INTEL_EXTENDED:
1569 info->cmd_reset = FLASH_CMD_RESET;
1570 break;
1571 case CFI_CMDSET_AMD_STANDARD:
1572 case CFI_CMDSET_AMD_EXTENDED:
1573 case CFI_CMDSET_AMD_LEGACY:
1574 info->cmd_reset = AMD_CMD_RESET;
1575 break;
1576 }
1577 info->flash_id = FLASH_MAN_CFI;
1578 return 1;
1579 }
1580 return 0; /* use CFI */
1581}
1582#else
1583static inline int flash_detect_legacy(ulong base, int banknum)
1584{
1585 return 0; /* use CFI */
1586}
1587#endif
1588
Stefan Roese260421a2006-11-13 13:55:24 +01001589/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001590 * detect if flash is compatible with the Common Flash Interface (CFI)
1591 * http://www.jedec.org/download/search/jesd68.pdf
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001592 */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001593static void flash_read_cfi (flash_info_t *info, void *buf,
1594 unsigned int start, size_t len)
1595{
1596 u8 *p = buf;
1597 unsigned int i;
1598
1599 for (i = 0; i < len; i++)
1600 p[i] = flash_read_uchar(info, start + i);
1601}
1602
1603static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
wdenk5653fc32004-02-08 22:55:38 +00001604{
Wolfgang Denk92eb7292006-12-27 01:26:13 +01001605 int cfi_offset;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001606
Michael Schwingen1ba639d2008-02-18 23:16:35 +01001607 /* We do not yet know what kind of commandset to use, so we issue
1608 the reset command in both Intel and AMD variants, in the hope
1609 that AMD flash roms ignore the Intel command. */
1610 flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
1611 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
1612
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001613 for (cfi_offset=0;
1614 cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
1615 cfi_offset++) {
1616 flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
1617 FLASH_CMD_CFI);
1618 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1619 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1620 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001621 flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1622 sizeof(struct cfi_qry));
1623 info->interface = le16_to_cpu(qry->interface_desc);
1624
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001625 info->cfi_offset = flash_offset_cfi[cfi_offset];
1626 debug ("device interface is %d\n",
1627 info->interface);
1628 debug ("found port %d chip %d ",
1629 info->portwidth, info->chipwidth);
1630 debug ("port %d bits chip %d bits\n",
1631 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1632 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1633
1634 /* calculate command offsets as in the Linux driver */
1635 info->addr_unlock1 = 0x555;
1636 info->addr_unlock2 = 0x2aa;
1637
1638 /*
1639 * modify the unlock address if we are
1640 * in compatibility mode
1641 */
1642 if ( /* x8/x16 in x8 mode */
1643 ((info->chipwidth == FLASH_CFI_BY8) &&
1644 (info->interface == FLASH_CFI_X8X16)) ||
1645 /* x16/x32 in x16 mode */
1646 ((info->chipwidth == FLASH_CFI_BY16) &&
1647 (info->interface == FLASH_CFI_X16X32)))
1648 {
1649 info->addr_unlock1 = 0xaaa;
1650 info->addr_unlock2 = 0x555;
1651 }
1652
1653 info->name = "CFI conformant";
1654 return 1;
1655 }
1656 }
1657
1658 return 0;
1659}
1660
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001661static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001662{
wdenkbf9e3b32004-02-12 00:47:09 +00001663 debug ("flash detect cfi\n");
wdenk5653fc32004-02-08 22:55:38 +00001664
Stefan Roese79b4cda2006-02-28 15:29:58 +01001665 for (info->portwidth = CFG_FLASH_CFI_WIDTH;
wdenkbf9e3b32004-02-12 00:47:09 +00001666 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1667 for (info->chipwidth = FLASH_CFI_BY8;
1668 info->chipwidth <= info->portwidth;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001669 info->chipwidth <<= 1)
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001670 if (__flash_detect_cfi(info, qry))
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001671 return 1;
wdenk5653fc32004-02-08 22:55:38 +00001672 }
wdenkbf9e3b32004-02-12 00:47:09 +00001673 debug ("not found\n");
wdenk5653fc32004-02-08 22:55:38 +00001674 return 0;
1675}
wdenkbf9e3b32004-02-12 00:47:09 +00001676
wdenk5653fc32004-02-08 22:55:38 +00001677/*
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001678 * Manufacturer-specific quirks. Add workarounds for geometry
1679 * reversal, etc. here.
1680 */
1681static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1682{
1683 /* check if flash geometry needs reversal */
1684 if (qry->num_erase_regions > 1) {
1685 /* reverse geometry if top boot part */
1686 if (info->cfi_version < 0x3131) {
1687 /* CFI < 1.1, try to guess from device id */
1688 if ((info->device_id & 0x80) != 0)
1689 cfi_reverse_geometry(qry);
1690 } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1691 /* CFI >= 1.1, deduct from top/bottom flag */
1692 /* note: ext_addr is valid since cfi_version > 0 */
1693 cfi_reverse_geometry(qry);
1694 }
1695 }
1696}
1697
1698static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1699{
1700 int reverse_geometry = 0;
1701
1702 /* Check the "top boot" bit in the PRI */
1703 if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1704 reverse_geometry = 1;
1705
1706 /* AT49BV6416(T) list the erase regions in the wrong order.
1707 * However, the device ID is identical with the non-broken
1708 * AT49BV642D since u-boot only reads the low byte (they
1709 * differ in the high byte.) So leave out this fixup for now.
1710 */
1711#if 0
1712 if (info->device_id == 0xd6 || info->device_id == 0xd2)
1713 reverse_geometry = !reverse_geometry;
1714#endif
1715
1716 if (reverse_geometry)
1717 cfi_reverse_geometry(qry);
1718}
1719
1720/*
wdenk5653fc32004-02-08 22:55:38 +00001721 * The following code cannot be run from FLASH!
1722 *
1723 */
Marian Balakowicze6f2e902005-10-11 19:09:42 +02001724ulong flash_get_size (ulong base, int banknum)
wdenk5653fc32004-02-08 22:55:38 +00001725{
wdenkbf9e3b32004-02-12 00:47:09 +00001726 flash_info_t *info = &flash_info[banknum];
wdenk5653fc32004-02-08 22:55:38 +00001727 int i, j;
1728 flash_sect_t sect_cnt;
1729 unsigned long sector;
1730 unsigned long tmp;
1731 int size_ratio;
1732 uchar num_erase_regions;
wdenkbf9e3b32004-02-12 00:47:09 +00001733 int erase_region_size;
1734 int erase_region_count;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001735 struct cfi_qry qry;
Stefan Roese260421a2006-11-13 13:55:24 +01001736
1737 info->ext_addr = 0;
1738 info->cfi_version = 0;
Stefan Roese2662b402006-04-01 13:41:03 +02001739#ifdef CFG_FLASH_PROTECTION
Stefan Roese2662b402006-04-01 13:41:03 +02001740 info->legacy_unlock = 0;
1741#endif
wdenk5653fc32004-02-08 22:55:38 +00001742
1743 info->start[0] = base;
1744
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001745 if (flash_detect_cfi (info, &qry)) {
1746 info->vendor = le16_to_cpu(qry.p_id);
1747 info->ext_addr = le16_to_cpu(qry.p_adr);
1748 num_erase_regions = qry.num_erase_regions;
1749
Stefan Roese260421a2006-11-13 13:55:24 +01001750 if (info->ext_addr) {
1751 info->cfi_version = (ushort) flash_read_uchar (info,
1752 info->ext_addr + 3) << 8;
1753 info->cfi_version |= (ushort) flash_read_uchar (info,
1754 info->ext_addr + 4);
1755 }
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001756
wdenkbf9e3b32004-02-12 00:47:09 +00001757#ifdef DEBUG
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001758 flash_printqry (&qry);
wdenkbf9e3b32004-02-12 00:47:09 +00001759#endif
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001760
wdenkbf9e3b32004-02-12 00:47:09 +00001761 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +00001762 case CFI_CMDSET_INTEL_STANDARD:
1763 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001764 cmdset_intel_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001765 break;
1766 case CFI_CMDSET_AMD_STANDARD:
1767 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001768 cmdset_amd_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001769 break;
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001770 default:
1771 printf("CFI: Unknown command set 0x%x\n",
1772 info->vendor);
1773 /*
1774 * Unfortunately, this means we don't know how
1775 * to get the chip back to Read mode. Might
1776 * as well try an Intel-style reset...
1777 */
1778 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1779 return 0;
wdenk5653fc32004-02-08 22:55:38 +00001780 }
wdenkcd37d9e2004-02-10 00:03:41 +00001781
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001782 /* Do manufacturer-specific fixups */
1783 switch (info->manufacturer_id) {
1784 case 0x0001:
1785 flash_fixup_amd(info, &qry);
1786 break;
1787 case 0x001f:
1788 flash_fixup_atmel(info, &qry);
1789 break;
1790 }
1791
wdenkbf9e3b32004-02-12 00:47:09 +00001792 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese260421a2006-11-13 13:55:24 +01001793 debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
1794 debug ("device id is 0x%x\n", info->device_id);
1795 debug ("device id2 is 0x%x\n", info->device_id2);
1796 debug ("cfi version is 0x%04x\n", info->cfi_version);
1797
wdenk5653fc32004-02-08 22:55:38 +00001798 size_ratio = info->portwidth / info->chipwidth;
wdenkbf9e3b32004-02-12 00:47:09 +00001799 /* if the chip is x8/x16 reduce the ratio by half */
1800 if ((info->interface == FLASH_CFI_X8X16)
1801 && (info->chipwidth == FLASH_CFI_BY8)) {
1802 size_ratio >>= 1;
1803 }
wdenkbf9e3b32004-02-12 00:47:09 +00001804 debug ("size_ratio %d port %d bits chip %d bits\n",
1805 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1806 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1807 debug ("found %d erase regions\n", num_erase_regions);
wdenk5653fc32004-02-08 22:55:38 +00001808 sect_cnt = 0;
1809 sector = base;
wdenkbf9e3b32004-02-12 00:47:09 +00001810 for (i = 0; i < num_erase_regions; i++) {
1811 if (i > NUM_ERASE_REGIONS) {
wdenk028ab6b2004-02-23 23:54:43 +00001812 printf ("%d erase regions found, only %d used\n",
1813 num_erase_regions, NUM_ERASE_REGIONS);
wdenk5653fc32004-02-08 22:55:38 +00001814 break;
1815 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001816
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001817 tmp = le32_to_cpu(qry.erase_region_info[i]);
1818 debug("erase region %u: 0x%08lx\n", i, tmp);
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001819
1820 erase_region_count = (tmp & 0xffff) + 1;
1821 tmp >>= 16;
wdenkbf9e3b32004-02-12 00:47:09 +00001822 erase_region_size =
1823 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenk4c0d4c32004-06-09 17:34:58 +00001824 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenk028ab6b2004-02-23 23:54:43 +00001825 erase_region_count, erase_region_size);
wdenkbf9e3b32004-02-12 00:47:09 +00001826 for (j = 0; j < erase_region_count; j++) {
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001827 if (sect_cnt >= CFG_MAX_FLASH_SECT) {
1828 printf("ERROR: too many flash sectors\n");
1829 break;
1830 }
wdenk5653fc32004-02-08 22:55:38 +00001831 info->start[sect_cnt] = sector;
1832 sector += (erase_region_size * size_ratio);
wdenka1191902005-01-09 17:12:27 +00001833
1834 /*
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001835 * Only read protection status from
1836 * supported devices (intel...)
wdenka1191902005-01-09 17:12:27 +00001837 */
1838 switch (info->vendor) {
1839 case CFI_CMDSET_INTEL_EXTENDED:
1840 case CFI_CMDSET_INTEL_STANDARD:
1841 info->protect[sect_cnt] =
1842 flash_isset (info, sect_cnt,
1843 FLASH_OFFSET_PROTECT,
1844 FLASH_STATUS_PROTECT);
1845 break;
1846 default:
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001847 /* default: not protected */
1848 info->protect[sect_cnt] = 0;
wdenka1191902005-01-09 17:12:27 +00001849 }
1850
wdenk5653fc32004-02-08 22:55:38 +00001851 sect_cnt++;
1852 }
1853 }
1854
1855 info->sector_count = sect_cnt;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001856 info->size = 1 << qry.dev_size;
wdenk5653fc32004-02-08 22:55:38 +00001857 /* multiply the size by the number of chips */
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001858 info->size *= size_ratio;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001859 info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1860 tmp = 1 << qry.block_erase_timeout_typ;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001861 info->erase_blk_tout = tmp *
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001862 (1 << qry.block_erase_timeout_max);
1863 tmp = (1 << qry.buf_write_timeout_typ) *
1864 (1 << qry.buf_write_timeout_max);
1865
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001866 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001867 info->buffer_write_tout = (tmp + 999) / 1000;
1868 tmp = (1 << qry.word_write_timeout_typ) *
1869 (1 << qry.word_write_timeout_max);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001870 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001871 info->write_tout = (tmp + 999) / 1000;
wdenk5653fc32004-02-08 22:55:38 +00001872 info->flash_id = FLASH_MAN_CFI;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001873 if ((info->interface == FLASH_CFI_X8X16) &&
1874 (info->chipwidth == FLASH_CFI_BY8)) {
1875 /* XXX - Need to test on x8/x16 in parallel. */
1876 info->portwidth >>= 1;
wdenk855a4962004-03-14 18:23:55 +00001877 }
wdenk5653fc32004-02-08 22:55:38 +00001878 }
1879
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001880 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenkbf9e3b32004-02-12 00:47:09 +00001881 return (info->size);
wdenk5653fc32004-02-08 22:55:38 +00001882}
1883
wdenk5653fc32004-02-08 22:55:38 +00001884/*-----------------------------------------------------------------------
1885 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001886unsigned long flash_init (void)
wdenk5653fc32004-02-08 22:55:38 +00001887{
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001888 unsigned long size = 0;
1889 int i;
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
1983 return (size);
wdenk5653fc32004-02-08 22:55:38 +00001984}
Heiko Schocherca43ba12007-01-11 15:44:44 +01001985
wdenk5653fc32004-02-08 22:55:38 +00001986#endif /* CFG_FLASH_CFI */