最终还是搞到这来了,学习中,记录点笔记
设备树从/根开始,这点接触过Linux的人都懂。
设备树的内容其实还是为了给驱动用的,所以其实内容都是由驱动决定的,不过实际写的时候遵循一定语法
/* ethernet@e000b000 {
compatible = "cdns,zynq-gem", "cdns,gem";
reg = <0xe000b000 0x0000012e>;
status = "okay";
interrupts = <0x00000000 0x00000018 0x00000001>;
clocks = <0x00000001 0x00000001 0x00000135 0x5f636c6b 0x00000000 0x0000000f>;
clock-names = "pclk", "hclk", "tx_clk";
#address-cells = <0x00000001>;
#size-cells = <0x00000000>;
local-mac-address = [00 0a 35 00 00 00];
phy-mode = "mii";
ethernet-phy@0 {
reg = <0x00000000>;
};
}; */
例如上面这一段 ethernet@e000b000 这个节点,ethernet表示节点名字,字面看是网卡,其实完全可以起一个其他名字诸如wangka1这样的,后面@e000b000表示设备寄存器首地址,多个网卡可以用相同的节点名字,但寄存器地址不一样就行。节点包含了寄存器地址后,属性里就必须包含reg= <>;这个属性,地址嘛还是@后面那个地址。
ethernet_phy: ethernet-phy@0 {
reg = <0>;
};
另外,像这样写的 ethernet_phy : 这个冒号前面的就是个标签。其他地方可以引用。
clock-names = "pclk", "hclk", "tx_clk";
#address-cells = <0x00000001>;
#size-cells = <0x00000000>;
上面的就是节点的属性了。比节点名还可以多2个字符 ? #,搞不懂为啥这么搞,第一次看到#还以为是注释。。。。。
中断一般包括中断产生设备和中断处理设备。中断控制器负责处理中断,每一个中断都有对应的中断号及触发条件。中断产生设备可能有多个中断源,有时多个中断源对应中断控制器中的一个中断,这种情况中断产生设备的中断源称之为中断控制器中对应中断的子中断。一般情况中断产生设备数量要多于中断控制器,多个中断产生设备的中断都由一个中断控制器处理,这种多对一的关系也很像一个树形结构,所以在设备树中,中断也被描述成树,叫中断树。以下表述的时候为了明确是在说中断树,在父节点和子节点前边我们都加上“中断”二字,是为了防止和设备树的父节点、子节点混淆(虽然大部分情况设备树的父子关系就是中断树的父子关系,但是因为存在特例,所以我们还是强调是中断父子关系)。
中断产生设备用interrupts属性描述中断源(interrupt specifier),因为不同的硬件描述中断源需要的数据量不同,所以interrupts属性的类型也是。为了明确表示一个中断由几个u32表示,又引入了#interrupt-cells属性,#interrupt-cells属性的类型是u32,假如一个中断源需要2个u32表示(一个表示中断号,另一个表示中断类型),那么#interrupt-cells就设置成2。有些情况下,设备树的父节点不是中断的父节点(主要是中断控制器一般不是父节点),为此引入了interrupt-parent属性,该属性的类型是,用来引用中断父节点(我们前边说过,一般用父节点的标签,这个地方说中断父节点而不是中断控制器是有原因的)。如果设备树的父节点就是中断父节点,那么可以不用设置interrupt-parent属性。interrupts属性和interrupt-parent属性都是中断产生设备节点的属性,但是#interrupt-cells属性不是,#interrupt-cells属性是中断控制器节点以及interrupt nexus节点的属性,这两类节点都可能是中断父节点。
中断控制器节点用interrupt-controller属性表示自己是中断控制器,这个属性的类型是空,不用设置值,只要存在这个节点就表示该节点是中断控制器。除了这个属性外,中断控制器节点还有#interrupt-cells属性,用来表示该中断控制器直接管理下的interrupt domain(后边我们会讲中断控制器的中断子节点interrupt nexus节点有单独的interrupt domain)用几个u32表示一个中断源(interrupt specifier)。中断控制器节点就包括interrupt-controller和#interrupt-cells两个关于中断的属性。中断控制器的#address-cells属性和中断映射有关系,但是该属性不是为中断设计的,中断映射只是用到了这个属性而已。
从软件的层面讲model属性仅仅表示一个名字而已,没有更多的作用。compatible属性则不同,该属性决定软件如何匹配硬件对硬件进行初始化。属性那一节我们说过compatible属性的类型是字符串数组,按照范围从小到大的顺序排列,每个字符串表示一种匹配类型。根节点的compatible属性表示平台如何匹配,比如‘compatible = “samsung,smdk5420”, “samsung,exynos5420”, “samsung,exynos5”’,表示软件应该首先匹配’samsung,smdk5420’,这个是一款开发板。如果无法匹配,再试着匹配"samsung,exynos5420",这个是一款芯片平台。如果还是无法匹配,还可以试着匹配 “samsung,exynos5”,这是一个系列的芯片平台。这里说的匹配是指软件根据该信息找到对应的代码,如对应的初始化函数。
关于根节点的"compatible"属性我们就说到这,一句话总结下就是内核通过"compatible"属性找到对应的平台描述信息,按照范围从小到大尽量匹配范围最小的,如果匹配不到,那么说明内核不支持该平台,系统将在初始化的时候就出错。
根节点还可能包含的属性为#address-cells和#size-cells,规范中说明这两个属性是必须的,实际应用时是可选的,还记得属性那一节说这两个属性如果没有都是有默认值的,#address-cells默认值为2,#size-cells默认值为1。根节点下必须包含的子节点为cpus和memory,后边会说明cpus下边还有每个cpu的子节点,memory节点下边定义的就是memory的起始地址及大小,所以根节点的#address-cells和#size-cells属性实际上说明的就是从cpu角度看系统总线的地址长度和大小。
根节点那一节我们说过,最简单的设备树也必须包含cpus节点和memory节点。memory节点用来描述硬件内存布局的。如果有多块内存,既可以通过多个memory节点表示,也可以通过一个memory节点的reg属性的多个元素支持。举一个例子,假如某个64位的系统有两块内存,分别是
• RAM: 起始地址 0x0, 长度 0x80000000 (2GB)
• RAM: 起始地址 0x100000000, 长度 0x100000000 (4GB)
对于64位的系统,根节点的#address-cells属性和#size-cells属性都设置成2。一个memory节点的形式如下(还记得前几节说过节点地址必须和reg属性第一个地址相同的事情吧):
memory@0 {
device_type = “memory”;
reg = <0x000000000 0x00000000 0x00000000 0x80000000
0x000000001 0x00000000 0x00000001 0x00000000>;
};
两个memory节点的形式如下:
memory@0 {
device_type = “memory”;
reg = <0x000000000 0x00000000 0x00000000 0x80000000>;
};
memory@100000000 {
device_type = “memory”;
reg = <0x000000001 0x00000000 0x00000001 0x00000000>;
};
chosen节点也位于根节点下,该节点用来给内核传递参数(不代表实际硬件)。对于Linux内核,该节点下最有用的属性是bootargs,该属性的类型是字符串,用来向Linux内核传递cmdline。规范中还定义了stdout-path和stdin-path两个可选的、字符串类型的属性,这两个属性的目的是用来指定标准输入输出设备的,在linux中,这两个属性基本不用。