LCD 调试总结
数据流程:
Framebuffer -> DC -> Dsi -> Dsi83 -> LCD
DC 通过DMA从framebuffer取数据 ,然后通过并口传递给Dsi , Dsi输出mipi信号给Dsi83 , Dsi83将MIPI信号转成LVDS信号给LCD。
初始化流程:
首先得给各个器件上电,然后执行各个控制器的初始化代码,这个过程里面要确保各个信号的稳定性以及时序符合芯片要求,这是调试驱动的第一步,这一步不能确保后面不管怎么搞都是瞎搞。
遇到的问题:
一、不知道pclk是什么意思,也不了解pclk与mipi clk的换算关系:
1,Pclk是一秒钟要送出的总的像素点,实际上就是 一行的像素点*总行数*帧率
2,mipi clk的算式就是mipi clk = pclk * bpp/num(lane)*2
文字解释,pclk*bpp就是一秒要送出的总的bit位也就是比特率,这是每一秒由DC送给Dsi的数据,因为它在芯片内部是以并口的形式送出的,而Dsi拿到数据后是以串口的形式送出的,所以这里计算mipi的clk要除以lane的总数,又因为mipi是上升沿下降沿都取数据,所以这里要除以2。
二、这次主要是遇到LCD不断闪屏,为了debug做过的实验有:
1, 测试模式下用mipi clk,仍然闪屏
2,测试模式下用外部clk,不闪屏
实际上从这里就有理由怀疑mipi的输出有问题,从原理上来看接下来也应该去check dsi的输出信号,但是因为mipi没有测试点接出来,所以一开始居然避开了这一项检测,转而去狂填参数,现在想起来大概是因为填参数对软件而言比较容易,但实在是没什么道理,我也对一开始没有坚持自己的推理让硬件去测信号感到不满。
解决问题:
最终吹掉dsi83 IC,量mipi信号,发现时钟的确输出不连贯,而对比使用该IC的能正常显示的板子,其clk是连贯的。那么我们首先要保证mipi信号输出的正确性。
最后改掉一个控制clk的 参数TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS即可。
总结: 遇到问题,应该跳出来,找人喝茶聊天,根据原理寻找思路,而不是匆匆忙忙冒冒失失的一头扎进去,以至深陷其中,不能自拔。
最后附上一张图:

方向不对,越努力越尴尬。
========================================华丽丽的分界线================代码======================
代码介绍:
英伟达平台:
对于linux内核显示相关代码在Dc.c (drivers\video\tegra\dc)目录下。
这是display control的驱动文件,在这个文件中首先看driver结构体:
struct platform_driver tegra_dc_driver = {
.driver = {
.name = "tegradc",// 根据这个名字找到对应设备资源
.owner = THIS_MODULE,
},
.probe = tegra_dc_probe,
.remove = tegra_dc_remove,
#ifdef CONFIG_PM
.suspend = tegra_dc_suspend,
.resume = tegra_dc_resume,
#endif
.shutdown = tegra_dc_shutdown,
};
设备资源在文件Board-macallan-panel.c (arch\arm\mach-tegra) 中
static struct platform_device macallan_disp2_device = {
.name= "tegradc",
.id= 1,
.resource= macallan_disp2_resources,
.num_resources= ARRAY_SIZE(macallan_disp2_resources),
.dev = {
.platform_data = &macallan_disp2_pdata,
},
};
static struct platform_device macallan_disp1_device = {
.name= "tegradc",
.id= 0,
.resource= macallan_disp1_resources,
.num_resources= ARRAY_SIZE(macallan_disp1_resources),
.dev = {
.platform_data = &macallan_disp1_pdata,
},
};
这里tegra4有两个控制器,一个给Dsi用,另一个给HDMI用。这些板级资源的具体功能需要对照tegra4的spec来看,主要是一些寄存器的配置。
然后在看DC和DSI的控制器初始化代码前得看panel的代码,因为DC和DSI输出要匹配panel的接受,两者不匹配就会出问题,匹配了,就OK!
DC 的输出分HDMI和DSI,他们的配置是如下函数设置的:
static void tegra_dc_set_out(struct tegra_dc *dc, struct tegra_dc_out *out)
{
struct tegra_dc_mode *mode;
dc->out = out;
printk("liucong tegra_dc_set_out\n");
mode = tegra_dc_get_override_mode(dc);
if (mode)
tegra_dc_set_mode(dc, mode);
else if (out->n_modes > 0)
tegra_dc_set_mode(dc, &dc->out->modes[0]);
switch (out->type) {
case TEGRA_DC_OUT_RGB:
dc->out_ops = &tegra_dc_rgb_ops;
break;
case TEGRA_DC_OUT_HDMI:
dc->out_ops = &tegra_dc_hdmi_ops;
break;
case TEGRA_DC_OUT_DSI:
dc->out_ops = &tegra_dc_dsi_ops;// 通用显示串行输出接口,这里是mipi控制器的操作接口
break;
default:
dc->out_ops = NULL;
break;
}
if (dc->out_ops && dc->out_ops->init)
dc->out_ops->init(dc);
}
望文生义,tegra_dc_set_out就是设置DC的输出,这里是以结构体的方式赋值的,这个结构体包含了具体输出的各种接口,比如DSI的tegra_dc_dsi_ops:
struct tegra_dc_out_ops tegra_dc_dsi_ops = {
.init = tegra_dc_dsi_init,
.destroy = tegra_dc_dsi_destroy,
.enable = tegra_dc_dsi_enable,
.postpoweron = tegra_dc_dsi_postpoweron,
.disable = tegra_dc_dsi_disable,
.postpoweroff = tegra_dc_dsi_postpoweroff,
.hold = tegra_dc_dsi_hold_host,
.release = tegra_dc_dsi_release_host,
#ifdef CONFIG_PM
.suspend = tegra_dc_dsi_suspend,
.resume = tegra_dc_dsi_resume,
#endif
.setup_clk = tegra_dc_dsi_setup_clk,
};
Panel 的代码在Panel-p-wuxga-10-1.c (arch\arm\mach-tegra)
这里主要做三件事,1,背光数据的初始化,2,LCD相关上电时序的控制,3,DSI输出信号的配置(需要匹配panel)
背光初始化和上电时序就不说了,这里说下第三点:
static struct tegra_dc_mode dsi_p_wuxga_10_1_modes[] = {
{
.pclk = 68900000,
.h_ref_to_sync = 10,// 4
.v_ref_to_sync = 1,// 1
.h_sync_width = 32,// 16
.v_sync_width = 6,// 2
.h_back_porch = 80,// 32
.v_back_porch = 14,// 16
.h_active = 1280,// 1920
.v_active = 800,// 1200
.h_front_porch = 48,// 120
.v_front_porch = 3,// 17
},
};
望文生义,看这个结构体的名字就知道tegra_dc_mode是配置DC输出要求的,这里有PCLK HBP HFP HWP VBP VFP VWP等,他们的具体含义请自行百度了。
另外还有一个比较重要的结构体:
static struct tegra_dsi_out dsi_p_wuxga_10_1_pdata = {
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
.n_data_lanes = 2,
.controller_vs = DSI_VS_0,
#else
.controller_vs = DSI_VS_1,
#endif
.n_data_lanes = 2,
.video_burst_mode = TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END,
.pixel_format = TEGRA_DSI_PIXEL_FORMAT_24BIT_P,
.refresh_rate = 60,
.virtual_channel = TEGRA_DSI_VIRTUAL_CHANNEL_0,
.dsi_instance = DSI_INSTANCE_0,
.dsi2lvds_bridge_enable = 1,
.panel_reset = DSI_PANEL_RESET,
.power_saving_suspend = true,
.video_data_type = TEGRA_DSI_VIDEO_TYPE_VIDEO_MODE,
.video_clock_mode = TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS,// 这次卡这里了
.dsi_init_cmd = dsi_p_1280x800_8_0_init_cmd,
.n_init_cmd = ARRAY_SIZE(dsi_p_1280x800_8_0_init_cmd),
};
同样望文生义 tegra_dsi_out是配置dsi输出信号的,这些都很重要,具体含义也不细说了,看注释或百度即可。
一般而言,上面的信息填好后panel就可以工作了,但我们这里还有个转接芯片,转接芯片的代码在Dsi2lvds.c (drivers\video\tegra\dc),这里面就是做了dsi83芯片的初始化,通过I2C接口。
另外我们还要注意 的是,这个Dsi是用的mipi协议,要注意MIPI协议的一些规范,以及内核提供给我们的mipi协议的接口,比如进入LP模式的接口tegra_dsi_set_to_lp_mode等。代码在Dsi.c (drivers\video\tegra\dc)
=============================初始化流程========================
Init 流程:
[ 2.012377] [] (unwind_backtrace+0x0/0x140) from [] (tegra_dsi2lvds_init+0x20/0xd8)
[ 2.012821] [] (tegra_dsi2lvds_init+0x20/0xd8) from [] (__tegra_dc_dsi_init+0x80/0xd8)
[ 2.013300] [] (__tegra_dc_dsi_init+0x80/0xd8) from [] (_tegra_dc_dsi_init+0x23c/0x3b8)
[ 2.013733] [] (_tegra_dc_dsi_init+0x23c/0x3b8) from [] (tegra_dc_dsi_init+0x14/0xcc)
[ 2.014165] [] (tegra_dc_dsi_init+0x14/0xcc) from [] (tegra_dc_set_out+0x88/0x10c)
[ 2.014455] [] (tegra_dc_set_out+0x88/0x10c) from [] (tegra_dc_probe+0x558/0xb88)
[ 2.014881] [] (tegra_dc_probe+0x558/0xb88) from [] (platform_drv_probe+0x20/0x24)
[ 2.015345] [] (platform_drv_probe+0x20/0x24) from [] (really_probe+0x7c/0x2f0)
[ 2.015780] [] (really_probe+0x7c/0x2f0) from [] (driver_probe_device+0x4c/0xa8)
[ 2.016200] [] (driver_probe_device+0x4c/0xa8) from [] (__driver_attach+0x94/0x98)
[ 2.016670] [] (__driver_attach+0x94/0x98) from [] (bus_for_each_dev+0x68/0x9c)
[ 2.016933] [] (bus_for_each_dev+0x68/0x9c) from [] (bus_add_driver+0x190/0x270)
[ 2.017405] [] (bus_add_driver+0x190/0x270) from [] (driver_register+0x80/0x134)
[ 2.017832] [] (driver_register+0x80/0x134) from [] (do_one_initcall+0xa0/0x100)
[ 2.018294] [] (do_one_initcall+0xa0/0x100) from [] (do_initcalls+0x78/0xac)
[ 2.018721] [] (do_initcalls+0x78/0xac) from [] (kernel_init+0x90/0x128)
[ 2.018976] [] (kernel_init+0x90/0x128) from [] (kernel_thread_exit+0x0/0x8)
Enable 流程:
[ 2.121421] [] (unwind_backtrace+0x0/0x140) from [] (tegra_dsi2lvds_enable+0x18/0x208)
[ 2.121856] [] (tegra_dsi2lvds_enable+0x18/0x208) from [] (tegra_dc_dsi_enable+0xb0/0x250)
[ 2.122339] [] (tegra_dc_dsi_enable+0xb0/0x250) from [] (_tegra_dc_controller_enable+0x300/0x640)
[ 2.122779] [] (_tegra_dc_controller_enable+0x300/0x640) from [] (tegra_dc_probe+0x6b8/0xb88)
[ 2.123211] [] (tegra_dc_probe+0x6b8/0xb88) from [] (platform_drv_probe+0x20/0x24)
[ 2.123687] [] (platform_drv_probe+0x20/0x24) from [] (really_probe+0x7c/0x2f0)
[ 2.124110] [] (really_probe+0x7c/0x2f0) from [] (driver_probe_device+0x4c/0xa8)
[ 2.124396] [] (driver_probe_device+0x4c/0xa8) from [] (__driver_attach+0x94/0x98)
[ 2.124821] [] (__driver_attach+0x94/0x98) from [] (bus_for_each_dev+0x68/0x9c)
[ 2.125255] [] (bus_for_each_dev+0x68/0x9c) from [] (bus_add_driver+0x190/0x270)
[ 2.125724] [] (bus_add_driver+0x190/0x270) from [] (driver_register+0x80/0x134)
[ 2.126146] [] (driver_register+0x80/0x134) from [] (do_one_initcall+0xa0/0x100)
[ 2.126462] [] (do_one_initcall+0xa0/0x100) from [] (do_initcalls+0x78/0xac)
[ 2.126721] [] (do_initcalls+0x78/0xac) from [] (kernel_init+0x90/0x128)
[ 2.127154] [] (kernel_init+0x90/0x128) from [] (kernel_thread_exit+0x0/0x8)
2243




被折叠的 条评论
为什么被折叠?



