有了Device Tree后,大量的板级信息都不再需要,譬如过去经常在arch/arm/plat-xxx和arch/arm/mach-xxx实施的如下事情:

  1. 注册platform_device,绑定resource,即内存、IRQ等板级信息。
    透过Device Tree后,形如
 static struct resource xxx_resources[] = {  [0] = {  .start  = …,  .end    = …,  .flags  = IORESOURCE_MEM,  },  [1] = {  .start  = …,  .end    = …,  .flags  = IORESOURCE_IRQ,  },  };  static struct platform_device xxx_device = {  .name           = "xxx",  .id             = -1,  .dev            = {  .platform_data          = &xxx_data,  },  .resource       = xxx_resources,  .num_resources  = ARRAY_SIZE(xxx_resources),   };  

之类的platform_device代码都不再需要,其中platform_device会由kernel自动展开。而这些resource实际来源于.dts中设备结点的reg、interrupts属性。典型地,大多数总线都与“simple_bus”兼容,而在SoC对应的machine的.init_machine成员函数中,调用of_platform_bus_probe(NULL, xxx_of_bus_ids, NULL);即可自动展开所有的platform_device。譬如,假设我们有个XXX SoC,则可在arch/arm/mach-xxx/的板文件中透过如下方式展开.dts中的设备结点对应的platform_device:

 static struct of_device_id xxx_of_bus_ids[] __initdata = {  { .compatible = "simple-bus", },  {},  };  void __init xxx_mach_init(void)  {  of_platform_bus_probe(NULL, xxx_of_bus_ids, NULL);  }  #ifdef CONFIG_ARCH_XXX  DT_MACHINE_START(XXX_DT, "Generic XXX (Flattened Device Tree)")  …  .init_machine   = xxx_mach_init,  …  MACHINE_END  #endif  
  1. 注册i2c_board_info,指定IRQ等板级信息。
    形如
     static struct i2c_board_info __initdata afeb9260_i2c_devices[] = {  {  I2C_BOARD_INFO("tlv320aic23", 0x1a),  }, {  I2C_BOARD_INFO("fm3130", 0x68),  }, {  I2C_BOARD_INFO("24c64", 0x50),  },  };

之类的i2c_board_info代码,目前不再需要出现,现在只需要把tlv320aic23、fm3130、24c64这些设备结点填充作为相应的I2C controller结点的子结点即可,类似于前面的

     i2c@1,0 {  compatible = "acme,a1234-i2c-bus";  …  rtc@58 {  compatible = "maxim,ds1338";  reg = <58>;  interrupts = < 7 3 >;  };  };

Device Tree中的I2C client会透过I2C host驱动的probe()函数中调用of_i2c_register_devices(&i2c_dev->adapter);被自动展开。

  1. 注册spi_board_info,指定IRQ等板级信息。
    形如
     static struct spi_board_info afeb9260_spi_devices[] = {  {       /* DataFlash chip */  .modalias       = "mtd_dataflash",  .chip_select    = 1,  .max_speed_hz   = 15 * 1000 * 1000,  .bus_num        = 0,  },  };

之类的spi_board_info代码,目前不再需要出现,与I2C类似,现在只需要把mtd_dataflash之类的结点,作为SPI控制器的子结点即可,SPI host驱动的probe函数透过spi_register_master()注册master的时候,会自动展开依附于它的slave。

  1. 多个针对不同电路板的machine,以及相关的callback。

过去,ARM Linux针对不同的电路板会建立由MACHINE_START和MACHINE_END包围起来的针对这个machine的一系列callback,譬如:

     MACHINE_START(VEXPRESS, "ARM-Versatile Express")  .atag_offset    = 0x100,  .smp            = smp_ops(vexpress_smp_ops),  .map_io         = v2m_map_io,  .init_early     = v2m_init_early,  .init_irq       = v2m_init_irq,  .timer          = &v2m_timer,  .handle_irq     = gic_handle_irq,  .init_machine   = v2m_init,  .restart        = vexpress_restart,  MACHINE_END

这些不同的machine会有不同的MACHINE ID,Uboot在启动Linux内核时会将MACHINE ID存放在r1寄存器,Linux启动时会匹配Bootloader传递的MACHINE ID和MACHINE_START声明的MACHINE ID,然后执行相应machine的一系列初始化函数。

引入Device Tree之后,MACHINE_START变更为DT_MACHINE_START,其中含有一个.dt_compat成员,用于表明相关的machine与.dts中root结点的compatible属性兼容关系。如果Bootloader传递给内核的Device Tree中root结点的compatible属性出现在某machine的.dt_compat表中,相关的machine就与对应的Device Tree匹配,从而引发这一machine的一系列初始化函数被执行。

  static const char * const v2m_dt_match[] __initconst = {  "arm,vexpress",  "xen,xenvm",  NULL,  };  DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")  .dt_compat      = v2m_dt_match,  .smp            = smp_ops(vexpress_smp_ops),  .map_io         = v2m_dt_map_io,  .init_early     = v2m_dt_init_early,  .init_irq       = v2m_dt_init_irq,  .timer          = &v2m_dt_timer,  .init_machine   = v2m_dt_init,  .handle_irq     = gic_handle_irq,  .restart        = vexpress_restart,  MACHINE_END

Linux倡导针对多个SoC、多个电路板的通用DT machine,即一个DT machine的.dt_compat表含多个电路板.dts文件的root结点compatible属性字符串。之后,如果的电路板的初始化序列不一样,可以透过int of_machine_is_compatible(const char *compat) API判断具体的电路板是什么。

譬如arch/arm/mach-exynos/mach-exynos5-dt.c的EXYNOS5_DT machine同时兼容"samsung,exynos5250"和"samsung,exynos5440":

     static char const *exynos5_dt_compat[] __initdata = {  "samsung,exynos5250",  "samsung,exynos5440",  NULL  };  DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)")  /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */  .init_irq       = exynos5_init_irq,  .smp            = smp_ops(exynos_smp_ops),  .map_io         = exynos5_dt_map_io,  .handle_irq     = gic_handle_irq,  .init_machine   = exynos5_dt_machine_init,  .init_late      = exynos_init_late,  .timer          = &exynos4_timer,  .dt_compat      = exynos5_dt_compat,  .restart        = exynos5_restart,  .reserve        = exynos5_reserve,  MACHINE_END

它的.init_machine成员函数就针对不同的machine进行了不同的分支处理:

      static void __init exynos5_dt_machine_init(void)  {  …  if (of_machine_is_compatible("samsung,exynos5250"))  of_platform_populate(NULL, of_default_bus_match_table,  exynos5250_auxdata_lookup, NULL);  else if (of_machine_is_compatible("samsung,exynos5440"))  of_platform_populate(NULL, of_default_bus_match_table,  exynos5440_auxdata_lookup, NULL);  }

使用Device Tree后,驱动需要与.dts中描述的设备结点进行匹配,从而引发驱动的probe()函数执行。对于platform_driver而言,需要添加一个OF匹配表,如前文的.dts文件的"acme,a1234-i2c-bus"兼容I2C控制器结点的OF匹配表可以是:

  static const struct of_device_id a1234_i2c_of_match[] = {  { .compatible = "acme,a1234-i2c-bus ", },  {},  };  MODULE_DEVICE_TABLE(of, a1234_i2c_of_match);  static struct platform_driver i2c_a1234_driver = {  .driver = {  .name = "a1234-i2c-bus ",  .owner = THIS_MODULE,  .of_match_table = a1234_i2c_of_match,  },  .probe = i2c_a1234_probe,  .remove = i2c_a1234_remove,  };  module_platform_driver(i2c_a1234_driver);

对于I2C和SPI从设备而言,同样也可以透过of_match_table添加匹配的.dts中的相关结点的compatible属性,如sound/soc/codecs/wm8753.c中的:

         .............1533 static const struct of_device_id wm8753_of_match[] = {  1534         { .compatible = "wlf,wm8753", },  1535         { }  1536 };  1537 MODULE_DEVICE_TABLE(of, wm8753_of_match);  1587 static struct spi_driver wm8753_spi_driver = {  1588         .driver = {  1589                 .name   = "wm8753",  1590                 .owner  = THIS_MODULE,  1591                 .of_match_table = wm8753_of_match,  1592         },  1593         .probe          = wm8753_spi_probe,  1594         .remove         = wm8753_spi_remove,  1595 };  1640 static struct i2c_driver wm8753_i2c_driver = {  1641         .driver = {  1642                 .name = "wm8753",  1643                 .owner = THIS_MODULE,  1644                 .of_match_table = wm8753_of_match,  1645         },  1646         .probe =    wm8753_i2c_probe,  1647         .remove =   wm8753_i2c_remove,  1648         .id_table = wm8753_i2c_id,  1649 };

不过这边有一点需要提醒的是,I2C和SPI外设驱动和Device Tree中设备结点的compatible 属性还有一种弱式匹配方法,就是别名匹配。compatible 属性的组织形式为,,别名其实就是去掉compatible 属性中逗号前的manufacturer前缀。关于这一点,可查看drivers/spi/spi.c的源代码,函数spi_match_device()暴露了更多的细节,如果别名出现在设备spi_driver的id_table里面,或者别名与spi_driver的name字段相同,SPI设备和驱动都可以匹配上:

     static int spi_match_device(struct device *dev, struct device_driver *drv)  {  const struct spi_device *spi = to_spi_device(dev);  const struct spi_driver *sdrv = to_spi_driver(drv);  /* Attempt an OF style match */  if (of_driver_match_device(dev, drv))  return 1;  /* Then try ACPI */  if (acpi_driver_match_device(dev, drv))  return 1;  if (sdrv->id_table)  return !!spi_match_id(sdrv->id_table, spi);  return strcmp(spi->modalias, drv->name) == 0;  }  static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,  const struct spi_device *sdev)  {  while (id->name[0]) {  if (!strcmp(sdev->modalias, id->name))  return id;  id++;  }  return NULL;  }

Device Tree引发的BSP和驱动变更相关推荐

  1. ARM Linux 3.x的设备树(Device Tree)【转】

    转自:http://blog.csdn.net/21cnbao/article/details/8457546 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] ARM Devi ...

  2. ARM Linux 3.x的设备树(Device Tree)

    宋宝华 Barry Song <21cnbao@gmail.com> 1.    ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux ...

  3. linux内核 设备列表,Linux 设备树(Device Tree)(转载)

    ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称 "this whole ARM thing is a f*cking ...

  4. dtb文件linux位置,dtb文件的由来与ARM Linux 3.x的设备树(Device Tree)

    1. ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称"this whole ARM thing is a f*ckin ...

  5. linux驱动开发音频设备驱动,linux驱动开发—基于Device tree机制的驱动编写

    摘要:媒介 Device Tree是一种用去描绘硬件的数据布局,类似板级描绘说话,发源于OpenFirmware(OF).正在现在遍及应用的kernel 2.6.x版本中,对分歧仄台.分歧硬件,往] ...

  6. Android 驱动(12)---Linux DTS(Device Tree Source)设备树详解

    Linux DTS(Device Tree Source)设备树详解 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) Linux DTS(Device Tr ...

  7. Android 驱动开发(14)---深入学习Linux Device Tree

    深入学习Linux Device Tree 这个世界需要的是全力以赴,战胜他人先战胜子自己!! Linux Device Tree可描述的信息包括: cpu的数量和类型 内存基地址和大小 总线 外设 ...

  8. Linux设备模型、平台设备驱动、设备树(device tree)、GPIO子系统以及pinctrl子系统介绍

    文章目录 一.Linux设备模型介绍 (1)设备驱动模型总体介绍 (2)设备驱动模型文件表现 (3)设备驱动模型工作原理 [1]总线 [2]设备 [3]驱动 [4]注册流程 二.平台设备驱动介绍 (1 ...

  9. (DT系列四)驱动加载中, 如何取得device tree中的属性

    转载于: http://blog.csdn.net/lichengtongxiazai/article/details/38941933 本文以At91rm9200平台为例,从源码实现的角度来分析驱动 ...

最新文章

  1. ****题(alb)
  2. c++函数重载机制实现原理
  3. chrome开发总结(交互/权限/存储)-爬虫
  4. RoboGuice入门
  5. Lead saved query bug
  6. 我国三大坐标系的区别(西安80、北京54、WGS-84)
  7. PLSQL 设置布局
  8. 社交网络分析之关系图(原理+Python代码)
  9. 实战第二步:如何做一份有针对性的竞品分析
  10. PDMS二次开发(十二)——螺栓材料统计功能一批bug修复之后再次用sample项目进行验证
  11. python语句中生成小数的语句_下列 Python 语句的输出结果是 。 print( 数量 {0}, 单价 {1} .format(100,285.6)) print(str.format(...
  12. python配对t检验_T检验第二篇(SPSS,SAS,R,Python) 配对T检验
  13. LM317的直流可调稳压电源Multisim仿真设计(附仿真+论文+参考资料)
  14. ue5-预计算可视性体积(PVS)
  15. html css标记文本,HTML图像标记和CSS核心基础和文本相关样式
  16. 如何在内网环境下解决rpm包的问题
  17. 防火墙NAT综合实验——nat控制,豁免,远程,DMZ区域(带命令)
  18. git clone时遇到问题:remote: Incorrect username or password ( access token )
  19. 网络入侵检测系统之Suricata(七)--DDOS流量检测模型
  20. java读取word文档的复杂表格_poi读取word表格 java POI 如何读取word的表格中的表格...

热门文章

  1. office、vs各版本软件下载
  2. 如何使用Hibernate Envers审核数据,包括用户名信息
  3. 1.2.2 通用的标量输运方程|1.2.3 控制方程的分类(OpenFOAM理论笔记系列)
  4. leetcode记录-524-通过删除字母匹配到字典里最长单词-双指针
  5. audio标签,播放音乐
  6. 2020第十一届蓝桥杯 平面切分 最详细题解
  7. UESTC 1599 wtmsb【优先队列+排序】
  8. python表情包多样化图形化聊天室_如何用python绘制一系列三维的逗比风格表情包...
  9. Tensorflow 2.x源码详解之开宗明义:基本介绍和张量(万文多图)
  10. 《开源圆桌派》第十一期“冰与火之歌”——如何平衡开源与安全间的天然矛盾?...