u-boot2020.04移植(eMMC/SD调试)

前奏

随着u-boot版本的变迁,u-boot的功能也越来越多越来越强大,在较新的u-boot中已经支持很多不同类型的文件系统,告别了以前需要移植者自己手动规划eMMC/SD等镜像存储介质的分区信息(并非真正的磁盘分区,只是一个标号而已),可直接使用相关的命令就可以读取出各种文件系统类型的存储介质中的文件,使烧录、更新、启动等操作变得更加方便,所以在u-boot中支持eMMC/SD卡是很有必要的。

流程

在我现在用的u-boot版本2020.04中mmc相关的驱动默认使用了驱动模型,为了不破坏原有的结构,所以也决定使用驱动模型进行移植调试。通过阅读源码发现mmc相关的driver与uclass_driver都已经有了,唯一缺的就是driver_info(这里需要了解dm驱动模型相关的知识),驱动模型建议使用设备树传递driver_info,但不幸的是三星(什么东西都藏着掖着)并没有提供我这块板子mmc相关的设备树参考,便只好再次阅读源码,下面跟着源码重点分析一下,该怎么从源码中提取设备树必须提供的属性。
uclass_driver:

/*drivers\mmc\mmc-uclass.c*/

UCLASS_DRIVER(mmc) = {
	.id		= UCLASS_MMC,
	.name		= "mmc",
	.flags		= DM_UC_FLAG_SEQ_ALIAS,
	.per_device_auto_alloc_size = sizeof(struct mmc_uclass_priv),
};

driver:

/*drivers\mmc\s5p_sdhci.c*/

U_BOOT_DRIVER(s5p_sdhci_drv) = {
	.name		= "s5p_sdhci",
	.id		= UCLASS_MMC,
	.of_match	= s5p_sdhci_ids,
	.bind		= s5p_sdhci_bind,
	.ops		= &sdhci_ops,
	.probe		= s5p_sdhci_probe,
	.priv_auto_alloc_size = sizeof(struct sdhci_host),
	.platdata_auto_alloc_size = sizeof(struct s5p_sdhci_plat),
};

本文略过dm驱动模型相关的内容

驱动匹配

在u-boot启动过程中会有一个加载并驱动匹配的过程,当驱动匹配的时候会执行对应的probe函数,这个probe函数就是本次的重点,这里对应s5p_sdhci_probe函数。
那怎么才能让驱动知道该和谁进行匹配呢?
这里就要看其中的of_match参数了,下面是s5p对应的of_match参数:

static const struct udevice_id s5p_sdhci_ids[] = {
	{ .compatible = "samsung,exynos4412-sdhci"},
	{ }
};

从这里我们知道首先得定义一个compatible属性,并指定其值为samsung,exynos4412-sdhci,如下:

/*如果不懂,可先了解一下设备树相关的知识*/
sdhci0:sdhci@eb000000 {
        compatible = "samsung,exynos4412-sdhci";
    };  

这步完了后,驱动和设备就能匹配了,但是我们还需要其它参数,接着往下看。

分析需要的属性

我们看一下s5p_sdhci_probe函数:

static int s5p_sdhci_probe(struct udevice *dev)
{
	/*
		省略
	*/

	/*这个函数就是从设备树解析我们想要的数据*/
	ret = sdhci_get_config(gd->fdt_blob, dev_of_offset(dev), host);
	if (ret)
		return ret;
	
	/*
		省略
	*/
	/*这个函数也会从设备树获取相应的数据*/
	ret = mmc_of_parse(dev, &plat->cfg);
	if (ret)
		return ret;
	
	/*
		省略
	*/
}

从源码知道了sdhci_get_config函数和mmc_of_parse函数会从设备树获取相关的数据,看一下到底哪些数据是必须的:

static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host)
{
	int bus_width, dev_id;
	unsigned int base;

	/* Get device id */
	dev_id = pinmux_decode_periph_id(blob, node);
	if (dev_id < PERIPH_ID_SDMMC0 || dev_id > PERIPH_ID_SDMMC3) {
		debug("MMC: Can't get device id\n");
		return -EINVAL;
	}
	host->index = dev_id - PERIPH_ID_SDMMC0;

	/* Get bus width */
	bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0);
	if (bus_width <= 0) {
		debug("MMC: Can't get bus-width\n");
		return -EINVAL;
	}
	host->bus_width = bus_width;

	/* Get the base address from the device node */
	base = fdtdec_get_addr(blob, node, "reg");
	if (!base) {
		debug("MMC: Can't get base address\n");
		return -EINVAL;
	}
	host->ioaddr = (void *)base;

	gpio_request_by_name_nodev(offset_to_ofnode(node), "pwr-gpios", 0,
				   &host->pwr_gpio, GPIOD_IS_OUT);
	gpio_request_by_name_nodev(offset_to_ofnode(node), "cd-gpios", 0,
				   &host->cd_gpio, GPIOD_IS_IN);

	return 0;
}

# u-boot-2020.04\drivers\mmc\mmc-uclass.c
int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg)
{
	int val;

	/* 也有个总线宽度,但是增加了也没有效果 */
	val = dev_read_u32_default(dev, "bus-width", 1);
	
	/*
		省略
	*/

	/* 这里的很重要,从这里可以看出,卡检测支持三种方式,一种是不可热插拔的,一种是高电平有效,一种是轮询检测(可以看到没有低电平有效) */
	if (dev_read_bool(dev, "non-removable")) {
		cfg->host_caps |= MMC_CAP_NONREMOVABLE;
	} else {
		if (dev_read_bool(dev, "cd-inverted"))
			cfg->host_caps |= MMC_CAP_CD_ACTIVE_HIGH;
		if (dev_read_bool(dev, "broken-cd"))
			cfg->host_caps |= MMC_CAP_NEEDS_POLL;
	}

	if (dev_read_bool(dev, "no-1-8-v")) {
		cfg->host_caps &= ~(UHS_CAPS | MMC_MODE_HS200 |
				    MMC_MODE_HS400 | MMC_MODE_HS400_ES);
	}

	return 0;
}

经过分析,我们需要的参数如下:

  • 设备id
  • 总线宽度
  • 寄存器基地址
  • 电源引脚(可选)
  • 卡检测引脚(可选)或卡检测方式

所以可以推导出设备树如下:

sdhci0:sdhci@eb000000 {
        compatible = "samsung,exynos4412-sdhci";
        /*根据芯片手册得知*/
        reg = <0xeb000000 0x100000>;
        /*根据硬件原理图得知*/
        samsung,bus-width = <8>;
        /*设备id定义于arch/arm/mach-s5pc1xx/include/mach/periph.h*/
        id = <75>;
        /*通道0是eMMC不可热插拔*/
        non-removable;
        /*使能该设备*/
        status = "okay";
    };

	sdhci2:sdhci@eb200000 {
        compatible = "samsung,exynos4412-sdhci";
        /*根据芯片手册得知*/
        reg = <0xeb200000 0x100000>;
        /*根据硬件原理图得知*/
        samsung,bus-width = <8>;
        /*设备id定义于arch/arm/mach-s5pc1xx/include/mach/periph.h*/
        id = <77>;
        /*通道2是SD卡,硬件上SD卡检测是低电平有效,但看u-boot源码,貌似根本就不支持低电平有效,只能采用轮询的方式*/
        broken-cd;
        /*使能该设备*/
        status = "okay";
    };

调试

经过上面的步骤,driver_info也就准备好了,但经过测试,启动u-boot后还是probe失败,调了好久没办法,只能开启调试信息看输出log,最后定位到读取id失败,明明设置了id为什么还是失败。看一下id读取函数:

/*drivers\mmc\s5p_sdhci.c*/

int pinmux_decode_periph_id(const void *blob, int node)
{
	return 0;
}

找到问题了,原来是id读取函数是空的,之前也没有仔细把每个函数都看一遍,导致在这里卡了很久,修改成下面的代码,从设备树中获取id即可:

/*drivers\mmc\s5p_sdhci.c*/

int pinmux_decode_periph_id(const void *blob, int node)
{
	return fdtdec_get_int(blob, node, "id", 0);
}

补充

另外再补充一个关于SD卡的问题,当你发现SD卡探测成功,但无论如何都检测不到卡的时候,可以试下以下几种方法:

  • 通过menuconfig将CONFIG_MMC_BROKEN_CD配置宏打开,其作用是使用轮询的方式来检测卡,有时候检测不到卡可能是因为卡检测引脚没有被正确的配置,使用轮询方式检测就可以了:
Device Drivers  --->
	MMC Host controller Support  --->
		[*] Poll for broken card detection case
  • 在设备树里面配置卡检测方式为broken-cd;和上面的配置宏方式一样的效果
  • 检查你的硬件sd卡检测是否是高电平有效,因为我的硬件上是低电平有效,结果看源码,貌似根本不支持低电平检测
# u-boot-2020.04\include\mmc.h

/* 只有以下三种检测方式 */
#define MMC_CAP_NONREMOVABLE	BIT(14)
#define MMC_CAP_NEEDS_POLL	BIT(15)
#define MMC_CAP_CD_ACTIVE_HIGH  BIT(16)

结果

修改后再次测试已经能够正确的读取到eMMC并且各种操作也没有问题。


欢迎扫码关注我的微信公众号
漫长当下

Rockchip RK3566是一款由Rockchip推出的高性能应用处理器,其集成了四核ARM Cortex-A55 CPU和ARM Mali-G52 GPU。在移植U-Boot 2023.04时,我们需要考虑以下几个方面的工作: 1. 了解RK3566芯片的硬件架构和技术规格,包括处理器核心、内存控制器、外设接口等。这将有助于理解U-Boot如何与硬件交互,并进行相应的配置。 2. 下载并准备U-Boot 2023.04的源代码。在Rockchip官方网站或开源社区中可以找到最新的U-Boot代码。将其下载并解压到开发机上。 3. 设置交叉编译环境。因为U-Boot是一个跨平台的项目,所以需要配置适合RK3566的交叉编译器,确保能够正确编译U-Boot代码。 4. 配置U-Boot。根据RK3566的硬件架构和技术规格,需要进行相应的配置,包括处理器、内存、外设等设置。这些设置在U-Boot的配置文件中进行,可以根据需求进行修改。 5. 编译U-Boot。在配置好U-Boot后,使用交叉编译器编译U-Boot代码。编译完成后,将生成的U-Boot二进制文件烧录到RK3566的启动设备上,如eMMCSD卡。 6. 测试U-Boot。将准备好的启动设备插入RK3566开发板中,根据开发板的启动方式,进入U-Boot命令行界面。在命令行界面中可以进行各种操作和调试,如加载内核、启动操作系统等。 7. 调试和优化。在移植和测试U-Boot过程中,可能会出现一些问题和不稳定的情况。需要通过调试和优化来解决这些问题,确保U-Boot的正常运行和稳定性。 总之,移植U-Boot 2023.04到Rockchip RK3566需要了解芯片的硬件架构和技术规格,配置和编译U-Boot代码,进行测试和调试。这样可以确保U-Boot能够与RK3566正常交互,并为后续的操作系统加载和启动提供基础支持。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值