图片来自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);
goto out;
}
master->bound = true;
return 1;
out:
master_remove_components(master);
return ret;
}
static int find_components(struct master *master)
{
struct component_match *match = master->match;
size_t i;
int ret = 0;
if (!match) {
/*
* Search the list of components, looking for components that
* belong to this master, and attach them to the master.
*/
return master->ops->add_components(master->dev, master);
}
/*
* Scan the array of match functions and attach
* any components which are found to this master.
*/
for (i = 0; i < match->num; i++) { //本match已经添加的crtc跟连接器connector
ret = component_master_add_child(master, 下面分析
match->compare[i].fn,
match->compare[i].data);
if (ret)
break;
}
return ret;
}
int component_master_add_child(struct master *master,
int (*compare)(struct device *, void *), void *compare_data)
{
struct component *c;
int ret = -ENXIO;
list_for_each_entry(c, &component_list, node) { 查找component_list链表,找到属于本master的component
if (c->master && c->master != master)
continue;
if (compare(c->dev, compare_data)) { //比较这个设备的节点是不是这个器件,通过component_match_add绑定好的,下面分析
if (!c->master)
component_attach_master(master, c); 把这个component添加到master的component链表
ret = 0; 找到就返回0
break;
}
}
return ret; 没找到返回错误
}
static int compare_of(struct device *dev, void *data)
{
struct device_node *np = data;
return dev->of_node == np; 判断这个节点跟传入的是不是一个
}
主drm驱动的加载过程结束
rockchip_drm_bind H:\RK3399\kernel\drivers\gpu\drm\rockchip\rockchip_drm_drv.c
component_bind_all
int component_bind_all(struct device *master_dev, void *data)
{
struct master *master;
struct component *c;
int ret = 0;
WARN_ON(!mutex_is_locked(&component_mutex));
master = __master_find(master_dev, NULL);
if (!master)
return -EINVAL;
list_for_each_entry(c, &master->components, master_node) {
ret = component_bind(c, master, data); //调用各components的bind函数
if (ret)
break;
}
if (ret != 0) {
list_for_each_entry_continue_reverse(c, &master->components,
master_node)
component_unbind(c, master, data);
}
return ret;
}
2.component从器件mipi的添加过程分析
dw_mipi_dsi_probe H:\RK3399\kernel\drivers\gpu\drm\rockchip\dw-mipi-dsi.c
component_add(dev, &dw_mipi_dsi_ops); 下面分析
static const struct component_ops dw_mipi_dsi_ops = {
.bind = dw_mipi_dsi_bind, 这个方法在rockchip_drm_bind中会被调用到
.unbind = dw_mipi_dsi_unbind,
};
int component_add(struct device *dev, const struct component_ops *ops) H:\RK3399\kernel\drivers\base\component.c
{
struct component *component;
int ret;
component = kzalloc(sizeof(*component), GFP_KERNEL);
if (!component)
return -ENOMEM;
component->ops = ops;
component->dev = dev;
dev_dbg(dev, "adding component (ops %ps)\n", ops);
mutex_lock(&component_mutex);
list_add_tail(&component->node, &component_list);
ret = try_to_bring_up_masters(component); 查找masters链表中所有的master,下面分析
if (ret < 0) {
list_del(&component->node);
kfree(component);
}
mutex_unlock(&component_mutex);
return ret < 0 ? ret : 0;
}
static int try_to_bring_up_masters(struct component *component)
{
struct master *m;
int ret = 0;
list_for_each_entry(m, &masters, node) { 查找masters链表中所有的master
ret = try_to_bring_up_master(m, component); 这 个函数上面master的时候分析过,从component引发到master检查它所有的component是否加载完成,完成之后调用master上面的bind函数,没完成则退出,master上的bind函数又会调用componet上的bind函数
if (ret != 0)
break;
}
return ret;
}
If a required resource is not available yet, a driver can
static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
void *data)
{
struct drm_device *drm = data;
struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
int ret;
ret = dw_mipi_dsi_dual_channel_probe(dsi);
if (ret)
return ret;
if (dsi->master)
return 0;
dsi->panel = of_drm_find_panel(dsi->client); //获取绑定到此dsi的panel设备,没有绑定好则检查是否绑定有bridge
if (!dsi->panel) {
dsi->bridge = of_drm_find_bridge(dsi->client); 没有绑定bridge则退出返回-EPROBE_DEFER,一旦返回就把
本驱动又加入了延时probe线程,等会会再次进行probe,直到发现了panel,而panel的加载在H:\RK3399\kernel\drivers\gpu\drm\panel\panel-simple.c完成,这里同时注册了mipi跟lvds的驱动在一起,通过comptable判断区分
if (!dsi->bridge)
return -EPROBE_DEFER;
}
ret = dw_mipi_dsi_register(drm, dsi); 绑定编码器,连接器,panel
if (ret) {
dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
return ret;
}
dev_set_drvdata(dev, dsi);
pm_runtime_enable(dev);
if (dsi->slave)
pm_runtime_enable(dsi->slave->dev);
return ret;
}
static int dw_mipi_dsi_register(struct drm_device *drm,
struct dw_mipi_dsi *dsi)
{
struct drm_encoder *encoder = &dsi->encoder;
struct drm_connector *connector = &dsi->connector;
struct device *dev = dsi->dev;
int ret;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm,
dev->of_node);
/*
* If we failed to find the CRTC(s) which this encoder is
* supposed to be connected to, it's because the CRTC has
* not been registered yet. Defer probing, and hope that
* the required CRTC is added later.
*/
if (encoder->possible_crtcs == 0)
return -EPROBE_DEFER;
drm_encoder_helper_add(&dsi->encoder,
&dw_mipi_dsi_encoder_helper_funcs);
ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs, //初始化encoder,格式为DRM_MODE_ENCODER_DSI,功能函数为dw_mipi_dsi_encoder_funcs
DRM_MODE_ENCODER_DSI, NULL);
if (ret) {
dev_err(dev, "Failed to initialize encoder with drm\n");
return ret;
}
/* If there's a bridge, attach to it and let it create the connector. */
if (dsi->bridge) {
dsi->bridge->driver_private = &dsi->dsi_host;
dsi->bridge->encoder = encoder;
ret = drm_bridge_attach(drm, dsi->bridge);
if (ret) {
dev_err(dev, "Failed to attach bridge: %d\n", ret);
goto encoder_cleanup;
}
encoder->bridge = dsi->bridge;
/* Otherwise create our own connector and attach to a panel */
} else {
dsi->connector.port = dev->of_node;
ret = drm_connector_init(drm, &dsi->connector,
&dw_mipi_dsi_atomic_connector_funcs,
DRM_MODE_CONNECTOR_DSI);
if (ret) {
dev_err(dev, "Failed to initialize connector\n");
goto encoder_cleanup;
}
drm_connector_helper_add(connector,
&dw_mipi_dsi_connector_helper_funcs);
drm_mode_connector_attach_encoder(connector, encoder); 把编码器绑定到连接器
ret = drm_panel_attach(dsi->panel, &dsi->connector); 把panel绑定到连接器
if (ret) {
dev_err(dev, "Failed to attach panel: %d\n", ret);
goto connector_cleanup;
}
}
return 0;
connector_cleanup:
drm_connector_cleanup(connector);
encoder_cleanup:
drm_encoder_cleanup(encoder);
return ret;
}