blob: 68ab55f8a5fdf97aa6b3332337d8375d598750cf [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 */
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
wdenk2cefd152004-02-08 22:55:38 +0000314#ifdef DEBUG
wdenke65527f2004-02-12 00:47:09 +0000315/*-----------------------------------------------------------------------
316 * Debug support
317 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100318static void print_longlong (char *str, unsigned long long data)
wdenk2cefd152004-02-08 22:55:38 +0000319{
320 int i;
321 char *cp;
wdenke65527f2004-02-12 00:47:09 +0000322
323 cp = (unsigned char *) &data;
324 for (i = 0; i < 8; i++)
325 sprintf (&str[i * 2], "%2.2x", *cp++);
wdenk2cefd152004-02-08 22:55:38 +0000326}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200327
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100328static void flash_printqry (struct cfi_qry *qry)
wdenke65527f2004-02-12 00:47:09 +0000329{
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100330 u8 *p = (u8 *)qry;
wdenke65527f2004-02-12 00:47:09 +0000331 int x, y;
332
Haavard Skinnemoen53baec72007-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(" ");
wdenke65527f2004-02-12 00:47:09 +0000338 for (y = 0; y < 16; y++) {
Haavard Skinnemoen53baec72007-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(".");
wdenke65527f2004-02-12 00:47:09 +0000344 }
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100345 debug("\n");
wdenke65527f2004-02-12 00:47:09 +0000346 }
347}
wdenk2cefd152004-02-08 22:55:38 +0000348#endif
349
350
351/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000352 * read a character at a port width address
353 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100354static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000355{
356 uchar *cp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100357 uchar retval;
wdenke65527f2004-02-12 00:47:09 +0000358
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100359 cp = flash_map (info, 0, offset);
Heiko Schocher800db312007-01-19 18:05:26 +0100360#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100361 retval = flash_read8(cp);
wdenke65527f2004-02-12 00:47:09 +0000362#else
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100363 retval = flash_read8(cp + info->portwidth - 1);
wdenke65527f2004-02-12 00:47:09 +0000364#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100365 flash_unmap (info, 0, offset, cp);
366 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000367}
368
369/*-----------------------------------------------------------------------
Tor Krill7f2a3052008-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 Roese12797482006-11-13 13:55:24 +0100384 * read a long word by picking the least significant byte of each maximum
wdenk2cefd152004-02-08 22:55:38 +0000385 * port size word. Swap for ppc format.
386 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100387static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
388 uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000389{
wdenke65527f2004-02-12 00:47:09 +0000390 uchar *addr;
391 ulong retval;
392
393#ifdef DEBUG
394 int x;
395#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100396 addr = flash_map (info, sect, offset);
wdenk2cefd152004-02-08 22:55:38 +0000397
wdenke65527f2004-02-12 00:47:09 +0000398#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 Skinnemoene3ea1882007-12-13 12:56:34 +0100402 debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
wdenke65527f2004-02-12 00:47:09 +0000403 }
404#endif
Heiko Schocher800db312007-01-19 18:05:26 +0100405#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoene3ea1882007-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));
wdenke65527f2004-02-12 00:47:09 +0000410#else
Haavard Skinnemoene3ea1882007-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)));
wdenke65527f2004-02-12 00:47:09 +0000415#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100416 flash_unmap(info, sect, offset, addr);
417
wdenke65527f2004-02-12 00:47:09 +0000418 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000419}
420
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200421/*
422 * Write a proper sized command to the correct address
Michael Schwingen73d044d2007-12-07 23:35:02 +0100423 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200424static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
425 uint offset, uchar cmd)
Michael Schwingen73d044d2007-12-07 23:35:02 +0100426{
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100427
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100428 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200429 cfiword_t cword;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100430
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100431 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200432 flash_make_cmd (info, cmd, &cword);
433 switch (info->portwidth) {
434 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100435 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200436 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100437 flash_write8(cword.c, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200438 break;
439 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100440 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200441 cmd, cword.w,
442 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100443 flash_write16(cword.w, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200444 break;
445 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100446 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200447 cmd, cword.l,
448 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100449 flash_write32(cword.l, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200450 break;
451 case FLASH_CFI_64BIT:
452#ifdef DEBUG
453 {
454 char str[20];
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100455
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200456 print_longlong (str, cword.ll);
457
458 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100459 addr, cmd, str,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200460 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100461 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200462#endif
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100463 flash_write64(cword.ll, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200464 break;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100465 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200466
467 /* Ensure all the instructions are fully finished */
468 sync();
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100469
470 flash_unmap(info, sect, offset, addr);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100471}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200472
473static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
Michael Schwingen73d044d2007-12-07 23:35:02 +0100474{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200475 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);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100477}
Michael Schwingen73d044d2007-12-07 23:35:02 +0100478
479/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000480 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200481static int flash_isequal (flash_info_t * info, flash_sect_t sect,
482 uint offset, uchar cmd)
wdenk2cefd152004-02-08 22:55:38 +0000483{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100484 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200485 cfiword_t cword;
486 int retval;
wdenk2cefd152004-02-08 22:55:38 +0000487
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100488 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200489 flash_make_cmd (info, cmd, &cword);
Stefan Roeseefef95b2006-04-01 13:41:03 +0200490
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100491 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200492 switch (info->portwidth) {
493 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100494 debug ("is= %x %x\n", flash_read8(addr), cword.c);
495 retval = (flash_read8(addr) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200496 break;
497 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-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 Skinnemoen6dd763c2007-10-06 18:55:36 +0200500 break;
501 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-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 Skinnemoen6dd763c2007-10-06 18:55:36 +0200504 break;
505 case FLASH_CFI_64BIT:
506#ifdef DEBUG
507 {
508 char str1[20];
509 char str2[20];
Michael Schwingen73d044d2007-12-07 23:35:02 +0100510
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100511 print_longlong (str1, flash_read64(addr));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200512 print_longlong (str2, cword.ll);
513 debug ("is= %s %s\n", str1, str2);
wdenk2cefd152004-02-08 22:55:38 +0000514 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200515#endif
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100516 retval = (flash_read64(addr) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200517 break;
518 default:
519 retval = 0;
520 break;
521 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100522 flash_unmap(info, sect, offset, addr);
523
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200524 return retval;
525}
Stefan Roeseefef95b2006-04-01 13:41:03 +0200526
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200527/*-----------------------------------------------------------------------
528 */
529static int flash_isset (flash_info_t * info, flash_sect_t sect,
530 uint offset, uchar cmd)
531{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100532 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200533 cfiword_t cword;
534 int retval;
Stefan Roeseefef95b2006-04-01 13:41:03 +0200535
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100536 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200537 flash_make_cmd (info, cmd, &cword);
538 switch (info->portwidth) {
539 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100540 retval = ((flash_read8(addr) & cword.c) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200541 break;
542 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100543 retval = ((flash_read16(addr) & cword.w) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200544 break;
545 case FLASH_CFI_32BIT:
Stefan Roesed4e37c02008-01-02 14:05:37 +0100546 retval = ((flash_read32(addr) & cword.l) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200547 break;
548 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100549 retval = ((flash_read64(addr) & cword.ll) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200550 break;
551 default:
552 retval = 0;
553 break;
554 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100555 flash_unmap(info, sect, offset, addr);
556
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200557 return retval;
558}
Stefan Roeseefef95b2006-04-01 13:41:03 +0200559
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200560/*-----------------------------------------------------------------------
561 */
562static int flash_toggle (flash_info_t * info, flash_sect_t sect,
563 uint offset, uchar cmd)
564{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100565 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200566 cfiword_t cword;
567 int retval;
wdenke85b7a52004-10-10 22:16:06 +0000568
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100569 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200570 flash_make_cmd (info, cmd, &cword);
571 switch (info->portwidth) {
572 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100573 retval = ((flash_read8(addr) & cword.c) !=
574 (flash_read8(addr) & cword.c));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200575 break;
576 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100577 retval = ((flash_read16(addr) & cword.w) !=
578 (flash_read16(addr) & cword.w));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200579 break;
580 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100581 retval = ((flash_read32(addr) & cword.l) !=
582 (flash_read32(addr) & cword.l));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200583 break;
584 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100585 retval = ((flash_read64(addr) & cword.ll) !=
586 (flash_read64(addr) & cword.ll));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200587 break;
588 default:
589 retval = 0;
590 break;
591 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100592 flash_unmap(info, sect, offset, addr);
593
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200594 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000595}
596
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200597/*
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.
wdenk2cefd152004-02-08 22:55:38 +0000602 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200603static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
wdenk5c71a7a2005-05-16 15:23:22 +0000604{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200605 int retval;
wdenk5c71a7a2005-05-16 15:23:22 +0000606
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200607 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:
614#ifdef CONFIG_FLASH_CFI_LEGACY
615 case CFI_CMDSET_AMD_LEGACY:
616#endif
617 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
618 break;
619 default:
620 retval = 0;
wdenk5c71a7a2005-05-16 15:23:22 +0000621 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200622 debug ("flash_is_busy: %d\n", retval);
623 return retval;
wdenk5c71a7a2005-05-16 15:23:22 +0000624}
625
626/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200627 * 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.
wdenk5c71a7a2005-05-16 15:23:22 +0000629 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200630static int flash_status_check (flash_info_t * info, flash_sect_t sector,
631 ulong tout, char *prompt)
wdenk2cefd152004-02-08 22:55:38 +0000632{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200633 ulong start;
wdenk2cefd152004-02-08 22:55:38 +0000634
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200635#if CFG_HZ != 1000
636 tout *= CFG_HZ/1000;
637#endif
wdenk2cefd152004-02-08 22:55:38 +0000638
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200639 /* 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;
wdenk2cefd152004-02-08 22:55:38 +0000648 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200649 udelay (1); /* also triggers watchdog */
wdenk2cefd152004-02-08 22:55:38 +0000650 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200651 return ERR_OK;
652}
wdenk2cefd152004-02-08 22:55:38 +0000653
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200654/*-----------------------------------------------------------------------
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;
wdenk2cefd152004-02-08 22:55:38 +0000664
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200665 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");
wdenk2cefd152004-02-08 22:55:38 +0000684 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200685 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");
wdenk2cefd152004-02-08 22:55:38 +0000691 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200692 flash_write_cmd (info, sector, 0, info->cmd_reset);
693 break;
694 default:
695 break;
wdenk2cefd152004-02-08 22:55:38 +0000696 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200697 return retcode;
wdenk2cefd152004-02-08 22:55:38 +0000698}
699
700/*-----------------------------------------------------------------------
701 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200702static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
wdenk2cefd152004-02-08 22:55:38 +0000703{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200704#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
705 unsigned short w;
706 unsigned int l;
707 unsigned long long ll;
708#endif
wdenk2cefd152004-02-08 22:55:38 +0000709
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200710 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;
719#else
720 cword->w = (cword->w << 8) | c;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100721#endif
Haavard Skinnemoen6dd763c2007-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;
730#endif
731 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;
Stefan Roese12797482006-11-13 13:55:24 +0100741 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200742}
wdenk2cefd152004-02-08 22:55:38 +0000743
Haavard Skinnemoen6dd763c2007-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
746 */
747static flash_sect_t find_sector (flash_info_t * info, ulong addr)
748{
749 flash_sect_t sector;
wdenk2cefd152004-02-08 22:55:38 +0000750
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200751 for (sector = info->sector_count - 1; sector >= 0; sector--) {
752 if (addr >= info->start[sector])
753 break;
wdenk2cefd152004-02-08 22:55:38 +0000754 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200755 return sector;
wdenk2cefd152004-02-08 22:55:38 +0000756}
757
758/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000759 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200760static int flash_write_cfiword (flash_info_t * info, ulong dest,
761 cfiword_t cword)
wdenk2cefd152004-02-08 22:55:38 +0000762{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100763 void *dstaddr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200764 int flag;
wdenk2cefd152004-02-08 22:55:38 +0000765
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100766 dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
wdenk2cefd152004-02-08 22:55:38 +0000767
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200768 /* Check if Flash is (sufficiently) erased */
769 switch (info->portwidth) {
770 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100771 flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200772 break;
773 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100774 flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200775 break;
776 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100777 flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200778 break;
779 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100780 flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200781 break;
782 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100783 flag = 0;
784 break;
wdenk2cefd152004-02-08 22:55:38 +0000785 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100786 if (!flag) {
787 unmap_physmem(dstaddr, info->portwidth);
Stefan Roese707c1462007-12-27 07:50:54 +0100788 return ERR_NOT_ERASED;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100789 }
wdenk2cefd152004-02-08 22:55:38 +0000790
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200791 /* Disable interrupts which might cause a timeout here */
792 flag = disable_interrupts ();
Stefan Roesec865e6c2006-02-28 15:29:58 +0100793
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200794 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:
804#endif
805 flash_unlock_seq (info, 0);
806 flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
807 break;
wdenk2cefd152004-02-08 22:55:38 +0000808 }
809
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200810 switch (info->portwidth) {
811 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100812 flash_write8(cword.c, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200813 break;
814 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100815 flash_write16(cword.w, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200816 break;
817 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100818 flash_write32(cword.l, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200819 break;
820 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100821 flash_write64(cword.ll, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200822 break;
wdenk2cefd152004-02-08 22:55:38 +0000823 }
824
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200825 /* re-enable interrupts if necessary */
826 if (flag)
827 enable_interrupts ();
wdenk2cefd152004-02-08 22:55:38 +0000828
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100829 unmap_physmem(dstaddr, info->portwidth);
830
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200831 return flash_full_status_check (info, find_sector (info, dest),
832 info->write_tout, "write");
wdenk2cefd152004-02-08 22:55:38 +0000833}
834
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200835#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenk2cefd152004-02-08 22:55:38 +0000836
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200837static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
838 int len)
wdenk2cefd152004-02-08 22:55:38 +0000839{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200840 flash_sect_t sector;
841 int cnt;
842 int retcode;
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100843 void *src = cp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100844 void *dst = map_physmem(dest, len, MAP_NOCACHE);
Stefan Roese707c1462007-12-27 07:50:54 +0100845 void *dst2 = dst;
846 int flag = 0;
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200847 uint offset = 0;
848 unsigned int shift;
Stefan Roese707c1462007-12-27 07:50:54 +0100849
850 switch (info->portwidth) {
851 case FLASH_CFI_8BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200852 shift = 0;
Stefan Roese707c1462007-12-27 07:50:54 +0100853 break;
854 case FLASH_CFI_16BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200855 shift = 1;
Stefan Roese707c1462007-12-27 07:50:54 +0100856 break;
857 case FLASH_CFI_32BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200858 shift = 2;
Stefan Roese707c1462007-12-27 07:50:54 +0100859 break;
860 case FLASH_CFI_64BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200861 shift = 3;
Stefan Roese707c1462007-12-27 07:50:54 +0100862 break;
863 default:
864 retcode = ERR_INVAL;
865 goto out_unmap;
866 }
867
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200868 cnt = len >> shift;
869
Stefan Roese707c1462007-12-27 07:50:54 +0100870 while ((cnt-- > 0) && (flag == 0)) {
871 switch (info->portwidth) {
872 case FLASH_CFI_8BIT:
873 flag = ((flash_read8(dst2) & flash_read8(src)) ==
874 flash_read8(src));
875 src += 1, dst2 += 1;
876 break;
877 case FLASH_CFI_16BIT:
878 flag = ((flash_read16(dst2) & flash_read16(src)) ==
879 flash_read16(src));
880 src += 2, dst2 += 2;
881 break;
882 case FLASH_CFI_32BIT:
883 flag = ((flash_read32(dst2) & flash_read32(src)) ==
884 flash_read32(src));
885 src += 4, dst2 += 4;
886 break;
887 case FLASH_CFI_64BIT:
888 flag = ((flash_read64(dst2) & flash_read64(src)) ==
889 flash_read64(src));
890 src += 8, dst2 += 8;
891 break;
892 }
893 }
894 if (!flag) {
895 retcode = ERR_NOT_ERASED;
896 goto out_unmap;
897 }
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100898
Stefan Roese707c1462007-12-27 07:50:54 +0100899 src = cp;
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100900 sector = find_sector (info, dest);
wdenke65527f2004-02-12 00:47:09 +0000901
902 switch (info->vendor) {
wdenk2cefd152004-02-08 22:55:38 +0000903 case CFI_CMDSET_INTEL_STANDARD:
904 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200905 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
906 flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
907 retcode = flash_status_check (info, sector,
908 info->buffer_write_tout,
909 "write to buffer");
910 if (retcode == ERR_OK) {
911 /* reduce the number of loops by the width of
912 * the port */
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200913 cnt = len >> shift;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200914 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
915 while (cnt-- > 0) {
916 switch (info->portwidth) {
917 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100918 flash_write8(flash_read8(src), dst);
919 src += 1, dst += 1;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200920 break;
921 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100922 flash_write16(flash_read16(src), dst);
923 src += 2, dst += 2;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200924 break;
925 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100926 flash_write32(flash_read32(src), dst);
927 src += 4, dst += 4;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200928 break;
929 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100930 flash_write64(flash_read64(src), dst);
931 src += 8, dst += 8;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200932 break;
933 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100934 retcode = ERR_INVAL;
935 goto out_unmap;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200936 }
937 }
938 flash_write_cmd (info, sector, 0,
939 FLASH_CMD_WRITE_BUFFER_CONFIRM);
940 retcode = flash_full_status_check (
941 info, sector, info->buffer_write_tout,
942 "buffer write");
943 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100944
945 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200946
wdenk2cefd152004-02-08 22:55:38 +0000947 case CFI_CMDSET_AMD_STANDARD:
948 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200949 flash_unlock_seq(info,0);
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200950
951#ifdef CONFIG_FLASH_SPANSION_S29WS_N
952 offset = ((unsigned long)dst - info->start[sector]) >> shift;
953#endif
954 flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
955 cnt = len >> shift;
956 flash_write_cmd(info, sector, offset, (uchar)cnt - 1);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200957
958 switch (info->portwidth) {
959 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100960 while (cnt-- > 0) {
961 flash_write8(flash_read8(src), dst);
962 src += 1, dst += 1;
963 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200964 break;
965 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100966 while (cnt-- > 0) {
967 flash_write16(flash_read16(src), dst);
968 src += 2, dst += 2;
969 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200970 break;
971 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100972 while (cnt-- > 0) {
973 flash_write32(flash_read32(src), dst);
974 src += 4, dst += 4;
975 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200976 break;
977 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100978 while (cnt-- > 0) {
979 flash_write64(flash_read64(src), dst);
980 src += 8, dst += 8;
981 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200982 break;
983 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100984 retcode = ERR_INVAL;
985 goto out_unmap;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200986 }
987
988 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
989 retcode = flash_full_status_check (info, sector,
990 info->buffer_write_tout,
991 "buffer write");
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100992 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200993
wdenk2cefd152004-02-08 22:55:38 +0000994 default:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200995 debug ("Unknown Command Set\n");
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100996 retcode = ERR_INVAL;
997 break;
wdenk2cefd152004-02-08 22:55:38 +0000998 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100999
1000out_unmap:
1001 unmap_physmem(dst, len);
1002 return retcode;
wdenk2cefd152004-02-08 22:55:38 +00001003}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001004#endif /* CFG_FLASH_USE_BUFFER_WRITE */
1005
wdenke65527f2004-02-12 00:47:09 +00001006
wdenk2cefd152004-02-08 22:55:38 +00001007/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +00001008 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001009int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk2cefd152004-02-08 22:55:38 +00001010{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001011 int rcode = 0;
1012 int prot;
1013 flash_sect_t sect;
wdenk2cefd152004-02-08 22:55:38 +00001014
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001015 if (info->flash_id != FLASH_MAN_CFI) {
1016 puts ("Can't erase unknown flash type - aborted\n");
1017 return 1;
1018 }
1019 if ((s_first < 0) || (s_first > s_last)) {
1020 puts ("- no sectors to erase\n");
1021 return 1;
1022 }
Stefan Roeseefef95b2006-04-01 13:41:03 +02001023
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001024 prot = 0;
1025 for (sect = s_first; sect <= s_last; ++sect) {
1026 if (info->protect[sect]) {
1027 prot++;
wdenk2cefd152004-02-08 22:55:38 +00001028 }
1029 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001030 if (prot) {
1031 printf ("- Warning: %d protected sectors will not be erased!\n",
1032 prot);
1033 } else {
1034 putc ('\n');
1035 }
wdenke65527f2004-02-12 00:47:09 +00001036
wdenke65527f2004-02-12 00:47:09 +00001037
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001038 for (sect = s_first; sect <= s_last; sect++) {
1039 if (info->protect[sect] == 0) { /* not protected */
1040 switch (info->vendor) {
1041 case CFI_CMDSET_INTEL_STANDARD:
1042 case CFI_CMDSET_INTEL_EXTENDED:
1043 flash_write_cmd (info, sect, 0,
1044 FLASH_CMD_CLEAR_STATUS);
1045 flash_write_cmd (info, sect, 0,
1046 FLASH_CMD_BLOCK_ERASE);
1047 flash_write_cmd (info, sect, 0,
1048 FLASH_CMD_ERASE_CONFIRM);
1049 break;
1050 case CFI_CMDSET_AMD_STANDARD:
1051 case CFI_CMDSET_AMD_EXTENDED:
1052 flash_unlock_seq (info, sect);
1053 flash_write_cmd (info, sect,
1054 info->addr_unlock1,
1055 AMD_CMD_ERASE_START);
1056 flash_unlock_seq (info, sect);
1057 flash_write_cmd (info, sect, 0,
1058 AMD_CMD_ERASE_SECTOR);
1059 break;
1060#ifdef CONFIG_FLASH_CFI_LEGACY
1061 case CFI_CMDSET_AMD_LEGACY:
1062 flash_unlock_seq (info, 0);
1063 flash_write_cmd (info, 0, info->addr_unlock1,
1064 AMD_CMD_ERASE_START);
1065 flash_unlock_seq (info, 0);
1066 flash_write_cmd (info, sect, 0,
1067 AMD_CMD_ERASE_SECTOR);
1068 break;
1069#endif
1070 default:
1071 debug ("Unkown flash vendor %d\n",
1072 info->vendor);
1073 break;
wdenke65527f2004-02-12 00:47:09 +00001074 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001075
1076 if (flash_full_status_check
1077 (info, sect, info->erase_blk_tout, "erase")) {
1078 rcode = 1;
1079 } else
1080 putc ('.');
wdenk2cefd152004-02-08 22:55:38 +00001081 }
wdenk2cefd152004-02-08 22:55:38 +00001082 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001083 puts (" done\n");
1084 return rcode;
wdenk2cefd152004-02-08 22:55:38 +00001085}
wdenke65527f2004-02-12 00:47:09 +00001086
wdenk2cefd152004-02-08 22:55:38 +00001087/*-----------------------------------------------------------------------
1088 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001089void flash_print_info (flash_info_t * info)
wdenk2cefd152004-02-08 22:55:38 +00001090{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001091 int i;
wdenk369d43d2004-03-14 14:09:05 +00001092
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001093 if (info->flash_id != FLASH_MAN_CFI) {
1094 puts ("missing or unknown FLASH type\n");
1095 return;
1096 }
1097
1098 printf ("%s FLASH (%d x %d)",
1099 info->name,
1100 (info->portwidth << 3), (info->chipwidth << 3));
1101 if (info->size < 1024*1024)
1102 printf (" Size: %ld kB in %d Sectors\n",
1103 info->size >> 10, info->sector_count);
1104 else
1105 printf (" Size: %ld MB in %d Sectors\n",
1106 info->size >> 20, info->sector_count);
1107 printf (" ");
1108 switch (info->vendor) {
1109 case CFI_CMDSET_INTEL_STANDARD:
1110 printf ("Intel Standard");
1111 break;
1112 case CFI_CMDSET_INTEL_EXTENDED:
1113 printf ("Intel Extended");
1114 break;
1115 case CFI_CMDSET_AMD_STANDARD:
1116 printf ("AMD Standard");
1117 break;
1118 case CFI_CMDSET_AMD_EXTENDED:
1119 printf ("AMD Extended");
1120 break;
1121#ifdef CONFIG_FLASH_CFI_LEGACY
1122 case CFI_CMDSET_AMD_LEGACY:
1123 printf ("AMD Legacy");
1124 break;
wdenk369d43d2004-03-14 14:09:05 +00001125#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001126 default:
1127 printf ("Unknown (%d)", info->vendor);
1128 break;
wdenk2cefd152004-02-08 22:55:38 +00001129 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001130 printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
1131 info->manufacturer_id, info->device_id);
1132 if (info->device_id == 0x7E) {
1133 printf("%04X", info->device_id2);
1134 }
1135 printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n",
1136 info->erase_blk_tout,
1137 info->write_tout);
1138 if (info->buffer_size > 1) {
1139 printf (" Buffer write timeout: %ld ms, "
1140 "buffer size: %d bytes\n",
1141 info->buffer_write_tout,
1142 info->buffer_size);
1143 }
wdenk2cefd152004-02-08 22:55:38 +00001144
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001145 puts ("\n Sector Start Addresses:");
1146 for (i = 0; i < info->sector_count; ++i) {
1147 if ((i % 5) == 0)
1148 printf ("\n");
1149#ifdef CFG_FLASH_EMPTY_INFO
1150 int k;
1151 int size;
1152 int erased;
1153 volatile unsigned long *flash;
wdenk2cefd152004-02-08 22:55:38 +00001154
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001155 /*
1156 * Check if whole sector is erased
1157 */
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001158 size = flash_sector_size(info, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001159 erased = 1;
1160 flash = (volatile unsigned long *) info->start[i];
1161 size = size >> 2; /* divide by 4 for longword access */
1162 for (k = 0; k < size; k++) {
1163 if (*flash++ != 0xffffffff) {
1164 erased = 0;
1165 break;
1166 }
1167 }
wdenke65527f2004-02-12 00:47:09 +00001168
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001169 /* print empty and read-only info */
1170 printf (" %08lX %c %s ",
1171 info->start[i],
1172 erased ? 'E' : ' ',
1173 info->protect[i] ? "RO" : " ");
1174#else /* ! CFG_FLASH_EMPTY_INFO */
1175 printf (" %08lX %s ",
1176 info->start[i],
1177 info->protect[i] ? "RO" : " ");
wdenke65527f2004-02-12 00:47:09 +00001178#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001179 }
1180 putc ('\n');
1181 return;
wdenk2cefd152004-02-08 22:55:38 +00001182}
1183
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001184/*-----------------------------------------------------------------------
Jerry Van Barenaae73572008-03-08 13:48:01 -05001185 * This is used in a few places in write_buf() to show programming
1186 * progress. Making it a function is nasty because it needs to do side
1187 * effect updates to digit and dots. Repeated code is nasty too, so
1188 * we define it once here.
1189 */
Stefan Roese7758c162008-03-19 07:09:26 +01001190#ifdef CONFIG_FLASH_SHOW_PROGRESS
1191#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
1192 dots -= dots_sub; \
Jerry Van Barenaae73572008-03-08 13:48:01 -05001193 if ((scale > 0) && (dots <= 0)) { \
1194 if ((digit % 5) == 0) \
1195 printf ("%d", digit / 5); \
1196 else \
1197 putc ('.'); \
1198 digit--; \
1199 dots += scale; \
1200 }
Stefan Roese7758c162008-03-19 07:09:26 +01001201#else
1202#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1203#endif
Jerry Van Barenaae73572008-03-08 13:48:01 -05001204
1205/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001206 * Copy memory to flash, returns:
1207 * 0 - OK
1208 * 1 - write timeout
1209 * 2 - Flash not erased
wdenk2cefd152004-02-08 22:55:38 +00001210 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001211int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk2cefd152004-02-08 22:55:38 +00001212{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001213 ulong wp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001214 uchar *p;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001215 int aln;
wdenk2cefd152004-02-08 22:55:38 +00001216 cfiword_t cword;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001217 int i, rc;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001218#ifdef CFG_FLASH_USE_BUFFER_WRITE
1219 int buffered_size;
wdenk2cefd152004-02-08 22:55:38 +00001220#endif
Jerry Van Barenaae73572008-03-08 13:48:01 -05001221#ifdef CONFIG_FLASH_SHOW_PROGRESS
1222 int digit = CONFIG_FLASH_SHOW_PROGRESS;
1223 int scale = 0;
1224 int dots = 0;
1225
1226 /*
1227 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
1228 */
1229 if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
1230 scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
1231 CONFIG_FLASH_SHOW_PROGRESS);
1232 }
1233#endif
1234
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001235 /* get lower aligned address */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001236 wp = (addr & ~(info->portwidth - 1));
Haiying Wangc123a382007-02-21 16:52:31 +01001237
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001238 /* handle unaligned start */
1239 if ((aln = addr - wp) != 0) {
1240 cword.l = 0;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001241 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1242 for (i = 0; i < aln; ++i)
1243 flash_add_byte (info, &cword, flash_read8(p + i));
wdenk2cefd152004-02-08 22:55:38 +00001244
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001245 for (; (i < info->portwidth) && (cnt > 0); i++) {
1246 flash_add_byte (info, &cword, *src++);
1247 cnt--;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001248 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001249 for (; (cnt == 0) && (i < info->portwidth); ++i)
1250 flash_add_byte (info, &cword, flash_read8(p + i));
1251
1252 rc = flash_write_cfiword (info, wp, cword);
1253 unmap_physmem(p, info->portwidth);
1254 if (rc != 0)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001255 return rc;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001256
1257 wp += i;
Stefan Roese7758c162008-03-19 07:09:26 +01001258 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001259 }
1260
1261 /* handle the aligned part */
1262#ifdef CFG_FLASH_USE_BUFFER_WRITE
1263 buffered_size = (info->portwidth / info->chipwidth);
1264 buffered_size *= info->buffer_size;
1265 while (cnt >= info->portwidth) {
1266 /* prohibit buffer write when buffer_size is 1 */
1267 if (info->buffer_size == 1) {
1268 cword.l = 0;
1269 for (i = 0; i < info->portwidth; i++)
1270 flash_add_byte (info, &cword, *src++);
1271 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1272 return rc;
1273 wp += info->portwidth;
1274 cnt -= info->portwidth;
1275 continue;
1276 }
1277
1278 /* write buffer until next buffered_size aligned boundary */
1279 i = buffered_size - (wp % buffered_size);
1280 if (i > cnt)
1281 i = cnt;
1282 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
1283 return rc;
1284 i -= i & (info->portwidth - 1);
1285 wp += i;
1286 src += i;
1287 cnt -= i;
Stefan Roese7758c162008-03-19 07:09:26 +01001288 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001289 }
1290#else
1291 while (cnt >= info->portwidth) {
1292 cword.l = 0;
1293 for (i = 0; i < info->portwidth; i++) {
1294 flash_add_byte (info, &cword, *src++);
1295 }
1296 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1297 return rc;
1298 wp += info->portwidth;
1299 cnt -= info->portwidth;
Stefan Roese7758c162008-03-19 07:09:26 +01001300 FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001301 }
1302#endif /* CFG_FLASH_USE_BUFFER_WRITE */
Jerry Van Barenaae73572008-03-08 13:48:01 -05001303
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001304 if (cnt == 0) {
1305 return (0);
1306 }
1307
1308 /*
1309 * handle unaligned tail bytes
1310 */
1311 cword.l = 0;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001312 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1313 for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001314 flash_add_byte (info, &cword, *src++);
1315 --cnt;
1316 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001317 for (; i < info->portwidth; ++i)
1318 flash_add_byte (info, &cword, flash_read8(p + i));
1319 unmap_physmem(p, info->portwidth);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001320
1321 return flash_write_cfiword (info, wp, cword);
wdenk2cefd152004-02-08 22:55:38 +00001322}
wdenke65527f2004-02-12 00:47:09 +00001323
wdenk2cefd152004-02-08 22:55:38 +00001324/*-----------------------------------------------------------------------
1325 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001326#ifdef CFG_FLASH_PROTECTION
1327
1328int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk2cefd152004-02-08 22:55:38 +00001329{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001330 int retcode = 0;
wdenke65527f2004-02-12 00:47:09 +00001331
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001332 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1333 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1334 if (prot)
1335 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
1336 else
1337 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
wdenk2cefd152004-02-08 22:55:38 +00001338
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001339 if ((retcode =
1340 flash_full_status_check (info, sector, info->erase_blk_tout,
1341 prot ? "protect" : "unprotect")) == 0) {
wdenke65527f2004-02-12 00:47:09 +00001342
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001343 info->protect[sector] = prot;
1344
1345 /*
1346 * On some of Intel's flash chips (marked via legacy_unlock)
1347 * unprotect unprotects all locking.
1348 */
1349 if ((prot == 0) && (info->legacy_unlock)) {
1350 flash_sect_t i;
1351
1352 for (i = 0; i < info->sector_count; i++) {
1353 if (info->protect[i])
1354 flash_real_protect (info, i, 1);
1355 }
wdenk2cefd152004-02-08 22:55:38 +00001356 }
wdenk2cefd152004-02-08 22:55:38 +00001357 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001358 return retcode;
wdenk2cefd152004-02-08 22:55:38 +00001359}
wdenke65527f2004-02-12 00:47:09 +00001360
wdenk2cefd152004-02-08 22:55:38 +00001361/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001362 * flash_read_user_serial - read the OneTimeProgramming cells
wdenk2cefd152004-02-08 22:55:38 +00001363 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001364void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
1365 int len)
wdenk2cefd152004-02-08 22:55:38 +00001366{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001367 uchar *src;
1368 uchar *dst;
wdenke65527f2004-02-12 00:47:09 +00001369
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001370 dst = buffer;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001371 src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001372 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1373 memcpy (dst, src + offset, len);
1374 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001375 flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
wdenk2cefd152004-02-08 22:55:38 +00001376}
1377
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001378/*
1379 * flash_read_factory_serial - read the device Id from the protection area
wdenk2cefd152004-02-08 22:55:38 +00001380 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001381void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
1382 int len)
wdenk2cefd152004-02-08 22:55:38 +00001383{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001384 uchar *src;
wdenke65527f2004-02-12 00:47:09 +00001385
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001386 src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001387 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1388 memcpy (buffer, src + offset, len);
1389 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001390 flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
wdenk2cefd152004-02-08 22:55:38 +00001391}
1392
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001393#endif /* CFG_FLASH_PROTECTION */
1394
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001395/*-----------------------------------------------------------------------
1396 * Reverse the order of the erase regions in the CFI QRY structure.
1397 * This is needed for chips that are either a) correctly detected as
1398 * top-boot, or b) buggy.
1399 */
1400static void cfi_reverse_geometry(struct cfi_qry *qry)
1401{
1402 unsigned int i, j;
1403 u32 tmp;
1404
1405 for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
1406 tmp = qry->erase_region_info[i];
1407 qry->erase_region_info[i] = qry->erase_region_info[j];
1408 qry->erase_region_info[j] = tmp;
1409 }
1410}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001411
wdenk2cefd152004-02-08 22:55:38 +00001412/*-----------------------------------------------------------------------
Stefan Roese12797482006-11-13 13:55:24 +01001413 * read jedec ids from device and set corresponding fields in info struct
1414 *
1415 * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1416 *
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001417 */
1418static void cmdset_intel_read_jedec_ids(flash_info_t *info)
1419{
1420 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1421 flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1422 udelay(1000); /* some flash are slow to respond */
1423 info->manufacturer_id = flash_read_uchar (info,
1424 FLASH_OFFSET_MANUFACTURER_ID);
1425 info->device_id = flash_read_uchar (info,
1426 FLASH_OFFSET_DEVICE_ID);
1427 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1428}
1429
1430static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
1431{
1432 info->cmd_reset = FLASH_CMD_RESET;
1433
1434 cmdset_intel_read_jedec_ids(info);
1435 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1436
1437#ifdef CFG_FLASH_PROTECTION
1438 /* read legacy lock/unlock bit from intel flash */
1439 if (info->ext_addr) {
1440 info->legacy_unlock = flash_read_uchar (info,
1441 info->ext_addr + 5) & 0x08;
1442 }
1443#endif
1444
1445 return 0;
1446}
1447
1448static void cmdset_amd_read_jedec_ids(flash_info_t *info)
1449{
1450 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1451 flash_unlock_seq(info, 0);
1452 flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
1453 udelay(1000); /* some flash are slow to respond */
Tor Krill7f2a3052008-03-28 11:29:10 +01001454
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001455 info->manufacturer_id = flash_read_uchar (info,
1456 FLASH_OFFSET_MANUFACTURER_ID);
Tor Krill7f2a3052008-03-28 11:29:10 +01001457
1458 switch (info->chipwidth){
1459 case FLASH_CFI_8BIT:
1460 info->device_id = flash_read_uchar (info,
1461 FLASH_OFFSET_DEVICE_ID);
1462 if (info->device_id == 0x7E) {
1463 /* AMD 3-byte (expanded) device ids */
1464 info->device_id2 = flash_read_uchar (info,
1465 FLASH_OFFSET_DEVICE_ID2);
1466 info->device_id2 <<= 8;
1467 info->device_id2 |= flash_read_uchar (info,
1468 FLASH_OFFSET_DEVICE_ID3);
1469 }
1470 break;
1471 case FLASH_CFI_16BIT:
1472 info->device_id = flash_read_word (info,
1473 FLASH_OFFSET_DEVICE_ID);
1474 break;
1475 default:
1476 break;
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001477 }
1478 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1479}
1480
1481static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
1482{
1483 info->cmd_reset = AMD_CMD_RESET;
1484
1485 cmdset_amd_read_jedec_ids(info);
1486 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1487
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001488 return 0;
1489}
1490
1491#ifdef CONFIG_FLASH_CFI_LEGACY
Stefan Roese12797482006-11-13 13:55:24 +01001492static void flash_read_jedec_ids (flash_info_t * info)
1493{
1494 info->manufacturer_id = 0;
1495 info->device_id = 0;
1496 info->device_id2 = 0;
1497
1498 switch (info->vendor) {
1499 case CFI_CMDSET_INTEL_STANDARD:
1500 case CFI_CMDSET_INTEL_EXTENDED:
Michael Schwingen5fb0aa42008-01-12 20:29:47 +01001501 cmdset_intel_read_jedec_ids(info);
Stefan Roese12797482006-11-13 13:55:24 +01001502 break;
1503 case CFI_CMDSET_AMD_STANDARD:
1504 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen5fb0aa42008-01-12 20:29:47 +01001505 cmdset_amd_read_jedec_ids(info);
Stefan Roese12797482006-11-13 13:55:24 +01001506 break;
1507 default:
1508 break;
1509 }
1510}
1511
1512/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001513 * Call board code to request info about non-CFI flash.
1514 * board_flash_get_legacy needs to fill in at least:
1515 * info->portwidth, info->chipwidth and info->interface for Jedec probing.
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001516 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001517static int flash_detect_legacy(ulong base, int banknum)
wdenk2cefd152004-02-08 22:55:38 +00001518{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001519 flash_info_t *info = &flash_info[banknum];
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001520
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001521 if (board_flash_get_legacy(base, banknum, info)) {
1522 /* board code may have filled info completely. If not, we
1523 use JEDEC ID probing. */
1524 if (!info->vendor) {
1525 int modes[] = {
1526 CFI_CMDSET_AMD_STANDARD,
1527 CFI_CMDSET_INTEL_STANDARD
1528 };
1529 int i;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001530
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001531 for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1532 info->vendor = modes[i];
1533 info->start[0] = base;
1534 if (info->portwidth == FLASH_CFI_8BIT
1535 && info->interface == FLASH_CFI_X8X16) {
1536 info->addr_unlock1 = 0x2AAA;
1537 info->addr_unlock2 = 0x5555;
1538 } else {
1539 info->addr_unlock1 = 0x5555;
1540 info->addr_unlock2 = 0x2AAA;
1541 }
1542 flash_read_jedec_ids(info);
1543 debug("JEDEC PROBE: ID %x %x %x\n",
1544 info->manufacturer_id,
1545 info->device_id,
1546 info->device_id2);
1547 if (jedec_flash_match(info, base))
1548 break;
1549 }
1550 }
1551
1552 switch(info->vendor) {
1553 case CFI_CMDSET_INTEL_STANDARD:
1554 case CFI_CMDSET_INTEL_EXTENDED:
1555 info->cmd_reset = FLASH_CMD_RESET;
1556 break;
1557 case CFI_CMDSET_AMD_STANDARD:
1558 case CFI_CMDSET_AMD_EXTENDED:
1559 case CFI_CMDSET_AMD_LEGACY:
1560 info->cmd_reset = AMD_CMD_RESET;
1561 break;
1562 }
1563 info->flash_id = FLASH_MAN_CFI;
1564 return 1;
1565 }
1566 return 0; /* use CFI */
1567}
1568#else
1569static inline int flash_detect_legacy(ulong base, int banknum)
1570{
1571 return 0; /* use CFI */
1572}
1573#endif
1574
1575/*-----------------------------------------------------------------------
1576 * detect if flash is compatible with the Common Flash Interface (CFI)
1577 * http://www.jedec.org/download/search/jesd68.pdf
1578 */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001579static void flash_read_cfi (flash_info_t *info, void *buf,
1580 unsigned int start, size_t len)
1581{
1582 u8 *p = buf;
1583 unsigned int i;
1584
1585 for (i = 0; i < len; i++)
1586 p[i] = flash_read_uchar(info, start + i);
1587}
1588
1589static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001590{
1591 int cfi_offset;
1592
Michael Schwingen4661cf72008-02-18 23:16:35 +01001593 /* We do not yet know what kind of commandset to use, so we issue
1594 the reset command in both Intel and AMD variants, in the hope
1595 that AMD flash roms ignore the Intel command. */
1596 flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
1597 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
1598
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001599 for (cfi_offset=0;
1600 cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
1601 cfi_offset++) {
1602 flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
1603 FLASH_CMD_CFI);
1604 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1605 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1606 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001607 flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1608 sizeof(struct cfi_qry));
1609 info->interface = le16_to_cpu(qry->interface_desc);
1610
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001611 info->cfi_offset = flash_offset_cfi[cfi_offset];
1612 debug ("device interface is %d\n",
1613 info->interface);
1614 debug ("found port %d chip %d ",
1615 info->portwidth, info->chipwidth);
1616 debug ("port %d bits chip %d bits\n",
1617 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1618 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1619
1620 /* calculate command offsets as in the Linux driver */
1621 info->addr_unlock1 = 0x555;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001622 info->addr_unlock2 = 0x2aa;
1623
1624 /*
1625 * modify the unlock address if we are
1626 * in compatibility mode
1627 */
1628 if ( /* x8/x16 in x8 mode */
1629 ((info->chipwidth == FLASH_CFI_BY8) &&
1630 (info->interface == FLASH_CFI_X8X16)) ||
1631 /* x16/x32 in x16 mode */
1632 ((info->chipwidth == FLASH_CFI_BY16) &&
1633 (info->interface == FLASH_CFI_X16X32)))
1634 {
1635 info->addr_unlock1 = 0xaaa;
1636 info->addr_unlock2 = 0x555;
1637 }
1638
1639 info->name = "CFI conformant";
1640 return 1;
1641 }
1642 }
1643
1644 return 0;
1645}
1646
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001647static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001648{
wdenke65527f2004-02-12 00:47:09 +00001649 debug ("flash detect cfi\n");
wdenk2cefd152004-02-08 22:55:38 +00001650
Stefan Roesec865e6c2006-02-28 15:29:58 +01001651 for (info->portwidth = CFG_FLASH_CFI_WIDTH;
wdenke65527f2004-02-12 00:47:09 +00001652 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1653 for (info->chipwidth = FLASH_CFI_BY8;
1654 info->chipwidth <= info->portwidth;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001655 info->chipwidth <<= 1)
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001656 if (__flash_detect_cfi(info, qry))
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001657 return 1;
wdenk2cefd152004-02-08 22:55:38 +00001658 }
wdenke65527f2004-02-12 00:47:09 +00001659 debug ("not found\n");
wdenk2cefd152004-02-08 22:55:38 +00001660 return 0;
1661}
wdenke65527f2004-02-12 00:47:09 +00001662
wdenk2cefd152004-02-08 22:55:38 +00001663/*
Haavard Skinnemoen750ea7f2007-12-14 15:36:18 +01001664 * Manufacturer-specific quirks. Add workarounds for geometry
1665 * reversal, etc. here.
1666 */
1667static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1668{
1669 /* check if flash geometry needs reversal */
1670 if (qry->num_erase_regions > 1) {
1671 /* reverse geometry if top boot part */
1672 if (info->cfi_version < 0x3131) {
1673 /* CFI < 1.1, try to guess from device id */
1674 if ((info->device_id & 0x80) != 0)
1675 cfi_reverse_geometry(qry);
1676 } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1677 /* CFI >= 1.1, deduct from top/bottom flag */
1678 /* note: ext_addr is valid since cfi_version > 0 */
1679 cfi_reverse_geometry(qry);
1680 }
1681 }
1682}
1683
1684static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1685{
1686 int reverse_geometry = 0;
1687
1688 /* Check the "top boot" bit in the PRI */
1689 if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1690 reverse_geometry = 1;
1691
1692 /* AT49BV6416(T) list the erase regions in the wrong order.
1693 * However, the device ID is identical with the non-broken
1694 * AT49BV642D since u-boot only reads the low byte (they
1695 * differ in the high byte.) So leave out this fixup for now.
1696 */
1697#if 0
1698 if (info->device_id == 0xd6 || info->device_id == 0xd2)
1699 reverse_geometry = !reverse_geometry;
1700#endif
1701
1702 if (reverse_geometry)
1703 cfi_reverse_geometry(qry);
1704}
1705
1706/*
wdenk2cefd152004-02-08 22:55:38 +00001707 * The following code cannot be run from FLASH!
1708 *
1709 */
Marian Balakowicz513b4a12005-10-11 19:09:42 +02001710ulong flash_get_size (ulong base, int banknum)
wdenk2cefd152004-02-08 22:55:38 +00001711{
wdenke65527f2004-02-12 00:47:09 +00001712 flash_info_t *info = &flash_info[banknum];
wdenk2cefd152004-02-08 22:55:38 +00001713 int i, j;
1714 flash_sect_t sect_cnt;
1715 unsigned long sector;
1716 unsigned long tmp;
1717 int size_ratio;
1718 uchar num_erase_regions;
wdenke65527f2004-02-12 00:47:09 +00001719 int erase_region_size;
1720 int erase_region_count;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001721 struct cfi_qry qry;
Stefan Roese12797482006-11-13 13:55:24 +01001722
1723 info->ext_addr = 0;
1724 info->cfi_version = 0;
Stefan Roeseefef95b2006-04-01 13:41:03 +02001725#ifdef CFG_FLASH_PROTECTION
Stefan Roeseefef95b2006-04-01 13:41:03 +02001726 info->legacy_unlock = 0;
1727#endif
wdenk2cefd152004-02-08 22:55:38 +00001728
1729 info->start[0] = base;
1730
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001731 if (flash_detect_cfi (info, &qry)) {
1732 info->vendor = le16_to_cpu(qry.p_id);
1733 info->ext_addr = le16_to_cpu(qry.p_adr);
1734 num_erase_regions = qry.num_erase_regions;
1735
Stefan Roese12797482006-11-13 13:55:24 +01001736 if (info->ext_addr) {
1737 info->cfi_version = (ushort) flash_read_uchar (info,
1738 info->ext_addr + 3) << 8;
1739 info->cfi_version |= (ushort) flash_read_uchar (info,
1740 info->ext_addr + 4);
1741 }
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001742
wdenke65527f2004-02-12 00:47:09 +00001743#ifdef DEBUG
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001744 flash_printqry (&qry);
wdenke65527f2004-02-12 00:47:09 +00001745#endif
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001746
wdenke65527f2004-02-12 00:47:09 +00001747 switch (info->vendor) {
wdenk2cefd152004-02-08 22:55:38 +00001748 case CFI_CMDSET_INTEL_STANDARD:
1749 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001750 cmdset_intel_init(info, &qry);
wdenk2cefd152004-02-08 22:55:38 +00001751 break;
1752 case CFI_CMDSET_AMD_STANDARD:
1753 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001754 cmdset_amd_init(info, &qry);
wdenk2cefd152004-02-08 22:55:38 +00001755 break;
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001756 default:
1757 printf("CFI: Unknown command set 0x%x\n",
1758 info->vendor);
1759 /*
1760 * Unfortunately, this means we don't know how
1761 * to get the chip back to Read mode. Might
1762 * as well try an Intel-style reset...
1763 */
1764 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1765 return 0;
wdenk2cefd152004-02-08 22:55:38 +00001766 }
wdenk6cfa84e2004-02-10 00:03:41 +00001767
Haavard Skinnemoen750ea7f2007-12-14 15:36:18 +01001768 /* Do manufacturer-specific fixups */
1769 switch (info->manufacturer_id) {
1770 case 0x0001:
1771 flash_fixup_amd(info, &qry);
1772 break;
1773 case 0x001f:
1774 flash_fixup_atmel(info, &qry);
1775 break;
1776 }
1777
wdenke65527f2004-02-12 00:47:09 +00001778 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese12797482006-11-13 13:55:24 +01001779 debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
1780 debug ("device id is 0x%x\n", info->device_id);
1781 debug ("device id2 is 0x%x\n", info->device_id2);
1782 debug ("cfi version is 0x%04x\n", info->cfi_version);
1783
wdenk2cefd152004-02-08 22:55:38 +00001784 size_ratio = info->portwidth / info->chipwidth;
wdenke65527f2004-02-12 00:47:09 +00001785 /* if the chip is x8/x16 reduce the ratio by half */
1786 if ((info->interface == FLASH_CFI_X8X16)
1787 && (info->chipwidth == FLASH_CFI_BY8)) {
1788 size_ratio >>= 1;
1789 }
wdenke65527f2004-02-12 00:47:09 +00001790 debug ("size_ratio %d port %d bits chip %d bits\n",
1791 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1792 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1793 debug ("found %d erase regions\n", num_erase_regions);
wdenk2cefd152004-02-08 22:55:38 +00001794 sect_cnt = 0;
1795 sector = base;
wdenke65527f2004-02-12 00:47:09 +00001796 for (i = 0; i < num_erase_regions; i++) {
1797 if (i > NUM_ERASE_REGIONS) {
wdenke537b3b2004-02-23 23:54:43 +00001798 printf ("%d erase regions found, only %d used\n",
1799 num_erase_regions, NUM_ERASE_REGIONS);
wdenk2cefd152004-02-08 22:55:38 +00001800 break;
1801 }
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001802
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001803 tmp = le32_to_cpu(qry.erase_region_info[i]);
1804 debug("erase region %u: 0x%08lx\n", i, tmp);
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001805
1806 erase_region_count = (tmp & 0xffff) + 1;
1807 tmp >>= 16;
wdenke65527f2004-02-12 00:47:09 +00001808 erase_region_size =
1809 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenkaeba06f2004-06-09 17:34:58 +00001810 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenke537b3b2004-02-23 23:54:43 +00001811 erase_region_count, erase_region_size);
wdenke65527f2004-02-12 00:47:09 +00001812 for (j = 0; j < erase_region_count; j++) {
Michael Schwingen73d044d2007-12-07 23:35:02 +01001813 if (sect_cnt >= CFG_MAX_FLASH_SECT) {
1814 printf("ERROR: too many flash sectors\n");
1815 break;
1816 }
wdenk2cefd152004-02-08 22:55:38 +00001817 info->start[sect_cnt] = sector;
1818 sector += (erase_region_size * size_ratio);
wdenk26c58432005-01-09 17:12:27 +00001819
1820 /*
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001821 * Only read protection status from
1822 * supported devices (intel...)
wdenk26c58432005-01-09 17:12:27 +00001823 */
1824 switch (info->vendor) {
1825 case CFI_CMDSET_INTEL_EXTENDED:
1826 case CFI_CMDSET_INTEL_STANDARD:
1827 info->protect[sect_cnt] =
1828 flash_isset (info, sect_cnt,
1829 FLASH_OFFSET_PROTECT,
1830 FLASH_STATUS_PROTECT);
1831 break;
1832 default:
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001833 /* default: not protected */
1834 info->protect[sect_cnt] = 0;
wdenk26c58432005-01-09 17:12:27 +00001835 }
1836
wdenk2cefd152004-02-08 22:55:38 +00001837 sect_cnt++;
1838 }
1839 }
1840
1841 info->sector_count = sect_cnt;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001842 info->size = 1 << qry.dev_size;
wdenk2cefd152004-02-08 22:55:38 +00001843 /* multiply the size by the number of chips */
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001844 info->size *= size_ratio;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001845 info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1846 tmp = 1 << qry.block_erase_timeout_typ;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001847 info->erase_blk_tout = tmp *
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001848 (1 << qry.block_erase_timeout_max);
1849 tmp = (1 << qry.buf_write_timeout_typ) *
1850 (1 << qry.buf_write_timeout_max);
1851
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001852 /* round up when converting to ms */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001853 info->buffer_write_tout = (tmp + 999) / 1000;
1854 tmp = (1 << qry.word_write_timeout_typ) *
1855 (1 << qry.word_write_timeout_max);
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001856 /* round up when converting to ms */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001857 info->write_tout = (tmp + 999) / 1000;
wdenk2cefd152004-02-08 22:55:38 +00001858 info->flash_id = FLASH_MAN_CFI;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001859 if ((info->interface == FLASH_CFI_X8X16) &&
1860 (info->chipwidth == FLASH_CFI_BY8)) {
1861 /* XXX - Need to test on x8/x16 in parallel. */
1862 info->portwidth >>= 1;
wdenked2ac4b2004-03-14 18:23:55 +00001863 }
wdenk2cefd152004-02-08 22:55:38 +00001864 }
1865
Wolfgang Denka205a8f2005-09-25 16:41:22 +02001866 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenke65527f2004-02-12 00:47:09 +00001867 return (info->size);
wdenk2cefd152004-02-08 22:55:38 +00001868}
1869
wdenk2cefd152004-02-08 22:55:38 +00001870/*-----------------------------------------------------------------------
1871 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001872unsigned long flash_init (void)
wdenk2cefd152004-02-08 22:55:38 +00001873{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001874 unsigned long size = 0;
1875 int i;
Matthias Fuchs50431522008-04-18 16:29:40 +02001876#if defined(CFG_FLASH_AUTOPROTECT_LIST)
1877 struct apl_s {
1878 ulong start;
1879 ulong size;
1880 } apl[] = CFG_FLASH_AUTOPROTECT_LIST;
1881#endif
wdenk2cefd152004-02-08 22:55:38 +00001882
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001883#ifdef CFG_FLASH_PROTECTION
1884 char *s = getenv("unlock");
Michael Schwingen73d044d2007-12-07 23:35:02 +01001885#endif
wdenk2cefd152004-02-08 22:55:38 +00001886
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001887 /* Init: no FLASHes known */
1888 for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
1889 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenk2cefd152004-02-08 22:55:38 +00001890
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001891 if (!flash_detect_legacy (bank_base[i], i))
1892 flash_get_size (bank_base[i], i);
1893 size += flash_info[i].size;
1894 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
1895#ifndef CFG_FLASH_QUIET_TEST
1896 printf ("## Unknown FLASH on Bank %d "
1897 "- Size = 0x%08lx = %ld MB\n",
1898 i+1, flash_info[i].size,
1899 flash_info[i].size << 20);
1900#endif /* CFG_FLASH_QUIET_TEST */
1901 }
1902#ifdef CFG_FLASH_PROTECTION
1903 else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
1904 /*
1905 * Only the U-Boot image and it's environment
1906 * is protected, all other sectors are
1907 * unprotected (unlocked) if flash hardware
1908 * protection is used (CFG_FLASH_PROTECTION)
1909 * and the environment variable "unlock" is
1910 * set to "yes".
1911 */
1912 if (flash_info[i].legacy_unlock) {
1913 int k;
wdenk2cefd152004-02-08 22:55:38 +00001914
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001915 /*
1916 * Disable legacy_unlock temporarily,
1917 * since flash_real_protect would
1918 * relock all other sectors again
1919 * otherwise.
1920 */
1921 flash_info[i].legacy_unlock = 0;
wdenk2cefd152004-02-08 22:55:38 +00001922
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001923 /*
1924 * Legacy unlocking (e.g. Intel J3) ->
1925 * unlock only one sector. This will
1926 * unlock all sectors.
1927 */
1928 flash_real_protect (&flash_info[i], 0, 0);
wdenk2cefd152004-02-08 22:55:38 +00001929
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001930 flash_info[i].legacy_unlock = 1;
wdenk2cefd152004-02-08 22:55:38 +00001931
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001932 /*
1933 * Manually mark other sectors as
1934 * unlocked (unprotected)
1935 */
1936 for (k = 1; k < flash_info[i].sector_count; k++)
1937 flash_info[i].protect[k] = 0;
1938 } else {
1939 /*
1940 * No legancy unlocking -> unlock all sectors
1941 */
1942 flash_protect (FLAG_PROTECT_CLEAR,
1943 flash_info[i].start[0],
1944 flash_info[i].start[0]
1945 + flash_info[i].size - 1,
1946 &flash_info[i]);
Stefan Roesec865e6c2006-02-28 15:29:58 +01001947 }
Stefan Roesec865e6c2006-02-28 15:29:58 +01001948 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001949#endif /* CFG_FLASH_PROTECTION */
1950 }
Stefan Roesec865e6c2006-02-28 15:29:58 +01001951
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001952 /* Monitor protection ON by default */
1953#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
1954 flash_protect (FLAG_PROTECT_SET,
1955 CFG_MONITOR_BASE,
1956 CFG_MONITOR_BASE + monitor_flash_len - 1,
1957 flash_get_info(CFG_MONITOR_BASE));
1958#endif
Stefan Roesec865e6c2006-02-28 15:29:58 +01001959
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001960 /* Environment protection ON by default */
1961#ifdef CFG_ENV_IS_IN_FLASH
1962 flash_protect (FLAG_PROTECT_SET,
1963 CFG_ENV_ADDR,
1964 CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
1965 flash_get_info(CFG_ENV_ADDR));
1966#endif
Stefan Roesec865e6c2006-02-28 15:29:58 +01001967
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001968 /* Redundant environment protection ON by default */
1969#ifdef CFG_ENV_ADDR_REDUND
1970 flash_protect (FLAG_PROTECT_SET,
1971 CFG_ENV_ADDR_REDUND,
1972 CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
1973 flash_get_info(CFG_ENV_ADDR_REDUND));
1974#endif
Matthias Fuchs50431522008-04-18 16:29:40 +02001975
1976#if defined(CFG_FLASH_AUTOPROTECT_LIST)
1977 for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
1978 debug("autoprotecting from %08x to %08x\n",
1979 apl[i].start, apl[i].start + apl[i].size - 1);
1980 flash_protect (FLAG_PROTECT_SET,
1981 apl[i].start,
1982 apl[i].start + apl[i].size - 1,
1983 flash_get_info(apl[i].start));
1984 }
1985#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001986 return (size);
wdenk2cefd152004-02-08 22:55:38 +00001987}
Heiko Schocher3c58a992007-01-11 15:44:44 +01001988
wdenk2cefd152004-02-08 22:55:38 +00001989#endif /* CFG_FLASH_CFI */