公司基于 AM5728 处理器为客户定制了一款linux视频源板,主要输出一路hdmi视频信号。由于特殊原因,需要绕过hpd信号,强制hdmi输出视频。最简单的方法当然是直接将hpd信号拉高到板内的3.3v,便可以实现不再检测hpd信号。但由于板卡已经设计完成,强行拉高hpd信号需要飞线,因此只能从内核驱动下手,通过修改linux-drm驱动的方法,绕过hpd信号。另一个问题是板卡输出使用的应用是基于gstreamer的播放程序,sink使用的是waylandsink,热插拔会造成gstreamer播放程序被kill的问题。现将调试解决问题的方法记录如下:
omapdrm目录说明
AM5728 的hdmi驱动路径是 /linux-sdk/kernel/drivers/gpu/drm/omapdrm/
,该目录实现的是 TI OMAP DSS 显示子系统的 DRM 驱动(omapdrm),支持 HDMI、DSI、DPI、LVDS 等显示接口。主要负责:
- 实现 DRM framework 所需的 crtc、encoder、connector、plane 等核心对象
- 提供 TI 特有显示硬件的控制逻辑(DSS 管理、VENC、HDMI)
子目录说明
dss/ — DSS 子系统 HAL 封装层,DSS = Display SubSystem,是 TI SoC 显示硬件的控制核心,提供与具体硬件寄存器、时钟、reset、overlay、video port 等的接口。此处并不直接处理 DRM 接口,而是为 DRM CRTC/Plane 提供驱动支撑。
displays/ — 具体显示屏的 panel 驱动,实现具体 LCD 面板或显示器的驱动逻辑,注册 panel 信息给 DRM,如果自己开发了一个 LCD 面板,可以仿照这里写法。当前的hdmi接了一个 TPD12S015 芯片,该芯片是HDMI 接口保护和信号路由集成器件,主要应用于 HDMI 发射端(HDMI_TX)电路中,因此也在这个目录下。
关键代码说明
1、 encoder-tpd12s015.c 中的 tpd_hpd_isr
函数最终调用 omap_connector.c 中的 omap_connector_hpd_cb
函数,里边的 drm_kms_helper_hotplug_event
函数会影响并关闭gstreamer程序。
"encoder-tpd12s015.c"
static irqreturn_t tpd_hpd_isr(int irq, void *data)
{
struct panel_drv_data *ddata = data;
mutex_lock(&ddata->hpd_lock);
if (ddata->hpd_enabled && ddata->hpd_cb) {
enum drm_connector_status status;
if (tpd_detect(&ddata->dssdev))
status = connector_status_connected;
else
status = connector_status_disconnected;
ddata->hpd_cb(ddata->hpd_cb_data, status);
}
mutex_unlock(&ddata->hpd_lock);
return IRQ_HANDLED;
}
板卡开机,linux内核启动过程中的hpd连接检测不在 tpd_hpd_isr
里,第一次触发 tpd_hpd_isr
时,if判断条件中的ddata->hpd_cb还不满足,此时还没有注册热插拔callback函数。因此该函数主要处理的是进入系统之后的热插拔操作。
2、linux内核启动过程中的hpd连接检测使用的是 omap_connector_detect
函数,让该函数直接返回 connector_status_connected
,后续的hdmi控制器配置初始化便可以继续进行。
"omap_connector.c"
static enum drm_connector_status omap_connector_detect(
struct drm_connector *connector, bool force)
{
struct omap_connector *omap_connector = to_omap_connector(connector);
struct omap_dss_device *dssdev = omap_connector->dssdev;
struct omap_dss_driver *dssdrv = dssdev->driver;
enum drm_connector_status ret;
pr_info("ydbg : skip hpd detect\n");
return connector_status_connected;//ydbg 202506+ 跳过hpd检测,开机直接强制输出,不返回已连接的话,后续驱动不会初始化hdmi
if (dssdrv->detect) {
if (dssdrv->detect(dssdev))
ret = connector_status_connected;
else
ret = connector_status_disconnected;
} else if (dssdev->type == OMAP_DISPLAY_TYPE_DPI ||
dssdev->type == OMAP_DISPLAY_TYPE_DBI ||
dssdev->type == OMAP_DISPLAY_TYPE_SDI ||
dssdev->type == OMAP_DISPLAY_TYPE_DSI) {
ret = connector_status_connected;
} else {
ret = connector_status_unknown;
}
VERB("%s: %d (force=%d)", omap_connector->dssdev->name, ret, force);
return ret;
}
static void omap_connector_hpd_cb(void *cb_data,
enum drm_connector_status status)
{
struct omap_connector *omap_connector = cb_data;
struct drm_connector *connector = &omap_connector->base;
struct drm_device *dev = connector->dev;
enum drm_connector_status old_status;
status = connector_status_connected;
pr_info("ydbg : force the status to be connector_status_connected\n");
mutex_lock(&dev->mode_config.mutex);
old_status = connector->status;
connector->status = status;
mutex_unlock(&dev->mode_config.mutex);
/*if (old_status != status)
drm_kms_helper_hotplug_event(dev);*/
//ydbg encoder-tpd12s015.c中的tpd_hpd_isr这里会调用这里,会影响并关闭gstreamer应用,因此注释掉
}
同时注释掉 drm_kms_helper_hotplug_event
,在进入系统之后便不会因为拔插连接器而关闭gstreamer播放程序。
**最终跳过hpd并强制输出hdmi/dvi的方法:
- omap_connector.c中
omap_connector_detect
函数直接返回connector_status_connected
。 - 注释
drm_kms_helper_hotplug_event
。 - hdmi5.c中的函数
hdmi_set_hdmi_mode
令hdmi.cfg.hdmi_dvi_mode
等于HDMI_HDMI或者HDMI_DVI,即可设置输出类型是HDMI或DVI。**
评论 (0)