2008-02-25 17:41:25 +00:00
|
|
|
#include <common.h>
|
2010-02-08 12:52:46 +00:00
|
|
|
#include "cfi_flash.h"
|
2007-07-05 16:01:45 +00:00
|
|
|
|
2008-02-26 07:16:07 +00:00
|
|
|
/*
|
2007-07-05 16:01:45 +00:00
|
|
|
* read jedec ids from device and set corresponding fields in info struct
|
|
|
|
*
|
|
|
|
* Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
|
|
|
|
*
|
|
|
|
*/
|
2010-06-29 06:40:39 +00:00
|
|
|
static void intel_read_jedec_ids (struct flash_info *info)
|
2007-07-05 16:01:45 +00:00
|
|
|
{
|
2010-11-26 16:59:39 +00:00
|
|
|
info->cmd_reset = FLASH_CMD_RESET;
|
2007-07-05 16:01:45 +00:00
|
|
|
info->manufacturer_id = 0;
|
|
|
|
info->device_id = 0;
|
|
|
|
info->device_id2 = 0;
|
|
|
|
|
2010-11-26 16:59:39 +00:00
|
|
|
flash_write_cmd(info, 0, 0, info->cmd_reset);
|
2007-07-05 16:01:45 +00:00
|
|
|
flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
|
|
|
|
udelay(1000); /* some flash are slow to respond */
|
2010-11-26 16:00:38 +00:00
|
|
|
|
|
|
|
info->manufacturer_id = jedec_read_mfr(info);
|
2007-07-05 16:01:45 +00:00
|
|
|
info->device_id = flash_read_uchar (info,
|
|
|
|
FLASH_OFFSET_DEVICE_ID);
|
2010-11-26 16:59:39 +00:00
|
|
|
flash_write_cmd(info, 0, 0, info->cmd_reset);
|
2007-07-05 16:01:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
2010-06-29 06:40:39 +00:00
|
|
|
static int intel_flash_is_busy (struct flash_info *info, flash_sect_t sect)
|
2007-07-05 16:01:45 +00:00
|
|
|
{
|
|
|
|
return !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
|
|
|
|
}
|
|
|
|
|
2010-06-29 06:40:39 +00:00
|
|
|
static int intel_flash_erase_one (struct flash_info *info, long sect)
|
2007-07-05 16:01:45 +00:00
|
|
|
{
|
|
|
|
flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS);
|
|
|
|
flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE);
|
|
|
|
flash_write_cmd (info, sect, 0, FLASH_CMD_ERASE_CONFIRM);
|
|
|
|
|
2010-02-08 11:47:51 +00:00
|
|
|
return flash_status_check(info, sect, info->erase_blk_tout, "erase");
|
2007-07-05 16:01:45 +00:00
|
|
|
}
|
|
|
|
|
2010-06-29 06:40:39 +00:00
|
|
|
static void intel_flash_prepare_write(struct flash_info *info)
|
2007-07-05 16:01:45 +00:00
|
|
|
{
|
|
|
|
flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
|
|
|
|
flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_CFI_BUFFER_WRITE
|
2010-06-29 06:40:39 +00:00
|
|
|
static int intel_flash_write_cfibuffer (struct flash_info *info, ulong dest, const uchar * cp,
|
2007-07-05 16:01:45 +00:00
|
|
|
int len)
|
|
|
|
{
|
|
|
|
flash_sect_t sector;
|
|
|
|
int cnt;
|
|
|
|
int retcode;
|
2010-11-26 17:01:41 +00:00
|
|
|
void *src = (void*)cp;
|
|
|
|
void *dst = (void *)dest;
|
2012-04-05 08:46:57 +00:00
|
|
|
/* reduce width due to possible alignment problems */
|
|
|
|
const unsigned long ptr = (unsigned long)dest | (unsigned long)cp | info->portwidth;
|
|
|
|
const int width = ptr & -ptr;
|
2007-07-05 16:01:45 +00:00
|
|
|
|
|
|
|
sector = find_sector (info, dest);
|
|
|
|
flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
|
|
|
|
flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
|
2010-02-08 11:44:35 +00:00
|
|
|
|
|
|
|
retcode = flash_generic_status_check (info, sector, info->buffer_write_tout,
|
|
|
|
"write to buffer");
|
|
|
|
if (retcode != ERR_OK)
|
|
|
|
return retcode;
|
|
|
|
|
|
|
|
/* reduce the number of loops by the width of the port */
|
2012-04-05 08:44:28 +00:00
|
|
|
cnt = len / width;
|
2010-02-08 11:44:35 +00:00
|
|
|
|
2012-04-05 08:46:57 +00:00
|
|
|
flash_write_cmd(info, sector, 0, cnt - 1);
|
2010-02-08 11:44:35 +00:00
|
|
|
while (cnt-- > 0) {
|
2012-04-05 08:46:57 +00:00
|
|
|
switch (width) {
|
|
|
|
case 1:
|
2010-11-26 17:01:41 +00:00
|
|
|
flash_write8(flash_read8(src), dst);
|
|
|
|
src += 1, dst += 1;
|
2012-04-05 08:46:57 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2010-11-26 17:01:41 +00:00
|
|
|
flash_write16(flash_read16(src), dst);
|
|
|
|
src += 2, dst += 2;
|
2012-04-05 08:46:57 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2010-11-26 17:01:41 +00:00
|
|
|
flash_write32(flash_read32(src), dst);
|
|
|
|
src += 4, dst += 4;
|
2012-04-05 08:46:57 +00:00
|
|
|
break;
|
|
|
|
case 8:
|
2010-11-26 17:01:41 +00:00
|
|
|
flash_write64(flash_read64(src), dst);
|
|
|
|
src += 8, dst += 8;
|
2012-04-05 08:46:57 +00:00
|
|
|
break;
|
2007-07-05 16:01:45 +00:00
|
|
|
}
|
|
|
|
}
|
2010-02-08 11:44:35 +00:00
|
|
|
|
|
|
|
flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_BUFFER_CONFIRM);
|
|
|
|
retcode = flash_status_check (info, sector,
|
|
|
|
info->buffer_write_tout,
|
|
|
|
"buffer write");
|
2007-07-05 16:01:45 +00:00
|
|
|
return retcode;
|
|
|
|
}
|
2009-10-03 23:09:19 +00:00
|
|
|
#else
|
|
|
|
#define intel_flash_write_cfibuffer NULL
|
2007-07-05 16:01:45 +00:00
|
|
|
#endif /* CONFIG_CFI_BUFFER_WRITE */
|
|
|
|
|
2010-06-29 06:40:39 +00:00
|
|
|
static int intel_flash_status_check (struct flash_info *info, flash_sect_t sector,
|
2008-02-26 10:55:41 +00:00
|
|
|
uint64_t tout, char *prompt)
|
|
|
|
{
|
|
|
|
int retcode;
|
|
|
|
|
|
|
|
retcode = flash_generic_status_check (info, sector, tout, prompt);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
|
2010-11-26 16:00:38 +00:00
|
|
|
static int intel_flash_real_protect (struct flash_info *info, long sector, int prot)
|
|
|
|
{
|
|
|
|
flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
|
|
|
|
flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
|
|
|
|
if (prot)
|
|
|
|
flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
|
|
|
|
else
|
|
|
|
flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-11-26 16:55:51 +00:00
|
|
|
static void intel_flash_fixup (struct flash_info *info, struct cfi_qry *qry)
|
|
|
|
{
|
|
|
|
#ifdef CFG_FLASH_PROTECTION
|
|
|
|
/* read legacy lock/unlock bit from intel flash */
|
|
|
|
if (info->ext_addr) {
|
|
|
|
info->legacy_unlock = flash_read_uchar (info,
|
|
|
|
info->ext_addr + 5) & 0x08;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-07-05 16:01:45 +00:00
|
|
|
struct cfi_cmd_set cfi_cmd_set_intel = {
|
|
|
|
.flash_write_cfibuffer = intel_flash_write_cfibuffer,
|
|
|
|
.flash_erase_one = intel_flash_erase_one,
|
|
|
|
.flash_is_busy = intel_flash_is_busy,
|
|
|
|
.flash_read_jedec_ids = intel_read_jedec_ids,
|
|
|
|
.flash_prepare_write = intel_flash_prepare_write,
|
2008-02-26 10:55:41 +00:00
|
|
|
.flash_status_check = intel_flash_status_check,
|
2010-11-26 16:00:38 +00:00
|
|
|
.flash_real_protect = intel_flash_real_protect,
|
2010-11-26 16:55:51 +00:00
|
|
|
.flash_fixup = intel_flash_fixup,
|
2007-07-05 16:01:45 +00:00
|
|
|
};
|
|
|
|
|