All of lore.kernel.org
 help / color / mirror / Atom feed
From: CK Hu <ck.hu@mediatek.com>
To: Bo-Chen Chen <rex-bc.chen@mediatek.com>,
	<chunkuang.hu@kernel.org>, <p.zabel@pengutronix.de>,
	<daniel@ffwll.ch>, <robh+dt@kernel.org>,
	<krzysztof.kozlowski+dt@linaro.org>, <mripard@kernel.org>,
	<tzimmermann@suse.de>, <matthias.bgg@gmail.com>, <deller@gmx.de>,
	<airlied@linux.ie>
Cc: <msp@baylibre.com>, <granquet@baylibre.com>,
	<jitao.shi@mediatek.com>, <wenst@chromium.org>,
	<angelogioacchino.delregno@collabora.com>,
	<liangxu.xu@mediatek.com>, <dri-devel@lists.freedesktop.org>,
	<linux-mediatek@lists.infradead.org>,
	<devicetree@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-fbdev@vger.kernel.org>,
	<Project_Global_Chrome_Upstream_Group@mediatek.com>
Subject: Re: [PATCH v15 06/11] drm/mediatek: Add MT8195 External DisplayPort support
Date: Tue, 2 Aug 2022 10:37:41 +0800	[thread overview]
Message-ID: <4d54b439fab8b888598677e1e52fb098c9b93e03.camel@mediatek.com> (raw)
In-Reply-To: <20220727045035.32225-7-rex-bc.chen@mediatek.com>

Hi, Bo-Chen:

On Wed, 2022-07-27 at 12:50 +0800, Bo-Chen Chen wrote:
> From: Guillaume Ranquet <granquet@baylibre.com>
> 
> This patch adds External DisplayPort support to the mt8195 eDP
> driver.
> 
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_dp.c     | 181 +++++++++++++++++++++---
> --
>  drivers/gpu/drm/mediatek/mtk_dp_reg.h |   1 +
>  2 files changed, 146 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c
> b/drivers/gpu/drm/mediatek/mtk_dp.c
> index 06eeecedd49e..ce817cb59445 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> @@ -103,6 +103,11 @@ static struct regmap_config mtk_dp_regmap_config
> = {
>  	.name = "mtk-dp-registers",
>  };
>  
> +static bool mtk_dp_is_edp(struct mtk_dp *mtk_dp)
> +{
> +	return mtk_dp->next_bridge;

For external DP, it could also connect to a bridge IC which transfer DP
to HDMI or some interface else. Use the compatible to judge this edp or
dp.

> +}
> +
>  static struct mtk_dp *mtk_dp_from_bridge(struct drm_bridge *b)
>  {
>  	return container_of(b, struct mtk_dp, bridge);
> @@ -341,6 +346,19 @@ static void mtk_dp_pg_enable(struct mtk_dp
> *mtk_dp, bool enable)
>  			   4 << PGEN_PATTERN_SEL_SHIFT,
> PGEN_PATTERN_SEL_MASK);
>  }
>  
> +static bool mtk_dp_plug_state(struct mtk_dp *mtk_dp)
> +{
> +	return mtk_dp->train_info.cable_plugged_in;
> +}
> +
> +static bool mtk_dp_plug_state_avoid_pulse(struct mtk_dp *mtk_dp)
> +{
> +	bool ret;
> +
> +	return !(readx_poll_timeout(mtk_dp_plug_state, mtk_dp, ret,
> ret,
> +				    4000, 7 * 4000));
> +}
> +
>  static void mtk_dp_aux_irq_clear(struct mtk_dp *mtk_dp)
>  {
>  	mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3640,
> @@ -778,35 +796,67 @@ static void mtk_dp_get_calibration_data(struct
> mtk_dp *mtk_dp)
>  		return;
>  	}
>  
> -	cal_data->glb_bias_trim =
> -		check_cal_data_valid(mtk_dp, 1, 0x1e,
> -				     (buf[3] >> 27) & 0x1f, 0xf);
> -	cal_data->clktx_impse =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[0] >> 9) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[0] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 28) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[0] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 24) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[1] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 20) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[1] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 16) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[2] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 12) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[2] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 8) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[3] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 4) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[3] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe, buf[2] & 0xf,
> 0x8);
> +	if (mtk_dp_is_edp(mtk_dp)) {
> +		cal_data->glb_bias_trim =
> +			check_cal_data_valid(mtk_dp, 1, 0x1e,
> +					     (buf[3] >> 27) & 0x1f,
> 0xf);
> +		cal_data->clktx_impse =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[0] >> 9) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_pmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 28) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 24) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 20) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 16) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 12) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 8) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_pmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 4) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_nmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe, buf[2] &
> 0xf, 0x8);
> +	} else {
> +		cal_data->glb_bias_trim =
> +			check_cal_data_valid(mtk_dp, 1, 0x1e,
> +					     (buf[0] >> 27) & 0x1f,
> 0xf);

Why not place glb_bias_trim value in nvmem buf[3] for both edp and dp
case? Place in the same nvmem position, the driver code would be
simple. 

> +		cal_data->clktx_impse =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[0] >> 13) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 28) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 24) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 20) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 16) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 12) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 8) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_pmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 4) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_nmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe, buf[1] &
> 0xf, 0x8);

Why not place ln_tx_impsel_nmos and ln_tx_impsel_pmos value in nvmem
buf[2] for both edp and dp case? Place in the same nvmem position, the
driver code would be simple. 

> +	}
>  
>  	kfree(buf);
>  }
> @@ -926,7 +976,10 @@ static void mtk_dp_video_mute(struct mtk_dp
> *mtk_dp, bool enable)
>  			   VIDEO_MUTE_SEL_DP_ENC0_P0_MASK |
>  			   VIDEO_MUTE_SW_DP_ENC0_P0_MASK);
>  
> -	mtk_dp_sip_atf_call(mtk_dp, MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE,
> enable);
> +	mtk_dp_sip_atf_call(mtk_dp,
> +			    mtk_dp_is_edp(mtk_dp) ?
> +			    MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE :
> +			    MTK_DP_SIP_ATF_VIDEO_UNMUTE, enable);

Use of_device_get_match_data to select MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE
or MTK_DP_SIP_ATF_VIDEO_UNMUTE.

>  }
>  
>  static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
> @@ -1226,6 +1279,9 @@ static int mtk_dp_parse_capabilities(struct
> mtk_dp *mtk_dp)
>  	drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER,
> DP_SET_POWER_D0);
>  	usleep_range(2000, 5000);
>  
> +	if (!mtk_dp_plug_state(mtk_dp))
> +		return -ENODEV;
> +
>  	drm_dp_read_dpcd_caps(&mtk_dp->aux, mtk_dp->rx_cap);
>  
>  	train_info->link_rate = min_t(int, mtk_dp->max_linkrate,
> @@ -1277,6 +1333,9 @@ static int mtk_dp_train_start(struct mtk_dp
> *mtk_dp)
>  	u8 train_limit;
>  	u8 max_link_rate;
>  
> +	if (!mtk_dp_plug_state_avoid_pulse(mtk_dp))
> +		return -ENODEV;
> +
>  	link_rate = mtk_dp->rx_cap[1];
>  	lane_count = mtk_dp->rx_cap[2] & 0x1F;
>  
> @@ -1412,6 +1471,9 @@ static irqreturn_t mtk_dp_hpd_event_thread(int
> hpd, void *dev)
>  {
>  	struct mtk_dp *mtk_dp = dev;
>  
> +	dev_dbg(mtk_dp->dev, "drm_helper_hpd_irq_event\n");
> +	drm_helper_hpd_irq_event(mtk_dp->bridge.dev);

Because edp also have hpd interrupt, so I would like both edp and dp
have the same control flow for hdp. So move this to edp patch.

> +
>  	if (mtk_dp->train_info.hpd_inerrupt) {
>  		dev_dbg(mtk_dp->dev, "MTK_DP_HPD_INTERRUPT\n");
>  		mtk_dp->train_info.hpd_inerrupt = false;
> @@ -1452,9 +1514,20 @@ static irqreturn_t mtk_dp_hpd_event(int hpd,
> void *dev)
>  		else
>  			train_info->cable_plugged_in = false;
>  
> -		mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
> -				   DP_PWR_STATE_BANDGAP_TPLL_LANE,
> -				   DP_PWR_STATE_MASK);
> +		if (!train_info->cable_plugged_in) {
> +			mtk_dp_video_mute(mtk_dp, true);
> +
> +			mtk_dp_initialize_priv_data(mtk_dp);
> +			mtk_dp_set_idle_pattern(mtk_dp, true);
> +
> +			mtk_dp_update_bits(mtk_dp,
> MTK_DP_TOP_PWR_STATE,
> +					   DP_PWR_STATE_BANDGAP_TPLL,
> +					   DP_PWR_STATE_MASK);
> +		} else {
> +			mtk_dp_update_bits(mtk_dp,
> MTK_DP_TOP_PWR_STATE,
> +					   DP_PWR_STATE_BANDGAP_TPLL_LA
> NE,
> +					   DP_PWR_STATE_MASK);
> +		}
>  	}
>  
>  	return IRQ_HANDLED;
> @@ -1499,6 +1572,24 @@ static int mtk_dp_dt_parse(struct mtk_dp
> *mtk_dp,
>  	return 0;
>  }
>  
> +static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge
> *bridge)
> +{
> +	struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> +	enum drm_connector_status ret = connector_status_disconnected;
> +	u8 sink_count = 0;
> +
> +	if (mtk_dp_is_edp(mtk_dp))
> +		return connector_status_connected;

Because edp also have hpd interrupt, so I would like both edp and dp
have the same control flow for hdp. So remove this.

> +
> +	if (mtk_dp_plug_state_avoid_pulse(mtk_dp)) {
> +		drm_dp_dpcd_readb(&mtk_dp->aux, DP_SINK_COUNT,
> &sink_count);
> +		if (DP_GET_SINK_COUNT(sink_count))
> +			ret = connector_status_connected;
> +	}
> +
> +	return ret;
> +}
> +
>  static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
>  				    struct drm_connector *connector)
>  {
> @@ -1512,7 +1603,8 @@ static struct edid *mtk_dp_get_edid(struct
> drm_bridge *bridge,
>  	drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER,
> DP_SET_POWER_D0);
>  	usleep_range(2000, 5000);
>  
> -	new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
> +	if (mtk_dp_plug_state(mtk_dp))
> +		new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);

Please explain why only dp has this problem. If edp also has this
problem, move this to edp patch.

Regards,
CK

>  
>  	if (!enabled)
>  		drm_bridge_chain_post_disable(bridge);
> @@ -1852,6 +1944,7 @@ static const struct drm_bridge_funcs
> mtk_dp_bridge_funcs = {
>  	.atomic_disable = mtk_dp_bridge_atomic_disable,
>  	.mode_valid = mtk_dp_bridge_mode_valid,
>  	.get_edid = mtk_dp_get_edid,
> +	.detect = mtk_dp_bdg_detect,
>  };
>  
>  static int mtk_dp_probe(struct platform_device *pdev)
> @@ -1873,9 +1966,15 @@ static int mtk_dp_probe(struct platform_device
> *pdev)
>  				     "failed to request dp irq
> resource\n");
>  
>  	mtk_dp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 
> 1, 0);
> -	if (IS_ERR(mtk_dp->next_bridge))
> +	if (IS_ERR(mtk_dp->next_bridge) &&
> +	    PTR_ERR(mtk_dp->next_bridge) == -ENODEV) {
> +		dev_info(dev,
> +			 "No panel connected in devicetree, continue as
> external DP\n");
> +		mtk_dp->next_bridge = NULL;
> +	} else if (IS_ERR(mtk_dp->next_bridge)) {
>  		return dev_err_probe(dev, PTR_ERR(mtk_dp->next_bridge),
>  				     "Failed to get bridge\n");
> +	}
>  
>  	ret = mtk_dp_dt_parse(mtk_dp, pdev);
>  	if (ret)
> @@ -1918,7 +2017,10 @@ static int mtk_dp_probe(struct platform_device
> *pdev)
>  
>  	mtk_dp->bridge.ops =
>  		DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
> DRM_BRIDGE_OP_HPD;
> -	mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
> +	if (mtk_dp_is_edp(mtk_dp))
> +		mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
> +	else
> +		mtk_dp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
>  
>  	drm_bridge_add(&mtk_dp->bridge);
>  
> @@ -1945,6 +2047,12 @@ static int mtk_dp_suspend(struct device *dev)
>  {
>  	struct mtk_dp *mtk_dp = dev_get_drvdata(dev);
>  
> +	if (mtk_dp_plug_state(mtk_dp)) {
> +		drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER,
> DP_SET_POWER_D3);
> +		/* Ensure the sink is off before shutting down power */
> +		usleep_range(2000, 3000);
> +	}
> +
>  	mtk_dp_power_disable(mtk_dp);
>  
>  	mtk_dp_hwirq_enable(mtk_dp, false);
> @@ -1978,6 +2086,7 @@ static SIMPLE_DEV_PM_OPS(mtk_dp_pm_ops,
> mtk_dp_suspend, mtk_dp_resume);
>  
>  static const struct of_device_id mtk_dp_of_match[] = {
>  	{ .compatible = "mediatek,mt8195-edp-tx" },
> +	{ .compatible = "mediatek,mt8195-dp-tx" },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, mtk_dp_of_match);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> index 4ff8e9880dc9..59086eb82868 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> @@ -14,6 +14,7 @@
>  #define SEC_OFFSET	0x4000
>  
>  #define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE	(BIT(0) | BIT(5))
> +#define MTK_DP_SIP_ATF_VIDEO_UNMUTE	BIT(5)
>  
>  #define DP_PHY_GLB_BIAS_GEN_00		0
>  #define RG_XTP_GLB_BIAS_INTR_CTRL	GENMASK(20, 16)


WARNING: multiple messages have this Message-ID (diff)
From: CK Hu <ck.hu@mediatek.com>
To: Bo-Chen Chen <rex-bc.chen@mediatek.com>,
	<chunkuang.hu@kernel.org>, <p.zabel@pengutronix.de>,
	<daniel@ffwll.ch>, <robh+dt@kernel.org>,
	<krzysztof.kozlowski+dt@linaro.org>, <mripard@kernel.org>,
	<tzimmermann@suse.de>, <matthias.bgg@gmail.com>, <deller@gmx.de>,
	<airlied@linux.ie>
Cc: devicetree@vger.kernel.org, linux-fbdev@vger.kernel.org,
	granquet@baylibre.com, jitao.shi@mediatek.com,
	liangxu.xu@mediatek.com, linux-kernel@vger.kernel.org,
	dri-devel@lists.freedesktop.org, msp@baylibre.com,
	Project_Global_Chrome_Upstream_Group@mediatek.com,
	linux-mediatek@lists.infradead.org, wenst@chromium.org,
	linux-arm-kernel@lists.infradead.org,
	angelogioacchino.delregno@collabora.com
Subject: Re: [PATCH v15 06/11] drm/mediatek: Add MT8195 External DisplayPort support
Date: Tue, 2 Aug 2022 10:37:41 +0800	[thread overview]
Message-ID: <4d54b439fab8b888598677e1e52fb098c9b93e03.camel@mediatek.com> (raw)
In-Reply-To: <20220727045035.32225-7-rex-bc.chen@mediatek.com>

Hi, Bo-Chen:

On Wed, 2022-07-27 at 12:50 +0800, Bo-Chen Chen wrote:
> From: Guillaume Ranquet <granquet@baylibre.com>
> 
> This patch adds External DisplayPort support to the mt8195 eDP
> driver.
> 
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_dp.c     | 181 +++++++++++++++++++++---
> --
>  drivers/gpu/drm/mediatek/mtk_dp_reg.h |   1 +
>  2 files changed, 146 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c
> b/drivers/gpu/drm/mediatek/mtk_dp.c
> index 06eeecedd49e..ce817cb59445 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> @@ -103,6 +103,11 @@ static struct regmap_config mtk_dp_regmap_config
> = {
>  	.name = "mtk-dp-registers",
>  };
>  
> +static bool mtk_dp_is_edp(struct mtk_dp *mtk_dp)
> +{
> +	return mtk_dp->next_bridge;

For external DP, it could also connect to a bridge IC which transfer DP
to HDMI or some interface else. Use the compatible to judge this edp or
dp.

> +}
> +
>  static struct mtk_dp *mtk_dp_from_bridge(struct drm_bridge *b)
>  {
>  	return container_of(b, struct mtk_dp, bridge);
> @@ -341,6 +346,19 @@ static void mtk_dp_pg_enable(struct mtk_dp
> *mtk_dp, bool enable)
>  			   4 << PGEN_PATTERN_SEL_SHIFT,
> PGEN_PATTERN_SEL_MASK);
>  }
>  
> +static bool mtk_dp_plug_state(struct mtk_dp *mtk_dp)
> +{
> +	return mtk_dp->train_info.cable_plugged_in;
> +}
> +
> +static bool mtk_dp_plug_state_avoid_pulse(struct mtk_dp *mtk_dp)
> +{
> +	bool ret;
> +
> +	return !(readx_poll_timeout(mtk_dp_plug_state, mtk_dp, ret,
> ret,
> +				    4000, 7 * 4000));
> +}
> +
>  static void mtk_dp_aux_irq_clear(struct mtk_dp *mtk_dp)
>  {
>  	mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3640,
> @@ -778,35 +796,67 @@ static void mtk_dp_get_calibration_data(struct
> mtk_dp *mtk_dp)
>  		return;
>  	}
>  
> -	cal_data->glb_bias_trim =
> -		check_cal_data_valid(mtk_dp, 1, 0x1e,
> -				     (buf[3] >> 27) & 0x1f, 0xf);
> -	cal_data->clktx_impse =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[0] >> 9) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[0] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 28) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[0] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 24) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[1] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 20) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[1] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 16) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[2] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 12) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[2] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 8) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[3] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 4) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[3] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe, buf[2] & 0xf,
> 0x8);
> +	if (mtk_dp_is_edp(mtk_dp)) {
> +		cal_data->glb_bias_trim =
> +			check_cal_data_valid(mtk_dp, 1, 0x1e,
> +					     (buf[3] >> 27) & 0x1f,
> 0xf);
> +		cal_data->clktx_impse =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[0] >> 9) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_pmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 28) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 24) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 20) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 16) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 12) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 8) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_pmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 4) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_nmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe, buf[2] &
> 0xf, 0x8);
> +	} else {
> +		cal_data->glb_bias_trim =
> +			check_cal_data_valid(mtk_dp, 1, 0x1e,
> +					     (buf[0] >> 27) & 0x1f,
> 0xf);

Why not place glb_bias_trim value in nvmem buf[3] for both edp and dp
case? Place in the same nvmem position, the driver code would be
simple. 

> +		cal_data->clktx_impse =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[0] >> 13) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 28) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 24) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 20) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 16) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 12) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 8) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_pmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 4) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_nmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe, buf[1] &
> 0xf, 0x8);

Why not place ln_tx_impsel_nmos and ln_tx_impsel_pmos value in nvmem
buf[2] for both edp and dp case? Place in the same nvmem position, the
driver code would be simple. 

> +	}
>  
>  	kfree(buf);
>  }
> @@ -926,7 +976,10 @@ static void mtk_dp_video_mute(struct mtk_dp
> *mtk_dp, bool enable)
>  			   VIDEO_MUTE_SEL_DP_ENC0_P0_MASK |
>  			   VIDEO_MUTE_SW_DP_ENC0_P0_MASK);
>  
> -	mtk_dp_sip_atf_call(mtk_dp, MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE,
> enable);
> +	mtk_dp_sip_atf_call(mtk_dp,
> +			    mtk_dp_is_edp(mtk_dp) ?
> +			    MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE :
> +			    MTK_DP_SIP_ATF_VIDEO_UNMUTE, enable);

Use of_device_get_match_data to select MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE
or MTK_DP_SIP_ATF_VIDEO_UNMUTE.

>  }
>  
>  static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
> @@ -1226,6 +1279,9 @@ static int mtk_dp_parse_capabilities(struct
> mtk_dp *mtk_dp)
>  	drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER,
> DP_SET_POWER_D0);
>  	usleep_range(2000, 5000);
>  
> +	if (!mtk_dp_plug_state(mtk_dp))
> +		return -ENODEV;
> +
>  	drm_dp_read_dpcd_caps(&mtk_dp->aux, mtk_dp->rx_cap);
>  
>  	train_info->link_rate = min_t(int, mtk_dp->max_linkrate,
> @@ -1277,6 +1333,9 @@ static int mtk_dp_train_start(struct mtk_dp
> *mtk_dp)
>  	u8 train_limit;
>  	u8 max_link_rate;
>  
> +	if (!mtk_dp_plug_state_avoid_pulse(mtk_dp))
> +		return -ENODEV;
> +
>  	link_rate = mtk_dp->rx_cap[1];
>  	lane_count = mtk_dp->rx_cap[2] & 0x1F;
>  
> @@ -1412,6 +1471,9 @@ static irqreturn_t mtk_dp_hpd_event_thread(int
> hpd, void *dev)
>  {
>  	struct mtk_dp *mtk_dp = dev;
>  
> +	dev_dbg(mtk_dp->dev, "drm_helper_hpd_irq_event\n");
> +	drm_helper_hpd_irq_event(mtk_dp->bridge.dev);

Because edp also have hpd interrupt, so I would like both edp and dp
have the same control flow for hdp. So move this to edp patch.

> +
>  	if (mtk_dp->train_info.hpd_inerrupt) {
>  		dev_dbg(mtk_dp->dev, "MTK_DP_HPD_INTERRUPT\n");
>  		mtk_dp->train_info.hpd_inerrupt = false;
> @@ -1452,9 +1514,20 @@ static irqreturn_t mtk_dp_hpd_event(int hpd,
> void *dev)
>  		else
>  			train_info->cable_plugged_in = false;
>  
> -		mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
> -				   DP_PWR_STATE_BANDGAP_TPLL_LANE,
> -				   DP_PWR_STATE_MASK);
> +		if (!train_info->cable_plugged_in) {
> +			mtk_dp_video_mute(mtk_dp, true);
> +
> +			mtk_dp_initialize_priv_data(mtk_dp);
> +			mtk_dp_set_idle_pattern(mtk_dp, true);
> +
> +			mtk_dp_update_bits(mtk_dp,
> MTK_DP_TOP_PWR_STATE,
> +					   DP_PWR_STATE_BANDGAP_TPLL,
> +					   DP_PWR_STATE_MASK);
> +		} else {
> +			mtk_dp_update_bits(mtk_dp,
> MTK_DP_TOP_PWR_STATE,
> +					   DP_PWR_STATE_BANDGAP_TPLL_LA
> NE,
> +					   DP_PWR_STATE_MASK);
> +		}
>  	}
>  
>  	return IRQ_HANDLED;
> @@ -1499,6 +1572,24 @@ static int mtk_dp_dt_parse(struct mtk_dp
> *mtk_dp,
>  	return 0;
>  }
>  
> +static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge
> *bridge)
> +{
> +	struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> +	enum drm_connector_status ret = connector_status_disconnected;
> +	u8 sink_count = 0;
> +
> +	if (mtk_dp_is_edp(mtk_dp))
> +		return connector_status_connected;

Because edp also have hpd interrupt, so I would like both edp and dp
have the same control flow for hdp. So remove this.

> +
> +	if (mtk_dp_plug_state_avoid_pulse(mtk_dp)) {
> +		drm_dp_dpcd_readb(&mtk_dp->aux, DP_SINK_COUNT,
> &sink_count);
> +		if (DP_GET_SINK_COUNT(sink_count))
> +			ret = connector_status_connected;
> +	}
> +
> +	return ret;
> +}
> +
>  static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
>  				    struct drm_connector *connector)
>  {
> @@ -1512,7 +1603,8 @@ static struct edid *mtk_dp_get_edid(struct
> drm_bridge *bridge,
>  	drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER,
> DP_SET_POWER_D0);
>  	usleep_range(2000, 5000);
>  
> -	new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
> +	if (mtk_dp_plug_state(mtk_dp))
> +		new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);

Please explain why only dp has this problem. If edp also has this
problem, move this to edp patch.

Regards,
CK

>  
>  	if (!enabled)
>  		drm_bridge_chain_post_disable(bridge);
> @@ -1852,6 +1944,7 @@ static const struct drm_bridge_funcs
> mtk_dp_bridge_funcs = {
>  	.atomic_disable = mtk_dp_bridge_atomic_disable,
>  	.mode_valid = mtk_dp_bridge_mode_valid,
>  	.get_edid = mtk_dp_get_edid,
> +	.detect = mtk_dp_bdg_detect,
>  };
>  
>  static int mtk_dp_probe(struct platform_device *pdev)
> @@ -1873,9 +1966,15 @@ static int mtk_dp_probe(struct platform_device
> *pdev)
>  				     "failed to request dp irq
> resource\n");
>  
>  	mtk_dp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 
> 1, 0);
> -	if (IS_ERR(mtk_dp->next_bridge))
> +	if (IS_ERR(mtk_dp->next_bridge) &&
> +	    PTR_ERR(mtk_dp->next_bridge) == -ENODEV) {
> +		dev_info(dev,
> +			 "No panel connected in devicetree, continue as
> external DP\n");
> +		mtk_dp->next_bridge = NULL;
> +	} else if (IS_ERR(mtk_dp->next_bridge)) {
>  		return dev_err_probe(dev, PTR_ERR(mtk_dp->next_bridge),
>  				     "Failed to get bridge\n");
> +	}
>  
>  	ret = mtk_dp_dt_parse(mtk_dp, pdev);
>  	if (ret)
> @@ -1918,7 +2017,10 @@ static int mtk_dp_probe(struct platform_device
> *pdev)
>  
>  	mtk_dp->bridge.ops =
>  		DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
> DRM_BRIDGE_OP_HPD;
> -	mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
> +	if (mtk_dp_is_edp(mtk_dp))
> +		mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
> +	else
> +		mtk_dp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
>  
>  	drm_bridge_add(&mtk_dp->bridge);
>  
> @@ -1945,6 +2047,12 @@ static int mtk_dp_suspend(struct device *dev)
>  {
>  	struct mtk_dp *mtk_dp = dev_get_drvdata(dev);
>  
> +	if (mtk_dp_plug_state(mtk_dp)) {
> +		drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER,
> DP_SET_POWER_D3);
> +		/* Ensure the sink is off before shutting down power */
> +		usleep_range(2000, 3000);
> +	}
> +
>  	mtk_dp_power_disable(mtk_dp);
>  
>  	mtk_dp_hwirq_enable(mtk_dp, false);
> @@ -1978,6 +2086,7 @@ static SIMPLE_DEV_PM_OPS(mtk_dp_pm_ops,
> mtk_dp_suspend, mtk_dp_resume);
>  
>  static const struct of_device_id mtk_dp_of_match[] = {
>  	{ .compatible = "mediatek,mt8195-edp-tx" },
> +	{ .compatible = "mediatek,mt8195-dp-tx" },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, mtk_dp_of_match);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> index 4ff8e9880dc9..59086eb82868 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> @@ -14,6 +14,7 @@
>  #define SEC_OFFSET	0x4000
>  
>  #define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE	(BIT(0) | BIT(5))
> +#define MTK_DP_SIP_ATF_VIDEO_UNMUTE	BIT(5)
>  
>  #define DP_PHY_GLB_BIAS_GEN_00		0
>  #define RG_XTP_GLB_BIAS_INTR_CTRL	GENMASK(20, 16)


WARNING: multiple messages have this Message-ID (diff)
From: CK Hu <ck.hu@mediatek.com>
To: Bo-Chen Chen <rex-bc.chen@mediatek.com>,
	<chunkuang.hu@kernel.org>, <p.zabel@pengutronix.de>,
	<daniel@ffwll.ch>, <robh+dt@kernel.org>,
	<krzysztof.kozlowski+dt@linaro.org>, <mripard@kernel.org>,
	<tzimmermann@suse.de>, <matthias.bgg@gmail.com>, <deller@gmx.de>,
	<airlied@linux.ie>
Cc: <msp@baylibre.com>, <granquet@baylibre.com>,
	<jitao.shi@mediatek.com>, <wenst@chromium.org>,
	<angelogioacchino.delregno@collabora.com>,
	<liangxu.xu@mediatek.com>, <dri-devel@lists.freedesktop.org>,
	<linux-mediatek@lists.infradead.org>,
	<devicetree@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-fbdev@vger.kernel.org>,
	<Project_Global_Chrome_Upstream_Group@mediatek.com>
Subject: Re: [PATCH v15 06/11] drm/mediatek: Add MT8195 External DisplayPort support
Date: Tue, 2 Aug 2022 10:37:41 +0800	[thread overview]
Message-ID: <4d54b439fab8b888598677e1e52fb098c9b93e03.camel@mediatek.com> (raw)
In-Reply-To: <20220727045035.32225-7-rex-bc.chen@mediatek.com>

Hi, Bo-Chen:

On Wed, 2022-07-27 at 12:50 +0800, Bo-Chen Chen wrote:
> From: Guillaume Ranquet <granquet@baylibre.com>
> 
> This patch adds External DisplayPort support to the mt8195 eDP
> driver.
> 
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_dp.c     | 181 +++++++++++++++++++++---
> --
>  drivers/gpu/drm/mediatek/mtk_dp_reg.h |   1 +
>  2 files changed, 146 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c
> b/drivers/gpu/drm/mediatek/mtk_dp.c
> index 06eeecedd49e..ce817cb59445 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> @@ -103,6 +103,11 @@ static struct regmap_config mtk_dp_regmap_config
> = {
>  	.name = "mtk-dp-registers",
>  };
>  
> +static bool mtk_dp_is_edp(struct mtk_dp *mtk_dp)
> +{
> +	return mtk_dp->next_bridge;

For external DP, it could also connect to a bridge IC which transfer DP
to HDMI or some interface else. Use the compatible to judge this edp or
dp.

> +}
> +
>  static struct mtk_dp *mtk_dp_from_bridge(struct drm_bridge *b)
>  {
>  	return container_of(b, struct mtk_dp, bridge);
> @@ -341,6 +346,19 @@ static void mtk_dp_pg_enable(struct mtk_dp
> *mtk_dp, bool enable)
>  			   4 << PGEN_PATTERN_SEL_SHIFT,
> PGEN_PATTERN_SEL_MASK);
>  }
>  
> +static bool mtk_dp_plug_state(struct mtk_dp *mtk_dp)
> +{
> +	return mtk_dp->train_info.cable_plugged_in;
> +}
> +
> +static bool mtk_dp_plug_state_avoid_pulse(struct mtk_dp *mtk_dp)
> +{
> +	bool ret;
> +
> +	return !(readx_poll_timeout(mtk_dp_plug_state, mtk_dp, ret,
> ret,
> +				    4000, 7 * 4000));
> +}
> +
>  static void mtk_dp_aux_irq_clear(struct mtk_dp *mtk_dp)
>  {
>  	mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3640,
> @@ -778,35 +796,67 @@ static void mtk_dp_get_calibration_data(struct
> mtk_dp *mtk_dp)
>  		return;
>  	}
>  
> -	cal_data->glb_bias_trim =
> -		check_cal_data_valid(mtk_dp, 1, 0x1e,
> -				     (buf[3] >> 27) & 0x1f, 0xf);
> -	cal_data->clktx_impse =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[0] >> 9) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[0] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 28) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[0] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 24) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[1] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 20) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[1] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 16) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[2] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 12) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[2] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 8) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_pmos[3] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe,
> -				     (buf[2] >> 4) & 0xf, 0x8);
> -	cal_data->ln_tx_impsel_nmos[3] =
> -		check_cal_data_valid(mtk_dp, 1, 0xe, buf[2] & 0xf,
> 0x8);
> +	if (mtk_dp_is_edp(mtk_dp)) {
> +		cal_data->glb_bias_trim =
> +			check_cal_data_valid(mtk_dp, 1, 0x1e,
> +					     (buf[3] >> 27) & 0x1f,
> 0xf);
> +		cal_data->clktx_impse =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[0] >> 9) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_pmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 28) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 24) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 20) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 16) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 12) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 8) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_pmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[2] >> 4) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_nmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe, buf[2] &
> 0xf, 0x8);
> +	} else {
> +		cal_data->glb_bias_trim =
> +			check_cal_data_valid(mtk_dp, 1, 0x1e,
> +					     (buf[0] >> 27) & 0x1f,
> 0xf);

Why not place glb_bias_trim value in nvmem buf[3] for both edp and dp
case? Place in the same nvmem position, the driver code would be
simple. 

> +		cal_data->clktx_impse =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[0] >> 13) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 28) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[0] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 24) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 20) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[1] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 16) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_pmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 12) & 0xf,
> 0x8);
> +		cal_data->ln_tx_impsel_nmos[2] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 8) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_pmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe,
> +					     (buf[1] >> 4) & 0xf, 0x8);
> +		cal_data->ln_tx_impsel_nmos[3] =
> +			check_cal_data_valid(mtk_dp, 1, 0xe, buf[1] &
> 0xf, 0x8);

Why not place ln_tx_impsel_nmos and ln_tx_impsel_pmos value in nvmem
buf[2] for both edp and dp case? Place in the same nvmem position, the
driver code would be simple. 

> +	}
>  
>  	kfree(buf);
>  }
> @@ -926,7 +976,10 @@ static void mtk_dp_video_mute(struct mtk_dp
> *mtk_dp, bool enable)
>  			   VIDEO_MUTE_SEL_DP_ENC0_P0_MASK |
>  			   VIDEO_MUTE_SW_DP_ENC0_P0_MASK);
>  
> -	mtk_dp_sip_atf_call(mtk_dp, MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE,
> enable);
> +	mtk_dp_sip_atf_call(mtk_dp,
> +			    mtk_dp_is_edp(mtk_dp) ?
> +			    MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE :
> +			    MTK_DP_SIP_ATF_VIDEO_UNMUTE, enable);

Use of_device_get_match_data to select MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE
or MTK_DP_SIP_ATF_VIDEO_UNMUTE.

>  }
>  
>  static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
> @@ -1226,6 +1279,9 @@ static int mtk_dp_parse_capabilities(struct
> mtk_dp *mtk_dp)
>  	drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER,
> DP_SET_POWER_D0);
>  	usleep_range(2000, 5000);
>  
> +	if (!mtk_dp_plug_state(mtk_dp))
> +		return -ENODEV;
> +
>  	drm_dp_read_dpcd_caps(&mtk_dp->aux, mtk_dp->rx_cap);
>  
>  	train_info->link_rate = min_t(int, mtk_dp->max_linkrate,
> @@ -1277,6 +1333,9 @@ static int mtk_dp_train_start(struct mtk_dp
> *mtk_dp)
>  	u8 train_limit;
>  	u8 max_link_rate;
>  
> +	if (!mtk_dp_plug_state_avoid_pulse(mtk_dp))
> +		return -ENODEV;
> +
>  	link_rate = mtk_dp->rx_cap[1];
>  	lane_count = mtk_dp->rx_cap[2] & 0x1F;
>  
> @@ -1412,6 +1471,9 @@ static irqreturn_t mtk_dp_hpd_event_thread(int
> hpd, void *dev)
>  {
>  	struct mtk_dp *mtk_dp = dev;
>  
> +	dev_dbg(mtk_dp->dev, "drm_helper_hpd_irq_event\n");
> +	drm_helper_hpd_irq_event(mtk_dp->bridge.dev);

Because edp also have hpd interrupt, so I would like both edp and dp
have the same control flow for hdp. So move this to edp patch.

> +
>  	if (mtk_dp->train_info.hpd_inerrupt) {
>  		dev_dbg(mtk_dp->dev, "MTK_DP_HPD_INTERRUPT\n");
>  		mtk_dp->train_info.hpd_inerrupt = false;
> @@ -1452,9 +1514,20 @@ static irqreturn_t mtk_dp_hpd_event(int hpd,
> void *dev)
>  		else
>  			train_info->cable_plugged_in = false;
>  
> -		mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
> -				   DP_PWR_STATE_BANDGAP_TPLL_LANE,
> -				   DP_PWR_STATE_MASK);
> +		if (!train_info->cable_plugged_in) {
> +			mtk_dp_video_mute(mtk_dp, true);
> +
> +			mtk_dp_initialize_priv_data(mtk_dp);
> +			mtk_dp_set_idle_pattern(mtk_dp, true);
> +
> +			mtk_dp_update_bits(mtk_dp,
> MTK_DP_TOP_PWR_STATE,
> +					   DP_PWR_STATE_BANDGAP_TPLL,
> +					   DP_PWR_STATE_MASK);
> +		} else {
> +			mtk_dp_update_bits(mtk_dp,
> MTK_DP_TOP_PWR_STATE,
> +					   DP_PWR_STATE_BANDGAP_TPLL_LA
> NE,
> +					   DP_PWR_STATE_MASK);
> +		}
>  	}
>  
>  	return IRQ_HANDLED;
> @@ -1499,6 +1572,24 @@ static int mtk_dp_dt_parse(struct mtk_dp
> *mtk_dp,
>  	return 0;
>  }
>  
> +static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge
> *bridge)
> +{
> +	struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> +	enum drm_connector_status ret = connector_status_disconnected;
> +	u8 sink_count = 0;
> +
> +	if (mtk_dp_is_edp(mtk_dp))
> +		return connector_status_connected;

Because edp also have hpd interrupt, so I would like both edp and dp
have the same control flow for hdp. So remove this.

> +
> +	if (mtk_dp_plug_state_avoid_pulse(mtk_dp)) {
> +		drm_dp_dpcd_readb(&mtk_dp->aux, DP_SINK_COUNT,
> &sink_count);
> +		if (DP_GET_SINK_COUNT(sink_count))
> +			ret = connector_status_connected;
> +	}
> +
> +	return ret;
> +}
> +
>  static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
>  				    struct drm_connector *connector)
>  {
> @@ -1512,7 +1603,8 @@ static struct edid *mtk_dp_get_edid(struct
> drm_bridge *bridge,
>  	drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER,
> DP_SET_POWER_D0);
>  	usleep_range(2000, 5000);
>  
> -	new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
> +	if (mtk_dp_plug_state(mtk_dp))
> +		new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);

Please explain why only dp has this problem. If edp also has this
problem, move this to edp patch.

Regards,
CK

>  
>  	if (!enabled)
>  		drm_bridge_chain_post_disable(bridge);
> @@ -1852,6 +1944,7 @@ static const struct drm_bridge_funcs
> mtk_dp_bridge_funcs = {
>  	.atomic_disable = mtk_dp_bridge_atomic_disable,
>  	.mode_valid = mtk_dp_bridge_mode_valid,
>  	.get_edid = mtk_dp_get_edid,
> +	.detect = mtk_dp_bdg_detect,
>  };
>  
>  static int mtk_dp_probe(struct platform_device *pdev)
> @@ -1873,9 +1966,15 @@ static int mtk_dp_probe(struct platform_device
> *pdev)
>  				     "failed to request dp irq
> resource\n");
>  
>  	mtk_dp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 
> 1, 0);
> -	if (IS_ERR(mtk_dp->next_bridge))
> +	if (IS_ERR(mtk_dp->next_bridge) &&
> +	    PTR_ERR(mtk_dp->next_bridge) == -ENODEV) {
> +		dev_info(dev,
> +			 "No panel connected in devicetree, continue as
> external DP\n");
> +		mtk_dp->next_bridge = NULL;
> +	} else if (IS_ERR(mtk_dp->next_bridge)) {
>  		return dev_err_probe(dev, PTR_ERR(mtk_dp->next_bridge),
>  				     "Failed to get bridge\n");
> +	}
>  
>  	ret = mtk_dp_dt_parse(mtk_dp, pdev);
>  	if (ret)
> @@ -1918,7 +2017,10 @@ static int mtk_dp_probe(struct platform_device
> *pdev)
>  
>  	mtk_dp->bridge.ops =
>  		DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
> DRM_BRIDGE_OP_HPD;
> -	mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
> +	if (mtk_dp_is_edp(mtk_dp))
> +		mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
> +	else
> +		mtk_dp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
>  
>  	drm_bridge_add(&mtk_dp->bridge);
>  
> @@ -1945,6 +2047,12 @@ static int mtk_dp_suspend(struct device *dev)
>  {
>  	struct mtk_dp *mtk_dp = dev_get_drvdata(dev);
>  
> +	if (mtk_dp_plug_state(mtk_dp)) {
> +		drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER,
> DP_SET_POWER_D3);
> +		/* Ensure the sink is off before shutting down power */
> +		usleep_range(2000, 3000);
> +	}
> +
>  	mtk_dp_power_disable(mtk_dp);
>  
>  	mtk_dp_hwirq_enable(mtk_dp, false);
> @@ -1978,6 +2086,7 @@ static SIMPLE_DEV_PM_OPS(mtk_dp_pm_ops,
> mtk_dp_suspend, mtk_dp_resume);
>  
>  static const struct of_device_id mtk_dp_of_match[] = {
>  	{ .compatible = "mediatek,mt8195-edp-tx" },
> +	{ .compatible = "mediatek,mt8195-dp-tx" },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, mtk_dp_of_match);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> index 4ff8e9880dc9..59086eb82868 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> @@ -14,6 +14,7 @@
>  #define SEC_OFFSET	0x4000
>  
>  #define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE	(BIT(0) | BIT(5))
> +#define MTK_DP_SIP_ATF_VIDEO_UNMUTE	BIT(5)
>  
>  #define DP_PHY_GLB_BIAS_GEN_00		0
>  #define RG_XTP_GLB_BIAS_INTR_CTRL	GENMASK(20, 16)


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2022-08-02  2:38 UTC|newest]

Thread overview: 89+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-27  4:50 [PATCH v15 00/11] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
2022-07-27  4:50 ` Bo-Chen Chen
2022-07-27  4:50 ` Bo-Chen Chen
2022-07-27  4:50 ` [PATCH v15 01/11] dt-bindings: mediatek,dp: Add Display Port binding Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  7:23   ` Krzysztof Kozlowski
2022-07-27  7:23     ` Krzysztof Kozlowski
2022-07-27  7:23     ` Krzysztof Kozlowski
2022-07-28  9:39     ` Rex-BC Chen
2022-07-28  9:39       ` Rex-BC Chen
2022-07-28  9:39       ` Rex-BC Chen
2022-07-27  4:50 ` [PATCH v15 02/11] drm/edid: Convert cea_sad helper struct to kernelDoc Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50 ` [PATCH v15 03/11] drm/edid: Add cea_sad helpers for freq/length Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  9:34   ` AngeloGioacchino Del Regno
2022-07-27  9:34     ` AngeloGioacchino Del Regno
2022-07-27  9:34     ` AngeloGioacchino Del Regno
2022-08-02 14:11   ` Jani Nikula
2022-08-02 14:11     ` Jani Nikula
2022-08-02 14:11     ` Jani Nikula
2022-08-05  6:54     ` Rex-BC Chen
2022-08-05  6:54       ` Rex-BC Chen
2022-08-05  6:54       ` Rex-BC Chen
2022-08-05  7:54       ` Jani Nikula
2022-08-05  7:54         ` Jani Nikula
2022-07-27  4:50 ` [PATCH v15 04/11] video/hdmi: Add audio_infoframe packing for DP Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  9:35   ` AngeloGioacchino Del Regno
2022-07-27  9:35     ` AngeloGioacchino Del Regno
2022-07-27  9:35     ` AngeloGioacchino Del Regno
2022-07-27  4:50 ` [PATCH v15 05/11] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  9:36   ` AngeloGioacchino Del Regno
2022-07-27  9:36     ` AngeloGioacchino Del Regno
2022-07-27  9:36     ` AngeloGioacchino Del Regno
2022-08-02  2:56   ` CK Hu
2022-08-02  2:56     ` CK Hu
2022-08-02  2:56     ` CK Hu
2022-08-02  5:09   ` CK Hu
2022-08-02  5:09     ` CK Hu
2022-08-02  5:09     ` CK Hu
2022-08-05  8:22     ` Rex-BC Chen
2022-08-05  8:22       ` Rex-BC Chen
2022-08-05  8:22       ` Rex-BC Chen
2022-08-02  7:57   ` CK Hu
2022-08-02  7:57     ` CK Hu
2022-08-02  7:57     ` CK Hu
2022-07-27  4:50 ` [PATCH v15 06/11] drm/mediatek: Add MT8195 External DisplayPort support Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  9:38   ` AngeloGioacchino Del Regno
2022-07-27  9:38     ` AngeloGioacchino Del Regno
2022-07-27  9:38     ` AngeloGioacchino Del Regno
2022-08-02  2:37   ` CK Hu [this message]
2022-08-02  2:37     ` CK Hu
2022-08-02  2:37     ` CK Hu
2022-08-03  5:47     ` Rex-BC Chen
2022-08-03  5:47       ` Rex-BC Chen
2022-08-03  5:47       ` Rex-BC Chen
2022-07-27  4:50 ` [PATCH v15 07/11] drm/mediatek: Add retry to prevent misjudgment for sink devices Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  9:40   ` AngeloGioacchino Del Regno
2022-07-27  9:40     ` AngeloGioacchino Del Regno
2022-07-27  9:40     ` AngeloGioacchino Del Regno
2022-07-28  9:40     ` Rex-BC Chen
2022-07-28  9:40       ` Rex-BC Chen
2022-07-28  9:40       ` Rex-BC Chen
2022-08-05  7:10       ` Rex-BC Chen
2022-08-05  7:10         ` Rex-BC Chen
2022-08-05  7:10         ` Rex-BC Chen
2022-07-27  4:50 ` [PATCH v15 08/11] drm/mediatek: add hpd debounce Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50 ` [PATCH v15 09/11] drm/mediatek: set monitor to DP_SET_POWER_D3 to avoid garbage Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50 ` [PATCH v15 10/11] drm/mediatek: DP audio support for MT8195 Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50 ` [PATCH v15 11/11] drm/mediatek: Use cached audio config when changing resolution Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen
2022-07-27  4:50   ` Bo-Chen Chen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4d54b439fab8b888598677e1e52fb098c9b93e03.camel@mediatek.com \
    --to=ck.hu@mediatek.com \
    --cc=Project_Global_Chrome_Upstream_Group@mediatek.com \
    --cc=airlied@linux.ie \
    --cc=angelogioacchino.delregno@collabora.com \
    --cc=chunkuang.hu@kernel.org \
    --cc=daniel@ffwll.ch \
    --cc=deller@gmx.de \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=granquet@baylibre.com \
    --cc=jitao.shi@mediatek.com \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=liangxu.xu@mediatek.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=matthias.bgg@gmail.com \
    --cc=mripard@kernel.org \
    --cc=msp@baylibre.com \
    --cc=p.zabel@pengutronix.de \
    --cc=rex-bc.chen@mediatek.com \
    --cc=robh+dt@kernel.org \
    --cc=tzimmermann@suse.de \
    --cc=wenst@chromium.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.