基于S3c2440的LCD驱动

LCD驱动程序

LCD的一些重要函数定义

  • fb_info结构体
    包含了关于帧缓冲设备属性和操作的完整过程

    fb_info中记录了帧缓冲设备的全部信息,包括设备的设置参数,状态以及操作函数指针。每一个帧缓冲设备都必须对应一个fb_info
struct fb_info {
    int node;
    int flags;
    struct fb_var_screeninfo var;   /* 可变参数*/
    struct fb_fix_screeninfo fix;   /* 固定参数 */
    struct fb_monspecs monspecs;    /* 显示器标准 */
    struct work_struct queue;   /* 帧缓冲事件队列 */
    struct fb_pixmap pixmap;    /* 图像硬件mapper */
    struct fb_pixmap sprite;    /* 光标硬件mapper */
    struct fb_cmap cmap;        /* 目前的颜色表*/
    struct list_head modelist;      /* 模式列表 */
    struct fb_videomode *mode;  /* 目前的video模式 */

#ifdef CONFIG_FB_BACKLIGHT
    /* 对应的背光设备 */
    /* 在framebuffer注册之前设置,
注销后移除 */
    struct backlight_device *bl_dev;

    /* 背光调整 */
    struct mutex bl_curve_mutex;    
    u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IO
    struct delayed_work deferred_work;
    struct fb_deferred_io *fbdefio;
#endif

    struct fb_ops *fbops;   /*fb_ops帧缓冲设备操作*/
    struct device *device;      /* 父设备 */
    struct device *dev;     /* fb设备 */
    int class_flag;                    /*私有sysfs标志 */
#ifdef CONFIG_FB_TILEBLITTING
    struct fb_tile_ops *tileops;    /* 图块Blitting */
#endif
    char __iomem *screen_base;  /* 虚拟基地址 */
    unsigned long screen_size;  /* ioremapped的虚拟内存大小 */ 
    void *pseudo_palette;       /* 伪16色颜色表 */ 
#define FBINFO_STATE_RUNNING    0
#define FBINFO_STATE_SUSPENDED  1
    u32 state;          /* 硬件状态如挂起 */
    void *fbcon_par;                /* 仅使用fbcon区域 */
    /*这里的一切都是依赖设备的 */
    void *par;  
};
  • fb_ops结构体

fb_info的成员变量fb_ops为指向底层操作的函数的指针,这些函数是需要驱动程序人员编写的


/*
 * 帧缓冲操作
 */

struct fb_ops {
    /* 打开/释放 */
    struct module *owner;
    int (*fb_open)(struct fb_info *info, int user);
    int (*fb_release)(struct fb_info *info, int user);

    /* 
     * 对于非线性布局的/常规内存映射无法工作的帧缓冲设备需要
     */
    ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
               size_t count, loff_t *ppos);
    ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
                size_t count, loff_t *ppos);

    /*
     * 检测可变参数,并调整到支持的值
     */
    int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);

    /*  根据info->var设置video模式 */
    int (*fb_set_par)(struct fb_info *info);

    /* 设置color寄存器*/
    int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
                unsigned blue, unsigned transp, struct fb_info *info);

    /* 批量设置color寄存器,设置颜色表 */
    int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);

    /* 显示空白 */
    int (*fb_blank)(int blank, struct fb_info *info);

    /* pan显示 */
    int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);

    /* 矩形填充 */
    void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
    /* 数据复制到另一个区域 */
    void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
    /* 图形填充 */
    void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);

    /* 绘制光标 */
    int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);

    /* 旋转显示 */
    void (*fb_rotate)(struct fb_info *info, int angle);

    /*等待blit空闲(可选) */
    int (*fb_sync)(struct fb_info *info);

    /*fb特定的ictol(可选) */
    int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
            unsigned long arg);

    /* 处理32位的compat ioctl (可选) */
    int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
            unsigned long arg);

    /* fb特定的mmap */
    int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);

    /* 保存目前的硬件状态 */
    void (*fb_save_state)(struct fb_info *info);

    /* 恢复被保存的硬件状态 */
    void (*fb_restore_state)(struct fb_info *info);

    /* 通过fb_info获得framebuffer的能力 */
    void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
                struct fb_var_screeninfo *var);
};
  • fb_ops的fb_check_var()成员函数用于检查可以修改的屏幕参数并调整到合适的值,而fb_set_par()则使得用户设置的屏幕参数在硬件上有效
  • b_fix_screeninfo结构体中,记录了用户不能修改的固定显示控制器参数。这些固定的参数如缓冲区的物理地址、缓冲区的长度等等。
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */

  字符串形式的标识符
unsigned long smem_start;/* Start of frame buffer mem */

  /* (physical address) */

  fb缓存的开始位置
__u32 smem_len;/* Length of frame buffer mem */

  fb缓存的长度
__u32 type; /* see FB_TYPE_* */

  FB_TYPE_*类型
__u32 type_aux;/* Interleave for interleaved Planes */

  分界
__u32 visual; /* see FB_VISUAL_* */

  屏幕使用的色彩模式 
__u16 xpanstep;/* zero if no hardware panning  */

  如果没有硬件panning ,赋0
__u16 ypanstep;/* zero if no hardware panning  */

  __u16 ywrapstep;/* zero if no hardware ywrap    */

  1行的字节数
__u32 line_length;/* length of a line in bytes    */

  内存映射I/O的开始位置
unsigned long mmio_start;/* Start of Memory Mapped I/O   */
/* (physical address) */

  内存映射I/O的长度
__u32 mmio_len;/* Length of Memory Mapped I/O  */
__u32 accel; /* Indicate to driver which */
/*  specific chip/card we have*/
__u16 reserved[3];/* Reserved for future compatibility */
};
  • fb_var_screeninfo结构体中存储了用户可以修改的显示器控制参数,例如屏幕分辨率、透明度等等。

struct fb_var_screeninfo {
__u32 xres; /* visible resolution  可见分辨率*/
__u32 yres;

                    可见解析度,即分辨率
__u32 xres_virtual;/* virtual resolution */
__u32 yres_virtual;

  虚拟解析度
__u32 xoffset;/* offset from virtual to visible */
__u32 yoffset;/* resolution */

        虚拟到可见之间的偏移
__u32 bits_per_pixel;/* guess what */

  每像素位数,BPP
__u32 grayscale;/* != 0 Graylevels instead of colors */

  非0时指灰度


struct fb_bitfield red;/* bitfield in fb mem if true color, */
struct fb_bitfield green;/* else only length is significant */
struct fb_bitfield blue;

  fb缓存的R\G\B位域
struct fb_bitfield transp;/* transparency */

  透明度

__u32 nonstd; /* != 0 Non standard pixel format */

  != 0 非标准像素格式

__u32 activate;/* see FB_ACTIVATE_* */

  
__u32 height; /* height of picture in mm    */

  屏幕的高度
__u32 width; /* width of picture in mm     */

         屏幕的宽度
__u32 accel_flags;/* (OBSOLETE) see fb_info.flags */
         fb_info的标志

/* Timing: All values in pixclocks, except pixclock (of course) */
__u32 pixclock;/* pixel clock in ps (pico seconds) */

  /* 像素时钟(皮秒) */
__u32 left_margin;/* time from sync to picture */

  行切换:从同步到绘图之间的延迟
__u32 right_margin;/* time from picture to sync */

  行切换:从绘图到同步之间的延迟
__u32 upper_margin;/* time from sync to picture */

  帧切换:从同步到绘图之间的延迟
__u32 lower_margin;

  帧切换:从绘图到同步之间的延迟
__u32 hsync_len;/* length of horizontal sync */

  水平同步的长度
__u32 vsync_len;/* length of vertical sync */

  垂直同步的长度
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 rotate; /* angle we rotate counter clockwise */

  顺时钟旋转的角度
__u32 reserved[5];/* Reserved for future compatibility */
};
  • fb_cmap结构体中记录了颜色板信息,即调色板信息。,用户空间可以通过ioctl()的FBIOGETCMAP和 FBIOPUTCMAP命令读取或设定颜色表。

struct fb_cmap {
__u32 start; /* First entry */第一个元素的入口
__u32 len; /* Number of entries */元素个数
__u16 *red; /* Red values */红色、绿色、蓝色
__u16 *green;  
__u16 *blue;
__u16 *transp;/* transparency, can be NULL */透明度
};

怎么写LCD驱动程序?

  1. 分配一个fb_info结构体: framebuffer_alloc
  2. 设置参数
  3. 注册: register_framebuffer
  4. 硬件相关的操作

     
static int lcd_init(void)
{
    /* 1. 分配一个fb_info */
    s3c_lcd = framebuffer_alloc(0, NULL);

    /* 2. 设置 */
    /* 2.1 设置固定的参数 */
    strcpy(s3c_lcd->fix.id, "mylcd");
    s3c_lcd->fix.smem_len = 240*320*16/8;
    s3c_lcd->fix.type     = FB_TYPE_PACKED_PIXELS;
    s3c_lcd->fix.visual   = FB_VISUAL_TRUECOLOR; /* TFT */
    s3c_lcd->fix.line_length = 240*2;

    /* 2.2 设置可变的参数 */
    s3c_lcd->var.xres           = 240;
    s3c_lcd->var.yres           = 320;
    s3c_lcd->var.xres_virtual   = 240;
    s3c_lcd->var.yres_virtual   = 320;
    s3c_lcd->var.bits_per_pixel = 16;

    /* RGB:565 */
    s3c_lcd->var.red.offset     = 11;
    s3c_lcd->var.red.length     = 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 =; //
    //s3c_lcd->screen_base  = ;  /* 显存的虚拟地址 */ 
    s3c_lcd->screen_size   = 240*324*16/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;   /* GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND */
    *gpdcon  = 0xaaaaaaaa;   /* GPIO管脚用于VD[23:8] */ 

    *gpbcon &= ~(3);  /* GPB0设置为输出引脚 */
    *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) x 2], LCD手册P14
     *            10MHz(100ns) = 100MHz / [(CLKVAL+1) x 2]
     *            CLKVAL = 4
     * bit[6:5]: 0b11, TFT LCD
     * bit[4:1]: 0b1100, 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, VSYNC之后再过多长时间才能发出第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<<8) | (10<<0);

    /* 水平方向的同步信号
     * bit[7:0] : HSPW, HSYNC信号的脉冲宽度, LCD手册T7=5, 所以HSPW=5-1=4
     */ 
    lcd_regs->lcdcon4 = 4;

    /* 信号的极性 
     * bit[11]: 1=565 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
     * bit[1] : 0 = BSWP
     * bit[0] : 1 = HWSWP 2440手册P413
     */
    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);

    /参数说明 设备类型NULL  显存空间大小  存放取值物理地址  标记

    lcd_regs->lcdsaddr1  = (s3c_lcd->fix.smem_start >> 1) & ~(3<<30);  //起始地址最高两位清0
    lcd_regs->lcdsaddr2  = ((s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len) >> 1) & 0x1fffff; //结束地址 A21 到 1 左移一位
    lcd_regs->lcdsaddr3  = (240*16/16);  /* 一行的长度(单位: 2字节)半字 = 2字节 */    

    //s3c_lcd->fix.smem_start = xxx;  /* 显存的物理地址 */
    /* 启动LCD */
    lcd_regs->lc dcon1 |= (1<<0); /* 使能LCD本身 */
    *gpbdat |= 1;     /* 输出高电平, 使能背光 */     

    /* 4. 注册 */
    register_framebuffer(s3c_lcd);

    return 0;
  • 注册显存空间

    static int __devinit s3c2410fb_map_video_memory(struct fb_info *info)

    dma_alloc_writecombine//开辟一块显存空间

  • 为了省显存
    假如一个像素我只想给8位数据 但是lcd本身是16位 如何解决
    lcd控制器取到一个字节如何转换成16位数据呢 如何转换
    通过设置调色板
    原理就像数组一样 8位通过调色板数组去查询16位

  • 定义一个假的调色板

    static u32 pseudo_palette[16];

调色板处理函数

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


//红绿蓝只用到了里面16位
/* from pxafb.c */
static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
{
    chan &= 0xffff;  //只保留低16位
    chan >>= 16 - bf->length; //假设这个长度是5的话,那么16 - 5 =11 ,那就右移11位把低11位全部清掉 自保留高5位
    return chan << bf->offset;  //左移后这个值就可以使用了
}
基本的安装完后 设置调色板
s3c_lcd->pseudo_palette =

测试:

1

make menuconfig去掉原来的驱动程序

-> Device Drivers

-> Graphics support //进入图形支持

S3C2410 LCD framebuffer support //配置为M 代表是模块

2

make uImage
make modules //编译模块
3
使用新的uImage启动开发板:

4

insmod cfbcopyarea.ko

insmod cfbfillrect.ko

insmod cfbimgblt.ko

insmod lcd.ko

echo hello > /dev/tty1 // 可以在LCD上看见hello

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

5

修改 /etc/inittab

tty1::askfirst:-/bin/sh

用新内核重启开发板

insmod cfbcopyarea.ko

insmod cfbfillrect.ko

insmod cfbimgblt.ko

insmod lcd.ko

insmod buttons.ko

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值