本文纯属个人见解,是对前面学习的总结,如有描述不正确的地方还请高手指正~
本文是Android Display部分分析的一部分,描述屏Framebuffer设备注册过程。
QC MSM7xxx/MSM8xxx平台本身就提供了很多接口的屏的支持,每种屏对应一个驱动文件。由于QC MSM平台显示驱动架构做了绝大部分的任务,驱动一块新的屏仅需要做很少许的任务。下面的过程是屏Framebuffer注册过程的分析。
设备资源申请是在MACHINE_DESC中实现的。示例如下:
3463MACHINE_START(MSM8930_CDP, "QCT MSM8930 CDP") 3464 .map_io = msm8930_map_io, 3465 .reserve = msm8930_reserve, 3466 .init_irq = msm8930_init_irq, 3467 .handle_irq = gic_handle_irq, 3468 .timer = &msm_timer, 3469 .init_machine = msm8930_cdp_init, 3470 .init_early = msm8930_allocate_memory_regions, 3471 .init_very_early = msm8930_early_memory, 3472 .restart = msm_restart, 3473MACHINE_END
machine_desc{.init_very_early, .init_early, .init_machine, .restart}, module_init driver的初始化顺序参考Machine_desc & boot & Kernel_init & initcall & module_init
在machine_desc.init中做了许多machine级别设备的注册任务,主要意图是做设备资源分配。该.init函数部分示例代码如下:
static void __init msm8930_cdp_init(void) @ kernel/arch/arm/mach-msm/board-8930.c { … platform_add_devices(common_devices, ARRAY_SIZE(common_devices)); msm8930_init_gpu(); msm8930_init_mmc(); msm8930_init_cam(); msm8930_init_fb(); }
其中,msm8930_cdp_init中与display相干的是msm8930_init_fb()函数,这个函数注册了几个id为0的设备。各主要设备名如下,
“msm_fb” msm framebuffer设备,注意不是linux framebuffer设备,但是有对应关系;
“wfd” wifi显示设备;
“mipi_dsi_cmd_samsung_fwvga” mipi-dsi接口cmd模式LCD屏设备;
“hdmi_msm” HDMI显示器设备;
“mdp” mobile display station显示引擎设备;
“mipi-dsi” MIPI-DSI显示器驱动设备(id破例用了1,可能有的平台两个MIPI-DSI,另外一个id为0);
1168void __init msm8930_init_fb(void) @ kernel/arch/arm/mach-msm/board-8930-display.c 1169{ 1170 platform_device_register(&msm_fb_device); 1171 1172#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL 1173 platform_device_register(&wfd_panel_device); 1174 platform_device_register(&wfd_device); 1175#endif 1176 1178#ifdef CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT 1179 platform_device_register(&mipi_dsi_novatek_panel_device); 1180#endif 1181 1184#ifdef CONFIG_FB_MSM_MIPI_SA77_CMD_FWVGA_PANEL 1185 platform_device_register(&mipi_dsi_cmd_chimei_fwvga_panel_device); 1186 platform_device_register(&mipi_dsi_cmd_samsung_fwvga_panel_device); 1187#endif 1189 1190#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL 1191 platform_device_register(&hdmi_msm_device); 1192#endif 1193 1194 platform_device_register(&mipi_dsi_toshiba_panel_device); 1195 1196 msm_fb_register_device("mdp", &mdp_pdata); 1197 msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata); 1198#ifdef CONFIG_MSM_BUS_SCALING 1199#ifdef CONFIG_FB_MSM_DTV 1200 msm_fb_register_device("dtv", &dtv_pdata); 1201#endif 1202#endif 1203}
因为注册这些设备的意图主要是资源申请和初步初始化设备,所以各设备注册顺序并可有可无。其初始化顺序还与后来的驱动现实注册顺序有关。
首先注册paltform_device msm_fb_device,该设备定义如下:
71static struct resource msm_fb_resources[] = { 72 { 73 .flags = IORESOURCE_DMA, 74 } 75}; 135static struct msm_fb_platform_data msm_fb_pdata = { 136 .detect_client = msm_fb_detect_panel, 137}; 138 139static struct platform_device msm_fb_device = { 140 .name = "msm_fb", 141 .id = 0, 142 .num_resources = ARRAY_SIZE(msm_fb_resources), 143 .resource = msm_fb_resources, 144 .dev.platform_data = &msm_fb_pdata, 145};
然后注册panel设备,定义如下:
845static struct mipi_dsi_panel_platform_data samsung_pdata = { 846 .enable_wled_bl_ctrl = 0x1, 847}; 848 849static struct platform_device mipi_dsi_cmd_samsung_fwvga_panel_device = { 850 .name = "dsi_cmd_samsung_fwvga", 851 .id = 0, 852 .dev = { 853 .platform_data = &samsung_pdata, 854 } 855};
然后症结的注册mdp和mipi-dsi controller.
1749void __init msm_fb_register_device(char *name, void *data) 1750{ 1751 if (!strncmp(name, "mdp", 3)) 1752 msm_register_device(&msm_mdp_device, data); 1753 else if (!strncmp(name, "lcdc", 4)) 1754 msm_register_device(&msm_lcdc_device, data); 1755 else if (!strncmp(name, "mipi_dsi", 8)) 1756 msm_register_device(&msm_mipi_dsi_device, data); 1757#ifdef CONFIG_FB_MSM_TVOUT 1758 else if (!strncmp(name, "tvenc", 5)) 1759 msm_register_device(&msm_tvenc_device, data); 1760 else if (!strncmp(name, "tvout_device", 12)) 1761 msm_register_device(&msm_tvout_device, data); 1762#endif 1763#ifdef CONFIG_MSM_BUS_SCALING 1764 else if (!strncmp(name, "dtv", 3)) 1765 msm_register_device(&msm_dtv_device, data); 1766#endif 1767 else 1768 printk(KERN_ERR "%s: unknown device! %s\n", __func__, name); 1769}
mdp和mipi-dsi设备及寄存器映射和中断需求如下
1484#define MIPI_DSI_HW_BASE 0x04700000 1485#define ROTATOR_HW_BASE 0x04E00000 1486#define TVENC_HW_BASE 0x04F00000 1487#define MDP_HW_BASE 0x05100000 1488 1489static struct resource msm_mipi_dsi_resources[] = { 1490 { 1491 .name = "mipi_dsi", 1492 .start = MIPI_DSI_HW_BASE, 1493 .end = MIPI_DSI_HW_BASE + 0x000F0000 - 1, 1494 .flags = IORESOURCE_MEM, 1495 }, 1496 { 1497 .start = DSI_IRQ, 1498 .end = DSI_IRQ, 1499 .flags = IORESOURCE_IRQ, 1500 }, 1501}; 1502 1503static struct platform_device msm_mipi_dsi_device = { 1504 .name = "mipi_dsi", 1505 .id = 1, 1506 .num_resources = ARRAY_SIZE(msm_mipi_dsi_resources), 1507 .resource = msm_mipi_dsi_resources, 1508}; 1509 1510static struct resource msm_mdp_resources[] = { 1511 { 1512 .name = "mdp", 1513 .start = MDP_HW_BASE, 1514 .end = MDP_HW_BASE + 0x000F0000 - 1, 1515 .flags = IORESOURCE_MEM, 1516 }, 1517 { 1518 .start = INT_MDP, 1519 .end = INT_MDP, 1520 .flags = IORESOURCE_IRQ, 1521 }, 1522}; 1523 1524static struct platform_device msm_mdp_device = { 1525 .name = "mdp", 1526 .id = 0, 1527 .num_resources = ARRAY_SIZE(msm_mdp_resources), 1528 .resource = msm_mdp_resources, 1529};
以上设备注册时,其驱动并未加载,因为machine_desc.init_machine设备注册的arch_initcall是在.initcall3.init中,而module_init driver注册是在.initcall6.init中。等其驱动加载时,在对应的probe函数中,判断设备id,初步初始化设备,保存其资源分配。
此时,以下设备中id为0,mipi-dsi id为1的设备已经注册进系统了。
dsi_cmd_chimei_fwvga.0
dsi_cmd_samsung_fwvga.0
dsi_cmd_samsung_fwvga.1281
dtv.0
dtv.458753
hdmi_msm.0
hdmi_msm.1
mdp.0
mdp.458753
mdp.591105
mdp.655361
mipi_dsi.1
mipi_dsi.591105
mipi_toshiba.0
msm_fb.0
msm_fb.458753
msm_fb.591105
msm_fb.655361
下面描述各驱动注册,各驱动都是module_init的。
msm_fb驱动注册如下
module_init(msm_fb_init); 3898int __init msm_fb_init(void) @ kernel/drivers/video/msm/msm_fb.c 3899{ 3900 int rc = -ENODEV; 3901 3902 if (msm_fb_register_driver()) 3903 return rc; …. } 3705static int msm_fb_register_driver(void) 3706{ 3707 return platform_driver_register(&msm_fb_driver); 3708}
msm_fb_driver驱动定义如下
734static struct platform_driver msm_fb_driver = { 735 .probe = msm_fb_probe, 736 .remove = msm_fb_remove, 737#ifndef CONFIG_HAS_EARLYSUSPEND 738 .suspend = msm_fb_suspend, 739 .resume = msm_fb_resume, 740#endif 741 .shutdown = NULL, 742 .driver = { 743 /* Driver name must match the device name added in platform.c. */ 744 .name = "msm_fb", 745 .pm = &msm_fb_dev_pm_ops, 746 }, 747};
platform_device “msm_fb”的resource[0]是一块DMA内存,是framebuffer内存,但是在资源定义中并没有设置size,而在msm_fb_probe中从其应用可以看到该DMA内存已经分配。其size是在machine的init_early中从bootmem中分配的,比machine级别设备注册要早!
.init_early = msm8930_allocate_memory_regions,
msm8930_allocate_memory_regions(void) @ kernel/arch/arm/mach-msm/board-8930.c
1006static void __init msm8930_allocate_memory_regions(void) 1007{ 1008 msm8930_allocate_fb_region(); 1009}
msm8930_allocate_fb_region() @ kernel/arch/arm/mach-msm/board-8930-display.c
1205void __init msm8930_allocate_fb_region(void) 1206{ 1207 void *addr; 1208 unsigned long size; 1209 1210 size = MSM_FB_SIZE; 1211 addr = alloc_bootmem_align(size, 0x1000); 1212 msm_fb_resources[0].start = __pa(addr); 1213 msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1; 1214 pr_info("allocating %lu bytes at %p (%lx physical) for fb\n", size, addr, __pa(addr)); 1216}
MSM_FB_SIZE宏定义如下,TRIPLE_BUFFER已是主流;对应地SurfaceFlinger中FB layer也会分配有3个buffer。
32#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER 33#define MSM_FB_PRIM_BUF_SIZE \ 34 (roundup((1920 * 1088 * 4), 4096) * 3) /* 4 bpp x 3 pages */ 35#else 36#define MSM_FB_PRIM_BUF_SIZE \ 37 (roundup((1920 * 1088 * 4), 4096) * 2) /* 4 bpp x 2 pages */ 38#endif 39/* Note: must be multiple of 4096 */ 40#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
当”msm_fb”注册时,msm_fb_probe在设备和驱动match后被调用。对于msm_fb_device id=0, 只做fbram保存和ION client创建;这时probe到的设备对应/sys/bus/platform/devices /msm_fb.0。msm_ion_client_create(-1, pdev->name); ”mipi-dsi” driver定义和注册如下 (in kernel/drivers/video/msm/mipi_dsi.c)
55static struct platform_driver mipi_dsi_driver = { 56 .probe = mipi_dsi_probe, 57 .remove = mipi_dsi_remove, 58 .shutdown = NULL, 59 .driver = { 60 .name = "mipi_dsi", 61 }, 62}; 603static int mipi_dsi_register_driver(void) 604{ 605 return platform_driver_register(&mipi_dsi_driver); 606} 607 608static int __init mipi_dsi_driver_init(void) 609{ 610 int ret; 611 612 mipi_dsi_init(); 613 614 ret = mipi_dsi_register_driver(); 615 616 device_initialize(&dsi_dev); 617 618 if (ret) { 619 pr_err("mipi_dsi_register_driver() failed!\n"); 620 return ret; 621 } 622 623 return ret; 624} 625 626module_init(mipi_dsi_driver_init);
“mdp” driver定义和注册如下(in kernel/drivers/video/msm/mdp.c)
2094static struct platform_driver mdp_driver = { 2095 .probe = mdp_probe, 2096 .remove = mdp_remove, 2097#ifndef CONFIG_HAS_EARLYSUSPEND 2098 .suspend = mdp_suspend, 2099 .resume = NULL, 2100#endif 2101 .shutdown = NULL, 2102 .driver = { 2103 /* 2104 * Driver name must match the device name added in 2105 * platform.c. 2106 */ 2107 .name = "mdp", 2108 .pm = &mdp_dev_pm_ops, 2109 }, 2110}; 3001static int mdp_register_driver(void) 3002{ 3003#ifdef CONFIG_HAS_EARLYSUSPEND 3004 early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1; 3005 early_suspend.suspend = mdp_early_suspend; 3006 early_suspend.resume = mdp_early_resume; 3007 register_early_suspend(&early_suspend); 3008#endif 3009 3010 return platform_driver_register(&mdp_driver); 3011} 3012 3013static int __init mdp_driver_init(void) 3014{ 3015 int ret; 3016 3017 mdp_drv_init(); 3018 3019 ret = mdp_register_driver(); 3020 if (ret) { 3021 printk(KERN_ERR "mdp_register_driver() failed!\n"); 3022 return ret; 3023 } 3024 3025#if defined(CONFIG_DEBUG_FS) 3026 mdp_debugfs_init(); 3027#endif 3028 3029 return 0; 3030 3031} 3032 3033module_init(mdp_driver_init);
当真正从屏驱动中添加一块显示设备时,为了让上级设备(“mipi-dsi” “mdp” “msm_fb” “fb”)应用上级设备,高通实现为上级设备创建了每一个上级设备的实例,通过从下到上的设备probe链一级一级向上注册。这时保障从下到上的设备注册顺序就是至关重要的了,probe链做注册来保障这一点。
当然为了达到上级设备应用和管理上级设备的目标,另一种方法是上级设备向上级设备做register,这时要保障上级设备向上级设备注册时,上级设备的用于管理的相干数据结构已经准备好。
下面描述由屏驱动添加屏到注册linux framebuffer设备的流程。
在各自的屏设备注册文件中,会去探测屏,这种探测不是做真正扫描,仅仅是应用设备名字验证一下,以SAMSUNG MIPI DSI CMD屏为例,驱动会应用响应规矩ID注册一块屏。
static int __init mipi_cmd_samsung_fwvga_pt_init(void) @ kernel/drivers/video/msm/mipi_samsung_cmd_fwvga_pt.c { 37 int ret; 38 39 if (msm_fb_detect_client("mipi_cmd_samsung_fwvga")) 40 return 0; …… 88 ret = mipi_samsung_device_register(&pinfo, MIPI_DSI_PRIM, MIPI_DSI_PANEL_QHD_PT); 90 if (ret) 91 pr_err("%s: failed to register device!\n", __func__); 92 93 return ret; 94} 95 96module_init(mipi_cmd_samsung_fwvga_pt_init);
探测函数int msm_fb_detect_client(const char *name)首先应用主屏和外屏名字匹配,匹配不成则应用msm_fd_device.dev.platform .detect_client = msm_fb_detect_panel去匹配。下面欲同时注册SAMSUNG和CHIMEI两块屏设备,当然不能同时detect_panel胜利,应用GPIO管脚配置做了二次匹配。现实不同批次的手机可能用到两块屏中的一种。
然后mipi_samsung_device_register()(对CHIMEI则是mipi_chimei_device_register)注册屏驱动和屏设备。驱动定义和注册具体如下,
358static struct platform_driver this_driver = { 359 .probe = mipi_samsung_lcd_probe, 360 .driver = { 361 .name = "dsi_cmd_samsung_fwvga", 362 }, 363}; 364 365static struct msm_fb_panel_data samsung_panel_data = { 366 .on = mipi_samsung_lcd_on, 367 .off = mipi_samsung_lcd_off, 368 .set_backlight = mipi_samsung_set_backlight, 369}; 373int mipi_samsung_device_register(struct msm_panel_info *pinfo, u32 channel, u32 panel) 375{ 376 struct platform_device *pdev = NULL; 377 int ret; 378 379 if ((channel >= 3) || ch_used[channel]) 380 return -ENODEV; 381 382 ch_used[channel] = TRUE; 383 384 ret = mipi_samsung_lcd_init(); 385 if (ret) { 386 pr_err("mipi_samsung_lcd_init() failed with ret %u\n", ret); 387 return ret; 388 } 389 390 pdev = platform_device_alloc("dsi_cmd_samsung_fwvga", (panel << 8)|channel); 391 if (!pdev) 392 return -ENOMEM; 393 394 samsung_panel_data.panel_info = *pinfo; 395 396 ret = platform_device_add_data(pdev, &samsung_panel_data, 397 sizeof(samsung_panel_data)); 398 if (ret) { 399 printk(KERN_ERR 400 "%s: platform_device_add_data failed!\n", __func__); 401 goto err_device_put; 402 } 403 404 ret = platform_device_add(pdev); 405 if (ret) { 406 printk(KERN_ERR 407 "%s: platform_device_register failed!\n", __func__); 408 goto err_device_put; 409 } 410 411 return 0; 412 413err_device_put: 414 platform_device_put(pdev); 415 return ret; 416} 417 418static int mipi_samsung_lcd_init(void) 419{ 420 421 led_trigger_register_simple("bkl_trigger", &bkl_led_trigger); 422 pr_info("%s: SUCCESS (WLED TRIGGER)\n", __func__); 423 wled_trigger_initialized = 1; 424 425 mipi_dsi_buf_alloc(&samsung_tx_buf, DSI_BUF_SIZE); 426 mipi_dsi_buf_alloc(&samsung_rx_buf, DSI_BUF_SIZE); 427 428 return platform_driver_register(&this_driver); 429}
在mipi_samsung_lcd_init()中注册platform_driver屏驱动,然后分配注册platform_device屏设备;platform_data设置为msm_fb_panel_data向上传递参数并用于上级设备调用控制屏开关和背光。
屏设备注册后,platform_device和platform_driver match, 驱动的probe函数被调用,把参数一级一级向上带,用于设置上级设备参数,向上一级一级注册设备(“mipi-dsi”, “mdp”, “msm_fb”, “framebuffer”)。
一个类似的调用栈如下
------------[ cut here ]------------ WARNING: at /home/CORPUSERS/xp010548/myworkdroid/7x25a/LINUX/kernel/drivers/video/msm/msm_fb.c:1221 msm_fb_probe+0xf4/0xcbc() msm_fb_probe Modules linked in: [<c003fe0c>] (unwind_backtrace+0x0/0x12c) from [<c00adccc>] (warn_slowpath_common+0x4c/0x64) [<c00adccc>] (warn_slowpath_common+0x4c/0x64) from [<c00add64>] (warn_slowpath_fmt+0x2c/0x3c) [<c00add64>] (warn_slowpath_fmt+0x2c/0x3c) from [<c0223c44>] (msm_fb_probe+0xf4/0xcbc) [<c0223c44>] (msm_fb_probe+0xf4/0xcbc) from [<c026e624>] (platform_drv_probe+0x18/0x1c) [<c026e624>] (platform_drv_probe+0x18/0x1c) from [<c026d354>] (driver_probe_device+0x144/0x264) [<c026d354>] (driver_probe_device+0x144/0x264) from [<c026c78c>] (bus_for_each_drv+0x48/0x84) [<c026c78c>] (bus_for_each_drv+0x48/0x84) from [<c026d5d0>] (device_attach+0x74/0xa0) [<c026d5d0>] (device_attach+0x74/0xa0) from [<c026c5a4>] (bus_probe_device+0x24/0x40) [<c026c5a4>] (bus_probe_device+0x24/0x40) from [<c026b4c4>] (device_add+0x3f0/0x570) [<c026b4c4>] (device_add+0x3f0/0x570) from [<c026ec54>] (platform_device_add+0x13c/0x1a0) [<c026ec54>] (platform_device_add+0x13c/0x1a0) from [<c02264b4>] (mdp_probe+0x828/0x940) [<c02264b4>] (mdp_probe+0x828/0x940) from [<c026e624>] (platform_drv_probe+0x18/0x1c) [<c026e624>] (platform_drv_probe+0x18/0x1c) from [<c026d354>] (driver_probe_device+0x144/0x264) [<c026d354>] (driver_probe_device+0x144/0x264) from [<c026c78c>] (bus_for_each_drv+0x48/0x84) [<c026c78c>] (bus_for_each_drv+0x48/0x84) from [<c026d5d0>] (device_attach+0x74/0xa0) [<c026d5d0>] (device_attach+0x74/0xa0) from [<c026c5a4>] (bus_probe_device+0x24/0x40) [<c026c5a4>] (bus_probe_device+0x24/0x40) from [<c026b4c4>] (device_add+0x3f0/0x570) [<c026b4c4>] (device_add+0x3f0/0x570) from [<c026ec54>] (platform_device_add+0x13c/0x1a0) [<c026ec54>] (platform_device_add+0x13c/0x1a0) from [<c023db98>] (mipi_dsi_probe+0x514/0x5d0) [<c023db98>] (mipi_dsi_probe+0x514/0x5d0) from [<c026e624>] (platform_drv_probe+0x18/0x1c) [<c026e624>] (platform_drv_probe+0x18/0x1c) from [<c026d354>] (driver_probe_device+0x144/0x264) [<c026d354>] (driver_probe_device+0x144/0x264) from [<c026c78c>] (bus_for_each_drv+0x48/0x84) [<c026c78c>] (bus_for_each_drv+0x48/0x84) from [<c026d5d0>] (device_attach+0x74/0xa0) [<c026d5d0>] (device_attach+0x74/0xa0) from [<c026c5a4>] (bus_probe_device+0x24/0x40) [<c026c5a4>] (bus_probe_device+0x24/0x40) from [<c026b4c4>] (device_add+0x3f0/0x570) [<c026b4c4>] (device_add+0x3f0/0x570) from [<c026ec54>] (platform_device_add+0x13c/0x1a0) [<c026ec54>] (platform_device_add+0x13c/0x1a0) from [<c02223b8>] (msm_fb_add_device+0x150/0x1b4) [<c02223b8>] (msm_fb_add_device+0x150/0x1b4) from [<c051e830>] (mipi_himax_lcd_probe+0x38/0x108) [<c051e830>] (mipi_himax_lcd_probe+0x38/0x108) from [<c026e624>] (platform_drv_probe+0x18/0x1c) [<c026e624>] (platform_drv_probe+0x18/0x1c) from [<c026d354>] (driver_probe_device+0x144/0x264) [<c026d354>] (driver_probe_device+0x144/0x264) from [<c026c78c>] (bus_for_each_drv+0x48/0x84) [<c026c78c>] (bus_for_each_drv+0x48/0x84) from [<c026d5d0>] (device_attach+0x74/0xa0) [<c026d5d0>] (device_attach+0x74/0xa0) from [<c026c5a4>] (bus_probe_device+0x24/0x40) [<c026c5a4>] (bus_probe_device+0x24/0x40) from [<c026b4c4>] (device_add+0x3f0/0x570) [<c026b4c4>] (device_add+0x3f0/0x570) from [<c026ec54>] (platform_device_add+0x13c/0x1a0) [<c026ec54>] (platform_device_add+0x13c/0x1a0) from [<c02409ec>] (mipi_himax_device_register+0x7c/0xc0) [<c02409ec>] (mipi_himax_device_register+0x7c/0xc0) from [<c001ac34>] (mipi_cmd_himax_hvga_pt_init+0x148/0x180) [<c001ac34>] (mipi_cmd_himax_hvga_pt_init+0x148/0x180) from [<c0034388>] (do_one_initcall+0x94/0x164) [<c0034388>] (do_one_initcall+0x94/0x164) from [<c00083d8>] (kernel_init+0x98/0x144) [<c00083d8>] (kernel_init+0x98/0x144) from [<c003b0d0>] (kernel_thread_exit+0x0/0x8) ---[ end trace 65f8ea860415c051 ]---
下面考察设备probe链。
311static int __devinit mipi_samsung_lcd_probe(struct platform_device *pdev) 312{ ….. 338 current_pdev = msm_fb_add_device(pdev); 339 340 if (current_pdev) { 341 mfd = platform_get_drvdata(current_pdev); 342 if (!mfd) 343 return -ENODEV; 344 if (mfd->key != MFD_KEY) 345 return -EINVAL; 346 347 mipi = &mfd->panel_info.mipi; 348 349 if (phy_settings != NULL) 350 mipi->dsi_phy_db = phy_settings; 351 352 if (dlane_swap) 353 mipi->dlane_swap = dlane_swap; 354 } 355 return 0; 356}
msm_fb_add_device做如下事件:
调用struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata, u32 type, u32 id)函数分配platform_device “mipi-dsi.type_devid”并设置其platform_data为msm_fb_panel_data。
以额定msm_fb_data_type结构分配framebuffer。
注册”mipi-dsi”设备platform_device_add(this_dev)。
“mipi-dsi”设备和驱动停止attach, match后,“mipi-dsi” driver的probe被调用到。
static int mipi_dsi_probe(struct platform_device *pdev) @ kernel/drivers/video/msm/mipi_dsi.c做如下事件(此次的设备ID是真正实例的了,不是1了):
分配”mdp”设备实例并设置其数据,设置”mipi-dsi”设备操纵函数,用于向下操纵一级一级设备;
继续设置linux framebuffer的参数;
根据屏分辨率设置mipi-dsi任务频率;
注册该”mdp”设备实例;
“mdp”设备和驱动停止attach, match后,“mdp” driver的probe被调用到。
static int mdp_probe(struct platform_device *pdev) @ kernel/drivers/video/msm/mdp.c
分配”msm_fb”实例并设置其数据;
配置”mdp”任务模式;
注册”msm_fb”实例;
“msm_fb”设备和驱动停止attach, match后,“msm_fb” driver的probe被调用到。
static int msm_fb_probe(struct platform_device *pdev) @ kernel/drivers/video/msm/msm_fb.c
调用msm_fb_register设置linux framebuffer并register_framebuffer。
至此,系统中相干设备如下:
dsi_cmd_chimei_fwvga.0
dsi_cmd_samsung_fwvga.0
dsi_cmd_samsung_fwvga.1281 -> mipi_dsi.591105 -> mdp.591105 -> msm_fb.591105 -> fbx
dtv.0
dtv.458753 -> mdp.458753 -> msm_fb.458753 -> fbx
hdmi_msm.0
hdmi_msm.1 -> mdp.655361 -> msm_fb.655361 -> fbx (hdmi)
mdp.0
mipi_dsi.1
mipi_toshiba.0
msm_fb.0
Framebuffer设备注册后,应用FBIOCPUT_VSCREEN或FBIOCPAN_DISPLAY,驱动都市应用msmfb_pan_display停止响应显示,由于涉及到MDP,另文分析。
[END]
文章结束给大家分享下程序员的一些笑话语录: IT业众生相
第一级:神人,天资过人而又是技术狂热者同时还拥有过人的商业头脑,高瞻远瞩,技术过人,大器也。如丁磊,求伯君。
第二级:高人,有天赋,技术过人但没有过人的商业头脑,通常此类人不是顶尖黑客就是技术总监之流。
第三级:牛人,技术精湛,熟悉行业知识,敢于创新,有自己的公司和软件产品。
第四级:工头,技术精湛,有领导团队的能力,此类人大公司项目经理居多。
第五级:技术工人,技术精湛,熟悉行业知识但领导能力欠加,此类人大多为系分人员或资深程序员,基本上桀骜不逊,自视清高,不愿于一般技术人员为伍,在论坛上基本以高手面目出现。
第六级:熟练工人,技术有广度无深度,喜欢钻研但浅尝辄止。此类人大多为老程序员,其中一部分喜欢利用工具去查找网上有漏洞的服务器,干点坏事以获取成绩感。如果心情好,在论坛上他们会回答菜鸟的大部分问题。此级别为软件业苦力的重要组成部分。
第七级:工人,某些技术较熟练但缺乏深度和广度,此类人大多为程序员级别,经常在论坛上提问偶尔也回答菜鸟的问题。为软件产业苦力的主要组成部分。
第八级:菜鸟,入门时间不长,在论坛上会反复提问很初级的问题,有一种唐僧的精神。虽然招人烦但基本很可爱。只要认真钻研,一两年后就能升级到上一层。
第九级:大忽悠,利用中国教育的弊病,顶着一顶高学历的帽子,在小公司里混个软件部经理,设计不行,代码不行,只会胡乱支配下属,拍领导马屁,在领导面前胡吹海侃,把自己打扮成技术高手的模样。把勾心斗角的办公室文化引入技术部门,实在龌龊!
第十级:驴或傻X,会写SELECT语句就说自己精通ORALCE,连寄存器有几种都不知道就说自己懂汇编,建议全部送到日本当IT产业工人,挣了日本人的钱还严重打击日本的软件业!
--------------------------------- 原创文章 By
设备和注册
---------------------------------