zoukankan      html  css  js  c++  java
  • linux下LCD驱动程序

    定义LCD相应寄存器的结构体

    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;
    };

    定义调色板,假的调色板,如果framebuffer中的数据足够用的话,就不需要调色板,这里只是为了兼容。

    u32 pseudo_palette[16];

    定义LCD寄存器结构体变量

    volatile struct lcd_regs* lcd_regs;
    其他定义
    static struct fb_info *s3c_lcd;
    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;
    构造fb_ops结构体
    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 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;
    }

    1.分配fb_info结构体

    struct fb_info *s3c_lcd = framebuffer_alloc(0, NULL);
    2.设置fb_info结构体
    2.1设置固定参数
    strcpy(s3c_lcd->fix.id, "mylcd");
    s3c_lcd->fix.smem_len = 480*272*32/8;/* 单位字节 */
    s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS;
    s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR;
    s3c_lcd->fix.line_length = 480*4;/* 单位字节 */

    2.2设置可变参数

    s3c_lcd->var.xres = 480;
    s3c_lcd->var.yres = 272;
    s3c_lcd->var.xres_virtual = 480;
    s3c_lcd->var.yres_virtual = 272;
    s3c_lcd->var.bit_per_pixel = 32;
    /* RGB */
    s3c_lcd->var.red.offset = 16;
    s3c_lcd->var.red.lenght = 8;
    s3c_lcd->var.green.offset = 8;
    s3c_lcd->var.green.length = 8;
    s3c_lcd->var.blue.offset = 0;
    s3c_lcd->var.blue.length = 8;
    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_size = 480*270*32/8;
    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;
    *gpdcon = 0xaaaaaaaa;
    *gpbcon |= (3<<8);/* 使能LCD_PWREN */
    3.2映射LCD寄存器并设置
    lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs));
    lcd_regs->lcdcon1 = (4<<8) | (3<<5) | (0x0d<<1);/* 设置CLKVAL,VCLK = HCLK / [(CLKVAL+1) x 2], LCD手册P22 (Dclk=9MHz~15MHz) */
    /* 垂直方向的时间参数 */
    /*VBPD VSYNC之后再过多长时间发出第一行数据*/
    /* VFPD 发出最后一行后再过多长时间发出VSYNC */
    /* VSPW VSYNC信号的脉冲宽度 */
    lcd_regs->lcdcon2 = (1<<24) | (271<<14) | (1<<6) | (9<<0);
    /* 水平方向的时间参数 */
    /* HBPD HSYNC之后再过多长时间才能发出这一行数据 */
    /* HFPD 发出一行最后一个像素数据之后,再过多长时间才能发出HSYNC */
    lcd_regs->lcdcon3 = (1<<19) | (479<<8) | (1<<0);
    /* HSPW HSYNC信号的脉冲宽度 */
    lcd_regs->lcdcon4 = 40;
    /* 信号极性、字节序 */
    lcd_regs->lcdcon5 = (0<<10) | (1<<9) | (1<<8) | (0<<12) | (0<<1) | (0<<0);
    3.3分配显存,并把地址告诉LCD控制器
    /* s3c_lcd->fix.smem_start为显存的物理地址 */
    s3c_lcd->screen_base = dma_alloc_writecombine(NULL, s3c_lcd->fix.smem_len, &s3c_lcd->fix.smem_start, GFP_KERNEL);
    lcd_regs->lcdaddr1 = (s3c_lcd->fix.smem_start >> 1) & ~(3<<30);
    lcd_regs->lcdaddr2 = ((s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len) >> 1) & 0x1fffff;
    lcd_regs->lcdaddr3 = (480*32/16);  /* 一行的长度(单位: 2字节) */
    3.4启动LCD
    lcd_regs->lcdcon1 |= (1<<0); /* 使能LCD控制器 */
    lcd_regs->lcdcon5 |= (1<<3); /* 使能LCD器件: LCD_PWREN */
    4.注册
    register_framebuffer(s3c_lcd);/* /dev/fb0 */

    5.测试LCD驱动

    5.1配置内核,去掉原来的驱动程序

    -> Device Drivers
      -> Graphics support
    <M> S3C2410 LCD framebuffer support
    5.2编译内核
    make zImage
    make modules
    将编译出来的cfbcopyarea.ko、cfbfillrect.ko、cfbimgblt.ko模块拷贝到文件系统
    5.3使用新内核启动开发板
    insmod cfbcopyarea.ko
    insmod cfbfillrect.ko
    insmod cfbimgblt.ko
    insmod lcd.ko
    5.4测试
    echo hello > /dev/tty1  // 可以在LCD上看见hello。
    echo hello起作用的前提是要配置:CONFIG_FRAMEBUFFER_CONSOLE
    cat lcd.ko > /dev/fb0   // 花屏
  • 相关阅读:
    【Maven实战技巧】「插件使用专题」MavenArchetype插件创建自定义maven项目骨架
    ☕【权限设计系列】「认证授权专题」微服务架构的登陆认证问题
    ☕【Java深层系列】「技术盲区」让我们一起探索一下Netty(Java)底层的“零拷贝ZeroCopy”技术(上)
    【Redis集群原理专题】分析一下相关的Redis集群模式下的脑裂问题!
    🏆【Alibaba中间件技术系列】「RocketMQ技术专题」Broker配置介绍及发送流程、异常(XX Busy)问题分析
    ☕【难点攻克技术系列】「海量数据计算系列」如何使用BitMap在海量数据中对相应的进行去重、查找和排序
    盘点 2021|「避坑宝典」为大家分享一下笔者在 2021 年所遇到“匪夷所思”的 Bug 趣事(上)
    🏆【Alibaba中间件技术系列】「RocketMQ技术专题」小白专区之领略一下RocketMQ基础之最!
    🍃【Spring专题】「原理系列」SpringMVC的运行工作原理(补充修订)
    🏆【Alibaba中间件技术系列】「EasyExcel实战案例」实战研究一下EasyExcel如何从指定文件位置进行读取数据
  • 原文地址:https://www.cnblogs.com/zpehome/p/3817702.html
Copyright © 2011-2022 走看看