**
Platform: ROCKCHIP
Chip: RK3399
OS: Android7.1.2
Kernel: 4.4.126*
**
【接上篇】上篇虽然HDMI能正常输出4K,但是帧率却达不到60帧,只能30帧,具体分析如下
按网上和官方的分别试了下修改,均没成功kernel/driversideo/rockchipmi/rockchip-hdmiv2 中的 rockchip-hdmi.h 文件,
/* HDMI default vide mode */
#define HDMI_VIDEO_DEFAULT_MODE HDMI_1280X720P_60HZ
又在dtsi中加入 rockchip,defaultmode = <4>;也没有成功。
以上是开机那时候的分辨率。
将输出特殊分辨率的方法输出
相关文件:
kernel/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
kernel/drivers/gpu/drm/drm_edid.c
如上修改:
1、在edid_cea_modes数据的最后定义特殊的分辨率(drm_edid.c文件中)。
2、把def_mode数组的第一个值改成特殊分辨率对应的 vic(vic在drivers/gpu/drm/drm_edid.c文件中edid_cea_modes结构体中).
3、edid = NULL;强制把edid赋为NULL,不管有没有读到edid都强制按def_modes来显示。
kernel/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c下的函数dw_hdmi_connector_get_modes(),修改def_modes
先通过i2c获取屏的edid信息。
EDID的全称是Extended Display Identification Data(扩展显示标识数据),共有128字节。其中包含有关显示器及其性能的参数,包括供应商信息、最大图像大小、颜色设置、厂商预设置、
频率范围的限制以及显示器名和序列号的字符串等等。
如何查看edid信息?
cat sys/class/drm/card0-HDMI-A-1/edid > /data/edid.bin //然后把edid.bin拷贝出来
或者:cat sys/class/drm/card0-HDMI-A-1/edid |busybox hexdump
驱动文件清单
通用屏配置驱动:
drivers/gpu/drm/panel/panel-simple.c //.c文件里面包含mipi的时序参数配置和mipi一些接口还有背光的使能关闭等,配置屏参可以在此文件或者dts
Core:
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
framebuffer drivers/gpu/drm/rockchip/rockchip_drm_fb.c
gem drivers/gpu/drm/rockchip/rockchip_drm_gem.c
vop:
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/rockchip/rockchip_vop_reg.c
lvds:
drivers/gpu/drm/rockchip/rockchip_lvds.c
rga:
drivers/gpu/drm/rockchip/rockchip_drm_rga.c
mipi:
drivers/gpu/drm/rockchip/dw-mipi-dsi.c
hdmi:
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
drivers/gpu/drm/bridge/dw-hdmi.c
inno hdmi:
drivers/gpu/drm/rockchip/inno_hdmi.c
edp:
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
dp:
drivers/gpu/drm/rockchip/cdn-dp-core.c
drivers/gpu/drm/rockchip/cdn-dp-reg.c
具体相关接口分析:
基于component框架, 在probe阶段解析dts中各个设备的信息, 加到component match 列表中, 等所有设备加
载完毕后, 就会引发master设备的bind.
Rockchip drm主设备驱动:drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
VOP驱动:drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/rockchip/rockchip_vop_reg.c
图层接口:
static const struct drm_plane_helper_funcs plane_helper_funcs = {
// 预先对图层进行处理
.prepare_fb = vop_plane_prepare_fb,
// 图层显示完成后的处理
.cleanup_fb = vop_plane_cleanup_fb,
// 在显示前进行参数检查
.atomic_check = vop_plane_atomic_check,
// 更新图层参数
.atomic_update = vop_plane_atomic_update,
// 关闭图层
.atomic_disable = vop_plane_atomic_disable,
};
VOP接口:
static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
// 使能vop, 在这里面会将timing配好
.enable = vop_crtc_enable,
// 关闭vop
.disable = vop_crtc_disable,
// 对timing进行检查修正
.mode_fixup = vop_crtc_mode_fixup,
// 在一帧显示开始前做的处理
.atomic_begin = vop_crtc_atomic_begin,
// 检查显示的参数
.atomic_check = vop_crtc_atomic_check,
// 提交硬件显示
.atomic_flush = vop_crtc_atomic_flush,
};
接口执行顺序:
vop_plane_atomic_check //在显示前进行参数检查
vop_plane_prepare_fb //预先对图层进行处理
vop_plane_atomic_update //更新图层参数
vop_crtc_atomic_flush //提交硬件显示
vop_plane_cleanup_fb //图层显示完成后的处理
对应文件:
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
./drivers/gpu/drm/drm_edid.c
调用get_modes获取分辨率的时候会去调用
.get_modes = dw_hdmi_connector_get_modes
->edid = drm_get_edid(connector, hdmi->ddc); //获取edid
->drm_do_get_edid
->drm_do_probe_ddc_edid //尝试通过i2获取edid信息,成功时为0,失败时为-1。
->drm_get_displayid //如果edid存在,则获取显示id
如果获取到edid,则调用:
hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); //检测显示器是否是HDMI,是就返回true,否则return false;
->drm_find_cea_extension //
->drm_find_edid_extension //在edid中搜索CEA扩展块
->if (cea_db_is_hdmi_vsdb(&edid_ext[i]))
return true; //因为HDMI标识符在特定于供应商的块中,所以从CEA扩展的所有数据块中搜索它。
hdmi->sink_has_audio = drm_detect_monitor_audio(edid); //检测显示器audio音频功能,如果显示器支持音频,就返回true,否则return false;
drm_mode_connector_update_edid_property(connector, edid); //更新连接器的edid属性
cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid);
ret = drm_add_edid_modes(connector, edid); //从连接的显示器中读取到的edid数据添加分辨率[mode](如果mode可用),
*edid spec说 mode(分辨率)应该按以下顺序优先选择:
*-首选 详细 mode(分辨率)
*-来自基础块的其他详细 mode(分辨率)
*-扩展块的详细 mode(分辨率)
*-CVT 3字节代码 mode(分辨率)
*-标准定时代码
*-已建立的时间代码
*-根据GTF或CVT范围信息推断的 mode(分辨率)
/* Store the ELD */
drm_edid_to_eld(connector, edid); //从edid构建ELD, 填充ELD(类似于edid的数据)缓冲区以传递给音频驱动程序。这个HDCP和端口字段留给图形驱动程序填写。
drm_mode_connector_update_hdr_property(connector, metedata); //原子替换现有blob属性
如果获取不到edid,则调用:
hdmi->sink_is_hdmi = true;
hdmi->sink_has_audio = true;
for (i = 0; i < sizeof(def_modes); i++) { //去遍历def_mode数组的值,他们对应在edid_cea_modes里面的分辨率[mode]-->取自CEA-861规范。
mode = drm_display_mode_from_vic_index(connector, def_modes, 31, i); //调用该接口来设置def_modes数组中第一个分辨率值
->调用vic = svd_to_vic(video_db[video_index]); // vic值对应 edid_cea_modes 中的分辨率参数
->if (!drm_valid_cea_vic(vic))
->vic > 0 && vic < ARRAY_SIZE(edid_cea_modes); 则设置 edid_cea_modes 里面相应的分辨率
->newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]);
->drm_mode_copy(nmode, mode);分配和复制现有模式, 返回:成功时指向复制模式的指针,错误时为空。