Linux驱动分析之Framebuffer驱动

简介: 前面我们了解了LCD的基本架构《Linux驱动分析之LCD驱动架构》,接下来我们拿个具体的实例来分析分析。这样可以了解其大概是如何使用和工作的。

 前言

   前面我们了解了LCD的基本架构《Linux驱动分析之LCD驱动架构》,接下来我们拿个具体的实例来分析分析。这样可以了解其大概是如何使用和工作的。


FrameBuffer驱动分析

内核版本:4.20

芯片平台:s3c2410

依然是使用之前的方式进行分析,大部分内容在注释。

(1)装载和卸载函数

staticstructplatform_drivers3c2410fb_driver= {
  .probe=s3c2410fb_probe,
  .remove=s3c2410fb_remove,
  .suspend=s3c2410fb_suspend,
  .resume=s3c2410fb_resume,
  .driver= {
    .name="s3c2410-lcd",
  },
};
int__inits3c2410fb_init(void)
{
intret=platform_driver_register(&s3c2410fb_driver);
returnret;
}
staticvoid__exits3c2410fb_cleanup(void)
{
platform_driver_unregister(&s3c2410fb_driver);
}
module_init(s3c2410fb_init);
module_exit(s3c2410fb_cleanup);

image.gif

上面比较简单,就是注册一个platform_driver, 控制器一般都是使用platform总线。

(2)probe()

staticints3c2410fb_probe(structplatform_device*pdev)
{
returns3c24xxfb_probe(pdev, DRV_S3C2410);
}
staticints3c24xxfb_probe(structplatform_device*pdev,
enums3c_drv_typedrv_type)
{
structs3c2410fb_info*info;
structs3c2410fb_display*display;
structfb_info*fbinfo;
structs3c2410fb_mach_info*mach_info;
structresource*res;
intret;
intirq;
inti;
intsize;
u32lcdcon1;
//获取板子配置信息mach_info=dev_get_platdata(&pdev->dev);
//省略......//display包含了屏幕的分辨率信息等display=mach_info->displays+mach_info->default_display;
//获取中断号irq=platform_get_irq(pdev, 0);
//分配一个fb_infofbinfo=framebuffer_alloc(sizeof(structs3c2410fb_info), &pdev->dev);
//保存fbinfo到driver dataplatform_set_drvdata(pdev, fbinfo);
info=fbinfo->par;
info->dev=&pdev->dev;
info->drv_type=drv_type;
//获取IO资源并申请res=platform_get_resource(pdev, IORESOURCE_MEM, 0);
size=resource_size(res);
info->mem=request_mem_region(res->start, size, pdev->name);
//映射为虚拟地址info->io=ioremap(res->start, size);
//获取中断基地址info->irq_base=info->io+S3C2410_LCDINTBASE;
strcpy(fbinfo->fix.id, driver_name);
//操作寄存器,停止LCDC输出lcdcon1=readl(info->io+S3C2410_LCDCON1);
writel(lcdcon1&~S3C2410_LCDCON1_ENVID, info->io+S3C2410_LCDCON1);
//初始化固定参数fbinfo->fix.type=FB_TYPE_PACKED_PIXELS;
fbinfo->fix.type_aux=0;
fbinfo->fix.xpanstep=0;
fbinfo->fix.ypanstep=0;
fbinfo->fix.ywrapstep=0;
fbinfo->fix.accel=FB_ACCEL_NONE;
//初始化可变参数fbinfo->var.nonstd=0;
fbinfo->var.activate=FB_ACTIVATE_NOW;
fbinfo->var.accel_flags=0;
fbinfo->var.vmode=FB_VMODE_NONINTERLACED;
//设置操作函数fbinfo->fbops=&s3c2410fb_ops;
fbinfo->flags=FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette=&info->pseudo_pal;
//清除画板for (i=0; i<256; i++)
info->palette_buffer[i] =PALETTE_BUFF_CLEAR;
//申请中断ret=request_irq(irq, s3c2410fb_irq, 0, pdev->name, info);
//获取时钟并使能info->clk=clk_get(NULL, "lcd");
clk_prepare_enable(info->clk);
usleep_range(1000, 1100);
info->clk_rate=clk_get_rate(info->clk);
/* 计算显示所需分配的内存大小 */for (i=0; i<mach_info->num_displays; i++) {
unsignedlongsmem_len=mach_info->displays[i].xres;
smem_len*=mach_info->displays[i].yres;
smem_len*=mach_info->displays[i].bpp;
smem_len>>=3;
if (fbinfo->fix.smem_len<smem_len)
fbinfo->fix.smem_len=smem_len;
  }
/* 初始化显存,这里面设置了DMA */ret=s3c2410fb_map_video_memory(fbinfo);
//根据屏幕信息初始化fbinfo中的可变参数fbinfo->var.xres=display->xres;
fbinfo->var.yres=display->yres;
fbinfo->var.bits_per_pixel=display->bpp;
//初始化LCDC相关寄存器s3c2410fb_init_registers(fbinfo);
//注册framebufferret=register_framebuffer(fbinfo);
return0;
}

image.gif

上面省略了一些错误判断。

上面总结下来就两个部分:

1. 根据屏幕信息填充fb_info, 然后调用register_framebuffer进行注册

2. LCDC相对应的寄存器的配置(硬件平台相关的)

(3)各种操作屏幕的函数

staticstructfb_opss3c2410fb_ops= {
  .owner=THIS_MODULE,
  .fb_check_var=s3c2410fb_check_var, //检查可变参数合法性  .fb_set_par=s3c2410fb_set_par, //设置可变参数  .fb_blank=s3c2410fb_blank, //设置开关屏  .fb_setcolreg=s3c2410fb_setcolreg, //设置颜色寄存器//下面三个都是使用内核自带的函数  .fb_fillrect=cfb_fillrect, //绘制矩形  .fb_copyarea=cfb_copyarea, //区域拷贝  .fb_imageblit=cfb_imageblit,//绘制位图};

image.gif

简单看几个函数,其实就是对寄存器的操作。

    • s3c2410fb_set_par
    static int s3c2410fb_set_par(struct fb_info *info)
    {
        //设置参数信息
      struct fb_var_screeninfo *var = &info->var;
      switch (var->bits_per_pixel) {
      case 32:
      case 16:
      case 12:
        info->fix.visual = FB_VISUAL_TRUECOLOR;
        break;
      case 1:
        info->fix.visual = FB_VISUAL_MONO01;
        break;
      default:
        info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
        break;
      }
      info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
        //设置寄存器,该函数中都是寄存器的操作
      s3c2410fb_activate_var(info);
      return 0;
    }

    image.gif

      • s3c2410fb_blank
      static int s3c2410fb_blank(int blank_mode, struct fb_info *info)
      {
        struct s3c2410fb_info *fbi = info->par;
        void __iomem *tpal_reg = fbi->io;
        dprintk("blank(mode=%d, info=%p)\n", blank_mode, info);
        tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;
          //根据开关设置寄存器
        if (blank_mode == FB_BLANK_POWERDOWN)
          s3c2410fb_lcd_enable(fbi, 0);
        else
          s3c2410fb_lcd_enable(fbi, 1);
        if (blank_mode == FB_BLANK_UNBLANK)
          writel(0x0, tpal_reg);
        else {
          dprintk("setting TPAL to output 0x000000\n");
          writel(S3C2410_TPAL_EN, tpal_reg);
        }
        return 0;
      }

      image.gif

      这些操作函数和裸机程序基本差不多,就是一些对寄存器的操作。


      总结

         上面其实没有多少内容,我们并不需要过多关注细节。比如寄存器配置的含义之类的,因为每个平台都不一样,即使你把这款芯片的所有细节理解了,换个平台,依然要重新来。所以我们应该理解的是框架。

         随着技术的发展,特别是GPU的出现,单纯使用Framebuffer来显示越来越少,它已经渐渐成为DRM的一部分了。特别是现在的Android设备, 对显示要求越来越高。后期会带来一些DRM相关的文章!

      相关文章
      |
      3月前
      |
      Linux 调度
      Linux 内核源代码情景分析(一)(下)
      Linux 内核源代码情景分析(一)
      50 1
      |
      3月前
      |
      存储 IDE Unix
      Linux 内核源代码情景分析(四)(上)
      Linux 内核源代码情景分析(四)
      26 1
      Linux 内核源代码情景分析(四)(上)
      |
      3月前
      |
      Java Linux API
      Linux设备驱动开发详解2
      Linux设备驱动开发详解
      41 6
      |
      3月前
      |
      存储 Linux 块存储
      Linux 内核源代码情景分析(三)(下)
      Linux 内核源代码情景分析(三)
      32 4
      |
      3月前
      |
      Linux C语言
      深度探索Linux操作系统 —— 编译过程分析
      深度探索Linux操作系统 —— 编译过程分析
      26 2
      |
      3月前
      |
      存储 Unix Linux
      Linux 内核源代码情景分析(四)(下)
      Linux 内核源代码情景分析(四)
      23 2
      |
      3月前
      |
      Linux 人机交互 调度
      Linux 内核源代码情景分析(二)(下)
      Linux 内核源代码情景分析(二)
      32 2
      |
      3月前
      |
      存储 Unix Linux
      Linux 内核源代码情景分析(二)(上)
      Linux 内核源代码情景分析(二)
      29 2
      |
      3月前
      |
      存储 Linux 程序员
      Linux 内核源代码情景分析(一)(上)
      Linux 内核源代码情景分析(一)
      52 1
      |
      2月前
      |
      存储 传感器 Linux
      STM32微控制器为何不适合运行Linux系统的分析
      总的来说,虽然技术上可能存在某些特殊情况下将Linux移植到高端STM32微控制器上的可能性,但从资源、性能、成本和应用场景等多个方面考虑,STM32微控制器不适合运行Linux系统。对于需要运行Linux的应用,更适合选择ARM Cortex-A系列处理器的开发平台。
      191 0