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

本文档是看韦东山老师的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");



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值