Self study linux driver from getting started to giving up the device tree

Keywords: Linux Ubuntu

catalogue

1. What is a device tree?

2. Structure of equipment tree

3. Node structure

4. Node standard attributes

4.1 compatible

4.2 status

4.3 #address-cells #size-cells

4.4 reg

4.5 name

4.6 device_type

4.7 phandle

4.8 virtul-reg

4.9 range

4.10 dma-range

5. Special nodes

5.1 /aliases node

5.2 /chosen node

6."of_" correlation function

6.1 finding nodes

6.1.1 of_find_node_by_name

6.1.2 of_find_node_by_type

6.1.3 of_find_compatible_node

6.1.4 of_find_node_by_path

6.2 extracting attribute values

6.2.1 of_find_property

 6.2.2 of_property_read_u32_index

 6.2.3 of_property_read_u*_array

6.2.4 of_property_read_u*

 

        Let's not talk about the background of the introduction of the device tree. Look directly at the device tree.

1. What is a device tree?

        The device tree describes the hardware in the system with a tree structure and nodes. Each node has attributes / values that describe the characteristics of the represented device, etc. So there are several concepts.

DTSThe code source file of the device tree can be understood as the reference customization of each DTSI node on each development board.
DTSIDevice tree codes that are more common to the same platform can be defined in DTS files as header files.
DTCDTS compilation files can be compiled into DTB or decompiled into DTS
DTBBinary file compiled by DTC

2. Structure of equipment tree

/dts-v1/;                   
[memory reservations]        
/{
    [property defintions]
    [child node]
};
/dts-v1/;Version information of the device tree
[memory reservations] The reserved memory space is not used / allocated by memory: / memreserve / < address > < lenth >;
[property defintions]Name of attribute and value of attribute: property name = value;

There are two types of property name: one is a user-defined name, such as "led pins", and the other is a fixed name, such as "compatible".

The value of value is as follows:

emptyCan be empty, such as: enable active high;
<u32>
32-bit data: TX_ delay = <0x30>;
<u64>
Two 32-bit data: < 0x11223344 0x55667788 >
<string>
String: compatible = "silergy,syr827";
<prop-encoded-array>
Specified value: status = "okay";
<phandle>
phandle value: basically not recommended
<stringlist>
Multiple strings: "hello", "world"
Hexadecimal number
local-mac-address = [00 00 12 34 56 78];
or: local-mac-address = [000012345678];
Node reference
interrupt-parent = < &mpic >;
or: interrupt-parent = < &{/soc/interrupt-controller@40000} >;
No node reference for < >
ethernet0 = &EMAC0; Here & emac0 will be expanded to the full path of the node


3. Node structure

         The device tree has only one root node '/' and several nodes node1 and node2... If there are nodes under these nodes, such as node-a under node1, node-a is called a child node and node1 is its parent node.

[label:] node-name[@unit-address] {
[properties definitions]
[child nodes]
};
[label:]Node identification for easy reference
node-nameNode name
[@unit-address]Starting address of node memory (if there is no node with the same name to distinguish, it can be omitted)

4. Node standard attributes

4.1 compatible

        This node is used to match the platform Driver when the attribute name and platform_ Of in drvier_ match_ When the table matches, the probe function will be executed on the driver matching.

Example: compatible = "active-semi,act8846";

4.2 status

        Node status, available, disabled, and error.

valueDescription
"okay"Equipment available
"disabled"Device disabled
"fail"The device has encountered an error and is unavailable
"fail-sss"An error occurred on the device with the error content "sss"
Example: status = "okay";

4.3 #address-cells #size-cells

#address-cellsThe address of the "reg" attribute in the specified child node is represented by several 32 digits
#size-cellsThe address length of the "reg" attribute in the specified child node is represented by several 32 bits
 bus_intmem@ff700000 {
                compatible = "mmio-sram";
                reg = <0x0 0xff700000 0x0 0x18000>;
                #address-cells = <1>;    // The address is represented by a 32-digit number
                #size-cells = <1>;        // The length is represented by a 32-digit number
                ranges = <0 0x0 0xff700000 0x18000>;
                smp-sram@0 {
                        compatible = "rockchip,rk3066-smp-sram";
                        reg = <0x00 0x10>;    //Here is the embodiment
                };

4.4 reg

        It is used to define the starting address and length of the address / register. The value inside is specified by #address cells #size cells.

Format: reg = <addr1 lenth1 addr2 lenth2 ...>

4.5 name

        Not recommended

4.6 device_type

        It is not recommended. It should only be included in the "cpu" and "memory" nodes, but some devices will also be described with this attribute. I don't know why

serial@4600 {
    device_type = "serial";
    compatible = "ns16550";
    reg = <0x4600 0x100>;
    clock-frequency = <0>;
    interrupts = <0xA 0x8>;
    interrupt-parent = <&ipic>;
}

4.7 phandle

        It is used to specify that this node is the only node in the equipment tree and can be used by other nodes to associate this node. It is generally not used now.

pic@10000000 {
    phandle = <1>;
    interrupt-controller;
};

another-device-node {
    interrupt-parent = <1>;
};

4.8 virtul-reg

        No research

4.9 range

        No research

4.10 dma-range

        No research

5. Special nodes

5.1 /aliases node

        The official explanation is that this node is under the root node and can define an alias for other nodes. Let's start with an example.

/ {
        compatible = "rockchip,rk3288";

        interrupt-parent = <&gic>;

        aliases {
                ethernet0 = &gmac;
                i2c0 = &i2c0;
                i2c1 = &i2c1;
                i2c2 = &i2c2;
                ...
                ...
        };
};

         As mentioned above, property name = value. When value does not have < >, it will be expanded into a full path. You can see the full path of "&i2c0" through decompilation above. Here is an example.

aliases {
    serial0 = "/simple-bus@fe000000/serial@llc500";
    ethernet0 = "/simple-bus@fe000000/ethernet@31c000";
};

         After reading some articles on the Internet, the kernel will parse the node, find the node through the expanded node path, and explain the alias id (that is, the numbers' 0 ',' 1 'after i2c0 and i2c1) to register drivers and devices.

5.2 /chosen node

        Parameters selected during system startup, such as nfs mount point, etc.

chosen {
    bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};

6."of_" correlation function

6.1 finding nodes

6.1.1 of_find_node_by_name

struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
functionFind nodes by node name
*fromThe node name to start searching. If 'NULL', the entire device tree will be searched from the root node
*nameNode name to find
Return valueFound node pointer


6.1.2 of_find_node_by_type

struct device_node *of_find_node_by_type(struct device_node *from, const char *type);
functionVia 'device'_ Find node with value of 'type'
*fromThe node name to start searching. If 'NULL', the entire device tree will be searched from the root node
*name'device 'to find_ value of 'type' attribute (string)
Return valueFound node pointer

6.1.3 of_find_compatible_node

struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible)
functionVia 'device'_ The values of the 'type' and 'compatible' attributes find the node if the device_ If the type is NULL, the value of this attribute is ignored and the search is from the value of compatible
*fromThe node to start searching. If NULL, it means to start searching the entire device tree from the root node
*typeDevice corresponding to the node to be found_ Type attribute value, 'NULL' means to ignore this attribute
 *compatibleThe compatible attribute value corresponding to the node to find
Return valueFound node pointer

6.1.4 of_find_node_by_path

struct device_node *of_find_node_by_path(const char *path)
functionFind nodes by their full path
*pathFull path of node
Return valueFound node pointer

6.2 extracting attribute values

6.2.1 of_find_property

property *of_find_property(const struct device_node *np, const char *name, int *lenp)
functionFind properties
*npNode pointer
*nameThe name of the property
*lenpThe value length of the attribute
Return valueFound node pointer

 6.2.2 of_property_read_u32_index

int of_property_read_u32_index(const struct device_node *np, const char *propname,                   
                               u32 index, u32 *out_value);
functionReads the 32-bit unsigned value of the property
*npNode pointer
*propnameThe name of the property
indexindex of attribute value
 *out_valueRead value
Return value0 read succeeded, non-0 read failed
opp-microvolt = <1111 2222 3333>;    //The value of this attribute is three 32-bit unsigned integer values

If this function index Is 0, then the read value is'1111'

 6.2.3 of_property_read_u*_array

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_array(const struct device_node *np,
            const char *propname,u32 *out_values, size_t sz);
functionAttribute values are multiple u8(u16, u32, u64) numbers that can be read out at one time
*npNode pointer
*propnameThe name of the property
*out_valuesArray pointer read
 szThe number of array members to read
Return value0 read succeeded, non-0 read failed

6.2.4 of_property_read_u*

int of_property_read_u8(const struct device_node *np, const char *propname, 
                        u8 *out_value)
int of_property_read_u16(const struct device_node *np, const char *propname, 
                        u16 *out_value)
int of_property_read_u32(const struct device_node *np, const char *propname, 
                        u32 *out_value)
int of_property_read_u64(const struct device_node *np, const char *propname, 
                        u64 *out_value)
functionThe value of the property has only one u8 (u16,u32,u64) value. Read the value
*npNode pointer
*propnameThe name of the property
*out_valuesPointer to the value read
Return value0 read succeeded, non-0 read failed
remarks:These functions can be used_ The function of array is replaced, but the sz variable is set to 1

Posted by PaulRyan on Thu, 02 Dec 2021 22:39:33 -0800