diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index 35ba396e1cd1..3c149f191871 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -1342,15 +1342,73 @@ fail: return ret; } +int sde_hdmi_core_enable(struct sde_hdmi *sde_hdmi) +{ + struct hdmi *hdmi = sde_hdmi->ctrl.ctrl; + const struct hdmi_platform_config *config = hdmi->config; + struct device *dev = &hdmi->pdev->dev; + int i, ret; + struct drm_connector *connector; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + connector = hdmi->connector; + priv = connector->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + + for (i = 0; i < config->hpd_reg_cnt; i++) { + ret = regulator_enable(hdmi->hpd_regs[i]); + if (ret) { + SDE_ERROR("failed to enable hpd regulator: %s (%d)\n", + config->hpd_reg_names[i], ret); + } + } + + ret = pinctrl_pm_select_default_state(dev); + if (ret) + SDE_ERROR("pinctrl state chg failed: %d\n", ret); + + ret = _sde_hdmi_gpio_config(hdmi, true); + if (ret) + SDE_ERROR("failed to configure GPIOs: %d\n", ret); + + for (i = 0; i < config->hpd_clk_cnt; i++) { + if (config->hpd_freq && config->hpd_freq[i]) { + ret = clk_set_rate(hdmi->hpd_clks[i], + config->hpd_freq[i]); + if (ret) + pr_warn("failed to set clk %s (%d)\n", + config->hpd_clk_names[i], ret); + } + + ret = clk_prepare_enable(hdmi->hpd_clks[i]); + if (ret) { + SDE_ERROR("failed to enable hpd clk: %s (%d)\n", + config->hpd_clk_names[i], ret); + } + } + sde_hdmi_set_mode(hdmi, true); + + /* Wait for vsync */ + msleep(20); + + return ret; +} + static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi) { struct hdmi *hdmi = sde_hdmi->ctrl.ctrl; const struct hdmi_platform_config *config = hdmi->config; struct device *dev = &hdmi->pdev->dev; int i, ret = 0; + unsigned long flags; + spin_lock_irqsave(&hdmi->reg_lock, flags); /* Disable HPD interrupt */ + hdmi_write(hdmi, REG_HDMI_HPD_CTRL, 0); hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0); + hdmi_write(hdmi, REG_HDMI_HPD_INT_STATUS, 0); + spin_unlock_irqrestore(&hdmi->reg_lock, flags); sde_hdmi_set_mode(hdmi, false); @@ -1373,6 +1431,12 @@ static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi) } } +void sde_hdmi_core_disable(struct sde_hdmi *sde_hdmi) +{ + /* HPD contains all the core clock and pwr */ + _sde_hdmi_hdp_disable(sde_hdmi); +} + static void _sde_hdmi_cec_update_phys_addr(struct sde_hdmi *display) { struct edid *edid = display->edid_ctrl->edid; @@ -2388,10 +2452,17 @@ int sde_hdmi_connector_post_init(struct drm_connector *connector, hdmi->connector = connector; INIT_WORK(&sde_hdmi->hpd_work, _sde_hdmi_hotplug_work); - /* Enable HPD detection */ - rc = _sde_hdmi_hpd_enable(sde_hdmi); - if (rc) - SDE_ERROR("failed to enable HPD: %d\n", rc); + if (sde_hdmi->non_pluggable) { + /* Disable HPD interrupt */ + hdmi_write(hdmi, REG_HDMI_HPD_CTRL, 0); + hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0); + hdmi_write(hdmi, REG_HDMI_HPD_INT_STATUS, 0); + } else { + /* Enable HPD detection if non_pluggable flag is not defined */ + rc = _sde_hdmi_hpd_enable(sde_hdmi); + if (rc) + SDE_ERROR("failed to enable HPD: %d\n", rc); + } _sde_hdmi_get_tx_version(sde_hdmi); @@ -3147,6 +3218,8 @@ int sde_hdmi_drm_init(struct sde_hdmi *display, struct drm_encoder *enc) if (sde_kms->splash_info.handoff) { sde_hdmi_bridge_power_on(hdmi->bridge); hdmi->power_on = true; + } else { + hdmi->power_on = false; } mutex_unlock(&display->display_lock); diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h index 865998c6a126..471472ea23cf 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -301,6 +301,22 @@ sde_hdmi_connector_detect(struct drm_connector *connector, bool force, void *display); +/** + * sde_hdmi_core_enable()- turn on clk and pwr for hdmi core + * @sde_hdmi: Pointer to sde_hdmi structure + * + * Return: error code + */ +int sde_hdmi_core_enable(struct sde_hdmi *sde_hdmi); + +/** + * sde_hdmi_core_disable()- turn off clk and pwr for hdmi core + * @sde_hdmi: Pointer to sde_hdmi structure + * + * Return: none + */ +void sde_hdmi_core_disable(struct sde_hdmi *sde_hdmi); + /** * sde_hdmi_connector_get_modes - add drm modes via drm_mode_probed_add() * @connector: Pointer to drm connector structure diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c index 5fbe4767ad3a..5a4c4b02c340 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -129,8 +129,22 @@ static void _sde_hdmi_bridge_power_on(struct drm_bridge *bridge) struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; const struct hdmi_platform_config *config = hdmi->config; + struct sde_connector *c_conn = to_sde_connector(hdmi->connector); + struct sde_hdmi *display = NULL; int i, ret; + if (c_conn) + display = (struct sde_hdmi *)c_conn->display; + + if (display) { + if (display->non_pluggable) { + ret = sde_hdmi_core_enable(display); + if (ret) + SDE_ERROR("failed to enable HDMI core (%d)\n", + ret); + } + } + for (i = 0; i < config->pwr_reg_cnt; i++) { ret = regulator_enable(hdmi->pwr_regs[i]); if (ret) { @@ -162,6 +176,8 @@ static void _sde_hdmi_bridge_power_off(struct drm_bridge *bridge) struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; const struct hdmi_platform_config *config = hdmi->config; + struct sde_connector *c_conn = to_sde_connector(hdmi->connector); + struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; int i, ret; /* Wait for vsync */ @@ -177,6 +193,10 @@ static void _sde_hdmi_bridge_power_off(struct drm_bridge *bridge) config->pwr_reg_names[i], ret); } } + + if (display->non_pluggable) { + sde_hdmi_core_disable(display); + } } static int _sde_hdmi_bridge_ddc_clear_irq(struct hdmi *hdmi, @@ -611,8 +631,10 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) hdmi->power_on = false; } - /* Powering-on the controller for HPD */ - sde_hdmi_ctrl_cfg(hdmi, 1); + if (!display->non_pluggable) { + /* Powering-on the controller for HPD */ + sde_hdmi_ctrl_cfg(hdmi, 1); + } } static void _sde_hdmi_bridge_set_avi_infoframe(struct hdmi *hdmi, @@ -822,6 +844,11 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, mode = adjusted_mode; + if (display->non_pluggable && !hdmi->power_on) { + if (sde_hdmi_core_enable(display)) + pr_err("mode set enable core failured\n"); + } + display->dc_enable = mode->private_flags & (MSM_MODE_FLAG_RGB444_DC_ENABLE | MSM_MODE_FLAG_YUV420_DC_ENABLE); @@ -898,6 +925,9 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, _sde_hdmi_save_mode(hdmi, mode); _sde_hdmi_bridge_setup_scrambler(hdmi, mode); _sde_hdmi_bridge_setup_deep_color(hdmi); + if (display->non_pluggable && !hdmi->power_on) { + sde_hdmi_core_disable(display); + } } static bool _sde_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,