Commit 3c7623fb authored by Baihan Li's avatar Baihan Li Committed by Dmitry Baryshkov
Browse files

drm/hisilicon/hibmc: Enable this hot plug detect of irq feature



Add HPD interrupt enable functions in drm framework, and also add
detect_ctx functions. Because of the debouncing when HPD pulled out,
add 200 ms delay in detect. Add link reset process to reset link status
when a new connector pulgged in.

Signed-off-by: default avatarBaihan Li <libaihan@huawei.com>
Signed-off-by: default avatarYongbang Shi <shiyongbang@huawei.com>
Reviewed-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/20250331074212.3370287-8-shiyongbang@huawei.com


Signed-off-by: default avatarDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
parent 2f618261
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -16,5 +16,6 @@
#define HIBMC_DP_SYNC_EN_MASK		0x3
#define HIBMC_DP_LINK_RATE_CAL		27
#define HIBMC_DP_SYNC_DELAY(lanes)	((lanes) == 0x2 ? 86 : 46)
#define HIBMC_DP_INT_ENABLE		0xc

#endif
+36 −0
Original line number Diff line number Diff line
@@ -189,6 +189,36 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp)
	return 0;
}

void hibmc_dp_enable_int(struct hibmc_dp *dp)
{
	struct hibmc_dp_dev *dp_dev = dp->dp_dev;

	writel(HIBMC_DP_INT_ENABLE, dp_dev->base + HIBMC_DP_INTR_ENABLE);
}

void hibmc_dp_disable_int(struct hibmc_dp *dp)
{
	struct hibmc_dp_dev *dp_dev = dp->dp_dev;

	writel(0, dp_dev->base + HIBMC_DP_INTR_ENABLE);
	writel(HIBMC_DP_INT_RST, dp_dev->base + HIBMC_DP_INTR_ORIGINAL_STATUS);
}

void hibmc_dp_hpd_cfg(struct hibmc_dp *dp)
{
	struct hibmc_dp_dev *dp_dev = dp->dp_dev;

	hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_SYNC_LEN_SEL, 0x0);
	hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_TIMER_TIMEOUT, 0x1);
	hibmc_dp_reg_write_field(dp->dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_MIN_PULSE_NUM, 0x9);
	writel(HIBMC_DP_HDCP, dp_dev->base + HIBMC_DP_HDCP_CFG);
	writel(0, dp_dev->base + HIBMC_DP_INTR_ENABLE);
	writel(HIBMC_DP_INT_RST, dp_dev->base + HIBMC_DP_INTR_ORIGINAL_STATUS);
	writel(HIBMC_DP_INT_ENABLE, dp_dev->base + HIBMC_DP_INTR_ENABLE);
	writel(HIBMC_DP_DPTX_RST, dp_dev->base + HIBMC_DP_DPTX_RST_CTRL);
	writel(HIBMC_DP_CLK_EN, dp_dev->base + HIBMC_DP_DPTX_CLK_CTRL);
}

void hibmc_dp_display_en(struct hibmc_dp *dp, bool enable)
{
	struct hibmc_dp_dev *dp_dev = dp->dp_dev;
@@ -227,6 +257,12 @@ int hibmc_dp_mode_set(struct hibmc_dp *dp, struct drm_display_mode *mode)
	return 0;
}

void hibmc_dp_reset_link(struct hibmc_dp *dp)
{
	dp->dp_dev->link.status.clock_recovered = false;
	dp->dp_dev->link.status.channel_equalized = false;
}

static const struct hibmc_dp_color_raw g_rgb_raw[] = {
	{CBAR_COLOR_BAR, 0x000, 0x000, 0x000},
	{CBAR_WHITE,     0xfff, 0xfff, 0xfff},
+5 −0
Original line number Diff line number Diff line
@@ -49,11 +49,16 @@ struct hibmc_dp {
	void __iomem *mmio;
	struct drm_dp_aux aux;
	struct hibmc_dp_cbar_cfg cfg;
	u32 irq_status;
};

int hibmc_dp_hw_init(struct hibmc_dp *dp);
int hibmc_dp_mode_set(struct hibmc_dp *dp, struct drm_display_mode *mode);
void hibmc_dp_display_en(struct hibmc_dp *dp, bool enable);
void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg *cfg);
void hibmc_dp_reset_link(struct hibmc_dp *dp);
void hibmc_dp_hpd_cfg(struct hibmc_dp *dp);
void hibmc_dp_enable_int(struct hibmc_dp *dp);
void hibmc_dp_disable_int(struct hibmc_dp *dp);

#endif
+42 −0
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@
#include "hibmc_drm_drv.h"
#include "dp/dp_hw.h"

#define DP_MASKED_SINK_HPD_PLUG_INT	BIT(2)

static int hibmc_dp_connector_get_modes(struct drm_connector *connector)
{
	const struct drm_edid *drm_edid;
@@ -29,14 +31,25 @@ static int hibmc_dp_connector_get_modes(struct drm_connector *connector)
	return count;
}

static int hibmc_dp_detect(struct drm_connector *connector,
			   struct drm_modeset_acquire_ctx *ctx, bool force)
{
	mdelay(200);

	return drm_connector_helper_detect_from_ddc(connector, ctx, force);
}

static const struct drm_connector_helper_funcs hibmc_dp_conn_helper_funcs = {
	.get_modes = hibmc_dp_connector_get_modes,
	.detect_ctx = hibmc_dp_detect,
};

static int hibmc_dp_late_register(struct drm_connector *connector)
{
	struct hibmc_dp *dp = to_hibmc_dp(connector);

	hibmc_dp_enable_int(dp);

	return drm_dp_aux_register(&dp->aux);
}

@@ -45,6 +58,8 @@ static void hibmc_dp_early_unregister(struct drm_connector *connector)
	struct hibmc_dp *dp = to_hibmc_dp(connector);

	drm_dp_aux_unregister(&dp->aux);

	hibmc_dp_disable_int(dp);
}

static const struct drm_connector_funcs hibmc_dp_conn_funcs = {
@@ -96,6 +111,31 @@ static const struct drm_encoder_helper_funcs hibmc_dp_encoder_helper_funcs = {
	.atomic_disable = hibmc_dp_encoder_disable,
};

irqreturn_t hibmc_dp_hpd_isr(int irq, void *arg)
{
	struct drm_device *dev = (struct drm_device *)arg;
	struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);
	int idx;

	if (!drm_dev_enter(dev, &idx))
		return -ENODEV;

	if (priv->dp.irq_status & DP_MASKED_SINK_HPD_PLUG_INT) {
		drm_dbg_dp(&priv->dev, "HPD IN isr occur!\n");
		hibmc_dp_hpd_cfg(&priv->dp);
	} else {
		drm_dbg_dp(&priv->dev, "HPD OUT isr occur!\n");
		hibmc_dp_reset_link(&priv->dp);
	}

	if (dev->registered)
		drm_connector_helper_hpd_irq_event(&priv->dp.connector);

	drm_dev_exit(idx);

	return IRQ_HANDLED;
}

int hibmc_dp_init(struct hibmc_drm_private *priv)
{
	struct drm_device *dev = &priv->dev;
@@ -136,5 +176,7 @@ int hibmc_dp_init(struct hibmc_drm_private *priv)

	drm_connector_attach_encoder(connector, encoder);

	connector->polled = DRM_CONNECTOR_POLL_HPD;

	return 0;
}
+2 −0
Original line number Diff line number Diff line
@@ -71,4 +71,6 @@ int hibmc_dp_init(struct hibmc_drm_private *priv);

void hibmc_debugfs_init(struct drm_connector *connector, struct dentry *root);

irqreturn_t hibmc_dp_hpd_isr(int irq, void *arg);

#endif