Commit 484436ec authored by Kuro Chung's avatar Kuro Chung Committed by Robert Foss

drm/bridge: it6505: fix hibernate to resume no display issue

When the system power resumes, the TTL input of IT6505 may experience
some noise before the video signal stabilizes, necessitating a video
reset. This patch is implemented to prevent a loop of video error
interrupts, which can occur when a video reset in the video FIFO error
interrupt triggers another such interrupt. The patch processes the SCDT
and FIFO error interrupts simultaneously and ignores any video FIFO
error interrupts caused by a video reset.

Fixes: b5c84a9e ("drm/bridge: add it6505 driver")
Signed-off-by: default avatarKuro Chung <kuro.chung@ite.com.tw>
Signed-off-by: default avatarHermes Wu <hermes.wu@ite.com.tw>
Reviewed-by: default avatarAngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: default avatarRobert Foss <rfoss@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20240522065528.1053439-1-kuro.chung@ite.com.tw
parent a856a53d
...@@ -1307,9 +1307,15 @@ static void it6505_video_reset(struct it6505 *it6505) ...@@ -1307,9 +1307,15 @@ static void it6505_video_reset(struct it6505 *it6505)
it6505_link_reset_step_train(it6505); it6505_link_reset_step_train(it6505);
it6505_set_bits(it6505, REG_DATA_MUTE_CTRL, EN_VID_MUTE, EN_VID_MUTE); it6505_set_bits(it6505, REG_DATA_MUTE_CTRL, EN_VID_MUTE, EN_VID_MUTE);
it6505_set_bits(it6505, REG_INFOFRAME_CTRL, EN_VID_CTRL_PKT, 0x00); it6505_set_bits(it6505, REG_INFOFRAME_CTRL, EN_VID_CTRL_PKT, 0x00);
it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, VIDEO_RESET);
it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, TX_FIFO_RESET);
it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, 0x00);
it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, RST_501_FIFO); it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, RST_501_FIFO);
it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, 0x00); it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, 0x00);
it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, VIDEO_RESET);
usleep_range(1000, 2000);
it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, 0x00); it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, 0x00);
} }
...@@ -2245,12 +2251,11 @@ static void it6505_link_training_work(struct work_struct *work) ...@@ -2245,12 +2251,11 @@ static void it6505_link_training_work(struct work_struct *work)
if (ret) { if (ret) {
it6505->auto_train_retry = AUTO_TRAIN_RETRY; it6505->auto_train_retry = AUTO_TRAIN_RETRY;
it6505_link_train_ok(it6505); it6505_link_train_ok(it6505);
return;
} else { } else {
it6505->auto_train_retry--; it6505->auto_train_retry--;
it6505_dump(it6505);
} }
it6505_dump(it6505);
} }
static void it6505_plugged_status_to_codec(struct it6505 *it6505) static void it6505_plugged_status_to_codec(struct it6505 *it6505)
...@@ -2471,31 +2476,53 @@ static void it6505_irq_link_train_fail(struct it6505 *it6505) ...@@ -2471,31 +2476,53 @@ static void it6505_irq_link_train_fail(struct it6505 *it6505)
schedule_work(&it6505->link_works); schedule_work(&it6505->link_works);
} }
static void it6505_irq_video_fifo_error(struct it6505 *it6505) static bool it6505_test_bit(unsigned int bit, const unsigned int *addr)
{ {
struct device *dev = it6505->dev; return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE));
DRM_DEV_DEBUG_DRIVER(dev, "video fifo overflow interrupt");
it6505->auto_train_retry = AUTO_TRAIN_RETRY;
flush_work(&it6505->link_works);
it6505_stop_hdcp(it6505);
it6505_video_reset(it6505);
} }
static void it6505_irq_io_latch_fifo_overflow(struct it6505 *it6505) static void it6505_irq_video_handler(struct it6505 *it6505, const int *int_status)
{ {
struct device *dev = it6505->dev; struct device *dev = it6505->dev;
int reg_0d, reg_int03;
DRM_DEV_DEBUG_DRIVER(dev, "IO latch fifo overflow interrupt"); /*
it6505->auto_train_retry = AUTO_TRAIN_RETRY; * When video SCDT change with video not stable,
flush_work(&it6505->link_works); * Or video FIFO error, need video reset
it6505_stop_hdcp(it6505); */
it6505_video_reset(it6505);
}
static bool it6505_test_bit(unsigned int bit, const unsigned int *addr) if ((!it6505_get_video_status(it6505) &&
{ (it6505_test_bit(INT_SCDT_CHANGE, (unsigned int *)int_status))) ||
return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE)); (it6505_test_bit(BIT_INT_IO_FIFO_OVERFLOW,
(unsigned int *)int_status)) ||
(it6505_test_bit(BIT_INT_VID_FIFO_ERROR,
(unsigned int *)int_status))) {
it6505->auto_train_retry = AUTO_TRAIN_RETRY;
flush_work(&it6505->link_works);
it6505_stop_hdcp(it6505);
it6505_video_reset(it6505);
usleep_range(10000, 11000);
/*
* Clear FIFO error IRQ to prevent fifo error -> reset loop
* HW will trigger SCDT change IRQ again when video stable
*/
reg_int03 = it6505_read(it6505, INT_STATUS_03);
reg_0d = it6505_read(it6505, REG_SYSTEM_STS);
reg_int03 &= (BIT(INT_VID_FIFO_ERROR) | BIT(INT_IO_LATCH_FIFO_OVERFLOW));
it6505_write(it6505, INT_STATUS_03, reg_int03);
DRM_DEV_DEBUG_DRIVER(dev, "reg08 = 0x%02x", reg_int03);
DRM_DEV_DEBUG_DRIVER(dev, "reg0D = 0x%02x", reg_0d);
return;
}
if (it6505_test_bit(INT_SCDT_CHANGE, (unsigned int *)int_status))
it6505_irq_scdt(it6505);
} }
static irqreturn_t it6505_int_threaded_handler(int unused, void *data) static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
...@@ -2508,15 +2535,12 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) ...@@ -2508,15 +2535,12 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
} irq_vec[] = { } irq_vec[] = {
{ BIT_INT_HPD, it6505_irq_hpd }, { BIT_INT_HPD, it6505_irq_hpd },
{ BIT_INT_HPD_IRQ, it6505_irq_hpd_irq }, { BIT_INT_HPD_IRQ, it6505_irq_hpd_irq },
{ BIT_INT_SCDT, it6505_irq_scdt },
{ BIT_INT_HDCP_FAIL, it6505_irq_hdcp_fail }, { BIT_INT_HDCP_FAIL, it6505_irq_hdcp_fail },
{ BIT_INT_HDCP_DONE, it6505_irq_hdcp_done }, { BIT_INT_HDCP_DONE, it6505_irq_hdcp_done },
{ BIT_INT_AUX_CMD_FAIL, it6505_irq_aux_cmd_fail }, { BIT_INT_AUX_CMD_FAIL, it6505_irq_aux_cmd_fail },
{ BIT_INT_HDCP_KSV_CHECK, it6505_irq_hdcp_ksv_check }, { BIT_INT_HDCP_KSV_CHECK, it6505_irq_hdcp_ksv_check },
{ BIT_INT_AUDIO_FIFO_ERROR, it6505_irq_audio_fifo_error }, { BIT_INT_AUDIO_FIFO_ERROR, it6505_irq_audio_fifo_error },
{ BIT_INT_LINK_TRAIN_FAIL, it6505_irq_link_train_fail }, { BIT_INT_LINK_TRAIN_FAIL, it6505_irq_link_train_fail },
{ BIT_INT_VID_FIFO_ERROR, it6505_irq_video_fifo_error },
{ BIT_INT_IO_FIFO_OVERFLOW, it6505_irq_io_latch_fifo_overflow },
}; };
int int_status[3], i; int int_status[3], i;
...@@ -2546,6 +2570,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) ...@@ -2546,6 +2570,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
if (it6505_test_bit(irq_vec[i].bit, (unsigned int *)int_status)) if (it6505_test_bit(irq_vec[i].bit, (unsigned int *)int_status))
irq_vec[i].handler(it6505); irq_vec[i].handler(it6505);
} }
it6505_irq_video_handler(it6505, (unsigned int *)int_status);
} }
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment