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框架中了。

<think>嗯,用户现在遇到了一个问题,他的AMD显卡在内核启动后,用lspci看不到驱动信息。之前他问过关于amdgpu报错的问题,现在可能是相关的后续问题。我需要先分析可能的原因,然后给出解决方案。 首先,用户提到使用lspci无法打印显卡驱动信息,这可能意味着驱动没有正确加载或者未被内核识别。可能的原因包括内核配置中AMDGPU驱动未启用、固件缺失,或者内核模块未正确编译和加载。 回想之前的对话,用户曾经遇到过CRAT表找不到和固件加载失败的问题,尤其是si58_mc.bin缺失。因此,这次的问题可能与内核配置或固件有关,也可能涉及驱动模块的参数设置。 接下来,我需要考虑如何通过make menuconfig来解决。可能的步骤包括检查AMDGPU驱动是否启用,确认SI/CIK支持是否开启,确保ACPI相关配置正确,以及固件支持是否包含在内。此外,用户可能需要更新linux-firmware包,或者手动添加缺失的固件文件。 另外,用户可能在内核编译时没有包含必要的选项,导致驱动无法加载。例如,CONFIG_DRM_AMDGPU和相关的SI支持是否设置为y。此外,用户可能需要禁用其他冲突的驱动,如radeon,通过内核参数或内核配置。 还需要考虑用户的内核版本是否足够新,以支持其显卡型号。例如,较旧的GCN 1.0架构显卡可能需要特定的内核版本或配置选项。 最后,建议用户检查dmesg输出,查看是否有相关错误信息,如固件加载失败或驱动初始化错误,这可以帮助进一步诊断问题。同时,编译后的验证步骤也很重要,比如使用modprobe加载驱动并检查日志。</think>以下是对该问题的分步解决方案,通过内核配置(`make menuconfig`)和系统调试逐步排查: --- ### **一、核心问题定位** 1. **验证显卡硬件识别** 首先确认显卡是否被系统检测到: ```bash lspci -nn | grep -i "VGA\|AMD" ``` - 如果能看到类似`AMD Radeon ... [1002:xxxx]`的条目,说明硬件已被识别但驱动未加载 - 如果无输出,可能是硬件连接问题或内核未包含PCIe支持 2. **检查驱动加载状态** ```bash dmesg | grep -i "amdgpu\|drm" ``` 关键日志示例: ```log [ 3.046195] amdgpu: Failed to load firmware... [ 3.078043] drm: amdgpu_device_init failed ``` --- ### **二、内核配置修复(make menuconfig)** #### **步骤1:启用基础AMDGPU支持** 导航路径: ``` Device Drivers ---> Graphics support ---> <*> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) ---> <*> AMD GPU [*] Enable amdgpu support for SI parts (GCN 1.0) [*] Enable amdgpu support for CIK parts (GCN 1.1) ``` 必须选项: ``` CONFIG_DRM_AMDGPU=y CONFIG_DRM_AMDGPU_SI=y # 对应OLAND/TAHITI等GCN 1.0显卡 CONFIG_DRM_AMDGPU_CIK=y # 对应BONAIRE/HAWAII等GCN 1.1显卡 ``` #### **步骤2:关闭冲突驱动** 禁用可能冲突的旧版`radeon`驱动: ``` Device Drivers ---> Graphics support ---> < > ATI Radeon ``` 配置结果: ``` CONFIG_DRM_RADEON=n ``` #### **步骤3:强化固件支持** 确保内核包含固件加载机制: ``` Device Drivers ---> Generic Driver Options ---> [*] Userspace firmware loading support [*] Include in-kernel firmware blobs in kernel build (/lib/firmware) Firmware blobs root directory ``` 关键配置: ``` CONFIG_FW_LOADER=y CONFIG_EXTRA_FIRMWARE="amdgpu/si58_mc.bin" # 根据显卡型号添加具体固件 ``` --- ### **三、固件文件补充** 1. **检查固件目录** ```bash ls /lib/firmware/amdgpu/si58_mc.bin # OLAND显卡所需固件 ``` - 如果文件缺失,手动下载: ```bash sudo wget -O /lib/firmware/amdgpu/si58_mc.bin \ https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/amdgpu/si58_mc.bin ``` 2. **更新initramfs** ```bash sudo update-initramfs -u ``` --- ### **四、内核编译验证** 1. **配置检查** ```bash grep -E "DRM_AMDGPU|AMDGPU_SI|FW_LOADER" .config ``` 预期输出: ``` CONFIG_DRM_AMDGPU=y CONFIG_DRM_AMDGPU_SI=y CONFIG_FW_LOADER=y ``` 2. **加载驱动测试** ```bash sudo modprobe amdgpu dmesg | tail -n 20 | grep -i "amdgpu\|firmware" ``` - 成功标志:显示`firmware: direct-loading firmware amdgpu/si58_mc.bin` --- ### **五、故障排除补充** 1. **内核启动参数** 如果驱动仍不加载,在GRUB配置中添加: ```text amdgpu.si_support=1 radeon.si_support=0 ``` 更新GRUB: ```bash sudo update-grub ``` 2. **兼容性检查** - 确认显卡型号与内核版本匹配: - GCN 1.0显卡(如HD 7790/8770)需内核≥4.15 - 若使用旧内核(如4.x),需手动反向移植补丁 --- ### **典型成功日志** ```log [ 2.946913] [drm] amdgpu kernel modesetting enabled [ 3.018253] amdgpu 0000:01:00.0: firmware: direct-loading firmware amdgpu/si58_mc.bin [ 3.046195] [drm] mc firmware successfully loaded [ 3.078043] [drm] Initialized amdgpu 3.42.0 20150101 ``` 按照以上步骤操作后,使用`lspci -k`应能看到`Kernel driver in use: amdgpu`。如果仍有问题,建议提供完整的`dmesg`输出进一步分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值