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

Commit c74b2c0e authored by Ray Zhang's avatar Ray Zhang
Browse files

drm/msm: notify hpd status when audio codec is ready



HDMI connector should wait for audio codec status and notify
HPD status only in case that audio codec has been registered
successfully. Meanwhile move HPD notification to bridge enable
and disable instead of hotplug work. This ensures the correct
video and audio sequence.

Change-Id: I0dac915c8639bb881265a608016e9d37ec9a153c
Signed-off-by: default avatarRay Zhang <rayz@codeaurora.org>
parent 839e05b9
Loading
Loading
Loading
Loading
+24 −23
Original line number Diff line number Diff line
@@ -823,7 +823,6 @@ static void _sde_hdmi_hotplug_work(struct work_struct *work)
	} else
		sde_free_edid((void **)&sde_hdmi->edid_ctrl);

	sde_hdmi_notify_clients(connector, sde_hdmi->connected);
	drm_helper_hpd_irq_event(connector->dev);
}

@@ -853,7 +852,6 @@ static void _sde_hdmi_connector_irq(struct sde_hdmi *sde_hdmi)
			hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
		hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);

		if (!sde_hdmi->non_pluggable)
		queue_work(hdmi->workq, &sde_hdmi->hpd_work);
	}
}
@@ -943,6 +941,25 @@ static int _sde_hdmi_get_cable_status(struct platform_device *pdev, u32 vote)
	return hdmi->power_on && display->connected;
}

static void _sde_hdmi_audio_codec_ready(struct platform_device *pdev)
{
	struct sde_hdmi *display = platform_get_drvdata(pdev);

	if (!display) {
		SDE_ERROR("invalid param(s), display %pK\n", display);
		return;
	}

	mutex_lock(&display->display_lock);
	if (!display->codec_ready) {
		display->codec_ready = true;

		if (display->client_notify_pending)
			sde_hdmi_notify_clients(display, display->connected);
	}
	mutex_unlock(&display->display_lock);
}

static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display)
{
	int rc = 0;
@@ -962,6 +979,8 @@ static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display)
		_sde_hdmi_get_audio_edid_blk;
	display->ext_audio_data.codec_ops.cable_status =
		_sde_hdmi_get_cable_status;
	display->ext_audio_data.codec_ops.codec_ready =
		_sde_hdmi_audio_codec_ready;

	if (!display->pdev->dev.of_node) {
		SDE_ERROR("[%s]cannot find sde_hdmi of_node\n", display->name);
@@ -990,17 +1009,14 @@ static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display)
	return rc;
}

void sde_hdmi_notify_clients(struct drm_connector *connector,
	bool connected)
void sde_hdmi_notify_clients(struct sde_hdmi *display, bool connected)
{
	struct sde_connector *c_conn = to_sde_connector(connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
	int state = connected ?
		EXT_DISPLAY_CABLE_CONNECT : EXT_DISPLAY_CABLE_DISCONNECT;

	if (display && display->ext_audio_data.intf_ops.hpd) {
		struct hdmi *hdmi = display->ctrl.ctrl;
		u32 flags = MSM_EXT_DISP_HPD_VIDEO;
		u32 flags = MSM_EXT_DISP_HPD_ASYNC_VIDEO;

		if (hdmi->hdmi_mode)
			flags |= MSM_EXT_DISP_HPD_AUDIO;
@@ -1010,21 +1026,6 @@ void sde_hdmi_notify_clients(struct drm_connector *connector,
	}
}

void sde_hdmi_ack_state(struct drm_connector *connector,
	enum drm_connector_status status)
{
	struct sde_connector *c_conn = to_sde_connector(connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;

	if (display) {
		struct hdmi *hdmi = display->ctrl.ctrl;

		if (hdmi->hdmi_mode && display->ext_audio_data.intf_ops.notify)
			display->ext_audio_data.intf_ops.notify(
				display->ext_pdev, status);
	}
}

void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on)
{
	uint32_t ctrl = 0;
+6 −3
Original line number Diff line number Diff line
@@ -83,6 +83,8 @@ struct sde_hdmi_ctrl {
 * @connected:        If HDMI display is connected.
 * @is_tpg_enabled:   TPG state.
 * @hpd_work:         HPD work structure.
 * @codec_ready:      If audio codec is ready.
 * @client_notify_pending: If there is client notification pending.
 * @root:             Debug fs root entry.
 */
struct sde_hdmi {
@@ -107,6 +109,8 @@ struct sde_hdmi {
	bool is_tpg_enabled;

	struct work_struct hpd_work;
	bool codec_ready;
	bool client_notify_pending;

	/* DEBUG FS */
	struct dentry *root;
@@ -361,13 +365,12 @@ int sde_hdmi_config_avmute(struct hdmi *hdmi, bool set);

/**
 * sde_hdmi_notify_clients() - notify hdmi clients of the connection status.
 * @connector:     Handle to the drm_connector.
 * @display:       Handle to sde_hdmi.
 * @connected:     connection status.
 *
 * Return: void.
 */
void sde_hdmi_notify_clients(struct drm_connector *connector,
	bool connected);
void sde_hdmi_notify_clients(struct sde_hdmi *display, bool connected);

/**
 * sde_hdmi_ack_state() - acknowledge the connection status.
+12 −29
Original line number Diff line number Diff line
@@ -372,6 +372,8 @@ 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;

	DRM_DEBUG("power up");

@@ -388,41 +390,20 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
	if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported)
		hdmi_hdcp_ctrl_on(hdmi->hdcp_ctrl);

	sde_hdmi_ack_state(hdmi->connector, EXT_DISPLAY_CABLE_CONNECT);
}

static void sde_hdmi_force_update_audio(struct drm_connector *connector,
	enum drm_connector_status status)
{
	struct sde_connector *c_conn = to_sde_connector(connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;

	if (display && display->non_pluggable) {
		display->ext_audio_data.intf_ops.hpd(display->ext_pdev,
				display->ext_audio_data.type,
				status,
				MSM_EXT_DISP_HPD_AUDIO);
	}
	mutex_lock(&display->display_lock);
	if (display->codec_ready)
		sde_hdmi_notify_clients(display, display->connected);
	else
		display->client_notify_pending = true;
	mutex_unlock(&display->display_lock);
}

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;

	/* force update audio ops when there's no HPD event */
	sde_hdmi_force_update_audio(hdmi->connector,
		EXT_DISPLAY_CABLE_CONNECT);
}

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;

	/* force update audio ops when there's no HPD event */
	sde_hdmi_force_update_audio(hdmi->connector,
		EXT_DISPLAY_CABLE_DISCONNECT);
}

static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)
@@ -430,6 +411,10 @@ 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;

	sde_hdmi_notify_clients(display, display->connected);

	if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported)
		hdmi_hdcp_ctrl_off(hdmi->hdcp_ctrl);
@@ -446,8 +431,6 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)
		_sde_hdmi_bridge_power_off(bridge);
		hdmi->power_on = false;
	}

	sde_hdmi_ack_state(hdmi->connector, EXT_DISPLAY_CABLE_DISCONNECT);
}

static void _sde_hdmi_bridge_set_avi_infoframe(struct hdmi *hdmi,