Chinaunix首页 | 论坛 | 博客
  • 博客访问: 356377
  • 博文数量: 197
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 303
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-02 14:21
文章分类

全部博文(197)

文章存档

2014年(89)

2013年(108)

我的朋友

分类: LINUX

2014-03-10 18:06:19

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include
#include
#include

#include
#include
#include
#include

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 struct fb_info *s3clcdfb_info;
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 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 __init lcd_init(void)
  {
   s3clcdfb_info= framebuffer_alloc(0,NULL);               // 1. 分配一个fb_info,分配的内存大小在该函数内部会自动指定
  
   /* 2. 设置 */
  /* 2.1 设置固定的参数 */
  strcpy(s3clcdfb_info->fix.id,"lcd");                    //字符串形式的标识符
 // s3clcdfb_info->fix.smem_start=                        //fb缓冲内存的开始地址(物理地址)
 s3clcdfb_info->fix.smem_len     = 480*272*32/8;          //fb缓冲的长度max_xres *max_yres*max_bpp/8 , TQ2440的LCD位宽是24,但是2440里会分配4字节即32位(浪费1字节)          
 s3clcdfb_info->fix.type         =FB_TYPE_PACKED_PIXELS;  //查看宏 FB_TYPE_    FB_TYPE_PACKED_PIXELS=0  
 s3clcdfb_info->fix.type_aux     =0;
 s3clcdfb_info->fix.visual       =FB_VISUAL_TRUECOLOR;    //查看宏FB_VISUAL_,用于记录屏幕使用的色彩模式,一般是FB_VISUAL_TRUECOLOR(真彩色)
 s3clcdfb_info->fix.xpanstep     =0;                      //如果没有硬件 panning,=0
 s3clcdfb_info->fix.ypanstep     =0;                      //如果没有硬件 panning,=0
 s3clcdfb_info->fix.ywrapstep    =0;                      //如果没有硬件 panning,=0
 s3clcdfb_info->fix.line_length  =480*32/8;               //1行的字节数,TQ2440的LCD位宽是24,但是2440里会分配4字节即32位(浪费1字节)
 s3clcdfb_info->fix.accel        = FB_ACCEL_NONE;
 
 /* 2.2 设置可变的参数 */
 s3clcdfb_info->var.xres            =480;   //定义屏幕一行有多少个点
 s3clcdfb_info->var.yres            =272;   //定义屏幕一列由多少个点
 s3clcdfb_info->var.xres_virtual    =480;   //虚拟屏幕一行有多少个点
 s3clcdfb_info->var.yres_virtual    =272;   //虚拟屏幕一列由多少个点
 s3clcdfb_info->var.xoffset         =0;     //虚拟到可见(实际)之间的行方向偏移
 s3clcdfb_info->var.yoffset         =0;     //虚拟到可见(实际)之间的列方向偏移
 s3clcdfb_info->var.bits_per_pixel  =16;
 s3clcdfb_info->var.grayscale       =0;
 /* RGB:565 */
 s3clcdfb_info->var.red.offset     = 16;   //位域偏移
 s3clcdfb_info->var.red.length     = 8;    //位域长度
 s3clcdfb_info->var.green.offset   = 8;    //位域偏移
 s3clcdfb_info->var.green.length   = 8;    //位域长度
 s3clcdfb_info->var.blue.offset    = 0;    //位域偏移
 s3clcdfb_info->var.blue.length    = 8;    //位域长度
 
 /* 2.3 设置操作函数 */
 s3clcdfb_info->fbops           =&s3c_lcdfb_ops; //设置操作函数
 s3clcdfb_info->flags           =FBINFO_FLAG_DEFAULT;
 s3clcdfb_info->pseudo_palette  =pseudo_palette;   //伪16色调色板
 s3clcdfb_info->screen_base     = dma_alloc_writecombine(NULL, s3clcdfb_info->fix.smem_len, &s3clcdfb_info->fix.smem_start, GFP_KERNEL); //虚拟基地址
 s3clcdfb_info->screen_size     = 480*272*32/8;   //ioremapped 的虚拟内存大小
 
 /* 2.4 其他的设置 */
 s3clcdfb_info->var.nonstd        =0;                         //标准像素格式
 s3clcdfb_info->var.activate      =FB_ACTIVATE_NOW;
 s3clcdfb_info->var.accel_flags   =0;
 s3clcdfb_info->var.pixclock      =100000;  //像素时钟(皮秒),pixclock=1/Dclk=
 s3clcdfb_info->var.left_margin   =2;                         //行切换,从同步到绘图之间的延迟, Hsyn front-porch,查看LCD数据手册
 s3clcdfb_info->var.right_margin  =2;                         //行切换,从绘图到同步之间的延迟  Hsyn back-porch
 s3clcdfb_info->var.upper_margin  =2;                         //帧切换,从同步到绘图之间的延迟  Vsyn front-porch
 s3clcdfb_info->var.lower_margin  =2;                         //帧切换,从绘图到同步之间的延迟  Vsyn back-porch
 s3clcdfb_info->var.hsync_len     =41;                        //水平同步的长度    Hsyn pulse Width
 s3clcdfb_info->var.vsync_len     =10;                        //垂直同步的长度    Vsyn pulse Width
 s3clcdfb_info->var.vmode         = FB_VMODE_NONINTERLACED;
 
 /* 3. 硬件相关的操作 */
 /* 3.1 配置GPIO用于LCD */
 gpbcon = ioremap(0x56000010, 8);
 gpbdat = gpbcon+1;
 gpccon = ioremap(0x56000020, 4);
 gpdcon = ioremap(0x56000030, 4);
 gpgcon = ioremap(0x56000060, 4); 
 *gpccon  = 0xaaaaaaaa;   /* GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND */
 *gpdcon  = 0xaaaaaaaa;   /* GPIO管脚用于VD[23:8] */
 *gpgcon |= (3<<8); /* GPG4用作LCD_PWREN */
 
 /* 3.2 根据LCD手册设置LCD控制器, 比如VCLK的频率等 */
 lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs));
 /* bit[17:8]: VCLK = HCLK / [(CLKVAL+1) x 2], LCD手册P5 (Dclk=9MHz~15MHz)
  *            10MHz(100ns) = 100MHz / [(CLKVAL+1) x 2]
  *            CLKVAL = 4
  * bit[6:5]: 0b11, TFT LCD
  * bit[4:1]: 0b1101, 24 bpp for TFT
  * bit[0]  : 0 = 禁止视频输出LCD控制信号
  */
 lcd_regs->lcdcon1  = (4<<8) | (3<<5) | (0x0d<<1);
 
  /* 垂直方向的时间参数
  * bit[31:24]: VBPD, VSYNC之后再过多长时间才能发出第1行数据
  *             LCD手册 tvb=2
  *             VBPD=2-1=1
  * bit[23:14]: 多少行, 272, 所以LINEVAL=272-1=271
  * bit[13:6] : VFPD, 发出最后一行数据之后,再过多长时间才发出VSYNC
  *             LCD手册tvf=2, 所以VFPD=2-1=1
  * bit[5:0]  : VSPW, VSYNC信号的脉冲宽度, LCD手册tvp=10, 所以VSPW=10-1=9
  */
 lcd_regs->lcdcon2  = (1<<24) | (271<<14) | (1<<6) | (9<<0);
 
 /* 水平方向的时间参数
  * bit[25:19]: HBPD, VSYNC之后再过多长时间才能发出第1行数据
  *             LCD手册 thb=2
  *             HBPD=1
  * bit[18:8]: 多少列, 480, 所以HOZVAL=480-1=479
  * bit[7:0] : HFPD, 发出最后一行里最后一个象素数据之后,再过多长时间才发出HSYNC
  *             LCD手册thf=2, 所以HFPD=2-1=1
  */
 lcd_regs->lcdcon3 = (1<<19) | (479<<8) | (1<<0);
 
 /* 水平方向的同步信号
  * bit[7:0] : HSPW, HSYNC信号的脉冲宽度, LCD手册Thp=41, 所以HSPW=41-1=40
  */ 
 lcd_regs->lcdcon4 = 40;
 
 /* 信号的极性
  * bit[11]: 1=565 format, 对于24bpp这个不用设
  * bit[10]: 0 = VCLK下降沿取视频数据
  * bit[9] : 1 = HSYNC信号要反转,即低电平有效
  * bit[8] : 1 = VSYNC信号要反转,即低电平有效
  * bit[6] : 0 = VDEN不用反转
  * bit[3] : 0 = PWREN输出0
  *
  * BSWP = 0, HWSWP = 0, BPP24BL = 0 : 当bpp=24时,2440会给每一个象素分配32位即4字节,哪一个字节是不使用的? 看2440手册P412
         * bit[12]: 0, LSB valid, 即最高字节不使用
  * bit[1] : 0 = BSWP
  * bit[0] : 0 = HWSWP
  */
 lcd_regs->lcdcon5 = (0<<10) | (1<<9) | (1<<8) | (0<<12) | (0<<1) | (0<<0);
 
 lcd_regs->lcdsaddr1  = (s3clcdfb_info->fix.smem_start >> 1) & ~(3<<30);
 lcd_regs->lcdsaddr2  = ((s3clcdfb_info->fix.smem_start +s3clcdfb_info->fix.smem_len ) >> 1) & 0x1fffff;
 lcd_regs->lcdsaddr3  = (480*32/16);  // 一行的长度(单位: 2字节)
 
 lcd_regs->lcdcon1 |= (1<<0);         //使能LCD控制器
 
 lcd_regs->lcdcon5 |= (1<<3);        //使能LCD本身: LCD_PWREN
 
 
 register_framebuffer(s3clcdfb_info); // 4. 注册
  return 0; 
  }
static void __exit lcd_exit(void)
 {
 unregister_framebuffer(s3clcdfb_info);  //释放fb_info
 lcd_regs->lcdcon1 &= ~(1<<0); /* 关闭LCD控制器 */
 lcd_regs->lcdcon1 &= ~(1<<3); /* 关闭LCD本身 */
 dma_free_writecombine(NULL, s3clcdfb_info->fix.smem_len, s3clcdfb_info->screen_base, s3clcdfb_info->fix.smem_start);  //释放缓冲区
 iounmap(lcd_regs);  //取消映射
 iounmap(gpbcon);
 iounmap(gpccon);
 iounmap(gpdcon);
 iounmap(gpgcon);
 framebuffer_release(s3clcdfb_info);  //注销
 }
module_init(lcd_init);
module_exit(lcd_exit);
MODULE_AUTHOR("shenchaoping"); //描述模块作者
MODULE_LICENSE("Dual BSD/GPL");//指定代码使用双重许可证
MODULE_VERSION("v1.0");        //模块版本
MODULE_DESCRIPTION("A lcd operation module"); //说明模块用途
MODULE_ALIAS("lcd");    //模块别名

阅读(761) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~