blob: 9b10220fc74520e48befc9a4d2b8664f1337494d [file] [log] [blame]
wdenk5653fc32004-02-08 22:55:38 +00001/*
wdenkbf9e3b32004-02-12 00:47:09 +00002 * (C) Copyright 2002-2004
wdenk5653fc32004-02-08 22:55:38 +00003 * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com
4 *
5 * Copyright (C) 2003 Arabella Software Ltd.
6 * Yuli Barcohen <yuli@arabellasw.com>
wdenk5653fc32004-02-08 22:55:38 +00007 *
wdenkbf9e3b32004-02-12 00:47:09 +00008 * Copyright (C) 2004
9 * Ed Okerson
Stefan Roese260421a2006-11-13 13:55:24 +010010 *
11 * Copyright (C) 2006
12 * Tolunay Orkun <listmember@orkun.us>
wdenkbf9e3b32004-02-12 00:47:09 +000013 *
wdenk5653fc32004-02-08 22:55:38 +000014 * See file CREDITS for list of people who contributed to this
15 * project.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30 * MA 02111-1307 USA
31 *
wdenk5653fc32004-02-08 22:55:38 +000032 */
33
34/* The DEBUG define must be before common to enable debugging */
wdenk2d1a5372004-02-23 19:30:57 +000035/* #define DEBUG */
36
wdenk5653fc32004-02-08 22:55:38 +000037#include <common.h>
38#include <asm/processor.h>
wdenk4c0d4c32004-06-09 17:34:58 +000039#include <asm/byteorder.h>
wdenk2a8af182005-04-13 10:02:42 +000040#include <environment.h>
wdenkbf9e3b32004-02-12 00:47:09 +000041#ifdef CFG_FLASH_CFI_DRIVER
wdenk028ab6b2004-02-23 23:54:43 +000042
wdenk5653fc32004-02-08 22:55:38 +000043/*
44 * This file implements a Common Flash Interface (CFI) driver for U-Boot.
45 * The width of the port and the width of the chips are determined at initialization.
46 * These widths are used to calculate the address for access CFI data structures.
wdenk5653fc32004-02-08 22:55:38 +000047 *
48 * References
49 * JEDEC Standard JESD68 - Common Flash Interface (CFI)
50 * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
51 * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
52 * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
Stefan Roese260421a2006-11-13 13:55:24 +010053 * AMD CFI Specification, Release 2.0 December 1, 2001
54 * AMD/Spansion Application Note: Migration from Single-byte to Three-byte
55 * Device IDs, Publication Number 25538 Revision A, November 8, 2001
wdenk5653fc32004-02-08 22:55:38 +000056 *
wdenk5653fc32004-02-08 22:55:38 +000057 */
58
wdenkbf9e3b32004-02-12 00:47:09 +000059#ifndef CFG_FLASH_BANKS_LIST
60#define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE }
61#endif
62
wdenk5653fc32004-02-08 22:55:38 +000063#define FLASH_CMD_CFI 0x98
64#define FLASH_CMD_READ_ID 0x90
65#define FLASH_CMD_RESET 0xff
66#define FLASH_CMD_BLOCK_ERASE 0x20
67#define FLASH_CMD_ERASE_CONFIRM 0xD0
68#define FLASH_CMD_WRITE 0x40
69#define FLASH_CMD_PROTECT 0x60
70#define FLASH_CMD_PROTECT_SET 0x01
71#define FLASH_CMD_PROTECT_CLEAR 0xD0
72#define FLASH_CMD_CLEAR_STATUS 0x50
wdenkbf9e3b32004-02-12 00:47:09 +000073#define FLASH_CMD_WRITE_TO_BUFFER 0xE8
74#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0
wdenk5653fc32004-02-08 22:55:38 +000075
76#define FLASH_STATUS_DONE 0x80
77#define FLASH_STATUS_ESS 0x40
78#define FLASH_STATUS_ECLBS 0x20
79#define FLASH_STATUS_PSLBS 0x10
80#define FLASH_STATUS_VPENS 0x08
81#define FLASH_STATUS_PSS 0x04
82#define FLASH_STATUS_DPS 0x02
83#define FLASH_STATUS_R 0x01
84#define FLASH_STATUS_PROTECT 0x01
85
86#define AMD_CMD_RESET 0xF0
87#define AMD_CMD_WRITE 0xA0
88#define AMD_CMD_ERASE_START 0x80
89#define AMD_CMD_ERASE_SECTOR 0x30
wdenk855a4962004-03-14 18:23:55 +000090#define AMD_CMD_UNLOCK_START 0xAA
91#define AMD_CMD_UNLOCK_ACK 0x55
Stefan Roese79b4cda2006-02-28 15:29:58 +010092#define AMD_CMD_WRITE_TO_BUFFER 0x25
93#define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29
wdenk5653fc32004-02-08 22:55:38 +000094
95#define AMD_STATUS_TOGGLE 0x40
96#define AMD_STATUS_ERROR 0x20
Stefan Roese79b4cda2006-02-28 15:29:58 +010097
98#define AMD_ADDR_ERASE_START ((info->portwidth == FLASH_CFI_8BIT) ? 0xAAA : 0x555)
99#define AMD_ADDR_START ((info->portwidth == FLASH_CFI_8BIT) ? 0xAAA : 0x555)
100#define AMD_ADDR_ACK ((info->portwidth == FLASH_CFI_8BIT) ? 0x555 : 0x2AA)
wdenk5653fc32004-02-08 22:55:38 +0000101
Stefan Roese260421a2006-11-13 13:55:24 +0100102#define FLASH_OFFSET_MANUFACTURER_ID 0x00
103#define FLASH_OFFSET_DEVICE_ID 0x01
104#define FLASH_OFFSET_DEVICE_ID2 0x0E
105#define FLASH_OFFSET_DEVICE_ID3 0x0F
wdenk5653fc32004-02-08 22:55:38 +0000106#define FLASH_OFFSET_CFI 0x55
107#define FLASH_OFFSET_CFI_RESP 0x10
wdenkbf9e3b32004-02-12 00:47:09 +0000108#define FLASH_OFFSET_PRIMARY_VENDOR 0x13
Stefan Roese2662b402006-04-01 13:41:03 +0200109#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15 /* extended query table primary addr */
wdenk5653fc32004-02-08 22:55:38 +0000110#define FLASH_OFFSET_WTOUT 0x1F
wdenkbf9e3b32004-02-12 00:47:09 +0000111#define FLASH_OFFSET_WBTOUT 0x20
wdenk5653fc32004-02-08 22:55:38 +0000112#define FLASH_OFFSET_ETOUT 0x21
wdenkbf9e3b32004-02-12 00:47:09 +0000113#define FLASH_OFFSET_CETOUT 0x22
wdenk5653fc32004-02-08 22:55:38 +0000114#define FLASH_OFFSET_WMAX_TOUT 0x23
wdenkbf9e3b32004-02-12 00:47:09 +0000115#define FLASH_OFFSET_WBMAX_TOUT 0x24
wdenk5653fc32004-02-08 22:55:38 +0000116#define FLASH_OFFSET_EMAX_TOUT 0x25
wdenkbf9e3b32004-02-12 00:47:09 +0000117#define FLASH_OFFSET_CEMAX_TOUT 0x26
wdenk5653fc32004-02-08 22:55:38 +0000118#define FLASH_OFFSET_SIZE 0x27
wdenkbf9e3b32004-02-12 00:47:09 +0000119#define FLASH_OFFSET_INTERFACE 0x28
120#define FLASH_OFFSET_BUFFER_SIZE 0x2A
wdenk5653fc32004-02-08 22:55:38 +0000121#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C
122#define FLASH_OFFSET_ERASE_REGIONS 0x2D
123#define FLASH_OFFSET_PROTECT 0x02
wdenkbf9e3b32004-02-12 00:47:09 +0000124#define FLASH_OFFSET_USER_PROTECTION 0x85
125#define FLASH_OFFSET_INTEL_PROTECTION 0x81
wdenk5653fc32004-02-08 22:55:38 +0000126
Stefan Roese260421a2006-11-13 13:55:24 +0100127#define CFI_CMDSET_NONE 0
128#define CFI_CMDSET_INTEL_EXTENDED 1
129#define CFI_CMDSET_AMD_STANDARD 2
130#define CFI_CMDSET_INTEL_STANDARD 3
131#define CFI_CMDSET_AMD_EXTENDED 4
132#define CFI_CMDSET_MITSU_STANDARD 256
133#define CFI_CMDSET_MITSU_EXTENDED 257
134#define CFI_CMDSET_SST 258
wdenk5653fc32004-02-08 22:55:38 +0000135
wdenkf7d15722004-12-18 22:35:43 +0000136#ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
137# undef FLASH_CMD_RESET
Stefan Roese260421a2006-11-13 13:55:24 +0100138# define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */
wdenkf7d15722004-12-18 22:35:43 +0000139#endif
140
wdenk5653fc32004-02-08 22:55:38 +0000141typedef union {
142 unsigned char c;
143 unsigned short w;
144 unsigned long l;
145 unsigned long long ll;
146} cfiword_t;
147
148typedef union {
wdenkbf9e3b32004-02-12 00:47:09 +0000149 volatile unsigned char *cp;
wdenk5653fc32004-02-08 22:55:38 +0000150 volatile unsigned short *wp;
wdenkbf9e3b32004-02-12 00:47:09 +0000151 volatile unsigned long *lp;
wdenk5653fc32004-02-08 22:55:38 +0000152 volatile unsigned long long *llp;
153} cfiptr_t;
154
Stefan Roese260421a2006-11-13 13:55:24 +0100155#define NUM_ERASE_REGIONS 4 /* max. number of erase regions */
wdenk5653fc32004-02-08 22:55:38 +0000156
Marian Balakowicze6f2e902005-10-11 19:09:42 +0200157/* use CFG_MAX_FLASH_BANKS_DETECT if defined */
158#ifdef CFG_MAX_FLASH_BANKS_DETECT
159static ulong bank_base[CFG_MAX_FLASH_BANKS_DETECT] = CFG_FLASH_BANKS_LIST;
160flash_info_t flash_info[CFG_MAX_FLASH_BANKS_DETECT]; /* FLASH chips info */
161#else
wdenk5653fc32004-02-08 22:55:38 +0000162static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST;
Marian Balakowicze6f2e902005-10-11 19:09:42 +0200163flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */
164#endif
wdenk5653fc32004-02-08 22:55:38 +0000165
Stefan Roese79b4cda2006-02-28 15:29:58 +0100166/*
167 * Check if chip width is defined. If not, start detecting with 8bit.
168 */
169#ifndef CFG_FLASH_CFI_WIDTH
170#define CFG_FLASH_CFI_WIDTH FLASH_CFI_8BIT
171#endif
172
wdenk5653fc32004-02-08 22:55:38 +0000173
174/*-----------------------------------------------------------------------
175 * Functions
176 */
177
178typedef unsigned long flash_sect_t;
179
wdenkbf9e3b32004-02-12 00:47:09 +0000180static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c);
181static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf);
wdenk028ab6b2004-02-23 23:54:43 +0000182static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
wdenkbf9e3b32004-02-12 00:47:09 +0000183static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect);
wdenk028ab6b2004-02-23 23:54:43 +0000184static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
185static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
186static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
Stefan Roese260421a2006-11-13 13:55:24 +0100187static void flash_read_jedec_ids (flash_info_t * info);
wdenkbf9e3b32004-02-12 00:47:09 +0000188static int flash_detect_cfi (flash_info_t * info);
wdenk028ab6b2004-02-23 23:54:43 +0000189static int flash_write_cfiword (flash_info_t * info, ulong dest, cfiword_t cword);
wdenkbf9e3b32004-02-12 00:47:09 +0000190static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
191 ulong tout, char *prompt);
Stefan Roesef18e8742006-03-01 17:00:49 +0100192ulong flash_get_size (ulong base, int banknum);
Wolfgang Denk080bdb72005-10-05 01:51:29 +0200193#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
wdenk7680c142005-05-16 15:23:22 +0000194static flash_info_t *flash_get_info(ulong base);
Wolfgang Denk080bdb72005-10-05 01:51:29 +0200195#endif
wdenk5653fc32004-02-08 22:55:38 +0000196#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenk028ab6b2004-02-23 23:54:43 +0000197static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, int len);
wdenk5653fc32004-02-08 22:55:38 +0000198#endif
199
wdenk5653fc32004-02-08 22:55:38 +0000200/*-----------------------------------------------------------------------
201 * create an address based on the offset and the port width
202 */
wdenk028ab6b2004-02-23 23:54:43 +0000203inline uchar *flash_make_addr (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000204{
wdenkbf9e3b32004-02-12 00:47:09 +0000205 return ((uchar *) (info->start[sect] + (offset * info->portwidth)));
wdenk5653fc32004-02-08 22:55:38 +0000206}
wdenkbf9e3b32004-02-12 00:47:09 +0000207
208#ifdef DEBUG
209/*-----------------------------------------------------------------------
210 * Debug support
211 */
212void print_longlong (char *str, unsigned long long data)
213{
214 int i;
215 char *cp;
216
217 cp = (unsigned char *) &data;
218 for (i = 0; i < 8; i++)
219 sprintf (&str[i * 2], "%2.2x", *cp++);
220}
221static void flash_printqry (flash_info_t * info, flash_sect_t sect)
222{
223 cfiptr_t cptr;
224 int x, y;
225
Wolfgang Denk47340a42005-10-09 00:25:58 +0200226 for (x = 0; x < 0x40; x += 16U / info->portwidth) {
wdenkbf9e3b32004-02-12 00:47:09 +0000227 cptr.cp =
228 flash_make_addr (info, sect,
229 x + FLASH_OFFSET_CFI_RESP);
230 debug ("%p : ", cptr.cp);
231 for (y = 0; y < 16; y++) {
232 debug ("%2.2x ", cptr.cp[y]);
233 }
234 debug (" ");
235 for (y = 0; y < 16; y++) {
236 if (cptr.cp[y] >= 0x20 && cptr.cp[y] <= 0x7e) {
237 debug ("%c", cptr.cp[y]);
238 } else {
239 debug (".");
240 }
241 }
242 debug ("\n");
243 }
244}
wdenkbf9e3b32004-02-12 00:47:09 +0000245#endif
246
247
wdenk5653fc32004-02-08 22:55:38 +0000248/*-----------------------------------------------------------------------
249 * read a character at a port width address
250 */
wdenkbf9e3b32004-02-12 00:47:09 +0000251inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000252{
253 uchar *cp;
wdenkbf9e3b32004-02-12 00:47:09 +0000254
255 cp = flash_make_addr (info, 0, offset);
256#if defined(__LITTLE_ENDIAN)
257 return (cp[0]);
258#else
wdenk5653fc32004-02-08 22:55:38 +0000259 return (cp[info->portwidth - 1]);
wdenkbf9e3b32004-02-12 00:47:09 +0000260#endif
wdenk5653fc32004-02-08 22:55:38 +0000261}
262
263/*-----------------------------------------------------------------------
264 * read a short word by swapping for ppc format.
265 */
wdenkbf9e3b32004-02-12 00:47:09 +0000266ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000267{
wdenkbf9e3b32004-02-12 00:47:09 +0000268 uchar *addr;
269 ushort retval;
wdenk5653fc32004-02-08 22:55:38 +0000270
wdenkbf9e3b32004-02-12 00:47:09 +0000271#ifdef DEBUG
272 int x;
273#endif
274 addr = flash_make_addr (info, sect, offset);
wdenk5653fc32004-02-08 22:55:38 +0000275
wdenkbf9e3b32004-02-12 00:47:09 +0000276#ifdef DEBUG
277 debug ("ushort addr is at %p info->portwidth = %d\n", addr,
278 info->portwidth);
279 for (x = 0; x < 2 * info->portwidth; x++) {
280 debug ("addr[%x] = 0x%x\n", x, addr[x]);
281 }
282#endif
283#if defined(__LITTLE_ENDIAN)
284 retval = ((addr[(info->portwidth)] << 8) | addr[0]);
285#else
286 retval = ((addr[(2 * info->portwidth) - 1] << 8) |
287 addr[info->portwidth - 1]);
288#endif
289
290 debug ("retval = 0x%x\n", retval);
291 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000292}
293
294/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +0100295 * read a long word by picking the least significant byte of each maximum
wdenk5653fc32004-02-08 22:55:38 +0000296 * port size word. Swap for ppc format.
297 */
wdenkbf9e3b32004-02-12 00:47:09 +0000298ulong flash_read_long (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000299{
wdenkbf9e3b32004-02-12 00:47:09 +0000300 uchar *addr;
301 ulong retval;
wdenk5653fc32004-02-08 22:55:38 +0000302
wdenkbf9e3b32004-02-12 00:47:09 +0000303#ifdef DEBUG
304 int x;
305#endif
306 addr = flash_make_addr (info, sect, offset);
307
308#ifdef DEBUG
309 debug ("long addr is at %p info->portwidth = %d\n", addr,
310 info->portwidth);
311 for (x = 0; x < 4 * info->portwidth; x++) {
312 debug ("addr[%x] = 0x%x\n", x, addr[x]);
313 }
314#endif
315#if defined(__LITTLE_ENDIAN)
316 retval = (addr[0] << 16) | (addr[(info->portwidth)] << 24) |
wdenk028ab6b2004-02-23 23:54:43 +0000317 (addr[(2 * info->portwidth)]) | (addr[(3 * info->portwidth)] << 8);
wdenkbf9e3b32004-02-12 00:47:09 +0000318#else
319 retval = (addr[(2 * info->portwidth) - 1] << 24) |
320 (addr[(info->portwidth) - 1] << 16) |
321 (addr[(4 * info->portwidth) - 1] << 8) |
322 addr[(3 * info->portwidth) - 1];
323#endif
324 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000325}
326
Stefan Roese79b4cda2006-02-28 15:29:58 +0100327
wdenk5653fc32004-02-08 22:55:38 +0000328/*-----------------------------------------------------------------------
329 */
330unsigned long flash_init (void)
331{
332 unsigned long size = 0;
333 int i;
334
Stefan Roese2662b402006-04-01 13:41:03 +0200335#ifdef CFG_FLASH_PROTECTION
336 char *s = getenv("unlock");
337#endif
338
wdenk5653fc32004-02-08 22:55:38 +0000339 /* Init: no FLASHes known */
wdenkbf9e3b32004-02-12 00:47:09 +0000340 for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
wdenk5653fc32004-02-08 22:55:38 +0000341 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenkbf9e3b32004-02-12 00:47:09 +0000342 size += flash_info[i].size = flash_get_size (bank_base[i], i);
wdenk5653fc32004-02-08 22:55:38 +0000343 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
Stefan Roese5568e612005-11-22 13:20:42 +0100344#ifndef CFG_FLASH_QUIET_TEST
wdenk028ab6b2004-02-23 23:54:43 +0000345 printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
346 i, flash_info[i].size, flash_info[i].size << 20);
Stefan Roese5568e612005-11-22 13:20:42 +0100347#endif /* CFG_FLASH_QUIET_TEST */
wdenk5653fc32004-02-08 22:55:38 +0000348 }
Stefan Roese79b4cda2006-02-28 15:29:58 +0100349#ifdef CFG_FLASH_PROTECTION
Stefan Roese2662b402006-04-01 13:41:03 +0200350 else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
351 /*
352 * Only the U-Boot image and it's environment is protected,
353 * all other sectors are unprotected (unlocked) if flash
354 * hardware protection is used (CFG_FLASH_PROTECTION) and
355 * the environment variable "unlock" is set to "yes".
356 */
357 if (flash_info[i].legacy_unlock) {
358 int k;
Stefan Roese79b4cda2006-02-28 15:29:58 +0100359
Stefan Roese79b4cda2006-02-28 15:29:58 +0100360 /*
Stefan Roese2662b402006-04-01 13:41:03 +0200361 * Disable legacy_unlock temporarily, since
362 * flash_real_protect would relock all other sectors
363 * again otherwise.
364 */
365 flash_info[i].legacy_unlock = 0;
366
367 /*
368 * Legacy unlocking (e.g. Intel J3) -> unlock only one
369 * sector. This will unlock all sectors.
370 */
371 flash_real_protect (&flash_info[i], 0, 0);
372
373 flash_info[i].legacy_unlock = 1;
374
375 /*
376 * Manually mark other sectors as unlocked (unprotected)
377 */
378 for (k = 1; k < flash_info[i].sector_count; k++)
379 flash_info[i].protect[k] = 0;
380 } else {
381 /*
382 * No legancy unlocking -> unlock all sectors
Stefan Roese79b4cda2006-02-28 15:29:58 +0100383 */
384 flash_protect (FLAG_PROTECT_CLEAR,
385 flash_info[i].start[0],
386 flash_info[i].start[0] + flash_info[i].size - 1,
387 &flash_info[i]);
388 }
389 }
390#endif /* CFG_FLASH_PROTECTION */
wdenk5653fc32004-02-08 22:55:38 +0000391 }
392
393 /* Monitor protection ON by default */
394#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
wdenkbf9e3b32004-02-12 00:47:09 +0000395 flash_protect (FLAG_PROTECT_SET,
396 CFG_MONITOR_BASE,
wdenk7680c142005-05-16 15:23:22 +0000397 CFG_MONITOR_BASE + monitor_flash_len - 1,
398 flash_get_info(CFG_MONITOR_BASE));
wdenk5653fc32004-02-08 22:55:38 +0000399#endif
400
wdenk656658d2004-10-10 22:16:06 +0000401 /* Environment protection ON by default */
402#ifdef CFG_ENV_IS_IN_FLASH
403 flash_protect (FLAG_PROTECT_SET,
404 CFG_ENV_ADDR,
405 CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
wdenk7680c142005-05-16 15:23:22 +0000406 flash_get_info(CFG_ENV_ADDR));
wdenk656658d2004-10-10 22:16:06 +0000407#endif
408
409 /* Redundant environment protection ON by default */
410#ifdef CFG_ENV_ADDR_REDUND
411 flash_protect (FLAG_PROTECT_SET,
412 CFG_ENV_ADDR_REDUND,
413 CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
wdenk7680c142005-05-16 15:23:22 +0000414 flash_get_info(CFG_ENV_ADDR_REDUND));
wdenk656658d2004-10-10 22:16:06 +0000415#endif
wdenk5653fc32004-02-08 22:55:38 +0000416 return (size);
417}
418
419/*-----------------------------------------------------------------------
420 */
Wolfgang Denk080bdb72005-10-05 01:51:29 +0200421#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
wdenk7680c142005-05-16 15:23:22 +0000422static flash_info_t *flash_get_info(ulong base)
423{
424 int i;
Marian Balakowicze6f2e902005-10-11 19:09:42 +0200425 flash_info_t * info = 0;
wdenk7680c142005-05-16 15:23:22 +0000426
427 for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) {
428 info = & flash_info[i];
429 if (info->size && info->start[0] <= base &&
430 base <= info->start[0] + info->size - 1)
431 break;
432 }
433
434 return i == CFG_MAX_FLASH_BANKS ? 0 : info;
435}
Wolfgang Denk080bdb72005-10-05 01:51:29 +0200436#endif
wdenk7680c142005-05-16 15:23:22 +0000437
438/*-----------------------------------------------------------------------
439 */
wdenkbf9e3b32004-02-12 00:47:09 +0000440int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk5653fc32004-02-08 22:55:38 +0000441{
442 int rcode = 0;
443 int prot;
444 flash_sect_t sect;
445
wdenkbf9e3b32004-02-12 00:47:09 +0000446 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +0000447 puts ("Can't erase unknown flash type - aborted\n");
wdenk5653fc32004-02-08 22:55:38 +0000448 return 1;
449 }
450 if ((s_first < 0) || (s_first > s_last)) {
wdenk4b9206e2004-03-23 22:14:11 +0000451 puts ("- no sectors to erase\n");
wdenk5653fc32004-02-08 22:55:38 +0000452 return 1;
453 }
454
455 prot = 0;
wdenkbf9e3b32004-02-12 00:47:09 +0000456 for (sect = s_first; sect <= s_last; ++sect) {
wdenk5653fc32004-02-08 22:55:38 +0000457 if (info->protect[sect]) {
458 prot++;
459 }
460 }
461 if (prot) {
wdenkbf9e3b32004-02-12 00:47:09 +0000462 printf ("- Warning: %d protected sectors will not be erased!\n", prot);
wdenk5653fc32004-02-08 22:55:38 +0000463 } else {
wdenk4b9206e2004-03-23 22:14:11 +0000464 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +0000465 }
466
467
wdenkbf9e3b32004-02-12 00:47:09 +0000468 for (sect = s_first; sect <= s_last; sect++) {
wdenk5653fc32004-02-08 22:55:38 +0000469 if (info->protect[sect] == 0) { /* not protected */
wdenkbf9e3b32004-02-12 00:47:09 +0000470 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +0000471 case CFI_CMDSET_INTEL_STANDARD:
472 case CFI_CMDSET_INTEL_EXTENDED:
wdenk028ab6b2004-02-23 23:54:43 +0000473 flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS);
474 flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE);
475 flash_write_cmd (info, sect, 0, FLASH_CMD_ERASE_CONFIRM);
wdenk5653fc32004-02-08 22:55:38 +0000476 break;
477 case CFI_CMDSET_AMD_STANDARD:
478 case CFI_CMDSET_AMD_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +0000479 flash_unlock_seq (info, sect);
wdenk855a4962004-03-14 18:23:55 +0000480 flash_write_cmd (info, sect, AMD_ADDR_ERASE_START,
481 AMD_CMD_ERASE_START);
wdenkbf9e3b32004-02-12 00:47:09 +0000482 flash_unlock_seq (info, sect);
wdenk028ab6b2004-02-23 23:54:43 +0000483 flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR);
wdenk5653fc32004-02-08 22:55:38 +0000484 break;
485 default:
wdenkbf9e3b32004-02-12 00:47:09 +0000486 debug ("Unkown flash vendor %d\n",
487 info->vendor);
wdenk5653fc32004-02-08 22:55:38 +0000488 break;
489 }
490
wdenkbf9e3b32004-02-12 00:47:09 +0000491 if (flash_full_status_check
492 (info, sect, info->erase_blk_tout, "erase")) {
wdenk5653fc32004-02-08 22:55:38 +0000493 rcode = 1;
494 } else
wdenk4b9206e2004-03-23 22:14:11 +0000495 putc ('.');
wdenk5653fc32004-02-08 22:55:38 +0000496 }
497 }
wdenk4b9206e2004-03-23 22:14:11 +0000498 puts (" done\n");
wdenk5653fc32004-02-08 22:55:38 +0000499 return rcode;
500}
501
502/*-----------------------------------------------------------------------
503 */
wdenkbf9e3b32004-02-12 00:47:09 +0000504void flash_print_info (flash_info_t * info)
wdenk5653fc32004-02-08 22:55:38 +0000505{
506 int i;
507
508 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +0000509 puts ("missing or unknown FLASH type\n");
wdenk5653fc32004-02-08 22:55:38 +0000510 return;
511 }
512
wdenkbf9e3b32004-02-12 00:47:09 +0000513 printf ("CFI conformant FLASH (%d x %d)",
514 (info->portwidth << 3), (info->chipwidth << 3));
wdenk5653fc32004-02-08 22:55:38 +0000515 printf (" Size: %ld MB in %d Sectors\n",
516 info->size >> 20, info->sector_count);
Stefan Roese260421a2006-11-13 13:55:24 +0100517 printf (" ");
518 switch (info->vendor) {
519 case CFI_CMDSET_INTEL_STANDARD:
520 printf ("Intel Standard");
521 break;
522 case CFI_CMDSET_INTEL_EXTENDED:
523 printf ("Intel Extended");
524 break;
525 case CFI_CMDSET_AMD_STANDARD:
526 printf ("AMD Standard");
527 break;
528 case CFI_CMDSET_AMD_EXTENDED:
529 printf ("AMD Extended");
530 break;
531 default:
532 printf ("Unknown (%d)", info->vendor);
533 break;
534 }
535 printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
536 info->manufacturer_id, info->device_id);
537 if (info->device_id == 0x7E) {
538 printf("%04X", info->device_id2);
539 }
540 printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n",
wdenk028ab6b2004-02-23 23:54:43 +0000541 info->erase_blk_tout,
Stefan Roese260421a2006-11-13 13:55:24 +0100542 info->write_tout);
543 if (info->buffer_size > 1) {
544 printf (" Buffer write timeout: %ld ms, buffer size: %d bytes\n",
wdenk028ab6b2004-02-23 23:54:43 +0000545 info->buffer_write_tout,
546 info->buffer_size);
Stefan Roese260421a2006-11-13 13:55:24 +0100547 }
wdenk5653fc32004-02-08 22:55:38 +0000548
Stefan Roese260421a2006-11-13 13:55:24 +0100549 puts ("\n Sector Start Addresses:");
wdenkbf9e3b32004-02-12 00:47:09 +0000550 for (i = 0; i < info->sector_count; ++i) {
Stefan Roese260421a2006-11-13 13:55:24 +0100551 if ((i % 5) == 0)
552 printf ("\n");
wdenk5653fc32004-02-08 22:55:38 +0000553#ifdef CFG_FLASH_EMPTY_INFO
554 int k;
555 int size;
556 int erased;
557 volatile unsigned long *flash;
558
559 /*
560 * Check if whole sector is erased
561 */
wdenkbf9e3b32004-02-12 00:47:09 +0000562 if (i != (info->sector_count - 1))
563 size = info->start[i + 1] - info->start[i];
wdenk5653fc32004-02-08 22:55:38 +0000564 else
wdenkbf9e3b32004-02-12 00:47:09 +0000565 size = info->start[0] + info->size - info->start[i];
wdenk5653fc32004-02-08 22:55:38 +0000566 erased = 1;
wdenkbf9e3b32004-02-12 00:47:09 +0000567 flash = (volatile unsigned long *) info->start[i];
568 size = size >> 2; /* divide by 4 for longword access */
569 for (k = 0; k < size; k++) {
570 if (*flash++ != 0xffffffff) {
571 erased = 0;
572 break;
573 }
574 }
wdenk5653fc32004-02-08 22:55:38 +0000575
wdenk5653fc32004-02-08 22:55:38 +0000576 /* print empty and read-only info */
Stefan Roese260421a2006-11-13 13:55:24 +0100577 printf (" %08lX %c %s ",
wdenk5653fc32004-02-08 22:55:38 +0000578 info->start[i],
Stefan Roese260421a2006-11-13 13:55:24 +0100579 erased ? 'E' : ' ',
580 info->protect[i] ? "RO" : " ");
Wolfgang Denkb63de2c2005-09-25 00:23:05 +0200581#else /* ! CFG_FLASH_EMPTY_INFO */
Stefan Roese260421a2006-11-13 13:55:24 +0100582 printf (" %08lX %s ",
583 info->start[i],
584 info->protect[i] ? "RO" : " ");
wdenk5653fc32004-02-08 22:55:38 +0000585#endif
586 }
wdenk4b9206e2004-03-23 22:14:11 +0000587 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +0000588 return;
589}
590
591/*-----------------------------------------------------------------------
592 * Copy memory to flash, returns:
593 * 0 - OK
594 * 1 - write timeout
595 * 2 - Flash not erased
596 */
wdenkbf9e3b32004-02-12 00:47:09 +0000597int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk5653fc32004-02-08 22:55:38 +0000598{
599 ulong wp;
600 ulong cp;
601 int aln;
602 cfiword_t cword;
603 int i, rc;
604
wdenkbf9e3b32004-02-12 00:47:09 +0000605#ifdef CFG_FLASH_USE_BUFFER_WRITE
606 int buffered_size;
607#endif
wdenkbf9e3b32004-02-12 00:47:09 +0000608 /* get lower aligned address */
wdenk5653fc32004-02-08 22:55:38 +0000609 /* get lower aligned address */
610 wp = (addr & ~(info->portwidth - 1));
611
612 /* handle unaligned start */
wdenkbf9e3b32004-02-12 00:47:09 +0000613 if ((aln = addr - wp) != 0) {
wdenk5653fc32004-02-08 22:55:38 +0000614 cword.l = 0;
615 cp = wp;
wdenkbf9e3b32004-02-12 00:47:09 +0000616 for (i = 0; i < aln; ++i, ++cp)
617 flash_add_byte (info, &cword, (*(uchar *) cp));
wdenk5653fc32004-02-08 22:55:38 +0000618
wdenkbf9e3b32004-02-12 00:47:09 +0000619 for (; (i < info->portwidth) && (cnt > 0); i++) {
620 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +0000621 cnt--;
622 cp++;
623 }
wdenkbf9e3b32004-02-12 00:47:09 +0000624 for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp)
625 flash_add_byte (info, &cword, (*(uchar *) cp));
626 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk5653fc32004-02-08 22:55:38 +0000627 return rc;
628 wp = cp;
629 }
630
wdenkbf9e3b32004-02-12 00:47:09 +0000631 /* handle the aligned part */
wdenk5653fc32004-02-08 22:55:38 +0000632#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenkbf9e3b32004-02-12 00:47:09 +0000633 buffered_size = (info->portwidth / info->chipwidth);
634 buffered_size *= info->buffer_size;
635 while (cnt >= info->portwidth) {
Stefan Roese79b4cda2006-02-28 15:29:58 +0100636 /* prohibit buffer write when buffer_size is 1 */
637 if (info->buffer_size == 1) {
638 cword.l = 0;
639 for (i = 0; i < info->portwidth; i++)
640 flash_add_byte (info, &cword, *src++);
641 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
642 return rc;
643 wp += info->portwidth;
644 cnt -= info->portwidth;
645 continue;
646 }
647
648 /* write buffer until next buffered_size aligned boundary */
649 i = buffered_size - (wp % buffered_size);
650 if (i > cnt)
651 i = cnt;
wdenkbf9e3b32004-02-12 00:47:09 +0000652 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
wdenk5653fc32004-02-08 22:55:38 +0000653 return rc;
Wolfgang Denk8d4ba3d2005-08-12 22:35:59 +0200654 i -= i & (info->portwidth - 1);
wdenk5653fc32004-02-08 22:55:38 +0000655 wp += i;
656 src += i;
wdenkbf9e3b32004-02-12 00:47:09 +0000657 cnt -= i;
wdenk5653fc32004-02-08 22:55:38 +0000658 }
659#else
wdenkbf9e3b32004-02-12 00:47:09 +0000660 while (cnt >= info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +0000661 cword.l = 0;
wdenkbf9e3b32004-02-12 00:47:09 +0000662 for (i = 0; i < info->portwidth; i++) {
663 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +0000664 }
wdenkbf9e3b32004-02-12 00:47:09 +0000665 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk5653fc32004-02-08 22:55:38 +0000666 return rc;
667 wp += info->portwidth;
668 cnt -= info->portwidth;
669 }
670#endif /* CFG_FLASH_USE_BUFFER_WRITE */
671 if (cnt == 0) {
672 return (0);
673 }
674
675 /*
676 * handle unaligned tail bytes
677 */
678 cword.l = 0;
wdenkbf9e3b32004-02-12 00:47:09 +0000679 for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) {
680 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +0000681 --cnt;
682 }
wdenkbf9e3b32004-02-12 00:47:09 +0000683 for (; i < info->portwidth; ++i, ++cp) {
684 flash_add_byte (info, &cword, (*(uchar *) cp));
wdenk5653fc32004-02-08 22:55:38 +0000685 }
686
wdenkbf9e3b32004-02-12 00:47:09 +0000687 return flash_write_cfiword (info, wp, cword);
wdenk5653fc32004-02-08 22:55:38 +0000688}
689
690/*-----------------------------------------------------------------------
691 */
692#ifdef CFG_FLASH_PROTECTION
693
wdenkbf9e3b32004-02-12 00:47:09 +0000694int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk5653fc32004-02-08 22:55:38 +0000695{
696 int retcode = 0;
697
wdenkbf9e3b32004-02-12 00:47:09 +0000698 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
699 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
700 if (prot)
701 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
wdenk5653fc32004-02-08 22:55:38 +0000702 else
wdenkbf9e3b32004-02-12 00:47:09 +0000703 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
wdenk5653fc32004-02-08 22:55:38 +0000704
wdenkbf9e3b32004-02-12 00:47:09 +0000705 if ((retcode =
706 flash_full_status_check (info, sector, info->erase_blk_tout,
707 prot ? "protect" : "unprotect")) == 0) {
wdenk5653fc32004-02-08 22:55:38 +0000708
709 info->protect[sector] = prot;
Stefan Roese2662b402006-04-01 13:41:03 +0200710
711 /*
712 * On some of Intel's flash chips (marked via legacy_unlock)
713 * unprotect unprotects all locking.
714 */
715 if ((prot == 0) && (info->legacy_unlock)) {
wdenk5653fc32004-02-08 22:55:38 +0000716 flash_sect_t i;
wdenkbf9e3b32004-02-12 00:47:09 +0000717
718 for (i = 0; i < info->sector_count; i++) {
719 if (info->protect[i])
720 flash_real_protect (info, i, 1);
wdenk5653fc32004-02-08 22:55:38 +0000721 }
722 }
723 }
wdenk5653fc32004-02-08 22:55:38 +0000724 return retcode;
wdenkbf9e3b32004-02-12 00:47:09 +0000725}
726
wdenk5653fc32004-02-08 22:55:38 +0000727/*-----------------------------------------------------------------------
728 * flash_read_user_serial - read the OneTimeProgramming cells
729 */
wdenkbf9e3b32004-02-12 00:47:09 +0000730void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
731 int len)
wdenk5653fc32004-02-08 22:55:38 +0000732{
wdenkbf9e3b32004-02-12 00:47:09 +0000733 uchar *src;
734 uchar *dst;
wdenk5653fc32004-02-08 22:55:38 +0000735
736 dst = buffer;
wdenkbf9e3b32004-02-12 00:47:09 +0000737 src = flash_make_addr (info, 0, FLASH_OFFSET_USER_PROTECTION);
738 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
739 memcpy (dst, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +0200740 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenk5653fc32004-02-08 22:55:38 +0000741}
wdenkbf9e3b32004-02-12 00:47:09 +0000742
wdenk5653fc32004-02-08 22:55:38 +0000743/*
744 * flash_read_factory_serial - read the device Id from the protection area
745 */
wdenkbf9e3b32004-02-12 00:47:09 +0000746void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
747 int len)
wdenk5653fc32004-02-08 22:55:38 +0000748{
wdenkbf9e3b32004-02-12 00:47:09 +0000749 uchar *src;
wdenkcd37d9e2004-02-10 00:03:41 +0000750
wdenkbf9e3b32004-02-12 00:47:09 +0000751 src = flash_make_addr (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
752 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
753 memcpy (buffer, src + offset, len);
Wolfgang Denkdb421e62005-09-25 16:41:22 +0200754 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenk5653fc32004-02-08 22:55:38 +0000755}
756
757#endif /* CFG_FLASH_PROTECTION */
758
wdenkbf9e3b32004-02-12 00:47:09 +0000759/*
760 * flash_is_busy - check to see if the flash is busy
761 * This routine checks the status of the chip and returns true if the chip is busy
762 */
763static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
wdenk5653fc32004-02-08 22:55:38 +0000764{
765 int retval;
wdenkbf9e3b32004-02-12 00:47:09 +0000766
767 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +0000768 case CFI_CMDSET_INTEL_STANDARD:
769 case CFI_CMDSET_INTEL_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +0000770 retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
wdenk5653fc32004-02-08 22:55:38 +0000771 break;
772 case CFI_CMDSET_AMD_STANDARD:
773 case CFI_CMDSET_AMD_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +0000774 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
wdenk5653fc32004-02-08 22:55:38 +0000775 break;
776 default:
777 retval = 0;
778 }
wdenkbf9e3b32004-02-12 00:47:09 +0000779 debug ("flash_is_busy: %d\n", retval);
wdenk5653fc32004-02-08 22:55:38 +0000780 return retval;
781}
wdenkbf9e3b32004-02-12 00:47:09 +0000782
wdenk5653fc32004-02-08 22:55:38 +0000783/*-----------------------------------------------------------------------
784 * wait for XSR.7 to be set. Time out with an error if it does not.
785 * This routine does not set the flash to read-array mode.
786 */
wdenkbf9e3b32004-02-12 00:47:09 +0000787static int flash_status_check (flash_info_t * info, flash_sect_t sector,
788 ulong tout, char *prompt)
wdenk5653fc32004-02-08 22:55:38 +0000789{
790 ulong start;
791
Stefan Roese2662b402006-04-01 13:41:03 +0200792#if CFG_HZ != 1000
793 tout *= CFG_HZ/1000;
794#endif
795
wdenk5653fc32004-02-08 22:55:38 +0000796 /* Wait for command completion */
797 start = get_timer (0);
wdenkbf9e3b32004-02-12 00:47:09 +0000798 while (flash_is_busy (info, sector)) {
Stefan Roese79b4cda2006-02-28 15:29:58 +0100799 if (get_timer (start) > tout) {
wdenkbf9e3b32004-02-12 00:47:09 +0000800 printf ("Flash %s timeout at address %lx data %lx\n",
801 prompt, info->start[sector],
802 flash_read_long (info, sector, 0));
803 flash_write_cmd (info, sector, 0, info->cmd_reset);
wdenk5653fc32004-02-08 22:55:38 +0000804 return ERR_TIMOUT;
805 }
Wolfgang Denk62b8f542006-06-02 11:46:20 +0200806 udelay (1); /* also triggers watchdog */
wdenk5653fc32004-02-08 22:55:38 +0000807 }
808 return ERR_OK;
809}
wdenkbf9e3b32004-02-12 00:47:09 +0000810
wdenk5653fc32004-02-08 22:55:38 +0000811/*-----------------------------------------------------------------------
812 * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check.
813 * This routine sets the flash to read-array mode.
814 */
wdenkbf9e3b32004-02-12 00:47:09 +0000815static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
816 ulong tout, char *prompt)
wdenk5653fc32004-02-08 22:55:38 +0000817{
818 int retcode;
wdenkbf9e3b32004-02-12 00:47:09 +0000819
820 retcode = flash_status_check (info, sector, tout, prompt);
821 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +0000822 case CFI_CMDSET_INTEL_EXTENDED:
823 case CFI_CMDSET_INTEL_STANDARD:
Stefan Roese79b4cda2006-02-28 15:29:58 +0100824 if ((retcode == ERR_OK)
wdenkbf9e3b32004-02-12 00:47:09 +0000825 && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
wdenk5653fc32004-02-08 22:55:38 +0000826 retcode = ERR_INVAL;
wdenkbf9e3b32004-02-12 00:47:09 +0000827 printf ("Flash %s error at address %lx\n", prompt,
828 info->start[sector]);
wdenk028ab6b2004-02-23 23:54:43 +0000829 if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) {
wdenk4b9206e2004-03-23 22:14:11 +0000830 puts ("Command Sequence Error.\n");
wdenk028ab6b2004-02-23 23:54:43 +0000831 } else if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS)) {
wdenk4b9206e2004-03-23 22:14:11 +0000832 puts ("Block Erase Error.\n");
wdenk5653fc32004-02-08 22:55:38 +0000833 retcode = ERR_NOT_ERASED;
wdenk028ab6b2004-02-23 23:54:43 +0000834 } else if (flash_isset (info, sector, 0, FLASH_STATUS_PSLBS)) {
wdenk4b9206e2004-03-23 22:14:11 +0000835 puts ("Locking Error\n");
wdenk5653fc32004-02-08 22:55:38 +0000836 }
wdenkbf9e3b32004-02-12 00:47:09 +0000837 if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
wdenk4b9206e2004-03-23 22:14:11 +0000838 puts ("Block locked.\n");
wdenkbf9e3b32004-02-12 00:47:09 +0000839 retcode = ERR_PROTECTED;
840 }
841 if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
wdenk4b9206e2004-03-23 22:14:11 +0000842 puts ("Vpp Low Error.\n");
wdenk5653fc32004-02-08 22:55:38 +0000843 }
Wolfgang Denkdb421e62005-09-25 16:41:22 +0200844 flash_write_cmd (info, sector, 0, info->cmd_reset);
wdenk5653fc32004-02-08 22:55:38 +0000845 break;
846 default:
847 break;
848 }
849 return retcode;
850}
wdenkbf9e3b32004-02-12 00:47:09 +0000851
wdenk5653fc32004-02-08 22:55:38 +0000852/*-----------------------------------------------------------------------
853 */
wdenkbf9e3b32004-02-12 00:47:09 +0000854static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
wdenk5653fc32004-02-08 22:55:38 +0000855{
wdenk4d13cba2004-03-14 14:09:05 +0000856#if defined(__LITTLE_ENDIAN)
857 unsigned short w;
858 unsigned int l;
859 unsigned long long ll;
860#endif
861
wdenkbf9e3b32004-02-12 00:47:09 +0000862 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +0000863 case FLASH_CFI_8BIT:
864 cword->c = c;
865 break;
866 case FLASH_CFI_16BIT:
wdenk4d13cba2004-03-14 14:09:05 +0000867#if defined(__LITTLE_ENDIAN)
868 w = c;
869 w <<= 8;
870 cword->w = (cword->w >> 8) | w;
871#else
wdenk5653fc32004-02-08 22:55:38 +0000872 cword->w = (cword->w << 8) | c;
wdenk4d13cba2004-03-14 14:09:05 +0000873#endif
wdenk5653fc32004-02-08 22:55:38 +0000874 break;
875 case FLASH_CFI_32BIT:
wdenk4d13cba2004-03-14 14:09:05 +0000876#if defined(__LITTLE_ENDIAN)
877 l = c;
878 l <<= 24;
879 cword->l = (cword->l >> 8) | l;
880#else
wdenk5653fc32004-02-08 22:55:38 +0000881 cword->l = (cword->l << 8) | c;
wdenk4d13cba2004-03-14 14:09:05 +0000882#endif
wdenk5653fc32004-02-08 22:55:38 +0000883 break;
884 case FLASH_CFI_64BIT:
wdenk4d13cba2004-03-14 14:09:05 +0000885#if defined(__LITTLE_ENDIAN)
886 ll = c;
887 ll <<= 56;
888 cword->ll = (cword->ll >> 8) | ll;
889#else
wdenk5653fc32004-02-08 22:55:38 +0000890 cword->ll = (cword->ll << 8) | c;
wdenk4d13cba2004-03-14 14:09:05 +0000891#endif
wdenk5653fc32004-02-08 22:55:38 +0000892 break;
893 }
894}
895
896
897/*-----------------------------------------------------------------------
898 * make a proper sized command based on the port and chip widths
899 */
wdenkbf9e3b32004-02-12 00:47:09 +0000900static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
wdenk5653fc32004-02-08 22:55:38 +0000901{
902 int i;
wdenkbf9e3b32004-02-12 00:47:09 +0000903 uchar *cp = (uchar *) cmdbuf;
904
wdenkbf9e3b32004-02-12 00:47:09 +0000905#if defined(__LITTLE_ENDIAN)
Wolfgang Denkdafbe372005-09-24 23:32:48 +0200906 for (i = info->portwidth; i > 0; i--)
907#else
908 for (i = 1; i <= info->portwidth; i++)
wdenkbf9e3b32004-02-12 00:47:09 +0000909#endif
Wolfgang Denk47340a42005-10-09 00:25:58 +0200910 *cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;
wdenk5653fc32004-02-08 22:55:38 +0000911}
912
913/*
914 * Write a proper sized command to the correct address
915 */
wdenk028ab6b2004-02-23 23:54:43 +0000916static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk5653fc32004-02-08 22:55:38 +0000917{
918
919 volatile cfiptr_t addr;
920 cfiword_t cword;
wdenkbf9e3b32004-02-12 00:47:09 +0000921
922 addr.cp = flash_make_addr (info, sect, offset);
923 flash_make_cmd (info, cmd, &cword);
924 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +0000925 case FLASH_CFI_8BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000926 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr.cp, cmd,
927 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
wdenk5653fc32004-02-08 22:55:38 +0000928 *addr.cp = cword.c;
Wolfgang Denk0afe5192006-03-12 02:10:00 +0100929#ifdef CONFIG_BLACKFIN
930 asm("ssync;");
931#endif
wdenk5653fc32004-02-08 22:55:38 +0000932 break;
933 case FLASH_CFI_16BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000934 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr.wp,
935 cmd, cword.w,
wdenk5653fc32004-02-08 22:55:38 +0000936 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
937 *addr.wp = cword.w;
Wolfgang Denk0afe5192006-03-12 02:10:00 +0100938#ifdef CONFIG_BLACKFIN
939 asm("ssync;");
940#endif
wdenk5653fc32004-02-08 22:55:38 +0000941 break;
942 case FLASH_CFI_32BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000943 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr.lp,
944 cmd, cword.l,
wdenk5653fc32004-02-08 22:55:38 +0000945 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
946 *addr.lp = cword.l;
Wolfgang Denk0afe5192006-03-12 02:10:00 +0100947#ifdef CONFIG_BLACKFIN
948 asm("ssync;");
949#endif
wdenk5653fc32004-02-08 22:55:38 +0000950 break;
951 case FLASH_CFI_64BIT:
952#ifdef DEBUG
wdenkbf9e3b32004-02-12 00:47:09 +0000953 {
wdenk5653fc32004-02-08 22:55:38 +0000954 char str[20];
wdenkcd37d9e2004-02-10 00:03:41 +0000955
wdenkbf9e3b32004-02-12 00:47:09 +0000956 print_longlong (str, cword.ll);
957
958 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
959 addr.llp, cmd, str,
wdenk5653fc32004-02-08 22:55:38 +0000960 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
961 }
962#endif
963 *addr.llp = cword.ll;
Wolfgang Denk0afe5192006-03-12 02:10:00 +0100964#ifdef CONFIG_BLACKFIN
965 asm("ssync;");
966#endif
wdenk5653fc32004-02-08 22:55:38 +0000967 break;
968 }
969}
970
wdenkbf9e3b32004-02-12 00:47:09 +0000971static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
wdenk5653fc32004-02-08 22:55:38 +0000972{
wdenk855a4962004-03-14 18:23:55 +0000973 flash_write_cmd (info, sect, AMD_ADDR_START, AMD_CMD_UNLOCK_START);
974 flash_write_cmd (info, sect, AMD_ADDR_ACK, AMD_CMD_UNLOCK_ACK);
wdenk5653fc32004-02-08 22:55:38 +0000975}
wdenkbf9e3b32004-02-12 00:47:09 +0000976
wdenk5653fc32004-02-08 22:55:38 +0000977/*-----------------------------------------------------------------------
978 */
wdenk028ab6b2004-02-23 23:54:43 +0000979static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk5653fc32004-02-08 22:55:38 +0000980{
981 cfiptr_t cptr;
982 cfiword_t cword;
983 int retval;
wdenk5653fc32004-02-08 22:55:38 +0000984
wdenkbf9e3b32004-02-12 00:47:09 +0000985 cptr.cp = flash_make_addr (info, sect, offset);
986 flash_make_cmd (info, cmd, &cword);
987
988 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, cptr.cp);
989 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +0000990 case FLASH_CFI_8BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000991 debug ("is= %x %x\n", cptr.cp[0], cword.c);
wdenk5653fc32004-02-08 22:55:38 +0000992 retval = (cptr.cp[0] == cword.c);
993 break;
994 case FLASH_CFI_16BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000995 debug ("is= %4.4x %4.4x\n", cptr.wp[0], cword.w);
wdenk5653fc32004-02-08 22:55:38 +0000996 retval = (cptr.wp[0] == cword.w);
997 break;
998 case FLASH_CFI_32BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000999 debug ("is= %8.8lx %8.8lx\n", cptr.lp[0], cword.l);
wdenk5653fc32004-02-08 22:55:38 +00001000 retval = (cptr.lp[0] == cword.l);
1001 break;
1002 case FLASH_CFI_64BIT:
wdenkcd37d9e2004-02-10 00:03:41 +00001003#ifdef DEBUG
wdenkbf9e3b32004-02-12 00:47:09 +00001004 {
wdenk5653fc32004-02-08 22:55:38 +00001005 char str1[20];
1006 char str2[20];
wdenkbf9e3b32004-02-12 00:47:09 +00001007
1008 print_longlong (str1, cptr.llp[0]);
1009 print_longlong (str2, cword.ll);
1010 debug ("is= %s %s\n", str1, str2);
wdenk5653fc32004-02-08 22:55:38 +00001011 }
1012#endif
1013 retval = (cptr.llp[0] == cword.ll);
1014 break;
1015 default:
1016 retval = 0;
1017 break;
1018 }
1019 return retval;
1020}
wdenkbf9e3b32004-02-12 00:47:09 +00001021
wdenk5653fc32004-02-08 22:55:38 +00001022/*-----------------------------------------------------------------------
1023 */
wdenk028ab6b2004-02-23 23:54:43 +00001024static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk5653fc32004-02-08 22:55:38 +00001025{
1026 cfiptr_t cptr;
1027 cfiword_t cword;
1028 int retval;
wdenkbf9e3b32004-02-12 00:47:09 +00001029
1030 cptr.cp = flash_make_addr (info, sect, offset);
1031 flash_make_cmd (info, cmd, &cword);
1032 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001033 case FLASH_CFI_8BIT:
1034 retval = ((cptr.cp[0] & cword.c) == cword.c);
1035 break;
1036 case FLASH_CFI_16BIT:
1037 retval = ((cptr.wp[0] & cword.w) == cword.w);
1038 break;
1039 case FLASH_CFI_32BIT:
1040 retval = ((cptr.lp[0] & cword.l) == cword.l);
1041 break;
1042 case FLASH_CFI_64BIT:
1043 retval = ((cptr.llp[0] & cword.ll) == cword.ll);
wdenkbf9e3b32004-02-12 00:47:09 +00001044 break;
wdenk5653fc32004-02-08 22:55:38 +00001045 default:
1046 retval = 0;
1047 break;
1048 }
1049 return retval;
1050}
1051
1052/*-----------------------------------------------------------------------
1053 */
wdenk028ab6b2004-02-23 23:54:43 +00001054static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk5653fc32004-02-08 22:55:38 +00001055{
1056 cfiptr_t cptr;
1057 cfiword_t cword;
1058 int retval;
wdenkbf9e3b32004-02-12 00:47:09 +00001059
1060 cptr.cp = flash_make_addr (info, sect, offset);
1061 flash_make_cmd (info, cmd, &cword);
1062 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001063 case FLASH_CFI_8BIT:
1064 retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c));
1065 break;
1066 case FLASH_CFI_16BIT:
1067 retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w));
1068 break;
1069 case FLASH_CFI_32BIT:
1070 retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l));
1071 break;
1072 case FLASH_CFI_64BIT:
wdenkbf9e3b32004-02-12 00:47:09 +00001073 retval = ((cptr.llp[0] & cword.ll) !=
1074 (cptr.llp[0] & cword.ll));
wdenk5653fc32004-02-08 22:55:38 +00001075 break;
1076 default:
1077 retval = 0;
1078 break;
1079 }
1080 return retval;
1081}
1082
1083/*-----------------------------------------------------------------------
Stefan Roese260421a2006-11-13 13:55:24 +01001084 * read jedec ids from device and set corresponding fields in info struct
1085 *
1086 * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
1087 *
1088*/
1089static void flash_read_jedec_ids (flash_info_t * info)
1090{
1091 info->manufacturer_id = 0;
1092 info->device_id = 0;
1093 info->device_id2 = 0;
1094
1095 switch (info->vendor) {
1096 case CFI_CMDSET_INTEL_STANDARD:
1097 case CFI_CMDSET_INTEL_EXTENDED:
1098 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1099 flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
1100 udelay(1000); /* some flash are slow to respond */
1101 info->manufacturer_id = flash_read_uchar (info,
1102 FLASH_OFFSET_MANUFACTURER_ID);
1103 info->device_id = flash_read_uchar (info,
1104 FLASH_OFFSET_DEVICE_ID);
1105 flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
1106 break;
1107 case CFI_CMDSET_AMD_STANDARD:
1108 case CFI_CMDSET_AMD_EXTENDED:
1109 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1110 flash_unlock_seq(info, 0);
1111 flash_write_cmd(info, 0, AMD_ADDR_START, FLASH_CMD_READ_ID);
1112 udelay(1000); /* some flash are slow to respond */
1113 info->manufacturer_id = flash_read_uchar (info,
1114 FLASH_OFFSET_MANUFACTURER_ID);
1115 info->device_id = flash_read_uchar (info,
1116 FLASH_OFFSET_DEVICE_ID);
1117 if (info->device_id == 0x7E) {
1118 /* AMD 3-byte (expanded) device ids */
1119 info->device_id2 = flash_read_uchar (info,
1120 FLASH_OFFSET_DEVICE_ID2);
1121 info->device_id2 <<= 8;
1122 info->device_id2 |= flash_read_uchar (info,
1123 FLASH_OFFSET_DEVICE_ID3);
1124 }
1125 flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
1126 break;
1127 default:
1128 break;
1129 }
1130}
1131
1132/*-----------------------------------------------------------------------
wdenk5653fc32004-02-08 22:55:38 +00001133 * detect if flash is compatible with the Common Flash Interface (CFI)
1134 * http://www.jedec.org/download/search/jesd68.pdf
1135 *
1136*/
wdenkbf9e3b32004-02-12 00:47:09 +00001137static int flash_detect_cfi (flash_info_t * info)
wdenk5653fc32004-02-08 22:55:38 +00001138{
wdenkbf9e3b32004-02-12 00:47:09 +00001139 debug ("flash detect cfi\n");
wdenk5653fc32004-02-08 22:55:38 +00001140
Stefan Roese79b4cda2006-02-28 15:29:58 +01001141 for (info->portwidth = CFG_FLASH_CFI_WIDTH;
wdenkbf9e3b32004-02-12 00:47:09 +00001142 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
1143 for (info->chipwidth = FLASH_CFI_BY8;
1144 info->chipwidth <= info->portwidth;
1145 info->chipwidth <<= 1) {
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001146 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenk028ab6b2004-02-23 23:54:43 +00001147 flash_write_cmd (info, 0, FLASH_OFFSET_CFI, FLASH_CMD_CFI);
1148 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1149 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1150 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
1151 info->interface = flash_read_ushort (info, 0, FLASH_OFFSET_INTERFACE);
wdenkbf9e3b32004-02-12 00:47:09 +00001152 debug ("device interface is %d\n",
1153 info->interface);
1154 debug ("found port %d chip %d ",
1155 info->portwidth, info->chipwidth);
1156 debug ("port %d bits chip %d bits\n",
wdenk028ab6b2004-02-23 23:54:43 +00001157 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1158 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
wdenk5653fc32004-02-08 22:55:38 +00001159 return 1;
1160 }
1161 }
1162 }
wdenkbf9e3b32004-02-12 00:47:09 +00001163 debug ("not found\n");
wdenk5653fc32004-02-08 22:55:38 +00001164 return 0;
1165}
wdenkbf9e3b32004-02-12 00:47:09 +00001166
wdenk5653fc32004-02-08 22:55:38 +00001167/*
1168 * The following code cannot be run from FLASH!
1169 *
1170 */
Marian Balakowicze6f2e902005-10-11 19:09:42 +02001171ulong flash_get_size (ulong base, int banknum)
wdenk5653fc32004-02-08 22:55:38 +00001172{
wdenkbf9e3b32004-02-12 00:47:09 +00001173 flash_info_t *info = &flash_info[banknum];
wdenk5653fc32004-02-08 22:55:38 +00001174 int i, j;
1175 flash_sect_t sect_cnt;
1176 unsigned long sector;
1177 unsigned long tmp;
1178 int size_ratio;
1179 uchar num_erase_regions;
wdenkbf9e3b32004-02-12 00:47:09 +00001180 int erase_region_size;
1181 int erase_region_count;
Stefan Roese260421a2006-11-13 13:55:24 +01001182 int geometry_reversed = 0;
1183
1184 info->ext_addr = 0;
1185 info->cfi_version = 0;
Stefan Roese2662b402006-04-01 13:41:03 +02001186#ifdef CFG_FLASH_PROTECTION
Stefan Roese2662b402006-04-01 13:41:03 +02001187 info->legacy_unlock = 0;
1188#endif
wdenk5653fc32004-02-08 22:55:38 +00001189
1190 info->start[0] = base;
1191
wdenkbf9e3b32004-02-12 00:47:09 +00001192 if (flash_detect_cfi (info)) {
Stefan Roese260421a2006-11-13 13:55:24 +01001193 info->vendor = flash_read_ushort (info, 0,
1194 FLASH_OFFSET_PRIMARY_VENDOR);
1195 flash_read_jedec_ids (info);
1196 flash_write_cmd (info, 0, FLASH_OFFSET_CFI, FLASH_CMD_CFI);
1197 num_erase_regions = flash_read_uchar (info,
1198 FLASH_OFFSET_NUM_ERASE_REGIONS);
1199 info->ext_addr = flash_read_ushort (info, 0,
1200 FLASH_OFFSET_EXT_QUERY_T_P_ADDR);
1201 if (info->ext_addr) {
1202 info->cfi_version = (ushort) flash_read_uchar (info,
1203 info->ext_addr + 3) << 8;
1204 info->cfi_version |= (ushort) flash_read_uchar (info,
1205 info->ext_addr + 4);
1206 }
wdenkbf9e3b32004-02-12 00:47:09 +00001207#ifdef DEBUG
1208 flash_printqry (info, 0);
1209#endif
1210 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +00001211 case CFI_CMDSET_INTEL_STANDARD:
1212 case CFI_CMDSET_INTEL_EXTENDED:
1213 default:
1214 info->cmd_reset = FLASH_CMD_RESET;
Stefan Roese2662b402006-04-01 13:41:03 +02001215#ifdef CFG_FLASH_PROTECTION
1216 /* read legacy lock/unlock bit from intel flash */
Stefan Roese260421a2006-11-13 13:55:24 +01001217 if (info->ext_addr) {
1218 info->legacy_unlock = flash_read_uchar (info,
1219 info->ext_addr + 5) & 0x08;
1220 }
Stefan Roese2662b402006-04-01 13:41:03 +02001221#endif
wdenk5653fc32004-02-08 22:55:38 +00001222 break;
1223 case CFI_CMDSET_AMD_STANDARD:
1224 case CFI_CMDSET_AMD_EXTENDED:
1225 info->cmd_reset = AMD_CMD_RESET;
Stefan Roese260421a2006-11-13 13:55:24 +01001226 /* check if flash geometry needs reversal */
1227 if (num_erase_regions <= 1)
1228 break;
1229 /* reverse geometry if top boot part */
1230 if (info->cfi_version < 0x3131) {
1231 /* CFI < 1.1, try to guess from device id */
1232 if ((info->device_id & 0x80) != 0) {
1233 geometry_reversed = 1;
1234 }
1235 break;
1236 }
1237 /* CFI >= 1.1, deduct from top/bottom flag */
1238 /* note: ext_addr is valid since cfi_version > 0 */
1239 if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
1240 geometry_reversed = 1;
1241 }
wdenk5653fc32004-02-08 22:55:38 +00001242 break;
1243 }
wdenkcd37d9e2004-02-10 00:03:41 +00001244
wdenkbf9e3b32004-02-12 00:47:09 +00001245 debug ("manufacturer is %d\n", info->vendor);
Stefan Roese260421a2006-11-13 13:55:24 +01001246 debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
1247 debug ("device id is 0x%x\n", info->device_id);
1248 debug ("device id2 is 0x%x\n", info->device_id2);
1249 debug ("cfi version is 0x%04x\n", info->cfi_version);
1250
wdenk5653fc32004-02-08 22:55:38 +00001251 size_ratio = info->portwidth / info->chipwidth;
wdenkbf9e3b32004-02-12 00:47:09 +00001252 /* if the chip is x8/x16 reduce the ratio by half */
1253 if ((info->interface == FLASH_CFI_X8X16)
1254 && (info->chipwidth == FLASH_CFI_BY8)) {
1255 size_ratio >>= 1;
1256 }
wdenkbf9e3b32004-02-12 00:47:09 +00001257 debug ("size_ratio %d port %d bits chip %d bits\n",
1258 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1259 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1260 debug ("found %d erase regions\n", num_erase_regions);
wdenk5653fc32004-02-08 22:55:38 +00001261 sect_cnt = 0;
1262 sector = base;
wdenkbf9e3b32004-02-12 00:47:09 +00001263 for (i = 0; i < num_erase_regions; i++) {
1264 if (i > NUM_ERASE_REGIONS) {
wdenk028ab6b2004-02-23 23:54:43 +00001265 printf ("%d erase regions found, only %d used\n",
1266 num_erase_regions, NUM_ERASE_REGIONS);
wdenk5653fc32004-02-08 22:55:38 +00001267 break;
1268 }
Stefan Roese260421a2006-11-13 13:55:24 +01001269 if (geometry_reversed)
1270 tmp = flash_read_long (info, 0,
1271 FLASH_OFFSET_ERASE_REGIONS +
1272 (num_erase_regions - 1 - i) * 4);
1273 else
1274 tmp = flash_read_long (info, 0,
wdenkbf9e3b32004-02-12 00:47:09 +00001275 FLASH_OFFSET_ERASE_REGIONS +
1276 i * 4);
1277 erase_region_size =
1278 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenk5653fc32004-02-08 22:55:38 +00001279 tmp >>= 16;
wdenkbf9e3b32004-02-12 00:47:09 +00001280 erase_region_count = (tmp & 0xffff) + 1;
wdenk4c0d4c32004-06-09 17:34:58 +00001281 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenk028ab6b2004-02-23 23:54:43 +00001282 erase_region_count, erase_region_size);
wdenkbf9e3b32004-02-12 00:47:09 +00001283 for (j = 0; j < erase_region_count; j++) {
wdenk5653fc32004-02-08 22:55:38 +00001284 info->start[sect_cnt] = sector;
1285 sector += (erase_region_size * size_ratio);
wdenka1191902005-01-09 17:12:27 +00001286
1287 /*
1288 * Only read protection status from supported devices (intel...)
1289 */
1290 switch (info->vendor) {
1291 case CFI_CMDSET_INTEL_EXTENDED:
1292 case CFI_CMDSET_INTEL_STANDARD:
1293 info->protect[sect_cnt] =
1294 flash_isset (info, sect_cnt,
1295 FLASH_OFFSET_PROTECT,
1296 FLASH_STATUS_PROTECT);
1297 break;
1298 default:
1299 info->protect[sect_cnt] = 0; /* default: not protected */
1300 }
1301
wdenk5653fc32004-02-08 22:55:38 +00001302 sect_cnt++;
1303 }
1304 }
1305
1306 info->sector_count = sect_cnt;
1307 /* multiply the size by the number of chips */
wdenk028ab6b2004-02-23 23:54:43 +00001308 info->size = (1 << flash_read_uchar (info, FLASH_OFFSET_SIZE)) * size_ratio;
1309 info->buffer_size = (1 << flash_read_ushort (info, 0, FLASH_OFFSET_BUFFER_SIZE));
wdenkbf9e3b32004-02-12 00:47:09 +00001310 tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT);
wdenk028ab6b2004-02-23 23:54:43 +00001311 info->erase_blk_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_EMAX_TOUT)));
Stefan Roese2662b402006-04-01 13:41:03 +02001312 tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT)) *
1313 (1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT));
1314 info->buffer_write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */
Stefan Roese79b4cda2006-02-28 15:29:58 +01001315 tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT)) *
1316 (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT));
1317 info->write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */
wdenk5653fc32004-02-08 22:55:38 +00001318 info->flash_id = FLASH_MAN_CFI;
wdenk855a4962004-03-14 18:23:55 +00001319 if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) {
1320 info->portwidth >>= 1; /* XXX - Need to test on x8/x16 in parallel. */
1321 }
wdenk5653fc32004-02-08 22:55:38 +00001322 }
1323
Wolfgang Denkdb421e62005-09-25 16:41:22 +02001324 flash_write_cmd (info, 0, 0, info->cmd_reset);
wdenkbf9e3b32004-02-12 00:47:09 +00001325 return (info->size);
wdenk5653fc32004-02-08 22:55:38 +00001326}
1327
Stefan Roese79b4cda2006-02-28 15:29:58 +01001328/* loop through the sectors from the highest address
1329 * when the passed address is greater or equal to the sector address
1330 * we have a match
1331 */
1332static flash_sect_t find_sector (flash_info_t * info, ulong addr)
1333{
1334 flash_sect_t sector;
1335
1336 for (sector = info->sector_count - 1; sector >= 0; sector--) {
1337 if (addr >= info->start[sector])
1338 break;
1339 }
1340 return sector;
1341}
wdenk5653fc32004-02-08 22:55:38 +00001342
1343/*-----------------------------------------------------------------------
1344 */
wdenkbf9e3b32004-02-12 00:47:09 +00001345static int flash_write_cfiword (flash_info_t * info, ulong dest,
1346 cfiword_t cword)
wdenk5653fc32004-02-08 22:55:38 +00001347{
wdenk5653fc32004-02-08 22:55:38 +00001348 cfiptr_t ctladdr;
1349 cfiptr_t cptr;
1350 int flag;
1351
wdenkbf9e3b32004-02-12 00:47:09 +00001352 ctladdr.cp = flash_make_addr (info, 0, 0);
1353 cptr.cp = (uchar *) dest;
wdenk5653fc32004-02-08 22:55:38 +00001354
1355
1356 /* Check if Flash is (sufficiently) erased */
wdenkbf9e3b32004-02-12 00:47:09 +00001357 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001358 case FLASH_CFI_8BIT:
1359 flag = ((cptr.cp[0] & cword.c) == cword.c);
1360 break;
1361 case FLASH_CFI_16BIT:
1362 flag = ((cptr.wp[0] & cword.w) == cword.w);
1363 break;
1364 case FLASH_CFI_32BIT:
wdenkbf9e3b32004-02-12 00:47:09 +00001365 flag = ((cptr.lp[0] & cword.l) == cword.l);
wdenk5653fc32004-02-08 22:55:38 +00001366 break;
1367 case FLASH_CFI_64BIT:
wdenke1599e82004-10-10 23:27:33 +00001368 flag = ((cptr.llp[0] & cword.ll) == cword.ll);
wdenk5653fc32004-02-08 22:55:38 +00001369 break;
1370 default:
1371 return 2;
1372 }
wdenkbf9e3b32004-02-12 00:47:09 +00001373 if (!flag)
wdenk5653fc32004-02-08 22:55:38 +00001374 return 2;
1375
1376 /* Disable interrupts which might cause a timeout here */
wdenkbf9e3b32004-02-12 00:47:09 +00001377 flag = disable_interrupts ();
wdenk5653fc32004-02-08 22:55:38 +00001378
wdenkbf9e3b32004-02-12 00:47:09 +00001379 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +00001380 case CFI_CMDSET_INTEL_EXTENDED:
1381 case CFI_CMDSET_INTEL_STANDARD:
wdenkbf9e3b32004-02-12 00:47:09 +00001382 flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
1383 flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
wdenk5653fc32004-02-08 22:55:38 +00001384 break;
1385 case CFI_CMDSET_AMD_EXTENDED:
1386 case CFI_CMDSET_AMD_STANDARD:
wdenkbf9e3b32004-02-12 00:47:09 +00001387 flash_unlock_seq (info, 0);
wdenk855a4962004-03-14 18:23:55 +00001388 flash_write_cmd (info, 0, AMD_ADDR_START, AMD_CMD_WRITE);
wdenk5653fc32004-02-08 22:55:38 +00001389 break;
1390 }
1391
wdenkbf9e3b32004-02-12 00:47:09 +00001392 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001393 case FLASH_CFI_8BIT:
1394 cptr.cp[0] = cword.c;
1395 break;
1396 case FLASH_CFI_16BIT:
1397 cptr.wp[0] = cword.w;
1398 break;
1399 case FLASH_CFI_32BIT:
1400 cptr.lp[0] = cword.l;
1401 break;
1402 case FLASH_CFI_64BIT:
1403 cptr.llp[0] = cword.ll;
1404 break;
1405 }
1406
1407 /* re-enable interrupts if necessary */
wdenkbf9e3b32004-02-12 00:47:09 +00001408 if (flag)
1409 enable_interrupts ();
wdenk5653fc32004-02-08 22:55:38 +00001410
Stefan Roese79b4cda2006-02-28 15:29:58 +01001411 return flash_full_status_check (info, find_sector (info, dest),
1412 info->write_tout, "write");
wdenk5653fc32004-02-08 22:55:38 +00001413}
1414
1415#ifdef CFG_FLASH_USE_BUFFER_WRITE
1416
wdenkbf9e3b32004-02-12 00:47:09 +00001417static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
1418 int len)
wdenk5653fc32004-02-08 22:55:38 +00001419{
1420 flash_sect_t sector;
1421 int cnt;
1422 int retcode;
1423 volatile cfiptr_t src;
1424 volatile cfiptr_t dst;
1425
Stefan Roese79b4cda2006-02-28 15:29:58 +01001426 switch (info->vendor) {
1427 case CFI_CMDSET_INTEL_STANDARD:
1428 case CFI_CMDSET_INTEL_EXTENDED:
1429 src.cp = cp;
1430 dst.cp = (uchar *) dest;
1431 sector = find_sector (info, dest);
1432 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1433 flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
1434 if ((retcode = flash_status_check (info, sector, info->buffer_write_tout,
1435 "write to buffer")) == ERR_OK) {
1436 /* reduce the number of loops by the width of the port */
wdenkbf9e3b32004-02-12 00:47:09 +00001437 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001438 case FLASH_CFI_8BIT:
Stefan Roese79b4cda2006-02-28 15:29:58 +01001439 cnt = len;
wdenk5653fc32004-02-08 22:55:38 +00001440 break;
1441 case FLASH_CFI_16BIT:
Stefan Roese79b4cda2006-02-28 15:29:58 +01001442 cnt = len >> 1;
wdenk5653fc32004-02-08 22:55:38 +00001443 break;
1444 case FLASH_CFI_32BIT:
Stefan Roese79b4cda2006-02-28 15:29:58 +01001445 cnt = len >> 2;
wdenk5653fc32004-02-08 22:55:38 +00001446 break;
1447 case FLASH_CFI_64BIT:
Stefan Roese79b4cda2006-02-28 15:29:58 +01001448 cnt = len >> 3;
wdenk5653fc32004-02-08 22:55:38 +00001449 break;
1450 default:
1451 return ERR_INVAL;
1452 break;
1453 }
Stefan Roese79b4cda2006-02-28 15:29:58 +01001454 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
1455 while (cnt-- > 0) {
1456 switch (info->portwidth) {
1457 case FLASH_CFI_8BIT:
1458 *dst.cp++ = *src.cp++;
1459 break;
1460 case FLASH_CFI_16BIT:
1461 *dst.wp++ = *src.wp++;
1462 break;
1463 case FLASH_CFI_32BIT:
1464 *dst.lp++ = *src.lp++;
1465 break;
1466 case FLASH_CFI_64BIT:
1467 *dst.llp++ = *src.llp++;
1468 break;
1469 default:
1470 return ERR_INVAL;
1471 break;
1472 }
1473 }
1474 flash_write_cmd (info, sector, 0,
1475 FLASH_CMD_WRITE_BUFFER_CONFIRM);
1476 retcode = flash_full_status_check (info, sector,
1477 info->buffer_write_tout,
1478 "buffer write");
wdenk5653fc32004-02-08 22:55:38 +00001479 }
Stefan Roese79b4cda2006-02-28 15:29:58 +01001480 return retcode;
1481
1482 case CFI_CMDSET_AMD_STANDARD:
1483 case CFI_CMDSET_AMD_EXTENDED:
1484 src.cp = cp;
1485 dst.cp = (uchar *) dest;
1486 sector = find_sector (info, dest);
1487
1488 flash_unlock_seq(info,0);
1489 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER);
1490
1491 switch (info->portwidth) {
1492 case FLASH_CFI_8BIT:
1493 cnt = len;
1494 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
1495 while (cnt-- > 0) *dst.cp++ = *src.cp++;
1496 break;
1497 case FLASH_CFI_16BIT:
1498 cnt = len >> 1;
1499 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
1500 while (cnt-- > 0) *dst.wp++ = *src.wp++;
1501 break;
1502 case FLASH_CFI_32BIT:
1503 cnt = len >> 2;
1504 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
1505 while (cnt-- > 0) *dst.lp++ = *src.lp++;
1506 break;
1507 case FLASH_CFI_64BIT:
1508 cnt = len >> 3;
1509 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
1510 while (cnt-- > 0) *dst.llp++ = *src.llp++;
1511 break;
1512 default:
1513 return ERR_INVAL;
1514 }
1515
1516 flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
1517 retcode = flash_full_status_check (info, sector, info->buffer_write_tout,
1518 "buffer write");
1519 return retcode;
1520
1521 default:
1522 debug ("Unknown Command Set\n");
1523 return ERR_INVAL;
wdenk5653fc32004-02-08 22:55:38 +00001524 }
wdenk5653fc32004-02-08 22:55:38 +00001525}
wdenkcce625e2004-09-28 19:00:19 +00001526#endif /* CFG_FLASH_USE_BUFFER_WRITE */
wdenk5653fc32004-02-08 22:55:38 +00001527#endif /* CFG_FLASH_CFI */