LCD(二) linux驱动分析
来源:互联网 发布:志鸿优化系列 编辑:程序博客网 时间:2024/05/21 20:43
数据结构
//struct fb_infostruct fb_info { int node; int flags; struct mutex lock; /* Lock for open/release/ioctl funcs */ struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */ struct fb_var_screeninfo var; /* 可变参数 */ struct fb_fix_screeninfo fix; /* 固定参数 */ struct fb_monspecs monspecs; /* 显示器标准特性 */ struct work_struct queue; /* Framebuffer event queue */ struct fb_pixmap pixmap; /* 图像硬件mapper */ struct fb_pixmap sprite; /* 光标硬件 mapper */ struct fb_cmap cmap; /* 颜色表 */ struct list_head modelist; /* mode list */ struct fb_videomode *mode; /* video模式 */#ifdef CONFIG_FB_BACKLIGHT //背光驱动 /* assigned backlight device */ /* set before framebuffer registration, remove after unregister */ struct backlight_device *bl_dev; /* Backlight level curve */ struct mutex bl_curve_mutex; u8 bl_curve[FB_BACKLIGHT_LEVELS];#endif#ifdef CONFIG_FB_DEFERRED_IO struct delayed_work deferred_work; struct fb_deferred_io *fbdefio;#endif struct fb_ops *fbops; //对帧缓冲的操作 struct device *device; /* This is the parent */ struct device *dev; /* This is this fb device */ int class_flag; /* private sysfs flags */ char __iomem *screen_base; /* 显存虚拟基地址 */ unsigned long screen_size; /* 显存大小 */ void *pseudo_palette; /* 伪16色颜色表*/ #define FBINFO_STATE_RUNNING 0#define FBINFO_STATE_SUSPENDED 1 u32 state; /* Hardware state i.e suspend */ void *fbcon_par; /* fbcon use-only private area */ /* From here on everything is device dependent */ void *par; //.....};struct fb_var_screeninfo { __u32 xres; //可见分辨率 __u32 yres; __u32 xres_virtual; __u32 yres_virtual; __u32 xoffset; __u32 yoffset; __u32 bits_per_pixel; //每个像素位数 __u32 grayscale; struct fb_bitfield red; //颜色位域 struct fb_bitfield green; struct fb_bitfield blue; struct fb_bitfield transp; //透明度 __u32 nonstd; __u32 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 (皮秒) */ __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 */};struct fb_fix_screeninfo { char id[16]; /* identification string eg "TT Builtin" */ unsigned long smem_start; /* Start of frame buffer mem *//* (physical address) */ __u32 smem_len; /* Length of frame buffer mem */ __u32 type; /* see FB_TYPE_* */ __u32 type_aux; /* Interleave for interleaved Planes */ __u32 visual; /* see FB_VISUAL_* */ //色彩模式,真彩色,伪彩色 __u16 xpanstep; /* zero if no hardware panning */ __u16 ypanstep; /* zero if no hardware panning */ __u16 ywrapstep; /* zero if no hardware ywrap */ __u32 line_length; /* length of a line in bytes */ unsigned long mmio_start; /* Start of Memory Mapped I/O */ /* (physical address) */ __u32 mmio_len; /* Length of Memory Mapped I/O */ __u32 accel; /* Indicate to driver which */ /* specific chip/card we have */ __u16 reserved[3]; /* Reserved for future compatibility */};//颜色位域struct fb_bitfield { __u32 offset; /* beginning of bitfield */ __u32 length; /* length of bitfield */ __u32 msb_right; /* != 0 : Most significant bit is */ /* right */ };//像素深度:BPP// 像素深度是指存储每个像素所用的位数,它也是用来度量图像的分辨率。//像素深度决定彩色图像的每个像素可能有的颜色数,或者确定灰度图像//的每个像素可能有的灰度级数,例如,一幅彩色图像的每个像素用R,//就说像素的深度为24,每个像素可以是16 777 216(2的24次方)种颜//色中的一种。在这个意义上,往往把像素深度说成是图像深度。//表示一个像素的位数越多,它能表达的颜色数目就越多,而它的深度就越深。//调色板原理<详见调色板原理>:// 在计算机图像技术中,一个像素的颜色是由它的R,G,B分量表示的,//每个分量又经过量化,一个像素总的量化级数就是这个显示系统的颜色//深度。量化级数越高,可以表示的颜色也就越多,最终的图像也就越逼真。//当量化级数达到16位以上时,被称为真彩色。但是,量化级数越高,就需//要越高的数据宽度,给处理器带来的负担也就越重;量化级数在8位以下时,//所能表达的颜色又太少,不能够满足用户特定的需求。 // 为了解决这个问题,可以采取调色板技术。所谓调色板,就是在低颜色//深度的模式下,在有限的像素值与RGB颜色之间建立对应关系的一个线性表。//比如说,从所有的16位彩色中抽取一定数量的颜色,编制索引。当需要使用//某种彩色时,不需要对这种颜色的RGB分量进行描述,只需要引用它的索引号,//就可以使用户选取自己需要的颜色。索引号的编码长度远远小于RGB分量的//编码长度,因此在彩色显示的同时,也大大减轻了系统的负担。 // 以256色调色板为例,调色板中存储256种颜色的RGB值,每种颜色的RGB值//是16位。用这256种颜色编制索引时,从00H~FFH只需要8位数据宽度,而每个//索引所对应的颜色却是16位宽度的颜色信息。在一些对色彩种类要求不高的场合,//如仪表终端、信息终端等,调色板技术便巧妙地解决了数据宽度与颜色深度之间//的矛盾。
驱动框架
驱动例子
#include <linux/delay.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/dma-mapping.h>#include <linux/interrupt.h>#include <linux/workqueue.h>#include <linux/wait.h>#include <linux/platform_device.h>#include <linux/clk.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/div64.h>#include <asm/mach/map.h>#include <asm/arch/regs-lcd.h>#include <asm/arch/regs-gpio.h>#include <asm/arch/fb.h>static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info);struct lcd_regs { unsigned long lcdcon1; unsigned long lcdcon2; unsigned long lcdcon3; unsigned long lcdcon4; unsigned long lcdcon5; unsigned long lcdsaddr1; unsigned long lcdsaddr2; unsigned long lcdsaddr3; unsigned long redlut; unsigned long greenlut; unsigned long bluelut; unsigned long reserved[9]; unsigned long dithmode; unsigned long tpal; unsigned long lcdintpnd; unsigned long lcdsrcpnd; unsigned long lcdintmsk; unsigned long lpcsel;};static struct fb_ops s3c_lcdfb_ops = { .owner = THIS_MODULE, .fb_setcolreg = s3c_lcdfb_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit,};static struct fb_info *s3c_lcd;static volatile unsigned long *gpbcon;static volatile unsigned long *gpbdat;static volatile unsigned long *gpccon;static volatile unsigned long *gpdcon;static volatile unsigned long *gpgcon;static volatile struct lcd_regs* lcd_regs;static u32 pseudo_palette[16];/* from pxafb.c */static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf){ chan &= 0xffff; chan >>= 16 - bf->length; return chan << bf->offset;}static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info){ unsigned int val; if (regno > 16) return 1; /* 用red,green,blue三原色构造出val */ val = chan_to_field(red, &info->var.red); val |= chan_to_field(green, &info->var.green); val |= chan_to_field(blue, &info->var.blue); //((u32 *)(info->pseudo_palette))[regno] = val; pseudo_palette[regno] = val; return 0;}static int lcd_init(void){ /* 1. 分配一个fb_info */ s3c_lcd = framebuffer_alloc(0, NULL); /* 2. 设置 */ /* 2.1 设置固定的参数 */ strcpy(s3c_lcd->fix.id, "mylcd"); s3c_lcd->fix.smem_len = 240*320*16/8; s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS; s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR; /* TFT */ s3c_lcd->fix.line_length = 240*2; /* 2.2 设置可变的参数 */ s3c_lcd->var.xres = 240; s3c_lcd->var.yres = 320; s3c_lcd->var.xres_virtual = 240; s3c_lcd->var.yres_virtual = 320; s3c_lcd->var.bits_per_pixel = 16; /* RGB:565 */ s3c_lcd->var.red.offset = 11; s3c_lcd->var.red.length = 5; s3c_lcd->var.green.offset = 5; s3c_lcd->var.green.length = 6; s3c_lcd->var.blue.offset = 0; s3c_lcd->var.blue.length = 5; s3c_lcd->var.activate = FB_ACTIVATE_NOW; /* 2.3 设置操作函数 */ s3c_lcd->fbops = &s3c_lcdfb_ops; /* 2.4 其他的设置 */ s3c_lcd->pseudo_palette = pseudo_palette; //s3c_lcd->screen_base = ; /* 显存的虚拟地址 */ s3c_lcd->screen_size = 240*324*16/8; /* 3. 硬件相关的操作 */ /* 3.1 配置GPIO用于LCD */ gpbcon = ioremap(0x56000010, 8); gpbdat = gpbcon+1; gpccon = ioremap(0x56000020, 4); gpdcon = ioremap(0x56000030, 4); gpgcon = ioremap(0x56000060, 4); *gpccon = 0xaaaaaaaa; /* GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND */ *gpdcon = 0xaaaaaaaa; /* GPIO管脚用于VD[23:8] */ *gpbcon &= ~(3); /* GPB0设置为输出引脚 */ *gpbcon |= 1; *gpbdat &= ~1; /* 输出低电平 */ *gpgcon |= (3<<8); /* GPG4用作LCD_PWREN */ /* 3.2 根据LCD手册设置LCD控制器, 比如VCLK的频率等 */ lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs)); /* bit[17:8]: VCLK = HCLK / [(CLKVAL+1) x 2], LCD手册P14 * 10MHz(100ns) = 100MHz / [(CLKVAL+1) x 2] * CLKVAL = 4 * bit[6:5]: 0b11, TFT LCD * bit[4:1]: 0b1100, 16 bpp for TFT * bit[0] : 0 = Disable the video output and the LCD control signal. */ lcd_regs->lcdcon1 = (4<<8) | (3<<5) | (0x0c<<1);#if 1 /* 垂直方向的时间参数 * bit[31:24]: VBPD, VSYNC之后再过多长时间才能发出第1行数据 * LCD手册 T0-T2-T1=4 * VBPD=3 * bit[23:14]: 多少行, 320, 所以LINEVAL=320-1=319 * bit[13:6] : VFPD, 发出最后一行数据之后,再过多长时间才发出VSYNC * LCD手册T2-T5=322-320=2, 所以VFPD=2-1=1 * bit[5:0] : VSPW, VSYNC信号的脉冲宽度, LCD手册T1=1, 所以VSPW=1-1=0 */ lcd_regs->lcdcon2 = (3<<24) | (319<<14) | (1<<6) | (0<<0); /* 水平方向的时间参数 * bit[25:19]: HBPD, VSYNC之后再过多长时间才能发出第1行数据 * LCD手册 T6-T7-T8=17 * HBPD=16 * bit[18:8]: 多少列, 240, 所以HOZVAL=240-1=239 * bit[7:0] : HFPD, 发出最后一行里最后一个象素数据之后,再过多长时间才发出HSYNC * LCD手册T8-T11=251-240=11, 所以HFPD=11-1=10 */ lcd_regs->lcdcon3 = (16<<19) | (239<<8) | (10<<0); /* 水平方向的同步信号 * bit[7:0] : HSPW, HSYNC信号的脉冲宽度, LCD手册T7=5, 所以HSPW=5-1=4 */ lcd_regs->lcdcon4 = 4;#elselcd_regs->lcdcon2 = S3C2410_LCDCON2_VBPD(5) | \ S3C2410_LCDCON2_LINEVAL(319) | \ S3C2410_LCDCON2_VFPD(3) | \ S3C2410_LCDCON2_VSPW(1);lcd_regs->lcdcon3 = S3C2410_LCDCON3_HBPD(10) | \ S3C2410_LCDCON3_HOZVAL(239) | \ S3C2410_LCDCON3_HFPD(1);lcd_regs->lcdcon4 = S3C2410_LCDCON4_MVAL(13) | \ S3C2410_LCDCON4_HSPW(0);#endif /* 信号的极性 * bit[11]: 1=565 format * bit[10]: 0 = The video data is fetched at VCLK falling edge * bit[9] : 1 = HSYNC信号要反转,即低电平有效 * bit[8] : 1 = VSYNC信号要反转,即低电平有效 * bit[6] : 0 = VDEN不用反转 * bit[3] : 0 = PWREN输出0 * bit[1] : 0 = BSWP * bit[0] : 1 = HWSWP 2440手册P413 */ lcd_regs->lcdcon5 = (1<<11) | (0<<10) | (1<<9) | (1<<8) | (1<<0); /* 3.3 分配显存(framebuffer), 并把地址告诉LCD控制器 */ s3c_lcd->screen_base = dma_alloc_writecombine(NULL, s3c_lcd->fix.smem_len, &s3c_lcd->fix.smem_start, GFP_KERNEL); lcd_regs->lcdsaddr1 = (s3c_lcd->fix.smem_start >> 1) & ~(3<<30); lcd_regs->lcdsaddr2 = ((s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len) >> 1) & 0x1fffff; lcd_regs->lcdsaddr3 = (240*16/16); /* 一行的长度(单位: 2字节) */ //s3c_lcd->fix.smem_start = xxx; /* 显存的物理地址 */ /* 启动LCD */ lcd_regs->lcdcon1 |= (1<<0); /* 使能LCD控制器 */ lcd_regs->lcdcon5 |= (1<<3); /* 使能LCD本身 */ *gpbdat |= 1; /* 输出高电平, 使能背光 */ /* 4. 注册 */ register_framebuffer(s3c_lcd); return 0;}static void lcd_exit(void){ unregister_framebuffer(s3c_lcd); lcd_regs->lcdcon1 &= ~(1<<0); /* 关闭LCD本身 */ *gpbdat &= ~1; /* 关闭背光 */ dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, s3c_lcd->screen_base, s3c_lcd->fix.smem_start); iounmap(lcd_regs); iounmap(gpbcon); iounmap(gpccon); iounmap(gpdcon); iounmap(gpgcon); framebuffer_release(s3c_lcd);}module_init(lcd_init);module_exit(lcd_exit);MODULE_LICENSE("GPL");
0 0
- linux lcd驱动分析二
- LCD(二) linux驱动分析
- LCD(二) linux驱动分析
- LCD(二) linux驱动分析
- Linux LCD驱动分析
- Linux-2.6.20的LCD驱动分析(二)[转]
- Linux-2.6.20的LCD驱动分析(二)[转]
- Linux-2.6.20的LCD驱动分析(二)
- Linux-2.6.38的LCD驱动分析(二)
- Linux-2.6.20的LCD驱动分析(二)
- Linux-2.6.38的LCD驱动分析(二)
- Linux-2.6.38的LCD驱动分析(二)
- linux lcd驱动分析一
- linux lcd驱动分析三
- linux lcd驱动分析四
- linux lcd驱动分析五
- Linux的LCD驱动分析
- Linux驱动:LCD驱动框架分析
- log4cxx样例
- php监控日志打印
- ACM第四次练习—1009
- C语言的内存布局
- php的断点调试
- LCD(二) linux驱动分析
- js---javaScript (if....else和switch...case的使用实例)
- JavaScript填坑史
- Linux多线程编程实例解析
- 山东省第七届ACM大学生程序设计竞赛-Fibonacci
- 进程与线程的一个简单解释
- linux在/etc/sysconf/network-scripts/ifcfg-DEVICE修改ip地址
- IT世界的三个重要思考点
- dpの谁在我前面