• 驱动05.lcd设备驱动程序


    参考s3c2410fb.c总结出框架

    1.代码分析

    1.1 入口函数

    1 int __devinit s3c2410fb_init(void)
    2 {
    3     return platform_driver_register(&s3c2410fb_driver);
    4 }

    注册一个platform_driver结构体,如果存在同名的设备dev时,将调用probe函数。

     1 static struct platform_driver s3c2410fb_driver = {
     2     .probe        = s3c2410fb_probe,
     3     .remove        = s3c2410fb_remove,
     4     .suspend    = s3c2410fb_suspend,
     5     .resume        = s3c2410fb_resume,
     6     .driver        = {
     7         .name    = "s3c2410-lcd",   //如果存在有同名"s3c2410-lcd"的平台设备,就会调用s3c2410fb_driver的s3c2410fb_probe函数
     8         .owner    = THIS_MODULE,
     9     },
    10 };      //这是s3c2410fb_driver这个结构体的具体成员

    搜索s3c2410-lcd可得下面的s3c_device_lcd结构体

     1 struct platform_device s3c_device_lcd = {
     2     .name          = "s3c2410-lcd",
     3     .id          = -1,
     4     .num_resources      = ARRAY_SIZE(s3c_lcd_resource),
     5     .resource      = s3c_lcd_resource,               //最重要的部分
     6     .dev              = {
     7         .dma_mask        = &s3c_device_lcd_dmamask,
     8         .coherent_dma_mask    = 0xffffffffUL
     9     }
    10 };

    1.2 probe函数(只列出关键性代码)

     1 static int __init s3c2410fb_probe(struct platform_device *pdev)
     2 {
     3     struct s3c2410fb_info *info;
     4     struct fb_info       *fbinfo;
     5                         ......
     6 
     7     fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);
     8     if (!fbinfo) {
     9         return -ENOMEM;
    10     }
    11                         ......
    12     fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;
    13     fbinfo->fix.type_aux        = 0;
    14     fbinfo->fix.xpanstep        = 0;
    15     fbinfo->fix.ypanstep        = 0;
    16     fbinfo->fix.ywrapstep        = 0;
    17     fbinfo->fix.accel        = FB_ACCEL_NONE;
    18 
    19     fbinfo->var.nonstd        = 0;
    20     fbinfo->var.activate        = FB_ACTIVATE_NOW;
    21     fbinfo->var.height        = mach_info->height;
    22     fbinfo->var.width        = mach_info->width;
    23     fbinfo->var.accel_flags     = 0;
    24     fbinfo->var.vmode        = FB_VMODE_NONINTERLACED;
    25                         .......
    26     ret = register_framebuffer(fbinfo);
    27     return 0;
    28 
    29 }

    由此可知,其主要框架是

    (1)分配一个fb_info结构体

    (2)设置其参数

    (3)注册这个结构体

    (4)硬件相关的操作

    1.3 fb_info结构体成员的了解

    lcd为标准的帧缓冲设备,其主设备号为29,对应的设备为/dev/fb*

     1     struct fb_info {  
     2         int node;                       //用作次设备号索引  
     3         int flags;  
     4         struct mutex lock;              //用于open/release/ioctl函数的锁  
     5         struct fb_var_screeninfo var;   //可变参数,重点  
     6         struct fb_fix_screeninfo fix;   //固定参数,重点  
     7         struct fb_monspecs monspecs;    //显示器标准  
     8         struct work_struct queue;       //帧缓冲区队列  
     9         struct fb_pixmap pixmap;        //图像硬件映射  
    10         struct fb_pixmap sprite;        //光标硬件映射  
    11         struct fb_cmap cmap;            //当前颜色表  
    12         struct list_head modelist;      //模式链表  
    13         struct fb_videomode *mode;      //当前video模式  
    14       
    15         char __iomem *screen_base;      //显存基地址  
    16         unsigned long screen_size;      //显存大小  
    17         void *pseudo_palette;           //16色调色板  
    18     #define FBINFO_STATE_RUNNING    0  
    19     #define FBINFO_STATE_SUSPENDED  1  
    20         u32 state;                      //硬件状态,如挂起  
    21         void *fbcon_par;                //用作私有数据区  
    22         void *par;                      //info->par指向了额外多申请内存空间的首地址  
    23     };  

    另外,fb_fix_screeninfofb_var_screeninfo也是两个比较重要的结构体,在设置fb_info结构体时会大量用到。

     1 struct fb_fix_screeninfo {
     2     char id[16];            /* identification string eg "TT Builtin" */
     3     unsigned long smem_start;    /* Start of frame buffer mem */
     4                     /* (physical address) */
     5     __u32 smem_len;            /* Length of frame buffer mem */
     6     __u32 type;            /* see FB_TYPE_*        */
     7     __u32 type_aux;            /* Interleave for interleaved Planes */
     8     __u32 visual;            /* see FB_VISUAL_*        */ 
     9     __u16 xpanstep;            /* zero if no hardware panning  */
    10     __u16 ypanstep;            /* zero if no hardware panning  */
    11     __u16 ywrapstep;        /* zero if no hardware ywrap    */
    12     __u32 line_length;        /* length of a line in bytes    */
    13     unsigned long mmio_start;    /* Start of Memory Mapped I/O   */
    14                     /* (physical address) */
    15     __u32 mmio_len;            /* Length of Memory Mapped I/O  */
    16     __u32 accel;            /* Indicate to driver which    */
    17                     /*  specific chip/card we have    */
    18     __u16 reserved[3];        /* Reserved for future compatibility */
    19 };
    struct fb_var_screeninfo {
        __u32 xres;            /* visible resolution        */
        __u32 yres;
        __u32 xres_virtual;        /* virtual resolution        */
        __u32 yres_virtual;
        __u32 xoffset;            /* offset from virtual to visible */
        __u32 yoffset;            /* resolution            */
    
        __u32 bits_per_pixel;        /* guess what            */
        __u32 grayscale;        /* != 0 Graylevels instead of colors */
    
        struct fb_bitfield red;        /* bitfield in fb mem if true color, */
        struct fb_bitfield green;    /* else only length is significant */
        struct fb_bitfield blue;
        struct fb_bitfield transp;    /* transparency            */    
    
        __u32 nonstd;            /* != 0 Non standard pixel format */
    
        __u32 activate;            /* see FB_ACTIVATE_*        */
    
        __u32 height;            /* height of picture in mm    */
        __u32 width;            /* width of picture in mm     */
    
        __u32 accel_flags;        /* (OBSOLETE) see fb_info.flags */
    
        /* Timing: All values in pixclocks, except pixclock (of course) */
        __u32 pixclock;            /* pixel clock in ps (pico seconds) */
        __u32 left_margin;        /* time from sync to picture    */
        __u32 right_margin;        /* time from picture to sync    */
        __u32 upper_margin;        /* time from sync to picture    */
        __u32 lower_margin;
        __u32 hsync_len;        /* length of horizontal sync    */
        __u32 vsync_len;        /* length of vertical sync    */
        __u32 sync;            /* see FB_SYNC_*        */
        __u32 vmode;            /* see FB_VMODE_*        */
        __u32 rotate;            /* angle we rotate counter clockwise */
        __u32 reserved[5];        /* Reserved for future compatibility */
    };

    1.4 fb_open函数

    app:  open("/dev/fb0"...)   主设备号:29   次设备号:0
    -----------------------------------------------------------
    kernel:
          fb_open
                   int fbidx = iminor(inode)//获取次设备号
                        struct fb_info *info =  registered_fb[fbidx]

    1.5 fb_read函数

    app:    read()
    ------------------------------------------------------------            
    kernel:
                fb_read
                    int fbidx = iminor(inode);
                    struct fb_info *info = registered_fb[fbidx];    
                        if (info->fbops->fb_read)
                                return info->fbops->fb_read(info, buf, count, ppos);
                        src = (u32 __iomem *) (info->screen_base + p);
                        *dst++ = fb_readl(src++);
                        copy_to_user(buf, buffer, c)

    1.6 registered_fb数组由谁来定义?

    register_framebuffer

      registered_fb[i] = fb_info

    2 写代码

    由1.2我们可以得知,代码的总体框架为:

    (1)分配一个fb_info结构体

    (2)设置其参数

    (3)注册这个结构体

    (4)硬件相关的操作

    其实难点就在于第(2)步,主要是设置fb_info结构体的固定参数 fb_fix_screeninfo结构体和可变参数fb_var_screeninfo结构体,还有就是硬件相关

    的设置,比如lcd时序参数的设置,也就是要设置lcdcon1~lcdcon5,lcdaddr1~lcdaddr3个寄存器。

     2.2 源代码

      1 #include <linux/module.h>
      2 #include <linux/kernel.h>
      3 #include <linux/errno.h>
      4 #include <linux/string.h>
      5 #include <linux/mm.h>
      6 #include <linux/slab.h>
      7 #include <linux/delay.h>
      8 #include <linux/fb.h>
      9 #include <linux/init.h>
     10 #include <linux/dma-mapping.h>
     11 #include <linux/interrupt.h>
     12 #include <linux/workqueue.h>
     13 #include <linux/wait.h>
     14 #include <linux/platform_device.h>
     15 #include <linux/clk.h>
     16 
     17 #include <asm/io.h>
     18 #include <asm/uaccess.h>
     19 #include <asm/div64.h>
     20 
     21 #include <asm/mach/map.h>
     22 #include <asm/arch/regs-lcd.h>
     23 #include <asm/arch/regs-gpio.h>
     24 #include <asm/arch/fb.h>
     25 
     26 
     27 struct lcd_regs{
     28     unsigned long lcdcon1;
     29     unsigned long lcdcon2;
     30     unsigned long lcdcon3;
     31     unsigned long lcdcon4;
     32     unsigned long lcdcon5;
     33     unsigned long lcdsaddr1;
     34     unsigned long lcdsaddr2;
     35     unsigned long lcdsaddr3;
     36     unsigned long redlut;
     37     unsigned long greenlut;
     38     unsigned long bluelut;
     39     unsigned long reserved[9];
     40     unsigned long dithmode;
     41     unsigned long tpal;
     42     unsigned long lcdintpnd;
     43     unsigned long lcdsrcpnd;
     44     unsigned long lcdintmsk;
     45     unsigned long tconsel;
     46 };
     47 
     48 static struct fb_info *s3c_lcd;
     49 static volatile unsigned long *gpbcon;
     50 static volatile unsigned long *gpbdat;
     51 static volatile unsigned long *gpccon;
     52 static volatile unsigned long *gpdcon;
     53 static volatile unsigned long *gpgcon;
     54 static u32 pseudo_palette[16];
     55 static volatile struct lcd_regs *lcd_regs;
     56 
     57 
     58 static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
     59 {
     60     chan &= 0xffff;
     61     chan >>= 16 - bf->length;
     62     return chan << bf->offset;
     63 }
     64 
     65 static int s3c_lcdfb_setcolreg(unsigned regno,
     66                    unsigned red, unsigned green, unsigned blue,
     67                    unsigned transp, struct fb_info *info)
     68 {
     69     unsigned int val;
     70     
     71     if (regno < 16) 
     72     {
     73 //        u32 *pal = fbi->fb->pseudo_palette;
     74         val  = chan_to_field(red,   &info->var.red);
     75         val |= chan_to_field(green, &info->var.green);
     76         val |= chan_to_field(blue,  &info->var.blue);
     77         pseudo_palette[regno] = val;
     78     }
     79     else
     80         return 1;
     81 
     82     return 0;
     83 
     84 }
     85 
     86 static struct fb_ops s3clcdfb_ops = {
     87     .owner        = THIS_MODULE,
     88     .fb_setcolreg    = s3c_lcdfb_setcolreg,//调色板
     89     .fb_fillrect    = cfb_fillrect,
     90     .fb_copyarea    = cfb_copyarea,
     91     .fb_imageblit    = cfb_imageblit,
     92 };
     93 
     94 static int lcd_init(void)
     95 {
     96     int ret;
     97     /*1.分配一个fb_info结构体*/
     98     s3c_lcd = framebuffer_alloc(0, NULL);
     99     if (!s3c_lcd) {
    100         return -ENOMEM;
    101     }
    102 
    103 
    104     /*2.设置 */
    105     strcpy(s3c_lcd->fix.id, "mylcd");
    106 
    107     /*2.1设置固定数据fix*/
    108     s3c_lcd->fix.smem_len = 480*272*16/8;
    109     s3c_lcd->fix.type         = FB_TYPE_PACKED_PIXELS;
    110     s3c_lcd->fix.type_aux   = 0;
    111     s3c_lcd->fix.visual           = FB_VISUAL_TRUECOLOR;//TFT真彩色
    112     s3c_lcd->fix.line_length = 480*16/8;
    113 //    s3c_lcd->fix.smem_start
    114 
    115     /*2.2设置可变参数var*/
    116     s3c_lcd->var.xres = 480;
    117     s3c_lcd->var.yres = 272;
    118     s3c_lcd->var.xres_virtual = 480;
    119     s3c_lcd->var.yres_virtual = 272;
    120     s3c_lcd->var.bits_per_pixel = 16;
    121 
    122     /*RGB:565*/
    123     s3c_lcd->var.red.offset= 11;
    124     s3c_lcd->var.red.length = 5;
    125     s3c_lcd->var.green.offset = 5;
    126     s3c_lcd->var.green.length = 6;
    127     s3c_lcd->var.blue.offset = 0;
    128     s3c_lcd->var.blue.length = 5;
    129 
    130     s3c_lcd->var.activate = FB_ACTIVATE_NOW;
    131 
    132     s3c_lcd->fbops            = &s3clcdfb_ops;
    133     s3c_lcd->pseudo_palette = pseudo_palette;
    134     s3c_lcd->screen_size   = 480*272*16/8;
    135 
    136     /*3.硬件相关的操作*/
    137     /*3.1GPIO的初始化*/
    138     gpbcon = ioremap(0x56000010, 8);
    139     gpbdat = gpbcon+1;
    140     gpccon = ioremap(0x56000020, 4);
    141     gpdcon = ioremap(0x56000030, 4);
    142     gpgcon = ioremap(0x56000060, 4);
    143 
    144     *gpccon = 0xaaaaaaaa;
    145     *gpdcon = 0xaaaaaaaa;
    146     
    147     *gpbcon &= ~(3);
    148     *gpbcon |= 1;
    149     *gpbdat &= ~1;//背光使能
    150     
    151     *gpgcon  |= (3<<8); //LCD 电源使能
    152 
    153     /*3.2 设置LCD controller*/
    154     lcd_regs = ioremap(0x4D000000,sizeof(struct lcd_regs));
    155 
    156 
    157     lcd_regs->lcdcon1 = (4<<8) |(3<<5) |(0x0c<<1);
    158     //lcdcon1[0] Enable the video output and the LCD control signal
    159 
    160     lcd_regs->lcdcon2 = (1<<24) |(271<<14) |(1<<6) |(9);
    161 
    162     lcd_regs->lcdcon3 = (1<<19) |(479<<8) |(1);
    163 
    164     lcd_regs->lcdcon4 = 40;
    165 
    166     lcd_regs->lcdcon5 = (1<<11) |(1<<9) |(1<<8) |(1<<0);
    167 
    168     /*3.3 设置显存的地址*/
    169     s3c_lcd->screen_base = dma_alloc_writecombine(NULL,s3c_lcd->fix.smem_len,&s3c_lcd->fix.smem_start,GFP_KERNEL);
    170     
    171     lcd_regs->lcdsaddr1 = (s3c_lcd->fix.smem_start>>1) & ~(3<<30);
    172     lcd_regs->lcdsaddr2 = (s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len) & 0x1fffff;
    173     lcd_regs->lcdsaddr3 = (480*16/16);//行的长度
    174 
    175 
    176     /*启动lcd*/
    177     
    178     lcd_regs->lcdcon1 |= (1);//使能LCD控制器
    179     lcd_regs->lcdcon5 |= (1<<3);//使能LCD电源
    180     *gpbdat |=1;  //使能背光
    181 
    182 
    183     /*4.注册该结构体*/
    184     ret = register_framebuffer(s3c_lcd);
    185     if (ret < 0) {
    186         printk("Failed to register framebuffer device: %d
    ", ret);
    187     }
    188 
    189     return 0;
    190 }
    191 
    192 static int lcd_exit(void)
    193 {    
    194     unregister_framebuffer(s3c_lcd);
    195     lcd_regs->lcdcon1 &= ~1;
    196     lcd_regs->lcdcon5 &= ~(1<<3);
    197     *gpbdat &= ~1;  
    198 
    199     dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, s3c_lcd->screen_base, s3c_lcd->fix.smem_start);
    200     iounmap(lcd_regs);
    201     iounmap(gpbcon);
    202     iounmap(gpccon);
    203     iounmap(gpdcon);
    204     iounmap(gpgcon);
    205 
    206     framebuffer_release(s3c_lcd);
    207     return 0;
    208 }
    209 
    210 module_init(lcd_init);
    211 module_exit(lcd_exit);
    212 
    213 MODULE_AUTHOR("lwd20170110");
    214 
    215 MODULE_LICENSE("GPL");
    lcd驱动程序
    测试:
    1. make menuconfig去掉原来的驱动程序
    -> Device Drivers
      -> Graphics support
    <M> S3C2410 LCD framebuffer support
    
    2. make uImage
       make modules  
    
    3. 使用新的uImage启动开发板:
    
    4. 
    insmod cfbcopyarea.ko 
    insmod cfbfillrect.ko 
    insmod cfbimgblt.ko 
    insmod lcd.ko
    
    echo hello > /dev/tty1  // 可以在LCD上看见hello
    cat lcd.ko > /dev/fb0   // 花屏
    
    5. 修改 /etc/inittab
    tty1::askfirst:-/bin/sh
    用新内核重启开发板
    
    insmod cfbcopyarea.ko 
    insmod cfbfillrect.ko 
    insmod cfbimgblt.ko 
    insmod lcd.ko
    insmod buttons.ko

    2.3 待解决:1.出现段错误。2.用新内核启动后无法挂载nfs。

    2017-01-10 16:12:27

  • 相关阅读:
    DHTML 动态效果100例
    Apache 发布网站
    Django笔记 3
    JDBC
    Android国行手机使用Google Play Store
    Cloud9 使用 GitHub
    maven
    linux 下查看系统信息的一些命令
    C++成员变量指针和成员函数指针
    SIP 协议
  • 原文地址:https://www.cnblogs.com/Lwd-linux/p/6267595.html
Copyright © 2020-2023  润新知