powerpc linux下dts解析过程

PHY设备驱动综合分析 PHY设备驱动分析 声明: 使用原创资料较多就不一一列举,望海涵。我原创也不少咯。 MAC和PHY可能是集成在CPU中可能独立,下图介绍典型的MAC集成,PHY独立。两者搭配实现网卡功能。 struct phy_device { struct phy_driver *drv; //PHY设备驱动 struct mii_bus *bus; //对应的MII总线 struct device dev; ... 阅读详情

一. 在linux中,对dtb文件解析的整个过程序如下:

1)首先将从u-boot 传递过来的映像基地址和dtb 文件映像基地址保存通用寄存器r30,r31;
2)通过调用machine_init()、early_init_devtree()函数来获取内核前期初始化所需的bootargs,cmd_line等系统引导参数;
3)调用start_kernel()、setup_arch()、unflatten_device_tree()函数来解析dtb 文件,构建一个由device_node 结构连接而成的单项链表,并使用全局变量allnodes 指针来保存这个链表的头指针;如下在此函数执行过后,在内存中会存在一个如下的链表,后面所有的函数,如果需要从of tree结构上读取设备资料的,都将从这个链表中遍历并读取。


4)内核调用OF 提供的API 函数获取allnodes链表信息来初始化内核其他子系统、设备等。(of_flatform_device)

 二、dts文件首地址解析

在进行DTS文件解析之前先要从bootm启动命令中获取dtb文件所在的地址。而这一步的开始是从arch/powerpc/kernel/head_32.s文件开始中的。

1、arch/powerpc/kernel/head_32.s

 * This is where the main kernel code starts.
 */
start_here:
/* ptr to current */
lis r2,init_task@h
ori r2,r2,init_task@l
/* Set up for using our exception vectors */
/* ptr to phys current thread */
tophys(r4,r2)
addi r4,r4,THREAD /* init task's THREAD */
CLR_TOP32(r4)
mtspr SPRN_SPRG_THREAD,r4
li r3,0
mtspr SPRN_SPRG_RTAS,r3 /* 0 => not in RTAS */
/* stack */
lis r1,init_thread_union@ha
addi r1,r1,init_thread_union@l
li r0,0
stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
/*
 * Do early platform-specific initialization,
 * and set up the MMU.
 */
mr r3,r31
mr r4,r30
bl machine_init  //在这个函数中
bl __save_cpu_setup
bl MMU_init



notrace void __init machine_init(unsigned long dt_ptr)
{
lockdep_init();


/* Enable early debugging if any specified (see udbg.h) */
udbg_early_init();


/* Do some early initialization based on the flat device tree */
early_init_devtree(__va(dt_ptr));



probe_machine();


setup_kdump_trampoline();


#ifdef CONFIG_6xx
if (cpu_has_feature(CPU_FTR_CAN_DOZE) ||
   cpu_has_feature(CPU_FTR_CAN_NAP))
ppc_md.power_save = ppc6xx_idle;
#endif


#ifdef CONFIG_E500
if (cpu_has_feature(CPU_FTR_CAN_DOZE) ||
   cpu_has_feature(CPU_FTR_CAN_NAP))
ppc_md.power_save = e500_idle;
#endif
if (ppc_md.progress)
ppc_md.progress("id mach(): done", 0x200);
}


void __init early_init_devtree(void *params)
{
phys_addr_t limit;


DBG(" -> early_init_devtree(%p)\n", params);


/* Setup flat device-tree pointer */
initial_boot_params = params;


#ifdef CONFIG_PPC_RTAS
/* Some machines might need RTAS info for debugging, grab it now. */
of_scan_flat_dt(early_init_dt_scan_rtas, NULL);
#endif


#ifdef CONFIG_PHYP_DUMP
/* scan tree to see if dump occured during last boot */
of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL);
#endif


/* Retrieve various informations from the /chosen node of the
* device-tree, including the platform type, initrd location and
* size, TCE reserve, and more ...
*/
of_scan_flat_dt(early_init_dt_scan_chosen, NULL);


/* Scan memory nodes and rebuild LMBs */
lmb_init();
of_scan_flat_dt(early_init_dt_scan_root, NULL);
of_scan_flat_dt(early_init_dt_scan_memory, NULL);


/* Save command line for /proc/cmdline and then parse parameters */
strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE);
parse_early_param();


/* Reserve LMB regions used by kernel, initrd, dt, etc... */
lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
/* If relocatable, reserve first 32k for interrupt vectors etc. */
if (PHYSICAL_START > MEMORY_START)
lmb_reserve(MEMORY_START, 0x8000);
reserve_kdump_trampoline();
reserve_crashkernel();
early_reserve_mem();
phyp_dump_reserve_mem();


limit = memory_limit;
if (! limit) {
phys_addr_t memsize;


/* Ensure that total memory size is page-aligned, because
* otherwise mark_bootmem() gets upset. */
lmb_analyze();
memsize = lmb_phys_mem_size();
if ((memsize & PAGE_MASK) != memsize)
limit = memsize & PAGE_MASK;
}
lmb_enforce_memory_limit(limit);


lmb_analyze();
lmb_dump_all();


DBG("Phys. mem: %llx\n", lmb_phys_mem_size());


/* We may need to relocate the flat tree, do it now.
* FIXME .. and the initrd too? */
move_device_tree();


DBG("Scanning CPUs ...\n");


/* Retreive CPU related informations from the flat tree
* (altivec support, boot CPU ID, ...)
*/
of_scan_flat_dt(early_init_dt_scan_cpus, NULL);


DBG(" <- early_init_devtree()\n");
}

三、解析

main.c-------------->arch/pwerpc/kernel/setup_32.c-------------->arch/powerpc/kernel/prom.c

start_kernel()------>setup_arch()---------->unflatten_device_tree()

/**
 * unflattens the device-tree passed by the firmware, creating the
 * tree of struct device_node. It also fills the "name" and "type"
 * pointers of the nodes so the normal device-tree walking functions
 * can be used (this used to be done by finish_device_tree)
 */
void __init unflatten_device_tree(void)
{
unsigned long start, mem, size;
struct device_node **allnextp = &allnodes;


DBG(" -> unflatten_device_tree()\n");


/* First pass, scan for size */
start = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
size = unflatten_dt_node(0, &start, NULL, NULL, 0);
size = (size | 3) + 1;


DBG("  size is %lx, allocating...\n", size);


/* Allocate memory for the expanded device tree */
mem = lmb_alloc(size + 4, __alignof__(struct device_node));
mem = (unsigned long) __va(mem);


((u32 *)mem)[size / 4] = 0xdeadbeef;


DBG("  unflattening %lx...\n", mem);


/* Second pass, do actual unflattening */
start = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
if (*((u32 *)start) != OF_DT_END)
printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start));
if (((u32 *)mem)[size / 4] != 0xdeadbeef)
printk(KERN_WARNING "End of tree marker overwritten: %08x\n",
      ((u32 *)mem)[size / 4] );
*allnextp = NULL;


/* Get pointer to OF "/chosen" node for use everywhere */
of_chosen = of_find_node_by_path("/chosen");
if (of_chosen == NULL)
of_chosen = of_find_node_by_path("/chosen@0");


DBG(" <- unflatten_device_tree()\n");
}

四. 将allnodes显示在/proc/device-tree目录下

start_kernel() --> 
#ifdef CONFIG_PROC_FS
proc_root_init(); --> 
#endif
#ifdef CONFIG_PROC_DEVICETREE
proc_device_tree_init(); --> 
#endif


proc_device_tree_add_node(root, proc_device_tree);

此时将在/proc/device-tree目录下生成设备节点
# ls -al /proc/device-tree

五. of_platform_bus_type的注册/初始化 

-------------------------------------------------------------------
arch/powerpc/kernel/of_platform.c
struct bus_type  of_platform_bus_type  = {
       .uevent   = of_device_uevent,
};
EXPORT_SYMBOL(of_platform_bus_type);

static int __init of_bus_driver_init(void)
{
   return of_bus_type_init(&of_platform_bus_type, "of_platform");
}
postcore_initcall(of_bus_driver_init);

of_platform_bus_type总线注册完毕。
此时/sys/bus/目录下将会有of_platform


六. 将allnodes设备节点添加到总线of_platform_bus_type

-------------------------------------------------------------------
arch/powerpc/platform/85xx/mpc85Xx_ads.c

static int __init declare_of_platform_devices(void)
{
of_platform_bus_probe(NULL, of_bus_ids, NULL);


return 0;
}
machine_device_initcall(mpc85xx_ads, declare_of_platform_devices);

declare_of_platform_devices() --> of_platform_bus_probe(NULL, of_bus_ids, NULL)

arch/powerpc/kernel/of_platform.c
遍历第一步中在内存中生成链表的所有soc的子节点,将所有的soc子节点设备添加到of_platform总线。
int of_platform_bus_probe(struct device_node *root,
 const struct of_device_id *matches,
 struct device *parent)
{
struct device_node *child;
struct of_device *dev;
int rc = 0;


if (matches == NULL)
matches = of_default_bus_ids;
if (matches == OF_NO_DEEP_PROBE)
return -EINVAL;
if (root == NULL)
root = of_find_node_by_path("/");
else
of_node_get(root);


pr_debug("of_platform_bus_probe()\n");
pr_debug(" starting at: %s\n", root->full_name);


/* Do a self check of bus type, if there's a match, create
* children
*/
if (of_match_node(matches, root)) {
pr_debug(" root match, create all sub devices\n");
dev = of_platform_device_create(root, NULL, parent);
if (dev == NULL) {
rc = -ENOMEM;
goto bail;
}
pr_debug(" create all sub busses\n");
rc = of_platform_bus_create(root, matches, &dev->dev);
goto bail;
}
for_each_child_of_node(root, child) {
if (!of_match_node(matches, child))
continue;


pr_debug("  match: %s\n", child->full_name);
dev = of_platform_device_create(child, NULL, parent);
if (dev == NULL)
rc = -ENOMEM;
else
rc = of_platform_bus_create(child, matches, &dev->dev);
if (rc) {
of_node_put(child);
break;
}
}
 bail:
of_node_put(root);
return rc;
}
EXPORT_SYMBOL(of_platform_bus_probe);
--> of_platform_device_create--> of_device_register() --> device_add()

of_platform总线上的所有设备添加完毕,e0024000.ethernet,e0024520.mdio等设备现在都在总线上。至此设备节点将出现在/sys/devices/platform/

    

七、实例

 1、mdio总线的注册

/driver/net/phy_device.c

subsys_initcall(phy_init)
phy_init --> mdio_bus_init --> bus_register(&mdio_bus_type)

总线注册后,在总线上注册了一个默认的phy的驱动 genphy_driver:

.phy_id      = 0xffffffff,
.phy_id_mask = 0xffffffff,
.name        = "Generic phy",

mdio总线注册完毕。
/sys/bus/mdio


2、 mdio总线上驱动的添加
--------------------------------------------

/driver/net/phy/marvell.c
module_init(marvell_init)
marvell_init() --> 
phy_driver_register(&marvell_drivers[i]) --> 
driver_register()

前面第三步,注册mdio总线后,已经添加了一个默认的phy的驱动,现在要将所有的phy驱动添加到总线上,这里将所有的marvell的phy都添加。

这步过后,内核的/sys/bus/mdio/driver里面就有了各种phy的驱动,但这时还没有和具体的设备绑定。


3、 of_platform总线上mdio设备驱动(该驱动的目的是在mdio总线上添加phy设备)的添加,并绑定设备:e0024520.mdio和e0025520.mdio

/driver/net/fsl_pq_mdio.c
module_init(fsl_pq_mdio_init)
fsl_pq_mdio_init --> of_register_platform_driver(&fsl_pq_mdio_driver) --> of_register_driver --> driver_register --> bus_add_driver --> driver_attach

遍历整个of_platform总线,寻找与之相匹配的设备,找到e0024520.mdio
driver_attach --> __driver_attach --> driver_match_device
将driver的match_table里的信息和dev_nod中的做比较,若符合就进入driver的probe,也就是fsl_pq_mdio_probe。

现在of_platform总线上的设备e0024520.mdio和e0025520.mdio已经绑定了驱动。
4、 mdio总线上的设备的添加,寻找并绑定相应的驱动。
/driver/net/fsl_pq_mdio.c
fsl_pq_mdio_probe --> of_mdiobus_register --> phy_device_register --> device_register(&phydev->dev) --> device_add --> bus_probe_device --> device_attach -->bus_for_each_drv
扫描mdio总线上的所有的驱动,若找到匹配的,就绑定,并probe。
__device_attach --> driver_probe_device --> really_probe --> phy_probe

将所有的phy和tbi-phy的设备都添加到mdio总线上,并且两个phy设备和两个tbi-phy设备都会根据其自己的phyID找到各自的驱动

dts 编译过程_linux设备树dts移植详解 【转】摘 要:设备树的引入减少了内核为支持新硬件而需要的改变,提高代码重用,加速了Linux支持包的开发,使得单个内核镜像能支持多个系统。作为U-Boot 和Linux 内核之间的动态接口,本文阐述了设备树的数据存储格式以及源码描述语法,进而分析了U-Boot 对扁平设备树的支持设置,Linux 内核对设备树的解析流程。关键词:扁平设备树; DTS; PowerPC; LinuxIBM、Sun 等... 阅读详情

相关推荐

Linux ARM平台开发系列讲解(网络篇)1.5 MDIO总线设备phy driver中phy ID的定义

中的定义又与有所不同,需要开发者自行定义,然后设备会自动去匹配设备,具体匹配流程可以看前几章节,这里就不扩展了。由于中需要手动去定义,所以需要用户去仔细查看数据手册并填写进去,这样和才会匹配成功,具体设置就是在初始化时,对进行赋值,具体方法如下:以设备 为例 源码路径: 返回总目录...

DSMGUOGUO的博客 1954

Linux设备树学习3 - __unflatten_device_tree分析

linux device tree device_node树构建分析

to_be_better_wen的博客 1147

Linux内存管理(14):unflatten_device_tree 详解

对于 debug 版本若通过节点查看,会发现很多细小的reserved hole。在之前《reserved-memory 详解》一文中分析了dts 中 reserved-memory 部分的内存 reserved 过程,这些内存都是工程师根据平台需要定义好的。在《paging_init 详解》一文中在进行 map_kernel 和 map_mem 映射时创建了很多的页表,系统将这部分的内存也当成了 reserved memory。本文将继上面分析系统 reserved 的另一块细小的 memory。

私房菜 912

Powerpc构架系统内核和内核模块调试

作者:易松华,华清远见嵌入式学院深圳中心讲师。说明:此文档的目标系统为freescale MPC8349E-mITX,对其他采用POWERPC,MIPS,ARM的芯片的系统亦具有参考意义。 此文档中内核调试为了简化,采用目标系统中的UBOOT初始化目标板,并通过UBOOT或者BDI2000加载内核到目标板的RAM中。1. BDI2000配置:下面是MPC8349E-mITX的B

farsightliuht的专栏 1105

linux设备树dtspowerpc 平台解析过程

一. 在linux中,对dtb文件解析的整个过程序如下: 1)首先将从u-boot 传递过来的映像基地址和dtb 文件映像基地址保存通用寄存器r30,r31; 2)通过调用machine_init()、early_init_devtree()函数来获取内核前期初始化所需的bootargs,cmd_line等系统引导参数; 3)调用start_kernel()、setup_arch()、unf

Jkf40622的专栏 2753

PowerPC的PCI总线的dts配置【转】

powerpc使用称为FDT 扁平设备描述树的机制传递给内核硬件配置参数,从而引导内核。 这样的优势是PowerPCLinux上的移植基本上都是对dts文件的修改,而升级内核的工作量远远小于其他cpu体系结构。 只是目前介绍FDT或者OPEN Firmware的中文资料欠缺,这里记录我领悟的关于PCI总线树部分的ranges参数。 pci0: pci@e0008500 { in

zjy900507的博客 2284

linux设备树dts移植详解

【转】 摘 要:设备树的引入减少了内核为支持新硬件而需要的改变,提高代码重用,加速了Linux 支持包的开发,使得单个内核镜像能支持多个系统。作为U-Boot 和Linux 内核之间的动态 接口,本文阐述了设备树的数据存储格式以及源码描述语法,进而分析了U-Boot 对扁平设 备树的支持设置,Linux 内核对设备树的解析流程。 关键词:扁平设备树; DTS; PowerPC; Linu

cosmoslhf的专栏 5万+

linux的dst设备树,Linux设备树dts移植详解

摘 要:设备树的引入减少了内核为支持新硬件而需要的改变,提高代码重用,加速了Linux支持包的开发,使得单个内核镜像能支持多个系统。作为U-Boot 和Linux 内核之间的动态接口,本文阐述了设备树的数据存储格式以及源码描述语法,进而分析了U-Boot 对扁平设备树的支持设置,Linux 内核对设备树的解析流程。关键词:扁平设备树; DTS; PowerPC; LinuxIBM、Sun 等厂家的...

weixin_32115669的博客 677

powerPC的PCI总线的dts配置

powerpc使用称为FDT 扁平设备描述树的机制传递给内核硬件配置参数,从而引导内核。 这样的优势是PowerPCLinux上的移植基本上都是对dts文件的修改,而升级内核的工作量远远小于其他cpu体系结构。   只是目前介绍FDT或者OPEN Firmware的中文资料欠缺,这里记录我领悟的关于PCI总线树部分的ranges参数。   pci0: pci@e0

Bean Huo 1242

powerpc 设备树dts 详解

原文地址:http://blog.chinaunix.net/uid-26675482-id-3358038.html 摘 要:设备树的引入减少了内核为支持新硬件而需要的改变,提高代码重用,加速了Linux 支持包的开发,使得单个内核镜像能支持多个系统。作为U-Boot 和Linux 内核之间的动态 接口,本文阐述了设备树的数据存储格式以及源码描述语法,进而分析了U-Boot 对扁平设 备

风之伤 3844

【嵌入式Linux学习七步曲之第三篇 Linux系统bootlaoder移植】全面解析PowerPC架构下的扁平设备树FDT

全面解析PowerPC架构下的扁平设备树FDTSailor_forever  sailing_9806#163.com(本原创文章发表于Sailor_forever 的个人blog,未经本人许可,不得用于商业用途。任何个人、媒体、其他网站不得私自抄袭;网络媒体转载请注明出处,增加原文链接,否则属于侵权行为。如有任何问题,请留言或者发邮件给sailing_9806@163.com

Sailor_forever 1万+

全面解析PowerPC架构下的扁平设备树FDT

全面解析PowerPC架构下的扁平设备树FDT Sailor_forever  sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人blog,未经本人许可,不得用于商业用途。任何个人、媒体、其他网站不得私自抄袭;网络媒体转载请注明出处,增加原文链接,否则属于侵权行为。如有任何问题,请留言或者发邮件给sailing_9806@163.com)

若水心境的专栏 1949

linux 移植 内存 配置,linux设备树dts一之移植详解

http://blog.csdn.net/cosmoslhf/article/details/9252509摘 要:设备树的引入减少了内核为支持新硬件而需要的改变,提高代码重用,加速了Linux支持包的开发,使得单个内核镜像能支持多个系统。作为U-Boot 和Linux 内核之间的动态接口,本文阐述了设备树的数据存储格式以及源码描述语法,进而分析了U-Boot 对扁平设备树的支持设置,Linux ...

weixin_31910545的博客 836

powerpc linux 设备树解析

转载自:http://www.kaixinwenda.com/article-jackyard-8518304.html 一. 在linux中,对dtb文件解析的整个过程序如下: 1)首先将从u-boot 传递过来的映像基地址和dtb 文件映像基地址保存通用寄存器r30,r31; 2)通过调用machine_init()、early_init_devtree()函数来获取内核前期

1769

全面解析PowerPC架构下的扁平设备树FDT(ZT)

Sailor_forever sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人blog,未经本人许可,不得用于商业用途。任何个人、媒体、其他网站不得私自抄袭;网络媒体转载请注明出处,增加原文链接,否则属于侵权行为。如有任何问题,请留言或者发邮件给sailing_9806@163.com) http://blog.csdn.net/sailo...

fanrey123的博客 1121

别再硬编码了!用设备树DTS管理Linux硬件,一个.dts文件搞定一块板子

本文深入探讨了设备树(DTS)在现代Linux嵌入式开发中的关键作用,展示了如何通过.dts文件高效管理硬件配置。从硬编码到设备树的转变,不仅实现了内核与硬件的解耦,还提升了配置的灵活性和可维护性。文章详细介绍了设备树的结构、工具链(如DTC编译器)以及实战编写技巧,帮助开发者快速掌握这一核心技术。

weixin_30564901的博客 467

嵌入式 PowerPC Linux 平台扁平设备树FDT解析

嵌入式 PowerPC Linux 平台扁平设备树FDT解析      摘 要:设备树的引入减少了内核为支持新硬件而需要的改变,提高代码重用,加速了Linux支持包的开发,使得单个内核镜像能支持多个系统。作为U-Boot 和Linux内核之间的动态接口,本文阐述了设备树的数据存储格式以及源码描述语法,进而分析了U-Boot对扁平设备树的支持设置,Linux内核对设 备树的解析流程。

ermuzhi的专栏 4556
上一篇: Uboot启动参数说明
下一篇: Uboot 2012.10移植到at91sam9260ek草稿之一
Bean Huo
博客等级 码龄18年 40粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值