MTK LCM驅動分析


參考:

http://blog.csdn.net/sunweizhong1024/article/details/8447915

http://blog.csdn.net/cbk861110/article/details/40931835
 

一.驅動分析5.1
Mtkfb.c (kernel-3.10\drivers\misc\mediatek\videox\mt6735)
 
1.初始化
mtkfb_init
    platform_driver_register(&mtkfb_driver)
 
 
2.重要結構體
static struct fb_ops mtkfb_ops = {
    .owner          = THIS_MODULE,
    .fb_open        = mtkfb_open,
    .fb_release     = mtkfb_release,
    .fb_setcolreg   = mtkfb_setcolreg,
    .fb_pan_display = mtkfb_pan_display_proxy,
    .fb_fillrect    = cfb_fillrect,
    .fb_copyarea    = cfb_copyarea,
    .fb_imageblit   = cfb_imageblit,
    .fb_cursor      = mtkfb_soft_cursor,
    .fb_check_var   = mtkfb_check_var,
    .fb_set_par     = mtkfb_set_par,
    .fb_ioctl       = mtkfb_ioctl,
#ifdef CONFIG_COMPAT
.fb_compat_ioctl = mtkfb_compat_ioctl,
#endif    
#ifdef CONFIG_DMA_SHARED_BUFFER
    .fb_dmabuf_export = mtkfb_dmabuf_export,
#endif
};


probe
    strstr(saved_command_line, "fps=");    //得到UBOOT傳過來的參數
    fbi = framebuffer_alloc(sizeof(struct mtkfb_device), dev);  //分配fb_info結構體
       mtkfb_find_lcm_driver :hj101na02a_lcm_drv
            disp_drv_get_lcm_driver
                lcm->set_util_funcs(&lcm_utils); //設置LCD操作函數
                lcm->get_params(lcm_params); //得到LCD的一些硬件參數
                disp_drv_init_ctrl_if  //如果是DBI(mcu 屏)
                    //LCM_CTRL_SERIAL_DBI
                    LCD_Init()
                    LCD_ConfigSerialIF
                    //LCM_CTRL_PARALLEL_DBI
                    LCD_Init()
                    LCD_ConfigParallelIF
                LCD_SelectWriteIF //選擇是串口還是並口
                LCD_ConfigIfFormat //配置接口的數據類型
                to_lcd_if_width //數據寬度,DBI
                disp_drv_set_driving_current //設置接口的電流
                LCD_Init_IO_pad //初始化GPIO
            disp_drv_init_context
                DISP_GetDriverDBI :DBI_DISP_DRV 操作函數
                DISP_GetDriverDPI :DPI_DISP_DRV
                DISP_GetDriverDSI :DSI_DISP_DRV
    //得到LCD的一些參數
    DISP_GetScreenWidth
     。。。。。。
    kthread_create(esd_recovery_kthread, NULL, "esd_recovery_kthread"); //esd檢測     




得到指點屏幕的信息:
 mtkfb_probe
    primary_display_init(mtkfb_find_lcm_driver(), lcd_fps);
        pgc->plcm = disp_lcm_probe( lcm_name, LCM_INTERFACE_NOTDEFINED);
             lcm_drv = lcm_driver_list[0];或者lcm_drv = lcm_driver_list[i];




二.驅動分析6.0(6735)
Mtkfb.c (kernel-3.18\drivers\misc\mediatek\video\common)
 mtkfb_probe
    p = strstr(saved_command_line, "fps="); //獲得命令行參數
    fbi = framebuffer_alloc(sizeof(struct mtkfb_device), dev); //分配  mtkfb_device,creates a new frame buffer info structure
    struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //得到資源,get a resource for a device,這里是IO口資源
    
disp_hal_allocate_framebuffer(res->start, res->end, 
(unsigned int *)&fbdev->fb_va_base, &fb_pa); //
(物理地址映射為虛擬地址),也就是io物理地址映射成虛擬地址
          *va = (unsigned long)ioremap_nocache(pa_start, pa_end - pa_start + 1);
     primary_display_set_frame_buffer_address((unsigned long)fbdev->fb_va_base, fb_pa); //設置frame的虛擬地址
          pgc->framebuffer_va = va;
pgc->framebuffer_mva = mva;
    primary_display_init(mtkfb_find_lcm_driver(), lcd_fps); //早期顯示設備初始化,第一個參數是LCM名字 ,
mtkfb_find_lcm_driver單獨分析1
          dprec_init
 
               dprec_logger_event_init(&dprec_vsync_irq_event, "VSYNC_IRQ", DPREC_LOGGER_LEVEL_SYSTRACE, NULL);
          dpmgr_init //顯示設備管理初始化,
               ddp_debug_init //
Ddp_debug.c (kernel-3.18\drivers\misc\mediatek\video\mt6735\dispsys),初始化調試接口
                    debugfs = debugfs_create_file("dispsys", S_IFREG | S_IRUGO, NULL, (void *)0, &debug_fops);
 
                    debugDir = debugfs_create_dir("disp", NULL);
                    debugfs_dump = debugfs_create_file("dump", S_IFREG | S_IRUGO, debugDir, NULL, &debug_fops_dump);
               disp_init_irq //顯示設備中斷初始化
                    init_waitqueue_head(&disp_irq_log_wq);
                    disp_irq_log_task = kthread_create(disp_irq_log_kthread_func, NULL, "ddp_irq_log_kthread"); //單獨分析2
                    wake_up_process(disp_irq_log_task);
               disp_register_irq_callback(dpmgr_irq_handler); //注冊顯示中斷處理函數,中斷處理函數單獨分析3
                    irq_callback_table[i] = cb;  //中斷函數賦值
          pgc->plcm = disp_lcm_probe(lcm_name, LCM_INTERFACE_NOTDEFINED); //lcm probe,做一些初始化,單獨分析4
          lcm_param = disp_lcm_get_params(pgc->plcm); //調用具體屏驅動的lcm_get_params,得到屏的參數
               lcm_get_params 
         mtk cmdq的一些設置。。。。。。。
          dpmgr_path_set_video_mode(pgc->dpmgr_handle, primary_display_is_video_mode()); //設置LCM的模式, primary_display_is_video_mode
單獨分析5
               handle = (ddp_path_handle) dp_handle;
    handle->mode = is_vdo_mode ? DDP_VIDEO_MODE : DDP_CMD_MODE;
        /* use fake timer to generate vsync signal for cmd mode w/
        if (!primary_display_is_video_mode()) { //如果不是VDO模式,需要設置同步信號
    _init_vsync_fake_monitor(lcm_fps);
        data_config = dpmgr_path_get_last_config(pgc->dpmgr_handle); //獲得data_config 
        data_config->dst_w = lcm_param->width;
data_config->dst_h = lcm_param->height;
        data_config->lcm_bpp = 24; //設置BPP
        ret = disp_lcm_init(pgc->plcm, 0);//初始化LCM,調用具體屏的lcm_init
            lcm_drv->init();
                    lcm_init
          primary_display_esd_check_task = kthread_create(primary_display_esd_check_worker_kthread,  NULL, "display_esd_check"); //靜電處理線程,單獨分析6
          if (_need_register_eint()) //如果需要TE中斷
               (request_irq(irq, _esd_check_ext_te_irq_handler, IRQF_TRIGGER_NONE, "DSI_TE_1-eint", NULL)) //注冊中斷
          if (_need_do_esd_check()) //需要使能靜電保護
primary_display_esd_check_enable(1); //使能
        primary_path_aal_task = kthread_create(_disp_primary_path_check_trigger, NULL, "display_check_aal"); //aal檢測線程,_disp_primary_path_check_trigger單獨分析7
        present_fence_release_worker_task = kthread_create(_present_fence_release_worker_thread, NULL, "present_fence_worker");  //見Android4.4 fence機制分析章,控制每個buffer的“生命周期”
    disp_register_module_irq_callback(DISP_MODULE_RDMA0, primary_display_frame_update_irq_callback);
            if (module == DISP_MODULE_RDMA0)
                update_frm_seq_info(ddp_ovl_get_cur_addr(1, 0), 0, 1, FRM_START); //更新顯存隊列信息
disp_register_module_irq_callback(DISP_MODULE_OVL0, primary_display_frame_update_irq_callback);
            if ((module == DISP_MODULE_OVL0) && (_is_decouple_mode(pgc->session_mode) == 0)) {
                wake_up_interruptible(&primary_display_frame_update_wq); //喚醒隊列primary_display_frame_update_kthread,后面分析           
disp_register_module_irq_callback(DISP_MODULE_WDMA0, primary_display_frame_update_irq_callback);
            if ((module == DISP_MODULE_WDMA0) && (_is_decouple_mode(pgc->session_mode) == 1)) 
                wake_up_interruptible(&decouple_fence_release_wq); //喚醒decouple_fence_release_wq隊列,Android4.4 fence機制分析章,控制每個buffer的“生命周期”
primary_display_frame_update_task = kthread_create(primary_display_frame_update_kthread, NULL,  "frame_update_worker");  primary_display_frame_update_kthread單獨分析8
        decouple_fence_release_task = kthread_create(decouple_fence_release_kthread, NULL,) //Android4.4 fence機制分析章,控制每個buffer的“生命周期”
 mtkfb_fbinfo_init //Initialize system fb_info object and set the default video mode.
    r = fb_alloc_cmap(&info->cmap, 32, 0);
    r = mtkfb_check_var(&var, info);
    r = mtkfb_set_par(info);
  register_framebuffer(fbi);
 
    
         
         
    
mtkfb_find_lcm_driver單獨分析1,獲取LCM名字
    /* mtkfb should parse lcm name from kernel boot command line */
    p = strstr(saved_command_line, "lcm="); //獲得LCM的名字,從uboot傳過來的參數
    strncpy((char *)mtkfb_lcm_name, (const char *)p, (int)(q - p)); //設置lcm名字
 
 
disp_irq_log_kthread_func 
單獨分析2

    Overlay是Android經常看到的名字,我們可以理解為視頻疊加,Overlay也可以理解為視頻輸出
 
    primary_display_reset_ovl_by_cmdq(disp_irq_log_module & 0x1); //重啟Overlay
    ddp_dump_reg(i); //打印Overlay寄存器的值
    
 
 
dpmgr_irq_handler 單獨分析3
    irq_bits_num = ddp_get_module_max_irq_bit(module); //得到中斷寄存器相應中斷
    handle = (ddp_path_handle)hw_mutex_id_to_handle_map[i]; //得到相應中斷處理函數
    dprec_stub_irq(irq_bit);
        dprec_stub_event(j);
        wake_up_interruptible(&(handle->wq_list[j].wq));  //喚醒處理等待隊列
 
 
disp_lcm_probe 單獨分析4
disp_lcm_probe
    lcm_drv = lcm_driver_list[i]; //得到LCM driver
    plcm = kzalloc(sizeof(uint8_t *) * sizeof(disp_lcm_handle), GFP_KERNEL);  //分配disp_lcm_handle
    lcm_param = kzalloc(sizeof(uint8_t *) * sizeof(LCM_PARAMS), GFP_KERNEL); //分配LCM_PARAMS
    if (plcm && lcm_param) { //設置
plcm->params = lcm_param;
plcm->drv = lcm_drv;
plcm->is_inited = isLCMInited;
plcm->index = lcmindex;
    plcm->drv->get_params(plcm->params); //這里調用具體屏驅動中的lcm_get_params
    if (plcm->params->type == LCM_TYPE_DSI && plcm->params->lcm_if == LCM_INTERFACE_NOTDEFINED)
plcm->lcm_if_id = LCM_INTERFACE_DSI0; //獲得LCM傳輸總線類型
 
 
primary_display_is_video_mode
單獨分析5
    disp_lcm_is_video_mode  //判讀是否是VDO模式
 
        if (lcm_param->type == LCM_TYPE_DSI) {
    switch (lcm_param->dsi.mode)
                case SYNC_PULSE_VDO_MODE:
case SYNC_EVENT_VDO_MODE:
case BURST_VDO_MODE:
return true;
 
 
primary_display_esd_check_worker_kthread靜電處理線程,單獨分析6
    
sched_setscheduler(current, SCHED_RR, &param);
     //設置調度為實時調度
    dpmgr_enable_event(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_DONE);
    dpmgr_enable_event(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_START);
    ret = primary_display_esd_check();
     while (1) {
        msleep(2000);/* esd check every 2s */ 兩秒就會檢測一次
        ret = wait_event_interruptible(esd_check_task_wq, atomic_read(&esd_check_task_wakeup));
        兩種檢測模式
        1./* / Esd Check : EXT TE */ 配置dsi.customization_esd_check_enable == 0
        2./* / Esd Check : Read from lcm */ 配置dsi.customization_esd_check_enable == 1
        /* 0.create esd check cmdq */
        cmdqRecCreate(CMDQ_SCENARIO_DISP_ESD_CHECK, &(pgc->cmdq_handle_config_esd));
        dpmgr_path_build_cmdq(pgc->dpmgr_handle, pgc->cmdq_handle_config_esd, CMDQ_ESD_ALLC_SLOT);
MMProfileLogEx(ddp_mmp_get_events()->esd_rdlcm, MMProfileFlagPulse, 0, 2);
        /* 1.use cmdq to read from lcm */
if (primary_display_is_video_mode())
    ret = _esd_check_config_handle_vdo();
         /* 2.check data(*cpu check now) */
        ret = dpmgr_path_build_cmdq(pgc->dpmgr_handle, pgc->cmdq_handle_config_esd, CMDQ_ESD_CHECK_CMP);
MMProfileLogEx(ddp_mmp_get_events()->esd_rdlcm, MMProfileFlagPulse, 0, 4);
        /* 3.destroy esd config thread */
cmdqRecDestroy(pgc->cmdq_handle_config_esd);
}
if (ret == 1) { //如果發現LCM被打死,需要重啟
    primary_display_esd_recovery();
                DISPCHECK("[POWER]lcm suspend[begin]\n");
        disp_lcm_suspend(pgc->plcm); //調用具體屏的lcm_suspend函數
        DISPCHECK("[POWER]lcm suspend[end]\n");      
                disp_lcm_init(pgc->plcm, 1); //吊具體屏幕的init函數
                ...........一些CMMQ命令........
            ret = primary_display_esd_check(); //再次檢測,如果失敗5次就定制重啟
 
   
 _disp_primary_path_check_trigger單獨分析7
    while (1) {
        if (gResetOVLInAALTrigger == 1) {  //操作OVL
ovl_reset_by_cmdq(handle, DISP_MODULE_OVL0);
if (ovl_get_status() != DDP_OVL1_STATUS_SUB)
ovl_reset_by_cmdq(handle, DISP_MODULE_OVL1);
}
        _cmdq_set_config_handle_dirty_mira(handle);  //設置
        _cmdq_flush_config_handle_mira(handle, 0);
 
 
primary_display_frame_update_kthread單獨分析8
    update_frm_seq_info(0, 0, 0, FRM_END); //更新
        dprec_logger_frame_seq_end(pgc->session_id, frm_update_sequence[i].seq);
MMProfileLogEx(ddp_mmp_get_events()->primary_seq_release, MMProfileFlagPulse, frm_update_sequence[i].mva, frm_update_sequence[i].seq);
 
 

三、Display

1.lcm 相關概念

1.1) MIPI接口:

    一共有三種接口:DBI(也做CPU或MCU接口)、DPI(也叫RGB接口)、DSI.

    在使用DSI接口時,目前75/77都只支持到2條data lane,加上一條clock lane.

    使用DPI接口時,根據LCM IC支持的情況,可以選擇16bus、18bus傳輸RGB格式文件,在GPIO部分分為R、G、B分別對應 8個GPIO(GPIO20~46期間),客戶采用DPI接口需要根據選擇的bus方式進行配置,推薦RGB端口全部配置為對應的復選模 式,並設置為OUT輸出。

    采用DBI接口,有兩種模式選擇,一種是選擇共用DPI的bus腳 +DPI控制線,另一種是共用nand data pin+CPU 控制線。

 

1.2) DSI接口有兩種sync 模式:

    video mode和command mode,其中video mode是BB端一直刷數據到LCM,cmd mode是在有數 據更新時刷數據到LCM GRAM中) 和DSI command mode相比,video mode 是需要實時傳輸image data到lcm端,DSI 的refresh rate決定了lcm的refresh rate。

 

1.3)EDS機制:

    92平台LCM driver中定義了esd_check和esd_recovery的接口,但ESD線程不工作。

    目前在MT6589之前平台,video mode的ESD實現有三種模式,分別是:ext TE(外部TE信號檢測)、int TE(內部TE信號檢 測)、non cout clk不同ESD方式需要注意的方面

    a) int TE和ext TE的檢測,都不需要實現lcm_esd_check函數,而需要實現lcm_esd_recover函數。

        non cont clk則不需要實現lcm_esd_check函數和lcm_esd_recover函數,而只需要在上面 params中配置為TRUE即可

    b) ext TE的實現,需要LCM外接TE pin到BB端,同時在inital code中配置寄存器打開TE信號的輸出 (一般是寫0x35寄存器,具體需要和LCM IC FAE確認)

 

1.4)HDMI/MHL:

    目前我司HDMI/MHL的相關code和driver都是有集成在codebase中的,要使用的話,只需要只需要在對應的 ProjectConfig.mk文件中開啟,並且在dct中配置好對應的引腳定義即可。

以下以MHL為例:

    ProjectConfig中配置:

    MTK_HDMI_SUPPORT=yes #表明開啟HDMI/MHL功能

    CUSTOM_KERNEL_HDMI=Sii8338 #表明配置為MHL的IC型號

 

1.5)TE 信號:

    大部分TE問題是由於沒有正常開啟TE所導致,首先檢查TE是否開啟。

    89平台使用內部TE,lcm driver中只需要在init過程中打開LCM TE即可,一般是寫0x35寄存器,部分IC需要額外寫其他 寄存器,可與FAE確認。

    檢查TE是否正常開啟,如果是工版,則可使用如下方式打開fps的log,查看TE信息:

        adb shell

        cd sys/kernel/debug

        echo fps:on>mtkfb

然后查看mtklog, 搜索“FPS”,若看到等待TE時間為0, 表示TE未正常開啟,需要與LCM IC的FAE進一步確認開啟流程 。

若TE已經成功開啟,依然有Teering現象,可從如下方面思考分析。

    1)是否使用了豎屏橫用,導致對GRAM的讀寫方向不一致,一般會出現斜線切屏現象。

    2)是否clock速度過低,FPS低於LCM自刷新率的1/2?

    3)是否clock速率過快,超過LCM的自刷新率,導致寫GRAM時可能從后面趕上讀,導致Teering發生。

 

    4)fmark周期與CS周期

          出現TE現象的根本原因是兩邊速度不一致,具體是LCM的刷新速度要快於主控送數據的速度,兩者的速度要符合一定的范圍才行。只要保證CS的周期在兩個TE周期之間即可,也就是CS的寫頻率不能低於TE讀頻率的二分之一,Tearing出現的根本條件是讀寫有交叉。通常都是寫Gram速度(WR)慢於lcd刷屏速度(TE[x2] 只要刷屏的位置不超過寫Gram位置就不會有切屏現象[x3] 

          舉個實例:比如CS差不多就比兩個TE周期小一點,要刷兩楨數據,首先第一楨刷屏開始刷屏了,表示讀GRAM開始,它的速度比較快,它讀的是老舊數據;緊接着主控開始寫GRAM,大概寫到GRAM的快一半時,這時候已經刷完一楨,然后開始刷第二楨,即又從GRAM的最上方開始讀並刷屏,此時讀出來的才是剛寫入的新數據,在寫完GRAM之前,讀的步驟永遠跟不上寫的步驟,就不會出現tearing。

     如果CS比兩個TE周期大,假設相當於三個TE周期,那么只有在第三個TE讀周期時,顯示的數據才是寫好的GRAM的數據;第一個TE讀的是老舊的數據,第二個TE周期由於GRAM還沒有寫完,但讀步驟趕上寫GRAM步驟了,導致顯式一部分是舊的一部分是新的,所以出現TE。此即本質。
    5) TE類型

        TE顯示使能時,必須保證CPU的LCD TE使能和LCM驅動的TE功能都打開。LCM的TM使能有兩


 

 

1.6)HS/LP:

HS:high speed , clock切為HS模式,高速模式。

LP:low power,低電平

    有些LCM在開機的時候,如果使用LP下發init code,可能會不准確或者導致花屏等問題,這時候需要使用HS mode發送init code,比如三星的某款OLED(D53D6EA8061V-Amoled)。

continuous clock/no-continuous clock模式

 

1.6)dithering:

抖動顯示技術:

    MT6572 如所用lcm不支持RGB888 color format, 顯示效果差需要開啟dithering的。

 

1.7)其他概念:

    AAL:BB端CABC(即AAL),為1種方式控制背光

        continuous clock/Non-continuous clock : Switch clock lane from HS to LP

 

 

2.LCM時鍾配置

MT6582 LCM Driver中配置:params->dsi.PLL_CLOCK = 234;

計算方法:

    展頻開關:

    如果MIPI Clock對RF/WCN產生干擾,並且在嘗試尋找相應的頻點依然無法解除 EMI,可以嘗試做Frequency Hopping;

82平台默認打開展頻開關,不同於72/89平台,將展頻的開關以及展頻幅度的選擇 ,都開放到LCM Driver中,以如下為例:

    params->dsi.ssc_range =4;

    params->dsi.ssc_disable = 0;

    代表:展頻打開,ssc_range = 4%

 

 

3.AAL與CABC背光選擇(兩種方式控制背光):

參考[FAQ05966]

【BB端CABC(即AAL)】

    - 打開功能,向MTK申請patch,並在ProjectConfig.mk中打開MTK_AAL_SUPPORT = yes

    cust_leds.c(包括lk與kernel中的兩支文件)設置如下
    
 
     【LCM端CABC】
    - 對於Video Mode,ALPS.JB2.MP.V1.3(包括1.3)之前的版本,請向MTK申請patch
    - lcm driver中實現set_backlight接口
    - cust_leds.c(包括lk與kernel中的兩支文件)設置如下
    

 

 

4. 調整Display 消耗的BW(bandwidth帶寬)方法:

•LCM driver建議如下:

    –MIPI的clock 盡量低,建議60fps

    –For DSI Video mode,建議不要使用burst mode(比較能吃BW)

        params->dsi.mode = BURST_VDO_MODE;

    –Video mode的時序,blank 區間(如VBP/VFP/HBP/HFP)盡量少(當然也需要滿足LCM module的spec)

 

 

5.DSI video mode相關參數配置方法:

對應配置文件:\alps\mediatek\custom\common\kernel\lcm\xxxx.c中lcm_get_params()函數

1,data lane每幀回LP11(Low Power state,dp,dn都為高電平),clk一直HS( High Speed),對應配置:

    params->dsi.cont_clock=1;

    params->dsi.clk_lp_per_line_enable=0;

 

2,data lane每一行回一次LP11,clk lane每一幀回一次LP,對應配置:

    params->dsi.cont_clock=0;

    params->dsi.clk_lp_per_line_enable=0;

 

3,data lane和clk lane都是每行回一次LP11,對應配置:

    params->dsi.cont_clock=0;

    params->dsi.clk_lp_per_line_enable=1;

 

 

6.LCM CABC 配置

參考[FAQ12413]

    

 

 

7.MHL 卡頓問題

 

 

8.ESD機制各個平台的差異:

    對於89/72/82等新平台,Display架構做了調整,ESD的實現方式與之前的75/77等平台稍有差異。對於之前75/77平台,可以參考FAQ03210及FAQ05163.

    新舊架構下,主要是DSI Video Mode下ESD方式不一樣。

之前的架構下Video Mode的屏采用檢測外部TE或者內部TE來做ESD Check,因此需要在lcm driver中配置相應的參數。

 

新架構下不支持外部TE或內部TE來做ESD check, lcm_get_params中關於esd的參數不用再配置。

如lcm_int_te_monitor、lcm_int_te_period、lcm_ext_te_monitor等無需配置。

[SOLUTION]

    新的Display架構下,DSI Video Mode及DSI Command Mode都采用讀寄存器的方式來進行esd check. 因此都只需要在lcm driver中實現esd_check和esd_recover函數即可。

對於具體讀取哪些寄存器來進行esd check,需要與屏廠確認。

ESD實現后如果出現每兩秒閃屏的問題,可以按如下流程處理:

    1. 首先檢查esd check中是否添了過多的log信息或者有delay操作,建議先去掉所有log測試。

    2. 如果依然出現每兩秒閃屏,可參考FAQ05680和FAQ05681進行處理。

 

 

9.DBI/DPI接口的GPIO的配置情況

    DBI:DBI接口分為串行和並行兩種。由lcm_params->ctrl這個參數控制。

    LCM_CTRL_SERIAL_DBI/LCM_CTRL_PARALLEL_DBI

    1.)如果是serial類型的,是通過MT6572 datasheet里面的0x14012028 DBI_SCNF (DBI Serial Interface Configuration Register)這個寄存器來config串行接口。比如使用LSDI還是LSDA,LSCK上升沿還是下降沿發送數據 ,LSCK在沒有數據的時候是LOW/HIGH.

    配置幾個GPIO pin:LSCE0B(相當於數據使能信號,低電平有效), LSCK, LSDA/LSDI(傳送command時用),DBI[XX:0](傳 送data時用)

CSS,CSH:chip select setup time/chip select hold time

(這兩個時間之內是不會傳數據的,Invalid data)

 

    2.)如果是Parallel類型的,

        配置幾個GPIO pin:LPCE0B(相當於CS信號,低電平有效), LPA0(RS信號,MTK平台上面和CS信號是同步的), LCD CLK,LPWRB/LPRDB(類似數據使能信號)和DBI[XX:0](復用DPI的data pin,傳送data和command時用)

寫的時候用LPWRB,讀的時候用LPRDB

有C2WS和C2WH兩個變量:chip selection to write setup time和chip selection to write hold time

同理C2RS和C2RH.

硬件連接:

DBI Parallel類型:BB端需要打開LRDB、LWRB、LPA0 pin腳復用功能,並連接到LCM的RD、WR、RS

DBI serial類型: BB端需要打開LSCE0B、LSCK、LSDA/LSDI pin腳復用功能, 並連接到LCM的CSX, SCL, SDA/DOUT/DIN

lcm Driver里面變量write wait state time,是處於wait狀態的時間。比如大於等於C2WS,參考MT6572 datasheet PAGE1659原理圖

note:89和72的DBI的clock都是不可調整的,都是130Mhz.

但是如果需要調整DBI的FPS的話,可以調整C2WS/C2WH/WST,分別對應write_setup/write_hold/write_wait

DPI:

使用DPI接口時,根據LCM IC支持的情況,可以選擇16bus、18bus傳輸RGB格式文件,在GPIO部分分為R、G、B分別對應 8個GPIO(GPIO20~46期間),客戶采用DPI接口需要根據選擇的bus方式進行配置,推薦RGB端口全部配置為對應的復選模式,並設置為 OUT輸出。

同時DPI的接口需要BB端打開DPIHSYNC、DPIVSYNC、DPIDE、DPICK復用功能,並分別連接到對應的LCM控制端

另注:

其實DPI和DBI一樣,都是可以通過lcm_params->ctrl這個變量來控制是使用Parallel還是serial還是GPIO的類型來下 command。

但是一般DPI都會選擇使用LCM_CTRL_SERIAL_DBI這個類型,因為DPI的屏,DB[17..0]只是會用來做數據傳輸,控制線是 會通過LSDA/LSDI傳輸。

 

 

10.LCM Porting時如何配置Clock

clock配置方法:

    lcm driver中配置clock有不同的方式,曾經使用過的配置方法有如下幾種:

    Type1: 配置倍頻與分頻參數:dsi.pll_div1(倍頻), dsi.pll_div2(分頻)--- (適用於75/77等之前的平台)

    Type2: 配置倍頻與分頻參數:dsi.pll_fbk_div(倍頻), dsi.pll_div1 & dsi.pll_div2 (分頻)---(適用於89/72等前 期版本)

    Type3: 直接配置clock lane頻率:dsi.PLL_CLOCK(前期配置成枚舉值,后期將直接配置成對應的頻率常數值)----(適 用於89/72/82...)

 

11.如何使用PMIC的LDO方式供給LCM端 1.8/2.8v的電壓

參考[FAQ10038]

    1. 如何在開機階段使用PMIC的LDO方式供給LCM端1.8/2.8v的電壓?

    2. 如何在suspend/resume的時候,斷掉/供給LCM端1.8/2.8v的電壓?

 

1. )在開機的時候,建議在preloader或者LK階段就通過PMIC的LDO方式來給LCM端上電,

    比如可以在alps\mediatek\platform\mt6589\preloader\src\drivers\mtk_pmic_6320.c文件里面的 pmic6320_init函數中做上電1.8/2.8v的操作。

    AOSP版本mtk_pmic_6320.c的路徑 :alps/bootable/bootloader/preloader/platform/mt6572/src/drivers/mtk_pmic_6320.c

下面是在LK階段的上電/掉電方法:

    使用upmu_common.c文件里面API來分別控制每一個LDO_VGPX.

比如:

    upmu_set_rg_vgp6_vosel用來控制上電的電壓值;

    upmu_set_rg_vgp6_en用來控制enable VGP6這個pin

 

2. )因為在suspend/resume的時候,kernel都是跑起來的,所以上電/掉電 1.8/2.8v的操作都應該放在kernel里面。

    下面是在kernel里面的上電/掉電方法,在kernel里面有統一的上電/掉電的接口函數: 上電接口函數:hwPowerOn 掉電接口函數hwPowerDown

以下以PMIC6320的VGP6為例。

請在您要上電的文件#include <mach/mt_pm_ldo.h> 上電請調用 hwPowerOn,掉電請調用hwPowerDown

    hwPowerOn(MT65XX_POWER_LDO_VGP6, VOL_2800, "ldo_test");

    bool hwPowerDown(MT65XX_POWER_LDO_VGP6, "ldo_test");

 

 

12.如何拉低並保持LCM RESET PIN腳為低 電平

平台默認RESET PIN腳輸出為高平的,如果一定需要拉低,可以配置RESET PIN腳為GPIO模式,再通過GPIO方式拉低。

使用mediatek/dct目錄下的DCT工具,使用其打開custom/XXX/kernel/dct/dct目錄下的DWS文件,將GPIO131配置成 0:GPIO131. 

對GPIO PIN腳的控制有如下一些方法:

    lcm_util.set_gpio_mode(GPIO131, GPIO_MODE_00);

    lcm_util.set_gpio_dir(GPIO131,GPIO_DIR_OUT);

    lcm_util.set_gpio_out(GPIO131,0);

 

 

13.如何調節MIPI接口驅動能力

    在使用DBI、DPI的MIPI接口時,可以在lcm_get_params函數中設置參數 io_driving_current的值來配置IO的驅動電流(6589上面不支持) 

DSI的MIPI接口,不支持IO驅動電路的調節 ,其可選值的大小可以在lcm_drv.h看到定義。

其可選值的大小可以在lcm_drv.h看到定義:

    typedef enum{

    }LCM_DRIVING_CURRENT;

該值的會在lcd_drv.c文件中寫到寄存器中:

    LCD_STATUS LCD_Set_DrivingCurrent();

 

 

14.如何通過檢測外部TE實現esd check的 功能

    在72/82/92的JB/KK版本,我們都是通過讀取esd寄存器的方式實現esd check,但是由於esd  check的時候會切換到cmd mode去讀,所以屏的玻璃存在最大1幀時間的等待,如果這個vdo 

mode屏的玻璃延時等待時間較小(小於切換的時間),就會出現閃屏,所以不能使用讀esd寄存器 的方式做esd check。 

    如果這個屏有 external TE管腳的話,可以通過檢測ext.TE的方式來做esd check,具體原理 為:把原來的esd流程全部關閉,啟動一個新的線程,循環檢測外部TE中斷,如果檢測失敗,就

recovery。

新的esd流程里面需要做三件事:

    1)         物理連接一根外部TE pin,然后在dws文件里面配置一個GPIO口為DSI_TE模式。

    2)         在DSI初始化的時候,注冊該ext.TE的irq處理函數,收到中斷則設置irq_flag為TRUE。

    3)         啟動線程定時去wait flag==1,如果超時,則做esd recovery。

 

 

15.如何配置DSI時鍾頻率

    1、)DSI vdo mode下的數據速率data_rate的大致計算公式為: Data rate= (Height+VSA+VBP+VFP)*(Width+HSA+HBP+HFP)* total_bit_per_pixel*frame_per_second/total_lane_num 

 

    2、)DSI cmd mode下的數據速率data_rate的大致計算公式為: Data rate= width*height*1.2* total_bit_per_pixel*frame_per_second/total_lane_num 

參數注釋:

    data_rate : 表示的是數據速率

    width,height  :屏幕分辨率

    VSA VBP VFP :DSI vdo mode的vertical porch配置參數

    HSA HBP HFP :DSI vdo mode的horizontal porch配置參數

    total_bit_per_pixel :表示的是一個pixel需要用幾個bit來表示,比如RGB565的話 就是16個bit 

    frame_per_second :就是我們通常看到的fps,叫做幀率,表示每秒發送多少個幀 ,一般是60幀每秒 

    total_lane_num :表示的是data lane的對數。

 

3、)DSI采用的是雙邊采樣,則clk等於數據速率的一半,因此: clk=data_rate/2

有兩種配置clk的方式,第一種方式配置四個參數得到,第二種配置方式直接配置頻 率,建議采用第二種。 

第一種方式,通過div分頻倍頻實現,各個平台略有差異,但是原理基本一致,請參 考porting guide,如下舉例89平台: 

    params->dsi.pll_div1   = ;  //配置范圍為0,1,2,3的時候,對應的 div1_real等於1,2,4,4 

    params->dsi.pll_div2   = ;  //配置范圍為0,1,2,3的時候,對應的 div2_real等於1,2,4,4 

    params->dsi.fbk_div   = ;  //范圍 0..63

    params->dsi.fbk_sel   = ;  //配置范圍為0,1,2,3的時候,對應的 fbk_sel_real等於1,2,4,4 

    輸出頻率 =26MHz*(fbk_div+1)*(2*fbk_sel_real)/(div1_real*div2_real) 

第二種方式,直接配置clk大小:

    params->dsi.PLL_CLOCK = LCM_DSI_6589_PLL_CLOCK_234;//這里舉例89平台,使用 一個宏,表示配置的clk等於234MHz。但是在89之后的平台,使用直接配置一個頻率 

數字的方式,比如params->dsi.PLL_CLOCK = 234,表示234MHZ)

 

 

4、在lcm porting過程中,這些參數都定義在lcm_drv.h文件中的LCM_DSI_PARAMS結 構體中,隨着平台的發展,或許有所不同,但是基本原理都是一致的,如何配置clk的大小,請先根據自己的幀率、像素格式、porch值、屏的分辨率、 data lane對數等計算出data_rate,然后計算出clk。

 

 

16.背光模式設置成 T65XX_LED_MODE_CUST_BLS_PWM,如何修改PWM的工作頻率

前提:cust_leds.c文件里面使用的背光模式是MT65XX_LED_MODE_CUST_BLS_PWM

MT6582版本工作頻率計算公式如下:

    PWM工作頻率計算公式:26MHz (clock freq.) / (PWM_CLKDIV+1) / 1024 (period) 26 KHz 

    所以需要修改PWM的工作頻率,可以通過修改PWM_CLKDIV,clock freq,或者period的值來達到修 改PWM的工作頻率的效果。 

以下的三種方法可以任選1~2種來達到想要的PWM工作頻率:

1.  修改分頻參數方法,修改config_data里面的第二個參數:

    {"lcd-backlight",     MT65XX_LED_MODE_CUST_BLS_PWM, (int)disp_bls_set_backlight,{0, 1, 0, 0, 0}} //設置div=1 

2. 修改clock freq:

在alps\mediatek\platform\mt6582\kernel\drivers\dispsys\ddp_bls.c文件的 disp_bls_init和disp_bls_config函數中設置CLK_CFG_1這個寄存器的值,來選擇合適的時鍾源,加入如下代碼: 

    mt65xx_reg_sync_writel(DRV_Reg32(CLK_CFG_1) | (0x00000003), CLK_CFG_1); //設置156 MHz的時鍾源 

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM