//================================================================================================================================= [1] >> 设备树基础知识 [ 0>>设备树由来 [ 在Linux2.6中,arch/arm/plat-xxx和arch/arm/mach-xxx(存放产品设备信息)中充斥着大量的垃圾代码
	    Linux开发社区就开始整改,借鉴PowerPC设备树 ] 1>>FDT = Flattened device tree 展开设备树 -- /proc/device-tree/ 各个设备树节点 2>>OF = open firmware(固件) = 打开固件 3>>DTSI = device tree source include 设备树源码头的文件 4>>DTC = device tree compiler [ 1>>开源,源代码位于/script/dtc  #注意:在Linux内核使能了Device Tree的情况下,TDC才能被编译出来 2>>DTS --> DTC --> DTB 3>>编译DTC的步骤 [ 1>>步骤1:在inux内核的ach/arm/boot/dts/Makefile中,选中EXYNOS的Soc被选中后CONFIG_ARCH_EXYNOS宏被置1 [方法1举例] dtb-$(CONFIG_ARCH_EXYNOS)+ = exynos 4210-origen dtb 
					exynos 4412-fs4412.dtb 
					exynos 4210-trats.dtb 2>>步骤2: 再Linux内核下make dtbs [方法2举例] ubuntu:~/Linux_4412/kernel/linux-3.14$make dtbs     
					DTC      arch/arm/boot/dts/exynos 4412-fs4412 dtb
					DTC      arch/arm/boot/dts/ 4210-trats dtb 3>>步骤3:将编译后的DTB拷贝到开发板 4>>步骤4:在bootloader设置启动该dtb文件 [步骤4举例] set bootcmd tftp 0x41000000 ulmage \; //内核加载到0x41000000地址 tftp Ox42000000 exynos4412-fs4412.dtb \; //将设备树dtb文件加载到Ox42000000 bootm 0x41000000-0x42000000 \; //解析0x41000000-0x42000000内存 ] ] 5>>DTB = device tree binary   设备树二进制 6>>boot loader运行 --> DTB传递给操作系统 --> 操作系统将DTB展开(Flattened) --> 产生硬件拓扑图 --> 编程获取设备树拓扑图的节点与属性
							↓							↓							 ↓			
							↓							↓ [/proc/device-tree/][DTB展开在平台总线内,平台总线可直接使用] [描述了所有硬件信息] ] //================================================================================================================================= [2] >> 设备树语法 [ /{  //根节点 string1 = "hello word" ; //字符串数据 data1 = <0xFF12 0xEE34 8888> ; //非二进制数据 bindata1 = [11 22 33 44] ; //二进制数据 mixdata1 = [11 22 33 44],"hello word",<0xFF12> ; //混合数据 compatible ="acme, coyotes-revenge"; //"制造商,型号",每个节点必须由compatiblej节点 #address-cells= <2>; //表示子节点的reg属性只有1个寄存器地址 #size-cells= <1>; //表示子节点的reg属性只有1个表示寄存器长度 interrupt-parent =<&intc>; //父中断 -- 继承intc节点 serial@101f0000{  //[设备地址101f0000] [node-name : serial] [device-full-name : serial@101f0000] compatible="arm,pl011"; //"制造商,型号",每个节点必须由compatiblej节点 reg=<0x1 0x2 0x1000>; // <寄存器1地址 寄存器2地址 寄存器空间大小>  interrupts=<1 0>; //中断gpx_1 ,触发方式=0 } intc:interrupt-controller@10140000{  //设备名interrupt-controller + 设备地址10140000 compatible ="arm,pl190"; //"制造商,型号",每个节点必须由compatiblej节点 reg=<0x3 0x4 0x1000>; //<寄存器1地址 寄存器2地址 寄存器空间大小>  interrupt-controller; //中断控制器节点 #interrupt-cells =<2>; //子节点的interrupt = <x1 x2> } } ] //================================================================================================================================= [3] >> 常用OF API [ 1>>struct device_node *of_find_node_by_path(const char *path) #将展开后的节点封装在device_node对象[device_node对象 <--> 设备树节点] 2>>struct property *of_find_property(const struct device_node *np, const char *name,int *lenp) #根据属性名获取属性值 -- 存储在属性结构体property
		#由于属性值可能是int,char,str,所以用void类型存储在property结构体,使用时在强制转换 3>>int of_device_is_compatible(const struct device_node *device,const char *compat) #判断compatible值是否该设备树节点的compatible 4>>struct device_node *of_get_parent(const struct device_node *node) #获取当前节点的父亲节点 5>>int of_property_read_u32_array(const struct device_node *np,const char *propname, u8 *out_values, size_t sz) #获取u32数组 6>>unsigned int irq_of_parse_and_map(struct device_node *dev, int index) #解析interrupt的中断号 ] //================================================================================================================================= 
==================================================================================================== 实验 >> 获取下面设备树的信息
		test_nod@12345678{  compatible = "test,farsight"; reg = <0xa2345678 0x24 0xb3456780 0x24>; mytest; test_list_string = "red fish", "blue fish"; interrupt-parent = <&gpx1>; interrupts = <1 2>; //gpx1_1,中断触发方式2 }; ==================================================================================================== ==================================================================================================== // d t _ d e v . c #include <linux/init.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/interrupt.h> #define ARRAY_MAX 4 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) {  struct device_node *np = NULL; //创建设备树节点 --> device_node np = of_find_node_by_path("/test_nod@12345678"); if(np!=0){  printk("node name = %s\n", np->name); //test_nod printk("node full name = %s\n", np->full_name); //test_nod@12345678 } //节点树属性对象 struct property *prop = NULL; //获取compatible属性值 prop = of_find_property(np, "compatible",NULL); if(prop!=0) {  printk("compatible value = %s\n", prop->value); printk("compatible name = %s\n", prop->name); } //判断该设备树节点的compatible值 if(of_device_is_compatible(np, "farsight,test") >0 ) {  printk("this node have a compatible named : farsight,test\n"); } //读取u32数组 u32 regdata[ARRAY_MAX]; int ret; ret = of_property_read_u32_array(np, "reg", regdata, ARRAY_MAX); if(!ret) {  int i; for(i=0; i<ARRAY_MAX; i++) printk("----regdata[%d] = 0x%x\n", i,regdata[i]); } //读取字符串数组 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]); } } //获取到中断号 irqno = irq_of_parse_and_map(np, 0); printk("-----irqno = %d\n", irqno); //申请中断服务函数key_irq_handler 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");