zoukankan      html  css  js  c++  java
  • IMX6ULL开发板Linux设备树实验

    在上一节迅为IMX6ULL开发板已经对DTS的语法做了比较详细的介绍,在本节中根据前面讲解的语法,从头到尾编写一个小型的设备树文件。我们会以一个虚拟的设备作为参考,提前假设一些外部设备和功能。当然这个虚拟的设备没有任何的意思,只是为了复习掌握前面学习的设备树语法。在实际产品的开发过程中,我们不需要从头编写一个dts设备树文件,一般都是使用soc厂商提供的dts文件,我们只需要根据自己的实际情况修改添加自己的内容即可。
    下面这个假设的设备,制造商为Acme”,并命名为“Coyote's Revenge”,具体功能如下:
    一个32ARM CPU
    l 处理器本地总线连接到内存映射的串行口、spi 总线控制器、i2c 控制器、中断控制器和外部总线桥
    l 256MB SDRAM起始地址为0
    两个串口起始地址:0x101F10000x101F2000
    l GPIO控制器起始地址:0x101F3000
    带有一下设备的SPI控制器起始地址:0x10170000
    n MMC插槽的SS管脚连接至GPIO #1
    l 外部总线桥挂载一下设备
    n SMC SMC91111 以太网,起始地址:0x10100000
    l i2c控制器起始地址:0x10160000,并挂载一下设备
    Maxim DS1338实时时钟,响应至从地址110100000x58
    n 64MB NOR闪存起始地址:0x30000000
    1、初始结构
    第一步就是要给这个虚拟的设备构建一个基本结构,这是一个有效的设备树的最基本的结构,在这个阶段需要唯一的标识该设备:
    / {
    compatible = "acme,coyotes-revenge";
    };
    2、添加CPU处理器
    接着就是描述每个CPU了,先添加一个名为“cpus”的容器节点,然后为每个CPU分别添加子节点,具体到我们的情况就是一个ARM的双核Cortex A9系统。
    / {
    compatible = "acme,coyotes-revenge";
     
    cpus {
    cpu@0 {
    compatible = "arm,cortex-a9";
    };
    cpu@1 {
    compatible = "arm,cortex-a9";
    };
    };
    };
     
    1、添加设备
    系统中的每个设备都表示为一个设备树节点,所以接下来就应该为这个设备树填充设备节点,我们先简单的形成一个框架,设备节点中的某些属性在后面不断添加。
    / {
    compatible = "acme,coyotes-revenge";
     
    cpus {
    cpu@0 {
    compatible = "arm,cortex-a9";
    };
    cpu@1 {
    compatible = "arm,cortex-a9";
    };
    };
     
    serial@101F0000 {
    compatible = "arm,pl011";
    };
     
    serial@101F2000 {
    compatible = "arm,pl011";
    };
     
    gpio@101F3000 {
    compatible = "arm,pl061";
    };
     
    interrupt-controller@10140000 {
    compatible = "arm,pl190";
    };
     
    spi@10115000 {
    compatible = "arm,pl022";
    };
     
    external-bus {
    ethernet@0,0 {
    compatible = "smc,smc91c111";
    };
     
    i2c@1,0 {
    compatible = "acme,a1234-i2c-bus";
    rtc@58 {
    compatible = "maxim,ds1338";
    };
    };
     
    flash@2,0 {
    compatible = "samsung,k8f1315ebm", "cfi-flash";
    };
    };
    };
    在此树中,已经为系统中的每个设备添加了节点,而且这个层次结构也反映了设备与系统的连接方式。例如,外部总线上的设备就是外部总线节点的子节点,i2c 设备就是 i2c 总线节点的子节点。通常,这个层次结构表现的是 CPU 视角的系统视图。
    2、CPU编址
    现在这个树还是无效的,因为他缺少关于设备之间的关联信息,接下来我们添加这些属性信息。
    cpus {
    #address-cells = <1>;
    #size-cells = <0>;
    cpu@0 {
    compatible = "arm,cortex-a9";
    reg = <0>;
    };
    cpu@1 {
    compatible = "arm,cortex-a9";
    reg = <1>;
    };
    };
     cpu 节点中,#address-cells 设置为 1#size-cells 设置为 0。这意味着子节点的 reg 值是一个单一的 uint32,这是一个不包含大小字段的地址,为这两个 cpu 分配的地址是 和 1cpu 节点的 #size-cells 为 是因为只为每个 cpu 分配一个单独的地址。
    3、内存映射设备
     cpu 节点里单一地址值不同,应该分配给内存映射设备一个地址范围。#size-cells 声明每个子节点的 reg 元组中长度字段的大小。在接下来的例子中,每个地址值是 1 cell32 位),每个长度值也是 1 cell,这是典型的 32 位系统。
    / {
    #address-cells = <1>;
    #size-cells = <1>;
     
    ...
     
    serial@101f0000 {
    compatible = "arm,pl011";
    reg = <0x101f0000 0x1000 >;
    };
     
    serial@101f2000 {
    compatible = "arm,pl011";
    reg = <0x101f2000 0x1000 >;
    };
     
    gpio@101f3000 {
    compatible = "arm,pl061";
    reg = <0x101f3000 0x1000
    0x101f4000 0x0010>;
    };
     
    interrupt-controller@10140000 {
    compatible = "arm,pl190";
    reg = <0x10140000 0x1000 >;
    };
     
    spi@10115000 {
    compatible = "arm,pl022";
    reg = <0x10115000 0x1000 >;
    };
     
    ...
    };
    一些挂在总线上的设备有不同的编址方案。例如一个带独立片选线的设备也可以连接至外部总线。由于父节点会为其子节点定义地址域,所以可以选择不同的地址映射来最恰当的描述该系统。
    external-bus {
    #address-cells = <2>
    #size-cells = <1>;
     
    ethernet@0,0 {
    compatible = "smc,smc91c111";
    reg = <0 0 0x1000>;
    };
     
    i2c@1,0 {
    compatible = "acme,a1234-i2c-bus";
    reg = <1 0 0x1000>;
    rtc@58 {
    compatible = "maxim,ds1338";
    };
    };
     
    flash@2,0 {
    compatible = "samsung,k8f1315ebm", "cfi-flash";
    reg = <2 0 0x4000000>;
    };
    };
    外部总线的地址值使用了两个 cell,一个用于片选号;另一个则用于片选基址的偏移量。而长度字段则还是单个 cell,这是因为只有地址的偏移部分才需要一个范围量。所以,在这个例子中,每个 reg 项都有三个 cell:片选号、偏移量和长度。
    4、非内存映射设备
    其他的设备没有被映射到处理机总线上。虽然这些设备可以有一个地址范围,但他们并不是由 CPU 直接访问。取而代之的是,父设备的驱动程序会代表 CPU 执行简介访问。
     i2c 设备为例,每个设备都分配了一个地址,但并没有与之关联的长度或范围信息。这看起来和 CPU 的地址分配很像
    i2c@1,0 {
    compatible = "acme,a1234-i2c-bus";
    #address-cells = <1>;
    #size-cells = <0>;
    reg = <1 0 0x1000>;
    rtc@58 {
    compatible = "maxim,ds1338";
    reg = <58>;
    };
    };
    5、地址转换
    前面描述了如何给设备分配地址,但目前来说这些地址还只是设备节点的本地地址,最终要将这些地址映射成 CPU 可使用的地址
    根节点始终描述的是 CPU 视角的地址空间。根节点的子节点已经使用的是 CPU 的地址域,所以它们不需要任何直接映射。例如,serial@101f0000 设备就是直接分配的 0x101f0000 地址。
    那些非根节点直接子节点的节点就没有使用 CPU 地址域。为了得到一个内存映射地址,设备树必须指定从一个域到另一个域地址转换地方法,而 ranges 属性就为此而生。
    下面就是一个添加了 ranges 属性的示例设备树。
    / {
    compatible = "acme,coyotes-revenge";
    #address-cells = <1>;
    #size-cells = <1>;
    ...
    external-bus {
    #address-cells = <2>
    #size-cells = <1>;
    ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
    1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
    2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
     
    ethernet@0,0 {
    compatible = "smc,smc91c111";
    reg = <0 0 0x1000>;
    };
     
    i2c@1,0 {
    compatible = "acme,a1234-i2c-bus";
    #address-cells = <1>;
    #size-cells = <0>;
    reg = <1 0 0x1000>;
    rtc@58 {
    compatible = "maxim,ds1338";
    reg = <58>;
    };
    };
    flash@2,0 {
    compatible = "samsung,k8f1315ebm", "cfi-flash";
    reg = <2 0 0x4000000>;
    };
    };
    };
    那么这三个 ranges 被翻译为:
    从片选 0 开始的偏移量 被映射为地址范围:
    0x10100000..0x1010ffff
    从片选 0 开始的偏移量 被映射为地址范围:
    0x10160000..0x1016ffff
    从片选 0 开始的偏移量 被映射为地址范围:
    0x30000000..0x10000000
    另外,如果父地址空间和子地址空间是相同的,那么该节点可以添加一个空的 range 属性。一个空的 range 属性意味着子地址将被 1:1 映射到父地址空间。
     
    8、添加中断
    与遵循树的自然结构而进行的地址转换不同,机器上的任何设备都可以发起和终止中断信号。另外地址的编址也不同于中断信号,前者是设备树的自然表示,而后者者表现为独立于设备树结构的节点之间的链接。描述中断连接需要四个属性:
    ■ interrupt-controller -一个空的属性定义该节点作为一个接收中断信号的设备。
    ■ #interrupt-cells - 这是一个中断控制器节点的属性。它声明了该中断控制器的中断指示符中 cell 的个数(类似于 #address-cells 和 #size-cells)。
    ■ interrupt-parent -这是一个设备节点的属性,包含一个指向该设备连接的中断控制器的 phandle。那些没有 interrupt-parent 的节点则从它们的父节点中继承该属性。
    ■ interrupts - 一个设备节点属性,包含一个中断指示符的列表,对应于该设备上的每个中断输出信号。
    中断指示符是一个或多个 cell 的数据(由 #interrupt-cells 指定),这些数据指定了该设备连接至哪些输入中断。在以下的例子中,大部分设备都只有一个输出中断,但也有可能在一个设备上有多个输出中断。一个中断指示符的意义完全取决于与中断控制器设备的 binding。每个中断控制器可以决定使用几个 cell 来唯一的定义一个输入中断。
    / {
    compatible = "acme,coyotes-revenge";
    #address-cells = <1>;
    #size-cells = <1>;
    interrupt-parent = <&intc>;
     
    cpus {
    #address-cells = <1>;
    #size-cells = <0>;
    cpu@0 {
    compatible = "arm,cortex-a9";
    reg = <0>;
    };
    cpu@1 {
    compatible = "arm,cortex-a9";
    reg = <1>;
    };
    };
     
    serial@101f0000 {
    compatible = "arm,pl011";
    reg = <0x101f0000 0x1000 >;
    interrupts = < 1 0 >;
    };
     
    serial@101f2000 {
    compatible = "arm,pl011";
    reg = <0x101f2000 0x1000 >;
    interrupts = < 2 0 >;
    };
     
    gpio@101f3000 {
    compatible = "arm,pl061";
    reg = <0x101f3000 0x1000
    0x101f4000 0x0010>;
    interrupts = < 3 0 >;
    };
     
    intc: interrupt-controller@10140000 {
    compatible = "arm,pl190";
    reg = <0x10140000 0x1000 >;
    interrupt-controller;
    #interrupt-cells = <2>;
    };
     
    spi@10115000 {
    compatible = "arm,pl022";
    reg = <0x10115000 0x1000 >;
    interrupts = < 4 0 >;
    };
     
    external-bus {
    #address-cells = <2>
    #size-cells = <1>;
    ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
    1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
    2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
     
    ethernet@0,0 {
    compatible = "smc,smc91c111";
    reg = <0 0 0x1000>;
    interrupts = < 5 2 >;
    };
     
    i2c@1,0 {
    compatible = "acme,a1234-i2c-bus";
    #address-cells = <1>;
    #size-cells = <0>;
    reg = <1 0 0x1000>;
    interrupts = < 6 2 >;
    rtc@58 {
    compatible = "maxim,ds1338";
    reg = <58>;
    interrupts = < 7 3 >;
    };
    };
     
    flash@2,0 {
    compatible = "samsung,k8f1315ebm", "cfi-flash";
    reg = <2 0 0x4000000>;
    };
    };
    };
    需要注意的事情:
    ■ 这个机器只有一个中断控制器:interrupt-controller@10140000
    ■ 中断控制器节点上添加了‘inc:’标签,该标签用于给根节点的 interrupt-parent 属性分配一个 phandle。这个 interrupt-parent 将成为本系统的默认值,因为所有的子节点都将继承它,除非显示覆写这个属性。
    ■每个设备使用 interrupts 属性来不同的中断输入线。
    ■ #interrupt-cells 是 2,所以每个中断指示符都有 个 cell。本例使用一种通用的模式,也就是用第一个 cell 来编码中断线号;然后用第二个 cell 编码标志位,比如高电平/低电平有效,或者边缘/水平触发。对于任何给定的中断控制器,请参考该控制器的 binding 文档以了解指示符如何编码。
    经过上面几步后,一个较为完整的设备树文件就形成了,当然这个设备树文件只是作为一个实验,让我们在熟悉一遍关于设备树的知识,对于不同平台的设备,设备树文件会有所不同,需要根据具体的soc平台手册具体修改。
  • 相关阅读:
    解决DeDeCms文章中上传的图片点击新窗口打开的方法
    织梦dedecms 5.7解决修改文章后,发布时间自动更新的方法
    织梦DedeCMS实用技巧-八大安全措施
    data目录迁移到web以外目录
    《DSP using MATLAB》示例Example6.6
    《DSP using MATLAB》示例 Example 6.5
    《DSP using MATLAB》示例Example6.4
    《DSP using MATLAB 》示例Example6.3
    《DSP using MATLAB》示例Example6.2
    《DSP using MATLAB》示例Example6.1
  • 原文地址:https://www.cnblogs.com/liyue3/p/13425065.html
Copyright © 2011-2022 走看看