diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm')
-rw-r--r-- | drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_crtc.c | 180 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_crtc.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_fb.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_irq.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_irq.h | 1 |
9 files changed, 232 insertions, 40 deletions
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index 8edef8ef23b0..564e3e1a1891 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -407,8 +407,7 @@ static const struct backlight_ops dsicm_bl_ops = { static ssize_t dsicm_num_errors_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); struct omap_dss_device *src = ddata->src; u8 errors = 0; int r; @@ -439,8 +438,7 @@ static ssize_t dsicm_num_errors_show(struct device *dev, static ssize_t dsicm_hw_revision_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); struct omap_dss_device *src = ddata->src; u8 id1, id2, id3; int r; @@ -471,8 +469,7 @@ static ssize_t dsicm_store_ulps(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); struct omap_dss_device *src = ddata->src; unsigned long t; int r; @@ -506,8 +503,7 @@ static ssize_t dsicm_show_ulps(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); unsigned int t; mutex_lock(&ddata->lock); @@ -521,8 +517,7 @@ static ssize_t dsicm_store_ulps_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); struct omap_dss_device *src = ddata->src; unsigned long t; int r; @@ -553,8 +548,7 @@ static ssize_t dsicm_show_ulps_timeout(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); unsigned int t; mutex_lock(&ddata->lock); diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c index 07b8a1d4d643..a140de79c50e 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c +++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c @@ -187,6 +187,7 @@ static const struct of_device_id omapdss_of_fixups_whitelist[] __initconst = { { .compatible = "toppoly,td028ttec1" }, { .compatible = "tpo,td028ttec1" }, { .compatible = "tpo,td043mtea1" }, + {}, }; static int __init omapdss_boot_init(void) diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 8712af79a49c..f9ac9afc5641 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -21,6 +21,7 @@ struct omap_crtc_state { /* Shadow values for legacy userspace support. */ unsigned int rotation; unsigned int zpos; + bool manually_updated; }; #define to_omap_crtc(x) container_of(x, struct omap_crtc, base) @@ -40,6 +41,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; }; /* ----------------------------------------------------------------------------- @@ -91,21 +96,18 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc) /* * Manager-ops, callbacks from output when they need to configure * the upstream part of the video pipe. - * - * Most of these we can ignore until we add support for command-mode - * panels.. for video-mode the crtc-helpers already do an adequate - * job of sequencing the setup of the video pipe in the proper order */ -/* we can probably ignore these until we support command-mode panels: */ static void omap_crtc_dss_start_update(struct omap_drm_private *priv, enum omap_channel channel) { + priv->dispc_ops->mgr_enable(priv->dispc, channel, true); } /* Called only from the encoder enable/disable and suspend/resume handlers. */ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) { + struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state); struct drm_device *dev = crtc->dev; struct omap_drm_private *priv = dev->dev_private; struct omap_crtc *omap_crtc = to_omap_crtc(crtc); @@ -117,6 +119,12 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) if (WARN_ON(omap_crtc->enabled == enable)) return; + if (omap_state->manually_updated) { + omap_irq_enable_framedone(crtc, enable); + omap_crtc->enabled = enable; + return; + } + if (omap_crtc->pipe->output->type == OMAP_DISPLAY_TYPE_HDMI) { priv->dispc_ops->mgr_enable(priv->dispc, channel, enable); omap_crtc->enabled = enable; @@ -219,6 +227,18 @@ static int omap_crtc_dss_register_framedone( struct omap_drm_private *priv, enum omap_channel channel, void (*handler)(void *), void *data) { + struct drm_crtc *crtc = priv->channels[channel]->crtc; + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + 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; } @@ -226,6 +246,17 @@ static void omap_crtc_dss_unregister_framedone( struct omap_drm_private *priv, enum omap_channel channel, void (*handler)(void *), void *data) { + struct drm_crtc *crtc = priv->channels[channel]->crtc; + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + 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 = { @@ -291,6 +322,73 @@ 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) + 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); + struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state); + + if (!omap_state->manually_updated) + 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 drm_display_mode *mode = &omap_crtc->pipe->crtc->mode; + struct omap_dss_device *dssdev = omap_crtc->pipe->output->next; + struct drm_device *dev = omap_crtc->base.dev; + const struct omap_dss_driver *dssdrv; + int ret; + + if (!dssdev) { + dev_err_once(dev->dev, "missing display dssdev!"); + return; + } + + dssdrv = dssdev->driver; + if (!dssdrv || !dssdrv->update) { + dev_err_once(dev->dev, "missing or incorrect dssdrv!"); + return; + } + + if (dssdrv->sync) + dssdrv->sync(dssdev); + + ret = dssdrv->update(dssdev, 0, 0, mode->hdisplay, mode->vdisplay); + 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; @@ -340,12 +438,17 @@ static void omap_crtc_atomic_enable(struct drm_crtc *crtc, { struct omap_drm_private *priv = crtc->dev->dev_private; struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state); int ret; DBG("%s", omap_crtc->name); priv->dispc_ops->runtime_get(priv->dispc); + /* manual updated display will not trigger vsync irq */ + if (omap_state->manually_updated) + return; + spin_lock_irq(&crtc->dev->event_lock); drm_crtc_vblank_on(crtc); ret = drm_crtc_vblank_get(crtc); @@ -360,6 +463,7 @@ static void omap_crtc_atomic_disable(struct drm_crtc *crtc, { struct omap_drm_private *priv = crtc->dev->dev_private; struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct drm_device *dev = crtc->dev; DBG("%s", omap_crtc->name); @@ -370,6 +474,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); priv->dispc_ops->runtime_put(priv->dispc); @@ -384,10 +493,20 @@ static enum drm_mode_status omap_crtc_mode_valid(struct drm_crtc *crtc, int r; drm_display_mode_to_videomode(mode, &vm); - r = priv->dispc_ops->mgr_check_timings(priv->dispc, omap_crtc->channel, - &vm); - if (r) - return r; + + /* + * DSI might not call this, since the supplied mode is not a + * valid DISPC mode. DSI will calculate and configure the + * proper DISPC mode later. + */ + if (omap_crtc->pipe->output->next == NULL || + omap_crtc->pipe->output->next->type != OMAP_DISPLAY_TYPE_DSI) { + r = priv->dispc_ops->mgr_check_timings(priv->dispc, + omap_crtc->channel, + &vm); + if (r) + return r; + } /* Check for bandwidth limit */ if (priv->max_bandwidth) { @@ -430,6 +549,22 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc) drm_display_mode_to_videomode(mode, &omap_crtc->vm); } +static bool omap_crtc_is_manually_updated(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct omap_dss_device *display = omap_crtc->pipe->output->next; + + if (!display) + return false; + + if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { + DBG("detected manually updated display!"); + return true; + } + + return false; +} + static int omap_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -451,6 +586,9 @@ static int omap_crtc_atomic_check(struct drm_crtc *crtc, /* Mirror new values for zpos and rotation in omap_crtc_state */ omap_crtc_state->zpos = pri_state->zpos; omap_crtc_state->rotation = pri_state->rotation; + + /* Check if this CRTC is for a manually updated display */ + omap_crtc_state->manually_updated = omap_crtc_is_manually_updated(crtc); } return 0; @@ -466,6 +604,7 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, { struct omap_drm_private *priv = crtc->dev->dev_private; struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct omap_crtc_state *omap_crtc_state = to_omap_crtc_state(crtc->state); int ret; if (crtc->state->color_mgmt_changed) { @@ -490,6 +629,15 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, DBG("%s: GO", omap_crtc->name); + if (omap_crtc_state->manually_updated) { + /* send new image for page flips and modeset changes */ + spin_lock_irq(&crtc->dev->event_lock); + omap_crtc_flush(crtc); + omap_crtc_arm_event(crtc); + spin_unlock_irq(&crtc->dev->event_lock); + return; + } + ret = drm_crtc_vblank_get(crtc); WARN_ON(ret != 0); @@ -575,6 +723,7 @@ omap_crtc_duplicate_state(struct drm_crtc *crtc) state->zpos = current_state->zpos; state->rotation = current_state->rotation; + state->manually_updated = current_state->manually_updated; return &state->base; } @@ -651,6 +800,19 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, omap_crtc->channel = channel; omap_crtc->name = channel_names[channel]; + /* + * We want to refresh manually updated displays from dirty callback, + * which is called quite often (e.g. for each drawn line). This will + * be used to do the display update asynchronously to avoid blocking + * the rendering process and merges multiple dirty calls into one + * update if they arrive very fast. We also call this function for + * atomic display updates (e.g. for page flips), which means we do + * not need extra locking. Atomic updates should be synchronous, but + * need to wait for the framedone interrupt anyways. + */ + 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 3963f2db92a9..2fd57751ae2b 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.h +++ b/drivers/gpu/drm/omapdrm/omap_crtc.h @@ -30,5 +30,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, u32 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_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index d1b8075e792f..288c59dae56a 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -428,20 +428,6 @@ static int ioctl_get_param(struct drm_device *dev, void *data, return 0; } -static int ioctl_set_param(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_omap_param *args = data; - - switch (args->param) { - default: - DBG("unknown parameter %lld", args->param); - return -EINVAL; - } - - return 0; -} - #define OMAP_BO_USER_MASK 0x00ffffff /* flags settable by userspace */ static int ioctl_gem_new(struct drm_device *dev, void *data, @@ -481,7 +467,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data, static const struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = { DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param, DRM_AUTH | DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param, + DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, drm_invalid_op, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, DRM_AUTH | DRM_RENDER_ALLOW), diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 94d00b47db6b..025bd57081d5 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -26,8 +26,8 @@ #include "omap_irq.h" #include "omap_plane.h" -#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) -#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */ +#define DBG(fmt, ...) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__) +#define VERB(fmt, ...) if (0) DRM_DEBUG_DRIVER(fmt, ##__VA_ARGS__) /* verbose debug */ #define MODULE_NAME "omapdrm" diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 1c9048e35d90..7e89e5cb4068 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -55,8 +55,27 @@ struct omap_framebuffer { struct mutex lock; }; +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_crtc *crtc; + + drm_modeset_lock_all(fb->dev); + + drm_for_each_crtc(crtc, fb->dev) + omap_crtc_flush(crtc); + + drm_modeset_unlock_all(fb->dev); + + return 0; +} + static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { .create_handle = drm_gem_fb_create_handle, + .dirty = omap_framebuffer_dirty, .destroy = drm_gem_fb_destroy, }; @@ -287,7 +306,9 @@ void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) { - unsigned int num_planes = drm_format_num_planes(mode_cmd->pixel_format); + const struct drm_format_info *info = drm_get_format_info(dev, + mode_cmd); + unsigned int num_planes = info->num_planes; struct drm_gem_object *bos[4]; struct drm_framebuffer *fb; int i; @@ -326,7 +347,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, dev, mode_cmd, mode_cmd->width, mode_cmd->height, (char *)&mode_cmd->pixel_format); - format = drm_format_info(mode_cmd->pixel_format); + format = drm_get_format_info(dev, mode_cmd); for (i = 0; i < ARRAY_SIZE(formats); i++) { if (formats[i] == mode_cmd->pixel_format) diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index 0e6b410ee741..726a013e7988 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c @@ -74,6 +74,28 @@ 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(priv->dispc, 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 @@ -206,6 +228,9 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) if (irqstatus & priv->dispc_ops->mgr_get_sync_lost_irq(priv->dispc, channel)) omap_crtc_error_irq(crtc, irqstatus); + + if (irqstatus & priv->dispc_ops->mgr_get_framedone_irq(priv->dispc, 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 f7ecd728f7b3..35e9586c4a51 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.h +++ b/drivers/gpu/drm/omapdrm/omap_irq.h @@ -16,6 +16,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); |