Linux设备树学习1 - DTS文件格式

一. 设备树简介

        Linux设备树,英文称为Devicetree,设备树的源文件称为DTS。设备树是用于描述系统的硬件资源。例如在Linux2.x时,我们写驱动程序需要在代码中写死我们需要使用的GPIO等资源,但是当硬件改板或是开发另一款设备时,GPIO有所改动时,我们就要修改驱动源码了,这样修改有可能会遗漏,特别GPIO改动太大时。Linux3.x内核出现设备树时,我们就可以在可以在一个设备树文件中把GPIO资源都修改好,不仅提高了效率,而且也避免了出错。

二. DTS文件

1. DTS文件类型

        设备树文件有两种文件,以.dts和.dtsi结尾的文件。dtsi文件通常是用来描述CPU所支持的外设 ,dts文件通常是用来描述具体单板的硬件资源使用。所以dtsi文件是用来被dts文件包含的。它们的关系类似于C语言中的.c和.h文件的关系。

2. DTS文件布局

[label:] node-name[@unit-address] {
    [properties definitions]
    [child nodes]
};

dtsi示例代码:

/ {
	#address-cells = <1>;
	#size-cells = <1>;
	compatible = "ralink,mtk7620n-soc";
 
	cpus {
		cpu@0 {
			compatible = "mips,mips24KEc";
		};
	};
 
	chosen {
		bootargs = "console=ttyS0,57600";
	};
 
	cpuintc: cpuintc@0 {
		#address-cells = <0>;
		#interrupt-cells = <1>;
		interrupt-controller;
		compatible = "mti,cpu-interrupt-controller";
	};
 
	palmbus@10000000 {
		compatible = "palmbus";
		reg = <0x10000000 0x200000>;
                ranges = <0x0 0x10000000 0x1FFFFF>;
 
		#address-cells = <1>;
		#size-cells = <1>;
 
		sysc@0 {
			compatible = "ralink,mt7620a-sysc", "ralink,rt3050-sysc";
			reg = <0x0 0x100>;
		};
 
		timer@100 {
			compatible = "ralink,mt7620a-timer", "ralink,rt2880-timer";
			reg = <0x100 0x20>;
 
			interrupt-parent = <&intc>;
			interrupts = <1>;
		};
 
		watchdog@120 {
			compatible = "ralink,mt7620a-wdt", "ralink,rt2880-wdt";
			reg = <0x120 0x10>;
 
			resets = <&rstctrl 8>;
			reset-names = "wdt";
 
			interrupt-parent = <&intc>;
			interrupts = <1>;
		};
 
		intc: intc@200 {
			compatible = "ralink,mt7620a-intc", "ralink,rt2880-intc";
			reg = <0x200 0x100>;
 
			resets = <&rstctrl 19>;
			reset-names = "intc";
 
			interrupt-controller;
			#interrupt-cells = <1>;
 
			interrupt-parent = <&cpuintc>;
			interrupts = <2>;
		};
 
		memc@300 {
			compatible = "ralink,mt7620a-memc", "ralink,rt3050-memc";
			reg = <0x300 0x100>;
 
			resets = <&rstctrl 20>;
			reset-names = "mc";
 
			interrupt-parent = <&intc>;
			interrupts = <3>;
		};
 
		gpio0: gpio@600 {
			compatible = "ralink,mt7620a-gpio", "ralink,rt2880-gpio";
			reg = <0x600 0x34>;
 
			resets = <&rstctrl 13>;
			reset-names = "pio";
 
			interrupt-parent = <&intc>;
			interrupts = <6>;
 
			gpio-controller;
			#gpio-cells = <2>;
 
			ralink,gpio-base = <0>;
			ralink,num-gpios = <24>;
			ralink,register-map = [ 00 04 08 0c
						20 24 28 2c
						30 34 ];
		};
 
		gpio1: gpio@638 {
			compatible = "ralink,mt7620a-gpio", "ralink,rt2880-gpio";
			reg = <0x638 0x24>;
 
			interrupt-parent = <&intc>;
			interrupts = <6>;
 
			gpio-controller;
			#gpio-cells = <2>;
 
			ralink,gpio-base = <24>;
			ralink,num-gpios = <16>;
			ralink,register-map = [ 00 04 08 0c
						10 14 18 1c
						20 24 ];
 
			#status = "disabled";
			status = "okay";
		};
 
		gpio2: gpio@660 {
			compatible = "ralink,mt7620a-gpio", "ralink,rt2880-gpio";
			reg = <0x660 0x24>;
 
			interrupt-parent = <&intc>;
			interrupts = <6>;
 
			gpio-controller;
			#gpio-cells = <2>;
 
			ralink,gpio-base = <40>;
			ralink,num-gpios = <32>;
			ralink,register-map = [ 00 04 08 0c
						10 14 18 1c
						20 24 ];
 
			status = "disabled";
		};
 
		gpio3: gpio@688 {
			compatible = "ralink,mt7620a-gpio", "ralink,rt2880-gpio";
			reg = <0x688 0x24>;
 
			interrupt-parent = <&intc>;
			interrupts = <6>;
 
			gpio-controller;
			#gpio-cells = <2>;
 
			ralink,gpio-base = <72>;
			ralink,num-gpios = <1>;
			ralink,register-map = [ 00 04 08 0c
						10 14 18 1c
						20 24 ];
 
			status = "disabled";
		};
        
        i2c: i2c@900 {
            compatible = "ralink,rt2880-i2c";
            reg = <0x900 0x100>;
 
            resets = <&rstctrl 16>;
            reset-names = "i2c";
 
            #address-cells = <1>;
            #size-cells = <0>;
 
            pinctrl-names = "default";
            pinctrl-0 = <&i2c_pins>;
        };
 
		spi@b00 {
			compatible = "ralink,mt7620a-spi", "ralink,rt2880-spi";
			reg = <0xb00 0x100>;
 
			resets = <&rstctrl 18>;
			reset-names = "spi";
 
			#address-cells = <1>;
			#size-cells = <1>;
 
			pinctrl-names = "default";
			pinctrl-0 = <&spi_pins>;
		};
 
		uartlite@c00 {
			compatible = "ralink,mt7620a-uart", "ralink,rt2880-uart", "ns16550a";
			reg = <0xc00 0x100>;
 
			resets = <&rstctrl 19>;
			reset-names = "uartl";
 
			interrupt-parent = <&intc>;
			interrupts = <12>;
 
			reg-shift = <2>;
 
			pinctrl-names = "default";
			pinctrl-0 = <&uartlite_pins>;
		};
 
		systick@d00 {
			compatible = "ralink,mt7620a-systick", "ralink,cevt-systick";
			reg = <0xd00 0x10>;
 
			resets = <&rstctrl 28>;
			reset-names = "intc";
 
			interrupt-parent = <&cpuintc>;
			interrupts = <7>;
		};
	};
 
	pinctrl {
		compatible = "ralink,rt2880-pinmux";
		pinctrl-names = "default";
		pinctrl-0 = <&state_default>;
		state_default: pinctrl0 {
		};
		spi_pins: spi {
			spi {
				ralink,group = "spi";
				ralink,function = "spi";
			};
		};
		uartlite_pins: uartlite {
			uart {
				ralink,group = "uartlite";
				ralink,function = "uartlite";
			};
		};
	};
 
	rstctrl: rstctrl {
		compatible = "ralink,mt7620a-reset", "ralink,rt2880-reset";
		#reset-cells = <1>;
	};
 
	usbphy: usbphy {
		compatible = "ralink,mt7620a-usbphy";
		#phy-cells = <1>;
 
		resets = <&rstctrl 22 &rstctrl 25>;
		reset-names = "host", "device";
	};
 
	ethernet@10100000 {
		compatible = "ralink,mt7620a-eth";
		reg = <0x10100000 10000>;
 
		#address-cells = <1>;
		#size-cells = <0>;
 
		interrupt-parent = <&cpuintc>;
		interrupts = <5>;
 
		resets = <&rstctrl 21 &rstctrl 23>;
		reset-names = "fe", "esw";
 
		mdio-bus {
			#address-cells = <1>;
			#size-cells = <0>;
 
			status = "disabled";
		};
	};
 
	gsw@10110000 {
		compatible = "ralink,mt7620a-gsw";
		reg = <0x10110000 8000>;
 
		resets = <&rstctrl 23>;
		reset-names = "esw";
 
		interrupt-parent = <&intc>;
		interrupts = <17>;
		ralink,port4 = "gmac";
	};
 
	ehci@101c0000 {
		compatible = "ralink,rt3xxx-ehci";
		reg = <0x101c0000 0x1000>;
 
		interrupt-parent = <&intc>;
		interrupts = <18>;
 
		phys = <&usbphy 1>;
		phy-names = "usb";
 
		status = "disabled";
	};
 
	ohci@101c1000 {
		compatible = "ralink,rt3xxx-ohci";
		reg = <0x101c1000 0x1000>;
 
		phys = <&usbphy 1>;
		phy-names = "usb";
 
		interrupt-parent = <&intc>;
		interrupts = <18>;
 
		status = "disabled";
	};
 
	wmac@10180000 {
		compatible = "ralink,rt7620-wmac", "ralink,rt2880-wmac";
		reg = <0x10180000 40000>;
 
		interrupt-parent = <&cpuintc>;
		interrupts = <6>;
 
		ralink,eeprom = "soc_wmac.eeprom";
	};
};

dts文件示例:

/dts-v1/;
 
/include/ "mt7620n.dtsi"
 
/ {
	compatible = "mediatek,hiwooya", "ralink,mt7620n-soc";
	model = "Wooya IOT Smart 7620";
 
	palmbus@10000000 {
		gpio0: gpio@600 {
			status = "okay";
		};
	
		gpio2: gpio@660 {
			status = "okay";
		};
 
		gpio3: gpio@688 {
			status = "okay";
		};
 
		spi@b00 {
			status = "okay";
 
			m25p80@0 {
				#address-cells = <1>;
				#size-cells = <1>;
				compatible = "mx25l12805d";
				reg = <0 0>;
				linux,modalias = "m25p80", "w25q128";
				spi-max-frequency = <10000000>;
 
				partition@0 {
					label = "u-boot";
					reg = <0x0 0x30000>;
					read-only;
				};
 
				partition@30000 {
					label = "u-boot-env";
					reg = <0x30000 0x10000>;
					read-only;
				};
 
				factory: partition@40000 {
					label = "factory";
					reg = <0x40000 0x10000>;
					read-only;
				};
 
				partition@50000 {
					label = "firmware";
					reg = <0x50000 0xdb0000>;
				};
				
				partition@ff0000 {
					label = "config";
					reg = <0xe00000 0x100000>;
				};
			};
		};
	};
	
	lte-leds {
		compatible = "gpio-leds";
		red-led {
			label = "red";
			gpios = <&gpio0 7 1>;
			linux,default-trigger = "none";
		};
		
		green-led {
			label = "green";
			gpios = <&gpio0 1 1>;
		};
		
		blue-led {
			label = "blue";
			gpios = <&gpio1 14 1>;
			linux,default-trigger = "none";
		};
		l1 {
			label = "led1";
			gpios = <&gpio2 6 1>;
			linux,default-trigger = "none";
		};
		l2 {
			label = "led2";
			gpios = <&gpio2 11 1>;
			linux,default-trigger = "none";
		};
		l3 {
			label = "led3";
			gpios = <&gpio2 10 1>;
			linux,default-trigger = "none";
		};
		l4 {
			label = "led4";
			gpios = <&gpio2 19 1>;
			linux,default-trigger = "none";
		};
 
	};
	
	gpio-keys-polled {
    compatible = "gpio-keys-polled";
	#address-cells = <1>;
	#size-cells = <0>;
	poll-interval = <20>;
	reset {
			label = "reset";
			gpios = <&gpio1 13 1>;
			linux,code = <0x198>;
		  };
	}; 
 
	ehci@101c0000 {
		status = "okay";
	};
 
	ohci@101c1000 {
		status = "okay";
	};
 
	ethernet@10100000 {
		mtd-mac-address = <&factory 0x4>;
		ralink,port-map = "llllw";
	};
 
	wmac@10180000 {
		ralink,mtd-eeprom = <&factory 0>;
	};
 
	pinctrl {
		state_default: pinctrl0 {
			default {
				ralink,group = "pa", "spi refclk", "wdt", "uartf", "nd_sd";
				ralink,function = "gpio";
			};
            
            i2c_pins: i2c_pins {
                i2c_pins {
                        ralink,group = "i2c";
                        ralink,function = "i2c";
                };
            };
		};
	};
    
    
};

        从上面设备的设备树代码来看,设备树dts文件需要指定dts的版本号(/dts-v1/;),包含了什么dtsi文件(/include/ "mt7620n.dtsi"),以/开始的根节点和节点名开始的子节点。简化代码如下

/dts-v1/;
 
/include/ "mt7620n.dtsi"
 
/ {
	compatible = "mediatek,hiwooya", "ralink,mt7620n-soc";
	model = "Wooya IOT Smart 7620";
 
	palmbus@10000000 {
        ........
	};
	
	lte-leds {
		compatible = "gpio-leds";
		red-led {
            ........
		};
 
	};
	
	gpio-keys-polled {
        compatible = "gpio-keys-polled";
        ........
	}; 
 
	ohci@101c1000 {
		status = "okay";
	};
};

        从上面代码可以看出设备树的节点是以node-name@unit-address { }组成,node-name一般以字母数字等ASCII码组成,根节点是一种特殊节点。有些节点带有unit-address,而有些没有,节点都有一个compatible属性等。接下来详细介绍。        

三. DTS设备节点属性介绍

1. compatible

        compatible可以包含一个或者多个字符串,中间以逗号隔开。主要用来指定驱动代码设备的型号名称。当驱动代码中的名称和设备树的某个节点compatible属性名称一样,驱动代码则调用probe函数。示例如下:

compatible = "fsl,mpc8641", "ns16550";

2. model

        主要用来指定产商的设备型号。示例如下

model = "fsl,MPC8349EMITX";

3. phandle

        phandle属性指定一个设备树中唯一的数字标识。带有phandle属性的节点可以被其他节点引用,示例如下

pic@10000000 {
    phandle = <1>;
    interrupt-controller;
};
 
another-device-node {
    interrupt-parent = <1>;
};

4. status

        status属性指示设备的可操作的状态,可用的状态如下:

okay :表示设备可以操作

disabled :表示设备当前不可操作,但未来可能可以操作

fail :表示设备不可操作,检测到严重的错误,如果不修复无法操作。

fail-sss :和fail的含义类型

5. #address-cells和#size-cells

        #address-cells和#size-cells属性可用于任何在设备树层次结构中拥有子节点的设备节点,并描述子设备节点应该如何被寻址。#address-cells属性定义了该节点的子节点中的reg属性该用几个u32类型的数字编码其地址字段。#size-cells则定义了reg属性的size字段需要使用的u32类型的数字的数量。#address-cells和#size-cells都不从父节点那继承,需要明确的定义。示例如下

soc {
    #address-cells = <1>;
    #size-cells = <1>;
    serial {
        compatible = "ns16550";
        reg = <0x4600 0x100>;
        clock-frequency = <0>;
        interrupts = <0xA 0x8>;
        interrupt-parent = <&ipic>;
    };
};

6. reg

        reg属性描述了在父总线定义的地址空间中设备资源的地址。通常表示寄存器映射在内存中的起始地址和长度,或者CPU寄存器地址的真实地址。

        当寄存器在内存中有两段地址时,reg需要指定两对#address-cells和#size-cells,示例如下

reg = <0x3000 0x20 0xFE00 0x100>;

7. ranges

        以后补充

8. dma-ranges

        以后补充

四. DTS设备节点类型介绍

1. 根节点(/)

        设备树有一个根节点,其余节点都是子节点,根节点使用/表示,示意代码如下

/ {
 
};

2. /aliases

        aliases节点是用来定义一个设备节点的别名的,aliases节点应该在设备树的根节点中使用。

aliases的属性名是需要指定的别名,属性值是设备树中某个节点的完整路径,示例如下

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

3. /memory

       memory节点是用于描述系统的物理内存的的布局的,如果系统有多个地址范围的内存,则多个memory节点需要创建,或者在reg节点中指定多个范围。示例如下

memory@0 {
    device_type = "memory";
    reg = <0x000000000 0x00000000 0x00000000 0x80000000
           0x000000001 0x00000000 0x00000001 0x00000000>;
};
memory@0 {
    device_type = "memory";
    reg = <0x000000000 0x00000000 0x00000000 0x80000000>;
};
memory@100000000 {
    device_type = "memory";
    reg = <0x000000001 0x00000000 0x00000001 0x00000000>;
};

4. /chosen

        chosen节点不用来描述一个真实的设备,而是描述设备的启动和运行参数,例如bootargs,示例如下

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

5. /cpus

        后面补充

6. /cpus/cpu*

        后面补充

五. 总结

        本文主要介绍了设备树的格式布局,属性名,设备节点名的使用。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值