文章目录
- 1、介绍
- 2、设备树的获取与设置
- 3、uboot如何获取dtb
- 4、uboot设备树接口
1、介绍
uboot的设备树可以在uboot运行过程中进行一些配置,uboot可以根据配置,选择不同的设备树,这种方式在已经在armLinux kernel中和pc端已经应用了一段时间了。
fdt非常的易用,通过节点和属性进行设备的配置,通过分层的进行设备的管理。当有好几种不同的板子的时候,可以使用同一套源码,仅修改一下设备树就可以完成对板级硬件的匹配。
2、设备树的获取与设置
设备树可以通过kernel源码进行获取,uboot引导kernel启动,kernel中的设备树放到uboot 中也是可以直接运行使用的。
通过以下代码进行配置设备树
#define CONFIG_DEFAULT_DEVICE_TREE “”
设备树通过编译,可以编译至uboot的尾部、也可以嵌入在uboot当中。另外的还可以通过设置fdtcontroladdr环境变量,使设备树加载在某一地址当中,通过这种方式可以通过板级信息进行加载不同的设备树,达到相同代码,不同板子的适配目的。
3、uboot如何获取dtb
[common/board_f.c]
static init_fnc_t init_sequence_f[] = {
···
#ifdef CONFIG_OF_CONTROL
fdtdec_setup,//获取设备树地址
#endif
···
#ifdef CONFIG_OF_CONTROL
fdtdec_prepare_fdt,//判断设备树地址是否正确
#endif
···
reserve_fdt,//为fdt分配内存
···
reloc_fdt,//重载fdt
···
NULL,
};
以上是board_init_f当中对于fdt的操作。
int fdtdec_setup(void)
{
#if CONFIG_IS_ENABLED(OF_CONTROL)
# ifdef CONFIG_OF_EMBED
/* Get a pointer to the FDT */
gd->fdt_blob = __dtb_dt_begin;//如果使用
# elif defined CONFIG_OF_SEPARATE
# ifdef CONFIG_SPL_BUILD
/* FDT is at end of BSS unless it is in a different memory region */
if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))
gd->fdt_blob = (ulong *)&_image_binary_end;
else
gd->fdt_blob = (ulong *)&__bss_end;
# else
/* FDT is at end of image */
gd->fdt_blob = (ulong *)&_end;
# endif
# elif defined(CONFIG_OF_HOSTFILE)
if (sandbox_read_fdt_from_file()) {
puts("Failed to read control FDT\n");
return -1;
}
# endif
# ifndef CONFIG_SPL_BUILD
/* Allow the early environment to override the fdt address */
gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
(uintptr_t)gd->fdt_blob);
# endif
#endif
return fdtdec_prepare_fdt();
}
int fdtdec_prepare_fdt(void)
{
if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
fdt_check_header(gd->fdt_blob)) {
···//如果有错则打印一些信息,主要进行以上的判断
return -1;
}
return 0;//如果无错误,则直接返回0
}
对设备树的地址进行判断,检查设备树的头,确认设备树正确。
4、uboot设备树接口
gd->fdt_blob已经设置成了dtb的地址了。
注意,fdt提供的接口都是以gd->fdt_blob(dtb的地址)为参数的。
以下只简单说明几个接口的功能。
另外,用节点在dtb中的偏移地址来表示一个节点。也就是节点变量node中,存放的是节点的偏移地址
- lib/fdtdec.c中
- fdt_path_offset
int fdt_path_offset(const void *fdt, const char *path)
eg:node = fdt_path_offset(gd->fdt_blob, “/aliases”);
功能:获得dtb下某个节点的路径path的偏移。这个偏移就代表了这个节点。 - fdt_getprop
const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name, int *lenp)
eg: mac = fdt_getprop(gd->fdt_blob, node, “mac-address”, &len);
功能:获得节点node的某个字符串属性值。 - fdtdec_get_int_array、fdtdec_get_byte_array
int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, u32 *array, int count)
eg: ret = fdtdec_get_int_array(blob, node, “interrupts”, cell, ARRAY_SIZE(cell));
功能:获得节点node的某个整形数组属性值。 - fdtdec_get_addr
fdt_addr_t fdtdec_get_addr(const void *blob, int node, const char *prop_name)
eg:fdtdec_get_addr(blob, node, “reg”);
功能:获得节点node的地址属性值。 - fdtdec_get_config_int、fdtdec_get_config_bool、fdtdec_get_config_string
功能:获得config节点下的整形属性、bool属性、字符串等等。 - fdtdec_get_chosen_node
int fdtdec_get_chosen_node(const void *blob, const char *name)
功能:获得chosen下的name节点的偏移 - fdtdec_get_chosen_prop
const char *fdtdec_get_chosen_prop(const void *blob, const char *name)
功能:获得chosen下name属性的值
- lib/fdtdec_common.c中
- fdtdec_get_int
int fdtdec_get_int(const void *blob, int node, const char *prop_name, int default_val)
eg: bus->udelay = fdtdec_get_int(blob, node, “i2c-gpio,delay-us”, DEFAULT_UDELAY);
功能:获得节点node的某个整形属性值。 - fdtdec_get_uint
功能:获得节点node的某个无符号整形属性值。
以上的接口配合uboot的设备驱动模型,驱动开发会简单很多,后期再具体分析一个通过设备树开发的驱动。