测试:
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控制台
1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/errno.h> 4 #include <linux/string.h> 5 #include <linux/mm.h> 6 #include <linux/slab.h> 7 #include <linux/delay.h> 8 #include <linux/fb.h> 9 #include <linux/init.h> 10 #include <linux/dma-mapping.h> 11 #include <linux/interrupt.h> 12 #include <linux/workqueue.h> 13 #include <linux/wait.h> 14 #include <linux/platform_device.h> 15 #include <linux/clk.h> 16 17 #include <asm/io.h> 18 #include <asm/uaccess.h> 19 #include <asm/div64.h> 20 21 #include <asm/mach/map.h> 22 #include <asm/arch/regs-lcd.h> 23 #include <asm/arch/regs-gpio.h> 24 #include <asm/arch/fb.h> 25 26 struct lcd_regs{ 27 unsigned long lcdcon1; 28 unsigned long lcdcon2; 29 unsigned long lcdcon3; 30 unsigned long lcdcon4; 31 unsigned long lcdcon5; 32 unsigned long lcdsaddr1; 33 unsigned long lcdsaddr2; 34 unsigned long lcdsaddr3; 35 unsigned long redlut; 36 unsigned long greenlut; 37 unsigned long bluelut; 38 unsigned long reserved[9]; 39 unsigned long dithmode; 40 unsigned long tpal; 41 unsigned long lcdintpnd; 42 unsigned long lcdsrcpnd; 43 unsigned long lcdintmsk; 44 unsigned long lpcsel; 45 46 }; 47 48 static struct fb_info *s3c_lcd; 49 /* gpbon,gpbdat,c,d,g, */ 50 volatile unsigned long *gpbcon; 51 volatile unsigned long *gpbdat; 52 volatile unsigned long *gpccon; 53 volatile unsigned long *gpdcon; 54 volatile unsigned long *gpgcon; 55 static volatile struct lcd_regs* lcd_regs; 56 static u32 pseudo_palette[16]; 57 58 static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) 59 { 60 chan &= 0xffff; 61 chan >>= 16 - bf->length; 62 return chan << bf->offset; 63 } 64 65 static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red, 66 unsigned int green, unsigned int blue, 67 unsigned int transp, struct fb_info *info) 68 { 69 unsigned int val; 70 71 if (regno > 16) 72 return 1; 73 74 /* 用red,green,blue三原色构造出val */ 75 val = chan_to_field(red, &info->var.red); 76 val |= chan_to_field(green, &info->var.green); 77 val |= chan_to_field(blue, &info->var.blue); 78 79 //((u32 *)(info->pseudo_palette))[regno] = val; 80 pseudo_palette[regno] = val; 81 return 0; 82 } 83 84 static struct fb_ops s3c_lcdfb_ops = { 85 .owner = THIS_MODULE, 86 .fb_setcolreg = s3c_lcdfb_setcolreg, 87 .fb_fillrect = cfb_fillrect, 88 .fb_copyarea = cfb_copyarea, 89 .fb_imageblit = cfb_imageblit, 90 }; 91 92 93 static int lcd_init(void) 94 { 95 96 /* 1. 分配一个fb_info */ 97 s3c_lcd = framebuffer_alloc(0, NULL); 98 99 /* 2. 设置 */ 100 /* 2.1 设置固定的参数 */ 101 strcpy(s3c_lcd->fix.id, "mylcd"); 102 s3c_lcd->fix.smem_len = 480 * 272 * 16 / 8; 103 s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS; 104 s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR; /*TFT*/ 105 s3c_lcd->fix.line_length = 480 * 2; 106 107 /* 2.2 设置可变的参数 */ 108 s3c_lcd->var.xres = 480; 109 s3c_lcd->var.yres = 272; 110 s3c_lcd->var.xres_virtual = 480; 111 s3c_lcd->var.yres_virtual = 272; 112 s3c_lcd->var.bits_per_pixel = 16; 113 114 /* RGB:565 */ 115 s3c_lcd->var.red.offset = 11; 116 s3c_lcd->var.red.length = 5; 117 118 s3c_lcd->var.green.offset = 5; 119 s3c_lcd->var.green.length = 6; 120 121 s3c_lcd->var.blue.offset = 0; 122 s3c_lcd->var.blue.length = 5; 123 124 s3c_lcd->var.activate = FB_ACTIVATE_NOW; 125 126 /* 2.3 设置操作函数 */ 127 s3c_lcd->fbops = &s3c_lcdfb_ops; 128 129 /* 2.4 其他设置 */ 130 s3c_lcd->pseudo_palette = pseudo_palette; //假的调色板 131 132 s3c_lcd->screen_size = 480 * 272 * 16 / 8; 133 134 /* 3. 硬件相关的设置 */ 135 /* 3.1 配置GPIO用于LCD */ 136 //0x56000010 ,8 137 gpbcon = ioremap(0x56000010, 8); 138 gpbdat = gpbcon + 1; 139 gpccon = ioremap(0x56000020, 4); 140 gpdcon = ioremap(0x56000030, 4); 141 gpgcon = ioremap(0x56000060, 4); 142 //映射是一页一页映射,不用担心不足 143 *gpccon = 0xaaaaaaaa; // GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND 144 *gpdcon = 0xaaaaaaaa; // GPIO管脚用于VD[23:8] 145 *gpbcon &= ~(3); // Power enable pin 146 *gpbcon |= (0x01); 147 *gpbdat &= ~(1<<0); // Power off 148 *gpgcon |= (3<<8); // GPG4用作LCD_PWREN 149 150 /* 3.2 根据LCD手册设置LCD控制器,比如VCLK的频率等 */ 151 lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs)); 152 153 /* 154 * 设置LCD控制器的控制寄存器LCDCON1~5 155 * 1. LCDCON1: 156 * 设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2] 157 * 选择LCD类型: TFT LCD 158 * 设置显示模式: 16BPP 159 * 先禁止LCD信号输出 160 * 2. LCDCON2/3/4: 161 * 设置控制信号的时间参数 162 * 设置分辨率,即行数及列数 163 * 现在,可以根据公式计算出显示器的频率: 164 * 当HCLK=100MHz时, 165 * Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LIINEVAL+1)+(VFPD+1)}x 166 * {(HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1)}x 167 * {2x(CLKVAL+1)/(HCLK)}] 168 * = 60Hz 169 * 3. LCDCON5: 170 * 设置显示模式为16BPP时的数据格式: 5:6:5 171 * 设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转 172 * 半字(2字节)交换使能 173 */ 174 175 lcd_regs->lcdcon1 = (4<<8) | (0x3<<5) | \ 176 (0xC<<1) | (0<<0); 177 lcd_regs->lcdcon2 = (1<<24) | (271<<14) | \ 178 (1<<6) | (10-1); 179 lcd_regs->lcdcon3 = (1<<19) | (479<<8) | (1); 180 lcd_regs->lcdcon4 = 40; 181 lcd_regs->lcdcon5 = (1<<11) | (1<<9) | (1<<8) | \ 182 (1<<1); 183 /* 3.3 分配显存(framebuffer),并把地址告诉LCD控制器 */ 184 s3c_lcd->screen_base = dma_alloc_writecombine(NULL, \ 185 s3c_lcd->fix.smem_len, &s3c_lcd->fix.smem_start, GFP_KERNEL); 186 lcd_regs->lcdsaddr1 = (s3c_lcd->fix.smem_start>>1) & ~(3 << 30); 187 lcd_regs->lcdsaddr2 = ((s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len) >> 1) \ 188 & ( 0X1fffff ); 189 lcd_regs->lcdsaddr3 = (0<<11) | (480 *16/16); 190 191 /* 启动LCD */ 192 lcd_regs->lcdcon1 |= (1 << 0); //使能LCD本身 193 lcd_regs->lcdcon5 |= (1<<3); // 设置是否输出LCD_PWREN 194 *gpbdat |= (1<<0); // Power on 195 196 /* 4. 注册 */ 197 198 register_framebuffer(s3c_lcd); 199 200 return 0; 201 } 202 203 static int lcd_exit(void) 204 { 205 unregister_framebuffer(s3c_lcd); 206 lcd_regs->lcdcon1 &= ~(1 << 0); //关闭LCD本身 207 *gpbdat &= ~(1<<0); // Power off 208 dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, \ 209 s3c_lcd->screen_base, s3c_lcd->fix.smem_start); 210 211 iounmap(gpbcon); 212 iounmap(gpccon); 213 iounmap(gpdcon); 214 iounmap(gpgcon); 215 216 framebuffer_release(&s3c_lcd); 217 return 0; 218 } 219 220 module_init(lcd_init); 221 module_exit(lcd_exit); 222 223 MODULE_LICENSE("GPL");