本文档是看韦东山老师的LCD驱动视频手打下来的,所以可能会提示头文件找不到啊之类的,呵呵。另外cfb_fillrect.ko,cfb_copyarea.ko ,cfb_imageblit.ko这三个模块可以在内核的/drivers/video找到
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int s3c_lcdfb_setcolreg(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue,unsigned int transp,struct fb_info *info); 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_ops s3c_lcdfb_ops={ .owner =THIS_MODULE, .fb_setcolreg =s3c_lcdfb_setcolreg, /*这三个函数分别由三个模块(在drivers/vedio目录下)来具体实现,然后一起加载,它们经常用到,所以这里不用实现他们*/ .fb_fillrect =cfb_fillrect,/*填充矩形 */ .fb_copyarea =cfb_copyarea,/*拷贝一个区域*/ .fb_imageblit =cfb_imageblit, }; static struct fb_info *s3c_lcd;/*分配info结构体*/ /*GPIO控制器*/ 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];/*假的调色板*/ /*调色板函数*/ /*5:6:5 format*/ 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 int lcd_init(void) { /*1.分配一个fb_info *其中分配时fb_info里面的值默认都是0,所有下面有些参数可以不用设置默认0 */ s3c_lcd=framebuffer_alloc(0,NULL); /*其中0代表不需要额外的私有数据空间*/ /*2.设置*/ /*2.1设置固定的参数*/ strcpy(s3c_lcd->fix.id,"mylcd"); /*设置fix的名称*/ s3c_lcd->fix.smem_len =240*320*16; /*按具体的屏幕--设置一帧的大小*/ s3c_lcd->fix.type =FB_TYPE_PACKED_PIXELS;/*默认值0*/ s3c_lcd->fix.visual =FB_VISUAL_TRUECOLOR; /*TFT真彩色*/ s3c_lcd->fix.line_lenth =240*2; /*一行的长度大小。。单位byte*/ /*2.2设置可变的参数*/ s3c_lcd->var.xres =240; /*x方向的分辨率*/ s3c_lcd->var.yres =320; /*y方向的分辨率*/ s3c_lcd->var.xres_virtual =240; /*x方向的虚拟分辨率*/ s3c_lcd->var.xres_virtual =320; /*y方向的虚拟分辨率*/ s3c_lcd->var.bits_per_pixel =16; /*每个像素16位--bpp*/ /*RGB--5:6:5*/ s3c_lcd->var.red.offset =11; /*第11位开始*/ s3c_lcd->var.red.length =5; /*长度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; /*2.3设置操作函数*/ s3c_lcd->fbops =&s3c_lcdfb_ops; /*2.4其他的设置*/ s3c_lcd->pseudo_palette = pseudo_palette; //s3c_lcd->screen_base =; /*显存的虚拟地址*/ s3c_lcd->screen_size =240*320*2; /*屏幕的大小,单位byte*/ /*3.硬件相关的设置*/ /*3.1配置GPIO用于LCD*/ gpbcon=ioremap(0x56000010,8); gpbdat=gpbcon+1;/*相当于+4 byte*/ 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]*/ *gpbcon&=~(3);/*GPBO设置为输出引脚*/ *gpbcon |=1; *gpbdat &=~1;/*输出低电平*/ *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)*2],LCD手册P14 * 10MHz=100MHz/[CLKVAL+1]*2] * 10MHz是我们2440手册里的100ns得出的(1us->1MHz) * 100MHz是我们主机的频率 * CLKVAL=4 *bit[6:5]: ob11,TFT LCD *bit[4:1]: ob1100,16 bpp for TFT *bit[0]: 0=Disable the video output and the LCD control signal. */ lcd_regs->lcdcon1 =(4<<8) | (3<<5) | (0x0c<<1); /*垂直方向的时间参数 *bit[31:24]:VBPD,VSYNC之后再过多长时间才能发出第1行数据 * LCD手册 T0-T2-T1=4 * VBPD=3 *bit[23:14]:多少行,320,所以LINEVAL=320-1=319 *bit[13:6] :VFPD,发出最后一行数据之后,再过多长时间才发出VSYNC * LCD手册T2-T5=322-320=2,所以VFPD=2-1=1 *bit[5:0] : VSPW,VSYNC信号的脉冲宽度,LCD手册T1=1,所以VSPW=1-1=0 */ lcd_regs->lcdcon2 =(3<<24) | (319<<14) | (1<<6) | (0<<0); /*水平方向的时间参数 *bit[25:19]:HBPD,HSYNC之后再过多长时间才能发出第1行数据 * LCD手册 T6-T7-T8=17 * HBPD=16 *bit[18:8]:多少列,240,所以HOZVAL=240-1=239 *bit[7:0]:HFPD,发出最后一行里最后一个像素数据之后,再过多长时间才能发出HSYNC * LCD手册T8-T11=251-240=11,所以HFPD=11-1=10 */ lcd_regs->lcdcon3=(16<<19) | (239<<9) | (10<<0); /*水平方向的同步信号 *bit[7:0]:HSPW,HSYNC信号的脉冲宽度,LCD手册T7=5,所以HSPW=5-1=4 */ lcd_regs->lcdcon4=4; /*信号的极性 *bit[11]: 1=5:6:5 format *bit[10]: 0=The video data is fetched at VCLK falling edge *bit[9]: 1=HSYNC信号要反转,即低电平有效 *bit[8]: 1=VSYNC信号要反转,即低电平有效 *bit[6]: 0=VDEN不用反转 *bit[3]: 0=PWREN输出0 *下面两位控制在framebuffer中[0:31]->[P1,P2]还是[p2,p1] *bit[1]: 0=BSWP *bit[0]: 1=HWSWP 2440手册P413 *很明显是[p1,p2] */ lcd_regs->lcdcon5= (1<<11) | (0<<10) | (1<<9) | (1<<8) | (1<<0); /*3.3分配显存(framebuffer),并把地址告诉LCD控制器*/ /*申请一块连续的内存,返回虚拟地址*/ s3c_lcd->screen_base=dma_alloc_writecombine(NULL,s3c_lcd->fix.smem_len,&s3c_lcd->fix.smem_start,GFP_KERNEL); /*lcdsaddr1的bit[29:0]对应A[30:1],最低1位不要,所以右移一位--最高两位不需要--清0*/ lcd_regs->lcdsaddr1=(s3c_lcd->fix.smem_start>>1) & ~(3<<30); /*lcsaddr2的bit[20:0]对应A[21:1],所以最低一位不需要,右移一位,其他位清0*/ lcd_regs->lcdsaddr2=((s3c_lcd->fix.smem_start+s3c_lcd->fix.smem_len)>>1)& 0x1fffff; lcd_regs->lcdsaddr3=(240*16/16);/*一行的长度(单位2字节)*/ //s3c_lcd->fix.smem_start=xxx;/*显存的物理地址*/ /*启动LCD*/ lcd_regs->lcdcon1 |=(1<<0);/*使能LCD控制器*/ lcd_regs->lcdcon5 |=(1<<3);/*使能LCD本身*/ *gpbdat |=1; /*输出高电平,使能背光*/ /*4.注册*/ register_framebuffer(s3c_lcd); return 0; } static void lcd_exit(void) { unrigster_framebuffer(s3c_lcd); lcd_regs->lcdcon1 &= ~(1<<0); /*关闭LCD本身*/ *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");
上一篇:ARM9 mini2451裸机学习——NAND flash驱动学习 2
下一篇:《韦东山视频第二期》——LCD驱动
推荐阅读最新更新时间:2024-11-17 08:19