blob: d31b38f1b479487507380605fa8470c03e034ccb [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>
7 * Modified to work with AMD flashes
8 *
wdenke65527f2004-02-12 00:47:09 +00009 * Copyright (C) 2004
10 * Ed Okerson
11 * Modified to work with little-endian systems.
12 *
wdenk2cefd152004-02-08 22:55:38 +000013 * See file CREDITS for list of people who contributed to this
14 * project.
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License as
18 * published by the Free Software Foundation; either version 2 of
19 * the License, or (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29 * MA 02111-1307 USA
30 *
31 * History
32 * 01/20/2004 - combined variants of original driver.
wdenke65527f2004-02-12 00:47:09 +000033 * 01/22/2004 - Write performance enhancements for parallel chips (Tolunay)
34 * 01/23/2004 - Support for x8/x16 chips (Rune Raknerud)
35 * 01/27/2004 - Little endian support Ed Okerson
wdenk2cefd152004-02-08 22:55:38 +000036 *
37 * Tested Architectures
wdenke65527f2004-02-12 00:47:09 +000038 * Port Width Chip Width # of banks Flash Chip Board
wdenk2ebee312004-02-23 19:30:57 +000039 * 32 16 1 28F128J3 seranoa/eagle
40 * 64 16 1 28F128J3 seranoa/falcon
wdenk6cfa84e2004-02-10 00:03:41 +000041 *
wdenk2cefd152004-02-08 22:55:38 +000042 */
43
44/* The DEBUG define must be before common to enable debugging */
wdenk2ebee312004-02-23 19:30:57 +000045/* #define DEBUG */
46
wdenk2cefd152004-02-08 22:55:38 +000047#include <common.h>
48#include <asm/processor.h>
wdenke537b3b2004-02-23 23:54:43 +000049#include <linux/byteorder/swab.h>
wdenke65527f2004-02-12 00:47:09 +000050#ifdef CFG_FLASH_CFI_DRIVER
wdenke537b3b2004-02-23 23:54:43 +000051
wdenk2cefd152004-02-08 22:55:38 +000052/*
53 * This file implements a Common Flash Interface (CFI) driver for U-Boot.
54 * The width of the port and the width of the chips are determined at initialization.
55 * These widths are used to calculate the address for access CFI data structures.
56 * It has been tested on an Intel Strataflash implementation and AMD 29F016D.
57 *
58 * References
59 * JEDEC Standard JESD68 - Common Flash Interface (CFI)
60 * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
61 * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
62 * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
63 *
64 * TODO
65 *
66 * Use Primary Extended Query table (PRI) and Alternate Algorithm Query
67 * Table (ALT) to determine if protection is available
68 *
69 * Add support for other command sets Use the PRI and ALT to determine command set
70 * Verify erase and program timeouts.
71 */
72
wdenke65527f2004-02-12 00:47:09 +000073#ifndef CFG_FLASH_BANKS_LIST
74#define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE }
75#endif
76
wdenk2cefd152004-02-08 22:55:38 +000077#define FLASH_CMD_CFI 0x98
78#define FLASH_CMD_READ_ID 0x90
79#define FLASH_CMD_RESET 0xff
80#define FLASH_CMD_BLOCK_ERASE 0x20
81#define FLASH_CMD_ERASE_CONFIRM 0xD0
82#define FLASH_CMD_WRITE 0x40
83#define FLASH_CMD_PROTECT 0x60
84#define FLASH_CMD_PROTECT_SET 0x01
85#define FLASH_CMD_PROTECT_CLEAR 0xD0
86#define FLASH_CMD_CLEAR_STATUS 0x50
wdenke65527f2004-02-12 00:47:09 +000087#define FLASH_CMD_WRITE_TO_BUFFER 0xE8
88#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0
wdenk2cefd152004-02-08 22:55:38 +000089
90#define FLASH_STATUS_DONE 0x80
91#define FLASH_STATUS_ESS 0x40
92#define FLASH_STATUS_ECLBS 0x20
93#define FLASH_STATUS_PSLBS 0x10
94#define FLASH_STATUS_VPENS 0x08
95#define FLASH_STATUS_PSS 0x04
96#define FLASH_STATUS_DPS 0x02
97#define FLASH_STATUS_R 0x01
98#define FLASH_STATUS_PROTECT 0x01
99
100#define AMD_CMD_RESET 0xF0
101#define AMD_CMD_WRITE 0xA0
102#define AMD_CMD_ERASE_START 0x80
103#define AMD_CMD_ERASE_SECTOR 0x30
104
105#define AMD_STATUS_TOGGLE 0x40
106#define AMD_STATUS_ERROR 0x20
107
108#define FLASH_OFFSET_CFI 0x55
109#define FLASH_OFFSET_CFI_RESP 0x10
wdenke65527f2004-02-12 00:47:09 +0000110#define FLASH_OFFSET_PRIMARY_VENDOR 0x13
wdenk2cefd152004-02-08 22:55:38 +0000111#define FLASH_OFFSET_WTOUT 0x1F
wdenke65527f2004-02-12 00:47:09 +0000112#define FLASH_OFFSET_WBTOUT 0x20
wdenk2cefd152004-02-08 22:55:38 +0000113#define FLASH_OFFSET_ETOUT 0x21
wdenke65527f2004-02-12 00:47:09 +0000114#define FLASH_OFFSET_CETOUT 0x22
wdenk2cefd152004-02-08 22:55:38 +0000115#define FLASH_OFFSET_WMAX_TOUT 0x23
wdenke65527f2004-02-12 00:47:09 +0000116#define FLASH_OFFSET_WBMAX_TOUT 0x24
wdenk2cefd152004-02-08 22:55:38 +0000117#define FLASH_OFFSET_EMAX_TOUT 0x25
wdenke65527f2004-02-12 00:47:09 +0000118#define FLASH_OFFSET_CEMAX_TOUT 0x26
wdenk2cefd152004-02-08 22:55:38 +0000119#define FLASH_OFFSET_SIZE 0x27
wdenke65527f2004-02-12 00:47:09 +0000120#define FLASH_OFFSET_INTERFACE 0x28
121#define FLASH_OFFSET_BUFFER_SIZE 0x2A
wdenk2cefd152004-02-08 22:55:38 +0000122#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C
123#define FLASH_OFFSET_ERASE_REGIONS 0x2D
124#define FLASH_OFFSET_PROTECT 0x02
wdenke65527f2004-02-12 00:47:09 +0000125#define FLASH_OFFSET_USER_PROTECTION 0x85
126#define FLASH_OFFSET_INTEL_PROTECTION 0x81
wdenk2cefd152004-02-08 22:55:38 +0000127
128
129#define FLASH_MAN_CFI 0x01000000
130
wdenke65527f2004-02-12 00:47:09 +0000131#define CFI_CMDSET_NONE 0
wdenk2cefd152004-02-08 22:55:38 +0000132#define CFI_CMDSET_INTEL_EXTENDED 1
wdenke65527f2004-02-12 00:47:09 +0000133#define CFI_CMDSET_AMD_STANDARD 2
wdenk2cefd152004-02-08 22:55:38 +0000134#define CFI_CMDSET_INTEL_STANDARD 3
wdenke65527f2004-02-12 00:47:09 +0000135#define CFI_CMDSET_AMD_EXTENDED 4
wdenk2cefd152004-02-08 22:55:38 +0000136#define CFI_CMDSET_MITSU_STANDARD 256
137#define CFI_CMDSET_MITSU_EXTENDED 257
wdenke65527f2004-02-12 00:47:09 +0000138#define CFI_CMDSET_SST 258
wdenk2cefd152004-02-08 22:55:38 +0000139
140
141typedef union {
142 unsigned char c;
143 unsigned short w;
144 unsigned long l;
145 unsigned long long ll;
146} cfiword_t;
147
148typedef union {
wdenke65527f2004-02-12 00:47:09 +0000149 volatile unsigned char *cp;
wdenk2cefd152004-02-08 22:55:38 +0000150 volatile unsigned short *wp;
wdenke65527f2004-02-12 00:47:09 +0000151 volatile unsigned long *lp;
wdenk2cefd152004-02-08 22:55:38 +0000152 volatile unsigned long long *llp;
153} cfiptr_t;
154
155#define NUM_ERASE_REGIONS 4
156
157static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST;
158
wdenke65527f2004-02-12 00:47:09 +0000159flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenk2cefd152004-02-08 22:55:38 +0000160
161/*-----------------------------------------------------------------------
162 * Functions
163 */
164
165typedef unsigned long flash_sect_t;
166
wdenke65527f2004-02-12 00:47:09 +0000167static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c);
168static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf);
wdenke537b3b2004-02-23 23:54:43 +0000169static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
wdenke65527f2004-02-12 00:47:09 +0000170static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect);
wdenke537b3b2004-02-23 23:54:43 +0000171static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
172static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
173static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
wdenke65527f2004-02-12 00:47:09 +0000174static int flash_detect_cfi (flash_info_t * info);
wdenk2cefd152004-02-08 22:55:38 +0000175static ulong flash_get_size (ulong base, int banknum);
wdenke537b3b2004-02-23 23:54:43 +0000176static int flash_write_cfiword (flash_info_t * info, ulong dest, cfiword_t cword);
wdenke65527f2004-02-12 00:47:09 +0000177static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
178 ulong tout, char *prompt);
wdenk2cefd152004-02-08 22:55:38 +0000179#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenke537b3b2004-02-23 23:54:43 +0000180static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, int len);
wdenk2cefd152004-02-08 22:55:38 +0000181#endif
182
wdenke65527f2004-02-12 00:47:09 +0000183/*-----------------------------------------------------------------------
184 * create an address based on the offset and the port width
185 */
wdenke537b3b2004-02-23 23:54:43 +0000186inline uchar *flash_make_addr (flash_info_t * info, flash_sect_t sect, uint offset)
wdenke65527f2004-02-12 00:47:09 +0000187{
188 return ((uchar *) (info->start[sect] + (offset * info->portwidth)));
189}
190
wdenk2cefd152004-02-08 22:55:38 +0000191#ifdef DEBUG
wdenke65527f2004-02-12 00:47:09 +0000192/*-----------------------------------------------------------------------
193 * Debug support
194 */
195void print_longlong (char *str, unsigned long long data)
wdenk2cefd152004-02-08 22:55:38 +0000196{
197 int i;
198 char *cp;
wdenke65527f2004-02-12 00:47:09 +0000199
200 cp = (unsigned char *) &data;
201 for (i = 0; i < 8; i++)
202 sprintf (&str[i * 2], "%2.2x", *cp++);
wdenk2cefd152004-02-08 22:55:38 +0000203}
wdenke65527f2004-02-12 00:47:09 +0000204static void flash_printqry (flash_info_t * info, flash_sect_t sect)
205{
206 cfiptr_t cptr;
207 int x, y;
208
209 for (x = 0; x < 0x40; x += 16 / info->portwidth) {
210 cptr.cp =
211 flash_make_addr (info, sect,
212 x + FLASH_OFFSET_CFI_RESP);
213 debug ("%p : ", cptr.cp);
214 for (y = 0; y < 16; y++) {
215 debug ("%2.2x ", cptr.cp[y]);
216 }
217 debug (" ");
218 for (y = 0; y < 16; y++) {
219 if (cptr.cp[y] >= 0x20 && cptr.cp[y] <= 0x7e) {
220 debug ("%c", cptr.cp[y]);
221 } else {
222 debug (".");
223 }
224 }
225 debug ("\n");
226 }
227}
wdenk2cefd152004-02-08 22:55:38 +0000228#endif
229
230
231/*-----------------------------------------------------------------------
wdenk2cefd152004-02-08 22:55:38 +0000232 * read a character at a port width address
233 */
wdenke65527f2004-02-12 00:47:09 +0000234inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000235{
236 uchar *cp;
wdenke65527f2004-02-12 00:47:09 +0000237
238 cp = flash_make_addr (info, 0, offset);
239#if defined(__LITTLE_ENDIAN)
240 return (cp[0]);
241#else
wdenk2cefd152004-02-08 22:55:38 +0000242 return (cp[info->portwidth - 1]);
wdenke65527f2004-02-12 00:47:09 +0000243#endif
wdenk2cefd152004-02-08 22:55:38 +0000244}
245
246/*-----------------------------------------------------------------------
247 * read a short word by swapping for ppc format.
248 */
wdenke65527f2004-02-12 00:47:09 +0000249ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000250{
wdenke65527f2004-02-12 00:47:09 +0000251 uchar *addr;
252 ushort retval;
wdenk2cefd152004-02-08 22:55:38 +0000253
wdenke65527f2004-02-12 00:47:09 +0000254#ifdef DEBUG
255 int x;
256#endif
257 addr = flash_make_addr (info, sect, offset);
wdenk2cefd152004-02-08 22:55:38 +0000258
wdenke65527f2004-02-12 00:47:09 +0000259#ifdef DEBUG
260 debug ("ushort addr is at %p info->portwidth = %d\n", addr,
261 info->portwidth);
262 for (x = 0; x < 2 * info->portwidth; x++) {
263 debug ("addr[%x] = 0x%x\n", x, addr[x]);
264 }
265#endif
266#if defined(__LITTLE_ENDIAN)
267 retval = ((addr[(info->portwidth)] << 8) | addr[0]);
268#else
269 retval = ((addr[(2 * info->portwidth) - 1] << 8) |
270 addr[info->portwidth - 1]);
271#endif
272
273 debug ("retval = 0x%x\n", retval);
274 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000275}
276
277/*-----------------------------------------------------------------------
278 * read a long word by picking the least significant byte of each maiximum
279 * port size word. Swap for ppc format.
280 */
wdenke65527f2004-02-12 00:47:09 +0000281ulong flash_read_long (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk2cefd152004-02-08 22:55:38 +0000282{
wdenke65527f2004-02-12 00:47:09 +0000283 uchar *addr;
284 ulong retval;
285
286#ifdef DEBUG
287 int x;
288#endif
289 addr = flash_make_addr (info, sect, offset);
wdenk2cefd152004-02-08 22:55:38 +0000290
wdenke65527f2004-02-12 00:47:09 +0000291#ifdef DEBUG
292 debug ("long addr is at %p info->portwidth = %d\n", addr,
293 info->portwidth);
294 for (x = 0; x < 4 * info->portwidth; x++) {
295 debug ("addr[%x] = 0x%x\n", x, addr[x]);
296 }
297#endif
298#if defined(__LITTLE_ENDIAN)
299 retval = (addr[0] << 16) | (addr[(info->portwidth)] << 24) |
wdenke537b3b2004-02-23 23:54:43 +0000300 (addr[(2 * info->portwidth)]) | (addr[(3 * info->portwidth)] << 8);
wdenke65527f2004-02-12 00:47:09 +0000301#else
302 retval = (addr[(2 * info->portwidth) - 1] << 24) |
303 (addr[(info->portwidth) - 1] << 16) |
304 (addr[(4 * info->portwidth) - 1] << 8) |
305 addr[(3 * info->portwidth) - 1];
306#endif
307 return retval;
wdenk2cefd152004-02-08 22:55:38 +0000308}
309
310/*-----------------------------------------------------------------------
311 */
312unsigned long flash_init (void)
313{
314 unsigned long size = 0;
315 int i;
316
317 /* Init: no FLASHes known */
wdenke65527f2004-02-12 00:47:09 +0000318 for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
wdenk2cefd152004-02-08 22:55:38 +0000319 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenke65527f2004-02-12 00:47:09 +0000320 size += flash_info[i].size = flash_get_size (bank_base[i], i);
wdenk2cefd152004-02-08 22:55:38 +0000321 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
wdenke537b3b2004-02-23 23:54:43 +0000322 printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
323 i, flash_info[i].size, flash_info[i].size << 20);
wdenk2cefd152004-02-08 22:55:38 +0000324 }
325 }
326
327 /* Monitor protection ON by default */
328#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
wdenke65527f2004-02-12 00:47:09 +0000329 flash_protect (FLAG_PROTECT_SET,
330 CFG_MONITOR_BASE,
331 CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
332 &flash_info[0]);
wdenk2cefd152004-02-08 22:55:38 +0000333#endif
334
335 return (size);
336}
337
338/*-----------------------------------------------------------------------
339 */
wdenke65527f2004-02-12 00:47:09 +0000340int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk2cefd152004-02-08 22:55:38 +0000341{
342 int rcode = 0;
343 int prot;
344 flash_sect_t sect;
345
wdenke65527f2004-02-12 00:47:09 +0000346 if (info->flash_id != FLASH_MAN_CFI) {
wdenk2cefd152004-02-08 22:55:38 +0000347 printf ("Can't erase unknown flash type - aborted\n");
348 return 1;
349 }
350 if ((s_first < 0) || (s_first > s_last)) {
351 printf ("- no sectors to erase\n");
352 return 1;
353 }
354
355 prot = 0;
wdenke65527f2004-02-12 00:47:09 +0000356 for (sect = s_first; sect <= s_last; ++sect) {
wdenk2cefd152004-02-08 22:55:38 +0000357 if (info->protect[sect]) {
358 prot++;
359 }
360 }
361 if (prot) {
wdenke65527f2004-02-12 00:47:09 +0000362 printf ("- Warning: %d protected sectors will not be erased!\n", prot);
wdenk2cefd152004-02-08 22:55:38 +0000363 } else {
364 printf ("\n");
365 }
366
367
wdenke65527f2004-02-12 00:47:09 +0000368 for (sect = s_first; sect <= s_last; sect++) {
wdenk2cefd152004-02-08 22:55:38 +0000369 if (info->protect[sect] == 0) { /* not protected */
wdenke65527f2004-02-12 00:47:09 +0000370 switch (info->vendor) {
wdenk2cefd152004-02-08 22:55:38 +0000371 case CFI_CMDSET_INTEL_STANDARD:
372 case CFI_CMDSET_INTEL_EXTENDED:
wdenke537b3b2004-02-23 23:54:43 +0000373 flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS);
374 flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE);
375 flash_write_cmd (info, sect, 0, FLASH_CMD_ERASE_CONFIRM);
wdenk2cefd152004-02-08 22:55:38 +0000376 break;
377 case CFI_CMDSET_AMD_STANDARD:
378 case CFI_CMDSET_AMD_EXTENDED:
wdenke65527f2004-02-12 00:47:09 +0000379 flash_unlock_seq (info, sect);
wdenke537b3b2004-02-23 23:54:43 +0000380 flash_write_cmd (info, sect, 0x555, AMD_CMD_ERASE_START);
wdenke65527f2004-02-12 00:47:09 +0000381 flash_unlock_seq (info, sect);
wdenke537b3b2004-02-23 23:54:43 +0000382 flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR);
wdenk2cefd152004-02-08 22:55:38 +0000383 break;
384 default:
wdenke65527f2004-02-12 00:47:09 +0000385 debug ("Unkown flash vendor %d\n",
386 info->vendor);
wdenk2cefd152004-02-08 22:55:38 +0000387 break;
388 }
389
wdenke65527f2004-02-12 00:47:09 +0000390 if (flash_full_status_check
391 (info, sect, info->erase_blk_tout, "erase")) {
wdenk2cefd152004-02-08 22:55:38 +0000392 rcode = 1;
393 } else
wdenke65527f2004-02-12 00:47:09 +0000394 printf (".");
wdenk2cefd152004-02-08 22:55:38 +0000395 }
396 }
397 printf (" done\n");
398 return rcode;
399}
400
401/*-----------------------------------------------------------------------
402 */
wdenke65527f2004-02-12 00:47:09 +0000403void flash_print_info (flash_info_t * info)
wdenk2cefd152004-02-08 22:55:38 +0000404{
405 int i;
406
407 if (info->flash_id != FLASH_MAN_CFI) {
408 printf ("missing or unknown FLASH type\n");
409 return;
410 }
411
wdenke65527f2004-02-12 00:47:09 +0000412 printf ("CFI conformant FLASH (%d x %d)",
413 (info->portwidth << 3), (info->chipwidth << 3));
wdenk2cefd152004-02-08 22:55:38 +0000414 printf (" Size: %ld MB in %d Sectors\n",
415 info->size >> 20, info->sector_count);
wdenke537b3b2004-02-23 23:54:43 +0000416 printf (" Erase timeout %ld ms, write timeout %ld ms, buffer write timeout %ld ms, buffer size %d\n",
417 info->erase_blk_tout,
418 info->write_tout,
419 info->buffer_write_tout,
420 info->buffer_size);
wdenk2cefd152004-02-08 22:55:38 +0000421
422 printf (" Sector Start Addresses:");
wdenke65527f2004-02-12 00:47:09 +0000423 for (i = 0; i < info->sector_count; ++i) {
wdenk2cefd152004-02-08 22:55:38 +0000424#ifdef CFG_FLASH_EMPTY_INFO
425 int k;
426 int size;
427 int erased;
428 volatile unsigned long *flash;
429
430 /*
431 * Check if whole sector is erased
432 */
wdenke65527f2004-02-12 00:47:09 +0000433 if (i != (info->sector_count - 1))
434 size = info->start[i + 1] - info->start[i];
wdenk2cefd152004-02-08 22:55:38 +0000435 else
wdenke65527f2004-02-12 00:47:09 +0000436 size = info->start[0] + info->size - info->start[i];
wdenk2cefd152004-02-08 22:55:38 +0000437 erased = 1;
wdenke65527f2004-02-12 00:47:09 +0000438 flash = (volatile unsigned long *) info->start[i];
439 size = size >> 2; /* divide by 4 for longword access */
440 for (k = 0; k < size; k++) {
441 if (*flash++ != 0xffffffff) {
442 erased = 0;
443 break;
444 }
445 }
wdenk2cefd152004-02-08 22:55:38 +0000446
447 if ((i % 5) == 0)
448 printf ("\n");
449 /* print empty and read-only info */
450 printf (" %08lX%s%s",
451 info->start[i],
452 erased ? " E" : " ",
453 info->protect[i] ? "RO " : " ");
454#else
455 if ((i % 5) == 0)
456 printf ("\n ");
457 printf (" %08lX%s",
wdenke65527f2004-02-12 00:47:09 +0000458 info->start[i], info->protect[i] ? " (RO)" : " ");
wdenk2cefd152004-02-08 22:55:38 +0000459#endif
460 }
461 printf ("\n");
462 return;
463}
464
465/*-----------------------------------------------------------------------
466 * Copy memory to flash, returns:
467 * 0 - OK
468 * 1 - write timeout
469 * 2 - Flash not erased
470 */
wdenke65527f2004-02-12 00:47:09 +0000471int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk2cefd152004-02-08 22:55:38 +0000472{
473 ulong wp;
474 ulong cp;
475 int aln;
476 cfiword_t cword;
477 int i, rc;
478
wdenke65527f2004-02-12 00:47:09 +0000479#ifdef CFG_FLASH_USE_BUFFER_WRITE
480 int buffered_size;
481#endif
482 int x8mode = 0;
483
484 /* special handling of 16 bit devices in 8 bit mode */
485 if ((info->interface == FLASH_CFI_X8X16)
486 && (info->chipwidth == FLASH_CFI_BY8)) {
487 switch (info->vendor) {
488 case CFI_CMDSET_INTEL_STANDARD:
489 case CFI_CMDSET_INTEL_EXTENDED:
490 x8mode = info->portwidth;
491 info->portwidth >>= 1; /* XXX - Need to test on x9/x16 in parallel. */
492 /*info->portwidth = FLASH_CFI_8BIT; */ /* XXX - Need to test on x9/x16 in parallel. */
493 break;
494 case CFI_CMDSET_AMD_STANDARD:
495 case CFI_CMDSET_AMD_EXTENDED:
496 default:
497 break;
498 }
499 }
500 /* get lower aligned address */
wdenk2cefd152004-02-08 22:55:38 +0000501 /* get lower aligned address */
502 wp = (addr & ~(info->portwidth - 1));
503
504 /* handle unaligned start */
wdenke65527f2004-02-12 00:47:09 +0000505 if ((aln = addr - wp) != 0) {
wdenk2cefd152004-02-08 22:55:38 +0000506 cword.l = 0;
507 cp = wp;
wdenke65527f2004-02-12 00:47:09 +0000508 for (i = 0; i < aln; ++i, ++cp)
509 flash_add_byte (info, &cword, (*(uchar *) cp));
wdenk2cefd152004-02-08 22:55:38 +0000510
wdenke65527f2004-02-12 00:47:09 +0000511 for (; (i < info->portwidth) && (cnt > 0); i++) {
512 flash_add_byte (info, &cword, *src++);
wdenk2cefd152004-02-08 22:55:38 +0000513 cnt--;
514 cp++;
515 }
wdenke65527f2004-02-12 00:47:09 +0000516 for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp)
517 flash_add_byte (info, &cword, (*(uchar *) cp));
518 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk2cefd152004-02-08 22:55:38 +0000519 return rc;
520 wp = cp;
521 }
522
wdenke65527f2004-02-12 00:47:09 +0000523 /* handle the aligned part */
wdenk2cefd152004-02-08 22:55:38 +0000524#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenke65527f2004-02-12 00:47:09 +0000525 buffered_size = (info->portwidth / info->chipwidth);
526 buffered_size *= info->buffer_size;
527 while (cnt >= info->portwidth) {
528 i = buffered_size > cnt ? cnt : buffered_size;
529 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
wdenk2cefd152004-02-08 22:55:38 +0000530 return rc;
531 wp += i;
532 src += i;
wdenke65527f2004-02-12 00:47:09 +0000533 cnt -= i;
wdenk2cefd152004-02-08 22:55:38 +0000534 }
535#else
wdenke65527f2004-02-12 00:47:09 +0000536 while (cnt >= info->portwidth) {
wdenk2cefd152004-02-08 22:55:38 +0000537 cword.l = 0;
wdenke65527f2004-02-12 00:47:09 +0000538 for (i = 0; i < info->portwidth; i++) {
539 flash_add_byte (info, &cword, *src++);
wdenk2cefd152004-02-08 22:55:38 +0000540 }
wdenke65527f2004-02-12 00:47:09 +0000541 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk2cefd152004-02-08 22:55:38 +0000542 return rc;
543 wp += info->portwidth;
544 cnt -= info->portwidth;
545 }
546#endif /* CFG_FLASH_USE_BUFFER_WRITE */
547 if (cnt == 0) {
548 return (0);
549 }
550
551 /*
552 * handle unaligned tail bytes
553 */
554 cword.l = 0;
wdenke65527f2004-02-12 00:47:09 +0000555 for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) {
556 flash_add_byte (info, &cword, *src++);
wdenk2cefd152004-02-08 22:55:38 +0000557 --cnt;
558 }
wdenke65527f2004-02-12 00:47:09 +0000559 for (; i < info->portwidth; ++i, ++cp) {
560 flash_add_byte (info, &cword, (*(uchar *) cp));
wdenk2cefd152004-02-08 22:55:38 +0000561 }
562
wdenke65527f2004-02-12 00:47:09 +0000563 /* special handling of 16 bit devices in 8 bit mode */
564 if (x8mode) {
565 info->portwidth = x8mode;;
566 }
567 return flash_write_cfiword (info, wp, cword);
wdenk2cefd152004-02-08 22:55:38 +0000568}
569
570/*-----------------------------------------------------------------------
571 */
572#ifdef CFG_FLASH_PROTECTION
573
wdenke65527f2004-02-12 00:47:09 +0000574int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk2cefd152004-02-08 22:55:38 +0000575{
576 int retcode = 0;
577
wdenke65527f2004-02-12 00:47:09 +0000578 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
579 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
580 if (prot)
581 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
wdenk2cefd152004-02-08 22:55:38 +0000582 else
wdenke65527f2004-02-12 00:47:09 +0000583 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
wdenk2cefd152004-02-08 22:55:38 +0000584
wdenke65527f2004-02-12 00:47:09 +0000585 if ((retcode =
586 flash_full_status_check (info, sector, info->erase_blk_tout,
587 prot ? "protect" : "unprotect")) == 0) {
wdenk2cefd152004-02-08 22:55:38 +0000588
589 info->protect[sector] = prot;
590 /* Intel's unprotect unprotects all locking */
wdenke65527f2004-02-12 00:47:09 +0000591 if (prot == 0) {
wdenk2cefd152004-02-08 22:55:38 +0000592 flash_sect_t i;
wdenke65527f2004-02-12 00:47:09 +0000593
594 for (i = 0; i < info->sector_count; i++) {
595 if (info->protect[i])
596 flash_real_protect (info, i, 1);
wdenk2cefd152004-02-08 22:55:38 +0000597 }
598 }
599 }
wdenk2cefd152004-02-08 22:55:38 +0000600 return retcode;
wdenke65527f2004-02-12 00:47:09 +0000601}
602
wdenk2cefd152004-02-08 22:55:38 +0000603/*-----------------------------------------------------------------------
604 * flash_read_user_serial - read the OneTimeProgramming cells
605 */
wdenke65527f2004-02-12 00:47:09 +0000606void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
607 int len)
wdenk2cefd152004-02-08 22:55:38 +0000608{
wdenke65527f2004-02-12 00:47:09 +0000609 uchar *src;
610 uchar *dst;
wdenk2cefd152004-02-08 22:55:38 +0000611
612 dst = buffer;
wdenke65527f2004-02-12 00:47:09 +0000613 src = flash_make_addr (info, 0, FLASH_OFFSET_USER_PROTECTION);
614 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
615 memcpy (dst, src + offset, len);
616 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
wdenk2cefd152004-02-08 22:55:38 +0000617}
wdenke65527f2004-02-12 00:47:09 +0000618
wdenk2cefd152004-02-08 22:55:38 +0000619/*
620 * flash_read_factory_serial - read the device Id from the protection area
621 */
wdenke65527f2004-02-12 00:47:09 +0000622void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
623 int len)
wdenk2cefd152004-02-08 22:55:38 +0000624{
wdenke65527f2004-02-12 00:47:09 +0000625 uchar *src;
wdenk6cfa84e2004-02-10 00:03:41 +0000626
wdenke65527f2004-02-12 00:47:09 +0000627 src = flash_make_addr (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
628 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
629 memcpy (buffer, src + offset, len);
630 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
wdenk2cefd152004-02-08 22:55:38 +0000631}
632
633#endif /* CFG_FLASH_PROTECTION */
634
wdenke65527f2004-02-12 00:47:09 +0000635/*
636 * flash_is_busy - check to see if the flash is busy
637 * This routine checks the status of the chip and returns true if the chip is busy
638 */
639static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
wdenk2cefd152004-02-08 22:55:38 +0000640{
641 int retval;
wdenke65527f2004-02-12 00:47:09 +0000642
643 switch (info->vendor) {
wdenk2cefd152004-02-08 22:55:38 +0000644 case CFI_CMDSET_INTEL_STANDARD:
645 case CFI_CMDSET_INTEL_EXTENDED:
wdenke65527f2004-02-12 00:47:09 +0000646 retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
wdenk2cefd152004-02-08 22:55:38 +0000647 break;
648 case CFI_CMDSET_AMD_STANDARD:
649 case CFI_CMDSET_AMD_EXTENDED:
wdenke65527f2004-02-12 00:47:09 +0000650 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
wdenk2cefd152004-02-08 22:55:38 +0000651 break;
652 default:
653 retval = 0;
654 }
wdenke65527f2004-02-12 00:47:09 +0000655 debug ("flash_is_busy: %d\n", retval);
wdenk2cefd152004-02-08 22:55:38 +0000656 return retval;
657}
wdenke65527f2004-02-12 00:47:09 +0000658
wdenk2cefd152004-02-08 22:55:38 +0000659/*-----------------------------------------------------------------------
660 * wait for XSR.7 to be set. Time out with an error if it does not.
661 * This routine does not set the flash to read-array mode.
662 */
wdenke65527f2004-02-12 00:47:09 +0000663static int flash_status_check (flash_info_t * info, flash_sect_t sector,
664 ulong tout, char *prompt)
wdenk2cefd152004-02-08 22:55:38 +0000665{
666 ulong start;
667
668 /* Wait for command completion */
669 start = get_timer (0);
wdenke65527f2004-02-12 00:47:09 +0000670 while (flash_is_busy (info, sector)) {
671 if (get_timer (start) > info->erase_blk_tout * CFG_HZ) {
672 printf ("Flash %s timeout at address %lx data %lx\n",
673 prompt, info->start[sector],
674 flash_read_long (info, sector, 0));
675 flash_write_cmd (info, sector, 0, info->cmd_reset);
wdenk2cefd152004-02-08 22:55:38 +0000676 return ERR_TIMOUT;
677 }
678 }
679 return ERR_OK;
680}
wdenke65527f2004-02-12 00:47:09 +0000681
wdenk2cefd152004-02-08 22:55:38 +0000682/*-----------------------------------------------------------------------
683 * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check.
684 * This routine sets the flash to read-array mode.
685 */
wdenke65527f2004-02-12 00:47:09 +0000686static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
687 ulong tout, char *prompt)
wdenk2cefd152004-02-08 22:55:38 +0000688{
689 int retcode;
wdenke65527f2004-02-12 00:47:09 +0000690
691 retcode = flash_status_check (info, sector, tout, prompt);
692 switch (info->vendor) {
wdenk2cefd152004-02-08 22:55:38 +0000693 case CFI_CMDSET_INTEL_EXTENDED:
694 case CFI_CMDSET_INTEL_STANDARD:
wdenke65527f2004-02-12 00:47:09 +0000695 if ((retcode != ERR_OK)
696 && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
wdenk2cefd152004-02-08 22:55:38 +0000697 retcode = ERR_INVAL;
wdenke65527f2004-02-12 00:47:09 +0000698 printf ("Flash %s error at address %lx\n", prompt,
699 info->start[sector]);
wdenke537b3b2004-02-23 23:54:43 +0000700 if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) {
wdenke65527f2004-02-12 00:47:09 +0000701 printf ("Command Sequence Error.\n");
wdenke537b3b2004-02-23 23:54:43 +0000702 } else if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS)) {
wdenke65527f2004-02-12 00:47:09 +0000703 printf ("Block Erase Error.\n");
wdenk2cefd152004-02-08 22:55:38 +0000704 retcode = ERR_NOT_ERASED;
wdenke537b3b2004-02-23 23:54:43 +0000705 } else if (flash_isset (info, sector, 0, FLASH_STATUS_PSLBS)) {
wdenke65527f2004-02-12 00:47:09 +0000706 printf ("Locking Error\n");
wdenk2cefd152004-02-08 22:55:38 +0000707 }
wdenke65527f2004-02-12 00:47:09 +0000708 if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
709 printf ("Block locked.\n");
710 retcode = ERR_PROTECTED;
711 }
712 if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
713 printf ("Vpp Low Error.\n");
wdenk2cefd152004-02-08 22:55:38 +0000714 }
wdenke65527f2004-02-12 00:47:09 +0000715 flash_write_cmd (info, sector, 0, FLASH_CMD_RESET);
wdenk2cefd152004-02-08 22:55:38 +0000716 break;
717 default:
718 break;
719 }
720 return retcode;
721}
wdenke65527f2004-02-12 00:47:09 +0000722
wdenk2cefd152004-02-08 22:55:38 +0000723/*-----------------------------------------------------------------------
724 */
wdenke65527f2004-02-12 00:47:09 +0000725static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
wdenk2cefd152004-02-08 22:55:38 +0000726{
wdenke65527f2004-02-12 00:47:09 +0000727 switch (info->portwidth) {
wdenk2cefd152004-02-08 22:55:38 +0000728 case FLASH_CFI_8BIT:
729 cword->c = c;
730 break;
731 case FLASH_CFI_16BIT:
732 cword->w = (cword->w << 8) | c;
733 break;
734 case FLASH_CFI_32BIT:
735 cword->l = (cword->l << 8) | c;
736 break;
737 case FLASH_CFI_64BIT:
738 cword->ll = (cword->ll << 8) | c;
739 break;
740 }
741}
742
743
744/*-----------------------------------------------------------------------
745 * make a proper sized command based on the port and chip widths
746 */
wdenke65527f2004-02-12 00:47:09 +0000747static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
wdenk2cefd152004-02-08 22:55:38 +0000748{
749 int i;
wdenke65527f2004-02-12 00:47:09 +0000750
751#if defined(__LITTLE_ENDIAN)
wdenke537b3b2004-02-23 23:54:43 +0000752 ushort stmpw;
753 uint stmpi;
wdenke65527f2004-02-12 00:47:09 +0000754#endif
755 uchar *cp = (uchar *) cmdbuf;
756
757 for (i = 0; i < info->portwidth; i++)
758 *cp++ = ((i + 1) % info->chipwidth) ? '\0' : cmd;
759#if defined(__LITTLE_ENDIAN)
wdenke537b3b2004-02-23 23:54:43 +0000760 switch (info->portwidth) {
761 case FLASH_CFI_8BIT:
762 break;
763 case FLASH_CFI_16BIT:
764 stmpw = *(ushort *) cmdbuf;
765 *(ushort *) cmdbuf = __swab16 (stmpw);
766 break;
767 case FLASH_CFI_32BIT:
768 stmpi = *(uint *) cmdbuf;
769 *(uint *) cmdbuf = __swab32 (stmpi);
770 break;
771 default:
772 printf("WARNING: flash_make_cmd: unsuppported LittleEndian mode\n");
773 break;
wdenke65527f2004-02-12 00:47:09 +0000774 }
775#endif
wdenk2cefd152004-02-08 22:55:38 +0000776}
777
778/*
779 * Write a proper sized command to the correct address
780 */
wdenke537b3b2004-02-23 23:54:43 +0000781static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk2cefd152004-02-08 22:55:38 +0000782{
783
784 volatile cfiptr_t addr;
785 cfiword_t cword;
wdenke65527f2004-02-12 00:47:09 +0000786
787 addr.cp = flash_make_addr (info, sect, offset);
788 flash_make_cmd (info, cmd, &cword);
789 switch (info->portwidth) {
wdenk2cefd152004-02-08 22:55:38 +0000790 case FLASH_CFI_8BIT:
wdenke65527f2004-02-12 00:47:09 +0000791 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr.cp, cmd,
792 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
wdenk2cefd152004-02-08 22:55:38 +0000793 *addr.cp = cword.c;
794 break;
795 case FLASH_CFI_16BIT:
wdenke65527f2004-02-12 00:47:09 +0000796 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr.wp,
797 cmd, cword.w,
wdenk2cefd152004-02-08 22:55:38 +0000798 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
799 *addr.wp = cword.w;
800 break;
801 case FLASH_CFI_32BIT:
wdenke65527f2004-02-12 00:47:09 +0000802 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr.lp,
803 cmd, cword.l,
wdenk2cefd152004-02-08 22:55:38 +0000804 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
805 *addr.lp = cword.l;
806 break;
807 case FLASH_CFI_64BIT:
808#ifdef DEBUG
wdenke65527f2004-02-12 00:47:09 +0000809 {
wdenk2cefd152004-02-08 22:55:38 +0000810 char str[20];
wdenk6cfa84e2004-02-10 00:03:41 +0000811
wdenke65527f2004-02-12 00:47:09 +0000812 print_longlong (str, cword.ll);
813
814 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
815 addr.llp, cmd, str,
wdenk2cefd152004-02-08 22:55:38 +0000816 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
817 }
818#endif
819 *addr.llp = cword.ll;
820 break;
821 }
822}
823
wdenke65527f2004-02-12 00:47:09 +0000824static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
wdenk2cefd152004-02-08 22:55:38 +0000825{
wdenke65527f2004-02-12 00:47:09 +0000826 flash_write_cmd (info, sect, 0x555, 0xAA);
827 flash_write_cmd (info, sect, 0x2AA, 0x55);
wdenk2cefd152004-02-08 22:55:38 +0000828}
wdenke65527f2004-02-12 00:47:09 +0000829
wdenk2cefd152004-02-08 22:55:38 +0000830/*-----------------------------------------------------------------------
831 */
wdenke537b3b2004-02-23 23:54:43 +0000832static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk2cefd152004-02-08 22:55:38 +0000833{
834 cfiptr_t cptr;
835 cfiword_t cword;
836 int retval;
wdenke65527f2004-02-12 00:47:09 +0000837
838 cptr.cp = flash_make_addr (info, sect, offset);
839 flash_make_cmd (info, cmd, &cword);
wdenk2cefd152004-02-08 22:55:38 +0000840
wdenke65527f2004-02-12 00:47:09 +0000841 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, cptr.cp);
842 switch (info->portwidth) {
wdenk2cefd152004-02-08 22:55:38 +0000843 case FLASH_CFI_8BIT:
wdenke65527f2004-02-12 00:47:09 +0000844 debug ("is= %x %x\n", cptr.cp[0], cword.c);
wdenk2cefd152004-02-08 22:55:38 +0000845 retval = (cptr.cp[0] == cword.c);
846 break;
847 case FLASH_CFI_16BIT:
wdenke65527f2004-02-12 00:47:09 +0000848 debug ("is= %4.4x %4.4x\n", cptr.wp[0], cword.w);
wdenk2cefd152004-02-08 22:55:38 +0000849 retval = (cptr.wp[0] == cword.w);
850 break;
851 case FLASH_CFI_32BIT:
wdenke65527f2004-02-12 00:47:09 +0000852 debug ("is= %8.8lx %8.8lx\n", cptr.lp[0], cword.l);
wdenk2cefd152004-02-08 22:55:38 +0000853 retval = (cptr.lp[0] == cword.l);
854 break;
855 case FLASH_CFI_64BIT:
wdenk6cfa84e2004-02-10 00:03:41 +0000856#ifdef DEBUG
wdenke65527f2004-02-12 00:47:09 +0000857 {
wdenk2cefd152004-02-08 22:55:38 +0000858 char str1[20];
859 char str2[20];
wdenke65527f2004-02-12 00:47:09 +0000860
861 print_longlong (str1, cptr.llp[0]);
862 print_longlong (str2, cword.ll);
863 debug ("is= %s %s\n", str1, str2);
wdenk2cefd152004-02-08 22:55:38 +0000864 }
865#endif
866 retval = (cptr.llp[0] == cword.ll);
867 break;
868 default:
869 retval = 0;
870 break;
871 }
872 return retval;
873}
wdenke65527f2004-02-12 00:47:09 +0000874
wdenk2cefd152004-02-08 22:55:38 +0000875/*-----------------------------------------------------------------------
876 */
wdenke537b3b2004-02-23 23:54:43 +0000877static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk2cefd152004-02-08 22:55:38 +0000878{
879 cfiptr_t cptr;
880 cfiword_t cword;
881 int retval;
wdenke65527f2004-02-12 00:47:09 +0000882
883 cptr.cp = flash_make_addr (info, sect, offset);
884 flash_make_cmd (info, cmd, &cword);
885 switch (info->portwidth) {
wdenk2cefd152004-02-08 22:55:38 +0000886 case FLASH_CFI_8BIT:
887 retval = ((cptr.cp[0] & cword.c) == cword.c);
888 break;
889 case FLASH_CFI_16BIT:
890 retval = ((cptr.wp[0] & cword.w) == cword.w);
891 break;
892 case FLASH_CFI_32BIT:
893 retval = ((cptr.lp[0] & cword.l) == cword.l);
894 break;
895 case FLASH_CFI_64BIT:
896 retval = ((cptr.llp[0] & cword.ll) == cword.ll);
wdenke65527f2004-02-12 00:47:09 +0000897 break;
wdenk2cefd152004-02-08 22:55:38 +0000898 default:
899 retval = 0;
900 break;
901 }
902 return retval;
903}
904
905/*-----------------------------------------------------------------------
906 */
wdenke537b3b2004-02-23 23:54:43 +0000907static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk2cefd152004-02-08 22:55:38 +0000908{
909 cfiptr_t cptr;
910 cfiword_t cword;
911 int retval;
wdenke65527f2004-02-12 00:47:09 +0000912
913 cptr.cp = flash_make_addr (info, sect, offset);
914 flash_make_cmd (info, cmd, &cword);
915 switch (info->portwidth) {
wdenk2cefd152004-02-08 22:55:38 +0000916 case FLASH_CFI_8BIT:
917 retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c));
918 break;
919 case FLASH_CFI_16BIT:
920 retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w));
921 break;
922 case FLASH_CFI_32BIT:
923 retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l));
924 break;
925 case FLASH_CFI_64BIT:
wdenke65527f2004-02-12 00:47:09 +0000926 retval = ((cptr.llp[0] & cword.ll) !=
927 (cptr.llp[0] & cword.ll));
wdenk2cefd152004-02-08 22:55:38 +0000928 break;
929 default:
930 retval = 0;
931 break;
932 }
933 return retval;
934}
935
936/*-----------------------------------------------------------------------
937 * detect if flash is compatible with the Common Flash Interface (CFI)
938 * http://www.jedec.org/download/search/jesd68.pdf
939 *
940*/
wdenke65527f2004-02-12 00:47:09 +0000941static int flash_detect_cfi (flash_info_t * info)
wdenk2cefd152004-02-08 22:55:38 +0000942{
wdenke65527f2004-02-12 00:47:09 +0000943 debug ("flash detect cfi\n");
wdenk2cefd152004-02-08 22:55:38 +0000944
wdenke65527f2004-02-12 00:47:09 +0000945 for (info->portwidth = FLASH_CFI_8BIT;
946 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
947 for (info->chipwidth = FLASH_CFI_BY8;
948 info->chipwidth <= info->portwidth;
949 info->chipwidth <<= 1) {
950 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
wdenke537b3b2004-02-23 23:54:43 +0000951 flash_write_cmd (info, 0, FLASH_OFFSET_CFI, FLASH_CMD_CFI);
952 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
953 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
954 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
955 info->interface = flash_read_ushort (info, 0, FLASH_OFFSET_INTERFACE);
wdenke65527f2004-02-12 00:47:09 +0000956 debug ("device interface is %d\n",
957 info->interface);
958 debug ("found port %d chip %d ",
959 info->portwidth, info->chipwidth);
960 debug ("port %d bits chip %d bits\n",
wdenke537b3b2004-02-23 23:54:43 +0000961 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
962 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
wdenk2cefd152004-02-08 22:55:38 +0000963 return 1;
964 }
965 }
966 }
wdenke65527f2004-02-12 00:47:09 +0000967 debug ("not found\n");
wdenk2cefd152004-02-08 22:55:38 +0000968 return 0;
969}
wdenke65527f2004-02-12 00:47:09 +0000970
wdenk2cefd152004-02-08 22:55:38 +0000971/*
972 * The following code cannot be run from FLASH!
973 *
974 */
975static ulong flash_get_size (ulong base, int banknum)
976{
wdenke65527f2004-02-12 00:47:09 +0000977 flash_info_t *info = &flash_info[banknum];
wdenk2cefd152004-02-08 22:55:38 +0000978 int i, j;
979 flash_sect_t sect_cnt;
980 unsigned long sector;
981 unsigned long tmp;
982 int size_ratio;
983 uchar num_erase_regions;
wdenke65527f2004-02-12 00:47:09 +0000984 int erase_region_size;
985 int erase_region_count;
wdenk2cefd152004-02-08 22:55:38 +0000986
987 info->start[0] = base;
988
wdenke65527f2004-02-12 00:47:09 +0000989 if (flash_detect_cfi (info)) {
wdenke537b3b2004-02-23 23:54:43 +0000990 info->vendor = flash_read_ushort (info, 0, FLASH_OFFSET_PRIMARY_VENDOR);
wdenke65527f2004-02-12 00:47:09 +0000991#ifdef DEBUG
992 flash_printqry (info, 0);
993#endif
994 switch (info->vendor) {
wdenk2cefd152004-02-08 22:55:38 +0000995 case CFI_CMDSET_INTEL_STANDARD:
996 case CFI_CMDSET_INTEL_EXTENDED:
997 default:
998 info->cmd_reset = FLASH_CMD_RESET;
999 break;
1000 case CFI_CMDSET_AMD_STANDARD:
1001 case CFI_CMDSET_AMD_EXTENDED:
1002 info->cmd_reset = AMD_CMD_RESET;
1003 break;
1004 }
wdenk6cfa84e2004-02-10 00:03:41 +00001005
wdenke65527f2004-02-12 00:47:09 +00001006 debug ("manufacturer is %d\n", info->vendor);
wdenk2cefd152004-02-08 22:55:38 +00001007 size_ratio = info->portwidth / info->chipwidth;
wdenke65527f2004-02-12 00:47:09 +00001008 /* if the chip is x8/x16 reduce the ratio by half */
1009 if ((info->interface == FLASH_CFI_X8X16)
1010 && (info->chipwidth == FLASH_CFI_BY8)) {
1011 size_ratio >>= 1;
1012 }
wdenke537b3b2004-02-23 23:54:43 +00001013 num_erase_regions = flash_read_uchar (info, FLASH_OFFSET_NUM_ERASE_REGIONS);
wdenke65527f2004-02-12 00:47:09 +00001014 debug ("size_ratio %d port %d bits chip %d bits\n",
1015 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1016 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1017 debug ("found %d erase regions\n", num_erase_regions);
wdenk2cefd152004-02-08 22:55:38 +00001018 sect_cnt = 0;
1019 sector = base;
wdenke65527f2004-02-12 00:47:09 +00001020 for (i = 0; i < num_erase_regions; i++) {
1021 if (i > NUM_ERASE_REGIONS) {
wdenke537b3b2004-02-23 23:54:43 +00001022 printf ("%d erase regions found, only %d used\n",
1023 num_erase_regions, NUM_ERASE_REGIONS);
wdenk2cefd152004-02-08 22:55:38 +00001024 break;
1025 }
wdenke65527f2004-02-12 00:47:09 +00001026 tmp = flash_read_long (info, 0,
1027 FLASH_OFFSET_ERASE_REGIONS +
1028 i * 4);
1029 erase_region_size =
1030 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenk2cefd152004-02-08 22:55:38 +00001031 tmp >>= 16;
wdenke65527f2004-02-12 00:47:09 +00001032 erase_region_count = (tmp & 0xffff) + 1;
wdenke537b3b2004-02-23 23:54:43 +00001033 printf ("erase_region_count = %d erase_region_size = %d\n",
1034 erase_region_count, erase_region_size);
wdenke65527f2004-02-12 00:47:09 +00001035 for (j = 0; j < erase_region_count; j++) {
wdenk2cefd152004-02-08 22:55:38 +00001036 info->start[sect_cnt] = sector;
1037 sector += (erase_region_size * size_ratio);
wdenke65527f2004-02-12 00:47:09 +00001038 info->protect[sect_cnt] =
1039 flash_isset (info, sect_cnt,
1040 FLASH_OFFSET_PROTECT,
1041 FLASH_STATUS_PROTECT);
wdenk2cefd152004-02-08 22:55:38 +00001042 sect_cnt++;
1043 }
1044 }
1045
1046 info->sector_count = sect_cnt;
1047 /* multiply the size by the number of chips */
wdenke537b3b2004-02-23 23:54:43 +00001048 info->size = (1 << flash_read_uchar (info, FLASH_OFFSET_SIZE)) * size_ratio;
1049 info->buffer_size = (1 << flash_read_ushort (info, 0, FLASH_OFFSET_BUFFER_SIZE));
wdenke65527f2004-02-12 00:47:09 +00001050 tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT);
wdenke537b3b2004-02-23 23:54:43 +00001051 info->erase_blk_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_EMAX_TOUT)));
wdenke65527f2004-02-12 00:47:09 +00001052 tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT);
wdenke537b3b2004-02-23 23:54:43 +00001053 info->buffer_write_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT)));
wdenke65527f2004-02-12 00:47:09 +00001054 tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT);
wdenke537b3b2004-02-23 23:54:43 +00001055 info->write_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT))) / 1000;
wdenk2cefd152004-02-08 22:55:38 +00001056 info->flash_id = FLASH_MAN_CFI;
1057 }
1058
wdenke65527f2004-02-12 00:47:09 +00001059 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
1060 return (info->size);
wdenk2cefd152004-02-08 22:55:38 +00001061}
1062
1063
1064/*-----------------------------------------------------------------------
1065 */
wdenke65527f2004-02-12 00:47:09 +00001066static int flash_write_cfiword (flash_info_t * info, ulong dest,
1067 cfiword_t cword)
wdenk2cefd152004-02-08 22:55:38 +00001068{
1069
1070 cfiptr_t ctladdr;
1071 cfiptr_t cptr;
1072 int flag;
1073
wdenke65527f2004-02-12 00:47:09 +00001074 ctladdr.cp = flash_make_addr (info, 0, 0);
1075 cptr.cp = (uchar *) dest;
wdenk2cefd152004-02-08 22:55:38 +00001076
1077
1078 /* Check if Flash is (sufficiently) erased */
wdenke65527f2004-02-12 00:47:09 +00001079 switch (info->portwidth) {
wdenk2cefd152004-02-08 22:55:38 +00001080 case FLASH_CFI_8BIT:
1081 flag = ((cptr.cp[0] & cword.c) == cword.c);
1082 break;
1083 case FLASH_CFI_16BIT:
1084 flag = ((cptr.wp[0] & cword.w) == cword.w);
1085 break;
1086 case FLASH_CFI_32BIT:
wdenke65527f2004-02-12 00:47:09 +00001087 flag = ((cptr.lp[0] & cword.l) == cword.l);
wdenk2cefd152004-02-08 22:55:38 +00001088 break;
1089 case FLASH_CFI_64BIT:
1090 flag = ((cptr.lp[0] & cword.ll) == cword.ll);
1091 break;
1092 default:
1093 return 2;
1094 }
wdenke65527f2004-02-12 00:47:09 +00001095 if (!flag)
wdenk2cefd152004-02-08 22:55:38 +00001096 return 2;
1097
1098 /* Disable interrupts which might cause a timeout here */
wdenke65527f2004-02-12 00:47:09 +00001099 flag = disable_interrupts ();
wdenk2cefd152004-02-08 22:55:38 +00001100
wdenke65527f2004-02-12 00:47:09 +00001101 switch (info->vendor) {
wdenk2cefd152004-02-08 22:55:38 +00001102 case CFI_CMDSET_INTEL_EXTENDED:
1103 case CFI_CMDSET_INTEL_STANDARD:
wdenke65527f2004-02-12 00:47:09 +00001104 flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
1105 flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
wdenk2cefd152004-02-08 22:55:38 +00001106 break;
1107 case CFI_CMDSET_AMD_EXTENDED:
1108 case CFI_CMDSET_AMD_STANDARD:
wdenke65527f2004-02-12 00:47:09 +00001109 flash_unlock_seq (info, 0);
1110 flash_write_cmd (info, 0, 0x555, AMD_CMD_WRITE);
wdenk2cefd152004-02-08 22:55:38 +00001111 break;
1112 }
1113
wdenke65527f2004-02-12 00:47:09 +00001114 switch (info->portwidth) {
wdenk2cefd152004-02-08 22:55:38 +00001115 case FLASH_CFI_8BIT:
1116 cptr.cp[0] = cword.c;
1117 break;
1118 case FLASH_CFI_16BIT:
1119 cptr.wp[0] = cword.w;
1120 break;
1121 case FLASH_CFI_32BIT:
1122 cptr.lp[0] = cword.l;
1123 break;
1124 case FLASH_CFI_64BIT:
1125 cptr.llp[0] = cword.ll;
1126 break;
1127 }
1128
1129 /* re-enable interrupts if necessary */
wdenke65527f2004-02-12 00:47:09 +00001130 if (flag)
1131 enable_interrupts ();
wdenk2cefd152004-02-08 22:55:38 +00001132
wdenke65527f2004-02-12 00:47:09 +00001133 return flash_full_status_check (info, 0, info->write_tout, "write");
wdenk2cefd152004-02-08 22:55:38 +00001134}
1135
1136#ifdef CFG_FLASH_USE_BUFFER_WRITE
1137
1138/* loop through the sectors from the highest address
1139 * when the passed address is greater or equal to the sector address
1140 * we have a match
1141 */
wdenke65527f2004-02-12 00:47:09 +00001142static flash_sect_t find_sector (flash_info_t * info, ulong addr)
wdenk2cefd152004-02-08 22:55:38 +00001143{
1144 flash_sect_t sector;
wdenke65527f2004-02-12 00:47:09 +00001145
1146 for (sector = info->sector_count - 1; sector >= 0; sector--) {
1147 if (addr >= info->start[sector])
wdenk2cefd152004-02-08 22:55:38 +00001148 break;
1149 }
1150 return sector;
1151}
1152
wdenke65527f2004-02-12 00:47:09 +00001153static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
1154 int len)
wdenk2cefd152004-02-08 22:55:38 +00001155{
1156 flash_sect_t sector;
1157 int cnt;
1158 int retcode;
1159 volatile cfiptr_t src;
1160 volatile cfiptr_t dst;
1161
1162 src.cp = cp;
wdenke65527f2004-02-12 00:47:09 +00001163 dst.cp = (uchar *) dest;
1164 sector = find_sector (info, dest);
1165 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1166 flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
1167 if ((retcode =
1168 flash_status_check (info, sector, info->buffer_write_tout,
1169 "write to buffer")) == ERR_OK) {
1170 /* reduce the number of loops by the width of the port */
1171 switch (info->portwidth) {
wdenk2cefd152004-02-08 22:55:38 +00001172 case FLASH_CFI_8BIT:
1173 cnt = len;
1174 break;
1175 case FLASH_CFI_16BIT:
1176 cnt = len >> 1;
1177 break;
1178 case FLASH_CFI_32BIT:
1179 cnt = len >> 2;
1180 break;
1181 case FLASH_CFI_64BIT:
1182 cnt = len >> 3;
1183 break;
1184 default:
1185 return ERR_INVAL;
1186 break;
1187 }
wdenke65527f2004-02-12 00:47:09 +00001188 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
1189 while (cnt-- > 0) {
1190 switch (info->portwidth) {
wdenk2cefd152004-02-08 22:55:38 +00001191 case FLASH_CFI_8BIT:
1192 *dst.cp++ = *src.cp++;
1193 break;
1194 case FLASH_CFI_16BIT:
1195 *dst.wp++ = *src.wp++;
1196 break;
1197 case FLASH_CFI_32BIT:
1198 *dst.lp++ = *src.lp++;
1199 break;
1200 case FLASH_CFI_64BIT:
1201 *dst.llp++ = *src.llp++;
1202 break;
1203 default:
1204 return ERR_INVAL;
1205 break;
1206 }
1207 }
wdenke65527f2004-02-12 00:47:09 +00001208 flash_write_cmd (info, sector, 0,
1209 FLASH_CMD_WRITE_BUFFER_CONFIRM);
1210 retcode =
1211 flash_full_status_check (info, sector,
1212 info->buffer_write_tout,
1213 "buffer write");
wdenk2cefd152004-02-08 22:55:38 +00001214 }
wdenke65527f2004-02-12 00:47:09 +00001215 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
wdenk2cefd152004-02-08 22:55:38 +00001216 return retcode;
1217}
1218#endif /* CFG_USE_FLASH_BUFFER_WRITE */
1219#endif /* CFG_FLASH_CFI */