linux
以3.18内核为例子
在内核源码中找到路径为drivers/mtd/spi-nor/spi-nor.c
的文件
打开后找到flash支持表。 内核启动过程会对比表中的INFO()
里面的参数,即flash JEDEC ID,匹配到后,按照后面的 64 * 1024等参数初始化flash的设置。
/* NOTE: double check command sets and memory organization when you add
* more nor chips. This current list focusses on newer chips, which
* have been converging on command sets which including JEDEC ID.
*/
static const struct spi_device_id spi_nor_ids[] = {
/* Atmel -- some are (confusingly) marketed as "DataFlash" */
{ "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) },
{ "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) },
{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) },
{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) },
{ "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
{ "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) },
{ "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
{ "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
/* EON -- en25xxx */
{ "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) },
{ "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) },
{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) },
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
{ "en25qh64a", INFO(0x1c7017, 0, 64 * 1024, 128, SECT_4K) },
{ "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) },
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
/* ESMT */
{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
/* Everspin */
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
.................... //省略部分代码
}
假设一款新的flash的JEDEC ID
为0x204017,大小与en25q64
的参数一样。
则需要在表中添加如下代码
{ "newboard", INFO(0x204017, 0, 64 * 1024, 128, SECT_4K) }, //只是修改了INFO()里面的第一个参数,即JEDEC ID
重新编译固件后,观看启动流程。
[ 0.680000] m25p80 spi32766.0: found newboard, expected newboard
[ 0.680000] m25p80 spi32766.0: newboard (8192 Kbytes)
[ 0.690000] m25p80 spi32766.0: using chunked io
[ 0.690000] 5 ofpart partitions found on MTD device spi32766.0
[ 0.700000] Creating 5 MTD partitions on "spi32766.0":
配置正确。
详细的匹配过程可以搜索代码中spi_nor_ids的判断代码。
uboot
在uboot中也是有类似的机制,查看是否支持该flash。 若不支持,则烧写固件时候的参数都不正确。
焊接新款flash后,uboot启动过程显示如下log
flash manufacture id: 20, device id 40 17
Warning: un-recognized chip ID, please update bootloader!
烧写固件显示如下错误log
NetBootFileXferSize= 00640004
Abort: image size larger than 3866624!
在源码中定位错误的代码,通过image size larger than
定位源码。
查找到uboot目录下drivers/spi_flash.c
,查看源码,添加JEDEC ID的打印。
int raspi_erase_write(char *buf, unsigned int offs, int count)
{
int blocksize = spi_chip_info->sector_size;
int blockmask = blocksize - 1;
ra_dbg("%s: offs:%x, count:%x\n", __func__, offs, count);
if (count > (spi_chip_info->sector_size * spi_chip_info->n_sectors) -
(CFG_BOOTLOADER_SIZE + CFG_CONFIG_SIZE + CFG_FACTORY_SIZE)) {
printf("id=0x%x, jedec=0x%x, sector_size=%d, n_sectors=%d\n", spi_chip_info->id, spi_chip_info->jedec_id, spi_chip_info->sector_size, spi_chip_info->n_sectors); //添加jedec id的打印。
printf("Abort: image size larger than %d!\n\n", (spi_chip_info->sector_size * spi_chip_info->n_sectors) -
(CFG_BOOTLOADER_SIZE + CFG_CONFIG_SIZE + CFG_FACTORY_SIZE));
udelay(10*1000*1000);
return -1;
}
添加代码后,重新启动uboot,烧写固件,显示错误如下,可以看到jedec为0x40178331
,这跟linux下读取的204017也是同一个,只不过uboot中,分开了ID 与 JEDEC。
NetBootFileXferSize= 00640004
id=0x20, jedec=0x40178331, sector_size=65536, n_sectors=64
Abort: image size larger than 3866624!
查看同文件下代码,是通过spi_chip_info
来判断uboot是否支持该flash
struct chip_info {
char *name;
u8 id;
u32 jedec_id;
unsigned long sector_size;
unsigned int n_sectors;
char addr4b;
};
struct chip_info *spi_chip_info = NULL;
static struct chip_info chips_data [] = {
/* REVISIT: fill in JEDEC ids, for parts that have them */
{ "AT25DF321", 0x1f, 0x47000000, 64 * 1024, 64, 0 },
{ "AT26DF161", 0x1f, 0x46000000, 64 * 1024, 32, 0 },
{ "FL016AIF", 0x01, 0x02140000, 64 * 1024, 32, 0 },
{ "FL064AIF", 0x01, 0x02160000, 64 * 1024, 128, 0 },
{ "MX25L1605D", 0xc2, 0x2015c220, 64 * 1024, 32, 0 },
{ "MX25L3205D", 0xc2, 0x2016c220, 64 * 1024, 64, 0 },
{ "MX25L6405D", 0xc2, 0x2017c220, 64 * 1024, 128, 0 },
{ "MX25L12805D", 0xc2, 0x2018c220, 64 * 1024, 256, 0 },
#ifndef NO_4B_ADDRESS_SUPPORT
{ "MX25L25635E", 0xc2, 0x2019c220, 64 * 1024, 512, 1 },
{ "S25FL256S", 0x01, 0x02194D01, 64 * 1024, 512, 1 },
{ "N25Q256A", 0x20, 0xba191000, 64 * 1024, 512, 1 },
{ "MT25QL512AB", 0x20, 0xba201044, 64 * 1024, 1024, 1 },
#endif
{ "S25FL128P", 0x01, 0x20180301, 64 * 1024, 256, 0 },
{ "S25FL129P", 0x01, 0x20184D01, 64 * 1024, 256, 0 },
{ "S25FL164K", 0x01, 0x40170140, 64 * 1024, 128, 0 },
{ "S25FL132K", 0x01, 0x40160140, 64 * 1024, 64, 0 },
{ "S25FL032P", 0x01, 0x02154D00, 64 * 1024, 64, 0 },
{ "S25FL064P", 0x01, 0x02164D00, 64 * 1024, 128, 0 },
{ "S25FL116K", 0x01, 0x40150140, 64 * 1024, 32, 0 },
{ "F25L64QA", 0x8c, 0x41170000, 64 * 1024, 128, 0 }, //ESMT
{ "F25L32QA", 0x8c, 0x41168c41, 64 * 1024, 64, 0 }, //ESMT
{ "EN25F16", 0x1c, 0x31151c31, 64 * 1024, 32, 0 },
{ "EN25Q32B", 0x1c, 0x30161c30, 64 * 1024, 64, 0 },
{ "EN25F32", 0x1c, 0x31161c31, 64 * 1024, 64, 0 },
{ "EN25F64", 0x1c, 0x20171c20, 64 * 1024, 128, 0 }, //EN25P64
{ "EN25Q64", 0x1c, 0x30171c30, 64 * 1024, 128, 0 },
{ "W25Q32BV", 0xef, 0x40160000, 64 * 1024, 64, 0 }, //S25FL032K //W25Q32FV
{ "W25Q64BV", 0xef, 0x40170000, 64 * 1024, 128, 0 }, //S25FL064K //W25Q64FV
{ "W25Q128BV", 0xef, 0x40180000, 64 * 1024, 256, 0 }, //W25Q128FV
{ "W25Q256FV", 0xef, 0x40190000, 64 * 1024, 512, 1 },
{ "N25Q032A13ESE40F", 0x20, 0xba161000, 64 * 1024, 64, 0 }
.............................. //省略部分代码
}
同样添加JEDEC ID
{ "newboard", 0x1c, 0x40178331, 64 * 1024, 128, 0 }, //其他参数也是参考之前正确的flash参数,也可以看flash的参数pdf文档。
重新编译固件后,启动uboot,出现如下log
flash manufacture id: 20, device id 40 17
find flash: newboard
重新烧写固件也不提示固件超大的问题,即正常了。