> 文章列表 > DRM驱动

DRM驱动

DRM驱动

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不存在,刚申请的,实际使用的数量为0new->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);}//分配了一个mastermaster = 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_bindcomponent->ops->bind(component->dev, master->dev, data);

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

drivers\\gpu\\drm\\rockchip\\rockchip_lvds.c

rockchip_lvds_probestruct 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_probestruct device *dev = &pdev->dev;component_add(dev, &vop_component_ops);

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

panel_simple_probestruct 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;
}