uboot中LCD初始化之datasheet

Sc8810 DataSheet分析LCD初始化

一、基础条件

依赖代码:Sc8810_fb.c

LCD型号:NT35510_A45026N00HN

pdf中的内容如下:

二、初始化分析

1、初始化部分从static int sc8810fb_probe(void * lcdbase)开始

     LCD最后Application Notes中提到如下:

     uboot中LCD初始化之datasheet_第1张图片

 对应代码static void hw_early_init(struct sc8810fb_info *fb),如下:

          //select LCD clock source

      __raw_bits_and(~(1<<6), GR_PLL_SRC);    //pll_src=96M

      __raw_bits_and(~(1<<7), GR_PLL_SRC);

 

      //set LCD divdior

      __raw_bits_and(~(1<<0), GR_GEN4);  //div=0

      __raw_bits_and(~(1<<1), GR_GEN4);

      __raw_bits_and(~(1<<2), GR_GEN4);

 

      //enable LCD clock

      __raw_bits_or(1<<3, AHB_CTL0);

 

      //LCD soft reset

      __raw_bits_or(1<<3, AHB_SOFT_RST);

      mdelay(10);

      __raw_bits_and(~(1<<3), AHB_SOFT_RST);

 

         //LCD enable LCDC global interrupt

      __raw_bits_and(~(1<<0), LCDC_IRQ_EN);

配置好上述寄存器之后,执行到显示模式,datasheet描述拉如下:

对应代码如下:

      __raw_bits_or((1<<0), LCDC_IRQ_CLR);

          执行子函数lcdc_mcu_init,其内容如下:

         //panel reset

      panel_reset();

 

      //LCDC module enable

      reg_val |= (1<<0);

 

      /*FMARK mode*/

      reg_val |= (1<<1);  // no f-mark

 

      /*FMARK pol*/

      //reg_val |= (1<<2);

 

      __raw_writel(reg_val, LCDC_CTRL);

 

2、为了区分同一个厂家的LCD模块,由于其读取的ID是相同的,因此需要读取电压AD值来区分不同型号

    ADC_Init(); //为了读取电压值

         ANA_REG_OR(ANA_AGEN, AGEN_ADC_EN);

         ANA_REG_OR(ANA_CLK_CTL, ACLK_CTL_AUXAD_EN |    ACLK_CTL_AUXADC_EN);

         ANA_REG_OR(ADC_CTRL, ADC_EN_BIT);

 

 

3find_adapt_from_readid读取LCDID值,并进行挂载,从而才能实现特定的LCD屏幕初始化。

   for循环依次挂载,并相应初始化后,再读取ID值。

      int i;

      uint32_t id;

      for(i = 0;i<(sizeof(lcd_panel))/(sizeof(lcd_panel[0]));i++) {

             //first ,try mount

             mount_panel(fb,lcd_panel[i].panel);

             //hw init to every panel

             hw_init(fb);

             //readid

             if(fb->panel->ops->lcd_readid) {

                    id = fb->panel->ops->lcd_readid(fb->panel);

                    FB_PRINT("[The panel id is 0x%x]\n", id);

             } else {

                    id = lcd_readid_default(fb->panel);

             }

             //if the id is right?

             if(id == lcd_panel[i].lcd_id) {

                    FB_PRINT("[The lcd panel return id is 0x%x]\n", id);

                    save_lcd_id_to_kernel(id);

                    return i;

             }

      }

      return -1;

 

4、分配显存

    fb->smem_start = (uint32_t)lcdbase;

      fb->smem_len = fb->panel->width * fb->panel->height; 

 

5、这里根据datasheet的操作如下:

uboot中LCD初始化之datasheet_第2张图片

初始化代码中是先进行LCM参数配置,再进行图层信息的配置,个人觉得这里初始化顺序允许颠倒。

代码中LCM参数初始化对应static void hw_init(struct sc8810fb_info *fb),如下:

          /* only MCU mode is supported currently */

      if (LCD_MODE_RGB == fb->panel->mode)

             return;

 

      //panel reset

      panel_reset(fb->panel);

 

      /* set lcdc-lcd interface parameters */

      lcdc_lcm_configure(fb);

 

      /* set timing parameters for LCD */

      lcdc_update_lcm_timing(fb->register_timing);

 

其中lcdc_lcm_configure(fb);内容如下:

          uint32_t reg_val = 0;

      /* CS1 bus mode [BIT0]: 8080/6800 */

      switch (fb->panel->info.mcu->bus_mode) {

      case LCD_BUS_8080:

 

             break;

      case LCD_BUS_6800:

             reg_val  |= (1 << 8);

             break;

      default:

             break;

      }

      /* CS1 bus width [BIT1:0] */

      switch (fb->panel->info.mcu->bus_width) {

      case 8:

             break;

      case 9:

             reg_val  |= ((1 << 9) | (1 << 12));

             break;

      case 16:

             reg_val  |= (2 << 9);

             break;

      case 18:

             reg_val  |= ((3 << 9) | (1 << 12));

             break;

      case 24:

             reg_val  |= ((4 << 9) | (2 << 12));

             break;

      default:

             break;

 

      }

 

      reg_val  |= (1 << 16);

      __raw_writel(reg_val, LCM_CTRL);

其中lcdc_update_lcm_timing(fb->register_timing);内容如下:

      __raw_writel(value, LCM_PARAMETER1);

 

6、以上初始化LCM,根据之前的datasheet知道接着初始化OSD,这之前需要先初始化屏幕,然后再初始化OSD   fb->panel->ops->lcd_init(fb->panel);

 

7、初始化OSDIMG总共6

      __raw_bits_and(~(1<<0),LCDC_IMG_CTRL);

      __raw_bits_and(~(1<<0),LCDC_OSD2_CTRL);

      __raw_bits_and(~(1<<0),LCDC_OSD3_CTRL);

      __raw_bits_and(~(1<<0),LCDC_OSD4_CTRL);

      __raw_bits_and(~(1<<0),LCDC_OSD5_CTRL);

 

      reg_val |= (1 << 0);

      reg_val |= (1 << 2);

      reg_val |= (5 << 3); //RGB565

      reg_val |= (2 << 7); //B2B3B0B1

      __raw_writel(reg_val, LCDC_OSD1_CTRL);

 

      /* OSD1 layer base */

      reg_val = fb->smem_start;

 

      /*OSD1 layer alpha value*/

      __raw_writel(0xff, LCDC_OSD1_ALPHA);

 

      /*OSD1 layer size*/

      reg_val = ( fb->panel->width & 0xfff) | (( fb->panel->height & 0xfff )<<16);

      __raw_writel(reg_val, LCDC_OSD1_SIZE_XY);

 

      /*OSD1 layer start position*/

      __raw_writel(0, LCDC_OSD1_DISP_XY);

 

      /*OSD1 layer pitch*/

      reg_val = ( fb->panel->width & 0xfff) ;

      __raw_writel(reg_val, LCDC_OSD1_PITCH);

 

8、最后设置LCDCLCM的尺寸

      /*LCDC workplane size*/

      set_lcdsize(fb->panel);

 

      /*LCDC LCM rect size*/

      set_lcmrect(fb->panel);

 

9、清除LCD,并设置开机Logo

      lcd_clear (NULL, 1, 1, NULL);     /* dummy args */

      lcd_enable ();//未实现

 

10、通过阅读datasheet后面的屏幕初始化,刷屏如下:

 

 

 

 

 

通过代码查找,定位到static void real_refresh(struct sc8810fb_info *fb)

      fb->panel->ops->lcd_invalidate(fb->panel);

      /* set timing parameters for LCD */

      lcdc_update_lcm_timing(fb->gram_timing);

 

      __raw_bits_or((1<<3), LCDC_CTRL); /* start refresh */

      

      while(!(__raw_readl(LCDC_IRQ_RAW) & (1<<0))); // wait util done

 

      __raw_bits_or((1<<0), LCDC_IRQ_CLR);

 

      /* set timing parameters for LCD */

      lcdc_update_lcm_timing(fb->register_timing);

 

三、总结

不难看出,整个屏幕初始化程序的编写基本都是依据datasheet中的lcd application notes编写的,因此如果以后需要编写初始化程序,完全可以按照datasheet中的应用来编写或者分析。

 

你可能感兴趣的:(uboot中LCD初始化之datasheet)