您的位置:首页 > 编程语言

分析rk代码中fb的加载及逻辑

2015-03-03 17:13 621 查看
fb先于lcdc加载。

fb_probe只是简单的加载一个platform设备fb,并将rk_fb_inf作为fb设备的私有数据。

 

lcdc设备加载:

根据芯片的配置,RK29中存在两个lcdc设备,分别为lcdc0和lcdc1,通过设备的id来区别。

static struct platform_devicedevice_lcdc0 = {

   .name     = "rk30-lcdc",

   .id       = 0,

   .num_resources     =ARRAY_SIZE(resource_lcdc0),

   .resource    = resource_lcdc0,

   .dev     = {

      .platform_data = &lcdc0_screen_info,

   },

};

static struct platform_devicedevice_lcdc1 = {

   .name     = "rk30-lcdc",

   .id       = 1,

   .num_resources     =ARRAY_SIZE(resource_lcdc1),

   .resource    = resource_lcdc1,

   .dev     = {

      .platform_data = &lcdc1_screen_info,

   },

};

lcdc0用作lcd显示,lcdc1用作hdmi。这些外接设备的控制方式通过lcdc设备的platform_data来设置,并且通过rk29fb_info中的.prop成员制定其中一个设备为主显示设备(primary),另一个为扩展显示设备(extend)

struct rk29fb_info lcdc0_screen_info= {

   .prop    = PRMRY,   //primary display device

   .io_init   = rk_fb_io_init,          //lcd

   .io_disable = rk_fb_io_disable,

   .io_enable = rk_fb_io_enable,

   .set_screen_info = set_lcd_info,

};

struct rk29fb_info lcdc1_screen_info= {

   .prop   = EXTEND,  //extend display device

   .lcd_info  = NULL,

   .set_screen_info = hdmi_init_lcdc,     //hdmi

};

其中的set_screen_info是对具体的外接显示设备进行配置。

 

lcdc设备probe中,rk自己定义了一个设备类型rk30_lcdc_device,rk30_lcdc_device相当于对platform_device的一个扩展,能够根据lcdc的特性,更详细地描述lcdc设备。rk30_lcdc_device中包含了外接设备的控制信息,并且定义了一个rk_screen结构体,这个结构体从screen的角度,描述lcdc对应的显示设备。

lcdc驱动中同时定义了rk30_lcdc_device设备对应的驱动程序rk_lcdc_device_driver。rk_lcdc_device_driver中定义了对lcdc操作的接口,开放给lcdc设备调用。

lcdc驱动中调用rk_fb_register将rk30_lcdc_device和rk_lcdc_device_driver链接起来,将设备注册到fb系统中。在此之前,通过set_screen_info先对外接显示设备进行了初始化。

每个lcdc中可能包含多个layer,目前rk30的lcdc 3个layer,这些信息都是在rk_lcdc_device_driver定义的。

rk_fb_register中,将lcdc的信息添加到rk_fb_inf结构体的lcdc_dev_drv数组成员中,rk_fb_inf最多可以支持4个lcdc。并且初始化lcdc及其各个layer。rk_fb_inf最多支持8个layer。

初始化lcdc之后,系统为lcdc的每个layer分配一个fb_info结构体来保存信息,但是只为lay0层分配buffer。之后为每个layer创建对应的sys操作接口。

以前这些完成后,如果执行rk_fb_register的lcdc是主显示设备(primary),则在此lcdc的外接显示设备上显示开机logo。

此后对于显示的所有操作,都是通过fb完成,fb再通过rk_lcdc_device_driver完成对lcdc的操作。

 

对应的流程:

fb probe:

static int __devinit rk_fb_probe(struct platform_device *pdev)

{

   struct rk_fb_inf *fb_inf = NULL;         
//定义一个描述fb信息的数据结构fb_inf

   ......

   fb_inf = kzalloc(sizeof(struct rk_fb_inf), GFP_KERNEL);

   ......

   platform_set_drvdata(pdev,fb_inf);      
//将fb_inf设备paltform_device的私有数据

   ......

}

 

lcdc probe:

static int __devinit rk30_lcdc_probe(struct platform_device *pdev)

{

   struct rk30_lcdc_device
*lcdc_dev=NULL;   //定义一个rk30_lcdc_device设备

   rk_screen *screen;                          
//定义一个描述screen的数据结构

   struct rk29fb_info *screen_ctr_info;     
//定义针对外接显示设备控制接口的数据结构

   ......

   platform_set_drvdata(pdev, lcdc_dev);       
//将rk30_lcdc_device设为platform_device的私有数据

 

   screen_ctr_info = (structrk29fb_info * )pdev->dev.platform_data;

   screen =  kzalloc(sizeof(rk_screen), GFP_KERNEL);

   ......

   /****************get lcdc0 reg *************************/

   lcdc_dev->id = pdev->id;

   res = platform_get_resource(pdev, IORESOURCE_MEM,0);

   ......

   lcdc_dev->reg_phy_base = res->start;

   lcdc_dev->len = resource_size(res);

   mem =request_mem_region(lcdc_dev->reg_phy_base, resource_size(res),pdev->name);

   ......

   lcdc_dev->reg_vir_base =ioremap(lcdc_dev->reg_phy_base, resource_size(res));

   ......

   lcdc_dev->regs = lcdc_dev->reg_vir_base;

   lcdc_dev->regsbak = kzalloc(lcdc_dev->len,GFP_KERNEL);

   lcdc_dev->dsp_lut_addr_base = (lcdc_dev->regs +DSP_LUT_ADDR);

   lcdc_dev->driver.dev=&pdev->dev;

   lcdc_dev->driver.screen0 = screen;

   lcdc_dev->driver.cur_screen = screen;

   lcdc_dev->driver.screen_ctr_info = screen_ctr_info;

   lcdc_dev->irq = platform_get_irq(pdev, 0);

   ret = request_irq(lcdc_dev->irq, rk30_lcdc_isr,IRQF_DISABLED,dev_name(&pdev->dev),lcdc_dev);

//以上均为填充rk30_lcdc_device设备的数据

   if(screen_ctr_info->set_screen_info)

   {

      screen_ctr_info->set_screen_info(screen,screen_ctr_info->lcd_info);

      if(SCREEN_NULL==screen->type)

      {

         printk(KERN_WARNING "no display device onlcdc%d!?\n",lcdc_dev->id);

        ret = -ENODEV;

      }

      if(screen_ctr_info->io_init)

        screen_ctr_info->io_init(NULL);

   }       //外接显示设备的初始化

   ...  

   ret = rk_fb_register(&(lcdc_dev->driver),&lcdc_driver,lcdc_dev->id);

   ......

}

 

static struct layer_par lcdc_layer[] = {     //lcdc的三个layer的配置

   [0] = {

      .name      ="win0",

      .id     = 0,

      .support_3d = true,

   },

   [1] = {

      .name      ="win1",

      .id     = 1,

      .support_3d = false,

   },

   [2] = {

      .name      ="win2",

      .id     = 2,

      .support_3d = false,

   },

};

 

static struct rk_lcdc_device_driverlcdc_driver = {    
//定义rk30_lcdc_device设备的驱动driver

   .name      = "lcdc",

   .def_layer_par      = lcdc_layer,

   .num_layer    = ARRAY_SIZE(lcdc_layer),

   .open      = rk30_lcdc_open,

   .init_lcdc    = rk30_lcdc_init,

   .ioctl        = rk30_lcdc_ioctl,

   .suspend   = rk30_lcdc_early_suspend,

   .resume       = rk30_lcdc_early_resume,

   .set_par            =rk30_lcdc_set_par,

   .blank               =rk30_lcdc_blank,

   .pan_display            = rk30_lcdc_pan_display,

   .load_screen     = rk30_load_screen,

   .get_layer_state = rk30_lcdc_get_layer_state,

   .ovl_mgr   = rk30_lcdc_ovl_mgr,

   .get_disp_info      = rk30_lcdc_get_disp_info,

   .fps_mgr   = rk30_lcdc_fps_mgr,

   .fb_get_layer           = rk30_fb_get_layer,

   .fb_layer_remap         = rk30_fb_layer_remap,

   .set_dsp_lut            = rk30_set_dsp_lut,

   .read_dsp_lut           = rk30_read_dsp_lut,

};

 

上面的rk_fb_register(&(lcdc_dev->driver),&lcdc_driver,lcdc_dev->id)就是讲rk30_lcdc_device与rk_lcdc_device_driver建立连接,将rk30_lcdc_device的driver成员指向rk_lcdc_device_driver。

 

int rk_fb_register(structrk_lcdc_device_driver *dev_drv,

   struct rk_lcdc_device_driver*def_drv,int id)

{

   struct rk_fb_inf *fb_inf =platform_get_drvdata(g_fb_pdev);//获取fb描述信息的数据结构

   struct fb_info *fbi;

   int lcdc_id = 0;

   for(i=0;i<RK30_MAX_LCDC_SUPPORT;i++) //可以保存多个lcdc

   {

      if(NULL==fb_inf->lcdc_dev_drv[i])

      {

        fb_inf->lcdc_dev_drv[i]= dev_drv;

        fb_inf->lcdc_dev_drv[i]->id= id;

        fb_inf->num_lcdc++;

        break;

      }

   }

   ......

   lcdc_id = i;

   init_lcdc_device_driver(dev_drv,def_drv,id);     //将rk_lcdc_device_driver中的api赋给rk30_lcdc_device中对应的操作接口,并对部分数据设置进行初始化.

  

   dev_drv->init_lcdc(dev_drv);   //硬件初始化LCDC

   /************fb set,one layerone fb ***********/

   dev_drv->fb_index_base =fb_inf->num_fb;

   for(i=0;i<dev_drv->num_layer;i++)               //每个lcdc存在多个layer

   {

      fbi= framebuffer_alloc(0,&g_fb_pdev->dev);     //为每个layer分配一个fb_info

      if(!fbi)

      {

        dev_err(&g_fb_pdev->dev,">>fb framebuffer_alloc fail!");

        fbi = NULL;

        ret = -ENOMEM;

      }

      fbi->par = dev_drv;

      fbi->var = def_var;

      fbi->fix = def_fix;

      sprintf(fbi->fix.id,"fb%d",fb_inf->num_fb);

      fbi->var.xres =fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->x_res;

      fbi->var.yres =fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->y_res;

      fbi->var.grayscale |=(fbi->var.xres<<8) + (fbi->var.yres<<20);

#ifdef  CONFIG_LOGO_LINUX_BMP

      fbi->var.bits_per_pixel =32;

#else

      fbi->var.bits_per_pixel =16;

#endif

      fbi->fix.line_length  =(fbi->var.xres)*(fbi->var.bits_per_pixel>>3);

      fbi->var.xres_virtual =fbi->var.xres;

      fbi->var.yres_virtual =fbi->var.yres;

      fbi->var.width = fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->width;

      fbi->var.height =fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->height;

      fbi->var.pixclock =fb_inf->lcdc_dev_drv[lcdc_id]->pixclock;

      fbi->var.left_margin =fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->left_margin;

      fbi->var.right_margin =fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->right_margin;

      fbi->var.upper_margin =fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->upper_margin;

      fbi->var.lower_margin = fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->lower_margin;

      fbi->var.vsync_len =fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->vsync_len;

      fbi->var.hsync_len =fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->hsync_len;

      fbi->fbops       = &fb_ops;

      fbi->flags       = FBINFO_FLAG_DEFAULT;

      fbi->pseudo_palette  =fb_inf->lcdc_dev_drv[lcdc_id]->layer_par[i]->pseudo_pal;

      if (i == 0) //only allocmemory for main fb

      {

        rk_request_fb_buffer(fbi,fb_inf->num_fb);       //只为layer0分配Buffer

      }

      ret =register_framebuffer(fbi);                     //注册到fbmem

      if(ret<0)

      {

        printk("%s>>fb%dregister_framebuffer fail!\n",__func__,fb_inf->num_fb);

        ret = -EINVAL;

      }

      rkfb_create_sysfs(fbi);                              //创建sys接口

 

      if(i == 0)

      {

        init_waitqueue_head(&dev_drv->vsync_info.wait);

        ret =device_create_file(fbi->dev,&dev_attr_vsync);

        if (ret)

        {

           dev_err(fbi->dev,"failed to create vsync file\n");

        }

        dev_drv->vsync_info.thread= kthread_run(rk_fb_wait_for_vsync_thread,

           dev_drv,"fb-vsync");

       

        if (dev_drv->vsync_info.thread== ERR_PTR(-ENOMEM))

        {

           dev_err(fbi->dev,"failed to run vsync thread\n");

           dev_drv->vsync_info.thread= NULL;

        }

        dev_drv->vsync_info.active= 1;

      }

      fb_inf->fb[fb_inf->num_fb]= fbi;

      printk("%s>>>>>%s\n",__func__,fb_inf->fb[fb_inf->num_fb]->fix.id);

      fb_inf->num_fb++;  

   }

   if(dev_drv->screen_ctr_info->prop == PRMRY) //show logo for primary displaydevice

    {

      fb_inf->fb[0]->fbops->fb_open(fb_inf->fb[0],1);

      fb_inf->fb[0]->fbops->fb_set_par(fb_inf->fb[0]);

 

      if(fb_prepare_logo(fb_inf->fb[0], FB_ROTATE_UR)) {

        /* Start display and showlogo on boot */

         fb_set_cmap(&fb_inf->fb[0]->cmap, fb_inf->fb[0]);

         fb_show_logo(fb_inf->fb[0], FB_ROTATE_UR);

         fb_inf->fb[0]->fbops->fb_pan_display(&(fb_inf->fb[0]->var),fb_inf->fb[0]);

      }

    fb_inf->fb[0]->fbops->fb_ioctl(fb_inf->fb[0],RK_FBIOSET_CONFIG_DONE,NULL);      

    }

    return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android rk fb lcdc