Linux 驱动-设备树

设备树格式

/ {
  属性名 = "属性值","可以多个";
  标签(通常是节点名简写): 字节点名@地址 {
    属性名 = "属性值";
    属性名 = [0x00 0x01];
    属性名 = <1 2 3>;
  };
}

&标签 {
    属性名 = "向标签的节点追加内容";
};

特殊节点:

aliases { //为字节的设置别名
别名 = &标签;
}

chosen { //向内核传递参数
bootargs = "内核启动参数";
linux,stdout-path = "/plb/serial@84000000";
}

属性可以自定义也有一些标准属性:

  • compatible = "用于设备匹配";
  • model = "制造商和型号";
  • status = "okay"(默认) or "disabled" or "fail" or "fail-sss"(sss是错误原因);
  • addres-cells = <2>

  • size-cells = <1>

  • reg = <1 2 3> //父节点的#addres-cells 表示前2个是地址, #size-cells 表示地址后一个是大小, 每个数据叫一个cell,每个cell 32 bit.
  • ranges = <子地址起始 对应的父地址起始 地址范围大小> //描述当前节点的子节点的地址和当前节点地址的映射关系

获取设备树信息

内核中使用struct device_node 表示设备节点,主要成员如下:

成员 描述
name 节点中属性为name的值
full_name 节点的名字,在device_node结构体后面放一个字符串,full_name指向它
properties 链表,连接该节点的所有属性
parent 指向父节点
child 指向子节点
sibling 指向兄弟节点

使用of_开头的函数:

查找节点
static inline struct device_node *of_find_compatible_node(
struct device_node *from, //指定从哪个节点开始查找,如果设置为NULL表示从根节点开始查找
const char *type,
const char *compat)

static inline struct device_node *of_find_node_by_path(const char *path)

static inline struct device_node *of_find_matching_node_and_match(
struct device_node *from,
const struct of_device_id *matches,
const struct of_device_id **match)

static inline struct device_node *of_find_node_by_name(struct device_node *from, const char *name)

static inline struct device_node *of_find_node_by_type(struct device_node *from, const char *type)

查找父节点和子节点
static inline struct device_node *of_get_parent(const struct device_node *node)

static inline struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev)

查找属性
static inline struct property *of_find_property(const struct device_node *np, const char *name, int *lenp)

内核用struct property表示属性,主要成员如下:

成员 描述
name 属性名
length 属性长度
value 属性值
next 下一个属性

读取属性值
static inline int of_property_read_string(const struct device_node *np, const char *propname, const char **out_string)

static inline int of_property_read_string_index(const struct device_node *np,
const char *propname,
int index, const char **output) //读取属性值的第index个字符串

static inline int of_property_read_u8_array(const struct device_node *np,const char *propname, u8 *out_values, size_t sz)

static inline int of_property_read_u16_array(const struct device_node *np,const char *propname, u32 *out_values, size_t sz)

static inline int of_property_read_u32_array(const struct device_node *np,const char *propname, u32 *out_values, size_t sz)

static inline int of_property_read_u64_array(const struct device_node *np,const char *propname, u64 *out_values, size_t sz)

判断属性是否存在
static inline bool of_property_read_bool(const struct device_node *np, const char *propname)

读取地址
void __iomem *of_iomap(struct device_node *np, int index) //自动读取reg属性并ioremap为内核虚拟地址

int of_address_to_resource(struct device_node *dev, int index, struct resource *r)

编译和加载设备树

编译内核时会自动去编译设备树, 也可以单独编译

make dtbs

# 编译 dts 为 dtb
内核目录/scripts/dtc/dtc -I dts -O dtb -o xxx.dtb xxx.dts

使用make dtbs时会更加.config文件去编译对应的设备树, 以arm为列, arch/arm/boot/dts/目录下的makefile会根据某些条件去编译对应的设备树文件.

补充

/proc/device-tree 可以查看设备树信息

设备树被内核读取后会使用device_node结构体表示, 根节点是of_root.
并且有些device_node会被转化成platform_device: 节点的compatile属性含有这些特殊的值(“simple-bus”,“simple-mfd”,“isa”,“arm,amba-bus”)之一, 它及其子节点会被转化成platform_device.

posted @ 2025-03-09 17:12  天刚刚破晓  阅读(63)  评论(0)    收藏  举报