@@ -821,7 +821,7 @@ static void it6505_int_mask_enable(struct it6505 *it6505)
it6505_write(it6505, INT_MASK_02, BIT(INT_AUX_CMD_FAIL) |
BIT(INT_HDCP_KSV_CHECK) | BIT(INT_AUDIO_FIFO_ERROR));
- it6505_write(it6505, INT_MASK_03, BIT(INT_LINK_TRAIN_FAIL) |
+ it6505_write(it6505, INT_MASK_03,
BIT(INT_VID_FIFO_ERROR) | BIT(INT_IO_LATCH_FIFO_OVERFLOW));
}
@@ -1800,30 +1800,62 @@ static void it6505_link_training_setup(struct it6505 *it6505)
static bool it6505_link_start_auto_train(struct it6505 *it6505)
{
- int timeout = 500, link_training_state;
+ int link_training_state;
bool state = false;
+ struct device *dev = it6505->dev;
+ int int03;
+ unsigned long timeout;
+
+ guard(mutex)(&it6505->aux_lock);
+ /* Disable FIFO error interrupt trigger */
+ /* to prevent training fail loop issue */
+ it6505_set_bits(it6505, INT_MASK_03, BIT(INT_VID_FIFO_ERROR), 0);
+
+ it6505_write(it6505, INT_STATUS_03,
+ BIT(INT_LINK_TRAIN_FAIL) | BIT(INT_VID_FIFO_ERROR));
+ int03 = it6505_read(it6505, INT_STATUS_03);
- mutex_lock(&it6505->aux_lock);
it6505_set_bits(it6505, REG_TRAIN_CTRL0,
FORCE_CR_DONE | FORCE_EQ_DONE, 0x00);
- it6505_write(it6505, REG_TRAIN_CTRL1, FORCE_RETRAIN);
+
+ /* reset link state machine and re start training*/
+ it6505_write(it6505, REG_TRAIN_CTRL1,
+ FORCE_RETRAIN | MANUAL_TRAIN);
it6505_write(it6505, REG_TRAIN_CTRL1, AUTO_TRAIN);
- while (timeout > 0) {
+ timeout = jiffies + msecs_to_jiffies(100) + 1;
+ for (;;) {
usleep_range(1000, 2000);
link_training_state = it6505_read(it6505, REG_LINK_TRAIN_STS);
+ int03 = it6505_read(it6505, INT_STATUS_03);
+ if (int03 & BIT(INT_LINK_TRAIN_FAIL)) {
+ /* Ignore INT_VID_FIFO_ERROR when auto training fail*/
+ it6505_write(it6505, INT_STATUS_03,
+ BIT(INT_LINK_TRAIN_FAIL) |
+ BIT(INT_VID_FIFO_ERROR));
+
+ if (int03 & BIT(INT_VID_FIFO_ERROR)) {
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "video fifo error when training fail (%x)!",
+ int03);
+ }
+
+ break;
+ }
if (link_training_state > 0 &&
(link_training_state & LINK_STATE_NORP)) {
state = true;
- goto unlock;
+ break;
}
- timeout--;
+ if (time_after(jiffies, timeout))
+ break;
}
-unlock:
- mutex_unlock(&it6505->aux_lock);
+ /* recover interrupt trigger*/
+ it6505_set_bits(it6505, INT_MASK_03,
+ BIT(INT_VID_FIFO_ERROR), BIT(INT_VID_FIFO_ERROR));
return state;
}
@@ -2377,7 +2409,7 @@ static void it6505_stop_link_train(struct it6505 *it6505)
{
it6505->link_state = LINK_IDLE;
cancel_work_sync(&it6505->link_works);
- it6505_write(it6505, REG_TRAIN_CTRL1, FORCE_RETRAIN);
+ it6505_write(it6505, REG_TRAIN_CTRL1, FORCE_RETRAIN | MANUAL_TRAIN);
}
static void it6505_link_train_ok(struct it6505 *it6505)
@@ -2691,14 +2723,6 @@ static void it6505_irq_audio_fifo_error(struct it6505 *it6505)
it6505_enable_audio(it6505);
}
-static void it6505_irq_link_train_fail(struct it6505 *it6505)
-{
- struct device *dev = it6505->dev;
-
- DRM_DEV_DEBUG_DRIVER(dev, "link training fail interrupt");
- schedule_work(&it6505->link_works);
-}
-
static bool it6505_test_bit(unsigned int bit, const unsigned int *addr)
{
return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE));
@@ -2763,7 +2787,6 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
{ BIT_INT_AUX_CMD_FAIL, it6505_irq_aux_cmd_fail },
{ BIT_INT_HDCP_KSV_CHECK, it6505_irq_hdcp_ksv_check },
{ BIT_INT_AUDIO_FIFO_ERROR, it6505_irq_audio_fifo_error },
- { BIT_INT_LINK_TRAIN_FAIL, it6505_irq_link_train_fail },
};
int int_status[3], i;