From 2c62ef61b0361f6850140832b35bc4f400b9ccfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Matijevi=C4=87?= Date: Sat, 10 Feb 2018 20:33:59 +0100 Subject: [PATCH 01/11] SREv2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filip Matijević --- .../bindings/display/panel/panel-common.txt | 12 ++ arch/arm/boot/dts/omap4-droid4-xt894.dts | 3 + drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 13 ++ drivers/gpu/drm/omapdrm/dss/dispc.c | 36 ++++- drivers/gpu/drm/omapdrm/dss/omapdss.h | 2 + drivers/gpu/drm/omapdrm/omap_connector.c | 18 ++- drivers/gpu/drm/omapdrm/omap_connector.h | 1 + drivers/gpu/drm/omapdrm/omap_crtc.c | 158 +++++++++++++++++++-- drivers/gpu/drm/omapdrm/omap_crtc.h | 2 + drivers/gpu/drm/omapdrm/omap_fb.c | 20 +++ drivers/gpu/drm/omapdrm/omap_irq.c | 24 ++++ drivers/gpu/drm/omapdrm/omap_irq.h | 1 + 12 files changed, 280 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/panel-common.txt b/Documentation/devicetree/bindings/display/panel/panel-common.txt index 557fa765adcb..c646b8908458 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-common.txt +++ b/Documentation/devicetree/bindings/display/panel/panel-common.txt @@ -18,6 +18,18 @@ Descriptive Properties physical area where images are displayed. These properties are expressed in millimeters and rounded to the closest unit. +- orientation: The orientation property specifies the panel orientation + in relation to the device's casing. The following values are possible: + + * 0 = The top side of the panel matches the top side of the device's + casing. + * 1 = The top side of the panel matches the bottom side of the device's + casing. In other words the panel is mounted upside-down. + * 2 = The left side of the panel matches the top side of the device's + casing. + * 3 = The right side of the panel matches the top side of the device's + casing. + - label: The label property specifies a symbolic name for the panel as a string suitable for use by humans. It typically contains a name inscribed on the system (e.g. as an affixed label) or specified in the system's diff --git a/arch/arm/boot/dts/omap4-droid4-xt894.dts b/arch/arm/boot/dts/omap4-droid4-xt894.dts index b21084da490b..e11a24397163 100644 --- a/arch/arm/boot/dts/omap4-droid4-xt894.dts +++ b/arch/arm/boot/dts/omap4-droid4-xt894.dts @@ -6,6 +6,7 @@ /dts-v1/; #include +#include #include "omap443x.dtsi" #include "motorola-cpcap-mapphone.dtsi" @@ -181,6 +182,8 @@ height-mm = <89>; backlight = <&lcd_backlight>; + orientation = ; + panel-timing { clock-frequency = <0>; /* Calculated by dsi */ diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index 15399a1a666b..7a63d6775a27 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -68,6 +68,7 @@ struct panel_drv_data { int width_mm; int height_mm; + int orientation; struct omap_dsi_pin_config pin_config; @@ -1198,6 +1199,14 @@ static void dsicm_get_size(struct omap_dss_device *dssdev, *height = ddata->height_mm; } +static void dsicm_get_orientation(struct omap_dss_device *dssdev, + int *orientation) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + + *orientation = ddata->orientation; +} + static struct omap_dss_driver dsicm_ops = { .connect = dsicm_connect, .disconnect = dsicm_disconnect, @@ -1211,6 +1220,7 @@ static struct omap_dss_driver dsicm_ops = { .get_timings = dsicm_get_timings, .check_timings = dsicm_check_timings, .get_size = dsicm_get_size, + .get_orientation = dsicm_get_orientation, .enable_te = dsicm_enable_te, .get_te = dsicm_get_te, @@ -1259,6 +1269,9 @@ static int dsicm_probe_of(struct platform_device *pdev) ddata->height_mm = 0; of_property_read_u32(node, "height-mm", &ddata->height_mm); + ddata->orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; + of_property_read_u32(node, "orientation", &ddata->orientation); + in = omapdss_of_find_source_for_first_ep(node); if (IS_ERR(in)) { dev_err(&pdev->dev, "failed to find video source\n"); diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 4e8f68efd169..0904c3201914 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -157,6 +157,8 @@ struct dispc_features { bool has_gamma_table:1; bool has_gamma_i734_bug:1; + + bool has_fifo_stallmode_bug:1; }; #define DISPC_MAX_NR_FIFOS 5 @@ -1489,6 +1491,18 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, } } +static void dispc_ovl_set_manual_fifo_threshold(enum omap_plane_id plane) +{ + u32 fifo_low, fifo_high; + bool use_fifo_merge = false; + bool use_manual_update = true; + + dispc_ovl_compute_fifo_thresholds(plane, &fifo_low, &fifo_high, + use_fifo_merge, use_manual_update); + + dispc_ovl_set_fifo_threshold(plane, fifo_low, fifo_high); +} + static void dispc_ovl_set_mflag(enum omap_plane_id plane, bool enable) { int bit; @@ -2651,8 +2665,21 @@ static int dispc_ovl_setup(enum omap_plane_id plane, oi->out_width, oi->out_height, oi->fourcc, oi->rotation, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, oi->rotation_type, replication, vm, mem_to_mem); + if (r) + return r; - return r; + /* + * OMAP3 chips have non-working FIFO thresholds for manually updated + * displays. The issue is not fully understood, but this workaround + * fixes the issue. OMAP4 is known to work with default thresholds. + */ + if (mgr_fld_read(channel, DISPC_MGR_FLD_STALLMODE) && + dispc.feat->has_fifo_stallmode_bug) { + DSSDBG("Enable OMAP3 FIFO stallmode bug workaround!\n"); + dispc_ovl_set_manual_fifo_threshold(plane); + } + + return 0; } int dispc_wb_setup(const struct omap_dss_writeback_info *wi, @@ -4067,6 +4094,7 @@ static const struct dispc_features omap24xx_dispc_feats = { .no_framedone_tv = true, .set_max_preload = false, .last_pixel_inc_missing = true, + .has_fifo_stallmode_bug = true, }; static const struct dispc_features omap34xx_rev1_0_dispc_feats = { @@ -4101,6 +4129,7 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats = { .no_framedone_tv = true, .set_max_preload = false, .last_pixel_inc_missing = true, + .has_fifo_stallmode_bug = true, }; static const struct dispc_features omap34xx_rev3_0_dispc_feats = { @@ -4135,6 +4164,7 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats = { .no_framedone_tv = true, .set_max_preload = false, .last_pixel_inc_missing = true, + .has_fifo_stallmode_bug = true, }; static const struct dispc_features omap36xx_dispc_feats = { @@ -4169,6 +4199,7 @@ static const struct dispc_features omap36xx_dispc_feats = { .no_framedone_tv = true, .set_max_preload = false, .last_pixel_inc_missing = true, + .has_fifo_stallmode_bug = true, }; static const struct dispc_features am43xx_dispc_feats = { @@ -4203,6 +4234,7 @@ static const struct dispc_features am43xx_dispc_feats = { .no_framedone_tv = true, .set_max_preload = false, .last_pixel_inc_missing = true, + .has_fifo_stallmode_bug = false, }; static const struct dispc_features omap44xx_dispc_feats = { @@ -4242,6 +4274,7 @@ static const struct dispc_features omap44xx_dispc_feats = { .reverse_ilace_field_order = true, .has_gamma_table = true, .has_gamma_i734_bug = true, + .has_fifo_stallmode_bug = false, }; static const struct dispc_features omap54xx_dispc_feats = { @@ -4282,6 +4315,7 @@ static const struct dispc_features omap54xx_dispc_feats = { .reverse_ilace_field_order = true, .has_gamma_table = true, .has_gamma_i734_bug = true, + .has_fifo_stallmode_bug = false, }; static irqreturn_t dispc_irq_handler(int irq, void *arg) diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index f8f83e826a56..72ebd82409d3 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -565,6 +565,8 @@ struct omap_dss_driver { struct videomode *vm); void (*get_size)(struct omap_dss_device *dssdev, unsigned int *width, unsigned int *height); + void (*get_orientation)(struct omap_dss_device *dssdev, + int *orientation); int (*set_wss)(struct omap_dss_device *dssdev, u32 wss); u32 (*get_wss)(struct omap_dss_device *dssdev); diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index a0d7b1d905e8..2f296d29b74b 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -57,6 +57,14 @@ bool omap_connector_get_hdmi_mode(struct drm_connector *connector) return omap_connector->hdmi_mode; } +bool omap_connector_get_manually_updated(struct drm_connector *connector) +{ + struct omap_connector *omap_connector = to_omap_connector(connector); + + return !!(omap_connector->dssdev->caps & + OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE); +} + static enum drm_connector_status omap_connector_detect( struct drm_connector *connector, bool force) { @@ -241,6 +249,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, struct drm_connector *connector = NULL; struct omap_connector *omap_connector; bool hpd_supported = false; + int ret; DBG("%s", dssdev->name); @@ -259,7 +268,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, drm_connector_helper_add(connector, &omap_connector_helper_funcs); if (dssdev->driver->register_hpd_cb) { - int ret = dssdev->driver->register_hpd_cb(dssdev, + ret = dssdev->driver->register_hpd_cb(dssdev, omap_connector_hpd_cb, omap_connector); if (!ret) @@ -280,6 +289,13 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, connector->interlace_allowed = 1; connector->doublescan_allowed = 0; + if (dssdev->driver->get_orientation) + dssdev->driver->get_orientation(dssdev, &connector->display_info.panel_orientation); + + ret = drm_connector_init_panel_orientation_property(connector, 0, 0); + if (ret) + DBG("%s: Failed to init orientation property (%d)", dssdev->name, ret); + return connector; fail: diff --git a/drivers/gpu/drm/omapdrm/omap_connector.h b/drivers/gpu/drm/omapdrm/omap_connector.h index 98bbc779b302..652136d167f5 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.h +++ b/drivers/gpu/drm/omapdrm/omap_connector.h @@ -33,5 +33,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, struct drm_encoder *omap_connector_attached_encoder( struct drm_connector *connector); bool omap_connector_get_hdmi_mode(struct drm_connector *connector); +bool omap_connector_get_manually_updated(struct drm_connector *connector); #endif /* __OMAPDRM_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 1b8154e58d18..c2defb514b9f 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -51,6 +51,10 @@ struct omap_crtc { bool pending; wait_queue_head_t pending_wait; struct drm_pending_vblank_event *event; + struct delayed_work update_work; + + void (*framedone_handler)(void *); + void *framedone_handler_data; }; /* ----------------------------------------------------------------------------- @@ -139,6 +143,28 @@ static void omap_crtc_dss_disconnect(enum omap_channel channel, static void omap_crtc_dss_start_update(enum omap_channel channel) { + struct omap_crtc *omap_crtc = omap_crtcs[channel]; + struct omap_drm_private *priv = omap_crtc->base.dev->dev_private; + + priv->dispc_ops->mgr_enable(channel, true); +} + +static bool omap_crtc_is_manually_updated(struct drm_crtc *crtc) +{ + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + bool result = false; + + drm_connector_list_iter_begin(crtc->dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (connector->state->crtc != crtc) + continue; + result = omap_connector_get_manually_updated(connector); + break; + } + drm_connector_list_iter_end(&conn_iter); + + return result; } /* Called only from the encoder enable/disable and suspend/resume handlers. */ @@ -150,12 +176,17 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) enum omap_channel channel = omap_crtc->channel; struct omap_irq_wait *wait; u32 framedone_irq, vsync_irq; + bool is_manual = omap_crtc_is_manually_updated(crtc); + enum omap_display_type type = omap_crtc_output[channel]->output_type; int ret; if (WARN_ON(omap_crtc->enabled == enable)) return; - if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) { + if (is_manual) + omap_irq_enable_framedone(crtc, enable); + + if (is_manual || type == OMAP_DISPLAY_TYPE_HDMI) { priv->dispc_ops->mgr_enable(channel, enable); omap_crtc->enabled = enable; return; @@ -206,7 +237,6 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) } } - static int omap_crtc_dss_enable(enum omap_channel channel) { struct omap_crtc *omap_crtc = omap_crtcs[channel]; @@ -247,6 +277,17 @@ static int omap_crtc_dss_register_framedone( enum omap_channel channel, void (*handler)(void *), void *data) { + struct omap_crtc *omap_crtc = omap_crtcs[channel]; + struct drm_device *dev = omap_crtc->base.dev; + + if (omap_crtc->framedone_handler) + return -EBUSY; + + dev_dbg(dev->dev, "register framedone %s", omap_crtc->name); + + omap_crtc->framedone_handler = handler; + omap_crtc->framedone_handler_data = data; + return 0; } @@ -254,6 +295,16 @@ static void omap_crtc_dss_unregister_framedone( enum omap_channel channel, void (*handler)(void *), void *data) { + struct omap_crtc *omap_crtc = omap_crtcs[channel]; + struct drm_device *dev = omap_crtc->base.dev; + + dev_dbg(dev->dev, "unregister framedone %s", omap_crtc->name); + + WARN_ON(omap_crtc->framedone_handler != handler); + WARN_ON(omap_crtc->framedone_handler_data != data); + + omap_crtc->framedone_handler = NULL; + omap_crtc->framedone_handler_data = NULL; } static const struct dss_mgr_ops mgr_ops = { @@ -321,6 +372,77 @@ void omap_crtc_vblank_irq(struct drm_crtc *crtc) DBG("%s: apply done", omap_crtc->name); } +void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + + if (!omap_crtc->framedone_handler) { + dev_warn(omap_crtc->base.dev->dev, "no framedone handler?"); + return; + } + + omap_crtc->framedone_handler(omap_crtc->framedone_handler_data); + + spin_lock(&crtc->dev->event_lock); + /* Send the vblank event if one has been requested. */ + if (omap_crtc->event) { + drm_crtc_send_vblank_event(crtc, omap_crtc->event); + omap_crtc->event = NULL; + } + omap_crtc->pending = false; + spin_unlock(&crtc->dev->event_lock); + + /* Wake up omap_atomic_complete. */ + wake_up(&omap_crtc->pending_wait); +} + +void omap_crtc_flush(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + + if (!omap_crtc_is_manually_updated(crtc)) + return; + + if (!delayed_work_pending(&omap_crtc->update_work)) + schedule_delayed_work(&omap_crtc->update_work, 0); +} + +static void omap_crtc_manual_display_update(struct work_struct *data) +{ + struct omap_crtc *omap_crtc = + container_of(data, struct omap_crtc, update_work.work); + struct omap_dss_device *dssdev = omap_crtc_output[omap_crtc->channel]; + struct drm_device *dev = omap_crtc->base.dev; + struct omap_dss_driver *dssdrv; + int ret, width, height; + + if (!dssdev || !dssdev->dst) { + dev_err_once(dev->dev, "missing dssdev!"); + return; + } + + dssdev = dssdev->dst; + dssdrv = dssdev->driver; + + if (!dssdrv || !dssdrv->update) { + dev_err_once(dev->dev, "incorrect dssdrv!"); + return; + } + + if (dssdrv->sync) + dssdrv->sync(dssdev); + + width = dssdev->panel.vm.hactive; + height = dssdev->panel.vm.vactive; + ret = dssdrv->update(dssdev, 0, 0, width, height); + if (ret < 0) { + spin_lock_irq(&dev->event_lock); + omap_crtc->pending = false; + spin_unlock_irq(&dev->event_lock); + wake_up(&omap_crtc->pending_wait); + } +} + static void omap_crtc_write_crtc_properties(struct drm_crtc *crtc) { struct omap_drm_private *priv = crtc->dev->dev_private; @@ -373,6 +495,10 @@ static void omap_crtc_atomic_enable(struct drm_crtc *crtc, DBG("%s", omap_crtc->name); + /* manual updated display will not trigger vsync irq */ + if (omap_crtc_is_manually_updated(crtc)) + return; + spin_lock_irq(&crtc->dev->event_lock); drm_crtc_vblank_on(crtc); ret = drm_crtc_vblank_get(crtc); @@ -386,6 +512,7 @@ static void omap_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct drm_device *dev = crtc->dev; DBG("%s", omap_crtc->name); @@ -396,6 +523,11 @@ static void omap_crtc_atomic_disable(struct drm_crtc *crtc, } spin_unlock_irq(&crtc->dev->event_lock); + cancel_delayed_work(&omap_crtc->update_work); + + if (!omap_crtc_wait_pending(crtc)) + dev_warn(dev->dev, "manual display update did not finish!"); + drm_crtc_vblank_off(crtc); } @@ -545,13 +677,20 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, DBG("%s: GO", omap_crtc->name); - ret = drm_crtc_vblank_get(crtc); - WARN_ON(ret != 0); + if (!omap_crtc_is_manually_updated(crtc)) { + ret = drm_crtc_vblank_get(crtc); + WARN_ON(ret != 0); - spin_lock_irq(&crtc->dev->event_lock); - priv->dispc_ops->mgr_go(omap_crtc->channel); - omap_crtc_arm_event(crtc); - spin_unlock_irq(&crtc->dev->event_lock); + spin_lock_irq(&crtc->dev->event_lock); + priv->dispc_ops->mgr_go(omap_crtc->channel); + omap_crtc_arm_event(crtc); + spin_unlock_irq(&crtc->dev->event_lock); + } else { + spin_lock_irq(&crtc->dev->event_lock); + omap_crtc_flush(crtc); + omap_crtc_arm_event(crtc); + spin_unlock_irq(&crtc->dev->event_lock); + } } static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, @@ -713,6 +852,9 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, omap_crtc->channel = channel; omap_crtc->name = channel_names[channel]; + INIT_DELAYED_WORK(&omap_crtc->update_work, + omap_crtc_manual_display_update); + ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, &omap_crtc_funcs, NULL); if (ret < 0) { diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.h b/drivers/gpu/drm/omapdrm/omap_crtc.h index ad7b007c6174..b61c94b34f04 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.h +++ b/drivers/gpu/drm/omapdrm/omap_crtc.h @@ -39,5 +39,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, int omap_crtc_wait_pending(struct drm_crtc *crtc); void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus); void omap_crtc_vblank_irq(struct drm_crtc *crtc); +void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus); +void omap_crtc_flush(struct drm_crtc *crtc); #endif /* __OMAPDRM_CRTC_H__ */ diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index b2539a90e1a4..57b1767bef09 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -95,8 +95,28 @@ static void omap_framebuffer_destroy(struct drm_framebuffer *fb) kfree(omap_fb); } +static int omap_framebuffer_dirty(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned flags, unsigned color, + struct drm_clip_rect *clips, + unsigned num_clips) +{ + struct drm_connector *connector = NULL; + + drm_modeset_lock_all(fb->dev); + + while ((connector = omap_framebuffer_get_next_connector(fb, connector))) + if (connector->encoder && connector->encoder->crtc) + omap_crtc_flush(connector->encoder->crtc); + + drm_modeset_unlock_all(fb->dev); + + return 0; +} + static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { .create_handle = omap_framebuffer_create_handle, + .dirty = omap_framebuffer_dirty, .destroy = omap_framebuffer_destroy, }; diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index 53ba424823b2..354df3583229 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c @@ -85,6 +85,27 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, return ret == 0 ? -1 : 0; } +int omap_irq_enable_framedone(struct drm_crtc *crtc, bool enable) +{ + struct drm_device *dev = crtc->dev; + struct omap_drm_private *priv = dev->dev_private; + unsigned long flags; + enum omap_channel channel = omap_crtc_channel(crtc); + int framedone_irq = priv->dispc_ops->mgr_get_framedone_irq(channel); + + DBG("dev=%p, crtc=%u, enable=%d", dev, channel, enable); + + spin_lock_irqsave(&priv->wait_lock, flags); + if (enable) + priv->irq_mask |= framedone_irq; + else + priv->irq_mask &= ~framedone_irq; + omap_irq_update(dev); + spin_unlock_irqrestore(&priv->wait_lock, flags); + + return 0; +} + /** * enable_vblank - enable vblank interrupt events * @dev: DRM device @@ -215,6 +236,9 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) if (irqstatus & priv->dispc_ops->mgr_get_sync_lost_irq(channel)) omap_crtc_error_irq(crtc, irqstatus); + + if (irqstatus & priv->dispc_ops->mgr_get_framedone_irq(channel)) + omap_crtc_framedone_irq(crtc, irqstatus); } omap_irq_ocp_error_handler(dev, irqstatus); diff --git a/drivers/gpu/drm/omapdrm/omap_irq.h b/drivers/gpu/drm/omapdrm/omap_irq.h index 606c09932bc0..69f4ff80a0e4 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.h +++ b/drivers/gpu/drm/omapdrm/omap_irq.h @@ -27,6 +27,7 @@ struct drm_device; struct omap_irq_wait; int omap_irq_enable_vblank(struct drm_crtc *crtc); +int omap_irq_enable_framedone(struct drm_crtc *crtc, bool enable); void omap_irq_disable_vblank(struct drm_crtc *crtc); void omap_drm_irq_uninstall(struct drm_device *dev); int omap_drm_irq_install(struct drm_device *dev); -- 2.14.1