디바이스 트리
- 임베디드 개발자는 하드웨어를 변경해야할 때가 많이 생긴다.
- 커널이 어떤 하드웨어가 있는지 알아야 초기화 하고 사용한다.
- 하드웨어 자원의 명세를 어떻게 알까?
- flash가 SD카드였다가 eMMC였다가
- 커널에 하드코딩을 한다. => 하드웨어가 바뀌면 소스코드가 바뀌고 다시 빌드하고 다시 다운로드 해야한다.
- 커널은 그대로 두고 configuration만 따로
- 하드웨어 변경시 DTS파일만 컴파일한다.
- 커널 재컴파일 시간이 필요없음
- 컴파일러 소스 코드 => script/dtc/소스코드
- 노드들의 계층구조 => 트리
Arm architecture 에서 DTS 파일 위치:
arch/arm/boot/dts 또는 arch/arm64/boot/dts
▪ .dts files : 보드 레벨 정의
▪ .dtsi files : include 파일
device tree compiler로 DTS를 DTB로 컴파일
▪ DTB 는 부트로더에서 로드되고, 커널이 boot time에 parsing
• Device tree file 들은 여러 파일로나누어질 수 있음
Device Tree Syntax
![](https://velog.velcdn.com/images/ooweatah/post/f0fb43c2-55d3-4cdb-96c2-66eeb25f21ab/image.png)
/ : 트리의 루트를 나타낸다.
- 끝날 때 ;
- 값은 key , value 쌍으로 이루어짐
- 문자열인 경우 ; , 바이트인 경우 대괄호
- 다른 노드를 가리킬 수 있다.
- ch nod0가 1을 가리킴
- node1은 chnod0을 가리킴
Device Tree Content
![](https://velog.velcdn.com/images/ooweatah/post/21c2f385-d5c6-43ad-855a-fd4bcd1b1083/image.png)
device tree 의 root 에 포함되는 것:
cpus 노드 : 시스템의 각 CPU 명세
memory node : RAM의 주소와 크기
chosen 노드 : 부팅시에 arg를 kernel에 넘길
parameter (kernel command line)
SoC 버스를 정의하는 노드 (apb)
온보드 디바이스들에 대한 정의 노드
Device Tree Addressing
![](https://velog.velcdn.com/images/ooweatah/post/19b3692b-2731-4818-a828-ce25935d3ee5/image.png)
- cpus : 루트 밑에 나타날 수 있는 노드
- 듀얼코어 - cpu#0,1
- reg : address, length가 없는이유 = cpu이기 때문
- 어드레스 셀 : 주소의 길이 // 32비트 값이 1개
- 사이즈 셀 : 주소를 나타내기 위한 크기의 길이 // 0 : 32비트 값이 없다
- compatible : 디바이스 노드가 반드시 가져야함
- 이 디바이스를 위한 드라이버를 찾는다. (디바이스 드라이버와 연계됨)
CPU 어드레싱
![](https://velog.velcdn.com/images/ooweatah/post/5a5dad04-b8bb-4af2-b63f-c2222040f1ff/image.png)
- 64비트에서는 어드레스 셀이 2개
- 0209c000 : address 주소가 된다. // 구분을 하기 위함
- 진짜 address는 reg = <> 에 나타난다.
시작 주소가 2개인 경우?
-
예를 들어 I2C 같은 것을 써서 시리얼 버스에 여러개의 디바이스를 단다.
![](https://velog.velcdn.com/images/ooweatah/post/940181e6-d80b-4ef5-9f3f-50dc43c5a4f8/image.png)
-
ranges : 칩 셀렉트가 있는 부분을 0,1로 구분하여 주소를 지정하기 위해 사용하는 요소
ex) 이더넷이 0 , i2c가 1 ==> reg 첫 부분이 0/1
라즈베리 파이에선?
![](https://velog.velcdn.com/images/ooweatah/post/4be46d68-b4f0-421f-a952-3f520ffcfe6c/image.png)
-
Makefile
arch/arm64/boot/dts/broadcom/Makefile
-
Device tree 의 공통
인터페이스에서 벗어나 제조사별로 필요한 구현
▪ arch/arm64/Kconfig.platforms
-
DTS
▪ 예를 들어, arch/arm/boot/dts/bcm2711-rpi-4-b.dts
드라이버 연결 예시
![](https://velog.velcdn.com/images/ooweatah/post/d8f3a6ea-15f5-4cd7-97c8-5c7d2f601075/image.png)
- compatible 확인 가능
- struct of_device_id 에 매칭시켜준다.
- 디바이스 테이블에 넣게되고 드라이버는 ids를 가지고 드라이버를 매칭한다.
▪ arch/arm/boot/dts/bcm2711-rpi.dtsi
▪ linux/drivers/gpio/gpio-raspberrypi-exp.c
Kernel entry – 부트로더에서 커널 시작
![](https://velog.velcdn.com/images/ooweatah/post/7580c7b4-56a9-4a15-9f9f-5af53b4ddfe2/image.png)
![](https://velog.velcdn.com/images/ooweatah/post/4132ec73-481d-40d0-ac78-fa7229045ebb/image.png)
- 32, 64bit 모두 마지막은 start kernel로 진입
- 아직까지 아키텍처에 의존적이다.
![](https://velog.velcdn.com/images/ooweatah/post/a88632ca-383f-4ed1-b0ad-3f7f44e2277e/image.png)
DTB 처리
![](https://velog.velcdn.com/images/ooweatah/post/0ec7bd8b-7013-4295-ab4a-22c08d0526e3/image.png)
- setup arch는 아키텍처에 의존적이다. 하드웨어를 초기화해야하기 때문에.
- 이후 dtb의 포인터를 가지고 머신 디바이스 트리를 처리하게 된다.
- 부팅부터 어떤 일들을 하고 커널을 불러오게 되는데 하드웨어 초기화는 디바이스 트리라는 매커니즘을 통해서 부트로더가 전달을 하고 리눅스 커널이 이걸 가져다가 처리를 하게된다.
부팅 후 디바이스 트리
![](https://velog.velcdn.com/images/ooweatah/post/ee90be0d-813b-4e27-a7f7-d3511c06d5f8/image.png)