1.先从驱动节点入手
/sys/class/display # cd HDMI/
ls
3dmode audioinfo color connect debug enable mode modes monspecs name power property scale subsystem type uevent
找一个特立独行的节点名称
grep -rI "3dmode"
drivers/video/rockchip/hdmi/rockchip-hdmi-sysfs.c: .get3dmode = hdmi_get_3dmode,
定位到文件
drivers/video/rockchip/display-sys.c
那我们看到
__ATTR(modes, S_IRUGO, display_show_modes, NULL),
cat modes对应的是
display_show_modes 这个函数,看看这个函数为啥没有添加我们显示器的分辨率
这个函数里面有一行代码
if (dsp->ops->getmodelist(dsp, &modelist))
那我们就找到对应的
drivers/video/rockchip/hdmi/rockchip-hdmi-sysfs.c
.getmodelist = hdmi_get_modelist,
这个函数长这样
static int hdmi_get_modelist(struct rk_display_device *device,
struct list_head **modelist)
{
struct hdmi *hdmi = device->priv_data;
*modelist = &hdmi->edid.modelist;
return 0;
}
那这个modelist是个啥东西?我们在kenel下面 grep -rI "modelist",出来的东西挺多,但是别慌,一眼看到正主
drivers/video/rockchip/hdmi/rockchip-hdmi-edid.c: hdmi_add_vic(vic, &pedid->modelist);
甭管它是谁的,反正给他加的是在这。那么这个函数的真身是?grep -rI "hdmi_add_vic"
drivers/video/rockchip/hdmi/rockchip-hdmi-lcdc.c:int hdmi_add_vic(int vic, struct list_head *head)
找到了也不着急找它,因为我们都知道hdmi最佳分辨率是在dtd块里面的。那么在这个文件里面我们找到hdmi_add_vic的所有调用地方
很快找到hdmi_edid_parse_dtd
有如下代码:
hdmi_edid_parse_dtd(buf + ddc_offset, vmode);
hdmi_add_vic(hdmi_videomode_to_vic(vmode), &pedid->modelist);
那么找一下这个函数
hdmi_videomode_to_vic
这个函数长这样
int hdmi_videomode_to_vic(struct fb_videomode *vmode)
{
struct fb_videomode *mode;
unsigned int vic = 0;
int i = 0;
for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
mode = (struct fb_videomode *)&(hdmi_mode[i].mode);
if (vmode->vmode == mode->vmode &&
vmode->refresh == mode->refresh &&
vmode->xres == mode->xres &&
vmode->yres == mode->yres &&
vmode->left_margin == mode->left_margin &&
vmode->right_margin == mode->right_margin &&
vmode->upper_margin == mode->upper_margin &&
vmode->lower_margin == mode->lower_margin &&
vmode->hsync_len == mode->hsync_len &&
vmode->vsync_len == mode->vsync_len) {
vic = hdmi_mode[i].vic;
break;
}
}
return vic;
}
而这个hdmi_mode 显然在drivers/video/rockchip/hdmi/rockchip-hdmi-lcdc.c中,那一串长长结构体就是。
我们就伊葫芦画瓢,添加一个自己的结构体。如下
{
.mode = {
.name = "1280x1024p@60Hz",
.refresh = 60,
.xres = 1280,
.yres = 1024,
.pixclock = 108000000,
.left_margin = 248,
.right_margin = 48,
.upper_margin = 38,
.lower_margin = 1,
.hsync_len = 112,
.vsync_len = 3,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.vmode = 0,
.flag = 0,
},
.vic = HDMI_1280X1024P_60HZ,
.vic_2nd = 0,
.pixelrepeat = 1,
.interface = OUT_P888,
},
那么这个VIC怎么写呢,我们grep一下随便系统自己的,找到drivers/video/rockchip/hdmi/rockchip-hdmi.h
enum hdmi_video_information_code里面添加一个就行了。比如我这里就是HDMI_1280X1024P_60HZ
编译固件,大功告成。如果还有添加不成功的,建议追踪一下modelist 最后你会看到有个地方hdmi_ouputmode_select,它会过滤vic。你手动给他nop掉逻辑就行啦。
这个办法改了以后,可以使显示器自动probe到合适的分辨率,但是观察到framebuffersize和它输出的不合适,因此会花屏。这就是另一个问题了。
本人初接触rk平台,这个自适应HDMI的问题,尚需进一步研究,据我所知,rk在3568以后,基本把hdmi这块完善得完全没有毛病。它找不到的时序配置,它就读edid自己生成一个配置。
简直是插什么屏,就亮什么屏,基本没有调屏的困扰。这点要为国产点赞!