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

Commit 42123387 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/dp: add dp mst audio support" into msm-4.14

parents 281322ba bb3a5de1
Loading
Loading
Loading
Loading
+67 −13
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
@@ -299,8 +299,15 @@ static void dp_audio_isrc_sdp(struct dp_audio_private *audio)

static void dp_audio_setup_sdp(struct dp_audio_private *audio)
{
	/* always program stream 0 first before actual stream cfg */
	audio->catalog->stream_id = DP_STREAM_0;
	audio->catalog->config_sdp(audio->catalog);

	if (audio->panel->stream_id == DP_STREAM_1) {
		audio->catalog->stream_id = DP_STREAM_1;
		audio->catalog->config_sdp(audio->catalog);
	}

	dp_audio_stream_sdp(audio);
	dp_audio_timestamp_sdp(audio);
	dp_audio_infoframe_sdp(audio);
@@ -413,6 +420,12 @@ static int dp_audio_info_setup(struct platform_device *pdev,

	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;
		goto end;
	}

	dp_audio_setup_sdp(audio);
	dp_audio_setup_acr(audio);
	dp_audio_safe_to_exit_level(audio);
@@ -553,18 +566,23 @@ static int dp_audio_codec_ready(struct platform_device *pdev)
	return rc;
}

static int dp_audio_init_ext_disp(struct dp_audio_private *audio)
static int dp_audio_register_ext_disp(struct dp_audio *dp_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;

	ext->type = EXT_DISPLAY_TYPE_DP;
	ext->codec.type = EXT_DISPLAY_TYPE_DP;
	ext->codec.ctrl_id = 0;
	ext->codec.stream_id = audio->panel->stream_id;
	ext->pdev = audio->pdev;
	ext->intf_data = &audio->dp_audio;

@@ -606,13 +624,53 @@ static int dp_audio_init_ext_disp(struct dp_audio_private *audio)
	return rc;
}

static int dp_audio_deregister_ext_disp(struct dp_audio *dp_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;

	if (!audio->pdev->dev.of_node) {
		pr_err("cannot find audio dev.of_node\n");
		rc = -ENODEV;
		goto end;
	}

	pd = of_parse_phandle(audio->pdev->dev.of_node, phandle, 0);
	if (!pd) {
		pr_err("cannot parse %s handle\n", phandle);
		rc = -ENODEV;
		goto end;
	}

	audio->ext_pdev = of_find_device_by_node(pd);
	if (!audio->ext_pdev) {
		pr_err("cannot find %s pdev\n", phandle);
		rc = -ENODEV;
		goto end;
	}

	rc = msm_ext_disp_deregister_intf(audio->ext_pdev, ext);
	if (rc)
		pr_err("failed to deregister disp\n");

end:
	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);
			&ext->codec, state);
	if (rc) {
		pr_err("failed to notify audio. state=%d err=%d\n", state, rc);
		goto end;
@@ -653,7 +711,7 @@ static int dp_audio_on(struct dp_audio *dp_audio)
	audio->session_on = true;

	rc = ext->intf_ops.audio_config(audio->ext_pdev,
			EXT_DISPLAY_TYPE_DP,
			&ext->codec,
			EXT_DISPLAY_CABLE_CONNECT);
	if (rc) {
		pr_err("failed to config audio, err=%d\n", rc);
@@ -695,7 +753,7 @@ static int dp_audio_off(struct dp_audio *dp_audio)
	pr_debug("success\n");
end:
	rc = ext->intf_ops.audio_config(audio->ext_pdev,
			EXT_DISPLAY_TYPE_DP,
			&ext->codec,
			EXT_DISPLAY_CABLE_DISCONNECT);
	if (rc)
		pr_err("failed to config audio, err=%d\n", rc);
@@ -771,17 +829,13 @@ struct dp_audio *dp_audio_get(struct platform_device *pdev,

	dp_audio->on  = dp_audio_on;
	dp_audio->off = dp_audio_off;

	rc = dp_audio_init_ext_disp(audio);
	if (rc) {
		goto error_ext_disp;
	}
	dp_audio->register_ext_disp = dp_audio_register_ext_disp;
	dp_audio->deregister_ext_disp = dp_audio_deregister_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:
+23 −1
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
@@ -52,6 +52,28 @@ 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);
};

/**
+16 −6
Original line number Diff line number Diff line
@@ -1678,16 +1678,26 @@ static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio)
{
	struct dp_catalog_private *catalog;
	struct dp_io_data *io_data;
	u32 sdp_cfg = 0;
	u32 sdp_cfg2 = 0;
	u32 sdp_cfg = 0, sdp_cfg_off = 0;
	u32 sdp_cfg2 = 0, sdp_cfg2_off = 0;

	if (!audio)
		return;

	if (audio->stream_id >= DP_STREAM_MAX) {
		pr_err("invalid stream id:%d\n", audio->stream_id);
		return;
	}

	if (audio->stream_id == DP_STREAM_1) {
		sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG;
		sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2;
	}

	catalog = dp_catalog_get_priv(audio);
	io_data = catalog->io.dp_link;

	sdp_cfg = dp_read(catalog, io_data, MMSS_DP_SDP_CFG);
	sdp_cfg = dp_read(catalog, io_data, MMSS_DP_SDP_CFG + sdp_cfg_off);

	/* AUDIO_TIMESTAMP_SDP_EN */
	sdp_cfg |= BIT(1);
@@ -1701,16 +1711,16 @@ static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio)
	sdp_cfg |= BIT(20);

	pr_debug("sdp_cfg = 0x%x\n", sdp_cfg);
	dp_write(catalog, io_data, MMSS_DP_SDP_CFG, sdp_cfg);
	dp_write(catalog, io_data, MMSS_DP_SDP_CFG + sdp_cfg_off, sdp_cfg);

	sdp_cfg2 = dp_read(catalog, io_data, MMSS_DP_SDP_CFG2);
	sdp_cfg2 = dp_read(catalog, io_data, MMSS_DP_SDP_CFG2 + sdp_cfg_off);
	/* IFRM_REGSRC -> Do not use reg values */
	sdp_cfg2 &= ~BIT(0);
	/* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */
	sdp_cfg2 &= ~BIT(1);

	pr_debug("sdp_cfg2 = 0x%x\n", sdp_cfg2);
	dp_write(catalog, io_data, MMSS_DP_SDP_CFG2, sdp_cfg2);
	dp_write(catalog, io_data, MMSS_DP_SDP_CFG2 + sdp_cfg_off, sdp_cfg2);
}

static void dp_catalog_audio_get_header(struct dp_catalog_audio *audio)
+2 −0
Original line number Diff line number Diff line
@@ -155,6 +155,8 @@ struct dp_catalog_audio {
	enum dp_catalog_audio_header_type sdp_header;
	u32 data;

	enum dp_stream_id stream_id;

	void (*init)(struct dp_catalog_audio *audio);
	void (*enable)(struct dp_catalog_audio *audio);
	void (*config_acr)(struct dp_catalog_audio *audio);
+7 −5
Original line number Diff line number Diff line
@@ -135,7 +135,7 @@ static void dp_catalog_panel_config_msa_v420(struct dp_catalog_panel *panel,
					bool fixed_nvid)
{
	u32 pixel_m, pixel_n;
	u32 mvid, nvid, reg_off = 0;
	u32 mvid, nvid, reg_off = 0, mvid_off = 0, nvid_off = 0;
	u64 mvid_calc;
	u32 const nvid_fixed = 0x8000;
	u32 const link_rate_hbr2 = 540000;
@@ -199,12 +199,14 @@ static void dp_catalog_panel_config_msa_v420(struct dp_catalog_panel *panel,

	io_data = catalog->io->dp_link;

	if (panel->stream_id == DP_STREAM_1)
		reg_off = DP1_SOFTWARE_MVID - DP_SOFTWARE_MVID;
	if (panel->stream_id == DP_STREAM_1) {
		mvid_off = DP1_SOFTWARE_MVID - DP_SOFTWARE_MVID;
		nvid_off = DP1_SOFTWARE_NVID - DP_SOFTWARE_NVID;
	}

	pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
	dp_write(catalog, io_data, DP_SOFTWARE_MVID + reg_off, mvid);
	dp_write(catalog, io_data, DP_SOFTWARE_NVID + reg_off, nvid);
	dp_write(catalog, io_data, DP_SOFTWARE_MVID + mvid_off, mvid);
	dp_write(catalog, io_data, DP_SOFTWARE_NVID + nvid_off, nvid);
}

static void dp_catalog_ctrl_phy_lane_cfg_v420(struct dp_catalog_ctrl *ctrl,
Loading