blob: b8422e15f365dab1df374b83765c110898e784c6 [file] [log] [blame]
wdenk5653fc32004-02-08 22:55:38 +00001/*
wdenkbf9e3b32004-02-12 00:47:09 +00002 * (C) Copyright 2002-2004
wdenk5653fc32004-02-08 22:55:38 +00003 * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com
4 *
5 * Copyright (C) 2003 Arabella Software Ltd.
6 * Yuli Barcohen <yuli@arabellasw.com>
wdenk5653fc32004-02-08 22:55:38 +00007 *
wdenkbf9e3b32004-02-12 00:47:09 +00008 * Copyright (C) 2004
9 * Ed Okerson
Stefan Roese260421a2006-11-13 13:55:24 +010010 *
11 * Copyright (C) 2006
12 * Tolunay Orkun <listmember@orkun.us>
wdenkbf9e3b32004-02-12 00:47:09 +000013 *
wdenk5653fc32004-02-08 22:55:38 +000014 * See file CREDITS for list of people who contributed to this
15 * project.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30 * MA 02111-1307 USA
31 *
wdenk5653fc32004-02-08 22:55:38 +000032 */
33
34/* The DEBUG define must be before common to enable debugging */
wdenk2d1a5372004-02-23 19:30:57 +000035/* #define DEBUG */
36
wdenk5653fc32004-02-08 22:55:38 +000037#include <common.h>
38#include <asm/processor.h>
Haiying Wang3a197b22007-02-21 16:52:31 +010039#include <asm/io.h>
wdenk4c0d4c32004-06-09 17:34:58 +000040#include <asm/byteorder.h>
wdenk2a8af182005-04-13 10:02:42 +000041#include <environment.h>
wdenk028ab6b2004-02-23 23:54:43 +000042
wdenk5653fc32004-02-08 22:55:38 +000043/*
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +010044 * This file implements a Common Flash Interface (CFI) driver for
45 * U-Boot.
46 *
47 * The width of the port and the width of the chips are determined at
48 * initialization. These widths are used to calculate the address for
49 * access CFI data structures.
wdenk5653fc32004-02-08 22:55:38 +000050 *
51 * References
52 * JEDEC Standard JESD68 - Common Flash Interface (CFI)
53 * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
54 * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
55 * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
Stefan Roese260421a2006-11-13 13:55:24 +010056 * AMD CFI Specification, Release 2.0 December 1, 2001
57 * AMD/Spansion Application Note: Migration from Single-byte to Three-byte
58 * Device IDs, Publication Number 25538 Revision A, November 8, 2001
wdenk5653fc32004-02-08 22:55:38 +000059 *
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020060 * Define CONFIG_SYS_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
Heiko Schocherd0b6e142007-01-19 18:05:26 +010061 * reading and writing ... (yes there is such a Hardware).
wdenk5653fc32004-02-08 22:55:38 +000062 */
63
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020064#ifndef CONFIG_SYS_FLASH_BANKS_LIST
65#define CONFIG_SYS_FLASH_BANKS_LIST { CONFIG_SYS_FLASH_BASE }
wdenkbf9e3b32004-02-12 00:47:09 +000066#endif
67
wdenk5653fc32004-02-08 22:55:38 +000068#define FLASH_CMD_CFI 0x98
69#define FLASH_CMD_READ_ID 0x90
70#define FLASH_CMD_RESET 0xff
71#define FLASH_CMD_BLOCK_ERASE 0x20
72#define FLASH_CMD_ERASE_CONFIRM 0xD0
73#define FLASH_CMD_WRITE 0x40
74#define FLASH_CMD_PROTECT 0x60
75#define FLASH_CMD_PROTECT_SET 0x01
76#define FLASH_CMD_PROTECT_CLEAR 0xD0
77#define FLASH_CMD_CLEAR_STATUS 0x50
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +040078#define FLASH_CMD_READ_STATUS 0x70
wdenkbf9e3b32004-02-12 00:47:09 +000079#define FLASH_CMD_WRITE_TO_BUFFER 0xE8
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +040080#define FLASH_CMD_WRITE_BUFFER_PROG 0xE9
wdenkbf9e3b32004-02-12 00:47:09 +000081#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0
wdenk5653fc32004-02-08 22:55:38 +000082
83#define FLASH_STATUS_DONE 0x80
84#define FLASH_STATUS_ESS 0x40
85#define FLASH_STATUS_ECLBS 0x20
86#define FLASH_STATUS_PSLBS 0x10
87#define FLASH_STATUS_VPENS 0x08
88#define FLASH_STATUS_PSS 0x04
89#define FLASH_STATUS_DPS 0x02
90#define FLASH_STATUS_R 0x01
91#define FLASH_STATUS_PROTECT 0x01
92
93#define AMD_CMD_RESET 0xF0
94#define AMD_CMD_WRITE 0xA0
95#define AMD_CMD_ERASE_START 0x80
96#define AMD_CMD_ERASE_SECTOR 0x30
wdenk855a4962004-03-14 18:23:55 +000097#define AMD_CMD_UNLOCK_START 0xAA
98#define AMD_CMD_UNLOCK_ACK 0x55
Stefan Roese79b4cda2006-02-28 15:29:58 +010099#define AMD_CMD_WRITE_TO_BUFFER 0x25
100#define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29
wdenk5653fc32004-02-08 22:55:38 +0000101
102#define AMD_STATUS_TOGGLE 0x40
103#define AMD_STATUS_ERROR 0x20
Stefan Roese79b4cda2006-02-28 15:29:58 +0100104
Rafael Camposbc9019e2008-07-31 10:22:20 +0200105#define ATM_CMD_UNLOCK_SECT 0x70
106#define ATM_CMD_SOFTLOCK_START 0x80
107#define ATM_CMD_LOCK_SECT 0x40
108
Stefan Roese260421a2006-11-13 13:55:24 +0100109#define FLASH_OFFSET_MANUFACTURER_ID 0x00
110#define FLASH_OFFSET_DEVICE_ID 0x01
111#define FLASH_OFFSET_DEVICE_ID2 0x0E
112#define FLASH_OFFSET_DEVICE_ID3 0x0F
wdenk5653fc32004-02-08 22:55:38 +0000113#define FLASH_OFFSET_CFI 0x55
Wolfgang Denk92eb7292006-12-27 01:26:13 +0100114#define FLASH_OFFSET_CFI_ALT 0x555
wdenk5653fc32004-02-08 22:55:38 +0000115#define FLASH_OFFSET_CFI_RESP 0x10
wdenkbf9e3b32004-02-12 00:47:09 +0000116#define FLASH_OFFSET_PRIMARY_VENDOR 0x13
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +0100117/* extended query table primary address */
118#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15
wdenk5653fc32004-02-08 22:55:38 +0000119#define FLASH_OFFSET_WTOUT 0x1F
wdenkbf9e3b32004-02-12 00:47:09 +0000120#define FLASH_OFFSET_WBTOUT 0x20
wdenk5653fc32004-02-08 22:55:38 +0000121#define FLASH_OFFSET_ETOUT 0x21
wdenkbf9e3b32004-02-12 00:47:09 +0000122#define FLASH_OFFSET_CETOUT 0x22
wdenk5653fc32004-02-08 22:55:38 +0000123#define FLASH_OFFSET_WMAX_TOUT 0x23
wdenkbf9e3b32004-02-12 00:47:09 +0000124#define FLASH_OFFSET_WBMAX_TOUT 0x24
wdenk5653fc32004-02-08 22:55:38 +0000125#define FLASH_OFFSET_EMAX_TOUT 0x25
wdenkbf9e3b32004-02-12 00:47:09 +0000126#define FLASH_OFFSET_CEMAX_TOUT 0x26
wdenk5653fc32004-02-08 22:55:38 +0000127#define FLASH_OFFSET_SIZE 0x27
wdenkbf9e3b32004-02-12 00:47:09 +0000128#define FLASH_OFFSET_INTERFACE 0x28
129#define FLASH_OFFSET_BUFFER_SIZE 0x2A
wdenk5653fc32004-02-08 22:55:38 +0000130#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C
131#define FLASH_OFFSET_ERASE_REGIONS 0x2D
132#define FLASH_OFFSET_PROTECT 0x02
wdenkbf9e3b32004-02-12 00:47:09 +0000133#define FLASH_OFFSET_USER_PROTECTION 0x85
134#define FLASH_OFFSET_INTEL_PROTECTION 0x81
wdenk5653fc32004-02-08 22:55:38 +0000135
Stefan Roese260421a2006-11-13 13:55:24 +0100136#define CFI_CMDSET_NONE 0
137#define CFI_CMDSET_INTEL_EXTENDED 1
138#define CFI_CMDSET_AMD_STANDARD 2
139#define CFI_CMDSET_INTEL_STANDARD 3
140#define CFI_CMDSET_AMD_EXTENDED 4
141#define CFI_CMDSET_MITSU_STANDARD 256
142#define CFI_CMDSET_MITSU_EXTENDED 257
143#define CFI_CMDSET_SST 258
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400144#define CFI_CMDSET_INTEL_PROG_REGIONS 512
wdenk5653fc32004-02-08 22:55:38 +0000145
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200146#ifdef CONFIG_SYS_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
wdenkf7d15722004-12-18 22:35:43 +0000147# undef FLASH_CMD_RESET
Stefan Roese260421a2006-11-13 13:55:24 +0100148# define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */
wdenkf7d15722004-12-18 22:35:43 +0000149#endif
150
wdenk5653fc32004-02-08 22:55:38 +0000151typedef union {
152 unsigned char c;
153 unsigned short w;
154 unsigned long l;
155 unsigned long long ll;
156} cfiword_t;
157
Stefan Roese260421a2006-11-13 13:55:24 +0100158#define NUM_ERASE_REGIONS 4 /* max. number of erase regions */
wdenk5653fc32004-02-08 22:55:38 +0000159
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +0100160static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
Piotr Ziecik6ea808e2008-11-17 15:49:32 +0100161static uint flash_verbose = 1;
Wolfgang Denk92eb7292006-12-27 01:26:13 +0100162
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200163/* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */
164#ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT
165# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS_DETECT
Marian Balakowicze6f2e902005-10-11 19:09:42 +0200166#else
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200167# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS
Marian Balakowicze6f2e902005-10-11 19:09:42 +0200168#endif
wdenk5653fc32004-02-08 22:55:38 +0000169
Wolfgang Denk2a112b22008-08-08 16:39:54 +0200170flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */
171
Stefan Roese79b4cda2006-02-28 15:29:58 +0100172/*
173 * Check if chip width is defined. If not, start detecting with 8bit.
174 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200175#ifndef CONFIG_SYS_FLASH_CFI_WIDTH
176#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_8BIT
Stefan Roese79b4cda2006-02-28 15:29:58 +0100177#endif
178
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100179/* CFI standard query structure */
180struct cfi_qry {
181 u8 qry[3];
182 u16 p_id;
183 u16 p_adr;
184 u16 a_id;
185 u16 a_adr;
186 u8 vcc_min;
187 u8 vcc_max;
188 u8 vpp_min;
189 u8 vpp_max;
190 u8 word_write_timeout_typ;
191 u8 buf_write_timeout_typ;
192 u8 block_erase_timeout_typ;
193 u8 chip_erase_timeout_typ;
194 u8 word_write_timeout_max;
195 u8 buf_write_timeout_max;
196 u8 block_erase_timeout_max;
197 u8 chip_erase_timeout_max;
198 u8 dev_size;
199 u16 interface_desc;
200 u16 max_buf_write_size;
201 u8 num_erase_regions;
202 u32 erase_region_info[NUM_ERASE_REGIONS];
203} __attribute__((packed));
204
205struct cfi_pri_hdr {
206 u8 pri[3];
207 u8 major_version;
208 u8 minor_version;
209} __attribute__((packed));
210
Stefan Roese45aa5a72008-11-17 14:45:22 +0100211static void __flash_write8(u8 value, void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100212{
213 __raw_writeb(value, addr);
214}
215
Stefan Roese45aa5a72008-11-17 14:45:22 +0100216static void __flash_write16(u16 value, void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100217{
218 __raw_writew(value, addr);
219}
220
Stefan Roese45aa5a72008-11-17 14:45:22 +0100221static void __flash_write32(u32 value, void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100222{
223 __raw_writel(value, addr);
224}
225
Stefan Roese45aa5a72008-11-17 14:45:22 +0100226static void __flash_write64(u64 value, void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100227{
228 /* No architectures currently implement __raw_writeq() */
229 *(volatile u64 *)addr = value;
230}
231
Stefan Roese45aa5a72008-11-17 14:45:22 +0100232static u8 __flash_read8(void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100233{
234 return __raw_readb(addr);
235}
236
Stefan Roese45aa5a72008-11-17 14:45:22 +0100237static u16 __flash_read16(void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100238{
239 return __raw_readw(addr);
240}
241
Stefan Roese45aa5a72008-11-17 14:45:22 +0100242static u32 __flash_read32(void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100243{
244 return __raw_readl(addr);
245}
246
Daniel Hellstrom97bf85d2008-03-28 20:40:19 +0100247static u64 __flash_read64(void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100248{
249 /* No architectures currently implement __raw_readq() */
250 return *(volatile u64 *)addr;
251}
252
Stefan Roese45aa5a72008-11-17 14:45:22 +0100253#ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
254void flash_write8(u8 value, void *addr)__attribute__((weak, alias("__flash_write8")));
255void flash_write16(u16 value, void *addr)__attribute__((weak, alias("__flash_write16")));
256void flash_write32(u32 value, void *addr)__attribute__((weak, alias("__flash_write32")));
257void flash_write64(u64 value, void *addr)__attribute__((weak, alias("__flash_write64")));
258u8 flash_read8(void *addr)__attribute__((weak, alias("__flash_read8")));
259u16 flash_read16(void *addr)__attribute__((weak, alias("__flash_read16")));
260u32 flash_read32(void *addr)__attribute__((weak, alias("__flash_read32")));
Daniel Hellstrom97bf85d2008-03-28 20:40:19 +0100261u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
Stefan Roese45aa5a72008-11-17 14:45:22 +0100262#else
263#define flash_write8 __flash_write8
264#define flash_write16 __flash_write16
265#define flash_write32 __flash_write32
266#define flash_write64 __flash_write64
267#define flash_read8 __flash_read8
268#define flash_read16 __flash_read16
269#define flash_read32 __flash_read32
270#define flash_read64 __flash_read64
271#endif
Daniel Hellstrom97bf85d2008-03-28 20:40:19 +0100272
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200273/*-----------------------------------------------------------------------
274 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200275#if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200276static flash_info_t *flash_get_info(ulong base)
277{
278 int i;
279 flash_info_t * info = 0;
280
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200281 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200282 info = & flash_info[i];
283 if (info->size && info->start[0] <= base &&
284 base <= info->start[0] + info->size - 1)
285 break;
286 }
287
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200288 return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200289}
wdenk5653fc32004-02-08 22:55:38 +0000290#endif
291
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100292unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
293{
294 if (sect != (info->sector_count - 1))
295 return info->start[sect + 1] - info->start[sect];
296 else
297 return info->start[0] + info->size - info->start[sect];
298}
299
wdenk5653fc32004-02-08 22:55:38 +0000300/*-----------------------------------------------------------------------
301 * create an address based on the offset and the port width
302 */
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100303static inline void *
304flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000305{
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100306 unsigned int byte_offset = offset * info->portwidth;
307
308 return map_physmem(info->start[sect] + byte_offset,
309 flash_sector_size(info, sect) - byte_offset,
310 MAP_NOCACHE);
311}
312
313static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
314 unsigned int offset, void *addr)
315{
316 unsigned int byte_offset = offset * info->portwidth;
317
318 unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset);
wdenk5653fc32004-02-08 22:55:38 +0000319}
wdenkbf9e3b32004-02-12 00:47:09 +0000320
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200321/*-----------------------------------------------------------------------
322 * make a proper sized command based on the port and chip widths
323 */
Sebastian Siewior7288f972008-07-15 13:35:23 +0200324static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200325{
326 int i;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400327 int cword_offset;
328 int cp_offset;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200329#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Sebastian Siewior340ccb22008-07-16 20:04:49 +0200330 u32 cmd_le = cpu_to_le32(cmd);
331#endif
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400332 uchar val;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200333 uchar *cp = (uchar *) cmdbuf;
334
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400335 for (i = info->portwidth; i > 0; i--){
336 cword_offset = (info->portwidth-i)%info->chipwidth;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200337#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400338 cp_offset = info->portwidth - i;
Sebastian Siewior340ccb22008-07-16 20:04:49 +0200339 val = *((uchar*)&cmd_le + cword_offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200340#else
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400341 cp_offset = i - 1;
Sebastian Siewior7288f972008-07-15 13:35:23 +0200342 val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200343#endif
Sebastian Siewior7288f972008-07-15 13:35:23 +0200344 cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400345 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200346}
347
wdenkbf9e3b32004-02-12 00:47:09 +0000348#ifdef DEBUG
349/*-----------------------------------------------------------------------
350 * Debug support
351 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100352static void print_longlong (char *str, unsigned long long data)
wdenkbf9e3b32004-02-12 00:47:09 +0000353{
354 int i;
355 char *cp;
356
357 cp = (unsigned char *) &data;
358 for (i = 0; i < 8; i++)
359 sprintf (&str[i * 2], "%2.2x", *cp++);
360}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200361
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100362static void flash_printqry (struct cfi_qry *qry)
wdenkbf9e3b32004-02-12 00:47:09 +0000363{
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100364 u8 *p = (u8 *)qry;
wdenkbf9e3b32004-02-12 00:47:09 +0000365 int x, y;
366
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100367 for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
368 debug("%02x : ", x);
369 for (y = 0; y < 16; y++)
370 debug("%2.2x ", p[x + y]);
371 debug(" ");
wdenkbf9e3b32004-02-12 00:47:09 +0000372 for (y = 0; y < 16; y++) {
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100373 unsigned char c = p[x + y];
374 if (c >= 0x20 && c <= 0x7e)
375 debug("%c", c);
376 else
377 debug(".");
wdenkbf9e3b32004-02-12 00:47:09 +0000378 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100379 debug("\n");
wdenkbf9e3b32004-02-12 00:47:09 +0000380 }
381}
wdenkbf9e3b32004-02-12 00:47:09 +0000382#endif
383
384
wdenk5653fc32004-02-08 22:55:38 +0000385/*-----------------------------------------------------------------------
386 * read a character at a port width address
387 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100388static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000389{
390 uchar *cp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100391 uchar retval;
wdenkbf9e3b32004-02-12 00:47:09 +0000392
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100393 cp = flash_map (info, 0, offset);
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200394#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100395 retval = flash_read8(cp);
wdenkbf9e3b32004-02-12 00:47:09 +0000396#else
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100397 retval = flash_read8(cp + info->portwidth - 1);
wdenkbf9e3b32004-02-12 00:47:09 +0000398#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100399 flash_unmap (info, 0, offset, cp);
400 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000401}
402
403/*-----------------------------------------------------------------------
Tor Krill90447ec2008-03-28 11:29:10 +0100404 * read a word at a port width address, assume 16bit bus
405 */
406static inline ushort flash_read_word (flash_info_t * info, uint offset)
407{
408 ushort *addr, retval;
409
410 addr = flash_map (info, 0, offset);
411 retval = flash_read16 (addr);
412 flash_unmap (info, 0, offset, addr);
413 return retval;
414}
415
416
417/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +0100418 * read a long word by picking the least significant byte of each maximum
wdenk5653fc32004-02-08 22:55:38 +0000419 * port size word. Swap for ppc format.
420 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100421static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
422 uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000423{
wdenkbf9e3b32004-02-12 00:47:09 +0000424 uchar *addr;
425 ulong retval;
wdenk5653fc32004-02-08 22:55:38 +0000426
wdenkbf9e3b32004-02-12 00:47:09 +0000427#ifdef DEBUG
428 int x;
429#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100430 addr = flash_map (info, sect, offset);
wdenkbf9e3b32004-02-12 00:47:09 +0000431
432#ifdef DEBUG
433 debug ("long addr is at %p info->portwidth = %d\n", addr,
434 info->portwidth);
435 for (x = 0; x < 4 * info->portwidth; x++) {
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100436 debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
wdenkbf9e3b32004-02-12 00:47:09 +0000437 }
438#endif
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200439#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100440 retval = ((flash_read8(addr) << 16) |
441 (flash_read8(addr + info->portwidth) << 24) |
442 (flash_read8(addr + 2 * info->portwidth)) |
443 (flash_read8(addr + 3 * info->portwidth) << 8));
wdenkbf9e3b32004-02-12 00:47:09 +0000444#else
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100445 retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
446 (flash_read8(addr + info->portwidth - 1) << 16) |
447 (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
448 (flash_read8(addr + 3 * info->portwidth - 1)));
wdenkbf9e3b32004-02-12 00:47:09 +0000449#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100450 flash_unmap(info, sect, offset, addr);
451
wdenkbf9e3b32004-02-12 00:47:09 +0000452 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000453}
454
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200455/*
456 * Write a proper sized command to the correct address
457 */
458static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
Sebastian Siewior7288f972008-07-15 13:35:23 +0200459 uint offset, u32 cmd)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200460{
Stefan Roese79b4cda2006-02-28 15:29:58 +0100461
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100462 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200463 cfiword_t cword;
464
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100465 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200466 flash_make_cmd (info, cmd, &cword);
467 switch (info->portwidth) {
468 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100469 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200470 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100471 flash_write8(cword.c, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200472 break;
473 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100474 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200475 cmd, cword.w,
476 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100477 flash_write16(cword.w, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200478 break;
479 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100480 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200481 cmd, cword.l,
482 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100483 flash_write32(cword.l, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200484 break;
485 case FLASH_CFI_64BIT:
486#ifdef DEBUG
487 {
488 char str[20];
489
490 print_longlong (str, cword.ll);
491
492 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100493 addr, cmd, str,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200494 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
495 }
496#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100497 flash_write64(cword.ll, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200498 break;
499 }
500
501 /* Ensure all the instructions are fully finished */
502 sync();
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100503
504 flash_unmap(info, sect, offset, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200505}
506
507static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
508{
509 flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
510 flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
511}
512
513/*-----------------------------------------------------------------------
514 */
515static int flash_isequal (flash_info_t * info, flash_sect_t sect,
516 uint offset, uchar cmd)
517{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100518 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200519 cfiword_t cword;
520 int retval;
521
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100522 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200523 flash_make_cmd (info, cmd, &cword);
524
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100525 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200526 switch (info->portwidth) {
527 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100528 debug ("is= %x %x\n", flash_read8(addr), cword.c);
529 retval = (flash_read8(addr) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200530 break;
531 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100532 debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
533 retval = (flash_read16(addr) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200534 break;
535 case FLASH_CFI_32BIT:
Andrew Klossner52514692008-08-21 07:12:26 -0700536 debug ("is= %8.8x %8.8lx\n", flash_read32(addr), cword.l);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100537 retval = (flash_read32(addr) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200538 break;
539 case FLASH_CFI_64BIT:
540#ifdef DEBUG
541 {
542 char str1[20];
543 char str2[20];
544
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100545 print_longlong (str1, flash_read64(addr));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200546 print_longlong (str2, cword.ll);
547 debug ("is= %s %s\n", str1, str2);
548 }
549#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100550 retval = (flash_read64(addr) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200551 break;
552 default:
553 retval = 0;
554 break;
555 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100556 flash_unmap(info, sect, offset, addr);
557
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200558 return retval;
559}
560
561/*-----------------------------------------------------------------------
562 */
563static int flash_isset (flash_info_t * info, flash_sect_t sect,
564 uint offset, uchar cmd)
565{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100566 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200567 cfiword_t cword;
568 int retval;
569
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100570 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200571 flash_make_cmd (info, cmd, &cword);
572 switch (info->portwidth) {
573 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100574 retval = ((flash_read8(addr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200575 break;
576 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100577 retval = ((flash_read16(addr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200578 break;
579 case FLASH_CFI_32BIT:
Stefan Roese47cc23c2008-01-02 14:05:37 +0100580 retval = ((flash_read32(addr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200581 break;
582 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100583 retval = ((flash_read64(addr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200584 break;
585 default:
586 retval = 0;
587 break;
588 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100589 flash_unmap(info, sect, offset, addr);
590
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200591 return retval;
592}
593
594/*-----------------------------------------------------------------------
595 */
596static int flash_toggle (flash_info_t * info, flash_sect_t sect,
597 uint offset, uchar cmd)
598{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100599 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200600 cfiword_t cword;
601 int retval;
602
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100603 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200604 flash_make_cmd (info, cmd, &cword);
605 switch (info->portwidth) {
606 case FLASH_CFI_8BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200607 retval = flash_read8(addr) != flash_read8(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200608 break;
609 case FLASH_CFI_16BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200610 retval = flash_read16(addr) != flash_read16(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200611 break;
612 case FLASH_CFI_32BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200613 retval = flash_read32(addr) != flash_read32(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200614 break;
615 case FLASH_CFI_64BIT:
Wolfgang Denk9abda6b2008-10-31 01:12:28 +0100616 retval = ( (flash_read32( addr ) != flash_read32( addr )) ||
617 (flash_read32(addr+4) != flash_read32(addr+4)) );
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200618 break;
619 default:
620 retval = 0;
621 break;
622 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100623 flash_unmap(info, sect, offset, addr);
624
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200625 return retval;
626}
627
628/*
629 * flash_is_busy - check to see if the flash is busy
630 *
631 * This routine checks the status of the chip and returns true if the
632 * chip is busy.
633 */
634static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
635{
636 int retval;
637
638 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400639 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200640 case CFI_CMDSET_INTEL_STANDARD:
641 case CFI_CMDSET_INTEL_EXTENDED:
642 retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
643 break;
644 case CFI_CMDSET_AMD_STANDARD:
645 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100646#ifdef CONFIG_FLASH_CFI_LEGACY
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200647 case CFI_CMDSET_AMD_LEGACY:
648#endif
649 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
650 break;
651 default:
652 retval = 0;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100653 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200654 debug ("flash_is_busy: %d\n", retval);
655 return retval;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100656}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200657
658/*-----------------------------------------------------------------------
659 * wait for XSR.7 to be set. Time out with an error if it does not.
660 * This routine does not set the flash to read-array mode.
661 */
662static int flash_status_check (flash_info_t * info, flash_sect_t sector,
663 ulong tout, char *prompt)
664{
665 ulong start;
666
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200667#if CONFIG_SYS_HZ != 1000
668 tout *= CONFIG_SYS_HZ/1000;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200669#endif
670
671 /* Wait for command completion */
672 start = get_timer (0);
673 while (flash_is_busy (info, sector)) {
674 if (get_timer (start) > tout) {
675 printf ("Flash %s timeout at address %lx data %lx\n",
676 prompt, info->start[sector],
677 flash_read_long (info, sector, 0));
678 flash_write_cmd (info, sector, 0, info->cmd_reset);
679 return ERR_TIMOUT;
680 }
681 udelay (1); /* also triggers watchdog */
682 }
683 return ERR_OK;
684}
685
686/*-----------------------------------------------------------------------
687 * Wait for XSR.7 to be set, if it times out print an error, otherwise
688 * do a full status check.
689 *
690 * This routine sets the flash to read-array mode.
691 */
692static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
693 ulong tout, char *prompt)
694{
695 int retcode;
696
697 retcode = flash_status_check (info, sector, tout, prompt);
698 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400699 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200700 case CFI_CMDSET_INTEL_EXTENDED:
701 case CFI_CMDSET_INTEL_STANDARD:
Ed Swarthout0d01f662008-10-09 01:26:36 -0500702 if ((retcode != ERR_OK)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200703 && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
704 retcode = ERR_INVAL;
705 printf ("Flash %s error at address %lx\n", prompt,
706 info->start[sector]);
707 if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
708 FLASH_STATUS_PSLBS)) {
709 puts ("Command Sequence Error.\n");
710 } else if (flash_isset (info, sector, 0,
711 FLASH_STATUS_ECLBS)) {
712 puts ("Block Erase Error.\n");
713 retcode = ERR_NOT_ERASED;
714 } else if (flash_isset (info, sector, 0,
715 FLASH_STATUS_PSLBS)) {
716 puts ("Locking Error\n");
717 }
718 if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
719 puts ("Block locked.\n");
720 retcode = ERR_PROTECTED;
721 }
722 if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
723 puts ("Vpp Low Error.\n");
724 }
725 flash_write_cmd (info, sector, 0, info->cmd_reset);
726 break;
727 default:
728 break;
729 }
730 return retcode;
731}
732
733/*-----------------------------------------------------------------------
734 */
735static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
736{
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200737#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200738 unsigned short w;
739 unsigned int l;
740 unsigned long long ll;
741#endif
742
743 switch (info->portwidth) {
744 case FLASH_CFI_8BIT:
745 cword->c = c;
746 break;
747 case FLASH_CFI_16BIT:
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200748#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200749 w = c;
750 w <<= 8;
751 cword->w = (cword->w >> 8) | w;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100752#else
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200753 cword->w = (cword->w << 8) | c;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100754#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200755 break;
756 case FLASH_CFI_32BIT:
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200757#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200758 l = c;
759 l <<= 24;
760 cword->l = (cword->l >> 8) | l;
761#else
762 cword->l = (cword->l << 8) | c;
Stefan Roese2662b402006-04-01 13:41:03 +0200763#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200764 break;
765 case FLASH_CFI_64BIT:
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200766#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200767 ll = c;
768 ll <<= 56;
769 cword->ll = (cword->ll >> 8) | ll;
770#else
771 cword->ll = (cword->ll << 8) | c;
772#endif
773 break;
wdenk5653fc32004-02-08 22:55:38 +0000774 }
wdenk5653fc32004-02-08 22:55:38 +0000775}
776
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200777/* loop through the sectors from the highest address when the passed
778 * address is greater or equal to the sector address we have a match
wdenk5653fc32004-02-08 22:55:38 +0000779 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200780static flash_sect_t find_sector (flash_info_t * info, ulong addr)
wdenk7680c142005-05-16 15:23:22 +0000781{
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200782 flash_sect_t sector;
wdenk7680c142005-05-16 15:23:22 +0000783
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200784 for (sector = info->sector_count - 1; sector >= 0; sector--) {
785 if (addr >= info->start[sector])
wdenk7680c142005-05-16 15:23:22 +0000786 break;
787 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200788 return sector;
wdenk7680c142005-05-16 15:23:22 +0000789}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200790
791/*-----------------------------------------------------------------------
792 */
793static int flash_write_cfiword (flash_info_t * info, ulong dest,
794 cfiword_t cword)
795{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100796 void *dstaddr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200797 int flag;
Ed Swarthout0d01f662008-10-09 01:26:36 -0500798 flash_sect_t sect;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200799
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100800 dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200801
802 /* Check if Flash is (sufficiently) erased */
803 switch (info->portwidth) {
804 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100805 flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200806 break;
807 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100808 flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200809 break;
810 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100811 flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200812 break;
813 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100814 flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200815 break;
816 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100817 flag = 0;
818 break;
819 }
820 if (!flag) {
821 unmap_physmem(dstaddr, info->portwidth);
Stefan Roese0dc80e22007-12-27 07:50:54 +0100822 return ERR_NOT_ERASED;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200823 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200824
825 /* Disable interrupts which might cause a timeout here */
826 flag = disable_interrupts ();
827
828 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400829 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200830 case CFI_CMDSET_INTEL_EXTENDED:
831 case CFI_CMDSET_INTEL_STANDARD:
832 flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
833 flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
834 break;
835 case CFI_CMDSET_AMD_EXTENDED:
836 case CFI_CMDSET_AMD_STANDARD:
837#ifdef CONFIG_FLASH_CFI_LEGACY
838 case CFI_CMDSET_AMD_LEGACY:
Wolfgang Denk080bdb72005-10-05 01:51:29 +0200839#endif
Ed Swarthout0d01f662008-10-09 01:26:36 -0500840 sect = find_sector(info, dest);
841 flash_unlock_seq (info, sect);
842 flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200843 break;
844 }
845
846 switch (info->portwidth) {
847 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100848 flash_write8(cword.c, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200849 break;
850 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100851 flash_write16(cword.w, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200852 break;
853 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100854 flash_write32(cword.l, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200855 break;
856 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100857 flash_write64(cword.ll, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200858 break;
859 }
860
861 /* re-enable interrupts if necessary */
862 if (flag)
863 enable_interrupts ();
864
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100865 unmap_physmem(dstaddr, info->portwidth);
866
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200867 return flash_full_status_check (info, find_sector (info, dest),
868 info->write_tout, "write");
869}
870
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200871#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200872
873static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
874 int len)
875{
876 flash_sect_t sector;
877 int cnt;
878 int retcode;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100879 void *src = cp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100880 void *dst = map_physmem(dest, len, MAP_NOCACHE);
Stefan Roese0dc80e22007-12-27 07:50:54 +0100881 void *dst2 = dst;
882 int flag = 0;
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200883 uint offset = 0;
884 unsigned int shift;
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400885 uchar write_cmd;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100886
Stefan Roese0dc80e22007-12-27 07:50:54 +0100887 switch (info->portwidth) {
888 case FLASH_CFI_8BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200889 shift = 0;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100890 break;
891 case FLASH_CFI_16BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200892 shift = 1;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100893 break;
894 case FLASH_CFI_32BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200895 shift = 2;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100896 break;
897 case FLASH_CFI_64BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200898 shift = 3;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100899 break;
900 default:
901 retcode = ERR_INVAL;
902 goto out_unmap;
903 }
904
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200905 cnt = len >> shift;
906
Stefan Roese0dc80e22007-12-27 07:50:54 +0100907 while ((cnt-- > 0) && (flag == 0)) {
908 switch (info->portwidth) {
909 case FLASH_CFI_8BIT:
910 flag = ((flash_read8(dst2) & flash_read8(src)) ==
911 flash_read8(src));
912 src += 1, dst2 += 1;
913 break;
914 case FLASH_CFI_16BIT:
915 flag = ((flash_read16(dst2) & flash_read16(src)) ==
916 flash_read16(src));
917 src += 2, dst2 += 2;
918 break;
919 case FLASH_CFI_32BIT:
920 flag = ((flash_read32(dst2) & flash_read32(src)) ==
921 flash_read32(src));
922 src += 4, dst2 += 4;
923 break;
924 case FLASH_CFI_64BIT:
925 flag = ((flash_read64(dst2) & flash_read64(src)) ==
926 flash_read64(src));
927 src += 8, dst2 += 8;
928 break;
929 }
930 }
931 if (!flag) {
932 retcode = ERR_NOT_ERASED;
933 goto out_unmap;
934 }
935
936 src = cp;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100937 sector = find_sector (info, dest);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200938
939 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400940 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200941 case CFI_CMDSET_INTEL_STANDARD:
942 case CFI_CMDSET_INTEL_EXTENDED:
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400943 write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
944 FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200945 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400946 flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS);
947 flash_write_cmd (info, sector, 0, write_cmd);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200948 retcode = flash_status_check (info, sector,
949 info->buffer_write_tout,
950 "write to buffer");
951 if (retcode == ERR_OK) {
952 /* reduce the number of loops by the width of
953 * the port */
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200954 cnt = len >> shift;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400955 flash_write_cmd (info, sector, 0, cnt - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200956 while (cnt-- > 0) {
957 switch (info->portwidth) {
958 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100959 flash_write8(flash_read8(src), dst);
960 src += 1, dst += 1;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200961 break;
962 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100963 flash_write16(flash_read16(src), dst);
964 src += 2, dst += 2;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200965 break;
966 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100967 flash_write32(flash_read32(src), dst);
968 src += 4, dst += 4;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200969 break;
970 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100971 flash_write64(flash_read64(src), dst);
972 src += 8, dst += 8;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200973 break;
974 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100975 retcode = ERR_INVAL;
976 goto out_unmap;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200977 }
978 }
979 flash_write_cmd (info, sector, 0,
980 FLASH_CMD_WRITE_BUFFER_CONFIRM);
981 retcode = flash_full_status_check (
982 info, sector, info->buffer_write_tout,
983 "buffer write");
984 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100985
986 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200987
988 case CFI_CMDSET_AMD_STANDARD:
989 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200990 flash_unlock_seq(info,0);
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200991
992#ifdef CONFIG_FLASH_SPANSION_S29WS_N
993 offset = ((unsigned long)dst - info->start[sector]) >> shift;
994#endif
995 flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
996 cnt = len >> shift;
997 flash_write_cmd(info, sector, offset, (uchar)cnt - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200998
999 switch (info->portwidth) {
1000 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +01001001 while (cnt-- > 0) {
1002 flash_write8(flash_read8(src), dst);
1003 src += 1, dst += 1;
1004 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001005 break;
1006 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +01001007 while (cnt-- > 0) {
1008 flash_write16(flash_read16(src), dst);
1009 src += 2, dst += 2;
1010 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001011 break;
1012 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +01001013 while (cnt-- > 0) {
1014 flash_write32(flash_read32(src), dst);
1015 src += 4, dst += 4;
1016 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001017 break;
1018 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +01001019 while (cnt-- > 0) {
1020 flash_write64(flash_read64(src), dst);
1021 src += 8, dst += 8;
1022 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001023 break;
1024 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001025 retcode = ERR_INVAL;
1026 goto out_unmap;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001027 }
1028
1029 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1030 retcode = flash_full_status_check (info, sector,
1031 info->buffer_write_tout,
1032 "buffer write");
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001033 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001034
1035 default:
1036 debug ("Unknown Command Set\n");
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001037 retcode = ERR_INVAL;
1038 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001039 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001040
1041out_unmap:
1042 unmap_physmem(dst, len);
1043 return retcode;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001044}
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001045#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001046
wdenk7680c142005-05-16 15:23:22 +00001047
1048/*-----------------------------------------------------------------------
1049 */
wdenkbf9e3b32004-02-12 00:47:09 +00001050int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk5653fc32004-02-08 22:55:38 +00001051{
1052 int rcode = 0;
1053 int prot;
1054 flash_sect_t sect;
1055
wdenkbf9e3b32004-02-12 00:47:09 +00001056 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001057 puts ("Can't erase unknown flash type - aborted\n");
wdenk5653fc32004-02-08 22:55:38 +00001058 return 1;
1059 }
1060 if ((s_first < 0) || (s_first > s_last)) {
wdenk4b9206e2004-03-23 22:14:11 +00001061 puts ("- no sectors to erase\n");
wdenk5653fc32004-02-08 22:55:38 +00001062 return 1;
1063 }
1064
1065 prot = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001066 for (sect = s_first; sect <= s_last; ++sect) {
wdenk5653fc32004-02-08 22:55:38 +00001067 if (info->protect[sect]) {
1068 prot++;
1069 }
1070 }
1071 if (prot) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001072 printf ("- Warning: %d protected sectors will not be erased!\n",
1073 prot);
Piotr Ziecik6ea808e2008-11-17 15:49:32 +01001074 } else if (flash_verbose) {
wdenk4b9206e2004-03-23 22:14:11 +00001075 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001076 }
1077
1078
wdenkbf9e3b32004-02-12 00:47:09 +00001079 for (sect = s_first; sect <= s_last; sect++) {
wdenk5653fc32004-02-08 22:55:38 +00001080 if (info->protect[sect] == 0) { /* not protected */
wdenkbf9e3b32004-02-12 00:47:09 +00001081 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001082 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk5653fc32004-02-08 22:55:38 +00001083 case CFI_CMDSET_INTEL_STANDARD:
1084 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001085 flash_write_cmd (info, sect, 0,
1086 FLASH_CMD_CLEAR_STATUS);
1087 flash_write_cmd (info, sect, 0,
1088 FLASH_CMD_BLOCK_ERASE);
1089 flash_write_cmd (info, sect, 0,
1090 FLASH_CMD_ERASE_CONFIRM);
wdenk5653fc32004-02-08 22:55:38 +00001091 break;
1092 case CFI_CMDSET_AMD_STANDARD:
1093 case CFI_CMDSET_AMD_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +00001094 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001095 flash_write_cmd (info, sect,
1096 info->addr_unlock1,
1097 AMD_CMD_ERASE_START);
wdenkbf9e3b32004-02-12 00:47:09 +00001098 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001099 flash_write_cmd (info, sect, 0,
1100 AMD_CMD_ERASE_SECTOR);
wdenk5653fc32004-02-08 22:55:38 +00001101 break;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001102#ifdef CONFIG_FLASH_CFI_LEGACY
1103 case CFI_CMDSET_AMD_LEGACY:
1104 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001105 flash_write_cmd (info, 0, info->addr_unlock1,
1106 AMD_CMD_ERASE_START);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001107 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001108 flash_write_cmd (info, sect, 0,
1109 AMD_CMD_ERASE_SECTOR);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001110 break;
1111#endif
wdenk5653fc32004-02-08 22:55:38 +00001112 default:
wdenkbf9e3b32004-02-12 00:47:09 +00001113 debug ("Unkown flash vendor %d\n",
1114 info->vendor);
wdenk5653fc32004-02-08 22:55:38 +00001115 break;
1116 }
1117
wdenkbf9e3b32004-02-12 00:47:09 +00001118 if (flash_full_status_check
1119 (info, sect, info->erase_blk_tout, "erase")) {
wdenk5653fc32004-02-08 22:55:38 +00001120 rcode = 1;
Piotr Ziecik6ea808e2008-11-17 15:49:32 +01001121 } else if (flash_verbose)
wdenk4b9206e2004-03-23 22:14:11 +00001122 putc ('.');
wdenk5653fc32004-02-08 22:55:38 +00001123 }
1124 }
Piotr Ziecik6ea808e2008-11-17 15:49:32 +01001125
1126 if (flash_verbose)
1127 puts (" done\n");
1128
wdenk5653fc32004-02-08 22:55:38 +00001129 return rcode;
1130}
1131
1132/*-----------------------------------------------------------------------
1133 */
wdenkbf9e3b32004-02-12 00:47:09 +00001134void flash_print_info (flash_info_t * info)
wdenk5653fc32004-02-08 22:55:38 +00001135{
1136 int i;
1137
1138 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001139 puts ("missing or unknown FLASH type\n");
wdenk5653fc32004-02-08 22:55:38 +00001140 return;
1141 }
1142
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001143 printf ("%s FLASH (%d x %d)",
1144 info->name,
wdenkbf9e3b32004-02-12 00:47:09 +00001145 (info->portwidth << 3), (info->chipwidth << 3));
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001146 if (info->size < 1024*1024)
1147 printf (" Size: %ld kB in %d Sectors\n",
1148 info->size >> 10, info->sector_count);
1149 else
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001150 printf (" Size: %ld MB in %d Sectors\n",
1151 info->size >> 20, info->sector_count);
Stefan Roese260421a2006-11-13 13:55:24 +01001152 printf (" ");
1153 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001154 case CFI_CMDSET_INTEL_PROG_REGIONS:
1155 printf ("Intel Prog Regions");
1156 break;
Stefan Roese260421a2006-11-13 13:55:24 +01001157 case CFI_CMDSET_INTEL_STANDARD:
1158 printf ("Intel Standard");
1159 break;
1160 case CFI_CMDSET_INTEL_EXTENDED:
1161 printf ("Intel Extended");
1162 break;
1163 case CFI_CMDSET_AMD_STANDARD:
1164 printf ("AMD Standard");
1165 break;
1166 case CFI_CMDSET_AMD_EXTENDED:
1167 printf ("AMD Extended");
1168 break;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001169#ifdef CONFIG_FLASH_CFI_LEGACY
1170 case CFI_CMDSET_AMD_LEGACY:
1171 printf ("AMD Legacy");
1172 break;
1173#endif
Stefan Roese260421a2006-11-13 13:55:24 +01001174 default:
1175 printf ("Unknown (%d)", info->vendor);
1176 break;
1177 }
1178 printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
1179 info->manufacturer_id, info->device_id);
1180 if (info->device_id == 0x7E) {
1181 printf("%04X", info->device_id2);
1182 }
1183 printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n",
wdenk028ab6b2004-02-23 23:54:43 +00001184 info->erase_blk_tout,
Stefan Roese260421a2006-11-13 13:55:24 +01001185 info->write_tout);
1186 if (info->buffer_size > 1) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001187 printf (" Buffer write timeout: %ld ms, "
1188 "buffer size: %d bytes\n",
wdenk028ab6b2004-02-23 23:54:43 +00001189 info->buffer_write_tout,
1190 info->buffer_size);
Stefan Roese260421a2006-11-13 13:55:24 +01001191 }
wdenk5653fc32004-02-08 22:55:38 +00001192
Stefan Roese260421a2006-11-13 13:55:24 +01001193 puts ("\n Sector Start Addresses:");
wdenkbf9e3b32004-02-12 00:47:09 +00001194 for (i = 0; i < info->sector_count; ++i) {
Stefan Roese260421a2006-11-13 13:55:24 +01001195 if ((i % 5) == 0)
1196 printf ("\n");
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001197#ifdef CONFIG_SYS_FLASH_EMPTY_INFO
wdenk5653fc32004-02-08 22:55:38 +00001198 int k;
1199 int size;
1200 int erased;
1201 volatile unsigned long *flash;
1202
1203 /*
1204 * Check if whole sector is erased
1205 */
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001206 size = flash_sector_size(info, i);
wdenk5653fc32004-02-08 22:55:38 +00001207 erased = 1;
wdenkbf9e3b32004-02-12 00:47:09 +00001208 flash = (volatile unsigned long *) info->start[i];
1209 size = size >> 2; /* divide by 4 for longword access */
1210 for (k = 0; k < size; k++) {
1211 if (*flash++ != 0xffffffff) {
1212 erased = 0;
1213 break;
1214 }
1215 }
wdenk5653fc32004-02-08 22:55:38 +00001216
wdenk5653fc32004-02-08 22:55:38 +00001217 /* print empty and read-only info */
Stefan Roese260421a2006-11-13 13:55:24 +01001218 printf (" %08lX %c %s ",
wdenk5653fc32004-02-08 22:55:38 +00001219 info->start[i],
Stefan Roese260421a2006-11-13 13:55:24 +01001220 erased ? 'E' : ' ',
1221 info->protect[i] ? "RO" : " ");
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001222#else /* ! CONFIG_SYS_FLASH_EMPTY_INFO */
Stefan Roese260421a2006-11-13 13:55:24 +01001223 printf (" %08lX %s ",
1224 info->start[i],
1225 info->protect[i] ? "RO" : " ");
wdenk5653fc32004-02-08 22:55:38 +00001226#endif
1227 }
wdenk4b9206e2004-03-23 22:14:11 +00001228 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001229 return;
1230}
1231
1232/*-----------------------------------------------------------------------
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001233 * This is used in a few places in write_buf() to show programming
1234 * progress. Making it a function is nasty because it needs to do side
1235 * effect updates to digit and dots. Repeated code is nasty too, so
1236 * we define it once here.
1237 */
Stefan Roesef0105722008-03-19 07:09:26 +01001238#ifdef CONFIG_FLASH_SHOW_PROGRESS
1239#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
Piotr Ziecik6ea808e2008-11-17 15:49:32 +01001240 if (flash_verbose) { \
1241 dots -= dots_sub; \
1242 if ((scale > 0) && (dots <= 0)) { \
1243 if ((digit % 5) == 0) \
1244 printf ("%d", digit / 5); \
1245 else \
1246 putc ('.'); \
1247 digit--; \
1248 dots += scale; \
1249 } \
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001250 }
Stefan Roesef0105722008-03-19 07:09:26 +01001251#else
1252#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1253#endif
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001254
1255/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001256 * Copy memory to flash, returns:
1257 * 0 - OK
1258 * 1 - write timeout
1259 * 2 - Flash not erased
1260 */
wdenkbf9e3b32004-02-12 00:47:09 +00001261int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk5653fc32004-02-08 22:55:38 +00001262{
1263 ulong wp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001264 uchar *p;
wdenk5653fc32004-02-08 22:55:38 +00001265 int aln;
1266 cfiword_t cword;
1267 int i, rc;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001268#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
wdenkbf9e3b32004-02-12 00:47:09 +00001269 int buffered_size;
1270#endif
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001271#ifdef CONFIG_FLASH_SHOW_PROGRESS
1272 int digit = CONFIG_FLASH_SHOW_PROGRESS;
1273 int scale = 0;
1274 int dots = 0;
1275
1276 /*
1277 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
1278 */
1279 if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
1280 scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
1281 CONFIG_FLASH_SHOW_PROGRESS);
1282 }
1283#endif
1284
wdenkbf9e3b32004-02-12 00:47:09 +00001285 /* get lower aligned address */
wdenk5653fc32004-02-08 22:55:38 +00001286 wp = (addr & ~(info->portwidth - 1));
1287
1288 /* handle unaligned start */
wdenkbf9e3b32004-02-12 00:47:09 +00001289 if ((aln = addr - wp) != 0) {
wdenk5653fc32004-02-08 22:55:38 +00001290 cword.l = 0;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001291 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1292 for (i = 0; i < aln; ++i)
1293 flash_add_byte (info, &cword, flash_read8(p + i));
wdenk5653fc32004-02-08 22:55:38 +00001294
wdenkbf9e3b32004-02-12 00:47:09 +00001295 for (; (i < info->portwidth) && (cnt > 0); i++) {
1296 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001297 cnt--;
wdenk5653fc32004-02-08 22:55:38 +00001298 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001299 for (; (cnt == 0) && (i < info->portwidth); ++i)
1300 flash_add_byte (info, &cword, flash_read8(p + i));
1301
1302 rc = flash_write_cfiword (info, wp, cword);
1303 unmap_physmem(p, info->portwidth);
1304 if (rc != 0)
wdenk5653fc32004-02-08 22:55:38 +00001305 return rc;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001306
1307 wp += i;
Stefan Roesef0105722008-03-19 07:09:26 +01001308 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001309 }
1310
wdenkbf9e3b32004-02-12 00:47:09 +00001311 /* handle the aligned part */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001312#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
wdenkbf9e3b32004-02-12 00:47:09 +00001313 buffered_size = (info->portwidth / info->chipwidth);
1314 buffered_size *= info->buffer_size;
1315 while (cnt >= info->portwidth) {
Stefan Roese79b4cda2006-02-28 15:29:58 +01001316 /* prohibit buffer write when buffer_size is 1 */
1317 if (info->buffer_size == 1) {
1318 cword.l = 0;
1319 for (i = 0; i < info->portwidth; i++)
1320 flash_add_byte (info, &cword, *src++);
1321 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1322 return rc;
1323 wp += info->portwidth;
1324 cnt -= info->portwidth;
1325 continue;
1326 }
1327
1328 /* write buffer until next buffered_size aligned boundary */
1329 i = buffered_size - (wp % buffered_size);
1330 if (i > cnt)
1331 i = cnt;
wdenkbf9e3b32004-02-12 00:47:09 +00001332 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
wdenk5653fc32004-02-08 22:55:38 +00001333 return rc;
Wolfgang Denk8d4ba3d2005-08-12 22:35:59 +02001334 i -= i & (info->portwidth - 1);
wdenk5653fc32004-02-08 22:55:38 +00001335 wp += i;
1336 src += i;
wdenkbf9e3b32004-02-12 00:47:09 +00001337 cnt -= i;
Stefan Roesef0105722008-03-19 07:09:26 +01001338 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001339 }
1340#else
wdenkbf9e3b32004-02-12 00:47:09 +00001341 while (cnt >= info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001342 cword.l = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001343 for (i = 0; i < info->portwidth; i++) {
1344 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001345 }
wdenkbf9e3b32004-02-12 00:47:09 +00001346 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk5653fc32004-02-08 22:55:38 +00001347 return rc;
1348 wp += info->portwidth;
1349 cnt -= info->portwidth;
Stefan Roesef0105722008-03-19 07:09:26 +01001350 FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
wdenk5653fc32004-02-08 22:55:38 +00001351 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001352#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001353
wdenk5653fc32004-02-08 22:55:38 +00001354 if (cnt == 0) {
1355 return (0);
1356 }
1357
1358 /*
1359 * handle unaligned tail bytes
1360 */
1361 cword.l = 0;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001362 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1363 for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
wdenkbf9e3b32004-02-12 00:47:09 +00001364 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001365 --cnt;
1366 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001367 for (; i < info->portwidth; ++i)
1368 flash_add_byte (info, &cword, flash_read8(p + i));
1369 unmap_physmem(p, info->portwidth);
wdenk5653fc32004-02-08 22:55:38 +00001370
wdenkbf9e3b32004-02-12 00:47:09 +00001371 return flash_write_cfiword (info, wp, cword);
wdenk5653fc32004-02-08 22:55:38 +00001372}
1373
1374/*-----------------------------------------------------------------------
1375 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001376#ifdef CONFIG_SYS_FLASH_PROTECTION
wdenk5653fc32004-02-08 22:55:38 +00001377
wdenkbf9e3b32004-02-12 00:47:09 +00001378int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk5653fc32004-02-08 22:55:38 +00001379{
1380 int retcode = 0;
1381
Rafael Camposbc9019e2008-07-31 10:22:20 +02001382 switch (info->vendor) {
1383 case CFI_CMDSET_INTEL_PROG_REGIONS:
1384 case CFI_CMDSET_INTEL_STANDARD:
Nick Spence9e8e63c2008-08-19 22:21:16 -07001385 case CFI_CMDSET_INTEL_EXTENDED:
Rafael Camposbc9019e2008-07-31 10:22:20 +02001386 flash_write_cmd (info, sector, 0,
1387 FLASH_CMD_CLEAR_STATUS);
1388 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1389 if (prot)
1390 flash_write_cmd (info, sector, 0,
1391 FLASH_CMD_PROTECT_SET);
1392 else
1393 flash_write_cmd (info, sector, 0,
1394 FLASH_CMD_PROTECT_CLEAR);
1395 break;
1396 case CFI_CMDSET_AMD_EXTENDED:
1397 case CFI_CMDSET_AMD_STANDARD:
Rafael Camposbc9019e2008-07-31 10:22:20 +02001398 /* U-Boot only checks the first byte */
1399 if (info->manufacturer_id == (uchar)ATM_MANUFACT) {
1400 if (prot) {
1401 flash_unlock_seq (info, 0);
1402 flash_write_cmd (info, 0,
1403 info->addr_unlock1,
1404 ATM_CMD_SOFTLOCK_START);
1405 flash_unlock_seq (info, 0);
1406 flash_write_cmd (info, sector, 0,
1407 ATM_CMD_LOCK_SECT);
1408 } else {
1409 flash_write_cmd (info, 0,
1410 info->addr_unlock1,
1411 AMD_CMD_UNLOCK_START);
1412 if (info->device_id == ATM_ID_BV6416)
1413 flash_write_cmd (info, sector,
1414 0, ATM_CMD_UNLOCK_SECT);
1415 }
1416 }
1417 break;
TsiChung Liew4e00acd2008-08-19 16:53:39 +00001418#ifdef CONFIG_FLASH_CFI_LEGACY
1419 case CFI_CMDSET_AMD_LEGACY:
1420 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1421 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1422 if (prot)
1423 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
1424 else
1425 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
1426#endif
Rafael Camposbc9019e2008-07-31 10:22:20 +02001427 };
wdenk5653fc32004-02-08 22:55:38 +00001428
wdenkbf9e3b32004-02-12 00:47:09 +00001429 if ((retcode =
1430 flash_full_status_check (info, sector, info->erase_blk_tout,
1431 prot ? "protect" : "unprotect")) == 0) {
wdenk5653fc32004-02-08 22:55:38 +00001432
1433 info->protect[sector] = prot;
Stefan Roese2662b402006-04-01 13:41:03 +02001434
1435 /*
1436 * On some of Intel's flash chips (marked via legacy_unlock)
1437 * unprotect unprotects all locking.
1438 */
1439 if ((prot == 0) && (info->legacy_unlock)) {
wdenk5653fc32004-02-08 22:55:38 +00001440 flash_sect_t i;
wdenkbf9e3b32004-02-12 00:47:09 +00001441
1442 for (i = 0; i < info->sector_count; i++) {
1443 if (info->protect[i])
1444 flash_real_protect (info, i, 1);
wdenk5653fc32004-02-08 22:55:38 +00001445 }
1446 }
1447 }
wdenk5653fc32004-02-08 22:55:38 +00001448 return retcode;
wdenkbf9e3b32004-02-12 00:47:09 +00001449}
1450
wdenk5653fc32004-02-08 22:55:38 +00001451/*-----------------------------------------------------------------------
1452 * flash_read_user_serial - read the OneTimeProgramming cells
1453 */
wdenkbf9e3b32004-02-12 00:47:09 +00001454void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
1455 int len)
wdenk5653fc32004-02-08 22:55:38 +00001456{
wdenkbf9e3b32004-02-12 00:47:09 +00001457 uchar *src;
1458 uchar *dst;
wdenk5653fc32004-02-08 22:55:38 +00001459
1460 dst = buffer;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001461 src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001462 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1463 memcpy (dst, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001464 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001465 flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001466}
wdenkbf9e3b32004-02-12 00:47:09 +00001467
wdenk5653fc32004-02-08 22:55:38 +00001468/*
1469 * flash_read_factory_serial - read the device Id from the protection area
1470 */
wdenkbf9e3b32004-02-12 00:47:09 +00001471void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
1472 int len)
wdenk5653fc32004-02-08 22:55:38 +00001473{
wdenkbf9e3b32004-02-12 00:47:09 +00001474 uchar *src;
wdenkcd37d9e2004-02-10 00:03:41 +00001475
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001476 src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001477 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1478 memcpy (buffer, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001479 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001480 flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001481}
1482
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001483#endif /* CONFIG_SYS_FLASH_PROTECTION */
wdenk5653fc32004-02-08 22:55:38 +00001484
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001485/*-----------------------------------------------------------------------
1486 * Reverse the order of the erase regions in the CFI QRY structure.
1487 * This is needed for chips that are either a) correctly detected as
1488 * top-boot, or b) buggy.
1489 */
1490static void cfi_reverse_geometry(struct cfi_qry *qry)
1491{
1492 unsigned int i, j;
1493 u32 tmp;
1494
1495 for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
1496 tmp = qry->erase_region_info[i];
1497 qry->erase_region_info[i] = qry->erase_region_info[j];
1498 qry->erase_region_info[j] = tmp;
1499 }
1500}
wdenk5653fc32004-02-08 22:55:38 +00001501
1502/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +01001503 * read jedec ids from device and set corresponding fields in info struct
1504 *
1505 * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1506 *
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001507 */
1508static void cmdset_intel_read_jedec_ids(flash_info_t *info)
1509{
1510 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1511 flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1512 udelay(1000); /* some flash are slow to respond */
1513 info->manufacturer_id = flash_read_uchar (info,
1514 FLASH_OFFSET_MANUFACTURER_ID);
1515 info->device_id = flash_read_uchar (info,
1516 FLASH_OFFSET_DEVICE_ID);
1517 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1518}
1519
1520static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
1521{
1522 info->cmd_reset = FLASH_CMD_RESET;
1523
1524 cmdset_intel_read_jedec_ids(info);
1525 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1526
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001527#ifdef CONFIG_SYS_FLASH_PROTECTION
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001528 /* read legacy lock/unlock bit from intel flash */
1529 if (info->ext_addr) {
1530 info->legacy_unlock = flash_read_uchar (info,
1531 info->ext_addr + 5) & 0x08;
1532 }
1533#endif
1534
1535 return 0;
1536}
1537
1538static void cmdset_amd_read_jedec_ids(flash_info_t *info)
1539{
1540 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1541 flash_unlock_seq(info, 0);
1542 flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
1543 udelay(1000); /* some flash are slow to respond */
Tor Krill90447ec2008-03-28 11:29:10 +01001544
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001545 info->manufacturer_id = flash_read_uchar (info,
1546 FLASH_OFFSET_MANUFACTURER_ID);
Tor Krill90447ec2008-03-28 11:29:10 +01001547
1548 switch (info->chipwidth){
1549 case FLASH_CFI_8BIT:
1550 info->device_id = flash_read_uchar (info,
1551 FLASH_OFFSET_DEVICE_ID);
1552 if (info->device_id == 0x7E) {
1553 /* AMD 3-byte (expanded) device ids */
1554 info->device_id2 = flash_read_uchar (info,
1555 FLASH_OFFSET_DEVICE_ID2);
1556 info->device_id2 <<= 8;
1557 info->device_id2 |= flash_read_uchar (info,
1558 FLASH_OFFSET_DEVICE_ID3);
1559 }
1560 break;
1561 case FLASH_CFI_16BIT:
1562 info->device_id = flash_read_word (info,
1563 FLASH_OFFSET_DEVICE_ID);
1564 break;
1565 default:
1566 break;
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001567 }
1568 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1569}
1570
1571static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
1572{
1573 info->cmd_reset = AMD_CMD_RESET;
1574
1575 cmdset_amd_read_jedec_ids(info);
1576 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1577
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001578 return 0;
1579}
1580
1581#ifdef CONFIG_FLASH_CFI_LEGACY
Stefan Roese260421a2006-11-13 13:55:24 +01001582static void flash_read_jedec_ids (flash_info_t * info)
1583{
1584 info->manufacturer_id = 0;
1585 info->device_id = 0;
1586 info->device_id2 = 0;
1587
1588 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001589 case CFI_CMDSET_INTEL_PROG_REGIONS:
Stefan Roese260421a2006-11-13 13:55:24 +01001590 case CFI_CMDSET_INTEL_STANDARD:
1591 case CFI_CMDSET_INTEL_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001592 cmdset_intel_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001593 break;
1594 case CFI_CMDSET_AMD_STANDARD:
1595 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001596 cmdset_amd_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001597 break;
1598 default:
1599 break;
1600 }
1601}
1602
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001603/*-----------------------------------------------------------------------
1604 * Call board code to request info about non-CFI flash.
1605 * board_flash_get_legacy needs to fill in at least:
1606 * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1607 */
1608static int flash_detect_legacy(ulong base, int banknum)
1609{
1610 flash_info_t *info = &flash_info[banknum];
1611
1612 if (board_flash_get_legacy(base, banknum, info)) {
1613 /* board code may have filled info completely. If not, we
1614 use JEDEC ID probing. */
1615 if (!info->vendor) {
1616 int modes[] = {
1617 CFI_CMDSET_AMD_STANDARD,
1618 CFI_CMDSET_INTEL_STANDARD
1619 };
1620 int i;
1621
1622 for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1623 info->vendor = modes[i];
1624 info->start[0] = base;
1625 if (info->portwidth == FLASH_CFI_8BIT
1626 && info->interface == FLASH_CFI_X8X16) {
1627 info->addr_unlock1 = 0x2AAA;
1628 info->addr_unlock2 = 0x5555;
1629 } else {
1630 info->addr_unlock1 = 0x5555;
1631 info->addr_unlock2 = 0x2AAA;
1632 }
1633 flash_read_jedec_ids(info);
1634 debug("JEDEC PROBE: ID %x %x %x\n",
1635 info->manufacturer_id,
1636 info->device_id,
1637 info->device_id2);
1638 if (jedec_flash_match(info, base))
1639 break;
1640 }
1641 }
1642
1643 switch(info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001644 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001645 case CFI_CMDSET_INTEL_STANDARD:
1646 case CFI_CMDSET_INTEL_EXTENDED:
1647 info->cmd_reset = FLASH_CMD_RESET;
1648 break;
1649 case CFI_CMDSET_AMD_STANDARD:
1650 case CFI_CMDSET_AMD_EXTENDED:
1651 case CFI_CMDSET_AMD_LEGACY:
1652 info->cmd_reset = AMD_CMD_RESET;
1653 break;
1654 }
1655 info->flash_id = FLASH_MAN_CFI;
1656 return 1;
1657 }
1658 return 0; /* use CFI */
1659}
1660#else
1661static inline int flash_detect_legacy(ulong base, int banknum)
1662{
1663 return 0; /* use CFI */
1664}
1665#endif
1666
Stefan Roese260421a2006-11-13 13:55:24 +01001667/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001668 * detect if flash is compatible with the Common Flash Interface (CFI)
1669 * http://www.jedec.org/download/search/jesd68.pdf
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001670 */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001671static void flash_read_cfi (flash_info_t *info, void *buf,
1672 unsigned int start, size_t len)
1673{
1674 u8 *p = buf;
1675 unsigned int i;
1676
1677 for (i = 0; i < len; i++)
1678 p[i] = flash_read_uchar(info, start + i);
1679}
1680
1681static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
wdenk5653fc32004-02-08 22:55:38 +00001682{
Wolfgang Denk92eb7292006-12-27 01:26:13 +01001683 int cfi_offset;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001684
Michael Schwingen1ba639d2008-02-18 23:16:35 +01001685 /* We do not yet know what kind of commandset to use, so we issue
1686 the reset command in both Intel and AMD variants, in the hope
1687 that AMD flash roms ignore the Intel command. */
1688 flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
1689 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
1690
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001691 for (cfi_offset=0;
1692 cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
1693 cfi_offset++) {
1694 flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
1695 FLASH_CMD_CFI);
1696 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1697 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1698 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001699 flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1700 sizeof(struct cfi_qry));
1701 info->interface = le16_to_cpu(qry->interface_desc);
1702
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001703 info->cfi_offset = flash_offset_cfi[cfi_offset];
1704 debug ("device interface is %d\n",
1705 info->interface);
1706 debug ("found port %d chip %d ",
1707 info->portwidth, info->chipwidth);
1708 debug ("port %d bits chip %d bits\n",
1709 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1710 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1711
1712 /* calculate command offsets as in the Linux driver */
1713 info->addr_unlock1 = 0x555;
1714 info->addr_unlock2 = 0x2aa;
1715
1716 /*
1717 * modify the unlock address if we are
1718 * in compatibility mode
1719 */
1720 if ( /* x8/x16 in x8 mode */
1721 ((info->chipwidth == FLASH_CFI_BY8) &&
1722 (info->interface == FLASH_CFI_X8X16)) ||
1723 /* x16/x32 in x16 mode */
1724 ((info->chipwidth == FLASH_CFI_BY16) &&
1725 (info->interface == FLASH_CFI_X16X32)))
1726 {
1727 info->addr_unlock1 = 0xaaa;
1728 info->addr_unlock2 = 0x555;
1729 }
1730
1731 info->name = "CFI conformant";
1732 return 1;
1733 }
1734 }
1735
1736 return 0;
1737}
1738
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001739static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001740{
wdenkbf9e3b32004-02-12 00:47:09 +00001741 debug ("flash detect cfi\n");
wdenk5653fc32004-02-08 22:55:38 +00001742
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001743 for (info->portwidth = CONFIG_SYS_FLASH_CFI_WIDTH;
wdenkbf9e3b32004-02-12 00:47:09 +00001744 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1745 for (info->chipwidth = FLASH_CFI_BY8;
1746 info->chipwidth <= info->portwidth;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001747 info->chipwidth <<= 1)
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001748 if (__flash_detect_cfi(info, qry))
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001749 return 1;
wdenk5653fc32004-02-08 22:55:38 +00001750 }
wdenkbf9e3b32004-02-12 00:47:09 +00001751 debug ("not found\n");
wdenk5653fc32004-02-08 22:55:38 +00001752 return 0;
1753}
wdenkbf9e3b32004-02-12 00:47:09 +00001754
wdenk5653fc32004-02-08 22:55:38 +00001755/*
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001756 * Manufacturer-specific quirks. Add workarounds for geometry
1757 * reversal, etc. here.
1758 */
1759static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1760{
1761 /* check if flash geometry needs reversal */
1762 if (qry->num_erase_regions > 1) {
1763 /* reverse geometry if top boot part */
1764 if (info->cfi_version < 0x3131) {
1765 /* CFI < 1.1, try to guess from device id */
1766 if ((info->device_id & 0x80) != 0)
1767 cfi_reverse_geometry(qry);
1768 } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1769 /* CFI >= 1.1, deduct from top/bottom flag */
1770 /* note: ext_addr is valid since cfi_version > 0 */
1771 cfi_reverse_geometry(qry);
1772 }
1773 }
1774}
1775
1776static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1777{
1778 int reverse_geometry = 0;
1779
1780 /* Check the "top boot" bit in the PRI */
1781 if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1782 reverse_geometry = 1;
1783
1784 /* AT49BV6416(T) list the erase regions in the wrong order.
1785 * However, the device ID is identical with the non-broken
1786 * AT49BV642D since u-boot only reads the low byte (they
1787 * differ in the high byte.) So leave out this fixup for now.
1788 */
1789#if 0
1790 if (info->device_id == 0xd6 || info->device_id == 0xd2)
1791 reverse_geometry = !reverse_geometry;
1792#endif
1793
1794 if (reverse_geometry)
1795 cfi_reverse_geometry(qry);
1796}
1797
1798/*
wdenk5653fc32004-02-08 22:55:38 +00001799 * The following code cannot be run from FLASH!
1800 *
1801 */
Marian Balakowicze6f2e902005-10-11 19:09:42 +02001802ulong flash_get_size (ulong base, int banknum)
wdenk5653fc32004-02-08 22:55:38 +00001803{
wdenkbf9e3b32004-02-12 00:47:09 +00001804 flash_info_t *info = &flash_info[banknum];
wdenk5653fc32004-02-08 22:55:38 +00001805 int i, j;
1806 flash_sect_t sect_cnt;
1807 unsigned long sector;
1808 unsigned long tmp;
1809 int size_ratio;
1810 uchar num_erase_regions;
wdenkbf9e3b32004-02-12 00:47:09 +00001811 int erase_region_size;
1812 int erase_region_count;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001813 struct cfi_qry qry;
Stefan Roese260421a2006-11-13 13:55:24 +01001814
Kumar Galaf9796902008-05-15 15:13:08 -05001815 memset(&qry, 0, sizeof(qry));
1816
Stefan Roese260421a2006-11-13 13:55:24 +01001817 info->ext_addr = 0;
1818 info->cfi_version = 0;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001819#ifdef CONFIG_SYS_FLASH_PROTECTION
Stefan Roese2662b402006-04-01 13:41:03 +02001820 info->legacy_unlock = 0;
1821#endif
wdenk5653fc32004-02-08 22:55:38 +00001822
1823 info->start[0] = base;
1824
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001825 if (flash_detect_cfi (info, &qry)) {
1826 info->vendor = le16_to_cpu(qry.p_id);
1827 info->ext_addr = le16_to_cpu(qry.p_adr);
1828 num_erase_regions = qry.num_erase_regions;
1829
Stefan Roese260421a2006-11-13 13:55:24 +01001830 if (info->ext_addr) {
1831 info->cfi_version = (ushort) flash_read_uchar (info,
1832 info->ext_addr + 3) << 8;
1833 info->cfi_version |= (ushort) flash_read_uchar (info,
1834 info->ext_addr + 4);
1835 }
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001836
wdenkbf9e3b32004-02-12 00:47:09 +00001837#ifdef DEBUG
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001838 flash_printqry (&qry);
wdenkbf9e3b32004-02-12 00:47:09 +00001839#endif
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001840
wdenkbf9e3b32004-02-12 00:47:09 +00001841 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001842 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk5653fc32004-02-08 22:55:38 +00001843 case CFI_CMDSET_INTEL_STANDARD:
1844 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001845 cmdset_intel_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001846 break;
1847 case CFI_CMDSET_AMD_STANDARD:
1848 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001849 cmdset_amd_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001850 break;
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001851 default:
1852 printf("CFI: Unknown command set 0x%x\n",
1853 info->vendor);
1854 /*
1855 * Unfortunately, this means we don't know how
1856 * to get the chip back to Read mode. Might
1857 * as well try an Intel-style reset...
1858 */
1859 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1860 return 0;
wdenk5653fc32004-02-08 22:55:38 +00001861 }
wdenkcd37d9e2004-02-10 00:03:41 +00001862
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001863 /* Do manufacturer-specific fixups */
1864 switch (info->manufacturer_id) {
1865 case 0x0001:
1866 flash_fixup_amd(info, &qry);
1867 break;
1868 case 0x001f:
1869 flash_fixup_atmel(info, &qry);
1870 break;
1871 }
1872
wdenkbf9e3b32004-02-12 00:47:09 +00001873 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese260421a2006-11-13 13:55:24 +01001874 debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
1875 debug ("device id is 0x%x\n", info->device_id);
1876 debug ("device id2 is 0x%x\n", info->device_id2);
1877 debug ("cfi version is 0x%04x\n", info->cfi_version);
1878
wdenk5653fc32004-02-08 22:55:38 +00001879 size_ratio = info->portwidth / info->chipwidth;
wdenkbf9e3b32004-02-12 00:47:09 +00001880 /* if the chip is x8/x16 reduce the ratio by half */
1881 if ((info->interface == FLASH_CFI_X8X16)
1882 && (info->chipwidth == FLASH_CFI_BY8)) {
1883 size_ratio >>= 1;
1884 }
wdenkbf9e3b32004-02-12 00:47:09 +00001885 debug ("size_ratio %d port %d bits chip %d bits\n",
1886 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1887 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1888 debug ("found %d erase regions\n", num_erase_regions);
wdenk5653fc32004-02-08 22:55:38 +00001889 sect_cnt = 0;
1890 sector = base;
wdenkbf9e3b32004-02-12 00:47:09 +00001891 for (i = 0; i < num_erase_regions; i++) {
1892 if (i > NUM_ERASE_REGIONS) {
wdenk028ab6b2004-02-23 23:54:43 +00001893 printf ("%d erase regions found, only %d used\n",
1894 num_erase_regions, NUM_ERASE_REGIONS);
wdenk5653fc32004-02-08 22:55:38 +00001895 break;
1896 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001897
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001898 tmp = le32_to_cpu(qry.erase_region_info[i]);
1899 debug("erase region %u: 0x%08lx\n", i, tmp);
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001900
1901 erase_region_count = (tmp & 0xffff) + 1;
1902 tmp >>= 16;
wdenkbf9e3b32004-02-12 00:47:09 +00001903 erase_region_size =
1904 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenk4c0d4c32004-06-09 17:34:58 +00001905 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenk028ab6b2004-02-23 23:54:43 +00001906 erase_region_count, erase_region_size);
wdenkbf9e3b32004-02-12 00:47:09 +00001907 for (j = 0; j < erase_region_count; j++) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001908 if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001909 printf("ERROR: too many flash sectors\n");
1910 break;
1911 }
wdenk5653fc32004-02-08 22:55:38 +00001912 info->start[sect_cnt] = sector;
1913 sector += (erase_region_size * size_ratio);
wdenka1191902005-01-09 17:12:27 +00001914
1915 /*
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001916 * Only read protection status from
1917 * supported devices (intel...)
wdenka1191902005-01-09 17:12:27 +00001918 */
1919 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001920 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenka1191902005-01-09 17:12:27 +00001921 case CFI_CMDSET_INTEL_EXTENDED:
1922 case CFI_CMDSET_INTEL_STANDARD:
1923 info->protect[sect_cnt] =
1924 flash_isset (info, sect_cnt,
1925 FLASH_OFFSET_PROTECT,
1926 FLASH_STATUS_PROTECT);
1927 break;
1928 default:
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001929 /* default: not protected */
1930 info->protect[sect_cnt] = 0;
wdenka1191902005-01-09 17:12:27 +00001931 }
1932
wdenk5653fc32004-02-08 22:55:38 +00001933 sect_cnt++;
1934 }
1935 }
1936
1937 info->sector_count = sect_cnt;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001938 info->size = 1 << qry.dev_size;
wdenk5653fc32004-02-08 22:55:38 +00001939 /* multiply the size by the number of chips */
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001940 info->size *= size_ratio;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001941 info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1942 tmp = 1 << qry.block_erase_timeout_typ;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001943 info->erase_blk_tout = tmp *
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001944 (1 << qry.block_erase_timeout_max);
1945 tmp = (1 << qry.buf_write_timeout_typ) *
1946 (1 << qry.buf_write_timeout_max);
1947
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001948 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001949 info->buffer_write_tout = (tmp + 999) / 1000;
1950 tmp = (1 << qry.word_write_timeout_typ) *
1951 (1 << qry.word_write_timeout_max);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001952 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001953 info->write_tout = (tmp + 999) / 1000;
wdenk5653fc32004-02-08 22:55:38 +00001954 info->flash_id = FLASH_MAN_CFI;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001955 if ((info->interface == FLASH_CFI_X8X16) &&
1956 (info->chipwidth == FLASH_CFI_BY8)) {
1957 /* XXX - Need to test on x8/x16 in parallel. */
1958 info->portwidth >>= 1;
wdenk855a4962004-03-14 18:23:55 +00001959 }
Mike Frysinger22159872008-10-02 01:55:38 -04001960
1961 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenk5653fc32004-02-08 22:55:38 +00001962 }
1963
wdenkbf9e3b32004-02-12 00:47:09 +00001964 return (info->size);
wdenk5653fc32004-02-08 22:55:38 +00001965}
1966
Piotr Ziecik6ea808e2008-11-17 15:49:32 +01001967void flash_set_verbose(uint v)
1968{
1969 flash_verbose = v;
1970}
1971
wdenk5653fc32004-02-08 22:55:38 +00001972/*-----------------------------------------------------------------------
1973 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001974unsigned long flash_init (void)
wdenk5653fc32004-02-08 22:55:38 +00001975{
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001976 unsigned long size = 0;
1977 int i;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001978#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
Matthias Fuchsc63ad632008-04-18 16:29:40 +02001979 struct apl_s {
1980 ulong start;
1981 ulong size;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001982 } apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST;
Matthias Fuchsc63ad632008-04-18 16:29:40 +02001983#endif
wdenk5653fc32004-02-08 22:55:38 +00001984
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001985#ifdef CONFIG_SYS_FLASH_PROTECTION
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001986 char *s = getenv("unlock");
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001987#endif
wdenk5653fc32004-02-08 22:55:38 +00001988
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001989#define BANK_BASE(i) (((unsigned long [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i])
Wolfgang Denk2a112b22008-08-08 16:39:54 +02001990
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001991 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001992 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001993 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenk5653fc32004-02-08 22:55:38 +00001994
Wolfgang Denk2a112b22008-08-08 16:39:54 +02001995 if (!flash_detect_legacy (BANK_BASE(i), i))
1996 flash_get_size (BANK_BASE(i), i);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001997 size += flash_info[i].size;
1998 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001999#ifndef CONFIG_SYS_FLASH_QUIET_TEST
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002000 printf ("## Unknown FLASH on Bank %d "
2001 "- Size = 0x%08lx = %ld MB\n",
2002 i+1, flash_info[i].size,
2003 flash_info[i].size << 20);
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002004#endif /* CONFIG_SYS_FLASH_QUIET_TEST */
wdenk5653fc32004-02-08 22:55:38 +00002005 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002006#ifdef CONFIG_SYS_FLASH_PROTECTION
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002007 else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
2008 /*
2009 * Only the U-Boot image and it's environment
2010 * is protected, all other sectors are
2011 * unprotected (unlocked) if flash hardware
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002012 * protection is used (CONFIG_SYS_FLASH_PROTECTION)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002013 * and the environment variable "unlock" is
2014 * set to "yes".
2015 */
2016 if (flash_info[i].legacy_unlock) {
2017 int k;
Stefan Roese79b4cda2006-02-28 15:29:58 +01002018
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002019 /*
2020 * Disable legacy_unlock temporarily,
2021 * since flash_real_protect would
2022 * relock all other sectors again
2023 * otherwise.
2024 */
2025 flash_info[i].legacy_unlock = 0;
Stefan Roese79b4cda2006-02-28 15:29:58 +01002026
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002027 /*
2028 * Legacy unlocking (e.g. Intel J3) ->
2029 * unlock only one sector. This will
2030 * unlock all sectors.
2031 */
2032 flash_real_protect (&flash_info[i], 0, 0);
Stefan Roese79b4cda2006-02-28 15:29:58 +01002033
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002034 flash_info[i].legacy_unlock = 1;
2035
2036 /*
2037 * Manually mark other sectors as
2038 * unlocked (unprotected)
2039 */
2040 for (k = 1; k < flash_info[i].sector_count; k++)
2041 flash_info[i].protect[k] = 0;
2042 } else {
2043 /*
2044 * No legancy unlocking -> unlock all sectors
2045 */
2046 flash_protect (FLAG_PROTECT_CLEAR,
2047 flash_info[i].start[0],
2048 flash_info[i].start[0]
2049 + flash_info[i].size - 1,
2050 &flash_info[i]);
2051 }
Stefan Roese79b4cda2006-02-28 15:29:58 +01002052 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002053#endif /* CONFIG_SYS_FLASH_PROTECTION */
wdenk5653fc32004-02-08 22:55:38 +00002054 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002055
2056 /* Monitor protection ON by default */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002057#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002058 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002059 CONFIG_SYS_MONITOR_BASE,
2060 CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
2061 flash_get_info(CONFIG_SYS_MONITOR_BASE));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002062#endif
2063
2064 /* Environment protection ON by default */
Jean-Christophe PLAGNIOL-VILLARD5a1aceb2008-09-10 22:48:04 +02002065#ifdef CONFIG_ENV_IS_IN_FLASH
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002066 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +02002067 CONFIG_ENV_ADDR,
2068 CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
2069 flash_get_info(CONFIG_ENV_ADDR));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002070#endif
2071
2072 /* Redundant environment protection ON by default */
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +02002073#ifdef CONFIG_ENV_ADDR_REDUND
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002074 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +02002075 CONFIG_ENV_ADDR_REDUND,
2076 CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SIZE_REDUND - 1,
2077 flash_get_info(CONFIG_ENV_ADDR_REDUND));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002078#endif
Matthias Fuchsc63ad632008-04-18 16:29:40 +02002079
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002080#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
Matthias Fuchsc63ad632008-04-18 16:29:40 +02002081 for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
2082 debug("autoprotecting from %08x to %08x\n",
2083 apl[i].start, apl[i].start + apl[i].size - 1);
2084 flash_protect (FLAG_PROTECT_SET,
2085 apl[i].start,
2086 apl[i].start + apl[i].size - 1,
2087 flash_get_info(apl[i].start));
2088 }
2089#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002090 return (size);
wdenk5653fc32004-02-08 22:55:38 +00002091}