设备树相关知识

1一个pinctrl子系统应当由以下三部分:

引脚枚举与命名(用来描述引脚,对所有引脚进行编号,命名,对引脚支持的功能进行描述)
引脚复用,复用为GPIO,I2C等功能
引脚配置,对引脚的的上拉、下拉、推挽、开漏、驱动能力进行配置

 


2.Pinctrl子系统的使用
Pinctrl子系统一般由芯片原厂的BSP工程时编写,所以我们主要是学会如何使用。

现在的驱动都是与设备树结合使用,所以一般我们使用Pinctrl子系统时主要体现在设备树中,在驱动程序中一般不用写Pinctrl相关的代码。下面采用一个案例来说明如何使用。

这是STM32MP157芯片串口3的设备节点

 

&usart3 { 
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&usart3_pins_c>;
    pinctrl-1 = <&usart3_sleep_pins_c>;
    status = "okay";
};

 


pinctrl-names:里边有两个字符串,这两个字符串是用来描述设备状态的,default:默认状态,sleep:休眠状态, 既是功能,也是状态。
pinctrl-0 :pinctrl-names所描述的第一个设备状态default所对应的引脚节点
pinctrl-1 :pinctrl-names所描述的第二个设备状态sleep所对应的引脚节点
如果有其他状态则继续添加,在pinctrl-names添加第三项,对应的引脚节点就是pinctrl-2。

上面所说的pinctrl-0和pinctrl-1的值 <&usart3_pins_c>、 <&usart3_sleep_pins_c>就是pincontroller子节点,最终pinctrl子系统会根据这个节点来配置引脚功能。这两个节点的定义如下图所示:

 

pin-controller{
        usart3_pins_c: uart3-0 {
                pins1 {
                    pinmux = <STM32_PINMUX('D', 8, AF7)>; /* UART5_TX */
                    bias-disable;
                    drive-push-pull;
                    slew-rate = <0>;
                };
                pins2 {
                    pinmux = <STM32_PINMUX('D', 9, AF7)>; /* UART5_RX */
                    bias-disable;
                };
            };

            usart3_sleep_pins_c: uart3-sleep-0 {
                pins {
                    pinmux = <STM32_PINMUX('D', 8, ANALOG)>, /* UART5_TX */
                                         <STM32_PINMUX('D', 9, ANALOG)>; /* UART5_RX */
                };
            };
    };

 

进过查STM32MP157数据手册:

 

usart3_pins_c节点:

PD8引脚复用为AF7,复用功能为USART_TX功能,内部上下拉禁止,推挽输出,压摆率:低速

PD9引脚复用为AF7,复用功能为USART_RX功能,内部上下拉禁止。

usart3_sleep_pins_c节点:

PD8和PD9引脚复用为ANALOG,模拟量模式
通过上面代码及分析,我们可以将pinctrl子系统在设备树下的描述分为两部分:

客户端设备:
pinctrl-names:描述设备状态
pinctrl-n: n从0开始,用来描述每个设备状态下所使用引脚,该引脚在pin controller中定义
pin-controller:
客户端设备节点下所使用的引脚复用功能和配置信息的描述。
我们再看以下imx6ul的设备树下对于pinctrl的使用:

客户端设备:

&uart2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart2>;
uart-has-rtscts;
status = "okay";
};

 

pin-controller端:

iomuxc{
pinctrl_uart2: uart2grp {
fsl,pins = <
MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1
MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1
MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS 0x1b0b1
MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS 0x1b0b1
>;
};
};

 

我们可以通过Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt文档得知:

MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX这种类型为一个宏定义,里边有5个值,用来配置引脚的复用功能,复用为串口2的TX功能。
0x1b0b1:配置信息,配置上下拉、驱动能力等等
通过对比上面STM32MP157的设备树和imx6ul的设备树信息可知:

客户端设备:统一的格式,都是通过pinctrl-names描述设备状态,pinctrl-n用来指定对于客户端每个状态下对应的引脚。

pin-controller:没有统一的格式,对于不同的SOC厂家的格式不同,但是最后要实现的目的都是一致的,都是要设置引脚复用和引脚配置
————————————————

 

 

左边pin controller节点,右边client device节点。
1)pin state
对于一个"client device",如UART设备,它有多个“状态”:default、sleep等,那么对应的引脚也有这些状态。

比如,默认状态下,UART设备正常工作,那么所用的引脚就要复用为UART功能;
休眠状态下,为了省电,可以把这些引脚复用为GPIO功能;或者直接把它们配置输出高电平。

上图pinctrl-names定义2种状态:default,sleep。
第0种状态用到的引脚在pinctrl-0中定义,它是state_0_node_a,位于pincontroller节点中。
第1种状态用到的引脚在Pinctrl-1中定义,它是state_1_node_a,位于pincontroller节点中。

当UART设备处于default状态时,pinctrl子系统会自动根据上述信息将所用引脚复用为uart0功能。
当UART设备处于sleep状态时,pinctrl子系统会自动根据上述信息将所用引脚配置为高电平。

2)groups和function
一个设备会用到一个或多个引脚,这些引脚可以归纳为一组(group);
这些引脚可以复用为某个功能:function,如I2C功能,SPI功能,GPIO功能等。

一个设备可以用的多组引脚,如A1、A2两组引脚,A1组复用为F1功能,A2组复用为F2功能。

3)Generic pin multiplexing node和Generic pin configuration node
上图左边pin controller节点中,有子节点或孙节点,它们是给client device使用的。
可用来描述复用信息:哪组(group)引脚复用为哪个功能(function);
配置信息:哪组(group)引脚配置为哪个设置功能(setting),如上拉、下拉等;

注意:pin controller节点格式,没有统一格式,每家芯片都不一样。可能group、function关键字也不一样,但都有这样的概念。
client device节点格式都是类似的。

IMX6ULL pin controller

pinctrl_uart1: uart1grp {                /*!< Function assigned for  the core: Cortex-A7[ca7] */
    fsl,pins = <
        MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX      0x000010B0
        MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX      0x000010B0
    >;
};

对应client device

&uart1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_uart1>;
    status = "okay";
};

设备树相关符号

“/” 根节点

“@” 如果设备有地址,则由此符号指定

“&” 引用节点(比如这个设备树include了其他的设备树文件,其他设备树文件里有个ABC节点,&ABC就可以引用这个节点并添加新的属性了)

“:” 冒号前的label是为了方便引用给节点起的别名,此label一般使用为&label,冒号后面的就是这个节点真正的名字了

“,” 属性名称中可以包含逗号。如compatible属性的名字 组成方式为"[manufacturer], [model]",加入厂商名是为了避免重名。自定义属性名中通常也要有厂商名,并以逗号分隔。

“#” #并不表示注释。如 #address-cells ,#size-cells 用来决定reg属性的格式。

空属性并不一定表示没有赋值。如 interrupt-controller 一个空属性用来声明这个node接收中断信号

数据类型

“” 引号中的为字符串,字符串数组:”strint1”,”string2”,”string3”

< > 尖括号中的为32位整形数字,整形数组<12 3 4>

“[ ]” 方括号中的为32位十六进制数,十六机制数据[0x11 0x12 0x13] 其中0x可省略

stm32mp13x系列资源异同:
      135        133        131
LCD     Y         N         N
ETH     2         2         1
CAN     2         2         0
CAMERA Y         N         N
AD     2         2         1
stm32mp135x系列资源异同:

   135A 135C      135D     135F
freq.   650M       650M 1G        1G
AES N         Y         N       Y
Temp. 125        125        125       125

dtc会在最终的dtb中生成__symbols__节点,该节点中会收集所有带label的节点的在设备树中位置信息

在根文件系统查看设备树(有助于调试)

a. /sys/firmware/fdt // 原始dtb文件
对这个文件使用命令 可以查看原始的dtb文件

hexdump -C /sys/firmware/fdt

b. /sys/firmware/devicetree

以目录结构程现的dtb文件, 根节点对应base目录, 每一个节点对应一个目录, 每一个属性对应一个文件
同样用命令hexdump -C ./led 进行查看

c./sys/devices/platform
系统中所有的platform_device, 有来自设备树的, 也有来有.c文件中注册的
对于来自设备树的platform_device,
可以进入 /sys/devices/platform/<设备名>/of_node 查看它的设备树属性

d./proc/device-tree
/proc/device-tree 是链接文件, 指向 /sys/firmware/devicetree/base

平台设备和 字符设备,块设备是并行的概念(不是并列),是从另一个角度来描述设备。

 

 Linux内核的OF操作函数
1.查找节点的 OF 函数
        设备都是以节点的形式“挂”到设备树上的,因此要想获取这个设备的其他属性信息,必须先获取到这个设备的节点。Linux 内核使用 device_node 结构体来描述一个节点。与查找节点有关的OF 函数有 5 个:

 

 

4)删除设备树节点,删除节点属性

/delete-node/ gpu@59000000; 或者 /delete-node/ &gpu;

&dsi {
/delete-property/ phy-dsi-suppry;
};

5)设备树的语法规范---需要相应的驱动进行解释

posted @ 2023-11-22 17:12  okyihu  阅读(11)  评论(0编辑  收藏  举报