QCom MSM平臺顯示屏Framebuffer設備註冊過程
本文是Android Display部分分析的一部分,描述屏Framebuffer設備註冊過程。
QC MSM7xxx/MSM8xxx平臺本身就提供了很多介面的屏的支援,每種屏對應一個驅動檔案。由於QC MSM平臺顯示驅動架構做了絕大部分的工作,驅動一塊新的屏僅需要做很少量的工作。下面的過程是屏Framebuffer註冊過程的分析。
裝置資源申請是在MACHINE_DESC中實現的。示例如下:
[cpp] view plain copy print?- 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
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.init中做了許多machine級別裝置的註冊工作,主要意圖是做裝置資源分配。該.init函式部分示例程式碼如下:
- <span style="font-size:12px;">staticvoid __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();
- }</span>
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);
[cpp] view plain copy print?- <span style="font-size:12px;">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}</span>
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,該裝置定義如下:
[cpp] view plain copy print?- <span style="font-size:12px;">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};</span>
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裝置,定義如下:
[cpp] view plain copy print?- <span style="font-size:12px;">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};</span>
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.
[cpp] view plain copy print?- <span style="font-size:12px;">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 elseif (!strncmp(name, "lcdc", 4))
- 1754 msm_register_device(&msm_lcdc_device, data);
- 1755 elseif (!strncmp(name, "mipi_dsi", 8))
- 1756 msm_register_device(&msm_mipi_dsi_device, data);
- 1757#ifdef CONFIG_FB_MSM_TVOUT
- 1758 elseif (!strncmp(name, "tvenc", 5))
- 1759 msm_register_device(&msm_tvenc_device, data);
- 1760 elseif (!strncmp(name, "tvout_device", 12))
- 1761 msm_register_device(&msm_tvout_device, data);
- 1762#endif
- 1763#ifdef CONFIG_MSM_BUS_SCALING
- 1764 elseif (!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}</span>
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裝置及暫存器對映和中斷需求如下
[cpp] view plain copy print?- <span style="font-size:12px;">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};</span>
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驅動註冊如下
[cpp] view plain copy print?- <span style="font-size:12px;">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}</span>
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驅動定義如下
[cpp] view plain copy print?- <span style="font-size:12px;">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};</span>
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
[cpp] view plain copy print?- 1006static void __init msm8930_allocate_memory_regions(void)
- 1007{
- 1008 msm8930_allocate_fb_region();
- 1009}
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}
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。
[cpp] view plain copy print?- <span style="font-size:12px;">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)</span>
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)
- <span style="font-size:12px;">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);</span>
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)
- <span style="font-size:12px;">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);</span>
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註冊一塊屏。
- <span style="font-size:12px;">staticint __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);</span>
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)註冊屏驅動和屏裝置。驅動定義和註冊具體如下,
- <span style="font-size:12px;">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}</span>