Xunwei Embedded Linux Driver Development Notes (4) - Device Tree

1. Device tree

1. What is a device tree?
A device tree is a data structure that describes hardware resources. It transmits hardware resources to the kernel through the bootloader, so that the description of the kernel and hardware resources is relatively independent.

Second, the basic concept of the device tree
1. Why is it called the device tree?
Because its grammatical structure is like a tree, it is called a device tree.

2. Explanation of common terms

<1>DT:Device Tree // Device tree

<2>FDT:Flattened Device Tree // Expand the device tree // Open firmware, the device tree originated from OF, so we can see many functions with the letter of in the device tree

<3>device tree source(dts)// device tree code

<4>device tree source include(dtsi) // More general device tree code, that is, the code that can be used by the same chip but not all platforms

<5>device tree blob(dtb)//DTB file obtained after DTS compilation

<6>device tree compiler(dtc)// device tree compiler
insert image description here

Second, the basic syntax of the device tree

one. Device Tree Basic Framework
<1> The device tree starts from the root node, and each device is a node.
<2> Nodes and nodes can be nested with each other to form a parent-child relationship.
<3> The attributes of the device are described by key-value pairs (key-value pairs), and each attribute is terminated with a semicolon.

two. device tree syntax

2.1 Nodes

What is a node?
A node is like a big tree, starting from the trunk of the tree, and then there are branches, which are called nodes. What does the node look like in the code. We pick out the root node in the above template, as shown in the figure below, this is the root node. Equivalent to the trunk of a large tree.

/{
    
     
};// 分号

The branch is equivalent to the child node of the device tree. Similarly, we pick out the child node to be node1 and node2 in the root node, as shown in the following figure:

/{
    
     // 根节点 
		node1// 子节点 node1
		{
    
     
		}; 
		node2// 子节点 node2 
		{
    
    
		}; 
 };// 分号

Can a branch be divided into several branches, that is to say, child nodes can contain child child nodes. So child-node1 and child-node2 are child nodes of node1 and node1, as shown below:

/{
    
     // 根节点 
			node1// 子节点 node1 
			{
    
     
				child-node1 // 子子节点
				 {
    
     
				 };
			};
				node2//子节点node2 
				{
    
     
					child-node2 // 子子节点
					{
    
    
					}; 
			  }; 
};// 分号

2.2 Node name

Node names have a fixed format.

格式: < 名称 >[@< 设备地址 >]

<Name> The name of the node is not arbitrary. Generally, it should reflect the type of the device rather than the characteristic model. For example, the network port should be named ethernet instead of one randomly, such as 111.
<device address> is the base address used to access the device. But it does not mean to describe an address during operation, it is mainly used to distinguish.

Note:
<1> Nodes at the same level can have different names as long as their addresses are different.
<2> The device address is an optional option and can not be written. But in order to be easy to distinguish and understand, they are generally written.

2.3 Node Aliases

When we find a node, we have to write the complete node path. If our node name is very long, it is very inconvenient for us to refer to it. Therefore, the device tree allows us to use the following form to mark the reference for the node ( alias). For example, the name of an anime character is Mengqi D Luffy, and his nickname is Luffy. Is that nickname easier to remember than our full name? This is the alias.
Example:

uart8: serial@02288000

Among them, uart8 is the alias of the node name, and serial@02288000 is the node name.

2.4 Node references

Generally, when I add content to a node, I will not directly write the added content to the node, but add it through the reference of the node.
Example:

&uart8 {
    
    
 pinctrl-names = "default"; 
 pinctrl-0 = <&pinctrl_uart8>; 
 status = "okay"; 
 }

&uart8 means to refer to the node whose node alias is uart8, and add the following content to this node:

pinctrl-names = "default"; 
pinctrl-0 = <&pinctrl_uart8>; 
status = "okay"

Note: When compiling the device tree, the different attribute information of the same node will be merged, and the same attribute of the same node will be rewritten. Using references can avoid the transplanter looking for nodes everywhere. For example, both dts and dtsi have root nodes, but they will eventually be merged into one root node.

2.5 Properties

(1) reg attribute The reg attribute is used to describe the address range of a device.
Format:

reg=<add1 length1 [add2 length2]......> 

Example:

  serial@02288000 {
    
     
  					reg = <101F2000 0x1000>;
  				 }; 

101F2000 is the starting address, and 0x1000 is the length.
(2)
#address-cells and #size-cells attributes
#address-cells is used to set the number of reg addresses in the child node
#size-cells is used to set the number of reg address lengths in the child node.
Example:

 cpu{
    
    
  #address-cells = <1>;
   #size-cells = <1>;
    serial@101F2000{
    
    
    compatible = "serial";
     reg = <101F2000 0x1000>; 
     }; 
};

Among them, #address-cells and #size-cell are both 1, which means that there is only one starting address and one length of this register group in the reg attribute in the child node. So 101F2000 is the start address and 0x1000 is the length.
( 3 ) The compatible property
compatible is a list of strings that can be matched in code. Example:

  compatible = "led"

(4) status
attribute The value type of the status attribute is a string, here we just need to remember two commonly used ones, one is OK, which means the device can be used normally, and the other is disable, which means the device cannot be used normally.

3. Add your own node to the device tree

If there is no dtc tool in the environment, you need to install the dtc tool.
Installation command:
apt-get install device-tree-compiler

The of function of the device tree

#include<linux/init.h>
#include<linux/module.h>

#include <linux/of.h>



struct device_node *test_device_node;

struct property *test_node_property;

int size;

u32 out_value[2] = {
    
    0};

const char *str;

int ret = 0;

static int hello_init(void)
{
    
    
    printk("hello world");

    /*查找我们要查找的节点*/
    test_device_node = of_find_node_by_path("/test");
    if (test_device_node == NULL)
    {
    
    
        printk("of_find_by_path is erron\n");
        return -1;
    }
    printk("test_device_node is %s",test_device_node->name);
    
    /*获取compatible属性*/    
    test_node_property = of_find_property(test_device_node,"compatible",&size);

    if (test_node_property == NULL)
    {
    
    
        printk("test_node_property is error\n");
    }
    printk("test_node_property name is %s\n",test_node_property->name);//获取属性名称

    printk("test_node_property value is %s\n",(char *)test_node_property->value);//获取属性值

    /*获取reg属性内容*/
    ret = of_property_read_u32_array(test_device_node,"reg",out_value,2);
    if (ret<0)
    {
    
    
         printk("of_property_read_u32_array is error\n");
    }
    printk("out_value[0] is 0x%08x",out_value[0]);

    printk("out_value[1] is 0x%08x",out_value[1]);
    
    /*获取status属性内容*/
    ret = of_property_read_string(test_device_node,"status",&str);
    if (ret<0)
    {
    
    
         printk("of_property_read_string is error\n");
    }
    printk("status is %s\n",str);

    return 0;
}

static int hello_exit(void)
{
    
    
    printk("bye bye");
    return 0;
}

module_init(hello_init);

module_exit(hello_exit);

MODULE_LICENSE("GPL");

Platform bus
name matching under the device tree: .of_match_table = of_match_table

const struct of_match_table[] = 
{
    
    
    {
    
    .compatible = "test1234"},
    {
    
    },
}

struct platform_driver beep_driver = {
    
    
     .probe = beep_probe,
     .remove = beep_remove,
     .driver = {
    
    
         .owner = THIS_MODULE,
         .name = "beep_test",
         .of_match_table = of_match_table
     },
     .id_table = &beepid_table
 };

Resource acquisition, after matching the probe and entering the probe function, the resource can be acquired
Method 1: Direct acquisition

printk("node name is %s\n",pdev->dev.of_node->name);

Method 2:

int beep_probe(struct platform_device *pdev){
    
    

    printk("beep_probe");
    
    //printk("node name is %s\n",pdev->dev.of_node->name);

    /*查找我们要查找的节点*/
    test_device_node = of_find_node_by_path("/test");
    if (test_device_node == NULL)
    {
    
    
        printk("of_find_by_path is erron\n");
        return -1;
    }
    printk("test_device_node is %s",test_device_node->name);
    
    /*获取reg属性内容*/
    ret = of_property_read_u32_array(test_device_node,"reg",out_value,2);
    if (ret<0)
    {
    
    
         printk("of_property_read_u32_array is error\n");
    }
    printk("out_value[0] is 0x%08x",out_value[0]);
    printk("out_value[1] is 0x%08x",out_value[1]);
    return 0;
}

of_iomap remapping function:

  vir_gpio_dr = of_iomap(pdev->dev.of_node,0);
    if (vir_gpio_dr == NULL)
    {
    
    
        printk("of_iomap is error\n");
        return -1;
    }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324149590&siteId=291194637