Setup the HDMI connector on the MSM HDMI outputs. Make use of atomic_check hook and of the provided Infoframe infrastructure. Note: for now only AVI Infoframes are enabled. Audio Infoframes are currenly handled separately. This will be fixed for the final version. Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxx> --- drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 83 +++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index d839c71091dc..26c847f42522 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -68,23 +68,15 @@ static void power_off(struct drm_bridge *bridge) #define AVI_IFRAME_LINE_NUMBER 1 -static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi) +static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi, + const u8 *buffer, size_t len) { - struct drm_crtc *crtc = hdmi->encoder->crtc; - const struct drm_display_mode *mode = &crtc->state->adjusted_mode; - union hdmi_infoframe frame; - u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; u32 val; - int len; - drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, - hdmi->connector, mode); - - len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (len < 0) { + if (len != HDMI_INFOFRAME_SIZE(AVI)) { DRM_DEV_ERROR(&hdmi->pdev->dev, "failed to configure avi infoframe\n"); - return; + return -EINVAL; } /* @@ -124,6 +116,55 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi) val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK; val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER); hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val); + + return 0; +} + +static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) +{ + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = hdmi_bridge->hdmi; + u32 val; + + val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); + + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND | + HDMI_INFOFRAME_CTRL0_AVI_CONT); + break; + case HDMI_INFOFRAME_TYPE_AUDIO: + val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE); + break; + default: + drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type); + } + + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val); + + return 0; +} + +static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) +{ + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = hdmi_bridge->hdmi; + + msm_hdmi_bridge_clear_infoframe(bridge, type); + + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + return msm_hdmi_config_avi_infoframe(hdmi, buffer, len); + default: + drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type); + return 0; + } } static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge, @@ -132,6 +173,10 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge, struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = hdmi_bridge->hdmi; struct hdmi_phy *phy = hdmi->phy; + struct drm_encoder *encoder = bridge->encoder; + struct drm_atomic_state *state = old_bridge_state->base.state; + struct drm_connector *connector = + drm_atomic_get_new_connector_for_encoder(state, encoder); DBG("power up"); @@ -139,12 +184,13 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge, msm_hdmi_phy_resource_enable(phy); msm_hdmi_power_on(bridge); hdmi->power_on = true; - if (hdmi->hdmi_mode) { - msm_hdmi_config_avi_infoframe(hdmi); - msm_hdmi_audio_update(hdmi); - } } + drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); + + if (hdmi->hdmi_mode) + msm_hdmi_audio_update(hdmi); + msm_hdmi_phy_powerup(phy, hdmi->pixclock); msm_hdmi_set_mode(hdmi, true); @@ -310,6 +356,8 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = { .mode_valid = msm_hdmi_bridge_mode_valid, .edid_read = msm_hdmi_bridge_edid_read, .detect = msm_hdmi_bridge_detect, + .clear_infoframe = msm_hdmi_bridge_clear_infoframe, + .write_infoframe = msm_hdmi_bridge_write_infoframe, }; static void @@ -341,8 +389,11 @@ int msm_hdmi_bridge_init(struct hdmi *hdmi) bridge->funcs = &msm_hdmi_bridge_funcs; bridge->ddc = hdmi->i2c; bridge->type = DRM_MODE_CONNECTOR_HDMIA; + bridge->vendor = "Qualcomm"; + bridge->product = "Snapdragon"; bridge->ops = DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_DETECT | + DRM_BRIDGE_OP_HDMI | DRM_BRIDGE_OP_EDID; ret = devm_drm_bridge_add(hdmi->dev->dev, bridge); -- 2.39.2