blob: e8afe9985c8c5598763e9a863914ca9d92be4fcb [file] [log] [blame]
wdenk2cefd152004-02-08 22:55:38 +00001/*
wdenke65527f2004-02-12 00:47:09 +00002 * (C) Copyright 2002-2004
wdenk2cefd152004-02-08 22:55:38 +00003 * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com
4 *
5 * Copyright (C) 2003 Arabella Software Ltd.
6 * Yuli Barcohen <yuli@arabellasw.com>
wdenk2cefd152004-02-08 22:55:38 +00007 *
wdenke65527f2004-02-12 00:47:09 +00008 * Copyright (C) 2004
9 * Ed Okerson
Stefan Roese12797482006-11-13 13:55:24 +010010 *
11 * Copyright (C) 2006
12 * Tolunay Orkun <listmember@orkun.us>
wdenke65527f2004-02-12 00:47:09 +000013 *
wdenk2cefd152004-02-08 22:55:38 +000014 * See file CREDITS for list of people who contributed to this
15 * project.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30 * MA 02111-1307 USA
31 *
wdenk2cefd152004-02-08 22:55:38 +000032 */
33
34/* The DEBUG define must be before common to enable debugging */
wdenk2ebee312004-02-23 19:30:57 +000035/* #define DEBUG */
36
wdenk2cefd152004-02-08 22:55:38 +000037#include <common.h>
38#include <asm/processor.h>
Haiying Wangc123a382007-02-21 16:52:31 +010039#include <asm/io.h>
wdenkaeba06f2004-06-09 17:34:58 +000040#include <asm/byteorder.h>
wdenkd0245fc2005-04-13 10:02:42 +000041#include <environment.h>
wdenke537b3b2004-02-23 23:54:43 +000042
wdenk2cefd152004-02-08 22:55:38 +000043/*
Haavard Skinnemoend523e392007-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.
wdenk2cefd152004-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 Roese12797482006-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
wdenk2cefd152004-02-08 22:55:38 +000059 *
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020060 * Define CONFIG_SYS_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
Heiko Schocher800db312007-01-19 18:05:26 +010061 * reading and writing ... (yes there is such a Hardware).
wdenk2cefd152004-02-08 22:55:38 +000062 */
63
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020064#ifndef CONFIG_SYS_FLASH_BANKS_LIST
65#define CONFIG_SYS_FLASH_BANKS_LIST { CONFIG_SYS_FLASH_BASE }
wdenke65527f2004-02-12 00:47:09 +000066#endif
67
wdenk2cefd152004-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 Leoenenko7d1794c2008-05-07 21:25:33 +040078#define FLASH_CMD_READ_STATUS 0x70
wdenke65527f2004-02-12 00:47:09 +000079#define FLASH_CMD_WRITE_TO_BUFFER 0xE8
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +040080#define FLASH_CMD_WRITE_BUFFER_PROG 0xE9
wdenke65527f2004-02-12 00:47:09 +000081#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0
wdenk2cefd152004-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
wdenked2ac4b2004-03-14 18:23:55 +000097#define AMD_CMD_UNLOCK_START 0xAA
98#define AMD_CMD_UNLOCK_ACK 0x55
Stefan Roesec865e6c2006-02-28 15:29:58 +010099#define AMD_CMD_WRITE_TO_BUFFER 0x25
100#define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29
wdenk2cefd152004-02-08 22:55:38 +0000101
102#define AMD_STATUS_TOGGLE 0x40
103#define AMD_STATUS_ERROR 0x20
Stefan Roesec865e6c2006-02-28 15:29:58 +0100104
Rafael Campos13d2b612008-07-31 10:22:20 +0200105#define ATM_CMD_UNLOCK_SECT 0x70
106#define ATM_CMD_SOFTLOCK_START 0x80
107#define ATM_CMD_LOCK_SECT 0x40
108
Stefan Roese12797482006-11-13 13:55:24 +0100109#define FLASH_OFFSET_MANUFACTURER_ID 0x00
110#define FLASH_OFFSET_DEVICE_ID 0x01
111#define FLASH_OFFSET_DEVICE_ID2 0x0E
112#define FLASH_OFFSET_DEVICE_ID3 0x0F
wdenk2cefd152004-02-08 22:55:38 +0000113#define FLASH_OFFSET_CFI 0x55
Wolfgang Denkafa0dd02006-12-27 01:26:13 +0100114#define FLASH_OFFSET_CFI_ALT 0x555
wdenk2cefd152004-02-08 22:55:38 +0000115#define FLASH_OFFSET_CFI_RESP 0x10
wdenke65527f2004-02-12 00:47:09 +0000116#define FLASH_OFFSET_PRIMARY_VENDOR 0x13
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100117/* extended query table primary address */
118#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15
wdenk2cefd152004-02-08 22:55:38 +0000119#define FLASH_OFFSET_WTOUT 0x1F
wdenke65527f2004-02-12 00:47:09 +0000120#define FLASH_OFFSET_WBTOUT 0x20
wdenk2cefd152004-02-08 22:55:38 +0000121#define FLASH_OFFSET_ETOUT 0x21
wdenke65527f2004-02-12 00:47:09 +0000122#define FLASH_OFFSET_CETOUT 0x22
wdenk2cefd152004-02-08 22:55:38 +0000123#define FLASH_OFFSET_WMAX_TOUT 0x23
wdenke65527f2004-02-12 00:47:09 +0000124#define FLASH_OFFSET_WBMAX_TOUT 0x24
wdenk2cefd152004-02-08 22:55:38 +0000125#define FLASH_OFFSET_EMAX_TOUT 0x25
wdenke65527f2004-02-12 00:47:09 +0000126#define FLASH_OFFSET_CEMAX_TOUT 0x26
wdenk2cefd152004-02-08 22:55:38 +0000127#define FLASH_OFFSET_SIZE 0x27
wdenke65527f2004-02-12 00:47:09 +0000128#define FLASH_OFFSET_INTERFACE 0x28
129#define FLASH_OFFSET_BUFFER_SIZE 0x2A
wdenk2cefd152004-02-08 22:55:38 +0000130#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C
131#define FLASH_OFFSET_ERASE_REGIONS 0x2D
132#define FLASH_OFFSET_PROTECT 0x02
wdenke65527f2004-02-12 00:47:09 +0000133#define FLASH_OFFSET_USER_PROTECTION 0x85
134#define FLASH_OFFSET_INTEL_PROTECTION 0x81
wdenk2cefd152004-02-08 22:55:38 +0000135
Stefan Roese12797482006-11-13 13:55:24 +0100136#define CFI_CMDSET_NONE 0
137#define CFI_CMDSET_INTEL_EXTENDED 1
138#define CFI_CMDSET_AMD_STANDARD 2
139#define CFI_CMDSET_INTEL_STANDARD 3
140#define CFI_CMDSET_AMD_EXTENDED 4
141#define CFI_CMDSET_MITSU_STANDARD 256
142#define CFI_CMDSET_MITSU_EXTENDED 257
143#define CFI_CMDSET_SST 258
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400144#define CFI_CMDSET_INTEL_PROG_REGIONS 512
wdenk2cefd152004-02-08 22:55:38 +0000145
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200146#ifdef CONFIG_SYS_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
wdenk51242782004-12-18 22:35:43 +0000147# undef FLASH_CMD_RESET
Stefan Roese12797482006-11-13 13:55:24 +0100148# define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */
wdenk51242782004-12-18 22:35:43 +0000149#endif
150
wdenk2cefd152004-02-08 22:55:38 +0000151typedef union {
152 unsigned char c;
153 unsigned short w;
154 unsigned long l;
155 unsigned long long ll;
156} cfiword_t;
157
Stefan Roese12797482006-11-13 13:55:24 +0100158#define NUM_ERASE_REGIONS 4 /* max. number of erase regions */
wdenk2cefd152004-02-08 22:55:38 +0000159
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100160static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
Piotr Ziecik2a7493c2008-11-17 15:49:32 +0100161static uint flash_verbose = 1;
Wolfgang Denkafa0dd02006-12-27 01:26:13 +0100162
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200163/* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */
164#ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT
165# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS_DETECT
Marian Balakowicz513b4a12005-10-11 19:09:42 +0200166#else
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200167# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS
Marian Balakowicz513b4a12005-10-11 19:09:42 +0200168#endif
wdenk2cefd152004-02-08 22:55:38 +0000169
Wolfgang Denk9f5fb0f2008-08-08 16:39:54 +0200170flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */
171
Stefan Roesec865e6c2006-02-28 15:29:58 +0100172/*
173 * Check if chip width is defined. If not, start detecting with 8bit.
174 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200175#ifndef CONFIG_SYS_FLASH_CFI_WIDTH
176#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_8BIT
Stefan Roesec865e6c2006-02-28 15:29:58 +0100177#endif
178
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100179/* CFI standard query structure */
180struct cfi_qry {
181 u8 qry[3];
182 u16 p_id;
183 u16 p_adr;
184 u16 a_id;
185 u16 a_adr;
186 u8 vcc_min;
187 u8 vcc_max;
188 u8 vpp_min;
189 u8 vpp_max;
190 u8 word_write_timeout_typ;
191 u8 buf_write_timeout_typ;
192 u8 block_erase_timeout_typ;
193 u8 chip_erase_timeout_typ;
194 u8 word_write_timeout_max;
195 u8 buf_write_timeout_max;
196 u8 block_erase_timeout_max;
197 u8 chip_erase_timeout_max;
198 u8 dev_size;
199 u16 interface_desc;
200 u16 max_buf_write_size;
201 u8 num_erase_regions;
202 u32 erase_region_info[NUM_ERASE_REGIONS];
203} __attribute__((packed));
204
205struct cfi_pri_hdr {
206 u8 pri[3];
207 u8 major_version;
208 u8 minor_version;
209} __attribute__((packed));
210
Stefan Roese38ae9822008-11-17 14:45:22 +0100211static void __flash_write8(u8 value, void *addr)
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100212{
213 __raw_writeb(value, addr);
214}
215
Stefan Roese38ae9822008-11-17 14:45:22 +0100216static void __flash_write16(u16 value, void *addr)
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100217{
218 __raw_writew(value, addr);
219}
220
Stefan Roese38ae9822008-11-17 14:45:22 +0100221static void __flash_write32(u32 value, void *addr)
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100222{
223 __raw_writel(value, addr);
224}
225
Stefan Roese38ae9822008-11-17 14:45:22 +0100226static void __flash_write64(u64 value, void *addr)
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100227{
228 /* No architectures currently implement __raw_writeq() */
229 *(volatile u64 *)addr = value;
230}
231
Stefan Roese38ae9822008-11-17 14:45:22 +0100232static u8 __flash_read8(void *addr)
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100233{
234 return __raw_readb(addr);
235}
236
Stefan Roese38ae9822008-11-17 14:45:22 +0100237static u16 __flash_read16(void *addr)
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100238{
239 return __raw_readw(addr);
240}
241
Stefan Roese38ae9822008-11-17 14:45:22 +0100242static u32 __flash_read32(void *addr)
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100243{
244 return __raw_readl(addr);
245}
246
Daniel Hellstromcfd71382008-03-28 20:40:19 +0100247static u64 __flash_read64(void *addr)
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100248{
249 /* No architectures currently implement __raw_readq() */
250 return *(volatile u64 *)addr;
251}
252
Stefan Roese38ae9822008-11-17 14:45:22 +0100253#ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
254void flash_write8(u8 value, void *addr)__attribute__((weak, alias("__flash_write8")));
255void flash_write16(u16 value, void *addr)__attribute__((weak, alias("__flash_write16")));
256void flash_write32(u32 value, void *addr)__attribute__((weak, alias("__flash_write32")));
257void flash_write64(u64 value, void *addr)__attribute__((weak, alias("__flash_write64")));
258u8 flash_read8(void *addr)__attribute__((weak, alias("__flash_read8")));
259u16 flash_read16(void *addr)__attribute__((weak, alias("__flash_read16")));
260u32 flash_read32(void *addr)__attribute__((weak, alias("__flash_read32")));
Daniel Hellstromcfd71382008-03-28 20:40:19 +0100261u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
Stefan Roese38ae9822008-11-17 14:45:22 +0100262#else
263#define flash_write8 __flash_write8
264#define flash_write16 __flash_write16
265#define flash_write32 __flash_write32
266#define flash_write64 __flash_write64
267#define flash_read8 __flash_read8
268#define flash_read16 __flash_read16
269#define flash_read32 __flash_read32
270#define flash_read64 __flash_read64
271#endif
Daniel Hellstromcfd71382008-03-28 20:40:19 +0100272
wdenk2cefd152004-02-08 22:55:38 +0000273/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000274 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200275#if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200276static flash_info_t *flash_get_info(ulong base)
277{
278 int i;
279 flash_info_t * info = 0;
wdenk2cefd152004-02-08 22:55:38 +0000280
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200281 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200282 info = & flash_info[i];
283 if (info->size && info->start[0] <= base &&
284 base <= info->start[0] + info->size - 1)
285 break;
286 }
wdenk2cefd152004-02-08 22:55:38 +0000287
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200288 return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200289}
wdenk2cefd152004-02-08 22:55:38 +0000290#endif
291
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100292unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
293{
294 if (sect != (info->sector_count - 1))
295 return info->start[sect + 1] - info->start[sect];
296 else
297 return info->start[0] + info->size - info->start[sect];
298}
299
wdenke65527f2004-02-12 00:47:09 +0000300/*-----------------------------------------------------------------------
301 * create an address based on the offset and the port width
302 */
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100303static inline void *
304flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
wdenke65527f2004-02-12 00:47:09 +0000305{
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100306 unsigned int byte_offset = offset * info->portwidth;
307
308 return map_physmem(info->start[sect] + byte_offset,
309 flash_sector_size(info, sect) - byte_offset,
310 MAP_NOCACHE);
311}
312
313static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
314 unsigned int offset, void *addr)
315{
316 unsigned int byte_offset = offset * info->portwidth;
317
318 unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset);
wdenke65527f2004-02-12 00:47:09 +0000319}
320
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200321/*-----------------------------------------------------------------------
322 * make a proper sized command based on the port and chip widths
323 */
Sebastian Siewior7746ed82008-07-15 13:35:23 +0200324static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200325{
326 int i;
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400327 int cword_offset;
328 int cp_offset;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200329#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Sebastian Siewiord528cd62008-07-16 20:04:49 +0200330 u32 cmd_le = cpu_to_le32(cmd);
331#endif
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400332 uchar val;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200333 uchar *cp = (uchar *) cmdbuf;
334
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400335 for (i = info->portwidth; i > 0; i--){
336 cword_offset = (info->portwidth-i)%info->chipwidth;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200337#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400338 cp_offset = info->portwidth - i;
Sebastian Siewiord528cd62008-07-16 20:04:49 +0200339 val = *((uchar*)&cmd_le + cword_offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200340#else
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400341 cp_offset = i - 1;
Sebastian Siewior7746ed82008-07-15 13:35:23 +0200342 val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200343#endif
Sebastian Siewior7746ed82008-07-15 13:35:23 +0200344 cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400345 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200346}
347
wdenk2cefd152004-02-08 22:55:38 +0000348#ifdef DEBUG
wdenke65527f2004-02-12 00:47:09 +0000349/*-----------------------------------------------------------------------
350 * Debug support
351 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100352static void print_longlong (char *str, unsigned long long data)
wdenk2cefd152004-02-08 22:55:38 +0000353{
354 int i;
355 char *cp;
wdenke65527f2004-02-12 00:47:09 +0000356
357 cp = (unsigned char *) &data;
358 for (i = 0; i < 8; i++)
359 sprintf (&str[i * 2], "%2.2x", *cp++);
wdenk2cefd152004-02-08 22:55:38 +0000360}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200361
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100362static void flash_printqry (struct cfi_qry *qry)
wdenke65527f2004-02-12 00:47:09 +0000363{
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100364 u8 *p = (u8 *)qry;
wdenke65527f2004-02-12 00:47:09 +0000365 int x, y;
366
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100367 for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
368 debug("%02x : ", x);
369 for (y = 0; y < 16; y++)
370 debug("%2.2x ", p[x + y]);
371 debug(" ");
wdenke65527f2004-02-12 00:47:09 +0000372 for (y = 0; y < 16; y++) {
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100373 unsigned char c = p[x + y];
374 if (c >= 0x20 && c <= 0x7e)
375 debug("%c", c);
376 else
377 debug(".");
wdenke65527f2004-02-12 00:47:09 +0000378 }
Haavard Skinnemoen53baec72007-12-14 15:36:16 +0100379 debug("\n");
wdenke65527f2004-02-12 00:47:09 +0000380 }
381}
wdenk2cefd152004-02-08 22:55:38 +0000382#endif
383
384
385/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000386 * read a character at a port width address
387 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100388static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000389{
390 uchar *cp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100391 uchar retval;
wdenke65527f2004-02-12 00:47:09 +0000392
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100393 cp = flash_map (info, 0, offset);
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200394#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100395 retval = flash_read8(cp);
wdenke65527f2004-02-12 00:47:09 +0000396#else
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100397 retval = flash_read8(cp + info->portwidth - 1);
wdenke65527f2004-02-12 00:47:09 +0000398#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100399 flash_unmap (info, 0, offset, cp);
400 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000401}
402
403/*-----------------------------------------------------------------------
Tor Krill7f2a3052008-03-28 11:29:10 +0100404 * read a word at a port width address, assume 16bit bus
405 */
406static inline ushort flash_read_word (flash_info_t * info, uint offset)
407{
408 ushort *addr, retval;
409
410 addr = flash_map (info, 0, offset);
411 retval = flash_read16 (addr);
412 flash_unmap (info, 0, offset, addr);
413 return retval;
414}
415
416
417/*-----------------------------------------------------------------------
Stefan Roese12797482006-11-13 13:55:24 +0100418 * read a long word by picking the least significant byte of each maximum
wdenk2cefd152004-02-08 22:55:38 +0000419 * port size word. Swap for ppc format.
420 */
Haavard Skinnemoen670a3232007-12-13 12:56:29 +0100421static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
422 uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000423{
wdenke65527f2004-02-12 00:47:09 +0000424 uchar *addr;
425 ulong retval;
426
427#ifdef DEBUG
428 int x;
429#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100430 addr = flash_map (info, sect, offset);
wdenk2cefd152004-02-08 22:55:38 +0000431
wdenke65527f2004-02-12 00:47:09 +0000432#ifdef DEBUG
433 debug ("long addr is at %p info->portwidth = %d\n", addr,
434 info->portwidth);
435 for (x = 0; x < 4 * info->portwidth; x++) {
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100436 debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
wdenke65527f2004-02-12 00:47:09 +0000437 }
438#endif
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200439#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100440 retval = ((flash_read8(addr) << 16) |
441 (flash_read8(addr + info->portwidth) << 24) |
442 (flash_read8(addr + 2 * info->portwidth)) |
443 (flash_read8(addr + 3 * info->portwidth) << 8));
wdenke65527f2004-02-12 00:47:09 +0000444#else
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100445 retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
446 (flash_read8(addr + info->portwidth - 1) << 16) |
447 (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
448 (flash_read8(addr + 3 * info->portwidth - 1)));
wdenke65527f2004-02-12 00:47:09 +0000449#endif
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100450 flash_unmap(info, sect, offset, addr);
451
wdenke65527f2004-02-12 00:47:09 +0000452 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000453}
454
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200455/*
456 * Write a proper sized command to the correct address
Michael Schwingen73d044d2007-12-07 23:35:02 +0100457 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200458static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
Sebastian Siewior7746ed82008-07-15 13:35:23 +0200459 uint offset, u32 cmd)
Michael Schwingen73d044d2007-12-07 23:35:02 +0100460{
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100461
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100462 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200463 cfiword_t cword;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100464
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100465 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200466 flash_make_cmd (info, cmd, &cword);
467 switch (info->portwidth) {
468 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100469 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200470 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100471 flash_write8(cword.c, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200472 break;
473 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100474 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200475 cmd, cword.w,
476 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100477 flash_write16(cword.w, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200478 break;
479 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100480 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200481 cmd, cword.l,
482 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100483 flash_write32(cword.l, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200484 break;
485 case FLASH_CFI_64BIT:
486#ifdef DEBUG
487 {
488 char str[20];
Haavard Skinnemoend523e392007-12-13 12:56:28 +0100489
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200490 print_longlong (str, cword.ll);
491
492 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100493 addr, cmd, str,
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200494 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100495 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200496#endif
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100497 flash_write64(cword.ll, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200498 break;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100499 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200500
501 /* Ensure all the instructions are fully finished */
502 sync();
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100503
504 flash_unmap(info, sect, offset, addr);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100505}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200506
507static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
Michael Schwingen73d044d2007-12-07 23:35:02 +0100508{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200509 flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
510 flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
Michael Schwingen73d044d2007-12-07 23:35:02 +0100511}
Michael Schwingen73d044d2007-12-07 23:35:02 +0100512
513/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000514 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200515static int flash_isequal (flash_info_t * info, flash_sect_t sect,
516 uint offset, uchar cmd)
wdenk2cefd152004-02-08 22:55:38 +0000517{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100518 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200519 cfiword_t cword;
520 int retval;
wdenk2cefd152004-02-08 22:55:38 +0000521
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100522 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200523 flash_make_cmd (info, cmd, &cword);
Stefan Roeseefef95b2006-04-01 13:41:03 +0200524
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100525 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200526 switch (info->portwidth) {
527 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100528 debug ("is= %x %x\n", flash_read8(addr), cword.c);
529 retval = (flash_read8(addr) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200530 break;
531 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100532 debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
533 retval = (flash_read16(addr) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200534 break;
535 case FLASH_CFI_32BIT:
Andrew Klossner7ddfafc2008-08-21 07:12:26 -0700536 debug ("is= %8.8x %8.8lx\n", flash_read32(addr), cword.l);
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100537 retval = (flash_read32(addr) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200538 break;
539 case FLASH_CFI_64BIT:
540#ifdef DEBUG
541 {
542 char str1[20];
543 char str2[20];
Michael Schwingen73d044d2007-12-07 23:35:02 +0100544
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100545 print_longlong (str1, flash_read64(addr));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200546 print_longlong (str2, cword.ll);
547 debug ("is= %s %s\n", str1, str2);
wdenk2cefd152004-02-08 22:55:38 +0000548 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200549#endif
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100550 retval = (flash_read64(addr) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200551 break;
552 default:
553 retval = 0;
554 break;
555 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100556 flash_unmap(info, sect, offset, addr);
557
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200558 return retval;
559}
Stefan Roeseefef95b2006-04-01 13:41:03 +0200560
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200561/*-----------------------------------------------------------------------
562 */
563static int flash_isset (flash_info_t * info, flash_sect_t sect,
564 uint offset, uchar cmd)
565{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100566 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200567 cfiword_t cword;
568 int retval;
Stefan Roeseefef95b2006-04-01 13:41:03 +0200569
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100570 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200571 flash_make_cmd (info, cmd, &cword);
572 switch (info->portwidth) {
573 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100574 retval = ((flash_read8(addr) & cword.c) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200575 break;
576 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100577 retval = ((flash_read16(addr) & cword.w) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200578 break;
579 case FLASH_CFI_32BIT:
Stefan Roesed4e37c02008-01-02 14:05:37 +0100580 retval = ((flash_read32(addr) & cword.l) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200581 break;
582 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100583 retval = ((flash_read64(addr) & cword.ll) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200584 break;
585 default:
586 retval = 0;
587 break;
588 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100589 flash_unmap(info, sect, offset, addr);
590
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200591 return retval;
592}
Stefan Roeseefef95b2006-04-01 13:41:03 +0200593
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200594/*-----------------------------------------------------------------------
595 */
596static int flash_toggle (flash_info_t * info, flash_sect_t sect,
597 uint offset, uchar cmd)
598{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100599 void *addr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200600 cfiword_t cword;
601 int retval;
wdenke85b7a52004-10-10 22:16:06 +0000602
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100603 addr = flash_map (info, sect, offset);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200604 flash_make_cmd (info, cmd, &cword);
605 switch (info->portwidth) {
606 case FLASH_CFI_8BIT:
Stefan Roesecff2b492008-06-16 10:40:02 +0200607 retval = flash_read8(addr) != flash_read8(addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200608 break;
609 case FLASH_CFI_16BIT:
Stefan Roesecff2b492008-06-16 10:40:02 +0200610 retval = flash_read16(addr) != flash_read16(addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200611 break;
612 case FLASH_CFI_32BIT:
Stefan Roesecff2b492008-06-16 10:40:02 +0200613 retval = flash_read32(addr) != flash_read32(addr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200614 break;
615 case FLASH_CFI_64BIT:
Wolfgang Denk600e1832008-10-31 01:12:28 +0100616 retval = ( (flash_read32( addr ) != flash_read32( addr )) ||
617 (flash_read32(addr+4) != flash_read32(addr+4)) );
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200618 break;
619 default:
620 retval = 0;
621 break;
622 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100623 flash_unmap(info, sect, offset, addr);
624
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200625 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000626}
627
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200628/*
629 * flash_is_busy - check to see if the flash is busy
630 *
631 * This routine checks the status of the chip and returns true if the
632 * chip is busy.
wdenk2cefd152004-02-08 22:55:38 +0000633 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200634static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
wdenk5c71a7a2005-05-16 15:23:22 +0000635{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200636 int retval;
wdenk5c71a7a2005-05-16 15:23:22 +0000637
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200638 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400639 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200640 case CFI_CMDSET_INTEL_STANDARD:
641 case CFI_CMDSET_INTEL_EXTENDED:
642 retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
643 break;
644 case CFI_CMDSET_AMD_STANDARD:
645 case CFI_CMDSET_AMD_EXTENDED:
646#ifdef CONFIG_FLASH_CFI_LEGACY
647 case CFI_CMDSET_AMD_LEGACY:
648#endif
649 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
650 break;
651 default:
652 retval = 0;
wdenk5c71a7a2005-05-16 15:23:22 +0000653 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200654 debug ("flash_is_busy: %d\n", retval);
655 return retval;
wdenk5c71a7a2005-05-16 15:23:22 +0000656}
657
658/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200659 * wait for XSR.7 to be set. Time out with an error if it does not.
660 * This routine does not set the flash to read-array mode.
wdenk5c71a7a2005-05-16 15:23:22 +0000661 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200662static int flash_status_check (flash_info_t * info, flash_sect_t sector,
663 ulong tout, char *prompt)
wdenk2cefd152004-02-08 22:55:38 +0000664{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200665 ulong start;
wdenk2cefd152004-02-08 22:55:38 +0000666
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200667#if CONFIG_SYS_HZ != 1000
668 tout *= CONFIG_SYS_HZ/1000;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200669#endif
wdenk2cefd152004-02-08 22:55:38 +0000670
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200671 /* Wait for command completion */
672 start = get_timer (0);
673 while (flash_is_busy (info, sector)) {
674 if (get_timer (start) > tout) {
675 printf ("Flash %s timeout at address %lx data %lx\n",
676 prompt, info->start[sector],
677 flash_read_long (info, sector, 0));
678 flash_write_cmd (info, sector, 0, info->cmd_reset);
679 return ERR_TIMOUT;
wdenk2cefd152004-02-08 22:55:38 +0000680 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200681 udelay (1); /* also triggers watchdog */
wdenk2cefd152004-02-08 22:55:38 +0000682 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200683 return ERR_OK;
684}
wdenk2cefd152004-02-08 22:55:38 +0000685
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200686/*-----------------------------------------------------------------------
687 * Wait for XSR.7 to be set, if it times out print an error, otherwise
688 * do a full status check.
689 *
690 * This routine sets the flash to read-array mode.
691 */
692static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
693 ulong tout, char *prompt)
694{
695 int retcode;
wdenk2cefd152004-02-08 22:55:38 +0000696
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200697 retcode = flash_status_check (info, sector, tout, prompt);
698 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400699 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200700 case CFI_CMDSET_INTEL_EXTENDED:
701 case CFI_CMDSET_INTEL_STANDARD:
Ed Swarthout2da14102008-10-09 01:26:36 -0500702 if ((retcode != ERR_OK)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200703 && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
704 retcode = ERR_INVAL;
705 printf ("Flash %s error at address %lx\n", prompt,
706 info->start[sector]);
707 if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
708 FLASH_STATUS_PSLBS)) {
709 puts ("Command Sequence Error.\n");
710 } else if (flash_isset (info, sector, 0,
711 FLASH_STATUS_ECLBS)) {
712 puts ("Block Erase Error.\n");
713 retcode = ERR_NOT_ERASED;
714 } else if (flash_isset (info, sector, 0,
715 FLASH_STATUS_PSLBS)) {
716 puts ("Locking Error\n");
wdenk2cefd152004-02-08 22:55:38 +0000717 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200718 if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
719 puts ("Block locked.\n");
720 retcode = ERR_PROTECTED;
721 }
722 if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
723 puts ("Vpp Low Error.\n");
wdenk2cefd152004-02-08 22:55:38 +0000724 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200725 flash_write_cmd (info, sector, 0, info->cmd_reset);
726 break;
727 default:
728 break;
wdenk2cefd152004-02-08 22:55:38 +0000729 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200730 return retcode;
wdenk2cefd152004-02-08 22:55:38 +0000731}
732
733/*-----------------------------------------------------------------------
734 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200735static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
wdenk2cefd152004-02-08 22:55:38 +0000736{
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200737#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200738 unsigned short w;
739 unsigned int l;
740 unsigned long long ll;
741#endif
wdenk2cefd152004-02-08 22:55:38 +0000742
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200743 switch (info->portwidth) {
744 case FLASH_CFI_8BIT:
745 cword->c = c;
746 break;
747 case FLASH_CFI_16BIT:
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200748#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200749 w = c;
750 w <<= 8;
751 cword->w = (cword->w >> 8) | w;
752#else
753 cword->w = (cword->w << 8) | c;
Michael Schwingen73d044d2007-12-07 23:35:02 +0100754#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200755 break;
756 case FLASH_CFI_32BIT:
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200757#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200758 l = c;
759 l <<= 24;
760 cword->l = (cword->l >> 8) | l;
761#else
762 cword->l = (cword->l << 8) | c;
763#endif
764 break;
765 case FLASH_CFI_64BIT:
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200766#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200767 ll = c;
768 ll <<= 56;
769 cword->ll = (cword->ll >> 8) | ll;
770#else
771 cword->ll = (cword->ll << 8) | c;
772#endif
773 break;
Stefan Roese12797482006-11-13 13:55:24 +0100774 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200775}
wdenk2cefd152004-02-08 22:55:38 +0000776
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200777/* loop through the sectors from the highest address when the passed
778 * address is greater or equal to the sector address we have a match
779 */
780static flash_sect_t find_sector (flash_info_t * info, ulong addr)
781{
782 flash_sect_t sector;
wdenk2cefd152004-02-08 22:55:38 +0000783
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200784 for (sector = info->sector_count - 1; sector >= 0; sector--) {
785 if (addr >= info->start[sector])
786 break;
wdenk2cefd152004-02-08 22:55:38 +0000787 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200788 return sector;
wdenk2cefd152004-02-08 22:55:38 +0000789}
790
791/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000792 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200793static int flash_write_cfiword (flash_info_t * info, ulong dest,
794 cfiword_t cword)
wdenk2cefd152004-02-08 22:55:38 +0000795{
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100796 void *dstaddr;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200797 int flag;
Ed Swarthout2da14102008-10-09 01:26:36 -0500798 flash_sect_t sect;
wdenk2cefd152004-02-08 22:55:38 +0000799
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100800 dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
wdenk2cefd152004-02-08 22:55:38 +0000801
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200802 /* Check if Flash is (sufficiently) erased */
803 switch (info->portwidth) {
804 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100805 flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200806 break;
807 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100808 flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200809 break;
810 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100811 flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200812 break;
813 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100814 flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200815 break;
816 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100817 flag = 0;
818 break;
wdenk2cefd152004-02-08 22:55:38 +0000819 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100820 if (!flag) {
821 unmap_physmem(dstaddr, info->portwidth);
Stefan Roese707c1462007-12-27 07:50:54 +0100822 return ERR_NOT_ERASED;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100823 }
wdenk2cefd152004-02-08 22:55:38 +0000824
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200825 /* Disable interrupts which might cause a timeout here */
826 flag = disable_interrupts ();
Stefan Roesec865e6c2006-02-28 15:29:58 +0100827
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200828 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400829 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200830 case CFI_CMDSET_INTEL_EXTENDED:
831 case CFI_CMDSET_INTEL_STANDARD:
832 flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
833 flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
834 break;
835 case CFI_CMDSET_AMD_EXTENDED:
836 case CFI_CMDSET_AMD_STANDARD:
837#ifdef CONFIG_FLASH_CFI_LEGACY
838 case CFI_CMDSET_AMD_LEGACY:
839#endif
Ed Swarthout2da14102008-10-09 01:26:36 -0500840 sect = find_sector(info, dest);
841 flash_unlock_seq (info, sect);
842 flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200843 break;
wdenk2cefd152004-02-08 22:55:38 +0000844 }
845
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200846 switch (info->portwidth) {
847 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100848 flash_write8(cword.c, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200849 break;
850 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100851 flash_write16(cword.w, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200852 break;
853 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100854 flash_write32(cword.l, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200855 break;
856 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100857 flash_write64(cword.ll, dstaddr);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200858 break;
wdenk2cefd152004-02-08 22:55:38 +0000859 }
860
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200861 /* re-enable interrupts if necessary */
862 if (flag)
863 enable_interrupts ();
wdenk2cefd152004-02-08 22:55:38 +0000864
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100865 unmap_physmem(dstaddr, info->portwidth);
866
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200867 return flash_full_status_check (info, find_sector (info, dest),
868 info->write_tout, "write");
wdenk2cefd152004-02-08 22:55:38 +0000869}
870
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200871#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
wdenk2cefd152004-02-08 22:55:38 +0000872
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200873static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
874 int len)
wdenk2cefd152004-02-08 22:55:38 +0000875{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200876 flash_sect_t sector;
877 int cnt;
878 int retcode;
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100879 void *src = cp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100880 void *dst = map_physmem(dest, len, MAP_NOCACHE);
Stefan Roese707c1462007-12-27 07:50:54 +0100881 void *dst2 = dst;
882 int flag = 0;
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200883 uint offset = 0;
884 unsigned int shift;
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400885 uchar write_cmd;
Stefan Roese707c1462007-12-27 07:50:54 +0100886
887 switch (info->portwidth) {
888 case FLASH_CFI_8BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200889 shift = 0;
Stefan Roese707c1462007-12-27 07:50:54 +0100890 break;
891 case FLASH_CFI_16BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200892 shift = 1;
Stefan Roese707c1462007-12-27 07:50:54 +0100893 break;
894 case FLASH_CFI_32BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200895 shift = 2;
Stefan Roese707c1462007-12-27 07:50:54 +0100896 break;
897 case FLASH_CFI_64BIT:
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200898 shift = 3;
Stefan Roese707c1462007-12-27 07:50:54 +0100899 break;
900 default:
901 retcode = ERR_INVAL;
902 goto out_unmap;
903 }
904
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200905 cnt = len >> shift;
906
Stefan Roese707c1462007-12-27 07:50:54 +0100907 while ((cnt-- > 0) && (flag == 0)) {
908 switch (info->portwidth) {
909 case FLASH_CFI_8BIT:
910 flag = ((flash_read8(dst2) & flash_read8(src)) ==
911 flash_read8(src));
912 src += 1, dst2 += 1;
913 break;
914 case FLASH_CFI_16BIT:
915 flag = ((flash_read16(dst2) & flash_read16(src)) ==
916 flash_read16(src));
917 src += 2, dst2 += 2;
918 break;
919 case FLASH_CFI_32BIT:
920 flag = ((flash_read32(dst2) & flash_read32(src)) ==
921 flash_read32(src));
922 src += 4, dst2 += 4;
923 break;
924 case FLASH_CFI_64BIT:
925 flag = ((flash_read64(dst2) & flash_read64(src)) ==
926 flash_read64(src));
927 src += 8, dst2 += 8;
928 break;
929 }
930 }
931 if (!flag) {
932 retcode = ERR_NOT_ERASED;
933 goto out_unmap;
934 }
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100935
Stefan Roese707c1462007-12-27 07:50:54 +0100936 src = cp;
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100937 sector = find_sector (info, dest);
wdenke65527f2004-02-12 00:47:09 +0000938
939 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400940 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk2cefd152004-02-08 22:55:38 +0000941 case CFI_CMDSET_INTEL_STANDARD:
942 case CFI_CMDSET_INTEL_EXTENDED:
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400943 write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
944 FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200945 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +0400946 flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS);
947 flash_write_cmd (info, sector, 0, write_cmd);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200948 retcode = flash_status_check (info, sector,
949 info->buffer_write_tout,
950 "write to buffer");
951 if (retcode == ERR_OK) {
952 /* reduce the number of loops by the width of
953 * the port */
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200954 cnt = len >> shift;
Vasiliy Leoenenkoc47c0d42008-05-07 21:24:44 +0400955 flash_write_cmd (info, sector, 0, cnt - 1);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200956 while (cnt-- > 0) {
957 switch (info->portwidth) {
958 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100959 flash_write8(flash_read8(src), dst);
960 src += 1, dst += 1;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200961 break;
962 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100963 flash_write16(flash_read16(src), dst);
964 src += 2, dst += 2;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200965 break;
966 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100967 flash_write32(flash_read32(src), dst);
968 src += 4, dst += 4;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200969 break;
970 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +0100971 flash_write64(flash_read64(src), dst);
972 src += 8, dst += 8;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200973 break;
974 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100975 retcode = ERR_INVAL;
976 goto out_unmap;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200977 }
978 }
979 flash_write_cmd (info, sector, 0,
980 FLASH_CMD_WRITE_BUFFER_CONFIRM);
981 retcode = flash_full_status_check (
982 info, sector, info->buffer_write_tout,
983 "buffer write");
984 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +0100985
986 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200987
wdenk2cefd152004-02-08 22:55:38 +0000988 case CFI_CMDSET_AMD_STANDARD:
989 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200990 flash_unlock_seq(info,0);
Guennadi Liakhovetski183284f2008-04-03 13:36:02 +0200991
992#ifdef CONFIG_FLASH_SPANSION_S29WS_N
993 offset = ((unsigned long)dst - info->start[sector]) >> shift;
994#endif
995 flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
996 cnt = len >> shift;
997 flash_write_cmd(info, sector, offset, (uchar)cnt - 1);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +0200998
999 switch (info->portwidth) {
1000 case FLASH_CFI_8BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +01001001 while (cnt-- > 0) {
1002 flash_write8(flash_read8(src), dst);
1003 src += 1, dst += 1;
1004 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001005 break;
1006 case FLASH_CFI_16BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +01001007 while (cnt-- > 0) {
1008 flash_write16(flash_read16(src), dst);
1009 src += 2, dst += 2;
1010 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001011 break;
1012 case FLASH_CFI_32BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +01001013 while (cnt-- > 0) {
1014 flash_write32(flash_read32(src), dst);
1015 src += 4, dst += 4;
1016 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001017 break;
1018 case FLASH_CFI_64BIT:
Haavard Skinnemoen21b95b42007-12-13 12:56:32 +01001019 while (cnt-- > 0) {
1020 flash_write64(flash_read64(src), dst);
1021 src += 8, dst += 8;
1022 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001023 break;
1024 default:
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001025 retcode = ERR_INVAL;
1026 goto out_unmap;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001027 }
1028
1029 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1030 retcode = flash_full_status_check (info, sector,
1031 info->buffer_write_tout,
1032 "buffer write");
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001033 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001034
wdenk2cefd152004-02-08 22:55:38 +00001035 default:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001036 debug ("Unknown Command Set\n");
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001037 retcode = ERR_INVAL;
1038 break;
wdenk2cefd152004-02-08 22:55:38 +00001039 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001040
1041out_unmap:
1042 unmap_physmem(dst, len);
1043 return retcode;
wdenk2cefd152004-02-08 22:55:38 +00001044}
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001045#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001046
wdenke65527f2004-02-12 00:47:09 +00001047
wdenk2cefd152004-02-08 22:55:38 +00001048/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +00001049 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001050int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk2cefd152004-02-08 22:55:38 +00001051{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001052 int rcode = 0;
1053 int prot;
1054 flash_sect_t sect;
wdenk2cefd152004-02-08 22:55:38 +00001055
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001056 if (info->flash_id != FLASH_MAN_CFI) {
1057 puts ("Can't erase unknown flash type - aborted\n");
1058 return 1;
1059 }
1060 if ((s_first < 0) || (s_first > s_last)) {
1061 puts ("- no sectors to erase\n");
1062 return 1;
1063 }
Stefan Roeseefef95b2006-04-01 13:41:03 +02001064
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001065 prot = 0;
1066 for (sect = s_first; sect <= s_last; ++sect) {
1067 if (info->protect[sect]) {
1068 prot++;
wdenk2cefd152004-02-08 22:55:38 +00001069 }
1070 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001071 if (prot) {
1072 printf ("- Warning: %d protected sectors will not be erased!\n",
1073 prot);
Piotr Ziecik2a7493c2008-11-17 15:49:32 +01001074 } else if (flash_verbose) {
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001075 putc ('\n');
1076 }
wdenke65527f2004-02-12 00:47:09 +00001077
wdenke65527f2004-02-12 00:47:09 +00001078
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001079 for (sect = s_first; sect <= s_last; sect++) {
1080 if (info->protect[sect] == 0) { /* not protected */
1081 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001082 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001083 case CFI_CMDSET_INTEL_STANDARD:
1084 case CFI_CMDSET_INTEL_EXTENDED:
1085 flash_write_cmd (info, sect, 0,
1086 FLASH_CMD_CLEAR_STATUS);
1087 flash_write_cmd (info, sect, 0,
1088 FLASH_CMD_BLOCK_ERASE);
1089 flash_write_cmd (info, sect, 0,
1090 FLASH_CMD_ERASE_CONFIRM);
1091 break;
1092 case CFI_CMDSET_AMD_STANDARD:
1093 case CFI_CMDSET_AMD_EXTENDED:
1094 flash_unlock_seq (info, sect);
1095 flash_write_cmd (info, sect,
1096 info->addr_unlock1,
1097 AMD_CMD_ERASE_START);
1098 flash_unlock_seq (info, sect);
1099 flash_write_cmd (info, sect, 0,
1100 AMD_CMD_ERASE_SECTOR);
1101 break;
1102#ifdef CONFIG_FLASH_CFI_LEGACY
1103 case CFI_CMDSET_AMD_LEGACY:
1104 flash_unlock_seq (info, 0);
1105 flash_write_cmd (info, 0, info->addr_unlock1,
1106 AMD_CMD_ERASE_START);
1107 flash_unlock_seq (info, 0);
1108 flash_write_cmd (info, sect, 0,
1109 AMD_CMD_ERASE_SECTOR);
1110 break;
1111#endif
1112 default:
1113 debug ("Unkown flash vendor %d\n",
1114 info->vendor);
1115 break;
wdenke65527f2004-02-12 00:47:09 +00001116 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001117
1118 if (flash_full_status_check
1119 (info, sect, info->erase_blk_tout, "erase")) {
1120 rcode = 1;
Piotr Ziecik2a7493c2008-11-17 15:49:32 +01001121 } else if (flash_verbose)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001122 putc ('.');
wdenk2cefd152004-02-08 22:55:38 +00001123 }
wdenk2cefd152004-02-08 22:55:38 +00001124 }
Piotr Ziecik2a7493c2008-11-17 15:49:32 +01001125
1126 if (flash_verbose)
1127 puts (" done\n");
1128
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001129 return rcode;
wdenk2cefd152004-02-08 22:55:38 +00001130}
wdenke65527f2004-02-12 00:47:09 +00001131
wdenk2cefd152004-02-08 22:55:38 +00001132/*-----------------------------------------------------------------------
1133 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001134void flash_print_info (flash_info_t * info)
wdenk2cefd152004-02-08 22:55:38 +00001135{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001136 int i;
wdenk369d43d2004-03-14 14:09:05 +00001137
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001138 if (info->flash_id != FLASH_MAN_CFI) {
1139 puts ("missing or unknown FLASH type\n");
1140 return;
1141 }
1142
1143 printf ("%s FLASH (%d x %d)",
1144 info->name,
1145 (info->portwidth << 3), (info->chipwidth << 3));
1146 if (info->size < 1024*1024)
1147 printf (" Size: %ld kB in %d Sectors\n",
1148 info->size >> 10, info->sector_count);
1149 else
1150 printf (" Size: %ld MB in %d Sectors\n",
1151 info->size >> 20, info->sector_count);
1152 printf (" ");
1153 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001154 case CFI_CMDSET_INTEL_PROG_REGIONS:
1155 printf ("Intel Prog Regions");
1156 break;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001157 case CFI_CMDSET_INTEL_STANDARD:
1158 printf ("Intel Standard");
1159 break;
1160 case CFI_CMDSET_INTEL_EXTENDED:
1161 printf ("Intel Extended");
1162 break;
1163 case CFI_CMDSET_AMD_STANDARD:
1164 printf ("AMD Standard");
1165 break;
1166 case CFI_CMDSET_AMD_EXTENDED:
1167 printf ("AMD Extended");
1168 break;
1169#ifdef CONFIG_FLASH_CFI_LEGACY
1170 case CFI_CMDSET_AMD_LEGACY:
1171 printf ("AMD Legacy");
1172 break;
wdenk369d43d2004-03-14 14:09:05 +00001173#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001174 default:
1175 printf ("Unknown (%d)", info->vendor);
1176 break;
wdenk2cefd152004-02-08 22:55:38 +00001177 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001178 printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
1179 info->manufacturer_id, info->device_id);
1180 if (info->device_id == 0x7E) {
1181 printf("%04X", info->device_id2);
1182 }
1183 printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n",
1184 info->erase_blk_tout,
1185 info->write_tout);
1186 if (info->buffer_size > 1) {
1187 printf (" Buffer write timeout: %ld ms, "
1188 "buffer size: %d bytes\n",
1189 info->buffer_write_tout,
1190 info->buffer_size);
1191 }
wdenk2cefd152004-02-08 22:55:38 +00001192
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001193 puts ("\n Sector Start Addresses:");
1194 for (i = 0; i < info->sector_count; ++i) {
1195 if ((i % 5) == 0)
1196 printf ("\n");
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001197#ifdef CONFIG_SYS_FLASH_EMPTY_INFO
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001198 int k;
1199 int size;
1200 int erased;
1201 volatile unsigned long *flash;
wdenk2cefd152004-02-08 22:55:38 +00001202
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001203 /*
1204 * Check if whole sector is erased
1205 */
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001206 size = flash_sector_size(info, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001207 erased = 1;
1208 flash = (volatile unsigned long *) info->start[i];
1209 size = size >> 2; /* divide by 4 for longword access */
1210 for (k = 0; k < size; k++) {
1211 if (*flash++ != 0xffffffff) {
1212 erased = 0;
1213 break;
1214 }
1215 }
wdenke65527f2004-02-12 00:47:09 +00001216
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001217 /* print empty and read-only info */
1218 printf (" %08lX %c %s ",
1219 info->start[i],
1220 erased ? 'E' : ' ',
1221 info->protect[i] ? "RO" : " ");
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001222#else /* ! CONFIG_SYS_FLASH_EMPTY_INFO */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001223 printf (" %08lX %s ",
1224 info->start[i],
1225 info->protect[i] ? "RO" : " ");
wdenke65527f2004-02-12 00:47:09 +00001226#endif
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001227 }
1228 putc ('\n');
1229 return;
wdenk2cefd152004-02-08 22:55:38 +00001230}
1231
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001232/*-----------------------------------------------------------------------
Jerry Van Barenaae73572008-03-08 13:48:01 -05001233 * This is used in a few places in write_buf() to show programming
1234 * progress. Making it a function is nasty because it needs to do side
1235 * effect updates to digit and dots. Repeated code is nasty too, so
1236 * we define it once here.
1237 */
Stefan Roese7758c162008-03-19 07:09:26 +01001238#ifdef CONFIG_FLASH_SHOW_PROGRESS
1239#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
Piotr Ziecik2a7493c2008-11-17 15:49:32 +01001240 if (flash_verbose) { \
1241 dots -= dots_sub; \
1242 if ((scale > 0) && (dots <= 0)) { \
1243 if ((digit % 5) == 0) \
1244 printf ("%d", digit / 5); \
1245 else \
1246 putc ('.'); \
1247 digit--; \
1248 dots += scale; \
1249 } \
Jerry Van Barenaae73572008-03-08 13:48:01 -05001250 }
Stefan Roese7758c162008-03-19 07:09:26 +01001251#else
1252#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
1253#endif
Jerry Van Barenaae73572008-03-08 13:48:01 -05001254
1255/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001256 * Copy memory to flash, returns:
1257 * 0 - OK
1258 * 1 - write timeout
1259 * 2 - Flash not erased
wdenk2cefd152004-02-08 22:55:38 +00001260 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001261int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk2cefd152004-02-08 22:55:38 +00001262{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001263 ulong wp;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001264 uchar *p;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001265 int aln;
wdenk2cefd152004-02-08 22:55:38 +00001266 cfiword_t cword;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001267 int i, rc;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001268#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001269 int buffered_size;
wdenk2cefd152004-02-08 22:55:38 +00001270#endif
Jerry Van Barenaae73572008-03-08 13:48:01 -05001271#ifdef CONFIG_FLASH_SHOW_PROGRESS
1272 int digit = CONFIG_FLASH_SHOW_PROGRESS;
1273 int scale = 0;
1274 int dots = 0;
1275
1276 /*
1277 * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.
1278 */
1279 if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {
1280 scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /
1281 CONFIG_FLASH_SHOW_PROGRESS);
1282 }
1283#endif
1284
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001285 /* get lower aligned address */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001286 wp = (addr & ~(info->portwidth - 1));
Haiying Wangc123a382007-02-21 16:52:31 +01001287
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001288 /* handle unaligned start */
1289 if ((aln = addr - wp) != 0) {
1290 cword.l = 0;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001291 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1292 for (i = 0; i < aln; ++i)
1293 flash_add_byte (info, &cword, flash_read8(p + i));
wdenk2cefd152004-02-08 22:55:38 +00001294
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001295 for (; (i < info->portwidth) && (cnt > 0); i++) {
1296 flash_add_byte (info, &cword, *src++);
1297 cnt--;
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001298 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001299 for (; (cnt == 0) && (i < info->portwidth); ++i)
1300 flash_add_byte (info, &cword, flash_read8(p + i));
1301
1302 rc = flash_write_cfiword (info, wp, cword);
1303 unmap_physmem(p, info->portwidth);
1304 if (rc != 0)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001305 return rc;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001306
1307 wp += i;
Stefan Roese7758c162008-03-19 07:09:26 +01001308 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001309 }
1310
1311 /* handle the aligned part */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001312#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001313 buffered_size = (info->portwidth / info->chipwidth);
1314 buffered_size *= info->buffer_size;
1315 while (cnt >= info->portwidth) {
1316 /* prohibit buffer write when buffer_size is 1 */
1317 if (info->buffer_size == 1) {
1318 cword.l = 0;
1319 for (i = 0; i < info->portwidth; i++)
1320 flash_add_byte (info, &cword, *src++);
1321 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1322 return rc;
1323 wp += info->portwidth;
1324 cnt -= info->portwidth;
1325 continue;
1326 }
1327
1328 /* write buffer until next buffered_size aligned boundary */
1329 i = buffered_size - (wp % buffered_size);
1330 if (i > cnt)
1331 i = cnt;
1332 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
1333 return rc;
1334 i -= i & (info->portwidth - 1);
1335 wp += i;
1336 src += i;
1337 cnt -= i;
Stefan Roese7758c162008-03-19 07:09:26 +01001338 FLASH_SHOW_PROGRESS(scale, dots, digit, i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001339 }
1340#else
1341 while (cnt >= info->portwidth) {
1342 cword.l = 0;
1343 for (i = 0; i < info->portwidth; i++) {
1344 flash_add_byte (info, &cword, *src++);
1345 }
1346 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
1347 return rc;
1348 wp += info->portwidth;
1349 cnt -= info->portwidth;
Stefan Roese7758c162008-03-19 07:09:26 +01001350 FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001351 }
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001352#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
Jerry Van Barenaae73572008-03-08 13:48:01 -05001353
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001354 if (cnt == 0) {
1355 return (0);
1356 }
1357
1358 /*
1359 * handle unaligned tail bytes
1360 */
1361 cword.l = 0;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001362 p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
1363 for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001364 flash_add_byte (info, &cword, *src++);
1365 --cnt;
1366 }
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001367 for (; i < info->portwidth; ++i)
1368 flash_add_byte (info, &cword, flash_read8(p + i));
1369 unmap_physmem(p, info->portwidth);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001370
1371 return flash_write_cfiword (info, wp, cword);
wdenk2cefd152004-02-08 22:55:38 +00001372}
wdenke65527f2004-02-12 00:47:09 +00001373
wdenk2cefd152004-02-08 22:55:38 +00001374/*-----------------------------------------------------------------------
1375 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001376#ifdef CONFIG_SYS_FLASH_PROTECTION
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001377
1378int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk2cefd152004-02-08 22:55:38 +00001379{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001380 int retcode = 0;
wdenke65527f2004-02-12 00:47:09 +00001381
Rafael Campos13d2b612008-07-31 10:22:20 +02001382 switch (info->vendor) {
1383 case CFI_CMDSET_INTEL_PROG_REGIONS:
1384 case CFI_CMDSET_INTEL_STANDARD:
Nick Spenceec81b472008-08-19 22:21:16 -07001385 case CFI_CMDSET_INTEL_EXTENDED:
Rafael Campos13d2b612008-07-31 10:22:20 +02001386 flash_write_cmd (info, sector, 0,
1387 FLASH_CMD_CLEAR_STATUS);
1388 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1389 if (prot)
1390 flash_write_cmd (info, sector, 0,
1391 FLASH_CMD_PROTECT_SET);
1392 else
1393 flash_write_cmd (info, sector, 0,
1394 FLASH_CMD_PROTECT_CLEAR);
1395 break;
1396 case CFI_CMDSET_AMD_EXTENDED:
1397 case CFI_CMDSET_AMD_STANDARD:
Rafael Campos13d2b612008-07-31 10:22:20 +02001398 /* U-Boot only checks the first byte */
1399 if (info->manufacturer_id == (uchar)ATM_MANUFACT) {
1400 if (prot) {
1401 flash_unlock_seq (info, 0);
1402 flash_write_cmd (info, 0,
1403 info->addr_unlock1,
1404 ATM_CMD_SOFTLOCK_START);
1405 flash_unlock_seq (info, 0);
1406 flash_write_cmd (info, sector, 0,
1407 ATM_CMD_LOCK_SECT);
1408 } else {
1409 flash_write_cmd (info, 0,
1410 info->addr_unlock1,
1411 AMD_CMD_UNLOCK_START);
1412 if (info->device_id == ATM_ID_BV6416)
1413 flash_write_cmd (info, sector,
1414 0, ATM_CMD_UNLOCK_SECT);
1415 }
1416 }
1417 break;
TsiChung Liewb8c19292008-08-19 16:53:39 +00001418#ifdef CONFIG_FLASH_CFI_LEGACY
1419 case CFI_CMDSET_AMD_LEGACY:
1420 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1421 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
1422 if (prot)
1423 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
1424 else
1425 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
1426#endif
Rafael Campos13d2b612008-07-31 10:22:20 +02001427 };
wdenk2cefd152004-02-08 22:55:38 +00001428
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001429 if ((retcode =
1430 flash_full_status_check (info, sector, info->erase_blk_tout,
1431 prot ? "protect" : "unprotect")) == 0) {
wdenke65527f2004-02-12 00:47:09 +00001432
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001433 info->protect[sector] = prot;
1434
1435 /*
1436 * On some of Intel's flash chips (marked via legacy_unlock)
1437 * unprotect unprotects all locking.
1438 */
1439 if ((prot == 0) && (info->legacy_unlock)) {
1440 flash_sect_t i;
1441
1442 for (i = 0; i < info->sector_count; i++) {
1443 if (info->protect[i])
1444 flash_real_protect (info, i, 1);
1445 }
wdenk2cefd152004-02-08 22:55:38 +00001446 }
wdenk2cefd152004-02-08 22:55:38 +00001447 }
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001448 return retcode;
wdenk2cefd152004-02-08 22:55:38 +00001449}
wdenke65527f2004-02-12 00:47:09 +00001450
wdenk2cefd152004-02-08 22:55:38 +00001451/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001452 * flash_read_user_serial - read the OneTimeProgramming cells
wdenk2cefd152004-02-08 22:55:38 +00001453 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001454void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
1455 int len)
wdenk2cefd152004-02-08 22:55:38 +00001456{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001457 uchar *src;
1458 uchar *dst;
wdenke65527f2004-02-12 00:47:09 +00001459
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001460 dst = buffer;
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001461 src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001462 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1463 memcpy (dst, src + offset, len);
1464 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001465 flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
wdenk2cefd152004-02-08 22:55:38 +00001466}
1467
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001468/*
1469 * flash_read_factory_serial - read the device Id from the protection area
wdenk2cefd152004-02-08 22:55:38 +00001470 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001471void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
1472 int len)
wdenk2cefd152004-02-08 22:55:38 +00001473{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001474 uchar *src;
wdenke65527f2004-02-12 00:47:09 +00001475
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001476 src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001477 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
1478 memcpy (buffer, src + offset, len);
1479 flash_write_cmd (info, 0, 0, info->cmd_reset);
Haavard Skinnemoene3ea1882007-12-13 12:56:34 +01001480 flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
wdenk2cefd152004-02-08 22:55:38 +00001481}
1482
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001483#endif /* CONFIG_SYS_FLASH_PROTECTION */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001484
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001485/*-----------------------------------------------------------------------
1486 * Reverse the order of the erase regions in the CFI QRY structure.
1487 * This is needed for chips that are either a) correctly detected as
1488 * top-boot, or b) buggy.
1489 */
1490static void cfi_reverse_geometry(struct cfi_qry *qry)
1491{
1492 unsigned int i, j;
1493 u32 tmp;
1494
1495 for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
1496 tmp = qry->erase_region_info[i];
1497 qry->erase_region_info[i] = qry->erase_region_info[j];
1498 qry->erase_region_info[j] = tmp;
1499 }
1500}
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001501
wdenk2cefd152004-02-08 22:55:38 +00001502/*-----------------------------------------------------------------------
Stefan Roese12797482006-11-13 13:55:24 +01001503 * read jedec ids from device and set corresponding fields in info struct
1504 *
1505 * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1506 *
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001507 */
1508static void cmdset_intel_read_jedec_ids(flash_info_t *info)
1509{
1510 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1511 flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1512 udelay(1000); /* some flash are slow to respond */
1513 info->manufacturer_id = flash_read_uchar (info,
1514 FLASH_OFFSET_MANUFACTURER_ID);
1515 info->device_id = flash_read_uchar (info,
1516 FLASH_OFFSET_DEVICE_ID);
1517 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1518}
1519
1520static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
1521{
1522 info->cmd_reset = FLASH_CMD_RESET;
1523
1524 cmdset_intel_read_jedec_ids(info);
1525 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1526
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001527#ifdef CONFIG_SYS_FLASH_PROTECTION
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001528 /* read legacy lock/unlock bit from intel flash */
1529 if (info->ext_addr) {
1530 info->legacy_unlock = flash_read_uchar (info,
1531 info->ext_addr + 5) & 0x08;
1532 }
1533#endif
1534
1535 return 0;
1536}
1537
1538static void cmdset_amd_read_jedec_ids(flash_info_t *info)
1539{
1540 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1541 flash_unlock_seq(info, 0);
1542 flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
1543 udelay(1000); /* some flash are slow to respond */
Tor Krill7f2a3052008-03-28 11:29:10 +01001544
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001545 info->manufacturer_id = flash_read_uchar (info,
1546 FLASH_OFFSET_MANUFACTURER_ID);
Tor Krill7f2a3052008-03-28 11:29:10 +01001547
1548 switch (info->chipwidth){
1549 case FLASH_CFI_8BIT:
1550 info->device_id = flash_read_uchar (info,
1551 FLASH_OFFSET_DEVICE_ID);
1552 if (info->device_id == 0x7E) {
1553 /* AMD 3-byte (expanded) device ids */
1554 info->device_id2 = flash_read_uchar (info,
1555 FLASH_OFFSET_DEVICE_ID2);
1556 info->device_id2 <<= 8;
1557 info->device_id2 |= flash_read_uchar (info,
1558 FLASH_OFFSET_DEVICE_ID3);
1559 }
1560 break;
1561 case FLASH_CFI_16BIT:
1562 info->device_id = flash_read_word (info,
1563 FLASH_OFFSET_DEVICE_ID);
1564 break;
1565 default:
1566 break;
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001567 }
1568 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1569}
1570
1571static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
1572{
1573 info->cmd_reset = AMD_CMD_RESET;
1574
1575 cmdset_amd_read_jedec_ids(info);
1576 flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
1577
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001578 return 0;
1579}
1580
1581#ifdef CONFIG_FLASH_CFI_LEGACY
Stefan Roese12797482006-11-13 13:55:24 +01001582static void flash_read_jedec_ids (flash_info_t * info)
1583{
1584 info->manufacturer_id = 0;
1585 info->device_id = 0;
1586 info->device_id2 = 0;
1587
1588 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001589 case CFI_CMDSET_INTEL_PROG_REGIONS:
Stefan Roese12797482006-11-13 13:55:24 +01001590 case CFI_CMDSET_INTEL_STANDARD:
1591 case CFI_CMDSET_INTEL_EXTENDED:
Michael Schwingen5fb0aa42008-01-12 20:29:47 +01001592 cmdset_intel_read_jedec_ids(info);
Stefan Roese12797482006-11-13 13:55:24 +01001593 break;
1594 case CFI_CMDSET_AMD_STANDARD:
1595 case CFI_CMDSET_AMD_EXTENDED:
Michael Schwingen5fb0aa42008-01-12 20:29:47 +01001596 cmdset_amd_read_jedec_ids(info);
Stefan Roese12797482006-11-13 13:55:24 +01001597 break;
1598 default:
1599 break;
1600 }
1601}
1602
1603/*-----------------------------------------------------------------------
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001604 * Call board code to request info about non-CFI flash.
1605 * board_flash_get_legacy needs to fill in at least:
1606 * info->portwidth, info->chipwidth and info->interface for Jedec probing.
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001607 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001608static int flash_detect_legacy(ulong base, int banknum)
wdenk2cefd152004-02-08 22:55:38 +00001609{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001610 flash_info_t *info = &flash_info[banknum];
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001611
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001612 if (board_flash_get_legacy(base, banknum, info)) {
1613 /* board code may have filled info completely. If not, we
1614 use JEDEC ID probing. */
1615 if (!info->vendor) {
1616 int modes[] = {
1617 CFI_CMDSET_AMD_STANDARD,
1618 CFI_CMDSET_INTEL_STANDARD
1619 };
1620 int i;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001621
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001622 for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
1623 info->vendor = modes[i];
1624 info->start[0] = base;
1625 if (info->portwidth == FLASH_CFI_8BIT
1626 && info->interface == FLASH_CFI_X8X16) {
1627 info->addr_unlock1 = 0x2AAA;
1628 info->addr_unlock2 = 0x5555;
1629 } else {
1630 info->addr_unlock1 = 0x5555;
1631 info->addr_unlock2 = 0x2AAA;
1632 }
1633 flash_read_jedec_ids(info);
1634 debug("JEDEC PROBE: ID %x %x %x\n",
1635 info->manufacturer_id,
1636 info->device_id,
1637 info->device_id2);
1638 if (jedec_flash_match(info, base))
1639 break;
1640 }
1641 }
1642
1643 switch(info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001644 case CFI_CMDSET_INTEL_PROG_REGIONS:
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001645 case CFI_CMDSET_INTEL_STANDARD:
1646 case CFI_CMDSET_INTEL_EXTENDED:
1647 info->cmd_reset = FLASH_CMD_RESET;
1648 break;
1649 case CFI_CMDSET_AMD_STANDARD:
1650 case CFI_CMDSET_AMD_EXTENDED:
1651 case CFI_CMDSET_AMD_LEGACY:
1652 info->cmd_reset = AMD_CMD_RESET;
1653 break;
1654 }
1655 info->flash_id = FLASH_MAN_CFI;
1656 return 1;
1657 }
1658 return 0; /* use CFI */
1659}
1660#else
1661static inline int flash_detect_legacy(ulong base, int banknum)
1662{
1663 return 0; /* use CFI */
1664}
1665#endif
1666
1667/*-----------------------------------------------------------------------
1668 * detect if flash is compatible with the Common Flash Interface (CFI)
1669 * http://www.jedec.org/download/search/jesd68.pdf
1670 */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001671static void flash_read_cfi (flash_info_t *info, void *buf,
1672 unsigned int start, size_t len)
1673{
1674 u8 *p = buf;
1675 unsigned int i;
1676
1677 for (i = 0; i < len; i++)
1678 p[i] = flash_read_uchar(info, start + i);
1679}
1680
1681static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001682{
1683 int cfi_offset;
1684
Michael Schwingen4661cf72008-02-18 23:16:35 +01001685 /* We do not yet know what kind of commandset to use, so we issue
1686 the reset command in both Intel and AMD variants, in the hope
1687 that AMD flash roms ignore the Intel command. */
1688 flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
1689 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
1690
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001691 for (cfi_offset=0;
1692 cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
1693 cfi_offset++) {
1694 flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
1695 FLASH_CMD_CFI);
1696 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1697 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1698 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001699 flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
1700 sizeof(struct cfi_qry));
1701 info->interface = le16_to_cpu(qry->interface_desc);
1702
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001703 info->cfi_offset = flash_offset_cfi[cfi_offset];
1704 debug ("device interface is %d\n",
1705 info->interface);
1706 debug ("found port %d chip %d ",
1707 info->portwidth, info->chipwidth);
1708 debug ("port %d bits chip %d bits\n",
1709 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1710 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1711
1712 /* calculate command offsets as in the Linux driver */
1713 info->addr_unlock1 = 0x555;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001714 info->addr_unlock2 = 0x2aa;
1715
1716 /*
1717 * modify the unlock address if we are
1718 * in compatibility mode
1719 */
1720 if ( /* x8/x16 in x8 mode */
1721 ((info->chipwidth == FLASH_CFI_BY8) &&
1722 (info->interface == FLASH_CFI_X8X16)) ||
1723 /* x16/x32 in x16 mode */
1724 ((info->chipwidth == FLASH_CFI_BY16) &&
1725 (info->interface == FLASH_CFI_X16X32)))
1726 {
1727 info->addr_unlock1 = 0xaaa;
1728 info->addr_unlock2 = 0x555;
1729 }
1730
1731 info->name = "CFI conformant";
1732 return 1;
1733 }
1734 }
1735
1736 return 0;
1737}
1738
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001739static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001740{
wdenke65527f2004-02-12 00:47:09 +00001741 debug ("flash detect cfi\n");
wdenk2cefd152004-02-08 22:55:38 +00001742
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001743 for (info->portwidth = CONFIG_SYS_FLASH_CFI_WIDTH;
wdenke65527f2004-02-12 00:47:09 +00001744 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1745 for (info->chipwidth = FLASH_CFI_BY8;
1746 info->chipwidth <= info->portwidth;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001747 info->chipwidth <<= 1)
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001748 if (__flash_detect_cfi(info, qry))
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001749 return 1;
wdenk2cefd152004-02-08 22:55:38 +00001750 }
wdenke65527f2004-02-12 00:47:09 +00001751 debug ("not found\n");
wdenk2cefd152004-02-08 22:55:38 +00001752 return 0;
1753}
wdenke65527f2004-02-12 00:47:09 +00001754
wdenk2cefd152004-02-08 22:55:38 +00001755/*
Haavard Skinnemoen750ea7f2007-12-14 15:36:18 +01001756 * Manufacturer-specific quirks. Add workarounds for geometry
1757 * reversal, etc. here.
1758 */
1759static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
1760{
1761 /* check if flash geometry needs reversal */
1762 if (qry->num_erase_regions > 1) {
1763 /* reverse geometry if top boot part */
1764 if (info->cfi_version < 0x3131) {
1765 /* CFI < 1.1, try to guess from device id */
1766 if ((info->device_id & 0x80) != 0)
1767 cfi_reverse_geometry(qry);
1768 } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1769 /* CFI >= 1.1, deduct from top/bottom flag */
1770 /* note: ext_addr is valid since cfi_version > 0 */
1771 cfi_reverse_geometry(qry);
1772 }
1773 }
1774}
1775
1776static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
1777{
1778 int reverse_geometry = 0;
1779
1780 /* Check the "top boot" bit in the PRI */
1781 if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
1782 reverse_geometry = 1;
1783
1784 /* AT49BV6416(T) list the erase regions in the wrong order.
1785 * However, the device ID is identical with the non-broken
1786 * AT49BV642D since u-boot only reads the low byte (they
1787 * differ in the high byte.) So leave out this fixup for now.
1788 */
1789#if 0
1790 if (info->device_id == 0xd6 || info->device_id == 0xd2)
1791 reverse_geometry = !reverse_geometry;
1792#endif
1793
1794 if (reverse_geometry)
1795 cfi_reverse_geometry(qry);
1796}
1797
1798/*
wdenk2cefd152004-02-08 22:55:38 +00001799 * The following code cannot be run from FLASH!
1800 *
1801 */
Marian Balakowicz513b4a12005-10-11 19:09:42 +02001802ulong flash_get_size (ulong base, int banknum)
wdenk2cefd152004-02-08 22:55:38 +00001803{
wdenke65527f2004-02-12 00:47:09 +00001804 flash_info_t *info = &flash_info[banknum];
wdenk2cefd152004-02-08 22:55:38 +00001805 int i, j;
1806 flash_sect_t sect_cnt;
1807 unsigned long sector;
1808 unsigned long tmp;
1809 int size_ratio;
1810 uchar num_erase_regions;
wdenke65527f2004-02-12 00:47:09 +00001811 int erase_region_size;
1812 int erase_region_count;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001813 struct cfi_qry qry;
Stefan Roese12797482006-11-13 13:55:24 +01001814
Kumar Gala899032b2008-05-15 15:13:08 -05001815 memset(&qry, 0, sizeof(qry));
1816
Stefan Roese12797482006-11-13 13:55:24 +01001817 info->ext_addr = 0;
1818 info->cfi_version = 0;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001819#ifdef CONFIG_SYS_FLASH_PROTECTION
Stefan Roeseefef95b2006-04-01 13:41:03 +02001820 info->legacy_unlock = 0;
1821#endif
wdenk2cefd152004-02-08 22:55:38 +00001822
1823 info->start[0] = base;
1824
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001825 if (flash_detect_cfi (info, &qry)) {
1826 info->vendor = le16_to_cpu(qry.p_id);
1827 info->ext_addr = le16_to_cpu(qry.p_adr);
1828 num_erase_regions = qry.num_erase_regions;
1829
Stefan Roese12797482006-11-13 13:55:24 +01001830 if (info->ext_addr) {
1831 info->cfi_version = (ushort) flash_read_uchar (info,
1832 info->ext_addr + 3) << 8;
1833 info->cfi_version |= (ushort) flash_read_uchar (info,
1834 info->ext_addr + 4);
1835 }
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001836
wdenke65527f2004-02-12 00:47:09 +00001837#ifdef DEBUG
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001838 flash_printqry (&qry);
wdenke65527f2004-02-12 00:47:09 +00001839#endif
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001840
wdenke65527f2004-02-12 00:47:09 +00001841 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001842 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk2cefd152004-02-08 22:55:38 +00001843 case CFI_CMDSET_INTEL_STANDARD:
1844 case CFI_CMDSET_INTEL_EXTENDED:
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001845 cmdset_intel_init(info, &qry);
wdenk2cefd152004-02-08 22:55:38 +00001846 break;
1847 case CFI_CMDSET_AMD_STANDARD:
1848 case CFI_CMDSET_AMD_EXTENDED:
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001849 cmdset_amd_init(info, &qry);
wdenk2cefd152004-02-08 22:55:38 +00001850 break;
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001851 default:
1852 printf("CFI: Unknown command set 0x%x\n",
1853 info->vendor);
1854 /*
1855 * Unfortunately, this means we don't know how
1856 * to get the chip back to Read mode. Might
1857 * as well try an Intel-style reset...
1858 */
1859 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1860 return 0;
wdenk2cefd152004-02-08 22:55:38 +00001861 }
wdenk6cfa84e2004-02-10 00:03:41 +00001862
Haavard Skinnemoen750ea7f2007-12-14 15:36:18 +01001863 /* Do manufacturer-specific fixups */
1864 switch (info->manufacturer_id) {
1865 case 0x0001:
1866 flash_fixup_amd(info, &qry);
1867 break;
1868 case 0x001f:
1869 flash_fixup_atmel(info, &qry);
1870 break;
1871 }
1872
wdenke65527f2004-02-12 00:47:09 +00001873 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese12797482006-11-13 13:55:24 +01001874 debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
1875 debug ("device id is 0x%x\n", info->device_id);
1876 debug ("device id2 is 0x%x\n", info->device_id2);
1877 debug ("cfi version is 0x%04x\n", info->cfi_version);
1878
wdenk2cefd152004-02-08 22:55:38 +00001879 size_ratio = info->portwidth / info->chipwidth;
wdenke65527f2004-02-12 00:47:09 +00001880 /* if the chip is x8/x16 reduce the ratio by half */
1881 if ((info->interface == FLASH_CFI_X8X16)
1882 && (info->chipwidth == FLASH_CFI_BY8)) {
1883 size_ratio >>= 1;
1884 }
wdenke65527f2004-02-12 00:47:09 +00001885 debug ("size_ratio %d port %d bits chip %d bits\n",
1886 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1887 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1888 debug ("found %d erase regions\n", num_erase_regions);
wdenk2cefd152004-02-08 22:55:38 +00001889 sect_cnt = 0;
1890 sector = base;
wdenke65527f2004-02-12 00:47:09 +00001891 for (i = 0; i < num_erase_regions; i++) {
1892 if (i > NUM_ERASE_REGIONS) {
wdenke537b3b2004-02-23 23:54:43 +00001893 printf ("%d erase regions found, only %d used\n",
1894 num_erase_regions, NUM_ERASE_REGIONS);
wdenk2cefd152004-02-08 22:55:38 +00001895 break;
1896 }
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001897
Haavard Skinnemoenc4d478b2007-12-14 15:36:17 +01001898 tmp = le32_to_cpu(qry.erase_region_info[i]);
1899 debug("erase region %u: 0x%08lx\n", i, tmp);
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001900
1901 erase_region_count = (tmp & 0xffff) + 1;
1902 tmp >>= 16;
wdenke65527f2004-02-12 00:47:09 +00001903 erase_region_size =
1904 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenkaeba06f2004-06-09 17:34:58 +00001905 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenke537b3b2004-02-23 23:54:43 +00001906 erase_region_count, erase_region_size);
wdenke65527f2004-02-12 00:47:09 +00001907 for (j = 0; j < erase_region_count; j++) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001908 if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
Michael Schwingen73d044d2007-12-07 23:35:02 +01001909 printf("ERROR: too many flash sectors\n");
1910 break;
1911 }
wdenk2cefd152004-02-08 22:55:38 +00001912 info->start[sect_cnt] = sector;
1913 sector += (erase_region_size * size_ratio);
wdenk26c58432005-01-09 17:12:27 +00001914
1915 /*
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001916 * Only read protection status from
1917 * supported devices (intel...)
wdenk26c58432005-01-09 17:12:27 +00001918 */
1919 switch (info->vendor) {
Vasiliy Leoenenko7d1794c2008-05-07 21:25:33 +04001920 case CFI_CMDSET_INTEL_PROG_REGIONS:
wdenk26c58432005-01-09 17:12:27 +00001921 case CFI_CMDSET_INTEL_EXTENDED:
1922 case CFI_CMDSET_INTEL_STANDARD:
1923 info->protect[sect_cnt] =
1924 flash_isset (info, sect_cnt,
1925 FLASH_OFFSET_PROTECT,
1926 FLASH_STATUS_PROTECT);
1927 break;
1928 default:
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001929 /* default: not protected */
1930 info->protect[sect_cnt] = 0;
wdenk26c58432005-01-09 17:12:27 +00001931 }
1932
wdenk2cefd152004-02-08 22:55:38 +00001933 sect_cnt++;
1934 }
1935 }
1936
1937 info->sector_count = sect_cnt;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001938 info->size = 1 << qry.dev_size;
wdenk2cefd152004-02-08 22:55:38 +00001939 /* multiply the size by the number of chips */
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001940 info->size *= size_ratio;
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001941 info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
1942 tmp = 1 << qry.block_erase_timeout_typ;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001943 info->erase_blk_tout = tmp *
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001944 (1 << qry.block_erase_timeout_max);
1945 tmp = (1 << qry.buf_write_timeout_typ) *
1946 (1 << qry.buf_write_timeout_max);
1947
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001948 /* round up when converting to ms */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001949 info->buffer_write_tout = (tmp + 999) / 1000;
1950 tmp = (1 << qry.word_write_timeout_typ) *
1951 (1 << qry.word_write_timeout_max);
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001952 /* round up when converting to ms */
Haavard Skinnemoen53baec72007-12-14 15:36:16 +01001953 info->write_tout = (tmp + 999) / 1000;
wdenk2cefd152004-02-08 22:55:38 +00001954 info->flash_id = FLASH_MAN_CFI;
Haavard Skinnemoend523e392007-12-13 12:56:28 +01001955 if ((info->interface == FLASH_CFI_X8X16) &&
1956 (info->chipwidth == FLASH_CFI_BY8)) {
1957 /* XXX - Need to test on x8/x16 in parallel. */
1958 info->portwidth >>= 1;
wdenked2ac4b2004-03-14 18:23:55 +00001959 }
Mike Frysinger59404ee2008-10-02 01:55:38 -04001960
1961 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenk2cefd152004-02-08 22:55:38 +00001962 }
1963
wdenke65527f2004-02-12 00:47:09 +00001964 return (info->size);
wdenk2cefd152004-02-08 22:55:38 +00001965}
1966
Piotr Ziecik2a7493c2008-11-17 15:49:32 +01001967void flash_set_verbose(uint v)
1968{
1969 flash_verbose = v;
1970}
1971
wdenk2cefd152004-02-08 22:55:38 +00001972/*-----------------------------------------------------------------------
1973 */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001974unsigned long flash_init (void)
wdenk2cefd152004-02-08 22:55:38 +00001975{
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001976 unsigned long size = 0;
1977 int i;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001978#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
Matthias Fuchs50431522008-04-18 16:29:40 +02001979 struct apl_s {
1980 ulong start;
1981 ulong size;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001982 } apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST;
Matthias Fuchs50431522008-04-18 16:29:40 +02001983#endif
wdenk2cefd152004-02-08 22:55:38 +00001984
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001985#ifdef CONFIG_SYS_FLASH_PROTECTION
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001986 char *s = getenv("unlock");
Michael Schwingen73d044d2007-12-07 23:35:02 +01001987#endif
wdenk2cefd152004-02-08 22:55:38 +00001988
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001989#define BANK_BASE(i) (((unsigned long [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i])
Wolfgang Denk9f5fb0f2008-08-08 16:39:54 +02001990
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001991 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001992 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001993 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenk2cefd152004-02-08 22:55:38 +00001994
Wolfgang Denk9f5fb0f2008-08-08 16:39:54 +02001995 if (!flash_detect_legacy (BANK_BASE(i), i))
1996 flash_get_size (BANK_BASE(i), i);
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02001997 size += flash_info[i].size;
1998 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001999#ifndef CONFIG_SYS_FLASH_QUIET_TEST
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002000 printf ("## Unknown FLASH on Bank %d "
2001 "- Size = 0x%08lx = %ld MB\n",
2002 i+1, flash_info[i].size,
2003 flash_info[i].size << 20);
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02002004#endif /* CONFIG_SYS_FLASH_QUIET_TEST */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002005 }
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02002006#ifdef CONFIG_SYS_FLASH_PROTECTION
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002007 else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
2008 /*
2009 * Only the U-Boot image and it's environment
2010 * is protected, all other sectors are
2011 * unprotected (unlocked) if flash hardware
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02002012 * protection is used (CONFIG_SYS_FLASH_PROTECTION)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002013 * and the environment variable "unlock" is
2014 * set to "yes".
2015 */
2016 if (flash_info[i].legacy_unlock) {
2017 int k;
wdenk2cefd152004-02-08 22:55:38 +00002018
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002019 /*
2020 * Disable legacy_unlock temporarily,
2021 * since flash_real_protect would
2022 * relock all other sectors again
2023 * otherwise.
2024 */
2025 flash_info[i].legacy_unlock = 0;
wdenk2cefd152004-02-08 22:55:38 +00002026
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002027 /*
2028 * Legacy unlocking (e.g. Intel J3) ->
2029 * unlock only one sector. This will
2030 * unlock all sectors.
2031 */
2032 flash_real_protect (&flash_info[i], 0, 0);
wdenk2cefd152004-02-08 22:55:38 +00002033
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002034 flash_info[i].legacy_unlock = 1;
wdenk2cefd152004-02-08 22:55:38 +00002035
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002036 /*
2037 * Manually mark other sectors as
2038 * unlocked (unprotected)
2039 */
2040 for (k = 1; k < flash_info[i].sector_count; k++)
2041 flash_info[i].protect[k] = 0;
2042 } else {
2043 /*
2044 * No legancy unlocking -> unlock all sectors
2045 */
2046 flash_protect (FLAG_PROTECT_CLEAR,
2047 flash_info[i].start[0],
2048 flash_info[i].start[0]
2049 + flash_info[i].size - 1,
2050 &flash_info[i]);
Stefan Roesec865e6c2006-02-28 15:29:58 +01002051 }
Stefan Roesec865e6c2006-02-28 15:29:58 +01002052 }
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02002053#endif /* CONFIG_SYS_FLASH_PROTECTION */
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002054 }
Stefan Roesec865e6c2006-02-28 15:29:58 +01002055
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002056 /* Monitor protection ON by default */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02002057#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002058 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02002059 CONFIG_SYS_MONITOR_BASE,
2060 CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
2061 flash_get_info(CONFIG_SYS_MONITOR_BASE));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002062#endif
Stefan Roesec865e6c2006-02-28 15:29:58 +01002063
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002064 /* Environment protection ON by default */
Jean-Christophe PLAGNIOL-VILLARD53db4cd2008-09-10 22:48:04 +02002065#ifdef CONFIG_ENV_IS_IN_FLASH
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002066 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +02002067 CONFIG_ENV_ADDR,
2068 CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
2069 flash_get_info(CONFIG_ENV_ADDR));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002070#endif
Stefan Roesec865e6c2006-02-28 15:29:58 +01002071
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002072 /* Redundant environment protection ON by default */
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +02002073#ifdef CONFIG_ENV_ADDR_REDUND
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002074 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +02002075 CONFIG_ENV_ADDR_REDUND,
2076 CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SIZE_REDUND - 1,
2077 flash_get_info(CONFIG_ENV_ADDR_REDUND));
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002078#endif
Matthias Fuchs50431522008-04-18 16:29:40 +02002079
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02002080#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
Matthias Fuchs50431522008-04-18 16:29:40 +02002081 for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
2082 debug("autoprotecting from %08x to %08x\n",
2083 apl[i].start, apl[i].start + apl[i].size - 1);
2084 flash_protect (FLAG_PROTECT_SET,
2085 apl[i].start,
2086 apl[i].start + apl[i].size - 1,
2087 flash_get_info(apl[i].start));
2088 }
2089#endif
Piotr Ziecik3e939e92008-11-17 15:57:58 +01002090
2091#ifdef CONFIG_FLASH_CFI_MTD
2092 cfi_mtd_init();
2093#endif
2094
Haavard Skinnemoen6dd763c2007-10-06 18:55:36 +02002095 return (size);
wdenk2cefd152004-02-08 22:55:38 +00002096}