Linux 드라이버 개발 연구 노트 [3] : 장치 트리

목차

1. 장치 트리 란?

2. DTS, DTB 및 DTC의 관계

세, DTS 기본 구문

넷째, 작은 장치 트리 템플릿 만들기

다섯, 시스템에서 장치 트리의 구현

6 개의 특수 노드

1, 별칭 노드

2. 선택한 노드

일곱, 특별한 속성

1. 호환 속성 (호환 속성)

2. 모델 속성

3. 상태 속성

4. # address-cells 및 # size-cells 속성

5. reg 속성

6, 범위 속성

7, device_type 속성

여덟, 리눅스 커널의 OF 작동 기능


1. 장치 트리 란?

Device Tree (Device Tree) . 단어를 "device"와 "tree"로 분리하여 장치 트리를 설명하는 파일을 DTS (Device Tree Source)라고하며이 DTS 파일은 트리 구조를 사용하여 보드 레벨 장치, 즉 개발 기판을 설명합니다. 그림과 같이 CPU 수, 메모리 기본 주소, IIC 인터페이스에 연결된 장치, SPI 인터페이스에 연결된 장치 등과 같은 장치 정보 :

 

2. DTS, DTB 및 DTC의 관계

1. DTS는 장치 트리의 소스 파일 인 .c와 동일합니다.

2. DTC 도구는 .dts를 .dtb로 컴파일하는 gcc 컴파일러와 동일하며 DTC 도구의 소스 코드는 Linux 커널의 scripts / dtc 디렉토리에 있습니다.

3. DTB는 DTS를 컴파일 한 후 얻은 바이너리 파일입니다.

모든 DTS 파일을 컴파일 하여 메이크업의 dtbs을

다음과 같이 지정된 dtb를 컴파일 할 수도 있습니다. make imx6ull-alientek-emmc.dtb

dtb 파일을 컴파일 할 때 \ arch \ arm \ boot \ dts \ Makefile을 통해 컴파일 할 dts 장치 트리 소스 파일을 지정할 수 있습니다.

세, DTS 기본 구문

장치 트리에는 확장명이 .dtsi 인 헤더 파일도 있습니다. SOC 및 기타 모든 장치 / 플랫폼의 공통 정보를 공통 .dtsi 파일로 가져올 수 있습니다.

1, DTS도  시작, / 노드 트리가있는 전체 장치

2. 루트 노드의 장치 정보 설명

 

3. 루트 노드 외부의 & cpu0과 같은 일부 명령문은 "추가"입니다.

 

4. 노드 이름 지정

label:node-name@unit-address

label : 노드의 레이블 이고 뒤에 이름이옵니다. 예를 들어 선택 사항입니다.

intc: interrupt-controller@00a01000 完整的名字是interrupt-controller@00a01000

在后面追加的时候直接使用&intc

node-name : 노드 이름

단위 주소 : 일반적으로 주변 레지스터의 시작 주소, 때로는 I2C의 장치 주소 또는 기타 의미, 특정 노드의 특정 분석

넷째, 작은 장치 트리 템플릿 만들기

/dts-v1

#include .h
#include .dtsi

/ {
    /* skeleton.dtsi文件*/
    #address-cells = <1>;
    #size-cells = <1>;
    
    chosen {
      stdout-path = &uart1;  
    };
    
    aliases {
	};

	cpus {
	};

	intc: interrupt-controller@00a01000 {
	};

	clocks {
	};

	soc {
	};
 
    memory {
    };
    
    reserved-memory{
    };
    
    ...
}

다섯, 시스템에서 장치 트리의 구현

Linux 커널은 시작할 때 DTB 파일을 구문 분석 한 다음 / proc / device-tree 디렉토리에 해당 장치 트리 노드 파일을 생성합니다.

Linux 커널이 DTB 파일을 구문 분석하는 방법은 다음과 같습니다.

6 개의 특수 노드

1, 별칭 노드

2. 선택한 노드

주된 목적은 uboot의 bootargs 환경 변수 값을 명령 줄 매개 변수 인 command line 으로 Linux 커널에 전달하는 것 입니다. uboot의 bootargs 값은 다음과 같습니다.

bootargs=console=ttymxc0,115200 root=/dev/nfs rw 
nfsroot=192.168.199.158:/home/denghengli/linux/nfs/rootfs ip=192.168.199.20:192.168.199.158:192.168.199.1:255.255.255.0::eth0:off
//说明:192.168.199.158为ubuntu主机ip,192.168.199.20为开发板ip

Linux 커널 cmdline 값은 다음과 같습니다.

Kernel command line: console=ttymxc0,115200 root=/dev/nfs rw 
nfsroot=192.168.199.158:/home/denghengli/linux/nfs/rootfs ip=192.168.199.20:192.168.199.158:192.168.199.1:255.255.255.0::eth0:off

그렇다면 uboot는 어떻게 bootargs를 커널에 전달합니까?

확인 후 선택한 노드에 bootargs 속성이 포함되어 있고 속성 값이 uboot의 bootargs와 일치 함을 발견했습니다. uboot는 dtb에 접속하고 마침내 bootz 80800000-83000000을 통해 커널을 시작했습니다. 분석 결과 uboot에 bootargs 환경 변수와 dtb가있는 것으로 판단되어 범죄를 저지를 가능성이 가장 높습니다. 마지막으로, 선택된 노드가 uboot의 fdt_chosen 함수에서 발견되고 bootargs 속성이 여기에 추가되고 속성 값이 bootargs 변수의 값이됩니다.

일곱, 특별한 속성

1. 호환 속성 (호환 속성)

(1) 값은 문자열입니다. ompatible 속성은 장치와 드라이버를 바인딩하는 데 사용됩니다. 문자열 목록은 장치에서 사용할 드라이버를 선택하는 데 사용됩니다. 호환 속성의 값 형식은 "제조업체, 모델"입니다. 여기서 제조업체는 제조업체를 나타내고 모델은 일반적으로 모듈에 해당하는 드라이버 이름입니다. 예를 들어 imx6ull-alientek-emmc.dts의 사운드 노드는 i.MX6U-ALPHA 개발 보드의 오디오 장치 노드입니다.

compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";
其中 fsl表示厂商是飞思卡尔,“imx6ul-evk-wm8960”和 imx-audio-wm8960”表示驱动模块名字。
sound这个设备首先使用第一个兼容值在 Linux内核里面查找,看看能不能找到与之匹配的驱动文件,
如果没有找到的话就使用第二个兼容值查。

(2) 일반적으로 드라이버 파일에는 OF 매칭 테이블이 있습니다.이 OF 매칭 테이블은 일부 호환 가능한 값을 저장합니다. 장치 노드의 호환 속성 값이 OF 매칭 테이블의 값과 같으면 장치가이 드라이버를 사용할 수 있습니다. .

static const struct of_device_id imx_wm8960_dt_ids[] = {
	{ .compatible = "fsl,imx-audio-wm8960", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_wm8960_dt_ids);

static struct platform_driver imx_wm8960_driver = {
	.driver = {
		.name = "imx-wm8960",
		.pm = &snd_soc_pm_ops,
		.of_match_table = imx_wm8960_dt_ids,
	},
	.probe = imx_wm8960_probe,
	.remove = imx_wm8960_remove,
};
module_platform_driver(imx_wm8960_driver);

(3) 아래루트 노드 / 호환 . 커널이 시작되면이 플랫폼 또는 시스템을 지원하는지 확인합니다.

장치 트리가 사용되지 않는 경우 시스템 ID는 커널이이 시스템을 지원하는지 여부를 확인하는 데 사용됩니다.

#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
 __used \
 __attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
 
#define MACHINE_END \
};


MACHINE_START(MX35_3DS, "Freescale MX35PDK")
/* Maintainer: Freescale Semiconductor, Inc */
.atag_offset = 0x100,
.map_io = mx35_map_io,
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.init_time = mx35pdk_timer_init,
.init_machine = mx35_3ds_init,
.reserve = mx35_3ds_reserve,
.restart = mxc_restart,
MACHINE_END


展开以后:
static const struct machine_desc __mach_desc_MX35_3DS __used
 __attribute__((__section__(".arch.info.init"))) = {
.nr = MACH_TYPE_MX35_3DS, //机器ID
.name = "Freescale MX35PDK",
.atag_offset = 0x100,
.map_io = mx35_map_io,
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.init_time = mx35pdk_timer_init,
.init_machine = mx35_3ds_init,
.reserve = mx35_3ds_reserve,
.restart = mxc_restart,
};

장치 트리를 사용할 때 컴퓨터 ID는 사용되지 않지만 루트 노드 /에서 호환됩니다.

#define DT_MACHINE_START(_name, _namestr) \
static const struct machine_desc __mach_desc_##_name \
 __used \
 __attribute__((__section__(".arch.info.init"))) = { \
.nr = ~0, \
.name = _namestr,


DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)")
.map_io = imx6ul_map_io,
.init_irq = imx6ul_init_irq,
.init_machine = imx6ul_init_machine,
.init_late = imx6ul_init_late,
.dt_compat = imx6ul_dt_compat,
MACHINE_END


展开以后:
static const struct machine_desc __mach_desc_IMX6UL __used
 __attribute__((__section__(".arch.info.init"))) = {
.nr = ~0,
.name = "Freescale i.MX6 Ultralite (Device Tree)",
.map_io = imx6ul_map_io,
.init_irq = imx6ul_init_irq,
.init_machine = imx6ul_init_machine,
.init_late = imx6ul_init_late,
.dt_compat = imx6ul_dt_compat,
};

2. 모델 속성

모델 속성 값도 문자열입니다. 일반적으로 모델 속성은 다음과 같은 이름과 같은 장치 모듈 정보를 설명합니다.

model = "wm8960-audio";

3. 상태 속성

상태 속성은 이름을 보면 장치 상태와 관련이 있으며, 상태 속성 값도 장치의 상태 정보 인 문자열이며, 옵션 상태는 테이블에 표시됩니다.

4. # address-cells 및 # size-cells 속성

하위 노드가있는 장치에서는 하위 노드의 주소 정보를 설명하는 데 사용됩니다. # address-cells 속성 값은 자식 노드의 reg 속성에서 주소 정보가 차지하는 단어 길이 (32 비트)를 결정하고, # size-cells 속성 값은 자식 노드 reg 속성의 길이 정보가 차지하는 단어 길이 (32 비트)를 결정합니다. # address-cells 및 # size-cells는 자식 노드가 reg 속성 값을 작성하는 방법을 나타냅니다. 일반적으로 reg 속성은 주소와 관련된 내용이며 주소와 관련된 정보에는 시작 주소와 주소 길이, reg 속성의 두 종류가 있습니다. 형식 1은 다음과 같습니다.

reg = <address1 length1 address2 length2 address3 length3…………>

5. reg 속성

일반적으로 장치 주소 공간 리소스 정보를 설명하는 데 사용되며 일반적으로 특정 주변 장치의 레지스터 주소 범위 정보입니다.

reg = <0x4600 0x100>;

6, 범위 속성

ranges 속성의 값은 비어 있거나 (child-bus-address, parent-bus-address, length) 형식으로 작성된 숫자 행렬 일 수 있으며 ranges는 주소 매핑 / 변환 테이블이며 ranges 속성의 각 항목은 하위 주소, 상위 주소 및 주소로 구성됩니다. 공간 길이는 세 부분으로 구성됩니다.

child-bus-address : 자식 버스 주소 공간의 물리적 주소 부모 노드의 # address-cells는이 물리적 주소가 차지하는 단어 길이를 결정합니다.

parent-bus-address : 상위 버스 주소 공간의 물리적 주소와이 물리적 주소가 차지하는 단어 길이도 상위 노드의 # address-cells에 의해 결정됩니다.

length : 하위 주소 공간의 길이 부모 노드의 # size-cells는이 주소 길이가 차지하는 단어 길이를 결정합니다.

범위 속성 값이 null 값이면 하위 주소 공간이 상위 주소 공간과 정확히 동일하며 주소 변환이 필요하지 않음을 의미합니다.

7, device_type 속성

device_type 속성 값은 문자열이고 IEEE 1275는이 속성을 사용하여 장치의 FCode를 설명하지만 장치 트리에는 FCode가 없으므로이 속성도 삭제됩니다. 이 속성은 CPU 노드 또는 메모리 노드에만 사용할 수 있습니다. imx6ull.dtsi의 cpu0 노드는이 속성을 사용합니다.

여덟, 리눅스 커널의 OF 작동 기능

1. 드라이버의 디바이스 트리에서 노드 또는 속성 정보를 얻으려면 OF 함수를 사용해야하며 이러한 OF 함수의 프로토 타입은 include / linux / of.h 파일에 정의되어 있습니다.

2. 드라이버가 장치 트리 노드의 내용을 얻으려면 먼저 노드를 찾아야합니다.

 

 

추천

출처blog.csdn.net/m0_37845735/article/details/106976651