LCD驱动 15-3

时间:2023-12-01 18:33:08

测试:
1:make menuconfig去掉原来的驱动程序
    Device Drivers  --->    
        Graphics support  ---> 
           <M> S3C2410 LCD framebuffer support                 
2: make uImage
  make modules
  cp arch/arm/boot/uImage  /work/nfs_root/uImage_nolcd

3.使用新的uImage启动开发板:

insmod cfbcopyarea.ko
insmod cfbfillrect.ko 
insmod cfbimgblt.ko

insmod lcd.ko

4.

ech0 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

通过按键控制另一个sh控制台

 #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> 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_info *s3c_lcd;
/* gpbon,gpbdat,c,d,g, */
volatile unsigned long *gpbcon;
volatile unsigned long *gpbdat;
volatile unsigned long *gpccon;
volatile unsigned long *gpdcon;
volatile unsigned long *gpgcon;
static volatile struct lcd_regs* lcd_regs;
static u32 pseudo_palette[]; 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 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 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_size = * * / ; /* 3. 硬件相关的设置 */
/* 3.1 配置GPIO用于LCD */
//0x56000010 ,8
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 &= ~(); // Power enable pin
*gpbcon |= (0x01);
*gpbdat &= ~(<<); // Power off
*gpgcon |= (<<); // GPG4用作LCD_PWREN /* 3.2 根据LCD手册设置LCD控制器,比如VCLK的频率等 */
lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs)); /*
* 设置LCD控制器的控制寄存器LCDCON1~5
* 1. LCDCON1:
* 设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2]
* 选择LCD类型: TFT LCD
* 设置显示模式: 16BPP
* 先禁止LCD信号输出
* 2. LCDCON2/3/4:
* 设置控制信号的时间参数
* 设置分辨率,即行数及列数
* 现在,可以根据公式计算出显示器的频率:
* 当HCLK=100MHz时,
* Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LIINEVAL+1)+(VFPD+1)}x
* {(HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1)}x
* {2x(CLKVAL+1)/(HCLK)}]
* = 60Hz
* 3. LCDCON5:
* 设置显示模式为16BPP时的数据格式: 5:6:5
* 设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转
* 半字(2字节)交换使能
*/ lcd_regs->lcdcon1 = (<<) | (0x3<<) | \
(0xC<<) | (<<);
lcd_regs->lcdcon2 = (<<) | (<<) | \
(<<) | (-);
lcd_regs->lcdcon3 = (<<) | (<<) | ();
lcd_regs->lcdcon4 = ;
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 = (<<) | ( */); /* 启动LCD */
lcd_regs->lcdcon1 |= ( << ); //使能LCD本身
lcd_regs->lcdcon5 |= (<<); // 设置是否输出LCD_PWREN
*gpbdat |= (<<); // Power on /* 4. 注册 */ register_framebuffer(s3c_lcd); return ;
} static int lcd_exit(void)
{
unregister_framebuffer(s3c_lcd);
lcd_regs->lcdcon1 &= ~( << ); //关闭LCD本身
*gpbdat &= ~(<<); // Power off
dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, \
s3c_lcd->screen_base, s3c_lcd->fix.smem_start); iounmap(gpbcon);
iounmap(gpccon);
iounmap(gpdcon);
iounmap(gpgcon); framebuffer_release(&s3c_lcd);
return ;
} module_init(lcd_init);
module_exit(lcd_exit); MODULE_LICENSE("GPL");