1.既然是软件模拟控制器,则我们首先关注控制器的设备和驱动
先看设备树
u-boot/arch/arm/dts/sun8i-h3-nanopi.dtsi
spi0{
compatible = "spi-gpio";
pinctrl-names = "default";
pinctrl-0 = <&spi0_in_pins>, <&spi0_out_pins>;
status = "okay";
spi-delay-us = <10>;
gpio-sck = <&pio 2 2 GPIO_ACTIVE_HIGH>;
gpio-mosi = <&pio 2 0 GPIO_ACTIVE_HIGH>;
gpio-miso = <&pio 2 1 GPIO_ACTIVE_HIGH>;
cs-gpios = <&pio 2 3 GPIO_ACTIVE_HIGH>;
num-chipselects = <1>;
#address-cells = <1>;
#size-cells = <0>;
firmware_storage_spi: flash@0 {
reg = <0>;
compatible = "spi-flash";
spi-max-frequency = <10000>;
};
};
...
spi0_in_pins: spi0_in_pins@0 {
allwinner,pins = "PC2";
allwinner,function = "gpio_in";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
spi0_out_pins: spi0_out_pins@0 {
allwinner,pins = "PC0", "PC1", "PC3";
allwinner,function = "gpio_out";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
u-boot/drivers/spi/soft_spi.c
static const struct udevice_id soft_spi_ids[] = {
{ .compatible = "spi-gpio" },
{ }
};
U_BOOT_DRIVER(soft_spi) = {
.name = "soft_spi",
.id = UCLASS_SPI,
.of_match = soft_spi_ids,
.ops = &soft_spi_ops,
.ofdata_to_platdata = soft_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct soft_spi_platdata),
.priv_auto_alloc_size = sizeof(struct soft_spi_priv),
.probe = soft_spi_probe,
};
soft_spi
是对应的控制器驱动,换句话说soft_spi_probe
这个probe函数是必须要CALL到的,但是要CALL到这个probe函数,有了设备和驱动是不够的,这个有点类似于Linux的设备模型,在Linux的设备模型中,有了设备和驱动,我们还需要关注总线设备和驱动是否在位,这里也是同样的道理,我们还必须确保UCLASS_SPI
的SPI类驱动已经注册到系统了。
2.确保UCLASS_SPI
的SPI类驱动加载到系统了
u-boot/drivers/spi/spi-uclass.c
UCLASS_DRIVER(spi) = {
.id = UCLASS_SPI,
.name = "spi",
.flags = DM_UC_FLAG_SEQ_ALIAS,
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
.post_bind = dm_scan_fdt_dev,
#endif
.post_probe = spi_post_probe,
.child_pre_probe = spi_child_pre_probe,
.per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.per_child_platdata_auto_alloc_size =
sizeof(struct dm_spi_slave_platdata),
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
.child_post_bind = spi_child_post_bind,
#endif
};
这里说明一下SPI的类驱动加载后,post_bind和post_probe会被调度到,在post_bind中会调用dm_scan_fdt_dev函数
dm_scan_fdt_dev
->dm_scan_fdt_node
->lists_bind_fdt
->device_bind_with_driver_data
->device_bind_common
//创建一个spi总线的设备udevice,设备名称是“spi0”,驱动名称是“spi-gpio”,它指向的类是UCLASS_SPI,之后调用“spi-gpio”驱动的bind函数指针(这个指针可以设置也可以不设置,看需要了)完成绑定
->uclass_bind_device(dev); //关联到uc->dev_head的链表
但是完成bind也不意味者“spi-gpio”的probe函数就会被调用,我们还需要激活spi控制器的驱动。
3.激活SPI控制器的驱动
u-boot/common/board_r.c
+ initr_soft_spi, //在系统初始化中激活SPI控制器
u-boot/drivers/spi/spi-uclass.c
在SPI类驱动中加入SPI控制器的激活函数
void spi_soft_init()
{
struct udevice *dev;
debug("Jon,%s,LINE=%d\n",__func__,__LINE__);
uclass_get_device(UCLASS_SPI, 0, &dev);
device_probe(dev);
}
这里说明下uclass_get_device就是获取SPI控制器的设备指针,当我们拿到设备指针后,调用device_probe则会获取到设备关联的驱动,进而触发驱动的probe,使得SPI的控制器完成激活。
这里uclass_get_device的参数index(当前为0),指的是取出SPI类驱动关联的dev_head链表的第一个设备,因为我这儿在spi0下只有一个控制器,所以直接传入0即可了。
OK,SPI控制器总算注册完成了,随后我们还需要注册SPI FLASH
4.注册SPI FLASH的驱动
drivers/mtd/spi/sf_probe.c
static const struct udevice_id spi_flash_std_ids[] = {
{ .compatible = "spi-flash" },
{ }
};
U_BOOT_DRIVER(spi_flash_std) = {
.name = "spi_flash_std",
.id = UCLASS_SPI_FLASH,
.of_match = spi_flash_std_ids,
.probe = spi_flash_std_probe,
.priv_auto_alloc_size = sizeof(struct spi_flash),
.ops = &spi_flash_std_ops,
};
同理,我们同样需要保证UCLASS_SPI_FLASH的类驱动被注册上去
drivers/mtd/spi/sf-uclass.c
UCLASS_DRIVER(spi_flash) = {
.id = UCLASS_SPI_FLASH,
.name = "spi_flash",
.post_bind = spi_flash_post_bind,
.per_device_auto_alloc_size = sizeof(struct spi_flash),
};
加入这颗FLASH的信息到FLASH列表中
u-boot/drivers/mtd/spi/spi_flash_ids.c
const struct spi_flash_info spi_flash_ids[] = {
...
{"gd25q128", INFO(0xc84018, 0x0, 64 * 1024, 256, SECT_4K) },
...
OK,万事具备,理论上此时SPI的FLASH已经可以使用了
5.验证SPI FLASH是否Porting 成功
CONFIG_CMD_SF=y
我们在config中加入如上配置,使得我们可以通过命令行的方式验证 flash
如果一切顺利会有如下打印(命令行执行:sf probe
)
No controllers found
Hit any key to stop autoboot: 0
=> sf probe
SF: Detected gd25q128 with page size 256 Bytes, erase size 4 KiB, total 16 MiB
我们还可以进一步验证下读写:
=> sf read 0x82000000 0x0 16
device 0 offset 0x0, size 0x16
SF: 22 bytes @ 0x0 Read: OK
=> md 0x82000000 16
82000000: ea000016 4e4f4765 3054422e e7aafa85 ....eGON.BT0....
82000010: 00006000 ffff5053 ffffffff ffffffff .`..SP..........
82000020: ffffffff fffffffb ffffffff ffffffff ................
82000030: ffffffff ffffffff ffffffff ffffffff ................
82000040: ffffffff ffffffff ffffffff ffffffff ................
82000050: ffffffff ffffffff
6.sf probe的流程如下:
do_spi_flash
do_spi_flash_probe
spi_find_bus_and_cs
uclass_find_device_by_seq //寻找spi总线设备(SPI控制器)
spi_find_chip_select//在SPI总线设备下找到FLASH设备
spi_flash_probe_bus_cs
spi_get_bus_and_cs
device_probe(dev); //调用SPI FLASH的驱动
spi_flash_std_probe
spi_flash_probe_slave
spi_flash_scan
spi_flash_read_id