参考:韦东山2440lcd
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <plat/clock.h>
#include <plat/gpio-cfg.h>
#include <plat/fb.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <linux/io.h>
#include <mach/map.h>
#include <asm/io.h>
#include <asm/system.h>
#include <linux/fb.h>
#include <linux/dma-mapping.h>
static volatile unsigned long *gpd0con;
static volatile unsigned long *gpd0dat;
static volatile unsigned long *gpf0con;
static volatile unsigned long *gpf1con;
static volatile unsigned long *gpf2con;
static volatile unsigned long *gpf3con;
static volatile unsigned long *display_control;
static volatile unsigned long *vidcon0;
static volatile unsigned long *vidcon1;
static volatile unsigned long *vidcon2;
static volatile unsigned long *vidcon3;
static volatile unsigned long *vidtcon0;
static volatile unsigned long *vidtcon1;
static volatile unsigned long *vidtcon2;
static volatile unsigned long *wincon0;
static volatile unsigned long *vidosdoa;
static volatile unsigned long *vidosdob;
static volatile unsigned long *vidosdoc;
static volatile unsigned long *vidwooadd0bo;
static volatile unsigned long *vidwooadd1bo;
static volatile unsigned long *shadowcon;
static u32 pseudo_palette[16];
static struct fb_info *s3c_lcd;
#define VSPW 9
#define VBPD 12
#define LINEVAL 479
#define VFPD 21
#define HSPW 20
#define HBPD 24
#define HOZVAL 799
#define HFPD 209
#define LeftTopX 0
#define LeftTopY 0
#define RightBotX 799
#define RightBotY 479
#define SCR_XSIZE_TFT (800)
#define SCR_YSIZE_TFT (480)
static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
unsigned int transp, struct fb_info *info);
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_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 struct fb_ops s3c_lcdfb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = s3c_lcdfb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static int lcd_gpio_ioremap()
{
gpd0con = ioremap(0xE02000A0, 8);
gpd0dat=gpd0con+1;
gpf0con = ioremap(0xE0200120, 4);
gpf1con = ioremap(0xE0200140, 4);
gpf2con = ioremap(0xE0200160, 4);
gpf3con = ioremap(0xE0200180, 4);
display_control = ioremap(0xe0107008, 4);
vidcon0=ioremap(0xF8000000,16);
vidcon1=vidcon0+1;
vidcon2=vidcon1+1;
vidcon3=vidcon2+1;
vidtcon0=ioremap(0xF8000010,12);
vidtcon1=vidtcon0+1;
vidtcon2=vidtcon1+1;
wincon0=ioremap(0xF8000020,4);
vidosdoa=ioremap(0xf8000040,12);
vidosdob=vidosdoa+1;
vidosdoc=vidosdob+1;
vidwooadd0bo=ioremap(0xF80000A0,4);
vidwooadd1bo=ioremap(0xF80000D0,4);
shadowcon=ioremap(0xF8000034,4);
}
static int qt210_lcd_init(void)
{
/* 1. 分配一个fb_info */
s3c_lcd=framebuffer_alloc(0, NULL);
/* 2. 设置 */
/* 2.1 设置固定的参数 */
strcpy(s3c_lcd->fix.id,"mylcd");
s3c_lcd->fix.smem_len=800*480*4;
s3c_lcd->fix.type=FB_TYPE_PACKED_PIXELS;
s3c_lcd->fix.visual=FB_VISUAL_TRUECOLOR;
s3c_lcd->fix.line_length=800*4;
/* 2.2 设置可变的参数 */
s3c_lcd->var.xres =800;
s3c_lcd->var.yres =480;
s3c_lcd->var.xres_virtual=800;
s3c_lcd->var.yres_virtual=480;
s3c_lcd->var.bits_per_pixel=32;
/* RGB:565 */
s3c_lcd->var.red.offset = 16;
s3c_lcd->var.red.length = 8;
s3c_lcd->var.green.offset = 8;
s3c_lcd->var.green.length = 8;
s3c_lcd->var.blue.offset = 0;
s3c_lcd->var.blue.length = 8;
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 = 800*480*32/8;
/* 3. 硬件相关的操作 */
/* 使能LCD背光 */
lcd_gpio_ioremap();
*gpd0con&= ~(0xf<<12);
*gpd0con|= (1<<12);
*gpd0dat|= (1<<3);
/* 配置为lcd*/
*gpf0con =0x22222222;
*gpf1con =0x22222222;
*gpf2con =0x22222222;
*gpf3con =0x22222222;
*display_control =2<<0;
*vidcon0|= ((1<<0)|(1<<1)|(4<<6) | (1<<4) );
*vidcon1|= ((1<<6) | (1<<5));
*vidtcon0=(VBPD << 16) | (VFPD << 8) | (VSPW << 0);
*vidtcon1=(HBPD << 16) | (HFPD << 8) | (HSPW << 0);
*vidtcon2=(LINEVAL << 11) | (HOZVAL << 0);
*wincon0|=(1)| (0xB<<2)|(1<<15);
*vidosdoa=(LeftTopX<<11) | (LeftTopY << 0);
*vidosdob=(RightBotX<<11) | (RightBotY << 0);
*vidosdoc=(LINEVAL + 1) * (HOZVAL + 1);
s3c_lcd->screen_base = dma_alloc_writecombine(NULL, s3c_lcd->fix.smem_len, &s3c_lcd->fix.smem_start, GFP_KERNEL);
*vidwooadd0bo=s3c_lcd->fix.smem_start;
*vidwooadd1bo=(((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff);
*shadowcon=0x1;
/* 4. 注册 */
register_framebuffer(s3c_lcd);
return 0;
}
static void qt210_lcd_exit(void)
{
*gpd0dat&=~ (1<<3);
unregister_framebuffer(s3c_lcd);
dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, s3c_lcd->screen_base, s3c_lcd->fix.smem_start);
iounmap(gpd0con);
iounmap(gpf1con);
iounmap(gpf2con);
iounmap(gpf3con);
iounmap(display_control);
iounmap(vidcon0);
iounmap(vidtcon0);
iounmap(wincon0);
iounmap(vidosdoa);
iounmap(gpf0con);
iounmap(vidwooadd0bo);
iounmap(vidwooadd1bo);
iounmap(shadowcon);
framebuffer_release(s3c_lcd);
}
module_init(qt210_lcd_init);
module_exit(qt210_lcd_exit);
MODULE_LICENSE("GPL");