自制v3s板,串口2作为调试口,板载w25q128作为存储。
下载uboot2022,参考坑网教程修改uboot的设备树,添加了uart2部分,现在可以用uart2作为调试口了。
参照licheepi的uboot2017的spi版的设备树和defconfig文件作了修改。用sunxi-fel命令烧录uboot到spi flash里有,可以启动SPL,但是进入uboot后检测不到spi flash,然后就不停重启。
进入命令行模式后,输入sf probe 0,也是报错。
U-Boot SPL 2022.07-rc4 (Jun 10 2022 - 15:27:40 +0800)
DRAM: 64 MiB
Trying to boot from sunxi SPI
U-Boot 2022.07-rc4 (Jun 10 2022 - 15:27:40 +0800) Allwinner Technology
CPU: Allwinner V3s (SUN8I 1681)
Model: Lichee Pi Zero
DRAM: 64 MiB
Core: 34 devices, 15 uclasses, devicetree: separate
WDT: Not starting watchdog@1c20ca0
MMC: mmc@1c0f000: 0
Loading Environment from SPIFlash...
sun4i_spi spi@1c68000: Invalid chip select 0:0 (err=-19)
*** Warning - spi_flash_probe_bus_cs() failed, using default environment
Loading Environment from FAT... Card did not respond to voltage select! : -110
** Bad device specification mmc 0 **
In: serial@1c28800
Out: serial@1c28800
Err: serial@1c28800
Net: No ethernet found.
Hit any key to stop autoboot: 0
=> sf probe 0
bus:0, cs:0, speed:1000000, mode:0
sun4i_spi spi@1c68000: Invalid chip select 0:0 (err=-19)
=>
搜索Invalid chip select这句,在uboot/drivers/spi-uclass.c里的 int spi_get_bus_and_cs( )函数里找到了,错误19代表是无器件。
int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp)
{
struct dm_spi_ops *ops;
struct spi_cs_info info;
struct udevice *dev;
int ret;
/*
* Ask the driver. For the moment we don't have CS info.
* When we do we could provide the driver with a helper function
* to figure out what chip selects are valid, or just handle the
* request.
*/
ops = spi_get_ops(bus);
if (ops->cs_info) {
ret = ops->cs_info(bus, cs, &info);
} else {
/*
* We could assume there is at least one valid chip select.
* The driver didn't care enough to tell us.
*/
ret = 0;
}
if (ret) {
dev_err(bus, "Invalid cs %d (err=%d)\n", cs, ret);
return ret;
}
for (device_find_first_child(bus, &dev); dev;
device_find_next_child(&dev)) {
struct dm_spi_slave_plat *plat;
plat = dev_get_parent_plat(dev);
dev_dbg(bus, "%s: plat=%p, cs=%d\n", __func__, plat, plat->cs);
printf("%s: plat=%p, plat->cs=%d, cs=%d\n", __func__, plat, plat->cs, cs);
if (plat->cs == cs) {
*devp = dev;
return 0;
}
}
return -ENODEV;
}
该函数中最后部分的for循环里,device_find_first_child(bus, &dev) 没有得到dev的值,所以一次也没有循环。
for (device_find_first_child(bus, &dev); dev;
device_find_next_child(&dev)) {
struct dm_spi_slave_plat *plat;
plat = dev_get_parent_plat(dev);
dev_dbg(bus, "%s: plat=%p, cs=%d\n", __func__, plat, plat->cs);
printf("%s: plat=%p, plat->cs=%d, cs=%d\n", __func__, plat, plat->cs, cs);
if (plat->cs == cs) {
*devp = dev;
return 0;
}
}
device_find_first_child( )函数里判断&parent->child_head是空的,但为什么会是空的呢?也尝试将parent这个指针打印出来,是:
int device_find_first_child(const struct udevice *parent, struct udevice **devp)
{
printf("parent:%d\r\n", parent);
printf("parent name:%s\r\n", &parent->name);
printf("parent drive name:%s\r\n", &parent->driver->name);
if (list_empty(&parent->child_head)) {
printf("dev是空的\r\n");
*devp = NULL;
} else {
printf("dev不是空的\r\n");
*devp = list_first_entry(&parent->child_head, struct udevice,
sibling_node);
}
return 0;
}
=> sf probe 0
parent:1138158968
parent name:CC
parent drive name:vCc
dev是空的
parent:1138158972
parent name:CC
parent drive name:vCc
dev是空的
sun4i_spi spi@1c68000: Invalid chip select 0:0 (err=-19)
从parent->name及parent->drive->name都是乱码来看,有可能是parent这个指针不正确。或者,spi这个设备没创建好?
最近编辑记录 Gentlepig (2022-06-10 16:39:05)
离线
(V3s/V3x/S3/S3L/R11通吃)小智V3x开发板smallwitpi lite u-boot/linux/buildroot测试
https://whycan.com/t_7248.html
不建议折腾uboot,他只是一个引导程序,浪费的时间不值得。
离线
感谢,正在下小智的uboot,打算对比下。
另,parent传过来的值是正确的,我打印parent->name及parent->driver->name时,不该在前边加&。
int device_find_first_child(const struct udevice *parent, struct udevice **devp)
{
printf("parent:%d\r\n", parent);
printf("parent name:%s\r\n", parent->name);
printf("parent drive name:%s\r\n", parent->driver->name);
if (list_empty(&parent->child_head)) {
printf("dev是空的\r\n");
*devp = NULL;
} else {
printf("dev不是空的\r\n");
*devp = list_first_entry(&parent->child_head, struct udevice,
sibling_node);
}
return 0;
}
=> sf probe 0
parent:1138158968
parent name:spi@1c68000
parent drive name:sun4i_spi
dev是空的
parent:1138158968
parent name:spi@1c68000
parent drive name:sun4i_spi
dev是空的
sun4i_spi spi@1c68000: Invalid chip select 0:0 (err=-19)
那么现在问题是为什么list_empty(&parent->child_head)这个函数返回0了。
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
离线
uboot下SPI flash ID添加了没有 记得要搞这个不然匹配不上
离线
离线
默认有winbond的flash的。
我焊接的是w25q128,用sunxi-fel spiflash-info 查看到的是EF40。对得上。
#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */
/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
{ INFO("w25p80", 0xef2014, 0x0, 64 * 1024, 16, 0) },
{ INFO("w25p16", 0xef2015, 0x0, 64 * 1024, 32, 0) },
{ INFO("w25p32", 0xef2016, 0x0, 64 * 1024, 64, 0) },
{ INFO("w25x05", 0xef3010, 0, 64 * 1024, 1, SECT_4K) },
{ INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K) },
{ INFO("w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K) },
{
INFO("w25q16dw", 0xef6015, 0, 64 * 1024, 32,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{ INFO("w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K) },
{ INFO("w25q20cl", 0xef4012, 0, 64 * 1024, 4, SECT_4K) },
{ INFO("w25q20bw", 0xef5012, 0, 64 * 1024, 4, SECT_4K) },
{ INFO("w25q20ew", 0xef6012, 0, 64 * 1024, 4, SECT_4K) },
{ INFO("w25q32", 0xef4016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{
INFO("w25q32dw", 0xef6016, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
INFO("w25q32jv", 0xef7016, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
INFO("w25q32jwm", 0xef8016, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{ INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{
INFO("w25q64dw", 0xef6017, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
INFO("w25q64jv", 0xef7017, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
INFO("w25q128fw", 0xef6018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
INFO("w25q128jv", 0xef7018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
INFO("w25q128jw", 0xef8018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
INFO("w25q256fw", 0xef6019, 0, 64 * 1024, 512,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
INFO("w25q256jw", 0xef7019, 0, 64 * 1024, 512,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
INFO("w25q01jv", 0xef4021, 0, 64 * 1024, 2048,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{ INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("w25q16cl", 0xef4015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("w25q64cv", 0xef4017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("w25q128", 0xef4018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{ INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("w25m512jw", 0xef6119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("w25m512jv", 0xef7119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
#endif
#ifdef CONFIG_SPI_FLASH_XMC
/* XMC (Wuhan Xinxin Semiconductor Manufacturing Corp.) */
{ INFO("XM25QH64A", 0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("XM25QH64C", 0x204017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("XM25QH128A", 0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
#endif
#ifdef CONFIG_SPI_FLASH_XTX
/* XTX Technology (Shenzhen) Limited */
{ INFO("xt25f128b", 0x0b4018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
#endif
{ },
离线
下载了小智的uboot2021.07,编译后进入uboot里输入sf probe 0,可以检测到设备。我一会再去比对下两个uboot。
SF: Detected w25q128 with page size 256 Bytes, erase size 4 KiB, total 16 MiB
=>
离线
在小智uboot2021.07里的device_find_first_child( )函数里加上同样的打印函数,结果:
=> sf probe
parent:1138178232
parent name:spi@1c68000
parent drive name:sun4i_spi
dev不是空的
parent:1138178232
parent name:spi@1c68000
parent drive name:sun4i_spi
dev不是空的
SF: Detected w25q128 with page size 256 Bytes, erase sizeB
离线
晕死了,尝试打印出来parent->child_head,parent->child_head.next,parent->child_head.prev。
int device_find_first_child(const struct udevice *parent, struct udevice **devp)
{
printf("parent:%d\r\n", parent);
printf("parent name:%s\r\n", parent->name);
printf("parent drive name:%s\r\n", parent->driver->name);
printf("parent child_head:%X\r\n", parent->child_head);
printf("parent child_head next:%X\r\n", parent->child_head.next);
printf("parent child_head prev:%X\r\n", parent->child_head.prev);
if (list_empty(&parent->child_head)) {
printf("dev是空的\r\n");
*devp = NULL;
} else {
printf("dev不是空的\r\n");
*devp = list_first_entry(&parent->child_head, struct udevice,
sibling_node);
}
return 0;
}
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
struct list_head {
struct list_head *next, *prev;
};
小智uboot2021.07:
starting USB...
No working controllers found
No ethernet found.
No ethernet found.
=> sf probe
parent:1138178232
parent name:spi@1c68000
parent drive name:sun4i_spi
parent child_head:43D738EC
parent child_head next:43D738EC
parent child_head prev:43D738EC
dev是空的
parent:1138178232
parent name:spi@1c68000
parent drive name:sun4i_spi
parent child_head:43D738EC
parent child_head next:43D738EC
parent child_head prev:43D738EC
dev是空的
SF: Detected w25q128 with page size 256 Bytes, erase sizeB
=> sf probe 0
parent:1138178232
parent name:spi@1c68000
parent drive name:sun4i_spi
parent child_head:43D7496C
parent child_head next:43D7496C
parent child_head prev:43D7496C
dev不是空的
parent:1138178232
parent name:spi@1c68000
parent drive name:sun4i_spi
parent child_head:43D7496C
parent child_head next:43D7496C
parent child_head prev:43D7496C
dev不是空的
SF: Detected w25q128 with page size 256 Bytes, erase sizeB
=> sf probe
parent:1138178232
parent name:spi@1c68000
parent drive name:sun4i_spi
parent child_head:43D7496C
parent child_head next:43D7496C
parent child_head prev:43D7496C
dev不是空的
parent:1138178232
parent name:spi@1c68000
parent drive name:sun4i_spi
parent child_head:43D7496C
parent child_head next:43D7496C
parent child_head prev:43D7496C
dev不是空的
SF: Detected w25q128 with page size 256 Bytes, erase sizeB
=>
我编译的uboot2022.07:
Net: No ethernet found.
Hit any key to stop autoboot: 0
=> sf probe
parent:1138158968
parent name:spi@1c68000
parent drive name:sun4i_spi
parent child_head:43D6EDAC
parent child_head next:43D6EDAC
parent child_head prev:43D6EDAC
dev是空的
parent:1138158968
parent name:spi@1c68000
parent drive name:sun4i_spi
parent child_head:43D6EDAC
parent child_head next:43D6EDAC
parent child_head prev:43D6EDAC
dev是空的
sun4i_spi spi@1c68000: Invalid chip select 0:0 (err=-19)
=> sf probe 0
parent:1138158968
parent name:spi@1c68000
parent drive name:sun4i_spi
parent child_head:43D6EDAC
parent child_head next:43D6EDAC
parent child_head prev:43D6EDAC
dev是空的
parent:1138158968
parent name:spi@1c68000
parent drive name:sun4i_spi
parent child_head:43D6EDAC
parent child_head next:43D6EDAC
parent child_head prev:43D6EDAC
dev是空的
sun4i_spi spi@1c68000: Invalid chip select 0:0 (err=-19)
=>
几个疑问。
1是不是我打印parent->child_head.next方式不对?next是个指针变量。parent是指针,parent->child_head就是结构体对象了吧,其里面的next指针变量,应该是用child_head.next这种方式引用吧?
2对于小智uboot,我两次sf probe 0,打印出来的parent->child_head竟然不一样。
3对于小智uboot,两次打印出来的parent->child_head都和parent->child_head.next一样,但为何前一次是“dev是空的”,后边就是"dev不是空的"了?
最近编辑记录 Gentlepig (2022-06-11 17:05:11)
离线
我上个回复里是搞错了。
list_empty( )函数里传入的是parent->child_head的地址,所以应该是比较&parent->child_head和parent->child_head.next。
实际上确实是一样的。
继续查,发现uboot2021.07里面,第一次sf probe 0时,是打印"dev是空的",这句话,再次打印才是"dev不是空的"。那么就是第一次执行sf probe后是有其他操作的。
再查,在spi_get_bus_and_cs( )这个函数里,是判断ret = ENODEV错误时,会自动创建个设备的。有如下注释:
/*
* If there is no such device, create one automatically. This means
* that we don't need a device tree node or platform data for the
* SPI flash chip - we will bind to the correct driver.
*/
而uboot2022.07里是直接丢出个错误的。
离线
有个_spi_get_bus_and_cs( )函数是和uboot2021.07里的spi_get_bus_and_cs( )一样,调用它的是spi_flash_probe( )函数,可惜声明是要废弃的。
/*
* TODO(sjg@chromium.org): This is an old-style function. We should remove
* it when all SPI flash drivers use dm
*/
struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs,
unsigned int max_hz, unsigned int spi_mode)
{
struct spi_slave *slave;
struct udevice *bus;
char *str;
#if defined(CONFIG_SPL_BUILD) && CONFIG_IS_ENABLED(USE_TINY_PRINTF)
str = "spi_flash";
#else
char name[30];
snprintf(name, sizeof(name), "spi_flash@%d:%d", busnum, cs);
str = strdup(name);
#endif
if (_spi_get_bus_and_cs(busnum, cs, max_hz, spi_mode,
"jedec_spi_nor", str, &bus, &slave))
return NULL;
return dev_get_uclass_priv(slave->dev);
}
调用spi_get_bus_and_cs( )函数的是:
int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
struct udevice **devp)
{
struct spi_slave *slave;
struct udevice *bus;
int ret;
ret = spi_get_bus_and_cs(busnum, cs, &bus, &slave);
if (ret)
return ret;
*devp = slave->dev;
return 0;
}
再往上查,在do_spi_flash_probe( )函数里有:
...
if (use_dt) {
spi_flash_probe_bus_cs(bus, cs, &new);
flash = dev_get_uclass_priv(new);
} else {
flash = spi_flash_probe(bus, cs, speed, mode);
}
...
看样子,不用use_dt,就能使用旧的驱动函数。
最近编辑记录 Gentlepig (2022-06-13 16:11:17)
离线
使用sf probe 0会使use_dt = 1;使用sf probe 0 100000,就是多个参数,speed或mode,就会使use_dt = 0。
那么我就尝试在uboot命令行里输入sf probe 0 100000,结果还是报错,报-2错误,
#define ENOENT 2 /* No such file or directory */
找到报错位置,是在device.c的device_probe( )函数里。
...
if (drv->probe) {
ret = drv->probe(dev);
printf("------------drv->probe result:%d\r\n", ret);
if (ret)
goto fail;
}
...
这回不知道该怎么往下找了,既然drv-probe存在,但调用时却报错,我也不知道这个drv-probe指向了哪个函数。
离线
在sun8i-v3s-licheepi-zero.dts里的spi上添加了这部分:
...
&spi0 {
status = "okay";
spidev@0x00{
compatible = "spidev";
spi-max-frequency = <10000000>;
reg = <0>;
};
};
...
编译后烧录到v3s上,进入uboot命令模式后,输入sf probe 0 10000,可以识别到spiflash。从打印的信息可以看到,是判断了bus上没有dev,然后新建了个dev。
此时再用sf probe 0命令,也可以检测到spi flash。
但是,如果v3s启动进入uboot命令模式后,先输入sf probe 0,则仍识别不了spi flash,和以前的报错一样。
那么,如何在spi总线上预设spi设备呢?我感觉我在设备树里上边的修改,就是在spi0总线上添加了个spidev啊,但是为何没起作用?
-------------------------------------------------
搜了spi-uclass.c这个文件,只有_spi_get_bus_and_cs( )这个函数调用了device_bind_driver( )。
最近编辑记录 Gentlepig (2022-06-14 15:12:36)
离线
暂时总结下。
确实如1楼朋友所说,浪费时间不值得。目前改用uboot-v2022.04版本,可以认出spi flash。
在编译uboot-2022.07时,有个SPL_FLASH_SUNXI打不开,是在kconfig里定义的,仔细看了,依赖条件里没有V3S,自己加上去才行。
离线
看来兄台花了很多精力。我也折腾了好几天。在主线u-boot上搞不定spi flash启动。
在这里受到启发,用v2022.04可以。要改一下Kconfig(使能SPL_SPI_SUNXI)与dts(使能spi)
v3s_spi_flash.zip
离线