1. 程式人生 > >android lcd除錯 高通平臺lcd除錯深入分析總結(mipi和rgb介面)

android lcd除錯 高通平臺lcd除錯深入分析總結(mipi和rgb介面)

    各位網友:最近發現我這篇文章轉載的到處都是,有的則以原創存在,轉載時請註明出處,還有文中錯誤的地方請指正!謝謝合作。

     下面點lk方法適用於8660,8064。當然qrd則沒有那麼複雜。

一:點亮lcd in kernel

其實點亮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:仔細檢查上電同時測量,同時將28根rgb interface對應gpio設為lcdc func。對於傳統的lcd不需要RST操作只需拉高即可,對於mipi和需要下code的RGB panel需要RST高低高操作,這樣code才生效。注意一般sleep out(0x11)和display on(0x29)之間需要mdelay(100)左右,貌似這個對於大部分panel是必須的。

3:最後還要確認是否有framebuffer輸出,要是改動了display這塊的clk很有可能沒有buffer輸出的,可以通過cat /dev/graphyics/fb0檢視有沒有輸出字元。曾經除錯開機logo連續顯示時遇到過好幾次沒有buffer輸出導致kernel卡住,屏也不亮按power鍵沒有反映的情況。

4:如果以上操作正常同時序列正確,那麼螢幕應該可以點亮。對於遇到的有以下顯示問題:

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平臺許多上電我就是這樣做的,還有mipidsi相關設定clkREG

f:螢幕經常喚醒只顯示灰色底面,最後查明暫存器沒有使能外部升壓電路。

g:喚醒螢幕閃白光問題,說白了是背光早亮了,很有可能是下序列mdelay太久,改小點就沒有這個問題了。根本原因螢幕初始化序列下慢了。親身經歷的。

h:lcd喚醒閃屏問題,這個是由於每次重新RST下序列過程delay久了導致,適當減少delay時間即可。

i:用廠商給的序列要麼屏點不亮要麼介面有水波紋,這些通常都是rgb interface polarity導致,需要調整pclk hsync vsync de極性使之符合平臺極性。

j:結束開機logo至android動畫出現之間好多屏會出現閃屏或者閃白光的情況。原因:在這個時間點kernel會會對屏再次初始化,我們可以軟體上遮蔽第一次初始化動作從而解決。

k:點mipi video模式的lcd中遇見喚醒就只偶爾出現一幀,之後隱約看見刷的灰色介面但不能正常顯示。最後發現是high speed模式沒有設定正確,該屏只能使用burst模式,video還有其他2中模式,建議調屏時可以多嘗試一下;

l:屏有時可以喚醒有時則喚不醒,通常RST有問題,可以嘗試將RST動作移到下載序列之前。

m:最近在msm8974上遇見開機LOGO經常會消失又突然出現同時都是偶現的,最後查到是bitclk的太大導致的,由於LK預設lcd 重新整理率是60(改到50就不消失了),所以通過計算很容易導致LOGO的消失顯示不穩定的問題。記得使用裝置樹之前的平臺都是在lcd相關的檔案中可以直接定義的bitclk,現在修改bitclk很隱蔽,所以這個不太好查。

二:深入分析

高通平臺螢幕亮起來必須滿足一下條件

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裡面也寫了暫存器但是由於程式碼量太多,可能有時找起來不是很方便,下面等會貼出部分關鍵程式碼,再比較kernellk,需要強調的是驅動從本質上說都是些暫存器控制硬體,任何外界硬體都是一樣的實現。

    其實lk裡面點亮lcdkernel裡面一樣

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 720ppanel耗了不少時間,複雜度比kernel裡面難多了。

問題1:遇到不顯示的問題,查後發現配置的pll regkernel裡面重寫了,故需要在kernel裡面讀出來,再

填入lk裡面,其事用來配置bit clock通常mipi panel必須要300-500MCLK,而其實現高通平臺就是寫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 clkdsi pclk的暫存器的2個函式

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的函式

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);

}

//下面這兩個函式與mipi 螢幕顯示相關的,所以有關kernel裡面顯示正常但是在lk裡面顯示不正常,我們只用讀出暫存器對比即可。方可解決問題。

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);

}

問題三:遇見在lk裡面顯示內容閃爍很嚴重的問題,注意是內容查實不是配置螢幕的clk造成的,最後查出是porch沒有調整好。