基于Linux的LCD驱动及测试代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <asm/io.h>
#include <asm/div64.h>

#include <asm/mach/map.h>
#include <mach/regs-gpio.h>

#define MHZ (1000*1000)
#define PRINT_MHZ(m) ((m) / MHZ), ((m / 1000) % 1000)
#define VSPW       9  
#define VBPD       13 
#define LINEVAL    479
#define VFPD       21 

#define HSPW       19 
#define HBPD       25 
#define HOZVAL     799
#define HFPD       209

#define LeftTopX     0
#define LeftTopY     0
#define RightBotX   799
#define RightBotY   479

static unsigned long *vidcon0; /* video control 0 */                          
static unsigned long *vidcon1; /* video control 1 */                          
//static unsigned long *vidcon2; /* video control 2 */                          
static unsigned long *vidtcon0; /* video time control 0 */                   
static unsigned long *vidtcon1; /* video time control 1 */                   
static unsigned long *vidtcon2; /* video time control 2 */
static unsigned long *wincon0; /* window control 0 */                         
static unsigned long *vidosd0a; /* video window 0 position control */        
static unsigned long *vidosd0b; /* video window 0 position control1 */       
static unsigned long *vidosd0c; /* video window 0 position control */
static unsigned long *vidw00add0b0; /* window 0 buffer start address, buffer 0 */
static unsigned long *vidw00add1b0; /* window 0 buffer end address, buffer 0 */  
static unsigned long *vidw00add2; /* window 0 buffer size */   
static unsigned long *wpalcon;
static unsigned long *shadowcon;


static unsigned long *gpf0con;
static unsigned long *gpf1con;
static unsigned long *gpf2con;
static unsigned long *gpf3con;
//static unsigned long *gpd0con;
//static unsigned long *gpd0dat;
//static unsigned long *clk_gate_block;
//static unsigned long *display_control;

static struct fb_info *s5pv210_lcd;

/*提供通用的操作接口,当然你还可以提供
自己私有的相关接口
*/
static struct fb_ops s5pv210_lcdfb_ops = {
.owner = THIS_MODULE,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};


static int s5pv210_lcd_init(void)
{
struct clk *s5pv210_clk;


/*1. 分配fb_info*/
s5pv210_lcd = framebuffer_alloc(0, NULL);


/*2. 初始化fb_info*/
/*2.1 初始化LCD固定参数信息*/
strcpy(s5pv210_lcd->fix.id, "s5pv210_lcd");
s5pv210_lcd->fix.smem_len = 800*480*4; //480*272*2
s5pv210_lcd->fix.type = FB_TYPE_PACKED_PIXELS;
s5pv210_lcd->fix.visual = FB_VISUAL_TRUECOLOR;
s5pv210_lcd->fix.line_length = 800*4; //480*2

/*
24位:888
16位:565
s5pv210_lcd->fix.smem_len = 800*480*2;
s5pv210_lcd->fix.line_length = 800*2;
*/
/*2.2 初始化可变参数*/
s5pv210_lcd->var.xres             = 800; //480
s5pv210_lcd->var.yres             = 480; //272
s5pv210_lcd->var.xres_virtual  = 800;  //480
s5pv210_lcd->var.yres_virtual  = 480; //272
s5pv210_lcd->var.bits_per_pixel = 32; //16
s5pv210_lcd->var.red.offset          = 16; //11
s5pv210_lcd->var.red.length         = 8; //5
s5pv210_lcd->var.green.offset       = 8; //5
s5pv210_lcd->var.green.length      = 8; //6
s5pv210_lcd->var.blue.offset         = 0; //0
s5pv210_lcd->var.blue.length        = 8; //5
s5pv210_lcd->var.activate             = FB_ACTIVATE_NOW;


/*提供底层LCD操作结构,如果没有read,write,
ioctl,mmap,核心层给你实现
*/
s5pv210_lcd->fbops = &s5pv210_lcdfb_ops;
s5pv210_lcd->screen_size = 800*480*4; //4//480*272*2


//GPIO的复用处理
gpf0con = ioremap(0xE0200120,4);
gpf1con = ioremap(0xE0200140,4);
gpf2con = ioremap(0xE0200160,4);
gpf3con = ioremap(0xE0200180,4);
//gpd0con = ioremap(0xE02000A0,4);
//gpd0dat = ioremap(0xE02000A4,4);
*gpf0con = 0x22222222;// GPF0[7:0]
*gpf1con = 0x22222222;// GPF1[7:0]
*gpf2con = 0x22222222;// GPF2[7:0]
*gpf3con = 0x22222222;// GPF3[7:0]
//*gpd0con |= 1<<4;
//*gpd0dat |= 1<<1;


//内核为了实现电源管理,对于CPU的偏上I2C,每一个
//的时钟都是独立的,内核通过链表的形式来进行管理
//获取内核LCD时钟
s5pv210_clk = clk_get(NULL, "lcd");
if (!s5pv210_clk || IS_ERR(s5pv210_clk)) {
printk(KERN_INFO "failed to get lcd clock source\n");
}
//打开LCD时钟
clk_enable(s5pv210_clk);


//初始化LCD寄存器
//display_control = ioremap(0xe0107008,4);
vidcon0 = ioremap(0xF8000000,4);
vidcon1 = ioremap(0xF8000004,4);
wincon0 = ioremap(0xF8000020,4);
vidosd0a = ioremap(0xF8000040,4);
vidosd0b = ioremap(0xF8000044,4);
vidosd0c = ioremap(0xF8000048,4);
vidw00add0b0  = ioremap(0xF80000A0,4);
vidw00add1b0  = ioremap(0xF80000D0,4);
vidw00add2  = ioremap(0xF8000100,4);
vidtcon0  = ioremap(0xF8000010,4);
vidtcon1  = ioremap(0xF8000014,4);
vidtcon2  = ioremap(0xF8000018,4);
wpalcon  = ioremap(0xF80001A0,4);
shadowcon  = ioremap(0xF8000034,4);

//*display_control = 2<<0;
    //Page 1222
    //跟具体的CPU相关了
*vidcon0 &= ~((3<<26) | (1<<18) | (0xff<<6)  | (1<<2));  
       /* RGB I/F, RGB Parallel format,  */
*vidcon0 |= ((4<<6) | (1<<4) );     
       /* Divided by CLKVAL_F,vclk== HCLK / (CLKVAL+1) = 166.75/5 = 33.35MHz */


//1211
*vidcon1 &= ~(1<<7);   
*vidcon1 |= ((1<<6) | (1<<5));  


//设置通用的时间参数信息
*vidtcon0 = (VBPD << 16) | (VFPD << 8) | (VSPW << 0);
*vidtcon1 = (HBPD << 16) | (HFPD << 8) | (HSPW << 0);
*vidtcon2 = (LINEVAL << 11) | (HOZVAL << 0);


//特定LCD寄存器的初始化
*wincon0 &= ~(0xf << 2);
*wincon0 |= (0xB<<2)/*|(1<<15)*/;
*vidosd0a = (LeftTopX<<11) | (LeftTopY << 0);
*vidosd0b = (RightBotX<<11) | (RightBotY << 0);
*vidosd0c = (LINEVAL + 1) * (HOZVAL + 1);


//让内核帮你分配一个显存的起始物理地址,并且分配
//对应物理地址的内核虚拟地址
//起始物理地址:smem_start
//起始内核虚拟地址:screen_base
s5pv210_lcd->screen_base = dma_alloc_writecombine(NULL,
                        s5pv210_lcd->fix.smem_len,
                        (dma_addr_t *)&s5pv210_lcd->fix.smem_start, 
GFP_KERNEL);


//通过的硬件初始化
//告诉CPU显存的起始物理地址和起始结束地址
//将这两地址设置到LCD对应的寄存器中即可
*vidw00add0b0 = s5pv210_lcd->fix.smem_start; 
*vidw00add1b0 = s5pv210_lcd->fix.smem_start 
+ s5pv210_lcd->fix.smem_len; 


//启动LCD控制器,等待用户访问操作显存
*shadowcon = 0x1;
*vidcon0 |= 0x3; 
*wincon0 |= 1;   


//向核心层注册fb_info
register_framebuffer(s5pv210_lcd);
return 0;
}


static void s5pv210_lcd_exit(void)
{
unregister_framebuffer(s5pv210_lcd);
dma_free_writecombine(NULL, 
s5pv210_lcd->fix.smem_len, 
s5pv210_lcd->screen_base, 
s5pv210_lcd->fix.smem_start);
iounmap(gpf0con);
iounmap(gpf1con);
iounmap(gpf2con);
iounmap(gpf3con);
iounmap(vidcon0);
iounmap(vidcon1);
iounmap(vidtcon2);
iounmap(wincon0);
iounmap(vidosd0a);
iounmap(vidosd0b);
iounmap(vidosd0c);
iounmap(vidw00add0b0);
iounmap(vidw00add1b0);
iounmap(vidw00add2);
iounmap(vidtcon0);
iounmap(vidtcon1);
iounmap(shadowcon);
framebuffer_release(s5pv210_lcd);
}

module_init(s5pv210_lcd_init);
module_exit(s5pv210_lcd_exit);

MODULE_LICENSE("GPL");

*************************************************************************

                               测试代码:

*************************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/fb.h>

#define COLOR_RED 0x000000FF
#define COLOR_GREEN 0x0000FF00
#define COLOR_BLUE 0x00FF0000


int fdfb = -1;


struct fb_fix_screeninfo fbfix = { 0 };
struct fb_var_screeninfo fbvar = { 0 };
long screensize = 0;


int *fb32 = NULL;


int x = 0;
int y = 0;
long location = 0;


int main(int argc, char **argv)
{
// open framebuffer device
fdfb = open( argv[1], O_RDWR );
if( 0 > fdfb ) {
printf("Failure to open framebuffer device: /dev/fb0 !\n");
exit( -1 );
}
printf("Success to open framebuffer device: /dev/fb0 !\n");


// get fixed screen information
if( ioctl( fdfb, FBIOGET_FSCREENINFO, &fbfix ) ) {
printf("Failure to get fixed screen information !\n");
exit( -2 );
}
printf("Success to get fixed screen information !\n");


// get varible screen information
if( ioctl( fdfb, FBIOGET_VSCREENINFO, &fbvar ) ) {
printf("Failure to get varible screen information !\n");
exit( -3 );
}
printf("Success to get varible screen information !\n");


// calculate the number of bytes for screen size
screensize = fbvar.xres * fbvar.yres * ( fbvar.bits_per_pixel / 8 );
printf("sceeninfo.xres = %d, screeninfo.yres = %d, screeninfo.bits_per_pixel = %dbpp, screensize = %d !\n", fbvar.xres, fbvar.yres, fbvar.bits_per_pixel, screensize);


// mmap framebuffer to process memory space
fb32 = (int *)mmap( 0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fdfb, 0 );
if( NULL == fb32 ) {
printf("Failure to map framebuffer device memory to process's memory !\n");
exit( -4 );
}
printf("Success to map framebuffer device memory to process's memory !\n");


// draw pixel
if( 8 == fbvar.bits_per_pixel ) {
printf("Starting 8 bpp framebuffer test...\n");
}
else if( 16 == fbvar.bits_per_pixel ) {
printf("Starting 16 bpp framebuffer test...\n");


}
else if( 24 == fbvar.bits_per_pixel ) {
printf("Starting 24 bpp framebuffer test...\n");
}
else {
printf("Supporting 32 bpp !\n");
// draw red color area
printf("Starting to show RED area !\n");
for( y = 0; y < fbvar.yres / 3; y++ ) {
for( x = 0; x < fbvar.xres; x++ ) {
*( fb32 + y * fbvar.xres + x ) = COLOR_RED;
}
}


// draw green color area
printf("Starting to show GREEN area !\n");
for( y = ( fbvar.yres / 3 ); y < ( fbvar.yres * 2 / 3); y++ ) {
for( x = 0; x < fbvar.xres; x++ ) {
*( fb32 + y * fbvar.xres + x ) = COLOR_GREEN;
}
}


// draw blue color area 
printf("Starting to show BLUE area !\n");
for( y = ( fbvar.yres * 2 / 3 ); y < fbvar.yres; y++ ) {
for( x = 0; x < fbvar.xres; x++ ) {
*( fb32 + y * fbvar.xres + x ) = COLOR_BLUE;
}
}
}


// unmap framebuffer memory
munmap( fb32, screensize );


printf("Finished to demo to operate framebuffer !\n");


// close device handle
close( fdfb );


return 0;
}




  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值