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