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

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

Merge "mdss: DisplayPort: update link-training settings and do DP reset"

parents 5cdf898e 92618b15
Loading
Loading
Loading
Loading
+70 −13
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/iopoll.h>
#include <linux/delay.h>
#include <linux/clk/msm-clock-generic.h>
#include <linux/usb/usbpd.h>

#include "mdss-pll.h"
#include "mdss-dp-pll.h"
@@ -172,9 +173,27 @@ int dp_config_vco_rate(struct dp_pll_vco_clk *vco, unsigned long rate)
{
	u32 res = 0;
	struct mdss_pll_resources *dp_res = vco->priv;
	u8 orientation, ln_cnt;
	u32 spare_value;

	spare_value = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_SPARE0);
	ln_cnt = spare_value & 0x0F;
	orientation = (spare_value & 0xF0) >> 4;
	pr_debug("%s: spare_value=0x%x, ln_cnt=0x%x, orientation=0x%x\n",
				__func__, spare_value, ln_cnt, orientation);

	if (ln_cnt != 4) {
		if (orientation == ORIENTATION_CC2)
			MDSS_PLL_REG_W(dp_res->phy_base,
				DP_PHY_PD_CTL, 0x2d);
		else
			MDSS_PLL_REG_W(dp_res->phy_base,
				DP_PHY_PD_CTL, 0x35);
	} else {
		MDSS_PLL_REG_W(dp_res->phy_base,
				DP_PHY_PD_CTL, 0x3d);
	}

	/* Make sure the PHY register writes are done */
	wmb();
	MDSS_PLL_REG_W(dp_res->pll_base,
@@ -314,8 +333,13 @@ int dp_config_vco_rate(struct dp_pll_vco_clk *vco, unsigned long rate)
	/* Make sure the PLL register writes are done */
	wmb();

	if (orientation == ORIENTATION_CC2)
		MDSS_PLL_REG_W(dp_res->phy_base,
				DP_PHY_MODE, 0x48);
	else
		MDSS_PLL_REG_W(dp_res->phy_base,
				DP_PHY_MODE, 0x58);

	MDSS_PLL_REG_W(dp_res->phy_base,
			DP_PHY_TX0_TX1_LANE_CTL, 0x05);
	MDSS_PLL_REG_W(dp_res->phy_base,
@@ -427,6 +451,12 @@ static int dp_pll_enable(struct clk *c)
	u32 status;
	struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
	struct mdss_pll_resources *dp_res = vco->priv;
	u8 orientation, ln_cnt;
	u32 spare_value, bias_en, drvr_en;

	spare_value = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_SPARE0);
	ln_cnt = spare_value & 0x0F;
	orientation = (spare_value & 0xF0) >> 4;

	MDSS_PLL_REG_W(dp_res->phy_base,
			DP_PHY_CFG, 0x01);
@@ -474,18 +504,45 @@ static int dp_pll_enable(struct clk *c)

	pr_debug("%s: PLL is locked\n", __func__);

	if (ln_cnt == 1) {
		bias_en = 0x3e;
		drvr_en = 0x13;
	} else {
		bias_en = 0x3f;
		drvr_en = 0x10;
	}

	if (ln_cnt != 4) {
		if (orientation == ORIENTATION_CC1) {
			MDSS_PLL_REG_W(dp_res->phy_base,
			QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
			0x3f);
			bias_en);
			MDSS_PLL_REG_W(dp_res->phy_base,
			QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN,
			0x10);
			drvr_en);
		} else {
			MDSS_PLL_REG_W(dp_res->phy_base,
			QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
			bias_en);
			MDSS_PLL_REG_W(dp_res->phy_base,
			QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN,
			drvr_en);
		}
	} else {
		MDSS_PLL_REG_W(dp_res->phy_base,
			QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
			0x3f);
			bias_en);
		MDSS_PLL_REG_W(dp_res->phy_base,
			QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN,
			0x10);
			drvr_en);
		MDSS_PLL_REG_W(dp_res->phy_base,
			QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
			bias_en);
		MDSS_PLL_REG_W(dp_res->phy_base,
			QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN,
			drvr_en);
	}

	MDSS_PLL_REG_W(dp_res->phy_base,
			QSERDES_TX0_OFFSET + TXn_TX_POL_INV,
			0x0a);
@@ -615,7 +672,7 @@ int dp_vco_prepare(struct clk *c)
	rc = dp_pll_enable(c);
	if (rc) {
		mdss_pll_resource_enable(dp_pll_res, false);
		pr_err("ndx=%d failed to enable dsi pll\n",
		pr_err("ndx=%d failed to enable dp pll\n",
					dp_pll_res->index);
		goto error;
	}
+1 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#define DP_PHY_TX0_TX1_LANE_CTL			0x0068

#define DP_PHY_TX2_TX3_LANE_CTL			0x0084
#define DP_PHY_SPARE0				0x00A8
#define DP_PHY_STATUS				0x00BC

/* Tx registers */
+95 −24
Original line number Diff line number Diff line
@@ -789,17 +789,34 @@ void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *dp)

	cap = &dp->dpcd;

	data = dp->lane_cnt - 1;
	data <<= 4;
	data |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK  */

	/* Color Format */
	switch (dp->panel_data.panel_info.out_format) {
	case MDP_Y_CBCR_H2V2:
		data |= (1 << 11); /* YUV420 */
		break;
	case MDP_Y_CBCR_H2V1:
		data |= (2 << 11); /* YUV422 */
		break;
	default:
		data |= (0 << 11); /* RGB */
		break;
	}

	/* Scrambler reset enable */
	if (cap->scrambler_reset)
		data |= (1 << 10);

	if (dp->edid.color_depth != 6)
		data |= 0x100;	/* Default: 8 bits */

	/* Num of Lanes */
	data |= ((dp->lane_cnt - 1) << 4);

	if (cap->enhanced_frame)
		data |= 0x40;

	if (dp->edid.color_depth == 8) {
		/* 0 == 6 bits, 1 == 8 bits */
		data |= 0x100;	/* bit 8 */
	}

	if (!timing->interlaced)	/* progressive */
		data |= 0x04;

@@ -863,6 +880,8 @@ static int dp_audio_info_setup(struct platform_device *pdev,
	mdss_dp_set_safe_to_exit_level(&dp_ctrl->ctrl_io, dp_ctrl->lane_cnt);
	mdss_dp_audio_enable(&dp_ctrl->ctrl_io, true);

	dp_ctrl->wait_for_audio_comp = true;

	return rc;
} /* dp_audio_info_setup */

@@ -885,6 +904,17 @@ static int dp_get_audio_edid_blk(struct platform_device *pdev,
	return rc;
} /* dp_get_audio_edid_blk */

static void dp_audio_codec_teardown_done(struct platform_device *pdev)
{
	struct mdss_dp_drv_pdata *dp = platform_get_drvdata(pdev);

	if (!dp)
		pr_err("invalid input\n");

	pr_debug("audio codec teardown done\n");
	complete_all(&dp->audio_comp);
}

static int mdss_dp_init_ext_disp(struct mdss_dp_drv_pdata *dp)
{
	int ret = 0;
@@ -906,6 +936,8 @@ static int mdss_dp_init_ext_disp(struct mdss_dp_drv_pdata *dp)
		dp_get_audio_edid_blk;
	dp->ext_audio_data.codec_ops.cable_status =
		dp_get_cable_status;
	dp->ext_audio_data.codec_ops.teardown_done =
		dp_audio_codec_teardown_done;

	if (!dp->pdev->dev.of_node) {
		pr_err("%s cannot find dp dev.of_node\n", __func__);
@@ -987,6 +1019,13 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic)
	return 0;
} /* dp_init_panel_info */

static inline void mdss_dp_set_audio_switch_node(
	struct mdss_dp_drv_pdata *dp, int val)
{
	if (dp && dp->ext_audio_data.intf_ops.notify)
		dp->ext_audio_data.intf_ops.notify(dp->ext_pdev,
				val);
}

int mdss_dp_on(struct mdss_panel_data *pdata)
{
@@ -1054,6 +1093,9 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
			goto exit;
		}

		mdss_dp_phy_share_lane_config(&dp_drv->phy_io,
				orientation, dp_drv->dpcd.max_lane_count);

		pr_debug("link_rate = 0x%x\n", dp_drv->link_rate);

		dp_drv->power_data[DP_CTRL_PM].clk_config[0].rate =
@@ -1096,6 +1138,7 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
		pr_debug("mainlink ready\n");

	dp_drv->power_on = true;
	mdss_dp_set_audio_switch_node(dp_drv, true);
	pr_debug("End-\n");

exit:
@@ -1119,14 +1162,15 @@ int mdss_dp_off(struct mdss_panel_data *pdata)
	mutex_lock(&dp_drv->train_mutex);

	reinit_completion(&dp_drv->idle_comp);

	mdss_dp_state_ctrl(&dp_drv->ctrl_io, 0);
	mdss_dp_state_ctrl(&dp_drv->ctrl_io, ST_PUSH_IDLE);

	if (dp_drv->link_clks_on)
		mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false);

	mdss_dp_aux_ctrl(&dp_drv->ctrl_io, false);

	mdss_dp_audio_enable(&dp_drv->ctrl_io, false);

	mdss_dp_irq_disable(dp_drv);

	mdss_dp_config_gpios(dp_drv, false);
@@ -1147,14 +1191,6 @@ int mdss_dp_off(struct mdss_panel_data *pdata)
	return 0;
}

static inline void mdss_dp_set_audio_switch_node(
	struct mdss_dp_drv_pdata *dp, int val)
{
	if (dp && dp->ext_audio_data.intf_ops.notify)
		dp->ext_audio_data.intf_ops.notify(dp->ext_pdev,
				val);
}

static void mdss_dp_send_cable_notification(
	struct mdss_dp_drv_pdata *dp, int val)
{
@@ -1169,6 +1205,38 @@ static void mdss_dp_send_cable_notification(
				dp->ext_audio_data.type, val);
}

static void mdss_dp_audio_codec_wait(struct mdss_dp_drv_pdata *dp)
{
	const int audio_completion_timeout_ms = HZ * 3;
	int ret = 0;

	if (!dp->wait_for_audio_comp)
		return;

	reinit_completion(&dp->audio_comp);
	ret = wait_for_completion_timeout(&dp->audio_comp,
			audio_completion_timeout_ms);
	if (ret <= 0)
		pr_warn("audio codec teardown timed out\n");

	dp->wait_for_audio_comp = false;
}

static void mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, bool enable)
{
	if (enable) {
		mdss_dp_send_cable_notification(dp, enable);
	} else {
		mdss_dp_set_audio_switch_node(dp, enable);
		mdss_dp_audio_codec_wait(dp);
		mdss_dp_send_cable_notification(dp, enable);
	}

	pr_debug("notify state %s done\n",
			enable ? "ENABLE" : "DISABLE");
}


static int mdss_dp_edid_init(struct mdss_panel_data *pdata)
{
	struct mdss_dp_drv_pdata *dp_drv = NULL;
@@ -1236,15 +1304,19 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)

	mdss_dp_aux_init(dp_drv);

	mdss_dp_phy_initialize(dp_drv);
	mdss_dp_ctrl_reset(&dp_drv->ctrl_io);
	mdss_dp_phy_reset(&dp_drv->ctrl_io);
	mdss_dp_aux_reset(&dp_drv->ctrl_io);
	mdss_dp_phy_initialize(dp_drv);
	mdss_dp_aux_ctrl(&dp_drv->ctrl_io, true);

	pr_debug("Ctrl_hw_rev =0x%x, phy hw_rev =0x%x\n",
	       mdss_dp_get_ctrl_hw_version(&dp_drv->ctrl_io),
	       mdss_dp_get_phy_hw_version(&dp_drv->phy_io));

	pr_debug("plug Orientation = %d\n",
			usbpd_get_plug_orientation(dp_drv->pd));

	mdss_dp_phy_aux_setup(&dp_drv->phy_io);

	mdss_dp_irq_enable(dp_drv);
@@ -1264,8 +1336,7 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)
		goto edid_error;
	}

	mdss_dp_send_cable_notification(dp_drv, true);
	mdss_dp_set_audio_switch_node(dp_drv, true);
	mdss_dp_notify_clients(dp_drv, true);
	dp_drv->dp_initialized = true;

	return ret;
@@ -1771,8 +1842,7 @@ static void dp_send_events(struct mdss_dp_drv_pdata *dp, u32 events)
{
	spin_lock(&dp->event_lock);
	dp->current_event = events;
	queue_delayed_work(dp->workq,
				&dp->dwork, HZ);
	queue_delayed_work(dp->workq, &dp->dwork, HZ / 100);
	spin_unlock(&dp->event_lock);
}

@@ -1883,8 +1953,7 @@ static void usbpd_disconnect_callback(struct usbpd_svid_handler *hdlr)
	mutex_lock(&dp_drv->pd_msg_mutex);
	dp_drv->cable_connected = false;
	mutex_unlock(&dp_drv->pd_msg_mutex);
	mdss_dp_send_cable_notification(dp_drv, false);
	mdss_dp_set_audio_switch_node(dp_drv, false);
	mdss_dp_notify_clients(dp_drv, false);
}

static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
@@ -2135,6 +2204,8 @@ static int mdss_dp_probe(struct platform_device *pdev)
	mdss_dp_device_register(dp_drv);

	dp_drv->inited = true;
	dp_drv->wait_for_audio_comp = false;
	init_completion(&dp_drv->audio_comp);

	pr_debug("done\n");

+2 −0
Original line number Diff line number Diff line
@@ -399,6 +399,7 @@ struct mdss_dp_drv_pdata {
	struct completion train_comp;
	struct completion idle_comp;
	struct completion video_comp;
	struct completion audio_comp;
	struct mutex aux_mutex;
	struct mutex train_mutex;
	struct mutex pd_msg_mutex;
@@ -423,6 +424,7 @@ struct mdss_dp_drv_pdata {
	char delay_start;
	u32 bpp;
	struct dp_statistic dp_stat;
	bool wait_for_audio_comp;

	/* event */
	struct workqueue_struct *workq;
+7 −7
Original line number Diff line number Diff line
@@ -1113,17 +1113,17 @@ static void dp_host_train_set(struct mdss_dp_drv_pdata *ep, int train)
}

char vm_pre_emphasis[4][4] = {
	{0x00, 0x06, 0x09, 0x0C},	/* pe0, 0 db */
	{0x00, 0x06, 0x09, 0xFF},	/* pe1, 3.5 db */
	{0x03, 0x06, 0xFF, 0xFF},	/* pe2, 6.0 db */
	{0x03, 0xFF, 0xFF, 0xFF}	/* pe3, 9.5 db */
	{0x00, 0x09, 0x11, 0x0C},	/* pe0, 0 db */
	{0x00, 0x0A, 0x10, 0xFF},	/* pe1, 3.5 db */
	{0x00, 0x0C, 0xFF, 0xFF},	/* pe2, 6.0 db */
	{0x00, 0xFF, 0xFF, 0xFF}	/* pe3, 9.5 db */
};

/* voltage swing, 0.2v and 1.0v are not support */
char vm_voltage_swing[4][4] = {
	{0x0a, 0x18, 0x1A, 0x1E}, /* sw0, 0.4v  */
	{0x07, 0x1A, 0x1E, 0xFF}, /* sw1, 0.6 v */
	{0x1A, 0x1E, 0xFF, 0xFF}, /* sw1, 0.8 v */
	{0x07, 0x0f, 0x12, 0x1E}, /* sw0, 0.4v  */
	{0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */
	{0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
	{0x1E, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
};

Loading