宋宝华 Barry Song <21cnbao@gmail.com>
1. ARM Device Tree起源
- CPU的数量和类别
- 内存基地址和大小
- 总线和桥
- 外设连接
- 中断控制器和中断使用情况
- GPIO控制器和GPIO使用情况
- Clock控制器和Clock使用情况
2. Device Tree组成和结构
DTS (device tree source)
/ {node1 {a-string-property = "A string";a-string-list-property = "first string", "second string";a-byte-data-property = [0x01 0x23 0x34 0x56];child-node1 {first-child-property;second-child-property = <1>;a-string-property = "Hello, world";};child-node2 {};};node2 {an-empty-property;a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */child-node1 {};};
};
/ {compatible = "acme,coyotes-revenge";#address-cells = <1>;#size-cells = <1>;interrupt-parent = <&intc>;cpus {#address-cells = <1>;#size-cells = <0>;cpu@0 {compatible = "arm,cortex-a9";reg = <0>;};cpu@1 {compatible = "arm,cortex-a9";reg = <1>;};};serial@101f0000 {compatible = "arm,pl011";reg = <0x101f0000 0x1000 >;interrupts = < 1 0 >;};serial@101f2000 {compatible = "arm,pl011";reg = <0x101f2000 0x1000 >;interrupts = < 2 0 >;};gpio@101f3000 {compatible = "arm,pl061";reg = <0x101f3000 0x10000x101f4000 0x0010>;interrupts = < 3 0 >;};intc: interrupt-controller@10140000 {compatible = "arm,pl190";reg = <0x10140000 0x1000 >;interrupt-controller;#interrupt-cells = <2>;};spi@10115000 {compatible = "arm,pl022";reg = <0x10115000 0x1000 >;interrupts = < 4 0 >;};external-bus {#address-cells = <2>#size-cells = <1>;ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet1 0 0x10160000 0x10000 // Chipselect 2, i2c controller2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flashethernet@0,0 {compatible = "smc,smc91c111";reg = <0 0 0x1000>;interrupts = < 5 2 >;};i2c@1,0 {compatible = "acme,a1234-i2c-bus";#address-cells = <1>;#size-cells = <0>;reg = <1 0 0x1000>;interrupts = < 6 2 >;rtc@58 {compatible = "maxim,ds1338";reg = <58>;interrupts = < 7 3 >;};};flash@2,0 {compatible = "samsung,k8f1315ebm", "cfi-flash";reg = <2 0 0x4000000>;};};
};
flash@0,00000000 {compatible = "arm,vexpress-flash", "cfi-flash";reg = <0 0x00000000 0x04000000>,<1 0x00000000 0x04000000>;bank-width = <4>;};
- reg
- #address-cells
- #size-cells
ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet1 0 0x10160000 0x10000 // Chipselect 2, i2c controller2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
01 The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
02 interrupts.
03
04 The 2nd cell contains the interrupt number for the interrupt type.
05 SPI interrupts are in the range [0-987]. PPI interrupts are in the
06 range [0-15].
07
08 The 3rd cell is the flags, encoded as follows:
09 bits[3:0] trigger type and level flags.
10 1 = low-to-high edge triggered
11 2 = high-to-low edge triggered
12 4 = active high level-sensitive
13 8 = active low level-sensitive
14 bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of
15 the 8 possible cpus attached to the GIC. A bit set to '1' indicated
16 the interrupt is wired to that CPU. Only valid for PPI interrupts.
DTC (device tree compiler)
dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \vexpress-v2p-ca9.dtb \vexpress-v2p-ca15-tc1.dtb \vexpress-v2p-ca15_a7.dtb \xenvm-4.2.dtb
Device Tree Blob (.dtb)
Binding
Bootloader
3. Device Tree引发的BSP和驱动变更
90 static struct resource xxx_resources[] = {
91 [0] = {
92 .start = …,
93 .end = …,
94 .flags = IORESOURCE_MEM,
95 },
96 [1] = {
97 .start = …,
98 .end = …,
99 .flags = IORESOURCE_IRQ,
100 },
101 };
102
103 static struct platform_device xxx_device = {
104 .name = "xxx",
105 .id = -1,
106 .dev = {
107 .platform_data = &xxx_data,
108 },
109 .resource = xxx_resources,
110 .num_resources = ARRAY_SIZE(xxx_resources),
111 };
18 static struct of_device_id xxx_of_bus_ids[] __initdata = {
19 { .compatible = "simple-bus", },
20 {},
21 };
22
23 void __init xxx_mach_init(void)
24 {
25 of_platform_bus_probe(NULL, xxx_of_bus_ids, NULL);
26 }
32
33 #ifdef CONFIG_ARCH_XXX
38
39 DT_MACHINE_START(XXX_DT, "Generic XXX (Flattened Device Tree)")
41 …
45 .init_machine = xxx_mach_init,
46 …
49 MACHINE_END
50 #endif
145 static struct i2c_board_info __initdata afeb9260_i2c_devices[] = {
146 {
147 I2C_BOARD_INFO("tlv320aic23", 0x1a),
148 }, {
149 I2C_BOARD_INFO("fm3130", 0x68),
150 }, {
151 I2C_BOARD_INFO("24c64", 0x50),
152 },
153 };
i2c@1,0 {compatible = "acme,a1234-i2c-bus";…rtc@58 {compatible = "maxim,ds1338";reg = <58>;interrupts = < 7 3 >;};};
79 static struct spi_board_info afeb9260_spi_devices[] = {
80 { /* DataFlash chip */
81 .modalias = "mtd_dataflash",
82 .chip_select = 1,
83 .max_speed_hz = 15 * 1000 * 1000,
84 .bus_num = 0,
85 },
86 };
373 MACHINE_START(VEXPRESS, "ARM-Versatile Express")
374 .atag_offset = 0x100,
375 .smp = smp_ops(vexpress_smp_ops),
376 .map_io = v2m_map_io,
377 .init_early = v2m_init_early,
378 .init_irq = v2m_init_irq,
379 .timer = &v2m_timer,
380 .handle_irq = gic_handle_irq,
381 .init_machine = v2m_init,
382 .restart = vexpress_restart,
383 MACHINE_END
489 static const char * const v2m_dt_match[] __initconst = {
490 "arm,vexpress",
491 "xen,xenvm",
492 NULL,
493 };
495 DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
496 .dt_compat = v2m_dt_match,
497 .smp = smp_ops(vexpress_smp_ops),
498 .map_io = v2m_dt_map_io,
499 .init_early = v2m_dt_init_early,
500 .init_irq = v2m_dt_init_irq,
501 .timer = &v2m_dt_timer,
502 .init_machine = v2m_dt_init,
503 .handle_irq = gic_handle_irq,
504 .restart = vexpress_restart,
505 MACHINE_END
158 static char const *exynos5_dt_compat[] __initdata = {
159 "samsung,exynos5250",
160 "samsung,exynos5440",
161 NULL
162 };
163
177 DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)")
178 /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
179 .init_irq = exynos5_init_irq,
180 .smp = smp_ops(exynos_smp_ops),
181 .map_io = exynos5_dt_map_io,
182 .handle_irq = gic_handle_irq,
183 .init_machine = exynos5_dt_machine_init,
184 .init_late = exynos_init_late,
185 .timer = &exynos4_timer,
186 .dt_compat = exynos5_dt_compat,
187 .restart = exynos5_restart,
188 .reserve = exynos5_reserve,
189 MACHINE_END
126 static void __init exynos5_dt_machine_init(void)
127 {
128 …
149
150 if (of_machine_is_compatible("samsung,exynos5250"))
151 of_platform_populate(NULL, of_default_bus_match_table,
152 exynos5250_auxdata_lookup, NULL);
153 else if (of_machine_is_compatible("samsung,exynos5440"))
154 of_platform_populate(NULL, of_default_bus_match_table,
155 exynos5440_auxdata_lookup, NULL);
156 }
436 static const struct of_device_id a1234_i2c_of_match[] = {
437 { .compatible = "acme,a1234-i2c-bus ", },
438 {},
439 };
440 MODULE_DEVICE_TABLE(of, a1234_i2c_of_match);
441
442 static struct platform_driver i2c_a1234_driver = {
443 .driver = {
444 .name = "a1234-i2c-bus ",
445 .owner = THIS_MODULE,
449 .of_match_table = a1234_i2c_of_match,
450 },
451 .probe = i2c_a1234_probe,
452 .remove = i2c_a1234_remove,
453 };
454 module_platform_driver(i2c_a1234_driver);
1533 static const struct of_device_id wm8753_of_match[] = {
1534 { .compatible = "wlf,wm8753", },
1535 { }
1536 };
1537 MODULE_DEVICE_TABLE(of, wm8753_of_match);
1587 static struct spi_driver wm8753_spi_driver = {
1588 .driver = {
1589 .name = "wm8753",
1590 .owner = THIS_MODULE,
1591 .of_match_table = wm8753_of_match,
1592 },
1593 .probe = wm8753_spi_probe,
1594 .remove = wm8753_spi_remove,
1595 };
1640 static struct i2c_driver wm8753_i2c_driver = {
1641 .driver = {
1642 .name = "wm8753",
1643 .owner = THIS_MODULE,
1644 .of_match_table = wm8753_of_match,
1645 },
1646 .probe = wm8753_i2c_probe,
1647 .remove = wm8753_i2c_remove,
1648 .id_table = wm8753_i2c_id,
1649 };
90 static int spi_match_device(struct device *dev, struct device_driver *drv)
91 {
92 const struct spi_device *spi = to_spi_device(dev);
93 const struct spi_driver *sdrv = to_spi_driver(drv);
94
95 /* Attempt an OF style match */
96 if (of_driver_match_device(dev, drv))
97 return 1;
98
99 /* Then try ACPI */
100 if (acpi_driver_match_device(dev, drv))
101 return 1;
102
103 if (sdrv->id_table)
104 return !!spi_match_id(sdrv->id_table, spi);
105
106 return strcmp(spi->modalias, drv->name) == 0;
107 }
71 static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,
72 const struct spi_device *sdev)
73 {
74 while (id->name[0]) {
75 if (!strcmp(sdev->modalias, id->name))
76 return id;
77 id++;
78 }
79 return NULL;
80 }
4. 常用OF API
1682 if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
1683 is_marco = 1;
struct device_node *of_find_compatible_node(struct device_node *from,
534 of_property_read_u32_array(np, "arm,data-latency",
535 data, ARRAY_SIZE(data));
137 L2: cache-controller@1e00a000 {
138 compatible = "arm,pl310-cache";
139 reg = <0x1e00a000 0x1000>;
140 interrupts = <0 43 4>;
141 cache-level = <2>;
142 arm,data-latency = <1 1 1>;
143 arm,tag-latency = <1 1 1>;
144 }
513 static inline int of_property_read_u8(const struct device_node *np,
514 const char *propname,
515 u8 *out_value)
516 {
517 return of_property_read_u8_array(np, propname, out_value, 1);
518 }
519
520 static inline int of_property_read_u16(const struct device_node *np,
521 const char *propname,
522 u16 *out_value)
523 {
524 return of_property_read_u16_array(np, propname, out_value, 1);
525 }
526
527 static inline int of_property_read_u32(const struct device_node *np,
528 const char *propname,
529 u32 *out_value)
530 {
531 return of_property_read_u32_array(np, propname, out_value, 1);
532 }
int of_property_read_string(struct device_node *np, const char
1759 const char *of_clk_get_parent_name(struct device_node *np, int index)
1760 {
1761 struct of_phandle_args clkspec;
1762 const char *clk_name;
1763 int rc;
1764
1765 if (index < 0)
1766 return NULL;
1767
1768 rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
1769 &clkspec);
1770 if (rc)
1771 return NULL;
1772
1773 if (of_property_read_string_index(clkspec.np, "clock-output-names",
1774 clkspec.args_count ? clkspec.args[0] : 0,
1775 &clk_name) < 0)
1776 clk_name = clkspec.np->name;
1777
1778 of_node_put(clkspec.np);
1779 return clk_name;
1780 }
1781 EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
static inline bool of_property_read_bool(const struct device_node *np,