您的位置:首页 > 其它

mini2440驱动分析之LCD

2013-09-05 20:37 423 查看



[日期:2011-10-04]来源:Linux社区 作者:yaozhenguo2006[字体:大 中 小]
mini2440集成了lcd控制器的接口,板子上接的lcd硬件是统宝240*320,TFT型lcd。lcd驱动对应的文件为s3c2410fb.c。要读懂这个驱动必须了解linux platform子系统的知识。因为这个驱动是以platform驱动的形式注册到内核。而且还需要frambuffer驱动的知识,因为这个驱动还是frambuffer接口的。lcd驱动在模块初始化的时候,调用platform注册函数将自己注册到内核,利用linux设备模型核心的机制调用platform_bus总线的match函数找到相应的设备,然后由linux设备模型核心调用s3c2410fb.c中的s3c2410fb_probe
,进行硬件相关初始化,并初始化frambuffer结构。然后注册到frambuffer核心。lcd的功能实现通过frambuffer核心来完成。s3c2410fb.c的功能实现都是配合frambuffer核心的。下面详细分析lcd驱动的实现。

程序基本结构

1.模块初始化-->向platform核心注册自己

2.实现linux设备模型必须的probe函数-->向frambuffer核心注册自己(最重要)

resume函数-->系统在由挂起恢复的时候调用

suspand-->系统在挂起的时候调用

remove--> 驱动程序注销自己的时候调用

3.frambuffer驱动模型fb_ops各函数的实现-->实现fb驱动的ioctl命令需要的函数

4.其他函数-->由2.3.中的函数调用,帮助其实现功能。

一. 相关数据结构

1. struct fb_info 结构

struct 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; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image hardware mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper */
struct fb_cmap cmap; /* Current cmap */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode */

#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 */
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops; /* Tile Blitting */
#endif
char __iomem *screen_base; /* Virtual address */
unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
void *pseudo_palette; /* Fake palette of 16 colors */
#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;
/* we need the PCI or similiar aperture base/size not
smem_start/size as smem_start may just be an object
allocated inside the aperture so may not actually overlap */
resource_size_t aperture_base;
resource_size_t aperture_size;
};

这个结构是frambuffer驱动的基本数据结构,里面包含了帧缓存设备的所有信息,每一个注册成frambuffer接口的设备都应该声明并初始化这样一个结构。register_framebuffer 函数的参数就是这样一个结构,fb_info在mini2440lcd驱动中是在s3c24xxfb_probe函数中分配并初始化的。其中struct fb_var_screeninfo结构包含了lcd显示中可以改变的信息,结构如下:

struct fb_var_screeninfo {
__u32 xres; /* 视口水平分辨率 */
__u32 yres;
__u32 xres_virtual; /* 虚拟屏幕水平分辨率 */
__u32 yres_virtual;
__u32 xoffset; /* 视口与虚拟屏幕水平分辨率偏移 */
__u32 yoffset;

__u32 bits_per_pixel; /* 像素的位数 */
__u32 grayscale; /* 灰度标志,如果为1代表是灰度 */

struct fb_bitfield red; /* 如果是真彩色,这个是颜色位,如果不是那么只有结构的大小重要,其他表示的信息无关紧要 */
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp; /* 透明度 */

__u32 nonstd; /* 非标准颜色表示标志位 */
__u32 activate; /* 参照 FB_ACTIVATE_* */
__u32 height; /* 在内存地址空间的长度 */
__u32 width; /* 在内存地址空间的宽度 */

__u32 accel_flags; /* (不用了) 参照 fb_info.flags */

/* 时序: 以下所有的值单位都是pixclock, 当然除了pixclock */
__u32 pixclock; /* 每秒像素值 */
__u32 left_margin; /* 从sync信号到显示真正的像素的时钟个数 */
__u32 right_margin; /* 从真正显示像素到sync信号的时钟个数 */
__u32 upper_margin; /* 上面两个是针对列像素的,这个针对行的 */
__u32 lower_margin;
__u32 hsync_len; /* 水平sync信号的长度 */
__u32 vsync_len; /* 垂直sync信号的长度 */
__u32 sync; /* 参照 FB_SYNC_* */
__u32 vmode; /* 参照 FB_VMODE_* */
__u32 rotate; /* angle we rotate counter clockwise */
__u32 reserved[5]; /* 保留 */
};

fb_fix_screeninfo包含了lcd显示中不可改变的信息,结构如下:

struct fb_fix_screeninfo {
char id[16]; /* 身份表示符,例如 "TT Builtin" */
unsigned long smem_start; /* frame buffer内存的开始地址 */
/* (物理地址) */
__u32 smem_len; /* frame buffer内存地址的长度 */
__u32 type; /* 参照 FB_TYPE_* */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /* 参照 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; /* 每行的长度,单位字节 */
unsigned long mmio_start; /* I/O 内存的开始地址 */
/* (物理地址) */
__u32 mmio_len; /* I/O内存的长度 */
__u32 accel; /* 对驱动程序的标示:是哪个设备*/
__u16 reserved[3]; /* 保留 */
};

其中倒数第三个成员par是设备自定义数据结构。在mini2440lcd驱动中为s3c2410fb_info,结构如下:

struct s3c2410fb_info {
struct device *dev;
struct clk *clk;

struct resource *mem; //io内存物理地址也就是寄存器的地址
void __iomem *io; //用ioremap映射的io虚拟地址
void __iomem *irq_base; //中断控制器寄存器对应的虚拟地址

enum s3c_drv_type drv_type;
struct s3c2410fb_hw regs;

unsigned long clk_rate;
unsigned int palette_ready;

#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif

/* keep these registers in case we need to re-write palette */
u32 palette_buffer[256];
u32 pseudo_pal[16];
};

这个结构是和硬件相关的,包括寄存器的物理地址,虚拟地址和调色板的一些信息。这个结构也是在s3c24xxfb_probe中分配并初始化。

2. static struct fb_ops 结构

在mini2440lcd驱动中,fb_ops的初始化代码如下:

static struct fb_ops s3c2410fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = s3c2410fb_check_var,
.fb_set_par = s3c2410fb_set_par,
.fb_blank = s3c2410fb_blank,
.fb_setcolreg = s3c2410fb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};

这些函数是驱动程序必须实现的,他们实现的功能对应frambuffer核心的Ioctl系统调用,当应用程序调用ioctl系统调用的时候,他们会被直接或间接的调用。其中:

s3c2410fb_check_var 和s3c2410fb_set_par会由fb_set_var调用,对应Ioctl的FBIOPUT_VSCREENINFO命令

s3c2410fb_blank ,对应ioctl的FBIOBLANK命令,其他几个函数也是类似。

3. struct s3c2410fb_mach_info 结构

struct s3c2410fb_mach_info {
struct s3c2410fb_display *displays; /* attached diplays info */
unsigned num_displays; /* number of defined displays */
unsigned default_display;
/* GPIOs */
unsigned long gpcup;
unsigned long gpcup_mask;
unsigned long gpccon;
unsigned long gpccon_mask;
unsigned long gpdup;
unsigned long gpdup_mask;
unsigned long gpdcon;
unsigned long gpdcon_mask;

/* lpc3600 control register */
unsigned long lpcsel;
};

这个结构包括一个s3c2410fb_display结构体,其他的域是GPIO寄存器的信息。mini2440lcd驱动中定义并初始化了这样一个结构体:

static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
.displays = &mini2440_lcd_cfg,
.num_displays = 1,
.default_display = 0,

.gpccon = 0xaa955699,
.gpccon_mask = 0xffc003cc,
.gpcup = 0x0000ffff,
.gpcup_mask = 0xffffffff,

.gpdcon = 0xaa95aaa1,
.gpdcon_mask = 0xffc0fff0,
.gpdup = 0x0000faff,
.gpdup_mask = 0xffffffff,

.lpcsel = 0xf82,
};

这里初始化了结构中的所有成员,s3c2410fb_display结构初始化成mini2440_lcd_cfg,这个结构的初始化是在/arch/arm/mach-s3c2440/mach-mini2440.c这个文件中。这里设置了s3c2440 lcd控制器对应的GPIO寄存器的初始值,在s3c2410fb_init_registers函数中将这些值写到相应的寄存器中。

4. s3c2410fb_display 结构

struct s3c2410fb_display {
/* LCD type */
unsigned type;

/* Screen size */
unsigned short width;
unsigned short height;

/* Screen info */
unsigned short xres;
unsigned short yres;
unsigned short bpp;

unsigned pixclock; /* pixclock in picoseconds */
unsigned short left_margin; /* value in pixels (TFT) or HCLKs (STN) */
unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */
unsigned short hsync_len; /* value in pixels (TFT) or HCLKs (STN) */
unsigned short upper_margin; /* value in lines (TFT) or 0 (STN) */
unsigned short lower_margin; /* value in lines (TFT) or 0 (STN) */
unsigned short vsync_len; /* value in lines (TFT) or 0 (STN) */

/* lcd configuration registers */
unsigned long lcdcon5;
};

这个结构体非常重要,他包括了一个lcd显示的所有必须的配置信息。程序就是用这个结构体初始化fb_info结构中的fb_var_screeninfo相关成员的。最后这些值都会写进lcd控制器的相应寄存器中。如上分析,这个结构在mini2440lcd驱动中被初始化成了mini2440_lcd_cfg,他定义在/arch/arm/mach-s3c2440/mach-mini2440.c,如下所示:

static struct s3c2410fb_display mini2440_lcd_cfg __initdata = {

#if !defined (LCD_CON5)
.lcdcon5 = S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVLINE |
S3C2410_LCDCON5_INVVFRAME |
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_HWSWP,
#else
.lcdcon5 = LCD_CON5,
#endif
.type = S3C2410_LCDCON1_TFT,
.width = LCD_WIDTH,
.height = LCD_HEIGHT,
.pixclock = LCD_PIXCLOCK,
.xres = LCD_WIDTH,
.yres = LCD_HEIGHT,
.bpp = 16,
.left_margin = LCD_LEFT_MARGIN + 1,
.right_margin = LCD_RIGHT_MARGIN + 1,
.hsync_len = LCD_HSYNC_LEN + 1,
.upper_margin = LCD_UPPER_MARGIN + 1,
.lower_margin = LCD_LOWER_MARGIN + 1,
.vsync_len = LCD_VSYNC_LEN + 1,
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: