天天看點

[Android5.1][RK3288] LCD Mipi 初始化長包資料規範問題

    • 先說問題和結論
      • 環境
      • 問題
      • 真相
    • 正文

先說問題和結論

環境

正在 RK3288 調試 Mipi LCD(540×960)

問題

首先是因為我出現了這樣的 Bug:

[Android5.1][RK3288] LCD Mipi 初始化長包資料規範問題

我的 cmds7 明明填充的是 LP 模式,但是列印中卻說是 HS 模式。

我在一個文章中看到說 cmds 參數 不能為 8 和 16 的情況。

于是錯誤地将地将兩者聯系起來,認為參數為 8 或者 16 的情況下,LP 模式會被轉換成 HS 模式。

于是希望跟着代碼一探究竟。

真相

但是實際上兩者是沒有關聯的。

真相是

其實是可以傳遞 8 位元組 和 16 位元組的參數的。

跟蹤代碼發現列印 LP mode 和 HS mode 這個輸出資訊的代碼是根據 reg[0] 來判斷的

MIPI_DBG("%d command sent in %s size:%d\n", __LINE_, regs[] ? "LP mode" : "HS mode", liTmp);
           

我出現這種情況的原因,是因為擅自錯誤地将一個 36 位元組的參數 拆分成 28 和 8 。

而後面 8 位元組 cmds 的首位元組 為 0x00。

也就是 reg[0] = 0x00 ,是以會輸出 HS mode。

正文

假設我們有 8 個參數,那麼 cmds 實際為 { 0x39,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88 }

cmd_len = length / sizeof(u32) = 9

在 video/rockchip/screen/lcd_mipi.c 中的 rk_mipi_screen_cmd_init 可以看到是調用

dsi_send_packet 這個函數來進行參數傳遞

//...
        dcs_cmd = list_entry(screen_pos, struct mipi_dcs_cmd_ctr_list, list);
        len = dcs_cmd->dcs_cmd.cmd_len + ; // len = 9 + 1 = 10
        for (i = ; i < len ; i++) {  // 将 dcs_cmd->dcs_cmd.cmds 中的 9 個參數指派給 cmds
            cmds[i] = dcs_cmd->dcs_cmd.cmds[i-]; //cmds[1-9] 被 dcs_cmd.cmds[0-8] 指派
        }
        MIPI_SCREEN_DBG("dcs_cmd.name:%s\n", dcs_cmd->dcs_cmd.name);
        if (dcs_cmd->dcs_cmd.type == LPDT) {
            cmds[] = LPDT; //cmds[0] 表示傳輸資料模式的标志 1
            if (dcs_cmd->dcs_cmd.dsi_id == ) {
                MIPI_SCREEN_DBG("dcs_cmd.dsi_id == 0 line=%d\n", __LINE__);
                //調用這個函數進行 mipi 通信 
                //這裡的 cmds 中實際有 10 個位元組
                // 0 為 資料類型的标志 1
                // 1-9 為參數 cmds[1] = 0x39 資料類型為長包資料 cmds[2-9] 為螢幕初始化參數
                // len 為 10
                dsi_send_packet(, cmds, len); 
            } 
//...
           

跟代碼發現在 video/rockchip/transmitter/mipi_dsi.c 中

int dsi_send_dcs_packet(unsigned int id, unsigned char *packet, u32 n) {

    struct mipi_dsi_ops *ops = NULL;
    //printk("dsi_send_dcs_packet-------id=%d\n",id);
    if(id > (MAX_DSI_CHIPS - ))
        return -EINVAL;
    ops = dsi_ops[id];
    if(!ops)
        return -EINVAL;
    if(ops->dsi_send_dcs_packet)
        ops->dsi_send_dcs_packet(ops->dsi, packet, n);
    return ;
}
#ifdef CONFIG_MIPI_DSI
EXPORT_SYMBOL(dsi_send_dcs_packet);
           

ops->dsi_send_dcs_packet 這個實作是在 ops->的 dsi_send_dcs_packet

究其根源的實作是在

kernel/drivers/video/rockchip/transmitter/rk32_mipi_dsi.c

的 rk32_mipi_dsi_send_packet

//arg 是要傳輸的通道,預設為 0 
//cmds 就是 lcd dtsi 中的 cmds // 這裡假設為{ 0x39,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88 }
//length 就是 cmds 的長度 // 這裡為 10
static int rk32_mipi_dsi_send_packet(void *arg, unsigned char cmds[], u32 length)
{
    struct dsi *dsi = arg;
    unsigned char *regs;
    u32 type, liTmp = , i = , j = , data = ;

    if (rk32_dsi_get_bits(dsi, gen_cmd_full) == ) {
        MIPI_TRACE("gen_cmd_full\n");
        return -;
    }
    regs = kmalloc(, GFP_KERNEL);  
    if (!regs) {
        printk("request regs fail!\n");
        return -ENOMEM;
    }
    memcpy(regs, cmds, length); //regs 現在為 cmds 中的内容了

    liTmp = length - ;     //liTmp = 10 - 2 = 8
    type = regs[];         //type = regs[1] = cmds[1] = 0x39 (采用長包模式傳輸)
    switch (type) { //0x39 即 DTYPE_DCS_LWRITE
        //... 
    case DTYPE_DCS_LWRITE:
        rk32_dsi_set_bits(dsi, regs[], dcs_lw_tx); // 設定标志位,根據 regs[0] 設定寄存器 dcs_lw_tx 中的标志
        for (i = ; i < liTmp; i++) { 
            // 0-7 依次給 regs[0]-regs[7] 指派,這8個值便是螢幕初始化的内容
            // {0x11,0x22,0x33,0x44,0x55.0x66,0x77,0x88}
            regs[i] = regs[i+];
        }
        for (i = ; i < liTmp; i++) {
            j = i % ; //0 1 2 3 0 1 2 3
            data |= regs[i] << (j * ); 
            //data | (regs[0] << 0)
            //data | (regs[1] << 8)
            //data |  (regs[2] << 16)
            //data | (regs[3] << 24)
            // 8 個位元組的内容被組合成兩個 data
            // 0x44332211 0x88776655
            if (j ==  || ((i + ) == liTmp)) { //每當組成的 data 滿了的時候,或者是所有的參數都填充了的時候
                if (rk32_dsi_get_bits(dsi, gen_pld_w_full) == ) {
                    MIPI_TRACE("gen_pld_w_full :%d\n", i);
                    break;
                }
                rk32_dsi_set_bits(dsi, data, GEN_PLD_DATA);
                MIPI_DBG("write GEN_PLD_DATA:%d, %08x\n", i, data);
                data = ; //清空 data,開始下個 data 的傳輸
            }
        }
        data = type;//data = 0x39
        data |= (liTmp & ) << ;  //0x0839 //如果是 16 位元組的話為 0x1039(16 的16進制是 0x10)
        break;
        //...
        }

    MIPI_DBG("%d command sent in %s size:%d\n", __LINE__, regs[] ? "LP mode" : "HS mode", liTmp);
    //這裡就會列印究竟是什麼模式來傳輸
    //reg[0] 正是代表了 螢幕參數初始化的第一個位元組!
    //它的含義是這塊屏 IC 的 CMD!
    //0x11 0x22 0x33 0x44... 0x88 表示執行 0x11 這個 CMD,參數為 0x22 到 0x88
    //那為什麼  8 個位元組就會變成 HS mode 呢,
    //看我所傳輸的 cmds7 可以發現要傳輸的第一個參數為 0x00,是以被判别為 HS mode

    MIPI_DBG("write GEN_HDR:%08x\n", data);
    rk32_dsi_set_bits(dsi, data, GEN_HDR);

    i = ;
    while (!rk32_dsi_get_bits(dsi, gen_cmd_empty) && i--) {
        MIPI_DBG(".");
        udelay();
    }
    udelay();
    kfree(regs);
    return ;
}
           
[Android5.1][RK3288] LCD Mipi 初始化長包資料規範問題

至此,疑問解決了。

看 LCD 的 datasheet 也可以發現,像之前所說的,

在 commond mode 的時候,這個參數,

也就是 屏IC 的 CMD,是不會為 0x00 的。

隻有在 video mode 下才可能為 0x00。

而參數為 8 位元組 和 16 位元組 其實都可以,隻要不超過 struct dsc_cmd 中定義的大小 400 ,就夠了。

本文位址:http://blog.csdn.net/dearsq/article/details/52369879

歡迎轉載,轉載請著名出處和作者 Younix~謝謝~

繼續閱讀