本文转载自:http://blog.csdn.net/fengyuwuzu0519/article/details/74177978

版权声明:本文为博主原创文章,转载请注明http://blog.csdn.net/fengyuwuzu0519。

 

目录(?)[+]

 
  • 硬件平台:tiny4412
  • 系统:linux-4.4
  • 文件系统:busybox-1.25
  • 编译器: arm-none-linux-gnueabi-gcc(gcc version 4.8.3 20140320)
  • uboot:友善自带uboot.

一、DTS引入

1.什么是DTS?为什么要引入DTS?

DTS即Device Tree Source设备树源码,DeviceTree是一种描述硬件的数据结构,它起源于OpenFirmware (OF)。

在Linux2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,比如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data,这些板级细节代码对内核来讲只不过是垃圾代码。而采用DeviceTree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。

2.ARM平台的相关code做出如下相关规范调整

•ARM的核心代码仍然保存在arch/arm目录下
•ARM SoC corearchitecture code保存在arch/arm目录下
•ARMSOC的周边外设模块的驱动保存在drivers目录下
•ARMSOC的特定代码在arch/arm/mach-xxx目录下
•ARM SOCboard specific的代码被移除,由DeviceTree机制来负责传递硬件拓扑和硬件资源信息。

本质上,Device Tree改变了原来用hardcode方式将HW配置信息嵌入到内核代码的方法,改用bootloader传递一个DB的形式。

3.DTS的加载过程

如果要使用DeviceTree,首先用户要了解自己的硬件配置和系统运行参数,并把这些信息组织成DeviceTree source file。通过DTC(DeviceTree Compiler),可以将这些适合人类阅读的DeviceTree source file变成适合机器处理的DeviceTree binary file(DTB,devicetree blob)。在系统启动的时候,bootprogram(例如:firmware、bootloader)可以将保存在flash中的DTB copy到内存(当然也可以通过其他方式,例如可以通过bootloader的交互式命令加载DTB),并把DTB的起始地址传递给OSkernel。对于计算机系统(computersystem),一般是firmware->bootloader->OS,对于嵌入式系统,一般是bootloader->OS。

4.DTS的描述信息

Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。在DeviceTree中,可描述的信息包括(原先这些信息大多被hardcode到kernel中):

•CPU的数量和类别
•内存基地址和大小
•总线和桥
•外设连接
•中断控制器和中断使用情况
•GPIO控制器和GPIO使用情况
•Clock控制器和Clock使用情况

它基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。

一个.dts文件对应一个ARM的machine,一般放置在内核的arch/arm/boot/dts/目录。由于一个SoC可能对应多个machine(一个SoC可以对应多个产品和电路板),势必这些.dts文件需包含许多共同的部分,Linux内核为了简化,把SoC公用的部分或者多个machine共同的部分一般提炼为.dtsi。所有的ARMSoC的.dtsi都引用了skeleton.dtsi,即#include"skeleton.dtsi“或者 /include/ "skeleton.dtsi"

5.变化

platform之前:

现在:

二、设备树文件

1、修改设备树文件支持GPIO按键中断

(/work/linux-4.4.0/linux-4.4/arch/arm/boot/dts/exynos4412-tiny4412.dts)
  1. interrupt_demo: interrupt_demo {
  2. compatible         = "tiny4412,interrupt_demo";
  3. tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>;
  4. tiny4412,int_gpio2 = <&gpx3 3 GPIO_ACTIVE_HIGH>;
  5. tiny4412,int_gpio3 = <&gpx3 4 GPIO_ACTIVE_HIGH>;
  6. tiny4412,int_gpio4 = <&gpx3 5 GPIO_ACTIVE_HIGH>;
  7. };

2、完整的设备树文件:

Device Tree有自己的独立的语法,它的源文件为.dts,编译后得到.dtb,Bootloader在引导Linux内核的时候会将.dtb地址告知内核。之后内核会展开Device Tree并创建和注册相关的设备,因此arch/arm/mach-xxx和arch/arm/plat-xxx中大量的用于注册platform、I2C、SPI板级信息的代码被删除,而驱动也以新的方式和.dts中定义的设备结点进行匹配。
  1. /*
  2. * FriendlyARM's Exynos4412 based TINY4412 board device tree source
  3. *
  4. * Copyright (c) 2013 Alex Ling <kasimling@gmail.com>
  5. *
  6. * Device tree source file for FriendlyARM's TINY4412 board which is based on
  7. * Samsung's Exynos4412 SoC.
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. */
  13. /dts-v1/;
  14. #include "exynos4412.dtsi"
  15. #include <dt-bindings/gpio/gpio.h>
  16. / {  //root结点"/"
  17. model = "FriendlyARM TINY4412 board based on Exynos4412";
  18. //root结点"/"的属性compatible,组织形式为:<manufacturer>,<model>
  19. //Linux内核透过root结点"/"的compatible 属性即可判断它启动的是什么machine
  20. //compatible 属性是一个字符串的列表,列表中的第一个字符串表征了结点代表的确切设备,
  21. //形式为"<manufacturer>,<model>",其后的字符串表征可兼容的其他设备。
  22. //可以说前面的是特指,后面的则涵盖更广的范围。
  23. compatible = "friendlyarm,tiny4412", "samsung,exynos4412", "samsung,exynos4";
  24. //以下开始为子节点
  25. //子结点的命名,它们遵循的组织形式为:<name>[@<unit-address>],
  26. //<>中的内容是必选项,[]中的则为可选项。name是一个ASCII字符串,用于描述结点对应的设备类型,如memory;
  27. //多个相同类型设备结点的name可以一样,只要unit-address不同即可
  28. //chosen节点并不代表一个真正的设备,而是用来在Firmware与操作系统间传递数据,如启动参数。
  29. chosen {                         //子结点"chosen"
  30. stdout-path = &serial_0;
  31. bootargs = "root=/dev/ram0 rw rootfstype=ext4 console=ttySAC0,115200 init=/linuxrc earlyprintk";
  32. };
  33. memory {                         //子结点"memory"
  34. reg = <0x40000000 0x40000000>;
  35. };
  36. leds {                           //子结点"leds"
  37. compatible = "gpio-leds";
  38. led1 {                         //子子结点"led1"
  39. label = "led1";
  40. gpios = <&gpm4 0 GPIO_ACTIVE_LOW>;
  41. default-state = "off";
  42. linux,default-trigger = "heartbeat";
  43. };
  44. led2 {
  45. label = "led2";
  46. gpios = <&gpm4 1 GPIO_ACTIVE_LOW>;
  47. default-state = "off";
  48. };
  49. led3 {
  50. label = "led3";
  51. gpios = <&gpm4 2 GPIO_ACTIVE_LOW>;
  52. default-state = "off";
  53. };
  54. led4 {
  55. label = "led4";
  56. gpios = <&gpm4 3 GPIO_ACTIVE_LOW>;
  57. default-state = "off";
  58. linux,default-trigger = "mmc0";
  59. };
  60. };
  61. fixed-rate-clocks {
  62. xxti {
  63. compatible = "samsung,clock-xxti";
  64. clock-frequency = <0>;
  65. };
  66. xusbxti {
  67. compatible = "samsung,clock-xusbxti";
  68. clock-frequency = <24000000>;
  69. };
  70. };
  71. interrupt_demo: interrupt_demo {
  72. compatible         = "tiny4412,interrupt_demo";
  73. tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>;
  74. tiny4412,int_gpio2 = <&gpx3 3 GPIO_ACTIVE_HIGH>;
  75. tiny4412,int_gpio3 = <&gpx3 4 GPIO_ACTIVE_HIGH>;
  76. tiny4412,int_gpio4 = <&gpx3 5 GPIO_ACTIVE_HIGH>;
  77. };
  78. };
  79. &rtc {
  80. status = "okay";
  81. };
  82. &sdhci_2 {
  83. bus-width = <4>;
  84. pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
  85. pinctrl-names = "default";
  86. #status = "okay";
  87. status = "disabled";
  88. };
  89. &serial_0 {
  90. status = "okay";
  91. };
  92. &serial_1 {
  93. status = "okay";
  94. };
  95. &serial_2 {
  96. status = "okay";
  97. };
  98. &serial_3 {
  99. status = "okay";
  100. };

三、设备树驱动

设备树引来的驱动变化
  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/platform_device.h>
  4. #include <linux/gpio.h>
  5. #include <linux/of.h>
  6. #include <linux/of_gpio.h>
  7. #include <linux/interrupt.h>
  8. typedef struct
  9. {
  10. int gpio;
  11. int irq;
  12. char name[20];
  13. }int_demo_data_t;
  14. static irqreturn_t int_demo_isr(int irq, void *dev_id)
  15. {
  16. int_demo_data_t *data = dev_id;
  17. printk("%s enter, %s: gpio:%d, irq: %d\n", __func__, data->name, data->gpio, data->irq);
  18. return IRQ_HANDLED;
  19. }
  20. static int int_demo_probe(struct platform_device *pdev) {
  21. struct device *dev = &pdev->dev;
  22. int irq_gpio = -1;
  23. int irq = -1;
  24. int ret = 0;
  25. int i = 0;
  26. int_demo_data_t *data = NULL;
  27. printk("%s enter.\n", __func__);
  28. if (!dev->of_node) {
  29. dev_err(dev, "no platform data.\n");
  30. goto err1;
  31. }
  32. data = devm_kmalloc(dev, sizeof(*data)*4, GFP_KERNEL);
  33. if (!data) {
  34. dev_err(dev, "no memory.\n");
  35. goto err0;
  36. }
  37. #if 1
  38. for (i = 3; i >= 0; i--) {
  39. sprintf(data[i].name, "tiny4412,int_gpio%d", i+1);
  40. #else
  41. for (i = 0; i < 4; i++) {
  42. #endif
  43. irq_gpio = of_get_named_gpio(dev->of_node, data[i].name, 0);//通过名字获取gpio
  44. if (irq_gpio < 0) {
  45. dev_err(dev, "Looking up %s property in node %s failed %d\n",
  46. data[i].name, dev->of_node->full_name, irq_gpio);
  47. goto err1;
  48. }
  49. data[i].gpio = irq_gpio;
  50. irq = gpio_to_irq(irq_gpio);    //将gpio转换成对应的中断号
  51. if (irq < 0) {
  52. dev_err(dev,
  53. "Unable to get irq number for GPIO %d, error %d\n",
  54. irq_gpio, irq);
  55. goto err1;
  56. }
  57. data[i].irq = irq;
  58. printk("%s: gpio: %d ---> irq (%d)\n", __func__, irq_gpio, irq);
  59. //注册中断
  60. ret = devm_request_any_context_irq(dev, irq, int_demo_isr, IRQF_TRIGGER_FALLING, data[i].name, data+i);
  61. if (ret < 0) {
  62. dev_err(dev, "Unable to claim irq %d; error %d\n",
  63. irq, ret);
  64. goto err1;
  65. }
  66. }
  67. return 0;
  68. err1:
  69. devm_kfree(dev, data);
  70. err0:
  71. return -EINVAL;
  72. }
  73. static int int_demo_remove(struct platform_device *pdev) {
  74. printk("%s enter.\n", __func__);
  75. return 0;
  76. }
  77. static const struct of_device_id int_demo_dt_ids[] = {
  78. { .compatible = "tiny4412,interrupt_demo", },
  79. {},
  80. };
  81. MODULE_DEVICE_TABLE(of, int_demo_dt_ids);
  82. static struct platform_driver int_demo_driver = {
  83. .driver        = {
  84. .name      = "interrupt_demo",
  85. .of_match_table    = of_match_ptr(int_demo_dt_ids),
  86. },
  87. .probe         = int_demo_probe,
  88. .remove        = int_demo_remove,
  89. };
  90. static int __init int_demo_init(void)
  91. {
  92. int ret;
  93. ret = platform_driver_register(&int_demo_driver);
  94. if (ret)
  95. printk(KERN_ERR "int demo: probe failed: %d\n", ret);
  96. return ret;
  97. }
  98. module_init(int_demo_init);
  99. static void __exit int_demo_exit(void)
  100. {
  101. platform_driver_unregister(&int_demo_driver);
  102. }
  103. module_exit(int_demo_exit);
  104. MODULE_LICENSE("GPL");

编译驱动

  1. KERN_DIR = /work/system/linux-3.4.2
  2. all:
  3. make -C $(KERN_DIR) M=`pwd` modules
  4. clean:
  5. make -C $(KERN_DIR) M=`pwd` modules clean
  6. rm -rf modules.order
  7. obj-m   += mykey.o<span style="font-size:18px;">
  8. </span>

采用了platform平台设备驱动的方式

platform_driver_register(&int_demo_driver);-->

.of_match_table    = of_match_ptr(int_demo_dt_ids),-->

.probe         = int_demo_probe,-->

of_get_named_gpio(dev->of_node, data[i].name, 0):将dev->of_node节点上的data[i].name的值取下。-->

irq = gpio_to_irq(irq_gpio);    //将gpio转换成对应的中断号-->

ret = devm_request_any_context_irq(dev, irq, int_demo_isr, IRQF_TRIGGER_FALLING, data[i].name, data+i);

//注册中断-->

中断发生-->

执行中断处理函数int_demo_isr-->

等待中断发生。

四、下载测试

#u-boot:
setenv bootargs  'root=/dev/nfs  rw  nfsroot=192.168.1.123:/work/nfs/rootfs_for_tiny4412/rootfs ethmac=1C:6F:65:34:51:7E  ip=192.168.1.125:192.168.1.123:192.168.1.1:255.255.255.0::eth0:off console=ttySAC0,115200  init=/linuxrc'
#u-boot:save
#u-boot:dnw 0x40600000
dnw arch/arm/boot/uImage
#u-boot:dnw 0x42000000
dnw  arch/arm/boot/dts/exynos4412-tiny4412.dtb
bootm 0x40600000 - 0x42000000

内核:
git clone https://github.com/fengyuwuzu0519/linux4_forTiny4412.git
文件系统:
git clone https://github.com/fengyuwuzu0519/rootfs_forTiny4412
文件系统git下了少东西,则创建如下:
(mkdir dev  proc  sys  tmp  var    mknod  dev/console  c  5  1)
uboot:
git clone https://github.com/fengyuwuzu0519/u-boot_forTiny4412
make distclean
make tiny4412_config
make

tiny4412学习(四)之移植linux-设备树(1)设备树基础知识及GPIO中断【转】的更多相关文章

  1. Linux dts 设备树详解(一) 基础知识

    Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 1 前言 2 概念 2.1 什么是设备树 dts(device tree)? 2. ...

  2. 2.Linux系统之硬盘与分区基础知识

    我们是在虚拟机上安装的Linux系统.在安装的过程中,可能会遇到磁盘分区的问题,我们下面简单介绍一下分区的原理. 1.硬盘的基础知识 下面是一块空白的硬盘: 这是一块格式化后的硬盘: 格式化就是,在空 ...

  3. Angular 4 学习笔记 从入门到实战 打造在线竞拍网站 基础知识 快速入门 个人感悟

    最近搞到手了一部Angular4的视频教程,这几天正好有时间变学了一下,可以用来做一些前后端分离的网站,也可以直接去打包web app. 环境&版本信息声明 运行ng -v @angular/ ...

  4. C语言/C++编程学习:送给考计算机二级的同学:公共基础知识总结!

    数据结构与算法 1.算法 算法:是指解题方案的准确而完整的描述. 算法不等于程序,也不等计算机方法,程序的编制不可能优于算法的设计. 算法的基本特征:是一组严谨地定义运算顺序的规则,每一个规则都是有效 ...

  5. tiny4412学习(三)之移植linux-4.x驱动(1)支持网卡驱动【转】

    本文转载自:http://blog.csdn.net/fengyuwuzu0519/article/details/74160686 一.思路 上一节我们通过DNW将内核.文件系统.设备树文件烧入到内 ...

  6. 为AM335x移植Linux内核主线代码(35)使用platform中的GPIO

    http://www.eefocus.com/marianna/blog/15-02/310352_46e8f.html 使用GPIO,当然可以自己编写驱动,比如之前的第34节,也可以使用Kernel ...

  7. linux运维需要掌握的基础知识

    踏入linux运维工程师这一职业,其实有很多工具技能需要掌握,下面我来给大家一一介绍. 1.shell脚本和另一个脚本语言,shell是运维人员必须具备的,不懂这个连入职都不行,至少也要写出一些系统管 ...

  8. 【Linux笔记】CentOS&RHEL YUM基础知识

    以下内容收集自网络,以作参考. 一.YUM是什么 YUM = Yellow dog Updater, Modified. 主要功能是更方便的添加/删除/更新RPM包. 它能自动解决包的倚赖性问题. 它 ...

  9. Linux文件属性之用户与用户组基础知识回顾

    回顾: 用户.用户组的概念: 每个文件和进程,都需要对应一个用户和用户组. linux系统通过UID和GID来识别用户和组的. 用户名相当于人名 UID和GID  身份证号 管理员:root   do ...

随机推荐

  1. 网络编程基础_3.APC队列

    APC队列 #include <stdio.h> #include <windows.h> // 保存 IO 操作的结果 CHAR Buffer1[] = { }; CHAR ...

  2. 踩过好多次的坑 - ajax访问【mango】项目的service

    这个坑真的是踩过好多次了,好记性不如烂笔头,我总是太高估我的记忆力,这次真的是要写下来了. 项目是用的seam框架 + hibernate搭建的,架构是前辈们搭好的劳动成果,在配置service的访问 ...

  3. Commons_IO_FileUtils的使用

    commos_io.jar包下载地址:http://commons.apache.org/proper/commons-io/download_io.cgi 官方文档地址:http://commons ...

  4. JavaScipt30(第七个案例)(主要知识点:数组some,every,findIndex方法)

    承接上文,这是第7个案例,这个案例没什么说的,主要有三个注意点: 附上项目链接: https://github.com/wesbos/JavaScript30 // 1. slice(begin, e ...

  5. JavaScript 实现页面中录音功能

    页面中实现录音需要使用浏览器提供的 Media​Recorder API,所以前提是需要浏览器支持 MediaStream Recording 相关的功能. 以下代码默认工作在 Chrome 环境中. ...

  6. nginx平滑升级实战

    Nginx 平滑升级 1.查看旧版Nginx的编译参数 [root@master ~]# /usr/local/nginx/sbin/nginx -V [root@master ~]# ll ngin ...

  7. MySQL:INSERT ... UPDATE

    在 INSERT 语句末尾指定ON DUPLICATE KEY UPDATE时,如果插入的数据会导致表中的 UNIQUE 索引或 PRIMARY KEY 出现重复值,则会对导致重复的数据执行 UPDA ...

  8. vue启动

    首先在终端terminal连上npm 镜像库 npm config set registry https://registry.npm.taobao.orgnpm installnpm run loc ...

  9. set解两数之和--P2141 珠心算测验

    题目描述 珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术.珠心算训练,既能够开发智力,又能够为日常生活带来很多便利,因而在很多学校得到普及. 某学校的珠心算老师采用一种快速考察珠心算加 ...

  10. 【nginx】记录nginx+php-fpm实现大文件下载排坑的过程

    先上一段代码,支持大文件下载和断点续传,代码来源互联网. set_time_limit(0); // 省略取文件路径的过程,这里直接是文件完整路径 $filePath = get_save_path( ...