Embedded : : Linux/: : Device Tree

[Device Tree] 3. DTS 문법 상세

Jay.P Morgan 2026. 3. 4. 16:06

 

 

  3.  DTS 문법 상세

 

 
  /*
   * Device Tree Source (.dts) 문법
   *
   * 기본 구조: 노드(node)와 프로퍼티(property)의 트리
   *
   * 노드 형식:
   *    [label:] node-name[@unit-address] {
   *           [properties];
   *           [child nodes];
   *     };
   *
   * 프로퍼티 데이터 타입:
   *   - 빈 값:                속성 존재만 의미 (boolean)
   *   - u32:                 < 0x1234 >
   *   - u64:                 /bits/ 64 < 0x1234567890 >
   *   - 문자열:              "hello"
   *   - 문자열 목록:       "first", "second"
   *   - 바이트 배열:       [00 11 22 33]
   *   - phandle 참조:   <&label>
   *   - 혼합:                  < 0x1234 >, "string", [00 ff]
   */
 
 
  /* . 헤더 및 인클루드 섹션 */
  /* ===== 완전한 DTS 예제 ===== */
  /dts-v1/;                  /*  /dts-v1/: 이 파일이 디바이스 트리 문법 버전 1로 작성되었음을 알리는 필수 선언입니다. */
 
  /* .dtsi 인클루드 — SoC 공통 정의 재사용 */
  /* C언어처럼 다른 파일(.dtsi)을 가져옵니다. 보통 SoC 공통 설정은 .dtsi에, 보드 특화 설정은 .dts에 작성하여 재사용성을 높입니다. */
  #include "my-soc.dtsi"
  #include <dt-bindings/gpio/gpio.h>
  #include <dt-bindings/interrupt-controller/arm-gic.h>
  #include <dt-bindings/clock/my-soc-clk.h>
 
 
   /* . 루트 노드 (/) 및 기본 정보 */
 
  / {
          /* 루트 노드 — 보드 전체 정보 */                           
          model = "MyVendor MyBoard Rev.A"; 
          compatible = "myvendor,myboard", "myvendor,my-soc"; 
      /* model: 사용자가 읽을 수 있는 보드의 정확한 모델명 입니다. */                           
      /* compatible: 커널이 하드웨어에 맞는 드라이버를 찾을때 사용하는 가장 중요한 키워드 입니다. 
                              "가장 구체적인 것"에서 "범용적인 것" 순으로 나열합니다.*/   
 
          /* #address-cells / #size-cells:
           * 자식 노드의 reg 프로퍼티 해석 방법 지정
           * #address-cells = <2> → 주소가 u32 × 2 = 64-bit
           * #size-cells = <1> → 크기가 u32 × 1 = 32-bit */
          #address-cells = <2>;
          #size-cells = <2>;
 
  
 

     /* Ⅲ. 핵심 시스템 노드들 */

      /* chosen 노드 — 부트로더→커널 런타임 파라미터 */
      /* chosen: 하드웨어 정보는 아니지만, 커널에 전달할 실행 파라미터(bootargs)와 기본 입출력 콘솔(stdout-path)을 지정합니다. */
          chosen {
                    bootargs = "console=ttyS0,115200 root=/dev/mmcblk0p2 rw";
                    stdout-path = "serial0:115200n8";
          };
 
      /* aliases — 노드에 짧은 이름 부여 */
      /* aliases: 장치들에 짧은 별명을 붙여줍니다. (예: serial0은 uart0을 가리킴) */
          aliases {
                    serial0 = &uart0;
                    ethernet0 = ð0;
                    mmc0 = &sdhci0;
          };
 
      /* memory 노드 — 물리 메모리 레이아웃 */
      /* memory: RAM의 시작 주소와 크기를 정의합니다. 예제에서는 0x80000000 주소부터 1 GiB 크기의 메모리를 할당했습니다. */
          memory@80000000 {
                    device_type = "memory";
                    reg = <0x0 0x80000000 0x0 0x40000000>; /* 1 GiB @ 0x80000000 */
          };
 
      /* cpus 노드 */
      /* cpus: CPU 코어의 개수, 아키텍처, 클럭 속도, 전원 관리 방식(psci) 등을 기술합니다. */
          cpus {
                    #address-cells = <1>;
                    #size-cells = <0>;
 
                    cpu@0 {
                              device_type = "cpu";
                              compatible = "arm,cortex-a53";
                              reg = <0x0>;
                              enable-method = "psci";
                              clocks = <&cpu_clk>;
                              operating-points-v2 = <&cpu_opp_table>;
                    };
                    cpu@1 {
                              device_type = "cpu";
                              compatible = "arm,cortex-a53";
                              reg = <0x1>;
                              enable-method = "psci";
                    };
          };
 
 
     /* Ⅳ. 버스와 주소 지정 (SoC 노드)
       - 디바이스 트리에서 가장 복잡하지만 중요한 부분입니다.  */
 
          /* SoC 버스 — 주소 공간 정의 */
          soc {
                    compatible = "simple-bus";
                    #address-cells = <1>;
                    #size-cells = <1>;
                    ranges = <0x0 0x0 0x0 0x40000000>;  /* 자식→부모 주소 변환 */
 /* #address-cells / #size-cells: 자식 노드의 reg 속성에서 주소와 크기를 표현할 때 몇 개의 32비트 워드를 사용할지 결정합니다. */
 /* ranges: 버스 간의 주소 매핑을 정의합니다. 자식 버스의 주소 공간이 부모 버스의 어디에 위치하는지 변환해 주는 표입니다. */
 
                    /* 인터럽트 컨트롤러 */
                    gic: interrupt-controller@1c81000 {
                              compatible = "arm,gic-400";
                              interrupt-controller;                   /* 빈 프로퍼티 (boolean) */
                              #interrupt-cells = <3>;              /* 자식의 interrupts 해석: type irq flags */
                              reg = <0x1c81000 0x1000>,    /* GICD */
                                        <0x1c82000 0x2000>;   /* GICC */
                    };
 
                    /* 클럭 컨트롤러 — phandle로 참조 */
                    ccu: clock-controller@1c20000 {
                              compatible = "myvendor,my-soc-ccu";
                              reg = <0x1c20000 0x400>;
                              clocks = <&osc24m>, <&osc32k>;
                              clock-names = "hosc", "losc";
                              #clock-cells = <1>;                    /* 자식이 참조 시 인덱스 1개 */
                              #reset-cells = <1>;
                    };
 
/*  . 주요 장치(Peripheral) 정의 방식
       - 예제 내의 uart0, i2c0 등의 노드는 다음과 같은 공통 속성을 가집니다.  
     • reg: 장치의 제어 레지스터 물리 주소 범위입니다. 
     • interrupts: 장치가 사용하는 인터럽트 번호와 타입입니다.gic노드를 참조하여 인터럽트 컨트롤러에 연결됩니다.
     • clocks / resets:phandle(<&ccu>) 방식을 사용하여 클럭/리셋 컨트롤러 노드에 연결하고 특정 인덱스를 전달합니다.
     • status = "okay": 해당 장치를 실제로 활성화하겠다는 의미입니다. (기본값이disabled인 경우가 많음)
*/
                    /* UART — label로 phandle 자동 생성 */
                    uart0: serial@1c28000 {
                              compatible = "myvendor,my-soc-uart", "snps,dw-apb-uart";
                              reg = <0x1c28000 0x400>;
                              interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
                              clocks = <&ccu CLK_UART0>;
                              resets = <&ccu RST_UART0>;
                              reg-shift = <2>;
                              reg-io-width = <4>;
                              status = "okay";
                    };
 
 /* Ⅵ. 계층적 구조 (I2C 예시)
      I2C 컨트롤러 노드 안에 sensor나 pmic 같은 자식 노드가 들어있는 것을 볼 수 있습니다.
      이는 물리적으로 I2C 버스에 해당 장치들이 매달려 있음을 계층적으로 표현한 것입니다. */
                    /* I2C 컨트롤러 + 자식 디바이스 */
                    i2c0: i2c@1c2ac00 {
                              compatible = "myvendor,my-soc-i2c";
                              reg = <0x1c2ac00 0x400>;
                              interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
                              clocks = <&ccu CLK_I2C0>;
                              resets = <&ccu RST_I2C0>;
                              #address-cells = <1>;
                              #size-cells = <0>;
                              status = "okay";
 
                              /* I2C 슬레이브 디바이스 */
                              sensor@48 {
                                        compatible = "ti,tmp102";
                                        reg = <0x48>;                 /* I2C 주소 */
                                        interrupt-parent = <&gic>;
                                        interrupts = <GIC_SPI 20 IRQ_TYPE_EDGE_FALLING>;
                              };
 
                              pmic@34 {
                                        compatible = "xpower,axp803";
                                        reg = <0x34>;
                                        interrupt-parent = <&gic>;
                                        interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 
                                        /* 서브노드: PMIC 내 레귤레이터 */
                                        regulators {
                                                  reg_dcdc1: dcdc1 {
                                                            regulator-name = "vcc-3v3";
                                                            regulator-min-microvolt = <3300000>;
                                                            regulator-max-microvolt = <3300000>;
                                                            regulator-always-on;
                                                  };
                                        };
                              };
                    };
          };
  };
 
 
 
 
 /* 요약 
      이 DTS 파일은 ARM Cortex-A53 듀얼코어 기반의 SoC를 사용하는 보드 설정을 담고 있으며, 커널이 부팅될 때 이 정보를 읽어 UART로 로그를 뿌리고, I2C로 온도 센서와 전원 관리 칩(PMIC)을 제어할 수 있게 해주는 설계도와 같습니다.
*/
   
 

 

 

 

 

 

참조: https://www.minzkn.com/linuxkernel/pages/device-tree.html#dt-device-node