LCD DRM component 框架分析

本文是基于rk3566/rk3568平台的LCD驱动对DRM component 框架进行分析。

一、背景

        kernel中的component框架是为了subsystem能够按照一定的顺序初始化设备而提出的架构。由于subsystem中由较多设备模块组成,而内核加载每个模块时间不定,则需要component框架来保证需最后初始化的设备加载前,所需设备全部加载完毕。

二、component框架描述

        在component中,包含两个基本概念,master和component。master是设备树中的“超级设备(superdevice)”,负责管理该超级设备下的普通设备。component是由master管理的普通设备,要先初始化。master在设备树中一般为xxx-subsystem节点,如display-subsystem。在节点下有ports属性,属性里存有该master应该关联的普通设备。如下:

        display_subsystem: display-subsystem {
                compatible = "rockchip,display-subsystem";
                memory-region = <&drm_logo>, <&drm_cubic_lut>;
                memory-region-names = "drm-logo", "drm-cubic-lut";
                ports = <&vop_out>;
                devfreq = <&dmc>;

                route {
                        route_dsi0: route-dsi0 {
                                status = "okay";
                                logo,uboot = "logo.bmp";
                                logo,kernel = "logo_kernel.bmp";
                                logo,mode = "center";
                                charge_logo,mode = "center";
                                connect = <&vp0_out_dsi0>;
                        };
                };
        };

三、设备的初始化流程

        master即超级设备,执行probe函数时使用component_master_add_with_match函数注册自己到component框架中。
        component即普通设备,执行probe函数时使用component_add函数注册自己到component框架中。
两种流程先后顺序并无要求,可随意顺序。每一个设备加入到框架中,框架就尝试进行匹配,当master匹配上所有component后,会调用master的bind回调,开始按顺序进行初始化,保证了当所有子设备全部probe成功后再执行初始化操作。

注:记master设备为主设备,component设备为从设备。

1、master设备初始化流程

1)驱动匹配节点后,执行.probe 函数,即rockchip_drm_platform_probe函数,如下:

static int rockchip_drm_platform_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct component_match *match = NULL;
	int ret;

	ret = rockchip_drm_platform_of_probe(dev);
#if !IS_ENABLED(CONFIG_DRM_ROCKCHIP_VVOP)
	if (ret)
		return ret;
#endif

	match = rockchip_drm_match_add(dev);
	if (IS_ERR(match))
		return PTR_ERR(match);

	ret = component_master_add_with_match(dev, &rockchip_drm_ops, match);
	if (ret < 0) {
		rockchip_drm_match_remove(dev);
		return ret;
	}
	dev->coherent_dma_mask = DMA_BIT_MASK(64);

	return 0;
}

2)初始化match对象,即将已知的驱动和总线上的设备上进行匹配,并将匹配上的设备加入到struct component_match结构中,如下:

static int __init rockchip_drm_init(void)
{
	int ret;

	num_rockchip_sub_drivers = 0;
#if IS_ENABLED(CONFIG_DRM_ROCKCHIP_VVOP)
	ADD_ROCKCHIP_SUB_DRIVER(vvop_platform_driver, CONFIG_DRM_ROCKCHIP_VVOP);
#else
	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP);
	ADD_ROCKCHIP_SUB_DRIVER(vop2_platform_driver, CONFIG_ROCKCHIP_VOP2);
	ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver,
				CONFIG_ROCKCHIP_LVDS);
	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
				CONFIG_ROCKCHIP_ANALOGIX_DP);
	ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP);
	ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver,
				CONFIG_ROCKCHIP_DW_HDMI);
	ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_driver,
				CONFIG_ROCKCHIP_DW_MIPI_DSI);
	ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI);
	ADD_ROCKCHIP_SUB_DRIVER(rockchip_tve_driver,
				CONFIG_ROCKCHIP_DRM_TVE);
	ADD_ROCKCHIP_SUB_DRIVER(rockchip_rgb_driver, CONFIG_ROCKCHIP_RGB);
#endif
	ret = platform_register_drivers(rockchip_sub_drivers,
					num_rockchip_sub_drivers);
	if (ret)
		return ret;

	ret = platform_driver_register(&rockchip_drm_platform_driver);
	if (ret)
		goto err_unreg_drivers;

	return 0;

err_unreg_drivers:
	platform_unregister_drivers(rockchip_sub_drivers,
				    num_rockchip_sub_drivers);
	return ret;
}
static struct component_match *rockchip_drm_match_add(struct device *dev)
{
	struct component_match *match = NULL;
	int i;

	for (i = 0; i < num_rockchip_sub_drivers; i++) {
		struct platform_driver *drv = rockchip_sub_drivers[i];
		struct device *p = NULL, *d;

		do {
			d = bus_find_device(&platform_bus_type, p, &drv->driver,
					    (void *)platform_bus_type.match);
			put_device(p);
			p = d;

			if (!d)
				break;

			device_link_add(dev, d, DL_FLAG_STATELESS);
			component_match_add(dev, &match, compare_dev, d);
		} while (true);
	}

	if (IS_ERR(match))
		rockchip_drm_match_remove(dev);

	return match ?: ERR_PTR(-ENODEV);
}

注:

1)在图1,会添加默认vop2_platform_driver、dw_mipi_dsi_driver、dw_hdmi_rockchip_pltfm_driver、rockchip_rgb_driver等驱动到rockchip_sub_drivers中。

2)在图2,通过bus_find_device函数遍历platform总线上的设备,并将与rockchip_sub_drivers中的驱动进行匹配,若匹配上则通过component_match_add函数加入match中(即设备与驱动匹配上的则为从设备)。相关函数的具体实现如下:

static inline void component_match_add(struct device *master,
	struct component_match **matchptr,
	int (*compare)(struct device *, void *), void *compare_data)
{
	component_match_add_release(master, matchptr, NULL, compare,
				    compare_data);
}

void component_match_add_release(struct device *master,
	struct component_match **matchptr,
	void (*release)(struct device *, void *),
	int (*compare)(struct device *, void *), void *compare_data)
{
	struct component_match *match = *matchptr;

	if (IS_ERR(match))
		return;

	if (!match) {
		match = devres_alloc(devm_component_match_release,
				     sizeof(*match), GFP_KERNEL);
		if (!match) {
			*matchptr = ERR_PTR(-ENOMEM);
			return;
		}

		devres_add(master, match);

		*matchptr = match;
	}

	if (match->num == match->alloc) {
		size_t new_size = match->alloc + 16;
		int ret;

		ret = component_match_realloc(master, match, new_size);
		if (ret) {
			*matchptr = ERR_PTR(ret);
			return;
		}
	}

	match->compare[match->num].compare = compare;
	match->compare[match->num].release = release;
	match->compare[match->num].data = compare_data;
	match->compare[match->num].component = NULL;
	match->num++;
}

3)初始化master对象,并将master对象加到masters链表,再将component_list链表上与master上通过以dev进行匹配,然后将匹配上的component设备加到master设备的match成员,最后执行master的bind函数以及执行component下的bind函数进行初始化。相关代码如下:

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

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

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

	master->dev = dev;
	master->ops = ops;
	master->match = match;

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

	ret = try_to_bring_up_master(master, NULL);

	if (ret < 0)
		free_master(master);

	mutex_unlock(&component_mutex);

	return ret < 0 ? ret : 0;
}

在上面对象初始化结束后后,下面通过try_to_bring_up_master先通过find_components将匹配的component加到master的match成员中,然后进行回调master和component 的bind函数。

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

	dev_dbg(master->dev, "trying to bring up master\n");

	if (find_components(master)) {
		dev_dbg(master->dev, "master has incomplete components\n");
		return 0;
	}

	if (component && component->master != master) {
		dev_dbg(master->dev, "master is not for this component (%s)\n",
			dev_name(component->dev));
		return 0;
	}

	if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
		return -ENOMEM;

	/* Found all components */
	ret = master->ops->bind(master->dev);
	if (ret < 0) {
		devres_release_group(master->dev, NULL);
		if (ret != -EPROBE_DEFER)
			dev_info(master->dev, "master bind failed: %d\n", ret);
		return ret;
	}

	master->bound = true;
	return 1;
}
static int find_components(struct master *master)
{
	struct component_match *match = master->match;
	size_t i;
	int ret = 0;

	/*
	 * Scan the array of match functions and attach
	 * any components which are found to this master.
	 */
	for (i = 0; i < match->num; i++) {
		struct component_match_array *mc = &match->compare[i];
		struct component *c;

		dev_dbg(master->dev, "Looking for component %zu\n", i);

		if (match->compare[i].component)
			continue;

		c = find_component(master, mc->compare, mc->data);
		if (!c) {
			ret = -ENXIO;
			break;
		}

		dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master);

		/* Attach this component to the master */
		match->compare[i].duplicate = !!c->master;
		match->compare[i].component = c;
		c->master = master;
	}
	return ret;
}

static struct component *find_component(struct master *master,
	int (*compare)(struct device *, void *), void *compare_data)
{
	struct component *c;

	list_for_each_entry(c, &component_list, node) {
		if (c->master && c->master != master)
			continue;

		if (compare(c->dev, compare_data))
			return c;
	}

	return NULL;
}

4)bind函数的执行,由下知:master的bind函数除了自身初始化外,其他主要是为了回调component的bind函数。

static int rockchip_drm_bind(struct device *dev)
{
    ...
    ret = component_bind_all(dev, drm_dev);
    ...
}

int component_bind_all(struct device *master_dev, void *data)
{
	struct master *master;
	struct component *c;
	size_t i;
	int ret = 0;

	WARN_ON(!mutex_is_locked(&component_mutex));

	master = __master_find(master_dev, NULL);
	if (!master)
		return -EINVAL;

	/* Bind components in match order */
	for (i = 0; i < master->match->num; i++)
		if (!master->match->compare[i].duplicate) {
			c = master->match->compare[i].component;
			ret = component_bind(c, master, data);
			if (ret)
				break;
		}

	if (ret != 0) {
		for (; i > 0; i--)
			if (!master->match->compare[i - 1].duplicate) {
				c = master->match->compare[i - 1].component;
				component_unbind(c, master, data);
			}
	}

	return ret;
}
static int component_bind(struct component *component, struct master *master,
	void *data)
{
	int ret;
    ... //省略无关的代码
	ret = component->ops->bind(component->dev, master->dev, data);
    component->bound = true;
    ...//省略无关的代码
	return ret;
}

static void component_unbind(struct component *component,
	struct master *master, void *data)
{
	WARN_ON(!component->bound);

	component->ops->unbind(component->dev, master->dev, data);
	component->bound = false;

	/* Release all resources claimed in the binding of this component */
	devres_release_group(component->dev, component);
}
static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
			    void *data)
{
    ...
    ... //省略代码
}

注:

1)在component_bind_all函数中可知,若当前有component(从设备)尚未执行probe/初始化完毕,则在此时会bind失败,就会执行unbind回调。这就保证了会按顺序进行初始化且等待所有从设备全部probe成功后再执行初始化操作。

2)此处以dw_mipi_dsi_bind为component进行举例。也即对应component_bind函数中的component->ops->bind(component->dev, master->dev, data)。

2、component设备初始化流程

1)驱动匹配节点后,执行.probe 函数,即dw_mipi_dsi_probe函数,如下

static int dw_mipi_dsi_probe(struct platform_device *pdev)
{
    ...//省略无关代码
	return component_add(&pdev->dev, &dw_mipi_dsi_ops);
}


static const struct component_ops dw_mipi_dsi_ops = {
	.bind	= dw_mipi_dsi_bind,
	.unbind	= dw_mipi_dsi_unbind,
};

2)通过component_add函数分配并初始化component对象,并添加到component_list链表中,最后调用try_to_bring_up_masters进行初始化component。

int component_add(struct device *dev, const struct component_ops *ops)
{
	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);
	if (ret < 0) {
		if (component->master)
			remove_component(component->master, component);
		list_del(&component->node);

		kfree(component);
	}
	mutex_unlock(&component_mutex);

	return ret < 0 ? ret : 0;
}

3)在try_to_bring_up_masters函数中先遍历masters链表,再在try_to_bring_up_master中通过find_components函数进行component和master的相互绑定,最后调用master的bind回调。

static int try_to_bring_up_masters(struct component *component)
{
	struct master *m;
	int ret = 0;

	list_for_each_entry(m, &masters, node) {
		if (!m->bound) {
			ret = try_to_bring_up_master(m, component);
			if (ret != 0)
				break;
		}
	}

	return ret;
}

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

	dev_dbg(master->dev, "trying to bring up master\n");

	if (find_components(master)) {
		dev_dbg(master->dev, "master has incomplete components\n");
		return 0;
	}

	if (component && component->master != master) {
		dev_dbg(master->dev, "master is not for this component (%s)\n",
			dev_name(component->dev));
		return 0;
	}

	if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
		return -ENOMEM;

	/* Found all components */
	ret = master->ops->bind(master->dev);
	if (ret < 0) {
		devres_release_group(master->dev, NULL);
		if (ret != -EPROBE_DEFER)
			dev_info(master->dev, "master bind failed: %d\n", ret);
		return ret;
	}

	master->bound = true;
	return 1;
}

static int find_components(struct master *master)
{
	struct component_match *match = master->match;
	size_t i;
	int ret = 0;

	/*
	 * Scan the array of match functions and attach
	 * any components which are found to this master.
	 */
	for (i = 0; i < match->num; i++) {
		struct component_match_array *mc = &match->compare[i];
		struct component *c;

		dev_dbg(master->dev, "Looking for component %zu\n", i);

		if (match->compare[i].component)
			continue;

		c = find_component(master, mc->compare, mc->data);
		if (!c) {
			ret = -ENXIO;
			break;
		}

		dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master);

		/* Attach this component to the master */
		match->compare[i].duplicate = !!c->master;
		match->compare[i].component = c;
		c->master = master;
	}
	return ret;
}

//遍历component_list,将component和master进行匹配比较
static struct component *find_component(struct master *master,
	int (*compare)(struct device *, void *), void *compare_data)
{
	struct component *c;

	list_for_each_entry(c, &component_list, node) {
		if (c->master && c->master != master)
			continue;

		if (compare(c->dev, compare_data))
			return c;
	}

	return NULL;
}

注:以上即为两层遍历,先遍历masters链表取出master再和component_list中的每个component进行比较。若当前的master与componet_list无匹配上,则取出masters上的下个master来匹配。直到匹配上后执行master的bind回调,也即执行component的bind回调。

四、总结

componet框架是用来确保在subsystem中存在较多个设备模块组成时由于加载的顺序初始化不一定,所以用来保证最后初始化的设备加载前,所需的设备全部加载完毕。机制:每个设备加入到框架中,框架就尝试进行匹配,当master匹配上所有component后,会调用master的bind回调,开始按顺序进行初始化,保证当所有子设备全部probe成功后再执行初始化操作

1、master设备的流程:

component_match_add-》component_master_add_with_match-》try_to_bring_up_master-》

master->ops->bind(master->dev)

2、componet设备的流程:

component_add-》try_to_bring_up_masters-》try_to_bring_up_master-》master->ops->bind

-》component->ops->bind(component->dev, master->dev, data)

3、重点函数说明:

1)find_components-》find_component

说明:find_component函数遍历component_list链表,通过之前的compare和data(即dev)来查找在component_list链表上匹配的component(即受此master管理的component设备)

2)try_to_bring_up_master

说明:会基于master查找component_list链表和该master匹配的,并且回调master的bind函数。

3)try_to_bring_up_masters

说明:两轮遍历,即:外层为masters链表,内层为component_list链表,只是为了进行master和component的匹配,然后后尝试去回调master的bind函数。

4)component_bind_all

说明:遍历master上的match列表,然后执行component_bind去执行回调。并且在此函数中进行了尝试执行bind回调,若有一个失败则会再执行component_unbind。

猜你喜欢

转载自blog.csdn.net/qq_33782617/article/details/126166452
LCD