在早期的arm linux内核中,板级的细节信息使用代码的形式,存放在arch/arm目录中,这些板级代码只对相应的开发板有用,却被硬编码进linux内核,显然这不是一种好的方法。Device Tree是一种描述硬件的数据结构,它包含了板级硬件细节信息,通过Device Tree,可以把硬件信息传递给内核,而不需要再硬编码了。

1. s3c2416设备树

Linux内核已经完整支持s3c2416的设备树,基于s3c2416平台的目标板,可以不用更改内核代码,不同设备,不同的板级配置在Device Tree中实现。

1.1. 修改主目录Makefile

Makefile默认获取得是主机的架构以及编译环境,我们的内核是要运行在arm平台上,所以修改ARCH=arm,

  1. CROSS_COMPILE=arm-linux-

1.2. mach-s3c2416-dt.c

在mach-s3c24xx目录下已实现了s3c24xx系列的平台代码,其中mach-s3c2416-dt.c实现了基于s3c2416设备树的机器描述符定义。

Linux内核通过machine_desc结构体来控制系统体系架构相关部分的初始化,其通过DT_MACHINE_START/MACHINE_END宏定义进行描述。

  1. DT_MACHINE_START(S3C2416_DT,"Samsung S3C2416 (Flattened Device Tree)")
  2. .dt_compat =s3c2416_dt_compat,
  3. .map_io =s3c2416_dt_map_io,
  4. .init_irq =irqchip_init,
  5. .init_machine = s3c2416_dt_machine_init,
  6. MACHINE_END

Linux内核在启动时会配对bootloader传递的dtb(device tree binary),当配对到s3c2416_dt_compat,则获取s3c2416的机器描述符进行片上系统的初始化。从start_kernel()开始启动内核,按顺序调用machine_desc中的map_io()、init_irq()、init_machine()。

start_kernel()->setup_arch()->paging_init()->devicemaps_init()->map_io()实现调用s3c2416_dt_map_io (),默认外设IO资源地址不在Linux内核空间(3G~4G),需访问一些外设IO资源,可以在初始化页表时,静态映射IO资源空间到内核地址空间。

start_kernel()->init_IRQ()->init_irq()实现调用irqchip_init (),该函数将查找__irqchip_of_table,匹配到Device Tree中的中断控制器,调用相应的初始化函数,把特定CPU的中断信息注册进内核中断子系统中,使内核能响应并处理相应的中断。对于s3c2416,在drivers\irqchip\irq-s3c24xx.c中声明了相应的中断控制器。

IRQCHIP_DECLARE(s3c2416_irq,”samsung,s3c2416-irq”, s3c2416_init_intc_of);

kernel_init()->kernel_init_freeable()->do_basic_setup()->do_initcalls()实现调用s3c2416_dt_machine_init (),Linux在启动的最后会创建kernel_init进程,该进程中会初始化调用所有在”initcall”段的函数,arch_initcall(customize_machine)实现从customize_machine()中调用s3c2416_dt_machine_init(),该函数调用of_platform_populate(),把Device Tree中需要加载为device的device node转为platform device,用于匹配对应的设备驱动。

1.3. 内核配置

在Device Tree中实现板级的支持,在arch\arm\boot\dts目录,拷贝s3c2416-smdk2416.dts并命名成s3c2416-home2416.dts,作为HOME2416的板级配置,并在该目录Makefile文件中加入s3c2416-home2416.dts的设备树编译支持。

  1. dtb-$(CONFIG_ARCH_S3C24XX)+= \
  2. s3c2416-smdk2416.dtb \
  3. s3c2416-home2416.dts

我们基于s3c2410的配置文件进行配置,把arch\arm\configs文件夹中的s3c2410_defconfig拷贝到主目录,并命名成.config。

执行make menuconfig,进行Linux内核的配置。在Boot option下选择FlattenedDevice Tree support。

25_Linux设备树启动 - 图1

在System Type->SAMSUNG S3C24XX SoCs SupportSamsuug选择Samsung S3C2416 machine using devicetree。

25_Linux设备树启动 - 图2

1.4. 编译

执行make,进行编译,成功后会在arch\arm\boot目录下生成Image非压缩内核以及zImage压缩内核,在arch\arm\boot\dts目录中生成s3c2416-home2416.dtb的二进制设备树。

2. dts

dts即Device Tree Source设备树源码,它是一种ascii文本格式,可以用来描述硬件配置和系统运行参数。通过dtc(Device Tree Compiler),可以将Device Tree源码编译成适合机器处理的dtb文件,即Device Tree binary。在系统启动的时候,bootloader可以把储存在外部设备的dtb加载到内存中,并在跳转执行内核的同时,把dtb的起始位置传递给内核,由内核对dtb进行处理。

Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点,所谓属性,就是成对出现的name和value。linux内核设备驱动将会引用这些结点和属性。

此处以内核源码中s3c2416-smdk2416.dts为基础,加入了leds结点用于支持leds驱动,s3c2416-home2416.dts简单示例如下。

2.1. s3c2416-home2416.dts

.dts文件用于板级定义。

  1. /dts-v1/;
  2. #include<dt-bindings/gpio/gpio.h>
  3. #include"s3c2416.dtsi"
  4. / {
  5. model = "HOME2416";
  6. compatible = "samsung,s3c2416";
  7. memory {
  8. reg = <0x30000000 0x4000000>;
  9. };
  10. chosen {
  11. bootargs = "noinitrd root=/dev/mtdblock3 rootfstype=yaffs2 init=/init console=ttySAC0";
  12. };
  13. clocks {
  14. compatible ="simple-bus";
  15. #address-cells = <1>;
  16. #size-cells = <1>;
  17. xti: xti {
  18. compatible = "fixed-clock";
  19. clock-frequency =<12000000>;
  20. clock-output-names ="xti";
  21. #clock-cells = <0>;
  22. };
  23. };
  24. leds {
  25. compatible ="gpio-leds";
  26. pinctrl-names ="default";
  27. pinctrl-0 =<&gpio_leds>;
  28. led-4 {
  29. label = "LED4";
  30. gpios = <&gpe 13 GPIO_ACTIVE_HIGH>;
  31. linux,default-trigger ="heartbeat";
  32. };
  33. led-7 {
  34. label = "LED7";
  35. gpios = <&gpe 12GPIO_ACTIVE_HIGH>;
  36. linux,default-trigger ="timer";
  37. };
  38. };
  39. };
  40. &pinctrl_0 {
  41. gpio_leds: gpio-leds {
  42. samsung,pins = "gpe-12","gpe-13";
  43. samsung,pin-pud =<EXYNOS_PIN_PULL_NONE>;
  44. };
  45. };
  46. &rtc {
  47. status = "okay";
  48. };
  49. &sdhci_0 {
  50. pinctrl-names = "default";
  51. pinctrl-0 = <&sd1_clk>,<&sd1_cmd>,
  52. <&sd1_bus1>,<&sd1_bus4>;
  53. bus-width = <4>;
  54. cd-gpios = <&gpf 3 0>;
  55. cd-inverted;
  56. status = "okay";
  57. };
  58. &sdhci_1 {
  59. pinctrl-names = "default";
  60. pinctrl-0 = <&sd0_clk>,<&sd0_cmd>,
  61. <&sd0_bus1>,<&sd0_bus4>;
  62. bus-width = <4>;
  63. broken-cd;
  64. status = "okay";
  65. };
  66. &uart_0 {
  67. status = "okay";
  68. pinctrl-names = "default";
  69. pinctrl-0 = <&uart0_data>,<&uart0_fctl>;
  70. };
  71. &uart_1 {
  72. status = "okay";
  73. pinctrl-names = "default";
  74. pinctrl-0 = <&uart1_data>,<&uart1_fctl>;
  75. };
  76. &uart_2 {
  77. status = "okay";
  78. pinctrl-names = "default";
  79. pinctrl-0 = <&uart2_data>;
  80. };
  81. &uart_3 {
  82. status = "okay";
  83. pinctrl-names = "default";
  84. pinctrl-0 = <&uart3_data>;
  85. };
  86. &watchdog {
  87. status = "okay";
  88. };

a) dts可以分成多个文件,通过include进行包含。.dts包含板级的描述信息,.dtsi为头文件,描述一些片上系统级之类的通用信息。dts支持c预处理器,也可以包含c头文件。 b) “/”为根结点,model属性为板级名称,compatible属性用于匹配相应的平台,用于平台的初始化,对应machine_desc结构体中的.dt_compat。 c) memory结点定义了内存的地址以及大小。 d) chosen结点用来给内核传递参数,可以用bootargs定义linux内核启动时的命令行。 e) clocks结点compatible =”simple-bus”表示无需驱动的简单内存映射总线,它的子结点会被注册为platform device。 f) leds结点为针对HOME2416添加的leds驱动设备树描述。子结点用compatible属性来匹配相应的设备驱动,compatible = “gpio-leds”,即结点用来匹配”gpio-leds”驱动,该驱动文件为drivers\leds\Leds-gpio.c。可以在Documentation/devicetree/bindings目录查看结点和属性应该如何来描述设备的硬件细节的,例如”gpio-leds”对应的帮助文件为Documentation\devicetree\bindings\leds\leds-gpio.txt,可以从该文件了解leds结点应该如何描述。 当linux内核从Device Tree中注册了leds平台设备,需要匹配到对应的设备驱动,因此linux内核需要支持”gpio-leds”驱动,Device Drivers> LED Support > LED Trigger support选中LED Timer Trigger以及LED HeartbeatTrigger的支持。

25_Linux设备树启动 - 图3

g) &pinctrl_0、&rtc、&sdhci_0、&uart_0等结点中,pinctrl_0、rtc、sdhci_0、uart_0为节点标号,通过”&”对相应的节点进行引用,如&rtc引用的是在s3c2416.dtsi文件中的rtc:rtc@57000000 {xxx}结点,实现后面定义的结点属性覆盖、添加进前面定义的结点属性中。 h) leds 、&sdhci_0pinctrl、&uart_0等结点中的pinctrl-0为对应设备的引脚复用配置,pinctrl子系统用于管理引脚的复用,pinctrl-names属性为引脚配置状态的名称,pinctrl-0属性为引脚配置列表。在设备probed时,”default”名称的pinctrl状态会自动应用。 i) &rtc、&sdhci_0、&watchdog等结点具有” status”属性,status = “okay”表示设备被使能,相应的device node才会转为platformdevice,并匹配对应的驱动。

2.2. s3c2416.dtsi

.dtsi为头文件,描述一些片上系统级之类的通用信息。

  1. #include <dt-bindings/clock/s3c2443.h>
  2. #include "s3c24xx.dtsi"
  3. #include "s3c2416-pinctrl.dtsi"
  4. / {
  5. model ="Samsung S3C2416 SoC";
  6. compatible ="samsung,s3c2416";
  7. aliases {
  8. serial3= &uart_3;
  9. };
  10. cpus {
  11. #address-cells= <1>;
  12. #size-cells= <0>;
  13. cpu {
  14. compatible= "arm,arm926ej-s";
  15. };
  16. };
  17. interrupt-controller@4a000000{
  18. compatible= "samsung,s3c2416-irq";
  19. };
  20. clocks:clock-controller@0x4c000000 {
  21. compatible= "samsung,s3c2416-clock";
  22. reg =<0x4c000000 0x40>;
  23. #clock-cells= <1>;
  24. };
  25. pinctrl@56000000{
  26. compatible= "samsung,s3c2416-pinctrl";
  27. };
  28. timer@51000000{
  29. clocks= <&clocks PCLK_PWM>;
  30. clock-names= "timers";
  31. };
  32. uart_0: serial@50000000{
  33. compatible= "samsung,s3c2440-uart";
  34. clock-names= "uart", "clk_uart_baud2",
  35. "clk_uart_baud3";
  36. clocks= <&clocks PCLK_UART0>, <&clocks PCLK_UART0>,
  37. <&clocksSCLK_UART>;
  38. };
  39. uart_1:serial@50004000 {
  40. compatible= "samsung,s3c2440-uart";
  41. clock-names= "uart", "clk_uart_baud2",
  42. "clk_uart_baud3";
  43. clocks= <&clocks PCLK_UART1>, <&clocks PCLK_UART1>,
  44. <&clocksSCLK_UART>;
  45. };
  46. uart_2:serial@50008000 {
  47. compatible= "samsung,s3c2440-uart";
  48. clock-names= "uart", "clk_uart_baud2",
  49. "clk_uart_baud3";
  50. clocks= <&clocks PCLK_UART2>, <&clocks PCLK_UART2>,
  51. <&clocksSCLK_UART>;
  52. };
  53. uart_3:serial@5000C000 {
  54. compatible= "samsung,s3c2440-uart";
  55. reg =<0x5000C000 0x4000>;
  56. interrupts= <1 18 24 4>, <1 18 25 4>;
  57. clock-names= "uart", "clk_uart_baud2",
  58. "clk_uart_baud3";
  59. clocks= <&clocks PCLK_UART3>, <&clocks PCLK_UART3>,
  60. <&clocksSCLK_UART>;
  61. status= "disabled";
  62. };
  63. sdhci_1:sdhci@4AC00000 {
  64. compatible= "samsung,s3c6410-sdhci";
  65. reg =<0x4AC00000 0x100>;
  66. interrupts= <0 0 21 3>;
  67. clock-names= "hsmmc", "mmc_busclk.0",
  68. "mmc_busclk.2";
  69. clocks= <&clocks HCLK_HSMMC0>, <&clocks HCLK_HSMMC0>,
  70. <&clocksMUX_HSMMC0>;
  71. status= "disabled";
  72. };
  73. sdhci_0:sdhci@4A800000 {
  74. compatible= "samsung,s3c6410-sdhci";
  75. reg =<0x4A800000 0x100>;
  76. interrupts= <0 0 20 3>;
  77. clock-names= "hsmmc", "mmc_busclk.0",
  78. "mmc_busclk.2";
  79. clocks= <&clocks HCLK_HSMMC1>, <&clocks HCLK_HSMMC1>,
  80. <&clocksMUX_HSMMC1>;
  81. status= "disabled";
  82. };
  83. watchdog:watchdog@53000000 {
  84. interrupts= <1 9 27 3>;
  85. clocks= <&clocks PCLK_WDT>;
  86. clock-names= "watchdog";
  87. };
  88. rtc:rtc@57000000 {
  89. compatible= "samsung,s3c2416-rtc";
  90. clocks= <&clocks PCLK_RTC>;
  91. clock-names= "rtc";
  92. };
  93. i2c@54000000{
  94. compatible ="samsung,s3c2440-i2c";
  95. clocks= <&clocks PCLK_I2C0>;
  96. clock-names= "i2c";
  97. };
  98. };

a) aliases结点定义了一些别名,可以省写了引用结点时的完整路径。 b) cpus结点,其子结点描述了在系统中的每个cpu属性。 c) interrupt-controller@4a000000、clock-controller@0x4c000000、pinctrl@56000000等等结点中,”@”前面的为结点名,后面的为单元地址,一般对应结点的reg属性地址。 d) timer@51000000、uart_0: serial@50000000、watchdog: watchdog@53000000等等结点中,用clocks属性描述对应设备使用的clock source,clock provider为clocks:clock-controller@0x4c000000结点。clock-names属性用来描述该设备时钟源名称。clocks属性由内核clk_get函数所使用。

2.3. s3c24xx.dtsi

  1. #include "skeleton.dtsi"
  2. / {
  3. compatible = "samsung,s3c24xx";
  4. interrupt-parent = <&intc>;
  5. aliases {
  6. pinctrl0 = &pinctrl_0;
  7. serial0 = &uart0;
  8. serial1 = &uart1;
  9. serial2 = &uart2;
  10. };
  11. intc:interrupt-controller@4a000000 {
  12. compatible = "samsung,s3c2410-irq";
  13. reg = <0x4a000000 0x100>;
  14. interrupt-controller;
  15. #interrupt-cells = <4>;
  16. };
  17. pinctrl_0: pinctrl@56000000 {
  18. reg = <0x56000000 0x1000>;
  19. wakeup-interrupt-controller {
  20. compatible ="samsung,s3c2410-wakeup-eint";
  21. interrupts = <0 0 0 3>,
  22. <0 0 1 3>,
  23. <0 0 2 3>,
  24. <0 0 3 3>,
  25. <0 0 4 4>,
  26. <0 0 5 4>;
  27. };
  28. };
  29. timer@51000000 {
  30. compatible = "samsung,s3c2410-pwm";
  31. reg = <0x51000000 0x1000>;
  32. interrupts = <0 0 10 3>, <0 0 11 3>, <00 12 3>, <0 0 13 3>, <0 0 14 3>;
  33. #pwm-cells = <4>;
  34. };
  35. uart0: serial@50000000 {
  36. compatible = "samsung,s3c2410-uart";
  37. reg = <0x50000000 0x4000>;
  38. interrupts = <1 28 0 4>, <1 28 1 4>;
  39. status = "disabled";
  40. };
  41. uart1: serial@50004000 {
  42. compatible = "samsung,s3c2410-uart";
  43. reg = <0x50004000 0x4000>;
  44. interrupts = <1 23 3 4>, <1 23 4 4>;
  45. status = "disabled";
  46. };
  47. uart2: serial@50008000 {
  48. compatible = "samsung,s3c2410-uart";
  49. reg = <0x50008000 0x4000>;
  50. interrupts = <1 15 6 4>, <1 15 7 4>;
  51. status = "disabled";
  52. };
  53. watchdog@53000000 {
  54. compatible = "samsung,s3c2410-wdt";
  55. reg = <0x53000000 0x100>;
  56. interrupts = <0 0 9 3>;
  57. status = "disabled";
  58. };
  59. rtc@57000000 {
  60. compatible = "samsung,s3c2410-rtc";
  61. reg = <0x57000000 0x100>;
  62. interrupts = <0 0 30 3>, <0 0 8 3>;
  63. status = "disabled";
  64. };
  65. i2c@54000000 {
  66. compatible = "samsung,s3c2410-i2c";
  67. reg = <0x54000000 0x100>;
  68. interrupts = <0 0 27 3>;
  69. #address-cells = <1>;
  70. #size-cells = <0>;
  71. status = "disabled";
  72. };
  73. };

a) interrupt-parent属性表明当前结点所使用的中断控制器。 b) intc:interrupt-controller@4a000000结点中,用boolean值interrupt-controller属性表明当前结点是一个中断控制器。#interrupt-cell用来标识这个中断控制器需要多少个cell的中断描述符。 c) i2c@54000000等结点中,reg属性表示设备使用的地址信息,#address-cells标识在reg属性中基地址需要多少个cell(32位),#size-cells标识在reg属性中地址范围大小需要多少个cell,由内核platform_get_resource函数获取对应所需的IO资源。interrupts属性表示一个中断标识符列表,相应的每一个中断输出信号,由内核platform_get_irq函数获取对应所需的中断资源。

2.4. s3c2416-pinctrl.dtsi

s3c2416-pinctrl.dtsi描述了s3c2416相应外设的引脚配置。

  1. &pinctrl_0 {
  2. /*
  3. * Pin banks
  4. */
  5. gpa: gpa {
  6. gpio-controller;
  7. #gpio-cells = <2>;
  8. };
  9. gpb: gpb {
  10. gpio-controller;
  11. #gpio-cells = <2>;
  12. };
  13. gpc: gpc {
  14. gpio-controller;
  15. #gpio-cells = <2>;
  16. };
  17. gpd: gpd {
  18. gpio-controller;
  19. #gpio-cells = <2>;
  20. };
  21. gpe: gpe {
  22. gpio-controller;
  23. #gpio-cells = <2>;
  24. };
  25. gpf: gpf {
  26. gpio-controller;
  27. #gpio-cells = <2>;
  28. interrupt-controller;
  29. #interrupt-cells = <2>;
  30. };
  31. gpg: gpg {
  32. gpio-controller;
  33. #gpio-cells = <2>;
  34. interrupt-controller;
  35. #interrupt-cells = <2>;
  36. };
  37. gph: gph {
  38. gpio-controller;
  39. #gpio-cells = <2>;
  40. };
  41. gpj: gpj {
  42. gpio-controller;
  43. #gpio-cells = <2>;
  44. };
  45. gpk: gpk {
  46. gpio-controller;
  47. #gpio-cells = <2>;
  48. };
  49. gpl: gpl {
  50. gpio-controller;
  51. #gpio-cells = <2>;
  52. };
  53. gpm: gpm {
  54. gpio-controller;
  55. #gpio-cells = <2>;
  56. };
  57. /*
  58. * Pin groups
  59. */
  60. uart0_data: uart0-data {
  61. samsung,pins = "gph-0", "gph-1";
  62. samsung,pin-function = <2>;
  63. };
  64. uart0_fctl: uart0-fctl {
  65. samsung,pins = "gph-8", "gph-9";
  66. samsung,pin-function = <2>;
  67. };
  68. uart1_data: uart1-data {
  69. samsung,pins = "gph-2", "gph-3";
  70. samsung,pin-function = <2>;
  71. };
  72. uart1_fctl: uart1-fctl {
  73. samsung,pins = "gph-10", "gph-11";
  74. samsung,pin-function = <2>;
  75. };
  76. uart2_data: uart2-data {
  77. samsung,pins = "gph-4", "gph-5";
  78. samsung,pin-function = <2>;
  79. };
  80. uart2_fctl: uart2-fctl {
  81. samsung,pins = "gph-6", "gph-7";
  82. samsung,pin-function = <2>;
  83. };
  84. uart3_data: uart3-data {
  85. samsung,pins = "gph-6", "gph-7";
  86. samsung,pin-function = <2>;
  87. };
  88. extuart_clk: extuart-clk {
  89. samsung,pins = "gph-12";
  90. samsung,pin-function = <2>;
  91. };
  92. i2c0_bus: i2c0-bus {
  93. samsung,pins = "gpe-14", "gpe-15";
  94. samsung,pin-function = <2>;
  95. };
  96. spi0_bus: spi0-bus {
  97. samsung,pins = "gpe-11", "gpe-12","gpe-13";
  98. samsung,pin-function = <2>;
  99. };
  100. sd0_clk: sd0-clk {
  101. samsung,pins = "gpe-5";
  102. samsung,pin-function = <2>;
  103. };
  104. sd0_cmd: sd0-cmd {
  105. samsung,pins = "gpe-6";
  106. samsung,pin-function = <2>;
  107. };
  108. sd0_bus1: sd0-bus1 {
  109. samsung,pins = "gpe-7";
  110. samsung,pin-function = <2>;
  111. };
  112. sd0_bus4: sd0-bus4 {
  113. samsung,pins = "gpe-8", "gpe-9","gpe-10";
  114. samsung,pin-function = <2>;
  115. };
  116. sd1_cmd: sd1-cmd {
  117. samsung,pins = "gpl-8";
  118. samsung,pin-function = <2>;
  119. };
  120. sd1_clk: sd1-clk {
  121. samsung,pins = "gpl-9";
  122. samsung,pin-function = <2>;
  123. };
  124. sd1_bus1: sd1-bus1 {
  125. samsung,pins = "gpl-0";
  126. samsung,pin-function = <2>;
  127. };
  128. sd1_bus4: sd1-bus4 {
  129. samsung,pins = "gpl-1", "gpl-2","gpl-3";
  130. samsung,pin-function = <2>;
  131. };
  132. };

a) gpa: gpa、gpb: gpb、gpc: gpc等结点中,用boolean值gpio-controller属性表明当前结点是一个gpio控制器。#gpio-cells用来标识这个gpio控制器需要多少个cell的描述符。

2.5. skeleton.dtsi

skeleton.dtsi为各arm架构芯片共用的一些硬件定义信息。

  1. / {
  2. #address-cells = <1>;
  3. #size-cells = <1>;
  4. chosen { };
  5. aliases { };
  6. memory { device_type = "memory"; reg = <0 0>;};
  7. };

3. 内核运行

内核编译后,在arch\arm\boot目录下生成Image非压缩内核以及zImage压缩内核,在arch\arm\boot\dts目录中生成s3c2416-home2416.dtb的二进制设备树。此处内核采用initramfs,基于busybox的rootfs编译进内核,bootloader在启动内核时需要把内核加载进ram,同时需要把s3c2416-home2416.dtb也加载进内核,跳转内核时指定r0为0,r1不重要,r2为dtb存放的ram地址。基于mdk的s3c2416 bootloader如下,实现从sd卡加载内核、dtb到ram后,跳转启动内核。

  1. KernelBase = DRAM_BASE+LINUX_KERNEL_OFFSET;
  2. DtbBase = DRAM_BASE+LINUX_DTB_OFFSET;
  3. FileSize =Sd_ReadFileToRam("/image/s3c2416-home2416.dtb", (uint8_t *)DtbBase);
  4. if (FileSize < 0) {
  5. return -1;
  6. }
  7. FileSize =Sd_ReadFileToRam("/image/kernel.bin", (uint8_t *)KernelBase);
  8. if (FileSize < 0) {
  9. return -1;
  10. }
  11. Kernel = (void (*)(uint32_t, uint32_t,uint32_t))KernelBase;
  12. Kernel(0, 0, DtbBase); // never return

25_Linux设备树启动 - 图4

在控制台对brightness文件写入0或1控制led灯的亮灭。

25_Linux设备树启动 - 图5

4. 附录

基于s3c2416 mdk工程实现,用于从sd卡加载内核、dtb文件到ram,以device tree方式启动linux内核。

https://pan.baidu.com/s/1kUNjQUr