博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口)
阅读量:4104 次
发布时间:2019-05-25

本文共 9161 字,大约阅读时间需要 30 分钟。

一:点亮lcd inkernel

其实点亮lcd很简单必须保证以后几个步骤正确:

1:确认Lcd信息所在文件被编译进去,并且lcd 和board name里面注册一质,倘若这部正确,那么log里面应该有对应分辨率的一段framebuffer同时调到相对应的power_on函数。对于lcdc panel对应文件在lcdc_xx.c,对于mipi panel对应文件在mipi_xx.c(下序列操作)和mipi_xxxx.c(timing pll clk等初始化操作)。

2:仔细检查上电同时测量,同时enable28跟rgb对应gpio设为lcdc func。对于传统的lcd不需要RST操作只需拉高即可,对于mipi和需要下code的RGB panel需要RST高低高操作,这样code才生效。注意一般sleep out(0x11)和display on(0x29)之间需要mdelay(100)左右,貌似这个对于大部分panel是必须的。

3:如果以上操作正常同时序列正确,那么屏幕应该可以点亮。对于遇到的有以下问题:

a:屏幕呈现白色或者花瓶状态,说明lcd初始化成功,但是没有rgb刷过来。认真检查之后发现pclk时序不对,由于是新的平台所以设对以后,以后的屏就好办了。

b:RGB pane内容l闪烁通常由pclk设置不对导致还有可能与porch有关。通常wvga 16bit的panel使用24.5M的PCLK,qhd的24bit panel 30M PCLK。至于porch我们可以多替换几组试试或者找FAE发个可以点亮的。一般屏对porch要求不高,几乎都可以点亮的。

c:FPC没有贴好也有可能导致屏幕不亮。

d:rest有问题,一定仔细测量使用示波器看出波形,比如lk下面有时可能就没有控制对。

e:许多kernel里面实现的但是在lk下面由于代码比较少,就不好实现,比如pm上电,vibrator等等,其实在kernel里面归根也是写对应寄存器的,很简单,最好使的办法就是在kernel里面读出来,在在lk里面写进去,这样就好办了。8x平台许多上电我就是这样做的,还有mipi的dsi相关设置clk的REG。

f:屏幕经常唤醒只显示灰色底面,最后查明寄存器没有使能外部升压电路。

g:唤醒屏幕闪白光问题,说白了是背光早亮了,很有可能是下序列mdelay太久,改小点就没有这个问题了。根本原因屏幕初始化序列下慢了。亲身经历的。

h:lcd唤醒闪屏问题,这个是由于每次重新RST下序列过程delay久了导致,适当减少delay时间即可。

i:用厂商给的序列要么屏点不亮要么界面有水波纹,这些通常都是rgb interface polarity导致,需要调整pclk hsync vsync de极性使之符合平台极性。

二:深入分析

高通平台屏幕亮起来必须满足一下条件

Lcdc interface:

1:enable mdp core clk(max 200M)

2:enable pixel clk(pclk)(refer to panel spec),configure polarity of pclk,vsync,hsync,de.

3:enable 0-27gpio as lcdc func and power on

4:downloade code.(not necessary)

Mipi interface:

1:enable mdp core clk(max 200M)

2:enable bit clk(refer to panel spec),shoud set pll reg.

3:enable a series of dsi clk(du to display )

4:downloade code.

三:点亮lcd in bootloader

      由于开机logo的需要,故需要在bootloader lk里面将lcd给驱动起来,这样才可以显示开机logo。由于lk下面的代码没有kernel里面丰富。故lk写了很精致的代码主要还是写寄存器从而控制硬件,其实在kernel里面也写了寄存器但是由于代码量太多,可能有时找起来不是很方便,下面等会贴出部分关键代码,再比较kernel和lk,需要强调的是驱动从本质上说都是些寄存器控制硬件,任何外界硬件都是一样的实现。

    其实lk里面点亮lcd和kernel里面一样

Lcdc interface:

1:enable mdp core clk(max 200M)

2:enable pixel clk(pclk)(refer to panel spec),configure polarity of pclk,vsync,hsync,de.

3:enable 0-27gpio as lcdc func and power on

4:downloade code.(not necessary)

Mipi interface:

1:enable mdp core clk(max 200M)

2:enable bit clk(refer to panel spec),shoud set pll reg.

3:enable a series of dsi clk(du to display )

4:downloade code.

但是在lk里面点亮起来可能更加难度大点,lk里面调试需要串口线相比而言复杂点。

最近在lk里面点亮一款mipi 4lane video mode 720p的panel耗了不少时间,复杂度比kernel里面难多了。

问题1:遇到不显示的问题,查后发现配置的pll reg在kernel里面重写了,故需要在kernel里面读出来,再

填入lk里面,其事用来配置bit clock通常mipi panel必须要300-500M的CLK,而其实现高通平台就是写pll reg的。注意clk或大或小不会影响显示的,可能不匹配会造成屏幕闪烁,与其刷新率没有对上。

static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = {

/* DSI Bit Clock at 500 MHz, 2 lane, RGB888 */

/* regulator */

{0x03, 0x01, 0x01, 0x00},

/* timing   */

{0xb9, 0x8e, 0x1f, 0x00, 0x98, 0x9c, 0x22, 0x90,

0x18, 0x03, 0x04},

/* phy ctrl */

{0x7f, 0x00, 0x00, 0x00},

/* strength */

{0xbb, 0x02, 0x06, 0x00},

/* pll control */    在这里配置的clk,计算方法高通有个自动计算工具

{0x00, 0xec, 0x31, 0xd2, 0x00, 0x40, 0x37, 0x62,

0x01, 0x0f, 0x07,

0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0},

};

8x60有个重配的函数

int mipi_dsi_phy_pll_config(u32 clk_rate)

{

struct dsiphy_pll_divider_config *dividers;

u32 fb_divider, tmp;

dividers = &pll_divider_config;

/* DSIPHY_PLL_CTRL_x:    1     2     3     8     9     10 */

/* masks               0xff  0x07  0x3f  0x0f  0xff  0xff */

/* DSIPHY_PLL_CTRL_1 */

fb_divider = ((dividers->fb_divider) / 2) - 1;

MIPI_OUTP(MIPI_DSI_BASE + 0x204, fb_divider & 0xff);

/* DSIPHY_PLL_CTRL_2 */

tmp = MIPI_INP(MIPI_DSI_BASE + 0x208);

tmp &= ~0x07;

tmp |= (fb_divider >> 8) & 0x07;

MIPI_OUTP(MIPI_DSI_BASE + 0x208, tmp);

/* DSIPHY_PLL_CTRL_3 */

tmp = MIPI_INP(MIPI_DSI_BASE + 0x20c);

tmp &= ~0x3f;

tmp |= (dividers->ref_divider_ratio - 1) & 0x3f;

MIPI_OUTP(MIPI_DSI_BASE + 0x20c, tmp);

/* DSIPHY_PLL_CTRL_8 */

tmp = MIPI_INP(MIPI_DSI_BASE + 0x220);

tmp &= ~0x0f;

tmp |= (dividers->bit_clk_divider - 1) & 0x0f;

MIPI_OUTP(MIPI_DSI_BASE + 0x220, tmp);

/* DSIPHY_PLL_CTRL_9 */

MIPI_OUTP(MIPI_DSI_BASE + 0x224, (dividers->byte_clk_divider - 1));

/* DSIPHY_PLL_CTRL_10 */

MIPI_OUTP(MIPI_DSI_BASE + 0x228, (dividers->dsi_clk_divider - 1));

return 0;

}

所以lk里面填入的pll需要在kernel里面读出,再填入数组即可。其实许多操作都可以从kernel里面读出,在lk里面写入,比如给一系列的pm某个管脚上电,enable vibrate in lk等等,就是在kernel里面读出操作其寄存器的值,再在lk里面写入!用到的非常平凡,下面还有。

在lk里面mipi的瓶只要上电正常,RESET正常,这些必要手动测出的这是第一步,之后下载序列,屏幕有花屏,就说明可以下进去的,屏幕有反应。

问题二:有遇见在lk下面mipi 的屏显示不对的问题还有彩色不对,显示不对是dsi某个寄存器的值和kernel里面不一样,由于是video mode至于色彩是rgb或者bgr等打包方式不对,换下就好了。

在msm_dss_io_8x60.c中有写dis clk和dsi pclk的寄存器的2个函数

Kernel:

[cpp]
  1. static void mipi_dsi_pclk_ctrl(struct dsi_clk_desc *clk, int clk_en) 
  2.  
  3.  
  4. char *cc, *ns, *md; 
  5.  
  6. char mnd_en = 1, root_en = 1; 
  7.  
  8. uint32 data, val; 
  9.  
  10.  
  11. cc = mmss_cc_base + 0x0130; 
  12.  
  13. md = mmss_cc_base + 0x0134; 
  14.  
  15. ns = mmss_cc_base + 0x0138; 
  16.  
  17.  
  18. if (clk_en) { 
  19.  
  20. if (clk->mnd_mode == 0) { 
  21.  
  22. data  = clk->pre_div_func << 12; 
  23.  
  24. data |= clk->src; 
  25.  
  26. MIPI_OUTP_SECURE(ns, data); 
  27.  
  28. MIPI_OUTP_SECURE(cc, ((clk->mnd_mode << 6) 
  29.  
  30.       | (root_en << 2) | clk_en)); 
  31.  
  32. } else
  33.  
  34. val = clk->d * 2; 
  35.  
  36. data = (~val) & 0x0ff; 
  37.  
  38. data |= clk->m << 8; 
  39.  
  40. MIPI_OUTP_SECURE(md, data); 
  41.  
  42.  
  43. val = clk->n - clk->m; 
  44.  
  45. data = (~val) & 0x0ff; 
  46.  
  47. data <<= 24; 
  48.  
  49. data |= clk->src; 
  50.  
  51. MIPI_OUTP_SECURE(ns, data); 
  52.  
  53.  
  54. MIPI_OUTP_SECURE(cc, ((clk->mnd_mode << 6) 
  55.  
  56.       | (mnd_en << 5) 
  57.  
  58.       | (root_en << 2) | clk_en)); 
  59.  
  60.  
  61.  
  62. } else 
  63.  
  64. MIPI_OUTP_SECURE(cc, 0); 
  65.  
  66.  
  67. wmb(); 
  68.  
  69.  
  70.  
  71.  
  72.  
  73. <span style="font-family: SimSun; font-size: 14px;"></span> 
static void mipi_dsi_pclk_ctrl(struct dsi_clk_desc *clk, int clk_en){char *cc, *ns, *md;char mnd_en = 1, root_en = 1;uint32 data, val;cc = mmss_cc_base + 0x0130;md = mmss_cc_base + 0x0134;ns = mmss_cc_base + 0x0138;if (clk_en) {if (clk->mnd_mode == 0) {data  = clk->pre_div_func << 12;data |= clk->src;MIPI_OUTP_SECURE(ns, data);MIPI_OUTP_SECURE(cc, ((clk->mnd_mode << 6)      | (root_en << 2) | clk_en));} else {val = clk->d * 2;data = (~val) & 0x0ff;data |= clk->m << 8;MIPI_OUTP_SECURE(md, data);val = clk->n - clk->m;data = (~val) & 0x0ff;data <<= 24;data |= clk->src;MIPI_OUTP_SECURE(ns, data);MIPI_OUTP_SECURE(cc, ((clk->mnd_mode << 6)      | (mnd_en << 5)      | (root_en << 2) | clk_en));}} elseMIPI_OUTP_SECURE(cc, 0);wmb();}

Lk:

//这是配置mdp clk的函数

[cpp]
  1. void configure_dsicore_dsiclk() 
  2.  
  3.  
  4. unsigned char mnd_mode, root_en, clk_en; 
  5.  
  6. unsigned long src_sel = 0x3; // dsi_phy_pll0_src 
  7.  
  8. unsigned long pre_div_func = 0x00; // predivide by 1 
  9.  
  10. unsigned long pmxo_sel; 
  11.  
  12.  
  13. secure_writel(pre_div_func << 14 | src_sel, DSI_NS_REG); 
  14.  
  15. mnd_mode = 0; // Bypass MND 
  16.  
  17. root_en = 1; 
  18.  
  19. clk_en = 1; 
  20.  
  21. pmxo_sel = 0; 
  22.  
  23.  
  24. secure_writel((pmxo_sel << 8) | (mnd_mode << 6), DSI_CC_REG); 
  25.  
  26. secure_writel(secure_readl(DSI_CC_REG) | root_en << 2, DSI_CC_REG); 
  27.  
  28. secure_writel(secure_readl(DSI_CC_REG) | clk_en, DSI_CC_REG); 
  29.  
  30.  
  31.  
  32.  
  33. <span style="font-family: SimSun; font-size: 14px;">问题三:遇见在lk里面显示内容闪烁很严重的问题,注意是内容查实不是配置屏幕的clk造成的,最后查出是porch没有调整好。</span> 
void configure_dsicore_dsiclk(){unsigned char mnd_mode, root_en, clk_en;unsigned long src_sel = 0x3; // dsi_phy_pll0_srcunsigned long pre_div_func = 0x00; // predivide by 1unsigned long pmxo_sel;secure_writel(pre_div_func << 14 | src_sel, DSI_NS_REG);mnd_mode = 0; // Bypass MNDroot_en = 1;clk_en = 1;pmxo_sel = 0;secure_writel((pmxo_sel << 8) | (mnd_mode << 6), DSI_CC_REG);secure_writel(secure_readl(DSI_CC_REG) | root_en << 2, DSI_CC_REG);secure_writel(secure_readl(DSI_CC_REG) | clk_en, DSI_CC_REG);}问题三:遇见在lk里面显示内容闪烁很严重的问题,注意是内容查实不是配置屏幕的clk造成的,最后查出是porch没有调整好。

三:panel唤醒流程

       我认为对于调试lcd,对lcd唤醒流程的认知是必须的,加深理解lcd工作原理,睡眠流程同理。首先resume对应suspend,对么我们就会想到msm_fb.c中对应的early_resume和early_suspend。下面是流程图。

      msmfb_early_resume  ->  msm_fb_resume_sub ->  msm_fb_blank_sub ->mdp_lcdc_on(76x27对应mdp_dma_lcdc.c,8x60对应在mdp4_overlay_lcdc.c) ->lcdc.c ->lcdc_toshiba_wxvga.c(自己对应的panel)

      在msm_fb_resume_sub中会调到msm_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,mfd->op_enable)这个就是打开lcd的操作了。msm_fb_blank_sub这个函数将panel与fb联系起来。这个函数起着桥梁作用,无论第一次亮屏还是唤醒和熄灭,msm_fb_blank_sub起着至关作用。

static int msm_fb_blank_sub(int blank_mode, struct fb_info *info,

    boolean op_enable)

{

struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;

struct msm_fb_panel_data *pdata = NULL;

int ret = 0;

if (!op_enable)

return -EPERM;

pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;

if ((!pdata) || (!pdata->on) || (!pdata->off)) {

printk(KERN_ERR "msm_fb_blank_sub: no panel operation detected!\n");

return -ENODEV;

}

switch (blank_mode) {

case FB_BLANK_UNBLANK://点亮lcd操作

if (!mfd->panel_power_on) {

msleep(16);

ret = pdata->on(mfd->pdev);

if (ret == 0) {

mfd->panel_power_on = TRUE;

/* ToDo: possible conflict with android which doesn't expect sw refresher */

/*

  if (!mfd->hw_refresh)

  {

    if ((ret = msm_fb_resume_sw_refresher(mfd)) != 0)

    {

      MSM_FB_INFO("msm_fb_blank_sub: msm_fb_resume_sw_refresher failed = %d!\n",ret);

    }

  }

*/

}

}

break;

case FB_BLANK_VSYNC_SUSPEND:

case FB_BLANK_HSYNC_SUSPEND:

case FB_BLANK_NORMAL:

case FB_BLANK_POWERDOWN://熄灭lcd操作

default:

if (mfd->panel_power_on) {

int curr_pwr_state;

mfd->op_enable = FALSE;

curr_pwr_state = mfd->panel_power_on;

mfd->panel_power_on = FALSE;

bl_updated = 0;

msleep(16);

ret = pdata->off(mfd->pdev);

if (ret)

mfd->panel_power_on = curr_pwr_state;

mfd->op_enable = TRUE;

}

break;

}

return ret;

}

Msm_fb只是初始化frame_buffer,而进入上面函数则关联mdp端和panel。

所以我们可以这样理解,frame_buffer操作好了,可以打开屏了?首先还要操作mdp,接着打开pixel clk,接着给panel上电和下序列。

Panel_on时出fb之后首先进入mdp_dma_lcdc.c中mdp_lcdc_on,接着依次调用其他的panel-on,(panel_next_on),最终还是在msm_fb中结束。

其实知道流程还是很重要的,比如调连续显示,lcd唤醒出现问题,我们就可以从头查。

转载地址:http://gwbsi.baihongyu.com/

你可能感兴趣的文章
程序员,应该掌握的英语词汇
查看>>
程序员的十大烦恼
查看>>
让工作变得高效而简单的10种方法
查看>>
关于C++中的虚拟继承的一些总结
查看>>
C++中的多态和虚函数
查看>>
关于InterLockedIncrement
查看>>
#ifdef _DEBUG
查看>>
C++中typeid
查看>>
读《C专家编程》有感
查看>>
智能指针CComPtr 和 CComQIPtr
查看>>
ASV2010
查看>>
AS3变量作用域问题
查看>>
#ifndef 在头文件中的作用
查看>>
FB安装技巧
查看>>
Lua4虚拟机运行概述
查看>>
C++中explicit关键字的作用
查看>>
AS3中Object与Dictionary的区别
查看>>
C++中的rand()函数
查看>>
SVN文件版本冲突解决方法
查看>>
map、hash_map、迭代器
查看>>