移植tiny210 的lcd驱动

来源:互联网 发布:mac如何截取视频 编辑:程序博客网 时间:2024/06/05 16:52

lcd驱动:

RGB 接口, 写一个lcd驱动,我的建议就是有空必须认认真真的看完 210的lcd 控制器的datasheet。 

tiny210的lcd控制器支持很多复杂的功能,比如overlay , color-key等,我们这里不去关心。

一个lcd驱动简单来说就是软件框架和硬件数据传输。

软件框架:

        参考fbmem.c  这部分网上资料很多。

硬件数据传输:

        参考s5pv210 的lcd 控制器手册:

我们只需要根据 手册配置完相关寄存器实现下图的传输就好了。

 

 

 

附上lcd驱动的代码:

<strong>#include <linux/kernel.h>#include <linux/module.h>#include <linux/platform_device.h>#include <linux/dma-mapping.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/clk.h>#include <linux/fb.h>#include <linux/io.h>#include <linux/uaccess.h>#include <linux/interrupt.h>#include <linux/pm_runtime.h>#include <mach/map.h>#include <plat/regs-fb-v4.h>#include <plat/fb.h>#include <plat/gpio-cfg.h>#include <linux/gpio.h>#include <mach/regs-clock.h>#include <mach/regs-gpio.h>#include <linux/regulator/consumer.h>static u32 pseudo_palette[16];static  volatile   unsigned int  *vidw00add0b0; //  Window 2’s buffer start address register, buffer 0. static  volatile   unsigned int  *vidw00add1b0; // window 2’s buffer end address register, buffer 0static  volatile   unsigned int  *vidw00add2;  // win dow 2’s buffer size register.static  volatile   unsigned int  *gpd0con;  static  volatile   unsigned int  *gpd0dat;  static  volatile   unsigned int  *gpf0con;  static  volatile   unsigned int  *gpf1con;  static  volatile   unsigned int  *gpf2con;  static  volatile   unsigned int  *gpf3con;  static  volatile   unsigned int  *display_control;  static  volatile   unsigned int  *vidosd0a;  static  volatile   unsigned int  *vidosd0b;  static  volatile   unsigned int  *vidosd0c;  static  volatile   unsigned int *wincon0   ;static  volatile   unsigned int *vidcon0   ;static  volatile   unsigned int *vidcon1   ; static  volatile   unsigned int *vidtcon0  ; static  volatile   unsigned int *vidtcon1  ; static  volatile   unsigned int *vidtcon2  ; static  volatile   unsigned int *shadowcon ; static struct fb_info*s5p_lcd_info;static struct clk *lcd_clk ;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 s3cfb_setcolreg(unsigned int regno, unsigned int red,   unsigned int green, unsigned int blue,   unsigned int transp, struct fb_info *info){    unsigned int val;  printk("neo: s3cfb_setcolreg \n" );     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 s5pfb_ops = {.owner = THIS_MODULE,.fb_fillrect = cfb_fillrect,.fb_copyarea = cfb_copyarea,.fb_imageblit = cfb_imageblit,.fb_setcolreg = s3cfb_setcolreg,};static int __init s5p_fb_init(void){/*  分配一个fb_info */s5p_lcd_info = framebuffer_alloc(0, NULL);  //  size 是指 info 之外的大小/* 设置 fb_info */strcpy(s5p_lcd_info->fix.id, "s5pv210_lcd");s5p_lcd_info->fix.smem_len = 800*480*4;s5p_lcd_info->fix.type = FB_TYPE_PACKED_PIXELS;s5p_lcd_info->fix.visual = FB_VISUAL_TRUECOLOR;s5p_lcd_info->fix.line_length = 800*4;/* var */s5p_lcd_info->var.xres = 800;s5p_lcd_info->var.yres = 480;s5p_lcd_info->var.xres_virtual = 800;s5p_lcd_info->var.yres_virtual = 480;s5p_lcd_info->var.bits_per_pixel = 32;s5p_lcd_info->var.red.offset = 16;s5p_lcd_info->var.red.length = 8;s5p_lcd_info->var.green.offset = 8;s5p_lcd_info->var.green.length = 8;s5p_lcd_info->var.blue.offset = 0;s5p_lcd_info->var.blue.length = 8;s5p_lcd_info->var.activate = FB_ACTIVATE_NOW;s5p_lcd_info->screen_size = 800*480*4;s5p_lcd_info->pseudo_palette = pseudo_palette;s5p_lcd_info->fbops = &s5pfb_ops; /* 使能时钟 */      lcd_clk = clk_get(NULL, "lcd");      if (!lcd_clk || IS_ERR(lcd_clk)) {          printk(KERN_INFO "failed to get lcd clock source\n");     }      clk_enable(lcd_clk);  /* 映射lcd控制器的寄存器 */display_control = ioremap(0xe0107008, 4);gpd0con      = ioremap(0xE02000A0, 4);gpd0dat      = ioremap(0xE02000A4, 4);gpf0con      = ioremap(0xE0200120, 4);gpf1con      = ioremap(0xE0200140, 4);gpf2con      = ioremap(0xE0200160, 4);gpf3con      = ioremap(0xE0200180, 4);  vidcon0      = ioremap(0xF8000000, 4);  vidcon1      = ioremap(0xF8000004, 4);  vidtcon0     = ioremap(0xF8000010, 4);  vidtcon1     = ioremap(0xF8000014, 4);  vidtcon2     = ioremap(0xF8000018, 4);  wincon0      = ioremap(0xF8000020, 4); vidosd0a     = ioremap(0xF8000040, 4);vidosd0b     = ioremap(0xF8000044, 4);vidosd0c     = ioremap(0xF8000048, 4); vidw00add0b0 = ioremap(0xF80000A0, 4);vidw00add1b0 = ioremap(0xF80000D0, 4);shadowcon    = ioremap(0xF8000034, 4);  /* config  gpio */*gpf0con = 0x22222222;*gpf1con = 0x22222222;*gpf2con = 0x22222222;*gpf3con = 0x22222222;/* 打开背光 */*gpd0con &= ~(0xf<<4);          *gpd0con |= 1<<4;     *gpd0dat |= 1<<1;// 10: RGB=FIMD I80=FIMD ITU=FIMD*display_control = 2<<0;/* lcd 控制器初始化 和 设置  */    // 设置vclk 频率    // 一帧频率设为 65 hz     // 那么一个像素的频率为  (65* ( 80 + 36 + 10 + 480 ) *( 22 +15+ 8 + 800)) = 33284550 hz // hclk = 166750000hz   vclk = 33284550hz  div = 5+1 = 6 *vidcon0  |= (0<<16)|(0<<5)|(1<<4)|(0<<2)|(5<<6);// 设置  时钟 极性 *vidcon1  |= (0<<7)|(1<<6)|(1<<5)|(0<<4); // 设置video timing 即前后左右间距  设置lcd 的分辨率*vidtcon0 |= (0<<24)|(14<<16)|(21<<8)|(7<<0) ;  *vidtcon1 |= (0<<24)|(35<<16)|(209<<8)|(9<<0) ;*vidtcon2 |= (799<<0)|(479<<11);  *wincon0 &= ~(0xf << 2);*wincon0 |=  (1 << 15)|(0xb << 2);// 设置window position(0  0)(799 499)*vidosd0a  = (0<<11) |(0<<0);*vidosd0b  = (799<<11) |(479<<0);*vidosd0c  = 800*480;s5p_lcd_info->screen_base = dma_alloc_writecombine(NULL,PAGE_ALIGN(s5p_lcd_info->fix.smem_len),(dma_addr_t *)&(s5p_lcd_info->fix.smem_start), GFP_KERNEL); // 把 framebuffer 地址告诉lcd 控制器*vidw00add0b0 =  (unsigned int)s5p_lcd_info->fix.smem_start; // 放的是物理地址*vidw00add1b0 =  (unsigned int)s5p_lcd_info->fix.smem_start + s5p_lcd_info->fix.smem_len;// 打开输出信号总开关  打开window 0  窗口0  *vidcon0  |= (1<<0)|(1<<1); *wincon0   |= (1<<0);*shadowcon |= (1<<0);/* 4. 注册 fb_info */ register_framebuffer(s5p_lcd_info);  #if defined(CONFIG_LOGO)if (fb_prepare_logo( s5p_lcd_info, FB_ROTATE_UR)) {printk("Start display and show logo\n");/* Start display and show logo on boot */fb_set_cmap(&s5p_lcd_info->cmap, s5p_lcd_info);fb_show_logo(s5p_lcd_info, FB_ROTATE_UR);}#endifprintk("neo: lcd_init\n");return 0;}static void __exit s5p_fb_cleanup(void){unregister_framebuffer(s5p_lcd_info);dma_free_writecombine(NULL,  s5p_lcd_info->fix.smem_len, s5p_lcd_info->screen_base,s5p_lcd_info->fix.smem_start);iounmap(vidw00add0b0);iounmap(vidw00add1b0);iounmap(vidw00add2);iounmap(gpd0con);iounmap(gpd0dat);iounmap(gpf0con);iounmap(gpf1con);iounmap(gpf2con);iounmap(gpf3con);iounmap(display_control);iounmap(vidosd0a);iounmap(vidosd0b);iounmap(vidosd0c);    iounmap(shadowcon);      iounmap(wincon0);      iounmap(vidtcon2);      iounmap(vidtcon1);      iounmap(vidtcon0);      iounmap(vidcon1);      iounmap(vidcon0); framebuffer_release(s5p_lcd_info);}module_init(s5p_fb_init);module_exit(s5p_fb_cleanup);MODULE_LICENSE("GPL");</strong>


 

测试:

1. cat lcd.ko > /dev/fb0   // 花屏

2. 在内核启动时可以看到linux内核自带的小企鹅的图片。

3. 测试程序:

显示英文,中文,宋体汉字,以及图片。

参考韦老师的第一期项目视频。

我写在了另一篇博客里。

0 0
原创粉丝点击