Embedded : : Linux/: : Device Tree

[Device Tree] 5. .dtsi 인클루드 구조와 오버라이드

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

 

 

  5.  .dtsi 인클루드 구조와 오버라이드

 

.dtsi 인클루드와 오버라이드(Override)는 복잡한 하드웨어 설정을 효율적으로 관리하기 위한 일종의 '상속' 시스템이라고 이해하면 쉽습니다.

 

구조를 비유와 함께 조목조목 설명해 드릴게요.

 

  5.1  .dtsi (Device Tree Source Include): "공통 설계도"

 

.dtsi 파일은 여러 보드에서 공통으로 사용하는 SoC(System on Chip)의 내부 IP 블록들을 정의합니다.

  • 역할: C언어의 .h 헤더 파일과 비슷합니다. CPU 코어 개수, 메모리 컨트롤러, UART, I2C 같은 하드웨어 자원의 물리적 주소와 특징을 미리 선언해 둡니다.
  • 특징: 보통 하드웨어 자원은 존재하지만, 모든 보드에서 다 쓰는 것은 아니므로 status = "disabled"; 상태로 정의해 두는 경우가 많습니다. "우리 SoC에는 이런 기능이 있지만, 아직 켜지는 말아줘"라는 뜻이죠.

 

  5.2   .dts (Device Tree Source): "최종 조립 설명서"

 

.dts 파일은 실제 판매되는 보드(Board) 하나하나에 대응합니다.

  • 인클루드 (#include): #include "my-soc.dtsi"를 통해 SoC의 모든 설정을 몽땅 가져옵니다.
  • 오버라이드 (Override): 가져온 설정 중에서 이 보드에 실제로 연결된 부품만 활성화하거나 설정을 수정합니다.

 

디바이스 트리(Device Tree)의 핵심 설계 철학인 "재사용성"과 "유연성"을 완벽하게 보여주고 있습니다. 

 
  /*
   * .dtsi (Device Tree Source Include) — SoC 공통 정의
   * .dts — 보드별 최종 파일, .dtsi를 인클루드하고 오버라이드
   *
   * 계층 구조 예시:
   *    arch/arm64/boot/dts/
   *    ├─ myvendor/
   *     │      ├── my-soc.dtsi                 ← SoC 공통 (IP 블록, 클럭, 인터럽트)
   *     │      ├── my-soc-gpu.dtsi         ← GPU 관련 (선택적 인클루드)
   *     │      ├── myboard-rev-a.dts     ← 보드 A (오버라이드, 확장)
   *     │      └── myboard-rev-b.dts    ← 보드 B (다른 설정)
   *
   * 오버라이드 규칙:
   * - .dts에서 .dtsi의 노드를 재정의하면 프로퍼티가 병합/덮어쓰기
   * - &label 참조로 기존 노드를 수정 (노드 경로 생략 가능)
   */
 
  /* === my-soc.dtsi (SoC 공통) === */
  / {
        soc {
               uart0: serial@1c28000 {
                      compatible = "myvendor,my-soc-uart";
                      reg = <0x1c28000 0x400>;
                      clocks = <&ccu CLK_UART0>;
                      status = "disabled";            /* 기본: 비활성 */
               };
 
               i2c0: i2c@1c2ac00 {
                      compatible = "myvendor,my-soc-i2c";
                      reg = <0x1c2ac00 0x400>;
                      #address-cells = <1>;
                      #size-cells = <0>;
                      status = "disabled";
               };
        };
  };
 
  /* === myboard-rev-a.dts (보드별) === */
  /dts-v1/;
  #include "my-soc.dtsi"
 
  / {
        model = "MyBoard Rev.A";
  };
 
  /* &label 참조로 기존 노드 오버라이드 */
  &uart0 {
        status = "okay";                /* 이 보드에서 UART0 활성화 */
        pinctrl-0 = <&uart0_pins>;     /* 핀 설정 추가 */
        pinctrl-names = "default";
  };
 
  &i2c0 {
        status = "okay";
 
        /* 이 보드에 연결된 센서 추가 */
        accelerometer@1d {
               compatible = "st,lis3dh";
               reg = <0x1d>;
               interrupt-parent = <&gic>;
               interrupts = <GIC_SPI 25 IRQ_TYPE_EDGE_RISING>;
               vdd-supply = <®_3v3>;
        };
  };
 

 

 

  5.3  오버라이드의 작동 원리: "덮어쓰기 & 추가하기"

 

오버라이드는 크게 두 가지 방식으로 작동합니다.

 

 &label 방식 (가장 권장됨)

이미 정의된 노드의 라벨(Label)을 참조하여 내용을 수정합니다. 경로를 일일이 적지 않아도 되어 매우 깔끔합니다.    DTS

/* my-soc.dtsi에서 uart0: serial@1c28000로 정의됨 */
&uart0 {
    status = "okay";          /* 1. 값 변경: "disabled" -> "okay" */
    pinctrl-0 = <&uart0_pins>; /* 2. 속성 추가: 원래 없던 핀 설정 추가 */
};

 

② 경로 재정의 방식

루트(/)부터 경로를 따라가며 다시 선언하는 방식입니다. .dts 파일 하단에 위치하면 상위 설정을 덮어씁니다.    DTS

/ {
    soc {
        serial@1c28000 {
            status = "okay";
        };
    };
};

[핵심 규칙]

  • 병합(Merge): 같은 노드 안에 새로운 속성이 들어오면 기존 데이터에 합쳐집니다.
  • 덮어쓰기(Overwrite): 같은 이름의 속성이 이미 있다면, 나중에 선언된 것이 최종 승자가 됩니다.

 

 

 

  5.4  왜 이런 구조를 쓸까요? (장점)

 

  1. 중복 제거: SoC 하나로 보드 100개를 만들어도, 공통 주소(0x1c28000 등)는 .dtsi에 딱 한 번만 적으면 됩니다.
  2. 가독성: 보드 파일(.dts)만 보면 "아, 이 보드에서는 UART0과 I2C0을 쓰고 센서가 어디 붙어있구나!"라고 하드웨어 구성을 한눈에 파악할 수 있습니다.
  3. 유지보수: SoC 설계가 살짝 변경되어 UART 주소가 바뀌었다면, .dtsi 파일 하나만 고치면 이를 참조하는 모든 보드 파일에 자동으로 적용됩니다.

 

  5.5 Overlay (.dtbo)와의 차이점

 

  • DTS 오버라이드: 커널 빌드 시점에 결정됩니다. dtc 컴파일러가 .dtsi와 .dts를 합쳐 하나의 거대한 .dtb 이진 파일을 만듭니다.
  • DT Overlay: 이미 부팅된 후(런타임)에 하드웨어를 추가할 때 씁니다. 라즈베리 파이에 새 센서 모듈을 꽂았을 때 재부팅 없이 설정을 "덧칠"하는 개념입니다.

 

 



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