分析一个.dts文件

本文的正确性严重有待检验!!!

我先阅读了/lib/firmware/目录中的所有.dts文件,看一下它写了哪些东西,有哪些共性。经过阅读之后我有一些发现,记录一下。(因为这部分跟驱动关联很大,而我还不熟悉驱动相关的东西,所以只能是望文生义,不敢保证理解正确。)

以BB-UART1-00A0.dts文件为例说明

/dts-v1/;
/plugin/;

/ {
	compatible = "ti,beaglebone", "ti,beaglebone-black";

	/* identification */
	part-number = "BB-UART1";
	version = "00A0";

	/* state the resources this cape uses */
	exclusive-use =
		/* the pin header uses */
		"P9.24",	/* uart1_txd */
		"P9.26",	/* uart1_rxd */
		/* the hardware ip uses */
		"uart1";

	fragment@0 {
		target = <&am33xx_pinmux>;
		__overlay__ {
			bb_uart1_pins: pinmux_bb_uart1_pins {
				pinctrl-single,pins = <
					0x184 0x20 /* P9.24 uart1_txd.uart1_txd  OUTPUT  */
					0x180 0x20 /* P9.26 uart1_rxd.uart1_rxd  INPUT  */
				>;
			};
		};
	};

	fragment@1 {
		target = <&uart2>;	/* really uart1 */
		__overlay__ {
			status = "okay";
			pinctrl-names = "default";
			pinctrl-0 = <&bb_uart1_pins>;
		};
	};
};


所有的.dts文件中每个fragment下面紧接着就是 target 声明,然后是 __overlay__ ,这应该是device tree overlay的标准写法,从直观上看就是要重定义这个target的某些属性或添加某些属性。那我们能修改的target有哪些呢?经过查找,发现它们藏在了这里
# ls /proc/device-tree/__symbols__/

aes                         dcdc2_reg  gpmc       mmc2         timer7
am33xx_pinmux               dcdc3_reg  i2c0       mmc3         tps
baseboard_beaglebone        ecap0      i2c0_pins  name	       tscadc
baseboard_beaglebone_black  ecap1      i2c1       cop          uart1
baseboard_eeprom            ecap2      i2c2       pruss        uart2
cape_eeprom0                edma       i2c2_pins  rstctl       uart3
cape_eeprom1                ehrpwm0    intc       rstctl_pins  uart4
cape_eeprom2                ehrpwm1    lcdc       sham	       uart5
cape_eeprom3                ehrpwm2    ldo1_reg   spi0	       uart6
cpsw_emac0                  epwmss0    ldo2_reg   spi1	       usb_otg_hs
cpsw_emac1                  epwmss1    ldo3_reg   timer1       userled_pins
cpu                         epwmss2    ldo4_reg   timer2       vmmcsd_fixed
davinci_mdio                gpio1      mac        timer3       wdt2
dcan0                       gpio2      mcasp0	  timer4
dcan1                       gpio3      mcasp1	  timer5
dcdc1_reg                   gpio4      mmc1       timer6


这些都是文件,如果你用cat命令查看其中的内容,里面写的是相应target的位置。比如
# cat uart2

/ocp/serial@48022000


这个位置不是linux文件系统中的位置,而是device tree中的位置,第一个斜杠/是device tree的根节点。实际上device tree的根节点对应的正是/proc/device-tree/这个目录。所以/ocp/serial@48022000实际上对应的是/proc/device-tree/ocp/serial@48022000这个位置,我们看看这个目录里面有什么
# ls -l /proc/device-tree/ocp/serial@48022000

-r--r--r-- 1 root root  4 Jan  1 00:52 clock-frequency
-r--r--r-- 1 root root 14 Jan  1 00:52 compatible
-r--r--r-- 1 root root  4 Jan  1 00:52 interrupts
-r--r--r-- 1 root root  4 Jan  1 00:52 linux,phandle
-r--r--r-- 1 root root  7 Jan  1 00:52 name
-r--r--r-- 1 root root  4 Jan  1 00:52 phandle
-r--r--r-- 1 root root  8 Jan  1 00:52 reg
-r--r--r-- 1 root root  9 Jan  1 00:52 status
-r--r--r-- 1 root root  6 Jan  1 00:52 ti,hwmods


这些文件应该就是这个节点默认的属性了。在BB-UART1-00A0.dts里,它只修改了其中一个属性,status = “okay”; 代表使能。

	fragment@1 {
		target = <&uart2>;	/* really uart1 */
		__overlay__ {
			status = "okay";
			pinctrl-names = "default";
			pinctrl-0 = <&bb_uart1_pins>;
		};
	};


那下面两行pinctrl-names和pinctrl-0是什么呢?是添加了两个属性,定义了uart2的引脚复用。而具体复用了哪些引脚的哪些功能,是由第一个fragment定义的(可以看到pinctrl-0 = ;这句引用了上一个fragment中定义的节点)。所以接下来我们看下第一个fragment

	fragment@0 {
		target = <&am33xx_pinmux>;
		__overlay__ {
			bb_uart1_pins: pinmux_bb_uart1_pins {
				pinctrl-single,pins = <
					0x184 0x20 /* P9.24 uart1_txd.uart1_txd  OUTPUT  */
					0x180 0x20 /* P9.26 uart1_rxd.uart1_rxd  INPUT  */
				>;
			};
		};
	};


它的target是am33xx_pinmux,跟上面一样,我们先到/proc/device-tree/__symbols__/里找到am33xx_pinmux,然后cat一下内容,确定其位置是在/proc/device-tree/pinmux@44e10800,然后看一下这个目录里有什么(下面的列表里去掉了目录,只保留了文件)
# ls -l /proc/device-tree/pinmux@44e10800

-r--r--r-- 1 root root  4 Jan  1 02:24 #address-cells
-r--r--r-- 1 root root  4 Jan  1 02:24 #size-cells
-r--r--r-- 1 root root 15 Jan  1 02:24 compatible
-r--r--r-- 1 root root  4 Jan  1 02:24 linux,phandle
-r--r--r-- 1 root root  7 Jan  1 02:24 name
-r--r--r-- 1 root root  4 Jan  1 02:24 phandle
-r--r--r-- 1 root root  4 Jan  1 02:24 pinctrl-0
-r--r--r-- 1 root root  8 Jan  1 02:24 pinctrl-names
-r--r--r-- 1 root root  4 Jan  1 02:24 pinctrl-single,function-mask
-r--r--r-- 1 root root  4 Jan  1 02:24 pinctrl-single,register-width
-r--r--r-- 1 root root  8 Jan  1 02:24 reg


看起来fragment里出现的pinctrl-single,pins跟pinctrl-single,function-mask很像。经查询pinctrl-single驱动的官方说明,有很多pinctrl-single,whatever这样的属性。其中pinctrl-single,pins用来定义引脚的复用功能。下面两个16进制数,左边的代表引脚地址的偏移量,右边的代表功能。下面解释一下这两个数字是怎么来的。

首先要分清楚引脚名($PINS)和板子引脚编号(Head_pin)的区别,前者是系统对各个引脚的编号,后者是板子上引脚的位置编号。系统中可以轻松查看每个引脚的信息
root@beaglebone:~# cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pins

registered pins: 142
pin 0 (44e10800) 00000031 pinctrl-single 
pin 1 (44e10804) 00000031 pinctrl-single 
pin 2 (44e10808) 00000031 pinctrl-single 
pin 3 (44e1080c) 00000031 pinctrl-single 
pin 4 (44e10810) 00000031 pinctrl-single  
. . .
pin 137 (44e10a24) 00000028 pinctrl-single 
pin 138 (44e10a28) 00000028 pinctrl-single 
pin 139 (44e10a2c) 00000028 pinctrl-single 
pin 140 (44e10a30) 00000028 pinctrl-single 
pin 141 (44e10a34) 00000020 pinctrl-single 


这里的编号就是$PINS,编号后面括号里的内容就是这个引脚功能的地址,再后面跟着的就是引脚功能的16进制表示(实际上是AM335x芯片内部的CONTROL_MODULE寄存器地址,详见TI公司的那本4000多页的手册,我在之前的日志里提到过)。实际上在.dts文件的pinctrl-single驱动中,并没有使用完整的地址,而是用了偏移地址,基准是pin0的地址,即44e10800。那每个芯片引脚对应到哪个板子的引脚呢?Derekmolloy老师为我们总结了一份PDF文档,里面写得很清楚,大家可以到这里去看一看。

说完地址,再说功能。
第2,1,0位表示引脚的复用功能0到7,从Derekmolloy总结的PDF中能轻松查到。
第3位是引脚上拉/下拉使能,0为使能
第4位是设置上拉/下拉,0为下拉,1为上拉
第5位是输入使能,1为既能输入也能输出,0为只能输出
第6位是slew的速度,0是高速,1是低速(这个不知道是什么东西)
再高位就没用了。

我们用上面的例子解释一下,
0x184 0x20 /* P9.24 uart1_txd.uart1_txd OUTPUT */
其中0x184是偏移地址,加上0x44e10800是0x44e10984,查到是第97个芯片引脚
# pin 97 (44e10984) 00000037 pinctrl-single
查PDF知对应到板子上是P9.24这个引脚。
功能寄存器的值是0x37,化成2进制低7位是0110111,对应着功能7(查PDF知是uart1_txd.uart1_txd),使能了内部上拉,使能了输入。
解释完毕。

那为什么要创建bb_uart1_pins子节点呢?我猜纯粹是为了下面能引用。这个写法bb_uart1_pins: pinmux_bb_uart1_pins中冒号是什么含义?我找遍google也没找到,难道也是为了引用方便起的别名??我能随便起名吗?

还有我为什么能在uart2这个target中随意添加pinctrl-names和pinctrl-0这两个属性?那我还能不能添加别的属性?这个问题也暂时没找到答案。不过据我观察所有涉及引脚的功能节点都是这样写的,暂时就当成一种规则吧。更大的问题是,如果我添加了一些别的属性,系统怎么能知道我的这个属性是在哪里定义的?要用哪个驱动?似乎系统的驱动都放在了/sys/bus/platform/drivers目录下,那这些驱动都定义了哪些变量或属性呢?

还有波特率,奇偶校验啥的能在这里定义吗??

总之,BB-UART1-00A0.dts这个文件中写了两个节点的overlay,第1个节点修改了两个引脚的功能,第2个节点使能了uart1然后引用了第1个节点的引脚修改。

附:因为这两个地址太常用了,我们也可以把它们存成系统环境变量
export SLOTS=/sys/devices/bone_capemgr.8/slots
export PINS=/sys/kernel/debug/pinctrl/44e10800.pinmux/pins
以后用$SLOTS和$PINS就可以代表这两个地址了,但注意仅对本次启动有效。

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s