pmaports/main/linux-postmarketos/0001-rx51-drm-regression-workaround.patch

117 lines
3.3 KiB
Diff
Raw Normal View History

--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -36,12 +36,15 @@ struct omap_crtc {
struct videomode vm;
- bool ignore_digit_sync_lost;
+ bool ignore_sync_lost;
bool enabled;
bool pending;
wait_queue_head_t pending_wait;
struct drm_pending_vblank_event *event;
+
+ struct work_struct error_work;
+ u32 error_channels;
};
/* -----------------------------------------------------------------------------
@@ -157,7 +160,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
* Digit output produces some sync lost interrupts during the
* first frame when enabling, so we need to ignore those.
*/
- omap_crtc->ignore_digit_sync_lost = true;
+ omap_crtc->ignore_sync_lost = true;
}
framedone_irq = priv->dispc_ops->mgr_get_framedone_irq(channel);
@@ -191,7 +194,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
}
if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
- omap_crtc->ignore_digit_sync_lost = false;
+ omap_crtc->ignore_sync_lost = false;
/* make sure the irq handler sees the value above */
mb();
}
@@ -263,17 +266,65 @@ static const struct dss_mgr_ops mgr_ops = {
* Setup, Flush and Page Flip
*/
+static void omap_crtc_error_worker(struct work_struct *work)
+{
+ struct omap_crtc *omap_crtc = container_of(work, struct omap_crtc, error_work);
+ struct drm_crtc *crtc = &omap_crtc->base;
+ struct drm_device *dev = omap_crtc->base.dev;
+ struct omap_drm_private *priv = dev->dev_private;
+
+ drm_modeset_lock(&crtc->mutex, NULL);
+
+ dev_warn(dev->dev, "sync lost on %s, enabling & disabling...\n",
+ omap_crtc->name);
+
+ priv->dispc_ops->mgr_enable(omap_crtc->channel, false);
+
+ msleep(50);
+ dev_warn(dev->dev, "sync lost enabling %s\n",
+ omap_crtc->name);
+
+ priv->dispc_ops->mgr_enable(omap_crtc->channel, true);
+
+ msleep(50);
+
+ dev_warn(dev->dev, "sync lost recovery done on on %s\n",
+ omap_crtc->name);
+
+ omap_crtc->ignore_sync_lost = false;
+ /* make sure the irq handler sees the value above */
+ mb();
+
+ drm_modeset_unlock(&crtc->mutex);
+}
+
void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+ struct drm_device *dev = omap_crtc->base.dev;
+ struct omap_drm_private *priv = dev->dev_private;
+ enum omap_channel channel = omap_crtc_channel(crtc);
+ u32 sync_lost_irq;
+ bool sync_lost;
+
+ sync_lost_irq = priv->dispc_ops->mgr_get_sync_lost_irq(channel);
- if (omap_crtc->ignore_digit_sync_lost) {
- irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
- if (!irqstatus)
- return;
+ sync_lost = irqstatus & sync_lost_irq;
+
+ if (sync_lost) {
+ if (omap_crtc->ignore_sync_lost) {
+ irqstatus &= ~sync_lost_irq;
+ } else {
+ /* error worker will set this to false */
+ omap_crtc->ignore_sync_lost = true;
+ schedule_work(&omap_crtc->error_work);
+ }
}
- DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
+ if (!irqstatus)
+ return;
+
+ printk("%s: errors: %08x\n", omap_crtc->name, irqstatus);
}
void omap_crtc_vblank_irq(struct drm_crtc *crtc)
@@ -612,6 +663,8 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
init_waitqueue_head(&omap_crtc->pending_wait);
+ INIT_WORK(&omap_crtc->error_work, omap_crtc_error_worker);
+
omap_crtc->channel = channel;
omap_crtc->name = channel_names[channel];