struct drm_framebuffer *fb;
        struct drm_gem_object *bo;
        bool ywrap_enabled;
+
+       /* for deferred dmm roll when getting called in atomic ctx */
+       struct work_struct work;
 };
 
 static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h);
                                image->width, image->height);
 }
 
+static void pan_worker(struct work_struct *work)
+{
+       struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work);
+       struct fb_info *fbi = fbdev->base.fbdev;
+       int npages;
+
+       /* DMM roll shifts in 4K pages: */
+       npages = fbi->fix.line_length >> PAGE_SHIFT;
+       omap_gem_roll(fbdev->bo, fbi->var.yoffset * npages);
+}
+
 static int omap_fbdev_pan_display(struct fb_var_screeninfo *var,
                struct fb_info *fbi)
 {
        struct drm_fb_helper *helper = get_fb(fbi);
        struct omap_fbdev *fbdev = to_omap_fbdev(helper);
-       int npages;
 
        if (!helper)
                goto fallback;
        if (!fbdev->ywrap_enabled)
                goto fallback;
 
-       /* DMM roll shifts in 4K pages: */
-       npages = fbi->fix.line_length >> PAGE_SHIFT;
-       omap_gem_roll(fbdev->bo, var->yoffset * npages);
+       if (drm_can_sleep()) {
+               pan_worker(&fbdev->work);
+       } else {
+               struct omap_drm_private *priv = helper->dev->dev_private;
+               queue_work(priv->wq, &fbdev->work);
+       }
 
        return 0;
 
                goto fail;
        }
 
+       INIT_WORK(&fbdev->work, pan_worker);
+
        helper = &fbdev->base;
 
        helper->funcs = &omap_fb_helper_funcs;
 
 
 /* Set scrolling position.  This allows us to implement fast scrolling
  * for console.
+ *
+ * Call only from non-atomic contexts.
  */
 int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll)
 {
 
        omap_obj->roll = roll;
 
-       if (in_atomic() || mutex_is_locked(&obj->dev->struct_mutex)) {
-               /* this can get called from fbcon in atomic context.. so
-                * just ignore it and wait for next time called from
-                * interruptible context to update the PAT.. the result
-                * may be that user sees wrap-around instead of scrolling
-                * momentarily on the screen.  If we wanted to be fancier
-                * we could perhaps schedule some workqueue work at this
-                * point.
-                */
-               return 0;
-       }
-
        mutex_lock(&obj->dev->struct_mutex);
 
        /* if we aren't mapped yet, we don't need to do anything */