#define ATM_CMD_SOFTLOCK_START 0x80
#define ATM_CMD_LOCK_SECT 0x40
+#define FLASH_CONTINUATION_CODE 0x7F
+
#define FLASH_OFFSET_MANUFACTURER_ID 0x00
#define FLASH_OFFSET_DEVICE_ID 0x01
#define FLASH_OFFSET_DEVICE_ID2 0x0E
/*-----------------------------------------------------------------------
*/
#if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
-static flash_info_t *flash_get_info(ulong base)
+flash_info_t *flash_get_info(ulong base)
{
int i;
flash_info_t * info = 0;
{
unsigned int byte_offset = offset * info->portwidth;
- return map_physmem(info->start[sect] + byte_offset,
- flash_sector_size(info, sect) - byte_offset,
- MAP_NOCACHE);
+ return (void *)(info->start[sect] + byte_offset);
}
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);
}
/*-----------------------------------------------------------------------
int i;
char *cp;
- cp = (unsigned char *) &data;
+ cp = (char *) &data;
for (i = 0; i < 8; i++)
sprintf (&str[i * 2], "%2.2x", *cp++);
}
}
}
-/* loop through the sectors from the highest address when the passed
- * address is greater or equal to the sector address we have a match
+/*
+ * Loop through the sector table starting from the previously found sector.
+ * Searches forwards or backwards, dependent on the passed address.
*/
static flash_sect_t find_sector (flash_info_t * info, ulong addr)
{
- flash_sect_t sector;
+ static flash_sect_t saved_sector = 0; /* previously found sector */
+ flash_sect_t sector = saved_sector;
- for (sector = info->sector_count - 1; sector >= 0; sector--) {
- if (addr >= info->start[sector])
- break;
- }
+ while ((info->start[sector] < addr)
+ && (sector < info->sector_count - 1))
+ sector++;
+ while ((info->start[sector] > addr) && (sector > 0))
+ /*
+ * also decrements the sector in case of an overshot
+ * in the first loop
+ */
+ sector--;
+
+ saved_sector = sector;
return sector;
}
static int flash_write_cfiword (flash_info_t * info, ulong dest,
cfiword_t cword)
{
- void *dstaddr;
+ void *dstaddr = (void *)dest;
int flag;
- flash_sect_t sect;
-
- dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
+ flash_sect_t sect = 0;
+ char sect_found = 0;
/* Check if Flash is (sufficiently) erased */
switch (info->portwidth) {
flag = 0;
break;
}
- if (!flag) {
- unmap_physmem(dstaddr, info->portwidth);
+ if (!flag)
return ERR_NOT_ERASED;
- }
/* Disable interrupts which might cause a timeout here */
flag = disable_interrupts ();
break;
case CFI_CMDSET_AMD_EXTENDED:
case CFI_CMDSET_AMD_STANDARD:
-#ifdef CONFIG_FLASH_CFI_LEGACY
- case CFI_CMDSET_AMD_LEGACY:
-#endif
sect = find_sector(info, dest);
flash_unlock_seq (info, sect);
flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE);
+ sect_found = 1;
+ break;
+#ifdef CONFIG_FLASH_CFI_LEGACY
+ case CFI_CMDSET_AMD_LEGACY:
+ sect = find_sector(info, dest);
+ flash_unlock_seq (info, 0);
+ flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
+ sect_found = 1;
break;
+#endif
}
switch (info->portwidth) {
if (flag)
enable_interrupts ();
- unmap_physmem(dstaddr, info->portwidth);
+ if (!sect_found)
+ sect = find_sector (info, dest);
- return flash_full_status_check (info, find_sector (info, dest),
- info->write_tout, "write");
+ return flash_full_status_check (info, sect, info->write_tout, "write");
}
#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
int cnt;
int retcode;
void *src = cp;
- void *dst = map_physmem(dest, len, MAP_NOCACHE);
+ void *dst = (void *)dest;
void *dst2 = dst;
int flag = 0;
uint offset = 0;
#endif
flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
cnt = len >> shift;
- flash_write_cmd(info, sector, offset, (uchar)cnt - 1);
+ flash_write_cmd(info, sector, offset, cnt - 1);
switch (info->portwidth) {
case FLASH_CFI_8BIT:
}
out_unmap:
- unmap_physmem(dst, len);
return retcode;
}
#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
/* handle unaligned start */
if ((aln = addr - wp) != 0) {
cword.l = 0;
- p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
+ p = (uchar *)wp;
for (i = 0; i < aln; ++i)
flash_add_byte (info, &cword, flash_read8(p + i));
flash_add_byte (info, &cword, flash_read8(p + i));
rc = flash_write_cfiword (info, wp, cword);
- unmap_physmem(p, info->portwidth);
if (rc != 0)
return rc;
* handle unaligned tail bytes
*/
cword.l = 0;
- p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
+ p = (uchar *)wp;
for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
flash_add_byte (info, &cword, *src++);
--cnt;
}
for (; i < info->portwidth; ++i)
flash_add_byte (info, &cword, flash_read8(p + i));
- unmap_physmem(p, info->portwidth);
return flash_write_cfiword (info, wp, cword);
}
static void cmdset_amd_read_jedec_ids(flash_info_t *info)
{
+ ushort bankId = 0;
+ uchar manuId;
+
flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
flash_unlock_seq(info, 0);
flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
udelay(1000); /* some flash are slow to respond */
- info->manufacturer_id = flash_read_uchar (info,
- FLASH_OFFSET_MANUFACTURER_ID);
+ manuId = flash_read_uchar (info, FLASH_OFFSET_MANUFACTURER_ID);
+ /* JEDEC JEP106Z specifies ID codes up to bank 7 */
+ while (manuId == FLASH_CONTINUATION_CODE && bankId < 0x800) {
+ bankId += 0x100;
+ manuId = flash_read_uchar (info,
+ bankId | FLASH_OFFSET_MANUFACTURER_ID);
+ }
+ info->manufacturer_id = manuId;
switch (info->chipwidth){
case FLASH_CFI_8BIT:
* board_flash_get_legacy needs to fill in at least:
* info->portwidth, info->chipwidth and info->interface for Jedec probing.
*/
-static int flash_detect_legacy(ulong base, int banknum)
+static int flash_detect_legacy(phys_addr_t base, int banknum)
{
flash_info_t *info = &flash_info[banknum];
for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
info->vendor = modes[i];
- info->start[0] = base;
+ info->start[0] =
+ (ulong)map_physmem(base,
+ info->portwidth,
+ MAP_NOCACHE);
if (info->portwidth == FLASH_CFI_8BIT
&& info->interface == FLASH_CFI_X8X16) {
info->addr_unlock1 = 0x2AAA;
info->manufacturer_id,
info->device_id,
info->device_id2);
- if (jedec_flash_match(info, base))
+ if (jedec_flash_match(info, info->start[0]))
break;
+ else
+ unmap_physmem((void *)info->start[0],
+ MAP_NOCACHE);
}
}
return 0; /* use CFI */
}
#else
-static inline int flash_detect_legacy(ulong base, int banknum)
+static inline int flash_detect_legacy(phys_addr_t base, int banknum)
{
return 0; /* use CFI */
}
/* AT49BV6416(T) list the erase regions in the wrong order.
* However, the device ID is identical with the non-broken
- * AT49BV642D since u-boot only reads the low byte (they
- * differ in the high byte.) So leave out this fixup for now.
+ * AT49BV642D they differ in the high byte.
*/
-#if 0
if (info->device_id == 0xd6 || info->device_id == 0xd2)
reverse_geometry = !reverse_geometry;
-#endif
if (reverse_geometry)
cfi_reverse_geometry(qry);
}
+static void flash_fixup_stm(flash_info_t *info, struct cfi_qry *qry)
+{
+ /* check if flash geometry needs reversal */
+ if (qry->num_erase_regions > 1) {
+ /* reverse geometry if top boot part */
+ if (info->cfi_version < 0x3131) {
+ /* CFI < 1.1, guess by device id (M29W320{DT,ET} only) */
+ if (info->device_id == 0x22CA ||
+ info->device_id == 0x2256) {
+ cfi_reverse_geometry(qry);
+ }
+ }
+ }
+}
+
/*
* The following code cannot be run from FLASH!
*
*/
-ulong flash_get_size (ulong base, int banknum)
+ulong flash_get_size (phys_addr_t base, int banknum)
{
flash_info_t *info = &flash_info[banknum];
int i, j;
flash_sect_t sect_cnt;
- unsigned long sector;
+ phys_addr_t sector;
unsigned long tmp;
int size_ratio;
uchar num_erase_regions;
info->legacy_unlock = 0;
#endif
- info->start[0] = base;
+ info->start[0] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE);
if (flash_detect_cfi (info, &qry)) {
info->vendor = le16_to_cpu(qry.p_id);
case 0x001f:
flash_fixup_atmel(info, &qry);
break;
+ case 0x0020:
+ flash_fixup_stm(info, &qry);
+ break;
}
debug ("manufacturer is %d\n", info->vendor);
printf("ERROR: too many flash sectors\n");
break;
}
- info->start[sect_cnt] = sector;
+ info->start[sect_cnt] =
+ (ulong)map_physmem(sector,
+ info->portwidth,
+ MAP_NOCACHE);
sector += (erase_region_size * size_ratio);
/*
#endif
#ifdef CONFIG_SYS_FLASH_PROTECTION
- char *s = getenv("unlock");
+ /* read environment from EEPROM */
+ char s[64];
+ getenv_r ("unlock", s, sizeof(s));
#endif
-#define BANK_BASE(i) (((unsigned long [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i])
+#define BANK_BASE(i) (((phys_addr_t [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i])
/* Init: no FLASHes known */
for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
#ifdef CONFIG_ENV_ADDR_REDUND
flash_protect (FLAG_PROTECT_SET,
CONFIG_ENV_ADDR_REDUND,
- CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SIZE_REDUND - 1,
+ CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1,
flash_get_info(CONFIG_ENV_ADDR_REDUND));
#endif
flash_get_info(apl[i].start));
}
#endif
+
+#ifdef CONFIG_FLASH_CFI_MTD
+ cfi_mtd_init();
+#endif
+
return (size);
}