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