基于335X的UBOOT网口驱动分析

基于335X的UBOOT网口驱动分析

一、软硬件平台资料

1、  开发板:创龙AM3359核心板,网口采用RMII形式

2、  UBOOT版本:U-Boot-2016.05,采用FDT和DM。

参考链接:

https://blog.csdn.net/hahachenchen789/article/details/53339181

二、网口相关代码位置

1、  网口的PINMUX设置

RMII接口的相关PINMUX在MLO中进行设置,具体的设置代码为
|-board_init_f

  |-board_early_init_f

|-set_mux_conf_regs

  |-enable_board_pin_mux

    configure_module_pin_mux(rmii1_pin_mux);

2、DTS文件中的CPSW的配置

&cpsw_emac0 {
phy_id = <&davinci_mdio>, <0x12>;  //phy_id【1】为初始的phy_addr,为SW的PORT2口的ADDR。
phy-mode = "rmii";       //RMII 模式
};

&mac {                                               //未使用此处配置
slaves = <1>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&cpsw_default>;
pinctrl-1 = <&cpsw_sleep>;
status = "okay";
};

&phy_sel {
rmii-clock-ext;   //RMII模式的时钟为外部时钟
};

&davinci_mdio {                                 //未使用此处配置
pinctrl-names = "default", "sleep";
pinctrl-0 = <&davinci_mdio_default>;
pinctrl-1 = <&davinci_mdio_sleep>;
status = "okay";
reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
reset-delay-us = <2>; /* PHY datasheet states 1uS min */
};

3、  网口的初始化设置

     网口的初始化在UBOOT中进行,具体设置代码为

     |-board_init_r

       |-init_sequence_r

         |-initr_net

           |- eth_initialize   (eth-uclass.c)

三、有关网口的DM&FDT分析

1、  驱动实现方式

此版本的UBOOT中使用了FDT文件进行外设的相关配置,驱动模型使用了DM方式,有关FDT以及DM相关的知识请参考如下文章

https://blog.csdn.net/ooonebook/article/details/53206623

https://blog.csdn.net/ooonebook/article/details/53234020

2、  UBOOT中DM初始化

DM的初始化

.创建根设备root的udevice,存放在gd->dm_root中。

.根设备其实是一个虚拟设备,主要是为uboot的其他设备提供一个挂载点。

.初始化uclass链表gd->uclass_root

DM中udevice和uclass的解析

.udevice的创建和uclass的创建

.udevice和uclass的绑定

.uclass_driver和uclass的绑定

.driver和udevice的绑定

.部分driver函数的调用

(1)DM初始化调用过程

dm初始化的接口在dm_init_and_scan中。 可以发现在uboot relocate之前的initf_dm和之后的initr_dm都调用了这个函数。

static int initf_dm(void)

{

#if defined(CONFIG_DM) && defined(CONFIG_SYS_MALLOC_F_LEN)

    int ret;

    ret = dm_init_and_scan(true); // 调用dm_init_and_scan对DM进行初始化和设备的解析

    if (ret)

        return ret;

#endif

    return 0;

}

#ifdef CONFIG_DM

static int initr_dm(void)

{

    int ret;

    /* Save the pre-reloc driver model and start a new one */

    gd->dm_root_f = gd->dm_root; // 存储relocate之前的根设备

    gd->dm_root = NULL;

    ret = dm_init_and_scan(false); // 调用dm_init_and_scan对DM进行初始化和设备的解析

    if (ret)

        return ret;

    return 0;

}

#endif

主要区别在于参数。

首先说明一下dts节点中的“u-boot,dm-pre-reloc”属性,当设置了这个属性时,则表示这个设备在relocate之前就需要使用。

当dm_init_and_scan的参数为true时,只会对带有“u-boot,dm-pre-reloc”属性的节点进行解析。而当参数为false的时候,则会对所有节点都进行解析。

由于“u-boot,dm-pre-reloc”的情况比较少,所以这里只学习参数为false的情况。也就是initr_dm里面的dm_init_and_scan(false);。

dm_init_and_scan(driver/core/root.c)说明

int dm_init_and_scan(bool pre_reloc_only)

{

    int ret;

    ret = dm_init();    // DM的初始化

    if (ret) {

        debug("dm_init() failed: %d\n", ret);

        return ret;

    }

    ret = dm_scan_platdata(pre_reloc_only); //  从平台设备中解析udevice和uclass

    if (ret) {

        debug("dm_scan_platdata() failed: %d\n", ret);

        return ret;

    }

    if (CONFIG_IS_ENABLED(OF_CONTROL)) {

        ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); // 从dtb中解析udevice和uclass

        if (ret) {

            debug("dm_scan_fdt() failed: %d\n", ret);

            return ret;

        }

    }

    ret = dm_scan_other(pre_reloc_only);

    if (ret)

        return ret;

    return 0;

}

DM的初始化—dm_init(driver/core/root.c)

#define DM_ROOT_NON_CONST       (((gd_t *)gd)->dm_root) // 宏定义根设备指针gd->dm_root

#define DM_UCLASS_ROOT_NON_CONST    (((gd_t *)gd)->uclass_root) // 宏定义gd->uclass_root,uclass的链表

int dm_init(void)

{

    int ret;

    if (gd->dm_root) {

    // 根设备已经存在,说明DM已经初始化过了

        dm_warn("Virtual root driver already exists!\n");

        return -EINVAL;

    }

    INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);

        // 初始化uclass链表

    ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);

        // DM_ROOT_NON_CONST是指根设备udevice,root_info是表示根设备的设备信息

        // device_bind_by_name会查找和设备信息匹配的driver,然后创建对应的udevice和uclass并进行绑定,最后放在DM_ROOT_NON_CONST中。

        // device_bind_by_name后续我们会进行说明,这里我们暂时只需要了解root根设备的udevice以及对应的uclass都已经创建完成。

    if (ret)

        return ret;

#if CONFIG_IS_ENABLED(OF_CONTROL)

    DM_ROOT_NON_CONST->of_offset = 0;

#endif

    ret = device_probe(DM_ROOT_NON_CONST);

        // 对根设备执行probe操作,

        // device_probe后续再进行说明

    if (ret)

        return ret;

    return 0;

}

这里就完成的DM的初始化了

1)创建根设备root的udevice,存放在gd->dm_root中。

2)初始化uclass链表gd->uclass_root

(2)从平台设备中解析udevice和uclass—dm_scan_platdata(不涉及)

(3)从dtb中解析udevice和uclass——dm_scan_fdt

对应代码如下driver/core/root.c

int dm_scan_fdt(const void *blob, bool pre_reloc_only)

// 此时传进来的参数blob=gd->fdt_blob, pre_reloc_only=0

{

    return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);

// 直接调用dm_scan_fdt_node

}

int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,

             bool pre_reloc_only)

// 此时传进来的参数

// parent=gd->dm_root,表示以root设备作为父设备开始解析

// blob=gd->fdt_blob,指定了对应的dtb

// offset=0,从偏移0的节点开始扫描

// pre_reloc_only=0,不只是解析relotion之前的设备

{

    int ret = 0, err;

        /*  以下步骤相当于是遍历每一个dts节点并且调用lists_bind_fdt对其进行解析 */

    for (offset = fdt_first_subnode(blob, offset);

        // 获得blob设备树的offset偏移下的节点的第一个子节点

         offset > 0;

         offset = fdt_next_subnode(blob, offset)) {

               // 循环查找下一个子节点

        if (!fdtdec_get_is_enabled(blob, offset)) {

                        // 判断节点状态是否是disable,如果是的话直接忽略

            dm_dbg("   - ignoring disabled device\n");

            continue;

        }

        err = lists_bind_fdt(parent, blob, offset, NULL);

                // 解析绑定这个节点,dm_scan_fdt的核心,下面具体分析

        if (err && !ret) {

            ret = err;

            debug("%s: ret=%d\n", fdt_get_name(blob, offset, NULL),

                  ret);

        }

    }

    return ret;

}

lists_bind_fdt是从dtb中解析udevice和uclass的核心。

其具体实现如下: driver/core/lists.c

int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,

           struct udevice **devp)

// parent指定了父设备,通过blob和offset可以获得对应的设备的dts节点,对应udevice结构通过devp返回

{

    struct driver *driver = ll_entry_start(struct driver, dr

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值