s5pc110 lcd driver分析(1) (转)

s5pc110 lcd driver分析(1) (转)
2011-09-19 17:58

//设置寄存器0xF800_0130(Video Interrupt Control 0 Register) [16:15]位为01 = VSYNC,这两位可能的值为00 = BACK Porch,10 = ACTIVE
int s3cfb_set_vsync_interrupt(struct s3cfb_global *ctrl, int enable)


//设置寄存器0xF800_0130 enable或者disable第【12】位和第【0】位,分别表示
//INTFRMEN [12] Specifies the Video Frame Interrupt Enable Control Bit.
//   0 = Disables Video Frame Interrupt
//   1 = Enables Video Frame Interrupt
//   Note: This bit is meaningful when INTEN is high
//INTEN [0] Specifies the Video Interrupt Enable Control Bit.
//   0 = Disables Video Interrupt
//   1 = Enables Video Interrupt
int s3cfb_set_global_interrupt(struct s3cfb_global *ctrl, int enable)


static int s3cfb_init_global(void)
{
   fbdev->output = OUTPUT_RGB;
   fbdev->rgb_mode = MODE_RGB_P;

   fbdev->wq_count = 0;
   init_waitqueue_head(&fbdev->wq);
   mutex_init(&fbdev->lock);

   s3cfb_set_output(fbdev);      
//设置寄存器0xF800_0000 的第[28:26]位,这三位所代表的意义是
//Determines the output format of Video Controller.
//   000 = RGB interface
//   001 = Reserved
//   010 = Indirect I80 interface for LDI0
//   011 = Indirect I80 interface for LDI1
//   100 = WB interface and RGB interface
//   101 = Reserved
//   110 = WB Interface and i80 interface for LDI0
//   111 = WB Interface and i80 interface for LDI1
//设置寄存器0xF800_0008 [15:14] [13:12]位,这些代表的意义
//   Reserved [15:14] Reserved.
//   Note: This bit should be 1.
//TVFORMATSEL [13:12] Specifies the output format of YUV data.
//   00 = Reserved
//   01 = YUV422
//   1x = YUV444
// 将这四位都设置为0

   s3cfb_set_display_mode(fbdev);
//设置寄存器0xF800_0000 的第[18][17]位,这两位所代表的意义是
//   RGSPSEL [18] Selects display mode (VIDOUT[1:0] == 2’b00).
//   0 = RGB parallel format
//   1 = RGB serial format
//   Selects the display mode (VIDOUT[1:0] != 2’b00).
//   0 = RGB parallel format
//   PNRMODE [17] Controls inverting RGB_ORDER (@VIDCON3).
//   0 = Normal: RGBORDER[2] @VIDCON3
//   1 = Invert: ~RGBORDER[2] @VIDCON3
//   Note: This bit is used for the previous version of FIMD. You do
//   not have to use this bit if you use RGB_ORDER@VIDCON3
//   register.
//这是设置这两位均为0             MODE_RGB_P = 0,
               MODE_BGR_P = 1,
               MODE_RGB_S = 2,
               MODE_BGR_S = 3,

   s3cfb_set_polarity(fbdev);
//设置寄存器xF800_0004, 第[7],[6],[5],[4] 位,这四位代表的意思是
//IVCLK [7] Controls the polarity of the VCLK active edge.
//   0 = Video data is fetched at VCLK falling edge
//   1 = Video data is fetched at VCLK rising edge

//IHSYNC [6] Specifies the HSYNC pulse polarity.
//   0 = Normal
//   1 = Inverted

//IVSYNC [5] Specifies the VSYNC pulse polarity.
//   0 = Normal
//   1 = Inverted

//IVDEN [4] Specifies the VDEN signal polarity.
//   0 = Normal
//   1 = Inverted

   s3cfb_set_timing(fbdev);
//设置寄存器0xF800_0010 32位分别表示
//VBPDE [31:24] Vertical back porch specifies the number of inactive lines at the
//   start of a frame after vertical synchronization period. (Only for even
//   field of YVU interface
//VBPD [23:16] Vertical back porch specifies the number of inactive lines at the
//   start of a frame after vertical synchronization period.
//VFPD [15:8] Vertical front porch specifies the number of inactive lines at the end
//   of a frame before vertical synchronization period.
//VSPW [7:0] Vertical sync pulse width determines the high-level width of VSYNC
//   pulse by counting the number of inactive lines.

//设置寄存器0xF800_0014, 32位分别表示
//VFPDE [31:24] Vertical front porch specifies the number of inactive lines at the end
//   of a frame before vertical synchronization period. (Only for the even
//   field of YVU interface).

//HBPD [23:16] Horizontal back porch specifies the number of VCLK periods
//   between the falling edge of HSYNC and start of active data.

//HFPD [15:8] Horizontal front porch specifies the number of VCLK periods
//   between the end of active data and rising edge of HSYNC.

//HSPW [7:0] Horizontal sync pulse width determines the high-level width of
//   HSYNC pulse by counting the number of VCLK.

   s3cfb_set_lcd_size(fbdev);
//设置寄存器0xF800_0018, 22位有效位分别表示
//LINEVAL [21:11] Determines the vertical size of display. In the Interlace mode,
//   (LINEVAL + 1) should be even.

//HOZVAL [10:0] Determines the horizontal size of display.
//NOTE: HOZVAL = (Horizontal display size) -1 and LINEVAL = (Vertical display size) –1.


   return 0;
}


我们继续看probe函数

/////////////////////////////////////////

   LCDDEBUG("%s, s3cfb init global\n", __func__);
   s3cfb_init_global();
   LCDDEBUG("%s, s3cfb init global done\n", __func__);
  
#if !defined(CONFIG_FB_S3C_DUMMYLCD)
   s3cfb_display_on(fbdev);
//设置寄存器0xF800_0000 的第[1][0]为,这两位分别表示
//ENVID [1] Enables/ disables video output and logic immediately.
//   0 = Disables the video output and display control signal.
//   1 = Enables the video output and display control signal
//ENVID_F [0] Enables/ disables video output and logic at current frame end.
//   0 = Disables the video output and display control signal.
//   1 = Enables the video output and display control signal.
//   * If this bit is set to “on” and “off”, then “H” is read and video
//   controller is enabled until the end of current frame.
//这里设置这两位为1
#endif

   /* panel control */
#if defined(CONFIG_FB_S3C_TL2796)
   if (pdata->backlight_on)
       pdata->backlight_on(pdev);
#elif defined(CONFIG_FB_S3C_LTE480WV)
   LCDDEBUG("%s, pdata->backlight_onoff:%p\n", __func__, pdata->backlight_onoff);
//如果满足条件, 调用lte480wv_backlight_onoff,打开背光
   if (pdata->backlight_onoff)
       pdata->backlight_onoff(pdev, 1);
#endif

#if !defined(CONFIG_FB_S3C_DUMMYLCD)
   LCDDEBUG("%s, pdata->reset_lcd:%p\n", __func__, pdata->reset_lcd);
//如果满足条件,调用lte480wv_reset_lcd函数, GPH0_6脚是LCD的 reset引脚
//我们可以看到在函数lte480wv_reset_lcd中首先调用gpio_request,第一个参数传递宏S5PC11X_GPH0(6),用这个参数直接索引一个静态数组
//static struct gpio_desc gpio_desc[ARCH_NR_GPIOS] 在数组中找到相应gpio_desc元素的struct gpio_chip成员地址,判断是否函数指针
//chip->request是否为空,如果存在则调用此函数,在我们的平台中,这个函数并不存在,第二个参数是label的值,如果内核选项CONFIG_DEBUG_FS
//为真,那么结构体struct gpio_desc包含成员Label,需要将参数二赋值给它,反之为空
//
//调用gpio_direction_output(unsigned gpio, int value),此函数同样,利用参数一S5PC11X_GPH0(6),找到相应的struct gpio_chip,判断成员
//direction_output函数指针是否为空,不为空则调用此函数status = chip->direction_output(chip, gpio, value);实际调用函数
//gpio_direction_output(S5PC11X_GPH0(6), 1), 配置引脚S5PC11X_GPH0(6) (E020_0C00)为output,输出dat为1
//mdelay(10);延时10ms
//调用函数gpio_set_value(S5PC11X_GPH0(6), 0)
       #define gpio_set_value   __gpio_set_value
       __gpio_set_value(unsigned gpio, int value) // driver/gpio/gpiolib.c
           通过第一个参数S5PC11X_GPH0(6)找到相应的结构体struct gpio_chip
           调用结构体的成员,函数指针void   (*set)(struct gpio_chip *chip,
                       unsigned offset, int value);
           set指向函数s3c_gpiolib_set 这个函数位于/arch/arm/plat-s3c/pgio.c
       这个函数写GPH0(6)的数据寄存器为0
//由此可知这里向GPH0(6)发一个低电平
//mdelay(10)
//调用函数gpio_set_value(S5PC11X_GPH0(6), 1)在发一个高电平
//mdelay(10)
//gpio_free(S5PC11X_GPH0(6)); 释放该引脚
      
   if (pdata->reset_lcd)
       pdata->reset_lcd(pdev);
#endif

   LCDDEBUG("%s, fbdev lcd init ldi:%p\n", __func__, fbdev->lcd->init_ldi);
   if (fbdev->lcd->init_ldi)
       fbdev->lcd->init_ldi();

///////////////////////////////////

我们继续返回主程序看probe函数


///////////////////////////////

   /* prepare memory */
   LCDDEBUG(" %s, s3cfb_alloc_framebuffer \n",__func__);
   if (s3cfb_alloc_framebuffer())
       goto err_alloc;
*************************************
static int s3cfb_alloc_framebuffer(void) 分析
   struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
   int ret, i;

   /* alloc for framebuffers */
   fbdev->fb = (struct fb_info **) kmalloc(pdata->nr_wins * \
           sizeof(struct fb_info *), GFP_KERNEL);
   //按照平台数据设置的window数分配全局结构体struct s3cfb_global fbdev的成员fb的空间,fb的类型是struct fb_info**
   //这里分配的是二级指针的空间
   if (!fbdev->fb){   //错误处理
       err("not enough memory\n");
       ret = -ENOMEM;
       goto err_alloc;
   }
       /* alloc for each framebuffer */
   //外循环用pdata->nr_wins的值控制,这里等于5
   for (i = 0; i < pdata->nr_wins; i++) {
       fbdev->fb[i] = framebuffer_alloc(sizeof(struct s3cfb_window), \
               fbdev->dev);
       //fbdev->fb[i]的类型为struct fb_info*,调用函数framebuffer_alloc得到分配的struct fb_info空间的起始地址
       // framebuffer_alloc 函数分析
           * framebuffer_alloc - creates a new frame buffer info structure
            *
            * @size: size of driver private data, can be zero
            * @dev: pointer to the device for this fb, this can be NULL
            *
            * Creates a new frame buffer info structure. Also reserves @size bytes
           * for driver private data (info->par). info->par (if any) will be
            * aligned to sizeof(long).
            *
           * Returns the new structure, or NULL if an error occured.
           这里sizeof(struct s3cfb_window)=136 sizeof(struct fb_info)=596
           一共分配了136+596 bytes内存空间,info->par指向驱动私有数据struct s3cfb_window

       if (!fbdev->fb[i]) { //如果空间分配失败
           err("not enough memory\n");
           ret = -ENOMEM;
           goto err_alloc_fb;
       }

       ret = s3cfb_init_fbinfo(i);//初始化相应的struct fb_info
       if (ret) {
           err("failed to allocate memory for fb%d\n", i);
           ret = -ENOMEM;
           goto err_alloc_fb;
       }

       if (i == pdata->default_win) {
           if (s3cfb_map_video_memory(fbdev->fb[i])) {
               err("failed to map video memory " \
                   "for default window (%d)\n", i);
               ret = -ENOMEM;
               goto err_alloc_fb;
           }//这里默认的win是0,所以需要把第一个win的Memory空间映射到内核虚拟地址空间
       }
   }


*************************************
   LCDDEBUG(" %s, s3cfb_alloc_framebuffer done\n",__func__);

   if (s3cfb_register_framebuffer())
       goto err_alloc;

****************************************
下面我们看s3cfb_register_framebuffer函数,这个函数主要是通过调用register_framebuffer实现5个window的注册
宏定义CONFIG_FRAMEBUFFER_CONSOLE 为真, 该配置项在内核的kconfig文件中为
config FRAMEBUFFER_CONSOLE
   tristate "Framebuffer Console support"
   depends on FB
   select CRC32
   help
      Low-level framebuffer-based console driver.
这个konfig文件位于/drivers/video/console/kconfig


int s3cfb_register_framebuffer(void)
{
   struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
   int ret, i;

   for (i = 0; i < pdata->nr_wins; i++) {
       ret = register_framebuffer(fbdev->fb[i]);
       if (ret) {
           err("failed to register framebuffer device\n");
           return -EINVAL;
       }

#ifndef CONFIG_FRAMEBUFFER_CONSOLE
       if (i == pdata->default_win) {
           s3cfb_check_var(&fbdev->fb[i]->var, fbdev->fb[i]);
           s3cfb_set_par(fbdev->fb[i]);
           s3cfb_draw_logo(fbdev->fb[i]);
       }
#endif
   }

   return 0;
}

你可能感兴趣的:(struct,video,interface,output,parallel,structure)