MTK平台LCM驱动详细分析一 mtk lcm


MTK平台LCM驱动详细分析(一) mtk lcm
来自:http://blog.csdn.net/sunweizhong1024/article/details/8447915

MTK_LCD_Driver

代码的路是在/mediatek/source/kernel/driver/vedio/mtkfb.c

module_init(mtkfb_init);模块初始化函数

int__initmtkfb_init(void)

{

int r =0;

MSG_FUNC_ENTER();

if(platform_driver_register(&mtkfb_driver)){//以platform方式进行注册mtkfbdriver

PRNERR("failed toregister mtkfbdrivern");

r =-ENODEV;

gotoexit;

}

#ifdefCONFIG_HAS_EARLYSUSPEND

register_early_suspend(&mtkfb_early_suspend_handler);//LCD是以erly_suspend的方式注册的,这个涉及到power_management的内容

#endif

DBG_Init();

exit:

MSG_FUNC_LEAVE();

returnr;

知道设备模型的人应该知道platformbus总线的match函数的规则是device和driver的名字必须相同,当name匹配一样的时候,我们就会调用driver里面的probe函数,这个函数是LCDdriver的核心入口函数。

进入LCDprobe世界。

staticintmtkfb_probe(struct device *dev)

{

structplatform_device *pdev;

structmtkfb_device *fbdev= NULL;

structfb_info *fbi;

intinit_state;

int r =0;

char*p =NULL;

MSG_FUNC_ENTER();

printk("%s,%sn", __func__,saved_command_line);

p=strstr(saved_command_line, "fps=");

if(p==NULL){

lcd_fps=6000;

printk("[FBdriver]can not get fps fromubootn");

}

else{

p+=4;

lcd_fps=simple_strtol(p, NULL, 10);

}

…........................

…........................

r =register_framebuffer(fbi);

if (r !=0) {

PRNERR("register_framebufferfailedn");

gotocleanup;

}

fbdev->state=MTKFB_ACTIVE;

MSG(INFO,"MTKframebuffer initialized vram=%lun",fbdev->fb_size_in_byte);

MSG_FUNC_LEAVE();

return0;

cleanup:

mtkfb_free_resources(fbdev,init_state);

MSG_FUNC_LEAVE();

returnr;

}

这个函数比较长,下面我们一一对这个Probe函数进行讲解。

1、开始driver接受从uboot中传递过来的参数,saved_command_line变量,进行参数的取值。

2、DISP_IsContextInited这个函数判断lcm_params、disp_drv、lcm_drv是不是都进行初始化了,如果都初始化了,那么就返回TRUE如果有一个没有进行初始化的话,那么就返回FALSE。其实这里在uboot中已经进行了初始化了,我们这里假设这里还没有初始化,如果是FALSE的话,那么就会调用mtkfb_find_lcm_driver这个function函数。

mtkfb_find_lcm_driver

BOOLmtkfb_find_lcm_driver(void)

{

BOOLret =FALSE;

char*p,*q;

p=strstr(saved_command_line,"lcm=");//这里我们会找出”lcm=”这个字符串在saved_command_line中第一次出现的位置,取出这个指针。

if(p==NULL)

{

//we can'tfind lcm string in the command line, the uboot should beoldversion

returnDISP_SelectDevice(NULL);

}

p+=4;

if((p-saved_command_line) >strlen(saved_command_line+1))

{

ret=FALSE;

gotodone;

}

printk("%s,%sn", __func__,p);

q=p;

while(*q!=' ' && *q != '')

q++;

memset((void*)mtkfb_lcm_name,0,sizeof(mtkfb_lcm_name));

strncpy((char*)mtkfb_lcm_name,(constchar*)p, (int)(q-p));//这里会找出lcm的名字,接下来会将这个Name股指给mtkfb_lcm_name这个变量,下面会将这个变量传递给mtkfb_lcm_name这个函数。

printk("%s,%sn", __func__,mtkfb_lcm_name);

if(DISP_SelectDevice(mtkfb_lcm_name))

ret=TRUE;

done:

returnret;

}

continuetracecode:DISP_SelectDevice(mtkfb_lcm_name)

DISP_SelectDevice(mtkfb_lcm_name):

BOOLDISP_SelectDevice(const char*lcm_name)

{

LCD_STATUSret;

ret=LCD_Init();

printk("retof LCD_Init() = %dn",ret);

lcm_drv=disp_drv_get_lcm_driver(lcm_name);

if(NULL ==lcm_drv)

{

printk("%s,disp_drv_get_lcm_driver() returnsNULLn", __func__);

returnFALSE;

}

disp_dump_lcm_parameters(lcm_params);

returndisp_drv_init_context();

}

上面的函数还是比较复杂的,我们下面会进行一一的讲解:

2.1:LCD_Init

LCD_STATUSLCD_Init(void)

{

LCD_STATUSret =LCD_STATUS_OK;

memset(&_lcdContext,0,sizeof(_lcdContext));//我们可以发现-lcdContext这个变量是一个数组,而且是static类型的,C语言中我们定义了这种类型的变量的话,那么就会为这个变量分配一个地址

// LCDcontroller would NOTreset register as defaultvalues

// Do itby SW here

//

ResetBackupedLCDRegisterValues();这里我们会为上面的_lcdContext.regBackup里面的值进行赋值,我们所用的是LCD_OUTREG32,函数进行赋值的,开始我一直以为这个变量根本就没有赋值啊,我往哪里的地址写呢,换位思考下,我们定义了一个变量后就肯定有地址,向地址写值就是将这个变量所指向的指针写值,也就是赋值。regs->SERIAL_CFG;regs->PARALLEL_CFG[0];regs->PARALLEL_CFG[1];regs->PARALLEL_CFG[2]

ret=LCD_PowerOn();//通过配置regiter的值将LCD打开,这里就不具体纠结这个细节了,要深入的话,可以自己去看下。

LCD_OUTREG32(&LCD_REG->SYNC_LCM_SIZE,0x00010001);

LCD_OUTREG32(&LCD_REG->SYNC_CNT,0x1);

ASSERT(ret== LCD_STATUS_OK);

#ifENABLE_LCD_INTERRUPT

if(request_irq(MT6577_LCD_IRQ_ID,

_LCD_InterruptHandler,IRQF_TRIGGER_LOW,"mtklcd", NULL) < 0)//申请LCD的中断处理函数,当有新的数据需要刷新到屏上面的时候,我们就会调用这个中断处理函数,关于这个中断处理函数我们下面会讲解。这里我一直很奇怪的是这个interrupt到底做了什么事情,接下来我会联系lcm_update函数进行统一讲解,这样我就能够将所有的流程串起来了。

{

DBI_LOG("[LCD][ERROR]fail to request LCDirqn");

returnLCD_STATUS_ERROR;

}

//mt65xx_irq_unmask(MT6577_LCD_IRQ_ID);//下面是设置一些寄存器的值

//enable_irq(MT6577_LCD_IRQ_ID);

init_waitqueue_head(&_lcd_wait_queue);

LCD_REG->INT_ENABLE.COMPLETED=1;

//LCD_REG->INT_ENABLE.REG_COMPLETED= 1;

LCD_REG->INT_ENABLE.CMDQ_COMPLETED=1;

LCD_REG->INT_ENABLE.HTT=1;

LCD_REG->INT_ENABLE.SYNC=1;

#endif

returnLCD_STATUS_OK;

}

2.2disp_drv_get_lcm_driver(lcm_name)

disp_drv_get_lcm_driver(lcm_name):这会将我们在uboot中得到的Lcm的名字传递过来。

constLCM_DRIVER *disp_drv_get_lcm_driver(constchar *lcm_name)

{

LCM_DRIVER*lcm = NULL;

printk("[LCMAuto Detect], we have %d lcm driversbuilt inn", lcm_count);

printk("[LCMAuto Detect], try to find driver for[%s]n",

(lcm_name==NULL)?"unknown":lcm_name);

if(lcm_count==1)//进行判断Lcm_count的值,这个值是通过计算lcm_driver_list里面大小进行判断的,如果我们需要新添加一个新的lcm进去的话,那么就需要在这个数组里面添加新的IC厂商的lcm,添加代码的路径是在/meidatek/custom/common/kernel/lcm/mt65xx_lcm_list.c里面进行添加

{

//we needto verify whether the lcm is connected

//eventhere is only one lcm type defined

lcm=lcm_driver_list[0];//如果这个lcm_driver_list中只有一个Lcm的话,那么就默认的就只取地一个就可以了

lcm->set_util_funcs(&lcm_utils);//没一个lcm结构里面都自己对应的定义成员,这里会调用lcm->set_util_funcs函数,传递进去的参数是在disp_drv.c里面定义好的结构,这个结构是mediatek的自己实现的display_driver:/mediatek/source/kernel/driver/video/disp_drv.c,我们调用lcm.set_util_funcs函数就是完成将display_driver里面的结构赋值给lcm_util这个static结构。

lcm->get_params(&s_lcm_params);//调用Lcm.get_params函数将s_lcm_params这个变量进行初始化,所赋的值,我们都都在每一个lcm进行参数的初始化。

lcm_params=&s_lcm_params;

lcm_drv=lcm;

{

isLCMFound= TRUE;

}

printk("[LCMSpecified]t[%s]n",(lcm->name==NULL)?"unknown":lcm->name);

gotodone;

}

else

{

inti;

for(i= 0;i< lcm_count;i++)

{

lcm_params=&s_lcm_params;

lcm=lcm_driver_list[i];

printk("[LCMAuto Detect] [%d] - [%s]t",i,(lcm->name==NULL)?"unknown":lcm->name);

lcm->set_util_funcs(&lcm_utils);

memset((void*)lcm_params,0,sizeof(LCM_PARAMS));

lcm->get_params(lcm_params);//上面的函数和count等于1的status是一样的,参考上面就可以了。

disp_drv_init_ctrl_if();//初始化dispaly的controlinterface有串口和并口等

disp_drv_set_driving_current(lcm_params);//从函数的命名定义上面,我们是在设置lcd的电流,但是我根据地址查询mediatek的socdatasheet并没有找到相关的定义。

disp_drv_init_io_pad(lcm_params);//查看datasheet是说在设置这个register就可以设置pin脚的值

if(lcm_name!= NULL)

{

if(!strcmp(lcm_name,lcm->name))//将我们从uboot中得到的lcm_name和我们没一个的lcm里面的name进行对比,如果一样的话,那么就代表我们已经找到了我们使用的Lcm

{

printk("tt[success]n");

isLCMFound= TRUE;

lcm_drv=lcm;

gotodone;

}

else

{

printk("tt[fail]n");

}

}

else

{

if(LCM_TYPE_DSI==lcm_params->type){

init_dsi(FALSE);//初始化dsi这种模式

}

if(lcm->compare_id!= NULL&&lcm->compare_id())如果发现我们的传递的lcm_name是NULL;并且Lcm_list又不止一个的话,那么就会调用没一个lcm的compare_id函数,这个函数是我们lcm里面实现好的,我这里用的是r61408这个IC屏,我们就看看这个lcm的compare_id函数是如何实现的。我们R61408这个IC里面直接是读取IC里面的devicecode register进行和这个LCM默认的值进行对比而得到的,当然不同deIC可能compare_id函数实现也不一样,只要满足一个判断的标准就可以了。

{

printk("tt[success]n");

isLCMFound= TRUE;

lcm_drv=lcm;

gotodone;

}

else

{

if(LCM_TYPE_DSI==lcm_params->type)

DSI_Deinit();

printk("tt[fail]n");

}

}

}

#ifdefHQ_PROJECT_A75

if(FALSE==isLCMFound)// ynn

{

lcm=lcm_driver_list[0];

lcm->set_util_funcs(&lcm_utils);

lcm->get_params(&s_lcm_params);

lcm_params=&s_lcm_params;

lcm_drv=lcm;

isLCMFound= TRUE;

}

#endif

}

done:

returnlcm_drv;

}//当找到这个lcm的话,就将找到的lcm赋值给lc_drv;将获得的s_lcm_params赋值给lcm_params,并将isLCMFound这个标志变量设置为TRUE,代表我已经找到了LCM。

2.3disp_dump_lcm_parameters(lcm_params)

disp_dump_lcm_parameters(lcm_params):将获得的lcm_params进行打印出来

2.4disp_drv_init_context

disp_drv_init_context:

staticBOOLdisp_drv_init_context(void)

{

if(disp_drv != NULL && lcm_drv !=NULL){

returnTRUE;

}

if(!isLCMFound)

DISP_DetectDevice();//进而判断我们有没有找到设备,如果没有的话,调用这个函数再进一次找设备的过程,和上面的selectDevice函数是一样的

disp_drv_init_ctrl_if();//和上面的一样是在初始化control接口

switch(lcm_params->type)//下面是在根据我们的lcm的类型,取出disp_drv的值,这里我们会将我们属于哪一种模式的Lcm就将DISP_DRIVER这个结构赋值过去,这个代码的路径是在/mediatek/source/kernel/drivers/video/这个路径下面有每一种模式的结构的定义。

{

caseLCM_TYPE_DBI : disp_drv =DISP_GetDriverDBI(); break;

caseLCM_TYPE_DPI : disp_drv =DISP_GetDriverDPI(); break;

caseLCM_TYPE_DSI : disp_drv =DISP_GetDriverDSI(); break;

default:ASSERT(0);

}

if(!disp_drv) returnFALSE;

returnTRUE;

}

到这里的话,我们的DISP_SelectDevice这个函数就已经讲解完了。那么我们的mtk_find_lcm_driver这个函数也就讲解完了。

在这里我们就返回到mtkfb.c中的Probe函数了,讲解下面的内容。

  

爱华网本文地址 » http://www.aihuau.com/a/25101015/278433.html

更多阅读

教大家如何安装Kx驱动详细步骤和教程 剪窗花的详细步骤图

教大家如何安装Kx驱动详细步骤和教程——简介现在很多朋友喜欢网络K歌 喊麦 当然本人也是非常喜欢的 可是有时候不小心声卡松了驱动没了不会安装怎么办? kx驱动也是大家经常碰到的问题今天教大家如何正确安装kx驱动教程 看了我教程的

CF高跳教程,各种跳法详细分析攻略 教父1剧情详细分析

本人玩CF也有四年的时间了,也对这款游戏有一些自己的心得,今天就对CF里的高跳的方法做一个详细的分析和解说,主要包括三阶跳、AD半身、闪蹲、滑蹲、大跳等,希望对想提高自己CF水平的玩家有些帮助。CF高跳教程,各种跳法详细分析攻略——

两道2011年高考遗传学试题的详细分析 历年医学遗传学试题

两道2011年高考遗传学试题的详细分析 【例1】(2011·四川卷·31·II)小麦的染色体数为42条。下图表示小麦的三个纯种品系的部分染色体及基因组成:I、II表示染色体,A为矮杆基因,B为抗矮黄病基因,E为抗条斑病基因,均为显性。乙品系和丙品系

声明:《MTK平台LCM驱动详细分析一 mtk lcm》为网友云外雁行斜分享!如侵犯到您的合法权益请联系我们删除