Practice of uboot migration of Mini440 and NOR FLASH support

In the previous section, I wonder if you noticed that after starting u-boot, there is a line of information running:

The code for outputting Flash information is located on the board_init_r phase, execute Initr_ The output of the Flash() function.

Our development board is equipped with a 2MB(1M*16bit) NOR FLASH with the model S29AL016D70TF102. The output nor false size is 0 bytes. Obviously, 2M NOR FLASH can not be correctly recognized.

In this section, we will introduce how u-boot supports our NOR FLASH, so that we can read and write nor false through the command line.

1, NOR FLASH support

1.1 analyze startup information

When NOR starts, we print debugging information:

Flash: fwc addr 00000000 cmd f0 00f0 16bit x 16 bit
fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit
fwc addr 00005554 cmd 55 0055 16bit x 16 bit
fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit
fwc addr 00000000 cmd f0 00f0 16bit x 16 bit
JEDEC PROBE: ID 1 2249 0
fwc addr 00000000 cmd ff 00ff 16bit x 16 bit
fwc addr 00000000 cmd 90 0090 16bit x 16 bit
fwc addr 00000000 cmd ff 00ff 16bit x 16 bit
JEDEC PROBE: ID be ea00 0
0 Bytes

Print out the manufacturer ID of NOR FLASH = 0x01 (produced by AMD) and device ID=0x2249. We check the datasheet of S29AL016D70TF102 chip and find that the two IDs are correct, but they are not detected. It indicates that the underlying driver of the program is correct, but the board does not support this nor:

We located   initr_flash(common/board_r.c):

static int initr_flash(void)
{
    ulong flash_size = 0;
    bd_t *bd = gd->bd;

    puts("Flash: ");

    if (board_flash_wp_on())
        printf("Uninitialized - Write Protect On\n");
    else
        flash_size = flash_init();

    print_size(flash_size, "");
#ifdef CONFIG_SYS_FLASH_CHECKSUM
    /*
    * Compute and print flash CRC if flashchecksum is set to 'y'
    *
    * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
    */
    if (getenv_yesno("flashchecksum") == 1) {
        printf("  CRC: %08X", crc32(0,
            (const unsigned char *) CONFIG_SYS_FLASH_BASE,
            flash_size));
    }
#endif /* CONFIG_SYS_FLASH_CHECKSUM */
    putc('\n');

    /* update start of FLASH memory    */
#ifdef CONFIG_SYS_FLASH_BASE
    bd->bi_flashstart = CONFIG_SYS_FLASH_BASE;
#endif
    /* size of FLASH memory (final value) */
    bd->bi_flashsize = flash_size;

#if defined(CONFIG_SYS_UPDATE_FLASH_SIZE)
    /* Make a update of the Memctrl. */
    update_flash_size(flash_size);
#endif


#if defined(CONFIG_OXC) || defined(CONFIG_RMU)
    /* flash mapped at end of memory map */
    bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size;
#elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
    bd->bi_flashoffset = monitor_flash_len;    /* reserved area for monitor */
#endif
    return 0;
}

flash_init function in drivers \ MTD \ CFI_ Defined in flash. C:

unsigned long flash_init (void)
{
    unsigned long size = 0;
    int i;

#ifdef CONFIG_SYS_FLASH_PROTECTION
    /* read environment from EEPROM */
    char s[64];
    getenv_f("unlock", s, sizeof(s));
#endif

#ifdef CONFIG_CFI_FLASH /* for driver model */
    cfi_flash_init_dm();
#endif

    /* Init: no FLASHes known */
    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
        flash_info[i].flash_id = FLASH_UNKNOWN;            //0xFFFF

        /* Optionally write flash configuration register */
        cfi_flash_set_config_reg(cfi_flash_bank_addr(i),   // Nothing. It's empty
                     cfi_flash_config_reg(i));

        if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
            flash_get_size(cfi_flash_bank_addr(i), i);
        size += flash_info[i].size;
        if (flash_info[i].flash_id == FLASH_UNKNOWN) {
#ifndef CONFIG_SYS_FLASH_QUIET_TEST
            printf ("## Unknown flash on Bank %d "
                "- Size = 0x%08lx = %ld MB\n",
                i+1, flash_info[i].size,
                flash_info[i].size >> 20);
#endif /* CONFIG_SYS_FLASH_QUIET_TEST */
        }
#ifdef CONFIG_SYS_FLASH_PROTECTION
        else if (strcmp(s, "yes") == 0) {
            /*
             * Only the U-Boot image and it's environment
             * is protected, all other sectors are
             * unprotected (unlocked) if flash hardware
             * protection is used (CONFIG_SYS_FLASH_PROTECTION)
             * and the environment variable "unlock" is
             * set to "yes".
             */
            if (flash_info[i].legacy_unlock) {
                int k;

                /*
                 * Disable legacy_unlock temporarily,
                 * since flash_real_protect would
                 * relock all other sectors again
                 * otherwise.
                 */
                flash_info[i].legacy_unlock = 0;

                /*
                 * Legacy unlocking (e.g. Intel J3) ->
                 * unlock only one sector. This will
                 * unlock all sectors.
                 */
                flash_real_protect (&flash_info[i], 0, 0);

                flash_info[i].legacy_unlock = 1;

                /*
                 * Manually mark other sectors as
                 * unlocked (unprotected)
                 */
                for (k = 1; k < flash_info[i].sector_count; k++)
                    flash_info[i].protect[k] = 0;
            } else {
                /*
                 * No legancy unlocking -> unlock all sectors
                 */
                flash_protect (FLAG_PROTECT_CLEAR,
                           flash_info[i].start[0],
                           flash_info[i].start[0]
                           + flash_info[i].size - 1,
                           &flash_info[i]);
            }
        }
#endif /* CONFIG_SYS_FLASH_PROTECTION */
    }

    flash_protect_default();
#ifdef CONFIG_FLASH_CFI_MTD
    cfi_mtd_init();
#endif

    return (size);
}

Where CONFIG_SYS_MAX_FLASH_BANKS is defined as 1, FLASH_UNKNOWN is defined as 0xFFFF:

#define CONFIG_SYS_MAX_FLASH_BANKS    1
#define FLASH_UNKNOWN 0xFFFF /* unknown flash type */

flash_info is defined as follows:

#define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS
flash_info_t flash_info[CFI_MAX_FLASH_BANKS];    /* FLASH chips info */
/*-----------------------------------------------------------------------
 * FLASH Info: contains chip specific data, per FLASH bank
 */

typedef struct {
    ulong    size;            /* total bank size in bytes        */
    ushort    sector_count;        /* number of erase units        */
    ulong    flash_id;        /* combined device & manufacturer code    */
    ulong    start[CONFIG_SYS_MAX_FLASH_SECT];   /* virtual sector start address */
    uchar    protect[CONFIG_SYS_MAX_FLASH_SECT]; /* sector protection status    */
#ifdef CONFIG_SYS_FLASH_CFI
    uchar    portwidth;        /* the width of the port        */
    uchar    chipwidth;        /* the width of the chip        */
    ushort    buffer_size;        /* # of bytes in write buffer        */
    ulong    erase_blk_tout;        /* maximum block erase timeout        */
    ulong    write_tout;        /* maximum write timeout        */
    ulong    buffer_write_tout;    /* maximum buffer write timeout        */
    ushort    vendor;            /* the primary vendor id        */
    ushort    cmd_reset;        /* vendor specific reset command    */
    uchar   cmd_erase_sector;    /* vendor specific erase sect. command    */
    ushort    interface;        /* used for x8/x16 adjustments        */
    ushort    legacy_unlock;        /* support Intel legacy (un)locking    */
    ushort    manufacturer_id;    /* manufacturer id            */
    ushort    device_id;        /* device id                */
    ushort    device_id2;        /* extended device id            */
    ushort    ext_addr;        /* extended query table address        */
    ushort    cfi_version;        /* cfi version                */
    ushort    cfi_offset;        /* offset for cfi query            */
    ulong   addr_unlock1;        /* unlock address 1 for AMD flash roms  */
    ulong   addr_unlock2;        /* unlock address 2 for AMD flash roms  */
    const char *name;        /* human-readable name                    */
#endif
#ifdef CONFIG_MTD
    struct mtd_info *mtd;
#endif
} flash_info_t;

Here we focus on flash_detect_legacy and flash_get_size function.

1.2 flash_detect_legacy

/*-----------------------------------------------------------------------
 * Call board code to request info about non-CFI flash.
 * 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(phys_addr_t base, int banknum)
{
    flash_info_t *info = &flash_info[banknum];

    if (board_flash_get_legacy(base, banknum, info)) {
        /* board code may have filled info completely. If not, we
           use JEDEC ID probing. */
        if (!info->vendor) {
            int modes[] = {
                CFI_CMDSET_AMD_STANDARD,
                CFI_CMDSET_INTEL_STANDARD
            };
            int i;

            for (i = 0; i < ARRAY_SIZE(modes); i++) {
                info->vendor = modes[i];
                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->addr_unlock2 = 0x5555;
                } else {
                    info->addr_unlock1 = 0x5555;
                    info->addr_unlock2 = 0x2AAA;
                }
                flash_read_jedec_ids(info);
                debug("JEDEC PROBE: ID %x %x %x\n",
                        info->manufacturer_id,
                        info->device_id,
                        info->device_id2);
                if (jedec_flash_match(info, info->start[0]))
                    break;
                else
                    unmap_physmem((void *)info->start[0],
                              info->portwidth);
            }
        }

        switch(info->vendor) {
        case CFI_CMDSET_INTEL_PROG_REGIONS:
        case CFI_CMDSET_INTEL_STANDARD:
        case CFI_CMDSET_INTEL_EXTENDED:
            info->cmd_reset = FLASH_CMD_RESET;
            break;
        case CFI_CMDSET_AMD_STANDARD:
        case CFI_CMDSET_AMD_EXTENDED:
        case CFI_CMDSET_AMD_LEGACY:
            info->cmd_reset = AMD_CMD_RESET;
            break;
        }
        info->flash_id = FLASH_MAN_CFI;
        return 1;
    }
    return 0; /* use CFI */
}

  Enter jedec_flash_match function at drivers/mtd/jedec_flash.c:

/*-----------------------------------------------------------------------
 * match jedec ids against table. If a match is found, fill flash_info entry
 */
int jedec_flash_match(flash_info_t *info, ulong base)
{
    int ret = 0;
    int i;
    ulong mask = 0xFFFF;
    if (info->chipwidth == 1)
        mask = 0xFF;

    for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {
        if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&
            (jedec_table[i].dev_id & mask) == (info->device_id & mask)) {
            fill_info(info, &jedec_table[i], base);
            ret = 1;
            break;
        }
    }
    return ret;
}

Enter jedec_table array view:

static const struct amd_flash_info jedec_table[] = {
#ifdef CONFIG_SYS_FLASH_LEGACY_256Kx8
    {
        .mfr_id        = (u16)SST_MANUFACT,
        .dev_id        = SST39LF020,
        .name        = "SST 39LF020",
        .uaddr        = {
            [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
        },
        .DevSize    = SIZE_256KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x01000,64),
        }
    },
#endif
#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx8
    {
        .mfr_id        = (u16)AMD_MANUFACT,
        .dev_id        = AM29LV040B,
        .name        = "AMD AM29LV040B",
        .uaddr        = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000,8),
        }
    },
    {
        .mfr_id        = (u16)SST_MANUFACT,
        .dev_id        = SST39LF040,
        .name        = "SST 39LF040",
        .uaddr        = {
            [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x01000,128),
        }
    },
    {
        .mfr_id        = (u16)STM_MANUFACT,
        .dev_id        = STM_ID_M29W040B,
        .name        = "ST Micro M29W040B",
        .uaddr        = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000,8),
        }
    },
    {
        .mfr_id        = (u16)MX_MANUFACT,
        .dev_id        = MX29LV040,
        .name        = "MXIC MX29LV040",
        .uaddr        = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
    {
        .mfr_id        = (u16)WINB_MANUFACT,
        .dev_id        = W39L040A,
        .name        = "WINBOND W39L040A",
        .uaddr        = {
            [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
    {
        .mfr_id        = (u16)AMIC_MANUFACT,
        .dev_id        = A29L040,
        .name        = "AMIC A29L040",
        .uaddr        = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
    {
        .mfr_id        = (u16)EON_MANUFACT,
        .dev_id        = EN29LV040A,
        .name        = "EON EN29LV040A",
        .uaddr        = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
#endif
#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx16
    {
        .mfr_id        = (u16)AMD_MANUFACT,
        .dev_id        = AM29F400BB,
        .name        = "AMD AM29F400BB",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x04000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x10000, 7),
        }
    },
    {
        .mfr_id        = (u16)AMD_MANUFACT,
        .dev_id        = AM29LV400BB,
        .name        = "AMD AM29LV400BB",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x04000,1),
            ERASEINFO(0x02000,2),
            ERASEINFO(0x08000,1),
            ERASEINFO(0x10000,7),
        }
    },
    {
        .mfr_id        = (u16)AMD_MANUFACT,
        .dev_id        = AM29LV800BB,
        .name        = "AMD AM29LV800BB",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_1MiB,
        .CmdSet        = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x04000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x10000, 15),
        }
    },
    {
        .mfr_id        = (u16)AMD_MANUFACT,
        .dev_id        = AM29LV800BT,
        .name        = "AMD AM29LV800BT",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_1MiB,
        .CmdSet        = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x10000, 15),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x04000, 1),
        }
    },
    {
        .mfr_id        = (u16)MX_MANUFACT,
        .dev_id        = AM29LV800BT,
        .name        = "MXIC MX29LV800BT",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_1MiB,
        .CmdSet        = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x10000, 15),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x04000, 1),
        }
    },
    {
        .mfr_id        = (u16)EON_ALT_MANU,
        .dev_id        = AM29LV800BT,
        .name        = "EON EN29LV800BT",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_1MiB,
        .CmdSet        = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x10000, 15),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x04000, 1),
        }
    },
    {
        .mfr_id        = (u16)STM_MANUFACT,
        .dev_id        = STM29F400BB,
        .name        = "ST Micro M29F400BB",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize        = SIZE_512KiB,
        .CmdSet            = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions    = 4,
        .regions        = {
            ERASEINFO(0x04000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x10000, 7),
        }
    },
#endif
};

After query, it is found that there is no NOR FLASH model S29AL016D70TF102 we use.

Enter the macro definition code of the machine ID and find this:

#define AMD_MANUFACT    0x00010001    /* AMD       manuf. ID in D23..D16, D7..D0 */

01 is the NOR FLASH manufacturer ID we use, which indicates that u-boot can be supported, but it is not written in the array. Change the array and add our own NOR FLASH to support it.

1.3 modification jedec_table array (drivers/mtd/jedec_flash.c)

Because there is a macro definition in the array, I don't intend to destroy its structure. I just copied one and pasted it to the last end of the array.

    {
        .mfr_id        = (u16)AMD_MANUFACT,
        .dev_id        = AM29LV160DB,
        .name        = "AMD AM29LV160DB",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize        = SIZE_2MiB,
        .CmdSet            = P_ID_AMD_STD,
        .NumEraseRegions    = 4,
        .regions        = {
            ERASEINFO(64*1024, 31),
            ERASEINFO(32*1024, 1),
            ERASEINFO(8*1024, 2),
            ERASEINFO(16*1024, 1),
        }
    },
  • Manufacturer ID: mfr_id changed to AMD_MANUFACT;
  • Device ID: dev_ The ID is modified to 0x2249, i.e. AM29LV160DB;
  • Name: name is modified to AMD AM29LV160DB;
  • uaddr: the unlocking address is changed to [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ /*NOR flash unlock address * /. [0] indicates that NOR is 8 bits. I use 16 bits, so it is changed to 1. NORFlash will be locked when it is used, so it must be unlocked when writing, and it can only be unlocked when writing values in some addresses. The unlocking address can be found in the manual.
  • Size: modify DevSize to SIZE_2MiB;
  • NumEraseRegions: erasure blocks are different due to different structures of NOR. You can refer to the manual and write as many blocks as there are.
  • regions: describe the distribution of erasure blocks. From top to bottom, the addresses in NOR are arranged from low to high;

I use four types of NOR: one 8K word, one 4K byte, one 16K word and 31 32K words. The 1K word size is 2048 bytes.

 

Therefore, regions are configured as follows:

        .regions        = {
            ERASEINFO(64*1024, 31),
            ERASEINFO(32*1024, 1),
            ERASEINFO(8*1024, 2),
            ERASEINFO(16*1024, 1),
        }

Modify the include / config / smdk2440. H file, and use config here_ SYS_ MAX_ FLASH_ SEC defines the maximum number of NOR FLASH sectors, which we modify to 128.   In fact, this value can be any number, as long as it is greater than the erase block used.

#define CONFIG_SYS_MAX_FLASH_SECT (128)

1.4 flash_get_size

 

/*
 * The following code cannot be run from FLASH!
 *
 */
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;
    phys_addr_t sector;
    unsigned long tmp;
    int size_ratio;
    uchar num_erase_regions;
    int erase_region_size;
    int erase_region_count;
    struct cfi_qry qry;
    unsigned long max_size;

    memset(&qry, 0, sizeof(qry));

    info->ext_addr = 0;
    info->cfi_version = 0;
#ifdef CONFIG_SYS_FLASH_PROTECTION
    info->legacy_unlock = 0;
#endif

    info->start[0] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE);

    if (flash_detect_cfi (info, &qry)) {
        info->vendor = le16_to_cpu(get_unaligned(&(qry.p_id)));
        info->ext_addr = le16_to_cpu(get_unaligned(&(qry.p_adr)));
        num_erase_regions = qry.num_erase_regions;

        if (info->ext_addr) {
            info->cfi_version = (ushort) flash_read_uchar (info,
                        info->ext_addr + 3) << 8;
            info->cfi_version |= (ushort) flash_read_uchar (info,
                        info->ext_addr + 4);
        }

#ifdef DEBUG
        flash_printqry (&qry);
#endif

        switch (info->vendor) {
        case CFI_CMDSET_INTEL_PROG_REGIONS:
        case CFI_CMDSET_INTEL_STANDARD:
        case CFI_CMDSET_INTEL_EXTENDED:
            cmdset_intel_init(info, &qry);
            break;
        case CFI_CMDSET_AMD_STANDARD:
        case CFI_CMDSET_AMD_EXTENDED:
            cmdset_amd_init(info, &qry);
            break;
        default:
            printf("CFI: Unknown command set 0x%x\n",
                    info->vendor);
            /*
             * Unfortunately, this means we don't know how
             * to get the chip back to Read mode. Might
             * as well try an Intel-style reset...
             */
            flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
            return 0;
        }

        /* Do manufacturer-specific fixups */
        switch (info->manufacturer_id) {
        case 0x0001: /* AMD */
        case 0x0037: /* AMIC */
            flash_fixup_amd(info, &qry);
            break;
        case 0x001f:
            flash_fixup_atmel(info, &qry);
            break;
        case 0x0020:
            flash_fixup_stm(info, &qry);
            break;
        case 0x00bf: /* SST */
            flash_fixup_sst(info, &qry);
            break;
        case 0x0089: /* Numonyx */
            flash_fixup_num(info, &qry);
            break;
        }

        debug ("manufacturer is %d\n", info->vendor);
        debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
        debug ("device id is 0x%x\n", info->device_id);
        debug ("device id2 is 0x%x\n", info->device_id2);
        debug ("cfi version is 0x%04x\n", info->cfi_version);

        size_ratio = info->portwidth / info->chipwidth;
        /* if the chip is x8/x16 reduce the ratio by half */
        if ((info->interface == FLASH_CFI_X8X16)
            && (info->chipwidth == FLASH_CFI_BY8)) {
            size_ratio >>= 1;
        }
        debug ("size_ratio %d port %d bits chip %d bits\n",
               size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
               info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
        info->size = 1 << qry.dev_size;
        /* multiply the size by the number of chips */
        info->size *= size_ratio;
        max_size = cfi_flash_bank_size(banknum);
        if (max_size && (info->size > max_size)) {
            debug("[truncated from %ldMiB]", info->size >> 20);
            info->size = max_size;
        }
        debug ("found %d erase regions\n", num_erase_regions);
        sect_cnt = 0;
        sector = base;
        for (i = 0; i < num_erase_regions; i++) {
            if (i > NUM_ERASE_REGIONS) {
                printf ("%d erase regions found, only %d used\n",
                    num_erase_regions, NUM_ERASE_REGIONS);
                break;
            }

            tmp = le32_to_cpu(get_unaligned(
                        &(qry.erase_region_info[i])));
            debug("erase region %u: 0x%08lx\n", i, tmp);

            erase_region_count = (tmp & 0xffff) + 1;
            tmp >>= 16;
            erase_region_size =
                (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
            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 (sector - base >= info->size)
                    break;
                if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
                    printf("ERROR: too many flash sectors\n");
                    break;
                }
                info->start[sect_cnt] =
                    (ulong)map_physmem(sector,
                               info->portwidth,
                               MAP_NOCACHE);
                sector += (erase_region_size * size_ratio);

                /*
                 * Only read protection status from
                 * supported devices (intel...)
                 */
                switch (info->vendor) {
                case CFI_CMDSET_INTEL_PROG_REGIONS:
                case CFI_CMDSET_INTEL_EXTENDED:
                case CFI_CMDSET_INTEL_STANDARD:
                    /*
                     * Set flash to read-id mode. Otherwise
                     * reading protected status is not
                     * guaranteed.
                     */
                    flash_write_cmd(info, sect_cnt, 0,
                            FLASH_CMD_READ_ID);
                    info->protect[sect_cnt] =
                        flash_isset (info, sect_cnt,
                                 FLASH_OFFSET_PROTECT,
                                 FLASH_STATUS_PROTECT);
                    flash_write_cmd(info, sect_cnt, 0,
                            FLASH_CMD_RESET);
                    break;
                case CFI_CMDSET_AMD_EXTENDED:
                case CFI_CMDSET_AMD_STANDARD:
                    if (!info->legacy_unlock) {
                        /* default: not protected */
                        info->protect[sect_cnt] = 0;
                        break;
                    }

                    /* Read protection (PPB) from sector */
                    flash_write_cmd(info, 0, 0,
                            info->cmd_reset);
                    flash_unlock_seq(info, 0);
                    flash_write_cmd(info, 0,
                            info->addr_unlock1,
                            FLASH_CMD_READ_ID);
                    info->protect[sect_cnt] =
                        flash_isset(
                            info, sect_cnt,
                            FLASH_OFFSET_PROTECT,
                            FLASH_STATUS_PROTECT);
                    break;
                default:
                    /* default: not protected */
                    info->protect[sect_cnt] = 0;
                }

                sect_cnt++;
            }
        }

        info->sector_count = sect_cnt;
        info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
        tmp = 1 << qry.block_erase_timeout_typ;
        info->erase_blk_tout = tmp *
            (1 << qry.block_erase_timeout_max);
        tmp = (1 << qry.buf_write_timeout_typ) *
            (1 << qry.buf_write_timeout_max);

        /* round up when converting to ms */
        info->buffer_write_tout = (tmp + 999) / 1000;
        tmp = (1 << qry.word_write_timeout_typ) *
            (1 << qry.word_write_timeout_max);
        /* round up when converting to ms */
        info->write_tout = (tmp + 999) / 1000;
        info->flash_id = FLASH_MAN_CFI;
        if ((info->interface == FLASH_CFI_X8X16) &&
            (info->chipwidth == FLASH_CFI_BY8)) {
            /* XXX - Need to test on x8/x16 in parallel. */
            info->portwidth >>= 1;
        }

        flash_write_cmd (info, 0, 0, info->cmd_reset);
    }

    return (info->size);
}

2, Compile download run

2.1 compilation

make distclean
make smdk2440_config
make ARCH=arm CROSS_COMPILE=arm-linux- V=1

2.2 download to nor false

We download and run again, and the output of NOR FLASH is as follows:

Flash: fwc addr 00000000 cmd f0 00f0 16bit x 16 bit
fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit
fwc addr 00005554 cmd 55 0055 16bit x 16 bit
fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit
fwc addr 00000000 cmd f0 00f0 16bit x 16 bit
JEDEC PROBE: ID 1 2249 0
Found JEDEC Flash: AMD AM29LV160DB
unlock address index 1
unlock addresses are 0x555/0x2aa
erase_region_count = 31 erase_region_size = 65536
erase_region_count = 1 erase_region_size = 32768
erase_region_count = 2 erase_region_size = 8192
erase_region_count = 1 erase_region_size = 16384
flash_protect ON: from 0x00000000 to 0x0008931B
protect on 0
protect on 1
protect on 2
protect on 3
protect on 4
protect on 5
protect on 6
protect on 7
protect on 8
flash_protect ON: from 0x00070000 to 0x0007FFFF
protect on 7
2 MiB

Enter the flinfo command (flash info) on the console to view the flash information:

SMDK2440 # flinfo

Bank # 1: AMD AM29LV160DB flash (16 x 16)  Size: 2 MB in 35 Sectors
  AMD Legacy command set, Manufacturer ID: 0x01, Device ID: 0x2249
  Erase timeout: 30000 ms, write timeout: 100 ms

  Sector Start Addresses:
  00000000   RO   00010000   RO   00020000   RO   00030000   RO   00040000   RO 
  00050000   RO   00060000   RO   00070000   RO   00080000   RO   00090000      
  000A0000        000B0000        000C0000        000D0000        000E0000      
  000F0000        00100000        00110000        00120000        00130000      
  00140000        00150000        00160000        00170000        00180000      
  00190000        001A0000        001B0000        001C0000        001D0000      
  001E0000        001F0000        001F8000        001FA000        001FC000 

Then, use the u-boot command to check whether the reading and writing of NOR FLASH is correct. First, remove the write protection:

SMDK2440 # protect off all
Un-Protect Flash Bank # 1

View the Flash content. Here we view the data of NOR FLASH start address:

SMDK2440 # md.b 0000
00000000: be 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5    ................
00000010: 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5    ................
00000020: 60 00 00 00 c0 00 00 00 20 01 00 00 80 01 00 00    `....... .......
00000030: e0 01 00 00 40 02 00 00 a0 02 00 00 ef be ad de    ....@...........

Since we downloaded the u-boot to NOR FLASH, we can directly view the u-boot.dis file and make a comparison:

It can be seen that the data is the same. The low address data is in the low position and the high address data is in the high position. The small end storage mode is adopted.

Reference articles

[1]S3C2440 supports NORFLASH for porting uboot

[2]uboot supports NORFlash

[3]Step 5 of porting uboot: support NORFlash

[4]S29AL016D70TFI020

[5]mini2440 Hardware: Nor Flash

 

Posted on Sun, 28 Nov 2021 22:29:13 -0500 by edwardtilbury