本文基于RockPI 4A DRM框架介绍Linux 4.4内核component
组件bind
过程。
一、加载顺序
RockPI 4A单板DRM模块drivers/gpu/drm/rockchip/Makefile
内容如下:
rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_gem.o rockchip_drm_vop.o ... obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o ... obj-$(CONFIG_DRM_ROCKCHIP) += rockchip_vop_reg.o rockchipdrm.o
注:DRM框架目前只关注HDMI显示,其它连接方式处理相同,暂不讨论。
根据Makefile
内容,确定DRM模块的编译顺序,具体如下:
CC drivers/gpu/drm/rockchip/dw_hdmi-rockchip.o ... CC drivers/gpu/drm/rockchip/rockchip_vop_reg.o CC drivers/gpu/drm/rockchip/rockchip_drm_drv.o ... LD drivers/gpu/drm/rockchip/rockchipdrm.o LD drivers/gpu/drm/rockchip/built-in.o
即:
dw_hdmi-rockchip.c
(encoder component
设备)->
rockchip_vop_reg.c
(crtc component
设备)->
rockchip_drm_drv.c
(core master
设备)
编译和链接的过程决定了这三个模块的component
加载顺序:encoder component->crtc component ->core master
。
二、component设备
DRM模块encoder
和crtc
驱动在各自模块的探测函数probe()
中使用component_add()
函数添加component
设备。
crtc
实现文件:drivers/gpu/drm/rockchip/rockchip_drm_vop.c、rockchip_vop_reg.c
;
encoder
实现文件:drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
。
例:
文件: drivers/gpu/drm/rockchip/rockchip_vop_reg.c
## 初始化bind和unbind的实现函数 const struct component_ops vop_component_ops = { .bind = vop_bind, .unbind = vop_unbind, }; ## 添加crtc component设备 static int vop_probe(struct platform_device *pdev) { ... return component_add(dev, &vop_component_ops); }
文件:drivers/base/omponent.c
,component_add()
定义如下:
int component_add(struct device *dev, const struct component_ops *ops) { struct component *component; ... ## 1.初始化component结构体 component = kzalloc(sizeof(*component), GFP_KERNEL); ... component->ops = ops; component->dev = dev; ... ## 2.将component中node添加到component_list链表中 list_add_tail(&component->node, &component_list); ## 3.尝试匹配master设备 ret = try_to_bring_up_masters(component); ... } static int try_to_bring_up_masters(struct component *component) { struct master *m; ... ## 搜索masters链表,此时master设备尚未注册,不会执行try_to_bring_up_master() list_for_each_entry(m, &masters, node) { ret = try_to_bring_up_master(m, component); if (ret != 0) break; } ... }
上面函数中涉及的定义如下:
## master设备结构体定义 struct master { struct list_head node; struct list_head components; bool bound; const struct component_master_ops *ops; struct device *dev; struct component_match *match; }; ## component设备结构体定义 struct component { struct list_head node; struct list_head master_node; struct master *master; bool bound; const struct component_ops *ops; struct device *dev; }; ## componet设备链表和master设备链表 static LIST_HEAD(component_list); static LIST_HEAD(masters);
注:
在DRM模块中,先加载component
设备,不会运行到try_to_bring_up_master()
函数。
在其它模块中,component
和master
设备的加载顺序不一定相同,上面函数的执行流程可能会有差异。
三、master设备
添加master
设备包括两步:
1)、component_match_add()
:添加待匹配的component
设备。
2)、component_master_add_with_match()
:初始化master
设备并匹配component
设备。若匹配成功,则执行master
设备的bind
函数。
例:
文件:drivers/gpu/drm/rockchip/rockchip_drm_drv.c
,实现如下:
static int rockchip_drm_platform_probe(struct platform_device *pdev) { struct component_match *match = NULL; ... for (i = 0;; i++) { ... ## 1. 添加待匹配的component设备,即添加crtc component_match_add(dev, &match, compare_of, port->parent); ... } ... for (i = 0;; i++) { ... ## 2. 添加待绑定的component设备,即添加每个crtc的encoder rockchip_add_endpoints(dev, &match, port); ... } ... ## 3.添加master设备并匹配component设备 ## 由于component设备已经添加完成,会在完成componet设备匹配后调用master设备的bind函数 return component_master_add_with_match(dev, &rockchip_drm_ops, match); }
涉及的结构体定义如下:
struct component_match { size_t alloc; size_t num; struct { void *data; int (*fn)(struct device *, void *); } compare[0]; }; ## master设备bind和unbind定义 static const struct component_master_ops rockchip_drm_ops = { .bind = rockchip_drm_bind, .unbind = rockchip_drm_unbind, };
1、component_match_add()
函数
函数功能:添加待匹配的component
组件。
函数实现:
void component_match_add(struct device *dev, struct component_match **matchptr, int (*compare)(struct device *, void *), void *compare_data) { struct component_match *match = *matchptr; ... ## 1.添加第一个待匹配的组件时,match为空,new_size大小为15 if (!match || match->num == match->alloc) { size_t new_size = match ? match->alloc + 16 : 15; ## 申请16个(对应match->compare[0] ~ match->compare[15])component_match结构体大小的内存 ## 在component_master_add_with_match()函数中,会根据实际component个数,重新申请内存 match = component_match_realloc(dev, match, new_size); *matchptr = match; ... } ## 2.初始化match match->compare[match->num].fn = compare; match->compare[match->num].data = compare_data; match->num++; }
2、component_master_add_with_match()
函数
函数功能:初始化master
设备,在匹配component
设备成功后,调用master
设备的bind
函数。
函数实现:
int component_master_add_with_match(struct device *dev, const struct component_master_ops *ops, struct component_match *match) { struct master *master; ... ## 1.若存在match,则按照实际大小重新申请内存 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); } ## 2.初始化master设备 master = kzalloc(sizeof(*master), GFP_KERNEL); ... master->dev = dev; master->ops = ops; master->match = match; INIT_LIST_HEAD(&master->components); ## 3.将master设备的node添加到masters列表 list_add(&master->node, &masters); ## 4.查找component设备,若匹配成功,则执行master设备的bind函数。 ret = try_to_bring_up_master(master, NULL); ... }
2.1、try_to_bring_up_master()
函数
函数功能:查找component
设备,若匹配成功,则执行master
设备的bind
函数。
函数实现:
static int try_to_bring_up_master(struct master *master, struct component *component) { ... ## 1.查找component设备 if (find_components(master)) { ... } ## 2.查找到所有的component设备后,调用master设备的bind函数,即rockchip_drm_bind() ret = master->ops->bind(master->dev); ... }
2.2、find_components()
函数
函数功能:逐个扫描component
设备并和master
设备匹配。若匹配成功,则添加到master
设备。
函数实现:
static int find_components(struct master *master) { struct component_match *match = master->match; ... ## 逐个扫描component设备并和master设备匹配。成功,则添加到master设备 for (i = 0; i < match->num; i++) { ret = component_master_add_child(master, match->compare[i].fn, match->compare[i].data); ... } ... }
2.3、component_master_add_child()
函数功能:在component_list
链表中扫描component
设备并匹配。若匹配成功,则添加到master
设备中。
函数实现:
int component_master_add_child(struct master *master, int (*compare)(struct device *, void *), void *compare_data) { ... ## 1.在component_list链表中扫描component设备 list_for_each_entry(c, &component_list, node) { if (c->master && c->master != master) continue; ## 2.通过compare()函数匹配component设备。若匹配,则添加到master设备中 if (compare(c->dev, compare_data)) { if (!c->master) component_attach_master(master, c); ... } } ... }
注:component
设备的相关函数都在drivers/base/omponent.c
里实现。
四、bind过程
在try_to_bring_up_master()
函数中,最终会调用master
设备的bind
函数,即rockchip_drm_bind()
,在该函数里会执行component_bind_all()
函数,调用各component
设备的bind
函数。
int component_bind_all(struct device *master_dev, void *data) { struct master *master; ... list_for_each_entry(c, &master->components, master_node) { ret = component_bind(c, master, data); ... } ... }
在代码里添加了部分log,单板启动后,打印如下:
1、添加component
设备,此时没有添加master
设备,无法匹配
[ 2.259259] [drm] Initialized drm 1.1.0 20060810 ## 1.添加encoder component设备 [ 2.260622] --- dw_hdmi_rockchip_probe [ 2.260989] dwhdmi-rockchip ff940000.hdmi: adding component (ops 0xffffff8008d51f80) [ 2.261672] === try_to_bring_up_masters ## 2.添加crtc component设备 [ 2.266464] ---- vop_probe [ 2.266819] rockchip-vop ff8f0000.vop: adding component (ops 0xffffff8008d5b808) [ 2.267468] === try_to_bring_up_masters ## 3.添加crtc component设备 [ 2.268093] ---- vop_probe [ 2.268360] rockchip-vop ff900000.vop: adding component (ops 0xffffff8008d5b808) [ 2.269007] === try_to_bring_up_masters
2、在master
设备中,添加待匹配的component
设备,即:crtc
和encoder
[ 2.269867] [drm] Rockchip DRM driver version: v1.0.1 ## 1.添加待匹配的vopb对应crtc,第一次添加申请16个component_match结构体大小的内存 [ 2.270348] --- rockchip_drm_platform_probe crtc port is port, type is <NULL>, full_name is /vop@ff900000/port [ 2.271277] === component_match_add [ 2.271613] === component_match_realloc num 15 ## 2.添加待匹配的vopl对应crtc [ 2.272040] --- rockchip_drm_platform_probe crtc port is port, type is <NULL>, full_name is /vop@ff8f0000/port [ 2.272934] === component_match_add ## 3.添加待匹配的vopb对应的encoder [ 2.273268] --- rockchip_drm_platform_probe encoder port is port, type is <NULL>, full_name is /vop@ff900000/port [ 2.274230] --- endpoint port is hdmi, type is <NULL>, full_name is /hdmi@ff940000 [ 2.274918] === component_match_add ## 4.添加待匹配的vopl对应的encoder,3和4的component相同 [ 2.275284] --- rockchip_drm_platform_probe encoder port is port, type is <NULL>, full_name is /vop@ff8f0000/port [ 2.276242] --- endpoint port is hdmi, type is <NULL>, full_name is /hdmi@ff940000 [ 2.276912] === component_match_add
3、添加master
设备,并匹配
## 1.按照实际component个数申请内存 [ 2.277261] === component_match_realloc match num 4 ## 2.开始扫描,第一个匹配 [ 2.277705] === try_to_bring_up_master [ 2.278056] === find_components match->num 0 [ 2.278441] --- compare_of [ 2.278725] --- compare_of [ 2.278725] --- compare_of [ 2.279287] --- compare_of [ 2.279695] === component_attach_master ## 3.第二个匹配 [ 2.280045] === find_components match->num 1 [ 2.280429] --- compare_of [ 2.280697] --- compare_of [ 2.280697] --- compare_of [ 2.281257] === component_attach_master ## 3.第三个匹配 [ 2.281631] === find_components match->num 2 [ 2.282014] --- compare_of [ 2.282282] === component_attach_master ## 4.第四个不用匹配 [ 2.282669] === find_components match->num 3 [ 2.283053] --- compare_of
4、执行master
和各component
设备bind
## 1.master bind [ 2.283322] try_to_bring_up_master bind [ 2.284733] --- rockchip_drm_bind ## 2. component(vopb) bind [ 2.285039] === component_bind_all component_bind [ 2.285478] rockchip-drm display-subsystem: binding ff900000.vop (ops 0xffffff8008d5b808) [ 2.286195] --- drm vop bind [ 2.286539] rockchip-vop ff900000.vop: missing rockchip,grf property [ 2.287524] rockchip-drm display-subsystem: bound ff900000.vop (ops 0xffffff8008d5b808) ## 3. component(vopl) bind [ 2.288229] === component_bind_all component_bind [ 2.288667] rockchip-drm display-subsystem: binding ff8f0000.vop (ops 0xffffff8008d5b808) [ 2.289382] --- drm vop bind [ 2.289700] rockchip-vop ff8f0000.vop: missing rockchip,grf property [ 2.290522] rockchip-drm display-subsystem: bound ff8f0000.vop (ops 0xffffff8008d5b808) ## 4. component(hdmi encoder) bind [ 2.291245] === component_bind_all component_bind [ 2.291683] rockchip-drm display-subsystem: binding ff940000.hdmi (ops 0xffffff8008d51f80) [ 2.292411] ---- dw_hdmi_rockchip_bind
© 著作权归作者所有
微博