设备树实例(一)
如何单独编译设备树?
cd linux-x.xx & make dtbs
生成的dtb在目录linux-x.xx/arch/xxx/boot/dts下
反编译dtb,生成dts: linux-x.xx/scripts/dtc/dtc -I dtb -O dts xxxx.dtb -o xxxx.dts
全志A64实例:
arch/arm64/boot/dts/Makefile:
1 #dtb-$(CONFIG_ARCH_SUN50I) += sun50iw1p1-fpga.dtb sun50iw1p1-soc.dtb 2 dtb-$(CONFIG_ARCH_SUN50I) += sun50iw1p1-t1.dtb #add by kevin_hwang 3 4 targets += dtbs 5 6 DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES)) 7 ifneq ($(DTB_NAMES),) 8 DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES)) 9 else 10 DTB_LIST := $(dtb-y) 11 endif 12 targets += $(DTB_LIST) 13 14 dtbs: $(addprefix $(obj)/, $(DTB_LIST)) 15 16 clean-files := dts/*.dtb *.dtb
目的把sun50iw1p1-soc.dts生成sun50iw1p1-soc.dtb
sun50iw1p1-soc.dts:
1 /* 2 * Allwinner Technology CO., Ltd. sun50iw1p1 fpga board. 3 * 4 * 5 */ 6 7 /dts-v1/; 8 #include "sun50iw1p1.dtsi" 9 10 /{ 11 12 soc@01c00000 { 13 ...... 14 ...... 15 ...... 16 }; 17 };
Line 8:包含sun50iw1p1.dtsi,一般表示这个SOC公共部分,而sun50iw1p1-soc.dts是延伸扩展公共部分。
sun50iw1p1.dtsi:
1 /* 2 * Allwinner Technology CO., Ltd. sun50iw1p1 platform 3 * modify base on juno.dts 4 */ 5 6 #include <dt-bindings/interrupt-controller/arm-gic.h> 7 #include <dt-bindings/gpio/gpio.h> 8 #include "sun50iw1p1-clk.dtsi" 9 #include "sun50iw1p1-pinctrl.dtsi" 10 / { 11 model = "sun50iw1p1"; 12 compatible = "arm,sun50iw1p1", "arm,sun50iw1p1"; 13 interrupt-parent = <&gic>; 14 #address-cells = <2>; 15 #size-cells = <2>; 16 17 aliases { 18 serial0 = &uart0; 19 ...... 20 ...... 21 ...... 22 boot_disp = &boot_disp; 23 }; 24 25 chosen { 26 bootargs = "earlyprintk=sunxi-uart,0x01c28000 loglevel=8 initcall_debug=1 console=ttyS0 init=/init"; 27 linux,initrd-start = <0x0 0x0>; 28 linux,initrd-end = <0x0 0x0>; 29 }; 30 31 cpus { 32 #address-cells = <2>; 33 #size-cells = <0>; 34 35 cpu@0 { 36 device_type = "cpu"; 37 compatible = "arm,cortex-a53","arm,armv8"; 38 reg = <0x0 0x0>; 39 enable-method = "psci"; 40 cpufreq_tbl = < 480000 600000 720000 816000 1008000 41 1104000 1152000 1200000 1344000>; 42 clock-latency = <2000000>; 43 clock-frequency = <1008000000>; 44 cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0 &SYS_SLEEP_0>; 45 }; 46 cpu@1 { 47 device_type = "cpu"; 48 compatible = "arm,cortex-a53","arm,armv8"; 49 reg = <0x0 0x1>; 50 enable-method = "psci"; 51 clock-frequency = <1008000000>; 52 cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0 &SYS_SLEEP_0>; 53 }; 54 cpu@2 { 55 ...... 56 ...... 57 ...... 58 }; 59 cpu@3 { 60 ...... 61 ...... 62 ...... 63 }; 64 }; 65 66 memory@40000000 { 67 device_type = "memory"; 68 reg = <0x00000000 0x40000000 0x00000000 0x40000000>; 69 }; 70 71 gic: interrupt-controller@1c81000 { 72 compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; 73 #interrupt-cells = <3>; 74 #address-cells = <0>; 75 device_type = "gic"; 76 interrupt-controller; 77 reg = <0x0 0x01c81000 0 0x1000>, /* GIC Dist */ 78 <0x0 0x01c82000 0 0x2000>, /* GIC CPU */ 79 <0x0 0x01c84000 0 0x2000>, /* GIC VCPU Control */ 80 <0x0 0x01c86000 0 0x2000>; /* GIC VCPU */ 81 interrupts = <GIC_PPI 9 0xf04>; /* GIC Maintenence IRQ */ 82 }; 83 84 soc: soc@01c00000 { 85 compatible = "simple-bus"; 86 #address-cells = <2>; 87 #size-cells = <2>; 88 ranges; 89 device_type = "soc"; 90 91 uart0: uart@01c28000 { 92 compatible = "allwinner,sun50i-uart"; 93 device_type = "uart0"; 94 reg = <0x0 0x01c28000 0x0 0x400>; 95 interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; 96 clocks = <&clk_uart0>; 97 pinctrl-names = "default", "sleep"; 98 pinctrl-0 = <&uart0_pins_a>; 99 pinctrl-1 = <&uart0_pins_b>; 100 uart0_port = <0>; 101 uart0_type = <2>; 102 status = "disabled"; 103 ...... 104 ...... 105 ...... 106 }; 107 ...... 108 ...... 109 ...... 110 }; 111 };
*note:<name>[@<unit-address>]是节点的格式,其中unit-address是单位偏移地址,本人验证去掉[]内的内容依然可以运行,也没在source code找到必须存在的理由。
“/"代表根节点;
“model”是板的ID;
"compatible"是平台兼容,一般格式是"manufacturer,model"。内核或者uboot依靠这个属性找到相对应driver,若"compatible"出现多个属性,按序匹配driver;
“#address-cells”是address的单位(32bit);
“#size-cells”是length的单位(32bit);
"reg"是寄存器,格式是"<address,length>",作为平台内存资源;
"aliase" 是别名,必须节点全称,可以通过地址引用获取;
”chosen“是板级启动参数;
"cpus"是SOC的CPU信息,可以改变运行频率或者开关CPU;
"memory"是板级内存的信息。
"interrupts"是中断控制器,根据SOC自定义格式,这里是<输入类型 中断号 触发方式>,作为平台中断资源;
“interrupt-controller”指示这个节点是中断控制节点;
"[label:]"如gic: interrupt-controller@1c81000,这个标签可以作为地址赋值到其他节点的属性;
“device_type":设备类型,寻找节点可以依据这个属性;
"status"是开关节点设备的状态,取值"okay"或者"ok"表示使能,"disabled"表示失能。
Line 10和11包含"sun50iw1p1-clk.dtsi"和"sun50iw1p1-pinctrl.dtsi"以下简略查看代码:
sun50iw1p1-clk.dtsi:
1 /{ 2 clocks { 3 compatible = "allwinner,sunxi-clk-init"; 4 device_type = "clocks"; 5 #address-cells = <2>; 6 #size-cells = <2>; 7 ranges; 8 reg = <0x0 0x01c20000 0x0 0x0320> , /*cpux space*/ 9 <0x0 0x01f01400 0x0 0x00B0> , /*cpus space*/ 10 <0x0 0x01f00060 0x0 0x4>; 11 /* register fixed rate clock*/ 12 clk_uart0: uart0 { 13 #clock-cells = <0>; 14 compatible = "allwinner,sunxi-periph-clock"; 15 clock-output-names = "uart0"; 16 }; 17 ...... 18 ...... 19 ...... 20 21 };/*clocks end*/ 22 };
在"sun50iw1p1.dtsi"中"uart0: uart@01c28000"节点的"clock = <&clk_uart0>",引用的是"sun50iw1p1-clk.dtsi"中的"clk_uart0: uart0"节点。
sun50iw1p1-pinctrl.dtsi:
1 /* 2 * Allwinner 1689 pin config info. 3 */ 4 / { 5 soc@01c00000{ 6 ...... 7 ...... 8 ...... 9 pio: pinctrl@01c20800 { 10 compatible = "allwinner,sun50i-pinctrl"; 11 reg = <0x0 0x01c20800 0x0 0x400>; 12 interrupts = <GIC_SPI 11 4>, 13 <GIC_SPI 17 4>, 14 <GIC_SPI 21 4>; 15 device_type = "pio"; 16 clocks = <&clk_pio>; 17 gpio-controller; 18 interrupt-controller; 19 #interrupt-cells = <2>; 20 #size-cells = <0>; 21 #gpio-cells = <6>; 22 23 uart0_pins_a: uart0@0 { 24 allwinner,pins = "PB8", "PB9"; 25 allwinner,pname = "uart0_tx", "uart0_rx"; 26 allwinner,function = "uart0"; 27 allwinner,muxsel = <4>; 28 allwinner,drive = <1>; 29 allwinner,pull = <1>; 30 }; 31 32 uart0_pins_b: uart0@1 { 33 allwinner,pins = "PB8", "PB9"; 34 allwinner,function = "io_disabled"; 35 allwinner,muxsel = <7>; 36 allwinner,drive = <1>; 37 allwinner,pull = <1>; 38 }; 39 ...... 40 ...... 41 ...... 42 }; 43 ...... 44 ...... 45 ...... 46 }; 47 };
在"sun50iw1p1.dtsi"中"uart0: uart@01c28000"节点的"pinctrl-0 = <&uart0_pins_a>"和"pinctrl-1 = <&uart0_pins_b>",引用的是"sun50iw1p1-pinctrl.dtsi"中的"uart0_pins_a"和"uart0_pins_b"节点,分别对应工作和睡眠的IO状态。"sun50iw1p1-pinctrl.dtsi"是全志a64的具体io配置。
编译dts生成dtb,然后反编译得到.dts,再看看生成的代码:
1 / { 2 model = "sun50iw1p1"; 3 compatible = "arm,sun50iw1p1", "arm,sun50iw1p1"; 4 interrupt-parent = <0x1>; 5 #address-cells = <0x2>; 6 #size-cells = <0x2>; 7 8 clocks { 9 compatible = "allwinner,sunxi-clk-init"; 10 device_type = "clocks"; 11 #address-cells = <0x2>; 12 #size-cells = <0x2>; 13 ranges; 14 reg = <0x0 0x1c20000 0x0 0x320 0x0 0x1f01400 0x0 0xb0 0x0 0x1f00060 0x0 0x4>; 15 16 uart0 { 17 #clock-cells = <0x0>; 18 compatible = "allwinner,sunxi-periph-clock"; 19 clock-output-names = "uart0"; 20 linux,phandle = <0x18>; 21 phandle = <0x18>; 22 }; 23 24 ...... 25 ...... 26 ...... 27 }; 28 29 soc@01c00000 { 30 compatible = "simple-bus"; 31 #address-cells = <0x2>; 32 #size-cells = <0x2>; 33 ranges; 34 device_type = "soc"; 35 36 pinctrl@01c20800 { 37 compatible = "allwinner,sun50i-pinctrl"; 38 reg = <0x0 0x1c20800 0x0 0x400>; 39 interrupts = <0x0 0xb 0x4 0x0 0x11 0x4 0x0 0x15 0x4>; 40 device_type = "pio"; 41 clocks = <0xa>; 42 gpio-controller; 43 interrupt-controller; 44 #interrupt-cells = <0x2>; 45 #size-cells = <0x0>; 46 #gpio-cells = <0x6>; 47 linux,phandle = <0x30>; 48 phandle = <0x30>; 49 50 uart0@0 { 51 allwinner,pins = "PB8", "PB9"; 52 allwinner,pname = "uart0_tx", "uart0_rx"; 53 allwinner,function = "uart0"; 54 allwinner,muxsel = <0x4>; 55 allwinner,drive = <0x1>; 56 allwinner,pull = <0x1>; 57 linux,phandle = <0x19>; 58 phandle = <0x19>; 59 }; 60 61 uart0@1 { 62 allwinner,pins = "PB8", "PB9"; 63 allwinner,function = "io_disabled"; 64 allwinner,muxsel = <0x7>; 65 allwinner,drive = <0x1>; 66 allwinner,pull = <0x1>; 67 linux,phandle = <0x1a>; 68 phandle = <0x1a>; 69 }; 70 71 ...... 72 ...... 73 ...... 74 }; 75 76 uart@01c28000 { 77 compatible = "allwinner,sun50i-uart"; 78 device_type = "uart0"; 79 reg = <0x0 0x1c28000 0x0 0x400>; 80 interrupts = <0x0 0x0 0x4>; 81 clocks = <0x18>; 82 pinctrl-names = "default", "sleep"; 83 pinctrl-0 = <0x19>; 84 pinctrl-1 = <0x1a>; 85 uart0_port = <0x0>; 86 uart0_type = <0x2>; 87 status = "disabled"; 88 }; 89 90 ...... 91 ...... 92 ...... 93 94 aliases { 95 serial0 = "/soc@01c00000/uart@01c28000"; 96 ...... 97 ...... 98 ...... 99 boot_disp = "/soc@01c00000/boot_disp"; 100 }; 101 102 chosen { 103 bootargs = "earlyprintk=sunxi-uart,0x01c28000 loglevel=8 initcall_debug=1 console=ttyS0 init=/init"; 104 linux,initrd-start = <0x0 0x0>; 105 linux,initrd-end = <0x0 0x0>; 106 }; 107 108 cpus { 109 #address-cells = <0x2>; 110 #size-cells = <0x0>; 111 112 cpu@0 { 113 device_type = "cpu"; 114 compatible = "arm,cortex-a53", "arm,armv8"; 115 reg = <0x0 0x0>; 116 enable-method = "psci"; 117 cpufreq_tbl = <0x75300 0x927c0 0xafc80 0xc7380 0xf6180 0x10d880 0x119400 0x124f80 0x148200>; 118 clock-latency = <0x1e8480>; 119 clock-frequency = <0x3c14dc00>; 120 cpu-idle-states = <0x8e 0x8f 0x90>; 121 }; 122 123 cpu@1 { 124 device_type = "cpu"; 125 compatible = "arm,cortex-a53", "arm,armv8"; 126 reg = <0x0 0x1>; 127 enable-method = "psci"; 128 clock-frequency = <0x3c14dc00>; 129 cpu-idle-states = <0x8e 0x8f 0x90>; 130 }; 131 132 cpu@2 { 133 ...... 134 ...... 135 ...... 136 }; 137 138 cpu@3 { 139 ...... 140 ...... 141 ...... 142 }; 143 ...... 144 ...... 145 ...... 146 }; 147 148 memory@40000000 { 149 device_type = "memory"; 150 reg = <0x0 0x40000000 0x0 0x40000000>; 151 }; 152 153 interrupt-controller@1c81000 { 154 compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; 155 #interrupt-cells = <0x3>; 156 #address-cells = <0x0>; 157 device_type = "gic"; 158 interrupt-controller; 159 reg = <0x0 0x1c81000 0x0 0x1000 0x0 0x1c82000 0x0 0x2000 0x0 0x1c84000 0x0 0x2000 0x0 0x1c86000 0x0 0x2000>; 160 interrupts = <0x1 0x9 0xf04>; 161 linux,phandle = <0x1>; 162 phandle = <0x1>; 163 }; 164 165 ...... 166 ...... 167 ...... 168 };
"sun50iw1p1-clk.dtsi"的clock和"sun50iw1p1-pinctrl.dtsi"的pinctrl@01c20800在根目录自动寻找适合的文件路径合并。
可以看出引用地址其实就是取目的地址的"phandle = <0x>"的值如uart@01c28000{pinctrl-0 = <0x19>;}其实就是找到phandle = <0x19>的属性,这个属性在uart0@0节点下面。
而”aliases“则引用地址的全路径,不用phandle。