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

Commit dee24ac1 authored by Tatenda Chipeperekwa's avatar Tatenda Chipeperekwa Committed by Ajay Singh Parmar
Browse files

drm/msm/dp: fix audio notification path for boot up use case



Fix the audio notification path by triggering the sending of
the notification once the audio codec has been registered. This
allows the main display thread to execute until completion,
and for the audio setup to be done asynchronously once the audio
subsystem is ready.

CRs-Fixed: 2118984
Change-Id: Ib0712f983ac86f224fae66ca8ef2a07e3ae76ac2
Signed-off-by: default avatarTatenda Chipeperekwa <tatendac@codeaurora.org>
parent 04aa2a7a
Loading
Loading
Loading
Loading
+99 −31
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ struct dp_audio_private {
	u32 channels;

	struct completion hpd_comp;
	struct workqueue_struct *notify_workqueue;
	struct delayed_work notify_delayed_work;

	struct dp_audio dp_audio;
};
@@ -591,6 +593,24 @@ static int dp_audio_ack_done(struct platform_device *pdev, u32 ack)
	return rc;
}

static int dp_audio_codec_ready(struct platform_device *pdev)
{
	int rc = 0;
	struct dp_audio_private *audio;

	audio = dp_audio_get_data(pdev);
	if (IS_ERR(audio)) {
		pr_err("invalid input\n");
		rc = PTR_ERR(audio);
		goto end;
	}

	queue_delayed_work(audio->notify_workqueue,
			&audio->notify_delayed_work, HZ/4);
end:
	return rc;
}

static int dp_audio_init_ext_disp(struct dp_audio_private *audio)
{
	int rc = 0;
@@ -612,6 +632,7 @@ static int dp_audio_init_ext_disp(struct dp_audio_private *audio)
	ops->get_intf_id        = dp_audio_get_intf_id;
	ops->teardown_done      = dp_audio_teardown_done;
	ops->acknowledge        = dp_audio_ack_done;
	ops->ready              = dp_audio_codec_ready;

	if (!audio->pdev->dev.of_node) {
		pr_err("cannot find audio dev.of_node\n");
@@ -643,6 +664,31 @@ static int dp_audio_init_ext_disp(struct dp_audio_private *audio)
	return rc;
}

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;

	rc = ext->intf_ops.audio_notify(audio->ext_pdev,
			EXT_DISPLAY_TYPE_DP, state);
	if (rc) {
		pr_err("failed to notify audio. state=%d err=%d\n", state, rc);
		goto end;
	}

	reinit_completion(&audio->hpd_comp);
	rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5);
	if (!rc) {
		pr_err("timeout. state=%d err=%d\n", state, rc);
		rc = -ETIMEDOUT;
		goto end;
	}

	pr_debug("success\n");
end:
	return rc;
}

static int dp_audio_on(struct dp_audio *dp_audio)
{
	int rc = 0;
@@ -651,11 +697,14 @@ static int dp_audio_on(struct dp_audio *dp_audio)

	if (!dp_audio) {
		pr_err("invalid input\n");
		rc = -EINVAL;
		goto end;
		return -EINVAL;
	}

	audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
	if (IS_ERR(audio)) {
		pr_err("invalid input\n");
		return -EINVAL;
	}

	ext = &audio->ext_audio_data;

@@ -669,21 +718,9 @@ static int dp_audio_on(struct dp_audio *dp_audio)
		goto end;
	}

	rc = ext->intf_ops.audio_notify(audio->ext_pdev,
			EXT_DISPLAY_TYPE_DP,
			EXT_DISPLAY_CABLE_CONNECT);
	if (rc) {
		pr_err("failed to notify audio, err=%d\n", rc);
		goto end;
	}

	reinit_completion(&audio->hpd_comp);
	rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5);
	if (!rc) {
		pr_err("timeout\n");
		rc = -ETIMEDOUT;
	rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_CONNECT);
	if (rc)
		goto end;
	}

	pr_debug("success\n");
end:
@@ -695,6 +732,7 @@ static int dp_audio_off(struct dp_audio *dp_audio)
	int rc = 0;
	struct dp_audio_private *audio;
	struct msm_ext_disp_init_data *ext;
	bool work_pending = false;

	if (!dp_audio) {
		pr_err("invalid input\n");
@@ -704,21 +742,13 @@ static int dp_audio_off(struct dp_audio *dp_audio)
	audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
	ext = &audio->ext_audio_data;

	rc = ext->intf_ops.audio_notify(audio->ext_pdev,
			EXT_DISPLAY_TYPE_DP,
			EXT_DISPLAY_CABLE_DISCONNECT);
	if (rc) {
		pr_err("failed to notify audio, err=%d\n", rc);
		goto end;
	}
	work_pending = cancel_delayed_work_sync(&audio->notify_delayed_work);
	if (work_pending)
		pr_debug("pending notification work completed\n");

	reinit_completion(&audio->hpd_comp);
	rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5);
	if (!rc) {
		pr_err("timeout\n");
		rc = -ETIMEDOUT;
	rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_DISCONNECT);
	if (rc)
		goto end;
	}

	pr_debug("success\n");
end:
@@ -734,6 +764,35 @@ static int dp_audio_off(struct dp_audio *dp_audio)
	return rc;
}

static void dp_audio_notify_work_fn(struct work_struct *work)
{
	struct dp_audio_private *audio;
	struct delayed_work *dw = to_delayed_work(work);

	audio = container_of(dw, struct dp_audio_private, notify_delayed_work);

	dp_audio_notify(audio, EXT_DISPLAY_CABLE_CONNECT);
}

static int dp_audio_create_notify_workqueue(struct dp_audio_private *audio)
{
	audio->notify_workqueue = create_workqueue("sdm_dp_audio_notify");
	if (IS_ERR_OR_NULL(audio->notify_workqueue)) {
		pr_err("Error creating notify_workqueue\n");
		return -EPERM;
	}

	INIT_DELAYED_WORK(&audio->notify_delayed_work, dp_audio_notify_work_fn);

	return 0;
}

static void dp_audio_destroy_notify_workqueue(struct dp_audio_private *audio)
{
	if (audio->notify_workqueue)
		destroy_workqueue(audio->notify_workqueue);
}

struct dp_audio *dp_audio_get(struct platform_device *pdev,
			struct dp_panel *panel,
			struct dp_catalog_audio *catalog)
@@ -754,6 +813,10 @@ struct dp_audio *dp_audio_get(struct platform_device *pdev,
		goto error;
	}

	rc = dp_audio_create_notify_workqueue(audio);
	if (rc)
		goto error_notify_workqueue;

	init_completion(&audio->hpd_comp);

	audio->pdev = pdev;
@@ -769,13 +832,16 @@ struct dp_audio *dp_audio_get(struct platform_device *pdev,

	rc = dp_audio_init_ext_disp(audio);
	if (rc) {
		devm_kfree(&pdev->dev, audio);
		goto error;
		goto error_ext_disp;
	}

	catalog->init(catalog);

	return dp_audio;
error_ext_disp:
	dp_audio_destroy_notify_workqueue(audio);
error_notify_workqueue:
	devm_kfree(&pdev->dev, audio);
error:
	return ERR_PTR(rc);
}
@@ -790,5 +856,7 @@ void dp_audio_put(struct dp_audio *dp_audio)
	audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
	mutex_destroy(&dp_audio->ops_lock);

	dp_audio_destroy_notify_workqueue(audio);

	devm_kfree(&audio->pdev->dev, audio);
}
+44 −11
Original line number Diff line number Diff line
@@ -147,6 +147,12 @@ static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
	int ret = 0;
	int state;

	if (!ext_disp->ops) {
		pr_err("codec not registered, skip notification\n");
		ret = -EPERM;
		goto end;
	}

	state = ext_disp->audio_sdev.state;
	ret = extcon_set_state_sync(&ext_disp->audio_sdev,
			ext_disp->current_disp, !!new_state);
@@ -155,7 +161,7 @@ static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
			ext_disp->audio_sdev.state == state ?
			"is same" : "switched to",
			ext_disp->audio_sdev.state);

end:
	return ret;
}

@@ -218,14 +224,9 @@ static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp,
		goto end;
	}

	if (!ext_disp->ops) {
		pr_err("codec ops not registered\n");
		ret = -EINVAL;
		goto end;
	}

	if (state == EXT_DISPLAY_CABLE_CONNECT) {
		/* connect codec with interface */
		if (ext_disp->ops)
			*ext_disp->ops = data->codec_ops;

		/* update pdev for interface to use */
@@ -285,6 +286,28 @@ static int msm_ext_disp_audio_notify(struct platform_device *pdev,
	return ret;
}

static void msm_ext_disp_ready_for_display(struct msm_ext_disp *ext_disp)
{
	int ret;
	struct msm_ext_disp_init_data *data = NULL;

	if (!ext_disp) {
		pr_err("invalid input\n");
		return;
	}

	ret = msm_ext_disp_get_intf_data(ext_disp,
		ext_disp->current_disp, &data);
	if (ret) {
		pr_err("%s not found\n",
			msm_ext_disp_name(ext_disp->current_disp));
		return;
	}

	*ext_disp->ops = data->codec_ops;
	data->codec_ops.ready(ext_disp->pdev);
}

int msm_hdmi_register_audio_codec(struct platform_device *pdev,
		struct msm_ext_disp_audio_codec_ops *ops)
{
@@ -334,6 +357,8 @@ int msm_ext_disp_register_audio_codec(struct platform_device *pdev,

end:
	mutex_unlock(&ext_disp->lock);
	if (ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX)
		msm_ext_disp_ready_for_display(ext_disp);

	return ret;
}
@@ -341,6 +366,8 @@ EXPORT_SYMBOL(msm_ext_disp_register_audio_codec);

static int msm_ext_disp_validate_intf(struct msm_ext_disp_init_data *init_data)
{
	struct msm_ext_disp_audio_codec_ops *ops;

	if (!init_data) {
		pr_err("Invalid init_data\n");
		return -EINVAL;
@@ -351,9 +378,15 @@ static int msm_ext_disp_validate_intf(struct msm_ext_disp_init_data *init_data)
		return -EINVAL;
	}

	if (!init_data->codec_ops.get_audio_edid_blk ||
			!init_data->codec_ops.cable_status ||
			!init_data->codec_ops.audio_info_setup) {
	ops = &init_data->codec_ops;

	if (!ops->audio_info_setup   ||
	    !ops->get_audio_edid_blk ||
	    !ops->cable_status       ||
	    !ops->get_intf_id        ||
	    !ops->teardown_done      ||
	    !ops->acknowledge        ||
	    !ops->ready) {
		pr_err("Invalid codec operation pointers\n");
		return -EINVAL;
	}
+2 −0
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ struct msm_ext_disp_intf_ops {
 *  @get_intf_id: id of connected interface
 *  @teardown_done: audio session teardown done by qdsp
 *  @acknowledge: acknowledge audio status received by user modules
 *  @ready: notify audio when codec driver is ready.
 */
struct msm_ext_disp_audio_codec_ops {
	int (*audio_info_setup)(struct platform_device *pdev,
@@ -127,6 +128,7 @@ struct msm_ext_disp_audio_codec_ops {
	int (*get_intf_id)(struct platform_device *pdev);
	void (*teardown_done)(struct platform_device *pdev);
	int (*acknowledge)(struct platform_device *pdev, u32 ack);
	int (*ready)(struct platform_device *pdev);
};

/**