[U-Boot-Users] Mixing CFI and non-CFI flashs?

Michael Schwingen
2007-11-03T15:00:56Z

On Sat, Nov 03, 2007 at 08:13:40AM +0100, Stefan Roese wrote:
> I remember a discussion we had a while ago, about supporting non-CFI chips in
> a common driver, but I can't find the mails right now. IIRC, the idea was to
> add something close to the Linux JEDEC probe
> (drivers/mtd/chips/jedec_probe.c) for this.

Good idea. I currently hard-coded the flash parameters for the boot flash,
since I know there is exactly one type on the boards, but having
jedec-probing would be nicer.

I think the CFI driver is a good start as a framework - all the
infrastructure for handling mutliple banks, different chip/bus mappings etc.
is there and could be used by jedec-flash code. For now, it is probably
easiest to add the JEDEC code to cfi_flash.c, to get access to the static
functions defined there, and then later split it out if necessary.

> I suggest that you post your current version for review. This sounds like a
> start in the correct direction.

Fine. Here is what I have got now - it works for my board, but would
probably need some cleanup/renaming of symbols. The basic idea is that the
board-specific code provides a function "flash_detect_legacy" that is called
for every flash bank, which can provide hardcoded (or in the future
jedec-probed) flash information. If the function returns 0, the normal CFI
code is called.

Since that code is board-specific anyway, I think the board-specific code
can supply the information about chipwidth, buswidth etc. - there is no real
benefit in autoprobing these, and there is less probability for problems
(like 8-bit accesses to a 16-bit bus causing problems, etc.).

I have included one non-conditional patch I made:
@@ -1282,6 +1310,8 @@ ulong flash_get_size (ulong base, int banknum)
which causes the CFI code to stop in case CFG_MAX_FLASH_SECT is defined too
small - without that patch, u-boot overwrites other data and crashes
silently during startup.

cu
Michael

Signed-off-by: Michael Schwingen <michael@schwingen.org>

diff --git a/include/flash.h b/include/flash.h
index b0bf733..f0ef6f7 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -101,6 +101,11 @@ extern void flash_read_user_serial(flash_info_t * info,
void * buffer, int offse
extern void flash_read_factory_serial(flash_info_t * info, void * buffer,
int offset, int len);
#endif /* CFG_FLASH_PROTECTION */

+#ifdef CFG_FLASH_CFI_LEGACY
+extern ulong flash_detect_legacy(ulong base, int banknum);
+#define CFI_CMDSET_AMD_LEGACY 0xFFF0
+#endif
+
/*-----------------------------------------------------------------------
* return codes from flash_write():
*/

diff --git a/drivers/cfi_flash.c b/drivers/cfi_flash.c
index 5579a1e..20ccc3a 100644
--- a/drivers/cfi_flash.c
+++ b/drivers/cfi_flash.c
@@ -345,7 +345,13 @@ unsigned long flash_init (void)
/* Init: no FLASHes known */
for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
flash_info[i].flash_id = FLASH_UNKNOWN;
- size += flash_info[i].size = flash_get_size (bank_base[i], i);
+
+#ifdef CFG_FLASH_CFI_LEGACY
+ flash_info[i].size = flash_detect_legacy (bank_base[i], i);
+ if (flash_info[i].size == 0)
+#endif
+ flash_info[i].size = flash_get_size (bank_base[i], i);
+ size += flash_info[i].size;
if (flash_info[i].flash_id == FLASH_UNKNOWN) {
#ifndef CFG_FLASH_QUIET_TEST
printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
@@ -488,6 +494,16 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
flash_unlock_seq (info, sect);
flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR);
break;
+#ifdef CFG_FLASH_CFI_LEGACY
+ case CFI_CMDSET_AMD_LEGACY:
+ flash_write_cmd (info, 0, 0x5555, AMD_CMD_UNLOCK_START);
+ flash_write_cmd (info, 0, 0x2AAA, AMD_CMD_UNLOCK_ACK);
+ flash_write_cmd (info, 0, 0x5555, AMD_CMD_ERASE_START);
+ flash_write_cmd (info, 0, 0x5555, AMD_CMD_UNLOCK_START);
+ flash_write_cmd (info, 0, 0x2AAA, AMD_CMD_UNLOCK_ACK);
+ flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR);
+ break;
+#endif
default:
debug ("Unkown flash vendor %d\n",
info->vendor);
@@ -518,8 +534,12 @@ void flash_print_info (flash_info_t * info)

printf ("CFI conformant FLASH (%d x %d)",
(info->portwidth << 3), (info->chipwidth << 3));
- printf (" Size: %ld MB in %d Sectors\n",
- info->size >> 20, info->sector_count);
+ if (info->size < 1024*1024)
+ printf (" Size: %ld kB in %d Sectors\n",
+ info->size >> 10, info->sector_count);
+ else
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
printf (" ");
switch (info->vendor) {
case CFI_CMDSET_INTEL_STANDARD:
@@ -534,6 +554,11 @@ void flash_print_info (flash_info_t * info)
case CFI_CMDSET_AMD_EXTENDED:
printf ("AMD Extended");
break;
+#ifdef CFG_FLASH_CFI_LEGACY
+ case CFI_CMDSET_AMD_LEGACY:
+ printf ("AMD (non-CFI)");
+ break;
+#endif
default:
printf ("Unknown (%d)", info->vendor);
break;
@@ -777,6 +802,9 @@ static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
break;
case CFI_CMDSET_AMD_STANDARD:
case CFI_CMDSET_AMD_EXTENDED:
+#ifdef CFG_FLASH_CFI_LEGACY
+ case CFI_CMDSET_AMD_LEGACY:
+#endif
retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
break;
default:
@@ -1282,6 +1310,8 @@ ulong flash_get_size (ulong base, int banknum)
debug ("erase_region_count = %d erase_region_size = %d\n",
erase_region_count, erase_region_size);
for (j = 0; j < erase_region_count; j++) {
+ if (sect_cnt >= CFG_MAX_FLASH_SECT)
+ break;
info->start[sect_cnt] = sector;
sector += (erase_region_size * size_ratio);

@@ -1387,6 +1417,12 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest,
flash_unlock_seq (info, 0);
flash_write_cmd (info, 0, AMD_ADDR_START, AMD_CMD_WRITE);
break;
+#ifdef CFG_FLASH_CFI_LEGACY
+ case CFI_CMDSET_AMD_LEGACY:
+ flash_write_cmd (info, 0, 0x5555, AMD_CMD_UNLOCK_START);
+ flash_write_cmd (info, 0, 0x2AAA, AMD_CMD_UNLOCK_ACK);
+ flash_write_cmd (info, 0, 0x5555, AMD_CMD_WRITE);
+#endif
}

switch (info->portwidth) {

and then in the board-init code:

extern flash_info_t flash_info[];
#define AMD_CMD_RESET 0xF0

ulong flash_detect_legacy(ulong base, int banknum)
{
if (banknum == 0) {
flash_info_t *info = &flash_info[banknum];
int i;
unsigned long sector;

info->portwidth = 1;
info->chipwidth = 1;
info->ext_addr = 0;
info->cfi_version = 0;
info->legacy_unlock = 0;
info->start[0] = base;
info->cmd_reset = AMD_CMD_RESET;
info->vendor = CFI_CMDSET_AMD_LEGACY;
info->flash_id = FLASH_MAN_CFI;

info->sector_count = 64;

for (i = 0, sector = base; i < info->sector_count; i++) {
info->protect[i] = 0;
info->start[i] = sector;
sector += 4096;
}

info->buffer_size = 1;
info->erase_blk_tout = 10000;
info->buffer_write_tout = 1000;
info->write_tout = 100;
return 256*1024;
}
else
return 0;
}