blob: 90cb966775d489841939aaa0c0ea8bc7f5f2a37a [file] [log] [blame]
wdenk2cefd152004-02-08 22:55:38 +00001/*
wdenke65527f2004-02-12 00:47:09 +00002 * (C) Copyright 2002-2004
wdenk2cefd152004-02-08 22:55:38 +00003 * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com
4 *
5 * Copyright (C) 2003 Arabella Software Ltd.
6 * Yuli Barcohen <yuli@arabellasw.com>
wdenk2cefd152004-02-08 22:55:38 +00007 *
wdenke65527f2004-02-12 00:47:09 +00008 * Copyright (C) 2004
9 * Ed Okerson
Stefan Roese12797482006-11-13 13:55:24 +010010 *
11 * Copyright (C) 2006
12 * Tolunay Orkun <listmember@orkun.us>
wdenke65527f2004-02-12 00:47:09 +000013 *
wdenk2cefd152004-02-08 22:55:38 +000014 * See file CREDITS for list of people who contributed to this
15 * project.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30 * MA 02111-1307 USA
31 *
wdenk2cefd152004-02-08 22:55:38 +000032 */
33
34/* The DEBUG define must be before common to enable debugging */
wdenk2ebee312004-02-23 19:30:57 +000035/* #define DEBUG */
36
wdenk2cefd152004-02-08 22:55:38 +000037#include <common.h>
38#include <asm/processor.h>
Haiying Wangc123a382007-02-21 16:52:31 +010039#include <asm/io.h>
wdenkaeba06f2004-06-09 17:34:58 +000040#include <asm/byteorder.h>
wdenkd0245fc2005-04-13 10:02:42 +000041#include <environment.h>
wdenke65527f2004-02-12 00:47:09 +000042#ifdef CFG_FLASH_CFI_DRIVER
wdenke537b3b2004-02-23 23:54:43 +000043
wdenk2cefd152004-02-08 22:55:38 +000044/*
Haavard Skinnemoend523e392007-12-13 12:56:28 +010045 * This file implements a Common Flash Interface (CFI) driver for
46 * U-Boot.
47 *
48 * The width of the port and the width of the chips are determined at
49 * initialization. These widths are used to calculate the address for
50 * access CFI data structures.
wdenk2cefd152004-02-08 22:55:38 +000051 *
52 * References
53 * JEDEC Standard JESD68 - Common Flash Interface (CFI)
54 * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
55 * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
56 * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
Stefan Roese12797482006-11-13 13:55:24 +010057 * AMD CFI Specification, Release 2.0 December 1, 2001
58 * AMD/Spansion Application Note: Migration from Single-byte to Three-byte
59 * Device IDs, Publication Number 25538 Revision A, November 8, 2001
wdenk2cefd152004-02-08 22:55:38 +000060 *
Haavard Skinnemoend523e392007-12-13 12:56:28 +010061 * Define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
Heiko Schocher800db312007-01-19 18:05:26 +010062 * reading and writing ... (yes there is such a Hardware).
wdenk2cefd152004-02-08 22:55:38 +000063 */
64
wdenke65527f2004-02-12 00:47:09 +000065#ifndef CFG_FLASH_BANKS_LIST
66#define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE }
67#endif
68
wdenk2cefd152004-02-08 22:55:38 +000069#define FLASH_CMD_CFI 0x98
70#define FLASH_CMD_READ_ID 0x90
71#define FLASH_CMD_RESET 0xff
72#define FLASH_CMD_BLOCK_ERASE 0x20
73#define FLASH_CMD_ERASE_CONFIRM 0xD0
74#define FLASH_CMD_WRITE 0x40
75#define FLASH_CMD_PROTECT 0x60
76#define FLASH_CMD_PROTECT_SET 0x01
77#define FLASH_CMD_PROTECT_CLEAR 0xD0
78#define FLASH_CMD_CLEAR_STATUS 0x50
wdenke65527f2004-02-12 00:47:09 +000079#define FLASH_CMD_WRITE_TO_BUFFER 0xE8
80#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0
wdenk2cefd152004-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
wdenked2ac4b2004-03-14 18:23:55 +000096#define AMD_CMD_UNLOCK_START 0xAA
97#define AMD_CMD_UNLOCK_ACK 0x55
Stefan Roesec865e6c2006-02-28 15:29:58 +010098#define AMD_CMD_WRITE_TO_BUFFER 0x25
99#define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29
wdenk2cefd152004-02-08 22:55:38 +0000100
101#define AMD_STATUS_TOGGLE 0x40
102#define AMD_STATUS_ERROR 0x20
Stefan Roesec865e6c2006-02-28 15:29:58 +0100103
Stefan Roese12797482006-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
wdenk2cefd152004-02-08 22:55:38 +0000108#define FLASH_OFFSET_CFI 0x55
Wolfgang Denkafa0dd02006-12-27 01:26:13 +0100109#define FLASH_OFFSET_CFI_ALT 0x555
wdenk2cefd152004-02-08 22:55:38 +0000110#define FLASH_OFFSET_CFI_RESP 0x10
wdenke65527f2004-02-12 00:47:09 +0000111#define FLASH_OFFSET_PRIMARY_VENDOR 0x13
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100112/* extended query table primary address */
113#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15
wdenk2cefd152004-02-08 22:55:38 +0000114#define FLASH_OFFSET_WTOUT 0x1F
wdenke65527f2004-02-12 00:47:09 +0000115#define FLASH_OFFSET_WBTOUT 0x20
wdenk2cefd152004-02-08 22:55:38 +0000116#define FLASH_OFFSET_ETOUT 0x21
wdenke65527f2004-02-12 00:47:09 +0000117#define FLASH_OFFSET_CETOUT 0x22
wdenk2cefd152004-02-08 22:55:38 +0000118#define FLASH_OFFSET_WMAX_TOUT 0x23
wdenke65527f2004-02-12 00:47:09 +0000119#define FLASH_OFFSET_WBMAX_TOUT 0x24
wdenk2cefd152004-02-08 22:55:38 +0000120#define FLASH_OFFSET_EMAX_TOUT 0x25
wdenke65527f2004-02-12 00:47:09 +0000121#define FLASH_OFFSET_CEMAX_TOUT 0x26
wdenk2cefd152004-02-08 22:55:38 +0000122#define FLASH_OFFSET_SIZE 0x27
wdenke65527f2004-02-12 00:47:09 +0000123#define FLASH_OFFSET_INTERFACE 0x28
124#define FLASH_OFFSET_BUFFER_SIZE 0x2A
wdenk2cefd152004-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
wdenke65527f2004-02-12 00:47:09 +0000128#define FLASH_OFFSET_USER_PROTECTION 0x85
129#define FLASH_OFFSET_INTEL_PROTECTION 0x81
wdenk2cefd152004-02-08 22:55:38 +0000130
Stefan Roese12797482006-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
wdenk2cefd152004-02-08 22:55:38 +0000139
wdenk51242782004-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 Roese12797482006-11-13 13:55:24 +0100142# define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */
wdenk51242782004-12-18 22:35:43 +0000143#endif
144
wdenk2cefd152004-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 Roese12797482006-11-13 13:55:24 +0100152#define NUM_ERASE_REGIONS 4 /* max. number of erase regions */
wdenk2cefd152004-02-08 22:55:38 +0000153
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100154static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
Wolfgang Denkafa0dd02006-12-27 01:26:13 +0100155
Marian Balakowicz513b4a12005-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
wdenk2cefd152004-02-08 22:55:38 +0000161static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST;
Marian Balakowicz513b4a12005-10-11 19:09:42 +0200162flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */
163#endif
wdenk2cefd152004-02-08 22:55:38 +0000164
Stefan Roesec865e6c2006-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
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200172typedef unsigned long flash_sect_t;
wdenk2cefd152004-02-08 22:55:38 +0000173
Haavard Skinnemoen53baec72007-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 Skinnemoen21b95b42007-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 Hellstromcfd71382008-03-28 20:40:19 +0100242static u64 __flash_read64(void *addr)
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100243{
244 /* No architectures currently implement __raw_readq() */
245 return *(volatile u64 *)addr;
246}
247
Daniel Hellstromcfd71382008-03-28 20:40:19 +0100248u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
249
wdenk2cefd152004-02-08 22:55:38 +0000250/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000251 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200252#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
253static flash_info_t *flash_get_info(ulong base)
254{
255 int i;
256 flash_info_t * info = 0;
wdenk2cefd152004-02-08 22:55:38 +0000257
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200258 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 }
wdenk2cefd152004-02-08 22:55:38 +0000264
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200265 return i == CFG_MAX_FLASH_BANKS ? 0 : info;
266}
wdenk2cefd152004-02-08 22:55:38 +0000267#endif
268
Haavard Skinnemoene3ea1882007-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
wdenke65527f2004-02-12 00:47:09 +0000277/*-----------------------------------------------------------------------
278 * create an address based on the offset and the port width
279 */
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100280static inline void *
281flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
wdenke65527f2004-02-12 00:47:09 +0000282{
Haavard Skinnemoene3ea1882007-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);
wdenke65527f2004-02-12 00:47:09 +0000296}
297
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200298/*-----------------------------------------------------------------------
299 * make a proper sized command based on the port and chip widths
300 */
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400301static void flash_make_cmd (flash_info_t * info, ulong cmd, void *cmdbuf)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200302{
303 int i;
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400304 int cword_offset;
305 int cp_offset;
306 uchar val;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200307 uchar *cp = (uchar *) cmdbuf;
308
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400309 for (i = info->portwidth; i > 0; i--){
310 cword_offset = (info->portwidth-i)%info->chipwidth;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200311#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400312 cp_offset = info->portwidth - i;
313 val = *((uchar*)&cmd + cword_offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200314#else
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400315 cp_offset = i - 1;
316 val = *((uchar*)&cmd + sizeof(ulong) - cword_offset - 1);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200317#endif
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400318 cp[cp_offset] = (cword_offset >= sizeof(ulong)) ? 0x00 : val;
319 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200320}
321
wdenk2cefd152004-02-08 22:55:38 +0000322#ifdef DEBUG
wdenke65527f2004-02-12 00:47:09 +0000323/*-----------------------------------------------------------------------
324 * Debug support
325 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100326static void print_longlong (char *str, unsigned long long data)
wdenk2cefd152004-02-08 22:55:38 +0000327{
328 int i;
329 char *cp;
wdenke65527f2004-02-12 00:47:09 +0000330
331 cp = (unsigned char *) &data;
332 for (i = 0; i < 8; i++)
333 sprintf (&str[i * 2], "%2.2x", *cp++);
wdenk2cefd152004-02-08 22:55:38 +0000334}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200335
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100336static void flash_printqry (struct cfi_qry *qry)
wdenke65527f2004-02-12 00:47:09 +0000337{
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100338 u8 *p = (u8 *)qry;
wdenke65527f2004-02-12 00:47:09 +0000339 int x, y;
340
Haavard Skinnemoen53baec72007-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(" ");
wdenke65527f2004-02-12 00:47:09 +0000346 for (y = 0; y < 16; y++) {
Haavard Skinnemoen53baec72007-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(".");
wdenke65527f2004-02-12 00:47:09 +0000352 }
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100353 debug("\n");
wdenke65527f2004-02-12 00:47:09 +0000354 }
355}
wdenk2cefd152004-02-08 22:55:38 +0000356#endif
357
358
359/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000360 * read a character at a port width address
361 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100362static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000363{
364 uchar *cp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100365 uchar retval;
wdenke65527f2004-02-12 00:47:09 +0000366
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100367 cp = flash_map (info, 0, offset);
Heiko Schocher800db312007-01-19 18:05:26 +0100368#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100369 retval = flash_read8(cp);
wdenke65527f2004-02-12 00:47:09 +0000370#else
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100371 retval = flash_read8(cp + info->portwidth - 1);
wdenke65527f2004-02-12 00:47:09 +0000372#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100373 flash_unmap (info, 0, offset, cp);
374 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000375}
376
377/*-----------------------------------------------------------------------
Tor Krill7f2a3052008-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 Roese12797482006-11-13 13:55:24 +0100392 * read a long word by picking the least significant byte of each maximum
wdenk2cefd152004-02-08 22:55:38 +0000393 * port size word. Swap for ppc format.
394 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100395static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
396 uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000397{
wdenke65527f2004-02-12 00:47:09 +0000398 uchar *addr;
399 ulong retval;
400
401#ifdef DEBUG
402 int x;
403#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100404 addr = flash_map (info, sect, offset);
wdenk2cefd152004-02-08 22:55:38 +0000405
wdenke65527f2004-02-12 00:47:09 +0000406#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 Skinnemoene3ea1882007-12-13 12:56:34 +0100410 debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
wdenke65527f2004-02-12 00:47:09 +0000411 }
412#endif
Heiko Schocher800db312007-01-19 18:05:26 +0100413#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoene3ea1882007-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));
wdenke65527f2004-02-12 00:47:09 +0000418#else
Haavard Skinnemoene3ea1882007-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)));
wdenke65527f2004-02-12 00:47:09 +0000423#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100424 flash_unmap(info, sect, offset, addr);
425
wdenke65527f2004-02-12 00:47:09 +0000426 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000427}
428
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200429/*
430 * Write a proper sized command to the correct address
Michael Schwingen73d044d2007-12-07 23:35:02 +0100431 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200432static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400433 uint offset, ulong cmd)
Michael Schwingen73d044d2007-12-07 23:35:02 +0100434{
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100435
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100436 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200437 cfiword_t cword;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100438
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100439 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200440 flash_make_cmd (info, cmd, &cword);
441 switch (info->portwidth) {
442 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100443 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200444 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100445 flash_write8(cword.c, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200446 break;
447 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100448 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200449 cmd, cword.w,
450 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100451 flash_write16(cword.w, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200452 break;
453 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100454 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200455 cmd, cword.l,
456 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100457 flash_write32(cword.l, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200458 break;
459 case FLASH_CFI_64BIT:
460#ifdef DEBUG
461 {
462 char str[20];
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100463
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200464 print_longlong (str, cword.ll);
465
466 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100467 addr, cmd, str,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200468 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100469 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200470#endif
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100471 flash_write64(cword.ll, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200472 break;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100473 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200474
475 /* Ensure all the instructions are fully finished */
476 sync();
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100477
478 flash_unmap(info, sect, offset, addr);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100479}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200480
481static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
Michael Schwingen73d044d2007-12-07 23:35:02 +0100482{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200483 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);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100485}
Michael Schwingen73d044d2007-12-07 23:35:02 +0100486
487/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000488 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200489static int flash_isequal (flash_info_t * info, flash_sect_t sect,
490 uint offset, uchar cmd)
wdenk2cefd152004-02-08 22:55:38 +0000491{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100492 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200493 cfiword_t cword;
494 int retval;
wdenk2cefd152004-02-08 22:55:38 +0000495
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100496 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200497 flash_make_cmd (info, cmd, &cword);
Stefan Roeseefef95b2006-04-01 13:41:03 +0200498
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100499 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200500 switch (info->portwidth) {
501 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100502 debug ("is= %x %x\n", flash_read8(addr), cword.c);
503 retval = (flash_read8(addr) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200504 break;
505 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-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 Skinnemoen6dd763c2007-10-06 18:55:36 +0200508 break;
509 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-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 Skinnemoen6dd763c2007-10-06 18:55:36 +0200512 break;
513 case FLASH_CFI_64BIT:
514#ifdef DEBUG
515 {
516 char str1[20];
517 char str2[20];
Michael Schwingen73d044d2007-12-07 23:35:02 +0100518
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100519 print_longlong (str1, flash_read64(addr));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200520 print_longlong (str2, cword.ll);
521 debug ("is= %s %s\n", str1, str2);
wdenk2cefd152004-02-08 22:55:38 +0000522 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200523#endif
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100524 retval = (flash_read64(addr) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200525 break;
526 default:
527 retval = 0;
528 break;
529 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100530 flash_unmap(info, sect, offset, addr);
531
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200532 return retval;
533}
Stefan Roeseefef95b2006-04-01 13:41:03 +0200534
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200535/*-----------------------------------------------------------------------
536 */
537static int flash_isset (flash_info_t * info, flash_sect_t sect,
538 uint offset, uchar cmd)
539{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100540 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200541 cfiword_t cword;
542 int retval;
Stefan Roeseefef95b2006-04-01 13:41:03 +0200543
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100544 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200545 flash_make_cmd (info, cmd, &cword);
546 switch (info->portwidth) {
547 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100548 retval = ((flash_read8(addr) & cword.c) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200549 break;
550 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100551 retval = ((flash_read16(addr) & cword.w) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200552 break;
553 case FLASH_CFI_32BIT:
Stefan Roesed4e37c02008-01-02 14:05:37 +0100554 retval = ((flash_read32(addr) & cword.l) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200555 break;
556 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100557 retval = ((flash_read64(addr) & cword.ll) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200558 break;
559 default:
560 retval = 0;
561 break;
562 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100563 flash_unmap(info, sect, offset, addr);
564
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200565 return retval;
566}
Stefan Roeseefef95b2006-04-01 13:41:03 +0200567
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200568/*-----------------------------------------------------------------------
569 */
570static int flash_toggle (flash_info_t * info, flash_sect_t sect,
571 uint offset, uchar cmd)
572{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100573 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200574 cfiword_t cword;
575 int retval;
wdenke85b7a52004-10-10 22:16:06 +0000576
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100577 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200578 flash_make_cmd (info, cmd, &cword);
579 switch (info->portwidth) {
580 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100581 retval = ((flash_read8(addr) & cword.c) !=
582 (flash_read8(addr) & cword.c));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200583 break;
584 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100585 retval = ((flash_read16(addr) & cword.w) !=
586 (flash_read16(addr) & cword.w));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200587 break;
588 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100589 retval = ((flash_read32(addr) & cword.l) !=
590 (flash_read32(addr) & cword.l));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200591 break;
592 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100593 retval = ((flash_read64(addr) & cword.ll) !=
594 (flash_read64(addr) & cword.ll));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200595 break;
596 default:
597 retval = 0;
598 break;
599 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100600 flash_unmap(info, sect, offset, addr);
601
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200602 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000603}
604
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200605/*
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.
wdenk2cefd152004-02-08 22:55:38 +0000610 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200611static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
wdenk5c71a7a2005-05-16 15:23:22 +0000612{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200613 int retval;
wdenk5c71a7a2005-05-16 15:23:22 +0000614
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200615 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:
622#ifdef CONFIG_FLASH_CFI_LEGACY
623 case CFI_CMDSET_AMD_LEGACY:
624#endif
625 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
626 break;
627 default:
628 retval = 0;
wdenk5c71a7a2005-05-16 15:23:22 +0000629 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200630 debug ("flash_is_busy: %d\n", retval);
631 return retval;
wdenk5c71a7a2005-05-16 15:23:22 +0000632}
633
634/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200635 * wait for XSR.7 to be set. Time out with an error if it does not.
636 * This routine does not set the flash to read-array mode.
wdenk5c71a7a2005-05-16 15:23:22 +0000637 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200638static int flash_status_check (flash_info_t * info, flash_sect_t sector,
639 ulong tout, char *prompt)
wdenk2cefd152004-02-08 22:55:38 +0000640{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200641 ulong start;
wdenk2cefd152004-02-08 22:55:38 +0000642
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200643#if CFG_HZ != 1000
644 tout *= CFG_HZ/1000;
645#endif
wdenk2cefd152004-02-08 22:55:38 +0000646
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200647 /* Wait for command completion */
648 start = get_timer (0);
649 while (flash_is_busy (info, sector)) {
650 if (get_timer (start) > tout) {
651 printf ("Flash %s timeout at address %lx data %lx\n",
652 prompt, info->start[sector],
653 flash_read_long (info, sector, 0));
654 flash_write_cmd (info, sector, 0, info->cmd_reset);
655 return ERR_TIMOUT;
wdenk2cefd152004-02-08 22:55:38 +0000656 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200657 udelay (1); /* also triggers watchdog */
wdenk2cefd152004-02-08 22:55:38 +0000658 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200659 return ERR_OK;
660}
wdenk2cefd152004-02-08 22:55:38 +0000661
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200662/*-----------------------------------------------------------------------
663 * Wait for XSR.7 to be set, if it times out print an error, otherwise
664 * do a full status check.
665 *
666 * This routine sets the flash to read-array mode.
667 */
668static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
669 ulong tout, char *prompt)
670{
671 int retcode;
wdenk2cefd152004-02-08 22:55:38 +0000672
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200673 retcode = flash_status_check (info, sector, tout, prompt);
674 switch (info->vendor) {
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");
wdenk2cefd152004-02-08 22:55:38 +0000692 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200693 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");
wdenk2cefd152004-02-08 22:55:38 +0000699 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200700 flash_write_cmd (info, sector, 0, info->cmd_reset);
701 break;
702 default:
703 break;
wdenk2cefd152004-02-08 22:55:38 +0000704 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200705 return retcode;
wdenk2cefd152004-02-08 22:55:38 +0000706}
707
708/*-----------------------------------------------------------------------
709 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200710static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
wdenk2cefd152004-02-08 22:55:38 +0000711{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200712#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
713 unsigned short w;
714 unsigned int l;
715 unsigned long long ll;
716#endif
wdenk2cefd152004-02-08 22:55:38 +0000717
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200718 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;
727#else
728 cword->w = (cword->w << 8) | c;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100729#endif
Haavard Skinnemoen6dd763c2007-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;
738#endif
739 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;
Stefan Roese12797482006-11-13 13:55:24 +0100749 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200750}
wdenk2cefd152004-02-08 22:55:38 +0000751
Haavard Skinnemoen6dd763c2007-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
754 */
755static flash_sect_t find_sector (flash_info_t * info, ulong addr)
756{
757 flash_sect_t sector;
wdenk2cefd152004-02-08 22:55:38 +0000758
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200759 for (sector = info->sector_count - 1; sector >= 0; sector--) {
760 if (addr >= info->start[sector])
761 break;
wdenk2cefd152004-02-08 22:55:38 +0000762 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200763 return sector;
wdenk2cefd152004-02-08 22:55:38 +0000764}
765
766/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000767 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200768static int flash_write_cfiword (flash_info_t * info, ulong dest,
769 cfiword_t cword)
wdenk2cefd152004-02-08 22:55:38 +0000770{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100771 void *dstaddr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200772 int flag;
wdenk2cefd152004-02-08 22:55:38 +0000773
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100774 dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
wdenk2cefd152004-02-08 22:55:38 +0000775
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200776 /* Check if Flash is (sufficiently) erased */
777 switch (info->portwidth) {
778 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100779 flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200780 break;
781 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100782 flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200783 break;
784 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100785 flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200786 break;
787 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100788 flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200789 break;
790 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100791 flag = 0;
792 break;
wdenk2cefd152004-02-08 22:55:38 +0000793 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100794 if (!flag) {
795 unmap_physmem(dstaddr, info->portwidth);
Stefan Roese707c1462007-12-27 07:50:54 +0100796 return ERR_NOT_ERASED;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100797 }
wdenk2cefd152004-02-08 22:55:38 +0000798
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200799 /* Disable interrupts which might cause a timeout here */
800 flag = disable_interrupts ();
Stefan Roesec865e6c2006-02-28 15:29:58 +0100801
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200802 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:
812#endif
813 flash_unlock_seq (info, 0);
814 flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
815 break;
wdenk2cefd152004-02-08 22:55:38 +0000816 }
817
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200818 switch (info->portwidth) {
819 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100820 flash_write8(cword.c, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200821 break;
822 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100823 flash_write16(cword.w, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200824 break;
825 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100826 flash_write32(cword.l, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200827 break;
828 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100829 flash_write64(cword.ll, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200830 break;
wdenk2cefd152004-02-08 22:55:38 +0000831 }
832
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200833 /* re-enable interrupts if necessary */
834 if (flag)
835 enable_interrupts ();
wdenk2cefd152004-02-08 22:55:38 +0000836
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100837 unmap_physmem(dstaddr, info->portwidth);
838
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200839 return flash_full_status_check (info, find_sector (info, dest),
840 info->write_tout, "write");
wdenk2cefd152004-02-08 22:55:38 +0000841}
842
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200843#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenk2cefd152004-02-08 22:55:38 +0000844
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200845static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
846 int len)
wdenk2cefd152004-02-08 22:55:38 +0000847{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200848 flash_sect_t sector;
849 int cnt;
850 int retcode;
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100851 void *src = cp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100852 void *dst = map_physmem(dest, len, MAP_NOCACHE);
Stefan Roese707c1462007-12-27 07:50:54 +0100853 void *dst2 = dst;
854 int flag = 0;
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200855 uint offset = 0;
856 unsigned int shift;
Stefan Roese707c1462007-12-27 07:50:54 +0100857
858 switch (info->portwidth) {
859 case FLASH_CFI_8BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200860 shift = 0;
Stefan Roese707c1462007-12-27 07:50:54 +0100861 break;
862 case FLASH_CFI_16BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200863 shift = 1;
Stefan Roese707c1462007-12-27 07:50:54 +0100864 break;
865 case FLASH_CFI_32BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200866 shift = 2;
Stefan Roese707c1462007-12-27 07:50:54 +0100867 break;
868 case FLASH_CFI_64BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200869 shift = 3;
Stefan Roese707c1462007-12-27 07:50:54 +0100870 break;
871 default:
872 retcode = ERR_INVAL;
873 goto out_unmap;
874 }
875
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200876 cnt = len >> shift;
877
Stefan Roese707c1462007-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 }
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100906
Stefan Roese707c1462007-12-27 07:50:54 +0100907 src = cp;
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100908 sector = find_sector (info, dest);
wdenke65527f2004-02-12 00:47:09 +0000909
910 switch (info->vendor) {
wdenk2cefd152004-02-08 22:55:38 +0000911 case CFI_CMDSET_INTEL_STANDARD:
912 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen6dd763c2007-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 Liakhovetski183284f2008-04-03 13:36:02 +0200921 cnt = len >> shift;
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400922 flash_write_cmd (info, sector, 0, cnt - 1);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200923 while (cnt-- > 0) {
924 switch (info->portwidth) {
925 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100926 flash_write8(flash_read8(src), dst);
927 src += 1, dst += 1;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200928 break;
929 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100930 flash_write16(flash_read16(src), dst);
931 src += 2, dst += 2;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200932 break;
933 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100934 flash_write32(flash_read32(src), dst);
935 src += 4, dst += 4;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200936 break;
937 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100938 flash_write64(flash_read64(src), dst);
939 src += 8, dst += 8;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200940 break;
941 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100942 retcode = ERR_INVAL;
943 goto out_unmap;
Haavard Skinnemoen6dd763c2007-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 Skinnemoene3ea1882007-12-13 12:56:34 +0100952
953 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200954
wdenk2cefd152004-02-08 22:55:38 +0000955 case CFI_CMDSET_AMD_STANDARD:
956 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200957 flash_unlock_seq(info,0);
Guennadi Liakhovetski183284f2008-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 Leoenenkoc47c0d42008-05-07 21:24:44 +0400964 flash_write_cmd(info, sector, offset, cnt - 1);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200965
966 switch (info->portwidth) {
967 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100968 while (cnt-- > 0) {
969 flash_write8(flash_read8(src), dst);
970 src += 1, dst += 1;
971 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200972 break;
973 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100974 while (cnt-- > 0) {
975 flash_write16(flash_read16(src), dst);
976 src += 2, dst += 2;
977 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200978 break;
979 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100980 while (cnt-- > 0) {
981 flash_write32(flash_read32(src), dst);
982 src += 4, dst += 4;
983 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200984 break;
985 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100986 while (cnt-- > 0) {
987 flash_write64(flash_read64(src), dst);
988 src += 8, dst += 8;
989 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200990 break;
991 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100992 retcode = ERR_INVAL;
993 goto out_unmap;
Haavard Skinnemoen6dd763c2007-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 Skinnemoene3ea1882007-12-13 12:56:34 +01001000 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001001
wdenk2cefd152004-02-08 22:55:38 +00001002 default:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001003 debug ("Unknown Command Set\n");
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001004 retcode = ERR_INVAL;
1005 break;
wdenk2cefd152004-02-08 22:55:38 +00001006 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001007
1008out_unmap:
1009 unmap_physmem(dst, len);
1010 return retcode;
wdenk2cefd152004-02-08 22:55:38 +00001011}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001012#endif /* CFG_FLASH_USE_BUFFER_WRITE */
1013
wdenke65527f2004-02-12 00:47:09 +00001014
wdenk2cefd152004-02-08 22:55:38 +00001015/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +00001016 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001017int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk2cefd152004-02-08 22:55:38 +00001018{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001019 int rcode = 0;
1020 int prot;
1021 flash_sect_t sect;
wdenk2cefd152004-02-08 22:55:38 +00001022
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001023 if (info->flash_id != FLASH_MAN_CFI) {
1024 puts ("Can't erase unknown flash type - aborted\n");
1025 return 1;
1026 }
1027 if ((s_first < 0) || (s_first > s_last)) {
1028 puts ("- no sectors to erase\n");
1029 return 1;
1030 }
Stefan Roeseefef95b2006-04-01 13:41:03 +02001031
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001032 prot = 0;
1033 for (sect = s_first; sect <= s_last; ++sect) {
1034 if (info->protect[sect]) {
1035 prot++;
wdenk2cefd152004-02-08 22:55:38 +00001036 }
1037 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001038 if (prot) {
1039 printf ("- Warning: %d protected sectors will not be erased!\n",
1040 prot);
1041 } else {
1042 putc ('\n');
1043 }
wdenke65527f2004-02-12 00:47:09 +00001044
wdenke65527f2004-02-12 00:47:09 +00001045
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001046 for (sect = s_first; sect <= s_last; sect++) {
1047 if (info->protect[sect] == 0) { /* not protected */
1048 switch (info->vendor) {
1049 case CFI_CMDSET_INTEL_STANDARD:
1050 case CFI_CMDSET_INTEL_EXTENDED:
1051 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);
1057 break;
1058 case CFI_CMDSET_AMD_STANDARD:
1059 case CFI_CMDSET_AMD_EXTENDED:
1060 flash_unlock_seq (info, sect);
1061 flash_write_cmd (info, sect,
1062 info->addr_unlock1,
1063 AMD_CMD_ERASE_START);
1064 flash_unlock_seq (info, sect);
1065 flash_write_cmd (info, sect, 0,
1066 AMD_CMD_ERASE_SECTOR);
1067 break;
1068#ifdef CONFIG_FLASH_CFI_LEGACY
1069 case CFI_CMDSET_AMD_LEGACY:
1070 flash_unlock_seq (info, 0);
1071 flash_write_cmd (info, 0, info->addr_unlock1,
1072 AMD_CMD_ERASE_START);
1073 flash_unlock_seq (info, 0);
1074 flash_write_cmd (info, sect, 0,
1075 AMD_CMD_ERASE_SECTOR);
1076 break;
1077#endif
1078 default:
1079 debug ("Unkown flash vendor %d\n",
1080 info->vendor);
1081 break;
wdenke65527f2004-02-12 00:47:09 +00001082 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001083
1084 if (flash_full_status_check
1085 (info, sect, info->erase_blk_tout, "erase")) {
1086 rcode = 1;
1087 } else
1088 putc ('.');
wdenk2cefd152004-02-08 22:55:38 +00001089 }
wdenk2cefd152004-02-08 22:55:38 +00001090 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001091 puts (" done\n");
1092 return rcode;
wdenk2cefd152004-02-08 22:55:38 +00001093}
wdenke65527f2004-02-12 00:47:09 +00001094
wdenk2cefd152004-02-08 22:55:38 +00001095/*-----------------------------------------------------------------------
1096 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001097void flash_print_info (flash_info_t * info)
wdenk2cefd152004-02-08 22:55:38 +00001098{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001099 int i;
wdenk369d43d2004-03-14 14:09:05 +00001100
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001101 if (info->flash_id != FLASH_MAN_CFI) {
1102 puts ("missing or unknown FLASH type\n");
1103 return;
1104 }
1105
1106 printf ("%s FLASH (%d x %d)",
1107 info->name,
1108 (info->portwidth << 3), (info->chipwidth << 3));
1109 if (info->size < 1024*1024)
1110 printf (" Size: %ld kB in %d Sectors\n",
1111 info->size >> 10, info->sector_count);
1112 else
1113 printf (" Size: %ld MB in %d Sectors\n",
1114 info->size >> 20, info->sector_count);
1115 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;
1129#ifdef CONFIG_FLASH_CFI_LEGACY
1130 case CFI_CMDSET_AMD_LEGACY:
1131 printf ("AMD Legacy");
1132 break;
wdenk369d43d2004-03-14 14:09:05 +00001133#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001134 default:
1135 printf ("Unknown (%d)", info->vendor);
1136 break;
wdenk2cefd152004-02-08 22:55:38 +00001137 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001138 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",
1144 info->erase_blk_tout,
1145 info->write_tout);
1146 if (info->buffer_size > 1) {
1147 printf (" Buffer write timeout: %ld ms, "
1148 "buffer size: %d bytes\n",
1149 info->buffer_write_tout,
1150 info->buffer_size);
1151 }
wdenk2cefd152004-02-08 22:55:38 +00001152
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001153 puts ("\n Sector Start Addresses:");
1154 for (i = 0; i < info->sector_count; ++i) {
1155 if ((i % 5) == 0)
1156 printf ("\n");
1157#ifdef CFG_FLASH_EMPTY_INFO
1158 int k;
1159 int size;
1160 int erased;
1161 volatile unsigned long *flash;
wdenk2cefd152004-02-08 22:55:38 +00001162
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001163 /*
1164 * Check if whole sector is erased
1165 */
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001166 size = flash_sector_size(info, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001167 erased = 1;
1168 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 }
wdenke65527f2004-02-12 00:47:09 +00001176
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001177 /* print empty and read-only info */
1178 printf (" %08lX %c %s ",
1179 info->start[i],
1180 erased ? 'E' : ' ',
1181 info->protect[i] ? "RO" : " ");
1182#else /* ! CFG_FLASH_EMPTY_INFO */
1183 printf (" %08lX %s ",
1184 info->start[i],
1185 info->protect[i] ? "RO" : " ");
wdenke65527f2004-02-12 00:47:09 +00001186#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001187 }
1188 putc ('\n');
1189 return;
wdenk2cefd152004-02-08 22:55:38 +00001190}
1191
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001192/*-----------------------------------------------------------------------
Jerry Van Barenaae73572008-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 Roese7758c162008-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 Barenaae73572008-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 Roese7758c162008-03-19 07:09:26 +01001209#else
1210#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1211#endif
Jerry Van Barenaae73572008-03-08 13:48:01 -05001212
1213/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001214 * Copy memory to flash, returns:
1215 * 0 - OK
1216 * 1 - write timeout
1217 * 2 - Flash not erased
wdenk2cefd152004-02-08 22:55:38 +00001218 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001219int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk2cefd152004-02-08 22:55:38 +00001220{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001221 ulong wp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001222 uchar *p;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001223 int aln;
wdenk2cefd152004-02-08 22:55:38 +00001224 cfiword_t cword;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001225 int i, rc;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001226#ifdef CFG_FLASH_USE_BUFFER_WRITE
1227 int buffered_size;
wdenk2cefd152004-02-08 22:55:38 +00001228#endif
Jerry Van Barenaae73572008-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
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001243 /* get lower aligned address */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001244 wp = (addr & ~(info->portwidth - 1));
Haiying Wangc123a382007-02-21 16:52:31 +01001245
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001246 /* handle unaligned start */
1247 if ((aln = addr - wp) != 0) {
1248 cword.l = 0;
Haavard Skinnemoene3ea1882007-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));
wdenk2cefd152004-02-08 22:55:38 +00001252
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001253 for (; (i < info->portwidth) && (cnt > 0); i++) {
1254 flash_add_byte (info, &cword, *src++);
1255 cnt--;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001256 }
Haavard Skinnemoene3ea1882007-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)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001263 return rc;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001264
1265 wp += i;
Stefan Roese7758c162008-03-19 07:09:26 +01001266 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001267 }
1268
1269 /* handle the aligned part */
1270#ifdef CFG_FLASH_USE_BUFFER_WRITE
1271 buffered_size = (info->portwidth / info->chipwidth);
1272 buffered_size *= info->buffer_size;
1273 while (cnt >= info->portwidth) {
1274 /* 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;
1290 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
1291 return rc;
1292 i -= i & (info->portwidth - 1);
1293 wp += i;
1294 src += i;
1295 cnt -= i;
Stefan Roese7758c162008-03-19 07:09:26 +01001296 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001297 }
1298#else
1299 while (cnt >= info->portwidth) {
1300 cword.l = 0;
1301 for (i = 0; i < info->portwidth; i++) {
1302 flash_add_byte (info, &cword, *src++);
1303 }
1304 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1305 return rc;
1306 wp += info->portwidth;
1307 cnt -= info->portwidth;
Stefan Roese7758c162008-03-19 07:09:26 +01001308 FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001309 }
1310#endif /* CFG_FLASH_USE_BUFFER_WRITE */
Jerry Van Barenaae73572008-03-08 13:48:01 -05001311
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001312 if (cnt == 0) {
1313 return (0);
1314 }
1315
1316 /*
1317 * handle unaligned tail bytes
1318 */
1319 cword.l = 0;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001320 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1321 for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001322 flash_add_byte (info, &cword, *src++);
1323 --cnt;
1324 }
Haavard Skinnemoene3ea1882007-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);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001328
1329 return flash_write_cfiword (info, wp, cword);
wdenk2cefd152004-02-08 22:55:38 +00001330}
wdenke65527f2004-02-12 00:47:09 +00001331
wdenk2cefd152004-02-08 22:55:38 +00001332/*-----------------------------------------------------------------------
1333 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001334#ifdef CFG_FLASH_PROTECTION
1335
1336int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk2cefd152004-02-08 22:55:38 +00001337{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001338 int retcode = 0;
wdenke65527f2004-02-12 00:47:09 +00001339
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001340 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);
1344 else
1345 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
wdenk2cefd152004-02-08 22:55:38 +00001346
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001347 if ((retcode =
1348 flash_full_status_check (info, sector, info->erase_blk_tout,
1349 prot ? "protect" : "unprotect")) == 0) {
wdenke65527f2004-02-12 00:47:09 +00001350
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001351 info->protect[sector] = prot;
1352
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)) {
1358 flash_sect_t i;
1359
1360 for (i = 0; i < info->sector_count; i++) {
1361 if (info->protect[i])
1362 flash_real_protect (info, i, 1);
1363 }
wdenk2cefd152004-02-08 22:55:38 +00001364 }
wdenk2cefd152004-02-08 22:55:38 +00001365 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001366 return retcode;
wdenk2cefd152004-02-08 22:55:38 +00001367}
wdenke65527f2004-02-12 00:47:09 +00001368
wdenk2cefd152004-02-08 22:55:38 +00001369/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001370 * flash_read_user_serial - read the OneTimeProgramming cells
wdenk2cefd152004-02-08 22:55:38 +00001371 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001372void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
1373 int len)
wdenk2cefd152004-02-08 22:55:38 +00001374{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001375 uchar *src;
1376 uchar *dst;
wdenke65527f2004-02-12 00:47:09 +00001377
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001378 dst = buffer;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001379 src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001380 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1381 memcpy (dst, src + offset, len);
1382 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001383 flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
wdenk2cefd152004-02-08 22:55:38 +00001384}
1385
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001386/*
1387 * flash_read_factory_serial - read the device Id from the protection area
wdenk2cefd152004-02-08 22:55:38 +00001388 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001389void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
1390 int len)
wdenk2cefd152004-02-08 22:55:38 +00001391{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001392 uchar *src;
wdenke65527f2004-02-12 00:47:09 +00001393
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001394 src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001395 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1396 memcpy (buffer, src + offset, len);
1397 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001398 flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
wdenk2cefd152004-02-08 22:55:38 +00001399}
1400
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001401#endif /* CFG_FLASH_PROTECTION */
1402
Haavard Skinnemoenc4d478b2007-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}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001419
wdenk2cefd152004-02-08 22:55:38 +00001420/*-----------------------------------------------------------------------
Stefan Roese12797482006-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 Skinnemoenc4d478b2007-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 Krill7f2a3052008-03-28 11:29:10 +01001462
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001463 info->manufacturer_id = flash_read_uchar (info,
1464 FLASH_OFFSET_MANUFACTURER_ID);
Tor Krill7f2a3052008-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 Skinnemoenc4d478b2007-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 Skinnemoenc4d478b2007-12-14 15:36:17 +01001496 return 0;
1497}
1498
1499#ifdef CONFIG_FLASH_CFI_LEGACY
Stefan Roese12797482006-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 Schwingen5fb0aa42008-01-12 20:29:47 +01001509 cmdset_intel_read_jedec_ids(info);
Stefan Roese12797482006-11-13 13:55:24 +01001510 break;
1511 case CFI_CMDSET_AMD_STANDARD:
1512 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen5fb0aa42008-01-12 20:29:47 +01001513 cmdset_amd_read_jedec_ids(info);
Stefan Roese12797482006-11-13 13:55:24 +01001514 break;
1515 default:
1516 break;
1517 }
1518}
1519
1520/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001521 * 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.
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001524 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001525static int flash_detect_legacy(ulong base, int banknum)
wdenk2cefd152004-02-08 22:55:38 +00001526{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001527 flash_info_t *info = &flash_info[banknum];
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001528
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001529 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;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001538
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001539 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
1583/*-----------------------------------------------------------------------
1584 * detect if flash is compatible with the Common Flash Interface (CFI)
1585 * http://www.jedec.org/download/search/jesd68.pdf
1586 */
Haavard Skinnemoen53baec72007-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)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001598{
1599 int cfi_offset;
1600
Michael Schwingen4661cf72008-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 Skinnemoen6dd763c2007-10-06 18:55:36 +02001607 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 Skinnemoen53baec72007-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 Skinnemoen6dd763c2007-10-06 18:55:36 +02001619 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;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001630 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 Skinnemoen53baec72007-12-14 15:36:16 +01001655static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001656{
wdenke65527f2004-02-12 00:47:09 +00001657 debug ("flash detect cfi\n");
wdenk2cefd152004-02-08 22:55:38 +00001658
Stefan Roesec865e6c2006-02-28 15:29:58 +01001659 for (info->portwidth = CFG_FLASH_CFI_WIDTH;
wdenke65527f2004-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 Skinnemoend523e392007-12-13 12:56:28 +01001663 info->chipwidth <<= 1)
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001664 if (__flash_detect_cfi(info, qry))
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001665 return 1;
wdenk2cefd152004-02-08 22:55:38 +00001666 }
wdenke65527f2004-02-12 00:47:09 +00001667 debug ("not found\n");
wdenk2cefd152004-02-08 22:55:38 +00001668 return 0;
1669}
wdenke65527f2004-02-12 00:47:09 +00001670
wdenk2cefd152004-02-08 22:55:38 +00001671/*
Haavard Skinnemoen750ea7f2007-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/*
wdenk2cefd152004-02-08 22:55:38 +00001715 * The following code cannot be run from FLASH!
1716 *
1717 */
Marian Balakowicz513b4a12005-10-11 19:09:42 +02001718ulong flash_get_size (ulong base, int banknum)
wdenk2cefd152004-02-08 22:55:38 +00001719{
wdenke65527f2004-02-12 00:47:09 +00001720 flash_info_t *info = &flash_info[banknum];
wdenk2cefd152004-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;
wdenke65527f2004-02-12 00:47:09 +00001727 int erase_region_size;
1728 int erase_region_count;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001729 struct cfi_qry qry;
Stefan Roese12797482006-11-13 13:55:24 +01001730
1731 info->ext_addr = 0;
1732 info->cfi_version = 0;
Stefan Roeseefef95b2006-04-01 13:41:03 +02001733#ifdef CFG_FLASH_PROTECTION
Stefan Roeseefef95b2006-04-01 13:41:03 +02001734 info->legacy_unlock = 0;
1735#endif
wdenk2cefd152004-02-08 22:55:38 +00001736
1737 info->start[0] = base;
1738
Haavard Skinnemoen53baec72007-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 Roese12797482006-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 Skinnemoenc4d478b2007-12-14 15:36:17 +01001750
wdenke65527f2004-02-12 00:47:09 +00001751#ifdef DEBUG
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001752 flash_printqry (&qry);
wdenke65527f2004-02-12 00:47:09 +00001753#endif
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001754
wdenke65527f2004-02-12 00:47:09 +00001755 switch (info->vendor) {
wdenk2cefd152004-02-08 22:55:38 +00001756 case CFI_CMDSET_INTEL_STANDARD:
1757 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001758 cmdset_intel_init(info, &qry);
wdenk2cefd152004-02-08 22:55:38 +00001759 break;
1760 case CFI_CMDSET_AMD_STANDARD:
1761 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001762 cmdset_amd_init(info, &qry);
wdenk2cefd152004-02-08 22:55:38 +00001763 break;
Haavard Skinnemoenc4d478b2007-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;
wdenk2cefd152004-02-08 22:55:38 +00001774 }
wdenk6cfa84e2004-02-10 00:03:41 +00001775
Haavard Skinnemoen750ea7f2007-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
wdenke65527f2004-02-12 00:47:09 +00001786 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese12797482006-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
wdenk2cefd152004-02-08 22:55:38 +00001792 size_ratio = info->portwidth / info->chipwidth;
wdenke65527f2004-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 }
wdenke65527f2004-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);
wdenk2cefd152004-02-08 22:55:38 +00001802 sect_cnt = 0;
1803 sector = base;
wdenke65527f2004-02-12 00:47:09 +00001804 for (i = 0; i < num_erase_regions; i++) {
1805 if (i > NUM_ERASE_REGIONS) {
wdenke537b3b2004-02-23 23:54:43 +00001806 printf ("%d erase regions found, only %d used\n",
1807 num_erase_regions, NUM_ERASE_REGIONS);
wdenk2cefd152004-02-08 22:55:38 +00001808 break;
1809 }
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001810
Haavard Skinnemoenc4d478b2007-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 Skinnemoen53baec72007-12-14 15:36:16 +01001813
1814 erase_region_count = (tmp & 0xffff) + 1;
1815 tmp >>= 16;
wdenke65527f2004-02-12 00:47:09 +00001816 erase_region_size =
1817 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenkaeba06f2004-06-09 17:34:58 +00001818 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenke537b3b2004-02-23 23:54:43 +00001819 erase_region_count, erase_region_size);
wdenke65527f2004-02-12 00:47:09 +00001820 for (j = 0; j < erase_region_count; j++) {
Michael Schwingen73d044d2007-12-07 23:35:02 +01001821 if (sect_cnt >= CFG_MAX_FLASH_SECT) {
1822 printf("ERROR: too many flash sectors\n");
1823 break;
1824 }
wdenk2cefd152004-02-08 22:55:38 +00001825 info->start[sect_cnt] = sector;
1826 sector += (erase_region_size * size_ratio);
wdenk26c58432005-01-09 17:12:27 +00001827
1828 /*
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001829 * Only read protection status from
1830 * supported devices (intel...)
wdenk26c58432005-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 Skinnemoend523e392007-12-13 12:56:28 +01001841 /* default: not protected */
1842 info->protect[sect_cnt] = 0;
wdenk26c58432005-01-09 17:12:27 +00001843 }
1844
wdenk2cefd152004-02-08 22:55:38 +00001845 sect_cnt++;
1846 }
1847 }
1848
1849 info->sector_count = sect_cnt;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001850 info->size = 1 << qry.dev_size;
wdenk2cefd152004-02-08 22:55:38 +00001851 /* multiply the size by the number of chips */
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001852 info->size *= size_ratio;
Haavard Skinnemoen53baec72007-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 Skinnemoend523e392007-12-13 12:56:28 +01001855 info->erase_blk_tout = tmp *
Haavard Skinnemoen53baec72007-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 Skinnemoend523e392007-12-13 12:56:28 +01001860 /* round up when converting to ms */
Haavard Skinnemoen53baec72007-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 Skinnemoend523e392007-12-13 12:56:28 +01001864 /* round up when converting to ms */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001865 info->write_tout = (tmp + 999) / 1000;
wdenk2cefd152004-02-08 22:55:38 +00001866 info->flash_id = FLASH_MAN_CFI;
Haavard Skinnemoend523e392007-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;
wdenked2ac4b2004-03-14 18:23:55 +00001871 }
wdenk2cefd152004-02-08 22:55:38 +00001872 }
1873
Wolfgang Denka205a8f2005-09-25 16:41:22 +02001874 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenke65527f2004-02-12 00:47:09 +00001875 return (info->size);
wdenk2cefd152004-02-08 22:55:38 +00001876}
1877
wdenk2cefd152004-02-08 22:55:38 +00001878/*-----------------------------------------------------------------------
1879 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001880unsigned long flash_init (void)
wdenk2cefd152004-02-08 22:55:38 +00001881{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001882 unsigned long size = 0;
1883 int i;
Matthias Fuchs50431522008-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
wdenk2cefd152004-02-08 22:55:38 +00001890
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001891#ifdef CFG_FLASH_PROTECTION
1892 char *s = getenv("unlock");
Michael Schwingen73d044d2007-12-07 23:35:02 +01001893#endif
wdenk2cefd152004-02-08 22:55:38 +00001894
Haavard Skinnemoen6dd763c2007-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;
wdenk2cefd152004-02-08 22:55:38 +00001898
Haavard Skinnemoen6dd763c2007-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 */
1909 }
1910#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;
wdenk2cefd152004-02-08 22:55:38 +00001922
Haavard Skinnemoen6dd763c2007-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;
wdenk2cefd152004-02-08 22:55:38 +00001930
Haavard Skinnemoen6dd763c2007-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);
wdenk2cefd152004-02-08 22:55:38 +00001937
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001938 flash_info[i].legacy_unlock = 1;
wdenk2cefd152004-02-08 22:55:38 +00001939
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001940 /*
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]);
Stefan Roesec865e6c2006-02-28 15:29:58 +01001955 }
Stefan Roesec865e6c2006-02-28 15:29:58 +01001956 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001957#endif /* CFG_FLASH_PROTECTION */
1958 }
Stefan Roesec865e6c2006-02-28 15:29:58 +01001959
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001960 /* 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
Stefan Roesec865e6c2006-02-28 15:29:58 +01001967
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001968 /* 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
Stefan Roesec865e6c2006-02-28 15:29:58 +01001975
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001976 /* 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 Fuchs50431522008-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 Skinnemoen6dd763c2007-10-06 18:55:36 +02001994 return (size);
wdenk2cefd152004-02-08 22:55:38 +00001995}
Heiko Schocher3c58a992007-01-11 15:44:44 +01001996
wdenk2cefd152004-02-08 22:55:38 +00001997#endif /* CFG_FLASH_CFI */