Qcom_lcd_driver 之一 -- 总体架构

/*
//devices-xxx.c
static struct platform_device msm_lcdc_device = {
        .name   = "lcdc",
        .id     = 0,
};

//board-xxx.c
static struct lcdc_platform_data lcdc_pdata = {
        .lcdc_power_save   = lcdc_panel_power,
};


//board-msmxxx.c
static void __init msm7x30_init(void)
+-- msm_fb_add_devices();
    +-- msm_fb_register_device("mdp", &mdp_pdata);
    +-- msm_fb_register_device("pmdh", &mddi_pdata);
    +-- msm_fb_register_device("lcdc", &lcdc_pdata); //注册id=0的"lcdc"设备
        +-- msm_register_device(&msm_lcdc_device, data);  //将lcdc_device.dev.platform_data置为lcdc_pdata
            +-- pdev->dev.platform_data = data;
            +-- platform_device_register(pdev);
    +-- msm_fb_register_device("dtv", &dtv_pdata);
    +-- msm_fb_register_device("tvenc", &atv_pdata);
*/

#################################################################################################################

//@kernel/drivers/video/msm/Makefile
obj-$(CONFIG_FB_MSM_LCDC_HIMAX_WQVGA727) += lcdc_panel_wqvga727.o

//kernel/arch/arm/configs/msm7630_xxx_defconfig
CONFIG_FB_MSM_LCDC_HIMAX_WQVGA727=y

//因此,kernel/drivers/video/msm/lcdc_panel_wqvga727.c将被编入kernel.
//@kernel/drivers/video/msm/lcdc_panel_wqvga727.c
static struct platform_driver this_driver = {
        .probe  = lcdc_panel_probe,
        .driver = {
                .name   = "lcdc_panel_xx",
        },
};

static struct platform_device this_device = {
        .name   = "lcdc_panel_xx",
        .id     = 1,
        .dev    = {
                .platform_data = &lcdc_himax_panel_data,
        }
};

@kernel/drivers/video/msm/lcdc_panel_wqvga727.c
module_init(lcdc_himax_panel_init);
static int __init lcdc_himax_panel_init(void)
+-- platform_driver_register(&this_driver);  //注册“lcdc_panel_xx”驱动

+-- pinfo = &lcdc_himax_panel_data.panel_info;
+-- pinfo->xres = 240;
+-- pinfo->yres = 400;
+-- pinfo->type = LCDC_PANEL;                 //这里将panel_info->type初始化为LCDC_TYPE
+-- pinfo->pdest = DISPLAY_1;
+-- pinfo->wait_cycle = 0;
+-- pinfo->bpp = 18;
+-- pinfo->fb_num = 2;
+-- pinfo->clk_rate = 8192000;

+-- pinfo->lcdc.h_back_porch = 4;
+-- pinfo->lcdc.h_front_porch = 4;
+-- pinfo->lcdc.h_pulse_width = 4;
+-- pinfo->lcdc.v_back_porch = 3;
+-- pinfo->lcdc.v_front_porch = 3;
+-- pinfo->lcdc.v_pulse_width = 1;
+-- pinfo->lcdc.border_clr = 0;         /* blk */
+-- pinfo->lcdc.underflow_clr = 0xff;   /* blue */
+-- pinfo->lcdc.hsync_skew = 0;

+-- platform_device_register(&this_device);  //注册“lcdc_panel_xx”设备

//因此在lcdc_himax_panel_init()执行之后,lcdc_panel_probe()
static int __init 
lcdc_panel_probe(struct platform_device *pdev)
+-- msm_fb_add_device(pdev);      //在这里会设置driver_data.并把“lcdc_panel_xx”设备加入platform总线上
    +-- struct fb_info *fbi;
    +-- pdata = pdev->dev.platform_data;   //这里platform_data就是lcdc_himax_panel_data  
        //对于lcdc_panel_wqvga727.c,pdata->panel_info.type在lcdc_himax_panel_init()里面初始化为LCDC_PANEL  
    +-- type = pdata->panel_info.type;     
    +-- fb_num = pdata->panel_info.fb_num;
    +-- this_dev = msm_fb_device_alloc(pdata, type, id); //这里__重新__创建一个platform_device
        +-- struct platform_device *this_dev = NULL;
            //根据type来确定新的platform_device的name
        +-- switch (type) {
            case EBI2_PANEL:
                snprintf(dev_name, sizeof(dev_name), "ebi2_lcd");
        	break;
            case MDDI_PANEL:
                snprintf(dev_name, sizeof(dev_name), "mddi");
                break;
            case EXT_MDDI_PANEL:
                snprintf(dev_name, sizeof(dev_name), "mddi_ext");
        	break;
            case TV_PANEL:
        	snprintf(dev_name, sizeof(dev_name), "tvenc");
        	break;
            case HDMI_PANEL:
            case LCDC_PANEL:
                //因此对于lcdc_panel_wqvga727.c,type就是LCDC_PANEL,于是dev_name就被初始化为"lcdc"
        	printk("msm_fb_device_alloc: inside type!\n");
        	snprintf(dev_name, sizeof(dev_name), "lcdc");
        	break;
            case DTV_PANEL:
                snprintf(dev_name, sizeof(dev_name), "dtv");
                break;
            case MIPI_VIDEO_PANEL:
            case MIPI_CMD_PANEL:
                snprintf(dev_name, sizeof(dev_name), "mipi_dsi");
                break;
            default:
                return NULL;
            }
            //创建新的platform_device,并将其platform_data指向lcdc_himax_panel_data这个struct msm_fb_panel_data结构实例
        +-- this_dev = platform_device_alloc(dev_name, ((u32) type << 16) | (u32) id);
        +-- platform_device_add_data(this_dev, pdata, sizeof(struct msm_fb_panel_data))
            +-- void *d = kmemdup(data, size, GFP_KERNEL);
            +-- pdev->dev.platform_data = d;
        +-- return this_dev; //返回新的platform_device
        //开辟一段sizeof(fb_info)+sizeof(struct msm_fb_data_type)大小的内存,并用info->par指针指向后者
    +-- fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);
        +-- int fb_info_size = sizeof(struct fb_info);
        +-- struct fb_info *info;
        +-- p = kzalloc(fb_info_size + size, GFP_KERNEL);
        +-- info = (struct fb_info *) p;
        +-- info->par = p + fb_info_size;
        +-- info->device = dev;
        +-- return info;
        //将sizeof(struct msm_fb_data_type)那段内存单独提出来,用mfd指针指向之.
    +-- mfd = (struct msm_fb_data_type *)fbi->par;
    +-- mfd->key = MFD_KEY;
    +-- mfd->fbi = fbi;
    +-- mfd->panel.type = type;
    +-- mfd->panel.id = id;
    +-- mfd->fb_page = fb_num;
    +-- mfd->index = fbi_list_index;
    +-- mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
    +-- mfd->pdev = this_dev;

    +-- mfd_list[mfd_list_index++] = mfd;
    +-- fbi_list[fbi_list_index++] = fbi;

    +-- platform_set_drvdata(this_dev, mfd);     //把新创建的platform_device设备的dev->p->driver_data设置为mfd
        +-- dev_set_drvdata(&(_dev)->dev, (data))
            +-- dev->p->driver_data = data;
    +-- platform_device_add(this_dev)            //把新创建的platform_device设备挂到platform总线上.





board-msmxxx.c中注册了一个名为"lcdc"的platform_device,该platform_device在arch/arm/mach-msm/devices-msm7xxx.c
中定义.此platform设备将和lcdc_driver匹配,id为0.
lcdc_panel_wqvga727.c中也注册了一个名为"lcdc"的platform设备,也将匹配lcdc_driver,id为1.

lcdc_driver的定义在drivers/video/msm/lcdc.c中.
//@drivers/video/msm/lcdc.c
static struct platform_driver lcdc_driver = {
        .probe = lcdc_probe,
        .remove = lcdc_remove,
        .suspend = NULL,
        .resume = NULL,
        .shutdown = NULL,
        .driver = {
                   .name = "lcdc",
                   },
};



//@module_init(lcdc_driver_init);
static int __init lcdc_driver_init(void)
+-- pixel_mdp_clk = clk_get(NULL, "pixel_mdp_clk");
?-- pixel_lcdc_clk = clk_get(NULL, "pixel_lcdc_clk");
?-- pixel_mdp_clk = clk_get(NULL, "mdp_lcdc_pclk_clk");
?-- pixel_lcdc_clk = clk_get(NULL, "mdp_lcdc_pad_pclk_clk");
+-- pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc", PM_QOS_DEFAULT_VALUE);
+-- lcdc_register_driver();
    +-- platform_driver_register(&lcdc_driver);          //注册“lcdc”驱动




//设备&驱动匹配之后调用lcdc_probe()
static int lcdc_probe(struct platform_device *pdev)
+-- if (pdev->id == 0) {                    //id为0的"lcdc"设备没有dev->p->driver_data
        lcdc_pdata = pdev->dev.platform_data;  //取出lcdc_himax_panel_data结构,用lcdc_pdata指向之
        return 0;
    }
+-- mfd = platform_get_drvdata(pdev);      //取出id不为0的"lcdc"设备的dev->p->driver_data,用mfd指向之
+-- platform_driver_register(&lcdc_driver);
    //创建一个名为"mdp"的platform_device,并将其platform_data指向一个struct msm_fb_panel_data结构.
+-- mdp_dev = platform_device_alloc("mdp", pdev->id);
+-- mfd->pdev = mdp_dev;
+-- mfd->dest = DISPLAY_LCDC;
+-- platform_device_add_data(mdp_dev, pdev->dev.platform_data, sizeof(struct msm_fb_panel_data))
    +-- void *d = kmemdup(data, size, GFP_KERNEL);
    +-- pdev->dev.platform_data = d;
    //初始化"mdp"设备的platform_data
+-- pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data; //取出lcdc_himax_panel_data结构,用pdata指向之
+-- pdata->on = lcdc_on;
+-- pdata->off = lcdc_off;
+-- pdata->next = pdev;

+-- mfd->panel_info = pdata->panel_info; //实际上就是lcdc_himax_panel_data.panel_info
+-- if (mfd->index == 0)
        mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
    else
        mfd->fb_imgType = MDP_RGB_565;

+-- fbi = mfd->fbi;
+-- fbi->var.pixclock = clk_round_rate(pixel_mdp_clk,mfd->panel_info.clk_rate);
+-- fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
+-- fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
+-- fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
+-- fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
+-- fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
+-- fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
    //将"mdp"设备的dev->p->driver_data指向id不为0的"lcdc"设备的dev->p->driver_data指向的数据
    //即lcdc_panel_probe()函数中创建的struct msm_fb_data_type
+-- platform_set_drvdata(mdp_dev, mfd);  
+-- platform_device_add(mdp_dev);        //将"mdp"设备添加到platform总线,id不为0
+-- pdev_list[pdev_list_cnt++] = pdev;


/*
static struct platform_device msm_mdp_device = {
        .name   = "mdp",
        .id     = 0,
        .num_resources  = ARRAY_SIZE(msm_mdp_resources),
        .resource       = msm_mdp_resources,
};

static void __init msm7x30_init(void) 
+-- msm_fb_add_devices(); 
    +-- msm_fb_register_device("mdp", &mdp_pdata);       //注册id=0的"mdp"设备
        +-- msm_register_device(&msm_mdp_device, data);  //将msm_mdp_device.dev.platform_data置为mdp_data
            +-- pdev->dev.platform_data = data; 
            +-- platform_device_register(pdev); 
    +-- msm_fb_register_device("pmdh", &mddi_pdata); 
    +-- msm_fb_register_device("lcdc", &lcdc_pdata); 
    +-- msm_fb_register_device("dtv", &dtv_pdata); 
    +-- msm_fb_register_device("tvenc", &atv_pdata); 
*/

//@drivers/video/msm/mdp.c
static struct platform_driver mdp_driver = {
	.probe = mdp_probe,
        .remove = mdp_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
        .suspend = mdp_suspend,
        .resume = NULL,
#endif
        .shutdown = NULL,
        .driver = {
                .name = "mdp",
                .pm = &mdp_dev_pm_ops,
	},
};

//module_init(mdp_driver_init);
static int __init mdp_driver_init(void)
+-- mdp_drv_init();
+-- mdp_register_driver();
    +-- early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1;
    +-- early_suspend.suspend = mdp_early_suspend;
    +-- register_early_suspend(&early_suspend);
    +-- platform_driver_register(&mdp_driver);   //注册"mdp"驱动
+-- mdp4_debugfs_init();

//“mdp”设备/驱动匹配后调用mdp_probe()
//MDP -- Mobile Display Processor
static int mdp_probe(struct platform_device *pdev)
    //id为0的设备最先初始化,在其初始化期间初始化mdp硬件
+-- if ((pdev->id == 0) && (pdev->num_resources > 0)) {
        mdp_pdata = pdev->dev.platform_data;
        size =  resource_size(&pdev->resource[0]);
        msm_mdp_base = ioremap(pdev->resource[0].start, size);
        mdp_irq_clk_setup();
#ifdef CONFIG_FB_MSM_MDP40
        mdp4_hw_init();
        mdp4_fetch_cfg(clk_get_rate(mdp_clk));
#else
        mdp_hw_init();
#endif
        mdp_resource_initialized = 1;
        return 0;
    }

+-- if (!mdp_resource_initialized)
        return -EPERM;
+-- mfd = platform_get_drvdata(pdev);

+-- msm_fb_dev = platform_device_alloc("msm_fb", pdev->id); //创建"msm_fb"设备
+-- mfd->pdev = msm_fb_dev;

+-- platform_device_add_data(msm_fb_dev, pdev->dev.platform_data, sizeof(struct msm_fb_panel_data))
+-- pdata = msm_fb_dev->dev.platform_data;
+-- pdata->on = mdp_on;
+-- pdata->off = mdp_off;
+-- pdata->next = pdev;

+-- switch (mfd->panel.type) {
        case EXT_MDDI_PANEL:
        case MDDI_PANEL:
        case EBI2_PANEL:
        ...
        break;
        case HDMI_PANEL:
        case LCDC_PANEL:
            pdata->on = mdp_lcdc_on;
            pdata->off = mdp_lcdc_off;
            mfd->hw_refresh = TRUE;
            mfd->cursor_update = mdp_hw_cursor_update;  
            mfd->dma_fnc = mdp_lcdc_update;
            mfd->dma = &dma2_data;
            spin_lock_irqsave(&mdp_spin_lock, flag);
            mdp_intr_mask &= ~MDP_DMA_P_DONE;
            outp32(MDP_INTR_ENABLE, mdp_intr_mask);
            spin_unlock_irqrestore(&mdp_spin_lock, flag);
        break;
        ...
    }

+-- platform_set_drvdata(msm_fb_dev, mfd);   //将"msm_fb"设备的platform_data指向mfd指向的数据
+-- platform_device_add(msm_fb_dev);         //将"msm_fb"设备添加到platform总线上

+-- pm_runtime_set_active(&pdev->dev);
+-- pm_runtime_enable(&pdev->dev);
+-- pdev_list[pdev_list_cnt++] = pdev;

/*

//"msm_fb"设备的定义在board文件中
@arch/arm/mach-msm/board-xxx.c
static struct platform_device msm_fb_device = {
        .name   = "msm_fb"
        .id     = 0,
        .num_resources  = ARRAY_SIZE(msm_fb_resources),
	//这个resources的mem资源并没有在定义里面直接给出,但是在设备的probe里面却用到了,那么他是哪来的呢?
	.resource       = msm_fb_resources,     //...
        .dev    = {
                .platform_data = &msm_fb_pdata,
        }
};

MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF")
#ifdef CONFIG_MSM_DEBUG_UART
        .phys_io  = MSM_DEBUG_UART_PHYS,
        .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
#endif
        .boot_params = PHYS_OFFSET + 0x100,
        .map_io = msm7x30_map_io,          //msm7x30_map_io()...
        .init_irq = msm7x30_init_irq,
        .init_machine = msm7x30_init,
        .timer = &msm_timer,
MACHINE_END
*/
//msm_fb_resources[0]就是在这里初始化的:
msm7x30_map_io()
+-- msm_shared_ram_phys = 0x00100000;
+-- msm_map_msm7x30_io();
+-- msm7x30_allocate_memory_regions();
    //Request allocation of Hardware accessible PMEM regions at the beginning to make sure they are 
    //allocated in EBI-0. This will allow 7x30 with two mem banks enter the second mem bank into 
    //Self-Refresh State during Idle Power Collapse.
    //The current HW accessible PMEM regions are
    //1. Frame Buffer.
    //   LCDC HW can access msm_fb_resources during Idle-PC.
    //2. Audio
    //   LPA HW can access android_pmem_audio_pdata during Idle-PC.
    +-- size = fb_size ? : MSM_FB_SIZE;
        addr = alloc_bootmem(size);
        msm_fb_resources[0].start = __pa(addr);
        msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;

    +-- size = pmem_audio_size;
        if (size) {
                addr = alloc_bootmem(size);
                android_pmem_audio_pdata.start = __pa(addr);
                android_pmem_audio_pdata.size = size;
        }

    +-- size = gpu_phys_size;
        if (size) {
                addr = alloc_bootmem(size);
                kgsl_resources[1].start = __pa(addr);
                kgsl_resources[1].end = kgsl_resources[1].start + size - 1;
        }

    +-- size = pmem_kernel_ebi1_size;
        if (size) {
                addr = alloc_bootmem_aligned(size, 0x100000);
                android_pmem_kernel_ebi1_pdata.start = __pa(addr);
                android_pmem_kernel_ebi1_pdata.size = size;
        }

    +-- size = pmem_sf_size;
        if (size) {
                addr = alloc_bootmem(size);
                android_pmem_pdata.start = __pa(addr);
                android_pmem_pdata.size = size;
        }

    +-- if machine_is_msm7x30_fluid()
                size = fluid_pmem_adsp_size;
        else
                size = pmem_adsp_size;
        if (size) {
                addr = alloc_bootmem(size);
                android_pmem_adsp_pdata.start = __pa(addr);
                android_pmem_adsp_pdata.size = size;
        }

/*
static struct platform_device *devices[] __initdata = {
    ...
    &msm_fb_device,
    ...
}

static void __init msm7x30_init(void)
+-- platform_add_devices(devices, ARRAY_SIZE(devices));
*/


//"msm_fb"驱动的定义在drivers/video/msm/msm_fb.c文件中:
static struct platform_driver msm_fb_driver = {
        .probe = msm_fb_probe,
        .remove = msm_fb_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
        .suspend = msm_fb_suspend,
        .resume = msm_fb_resume,
#endif
        .shutdown = NULL,
        .driver = {
                   /* Driver name must match the device name added in platform.c. */
                   .name = "msm_fb",
                   .pm = &msm_fb_dev_pm_ops,
                   },
};

//驱动在module_init阶段注册
module_init(msm_fb_init);
int __init 
msm_fb_init(void)
+-- msm_fb_register_driver();        //注册"msm_fb"驱动
+-- root = msm_fb_get_debugfs_root()
+-- msm_fb_debugfs_file_create(root, "msm_fb_msg_printing_level", (u32 *) &msm_fb_msg_level);
+-- msm_fb_debugfs_file_create(root, "mddi_msg_printing_level",   (u32 *) &mddi_msg_level);
+-- msm_fb_debugfs_file_create(root, "msm_fb_debug_enabled",      (u32 *) &msm_fb_debug_enabled);


//msm_fb设备/驱动匹配后 msm_fb_probe()函数被调用
static int msm_fb_probe(struct platform_device *pdev)
+-- if ((pdev->id == 0) && (pdev->num_resources > 0)) {
        msm_fb_pdata = pdev->dev.platform_data;
        fbram_size = pdev->resource[0].end - pdev->resource[0].start + 1;
        fbram_phys = (char *)pdev->resource[0].start;
        fbram = ioremap((unsigned long)fbram_phys, fbram_size);
        if (!fbram) {
            printk(KERN_ERR "fbram ioremap failed!\n");
            return -ENOMEM;
        }
        MSM_FB_INFO("msm_fb_probe:  phy_Addr = 0x%x virt = 0x%x\n",
                    (int)fbram_phys, (int)fbram);
        msm_fb_resource_initialized = 1;
        return 0;
    }
+-- mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); //从driver data中拿到mfd
+-- err = pm_runtime_set_active(&pdev->dev);
+-- mfd->panel_info.frame_count = 0;
+-- mfd->bl_level = mfd->panel_info.bl_max;
+-- mfd->overlay_play_enable = 1;
+-- rc = msm_fb_register(mfd);           //msm_fb_register...
+-- msm_fb_config_backlight(mfd);
+-- pm_runtime_enable(&pdev->dev);
+-- pdev_list[pdev_list_cnt++] = pdev;
+-- msm_fb_create_sysfs(pdev);



static int msm_fb_register(struct msm_fb_data_type *mfd)
+-- struct msm_panel_info *panel_info = &mfd->panel_info;
+-- struct fb_info *fbi = mfd->fbi;
+-- struct fb_fix_screeninfo *fix;
+-- struct fb_var_screeninfo *var;
+-- struct fb_info *fbi = mfd->fbi;
+-- struct fb_fix_screeninfo *fix;
+-- struct fb_var_screeninfo *var;
+-- 初始化fix和var的各个成员

+-- fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram;
+-- fbram += fbram_offset;
+-- fbram_phys += fbram_offset;
+-- fbram_size -= fbram_offset;
+-- fbi->screen_base = fbram;     //screen_base是page aligned的,screen_base就是帧缓存对应的物理内存
+-- fbi->fix.smem_start = (unsigned long)fbram_phys;  //帧缓存的物理地址
+-- memset(fbi->screen_base, 0x0, fix->smem_len);

+-- mfd->op_enable = TRUE;
+-- mfd->panel_power_on = FALSE;

+-- if (mfd->cursor_update) {
        mfd->cursor_buf = dma_alloc_coherent(NULL, MDP_CURSOR_SIZE,
                                             (dma_addr_t *) &mfd->cursor_buf_phys, GFP_KERNEL);
    }
+-- if (mfd->lut_update) {
        ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
    }

+-- register_framebuffer(fbi)    //将framebuffer注册到registered_fb[]数组中去.这样就和帧缓存框架真正联系起来了.

+-- fbram += fix->smem_len;
+-- fbram_phys += fix->smem_len;
+-- fbram_size -= fix->smem_len;

+-- if (!load_565rle_image(INIT_IMAGE_FILE)) ; //这里需要看一看...

+-- if (mfd->panel_info.type != DTV_PANEL) {
        mfd->early_suspend.suspend = msmfb_early_suspend;
        mfd->early_suspend.resume = msmfb_early_resume;
        mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;
        register_early_suspend(&mfd->early_suspend);
    }
+-- root = msm_fb_get_debugfs_root();
+-- sub_name[0] = (char)(mfd->index + 0x30);
+-- sub_name[1] = '\0';
+-- sub_dir = debugfs_create_dir(sub_name, root);
+-- mfd->sub_dir = sub_dir;

+-- msm_fb_debugfs_file_create(sub_dir, "op_enable", (u32 *) &mfd->op_enable);
+-- msm_fb_debugfs_file_create(sub_dir, "panel_power_on", (u32 *) &mfd->panel_power_on);
    ...
+-- switch (mfd->dest) ...
                  probe()            probe()           probe()              probe()
"lcdc_panel_xx" ----------> "lcdc" ----------> "mdp" ----------> "msm_fb" ----------> .
struct msm_fb_data_type {
        __u32 key;
        __u32 index;
        __u32 ref_cnt;
        __u32 fb_page;

        panel_id_type panel;
        struct msm_panel_info panel_info;

        DISP_TARGET dest;
        struct fb_info *fbi;

        boolean op_enable;
        uint32 fb_imgType;
        boolean sw_currently_refreshing;
        boolean sw_refreshing_enable;
        boolean hw_refresh;
#ifdef CONFIG_FB_MSM_OVERLAY
        int overlay_play_enable;
#endif

        MDPIBUF ibuf;
        boolean ibuf_flushed;
        struct timer_list refresh_timer;
        struct completion refresher_comp;

        boolean pan_waiting;
        struct completion pan_comp;
        /* vsync */
        boolean use_mdp_vsync;
        __u32 vsync_gpio;
        __u32 total_lcd_lines;
        __u32 total_porch_lines;
        __u32 lcd_ref_usec_time;
        __u32 refresh_timer_duration;

        struct hrtimer dma_hrtimer;

        boolean panel_power_on;
        struct work_struct dma_update_worker;
        struct semaphore sem;

        struct timer_list vsync_resync_timer;
        boolean vsync_handler_pending;
        struct work_struct vsync_resync_worker;

        ktime_t last_vsync_timetick;

        __u32 *vsync_width_boundary;

        unsigned int pmem_id;
        struct disp_info_type_suspend suspend;

        __u32 channel_irq;

        struct mdp_dma_data *dma;
        void (*dma_fnc) (struct msm_fb_data_type *mfd);
        int (*cursor_update) (struct fb_info *info,
                              struct fb_cursor *cursor);
        int (*lut_update) (struct fb_info *info,
                              struct fb_cmap *cmap);
        int (*do_histogram) (struct fb_info *info,
                              struct mdp_histogram *hist);
        void *cursor_buf;
        void *cursor_buf_phys;

        void *cmd_port;
        void *data_port;
        void *data_port_phys;

        __u32 bl_level;

        struct platform_device *pdev;

        __u32 var_xres;
        __u32 var_yres;
        __u32 var_pixclock;

#ifdef MSM_FB_ENABLE_DBGFS
        struct dentry *sub_dir;
#endif

#ifdef CONFIG_HAS_EARLYSUSPEND
        struct early_suspend early_suspend;
        struct early_suspend mddi_early_suspend;
        struct early_suspend mddi_ext_early_suspend;
#endif
        u32 mdp_fb_page_protection;
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值