diff options
Diffstat (limited to 'drivers/gpu/drm/display/drm_bridge_connector.c')
-rw-r--r-- | drivers/gpu/drm/display/drm_bridge_connector.c | 160 |
1 files changed, 124 insertions, 36 deletions
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c index 30c736fc0067..7d2e499ea5de 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -98,6 +98,21 @@ struct drm_bridge_connector { * HDMI connector infrastructure, if any (see &DRM_BRIDGE_OP_HDMI). */ struct drm_bridge *bridge_hdmi; + /** + * @bridge_hdmi_audio: + * + * The bridge in the chain that implements necessary support for the + * HDMI Audio infrastructure, if any (see &DRM_BRIDGE_OP_HDMI_AUDIO). + */ + struct drm_bridge *bridge_hdmi_audio; + /** + * @bridge_dp_audio: + * + * The bridge in the chain that implements necessary support for the + * DisplayPort Audio infrastructure, if any (see + * &DRM_BRIDGE_OP_DP_AUDIO). + */ + struct drm_bridge *bridge_dp_audio; }; #define to_drm_bridge_connector(x) \ @@ -433,14 +448,25 @@ static int drm_bridge_connector_audio_startup(struct drm_connector *connector) to_drm_bridge_connector(connector); struct drm_bridge *bridge; - bridge = bridge_connector->bridge_hdmi; - if (!bridge) - return -EINVAL; + if (bridge_connector->bridge_hdmi_audio) { + bridge = bridge_connector->bridge_hdmi_audio; + + if (!bridge->funcs->hdmi_audio_startup) + return 0; + + return bridge->funcs->hdmi_audio_startup(connector, bridge); + } + + if (bridge_connector->bridge_dp_audio) { + bridge = bridge_connector->bridge_dp_audio; - if (!bridge->funcs->hdmi_audio_startup) - return 0; + if (!bridge->funcs->dp_audio_startup) + return 0; - return bridge->funcs->hdmi_audio_startup(connector, bridge); + return bridge->funcs->dp_audio_startup(connector, bridge); + } + + return -EINVAL; } static int drm_bridge_connector_audio_prepare(struct drm_connector *connector, @@ -451,11 +477,19 @@ static int drm_bridge_connector_audio_prepare(struct drm_connector *connector, to_drm_bridge_connector(connector); struct drm_bridge *bridge; - bridge = bridge_connector->bridge_hdmi; - if (!bridge) - return -EINVAL; + if (bridge_connector->bridge_hdmi_audio) { + bridge = bridge_connector->bridge_hdmi_audio; + + return bridge->funcs->hdmi_audio_prepare(connector, bridge, fmt, hparms); + } - return bridge->funcs->hdmi_audio_prepare(connector, bridge, fmt, hparms); + if (bridge_connector->bridge_dp_audio) { + bridge = bridge_connector->bridge_dp_audio; + + return bridge->funcs->dp_audio_prepare(connector, bridge, fmt, hparms); + } + + return -EINVAL; } static void drm_bridge_connector_audio_shutdown(struct drm_connector *connector) @@ -464,11 +498,15 @@ static void drm_bridge_connector_audio_shutdown(struct drm_connector *connector) to_drm_bridge_connector(connector); struct drm_bridge *bridge; - bridge = bridge_connector->bridge_hdmi; - if (!bridge) - return; + if (bridge_connector->bridge_hdmi_audio) { + bridge = bridge_connector->bridge_hdmi_audio; + bridge->funcs->hdmi_audio_shutdown(connector, bridge); + } - bridge->funcs->hdmi_audio_shutdown(connector, bridge); + if (bridge_connector->bridge_dp_audio) { + bridge = bridge_connector->bridge_dp_audio; + bridge->funcs->dp_audio_shutdown(connector, bridge); + } } static int drm_bridge_connector_audio_mute_stream(struct drm_connector *connector, @@ -478,15 +516,27 @@ static int drm_bridge_connector_audio_mute_stream(struct drm_connector *connecto to_drm_bridge_connector(connector); struct drm_bridge *bridge; - bridge = bridge_connector->bridge_hdmi; - if (!bridge) - return -EINVAL; + if (bridge_connector->bridge_hdmi_audio) { + bridge = bridge_connector->bridge_hdmi_audio; + + if (!bridge->funcs->hdmi_audio_mute_stream) + return -ENOTSUPP; - if (bridge->funcs->hdmi_audio_mute_stream) return bridge->funcs->hdmi_audio_mute_stream(connector, bridge, enable, direction); - else - return -ENOTSUPP; + } + + if (bridge_connector->bridge_dp_audio) { + bridge = bridge_connector->bridge_dp_audio; + + if (!bridge->funcs->dp_audio_mute_stream) + return -ENOTSUPP; + + return bridge->funcs->dp_audio_mute_stream(connector, bridge, + enable, direction); + } + + return -EINVAL; } static const struct drm_connector_hdmi_audio_funcs drm_bridge_connector_hdmi_audio_funcs = { @@ -576,6 +626,42 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, max_bpc = bridge->max_bpc; } + if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO) { + if (bridge_connector->bridge_hdmi_audio) + return ERR_PTR(-EBUSY); + + if (bridge_connector->bridge_dp_audio) + return ERR_PTR(-EBUSY); + + if (!bridge->hdmi_audio_max_i2s_playback_channels && + !bridge->hdmi_audio_spdif_playback) + return ERR_PTR(-EINVAL); + + if (!bridge->funcs->hdmi_audio_prepare || + !bridge->funcs->hdmi_audio_shutdown) + return ERR_PTR(-EINVAL); + + bridge_connector->bridge_hdmi_audio = bridge; + } + + if (bridge->ops & DRM_BRIDGE_OP_DP_AUDIO) { + if (bridge_connector->bridge_dp_audio) + return ERR_PTR(-EBUSY); + + if (bridge_connector->bridge_hdmi_audio) + return ERR_PTR(-EBUSY); + + if (!bridge->hdmi_audio_max_i2s_playback_channels && + !bridge->hdmi_audio_spdif_playback) + return ERR_PTR(-EINVAL); + + if (!bridge->funcs->dp_audio_prepare || + !bridge->funcs->dp_audio_shutdown) + return ERR_PTR(-EINVAL); + + bridge_connector->bridge_dp_audio = bridge; + } + if (!drm_bridge_get_next_bridge(bridge)) connector_type = bridge->type; @@ -611,22 +697,6 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, max_bpc); if (ret) return ERR_PTR(ret); - - if (bridge->hdmi_audio_max_i2s_playback_channels || - bridge->hdmi_audio_spdif_playback) { - if (!bridge->funcs->hdmi_audio_prepare || - !bridge->funcs->hdmi_audio_shutdown) - return ERR_PTR(-EINVAL); - - ret = drm_connector_hdmi_audio_init(connector, - bridge->hdmi_audio_dev, - &drm_bridge_connector_hdmi_audio_funcs, - bridge->hdmi_audio_max_i2s_playback_channels, - bridge->hdmi_audio_spdif_playback, - bridge->hdmi_audio_dai_port); - if (ret) - return ERR_PTR(ret); - } } else { ret = drmm_connector_init(drm, connector, &drm_bridge_connector_funcs, @@ -635,6 +705,24 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, return ERR_PTR(ret); } + if (bridge_connector->bridge_hdmi_audio || + bridge_connector->bridge_dp_audio) { + struct device *dev; + + if (bridge_connector->bridge_hdmi_audio) + dev = bridge_connector->bridge_hdmi_audio->hdmi_audio_dev; + else + dev = bridge_connector->bridge_dp_audio->hdmi_audio_dev; + + ret = drm_connector_hdmi_audio_init(connector, dev, + &drm_bridge_connector_hdmi_audio_funcs, + bridge->hdmi_audio_max_i2s_playback_channels, + bridge->hdmi_audio_spdif_playback, + bridge->hdmi_audio_dai_port); + if (ret) + return ERR_PTR(ret); + } + drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs); if (bridge_connector->bridge_hpd) |