/**
* LCD driver
* reference: fbmem.c s3c2410fb.c skeletonfb.c atmel_lcdfb.c
*/
----------------------------------------------------------driver---------------------------------------------------------------
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/delay.h>
//#include <asm/arch/board.h>
//#include <asm/arch/cpu.h>
#include <asm/arch/gpio.h>
#include <asm/arch/regs-lcd.h>
//#define S3C24XX_PA_LCD (0x4D000000)
//#define SZ_1M 0x00100000
//#define S3C24XX_SZ_LCD SZ_1M
//#define IRQ_LCD 7
//typedef u32 dma_addr_t;
//static dma_addr_t map_dma; /* physical */
dma_addr_t map_dma; /* physical */
//typedef unsigned char u_char;
//static u_char * map_cpu; /* virtual */
u_char * map_cpu; /* virtual */
//typedef unsigned int u_int;
//static u_int map_size;
u_int map_size;
struct s3c2410fb_hw {
unsigned long lcdcon1;
unsigned long lcdcon2;
unsigned long lcdcon3;
unsigned long lcdcon4;
unsigned long lcdcon5;
unsigned long lcdsaddr1;
unsigned long lcdsaddr2;
unsigned long lcdsaddr3;
};
static volatile struct s3c2410fb_hw *pczs3c2410fb_hw;
static struct fb_info *pczfb_info;
/*10^-12 = 1 * 10( -12)*/
/* pixclk is in picoseoncds, our clock is in Hz
*
* Hz -> picoseconds is / 10^-12
*/
/*HCLK=100MHz,PCLK=??MHz,*/
/* from pxafb.c */
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 czlcdfb_setcolreg(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
unsigned int transp, struct fb_info *info)
{
unsigned int val;
//u32 *pal;
u32 *pal = pczfb_info->pseudo_palette;
switch (pczfb_info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
//there be error if this code is here,why??????????
//u32 *pal = pczfb_info->pseudo_palette;
val = chan_to_field(red, &pczfb_info->var.red);
val |= chan_to_field(green, &pczfb_info->var.green);
val |= chan_to_field(blue, &pczfb_info->var.blue);
pal[regno] = val;
break;
default:
return 1; /* unknown type */
}
return 0;
}
static struct fb_ops czlcdfb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = czlcdfb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static u32 pseudo_pal[16];
//static u32 palette_buffer[256];
static volatile unsigned long *gpccon = NULL;
//volatile unsigned long *gpcdat = NULL;
static volatile unsigned long *gpdcon = NULL;
//volatile unsigned long *gpddat = NULL;
static volatile unsigned long *gpgcon = NULL;
//static volatile unsigned long *gpgdat = NULL;
static int __init czlcdfb_init(void)
{
int ret;
int i = 0;
unsigned long saddr1, saddr2, saddr3;
struct fb_fix_screeninfo *czfix;//still forbit,why????
struct fb_var_screeninfo *czvar;
gpccon = (volatile unsigned long *)ioremap(0x56000020,4);
//gpcdat = gpccon +1;
gpdcon = (volatile unsigned long *)ioremap(0x56000030,4);
//gpddat = gpdcon +1;
gpgcon = (volatile unsigned long *)ioremap(0x56000060,4);
//gpgdat = gpgcon +1;
*gpccon = 0xaaaaaaaa;
*gpdcon = 0xaaaaaaaa;
*gpgcon |= (0x3<<(4*2));
//pczfb_info = framebuffer_alloc(sizeof(struct fb_info),NULL);
pczfb_info = framebuffer_alloc(0,NULL);
printk("framebuffer_alloc successed\n");
czfix = &pczfb_info->fix;
czvar = &pczfb_info->var;
//tips:about -> and . 's difference!error: request for member `id' in something not a structure or union
strcpy(czfix->id, "czlcdfb");
printk("strcpy successed\n");
//fix
czfix->type = FB_TYPE_PACKED_PIXELS;//see FB_TYPE_
czfix->type_aux = 0; //Interleave for interleaved Planes
czfix->xpanstep = 0; //zero if no hardware panning
czfix->ypanstep = 0; //zero if no hardware panning
czfix->ywrapstep = 0; //zero if no hardware ywrap
czfix->accel = FB_ACCEL_NONE; //Indicate to driver which
czfix->smem_len = 320*240*16/8; //Length of frame buffer mem in bytes
czfix->line_length = 320*16/8;
czfix->visual = FB_VISUAL_TRUECOLOR; /* TFT */
pczfb_info->screen_size = 320*240*16/8;
map_size = czfix->smem_len;
//if (!request_mem_region(czfix.smem_start,czfix.smem_len, "s3c2410-lcd"))ret = -EBUSY;
//fb_info->screen_base = ioremap(czfix.smem_start, czfix.smem_len);
//fb_info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
//(dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
map_cpu = dma_alloc_writecombine(NULL, czfix->smem_len, &map_dma, GFP_KERNEL);
if (!map_cpu)
return -ENOMEM;
printk("dma_alloc_writecombine successed\n");
pczfb_info->screen_base = map_cpu;
czfix->smem_start = map_dma;
//var
czvar->xres = 320; //visible resolution
czvar->xres_virtual = 320; //virtual resolution
czvar->yres = 240;
czvar->yres_virtual = 240;
czvar->red.offset = 11;
czvar->green.offset = 5;
czvar->blue.offset = 0;
czvar->transp.offset = 0;
czvar->red.length = 5;
czvar->green.length = 6;
czvar->blue.length = 5;
czvar->transp.length = 0;
czvar->activate = FB_ACTIVATE_NOW; //set values immediately (or vbl)
czvar->accel_flags = 0; //(OBSOLETE) see fb_info.flags
czvar->bits_per_pixel = 16;
czvar->nonstd = 0;
//fbinfo->var.height = mach_info->height;
//fbinfo->var.width = mach_info->width;
czvar->vmode = FB_VMODE_NONINTERLACED;
printk("FB_VMODE_NONINTERLACED successed\n");
//there will be oops for the code below,why?????????
#if 0
czvar->upper_margin = S3C2410_LCDCON2_GET_VBPD(pczs3c2410fb_hw->lcdcon2) + 1;
czvar->lower_margin = S3C2410_LCDCON2_GET_VFPD(pczs3c2410fb_hw->lcdcon2) + 1;
czvar->vsync_len = S3C2410_LCDCON2_GET_VSPW(pczs3c2410fb_hw->lcdcon2) + 1;
czvar->left_margin = S3C2410_LCDCON3_GET_HFPD(pczs3c2410fb_hw->lcdcon3) + 1;
czvar->right_margin = S3C2410_LCDCON3_GET_HBPD(pczs3c2410fb_hw->lcdcon3) + 1;
czvar->hsync_len = S3C2410_LCDCON4_GET_HSPW(pczs3c2410fb_hw->lcdcon4) + 1;
#endif
//pczfb_info
pczfb_info->fbops = &czlcdfb_ops;
pczfb_info->flags = FBINFO_FLAG_DEFAULT;//?
pczfb_info->pseudo_palette = pseudo_pal;
printk("pseudo_palette successed\n");
/*
//entry is clear/invalid
#define PALETTE_BUFF_CLEAR (0x80000000)
// error: 'for' loop initial declaration used outside C99 mode
for ( i = 0; i < 256; i++){
palette_buffer[i] = PALETTE_BUFF_CLEAR;}
printk("palette_buffer successed\n");
*/
/*
//irq
ret = request_irq(IRQ_LCD, s3c2410fb_irq, IRQF_DISABLED, "s3c2410-lcd", "unique_ID for free irq");
if (ret) {
printk("cannot get irq %d - err %d\n", irq, ret);
return -EBUSY;
}*/
//error: syntax error before ')' token
//pczs3c2410fb_hw =((*pczs3c2410fb_hw) *)ioremap(S3C24XX_PA_LCD, S3C24XX_SZ_LCD);
//error: `s3c2410fb_hw' undeclared (first use in this function)
//pczs3c2410fb_hw =(s3c2410fb_hw *)ioremap(S3C24XX_PA_LCD, S3C24XX_SZ_LCD);
//pczs3c2410fb_hw =(volatile unsigned long *)ioremap(S3C24XX_PA_LCD, S3C24XX_SZ_LCD);
pczs3c2410fb_hw =(volatile unsigned long *)ioremap(S3C24XX_PA_LCD, sizeof(struct s3c2410fb_hw));
printk("pczs3c2410fb_hw successed\n");
pczs3c2410fb_hw->lcdcon1 = (4<<8)|(3<<5)|(12<<1)|(0<<0);
pczs3c2410fb_hw->lcdcon2 = (2<<24)|(239<<14)|(6<<6)|(12<<0);
pczs3c2410fb_hw->lcdcon3 = (24<<19)|(319<<8)|(28<<0);
pczs3c2410fb_hw->lcdcon4 = (42<<0);
pczs3c2410fb_hw->lcdcon5 = (1<<11)|(0<<10)|(1<<9)|(1<<8)|(0<<7)|(0<<6)|(0<<5)|(0<<3)|(0<<1)|(1<<0);
//saddr1 = czfix->smem_start >> 1&0x3fffffff;
saddr1 = (czfix->smem_start >> 1);
printk("saddr1 successed\n");
//saddr2 =( czfix->smem_start+czfix->smem_len)>>1&0xfffff;
saddr2 = czfix->smem_start;
saddr2 += (czvar->xres * czvar->yres * czvar->bits_per_pixel)/8;
saddr2>>= 1;
printk("saddr2 successed\n");
//saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((czvar->xres * czvar->bits_per_pixel / 16) & 0x7ff);
saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH(czvar->xres * czvar->bits_per_pixel / 16);
printk("saddr3 successed\n");
pczs3c2410fb_hw->lcdsaddr1 = saddr1;
pczs3c2410fb_hw->lcdsaddr2 = saddr2;
pczs3c2410fb_hw->lcdsaddr3 = saddr3;
printk("pczs3c2410fb_hw->lcdsaddr3 = saddr3 successed\n");
#if 0
//tips:Unable to handle kernel paging request at virtual address 000b00da, why????????
writel(saddr1, pczs3c2410fb_hw->lcdsaddr1);
printk("writel saddr1 successed\n");
writel(saddr2, pczs3c2410fb_hw->lcdsaddr2);
printk("writel saddr2 successed\n");
writel(saddr3, pczs3c2410fb_hw->lcdsaddr3);
printk("writel saddr3 successed\n");
#endif
ret = register_framebuffer(pczfb_info);
if (ret < 0)
printk("failed to register framebuffer device: %d\n", ret);
printk("register_framebuffer successed\n");
pczs3c2410fb_hw->lcdcon5 = pczs3c2410fb_hw->lcdcon5|(1<<3);
printk("pczs3c2410fb_hw->lcdcon5|(1<<3) successed\n");
pczs3c2410fb_hw->lcdcon1 = pczs3c2410fb_hw->lcdcon1|(1<<0);
printk("pczs3c2410fb_hw->lcdcon1|(1<<7) successed\n");
//*gpgdat |= 1<<4; //this way is wrong!remember!
return 0;
}
static void __exit czlcdfb_exit(void)
{
unregister_framebuffer(pczfb_info);
dma_free_writecombine(NULL, map_size, map_cpu, map_dma);
iounmap(pczs3c2410fb_hw);
framebuffer_release(pczfb_info);
iounmap(gpccon);
iounmap(gpdcon);
iounmap(gpgcon);
//pczs3c2410fb_hw->lcdcon1 = (pczs3c2410fb_hw->lcdcon1|(0<<0));
//pczs3c2410fb_hw->lcdcon5 = (pczs3c2410fb_hw->lcdcon5|(0<<3));
return;
}
module_init(czlcdfb_init);
module_exit(czlcdfb_exit);
MODULE_AUTHOR("chaozang(cz) <zangchao.cn@gmail.com>, copy frm teacher:weidongshan,thanks so much!");
MODULE_DESCRIPTION("LCD Controller framebuffer driver");
MODULE_LICENSE("GPL");
----------------------------------------------------test commands----------------------------------------------------------
# insmod cfbcopyarea.ko
#insmod cfbfillrect.ko
#insmod cfbimgblt.ko
#echo test >/dev/tty1
#echo xxx.ko >/dev/fb0
-----------------------------------------------------------------------------
Contact: zangchao.cn@gmail.com