天天看點

framebuffer驅動

2013-03-12 23:15

分析1

幀緩沖(framebuffer)是linux系統顯示裝置的架構,将顯示緩沖區抽象,屏蔽具體細節,使用者可以直接操作幀緩沖,達到顯示的目的。

常見的xwindow和qte也是基于幀緩沖而搭建,隻需将圖形的顔色值寫入幀緩沖對應點,就能達到具體的顯示效果。在嵌入式linux系統中,

LCD驅動都是基于framebuffer架構,以達到輕量級的圖形接口。

幀緩沖裝置是标準的字元裝置,對應主裝置号位29,裝置節點為/dev/fb*,最大支援32個裝置。幀緩沖與像素點的具體關系根據色彩位不同而不同,

常見的RGB565,對應一個short int 型,低5位為BULE,中間6位為GREEN,高5位為RED。

既然幀緩沖裝置是一種字元裝置,那必然存在一個file_operation結構,該結構在drivers/video/fbmem.c中,編寫驅動時不用關心,隻需注冊一個

幀緩沖裝置的struct fb_info資訊即可。

819 struct fb_info {

 820         int node;

 821         int flags;

 822         struct mutex lock;              

 823         struct mutex mm_lock;           

 824         struct fb_var_screeninfo var;   

 825         struct fb_fix_screeninfo fix;   

 826         struct fb_monspecs monspecs;    

 827         struct work_struct queue;       

 828         struct fb_pixmap pixmap;        

 829         struct fb_pixmap sprite;        

 830         struct fb_cmap cmap;            

 831         struct list_head modelist;      

 832         struct fb_videomode *mode;      

 833 

 834 #ifdef CONFIG_FB_BACKLIGHT 

 835         

 836         

 838         struct backlight_device *bl_dev;

 839 

 840         

 841         struct mutex bl_curve_mutex;

 842         u8 bl_curve[FB_BACKLIGHT_LEVELS];

 843 #endif

 844 #ifdef CONFIG_FB_DEFERRED_IO

 845         struct delayed_work deferred_work;

 846         struct fb_deferred_io *fbdefio;

 847 #endif

 848 

 849         struct fb_ops *fbops; 

 850         struct device *device;          

 851         struct device *dev;             

 852         int class_flag;                    

 854         struct fb_tile_ops *tileops;    

 855 #endif

 856         char __iomem *screen_base;      

 857         unsigned long screen_size;      

 858         void *pseudo_palette;           

 859 #define FBINFO_STATE_RUNNING    0

 860 #define FBINFO_STATE_SUSPENDED  1

 861         u32 state;                      

 862         void *fbcon_par;                

 863         

 864         void *par;

 865         

 868         resource_size_t aperture_base;

 869         resource_size_t aperture_size;

 870 };

struct fb_info 記錄一個幀緩沖裝置的所有資訊,一個裝置對應一個fb_info結構題,通過register_framebuffer向幀換沖架構注冊。

int register_framebuffer(struct fb_info *fb_info);

fb_var_screeninfo 結構體記錄着使用者可以修改的裝置參數,具體如下:

 237 struct fb_var_screeninfo {

 238         __u32 xres;                     

 239         __u32 yres;

 240         __u32 xres_virtual;             

 241         __u32 yres_virtual;

 242         __u32 xoffset;                  

 243         __u32 yoffset;                  

 244 

 245         __u32 bits_per_pixel;           

 247 

 248         struct fb_bitfield red;         

 249         struct fb_bitfield green;       

 250         struct fb_bitfield blue;

 251         struct fb_bitfield transp;      

 252 

 253         __u32 nonstd;                   

 254 

 255         __u32 activate;                 

 256 

 257         __u32 height;                   

 258         __u32 width;                    

 259 

 260         __u32 accel_flags;              

 261 

 262         

 263         __u32 pixclock;                 

 264         __u32 left_margin;              

 265         __u32 right_margin;             

 266         __u32 upper_margin;             

 267         __u32 lower_margin;

 268         __u32 hsync_len;                

 269         __u32 vsync_len;                

 270         __u32 sync;                     

 271         __u32 vmode;                    

 272         __u32 rotate;                   

 273         __u32 reserved[5];              

 274 };

以上是可變參數結構,另外還有struct fb_fix_screeninfo不可變參數:

 154 struct fb_fix_screeninfo {

 155         char id[16];                    

 156         unsigned long smem_start;       

 157                                         

 158         __u32 smem_len;                 

 160         __u32 type_aux;                 

 161         __u32 visual;                   

 162         __u16 xpanstep;                 

 163         __u16 ypanstep;                 

 164         __u16 ywrapstep;                

 165         __u32 line_length;              

 166         unsigned long mmio_start;       

 167                                         

 168         __u32 mmio_len;                 

 169         __u32 accel;                    

 170                                         

 171         __u16 reserved[3];              

 172 };

完成這三個結構體,一個framebuffer裝置驅動架構就完成了,如此針對具體控制器的驅動流程如下:

1.申請fb_info,填充fb_var_screeninfo和fb_fix_screeninfo

2.完成LCD控制器初始化,即時序的配置

3.注冊幀緩沖裝置

雖然framebuffer是一個字元裝置,但大多LCD控制器都內建在SOC上,在寫驅動時仍作為一種platform_device裝置進行注冊。

以omapl138/am1808 LCD控制器驅動分析framebuffer注冊流程,LCD屏使用群創7"屏。

 977 static struct platform_driver da8xx_fb_driver = {

 978         .probe = fb_probe,

 979         .remove = fb_remove,

 980         .suspend = fb_suspend,

 981         .resume = fb_resume,

 982         .driver = {

 983                    .name = DRIVER_NAME,

 984                    .owner = THIS_MODULE,

 985                    },

 986 };

标準的platform_drivers驅動結構,DRIVER_NAME與platform_device->name一緻,主要分析probe過程。

744 static int __init fb_probe(struct platform_device *device)

 745 {

 746         struct da8xx_lcdc_platform_data *fb_pdata =

 747                                                 device->dev.platform_data;

 748         struct lcd_ctrl_config *lcd_cfg;

 749         struct da8xx_panel *lcdc_info;

 750         struct fb_info *da8xx_fb_info;

 751         struct clk *fb_clk = NULL;

 752         struct da8xx_fb_par *par;

 753         resource_size_t len;

 754         int ret, i;

 755 

 756         if (fb_pdata == NULL) {

 757                 dev_err(&device->dev, "Can not get platform data\n");

 758                 return -ENOENT;

 759         }

 760 

 761         lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0);

 762         if (!lcdc_regs) {

 763                 dev_err(&device->dev,

 764                         "Can not get memory resource for LCD controller\n");

 765                 return -ENOENT;

 766         }

 767 

 768         len = resource_size(lcdc_regs);

 769 

 770         lcdc_regs = request_mem_region(lcdc_regs->start, len, lcdc_regs->name);

 771         if (!lcdc_regs)

 772                 return -EBUSY;

 773 

 774         da8xx_fb_reg_base = (resource_size_t)ioremap(lcdc_regs->start, len);

 775         if (!da8xx_fb_reg_base) {

 776                 ret = -EBUSY;

 777                 goto err_request_mem;

 778         }

 779 

 780         fb_clk = clk_get(&device->dev, NULL);

 781         if (IS_ERR(fb_clk)) {

 782                 dev_err(&device->dev, "Can not get device clock\n");

 783                 ret = -ENODEV;

 784                 goto err_ioremap;

 785         }

 786         ret = clk_enable(fb_clk);

 787         if (ret)

 788                 goto err_clk_put;

790         for (i = 0, lcdc_info = known_lcd_panels;

 791                 i < ARRAY_SIZE(known_lcd_panels);

 792                 i++, lcdc_info++) {

 793                 if (strcmp(fb_pdata->type, lcdc_info->name) == 0)

 794                         break;

 795         }

 796 

 797         if (i == ARRAY_SIZE(known_lcd_panels)) {

 798                 dev_err(&device->dev, "GLCD: No valid panel found\n");

 799                 ret = ENODEV;

 800                 goto err_clk_disable;

 801         } else

 802                 dev_info(&device->dev, "GLCD: Found %s panel\n",

 803                                         fb_pdata->type);

 804 

 805         lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data;

 806 

 807         da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par),

 808                                         &device->dev);

 809         if (!da8xx_fb_info) {

 810                 dev_dbg(&device->dev, "Memory allocation failed for fb_info\n");

 811                 ret = -ENOMEM;

 812                 goto err_clk_disable;

 813         }

 814 

 815         par = da8xx_fb_info->par;

 816         par->lcdc_clk = fb_clk;

 817         par->pxl_clk = lcdc_info->pxl_clk;

 818 

 819         if (lcd_init(par, lcd_cfg, lcdc_info) < 0) {

 820                 dev_err(&device->dev, "lcd_init failed\n");

 821                 ret = -EFAULT;

 822                 goto err_release_fb;

 823         }

 826         da8xx_fb_info->screen_base = dma_alloc_coherent(NULL,

 827                                         par->databuf_sz + PAGE_SIZE,

 828                                         (resource_size_t *)

 829                                         &da8xx_fb_info->fix.smem_start,

 830                                         GFP_KERNEL | GFP_DMA);

 831 

 832         if (!da8xx_fb_info->screen_base) {

 833                 dev_err(&device->dev,

 834                         "GLCD: kmalloc for frame buffer failed\n");

 835                 ret = -EINVAL;

 836                 goto err_release_fb;

 837         }

 838         memset(da8xx_fb_info->screen_base, 0, par->databuf_sz + PAGE_SIZE);

 839         

 840         par->v_palette_base = da8xx_fb_info->screen_base +

 841                                 (PAGE_SIZE - par->palette_sz);

 842         par->p_palette_base = da8xx_fb_info->fix.smem_start +

 843                                 (PAGE_SIZE - par->palette_sz);

844         memset(par->v_palette_base, 0, PALETTE_SIZE);

 845         

 846         da8xx_fb_info->screen_base = par->v_palette_base + par->palette_sz;

 847         da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz;

 862         da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp;

 863 

 864         da8xx_fb_var.xres = lcdc_info->width;

 865         da8xx_fb_var.xres_virtual = lcdc_info->width;

 866 

 867         da8xx_fb_var.yres = lcdc_info->height;

 868         da8xx_fb_var.yres_virtual = lcdc_info->height;

 869 

 870         da8xx_fb_var.grayscale =

 871             lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0;

 872         da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp;

 873 

 874         da8xx_fb_var.hsync_len = lcdc_info->hsw;

 875         da8xx_fb_var.vsync_len = lcdc_info->vsw;

877         

 878         da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT;

 879         da8xx_fb_info->fix = da8xx_fb_fix;

 880         da8xx_fb_info->var = da8xx_fb_var;

 881         da8xx_fb_info->fbops = &da8xx_fb_ops; 

 890         da8xx_fb_info->cmap.len = par->palette_sz;

 891 

 892         

 893         lcd_blit(LOAD_DATA, par);

 894 #if 0

 895         {

 896                 int i;

 897                 for (i = 0; i < (800 * 480 * 2);) {

 898                         *((volatile unsigned short *)(0xC7A01000 + i)) = 0x0;

 899                         i+=2;

 900                 }

 901         }

 902 #endif

 903         

 904         da8xx_fb_var.activate = FB_ACTIVATE_FORCE;

 905         fb_set_var(da8xx_fb_info, &da8xx_fb_var);

 906 

 907         dev_set_drvdata(&device->dev, da8xx_fb_info);

 908         

 909         if (register_framebuffer(da8xx_fb_info) < 0) {

 910                 dev_err(&device->dev,

 911                         "GLCD: Frame Buffer Registration Failed!\n");

 912                 ret = -EINVAL;

 913                 goto err_dealloc_cmap;

 914         }

916 #ifdef CONFIG_CPU_FREQ

 917         ret = lcd_da8xx_cpufreq_register(par);

 918         if (ret) {

 919                 dev_err(&device->dev, "failed to register cpufreq\n");

 920                 goto err_cpu_freq;

 921         }

 922 #endif

 923         

 924         lcdc_write(lcdc_read(LCD_RASTER_CTRL_REG) |

 925                         LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);

 926 

 927         return 0;

struct fb_ops結構體實作與硬體相關,使用者需要實作其中幾個函數:

 733 static struct fb_ops da8xx_fb_ops = {

 734         .owner = THIS_MODULE,

 735         .fb_check_var = fb_check_var, //調整顯示參數

 736         .fb_setcolreg = fb_setcolreg,//設定顔色表

 737         .fb_ioctl = fb_ioctl,   //設定vsync.hsync等

 738         .fb_fillrect = cfb_fillrect, //在drivers/video/cfbfillrect.c

 739         .fb_copyarea = cfb_copyarea, //drivers/video/cfbcopyarea.c 

 740         .fb_imageblit = cfb_imageblit,//drivers/video/cfbimgblt.c

 741         .fb_cursor = dummy_cursor, //這個實作了一個空函數,避免在LCD上顯示光标 

 742 };

 728 static int dummy_cursor(struct fb_info *info, struct fb_cursor *cursor)

 729 {

 730         return 0;

 731 }

至于幀緩沖的file_operation實作,在drivers/video/fbmem.c中實作

1423 static const struct file_operations fb_fops = {

1424         .owner =        THIS_MODULE,

1425         .read =         fb_read, 

1426         .write =        fb_write,

1427         .unlocked_ioctl = fb_ioctl,

1428 #ifdef CONFIG_COMPAT

1429         .compat_ioctl = fb_compat_ioctl,

1430 #endif

1431         .mmap =         fb_mmap,

1432         .open =         fb_open,

1433         .release =      fb_release,

1434 #ifdef HAVE_ARCH_FB_UNMAPPED_AREA

1435         .get_unmapped_area = get_fb_unmapped_area,

1436 #endif

1437 #ifdef CONFIG_FB_DEFERRED_IO

1438         .fsync =        fb_deferred_io_fsync,

1439 #endif

1440 };

主要關心read,write,ioctl,mmap,open,release函數即可