DRM驱动

商昂然
2023-12-01

vop:    video output processor,rk平台的LCD controllers
crt:      crt显示器,
crtc:    crt显示控制器,等同于lcdc、vop

drivers\gpu\drm\rockchip\rockchip_drm_drv.c: drm驱动入口。

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

其中ports属性里的结点对应vop结点下的子节点port。

px30有两个vop显示控制器,分别为vopb和vop1。

        vopb: vop@ff460000 {
                compatible = "rockchip,px30-vop-big";
                reg = <0x0 0xff470000 0x0 0x1fc>, <0x0 0xff470a00 0x0 0x400>;
                ......
                iommus = <&vopl_mmu>;

                vopb_out: port {
                        #address-cells = <1>;
                        #size-cells = <0>;

                        vopb_out_lvds: endpoint@0 {
                                reg = <0>;
                                remote-endpoint = <&lvds_in_vopb>;
                        };

                        ......

                };
        };
        vopl: vop@ff470000 {
                compatible = "rockchip,px30-vop-lit";
                reg = <0x0 0xff470000 0x0 0x1fc>, <0x0 0xff470a00 0x0 0x400>;
                ......
                iommus = <&vopl_mmu>;

                vopl_out: port {
                        #address-cells = <1>;
                        #size-cells = <0>;

                        vopl_out_lvds: endpoint@0 {
                                reg = <0>;
                                remote-endpoint = <&lvds_in_vopl>;
                        };
                        
                        ......

                };
        };

lvds结点:

                lvds: lvds {
                        compatible = "rockchip,px30-lvds";
                        phys = <&video_phy>;
                        phy-names = "phy";

                        ports { 
                                #address-cells = <1>;
                                #size-cells = <0>;
                                
                                port@0 {
                                        reg = <0>;
                                        #address-cells = <1>;
                                        #size-cells = <0>;

                                        lvds_in_vopb: endpoint@0 {
                                                reg = <0>;
                                                remote-endpoint = <&vopb_out_lvds>;
                                        };
                                }
                
                                port@1 {
                                        reg = <1>;

                                        lvds_out_panel: endpoint {
                                            remote-endpoint = <&panel_in_lvds>;
                                         };
                                };

                        };
                };

rockchip_drm_platform_probe函数: 

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;

	for (i = 0;; i++) {
		struct device_node *iommu;
        //对应vopb_out、vopl_out两结点
		port = of_parse_phandle(np, "ports", i);
        //vopb_out、vop1_out两结点的父结点分别为vopb、vop1两个显示控制器结点
		iommu = of_parse_phandle(port->parent, "iommus", 0);
		if (!iommu || !of_device_is_available(iommu->parent)) {
			is_support_iommu = false;
		}
        //第二个参数传入的是二维指针,二维指针获取一维指针,第一次match为空,后面指向某个内存空间
		component_match_add(dev, &match, compare_of, port->parent);
	}

	for (i = 0;; i++) {
		port = of_parse_phandle(np, "ports", i);
        //ports对应的结点下的子节点都是端点结点
		rockchip_add_endpoints(dev, &match, port);
	}

	return component_master_add_with_match(dev, &rockchip_drm_ops, match);
}

component_match_add函数:添加component匹配方法,定义了属于它master的每个component的区分方法(fn),就是component的设备结点得要是它master指定的这些(compare_data)。

void component_match_add(struct device *dev, struct component_match **matchptr,
	int (*compare)(struct device *, void *), void *compare_data)
{
	struct component_match *match = *matchptr;

	if (!match || match->num == match->alloc) {

        //match->alloc:初始分配的个数
        //match->num:已经使用的个数
		size_t new_size = match ? match->alloc + 16 : 15;

		match = component_match_realloc(dev, match, new_size);

		*matchptr = match;

	}
    
    //比较函数
	match->compare[match->num].fn = compare;
    //比较的数据
	match->compare[match->num].data = compare_data;
	match->num++;
}

component_match_realloc函数:重新分配一个component_match变量。

static struct component_match *component_match_realloc(struct device *dev,
	struct component_match *match, size_t num)
{
	struct component_match *new;

	new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL);

	if (match) {
        //match已经存在,如果实际使用的数量小于申请分配的数量,分配好内存后,
        //把已经使用的内存复制到新内存中
		memcpy(new, match, component_match_size(min(match->num, num)));
        //释放旧的内存
		devm_kfree(dev, match);
	} else {
        //match不存在,刚申请的,实际使用的数量为0
		new->num = 0;
	}

    //初始分配的数量为申请分配的数量
	new->alloc = num;

	return new;
}

compare_of函数:比较设备结点是否是同一个。

static int compare_of(struct device *dev, void *data)
{
	struct device_node *np = data;

	return dev->of_node == np;
}

struct component_match结构体定义: 

struct component_match {
    //初始分配的数量
	size_t alloc;
    //已经使用的数量
	size_t num;
    //compare数组:每个数组元素都对应着一种component匹配方法,即component的设备结点等于data,
    //该component才是该master的
	struct {
		void *data;
		int (*fn)(struct device *, void *);
	} compare[0];
};

rockchip_add_endpoints函数:

static void rockchip_add_endpoints(struct device *dev,struct component_match **match,
				   struct device_node *port)
{
	struct device_node *ep, *remote;
    
    //port:vop下的port结点,该结点下的子结点都是端点结点
	for_each_available_child_of_node(port, ep) {
		remote = of_graph_get_remote_port_parent(ep);
        //将比较的方法compare_of和用该方法比较的数据remote放到match的compare数组中
		component_match_add(dev, match, compare_of, remote);
		of_node_put(remote);
	}
}

of_graph_get_remote_port_parent函数:

struct device_node *of_graph_get_remote_port_parent(
			       const struct device_node *node)
{
	struct device_node *np;
	unsigned int depth;

	/* Get remote endpoint node. */
	np = of_parse_phandle(node, "remote-endpoint", 0);

	/* Walk 3 levels up only if there is 'ports' node. */
	for (depth = 3; depth && np; depth--) {
		np = of_get_next_parent(np);
        //注意:of_node_cmp,两者相同返回0,不同返回1,也就是结点名不是"ports"才有可能跳出
		if (depth == 2 && of_node_cmp(np->name, "ports"))
			break;
	}
	return np;
}

component_master_add_with_match函数:

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

	if (match) {
		/* Reallocate the match array for its true size */
		match = component_match_realloc(dev, match, match->num);
	}
    //分配了一个master
	master = kzalloc(sizeof(*master), GFP_KERNEL);

	master->dev = dev;
	master->ops = ops;
    //属于master的component的匹配方法
	master->match = match;
	INIT_LIST_HEAD(&master->components);

	list_add(&master->node, &masters);

    try_to_bring_up_master(master, NULL);

	return ret < 0 ? ret : 0;
}

try_to_bring_up_master函数:

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

	find_components(master));

	/* Found all components */
	ret = master->ops->bind(master->dev);

	master->bound = true;
	return 1;
}

find_components函数: 

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

	for (i = 0; i < match->num; i++) {
		ret = component_master_add_child(master,
						 match->compare[i].fn,
						 match->compare[i].data);
		if (ret)
			break;
	}
	return ret;
}

component_master_add_child函数:

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的master已经存在,且它的master不是这个master,直接跳过
        //component的master已经存在,且它的master等于此master,那该component肯定能通过此master
        //的匹配
		if (c->master && c->master != master)
			continue;

		if (compare(c->dev, compare_data)) {
			if (!c->master)
				component_attach_master(master, c);
			ret = 0;
			break;
		}
	}

	return ret;
}

component_attach_master函数:将component添加到master的components链表中。

static void component_attach_master(struct master *master, struct component *c)
{
	c->master = master;

	list_add_tail(&c->master_node, &master->components);
}

master->ops->bind指向rockchip_drm_ops的bind函数,也就是rockchip_drm_bind函数:

int rockchip_drm_bind(struct device *dev)
        struct drm_device *drm_dev;
        drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev);
        component_bind_all(dev, drm_dev);
            	struct master *master;
	            struct component *c;
                master = __master_find(master_dev, NULL);
                list_for_each_entry(c, &master->components, master_node) {
		            component_bind(c, master, data);
                }

component_bind函数:

component_bind
    component->ops->bind(component->dev, master->dev, data);

2、LVDS结点的对应的LVDS驱动:

drivers\gpu\drm\rockchip\rockchip_lvds.c

rockchip_lvds_probe
    struct device *dev = &pdev->dev;
    component_add(dev, &rockchip_lvds_component_ops);

component_add函数:

int component_add(struct device *dev, const struct component_ops *ops)
{
	struct component *component;
	int ret;

	component = kzalloc(sizeof(*component), GFP_KERNEL);

	component->ops = ops;
	component->dev = dev;

	list_add_tail(&component->node, &component_list);

	ret = try_to_bring_up_masters(component);

	return ret < 0 ? ret : 0;
}

bind函数:

static int rockchip_lvds_bind(struct device *dev, struct device *master,void *data)
{
	struct rockchip_lvds *lvds = dev_get_drvdata(dev);
	struct drm_device *drm_dev = data;
	struct drm_encoder *encoder = &lvds->encoder;
	struct drm_connector *connector = &lvds->connector;

	drm_of_find_panel_or_bridge(dev->of_node, 1, -1,&lvds->panel, &lvds->bridge);
    ......
}

 drm_of_find_panel_or_bridge函数:

int drm_of_find_panel_or_bridge(const struct device_node *np,int port, int endpoint,
				            struct drm_panel **panel, struct drm_bridge **bridge)
{
	struct device_node *remote;
    //@port==1 @endpoint==-1,返回panel结点
	remote = of_graph_get_remote_node(np, port, endpoint);

	if (panel) {
		*panel = of_drm_find_panel(remote);
	}

    ......
}

of_graph_get_remote_node函数:

struct device_node *of_graph_get_remote_node(const struct device_node *node,
					     u32 port, u32 endpoint)
{
	struct device_node *endpoint_node, *remote;

    //@port=1,@endpoint=-1
    //返回的是lvds结点下的lvds_out_panel端点
	endpoint_node = of_graph_get_endpoint_by_regs(node, port, endpoint);
    //该函数已被上面分析
    //lvds_out_panel下的remote端点是panel结点下的panel_in_lvds端点,它的父亲结点的父亲结点
    //是panel结点,该结点的结点名不是"ports",所以返回panel结点
	remote = of_graph_get_remote_port_parent(endpoint_node);

	return remote;
}

简洁版的lvds结点,完整版的看上面:

                lvds: lvds {
                        compatible = "rockchip,px30-lvds";
                        ports { 
                                port@0 {
                                        reg = <0>;
                                        lvds_in_vopb: endpoint@0 {
                                                reg = <0>;
                                                remote-endpoint = <&vopb_out_lvds>;
                                        };
                                }
                                port@1 {
                                        reg = <1>;
                                        lvds_out_panel: endpoint {
                                            remote-endpoint = <&panel_in_lvds>;
                                         };
                                };

                        };
                };

简化版的panel结点:

        panel {
                compatible = "simple-panel";

                display-timings {
                        native-mode = <&timing0>;

                        timing0: timing0 {
                                clock-frequency = <62000000>;
                                hactive = <1024>;
                                vactive = <600>;
                                ......
                };

                port {
                        panel_in_lvds: endpoint {
                                remote-endpoint = <&lvds_out_panel>;
                        };
                };
        };

  of_graph_get_endpoint_by_regs函数:

struct device_node *of_graph_get_endpoint_by_regs(const struct device_node *parent,
                                    int port_reg, int reg)
{
	struct of_endpoint endpoint;
	struct device_node *node = NULL;

    //遍历parent结点下的每个端点结点
	for_each_endpoint_of_node(parent, node) {
		of_graph_parse_endpoint(node, &endpoint);
        //@port_reg=1,@reg=-1
        //满足条件的端点是lvds结点下的lvds_out_panel端点
		if ((endpoint.port == port_reg) && (reg == -1))
			return node;
	}

	return NULL;
}

of_graph_parse_endpoint函数:

int of_graph_parse_endpoint(const struct device_node *node,struct of_endpoint *endpoint)
{
    //端点的父结点是port结点
	struct device_node *port_node = of_get_parent(node);
	memset(endpoint, 0, sizeof(*endpoint));
	endpoint->local_node = node;
    //port结点下的reg属性值是endpoint->port值
    //端点下的reg属性值是endpoint->id值
	of_property_read_u32(port_node, "reg", &endpoint->port);
	of_property_read_u32(node, "reg", &endpoint->id);

	return 0;
}

of_drm_find_panel函数:

struct drm_panel *of_drm_find_panel(struct device_node *np)
{
	struct drm_panel *panel;

    //对应panel驱动的drm_panel_add函数
	list_for_each_entry(panel, &panel_list, list) {
		if (panel->dev->of_node == np) {
			return panel;
		}
	}

	return NULL;
}

3、vop显示控制器设备结点vop对应的函数:

vop_probe
    struct device *dev = &pdev->dev;
    component_add(dev, &vop_component_ops);

4、panel设备节点对应的函数:

panel_simple_probe
    struct panel_simple *panel;
    panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
    .....
    drm_panel_init(&panel->base);
	panel->base.dev = dev;
    panel->base.funcs = &panel_simple_funcs;
	err = drm_panel_add(&panel->base);
void drm_panel_init(struct drm_panel *panel)
{
	INIT_LIST_HEAD(&panel->list);
}

int drm_panel_add(struct drm_panel *panel)
{
	list_add_tail(&panel->list, &panel_list);

	return 0;
}

 类似资料: