Chinaunix首页 | 论坛 | 博客
  • 博客访问: 154718
  • 博文数量: 49
  • 博客积分: 45
  • 博客等级: 民兵
  • 技术积分: 545
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-23 13:22
文章分类
文章存档

2017年(5)

2016年(18)

2015年(18)

2014年(8)

我的朋友

分类: 嵌入式

2014-04-23 10:34:40


                   LCD 调试总结

 

 

数据流程:

 

Framebuffer  -> DC  -> Dsi  ->  Dsi83 -> LCD 

 

DC 通过DMAframebuffer 取数据 ,然后通过并口传递给Dsi , Dsi 输出mipi 信号给Dsi83 , Dsi83 MIPI 信号转成LVDS 信号给LCD 

 

 

初始化流程:

 

首先得给各个器件上电,然后执行各个控制器的初始化代码,这个过程里面要确保各个信号的稳定性以及时序符合芯片要求,这是调试驱动的第一步,这一步不能确保后面不管怎么搞都是瞎搞。

 

 

遇到的问题:

 

一、不知道pclk 是什么意思,也不了解pclk mipi clk 的换算关系:

 

1Pclk 是一秒钟要送出的总的像素点,实际上就是 一行的像素点*总行数*帧率

 

2mipi clk 的算式就是mipi clk = pclk * bpp/num(lane)*2

文字解释,pclk*bpp 就是一秒要送出的总的bit 位也就是比特率,这是每一秒由DC 送给Dsi 的数据,因为它在芯片内部是以并口的形式送出的,而Dsi 拿到数据后是以串口的形式送出的,所以这里计算mipiclk 要除以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,背光数据的初始化,2LCD相关上电时序的控制,3DSI 输出信号的配置(需要匹配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)


 

 




阅读(4101) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~