博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
驱动05.lcd设备驱动程序
阅读量:6814 次
发布时间:2019-06-26

本文共 12731 字,大约阅读时间需要 42 分钟。

参考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 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 17 #include
18 #include
19 #include
20 21 #include
22 #include
23 #include
24 #include
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_start114 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 signal159 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\n", 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
S3C2410 LCD framebuffer support2. make uImage make modules 3. 使用新的uImage启动开发板:4. insmod cfbcopyarea.ko insmod cfbfillrect.ko insmod cfbimgblt.ko insmod lcd.koecho hello > /dev/tty1 // 可以在LCD上看见hellocat lcd.ko > /dev/fb0 // 花屏5. 修改 /etc/inittabtty1::askfirst:-/bin/sh用新内核重启开发板insmod cfbcopyarea.ko insmod cfbfillrect.ko insmod cfbimgblt.ko insmod lcd.koinsmod buttons.ko

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

2017-01-10 16:12:27

转载于:https://www.cnblogs.com/Lwd-linux/p/6267595.html

你可能感兴趣的文章
Apache Flink轻量级异步快照机制源码分析
查看>>
PostgreSQL 11 preview - 分区表 增强 汇总
查看>>
MediaCodec在Android视频硬解码组件的应用
查看>>
用JAVA自己画一张二维码
查看>>
Flutter Engine线程管理与Dart Isolate机制
查看>>
美国泛达公司:下一代数据中心的光缆布线系统
查看>>
以太坊(ethereum)技术开发相关资料
查看>>
Pandas数据排序
查看>>
gulp常用插件
查看>>
2018 前端趋势:更一致,更简单
查看>>
SQL物化视图 自动更新 定时刷新
查看>>
express框架应用接入阿里云函数计算
查看>>
几行代码实现ofo首页小黄人眼睛加速感应转动
查看>>
317TABLE ACCESS BY INDEX ROWID BATCHED3
查看>>
MapReduce Shuffle原理 与 Spark Shuffle原理
查看>>
题解 P3386 【【模板】二分图匹配】
查看>>
李彦宏:人工智能的互联网时代已经到来
查看>>
游标概念和作用(转载)
查看>>
python中全局变量、局部变量、类变量、实例变量简析
查看>>
大众公布量子计算北京交通新一代产品亮相
查看>>