Linux 드라이버의 장치 트리

Linux 드라이버의 장치 트리

장치 트리의 기원-장치 트리는 무엇입니까

  • Open Firmware Device Tree 개발 펌웨어 장치 트리
    (1) Device Tree 는 CPU의 수와 유형, 메모리 기본 주소 및 크기, 버스 및 브리지, 주변 장치 연결, 인터럽트 컨트롤러 및 인터럽트 사용량, GPIO 컨트롤러를 포함한 정보를 설명 할 수 있습니다. 그리고 GPIO 사용량, 클럭 컨트롤러 및 클럭 사용량.
    (2) 장치 트리 정보는 사람이 읽는 습관에 적합한 ASCII 텍스트 파일로 저장되며 xml 파일과 유사합니다 .ARM Linux에서 .dts 파일은 ARM 머신에 해당하며 커널의 arch / arm / boot에 배치됩니다. / dts / 디렉토리 ( 2.6 이전 버전에서는 사용할 수 없음 ).
    (3) 디바이스 트리는 디바이스 정보의 언어를 설명하는 데 사용되는 데이터 구조로 , 특히 운영 체제에서 하드웨어를 설명하는 데 사용되므로 디바이스 정보를 하드 코딩 할 필요가 없습니다.
    (4) 디바이스 트리는 일련의 명명 된 노드 및 속성 으로 구성되며 노드 자체에는 자식 노드가 포함될 수 있습니다. 소위 속성은 실제로 쌍으로 나타나는 이름과 값 입니다.
    (5) 장치 트리 소스 파일 DTS는 DTB 이진 파일로 컴파일 부트 로더가 실행하는 오퍼레이팅 시스템에 전달하고, 상기 운영 체제를 파싱하고이를 확장 (전개 된)를이에 따라 하드웨어 장치의 토폴로지 다이어그램이 생성 되며,이 토폴로지 다이어그램을 사용하면 프로그래밍 과정에서 시스템에서 제공하는 인터페이스를 통해 디바이스 트리의 노드 및 속성 정보를 직접 얻을 수 있습니다.

장치 트리는 실제로 파일이며이 파일에는 많은 노드가 포함되어 있으며 이러한 노드는 CPU 정보, GPIO 정보 등을 포함한 장치 정보를 설명하는 데 전념합니다. 정보에는 많은 속성이 포함됩니다. 속성에는 사용을 위해 커널에 전달되는 다양한 값이 포함됩니다. 커널은 이러한 파일 정보를 분석하여 프로그래머에게 사용할 수 있습니다.

리눅스 디바이스 트리의 기원-디바이스 트리가있는 이유

  • Linux 2.6에서 arch / arm / plat-xxx 및 arch / arm / mach-xxx 는 많은 정크 코드로 채워져 있습니다. 상당수의 코드는 보드 수준의 세부 정보 만 설명하고 이러한 보드 수준 세부 정보는 커널에만 해당됩니다. 플랫폼 장치, 리소스, i2c_board_info, spi_board_info 및 보드의 다양한 하드웨어 platform_data와 같은 쓰레기 . s3c2410, s3c6410과 같은 일반적인 보드 수준 디렉토리 및 코드 양은 수만 줄입니다. 따라서 커널 코드가 매우 크고 관리가 번거로운 것을 하드 코딩이라고 합니다.
    2.6 커널 설명 장치 구성은 arch / arm / plat-samsung / dev-i2c0.c
    여기에 사진 설명 삽입
    arch / arm / mach-s5vp210 / mach-smdkv210.c와 유사합니다.
    여기에 사진 설명 삽입

  • Linus Torvalds는 2011 년에 ARM Linux 메일 링리스트에서이 모든 ARM이 엉덩이에 엄청난 고통이라고 선언했습니다.

  • 따라서 Linux 개발 커뮤니티가 수정하기 시작했고 디바이스 트리는 PowerPC와 같은 다른 아키텍처에서 처음 사용되었으며 ARM 아키텍처 개발 커뮤니티에서는 디바이스 트리를 사용하여 디바이스 정보를 설명하기 시작했습니다 .

신속하게 장치 트리 컴파일-DTC (장치 트리 컴파일러)

  • .dts를 .dtb로 컴파일하는 도구
  • DTC의 소스 코드는 커널의 scripts / dtc 디렉토리에 있으며 Linux 커널에서 Device Tree를 활성화하면 커널이 컴파일 될 때 호스트 도구 dtc가 컴파일됩니다 .
  • Linux 커널 arch / arm / boot / dts / Makefile에서 특정 soc가 선택 될 때 어떤 .dtb 파일이 컴파일되는지 설명합니다 . 예를 들어 EXYNOS에 해당하는 .dtb에는 다음이 포함됩니다.
 dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \ 
 				exynos4210-sndkv310.dtb \
 				exynos4412-origen.dtb \
  • 장치 트리 파일을 별도로 컴파일 할 수 있습니다. Linux 커널에서 make dtbs를 실행할 때 이전에 ARCH_EXYNOS를 선택하면 위의 .dtb가 해당 .dts에 의해 컴파일됩니다.

신속하게 장치 트리 이해 — 장치 트리 파일 컴파일

  • 참고로 오리 젠 보드의 디바이스 트리 파일을 참조하십시오.
cp arch/arm/boot/dts/exynos4410-origen.dts  arch/arm/boot/dts/exynos4412-fs4412.dts
  • 새 파일을 추가하려면 Makefile을 수정하여 컴파일해야합니다.
vim arch/arm/boot/dts/Makefile ,在 exynos4410-origen.dtb \ 下添加如下内容
exynos4412-fs4412.dtb
  • 장치 트리 파일 컴파일
make dtbs
  • 커널 및 장치 트리 파일을 / tftpboot 디렉토리에 복사합니다.
  • 시작 매개 변수 설정
set bootcmd tftp 0x41000000 uImage \; tftp 0x42000000 exynos4410-fs4412.dtb \; bootm 0x41000000 - 0x42000000

dtb에서 사용하는 프로세스

여기에 사진 설명 삽입

장치 트리 구문 및 내부 구조

  • 부분 명사
DT: Device Tree
FDT: Flattened Device Tree
OF: Open Firmware
DTS: device tree source
DTSI: device tree source include
DTB: device tree blob
DTC: device tree compiler

장치 트리 구문

(1) 노드
(2) 속성
(3) 루트 노드
(4) 호환 속성
(5) Reg 속성
(6) # address-cells 및 # address-siz 속성
(7) 인터럽트 정보 속성-인터럽트 및 인터럽트

  • 간단한 장치 트리 콘텐츠
/ {
	node1{
		a-string-property = "A string";
		a-string-list-property = "first string","second string";
		a-byte-data-property = [0x01 0x23 0x34 0x56];
		child-node1{
			first-child-property;
			second-child-property = <1>;
			a-string-property = "Hello,world";
			};
			child-node2{
				
			};		
	};
	
	node2{
		an-empty-property;
		a-cell-property = <1 2 3 4>;  /*each number (cell) is a uint32*/
		child-node1{
		};
	};
};
  • 노드
    노드 이름 : 각 노드는 "<name> [@ <device address>]"형식의 이름을 가져야합니다.
    < name >은 31 자 이하의 간단한 ASCII 문자열입니다. 노드 이름은 이름을 기반으로해야합니다. 그것은 어떤 종류의 장비를 반영합니다. 예를 들어, 3com 이더넷 어댑터의 노드 이름은 3com509
    < device address > 대신 ethernet으로 지정해야 장치 의 기본 주소에 액세스 할 수 있으며 해당 주소는 노드의 reg 속성에도 나열됩니다. 동일한 수준의 노드 이름은 다음과 같아야합니다. 고유하지만 주소가 다른 경우 여러 노드에서 동일한 공통 이름을 사용할 수도 있습니다. 물론 장치 주소도 선택 사항입니다.
    장치를 나타내는 트리의 모든 노드에는 호환 가능한 속성이 필요합니다.
  • 특성
    여기에 사진 설명 삽입
  • 공통 속성 — 호환 속성
    여기에 사진 설명 삽입
  • 공통 속성-# address-cells 및 # size-cells
    여기에 사진 설명 삽입
  • 공통 속성-reg 속성
    여기에 사진 설명 삽입
  • 공통 속성-인터럽트 정보의
    여기에 사진 설명 삽입
    예 : 유사
/ {
	compatible = "acme,coyotes-revenge";
	#address-cells = <1>;
	#size-cells = <1>;
	interrupt-parent = <&intc>;
	
	serial@101f0000 {
		compatible = "arm,pl011";
		reg = <0x10170000,0x1000>;
		interrupts = <1 0>;
	};

	intc:interrupt-controller@10140000{
		compatible = "arm,pl190";
		reg = <0x10140000,0x1000>;
		interrupt-controller;
		#interrupt-cells = <2>;
	};
}

arm 아키텍처의 경우 기호는 특정 의미입니다. Documentation / devicetree / bindings / arm / gic.txt
여기에 사진 설명 삽입

장치 트리 전투

  • 해당 보드에 다음 정보를 추가합니다. (테스트 전용)
  test_node@123456 {
            compatible = "farsight,test";
             reg = <0x114001E0 0x24
                    0x11400c20 0x24>;
            testprop,mytest;
            test_list_string = "read fish","blue fish";
            interrupt-parent = <&gpx1>;   //因为按键接到了 gpx1_1
            interrupts = <2 2>;
            //因为按键接到了gpx1_1,如果接到了gpx2_1,那么就是 <2 2>

    };  

make dtbs
를 개발 보드에 다운로드하면 / proc / device_tree / device_tree 에서 많은 노드 볼 수 있으며 test_node @ 123456 노드가있는 폴더를 볼 수 있습니다.

  • OF API OF에서 제공 하는 일반적으로 사용되는
    기능은 주로 / drivers / of / 디렉토리에 집중되어 있습니다.
    여기에 사진 설명 삽입
  • 장치 트리 프로세스 프로그래밍 분석
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>


#define U32_DATA_LEN 4

static int is_good;
static int irqno;

irqreturn_t key_irq_handler(int irqno,void *devid)
{
    
    
	printk("key pressed\n");
	return IRQ_HANDLED;
}

static int __init dt_drv_init(void)
{
    
    
	/*
		 test_node@123456 {
            compatible = "farsight,test";
            reg = <0x12345678 0x24
                    0x87654321 0x24>;
            testprop,mytest;
            test_list_string = "read fish","blue fish";
    };  
	*/
	//在代码中获取节点的所有信息
	//先把节点获取到
	struct device_node *np = NULL;
	struct property *prop = NULL;
	
	np = of_find_node_by_path("/test_node@123456");
	if(np)
	{
    
    
		printk("find test node ok\n");
		printk("find name = %s\n",np->name);
		printk("find full_name = %s\n",np->full_name);
	}
	else
	{
    
    
		printk("find test node failed\n");
	}


	//获取到节点中的属性
	prop = of_find_property(np,"compatible",NULL);
	if(prop)
	{
    
    
		printk("find compatible ok\n");
		printk("compatible value = %s\n",prop->value);
		printk("compatible name = %s\n",prop->name);
	}
	else
	{
    
    
		printk("find compatible failed\n");
	}

	if(of_device_is_compatible(np,"farsight,test"))
	{
    
    
		printk("we have a compatible name called farsight,test\n");
	}
	else
	{
    
    
		printk("This compatible is none\n");
	}
	

	//获取到属性中整数的数组
	u32 regdata[U32_DATA_LEN];
	int ret;
	
	ret = of_property_read_u32_array(np,"reg",regdata,U32_DATA_LEN);
	if(!ret)
	{
    
    
		printk("get reg data succeed\n");
		int i;
		for(i = 0; i < U32_DATA_LEN; i++)
		{
    
    
			printk("regdata[%d] = 0x%x\n",i,regdata[i]);
		}
	}
	else
	{
    
    
		printk("get reg data failed\n");
	}


	//读取属性中的字符串数组
	const char *pstr[3];
	int i;
	for(i = 0; i < 3; i++)
	{
    
    
		ret = of_property_read_string_index(np,"test_list_string",i,&pstr[i]);
		
		if(!ret)
		{
    
    
			printk("pstr[%d] = %s\n",i,pstr[i]);
		}
		else
		{
    
    
			printk("get pstr data failed\n");
		}
	}


	//属性值为空,可以用于设置标志
	if(of_find_property(np," testprop,mytest",NULL))
	{
    
    
		is_good = 1;
		printk("is good = %d\n",is_good);
	}

	//获取到中断的号码
	irqno = irq_of_parse_and_map(np,0);
	printk("irqno = %d\n",irqno);
	
	//验证中断号码是否有效
	ret = request_irq(irqno,key_irq_handler,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"key_irq",NULL);
	if(ret)
	{
    
    
		printk("request_irq error\n");
		return -EBUSY;
	}

	
	
	return 0;
}

static void __exit dt_drv_exit(void)
{
    
    
	free_irq(irqno,NULL);
}

module_init(dt_drv_init);
module_exit(dt_drv_exit);
MODULE_LICENSE("GPL");

추천

출처blog.csdn.net/qq_41782149/article/details/101149210