-
- 先說問題和結論
- 環境
- 問題
- 真相
- 正文
- 先說問題和結論
先說問題和結論
環境
正在 RK3288 調試 Mipi LCD(540×960)
問題
首先是因為我出現了這樣的 Bug:
我的 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 ;
}
至此,疑問解決了。
看 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~謝謝~