您的位置:首页 > 其它

s3c2440的LCD驱动程序--转韦东山

2016-09-08 16:06 211 查看
本文档是看韦东山老师的LCD驱动视频手打下来的,所以可能会提示头文件找不到啊之类的,呵呵。另外cfb_fillrect.ko,cfb_copyarea.ko ,cfb_imageblit.ko这三个模块可以在内核的/drivers/video找到

#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/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,

/*这三个函数分别由三个模块(在drivers/vedio目录下)来具体实现,然后一起加载,它们经常用到,所以这里不用实现他们*/
.fb_fillrect =cfb_fillrect,/*填充矩形 */
.fb_copyarea =cfb_copyarea,/*拷贝一个区域*/
.fb_imageblit =cfb_imageblit,
};

static struct fb_info *s3c_lcd;/*分配info结构体*/
/*GPIO控制器*/
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];/*假的调色板*/

/*调色板函数*/
/*5:6:5 format*/
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
*其中分配时fb_info里面的值默认都是0,所有下面有些参数可以不用设置默认0
*/
s3c_lcd=framebuffer_alloc(0,NULL); /*其中0代表不需要额外的私有数据空间*/
/*2.设置*/
/*2.1设置固定的参数*/
strcpy(s3c_lcd->fix.id,"mylcd"); /*设置fix的名称*/
s3c_lcd->fix.smem_len =240*320*16; /*按具体的屏幕--设置一帧的大小*/
s3c_lcd->fix.type =FB_TYPE_PACKED_PIXELS;/*默认值0*/
s3c_lcd->fix.visual =FB_VISUAL_TRUECOLOR; /*TFT真彩色*/
s3c_lcd->fix.line_lenth =240*2; /*一行的长度大小。。单位byte*/
/*2.2设置可变的参数*/
s3c_lcd->var.xres =240; /*x方向的分辨率*/
s3c_lcd->var.yres =320; /*y方向的分辨率*/
s3c_lcd->var.xres_virtual =240; /*x方向的虚拟分辨率*/
s3c_lcd->var.xres_virtual =320; /*y方向的虚拟分辨率*/
s3c_lcd->var.bits_per_pixel =16; /*每个像素16位--bpp*/

/*RGB--5:6:5*/
s3c_lcd->var.red.offset =11; /*第11位开始*/
s3c_lcd->var.red.length =5; /*长度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*320*2; /*屏幕的大小,单位byte*/

/*3.硬件相关的设置*/
/*3.1配置GPIO用于LCD*/
gpbcon=ioremap(0x56000010,8);
gpbdat=gpbcon+1;/*相当于+4 byte*/
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);/*GPBO设置为输出引脚*/
*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)*2],LCD手册P14
* 10MHz=100MHz/[CLKVAL+1]*2]
* 10MHz是我们2440手册里的100ns得出的(1us->1MHz)
* 100MHz是我们主机的频率
* CLKVAL=4
*bit[6:5]: ob11,TFT LCD
*bit[4:1]: ob1100,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);

/*垂直方向的时间参数
*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,HSYNC之后再过多长时间才能发出第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<<9) | (10<<0);

/*水平方向的同步信号
*bit[7:0]:HSPW,HSYNC信号的脉冲宽度,LCD手册T7=5,所以HSPW=5-1=4
*/
lcd_regs->lcdcon4=4;

/*信号的极性
*bit[11]: 1=5:6:5 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
*下面两位控制在framebuffer中[0:31]->[P1,P2]还是[p2,p1]
*bit[1]: 0=BSWP
*bit[0]: 1=HWSWP 2440手册P413
*很明显是[p1,p2]
*/
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);

/*lcdsaddr1的bit[29:0]对应A[30:1],最低1位不要,所以右移一位--最高两位不需要--清0*/
lcd_regs->lcdsaddr1=(s3c_lcd->fix.smem_start>>1) & ~(3<<30);

/*lcsaddr2的bit[20:0]对应A[21:1],所以最低一位不需要,右移一位,其他位清0*/
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)
{
unrigster_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");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: