blob: f04c72d05a33bc6a2c0e2f6cefb660e001994416 [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
242static u64 flash_read64(void *addr)
243{
244 /* No architectures currently implement __raw_readq() */
245 return *(volatile u64 *)addr;
246}
247
wdenk2cefd152004-02-08 22:55:38 +0000248/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000249 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200250#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
251static flash_info_t *flash_get_info(ulong base)
252{
253 int i;
254 flash_info_t * info = 0;
wdenk2cefd152004-02-08 22:55:38 +0000255
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200256 for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
257 info = & flash_info[i];
258 if (info->size && info->start[0] <= base &&
259 base <= info->start[0] + info->size - 1)
260 break;
261 }
wdenk2cefd152004-02-08 22:55:38 +0000262
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200263 return i == CFG_MAX_FLASH_BANKS ? 0 : info;
264}
wdenk2cefd152004-02-08 22:55:38 +0000265#endif
266
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100267unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
268{
269 if (sect != (info->sector_count - 1))
270 return info->start[sect + 1] - info->start[sect];
271 else
272 return info->start[0] + info->size - info->start[sect];
273}
274
wdenke65527f2004-02-12 00:47:09 +0000275/*-----------------------------------------------------------------------
276 * create an address based on the offset and the port width
277 */
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100278static inline void *
279flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
wdenke65527f2004-02-12 00:47:09 +0000280{
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100281 unsigned int byte_offset = offset * info->portwidth;
282
283 return map_physmem(info->start[sect] + byte_offset,
284 flash_sector_size(info, sect) - byte_offset,
285 MAP_NOCACHE);
286}
287
288static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
289 unsigned int offset, void *addr)
290{
291 unsigned int byte_offset = offset * info->portwidth;
292
293 unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset);
wdenke65527f2004-02-12 00:47:09 +0000294}
295
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200296/*-----------------------------------------------------------------------
297 * make a proper sized command based on the port and chip widths
298 */
299static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
300{
301 int i;
302 uchar *cp = (uchar *) cmdbuf;
303
304#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
305 for (i = info->portwidth; i > 0; i--)
306#else
307 for (i = 1; i <= info->portwidth; i++)
308#endif
309 *cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;
310}
311
wdenk2cefd152004-02-08 22:55:38 +0000312#ifdef DEBUG
wdenke65527f2004-02-12 00:47:09 +0000313/*-----------------------------------------------------------------------
314 * Debug support
315 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100316static void print_longlong (char *str, unsigned long long data)
wdenk2cefd152004-02-08 22:55:38 +0000317{
318 int i;
319 char *cp;
wdenke65527f2004-02-12 00:47:09 +0000320
321 cp = (unsigned char *) &data;
322 for (i = 0; i < 8; i++)
323 sprintf (&str[i * 2], "%2.2x", *cp++);
wdenk2cefd152004-02-08 22:55:38 +0000324}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200325
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100326static void flash_printqry (struct cfi_qry *qry)
wdenke65527f2004-02-12 00:47:09 +0000327{
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100328 u8 *p = (u8 *)qry;
wdenke65527f2004-02-12 00:47:09 +0000329 int x, y;
330
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100331 for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
332 debug("%02x : ", x);
333 for (y = 0; y < 16; y++)
334 debug("%2.2x ", p[x + y]);
335 debug(" ");
wdenke65527f2004-02-12 00:47:09 +0000336 for (y = 0; y < 16; y++) {
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100337 unsigned char c = p[x + y];
338 if (c >= 0x20 && c <= 0x7e)
339 debug("%c", c);
340 else
341 debug(".");
wdenke65527f2004-02-12 00:47:09 +0000342 }
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100343 debug("\n");
wdenke65527f2004-02-12 00:47:09 +0000344 }
345}
wdenk2cefd152004-02-08 22:55:38 +0000346#endif
347
348
349/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000350 * read a character at a port width address
351 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100352static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000353{
354 uchar *cp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100355 uchar retval;
wdenke65527f2004-02-12 00:47:09 +0000356
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100357 cp = flash_map (info, 0, offset);
Heiko Schocher800db312007-01-19 18:05:26 +0100358#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100359 retval = flash_read8(cp);
wdenke65527f2004-02-12 00:47:09 +0000360#else
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100361 retval = flash_read8(cp + info->portwidth - 1);
wdenke65527f2004-02-12 00:47:09 +0000362#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100363 flash_unmap (info, 0, offset, cp);
364 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000365}
366
367/*-----------------------------------------------------------------------
Stefan Roese12797482006-11-13 13:55:24 +0100368 * read a long word by picking the least significant byte of each maximum
wdenk2cefd152004-02-08 22:55:38 +0000369 * port size word. Swap for ppc format.
370 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100371static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
372 uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000373{
wdenke65527f2004-02-12 00:47:09 +0000374 uchar *addr;
375 ulong retval;
376
377#ifdef DEBUG
378 int x;
379#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100380 addr = flash_map (info, sect, offset);
wdenk2cefd152004-02-08 22:55:38 +0000381
wdenke65527f2004-02-12 00:47:09 +0000382#ifdef DEBUG
383 debug ("long addr is at %p info->portwidth = %d\n", addr,
384 info->portwidth);
385 for (x = 0; x < 4 * info->portwidth; x++) {
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100386 debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
wdenke65527f2004-02-12 00:47:09 +0000387 }
388#endif
Heiko Schocher800db312007-01-19 18:05:26 +0100389#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100390 retval = ((flash_read8(addr) << 16) |
391 (flash_read8(addr + info->portwidth) << 24) |
392 (flash_read8(addr + 2 * info->portwidth)) |
393 (flash_read8(addr + 3 * info->portwidth) << 8));
wdenke65527f2004-02-12 00:47:09 +0000394#else
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100395 retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
396 (flash_read8(addr + info->portwidth - 1) << 16) |
397 (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
398 (flash_read8(addr + 3 * info->portwidth - 1)));
wdenke65527f2004-02-12 00:47:09 +0000399#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100400 flash_unmap(info, sect, offset, addr);
401
wdenke65527f2004-02-12 00:47:09 +0000402 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000403}
404
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200405/*
406 * Write a proper sized command to the correct address
Michael Schwingen73d044d2007-12-07 23:35:02 +0100407 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200408static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
409 uint offset, uchar cmd)
Michael Schwingen73d044d2007-12-07 23:35:02 +0100410{
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100411
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100412 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200413 cfiword_t cword;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100414
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100415 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200416 flash_make_cmd (info, cmd, &cword);
417 switch (info->portwidth) {
418 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100419 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200420 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100421 flash_write8(cword.c, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200422 break;
423 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100424 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200425 cmd, cword.w,
426 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100427 flash_write16(cword.w, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200428 break;
429 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100430 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200431 cmd, cword.l,
432 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100433 flash_write32(cword.l, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200434 break;
435 case FLASH_CFI_64BIT:
436#ifdef DEBUG
437 {
438 char str[20];
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100439
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200440 print_longlong (str, cword.ll);
441
442 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100443 addr, cmd, str,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200444 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100445 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200446#endif
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100447 flash_write64(cword.ll, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200448 break;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100449 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200450
451 /* Ensure all the instructions are fully finished */
452 sync();
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100453
454 flash_unmap(info, sect, offset, addr);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100455}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200456
457static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
Michael Schwingen73d044d2007-12-07 23:35:02 +0100458{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200459 flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
460 flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100461}
Michael Schwingen73d044d2007-12-07 23:35:02 +0100462
463/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000464 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200465static int flash_isequal (flash_info_t * info, flash_sect_t sect,
466 uint offset, uchar cmd)
wdenk2cefd152004-02-08 22:55:38 +0000467{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100468 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200469 cfiword_t cword;
470 int retval;
wdenk2cefd152004-02-08 22:55:38 +0000471
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100472 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200473 flash_make_cmd (info, cmd, &cword);
Stefan Roeseefef95b2006-04-01 13:41:03 +0200474
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100475 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200476 switch (info->portwidth) {
477 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100478 debug ("is= %x %x\n", flash_read8(addr), cword.c);
479 retval = (flash_read8(addr) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200480 break;
481 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100482 debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
483 retval = (flash_read16(addr) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200484 break;
485 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100486 debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
487 retval = (flash_read32(addr) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200488 break;
489 case FLASH_CFI_64BIT:
490#ifdef DEBUG
491 {
492 char str1[20];
493 char str2[20];
Michael Schwingen73d044d2007-12-07 23:35:02 +0100494
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100495 print_longlong (str1, flash_read64(addr));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200496 print_longlong (str2, cword.ll);
497 debug ("is= %s %s\n", str1, str2);
wdenk2cefd152004-02-08 22:55:38 +0000498 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200499#endif
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100500 retval = (flash_read64(addr) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200501 break;
502 default:
503 retval = 0;
504 break;
505 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100506 flash_unmap(info, sect, offset, addr);
507
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200508 return retval;
509}
Stefan Roeseefef95b2006-04-01 13:41:03 +0200510
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200511/*-----------------------------------------------------------------------
512 */
513static int flash_isset (flash_info_t * info, flash_sect_t sect,
514 uint offset, uchar cmd)
515{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100516 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200517 cfiword_t cword;
518 int retval;
Stefan Roeseefef95b2006-04-01 13:41:03 +0200519
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100520 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200521 flash_make_cmd (info, cmd, &cword);
522 switch (info->portwidth) {
523 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100524 retval = ((flash_read8(addr) & cword.c) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200525 break;
526 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100527 retval = ((flash_read16(addr) & cword.w) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200528 break;
529 case FLASH_CFI_32BIT:
Stefan Roesed4e37c02008-01-02 14:05:37 +0100530 retval = ((flash_read32(addr) & cword.l) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200531 break;
532 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100533 retval = ((flash_read64(addr) & cword.ll) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200534 break;
535 default:
536 retval = 0;
537 break;
538 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100539 flash_unmap(info, sect, offset, addr);
540
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200541 return retval;
542}
Stefan Roeseefef95b2006-04-01 13:41:03 +0200543
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200544/*-----------------------------------------------------------------------
545 */
546static int flash_toggle (flash_info_t * info, flash_sect_t sect,
547 uint offset, uchar cmd)
548{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100549 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200550 cfiword_t cword;
551 int retval;
wdenke85b7a52004-10-10 22:16:06 +0000552
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100553 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200554 flash_make_cmd (info, cmd, &cword);
555 switch (info->portwidth) {
556 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100557 retval = ((flash_read8(addr) & cword.c) !=
558 (flash_read8(addr) & cword.c));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200559 break;
560 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100561 retval = ((flash_read16(addr) & cword.w) !=
562 (flash_read16(addr) & cword.w));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200563 break;
564 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100565 retval = ((flash_read32(addr) & cword.l) !=
566 (flash_read32(addr) & cword.l));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200567 break;
568 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100569 retval = ((flash_read64(addr) & cword.ll) !=
570 (flash_read64(addr) & cword.ll));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200571 break;
572 default:
573 retval = 0;
574 break;
575 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100576 flash_unmap(info, sect, offset, addr);
577
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200578 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000579}
580
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200581/*
582 * flash_is_busy - check to see if the flash is busy
583 *
584 * This routine checks the status of the chip and returns true if the
585 * chip is busy.
wdenk2cefd152004-02-08 22:55:38 +0000586 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200587static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
wdenk5c71a7a2005-05-16 15:23:22 +0000588{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200589 int retval;
wdenk5c71a7a2005-05-16 15:23:22 +0000590
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200591 switch (info->vendor) {
592 case CFI_CMDSET_INTEL_STANDARD:
593 case CFI_CMDSET_INTEL_EXTENDED:
594 retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
595 break;
596 case CFI_CMDSET_AMD_STANDARD:
597 case CFI_CMDSET_AMD_EXTENDED:
598#ifdef CONFIG_FLASH_CFI_LEGACY
599 case CFI_CMDSET_AMD_LEGACY:
600#endif
601 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
602 break;
603 default:
604 retval = 0;
wdenk5c71a7a2005-05-16 15:23:22 +0000605 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200606 debug ("flash_is_busy: %d\n", retval);
607 return retval;
wdenk5c71a7a2005-05-16 15:23:22 +0000608}
609
610/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200611 * wait for XSR.7 to be set. Time out with an error if it does not.
612 * This routine does not set the flash to read-array mode.
wdenk5c71a7a2005-05-16 15:23:22 +0000613 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200614static int flash_status_check (flash_info_t * info, flash_sect_t sector,
615 ulong tout, char *prompt)
wdenk2cefd152004-02-08 22:55:38 +0000616{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200617 ulong start;
wdenk2cefd152004-02-08 22:55:38 +0000618
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200619#if CFG_HZ != 1000
620 tout *= CFG_HZ/1000;
621#endif
wdenk2cefd152004-02-08 22:55:38 +0000622
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200623 /* Wait for command completion */
624 start = get_timer (0);
625 while (flash_is_busy (info, sector)) {
626 if (get_timer (start) > tout) {
627 printf ("Flash %s timeout at address %lx data %lx\n",
628 prompt, info->start[sector],
629 flash_read_long (info, sector, 0));
630 flash_write_cmd (info, sector, 0, info->cmd_reset);
631 return ERR_TIMOUT;
wdenk2cefd152004-02-08 22:55:38 +0000632 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200633 udelay (1); /* also triggers watchdog */
wdenk2cefd152004-02-08 22:55:38 +0000634 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200635 return ERR_OK;
636}
wdenk2cefd152004-02-08 22:55:38 +0000637
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200638/*-----------------------------------------------------------------------
639 * Wait for XSR.7 to be set, if it times out print an error, otherwise
640 * do a full status check.
641 *
642 * This routine sets the flash to read-array mode.
643 */
644static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
645 ulong tout, char *prompt)
646{
647 int retcode;
wdenk2cefd152004-02-08 22:55:38 +0000648
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200649 retcode = flash_status_check (info, sector, tout, prompt);
650 switch (info->vendor) {
651 case CFI_CMDSET_INTEL_EXTENDED:
652 case CFI_CMDSET_INTEL_STANDARD:
653 if ((retcode == ERR_OK)
654 && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
655 retcode = ERR_INVAL;
656 printf ("Flash %s error at address %lx\n", prompt,
657 info->start[sector]);
658 if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
659 FLASH_STATUS_PSLBS)) {
660 puts ("Command Sequence Error.\n");
661 } else if (flash_isset (info, sector, 0,
662 FLASH_STATUS_ECLBS)) {
663 puts ("Block Erase Error.\n");
664 retcode = ERR_NOT_ERASED;
665 } else if (flash_isset (info, sector, 0,
666 FLASH_STATUS_PSLBS)) {
667 puts ("Locking Error\n");
wdenk2cefd152004-02-08 22:55:38 +0000668 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200669 if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
670 puts ("Block locked.\n");
671 retcode = ERR_PROTECTED;
672 }
673 if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
674 puts ("Vpp Low Error.\n");
wdenk2cefd152004-02-08 22:55:38 +0000675 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200676 flash_write_cmd (info, sector, 0, info->cmd_reset);
677 break;
678 default:
679 break;
wdenk2cefd152004-02-08 22:55:38 +0000680 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200681 return retcode;
wdenk2cefd152004-02-08 22:55:38 +0000682}
683
684/*-----------------------------------------------------------------------
685 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200686static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
wdenk2cefd152004-02-08 22:55:38 +0000687{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200688#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
689 unsigned short w;
690 unsigned int l;
691 unsigned long long ll;
692#endif
wdenk2cefd152004-02-08 22:55:38 +0000693
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200694 switch (info->portwidth) {
695 case FLASH_CFI_8BIT:
696 cword->c = c;
697 break;
698 case FLASH_CFI_16BIT:
699#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
700 w = c;
701 w <<= 8;
702 cword->w = (cword->w >> 8) | w;
703#else
704 cword->w = (cword->w << 8) | c;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100705#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200706 break;
707 case FLASH_CFI_32BIT:
708#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
709 l = c;
710 l <<= 24;
711 cword->l = (cword->l >> 8) | l;
712#else
713 cword->l = (cword->l << 8) | c;
714#endif
715 break;
716 case FLASH_CFI_64BIT:
717#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
718 ll = c;
719 ll <<= 56;
720 cword->ll = (cword->ll >> 8) | ll;
721#else
722 cword->ll = (cword->ll << 8) | c;
723#endif
724 break;
Stefan Roese12797482006-11-13 13:55:24 +0100725 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200726}
wdenk2cefd152004-02-08 22:55:38 +0000727
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200728/* loop through the sectors from the highest address when the passed
729 * address is greater or equal to the sector address we have a match
730 */
731static flash_sect_t find_sector (flash_info_t * info, ulong addr)
732{
733 flash_sect_t sector;
wdenk2cefd152004-02-08 22:55:38 +0000734
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200735 for (sector = info->sector_count - 1; sector >= 0; sector--) {
736 if (addr >= info->start[sector])
737 break;
wdenk2cefd152004-02-08 22:55:38 +0000738 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200739 return sector;
wdenk2cefd152004-02-08 22:55:38 +0000740}
741
742/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000743 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200744static int flash_write_cfiword (flash_info_t * info, ulong dest,
745 cfiword_t cword)
wdenk2cefd152004-02-08 22:55:38 +0000746{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100747 void *dstaddr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200748 int flag;
wdenk2cefd152004-02-08 22:55:38 +0000749
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100750 dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
wdenk2cefd152004-02-08 22:55:38 +0000751
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200752 /* Check if Flash is (sufficiently) erased */
753 switch (info->portwidth) {
754 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100755 flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200756 break;
757 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100758 flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200759 break;
760 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100761 flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200762 break;
763 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100764 flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200765 break;
766 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100767 flag = 0;
768 break;
wdenk2cefd152004-02-08 22:55:38 +0000769 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100770 if (!flag) {
771 unmap_physmem(dstaddr, info->portwidth);
Stefan Roese707c1462007-12-27 07:50:54 +0100772 return ERR_NOT_ERASED;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100773 }
wdenk2cefd152004-02-08 22:55:38 +0000774
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200775 /* Disable interrupts which might cause a timeout here */
776 flag = disable_interrupts ();
Stefan Roesec865e6c2006-02-28 15:29:58 +0100777
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200778 switch (info->vendor) {
779 case CFI_CMDSET_INTEL_EXTENDED:
780 case CFI_CMDSET_INTEL_STANDARD:
781 flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
782 flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
783 break;
784 case CFI_CMDSET_AMD_EXTENDED:
785 case CFI_CMDSET_AMD_STANDARD:
786#ifdef CONFIG_FLASH_CFI_LEGACY
787 case CFI_CMDSET_AMD_LEGACY:
788#endif
789 flash_unlock_seq (info, 0);
790 flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
791 break;
wdenk2cefd152004-02-08 22:55:38 +0000792 }
793
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200794 switch (info->portwidth) {
795 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100796 flash_write8(cword.c, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200797 break;
798 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100799 flash_write16(cword.w, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200800 break;
801 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100802 flash_write32(cword.l, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200803 break;
804 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100805 flash_write64(cword.ll, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200806 break;
wdenk2cefd152004-02-08 22:55:38 +0000807 }
808
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200809 /* re-enable interrupts if necessary */
810 if (flag)
811 enable_interrupts ();
wdenk2cefd152004-02-08 22:55:38 +0000812
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100813 unmap_physmem(dstaddr, info->portwidth);
814
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200815 return flash_full_status_check (info, find_sector (info, dest),
816 info->write_tout, "write");
wdenk2cefd152004-02-08 22:55:38 +0000817}
818
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200819#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenk2cefd152004-02-08 22:55:38 +0000820
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200821static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
822 int len)
wdenk2cefd152004-02-08 22:55:38 +0000823{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200824 flash_sect_t sector;
825 int cnt;
826 int retcode;
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100827 void *src = cp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100828 void *dst = map_physmem(dest, len, MAP_NOCACHE);
Stefan Roese707c1462007-12-27 07:50:54 +0100829 void *dst2 = dst;
830 int flag = 0;
831
832 switch (info->portwidth) {
833 case FLASH_CFI_8BIT:
834 cnt = len;
835 break;
836 case FLASH_CFI_16BIT:
837 cnt = len >> 1;
838 break;
839 case FLASH_CFI_32BIT:
840 cnt = len >> 2;
841 break;
842 case FLASH_CFI_64BIT:
843 cnt = len >> 3;
844 break;
845 default:
846 retcode = ERR_INVAL;
847 goto out_unmap;
848 }
849
850 while ((cnt-- > 0) && (flag == 0)) {
851 switch (info->portwidth) {
852 case FLASH_CFI_8BIT:
853 flag = ((flash_read8(dst2) & flash_read8(src)) ==
854 flash_read8(src));
855 src += 1, dst2 += 1;
856 break;
857 case FLASH_CFI_16BIT:
858 flag = ((flash_read16(dst2) & flash_read16(src)) ==
859 flash_read16(src));
860 src += 2, dst2 += 2;
861 break;
862 case FLASH_CFI_32BIT:
863 flag = ((flash_read32(dst2) & flash_read32(src)) ==
864 flash_read32(src));
865 src += 4, dst2 += 4;
866 break;
867 case FLASH_CFI_64BIT:
868 flag = ((flash_read64(dst2) & flash_read64(src)) ==
869 flash_read64(src));
870 src += 8, dst2 += 8;
871 break;
872 }
873 }
874 if (!flag) {
875 retcode = ERR_NOT_ERASED;
876 goto out_unmap;
877 }
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100878
Stefan Roese707c1462007-12-27 07:50:54 +0100879 src = cp;
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100880 sector = find_sector (info, dest);
wdenke65527f2004-02-12 00:47:09 +0000881
882 switch (info->vendor) {
wdenk2cefd152004-02-08 22:55:38 +0000883 case CFI_CMDSET_INTEL_STANDARD:
884 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200885 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
886 flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
887 retcode = flash_status_check (info, sector,
888 info->buffer_write_tout,
889 "write to buffer");
890 if (retcode == ERR_OK) {
891 /* reduce the number of loops by the width of
892 * the port */
893 switch (info->portwidth) {
894 case FLASH_CFI_8BIT:
895 cnt = len;
896 break;
897 case FLASH_CFI_16BIT:
898 cnt = len >> 1;
899 break;
900 case FLASH_CFI_32BIT:
901 cnt = len >> 2;
902 break;
903 case FLASH_CFI_64BIT:
904 cnt = len >> 3;
905 break;
906 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100907 retcode = ERR_INVAL;
908 goto out_unmap;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200909 }
910 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
911 while (cnt-- > 0) {
912 switch (info->portwidth) {
913 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100914 flash_write8(flash_read8(src), dst);
915 src += 1, dst += 1;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200916 break;
917 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100918 flash_write16(flash_read16(src), dst);
919 src += 2, dst += 2;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200920 break;
921 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100922 flash_write32(flash_read32(src), dst);
923 src += 4, dst += 4;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200924 break;
925 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100926 flash_write64(flash_read64(src), dst);
927 src += 8, dst += 8;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200928 break;
929 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100930 retcode = ERR_INVAL;
931 goto out_unmap;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200932 }
933 }
934 flash_write_cmd (info, sector, 0,
935 FLASH_CMD_WRITE_BUFFER_CONFIRM);
936 retcode = flash_full_status_check (
937 info, sector, info->buffer_write_tout,
938 "buffer write");
939 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100940
941 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200942
wdenk2cefd152004-02-08 22:55:38 +0000943 case CFI_CMDSET_AMD_STANDARD:
944 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200945 flash_unlock_seq(info,0);
946 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER);
947
948 switch (info->portwidth) {
949 case FLASH_CFI_8BIT:
950 cnt = len;
951 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100952 while (cnt-- > 0) {
953 flash_write8(flash_read8(src), dst);
954 src += 1, dst += 1;
955 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200956 break;
957 case FLASH_CFI_16BIT:
958 cnt = len >> 1;
959 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100960 while (cnt-- > 0) {
961 flash_write16(flash_read16(src), dst);
962 src += 2, dst += 2;
963 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200964 break;
965 case FLASH_CFI_32BIT:
966 cnt = len >> 2;
967 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100968 while (cnt-- > 0) {
969 flash_write32(flash_read32(src), dst);
970 src += 4, dst += 4;
971 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200972 break;
973 case FLASH_CFI_64BIT:
974 cnt = len >> 3;
975 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100976 while (cnt-- > 0) {
977 flash_write64(flash_read64(src), dst);
978 src += 8, dst += 8;
979 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200980 break;
981 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100982 retcode = ERR_INVAL;
983 goto out_unmap;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200984 }
985
986 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
987 retcode = flash_full_status_check (info, sector,
988 info->buffer_write_tout,
989 "buffer write");
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100990 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200991
wdenk2cefd152004-02-08 22:55:38 +0000992 default:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200993 debug ("Unknown Command Set\n");
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100994 retcode = ERR_INVAL;
995 break;
wdenk2cefd152004-02-08 22:55:38 +0000996 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100997
998out_unmap:
999 unmap_physmem(dst, len);
1000 return retcode;
wdenk2cefd152004-02-08 22:55:38 +00001001}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001002#endif /* CFG_FLASH_USE_BUFFER_WRITE */
1003
wdenke65527f2004-02-12 00:47:09 +00001004
wdenk2cefd152004-02-08 22:55:38 +00001005/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +00001006 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001007int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk2cefd152004-02-08 22:55:38 +00001008{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001009 int rcode = 0;
1010 int prot;
1011 flash_sect_t sect;
wdenk2cefd152004-02-08 22:55:38 +00001012
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001013 if (info->flash_id != FLASH_MAN_CFI) {
1014 puts ("Can't erase unknown flash type - aborted\n");
1015 return 1;
1016 }
1017 if ((s_first < 0) || (s_first > s_last)) {
1018 puts ("- no sectors to erase\n");
1019 return 1;
1020 }
Stefan Roeseefef95b2006-04-01 13:41:03 +02001021
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001022 prot = 0;
1023 for (sect = s_first; sect <= s_last; ++sect) {
1024 if (info->protect[sect]) {
1025 prot++;
wdenk2cefd152004-02-08 22:55:38 +00001026 }
1027 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001028 if (prot) {
1029 printf ("- Warning: %d protected sectors will not be erased!\n",
1030 prot);
1031 } else {
1032 putc ('\n');
1033 }
wdenke65527f2004-02-12 00:47:09 +00001034
wdenke65527f2004-02-12 00:47:09 +00001035
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001036 for (sect = s_first; sect <= s_last; sect++) {
1037 if (info->protect[sect] == 0) { /* not protected */
1038 switch (info->vendor) {
1039 case CFI_CMDSET_INTEL_STANDARD:
1040 case CFI_CMDSET_INTEL_EXTENDED:
1041 flash_write_cmd (info, sect, 0,
1042 FLASH_CMD_CLEAR_STATUS);
1043 flash_write_cmd (info, sect, 0,
1044 FLASH_CMD_BLOCK_ERASE);
1045 flash_write_cmd (info, sect, 0,
1046 FLASH_CMD_ERASE_CONFIRM);
1047 break;
1048 case CFI_CMDSET_AMD_STANDARD:
1049 case CFI_CMDSET_AMD_EXTENDED:
1050 flash_unlock_seq (info, sect);
1051 flash_write_cmd (info, sect,
1052 info->addr_unlock1,
1053 AMD_CMD_ERASE_START);
1054 flash_unlock_seq (info, sect);
1055 flash_write_cmd (info, sect, 0,
1056 AMD_CMD_ERASE_SECTOR);
1057 break;
1058#ifdef CONFIG_FLASH_CFI_LEGACY
1059 case CFI_CMDSET_AMD_LEGACY:
1060 flash_unlock_seq (info, 0);
1061 flash_write_cmd (info, 0, info->addr_unlock1,
1062 AMD_CMD_ERASE_START);
1063 flash_unlock_seq (info, 0);
1064 flash_write_cmd (info, sect, 0,
1065 AMD_CMD_ERASE_SECTOR);
1066 break;
1067#endif
1068 default:
1069 debug ("Unkown flash vendor %d\n",
1070 info->vendor);
1071 break;
wdenke65527f2004-02-12 00:47:09 +00001072 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001073
1074 if (flash_full_status_check
1075 (info, sect, info->erase_blk_tout, "erase")) {
1076 rcode = 1;
1077 } else
1078 putc ('.');
wdenk2cefd152004-02-08 22:55:38 +00001079 }
wdenk2cefd152004-02-08 22:55:38 +00001080 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001081 puts (" done\n");
1082 return rcode;
wdenk2cefd152004-02-08 22:55:38 +00001083}
wdenke65527f2004-02-12 00:47:09 +00001084
wdenk2cefd152004-02-08 22:55:38 +00001085/*-----------------------------------------------------------------------
1086 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001087void flash_print_info (flash_info_t * info)
wdenk2cefd152004-02-08 22:55:38 +00001088{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001089 int i;
wdenk369d43d2004-03-14 14:09:05 +00001090
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001091 if (info->flash_id != FLASH_MAN_CFI) {
1092 puts ("missing or unknown FLASH type\n");
1093 return;
1094 }
1095
1096 printf ("%s FLASH (%d x %d)",
1097 info->name,
1098 (info->portwidth << 3), (info->chipwidth << 3));
1099 if (info->size < 1024*1024)
1100 printf (" Size: %ld kB in %d Sectors\n",
1101 info->size >> 10, info->sector_count);
1102 else
1103 printf (" Size: %ld MB in %d Sectors\n",
1104 info->size >> 20, info->sector_count);
1105 printf (" ");
1106 switch (info->vendor) {
1107 case CFI_CMDSET_INTEL_STANDARD:
1108 printf ("Intel Standard");
1109 break;
1110 case CFI_CMDSET_INTEL_EXTENDED:
1111 printf ("Intel Extended");
1112 break;
1113 case CFI_CMDSET_AMD_STANDARD:
1114 printf ("AMD Standard");
1115 break;
1116 case CFI_CMDSET_AMD_EXTENDED:
1117 printf ("AMD Extended");
1118 break;
1119#ifdef CONFIG_FLASH_CFI_LEGACY
1120 case CFI_CMDSET_AMD_LEGACY:
1121 printf ("AMD Legacy");
1122 break;
wdenk369d43d2004-03-14 14:09:05 +00001123#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001124 default:
1125 printf ("Unknown (%d)", info->vendor);
1126 break;
wdenk2cefd152004-02-08 22:55:38 +00001127 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001128 printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
1129 info->manufacturer_id, info->device_id);
1130 if (info->device_id == 0x7E) {
1131 printf("%04X", info->device_id2);
1132 }
1133 printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n",
1134 info->erase_blk_tout,
1135 info->write_tout);
1136 if (info->buffer_size > 1) {
1137 printf (" Buffer write timeout: %ld ms, "
1138 "buffer size: %d bytes\n",
1139 info->buffer_write_tout,
1140 info->buffer_size);
1141 }
wdenk2cefd152004-02-08 22:55:38 +00001142
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001143 puts ("\n Sector Start Addresses:");
1144 for (i = 0; i < info->sector_count; ++i) {
1145 if ((i % 5) == 0)
1146 printf ("\n");
1147#ifdef CFG_FLASH_EMPTY_INFO
1148 int k;
1149 int size;
1150 int erased;
1151 volatile unsigned long *flash;
wdenk2cefd152004-02-08 22:55:38 +00001152
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001153 /*
1154 * Check if whole sector is erased
1155 */
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001156 size = flash_sector_size(info, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001157 erased = 1;
1158 flash = (volatile unsigned long *) info->start[i];
1159 size = size >> 2; /* divide by 4 for longword access */
1160 for (k = 0; k < size; k++) {
1161 if (*flash++ != 0xffffffff) {
1162 erased = 0;
1163 break;
1164 }
1165 }
wdenke65527f2004-02-12 00:47:09 +00001166
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001167 /* print empty and read-only info */
1168 printf (" %08lX %c %s ",
1169 info->start[i],
1170 erased ? 'E' : ' ',
1171 info->protect[i] ? "RO" : " ");
1172#else /* ! CFG_FLASH_EMPTY_INFO */
1173 printf (" %08lX %s ",
1174 info->start[i],
1175 info->protect[i] ? "RO" : " ");
wdenke65527f2004-02-12 00:47:09 +00001176#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001177 }
1178 putc ('\n');
1179 return;
wdenk2cefd152004-02-08 22:55:38 +00001180}
1181
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001182/*-----------------------------------------------------------------------
Jerry Van Barenaae73572008-03-08 13:48:01 -05001183 * This is used in a few places in write_buf() to show programming
1184 * progress. Making it a function is nasty because it needs to do side
1185 * effect updates to digit and dots. Repeated code is nasty too, so
1186 * we define it once here.
1187 */
Stefan Roese7758c162008-03-19 07:09:26 +01001188#ifdef CONFIG_FLASH_SHOW_PROGRESS
1189#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
1190 dots -= dots_sub; \
Jerry Van Barenaae73572008-03-08 13:48:01 -05001191 if ((scale > 0) && (dots <= 0)) { \
1192 if ((digit % 5) == 0) \
1193 printf ("%d", digit / 5); \
1194 else \
1195 putc ('.'); \
1196 digit--; \
1197 dots += scale; \
1198 }
Stefan Roese7758c162008-03-19 07:09:26 +01001199#else
1200#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1201#endif
Jerry Van Barenaae73572008-03-08 13:48:01 -05001202
1203/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001204 * Copy memory to flash, returns:
1205 * 0 - OK
1206 * 1 - write timeout
1207 * 2 - Flash not erased
wdenk2cefd152004-02-08 22:55:38 +00001208 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001209int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk2cefd152004-02-08 22:55:38 +00001210{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001211 ulong wp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001212 uchar *p;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001213 int aln;
wdenk2cefd152004-02-08 22:55:38 +00001214 cfiword_t cword;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001215 int i, rc;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001216#ifdef CFG_FLASH_USE_BUFFER_WRITE
1217 int buffered_size;
wdenk2cefd152004-02-08 22:55:38 +00001218#endif
Jerry Van Barenaae73572008-03-08 13:48:01 -05001219#ifdef CONFIG_FLASH_SHOW_PROGRESS
1220 int digit = CONFIG_FLASH_SHOW_PROGRESS;
1221 int scale = 0;
1222 int dots = 0;
1223
1224 /*
1225 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
1226 */
1227 if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
1228 scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
1229 CONFIG_FLASH_SHOW_PROGRESS);
1230 }
1231#endif
1232
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001233 /* get lower aligned address */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001234 wp = (addr & ~(info->portwidth - 1));
Haiying Wangc123a382007-02-21 16:52:31 +01001235
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001236 /* handle unaligned start */
1237 if ((aln = addr - wp) != 0) {
1238 cword.l = 0;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001239 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1240 for (i = 0; i < aln; ++i)
1241 flash_add_byte (info, &cword, flash_read8(p + i));
wdenk2cefd152004-02-08 22:55:38 +00001242
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001243 for (; (i < info->portwidth) && (cnt > 0); i++) {
1244 flash_add_byte (info, &cword, *src++);
1245 cnt--;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001246 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001247 for (; (cnt == 0) && (i < info->portwidth); ++i)
1248 flash_add_byte (info, &cword, flash_read8(p + i));
1249
1250 rc = flash_write_cfiword (info, wp, cword);
1251 unmap_physmem(p, info->portwidth);
1252 if (rc != 0)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001253 return rc;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001254
1255 wp += i;
Stefan Roese7758c162008-03-19 07:09:26 +01001256 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001257 }
1258
1259 /* handle the aligned part */
1260#ifdef CFG_FLASH_USE_BUFFER_WRITE
1261 buffered_size = (info->portwidth / info->chipwidth);
1262 buffered_size *= info->buffer_size;
1263 while (cnt >= info->portwidth) {
1264 /* prohibit buffer write when buffer_size is 1 */
1265 if (info->buffer_size == 1) {
1266 cword.l = 0;
1267 for (i = 0; i < info->portwidth; i++)
1268 flash_add_byte (info, &cword, *src++);
1269 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1270 return rc;
1271 wp += info->portwidth;
1272 cnt -= info->portwidth;
1273 continue;
1274 }
1275
1276 /* write buffer until next buffered_size aligned boundary */
1277 i = buffered_size - (wp % buffered_size);
1278 if (i > cnt)
1279 i = cnt;
1280 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
1281 return rc;
1282 i -= i & (info->portwidth - 1);
1283 wp += i;
1284 src += i;
1285 cnt -= i;
Stefan Roese7758c162008-03-19 07:09:26 +01001286 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001287 }
1288#else
1289 while (cnt >= info->portwidth) {
1290 cword.l = 0;
1291 for (i = 0; i < info->portwidth; i++) {
1292 flash_add_byte (info, &cword, *src++);
1293 }
1294 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1295 return rc;
1296 wp += info->portwidth;
1297 cnt -= info->portwidth;
Stefan Roese7758c162008-03-19 07:09:26 +01001298 FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001299 }
1300#endif /* CFG_FLASH_USE_BUFFER_WRITE */
Jerry Van Barenaae73572008-03-08 13:48:01 -05001301
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001302 if (cnt == 0) {
1303 return (0);
1304 }
1305
1306 /*
1307 * handle unaligned tail bytes
1308 */
1309 cword.l = 0;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001310 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1311 for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001312 flash_add_byte (info, &cword, *src++);
1313 --cnt;
1314 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001315 for (; i < info->portwidth; ++i)
1316 flash_add_byte (info, &cword, flash_read8(p + i));
1317 unmap_physmem(p, info->portwidth);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001318
1319 return flash_write_cfiword (info, wp, cword);
wdenk2cefd152004-02-08 22:55:38 +00001320}
wdenke65527f2004-02-12 00:47:09 +00001321
wdenk2cefd152004-02-08 22:55:38 +00001322/*-----------------------------------------------------------------------
1323 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001324#ifdef CFG_FLASH_PROTECTION
1325
1326int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk2cefd152004-02-08 22:55:38 +00001327{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001328 int retcode = 0;
wdenke65527f2004-02-12 00:47:09 +00001329
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001330 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1331 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1332 if (prot)
1333 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
1334 else
1335 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
wdenk2cefd152004-02-08 22:55:38 +00001336
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001337 if ((retcode =
1338 flash_full_status_check (info, sector, info->erase_blk_tout,
1339 prot ? "protect" : "unprotect")) == 0) {
wdenke65527f2004-02-12 00:47:09 +00001340
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001341 info->protect[sector] = prot;
1342
1343 /*
1344 * On some of Intel's flash chips (marked via legacy_unlock)
1345 * unprotect unprotects all locking.
1346 */
1347 if ((prot == 0) && (info->legacy_unlock)) {
1348 flash_sect_t i;
1349
1350 for (i = 0; i < info->sector_count; i++) {
1351 if (info->protect[i])
1352 flash_real_protect (info, i, 1);
1353 }
wdenk2cefd152004-02-08 22:55:38 +00001354 }
wdenk2cefd152004-02-08 22:55:38 +00001355 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001356 return retcode;
wdenk2cefd152004-02-08 22:55:38 +00001357}
wdenke65527f2004-02-12 00:47:09 +00001358
wdenk2cefd152004-02-08 22:55:38 +00001359/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001360 * flash_read_user_serial - read the OneTimeProgramming cells
wdenk2cefd152004-02-08 22:55:38 +00001361 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001362void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
1363 int len)
wdenk2cefd152004-02-08 22:55:38 +00001364{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001365 uchar *src;
1366 uchar *dst;
wdenke65527f2004-02-12 00:47:09 +00001367
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001368 dst = buffer;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001369 src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001370 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1371 memcpy (dst, src + offset, len);
1372 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001373 flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
wdenk2cefd152004-02-08 22:55:38 +00001374}
1375
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001376/*
1377 * flash_read_factory_serial - read the device Id from the protection area
wdenk2cefd152004-02-08 22:55:38 +00001378 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001379void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
1380 int len)
wdenk2cefd152004-02-08 22:55:38 +00001381{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001382 uchar *src;
wdenke65527f2004-02-12 00:47:09 +00001383
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001384 src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001385 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1386 memcpy (buffer, src + offset, len);
1387 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001388 flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
wdenk2cefd152004-02-08 22:55:38 +00001389}
1390
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001391#endif /* CFG_FLASH_PROTECTION */
1392
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001393/*-----------------------------------------------------------------------
1394 * Reverse the order of the erase regions in the CFI QRY structure.
1395 * This is needed for chips that are either a) correctly detected as
1396 * top-boot, or b) buggy.
1397 */
1398static void cfi_reverse_geometry(struct cfi_qry *qry)
1399{
1400 unsigned int i, j;
1401 u32 tmp;
1402
1403 for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
1404 tmp = qry->erase_region_info[i];
1405 qry->erase_region_info[i] = qry->erase_region_info[j];
1406 qry->erase_region_info[j] = tmp;
1407 }
1408}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001409
wdenk2cefd152004-02-08 22:55:38 +00001410/*-----------------------------------------------------------------------
Stefan Roese12797482006-11-13 13:55:24 +01001411 * read jedec ids from device and set corresponding fields in info struct
1412 *
1413 * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1414 *
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001415 */
1416static void cmdset_intel_read_jedec_ids(flash_info_t *info)
1417{
1418 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1419 flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1420 udelay(1000); /* some flash are slow to respond */
1421 info->manufacturer_id = flash_read_uchar (info,
1422 FLASH_OFFSET_MANUFACTURER_ID);
1423 info->device_id = flash_read_uchar (info,
1424 FLASH_OFFSET_DEVICE_ID);
1425 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1426}
1427
1428static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
1429{
1430 info->cmd_reset = FLASH_CMD_RESET;
1431
1432 cmdset_intel_read_jedec_ids(info);
1433 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1434
1435#ifdef CFG_FLASH_PROTECTION
1436 /* read legacy lock/unlock bit from intel flash */
1437 if (info->ext_addr) {
1438 info->legacy_unlock = flash_read_uchar (info,
1439 info->ext_addr + 5) & 0x08;
1440 }
1441#endif
1442
1443 return 0;
1444}
1445
1446static void cmdset_amd_read_jedec_ids(flash_info_t *info)
1447{
1448 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1449 flash_unlock_seq(info, 0);
1450 flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
1451 udelay(1000); /* some flash are slow to respond */
1452 info->manufacturer_id = flash_read_uchar (info,
1453 FLASH_OFFSET_MANUFACTURER_ID);
1454 info->device_id = flash_read_uchar (info,
1455 FLASH_OFFSET_DEVICE_ID);
1456 if (info->device_id == 0x7E) {
1457 /* AMD 3-byte (expanded) device ids */
1458 info->device_id2 = flash_read_uchar (info,
1459 FLASH_OFFSET_DEVICE_ID2);
1460 info->device_id2 <<= 8;
1461 info->device_id2 |= flash_read_uchar (info,
1462 FLASH_OFFSET_DEVICE_ID3);
1463 }
1464 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1465}
1466
1467static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
1468{
1469 info->cmd_reset = AMD_CMD_RESET;
1470
1471 cmdset_amd_read_jedec_ids(info);
1472 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1473
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001474 return 0;
1475}
1476
1477#ifdef CONFIG_FLASH_CFI_LEGACY
Stefan Roese12797482006-11-13 13:55:24 +01001478static void flash_read_jedec_ids (flash_info_t * info)
1479{
1480 info->manufacturer_id = 0;
1481 info->device_id = 0;
1482 info->device_id2 = 0;
1483
1484 switch (info->vendor) {
1485 case CFI_CMDSET_INTEL_STANDARD:
1486 case CFI_CMDSET_INTEL_EXTENDED:
Michael Schwingen5fb0aa42008-01-12 20:29:47 +01001487 cmdset_intel_read_jedec_ids(info);
Stefan Roese12797482006-11-13 13:55:24 +01001488 break;
1489 case CFI_CMDSET_AMD_STANDARD:
1490 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen5fb0aa42008-01-12 20:29:47 +01001491 cmdset_amd_read_jedec_ids(info);
Stefan Roese12797482006-11-13 13:55:24 +01001492 break;
1493 default:
1494 break;
1495 }
1496}
1497
1498/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001499 * Call board code to request info about non-CFI flash.
1500 * board_flash_get_legacy needs to fill in at least:
1501 * info->portwidth, info->chipwidth and info->interface for Jedec probing.
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001502 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001503static int flash_detect_legacy(ulong base, int banknum)
wdenk2cefd152004-02-08 22:55:38 +00001504{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001505 flash_info_t *info = &flash_info[banknum];
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001506
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001507 if (board_flash_get_legacy(base, banknum, info)) {
1508 /* board code may have filled info completely. If not, we
1509 use JEDEC ID probing. */
1510 if (!info->vendor) {
1511 int modes[] = {
1512 CFI_CMDSET_AMD_STANDARD,
1513 CFI_CMDSET_INTEL_STANDARD
1514 };
1515 int i;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001516
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001517 for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1518 info->vendor = modes[i];
1519 info->start[0] = base;
1520 if (info->portwidth == FLASH_CFI_8BIT
1521 && info->interface == FLASH_CFI_X8X16) {
1522 info->addr_unlock1 = 0x2AAA;
1523 info->addr_unlock2 = 0x5555;
1524 } else {
1525 info->addr_unlock1 = 0x5555;
1526 info->addr_unlock2 = 0x2AAA;
1527 }
1528 flash_read_jedec_ids(info);
1529 debug("JEDEC PROBE: ID %x %x %x\n",
1530 info->manufacturer_id,
1531 info->device_id,
1532 info->device_id2);
1533 if (jedec_flash_match(info, base))
1534 break;
1535 }
1536 }
1537
1538 switch(info->vendor) {
1539 case CFI_CMDSET_INTEL_STANDARD:
1540 case CFI_CMDSET_INTEL_EXTENDED:
1541 info->cmd_reset = FLASH_CMD_RESET;
1542 break;
1543 case CFI_CMDSET_AMD_STANDARD:
1544 case CFI_CMDSET_AMD_EXTENDED:
1545 case CFI_CMDSET_AMD_LEGACY:
1546 info->cmd_reset = AMD_CMD_RESET;
1547 break;
1548 }
1549 info->flash_id = FLASH_MAN_CFI;
1550 return 1;
1551 }
1552 return 0; /* use CFI */
1553}
1554#else
1555static inline int flash_detect_legacy(ulong base, int banknum)
1556{
1557 return 0; /* use CFI */
1558}
1559#endif
1560
1561/*-----------------------------------------------------------------------
1562 * detect if flash is compatible with the Common Flash Interface (CFI)
1563 * http://www.jedec.org/download/search/jesd68.pdf
1564 */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001565static void flash_read_cfi (flash_info_t *info, void *buf,
1566 unsigned int start, size_t len)
1567{
1568 u8 *p = buf;
1569 unsigned int i;
1570
1571 for (i = 0; i < len; i++)
1572 p[i] = flash_read_uchar(info, start + i);
1573}
1574
1575static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001576{
1577 int cfi_offset;
1578
Michael Schwingen4661cf72008-02-18 23:16:35 +01001579 /* We do not yet know what kind of commandset to use, so we issue
1580 the reset command in both Intel and AMD variants, in the hope
1581 that AMD flash roms ignore the Intel command. */
1582 flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
1583 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
1584
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001585 for (cfi_offset=0;
1586 cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
1587 cfi_offset++) {
1588 flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
1589 FLASH_CMD_CFI);
1590 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1591 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1592 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001593 flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1594 sizeof(struct cfi_qry));
1595 info->interface = le16_to_cpu(qry->interface_desc);
1596
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001597 info->cfi_offset = flash_offset_cfi[cfi_offset];
1598 debug ("device interface is %d\n",
1599 info->interface);
1600 debug ("found port %d chip %d ",
1601 info->portwidth, info->chipwidth);
1602 debug ("port %d bits chip %d bits\n",
1603 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1604 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1605
1606 /* calculate command offsets as in the Linux driver */
1607 info->addr_unlock1 = 0x555;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001608 info->addr_unlock2 = 0x2aa;
1609
1610 /*
1611 * modify the unlock address if we are
1612 * in compatibility mode
1613 */
1614 if ( /* x8/x16 in x8 mode */
1615 ((info->chipwidth == FLASH_CFI_BY8) &&
1616 (info->interface == FLASH_CFI_X8X16)) ||
1617 /* x16/x32 in x16 mode */
1618 ((info->chipwidth == FLASH_CFI_BY16) &&
1619 (info->interface == FLASH_CFI_X16X32)))
1620 {
1621 info->addr_unlock1 = 0xaaa;
1622 info->addr_unlock2 = 0x555;
1623 }
1624
1625 info->name = "CFI conformant";
1626 return 1;
1627 }
1628 }
1629
1630 return 0;
1631}
1632
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001633static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001634{
wdenke65527f2004-02-12 00:47:09 +00001635 debug ("flash detect cfi\n");
wdenk2cefd152004-02-08 22:55:38 +00001636
Stefan Roesec865e6c2006-02-28 15:29:58 +01001637 for (info->portwidth = CFG_FLASH_CFI_WIDTH;
wdenke65527f2004-02-12 00:47:09 +00001638 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1639 for (info->chipwidth = FLASH_CFI_BY8;
1640 info->chipwidth <= info->portwidth;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001641 info->chipwidth <<= 1)
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001642 if (__flash_detect_cfi(info, qry))
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001643 return 1;
wdenk2cefd152004-02-08 22:55:38 +00001644 }
wdenke65527f2004-02-12 00:47:09 +00001645 debug ("not found\n");
wdenk2cefd152004-02-08 22:55:38 +00001646 return 0;
1647}
wdenke65527f2004-02-12 00:47:09 +00001648
wdenk2cefd152004-02-08 22:55:38 +00001649/*
Haavard Skinnemoen750ea7f2007-12-14 15:36:18 +01001650 * Manufacturer-specific quirks. Add workarounds for geometry
1651 * reversal, etc. here.
1652 */
1653static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1654{
1655 /* check if flash geometry needs reversal */
1656 if (qry->num_erase_regions > 1) {
1657 /* reverse geometry if top boot part */
1658 if (info->cfi_version < 0x3131) {
1659 /* CFI < 1.1, try to guess from device id */
1660 if ((info->device_id & 0x80) != 0)
1661 cfi_reverse_geometry(qry);
1662 } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1663 /* CFI >= 1.1, deduct from top/bottom flag */
1664 /* note: ext_addr is valid since cfi_version > 0 */
1665 cfi_reverse_geometry(qry);
1666 }
1667 }
1668}
1669
1670static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1671{
1672 int reverse_geometry = 0;
1673
1674 /* Check the "top boot" bit in the PRI */
1675 if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1676 reverse_geometry = 1;
1677
1678 /* AT49BV6416(T) list the erase regions in the wrong order.
1679 * However, the device ID is identical with the non-broken
1680 * AT49BV642D since u-boot only reads the low byte (they
1681 * differ in the high byte.) So leave out this fixup for now.
1682 */
1683#if 0
1684 if (info->device_id == 0xd6 || info->device_id == 0xd2)
1685 reverse_geometry = !reverse_geometry;
1686#endif
1687
1688 if (reverse_geometry)
1689 cfi_reverse_geometry(qry);
1690}
1691
1692/*
wdenk2cefd152004-02-08 22:55:38 +00001693 * The following code cannot be run from FLASH!
1694 *
1695 */
Marian Balakowicz513b4a12005-10-11 19:09:42 +02001696ulong flash_get_size (ulong base, int banknum)
wdenk2cefd152004-02-08 22:55:38 +00001697{
wdenke65527f2004-02-12 00:47:09 +00001698 flash_info_t *info = &flash_info[banknum];
wdenk2cefd152004-02-08 22:55:38 +00001699 int i, j;
1700 flash_sect_t sect_cnt;
1701 unsigned long sector;
1702 unsigned long tmp;
1703 int size_ratio;
1704 uchar num_erase_regions;
wdenke65527f2004-02-12 00:47:09 +00001705 int erase_region_size;
1706 int erase_region_count;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001707 struct cfi_qry qry;
Stefan Roese12797482006-11-13 13:55:24 +01001708
1709 info->ext_addr = 0;
1710 info->cfi_version = 0;
Stefan Roeseefef95b2006-04-01 13:41:03 +02001711#ifdef CFG_FLASH_PROTECTION
Stefan Roeseefef95b2006-04-01 13:41:03 +02001712 info->legacy_unlock = 0;
1713#endif
wdenk2cefd152004-02-08 22:55:38 +00001714
1715 info->start[0] = base;
1716
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001717 if (flash_detect_cfi (info, &qry)) {
1718 info->vendor = le16_to_cpu(qry.p_id);
1719 info->ext_addr = le16_to_cpu(qry.p_adr);
1720 num_erase_regions = qry.num_erase_regions;
1721
Stefan Roese12797482006-11-13 13:55:24 +01001722 if (info->ext_addr) {
1723 info->cfi_version = (ushort) flash_read_uchar (info,
1724 info->ext_addr + 3) << 8;
1725 info->cfi_version |= (ushort) flash_read_uchar (info,
1726 info->ext_addr + 4);
1727 }
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001728
wdenke65527f2004-02-12 00:47:09 +00001729#ifdef DEBUG
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001730 flash_printqry (&qry);
wdenke65527f2004-02-12 00:47:09 +00001731#endif
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001732
wdenke65527f2004-02-12 00:47:09 +00001733 switch (info->vendor) {
wdenk2cefd152004-02-08 22:55:38 +00001734 case CFI_CMDSET_INTEL_STANDARD:
1735 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001736 cmdset_intel_init(info, &qry);
wdenk2cefd152004-02-08 22:55:38 +00001737 break;
1738 case CFI_CMDSET_AMD_STANDARD:
1739 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001740 cmdset_amd_init(info, &qry);
wdenk2cefd152004-02-08 22:55:38 +00001741 break;
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001742 default:
1743 printf("CFI: Unknown command set 0x%x\n",
1744 info->vendor);
1745 /*
1746 * Unfortunately, this means we don't know how
1747 * to get the chip back to Read mode. Might
1748 * as well try an Intel-style reset...
1749 */
1750 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1751 return 0;
wdenk2cefd152004-02-08 22:55:38 +00001752 }
wdenk6cfa84e2004-02-10 00:03:41 +00001753
Haavard Skinnemoen750ea7f2007-12-14 15:36:18 +01001754 /* Do manufacturer-specific fixups */
1755 switch (info->manufacturer_id) {
1756 case 0x0001:
1757 flash_fixup_amd(info, &qry);
1758 break;
1759 case 0x001f:
1760 flash_fixup_atmel(info, &qry);
1761 break;
1762 }
1763
wdenke65527f2004-02-12 00:47:09 +00001764 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese12797482006-11-13 13:55:24 +01001765 debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
1766 debug ("device id is 0x%x\n", info->device_id);
1767 debug ("device id2 is 0x%x\n", info->device_id2);
1768 debug ("cfi version is 0x%04x\n", info->cfi_version);
1769
wdenk2cefd152004-02-08 22:55:38 +00001770 size_ratio = info->portwidth / info->chipwidth;
wdenke65527f2004-02-12 00:47:09 +00001771 /* if the chip is x8/x16 reduce the ratio by half */
1772 if ((info->interface == FLASH_CFI_X8X16)
1773 && (info->chipwidth == FLASH_CFI_BY8)) {
1774 size_ratio >>= 1;
1775 }
wdenke65527f2004-02-12 00:47:09 +00001776 debug ("size_ratio %d port %d bits chip %d bits\n",
1777 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1778 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1779 debug ("found %d erase regions\n", num_erase_regions);
wdenk2cefd152004-02-08 22:55:38 +00001780 sect_cnt = 0;
1781 sector = base;
wdenke65527f2004-02-12 00:47:09 +00001782 for (i = 0; i < num_erase_regions; i++) {
1783 if (i > NUM_ERASE_REGIONS) {
wdenke537b3b2004-02-23 23:54:43 +00001784 printf ("%d erase regions found, only %d used\n",
1785 num_erase_regions, NUM_ERASE_REGIONS);
wdenk2cefd152004-02-08 22:55:38 +00001786 break;
1787 }
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001788
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001789 tmp = le32_to_cpu(qry.erase_region_info[i]);
1790 debug("erase region %u: 0x%08lx\n", i, tmp);
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001791
1792 erase_region_count = (tmp & 0xffff) + 1;
1793 tmp >>= 16;
wdenke65527f2004-02-12 00:47:09 +00001794 erase_region_size =
1795 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenkaeba06f2004-06-09 17:34:58 +00001796 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenke537b3b2004-02-23 23:54:43 +00001797 erase_region_count, erase_region_size);
wdenke65527f2004-02-12 00:47:09 +00001798 for (j = 0; j < erase_region_count; j++) {
Michael Schwingen73d044d2007-12-07 23:35:02 +01001799 if (sect_cnt >= CFG_MAX_FLASH_SECT) {
1800 printf("ERROR: too many flash sectors\n");
1801 break;
1802 }
wdenk2cefd152004-02-08 22:55:38 +00001803 info->start[sect_cnt] = sector;
1804 sector += (erase_region_size * size_ratio);
wdenk26c58432005-01-09 17:12:27 +00001805
1806 /*
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001807 * Only read protection status from
1808 * supported devices (intel...)
wdenk26c58432005-01-09 17:12:27 +00001809 */
1810 switch (info->vendor) {
1811 case CFI_CMDSET_INTEL_EXTENDED:
1812 case CFI_CMDSET_INTEL_STANDARD:
1813 info->protect[sect_cnt] =
1814 flash_isset (info, sect_cnt,
1815 FLASH_OFFSET_PROTECT,
1816 FLASH_STATUS_PROTECT);
1817 break;
1818 default:
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001819 /* default: not protected */
1820 info->protect[sect_cnt] = 0;
wdenk26c58432005-01-09 17:12:27 +00001821 }
1822
wdenk2cefd152004-02-08 22:55:38 +00001823 sect_cnt++;
1824 }
1825 }
1826
1827 info->sector_count = sect_cnt;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001828 info->size = 1 << qry.dev_size;
wdenk2cefd152004-02-08 22:55:38 +00001829 /* multiply the size by the number of chips */
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001830 info->size *= size_ratio;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001831 info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1832 tmp = 1 << qry.block_erase_timeout_typ;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001833 info->erase_blk_tout = tmp *
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001834 (1 << qry.block_erase_timeout_max);
1835 tmp = (1 << qry.buf_write_timeout_typ) *
1836 (1 << qry.buf_write_timeout_max);
1837
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001838 /* round up when converting to ms */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001839 info->buffer_write_tout = (tmp + 999) / 1000;
1840 tmp = (1 << qry.word_write_timeout_typ) *
1841 (1 << qry.word_write_timeout_max);
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001842 /* round up when converting to ms */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001843 info->write_tout = (tmp + 999) / 1000;
wdenk2cefd152004-02-08 22:55:38 +00001844 info->flash_id = FLASH_MAN_CFI;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001845 if ((info->interface == FLASH_CFI_X8X16) &&
1846 (info->chipwidth == FLASH_CFI_BY8)) {
1847 /* XXX - Need to test on x8/x16 in parallel. */
1848 info->portwidth >>= 1;
wdenked2ac4b2004-03-14 18:23:55 +00001849 }
wdenk2cefd152004-02-08 22:55:38 +00001850 }
1851
Wolfgang Denka205a8f2005-09-25 16:41:22 +02001852 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenke65527f2004-02-12 00:47:09 +00001853 return (info->size);
wdenk2cefd152004-02-08 22:55:38 +00001854}
1855
wdenk2cefd152004-02-08 22:55:38 +00001856/*-----------------------------------------------------------------------
1857 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001858unsigned long flash_init (void)
wdenk2cefd152004-02-08 22:55:38 +00001859{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001860 unsigned long size = 0;
1861 int i;
wdenk2cefd152004-02-08 22:55:38 +00001862
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001863#ifdef CFG_FLASH_PROTECTION
1864 char *s = getenv("unlock");
Michael Schwingen73d044d2007-12-07 23:35:02 +01001865#endif
wdenk2cefd152004-02-08 22:55:38 +00001866
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001867 /* Init: no FLASHes known */
1868 for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
1869 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenk2cefd152004-02-08 22:55:38 +00001870
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001871 if (!flash_detect_legacy (bank_base[i], i))
1872 flash_get_size (bank_base[i], i);
1873 size += flash_info[i].size;
1874 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
1875#ifndef CFG_FLASH_QUIET_TEST
1876 printf ("## Unknown FLASH on Bank %d "
1877 "- Size = 0x%08lx = %ld MB\n",
1878 i+1, flash_info[i].size,
1879 flash_info[i].size << 20);
1880#endif /* CFG_FLASH_QUIET_TEST */
1881 }
1882#ifdef CFG_FLASH_PROTECTION
1883 else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
1884 /*
1885 * Only the U-Boot image and it's environment
1886 * is protected, all other sectors are
1887 * unprotected (unlocked) if flash hardware
1888 * protection is used (CFG_FLASH_PROTECTION)
1889 * and the environment variable "unlock" is
1890 * set to "yes".
1891 */
1892 if (flash_info[i].legacy_unlock) {
1893 int k;
wdenk2cefd152004-02-08 22:55:38 +00001894
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001895 /*
1896 * Disable legacy_unlock temporarily,
1897 * since flash_real_protect would
1898 * relock all other sectors again
1899 * otherwise.
1900 */
1901 flash_info[i].legacy_unlock = 0;
wdenk2cefd152004-02-08 22:55:38 +00001902
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001903 /*
1904 * Legacy unlocking (e.g. Intel J3) ->
1905 * unlock only one sector. This will
1906 * unlock all sectors.
1907 */
1908 flash_real_protect (&flash_info[i], 0, 0);
wdenk2cefd152004-02-08 22:55:38 +00001909
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001910 flash_info[i].legacy_unlock = 1;
wdenk2cefd152004-02-08 22:55:38 +00001911
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001912 /*
1913 * Manually mark other sectors as
1914 * unlocked (unprotected)
1915 */
1916 for (k = 1; k < flash_info[i].sector_count; k++)
1917 flash_info[i].protect[k] = 0;
1918 } else {
1919 /*
1920 * No legancy unlocking -> unlock all sectors
1921 */
1922 flash_protect (FLAG_PROTECT_CLEAR,
1923 flash_info[i].start[0],
1924 flash_info[i].start[0]
1925 + flash_info[i].size - 1,
1926 &flash_info[i]);
Stefan Roesec865e6c2006-02-28 15:29:58 +01001927 }
Stefan Roesec865e6c2006-02-28 15:29:58 +01001928 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001929#endif /* CFG_FLASH_PROTECTION */
1930 }
Stefan Roesec865e6c2006-02-28 15:29:58 +01001931
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001932 /* Monitor protection ON by default */
1933#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
1934 flash_protect (FLAG_PROTECT_SET,
1935 CFG_MONITOR_BASE,
1936 CFG_MONITOR_BASE + monitor_flash_len - 1,
1937 flash_get_info(CFG_MONITOR_BASE));
1938#endif
Stefan Roesec865e6c2006-02-28 15:29:58 +01001939
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001940 /* Environment protection ON by default */
1941#ifdef CFG_ENV_IS_IN_FLASH
1942 flash_protect (FLAG_PROTECT_SET,
1943 CFG_ENV_ADDR,
1944 CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
1945 flash_get_info(CFG_ENV_ADDR));
1946#endif
Stefan Roesec865e6c2006-02-28 15:29:58 +01001947
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001948 /* Redundant environment protection ON by default */
1949#ifdef CFG_ENV_ADDR_REDUND
1950 flash_protect (FLAG_PROTECT_SET,
1951 CFG_ENV_ADDR_REDUND,
1952 CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
1953 flash_get_info(CFG_ENV_ADDR_REDUND));
1954#endif
1955 return (size);
wdenk2cefd152004-02-08 22:55:38 +00001956}
Heiko Schocher3c58a992007-01-11 15:44:44 +01001957
wdenk2cefd152004-02-08 22:55:38 +00001958#endif /* CFG_FLASH_CFI */