summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
diff options
context:
space:
mode:
authorDa Lv <lvda3@hisilicon.com>2019-08-20 23:06:02 +0000
committerSam Ravnborg <sam@ravnborg.org>2019-08-21 19:15:32 +0200
commitff57c6513820efe945b61863cf4a51b79f18b592 (patch)
treeab250db2b1680e7c3fcf1401a005404251c32e0f /drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
parent019cbd4a4feb3aa3a917d78e7110e3011bbff6d5 (diff)
drm: kirin: Fix for hikey620 display offset problem
The original HiKey (620) board has had a long running issue where when using a 1080p montior, the display would occasionally blink and come come back with a horizontal offset (usually also shifting the colors, depending on the value of the offset%4). After lots of analysis by HiSi developers, they found the issue was due to when running at 1080p, it was possible to hit the device memory bandwidth limits, which could cause the DSI signal to get out of sync. Unfortunately the DSI logic doesn't have the ability to automatically recover from this situation, but we can get a an LDI underflow interrupt when it happens. To then correct the issue, when we get an LDI underflow irq, we we can simply suspend and resume the display, which resets the hardware. Thus, this patch enables the ldi underflow interrupt, and initializes a workqueue that is used to suspend/resume the display to recover. Then when the irq occurs we clear it and schedule the workqueue to reset display engine. Cc: Rongrong Zou <zourongrong@gmail.com> Cc: Xinliang Liu <z.liuxinliang@hisilicon.com> Cc: David Airlie <airlied@linux.ie> Cc: Daniel Vetter <daniel@ffwll.ch> Cc: dri-devel <dri-devel@lists.freedesktop.org> Cc: Sam Ravnborg <sam@ravnborg.org> Acked-by: Xinliang Liu <z.liuxinliang@hisilicon.com> Reviewed-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: Da Lv <lvda3@hisilicon.com> Signed-off-by: Yidong Lin <linyidong@huawei.com> [jstultz: Reworded the commit message, checkpatch cleanups] Signed-off-by: John Stultz <john.stultz@linaro.org> Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Link: https://patchwork.freedesktop.org/patch/msgid/20190820230626.23253-2-john.stultz@linaro.org
Diffstat (limited to 'drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c')
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
index 0df1afdf319d..d972342527b8 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
@@ -58,6 +58,7 @@ struct ade_hw_ctx {
struct ade_crtc {
struct drm_crtc base;
struct ade_hw_ctx *ctx;
+ struct work_struct display_reset_wq;
bool enable;
u32 out_format;
};
@@ -176,6 +177,7 @@ static void ade_init(struct ade_hw_ctx *ctx)
*/
ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST,
FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND);
+ ade_update_bits(base + LDI_INT_EN, UNDERFLOW_INT_EN_OFST, MASK(1), 1);
}
static bool ade_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -345,6 +347,17 @@ static void ade_crtc_disable_vblank(struct drm_crtc *crtc)
MASK(1), 0);
}
+static void drm_underflow_wq(struct work_struct *work)
+{
+ struct ade_crtc *acrtc = container_of(work, struct ade_crtc,
+ display_reset_wq);
+ struct drm_device *drm_dev = (&acrtc->base)->dev;
+ struct drm_atomic_state *state;
+
+ state = drm_atomic_helper_suspend(drm_dev);
+ drm_atomic_helper_resume(drm_dev, state);
+}
+
static irqreturn_t ade_irq_handler(int irq, void *data)
{
struct ade_crtc *acrtc = data;
@@ -362,6 +375,12 @@ static irqreturn_t ade_irq_handler(int irq, void *data)
MASK(1), 1);
drm_crtc_handle_vblank(crtc);
}
+ if (status & BIT(UNDERFLOW_INT_EN_OFST)) {
+ ade_update_bits(base + LDI_INT_CLR, UNDERFLOW_INT_EN_OFST,
+ MASK(1), 1);
+ DRM_ERROR("LDI underflow!");
+ schedule_work(&acrtc->display_reset_wq);
+ }
return IRQ_HANDLED;
}
@@ -1038,6 +1057,9 @@ static int ade_drm_init(struct platform_device *pdev)
/* vblank irq init */
ret = devm_request_irq(dev->dev, ctx->irq, ade_irq_handler,
IRQF_SHARED, dev->driver->name, acrtc);
+
+ INIT_WORK(&acrtc->display_reset_wq, drm_underflow_wq);
+
if (ret)
return ret;