Device Tree Overlay 적용 안됨, 어디서부터 보나
Device Tree Overlay가 config.txt에 적어 두었는데도 장치가 안 뜨면, 드라이버부터 의심하기보다 컴파일 심볼 → 로더 경로 → 런타임 트리 순으로 좁히는 편이 문서상 원인과 맞습니다. 이 글은 보드별 실화·가격 없이, Linux 커널 Devicetree Dynamic Resolver Notes와 Raspberry Pi overlays README·configuration dtoverlay에 맞춰 점검 순서만 정리합니다.
dtc -@를 빼면 무슨 일이?
한 줄 답: -@ 없이 만든 .dtbo는 라벨·phandle을 나중에 붙일 __symbols__ / __fixups__ 메타가 빠지기 쉽고, /plugin/ 오버레이의 target = <&label> 해석이 깨집니다. 커널 리졸버는 “올바른 dtc 옵션 + /plugin/”으로 만든 트리를 전제로 __fixups__·__local_fixups__를 씁니다.
오버레이 소스는 보통 이렇게 시작합니다.
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&i2c1>;
__overlay__ {
/* status, compatible, reg … */
};
};
};
&i2c1 같은 베이스 트리 라벨은 컴파일 시점에 숫자 phandle로 확정되지 않습니다. dtc -@가 심볼·픽스업 노드를 넣어야, 병합 쪽에서 베이스 DTB의 __symbols__와 맞춰 target 자리를 패치합니다. U-Boot/커널 쪽 오버레이 문서도 베이스와 오버레이 모두 -@로 컴파일하라고 안내합니다.
권장 컴파일 예:
dtc -@ -I dts -O dtb -o myoverlay.dtbo myoverlay.dts
점검:
fdtdump myoverlay.dtbo또는dtc -I dtb -O dts myoverlay.dtbo로__fixups__/__symbols__/__local_fixups__유무를 본다./plugin/;가 소스에 있는지 확인한다. 없으면 플러그인 오버레이로 취급되지 않을 수 있다.#include가 필요하면 Raspberry Pikdtc처럼 cpp를 거치는 래퍼를 쓴다. 헤더만 빠진 채dtc만 돌리면 문법 오류로 아예 빌드가 실패한다.
-@를 빼면 “파일은 있는데 적용 후 노드가 안 생김 / 적용 실패”로 보이는 경우가 많습니다. 먼저 바이너리에 픽스업이 있는지 확인하는 것이 1순위입니다.
config.txt 경로 확인은?
한 줄 답: 펌웨어는 dtoverlay=이름을 확장자 없는 이름으로 읽고, 기본적으로 **…/overlays/이름.dtbo**를 찾습니다. 줄 문법·마운트된 boot 파티션 경로·파일 이름이 어긋나면 로더 단계에서 이미 실패합니다.
Raspberry Pi overlays README 기준:
dtoverlay=i2c-rtc,ds1307→/boot/overlays/i2c-rtc.dtbo로드(문서 표기).- 파라미터는 쉼표로 이어 붙인다.
dtparam=으로 베이스 인터페이스를 켤 수 있다. dtoverlay=(값 없음)은 파라미터 목록 종료 등으로 쓰이며, 맨 앞에 두면 HAT 오버레이 로드를 막을 수 있다(공식 config 문서).
실무 체크리스트:
| 확인할 것 | 왜 |
|---|---|
dtoverlay=foo vs foo.dtbo | 설정에는 이름만. .dtbo를 붙이면 파일을 못 찾는 경우가 많다 |
| 파일이 있는 디렉터리 | 구 OS는 /boot/overlays/, Bookworm 계열은 흔히 /boot/firmware/overlays/ (boot 파티션이 /boot/firmware에 마운트) |
config.txt 위치 | 같은 boot 파티션의 config.txt(예: /boot/firmware/config.txt)를 편집했는지 |
| 줄 길이·쉼표 | 오버레이 파라미터는 쉼표 구분. 공백으로 나누면 파싱이 깨질 수 있다(문서: 줄 길이 제한 언급) |
device_tree= 빈 값 | DT 자체를 끄는 설정. 오버레이만의 문제가 아님 |
# Bookworm 예시 — 실제 마운트를 먼저 확인
ls -l /boot/firmware/overlays/myoverlay.dtbo
grep -nE '^(dtoverlay|dtparam|device_tree)' /boot/firmware/config.txt
커스텀 .dtbo를 만든 뒤 이름과 디렉터리가 README의 규칙과 일치하는지만으로도 “적용 안 됨”의 절반은 갈립니다. 런타임 dtoverlay 유틸로 올리는 경우와 부팅 시 펌웨어 병합은 경로·실패 로그가 다릅니다. 부팅 병합 실패는 시리얼/펌웨어 로그·dmesg의 OF 관련 메시지를 함께 봅니다.
/proc/device-tree로 뭘 보나?
한 줄 답: 커널이 들고 있는 병합 결과 트리입니다. 오버레이가 넣으려던 노드·status·compatible·reg가 여기 없으면, 드라이버 로드 전에 DT 단계가 실패한 것으로 본다.
유용한 확인:
# 예상 노드 경로가 생겼는지
ls /proc/device-tree/soc/*/i2c@*/ 2>/dev/null
# 또는 문서·바인딩에 나온 경로를 직접
find /proc/device-tree -iname '*rtc*' 2>/dev/null | head
# status / compatible (바이너리 속성 → strings)
cat /proc/device-tree/.../status; echo
strings /proc/device-tree/.../compatible
# 전체 덤프(용량 큼)
dtc -I fs -O dts /proc/device-tree | less
해석 가이드:
- 노드 없음 → 컴파일/경로/
target라벨 불일치·픽스업 실패 쪽을 다시 본다. - 노드는 있는데
status = "disabled"→ 오버레이·dtparam이 enable을 안 했거나 다른 fragment가 덮었다. - 노드·status는 okay인데 장치 없음 → 그때부터
compatible↔ 드라이버, 모듈 블랙리스트, 전원/클럭을 본다(이 글 범위 밖이지만 분기점으로 명확하다). - 런타임으로만 올린 오버레이는
dtoverlay -l등으로 목록을 볼 수 있으나, 부팅 시 병합된 것은 목록에 안 나올 수 있다. 최종 판정은/proc/device-tree다.
Raspberry Pi dtoverlay/dtmerge 유틸 문서는 라이브 트리의 compatible·플랫폼 이름도 언급합니다. 디버그 순서를 바꾸지 않는 한, 심볼 → config 경로 → /proc/device-tree 세 단이면 “오버레이가 안 먹는다”의 대부분을 문서 근거로 가를 수 있습니다.
자주 묻는 질문
Q. /plugin/만 있고 -@가 없어도 되나요?
커널 리졸버 문서는 적절한 dtc 옵션과 /plugin/으로 __fixups__·__local_fixups__가 생긴 입력을 전제로 합니다. -@ 없이 라벨 target을 쓰면 병합이 실패하거나 잘못된 phandle로 남을 수 있습니다.
Q. dtoverlay -l에 안 보이면 실패인가요?
부팅 시 펌웨어가 이미 병합한 오버레이는 런타임 목록에 없을 수 있습니다. /proc/device-tree와 기대한 sysfs 장치를 기준으로 판단합니다.
Q. 가격·보드 추천은?
이 글 범위 밖입니다. 공식 오버레이 목록과 바인딩만 사용합니다.
정리
dtc -@+/plugin/→__fixups__/__symbols__확인.config.txt의dtoverlay=이름·overlays/*.dtbo실경로(Bookworm면/boot/firmware) 확인./proc/device-tree에서 노드·status·compatible 확인 후, 그다음에야 드라이버를 본다.
근거: Dynamic Resolver Notes, rpi overlays README, config.txt dtoverlay.