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

Commit 9e61b769 authored by Ajay Singh Parmar's avatar Ajay Singh Parmar Committed by Divya Sharma
Browse files

drm/msm/dp: fix audio during link maintenance



During link maintenance, audio needs to be switched off and
on to adapt to new link configurations. Move the registration
of audio functionalities with external-display module to
audio sub-module's initialization. This is needed to separate
out the audio initialization and registration from audio enable
and disable. Now, audio initialization and registration happens
during DisplayPort initialization. For MST case, it happens during
connector installation for a new stream.
This gives the flexibility to independently enabled or disabled
audio. It can be switched along with the video stream during
hot plug or during link maintenance.

CRs-Fixed: 2305680
Change-Id: I22a056af75a9851056c97e8174319c0dc3022f29
Signed-off-by: default avatarAjay Singh Parmar <aparmar@codeaurora.org>
parent 846bfdf1
Loading
Loading
Loading
Loading
+61 −37
Original line number Diff line number Diff line
@@ -39,8 +39,11 @@ struct dp_audio_private {
	struct completion hpd_comp;
	struct workqueue_struct *notify_workqueue;
	struct delayed_work notify_delayed_work;
	struct mutex ops_lock;

	struct dp_audio dp_audio;

	atomic_t acked;
};

static u32 dp_audio_get_header(struct dp_catalog_audio *catalog,
@@ -416,14 +419,14 @@ static int dp_audio_info_setup(struct platform_device *pdev,
		return rc;
	}

	mutex_lock(&audio->dp_audio.ops_lock);
	mutex_lock(&audio->ops_lock);

	audio->channels = params->num_of_channels;

	if (audio->panel->stream_id >= DP_STREAM_MAX) {
		pr_err("invalid stream id: %d\n", audio->panel->stream_id);
		rc = -EINVAL;
		mutex_unlock(&audio->dp_audio.ops_lock);
		mutex_unlock(&audio->ops_lock);
		return rc;
	}

@@ -432,7 +435,7 @@ static int dp_audio_info_setup(struct platform_device *pdev,
	dp_audio_safe_to_exit_level(audio);
	dp_audio_enable(audio, true);

	mutex_unlock(&audio->dp_audio.ops_lock);
	mutex_unlock(&audio->ops_lock);
	return rc;
}

@@ -506,10 +509,11 @@ static void dp_audio_teardown_done(struct platform_device *pdev)
	if (IS_ERR(audio))
		return;

	mutex_lock(&audio->dp_audio.ops_lock);
	mutex_lock(&audio->ops_lock);
	dp_audio_enable(audio, false);
	mutex_unlock(&audio->dp_audio.ops_lock);
	mutex_unlock(&audio->ops_lock);

	atomic_set(&audio->acked, 1);
	complete_all(&audio->hpd_comp);

	pr_debug("audio engine disabled\n");
@@ -542,8 +546,10 @@ static int dp_audio_ack_done(struct platform_device *pdev, u32 ack)

	pr_debug("acknowledging audio (%d)\n", ack_hpd);

	if (!audio->engine_on)
	if (!audio->engine_on) {
		atomic_set(&audio->acked, 1);
		complete_all(&audio->hpd_comp);
	}
end:
	return rc;
}
@@ -566,16 +572,13 @@ static int dp_audio_codec_ready(struct platform_device *pdev)
	return rc;
}

static int dp_audio_register_ext_disp(struct dp_audio *dp_audio)
static int dp_audio_register_ext_disp(struct dp_audio_private *audio)
{
	int rc = 0;
	struct device_node *pd = NULL;
	const char *phandle = "qcom,ext-disp";
	struct msm_ext_disp_init_data *ext;
	struct msm_ext_disp_audio_codec_ops *ops;
	struct dp_audio_private *audio;

	audio = container_of(dp_audio, struct dp_audio_private, dp_audio);

	ext = &audio->ext_audio_data;
	ops = &ext->codec_ops;
@@ -624,15 +627,12 @@ static int dp_audio_register_ext_disp(struct dp_audio *dp_audio)
	return rc;
}

static int dp_audio_deregister_ext_disp(struct dp_audio *dp_audio)
static int dp_audio_deregister_ext_disp(struct dp_audio_private *audio)
{
	int rc = 0;
	struct device_node *pd = NULL;
	const char *phandle = "qcom,ext-disp";
	struct msm_ext_disp_init_data *ext;
	struct dp_audio_private *audio;

	audio = container_of(dp_audio, struct dp_audio_private, dp_audio);

	ext = &audio->ext_audio_data;

@@ -669,9 +669,14 @@ static int dp_audio_notify(struct dp_audio_private *audio, u32 state)
	int rc = 0;
	struct msm_ext_disp_init_data *ext = &audio->ext_audio_data;

	if (!ext->intf_ops.audio_notify)
	atomic_set(&audio->acked, 0);

	if (!ext->intf_ops.audio_notify) {
		pr_err("audio notify not defined\n");
		goto end;
	}

	reinit_completion(&audio->hpd_comp);
	rc = ext->intf_ops.audio_notify(audio->ext_pdev,
			&ext->codec, state);
	if (rc) {
@@ -679,8 +684,10 @@ static int dp_audio_notify(struct dp_audio_private *audio, u32 state)
		goto end;
	}

	reinit_completion(&audio->hpd_comp);
	rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5);
	if (atomic_read(&audio->acked))
		goto end;

	rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 4);
	if (!rc) {
		pr_err("timeout. state=%d err=%d\n", state, rc);
		rc = -ETIMEDOUT;
@@ -692,6 +699,30 @@ static int dp_audio_notify(struct dp_audio_private *audio, u32 state)
	return rc;
}

static int dp_audio_config(struct dp_audio_private *audio, u32 state)
{
	int rc = 0;
	struct msm_ext_disp_init_data *ext = &audio->ext_audio_data;

	if (!ext || !ext->intf_ops.audio_config) {
		pr_err("audio_config not defined\n");
		goto end;
	}

	/*
	 * DP Audio sets default STREAM_0 only, other streams are
	 * set by audio driver based on the hardware/software support.
	 */
	if (audio->panel->stream_id == DP_STREAM_0) {
		rc = ext->intf_ops.audio_config(audio->ext_pdev,
				&ext->codec, state);
		if (rc)
			pr_err("failed to config audio, err=%d\n", rc);
	}
end:
	return rc;
}

static int dp_audio_on(struct dp_audio *dp_audio)
{
	int rc = 0;
@@ -713,15 +744,9 @@ static int dp_audio_on(struct dp_audio *dp_audio)

	audio->session_on = true;

	if (ext->intf_ops.audio_config) {
		rc = ext->intf_ops.audio_config(audio->ext_pdev,
				&ext->codec,
				EXT_DISPLAY_CABLE_CONNECT);
		if (rc) {
			pr_err("failed to config audio, err=%d\n", rc);
	rc = dp_audio_config(audio, EXT_DISPLAY_CABLE_CONNECT);
	if (rc)
		goto end;
		}
	}

	rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_CONNECT);
	if (rc)
@@ -757,13 +782,7 @@ static int dp_audio_off(struct dp_audio *dp_audio)

	pr_debug("success\n");
end:
	if (ext->intf_ops.audio_config) {
		rc = ext->intf_ops.audio_config(audio->ext_pdev,
				&ext->codec,
				EXT_DISPLAY_CABLE_DISCONNECT);
		if (rc)
			pr_err("failed to config audio, err=%d\n", rc);
	}
	dp_audio_config(audio, EXT_DISPLAY_CABLE_DISCONNECT);

	audio->session_on = false;
	audio->engine_on  = false;
@@ -830,17 +849,19 @@ struct dp_audio *dp_audio_get(struct platform_device *pdev,
	audio->panel = panel;
	audio->catalog = catalog;

	atomic_set(&audio->acked, 0);

	dp_audio = &audio->dp_audio;

	mutex_init(&dp_audio->ops_lock);
	mutex_init(&audio->ops_lock);

	dp_audio->on  = dp_audio_on;
	dp_audio->off = dp_audio_off;
	dp_audio->register_ext_disp = dp_audio_register_ext_disp;
	dp_audio->deregister_ext_disp = dp_audio_deregister_ext_disp;

	catalog->init(catalog);

	dp_audio_register_ext_disp(audio);

	return dp_audio;

error_notify_workqueue:
@@ -857,7 +878,10 @@ void dp_audio_put(struct dp_audio *dp_audio)
		return;

	audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
	mutex_destroy(&dp_audio->ops_lock);

	dp_audio_deregister_ext_disp(audio);

	mutex_destroy(&audio->ops_lock);

	dp_audio_destroy_notify_workqueue(audio);

+0 −24
Original line number Diff line number Diff line
@@ -29,8 +29,6 @@ struct dp_audio {
	u32 lane_count;
	u32 bw_code;

	struct mutex ops_lock;

	/**
	 * on()
	 *
@@ -52,28 +50,6 @@ struct dp_audio {
	 * Returns the error code in case of failure, 0 in success case.
	 */
	int (*off)(struct dp_audio *dp_audio);

	/**
	 * register_ext_disp()
	 *
	 * Registers the audio with external display module.
	 *
	 * @dp_audio: an instance of struct dp_audio.
	 *
	 * Returns the error code in case of failure, 0 in success case.
	 */
	int (*register_ext_disp)(struct dp_audio *dp_audio);

	/**
	 * deregister_ext_disp()
	 *
	 * Deregisters the audio with external display module.
	 *
	 * @dp_audio: an instance of struct dp_audio.
	 *
	 * Returns the error code in case of failure, 0 in success case.
	 */
	int (*deregister_ext_disp)(struct dp_audio *dp_audio);
};

/**
+1 −3
Original line number Diff line number Diff line
@@ -471,10 +471,8 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
	link_info.capabilities = ctrl->panel->link_info.capabilities;

	ret = drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
	if (ret) {
		pr_err_ratelimited("link_configure failed, rc=%d\n", ret);
	if (ret)
		goto end;
	}

	ret = drm_dp_dpcd_write(ctrl->aux->drm_aux,
		DP_MAIN_LINK_CHANNEL_CODING_SET, &encoding, 1);
+4 −26
Original line number Diff line number Diff line
@@ -98,7 +98,6 @@ struct dp_display_private {
	struct delayed_work hdcp_cb_work;
	struct delayed_work connect_work;
	struct work_struct attention_work;
	struct mutex hdcp_mutex;
	struct mutex session_lock;

	u32 active_stream_cnt;
@@ -293,7 +292,6 @@ static void dp_display_deinitialize_hdcp(struct dp_display_private *dp)
	}

	sde_dp_hdcp2p2_deinit(dp->hdcp.data);
	mutex_destroy(&dp->hdcp_mutex);
}

static int dp_display_initialize_hdcp(struct dp_display_private *dp)
@@ -309,8 +307,6 @@ static int dp_display_initialize_hdcp(struct dp_display_private *dp)

	parser = dp->parser;

	mutex_init(&dp->hdcp_mutex);

	hdcp_init_data.client_id     = HDCP_CLIENT_DP;
	hdcp_init_data.drm_aux       = dp->aux->drm_aux;
	hdcp_init_data.cb_data       = (void *)dp;
@@ -857,21 +853,17 @@ static void dp_display_handle_maintenance_req(struct dp_display_private *dp)
	int idx;
	struct dp_panel *dp_panel;

	mutex_lock(&dp->session_lock);

	for (idx = DP_STREAM_0; idx < DP_STREAM_MAX; idx++) {
		if (!dp->active_panels[idx])
			continue;

		dp_panel = dp->active_panels[idx];

		dp->ctrl->stream_pre_off(dp->ctrl, dp_panel);
		dp->ctrl->stream_off(dp->ctrl, dp_panel);

		mutex_lock(&dp_panel->audio->ops_lock);

		if (dp_panel->audio_supported)
			dp_panel->audio->off(dp_panel->audio);

		dp->ctrl->stream_pre_off(dp->ctrl, dp_panel);
		dp->ctrl->stream_off(dp->ctrl, dp_panel);
	}

	dp->ctrl->link_maintenance(dp->ctrl);
@@ -886,11 +878,7 @@ static void dp_display_handle_maintenance_req(struct dp_display_private *dp)

		if (dp_panel->audio_supported)
			dp_panel->audio->on(dp_panel->audio);

		mutex_unlock(&dp_panel->audio->ops_lock);
	}

	mutex_unlock(&dp->session_lock);
}

static void dp_display_mst_attention(struct dp_display_private *dp)
@@ -1411,8 +1399,6 @@ static void dp_display_stream_post_enable(struct dp_display_private *dp,
{
	dp_panel->spd_config(dp_panel);
	dp_panel->setup_hdr(dp_panel, NULL);

	dp_panel->audio->register_ext_disp(dp_panel->audio);
}

static int dp_display_post_enable(struct dp_display *dp_display, void *panel)
@@ -1436,10 +1422,8 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel)
		goto end;
	}

	if (atomic_read(&dp->aborted)) {
		pr_err("aborted\n");
	if (atomic_read(&dp->aborted))
		goto end;
	}

	if (!dp_display_is_ready(dp) || !dp->core_initialized) {
		pr_err("display not ready\n");
@@ -1479,7 +1463,6 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel)
static int dp_display_stream_pre_disable(struct dp_display_private *dp,
			struct dp_panel *dp_panel)
{
	dp_panel->audio->deregister_ext_disp(dp_panel->audio);
	dp->ctrl->stream_pre_off(dp->ctrl, dp_panel);

	return 0;
@@ -1770,13 +1753,8 @@ static void dp_display_convert_to_dp_mode(struct dp_display *dp_display,
	dp = container_of(dp_display, struct dp_display_private, dp_display);
	dp_panel = panel;

	mutex_lock(&dp->session_lock);

	memset(dp_mode, 0, sizeof(*dp_mode));

	dp_panel->convert_to_dp_mode(dp_panel, drm_mode, dp_mode);

	mutex_unlock(&dp->session_lock);
}

static int dp_display_config_hdr(struct dp_display *dp_display, void *panel,
+0 −1
Original line number Diff line number Diff line
@@ -1683,7 +1683,6 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
	dp_panel->spd_enabled = true;
	memcpy(panel->spd_vendor_name, vendor_name, (sizeof(u8) * 8));
	memcpy(panel->spd_product_description, product_desc, (sizeof(u8) * 16));
	dp_panel->stream_id = DP_STREAM_MAX;
	dp_panel->connector = in->connector;

	if (in->base_panel) {
Loading