图片来自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
图片来自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)

博客详细解析了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驱动如何与硬件资源进行交互和配置。
1032

被折叠的 条评论
为什么被折叠?



