图显系统DRM ENCODER和CONNECTOR完全解析


0. 引言

DRM ENCODER 和 CONNECTOR 模块由图显外设抽象而来,从传统意义上来讲,ENCODER 包含外设控制器的功能,而 CONNECTOR 包含外设 PHY 或者显示器参数。但是这两部分又紧密关联,因此,软件 DRM 架构下的 ENCODER 和 CONNECTOR 需要按照一个整体来理解和实现。
HDMI驱动的DRM注册
目前的图显外设接口主要有 MIPI、HDMI、LVDS、DP、VGA、DVI、RGB 等等,同时,又可以通过转接卡来实现各种接口之间的转换。目前,市面上的处理器 SoC 又同时具备以上接口。

SoC集成多种图显外设接口
因此,DRM 架构为了统一管理、无差别化对待不同芯片厂商的 IP,抽象出了 ENCODER 和 CONNECTOR 两部分内容。

2. 功能

ENCODER 作为图显外设的逻辑控制器,从图显处理器接收并行的 RGB 数据,并按照接口类型对 RGB 数据进行编码,例如 HDMI 通过 encoder 将 RGB 数据编码为 TMDS 类型的数据。
在软件层面的 DRM 架构中规定了使用下面两个数据结构,注册 DRM ENCODER 相关功能。
encoder 控制

struct drm_encoder_funcs {
	void (*reset)(struct drm_encoder *encoder);
	void (*destroy)(struct drm_encoder *encoder);
	int (*late_register)(struct drm_encoder *encoder);
	void (*early_unregister)(struct drm_encoder *encoder);
};

encoder 配置

struct drm_encoder_helper_funcs {
	void (*dpms)();
	enum drm_mode_status ();
	bool (*mode_fixup)();
	void (*prepare)();
	void (*commit)();
	void (*mode_set)();
	void (*atomic_mode_set)();
	struct drm_crtc *(*get_crtc)();
	enum drm_connector_status ();
	void (*atomic_disable)();
	void (*atomic_enable)();
	void (*disable)();
	void (*enable)();
	int (*atomic_check)();
};

图显外设 IP 厂商需要提供相关的例化代码,如下:

static const struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
	.destroy = drm_encoder_cleanup,
};

static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
	.mode_fixup	= hdmi_mode_fixup,
	.enable		= hdmi_enable,
	.disable	= hdmi_disable,
};

mode_fixup()会将上层应用下发的图显参数进行校验,可以对参数进行修正也可以终止不符合显示要求的请求。若显示参数符合要求,将其拷贝给 struct drm_display_mode。

static bool hdmi_mode_fixup(struct drm_encoder *encoder,
			    const struct drm_display_mode *mode,
			    struct drm_display_mode *adjusted_mode)
{
...
	  mode_ok = hdmi_mode_valid(connector, adjusted_mode);
...
	  drm_mode_copy(adjusted_mode, m);
...

CONNECTOR 包含 PHY 或者显示屏的参数,接收 ENCODER 发送过来的编码数据后,按照显示接口类型发送给显示器。例如 HDMI PHY 内部集成 Serializer,将 TMDS 数据转换成高速串行 bit 流发送到差分数据通道。
DRM 架构中 connector 需要提供支持的显示参数以及显示屏的连接状态等。规定使用下面两个数据结构,注册 DRM CONNECTR 相关功能。
connctor 控制

struct drm_connector_funcs {
	int (*dpms)();
	void (*reset)();
	enum drm_connector_status ();
	void (*force)();
	int (*fill_modes)();
	int (*set_property)();
	int (*late_register)();
	void (*early_unregister)();
	void (*destroy)();
	struct drm_connector_state *();
	void (*atomic_destroy_state)();
	int (*atomic_set_property)();
	int (*atomic_get_property)();
	void (*atomic_print_state)();
};

connector 配置

struct drm_connector_helper_funcs {
	int (*get_modes)();
	int (*detect_ctx)();
	enum drm_mode_status (*mode_valid)();
	struct drm_encoder *(*best_encoder)();
	struct drm_encoder *(*atomic_best_encoder)();
	int (*atomic_check)();
	void (*atomic_commit)();
	int (*prepare_writeback_job)();
	void (*cleanup_writeback_job)();
};

图显外设 IP 厂商需要提供相关的例化代码,如下:

static const struct drm_connector_funcs hdmi_connector_funcs = {
	.fill_modes = drm_helper_probe_single_connector_modes,
	.detect = hdmi_detect,
	.destroy = hdmi_connector_destroy,
	.reset = drm_atomic_helper_connector_reset,
	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};

static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
	.get_modes = hdmi_get_modes,
	.mode_valid = hdmi_mode_valid,
};

对于显示参数等信息需要通过某种方式从外部获取的图显 IP,如 HDMI、MIPI,hdmi_get_modes 是一个很关键的函数。
对于 HDMI 而言,通过 DDC 总线从外部显示屏中获取显示参数 EDID,以此决定是否支持当前显示要求。若无法获取 EDID 信息,那么是无法点亮屏幕的。DRM 也规定了获取 EDID 的统一标准接口,即 drm_get_edid()。

static int hdmi_get_modes(struct drm_connector *connector)
{
  ...

	  edid = drm_get_edid(connector, hdata->ddc_adpt);
	  if (!edid)
		  return -ENODEV;
  ...
}

SoC 芯片能够同时连接、同时工作的 ENCODER 和 CONNECTOR 数量,取决于内部集成的图显处理器的数量以及每个图显处理器的端口数,当然,SoC 芯片的时钟系统也是影响多个接口能否同时显示的一个关键要素。

3. 初始化

图显外设使用 component_add()注册进 DRM 系统,关于 component_add()
链接
encoder 的初始化包含两部分内容,分别是:

  • drm_encoder_init()
  • drm_encoder_helper_add()

DRM通过数据结构struct drm_encoder来描述ENCODER设备信息及同其他DRM组件之间的关系。

struct drm_encoder {
	struct drm_device *dev;
	struct list_head head;
	struct drm_mode_object base;
	char *name;
	int encoder_type;
	unsigned index;
	uint32_t possible_crtcs;
	uint32_t possible_clones;
	struct drm_crtc *crtc;
	struct drm_bridge *bridge;
	const struct drm_encoder_funcs *funcs;
	const struct drm_encoder_helper_funcs *helper_private;
};

DRM ENCODER初始化流程如下图所示,其主要实现了drm_encoder的例化以及注册drm_encoder_funcs、drm_encoder_helper_funcs两个数据结构。
ENCODER初始化流程
DRM CONNECTOR初始化流程如下图所示,其主要实现了drm_connector的例化以及注册drm_connector_funcs、drm_connector_helper_funcs两个数据结构。
CONNECTOR初始化流程

  • 9
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux与SoC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值