1*f773455cSYanteng Si.. SPDX-License-Identifier: GPL-2.0 2*f773455cSYanteng Si.. include:: ../disclaimer-zh_CN.rst 3*f773455cSYanteng Si 4*f773455cSYanteng Si:Original: Documentation/Devicetree/overlay-notes.rst 5*f773455cSYanteng Si 6*f773455cSYanteng Si:翻译: 7*f773455cSYanteng Si 8*f773455cSYanteng Si 司延腾 Yanteng Si <siyanteng@loongson.cn> 9*f773455cSYanteng Si 10*f773455cSYanteng Si:校译: 11*f773455cSYanteng Si 12*f773455cSYanteng Si============== 13*f773455cSYanteng Si设备树覆盖说明 14*f773455cSYanteng Si============== 15*f773455cSYanteng Si 16*f773455cSYanteng Si本文档描述了drivers/of/overlay.c中的内核内设备树覆盖功能的实现,是 17*f773455cSYanteng SiDocumentation/devicetree/dynamic-resolution-notes.rst[1]的配套文档。 18*f773455cSYanteng Si 19*f773455cSYanteng Si覆盖如何工作 20*f773455cSYanteng Si------------ 21*f773455cSYanteng Si 22*f773455cSYanteng Si设备树覆盖的目的是修改内核的实时树,并使修改以反映变化的方式影响内核的状态。 23*f773455cSYanteng Si由于内核主要处理的是设备,任何新的设备节点如果导致一个活动的设备,就应该创建它, 24*f773455cSYanteng Si而如果设备节点被禁用或被全部删除,受影响的设备应该被取消注册。 25*f773455cSYanteng Si 26*f773455cSYanteng Si让我们举个例子,我们有一个foo板,它的基本树形图如下:: 27*f773455cSYanteng Si 28*f773455cSYanteng Si ---- foo.dts --------------------------------------------------------------- 29*f773455cSYanteng Si /* FOO平台 */ 30*f773455cSYanteng Si /dts-v1/; 31*f773455cSYanteng Si / { 32*f773455cSYanteng Si compatible = "corp,foo"; 33*f773455cSYanteng Si 34*f773455cSYanteng Si /* 共享的资源 */ 35*f773455cSYanteng Si res: res { 36*f773455cSYanteng Si }; 37*f773455cSYanteng Si 38*f773455cSYanteng Si /* 芯片上的外围设备 */ 39*f773455cSYanteng Si ocp: ocp { 40*f773455cSYanteng Si /* 总是被实例化的外围设备 */ 41*f773455cSYanteng Si peripheral1 { ... }; 42*f773455cSYanteng Si }; 43*f773455cSYanteng Si }; 44*f773455cSYanteng Si ---- foo.dts --------------------------------------------------------------- 45*f773455cSYanteng Si 46*f773455cSYanteng Si覆盖bar.dts, 47*f773455cSYanteng Si:: 48*f773455cSYanteng Si 49*f773455cSYanteng Si ---- bar.dts - 按标签覆盖目标位置 ---------------------------- 50*f773455cSYanteng Si /dts-v1/; 51*f773455cSYanteng Si /插件/; 52*f773455cSYanteng Si &ocp { 53*f773455cSYanteng Si /* bar外围 */ 54*f773455cSYanteng Si bar { 55*f773455cSYanteng Si compatible = "corp,bar"; 56*f773455cSYanteng Si ... /* 各种属性和子节点 */ 57*f773455cSYanteng Si }; 58*f773455cSYanteng Si }; 59*f773455cSYanteng Si ---- bar.dts --------------------------------------------------------------- 60*f773455cSYanteng Si 61*f773455cSYanteng Si当加载(并按照[1]中描述的方式解决)时,应该产生foo+bar.dts:: 62*f773455cSYanteng Si 63*f773455cSYanteng Si ---- foo+bar.dts ----------------------------------------------------------- 64*f773455cSYanteng Si /* FOO平台 + bar外围 */ 65*f773455cSYanteng Si / { 66*f773455cSYanteng Si compatible = "corp,foo"; 67*f773455cSYanteng Si 68*f773455cSYanteng Si /* 共享资源 */ 69*f773455cSYanteng Si res: res { 70*f773455cSYanteng Si }; 71*f773455cSYanteng Si 72*f773455cSYanteng Si /* 芯片上的外围设备 */ 73*f773455cSYanteng Si ocp: ocp { 74*f773455cSYanteng Si /* 总是被实例化的外围设备 */ 75*f773455cSYanteng Si peripheral1 { ... }; 76*f773455cSYanteng Si 77*f773455cSYanteng Si /* bar外围 */ 78*f773455cSYanteng Si bar { 79*f773455cSYanteng Si compatible = "corp,bar"; 80*f773455cSYanteng Si ... /* 各种属性和子节点 */ 81*f773455cSYanteng Si }; 82*f773455cSYanteng Si }; 83*f773455cSYanteng Si }; 84*f773455cSYanteng Si ---- foo+bar.dts ----------------------------------------------------------- 85*f773455cSYanteng Si 86*f773455cSYanteng Si作为覆盖的结果,已经创建了一个新的设备节点(bar),因此将注册一个bar平台设备, 87*f773455cSYanteng Si如果加载了匹配的设备驱动程序,将按预期创建设备。 88*f773455cSYanteng Si 89*f773455cSYanteng Si如果基础DT不是用-@选项编译的,那么“&ocp”标签将不能用于将覆盖节点解析到基础 90*f773455cSYanteng SiDT中的适当位置。在这种情况下,可以提供目标路径。通过标签的目标位置的语法是比 91*f773455cSYanteng Si较好的,因为不管标签在DT中出现在哪里,覆盖都可以被应用到任何包含标签的基础DT上。 92*f773455cSYanteng Si 93*f773455cSYanteng Si上面的bar.dts例子被修改为使用目标路径语法,即为:: 94*f773455cSYanteng Si 95*f773455cSYanteng Si ---- bar.dts - 通过明确的路径覆盖目标位置 -------------------- 96*f773455cSYanteng Si /dts-v1/; 97*f773455cSYanteng Si /插件/; 98*f773455cSYanteng Si &{/ocp} { 99*f773455cSYanteng Si /* bar外围 */ 100*f773455cSYanteng Si bar { 101*f773455cSYanteng Si compatible = "corp,bar"; 102*f773455cSYanteng Si ... /* 各种外围设备和子节点 */ 103*f773455cSYanteng Si } 104*f773455cSYanteng Si }; 105*f773455cSYanteng Si ---- bar.dts --------------------------------------------------------------- 106*f773455cSYanteng Si 107*f773455cSYanteng Si 108*f773455cSYanteng Si内核中关于覆盖的API 109*f773455cSYanteng Si------------------- 110*f773455cSYanteng Si 111*f773455cSYanteng Si该API相当容易使用。 112*f773455cSYanteng Si 113*f773455cSYanteng Si1) 调用of_overlay_fdt_apply()来创建和应用一个覆盖的变更集。返回值是一个 114*f773455cSYanteng Si 错误或一个识别这个覆盖的cookie。 115*f773455cSYanteng Si 116*f773455cSYanteng Si2) 调用of_overlay_remove()来删除和清理先前通过调用of_overlay_fdt_apply() 117*f773455cSYanteng Si 而创建的覆盖变更集。不允许删除一个被另一个覆盖的覆盖变化集。 118*f773455cSYanteng Si 119*f773455cSYanteng Si最后,如果你需要一次性删除所有的覆盖,只需调用of_overlay_remove_all(), 120*f773455cSYanteng Si它将以正确的顺序删除每一个覆盖。 121*f773455cSYanteng Si 122*f773455cSYanteng Si你可以选择注册在覆盖操作中被调用的通知器。详见 123*f773455cSYanteng Siof_overlay_notifier_register/unregister和enum of_overlay_notify_action。 124*f773455cSYanteng Si 125*f773455cSYanteng SiOF_OVERLAY_PRE_APPLY、OF_OVERLAY_POST_APPLY或OF_OVERLAY_PRE_REMOVE 126*f773455cSYanteng Si的通知器回调可以存储指向覆盖层中的设备树节点或其内容的指针,但这些指针不能持 127*f773455cSYanteng Si续到OF_OVERLAY_POST_REMOVE的通知器回调。在OF_OVERLAY_POST_REMOVE通 128*f773455cSYanteng Si知器被调用后,包含覆盖层的内存将被kfree()ed。请注意,即使OF_OVERLAY_POST_REMOVE 129*f773455cSYanteng Si的通知器返回错误,内存也会被kfree()ed。 130*f773455cSYanteng Si 131*f773455cSYanteng Sidrivers/of/dynamic.c中的变更集通知器是第二种类型的通知器,可以通过应用或移除 132*f773455cSYanteng Si覆盖层来触发。这些通知器不允许在覆盖层或其内容中存储指向设备树节点的指针。当包含 133*f773455cSYanteng Si覆盖层的内存因移除覆盖层而被释放时,覆盖层代码并不能防止这类指针仍然有效。 134*f773455cSYanteng Si 135*f773455cSYanteng Si任何其他保留指向覆盖层节点或数据的指针的代码都被认为是一个错误,因为在移除覆盖层 136*f773455cSYanteng Si后,该指针将指向已释放的内存。 137*f773455cSYanteng Si 138*f773455cSYanteng Si覆盖层的用户必须特别注意系统上发生的整体操作,以确保其他内核代码不保留任何指向覆 139*f773455cSYanteng Si盖层节点或数据的指针。任何无意中使用这种指针的例子是,如果一个驱动或子系统模块在 140*f773455cSYanteng Si应用了覆盖后被加载,并且该驱动或子系统扫描了整个设备树或其大部分,包括覆盖节点。 141