Display DRM架构之component

刚开始做显示驱动的时候就一直接触到component组件,DRM中的各个模块使用component来管理。最近学习了一下这一块源码,彻底明白了component的机制。

为什么引入component机制

为什么会引入这个这个机制呢?

display和camera等这种框架会涉及到很多模块,像高通处理中,里面有MDP,mipi,hdmi,edp等等其他模块;模块之间会存在依赖,就需要考虑加载顺序。虽然内核也提供了像core_initcallarch_initcalllate_initcall这些接口控制加载驱动的顺序,但是使用不够灵活。

而component就可以达到这种控制整个流程的作用,


Component工作机制

Master component

  1. 通过设备树控制各个component的连接关系,即模块的加载顺序
  2. 解析设备树节点,并调用component_match_add,添加对应节点(add顺序决定模块bind顺序)
  3. 创建struct component_master_ops,调用component_master_add_with_match创建master;并在component_master_ops->bind函数中调用component_bind_all;

 

Slave component

       创建struct component_ops,调用component_add,将slave component添加进component框架。

当master解析到的所有节点均已component add,则会调用master_ops->bind中component_bind_all,按照设备树中解析的顺序依次执行从设备中component_ops的bind。

上面说的可能不是很清楚,来个例子:

假设现在有五个设备,一个master_component,和四个component;master_compoent中ports中使用了两个component,component1和component2;

Cmt1连接cmt3;cmt2连接cmt4;期望执行顺序为

 

设备树除了要配置必要的一些参数外,还需要配置port的节点(port可以有多个),port节点包含endpoint节点;endpoint节点中包含remote-endpoint节点,remote-endpoint节点指向所要连接节点中port中的endpoint节点(此处有点绕),比如cmt1中的remote-endpoint = <&cmt3_in>;cmt3_in为cmt3中port的endpoint节点;

 

完整设备树结构

代码如下

master_cmt: master_component {

           compatible = "master,component";

           status = "okay";



           ports = <&cmt1 &cmt2>;   //使用了component1和component2

};



cmt1: component1 {

           compatible = "slave1,component";

           status = "okay";



           port {

                    cmt1_out:endpoint {

                             remote-endpoint = <&cmt3_in>; //连接component3

                    };

           };

};



cmt2: component2 {

           compatible = "slave2,component";

           status = "okay";



           port {

                    cmt2_out:endpoint {

                             remote-endpoint = <&cmt4_in>;//连接component4

                    };

           };

};



cmt3: component3 {

           compatible = "slave3,component";

           status = "okay";



           port {

                    cmt3_in:endpoint {

                             //remote-endpoint = <&cmt1_out>;//未连接下一个从设备可不设置

                    };

           };

};



cmt4: component4 {

           compatible = "slave4,component";

           status = "okay";



           port {

                    cmt4_in:endpoint {

                             //remote-endpoint = <&cmt2_out>;//未连接下一个从设备可不设置

                    };

           };

};

驱动代码:

master component probe的函数

static const struct component_master_ops master_cmt_ops = {

.bind = master_cmt_bind,

.unbind = master_cmt_unbind,

};



int master_cmt_probe(struct platform_device *pdev)

{

struct component_match *match = NULL;

struct device_node *np = NULL;

struct device_node *ep = NULL, *remote = NULL;

struct device *dev = &pdev->dev;

int i = 0;



pr_err("%s entry\n", __func__);



for(i = 0; ; i++) {



          //获取master component节点中ports所指向的节点,第一次循环拿到cmt1,第二次循环拿到cmt2

          np = of_parse_phandle(dev->of_node, "ports", i);

          if (!np) {

                   break;

          }



          component_match_add(dev, &match, compare_of, np); //获取到cmt1或cmt2后添加到component框架中

          pr_err("%s add component:%s\n", __func__, np->name);



          for_each_endpoint_of_node(np, ep)         //此函数用于获取np节点中所有endpoint节点,这里不管cmt1或者cmt2均只有一个endpoint节点

          {

                   remote = of_graph_get_remote_port_parent(ep); //获取endpoint节点中remote-endpoint所指向节点的父节点,如果remote-endpoint = <&cmt3_in> 则remote为cmt3

                   if(!remote || !of_device_is_available(remote))

                   {

                            pr_err("remote device is not available\n");

                            of_node_put(remote);

                            continue;

                   }

                   else if (!of_device_is_available(remote->parent)) {

                            pr_err("parent device of %s is not available\n",

                                       remote->full_name);

                            of_node_put(remote);

                            continue;

                   }



                   component_match_add(dev, &match, compare_of, remote); //将获取到的remote添加进component框架

                   pr_err("%s add component:%s\n", __func__, remote->name);



                   of_node_put(remote);

          }

}



return component_master_add_with_match(&pdev->dev, &master_cmt_ops, match); //此函数用于创建master,用于调用bind函数指针

}

Slave component驱动

static const struct component_ops slave_cmt_ops = {

       .bind = slave_cmt_bind,

       .unbind = slave_cmt_unbind,

};



int slave_cmt_probe(struct platform_device *pdev)

{

       int ret = 0;

       pr_err("%s entry %s\n", __func__, pdev->dev.of_node->name);



       ret = component_add(&pdev->dev, &slave_cmt_ops);//将设备添加进component用于与master中添加的component进行匹配,当所有slave component全部add,就会调用master中的bind函数指针

       pr_err("%s component %s add ret %d\n", __func__, pdev->dev.of_node->name, ret);



       return ret;

}

详细代码已经上传github,地址https://github.com/chaochaofeng/LinuxComponent

这里只是利用一个简单的例子大致介绍了component的工作机制和使用方式,没有分析其内部源码,后面会对源码进行剖析。有问题可以指出,互相交流学习一下。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值