From 90579e82d5f79eb858954a9a97f067f18ab19a5c Mon Sep 17 00:00:00 2001 From: prafulls Date: Fri, 29 Jul 2022 07:50:01 +0000 Subject: [PATCH] video: tegra: bridge: Enable CRC check for MAX Ser This change enables external video CRC check for Maxim DP Serializer. This change - 1. Enable video line CRC functionality by setting specific register bit. 2. Add interrupt handler check for remote CRC check failure. 3. Reverse GPIO tunnel and remote error check is already set. 4. If there are CRC error across GMSL link then dmesg spew will indicate it. Verification - 1. Play some GFX application and view on monitor. 2. At DES side, using GUI, For register INTR8, set bit ERR_TX_EN to 1. 3. Clear exiting dmesg using "dmesg --clear" 4. On SER, using i2ccmd tool, Set bit LINE_CRC_EN to 0 at register 0x100. 5. Confirm on dmesg for error message like - "Remote deserializer error detected" bug 3463178 Signed-off-by: prafulls Change-Id: Ieba2b19b7ce1a71173f6d34e61b1607f237cb1a5 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2753202 Reviewed-by: svc-mobile-coverity Reviewed-by: svc-mobile-cert Reviewed-by: svc_kernel_abi Reviewed-by: Shu Zhong GVS: Gerrit_Virtual_Submit --- .../dc/bridge/maxim_gmsl_dp_serializer.c | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/drivers/video/tegra/dc/bridge/maxim_gmsl_dp_serializer.c b/drivers/video/tegra/dc/bridge/maxim_gmsl_dp_serializer.c index f26e494a..4f2c49ea 100644 --- a/drivers/video/tegra/dc/bridge/maxim_gmsl_dp_serializer.c +++ b/drivers/video/tegra/dc/bridge/maxim_gmsl_dp_serializer.c @@ -28,6 +28,16 @@ #define MAX_GMSL_DP_SER_CTRL3_LOCK_MASK (1 << 3) #define MAX_GMSL_DP_SER_CTRL3_LOCK_VAL (1 << 3) +#define MAX_GMSL_DP_SER_INTR2 0x1A +#define MAX_GMSL_DP_SER_REM_ERR_OEN_A_MASK (1 << 4) +#define MAX_GMSL_DP_SER_REM_ERR_OEN_A_VAL (1 << 4) +#define MAX_GMSL_DP_SER_REM_ERR_OEN_B_MASK (1 << 5) +#define MAX_GMSL_DP_SER_REM_ERR_OEN_B_VAL (1 << 5) + +#define MAX_GMSL_DP_SER_INTR3 0x1B +#define MAX_GMSL_DP_SER_REM_ERR_FLAG_A (1 << 4) +#define MAX_GMSL_DP_SER_REM_ERR_FLAG_B (1 << 5) + #define MAX_GMSL_DP_SER_INTR8 0x20 #define MAX_GMSL_DP_SER_INTR8_MASK (1 << 0) #define MAX_GMSL_DP_SER_INTR8_VAL 0x1 @@ -307,6 +317,29 @@ static void max_gmsl_detect_internal_crc_error(struct max_gmsl_dp_ser_priv *priv } } +/* + * This function is responsible for detecting ANY remote deserializer + * errors. Note that the main error that we're interested in today is + * any video line CRC error reported by the deserializer. + */ +static void max_gmsl_detect_remote_error(struct max_gmsl_dp_ser_priv *priv, + struct device *dev) +{ + int ret = 0; + + ret = max_gmsl_dp_ser_read(priv, MAX_GMSL_DP_SER_INTR3); + + if (priv->link_a_is_enabled) { + if ((ret & MAX_GMSL_DP_SER_REM_ERR_FLAG_A) != 0) + dev_err(dev, "%s: Remote deserializer error detected on Link A\n", __func__); + } + + if (priv->link_b_is_enabled) { + if ((ret & MAX_GMSL_DP_SER_REM_ERR_FLAG_B) != 0) + dev_err(dev, "%s: Remote deserializer error detected on Link B\n", __func__); + } +} + static irqreturn_t max_gsml_dp_ser_irq_handler(int irq, void *dev_id) { struct max_gmsl_dp_ser_priv *priv = dev_id; @@ -317,10 +350,11 @@ static irqreturn_t max_gsml_dp_ser_irq_handler(int irq, void *dev_id) if (ret & MAX_GMSL_DP_SER_LOSS_OF_LOCK_FLAG) dev_dbg(dev, "%s: Fault due to GMSL Link Loss\n", __func__); - /* Detect error for CRC */ + /* Detect internal CRC errors inside serializer */ max_gmsl_detect_internal_crc_error(priv, dev); - dev_dbg(dev, "%s: Sticky bit LOSS_OF_LOCK_FLAG cleared\n", __func__); + /* Detect remote error across GMSL link */ + max_gmsl_detect_remote_error(priv, dev); return IRQ_HANDLED; } @@ -476,12 +510,21 @@ static int max_gmsl_dp_ser_init(struct device *dev) queue_delayed_work(priv->wq, &priv->delay_work, msecs_to_jiffies(500)); - ret = max_gmsl_dp_ser_read(priv, MAX_GMSL_DP_SER_INTR9); if (ret < 0) { dev_err(dev, "%s: INTR9 register read failed\n", __func__); return -EFAULT; } + + if (priv->link_a_is_enabled) + max_gmsl_dp_ser_update(priv, MAX_GMSL_DP_SER_INTR2, + MAX_GMSL_DP_SER_REM_ERR_OEN_A_MASK, + MAX_GMSL_DP_SER_REM_ERR_OEN_A_VAL); + if (priv->link_b_is_enabled) + max_gmsl_dp_ser_update(priv, MAX_GMSL_DP_SER_INTR2, + MAX_GMSL_DP_SER_REM_ERR_OEN_B_MASK, + MAX_GMSL_DP_SER_REM_ERR_OEN_B_VAL); + /* enable INTR8.LOSS_OF_LOCK_OEN */ max_gmsl_dp_ser_update(priv, MAX_GMSL_DP_SER_INTR8, MAX_GMSL_DP_SER_INTR8_MASK,