Linux解析DTS常用OF API

常用OF API

在Linux的BSP和驱动代码中,还经常会使用到Linux中一组Device Tree的API,这些API通常被冠以of_前缀,它们的实现代码位于内核的drivers/of目录。这些常用的API包括:

int of_device_is_compatible(const struct device_node *device,const char *compat);

判断设备结点的compatible 属性是否包含compat指定的字符串。当一个驱动支持2个或多个设备的时候,这些不同.dts文件中设备的compatible 属性都会进入驱动 OF匹配表。因此驱动可以透过Bootloader传递给内核的Device Tree中的真正结点的compatible 属性以确定究竟是哪一种设备,从而根据不同的设备类型进行不同的处理。如drivers/pinctrl/pinctrl-sirf.c即兼容于"sirf,prima2-pinctrl",又兼容于"sirf,prima2-pinctrl",在驱动中就有相应分支处理:
if (of_device_is_compatible(np, “sirf,marco-pinctrl”))
is_marco = 1;
struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible);

根据compatible属性,获得设备结点。遍历Device Tree中所有的设备结点,看看哪个结点的类型、compatible属性与本函数的输入参数匹配,大多数情况下,from、type为NULL。

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

int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz);

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

int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value);

读取设备结点np的属性名为propname,类型为8、16、32、64位整型数组的属性。对于32位处理器来讲,最常用的是of_property_read_u32_array()。如在arch/arm/mm/cache-l2x0.c中,透过如下语句读取L2 cache的"arm,data-latency"属性:

     of_property_read_u32_array(np, "arm,data-latency",
                                data, ARRAY_SIZE(data));

在arch/arm/boot/dts/vexpress-v2p-ca9.dts中,含有"arm,data-latency"属性的L2 cache结点如下:

137 L2: cache-controller@1e00a000 {
138 compatible = “arm,pl310-cache”;
139 reg = <0x1e00a000 0x1000>;
140 interrupts = <0 43 4>;
141 cache-level = <2>;
142 arm,data-latency = <1 1 1>;
143 arm,tag-latency = <1 1 1>;
144 }

有些情况下,整形属性的长度可能为1,于是内核为了方便调用者,又在上述API的基础上封装出了更加简单的读单一整形属性的API,它们为int of_property_read_u8()、of_property_read_u16()等,实现于include/linux/of.h:

513 static inline int of_property_read_u8(const struct device_node *np,
514 const char *propname,
515 u8 *out_value)
516 {
517 return of_property_read_u8_array(np, propname, out_value, 1);
518 }
519
520 static inline int of_property_read_u16(const struct device_node *np,
521 const char *propname,
522 u16 *out_value)
523 {
524 return of_property_read_u16_array(np, propname, out_value, 1);
525 }
526
527 static inline int of_property_read_u32(const struct device_node *np,
528 const char *propname,
529 u32 *out_value)
530 {
531 return of_property_read_u32_array(np, propname, out_value, 1);
532 }

int of_property_read_string(struct device_node *np, const char *propname, const char **out_string);

int of_property_read_string_index(struct device_node *np, const char *propname, int index, const char **output);

前者读取字符串属性,后者读取字符串数组属性中的第index个字符串。如drivers/clk/clk.c中的of_clk_get_parent_name()透过of_property_read_string_index()遍历clkspec结点的所有"clock-output-names"字符串数组属性。

1759 const char *of_clk_get_parent_name(struct device_node *np, int index)
1760 {
1761 struct of_phandle_args clkspec;
1762 const char *clk_name;
1763 int rc;
1764
1765 if (index < 0)
1766 return NULL;
1767
1768 rc = of_parse_phandle_with_args(np, “clocks”, “#clock-cells”, index,
1769 &clkspec);
1770 if (rc)
1771 return NULL;
1772
1773 if (of_property_read_string_index(clkspec.np, “clock-output-names”,
1774 clkspec.args_count ? clkspec.args[0] : 0,
1775 &clk_name) < 0)
1776 clk_name = clkspec.np->name;
1777
1778 of_node_put(clkspec.np);
1779 return clk_name;
1780 }
1781 EXPORT_SYMBOL_GPL(of_clk_get_parent_name);

static inline bool of_property_read_bool(const struct device_node *np, const char *propname);

如果设备结点np含有propname属性,则返回true,否则返回false。一般用于检查空属性是否存在。

void __iomem *of_iomap(struct device_node *node, int index);

通过设备结点直接进行设备内存区间的 ioremap(),index是内存段的索引。若设备结点的reg属性有多段,可通过index标示要ioremap的是哪一段,只有1段的情况,index为0。采用Device Tree后,大量的设备驱动通过of_iomap()进行映射,而不再通过传统的ioremap。

unsigned int irq_of_parse_and_map(struct device_node *dev, int index);

透过Device Tree或者设备的中断号,实际上是从.dts中的interrupts属性解析出中断号。若设备使用了多个中断,index指定中断的索引号。

还有一些OF API,这里不一一列举,具体可参考include/linux/of.h头文件。
————————————————
版权声明:本文为CSDN博主「宋宝华」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/21cnbao/article/details/8457546

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要修改Linux内核的设备树源文件(Device Tree Source, DTS),您可以按照以下步骤进行操作: 1. 定位设备树源文件:在Linux内核源码目录中,通常位于`arch/<架构>/boot/dts/`目录下,其中`<架构>`是您的目标硬件架构,比如`arm`、`arm64`等。在该目录中,找到您要修改的设备树源文件(通常以`.dts`或`.dtsi`为扩展名)。 2. 编辑设备树源文件:使用任何文本编辑器打开设备树源文件。确保您具有足够的权限来修改该文件。 3. 进行所需的修改:根据您的需求,在设备树源文件中找到相应的节点,并进行相应的修改。设备树使用了一种类似于树形结构的语法,您需要了解设备树的语法和结构以正确地进行修改。在修改之前,建议先备份原始的设备树源文件,以防止错误导致系统无法启动。 4. 保存并退出编辑器:在完成修改后,保存您所做的更改,并关闭编辑器。 5. 重新编译设备树:通过以下命令重新编译设备树文件: ```bash $ make dtbs ``` 这将重新生成设备树二进制文件(Device Tree Blob, DTB)。 6. 更新内核镜像:将生成的DTB文件复制到适当的位置,以便在系统启动时使用。具体位置取决于您的系统和引导方式。通常情况下,DTB文件位于`/boot`目录下。 7. 重新启动系统:重新启动计算机,使新的设备树生效。 请注意,修改设备树源文件需要对硬件和设备树的了解,以确保正确地进行修改。不正确的修改可能导致系统无法正常启动或硬件功能失效。因此,在修改设备树之前,请务必备份原始的设备树源文件,并确保您对所做的更改有深入的了解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值