android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口)
一:點(diǎn)亮lcd?in kernel
其實(shí)點(diǎn)亮lcd很簡(jiǎn)單必須保證以后幾個(gè)步驟正確:
1:確認(rèn)Lcd信息所在文件被編譯進(jìn)去,并且lcd?和board?name里面注冊(cè)一質(zhì),倘若這部正確,那么log里面應(yīng)該有對(duì)應(yīng)分辨率的一段framebuffer同時(shí)調(diào)到相對(duì)應(yīng)的power_on函數(shù)。對(duì)于lcdc?panel對(duì)應(yīng)文件在lcdc_xx.c,對(duì)于mipi?panel對(duì)應(yīng)文件在mipi_xx.c(下序列操作)和mipi_xxxx.c(timing?pll?clk等初始化操作)。
2:仔細(xì)檢查上電同時(shí)測(cè)量,同時(shí)將28根rgb interface對(duì)應(yīng)gpio設(shè)為lcdc?func。對(duì)于傳統(tǒng)的lcd不需要RST操作只需拉高即可,對(duì)于mipi和需要下code的RGB?panel需要RST高低高操作,這樣code才生效。注意一般sleep?out(0x11)和display?on(0x29)之間需要mdelay(100)左右,貌似這個(gè)對(duì)于大部分panel是必須的。
3:最后還要確認(rèn)是否有framebuffer輸出,要是改動(dòng)了display這塊的clk很有可能沒(méi)有buffer輸出的,可以通過(guò)cat /dev/graphyics/fb0查看有沒(méi)有輸出字符。曾經(jīng)調(diào)試開機(jī)logo連續(xù)顯示時(shí)遇到過(guò)好幾次沒(méi)有buffer輸出導(dǎo)致kernel卡住,屏也不亮按power鍵沒(méi)有反映的情況。
4:如果以上操作正常同時(shí)序列正確,那么屏幕應(yīng)該可以點(diǎn)亮。對(duì)于遇到的有以下顯示問(wèn)題:
a:屏幕呈花屏狀態(tài),說(shuō)明lcd初始化成功,但是沒(méi)有rgb刷過(guò)來(lái)。認(rèn)真檢查之后發(fā)現(xiàn)pclk時(shí)序不對(duì),由于是新的平臺(tái)所以設(shè)對(duì)以后,以后的屏就好辦了。
b:RGB pane內(nèi)容l閃爍通常由pclk設(shè)置不對(duì)導(dǎo)致還有可能與porch有關(guān)。通常wvga 16bit的panel使用24.5M的PCLK,qhd的24bit panel 30M PCLK。至于porch我們可以多替換幾組試試或者找FAE發(fā)個(gè)可以點(diǎn)亮的。一般屏對(duì)porch要求不高,幾乎都可以點(diǎn)亮的。
c:FPC沒(méi)有貼好也有可能導(dǎo)致屏幕不亮。
d:rest有問(wèn)題,一定仔細(xì)測(cè)量使用示波器看出波形,比如lk下面有時(shí)可能就沒(méi)有控制對(duì)。
e:許多kernel里面實(shí)現(xiàn)的但是在lk下面由于代碼比較少,就不好實(shí)現(xiàn),比如pm上電,vibrator等等,其實(shí)在kernel里面歸根也是寫對(duì)應(yīng)寄存器的,很簡(jiǎn)單,最好使的辦法就是在kernel里面讀出來(lái),在在lk里面寫進(jìn)去,這樣就好辦了。8x平臺(tái)許多上電我就是這樣做的,還有mipi的dsi相關(guān)設(shè)置clk的REG。
f:屏幕經(jīng)常喚醒只顯示灰色底面,最后查明寄存器沒(méi)有使能外部升壓電路。
g:喚醒屏幕閃白光問(wèn)題,說(shuō)白了是背光早亮了,很有可能是下序列mdelay太久,改小點(diǎn)就沒(méi)有這個(gè)問(wèn)題了。根本原因屏幕初始化序列下慢了。親身經(jīng)歷的。
h:lcd喚醒閃屏問(wèn)題,這個(gè)是由于每次重新RST下序列過(guò)程delay久了導(dǎo)致,適當(dāng)減少delay時(shí)間即可。
i:用廠商給的序列要么屏點(diǎn)不亮要么界面有水波紋,這些通常都是rgb interface polarity導(dǎo)致,需要調(diào)整pclk hsync vsync de極性使之符合平臺(tái)極性。
j:結(jié)束開機(jī)logo至android動(dòng)畫出現(xiàn)之間好多屏?xí)霈F(xiàn)閃屏或者閃白光的情況。原因:在這個(gè)時(shí)間點(diǎn)kernel會(huì)會(huì)對(duì)屏再次初始化,我們可以軟件上屏蔽第一次初始化動(dòng)作從而解決。
?
?
二:深入分析
高通平臺(tái)屏幕亮起來(lái)必須滿足一下條件
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.
?
?
三:點(diǎn)亮lcd?in?bootloader
??????由于開機(jī)logo的需要,故需要在bootloader?lk里面將lcd給驅(qū)動(dòng)起來(lái),這樣才可以顯示開機(jī)logo。由于lk下面的代碼沒(méi)有kernel里面豐富。故lk寫了很精致的代碼主要還是寫寄存器從而控制硬件,其實(shí)在kernel里面也寫了寄存器但是由于代碼量太多,可能有時(shí)找起來(lái)不是很方便,下面等會(huì)貼出部分關(guān)鍵代碼,再比較kernel和lk,需要強(qiáng)調(diào)的是驅(qū)動(dòng)從本質(zhì)上說(shuō)都是些寄存器控制硬件,任何外界硬件都是一樣的實(shí)現(xiàn)。
????其實(shí)lk里面點(diǎn)亮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里面點(diǎn)亮起來(lái)可能更加難度大點(diǎn),lk里面調(diào)試需要串口線相比而言復(fù)雜點(diǎn)。
最近在lk里面點(diǎn)亮一款mipi?4lane?video?mode?720p的panel耗了不少時(shí)間,復(fù)雜度比kernel里面難多了。
問(wèn)題1:遇到不顯示的問(wèn)題,查后發(fā)現(xiàn)配置的pll?reg在kernel里面重寫了,故需要在kernel里面讀出來(lái),再
填入lk里面,其事用來(lái)配置bit?clock通常mipi?panel必須要300-500M的CLK,而其實(shí)現(xiàn)高通平臺(tái)就是寫pll?reg的。注意clk或大或小不會(huì)影響顯示的,可能不匹配會(huì)造成屏幕閃爍,與其刷新率沒(méi)有對(duì)上。
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,計(jì)算方法高通有個(gè)自動(dòng)計(jì)算工具
{0x00,?0xec,?0x31,?0xd2,?0x00,?0x40,?0x37,?0x62,
0x01,?0x0f,?0x07,
0x05,?0x14,?0x03,?0x0,?0x0,?0x0,?0x20,?0x0,?0x02,?0x0},
};
8x60有個(gè)重配的函數(shù)
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里面讀出,再填入數(shù)組即可。其實(shí)許多操作都可以從kernel里面讀出,在lk里面寫入,比如給一系列的pm某個(gè)管腳上電,enable?vibrate?in?lk等等,就是在kernel里面讀出操作其寄存器的值,再在lk里面寫入!用到的非常平凡,下面還有。
在lk里面mipi的瓶只要上電正常,RESET正常,這些必要手動(dòng)測(cè)出的這是第一步,之后下載序列,屏幕有花屏,就說(shuō)明可以下進(jìn)去的,屏幕有反應(yīng)。
問(wèn)題二:有遇見(jiàn)在lk下面mipi?的屏顯示不對(duì)的問(wèn)題還有彩色不對(duì),顯示不對(duì)是dsi某個(gè)寄存器的值和kernel里面不一樣,由于是video?mode至于色彩是rgb或者bgr等打包方式不對(duì),換下就好了。
在msm_dss_io_8x60.c中有寫dis?clk和dsi?pclk的寄存器的2個(gè)函數(shù)
Kernel:
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));
}
}?else
MIPI_OUTP_SECURE(cc,?0);
wmb();
}
static?void?mipi_dsi_clk_ctrl(struct?dsi_clk_desc?*clk,?int?clk_en)
{
char *cc,?*ns,?*md;
int pmxo_sel?=?0;
char mnd_en?=?1,?root_en?=?1;
uint32 data,?val;
cc?=?mmss_cc_base?+?0x004c;
md?=?mmss_cc_base?+?0x0050;
ns?=?mmss_cc_base?+?0x0054;
if?(clk_en)?{
if?(clk->mnd_mode?==?0)?{
data??=?clk->pre_div_func?<<?14;
data?|=?clk->src;
MIPI_OUTP_SECURE(ns,?data);
MIPI_OUTP_SECURE(cc,?((pmxo_sel?<<?8)
|?(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,?((pmxo_sel?<<?8)
??????|?(clk->mnd_mode?<<?6)
??????|?(mnd_en?<<?5)
??????|?(root_en?<<?2)?|?clk_en));
}
}?else
MIPI_OUTP_SECURE(cc,?0);
wmb();
}
Lk:
//這是配置mdp?clk的函數(shù)
void?mdp_clock_init(void)
{
/*?Turn?on?the?PLL2,?to?ramp?up?the?MDP?clock?to?max?(200MHz)?*/
nt_pll_enable(PLL_2,?1);
config_mdp_clk(MDP_NS_VAL,?MDP_MD_VAL,
???????MDP_CC_VAL,?MDP_NS_REG,?MDP_MD_REG,?MDP_CC_REG);
}
//下面這兩個(gè)函數(shù)與mipi?屏幕顯示相關(guān)的,所以有關(guān)kernel里面顯示正常但是在lk里面顯示不正常,我們只用讀出寄存器對(duì)比即可。方可解決問(wèn)題。
void?configure_dsicore_dsiclk()
{
unsigned?char?mnd_mode,?root_en,?clk_en;
unsigned?long?src_sel?=?0x3; //?dsi_phy_pll0_src
unsigned?long?pre_div_func?=?0x00; //?predivide?by?1
unsigned?long?pmxo_sel;
secure_writel(pre_div_func?<<?14?|?src_sel,?DSI_NS_REG);
mnd_mode?=?0; //?Bypass?MND
root_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);
}
void?configure_dsicore_pclk(void)
{
unsigned?char?mnd_mode,?root_en,?clk_en;
unsigned?long?src_sel?=?0x3; //?dsi_phy_pll0_src
unsigned?long?pre_div_func?=?0x01; //?predivide?by?2
secure_writel(pre_div_func?<<?12?|?src_sel,?PIXEL_NS_REG);
mnd_mode?=?0; //?Bypass?MND
root_en?=?1;
clk_en?=?1;
secure_writel(mnd_mode?<<?6,?PIXEL_CC_REG);
secure_writel(secure_readl(PIXEL_CC_REG)?|?root_en?<<?2,?PIXEL_CC_REG);
secure_writel(secure_readl(PIXEL_CC_REG)?|?clk_en,?PIXEL_CC_REG);
}
問(wèn)題三:遇見(jiàn)在lk里面顯示內(nèi)容閃爍很嚴(yán)重的問(wèn)題,注意是內(nèi)容查實(shí)不是配置屏幕的clk造成的,最后查出是porch沒(méi)有調(diào)整好。
?
?
三:panel喚醒流程
???????我認(rèn)為對(duì)于調(diào)試lcd,對(duì)lcd喚醒流程的認(rèn)知是必須的,加深理解lcd工作原理,睡眠流程同理。首先resume對(duì)應(yīng)suspend,對(duì)么我們就會(huì)想到msm_fb.c中對(duì)應(yīng)的early_resume和early_suspend。下面是流程圖。
??????msmfb_early_resume??->??msm_fb_resume_sub?->??msm_fb_blank_sub?->mdp_lcdc_on(76x27對(duì)應(yīng)mdp_dma_lcdc.c,8x60對(duì)應(yīng)在mdp4_overlay_lcdc.c)?->lcdc.c?->lcdc_toshiba_wxvga.c(自己對(duì)應(yīng)的panel)
??????在msm_fb_resume_sub中會(huì)調(diào)到msm_fb_blank_sub(FB_BLANK_UNBLANK,?mfd->fbi,mfd->op_enable)這個(gè)就是打開lcd的操作了。msm_fb_blank_sub這個(gè)函數(shù)將panel與fb聯(lián)系起來(lái)。這個(gè)函數(shù)起著橋梁作用,無(wú)論第一次亮屏還是喚醒和熄滅,msm_fb_blank_sub起著至關(guān)作用。
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://點(diǎn)亮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,而進(jìn)入上面函數(shù)則關(guān)聯(lián)mdp端和panel。
所以我們可以這樣理解,frame_buffer操作好了,可以打開屏了?首先還要操作mdp,接著打開pixel?clk,接著給panel上電和下序列。
?Panel_on時(shí)出fb之后首先進(jìn)入mdp_dma_lcdc.c中mdp_lcdc_on,接著依次調(diào)用其他的panel-on,(panel_next_on),最終還是在msm_fb中結(jié)束。
其實(shí)知道流程還是很重要的,比如調(diào)連續(xù)顯示,lcd喚醒出現(xiàn)問(wèn)題,我們就可以從頭查。
?
四:開機(jī)Logo連續(xù)顯示 待寫!后續(xù)補(bǔ)充。總結(jié)
以上是生活随笔為你收集整理的android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android4.1 触摸屏(TP)划线
- 下一篇: USB数据线内阻对充电电流的影响