drm/i915: restore only the mode of this driver on lastclose (v2)
[linux-flexiantxendom0-natty.git] / drivers / gpu / drm / drm_fb_helper.c
index 5db4f47..efe756e 100644 (file)
@@ -42,8 +42,6 @@ MODULE_LICENSE("GPL and additional rights");
 
 static LIST_HEAD(kernel_fb_helper_list);
 
-static struct slow_work_ops output_status_change_ops;
-
 /* simple single crtc case helper function */
 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
 {
@@ -96,10 +94,11 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_conn
        int i;
        enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
        struct drm_fb_helper_cmdline_mode *cmdline_mode;
-       struct drm_connector *connector = fb_helper_conn->connector;
+       struct drm_connector *connector;
 
        if (!fb_helper_conn)
                return false;
+       connector = fb_helper_conn->connector;
 
        cmdline_mode = &fb_helper_conn->cmdline_mode;
        if (!mode_option)
@@ -148,7 +147,7 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_conn
                                cvt = 1;
                        break;
                case 'R':
-                       if (!cvt)
+                       if (cvt)
                                rb = 1;
                        break;
                case 'm':
@@ -243,9 +242,122 @@ static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
        return 0;
 }
 
+static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
+{
+       uint16_t *r_base, *g_base, *b_base;
+       int i;
+
+       r_base = crtc->gamma_store;
+       g_base = r_base + crtc->gamma_size;
+       b_base = g_base + crtc->gamma_size;
+
+       for (i = 0; i < crtc->gamma_size; i++)
+               helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
+}
+
+static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
+{
+       uint16_t *r_base, *g_base, *b_base;
+
+       r_base = crtc->gamma_store;
+       g_base = r_base + crtc->gamma_size;
+       b_base = g_base + crtc->gamma_size;
+
+       crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
+}
+
+int drm_fb_helper_debug_enter(struct fb_info *info)
+{
+       struct drm_fb_helper *helper = info->par;
+       struct drm_crtc_helper_funcs *funcs;
+       int i;
+
+       if (list_empty(&kernel_fb_helper_list))
+               return false;
+
+       list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
+               for (i = 0; i < helper->crtc_count; i++) {
+                       struct drm_mode_set *mode_set =
+                               &helper->crtc_info[i].mode_set;
+
+                       if (!mode_set->crtc->enabled)
+                               continue;
+
+                       funcs = mode_set->crtc->helper_private;
+                       drm_fb_helper_save_lut_atomic(mode_set->crtc, helper);
+                       funcs->mode_set_base_atomic(mode_set->crtc,
+                                                   mode_set->fb,
+                                                   mode_set->x,
+                                                   mode_set->y,
+                                                   ENTER_ATOMIC_MODE_SET);
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_debug_enter);
+
+/* Find the real fb for a given fb helper CRTC */
+static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_crtc *c;
+
+       list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
+               if (crtc->base.id == c->base.id)
+                       return c->fb;
+       }
+
+       return NULL;
+}
+
+int drm_fb_helper_debug_leave(struct fb_info *info)
+{
+       struct drm_fb_helper *helper = info->par;
+       struct drm_crtc *crtc;
+       struct drm_crtc_helper_funcs *funcs;
+       struct drm_framebuffer *fb;
+       int i;
+
+       for (i = 0; i < helper->crtc_count; i++) {
+               struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
+               crtc = mode_set->crtc;
+               funcs = crtc->helper_private;
+               fb = drm_mode_config_fb(crtc);
+
+               if (!crtc->enabled)
+                       continue;
+
+               if (!fb) {
+                       DRM_ERROR("no fb to restore??\n");
+                       continue;
+               }
+
+               drm_fb_helper_restore_lut_atomic(mode_set->crtc);
+               funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
+                                           crtc->y, LEAVE_ATOMIC_MODE_SET);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_debug_leave);
+
+bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
+{
+       bool error = false;
+       int i, ret;
+       for (i = 0; i < fb_helper->crtc_count; i++) {
+               struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+               ret = drm_crtc_helper_set_config(mode_set);
+               if (ret)
+                       error = true;
+       }
+       return error;
+}
+EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode);
+
 bool drm_fb_helper_force_kernel_mode(void)
 {
-       int i = 0;
        bool ret, error = false;
        struct drm_fb_helper *helper;
 
@@ -253,12 +365,12 @@ bool drm_fb_helper_force_kernel_mode(void)
                return false;
 
        list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
-               for (i = 0; i < helper->crtc_count; i++) {
-                       struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
-                       ret = drm_crtc_helper_set_config(mode_set);
-                       if (ret)
-                               error = true;
-               }
+               if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+                       continue;
+
+               ret = drm_fb_helper_restore_fbdev_mode(helper);
+               if (ret)
+                       error = true;
        }
        return error;
 }
@@ -266,7 +378,7 @@ bool drm_fb_helper_force_kernel_mode(void)
 int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
                        void *panic_str)
 {
-       DRM_ERROR("panic occurred, switching back to text console\n");
+       printk(KERN_ERR "panic occurred, switching back to text console\n");
        return drm_fb_helper_force_kernel_mode();
        return 0;
 }
@@ -297,7 +409,7 @@ static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
 }
 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
 
-static void drm_fb_helper_sysrq(int dummy1, struct tty_struct *dummy3)
+static void drm_fb_helper_sysrq(int dummy1)
 {
        schedule_work(&drm_fb_helper_restore_work);
 }
@@ -317,8 +429,9 @@ static void drm_fb_helper_on(struct fb_info *info)
        struct drm_device *dev = fb_helper->dev;
        struct drm_crtc *crtc;
        struct drm_crtc_helper_funcs *crtc_funcs;
+       struct drm_connector *connector;
        struct drm_encoder *encoder;
-       int i;
+       int i, j;
 
        /*
         * For each CRTC in this fb, turn the crtc on then,
@@ -334,7 +447,14 @@ static void drm_fb_helper_on(struct fb_info *info)
 
                crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
 
-
+               /* Walk the connectors & encoders on this fb turning them on */
+               for (j = 0; j < fb_helper->connector_count; j++) {
+                       connector = fb_helper->connector_info[j]->connector;
+                       connector->dpms = DRM_MODE_DPMS_ON;
+                       drm_connector_property_set_value(connector,
+                                                        dev->mode_config.dpms_property,
+                                                        DRM_MODE_DPMS_ON);
+               }
                /* Found a CRTC on this fb, now find encoders */
                list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                        if (encoder->crtc == crtc) {
@@ -354,8 +474,9 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
        struct drm_device *dev = fb_helper->dev;
        struct drm_crtc *crtc;
        struct drm_crtc_helper_funcs *crtc_funcs;
+       struct drm_connector *connector;
        struct drm_encoder *encoder;
-       int i;
+       int i, j;
 
        /*
         * For each CRTC in this fb, find all associated encoders
@@ -369,6 +490,14 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
                if (!crtc->enabled)
                        continue;
 
+               /* Walk the connectors on this fb and mark them off */
+               for (j = 0; j < fb_helper->connector_count; j++) {
+                       connector = fb_helper->connector_info[j]->connector;
+                       connector->dpms = dpms_mode;
+                       drm_connector_property_set_value(connector,
+                                                        dev->mode_config.dpms_property,
+                                                        dpms_mode);
+               }
                /* Found a CRTC on this fb, now find encoders */
                list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                        if (encoder->crtc == crtc) {
@@ -425,19 +554,13 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
 
 int drm_fb_helper_init(struct drm_device *dev,
                       struct drm_fb_helper *fb_helper,
-                      int crtc_count, int max_conn_count,
-                      bool polled)
+                      int crtc_count, int max_conn_count)
 {
        struct drm_crtc *crtc;
        int ret = 0;
        int i;
 
        fb_helper->dev = dev;
-       fb_helper->poll_enabled = polled;
-
-       slow_work_register_user(THIS_MODULE);
-       delayed_slow_work_init(&fb_helper->output_status_change_slow_work,
-                              &output_status_change_ops);
 
        INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
 
@@ -494,8 +617,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 
        drm_fb_helper_crtc_free(fb_helper);
 
-       delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
-       slow_work_unregister_user(THIS_MODULE);
 }
 EXPORT_SYMBOL(drm_fb_helper_fini);
 
@@ -564,7 +685,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
        struct drm_crtc_helper_funcs *crtc_funcs;
        u16 *red, *green, *blue, *transp;
        struct drm_crtc *crtc;
-       int i, rc = 0;
+       int i, j, rc = 0;
        int start;
 
        for (i = 0; i < fb_helper->crtc_count; i++) {
@@ -577,7 +698,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
                transp = cmap->transp;
                start = cmap->start;
 
-               for (i = 0; i < cmap->len; i++) {
+               for (j = 0; j < cmap->len; j++) {
                        u16 hred, hgreen, hblue, htransp = 0xffff;
 
                        hred = *red++;
@@ -604,7 +725,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
        struct drm_framebuffer *fb = fb_helper->fb;
        int depth;
 
-       if (var->pixclock != 0)
+       if (var->pixclock != 0 || in_dbg_master())
                return -EINVAL;
 
        /* Need to resize the fb object !!! */
@@ -713,7 +834,7 @@ int drm_fb_helper_set_par(struct fb_info *info)
 
        if (fb_helper->delayed_hotplug) {
                fb_helper->delayed_hotplug = false;
-               delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
+               drm_fb_helper_hotplug_event(fb_helper);
        }
        return 0;
 }
@@ -826,7 +947,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
        if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
                /* hmm everyone went away - assume VGA cable just fell out
                   and will come back later. */
-               DRM_ERROR("Cannot find any crtc or sizes - going 1024x768\n");
+               DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n");
                sizes.fb_width = sizes.surface_width = 1024;
                sizes.fb_height = sizes.surface_height = 768;
        }
@@ -877,6 +998,8 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
        info->fix.type = FB_TYPE_PACKED_PIXELS;
        info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
                FB_VISUAL_TRUECOLOR;
+       info->fix.mmio_start = 0;
+       info->fix.mmio_len = 0;
        info->fix.type_aux = 0;
        info->fix.xpanstep = 1; /* doing it in hw */
        info->fix.ypanstep = 1; /* doing it in hw */
@@ -897,6 +1020,7 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
        info->var.xres_virtual = fb->width;
        info->var.yres_virtual = fb->height;
        info->var.bits_per_pixel = fb->bits_per_pixel;
+       info->var.accel_flags = FB_ACCELF_TEXT;
        info->var.xoffset = 0;
        info->var.yoffset = 0;
        info->var.activate = FB_ACTIVATE_NOW;
@@ -1034,11 +1158,18 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
        }
 
 create_mode:
-       mode = drm_cvt_mode(fb_helper_conn->connector->dev, cmdline_mode->xres,
-                           cmdline_mode->yres,
-                           cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
-                           cmdline_mode->rb, cmdline_mode->interlace,
-                           cmdline_mode->margins);
+       if (cmdline_mode->cvt)
+               mode = drm_cvt_mode(fb_helper_conn->connector->dev,
+                                   cmdline_mode->xres, cmdline_mode->yres,
+                                   cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
+                                   cmdline_mode->rb, cmdline_mode->interlace,
+                                   cmdline_mode->margins);
+       else
+               mode = drm_gtf_mode(fb_helper_conn->connector->dev,
+                                   cmdline_mode->xres, cmdline_mode->yres,
+                                   cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
+                                   cmdline_mode->interlace,
+                                   cmdline_mode->margins);
        drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
        list_add(&mode->head, &fb_helper_conn->connector->modes);
        return mode;
@@ -1080,6 +1211,79 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
        }
 }
 
+static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
+                             struct drm_display_mode **modes,
+                             bool *enabled, int width, int height)
+{
+       int count, i, j;
+       bool can_clone = false;
+       struct drm_fb_helper_connector *fb_helper_conn;
+       struct drm_display_mode *dmt_mode, *mode;
+
+       /* only contemplate cloning in the single crtc case */
+       if (fb_helper->crtc_count > 1)
+               return false;
+
+       count = 0;
+       for (i = 0; i < fb_helper->connector_count; i++) {
+               if (enabled[i])
+                       count++;
+       }
+
+       /* only contemplate cloning if more than one connector is enabled */
+       if (count <= 1)
+               return false;
+
+       /* check the command line or if nothing common pick 1024x768 */
+       can_clone = true;
+       for (i = 0; i < fb_helper->connector_count; i++) {
+               if (!enabled[i])
+                       continue;
+               fb_helper_conn = fb_helper->connector_info[i];
+               modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
+               if (!modes[i]) {
+                       can_clone = false;
+                       break;
+               }
+               for (j = 0; j < i; j++) {
+                       if (!enabled[j])
+                               continue;
+                       if (!drm_mode_equal(modes[j], modes[i]))
+                               can_clone = false;
+               }
+       }
+
+       if (can_clone) {
+               DRM_DEBUG_KMS("can clone using command line\n");
+               return true;
+       }
+
+       /* try and find a 1024x768 mode on each connector */
+       can_clone = true;
+       dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60);
+
+       for (i = 0; i < fb_helper->connector_count; i++) {
+
+               if (!enabled[i])
+                       continue;
+
+               fb_helper_conn = fb_helper->connector_info[i];
+               list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
+                       if (drm_mode_equal(mode, dmt_mode))
+                               modes[i] = mode;
+               }
+               if (!modes[i])
+                       can_clone = false;
+       }
+
+       if (can_clone) {
+               DRM_DEBUG_KMS("can clone using 1024x768\n");
+               return true;
+       }
+       DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
+       return false;
+}
+
 static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
                                 struct drm_display_mode **modes,
                                 bool *enabled, int width, int height)
@@ -1173,8 +1377,12 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
                                break;
 
                if (o < n) {
-                       /* ignore cloning for now */
-                       continue;
+                       /* ignore cloning unless only a single crtc */
+                       if (fb_helper->crtc_count > 1)
+                               continue;
+
+                       if (!drm_mode_equal(modes[o], modes[n]))
+                               continue;
                }
 
                crtcs[n] = crtc;
@@ -1224,9 +1432,12 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
 
        drm_enable_connectors(fb_helper, enabled);
 
-       ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
-       if (!ret)
-               DRM_ERROR("Unable to find initial modes\n");
+       ret = drm_target_cloned(fb_helper, modes, enabled, width, height);
+       if (!ret) {
+               ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
+               if (!ret)
+                       DRM_ERROR("Unable to find initial modes\n");
+       }
 
        DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
 
@@ -1292,12 +1503,7 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
         * we shouldn't end up with no modes here.
         */
        if (count == 0) {
-               if (fb_helper->poll_enabled) {
-                       delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work,
-                                                 5*HZ);
-                       printk(KERN_INFO "No connectors reported connected with modes - started polling\n");
-               } else
-                       printk(KERN_INFO "No connectors reported connected with modes\n");
+               printk(KERN_INFO "No connectors reported connected with modes\n");
        }
        drm_setup_crtcs(fb_helper);
 
@@ -1305,26 +1511,27 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
 }
 EXPORT_SYMBOL(drm_fb_helper_initial_config);
 
-/* we got a hotplug irq - need to update fbcon */
-void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper)
-{
-       /* if we don't have the fbdev registered yet do nothing */
-       if (!fb_helper->fbdev)
-               return;
-
-       /* schedule a slow work asap */
-       delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
-}
-EXPORT_SYMBOL(drm_helper_fb_hpd_irq_event);
-
-bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, bool polled)
+bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 {
        int count = 0;
-       int ret;
        u32 max_width, max_height, bpp_sel;
+       bool bound = false, crtcs_bound = false;
+       struct drm_crtc *crtc;
 
        if (!fb_helper->fb)
                return false;
+
+       list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
+               if (crtc->fb)
+                       crtcs_bound = true;
+               if (crtc->fb == fb_helper->fb)
+                       bound = true;
+       }
+
+       if (!bound && crtcs_bound) {
+               fb_helper->delayed_hotplug = true;
+               return false;
+       }
        DRM_DEBUG_KMS("\n");
 
        max_width = fb_helper->fb->width;
@@ -1333,82 +1540,30 @@ bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, bool polled)
 
        count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
                                                    max_height);
-       if (fb_helper->poll_enabled && !polled) {
-               if (count) {
-                       delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
-               } else {
-                       ret = delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 5*HZ);
-               }
-       }
        drm_setup_crtcs(fb_helper);
 
        return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
 }
-EXPORT_SYMBOL(drm_helper_fb_hotplug_event);
+EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
 
-/*
- * delayed work queue execution function
- * - check if fbdev is actually in use on the gpu
- *   - if not set delayed flag and repoll if necessary
- * - check for connector status change
- * - repoll if 0 modes found
- *- call driver output status changed notifier
+/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
+ * but the module doesn't depend on any fb console symbols.  At least
+ * attempt to load fbcon to avoid leaving the system without a usable console.
  */
-static void output_status_change_execute(struct slow_work *work)
+#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
+static int __init drm_fb_helper_modinit(void)
 {
-       struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
-       struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_status_change_slow_work);
-       struct drm_connector *connector;
-       enum drm_connector_status old_status, status;
-       bool repoll, changed = false;
-       int ret;
-       int i;
-       bool bound = false, crtcs_bound = false;
-       struct drm_crtc *crtc;
-
-       repoll = fb_helper->poll_enabled;
-
-       /* first of all check the fbcon framebuffer is actually bound to any crtc */
-       /* take into account that no crtc at all maybe bound */
-       list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
-               if (crtc->fb)
-                       crtcs_bound = true;
-               if (crtc->fb == fb_helper->fb)
-                       bound = true;
-       }
+       const char *name = "fbcon";
+       struct module *fbcon;
 
-       if (bound == false && crtcs_bound) {
-               fb_helper->delayed_hotplug = true;
-               goto requeue;
-       }
+       mutex_lock(&module_mutex);
+       fbcon = find_module(name);
+       mutex_unlock(&module_mutex);
 
-       for (i = 0; i < fb_helper->connector_count; i++) {
-               connector = fb_helper->connector_info[i]->connector;
-               old_status = connector->status;
-               status = connector->funcs->detect(connector);
-               if (old_status != status) {
-                       changed = true;
-               }
-               if (status == connector_status_connected && repoll) {
-                       DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector));
-                       repoll = false;
-               }
-       }
-
-       if (changed) {
-               if (fb_helper->funcs->fb_output_status_changed)
-                       fb_helper->funcs->fb_output_status_changed(fb_helper);
-       }
-
-requeue:
-       if (repoll) {
-               ret = delayed_slow_work_enqueue(delayed_work, 5*HZ);
-               if (ret)
-                       DRM_ERROR("delayed enqueue failed %d\n", ret);
-       }
+       if (!fbcon)
+               request_module_nowait(name);
+       return 0;
 }
 
-static struct slow_work_ops output_status_change_ops = {
-       .execute = output_status_change_execute,
-};
-
+module_init(drm_fb_helper_modinit);
+#endif