修改RK3399 HDMI显示分辨率

转载自:
[RK3399] HDMI正常输出4K30帧 无法输出60帧以及设置分辨率的流程分析
**
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

def_modes[1] = {97};//3840x2160P60

烧录设备结果:hdmi输出显示屏黑屏 cat 设备结果如下
在这里插入图片描述

特殊分辨率 def_modes[1] = {108};//特殊分辨率 800x1280P60
/* 108 - 800x1280@60Hz */
kernel/drivers/gpu/drm/drm_edid.c里edid_cea_modes[]:新增如下特殊分辨率:
{ DRM_MODE(“800x1280”, DRM_MODE_TYPE_DRIVER, 76000, 800, 848,
880, 960, 0, 1280, 1300, 1304, 1314, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
烧录设备结果:出图正常 cat 设备结果如下
在这里插入图片描述
在这里插入图片描述

原因:显示屏不支持4K60hz,支支持4K30hz,所以导致设备分辨率为60hz时黑屏
其工作流程:底层通过edid,读取到显示器的分辨率列表,然后反馈给Android系统,在系统界面里显示出来
设置分辨率的流程分析

先通过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);分配和复制现有模式, 返回:成功时指向复制模式的指针,错误时为空。

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值