Chinaunix首页 | 论坛 | 博客
  • 博客访问: 51384
  • 博文数量: 17
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 70
  • 用 户 组: 普通用户
  • 注册时间: 2014-11-09 22:49
文章分类
文章存档

2015年(9)

2014年(8)

我的朋友

分类: LINUX

2014-12-01 19:12:41

以下是驱动解析,drivers/video/samsung/s3cfb.c

点击(此处)折叠或打开

  1. static struct platform_driver s3cfb_driver = {
  2.     .probe        = s3cfb_probe,
  3.     .remove        = s3cfb_remove,
  4.     .suspend    = s3cfb_suspend,
  5.     .resume        = s3cfb_resume,
  6.         .driver        = {
  7.         .name    = "s3c-fb",
  8.         .owner    = THIS_MODULE,
  9.     },
  10. };

  11. int __devinit s3cfb_init(void)
  12. {
  13.        /* 模块加载函数实现平台驱动的注册 */
  14.     return platform_driver_register(&s3cfb_driver);
  15. }
  16. static void __exit s3cfb_cleanup(void)
  17. {
  18.     platform_driver_unregister(&s3cfb_driver);
  19. }

  20. module_init(s3cfb_init);
  21. module_exit(s3cfb_cleanup);
    s3cfb_probe平台驱动的探测函数,主要初始化fb_info结构体中的可变参数和不可变参数结构体,LCD硬件控制器的初始化,获取时钟来源,显示缓存空间的申请,注册帧缓冲设备等工作。
点击(此处)折叠或打开
  1. static int __init s3cfb_probe(struct platform_device *pdev)
  2. {
  3.     /* 定义局部变量 */
  4.     struct resource *res;    /* 用于保存platform_device需要的平台资源 */
  5.     struct fb_info *fbinfo;  /* 描述frambuffer驱动的结构 */
  6.     s3cfb_info_t *info;      /* 保存LCD驱动的相关信息 */

  7.     char driver_name[] = "s3cfb";/* 驱动的名字 */
  8.     int index = 0, ret, size; /*  */

  9.     /* 分配s3cfb_info_t结构体空间 */
  10.     fbinfo = framebuffer_alloc(sizeof(s3cfb_info_t), &pdev->dev);

  11.     if (!fbinfo)
  12.         return -ENOMEM;

  13.     /* 保存为pdev的私有数据pdev->p->driver_data = data */
  14.     platform_set_drvdata(pdev, fbinfo);    

  15.     info = fbinfo->par;
  16.     info->dev = &pdev->dev;

  17.     /* 获取平台设备所需要的资源,这些资源一般在bsp文件中被赋值 */
  18.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0)

  19.     if (res == NULL) {
  20.         dev_err(&pdev->dev, "failed to get memory registers\n");
  21.         ret = -ENXIO;
  22.         goto dealloc_fb;
  23.     }

  24.     size = (res->end - res->start) + 1;    /* 计算资源大小 */
  25.     /* 为IO资源分配内存,如果分配成功返回非NULL */
  26.     info->mem = request_mem_region(res->start, size, pdev->name);    

  27.     if (info->mem == NULL) {
  28.         dev_err(&pdev->dev, "failed to get memory region\n");
  29.         ret = -ENOENT;
  30.         goto dealloc_fb;
  31.     }

  32.     info->io = ioremap(res->start, size);    /* 将IO内存地址映射成虚拟空间地址 */

  33.     if (info->io == NULL) {
  34.         dev_err(&pdev->dev, "ioremap() of registers failed\n");
  35.         ret = -ENXIO;
  36.         goto release_mem;
  37.     }

  38.     s3cfb_pre_init();            /* 初始化视频中断寄存器VIDINTCON0,并使能 */
  39.     s3cfb_set_backlight_power(1);/* 设置背光电源 */
  40.     s3cfb_set_lcd_power(1);      /* LCD上电 */
  41.     s3cfb_set_backlight_level(S3CFB_DEFAULT_BACKLIGHT_LEVEL);/* 设置背光亮度为默认亮度*/

  42.     info->clk = clk_get(NULL, "lcd");  /* 获取时钟 */

  43.     if (!info->clk || IS_ERR(info->clk)) {
  44.         printk(KERN_INFO "failed to get lcd clock source\n");
  45.         ret = -ENOENT;
  46.         goto release_io;
  47.     }

  48.     clk_enable(info->clk);            /* 使能时钟 */
  49.     printk("S3C_LCD clock got enabled :: %ld.%03ld Mhz\n", PRINT_MHZ(clk_get_rate(info->clk)));

  50.     s3cfb_fimd.vsync_info.count = 0;  /* 初始化帧同步信号等待序列 */
  51.     init_waitqueue_head(&s3cfb_fimd.vsync_info.wait_queue);

  52.     /* 获取中断资源 */
  53.     res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

  54.     if (res == NULL) {
  55.         dev_err(&pdev->dev, "failed to get irq\n");
  56.         ret = -ENXIO;
  57.         goto release_clock;
  58.     }

  59.     ret = request_irq(res->start, s3cfb_irq, 0, "s3c-lcd", pdev);  /* 申请中断 */

  60.     if (ret != 0) {
  61.         printk("Failed to install irq (%d)\n", ret);
  62.         goto release_clock;
  63.     }

  64.     msleep(5);

  65.     /* s3c6410 LCD支持多种屏幕,控制器一共有5个窗口,每一个窗口都可以看成是一个frambuffer设备 */
  66.     /*  这个s3cfb_info就是一个s3cfb_info_t类型的数组,每一款LCD对应着一个索引 */
  67.     for (index = 0; index < S3CFB_NUM; index++) {
  68.         /* 上面获取了IO内存,映射了IO,获取到了时钟等,这里用来填充这个s3cfb_info结构 */
  69.         s3cfb_info[index].mem = info->mem;
  70.         s3cfb_info[index].io = info->io;
  71.         s3cfb_info[index].clk = info->clk;

  72.         s3cfb_init_fbinfo(&s3cfb_info[index], driver_name, index);
  73.         /* Initialize video memory */
  74.         ret = s3cfb_map_video_memory(&s3cfb_info[index]);

  75.         if (ret) {
  76.             printk("Failed to allocate video RAM: %d\n", ret);
  77.             ret = -ENOMEM;
  78.             goto release_irq;
  79.         }
  80.         ret = s3cfb_init_registers(&s3cfb_info[index]);
  81.         ret = s3cfb_check_var(&s3cfb_info[index].fb.var, &s3cfb_info[index].fb);

  82.         if (index < 2){
  83.             if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 256, 0) < 0)
  84.                 goto dealloc_fb;
  85.         } else {
  86.             if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 16, 0) < 0)
  87.                 goto dealloc_fb;
  88.         }

  89.         /* 注册帧缓冲设备(FrameBuffer)fb_info到系统当中 */
  90.         ret = register_framebuffer(&s3cfb_info[index].fb);

  91.         if (ret < 0) {
  92.             printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret);
  93.             goto free_video_memory;
  94.         }

  95.         printk(KERN_INFO "fb%d: %s frame buffer device\n", s3cfb_info[index].fb.node, s3cfb_info[index].fb.fix.id);
  96.     }

  97.     /* create device files */
  98.     /* 每一个设备它都有自己的属性,每一个属性都对应着一个文件 */
  99.     ret = device_create_file(&(pdev->dev), &dev_attr_backlight_power);

  100.     if (ret < 0)
  101.         printk(KERN_WARNING "s3cfb: failed to add entries\n");

  102.     ret = device_create_file(&(pdev->dev), &dev_attr_backlight_level);

  103.     if (ret < 0)
  104.         printk(KERN_WARNING "s3cfb: failed to add entries\n");

  105.     ret = device_create_file(&(pdev->dev), &dev_attr_lcd_power);

  106.     if (ret < 0)
  107.         printk(KERN_WARNING "s3cfb: failed to add entries\n");

  108.     return 0;

  109. /* 以下是一些错误处理函数 */
  110. free_video_memory:
  111.     s3cfb_unmap_video_memory(&s3cfb_info[index]);

  112. release_irq:
  113.     free_irq(res->start, &info);

  114. release_clock:
  115.     clk_disable(info->clk);
  116.     clk_put(info->clk);

  117. release_io:
  118.     iounmap(info->io);

  119. release_mem:
  120.     release_resource(info->mem);
  121.     kfree(info->mem);

  122. dealloc_fb:
  123.     framebuffer_release(fbinfo);
  124.     return ret;
  125. }
    接着对probe中所调用的函数从上到下一次分析:
点击(此处)折叠或打开
  1. /* 初始化LCD视频中断控制寄存器0 */
  2. void s3cfb_pre_init(void)
  3. {
  4.     /* initialize the fimd specific */
  5.     s3cfb_fimd.vidintcon0 &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;
  6.     s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;
  7.     s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_INTFRMEN_ENABLE;
  8.     /* 详情请看S3C6410数据手册第14章482页。。初始化视频中断以VSYNS开始并使能该寄存器 */
  9.     writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);
  10. }
    下面这三个是控制LCD电源以及背光控制的

点击(此处)折叠或打开

  1. /* LCD背光电源控制 */
  2. static void s3cfb_set_backlight_power(int to)
  3. {
  4.     s3cfb_fimd.backlight_power = to;

  5.     if (s3cfb_fimd.set_backlight_power)
  6.         (s3cfb_fimd.set_backlight_power)(to);
  7. }
  8. /* LCD电源控制 */
  9. static void s3cfb_set_lcd_power(int to)
  10. {
  11.     s3cfb_fimd.lcd_power = to;

  12.     if (s3cfb_fimd.set_lcd_power)
  13.         (s3cfb_fimd.set_lcd_power)(to);
  14. }
  15. /* LCD背光亮度调节 */
  16. static void s3cfb_set_backlight_power(int to)
  17. {
  18.     s3cfb_fimd.backlight_power = to;

  19.     if (s3cfb_fimd.set_backlight_power)
  20.         (s3cfb_fimd.set_backlight_power)(to);
  21. }
    该函数在probe中被调用就是用来填充各种结构中的成员变量的它们的具体实现在s3cfb_fimd4x.c

点击(此处)折叠或打开

  1. static void s3cfb_init_fbinfo(s3cfb_info_t *finfo, char *drv_name, int index)
  2. {
  3.     int i = 0;

  4.     if (index == 0)
  5.     {
  6.         if(lcdsize == 0)        /* lcdsize是一全局变量用来标记LCD所使用的尺寸 */
  7.             s3cfb_init_hw_35();
  8.         else if(lcdsize == 1)   /*初始化4.3寸液晶显示器 */
  9.             s3cfb_init_hw_43();
  10.         else if(lcdsize == 2)
  11.             s3cfb_init_hw_56();
  12.         else if(lcdsize == 3)
  13.             s3cfb_init_hw_70();
  14.         else if(lcdsize == 4)
  15.             s3cfb_init_hw_vga800();
  16.         else if(lcdsize == 5)
  17.             s3cfb_init_hw_xga1024();
  18.         else
  19.             s3cfb_init_hw_43();    
  20.     }

  21.     strcpy(finfo->fb.fix.id, drv_name);         /* 初始化不可变参数结构中的char id[16]数组 */
  22.     /* 将窗口索引传入,一共是5个窗口 */
  23.     finfo->win_id = index;    
  24.     finfo->fb.fix.type = FB_TYPE_PACKED_PIXELS; /* 使用默认类型,其余还有VGA */
  25.     finfo->fb.fix.type_aux = 0;
  26.     finfo->fb.fix.xpanstep = 0;
  27.     finfo->fb.fix.ypanstep = 1;
  28.     finfo->fb.fix.ywrapstep = 0;
  29.     finfo->fb.fix.accel = FB_ACCEL_NONE;        /* 无硬件加速  */

  30.     finfo->fb.fbops = &s3cfb_ops;
  31.     finfo->fb.flags    = FBINFO_FLAG_DEFAULT;

  32.     finfo->fb.pseudo_palette = &finfo->pseudo_pal;/* 16位颜色表 */
  33.     /* 给可变参数赋值 */
  34.     finfo->fb.var.nonstd = 0;                   /* 像素格式,0代表标准像素格式,!0代表非标准像素格式 */
  35.     finfo->fb.var.activate = FB_ACTIVATE_NOW;
  36.     finfo->fb.var.accel_flags = 0;              /* (OBSOLETE) see fb_info.flags */
  37.     finfo->fb.var.vmode = FB_VMODE_NONINTERLACED;
  38.     
  39.     /* 下面就是设置LCD分辨率了,具体的取值情况还要结合数据手册,不过这些默认值在s3cfb_fimd4x.c文件中已经有了,当然了这个文件从官方下载下来的源代码是没有的,这三星提供的吧 */
  40.     finfo->fb.var.xoffset = s3cfb_fimd.xoffset;    /* 水平方向虚拟到可见之间的偏移 */
  41.     finfo->fb.var.yoffset = s3cfb_fimd.yoffset;    /* 垂直方向虚拟到可见之间的偏移 */

  42.     if (index == 0) {
  43.         finfo->fb.var.height = s3cfb_fimd.height;  /*屏幕高度 */
  44.         finfo->fb.var.width = s3cfb_fimd.width;    /*屏幕宽度 */

  45.         finfo->fb.var.xres = s3cfb_fimd.xres;      /* 水平可视 */
  46.         finfo->fb.var.yres = s3cfb_fimd.yres;      /* 垂直可视 */

  47.         finfo->fb.var.xres_virtual = s3cfb_fimd.xres_virtual;/* 与之对应的虚拟分辨率-水平 */
  48.         finfo->fb.var.yres_virtual = s3cfb_fimd.yres_virtual;/* 与之对应的虚拟分辨率-垂直 */
  49. /********这里用文字表达一下:fb_var_screeninfo中的成员变量xres和yres是指在显示屏上真是显示的频率。而xres_virtual和yres_virtual是虚拟分辨率,它们是指显存的分辨率。举个例子假如LCD垂直分辨率是400,而虚拟分辨率是800,这就是说在显存    中是存储着800行要显示的,但是实际上显示器每次只能显示400行,至于具体需要显示那些行还需要fb_var_screeninfo中的另一个变量yoffset,若yoffset=0则从0行开始显示400行,n=20则从显存21行开始显示400行。**********/
  50.     } else {
  51.         finfo->fb.var.height = s3cfb_fimd.osd_height;
  52.         finfo->fb.var.width = s3cfb_fimd.osd_width;

  53.         finfo->fb.var.xres = s3cfb_fimd.osd_xres;
  54.         finfo->fb.var.yres = s3cfb_fimd.osd_yres;

  55.         finfo->fb.var.xres_virtual = s3cfb_fimd.osd_xres_virtual;
  56.         finfo->fb.var.yres_virtual = s3cfb_fimd.osd_yres_virtual;
  57.     }

  58.     /* 下面这些就与具体的时序有关了 */
  59.     finfo->fb.var.bits_per_pixel = s3cfb_fimd.bpp;        /* 每一像素的位数 */
  60.     finfo->fb.var.pixclock = s3cfb_fimd.pixclock;         /* 像素时钟、单位(ps) */
  61.     finfo->fb.var.hsync_len = s3cfb_fimd.hsync_len;       /* 行同步信号宽度,用VCLK计算,对应时序图中HSPW */
  62.     finfo->fb.var.left_margin = s3cfb_fimd.left_margin;   /* 行切换:同步到绘图之间的延迟,对应HBPD */
  63.     finfo->fb.var.right_margin = s3cfb_fimd.right_margin; /* 行切换:绘图到同步之间的延迟,对应HFPD*/
  64.     finfo->fb.var.vsync_len = s3cfb_fimd.vsync_len;       /* 帧同步信号长度,对应VSPW */
  65.     finfo->fb.var.upper_margin = s3cfb_fimd.upper_margin; /* 帧切换:同步到绘图之间的延迟,对应VBPD */
  66.     finfo->fb.var.lower_margin = s3cfb_fimd.lower_margin; /* 帧切换:绘图到同步之间的延迟,对应VFPD */
  67.     finfo->fb.var.sync = s3cfb_fimd.sync;
  68.     finfo->fb.var.grayscale = s3cfb_fimd.cmap_grayscale;  /* 灰度 */

  69.     finfo->fb.fix.smem_len = finfo->fb.var.xres_virtual * finfo->fb.var.yres_virtual * s3cfb_fimd.bytes_per_pixel;    /* fb缓冲区内存的字节数 */
  70.     finfo->fb.fix.line_length = finfo->fb.var.width * s3cfb_fimd.bytes_per_pixel;    /* 一行的字节数 */   

  71. #if !defined(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)

  72. #if defined(CONFIG_FB_S3C_EXT_DOUBLE_BUFFERING)
  73.     if (index < 2)
  74.         finfo->fb.fix.smem_len *= 2;    /* 缓冲区长度 */
  75. #else
  76.     /*
  77.     * Some systems(ex. DirectFB) use FB0 memory as a video memory.
  78.     * You can modify the size of multiple.
  79.     *
  80.     * !WARN: smem_len*5 may break the probe for 1024*768
  81.     */
  82.     if (index == 0)
  83.         finfo->fb.fix.smem_len *= 5;
  84. #endif

  85. #endif
  86.     /* 初始化色调色板(颜色表)为空 */
  87.     for (= 0; i < 256; i++)
  88.         finfo->palette_buffer[i] = S3CFB_PALETTE_BUFF_CLEAR;
  89. }
    在probe函数中调用了该函数为显存分配内存

点击(此处)折叠或打开

  1. static int __init s3cfb_map_video_memory(s3cfb_info_t *fbi)
  2. {
  3.     DPRINTK("map_video_memory(fbi=%p)\n", fbi);

  4.     /* 获取framebuffer缓存的大小,并进行页对齐 */
  5.     fbi->map_size_f1 = PAGE_ALIGN(fbi->fb.fix.smem_len);
  6.     /* 因为系统采用DMA来搬移显示数据,所以使用dma_alloc_writecombine来分配一段writecombine区域 */
  7.     fbi->map_cpu_f1 = dma_alloc_writecombine(fbi->dev, fbi->map_size_f1, &fbi->map_dma_f1, GFP_KERNEL);    /* 分配内存,分配可供DMA使用的地址,fbi->map_cpu_f1为虚拟地址,fbi->map_dma_f1为物理地址 */
  8.     fbi->map_size_f1 = fbi->fb.fix.smem_len; /* 恢复真实的大小 */

  9.     if (fbi->map_cpu_f1) {
  10.         /* prevent initial garbage on screen */
  11.         printk("Window[%d] - FB1: map_video_memory: clear %p:%08x\n",
  12.             fbi->win_id, fbi->map_cpu_f1, fbi->map_size_f1);
  13.         /* 使用之前先初始化,以防止缓存中的一些无效数据信息显示到LCD上 */
  14.         memset(fbi->map_cpu_f1, 0xf0, fbi->map_size_f1);
  15.         /**********DMA搬迁数据*****************/
  16.         fbi->screen_dma_f1 = fbi->map_dma_f1;           /* 物理地址 */
  17.         fbi->fb.screen_base = fbi->map_cpu_f1;          /* 虚拟地址 */
  18.         fbi->fb.fix.smem_start = fbi->screen_dma_f1;    /* 物理地址 */
  19.         printk(" FB1: map_video_memory: dma=%08x cpu=%p size=%08x\n",
  20.             fbi->map_dma_f1, fbi->map_cpu_f1, fbi->fb.fix.smem_len);
  21.     }

  22.     if (!fbi->map_cpu_f1)
  23.         return -ENOMEM;

  24. #if defined(CONFIG_FB_S3C_EXT_DOUBLE_BUFFERING)
  25.     if (fbi->win_id < 2 && fbi->map_cpu_f1) {
  26.         fbi->map_size_f2 = (fbi->fb.fix.smem_len / 2);
  27.         fbi->map_cpu_f2 = fbi->map_cpu_f1 + fbi->map_size_f2;
  28.         fbi->map_dma_f2 = fbi->map_dma_f1 + fbi->map_size_f2;

  29.         /* prevent initial garbage on screen */
  30.         printk("Window[%d] - FB2: map_video_memory: clear %p:%08x\n",
  31.             fbi->win_id, fbi->map_cpu_f2, fbi->map_size_f2);

  32.         fbi->screen_dma_f2 = fbi->map_dma_f2;

  33.         printk(" FB2: map_video_memory: dma=%08x cpu=%p size=%08x\n",
  34.             fbi->map_dma_f2, fbi->map_cpu_f2, fbi->map_size_f2);
  35.     }
  36. #endif

  37.     if (s3cfb_fimd.map_video_memory)
  38.         (s3cfb_fimd.map_video_memory)(fbi);

  39.     return 0;
  40. }
     初始化LCD控制寄存器:

点击(此处)折叠或打开

  1. int s3cfb_init_registers(s3cfb_info_t *fbi)
  2. {
  3.     struct clk *lcd_clock;
  4.     struct fb_var_screeninfo *var = &fbi->fb.var;
  5.     unsigned long flags = 0, page_width = 0, offset = 0;
  6.     unsigned long video_phy_temp_f1 = fbi->screen_dma_f1;    /* frambuffer物理地址 */
  7.     unsigned long video_phy_temp_f2 = fbi->screen_dma_f2;    /* frambuffer物理地址 */
  8.     int win_num = fbi->win_id;       /* 5个窗口 */

  9.     /* Initialise LCD with values from here */
  10.     local_irq_save(flags);

  11.     page_width = var->xres * s3cfb_fimd.bytes_per_pixel;    /* 显示宽度,以字节为单位 */
  12.     offset = (var->xres_virtual - var->xres) * s3cfb_fimd.bytes_per_pixel;/* 虚拟到可见区域的偏移量,以字节为单位 */
  13.     if (win_num == 0) {
  14.         s3cfb_fimd.vidcon0 = s3cfb_fimd.vidcon0 & ~(S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE);    /* 配置LCD控制器之前需要先关闭LCD视频输出 */
  15.         writel(s3cfb_fimd.vidcon0, S3C_VIDCON0);

  16.         lcd_clock = clk_get(NULL, "lcd");                   /* 获取LCD时钟 */
  17.         s3cfb_fimd.vidcon0 |= S3C_VIDCON0_CLKVAL_F((int) ((clk_get_rate(lcd_clock) / s3cfb_fimd.pixclock) - 1));/* 计算VCLK = lcd_clock / (CLKVAL+1) */
  18. #if defined(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)
  19.         offset = 0;                                         /* 将虚拟到可见区域的偏移量设置成0 */
  20.         s3cfb_fimd.vidw00add0b0 = video_phy_temp_f1;
  21.         s3cfb_fimd.vidw00add0b1 = video_phy_temp_f2;
  22.         s3cfb_fimd.vidw00add1b0 = S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f1 + (page_width + offset) * (var->yres));
  23.         s3cfb_fimd.vidw00add1b1 = S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f2 + (page_width + offset) * (var->yres));
  24. #endif
  25.      }
  26.     /* 各窗口起始地址 */
  27.     writel(video_phy_temp_f1, S3C_VIDW00ADD0B0 + (0x08 * win_num));
  28.     /* 各窗口结束地址 */
  29.     writel(S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f1 + (page_width + offset) * (var->yres)), S3C_VIDW00ADD1B0 + (0x08 * win_num));
  30.     /* 各虚拟窗口尺寸 */
  31.     writel(S3C_VIDWxxADD2_OFFSIZE_F(offset) | (S3C_VIDWxxADD2_PAGEWIDTH_F(page_width)), S3C_VIDW00ADD2 + (0x04 * win_num));

  32.     if (win_num < 2) {
  33.         writel(video_phy_temp_f2, S3C_VIDW00ADD0B1 + (0x08 * win_num));
  34.         writel(S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f2 + (page_width + offset) * (var->yres)), S3C_VIDW00ADD1B1 + (0x08 * win_num));
  35.     }

  36.     /* 将配置好的值都写入个寄存器当中 */
  37.     switch (win_num) {
  38.     case 0:
  39.         writel(s3cfb_fimd.wincon0, S3C_WINCON0);
  40.         writel(s3cfb_fimd.vidcon0, S3C_VIDCON0);
  41.         writel(s3cfb_fimd.vidcon1, S3C_VIDCON1);
  42.         writel(s3cfb_fimd.vidtcon0, S3C_VIDTCON0);
  43.         writel(s3cfb_fimd.vidtcon1, S3C_VIDTCON1);
  44.         writel(s3cfb_fimd.vidtcon2, S3C_VIDTCON2);
  45.         writel(s3cfb_fimd.dithmode, S3C_DITHMODE);
  46.         writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);
  47.         writel(s3cfb_fimd.vidintcon1, S3C_VIDINTCON1);
  48.         writel(s3cfb_fimd.vidosd0a, S3C_VIDOSD0A);
  49.         writel(s3cfb_fimd.vidosd0b, S3C_VIDOSD0B);
  50.         writel(s3cfb_fimd.vidosd0c, S3C_VIDOSD0C);
  51.         writel(s3cfb_fimd.wpalcon, S3C_WPALCON);

  52.         s3cfb_onoff_win(fbi, ON);
  53.         break;

  54.     case 1:
  55.         writel(s3cfb_fimd.wincon1, S3C_WINCON1);
  56.         writel(s3cfb_fimd.vidosd1a, S3C_VIDOSD1A);
  57.         writel(s3cfb_fimd.vidosd1b, S3C_VIDOSD1B);
  58.         writel(s3cfb_fimd.vidosd1c, S3C_VIDOSD1C);
  59.         writel(s3cfb_fimd.vidosd1d, S3C_VIDOSD1D);
  60.         writel(s3cfb_fimd.wpalcon, S3C_WPALCON);

  61.         s3cfb_onoff_win(fbi, OFF);
  62.         break;

  63.     case 2:
  64.         writel(s3cfb_fimd.wincon2, S3C_WINCON2);
  65.         writel(s3cfb_fimd.vidosd2a, S3C_VIDOSD2A);
  66.         writel(s3cfb_fimd.vidosd2b, S3C_VIDOSD2B);
  67.         writel(s3cfb_fimd.vidosd2c, S3C_VIDOSD2C);
  68.         writel(s3cfb_fimd.vidosd2d, S3C_VIDOSD2D);
  69.         writel(s3cfb_fimd.wpalcon, S3C_WPALCON);

  70.         s3cfb_onoff_win(fbi, OFF);
  71.         break;

  72.     case 3:
  73.         writel(s3cfb_fimd.wincon3, S3C_WINCON3);
  74.         writel(s3cfb_fimd.vidosd3a, S3C_VIDOSD3A);
  75.         writel(s3cfb_fimd.vidosd3b, S3C_VIDOSD3B);
  76.         writel(s3cfb_fimd.vidosd3c, S3C_VIDOSD3C);
  77.         writel(s3cfb_fimd.wpalcon, S3C_WPALCON);

  78.         s3cfb_onoff_win(fbi, OFF);
  79.         break;

  80.     case 4:
  81.         writel(s3cfb_fimd.wincon4, S3C_WINCON4);
  82.         writel(s3cfb_fimd.vidosd4a, S3C_VIDOSD4A);
  83.         writel(s3cfb_fimd.vidosd4b, S3C_VIDOSD4B);
  84.         writel(s3cfb_fimd.vidosd4c, S3C_VIDOSD4C);
  85.         writel(s3cfb_fimd.wpalcon, S3C_WPALCON);

  86.         s3cfb_onoff_win(fbi, OFF);
  87.         break;
  88.     }

  89.     local_irq_restore(flags);

  90.     return 0;
  91.  }
    检查fb_info中的可变参数,具体的分析还需要S3C6410数据手册:

点击(此处)折叠或打开

  1. static int s3cfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  2. {
  3.     s3cfb_info_t *fbi = (s3cfb_info_t *) info;

  4.     DPRINTK("check_var(var=%p, info=%p)\n", var, info);

  5.     switch (var->bits_per_pixel) {
  6.         case 8:
  7.             var->red = s3cfb_rgb_8.red;
  8.             var->green = s3cfb_rgb_8.green;
  9.             var->blue = s3cfb_rgb_8.blue;
  10.             var->transp = s3cfb_rgb_8.transp;
  11.             s3cfb_fimd.bytes_per_pixel = 1;
  12.             break;

  13.         case 16:
  14.             var->red = s3cfb_rgb_16.red;
  15.             var->green = s3cfb_rgb_16.green;
  16.             var->blue = s3cfb_rgb_16.blue;
  17.             var->transp = s3cfb_rgb_16.transp;
  18.             s3cfb_fimd.bytes_per_pixel = 2;
  19.             break;

  20.         case 24:
  21.             var->red = s3cfb_rgb_24.red;
  22.             var->green = s3cfb_rgb_24.green;
  23.             var->blue = s3cfb_rgb_24.blue;
  24.             var->transp = s3cfb_rgb_24.transp;
  25.             s3cfb_fimd.bytes_per_pixel = 4;
  26.             break;

  27.         case 28:
  28.             var->red = s3cfb_rgb_28.red;
  29.             var->green = s3cfb_rgb_28.green;
  30.             var->blue = s3cfb_rgb_28.blue;
  31.             var->transp = s3cfb_rgb_28.transp;
  32.             s3cfb_fimd.bytes_per_pixel = 4;
  33.             break;

  34.         case 32:
  35.             var->red = s3cfb_rgb_32.red;
  36.             var->green = s3cfb_rgb_32.green;
  37.             var->blue = s3cfb_rgb_32.blue;
  38.             var->transp = s3cfb_rgb_32.transp;
  39.             s3cfb_fimd.bytes_per_pixel = 4;
  40.             break;
  41.     }

  42.     /* WIN0 cannot support alpha channel. */
  43.     if( (fbi->win_id == 0) && (var->bits_per_pixel == 28) ){
  44.         var->transp.length = 0;
  45.     }
  46.     
  47.     return 0;
  48. }
    为了说明上面这个检查可变参数函数下面这个结构定义在s3cfb.h中三星提供的Z官方源码中

点击(此处)折叠或打开

  1. typedef struct {
  2.     struct fb_bitfield red;
  3.     struct fb_bitfield green;
  4.     struct fb_bitfield blue;
  5.     struct fb_bitfield transp;
  6. } s3cfb_rgb_t;

  7. const static s3cfb_rgb_t s3cfb_rgb_8 = {
  8.     .red = {.offset = 0, .length = 8,},
  9.     .green = {.offset = 0, .length = 8,},
  10.     .blue = {.offset = 0, .length = 8,},
  11.     .transp = {.offset = 0, .length = 0,},
  12. };

  13. const static s3cfb_rgb_t s3cfb_rgb_16 = {
  14.     .red = {.offset = 11, .length = 5,},
  15.     .green = {.offset = 5, .length = 6,},
  16.     .blue = {.offset = 0, .length = 5,},
  17.     .transp = {.offset = 0, .length = 0,},
  18. };

  19. const static s3cfb_rgb_t s3cfb_rgb_24 = {
  20.     .red = {.offset = 16, .length = 8,},
  21.     .green = {.offset = 8, .length = 8,},
  22.     .blue = {.offset = 0, .length = 8,},
  23.     .transp = {.offset = 0, .length = 0,},
  24. };

  25. const static s3cfb_rgb_t s3cfb_rgb_28 = {
  26.     .red = {.offset = 16, .length = 8,},
  27.     .green = {.offset = 8, .length = 8,},
  28.     .blue = {.offset = 0, .length = 8,},
  29.     .transp = {.offset = 24, .length = 4,},
  30. };

  31. const static s3cfb_rgb_t s3cfb_rgb_32 = {
  32.     .red = {.offset = 16, .length = 8,},
  33.     .green = {.offset = 8, .length = 8,},
  34.     .blue = {.offset = 0, .length = 8,},
  35.     .transp = {.offset = 24, .length = 8,},
  36. };
    下面可以分析framebuffer提供给应用层的函数操作指针了

点击(此处)折叠或打开

  1. struct fb_ops s3cfb_ops = {
  2.     .owner = THIS_MODULE,
  3.     .fb_check_var = s3cfb_check_var,
  4.     .fb_set_par = s3cfb_set_par,
  5.     .fb_blank = s3cfb_blank,
  6.     .fb_pan_display = s3cfb_pan_display,
  7.     .fb_setcolreg = s3cfb_setcolreg,
  8.     .fb_fillrect = cfb_fillrect,
  9.     .fb_copyarea = cfb_copyarea,
  10.     .fb_imageblit = cfb_imageblit,
  11.     .fb_cursor = soft_cursor,
  12.     .fb_ioctl = s3cfb_ioctl,
  13. };
   需要实现的是跟s3c有关的几个函数,具体可参考s3cfb.c文件。这里只贴s3cfb_ioctl的代码,其余的详情可以参见Linux内核源代码,另外值得注意的就是这些函数都可以使用默认内核默认的fbmem.c中。

点击(此处)折叠或打开

  1. int s3cfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
  2. {
  3.     s3cfb_info_t *fbi = container_of(info, s3cfb_info_t, fb);
  4.     s3cfb_win_info_t win_info;
  5.     s3cfb_color_key_info_t colkey_info;
  6.     s3cfb_color_val_info_t colval_info;
  7.     s3cfb_dma_info_t dma_info;
  8.     s3cfb_next_info_t next_fb_info;
  9.     struct fb_var_screeninfo *var= &fbi->fb.var;
  10.     unsigned int crt, alpha_level, alpha_mode;

  11. #if defined(CONFIG_S3C6410_PWM)
  12.     int brightness;
  13. #endif

  14. #if defined(CONFIG_FB_S3C_EXT_DOUBLE_BUFFERING)
  15.     unsigned int f_num_val;
  16. #endif

  17. #if defined(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)
  18.     s3cfb_vs_info_t vs_info;
  19. #endif

  20.     switch(cmd){
  21.     case S3CFB_GET_INFO:
  22.         dma_info.map_dma_f1 = fbi->map_dma_f1;
  23.         dma_info.map_dma_f2 = fbi->map_dma_f2;

  24.         if(copy_to_user((void *) arg, (const void *) &dma_info, sizeof(s3cfb_dma_info_t)))
  25.             return -EFAULT;
  26.         break;

  27.     case S3CFB_OSD_SET_INFO:
  28.         if (copy_from_user(&win_info, (s3cfb_win_info_t *) arg, sizeof(s3cfb_win_info_t)))
  29.             return -EFAULT;

  30.         s3cfb_init_win(fbi, win_info.bpp, win_info.left_x, win_info.top_y, win_info.width, win_info.height, OFF);
  31.         break;

  32.     case S3CFB_OSD_START:
  33.         s3cfb_onoff_win(fbi, ON);
  34.         break;

  35.     case S3CFB_OSD_STOP:
  36.         s3cfb_onoff_win(fbi, OFF);
  37.         break;

  38.     case S3CFB_OSD_ALPHA_UP:
  39.         alpha_level = readl(S3C_VIDOSD0C + (0x10 * fbi->win_id)) & 0xf;

  40.         if (alpha_level < S3CFB_MAX_ALPHA_LEVEL)
  41.             alpha_level++;

  42.         s3cfb_set_alpha_level(fbi, alpha_level, 1);
  43.         break;

  44.     case S3CFB_OSD_ALPHA_DOWN:
  45.         alpha_level = readl(S3C_VIDOSD0C + (0x10 * fbi->win_id)) & 0xf;

  46.         if (alpha_level > 0)
  47.             alpha_level--;

  48.         s3cfb_set_alpha_level(fbi, alpha_level, 1);
  49.         break;

  50.     case S3CFB_OSD_ALPHA0_SET:
  51.         alpha_level = (unsigned int) arg;

  52.         if (alpha_level > S3CFB_MAX_ALPHA_LEVEL)
  53.             alpha_level = S3CFB_MAX_ALPHA_LEVEL;

  54.         s3cfb_set_alpha_level(fbi, alpha_level, 0);
  55.         break;

  56.     case S3CFB_OSD_ALPHA1_SET:
  57.         alpha_level = (unsigned int) arg;

  58.         if (alpha_level > S3CFB_MAX_ALPHA_LEVEL)
  59.             alpha_level = S3CFB_MAX_ALPHA_LEVEL;

  60.         s3cfb_set_alpha_level(fbi, alpha_level, 1);
  61.         break;

  62.     case S3CFB_OSD_ALPHA_MODE:
  63.         alpha_mode = (unsigned int) arg;
  64.         s3cfb_set_alpha_mode(fbi, alpha_mode);
  65.         break;

  66.     case S3CFB_OSD_MOVE_LEFT:
  67.         if (var->xoffset > 0)
  68.             var->xoffset--;

  69.         s3cfb_set_win_position(fbi, var->xoffset, var->yoffset, var->xres, var->yres);
  70.         break;

  71.     case S3CFB_OSD_MOVE_RIGHT:
  72.         if (var->xoffset < (s3cfb_fimd.width - var->xres))
  73.             var->xoffset++;

  74.         s3cfb_set_win_position(fbi, var->xoffset, var->yoffset, var->xres, var->yres);
  75.         break;

  76.     case S3CFB_OSD_MOVE_UP:
  77.         if (var->yoffset > 0)
  78.             var->yoffset--;

  79.         s3cfb_set_win_position(fbi, var->xoffset, var->yoffset, var->xres, var->yres);
  80.         break;

  81.     case S3CFB_OSD_MOVE_DOWN:
  82.         if (var->yoffset < (s3cfb_fimd.height - var->yres))
  83.             var->yoffset++;

  84.         s3cfb_set_win_position(fbi, var->xoffset, var->yoffset, var->xres, var->yres);
  85.         break;

  86.     case FBIO_WAITFORVSYNC:
  87.         if (get_user(crt, (unsigned int __user *)arg))
  88.             return -EFAULT;

  89.         return s3cfb_wait_for_vsync();

  90.     case S3CFB_COLOR_KEY_START:
  91.         s3cfb_onoff_color_key(fbi, ON);
  92.         break;

  93.     case S3CFB_COLOR_KEY_STOP:
  94.         s3cfb_onoff_color_key(fbi, OFF);
  95.         break;

  96.     case S3CFB_COLOR_KEY_ALPHA_START:
  97.         s3cfb_onoff_color_key_alpha(fbi, ON);
  98.         break;

  99.     case S3CFB_COLOR_KEY_ALPHA_STOP:
  100.         s3cfb_onoff_color_key_alpha(fbi, OFF);
  101.         break;

  102.     case S3CFB_COLOR_KEY_SET_INFO:
  103.         if (copy_from_user(&colkey_info, (s3cfb_color_key_info_t *) arg, sizeof(s3cfb_color_key_info_t)))
  104.             return -EFAULT;

  105.         s3cfb_set_color_key_registers(fbi, colkey_info);
  106.         break;

  107.     case S3CFB_COLOR_KEY_VALUE:
  108.         if (copy_from_user(&colval_info, (s3cfb_color_val_info_t *) arg, sizeof(s3cfb_color_val_info_t)))
  109.             return -EFAULT;

  110.         s3cfb_set_color_value(fbi, colval_info);
  111.         break;

  112.     case S3CFB_SET_VSYNC_INT:
  113.         s3cfb_fimd.vidintcon0 &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;
  114.         s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;

  115.         if (arg)
  116.             s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_INTFRMEN_ENABLE;
  117.         else
  118.             s3cfb_fimd.vidintcon0 &= ~S3C_VIDINTCON0_INTFRMEN_ENABLE;

  119.         writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);
  120.         break;

  121.     case S3CFB_SET_NEXT_FB_INFO:
  122.         if (copy_from_user(&next_fb_info, (s3cfb_next_info_t *) arg, sizeof(s3cfb_next_info_t)))
  123.             return -EFAULT;

  124.         /* check arguments */
  125.         if ((next_fb_info.xres + next_fb_info.xoffset) > next_fb_info.xres_virtual ||
  126.             (next_fb_info.yres + next_fb_info.yoffset) > next_fb_info.yres_virtual ||
  127.             (next_fb_info.xres + next_fb_info.lcd_offset_x ) > s3cfb_fimd.width ||
  128.             (next_fb_info.yres + next_fb_info.lcd_offset_y ) > s3cfb_fimd.height) {
  129.             printk("Error : S3CFB_SET_NEXT_FB_INFO\n");
  130.              return -EINVAL;
  131.         }


  132.         fbi->next_fb_info = next_fb_info;
  133.         fbi->next_fb_info_change_req = 1;
  134.         break;

  135.     case S3CFB_GET_CURR_FB_INFO:
  136.         next_fb_info.phy_start_addr = fbi->fb.fix.smem_start;
  137.         next_fb_info.xres = fbi->fb.var.xres;
  138.         next_fb_info.yres = fbi->fb.var.yres;
  139.         next_fb_info.xres_virtual = fbi->fb.var.xres_virtual;
  140.         next_fb_info.yres_virtual = fbi->fb.var.yres_virtual;
  141.         next_fb_info.xoffset = fbi->fb.var.xoffset;
  142.         next_fb_info.yoffset = fbi->fb.var.yoffset;
  143.         next_fb_info.lcd_offset_x = fbi->lcd_offset_x;
  144.         next_fb_info.lcd_offset_y = fbi->lcd_offset_y;

  145.         if (copy_to_user((void *)arg, (s3cfb_next_info_t *) &next_fb_info, sizeof(s3cfb_next_info_t)))
  146.             return -EFAULT;
  147.         break;

  148.     case S3CFB_GET_BRIGHTNESS:
  149.         if (copy_to_user((void *)arg, (const void *) &s3cfb_fimd.brightness, sizeof(int)))
  150.             return -EFAULT;
  151.         break;

  152. #if defined(CONFIG_S3C6410_PWM)
  153.     case S3CFB_SET_BRIGHTNESS:
  154.         if (copy_from_user(&brightness, (int *) arg, sizeof(int)))
  155.             return -EFAULT;

  156.         s3cfb_set_brightness(brightness);
  157.         break;
  158. #endif

  159. #if defined(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)
  160.     case S3CFB_VS_START:
  161.         s3cfb_fimd.wincon0 &= ~(S3C_WINCONx_ENWIN_F_ENABLE);
  162.         writel(s3cfb_fimd.wincon0 | S3C_WINCONx_ENWIN_F_ENABLE, S3C_WINCON0);

  163.         fbi->fb.var.xoffset = s3cfb_fimd.xoffset;
  164.         fbi->fb.var.yoffset = s3cfb_fimd.yoffset;
  165.         break;

  166.     case S3CFB_VS_STOP:
  167.         s3cfb_fimd.vidw00add0b0 = fbi->screen_dma_f1;
  168.         s3cfb_fimd.vidw00add0b1 = fbi->screen_dma_f2;
  169.         fbi->fb.var.xoffset = 0;
  170.         fbi->fb.var.yoffset = 0;

  171.         writel(s3cfb_fimd.vidw00add0b0, S3C_VIDW00ADD0B0);
  172.         writel(s3cfb_fimd.vidw00add0b1, S3C_VIDW00ADD0B1);

  173.         break;

  174.     case S3CFB_VS_SET_INFO:
  175.         if (copy_from_user(&vs_info, (s3cfb_vs_info_t *) arg, sizeof(s3cfb_vs_info_t)))
  176.             return -EFAULT;

  177.         if (s3cfb_set_vs_info(vs_info)) {
  178.             printk("Error S3CFB_VS_SET_INFO\n");
  179.             return -EINVAL;
  180.         }

  181.         s3cfb_set_vs_registers(S3CFB_VS_SET);

  182.         fbi->fb.var.xoffset = s3cfb_fimd.xoffset;
  183.         fbi->fb.var.yoffset = s3cfb_fimd.yoffset;
  184.         break;

  185.     case S3CFB_VS_MOVE:
  186.         s3cfb_set_vs_registers(arg);

  187.         fbi->fb.var.xoffset = s3cfb_fimd.xoffset;
  188.         fbi->fb.var.yoffset = s3cfb_fimd.yoffset;
  189.         break;
  190. #endif

  191. #if defined(CONFIG_FB_S3C_EXT_DOUBLE_BUFFERING)
  192.     case S3CFB_GET_NUM:
  193.         if (copy_from_user((void *)&f_num_val, (const void *)arg, sizeof(u_int)))
  194.             return -EFAULT;

  195.         if (copy_to_user((void *)arg, (const void *) &f_num_val, sizeof(u_int)))
  196.             return -EFAULT;

  197.         break;

  198.     case S3CFB_CHANGE_REQ:
  199.         s3cfb_change_buff(0, (int) arg);
  200.         break;
  201. #endif

  202.     default:
  203.         return -EINVAL;
  204.     }

  205.     return 0;
  206. }

关于IOCTL中的命令的定义以及各命令当中的处理函数可以下载LCD驱动源码连接 这些命令都定义在s3cfb.h当中,另外值得注意的就是linux内核当中提供给framebuffer的通用代码fbmem.c中的ioctl函数,具体ioctl命令实现跟硬件相关。





阅读(1267) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~