From nobody Thu Jan 30 19:15:55 2025 Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 99FC31FC11B for ; Mon, 27 Jan 2025 03:27:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.187 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737948502; cv=none; b=r1rSjiucB/V0dMRHs3xpXtrCQFUW/EI4J4Uktclnvl64GKoLIQ2saJaxi8Kpn7ufC5HU5WIrZhI1cUkbTJbhKH9EJtdaFCZ052YK3KBI+TZGoZt4YTyBrQ4pNrkgLFBAFZjhsFwwHc/M6y1UYMFIZQHrDk2dFcBfvBNCkDwLNGs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737948502; c=relaxed/simple; bh=BypsDgKIbNSD4JbmIdu5pCiNZbSbL6owtdy46pFhwE0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=vFX3PWxqczL5h9PEEE6lHfGEYaZ24QTXYMPJ6FomMqW6wbmQuI44awWB2/AQJ0pVyimldrTZFX3LxwKKTSsPIa2GDkb+3Cv7c57X4f20l8eXJvCFdBtXamQX5Q5CQQM7ltSXU/PMlBZ/vLFjiZuwpVgVi/qMDLna+PgS/+Dc2bc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=45.249.212.187 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.19.163.174]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4YhDJZ4h0fz11PHd; Mon, 27 Jan 2025 11:23:10 +0800 (CST) Received: from kwepemd500013.china.huawei.com (unknown [7.221.188.12]) by mail.maildlp.com (Postfix) with ESMTPS id DE8A31402DA; Mon, 27 Jan 2025 11:27:16 +0800 (CST) Received: from localhost.huawei.com (10.169.71.169) by kwepemd500013.china.huawei.com (7.221.188.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.34; Mon, 27 Jan 2025 11:27:15 +0800 From: Yongbang Shi To: , , , , , , , CC: , , , , , , , , Subject: [PATCH v1 drm-dp 1/4] drm/hisilicon/hibmc: Add dp phy cfg to adjust serdes rate, voltage and pre-emphasis Date: Mon, 27 Jan 2025 11:20:21 +0800 Message-ID: <20250127032024.1542219-2-shiyongbang@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20250127032024.1542219-1-shiyongbang@huawei.com> References: <20250127032024.1542219-1-shiyongbang@huawei.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) To kwepemd500013.china.huawei.com (7.221.188.12) Content-Type: text/plain; charset="utf-8" From: Baihan Li This phy is inited and configured for dp, and integrating them into dp init and dp link training process. Signed-off-by: Baihan Li Signed-off-by: Yongbang Shi --- drivers/gpu/drm/hisilicon/hibmc/Makefile | 2 +- drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h | 1 + .../gpu/drm/hisilicon/hibmc/dp/dp_config.h | 1 + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 9 ++- drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c | 33 +++++++-- drivers/gpu/drm/hisilicon/hibmc/dp/dp_phy.c | 72 +++++++++++++++++++ drivers/gpu/drm/hisilicon/hibmc/dp/dp_phy.h | 38 ++++++++++ drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h | 1 + .../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 8 +-- 9 files changed, 153 insertions(+), 12 deletions(-) create mode 100644 drivers/gpu/drm/hisilicon/hibmc/dp/dp_phy.c create mode 100644 drivers/gpu/drm/hisilicon/hibmc/dp/dp_phy.h diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/his= ilicon/hibmc/Makefile index 95a4ed599d98..35a74cc10c80 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only hibmc-drm-y :=3D hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm= _i2c.o \ - dp/dp_aux.o dp/dp_link.o dp/dp_hw.o hibmc_drm_dp.o + dp/dp_aux.o dp/dp_link.o dp/dp_hw.o dp/dp_phy.o hibmc_drm_dp.o =20 obj-$(CONFIG_DRM_HISI_HIBMC) +=3D hibmc-drm.o diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h b/drivers/gpu/drm= /hisilicon/hibmc/dp/dp_comm.h index 2c52a4476c4d..00b23301d26e 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h @@ -38,6 +38,7 @@ struct hibmc_dp_dev { struct mutex lock; /* protects concurrent RW in hibmc_dp_reg_write_field(= ) */ struct hibmc_dp_link link; u8 dpcd[DP_RECEIVER_CAP_SIZE]; + void __iomem *phy_base; }; =20 #define dp_field_modify(reg_value, mask, val) \ diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h b/drivers/gpu/d= rm/hisilicon/hibmc/dp/dp_config.h index 74dd9956144e..c5feef8dc27d 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h @@ -15,5 +15,6 @@ #define HIBMC_DP_CLK_EN 0x7 #define HIBMC_DP_SYNC_EN_MASK 0x3 #define HIBMC_DP_LINK_RATE_CAL 27 +#define HIBMC_DP_SYNC_DELAY(lanes) ((lanes) =3D=3D 0x2 ? 86 : 46) =20 #endif diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/h= isilicon/hibmc/dp/dp_hw.c index a8d543881c09..0dac4cfdde7c 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c @@ -7,6 +7,7 @@ #include "dp_comm.h" #include "dp_reg.h" #include "dp_hw.h" +#include "dp_phy.h" =20 static void hibmc_dp_set_tu(struct hibmc_dp_dev *dp, struct drm_display_mo= de *mode) { @@ -72,6 +73,9 @@ static void hibmc_dp_set_sst(struct hibmc_dp_dev *dp, str= uct drm_display_mode *m HIBMC_DP_CFG_STREAM_HTOTAL_SIZE, htotal_size); hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_HORIZONTAL_SIZE, HIBMC_DP_CFG_STREAM_HBLANK_SIZE, hblank_size); + hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_PACKET, + HIBMC_DP_CFG_STREAM_SYNC_CALIBRATION, + HIBMC_DP_SYNC_DELAY(dp->link.cap.lanes)); } =20 static void hibmc_dp_link_cfg(struct hibmc_dp_dev *dp, struct drm_display_= mode *mode) @@ -165,8 +169,11 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp) =20 hibmc_dp_aux_init(dp_dev); =20 + if (hibmc_dp_phy_init(dp_dev)) + return -EAGAIN; + dp_dev->link.cap.lanes =3D 0x2; - dp_dev->link.cap.link_rate =3D DP_LINK_BW_2_7; + dp_dev->link.cap.link_rate =3D DP_LINK_BW_8_1; =20 /* hdcp data */ writel(HIBMC_DP_HDCP, dp_dev->base + HIBMC_DP_HDCP_CFG); diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c b/drivers/gpu/drm= /hisilicon/hibmc/dp/dp_link.c index f6355c16cc0a..1124cd70c320 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c @@ -6,6 +6,7 @@ #include #include "dp_comm.h" #include "dp_reg.h" +#include "dp_phy.h" =20 #define HIBMC_EQ_MAX_RETRY 5 =20 @@ -108,7 +109,11 @@ static int hibmc_dp_link_training_cr_pre(struct hibmc_= dp_dev *dp) return ret; =20 for (i =3D 0; i < dp->link.cap.lanes; i++) - train_set[i] =3D DP_TRAIN_VOLTAGE_SWING_LEVEL_2; + train_set[i] =3D DP_TRAIN_VOLTAGE_SWING_LEVEL_0; + + ret =3D hibmc_dp_serdes_set_tx_cfg(dp, dp->link.train_set); + if (ret) + return ret; =20 ret =3D drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, train_set, dp-= >link.cap.lanes); if (ret !=3D dp->link.cap.lanes) { @@ -137,21 +142,28 @@ static bool hibmc_dp_link_get_adjust_train(struct hib= mc_dp_dev *dp, return false; } =20 -static inline int hibmc_dp_link_reduce_rate(struct hibmc_dp_dev *dp) +static int hibmc_dp_link_reduce_rate(struct hibmc_dp_dev *dp) { + u8 rate =3D 0; + switch (dp->link.cap.link_rate) { case DP_LINK_BW_2_7: dp->link.cap.link_rate =3D DP_LINK_BW_1_62; - return 0; + rate =3D DP_PHY_BW_1_62; + break; case DP_LINK_BW_5_4: dp->link.cap.link_rate =3D DP_LINK_BW_2_7; - return 0; + rate =3D DP_PHY_BW_2_7; + break; case DP_LINK_BW_8_1: dp->link.cap.link_rate =3D DP_LINK_BW_5_4; - return 0; + rate =3D DP_PHY_BW_5_4; + break; default: return -EINVAL; } + + return hibmc_dp_serdes_rate_switch(rate, dp); } =20 static inline int hibmc_dp_link_reduce_lane(struct hibmc_dp_dev *dp) @@ -159,6 +171,7 @@ static inline int hibmc_dp_link_reduce_lane(struct hibm= c_dp_dev *dp) switch (dp->link.cap.lanes) { case 0x2: dp->link.cap.lanes--; + drm_warn(dp->dev, "dp link training reduce to 1 lane\n"); break; case 0x1: drm_err(dp->dev, "dp link training reduce lane failed, already reach min= imum\n"); @@ -206,6 +219,11 @@ static int hibmc_dp_link_training_cr(struct hibmc_dp_d= ev *dp) } =20 level_changed =3D hibmc_dp_link_get_adjust_train(dp, lane_status); + + ret =3D hibmc_dp_serdes_set_tx_cfg(dp, dp->link.train_set); + if (ret) + return ret; + ret =3D drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dp->link.trai= n_set, dp->link.cap.lanes); if (ret !=3D dp->link.cap.lanes) { @@ -255,6 +273,11 @@ static int hibmc_dp_link_training_channel_eq(struct hi= bmc_dp_dev *dp) } =20 hibmc_dp_link_get_adjust_train(dp, lane_status); + + ret =3D hibmc_dp_serdes_set_tx_cfg(dp, dp->link.train_set); + if (ret) + return ret; + ret =3D drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dp->link.train_set, dp->link.cap.lanes); if (ret !=3D dp->link.cap.lanes) { diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_phy.c b/drivers/gpu/drm/= hisilicon/hibmc/dp/dp_phy.c new file mode 100644 index 000000000000..07940b5baf29 --- /dev/null +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_phy.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2024 Hisilicon Limited. +#include +#include +#include +#include "dp_comm.h" +#include "dp_config.h" +#include "dp_reg.h" +#include "dp_phy.h" + +int hibmc_dp_serdes_set_tx_cfg(struct hibmc_dp_dev *dp, u8 train_set[HIBMC= _DP_LANE_NUM_MAX]) +{ + u32 serdes_tx_cfg[4][4] =3D { {DP_PHY_VOL0_PRE0, DP_PHY_VOL0_PRE1, + DP_PHY_VOL0_PRE2, DP_PHY_VOL0_PRE3}, + {DP_PHY_VOL1_PRE0, DP_PHY_VOL1_PRE1, DP_PHY_VOL1_PRE2}, + {DP_PHY_VOL2_PRE0, DP_PHY_VOL2_PRE1}, {DP_PHY_VOL3_PRE0}}; + int cfg[2]; + int i; + + for (i =3D 0; i < HIBMC_DP_LANE_NUM_MAX; i++) { + cfg[i] =3D serdes_tx_cfg[(train_set[i] & 0x3)] + [(train_set[i] << DP_TRAIN_PRE_EMPHASIS_SHIFT & 0x3)]; + if (!cfg[i]) { + cfg[i] =3D DP_PHY_VOL3_PRE0; + drm_warn(dp->dev, "dp serdes cfg beyonds the allowable range\n"); + } + + /* lane1 offset is 4 */ + writel(FIELD_PREP(HIBMC_DP_PMA_TXDEEMPH, cfg[i]), + dp->phy_base + HIBMC_DP_PMA_LANE0_OFFSET + i * 4); + } + + usleep_range(300, 500); + + if (readl(dp->phy_base + HIBMC_DP_LANE_STATUS_OFFSET) !=3D DP_PHY_DONE) { + drm_err(dp->dev, "dp serdes cfg failed\n"); + return -EAGAIN; + } + + return 0; +} + +int hibmc_dp_serdes_rate_switch(u8 rate, struct hibmc_dp_dev *dp) +{ + writel(rate, dp->phy_base + HIBMC_DP_LANE0_RATE_OFFSET); + writel(rate, dp->phy_base + HIBMC_DP_LANE1_RATE_OFFSET); + + usleep_range(300, 500); + + if (readl(dp->phy_base + HIBMC_DP_LANE_STATUS_OFFSET) !=3D DP_PHY_DONE) { + drm_err(dp->dev, "dp serdes rate switching failed\n"); + return -EAGAIN; + } + + if (rate < DP_PHY_BW_8_1) + drm_warn(dp->dev, "reducing serdes rate to :%d\n", + rate ? rate * HIBMC_DP_LINK_RATE_CAL * 10 : 162); + + return 0; +} + +int hibmc_dp_phy_init(struct hibmc_dp_dev *dp) +{ + dp->phy_base =3D dp->base + HIBMC_DP_HOST_OFFSET; + + writel(FIELD_PREP(HIBMC_DP_PMA_TXDEEMPH, DP_PHY_VOL0_PRE0), + dp->phy_base + HIBMC_DP_PMA_LANE0_OFFSET); + writel(FIELD_PREP(HIBMC_DP_PMA_TXDEEMPH, DP_PHY_VOL0_PRE0), + dp->phy_base + HIBMC_DP_PMA_LANE1_OFFSET); + + return hibmc_dp_serdes_rate_switch(DP_PHY_BW_8_1, dp); +} diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_phy.h b/drivers/gpu/drm/= hisilicon/hibmc/dp/dp_phy.h new file mode 100644 index 000000000000..db9fddd24d0e --- /dev/null +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_phy.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (c) 2025 Hisilicon Limited. */ + +#ifndef DP_PHY_H +#define DP_PHY_H + +/* dp phy reg */ +#define HIBMC_DP_HOST_OFFSET 0x10000 +#define HIBMC_DP_LANE0_RATE_OFFSET 0x4 +#define HIBMC_DP_LANE1_RATE_OFFSET 0xc +#define HIBMC_DP_LANE_STATUS_OFFSET 0x10 +#define HIBMC_DP_PMA_LANE0_OFFSET 0x18 +#define HIBMC_DP_PMA_LANE1_OFFSET 0x1c +#define HIBMC_DP_PMA_TXDEEMPH GENMASK(18, 1) + +/* dp phy cfg parameter */ +#define DP_PHY_VOL0_PRE0 0x280 +#define DP_PHY_VOL0_PRE1 0x2300 +#define DP_PHY_VOL0_PRE2 0x53c0 +#define DP_PHY_VOL0_PRE3 0x8400 +#define DP_PHY_VOL1_PRE0 0x380 +#define DP_PHY_VOL1_PRE1 0x3440 +#define DP_PHY_VOL1_PRE2 0x6480 +#define DP_PHY_VOL2_PRE0 0x500 +#define DP_PHY_VOL2_PRE1 0x4500 +#define DP_PHY_VOL3_PRE0 0x600 +#define DP_PHY_BW_8_1 0x3 +#define DP_PHY_BW_5_4 0x2 +#define DP_PHY_BW_2_7 0x1 +#define DP_PHY_BW_1_62 0x0 + +#define DP_PHY_DONE 0x3 + +int hibmc_dp_phy_init(struct hibmc_dp_dev *dp); +int hibmc_dp_serdes_rate_switch(u8 rate, struct hibmc_dp_dev *dp); +int hibmc_dp_serdes_set_tx_cfg(struct hibmc_dp_dev *dp, u8 train_set[HIBMC= _DP_LANE_NUM_MAX]); + +#endif diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h b/drivers/gpu/drm/= hisilicon/hibmc/dp/dp_reg.h index 4a515c726d52..99ba9c951c41 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h @@ -72,5 +72,6 @@ #define HIBMC_DP_CFG_STREAM_TU_SYMBOL_FRAC_SIZE GENMASK(9, 6) #define HIBMC_DP_CFG_STREAM_HTOTAL_SIZE GENMASK(31, 16) #define HIBMC_DP_CFG_STREAM_HBLANK_SIZE GENMASK(15, 0) +#define HIBMC_DP_CFG_STREAM_SYNC_CALIBRATION GENMASK(31, 20) =20 #endif diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/= drm/hisilicon/hibmc/hibmc_drm_drv.c index e6de6d5edf6b..bade693d9730 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -28,9 +28,7 @@ #include "hibmc_drm_drv.h" #include "hibmc_drm_regs.h" =20 -#define HIBMC_DP_HOST_SERDES_CTRL 0x1f001c -#define HIBMC_DP_HOST_SERDES_CTRL_VAL 0x8a00 -#define HIBMC_DP_HOST_SERDES_CTRL_MASK 0x7ffff +#define HIBMC_DP_HOST_SERDES_CTRL 0x1f001c =20 DEFINE_DRM_GEM_FOPS(hibmc_fops); =20 @@ -122,8 +120,8 @@ static int hibmc_kms_init(struct hibmc_drm_private *pri= v) } =20 /* if DP existed, init DP */ - if ((readl(priv->mmio + HIBMC_DP_HOST_SERDES_CTRL) & - HIBMC_DP_HOST_SERDES_CTRL_MASK) =3D=3D HIBMC_DP_HOST_SERDES_CTRL_VAL= ) { + ret =3D readl(priv->mmio + HIBMC_DP_HOST_SERDES_CTRL); + if (ret) { ret =3D hibmc_dp_init(priv); if (ret) drm_err(dev, "failed to init dp: %d\n", ret); --=20 2.33.0 From nobody Thu Jan 30 19:15:55 2025 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 38D0B2AE68 for ; Mon, 27 Jan 2025 03:27:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.188 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737948442; cv=none; b=AYRP9p+8ev1Ekhu39OXR9c5elb1Co0RH/SxOJVlWWIaPfoSX+mfT2RdvEGBtK+aSj9ZSt9k11hMcM1u9klx/bE5zgN0Sz2/EkP6CkpoDB0I0CMCkRstDu9IvNLfQLXB2fF1R0MFGwNIxcy0dhTsO2bqGSQgKVOI+kI9B9mi+plg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737948442; c=relaxed/simple; bh=2QFjkdN5AGOHdbnVYfdqtt9Jo+tK0c4uSa9j6VWbsek=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=T3iF3lSz5Jop5gbXJSo2b27ZNEFyA8mHU/P9Nbm2nDaR5dk76wktSW1iKodu9b0XSd7v7EhBRpkU/THxJSqz5knlzGzwm3opeFjQ1fxXIfqItoPP623cI0+uuOVbQQTiBpbL8l4qPGukwGDYuQY83kaUCucrKorMRaMuKFHYOgw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=45.249.212.188 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.19.88.105]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4YhDMS1fmczrSlq; Mon, 27 Jan 2025 11:25:40 +0800 (CST) Received: from kwepemd500013.china.huawei.com (unknown [7.221.188.12]) by mail.maildlp.com (Postfix) with ESMTPS id 314AC1402CF; Mon, 27 Jan 2025 11:27:18 +0800 (CST) Received: from localhost.huawei.com (10.169.71.169) by kwepemd500013.china.huawei.com (7.221.188.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.34; Mon, 27 Jan 2025 11:27:16 +0800 From: Yongbang Shi To: , , , , , , , CC: , , , , , , , , Subject: [PATCH v1 drm-dp 2/4] drm/hisilicon/hibmc: Getting connector info and edid by using aux channel Date: Mon, 27 Jan 2025 11:20:22 +0800 Message-ID: <20250127032024.1542219-3-shiyongbang@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20250127032024.1542219-1-shiyongbang@huawei.com> References: <20250127032024.1542219-1-shiyongbang@huawei.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) To kwepemd500013.china.huawei.com (7.221.188.12) Content-Type: text/plain; charset="utf-8" From: Baihan Li Registering drm_aux and using it to get connector edid with drm functions. Refactoring some structs to fit aux's register framework. Signed-off-by: Baihan Li Signed-off-by: Yongbang Shi --- drivers/gpu/drm/hisilicon/hibmc/dp/dp_aux.c | 16 +++++--- drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h | 7 +++- drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 5 ++- drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h | 2 + drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c | 22 +++++----- .../gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c | 40 +++++++++++++++++-- .../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 5 +++ 7 files changed, 72 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_aux.c b/drivers/gpu/drm/= hisilicon/hibmc/dp/dp_aux.c index 0a903cce1fa9..c07c970d2e50 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_aux.c +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_aux.c @@ -8,6 +8,7 @@ #include #include "dp_comm.h" #include "dp_reg.h" +#include "dp_hw.h" =20 #define HIBMC_AUX_CMD_REQ_LEN GENMASK(7, 4) #define HIBMC_AUX_CMD_ADDR GENMASK(27, 8) @@ -124,7 +125,8 @@ static int hibmc_dp_aux_parse_xfer(struct hibmc_dp_dev = *dp, struct drm_dp_aux_ms /* ret >=3D 0 ,ret is size; ret < 0, ret is err code */ static ssize_t hibmc_dp_aux_xfer(struct drm_dp_aux *aux, struct drm_dp_aux= _msg *msg) { - struct hibmc_dp_dev *dp =3D container_of(aux, struct hibmc_dp_dev, aux); + struct hibmc_dp_dev *dp =3D ((struct hibmc_dp *)container_of(aux, struct = hibmc_dp, + aux))->dp_dev; u32 aux_cmd; int ret; u32 val; /* val will be assigned at the beginning of readl_poll_timeout f= unction */ @@ -151,14 +153,16 @@ static ssize_t hibmc_dp_aux_xfer(struct drm_dp_aux *a= ux, struct drm_dp_aux_msg * return hibmc_dp_aux_parse_xfer(dp, msg); } =20 -void hibmc_dp_aux_init(struct hibmc_dp_dev *dp) +void hibmc_dp_aux_init(struct hibmc_dp *dp) { - hibmc_dp_reg_write_field(dp, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_SYNC_LEN_= SEL, 0x0); - hibmc_dp_reg_write_field(dp, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_TIMER_TIM= EOUT, 0x1); - hibmc_dp_reg_write_field(dp, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_MIN_PULSE= _NUM, + hibmc_dp_reg_write_field(dp->dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_S= YNC_LEN_SEL, 0x0); + hibmc_dp_reg_write_field(dp->dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_T= IMER_TIMEOUT, 0x1); + hibmc_dp_reg_write_field(dp->dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_M= IN_PULSE_NUM, HIBMC_DP_MIN_PULSE_NUM); =20 dp->aux.transfer =3D hibmc_dp_aux_xfer; - dp->aux.is_remote =3D 0; + dp->aux.name =3D kasprintf(GFP_KERNEL, "HIBMC DRM dp aux"); + dp->aux.drm_dev =3D dp->drm_dev; drm_dp_aux_init(&dp->aux); + dp->dp_dev->aux =3D &dp->aux; } diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h b/drivers/gpu/drm= /hisilicon/hibmc/dp/dp_comm.h index 00b23301d26e..7edcecd5a5f0 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h @@ -11,8 +11,11 @@ #include #include #include + #include =20 +#include "dp_hw.h" + #define HIBMC_DP_LANE_NUM_MAX 2 =20 struct hibmc_link_status { @@ -32,7 +35,7 @@ struct hibmc_dp_link { }; =20 struct hibmc_dp_dev { - struct drm_dp_aux aux; + struct drm_dp_aux *aux; struct drm_device *dev; void __iomem *base; struct mutex lock; /* protects concurrent RW in hibmc_dp_reg_write_field(= ) */ @@ -58,7 +61,7 @@ struct hibmc_dp_dev { mutex_unlock(&_dp->lock); \ } while (0) =20 -void hibmc_dp_aux_init(struct hibmc_dp_dev *dp); +void hibmc_dp_aux_init(struct hibmc_dp *dp); int hibmc_dp_link_training(struct hibmc_dp_dev *dp); =20 #endif diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/h= isilicon/hibmc/dp/dp_hw.c index 0dac4cfdde7c..50050908606f 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c @@ -3,6 +3,7 @@ =20 #include #include +#include #include "dp_config.h" #include "dp_comm.h" #include "dp_reg.h" @@ -156,7 +157,7 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp) struct drm_device *drm_dev =3D dp->drm_dev; struct hibmc_dp_dev *dp_dev; =20 - dp_dev =3D devm_kzalloc(drm_dev->dev, sizeof(struct hibmc_dp_dev), GFP_KE= RNEL); + dp_dev =3D drmm_kcalloc(drm_dev, 1, sizeof(struct hibmc_dp_dev), GFP_KERN= EL); if (!dp_dev) return -ENOMEM; =20 @@ -167,7 +168,7 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp) dp_dev->dev =3D drm_dev; dp_dev->base =3D dp->mmio + HIBMC_DP_OFFSET; =20 - hibmc_dp_aux_init(dp_dev); + hibmc_dp_aux_init(dp); =20 if (hibmc_dp_phy_init(dp_dev)) return -EAGAIN; diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h b/drivers/gpu/drm/h= isilicon/hibmc/dp/dp_hw.h index 4dc13b3d9875..53b6d0beecea 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h @@ -10,6 +10,7 @@ #include #include #include +#include =20 struct hibmc_dp_dev; =20 @@ -19,6 +20,7 @@ struct hibmc_dp { struct drm_encoder encoder; struct drm_connector connector; void __iomem *mmio; + struct drm_dp_aux aux; }; =20 int hibmc_dp_hw_init(struct hibmc_dp *dp); diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c b/drivers/gpu/drm= /hisilicon/hibmc/dp/dp_link.c index 1124cd70c320..695cb9c0b643 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c @@ -27,7 +27,7 @@ static int hibmc_dp_link_training_configure(struct hibmc_= dp_dev *dp) /* set rate and lane count */ buf[0] =3D dp->link.cap.link_rate; buf[1] =3D DP_LANE_COUNT_ENHANCED_FRAME_EN | dp->link.cap.lanes; - ret =3D drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, sizeof(buf)); + ret =3D drm_dp_dpcd_write(dp->aux, DP_LINK_BW_SET, buf, sizeof(buf)); if (ret !=3D sizeof(buf)) { drm_dbg_dp(dp->dev, "dp aux write link rate and lanes failed, ret: %d\n"= , ret); return ret >=3D 0 ? -EIO : ret; @@ -36,13 +36,13 @@ static int hibmc_dp_link_training_configure(struct hibm= c_dp_dev *dp) /* set 8b/10b and downspread */ buf[0] =3D DP_SPREAD_AMP_0_5; buf[1] =3D DP_SET_ANSI_8B10B; - ret =3D drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf, sizeof(buf)); + ret =3D drm_dp_dpcd_write(dp->aux, DP_DOWNSPREAD_CTRL, buf, sizeof(buf)); if (ret !=3D sizeof(buf)) { drm_dbg_dp(dp->dev, "dp aux write 8b/10b and downspread failed, ret: %d\= n", ret); return ret >=3D 0 ? -EIO : ret; } =20 - ret =3D drm_dp_read_dpcd_caps(&dp->aux, dp->dpcd); + ret =3D drm_dp_read_dpcd_caps(dp->aux, dp->dpcd); if (ret) drm_err(dp->dev, "dp aux read dpcd failed, ret: %d\n", ret); =20 @@ -85,7 +85,7 @@ static int hibmc_dp_link_set_pattern(struct hibmc_dp_dev = *dp, int pattern) =20 hibmc_dp_reg_write_field(dp, HIBMC_DP_PHYIF_CTRL0, HIBMC_DP_CFG_PAT_SEL, = val); =20 - ret =3D drm_dp_dpcd_write(&dp->aux, DP_TRAINING_PATTERN_SET, &buf, sizeof= (buf)); + ret =3D drm_dp_dpcd_write(dp->aux, DP_TRAINING_PATTERN_SET, &buf, sizeof(= buf)); if (ret !=3D sizeof(buf)) { drm_dbg_dp(dp->dev, "dp aux write training pattern set failed\n"); return ret >=3D 0 ? -EIO : ret; @@ -115,7 +115,7 @@ static int hibmc_dp_link_training_cr_pre(struct hibmc_d= p_dev *dp) if (ret) return ret; =20 - ret =3D drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, train_set, dp-= >link.cap.lanes); + ret =3D drm_dp_dpcd_write(dp->aux, DP_TRAINING_LANE0_SET, train_set, dp->= link.cap.lanes); if (ret !=3D dp->link.cap.lanes) { drm_dbg_dp(dp->dev, "dp aux write training lane set failed\n"); return ret >=3D 0 ? -EIO : ret; @@ -198,9 +198,9 @@ static int hibmc_dp_link_training_cr(struct hibmc_dp_de= v *dp) =20 voltage_tries =3D 1; for (cr_tries =3D 0; cr_tries < 80; cr_tries++) { - drm_dp_link_train_clock_recovery_delay(&dp->aux, dp->dpcd); + drm_dp_link_train_clock_recovery_delay(dp->aux, dp->dpcd); =20 - ret =3D drm_dp_dpcd_read_link_status(&dp->aux, lane_status); + ret =3D drm_dp_dpcd_read_link_status(dp->aux, lane_status); if (ret !=3D DP_LINK_STATUS_SIZE) { drm_err(dp->dev, "Get lane status failed\n"); return ret; @@ -224,7 +224,7 @@ static int hibmc_dp_link_training_cr(struct hibmc_dp_de= v *dp) if (ret) return ret; =20 - ret =3D drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dp->link.trai= n_set, + ret =3D drm_dp_dpcd_write(dp->aux, DP_TRAINING_LANE0_SET, dp->link.train= _set, dp->link.cap.lanes); if (ret !=3D dp->link.cap.lanes) { drm_dbg_dp(dp->dev, "Update link training failed\n"); @@ -251,9 +251,9 @@ static int hibmc_dp_link_training_channel_eq(struct hib= mc_dp_dev *dp) return ret; =20 for (eq_tries =3D 0; eq_tries < HIBMC_EQ_MAX_RETRY; eq_tries++) { - drm_dp_link_train_channel_eq_delay(&dp->aux, dp->dpcd); + drm_dp_link_train_channel_eq_delay(dp->aux, dp->dpcd); =20 - ret =3D drm_dp_dpcd_read_link_status(&dp->aux, lane_status); + ret =3D drm_dp_dpcd_read_link_status(dp->aux, lane_status); if (ret !=3D DP_LINK_STATUS_SIZE) { drm_err(dp->dev, "get lane status failed\n"); break; @@ -278,7 +278,7 @@ static int hibmc_dp_link_training_channel_eq(struct hib= mc_dp_dev *dp) if (ret) return ret; =20 - ret =3D drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, + ret =3D drm_dp_dpcd_write(dp->aux, DP_TRAINING_LANE0_SET, dp->link.train_set, dp->link.cap.lanes); if (ret !=3D dp->link.cap.lanes) { drm_dbg_dp(dp->dev, "Update link training failed\n"); diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c b/drivers/gpu/d= rm/hisilicon/hibmc/hibmc_drm_dp.c index 603d6b198a54..fac8485a69d9 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c @@ -15,11 +15,27 @@ =20 static int hibmc_dp_connector_get_modes(struct drm_connector *connector) { + struct hibmc_dp *dp =3D to_hibmc_dp(connector); + const struct drm_edid *drm_edid; int count; =20 - count =3D drm_add_modes_noedid(connector, connector->dev->mode_config.max= _width, + drm_edid =3D drm_edid_read_ddc(connector, &dp->aux.ddc); + + drm_edid_connector_update(connector, drm_edid); + + if (drm_edid) { + count =3D drm_edid_connector_add_modes(connector); + if (count) + goto out; + } + + count =3D drm_add_modes_noedid(connector, + connector->dev->mode_config.max_width, connector->dev->mode_config.max_height); - drm_set_preferred_mode(connector, 1024, 768); // temporary implementation + drm_set_preferred_mode(connector, 1024, 768); + +out: + drm_edid_free(drm_edid); =20 return count; } @@ -28,12 +44,28 @@ static const struct drm_connector_helper_funcs hibmc_dp= _conn_helper_funcs =3D { .get_modes =3D hibmc_dp_connector_get_modes, }; =20 +static int hibmc_dp_late_register(struct drm_connector *connector) +{ + struct hibmc_dp *dp =3D to_hibmc_dp(connector); + + return drm_dp_aux_register(&dp->aux); +} + +static void hibmc_dp_early_unregister(struct drm_connector *connector) +{ + struct hibmc_dp *dp =3D to_hibmc_dp(connector); + + drm_dp_aux_unregister(&dp->aux); +} + static const struct drm_connector_funcs hibmc_dp_conn_funcs =3D { .reset =3D drm_atomic_helper_connector_reset, .fill_modes =3D drm_helper_probe_single_connector_modes, .destroy =3D drm_connector_cleanup, .atomic_duplicate_state =3D drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state =3D drm_atomic_helper_connector_destroy_state, + .late_register =3D hibmc_dp_late_register, + .early_unregister =3D hibmc_dp_early_unregister, }; =20 static inline int hibmc_dp_prepare(struct hibmc_dp *dp, struct drm_display= _mode *mode) @@ -103,8 +135,8 @@ int hibmc_dp_init(struct hibmc_drm_private *priv) =20 drm_encoder_helper_add(encoder, &hibmc_dp_encoder_helper_funcs); =20 - ret =3D drm_connector_init(dev, connector, &hibmc_dp_conn_funcs, - DRM_MODE_CONNECTOR_DisplayPort); + ret =3D drm_connector_init_with_ddc(dev, connector, &hibmc_dp_conn_funcs, + DRM_MODE_CONNECTOR_DisplayPort, &dp->aux.ddc); if (ret) { drm_err(dev, "init dp connector failed: %d\n", ret); return ret; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/= drm/hisilicon/hibmc/hibmc_drm_drv.h index d982f1e4b958..3ddd71aada66 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -47,6 +47,11 @@ static inline struct hibmc_vdac *to_hibmc_vdac(struct dr= m_connector *connector) return container_of(connector, struct hibmc_vdac, connector); } =20 +static inline struct hibmc_dp *to_hibmc_dp(struct drm_connector *connector) +{ + return container_of(connector, struct hibmc_dp, connector); +} + static inline struct hibmc_drm_private *to_hibmc_drm_private(struct drm_de= vice *dev) { return container_of(dev, struct hibmc_drm_private, dev); --=20 2.33.0 From nobody Thu Jan 30 19:15:55 2025 Received: from szxga03-in.huawei.com (szxga03-in.huawei.com [45.249.212.189]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 688B540849 for ; Mon, 27 Jan 2025 03:27:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.189 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737948443; cv=none; b=QJ8hVl4lqTU/+nC9uD2DrQigQAcGury6P+L6Cqxc7X1Tw0ULXkWU39QkJX7H2XMn1o0FxGNkOJZXTIjvaDzjBl2kh6kHIN1MqSJ5pUUeU0TarRvR9okYiwxvm6Aq2Bbx+umRjQ2+RXIwspu05a5NpsFNWV3TPppLkr1wWH9Sloc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737948443; c=relaxed/simple; bh=XhPh9oHsRa4sv8n64JABG648snmDjQnlYQJzA+jAm/0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=r2/lkJPL1FaQS4ScdAuGgW+DIwgnzyTNFv83RU9pEDTN9G5EmRS7RZ0GWL4lHH/85i7XgRpGLYtEGEdeA9FH7g0Q+ANw0ImYlXnpPU/af+v0uifHHUZILZG001i2qLLijwJ/70yZf3Kjfy86y/fLP9Gnbq8LXmZxRjapDutf+FY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=45.249.212.189 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.19.163.48]) by szxga03-in.huawei.com (SkyGuard) with ESMTP id 4YhDLM6s7vzRlZ4; Mon, 27 Jan 2025 11:24:43 +0800 (CST) Received: from kwepemd500013.china.huawei.com (unknown [7.221.188.12]) by mail.maildlp.com (Postfix) with ESMTPS id 65F671802E1; Mon, 27 Jan 2025 11:27:19 +0800 (CST) Received: from localhost.huawei.com (10.169.71.169) by kwepemd500013.china.huawei.com (7.221.188.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.34; Mon, 27 Jan 2025 11:27:18 +0800 From: Yongbang Shi To: , , , , , , , CC: , , , , , , , , Subject: [PATCH v1 drm-dp 3/4] drm/hisilicon/hibmc: Add debugfs interface to enable colorbar feature and get link status Date: Mon, 27 Jan 2025 11:20:23 +0800 Message-ID: <20250127032024.1542219-4-shiyongbang@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20250127032024.1542219-1-shiyongbang@huawei.com> References: <20250127032024.1542219-1-shiyongbang@huawei.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) To kwepemd500013.china.huawei.com (7.221.188.12) Content-Type: text/plain; charset="utf-8" From: Baihan Li Create 3 files in drm debugfs: colorbar-cfg: Get/Set colorbar cfg hibmc-dp: Get dp link status hibmc-dp-edid: Print edid information Signed-off-by: Baihan Li Signed-off-by: Yongbang Shi --- drivers/gpu/drm/hisilicon/hibmc/Makefile | 3 +- drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h | 3 + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 58 +++++ drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h | 44 ++++ drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c | 40 +++- drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h | 4 +- .../drm/hisilicon/hibmc/hibmc_drm_debugfs.c | 214 ++++++++++++++++++ .../gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c | 2 + .../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 3 + .../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 2 + 10 files changed, 363 insertions(+), 10 deletions(-) create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_debugfs.c diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/his= ilicon/hibmc/Makefile index 35a74cc10c80..c14f5182c067 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only hibmc-drm-y :=3D hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm= _i2c.o \ - dp/dp_aux.o dp/dp_link.o dp/dp_hw.o dp/dp_phy.o hibmc_drm_dp.o + dp/dp_aux.o dp/dp_link.o dp/dp_hw.o dp/dp_phy.o hibmc_drm_dp.o \ + hibmc_drm_debugfs.o =20 obj-$(CONFIG_DRM_HISI_HIBMC) +=3D hibmc-drm.o diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h b/drivers/gpu/drm= /hisilicon/hibmc/dp/dp_comm.h index 7edcecd5a5f0..67f6c81a35ed 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h @@ -26,6 +26,9 @@ struct hibmc_link_status { struct hibmc_link_cap { u8 link_rate; u8 lanes; + int rx_dpcd_revision; + bool is_tps3; + bool is_tps4; }; =20 struct hibmc_dp_link { diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/h= isilicon/hibmc/dp/dp_hw.c index 50050908606f..9c8b91ff0e3b 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c @@ -226,3 +226,61 @@ int hibmc_dp_mode_set(struct hibmc_dp *dp, struct drm_= display_mode *mode) =20 return 0; } + +u8 hibmc_dp_get_link_rate(struct hibmc_dp *dp) +{ + return dp->dp_dev->link.cap.link_rate; +} + +u8 hibmc_dp_get_lanes(struct hibmc_dp *dp) +{ + return dp->dp_dev->link.cap.lanes; +} + +int hibmc_dp_get_dpcd(struct hibmc_dp *dp) +{ + return dp->dp_dev->link.cap.rx_dpcd_revision; +} + +static const struct hibmc_dp_color_raw g_rgb_raw[] =3D { + {CBAR_COLOR_BAR, 0x000, 0x000, 0x000}, + {CBAR_WHITE, 0xfff, 0xfff, 0xfff}, + {CBAR_RED, 0xfff, 0x000, 0x000}, + {CBAR_ORANGE, 0xfff, 0x800, 0x000}, + {CBAR_YELLOW, 0xfff, 0xfff, 0x000}, + {CBAR_GREEN, 0x000, 0xfff, 0x000}, + {CBAR_CYAN, 0x000, 0x800, 0x800}, + {CBAR_BLUE, 0x000, 0x000, 0xfff}, + {CBAR_PURPLE, 0x800, 0x000, 0x800}, + {CBAR_BLACK, 0x000, 0x000, 0x000}, +}; + +void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg= *cfg) +{ + struct hibmc_dp_dev *dp_dev =3D dp->dp_dev; + struct hibmc_dp_color_raw raw_data; + + if (cfg->enable) { + hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(9), + cfg->self_timing); + hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, GENMASK(8, 1), + cfg->dynamic_rate); + if (cfg->pattern =3D=3D CBAR_COLOR_BAR) { + hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(10), 0); + } else { + raw_data =3D g_rgb_raw[cfg->pattern]; + drm_dbg_dp(dp->drm_dev, "r:%x g:%x b:%x\n", raw_data.r_value, + raw_data.g_value, raw_data.b_value); + hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(10), 1); + hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, GENMASK(23, 1= 2), + raw_data.r_value); + hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL1, GENMASK(23, = 12), + raw_data.g_value); + hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL1, GENMASK(11, = 0), + raw_data.b_value); + } + } + + hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(0), cfg->en= able); + writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL); +} diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h b/drivers/gpu/drm/h= isilicon/hibmc/dp/dp_hw.h index 53b6d0beecea..f2f59f2feb3c 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h @@ -14,6 +14,44 @@ =20 struct hibmc_dp_dev; =20 +enum hibmc_dp_cbar_pattern { + CBAR_COLOR_BAR, + CBAR_WHITE, + CBAR_RED, + CBAR_ORANGE, + CBAR_YELLOW, + CBAR_GREEN, + CBAR_CYAN, + CBAR_BLUE, + CBAR_PURPLE, + CBAR_BLACK, +}; + +struct hibmc_dp_color_raw { + enum hibmc_dp_cbar_pattern pattern; + u32 r_value; + u32 g_value; + u32 b_value; +}; + +struct hibmc_dp_cbar_cfg { + bool enable; + bool self_timing; + u8 dynamic_rate; /* 0:static, 1-255(frame):dynamic */ + enum hibmc_dp_cbar_pattern pattern; +}; + +enum hibmc_dp_hpd_status { + HIBMC_DP_HPD_DETECTING, + HIBMC_DP_HPD_IN, + HIBMC_DP_HPD_OUT, + HIBMC_DP_HPD_SHORT, /* Short hpd (irq_hpd) */ + HIBMC_DP_HPD_DET_FAIL, + HIBMC_DP_HPD_IN_SIMULATE, + HIBMC_DP_HPD_OUT_SIMULATE, + HIBMC_DP_HPD_SHORT_SIMULATE, +}; + struct hibmc_dp { struct hibmc_dp_dev *dp_dev; struct drm_device *drm_dev; @@ -21,10 +59,16 @@ struct hibmc_dp { struct drm_connector connector; void __iomem *mmio; struct drm_dp_aux aux; + struct hibmc_dp_cbar_cfg cfg; + bool is_inited; }; =20 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); +int hibmc_dp_get_dpcd(struct hibmc_dp *dp); +u8 hibmc_dp_get_link_rate(struct hibmc_dp *dp); +u8 hibmc_dp_get_lanes(struct hibmc_dp *dp); +void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg= *cfg); =20 #endif diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c b/drivers/gpu/drm= /hisilicon/hibmc/dp/dp_link.c index 695cb9c0b643..20849f1ebd0c 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c @@ -4,9 +4,11 @@ #include #include #include + #include "dp_comm.h" #include "dp_reg.h" #include "dp_phy.h" +#include "dp_config.h" =20 #define HIBMC_EQ_MAX_RETRY 5 =20 @@ -42,11 +44,7 @@ static int hibmc_dp_link_training_configure(struct hibmc= _dp_dev *dp) return ret >=3D 0 ? -EIO : ret; } =20 - ret =3D drm_dp_read_dpcd_caps(dp->aux, dp->dpcd); - if (ret) - drm_err(dp->dev, "dp aux read dpcd failed, ret: %d\n", ret); - - return ret; + return 0; } =20 static int hibmc_dp_link_set_pattern(struct hibmc_dp_dev *dp, int pattern) @@ -189,15 +187,17 @@ static int hibmc_dp_link_training_cr(struct hibmc_dp_= dev *dp) bool level_changed; u32 voltage_tries; u32 cr_tries; + u32 max_cr; int ret; =20 /* * DP 1.4 spec define 10 for maxtries value, for pre DP 1.4 version set a= limit of 80 * (4 voltage levels x 4 preemphasis levels x 5 identical voltage retries) */ + max_cr =3D dp->link.cap.rx_dpcd_revision >=3D DP_DPCD_REV_14 ? 10 : 80; =20 voltage_tries =3D 1; - for (cr_tries =3D 0; cr_tries < 80; cr_tries++) { + for (cr_tries =3D 0; cr_tries < max_cr; cr_tries++) { drm_dp_link_train_clock_recovery_delay(dp->aux, dp->dpcd); =20 ret =3D drm_dp_dpcd_read_link_status(dp->aux, lane_status); @@ -234,7 +234,7 @@ static int hibmc_dp_link_training_cr(struct hibmc_dp_de= v *dp) voltage_tries =3D level_changed ? 1 : voltage_tries + 1; } =20 - drm_err(dp->dev, "dp link training clock recovery 80 times failed\n"); + drm_err(dp->dev, "dp link training clock recovery %u times failed\n", max= _cr); dp->link.status.clock_recovered =3D false; =20 return 0; @@ -244,9 +244,17 @@ static int hibmc_dp_link_training_channel_eq(struct hi= bmc_dp_dev *dp) { u8 lane_status[DP_LINK_STATUS_SIZE] =3D {0}; u8 eq_tries; + int tps; int ret; =20 - ret =3D hibmc_dp_link_set_pattern(dp, DP_TRAINING_PATTERN_2); + if (dp->link.cap.is_tps4) + tps =3D DP_TRAINING_PATTERN_4; + else if (dp->link.cap.is_tps3) + tps =3D DP_TRAINING_PATTERN_3; + else + tps =3D DP_TRAINING_PATTERN_2; + + ret =3D hibmc_dp_link_set_pattern(dp, tps); if (ret) return ret; =20 @@ -313,11 +321,27 @@ static int hibmc_dp_link_downgrade_training_eq(struct= hibmc_dp_dev *dp) return hibmc_dp_link_reduce_rate(dp); } =20 +static void hibmc_dp_update_caps(struct hibmc_dp_dev *dp) +{ + dp->link.cap.rx_dpcd_revision =3D dp->dpcd[DP_DPCD_REV]; + + dp->link.cap.is_tps3 =3D (dp->dpcd[DP_DPCD_REV] >=3D DP_DPCD_REV_13) && + (dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED); + dp->link.cap.is_tps4 =3D (dp->dpcd[DP_DPCD_REV] >=3D DP_DPCD_REV_14) && + (dp->dpcd[DP_MAX_DOWNSPREAD] & DP_TPS4_SUPPORTED); +} + int hibmc_dp_link_training(struct hibmc_dp_dev *dp) { struct hibmc_dp_link *link =3D &dp->link; int ret; =20 + ret =3D drm_dp_read_dpcd_caps(dp->aux, dp->dpcd); + if (ret) + drm_err(dp->dev, "dp aux read dpcd failed, ret: %d\n", ret); + + hibmc_dp_update_caps(dp); + while (true) { ret =3D hibmc_dp_link_training_cr_pre(dp); if (ret) diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h b/drivers/gpu/drm/= hisilicon/hibmc/dp/dp_reg.h index 99ba9c951c41..c43ad6b30c2c 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h @@ -23,6 +23,8 @@ #define HIBMC_DP_VIDEO_MSA1 0x11c #define HIBMC_DP_VIDEO_MSA2 0x120 #define HIBMC_DP_VIDEO_HORIZONTAL_SIZE 0X124 +#define HIBMC_DP_COLOR_BAR_CTRL 0x260 +#define HIBMC_DP_COLOR_BAR_CTRL1 0x264 #define HIBMC_DP_TIMING_GEN_CONFIG0 0x26c #define HIBMC_DP_TIMING_GEN_CONFIG2 0x274 #define HIBMC_DP_TIMING_GEN_CONFIG3 0x278 @@ -72,6 +74,6 @@ #define HIBMC_DP_CFG_STREAM_TU_SYMBOL_FRAC_SIZE GENMASK(9, 6) #define HIBMC_DP_CFG_STREAM_HTOTAL_SIZE GENMASK(31, 16) #define HIBMC_DP_CFG_STREAM_HBLANK_SIZE GENMASK(15, 0) -#define HIBMC_DP_CFG_STREAM_SYNC_CALIBRATION GENMASK(31, 20) +#define HIBMC_DP_CFG_STREAM_SYNC_CALIBRATION GENMASK(31, 20) =20 #endif diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_debugfs.c b/drivers/= gpu/drm/hisilicon/hibmc/hibmc_drm_debugfs.c new file mode 100644 index 000000000000..f6885399c2b3 --- /dev/null +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_debugfs.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2024 Hisilicon Limited. + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "hibmc_drm_drv.h" + +static void hibmc_dump_edid(struct seq_file *m, const struct edid *edid) +{ + const struct detailed_pixel_timing *pixel_data; + int i; + + seq_puts(m, "EDID:\n"); + seq_printf(m, "\theader: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x= 0x%02x\n", + edid->header[0], edid->header[1], edid->header[2], edid->header[3], + edid->header[4], edid->header[5], edid->header[6], edid->header[7]); + + seq_puts(m, "Vendor & product info:\n"); + seq_printf(m, "\tmfg_id: 0x%02x 0x%02x\n", edid->mfg_id[0], edid->mfg_id[= 1]); + seq_printf(m, "\tprod_code: 0x%02x 0x%02x\n", edid->prod_code[0], edid->p= rod_code[1]); + seq_printf(m, "\tserial: 0x%08x\n", edid->serial); + seq_printf(m, "\tmfg_week/year: 0x%02x 0x%02x\n", edid->mfg_week, edid->m= fg_year); + + seq_puts(m, "EDID version:\n"); + seq_printf(m, "\tversion: 0x%02x\n", edid->version); + seq_printf(m, "\trevision: 0x%02x\n", edid->revision); + + seq_puts(m, "Display info:\n"); + seq_printf(m, "\tinput: 0x%02x\n", edid->input); + seq_printf(m, "\twidth_cm: 0x%02x\n", edid->width_cm); + seq_printf(m, "\theight_cm: 0x%02x\n", edid->height_cm); + seq_printf(m, "\tgamma: 0x%02x\n", edid->gamma); + seq_printf(m, "\tfeatures: 0x%02x\n", edid->features); + + seq_puts(m, "Color characteristics:\n"); + seq_printf(m, "\tred_green_lo: 0x%02x\n", edid->red_green_lo); + seq_printf(m, "\tblue/black_white_lo: 0x%02x\n", *(&edid->red_green_lo) += 1); + seq_printf(m, "\tred_x/y: 0x%02x 0x%02x\n", edid->red_x, edid->red_y); + seq_printf(m, "\tgreen_x/y: 0x%02x 0x%02x\n", edid->green_x, edid->green_= y); + seq_printf(m, "\tblue_x/y: 0x%02x 0x%02x\n", edid->blue_x, edid->blue_y); + seq_printf(m, "\twhite_x/y: 0x%02x 0x%02x\n", edid->white_x, edid->white_= y); + + seq_puts(m, "Est. timings and mfg rsvd timings:\n"); + seq_printf(m, "\test_timings_t1/2: 0x%02x 0x%02x\n", + edid->established_timings.t1, edid->established_timings.t2); + + seq_puts(m, "Standard timings 1-8:\n"); + for (i =3D 0; i < ARRAY_SIZE(edid->standard_timings); i++) { + seq_printf(m, "\tstandard_timings[%d] hsize/vfreq_aspect: 0x%02x 0x%02x\= n", + i, edid->standard_timings[i].hsize, + edid->standard_timings[i].vfreq_aspect); + } + + seq_puts(m, "Detailing timings 1-4:\n"); + for (i =3D 0; i < ARRAY_SIZE(edid->detailed_timings); i++) { + pixel_data =3D &edid->detailed_timings[i].data.pixel_data; + seq_printf(m, "\tdetailed_timing[%d] pixel_clock: 0x%04x\n", + i, edid->detailed_timings[i].pixel_clock); + seq_printf(m, "\tdetailed_timing[%d] hactive: %u\n", i, + (pixel_data->hactive_hblank_hi & 0xf0) << 4 | pixel_data->hactive_lo= ); + seq_printf(m, "\tdetailed_timing[%d] vactive: %u\n", i, + (pixel_data->vactive_vblank_hi & 0xf0) << 4 | pixel_data->vactive_lo= ); + } + + seq_puts(m, "Others:\n"); + seq_printf(m, "\textensions: 0x%02x\n", edid->extensions); + seq_printf(m, "\tchecksum: 0x%02x\n", edid->checksum); +} + +static int hibmc_dp_edid_show(struct seq_file *m, void *arg) +{ + struct drm_info_node *node =3D m->private; + struct drm_device *dev =3D node->minor->dev; + struct hibmc_drm_private *priv =3D to_hibmc_drm_private(dev); + struct edid *edid; + char name[20]; + int idx; + + if (!drm_dev_enter(dev, &idx)) + return -ENODEV; + + edid =3D drm_get_edid(&priv->dp.connector, &priv->dp.aux.ddc); + if (edid) { + drm_edid_get_monitor_name(edid, name, ARRAY_SIZE(name)); + seq_printf(m, "Monitor name: %s\n", name); + hibmc_dump_edid(m, edid); + kfree(edid); + } else { + seq_puts(m, "No connector available!\n"); + } + + drm_dev_exit(idx); + + return 0; +} + +static int hibmc_dp_show(struct seq_file *m, void *arg) +{ + struct drm_info_node *node =3D m->private; + struct drm_device *dev =3D node->minor->dev; + struct hibmc_drm_private *priv =3D to_hibmc_drm_private(dev); + int idx; + + if (!drm_dev_enter(dev, &idx)) + return -ENODEV; + + seq_printf(m, "enable lanes: %u\n", hibmc_dp_get_lanes(&priv->dp)); + seq_printf(m, "link rate: %d\n", hibmc_dp_get_link_rate(&priv->dp) * 27); + seq_printf(m, "vfresh: %d\n", drm_mode_vrefresh(&priv->crtc.mode)); + seq_printf(m, "dpcd version: 0x%x\n", hibmc_dp_get_dpcd(&priv->dp)); + + drm_dev_exit(idx); + + return 0; +} + +static ssize_t hibmc_control_write(struct file *file, const char __user *u= ser_buf, + size_t size, loff_t *ppos) +{ + struct hibmc_drm_private *priv =3D file_inode(file)->i_private; + struct hibmc_dp_cbar_cfg *cfg =3D &priv->dp.cfg; + u32 input =3D 0; + int ret, idx; + u8 val; + + ret =3D kstrtou32_from_user(user_buf, size, 0, &input); + if (ret) + return ret; + + val =3D FIELD_GET(GENMASK(13, 10), input); + if (val > 9) + return -EINVAL; + cfg->pattern =3D val; + cfg->enable =3D FIELD_GET(BIT(0), input); + cfg->self_timing =3D FIELD_GET(BIT(1), input); + cfg->dynamic_rate =3D FIELD_GET(GENMASK(9, 2), input); + + ret =3D drm_dev_enter(&priv->dev, &idx); + if (!ret) + return -ENODEV; + + hibmc_dp_set_cbar(&priv->dp, cfg); + + drm_dev_exit(idx); + + return size; +} + +static int hibmc_dp_dbgfs_show(struct seq_file *m, void *arg) +{ + struct hibmc_drm_private *priv =3D m->private; + struct hibmc_dp_cbar_cfg *cfg =3D &priv->dp.cfg; + u32 output =3D 0; + int idx; + + if (!drm_dev_enter(&priv->dev, &idx)) + return -ENODEV; + + /* bit[0]: 0: enable colorbar, 1: disable colorbar + * bit[1]: 0: timing follows XDP, 1: internal self timing + * bit[2,9]: 0: static colorbar image, + * 1~255: right shifting a type of color per (1~255)frames + * bit[10,13]: 0~9: color bar, white, red, orange, + * yellow, green, cyan, bule, pupper, black + */ + output =3D cfg->enable | (cfg->self_timing << 1) | + (cfg->dynamic_rate << 2) | (cfg->pattern << 10); + + drm_dev_exit(idx); + + seq_printf(m, "hibmc dp colorbar cfg: %u\n", output); + + return 0; +} + +static int hibmc_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, hibmc_dp_dbgfs_show, inode->i_private); +} + +static const struct file_operations hibmc_dbg_fops =3D { + .owner =3D THIS_MODULE, + .write =3D hibmc_control_write, + .read =3D seq_read, + .open =3D hibmc_open, + .llseek =3D seq_lseek, + .release =3D single_release, +}; + +static struct drm_info_list hibmc_debugfs_list[] =3D { + { "hibmc-dp", hibmc_dp_show }, + { "hibmc-dp-edid", hibmc_dp_edid_show }, +}; + +void hibmc_debugfs_register(struct hibmc_drm_private *priv) +{ + struct drm_connector *dp_conn =3D &priv->dp.connector; + struct drm_minor *minor =3D priv->dev.primary; + + /* create the file in drm directory, so we don't need to remove manually = */ + debugfs_create_file("colorbar-cfg", 0200, + dp_conn->debugfs_entry, priv, &hibmc_dbg_fops); + + drm_debugfs_create_files(hibmc_debugfs_list, ARRAY_SIZE(hibmc_debugfs_lis= t), + minor->debugfs_root, minor); +} diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c b/drivers/gpu/d= rm/hisilicon/hibmc/hibmc_drm_dp.c index fac8485a69d9..cc1f9ee0656f 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c @@ -146,5 +146,7 @@ int hibmc_dp_init(struct hibmc_drm_private *priv) =20 drm_connector_attach_encoder(connector, encoder); =20 + dp->is_inited =3D true; + return 0; } diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/= drm/hisilicon/hibmc/hibmc_drm_drv.c index bade693d9730..3d4d5185c523 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -352,6 +352,9 @@ static int hibmc_pci_probe(struct pci_dev *pdev, goto err_unload; } =20 + if (priv->dp.is_inited) + hibmc_debugfs_register(priv); + drm_client_setup(dev, NULL); =20 return 0; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/= drm/hisilicon/hibmc/hibmc_drm_drv.h index 3ddd71aada66..ff61efb8a2ab 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -69,4 +69,6 @@ int hibmc_ddc_create(struct drm_device *drm_dev, struct h= ibmc_vdac *connector); =20 int hibmc_dp_init(struct hibmc_drm_private *priv); =20 +void hibmc_debugfs_register(struct hibmc_drm_private *priv); + #endif --=20 2.33.0 From nobody Thu Jan 30 19:15:55 2025 Received: from szxga05-in.huawei.com (szxga05-in.huawei.com [45.249.212.191]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D68701FC115 for ; Mon, 27 Jan 2025 03:27:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.191 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737948444; cv=none; b=Xvg/nIeZNLNUu5q8iM4IvyrFuHh7jetGZXGrK1gcIvKW7Aa9FyBtlb8otPirPQoijWMegFyRYd5vtVV5CRp/eYW4M0af9u6oYW15gcb0+HGhPozIFU8a/d5SBSCFnTRPNHH7+gyL63r+fVLuYDH0QZv3gcWJZHoN/SENvmm4Yuc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737948444; c=relaxed/simple; bh=iRE6ypUdFQkZskrrqu1GnMRBDtx8i3r96IqUy89Nb7c=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=l9Zv31KwEaMyfh6G4wTAkFxdQ2uwgEbAT/xrUSEamhCVubZPo6AHYm1o4llhh4D47TF7fK7Rkp5WjyoYc4px98Le826LJDHKLNYZCMlxX1FSh3lDG3yErVaq8rrX63Sss64sqUeblPs9mOVlWM388FVFa9URHnUUJAzjD2Ay3Jk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=45.249.212.191 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.19.88.234]) by szxga05-in.huawei.com (SkyGuard) with ESMTP id 4YhDKR4jPcz1l0Bk; Mon, 27 Jan 2025 11:23:55 +0800 (CST) Received: from kwepemd500013.china.huawei.com (unknown [7.221.188.12]) by mail.maildlp.com (Postfix) with ESMTPS id A0785140257; Mon, 27 Jan 2025 11:27:20 +0800 (CST) Received: from localhost.huawei.com (10.169.71.169) by kwepemd500013.china.huawei.com (7.221.188.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.34; Mon, 27 Jan 2025 11:27:19 +0800 From: Yongbang Shi To: , , , , , , , CC: , , , , , , , , Subject: [PATCH v1 drm-dp 4/4] drm/hisilicon/hibmc: Enable this hot plug detect of irq feature Date: Mon, 27 Jan 2025 11:20:24 +0800 Message-ID: <20250127032024.1542219-5-shiyongbang@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20250127032024.1542219-1-shiyongbang@huawei.com> References: <20250127032024.1542219-1-shiyongbang@huawei.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) To kwepemd500013.china.huawei.com (7.221.188.12) Content-Type: text/plain; charset="utf-8" From: Baihan Li This is a series of functions about getting dp connector status function, registering irq function, interrupt handler function, and hpd event process function to realize DP HPD feature. Signed-off-by: Baihan Li Signed-off-by: Yongbang Shi --- .../gpu/drm/hisilicon/hibmc/dp/dp_config.h | 1 + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 30 +++++++ drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h | 2 + drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h | 2 + .../gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c | 61 ++++++++++++++- .../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 78 +++++++++++++++---- .../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 14 ++++ 7 files changed, 171 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h b/drivers/gpu/d= rm/hisilicon/hibmc/dp/dp_config.h index c5feef8dc27d..08f9e1caf7fc 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h @@ -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) =3D=3D 0x2 ? 86 : 46) +#define HIBMC_DP_INT_ENABLE 0xc =20 #endif diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/h= isilicon/hibmc/dp/dp_hw.c index 9c8b91ff0e3b..1797b40e54fc 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c @@ -181,6 +181,7 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp) /* int init */ 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); /* rst */ writel(HIBMC_DP_DPTX_RST, dp_dev->base + HIBMC_DP_DPTX_RST_CTRL); /* clock enable */ @@ -284,3 +285,32 @@ void hibmc_dp_set_cbar(struct hibmc_dp *dp, const stru= ct hibmc_dp_cbar_cfg *cfg) hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(0), cfg->en= able); writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL); } + +enum hibmc_dp_hpd_status hibmc_dp_get_hpd_status(const struct hibmc_dp *dp) +{ + enum hibmc_dp_hpd_status status; + u32 val; + + mdelay(100); + + val =3D readl(dp->dp_dev->base + HIBMC_DP_HPD_STATUS); + val =3D (val & HIBMC_DP_CFG_SINK_HPD_STATE_MACHINE) >> 4; + + switch (val) { + case 0: /* 0: IDLE */ + case 3: /* 3: DONE */ + status =3D HIBMC_DP_HPD_OUT; + break; + case 1: /* 1: PLUG */ + status =3D HIBMC_DP_HPD_IN; + break; + case 4: /* 4: ASSERT_LENGHT */ + status =3D HIBMC_DP_HPD_DETECTING; + break; + default: /* unknown status */ + status =3D HIBMC_DP_HPD_DET_FAIL; + break; + } + + return status; +} diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h b/drivers/gpu/drm/h= isilicon/hibmc/dp/dp_hw.h index f2f59f2feb3c..6f1da7a0b9e7 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h @@ -61,6 +61,7 @@ struct hibmc_dp { struct drm_dp_aux aux; struct hibmc_dp_cbar_cfg cfg; bool is_inited; + u32 hpd_status; }; =20 int hibmc_dp_hw_init(struct hibmc_dp *dp); @@ -70,5 +71,6 @@ int hibmc_dp_get_dpcd(struct hibmc_dp *dp); u8 hibmc_dp_get_link_rate(struct hibmc_dp *dp); u8 hibmc_dp_get_lanes(struct hibmc_dp *dp); void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg= *cfg); +enum hibmc_dp_hpd_status hibmc_dp_get_hpd_status(const struct hibmc_dp *dp= ); =20 #endif diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h b/drivers/gpu/drm/= hisilicon/hibmc/dp/dp_reg.h index c43ad6b30c2c..6c4ba0412b15 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h @@ -12,6 +12,7 @@ #define HIBMC_DP_AUX_RD_DATA0 0x64 #define HIBMC_DP_AUX_REQ 0x74 #define HIBMC_DP_AUX_STATUS 0x78 +#define HIBMC_DP_HPD_STATUS 0x98 #define HIBMC_DP_PHYIF_CTRL0 0xa0 #define HIBMC_DP_VIDEO_CTRL 0x100 #define HIBMC_DP_VIDEO_CONFIG0 0x104 @@ -75,5 +76,6 @@ #define HIBMC_DP_CFG_STREAM_HTOTAL_SIZE GENMASK(31, 16) #define HIBMC_DP_CFG_STREAM_HBLANK_SIZE GENMASK(15, 0) #define HIBMC_DP_CFG_STREAM_SYNC_CALIBRATION GENMASK(31, 20) +#define HIBMC_DP_CFG_SINK_HPD_STATE_MACHINE GENMASK(7, 4) =20 #endif diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c b/drivers/gpu/d= rm/hisilicon/hibmc/hibmc_drm_dp.c index cc1f9ee0656f..e4aee75e12e8 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c @@ -11,8 +11,12 @@ #include =20 #include "hibmc_drm_drv.h" +#include "hibmc_drm_regs.h" #include "dp/dp_hw.h" =20 +#define DP_MASKED_SINK_HPD_UNPLUG_INT BIT(3) +#define DP_MASKED_SINK_HPD_PLUG_INT BIT(2) + static int hibmc_dp_connector_get_modes(struct drm_connector *connector) { struct hibmc_dp *dp =3D to_hibmc_dp(connector); @@ -106,6 +110,57 @@ static const struct drm_encoder_helper_funcs hibmc_dp_= encoder_helper_funcs =3D { .atomic_disable =3D hibmc_dp_encoder_disable, }; =20 +static int hibmc_dp_cfg(struct hibmc_dp *dp) +{ + int ret; + + ret =3D hibmc_dp_hw_init(dp); + if (ret) + return ret; + + hibmc_dp_display_en(dp, false); + + return 0; +} + +irqreturn_t hibmc_dp_hpd_event_isr(int irq, void *arg) +{ + struct drm_device *dev =3D (struct drm_device *)arg; + struct hibmc_drm_private *priv =3D to_hibmc_drm_private(dev); + enum hibmc_dp_hpd_status status; + struct drm_display_mode *mode; + int idx; + + if (!drm_dev_enter(dev, &idx)) + return -ENODEV; + + status =3D hibmc_dp_get_hpd_status(&priv->dp); + if (status =3D=3D HIBMC_DP_HPD_IN) { + if (!(priv->dp.hpd_status & DP_MASKED_SINK_HPD_PLUG_INT)) + goto err; + drm_dbg_dp(&priv->dev, "HPD IN isr occur!\n"); + hibmc_dp_cfg(&priv->dp); + drm_kms_helper_connector_hotplug_event(&priv->dp.connector); + mode =3D &priv->crtc.state->adjusted_mode; + hibmc_dp_prepare(&priv->dp, mode); + hibmc_dp_display_en(&priv->dp, true); + } else if (status =3D=3D HIBMC_DP_HPD_OUT) { + if (!(priv->dp.hpd_status & DP_MASKED_SINK_HPD_UNPLUG_INT)) + goto err; + drm_dbg_dp(&priv->dev, "HPD OUT isr occur!\n"); + hibmc_dp_display_en(&priv->dp, false); + } else { + drm_warn(&priv->dev, "HPD unknown isr occur, status: %d\n", status); + } + +err: + priv->dp.hpd_status =3D 0; + + drm_dev_exit(idx); + + return IRQ_HANDLED; +} + int hibmc_dp_init(struct hibmc_drm_private *priv) { struct drm_device *dev =3D &priv->dev; @@ -118,14 +173,12 @@ int hibmc_dp_init(struct hibmc_drm_private *priv) dp->mmio =3D priv->mmio; dp->drm_dev =3D dev; =20 - ret =3D hibmc_dp_hw_init(&priv->dp); + ret =3D hibmc_dp_cfg(dp); if (ret) { - drm_err(dev, "hibmc dp hw init failed: %d\n", ret); + drm_err(dev, "hibmc dp cfg failed: %d\n", ret); return ret; } =20 - hibmc_dp_display_en(&priv->dp, false); - encoder->possible_crtcs =3D drm_crtc_mask(crtc); ret =3D drmm_encoder_init(dev, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL= ); if (ret) { diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/= drm/hisilicon/hibmc/hibmc_drm_drv.c index 3d4d5185c523..42323ff89309 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -29,9 +29,13 @@ #include "hibmc_drm_regs.h" =20 #define HIBMC_DP_HOST_SERDES_CTRL 0x1f001c +#define HIBMC_DP_INTSTAT 0x1e0724 +#define HIBMC_DP_INTCLR 0x1e0728 =20 DEFINE_DRM_GEM_FOPS(hibmc_fops); =20 +static const char *g_irqs_names_map[HIBMC_MAX_VECTORS] =3D { "vblank", "hp= d" }; + static irqreturn_t hibmc_interrupt(int irq, void *arg) { struct drm_device *dev =3D (struct drm_device *)arg; @@ -49,6 +53,22 @@ static irqreturn_t hibmc_interrupt(int irq, void *arg) return IRQ_HANDLED; } =20 +static irqreturn_t hibmc_dp_interrupt(int irq, void *arg) +{ + struct drm_device *dev =3D (struct drm_device *)arg; + struct hibmc_drm_private *priv =3D to_hibmc_drm_private(dev); + u32 status; + + status =3D readl(priv->mmio + HIBMC_DP_INTSTAT); + if (status) { + priv->dp.hpd_status =3D status; + writel(status, priv->mmio + HIBMC_DP_INTCLR); + return IRQ_WAKE_THREAD; + } + + return IRQ_HANDLED; +} + static int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { @@ -248,15 +268,52 @@ static int hibmc_hw_init(struct hibmc_drm_private *pr= iv) return 0; } =20 -static int hibmc_unload(struct drm_device *dev) +static void hibmc_unload(struct drm_device *dev) +{ + drm_atomic_helper_shutdown(dev); + + pci_disable_msi(to_pci_dev(dev->dev)); +} + +static int hibmc_msi_init(struct drm_device *dev) { + struct hibmc_drm_private *priv =3D to_hibmc_drm_private(dev); struct pci_dev *pdev =3D to_pci_dev(dev->dev); + int ret; =20 - drm_atomic_helper_shutdown(dev); + ret =3D pci_alloc_irq_vectors(pdev, HIBMC_MIN_VECTORS, + HIBMC_MAX_VECTORS, PCI_IRQ_MSI); + if (ret < 0) { + drm_err(dev, "enabling MSI failed: %d\n", ret); + return ret; + } =20 - free_irq(pdev->irq, dev); + priv->valid_irq_num =3D ret; =20 - pci_disable_msi(to_pci_dev(dev->dev)); + priv->irqs =3D drmm_kcalloc(dev, priv->valid_irq_num, + sizeof(struct hibmc_irq), GFP_KERNEL); + if (!priv->irqs) + return -ENOMEM; + + for (int i =3D 0; i < priv->valid_irq_num; i++) { + snprintf(priv->irqs[i].name, sizeof(priv->irqs[i].name) - 1, "%s-%s-%s", + dev->driver->name, pci_name(pdev), g_irqs_names_map[i]); + + priv->irqs[i].irq_num =3D pci_irq_vector(pdev, i); + + if (i) + /* PCI devices require shared interrupts. */ + ret =3D devm_request_threaded_irq(&pdev->dev, priv->irqs[i].irq_num, + hibmc_dp_interrupt, hibmc_dp_hpd_event_isr, + IRQF_SHARED, priv->irqs[i].name, dev); + else + ret =3D devm_request_irq(&pdev->dev, priv->irqs[i].irq_num, hibmc_inter= rupt, + IRQF_SHARED, priv->irqs[i].name, dev); + if (ret) { + drm_err(dev, "install irq failed: %d\n", ret); + return ret; + } + } =20 return 0; } @@ -288,15 +345,10 @@ static int hibmc_load(struct drm_device *dev) goto err; } =20 - ret =3D pci_enable_msi(pdev); + ret =3D hibmc_msi_init(dev); if (ret) { - drm_warn(dev, "enabling MSI failed: %d\n", ret); - } else { - /* PCI devices require shared interrupts. */ - ret =3D request_irq(pdev->irq, hibmc_interrupt, IRQF_SHARED, - dev->driver->name, dev); - if (ret) - drm_warn(dev, "install irq failed: %d\n", ret); + drm_err(dev, "hibmc msi init failed, ret:%d\n", ret); + goto err; } =20 /* reset all the states of crtc/plane/encoder/connector */ @@ -375,7 +427,7 @@ static void hibmc_pci_remove(struct pci_dev *pdev) =20 static void hibmc_pci_shutdown(struct pci_dev *pdev) { - drm_atomic_helper_shutdown(pci_get_drvdata(pdev)); + hibmc_pci_remove(pdev); } =20 static const struct pci_device_id hibmc_pci_table[] =3D { diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/= drm/hisilicon/hibmc/hibmc_drm_drv.h index ff61efb8a2ab..3bc4194689cb 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -22,6 +22,14 @@ =20 #include "dp/dp_hw.h" =20 +#define HIBMC_MIN_VECTORS 1 +#define HIBMC_MAX_VECTORS 2 + +struct hibmc_irq { + s32 irq_num; + char name[32]; +}; + struct hibmc_vdac { struct drm_device *dev; struct drm_encoder encoder; @@ -40,6 +48,10 @@ struct hibmc_drm_private { struct drm_crtc crtc; struct hibmc_vdac vdac; struct hibmc_dp dp; + + /* irqs */ + struct hibmc_irq *irqs; + u32 valid_irq_num; }; =20 static inline struct hibmc_vdac *to_hibmc_vdac(struct drm_connector *conne= ctor) @@ -71,4 +83,6 @@ int hibmc_dp_init(struct hibmc_drm_private *priv); =20 void hibmc_debugfs_register(struct hibmc_drm_private *priv); =20 +irqreturn_t hibmc_dp_hpd_event_isr(int irq, void *arg); + #endif --=20 2.33.0