Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4d84e9f authored by Camus Wong's avatar Camus Wong Committed by Suprith Malligere Shankaregowda
Browse files

drm/msm: refine hdmi bridge implementation



This change fixes an unclocked hdmi register access while going
to suspend state.

When splash is enabled on HDMI interface & we are going to turn
on the hdmi bridge power. Context of sde_hdmi connector is found
to be NULL because connector was not initialized yet and we never
called sde_hdmi_core_enable which enables hpd clocks.

Now when going to suspend system would be calling clock unprepare
for clocks which were never enabled. Hence hdmi clock gets unbalanced
and resulted in unclocked access to one of the hdmi register during
disabling vblank.

Adding struct sde_hdmi as a member of struct sde_hdmi_bridge and remove
dependency on sde connector to get the hdmi display object.

Change-Id: If96324fd5152ab0e721dfd38e93a68321a615455
Signed-off-by: default avatarCamus Wong <camusw@codeaurora.org>
Signed-off-by: default avatarRahul Sharma <rahsha@codeaurora.org>
Signed-off-by: default avatarSuprith Malligere Shankaregowda <supgow@codeaurora.org>
parent 2c333d31
Loading
Loading
Loading
Loading
+1 −8
Original line number Diff line number Diff line
@@ -1353,13 +1353,6 @@ int sde_hdmi_core_enable(struct sde_hdmi *sde_hdmi)
	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]);
@@ -3216,7 +3209,7 @@ int sde_hdmi_drm_init(struct sde_hdmi *display, struct drm_encoder *enc)

	hdmi_audio_infoframe_init(&hdmi->audio.infoframe);

	hdmi->bridge = sde_hdmi_bridge_init(hdmi);
	hdmi->bridge = sde_hdmi_bridge_init(hdmi, display);
	if (IS_ERR(hdmi->bridge)) {
		rc = PTR_ERR(hdmi->bridge);
		SDE_ERROR("failed to create HDMI bridge: %d\n", rc);
+4 −2
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -431,10 +431,12 @@ int sde_hdmi_get_property(struct drm_connector *connector,
/**
 * sde_hdmi_bridge_init() - init sde hdmi bridge
 * @hdmi:          Handle to the hdmi.
 * @display:       Handle to the sde_hdmi
 *
 * Return: struct drm_bridge *.
 */
struct drm_bridge *sde_hdmi_bridge_init(struct hdmi *hdmi);
struct drm_bridge *sde_hdmi_bridge_init(struct hdmi *hdmi,
			struct sde_hdmi *display);

/**
 * sde_hdmi_set_mode() - Set HDMI mode API.
+22 −36
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
 * Copyright (C) 2013 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 *
@@ -90,6 +90,7 @@ static inline uint32_t SDE_HDMI_VSYNC_TOTAL_F2_V_TOTAL(uint32_t val)
struct sde_hdmi_bridge {
	struct drm_bridge base;
	struct hdmi *hdmi;
	struct sde_hdmi *display;
};
#define to_hdmi_bridge(x) container_of(x, struct sde_hdmi_bridge, base)

@@ -129,20 +130,15 @@ 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;
	struct sde_hdmi *display = sde_hdmi_bridge->display;

	if (c_conn)
		display = (struct sde_hdmi *)c_conn->display;

	if (display) {
		if (display->non_pluggable) {
	if ((display->non_pluggable) && (!hdmi->power_on)) {
		ret = sde_hdmi_core_enable(display);
		if (ret)
				SDE_ERROR("failed to enable HDMI core (%d)\n",
					ret);
		}
			SDE_ERROR("failed to enable HDMI core (%d)\n", ret);
		else
			hdmi->power_on = true;
	}

	for (i = 0; i < config->pwr_reg_cnt; i++) {
@@ -176,8 +172,7 @@ 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;
	struct sde_hdmi *display = sde_hdmi_bridge->display;
	int i, ret;

	/* Wait for vsync */
@@ -194,10 +189,9 @@ static void _sde_hdmi_bridge_power_off(struct drm_bridge *bridge)
		}
	}

	if (display->non_pluggable) {
	if (display->non_pluggable)
		sde_hdmi_core_disable(display);
}
}

static int _sde_hdmi_bridge_ddc_clear_irq(struct hdmi *hdmi,
			char *what)
@@ -490,14 +484,12 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
	struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
	struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
	struct hdmi_phy *phy = hdmi->phy;
	struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
	struct sde_hdmi *display = sde_hdmi_bridge->display;

	DRM_DEBUG("power up");

	if (!hdmi->power_on) {
		_sde_hdmi_bridge_power_on(bridge);
		hdmi->power_on = true;
	}

	if (phy)
@@ -572,8 +564,7 @@ static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge)
{
	struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
	struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
	struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
	struct sde_hdmi *display = sde_hdmi_bridge->display;

	/* need to update hdcp info here to ensure right HDCP support*/
	sde_hdmi_update_hdcp_info(hdmi->connector);
@@ -588,9 +579,7 @@ static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge)
static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge)
{
	struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
	struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
	struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
	struct sde_hdmi *display = sde_hdmi_bridge->display;

	mutex_lock(&display->display_lock);

@@ -610,8 +599,7 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)
	struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
	struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
	struct hdmi_phy *phy = hdmi->phy;
	struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
	struct sde_hdmi *display = sde_hdmi_bridge->display;

	sde_hdmi_notify_clients(display, display->connected);

@@ -835,19 +823,16 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge,
{
	struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
	struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
	struct drm_connector *connector = hdmi->connector;
	struct sde_connector *c_conn = to_sde_connector(connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
	struct sde_hdmi *display = sde_hdmi_bridge->display;
	int hstart, hend, vstart, vend;
	uint32_t frame_ctrl;
	u32 div = 0;

	mode = adjusted_mode;

	if (display->non_pluggable && !hdmi->power_on) {
	if (display->non_pluggable && !hdmi->power_on)
		if (sde_hdmi_core_enable(display))
			pr_err("mode set enable core failured\n");
	}
			pr_err("mode set enable core failed\n");

	display->dc_enable = mode->private_flags &
				(MSM_MODE_FLAG_RGB444_DC_ENABLE |
@@ -925,10 +910,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) {
	if (display->non_pluggable && !hdmi->power_on)
		sde_hdmi_core_disable(display);
}
}

static bool _sde_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
	 const struct drm_display_mode *mode,
@@ -961,7 +945,8 @@ static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = {


/* initialize bridge */
struct drm_bridge *sde_hdmi_bridge_init(struct hdmi *hdmi)
struct drm_bridge *sde_hdmi_bridge_init(struct hdmi *hdmi,
			struct sde_hdmi *display)
{
	struct drm_bridge *bridge = NULL;
	struct sde_hdmi_bridge *sde_hdmi_bridge;
@@ -975,6 +960,7 @@ struct drm_bridge *sde_hdmi_bridge_init(struct hdmi *hdmi)
	}

	sde_hdmi_bridge->hdmi = hdmi;
	sde_hdmi_bridge->display = display;

	bridge = &sde_hdmi_bridge->base;
	bridge->funcs = &_sde_hdmi_bridge_funcs;