From: Kuro Chung <kuro.chung@xxxxxxxxxx> 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: b5c84a9edcd4 ("drm/bridge: add it6505 driver") Signed-off-by: Kuro Chung <kuro.chung@xxxxxxxxxx> Signed-off-by: Hermes Wu <hermes.wu@xxxxxxxxxx> --- V1->V3: update MAINTAINERS mail list V3->V4: remove function it6505_irq_video_fifo_error,it6505_irq_io_latch_fifo_overflow V4->V5: customer feedback again, update again, kernel build pass V5->V6: remove unrelated patch change, split into another patch V6->V7: modify code 0x02 to TX_FIFO_RESET by macro define V7->V8: fix merge conflict, change mail from 'cc' to 'to' V8->V9: modify patch description, patch summary V9->V10: modify patch summary, add Fixes V10->V11: modify patch description, add Signed-off-by V11->V12: moidfy patch description. --- drivers/gpu/drm/bridge/ite-it6505.c | 73 +++++++++++++++++++---------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 469157341f3ab..5703fcf4b7b00 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -1307,9 +1307,15 @@ static void it6505_video_reset(struct it6505 *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_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, 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); } @@ -2245,12 +2251,11 @@ static void it6505_link_training_work(struct work_struct *work) if (ret) { it6505->auto_train_retry = AUTO_TRAIN_RETRY; it6505_link_train_ok(it6505); - return; } else { it6505->auto_train_retry--; + it6505_dump(it6505); } - it6505_dump(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) 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; - - 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); + return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE)); } -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; + int reg_0d, reg_int03; - DRM_DEV_DEBUG_DRIVER(dev, "IO latch fifo overflow interrupt"); - it6505->auto_train_retry = AUTO_TRAIN_RETRY; - flush_work(&it6505->link_works); - it6505_stop_hdcp(it6505); - it6505_video_reset(it6505); -} + /* + * When video SCDT change with video not stable, + * Or video FIFO error, need video reset + */ -static bool it6505_test_bit(unsigned int bit, const unsigned int *addr) -{ - return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE)); + if ((!it6505_get_video_status(it6505) && + (it6505_test_bit(INT_SCDT_CHANGE, (unsigned int *) int_status))) || + (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) @@ -2508,15 +2535,12 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) } irq_vec[] = { { BIT_INT_HPD, it6505_irq_hpd }, { 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_DONE, it6505_irq_hdcp_done }, { 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 }, - { 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; @@ -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)) irq_vec[i].handler(it6505); } + it6505_irq_video_handler(it6505, (unsigned int *) int_status); } pm_runtime_put_sync(dev); -- 2.25.1