我们可以通过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框架中了。