video: tegra: bridge: Enable CRC check for MAX Ser

This change enables internal video CRC check for
Maxim DP Serializer.

1. This sets the bit to enable CRC functionality
   and then add handlers for ERRB CRC errors.
2. Reading register clears the error.
3. Error can be injected using i2c tool to write
   error inject bit in register.

Below is flow to verify CRC functionality
1. Run GFX application like bubble
2. Read VTX41 register and confirm VID_ASIL_CRC_ERR bit is not set
3. Inject error by setting bit VID_ASIL_INJ_ERR.
4. Verify dmesg errors.

bug 3463178

Change-Id: I25c07413eb81bb4b40f35e15b53a4102ec68fa9e
Signed-off-by: prafulls <prafulls@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2751057
Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com>
Reviewed-by: Shu Zhong <shuz@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
prafulls
2022-07-25 15:50:04 +00:00
committed by Laxman Dewangan
parent 3cffc5689c
commit 02a15c114a

View File

@@ -96,6 +96,15 @@
#define MAX_GMSL_DP_SER_TX3_2 0xAB
#define MAX_GMSL_DP_SER_TX3_3 0xAF
#define MAX_GMSL_DP_SER_INTERNAL_CRC_X 0x449
#define MAX_GMSL_DP_SER_INTERNAL_CRC_Y 0x549
#define MAX_GMSL_DP_SER_INTERNAL_CRC_Z 0x649
#define MAX_GMSL_DP_SER_INTERNAL_CRC_U 0x749
#define MAX_GMSL_DP_SER_INTERNAL_CRC_ENABLE 0x9
#define MAX_GMSL_DP_SER_INTERNAL_CRC_ERR_DET 0x4
#define MAX_GMSL_DP_SER_INTERNAL_CRC_ERR_INJ 0x10
#define MAX_GMSL_ARRAY_SIZE 4
@@ -272,6 +281,32 @@ static int max_gmsl_read_lock(struct max_gmsl_dp_ser_priv *priv,
return -1;
}
static void max_gmsl_detect_internal_crc_error(struct max_gmsl_dp_ser_priv *priv,
struct device *dev)
{
int i, ret = 0;
static const int max_gmsl_internal_crc_regs[] = {
MAX_GMSL_DP_SER_INTERNAL_CRC_X,
MAX_GMSL_DP_SER_INTERNAL_CRC_Y,
MAX_GMSL_DP_SER_INTERNAL_CRC_Z,
MAX_GMSL_DP_SER_INTERNAL_CRC_U,
};
for (i = 0; i < MAX_GMSL_ARRAY_SIZE; i++) {
ret = max_gmsl_dp_ser_read(priv, max_gmsl_internal_crc_regs[i]);
/* Reading register will clear the detect bit */
if ((ret & MAX_GMSL_DP_SER_INTERNAL_CRC_ERR_DET) != 0U) {
dev_err(dev, "%s: INTERNAL CRC video error detected at pipe %d\n", __func__, i);
if ((ret & MAX_GMSL_DP_SER_INTERNAL_CRC_ERR_INJ) != 0U) {
/* CRC error is forcefuly injected, disable it */
ret = ret & (~MAX_GMSL_DP_SER_INTERNAL_CRC_ERR_INJ);
max_gmsl_dp_ser_write(priv, max_gmsl_internal_crc_regs[i], ret);
}
}
}
}
static irqreturn_t max_gsml_dp_ser_irq_handler(int irq, void *dev_id)
{
struct max_gmsl_dp_ser_priv *priv = dev_id;
@@ -282,6 +317,9 @@ 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 */
max_gmsl_detect_internal_crc_error(priv, dev);
dev_dbg(dev, "%s: Sticky bit LOSS_OF_LOCK_FLAG cleared\n", __func__);
return IRQ_HANDLED;
@@ -332,6 +370,16 @@ static void tegra_poll_gmsl_training_lock(struct work_struct *work)
goto reschedule;
}
/* enable internal CRC after link training */
max_gmsl_dp_ser_write(priv, MAX_GMSL_DP_SER_INTERNAL_CRC_X,
MAX_GMSL_DP_SER_INTERNAL_CRC_ENABLE);
max_gmsl_dp_ser_write(priv, MAX_GMSL_DP_SER_INTERNAL_CRC_Y,
MAX_GMSL_DP_SER_INTERNAL_CRC_ENABLE);
max_gmsl_dp_ser_write(priv, MAX_GMSL_DP_SER_INTERNAL_CRC_Z,
MAX_GMSL_DP_SER_INTERNAL_CRC_ENABLE);
max_gmsl_dp_ser_write(priv, MAX_GMSL_DP_SER_INTERNAL_CRC_U,
MAX_GMSL_DP_SER_INTERNAL_CRC_ENABLE);
max_gmsl_dp_ser_update(priv, MAX_GMSL_DP_SER_VID_TX_X,
MAX_GMSL_DP_SER_VID_TX_MASK, 0x1);
max_gmsl_dp_ser_update(priv, MAX_GMSL_DP_SER_VID_TX_Y,