ok6410的LCD驱动

经过 几天的研究 终于在飞凌的6410板子上的LCD出现了一些字符,虽然还有些不完美 就是那些字符不清晰,先写下来,我继续调这个bug。

飞凌的开发板首先要屏蔽自身的LCD驱动,在上一篇的博客中已经说过,这里不说了。我的代码 也是参考了别人了的,都大同小异,我感觉最大的区别可能是飞凌的板子LCD的电源控制和背光控制不需要人为控制,他的硬件是直接连通,上电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/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>

static struct fb_info *s3c_lcd_info;
static u32 s3c_pseudo_palette[16];

static volatile unsigned long *gpbcon;
static volatile unsigned long *gpbdat;
static volatile unsigned long *gpfcon;
static volatile unsigned long *gpfdat;
static volatile unsigned long *gpicon;
static volatile unsigned long *gpjcon;

static volatile unsigned long *mifpcon;
static volatile unsigned long *spcon;



struct s3c6410_lcd_regs {
	unsigned long vidcon0;
	unsigned long vidcon1;
	unsigned long vidcon2;
	unsigned long reserver1;
	unsigned long vidtcon0;
	unsigned long vidtcon1;
	unsigned long vidtcon2;
	unsigned long reserver2;
	unsigned long wincon0;
	unsigned long wincon1;
	unsigned long wincon2;
	unsigned long wincon3;
	unsigned long wincon4;
	unsigned long reserver3[3];
	unsigned long vidosd0a;
	unsigned long vidosd0b;
	unsigned long vidosd0c;
	unsigned long reserver4;
	unsigned long vidosd1a;
	unsigned long vidosd1b;
	unsigned long vidosd1c;
	unsigned long vidosd1d;
	unsigned long vidosd2a;
	unsigned long vidosd2b;
	unsigned long vidosd2c;
	unsigned long vidosd2d;
	unsigned long vidosd3a;
	unsigned long vidosd3b;
	unsigned long vidosd3c;
	unsigned long reserver5;
	unsigned long vidosd4a;
	unsigned long vidosd4b;
	unsigned long vidosd4c;
	unsigned long reserver6[5];
	unsigned long vidw00add0b0;
	unsigned long vidw00add0b1;
	unsigned long vidw01add0b0;
	unsigned long vidw01add0b1;
	unsigned long vidw02add0;
	unsigned long reserver7;
	unsigned long vidw03add0;
	unsigned long reserver8;
	unsigned long vidw04add0;
	unsigned long reserver9[3];
	unsigned long vidw00add1b0;
	unsigned long vidw00add1b1;
};

static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
{
	chan &= 0xffff;
	chan >>= 16 - bf->length;
	return chan << bf->offset;
}

static int s3c_fb_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;
	u32 *pal = info->pseudo_palette;

	/* 用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);
	
	
	pal[regno] = val;
	return 0;
}

static struct fb_ops s3c_fb_ops = {
	.owner = THIS_MODULE,
	.fb_setcolreg	= s3c_fb_setcolreg,
	.fb_fillrect	= cfb_fillrect,
	.fb_copyarea	= cfb_copyarea,
	.fb_imageblit	= cfb_imageblit,
};

static struct s3c6410_lcd_regs * lcd_regs;

static int s3c_lcd_init(void)
{
	struct clk *clk;
	int hclk;
	int clkval;
	
	/* 1. 分配fb_info */
	s3c_lcd_info = framebuffer_alloc(0, NULL);

	/* 2. 设置 */
	/* 2.1 设置固定的信息 */
	strcpy(s3c_lcd_info->fix.id, "uplooking_lcd");

	s3c_lcd_info->fix.smem_len    = 480*272*2;
	s3c_lcd_info->fix.type        = FB_TYPE_PACKED_PIXELS;
	s3c_lcd_info->fix.visual      = FB_VISUAL_TRUECOLOR;
	s3c_lcd_info->fix.line_length = 480*2;
	
	/* 2.2 设置可变的信息 */
	s3c_lcd_info->var.xres           = 480;
	s3c_lcd_info->var.yres           = 272;
	s3c_lcd_info->var.xres_virtual   = 480;
	s3c_lcd_info->var.yres_virtual   = 272;
	s3c_lcd_info->var.bits_per_pixel = 16;

	
	s3c_lcd_info->var.red.length     = 5;
	s3c_lcd_info->var.red.offset     = 11;

	s3c_lcd_info->var.green.length     = 6;
	s3c_lcd_info->var.green.offset     = 5;

	s3c_lcd_info->var.blue.length     = 5;
	s3c_lcd_info->var.blue.offset     = 0;

	s3c_lcd_info->var.activate        = FB_ACTIVATE_NOW;

	/* 2.3 设置操作函数 */
	s3c_lcd_info->fbops = &s3c_fb_ops;

	/* 2.4 设置其他信息 */
	//s3c_lcd_info->screen_base = ;/* 显存的虚拟地址 */
	s3c_lcd_info->screen_size = 480*272*2;
	s3c_lcd_info->pseudo_palette = &s3c_pseudo_palette;

	/* 4. 硬件相关的操作 */
	/* 4.1 配置GPIO用于LCD */
	gpicon = ioremap(0x7F008100, 4);
	*gpicon = 0xAAAAAAAA;

	gpjcon = ioremap(0x7F008120, 4);
	*gpjcon = 0xAAAAAAAA;

	gpbcon = ioremap(0x7F008020, 4);
	gpbdat = gpbcon + 1;


	gpfcon = ioremap(0x7F0080A0, 4);
	gpfdat = gpfcon + 1;


	/* 4.2 根据LCD的性能设置LCD控制器 */
	/* MIFPCON */
	mifpcon = ioremap(0x7410800C, 4);
	*mifpcon &= ~(1<<3);

	spcon = ioremap(0x7F0081A0, 4);
	*spcon &= ~(3);
	*spcon |= 1;

	lcd_regs = ioremap(0x77100000, sizeof(struct s3c6410_lcd_regs));

	clk = clk_get(NULL, "lcd");
	clk_enable(clk);  /* HCLK_GATE[3]设为1 */
	/*
	  HCLK_GATE = ioremap(0x7E00F030, 4);
	* HCLK_GATE |= (1<<3);
	*/

	/* bit[13:6], CLKVAL_F,VCLK = Video Clock Source / (CLKVAL+1)
	                       VCLK = 9000000
	              CLKVAL_F = hclk/9000000 - 1
	 * bit[3:2], CLKSEL_F, 00 = HCLK
	 * bit[1], ENVID-使能LCD控制器的输出, 先设为0, 最后全部设置好了再设为1
	 */
	clk = clk_get(NULL, "hclk");
	hclk = clk_get_rate(clk);
	clkval = hclk/9000000 - 1;
	printk(KERN_INFO "hclk = %d, clkval = %d\n", hclk, clkval);
	lcd_regs->vidcon0 = (0<<29)|(0<<26) | (0<<17) | (clkval << 6) | (1<<4);

	/* bit[7], 0-在VLCK下降沿读数据
     * bit[6], HSYNC低脉冲有效	
     * bit[5], VSYNC低脉冲有效	
	 * bit[4], VDEN高电平有效
	 */	
	lcd_regs->vidcon1 = (0<<7) | (1<<6) | (1<<5) | (0<<4);

	/* LCD手册P11
	 * tvp = 10, tvb = 2, tvf=2
	 */
	lcd_regs->vidtcon0 = (2<<16) | (2<<8) | (10<<0);  /*修改了 都加1*/

	/* LCD手册P11
	 * thp = 41, thb = 2, thf=2
	 */
	lcd_regs->vidtcon1 = (1<<16) | (1<<8) | (40<<0);

	lcd_regs->vidtcon2 = (271<<11) | (479<<0);

	/* 4.3 分配显存, 并告诉LCD控制器 */
	s3c_lcd_info->screen_base = dma_alloc_writecombine(NULL, s3c_lcd_info->screen_size, &s3c_lcd_info->fix.smem_start, GFP_KERNEL);

	/* bit[17],BSWP = 0, bit[16],HWSWP = 0 
	 * bit[5:2],BPPMODE_F, 0b1011, 24bpp
	 * bit[0], ENWIN_F, 0-先不使能
	 */
	lcd_regs->wincon0 &= ~(0xf << 2);
	//lcd_regs->wincon0 |= (0xb<<2);    /* unpacked 24 BPP (non-palletized R:8-G:8-B:8 ) */
	lcd_regs->wincon0 |= (0x5<<2);  
#define LeftTopX     0
#define LeftTopY     0

#define RightBotX   479
#define RightBotY   271

	lcd_regs->vidosd0a = (LeftTopX<<11) | (LeftTopY << 0);
	lcd_regs->vidosd0b = (RightBotX<<11) | (RightBotY << 0);
	//lcd_regs->vidosd0c = 480*272/2;
	lcd_regs->vidosd0c = 480*272;

	lcd_regs->vidw00add0b0 = s3c_lcd_info->fix.smem_start;
	lcd_regs->vidw00add1b0 = (s3c_lcd_info->fix.smem_start + s3c_lcd_info->fix.smem_len) & 0xffffff;		

	/* 4.4 使能 */

	lcd_regs->vidcon0 |= (3); /* 使能LCD控制器输出信号 */
	lcd_regs->wincon0 |= (1<<0); /* 使能窗口0 */
		
	/* 3. 注册 */
	register_framebuffer(s3c_lcd_info);

	return 0;
}

static void s3c_lcd_exit(void)
{
	struct clk *clk;
	
	unregister_framebuffer(s3c_lcd_info);


	lcd_regs->vidcon0 &= ~(1<<1); /* 禁止LCD控制器输出信号 */
	lcd_regs->wincon0 &= ~(1<<0); /* 禁止窗口0 */

	dma_free_writecombine(NULL, s3c_lcd_info->screen_size, s3c_lcd_info->screen_base, s3c_lcd_info->fix.smem_start);

	clk = clk_get(NULL, "lcd");
	clk_disable(clk);  /* HCLK_GATE[3]设为0 */

	iounmap(lcd_regs);
	iounmap(gpbcon);
	iounmap(gpfcon);
	iounmap(gpicon);
	iounmap(gpjcon);
	iounmap(mifpcon);
	iounmap(spcon);

	framebuffer_release(s3c_lcd_info);
	
}

module_init(s3c_lcd_init);
module_exit(s3c_lcd_exit);

MODULE_LICENSE("GPL");

 其中 有注释  。欢迎留言,一起讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值