[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 \;
tftp Ox42000000 exynos4412-fs4412.dtb \;
bootm 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";
#address-cells= <2>;
#size-cells= <1>;
interrupt-parent =<&intc>;
serial@101f0000{
compatible="arm,pl011";
reg=<0x1 0x2 0x1000>;
interrupts=<1 0>;
}
intc:interrupt-controller@10140000{
compatible ="arm,pl190";
reg=<0x3 0x4 0x1000>;
interrupt-controller;
#interrupt-cells =<2>;
}
}
]
[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>;
};
====================================================================================================
====================================================================================================
#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;
np = of_find_node_by_path("/test_nod@12345678");
if(np!=0){
printk("node name = %s\n", np->name);
printk("node full name = %s\n", np->full_name);
}
struct property *prop = NULL;
prop = of_find_property(np, "compatible",NULL);
if(prop!=0)
{
printk("compatible value = %s\n", prop->value);
printk("compatible name = %s\n", prop->name);
}
if(of_device_is_compatible(np, "farsight,test") >0 )
{
printk("this node have a compatible named : farsight,test\n");
}
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);
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");