blob: 3d0f2045011f1009258629ae45a8bbac9bd8ffa5 [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>
7 * Modified to work with AMD flashes
8 *
wdenkbf9e3b32004-02-12 00:47:09 +00009 * Copyright (C) 2004
10 * Ed Okerson
11 * Modified to work with little-endian systems.
12 *
wdenk5653fc32004-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.
wdenkbf9e3b32004-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
wdenk5653fc32004-02-08 22:55:38 +000036 *
37 * Tested Architectures
wdenkbf9e3b32004-02-12 00:47:09 +000038 * Port Width Chip Width # of banks Flash Chip Board
wdenk2d1a5372004-02-23 19:30:57 +000039 * 32 16 1 28F128J3 seranoa/eagle
40 * 64 16 1 28F128J3 seranoa/falcon
wdenkcd37d9e2004-02-10 00:03:41 +000041 *
wdenk5653fc32004-02-08 22:55:38 +000042 */
43
44/* The DEBUG define must be before common to enable debugging */
wdenk2d1a5372004-02-23 19:30:57 +000045/* #define DEBUG */
46
wdenk5653fc32004-02-08 22:55:38 +000047#include <common.h>
48#include <asm/processor.h>
wdenk4c0d4c32004-06-09 17:34:58 +000049#include <asm/byteorder.h>
wdenk028ab6b2004-02-23 23:54:43 +000050#include <linux/byteorder/swab.h>
wdenk2a8af182005-04-13 10:02:42 +000051#include <environment.h>
wdenkbf9e3b32004-02-12 00:47:09 +000052#ifdef CFG_FLASH_CFI_DRIVER
wdenk028ab6b2004-02-23 23:54:43 +000053
wdenk5653fc32004-02-08 22:55:38 +000054/*
55 * This file implements a Common Flash Interface (CFI) driver for U-Boot.
56 * The width of the port and the width of the chips are determined at initialization.
57 * These widths are used to calculate the address for access CFI data structures.
58 * It has been tested on an Intel Strataflash implementation and AMD 29F016D.
59 *
60 * References
61 * JEDEC Standard JESD68 - Common Flash Interface (CFI)
62 * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
63 * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
64 * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
65 *
66 * TODO
67 *
68 * Use Primary Extended Query table (PRI) and Alternate Algorithm Query
69 * Table (ALT) to determine if protection is available
70 *
71 * Add support for other command sets Use the PRI and ALT to determine command set
72 * Verify erase and program timeouts.
73 */
74
wdenkbf9e3b32004-02-12 00:47:09 +000075#ifndef CFG_FLASH_BANKS_LIST
76#define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE }
77#endif
78
wdenk5653fc32004-02-08 22:55:38 +000079#define FLASH_CMD_CFI 0x98
80#define FLASH_CMD_READ_ID 0x90
81#define FLASH_CMD_RESET 0xff
82#define FLASH_CMD_BLOCK_ERASE 0x20
83#define FLASH_CMD_ERASE_CONFIRM 0xD0
84#define FLASH_CMD_WRITE 0x40
85#define FLASH_CMD_PROTECT 0x60
86#define FLASH_CMD_PROTECT_SET 0x01
87#define FLASH_CMD_PROTECT_CLEAR 0xD0
88#define FLASH_CMD_CLEAR_STATUS 0x50
wdenkbf9e3b32004-02-12 00:47:09 +000089#define FLASH_CMD_WRITE_TO_BUFFER 0xE8
90#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0
wdenk5653fc32004-02-08 22:55:38 +000091
92#define FLASH_STATUS_DONE 0x80
93#define FLASH_STATUS_ESS 0x40
94#define FLASH_STATUS_ECLBS 0x20
95#define FLASH_STATUS_PSLBS 0x10
96#define FLASH_STATUS_VPENS 0x08
97#define FLASH_STATUS_PSS 0x04
98#define FLASH_STATUS_DPS 0x02
99#define FLASH_STATUS_R 0x01
100#define FLASH_STATUS_PROTECT 0x01
101
102#define AMD_CMD_RESET 0xF0
103#define AMD_CMD_WRITE 0xA0
104#define AMD_CMD_ERASE_START 0x80
105#define AMD_CMD_ERASE_SECTOR 0x30
wdenk855a4962004-03-14 18:23:55 +0000106#define AMD_CMD_UNLOCK_START 0xAA
107#define AMD_CMD_UNLOCK_ACK 0x55
wdenk5653fc32004-02-08 22:55:38 +0000108
109#define AMD_STATUS_TOGGLE 0x40
110#define AMD_STATUS_ERROR 0x20
wdenk855a4962004-03-14 18:23:55 +0000111#define AMD_ADDR_ERASE_START 0x555
112#define AMD_ADDR_START 0x555
113#define AMD_ADDR_ACK 0x2AA
wdenk5653fc32004-02-08 22:55:38 +0000114
115#define FLASH_OFFSET_CFI 0x55
116#define FLASH_OFFSET_CFI_RESP 0x10
wdenkbf9e3b32004-02-12 00:47:09 +0000117#define FLASH_OFFSET_PRIMARY_VENDOR 0x13
wdenk5653fc32004-02-08 22:55:38 +0000118#define FLASH_OFFSET_WTOUT 0x1F
wdenkbf9e3b32004-02-12 00:47:09 +0000119#define FLASH_OFFSET_WBTOUT 0x20
wdenk5653fc32004-02-08 22:55:38 +0000120#define FLASH_OFFSET_ETOUT 0x21
wdenkbf9e3b32004-02-12 00:47:09 +0000121#define FLASH_OFFSET_CETOUT 0x22
wdenk5653fc32004-02-08 22:55:38 +0000122#define FLASH_OFFSET_WMAX_TOUT 0x23
wdenkbf9e3b32004-02-12 00:47:09 +0000123#define FLASH_OFFSET_WBMAX_TOUT 0x24
wdenk5653fc32004-02-08 22:55:38 +0000124#define FLASH_OFFSET_EMAX_TOUT 0x25
wdenkbf9e3b32004-02-12 00:47:09 +0000125#define FLASH_OFFSET_CEMAX_TOUT 0x26
wdenk5653fc32004-02-08 22:55:38 +0000126#define FLASH_OFFSET_SIZE 0x27
wdenkbf9e3b32004-02-12 00:47:09 +0000127#define FLASH_OFFSET_INTERFACE 0x28
128#define FLASH_OFFSET_BUFFER_SIZE 0x2A
wdenk5653fc32004-02-08 22:55:38 +0000129#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C
130#define FLASH_OFFSET_ERASE_REGIONS 0x2D
131#define FLASH_OFFSET_PROTECT 0x02
wdenkbf9e3b32004-02-12 00:47:09 +0000132#define FLASH_OFFSET_USER_PROTECTION 0x85
133#define FLASH_OFFSET_INTEL_PROTECTION 0x81
wdenk5653fc32004-02-08 22:55:38 +0000134
135
136#define FLASH_MAN_CFI 0x01000000
137
wdenkbf9e3b32004-02-12 00:47:09 +0000138#define CFI_CMDSET_NONE 0
wdenk5653fc32004-02-08 22:55:38 +0000139#define CFI_CMDSET_INTEL_EXTENDED 1
wdenkbf9e3b32004-02-12 00:47:09 +0000140#define CFI_CMDSET_AMD_STANDARD 2
wdenk5653fc32004-02-08 22:55:38 +0000141#define CFI_CMDSET_INTEL_STANDARD 3
wdenkbf9e3b32004-02-12 00:47:09 +0000142#define CFI_CMDSET_AMD_EXTENDED 4
wdenk5653fc32004-02-08 22:55:38 +0000143#define CFI_CMDSET_MITSU_STANDARD 256
144#define CFI_CMDSET_MITSU_EXTENDED 257
wdenkbf9e3b32004-02-12 00:47:09 +0000145#define CFI_CMDSET_SST 258
wdenk5653fc32004-02-08 22:55:38 +0000146
147
wdenkf7d15722004-12-18 22:35:43 +0000148#ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
149# undef FLASH_CMD_RESET
150# define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */
151#endif
152
153
wdenk5653fc32004-02-08 22:55:38 +0000154typedef union {
155 unsigned char c;
156 unsigned short w;
157 unsigned long l;
158 unsigned long long ll;
159} cfiword_t;
160
161typedef union {
wdenkbf9e3b32004-02-12 00:47:09 +0000162 volatile unsigned char *cp;
wdenk5653fc32004-02-08 22:55:38 +0000163 volatile unsigned short *wp;
wdenkbf9e3b32004-02-12 00:47:09 +0000164 volatile unsigned long *lp;
wdenk5653fc32004-02-08 22:55:38 +0000165 volatile unsigned long long *llp;
166} cfiptr_t;
167
168#define NUM_ERASE_REGIONS 4
169
170static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST;
171
wdenkbf9e3b32004-02-12 00:47:09 +0000172flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
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);
wdenkbf9e3b32004-02-12 00:47:09 +0000187static int flash_detect_cfi (flash_info_t * info);
wdenk5653fc32004-02-08 22:55:38 +0000188static ulong flash_get_size (ulong base, int banknum);
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);
wdenk7680c142005-05-16 15:23:22 +0000192static flash_info_t *flash_get_info(ulong base);
wdenk5653fc32004-02-08 22:55:38 +0000193#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenk028ab6b2004-02-23 23:54:43 +0000194static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, int len);
wdenk5653fc32004-02-08 22:55:38 +0000195#endif
196
wdenk5653fc32004-02-08 22:55:38 +0000197/*-----------------------------------------------------------------------
198 * create an address based on the offset and the port width
199 */
wdenk028ab6b2004-02-23 23:54:43 +0000200inline uchar *flash_make_addr (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000201{
wdenkbf9e3b32004-02-12 00:47:09 +0000202 return ((uchar *) (info->start[sect] + (offset * info->portwidth)));
wdenk5653fc32004-02-08 22:55:38 +0000203}
wdenkbf9e3b32004-02-12 00:47:09 +0000204
205#ifdef DEBUG
206/*-----------------------------------------------------------------------
207 * Debug support
208 */
209void print_longlong (char *str, unsigned long long data)
210{
211 int i;
212 char *cp;
213
214 cp = (unsigned char *) &data;
215 for (i = 0; i < 8; i++)
216 sprintf (&str[i * 2], "%2.2x", *cp++);
217}
218static void flash_printqry (flash_info_t * info, flash_sect_t sect)
219{
220 cfiptr_t cptr;
221 int x, y;
222
223 for (x = 0; x < 0x40; x += 16 / info->portwidth) {
224 cptr.cp =
225 flash_make_addr (info, sect,
226 x + FLASH_OFFSET_CFI_RESP);
227 debug ("%p : ", cptr.cp);
228 for (y = 0; y < 16; y++) {
229 debug ("%2.2x ", cptr.cp[y]);
230 }
231 debug (" ");
232 for (y = 0; y < 16; y++) {
233 if (cptr.cp[y] >= 0x20 && cptr.cp[y] <= 0x7e) {
234 debug ("%c", cptr.cp[y]);
235 } else {
236 debug (".");
237 }
238 }
239 debug ("\n");
240 }
241}
wdenkbf9e3b32004-02-12 00:47:09 +0000242#endif
243
244
wdenk5653fc32004-02-08 22:55:38 +0000245/*-----------------------------------------------------------------------
246 * read a character at a port width address
247 */
wdenkbf9e3b32004-02-12 00:47:09 +0000248inline uchar flash_read_uchar (flash_info_t * info, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000249{
250 uchar *cp;
wdenkbf9e3b32004-02-12 00:47:09 +0000251
252 cp = flash_make_addr (info, 0, offset);
253#if defined(__LITTLE_ENDIAN)
254 return (cp[0]);
255#else
wdenk5653fc32004-02-08 22:55:38 +0000256 return (cp[info->portwidth - 1]);
wdenkbf9e3b32004-02-12 00:47:09 +0000257#endif
wdenk5653fc32004-02-08 22:55:38 +0000258}
259
260/*-----------------------------------------------------------------------
261 * read a short word by swapping for ppc format.
262 */
wdenkbf9e3b32004-02-12 00:47:09 +0000263ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000264{
wdenkbf9e3b32004-02-12 00:47:09 +0000265 uchar *addr;
266 ushort retval;
wdenk5653fc32004-02-08 22:55:38 +0000267
wdenkbf9e3b32004-02-12 00:47:09 +0000268#ifdef DEBUG
269 int x;
270#endif
271 addr = flash_make_addr (info, sect, offset);
wdenk5653fc32004-02-08 22:55:38 +0000272
wdenkbf9e3b32004-02-12 00:47:09 +0000273#ifdef DEBUG
274 debug ("ushort addr is at %p info->portwidth = %d\n", addr,
275 info->portwidth);
276 for (x = 0; x < 2 * info->portwidth; x++) {
277 debug ("addr[%x] = 0x%x\n", x, addr[x]);
278 }
279#endif
280#if defined(__LITTLE_ENDIAN)
281 retval = ((addr[(info->portwidth)] << 8) | addr[0]);
282#else
283 retval = ((addr[(2 * info->portwidth) - 1] << 8) |
284 addr[info->portwidth - 1]);
285#endif
286
287 debug ("retval = 0x%x\n", retval);
288 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000289}
290
291/*-----------------------------------------------------------------------
292 * read a long word by picking the least significant byte of each maiximum
293 * port size word. Swap for ppc format.
294 */
wdenkbf9e3b32004-02-12 00:47:09 +0000295ulong flash_read_long (flash_info_t * info, flash_sect_t sect, uint offset)
wdenk5653fc32004-02-08 22:55:38 +0000296{
wdenkbf9e3b32004-02-12 00:47:09 +0000297 uchar *addr;
298 ulong retval;
wdenk5653fc32004-02-08 22:55:38 +0000299
wdenkbf9e3b32004-02-12 00:47:09 +0000300#ifdef DEBUG
301 int x;
302#endif
303 addr = flash_make_addr (info, sect, offset);
304
305#ifdef DEBUG
306 debug ("long addr is at %p info->portwidth = %d\n", addr,
307 info->portwidth);
308 for (x = 0; x < 4 * info->portwidth; x++) {
309 debug ("addr[%x] = 0x%x\n", x, addr[x]);
310 }
311#endif
312#if defined(__LITTLE_ENDIAN)
313 retval = (addr[0] << 16) | (addr[(info->portwidth)] << 24) |
wdenk028ab6b2004-02-23 23:54:43 +0000314 (addr[(2 * info->portwidth)]) | (addr[(3 * info->portwidth)] << 8);
wdenkbf9e3b32004-02-12 00:47:09 +0000315#else
316 retval = (addr[(2 * info->portwidth) - 1] << 24) |
317 (addr[(info->portwidth) - 1] << 16) |
318 (addr[(4 * info->portwidth) - 1] << 8) |
319 addr[(3 * info->portwidth) - 1];
320#endif
321 return retval;
wdenk5653fc32004-02-08 22:55:38 +0000322}
323
324/*-----------------------------------------------------------------------
325 */
326unsigned long flash_init (void)
327{
328 unsigned long size = 0;
329 int i;
330
331 /* Init: no FLASHes known */
wdenkbf9e3b32004-02-12 00:47:09 +0000332 for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
wdenk5653fc32004-02-08 22:55:38 +0000333 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenkbf9e3b32004-02-12 00:47:09 +0000334 size += flash_info[i].size = flash_get_size (bank_base[i], i);
wdenk5653fc32004-02-08 22:55:38 +0000335 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
wdenk028ab6b2004-02-23 23:54:43 +0000336 printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
337 i, flash_info[i].size, flash_info[i].size << 20);
wdenk5653fc32004-02-08 22:55:38 +0000338 }
339 }
340
341 /* Monitor protection ON by default */
342#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
wdenkbf9e3b32004-02-12 00:47:09 +0000343 flash_protect (FLAG_PROTECT_SET,
344 CFG_MONITOR_BASE,
wdenk7680c142005-05-16 15:23:22 +0000345 CFG_MONITOR_BASE + monitor_flash_len - 1,
346 flash_get_info(CFG_MONITOR_BASE));
wdenk5653fc32004-02-08 22:55:38 +0000347#endif
348
wdenk656658d2004-10-10 22:16:06 +0000349 /* Environment protection ON by default */
350#ifdef CFG_ENV_IS_IN_FLASH
351 flash_protect (FLAG_PROTECT_SET,
352 CFG_ENV_ADDR,
353 CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
wdenk7680c142005-05-16 15:23:22 +0000354 flash_get_info(CFG_ENV_ADDR));
wdenk656658d2004-10-10 22:16:06 +0000355#endif
356
357 /* Redundant environment protection ON by default */
358#ifdef CFG_ENV_ADDR_REDUND
359 flash_protect (FLAG_PROTECT_SET,
360 CFG_ENV_ADDR_REDUND,
361 CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
wdenk7680c142005-05-16 15:23:22 +0000362 flash_get_info(CFG_ENV_ADDR_REDUND));
wdenk656658d2004-10-10 22:16:06 +0000363#endif
wdenk5653fc32004-02-08 22:55:38 +0000364 return (size);
365}
366
367/*-----------------------------------------------------------------------
368 */
wdenk7680c142005-05-16 15:23:22 +0000369static flash_info_t *flash_get_info(ulong base)
370{
371 int i;
372 flash_info_t * info;
373
374 for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) {
375 info = & flash_info[i];
376 if (info->size && info->start[0] <= base &&
377 base <= info->start[0] + info->size - 1)
378 break;
379 }
380
381 return i == CFG_MAX_FLASH_BANKS ? 0 : info;
382}
383
384/*-----------------------------------------------------------------------
385 */
wdenkbf9e3b32004-02-12 00:47:09 +0000386int flash_erase (flash_info_t * info, int s_first, int s_last)
wdenk5653fc32004-02-08 22:55:38 +0000387{
388 int rcode = 0;
389 int prot;
390 flash_sect_t sect;
391
wdenkbf9e3b32004-02-12 00:47:09 +0000392 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +0000393 puts ("Can't erase unknown flash type - aborted\n");
wdenk5653fc32004-02-08 22:55:38 +0000394 return 1;
395 }
396 if ((s_first < 0) || (s_first > s_last)) {
wdenk4b9206e2004-03-23 22:14:11 +0000397 puts ("- no sectors to erase\n");
wdenk5653fc32004-02-08 22:55:38 +0000398 return 1;
399 }
400
401 prot = 0;
wdenkbf9e3b32004-02-12 00:47:09 +0000402 for (sect = s_first; sect <= s_last; ++sect) {
wdenk5653fc32004-02-08 22:55:38 +0000403 if (info->protect[sect]) {
404 prot++;
405 }
406 }
407 if (prot) {
wdenkbf9e3b32004-02-12 00:47:09 +0000408 printf ("- Warning: %d protected sectors will not be erased!\n", prot);
wdenk5653fc32004-02-08 22:55:38 +0000409 } else {
wdenk4b9206e2004-03-23 22:14:11 +0000410 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +0000411 }
412
413
wdenkbf9e3b32004-02-12 00:47:09 +0000414 for (sect = s_first; sect <= s_last; sect++) {
wdenk5653fc32004-02-08 22:55:38 +0000415 if (info->protect[sect] == 0) { /* not protected */
wdenkbf9e3b32004-02-12 00:47:09 +0000416 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +0000417 case CFI_CMDSET_INTEL_STANDARD:
418 case CFI_CMDSET_INTEL_EXTENDED:
wdenk028ab6b2004-02-23 23:54:43 +0000419 flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS);
420 flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE);
421 flash_write_cmd (info, sect, 0, FLASH_CMD_ERASE_CONFIRM);
wdenk5653fc32004-02-08 22:55:38 +0000422 break;
423 case CFI_CMDSET_AMD_STANDARD:
424 case CFI_CMDSET_AMD_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +0000425 flash_unlock_seq (info, sect);
wdenk855a4962004-03-14 18:23:55 +0000426 flash_write_cmd (info, sect, AMD_ADDR_ERASE_START,
427 AMD_CMD_ERASE_START);
wdenkbf9e3b32004-02-12 00:47:09 +0000428 flash_unlock_seq (info, sect);
wdenk028ab6b2004-02-23 23:54:43 +0000429 flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR);
wdenk5653fc32004-02-08 22:55:38 +0000430 break;
431 default:
wdenkbf9e3b32004-02-12 00:47:09 +0000432 debug ("Unkown flash vendor %d\n",
433 info->vendor);
wdenk5653fc32004-02-08 22:55:38 +0000434 break;
435 }
436
wdenkbf9e3b32004-02-12 00:47:09 +0000437 if (flash_full_status_check
438 (info, sect, info->erase_blk_tout, "erase")) {
wdenk5653fc32004-02-08 22:55:38 +0000439 rcode = 1;
440 } else
wdenk4b9206e2004-03-23 22:14:11 +0000441 putc ('.');
wdenk5653fc32004-02-08 22:55:38 +0000442 }
443 }
wdenk4b9206e2004-03-23 22:14:11 +0000444 puts (" done\n");
wdenk5653fc32004-02-08 22:55:38 +0000445 return rcode;
446}
447
448/*-----------------------------------------------------------------------
449 */
wdenkbf9e3b32004-02-12 00:47:09 +0000450void flash_print_info (flash_info_t * info)
wdenk5653fc32004-02-08 22:55:38 +0000451{
452 int i;
453
454 if (info->flash_id != FLASH_MAN_CFI) {
wdenk4b9206e2004-03-23 22:14:11 +0000455 puts ("missing or unknown FLASH type\n");
wdenk5653fc32004-02-08 22:55:38 +0000456 return;
457 }
458
wdenkbf9e3b32004-02-12 00:47:09 +0000459 printf ("CFI conformant FLASH (%d x %d)",
460 (info->portwidth << 3), (info->chipwidth << 3));
wdenk5653fc32004-02-08 22:55:38 +0000461 printf (" Size: %ld MB in %d Sectors\n",
462 info->size >> 20, info->sector_count);
wdenk028ab6b2004-02-23 23:54:43 +0000463 printf (" Erase timeout %ld ms, write timeout %ld ms, buffer write timeout %ld ms, buffer size %d\n",
464 info->erase_blk_tout,
465 info->write_tout,
466 info->buffer_write_tout,
467 info->buffer_size);
wdenk5653fc32004-02-08 22:55:38 +0000468
wdenk4b9206e2004-03-23 22:14:11 +0000469 puts (" Sector Start Addresses:");
wdenkbf9e3b32004-02-12 00:47:09 +0000470 for (i = 0; i < info->sector_count; ++i) {
wdenk5653fc32004-02-08 22:55:38 +0000471#ifdef CFG_FLASH_EMPTY_INFO
472 int k;
473 int size;
474 int erased;
475 volatile unsigned long *flash;
476
477 /*
478 * Check if whole sector is erased
479 */
wdenkbf9e3b32004-02-12 00:47:09 +0000480 if (i != (info->sector_count - 1))
481 size = info->start[i + 1] - info->start[i];
wdenk5653fc32004-02-08 22:55:38 +0000482 else
wdenkbf9e3b32004-02-12 00:47:09 +0000483 size = info->start[0] + info->size - info->start[i];
wdenk5653fc32004-02-08 22:55:38 +0000484 erased = 1;
wdenkbf9e3b32004-02-12 00:47:09 +0000485 flash = (volatile unsigned long *) info->start[i];
486 size = size >> 2; /* divide by 4 for longword access */
487 for (k = 0; k < size; k++) {
488 if (*flash++ != 0xffffffff) {
489 erased = 0;
490 break;
491 }
492 }
wdenk5653fc32004-02-08 22:55:38 +0000493
494 if ((i % 5) == 0)
495 printf ("\n");
496 /* print empty and read-only info */
497 printf (" %08lX%s%s",
498 info->start[i],
499 erased ? " E" : " ",
500 info->protect[i] ? "RO " : " ");
501#else
502 if ((i % 5) == 0)
503 printf ("\n ");
504 printf (" %08lX%s",
wdenk30d56fa2004-10-09 22:44:59 +0000505 info->start[i], info->protect[i] ? " (RO) " : " ");
wdenk5653fc32004-02-08 22:55:38 +0000506#endif
507 }
wdenk4b9206e2004-03-23 22:14:11 +0000508 putc ('\n');
wdenk5653fc32004-02-08 22:55:38 +0000509 return;
510}
511
512/*-----------------------------------------------------------------------
513 * Copy memory to flash, returns:
514 * 0 - OK
515 * 1 - write timeout
516 * 2 - Flash not erased
517 */
wdenkbf9e3b32004-02-12 00:47:09 +0000518int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wdenk5653fc32004-02-08 22:55:38 +0000519{
520 ulong wp;
521 ulong cp;
522 int aln;
523 cfiword_t cword;
524 int i, rc;
525
wdenkbf9e3b32004-02-12 00:47:09 +0000526#ifdef CFG_FLASH_USE_BUFFER_WRITE
527 int buffered_size;
528#endif
wdenkbf9e3b32004-02-12 00:47:09 +0000529 /* get lower aligned address */
wdenk5653fc32004-02-08 22:55:38 +0000530 /* get lower aligned address */
531 wp = (addr & ~(info->portwidth - 1));
532
533 /* handle unaligned start */
wdenkbf9e3b32004-02-12 00:47:09 +0000534 if ((aln = addr - wp) != 0) {
wdenk5653fc32004-02-08 22:55:38 +0000535 cword.l = 0;
536 cp = wp;
wdenkbf9e3b32004-02-12 00:47:09 +0000537 for (i = 0; i < aln; ++i, ++cp)
538 flash_add_byte (info, &cword, (*(uchar *) cp));
wdenk5653fc32004-02-08 22:55:38 +0000539
wdenkbf9e3b32004-02-12 00:47:09 +0000540 for (; (i < info->portwidth) && (cnt > 0); i++) {
541 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +0000542 cnt--;
543 cp++;
544 }
wdenkbf9e3b32004-02-12 00:47:09 +0000545 for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp)
546 flash_add_byte (info, &cword, (*(uchar *) cp));
547 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk5653fc32004-02-08 22:55:38 +0000548 return rc;
549 wp = cp;
550 }
551
wdenkbf9e3b32004-02-12 00:47:09 +0000552 /* handle the aligned part */
wdenk5653fc32004-02-08 22:55:38 +0000553#ifdef CFG_FLASH_USE_BUFFER_WRITE
wdenkbf9e3b32004-02-12 00:47:09 +0000554 buffered_size = (info->portwidth / info->chipwidth);
555 buffered_size *= info->buffer_size;
556 while (cnt >= info->portwidth) {
557 i = buffered_size > cnt ? cnt : buffered_size;
558 if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
wdenk5653fc32004-02-08 22:55:38 +0000559 return rc;
Wolfgang Denk8d4ba3d2005-08-12 22:35:59 +0200560 i -= i & (info->portwidth - 1);
wdenk5653fc32004-02-08 22:55:38 +0000561 wp += i;
562 src += i;
wdenkbf9e3b32004-02-12 00:47:09 +0000563 cnt -= i;
wdenk5653fc32004-02-08 22:55:38 +0000564 }
565#else
wdenkbf9e3b32004-02-12 00:47:09 +0000566 while (cnt >= info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +0000567 cword.l = 0;
wdenkbf9e3b32004-02-12 00:47:09 +0000568 for (i = 0; i < info->portwidth; i++) {
569 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +0000570 }
wdenkbf9e3b32004-02-12 00:47:09 +0000571 if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
wdenk5653fc32004-02-08 22:55:38 +0000572 return rc;
573 wp += info->portwidth;
574 cnt -= info->portwidth;
575 }
576#endif /* CFG_FLASH_USE_BUFFER_WRITE */
577 if (cnt == 0) {
578 return (0);
579 }
580
581 /*
582 * handle unaligned tail bytes
583 */
584 cword.l = 0;
wdenkbf9e3b32004-02-12 00:47:09 +0000585 for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) {
586 flash_add_byte (info, &cword, *src++);
wdenk5653fc32004-02-08 22:55:38 +0000587 --cnt;
588 }
wdenkbf9e3b32004-02-12 00:47:09 +0000589 for (; i < info->portwidth; ++i, ++cp) {
590 flash_add_byte (info, &cword, (*(uchar *) cp));
wdenk5653fc32004-02-08 22:55:38 +0000591 }
592
wdenkbf9e3b32004-02-12 00:47:09 +0000593 return flash_write_cfiword (info, wp, cword);
wdenk5653fc32004-02-08 22:55:38 +0000594}
595
596/*-----------------------------------------------------------------------
597 */
598#ifdef CFG_FLASH_PROTECTION
599
wdenkbf9e3b32004-02-12 00:47:09 +0000600int flash_real_protect (flash_info_t * info, long sector, int prot)
wdenk5653fc32004-02-08 22:55:38 +0000601{
602 int retcode = 0;
603
wdenkbf9e3b32004-02-12 00:47:09 +0000604 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
605 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
606 if (prot)
607 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
wdenk5653fc32004-02-08 22:55:38 +0000608 else
wdenkbf9e3b32004-02-12 00:47:09 +0000609 flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
wdenk5653fc32004-02-08 22:55:38 +0000610
wdenkbf9e3b32004-02-12 00:47:09 +0000611 if ((retcode =
612 flash_full_status_check (info, sector, info->erase_blk_tout,
613 prot ? "protect" : "unprotect")) == 0) {
wdenk5653fc32004-02-08 22:55:38 +0000614
615 info->protect[sector] = prot;
616 /* Intel's unprotect unprotects all locking */
wdenkbf9e3b32004-02-12 00:47:09 +0000617 if (prot == 0) {
wdenk5653fc32004-02-08 22:55:38 +0000618 flash_sect_t i;
wdenkbf9e3b32004-02-12 00:47:09 +0000619
620 for (i = 0; i < info->sector_count; i++) {
621 if (info->protect[i])
622 flash_real_protect (info, i, 1);
wdenk5653fc32004-02-08 22:55:38 +0000623 }
624 }
625 }
wdenk5653fc32004-02-08 22:55:38 +0000626 return retcode;
wdenkbf9e3b32004-02-12 00:47:09 +0000627}
628
wdenk5653fc32004-02-08 22:55:38 +0000629/*-----------------------------------------------------------------------
630 * flash_read_user_serial - read the OneTimeProgramming cells
631 */
wdenkbf9e3b32004-02-12 00:47:09 +0000632void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
633 int len)
wdenk5653fc32004-02-08 22:55:38 +0000634{
wdenkbf9e3b32004-02-12 00:47:09 +0000635 uchar *src;
636 uchar *dst;
wdenk5653fc32004-02-08 22:55:38 +0000637
638 dst = buffer;
wdenkbf9e3b32004-02-12 00:47:09 +0000639 src = flash_make_addr (info, 0, FLASH_OFFSET_USER_PROTECTION);
640 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
641 memcpy (dst, src + offset, len);
642 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
wdenk5653fc32004-02-08 22:55:38 +0000643}
wdenkbf9e3b32004-02-12 00:47:09 +0000644
wdenk5653fc32004-02-08 22:55:38 +0000645/*
646 * flash_read_factory_serial - read the device Id from the protection area
647 */
wdenkbf9e3b32004-02-12 00:47:09 +0000648void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
649 int len)
wdenk5653fc32004-02-08 22:55:38 +0000650{
wdenkbf9e3b32004-02-12 00:47:09 +0000651 uchar *src;
wdenkcd37d9e2004-02-10 00:03:41 +0000652
wdenkbf9e3b32004-02-12 00:47:09 +0000653 src = flash_make_addr (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
654 flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
655 memcpy (buffer, src + offset, len);
656 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
wdenk5653fc32004-02-08 22:55:38 +0000657}
658
659#endif /* CFG_FLASH_PROTECTION */
660
wdenkbf9e3b32004-02-12 00:47:09 +0000661/*
662 * flash_is_busy - check to see if the flash is busy
663 * This routine checks the status of the chip and returns true if the chip is busy
664 */
665static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
wdenk5653fc32004-02-08 22:55:38 +0000666{
667 int retval;
wdenkbf9e3b32004-02-12 00:47:09 +0000668
669 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +0000670 case CFI_CMDSET_INTEL_STANDARD:
671 case CFI_CMDSET_INTEL_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +0000672 retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
wdenk5653fc32004-02-08 22:55:38 +0000673 break;
674 case CFI_CMDSET_AMD_STANDARD:
675 case CFI_CMDSET_AMD_EXTENDED:
wdenkbf9e3b32004-02-12 00:47:09 +0000676 retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
wdenk5653fc32004-02-08 22:55:38 +0000677 break;
678 default:
679 retval = 0;
680 }
wdenkbf9e3b32004-02-12 00:47:09 +0000681 debug ("flash_is_busy: %d\n", retval);
wdenk5653fc32004-02-08 22:55:38 +0000682 return retval;
683}
wdenkbf9e3b32004-02-12 00:47:09 +0000684
wdenk5653fc32004-02-08 22:55:38 +0000685/*-----------------------------------------------------------------------
686 * wait for XSR.7 to be set. Time out with an error if it does not.
687 * This routine does not set the flash to read-array mode.
688 */
wdenkbf9e3b32004-02-12 00:47:09 +0000689static int flash_status_check (flash_info_t * info, flash_sect_t sector,
690 ulong tout, char *prompt)
wdenk5653fc32004-02-08 22:55:38 +0000691{
692 ulong start;
693
694 /* Wait for command completion */
695 start = get_timer (0);
wdenkbf9e3b32004-02-12 00:47:09 +0000696 while (flash_is_busy (info, sector)) {
697 if (get_timer (start) > info->erase_blk_tout * CFG_HZ) {
698 printf ("Flash %s timeout at address %lx data %lx\n",
699 prompt, info->start[sector],
700 flash_read_long (info, sector, 0));
701 flash_write_cmd (info, sector, 0, info->cmd_reset);
wdenk5653fc32004-02-08 22:55:38 +0000702 return ERR_TIMOUT;
703 }
704 }
705 return ERR_OK;
706}
wdenkbf9e3b32004-02-12 00:47:09 +0000707
wdenk5653fc32004-02-08 22:55:38 +0000708/*-----------------------------------------------------------------------
709 * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check.
710 * This routine sets the flash to read-array mode.
711 */
wdenkbf9e3b32004-02-12 00:47:09 +0000712static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
713 ulong tout, char *prompt)
wdenk5653fc32004-02-08 22:55:38 +0000714{
715 int retcode;
wdenkbf9e3b32004-02-12 00:47:09 +0000716
717 retcode = flash_status_check (info, sector, tout, prompt);
718 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +0000719 case CFI_CMDSET_INTEL_EXTENDED:
720 case CFI_CMDSET_INTEL_STANDARD:
wdenkbf9e3b32004-02-12 00:47:09 +0000721 if ((retcode != ERR_OK)
722 && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
wdenk5653fc32004-02-08 22:55:38 +0000723 retcode = ERR_INVAL;
wdenkbf9e3b32004-02-12 00:47:09 +0000724 printf ("Flash %s error at address %lx\n", prompt,
725 info->start[sector]);
wdenk028ab6b2004-02-23 23:54:43 +0000726 if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) {
wdenk4b9206e2004-03-23 22:14:11 +0000727 puts ("Command Sequence Error.\n");
wdenk028ab6b2004-02-23 23:54:43 +0000728 } else if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS)) {
wdenk4b9206e2004-03-23 22:14:11 +0000729 puts ("Block Erase Error.\n");
wdenk5653fc32004-02-08 22:55:38 +0000730 retcode = ERR_NOT_ERASED;
wdenk028ab6b2004-02-23 23:54:43 +0000731 } else if (flash_isset (info, sector, 0, FLASH_STATUS_PSLBS)) {
wdenk4b9206e2004-03-23 22:14:11 +0000732 puts ("Locking Error\n");
wdenk5653fc32004-02-08 22:55:38 +0000733 }
wdenkbf9e3b32004-02-12 00:47:09 +0000734 if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
wdenk4b9206e2004-03-23 22:14:11 +0000735 puts ("Block locked.\n");
wdenkbf9e3b32004-02-12 00:47:09 +0000736 retcode = ERR_PROTECTED;
737 }
738 if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
wdenk4b9206e2004-03-23 22:14:11 +0000739 puts ("Vpp Low Error.\n");
wdenk5653fc32004-02-08 22:55:38 +0000740 }
wdenkbf9e3b32004-02-12 00:47:09 +0000741 flash_write_cmd (info, sector, 0, FLASH_CMD_RESET);
wdenk5653fc32004-02-08 22:55:38 +0000742 break;
743 default:
744 break;
745 }
746 return retcode;
747}
wdenkbf9e3b32004-02-12 00:47:09 +0000748
wdenk5653fc32004-02-08 22:55:38 +0000749/*-----------------------------------------------------------------------
750 */
wdenkbf9e3b32004-02-12 00:47:09 +0000751static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
wdenk5653fc32004-02-08 22:55:38 +0000752{
wdenk4d13cba2004-03-14 14:09:05 +0000753#if defined(__LITTLE_ENDIAN)
754 unsigned short w;
755 unsigned int l;
756 unsigned long long ll;
757#endif
758
wdenkbf9e3b32004-02-12 00:47:09 +0000759 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +0000760 case FLASH_CFI_8BIT:
761 cword->c = c;
762 break;
763 case FLASH_CFI_16BIT:
wdenk4d13cba2004-03-14 14:09:05 +0000764#if defined(__LITTLE_ENDIAN)
765 w = c;
766 w <<= 8;
767 cword->w = (cword->w >> 8) | w;
768#else
wdenk5653fc32004-02-08 22:55:38 +0000769 cword->w = (cword->w << 8) | c;
wdenk4d13cba2004-03-14 14:09:05 +0000770#endif
wdenk5653fc32004-02-08 22:55:38 +0000771 break;
772 case FLASH_CFI_32BIT:
wdenk4d13cba2004-03-14 14:09:05 +0000773#if defined(__LITTLE_ENDIAN)
774 l = c;
775 l <<= 24;
776 cword->l = (cword->l >> 8) | l;
777#else
wdenk5653fc32004-02-08 22:55:38 +0000778 cword->l = (cword->l << 8) | c;
wdenk4d13cba2004-03-14 14:09:05 +0000779#endif
wdenk5653fc32004-02-08 22:55:38 +0000780 break;
781 case FLASH_CFI_64BIT:
wdenk4d13cba2004-03-14 14:09:05 +0000782#if defined(__LITTLE_ENDIAN)
783 ll = c;
784 ll <<= 56;
785 cword->ll = (cword->ll >> 8) | ll;
786#else
wdenk5653fc32004-02-08 22:55:38 +0000787 cword->ll = (cword->ll << 8) | c;
wdenk4d13cba2004-03-14 14:09:05 +0000788#endif
wdenk5653fc32004-02-08 22:55:38 +0000789 break;
790 }
791}
792
793
794/*-----------------------------------------------------------------------
795 * make a proper sized command based on the port and chip widths
796 */
wdenkbf9e3b32004-02-12 00:47:09 +0000797static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
wdenk5653fc32004-02-08 22:55:38 +0000798{
799 int i;
wdenkbf9e3b32004-02-12 00:47:09 +0000800
801#if defined(__LITTLE_ENDIAN)
wdenk028ab6b2004-02-23 23:54:43 +0000802 ushort stmpw;
803 uint stmpi;
wdenkbf9e3b32004-02-12 00:47:09 +0000804#endif
805 uchar *cp = (uchar *) cmdbuf;
806
807 for (i = 0; i < info->portwidth; i++)
Wolfgang Denk8d4ba3d2005-08-12 22:35:59 +0200808 *cp++ = ((i + 1) & (info->chipwidth - 1)) ? '\0' : cmd;
wdenkbf9e3b32004-02-12 00:47:09 +0000809#if defined(__LITTLE_ENDIAN)
wdenk028ab6b2004-02-23 23:54:43 +0000810 switch (info->portwidth) {
811 case FLASH_CFI_8BIT:
812 break;
813 case FLASH_CFI_16BIT:
814 stmpw = *(ushort *) cmdbuf;
815 *(ushort *) cmdbuf = __swab16 (stmpw);
816 break;
817 case FLASH_CFI_32BIT:
818 stmpi = *(uint *) cmdbuf;
819 *(uint *) cmdbuf = __swab32 (stmpi);
820 break;
821 default:
wdenk4b9206e2004-03-23 22:14:11 +0000822 puts ("WARNING: flash_make_cmd: unsuppported LittleEndian mode\n");
wdenk028ab6b2004-02-23 23:54:43 +0000823 break;
wdenkbf9e3b32004-02-12 00:47:09 +0000824 }
825#endif
wdenk5653fc32004-02-08 22:55:38 +0000826}
827
828/*
829 * Write a proper sized command to the correct address
830 */
wdenk028ab6b2004-02-23 23:54:43 +0000831static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk5653fc32004-02-08 22:55:38 +0000832{
833
834 volatile cfiptr_t addr;
835 cfiword_t cword;
wdenkbf9e3b32004-02-12 00:47:09 +0000836
837 addr.cp = flash_make_addr (info, sect, offset);
838 flash_make_cmd (info, cmd, &cword);
839 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +0000840 case FLASH_CFI_8BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000841 debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr.cp, cmd,
842 cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
wdenk5653fc32004-02-08 22:55:38 +0000843 *addr.cp = cword.c;
844 break;
845 case FLASH_CFI_16BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000846 debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr.wp,
847 cmd, cword.w,
wdenk5653fc32004-02-08 22:55:38 +0000848 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
849 *addr.wp = cword.w;
850 break;
851 case FLASH_CFI_32BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000852 debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr.lp,
853 cmd, cword.l,
wdenk5653fc32004-02-08 22:55:38 +0000854 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
855 *addr.lp = cword.l;
856 break;
857 case FLASH_CFI_64BIT:
858#ifdef DEBUG
wdenkbf9e3b32004-02-12 00:47:09 +0000859 {
wdenk5653fc32004-02-08 22:55:38 +0000860 char str[20];
wdenkcd37d9e2004-02-10 00:03:41 +0000861
wdenkbf9e3b32004-02-12 00:47:09 +0000862 print_longlong (str, cword.ll);
863
864 debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
865 addr.llp, cmd, str,
wdenk5653fc32004-02-08 22:55:38 +0000866 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
867 }
868#endif
869 *addr.llp = cword.ll;
870 break;
871 }
872}
873
wdenkbf9e3b32004-02-12 00:47:09 +0000874static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
wdenk5653fc32004-02-08 22:55:38 +0000875{
wdenk855a4962004-03-14 18:23:55 +0000876 flash_write_cmd (info, sect, AMD_ADDR_START, AMD_CMD_UNLOCK_START);
877 flash_write_cmd (info, sect, AMD_ADDR_ACK, AMD_CMD_UNLOCK_ACK);
wdenk5653fc32004-02-08 22:55:38 +0000878}
wdenkbf9e3b32004-02-12 00:47:09 +0000879
wdenk5653fc32004-02-08 22:55:38 +0000880/*-----------------------------------------------------------------------
881 */
wdenk028ab6b2004-02-23 23:54:43 +0000882static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk5653fc32004-02-08 22:55:38 +0000883{
884 cfiptr_t cptr;
885 cfiword_t cword;
886 int retval;
wdenk5653fc32004-02-08 22:55:38 +0000887
wdenkbf9e3b32004-02-12 00:47:09 +0000888 cptr.cp = flash_make_addr (info, sect, offset);
889 flash_make_cmd (info, cmd, &cword);
890
891 debug ("is= cmd %x(%c) addr %p ", cmd, cmd, cptr.cp);
892 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +0000893 case FLASH_CFI_8BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000894 debug ("is= %x %x\n", cptr.cp[0], cword.c);
wdenk5653fc32004-02-08 22:55:38 +0000895 retval = (cptr.cp[0] == cword.c);
896 break;
897 case FLASH_CFI_16BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000898 debug ("is= %4.4x %4.4x\n", cptr.wp[0], cword.w);
wdenk5653fc32004-02-08 22:55:38 +0000899 retval = (cptr.wp[0] == cword.w);
900 break;
901 case FLASH_CFI_32BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000902 debug ("is= %8.8lx %8.8lx\n", cptr.lp[0], cword.l);
wdenk5653fc32004-02-08 22:55:38 +0000903 retval = (cptr.lp[0] == cword.l);
904 break;
905 case FLASH_CFI_64BIT:
wdenkcd37d9e2004-02-10 00:03:41 +0000906#ifdef DEBUG
wdenkbf9e3b32004-02-12 00:47:09 +0000907 {
wdenk5653fc32004-02-08 22:55:38 +0000908 char str1[20];
909 char str2[20];
wdenkbf9e3b32004-02-12 00:47:09 +0000910
911 print_longlong (str1, cptr.llp[0]);
912 print_longlong (str2, cword.ll);
913 debug ("is= %s %s\n", str1, str2);
wdenk5653fc32004-02-08 22:55:38 +0000914 }
915#endif
916 retval = (cptr.llp[0] == cword.ll);
917 break;
918 default:
919 retval = 0;
920 break;
921 }
922 return retval;
923}
wdenkbf9e3b32004-02-12 00:47:09 +0000924
wdenk5653fc32004-02-08 22:55:38 +0000925/*-----------------------------------------------------------------------
926 */
wdenk028ab6b2004-02-23 23:54:43 +0000927static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk5653fc32004-02-08 22:55:38 +0000928{
929 cfiptr_t cptr;
930 cfiword_t cword;
931 int retval;
wdenkbf9e3b32004-02-12 00:47:09 +0000932
933 cptr.cp = flash_make_addr (info, sect, offset);
934 flash_make_cmd (info, cmd, &cword);
935 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +0000936 case FLASH_CFI_8BIT:
937 retval = ((cptr.cp[0] & cword.c) == cword.c);
938 break;
939 case FLASH_CFI_16BIT:
940 retval = ((cptr.wp[0] & cword.w) == cword.w);
941 break;
942 case FLASH_CFI_32BIT:
943 retval = ((cptr.lp[0] & cword.l) == cword.l);
944 break;
945 case FLASH_CFI_64BIT:
946 retval = ((cptr.llp[0] & cword.ll) == cword.ll);
wdenkbf9e3b32004-02-12 00:47:09 +0000947 break;
wdenk5653fc32004-02-08 22:55:38 +0000948 default:
949 retval = 0;
950 break;
951 }
952 return retval;
953}
954
955/*-----------------------------------------------------------------------
956 */
wdenk028ab6b2004-02-23 23:54:43 +0000957static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
wdenk5653fc32004-02-08 22:55:38 +0000958{
959 cfiptr_t cptr;
960 cfiword_t cword;
961 int retval;
wdenkbf9e3b32004-02-12 00:47:09 +0000962
963 cptr.cp = flash_make_addr (info, sect, offset);
964 flash_make_cmd (info, cmd, &cword);
965 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +0000966 case FLASH_CFI_8BIT:
967 retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c));
968 break;
969 case FLASH_CFI_16BIT:
970 retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w));
971 break;
972 case FLASH_CFI_32BIT:
973 retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l));
974 break;
975 case FLASH_CFI_64BIT:
wdenkbf9e3b32004-02-12 00:47:09 +0000976 retval = ((cptr.llp[0] & cword.ll) !=
977 (cptr.llp[0] & cword.ll));
wdenk5653fc32004-02-08 22:55:38 +0000978 break;
979 default:
980 retval = 0;
981 break;
982 }
983 return retval;
984}
985
986/*-----------------------------------------------------------------------
987 * detect if flash is compatible with the Common Flash Interface (CFI)
988 * http://www.jedec.org/download/search/jesd68.pdf
989 *
990*/
wdenkbf9e3b32004-02-12 00:47:09 +0000991static int flash_detect_cfi (flash_info_t * info)
wdenk5653fc32004-02-08 22:55:38 +0000992{
wdenkbf9e3b32004-02-12 00:47:09 +0000993 debug ("flash detect cfi\n");
wdenk5653fc32004-02-08 22:55:38 +0000994
wdenkbf9e3b32004-02-12 00:47:09 +0000995 for (info->portwidth = FLASH_CFI_8BIT;
996 info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
997 for (info->chipwidth = FLASH_CFI_BY8;
998 info->chipwidth <= info->portwidth;
999 info->chipwidth <<= 1) {
1000 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
wdenk028ab6b2004-02-23 23:54:43 +00001001 flash_write_cmd (info, 0, FLASH_OFFSET_CFI, FLASH_CMD_CFI);
1002 if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
1003 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
1004 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
1005 info->interface = flash_read_ushort (info, 0, FLASH_OFFSET_INTERFACE);
wdenkbf9e3b32004-02-12 00:47:09 +00001006 debug ("device interface is %d\n",
1007 info->interface);
1008 debug ("found port %d chip %d ",
1009 info->portwidth, info->chipwidth);
1010 debug ("port %d bits chip %d bits\n",
wdenk028ab6b2004-02-23 23:54:43 +00001011 info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1012 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
wdenk5653fc32004-02-08 22:55:38 +00001013 return 1;
1014 }
1015 }
1016 }
wdenkbf9e3b32004-02-12 00:47:09 +00001017 debug ("not found\n");
wdenk5653fc32004-02-08 22:55:38 +00001018 return 0;
1019}
wdenkbf9e3b32004-02-12 00:47:09 +00001020
wdenk5653fc32004-02-08 22:55:38 +00001021/*
1022 * The following code cannot be run from FLASH!
1023 *
1024 */
1025static ulong flash_get_size (ulong base, int banknum)
1026{
wdenkbf9e3b32004-02-12 00:47:09 +00001027 flash_info_t *info = &flash_info[banknum];
wdenk5653fc32004-02-08 22:55:38 +00001028 int i, j;
1029 flash_sect_t sect_cnt;
1030 unsigned long sector;
1031 unsigned long tmp;
1032 int size_ratio;
1033 uchar num_erase_regions;
wdenkbf9e3b32004-02-12 00:47:09 +00001034 int erase_region_size;
1035 int erase_region_count;
wdenk5653fc32004-02-08 22:55:38 +00001036
1037 info->start[0] = base;
1038
wdenkbf9e3b32004-02-12 00:47:09 +00001039 if (flash_detect_cfi (info)) {
wdenk028ab6b2004-02-23 23:54:43 +00001040 info->vendor = flash_read_ushort (info, 0, FLASH_OFFSET_PRIMARY_VENDOR);
wdenkbf9e3b32004-02-12 00:47:09 +00001041#ifdef DEBUG
1042 flash_printqry (info, 0);
1043#endif
1044 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +00001045 case CFI_CMDSET_INTEL_STANDARD:
1046 case CFI_CMDSET_INTEL_EXTENDED:
1047 default:
1048 info->cmd_reset = FLASH_CMD_RESET;
1049 break;
1050 case CFI_CMDSET_AMD_STANDARD:
1051 case CFI_CMDSET_AMD_EXTENDED:
1052 info->cmd_reset = AMD_CMD_RESET;
1053 break;
1054 }
wdenkcd37d9e2004-02-10 00:03:41 +00001055
wdenkbf9e3b32004-02-12 00:47:09 +00001056 debug ("manufacturer is %d\n", info->vendor);
wdenk5653fc32004-02-08 22:55:38 +00001057 size_ratio = info->portwidth / info->chipwidth;
wdenkbf9e3b32004-02-12 00:47:09 +00001058 /* if the chip is x8/x16 reduce the ratio by half */
1059 if ((info->interface == FLASH_CFI_X8X16)
1060 && (info->chipwidth == FLASH_CFI_BY8)) {
1061 size_ratio >>= 1;
1062 }
wdenk028ab6b2004-02-23 23:54:43 +00001063 num_erase_regions = flash_read_uchar (info, FLASH_OFFSET_NUM_ERASE_REGIONS);
wdenkbf9e3b32004-02-12 00:47:09 +00001064 debug ("size_ratio %d port %d bits chip %d bits\n",
1065 size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
1066 info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
1067 debug ("found %d erase regions\n", num_erase_regions);
wdenk5653fc32004-02-08 22:55:38 +00001068 sect_cnt = 0;
1069 sector = base;
wdenkbf9e3b32004-02-12 00:47:09 +00001070 for (i = 0; i < num_erase_regions; i++) {
1071 if (i > NUM_ERASE_REGIONS) {
wdenk028ab6b2004-02-23 23:54:43 +00001072 printf ("%d erase regions found, only %d used\n",
1073 num_erase_regions, NUM_ERASE_REGIONS);
wdenk5653fc32004-02-08 22:55:38 +00001074 break;
1075 }
wdenkbf9e3b32004-02-12 00:47:09 +00001076 tmp = flash_read_long (info, 0,
1077 FLASH_OFFSET_ERASE_REGIONS +
1078 i * 4);
1079 erase_region_size =
1080 (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
wdenk5653fc32004-02-08 22:55:38 +00001081 tmp >>= 16;
wdenkbf9e3b32004-02-12 00:47:09 +00001082 erase_region_count = (tmp & 0xffff) + 1;
wdenk4c0d4c32004-06-09 17:34:58 +00001083 debug ("erase_region_count = %d erase_region_size = %d\n",
wdenk028ab6b2004-02-23 23:54:43 +00001084 erase_region_count, erase_region_size);
wdenkbf9e3b32004-02-12 00:47:09 +00001085 for (j = 0; j < erase_region_count; j++) {
wdenk5653fc32004-02-08 22:55:38 +00001086 info->start[sect_cnt] = sector;
1087 sector += (erase_region_size * size_ratio);
wdenka1191902005-01-09 17:12:27 +00001088
1089 /*
1090 * Only read protection status from supported devices (intel...)
1091 */
1092 switch (info->vendor) {
1093 case CFI_CMDSET_INTEL_EXTENDED:
1094 case CFI_CMDSET_INTEL_STANDARD:
1095 info->protect[sect_cnt] =
1096 flash_isset (info, sect_cnt,
1097 FLASH_OFFSET_PROTECT,
1098 FLASH_STATUS_PROTECT);
1099 break;
1100 default:
1101 info->protect[sect_cnt] = 0; /* default: not protected */
1102 }
1103
wdenk5653fc32004-02-08 22:55:38 +00001104 sect_cnt++;
1105 }
1106 }
1107
1108 info->sector_count = sect_cnt;
1109 /* multiply the size by the number of chips */
wdenk028ab6b2004-02-23 23:54:43 +00001110 info->size = (1 << flash_read_uchar (info, FLASH_OFFSET_SIZE)) * size_ratio;
1111 info->buffer_size = (1 << flash_read_ushort (info, 0, FLASH_OFFSET_BUFFER_SIZE));
wdenkbf9e3b32004-02-12 00:47:09 +00001112 tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT);
wdenk028ab6b2004-02-23 23:54:43 +00001113 info->erase_blk_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_EMAX_TOUT)));
wdenkbf9e3b32004-02-12 00:47:09 +00001114 tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT);
wdenk028ab6b2004-02-23 23:54:43 +00001115 info->buffer_write_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT)));
wdenkbf9e3b32004-02-12 00:47:09 +00001116 tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT);
wdenk028ab6b2004-02-23 23:54:43 +00001117 info->write_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT))) / 1000;
wdenk5653fc32004-02-08 22:55:38 +00001118 info->flash_id = FLASH_MAN_CFI;
wdenk855a4962004-03-14 18:23:55 +00001119 if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) {
1120 info->portwidth >>= 1; /* XXX - Need to test on x8/x16 in parallel. */
1121 }
wdenk5653fc32004-02-08 22:55:38 +00001122 }
1123
wdenkbf9e3b32004-02-12 00:47:09 +00001124 flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
1125 return (info->size);
wdenk5653fc32004-02-08 22:55:38 +00001126}
1127
1128
1129/*-----------------------------------------------------------------------
1130 */
wdenkbf9e3b32004-02-12 00:47:09 +00001131static int flash_write_cfiword (flash_info_t * info, ulong dest,
1132 cfiword_t cword)
wdenk5653fc32004-02-08 22:55:38 +00001133{
1134
1135 cfiptr_t ctladdr;
1136 cfiptr_t cptr;
1137 int flag;
1138
wdenkbf9e3b32004-02-12 00:47:09 +00001139 ctladdr.cp = flash_make_addr (info, 0, 0);
1140 cptr.cp = (uchar *) dest;
wdenk5653fc32004-02-08 22:55:38 +00001141
1142
1143 /* Check if Flash is (sufficiently) erased */
wdenkbf9e3b32004-02-12 00:47:09 +00001144 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001145 case FLASH_CFI_8BIT:
1146 flag = ((cptr.cp[0] & cword.c) == cword.c);
1147 break;
1148 case FLASH_CFI_16BIT:
1149 flag = ((cptr.wp[0] & cword.w) == cword.w);
1150 break;
1151 case FLASH_CFI_32BIT:
wdenkbf9e3b32004-02-12 00:47:09 +00001152 flag = ((cptr.lp[0] & cword.l) == cword.l);
wdenk5653fc32004-02-08 22:55:38 +00001153 break;
1154 case FLASH_CFI_64BIT:
wdenke1599e82004-10-10 23:27:33 +00001155 flag = ((cptr.llp[0] & cword.ll) == cword.ll);
wdenk5653fc32004-02-08 22:55:38 +00001156 break;
1157 default:
1158 return 2;
1159 }
wdenkbf9e3b32004-02-12 00:47:09 +00001160 if (!flag)
wdenk5653fc32004-02-08 22:55:38 +00001161 return 2;
1162
1163 /* Disable interrupts which might cause a timeout here */
wdenkbf9e3b32004-02-12 00:47:09 +00001164 flag = disable_interrupts ();
wdenk5653fc32004-02-08 22:55:38 +00001165
wdenkbf9e3b32004-02-12 00:47:09 +00001166 switch (info->vendor) {
wdenk5653fc32004-02-08 22:55:38 +00001167 case CFI_CMDSET_INTEL_EXTENDED:
1168 case CFI_CMDSET_INTEL_STANDARD:
wdenkbf9e3b32004-02-12 00:47:09 +00001169 flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
1170 flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
wdenk5653fc32004-02-08 22:55:38 +00001171 break;
1172 case CFI_CMDSET_AMD_EXTENDED:
1173 case CFI_CMDSET_AMD_STANDARD:
wdenkbf9e3b32004-02-12 00:47:09 +00001174 flash_unlock_seq (info, 0);
wdenk855a4962004-03-14 18:23:55 +00001175 flash_write_cmd (info, 0, AMD_ADDR_START, AMD_CMD_WRITE);
wdenk5653fc32004-02-08 22:55:38 +00001176 break;
1177 }
1178
wdenkbf9e3b32004-02-12 00:47:09 +00001179 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001180 case FLASH_CFI_8BIT:
1181 cptr.cp[0] = cword.c;
1182 break;
1183 case FLASH_CFI_16BIT:
1184 cptr.wp[0] = cword.w;
1185 break;
1186 case FLASH_CFI_32BIT:
1187 cptr.lp[0] = cword.l;
1188 break;
1189 case FLASH_CFI_64BIT:
1190 cptr.llp[0] = cword.ll;
1191 break;
1192 }
1193
1194 /* re-enable interrupts if necessary */
wdenkbf9e3b32004-02-12 00:47:09 +00001195 if (flag)
1196 enable_interrupts ();
wdenk5653fc32004-02-08 22:55:38 +00001197
wdenkbf9e3b32004-02-12 00:47:09 +00001198 return flash_full_status_check (info, 0, info->write_tout, "write");
wdenk5653fc32004-02-08 22:55:38 +00001199}
1200
1201#ifdef CFG_FLASH_USE_BUFFER_WRITE
1202
1203/* loop through the sectors from the highest address
1204 * when the passed address is greater or equal to the sector address
1205 * we have a match
1206 */
wdenkbf9e3b32004-02-12 00:47:09 +00001207static flash_sect_t find_sector (flash_info_t * info, ulong addr)
wdenk5653fc32004-02-08 22:55:38 +00001208{
1209 flash_sect_t sector;
wdenkbf9e3b32004-02-12 00:47:09 +00001210
1211 for (sector = info->sector_count - 1; sector >= 0; sector--) {
1212 if (addr >= info->start[sector])
wdenk5653fc32004-02-08 22:55:38 +00001213 break;
1214 }
1215 return sector;
1216}
1217
wdenkbf9e3b32004-02-12 00:47:09 +00001218static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
1219 int len)
wdenk5653fc32004-02-08 22:55:38 +00001220{
1221 flash_sect_t sector;
1222 int cnt;
1223 int retcode;
1224 volatile cfiptr_t src;
1225 volatile cfiptr_t dst;
wdenk855a4962004-03-14 18:23:55 +00001226 /* buffered writes in the AMD chip set is not supported yet */
1227 if((info->vendor == CFI_CMDSET_AMD_STANDARD) ||
1228 (info->vendor == CFI_CMDSET_AMD_EXTENDED))
1229 return ERR_INVAL;
wdenk5653fc32004-02-08 22:55:38 +00001230
1231 src.cp = cp;
wdenkbf9e3b32004-02-12 00:47:09 +00001232 dst.cp = (uchar *) dest;
1233 sector = find_sector (info, dest);
1234 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
1235 flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
1236 if ((retcode =
1237 flash_status_check (info, sector, info->buffer_write_tout,
1238 "write to buffer")) == ERR_OK) {
1239 /* reduce the number of loops by the width of the port */
1240 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001241 case FLASH_CFI_8BIT:
1242 cnt = len;
1243 break;
1244 case FLASH_CFI_16BIT:
1245 cnt = len >> 1;
1246 break;
1247 case FLASH_CFI_32BIT:
1248 cnt = len >> 2;
1249 break;
1250 case FLASH_CFI_64BIT:
1251 cnt = len >> 3;
1252 break;
1253 default:
1254 return ERR_INVAL;
1255 break;
1256 }
wdenkbf9e3b32004-02-12 00:47:09 +00001257 flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
1258 while (cnt-- > 0) {
1259 switch (info->portwidth) {
wdenk5653fc32004-02-08 22:55:38 +00001260 case FLASH_CFI_8BIT:
1261 *dst.cp++ = *src.cp++;
1262 break;
1263 case FLASH_CFI_16BIT:
1264 *dst.wp++ = *src.wp++;
1265 break;
1266 case FLASH_CFI_32BIT:
1267 *dst.lp++ = *src.lp++;
1268 break;
1269 case FLASH_CFI_64BIT:
1270 *dst.llp++ = *src.llp++;
1271 break;
1272 default:
1273 return ERR_INVAL;
1274 break;
1275 }
1276 }
wdenkbf9e3b32004-02-12 00:47:09 +00001277 flash_write_cmd (info, sector, 0,
1278 FLASH_CMD_WRITE_BUFFER_CONFIRM);
1279 retcode =
1280 flash_full_status_check (info, sector,
1281 info->buffer_write_tout,
1282 "buffer write");
wdenk5653fc32004-02-08 22:55:38 +00001283 }
wdenkbf9e3b32004-02-12 00:47:09 +00001284 flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
wdenk5653fc32004-02-08 22:55:38 +00001285 return retcode;
1286}
wdenkcce625e2004-09-28 19:00:19 +00001287#endif /* CFG_FLASH_USE_BUFFER_WRITE */
wdenk5653fc32004-02-08 22:55:38 +00001288#endif /* CFG_FLASH_CFI */