LCD驱动详解

参考文档:《液晶屏.pdf》《S3C2440用户手册》《JZ2440-V3原理图》

 

frame buffer: 显存,用于存放LCD显示数据;frame buffer通过LCD控制器和LCD Panel建立一一映射关系;

LCD控制器: 参考LCD用户手册,配置LCD控制器,用于发出LCD控制信号,驱动LCD显示;

扫描方向: 如图①所示,由start到end的扫描方向是:从左到右,从上到下(扫描方向的一种);

HSYNC: 行同步信号,用于行切换,一行扫描结束,需要扫描新行时,需要先发送行同步信号;

VSYNC: 列同步信号,用于列切换,一帧扫描结束,需要扫描新的一帧时,需要先发送列同步信号;

时钟信号: 每来一个时钟,扫描的点移位一;

   

原理图——管脚说明

 

   

 

 

硬件操作配置

①配置LCD控制引脚;

②根据LCD手册,配置LCD控制器;

③分配Frame buffer,并映射到LCD Panel;

   

《液晶屏.pdf》

Block Diagram

   

   

Interface Timing

   

Driver Timing

   

   

Timing Chart

a、

   

b、

 

《S3C2440用户手册》

LCD CONTROLLER SPECIAL REGISTERS

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

 

 

MEMORY DATA FORMAT (TFT)

 

 

驱动程序

1 /*
2 * 参考内核自带的lcd驱动程序:
3 * C:UsersliangDesktoplinux-2.6.22.6driversvideos3c2410fb.c
4 * 《液晶屏.pdf》、《s3c2440 用户手册》
5 */
6 #include <linux/module.h>
7 #include <linux/kernel.h>
8 #include <linux/errno.h>
9 #include <linux/string.h>
10 #include <linux/mm.h>
11 #include <linux/slab.h>
12 #include <linux/delay.h>
13 #include <linux/fb.h>
14 #include <linux/init.h>
15 #include <linux/dma-mapping.h>
16 #include <linux/interrupt.h>
17 #include <linux/workqueue.h>
18 #include <linux/wait.h>
19 #include <linux/platform_device.h>
20 #include <linux/clk.h>
21         
22 #include <asm/io.h>
23 #include <asm/uaccess.h>
24 #include <asm/div64.h>
25         
26 #include <asm/mach/map.h>
27 #include <asm/arch/regs-lcd.h>
28 #include <asm/arch/regs-gpio.h>
29 #include <asm/arch/fb.h>
30
31 struct lcd_regs {
32         unsigned long        lcdcon1;
33         unsigned long        lcdcon2;
34         unsigned long        lcdcon3;
35         unsigned long        lcdcon4;
36         unsigned long        lcdcon5;
37 unsigned long        lcdsaddr1;
38 unsigned long        lcdsaddr2;
39 unsigned long        lcdsaddr3;
40 unsigned long        redlut;
41 unsigned long        greenlut;
42 unsigned long        bluelut;
43 unsigned long        reserved[9];
44 unsigned long        dithmode;
45 unsigned long        tpal;
46 unsigned long        lcdintpnd;
47 unsigned long        lcdsrcpnd;
48 unsigned long        lcdintmsk;
49 unsigned long        lpcsel;
50 };
51
52
53 static volatile unsigned long *gpb_con;
54 static volatile unsigned long *gpb_dat;
55
56 static volatile unsigned long *gpc_con;
57 static volatile unsigned long *gpd_con;
58 static volatile unsigned long *gpg_con;
59
60 static volatile struct lcd_regs* lcd_regs;
61
62 static u32 pseudo_palette[16];//假的调色板
63
64 static struct fb_info *lcd_info;
65
66 static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
67 {
68         chan &= 0xffff;
69         chan >>= 16 - bf->length;
70         return chan << bf->offset;
71 }
72
73 static int lcdfb_setcolreg(unsigned int regno, unsigned int red,
74                          unsigned int green, unsigned int blue,
75                          unsigned int transp, struct fb_info *info)
76 {
77         unsigned int val;
78
79         if (regno > 16)
80         {
81                 return -1;
82         }
83
84         //用三原色构造出val
85         val = chan_to_field(red, &info->var.red);
86         val |= chan_to_field(green, &info->var.green);
87         val |= chan_to_field(blue, &info->var.blue);
88
89         pseudo_palette[regno] = val;        //调好颜色,放回调色板
90
91         return 0;
92 }
93
94
95 static struct fb_ops lcd_fbops = {
96         .owner                = THIS_MODULE,
97         .fb_setcolreg        = lcdfb_setcolreg,//假的调色板的调色函数
98         .fb_fillrect        = cfb_fillrect,                //
99         .fb_copyarea        = cfb_copyarea,
100         .fb_imageblit        = cfb_imageblit,
101 };
102
103 /* 1、出入口函数 */
104 static int lcd_init(void)
105 {
106         /* 2、分配一个fb_info结构体 */
107         lcd_info = framebuffer_alloc(0, NULL);
108         /******** 2 end ********/
109
110         /* 3、设置 */
111         /* 设置固定的参数:lcd_info->fix */
112         strcpy(lcd_info->fix.id, "mylcd");                                        //名字
113         lcd_info->fix.smem_len                 = 240*320*16/8;                        //framebuffer长度(240*320 dots,lrgb565: 16bit/dots)
114         lcd_info->fix.type                         = FB_TYPE_PACKED_PIXELS;
115         lcd_info->fix.visual                = FB_VISUAL_TRUECOLOR;        //颜色深度(tft-lcd设置为真彩)
116         lcd_info->fix.line_length        = 240*16/8;                                //framebuffer中每一行(line)占据的字节数;240*2(2:16bit/8)                
117
118         /* 设置可变的参数 */
119         lcd_info->var.xres                         = 240;        //x方向的分辨率
120         lcd_info->var.yres                         = 320;        //y方向的分辨率
121         lcd_info->var.xres_virtual         = 240;        //x方向的虚拟分辨率
122         lcd_info->var.yres_virtual         = 320;        //y方向的虚拟分辨率
123         lcd_info->var.bits_per_pixel= 16;        //每个像素点16位(rgb565)
124         lcd_info->var.activate                = FB_ACTIVATE_NOW;
125
126         // 颜色数据的位分配 rgb:565
127         lcd_info->var.red.offset        = 11;        //(5)bit11 - bit15
128         lcd_info->var.red.length        = 5;        
129         lcd_info->var.green.offset        = 5;        //(6)bit5 - bit10
130         lcd_info->var.green.length        = 6;
131         lcd_info->var.blue.offset        = 0;        //(5)bit0 - bit4
132         lcd_info->var.blue.length        = 5;
133         
134         /* 设置操作函数 */
135         lcd_info->fbops = &lcd_fbops;
136
137         /* 其他设置 */
138         lcd_info->pseudo_palette = pseudo_palette;        //假的调色板
139         lcd_info->screen_size = 240*320*16/8;                //
140         /******** 3 end ********/
141
142         /* 4、硬件相关设置 */
143         /* 配置gpio用于lcd */
144         gpc_con = ioremap(0x56000020, 4);
145         gpd_con = ioremap(0x56000030, 4);
146         gpg_con = ioremap(0x56000060, 4);
147         gpb_con = ioremap(0x56000010, 8);
148         gpb_dat = gpb_con + 1;
149
150         //GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND
151         *gpc_con = 0xaaaaaaaa;
152
153         //GPIO管脚用于VD[23:8]
154         *gpd_con = 0xaaaaaaaa;
155
156         //GPB0设置为输出引脚
157         *gpb_con &= ~(3);
158         *gpb_con |= 1;
159         *gpb_dat &= ~1;                //输出低电平
160
161         //GPG4用作LCD_PWREN
162         *gpg_con |= (3<<8);
163         
164         /* 根据lcd手册设置lcd控制器 */
165         lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs));
166         lcd_regs->lcdcon1 = (4<<8) | (3<<5) | (0x0c<<1);
167         lcd_regs->lcdcon2 = (3<<24) | (319<<14) | (1<<6) | (0<<0);
168         lcd_regs->lcdcon3 = (16<<19) | (239<<8) | (10<<0);
169         lcd_regs->lcdcon4 = 4;
170         lcd_regs->lcdcon5 = (1<<11) | (0<<10) | (1<<9) | (1<<8) | (1<<0);
171         
172         /* 分配显存(framebuffer),并把地址告诉lcd控制器 */
173         // 虚拟地址 大小 物理地址
174         lcd_info->screen_base = dma_alloc_writecombine(NULL, lcd_info->fix.smem_len, &lcd_info->fix.smem_start, GFP_KERNEL);
175         
176         lcd_regs->lcdsaddr1 = (lcd_info->fix.smem_start >> 1) & ~(3<<30);
177         lcd_regs->lcdsaddr2 = ((lcd_info->fix.smem_start + lcd_info->fix.smem_len) >> 1) & 0x1fffff;
178         lcd_regs->lcdsaddr3 = (240*16/16); /* 一行的长度(单位: 2字节) */        
179         
180         /* 启动LCD */
181         lcd_regs->lcdcon1 |= (1<<0);         //使能LCD本身
182         lcd_regs->lcdcon5 |= (1<<3);        
183         *gpb_dat |= 1;                         //输出高电平, 使能背光
184         /******** 4 end ********/
185         
186         /* 5、注册 */
187         register_framebuffer(lcd_info);
188         /******** 5 end ********/
189
190         return 0;
191 }
192
193 static void lcd_exit(void)
194 {
195         dma_free_writecombine(NULL, lcd_info->fix.smem_len, lcd_info->screen_base, lcd_info->fix.smem_start);
196         unregister_framebuffer(lcd_info);
197         /* 关闭LCD */
198         lcd_regs->lcdcon1 &= ~(1<<0);
199         lcd_regs->lcdcon5 &= ~(1<<3);
200         *gpb_dat &= ~(1<<0);
201
202         iounmap(lcd_regs);
203         iounmap(gpc_con);
204         iounmap(gpd_con);
205         iounmap(gpg_con);
206         iounmap(gpb_con);
207
208         framebuffer_release(lcd_info);
209         return;
210 }
211
212 module_init(lcd_init);
213 module_exit(lcd_exit);
214 MODULE_LICENSE("GPL");
215 /******** 1 end ********/

   

附:

1 /**
2 * framebuffer_alloc - creates a new frame buffer info structure
3 *
4 * @size: size of driver private data, can be zero
5 * @dev: pointer to the device for this fb, this can be NULL
6 *
7 * Creates a new frame buffer info structure. Also reserves @size bytes
8 * for driver private data (info->par). info->par (if any) will be
9 * aligned to sizeof(long).
10 *
11 * Returns the new structure, or NULL if an error occured.
12 *
13 */
14 struct fb_info *framebuffer_alloc(size_t size, struct device *dev);

 

调试

pc-linux:

cd /work/system/linux-2.6.22.6/

make menuconfig

(lcd驱动以模块方式编译)

make uImage

make modules

cp /work/system/linux-2.6.22.6/drivers/video/cfbcopyarea.ko /work/nfs_root

cp /work/system/linux-2.6.22.6/drivers/video/cfbfillrect.ko /work/nfs_root

cp /work/system/linux-2.6.22.6/drivers/video/cfbimgblt.ko /work/nfs_root

cp /work/system/linux-2.6.22.6/arch/arm/boot/uImage /work/nfs_root/uImage_nolcd

   

board-u-boot:

nfs 30000000 192.168.0.103:/work/nfs_root/uImage_nolcd

bootm 30000000

   

board-linux:

mount -t nfs -o nolock,vers=2 192.168.0.103:/work/nfs_root /mnt

cd /mnt

insmod cfbcopyarea.ko

insmod cfbfillrect.ko

insmod cfbimgblt.ko

insmod lcd.ko

echo hello world! 2019/10/18 > /dev/tty1

   

cat test.bmp > /dev/fb0

   

vi /etc/inittab

#+++

tty1::askfirst:-/bin/sh

   

reboot

insmod buttons.ko

insmod cfbcopyarea.ko

insmod cfbfillrect.ko

insmod cfbimgblt.ko

insmod lcd.ko

   

<input way:key>

KEY_L KEY_S KEY_ENTER(ls' ')

  

原文地址:https://www.cnblogs.com/lilto/p/11877847.html