原文地址:http://blog.chinaunix.net/uid-26009923-id-4013601.html
一.framebuffer device注册
1. framebuffer定义
在alps/kernel/mediatek/platform/mt6577/kernel/core/mt6577_devs.c中
-
#if defined(CONFIG_MTK_FB)
-
static u64 mtkfb_dmamask = ~(u32)0;
-
-
static struct resource resource_fb[] = {
-
{
-
.start = 0, //初始化start=0x3fb00000
-
.end = 0, //end=0x3fffffff
-
.flags = IORESOURCE_MEM
-
}
-
};
-
-
static struct platform_device mt6577_device_fb = {
-
.name = "mtkfb", //名字为mtkfb,与驱动匹配时用到
-
.id = 0,
-
.num_resources = ARRAY_SIZE(resource_fb),
-
.resource = resource_fb,
-
.dev = {
-
.dma_mask = &mtkfb_dmamask,
-
.coherent_dma_mask = 0xffffffff,
-
},
-
};
-
#endif
2. 设备注册
在alps/kernel/mediatek/platform/mt6577/kernel/core/mt6577_devs.c中
-
__init int mt6577_board_init(void)
-
{
-
#if defined(CONFIG_MTK_FB)
-
if (((bl_fb.base == FB_START) && (bl_fb.size == FB_SIZE)) ||(use_bl_fb == 2)) {
-
mtkfb_set_lcm_inited(1);
-
}
-
resource_fb[0].start = FB_START; //将start与end初始化
-
resource_fb[0].end = FB_START + FB_SIZE - 1;
-
-
retval = platform_device_register(&mt6577_device_fb); //注册平台设备
-
#endif
-
}
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中
-
UINT32 DISP_GetVRamSizeBoot(char *cmdline)
-
{
-
static UINT32 vramSize = 0;
-
-
if(vramSize)
-
{
-
return vramSize;
-
}
-
disp_get_lcm_name_boot(cmdline); //3.1 从字符串中解析出lcm的名字,并提取函数指针
-
-
if(disp_drv)
-
vramSize = DISP_GetVRamSize(); //3.2 获取fb_size,现在是5M
-
vramSize = ALIGN_TO_POW_OF_2(vramSize, 0x100000);
-
return vramSize;
-
}
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
-
char disp_lcm_name[256] = {0};
-
BOOL disp_get_lcm_name_boot(char *cmdline) //从命令字符串中解析出lcm的名字,并提取函数指针
-
{
-
p = strstr(cmdline, "lcm="); //解析出lcm字符串后面的就是lcm设备
-
if(p == NULL)
-
return DISP_SelectDeviceBoot(NULL); //如果没有找到 ret false
-
-
//找到之后将全局变量isLCMFound设为1
-
isLCMFound = 1;
-
//将lcm设备名nt35516保存在disp_lcm_name中,当然要去掉多余的"1-"
-
strncpy((char*)disp_lcm_name, (const char*)p, (int)(q-p));
-
-
if(DISP_SelectDeviceBoot(disp_lcm_name))
-
ret = TRUE;
-
}
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这三个全局变量
-
BOOL DISP_SelectDeviceBoot(const char* lcm_name)
-
{
-
LCM_DRIVER *lcm = NULL;
-
//全局变量lcm_count = sizeof(lcm_driver_list)/sizeof(LCM_DRIVER*);
-
//这儿用到了lcm_driver_list,在projectConfig.mk中可以配置list的项
-
for(i = 0;i < lcm_count;i++) //lcm_count=1
-
{
-
lcm_params = &s_lcm_params;
-
lcm = lcm_driver_list[i];
-
-
lcm->set_util_funcs(&lcm_utils); //这个没什么用处
-
lcm->get_params(lcm_params); //调用nt35516的lcm_get_params,获取参数
-
-
if(lcm_count == 1)
-
{
-
lcm_drv = lcm; //找到lcm的驱动结构体之后就保存在全局变量lcm_drv中
-
isLCMFound = TRUE; //标志isLCMFound设为true
-
break;
-
}
-
}
-
switch(lcm_params->type)
-
{
-
//将驱动的函数指针的保存在disp_drv中
-
case LCM_TYPE_DBI : disp_drv = DISP_GetDriverDBI(); break;
-
case LCM_TYPE_DPI : disp_drv = DISP_GetDriverDPI(); break;
-
case LCM_TYPE_DSI : disp_drv = DISP_GetDriverDSI(); break; //这儿用的是这个
-
default : ASSERT(0);
-
}
-
return TRUE;
-
}
3.2 获取FB_SIZE
DISP_GetVRamSizeBoot
--> DISP_GetVRamSize
-
UINT32 DISP_GetVRamSize(void)
-
{
-
static UINT32 vramSize = 0;
-
if (0 == vramSize)
-
{
-
disp_drv_init_context();
-
-
//获取fb_size=w*h*bpp/8*2=960*544*4*2=4177920
-
vramSize = DISP_GetFBRamSize();
-
-
///get DXI working buffer size=0
-
vramSize += disp_drv->get_working_buffer_size();
-
-
//layerSize=w*h*2+4096=960*540*2+4096, total=5218816
-
vramSize += DAL_GetLayerSize();
-
-
//对齐到1M, 0x500000=5M
-
vramSize = ALIGN_TO_POW_OF_2(vramSize, 0x100000);
-
}
-
return vramSize;
-
}
二. fb驱动
在alps/kernel/mediatek/source/kernel/drivers/video/mtkfb.c中
module_init(mtkfb_init);
--> platform_driver_register(&mtkfb_driver)
-
#define MTKFB_DRIVER "mtkfb"
-
static struct platform_driver mtkfb_driver =
-
{
-
.driver = {
-
.name = MTKFB_DRIVER, //驱动的name="mtkfb"正好与设备匹配,调用probe
-
.bus = &platform_bus_type,
-
.probe = mtkfb_probe,
-
.remove = mtkfb_remove,
-
.suspend = mtkfb_suspend,
-
.resume = mtkfb_resume,
-
.shutdown = mtkfb_shutdown,
-
},
-
};
1. 驱动的probe函数
-
static int mtkfb_probe(struct device *dev)
-
{
-
struct platform_device *pdev;
-
struct mtkfb_device *fbdev = NULL;
-
struct fb_info *fbi;
-
-
a.从uboot传给kernel的命令行字符串中解析出fps
-
//console=ttyMT0,921600n1 root=/dev/ram vmalloc=280M slub_max_order=0
-
//uboot_ver=2010.06 uboot_build_ver=MAIN2.2.ubt.4158 lcm=1-nt35516_3d fps=6004
-
lcd_fps = simple_strtol(p, NULL, 10); //lcd_fps=6004
-
-
-
if(DISP_IsContextInited() == FALSE) //在FB_SIZE宏中己经初始化过了,进入else
-
{
-
mtkfb_find_lcm_driver();
-
}
-
else
-
{
-
LCD_CHECK_RET(LCD_Init()); //1.1 硬件初始化并申请中断和等侍队列
-
}
-
-
//初始化下面这6个全局变量
-
MTK_FB_XRES = DISP_GetScreenWidth();
-
MTK_FB_YRES = DISP_GetScreenHeight();
-
fb_xres_update = MTK_FB_XRES;
-
fb_yres_update = MTK_FB_YRES;
-
MTK_FB_BPP = DISP_GetScreenBpp();
-
MTK_FB_PAGES = DISP_GetPages();
-
-
init_waitqueue_head(&screen_update_wq); //又一个等侍队列
-
-
//创建线程并唤醒, kthread_create之后并不会马上运行,需要wake_up
-
screen_update_task = kthread_create(screen_update_kthread, NULL, "screen_update_kthread");
-
wake_up_process(screen_update_task);
-
-
//注册两个回调函数
-
DISP_INTERRUPT_CALLBACK_STRUCT cbStruct;
-
cbStruct.pFunc = mtkfb_lcd_complete_interrupt;
-
cbStruct.pParam = NULL;
-
DISP_SetInterruptCallback(DISP_LCD_TRANSFER_COMPLETE_INT, &cbStruct);
-
-
DISP_INTERRUPT_CALLBACK_STRUCT cbStruct;
-
cbStruct.pFunc = mtkfb_dpi_vsync_interrupt;
-
cbStruct.pParam = NULL;
-
DISP_SetInterruptCallback(DISP_DPI_VSYNC_INT, &cbStruct);
-
-
init_state = 0;
-
-
pdev = to_platform_device(dev);
-
//申请framebuffer
-
fbi = framebuffer_alloc(sizeof(struct mtkfb_device), dev);
-
-
mtkfb_fbi = fbi;
-
fbdev = (struct mtkfb_device *)fbi->par;
-
fbdev->fb_info = fbi;
-
fbdev->dev = dev;
-
dev_set_drvdata(dev, fbdev);
-
-
init_state++;
-
fbdev->fb_size_in_byte = MTK_FB_SIZEV;
-
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
fbdev->fb_pa_base = res->start; //获取fb的物理地址,并映射
-
fbdev->fb_va_base = ioremap_nocache(res->start, res->end - res->start + 1);
-
-
#if defined(MTK_M4U_SUPPORT)
-
fb_va_m4u = fbdev->fb_pa_base;
-
fb_size_m4u = fbdev->fb_size_in_byte;
-
//为overlay的链表分配内存
-
overlay_buffer_head = (struct fb_overlay_buffer_list*)vmalloc(sizeof(struct fb_overlay_buffer_list));
-
overlay_buffer_head->next = NULL;
-
#endif
-
-
init_state++; // 2
-
DISP_Init((DWORD)fbdev->fb_va_base, (DWORD)fbdev->fb_pa_base, is_lcm_inited);
-
-
init_state++; // 3
-
r = mtkfb_fbinfo_init(fbi); //初始化 fb_info
-
-
init_state++; // 4
-
r = mtkfb_register_sysfs(fbdev);
-
-
init_state++; // 5
-
r = register_framebuffer(fbi); //注册
-
-
fbdev->state = MTKFB_ACTIVE;
-
return 0;
-
}
1.1 硬件初始化并申请中断+初始化等侍队列
-
LCD_STATUS LCD_Init(void)
-
{
-
memset(&_lcdContext, 0, sizeof(_lcdContext));
-
_ResetBackupedLCDRegisterValues();
-
ret = LCD_PowerOn();
-
LCD_OUTREG32(&LCD_REG->SYNC_LCM_SIZE, 0x00010001);
-
LCD_OUTREG32(&LCD_REG->SYNC_CNT, 0x1);
-
//申请中断和等侍队列
-
request_irq(MT6577_LCD_IRQ_ID, _LCD_InterruptHandler, IRQF_TRIGGER_LOW, "mtklcd", NULL);
-
init_waitqueue_head(&_lcd_wait_queue);
-
LCD_REG->INT_ENABLE.COMPLETED = 1;
-
LCD_REG->INT_ENABLE.CMDQ_COMPLETED = 1;
-
LCD_REG->INT_ENABLE.HTT = 1;
-
LCD_REG->INT_ENABLE.SYNC = 1;
-
-
return LCD_STATUS_OK;
-
}
-
static irqreturn_t _LCD_InterruptHandler(int irq, void *dev_id)
-
{
-
LCD_REG_INTERRUPT status = LCD_REG->INT_STATUS;
-
if (status.COMPLETED)
-
{
-
wake_up_interruptible(&_lcd_wait_queue);
-
//即调用mtkfb_lcd_complete_interrupt
-
if(_lcdContext.pIntCallback)
-
_lcdContext.pIntCallback(DISP_LCD_TRANSFER_COMPLETE_INT);
-
}
-
if (status.SYNC)
-
{
-
//DISP_LCD_SYNC_INT即调用mtkfb_lcd_complete_interrupt
-
if(_lcdContext.pIntCallback)
-
_lcdContext.pIntCallback(DISP_LCD_SYNC_INT);
-
lcd_esd_check = false;
-
}
-
LCD_OUTREG32(&LCD_REG->INT_STATUS, 0);
-
return IRQ_HANDLED;
-
}
-
static void mtkfb_lcd_complete_interrupt(void *param)
-
{
-
if(atomic_read(&has_pending_update))
-
{
-
wake_up_interruptible(&screen_update_wq);
-
}
-
-
#if defined(MTK_HDMI_SUPPORT)
-
hdmi_source_buffer_switch();
-
if(is_hdmi_active())
-
{
-
hdmi_update();
-
}
-
#endif
-
-
}
线程函数中wait_event
-
static int screen_update_kthread(void *data)
-
{
-
struct sched_param param = { .sched_priority = RTPM_PRIO_SCRN_UPDATE };
-
sched_setscheduler(current, SCHED_RR, ¶m);
-
-
for( ;; ) {
-
wait_event_interruptible(screen_update_wq, atomic_read(&has_pending_update));
-
MTKFB_LOG("wq wakeup\n");
-
mtkfb_update_screen_impl();
-
-
atomic_set(&has_pending_update,0);
-
if (kthread_should_stop())
-
break;
-
}
-
-
return 0;
-
}
阅读(1460) | 评论(0) | 转发(0) |