Linux驱动开发笔记(五)——设备树(上)

内容详见《【正点原子】I.MX6U嵌入式Linux驱动开发指南》四十三章

开发板:imx6ull mini

虚拟机:VMware17

ubuntu:ubuntu20.04

一、什么是设备树

视频:第6.1讲 Linux设备树详解-什么是设备树?_哔哩哔哩_bilibili

对应《指南》43.1部分

        uboot启动时需要内核zImage 和 .dtb文件,其中dtb便是由设备树文件dts(Device Tree Source)转换而来。dts文件用树形结构来描述板级信息,即开发板上的设备信息,如CPU数量、 内存基地址、IIC接了哪些设备等等。

        bootcmd命令中,80800000就是zImage在RAM中的存放起始地址,83000000就是设备树在RAM中的存储地址。

tftp 80800000 zImage;tftp 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 - 83000000

        没有设备树以前,设备的板级信息等都在.c文件中进行配置,最后会被编码到内核里面,又臭又长。因此引入了设备树,用一个专用的文件格式.dts来描述板级信息,将这些玩意与linux分离。

        如果不同的板子有相同的信息,就可以将这部分提取出来作为一个通用文件.dtsi,其他的.dts文件直接引用就可以。

        一般.dts描述板级信息,.dtsi描述SOC级信息。

二、DTS文件

视频:第6.2讲 Linux设备树详解-DTS文件以及组织形式_哔哩哔哩_bilibili

对应《指南》43.2~3部分

2.1 编译为dtb

命令:

# 进入到Linux源码根目录下
make all     # 全部编译,包括zImage、.ko文件等等
make dtbs    # 将当前内核里所有.dts文件编译为.dtb
make XXX.dtb # 将指定的dts文件编译为dtb

示例: 

cd …………/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/
make dtbs
cd arch/arm/boot/dts/
ls *.dtb     # 此时应当可以看到一大堆的dts文件

 2.2 dts语法

        打开两个文件:linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/boot/dts下的imx6ull-alientek-emmc.dts和imx6ull.dtsi。

        打开两个文档:(4、参考资料)中的Devicetree SpecificationV0.2.pdf和Power_ePAPR_APPROVED_v1.12.pdf

/dts-v1/;

首先在imx6ull-alientek-emmc.dts开头可以看到:

/dts-v1/;

(解释在power_ePAPR_APPROVED_v1.12.pdf的96页:)
        The /dts-v1/; shall be present to identify the file as a version 1 DTS (dts files without this tag will be treated by dtc as being in the obsolete version 0, which uses a different format for integers in addition to other small but incompatible changes).
        /dts-v1/; 必须写上,将文件标识为版本1 DTS(没有此标签的DTS文件将被dtc视为过时的版本0,而旧格式在整数的表示方式等方面与版本1不兼容)

节点命名规则

(Power_ePAPR_APPROVED_v1.12.pdf 15页)

《指南》43.3.2部分

        节点名完整写法为:node-name@unit-address。其中node-name为设备名,unit-address一般是外设寄存器的起始地址,但也不一定,比如下面的例子。需要具体分析。

// imx6ull.dtsi 1096行
i2c4: i2c@021f8000 {    // i2c为name,021f8000为i2c4寄存器起始绝对地址
    …………
};

// imx6ull-alientek-emmc.dts 245行
&i2c1 {
	mag3110@0e {    
        // 这里mag3110并不是IMX6ULL的外设,而是一个IIC外设,
        // 因此0e也不是外设寄存器起始地址,而是一个IIC地址
        …………
	};
};

// imx6ull.dtsi 94行
intc: interrupt-controller@00a01000 {  
    //↑这里有个冒号,冒号前面是一个标签label,后面才是节点名
    // 这样可以通过 &label 来访问该节点,如&intc就可以访问interrupt-controller@00a01000节点
    // 比如上面的&i2c1,就可以在imx6ull.dtsi 939行找到“i2c1: i2c@021a0000”
    // &定义的节点内容如果没有则追加,如果已存在则替换,比如&i2c1里的内容就会替换原本i2c1: i2c@021a0000的内容
    …………
};

层级结构

Power_ePAPR_APPROVED_v1.12.pdf 14页

         “/”表示设备树文件的根节点,每个设备树文件只有一个根节点。

        imx6ull.dtsi和imx6ull-alientek-emmc.dts这两个文件都有一个“/”根节点,这两个“/”根节点的内容会合并成一个根节点。

2.3 设备树在系统中的体现

第6.4讲 Linux设备树详解-设备树在根文件系统中的体现以及添加自定义节点_哔哩哔哩_bilibili

        系统启动后可以在根文件系统里看到设备树的节点信息。

        内核启动时会解析设备树文件,并在/proc/device-tree目录下生成相应的设备树节点文件,存放设备树信息。cd到该路径下使用ls命令,可以看到很到诸如chosen、memory、reserved-memory、backlight等文件。

        这与imx6ull-alientek-emmc.dts中的结构一致:

        cat查看model的内容:

        这与imx6ull-alientek-emmc.dts中model的属性一致:

        cd到soc/aips-bus@02100000/i2c@021a0000下,可以看到这些文件:

        但是imx6ull.dtsi的939行下只能看到:

        clock-frequency、fxls8471@1e、mag3110@0e、name、printrl-0、printrl-names是从哪来的?用&追加的。在imx6ull-alientek-emmc.dts的245行可以找到:

        其中还修改了status,使用cat status可以看到status被覆盖为了okay。

2.4 其他特殊节点

第6.5讲 Linux设备树详解-设备树特殊节点_哔哩哔哩_bilibili

《指南》43.6部分

2.4.1 aliases

在imx6ull.dtsi的开头可以看到:

/ {
	aliases {
		can0 = &flexcan1;
		can1 = &flexcan2;
        …………
    };
};

同时,/soc/下定义了flexcan1:

/ {
    soc {
        flexcan1: can@02090000{
            ……
        }
        ……
    };
    ……
}; 

        那么,can0 = &flexcan1; 等价于 can0 = &{/soc/can@02090000}; 或 can0 = "/soc/can@02090000";

        aliases节点的主要功能就是定义别名,以方便访问节点。不过一般会在节点命名的时候会加上label,然后通过&label来访问节点。

2.4.2 chosen

        主要目的是将uboot里的bootargs环境变量的值传给linux内核作为命令行参数cmd line

        在串口cd /proc/device-tree/chosen,可以看到bootargs、name、stdout-path三个。

但是imx6ull-alientek-emmc.dts中的chosen节点只定义了stdout-path一个:

	chosen {
		stdout-path = &uart1;
	};

        所以bootargs是从来的?(name先不管)当执行bootcmd中的bootz 80800000 - 83000000这句时,bootz层层调用,最终fdt_chosen函数读取bootargs的值并传给/chosen节点,供内核使用:

在alientek_uboot/common/fdt_common下可以找到fdt_chosen:

int fdt_chosen(void *fdt){
	int   nodeoffset;
	int   err;
	char  *str;		/* used to set string properties */

	err = fdt_check_header(fdt);
	if (err < 0) {
		printf("fdt_chosen: %s\n", fdt_strerror(err));
		return err;
	}

	/* find or create "/chosen" node.  如果存在子节点/chosen,则返回其偏移nodeoffset,否则创建并返回nodeoffset*/
	nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");  // fdt为指向设备树文件的指针,0表示根节点, chosen为要查找的子节点名称
	if (nodeoffset < 0)	// 失败
		return nodeoffset;

	str = getenv("bootargs");  // 从uboot的环境变量中读取bootargs的值
	if (str) {  // 如果bootargs不为空
		err = fdt_setprop(fdt, nodeoffset, "bootargs", str,  // 通过fdt_setprop向/chosen节点添加或修改bootargs属性
				  strlen(str) + 1);
		if (err < 0) {  // 失败
			printf("WARNING: could not set bootargs %s.\n",
			       fdt_strerror(err));
			return err;
		}
	}

	return fdt_fixup_stdout(fdt, nodeoffset);
}

2.4 修改节点

2.4.1添加自定义节点

        为方便查看,直接在imx6ull-alientek-emmc.dts的根节点下添加自定义节点:

	// 自定义节点。添加到imx6ull-alientek-emmc.dts的148行
	mytestnode: mytest@0101 {

	};
# VSCODE终端
cd .../linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek  # 到内核根目录下
make dtbs    # 编译
cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb .../tftpboot/ -f  # 复制到自己存放zImage和dtb文件的目录下,如果忘了哪个路径就用vi /etc/default/tftpd-hpa命令看看

# 串口
reboot    # 重启开发板

ls /proc/device-tree/   # 此时应当能看到mytest@0101

                                                                                 (打错字了↓) 

2.4.2 使用&进行追加

        在imx6ull-alientek-emmc.dts文件最末尾添加:

&intc{
	mytestnode{

	};
};
// 追加给imx6ull.dtsi 94行的intc
# VSCODE终端
cd .../linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek  # 到内核根目录下
make dtbs    # 编译
cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb .../tftpboot/ -f  # 复制到自己存放zImage和dtb文件的目录下,如果忘了哪个路径就用vi /etc/default/tftpd-hpa命令看看

# 串口
reboot    # 重启开发板

cd /proc/device-tree/interrupt-controller@00a01000/
ls        # 此时能看到mytestnode

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值