return;
                        drm_fb_helper_dirty_blit_real(helper, &clip_copy);
                }
-               helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
+               if (helper->fb->funcs->dirty)
+                       helper->fb->funcs->dirty(helper->fb, NULL, 0, 0,
+                                                &clip_copy, 1);
 
                if (helper->buffer)
                        drm_client_buffer_vunmap(helper->buffer);
 }
 EXPORT_SYMBOL(drm_fb_helper_unlink_fbi);
 
+static bool drm_fbdev_use_shadow_fb(struct drm_fb_helper *fb_helper)
+{
+       struct drm_device *dev = fb_helper->dev;
+       struct drm_framebuffer *fb = fb_helper->fb;
+
+       return dev->mode_config.prefer_shadow_fbdev ||
+              dev->mode_config.prefer_shadow ||
+              fb->funcs->dirty;
+}
+
 static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
                                u32 width, u32 height)
 {
        struct drm_clip_rect *clip = &helper->dirty_clip;
        unsigned long flags;
 
-       if (!helper->fb->funcs->dirty)
+       if (!drm_fbdev_use_shadow_fb(helper))
                return;
 
        spin_lock_irqsave(&helper->dirty_lock, flags);
 
        drm_fb_helper_fill_info(fbi, fb_helper, sizes);
 
-       if (fb->funcs->dirty) {
+       if (drm_fbdev_use_shadow_fb(fb_helper)) {
                struct fb_ops *fbops;
                void *shadow;
 
 
        /* dumb ioctl parameters */
        uint32_t preferred_depth, prefer_shadow;
 
+       /**
+        * @prefer_shadow_fbdev:
+        *
+        * Hint to framebuffer emulation to prefer shadow-fb rendering.
+        */
+       bool prefer_shadow_fbdev;
+
        /**
         * @quirk_addfb_prefer_xbgr_30bpp:
         *