2019-12-16
关键字:双屏异显
笔者手里有一块运行着 Android 5.1 的 rk3288 开发板。
最近接到一个需求:在这块开发板上实现 MIPI + EDP 双屏异显功能。
笔者手里的这块开发板默认是不支持双屏异显的,不过好在 rk 有官方补丁,合入补丁后可以支持双屏异显功能。
笔者是在网上找到的这份补丁程序,主要参考了以下两篇博客,感谢这两位博主的无私奉献:
https://www.cnblogs.com/lialong1st/p/9149213.html
https://blog.csdn.net/lb5761311/article/details/90024470
其实这两篇博客中所记载的补丁已经是将双屏异显的核心功能给支持上的了。一般来讲,合入博客中的补丁后都能成功实现双屏异显功能。但偏偏笔者就是那个“特殊情况”,笔者在仔细登入补丁后,仍然发现了一些问题,导致不能实现双异异显功能。这篇博客,就来记述一下这些问题以及解决办法。
当然,以下记载的问题现象首先都必须要保证补丁程序被正确无误地合并进去,一定要仔细检查每一行补丁代码,确保不是由于合补丁失误引发的问题。
1、主屏点不亮
上面两篇博客中都有提到,要将 uboot logo 关掉:
至少笔者手里的 MIPI 屏,或者说主屏,是在 uboot 阶段而不是在 kernel 阶段点亮的。在 uboot 阶段也会去解析 dts 配置,并根据 rockchip,uboot-logo-on 属性的值来决定是否跑 uboot 阶段的点屏操作。所以,如果你发现你在正确合入补丁以后出现了连主屏都点不亮的情况,可以尝试着将这个属性配置为1,让uboot去点一下屏。需要注意的是,rk3288不能直接烧 uboot 分区,需要编译大包才能应用到 uboot 的修改。但如果仅仅是改一下 kernel 层的 dts 文件,则可以通过烧 resource.img 来验证。
uboot 阶段的点屏流程大致如下:
./u-boot/board/rockchip/common/rkboot/fastboot.c
board_fbt_preboot();
./u-boot/common/lcd.c
drv_lcd_init();
lcd_init();
./u-boot/driver/video/rockchip_fb.c
lcd_ctrl_init();
对了,uboot 阶段点屏时解析的屏参 dts 是必须记载在根 dts 下的,即我们除了要像补丁程序中那样,在 rk_screen 节点下增加主屏参信息配置,也得在根 dts 下继续引用完整的屏参文件:
如果没有像上图那样 include 进来完整的 MIPI 屏参文件,uboot阶段点屏时会报找不到 display-timing 节点错误的。
一般来说,按照上面的步骤操作以后都能点亮主屏。
2、副屏不亮
副屏是无法在 uboot 阶段点亮的。或者说 uboot 默认只点了一块屏幕,如果你硬要像点主屏一样在 uboot 阶段副屏也点亮,那只能你自己去研究修改 uboot 代码了。
笔者的副屏不亮就没有动过 uboot 的代码。
在笔者的 rk3288 中,主屏的视频数据是来自于 fb0 的,而副屏的是来自于 fb4 的:dev/graphics/fb4。我们首先来查一下 fb4 的基础屏参信息:
cat /sys/class/graphics/fb4/screen_info
这里要确保副屏的分辨率与帧率与我们手里实际的屏幕对的上。如果对不上,比如笔者的之前就出现过副屏解析成 480x320 的情况。这样就当然点不亮了。如果出现了分辨率被解析错了的情况,修改以下这个文件:
./kernel/drivers/video/rockchip/lcdc/rk3288_lcdc.c
将 lcdc_read_reg_defalut_cfg 函数的设置屏幕分辨率的代码注释掉,如下图所示:
注掉这两段代码,可以解决分辨率被修改的问题。
如果发现分辨率与帧率都正确了,仍然点不亮,则可以查一下副屏的时钟,即 lcdc1 的时钟。
查询方式有好几种,第一种是看开机打印:
第二种方式是直接查询时钟配置表:
cat /d/clk/clk_summary | grep lcdc
lcdc1 的时钟必须在副屏的可接受范围以内,否则相当于副屏的屏参不正确,当然点不亮了。
如果发现 lcdc1 的时钟频率不对,与自己在 dtsi 中填写的不一致,则要修改 dtsi。
系统是在哪里强制将你设定在 dtsi 中的时钟频率给修改掉的呢?在以下代码中的 set_dclk 函数中。
./kernel/drivers/video/rockchip/lcdc/rk3288_lcdc.c
当初始化副屏时,这个函数会去执行上图红箭头所指的函数,并在里面根据一些条件来应用或修改你设定的频率值。有兴趣的可以加打印跟踪一下这个函数流程,它并不复杂,不过笔者就不在这里贴出来了。
总而言之,解决时钟频率被修改的办法就是加打印跟踪,并将副屏 dtsi 中的时钟频率设置成系统强制设给你的频率的倍数,当然这个倍数也得在你的屏幕的可接受范围之内才行。
3、HDMI不插副屏不亮
可能有些同学是没有严格按照补丁程序将 dts 中的 hdmi 节点给关闭掉的。
关不关 hdmi 本身不会影响双屏异显功能,但有的同学可能会发现一个神奇的现象:HDMI不插时副屏死活点不亮。
这其实是 rk3288 的机制为之。这个板子默认就将 lcdc1 与 HDMI 绑定死了的。没有HDMI时就不给 lcdc1 送视频数据。更过分的是当插了 HDMI 时,副屏虽然亮了,但使用的屏参却是 HDMI 显示器的。换句话说,如果你所接的 HDMI 显示器的屏参与你要点的副屏的屏参差异较大,是有可能出现插了 HDMI 后副屏黑掉的情况的。所以严格来讲,应该是当要用双屏异显时就关掉 HDMI 功能,当要使用 HDMI 时就不要用双屏异显功能。
不过如果我们不考虑兼容性而非要同时使用双屏异显与 HDMI 怎么办呢?
也简单,在确保了 fb4/screen_info 中的分辨率与 lcdc1 的时钟正确以后,在 android 系统中设置一条属性:
ro.htg.force=1
即可。即在 /system/build.prop 上添加上这条属性,重启即可。
4、HDMI拨掉导致副屏熄灭
前面有提到,rk3288 默认将 lcdc1 与 HDMI 绑定死了。当检测到拨掉 HDMI 时就不往 lcdc1 送视频数据。
所以最简单的解决办法就是不上报 HDMI 的拨出事件。只需修改一处代码即可,如下图所示:
5、副屏花屏
修改副屏的屏参,如果屏参正确了,则将上面第 3 步提到的 ro.htg.force=1 配置一下基本也能解决的了。