فهرست منبع

优化驱动注册流程并添加fdt至components

宋超 3 سال پیش
والد
کامیت
cd799688c1
32فایلهای تغییر یافته به همراه7891 افزوده شده و 10 حذف شده
  1. 13 0
      components/drivers/Kconfig
  2. 41 0
      components/drivers/fdt/README.md
  3. 16 0
      components/drivers/fdt/SConscript
  4. 13 0
      components/drivers/fdt/docs/README.md
  5. 434 0
      components/drivers/fdt/docs/api.md
  6. 81 0
      components/drivers/fdt/docs/examples.md
  7. 7 0
      components/drivers/fdt/docs/version.md
  8. 10 0
      components/drivers/fdt/examples/SConscript
  9. 143 0
      components/drivers/fdt/examples/fdt_test.c
  10. 379 0
      components/drivers/fdt/inc/dtb_node.h
  11. 10 0
      components/drivers/fdt/libfdt/SConscript
  12. 249 0
      components/drivers/fdt/libfdt/fdt.c
  13. 111 0
      components/drivers/fdt/libfdt/fdt.h
  14. 99 0
      components/drivers/fdt/libfdt/fdt_addresses.c
  15. 84 0
      components/drivers/fdt/libfdt/fdt_empty_tree.c
  16. 701 0
      components/drivers/fdt/libfdt/fdt_ro.c
  17. 489 0
      components/drivers/fdt/libfdt/fdt_rw.c
  18. 100 0
      components/drivers/fdt/libfdt/fdt_strerror.c
  19. 286 0
      components/drivers/fdt/libfdt/fdt_sw.c
  20. 137 0
      components/drivers/fdt/libfdt/fdt_wip.c
  21. 1876 0
      components/drivers/fdt/libfdt/libfdt.h
  22. 113 0
      components/drivers/fdt/libfdt/libfdt_env.h
  23. 95 0
      components/drivers/fdt/libfdt/libfdt_internal.h
  24. 17 0
      components/drivers/fdt/src/SConscript
  25. 650 0
      components/drivers/fdt/src/dtb_access.c
  26. 57 0
      components/drivers/fdt/src/dtb_addr.c
  27. 537 0
      components/drivers/fdt/src/dtb_base.c
  28. 817 0
      components/drivers/fdt/src/dtb_get.c
  29. 41 0
      components/drivers/fdt/src/dtb_head.c
  30. 105 0
      components/drivers/fdt/src/dtb_load.c
  31. 166 0
      components/drivers/fdt/src/dtb_set.c
  32. 14 10
      src/driver.c

+ 13 - 0
components/drivers/Kconfig

@@ -167,6 +167,19 @@ config RT_USING_PM
     bool "Using Power Management device drivers"
     default n
 
+config RT_USING_FDT
+    bool "Using fdt interface for device drivers"
+    default n
+    if RT_USING_FDT
+        config RT_USING_FDTLIB
+            bool "Using fdt lib for device drivers"
+            default y
+        config FDT_USING_DEBUG
+            bool "Using fdt debug function "
+            default n
+            
+    endif
+    
 config RT_USING_RTC
     bool "Using RTC device drivers"
     default n

+ 41 - 0
components/drivers/fdt/README.md

@@ -0,0 +1,41 @@
+# fdt
+
+## 1、介绍
+fdt基于libfdt进行封装,可实现在内存或文件系统中加载dtb设备树,对内存中的设备树修改、解析,并转换为设备节点树,通过该节点树开发者可通过设备树信息开发驱动。
+
+### 1.1 目录结构
+| 名称 | 说明 |
+| ---- | ---- |
+| docs  | 文档目录 |
+| examples | 例子目录,并有相应的一些说明 |
+| inc  | 头文件目录 |
+| src  | 源代码目录 |
+
+### 1.2 许可证
+fdt package 遵循 GPL-3.0 许可,详见 LICENSE 文件。
+
+### 1.3 依赖
+- RT-Thread 3.0+
+
+## 2、如何打开 fdt
+使用 fdt package 需要在 RT-Thread 的包管理器中选择它,具体路径如下:
+
+```
+RT-Thread online packages
+    tools packages --->
+        [*] Device Tree package in RT-Thread
+```
+
+## 3、使用 fdt
+在打开 fdt package 后,当进行 bsp 编译时,它会被加入到 bsp 工程中进行编译。
+
+* 完整的 API 手册可以访问这个[链接](docs/api.md)
+* 更多文档位于 [`/docs`](/docs) 下,使用前 **务必查看**
+
+## 4、注意事项
+如果发生`libfdt`库冲突,在package管理菜单中取消选择`Enable libfdt`
+
+## 5、联系方式
+
+* 维护:GuEe-GUI
+* 主页:https://github.com/GuEe-GUI/fdt

+ 16 - 0
components/drivers/fdt/SConscript

@@ -0,0 +1,16 @@
+# RT-Thread building script for bridge
+
+import os
+from building import *
+
+cwd = GetCurrentDir()
+objs = []
+list = os.listdir(cwd)
+
+if GetDepend('RT_USING_FDT'):
+    for d in list:
+        path = os.path.join(cwd, d)
+        if os.path.isfile(os.path.join(path, 'SConscript')):
+            objs = objs + SConscript(os.path.join(d, 'SConscript'))
+
+Return('objs')

+ 13 - 0
components/drivers/fdt/docs/README.md

@@ -0,0 +1,13 @@
+# 文档
+
+## 软件包地址
+
+- https://gitee.com/GuEe_GUI/fdt
+
+## 文档列表
+
+|文件名                             |描述|
+|:-----                             |:----|
+|[examples.md](examples.md)         |示例程序|
+|[version.md](version.md)           |版本信息|
+|[api.md](api.md)                   |API 说明|

+ 434 - 0
components/drivers/fdt/docs/api.md

@@ -0,0 +1,434 @@
+# fdt load API
+
+## 从文件系统上读取设备树
+```c
+void *fdt_load_from_fs(char *dtb_filename)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_filename | 设备树文件名 |
+| **返回** | **描述** |
+|void* | 设备树在内存上的地址 |
+
+## 从内存上读取设备树
+```c
+void *fdt_load_from_memory(void *dtb_ptr, rt_bool_t is_clone)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_ptr | 设备树在内存上的内存地址 |
+|is_clone | 是否克隆到新的内存区域 |
+| **返回** | **描述** |
+|void* | 设备树在内存上的地址 |
+
+# fdt set API
+
+## 设置Linux启动参数
+```c
+rt_size_t fdt_set_linux_cmdline(void *fdt, char *cmdline)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树指针 |
+|cmdline | 启动参数 |
+| **返回** | **描述** |
+|rt_size_t | 修改设备树后设备树的大小 |
+
+## 设置Linux init ramdisk
+```c
+rt_size_t fdt_set_linux_initrd(void *fdt, rt_uint64_t initrd_addr, rt_size_t initrd_size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树指针 |
+|initrd_addr | init ramdisk 内存地址 |
+|initrd_size | init 大小 |
+| **返回** | **描述** |
+|rt_size_t | 修改设备树后设备树的大小 |
+
+## 设置节点属性值
+```c
+rt_size_t fdt_set_dtb_property(void *fdt, char *pathname, char *property_name, rt_uint32_t *cells, rt_size_t cells_size);
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树指针 |
+|pathname | 节点路径 |
+|property_name | 属性名称 |
+|cells | 属性值地址 |
+|cells_size | 属性值长度 |
+| **返回** | **描述** |
+|rt_size_t | 修改设备树后设备树的大小 |
+
+## 添加保留内存
+```c
+rt_size_t fdt_add_dtb_memreserve(void *fdt, rt_uint64_t address, rt_uint64_t size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树指针 |
+|address | 保留内存起始地址 |
+|size | 保留内存大小 |
+| **返回** | **描述** |
+|rt_size_t | 修改设备树后设备树的大小 |
+
+## 删除保留内存
+```c
+rt_size_t fdt_del_dtb_memreserve(void *fdt, rt_uint64_t address)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树指针 |
+|address | 保留内存起始地址 |
+| **返回** | **描述** |
+|rt_size_t | 修改设备树后设备树的大小 |
+
+# fdt get API
+
+## 获取设备树软件包执行状态
+```c
+rt_err_t fdt_get_exec_status()
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|无 | 无参数 |
+| **返回** | **描述** |
+|FDT_RET_NO_MEMORY | 内存不足 |
+|FDT_RET_NO_LOADED | 设备树还未加载进内存 |
+|FDT_RET_GET_OK | 执行成功 |
+|FDT_RET_GET_EMPTY | 读取数据为空 |
+
+## 将原始设备树转换为设备节点树
+```c
+struct dtb_node *fdt_get_dtb_list(void *fdt)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树在内存上的地址 |
+| **返回** | **描述** |
+|struct dtb_node * | 设备节点树头指针 |
+## 释放设备节点树内存
+```c
+void fdt_free_dtb_list(struct dtb_node *dtb_node_head)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node_head | 设备节点树头节点 |
+| **返回** | **描述** |
+|无返回值 | 无描述 |
+
+示例:加载设备树
+
+```c
+#include <rtthread.h>
+#include <fdt.h>
+
+int main()
+{
+    void *fdt = fdt_load_from_fs("sample.dtb");
+    if (fdt != RT_NULL)
+    {
+        struct dtb_node *dtb_node_list = fdt_get_dtb_list(fdt);
+
+        if (dtb_node_list != RT_NULL)
+        {
+            /* load dtb node list OK */
+
+            /* free dtb_node_list here */
+            fdt_free_dtb_list(dtb_node_list);
+        }
+
+        rt_free(fdt);
+    }
+
+    return 0;
+}
+```
+
+## 打印设备树信息
+```c
+void fdt_get_dts_dump(struct dtb_node *dtb_node_head)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node_head | 设备节点树头节点 |
+| **返回** | **描述** |
+|无返回值 | 无描述 |
+
+## 遍历设备节点树并使用程序定义的回调函数
+```c
+void fdt_get_enum_dtb_node(struct dtb_node *dtb_node_head, void (*callback(struct dtb_node *dtb_node)))
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node_head | 设备节点树头节点 |
+|callback | 程序定义的回调函数 |
+| **返回** | **描述** |
+|无返回值 | 无描述 |
+
+示例:遍历设备树节点,并打印每个节点名称
+
+```c
+#include <rtthread.h>
+#include <fdt.h>
+
+void callback(struct dtb_node *node)
+{
+    rt_kprintf("this node's name is %s\n", node->name);
+}
+
+int main()
+{
+    /* loaded dtb_node */
+    extern struct dtb_node *dtb_node_list;
+
+    if (dtb_node_list != RT_NULL)
+    {
+        fdt_get_enum_dtb_node(dtb_node_list, callback);
+    }
+
+    return 0;
+}
+```
+
+## 通过节点名称查找节点
+```c
+struct dtb_node *fdt_get_dtb_node_by_name_DFS(struct dtb_node *dtb_node, const char *nodename)
+```
+```c
+struct dtb_node *fdt_get_dtb_node_by_name_BFS(struct dtb_node *dtb_node, const char *nodename)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|nodename | 查找节点的名称 |
+| **返回** | **描述** |
+|struct dtb_node * | 返回查找的节点 |
+|RT_NULL | 未找到为RT_NULL |
+
+## 通过节点路径查找节点
+```c
+struct dtb_node *fdt_get_dtb_node_by_path(struct dtb_node *dtb_node, const char *pathname)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|pathname | 查找节点的路径 |
+| **返回** | **描述** |
+|struct dtb_node * | 返回查找的节点 |
+|RT_NULL | 未找到为RT_NULL |
+
+## 通过节点phandle值查找节点
+```c
+struct dtb_node *fdt_get_dtb_node_by_phandle_DFS(struct dtb_node *dtb_node, phandle handle)
+```
+```c
+struct dtb_node *fdt_get_dtb_node_by_phandle_BFS(struct dtb_node *dtb_node, phandle handle)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|handle | 查找节点的phandle值 |
+| **返回** | **描述** |
+|struct dtb_node * | 返回查找的节点 |
+|RT_NULL | 未找到为RT_NULL |
+
+DFS和BFS是用于区分不同深度节点的搜索方法,时间复杂度和空间复杂度都较高,建议使用路径查找。
+
+## 读取节点属性值的单位
+```c
+void fdt_get_dtb_node_cells(struct dtb_node *dtb_node, int *addr_cells, int *size_cells)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|addr_cells | 返回的地址块的单位(u32)大小 |
+|size_cells | 返回的尺寸块的单位(u32)大小 |
+| **返回** | **描述** |
+|无返回值 | 无描述 |
+
+
+## 读取节点属性值
+```c
+void *fdt_get_dtb_node_property(struct dtb_node *dtb_node, const char *property_name, rt_size_t *property_size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|property_name | 属性名称 |
+|property_size | 属性大小 |
+| **返回** | **描述** |
+|void * | 无描述 |
+|RT_NULL | 该设备树没有该属性 |
+
+读取的值为在设备树中存储的值,CPU小端模式下可能需要使用其他API进行转换才是正确的值
+
+## 读取预留内存信息
+```c
+struct dtb_memreserve *fdt_get_dtb_memreserve(struct dtb_node *dtb_node, int *memreserve_size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|memreserve_size | 返回的内存信息数组长度 |
+| **返回** | **描述** |
+|struct dtb_memreserve *| 内存预留信息数组的内存地址 |
+|RT_NULL | 该设备树没有预留内存信息 |
+
+## 读取节点的状态
+```c
+rt_bool_t fdt_get_dtb_node_status(struct dtb_node *dtb_node)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+| **返回** | **描述** |
+|RT_FALSE | 状态为禁用 |
+|RT_TRUE | 状态为使用 |
+
+## 用于参数为字符串列表的函数
+```c
+fdt_string_list(string, ...)
+```
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|string | 字符串集合 |
+
+## 读取节点compatible标志匹配
+```c
+rt_bool_t fdt_get_dtb_node_compatible_match(struct dtb_node *dtb_node, char **compatibles)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|compatibles | 所有要匹配的字符串列表 |
+| **返回** | **描述** |
+|RT_FALSE | 匹配失败 |
+|RT_TRUE | 匹配成功 |
+
+## 读取属性值中的字符串
+```c
+char *fdt_get_dtb_string_list_value(void *value, int size, int index)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|value | 节点属性的内存地址 |
+|size | 节点属性的尺寸 |
+|index | 要读取字符串的索引 |
+| **返回** | **描述** |
+|char * | 字符串的内存地址 |
+|RT_NULL | 该索引没有字符串 |
+
+## 读取值为字符串属性下一个字符串
+```c
+char *fdt_get_dtb_string_list_value_next(void *value, void *end)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|value | 节点属性的内存地址 |
+|end | 节点属性的结束地址 |
+| **返回** | **描述** |
+|char * | 字符串的内存地址 |
+|RT_NULL | 没有下一个字符串 |
+
+## 读取值为u32属性的值
+```c
+rt_uint32_t fdt_get_dtb_cell_value(void *value)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|value | 节点属性的内存地址 |
+| **返回** | **描述** |
+|rt_uint32_t | 该值小端的值 |
+
+## 读取值为u8属性的值
+```c
+rt_uint8_t fdt_get_dtb_byte_value(void *value)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|value | 节点属性的内存地址 |
+| **返回** | **描述** |
+|rt_uint8_t | 该值小端的值 |
+
+# fdt foreach API
+
+## 遍历属性中字符串宏
+```c
+for_each_property_string(node_ptr, property_name, str, size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|node_ptr | 设备节点树节点 |
+|property_name | 节点属性名称 |
+|str | 每次遍历到的字符串 |
+|size | 用于保存节点属性的尺寸 |
+
+## 遍历属性中u32宏
+```c
+for_each_property_cell(node_ptr, property_name, value, list, size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|node_ptr | 设备节点树节点 |
+|property_name | 节点属性名称 |
+|value | 每次遍历到的值 |
+|list | 用于保存节点属性的值内存地址 |
+|size | 用于保存节点属性的尺寸 |
+
+## 遍历属性中u8宏
+```c
+for_each_property_byte(node_ptr, property_name, value, list, size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|node_ptr | 设备节点树节点 |
+|property_name | 节点属性名称 |
+|value | 每次遍历到的值 |
+|list | 用于保存节点属性的值内存地址 |
+|size | 用于保存节点属性的尺寸 |
+
+## 遍历子节点宏
+```c
+for_each_node_child(node_ptr)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|node_ptr | 设备节点树节点 |
+
+## 遍历兄弟节点宏
+```c
+for_each_node_sibling(node_ptr)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|node_ptr | 设备节点树节点 |

+ 81 - 0
components/drivers/fdt/docs/examples.md

@@ -0,0 +1,81 @@
+# fdt示例 #
+
+在`examples`文件夹中存放`bcm2711-rpi-4-b.dtb`和`vexpress-v2p-ca9.dtb`可供测试,如果系统可以从bootloader或其他方式获取到bsp本身的dtb,也可以通过修改示例程序进行测试
+
+## fdt_dump
+```bash
+fdt_dump vexpress-v2p-ca9.dtb
+```
+
+####  示例结果 ####
+```bash
+/dts-v1/;
+
+/ {
+        model = "V2P-CA9";
+        arm,hbi = <0x191>;
+        arm,vexpress,site = <0xf>;
+        compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
+        interrupt-parent = <0x1>;
+        #address-cells = <0x1>;
+        #size-cells = <0x1>;
+
+        chosen {
+        };
+
+        aliases {
+                serial0 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@9000";
+                serial1 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@a000";
+                serial2 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@b000";
+                serial3 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@c000";
+                i2c0 = "/smb@4000000/motherboard/iofpga@7,00000000/i2c@16000";
+                i2c1 = "/smb@4000000/motherboard/iofpga@7,00000000/i2c@2000";
+        };
+
+...... 省略
+
+        hsb@e0000000 {
+                compatible = "simple-bus";
+                #address-cells = <0x1>;
+                #size-cells = <0x1>;
+                ranges = <0x0 0xe0000000 0x20000000>;
+                #interrupt-cells = <0x1>;
+                interrupt-map-mask = <0x0 0x3>;
+                interrupt-map = <0x0 0x0 0x1 0x0 0x24 0x4 0x0 0x1 0x1 0x0 0x25 0x4 0x0 0x2 0x1 0x0 0x26 0x4 0x0 0x3 0x1 0x0 0x27 0x4>;
+        };
+};
+```
+
+## fdt_test
+```bash
+fdt_test
+```
+
+####  示例结果 ####
+```bash
+name = uart@9000
+reg = <0x9000,0x1000>;
+compatible = "arm,pl011","arm,primecell";
+
+name = cpus
+path = /cpus/cpu@0/
+path = /cpus/cpu@1/
+path = /cpus/cpu@2/
+path = /cpus/cpu@3/
+
+name = user1, lable = v2m:green:user1
+name = user2, lable = v2m:green:user2
+name = user3, lable = v2m:green:user3
+name = user4, lable = v2m:green:user4
+name = user5, lable = v2m:green:user5
+name = user6, lable = v2m:green:user6
+name = user7, lable = v2m:green:user7
+name = user8, lable = v2m:green:user8
+
+/memreserve/    0x0000000000000000 0x0000000000001000;
+
+phandle = <0x9>
+name = bt_pins
+path = /soc/gpio@7e200000/bt_pins/
+brcm,pins = [2d 00]
+```

+ 7 - 0
components/drivers/fdt/docs/version.md

@@ -0,0 +1,7 @@
+# 版本和修订 #
+
+| Date       | Version   |  Author    | Note  |
+| --------   | :-----:   | :----      | :---- |
+| 2021-9-1   | v0.0.1    | GuEe-GUI   | 初始版本 |
+| 2021-11-11   | v1.0.0    | GuEe-GUI   | API确定版本 |
+|            |           |            | |

+ 10 - 0
components/drivers/fdt/examples/SConscript

@@ -0,0 +1,10 @@
+
+from building import *
+
+cwd     = GetCurrentDir()
+src     = Glob('*.c')
+CPPPATH = [cwd]
+
+group = DefineGroup('FDT', src, depend = ['FDT_USING_DEBUG'], CPPPATH = CPPPATH)
+
+Return('group')

+ 143 - 0
components/drivers/fdt/examples/fdt_test.c

@@ -0,0 +1,143 @@
+#include <rtthread.h>
+#include "dtb_node.h"
+
+int dtb_test()
+{
+    void *fdt;
+
+    if ((fdt = dtb_node_load_from_fs("vexpress-v2p-ca9.dtb")) != RT_NULL)
+    {
+        struct dtb_node *dtb_node_list =  dtb_node_get_dtb_list(fdt);
+        if (dtb_node_list != RT_NULL)
+        {
+            struct dtb_node *serial0 = dtb_node_get_dtb_node_by_path(dtb_node_list, "/smb@4000000/motherboard/iofpga@7,00000000/uart@9000");
+            struct dtb_node *cpu = dtb_node_get_dtb_node_by_path(dtb_node_list, "/cpus");
+            struct dtb_node *user1 = dtb_node_get_dtb_node_by_path(dtb_node_list, "/smb@4000000/motherboard/leds/user1");
+
+            if (serial0 != RT_NULL)
+            {
+                int property_size;
+                rt_uint32_t u32_value;
+                rt_uint32_t *u32_ptr;
+                char *str_ptr;
+
+                rt_kprintf("name = %s\n", serial0->name);
+
+                rt_kputs("reg = <");
+                for_each_property_cell(serial0, "reg", u32_value, u32_ptr, property_size)
+                {
+                    rt_kprintf("0x%x,", u32_value);
+                }
+                rt_kputs("\b>;\n");
+
+                rt_kputs("compatible = ");
+                for_each_property_string(serial0, "compatible", str_ptr, property_size)
+                {
+                    rt_kprintf("\"%s\",", str_ptr);
+                }
+                rt_kputs("\b;\n");
+            }
+
+            if (cpu != RT_NULL)
+            {
+                struct dtb_node *cpu_child = cpu;
+
+                rt_kprintf("\nname = %s\n", cpu->name);
+
+                for_each_node_child(cpu_child)
+                {
+                    rt_kprintf("path = %s\n", cpu_child->path);
+                }
+            }
+
+            if (user1 != RT_NULL)
+            {
+                struct dtb_node *user = user1;
+
+                rt_kprintf("\nname = %s, lable = %s\n", user1->name, dtb_node_get_dtb_node_property(user1, "label", RT_NULL));
+
+                for_each_node_sibling(user)
+                {
+                    rt_kprintf("name = %s, lable = %s\n", user->name, dtb_node_get_dtb_node_property(user, "label", RT_NULL));
+                }
+            }
+        }
+        dtb_node_free_dtb_list(dtb_node_list);
+    }
+
+    if ((fdt = dtb_node_load_from_fs("bcm2711-rpi-4-b.dtb")) != RT_NULL)
+    {
+        struct dtb_node *dtb_node_list =  dtb_node_get_dtb_list(fdt);
+        if (dtb_node_list != RT_NULL)
+        {
+            struct dtb_node *bt_pins;
+            int memreserve_size;
+            struct dtb_memreserve *memreserve;
+
+            bt_pins = dtb_node_get_dtb_node_by_name_DFS(dtb_node_list, "bt_pins");
+            bt_pins = dtb_node_get_dtb_node_by_name_BFS(dtb_node_list, bt_pins->name);
+            bt_pins = dtb_node_get_dtb_node_by_phandle_DFS(dtb_node_list, bt_pins->handle);
+            bt_pins = dtb_node_get_dtb_node_by_phandle_BFS(dtb_node_list, bt_pins->handle);
+
+            memreserve = dtb_node_get_dtb_memreserve(bt_pins, &memreserve_size);
+            if (memreserve_size > 0)
+            {
+                int i;
+                for (i = 0; i < memreserve_size; ++i)
+                {
+                    rt_kputs("\n/memreserve/\t");
+                    if (IN_64BITS_MODE)
+                    {
+                        rt_kprintf("0x%016x 0x%016x;", memreserve[i].address, memreserve[i].size);
+                    }
+                    else
+                    {
+                        rt_kprintf("0x%08x%08x 0x%08x%08x;", memreserve[i].address, memreserve[i].size);
+                    }
+                }
+            }
+
+            if (bt_pins != RT_NULL)
+            {
+                int property_size;
+                rt_uint8_t u8_value;
+                rt_uint8_t *u8_ptr;
+
+                rt_kprintf("\n\nphandle = <0x%x>\n", bt_pins->handle);
+                rt_kprintf("name = %s\n", bt_pins->name);
+                rt_kprintf("path = %s\n", bt_pins->path);
+
+                rt_kputs("brcm,pins = [");
+                for_each_property_byte(bt_pins, "brcm,pins", u8_value, u8_ptr, property_size)
+                {
+                    rt_kprintf("%02x ", u8_value);
+                }
+                rt_kputs("\b]\n");
+            }
+        }
+        dtb_node_free_dtb_list(dtb_node_list);
+    }
+    return 0;
+}
+MSH_CMD_EXPORT(dtb_test, dtb API test);
+
+int dtb_dump(int argc, char** argv)
+{
+    struct dtb_node *dtb_root_node = get_dtb_node_head();
+    if(argc == 1)
+    {
+        if (dtb_root_node != RT_NULL)
+        {
+            dtb_node_get_dts_dump(dtb_root_node);
+        }
+    }
+    else
+    {
+        rt_kprintf("invailed parameter\n");
+    }
+
+    return 0;
+}
+MSH_CMD_EXPORT(dtb_dump, dtb dump from mem);
+
+

+ 379 - 0
components/drivers/fdt/inc/dtb_node.h

@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef _DTB_NODE_H__
+#define _DTB_NODE_H__
+
+#include "libfdt_env.h"
+#include <rtthread.h>
+
+//#define RT_DTB_DEBUG
+#ifdef RT_DTB_DEBUG
+#define debug(fmt, args...) rt_kprintf(fmt, ##args)
+#else
+#define debug(fmt, args...)
+#endif
+
+#define ERR_PTR(err)    ((void *)((long)(err)))
+#define PTR_ERR(ptr)    ((long)(ptr))
+#define IS_ERR(ptr)     ((unsigned long)(ptr) > (unsigned long)(-1000))
+
+#define DEV_ROOT_NODE_ADDR_CELLS_DEFAULT 2
+#define DEV_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+/* will be optimized to only u64 or u32 by gcc */
+#define IN_64BITS_MODE (sizeof(void *) == 8)
+
+#define FDT_ROOT_ADDR_CELLS_DEFAULT 1
+#define FDT_ROOT_SIZE_CELLS_DEFAULT 1
+
+#define FDT_DTB_ALL_NODES_PATH_SIZE (32 * 1024)
+#define FDT_DTB_PAD_SIZE 1024
+
+#define FDT_RET_NO_MEMORY 2
+#define FDT_RET_NO_LOADED 1
+#define FDT_RET_GET_OK 0
+#define FDT_RET_GET_EMPTY (-1)
+
+typedef uint32_t phandle;
+
+struct dtb_memreserve
+{
+    uintptr_t address;
+    size_t size;
+};
+
+struct dtb_header
+{
+    char root, zero; /* "/" */
+    struct dtb_memreserve *memreserve;
+    size_t memreserve_sz;
+};
+
+struct dtb_property
+{
+    const char *name;
+    int size;
+    void *value;
+
+    struct dtb_property *next;
+};
+
+struct dtb_node
+{
+    union
+    {
+        const char *name;
+        const struct dtb_header *header;
+    };
+    const char *path;
+    phandle handle;
+
+    struct dtb_property *properties;
+    struct dtb_node *parent;
+    struct dtb_node *child;
+    struct dtb_node *sibling;
+};
+
+#define FDT_MAX_PHANDLE_ARGS 16
+
+/**
+ * struct dtb_node_phandle_args - structure to hold phandle and arguments
+ *
+ * This is used when decoding a phandle in a device tree property. Typically
+ * these look like this:
+ *
+ * wibble {
+ *    phandle = <5>;
+ * };
+ *
+ * ...
+ * some-prop = <&wibble 1 2 3>
+ *
+ * Here &node is the phandle of the node 'wibble', i.e. 5. There are three
+ * arguments: 1, 2, 3.
+ *
+ * So when decoding the phandle in some-prop, np will point to wibble,
+ * args_count will be 3 and the three arguments will be in args.
+ *
+ * @np: Node that the phandle refers to
+ * @args_count: Number of arguments
+ * @args: Argument values
+ */
+struct fdt_phandle_args
+{
+    struct dtb_node *np;
+    int args_count;
+    uint32_t args[FDT_MAX_PHANDLE_ARGS];
+};
+
+/*
+ * A single signal can be specified via a range of minimal and maximal values
+ * with a typical value, that lies somewhere inbetween.
+ */
+struct timing_entry
+{
+    uint32_t min;
+    uint32_t typ;
+    uint32_t max;
+};
+
+void *get_fdt_blob(void);
+struct dtb_node *get_dtb_node_head(void);
+rt_bool_t dtb_node_active(void);
+int device_tree_setup(void *mem_addr);
+
+void *dtb_node_load_from_fs(char *dtb_filename);
+void *dtb_node_load_from_memory(void *dtb_ptr, rt_bool_t is_clone);
+
+size_t dtb_node_set_linux_cmdline(void *fdt, char *cmdline);
+size_t dtb_node_set_linux_initrd(void *fdt, uint64_t initrd_addr, size_t initrd_size);
+
+size_t dtb_node_set_dtb_property(void *fdt, char *pathname, char *property_name, uint32_t *cells, size_t cells_size);
+size_t dtb_node_add_dtb_memreserve(void *fdt, uint64_t address, uint64_t size);
+size_t dtb_node_del_dtb_memreserve(void *fdt, uint64_t address);
+
+int dtb_node_get_exec_status();
+struct dtb_node *dtb_node_get_dtb_list(void *fdt);
+void dtb_node_free_dtb_list(struct dtb_node *dtb_node_head);
+void dtb_node_get_dts_dump(struct dtb_node *dtb_node_head);
+void dtb_node_get_enum_dtb_node(struct dtb_node *dtb_node_head, void(callback(struct dtb_node *dtb_node)));
+
+struct dtb_node *dtb_node_get_dtb_node_by_name_DFS(struct dtb_node *dtb_node, const char *nodename);
+struct dtb_node *dtb_node_get_dtb_node_by_name_BFS(struct dtb_node *dtb_node, const char *nodename);
+struct dtb_node *dtb_node_get_dtb_node_by_path(struct dtb_node *dtb_node, const char *pathname);
+struct dtb_node *dtb_node_get_dtb_node_by_phandle_DFS(struct dtb_node *dtb_node, phandle handle);
+struct dtb_node *dtb_node_get_dtb_node_by_phandle_BFS(struct dtb_node *dtb_node, phandle handle);
+void dtb_node_get_dtb_node_cells(struct dtb_node *dtb_node, int *addr_cells, int *size_cells);
+struct dtb_memreserve *dtb_node_get_dtb_memreserve(struct dtb_node *dtb_node, int *memreserve_size);
+uint8_t dtb_node_get_dtb_byte_value(void *value);
+
+char *dtb_node_get_dtb_string_list_value(void *value, int size, int index);
+char *dtb_node_get_dtb_string_list_value_next(void *value, void *end);
+uint32_t dtb_node_get_dtb_cell_value(void *value);
+
+rt_bool_t dtb_node_get_dtb_node_status(const struct dtb_node *dtb_node);
+rt_bool_t dtb_node_get_dtb_node_compatible_match(const struct dtb_node *dtb_node, const char *compatibles);
+
+/*dtb_node_access.c */
+int dtb_node_read_u32(const struct dtb_node *dn, const char *propname, uint32_t *outp);
+uint32_t dtb_node_read_u32_default(const struct dtb_node *node, const char *propname, uint32_t def);
+int dtb_node_read_u32_index(const struct dtb_node *node, const char *propname, int index,
+                           uint32_t *outp);
+uint32_t dtb_node_read_u32_index_default(const struct dtb_node *node, const char *propname, int index,
+                                        uint32_t def);
+int dtb_node_read_u32_array(const struct dtb_node *dn, const char *propname,
+                       uint32_t *out_values, size_t sz);
+int dtb_node_read_u32_index(const struct dtb_node *dn, const char *propname,
+                       int index, uint32_t *outp);
+int dtb_node_read_s32_default(const struct dtb_node *node, const char *propname, int32_t def);
+int dtb_node_read_u64(const struct dtb_node *dn, const char *propname, uint64_t *outp);
+uint64_t dtb_node_read_u64_default(const struct dtb_node *node, const char *propname, uint64_t def);
+
+int dtb_node_n_addr_cells(const struct dtb_node *dn);
+int dtb_node_n_size_cells(const struct dtb_node *dn);
+int dtb_node_simple_addr_cells(const struct dtb_node *np);
+int dtb_node_simple_size_cells(const struct dtb_node *np);
+
+struct dtb_node *dtb_node_find_all_nodes(const struct dtb_node *prev);
+struct dtb_node *dtb_node_find_node_by_phandle(phandle handle);
+struct dtb_node *dtb_node_find_compatible_node(struct dtb_node *from, const char *compatible);
+void *dtb_node_get_dtb_node_property_value(const struct dtb_node *dtb_node, const char *property_name, int *property_size);
+struct dtb_property *dtb_node_get_dtb_node_property(const struct dtb_node *dtb_node, const char *property_name, int *property_size);
+const struct dtb_node *dtb_node_find_node_by_prop_value(struct dtb_node *from, const char *propname, const void *propval, int proplen);
+struct dtb_node *dtb_node_find_node_opts_by_path(const char *path,
+                                            const char **opts);
+
+static inline struct dtb_node *dtb_node_find_node_by_path(const char *path)
+{
+    return dtb_node_find_node_opts_by_path(path, NULL);
+}
+
+rt_bool_t dtb_node_device_is_available(const struct dtb_node *device);
+struct dtb_node *dtb_node_get_parent(const struct dtb_node *node);
+int dtb_node_property_match_string(const struct dtb_node *dn, const char *propname,
+                              const char *string);
+int dtb_node_property_read_string_helper(const struct dtb_node *dn,
+                                    const char *propname, const char **out_strs,
+                                    size_t sz, int skip);
+/**
+ * of_property_read_string_index() - Find and read a string from a multiple
+ * strings property.
+ * @np:		device node from which the property value is to be read.
+ * @propname:	name of the property to be searched.
+ * @index:	index of the string in the list of strings
+ * @out_string:	pointer to null terminated return string, modified only if
+ *		return value is 0.
+ *
+ * Search for a property in a device tree node and retrieve a null
+ * terminated string value (pointer to data, not a copy) in the list of strings
+ * contained in that property.
+ * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if
+ * property does not have a value, and -EILSEQ if the string is not
+ * null-terminated within the length of the property data.
+ *
+ * The out_string pointer is modified only if a valid string can be decoded.
+ */
+static inline int dtb_node_property_read_string_index(const struct dtb_node *dn,
+                                                 const char *propname,
+                                                 int index, const char **output)
+{
+    int rc = dtb_node_property_read_string_helper(dn, propname, output, 1, index);
+    return rc < 0 ? rc : 0;
+}
+
+/**
+ * of_property_count_strings() - Find and return the number of strings from a
+ * multiple strings property.
+ * @np:		device node from which the property value is to be read.
+ * @propname:	name of the property to be searched.
+ *
+ * Search for a property in a device tree node and retrieve the number of null
+ * terminated string contain in it. Returns the number of strings on
+ * success, -EINVAL if the property does not exist, -ENODATA if property
+ * does not have a value, and -EILSEQ if the string is not null-terminated
+ * within the length of the property data.
+ */
+static inline int dtb_node_property_count_strings(const struct dtb_node *dn,
+                                             const char *propname)
+{
+    return dtb_node_property_read_string_helper(dn, propname, NULL, 0, 0);
+}
+
+struct dtb_node *dtb_node_parse_phandle(const struct dtb_node *dn,
+                                   const char *phandle_name, int index);
+int dtb_node_parse_phandle_with_args(const struct dtb_node *dn,
+                                const char *list_name, const char *cells_name,
+                                int index, struct fdt_phandle_args *out_args);
+int dtb_node_count_phandle_with_args(const struct dtb_node *dn,
+                                const char *list_name, const char *cells_name);
+
+/* dtb_node_addr.c */
+const uint32_t *dtb_node_get_address(const struct dtb_node *dev, int index,
+                                uint64_t *size, unsigned int *flags);
+
+#define dtb_node_string_list(string, ...) ((char *[]){string, ##__VA_ARGS__, NULL})
+
+#define for_each_property_string(node_ptr, property_name, str, size)            \
+    for (str = dtb_node_get_dtb_node_property_value(node_ptr, property_name, &size), \
+        size += (typeof(size))(size_t)str;                                      \
+         str && *str;                                                           \
+         str = dtb_node_get_dtb_string_list_value_next((void *)str, (void *)(size_t)size))
+
+#define for_each_property_cell(node_ptr, property_name, value, list, size)       \
+    for (list = dtb_node_get_dtb_node_property_value(node_ptr, property_name, &size), \
+        value = dtb_node_get_dtb_cell_value(list),                                    \
+        size /= sizeof(uint32_t);                                                \
+         size > 0;                                                               \
+         value = dtb_node_get_dtb_cell_value(++list), --size)
+
+#define for_each_property_byte(node_ptr, property_name, value, list, size)       \
+    for (list = dtb_node_get_dtb_node_property_value(node_ptr, property_name, &size), \
+        value = dtb_node_get_dtb_byte_value(list);                                    \
+         size > 0;                                                               \
+         value = dtb_node_get_dtb_byte_value(++list), --size)
+
+#define for_each_node_child(node_ptr)                    \
+    for (node_ptr = (node_ptr ? node_ptr->child : NULL); \
+         node_ptr != NULL;                               \
+         node_ptr = node_ptr->sibling)
+
+#define for_each_node_sibling(node_ptr)                    \
+    for (node_ptr = (node_ptr ? node_ptr->sibling : NULL); \
+         node_ptr != NULL;                                 \
+         node_ptr = node_ptr->sibling)
+
+#define for_each_of_allnodes_from(from, dn) \
+    for (dn = dtb_node_find_all_nodes(from); dn; dn = dtb_node_find_all_nodes(dn))
+
+#define for_each_of_allnodes(dn) for_each_of_allnodes_from(NULL, dn)
+
+#define dtb_node_get(x) (x)
+static inline void dtb_node_put(const struct dtb_node *np)
+{
+}
+
+/* Helper to read a big number; size is in cells (not bytes) */
+static inline uint64_t dtb_node_read_number(const uint32_t *cell, int size)
+{
+    uint64_t r = 0;
+    while (size--)
+        r = (r << 32) | fdt32_to_cpu(*(cell++));
+    return r;
+}
+
+/**
+ * ofnode_valid() - check if an ofnode is valid
+ *
+ * @return true if the reference contains a valid ofnode, RT_FALSE if it is NULL
+ */
+static inline rt_bool_t dtb_node_valid(const struct dtb_node *node)
+{
+    if (dtb_node_active())
+        return node != NULL;
+    return RT_FALSE;
+}
+
+/*dtb_base.c */
+rt_bool_t dtb_node_read_bool(const struct dtb_node *node, const char *propname);
+const void *dtb_node_read_prop(const struct dtb_node *node, const char *propname, int *sizep);
+const char *dtb_node_read_string(const struct dtb_node *node, const char *propname);
+const struct dtb_node *dtb_node_find_subnode(const struct dtb_node *node, const char *subnode_name);
+int dtb_node_read_u32_array(const struct dtb_node *node, const char *propname,
+                           uint32_t *out_values, size_t sz);
+struct dtb_node *dtb_node_first_subnode(const struct dtb_node *node);
+struct dtb_node *dtb_node_next_subnode(const struct dtb_node *node);
+struct dtb_node *dtb_node_get_parent(const struct dtb_node *node);
+const char *dtb_node_get_name(const struct dtb_node *node);
+struct dtb_node *dtb_node_get_by_phandle(uint phandle);
+int dtb_node_read_size(const struct dtb_node *node, const char *propname);
+size_t dtb_node_get_addr_index(const struct dtb_node *node, int index);
+size_t dtb_node_get_addr(const struct dtb_node *node);
+int dtb_node_stringlist_search(const struct dtb_node *node, const char *property,
+                              const char *string);
+int dtb_node_read_string_index(const struct dtb_node *node, const char *property, int index,
+                              const char **outp);
+int dtb_node_read_string_count(const struct dtb_node *node, const char *property);
+struct dtb_node *dtb_node_path(const char *path);
+const char *dtb_node_get_chosen_prop(const char *name);
+struct dtb_node *dtb_node_get_chosen_node(const char *name);
+const void *dtb_node_get_property(const struct dtb_node *node, const char *propname, int *lenp);
+rt_bool_t dtb_node_is_available(const struct dtb_node *node);
+size_t dtb_node_get_addr_size(const struct dtb_node *node, const char *property,
+                             size_t *sizep);
+const uint8_t *dtb_node_read_u8_array_ptr(const struct dtb_node *node, const char *propname, size_t sz);
+int dtb_node_find_all_compatible_node(const struct dtb_node *from, const char *compatible, struct dtb_node **node_table, int max_num, int *node_num);
+int dtb_node_write_prop(const struct dtb_node *node, const char *propname, int len,
+                       const void *value);
+int dtb_node_write_string(const struct dtb_node *node, const char *propname, const char *value);
+int dtb_node_set_enabled(const struct dtb_node *node, rt_bool_t value);
+int dtb_node_irq_get(struct dtb_node *dev, int index);
+int dtb_node_irq_get_byname(struct dtb_node *dev, const char *name);
+int dtb_node_irq_count(struct dtb_node *dev);
+
+/**
+ * dtb_node_for_each_subnode() - iterate over all subnodes of a parent
+ *
+ * @node:       child node (ofnode, lvalue)
+ * @parent:     parent node (ofnode)
+ *
+ * This is a wrapper around a for loop and is used like so:
+ *
+ * ofnode node;
+ *
+ * dtb_node_for_each_subnode(node, parent) {
+ *      Use node
+ *       ...
+ * }
+ *
+ * Note that this is implemented as a macro and @node is used as
+ * iterator in the loop. The parent variable can be a constant or even a
+ * literal.
+ */
+#define dtb_node_for_each_subnode(node, parent) \
+    for (node = dtb_node_first_subnode(parent); \
+         dtb_node_valid(node);                  \
+         node = dtb_node_next_subnode(node))
+
+#endif /* RT_FDT_H__ */

+ 10 - 0
components/drivers/fdt/libfdt/SConscript

@@ -0,0 +1,10 @@
+from building import *
+
+cwd     = GetCurrentDir()
+src     = Glob('*.c')
+
+CPPPATH = [cwd]
+
+group = DefineGroup('FDT', src, depend = ['RT_USING_FDTLIB'], CPPPATH = CPPPATH)
+
+Return('group')

+ 249 - 0
components/drivers/fdt/libfdt/fdt.c

@@ -0,0 +1,249 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+int fdt_check_header(const void *fdt)
+{
+	if (fdt_magic(fdt) == FDT_MAGIC) {
+		/* Complete tree */
+		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+			return -FDT_ERR_BADVERSION;
+		if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
+			return -FDT_ERR_BADVERSION;
+	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+		/* Unfinished sequential-write blob */
+		if (fdt_size_dt_struct(fdt) == 0)
+			return -FDT_ERR_BADSTATE;
+	} else {
+		return -FDT_ERR_BADMAGIC;
+	}
+
+	return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
+{
+	unsigned absoffset = offset + fdt_off_dt_struct(fdt);
+
+	if ((absoffset < offset)
+	    || ((absoffset + len) < absoffset)
+	    || (absoffset + len) > fdt_totalsize(fdt))
+		return NULL;
+
+	if (fdt_version(fdt) >= 0x11)
+		if (((offset + len) < offset)
+		    || ((offset + len) > fdt_size_dt_struct(fdt)))
+			return NULL;
+
+	return _fdt_offset_ptr(fdt, offset);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+{
+	const fdt32_t *tagp, *lenp;
+	uint32_t tag;
+	int offset = startoffset;
+	const char *p;
+
+	*nextoffset = -FDT_ERR_TRUNCATED;
+	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+	if (!tagp)
+		return FDT_END; /* premature end */
+	tag = fdt32_to_cpu(*tagp);
+	offset += FDT_TAGSIZE;
+
+	*nextoffset = -FDT_ERR_BADSTRUCTURE;
+	switch (tag) {
+	case FDT_BEGIN_NODE:
+		/* skip name */
+		do {
+			p = fdt_offset_ptr(fdt, offset++, 1);
+		} while (p && (*p != '\0'));
+		if (!p)
+			return FDT_END; /* premature end */
+		break;
+
+	case FDT_PROP:
+		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+		if (!lenp)
+			return FDT_END; /* premature end */
+		/* skip-name offset, length and value */
+		offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+			+ fdt32_to_cpu(*lenp);
+		break;
+
+	case FDT_END:
+	case FDT_END_NODE:
+	case FDT_NOP:
+		break;
+
+	default:
+		return FDT_END;
+	}
+
+	if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
+		return FDT_END; /* premature end */
+
+	*nextoffset = FDT_TAGALIGN(offset);
+	return tag;
+}
+
+int _fdt_check_node_offset(const void *fdt, int offset)
+{
+	if ((offset < 0) || (offset % FDT_TAGSIZE)
+	    || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+		return -FDT_ERR_BADOFFSET;
+
+	return offset;
+}
+
+int _fdt_check_prop_offset(const void *fdt, int offset)
+{
+	if ((offset < 0) || (offset % FDT_TAGSIZE)
+	    || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
+		return -FDT_ERR_BADOFFSET;
+
+	return offset;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+	int nextoffset = 0;
+	uint32_t tag;
+
+	if (offset >= 0)
+		if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+			return nextoffset;
+
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		case FDT_BEGIN_NODE:
+			if (depth)
+				(*depth)++;
+			break;
+
+		case FDT_END_NODE:
+			if (depth && ((--(*depth)) < 0))
+				return nextoffset;
+			break;
+
+		case FDT_END:
+			if ((nextoffset >= 0)
+			    || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
+				return -FDT_ERR_NOTFOUND;
+			else
+				return nextoffset;
+		}
+	} while (tag != FDT_BEGIN_NODE);
+
+	return offset;
+}
+
+int fdt_first_subnode(const void *fdt, int offset)
+{
+	int depth = 0;
+
+	offset = fdt_next_node(fdt, offset, &depth);
+	if (offset < 0 || depth != 1)
+		return -FDT_ERR_NOTFOUND;
+
+	return offset;
+}
+
+int fdt_next_subnode(const void *fdt, int offset)
+{
+	int depth = 1;
+
+	/*
+	 * With respect to the parent, the depth of the next subnode will be
+	 * the same as the last.
+	 */
+	do {
+		offset = fdt_next_node(fdt, offset, &depth);
+		if (offset < 0 || depth < 1)
+			return -FDT_ERR_NOTFOUND;
+	} while (depth > 1);
+
+	return offset;
+}
+
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+{
+	int len = strlen(s) + 1;
+	const char *last = strtab + tabsize - len;
+	const char *p;
+
+	for (p = strtab; p <= last; p++)
+		if (memcmp(p, s, len) == 0)
+			return p;
+	return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+	FDT_CHECK_HEADER(fdt);
+
+	if (fdt_totalsize(fdt) > bufsize)
+		return -FDT_ERR_NOSPACE;
+
+	memmove(buf, fdt, fdt_totalsize(fdt));
+	return 0;
+}

+ 111 - 0
components/drivers/fdt/libfdt/fdt.h

@@ -0,0 +1,111 @@
+#ifndef _FDT_H
+#define _FDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * Copyright 2012 Kim Phillips, Freescale Semiconductor.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+	fdt32_t magic;			 /* magic word FDT_MAGIC */
+	fdt32_t totalsize;		 /* total size of DT block */
+	fdt32_t off_dt_struct;		 /* offset to structure */
+	fdt32_t off_dt_strings;		 /* offset to strings */
+	fdt32_t off_mem_rsvmap;		 /* offset to memory reserve map */
+	fdt32_t version;		 /* format version */
+	fdt32_t last_comp_version;	 /* last compatible version */
+
+	/* version 2 fields below */
+	fdt32_t boot_cpuid_phys;	 /* Which physical CPU id we're
+					    booting on */
+	/* version 3 fields below */
+	fdt32_t size_dt_strings;	 /* size of the strings block */
+
+	/* version 17 fields below */
+	fdt32_t size_dt_struct;		 /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+	fdt64_t address;
+	fdt64_t size;
+};
+
+struct fdt_node_header {
+	fdt32_t tag;
+	char name[0];
+};
+
+struct fdt_property {
+	fdt32_t tag;
+	fdt32_t len;
+	fdt32_t nameoff;
+	char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC	0xd00dfeed	/* 4: version, 4: total size */
+#define FDT_TAGSIZE	sizeof(fdt32_t)
+
+#define FDT_BEGIN_NODE	0x1		/* Start node: full name */
+#define FDT_END_NODE	0x2		/* End node */
+#define FDT_PROP	0x3		/* Property: name off,
+					   size, content */
+#define FDT_NOP		0x4		/* nop */
+#define FDT_END		0x9
+
+#define FDT_V1_SIZE	(7*sizeof(fdt32_t))
+#define FDT_V2_SIZE	(FDT_V1_SIZE + sizeof(fdt32_t))
+#define FDT_V3_SIZE	(FDT_V2_SIZE + sizeof(fdt32_t))
+#define FDT_V16_SIZE	FDT_V3_SIZE
+#define FDT_V17_SIZE	(FDT_V16_SIZE + sizeof(fdt32_t))
+
+#endif /* _FDT_H */

+ 99 - 0
components/drivers/fdt/libfdt/fdt_addresses.c

@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
+ * Copyright (C) 2018 embedded brains GmbH
+ */
+#include "libfdt_env.h"
+#include <fdt.h>
+#include <libfdt.h>
+#include "libfdt_internal.h"
+
+static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
+{
+    const fdt32_t *c;
+    uint32_t val;
+    int len;
+
+    c = fdt_getprop(fdt, nodeoffset, name, &len);
+    if (!c)
+        return len;
+
+    if (len != sizeof(*c))
+        return -FDT_ERR_BADNCELLS;
+
+    val = fdt32_to_cpu(*c);
+    if (val > FDT_MAX_NCELLS)
+        return -FDT_ERR_BADNCELLS;
+
+    return (int)val;
+}
+
+int fdt_address_cells(const void *fdt, int nodeoffset)
+{
+    int val;
+
+    val = fdt_cells(fdt, nodeoffset, "#address-cells");
+    if (val == 0)
+        return -FDT_ERR_BADNCELLS;
+    if (val == -FDT_ERR_NOTFOUND)
+        return 2;
+    return val;
+}
+
+int fdt_size_cells(const void *fdt, int nodeoffset)
+{
+    int val;
+
+    val = fdt_cells(fdt, nodeoffset, "#size-cells");
+    if (val == -FDT_ERR_NOTFOUND)
+        return 1;
+    return val;
+}
+
+/* This function assumes that [address|size]_cells is 1 or 2 */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+                 const char *name, uint64_t addr, uint64_t size)
+{
+    int addr_cells, size_cells, ret;
+    uint8_t data[sizeof(fdt64_t) * 2], *prop;
+
+    ret = fdt_address_cells(fdt, parent);
+    if (ret < 0)
+        return ret;
+    addr_cells = ret;
+
+    ret = fdt_size_cells(fdt, parent);
+    if (ret < 0)
+        return ret;
+    size_cells = ret;
+
+    /* check validity of address */
+    prop = data;
+    if (addr_cells == 1) {
+        if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
+            return -FDT_ERR_BADVALUE;
+
+        fdt32_st(prop, (uint32_t)addr);
+    } else if (addr_cells == 2) {
+        fdt64_st(prop, addr);
+    } else {
+        return -FDT_ERR_BADNCELLS;
+    }
+
+    /* check validity of size */
+    prop += addr_cells * sizeof(fdt32_t);
+    if (size_cells == 1) {
+        if (size > UINT32_MAX)
+            return -FDT_ERR_BADVALUE;
+
+        fdt32_st(prop, (uint32_t)size);
+    } else if (size_cells == 2) {
+        fdt64_st(prop, size);
+    } else {
+        return -FDT_ERR_BADNCELLS;
+    }
+
+    return fdt_appendprop(fdt, nodeoffset, name, data,
+                  (addr_cells + size_cells) * sizeof(fdt32_t));
+}

+ 84 - 0
components/drivers/fdt/libfdt/fdt_empty_tree.c

@@ -0,0 +1,84 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2012 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include "fdt.h"
+#include "libfdt.h"
+
+#include "libfdt_internal.h"
+
+int fdt_create_empty_tree(void *buf, int bufsize)
+{
+	int err;
+
+	err = fdt_create(buf, bufsize);
+	if (err)
+		return err;
+
+	err = fdt_finish_reservemap(buf);
+	if (err)
+		return err;
+
+	err = fdt_begin_node(buf, "");
+	if (err)
+		return err;
+
+	err =  fdt_end_node(buf);
+	if (err)
+		return err;
+
+	err = fdt_finish(buf);
+	if (err)
+		return err;
+
+	return fdt_open_into(buf, buf, bufsize);
+}
+

+ 701 - 0
components/drivers/fdt/libfdt/fdt_ro.c

@@ -0,0 +1,701 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+static int _fdt_nodename_eq(const void *fdt, int offset,
+			    const char *s, int len)
+{
+	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
+
+	if (! p)
+		/* short match */
+		return 0;
+
+	if (memcmp(p, s, len) != 0)
+		return 0;
+
+	if (p[len] == '\0')
+		return 1;
+	else if (!memchr(s, '@', len) && (p[len] == '@'))
+		return 1;
+	else
+		return 0;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+	return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+static int _fdt_string_eq(const void *fdt, int stroffset,
+			  const char *s, int len)
+{
+	const char *p = fdt_string(fdt, stroffset);
+
+	return (strlen(p) == len) && (memcmp(p, s, len) == 0);
+}
+
+uint32_t fdt_get_max_phandle(const void *fdt)
+{
+	uint32_t max_phandle = 0;
+	int offset;
+
+	for (offset = fdt_next_node(fdt, -1, NULL);;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		uint32_t phandle;
+
+		if (offset == -FDT_ERR_NOTFOUND)
+			return max_phandle;
+
+		if (offset < 0)
+			return (uint32_t)-1;
+
+		phandle = fdt_get_phandle(fdt, offset);
+		if (phandle == (uint32_t)-1)
+			continue;
+
+		if (phandle > max_phandle)
+			max_phandle = phandle;
+	}
+
+	return 0;
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+	FDT_CHECK_HEADER(fdt);
+	*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
+	*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+	return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+	int i = 0;
+
+	while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+		i++;
+	return i;
+}
+
+static int _nextprop(const void *fdt, int offset)
+{
+	uint32_t tag;
+	int nextoffset;
+
+	do {
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_END:
+			if (nextoffset >= 0)
+				return -FDT_ERR_BADSTRUCTURE;
+			else
+				return nextoffset;
+
+		case FDT_PROP:
+			return offset;
+		}
+		offset = nextoffset;
+	} while (tag == FDT_NOP);
+
+	return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
+			       const char *name, int namelen)
+{
+	int depth;
+
+	FDT_CHECK_HEADER(fdt);
+
+	for (depth = 0;
+	     (offset >= 0) && (depth >= 0);
+	     offset = fdt_next_node(fdt, offset, &depth))
+		if ((depth == 1)
+		    && _fdt_nodename_eq(fdt, offset, name, namelen))
+			return offset;
+
+	if (depth < 0)
+		return -FDT_ERR_NOTFOUND;
+	return offset; /* error */
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+		       const char *name)
+{
+	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
+{
+	const char *end = path + namelen;
+	const char *p = path;
+	int offset = 0;
+
+	FDT_CHECK_HEADER(fdt);
+
+	/* see if we have an alias */
+	if (*path != '/') {
+		const char *q = memchr(path, '/', end - p);
+
+		if (!q)
+			q = end;
+
+		p = fdt_get_alias_namelen(fdt, p, q - p);
+		if (!p)
+			return -FDT_ERR_BADPATH;
+		offset = fdt_path_offset(fdt, p);
+
+		p = q;
+	}
+
+	while (p < end) {
+		const char *q;
+
+		while (*p == '/') {
+			p++;
+			if (p == end)
+				return offset;
+		}
+		q = memchr(p, '/', end - p);
+		if (! q)
+			q = end;
+
+		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+		if (offset < 0)
+			return offset;
+
+		p = q;
+	}
+
+	return offset;
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+	return fdt_path_offset_namelen(fdt, path, strlen(path));
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+	const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
+	int err;
+
+	if (((err = fdt_check_header(fdt)) != 0)
+	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+			goto fail;
+
+	if (len)
+		*len = strlen(nh->name);
+
+	return nh->name;
+
+ fail:
+	if (len)
+		*len = err;
+	return NULL;
+}
+
+int fdt_first_property_offset(const void *fdt, int nodeoffset)
+{
+	int offset;
+
+	if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+		return offset;
+
+	return _nextprop(fdt, offset);
+}
+
+int fdt_next_property_offset(const void *fdt, int offset)
+{
+	if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
+		return offset;
+
+	return _nextprop(fdt, offset);
+}
+
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+						      int offset,
+						      int *lenp)
+{
+	int err;
+	const struct fdt_property *prop;
+
+	if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
+		if (lenp)
+			*lenp = err;
+		return NULL;
+	}
+
+	prop = _fdt_offset_ptr(fdt, offset);
+
+	if (lenp)
+		*lenp = fdt32_to_cpu(prop->len);
+
+	return prop;
+}
+
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+						    int offset,
+						    const char *name,
+						    int namelen, int *lenp)
+{
+	for (offset = fdt_first_property_offset(fdt, offset);
+	     (offset >= 0);
+	     (offset = fdt_next_property_offset(fdt, offset))) {
+		const struct fdt_property *prop;
+
+		if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
+			offset = -FDT_ERR_INTERNAL;
+			break;
+		}
+		if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
+				   name, namelen))
+			return prop;
+	}
+
+	if (lenp)
+		*lenp = offset;
+	return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+					    int nodeoffset,
+					    const char *name, int *lenp)
+{
+	return fdt_get_property_namelen(fdt, nodeoffset, name,
+					strlen(name), lenp);
+}
+
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+				const char *name, int namelen, int *lenp)
+{
+	const struct fdt_property *prop;
+
+	prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
+	if (! prop)
+		return NULL;
+
+	return prop->data;
+}
+
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+				  const char **namep, int *lenp)
+{
+	const struct fdt_property *prop;
+
+	prop = fdt_get_property_by_offset(fdt, offset, lenp);
+	if (!prop)
+		return NULL;
+	if (namep)
+		*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+	return prop->data;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+			const char *name, int *lenp)
+{
+	return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+	const fdt32_t *php;
+	int len;
+
+	/* FIXME: This is a bit sub-optimal, since we potentially scan
+	 * over all the properties twice. */
+	php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
+	if (!php || (len != sizeof(*php))) {
+		php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+		if (!php || (len != sizeof(*php)))
+			return 0;
+	}
+
+	return fdt32_to_cpu(*php);
+}
+
+const char *fdt_get_alias_namelen(const void *fdt,
+				  const char *name, int namelen)
+{
+	int aliasoffset;
+
+	aliasoffset = fdt_path_offset(fdt, "/aliases");
+	if (aliasoffset < 0)
+		return NULL;
+
+	return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
+}
+
+const char *fdt_get_alias(const void *fdt, const char *name)
+{
+	return fdt_get_alias_namelen(fdt, name, strlen(name));
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+	int pdepth = 0, p = 0;
+	int offset, depth, namelen;
+	const char *name;
+
+	FDT_CHECK_HEADER(fdt);
+
+	if (buflen < 2)
+		return -FDT_ERR_NOSPACE;
+
+	for (offset = 0, depth = 0;
+	     (offset >= 0) && (offset <= nodeoffset);
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		while (pdepth > depth) {
+			do {
+				p--;
+			} while (buf[p-1] != '/');
+			pdepth--;
+		}
+
+		if (pdepth >= depth) {
+			name = fdt_get_name(fdt, offset, &namelen);
+			if (!name)
+				return namelen;
+			if ((p + namelen + 1) <= buflen) {
+				memcpy(buf + p, name, namelen);
+				p += namelen;
+				buf[p++] = '/';
+				pdepth++;
+			}
+		}
+
+		if (offset == nodeoffset) {
+			if (pdepth < (depth + 1))
+				return -FDT_ERR_NOSPACE;
+
+			if (p > 1) /* special case so that root path is "/", not "" */
+				p--;
+			buf[p] = '\0';
+			return 0;
+		}
+	}
+
+	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+		return -FDT_ERR_BADOFFSET;
+	else if (offset == -FDT_ERR_BADOFFSET)
+		return -FDT_ERR_BADSTRUCTURE;
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth)
+{
+	int offset, depth;
+	int supernodeoffset = -FDT_ERR_INTERNAL;
+
+	FDT_CHECK_HEADER(fdt);
+
+	if (supernodedepth < 0)
+		return -FDT_ERR_NOTFOUND;
+
+	for (offset = 0, depth = 0;
+	     (offset >= 0) && (offset <= nodeoffset);
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		if (depth == supernodedepth)
+			supernodeoffset = offset;
+
+		if (offset == nodeoffset) {
+			if (nodedepth)
+				*nodedepth = depth;
+
+			if (supernodedepth > depth)
+				return -FDT_ERR_NOTFOUND;
+			else
+				return supernodeoffset;
+		}
+	}
+
+	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+		return -FDT_ERR_BADOFFSET;
+	else if (offset == -FDT_ERR_BADOFFSET)
+		return -FDT_ERR_BADSTRUCTURE;
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+	int nodedepth;
+	int err;
+
+	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+	if (err)
+		return (err < 0) ? err : -FDT_ERR_INTERNAL;
+	return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+	int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+	if (nodedepth < 0)
+		return nodedepth;
+	return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+					    nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+				  const char *propname,
+				  const void *propval, int proplen)
+{
+	int offset;
+	const void *val;
+	int len;
+
+	FDT_CHECK_HEADER(fdt);
+
+	/* FIXME: The algorithm here is pretty horrible: we scan each
+	 * property of a node in fdt_getprop(), then if that didn't
+	 * find what we want, we scan over them again making our way
+	 * to the next node.  Still it's the easiest to implement
+	 * approach; performance can come later. */
+	for (offset = fdt_next_node(fdt, startoffset, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		val = fdt_getprop(fdt, offset, propname, &len);
+		if (val && (len == proplen)
+		    && (memcmp(val, propval, len) == 0))
+			return offset;
+	}
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+	int offset;
+
+	if ((phandle == 0) || (phandle == -1))
+		return -FDT_ERR_BADPHANDLE;
+
+	FDT_CHECK_HEADER(fdt);
+
+	/* FIXME: The algorithm here is pretty horrible: we
+	 * potentially scan each property of a node in
+	 * fdt_get_phandle(), then if that didn't find what
+	 * we want, we scan over them again making our way to the next
+	 * node.  Still it's the easiest to implement approach;
+	 * performance can come later. */
+	for (offset = fdt_next_node(fdt, -1, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		if (fdt_get_phandle(fdt, offset) == phandle)
+			return offset;
+	}
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
+{
+	int len = strlen(str);
+	const char *p;
+
+	while (listlen >= len) {
+		if (memcmp(str, strlist, len+1) == 0)
+			return 1;
+		p = memchr(strlist, '\0', listlen);
+		if (!p)
+			return 0; /* malformed strlist.. */
+		listlen -= (p-strlist) + 1;
+		strlist = p + 1;
+	}
+	return 0;
+}
+
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
+{
+	const char *list, *end;
+	int length, count = 0;
+
+	list = fdt_getprop(fdt, nodeoffset, property, &length);
+	if (!list)
+		return length;
+
+	end = list + length;
+
+	while (list < end) {
+		length = strnlen(list, end - list) + 1;
+
+		/* Abort if the last string isn't properly NUL-terminated. */
+		if (list + length > end)
+			return -FDT_ERR_BADVALUE;
+
+		list += length;
+		count++;
+	}
+
+	return count;
+}
+
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+			  const char *string)
+{
+	int length, len, idx = 0;
+	const char *list, *end;
+
+	list = fdt_getprop(fdt, nodeoffset, property, &length);
+	if (!list)
+		return length;
+
+	len = strlen(string) + 1;
+	end = list + length;
+
+	while (list < end) {
+		length = strnlen(list, end - list) + 1;
+
+		/* Abort if the last string isn't properly NUL-terminated. */
+		if (list + length > end)
+			return -FDT_ERR_BADVALUE;
+
+		if (length == len && memcmp(list, string, length) == 0)
+			return idx;
+
+		list += length;
+		idx++;
+	}
+
+	return -FDT_ERR_NOTFOUND;
+}
+
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+			       const char *property, int idx,
+			       int *lenp)
+{
+	const char *list, *end;
+	int length;
+
+	list = fdt_getprop(fdt, nodeoffset, property, &length);
+	if (!list) {
+		if (lenp)
+			*lenp = length;
+
+		return NULL;
+	}
+
+	end = list + length;
+
+	while (list < end) {
+		length = strnlen(list, end - list) + 1;
+
+		/* Abort if the last string isn't properly NUL-terminated. */
+		if (list + length > end) {
+			if (lenp)
+				*lenp = -FDT_ERR_BADVALUE;
+
+			return NULL;
+		}
+
+		if (idx == 0) {
+			if (lenp)
+				*lenp = length - 1;
+
+			return list;
+		}
+
+		list += length;
+		idx--;
+	}
+
+	if (lenp)
+		*lenp = -FDT_ERR_NOTFOUND;
+
+	return NULL;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+			      const char *compatible)
+{
+	const void *prop;
+	int len;
+
+	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+	if (!prop)
+		return len;
+
+	return !fdt_stringlist_contains(prop, len, compatible);
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+				  const char *compatible)
+{
+	int offset, err;
+
+	FDT_CHECK_HEADER(fdt);
+
+	/* FIXME: The algorithm here is pretty horrible: we scan each
+	 * property of a node in fdt_node_check_compatible(), then if
+	 * that didn't find what we want, we scan over them again
+	 * making our way to the next node.  Still it's the easiest to
+	 * implement approach; performance can come later. */
+	for (offset = fdt_next_node(fdt, startoffset, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		err = fdt_node_check_compatible(fdt, offset, compatible);
+		if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+			return err;
+		else if (err == 0)
+			return offset;
+	}
+
+	return offset; /* error from fdt_next_node() */
+}

+ 489 - 0
components/drivers/fdt/libfdt/fdt_rw.c

@@ -0,0 +1,489 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+static int _fdt_blocks_misordered(const void *fdt,
+			      int mem_rsv_size, int struct_size)
+{
+	return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
+		|| (fdt_off_dt_struct(fdt) <
+		    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+		|| (fdt_off_dt_strings(fdt) <
+		    (fdt_off_dt_struct(fdt) + struct_size))
+		|| (fdt_totalsize(fdt) <
+		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int _fdt_rw_check_header(void *fdt)
+{
+	FDT_CHECK_HEADER(fdt);
+
+	if (fdt_version(fdt) < 17)
+		return -FDT_ERR_BADVERSION;
+	if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+				   fdt_size_dt_struct(fdt)))
+		return -FDT_ERR_BADLAYOUT;
+	if (fdt_version(fdt) > 17)
+		fdt_set_version(fdt, 17);
+
+	return 0;
+}
+
+#define FDT_RW_CHECK_HEADER(fdt) \
+	{ \
+		int __err; \
+		if ((__err = _fdt_rw_check_header(fdt)) != 0) \
+			return __err; \
+	}
+
+static inline int _fdt_data_size(void *fdt)
+{
+	return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+}
+
+static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
+{
+	char *p = splicepoint;
+	char *end = (char *)fdt + _fdt_data_size(fdt);
+
+	if (((p + oldlen) < p) || ((p + oldlen) > end))
+		return -FDT_ERR_BADOFFSET;
+	if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
+		return -FDT_ERR_BADOFFSET;
+	if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
+		return -FDT_ERR_NOSPACE;
+	memmove(p + newlen, p + oldlen, end - p - oldlen);
+	return 0;
+}
+
+static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+			       int oldn, int newn)
+{
+	int delta = (newn - oldn) * sizeof(*p);
+	int err;
+	err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+	if (err)
+		return err;
+	fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+	return 0;
+}
+
+static int _fdt_splice_struct(void *fdt, void *p,
+			      int oldlen, int newlen)
+{
+	int delta = newlen - oldlen;
+	int err;
+
+	if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
+		return err;
+
+	fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+	return 0;
+}
+
+static int _fdt_splice_string(void *fdt, int newlen)
+{
+	void *p = (char *)fdt
+		+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+	int err;
+
+	if ((err = _fdt_splice(fdt, p, 0, newlen)))
+		return err;
+
+	fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
+	return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+	char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+	const char *p;
+	char *new;
+	int len = strlen(s) + 1;
+	int err;
+
+	p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+	if (p)
+		/* found it */
+		return (p - strtab);
+
+	new = strtab + fdt_size_dt_strings(fdt);
+	err = _fdt_splice_string(fdt, len);
+	if (err)
+		return err;
+
+	memcpy(new, s, len);
+	return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+	struct fdt_reserve_entry *re;
+	int err;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
+	err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
+	if (err)
+		return err;
+
+	re->address = cpu_to_fdt64(address);
+	re->size = cpu_to_fdt64(size);
+	return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+	struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	if (n >= fdt_num_mem_rsv(fdt))
+		return -FDT_ERR_NOTFOUND;
+
+	return _fdt_splice_mem_rsv(fdt, re, 1, 0);
+}
+
+static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+				int len, struct fdt_property **prop)
+{
+	int oldlen;
+	int err;
+
+	*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+	if (! (*prop))
+		return oldlen;
+
+	if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+				      FDT_TAGALIGN(len))))
+		return err;
+
+	(*prop)->len = cpu_to_fdt32(len);
+	return 0;
+}
+
+static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
+			     int len, struct fdt_property **prop)
+{
+	int proplen;
+	int nextoffset;
+	int namestroff;
+	int err;
+
+	if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+		return nextoffset;
+
+	namestroff = _fdt_find_add_string(fdt, name);
+	if (namestroff < 0)
+		return namestroff;
+
+	*prop = _fdt_offset_ptr_w(fdt, nextoffset);
+	proplen = sizeof(**prop) + FDT_TAGALIGN(len);
+
+	err = _fdt_splice_struct(fdt, *prop, 0, proplen);
+	if (err)
+		return err;
+
+	(*prop)->tag = cpu_to_fdt32(FDT_PROP);
+	(*prop)->nameoff = cpu_to_fdt32(namestroff);
+	(*prop)->len = cpu_to_fdt32(len);
+	return 0;
+}
+
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+	char *namep;
+	int oldlen, newlen;
+	int err;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
+	if (!namep)
+		return oldlen;
+
+	newlen = strlen(name);
+
+	err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+				 FDT_TAGALIGN(newlen+1));
+	if (err)
+		return err;
+
+	memcpy(namep, name, newlen+1);
+	return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len)
+{
+	struct fdt_property *prop;
+	int err;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
+	if (err == -FDT_ERR_NOTFOUND)
+		err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+	if (err)
+		return err;
+
+	if (len)
+		memcpy(prop->data, val, len);
+	return 0;
+}
+
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+		   const void *val, int len)
+{
+	struct fdt_property *prop;
+	int err, oldlen, newlen;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+	if (prop) {
+		newlen = len + oldlen;
+		err = _fdt_splice_struct(fdt, prop->data,
+					 FDT_TAGALIGN(oldlen),
+					 FDT_TAGALIGN(newlen));
+		if (err)
+			return err;
+		prop->len = cpu_to_fdt32(newlen);
+		memcpy(prop->data + oldlen, val, len);
+	} else {
+		err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+		if (err)
+			return err;
+		memcpy(prop->data, val, len);
+	}
+	return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+	struct fdt_property *prop;
+	int len, proplen;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+	if (! prop)
+		return len;
+
+	proplen = sizeof(*prop) + FDT_TAGALIGN(len);
+	return _fdt_splice_struct(fdt, prop, proplen, 0);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+			    const char *name, int namelen)
+{
+	struct fdt_node_header *nh;
+	int offset, nextoffset;
+	int nodelen;
+	int err;
+	uint32_t tag;
+	fdt32_t *endtag;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+	if (offset >= 0)
+		return -FDT_ERR_EXISTS;
+	else if (offset != -FDT_ERR_NOTFOUND)
+		return offset;
+
+	/* Try to place the new node after the parent's properties */
+	fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+	} while ((tag == FDT_PROP) || (tag == FDT_NOP));
+
+	nh = _fdt_offset_ptr_w(fdt, offset);
+	nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
+
+	err = _fdt_splice_struct(fdt, nh, 0, nodelen);
+	if (err)
+		return err;
+
+	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+	memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
+	memcpy(nh->name, name, namelen);
+	endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
+	*endtag = cpu_to_fdt32(FDT_END_NODE);
+
+	return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+	return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+	int endoffset;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	if (endoffset < 0)
+		return endoffset;
+
+	return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+				  endoffset - nodeoffset, 0);
+}
+
+static void _fdt_packblocks(const char *old, char *new,
+			    int mem_rsv_size, int struct_size)
+{
+	int mem_rsv_off, struct_off, strings_off;
+
+	mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
+	struct_off = mem_rsv_off + mem_rsv_size;
+	strings_off = struct_off + struct_size;
+
+	memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
+	fdt_set_off_mem_rsvmap(new, mem_rsv_off);
+
+	memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
+	fdt_set_off_dt_struct(new, struct_off);
+	fdt_set_size_dt_struct(new, struct_size);
+
+	memmove(new + strings_off, old + fdt_off_dt_strings(old),
+		fdt_size_dt_strings(old));
+	fdt_set_off_dt_strings(new, strings_off);
+	fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+	int err;
+	int mem_rsv_size, struct_size;
+	int newsize;
+	const char *fdtstart = fdt;
+	const char *fdtend = fdtstart + fdt_totalsize(fdt);
+	char *tmp;
+
+	FDT_CHECK_HEADER(fdt);
+
+	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+		* sizeof(struct fdt_reserve_entry);
+
+	if (fdt_version(fdt) >= 17) {
+		struct_size = fdt_size_dt_struct(fdt);
+	} else {
+		struct_size = 0;
+		while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+			;
+		if (struct_size < 0)
+			return struct_size;
+	}
+
+	if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+		/* no further work necessary */
+		err = fdt_move(fdt, buf, bufsize);
+		if (err)
+			return err;
+		fdt_set_version(buf, 17);
+		fdt_set_size_dt_struct(buf, struct_size);
+		fdt_set_totalsize(buf, bufsize);
+		return 0;
+	}
+
+	/* Need to reorder */
+	newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+		+ struct_size + fdt_size_dt_strings(fdt);
+
+	if (bufsize < newsize)
+		return -FDT_ERR_NOSPACE;
+
+	/* First attempt to build converted tree at beginning of buffer */
+	tmp = buf;
+	/* But if that overlaps with the old tree... */
+	if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
+		/* Try right after the old tree instead */
+		tmp = (char *)(uintptr_t)fdtend;
+		if ((tmp + newsize) > ((char *)buf + bufsize))
+			return -FDT_ERR_NOSPACE;
+	}
+
+	_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+	memmove(buf, tmp, newsize);
+
+	fdt_set_magic(buf, FDT_MAGIC);
+	fdt_set_totalsize(buf, bufsize);
+	fdt_set_version(buf, 17);
+	fdt_set_last_comp_version(buf, 16);
+	fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+	return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+	int mem_rsv_size;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+		* sizeof(struct fdt_reserve_entry);
+	_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+	fdt_set_totalsize(fdt, _fdt_data_size(fdt));
+
+	return 0;
+}

+ 100 - 0
components/drivers/fdt/libfdt/fdt_strerror.c

@@ -0,0 +1,100 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+struct fdt_errtabent {
+	const char *str;
+};
+
+#define FDT_ERRTABENT(val) \
+	[(val)] = { .str = #val, }
+
+static struct fdt_errtabent fdt_errtable[] = {
+	FDT_ERRTABENT(FDT_ERR_NOTFOUND),
+	FDT_ERRTABENT(FDT_ERR_EXISTS),
+	FDT_ERRTABENT(FDT_ERR_NOSPACE),
+
+	FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+	FDT_ERRTABENT(FDT_ERR_BADPATH),
+	FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
+	FDT_ERRTABENT(FDT_ERR_BADSTATE),
+
+	FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+	FDT_ERRTABENT(FDT_ERR_BADMAGIC),
+	FDT_ERRTABENT(FDT_ERR_BADVERSION),
+	FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+	FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
+	FDT_ERRTABENT(FDT_ERR_INTERNAL),
+	FDT_ERRTABENT(FDT_ERR_BADNCELLS),
+	FDT_ERRTABENT(FDT_ERR_BADVALUE),
+	FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
+	FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
+};
+#define FDT_ERRTABSIZE	(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+	if (errval > 0)
+		return "<valid offset/length>";
+	else if (errval == 0)
+		return "<no error>";
+	else if (errval > -FDT_ERRTABSIZE) {
+		const char *s = fdt_errtable[-errval].str;
+
+		if (s)
+			return s;
+	}
+
+	return "<unknown error>";
+}

+ 286 - 0
components/drivers/fdt/libfdt/fdt_sw.c

@@ -0,0 +1,286 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+static int _fdt_sw_check_header(void *fdt)
+{
+	if (fdt_magic(fdt) != FDT_SW_MAGIC)
+		return -FDT_ERR_BADMAGIC;
+	/* FIXME: should check more details about the header state */
+	return 0;
+}
+
+#define FDT_SW_CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = _fdt_sw_check_header(fdt)) != 0) \
+			return err; \
+	}
+
+static void *_fdt_grab_space(void *fdt, size_t len)
+{
+	int offset = fdt_size_dt_struct(fdt);
+	int spaceleft;
+
+	spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+		- fdt_size_dt_strings(fdt);
+
+	if ((offset + len < offset) || (offset + len > spaceleft))
+		return NULL;
+
+	fdt_set_size_dt_struct(fdt, offset + len);
+	return _fdt_offset_ptr_w(fdt, offset);
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+	void *fdt = buf;
+
+	if (bufsize < sizeof(struct fdt_header))
+		return -FDT_ERR_NOSPACE;
+
+	memset(buf, 0, bufsize);
+
+	fdt_set_magic(fdt, FDT_SW_MAGIC);
+	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+	fdt_set_totalsize(fdt,  bufsize);
+
+	fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
+					      sizeof(struct fdt_reserve_entry)));
+	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+	fdt_set_off_dt_strings(fdt, bufsize);
+
+	return 0;
+}
+
+int fdt_resize(void *fdt, void *buf, int bufsize)
+{
+	size_t headsize, tailsize;
+	char *oldtail, *newtail;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	headsize = fdt_off_dt_struct(fdt);
+	tailsize = fdt_size_dt_strings(fdt);
+
+	if ((headsize + tailsize) > bufsize)
+		return -FDT_ERR_NOSPACE;
+
+	oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
+	newtail = (char *)buf + bufsize - tailsize;
+
+	/* Two cases to avoid clobbering data if the old and new
+	 * buffers partially overlap */
+	if (buf <= fdt) {
+		memmove(buf, fdt, headsize);
+		memmove(newtail, oldtail, tailsize);
+	} else {
+		memmove(newtail, oldtail, tailsize);
+		memmove(buf, fdt, headsize);
+	}
+
+	fdt_set_off_dt_strings(buf, bufsize);
+	fdt_set_totalsize(buf, bufsize);
+
+	return 0;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+	struct fdt_reserve_entry *re;
+	int offset;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	if (fdt_size_dt_struct(fdt))
+		return -FDT_ERR_BADSTATE;
+
+	offset = fdt_off_dt_struct(fdt);
+	if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+		return -FDT_ERR_NOSPACE;
+
+	re = (struct fdt_reserve_entry *)((char *)fdt + offset);
+	re->address = cpu_to_fdt64(addr);
+	re->size = cpu_to_fdt64(size);
+
+	fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+	return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+	return fdt_add_reservemap_entry(fdt, 0, 0);
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+	struct fdt_node_header *nh;
+	int namelen = strlen(name) + 1;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
+	if (! nh)
+		return -FDT_ERR_NOSPACE;
+
+	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+	memcpy(nh->name, name, namelen);
+	return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+	fdt32_t *en;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	en = _fdt_grab_space(fdt, FDT_TAGSIZE);
+	if (! en)
+		return -FDT_ERR_NOSPACE;
+
+	*en = cpu_to_fdt32(FDT_END_NODE);
+	return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+	char *strtab = (char *)fdt + fdt_totalsize(fdt);
+	const char *p;
+	int strtabsize = fdt_size_dt_strings(fdt);
+	int len = strlen(s) + 1;
+	int struct_top, offset;
+
+	p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
+	if (p)
+		return p - strtab;
+
+	/* Add it */
+	offset = -strtabsize - len;
+	struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+	if (fdt_totalsize(fdt) + offset < struct_top)
+		return 0; /* no more room :( */
+
+	memcpy(strtab + offset, s, len);
+	fdt_set_size_dt_strings(fdt, strtabsize + len);
+	return offset;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+	struct fdt_property *prop;
+	int nameoff;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	nameoff = _fdt_find_add_string(fdt, name);
+	if (nameoff == 0)
+		return -FDT_ERR_NOSPACE;
+
+	prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+	if (! prop)
+		return -FDT_ERR_NOSPACE;
+
+	prop->tag = cpu_to_fdt32(FDT_PROP);
+	prop->nameoff = cpu_to_fdt32(nameoff);
+	prop->len = cpu_to_fdt32(len);
+	memcpy(prop->data, val, len);
+	return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+	char *p = (char *)fdt;
+	fdt32_t *end;
+	int oldstroffset, newstroffset;
+	uint32_t tag;
+	int offset, nextoffset;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	/* Add terminator */
+	end = _fdt_grab_space(fdt, sizeof(*end));
+	if (! end)
+		return -FDT_ERR_NOSPACE;
+	*end = cpu_to_fdt32(FDT_END);
+
+	/* Relocate the string table */
+	oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+	newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+	memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+	fdt_set_off_dt_strings(fdt, newstroffset);
+
+	/* Walk the structure, correcting string offsets */
+	offset = 0;
+	while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+		if (tag == FDT_PROP) {
+			struct fdt_property *prop =
+				_fdt_offset_ptr_w(fdt, offset);
+			int nameoff;
+
+			nameoff = fdt32_to_cpu(prop->nameoff);
+			nameoff += fdt_size_dt_strings(fdt);
+			prop->nameoff = cpu_to_fdt32(nameoff);
+		}
+		offset = nextoffset;
+	}
+	if (nextoffset < 0)
+		return nextoffset;
+
+	/* Finally, adjust the header */
+	fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+	fdt_set_magic(fdt, FDT_MAGIC);
+	return 0;
+}

+ 137 - 0
components/drivers/fdt/libfdt/fdt_wip.c

@@ -0,0 +1,137 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
+					const char *name, int namelen,
+					uint32_t idx, const void *val,
+					int len)
+{
+	void *propval;
+	int proplen;
+
+	propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
+					&proplen);
+	if (!propval)
+		return proplen;
+
+	if (proplen < (len + idx))
+		return -FDT_ERR_NOSPACE;
+
+	memcpy((char *)propval + idx, val, len);
+	return 0;
+}
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+			const void *val, int len)
+{
+	const void *propval;
+	int proplen;
+
+	propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
+	if (! propval)
+		return proplen;
+
+	if (proplen != len)
+		return -FDT_ERR_NOSPACE;
+
+	return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
+						   strlen(name), 0,
+						   val, len);
+}
+
+static void _fdt_nop_region(void *start, int len)
+{
+	fdt32_t *p;
+
+	for (p = start; (char *)p < ((char *)start + len); p++)
+		*p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+	struct fdt_property *prop;
+	int len;
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+	if (! prop)
+		return len;
+
+	_fdt_nop_region(prop, len + sizeof(*prop));
+
+	return 0;
+}
+
+int _fdt_node_end_offset(void *fdt, int offset)
+{
+	int depth = 0;
+
+	while ((offset >= 0) && (depth >= 0))
+		offset = fdt_next_node(fdt, offset, &depth);
+
+	return offset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+	int endoffset;
+
+	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	if (endoffset < 0)
+		return endoffset;
+
+	_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+			endoffset - nodeoffset);
+	return 0;
+}

+ 1876 - 0
components/drivers/fdt/libfdt/libfdt.h

@@ -0,0 +1,1876 @@
+#ifndef _LIBFDT_H
+#define _LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "libfdt_env.h"
+#include "fdt.h"
+
+#define FDT_FIRST_SUPPORTED_VERSION	0x10
+#define FDT_LAST_SUPPORTED_VERSION	0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND	1
+	/* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS		2
+	/* FDT_ERR_EXISTS: Attempted to create a node or property which
+	 * already exists */
+#define FDT_ERR_NOSPACE		3
+	/* FDT_ERR_NOSPACE: Operation needed to expand the device
+	 * tree, but its buffer did not have sufficient space to
+	 * contain the expanded tree. Use fdt_open_into() to move the
+	 * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET	4
+	/* FDT_ERR_BADOFFSET: Function was passed a structure block
+	 * offset which is out-of-bounds, or which points to an
+	 * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH		5
+	/* FDT_ERR_BADPATH: Function was passed a badly formatted path
+	 * (e.g. missing a leading / for a function which requires an
+	 * absolute path) */
+#define FDT_ERR_BADPHANDLE	6
+	/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle.
+	 * This can be caused either by an invalid phandle property
+	 * length, or the phandle value was either 0 or -1, which are
+	 * not permitted. */
+#define FDT_ERR_BADSTATE	7
+	/* FDT_ERR_BADSTATE: Function was passed an incomplete device
+	 * tree created by the sequential-write functions, which is
+	 * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED	8
+	/* FDT_ERR_TRUNCATED: Structure block of the given device tree
+	 * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC	9
+	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+	 * device tree at all - it is missing the flattened device
+	 * tree magic number. */
+#define FDT_ERR_BADVERSION	10
+	/* FDT_ERR_BADVERSION: Given device tree has a version which
+	 * can't be handled by the requested operation.  For
+	 * read-write functions, this may mean that fdt_open_into() is
+	 * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE	11
+	/* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+	 * structure block or other serious error (e.g. misnested
+	 * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT	12
+	/* FDT_ERR_BADLAYOUT: For read-write functions, the given
+	 * device tree has it's sub-blocks in an order that the
+	 * function can't handle (memory reserve map, then structure,
+	 * then strings).  Use fdt_open_into() to reorganize the tree
+	 * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL	13
+	/* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+	 * Should never be returned, if it is, it indicates a bug in
+	 * libfdt itself. */
+
+/* Errors in device tree content */
+#define FDT_ERR_BADNCELLS	14
+	/* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells
+	 * or similar property with a bad format or value */
+
+#define FDT_ERR_BADVALUE	15
+	/* FDT_ERR_BADVALUE: Device tree has a property with an unexpected
+	 * value. For example: a property expected to contain a string list
+	 * is not NUL-terminated within the length of its value. */
+
+#define FDT_ERR_BADOVERLAY	16
+	/* FDT_ERR_BADOVERLAY: The device tree overlay, while
+	 * correctly structured, cannot be applied due to some
+	 * unexpected or missing value, property or node. */
+
+#define FDT_ERR_NOPHANDLES	17
+	/* FDT_ERR_NOPHANDLES: The device tree doesn't have any
+	 * phandle available anymore without causing an overflow */
+
+#define FDT_ERR_MAX		17
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these)                */
+/**********************************************************************/
+
+#ifndef SWIG /* This function is not useful in Python */
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
+#endif
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+	return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+static inline void fdt32_st(void *property, uint32_t value)
+{
+    uint8_t *bp = (uint8_t *)property;
+
+    bp[0] = value >> 24;
+    bp[1] = (value >> 16) & 0xff;
+    bp[2] = (value >> 8) & 0xff;
+    bp[3] = value & 0xff;
+}
+
+static inline void fdt64_st(void *property, uint64_t value)
+{
+    uint8_t *bp = (uint8_t *)property;
+
+    bp[0] = value >> 56;
+    bp[1] = (value >> 48) & 0xff;
+    bp[2] = (value >> 40) & 0xff;
+    bp[3] = (value >> 32) & 0xff;
+    bp[4] = (value >> 24) & 0xff;
+    bp[5] = (value >> 16) & 0xff;
+    bp[6] = (value >> 8) & 0xff;
+    bp[7] = value & 0xff;
+}
+
+/**********************************************************************/
+/* Traversal functions                                                */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**
+ * fdt_first_subnode() - get offset of first direct subnode
+ *
+ * @fdt:	FDT blob
+ * @offset:	Offset of node to check
+ * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
+ */
+int fdt_first_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_next_subnode() - get offset of next direct subnode
+ *
+ * After first calling fdt_first_subnode(), call this function repeatedly to
+ * get direct subnodes of a parent node.
+ *
+ * @fdt:	FDT blob
+ * @offset:	Offset of previous subnode
+ * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
+ * subnodes
+ */
+int fdt_next_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_for_each_subnode - iterate over all subnodes of a parent
+ *
+ * @node:	child node (int, lvalue)
+ * @fdt:	FDT blob (const void *)
+ * @parent:	parent node (int)
+ *
+ * This is actually a wrapper around a for loop and would be used like so:
+ *
+ *	fdt_for_each_subnode(node, fdt, parent) {
+ *		Use node
+ *		...
+ *	}
+ *
+ *	if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
+ *		Error handling
+ *	}
+ *
+ * Note that this is implemented as a macro and @node is used as
+ * iterator in the loop. The parent variable be constant or even a
+ * literal.
+ *
+ */
+#define fdt_for_each_subnode(node, fdt, parent)		\
+	for (node = fdt_first_subnode(fdt, parent);	\
+	     node >= 0;					\
+	     node = fdt_next_subnode(fdt, node))
+
+/**********************************************************************/
+/* General functions                                                  */
+/**********************************************************************/
+#define fdt_get_header(fdt, field) \
+	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt)			(fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt)		(fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt)		(fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt)		(fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt)	(fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt)	(fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt)	(fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct))
+
+#define __fdt_set_hdr(name) \
+	static inline void fdt_set_##name(void *fdt, uint32_t val) \
+	{ \
+		struct fdt_header *fdth = (struct fdt_header *)fdt; \
+		fdth->name = cpu_to_fdt32(val); \
+	}
+__fdt_set_hdr(magic);
+__fdt_set_hdr(totalsize);
+__fdt_set_hdr(off_dt_struct);
+__fdt_set_hdr(off_dt_strings);
+__fdt_set_hdr(off_mem_rsvmap);
+__fdt_set_hdr(version);
+__fdt_set_hdr(last_comp_version);
+__fdt_set_hdr(boot_cpuid_phys);
+__fdt_set_hdr(size_dt_strings);
+__fdt_set_hdr(size_dt_struct);
+#undef __fdt_set_hdr
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ *     0, if the buffer appears to contain a valid device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize.  The buffer may overlap
+ * with the existing device tree blob at fdt.  Therefore,
+ *     fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions                                                */
+/**********************************************************************/
+
+/**
+ * fdt_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ *     a pointer to the string, on success
+ *     NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_get_max_phandle - retrieves the highest phandle in a tree
+ * @fdt: pointer to the device tree blob
+ *
+ * fdt_get_max_phandle retrieves the highest phandle in the given
+ * device tree. This will ignore badly formatted phandles, or phandles
+ * with a value of 0 or -1.
+ *
+ * returns:
+ *      the highest phandle on success
+ *      0, if no phandle was found in the device tree
+ *      -1, if an error occurred
+ */
+uint32_t fdt_get_max_phandle(const void *fdt);
+
+/**
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map.  This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ *     the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name.  This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+			       const char *name, int namelen);
+#endif
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name.  name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ *	structure block offset of the requested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ *		tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset_namelen - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ * @namelen: number of characters of path to consider
+ *
+ * Identical to fdt_path_offset(), but only consider the first namelen
+ * characters of path as the path name.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
+#endif
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ *	structure block offset of the node with the requested path (>=0), on
+ *		success
+ *	-FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ *	-FDT_ERR_NOTFOUND, if the requested node does not exist
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retrieve the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset.  If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the node's name, on success
+ *		If lenp is non-NULL, *lenp contains the length of that name
+ *			(>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *			tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_first_property_offset - find the offset of a node's first property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ *
+ * fdt_first_property_offset() finds the first property of the node at
+ * the given structure block offset.
+ *
+ * returns:
+ *	structure block offset of the property (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested node has no properties
+ *	-FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_first_property_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_next_property_offset - step through a node's properties
+ * @fdt: pointer to the device tree blob
+ * @offset: structure block offset of a property
+ *
+ * fdt_next_property_offset() finds the property immediately after the
+ * one at the given structure block offset.  This will be a property
+ * of the same node as the given property.
+ *
+ * returns:
+ *	structure block offset of the next property (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the given property is the last in its node
+ *	-FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_next_property_offset(const void *fdt, int offset);
+
+/**
+ * fdt_for_each_property_offset - iterate over all properties of a node
+ *
+ * @property_offset:	property offset (int, lvalue)
+ * @fdt:		FDT blob (const void *)
+ * @node:		node offset (int)
+ *
+ * This is actually a wrapper around a for loop and would be used like so:
+ *
+ *	fdt_for_each_property_offset(property, fdt, node) {
+ *		Use property
+ *		...
+ *	}
+ *
+ *	if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
+ *		Error handling
+ *	}
+ *
+ * Note that this is implemented as a macro and property is used as
+ * iterator in the loop. The node variable can be constant or even a
+ * literal.
+ */
+#define fdt_for_each_property_offset(property, fdt, node)	\
+	for (property = fdt_first_property_offset(fdt, node);	\
+	     property >= 0;					\
+	     property = fdt_next_property_offset(fdt, property))
+
+/**
+ * fdt_get_property_by_offset - retrieve the property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @offset: offset of the property to retrieve
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property_by_offset() retrieves a pointer to the
+ * fdt_property structure within the device tree blob at the given
+ * offset.  If lenp is non-NULL, the length of the property value is
+ * also returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the structure representing the property
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+						      int offset,
+						      int *lenp);
+
+/**
+ * fdt_get_property_namelen - find a property based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_get_property(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+#ifndef SWIG /* Not available in Python */
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+						    int nodeoffset,
+						    const char *name,
+						    int namelen, int *lenp);
+#endif
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset.  If lenp is
+ * non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the structure representing the property
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *			tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+					    const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+						      const char *name,
+						      int *lenp)
+{
+	return (struct fdt_property *)(uintptr_t)
+		fdt_get_property(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_getprop_by_offset - retrieve the value of a property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @ffset: offset of the property to read
+ * @namep: pointer to a string variable (will be overwritten) or NULL
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop_by_offset() retrieves a pointer to the value of the
+ * property at structure block offset 'offset' (this will be a pointer
+ * to within the device blob itself, not a copy of the value).  If
+ * lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.  If namep is non-NULL,
+ * the property's namne will also be returned in the char * pointed to
+ * by namep (this will be a pointer to within the device tree's string
+ * block, not a new copy of the name).
+ *
+ * returns:
+ *	pointer to the property's value
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *		if namep is non-NULL *namep contiains a pointer to the property
+ *		name.
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+#ifndef SWIG /* This function is not useful in Python */
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+				  const char **namep, int *lenp);
+#endif
+
+/**
+ * fdt_getprop_namelen - get property value based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_getprop(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+#ifndef SWIG /* Not available in Python */
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+				const char *name, int namelen, int *lenp);
+static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
+					  const char *name, int namelen,
+					  int *lenp)
+{
+	return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name,
+						      namelen, lenp);
+}
+#endif
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the property's value
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *			tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+			const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+				  const char *name, int *lenp)
+{
+	return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retrieve the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ *	the phandle of the node at nodeoffset, on success (!= 0, != -1)
+ *	0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_alias_namelen - get alias based on substring
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_get_alias(), but only examine the first namelen
+ * characters of name for matching the alias name.
+ */
+#ifndef SWIG /* Not available in Python */
+const char *fdt_get_alias_namelen(const void *fdt,
+				  const char *name, int namelen);
+#endif
+
+/**
+ * fdt_get_alias - retrieve the path referenced by a given alias
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ *
+ * fdt_get_alias() retrieves the value of a given alias.  That is, the
+ * value of the property named 'name' in the node /aliases.
+ *
+ * returns:
+ *	a pointer to the expansion of the alias named 'name', if it exists
+ *	NULL, if the given alias or the /aliases node does not exist
+ */
+const char *fdt_get_alias(const void *fdt, const char *name);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	0, on success
+ *		buf contains the absolute path of the node at
+ *		nodeoffset, as a NUL-terminated string.
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ *		characters and will not fit in the given buffer.
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth).  So
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node.  If the node at
+ * nodeoffset has depth D, then:
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	structure block offset of the node at node offset's ancestor
+ *		of depth supernodedepth (>=0), on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of
+ *		nodeoffset
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node.  The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	depth of the node at nodeoffset (>=0), on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ *	structure block offset of the parent of the node at nodeoffset
+ *		(>=0), on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ *					       propval, proplen);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ *						       propval, proplen);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+				  const char *propname,
+				  const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_phandle() returns the offset of the node
+ * which has the given phandle value.  If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0), on success
+ *	-FDT_ERR_NOTFOUND, no node with that phandle exists
+ *	-FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ *	0, if the node has a 'compatible' property listing the given string
+ *	1, if the node has a 'compatible' property, but it does not list
+ *		the given string
+ *	-FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ *	-FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+			      const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+				  const char *compatible);
+
+/**
+ * fdt_stringlist_contains - check a string list property for a string
+ * @strlist: Property containing a list of strings to check
+ * @listlen: Length of property
+ * @str: String to search for
+ *
+ * This is a utility function provided for convenience. The list contains
+ * one or more strings, each terminated by \0, as is found in a device tree
+ * "compatible" property.
+ *
+ * @return: 1 if the string is found in the list, 0 not found, or invalid list
+ */
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
+
+/**
+ * fdt_stringlist_count - count the number of strings in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @return:
+ *   the number of strings in the given property
+ *   -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *   -FDT_ERR_NOTFOUND if the property does not exist
+ */
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property);
+
+/**
+ * fdt_stringlist_search - find a string in a string list and return its index
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @string: string to look up in the string list
+ *
+ * Note that it is possible for this function to succeed on property values
+ * that are not NUL-terminated. That's because the function will stop after
+ * finding the first occurrence of @string. This can for example happen with
+ * small-valued cell properties, such as #address-cells, when searching for
+ * the empty string.
+ *
+ * @return:
+ *   the index of the string in the list of strings
+ *   -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *   -FDT_ERR_NOTFOUND if the property does not exist or does not contain
+ *                     the given string
+ */
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+			  const char *string);
+
+/**
+ * fdt_stringlist_get() - obtain the string at a given index in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @index: index of the string to return
+ * @lenp: return location for the string length or an error code on failure
+ *
+ * Note that this will successfully extract strings from properties with
+ * non-NUL-terminated values. For example on small-valued cell properties
+ * this function will return the empty string.
+ *
+ * If non-NULL, the length of the string (on success) or a negative error-code
+ * (on failure) will be stored in the integer pointer to by lenp.
+ *
+ * @return:
+ *   A pointer to the string at the given index in the string list or NULL on
+ *   failure. On success the length of the string will be stored in the memory
+ *   location pointed to by the lenp parameter, if non-NULL. On failure one of
+ *   the following negative error codes will be returned in the lenp parameter
+ *   (if non-NULL):
+ *     -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *     -FDT_ERR_NOTFOUND if the property does not exist
+ */
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+			       const char *property, int index,
+			       int *lenp);
+
+/**********************************************************************/
+/* Read-only functions (addressing related)                           */
+/**********************************************************************/
+
+/**
+ * FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells
+ *
+ * This is the maximum value for #address-cells, #size-cells and
+ * similar properties that will be processed by libfdt.  IEE1275
+ * requires that OF implementations handle values up to 4.
+ * Implementations may support larger values, but in practice higher
+ * values aren't used.
+ */
+#define FDT_MAX_NCELLS		4
+
+/**
+ * fdt_address_cells - retrieve address size for a bus represented in the tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address size for
+ *
+ * When the node has a valid #address-cells property, returns its value.
+ *
+ * returns:
+ *	0 <= n < FDT_MAX_NCELLS, on success
+ *      2, if the node has no #address-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *		#address-cells property
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_address_cells(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_size_cells - retrieve address range size for a bus represented in the
+ *                  tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address range size for
+ *
+ * When the node has a valid #size-cells property, returns its value.
+ *
+ * returns:
+ *	0 <= n < FDT_MAX_NCELLS, on success
+ *      2, if the node has no #address-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *		#size-cells property
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_size_cells(const void *fdt, int nodeoffset);
+
+
+/**********************************************************************/
+/* Write-in-place functions                                           */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace_namelen_partial - change a property's value,
+ *                                       but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @namelen: number of characters of name to consider
+ * @idx: index of the property to change in the array
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * Identical to fdt_setprop_inplace(), but modifies the given property
+ * starting from the given index, and using only the first characters
+ * of the name. It is useful when you want to manipulate only one value of
+ * an array and you have a string that doesn't end with \0.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
+					const char *name, int namelen,
+					uint32_t idx, const void *val,
+					int len);
+#endif
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len.  This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+			const void *val, int len);
+#endif
+
+/**
+ * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u32() replaces the value of a given property
+ * with the 32-bit integer value in val, converting val to big-endian
+ * if necessary.  This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if the property's length is not equal to 4
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset,
+					  const char *name, uint32_t val)
+{
+	fdt32_t tmp = cpu_to_fdt32(val);
+	return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u64() replaces the value of a given property
+ * with the 64-bit integer value in val, converting val to big-endian
+ * if necessary.  This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 8.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if the property's length is not equal to 8
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset,
+					  const char *name, uint64_t val)
+{
+	fdt64_t tmp = cpu_to_fdt64(val);
+	return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ *
+ * This is an alternative name for fdt_setprop_inplace_u32()
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+					   const char *name, uint32_t val)
+{
+	return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions                                         */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_resize(void *fdt, void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val)
+{
+	fdt32_t tmp = cpu_to_fdt32(val);
+	return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
+{
+	fdt64_t tmp = cpu_to_fdt64(val);
+	return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+	return fdt_property_u32(fdt, name, val);
+}
+#define fdt_property_string(fdt, name, str) \
+	fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions                                               */
+/**********************************************************************/
+
+int fdt_create_empty_tree(void *buf, int bufsize);
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new reservation entry
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ *		are less than n+1 reserve map entries)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string.  NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ *		to contain the new name
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len);
+
+/**
+ * fdt_setprop_u32 - set a property to a 32-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u32() sets the value of the named property in the given
+ * node to the given 32-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name,
+				  uint32_t val)
+{
+	fdt32_t tmp = cpu_to_fdt32(val);
+	return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_u64 - set a property to a 64-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u64() sets the value of the named property in the given
+ * node to the given 64-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name,
+				  uint64_t val)
+{
+	fdt64_t tmp = cpu_to_fdt64(val);
+	return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ *
+ * This is an alternative name for fdt_setprop_u32()
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+				   uint32_t val)
+{
+	return fdt_setprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+	fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+
+/**
+ * fdt_setprop_empty - set a property to an empty value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ *
+ * fdt_setprop_empty() sets the value of the named property in the
+ * given node to an empty (zero length) value, or creates a new empty
+ * property if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_empty(fdt, nodeoffset, name) \
+	fdt_setprop((fdt), (nodeoffset), (name), NULL, 0)
+
+/**
+ * fdt_appendprop - append to or create a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to append to
+ * @val: pointer to data to append to the property value
+ * @len: length of the data to append to the property value
+ *
+ * fdt_appendprop() appends the value to the named property in the
+ * given node, creating the property if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+		   const void *val, int len);
+
+/**
+ * fdt_appendprop_u32 - append a 32-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u32() appends the given 32-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u32(void *fdt, int nodeoffset,
+				     const char *name, uint32_t val)
+{
+	fdt32_t tmp = cpu_to_fdt32(val);
+	return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_u64 - append a 64-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u64() appends the given 64-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u64(void *fdt, int nodeoffset,
+				     const char *name, uint64_t val)
+{
+	fdt64_t tmp = cpu_to_fdt64(val);
+	return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_cell - append a single cell value to a property
+ *
+ * This is an alternative name for fdt_appendprop_u32()
+ */
+static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
+				      const char *name, uint32_t val)
+{
+	return fdt_appendprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_appendprop_string - append a string to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value to append to the property
+ *
+ * fdt_appendprop_string() appends the given string to the value of
+ * the named property in the given node, or creates a new property
+ * with that value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_appendprop_string(fdt, nodeoffset, name, str) \
+	fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node.  This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+			    const char *name, int namelen);
+#endif
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ *	structure block offset of the created nodeequested subnode (>=0), on
+ *		success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ *		tag
+ *	-FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ *		the given name
+ *	-FDT_ERR_NOSPACE, if there is insufficient free space in the
+ *		blob to contain the new node
+ *	-FDT_ERR_NOSPACE
+ *	-FDT_ERR_BADLAYOUT
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**
+ * fdt_overlay_apply - Applies a DT overlay on a base DT
+ * @fdt: pointer to the base device tree blob
+ * @fdto: pointer to the device tree overlay blob
+ *
+ * fdt_overlay_apply() will apply the given device tree overlay on the
+ * given base device tree.
+ *
+ * Expect the base device tree to be modified, even if the function
+ * returns an error.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there's not enough space in the base device tree
+ *	-FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or
+ *		properties in the base DT
+ *	-FDT_ERR_BADPHANDLE,
+ *	-FDT_ERR_BADOVERLAY,
+ *	-FDT_ERR_NOPHANDLES,
+ *	-FDT_ERR_INTERNAL,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADOFFSET,
+ *	-FDT_ERR_BADPATH,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_overlay_apply(void *fdt, void *fdto);
+
+/**********************************************************************/
+/* Debugging / informational functions                                */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* _LIBFDT_H */

+ 113 - 0
components/drivers/fdt/libfdt/libfdt_env.h

@@ -0,0 +1,113 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * Copyright 2012 Kim Phillips, Freescale Semiconductor.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __CHECKER__
+#define FDT_FORCE __attribute__((force))
+#define FDT_BITWISE __attribute__((bitwise))
+#else
+#define FDT_FORCE
+#define FDT_BITWISE
+#endif
+
+typedef uint16_t FDT_BITWISE fdt16_t;
+typedef uint32_t FDT_BITWISE fdt32_t;
+typedef uint64_t FDT_BITWISE fdt64_t;
+typedef uint64_t unaligned_fdt64_t __attribute__((aligned(4)));
+
+#define EXTRACT_BYTE(x, n)	((unsigned long long)((uint8_t *)&x)[n])
+#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
+#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
+			 (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
+#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
+			 (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
+			 (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
+			 (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
+
+static inline uint16_t fdt16_to_cpu(fdt16_t x)
+{
+	return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
+}
+static inline fdt16_t cpu_to_fdt16(uint16_t x)
+{
+	return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
+}
+
+static inline uint32_t fdt32_to_cpu(fdt32_t x)
+{
+	return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
+}
+static inline fdt32_t cpu_to_fdt32(uint32_t x)
+{
+	return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
+}
+
+static inline uint64_t fdt64_to_cpu(fdt64_t x)
+{
+	return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
+}
+static inline fdt64_t cpu_to_fdt64(uint64_t x)
+{
+	return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
+}
+#undef CPU_TO_FDT64
+#undef CPU_TO_FDT32
+#undef CPU_TO_FDT16
+#undef EXTRACT_BYTE
+
+#endif /* _LIBFDT_ENV_H */

+ 95 - 0
components/drivers/fdt/libfdt/libfdt_internal.h

@@ -0,0 +1,95 @@
+#ifndef _LIBFDT_INTERNAL_H
+#define _LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "fdt.h"
+
+#define FDT_ALIGN(x, a)		(((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x)		(FDT_ALIGN((x), FDT_TAGSIZE))
+
+#define FDT_CHECK_HEADER(fdt) \
+	{ \
+		int __err; \
+		if ((__err = fdt_check_header(fdt)) != 0) \
+			return __err; \
+	}
+
+int _fdt_check_node_offset(const void *fdt, int offset);
+int _fdt_check_prop_offset(const void *fdt, int offset);
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
+int _fdt_node_end_offset(void *fdt, int nodeoffset);
+
+static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
+{
+	return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
+{
+	return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
+}
+
+static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
+{
+	const struct fdt_reserve_entry *rsv_table =
+		(const struct fdt_reserve_entry *)
+		((const char *)fdt + fdt_off_mem_rsvmap(fdt));
+
+	return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+{
+	return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
+}
+
+#define FDT_SW_MAGIC		(~FDT_MAGIC)
+
+#endif /* _LIBFDT_INTERNAL_H */

+ 17 - 0
components/drivers/fdt/src/SConscript

@@ -0,0 +1,17 @@
+from building import *
+
+cwd     = GetCurrentDir()
+src     = Glob('*.c')
+list    = os.listdir(cwd)
+CPPPATH = [cwd + '/../inc' , cwd + '/libfdt']
+objs    = []
+
+group = DefineGroup('FDT', src, depend = ['RT_USING_FDT'], CPPPATH = CPPPATH)
+
+for d in list:
+    path = os.path.join(cwd, d)
+    if os.path.isfile(os.path.join(path, 'SConscript')):
+        objs = objs + SConscript(os.path.join(d, 'SConscript'))
+objs = objs + group
+
+Return('objs')

+ 650 - 0
components/drivers/fdt/src/dtb_access.c

@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#define _GNU_SOURCE
+
+#include "libfdt.h"
+#include "dtb_node.h"
+
+/* "/aliaes" node */
+static struct dtb_node *fdt_aliases;
+
+/**
+ * of_find_property_value_of_size() - find property of given size
+ *
+ * Search for a property in a device node and validate the requested size.
+ *
+ * @np:     device node from which the property value is to be read.
+ * @propname:   name of the property to be searched.
+ * @len:    requested length of property value
+ *
+ * @return the property value on success, -EINVAL if the property does not
+ * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ */
+static void *dtb_node_find_property_value_of_size(const struct dtb_node *dn,
+                                             const char *propname, uint32_t len)
+{
+    struct dtb_property *prop = dtb_node_get_dtb_node_property(dn, propname, NULL);
+
+    if (!prop)
+        return ERR_PTR(-EINVAL);
+    if (!prop->value)
+        return ERR_PTR(-ENODATA);
+    if (len > prop->size)
+        return ERR_PTR(-EOVERFLOW);
+    return prop->value;
+}
+
+int dtb_node_read_u32(const struct dtb_node *dn, const char *propname, uint32_t *outp)
+{
+    const uint32_t *val;
+
+    debug("%s: %s: \n", __func__, propname);
+    if (!dn)
+        return -EINVAL;
+    val = dtb_node_find_property_value_of_size(dn, propname, sizeof(*outp));
+    if (IS_ERR(val))
+    {
+        debug("(not found)\n");
+        return PTR_ERR(val);
+    }
+
+    *outp = fdt32_to_cpu(*val);
+    debug("%#x (%d)\n", *outp, *outp);
+
+    return 0;
+}
+
+uint32_t dtb_node_read_u32_default(const struct dtb_node *node, const char *propname, uint32_t def)
+{
+    dtb_node_read_u32(node, propname, &def);
+
+    return def;
+}
+
+int dtb_node_read_u32_array(const struct dtb_node *dn, const char *propname,
+                       uint32_t *out_values, size_t sz)
+{
+    const uint32_t *val;
+
+    debug("%s: %s: ", __func__, propname);
+    val = dtb_node_find_property_value_of_size(dn, propname,
+                                          sz * sizeof(*out_values));
+
+    if (IS_ERR(val))
+        return PTR_ERR(val);
+
+    debug("size %zd, val:%d\n", sz, *val);
+    while (sz--)
+        *out_values++ = fdt32_to_cpu(*val++);
+
+    return 0;
+}
+
+uint32_t dtb_node_read_u32_index_default(const struct dtb_node *node, const char *propname, int index,
+                  uint32_t def)
+{
+    RT_ASSERT(dtb_node_valid(node));
+    dtb_node_read_u32_index(node, propname, index, &def);
+
+    return def;
+}
+
+int dtb_node_read_s32_default(const struct dtb_node *node, const char *propname, int32_t def)
+{
+    RT_ASSERT(dtb_node_valid(node));
+    dtb_node_read_u32(node, propname, (uint32_t *)&def);
+
+    return def;
+}
+
+int dtb_node_read_u32_index(const struct dtb_node *dn, const char *propname,
+                       int index, uint32_t *outp)
+{
+    const uint32_t *val;
+
+    debug("%s: %s: ", __func__, propname);
+    if (!dn)
+        return -EINVAL;
+
+    val = dtb_node_find_property_value_of_size(dn, propname,
+                                          sizeof(*outp) * (index + 1));
+    if (IS_ERR(val))
+    {
+        debug("(not found)\n");
+        return PTR_ERR(val);
+    }
+
+    *outp = fdt32_to_cpu(val[index]);
+    debug("%#x (%d)\n", *outp, *outp);
+
+    return 0;
+}
+
+int dtb_node_read_u64(const struct dtb_node *dn, const char *propname, uint64_t *outp)
+{
+    const uint64_t *val;
+
+    debug("%s: %s: ", __func__, propname);
+    if (!dn)
+        return -EINVAL;
+    val = dtb_node_find_property_value_of_size(dn, propname, sizeof(*outp));
+    if (IS_ERR(val))
+    {
+        debug("(not found)\n");
+        return PTR_ERR(val);
+    }
+
+    *outp = fdt64_to_cpu(*val);
+    debug("%#llx (%lld)\n", (unsigned long long)*outp,
+          (unsigned long long)*outp);
+
+    return 0;
+}
+
+uint64_t dtb_node_read_u64_default(const struct dtb_node *node, const char *propname, uint64_t def)
+{
+    RT_ASSERT(dtb_node_valid(node));
+    dtb_node_read_u64(node, propname, &def);
+
+    return def;
+}
+
+int dtb_node_n_addr_cells(const struct dtb_node *dn)
+{
+    const uint32_t *ip;
+
+    do
+    {
+        if (dn->parent)
+            dn = dn->parent;
+        ip = dtb_node_get_dtb_node_property_value(dn, "#address-cells", NULL);
+        if (ip)
+            return fdt32_to_cpu(*ip);
+    } while (dn->parent);
+
+    /* No #address-cells property for the root node */
+    return DEV_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+
+int dtb_node_n_size_cells(const struct dtb_node *dn)
+{
+    const uint32_t *ip;
+
+    do
+    {
+        if (dn->parent)
+            dn = dn->parent;
+        ip = dtb_node_get_dtb_node_property_value(dn, "#size-cells", NULL);
+        if (ip)
+            return fdt32_to_cpu(*ip);
+    } while (dn->parent);
+
+    /* No #size-cells property for the root node */
+    return DEV_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+
+int dtb_node_simple_addr_cells(const struct dtb_node *dn)
+{
+    const uint32_t *ip;
+
+    ip = dtb_node_get_dtb_node_property_value(dn, "#address-cells", NULL);
+    if (ip)
+        return fdt32_to_cpu(*ip);
+
+    /* Return a default of 2 to match fdt_address_cells()*/
+    return 2;
+}
+
+int dtb_node_simple_size_cells(const struct dtb_node *dn)
+{
+    const uint32_t *ip;
+
+    ip = dtb_node_get_dtb_node_property_value(dn, "#size-cells", NULL);
+    if (ip)
+        return fdt32_to_cpu(*ip);
+
+    /* Return a default of 2 to match fdt_size_cells()*/
+    return 2;
+}
+
+struct dtb_property *dtb_node_get_dtb_node_property(const struct dtb_node *dtb_node, const char *property_name, int *property_size)
+{
+    struct dtb_property *dtb_property = NULL;
+
+    if (dtb_node != NULL && property_name != NULL)
+    {
+        dtb_property = dtb_node->properties;
+
+        while (dtb_property != NULL)
+        {
+            if (!strcmp(dtb_property->name, property_name))
+            {
+                if (property_size != NULL)
+                {
+                    *property_size = dtb_property->size;
+                }
+                return dtb_property;
+            }
+            dtb_property = dtb_property->next;
+        }
+    }
+
+    return dtb_property;
+}
+
+#define for_each_property_of_node(dn, pp) \
+    for (pp = dn->properties; pp != NULL; pp = pp->next)
+
+struct dtb_node *dtb_node_find_node_opts_by_path(const char *path,
+                                            const char **opts)
+{
+    struct dtb_node *np = NULL;
+    struct dtb_property *pp;
+    const char *separator = strchr(path, ':');
+
+    if (opts)
+        *opts = separator ? separator + 1 : NULL;
+
+    if (strcmp(path, "/") == 0)
+        return dtb_node_get(get_dtb_node_head());
+
+    /* The path could begin with an alias */
+    if (*path != '/')
+    {
+        int len;
+        const char *p = separator;
+
+        if (!p)
+            p = strchrnul(path, '/');
+        len = p - path;
+
+        /* of_aliases must not be NULL */
+        if (!fdt_aliases)
+            return NULL;
+
+        for_each_property_of_node(fdt_aliases, pp)
+        {
+            if (strlen(pp->name) == len && !strncmp(pp->name, path,
+                                                    len))
+            {
+                np = dtb_node_find_node_by_path(pp->value);
+                break;
+            }
+        }
+        if (!np)
+            return NULL;
+        path = p;
+    }
+
+    /* Step down the tree matching path components */
+    if (!np)
+        np = dtb_node_get(get_dtb_node_head());
+    while (np && *path == '/')
+    {
+        struct dtb_node *tmp = np;
+
+        path++; /* Increment past '/' delimiter */
+        np = dtb_node_get_dtb_node_by_path(np, path);
+        dtb_node_put(tmp);
+        path = strchrnul(path, '/');
+        if (separator && separator < path)
+            break;
+    }
+
+    return np;
+}
+
+struct dtb_node *dtb_node_find_compatible_node(struct dtb_node *from, const char *compatible)
+{
+    struct dtb_node *dn;
+
+    for_each_of_allnodes_from(from, dn)
+    {
+        if (dtb_node_get_dtb_node_compatible_match(dn, compatible) &&
+            dtb_node_get(dn))
+            break;
+    }
+    dtb_node_put(from);
+
+    return dn;
+}
+
+void *dtb_node_get_dtb_node_property_value(const struct dtb_node *dtb_node, const char *property_name, int *property_size)
+{
+    struct dtb_property *dtb_property = dtb_node_get_dtb_node_property(dtb_node, property_name, NULL);
+
+    if (!dtb_property || !dtb_property->value || !dtb_property->size)
+    {
+        return NULL;
+    }
+
+    if (property_size != NULL)
+    {
+        *property_size = dtb_property->size;        
+    }
+
+    return dtb_property->value;
+}
+
+const struct dtb_node *dtb_node_find_node_by_prop_value(struct dtb_node *from,
+                                                   const char *propname,
+                                                   const void *propval, int proplen)
+{
+    struct dtb_node *np;
+    void *value;
+    for_each_of_allnodes_from(from, np)
+    {
+        value = dtb_node_get_dtb_node_property_value(np, propname, &proplen);
+        if (!memcmp(value, propval, proplen) && dtb_node_get(np))
+            break;
+    }
+    dtb_node_put(from);
+
+    return np;
+}
+
+struct dtb_node *dtb_node_find_all_nodes(const struct dtb_node *prev)
+{
+    const struct dtb_node *dn;
+
+    if (!prev)
+    {
+        dn = get_dtb_node_head();
+    }
+    else if (prev->child)
+    {
+        dn = prev->child;
+    }
+    else
+    {
+        /*
+         * Walk back up looking for a sibling, or the end of the
+         * structure
+         */
+        dn = prev;
+        while (dn->parent && !dn->sibling)
+            dn = dn->parent;
+        dn = dn->sibling; /* Might be null at the end of the tree */
+    }
+
+    return (struct dtb_node *)dn;
+}
+
+rt_bool_t dtb_node_device_is_available(const struct dtb_node *device)
+{
+    const char *status;
+    int statlen;
+
+    if (!device)
+        return RT_FALSE;
+
+    status = dtb_node_get_dtb_node_property_value(device, "status", &statlen);
+    if (status == NULL)
+        return RT_TRUE;
+
+    if (statlen > 0)
+    {
+        if (!strcmp(status, "okay"))
+            return RT_TRUE;
+    }
+
+    return RT_FALSE;
+}
+
+struct dtb_node *dtb_node_get_parent(const struct dtb_node *node)
+{
+    const struct dtb_node *dn;
+
+    if (!node)
+        return NULL;
+
+    dn = dtb_node_get(node->parent);
+
+    return (struct dtb_node *)dn;
+}
+
+struct dtb_node *dtb_node_find_node_by_phandle(phandle handle)
+{
+    struct dtb_node *dn;
+
+    if (!handle)
+        return NULL;
+
+    for_each_of_allnodes(dn) if (dn->handle == handle) break;
+    (void)dtb_node_get(dn);
+
+    return dn;
+}
+
+int dtb_node_property_match_string(const struct dtb_node *dn, const char *propname,
+                              const char *string)
+{
+    const struct dtb_property *prop = dtb_node_get_dtb_node_property(dn, propname, NULL);
+    size_t l;
+    int i;
+    const char *p, *end;
+
+    if (!prop)
+        return -EINVAL;
+    if (!prop->value)
+        return -ENODATA;
+
+    p = prop->value;
+    end = p + prop->size;
+
+    for (i = 0; p < end; i++, p += l)
+    {
+        l = strnlen(p, end - p) + 1;
+        if (p + l > end)
+            return -EILSEQ;
+        debug("comparing %s with %s\n", string, p);
+        if (strcmp(string, p) == 0)
+            return i; /* Found it; return index */
+    }
+    return -ENODATA;
+}
+
+/**
+ * of_property_read_string_helper() - Utility helper for parsing string properties
+ * @np:		device node from which the property value is to be read.
+ * @propname:	name of the property to be searched.
+ * @out_strs:	output array of string pointers.
+ * @sz:		number of array elements to read.
+ * @skip:	Number of strings to skip over at beginning of list.
+ *
+ * Don't call this function directly. It is a utility helper for the
+ * of_property_read_string*() family of functions.
+ */
+int dtb_node_property_read_string_helper(const struct dtb_node *dn,
+                                    const char *propname, const char **out_strs,
+                                    size_t sz, int skip)
+{
+    const struct dtb_property *prop = dtb_node_get_dtb_node_property(dn, propname, NULL);
+    int l = 0, i = 0;
+    const char *p, *end;
+
+    if (!prop)
+        return -EINVAL;
+    if (!prop->value)
+        return -ENODATA;
+    p = prop->value;
+    end = p + prop->size;
+
+    for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l)
+    {
+        l = strnlen(p, end - p) + 1;
+        if (p + l > end)
+            return -EILSEQ;
+        if (out_strs && i >= skip)
+            *out_strs++ = p;
+    }
+    i -= skip;
+    return i <= 0 ? -ENODATA : i;
+}
+
+static int __dtb_node_parse_phandle_with_args(const struct dtb_node *dn,
+                                         const char *list_name,
+                                         const char *cells_name,
+                                         int cell_count, int index,
+                                         struct fdt_phandle_args *out_args)
+{
+    const uint32_t *list, *list_end;
+    int rc = 0, cur_index = 0;
+    uint32_t count = 0;
+    struct dtb_node *node = NULL;
+    phandle phandle;
+    int size;
+
+    /* Retrieve the phandle list property */
+    list = dtb_node_get_dtb_node_property_value(dn, list_name, &size);
+    if (!list)
+        return -ENOENT;
+    list_end = list + size / sizeof(*list);
+
+    /* Loop over the phandles until all the requested entry is found */
+    while (list < list_end)
+    {
+        rc = -EINVAL;
+        count = 0;
+
+        /*
+         * If phandle is 0, then it is an empty entry with no
+         * arguments.  Skip forward to the next entry.
+         */
+        phandle = fdt32_to_cpu(*(list++));
+        if (phandle)
+        {
+            /*
+             * Find the provider node and parse the #*-cells
+             * property to determine the argument length.
+             *
+             * This is not needed if the cell count is hard-coded
+             * (i.e. cells_name not set, but cell_count is set),
+             * except when we're going to return the found node
+             * below.
+             */
+            if (cells_name || cur_index == index)
+            {
+                node = dtb_node_find_node_by_phandle(phandle);
+                if (!node)
+                {
+                    debug("%s: could not find phandle\n",
+                          dn->path);
+                    goto err;
+                }
+            }
+
+            if (cells_name)
+            {
+                if (dtb_node_read_u32(node, cells_name, &count))
+                {
+                    debug("%s: could not get %s for %s\n",
+                          dn->path, cells_name,
+                          node->path);
+                    goto err;
+                }
+            }
+            else
+            {
+                count = cell_count;
+            }
+
+            /*
+             * Make sure that the arguments actually fit in the
+             * remaining property data length
+             */
+            if (list + count > list_end)
+            {
+                debug("%s: arguments longer than property\n",
+                      dn->path);
+                goto err;
+            }
+        }
+
+        /*
+         * All of the error cases above bail out of the loop, so at
+         * this point, the parsing is successful. If the requested
+         * index matches, then fill the out_args structure and return,
+         * or return -ENOENT for an empty entry.
+         */
+        rc = -ENOENT;
+        if (cur_index == index)
+        {
+            if (!phandle)
+                goto err;
+
+            if (out_args)
+            {
+                int i;
+                if (count > FDT_MAX_PHANDLE_ARGS)
+                    count = FDT_MAX_PHANDLE_ARGS;
+                out_args->np = node;
+                out_args->args_count = count;
+                for (i = 0; i < count; i++)
+                    out_args->args[i] =
+                        fdt32_to_cpu(*(list++));
+            }
+            else
+            {
+                dtb_node_put(node);
+            }
+
+            /* Found it! return success */
+            return 0;
+        }
+
+        dtb_node_put(node);
+        node = NULL;
+        list += count;
+        cur_index++;
+    }
+
+    /*
+     * Unlock node before returning result; will be one of:
+     * -ENOENT : index is for empty phandle
+     * -EINVAL : parsing error on data
+     * [1..n]  : Number of phandle (count mode; when index = -1)
+     */
+    rc = index < 0 ? cur_index : -ENOENT;
+err:
+    if (node)
+        dtb_node_put(node);
+    return rc;
+}
+
+struct dtb_node *dtb_node_parse_phandle(const struct dtb_node *dn,
+                                   const char *phandle_name, int index)
+{
+    struct fdt_phandle_args args;
+
+    if (index < 0)
+        return NULL;
+
+    if (__dtb_node_parse_phandle_with_args(dn, phandle_name, NULL, 0, index,
+                                      &args))
+        return NULL;
+
+    return args.np;
+}
+
+int dtb_node_parse_phandle_with_args(const struct dtb_node *dn,
+                                const char *list_name, const char *cells_name,
+                                int index, struct fdt_phandle_args *out_args)
+{
+    if (index < 0)
+        return -EINVAL;
+
+    return __dtb_node_parse_phandle_with_args(dn, list_name, cells_name, 0,
+                                         index, out_args);
+}
+
+int dtb_node_count_phandle_with_args(const struct dtb_node *dn,
+                                const char *list_name, const char *cells_name)
+{
+    return __dtb_node_parse_phandle_with_args(dn, list_name, cells_name, 0,
+                                         -1, NULL);
+}

+ 57 - 0
components/drivers/fdt/src/dtb_addr.c

@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "libfdt.h"
+#include "dtb_node.h"
+
+/* Max address size we deal with */
+#define FDT_MAX_ADDR_CELLS	4
+#define FDT_CHECK_ADDR_COUNT(na)	((na) > 0 && (na) <= FDT_MAX_ADDR_CELLS)
+#define FDT_CHECK_COUNTS(na, ns)	(FDT_CHECK_ADDR_COUNT(na) && (ns) > 0)
+
+static void dtb_node_default_count_cells(const struct dtb_node *dn,
+				       int *addrc, int *sizec)
+{
+	if (addrc)
+		*addrc = dtb_node_n_addr_cells(dn);
+	if (sizec)
+		*sizec = dtb_node_n_size_cells(dn);
+}
+
+const uint32_t *dtb_node_get_address(const struct dtb_node *dev, int index,
+			     uint64_t *size, unsigned int *flags)
+{
+	const uint32_t *prop;
+	int psize;
+	struct dtb_node *parent;
+	int onesize, i, na, ns;
+
+	/* Get parent */
+	parent = dtb_node_get_parent(dev);
+	if (parent == NULL)
+		return NULL;
+
+	dtb_node_default_count_cells(dev, &na, &ns);
+	if (!FDT_CHECK_ADDR_COUNT(na))
+		return NULL;
+
+	/* Get "reg" or "assigned-addresses" property */
+	prop = dtb_node_get_dtb_node_property_value(dev, "reg", &psize);
+	if (prop == NULL)
+		return NULL;
+	psize /= 4;
+
+	onesize = na + ns;
+	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+		if (i == index)
+		{
+			if (size)
+				*size = dtb_node_read_number(prop + na, ns);
+			if (flags)
+				*flags = 0x200;
+			return prop;
+		}
+	return NULL;
+}

+ 537 - 0
components/drivers/fdt/src/dtb_base.c

@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "dtb_node.h"
+#include "libfdt.h"
+#include "libfdt_env.h"
+#include <ctype.h>
+
+static const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
+{
+    if (*base == 0)
+    {
+        if (s[0] == '0')
+        {
+            if (tolower(s[1]) == 'x' && isxdigit(s[2]))
+                *base = 16;
+            else
+                *base = 8;
+        }
+        else
+            *base = 10;
+    }
+    if (*base == 16 && s[0] == '0' && tolower(s[1]) == 'x')
+        s += 2;
+    return s;
+}
+
+unsigned long simple_strtoul(const char *cp, char **endp,
+                unsigned int base)
+{
+    unsigned long result = 0;
+    unsigned long value;
+
+    cp = _parse_integer_fixup_radix(cp, &base);
+
+    while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+        ? toupper(*cp) : *cp)-'A'+10) < base)
+    {
+        result = result*base + value;
+        cp++;
+    }
+
+    if (endp)
+        *endp = (char *)cp;
+
+    return result;
+}
+
+int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
+{
+    char *tail;
+    unsigned long val;
+    size_t len;
+
+    *res = 0;
+    len = strlen(cp);
+    if (len == 0)
+        return -EINVAL;
+
+    val = simple_strtoul(cp, &tail, base);
+    if (tail == cp)
+        return -EINVAL;
+
+    if ((*tail == '\0') ||
+        ((len == (size_t)(tail - cp) + 1) && (*tail == '\n')))
+    {
+        *res = val;
+        return 0;
+    }
+
+    return -EINVAL;
+}
+
+long simple_strtol(const char *cp, char **endp, unsigned int base)
+{
+    if (*cp == '-')
+        return -simple_strtoul(cp + 1, endp, base);
+
+    return simple_strtoul(cp, endp, base);
+}
+
+rt_bool_t dtb_node_read_bool(const struct dtb_node *node, const char *propname)
+{
+    const void *prop;
+
+    RT_ASSERT(dtb_node_valid(node));
+    debug("%s: %s: ", __func__, propname);
+
+    prop = dtb_node_get_property(node, propname, NULL);
+
+    debug("%s\n", prop ? "true" : "false");
+
+    return prop ? RT_TRUE : RT_FALSE;
+}
+
+const void *dtb_node_read_prop(const struct dtb_node *node, const char *propname, int *sizep)
+{
+    const char *val = NULL;
+    int len;
+
+    RT_ASSERT(dtb_node_valid(node));
+    debug("%s: %s: ", __func__, propname);
+
+    struct dtb_property *prop = dtb_node_get_dtb_node_property(node, propname, &len);
+
+    if (prop)
+    {
+        val = prop->value;
+        len = prop->size;
+    }
+
+    if (!val)
+    {
+        debug("<not found>\n");
+        if (sizep)
+            *sizep = -FDT_ERR_NOTFOUND;
+        return NULL;
+    }
+    if (sizep)
+        *sizep = len;
+
+    return val;
+}
+
+const char *dtb_node_read_string(const struct dtb_node *node, const char *propname)
+{
+    const char *str;
+    int len;
+
+    str = dtb_node_read_prop(node, propname, &len);
+    if (!str)
+        return NULL;
+
+    if (strnlen(str, len) >= len)
+    {
+        debug("<invalid>\n");
+        return NULL;
+    }
+    debug("%s\n", str);
+
+    return str;
+}
+
+const struct dtb_node *dtb_node_find_subnode(const struct dtb_node *node, const char *subnode_name)
+{
+    const struct dtb_node *subnode;
+
+    RT_ASSERT(dtb_node_valid(node));
+    debug("%s: %s: ", __func__, subnode_name);
+
+    for (node = node->child; node; node = node->sibling)
+    {
+        if (!strcmp(subnode_name, node->name))
+            break;
+    }
+    subnode = node;
+
+    debug("%s\n", dtb_node_valid(subnode) ?\
+          dtb_node_get_name(subnode) : "<none>");
+
+    return subnode;
+}
+
+struct dtb_node *dtb_node_first_subnode(const struct dtb_node *node)
+{
+    RT_ASSERT(dtb_node_valid(node));
+
+    return node->child;
+}
+
+struct dtb_node *dtb_node_next_subnode(const struct dtb_node *node)
+{
+    RT_ASSERT(dtb_node_valid(node));
+
+    return node->sibling;
+}
+
+const char *dtb_node_get_name(const struct dtb_node *node)
+{
+    if (!dtb_node_valid(node))
+    {
+        debug("%s node not valid\n", __func__);
+        return NULL;
+    }
+
+    return strrchr(node->path, '/') + 1;
+
+}
+
+struct dtb_node *dtb_node_get_by_phandle(uint phandle)
+{
+    if (dtb_node_active())
+        return dtb_node_find_node_by_phandle(phandle);
+    return NULL;
+}
+
+int dtb_node_read_size(const struct dtb_node *node, const char *propname)
+{
+    struct dtb_property *prop = dtb_node_get_dtb_node_property( node, propname, NULL);
+
+    if (prop)
+        return prop->size;
+
+    return -EINVAL;
+}
+
+size_t dtb_node_get_addr_index(const struct dtb_node *node, int index)
+{
+    int na;
+    size_t size;
+
+    const uint32_t *prop_val;
+    uint flags;
+
+    prop_val = dtb_node_get_address(node, index,
+                    (uint64_t *)&size, &flags);
+    if (!prop_val)
+        return -1;
+
+    na = dtb_node_n_addr_cells(node);
+
+    return dtb_node_read_number(prop_val, na);
+}
+
+size_t dtb_node_get_addr(const struct dtb_node *node)
+{
+    return dtb_node_get_addr_index(node, 0);
+}
+
+int dtb_node_stringlist_search(const struct dtb_node *node, const char *property,
+                 const char *string)
+{
+    return dtb_node_property_match_string(node, property, string);
+}
+
+int dtb_node_read_string_index(const struct dtb_node *node, const char *property, int index,
+                 const char **outp)
+{
+    return dtb_node_property_read_string_index(node, property, index, outp);
+}
+
+int dtb_node_read_string_count(const struct dtb_node *node, const char *property)
+{
+    return dtb_node_property_count_strings(node, property);
+}
+
+struct dtb_node *dtb_node_path(const char *path)
+{
+    if (dtb_node_active())
+        return dtb_node_find_node_by_path(path);
+    return NULL;
+}
+
+const char *dtb_node_get_chosen_prop(const char *name)
+{
+    const struct dtb_node *chosen_node;
+
+    chosen_node = (const struct dtb_node *)dtb_node_path("/chosen");
+
+    return dtb_node_read_string(chosen_node, name);
+}
+
+struct dtb_node *dtb_node_get_chosen_node(const char *name)
+{
+    const char *prop;
+
+    prop = dtb_node_get_chosen_prop(name);
+    if (!prop)
+        return NULL;
+
+    return dtb_node_path(prop);
+}
+
+const void *dtb_node_get_property(const struct dtb_node *node, const char *propname, int *lenp)
+{
+    return dtb_node_get_dtb_node_property_value(node, propname, lenp);
+}
+
+rt_bool_t dtb_node_is_available(const struct dtb_node *node)
+{
+    return dtb_node_device_is_available(node);
+}
+
+size_t dtb_node_get_addr_size(const struct dtb_node *node, const char *property,
+                size_t *sizep)
+{
+    int na, ns;
+    int psize;
+    const uint32_t *prop = dtb_node_get_dtb_node_property_value(node, property, &psize);
+
+    if (!prop)
+        return -1;
+    na = dtb_node_n_addr_cells(node);
+    ns = dtb_node_n_size_cells(node);
+    *sizep = dtb_node_read_number(prop + na, ns);
+
+    return dtb_node_read_number(prop, na);
+}
+
+const uint8_t *dtb_node_read_u8_array_ptr(const struct dtb_node *node, const char *propname,
+                    size_t sz)
+{
+    int psize;
+    const uint32_t *prop = dtb_node_get_dtb_node_property_value(node, propname, &psize);
+
+    if (!prop || sz != psize)
+        return NULL;
+    return (uint8_t *)prop;
+}
+
+int dtb_node_find_all_compatible_node(const struct dtb_node *from, const char *compatible, struct dtb_node **node_table, int max_num, int *node_num)
+{
+    const struct dtb_node *dn;
+    int num = 0;
+    for_each_of_allnodes_from(from, dn)
+    {
+        if (dtb_node_get_dtb_node_compatible_match(dn, compatible) &&
+            dtb_node_get(dn))
+        {
+
+            num++;
+            *node_table = (struct dtb_node *)dn;
+            node_table++;
+            if (num >= max_num)
+            {
+                break;
+            }
+        }
+    }
+    *node_num = num;
+    dtb_node_put(from);
+
+    return 0;
+}
+
+int dtb_node_write_prop(const struct dtb_node *node, const char *propname, int len,
+              const void *value)
+{
+    struct dtb_property *pp;
+    struct dtb_property *pp_last = NULL;
+    struct dtb_property *new;
+
+    if (!dtb_node_active())
+        return -ENOSYS;
+
+    if (!node)
+        return -EINVAL;
+
+    for (pp = node->properties; pp; pp = pp->next)
+    {
+        if (strcmp(pp->name, propname) == 0)
+        {
+            /* Property exists -> change value */
+            pp->value = (void *)value;
+            pp->size = len;
+            return 0;
+        }
+        pp_last = pp;
+    }
+
+    if (!pp_last)
+        return -ENOENT;
+
+    /* Property does not exist -> append new property */
+    new = malloc(sizeof(struct dtb_property));
+    if (!new)
+        return -ENOMEM;
+
+    new->name = strdup(propname);
+    if (!new->name)
+    {
+        free(new);
+        return -ENOMEM;
+    }
+
+    new->value = (void *)value;
+    new->size = len;
+    new->next = NULL;
+
+    pp_last->next = new;
+
+    return 0;
+}
+
+int dtb_node_write_string(const struct dtb_node *node, const char *propname, const char *value)
+{
+    if (!dtb_node_active())
+        return -ENOSYS;
+
+    RT_ASSERT(dtb_node_valid(node));
+
+    debug("%s: %s = %s", __func__, propname, value);
+
+    return dtb_node_write_prop(node, propname, strlen(value) + 1, value);
+}
+
+int dtb_node_set_enabled(const struct dtb_node *node, rt_bool_t value)
+{
+    if (!dtb_node_active())
+        return -ENOSYS;
+
+    RT_ASSERT(dtb_node_valid(node));
+
+    if (value)
+        return dtb_node_write_string(node, "status", "okay");
+    else
+        return dtb_node_write_string(node, "status", "disable");
+}
+
+/**
+ * dtb_node_irq_find_parent - Given a device node, find its interrupt parent node
+ * @child: pointer to device node
+ *
+ * Returns a pointer to the interrupt parent node, or NULL if the interrupt
+ * parent could not be determined.
+ */
+static struct dtb_node *dtb_node_irq_find_parent(struct dtb_node *child)
+{
+	struct dtb_node *p;
+	phandle parent;
+
+	if (!dtb_node_get(child))
+		return NULL;
+	do
+    {
+		if (dtb_node_read_u32_array(child, "interrupt-parent", &parent, 1))
+        {
+			p = dtb_node_get_parent(child);
+		}
+        else
+        {
+			p = dtb_node_get_by_phandle(parent);         
+		}
+		dtb_node_put(child);
+		child = p;
+	} while (p && dtb_node_get_property(p, "#interrupt-cells", NULL) == NULL);
+
+	return p;
+}
+
+int dtb_node_irq_get(struct dtb_node *dev, int index)
+{
+	int rc = 0;
+	struct fdt_phandle_args out_irq;
+    struct dtb_node *p;
+	uint32_t intsize;
+	int res, i;
+
+	p = dtb_node_irq_find_parent(dev);
+	if (p == NULL)
+		return -EINVAL;
+	/* Get size of interrupt specifier */
+	if (dtb_node_read_u32_array(p, "#interrupt-cells", &intsize, 1))
+    {
+		res = -EINVAL;
+		goto out;
+	}
+
+	debug(" path:%s, parent=%pOF, intsize=%d\n", p->path,p, intsize);
+    
+	/* Copy intspec into irq structure */
+	out_irq.np = p;
+	out_irq.args_count = intsize;
+	for (i = 0; i < intsize; i++)
+    {
+		res = dtb_node_read_u32_index(dev, "interrupts",
+						 (index * 3 + i),
+						 out_irq.args + i);
+		if (res)
+			goto out;
+	}
+    rc = out_irq.args[1];
+ out:
+	dtb_node_put(p);
+	return rc;
+
+}
+
+/**
+ * dtb_node_irq_get_byname - Decode a node's IRQ and return it as a Linux IRQ number
+ * @dev: pointer to device tree node
+ * @name: IRQ name
+ *
+ * Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
+ * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
+ * of any other failure.
+ */
+int dtb_node_irq_get_byname(struct dtb_node *dev, const char *name)
+{
+	int index;
+
+	if (!name)
+		return -EINVAL;
+
+	index = dtb_node_stringlist_search(dev, "interrupt-names", name);
+	if (index < 0)
+		return index;
+
+	return dtb_node_irq_get(dev, index);
+}
+
+/**
+ * dtb_node_irq_count - Count the number of IRQs a node uses
+ * @dev: pointer to device tree node
+ */
+int dtb_node_irq_count(struct dtb_node *device)
+{
+    struct dtb_node *p;
+	uint32_t intsize;
+	int nr = 0, res = 0;
+
+	p = dtb_node_irq_find_parent(device);
+	if (p == NULL)
+		return -EINVAL;
+
+	/* Get size of interrupt specifier */
+	if (dtb_node_read_u32_array(p, "#interrupt-cells", &intsize, 1))
+    {
+		res = -EINVAL;
+		goto out;
+	}
+
+	debug(" path:%s, parent=%pOF, intsize=%d\n", p->path,p, intsize);
+
+    res = dtb_node_read_size(device, "interrupts");
+    if (res < 0)
+    {
+        goto out;
+    }
+    nr = res / (intsize * 4);
+ out:
+	dtb_node_put(p);
+
+	return nr;
+}

+ 817 - 0
components/drivers/fdt/src/dtb_get.c

@@ -0,0 +1,817 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "libfdt.h"
+#include "dtb_node.h"
+
+static struct
+{
+    const char *ptr;
+    const char *end;
+    char *cur;
+} paths_buf = {NULL, NULL};
+static void *current_fdt;
+
+int fdt_exec_status = FDT_RET_GET_OK;
+
+int dtb_node_get_exec_status()
+{
+    return fdt_exec_status;
+}
+
+static int _dtb_node_get_dtb_properties_list(struct dtb_property *dtb_property, off_t node_off)
+{
+    /* caller alrealy checked current_fdt */
+    off_t property_off = fdt_first_property_offset(current_fdt, node_off);
+    struct fdt_property *fdt_property;
+
+    if (property_off < 0)
+    {
+        return FDT_RET_GET_EMPTY;
+    }
+
+    for (;;)
+    {
+        fdt_property = (struct fdt_property *)fdt_get_property_by_offset(current_fdt, property_off, &dtb_property->size);
+        if (fdt_property != NULL)
+        {
+            dtb_property->name = fdt_string(current_fdt, fdt32_to_cpu(fdt_property->nameoff));
+            dtb_property->value = fdt_property->data;
+            dtb_property->size = fdt32_to_cpu(fdt_property->len);
+        }
+
+        property_off = fdt_next_property_offset(current_fdt, property_off);
+        if (property_off >= 0)
+        {
+            dtb_property->next = (struct dtb_property *)malloc(sizeof(struct dtb_property));
+            if (dtb_property->next == NULL)
+            {
+                return FDT_RET_NO_MEMORY;
+            }
+            dtb_property = dtb_property->next;
+        }
+        else
+        {
+            dtb_property->next = NULL;
+            break;
+        }
+    }
+
+    return FDT_RET_GET_OK;
+}
+
+static int _dtb_node_get_dtb_nodes_list(struct dtb_node *dtb_node_head, struct dtb_node *dtb_node, const char *pathname)
+{
+    off_t root_off;
+    off_t node_off;
+    int pathname_sz;
+    int node_name_sz;
+
+    /* caller alrealy checked current_fdt */
+    if ((root_off = fdt_path_offset(current_fdt, pathname)) >= 0)
+    {
+        pathname_sz = strlen(pathname);
+        node_off = fdt_first_subnode(current_fdt, root_off);
+
+        if (node_off < 0)
+        {
+            return FDT_RET_GET_EMPTY;
+        }
+
+        for (;;)
+        {
+            dtb_node->parent = dtb_node_head;
+            dtb_node->sibling = NULL;
+            dtb_node->name = fdt_get_name(current_fdt, node_off, &node_name_sz);
+
+            /* parent_path + name + '/' + '\0' */
+            if (paths_buf.cur + pathname_sz + node_name_sz + 2 < paths_buf.end)
+            {
+                dtb_node->path = (const char *)paths_buf.cur;
+                strncpy(paths_buf.cur, pathname, pathname_sz);
+                paths_buf.cur += pathname_sz;
+                strncpy(paths_buf.cur, (char *)dtb_node->name, node_name_sz);
+                paths_buf.cur += node_name_sz;
+                *paths_buf.cur++ = '/';
+                *paths_buf.cur++ = '\0';
+            }
+            else
+            {
+                dtb_node->path = NULL;
+                rt_kprintf("\033[31m\rERROR: `FDT_DTB_ALL_NODES_PATH_SIZE' = %d bytes is configured too low.\033[0m\n", FDT_DTB_ALL_NODES_PATH_SIZE);
+                return FDT_RET_NO_MEMORY;
+            }
+
+            dtb_node->handle = fdt_get_phandle(current_fdt, node_off);
+            dtb_node->properties = (struct dtb_property *)malloc(sizeof(struct dtb_property));
+            dtb_node->child = (struct dtb_node *)malloc(sizeof(struct dtb_node));
+
+            if (dtb_node->properties == NULL || dtb_node->child == NULL)
+            {
+                return FDT_RET_NO_MEMORY;
+            }
+
+            fdt_exec_status = _dtb_node_get_dtb_properties_list(dtb_node->properties, node_off);
+            if (fdt_exec_status == FDT_RET_GET_EMPTY)
+            {
+                free(dtb_node->properties);
+                dtb_node->properties = NULL;
+            }
+            else if (fdt_exec_status != FDT_RET_GET_OK)
+            {
+                return fdt_exec_status;
+            }
+
+            fdt_exec_status = _dtb_node_get_dtb_nodes_list(dtb_node, dtb_node->child, dtb_node->path);
+            if (fdt_exec_status == FDT_RET_GET_EMPTY)
+            {
+                free(dtb_node->child);
+                dtb_node->child = NULL;
+            }
+            else if (fdt_exec_status != FDT_RET_GET_OK)
+            {
+                return fdt_exec_status;
+            }
+
+            node_off = fdt_next_subnode(current_fdt, node_off);
+            if (node_off >= 0)
+            {
+                dtb_node->sibling = (struct dtb_node *)malloc(sizeof(struct dtb_node));
+                if (dtb_node->sibling == NULL)
+                {
+                    return FDT_RET_NO_MEMORY;
+                }
+                dtb_node = dtb_node->sibling;
+            }
+            else
+            {
+                break;
+            }
+        }
+    }
+
+    return FDT_RET_GET_OK;
+}
+
+struct dtb_node *dtb_node_get_dtb_list(void *fdt)
+{
+    int root_off;
+    struct dtb_node *dtb_node_head = NULL;
+
+    if (fdt == NULL)
+    {
+        fdt_exec_status = FDT_RET_NO_LOADED;
+        goto fail;
+    }
+
+    current_fdt = fdt;
+
+    if ((dtb_node_head = (struct dtb_node *)malloc(sizeof(struct dtb_node))) == NULL)
+    {
+        fdt_exec_status = FDT_RET_NO_MEMORY;
+        goto fail;
+    }
+
+    if (paths_buf.ptr == NULL)
+    {
+        paths_buf.ptr = malloc(FDT_DTB_ALL_NODES_PATH_SIZE);
+        if (paths_buf.ptr == NULL)
+        {
+            fdt_exec_status = FDT_RET_NO_MEMORY;
+            goto fail;
+        }
+        paths_buf.cur = (char *)paths_buf.ptr;
+        paths_buf.end = (char *)(paths_buf.ptr + FDT_DTB_ALL_NODES_PATH_SIZE);
+    }
+
+    root_off = fdt_path_offset(fdt, "/");
+
+    if ((dtb_node_head->header = malloc(sizeof(struct dtb_header))) == NULL)
+    {
+        fdt_exec_status = FDT_RET_NO_MEMORY;
+        goto fail;
+    }
+    else
+    {
+        ((struct dtb_header *)dtb_node_head->header)->root = '/';
+        ((struct dtb_header *)dtb_node_head->header)->zero = '\0';
+        ((struct dtb_header *)dtb_node_head->header)->memreserve_sz = fdt_num_mem_rsv(fdt);
+
+        if (dtb_node_head->header->memreserve_sz > 0)
+        {
+            int i;
+            int memreserve_sz = dtb_node_head->header->memreserve_sz;
+            uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(fdt);
+            struct fdt_reserve_entry *rsvmap = (struct fdt_reserve_entry *)((char *)fdt + off_mem_rsvmap);
+
+            ((struct dtb_header *)dtb_node_head->header)->memreserve = malloc(sizeof(struct dtb_memreserve) * memreserve_sz);
+            if (dtb_node_head->header->memreserve == NULL)
+            {
+                fdt_exec_status = FDT_RET_NO_MEMORY;
+                goto fail;
+            }
+            for (i = 0; i < memreserve_sz; ++i)
+            {
+                ((struct dtb_header *)dtb_node_head->header)->memreserve[i].address = fdt64_to_cpu(rsvmap[i].address);
+                ((struct dtb_header *)dtb_node_head->header)->memreserve[i].size = fdt64_to_cpu(rsvmap[i].size);
+            }
+        }
+        else
+        {
+            ((struct dtb_header *)dtb_node_head->header)->memreserve = NULL;
+        }
+    }
+
+    dtb_node_head->path = paths_buf.ptr;
+    *paths_buf.cur++ = '/';
+    *paths_buf.cur++ = '\0';
+    dtb_node_head->parent = NULL;
+    dtb_node_head->sibling = NULL;
+
+    dtb_node_head->handle = fdt_get_phandle(fdt, root_off);
+    dtb_node_head->properties = (struct dtb_property *)malloc(sizeof(struct dtb_property));
+    dtb_node_head->child = (struct dtb_node *)malloc(sizeof(struct dtb_node));
+
+    if (dtb_node_head->properties == NULL || dtb_node_head->child == NULL)
+    {
+        fdt_exec_status = FDT_RET_NO_MEMORY;
+        goto fail;
+    }
+
+    if ((fdt_exec_status = _dtb_node_get_dtb_properties_list(dtb_node_head->properties, root_off)) != FDT_RET_GET_OK)
+    {
+        goto fail;
+    }
+
+    if ((fdt_exec_status = _dtb_node_get_dtb_nodes_list(dtb_node_head, dtb_node_head->child, dtb_node_head->path)) != FDT_RET_GET_OK)
+    {
+        goto fail;
+    }
+
+    /* paths_buf.ptr addr save in the dtb_node_head's path */
+    paths_buf.ptr = NULL;
+    paths_buf.cur = NULL;
+
+    return dtb_node_head;
+
+fail:
+    if (dtb_node_head != NULL)
+    {
+        dtb_node_free_dtb_list(dtb_node_head);
+    }
+
+    return NULL;
+}
+
+static void _dtb_node_free_dtb_node(struct dtb_node *dtb_node)
+{
+    struct dtb_node *dtb_node_last;
+    struct dtb_property *dtb_property;
+    struct dtb_property *dtb_property_last;
+
+    while (dtb_node != NULL)
+    {
+        dtb_property = dtb_node->properties;
+        while (dtb_property != NULL)
+        {
+            dtb_property_last = dtb_property;
+            dtb_property = dtb_property->next;
+            free(dtb_property_last);
+        }
+
+        _dtb_node_free_dtb_node(dtb_node->child);
+
+        dtb_node_last = dtb_node;
+        dtb_node = dtb_node->sibling;
+        free(dtb_node_last);
+    }
+}
+
+void dtb_node_free_dtb_list(struct dtb_node *dtb_node_head)
+{
+    if (dtb_node_head == NULL)
+    {
+        return;
+    }
+
+    /* only root node can free all path buffer */
+    if (dtb_node_head->parent == NULL || (dtb_node_head->path != NULL && !strcmp(dtb_node_head->path, "/")))
+    {
+        if (dtb_node_head->path != NULL)
+        {
+            free((void *)dtb_node_head->path);
+        }
+        if (dtb_node_head->header != NULL)
+        {
+            if (dtb_node_head->header->memreserve != NULL)
+            {
+                free((void *)dtb_node_head->header->memreserve);
+            }
+            free((void *)dtb_node_head->header);
+        }
+    }
+
+    _dtb_node_free_dtb_node(dtb_node_head);
+}
+
+static void _dtb_node_printf_depth(int depth)
+{
+    int i = depth;
+    while (i --> 0)
+    {
+        rt_kputs("\t");
+    }
+}
+
+rt_bool_t _dtb_node_test_string_list(const void *value, int size)
+{
+    const char *str = value;
+    const char *str_start, *str_end;
+
+    if (size == 0)
+    {
+        return RT_FALSE;
+    }
+
+    /* string end with '\0' */
+    if (str[size - 1] != '\0')
+    {
+        return RT_FALSE;
+    }
+
+    /* get string list end */
+    str_end = str + size;
+
+    while (str < str_end)
+    {
+        str_start = str;
+        /* before string list end, not '\0' and a printable characters */
+        while (str < str_end && *str && ((unsigned char)*str >= ' ' && (unsigned char)*str <= '~'))
+        {
+            ++str;
+        }
+
+        /* not zero, or not increased */
+        if (*str != '\0' || str == str_start)
+        {
+            return RT_FALSE;
+        }
+
+        /* next string */
+        ++str;
+    }
+
+    return RT_TRUE;
+}
+
+static void _dtb_node_printf_dtb_node_info(struct dtb_node *dtb_node)
+{
+    static int depth = 0;
+    struct dtb_property *dtb_property;
+
+    while (dtb_node != NULL)
+    {
+        rt_kputs("\n");
+        _dtb_node_printf_depth(depth);
+        rt_kputs(dtb_node->name);
+        rt_kputs(" {\n");
+        ++depth;
+
+        dtb_property = dtb_node->properties;
+        while (dtb_property != NULL)
+        {
+            _dtb_node_printf_depth(depth);
+
+            rt_kputs(dtb_property->name);
+
+            if (dtb_property->size > 0)
+            {
+                int size = dtb_property->size;
+                char *value = dtb_property->value;
+
+                rt_kputs(" = ");
+                if (_dtb_node_test_string_list(value, size) == RT_TRUE)
+                {
+                    /* print string list */
+                    char *str = value;
+                    do
+                    {
+                        rt_kprintf("\"%s\"", str);
+                        str += strlen(str) + 1;
+                        rt_kputs(", ");
+                    } while (str < value + size);
+                    rt_kputs("\b\b");
+                }
+                else if ((size % 4) == 0)
+                {
+                    /* print addr and size cell */
+                    int i;
+                    fdt32_t *cell = (fdt32_t *)value;
+
+                    rt_kputs("<");
+                    for (i = 0, size /= 4; i < size; ++i)
+                    {
+                        rt_kprintf("0x%x ", fdt32_to_cpu(cell[i]));
+                    }
+                    rt_kputs("\b>");
+                }
+                else
+                {
+                    /* print bytes array */
+                    int i;
+                    uint8_t *byte = (uint8_t *)value;
+
+                    rt_kputs("[");
+                    for (i = 0; i < size; ++i)
+                    {
+                       rt_kprintf("%02x ", *byte++);
+                    }
+                    rt_kputs("\b]");
+                }
+            }
+            rt_kputs(";\n");
+            dtb_property = dtb_property->next;
+        }
+
+        _dtb_node_printf_dtb_node_info(dtb_node->child);
+        dtb_node = dtb_node->sibling;
+
+        --depth;
+        _dtb_node_printf_depth(depth);
+        rt_kputs("};\n");
+    }
+}
+
+void dtb_node_get_dts_dump(struct dtb_node *dtb_node_head)
+{
+    if (dtb_node_head != NULL)
+    {
+        int i = dtb_node_head->header->memreserve_sz;
+
+        rt_kputs("/dts-v1/;\n");
+        while (i --> 0)
+        {
+            rt_kprintf("\n/memreserve/\t0x%lx 0x%zx;", dtb_node_head->header->memreserve[i].address, dtb_node_head->header->memreserve[i].size);
+        }
+
+        _dtb_node_printf_dtb_node_info(dtb_node_head);
+    }
+}
+
+static void _dtb_node_get_enum_dtb_node(struct dtb_node *dtb_node, void (callback(struct dtb_node *dtb_node)))
+{
+    while (dtb_node != NULL)
+    {
+        callback(dtb_node);
+        _dtb_node_get_enum_dtb_node(dtb_node->child, callback);
+        dtb_node = dtb_node->sibling;
+    }
+}
+
+void dtb_node_get_enum_dtb_node(struct dtb_node *dtb_node_head, void (callback(struct dtb_node *dtb_node)))
+{
+    if (dtb_node_head == NULL || callback == NULL)
+    {
+        return;
+    }
+
+    _dtb_node_get_enum_dtb_node(dtb_node_head, callback);
+}
+
+struct dtb_node *dtb_node_get_dtb_node_by_name_DFS(struct dtb_node *dtb_node, const char *nodename)
+{
+    struct dtb_node *dtb_node_child;
+
+    while (dtb_node != NULL)
+    {
+        if (!strcmp(nodename, dtb_node->name))
+        {
+            return dtb_node;
+        }
+
+        dtb_node_child = dtb_node_get_dtb_node_by_name_DFS(dtb_node->child, nodename);
+
+        if (dtb_node_child != NULL)
+        {
+            return dtb_node_child;
+        }
+        dtb_node = dtb_node->sibling;
+    }
+
+    return NULL;
+}
+
+struct dtb_node *dtb_node_get_dtb_node_by_name_BFS(struct dtb_node *dtb_node, const char *nodename)
+{
+    if (dtb_node != NULL)
+    {
+        struct dtb_node *dtb_node_child, *dtb_node_head = dtb_node;
+
+        while (dtb_node != NULL)
+        {
+            if (!strcmp(nodename, dtb_node->name))
+            {
+                return dtb_node;
+            }
+            dtb_node = dtb_node->sibling;
+        }
+
+        dtb_node = dtb_node_head;
+
+        while (dtb_node != NULL)
+        {
+            dtb_node_child = dtb_node_get_dtb_node_by_name_BFS(dtb_node->child, nodename);
+
+            if (dtb_node_child != NULL)
+            {
+                return dtb_node_child;
+            }
+            dtb_node = dtb_node->sibling;
+        }
+    }
+
+    return NULL;
+}
+
+struct dtb_node *dtb_node_get_dtb_node_by_path(struct dtb_node *dtb_node, const char *pathname)
+{
+    int i = 0;
+    char *node_name;
+    char *pathname_clone;
+    int pathname_sz;
+
+    if (pathname == NULL || dtb_node == NULL)
+    {
+        return NULL;
+    }
+
+    /* skip '/' */
+    if (*pathname == '/')
+    {
+        ++pathname;
+    }
+
+    /* root not have sibling, so skip */
+    if (dtb_node->parent == NULL || !strcmp(dtb_node->path, "/"))
+    {
+        dtb_node = dtb_node->child;
+    }
+
+    pathname_sz = strlen(pathname) + 1;
+    pathname_clone = malloc(pathname_sz);
+    if (pathname_clone == NULL)
+    {
+        return NULL;
+    }
+    strncpy(pathname_clone, pathname, pathname_sz);
+    node_name = pathname_clone;
+
+    while (pathname_clone[i])
+    {
+        if (pathname_clone[i] == '/')
+        {
+            /* set an end of name that can used to strcmp */
+            pathname_clone[i] = '\0';
+
+            while (dtb_node != NULL)
+            {
+                if (!strcmp(dtb_node->name, node_name))
+                {
+                    break;
+                }
+                dtb_node = dtb_node->sibling;
+            }
+            if (dtb_node == NULL)
+            {
+                free(pathname_clone);
+                return NULL;
+            }
+            dtb_node = dtb_node->child;
+            node_name = &pathname_clone[i + 1];
+        }
+        ++i;
+    }
+
+    /*
+     *  found the end node and it's name:
+     *      (pathname[pathname_sz - 1]) is '\0'
+     *      (&pathname_clone[i] - node_name) is the node_name's length
+     */
+    node_name = &((char *)pathname)[(pathname_sz - 1) - (&pathname_clone[i] - node_name)];
+    free(pathname_clone);
+
+    while (dtb_node != NULL)
+    {
+        if (!strcmp(dtb_node->name, node_name))
+        {
+            return dtb_node;
+        }
+        dtb_node = dtb_node->sibling;
+    }
+
+    return NULL;
+}
+
+struct dtb_node *dtb_node_get_dtb_node_by_phandle_DFS(struct dtb_node *dtb_node, phandle handle)
+{
+    struct dtb_node *dtb_node_child;
+
+    while (dtb_node != NULL)
+    {
+        if (dtb_node->handle == handle)
+        {
+            return dtb_node;
+        }
+
+        dtb_node_child = dtb_node_get_dtb_node_by_phandle_DFS(dtb_node->child, handle);
+
+        if (dtb_node_child != NULL)
+        {
+            return dtb_node_child;
+        }
+        dtb_node = dtb_node->sibling;
+    }
+
+    return NULL;
+}
+
+struct dtb_node *dtb_node_get_dtb_node_by_phandle_BFS(struct dtb_node *dtb_node, phandle handle)
+{
+    if (dtb_node != NULL)
+    {
+        struct dtb_node *dtb_node_child, *dtb_node_head = dtb_node;
+
+        while (dtb_node != NULL)
+        {
+            if (dtb_node->handle == handle)
+            {
+                return dtb_node;
+            }
+            dtb_node = dtb_node->sibling;
+        }
+
+        dtb_node = dtb_node_head;
+
+        while (dtb_node != NULL)
+        {
+            dtb_node_child = dtb_node_get_dtb_node_by_phandle_BFS(dtb_node->child, handle);
+
+            if (dtb_node_child != NULL)
+            {
+                return dtb_node_child;
+            }
+            dtb_node = dtb_node->sibling;
+        }
+    }
+
+    return NULL;
+}
+
+void dtb_node_get_dtb_node_cells(struct dtb_node *dtb_node, int *addr_cells, int *size_cells)
+{
+    if (dtb_node != NULL && addr_cells != NULL && size_cells != NULL)
+    {
+        struct dtb_property *dtb_property;
+        *addr_cells = -1;
+        *size_cells = -1;
+
+        /* if couldn't found, check parent */
+        while ((dtb_node = dtb_node->parent) != NULL)
+        {
+            dtb_property = dtb_node->properties;
+            while (dtb_property != NULL)
+            {
+                if (!strcmp(dtb_property->name, "#address-cells"))
+                {
+                    *addr_cells = fdt32_to_cpu(*(int *)dtb_property->value);
+                }
+                else if (!strcmp(dtb_property->name, "#size-cells"))
+                {
+                    *size_cells = fdt32_to_cpu(*(int *)dtb_property->value);
+                }
+                if (*addr_cells != -1 && *size_cells != -1)
+                {
+                    return;
+                }
+                dtb_property = dtb_property->next;
+            }
+        }
+
+        if (*addr_cells == -1)
+        {
+            *addr_cells = FDT_ROOT_ADDR_CELLS_DEFAULT;
+        }
+        if (*size_cells == -1)
+        {
+            *size_cells = FDT_ROOT_SIZE_CELLS_DEFAULT;
+        }
+    }
+}
+
+struct dtb_memreserve *dtb_node_get_dtb_memreserve(struct dtb_node *dtb_node, int *memreserve_size)
+{
+    if (dtb_node != NULL && memreserve_size != NULL)
+    {
+        struct dtb_node *dtb_node_root = dtb_node;
+
+        while (dtb_node_root != NULL)
+        {
+            if (!strcmp(dtb_node_root->path, "/"))
+            {
+                break;
+            }
+            dtb_node_root = dtb_node_root->parent;
+        }
+
+        *memreserve_size = dtb_node_root->header->memreserve_sz;
+
+        return dtb_node_root->header->memreserve;
+    }
+    return NULL;
+}
+
+rt_bool_t dtb_node_get_dtb_node_status(const struct dtb_node *dtb_node)
+{
+    if (dtb_node != NULL)
+    {
+        char *status = dtb_node_get_dtb_node_property_value(dtb_node, "status", NULL);
+        if (status != NULL)
+        {
+            return (!strcmp(status, "okay") || !strcmp(status, "ok")) ? RT_TRUE : RT_FALSE;
+        }
+
+        return RT_TRUE;
+    }
+
+    return RT_FALSE;
+}
+
+rt_bool_t dtb_node_get_dtb_node_compatible_match(const struct dtb_node *dtb_node, const char *compatibles)
+{
+    if (dtb_node != NULL)
+    {
+        if (compatibles != NULL)
+        {
+            char *str_ptr;
+            int prop_sz;
+
+            for_each_property_string(dtb_node, "compatible", str_ptr, prop_sz)
+            {
+                if (!strcmp(compatibles, str_ptr))
+                {
+                    return RT_TRUE;
+                }
+            }
+        }
+    }
+
+    return RT_FALSE;
+}
+
+char *dtb_node_get_dtb_string_list_value(void *value, int size, int index)
+{
+    int i = 0;
+    char *str = value;
+
+    if (str != NULL)
+    {
+        do
+        {
+            if (i++ == index)
+            {
+                return str;
+            }
+            str += strlen(str) + 1;
+        } while (str < (char *)value + size);
+    }
+
+    return NULL;
+}
+
+char *dtb_node_get_dtb_string_list_value_next(void *value, void *end)
+{
+    char *str = value;
+
+    if (str != NULL)
+    {
+        str += strlen(str) + 1;
+        if (str < (char *)end)
+        {
+            return str;
+        }
+    }
+
+    return NULL;
+}
+
+uint32_t dtb_node_get_dtb_cell_value(void *value)
+{
+    return fdt32_to_cpu(*(fdt32_t *)value);
+}
+
+uint8_t dtb_node_get_dtb_byte_value(void *value)
+{
+    return *(uint8_t *)value;
+}

+ 41 - 0
components/drivers/fdt/src/dtb_head.c

@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "dtb_node.h"
+
+static void *dtb_root = NULL;
+static struct dtb_node *dtb_node_list = NULL;
+void *get_fdt_blob(void)
+{
+    return dtb_root;
+}
+
+struct dtb_node *get_dtb_node_head(void)
+{
+    return dtb_node_list;
+}
+
+rt_bool_t dtb_node_active(void)
+{
+    return dtb_node_list != NULL;
+}
+
+int device_tree_setup(void *mem_addr)
+{
+    if(mem_addr)
+    {
+        if ((dtb_root = dtb_node_load_from_memory(mem_addr,1)) != NULL)
+        {
+            dtb_node_list = dtb_node_get_dtb_list(dtb_root);
+            if (dtb_node_list != NULL)
+            {
+                return -1;
+            }
+        }
+        return 0;
+    }
+
+    return -1;
+}

+ 105 - 0
components/drivers/fdt/src/dtb_load.c

@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "libfdt.h"
+#include <unistd.h>
+#include "dtb_node.h"
+
+extern int fdt_exec_status;
+
+rt_bool_t dtb_node_check(void *fdt)
+{
+    return fdt_check_header(fdt) == 0 ? RT_TRUE : RT_FALSE;
+}
+
+void *dtb_node_load_from_fs(char *dtb_filename)
+{
+    void *fdt = NULL;
+    size_t dtb_sz;
+    int fd = -1;
+
+    if (dtb_filename == NULL)
+    {
+        fdt_exec_status = FDT_RET_GET_EMPTY;
+        goto end;
+    }
+
+    fd = open(dtb_filename, O_RDONLY, 0);
+
+    if (fd == -1)
+    {
+        rt_kprintf("File `%s' not found.\n", dtb_filename);
+        fdt_exec_status = FDT_RET_GET_EMPTY;
+        goto end;
+    }
+
+    dtb_sz = lseek(fd, 0, SEEK_END);
+
+    if (dtb_sz > 0)
+    {
+        if ((fdt = (struct fdt_header *)malloc(sizeof(uint8_t) * dtb_sz)) == NULL)
+        {
+            fdt_exec_status = FDT_RET_NO_MEMORY;
+            goto end;
+        }
+
+        lseek(fd, 0, SEEK_SET);
+        read(fd, fdt, sizeof(uint8_t) * dtb_sz);
+
+        if (dtb_node_check(fdt) == RT_FALSE)
+        {
+            free(fdt);
+        }
+    }
+
+end:
+    if (fd != -1)
+    {
+        close(fd);
+    }
+
+    return fdt;
+}
+
+void *dtb_node_load_from_memory(void *dtb_ptr, rt_bool_t is_clone)
+{
+    void *fdt = NULL;
+
+    if (dtb_ptr == NULL)
+    {
+        fdt_exec_status = FDT_RET_GET_EMPTY;
+        goto end;
+    }
+
+    if (dtb_node_check(dtb_ptr) == RT_FALSE)
+    {
+        fdt_exec_status = FDT_RET_GET_EMPTY;
+        fdt = NULL;
+        goto end;
+    }
+
+    if (is_clone)
+    {
+        size_t dtb_sz = fdt_totalsize(dtb_ptr);
+        if (dtb_sz > 0)
+        {
+            if ((fdt = malloc(dtb_sz)) != NULL)
+            {
+                memcpy(fdt, dtb_ptr, dtb_sz);
+            }
+            else
+            {
+                fdt_exec_status = FDT_RET_NO_MEMORY;
+            }
+        }
+    }
+    else
+    {
+        fdt = dtb_ptr;
+    }
+
+end:
+    return fdt;
+}

+ 166 - 0
components/drivers/fdt/src/dtb_set.c

@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "libfdt.h"
+#include "dtb_node.h"
+
+static off_t dtb_node_find_and_add_subnode(void *fdt, char* name)
+{
+    off_t chosen_offset = 0;
+
+    chosen_offset = fdt_subnode_offset(fdt, 0, name);
+
+    if (chosen_offset == -FDT_ERR_NOTFOUND)
+    {
+        chosen_offset = fdt_add_subnode(fdt, 0, name);
+    }
+
+    return chosen_offset;
+}
+
+size_t dtb_node_set_linux_cmdline(void *fdt, char *cmdline)
+{
+    off_t chosen_offset;
+    size_t cmdline_size;
+
+    if (cmdline == NULL || fdt == NULL)
+    {
+        goto end;
+    }
+
+    chosen_offset = dtb_node_find_and_add_subnode(fdt, "chosen");
+    cmdline_size = strlen(cmdline);
+
+    /* install bootargs */
+    if (chosen_offset >= 0 || chosen_offset == -FDT_ERR_EXISTS)
+    {
+        if (fdt_setprop(fdt, chosen_offset, "bootargs", cmdline, cmdline_size) < 0)
+        {
+            fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_DTB_PAD_SIZE);
+            fdt_setprop(fdt, chosen_offset, "bootargs", cmdline, cmdline_size);
+        }
+    }
+
+end:
+    return fdt_totalsize(fdt);
+}
+
+size_t dtb_node_set_linux_initrd(void *fdt, uint64_t initrd_addr, size_t initrd_size)
+{
+    uint64_t addr, size_ptr;
+    off_t chosen_offset;
+    int i;
+
+    if (fdt == NULL)
+    {
+        goto end;
+    }
+
+    chosen_offset = dtb_node_find_and_add_subnode(fdt, "chosen");
+
+    /* update the entry */
+    for (i = fdt_num_mem_rsv(fdt) - 1; i >= 0; --i)
+    {
+        fdt_get_mem_rsv(fdt, i, &addr, &size_ptr);
+        if (addr == initrd_addr)
+        {
+            fdt_del_mem_rsv(fdt, i);
+            break;
+        }
+    }
+
+    /* add the memory */
+    if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0)
+    {
+        /* move the memory */
+        fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_DTB_PAD_SIZE);
+        if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0)
+        {
+            goto end;
+        }
+    }
+
+    /* install initrd */
+    if (chosen_offset >= 0 || chosen_offset == -FDT_ERR_EXISTS)
+    {
+        chosen_offset = fdt_path_offset(fdt, "/chosen");
+
+        if (IN_64BITS_MODE)
+        {
+            fdt_setprop_u64(fdt, chosen_offset, "linux,initrd-start", initrd_addr);
+            fdt_setprop_u64(fdt, chosen_offset, "linux,initrd-end", initrd_addr + initrd_size);
+        }
+        else
+        {
+            fdt_setprop_u32(fdt, chosen_offset, "linux,initrd-start", initrd_addr);
+            fdt_setprop_u32(fdt, chosen_offset, "linux,initrd-end", initrd_addr + initrd_size);
+        }
+    }
+
+end:
+    return fdt_totalsize(fdt);
+}
+
+size_t dtb_node_set_dtb_property(void *fdt, char *pathname, char *property_name, uint32_t *cells, size_t cells_size)
+{
+    int node_off;
+
+    if (fdt == NULL)
+    {
+        goto end;
+    }
+
+    node_off = fdt_path_offset(fdt, pathname);
+
+    if (node_off >= 0 && cells_size != 0)
+    {
+        fdt_setprop(fdt, node_off, property_name, cells, cells_size);
+    }
+
+end:
+    return fdt_totalsize(fdt);
+}
+
+size_t dtb_node_add_dtb_memreserve(void *fdt, uint64_t address, uint64_t size)
+{
+    if (fdt == NULL)
+    {
+        goto end;
+    }
+
+    fdt_add_mem_rsv(fdt, address, size);
+
+end:
+    return fdt_totalsize(fdt);
+}
+
+size_t dtb_node_del_dtb_memreserve(void *fdt, uint64_t address)
+{
+    int i;
+    int num_mem_rsvmap;
+    uint32_t off_mem_rsvmap;
+    struct fdt_reserve_entry *rsvmap;
+
+    if (fdt == NULL)
+    {
+        goto end;
+    }
+
+    num_mem_rsvmap = fdt_num_mem_rsv(fdt);
+    off_mem_rsvmap = fdt_off_mem_rsvmap(fdt);
+    rsvmap = (struct fdt_reserve_entry *)((char *)fdt + off_mem_rsvmap);
+
+    for (i = 0; i < num_mem_rsvmap; ++i)
+    {
+        if (address == fdt64_to_cpu(rsvmap[i].address))
+        {
+            fdt_del_mem_rsv(fdt, i);
+            break;
+        }
+    }
+
+end:
+    return fdt_totalsize(fdt);
+}

+ 14 - 10
src/driver.c

@@ -5,7 +5,7 @@
  */
 
 #include <rtthread.h>
-#ifdef PKG_USING_FDT
+#ifdef RT_USING_FDT
 #include <dtb_node.h>
 #endif
 #if defined(RT_USING_POSIX)
@@ -48,7 +48,7 @@ rt_err_t rt_driver_match_with_id(const rt_driver_t drv,int device_id)
 
 RTM_EXPORT(rt_driver_match_with_id);
 
-#ifdef PKG_USING_FDT
+#ifdef RT_USING_FDT
 /**
  * This function driver device match with dtb_node
  *
@@ -63,8 +63,8 @@ rt_err_t rt_driver_match_with_dtb(const rt_driver_t drv,void *from_node,int max_
     struct dtb_node** node_list; 
     rt_device_t device;
     int ret,i;
-    int active_dev_num = 0;
-    if ((!drv)||(!drv->dev_match)||(!drv->dev_match->compatible)||(!from_node))
+    int total_dev_num = 0;
+    if ((!drv)||(!drv->dev_match)||(!drv->dev_match->compatible)||(!from_node)||(!drv->device_size)||(!drv->device_priv_data_size))
     {
         return -RT_EINVAL;
     }
@@ -75,29 +75,33 @@ rt_err_t rt_driver_match_with_dtb(const rt_driver_t drv,void *from_node,int max_
         return -RT_ERROR;
     }
 
-    ret = dtb_node_find_all_active_compatible_node(from_node,drv->dev_match->compatible,node_list,max_dev_num,&active_dev_num);
-    if((ret != 0) || (!active_dev_num))
+    ret = dtb_node_find_all_compatible_node(from_node,drv->dev_match->compatible,node_list,max_dev_num,&total_dev_num);
+    if((ret != 0) || (!total_dev_num))
     {
         return -RT_ERROR;
     }
     
-    for(i = 0; i < active_dev_num; i ++)
+    for(i = 0; i < total_dev_num; i ++)
     {
+        if (!dtb_node_device_is_available(node_list[i]))
+        {
+            continue;
+        }
         device = rt_device_create_since_driver(drv,i);
         if(!device)
         {
-            return -RT_ERROR;
+            continue;
         }
     
         ret = rt_device_bind_driver(device,drv,node_list[i]);
         if(ret != 0)
         {
-            return -RT_ERROR;
+            continue;
         }
         ret = rt_device_probe_and_init(device);
         if(ret != 0)
         {
-            return -RT_ERROR;
+            continue;
         }
     }
     rt_free(node_list);