LCD Driver for Linux2.6.xx+ARM9

/**
  *   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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值