历史上的今天
今天是:2024年10月11日(星期五)
2018年10月11日 | OK6410之LCD驱动
2018-10-11 来源:eefocus
lcd.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/vmalloc.h"
#include "linux/delay.h"
#include "linux/interrupt.h"
#include "asm/uaccess.h"
#include "linux/fb.h"
#include "linux/init.h"
#include "linux/clk.h"
#include "linux/dma-mapping.h"
static struct fb_info *s3c_lcd_info;
static u32 s3c_pseudo_palette[16];
static volatile unsigned long *gpbcon;
static volatile unsigned long *gpbdat;
static volatile unsigned long *gpfcon;
static volatile unsigned long *gpfdat;
static volatile unsigned long *gpicon;
static volatile unsigned long *gpjcon;
static volatile unsigned long *mifpcon;
static volatile unsigned long *spcon;
struct s3c6410_lcd_regs {
unsigned long vidcon0;
unsigned long vidcon1;
unsigned long vidcon2;
unsigned long reserver1;
unsigned long vidtcon0;
unsigned long vidtcon1;
unsigned long vidtcon2;
unsigned long reserver2;
unsigned long wincon0;
unsigned long wincon1;
unsigned long wincon2;
unsigned long wincon3;
unsigned long wincon4;
unsigned long reserver3[3];
unsigned long vidosd0a;
unsigned long vidosd0b;
unsigned long vidosd0c;
unsigned long reserver4;
unsigned long vidosd1a;
unsigned long vidosd1b;
unsigned long vidosd1c;
unsigned long vidosd1d;
unsigned long vidosd2a;
unsigned long vidosd2b;
unsigned long vidosd2c;
unsigned long vidosd2d;
unsigned long vidosd3a;
unsigned long vidosd3b;
unsigned long vidosd3c;
unsigned long reserver5;
unsigned long vidosd4a;
unsigned long vidosd4b;
unsigned long vidosd4c;
unsigned long reserver6[5];
unsigned long vidw00add0b0;
unsigned long vidw00add0b1;
unsigned long vidw01add0b0;
unsigned long vidw01add0b1;
unsigned long vidw02add0;
unsigned long reserver7;
unsigned long vidw03add0;
unsigned long reserver8;
unsigned long vidw04add0;
unsigned long reserver9[3];
unsigned long vidw00add1b0;
unsigned long vidw00add1b1;
};
static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
{
chan &= 0xffff;
chan >>= 16 - bf->length;
return chan << bf->offset;
}
static int s3c_fb_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 > 16)
return 1;
u32 *pal = info->pseudo_palette;
// 用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);
pal[regno] = val;
return 0;
}
static struct fb_ops s3c_fb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = s3c_fb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static struct s3c6410_lcd_regs * lcd_regs;
static int s3c_lcd_init(void)
{
struct clk *clk;
int hclk;
int clkval;
// 1. 分配fb_info
s3c_lcd_info = framebuffer_alloc(0, NULL);
// 2. 设置
// 2.1 设置固定的信息
strcpy(s3c_lcd_info->fix.id, "uplooking_lcd");
s3c_lcd_info->fix.smem_len = 480*272*2;
s3c_lcd_info->fix.type = FB_TYPE_PACKED_PIXELS;
s3c_lcd_info->fix.visual = FB_VISUAL_TRUECOLOR;
s3c_lcd_info->fix.line_length = 480*2;
// 2.2 设置可变的信息
s3c_lcd_info->var.xres = 480; //分辨率
s3c_lcd_info->var.yres = 272;
s3c_lcd_info->var.xres_virtual = 480; //虚拟分辨率
s3c_lcd_info->var.yres_virtual = 272;
s3c_lcd_info->var.bits_per_pixel = 16;
s3c_lcd_info->var.red.length = 5;
s3c_lcd_info->var.red.offset = 11;
s3c_lcd_info->var.green.length = 6;
s3c_lcd_info->var.green.offset = 5;
s3c_lcd_info->var.blue.length = 5;
s3c_lcd_info->var.blue.offset = 0;
s3c_lcd_info->var.activate = FB_ACTIVATE_NOW;
// 2.3 设置操作函数
s3c_lcd_info->fbops = &s3c_fb_ops;
// 2.4 设置其他信息
//s3c_lcd_info->screen_base = ; // 显存的虚拟地址
s3c_lcd_info->screen_size = 480*272*2;
s3c_lcd_info->pseudo_palette = &s3c_pseudo_palette;
// 4. 硬件相关的操作
// 4.1 配置GPIO用于LCD
gpicon = ioremap(0x7F008100, 4);
*gpicon = 0xAAAAAAAA;
gpjcon = ioremap(0x7F008120, 4);
*gpjcon = 0xAAAAAAAA;
gpbcon = ioremap(0x7F008020, 4);
gpbdat = gpbcon + 1;
gpfcon = ioremap(0x7F0080A0, 4);
gpfdat = gpfcon + 1;
// 4.2 根据LCD的性能设置LCD控制器
// MIFPCON
mifpcon = ioremap(0x7410800C, 4);
*mifpcon &= ~(1<<3);
spcon = ioremap(0x7F0081A0, 4);
*spcon &= ~(3);
*spcon |= 1;
lcd_regs = ioremap(0x77100000, sizeof(struct s3c6410_lcd_regs));
clk = clk_get(NULL, "lcd");
clk_enable(clk); // HCLK_GATE[3]设为1
// HCLK_GATE = ioremap(0x7E00F030, 4);
// *HCLK_GATE |= (1<<3);
// bit[13:6], CLKVAL_F,VCLK = Video Clock Source / (CLKVAL+1)
// VCLK = 9000000
// CLKVAL_F = hclk/9000000 - 1
// bit[3:2], CLKSEL_F, 00 = HCLK
// bit[1], ENVID-使能LCD控制器的输出, 先设为0, 最后全部设置好了再设为1
clk = clk_get(NULL, "hclk");
hclk = clk_get_rate(clk);
clkval = hclk/9000000 - 1;
printk(KERN_INFO "hclk = %d, clkval = %d\n", hclk, clkval);
lcd_regs->vidcon0 = (0<<29)|(0<<26) | (0<<17) | (clkval << 6) | (1<<4);
// bit[7], 0-在VLCK下降沿读数据
// bit[6], HSYNC低脉冲有效
// bit[5], VSYNC低脉冲有效
// bit[4], VDEN高电平有效
lcd_regs->vidcon1 = (0<<7) | (1<<6) | (1<<5) | (0<<4);
// LCD手册P11
// tvp = 10, tvb = 2, tvf=2
lcd_regs->vidtcon0 = (2<<16) | (2<<8) | (10<<0); //修改了 都加1
// LCD手册P11
// thp = 41, thb = 2, thf=2
lcd_regs->vidtcon1 = (1<<16) | (1<<8) | (40<<0);
lcd_regs->vidtcon2 = (271<<11) | (479<<0);
// 4.3 分配显存, 并告诉LCD控制器
s3c_lcd_info->screen_base = dma_alloc_writecombine(NULL, s3c_lcd_info->screen_size,
&s3c_lcd_info->fix.smem_start, GFP_KERNEL);
// bit[17],BSWP = 0, bit[16],HWSWP = 0
// bit[5:2],BPPMODE_F, 0b1011, 24bpp
// bit[0], ENWIN_F, 0-先不使能
lcd_regs->wincon0 &= ~(0xf << 2);
//lcd_regs->wincon0 |= (0xb<<2); // unpacked 24 BPP (non-palletized R:8-G:8-B:8 )
lcd_regs->wincon0 |= (0x5<<2);
#define LeftTopX 0
#define LeftTopY 0
#define RightBotX 479
#define RightBotY 271
lcd_regs->vidosd0a = (LeftTopX<<11) | (LeftTopY << 0);
lcd_regs->vidosd0b = (RightBotX<<11) | (RightBotY << 0);
//lcd_regs->vidosd0c = 480*272/2;
lcd_regs->vidosd0c = 480*272;
lcd_regs->vidw00add0b0 = s3c_lcd_info->fix.smem_start;
lcd_regs->vidw00add1b0 = (s3c_lcd_info->fix.smem_start + s3c_lcd_info->fix.smem_len) & 0xffffff;
// 4.4 使能
lcd_regs->vidcon0 |= (3); // 使能LCD控制器输出信号
lcd_regs->wincon0 |= (1<<0); // 使能窗口0
// 3. 注册
register_framebuffer(s3c_lcd_info);
return 0;
}
static void s3c_lcd_exit(void)
{
struct clk *clk;
unregister_framebuffer(s3c_lcd_info);
lcd_regs->vidcon0 &= ~(1<<1); // 禁止LCD控制器输出信号
lcd_regs->wincon0 &= ~(1<<0); // 禁止窗口0
dma_free_writecombine(NULL, s3c_lcd_info->screen_size, s3c_lcd_info->screen_base,
s3c_lcd_info->fix.smem_start);
clk = clk_get(NULL, "lcd");
clk_disable(clk); // HCLK_GATE[3]设为0
iounmap(lcd_regs);
iounmap(gpbcon);
iounmap(gpfcon);
iounmap(gpicon);
iounmap(gpjcon);
iounmap(mifpcon);
iounmap(spcon);
framebuffer_release(s3c_lcd_info);
}
module_init(s3c_lcd_init);
module_exit(s3c_lcd_exit);
MODULE_LICENSE("GPL");
====================================================================
Makefile文件:
KERN_DIR = /home/linux/linux-3.0.1
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += lcd.o
==================================================================
LCD实验:
想在6410的驱动上面的测试自己的驱动首先要卸载开发板的官方驱动:
1、make menuconfig去掉内核自带的LCD驱动
在Device Drivers=>Graphics support=>S3C Framebuffer Support
和
Device Drivers=>Multimedia support=>Video For Linux
这两项要去掉!
默认:
->Device Drivers
[*] Multimedia support --->
[*] Video For Linux
->Graphics support
[*] S3C Framebuffer Support (eXtended)
Select LCD Type (4.3 inch 480x272 TFT LCD) --->
(X) 4.3 inch 480x272 TFT LCD
[*] Advanced options for S3C Framebuffer
Select BPP(Bits Per Pixel) (16 BPP) --->
(X) 16 BPP
(4) Number of Framebuffers
[*] Enable Virtual Screen
[*] Enable Double Buffering
改为:
->Device Drivers
[*] Multimedia support --->
[ ] Video For Linux
->Graphics support
[ ] S3C Framebuffer Support (eXtended)
[*] Support for frame buffer devices ---> //为了编译出要用的模块
[M] Samsung S3C Framebuffer Support
2、上面是去除自带的驱动支持,还要在arch\arm\mach-s3c64xx\mach-smdk6410.c和
change\mach-smdk6410.c这两个文件中相应的结构体注释掉:
s3c_device_vpp
s3c_device_mfc
s3c_device_tvenc
s3c_device_tvscaler
s3c_device_rotator
s3c_device_jpeg
s3c_device_g2d
s3c_device_g3d
这样子 就可以通过编译了:
make zImage //生成内核镜像文件
make modules
cp arch/arm/boot/zImage ../../zImage_no_lcd
然后把/drivers/video中的cfbcopyarea.ko 、cfbfillrect.ko 、cfbimgblt.ko 加载到开发板:
cp drivers/video/cfbcopyarea.ko drivers/video/cfbfillrect.ko drivers/video/cfbimgblt.ko ../../../fs_ok6410_yaffs2/driver/
3、把开发板设置为SD卡启动,使用SD卡启动后按空格进入SD卡的u-boot;
4、用SD卡里面的u-boot烧写内核到0x000000200000-0x000000700000 : "Kernel"分区:
tftp 50008000 zImage_no_lcd
nand erase 200000 500000
nand write 50008000 200000 500000
5、烧写完成后设置开发版为nand flash启动,使用新内核启动。
6、测试1:
重启开发板,然后执行以下命令
insmod cfbcopyarea.ko
insmod cfbfillrect.ko
insmod cfbimgblt.ko
insmod lcd.ko
echo hello > /dev/tty1
可以看到屏幕打印了文字hello
cat lcd.ko > /dev/fb0
可以看到花屏了
测试2:
在开发板的文件系统的/etc/inittab文件中添加一行tty1::askfirst:-/bin/sh
重启开发板,然后执行以下命令
insmod cfbcopyarea.ko
insmod cfbfillrect.ko
insmod cfbimgblt.ko
insmod lcd.ko
可以看到有文字在屏幕上显示,再装载我们之前做的输入子系统的按键驱动
insmod button_input.ko
就可以在开发板屏幕上看到shell命令行了
上一篇:OK6410触摸屏驱动
史海拾趣
|
本帖最后由 jameswangsynnex 于 2015-3-3 19:57 编辑 5月11日消息,据中国移动相关人士透露,5月中下旬中移动将正式公开发布采用OMS手机操作系统(Open mobile system)的Ophone手机。这将意味着中国自主研发的OMS手机操作系统将正式走上前台,向 ...… 查看全部问答> |
|
WINCE6.0操作系统在三星6410开发板上完美展现!--基于立宇泰ARMSYS6410开发板 精彩测评实例图片说明:1,WINCE6.0系统启动画面(进度条动态显示内核加载进程,LOGO图片可以根据客户需要免费更换);2,WINCE6.0桌面效果;3,800x480液晶屏全屏播放H.264视频流文件(采用硬件解码)4,800x480液晶屏全屏播放MPEG4(avi后缀)音视 ...… 查看全部问答> |
|
我在做同步相量测量(PMU) 就是把AD采集的三项交流电压和电流值打上时标然后上传,在接收PC发送的控制命令,如控制继电器开关的命令。由于要对数据打时标(时间戳),底层的PMU采集装置散布在不同的点,每一个点(PMU)安装一个GPS 不现实 ...… 查看全部问答> |
|
本人在一个项目中运用Ecan进行通信,在通信过程中会碰到中断故障(具体原因说不上来)。我是将Ecan设置成中断接收的(邮箱0-15设置成接收邮箱,16邮箱设置成发送邮箱),若接收到一个合理的读写命令,则返回 ...… 查看全部问答> |
|
#include \"msp430g2553.h\" int main( void ) { // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; P1DIR |= BIT0; P1OUT &= ~BIT0; & ...… 查看全部问答> |




