首先确认硬件是否正常,flash有无虚焊

开发板使用一个已经可以正常启动的 uboot 镜像,直接进入 uboot 的命令行,输入 sf probe

这时 uboot 会去读取 flash 的 id ,如果 uboot 中没有对应 flahs 的 id 号,就会报以下的错误

1
SF: unrecognized JEDEC id bytes: 0b, 40, 18 // 0b, 40, 18 是 flash 的 id

移植一个新的 flash 需要做的事情很简单,将 flash 对应的 id 和一些特性加入到 uboot 中就可以了

本人需要移植的 flash 为 xt25f128b,经过查询数据手册,发现和 winbond w25qxxx 系列的 flash 兼容性很高,硬件特性、指令基本一样

于是觉得基于 w25qxxx 系列进行移植

定位问题

在代码中搜索报错的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
{
...
tmp = spi_flash_cmd(flash->spi, CMD_READ_ID, id, SPI_FLASH_MAX_ID_LEN);
...

info = spi_flash_ids;
for (; info->name != NULL; info++) {
if (info->id_len) {
if (!memcmp(info->id, id, info->id_len))
return info;
}
}

printf("SF: unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
id[0], id[1], id[2]);
return ERR_PTR(-ENODEV);
}

从代码中可以看出,这段程序试图在 spi_flash_ids 这个数组中查找是否有和板载 flash 对应的 id

然后是找到这个数组

1
2
3
4
5
const struct spi_flash_info spi_flash_ids[] = {
...
{"w25q128fw", INFO(0xef6018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP | SECT_4K) },
...
};

其中使用到了一个 INFO 的宏定义,该宏定义的声明如下,通过声明我们就可以知道 spi_flash_ids 中定义着 flash 相关的特性

1
2
3
4
5
6
7
8
9
/* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
.id = { \
...
.id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))), \
.sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \
.page_size = 256, \
.flags = (_flags),

由于需要移植的 flash 芯片特性和 w25qxxx 系列的 flash 相似,所以可以直接复制过来,修改后如下

1
2
3
4
5
6
const struct spi_flash_info spi_flash_ids[] = {
...
{"w25q128fw", INFO(0xef6018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP | SECT_4K) },
{"xt25f128b", INFO(0x0b4018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP | SECT_4K) },
...
};

修改设备树中的 flash 相关的声明,添加上新增加的 flash 型号

1
2
3
4
5
6
7
8
&spi0 {
...
flash@0 {
...
compatible = "winbond,xt25f128b", "jedec,spi-nor";
...
};
};

上电测试,输出以下信息代表 nor-flash 移植成功

1
2
=> sf probe
SF: Detected xt25f128b with page size 256 Bytes, erase size 4 KiB, total 16 MiB