Newer
Older
* Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com
*
* Copyright (C) 2003 Arabella Software Ltd.
* Yuli Barcohen <yuli@arabellasw.com>
*
Stefan Roese
committed
*
* Copyright (C) 2006
* Tolunay Orkun <listmember@orkun.us>
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
/* The DEBUG define must be before common to enable debugging */
#include <common.h>
#include <asm/processor.h>
#include <asm/io.h>
* This file implements a Common Flash Interface (CFI) driver for
* U-Boot.
*
* The width of the port and the width of the chips are determined at
* initialization. These widths are used to calculate the address for
* access CFI data structures.
*
* References
* JEDEC Standard JESD68 - Common Flash Interface (CFI)
* JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
* Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
* Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
Stefan Roese
committed
* AMD CFI Specification, Release 2.0 December 1, 2001
* AMD/Spansion Application Note: Migration from Single-byte to Three-byte
* Device IDs, Publication Number 25538 Revision A, November 8, 2001
* Define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
* reading and writing ... (yes there is such a Hardware).
#ifndef CFG_FLASH_BANKS_LIST
#define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE }
#endif
#define FLASH_CMD_CFI 0x98
#define FLASH_CMD_READ_ID 0x90
#define FLASH_CMD_RESET 0xff
#define FLASH_CMD_BLOCK_ERASE 0x20
#define FLASH_CMD_ERASE_CONFIRM 0xD0
#define FLASH_CMD_WRITE 0x40
#define FLASH_CMD_PROTECT 0x60
#define FLASH_CMD_PROTECT_SET 0x01
#define FLASH_CMD_PROTECT_CLEAR 0xD0
#define FLASH_CMD_CLEAR_STATUS 0x50
#define FLASH_CMD_READ_STATUS 0x70
#define FLASH_CMD_WRITE_BUFFER_PROG 0xE9
#define FLASH_STATUS_DONE 0x80
#define FLASH_STATUS_ESS 0x40
#define FLASH_STATUS_ECLBS 0x20
#define FLASH_STATUS_PSLBS 0x10
#define FLASH_STATUS_VPENS 0x08
#define FLASH_STATUS_PSS 0x04
#define FLASH_STATUS_DPS 0x02
#define FLASH_STATUS_R 0x01
#define FLASH_STATUS_PROTECT 0x01
#define AMD_CMD_RESET 0xF0
#define AMD_CMD_WRITE 0xA0
#define AMD_CMD_ERASE_START 0x80
#define AMD_CMD_ERASE_SECTOR 0x30
#define AMD_CMD_UNLOCK_START 0xAA
#define AMD_CMD_UNLOCK_ACK 0x55
#define AMD_CMD_WRITE_TO_BUFFER 0x25
#define AMD_CMD_WRITE_BUFFER_CONFIRM 0x29
#define AMD_STATUS_TOGGLE 0x40
#define AMD_STATUS_ERROR 0x20
#define ATM_CMD_UNLOCK_SECT 0x70
#define ATM_CMD_SOFTLOCK_START 0x80
#define ATM_CMD_LOCK_SECT 0x40
Stefan Roese
committed
#define FLASH_OFFSET_MANUFACTURER_ID 0x00
#define FLASH_OFFSET_DEVICE_ID 0x01
#define FLASH_OFFSET_DEVICE_ID2 0x0E
#define FLASH_OFFSET_DEVICE_ID3 0x0F
#define FLASH_OFFSET_CFI_ALT 0x555
#define FLASH_OFFSET_CFI_RESP 0x10
/* extended query table primary address */
#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR 0x15
#define FLASH_OFFSET_WMAX_TOUT 0x23
#define FLASH_OFFSET_EMAX_TOUT 0x25
#define FLASH_OFFSET_INTERFACE 0x28
#define FLASH_OFFSET_BUFFER_SIZE 0x2A
#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C
#define FLASH_OFFSET_ERASE_REGIONS 0x2D
#define FLASH_OFFSET_PROTECT 0x02
#define FLASH_OFFSET_USER_PROTECTION 0x85
#define FLASH_OFFSET_INTEL_PROTECTION 0x81
Stefan Roese
committed
#define CFI_CMDSET_NONE 0
#define CFI_CMDSET_INTEL_EXTENDED 1
#define CFI_CMDSET_AMD_STANDARD 2
#define CFI_CMDSET_INTEL_STANDARD 3
#define CFI_CMDSET_AMD_EXTENDED 4
#define CFI_CMDSET_MITSU_STANDARD 256
#define CFI_CMDSET_MITSU_EXTENDED 257
#define CFI_CMDSET_SST 258
#define CFI_CMDSET_INTEL_PROG_REGIONS 512
#ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
# undef FLASH_CMD_RESET
Stefan Roese
committed
# define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */
typedef union {
unsigned char c;
unsigned short w;
unsigned long l;
unsigned long long ll;
} cfiword_t;
Stefan Roese
committed
#define NUM_ERASE_REGIONS 4 /* max. number of erase regions */
static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
/* use CFG_MAX_FLASH_BANKS_DETECT if defined */
#ifdef CFG_MAX_FLASH_BANKS_DETECT
# define CFI_MAX_FLASH_BANKS CFG_MAX_FLASH_BANKS_DETECT
# define CFI_MAX_FLASH_BANKS CFG_MAX_FLASH_BANKS
flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */
/*
* Check if chip width is defined. If not, start detecting with 8bit.
*/
#ifndef CFG_FLASH_CFI_WIDTH
#define CFG_FLASH_CFI_WIDTH FLASH_CFI_8BIT
#endif
typedef unsigned long flash_sect_t;
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/* CFI standard query structure */
struct cfi_qry {
u8 qry[3];
u16 p_id;
u16 p_adr;
u16 a_id;
u16 a_adr;
u8 vcc_min;
u8 vcc_max;
u8 vpp_min;
u8 vpp_max;
u8 word_write_timeout_typ;
u8 buf_write_timeout_typ;
u8 block_erase_timeout_typ;
u8 chip_erase_timeout_typ;
u8 word_write_timeout_max;
u8 buf_write_timeout_max;
u8 block_erase_timeout_max;
u8 chip_erase_timeout_max;
u8 dev_size;
u16 interface_desc;
u16 max_buf_write_size;
u8 num_erase_regions;
u32 erase_region_info[NUM_ERASE_REGIONS];
} __attribute__((packed));
struct cfi_pri_hdr {
u8 pri[3];
u8 major_version;
u8 minor_version;
} __attribute__((packed));
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
static void flash_write8(u8 value, void *addr)
{
__raw_writeb(value, addr);
}
static void flash_write16(u16 value, void *addr)
{
__raw_writew(value, addr);
}
static void flash_write32(u32 value, void *addr)
{
__raw_writel(value, addr);
}
static void flash_write64(u64 value, void *addr)
{
/* No architectures currently implement __raw_writeq() */
*(volatile u64 *)addr = value;
}
static u8 flash_read8(void *addr)
{
return __raw_readb(addr);
}
static u16 flash_read16(void *addr)
{
return __raw_readw(addr);
}
static u32 flash_read32(void *addr)
{
return __raw_readl(addr);
}
static u64 __flash_read64(void *addr)
{
/* No architectures currently implement __raw_readq() */
return *(volatile u64 *)addr;
}
u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
/*-----------------------------------------------------------------------
*/
#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
static flash_info_t *flash_get_info(ulong base)
{
int i;
flash_info_t * info = 0;
for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
info = & flash_info[i];
if (info->size && info->start[0] <= base &&
base <= info->start[0] + info->size - 1)
break;
}
return i == CFG_MAX_FLASH_BANKS ? 0 : info;
}
unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
{
if (sect != (info->sector_count - 1))
return info->start[sect + 1] - info->start[sect];
else
return info->start[0] + info->size - info->start[sect];
}
/*-----------------------------------------------------------------------
* create an address based on the offset and the port width
*/
static inline void *
flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
unsigned int byte_offset = offset * info->portwidth;
return map_physmem(info->start[sect] + byte_offset,
flash_sector_size(info, sect) - byte_offset,
MAP_NOCACHE);
}
static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
unsigned int offset, void *addr)
{
unsigned int byte_offset = offset * info->portwidth;
unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset);
/*-----------------------------------------------------------------------
* make a proper sized command based on the port and chip widths
*/
static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
{
int i;
int cword_offset;
int cp_offset;
#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
u32 cmd_le = cpu_to_le32(cmd);
#endif
uchar *cp = (uchar *) cmdbuf;
for (i = info->portwidth; i > 0; i--){
cword_offset = (info->portwidth-i)%info->chipwidth;
#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
cp_offset = info->portwidth - i;
val = *((uchar*)&cmd_le + cword_offset);
val = *((uchar*)&cmd + sizeof(u32) - cword_offset - 1);
cp[cp_offset] = (cword_offset >= sizeof(u32)) ? 0x00 : val;
/*-----------------------------------------------------------------------
* Debug support
*/
static void print_longlong (char *str, unsigned long long data)
cp = (unsigned char *) &data;
for (i = 0; i < 8; i++)
sprintf (&str[i * 2], "%2.2x", *cp++);
}
static void flash_printqry (struct cfi_qry *qry)
for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
debug("%02x : ", x);
for (y = 0; y < 16; y++)
debug("%2.2x ", p[x + y]);
debug(" ");
unsigned char c = p[x + y];
if (c >= 0x20 && c <= 0x7e)
debug("%c", c);
else
debug(".");
}
#endif
/*-----------------------------------------------------------------------
* read a character at a port width address
*/
static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
cp = flash_map (info, 0, offset);
#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
retval = flash_read8(cp);
retval = flash_read8(cp + info->portwidth - 1);
flash_unmap (info, 0, offset, cp);
return retval;
/*-----------------------------------------------------------------------
* read a word at a port width address, assume 16bit bus
*/
static inline ushort flash_read_word (flash_info_t * info, uint offset)
{
ushort *addr, retval;
addr = flash_map (info, 0, offset);
retval = flash_read16 (addr);
flash_unmap (info, 0, offset, addr);
return retval;
}
/*-----------------------------------------------------------------------
Stefan Roese
committed
* read a long word by picking the least significant byte of each maximum
* port size word. Swap for ppc format.
*/
static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
uint offset)
uchar *addr;
ulong retval;
#ifdef DEBUG
int x;
#endif
addr = flash_map (info, sect, offset);
#ifdef DEBUG
debug ("long addr is at %p info->portwidth = %d\n", addr,
info->portwidth);
for (x = 0; x < 4 * info->portwidth; x++) {
debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
retval = ((flash_read8(addr) << 16) |
(flash_read8(addr + info->portwidth) << 24) |
(flash_read8(addr + 2 * info->portwidth)) |
(flash_read8(addr + 3 * info->portwidth) << 8));
retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
(flash_read8(addr + info->portwidth - 1) << 16) |
(flash_read8(addr + 4 * info->portwidth - 1) << 8) |
(flash_read8(addr + 3 * info->portwidth - 1)));
flash_unmap(info, sect, offset, addr);
/*
* Write a proper sized command to the correct address
static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
cfiword_t cword;
addr = flash_map (info, sect, offset);
flash_make_cmd (info, cmd, &cword);
switch (info->portwidth) {
case FLASH_CFI_8BIT:
debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
flash_write8(cword.c, addr);
break;
case FLASH_CFI_16BIT:
debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
cmd, cword.w,
info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
flash_write16(cword.w, addr);
break;
case FLASH_CFI_32BIT:
debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
cmd, cword.l,
info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
flash_write32(cword.l, addr);
break;
case FLASH_CFI_64BIT:
#ifdef DEBUG
{
char str[20];
print_longlong (str, cword.ll);
debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
flash_write64(cword.ll, addr);
/* Ensure all the instructions are fully finished */
sync();
flash_unmap(info, sect, offset, addr);
static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
/*-----------------------------------------------------------------------
*/
static int flash_isequal (flash_info_t * info, flash_sect_t sect,
uint offset, uchar cmd)
cfiword_t cword;
int retval;
addr = flash_map (info, sect, offset);
flash_make_cmd (info, cmd, &cword);
debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
switch (info->portwidth) {
case FLASH_CFI_8BIT:
debug ("is= %x %x\n", flash_read8(addr), cword.c);
retval = (flash_read8(addr) == cword.c);
break;
case FLASH_CFI_16BIT:
debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
retval = (flash_read16(addr) == cword.w);
break;
case FLASH_CFI_32BIT:
debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
retval = (flash_read32(addr) == cword.l);
break;
case FLASH_CFI_64BIT:
#ifdef DEBUG
{
char str1[20];
char str2[20];
print_longlong (str1, flash_read64(addr));
print_longlong (str2, cword.ll);
debug ("is= %s %s\n", str1, str2);
retval = (flash_read64(addr) == cword.ll);
break;
default:
retval = 0;
break;
}
flash_unmap(info, sect, offset, addr);
return retval;
}
/*-----------------------------------------------------------------------
*/
static int flash_isset (flash_info_t * info, flash_sect_t sect,
uint offset, uchar cmd)
{
cfiword_t cword;
int retval;
addr = flash_map (info, sect, offset);
flash_make_cmd (info, cmd, &cword);
switch (info->portwidth) {
case FLASH_CFI_8BIT:
retval = ((flash_read8(addr) & cword.c) == cword.c);
break;
case FLASH_CFI_16BIT:
retval = ((flash_read16(addr) & cword.w) == cword.w);
break;
case FLASH_CFI_32BIT:
retval = ((flash_read32(addr) & cword.l) == cword.l);
break;
case FLASH_CFI_64BIT:
retval = ((flash_read64(addr) & cword.ll) == cword.ll);
break;
default:
retval = 0;
break;
}
flash_unmap(info, sect, offset, addr);
return retval;
}
/*-----------------------------------------------------------------------
*/
static int flash_toggle (flash_info_t * info, flash_sect_t sect,
uint offset, uchar cmd)
{
cfiword_t cword;
int retval;
addr = flash_map (info, sect, offset);
flash_make_cmd (info, cmd, &cword);
switch (info->portwidth) {
case FLASH_CFI_8BIT:
retval = flash_read8(addr) != flash_read8(addr);
break;
case FLASH_CFI_16BIT:
retval = flash_read16(addr) != flash_read16(addr);
break;
case FLASH_CFI_32BIT:
retval = flash_read32(addr) != flash_read32(addr);
break;
case FLASH_CFI_64BIT:
retval = flash_read64(addr) != flash_read64(addr);
break;
default:
retval = 0;
break;
}
flash_unmap(info, sect, offset, addr);
return retval;
/*
* flash_is_busy - check to see if the flash is busy
*
* This routine checks the status of the chip and returns true if the
* chip is busy.
static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
int retval;
switch (info->vendor) {
case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
break;
case CFI_CMDSET_AMD_STANDARD:
case CFI_CMDSET_AMD_EXTENDED:
#ifdef CONFIG_FLASH_CFI_LEGACY
case CFI_CMDSET_AMD_LEGACY:
#endif
retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
break;
default:
retval = 0;
debug ("flash_is_busy: %d\n", retval);
return retval;
/*-----------------------------------------------------------------------
* wait for XSR.7 to be set. Time out with an error if it does not.
* This routine does not set the flash to read-array mode.
static int flash_status_check (flash_info_t * info, flash_sect_t sector,
ulong tout, char *prompt)
ulong start;
#if CFG_HZ != 1000
tout *= CFG_HZ/1000;
#endif
/* Wait for command completion */
start = get_timer (0);
while (flash_is_busy (info, sector)) {
if (get_timer (start) > tout) {
printf ("Flash %s timeout at address %lx data %lx\n",
prompt, info->start[sector],
flash_read_long (info, sector, 0));
flash_write_cmd (info, sector, 0, info->cmd_reset);
return ERR_TIMOUT;
udelay (1); /* also triggers watchdog */
return ERR_OK;
}
/*-----------------------------------------------------------------------
* Wait for XSR.7 to be set, if it times out print an error, otherwise
* do a full status check.
*
* This routine sets the flash to read-array mode.
*/
static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
ulong tout, char *prompt)
{
int retcode;
retcode = flash_status_check (info, sector, tout, prompt);
switch (info->vendor) {
case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_EXTENDED:
case CFI_CMDSET_INTEL_STANDARD:
if ((retcode == ERR_OK)
&& !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
retcode = ERR_INVAL;
printf ("Flash %s error at address %lx\n", prompt,
info->start[sector]);
if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
FLASH_STATUS_PSLBS)) {
puts ("Command Sequence Error.\n");
} else if (flash_isset (info, sector, 0,
FLASH_STATUS_ECLBS)) {
puts ("Block Erase Error.\n");
retcode = ERR_NOT_ERASED;
} else if (flash_isset (info, sector, 0,
FLASH_STATUS_PSLBS)) {
puts ("Locking Error\n");
if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
puts ("Block locked.\n");
retcode = ERR_PROTECTED;
}
if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
puts ("Vpp Low Error.\n");
flash_write_cmd (info, sector, 0, info->cmd_reset);
break;
default:
break;
return retcode;
}
/*-----------------------------------------------------------------------
*/
static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
unsigned short w;
unsigned int l;
unsigned long long ll;
#endif
switch (info->portwidth) {
case FLASH_CFI_8BIT:
cword->c = c;
break;
case FLASH_CFI_16BIT:
#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
w = c;
w <<= 8;
cword->w = (cword->w >> 8) | w;
#else
cword->w = (cword->w << 8) | c;
break;
case FLASH_CFI_32BIT:
#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
l = c;
l <<= 24;
cword->l = (cword->l >> 8) | l;
#else
cword->l = (cword->l << 8) | c;
#endif
break;
case FLASH_CFI_64BIT:
#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
ll = c;
ll <<= 56;
cword->ll = (cword->ll >> 8) | ll;
#else
cword->ll = (cword->ll << 8) | c;
#endif
break;
Stefan Roese
committed
}
/* loop through the sectors from the highest address when the passed
* address is greater or equal to the sector address we have a match
*/
static flash_sect_t find_sector (flash_info_t * info, ulong addr)
{
flash_sect_t sector;
for (sector = info->sector_count - 1; sector >= 0; sector--) {
if (addr >= info->start[sector])
break;
return sector;
}
/*-----------------------------------------------------------------------
*/
static int flash_write_cfiword (flash_info_t * info, ulong dest,
cfiword_t cword)
int flag;
dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
/* Check if Flash is (sufficiently) erased */
switch (info->portwidth) {
case FLASH_CFI_8BIT:
flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
break;
case FLASH_CFI_16BIT:
flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
break;
case FLASH_CFI_32BIT:
flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
break;
case FLASH_CFI_64BIT:
flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
break;
default:
flag = 0;
break;
if (!flag) {
unmap_physmem(dstaddr, info->portwidth);
return ERR_NOT_ERASED;
/* Disable interrupts which might cause a timeout here */
flag = disable_interrupts ();
switch (info->vendor) {
case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_EXTENDED:
case CFI_CMDSET_INTEL_STANDARD:
flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
break;
case CFI_CMDSET_AMD_EXTENDED:
case CFI_CMDSET_AMD_STANDARD:
#ifdef CONFIG_FLASH_CFI_LEGACY
case CFI_CMDSET_AMD_LEGACY:
#endif
flash_unlock_seq (info, 0);
flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
break;
switch (info->portwidth) {
case FLASH_CFI_8BIT:
flash_write8(cword.c, dstaddr);
break;
case FLASH_CFI_16BIT:
flash_write16(cword.w, dstaddr);
break;
case FLASH_CFI_32BIT:
flash_write32(cword.l, dstaddr);
break;
case FLASH_CFI_64BIT:
flash_write64(cword.ll, dstaddr);
/* re-enable interrupts if necessary */
if (flag)
enable_interrupts ();
unmap_physmem(dstaddr, info->portwidth);
return flash_full_status_check (info, find_sector (info, dest),
info->write_tout, "write");
#ifdef CFG_FLASH_USE_BUFFER_WRITE
static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
int len)
flash_sect_t sector;
int cnt;
int retcode;
void *dst = map_physmem(dest, len, MAP_NOCACHE);
void *dst2 = dst;
int flag = 0;
Guennadi Liakhovetski
committed
uint offset = 0;
unsigned int shift;
switch (info->portwidth) {
case FLASH_CFI_8BIT:
Guennadi Liakhovetski
committed
shift = 0;
break;
case FLASH_CFI_16BIT:
Guennadi Liakhovetski
committed
shift = 1;
break;
case FLASH_CFI_32BIT:
Guennadi Liakhovetski
committed
shift = 2;
break;
case FLASH_CFI_64BIT:
Guennadi Liakhovetski
committed
shift = 3;
break;
default:
retcode = ERR_INVAL;
goto out_unmap;
}
Guennadi Liakhovetski
committed
cnt = len >> shift;
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
while ((cnt-- > 0) && (flag == 0)) {
switch (info->portwidth) {
case FLASH_CFI_8BIT:
flag = ((flash_read8(dst2) & flash_read8(src)) ==
flash_read8(src));
src += 1, dst2 += 1;
break;
case FLASH_CFI_16BIT:
flag = ((flash_read16(dst2) & flash_read16(src)) ==
flash_read16(src));
src += 2, dst2 += 2;
break;
case FLASH_CFI_32BIT:
flag = ((flash_read32(dst2) & flash_read32(src)) ==
flash_read32(src));
src += 4, dst2 += 4;
break;
case FLASH_CFI_64BIT:
flag = ((flash_read64(dst2) & flash_read64(src)) ==
flash_read64(src));
src += 8, dst2 += 8;
break;
}
}
if (!flag) {
retcode = ERR_NOT_ERASED;
goto out_unmap;
}
src = cp;
sector = find_sector (info, dest);
case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER;
flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS);
flash_write_cmd (info, sector, 0, write_cmd);
retcode = flash_status_check (info, sector,
info->buffer_write_tout,
"write to buffer");
if (retcode == ERR_OK) {
/* reduce the number of loops by the width of
* the port */
Guennadi Liakhovetski
committed
cnt = len >> shift;
flash_write_cmd (info, sector, 0, cnt - 1);
while (cnt-- > 0) {
switch (info->portwidth) {
case FLASH_CFI_8BIT:
flash_write8(flash_read8(src), dst);
src += 1, dst += 1;
break;
case FLASH_CFI_16BIT:
flash_write16(flash_read16(src), dst);
src += 2, dst += 2;
break;
case FLASH_CFI_32BIT:
flash_write32(flash_read32(src), dst);
src += 4, dst += 4;
break;
case FLASH_CFI_64BIT:
flash_write64(flash_read64(src), dst);
src += 8, dst += 8;
break;
default:
retcode = ERR_INVAL;
goto out_unmap;
}
}
flash_write_cmd (info, sector, 0,
FLASH_CMD_WRITE_BUFFER_CONFIRM);
retcode = flash_full_status_check (
info, sector, info->buffer_write_tout,
"buffer write");
}
case CFI_CMDSET_AMD_STANDARD:
case CFI_CMDSET_AMD_EXTENDED:
flash_unlock_seq(info,0);
Guennadi Liakhovetski
committed
#ifdef CONFIG_FLASH_SPANSION_S29WS_N
offset = ((unsigned long)dst - info->start[sector]) >> shift;
#endif
flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
cnt = len >> shift;
flash_write_cmd(info, sector, offset, (uchar)cnt - 1);
switch (info->portwidth) {
case FLASH_CFI_8BIT:
while (cnt-- > 0) {
flash_write8(flash_read8(src), dst);
src += 1, dst += 1;
}
break;
case FLASH_CFI_16BIT:
while (cnt-- > 0) {
flash_write16(flash_read16(src), dst);
src += 2, dst += 2;
}
break;
case FLASH_CFI_32BIT:
while (cnt-- > 0) {
flash_write32(flash_read32(src), dst);
src += 4, dst += 4;
}
break;
case FLASH_CFI_64BIT:
while (cnt-- > 0) {
flash_write64(flash_read64(src), dst);