一、LCD驱动框架:

1.分配一个fb_info结构体:s3c_lcd = framebuffer_alloc(0,NULL);

2.设置fb_info(s3c_lcd): ID、固定参数、可变参数、设置操作函数 及 其他设置

3.注册:register_framebuffer(s3c_lcd);

4.硬件相关的操作:   ①分配引脚用于LCD

          ②根据LCD手册设置控制器参数

          ③分配显存并将地址告诉LCD控制器

显存分配:在嵌入式系统中一般没有专门的显存,而仅仅是从RAM(SDRAM)空间中分配一段显示缓冲区,LCD也可说是一个frame buffer 设备

      lcdc.palette_virt = dma_alloc_writecombine(lcdc.fbdev->dev,MAX_PALETTE_SIZE, &lcdc.palette_phys, GFP_KERNEL);

 硬件时序:
      VCLK:每来一个时钟就向下移动一个像素。
      VD0~VD23:数据宽度,但是我们只用了16位。
      VLINE:(HYSNC,行同步型号,水平方向的,从上一行的行尾调到下一行的行首),
      VSYNC:(垂直同步信号,从最后一行行尾跳转到第一行的行首)
      VDEN:有效才打印颜色

调色板:存储256种颜色的RGB值,每种颜色的RGB值是16位。用这256种颜色编制索引,从OOH~FFH只需 要8位数据宽度,而每个索引所对应的颜色却是16位宽度的颜色信息,通过调色板的转换可以减少显存的开销。

二、LCD驱动代码:

  lcd_4.3.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/clk.h> #include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/div64.h> #include <asm/mach/map.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/fb.h> 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[];
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, //设置调色板
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
}; 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;
static volatile struct lcd_regs* lcd_regs;
static u32 pseudo_palette[]; /* from pxafb.c */
static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
{
chan &= 0xffff;
chan >>= - 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 > )
return ; /* 用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 ;
} static int lcd_init(void)
{
/* 1. 分配一个fb_info */
s3c_lcd = framebuffer_alloc(, NULL); /* 2. 设置 */
/* 2.1 设置固定的参数 */
strcpy(s3c_lcd->fix.id, "mylcd");
s3c_lcd->fix.smem_len = **/;
s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS;
s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR; /* TFT */
s3c_lcd->fix.line_length = *; /* 2.2 设置可变的参数 */
s3c_lcd->var.xres = ;
s3c_lcd->var.yres = ;
s3c_lcd->var.xres_virtual = ;
s3c_lcd->var.yres_virtual = ;
s3c_lcd->var.bits_per_pixel = ; /* RGB:565 */
s3c_lcd->var.red.offset = ;
s3c_lcd->var.red.length = ; s3c_lcd->var.green.offset = ;
s3c_lcd->var.green.length = ; s3c_lcd->var.blue.offset = ;
s3c_lcd->var.blue.length = ; 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 = **/; /* 3. 硬件相关的操作 */
/* 3.1 配置GPIO用于LCD */
gpbcon = ioremap(0x56000010, );
gpbdat = gpbcon+;
gpccon = ioremap(0x56000020, );
gpdcon = ioremap(0x56000030, );
gpgcon = ioremap(0x56000060, ); *gpccon = 0xaaaaaaaa; /* GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND */
*gpdcon = 0xaaaaaaaa; /* GPIO管脚用于VD[23:8] */ *gpbcon &= ~(); /* GPB0设置为输出引脚 */
*gpbcon |= ;
*gpbdat &= ~; /* 输出低电平,默认关闭背光 */ *gpgcon |= (<<); /* 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 = (<<) | (<<) | (0x0c<<); #if 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 = (<<) | (<<) | (<<) | (); /* 水平方向的时间参数
* 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 = (<<) | (<<) | (); /* 水平方向的同步信号
* bit[7:0] : HSPW, HSYNC信号的脉冲宽度, LCD手册T7=5, 所以HSPW=5-1=4
*/
lcd_regs->lcdcon4 = ; #else
lcd_regs->lcdcon2 = S3C2410_LCDCON2_VBPD() | \
S3C2410_LCDCON2_LINEVAL() | \
S3C2410_LCDCON2_VFPD() | \
S3C2410_LCDCON2_VSPW(); lcd_regs->lcdcon3 = S3C2410_LCDCON3_HBPD() | \
S3C2410_LCDCON3_HOZVAL() | \
S3C2410_LCDCON3_HFPD(); lcd_regs->lcdcon4 = S3C2410_LCDCON4_MVAL() | \
S3C2410_LCDCON4_HSPW(); #endif
/* 信号的极性
* 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 = (<<) | (<<) | (<<) | (<<) | (<<); /* 3.3 分配显存(framebuffer), 并把地址告诉LCD控制器 */
s3c_lcd->screen_base = dma_alloc_writecombine(NULL, s3c_lcd->fix.smem_len, &s3c_lcd->fix.smem_start, GFP_KERNEL); lcd_regs->lcdsaddr1 = (s3c_lcd->fix.smem_start >> ) & ~(<<);
lcd_regs->lcdsaddr2 = ((s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len) >> ) & 0x1fffff;
lcd_regs->lcdsaddr3 = (*/); /* 一行的长度(单位: 2字节) */ //s3c_lcd->fix.smem_start = xxx; /* 分配到的显存物理地址 */
/* 启动LCD */
lcd_regs->lcdcon1 |= (<<); /* 使能LCD控制器 */
lcd_regs->lcdcon5 |= (<<); /* 使能LCD本身 */
*gpbdat |= ; /* 输出高电平, 使能背光 */ /* 4. 注册 */
register_framebuffer(s3c_lcd); return ;
} static void lcd_exit(void)
{
unregister_framebuffer(s3c_lcd);
lcd_regs->lcdcon1 &= ~(<<); /* 关闭LCD本身 */
*gpbdat &= ~; /* 关闭背光 */
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");

Makefile

KERN_DIR = /work/system/linux-2.6.22.6

all:
make -C $(KERN_DIR) M=`pwd` modules clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order obj-m += lcd_4.3.o

三、测试驱动;

方法1:修改内核自带的lcd驱动代码  /drivers/video/s3c2410fb.c 以支持单板的LCD ;

方法2:配置内核lcd驱动编译为模块:

  make menuconfig

  Device Drivers  --->

    Graphics support  --->

      <*> Support for frame buffer devices  --->

         <M>   S3C2410 LCD framebuffer support

  

  make modules  ---> 生成 .ko

  make uImage    ---> 生成去掉lcd驱动的内核镜像

用U-boot下载烧录新内核:
  tftp 0x30000000 uImage
  nand erase.part kernel
  nand write.i 0x30000000 kernel $filesize

  reset 或者 用nfs 网络挂载启动新内核: nfs 32000000 192.168.1.123:/work/nfs_root/uImage_new; bootm 32000000 新内核启动后可以发现 /dev/fb0 节点已经不存在,
加载移植好的lcd驱动模块: insmod /mnt/nfs_root/3.4.83_driver/lcd_4.3.ko
然后 /dev/fb0 重新生成。

-end-

 

Linux学习: LCD驱动的更多相关文章

  1. Smart210学习-----lcd驱动

    帧缓冲设备 1.1帧缓冲设备:帧缓冲(framebuffer)是 Linux 系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行 ...

  2. Linux的LCD驱动分析及移植

    测试平台 宿主机平台:Ubuntu 12.04.4 LTS 目标机:Easy-ARM IMX283 目标机内核:Linux 2.6.35.3 LCD驱动分析 LCD屏的驱动总体上分成两块,一块是GUI ...

  3. Linux学习: 触摸屏驱动

    一.Linux输入子系统的结构: 二.触摸屏驱动代码: s3c_ts.c #include <linux/errno.h> #include <linux/kernel.h> ...

  4. Linux驱动:LCD驱动框架分析

    一直想花时间来整理一下Linux内核LCD驱动,却一直都忙着做其他事情去了,这些天特意抽出时间来整理之前落下的笔记,故事就这样开始了.LCD驱动也是字符设备驱动的一种,框架上相对于字符设备驱动稍微复杂 ...

  5. 嵌入式Linux驱动学习之路(十八)LCD驱动

    驱动代码: /************************************************************************* > File Name: lcd ...

  6. LCD驱动学习笔记

    通过这几天的学习发现驱动的框架感觉都差不多,一般分为以下几个步骤: 分配一个结构体 struct x *x = amlloc(); 设置结构体的参数 硬件寄存器 file_operations 注册 ...

  7. AM335x(TQ335x)学习笔记——LCD驱动移植

    TI的LCD控制器驱动是非常完善的,共通的地方已经由驱动封装好了,与按键一样,我们可以通过DTS配置完成LCD的显示.下面,我们来讨论下使用DTS方式配置内核完成LCD驱动的思路. (1)初步分析 由 ...

  8. Linux驱动之LCD驱动编写

    在Linux驱动之内核自带的S3C2440的LCD驱动分析这篇博客中已经分析了编写LCD驱动的步骤,接下来就按照这个步骤来字尝试字节编写LCD驱动.用的LCD屏幕为tft屏,每个像素点为16bit.对 ...

  9. linux 驱动之LCD驱动(有framebuffer)

    <简介> LCD驱动里有个很重要的概念叫帧缓冲(framebuffer),它是Linux系统为显示设备提供的一个接口,应用程序在图形模式允许对显示缓冲区进行读写操作.用户根本不用关心物理显 ...

随机推荐

  1. reactiveCocoa使用

    @代理 简介:使用RACSubject信号替换 控制器2的操作: <1在头文件定义一个信号: @property (nonatomic, strong) RACSubject *delegate ...

  2. 比对软件之STAR的使用方法

    建索引 普通比对 二次比对 用于cufflinks和stringtie的比对 待续~ 参考:比对软件STAR的简单使用

  3. H3C常用配置和命令

    邻居发现命令display lldp neighbor-information list DHCP中继配置dhcp enabledhcp relay server-group 1 ip x.x.x.x ...

  4. Linux网桥配置

    CentOS:1.配置临时网桥,重启后风格配置丢失[root@CentOS ~]# yum -y install bridge-utils[root@CentOS ~]# brctl addbr br ...

  5. 20170914xlVBA通讯公司分类汇总

    Sub 租房() Dim Wb As Workbook Dim Sht As Worksheet Dim OpenWb As Workbook Dim OpenSht As Worksheet Dim ...

  6. Practical Node.js (2018版) 第7章:Boosting Node.js and Mongoose

    参考:博客 https://www.cnblogs.com/chentianwei/p/10268346.html 参考: mongoose官网(https://mongoosejs.com/docs ...

  7. Xor-MST CodeForces - 888G (最小生成树,分治)

    大意: n结点无向完全图, 给定每个点的点权, 边权为两端点异或值, 求最小生成树

  8. python获取文件路径、文件名、后缀名的实例

    def jwkj_get_filePath_fileName_fileExt(filename): (filepath,tempfilename) = os.path.split(filename); ...

  9. 5月13 jquery的一些应用

    首先对于JavaScript的一些复习:操作内容,操作属性,操作样式 <title>无标题文档</title> <style> #aa { width:200px; ...

  10. HDU-6336-构造

    Problem E. Matrix from Arrays Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 ...