第六讲 Linux设备树详解
一、什么是设备树
1、uboot启动内核用到zImage,imx6ull-alientek-emmc.dtb。bootz 80800000 – 83000000.
2、设备树:设备和树。
3,在单片机驱动里面比如W25QXX,SPI,速度都是在.c文件里面写死。板级信息都写到.c里面,导致linux内核臃肿。因此 将板子信息做成独立的格式,文件扩展名为.dts。一个平台或者机器对应一个.dts。
二、DTS、DTB和DTC的关系
.dts相当于.c,就是DTS源码文件。
DTC工具相当于gcc编译器,将.dts编译成.dtb。
.dtb相当于bin文件,或可执行文件。
通过make dtbs编译所有的dts文件。如果要编译指定的dtbs
make imx6ull-alientek-emmc.dtb
三、DTS基本语法
1、设备树也有头文件,扩展名为.dtsi。可以将一款SOC他的其他所有设备/平台的共有的信息提出来,作为一个通用的.dtsi文件。
1、DTS也是’/’开始
2,从/根节点开始描述设备信息
3,在/根节点外有一些&cpu0这样的语句是“追加“。
4,节点名字,完整的要求
node-name@unit-address
unit-address一般都是外设寄存器的起始地址,有时候是I2C的设备地址,或者其他含义,具体节点具体分析。设备树里面常常遇到如下所示节点名字:
*intc: interrupt-controller@00a01000*
:前面是标签label,后面才是名字。intc,完整的名字是interrupt-controller@00a01000。&intc
四、创建小型的设备树模板
五、设备树在系统中的体现
系统启动以后可以在根文件系统里面看到设备树的节点信息。在/proc/device-tree/目录下存放着设备树信息。
内核启动的时候会解析设备树,然后在/proc/device-tree/目录下呈现出来。
六、特殊节点
1,aliases
2,chosen节点,主要目的就是将uboot里面bootargs环境变量值,传递给Linux内核作为命令行参数,cmd line。uboot里面bootargs值为:
bootargs=console=ttymxc0,115200 rw root=/dev/nfs nfsroot=192.168.1.249:/home/zzk/linux/nfs/rootfs ip=192.168.1.50:192.168.1.249:192.168.1.1:255.255.255.0::eth0:off
linux内核cmdline值为:
Kernel command line: console=ttymxc0,115200 rw root=/dev/nfs nfsroot=192.168.1.249:/home/zzk/linux/nfs/rootfs ip=192.168.1.50:192.168.1.249:192.168.1.1:255.255.255.0::eth0:off
uboot是如何向kernel传递bootargs。
经过查看发现chosen节点中包含bootargs属性,属性值和uboot的bootargs一致。
uboot接触过dtb,最终通过bootz 80800000 – 83000000 来启动内核。经过分析判断uboot拥有bootargs环境变量和dtb,因此最有可能“作案”。
最终发现在uboot的fdt_chosen函数中会查找chosen节点,并且在里面添加bootargs属性,属性值为bootargs变量值。
七、特殊的属性
1、compatible属性,值是字符串。
根节点/下面的compatible。内核启动的时候会检查是否支持此平台,或机器。
不使用设备树的时候通过machine id来判断内核是否支持此机器。
#define MACHINE_START(type,name) \
static const struct machine_desc _mach_desc##_type \
__used \
attribute((section(".arch.info.init"))) = { \
.nr = MACH_TYPE##type, \
.name = _name,
#define MACHINE_END \
};
MACHINE_START(MX35_3DS, "Freescale MX35PDK")
/* Maintainer: Freescale Semiconductor, Inc */
.atag_offset = 0x100,
.map_io = mx35_map_io,
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.init_time = mx35pdk_timer_init,
.init_machine = mx35_3ds_init,
.reserve = mx35_3ds_reserve,
.restart = mxc_restart,
MACHINE_END
展开以后:
static const struct machine_desc mach_desc_MX35_3DS used
attribute((section(".arch.info.init"))) = {
*.nr* *= MACH_TYPE_MX35_3DS,* *//**机器I****D***
.name = "Freescale MX35PDK",
.atag_offset = 0x100,
.map_io = mx35_map_io,
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.init_time = mx35pdk_timer_init,
.init_machine = mx35_3ds_init,
.reserve = mx35_3ds_reserve,
.restart = mxc_restart,
};
使用设备树的时候不使用机器ID,而是使用根节点/下的compatible。
#define DT_MACHINE_START(_name, _namestr) \
static const struct machine_desc _mach_desc##_name \
__used \
attribute((section(".arch.info.init"))) = { \
.nr = ~0, \
.name = _namestr,
DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)")
.map_io = imx6ul_map_io,
.init_irq = imx6ul_init_irq,
.init_machine = imx6ul_init_machine,
.init_late = imx6ul_init_late,
.dt_compat = imx6ul_dt_compat,
MACHINE_END
展开以后就是:
static const struct machine_desc mach_desc_IMX6UL used
attribute((section(".arch.info.init"))) = {
*.nr* *= ~0,*
.name = "Freescale i.MX6 Ultralite (Device Tree)",
.map_io = imx6ul_map_io,
.init_irq = imx6ul_init_irq,
.init_machine = imx6ul_init_machine,
.init_late = imx6ul_init_late,
*.dt_compat* *= imx6ul_dt_compat,*
};
八、Linux内核的OF操作函数
1、驱动如何获取到设备树中节点信息。在驱动中使用OF函数获取设备树属性内容。
2,驱动要想获取到设备树节点内容,首先要找到节点。
第七讲 设备树下的LED驱动实验
一、设备树LED驱动原理
二、修改设备树文件
设备节点最好添加到好区分的地方,1级节点是最好的地方。
三、编写驱动
四、运行测试