linux基于DRM显示框架分析

博客详细解析了Linux内核中Direct Rendering Manager (DRM)框架如何与Rockchip显示子系统进行组件绑定。在`rockchip_drm_platform_probe`函数中,首先遍历`ports`属性找到CRTC(如vopl, vopb)及其对应的iommus,然后通过`component_match_add`将它们添加到匹配列表中。接着,对于每个CRTC,添加其连接器(如dp_in_vopl, dsi_in_vopl等)。如果找不到`ports`属性或可用的VOP,将返回错误。最后,`component_master_add_with_match`尝试将所有组件绑定,并调用`rockchip_drm_bind`进行实际的绑定操作。此外,还分析了组件从器件mipi的添加过程,包括`dw_mipi_dsi_probe`函数和`component_add`函数。整个过程展示了DRM驱动如何与硬件资源进行交互和配置。

图片来自https://blog.csdn.net/u014674293/article/details/105732627?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2aggregatepagefirst_rank_v2~rank_aggregation-14-105732627.pc_agg_rank_aggregation&utm_term=drm%E6%98%BE%E7%A4%BA%E6%9E%B6%E6%9E%84&spm=1000.2123.3001.4430
jit图片来自https://www.eefocus.com/embedded/479281

display_subsystem: display-subsystem {
    compatible = "rockchip,display-subsystem";
    ports = <&vopl_out>, <&vopb_out>;
    clocks = <&cru PLL_VPLL>, <&cru PLL_CPLL>;
    clock-names = "hdmi-tmds-pll", "default-vop-pll";
    devfreq = <&dmc>;
    status = "disabled";
};

H:\RK3399\kernel\drivers\gpu\drm\rockchip\rockchip_drm_drv.c

vopl,vopb相当于是crtc,dp_in_vopl,dsi_in_vopl,edp_in_vopl,dp_in_vopl相当于是connector
static int rockchip_drm_platform_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct component_match *match = NULL;
struct device_node *np = dev->of_node;
struct device_node *port;
int i;

DRM_INFO("Rockchip DRM driver version: %s\n", DRIVER_VERSION);
if (!np)
    return -ENODEV;
/*
 * Bind the crtc ports first, so that
 * drm_of_find_possible_crtcs called from encoder .bind callbacks
 * works as expected.
 */
for (i = 0;; i++) {
    struct device_node *iommu;

    port = of_parse_phandle(np, "ports", i); //查找prots属性,找到它的 device_node节点,比如vopl_out节点
    if (!port)
        break;

    if (!of_device_is_available(port->parent)) {  //看vopl_out节点的父节点vopl是否可以使用 status 是否 "okay"或“ok”;
        of_node_put(port);
        continue;
    }

    iommu = of_parse_phandle(port->parent, "iommus", 0);  //找到其中的iommus的device_node节点
    if (!iommu || !of_device_is_available(iommu->parent)) {
        dev_dbg(dev, "no iommu attached for %s, using non-iommu buffers\n",
            port->parent->full_name);
        /*
         * if there is a crtc not support iommu, force set all
         * crtc use non-iommu buffer.
         */
        is_support_iommu = false;    //不存在或者父节点不可取就置为false
    }

    component_match_add(dev, &match, compare_of, port->parent); 在match中添加一个compare数组成员比如vopl,vopb,还会再将每个属性值关联的设备添加到match中
    of_node_put(port);
}

if (i == 0) {
    dev_err(dev, "missing 'ports' property\n");
    return -ENODEV;
}

if (!match) {
    dev_err(dev, "No available vop found for display-subsystem.\n");
    return -ENODEV;
}
/*
 * For each bound crtc, bind the encoders attached to its
 * remote endpoint.
 */
for (i = 0;; i++) {
    port = of_parse_phandle(np, "ports", i);
    if (!port)
        break;

    if (!of_device_is_available(port->parent)) {
        of_node_put(port);
        continue;
    }

    rockchip_add_endpoints(dev, &match, port);  //在match中添加一个remote-endpoint数组成员比如dp_in_vopl,dsi_in_vopl,edp_in_vopl,dp_in_vopl等
    of_node_put(port);
}

port = of_parse_phandle(np, "backlight", 0);
if (port && of_device_is_available(port)) {
    component_match_add(dev, &match, compare_of, port);
    of_node_put(port);
}

return component_master_add_with_match(dev, &rockchip_drm_ops, match); // 首先定义了一个component_master_ops 对象,为设备相关操作函数回调,当该master下的所有设备都初始化完成后,调用该回调的bind指针

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

int component_master_add_with_match(struct device *dev,
const struct component_master_ops *ops,
struct component_match *match)
{
struct master *master;
int ret;

if (ops->add_components && match)
    return -EINVAL;

if (match) {
    /* Reallocate the match array for its true size */
    match = component_match_realloc(dev, match, match->num);
    if (IS_ERR(match))
        return PTR_ERR(match);
}

master = kzalloc(sizeof(*master), GFP_KERNEL);
if (!master)
    return -ENOMEM;

master->dev = dev;
master->ops = ops;   //把rockchip_drm_ops给了master->ops 为后面调用ops的bind做准备
master->match = match;
INIT_LIST_HEAD(&master->components);

/* Add to the list of available masters. */
mutex_lock(&component_mutex);
list_add(&master->node, &masters);

ret = try_to_bring_up_master(master, NULL); 这个函 数就是检查是否所有的componet都加载完成,完成了就调用rockchip_drm_bind函数,后面分析rockchip_drm_bind 

if (ret < 0) {
    /* Delete off the list if we weren't successful */
    list_del(&master->node);
    kfree(master);
}
mutex_unlock(&component_mutex);

return ret < 0 ? ret : 0;

}

static int try_to_bring_up_master(struct master *master,
struct component *component)
{
int ret;

if (master->bound)
    return 0;

/*
 * Search the list of components, looking for components that
 * belong to this master, and attach them to the master.
 */
if (find_components(master)) {    //从component_list链表中找到所有属于本master的components,如果有component没有添加完成,就返回退出,不会调用下面的bind,如果全部找到就往下走调用bind,下面进入函数分析
        /* Failed to find all components */
        ret = 0;
        goto out;
    }

    if (component && component->master != master) {
   
   
        ret = 0;
        goto out;
    }

    if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
   
   
        ret = -ENOMEM;
        goto out;
    }

    /* Found all components */
    ret = master->ops->bind(master->dev);//调用之前传来的rockchip_drm_ops->bind,这里  .bind = rockchip_drm_bind,
    if (ret < 0) {
   
   
        devres_release_group(master->dev, NULL);
        dev_info(master->dev, "master bind failed: %d\n", ret)
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术求索者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值