AM5728绕过hpd信号,强制输出hdmi/dvi的设置方法

AM5728绕过hpd信号,强制输出hdmi/dvi的设置方法

Armin
2025-07-03 / 0 评论 / 2 阅读 / 正在检测是否收录...

公司基于 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的方法:

  1. omap_connector.c中 omap_connector_detect 函数直接返回 connector_status_connected
  2. 注释 drm_kms_helper_hotplug_event
  3. hdmi5.c中的函数 hdmi_set_hdmi_modehdmi.cfg.hdmi_dvi_mode 等于HDMI_HDMI或者HDMI_DVI,即可设置输出类型是HDMI或DVI。**
0

评论 (0)

取消