您的位置:首页 > Web前端

QCom MSM平台显示屏Framebuffer设备注册过程

2014-07-31 10:20 225 查看
本文是Android Display部分分析的一部分,描述屏Framebuffer设备注册过程。

QC MSM7xxx/MSM8xxx平台本身就提供了很多接口的屏的支持,每种屏对应一个驱动文件。由于QC MSM平台显示驱动架构做了绝大部分的工作,驱动一块新的屏仅需要做很少量的工作。下面的过程是屏Framebuffer注册过程的分析。

设备资源申请是在MACHINE_DESC中实现的。示例如下:

[cpp] view
plaincopy

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函数部分示例代码如下:

[cpp] view
plaincopy

<span style="font-size:12px;">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();

}</span>

其中,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
plaincopy

<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>

因为注册这些设备的意图主要是资源申请和初步初始化设备,所以各设备注册顺序并无关紧要。其初始化顺序还与后来的驱动实际注册顺序有关。

首先注册paltform_device msm_fb_device,该设备定义如下:

[cpp] view
plaincopy

<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>

然后注册panel设备,定义如下:

[cpp] view
plaincopy

<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>

然后关键的注册mdp和mipi-dsi controller.

[cpp] view
plaincopy

<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 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}</span>

mdp和mipi-dsi设备及寄存器映射和中断需求如下

[cpp] view
plaincopy

<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>

以上设备注册时,其驱动并未加载,因为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
plaincopy

<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>

msm_fb_driver驱动定义如下

[cpp] view
plaincopy

<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>

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
plaincopy

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

[cpp] view
plaincopy

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
plaincopy

<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>

当”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)

[cpp] view
plaincopy

<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>

“mdp” driver定义和注册如下(in kernel/drivers/video/msm/mdp.c)

[cpp] view
plaincopy

<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>

当真正从屏驱动中添加一块显示设备时,为了让上级设备(“mipi-dsi” “mdp” “msm_fb” “fb”)使用下级设备,高通实现为下级设备创建了每个上级设备的实例,通过从下到上的设备probe链一级一级向上注册。这时保证从下到上的设备注册顺序就是至关重要的了,probe链做注册来保证这一点。

当然为了达到上级设备使用和管理下级设备的目标,另一种方法是下级设备向上级设备做register,这时要保证下级设备向上级设备注册时,上级设备的用于管理的相关数据结构已经准备好。

下面描述由屏驱动添加屏到注册linux framebuffer设备的流程。

在各自的屏设备注册文件中,会去探测屏,这种探测不是做真正扫描,仅仅是使用设备名字验证一下,以SAMSUNG MIPI DSI CMD屏为例,驱动会使用相应规则ID注册一块屏。

[cpp] view
plaincopy

<span style="font-size:12px;">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);</span>

探测函数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)注册屏驱动和屏设备。驱动定义和注册具体如下,

[cpp] view
plaincopy

<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>

在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”)。

一个类似的调用栈如下

[plain] view
plaincopy

<span style="font-size:12px;">------------[ 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 ]---</span>

下面考察设备probe链。

[cpp] view
plaincopy

<span style="font-size:12px;">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}</span>

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]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: