imx8 kernel drm source trace

45 篇文章 13 订阅
17 篇文章 0 订阅

1. imx8 DRM 架构入门向导

设备树中的有个节点:

display-subsystem {
				compatible = "fsl,imx-display-subsystem";
				ports = <&lcdif_disp0>;
			};

它是drm 框架中的master,负责将各个drm 组件管理起来。

1.1 drm 的master

imx-drm-core.c 是master 的实现:

static const struct component_master_ops imx_drm_ops = {
	.bind = imx_drm_bind,
	.unbind = imx_drm_unbind,
};

他负责把绑定所有drm 组件。

1.2 drm 的crtc & plane

lcdif-crtc.c

static const struct component_ops lcdif_crtc_ops = {
	.bind   = lcdif_crtc_bind,
	.unbind = lcdif_crtc_unbind,
};

lcdif_crtc_bind实现了lcdif controller 层级的控制类API & plane。

1.3 drm encoder & connector

sec_mipi_dsim-imx.c

static int imx_sec_dsim_bind(struct device *dev, struct device *master,
			     void *data)
{
	.........
	encoder = &dsim_dev->encoder;
	ret = imx_drm_encoder_parse_of(drm_dev, encoder, np);
	if (ret)
		return ret;

	drm_encoder_helper_add(encoder, &imx_sec_dsim_encoder_helper_funcs);

	...........

	ret = drm_encoder_init(drm_dev, encoder,
			       &imx_sec_dsim_encoder_funcs,
			       DRM_MODE_ENCODER_DSI, dev_name(dev));
	if (ret)
		return ret;

	.......
	/* bind sec dsim bridge */
	ret = sec_mipi_dsim_bind(dev, master, data, encoder, res, irq, pdata);
	if (ret) {
		............
		return ret;
	}

	.............
}

static const struct component_ops imx_sec_dsim_ops = {
	.bind	= imx_sec_dsim_bind,
	.unbind	= imx_sec_dsim_unbind,
};

mipi-dsi 层级的控制api。sec_mipi_dsim_bind 是一个重要的函数,它里面将encoder 和 connector 进行绑定,同时将connector 和panel 进行了绑定。

1.4 drm panel

panel-simple.c or panel-xxx.c

static const struct drm_panel_funcs panel_simple_funcs = {
	.disable = panel_simple_disable,
	.unprepare = panel_simple_unprepare,
	.prepare = panel_simple_prepare,
	.enable = panel_simple_enable,
	.get_modes = panel_simple_get_modes,
	.get_timings = panel_simple_get_timings,
};

太熟悉了,好好看看就对了。

2. DRM 使能显示设备的API:

drm_atomic_helper_commit_modeset_enables

sec_mipi_dsim_bridge_enable 的调用连:

Workqueue: events deferred_probe_work_func
[    3.991709] Call trace:
[    3.991715]  dump_backtrace+0x0/0x140
[    3.991718]  show_stack+0x14/0x20
[    3.991725]  dump_stack+0xb4/0x114
[    3.991731]  sec_mipi_dsim_bridge_enable+0x364/0x478
[    3.991737]  drm_atomic_bridge_enable+0x4c/0x68
[    3.991742]  drm_atomic_helper_commit_modeset_enables+0x11c/0x230
[    3.991748]  lcdif_drm_atomic_commit_tail+0x2c/0x68
[    3.991752]  commit_tail+0x9c/0x138
[    3.991756]  drm_atomic_helper_commit+0xc8/0x140
[    3.991760]  drm_atomic_commit+0x48/0x58
[    3.991765]  drm_client_modeset_commit_atomic.isra.0+0x174/0x1f8
[    3.991768]  drm_client_modeset_commit_force+0x58/0x190
[    3.991774]  drm_fb_helper_restore_fbdev_mode_unlocked+0x70/0xd0
[    3.991778]  drm_fb_helper_set_par+0x2c/0x58
[    3.991783]  fbcon_init+0x3a4/0x508
[    3.991787]  visual_init+0xac/0x100
[    3.991791]  do_bind_con_driver+0x1cc/0x3a0
[    3.991794]  do_take_over_console+0x13c/0x1f8
[    3.991798]  do_fbcon_takeover+0x6c/0xd8
[    3.991801]  fbcon_fb_registered+0xf8/0x108
[    3.991809]  register_framebuffer+0x1e8/0x330
[    3.991812]  __drm_fb_helper_initial_config_and_unlock+0x2d0/0x470
[    3.991816]  drm_fbdev_client_hotplug+0xd4/0x188
[    3.991819]  drm_fbdev_generic_setup+0x98/0x140
[    3.991823]  imx_drm_bind+0x100/0x150
[    3.991826]  try_to_bring_up_master+0x164/0x1c8
[    3.991829]  __component_add+0xa0/0x168
[    3.991834]  component_add+0x10/0x18
[    3.991839]  imx_sec_dsim_probe+0x4c/0x70
[    3.991846]  platform_drv_probe+0x50/0xa0
[    3.991850]  really_probe+0xd4/0x318
[    3.991854]  driver_probe_device+0x54/0xe8
[    3.991861]  __device_attach_driver+0x80/0xb8
[    3.991867]  bus_for_each_drv+0x74/0xc0
[    3.991871]  __device_attach+0xe8/0x148
[    3.991878]  device_initial_probe+0x10/0x18
[    3.991884]  bus_probe_device+0x90/0x98
[    3.991888]  deferred_probe_work_func+0x64/0x98
[    3.991895]  process_one_work+0x198/0x320
[    3.991899]  worker_thread+0x1f0/0x420
[    3.991903]  kthread+0x138/0x158
[    3.991907]  ret_from_fork+0x10/0x1c

对这一段代码进行描述下:

	/* mipi dsi host needs to be registered before bridge attach, since:
	 * 1. Have Panel
	 *    The 'mipi_dsi_host_register' will allocate a mipi_dsi_device
	 *    if the dsi host node has a panel child node in DTB. And dsi
	 *    host ->attach() will be called in panel's probe().
	 *
	 * 2. Have Bridge
	 *    The dsi host ->attach() will be called through the below
	 *    'drm_bridge_attach()' which will attach next bridge in a
	 *    chain.
	 */
	ret = mipi_dsi_host_register(&dsim->dsi_host);
	if (ret) {
		dev_err(dev, "Unable to register mipi dsi host: %d\n", ret);
		return ret;
	}

	dsim->bridge = bridge;
	bridge->driver_private = dsim;
	bridge->funcs = &sec_mipi_dsim_bridge_funcs;
	bridge->of_node = dev->of_node;
	bridge->encoder = encoder;

	/* attach sec dsim bridge and its next bridge if exists */
	ret = drm_bridge_attach(encoder, bridge, NULL);
	if (ret) {
		dev_err(dev, "Failed to attach bridge: %s\n", dev_name(dev));

		/* no bridge exists, so defer probe to wait
		 * panel driver loading
		 */
		if (ret != -EPROBE_DEFER) {
			for_each_available_child_of_node(dev->of_node, node) {
				/* skip nodes without reg property */
				if (!of_find_property(node, "reg", NULL))
					continue;

				/* error codes only ENODEV or EPROBE_DEFER */
				dsim->panel = of_drm_find_panel(node);
				if (!IS_ERR(dsim->panel))
					goto panel;

				ret = PTR_ERR(dsim->panel);
			}
		}

		mipi_dsi_host_unregister(&dsim->dsi_host);
		return ret;
	}

panel:
	if (dsim->panel) {

如果存在panel,第一次调用drm_bridge_attach会失败,因为没有子bridge,会返回EPROBE_DEFER的错误,第二次probe,这时panel已经attach, drm_bridge_attach 会调用成功,从而完成sec_mipi_dsim桥与encoder的attach。
那么panel 是何时attach 的呢?
当该函数调用mipi_dsi_host_register 时,产生了一个device注册进内核,该device 会和panel-simple.c 中的panel_simple_dsi_driver 进行匹配,从而调用他的probe 函数:

static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
{
	.......
	err = mipi_dsi_attach(dsi);
	if (err) {
		struct panel_simple *panel = dev_get_drvdata(&dsi->dev);

		drm_panel_remove(&panel->base);
	}

	return err;
}

mipi_dsi_attach 又会回掉原来host api 的attach 函数sec_mipi_dsim_host_attach。让我们来看下这个函数的实现:

static int sec_mipi_dsim_host_attach(struct mipi_dsi_host *host,
				     struct mipi_dsi_device *dsi)
{
	......
	if (!dsim->next) {
		/* 'dsi' must be panel device */
		panel = of_drm_find_panel(dsi->dev.of_node);

		if (!panel) {
			dev_err(dev, "refuse unknown dsi device attach\n");
			WARN_ON(!panel);
			return -ENODEV;
		}

		/* Don't support multiple panels */
		if (dsim->panel && panel && dsim->panel != panel) {
			dev_err(dev, "don't support multiple panels\n");
			return -EBUSY;
		}

		dsim->panel = panel;
	}

	........
}

在这里为dsim->panel设定了直。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值