vi lcd.c
#include <linux/module.h>
#include <linux/fb.h>
#include <linux/dma-mapping.h>
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 int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info * info);
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 struct fb_info *s3c_lcd;
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];
static 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;
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)
{
s3c_lcd = framebuffer_alloc(0,NULL);
strcpy(s3c_lcd->fix.id,"mylcd");
s3c_lcd->fix.smem_len = 480*272*16/8;
s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS;
s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR;
s3c_lcd->fix.line_length = 480*2;
//s3c_lcd->fix.smem_start = ;
s3c_lcd->var.xres = 480;
s3c_lcd->var.yres = 272;
s3c_lcd->var.xres_virtual = 480;
s3c_lcd->var.yres_virtual = 272;
s3c_lcd->var.bits_per_pixel = 16;
s3c_lcd->var.red.offset = 11;
s3c_lcd->var.red.length = 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;
s3c_lcd->fbops = &s3c_lcdfb_ops;
s3c_lcd->pseudo_palette = pseudo_palette;
//s3c_lcd->screen_base = ;
s3c_lcd->screen_size = 272*480*16/8;
gpbcon = ioremap(0x56000010,8);
gpbdat = gpbcon + 1;
gpccon = ioremap(0x56000020,4);
gpdcon = ioremap(0x56000030,4);
gpgcon = ioremap(0x56000060,4);
*gpccon = 0xaaaaaaaa;
*gpdcon = 0xaaaaaaaa;
*gpbcon &= ~(3);
*gpbcon |= 1;
*gpbdat &= 0;
*gpgcon |= (3<<8);
lcd_regs = ioremap(0x4d000000,sizeof(struct lcd_regs));
lcd_regs->lcdcon1 = (4<<8)|(3<<5)|(0x0c<<1);
lcd_regs->lcdcon2 = (1<<24)|(271<<14)|(1<<6)|(9<<0);
lcd_regs->lcdcon3 = (1<<19)|(479<<8)|(1<<0);
lcd_regs->lcdcon4 = 40;
lcd_regs->lcdcon5 = (1<<11)|(0<<10)|(1<<9)|(1<<8)|(1<<0);
s3c_lcd->screen_base = dma_alloc_writecombine(NULL,s3c_lcd->fix.smem_len,(dma_addr_t *)&(s3c_lcd->fix.smem_start),GFP_KERNEL);
lcd_regs->lcdsaddr1 = (s3c_lcd->fix.smem_start >> 1) & ~(3<<30);
lcd_regs->lcdsaddr2 = ((s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len)>>1) & 0x1fffff;
lcd_regs->lcdsaddr3 = (480*16/16);
lcd_regs->lcdcon1 |= (1<<0);
lcd_regs->lcdcon5 |= (1<<3);
*gpbdat |= 1;
register_framebuffer(s3c_lcd);
return 0;
}
static void lcd_exit(void)
{
unregister_framebuffer(s3c_lcd);
lcd_regs->lcdcon1 &= ~(1<<0);
lcd_regs->lcdcon5 &= ~(1<<3);
*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");
测试驱动:先去掉uImage里的S3C2410 LCD驱动,
# ls /dev/fb*
ls: /dev/fb*: No such file or directory
# insmod lcd.ko
lcd: Unknown symbol cfb_fillrect
lcd: Unknown symbol cfb_imageblit
lcd: Unknown symbol cfb_copyarea
insmod: cannot insert 'lcd.ko': Unknown symbol in module (-1): No such file or directory
# insmod cfbcopyarea.ko
insmod lcd.ko# insmod cfbimgblt.ko
# insmod cfbfillrect.ko
# insmod lcd.ko
Console: switching to colour frame buffer device 60x34
# insmod lcd.ko
insmod: cannot insert 'lcd.ko': File exists (-1): File exists
# ls /dev/fb*
/dev/fb0
# echo hello > /dev/tty1
# cat lcd.ko > /dev/fb0
vi /etc/inittab添加tty1:::askfirst:-/bin/sh,重启后insmod上面的模块和button.ko,就可以在通过按键操作LCD显示。