MTK6577---LCM驱动分析

来源:互联网 发布:kde ubuntu 编辑:程序博客网 时间:2024/05/23 02:07
一.framebuffer device注册
1. framebuffer定义

在alps/kernel/mediatek/platform/mt6577/kernel/core/mt6577_devs.c中
  1. #if defined(CONFIG_MTK_FB)
  2. static u64 mtkfb_dmamask = ~(u32)0;

  3. static struct resource resource_fb[]= {
  4.     {
  5.         .start   = 0,  //初始化start=0x3fb00000
  6.         .end     = 0,  //end=0x3fffffff
  7.         .flags   = IORESOURCE_MEM
  8.     }
  9. };

  10. static struct platform_device mt6577_device_fb ={
  11.     .name ="mtkfb",      //名字为mtkfb,与驱动匹配时用到
  12.     .id = 0,
  13.     .num_resources = ARRAY_SIZE(resource_fb),
  14.     .resource = resource_fb,
  15.     .dev ={
  16.         .dma_mask = &mtkfb_dmamask,
  17.         .coherent_dma_mask = 0xffffffff,
  18.     },
  19. };
  20. #endif

2. 设备注册
alps/kernel/mediatek/platform/mt6577/kernel/core/mt6577_devs.c
  1. __init int mt6577_board_init(void)
  2. {
  3. #if defined(CONFIG_MTK_FB)
  4.     if (((bl_fb.base== FB_START)&& (bl_fb.size == FB_SIZE))||(use_bl_fb== 2)){
  5.         mtkfb_set_lcm_inited(1);
  6.     }
  7.     resource_fb[0].start= FB_START;                 //将start与end初始化
  8.     resource_fb[0].end= FB_START + FB_SIZE- 1;
  9.    
  10.     retval = platform_device_register(&mt6577_device_fb); //注册平台设备 
  11. #endif
  12. }
3. 关于FB_SIZE
本来是一个简简单的宏定义,这儿却是一个函数,而且是稍微有些复杂的函数.
  在mt6577_board_init中有如下:
    if (((bl_fb.base == FB_START) && (bl_fb.size == FB_SIZE))
用了宏FB_SIZE,其定义如下:
#define FB_SIZE        (RESERVED_MEM_SIZE_FOR_FB)
#define RESERVED_MEM_SIZE_FOR_FB (DISP_GetVRamSizeBoot((char*)&temp_command_line))
在alps/kernel/mediatek/source/kernel/drivers/video/disp_drv.c中
  1. UINT32 DISP_GetVRamSizeBoot(char*cmdline)
  2. {
  3.     static UINT32 vramSize = 0;

  4.     if(vramSize)
  5.     {
  6.         return vramSize;
  7.     }
  8.     disp_get_lcm_name_boot(cmdline);  //3.1 从字符串中解析出lcm的名字,并提取函数指针

  9.     if(disp_drv)
  10.       vramSize = DISP_GetVRamSize();   //3.2fb_size,现在是5M 
  11.     vramSize = ALIGN_TO_POW_OF_2(vramSize, 0x100000);
  12.     return vramSize;
  13. }
3.1 解析硬件名,并获取函数指针
DISP_GetVRamSizeBoot

    --> disp_get_lcm_name_boot
在alps/kernel/mediatek/source/kernel/drivers/video/disp_drv.c中
从命令行中传入的参数是:
console=ttyMT0,921600n1 root=/dev/ram vmalloc=280M slub_max_order=0 lcm=1-nt35516_3d fps=6020
  1. char disp_lcm_name[256]= {0};
  2. BOOL disp_get_lcm_name_boot(char *cmdline)  //从命令字符串中解析出lcm的名字,并提取函数指针
  3. {
  4.     p = strstr(cmdline,"lcm="); //解析出lcm字符串后面的就是lcm设备
  5.     if(p== NULL)
  6.         return DISP_SelectDeviceBoot(NULL);//如果没有找到 ret false

  7.     //找到之后将全局变量isLCMFound设为1
  8.     isLCMFound = 1;    
  9.     //将lcm设备名nt35516保存在disp_lcm_name中,当然要去掉多余的"1-"
  10.     strncpy((char*)disp_lcm_name, (const char*)p, (int)(q-p));

  11.     if(DISP_SelectDeviceBoot(disp_lcm_name))
  12.         ret = TRUE;
  13. }
3.1.1 从list中找到硬件,并调用具体的函数指针
DISP_GetVRamSizeBoot
    --> disp_get_lcm_name_boot
        --> DISP_SelectDeviceBoot
在alps/kernel/mediatek/source/kernel/drivers/video/disp_drv.c中
初始化lcm_drv, lcm_params , disp_drv这三个全局变量
  1. BOOL DISP_SelectDeviceBoot(const char* lcm_name)
  2. {
  3.     LCM_DRIVER *lcm = NULL;
  4.     //lcm_count = sizeof(lcm_driver_list)/sizeof(LCM_DRIVER*);
  5.    //这儿用到了lcm_driver_list,在projectConfig.mk中可以配置list的项
  6.     for(i= 0;i < lcm_count;i++)    //lcm_count=1
  7.     {
  8.         lcm_params = &s_lcm_params;
  9.         lcm = lcm_driver_list[i];

  10.         lcm->set_util_funcs(&lcm_utils);  //这个没什么用处
  11.         lcm->get_params(lcm_params);      //调用nt35516的lcm_get_params,获取参数

  12.         if(lcm_count== 1)
  13.         {
  14.             lcm_drv = lcm;                //找到lcm的驱动结构体之后就保存在全局变量lcm_drv中
  15.             isLCMFound = TRUE;            //标志isLCMFound设为true
  16.             break;
  17.         }       
  18.     }
  19.     switch(lcm_params->type)
  20.     {
  21.         //将驱动的函数指针的保存在disp_drv中
  22.         case LCM_TYPE_DBI : disp_drv = DISP_GetDriverDBI(); break;
  23.         case LCM_TYPE_DPI : disp_drv = DISP_GetDriverDPI(); break;
  24.         case LCM_TYPE_DSI : disp_drv = DISP_GetDriverDSI(); break;   //儿用的是这个
  25.         default : ASSERT(0);
  26.     }
  27.     return TRUE;
  28. }
3.2 获取FB_SIZE
DISP_GetVRamSizeBoot
    --> DISP_GetVRamSize
  1. UINT32 DISP_GetVRamSize(void)
  2. {
  3.     static UINT32 vramSize = 0;
  4.     if (0== vramSize)
  5.     {
  6.         disp_drv_init_context();

  7.         //获取fb_size=w*h*bpp/8*2=960*544*4*2=4177920
  8.         vramSize = DISP_GetFBRamSize();

  9.         ///get DXI working buffer size=0
  10.         vramSize += disp_drv->get_working_buffer_size();

  11.         //layerSize=w*h*2+4096=960*540*2+4096, total=5218816
  12.         vramSize += DAL_GetLayerSize();

  13.         //对齐到1M, 0x500000=5M
  14.         vramSize = ALIGN_TO_POW_OF_2(vramSize, 0x100000);
  15.     }
  16.     return vramSize;
  17. }

二. fb驱动
在alps/kernel/mediatek/source/kernel/drivers/video/mtkfb.c中
module_init(mtkfb_init);
    --> platform_driver_register(&mtkfb_driver)
  1. #define MTKFB_DRIVER "mtkfb"
  2. static struct platform_driver mtkfb_driver =
  3. {
  4.     .driver ={
  5.         .name = MTKFB_DRIVER,        //驱动的name="mtkfb"正好与设备匹配,调用probe
  6.         .bus =&platform_bus_type,
  7.         .probe = mtkfb_probe,
  8.         .remove = mtkfb_remove,
  9.         .suspend = mtkfb_suspend,
  10.         .resume= mtkfb_resume,
  11.         .shutdown = mtkfb_shutdown,
  12.     },
  13. };
1. 驱动的probe函数
  1. static int mtkfb_probe(struct device*dev)
  2. {
  3.     struct platform_device *pdev;
  4.     struct mtkfb_device *fbdev = NULL;
  5.     struct fb_info *fbi;
  6.   
  7.     a.从uboot传给kernel的命令行字符串中解析出fps
  8.     //console=ttyMT0,921600n1 root=/dev/ram vmalloc=280M slub_max_order=0
  9.     //uboot_ver=2010.06 uboot_build_ver=MAIN2.2.ubt.4158 lcm=1-nt35516_3d fps=6004
  10.     lcd_fps = simple_strtol(p,NULL, 10);  //lcd_fps=6004

  11.    
  12.     if(DISP_IsContextInited()== FALSE)      //在FB_SIZE宏中过了,进入else
  13.     {
  14.         mtkfb_find_lcm_driver();
  15.     }
  16.     else
  17.     {
  18.         LCD_CHECK_RET(LCD_Init());          //1.1 硬件初始化并申请中断和等侍队列
  19.     }
  20.    
  21.     //初始化下面这6个全局变量
  22.     MTK_FB_XRES = DISP_GetScreenWidth();
  23.     MTK_FB_YRES = DISP_GetScreenHeight();
  24.     fb_xres_update = MTK_FB_XRES;
  25.     fb_yres_update = MTK_FB_YRES;
  26.     MTK_FB_BPP = DISP_GetScreenBpp();
  27.     MTK_FB_PAGES = DISP_GetPages();

  28.     init_waitqueue_head(&screen_update_wq);      //又一个等侍队列
  29.    
  30.     //创建线程并唤醒, kthread_create之后并不会马上运行,需要wake_up
  31.     screen_update_task = kthread_create(screen_update_kthread,NULL, "screen_update_kthread");
  32.     wake_up_process(screen_update_task);
  33.    
  34.     //注册两个回调函数
  35.     DISP_INTERRUPT_CALLBACK_STRUCT cbStruct;
  36.     cbStruct.pFunc = mtkfb_lcd_complete_interrupt;
  37.     cbStruct.pParam = NULL;
  38.     DISP_SetInterruptCallback(DISP_LCD_TRANSFER_COMPLETE_INT, &cbStruct);

  39.     DISP_INTERRUPT_CALLBACK_STRUCT cbStruct;
  40.     cbStruct.pFunc = mtkfb_dpi_vsync_interrupt;
  41.     cbStruct.pParam = NULL;
  42.     DISP_SetInterruptCallback(DISP_DPI_VSYNC_INT,&cbStruct);

  43.     init_state = 0;

  44.     pdev = to_platform_device(dev);
  45.     //申请framebuffer
  46.     fbi = framebuffer_alloc(sizeof(struct mtkfb_device), dev);
  47.   
  48.     mtkfb_fbi = fbi;
  49.     fbdev = (struct mtkfb_device*)fbi->par;
  50.     fbdev->fb_info= fbi;
  51.     fbdev->dev= dev;
  52.     dev_set_drvdata(dev, fbdev);

  53.     init_state++;
  54.     fbdev->fb_size_in_byte= MTK_FB_SIZEV;
  55.     struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  56.     fbdev->fb_pa_base= res->start;        //获取fb的物理地址,并映射
  57.     fbdev->fb_va_base= ioremap_nocache(res->start, res->end- res->start+ 1);
  58.        
  59. #if defined(MTK_M4U_SUPPORT)
  60.     fb_va_m4u = fbdev->fb_pa_base;
  61.     fb_size_m4u = fbdev->fb_size_in_byte;
  62.     //为overlay的链表分配内存
  63.     overlay_buffer_head = (struct fb_overlay_buffer_list*)vmalloc(sizeof(struct fb_overlay_buffer_list));
  64.     overlay_buffer_head->next= NULL;
  65. #endif

  66.     init_state++;// 2
  67.     DISP_Init((DWORD)fbdev->fb_va_base,(DWORD)fbdev->fb_pa_base, is_lcm_inited);
  68.    
  69.     init_state++;// 3
  70.     r = mtkfb_fbinfo_init(fbi);   //初始化 fb_info
  71.   
  72.     init_state++;// 4
  73.     r = mtkfb_register_sysfs(fbdev);

  74.     init_state++;// 5
  75.     r = register_framebuffer(fbi); //

  76.     fbdev->state= MTKFB_ACTIVE;
  77.     return 0;
  78. }


1.1 硬件初始化并申请中断+初始化等侍队列
  1. LCD_STATUS LCD_Init(void)
  2. {
  3.     memset(&_lcdContext, 0, sizeof(_lcdContext));
  4.     _ResetBackupedLCDRegisterValues();
  5.     ret = LCD_PowerOn();
  6.     LCD_OUTREG32(&LCD_REG->SYNC_LCM_SIZE, 0x00010001);
  7.     LCD_OUTREG32(&LCD_REG->SYNC_CNT, 0x1);
  8.     //申请中断和等侍队列
  9.     request_irq(MT6577_LCD_IRQ_ID, _LCD_InterruptHandler, IRQF_TRIGGER_LOW,"mtklcd", NULL);
  10.     init_waitqueue_head(&_lcd_wait_queue);
  11.     LCD_REG->INT_ENABLE.COMPLETED= 1;
  12.     LCD_REG->INT_ENABLE.CMDQ_COMPLETED= 1;
  13.     LCD_REG->INT_ENABLE.HTT= 1;
  14.     LCD_REG->INT_ENABLE.SYNC= 1;

  15.     return LCD_STATUS_OK;
  16. }


  1. static irqreturn_t _LCD_InterruptHandler(int irq, void*dev_id)
  2. {
  3.     LCD_REG_INTERRUPT status = LCD_REG->INT_STATUS;
  4.     if (status.COMPLETED)
  5.     {
  6.         wake_up_interruptible(&_lcd_wait_queue);
  7.        //即调用mtkfb_lcd_complete_interrupt
  8.         if(_lcdContext.pIntCallback)
  9.             _lcdContext.pIntCallback(DISP_LCD_TRANSFER_COMPLETE_INT);             
  10.     }
  11.     if (status.SYNC)
  12.     {
  13.         //DISP_LCD_SYNC_INT即调用mtkfb_lcd_complete_interrupt
  14.         if(_lcdContext.pIntCallback)
  15.             _lcdContext.pIntCallback(DISP_LCD_SYNC_INT);
  16.         lcd_esd_check = false;
  17.     }
  18.     LCD_OUTREG32(&LCD_REG->INT_STATUS, 0);
  19.     return IRQ_HANDLED;
  20. }




  1. static void mtkfb_lcd_complete_interrupt(void*param)
  2. {
  3.     if(atomic_read(&has_pending_update))
  4.     {
  5.         wake_up_interruptible(&screen_update_wq);
  6.     }

  7. #if defined(MTK_HDMI_SUPPORT)
  8.     hdmi_source_buffer_switch();
  9.     if(is_hdmi_active())
  10.     {
  11.         hdmi_update();
  12.     }
  13. #endif

  14. }


线程函数中wait_event
  1. static int screen_update_kthread(void*data)
  2. {
  3.     struct sched_param param = { .sched_priority = RTPM_PRIO_SCRN_UPDATE };
  4.     sched_setscheduler(current, SCHED_RR,&param);

  5.     for(;; ) {
  6.         wait_event_interruptible(screen_update_wq, atomic_read(&has_pending_update));
  7.         MTKFB_LOG("wq wakeup\n");
  8.         mtkfb_update_screen_impl();

  9.         atomic_set(&has_pending_update,0);
  10.         if (kthread_should_stop())
  11.             break;
  12.     }

  13.     return 0;
  14. }

0 0
原创粉丝点击