Uboot下SPI FLASH的添加(SPI 控制器采用软件模拟的方式)

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
  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值