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
'Embedded : : Linux > : : Device Tree' 카테고리의 다른 글
| [Device Tree] 6. Device Tree Overlay (DTBO) (0) | 2026.03.04 |
|---|---|
| [Device Tree] 5. .dtsi 인클루드 구조와 오버라이드 (0) | 2026.03.04 |
| [Device Tree] 4. 표준 프로퍼티 레퍼런스 (0) | 2026.03.04 |
| [Device Tree 심화] 1. Intro / 2. DT Architecture (0) | 2026.03.04 |
| Device Tree (0) | 2025.02.26 |