blob: 6eea49a11ea752c1b77ccade8447ea8b9a601984 [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
Niklaus Giger3a7b2c22009-07-22 17:13:24 +0200109#define FLASH_CONTINUATION_CODE 0x7F
110
Stefan Roese260421a2006-11-13 13:55:24 +0100111#define FLASH_OFFSET_MANUFACTURER_ID 0x00
112#define FLASH_OFFSET_DEVICE_ID 0x01
113#define FLASH_OFFSET_DEVICE_ID2 0x0E
114#define FLASH_OFFSET_DEVICE_ID3 0x0F
wdenk5653fc32004-02-08 22:55:38 +0000115#define FLASH_OFFSET_CFI 0x55
Wolfgang Denk92eb7292006-12-27 01:26:13 +0100116#define FLASH_OFFSET_CFI_ALT 0x555
wdenk5653fc32004-02-08 22:55:38 +0000117#define FLASH_OFFSET_CFI_RESP 0x10
wdenkbf9e3b32004-02-12 00:47:09 +0000118#define FLASH_OFFSET_PRIMARY_VENDOR 0x13
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +0100119/* extended query table primary address */
120#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15
wdenk5653fc32004-02-08 22:55:38 +0000121#define FLASH_OFFSET_WTOUT 0x1F
wdenkbf9e3b32004-02-12 00:47:09 +0000122#define FLASH_OFFSET_WBTOUT 0x20
wdenk5653fc32004-02-08 22:55:38 +0000123#define FLASH_OFFSET_ETOUT 0x21
wdenkbf9e3b32004-02-12 00:47:09 +0000124#define FLASH_OFFSET_CETOUT 0x22
wdenk5653fc32004-02-08 22:55:38 +0000125#define FLASH_OFFSET_WMAX_TOUT 0x23
wdenkbf9e3b32004-02-12 00:47:09 +0000126#define FLASH_OFFSET_WBMAX_TOUT 0x24
wdenk5653fc32004-02-08 22:55:38 +0000127#define FLASH_OFFSET_EMAX_TOUT 0x25
wdenkbf9e3b32004-02-12 00:47:09 +0000128#define FLASH_OFFSET_CEMAX_TOUT 0x26
wdenk5653fc32004-02-08 22:55:38 +0000129#define FLASH_OFFSET_SIZE 0x27
wdenkbf9e3b32004-02-12 00:47:09 +0000130#define FLASH_OFFSET_INTERFACE 0x28
131#define FLASH_OFFSET_BUFFER_SIZE 0x2A
wdenk5653fc32004-02-08 22:55:38 +0000132#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C
133#define FLASH_OFFSET_ERASE_REGIONS 0x2D
134#define FLASH_OFFSET_PROTECT 0x02
wdenkbf9e3b32004-02-12 00:47:09 +0000135#define FLASH_OFFSET_USER_PROTECTION 0x85
136#define FLASH_OFFSET_INTEL_PROTECTION 0x81
wdenk5653fc32004-02-08 22:55:38 +0000137
Stefan Roese260421a2006-11-13 13:55:24 +0100138#define CFI_CMDSET_NONE 0
139#define CFI_CMDSET_INTEL_EXTENDED 1
140#define CFI_CMDSET_AMD_STANDARD 2
141#define CFI_CMDSET_INTEL_STANDARD 3
142#define CFI_CMDSET_AMD_EXTENDED 4
143#define CFI_CMDSET_MITSU_STANDARD 256
144#define CFI_CMDSET_MITSU_EXTENDED 257
145#define CFI_CMDSET_SST 258
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400146#define CFI_CMDSET_INTEL_PROG_REGIONS 512
wdenk5653fc32004-02-08 22:55:38 +0000147
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200148#ifdef CONFIG_SYS_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
wdenkf7d15722004-12-18 22:35:43 +0000149# undef FLASH_CMD_RESET
Stefan Roese260421a2006-11-13 13:55:24 +0100150# define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */
wdenkf7d15722004-12-18 22:35:43 +0000151#endif
152
wdenk5653fc32004-02-08 22:55:38 +0000153typedef union {
154 unsigned char c;
155 unsigned short w;
156 unsigned long l;
157 unsigned long long ll;
158} cfiword_t;
159
Stefan Roese260421a2006-11-13 13:55:24 +0100160#define NUM_ERASE_REGIONS 4 /* max. number of erase regions */
wdenk5653fc32004-02-08 22:55:38 +0000161
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +0100162static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
Piotr Ziecik6ea808e2008-11-17 15:49:32 +0100163static uint flash_verbose = 1;
Wolfgang Denk92eb7292006-12-27 01:26:13 +0100164
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200165/* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */
166#ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT
167# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS_DETECT
Marian Balakowicze6f2e902005-10-11 19:09:42 +0200168#else
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200169# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS
Marian Balakowicze6f2e902005-10-11 19:09:42 +0200170#endif
wdenk5653fc32004-02-08 22:55:38 +0000171
Wolfgang Denk2a112b22008-08-08 16:39:54 +0200172flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */
173
Stefan Roese79b4cda2006-02-28 15:29:58 +0100174/*
175 * Check if chip width is defined. If not, start detecting with 8bit.
176 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200177#ifndef CONFIG_SYS_FLASH_CFI_WIDTH
178#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_8BIT
Stefan Roese79b4cda2006-02-28 15:29:58 +0100179#endif
180
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100181/* CFI standard query structure */
182struct cfi_qry {
183 u8 qry[3];
184 u16 p_id;
185 u16 p_adr;
186 u16 a_id;
187 u16 a_adr;
188 u8 vcc_min;
189 u8 vcc_max;
190 u8 vpp_min;
191 u8 vpp_max;
192 u8 word_write_timeout_typ;
193 u8 buf_write_timeout_typ;
194 u8 block_erase_timeout_typ;
195 u8 chip_erase_timeout_typ;
196 u8 word_write_timeout_max;
197 u8 buf_write_timeout_max;
198 u8 block_erase_timeout_max;
199 u8 chip_erase_timeout_max;
200 u8 dev_size;
201 u16 interface_desc;
202 u16 max_buf_write_size;
203 u8 num_erase_regions;
204 u32 erase_region_info[NUM_ERASE_REGIONS];
205} __attribute__((packed));
206
207struct cfi_pri_hdr {
208 u8 pri[3];
209 u8 major_version;
210 u8 minor_version;
211} __attribute__((packed));
212
Stefan Roese45aa5a72008-11-17 14:45:22 +0100213static void __flash_write8(u8 value, void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100214{
215 __raw_writeb(value, addr);
216}
217
Stefan Roese45aa5a72008-11-17 14:45:22 +0100218static void __flash_write16(u16 value, void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100219{
220 __raw_writew(value, addr);
221}
222
Stefan Roese45aa5a72008-11-17 14:45:22 +0100223static void __flash_write32(u32 value, void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100224{
225 __raw_writel(value, addr);
226}
227
Stefan Roese45aa5a72008-11-17 14:45:22 +0100228static void __flash_write64(u64 value, void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100229{
230 /* No architectures currently implement __raw_writeq() */
231 *(volatile u64 *)addr = value;
232}
233
Stefan Roese45aa5a72008-11-17 14:45:22 +0100234static u8 __flash_read8(void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100235{
236 return __raw_readb(addr);
237}
238
Stefan Roese45aa5a72008-11-17 14:45:22 +0100239static u16 __flash_read16(void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100240{
241 return __raw_readw(addr);
242}
243
Stefan Roese45aa5a72008-11-17 14:45:22 +0100244static u32 __flash_read32(void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100245{
246 return __raw_readl(addr);
247}
248
Daniel Hellstrom97bf85d2008-03-28 20:40:19 +0100249static u64 __flash_read64(void *addr)
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100250{
251 /* No architectures currently implement __raw_readq() */
252 return *(volatile u64 *)addr;
253}
254
Stefan Roese45aa5a72008-11-17 14:45:22 +0100255#ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
256void flash_write8(u8 value, void *addr)__attribute__((weak, alias("__flash_write8")));
257void flash_write16(u16 value, void *addr)__attribute__((weak, alias("__flash_write16")));
258void flash_write32(u32 value, void *addr)__attribute__((weak, alias("__flash_write32")));
259void flash_write64(u64 value, void *addr)__attribute__((weak, alias("__flash_write64")));
260u8 flash_read8(void *addr)__attribute__((weak, alias("__flash_read8")));
261u16 flash_read16(void *addr)__attribute__((weak, alias("__flash_read16")));
262u32 flash_read32(void *addr)__attribute__((weak, alias("__flash_read32")));
Daniel Hellstrom97bf85d2008-03-28 20:40:19 +0100263u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
Stefan Roese45aa5a72008-11-17 14:45:22 +0100264#else
265#define flash_write8 __flash_write8
266#define flash_write16 __flash_write16
267#define flash_write32 __flash_write32
268#define flash_write64 __flash_write64
269#define flash_read8 __flash_read8
270#define flash_read16 __flash_read16
271#define flash_read32 __flash_read32
272#define flash_read64 __flash_read64
273#endif
Daniel Hellstrom97bf85d2008-03-28 20:40:19 +0100274
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200275/*-----------------------------------------------------------------------
276 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200277#if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
Heiko Schocher4f975672009-02-10 09:53:29 +0100278flash_info_t *flash_get_info(ulong base)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200279{
280 int i;
281 flash_info_t * info = 0;
282
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200283 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200284 info = & flash_info[i];
285 if (info->size && info->start[0] <= base &&
286 base <= info->start[0] + info->size - 1)
287 break;
288 }
289
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200290 return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200291}
wdenk5653fc32004-02-08 22:55:38 +0000292#endif
293
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100294unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
295{
296 if (sect != (info->sector_count - 1))
297 return info->start[sect + 1] - info->start[sect];
298 else
299 return info->start[0] + info->size - info->start[sect];
300}
301
wdenk5653fc32004-02-08 22:55:38 +0000302/*-----------------------------------------------------------------------
303 * create an address based on the offset and the port width
304 */
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100305static inline void *
306flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000307{
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100308 unsigned int byte_offset = offset * info->portwidth;
309
Becky Bruce09ce9922009-02-02 16:34:51 -0600310 return (void *)(info->start[sect] + byte_offset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100311}
312
313static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
314 unsigned int offset, void *addr)
315{
wdenk5653fc32004-02-08 22:55:38 +0000316}
wdenkbf9e3b32004-02-12 00:47:09 +0000317
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200318/*-----------------------------------------------------------------------
319 * make a proper sized command based on the port and chip widths
320 */
Sebastian Siewior7288f972008-07-15 13:35:23 +0200321static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200322{
323 int i;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400324 int cword_offset;
325 int cp_offset;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200326#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Sebastian Siewior340ccb22008-07-16 20:04:49 +0200327 u32 cmd_le = cpu_to_le32(cmd);
328#endif
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400329 uchar val;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200330 uchar *cp = (uchar *) cmdbuf;
331
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400332 for (i = info->portwidth; i > 0; i--){
333 cword_offset = (info->portwidth-i)%info->chipwidth;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200334#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400335 cp_offset = info->portwidth - i;
Sebastian Siewior340ccb22008-07-16 20:04:49 +0200336 val = *((uchar*)&cmd_le + cword_offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200337#else
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400338 cp_offset = i - 1;
Sebastian Siewior7288f972008-07-15 13:35:23 +0200339 val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200340#endif
Sebastian Siewior7288f972008-07-15 13:35:23 +0200341 cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400342 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200343}
344
wdenkbf9e3b32004-02-12 00:47:09 +0000345#ifdef DEBUG
346/*-----------------------------------------------------------------------
347 * Debug support
348 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100349static void print_longlong (char *str, unsigned long long data)
wdenkbf9e3b32004-02-12 00:47:09 +0000350{
351 int i;
352 char *cp;
353
Wolfgang Denk657f2062009-02-04 09:42:20 +0100354 cp = (char *) &data;
wdenkbf9e3b32004-02-12 00:47:09 +0000355 for (i = 0; i < 8; i++)
356 sprintf (&str[i * 2], "%2.2x", *cp++);
357}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200358
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100359static void flash_printqry (struct cfi_qry *qry)
wdenkbf9e3b32004-02-12 00:47:09 +0000360{
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100361 u8 *p = (u8 *)qry;
wdenkbf9e3b32004-02-12 00:47:09 +0000362 int x, y;
363
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100364 for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
365 debug("%02x : ", x);
366 for (y = 0; y < 16; y++)
367 debug("%2.2x ", p[x + y]);
368 debug(" ");
wdenkbf9e3b32004-02-12 00:47:09 +0000369 for (y = 0; y < 16; y++) {
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100370 unsigned char c = p[x + y];
371 if (c >= 0x20 && c <= 0x7e)
372 debug("%c", c);
373 else
374 debug(".");
wdenkbf9e3b32004-02-12 00:47:09 +0000375 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +0100376 debug("\n");
wdenkbf9e3b32004-02-12 00:47:09 +0000377 }
378}
wdenkbf9e3b32004-02-12 00:47:09 +0000379#endif
380
381
wdenk5653fc32004-02-08 22:55:38 +0000382/*-----------------------------------------------------------------------
383 * read a character at a port width address
384 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100385static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000386{
387 uchar *cp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100388 uchar retval;
wdenkbf9e3b32004-02-12 00:47:09 +0000389
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100390 cp = flash_map (info, 0, offset);
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200391#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100392 retval = flash_read8(cp);
wdenkbf9e3b32004-02-12 00:47:09 +0000393#else
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100394 retval = flash_read8(cp + info->portwidth - 1);
wdenkbf9e3b32004-02-12 00:47:09 +0000395#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100396 flash_unmap (info, 0, offset, cp);
397 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000398}
399
400/*-----------------------------------------------------------------------
Tor Krill90447ec2008-03-28 11:29:10 +0100401 * read a word at a port width address, assume 16bit bus
402 */
403static inline ushort flash_read_word (flash_info_t * info, uint offset)
404{
405 ushort *addr, retval;
406
407 addr = flash_map (info, 0, offset);
408 retval = flash_read16 (addr);
409 flash_unmap (info, 0, offset, addr);
410 return retval;
411}
412
413
414/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +0100415 * read a long word by picking the least significant byte of each maximum
wdenk5653fc32004-02-08 22:55:38 +0000416 * port size word. Swap for ppc format.
417 */
Haavard Skinnemoen30557932007-12-13 12:56:29 +0100418static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
419 uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000420{
wdenkbf9e3b32004-02-12 00:47:09 +0000421 uchar *addr;
422 ulong retval;
wdenk5653fc32004-02-08 22:55:38 +0000423
wdenkbf9e3b32004-02-12 00:47:09 +0000424#ifdef DEBUG
425 int x;
426#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100427 addr = flash_map (info, sect, offset);
wdenkbf9e3b32004-02-12 00:47:09 +0000428
429#ifdef DEBUG
430 debug ("long addr is at %p info->portwidth = %d\n", addr,
431 info->portwidth);
432 for (x = 0; x < 4 * info->portwidth; x++) {
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100433 debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
wdenkbf9e3b32004-02-12 00:47:09 +0000434 }
435#endif
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200436#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100437 retval = ((flash_read8(addr) << 16) |
438 (flash_read8(addr + info->portwidth) << 24) |
439 (flash_read8(addr + 2 * info->portwidth)) |
440 (flash_read8(addr + 3 * info->portwidth) << 8));
wdenkbf9e3b32004-02-12 00:47:09 +0000441#else
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100442 retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
443 (flash_read8(addr + info->portwidth - 1) << 16) |
444 (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
445 (flash_read8(addr + 3 * info->portwidth - 1)));
wdenkbf9e3b32004-02-12 00:47:09 +0000446#endif
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100447 flash_unmap(info, sect, offset, addr);
448
wdenkbf9e3b32004-02-12 00:47:09 +0000449 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000450}
451
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200452/*
453 * Write a proper sized command to the correct address
454 */
455static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
Sebastian Siewior7288f972008-07-15 13:35:23 +0200456 uint offset, u32 cmd)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200457{
Stefan Roese79b4cda2006-02-28 15:29:58 +0100458
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100459 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200460 cfiword_t cword;
461
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100462 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200463 flash_make_cmd (info, cmd, &cword);
464 switch (info->portwidth) {
465 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100466 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200467 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100468 flash_write8(cword.c, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200469 break;
470 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100471 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200472 cmd, cword.w,
473 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100474 flash_write16(cword.w, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200475 break;
476 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100477 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200478 cmd, cword.l,
479 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100480 flash_write32(cword.l, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200481 break;
482 case FLASH_CFI_64BIT:
483#ifdef DEBUG
484 {
485 char str[20];
486
487 print_longlong (str, cword.ll);
488
489 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100490 addr, cmd, str,
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200491 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
492 }
493#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100494 flash_write64(cword.ll, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200495 break;
496 }
497
498 /* Ensure all the instructions are fully finished */
499 sync();
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100500
501 flash_unmap(info, sect, offset, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200502}
503
504static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
505{
506 flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
507 flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
508}
509
510/*-----------------------------------------------------------------------
511 */
512static int flash_isequal (flash_info_t * info, flash_sect_t sect,
513 uint offset, uchar cmd)
514{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100515 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200516 cfiword_t cword;
517 int retval;
518
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100519 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200520 flash_make_cmd (info, cmd, &cword);
521
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100522 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200523 switch (info->portwidth) {
524 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100525 debug ("is= %x %x\n", flash_read8(addr), cword.c);
526 retval = (flash_read8(addr) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200527 break;
528 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100529 debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
530 retval = (flash_read16(addr) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200531 break;
532 case FLASH_CFI_32BIT:
Andrew Klossner52514692008-08-21 07:12:26 -0700533 debug ("is= %8.8x %8.8lx\n", flash_read32(addr), cword.l);
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100534 retval = (flash_read32(addr) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200535 break;
536 case FLASH_CFI_64BIT:
537#ifdef DEBUG
538 {
539 char str1[20];
540 char str2[20];
541
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100542 print_longlong (str1, flash_read64(addr));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200543 print_longlong (str2, cword.ll);
544 debug ("is= %s %s\n", str1, str2);
545 }
546#endif
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100547 retval = (flash_read64(addr) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200548 break;
549 default:
550 retval = 0;
551 break;
552 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100553 flash_unmap(info, sect, offset, addr);
554
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200555 return retval;
556}
557
558/*-----------------------------------------------------------------------
559 */
560static int flash_isset (flash_info_t * info, flash_sect_t sect,
561 uint offset, uchar cmd)
562{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100563 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200564 cfiword_t cword;
565 int retval;
566
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100567 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200568 flash_make_cmd (info, cmd, &cword);
569 switch (info->portwidth) {
570 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100571 retval = ((flash_read8(addr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200572 break;
573 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100574 retval = ((flash_read16(addr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200575 break;
576 case FLASH_CFI_32BIT:
Stefan Roese47cc23c2008-01-02 14:05:37 +0100577 retval = ((flash_read32(addr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200578 break;
579 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100580 retval = ((flash_read64(addr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200581 break;
582 default:
583 retval = 0;
584 break;
585 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100586 flash_unmap(info, sect, offset, addr);
587
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200588 return retval;
589}
590
591/*-----------------------------------------------------------------------
592 */
593static int flash_toggle (flash_info_t * info, flash_sect_t sect,
594 uint offset, uchar cmd)
595{
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100596 void *addr;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200597 cfiword_t cword;
598 int retval;
599
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100600 addr = flash_map (info, sect, offset);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200601 flash_make_cmd (info, cmd, &cword);
602 switch (info->portwidth) {
603 case FLASH_CFI_8BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200604 retval = flash_read8(addr) != flash_read8(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200605 break;
606 case FLASH_CFI_16BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200607 retval = flash_read16(addr) != flash_read16(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200608 break;
609 case FLASH_CFI_32BIT:
Stefan Roesefb8c0612008-06-16 10:40:02 +0200610 retval = flash_read32(addr) != flash_read32(addr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200611 break;
612 case FLASH_CFI_64BIT:
Wolfgang Denk9abda6b2008-10-31 01:12:28 +0100613 retval = ( (flash_read32( addr ) != flash_read32( addr )) ||
614 (flash_read32(addr+4) != flash_read32(addr+4)) );
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200615 break;
616 default:
617 retval = 0;
618 break;
619 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100620 flash_unmap(info, sect, offset, addr);
621
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200622 return retval;
623}
624
625/*
626 * flash_is_busy - check to see if the flash is busy
627 *
628 * This routine checks the status of the chip and returns true if the
629 * chip is busy.
630 */
631static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
632{
633 int retval;
634
635 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400636 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200637 case CFI_CMDSET_INTEL_STANDARD:
638 case CFI_CMDSET_INTEL_EXTENDED:
639 retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
640 break;
641 case CFI_CMDSET_AMD_STANDARD:
642 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100643#ifdef CONFIG_FLASH_CFI_LEGACY
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200644 case CFI_CMDSET_AMD_LEGACY:
645#endif
646 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
647 break;
648 default:
649 retval = 0;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100650 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200651 debug ("flash_is_busy: %d\n", retval);
652 return retval;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100653}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200654
655/*-----------------------------------------------------------------------
656 * wait for XSR.7 to be set. Time out with an error if it does not.
657 * This routine does not set the flash to read-array mode.
658 */
659static int flash_status_check (flash_info_t * info, flash_sect_t sector,
660 ulong tout, char *prompt)
661{
662 ulong start;
663
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200664#if CONFIG_SYS_HZ != 1000
665 tout *= CONFIG_SYS_HZ/1000;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200666#endif
667
668 /* Wait for command completion */
669 start = get_timer (0);
670 while (flash_is_busy (info, sector)) {
671 if (get_timer (start) > tout) {
672 printf ("Flash %s timeout at address %lx data %lx\n",
673 prompt, info->start[sector],
674 flash_read_long (info, sector, 0));
675 flash_write_cmd (info, sector, 0, info->cmd_reset);
676 return ERR_TIMOUT;
677 }
678 udelay (1); /* also triggers watchdog */
679 }
680 return ERR_OK;
681}
682
683/*-----------------------------------------------------------------------
684 * Wait for XSR.7 to be set, if it times out print an error, otherwise
685 * do a full status check.
686 *
687 * This routine sets the flash to read-array mode.
688 */
689static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
690 ulong tout, char *prompt)
691{
692 int retcode;
693
694 retcode = flash_status_check (info, sector, tout, prompt);
695 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400696 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200697 case CFI_CMDSET_INTEL_EXTENDED:
698 case CFI_CMDSET_INTEL_STANDARD:
Ed Swarthout0d01f662008-10-09 01:26:36 -0500699 if ((retcode != ERR_OK)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200700 && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
701 retcode = ERR_INVAL;
702 printf ("Flash %s error at address %lx\n", prompt,
703 info->start[sector]);
704 if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
705 FLASH_STATUS_PSLBS)) {
706 puts ("Command Sequence Error.\n");
707 } else if (flash_isset (info, sector, 0,
708 FLASH_STATUS_ECLBS)) {
709 puts ("Block Erase Error.\n");
710 retcode = ERR_NOT_ERASED;
711 } else if (flash_isset (info, sector, 0,
712 FLASH_STATUS_PSLBS)) {
713 puts ("Locking Error\n");
714 }
715 if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
716 puts ("Block locked.\n");
717 retcode = ERR_PROTECTED;
718 }
719 if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
720 puts ("Vpp Low Error.\n");
721 }
722 flash_write_cmd (info, sector, 0, info->cmd_reset);
723 break;
724 default:
725 break;
726 }
727 return retcode;
728}
729
730/*-----------------------------------------------------------------------
731 */
732static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
733{
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200734#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200735 unsigned short w;
736 unsigned int l;
737 unsigned long long ll;
738#endif
739
740 switch (info->portwidth) {
741 case FLASH_CFI_8BIT:
742 cword->c = c;
743 break;
744 case FLASH_CFI_16BIT:
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200745#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200746 w = c;
747 w <<= 8;
748 cword->w = (cword->w >> 8) | w;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100749#else
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200750 cword->w = (cword->w << 8) | c;
Michael Schwingen81b20cc2007-12-07 23:35:02 +0100751#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200752 break;
753 case FLASH_CFI_32BIT:
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200754#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200755 l = c;
756 l <<= 24;
757 cword->l = (cword->l >> 8) | l;
758#else
759 cword->l = (cword->l << 8) | c;
Stefan Roese2662b402006-04-01 13:41:03 +0200760#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200761 break;
762 case FLASH_CFI_64BIT:
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200763#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200764 ll = c;
765 ll <<= 56;
766 cword->ll = (cword->ll >> 8) | ll;
767#else
768 cword->ll = (cword->ll << 8) | c;
769#endif
770 break;
wdenk5653fc32004-02-08 22:55:38 +0000771 }
wdenk5653fc32004-02-08 22:55:38 +0000772}
773
Jens Gehrlein0f8e8512008-12-16 17:25:55 +0100774/*
775 * Loop through the sector table starting from the previously found sector.
776 * Searches forwards or backwards, dependent on the passed address.
wdenk5653fc32004-02-08 22:55:38 +0000777 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200778static flash_sect_t find_sector (flash_info_t * info, ulong addr)
wdenk7680c142005-05-16 15:23:22 +0000779{
Jens Gehrlein0f8e8512008-12-16 17:25:55 +0100780 static flash_sect_t saved_sector = 0; /* previously found sector */
781 flash_sect_t sector = saved_sector;
wdenk7680c142005-05-16 15:23:22 +0000782
Jens Gehrlein0f8e8512008-12-16 17:25:55 +0100783 while ((info->start[sector] < addr)
784 && (sector < info->sector_count - 1))
785 sector++;
786 while ((info->start[sector] > addr) && (sector > 0))
787 /*
788 * also decrements the sector in case of an overshot
789 * in the first loop
790 */
791 sector--;
792
793 saved_sector = sector;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200794 return sector;
wdenk7680c142005-05-16 15:23:22 +0000795}
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200796
797/*-----------------------------------------------------------------------
798 */
799static int flash_write_cfiword (flash_info_t * info, ulong dest,
800 cfiword_t cword)
801{
Becky Bruce09ce9922009-02-02 16:34:51 -0600802 void *dstaddr = (void *)dest;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200803 int flag;
Jens Gehrleina7292872008-12-16 17:25:54 +0100804 flash_sect_t sect = 0;
805 char sect_found = 0;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200806
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200807 /* Check if Flash is (sufficiently) erased */
808 switch (info->portwidth) {
809 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100810 flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200811 break;
812 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100813 flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200814 break;
815 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100816 flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200817 break;
818 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100819 flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200820 break;
821 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100822 flag = 0;
823 break;
824 }
Becky Bruce09ce9922009-02-02 16:34:51 -0600825 if (!flag)
Stefan Roese0dc80e22007-12-27 07:50:54 +0100826 return ERR_NOT_ERASED;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200827
828 /* Disable interrupts which might cause a timeout here */
829 flag = disable_interrupts ();
830
831 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400832 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200833 case CFI_CMDSET_INTEL_EXTENDED:
834 case CFI_CMDSET_INTEL_STANDARD:
835 flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
836 flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
837 break;
838 case CFI_CMDSET_AMD_EXTENDED:
839 case CFI_CMDSET_AMD_STANDARD:
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);
Jens Gehrleina7292872008-12-16 17:25:54 +0100843 sect_found = 1;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200844 break;
Po-Yu Chuangb4db4a72009-07-10 18:03:57 +0800845#ifdef CONFIG_FLASH_CFI_LEGACY
846 case CFI_CMDSET_AMD_LEGACY:
847 sect = find_sector(info, dest);
848 flash_unlock_seq (info, 0);
849 flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
850 sect_found = 1;
851 break;
852#endif
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200853 }
854
855 switch (info->portwidth) {
856 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100857 flash_write8(cword.c, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200858 break;
859 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100860 flash_write16(cword.w, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200861 break;
862 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100863 flash_write32(cword.l, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200864 break;
865 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100866 flash_write64(cword.ll, dstaddr);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200867 break;
868 }
869
870 /* re-enable interrupts if necessary */
871 if (flag)
872 enable_interrupts ();
873
Jens Gehrleina7292872008-12-16 17:25:54 +0100874 if (!sect_found)
875 sect = find_sector (info, dest);
876
877 return flash_full_status_check (info, sect, info->write_tout, "write");
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200878}
879
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200880#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200881
882static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
883 int len)
884{
885 flash_sect_t sector;
886 int cnt;
887 int retcode;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100888 void *src = cp;
Stefan Roeseec21d5c2009-02-05 11:25:57 +0100889 void *dst = (void *)dest;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100890 void *dst2 = dst;
891 int flag = 0;
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200892 uint offset = 0;
893 unsigned int shift;
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400894 uchar write_cmd;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100895
Stefan Roese0dc80e22007-12-27 07:50:54 +0100896 switch (info->portwidth) {
897 case FLASH_CFI_8BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200898 shift = 0;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100899 break;
900 case FLASH_CFI_16BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200901 shift = 1;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100902 break;
903 case FLASH_CFI_32BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200904 shift = 2;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100905 break;
906 case FLASH_CFI_64BIT:
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200907 shift = 3;
Stefan Roese0dc80e22007-12-27 07:50:54 +0100908 break;
909 default:
910 retcode = ERR_INVAL;
911 goto out_unmap;
912 }
913
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200914 cnt = len >> shift;
915
Stefan Roese0dc80e22007-12-27 07:50:54 +0100916 while ((cnt-- > 0) && (flag == 0)) {
917 switch (info->portwidth) {
918 case FLASH_CFI_8BIT:
919 flag = ((flash_read8(dst2) & flash_read8(src)) ==
920 flash_read8(src));
921 src += 1, dst2 += 1;
922 break;
923 case FLASH_CFI_16BIT:
924 flag = ((flash_read16(dst2) & flash_read16(src)) ==
925 flash_read16(src));
926 src += 2, dst2 += 2;
927 break;
928 case FLASH_CFI_32BIT:
929 flag = ((flash_read32(dst2) & flash_read32(src)) ==
930 flash_read32(src));
931 src += 4, dst2 += 4;
932 break;
933 case FLASH_CFI_64BIT:
934 flag = ((flash_read64(dst2) & flash_read64(src)) ==
935 flash_read64(src));
936 src += 8, dst2 += 8;
937 break;
938 }
939 }
940 if (!flag) {
941 retcode = ERR_NOT_ERASED;
942 goto out_unmap;
943 }
944
945 src = cp;
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100946 sector = find_sector (info, dest);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200947
948 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400949 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200950 case CFI_CMDSET_INTEL_STANDARD:
951 case CFI_CMDSET_INTEL_EXTENDED:
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400952 write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
953 FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200954 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +0400955 flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS);
956 flash_write_cmd (info, sector, 0, write_cmd);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200957 retcode = flash_status_check (info, sector,
958 info->buffer_write_tout,
959 "write to buffer");
960 if (retcode == ERR_OK) {
961 /* reduce the number of loops by the width of
962 * the port */
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +0200963 cnt = len >> shift;
Vasiliy Leoenenko93c56f22008-05-07 21:24:44 +0400964 flash_write_cmd (info, sector, 0, cnt - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200965 while (cnt-- > 0) {
966 switch (info->portwidth) {
967 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100968 flash_write8(flash_read8(src), dst);
969 src += 1, dst += 1;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200970 break;
971 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100972 flash_write16(flash_read16(src), dst);
973 src += 2, dst += 2;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200974 break;
975 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100976 flash_write32(flash_read32(src), dst);
977 src += 4, dst += 4;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200978 break;
979 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +0100980 flash_write64(flash_read64(src), dst);
981 src += 8, dst += 8;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200982 break;
983 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100984 retcode = ERR_INVAL;
985 goto out_unmap;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200986 }
987 }
988 flash_write_cmd (info, sector, 0,
989 FLASH_CMD_WRITE_BUFFER_CONFIRM);
990 retcode = flash_full_status_check (
991 info, sector, info->buffer_write_tout,
992 "buffer write");
993 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +0100994
995 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200996
997 case CFI_CMDSET_AMD_STANDARD:
998 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +0200999 flash_unlock_seq(info,0);
Guennadi Liakhovetski96ef8312008-04-03 13:36:02 +02001000
1001#ifdef CONFIG_FLASH_SPANSION_S29WS_N
1002 offset = ((unsigned long)dst - info->start[sector]) >> shift;
1003#endif
1004 flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
1005 cnt = len >> shift;
John Schmoller7dedefd2009-08-12 10:55:47 -05001006 flash_write_cmd(info, sector, offset, cnt - 1);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001007
1008 switch (info->portwidth) {
1009 case FLASH_CFI_8BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +01001010 while (cnt-- > 0) {
1011 flash_write8(flash_read8(src), dst);
1012 src += 1, dst += 1;
1013 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001014 break;
1015 case FLASH_CFI_16BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +01001016 while (cnt-- > 0) {
1017 flash_write16(flash_read16(src), dst);
1018 src += 2, dst += 2;
1019 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001020 break;
1021 case FLASH_CFI_32BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +01001022 while (cnt-- > 0) {
1023 flash_write32(flash_read32(src), dst);
1024 src += 4, dst += 4;
1025 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001026 break;
1027 case FLASH_CFI_64BIT:
Haavard Skinnemoencdbaefb2007-12-13 12:56:32 +01001028 while (cnt-- > 0) {
1029 flash_write64(flash_read64(src), dst);
1030 src += 8, dst += 8;
1031 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001032 break;
1033 default:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001034 retcode = ERR_INVAL;
1035 goto out_unmap;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001036 }
1037
1038 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1039 retcode = flash_full_status_check (info, sector,
1040 info->buffer_write_tout,
1041 "buffer write");
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001042 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001043
1044 default:
1045 debug ("Unknown Command Set\n");
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001046 retcode = ERR_INVAL;
1047 break;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001048 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001049
1050out_unmap:
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001051 return retcode;
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001052}
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001053#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001054
wdenk7680c142005-05-16 15:23:22 +00001055
1056/*-----------------------------------------------------------------------
1057 */
wdenkbf9e3b32004-02-12 00:47:09 +00001058int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk5653fc32004-02-08 22:55:38 +00001059{
1060 int rcode = 0;
1061 int prot;
1062 flash_sect_t sect;
1063
wdenkbf9e3b32004-02-12 00:47:09 +00001064 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001065 puts ("Can't erase unknown flash type - aborted\n");
wdenk5653fc32004-02-08 22:55:38 +00001066 return 1;
1067 }
1068 if ((s_first < 0) || (s_first > s_last)) {
wdenk4b9206e2004-03-23 22:14:11 +00001069 puts ("- no sectors to erase\n");
wdenk5653fc32004-02-08 22:55:38 +00001070 return 1;
1071 }
1072
1073 prot = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001074 for (sect = s_first; sect <= s_last; ++sect) {
wdenk5653fc32004-02-08 22:55:38 +00001075 if (info->protect[sect]) {
1076 prot++;
1077 }
1078 }
1079 if (prot) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001080 printf ("- Warning: %d protected sectors will not be erased!\n",
1081 prot);
Piotr Ziecik6ea808e2008-11-17 15:49:32 +01001082 } else if (flash_verbose) {
wdenk4b9206e2004-03-23 22:14:11 +00001083 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001084 }
1085
1086
wdenkbf9e3b32004-02-12 00:47:09 +00001087 for (sect = s_first; sect <= s_last; sect++) {
wdenk5653fc32004-02-08 22:55:38 +00001088 if (info->protect[sect] == 0) { /* not protected */
wdenkbf9e3b32004-02-12 00:47:09 +00001089 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001090 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk5653fc32004-02-08 22:55:38 +00001091 case CFI_CMDSET_INTEL_STANDARD:
1092 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001093 flash_write_cmd (info, sect, 0,
1094 FLASH_CMD_CLEAR_STATUS);
1095 flash_write_cmd (info, sect, 0,
1096 FLASH_CMD_BLOCK_ERASE);
1097 flash_write_cmd (info, sect, 0,
1098 FLASH_CMD_ERASE_CONFIRM);
wdenk5653fc32004-02-08 22:55:38 +00001099 break;
1100 case CFI_CMDSET_AMD_STANDARD:
1101 case CFI_CMDSET_AMD_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +00001102 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001103 flash_write_cmd (info, sect,
1104 info->addr_unlock1,
1105 AMD_CMD_ERASE_START);
wdenkbf9e3b32004-02-12 00:47:09 +00001106 flash_unlock_seq (info, sect);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001107 flash_write_cmd (info, sect, 0,
1108 AMD_CMD_ERASE_SECTOR);
wdenk5653fc32004-02-08 22:55:38 +00001109 break;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001110#ifdef CONFIG_FLASH_CFI_LEGACY
1111 case CFI_CMDSET_AMD_LEGACY:
1112 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001113 flash_write_cmd (info, 0, info->addr_unlock1,
1114 AMD_CMD_ERASE_START);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001115 flash_unlock_seq (info, 0);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001116 flash_write_cmd (info, sect, 0,
1117 AMD_CMD_ERASE_SECTOR);
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001118 break;
1119#endif
wdenk5653fc32004-02-08 22:55:38 +00001120 default:
wdenkbf9e3b32004-02-12 00:47:09 +00001121 debug ("Unkown flash vendor %d\n",
1122 info->vendor);
wdenk5653fc32004-02-08 22:55:38 +00001123 break;
1124 }
1125
wdenkbf9e3b32004-02-12 00:47:09 +00001126 if (flash_full_status_check
1127 (info, sect, info->erase_blk_tout, "erase")) {
wdenk5653fc32004-02-08 22:55:38 +00001128 rcode = 1;
Piotr Ziecik6ea808e2008-11-17 15:49:32 +01001129 } else if (flash_verbose)
wdenk4b9206e2004-03-23 22:14:11 +00001130 putc ('.');
wdenk5653fc32004-02-08 22:55:38 +00001131 }
1132 }
Piotr Ziecik6ea808e2008-11-17 15:49:32 +01001133
1134 if (flash_verbose)
1135 puts (" done\n");
1136
wdenk5653fc32004-02-08 22:55:38 +00001137 return rcode;
1138}
1139
1140/*-----------------------------------------------------------------------
1141 */
wdenkbf9e3b32004-02-12 00:47:09 +00001142void flash_print_info (flash_info_t * info)
wdenk5653fc32004-02-08 22:55:38 +00001143{
1144 int i;
1145
1146 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +00001147 puts ("missing or unknown FLASH type\n");
wdenk5653fc32004-02-08 22:55:38 +00001148 return;
1149 }
1150
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001151 printf ("%s FLASH (%d x %d)",
1152 info->name,
wdenkbf9e3b32004-02-12 00:47:09 +00001153 (info->portwidth << 3), (info->chipwidth << 3));
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001154 if (info->size < 1024*1024)
1155 printf (" Size: %ld kB in %d Sectors\n",
1156 info->size >> 10, info->sector_count);
1157 else
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001158 printf (" Size: %ld MB in %d Sectors\n",
1159 info->size >> 20, info->sector_count);
Stefan Roese260421a2006-11-13 13:55:24 +01001160 printf (" ");
1161 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001162 case CFI_CMDSET_INTEL_PROG_REGIONS:
1163 printf ("Intel Prog Regions");
1164 break;
Stefan Roese260421a2006-11-13 13:55:24 +01001165 case CFI_CMDSET_INTEL_STANDARD:
1166 printf ("Intel Standard");
1167 break;
1168 case CFI_CMDSET_INTEL_EXTENDED:
1169 printf ("Intel Extended");
1170 break;
1171 case CFI_CMDSET_AMD_STANDARD:
1172 printf ("AMD Standard");
1173 break;
1174 case CFI_CMDSET_AMD_EXTENDED:
1175 printf ("AMD Extended");
1176 break;
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001177#ifdef CONFIG_FLASH_CFI_LEGACY
1178 case CFI_CMDSET_AMD_LEGACY:
1179 printf ("AMD Legacy");
1180 break;
1181#endif
Stefan Roese260421a2006-11-13 13:55:24 +01001182 default:
1183 printf ("Unknown (%d)", info->vendor);
1184 break;
1185 }
1186 printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
1187 info->manufacturer_id, info->device_id);
1188 if (info->device_id == 0x7E) {
1189 printf("%04X", info->device_id2);
1190 }
1191 printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n",
wdenk028ab6b2004-02-23 23:54:43 +00001192 info->erase_blk_tout,
Stefan Roese260421a2006-11-13 13:55:24 +01001193 info->write_tout);
1194 if (info->buffer_size > 1) {
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001195 printf (" Buffer write timeout: %ld ms, "
1196 "buffer size: %d bytes\n",
wdenk028ab6b2004-02-23 23:54:43 +00001197 info->buffer_write_tout,
1198 info->buffer_size);
Stefan Roese260421a2006-11-13 13:55:24 +01001199 }
wdenk5653fc32004-02-08 22:55:38 +00001200
Stefan Roese260421a2006-11-13 13:55:24 +01001201 puts ("\n Sector Start Addresses:");
wdenkbf9e3b32004-02-12 00:47:09 +00001202 for (i = 0; i < info->sector_count; ++i) {
Stefan Roese260421a2006-11-13 13:55:24 +01001203 if ((i % 5) == 0)
1204 printf ("\n");
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001205#ifdef CONFIG_SYS_FLASH_EMPTY_INFO
wdenk5653fc32004-02-08 22:55:38 +00001206 int k;
1207 int size;
1208 int erased;
1209 volatile unsigned long *flash;
1210
1211 /*
1212 * Check if whole sector is erased
1213 */
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001214 size = flash_sector_size(info, i);
wdenk5653fc32004-02-08 22:55:38 +00001215 erased = 1;
wdenkbf9e3b32004-02-12 00:47:09 +00001216 flash = (volatile unsigned long *) info->start[i];
1217 size = size >> 2; /* divide by 4 for longword access */
1218 for (k = 0; k < size; k++) {
1219 if (*flash++ != 0xffffffff) {
1220 erased = 0;
1221 break;
1222 }
1223 }
wdenk5653fc32004-02-08 22:55:38 +00001224
wdenk5653fc32004-02-08 22:55:38 +00001225 /* print empty and read-only info */
Stefan Roese260421a2006-11-13 13:55:24 +01001226 printf (" %08lX %c %s ",
wdenk5653fc32004-02-08 22:55:38 +00001227 info->start[i],
Stefan Roese260421a2006-11-13 13:55:24 +01001228 erased ? 'E' : ' ',
1229 info->protect[i] ? "RO" : " ");
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001230#else /* ! CONFIG_SYS_FLASH_EMPTY_INFO */
Stefan Roese260421a2006-11-13 13:55:24 +01001231 printf (" %08lX %s ",
1232 info->start[i],
1233 info->protect[i] ? "RO" : " ");
wdenk5653fc32004-02-08 22:55:38 +00001234#endif
1235 }
wdenk4b9206e2004-03-23 22:14:11 +00001236 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +00001237 return;
1238}
1239
1240/*-----------------------------------------------------------------------
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001241 * This is used in a few places in write_buf() to show programming
1242 * progress. Making it a function is nasty because it needs to do side
1243 * effect updates to digit and dots. Repeated code is nasty too, so
1244 * we define it once here.
1245 */
Stefan Roesef0105722008-03-19 07:09:26 +01001246#ifdef CONFIG_FLASH_SHOW_PROGRESS
1247#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
Piotr Ziecik6ea808e2008-11-17 15:49:32 +01001248 if (flash_verbose) { \
1249 dots -= dots_sub; \
1250 if ((scale > 0) && (dots <= 0)) { \
1251 if ((digit % 5) == 0) \
1252 printf ("%d", digit / 5); \
1253 else \
1254 putc ('.'); \
1255 digit--; \
1256 dots += scale; \
1257 } \
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001258 }
Stefan Roesef0105722008-03-19 07:09:26 +01001259#else
1260#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1261#endif
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001262
1263/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001264 * Copy memory to flash, returns:
1265 * 0 - OK
1266 * 1 - write timeout
1267 * 2 - Flash not erased
1268 */
wdenkbf9e3b32004-02-12 00:47:09 +00001269int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk5653fc32004-02-08 22:55:38 +00001270{
1271 ulong wp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001272 uchar *p;
wdenk5653fc32004-02-08 22:55:38 +00001273 int aln;
1274 cfiword_t cword;
1275 int i, rc;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001276#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
wdenkbf9e3b32004-02-12 00:47:09 +00001277 int buffered_size;
1278#endif
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001279#ifdef CONFIG_FLASH_SHOW_PROGRESS
1280 int digit = CONFIG_FLASH_SHOW_PROGRESS;
1281 int scale = 0;
1282 int dots = 0;
1283
1284 /*
1285 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
1286 */
1287 if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
1288 scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
1289 CONFIG_FLASH_SHOW_PROGRESS);
1290 }
1291#endif
1292
wdenkbf9e3b32004-02-12 00:47:09 +00001293 /* get lower aligned address */
wdenk5653fc32004-02-08 22:55:38 +00001294 wp = (addr & ~(info->portwidth - 1));
1295
1296 /* handle unaligned start */
wdenkbf9e3b32004-02-12 00:47:09 +00001297 if ((aln = addr - wp) != 0) {
wdenk5653fc32004-02-08 22:55:38 +00001298 cword.l = 0;
Becky Bruce09ce9922009-02-02 16:34:51 -06001299 p = (uchar *)wp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001300 for (i = 0; i < aln; ++i)
1301 flash_add_byte (info, &cword, flash_read8(p + i));
wdenk5653fc32004-02-08 22:55:38 +00001302
wdenkbf9e3b32004-02-12 00:47:09 +00001303 for (; (i < info->portwidth) && (cnt > 0); i++) {
1304 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001305 cnt--;
wdenk5653fc32004-02-08 22:55:38 +00001306 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001307 for (; (cnt == 0) && (i < info->portwidth); ++i)
1308 flash_add_byte (info, &cword, flash_read8(p + i));
1309
1310 rc = flash_write_cfiword (info, wp, cword);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001311 if (rc != 0)
wdenk5653fc32004-02-08 22:55:38 +00001312 return rc;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001313
1314 wp += i;
Stefan Roesef0105722008-03-19 07:09:26 +01001315 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001316 }
1317
wdenkbf9e3b32004-02-12 00:47:09 +00001318 /* handle the aligned part */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001319#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
wdenkbf9e3b32004-02-12 00:47:09 +00001320 buffered_size = (info->portwidth / info->chipwidth);
1321 buffered_size *= info->buffer_size;
1322 while (cnt >= info->portwidth) {
Stefan Roese79b4cda2006-02-28 15:29:58 +01001323 /* prohibit buffer write when buffer_size is 1 */
1324 if (info->buffer_size == 1) {
1325 cword.l = 0;
1326 for (i = 0; i < info->portwidth; i++)
1327 flash_add_byte (info, &cword, *src++);
1328 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1329 return rc;
1330 wp += info->portwidth;
1331 cnt -= info->portwidth;
1332 continue;
1333 }
1334
1335 /* write buffer until next buffered_size aligned boundary */
1336 i = buffered_size - (wp % buffered_size);
1337 if (i > cnt)
1338 i = cnt;
wdenkbf9e3b32004-02-12 00:47:09 +00001339 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
wdenk5653fc32004-02-08 22:55:38 +00001340 return rc;
Wolfgang Denk8d4ba3d2005-08-12 22:35:59 +02001341 i -= i & (info->portwidth - 1);
wdenk5653fc32004-02-08 22:55:38 +00001342 wp += i;
1343 src += i;
wdenkbf9e3b32004-02-12 00:47:09 +00001344 cnt -= i;
Stefan Roesef0105722008-03-19 07:09:26 +01001345 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
wdenk5653fc32004-02-08 22:55:38 +00001346 }
1347#else
wdenkbf9e3b32004-02-12 00:47:09 +00001348 while (cnt >= info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001349 cword.l = 0;
wdenkbf9e3b32004-02-12 00:47:09 +00001350 for (i = 0; i < info->portwidth; i++) {
1351 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001352 }
wdenkbf9e3b32004-02-12 00:47:09 +00001353 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk5653fc32004-02-08 22:55:38 +00001354 return rc;
1355 wp += info->portwidth;
1356 cnt -= info->portwidth;
Stefan Roesef0105722008-03-19 07:09:26 +01001357 FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
wdenk5653fc32004-02-08 22:55:38 +00001358 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001359#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
Jerry Van Baren9a042e92008-03-08 13:48:01 -05001360
wdenk5653fc32004-02-08 22:55:38 +00001361 if (cnt == 0) {
1362 return (0);
1363 }
1364
1365 /*
1366 * handle unaligned tail bytes
1367 */
1368 cword.l = 0;
Becky Bruce09ce9922009-02-02 16:34:51 -06001369 p = (uchar *)wp;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001370 for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
wdenkbf9e3b32004-02-12 00:47:09 +00001371 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +00001372 --cnt;
1373 }
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001374 for (; i < info->portwidth; ++i)
1375 flash_add_byte (info, &cword, flash_read8(p + i));
wdenk5653fc32004-02-08 22:55:38 +00001376
wdenkbf9e3b32004-02-12 00:47:09 +00001377 return flash_write_cfiword (info, wp, cword);
wdenk5653fc32004-02-08 22:55:38 +00001378}
1379
1380/*-----------------------------------------------------------------------
1381 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001382#ifdef CONFIG_SYS_FLASH_PROTECTION
wdenk5653fc32004-02-08 22:55:38 +00001383
wdenkbf9e3b32004-02-12 00:47:09 +00001384int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk5653fc32004-02-08 22:55:38 +00001385{
1386 int retcode = 0;
1387
Rafael Camposbc9019e2008-07-31 10:22:20 +02001388 switch (info->vendor) {
1389 case CFI_CMDSET_INTEL_PROG_REGIONS:
1390 case CFI_CMDSET_INTEL_STANDARD:
Nick Spence9e8e63c2008-08-19 22:21:16 -07001391 case CFI_CMDSET_INTEL_EXTENDED:
Rafael Camposbc9019e2008-07-31 10:22:20 +02001392 flash_write_cmd (info, sector, 0,
1393 FLASH_CMD_CLEAR_STATUS);
1394 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1395 if (prot)
1396 flash_write_cmd (info, sector, 0,
1397 FLASH_CMD_PROTECT_SET);
1398 else
1399 flash_write_cmd (info, sector, 0,
1400 FLASH_CMD_PROTECT_CLEAR);
1401 break;
1402 case CFI_CMDSET_AMD_EXTENDED:
1403 case CFI_CMDSET_AMD_STANDARD:
Rafael Camposbc9019e2008-07-31 10:22:20 +02001404 /* U-Boot only checks the first byte */
1405 if (info->manufacturer_id == (uchar)ATM_MANUFACT) {
1406 if (prot) {
1407 flash_unlock_seq (info, 0);
1408 flash_write_cmd (info, 0,
1409 info->addr_unlock1,
1410 ATM_CMD_SOFTLOCK_START);
1411 flash_unlock_seq (info, 0);
1412 flash_write_cmd (info, sector, 0,
1413 ATM_CMD_LOCK_SECT);
1414 } else {
1415 flash_write_cmd (info, 0,
1416 info->addr_unlock1,
1417 AMD_CMD_UNLOCK_START);
1418 if (info->device_id == ATM_ID_BV6416)
1419 flash_write_cmd (info, sector,
1420 0, ATM_CMD_UNLOCK_SECT);
1421 }
1422 }
1423 break;
TsiChung Liew4e00acd2008-08-19 16:53:39 +00001424#ifdef CONFIG_FLASH_CFI_LEGACY
1425 case CFI_CMDSET_AMD_LEGACY:
1426 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1427 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1428 if (prot)
1429 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
1430 else
1431 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
1432#endif
Rafael Camposbc9019e2008-07-31 10:22:20 +02001433 };
wdenk5653fc32004-02-08 22:55:38 +00001434
wdenkbf9e3b32004-02-12 00:47:09 +00001435 if ((retcode =
1436 flash_full_status_check (info, sector, info->erase_blk_tout,
1437 prot ? "protect" : "unprotect")) == 0) {
wdenk5653fc32004-02-08 22:55:38 +00001438
1439 info->protect[sector] = prot;
Stefan Roese2662b402006-04-01 13:41:03 +02001440
1441 /*
1442 * On some of Intel's flash chips (marked via legacy_unlock)
1443 * unprotect unprotects all locking.
1444 */
1445 if ((prot == 0) && (info->legacy_unlock)) {
wdenk5653fc32004-02-08 22:55:38 +00001446 flash_sect_t i;
wdenkbf9e3b32004-02-12 00:47:09 +00001447
1448 for (i = 0; i < info->sector_count; i++) {
1449 if (info->protect[i])
1450 flash_real_protect (info, i, 1);
wdenk5653fc32004-02-08 22:55:38 +00001451 }
1452 }
1453 }
wdenk5653fc32004-02-08 22:55:38 +00001454 return retcode;
wdenkbf9e3b32004-02-12 00:47:09 +00001455}
1456
wdenk5653fc32004-02-08 22:55:38 +00001457/*-----------------------------------------------------------------------
1458 * flash_read_user_serial - read the OneTimeProgramming cells
1459 */
wdenkbf9e3b32004-02-12 00:47:09 +00001460void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
1461 int len)
wdenk5653fc32004-02-08 22:55:38 +00001462{
wdenkbf9e3b32004-02-12 00:47:09 +00001463 uchar *src;
1464 uchar *dst;
wdenk5653fc32004-02-08 22:55:38 +00001465
1466 dst = buffer;
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001467 src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001468 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1469 memcpy (dst, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001470 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001471 flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001472}
wdenkbf9e3b32004-02-12 00:47:09 +00001473
wdenk5653fc32004-02-08 22:55:38 +00001474/*
1475 * flash_read_factory_serial - read the device Id from the protection area
1476 */
wdenkbf9e3b32004-02-12 00:47:09 +00001477void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
1478 int len)
wdenk5653fc32004-02-08 22:55:38 +00001479{
wdenkbf9e3b32004-02-12 00:47:09 +00001480 uchar *src;
wdenkcd37d9e2004-02-10 00:03:41 +00001481
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001482 src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
wdenkbf9e3b32004-02-12 00:47:09 +00001483 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1484 memcpy (buffer, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001485 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoen12d30aa2007-12-13 12:56:34 +01001486 flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
wdenk5653fc32004-02-08 22:55:38 +00001487}
1488
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001489#endif /* CONFIG_SYS_FLASH_PROTECTION */
wdenk5653fc32004-02-08 22:55:38 +00001490
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001491/*-----------------------------------------------------------------------
1492 * Reverse the order of the erase regions in the CFI QRY structure.
1493 * This is needed for chips that are either a) correctly detected as
1494 * top-boot, or b) buggy.
1495 */
1496static void cfi_reverse_geometry(struct cfi_qry *qry)
1497{
1498 unsigned int i, j;
1499 u32 tmp;
1500
1501 for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
1502 tmp = qry->erase_region_info[i];
1503 qry->erase_region_info[i] = qry->erase_region_info[j];
1504 qry->erase_region_info[j] = tmp;
1505 }
1506}
wdenk5653fc32004-02-08 22:55:38 +00001507
1508/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +01001509 * read jedec ids from device and set corresponding fields in info struct
1510 *
1511 * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1512 *
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001513 */
1514static void cmdset_intel_read_jedec_ids(flash_info_t *info)
1515{
1516 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1517 flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1518 udelay(1000); /* some flash are slow to respond */
1519 info->manufacturer_id = flash_read_uchar (info,
1520 FLASH_OFFSET_MANUFACTURER_ID);
1521 info->device_id = flash_read_uchar (info,
1522 FLASH_OFFSET_DEVICE_ID);
1523 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1524}
1525
1526static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
1527{
1528 info->cmd_reset = FLASH_CMD_RESET;
1529
1530 cmdset_intel_read_jedec_ids(info);
1531 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1532
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001533#ifdef CONFIG_SYS_FLASH_PROTECTION
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001534 /* read legacy lock/unlock bit from intel flash */
1535 if (info->ext_addr) {
1536 info->legacy_unlock = flash_read_uchar (info,
1537 info->ext_addr + 5) & 0x08;
1538 }
1539#endif
1540
1541 return 0;
1542}
1543
1544static void cmdset_amd_read_jedec_ids(flash_info_t *info)
1545{
Niklaus Giger3a7b2c22009-07-22 17:13:24 +02001546 ushort bankId = 0;
1547 uchar manuId;
1548
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001549 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1550 flash_unlock_seq(info, 0);
1551 flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
1552 udelay(1000); /* some flash are slow to respond */
Tor Krill90447ec2008-03-28 11:29:10 +01001553
Niklaus Giger3a7b2c22009-07-22 17:13:24 +02001554 manuId = flash_read_uchar (info, FLASH_OFFSET_MANUFACTURER_ID);
1555 /* JEDEC JEP106Z specifies ID codes up to bank 7 */
1556 while (manuId == FLASH_CONTINUATION_CODE && bankId < 0x800) {
1557 bankId += 0x100;
1558 manuId = flash_read_uchar (info,
1559 bankId | FLASH_OFFSET_MANUFACTURER_ID);
1560 }
1561 info->manufacturer_id = manuId;
Tor Krill90447ec2008-03-28 11:29:10 +01001562
1563 switch (info->chipwidth){
1564 case FLASH_CFI_8BIT:
1565 info->device_id = flash_read_uchar (info,
1566 FLASH_OFFSET_DEVICE_ID);
1567 if (info->device_id == 0x7E) {
1568 /* AMD 3-byte (expanded) device ids */
1569 info->device_id2 = flash_read_uchar (info,
1570 FLASH_OFFSET_DEVICE_ID2);
1571 info->device_id2 <<= 8;
1572 info->device_id2 |= flash_read_uchar (info,
1573 FLASH_OFFSET_DEVICE_ID3);
1574 }
1575 break;
1576 case FLASH_CFI_16BIT:
1577 info->device_id = flash_read_word (info,
1578 FLASH_OFFSET_DEVICE_ID);
1579 break;
1580 default:
1581 break;
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001582 }
1583 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1584}
1585
1586static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
1587{
1588 info->cmd_reset = AMD_CMD_RESET;
1589
1590 cmdset_amd_read_jedec_ids(info);
1591 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1592
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001593 return 0;
1594}
1595
1596#ifdef CONFIG_FLASH_CFI_LEGACY
Stefan Roese260421a2006-11-13 13:55:24 +01001597static void flash_read_jedec_ids (flash_info_t * info)
1598{
1599 info->manufacturer_id = 0;
1600 info->device_id = 0;
1601 info->device_id2 = 0;
1602
1603 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001604 case CFI_CMDSET_INTEL_PROG_REGIONS:
Stefan Roese260421a2006-11-13 13:55:24 +01001605 case CFI_CMDSET_INTEL_STANDARD:
1606 case CFI_CMDSET_INTEL_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001607 cmdset_intel_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001608 break;
1609 case CFI_CMDSET_AMD_STANDARD:
1610 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen8225d1e2008-01-12 20:29:47 +01001611 cmdset_amd_read_jedec_ids(info);
Stefan Roese260421a2006-11-13 13:55:24 +01001612 break;
1613 default:
1614 break;
1615 }
1616}
1617
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001618/*-----------------------------------------------------------------------
1619 * Call board code to request info about non-CFI flash.
1620 * board_flash_get_legacy needs to fill in at least:
1621 * info->portwidth, info->chipwidth and info->interface for Jedec probing.
1622 */
Becky Bruce09ce9922009-02-02 16:34:51 -06001623static int flash_detect_legacy(phys_addr_t base, int banknum)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001624{
1625 flash_info_t *info = &flash_info[banknum];
1626
1627 if (board_flash_get_legacy(base, banknum, info)) {
1628 /* board code may have filled info completely. If not, we
1629 use JEDEC ID probing. */
1630 if (!info->vendor) {
1631 int modes[] = {
1632 CFI_CMDSET_AMD_STANDARD,
1633 CFI_CMDSET_INTEL_STANDARD
1634 };
1635 int i;
1636
1637 for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1638 info->vendor = modes[i];
Becky Bruce09ce9922009-02-02 16:34:51 -06001639 info->start[0] =
1640 (ulong)map_physmem(base,
Stefan Roesee1fb6d02009-02-05 11:44:52 +01001641 info->portwidth,
Becky Bruce09ce9922009-02-02 16:34:51 -06001642 MAP_NOCACHE);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001643 if (info->portwidth == FLASH_CFI_8BIT
1644 && info->interface == FLASH_CFI_X8X16) {
1645 info->addr_unlock1 = 0x2AAA;
1646 info->addr_unlock2 = 0x5555;
1647 } else {
1648 info->addr_unlock1 = 0x5555;
1649 info->addr_unlock2 = 0x2AAA;
1650 }
1651 flash_read_jedec_ids(info);
1652 debug("JEDEC PROBE: ID %x %x %x\n",
1653 info->manufacturer_id,
1654 info->device_id,
1655 info->device_id2);
Becky Bruce09ce9922009-02-02 16:34:51 -06001656 if (jedec_flash_match(info, info->start[0]))
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001657 break;
Becky Bruce09ce9922009-02-02 16:34:51 -06001658 else
Stefan Roesee1fb6d02009-02-05 11:44:52 +01001659 unmap_physmem((void *)info->start[0],
Becky Bruce09ce9922009-02-02 16:34:51 -06001660 MAP_NOCACHE);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001661 }
1662 }
1663
1664 switch(info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001665 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001666 case CFI_CMDSET_INTEL_STANDARD:
1667 case CFI_CMDSET_INTEL_EXTENDED:
1668 info->cmd_reset = FLASH_CMD_RESET;
1669 break;
1670 case CFI_CMDSET_AMD_STANDARD:
1671 case CFI_CMDSET_AMD_EXTENDED:
1672 case CFI_CMDSET_AMD_LEGACY:
1673 info->cmd_reset = AMD_CMD_RESET;
1674 break;
1675 }
1676 info->flash_id = FLASH_MAN_CFI;
1677 return 1;
1678 }
1679 return 0; /* use CFI */
1680}
1681#else
Becky Bruce09ce9922009-02-02 16:34:51 -06001682static inline int flash_detect_legacy(phys_addr_t base, int banknum)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02001683{
1684 return 0; /* use CFI */
1685}
1686#endif
1687
Stefan Roese260421a2006-11-13 13:55:24 +01001688/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001689 * detect if flash is compatible with the Common Flash Interface (CFI)
1690 * http://www.jedec.org/download/search/jesd68.pdf
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001691 */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001692static void flash_read_cfi (flash_info_t *info, void *buf,
1693 unsigned int start, size_t len)
1694{
1695 u8 *p = buf;
1696 unsigned int i;
1697
1698 for (i = 0; i < len; i++)
1699 p[i] = flash_read_uchar(info, start + i);
1700}
1701
1702static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
wdenk5653fc32004-02-08 22:55:38 +00001703{
Wolfgang Denk92eb7292006-12-27 01:26:13 +01001704 int cfi_offset;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001705
Michael Schwingen1ba639d2008-02-18 23:16:35 +01001706 /* We do not yet know what kind of commandset to use, so we issue
1707 the reset command in both Intel and AMD variants, in the hope
1708 that AMD flash roms ignore the Intel command. */
1709 flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
1710 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
1711
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001712 for (cfi_offset=0;
1713 cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
1714 cfi_offset++) {
1715 flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
1716 FLASH_CMD_CFI);
1717 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1718 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1719 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001720 flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1721 sizeof(struct cfi_qry));
1722 info->interface = le16_to_cpu(qry->interface_desc);
1723
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001724 info->cfi_offset = flash_offset_cfi[cfi_offset];
1725 debug ("device interface is %d\n",
1726 info->interface);
1727 debug ("found port %d chip %d ",
1728 info->portwidth, info->chipwidth);
1729 debug ("port %d bits chip %d bits\n",
1730 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1731 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1732
1733 /* calculate command offsets as in the Linux driver */
1734 info->addr_unlock1 = 0x555;
1735 info->addr_unlock2 = 0x2aa;
1736
1737 /*
1738 * modify the unlock address if we are
1739 * in compatibility mode
1740 */
1741 if ( /* x8/x16 in x8 mode */
1742 ((info->chipwidth == FLASH_CFI_BY8) &&
1743 (info->interface == FLASH_CFI_X8X16)) ||
1744 /* x16/x32 in x16 mode */
1745 ((info->chipwidth == FLASH_CFI_BY16) &&
1746 (info->interface == FLASH_CFI_X16X32)))
1747 {
1748 info->addr_unlock1 = 0xaaa;
1749 info->addr_unlock2 = 0x555;
1750 }
1751
1752 info->name = "CFI conformant";
1753 return 1;
1754 }
1755 }
1756
1757 return 0;
1758}
1759
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001760static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001761{
wdenkbf9e3b32004-02-12 00:47:09 +00001762 debug ("flash detect cfi\n");
wdenk5653fc32004-02-08 22:55:38 +00001763
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001764 for (info->portwidth = CONFIG_SYS_FLASH_CFI_WIDTH;
wdenkbf9e3b32004-02-12 00:47:09 +00001765 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1766 for (info->chipwidth = FLASH_CFI_BY8;
1767 info->chipwidth <= info->portwidth;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001768 info->chipwidth <<= 1)
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001769 if (__flash_detect_cfi(info, qry))
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001770 return 1;
wdenk5653fc32004-02-08 22:55:38 +00001771 }
wdenkbf9e3b32004-02-12 00:47:09 +00001772 debug ("not found\n");
wdenk5653fc32004-02-08 22:55:38 +00001773 return 0;
1774}
wdenkbf9e3b32004-02-12 00:47:09 +00001775
wdenk5653fc32004-02-08 22:55:38 +00001776/*
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001777 * Manufacturer-specific quirks. Add workarounds for geometry
1778 * reversal, etc. here.
1779 */
1780static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1781{
1782 /* check if flash geometry needs reversal */
1783 if (qry->num_erase_regions > 1) {
1784 /* reverse geometry if top boot part */
1785 if (info->cfi_version < 0x3131) {
1786 /* CFI < 1.1, try to guess from device id */
1787 if ((info->device_id & 0x80) != 0)
1788 cfi_reverse_geometry(qry);
1789 } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1790 /* CFI >= 1.1, deduct from top/bottom flag */
1791 /* note: ext_addr is valid since cfi_version > 0 */
1792 cfi_reverse_geometry(qry);
1793 }
1794 }
1795}
1796
1797static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1798{
1799 int reverse_geometry = 0;
1800
1801 /* Check the "top boot" bit in the PRI */
1802 if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1803 reverse_geometry = 1;
1804
1805 /* AT49BV6416(T) list the erase regions in the wrong order.
1806 * However, the device ID is identical with the non-broken
Ulf Samuelssoncb82a532009-03-27 23:26:43 +01001807 * AT49BV642D they differ in the high byte.
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001808 */
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001809 if (info->device_id == 0xd6 || info->device_id == 0xd2)
1810 reverse_geometry = !reverse_geometry;
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001811
1812 if (reverse_geometry)
1813 cfi_reverse_geometry(qry);
1814}
1815
Richard Retanubune8eac432009-01-14 08:44:26 -05001816static void flash_fixup_stm(flash_info_t *info, struct cfi_qry *qry)
1817{
1818 /* check if flash geometry needs reversal */
1819 if (qry->num_erase_regions > 1) {
1820 /* reverse geometry if top boot part */
1821 if (info->cfi_version < 0x3131) {
Richard Retanubun7a886012009-03-06 10:09:37 -05001822 /* CFI < 1.1, guess by device id (M29W320{DT,ET} only) */
1823 if (info->device_id == 0x22CA ||
1824 info->device_id == 0x2256) {
Richard Retanubune8eac432009-01-14 08:44:26 -05001825 cfi_reverse_geometry(qry);
1826 }
1827 }
1828 }
1829}
1830
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001831/*
wdenk5653fc32004-02-08 22:55:38 +00001832 * The following code cannot be run from FLASH!
1833 *
1834 */
Becky Bruce09ce9922009-02-02 16:34:51 -06001835ulong flash_get_size (phys_addr_t base, int banknum)
wdenk5653fc32004-02-08 22:55:38 +00001836{
wdenkbf9e3b32004-02-12 00:47:09 +00001837 flash_info_t *info = &flash_info[banknum];
wdenk5653fc32004-02-08 22:55:38 +00001838 int i, j;
1839 flash_sect_t sect_cnt;
Becky Bruce09ce9922009-02-02 16:34:51 -06001840 phys_addr_t sector;
wdenk5653fc32004-02-08 22:55:38 +00001841 unsigned long tmp;
1842 int size_ratio;
1843 uchar num_erase_regions;
wdenkbf9e3b32004-02-12 00:47:09 +00001844 int erase_region_size;
1845 int erase_region_count;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001846 struct cfi_qry qry;
Stefan Roese260421a2006-11-13 13:55:24 +01001847
Kumar Galaf9796902008-05-15 15:13:08 -05001848 memset(&qry, 0, sizeof(qry));
1849
Stefan Roese260421a2006-11-13 13:55:24 +01001850 info->ext_addr = 0;
1851 info->cfi_version = 0;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001852#ifdef CONFIG_SYS_FLASH_PROTECTION
Stefan Roese2662b402006-04-01 13:41:03 +02001853 info->legacy_unlock = 0;
1854#endif
wdenk5653fc32004-02-08 22:55:38 +00001855
Becky Bruce09ce9922009-02-02 16:34:51 -06001856 info->start[0] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE);
wdenk5653fc32004-02-08 22:55:38 +00001857
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001858 if (flash_detect_cfi (info, &qry)) {
1859 info->vendor = le16_to_cpu(qry.p_id);
1860 info->ext_addr = le16_to_cpu(qry.p_adr);
1861 num_erase_regions = qry.num_erase_regions;
1862
Stefan Roese260421a2006-11-13 13:55:24 +01001863 if (info->ext_addr) {
1864 info->cfi_version = (ushort) flash_read_uchar (info,
1865 info->ext_addr + 3) << 8;
1866 info->cfi_version |= (ushort) flash_read_uchar (info,
1867 info->ext_addr + 4);
1868 }
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001869
wdenkbf9e3b32004-02-12 00:47:09 +00001870#ifdef DEBUG
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001871 flash_printqry (&qry);
wdenkbf9e3b32004-02-12 00:47:09 +00001872#endif
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001873
wdenkbf9e3b32004-02-12 00:47:09 +00001874 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001875 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk5653fc32004-02-08 22:55:38 +00001876 case CFI_CMDSET_INTEL_STANDARD:
1877 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001878 cmdset_intel_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001879 break;
1880 case CFI_CMDSET_AMD_STANDARD:
1881 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001882 cmdset_amd_init(info, &qry);
wdenk5653fc32004-02-08 22:55:38 +00001883 break;
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001884 default:
1885 printf("CFI: Unknown command set 0x%x\n",
1886 info->vendor);
1887 /*
1888 * Unfortunately, this means we don't know how
1889 * to get the chip back to Read mode. Might
1890 * as well try an Intel-style reset...
1891 */
1892 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1893 return 0;
wdenk5653fc32004-02-08 22:55:38 +00001894 }
wdenkcd37d9e2004-02-10 00:03:41 +00001895
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001896 /* Do manufacturer-specific fixups */
1897 switch (info->manufacturer_id) {
1898 case 0x0001:
1899 flash_fixup_amd(info, &qry);
1900 break;
1901 case 0x001f:
1902 flash_fixup_atmel(info, &qry);
1903 break;
Richard Retanubune8eac432009-01-14 08:44:26 -05001904 case 0x0020:
1905 flash_fixup_stm(info, &qry);
1906 break;
Haavard Skinnemoen467bcee2007-12-14 15:36:18 +01001907 }
1908
wdenkbf9e3b32004-02-12 00:47:09 +00001909 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese260421a2006-11-13 13:55:24 +01001910 debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
1911 debug ("device id is 0x%x\n", info->device_id);
1912 debug ("device id2 is 0x%x\n", info->device_id2);
1913 debug ("cfi version is 0x%04x\n", info->cfi_version);
1914
wdenk5653fc32004-02-08 22:55:38 +00001915 size_ratio = info->portwidth / info->chipwidth;
wdenkbf9e3b32004-02-12 00:47:09 +00001916 /* if the chip is x8/x16 reduce the ratio by half */
1917 if ((info->interface == FLASH_CFI_X8X16)
1918 && (info->chipwidth == FLASH_CFI_BY8)) {
1919 size_ratio >>= 1;
1920 }
wdenkbf9e3b32004-02-12 00:47:09 +00001921 debug ("size_ratio %d port %d bits chip %d bits\n",
1922 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1923 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1924 debug ("found %d erase regions\n", num_erase_regions);
wdenk5653fc32004-02-08 22:55:38 +00001925 sect_cnt = 0;
1926 sector = base;
wdenkbf9e3b32004-02-12 00:47:09 +00001927 for (i = 0; i < num_erase_regions; i++) {
1928 if (i > NUM_ERASE_REGIONS) {
wdenk028ab6b2004-02-23 23:54:43 +00001929 printf ("%d erase regions found, only %d used\n",
1930 num_erase_regions, NUM_ERASE_REGIONS);
wdenk5653fc32004-02-08 22:55:38 +00001931 break;
1932 }
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001933
Haavard Skinnemoen0ddf06d2007-12-14 15:36:17 +01001934 tmp = le32_to_cpu(qry.erase_region_info[i]);
1935 debug("erase region %u: 0x%08lx\n", i, tmp);
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001936
1937 erase_region_count = (tmp & 0xffff) + 1;
1938 tmp >>= 16;
wdenkbf9e3b32004-02-12 00:47:09 +00001939 erase_region_size =
1940 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenk4c0d4c32004-06-09 17:34:58 +00001941 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenk028ab6b2004-02-23 23:54:43 +00001942 erase_region_count, erase_region_size);
wdenkbf9e3b32004-02-12 00:47:09 +00001943 for (j = 0; j < erase_region_count; j++) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001944 if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
Michael Schwingen81b20cc2007-12-07 23:35:02 +01001945 printf("ERROR: too many flash sectors\n");
1946 break;
1947 }
Becky Bruce09ce9922009-02-02 16:34:51 -06001948 info->start[sect_cnt] =
1949 (ulong)map_physmem(sector,
1950 info->portwidth,
1951 MAP_NOCACHE);
wdenk5653fc32004-02-08 22:55:38 +00001952 sector += (erase_region_size * size_ratio);
wdenka1191902005-01-09 17:12:27 +00001953
1954 /*
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001955 * Only read protection status from
1956 * supported devices (intel...)
wdenka1191902005-01-09 17:12:27 +00001957 */
1958 switch (info->vendor) {
Vasiliy Leoenenko9c048b52008-05-07 21:25:33 +04001959 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenka1191902005-01-09 17:12:27 +00001960 case CFI_CMDSET_INTEL_EXTENDED:
1961 case CFI_CMDSET_INTEL_STANDARD:
1962 info->protect[sect_cnt] =
1963 flash_isset (info, sect_cnt,
1964 FLASH_OFFSET_PROTECT,
1965 FLASH_STATUS_PROTECT);
1966 break;
1967 default:
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001968 /* default: not protected */
1969 info->protect[sect_cnt] = 0;
wdenka1191902005-01-09 17:12:27 +00001970 }
1971
wdenk5653fc32004-02-08 22:55:38 +00001972 sect_cnt++;
1973 }
1974 }
1975
1976 info->sector_count = sect_cnt;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001977 info->size = 1 << qry.dev_size;
wdenk5653fc32004-02-08 22:55:38 +00001978 /* multiply the size by the number of chips */
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001979 info->size *= size_ratio;
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001980 info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1981 tmp = 1 << qry.block_erase_timeout_typ;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001982 info->erase_blk_tout = tmp *
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001983 (1 << qry.block_erase_timeout_max);
1984 tmp = (1 << qry.buf_write_timeout_typ) *
1985 (1 << qry.buf_write_timeout_max);
1986
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001987 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001988 info->buffer_write_tout = (tmp + 999) / 1000;
1989 tmp = (1 << qry.word_write_timeout_typ) *
1990 (1 << qry.word_write_timeout_max);
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001991 /* round up when converting to ms */
Haavard Skinnemoene23741f2007-12-14 15:36:16 +01001992 info->write_tout = (tmp + 999) / 1000;
wdenk5653fc32004-02-08 22:55:38 +00001993 info->flash_id = FLASH_MAN_CFI;
Haavard Skinnemoen7e5b9b42007-12-13 12:56:28 +01001994 if ((info->interface == FLASH_CFI_X8X16) &&
1995 (info->chipwidth == FLASH_CFI_BY8)) {
1996 /* XXX - Need to test on x8/x16 in parallel. */
1997 info->portwidth >>= 1;
wdenk855a4962004-03-14 18:23:55 +00001998 }
Mike Frysinger22159872008-10-02 01:55:38 -04001999
2000 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenk5653fc32004-02-08 22:55:38 +00002001 }
2002
wdenkbf9e3b32004-02-12 00:47:09 +00002003 return (info->size);
wdenk5653fc32004-02-08 22:55:38 +00002004}
2005
Piotr Ziecik6ea808e2008-11-17 15:49:32 +01002006void flash_set_verbose(uint v)
2007{
2008 flash_verbose = v;
2009}
2010
wdenk5653fc32004-02-08 22:55:38 +00002011/*-----------------------------------------------------------------------
2012 */
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002013unsigned long flash_init (void)
wdenk5653fc32004-02-08 22:55:38 +00002014{
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002015 unsigned long size = 0;
2016 int i;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002017#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
Matthias Fuchsc63ad632008-04-18 16:29:40 +02002018 struct apl_s {
2019 ulong start;
2020 ulong size;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002021 } apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST;
Matthias Fuchsc63ad632008-04-18 16:29:40 +02002022#endif
wdenk5653fc32004-02-08 22:55:38 +00002023
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002024#ifdef CONFIG_SYS_FLASH_PROTECTION
Eric Schumann3a3baf32009-03-21 09:59:34 -04002025 /* read environment from EEPROM */
2026 char s[64];
2027 getenv_r ("unlock", s, sizeof(s));
Michael Schwingen81b20cc2007-12-07 23:35:02 +01002028#endif
wdenk5653fc32004-02-08 22:55:38 +00002029
Becky Bruce09ce9922009-02-02 16:34:51 -06002030#define BANK_BASE(i) (((phys_addr_t [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i])
Wolfgang Denk2a112b22008-08-08 16:39:54 +02002031
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002032 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002033 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002034 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenk5653fc32004-02-08 22:55:38 +00002035
Wolfgang Denk2a112b22008-08-08 16:39:54 +02002036 if (!flash_detect_legacy (BANK_BASE(i), i))
2037 flash_get_size (BANK_BASE(i), i);
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002038 size += flash_info[i].size;
2039 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002040#ifndef CONFIG_SYS_FLASH_QUIET_TEST
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002041 printf ("## Unknown FLASH on Bank %d "
2042 "- Size = 0x%08lx = %ld MB\n",
2043 i+1, flash_info[i].size,
2044 flash_info[i].size << 20);
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002045#endif /* CONFIG_SYS_FLASH_QUIET_TEST */
wdenk5653fc32004-02-08 22:55:38 +00002046 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002047#ifdef CONFIG_SYS_FLASH_PROTECTION
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002048 else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
2049 /*
2050 * Only the U-Boot image and it's environment
2051 * is protected, all other sectors are
2052 * unprotected (unlocked) if flash hardware
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002053 * protection is used (CONFIG_SYS_FLASH_PROTECTION)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002054 * and the environment variable "unlock" is
2055 * set to "yes".
2056 */
2057 if (flash_info[i].legacy_unlock) {
2058 int k;
Stefan Roese79b4cda2006-02-28 15:29:58 +01002059
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002060 /*
2061 * Disable legacy_unlock temporarily,
2062 * since flash_real_protect would
2063 * relock all other sectors again
2064 * otherwise.
2065 */
2066 flash_info[i].legacy_unlock = 0;
Stefan Roese79b4cda2006-02-28 15:29:58 +01002067
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002068 /*
2069 * Legacy unlocking (e.g. Intel J3) ->
2070 * unlock only one sector. This will
2071 * unlock all sectors.
2072 */
2073 flash_real_protect (&flash_info[i], 0, 0);
Stefan Roese79b4cda2006-02-28 15:29:58 +01002074
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002075 flash_info[i].legacy_unlock = 1;
2076
2077 /*
2078 * Manually mark other sectors as
2079 * unlocked (unprotected)
2080 */
2081 for (k = 1; k < flash_info[i].sector_count; k++)
2082 flash_info[i].protect[k] = 0;
2083 } else {
2084 /*
2085 * No legancy unlocking -> unlock all sectors
2086 */
2087 flash_protect (FLAG_PROTECT_CLEAR,
2088 flash_info[i].start[0],
2089 flash_info[i].start[0]
2090 + flash_info[i].size - 1,
2091 &flash_info[i]);
2092 }
Stefan Roese79b4cda2006-02-28 15:29:58 +01002093 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002094#endif /* CONFIG_SYS_FLASH_PROTECTION */
wdenk5653fc32004-02-08 22:55:38 +00002095 }
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002096
2097 /* Monitor protection ON by default */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002098#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002099 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002100 CONFIG_SYS_MONITOR_BASE,
2101 CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
2102 flash_get_info(CONFIG_SYS_MONITOR_BASE));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002103#endif
2104
2105 /* Environment protection ON by default */
Jean-Christophe PLAGNIOL-VILLARD5a1aceb2008-09-10 22:48:04 +02002106#ifdef CONFIG_ENV_IS_IN_FLASH
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002107 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +02002108 CONFIG_ENV_ADDR,
2109 CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
2110 flash_get_info(CONFIG_ENV_ADDR));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002111#endif
2112
2113 /* Redundant environment protection ON by default */
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +02002114#ifdef CONFIG_ENV_ADDR_REDUND
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002115 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +02002116 CONFIG_ENV_ADDR_REDUND,
Wolfgang Denkdfcd7f22009-05-15 00:16:03 +02002117 CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +02002118 flash_get_info(CONFIG_ENV_ADDR_REDUND));
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002119#endif
Matthias Fuchsc63ad632008-04-18 16:29:40 +02002120
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02002121#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
Matthias Fuchsc63ad632008-04-18 16:29:40 +02002122 for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
2123 debug("autoprotecting from %08x to %08x\n",
2124 apl[i].start, apl[i].start + apl[i].size - 1);
2125 flash_protect (FLAG_PROTECT_SET,
2126 apl[i].start,
2127 apl[i].start + apl[i].size - 1,
2128 flash_get_info(apl[i].start));
2129 }
2130#endif
Piotr Ziecik91809ed2008-11-17 15:57:58 +01002131
2132#ifdef CONFIG_FLASH_CFI_MTD
2133 cfi_mtd_init();
2134#endif
2135
Haavard Skinnemoenbe60a902007-10-06 18:55:36 +02002136 return (size);
wdenk5653fc32004-02-08 22:55:38 +00002137}