s3c2440-lcd驱动与帧缓冲
注意:本文是主要参考《S3C2440上LCD驱动详解》,《S3c2410_LCD驱动学习心得》,《嵌入式linux_Framebuffer驱动开发》部分直接搬过来。
一、帧缓冲机制
在谈到lcd驱动时,先谈谈,帧缓冲机制,为什么呢?因为Linux系统是工作在保护模式下,所以用户态进程无法像DOS那要使用显卡BIOS里提供的中断调用来实现直接写屏蔽,Framebuffer是出现在linux 2.2及以后的一种驱动程序接口,它是一项重要技术,基本上都是用它来实现图形界面的。
下面是LCD驱动程序与应用程序以及帧缓冲机制的关系
应用程序要操作LCD,就操作设备节点(/dev/fb0由帧缓冲创建),fbmem.c是提供应用程序的操作接口,fbmem.c本身并不实现这些功能,这就需要下一层接口实现,就是XXXfb.c要实现的与lcd底层硬件相关的操作接口。具体可以参考s3c2410fb.c。
帧缓冲技术是与LCD驱动混在一起从而形成帧缓冲LCD设备驱动程序,主要是由下面几个重要数据结构起关联。
1、Struct fb_info
Struct fb_info这结构记录了帧缓冲设备的全部信息,包括设备的设置参数、状态、以及对底层硬件操作的函数指针。下面具体分析一下。
int node;
int flags;
struct fb_var_screeninfo var; /*LCD可变参数结构体 */
struct fb_fix_screeninfo fix; /* LCD固定参数结构体 */
struct fb_monspecs monspecs; /* LCD显示器标准 */
struct work_struct 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; /* 当前的显示模式 */
#ifdef CONFIG_FB_BACKLIGHT
struct backlight_device *bl_dev;/*对应背光设备*/
/* Backlight level curve */
struct mutex bl_curve_mutex;
u8 bl_curve[FB_BACKLIGHT_LEVELS];/*背光调整*/
#endif
。。。。。。。。
struct fb_ops *fbops;/*对底层硬件操作的函数指针*/
……
struct device *dev; /* FB设备 */
……
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops; /*图块 Blitting */
#endif
char __iomem *screen_base; /* 虚拟基地址 */
unsigned long screen_size; /* LCD IO 映射的虚拟内存大小*/
void *pseudo_palette; /*伪16色颜色表 */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state; /* LCD挂起或者恢复的状态*/
void *fbcon_par; /* fbcon use-only private area */
/* From here on everything is device dependent */
void *par;
};
其中比较重要的就是struct fb_var_screeninfo var; struct fb_fix_screeninfo fix;
跟struct fb_ops *fbops;
下面各自分析一下
2、struct fb_var_screeninfo
struct fb_var_screeninfo 主要是记录用户可以修改的控制器可变参数
__u32 xres; /* 可见屏幕一行有多少个像素点*/
__u32 yres; /*可见屏幕一列有多少个像素点*/
__u32 xres_virtual; /*虚拟屏幕一列有多少个像素点*/
__u32 yres_virtual; /*虚拟屏幕一列有多少个像素点*/
__u32 xoffset; /* 虚拟到可见屏幕之间的行偏移*/
__u32 yoffset; /*虚拟到可见屏幕之间的列偏移 */
__u32 bits_per_pixel; /* 每个像素由多少位组成即BPP*/
__u32 grayscale; /* != 0 Graylevels instead of colors */
/*fb缓存的RGB位域*/
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; /*高度mm*/
__u32 width; /* 宽度 mm*/
__u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
/*时间选择:除了像素时钟外,所有的值都以像素时钟为单位*/
/* Timing: All values in pixclocks(像素时钟), except pixclock (of course) */
__u32 pixclock; /* 像素时钟(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 */
};
3、struct fb_fix_screeninfo
而struct fb_fix_screeninfo fix;就是固定的控制器配置,比如屏幕缓冲区的物理地址和长度,定义如下:
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; /* 没硬件panning就置0zero if no hardware panning */
__u16 ypanstep; /*没硬件panning就置0 zero if no hardware panning */
__u16 ywrapstep; /*没硬件ywrap就置0 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 */
};
4、struct fb_ops
struct fb_ops,帧缓冲操作,关联硬件跟应用程序。
* Frame buffer operations
*
* LOCKING NOTE: those functions must _ALL_ be called with the console
* semaphore held, this is the only suitable locking mechanism we have
* in 2.6. Some may be called at interrupt time at this point though.
*/
struct fb_ops {
/* open/release and usage marking */
struct module *owner;
。。。。。。
/*检查可变参数并进行设置*/
/* checks var and eventually tweaks it to something supported,
* DO NOT MODIFY PAR */
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
//根据设置的值进行更新,根据info->var
/* set the video mode according to info->var */
int (*fb_set_par)(struct fb_info *info);
//设置颜色寄存器
/* set color register */
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info);
/* set color registers in batch */
int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
//显示空白
/* blank display */
int (*fb_blank)(int blank, struct fb_info *info);
//矩形填充
/* pan display */
int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
/* Draws a rectangle */
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
/* Copy data from area to another */
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
/* Draws a image to the display */
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
/* Draws cursor */
int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
/* Rotates the display */
void (*fb_rotate)(struct fb_info *info, int angle);
/* wait for blit idle, optional */
int (*fb_sync)(struct fb_info *info);
/* perform fb specific ioctl (optional) */
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
unsigned long arg);
/* Handle 32bit compat ioctl (optional) */
int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
unsigned long arg);
/* perform fb specific mmap */
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
/* save current hardware state */
void (*fb_save_state)(struct fb_info *info);
/* restore saved state */
void (*fb_restore_state)(struct fb_info *info);
/* get capability given var */
void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
struct fb_var_screeninfo *var);
};
5、帧缓冲设备以及设备资源
LCD帧缓冲设备在Linux里是作为一个平台设备,在内核arch/arm/plat-s3c24xx/devs.c中定义LCD相关平台设备如下:
static struct resource s3c_lcd_resource[] = {
[0] = {
.start = S3C24XX_PA_LCD,//寄存器的开始地址
.end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,//长度
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}
};
static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
struct platform_device s3c_device_lcd = {
.name = "s3c2410-lcd",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_lcd_resource),资源数量
.resource = s3c_lcd_resource,
.dev = {
.dma_mask = &s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
EXPORT_SYMBOL(s3c_device_lcd);
这里导出s3c_device_lcd是为了在arch/asm/mach-s3c2410/mach-smdk2410.c里的smdk2410_devices[](或者其它smdk2440_devices[])中添加到平台设备列表中。
下面准备分析具体实例,但分析前还要了解LCD的特性以及读写时序。
实在不如别人做得漂亮,做得详细,大家还是去看原文吧,我这里就不接了。
二、LCD的硬件知识
1. LCD工作的硬件需求:
要使一块 LCD正常的显示文字或图像,不仅需要 LCD驱动器,而且还需要
相应的 LCD控制器。在通常情况下,生产厂商把LCD驱动器会以 COF/COG
的形式与 LCD玻璃基板制作在一起,而 LCD控制器则是由外部的电路来实现,
现在很多的 MCU内部都集成了 LCD控制器, 如 S3C2410/2440 等。 通过LCD
控制器就可以产生LCD驱动器所需要的控制信号来控制STN/TFT 屏了。
2. S3C2440内部 LCD 控制器结构图:
我们根据数据手册来描述一下这个集成在 S3C2440 内部的 LCD控制器:
a:LCD控制器由REGBANK、LCDCDMA、TIMEGEN、VIDPRCS寄存器组
成;
b:REGBANK由 17个可编程的寄存器组和一块 256*16 的调色板内存组成,
它们用来配置 LCD控制器的;
c:LCDCDMA是一个专用的 DMA,它能自动地把在侦内存中的视频数据传送
到 LCD驱动器,通过使用这个 DMA通道,视频数据在不需要 CPU的干预的情
况下显示在 LCD屏上;
d:VIDPRCS接收来自 LCDCDMA的数据,将数据转换为合适的数据格式,比
如说 4/8 位单扫,4 位双扫显示模式,然后通过数据端口 VD[23:0]传送视频数
据到 LCD驱动器;
……
在这里我加上《S3c2410 LCD驱动学习心得》因为这里面分析如何确定驱动里的lcd配置参数写得很明白
S3C2410实验箱上的LCD是一款3.5寸TFT真彩LCD屏,分辩率为240*320,下图为该屏的时序要求。
图1.3
通过对比图1.2和图1.3,我们不难看出:
VSPW+1=2 -> VSPW=1
VBPD+1=2 -> VBPD=1
LINVAL+1=320-> LINVAL=319
VFPD+1=3 -> VFPD=2
HSPW+1=4 -> HSPW=3
HBPD+1=7 -> HBPW=6
HOZVAL+1=240-> HOZVAL=239
HFPD+1=31 -> HFPD=30
以上各参数,除了LINVAL和HOZVAL