Embedded : : Linux/: : Device Tree

[Device Tree] 11. 특수 노드와 고급 패턴

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

 

 

 

  11.  특수 노드와 고급 패턴

 

Device Tree(DT)가 단순히 "하드웨어 목록"을 넘어 복합적인 시스템 제어를 수행할 수 있는 이유는 특수 노드 고급 데이터 패턴 덕분입니다. 시스템 부팅의 결정적인 설정부터 핀 하나하나의 전기적 특성까지 조율하는 이 요소들을 핵심 위주로 정리해 드릴게요.

 

  11.1  디바이스 트리: 노드 구조

 

디바이스 트리는 하드웨어 정보를 트리 구조로 설명하며 각 디바이스를 노드(Node)로 표현한다. 각 노드는 부모-자식 관계를 기반으로 조직되고, 트리의 최상단에는 루트 노드(Root Node)가 존재한다.

 

루트 노드

  • 트리 구조의 시작점이며 / 로 식별된다. (다른 노드와 달리 이름이 없다.)
  • 모든 디바이스 노드는 루트 노드를 기준으로 참조된다.
  • 루트 노드는 시스템에 하나만 존재하며, 디바이스 트리 최상단에 위치한다.
  • 루트 노드는 반드시 하나의 /cpus 노드와 최소 하나 이상의 /memory 노드를 포함해야 한다.

노드

  • 각 노드는 하드웨어 디바이스를 나타낸다.
  • 노드는 속성(Property)을 통데 데이터를 정의한다.
    • Property는 Key-Value 쌍으로 정의되며 문자열, 정수, boolean 등 다양한 데이터 유형을 지원한다.
    • Property는 Device Tree specification에 따라 작성해야 하며, 표준 속성과 사용자 정의 속성으로 구분된다.
  • 노드는 부모-자식 관계를 형성한다. 예를 들어 I2C 컨트롤러는 부모 노드이고 여기에 I2C 버스를 통해 연결된 디바이스들은 자식노드가 된다.

 

 

  11.2  시스템 제어를 위한 특수 노드 (Standard Special Nodes)

 

이 노드들은 특정 하드웨어 장치를 나타내지 않고, OS와 커널의 동작 방식을 결정하는 메타데이터를 담고 있습니다.

 

/chosen 노드

부트로더(U-Boot 등)가 커널에게 보내는 "쪽지" 같은 노드입니다. 하드웨어 소스 코드(.dts)에는 보통 비어있거나 기본값만 있고, 부트로더가 실행 중에 내용을 채워 넣습니다.

프로퍼티 설명
bootargs 커널 부팅 파라미터 (예: console=ttyS0,115200 root=/dev/mmcblk0p2)
stdout-path 시스템 로그가 출력될 기본 시리얼 포트 경로
kaslr-seed 커널 주소 공간 무작위화(KASLR)를 위한 랜덤 시드 값

 

/aliases 노드

긴 경로명을 가진 노드에 "별명"을 붙여줍니다. 예를 들어 /soc/serial@1c28000 대신 serial0이라는 짧은 이름으로 접근하게 하여, 드라이버가 인덱스 번호(UART0, UART1 등)를 쉽게 지정하게 돕습니다.

 

/reserved-memory 노드

리눅스 커널이 일반적인 용도로 사용하지 못하도록 물리 메모리의 특정 구역을 보호합니다.

  • CMA (Contiguous Memory Allocator): 카메라나 멀티미디어 장치용 연속 메모리 확보.
  • Framebuffer: 디스플레이 출력을 위한 전용 메모리 영역.

 

  11.3  고급 설계 패턴 (Advanced Patterns)

 

단순한 속성 정의를 넘어, 노드 간의 복잡한 관계를 정의하는 패턴들입니다.

 

Phandle (Pointer Handle)

노드와 노드를 연결하는 "포인터"입니다.

  • 패턴: 어떤 노드가 다른 노드(예: 클럭 컨트롤러, GPIO 컨트롤러)의 기능을 빌려 쓸 때 사용합니다.
  • 예시: clocks = <&ccu CLK_UART0>; 여기서 &ccu가 바로 phandle입니다.

 

Pinctrl (Pin Control) & Pinmux

하나의 물리적 핀을 UART로 쓸지, GPIO로 쓸지, I2C로 쓸지 결정하는 매우 중요한 패턴입니다.

  • Pattern: 장치 노드 안에 pinctrl-0 = <&uart0_pins>;와 같이 설정하여, 해당 장치가 활성화될 때 핀 설정도 자동으로 바뀌게 합니다.

 

DT Overlays (.dtbo)

이미 컴파일된 DTB를 수정하지 않고, 실행 중에 새로운 하드웨어를 추가하는 패턴입니다.

  • 활용: 라즈베리 파이의 HAT이나 비글본의 캡(Capes)처럼, 사용자가 나중에 꽂는 확장 보드의 정보를 기존 시스템에 "합체"시킬 때 사용합니다.

 

 

  11.4  계층적 관계 (Hierarchy) 패턴

 

DT는 트리 구조이므로, 자원(Resource)의 흐름도 트리 형태로 관리됩니다.

  • Interrupt Tree: 하위 장치의 인터럽트가 상위 인터럽트 컨트롤러(GIC 등)로 어떻게 타고 올라가는지 정의합니다. (interrupt-parent 속성 활용)
  • Clock Tree: 크리스탈 오실레이터에서 시작된 원천 클럭이 분주기(Divider)와 배율기(PLL)를 거쳐 각 장치로 퍼져나가는 계층을 표현합니다.

💡정리하자면...

특수 노드는 커널과의 대화 통로이고, 고급 패턴은 하드웨어 간의 유기적인 연결 고리입니다. 특히 pinctrl이나 phandle은 드라이버 개발 시 가장 많이 접하게 되는 실무적인 부분입니다.

 

 

 

  11.5  실전 특수 노드와 고급 패턴

 

 
  /* ===== 주요 특수 노드들 ===== */
  /* 1. reserved-memory — 커널이 사용하지 않을 메모리 영역 */
  reserved-memory {
          #address-cells = <2>;
          #size-cells = <2>;
          ranges;
 
          /* CMA (Contiguous Memory Allocator) 영역 */
          linux,cma {
                  compatible = "shared-dma-pool";
                  reusable;
                  size = <0x0 0x10000000>;           /* 256 MiB */
                  linux,cma-default;
          };
 
          /* 펌웨어 전용 영역 */
          fw_reserved: framebuffer@be000000 {
                  reg = <0x0 0xbe000000 0x0 0x2000000>;
                  no-map; /* 커널이 매핑하지 않음 */
          };
  };
 
  /* 2. GPIO hog — 부팅 시 GPIO를 고정 상태로 설정 */
  &gpio1 {
          led-hog {
                  gpio-hog;
                  gpios = <10 GPIO_ACTIVE_HIGH>;
                  output-high;
                  line-name = "status-led";
          };
  };
 
  /* 3. 클럭/레귤레이터 고정 정의 (물리 클럭을 DT에서 선언) */
  osc24m: oscillator-24m {
          compatible = "fixed-clock";
          #clock-cells = <0>;
          clock-frequency = <24000000>; /* 24 MHz */
          clock-output-names = "osc24m";
  };
 
  reg_3v3: regulator-3v3 {
          compatible = "regulator-fixed";
          regulator-name = "vcc-3v3";
          regulator-min-microvolt = <3300000>;
          regulator-max-microvolt = <3300000>;
          regulator-always-on;
  };
 
  /* 4. OPP (Operating Performance Points) 테이블 */
  cpu_opp_table: opp-table {
          compatible = "operating-points-v2";
 
          opp-600000000 {
                  opp-hz = /bits/ 64 <600000000>;
                  opp-microvolt = <900000>;
          };
          opp-1200000000 {
                  opp-hz = /bits/ 64 <1200000000>;
                  opp-microvolt = <1100000>;
          };
          opp-1800000000 {
                  opp-hz = /bits/ 64 <1800000000>;
                  opp-microvolt = <1300000>;
                  opp-suspend; /* suspend 시 이 OPP 사용 */
          };
  };
 
  /* 5. 인터럽트 매핑 (interrupt-map) — PCI 등 */
  pcie@10000000 {
          interrupt-map-mask = <0x1800 0 0 7>;
          interrupt-map =
                  <0x0000 0 0 1 &gic GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
                  <0x0000 0 0 2 &gic GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
  };
 

 

위 코드는 Device Tree(DT)의 "고급 설정 기술"들을 총망라하고 있습니다. 일반적인 장치 등록을 넘어 시스템의 메모리 관리, 전력 최적화, 그리고 부팅 초기 상태를 결정하는 핵심적인 노드들입니다.

각 섹션이 가진 실무적 의미를 쉽게 풀어서 설명해 드릴게요.

 

1. reserved-memory: 커널로부터 메모리 보호하기

커널이 마음대로 사용하지 못하도록 물리 메모리(RAM)의 특정 구역을 미리 찜해두는 설정입니다.

  • linux,cma (Contiguous Memory Allocator): 카메라 영상 처리나 GPU처럼 거대한 연속 메모리가 필요한 장치를 위한 전용 주차장입니다. reusable이 붙으면 평소에는 커널이 쓰다가, 장치가 달라고 하면 즉시 비워줍니다.
  • no-map: 이 설정이 핵심입니다. 커널이 이 영역에 대해 가상 주소 매핑 자체를 하지 않도록 하여, CPU의 예측 실행(Speculative execution)으로 인한 데이터 오염 등을 원천 차단합니다. 주로 보안 펌웨어나 하드웨어 전용 버퍼로 씁니다.

 

2. GPIO hog: "부팅되자마자 켜져 있어!"

원래 GPIO는 드라이버가 올라간 뒤에야 제어할 수 있습니다. 하지만 gpio-hog는 GPIO 컨트롤러 드라이버가 로드되는 즉시 해당 핀을 특정 상태로 고정합니다.

  • 용도: 시스템 상태 LED, 외부 장치 전원 인에이블(Enable) 핀 등 드라이버 로드까지 기다릴 수 없는 최우선 순위 설정에 사용합니다.
  • 특징: 별도의 소비 드라이버(Consumer) 없이 GPIO 컨트롤러가 스스로 "독점(Hog)"합니다.

 

 

3. Fixed Clock/Regulator: 하드웨어 추상화

시스템에는 제어할 수 없는 "고정된 것들"이 있습니다. 이를 DT 노드로 만들어 다른 장치들이 참조하게 합니다.

  • fixed-clock: 외부 크리스탈 오실레이터처럼 전원만 넣으면 항상 $24\text{ MHz}$를 뿜어내는 클럭 소스를 정의합니다.
  • regulator-fixed:  전원 라인을 노드로 만듭니다. regulator-always-on 덕분에 커널은 이 전원을 끌 시도조차 하지 않으며, 다른 장치(예: Wi-Fi 모듈)가 "나  전원 필요해"라고 할 때 이 노드를 가리키게(&reg_3v3) 됩니다.

 

 

4. OPP (Operating Performance Points): CPU 성능표

CPU가 낼 수 있는 "속도와 전압의 짝꿍" 리스트입니다.

  • DVFS (Dynamic Voltage and Frequency Scaling): CPU 부하가 적으면 $600\text{ MHz} / 0.9\text{ V}$로 낮춰 전기를 아끼고, 부하가 높으면 $1.8\text{ GHz} / 1.3\text{ V}$로 올려 성능을 냅니다.
  • opp-suspend: 시스템이 절전 모드(Suspend)에 들어갈 때 사용할 최적의 지점을 지정합니다.

 

 

5. interrupt-map: 복잡한 인터럽트 배선도

주로 PCI/PCIe 버스에서 사용되는 "인터럽트 번역기"입니다.

  • 상황: PCIe 슬롯에는 수많은 장치가 꽂힐 수 있는데, 각 장치의 인터럽트(INTA, INTB...)를 메인 인터럽트 컨트롤러(GIC)의 몇 번 핀에 연결할지 매핑합니다.
  • interrupt-map-mask: 주소와 인터럽트 번호 중 어떤 비트를 보고 매핑할지 결정하는 필터 역할을 합니다.

💡 요약하자면

이 코드는 시스템의 뼈대와 규칙을 정의합니다.

  1. 메모리 어디를 비워둘지 (reserved-memory)
  2.  초기 상태는 무엇인지 (gpio-hog)
  3. 에너지 소스는 무엇인지 (fixed-clock/regulator)
  4. 달리기 규칙은 무엇인지 (OPP)
  5. 신호 전달은 어떻게 할지 (interrupt-map)

이 코드들은 모두 커널이 부팅될 때 "준비 단계"에서 처리되어 시스템의 안정성을 보장합니다.

 

 

 

 

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