DRM入口之drm__XXXX_init

我们可以通过drm__XXXX_init系列接口完成DRM框架相关组件的初始化和注册。以drm_encoder_init函数为例:

drm_encoder_init 函数的作用是初始化DRM框架中的编码器(encoder)对象。编码器是显示系统中的一部分,它的作用是接收CRTC(Cathode Ray Tube Controller)输出的图像信号,并将其转换成适合特定连接器(connector)的信号格式,比如HDMI、DVI、DisplayPort等。这个转换过程可能包括信号编码和格式转换。

drm_encoder_init 函数中,会设置编码器的各个字段,包括但不限于:

  • dev:指向其所属的DRM设备。
  • name:编码器的名称。
  • encoder_type:编码器的类型,比如 DRM_MODE_ENCODER_TMDS 用于DVI和HDMI。
  • possible_crtcs:可能连接到该编码器的CRTC的位掩码。
  • funcs:指向编码器控制函数的指针,这些函数用于对编码器进行各种操作,如 reset 和 destroy

此外,drm_encoder_init 函数还会将编码器对象添加到DRM设备的相关列表中,使其成为显示配置的一部分。编码器初始化完成后,可以通过DRM提供的API进行进一步的配置和管理,例如设置模式(mode setting)、使能或禁用(enabling or disabling)等操作。

具体的代码流程:

static int sprd_dsi_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct sprd_dsi *dsi;

	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
	if (!dsi)
		return -ENOMEM;

	dev_set_drvdata(dev, dsi);

	dsi->host.ops = &sprd_dsi_host_ops;    // step1
	dsi->host.dev = dev;

	return mipi_dsi_host_register(&dsi->host);
}

static const struct mipi_dsi_host_ops sprd_dsi_host_ops = {
	.attach = sprd_dsi_host_attach,    // step
	.transfer = sprd_dsi_host_transfer,
};

static int sprd_dsi_host_attach(struct mipi_dsi_host *host,
				struct mipi_dsi_device *slave)
{
	struct sprd_dsi *dsi = host_to_dsi(host);
	struct dsi_context *ctx = &dsi->ctx;

	dsi->slave = slave;

	if (slave->mode_flags & MIPI_DSI_MODE_VIDEO)
		ctx->work_mode = DSI_MODE_VIDEO;
	else
		ctx->work_mode = DSI_MODE_CMD;

	if (slave->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
		ctx->burst_mode = VIDEO_BURST_WITH_SYNC_PULSES;
	else if (slave->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
		ctx->burst_mode = VIDEO_NON_BURST_WITH_SYNC_PULSES;
	else
		ctx->burst_mode = VIDEO_NON_BURST_WITH_SYNC_EVENTS;

	return component_add(host->dev, &dsi_component_ops);    // step3
}

static const struct component_ops dsi_component_ops = {
	.bind	= sprd_dsi_bind,    // step4
	.unbind	= sprd_dsi_unbind,
};

static int sprd_dsi_bind(struct device *dev, struct device *master, void *data)
{
	struct drm_device *drm = data;
	struct sprd_dsi *dsi = dev_get_drvdata(dev);
	int ret;

	dsi->drm = drm;

	ret = sprd_dsi_encoder_init(dsi, dev);    // step5
	if (ret)
		return ret;

	ret = sprd_dsi_bridge_init(dsi, dev);
	if (ret)
		return ret;

	ret = sprd_dsi_context_init(dsi, dev);
	if (ret)
		return ret;

	return 0;
}

static int sprd_dsi_encoder_init(struct sprd_dsi *dsi,
				 struct device *dev)
{
	struct drm_encoder *encoder = &dsi->encoder;
	u32 crtc_mask;
	int ret;

	crtc_mask = drm_of_find_possible_crtcs(dsi->drm, dev->of_node);
	if (!crtc_mask) {
		drm_err(dsi->drm, "failed to find crtc mask\n");
		return -EINVAL;
	}

	drm_dbg(dsi->drm, "find possible crtcs: 0x%08x\n", crtc_mask);

	encoder->possible_crtcs = crtc_mask;
	ret = drm_encoder_init(dsi->drm, encoder, &sprd_encoder_funcs,
			       DRM_MODE_ENCODER_DSI, NULL);    //   6
	if (ret) {
		drm_err(dsi->drm, "failed to init dsi encoder\n");
		return ret;
	}

	drm_encoder_helper_add(encoder, &sprd_encoder_helper_funcs);

	return 0;
}

int drm_encoder_init(struct drm_device *dev,
		     struct drm_encoder *encoder,
		     const struct drm_encoder_funcs *funcs,
		     int encoder_type, const char *name, ...)
{
	va_list ap;
	int ret;

	WARN_ON(!funcs->destroy);

	va_start(ap, name);
	ret = __drm_encoder_init(dev, encoder, funcs, encoder_type, name, ap);    // step7
	va_end(ap);

	return ret;
}

__printf(5, 0)
static int __drm_encoder_init(struct drm_device *dev,
			      struct drm_encoder *encoder,
			      const struct drm_encoder_funcs *funcs,
			      int encoder_type, const char *name, va_list ap)
{
	int ret;

	/* encoder index is used with 32bit bitmasks */
	if (WARN_ON(dev->mode_config.num_encoder >= 32))
		return -EINVAL;

	ret = drm_mode_object_add(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);    // step8
	if (ret)
		return ret;

	encoder->dev = dev;
	encoder->encoder_type = encoder_type;
	encoder->funcs = funcs;
	if (name) {
		encoder->name = kvasprintf(GFP_KERNEL, name, ap);
	} else {
		encoder->name = kasprintf(GFP_KERNEL, "%s-%d",
					  drm_encoder_enum_list[encoder_type].name,
					  encoder->base.id);
	}
	if (!encoder->name) {
		ret = -ENOMEM;
		goto out_put;
	}

	INIT_LIST_HEAD(&encoder->bridge_chain);
	list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
	encoder->index = dev->mode_config.num_encoder++;

out_put:
	if (ret)
		drm_mode_object_unregister(dev, &encoder->base);

	return ret;
}

这样经过Step1 ~Step8 ,drm encoder(DSI)就被注册进DRM框架中了。

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是 `rockchip_drm_init` 函数的代码框图及详细说明: ```mermaid graph TB A[rockchip_drm_init] --> B[drm_dev_init] B --> C[drm_mode_config_init] B --> D[drm_vblank_init] A --> E[rockchip_drm_encoder_init] A --> F[rockchip_drm_connector_init] A --> G[rockchip_drm_crtc_init] A --> H[drm_irq_install] A --> I[drm_dev_register] subgraph 编码器初始化 E --> E1[HDMI编码器初始化] E --> E2[LVDS编码器初始化] E --> E3[DP编码器初始化] end subgraph 连接器初始化 F --> F1[HDMI连接器初始化] F --> F2[LVDS连接器初始化] F --> F3[DP连接器初始化] end subgraph CRTC初始化 G --> G1[HDMI CRTC初始化] G --> G2[LVDS CRTC初始化] G --> G3[DP CRTC初始化] end ``` 详细说明如下: 1. `rockchip_drm_init` 函数首先调用 `drm_dev_init` 函数来初始化 DRM 设备结构体 `drm_device`。该函数会创建并初始化一个 `drm_device` 结构体,并为其分配设备节点和设备文件操作集等资源。 2. 接着,`rockchip_drm_init` 函数调用 `drm_mode_config_init` 函数来初始化 `drm_device` 中的 `mode_config` 数据结构,该结构体用于管理显示模式信息。该函数会创建并初始化一个 `drm_mode_config` 结构体,并为其分配显示模式信息等资源。 3. `rockchip_drm_init` 函数接着调用 `drm_vblank_init` 函数来初始化 `drm_device` 中的垂直同步信号(VBlank)管理器。该管理器用于处理垂直同步信号相关的事件,例如垂直同步中断和垂直同步定时器。 4. `rockchip_drm_init` 函数接着调用 `rockchip_drm_encoder_init` 函数来初始化所有的编码器。该函数会遍历所有支持的编码器,并分别调用对应的初始化函数来初始化编码器相关的数据结构。 5. `rockchip_drm_init` 函数接着调用 `rockchip_drm_connector_init` 函数来初始化所有的连接器。该函数会遍历所有支持的连接器,并分别调用对应的初始化函数来初始化连接器相关的数据结构。 6. `rockchip_drm_init` 函数接着调用 `rockchip_drm_crtc_init` 函数来初始化所有的 CRTC。该函数会遍历所有支持的 CRTC,并分别调用对应的初始化函数来初始化 CRTC 相关的数据结构。 7. `rockchip_drm_init` 函数接着调用 `drm_irq_install` 函数来注册中断处理程序。该函数会向内核注册一个中断处理函数,用于处理显示器相关的中断事件。 8. 最后,`rockchip_drm_init` 函数调用 `drm_dev_register` 函数来注册 DRM 设备。该函数会创建 `/dev/dri/cardX` 设备文件,并将其挂载到文件系统中,以便用户空间程序可以使用标准的文件操作接口来访问 DRM 设备。 需要注意的是,上述代码框图只是对 `rockchip_drm_init` 函数的主要流程进行了概括,实际上该函数还包括了一些错误处理、内存释放等操作。在实际使用中,需要仔细阅读该函数的源代码,以便了解其具体实现和细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值