arm: tegra: fb: Set new mode to all vc's
Shashank Sharma [Wed, 5 Dec 2012 08:41:25 +0000 (13:41 +0530)]
Send change all vc's notification from HDMI hot-plug reader to
fbcon, so that the new selected mode can be applied on all the
vc's from vc1 to vc6. This sometimes causes corruption on HDMI
hot plugin, when fbcon is mapped to HDMI

Bug 1166008
Signed-off-by: Shashank Sharma <shashanks@nvidia.com>
Change-Id: Id173de3014597f79c8c8b31bbbee7c9c560547b6
Reviewed-on: http://git-master/r/168683
Reviewed-by: Matthew Pedro <mapedro@nvidia.com>
Tested-by: Matthew Pedro <mapedro@nvidia.com>

drivers/video/tegra/dc/dc.c
drivers/video/tegra/fb.c

index ed54e9e..13e094a 100644 (file)
 #define DC_COM_PIN_OUTPUT_POLARITY1_INIT_VAL   0x01000000
 #define DC_COM_PIN_OUTPUT_POLARITY3_INIT_VAL   0x0
 
-static struct fb_videomode tegra_dc_hdmi_fallback_mode = {
-       .refresh = 60,
-       .xres = 640,
-       .yres = 480,
-       .pixclock = KHZ2PICOS(25200),
-       .hsync_len = 96,        /* h_sync_width */
-       .vsync_len = 2,         /* v_sync_width */
-       .left_margin = 48,      /* h_back_porch */
-       .upper_margin = 33,     /* v_back_porch */
-       .right_margin = 16,     /* h_front_porch */
-       .lower_margin = 10,     /* v_front_porch */
-       .vmode = 0,
-       .sync = 0,
-};
-
 static struct tegra_dc_mode override_disp_mode[3];
 
 static void _tegra_dc_controller_disable(struct tegra_dc *dc);
@@ -1458,34 +1443,6 @@ static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc)
 }
 #endif
 
-static int _tegra_dc_set_default_videomode(struct tegra_dc *dc)
-{
-       if (dc->mode.pclk == 0) {
-               switch (dc->out->type) {
-               case TEGRA_DC_OUT_HDMI:
-               /* DC enable called but no videomode is loaded.
-                    Check if HDMI is connected, then set fallback mdoe */
-               if (tegra_dc_hpd(dc)) {
-                       return tegra_dc_set_fb_mode(dc,
-                                       &tegra_dc_hdmi_fallback_mode, 0);
-               } else
-                       return false;
-
-               break;
-
-               /* Do nothing for other outputs for now */
-               case TEGRA_DC_OUT_RGB:
-
-               case TEGRA_DC_OUT_DSI:
-
-               default:
-                       return false;
-               }
-       }
-
-       return false;
-}
-
 static bool _tegra_dc_enable(struct tegra_dc *dc)
 {
        if (dc->mode.pclk == 0)
@@ -1914,6 +1871,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev,
                }
 
                dc->fb = tegra_fb_register(ndev, dc, dc->pdata->fb, fb_mem);
+
                if (IS_ERR_OR_NULL(dc->fb))
                        dc->fb = NULL;
        }
@@ -2028,10 +1986,8 @@ static int tegra_dc_resume(struct nvhost_device *ndev)
        mutex_lock(&dc->lock);
        dc->suspended = false;
 
-       if (dc->enabled) {
-               _tegra_dc_set_default_videomode(dc);
+       if (dc->enabled)
                _tegra_dc_enable(dc);
-       }
 
        if (dc->out && dc->out->hotplug_init)
                dc->out->hotplug_init();
index 46cbabf..f69048f 100644 (file)
@@ -493,33 +493,15 @@ const struct fb_videomode *tegra_fb_find_best_mode(
        return best;
 }
 
-static int tegra_fb_activate_mode(struct tegra_fb_info *fb_info,
-                               struct fb_var_screeninfo *var)
-{
-       int err;
-       struct fb_info *info = fb_info->info;
-
-       var->activate |= FB_ACTIVATE_FORCE;
-       console_lock();
-       info->flags |= FBINFO_MISC_USEREVENT;
-       err = fb_set_var(info, var);
-       info->flags &= ~FBINFO_MISC_USEREVENT;
-       console_unlock();
-       if (err)
-               return err;
-       return 0;
-}
-
 void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info,
                              struct fb_monspecs *specs,
                              bool (*mode_filter)(const struct tegra_dc *dc,
                                                  struct fb_videomode *mode))
 {
        int i;
-       int ret = 0;
+       bool first = false;
        struct fb_event event;
        struct fb_info *info = fb_info->info;
-       const struct fb_videomode *best_mode = NULL;
        struct fb_var_screeninfo var = {0,};
 
        mutex_lock(&fb_info->info->lock);
@@ -558,6 +540,13 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info,
                                fb_var_to_videomode(&m, &var);
                                fb_add_videomode(&m,
                                                 &fb_info->info->modelist);
+                               /* EDID stds recommend first detailed mode
+                               to be applied as default,but if first mode
+                               doesn't pass mode filter, we have to select
+                               and apply other mode. So flag on if first
+                               mode passes mode filter */
+                               if (!i)
+                                       first = true;
                        }
                } else {
                        fb_add_videomode(&specs->modedb[i],
@@ -565,36 +554,31 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info,
                }
        }
 
-       /* Get the best mode from modedb and apply on fb */
-       var.xres = 0;
-       var.yres = 0;
-       best_mode = tegra_fb_find_best_mode(&var, &info->modelist);
-
-       /* Update framebuffer with best mode */
-       fb_videomode_to_var(&var, best_mode);
-
-       /* TODO: Get proper way of getting rid of a 0 bpp */
-       if (!var.bits_per_pixel)
-               var.bits_per_pixel = 32;
-
-       memcpy(&info->var, &var, sizeof(struct fb_var_screeninfo));
-
-       ret = tegra_fb_activate_mode(fb_info, &var);
-       if (ret)
-               return;
+       /* We can't apply first detailed mode, so get the best mode
+       based on resolution and apply on fb */
+       if (!first) {
+               var.xres = 0;
+               var.yres = 0;
+               info->mode = (struct fb_videomode *)
+                       tegra_fb_find_best_mode(&var, &info->modelist);
+       }
 
+       /* Prepare fb info with new mode details */
+       fb_videomode_to_var(&info->var, info->mode);
        event.info = fb_info->info;
 
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE
-/* Lock the console before sending the noti. Fbconsole
-  * on HDMI might be using console
-  */
+       /* Send a noti to change fb_display[].mode for all vc's */
+       console_lock();
+       fb_notifier_call_chain(FB_EVENT_MODE_CHANGE_ALL, &event);
+       console_unlock();
+
+       /* Notify framebuffer console about mode change */
        console_lock();
-#endif
        fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
-#ifdef CONFIG_FRAMEBUFFER_CONSOLE
-/* Unlock the console */
        console_unlock();
+#else
+       fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
 #endif
 
        mutex_unlock(&fb_info->info->lock);