[RK3399][Android7.1] DRM中的Component System

OS: Android 7.1
Board: Firefly-RK3399
Kernel: v4.4.55

上一篇文章介绍了DRM的概念,有CRTC, Encoder, Connector等好多个模块,各个模块都作为一个组件添加到组件系统中,通过组件驱动来管理。

关于component system,下面是作者的一段话:

Subsystems such as ALSA, DRM and others require a single card-level
device structure to represent a subsystem.  However, firmware tends to
describe the individual devices and the connections between them.

Therefore, we need a way to gather up the individual component devices
together, and indicate when we have all the component devices.

We do this in DT by providing a "superdevice" node which specifies
the components, eg:

    imx-drm {
        compatible = "fsl,drm";
        crtcs = <&ipu1>;
        connectors = <&hdmi>;
    };

The superdevice is declared into the component support, along with the
subcomponents.  The superdevice receives callbacks to locate the
subcomponents, and identify when all components are present.  At this
point, we bind the superdevice, which causes the appropriate subsystem
to be initialised in the conventional way.

When any of the components or superdevice are removed from the system,
we unbind the superdevice, thereby taking the subsystem down.

也就是说DRM类似ALSA框架那样有一个代表整个子系统的东西,作者称它为”superdevice”, superdevice管理components,在rk平台上对应的dts node就是:
rk3399.dtsi

    display_subsystem: display-subsystem {
        compatible = "rockchip,display-subsystem";
        ports = <&vopl_out>, <&vopb_out>;
        status = "disabled";
    };

在rk3399-android.dtsi中被打开:

&display_subsystem {
    status = "okay";
    ports = <&vopb_out>, <&vopl_out>;
    memory-region = <&drm_logo>;
    route {
        ......
        route_edp: route-edp {
            .....
            connect = <&vopb_out_edp>;
        };
    };
};

对应的驱动文件是 rockchip_drm_drv.c, 在驱动中superdevice通过component_master_add_with_match()添加成为一个master。

static int rockchip_drm_platform_probe(struct platform_device *pdev)
{
    //绑定CRTC到match列表中,这样encoder在调用bind回调的时候能通过 drm_of_find_possible_crtcs()找到它们, 这里的CRTC是"vopb"和"vopl".
    //match这个list只是用于保存当前从dts中找到的有效的component, 如VOP,edp.
    //找到后在find_components()的时候会比较是否list中所有模块都已经被add进来了
    component_match_add(dev, &match, compare_of, port->parent);
    ......
    //添加远程endpoint到match上,也是调用component_match_add()实现
    //注意:只有有效的endpoint才会被添加到match中,比如这里只有edp被添加进去了。
    rockchip_add_endpoints(dev, &match, port);
    ......
    //把match列表添加到master中
    return component_master_add_with_match(dev, &rockchip_drm_ops, match);
}

当前的endpoint有:

    vopb: vop@ff900000 {
        ......
        vopb_out: port {
            #address-cells = <1>;
            #size-cells = <0>;
            vopb_out_edp: endpoint@0 {
                reg = <0>;
                remote-endpoint = <&edp_in_vopb>;
            };
            vopb_out_mipi: endpoint@1 {
                reg = <1>;
                remote-endpoint = <&mipi_in_vopb>;
            };
            vopb_out_hdmi: endpoint@2 {
                reg = <2>;
                remote-endpoint = <&hdmi_in_vopb>;
            };
            vopb_out_dp: endpoint@3 {
                reg = <3>;
                remote-endpoint = <&dp_in_vopb>;
            };
        };
    };

vopl里也有四个,通过remote-endpoint node找到parent node分别是edp: edp@ff970000, mipi_dsi: mipi@ff960000, hdmi: hdmi@ff940000,cdn_dp: dp@fec00000 。

其中的rockchip_drm_ops在所有components被found后会调用bind来绑定所有devices.

static const struct component_master_ops rockchip_drm_ops = {
    .bind = rockchip_drm_bind,
    .unbind = rockchip_drm_unbind,
};

调用过程:
component_master_add_with_match -> try_to_bring_up_master -> find_components ->
master->ops->bind

component_master_add_with_match()第一次不一定会成功,当且仅当所有的component都ready之后,master才会被bring up。因此在开机log中刚开始看到“failed to bind xxx”的信息是正常的。

那么这时候没有ready的话下次什么时候会再执行这个动作呢?
答案:每个component在被add的时候都会去重新调用try_to_bring_up_master()去判断是否所有component全部被match上。

find_components()就是用来寻找并判断所有match列表中的components是不是都被add即初始化了,如果没有ready,那么就不会再去走后面bring up master的流程。

拿edp驱动举例, analogix_dp-rockchip.c中有如下调用:
rockchip_dp_probe -> component_add -> try_to_bring_up_masters

master就会被bring up,master->bind就会被调用,最终也会调用各个component的bind回调函数。
rockchip_drm_bind -> component_bind_all -> component_bind -> component->ops->bind

借用rk drm作者的一张流程加载图可以对加载过程有更清晰的了解。

这里写图片描述


参考
Patchwork [RFC,26/46] drivers/base: provide an infrastructure for componentised subsystems
[PATCH 2/2] component: add kernel-docs in the header
rockchip_drm_integration_helper-zh.pdf




你可能感兴趣的:(Rk3399-Display)