linux2628下6410LCD驱动分析文档格式.docx
《linux2628下6410LCD驱动分析文档格式.docx》由会员分享,可在线阅读,更多相关《linux2628下6410LCD驱动分析文档格式.docx(27页珍藏版)》请在冰豆网上搜索。
//根据这个进行匹配
.id
=-1,
.num_resources
=ARRAY_SIZE(s3c_lcd_resource),
.resource
=s3c_lcd_resource,
.dev
={
.dma_mask
=&
s3c_device_lcd_dmamask,
.coherent_dma_mask
=0xffffffffUL
在arch/arm/mach-s3c6410/mach-smdk6410.c文件的
staticvoid__initsmdk6410_machine_init(void)函数中有这么一句话
platform_add_devices(smdk6410_devices,ARRAY_SIZE(smdk6410_devices));
这个就是对device设备进行注册,在注册driver驱动时,会根据name找到相应的device进行匹配,然后会调用probe。
下面分析driver,在drivers/video/samsung/s3cfb.c文件的最下面有这样的一段代码
staticstructplatform_drivers3cfb_driver={
.probe
=s3cfb_probe,
//匹配的话会调用这个函数
.remove
=s3cfb_remove,
.suspend
=s3cfb_suspend,
.resume
=s3cfb_resume,
.driver
={
="
//上面说的,内核会根据这个来找到相应的device
.owner
=THIS_MODULE,
int__devinits3cfb_init(void)
{
returnplatform_driver_register(&
s3cfb_driver);
//进行drive注册
匹配后会掉用s3cfb_probe();
这个函数里面对fbinfo进行初始化,对相关寄存器进行初始化,在6410lcd驱动中,主要要修改的几个文件是:
drivers/video/samsung目录下的s3cfb.c,假设你在配置的时候即用makemenuconfig命令,在里面选择的是480WV,他对应的文件时s3cfb_lte480wv.c,s3cfb_lte480wv.c是和屏参数相关的文件。
还有个要改的文件是s3cfb_fimd4x.c,这个文件主要是涉及寄存器的一些参数的配置。
主要几个重点:
对构架的分析,理清楚各个文件的关系。
s3cfb.c中的s3cfb_probe主要是在根据s3cfb_fimd4x.c和s3cfb_lte480wv.c文件来初始fbinfo,并且写相关LCD寄存器。
s3cfb_lte480wv.c主要是记录屏的参数,在这里进行修改来满足不同的lcd屏。
s3cfb_fimd4x.c是对寄存器的值进行初始化,比如各个窗口的显示模式、颜色表寄存器的模式、各个窗口的控制寄存器,此文件还包含6410对于lcd的特殊功能,用ioctl来进行实现的。
fbmem.c这个是fb字符设备驱动,每个窗口都是一个字符设备,在s3cfb_probe中通过调用register_buffer进行注册,注意,里面有一个fb_notifier_call_chain,他最终会调用drivers/video/console/fbcon.c中的fbcon_init,里面会有对logo的调用;
fbmem.c文件里还有通用的ioctl功能调用,适合所有带lcd控制器的处理器,这个文件时通用的,每个处理器的fbmem都是一样的,做成了和硬件无关。
lcd驱动简单构架图
abc
s3c2410_lcd&
framebuffer驱动分析
int__inits3c2410fb_probe(structdevice*dev)
structs3c2410fb_info*info;
structfb_info
*fbinfo;
structplatform_device*pdev=to_platform_device(dev);
structs3c2410fb_hw*mregs;
intret;
intirq;
inti;
mach_info=dev->
platform_data;
//获取lcd相关寄存器配置信息
if(mach_info==NULL){
dev_err(dev,"
noplatformdataforlcd,cannotattach\n"
);
return-EINVAL;
}
mregs=&
mach_info->
regs;
irq=platform_get_irq(pdev,0);
if(irq<
0){
dev_err(dev,"
noirqfordevice\n"
return-ENOENT;
fbinfo=framebuffer_alloc(sizeof(structs3c2410fb_info),dev);
//分配structfb_info和structs3c2410fb_info结构
if(!
fbinfo){
return-ENOMEM;
info=fbinfo->
par;
//调用framebuffer_alloc分配内存的时候,其实顺带分配了structs3c2410fb_info结构,紧跟structfb_info结构的后面,fbinfo->
par指针处。
info->
fb=fbinfo;
dev_set_drvdata(dev,fbinfo);
s3c2410fb_init_registers(info);
//lcd相关寄存器配置
dprintk("
devinit\n"
strcpy(fbinfo->
fix.id,driver_name);
/*配置信息存储起来,以后用到*/
memcpy(&
info->
regs,&
regs,sizeof(info->
regs));
mach_info
=dev->
/*以下配置,详细请参考网上资料*/
fbinfo->
fix.type
=FB_TYPE_PACKED_PIXELS;
fix.type_aux
=0;
fix.xpanstep
fix.ypanstep
fix.ywrapstep
fix.accel
=FB_ACCEL_NONE;
var.nonstd
var.activate
=FB_ACTIVATE_NOW;
/*设置分辨率*/
var.height
=mach_info->
height;
var.width
width;
var.accel_flags
var.vmode
=FB_VMODE_NONINTERLACED;
fbops
=&
s3c2410fb_ops;
//重要的fop结构(fb设备本质上是字符设备)
flags
=FBINFO_FLAG_DEFAULT;
pseudo_palette
pseudo_pal;
var.xres
xres.defval;
var.xres_virtual
var.yres
yres.defval;
var.yres_virtual
var.bits_per_pixel
bpp.defval;
var.upper_margin
=S3C2410_LCDCON2_GET_VBPD(mregs->
lcdcon2)+1;
var.lower_margin
=S3C2410_LCDCON2_GET_VFPD(mregs->
var.vsync_len
=S3C2410_LCDCON2_GET_VSPW(mregs->
lcdcon2)+1;
var.left_margin
=S3C2410_LCDCON3_GET_HFPD(mregs->
lcdcon3)+1;
var.right_margin
=S3C2410_LCDCON3_GET_HBPD(mregs->
var.hsync_len
=S3C2410_LCDCON4_GET_HSPW(mregs->
lcdcon4)+1;
/*配色板设置(采用5、6、5模式)*/
var.red.offset
=11;
var.green.offset
=5;
var.blue.offset
var.transp.offset
var.red.length
var.green.length
=6;
var.blue.length
var.transp.length
/*计算需要申请的framerbuffer大小(以字节为单位)*/
fix.smem_len
=
mach_info->
xres.max*
yres.max*
bpp.max/8;
for(i=0;
i<
256;
i++)
palette_buffer[i]=PALETTE_BUFF_CLEAR;
request_mem_region((unsignedlong)S3C24XX_VA_LCD,SZ_1M,"
s3c2410-lcd"
)){
ret=-EBUSY;
gotodealloc_fb;
gotLCDregion\n"
ret=request_irq(irq,s3c2410fb_irq,SA_INTERRUPT,pdev->
name,info);
if(ret){
cannotgetirq%d-err%d\n"
irq,ret);
gotorelease_mem;
clk=clk_get(NULL,"
lcd"
clk||IS_ERR(info->
clk)){
printk(KERN_ERR"
failedtogetlcdclocksource\n"
ret=-ENOENT;
gotorelease_irq;
clk_use(info->
clk);
clk_enable(info->
gotandenabledclock\n"
msleep
(1);
/*Initializevideomemory*/
ret=s3c2410fb_map_video_memory(info);
printk(KERN_ERR"
FailedtoallocatevideoRAM:
%d\n"
ret);
ret=-ENOMEM;
gotorelease_clock;
gotvideomemory\n"
ret=s3c2410fb_init_registers(info);
//怎么再次初始化lcd相关寄存器了?
ret=s3c2410fb_check_var(&
fbinfo->
var,fbinfo);
//注册framebuffer前的一个例行检查
ret=register_framebuffer(fbinfo);
if(ret<
Failedtoregisterframebufferdevice:
gotofree_video_memory;
/*createdevicefiles*/
device_create_file(dev,&
dev_attr_debug);
printk(KERN_INFO"
fb%d:
%sframebufferdevice\n"
node,fbinfo->
fix.id);
return0;
free_video_memory:
s3c2410fb_unmap_video_memory(info);
release_clock:
clk_disable(info->
clk_unuse(info->
clk_put(info->
release_irq:
free_irq(irq,info);
release_mem:
release_mem_region((unsignedlong)S3C24XX_VA_LCD,S3C24XX_SZ_LCD);
dealloc_fb:
framebuffer_release(fbinfo);
returnret;
/*
*s3c2410fb_map_video_memory():
*
AllocatestheDRAMmemoryfortheframebuffer.
Thisbufferis
remappedintoanon-cached,non-buffered,memoryregionto
allowpaletteandpixelwritestooccurwithoutflushingthe
cache.
Oncethisareaisremapped,allvirtualmemory
accesstothevideomemoryshouldoccuratthenewregion.
*/
staticint__inits3c2410fb_map_video_memory(structs3c2410fb_info*fbi)
map_video_memory(fbi=%p)\n"
fbi);
fbi->
map_size=PAGE_ALIGN(fbi->
fb->
fix.smem_len+PAGE_SIZE);
//页对齐
map_cpu
=dma_alloc_writecombine(fbi->
dev,fbi->
map_size,
&
fbi->
map_dma,GFP_KERNEL);
//目前我只知道用于分配可供dma使用的内存,其中返回地址fbi->
map_cpu为虚拟地址,fbi->
map_dma为物理地址。
map_size=fbi->
fix.smem_len;
//恢复真实的大小
if(fbi->
map_cpu){
/*preventinitialgarbageonscreen*/
map_video_memory:
clear%p:
%08x\n"
map_cpu,fbi->
map_size);
memset(fbi->
map_cpu,0xf0,fbi->
screen_dma
=fbi->
map_dma;
//物理地址
screen_base
map_cpu;
//虚拟地址
fix.smem_start
screen_dma;
dma=%08xcpu=%psize=%08x\n"
map_dma,fbi->
fix.smem_len);
returnfbi->
map_cpu?
0:
-ENOMEM;
staticstructs3c2410fb_mach_infosbc2410_lcdcfg__initdata={
.fixed_syncs=0,
.regs={
.lcdcon1=S3C2410_LCDCON1_TFT16BPP|\
S3C2410_LCDCON1_TFT|\
S3C2410_LCDCON1_CLKVAL(6),
.lcdcon2=S3C2410_LCDCON2_VBPD
(2)|\
S3C2410_LCDCON2_LINEVAL(319)|\
S3C2410_LCDCON2_VFPD(0)|\
S3C2410_LCDCON2_