高通安卓調試LCD幾方面總結(二)

   最近工作太忙了,而且經常出差,所以有一個多月沒有來得及更新博客了,唉,之前一個項目LCD也遇到幾個棘手的問題,壓力山大。

   閒話少說,直接進入正題了,在上一篇裏寫了高通平臺android2.3裏的kernel和bootloader(LK)裏LCD驅動的移植,這一篇主要寫一下在4.0裏LCD驅動的移植。

    (1) kernel

   高通的android4.0和2.3在kernel裏的LCD驅動是有區別的,主要在於4.0裏少了latedisplay.c這個文件。這裏我以renesas公司的r61408這顆IC來介紹。我使用的是RGB565的接口,由於kernel裏有高通公司提供的其它家IC的代碼,我同樣是以truly的來作爲參考的,代碼的框架不變。首先就是在kernel\drivers\video\msm下以truly的代碼爲模板,創建一個名爲lcdc_r61408.c的文件,文件裏的內容照着truly的來做。

   這裏先來把Makefile和Kconfig文件修改好。在kernel\drivers\video\msm文件夾下的Makefile裏添加:

        obj-$(CONFIG_FB_MSM_LCDC_RENESAS_R61408) += lcdc_renesas_r61408.o
     在此目錄下打開Kconfig文件,在裏面添加:

 config FB_MSM_LCDC_RENESAS_R61408
  bool
  select FB_MSM_LCDC_PANEL
  default n

config FB_MSM_LCDC_RENESAS_R61408_PT_PANEL
  depends on FB_MSM_LCDC_HW
  bool "LCDC Renesas PT Panel"
  select FB_MSM_LCDC_RENESAS_R61408
  default n
  ---help---
  Support for LCDC Renesas PT panel
    還要在kernel\arch\arm\configs目錄下的board config文件裏添加:

             CONFIG_FB_MSM_LCDC_RENESAS_R61408_PT_PANEL=y

    在lcdc_r61408.c文件裏主要就是要寫向LCD用SPI發指令和發數據的函數,我們的這個項目裏使用的是GPIO口模擬的SPI總線,所以SPI的時序一定要寫正確,R61408在用SPI發指令的時候data和command是在寫8bit數據前通過SDO口的高和低來判別的,但是有些LCD的IC,比如NT35510,需要在發8bit數據之前要發送R/W,H/L,D/C幾個信號來區別接下來發的數據表示什麼。所以一定要根據所選用的LCD的IC的spec嚴格的來寫SPI的時序,否則有可能造成LCD的初始化都不成功。

   在kernel裏,LCD的驅動的調用的流程是:

msm_fb_open()  (msm_fb.c)
  -> msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)
    -> if (!mfd->panel_power_on) {
           ret = pdata->on(mfd->pdev); //這裏的on指向的就是lcdc.c裏的lcdc_on()函數
                -> lcdc_on()	/*這個函數裏開啓LCDC時鐘,並且打開LCD*/
              -> clk_prepare_enable(pixel_mdp_clk);
                 clk_prepare_enable(pixel_lcdc_clk);
                 if (lcdc_pdata && lcdc_pdata->lcdc_power_save)
                   lcdc_pdata->lcdc_power_save(1);/*函數指針,指向board-display.c裏的msm_lcdc_power_save()*/
                 if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config)	/*這裏lcdc_gpio_config指針是空,所以不會接着調 下一步*/
                       ret = lcdc_pdata->lcdc_gpio_config(1);
                 ret = panel_next_on(pdev);/*函數指針,指向lcdc_renesas_r61408.c裏的lcdc_renesas_panel_on()函數*/

panel_next_on(pdev) (lcdc.c)

  -> lcdc_renesas_panel_on() (lcdc_renesas_r61408.c)
    -> renesas_disp_reginit() 	/*初始化LCD的寄存器*/
      -> renesas_spi_write_bytes() /*設用SPI寫函數*/

lcdc_renesas_panel_init(void) (lcdc_renesas_r61408.c)

-> platform_driver_register(&this_driver);/*註冊LCD驅動,此時renesas_probe函數會調一次,主要是爲了從board-display.c裏獲取SPI和背光各管腳的定義值*/
   /*設置與LCD相關的參數,具體各參數意義參考上一篇*/
   pinfo->xres = 480;
   pinfo->yres = 800;
   MSM_FB_SINGLE_MODE_PANEL(pinfo);
   pinfo->type = LCDC_PANEL;
   pinfo->pdest = DISPLAY_1;
   pinfo->wait_cycle = 0;
   pinfo->bpp = 16;
   pinfo->fb_num = 2;
   pinfo->clk_rate = 30720000;
   pinfo->bl_max = 32;
   pinfo->bl_min = 1;
   pinfo->lcdc.h_back_porch = 10;/* hsw = 8 + hbp=16 */
   pinfo->lcdc.h_front_porch = 150;////100
   pinfo->lcdc.h_pulse_width = 10;
   pinfo->lcdc.v_back_porch = 22;///12/* vsw=1 + vbp = 7 */
   pinfo->lcdc.v_front_porch = 10;
   pinfo->lcdc.v_pulse_width = 2;
   pinfo->lcdc.border_clr = 0;	/* blk */
   pinfo->lcdc.underflow_clr = 0xff;/* blue */
   pinfo->lcdc.hsync_skew = 0;

   platform_device_register(&this_device);/*這裏又註冊了一個device,這個device和board-display.c裏 的device是通過id來區別的,然後會再次調用renesas_probe函數*/
     -> msm_fb_add_device(pdev)	/*向高通的FB架構裏將上面的LCD信息註冊進去*/

    在關閉LCD的時候,kernel裏驅動調用流程剛好是和上面反向的。

   這裏有一點,因爲我們使用的背光是通過PMIC的一個1號腳來控制的,使用PMIC管腳產生PWM的使用方法是,在board-display.c裏初始化GPIO的函數裏,加上這麼一句:

                     pmapp_disp_backlight_init();
    然後在board-display.c里加上如下配置:

static int lcdc_set_bl(int level)
{
  int ret;
  //PRINTK("lcdc_renesas_set_bl,level = %d\r\n",level);
  ret = pmapp_disp_backlight_set_brightness(level);
  if (ret)
    pr_err("%s: can't set lcd backlight!\n", __func__);
  return ret;
}
static struct msm_panel_common_pdata lcdc_panel_data = {
  .panel_config_gpio = NULL,
  .pmic_backlight = lcdc_set_bl,
  .gpio_num	  = lcdc_gpio_table,
}
    最後在lcdc_renesas_r61408.c的pmic_backlight這個函數指針就可以實現背光的控制和調節。

 (2) bootloader(lk)

   和上一篇一樣,首先要在目錄/bootable/bootloader/lk/target/$(Projec)下更改lcd的makefile文件rules.mk,在rules.mk下添加:

                   DEFINES += DISPLAY_LCDC_PANEL_R61408=1
   代碼的流程可以跟着truly的例子來做,這裏簡單的介紹一下流程:
void kmain()(/bootable/bootloader/lk/kernel/main.c)
  -> thread_resume (thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
    -> bootstrap2
      -> target_init(); (bootable\bootloader\lk\target\$(project)\Init.c)
        -> /*這裏是bootloader裏按鍵的驅動*/
          #if (!ENABLE_NANDWRITE)
          keys_init();
          keypad_init();
          #endif

          display_init();	/*初臺化LCD驅動*/
          dprintf(INFO, "Diplay initialized\n");
           display_image_on_screen(); /*向LCD裏發送圖像數據*/

display_init()  (/bootable/bootloader/lk/platform/msm7627a/platform.c)
/*這裏lcdc_init()和panel_lcdc_init()的順序如果調過來LCD顯示就不正常,我也很奇怪,不知道是爲什麼*/
-> fb_config = lcdc_init();
  -> mdp_lcdc_clock_init();/*初始化LCDC的時鐘*/
      lcd_timing = get_lcd_timing();/*獲取LCD相關的硬件設置*/
      fb_cfg = lcdc_init_set(lcd_timing);/*根據上面得到的設置數據來設置CPU的寄存器*/

-> panel_lcdc_init();	/*初始化LCD,要完成的有RESET,SPI的讀寫函數等等*/

    LCDC接口的LCD驅動在LK裏相對MIPI的來說流程比較簡單,SPI的時序參考KERNEL裏的一般就沒有什麼問題的。

    到這裏,LCDC和MIPI的兩種LCD在高通平臺上的驅動也算是寫完了,小弟也正處在學習的過程當中,寫得不好。

文章轉自:http://blog.csdn.net/dacaozuo/article/details/7934774

發佈了15 篇原創文章 · 獲贊 19 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章