aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/DocBook/drm.tmpl1
-rw-r--r--drivers/gpu/drm/ast/ast_fb.c26
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_fbdev.c26
-rw-r--r--drivers/gpu/drm/drm_crtc.c16
-rw-r--r--drivers/gpu/drm/drm_fb_cma_helper.c22
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c251
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c35
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c14
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c1
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c1
-rw-r--r--drivers/gpu/drm/i915/intel_display.c20
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c1
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c1
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c21
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c1
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c1
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c1
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c1
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_fb.c27
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c25
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c25
-rw-r--r--drivers/gpu/drm/tegra/fb.c4
-rw-r--r--drivers/gpu/drm/udl/udl_fb.c26
-rw-r--r--drivers/staging/omapdrm/omap_fbdev.c21
-rw-r--r--include/drm/drm_crtc.h1
-rw-r--r--include/drm/drm_fb_helper.h18
27 files changed, 298 insertions, 290 deletions
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index b26de523ab70..51e1904ac4c7 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -2143,6 +2143,7 @@ void intel_crt_init(struct drm_device *dev)
2143 <title>fbdev Helper Functions Reference</title> 2143 <title>fbdev Helper Functions Reference</title>
2144!Pdrivers/gpu/drm/drm_fb_helper.c fbdev helpers 2144!Pdrivers/gpu/drm/drm_fb_helper.c fbdev helpers
2145!Edrivers/gpu/drm/drm_fb_helper.c 2145!Edrivers/gpu/drm/drm_fb_helper.c
2146!Iinclude/drm/drm_fb_helper.h
2146 </sect2> 2147 </sect2>
2147 <sect2> 2148 <sect2>
2148 <title>Display Port Helper Functions Reference</title> 2149 <title>Display Port Helper Functions Reference</title>
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index 3e6584b940dc..34931fe7d2c5 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -40,6 +40,7 @@
40#include <drm/drmP.h> 40#include <drm/drmP.h>
41#include <drm/drm_crtc.h> 41#include <drm/drm_crtc.h>
42#include <drm/drm_fb_helper.h> 42#include <drm/drm_fb_helper.h>
43#include <drm/drm_crtc_helper.h>
43#include "ast_drv.h" 44#include "ast_drv.h"
44 45
45static void ast_dirty_update(struct ast_fbdev *afbdev, 46static void ast_dirty_update(struct ast_fbdev *afbdev,
@@ -145,9 +146,10 @@ static int astfb_create_object(struct ast_fbdev *afbdev,
145 return ret; 146 return ret;
146} 147}
147 148
148static int astfb_create(struct ast_fbdev *afbdev, 149static int astfb_create(struct drm_fb_helper *helper,
149 struct drm_fb_helper_surface_size *sizes) 150 struct drm_fb_helper_surface_size *sizes)
150{ 151{
152 struct ast_fbdev *afbdev = (struct ast_fbdev *)helper;
151 struct drm_device *dev = afbdev->helper.dev; 153 struct drm_device *dev = afbdev->helper.dev;
152 struct drm_mode_fb_cmd2 mode_cmd; 154 struct drm_mode_fb_cmd2 mode_cmd;
153 struct drm_framebuffer *fb; 155 struct drm_framebuffer *fb;
@@ -248,26 +250,10 @@ static void ast_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
248 *blue = ast_crtc->lut_b[regno] << 8; 250 *blue = ast_crtc->lut_b[regno] << 8;
249} 251}
250 252
251static int ast_find_or_create_single(struct drm_fb_helper *helper,
252 struct drm_fb_helper_surface_size *sizes)
253{
254 struct ast_fbdev *afbdev = (struct ast_fbdev *)helper;
255 int new_fb = 0;
256 int ret;
257
258 if (!helper->fb) {
259 ret = astfb_create(afbdev, sizes);
260 if (ret)
261 return ret;
262 new_fb = 1;
263 }
264 return new_fb;
265}
266
267static struct drm_fb_helper_funcs ast_fb_helper_funcs = { 253static struct drm_fb_helper_funcs ast_fb_helper_funcs = {
268 .gamma_set = ast_fb_gamma_set, 254 .gamma_set = ast_fb_gamma_set,
269 .gamma_get = ast_fb_gamma_get, 255 .gamma_get = ast_fb_gamma_get,
270 .fb_probe = ast_find_or_create_single, 256 .fb_probe = astfb_create,
271}; 257};
272 258
273static void ast_fbdev_destroy(struct drm_device *dev, 259static void ast_fbdev_destroy(struct drm_device *dev,
@@ -314,6 +300,10 @@ int ast_fbdev_init(struct drm_device *dev)
314 } 300 }
315 301
316 drm_fb_helper_single_add_all_connectors(&afbdev->helper); 302 drm_fb_helper_single_add_all_connectors(&afbdev->helper);
303
304 /* disable all the possible outputs/crtcs before entering KMS mode */
305 drm_helper_disable_unused_functions(dev);
306
317 drm_fb_helper_initial_config(&afbdev->helper, 32); 307 drm_fb_helper_initial_config(&afbdev->helper, 32);
318 return 0; 308 return 0;
319} 309}
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index 3daea0f638c3..e25afccaf85b 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -11,6 +11,7 @@
11#include <linux/module.h> 11#include <linux/module.h>
12#include <drm/drmP.h> 12#include <drm/drmP.h>
13#include <drm/drm_fb_helper.h> 13#include <drm/drm_fb_helper.h>
14#include <drm/drm_crtc_helper.h>
14 15
15#include <linux/fb.h> 16#include <linux/fb.h>
16 17
@@ -120,9 +121,10 @@ static int cirrusfb_create_object(struct cirrus_fbdev *afbdev,
120 return ret; 121 return ret;
121} 122}
122 123
123static int cirrusfb_create(struct cirrus_fbdev *gfbdev, 124static int cirrusfb_create(struct drm_fb_helper *helper,
124 struct drm_fb_helper_surface_size *sizes) 125 struct drm_fb_helper_surface_size *sizes)
125{ 126{
127 struct cirrus_fbdev *gfbdev = (struct cirrus_fbdev *)helper;
126 struct drm_device *dev = gfbdev->helper.dev; 128 struct drm_device *dev = gfbdev->helper.dev;
127 struct cirrus_device *cdev = gfbdev->helper.dev->dev_private; 129 struct cirrus_device *cdev = gfbdev->helper.dev->dev_private;
128 struct fb_info *info; 130 struct fb_info *info;
@@ -219,23 +221,6 @@ out_iounmap:
219 return ret; 221 return ret;
220} 222}
221 223
222static int cirrus_fb_find_or_create_single(struct drm_fb_helper *helper,
223 struct drm_fb_helper_surface_size
224 *sizes)
225{
226 struct cirrus_fbdev *gfbdev = (struct cirrus_fbdev *)helper;
227 int new_fb = 0;
228 int ret;
229
230 if (!helper->fb) {
231 ret = cirrusfb_create(gfbdev, sizes);
232 if (ret)
233 return ret;
234 new_fb = 1;
235 }
236 return new_fb;
237}
238
239static int cirrus_fbdev_destroy(struct drm_device *dev, 224static int cirrus_fbdev_destroy(struct drm_device *dev,
240 struct cirrus_fbdev *gfbdev) 225 struct cirrus_fbdev *gfbdev)
241{ 226{
@@ -267,7 +252,7 @@ static int cirrus_fbdev_destroy(struct drm_device *dev,
267static struct drm_fb_helper_funcs cirrus_fb_helper_funcs = { 252static struct drm_fb_helper_funcs cirrus_fb_helper_funcs = {
268 .gamma_set = cirrus_crtc_fb_gamma_set, 253 .gamma_set = cirrus_crtc_fb_gamma_set,
269 .gamma_get = cirrus_crtc_fb_gamma_get, 254 .gamma_get = cirrus_crtc_fb_gamma_get,
270 .fb_probe = cirrus_fb_find_or_create_single, 255 .fb_probe = cirrusfb_create,
271}; 256};
272 257
273int cirrus_fbdev_init(struct cirrus_device *cdev) 258int cirrus_fbdev_init(struct cirrus_device *cdev)
@@ -291,6 +276,9 @@ int cirrus_fbdev_init(struct cirrus_device *cdev)
291 return ret; 276 return ret;
292 } 277 }
293 drm_fb_helper_single_add_all_connectors(&gfbdev->helper); 278 drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
279
280 /* disable all the possible outputs/crtcs before entering KMS mode */
281 drm_helper_disable_unused_functions(cdev->dev);
294 drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel); 282 drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel);
295 283
296 return 0; 284 return 0;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 9c797f6fea75..f17077307c65 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -68,9 +68,23 @@ void drm_modeset_unlock_all(struct drm_device *dev)
68 68
69 mutex_unlock(&dev->mode_config.mutex); 69 mutex_unlock(&dev->mode_config.mutex);
70} 70}
71
72EXPORT_SYMBOL(drm_modeset_unlock_all); 71EXPORT_SYMBOL(drm_modeset_unlock_all);
73 72
73/**
74 * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
75 * @dev: device
76 */
77void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
78{
79 struct drm_crtc *crtc;
80
81 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
82 WARN_ON(!mutex_is_locked(&crtc->mutex));
83
84 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
85}
86EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
87
74/* Avoid boilerplate. I'm tired of typing. */ 88/* Avoid boilerplate. I'm tired of typing. */
75#define DRM_ENUM_NAME_FN(fnname, list) \ 89#define DRM_ENUM_NAME_FN(fnname, list) \
76 char *fnname(int val) \ 90 char *fnname(int val) \
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index 3742bc96421e..e851658f87d5 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -275,23 +275,8 @@ err_drm_gem_cma_free_object:
275 return ret; 275 return ret;
276} 276}
277 277
278static int drm_fbdev_cma_probe(struct drm_fb_helper *helper,
279 struct drm_fb_helper_surface_size *sizes)
280{
281 int ret = 0;
282
283 if (!helper->fb) {
284 ret = drm_fbdev_cma_create(helper, sizes);
285 if (ret < 0)
286 return ret;
287 ret = 1;
288 }
289
290 return ret;
291}
292
293static struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = { 278static struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = {
294 .fb_probe = drm_fbdev_cma_probe, 279 .fb_probe = drm_fbdev_cma_create,
295}; 280};
296 281
297/** 282/**
@@ -333,6 +318,9 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
333 318
334 } 319 }
335 320
321 /* disable all the possible outputs/crtcs before entering KMS mode */
322 drm_helper_disable_unused_functions(dev);
323
336 ret = drm_fb_helper_initial_config(helper, preferred_bpp); 324 ret = drm_fb_helper_initial_config(helper, preferred_bpp);
337 if (ret < 0) { 325 if (ret < 0) {
338 dev_err(dev->dev, "Failed to set inital hw configuration.\n"); 326 dev_err(dev->dev, "Failed to set inital hw configuration.\n");
@@ -389,8 +377,10 @@ EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini);
389 */ 377 */
390void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma) 378void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma)
391{ 379{
380 drm_modeset_lock_all(dev);
392 if (fbdev_cma) 381 if (fbdev_cma)
393 drm_fb_helper_restore_fbdev_mode(&fbdev_cma->fb_helper); 382 drm_fb_helper_restore_fbdev_mode(&fbdev_cma->fb_helper);
383 drm_modeset_unlock_all(dev);
394} 384}
395EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode); 385EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode);
396 386
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 0c6e25e979dd..59d6b9bf204b 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -52,9 +52,36 @@ static LIST_HEAD(kernel_fb_helper_list);
52 * mode setting driver. They can be used mostly independantely from the crtc 52 * mode setting driver. They can be used mostly independantely from the crtc
53 * helper functions used by many drivers to implement the kernel mode setting 53 * helper functions used by many drivers to implement the kernel mode setting
54 * interfaces. 54 * interfaces.
55 *
56 * Initialization is done as a three-step process with drm_fb_helper_init(),
57 * drm_fb_helper_single_add_all_connectors() and drm_fb_helper_initial_config().
58 * Drivers with fancier requirements than the default beheviour can override the
59 * second step with their own code. Teardown is done with drm_fb_helper_fini().
60 *
61 * At runtime drivers should restore the fbdev console by calling
62 * drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They
63 * should also notify the fb helper code from updates to the output
64 * configuration by calling drm_fb_helper_hotplug_event(). For easier
65 * integration with the output polling code in drm_crtc_helper.c the modeset
66 * code proves a ->output_poll_changed callback.
67 *
68 * All other functions exported by the fb helper library can be used to
69 * implement the fbdev driver interface by the driver.
55 */ 70 */
56 71
57/* simple single crtc case helper function */ 72/**
73 * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev
74 * emulation helper
75 * @fb_helper: fbdev initialized with drm_fb_helper_init
76 *
77 * This functions adds all the available connectors for use with the given
78 * fb_helper. This is a separate step to allow drivers to freely assign
79 * connectors to the fbdev, e.g. if some are reserved for special purposes or
80 * not adequate to be used for the fbcon.
81 *
82 * Since this is part of the initial setup before the fbdev is published, no
83 * locking is required.
84 */
58int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) 85int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
59{ 86{
60 struct drm_device *dev = fb_helper->dev; 87 struct drm_device *dev = fb_helper->dev;
@@ -163,6 +190,10 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
163 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 190 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
164} 191}
165 192
193/**
194 * drm_fb_helper_debug_enter - implementation for ->fb_debug_enter
195 * @info: fbdev registered by the helper
196 */
166int drm_fb_helper_debug_enter(struct fb_info *info) 197int drm_fb_helper_debug_enter(struct fb_info *info)
167{ 198{
168 struct drm_fb_helper *helper = info->par; 199 struct drm_fb_helper *helper = info->par;
@@ -208,6 +239,10 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
208 return NULL; 239 return NULL;
209} 240}
210 241
242/**
243 * drm_fb_helper_debug_leave - implementation for ->fb_debug_leave
244 * @info: fbdev registered by the helper
245 */
211int drm_fb_helper_debug_leave(struct fb_info *info) 246int drm_fb_helper_debug_leave(struct fb_info *info)
212{ 247{
213 struct drm_fb_helper *helper = info->par; 248 struct drm_fb_helper *helper = info->par;
@@ -239,10 +274,21 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
239} 274}
240EXPORT_SYMBOL(drm_fb_helper_debug_leave); 275EXPORT_SYMBOL(drm_fb_helper_debug_leave);
241 276
277/**
278 * drm_fb_helper_restore_fbdev_mode - restore fbdev configuration
279 * @fb_helper: fbcon to restore
280 *
281 * This should be called from driver's drm ->lastclose callback
282 * when implementing an fbcon on top of kms using this helper. This ensures that
283 * the user isn't greeted with a black screen when e.g. X dies.
284 */
242bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) 285bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
243{ 286{
244 bool error = false; 287 bool error = false;
245 int i, ret; 288 int i, ret;
289
290 drm_warn_on_modeset_not_all_locked(fb_helper->dev);
291
246 for (i = 0; i < fb_helper->crtc_count; i++) { 292 for (i = 0; i < fb_helper->crtc_count; i++) {
247 struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; 293 struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
248 ret = drm_mode_set_config_internal(mode_set); 294 ret = drm_mode_set_config_internal(mode_set);
@@ -253,6 +299,10 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
253} 299}
254EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode); 300EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode);
255 301
302/*
303 * restore fbcon display for all kms driver's using this helper, used for sysrq
304 * and panic handling.
305 */
256static bool drm_fb_helper_force_kernel_mode(void) 306static bool drm_fb_helper_force_kernel_mode(void)
257{ 307{
258 bool ret, error = false; 308 bool ret, error = false;
@@ -272,7 +322,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
272 return error; 322 return error;
273} 323}
274 324
275int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed, 325static int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
276 void *panic_str) 326 void *panic_str)
277{ 327{
278 /* 328 /*
@@ -285,26 +335,11 @@ int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
285 pr_err("panic occurred, switching back to text console\n"); 335 pr_err("panic occurred, switching back to text console\n");
286 return drm_fb_helper_force_kernel_mode(); 336 return drm_fb_helper_force_kernel_mode();
287} 337}
288EXPORT_SYMBOL(drm_fb_helper_panic);
289 338
290static struct notifier_block paniced = { 339static struct notifier_block paniced = {
291 .notifier_call = drm_fb_helper_panic, 340 .notifier_call = drm_fb_helper_panic,
292}; 341};
293 342
294/**
295 * drm_fb_helper_restore - restore the framebuffer console (kernel) config
296 *
297 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
298 */
299void drm_fb_helper_restore(void)
300{
301 bool ret;
302 ret = drm_fb_helper_force_kernel_mode();
303 if (ret == true)
304 DRM_ERROR("Failed to restore crtc configuration\n");
305}
306EXPORT_SYMBOL(drm_fb_helper_restore);
307
308static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) 343static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
309{ 344{
310 struct drm_device *dev = fb_helper->dev; 345 struct drm_device *dev = fb_helper->dev;
@@ -326,7 +361,10 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
326#ifdef CONFIG_MAGIC_SYSRQ 361#ifdef CONFIG_MAGIC_SYSRQ
327static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) 362static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
328{ 363{
329 drm_fb_helper_restore(); 364 bool ret;
365 ret = drm_fb_helper_force_kernel_mode();
366 if (ret == true)
367 DRM_ERROR("Failed to restore crtc configuration\n");
330} 368}
331static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn); 369static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
332 370
@@ -353,6 +391,14 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
353 int i, j; 391 int i, j;
354 392
355 /* 393 /*
394 * fbdev->blank can be called from irq context in case of a panic.
395 * Since we already have our own special panic handler which will
396 * restore the fbdev console mode completely, just bail out early.
397 */
398 if (oops_in_progress)
399 return;
400
401 /*
356 * For each CRTC in this fb, turn the connectors on/off. 402 * For each CRTC in this fb, turn the connectors on/off.
357 */ 403 */
358 drm_modeset_lock_all(dev); 404 drm_modeset_lock_all(dev);
@@ -378,6 +424,11 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
378 drm_modeset_unlock_all(dev); 424 drm_modeset_unlock_all(dev);
379} 425}
380 426
427/**
428 * drm_fb_helper_blank - implementation for ->fb_blank
429 * @blank: desired blanking state
430 * @info: fbdev registered by the helper
431 */
381int drm_fb_helper_blank(int blank, struct fb_info *info) 432int drm_fb_helper_blank(int blank, struct fb_info *info)
382{ 433{
383 switch (blank) { 434 switch (blank) {
@@ -421,6 +472,24 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
421 kfree(helper->crtc_info); 472 kfree(helper->crtc_info);
422} 473}
423 474
475/**
476 * drm_fb_helper_init - initialize a drm_fb_helper structure
477 * @dev: drm device
478 * @fb_helper: driver-allocated fbdev helper structure to initialize
479 * @crtc_count: maximum number of crtcs to support in this fbdev emulation
480 * @max_conn_count: max connector count
481 *
482 * This allocates the structures for the fbdev helper with the given limits.
483 * Note that this won't yet touch the hardware (through the driver interfaces)
484 * nor register the fbdev. This is only done in drm_fb_helper_initial_config()
485 * to allow driver writes more control over the exact init sequence.
486 *
487 * Drivers must set fb_helper->funcs before calling
488 * drm_fb_helper_initial_config().
489 *
490 * RETURNS:
491 * Zero if everything went ok, nonzero otherwise.
492 */
424int drm_fb_helper_init(struct drm_device *dev, 493int drm_fb_helper_init(struct drm_device *dev,
425 struct drm_fb_helper *fb_helper, 494 struct drm_fb_helper *fb_helper,
426 int crtc_count, int max_conn_count) 495 int crtc_count, int max_conn_count)
@@ -549,6 +618,11 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
549 return 0; 618 return 0;
550} 619}
551 620
621/**
622 * drm_fb_helper_setcmap - implementation for ->fb_setcmap
623 * @cmap: cmap to set
624 * @info: fbdev registered by the helper
625 */
552int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) 626int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
553{ 627{
554 struct drm_fb_helper *fb_helper = info->par; 628 struct drm_fb_helper *fb_helper = info->par;
@@ -588,6 +662,11 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
588} 662}
589EXPORT_SYMBOL(drm_fb_helper_setcmap); 663EXPORT_SYMBOL(drm_fb_helper_setcmap);
590 664
665/**
666 * drm_fb_helper_check_var - implementation for ->fb_check_var
667 * @var: screeninfo to check
668 * @info: fbdev registered by the helper
669 */
591int drm_fb_helper_check_var(struct fb_var_screeninfo *var, 670int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
592 struct fb_info *info) 671 struct fb_info *info)
593{ 672{
@@ -680,13 +759,19 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
680} 759}
681EXPORT_SYMBOL(drm_fb_helper_check_var); 760EXPORT_SYMBOL(drm_fb_helper_check_var);
682 761
683/* this will let fbcon do the mode init */ 762/**
763 * drm_fb_helper_set_par - implementation for ->fb_set_par
764 * @info: fbdev registered by the helper
765 *
766 * This will let fbcon do the mode init and is called at initialization time by
767 * the fbdev core when registering the driver, and later on through the hotplug
768 * callback.
769 */
684int drm_fb_helper_set_par(struct fb_info *info) 770int drm_fb_helper_set_par(struct fb_info *info)
685{ 771{
686 struct drm_fb_helper *fb_helper = info->par; 772 struct drm_fb_helper *fb_helper = info->par;
687 struct drm_device *dev = fb_helper->dev; 773 struct drm_device *dev = fb_helper->dev;
688 struct fb_var_screeninfo *var = &info->var; 774 struct fb_var_screeninfo *var = &info->var;
689 struct drm_crtc *crtc;
690 int ret; 775 int ret;
691 int i; 776 int i;
692 777
@@ -697,7 +782,6 @@ int drm_fb_helper_set_par(struct fb_info *info)
697 782
698 drm_modeset_lock_all(dev); 783 drm_modeset_lock_all(dev);
699 for (i = 0; i < fb_helper->crtc_count; i++) { 784 for (i = 0; i < fb_helper->crtc_count; i++) {
700 crtc = fb_helper->crtc_info[i].mode_set.crtc;
701 ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set); 785 ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set);
702 if (ret) { 786 if (ret) {
703 drm_modeset_unlock_all(dev); 787 drm_modeset_unlock_all(dev);
@@ -714,6 +798,11 @@ int drm_fb_helper_set_par(struct fb_info *info)
714} 798}
715EXPORT_SYMBOL(drm_fb_helper_set_par); 799EXPORT_SYMBOL(drm_fb_helper_set_par);
716 800
801/**
802 * drm_fb_helper_pan_display - implementation for ->fb_pan_display
803 * @var: updated screen information
804 * @info: fbdev registered by the helper
805 */
717int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, 806int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
718 struct fb_info *info) 807 struct fb_info *info)
719{ 808{
@@ -751,10 +840,15 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
751} 840}
752EXPORT_SYMBOL(drm_fb_helper_pan_display); 841EXPORT_SYMBOL(drm_fb_helper_pan_display);
753 842
754int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, 843/*
755 int preferred_bpp) 844 * Allocates the backing storage and sets up the fbdev info structure through
845 * the ->fb_probe callback and then registers the fbdev and sets up the panic
846 * notifier.
847 */
848static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
849 int preferred_bpp)
756{ 850{
757 int new_fb = 0; 851 int ret = 0;
758 int crtc_count = 0; 852 int crtc_count = 0;
759 int i; 853 int i;
760 struct fb_info *info; 854 struct fb_info *info;
@@ -832,27 +926,30 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
832 } 926 }
833 927
834 /* push down into drivers */ 928 /* push down into drivers */
835 new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); 929 ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
836 if (new_fb < 0) 930 if (ret < 0)
837 return new_fb; 931 return ret;
838 932
839 info = fb_helper->fbdev; 933 info = fb_helper->fbdev;
840 934
841 /* set the fb pointer */ 935 /*
936 * Set the fb pointer - usually drm_setup_crtcs does this for hotplug
937 * events, but at init time drm_setup_crtcs needs to be called before
938 * the fb is allocated (since we need to figure out the desired size of
939 * the fb before we can allocate it ...). Hence we need to fix things up
940 * here again.
941 */
842 for (i = 0; i < fb_helper->crtc_count; i++) 942 for (i = 0; i < fb_helper->crtc_count; i++)
843 fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; 943 if (fb_helper->crtc_info[i].mode_set.num_connectors)
944 fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
844 945
845 if (new_fb) {
846 info->var.pixclock = 0;
847 if (register_framebuffer(info) < 0)
848 return -EINVAL;
849 946
850 dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n", 947 info->var.pixclock = 0;
851 info->node, info->fix.id); 948 if (register_framebuffer(info) < 0)
949 return -EINVAL;
852 950
853 } else { 951 dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n",
854 drm_fb_helper_set_par(info); 952 info->node, info->fix.id);
855 }
856 953
857 /* Switch back to kernel console on panic */ 954 /* Switch back to kernel console on panic */
858 /* multi card linked list maybe */ 955 /* multi card linked list maybe */
@@ -862,13 +959,25 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
862 &paniced); 959 &paniced);
863 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); 960 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
864 } 961 }
865 if (new_fb) 962
866 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); 963 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
867 964
868 return 0; 965 return 0;
869} 966}
870EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
871 967
968/**
969 * drm_fb_helper_fill_fix - initializes fixed fbdev information
970 * @info: fbdev registered by the helper
971 * @pitch: desired pitch
972 * @depth: desired depth
973 *
974 * Helper to fill in the fixed fbdev information useful for a non-accelerated
975 * fbdev emulations. Drivers which support acceleration methods which impose
976 * additional constraints need to set up their own limits.
977 *
978 * Drivers should call this (or their equivalent setup code) from their
979 * ->fb_probe callback.
980 */
872void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, 981void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
873 uint32_t depth) 982 uint32_t depth)
874{ 983{
@@ -889,6 +998,20 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
889} 998}
890EXPORT_SYMBOL(drm_fb_helper_fill_fix); 999EXPORT_SYMBOL(drm_fb_helper_fill_fix);
891 1000
1001/**
1002 * drm_fb_helper_fill_var - initalizes variable fbdev information
1003 * @info: fbdev instance to set up
1004 * @fb_helper: fb helper instance to use as template
1005 * @fb_width: desired fb width
1006 * @fb_height: desired fb height
1007 *
1008 * Sets up the variable fbdev metainformation from the given fb helper instance
1009 * and the drm framebuffer allocated in fb_helper->fb.
1010 *
1011 * Drivers should call this (or their equivalent setup code) from their
1012 * ->fb_probe callback after having allocated the fbdev backing
1013 * storage framebuffer.
1014 */
892void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, 1015void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
893 uint32_t fb_width, uint32_t fb_height) 1016 uint32_t fb_width, uint32_t fb_height)
894{ 1017{
@@ -1312,6 +1435,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
1312 for (i = 0; i < fb_helper->crtc_count; i++) { 1435 for (i = 0; i < fb_helper->crtc_count; i++) {
1313 modeset = &fb_helper->crtc_info[i].mode_set; 1436 modeset = &fb_helper->crtc_info[i].mode_set;
1314 modeset->num_connectors = 0; 1437 modeset->num_connectors = 0;
1438 modeset->fb = NULL;
1315 } 1439 }
1316 1440
1317 for (i = 0; i < fb_helper->connector_count; i++) { 1441 for (i = 0; i < fb_helper->connector_count; i++) {
@@ -1328,9 +1452,21 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
1328 modeset->mode = drm_mode_duplicate(dev, 1452 modeset->mode = drm_mode_duplicate(dev,
1329 fb_crtc->desired_mode); 1453 fb_crtc->desired_mode);
1330 modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; 1454 modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
1455 modeset->fb = fb_helper->fb;
1331 } 1456 }
1332 } 1457 }
1333 1458
1459 /* Clear out any old modes if there are no more connected outputs. */
1460 for (i = 0; i < fb_helper->crtc_count; i++) {
1461 modeset = &fb_helper->crtc_info[i].mode_set;
1462 if (modeset->num_connectors == 0) {
1463 BUG_ON(modeset->fb);
1464 BUG_ON(modeset->num_connectors);
1465 if (modeset->mode)
1466 drm_mode_destroy(dev, modeset->mode);
1467 modeset->mode = NULL;
1468 }
1469 }
1334out: 1470out:
1335 kfree(crtcs); 1471 kfree(crtcs);
1336 kfree(modes); 1472 kfree(modes);
@@ -1338,18 +1474,23 @@ out:
1338} 1474}
1339 1475
1340/** 1476/**
1341 * drm_helper_initial_config - setup a sane initial connector configuration 1477 * drm_fb_helper_initial_config - setup a sane initial connector configuration
1342 * @fb_helper: fb_helper device struct 1478 * @fb_helper: fb_helper device struct
1343 * @bpp_sel: bpp value to use for the framebuffer configuration 1479 * @bpp_sel: bpp value to use for the framebuffer configuration
1344 * 1480 *
1345 * LOCKING:
1346 * Called at init time by the driver to set up the @fb_helper initial
1347 * configuration, must take the mode config lock.
1348 *
1349 * Scans the CRTCs and connectors and tries to put together an initial setup. 1481 * Scans the CRTCs and connectors and tries to put together an initial setup.
1350 * At the moment, this is a cloned configuration across all heads with 1482 * At the moment, this is a cloned configuration across all heads with
1351 * a new framebuffer object as the backing store. 1483 * a new framebuffer object as the backing store.
1352 * 1484 *
1485 * Note that this also registers the fbdev and so allows userspace to call into
1486 * the driver through the fbdev interfaces.
1487 *
1488 * This function will call down into the ->fb_probe callback to let
1489 * the driver allocate and initialize the fbdev info structure and the drm
1490 * framebuffer used to back the fbdev. drm_fb_helper_fill_var() and
1491 * drm_fb_helper_fill_fix() are provided as helpers to setup simple default
1492 * values for the fbdev info structure.
1493 *
1353 * RETURNS: 1494 * RETURNS:
1354 * Zero if everything went ok, nonzero otherwise. 1495 * Zero if everything went ok, nonzero otherwise.
1355 */ 1496 */
@@ -1358,9 +1499,6 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1358 struct drm_device *dev = fb_helper->dev; 1499 struct drm_device *dev = fb_helper->dev;
1359 int count = 0; 1500 int count = 0;
1360 1501
1361 /* disable all the possible outputs/crtcs before entering KMS mode */
1362 drm_helper_disable_unused_functions(fb_helper->dev);
1363
1364 drm_fb_helper_parse_command_line(fb_helper); 1502 drm_fb_helper_parse_command_line(fb_helper);
1365 1503
1366 count = drm_fb_helper_probe_connector_modes(fb_helper, 1504 count = drm_fb_helper_probe_connector_modes(fb_helper,
@@ -1383,12 +1521,17 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
1383 * probing all the outputs attached to the fb 1521 * probing all the outputs attached to the fb
1384 * @fb_helper: the drm_fb_helper 1522 * @fb_helper: the drm_fb_helper
1385 * 1523 *
1386 * LOCKING:
1387 * Called at runtime, must take mode config lock.
1388 *
1389 * Scan the connectors attached to the fb_helper and try to put together a 1524 * Scan the connectors attached to the fb_helper and try to put together a
1390 * setup after *notification of a change in output configuration. 1525 * setup after *notification of a change in output configuration.
1391 * 1526 *
1527 * Called at runtime, takes the mode config locks to be able to check/change the
1528 * modeset configuration. Must be run from process context (which usually means
1529 * either the output polling work or a work item launched from the driver's
1530 * hotplug interrupt).
1531 *
1532 * Note that the driver must ensure that this is only called _after_ the fb has
1533 * been fully set up, i.e. after the call to drm_fb_helper_initial_config.
1534 *
1392 * RETURNS: 1535 * RETURNS:
1393 * 0 on success and a non-zero error code otherwise. 1536 * 0 on success and a non-zero error code otherwise.
1394 */ 1537 */
@@ -1418,7 +1561,9 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
1418 drm_setup_crtcs(fb_helper); 1561 drm_setup_crtcs(fb_helper);
1419 drm_modeset_unlock_all(dev); 1562 drm_modeset_unlock_all(dev);
1420 1563
1421 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); 1564 drm_fb_helper_set_par(fb_helper->fbdev);
1565
1566 return 0;
1422} 1567}
1423EXPORT_SYMBOL(drm_fb_helper_hotplug_event); 1568EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
1424 1569
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 90d335cfb8c0..68f0045f86b8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -226,36 +226,8 @@ out:
226 return ret; 226 return ret;
227} 227}
228 228
229static int exynos_drm_fbdev_probe(struct drm_fb_helper *helper,
230 struct drm_fb_helper_surface_size *sizes)
231{
232 int ret = 0;
233
234 DRM_DEBUG_KMS("%s\n", __FILE__);
235
236 /*
237 * with !helper->fb, it means that this funcion is called first time
238 * and after that, the helper->fb would be used as clone mode.
239 */
240 if (!helper->fb) {
241 ret = exynos_drm_fbdev_create(helper, sizes);
242 if (ret < 0) {
243 DRM_ERROR("failed to create fbdev.\n");
244 return ret;
245 }
246
247 /*
248 * fb_helper expects a value more than 1 if succeed
249 * because register_framebuffer() should be called.
250 */
251 ret = 1;
252 }
253
254 return ret;
255}
256
257static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = { 229static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = {
258 .fb_probe = exynos_drm_fbdev_probe, 230 .fb_probe = exynos_drm_fbdev_create,
259}; 231};
260 232
261int exynos_drm_fbdev_init(struct drm_device *dev) 233int exynos_drm_fbdev_init(struct drm_device *dev)
@@ -295,6 +267,9 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
295 267
296 } 268 }
297 269
270 /* disable all the possible outputs/crtcs before entering KMS mode */
271 drm_helper_disable_unused_functions(dev);
272
298 ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); 273 ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP);
299 if (ret < 0) { 274 if (ret < 0) {
300 DRM_ERROR("failed to set up hw configuration.\n"); 275 DRM_ERROR("failed to set up hw configuration.\n");
@@ -376,5 +351,7 @@ void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
376 if (!private || !private->fb_helper) 351 if (!private || !private->fb_helper)
377 return; 352 return;
378 353
354 drm_modeset_lock_all(dev);
379 drm_fb_helper_restore_fbdev_mode(private->fb_helper); 355 drm_fb_helper_restore_fbdev_mode(private->fb_helper);
356 drm_modeset_unlock_all(dev);
380} 357}
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index c1ef37e2efdf..2590cac84257 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -545,9 +545,7 @@ static int psbfb_probe(struct drm_fb_helper *helper,
545 struct psb_fbdev *psb_fbdev = (struct psb_fbdev *)helper; 545 struct psb_fbdev *psb_fbdev = (struct psb_fbdev *)helper;
546 struct drm_device *dev = psb_fbdev->psb_fb_helper.dev; 546 struct drm_device *dev = psb_fbdev->psb_fb_helper.dev;
547 struct drm_psb_private *dev_priv = dev->dev_private; 547 struct drm_psb_private *dev_priv = dev->dev_private;
548 int new_fb = 0;
549 int bytespp; 548 int bytespp;
550 int ret;
551 549
552 bytespp = sizes->surface_bpp / 8; 550 bytespp = sizes->surface_bpp / 8;
553 if (bytespp == 3) /* no 24bit packed */ 551 if (bytespp == 3) /* no 24bit packed */
@@ -562,13 +560,7 @@ static int psbfb_probe(struct drm_fb_helper *helper,
562 sizes->surface_depth = 16; 560 sizes->surface_depth = 16;
563 } 561 }
564 562
565 if (!helper->fb) { 563 return psbfb_create(psb_fbdev, sizes);
566 ret = psbfb_create(psb_fbdev, sizes);
567 if (ret)
568 return ret;
569 new_fb = 1;
570 }
571 return new_fb;
572} 564}
573 565
574static struct drm_fb_helper_funcs psb_fb_helper_funcs = { 566static struct drm_fb_helper_funcs psb_fb_helper_funcs = {
@@ -616,6 +608,10 @@ int psb_fbdev_init(struct drm_device *dev)
616 INTELFB_CONN_LIMIT); 608 INTELFB_CONN_LIMIT);
617 609
618 drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper); 610 drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper);
611
612 /* disable all the possible outputs/crtcs before entering KMS mode */
613 drm_helper_disable_unused_functions(dev);
614
619 drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32); 615 drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32);
620 return 0; 616 return 0;
621} 617}
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 68e79f32e100..729dd1a3fe72 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -685,7 +685,6 @@ static void intel_crt_reset(struct drm_connector *connector)
685static const struct drm_encoder_helper_funcs crt_encoder_funcs = { 685static const struct drm_encoder_helper_funcs crt_encoder_funcs = {
686 .mode_fixup = intel_crt_mode_fixup, 686 .mode_fixup = intel_crt_mode_fixup,
687 .mode_set = intel_crt_mode_set, 687 .mode_set = intel_crt_mode_set,
688 .disable = intel_encoder_noop,
689}; 688};
690 689
691static const struct drm_connector_funcs intel_crt_connector_funcs = { 690static const struct drm_connector_funcs intel_crt_connector_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index cedf4ab5ff16..a259e09eb6a8 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1481,7 +1481,6 @@ static const struct drm_encoder_funcs intel_ddi_funcs = {
1481static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { 1481static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = {
1482 .mode_fixup = intel_ddi_mode_fixup, 1482 .mode_fixup = intel_ddi_mode_fixup,
1483 .mode_set = intel_ddi_mode_set, 1483 .mode_set = intel_ddi_mode_set,
1484 .disable = intel_encoder_noop,
1485}; 1484};
1486 1485
1487void intel_ddi_init(struct drm_device *dev, enum port port) 1486void intel_ddi_init(struct drm_device *dev, enum port port)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0dfecaf599ff..ca8d5929063e 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3718,10 +3718,6 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc)
3718 intel_crtc_update_sarea(crtc, enable); 3718 intel_crtc_update_sarea(crtc, enable);
3719} 3719}
3720 3720
3721static void intel_crtc_noop(struct drm_crtc *crtc)
3722{
3723}
3724
3725static void intel_crtc_disable(struct drm_crtc *crtc) 3721static void intel_crtc_disable(struct drm_crtc *crtc)
3726{ 3722{
3727 struct drm_device *dev = crtc->dev; 3723 struct drm_device *dev = crtc->dev;
@@ -3770,10 +3766,6 @@ void intel_modeset_disable(struct drm_device *dev)
3770 } 3766 }
3771} 3767}
3772 3768
3773void intel_encoder_noop(struct drm_encoder *encoder)
3774{
3775}
3776
3777void intel_encoder_destroy(struct drm_encoder *encoder) 3769void intel_encoder_destroy(struct drm_encoder *encoder)
3778{ 3770{
3779 struct intel_encoder *intel_encoder = to_intel_encoder(encoder); 3771 struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
@@ -7277,7 +7269,6 @@ free_work:
7277static struct drm_crtc_helper_funcs intel_helper_funcs = { 7269static struct drm_crtc_helper_funcs intel_helper_funcs = {
7278 .mode_set_base_atomic = intel_pipe_set_base_atomic, 7270 .mode_set_base_atomic = intel_pipe_set_base_atomic,
7279 .load_lut = intel_crtc_load_lut, 7271 .load_lut = intel_crtc_load_lut,
7280 .disable = intel_crtc_noop,
7281}; 7272};
7282 7273
7283bool intel_encoder_check_is_cloned(struct intel_encoder *encoder) 7274bool intel_encoder_check_is_cloned(struct intel_encoder *encoder)
@@ -7987,14 +7978,9 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
7987 BUG_ON(!set->crtc); 7978 BUG_ON(!set->crtc);
7988 BUG_ON(!set->crtc->helper_private); 7979 BUG_ON(!set->crtc->helper_private);
7989 7980
7990 if (!set->mode) 7981 /* Enforce sane interface api - has been abused by the fb helper. */
7991 set->fb = NULL; 7982 BUG_ON(!set->mode && set->fb);
7992 7983 BUG_ON(set->fb && set->num_connectors == 0);
7993 /* The fb helper likes to play gross jokes with ->mode_set_config.
7994 * Unfortunately the crtc helper doesn't do much at all for this case,
7995 * so we have to cope with this madness until the fb helper is fixed up. */
7996 if (set->fb && set->num_connectors == 0)
7997 return 0;
7998 7984
7999 if (set->fb) { 7985 if (set->fb) {
8000 DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", 7986 DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 56e408b2e3c8..13c1536a8bb2 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2561,7 +2561,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
2561static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { 2561static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
2562 .mode_fixup = intel_dp_mode_fixup, 2562 .mode_fixup = intel_dp_mode_fixup,
2563 .mode_set = intel_dp_mode_set, 2563 .mode_set = intel_dp_mode_set,
2564 .disable = intel_encoder_noop,
2565}; 2564};
2566 2565
2567static const struct drm_connector_funcs intel_dp_connector_funcs = { 2566static const struct drm_connector_funcs intel_dp_connector_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 13afb37d8dec..a2ec01c49f40 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -521,7 +521,6 @@ extern void intel_modeset_disable(struct drm_device *dev);
521extern void intel_crtc_restore_mode(struct drm_crtc *crtc); 521extern void intel_crtc_restore_mode(struct drm_crtc *crtc);
522extern void intel_crtc_load_lut(struct drm_crtc *crtc); 522extern void intel_crtc_load_lut(struct drm_crtc *crtc);
523extern void intel_crtc_update_dpms(struct drm_crtc *crtc); 523extern void intel_crtc_update_dpms(struct drm_crtc *crtc);
524extern void intel_encoder_noop(struct drm_encoder *encoder);
525extern void intel_encoder_destroy(struct drm_encoder *encoder); 524extern void intel_encoder_destroy(struct drm_encoder *encoder);
526extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); 525extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode);
527extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder); 526extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder);
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 15da99533e5b..00e70dbe82da 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -345,7 +345,6 @@ static void intel_dvo_destroy(struct drm_connector *connector)
345static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { 345static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = {
346 .mode_fixup = intel_dvo_mode_fixup, 346 .mode_fixup = intel_dvo_mode_fixup,
347 .mode_set = intel_dvo_mode_set, 347 .mode_set = intel_dvo_mode_set,
348 .disable = intel_encoder_noop,
349}; 348};
350 349
351static const struct drm_connector_funcs intel_dvo_connector_funcs = { 350static const struct drm_connector_funcs intel_dvo_connector_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 1c510da04d16..981bdce3634e 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -57,9 +57,10 @@ static struct fb_ops intelfb_ops = {
57 .fb_debug_leave = drm_fb_helper_debug_leave, 57 .fb_debug_leave = drm_fb_helper_debug_leave,
58}; 58};
59 59
60static int intelfb_create(struct intel_fbdev *ifbdev, 60static int intelfb_create(struct drm_fb_helper *helper,
61 struct drm_fb_helper_surface_size *sizes) 61 struct drm_fb_helper_surface_size *sizes)
62{ 62{
63 struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
63 struct drm_device *dev = ifbdev->helper.dev; 64 struct drm_device *dev = ifbdev->helper.dev;
64 struct drm_i915_private *dev_priv = dev->dev_private; 65 struct drm_i915_private *dev_priv = dev->dev_private;
65 struct fb_info *info; 66 struct fb_info *info;
@@ -181,26 +182,10 @@ out:
181 return ret; 182 return ret;
182} 183}
183 184
184static int intel_fb_find_or_create_single(struct drm_fb_helper *helper,
185 struct drm_fb_helper_surface_size *sizes)
186{
187 struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
188 int new_fb = 0;
189 int ret;
190
191 if (!helper->fb) {
192 ret = intelfb_create(ifbdev, sizes);
193 if (ret)
194 return ret;
195 new_fb = 1;
196 }
197 return new_fb;
198}
199
200static struct drm_fb_helper_funcs intel_fb_helper_funcs = { 185static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
201 .gamma_set = intel_crtc_fb_gamma_set, 186 .gamma_set = intel_crtc_fb_gamma_set,
202 .gamma_get = intel_crtc_fb_gamma_get, 187 .gamma_get = intel_crtc_fb_gamma_get,
203 .fb_probe = intel_fb_find_or_create_single, 188 .fb_probe = intelfb_create,
204}; 189};
205 190
206static void intel_fbdev_destroy(struct drm_device *dev, 191static void intel_fbdev_destroy(struct drm_device *dev,
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 5b4efd64c2f9..3883bed80faa 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -972,7 +972,6 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
972static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { 972static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
973 .mode_fixup = intel_hdmi_mode_fixup, 973 .mode_fixup = intel_hdmi_mode_fixup,
974 .mode_set = intel_hdmi_mode_set, 974 .mode_set = intel_hdmi_mode_set,
975 .disable = intel_encoder_noop,
976}; 975};
977 976
978static const struct drm_connector_funcs intel_hdmi_connector_funcs = { 977static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 5e3f08e3fd8b..feb43fd7debf 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -656,7 +656,6 @@ static int intel_lvds_set_property(struct drm_connector *connector,
656static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { 656static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
657 .mode_fixup = intel_lvds_mode_fixup, 657 .mode_fixup = intel_lvds_mode_fixup,
658 .mode_set = intel_lvds_mode_set, 658 .mode_set = intel_lvds_mode_set,
659 .disable = intel_encoder_noop,
660}; 659};
661 660
662static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { 661static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index f01063a2323a..33b46d9694ea 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2043,7 +2043,6 @@ done:
2043static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { 2043static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
2044 .mode_fixup = intel_sdvo_mode_fixup, 2044 .mode_fixup = intel_sdvo_mode_fixup,
2045 .mode_set = intel_sdvo_mode_set, 2045 .mode_set = intel_sdvo_mode_set,
2046 .disable = intel_encoder_noop,
2047}; 2046};
2048 2047
2049static const struct drm_connector_funcs intel_sdvo_connector_funcs = { 2048static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 984a113c5d13..d808421c1c80 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1487,7 +1487,6 @@ out:
1487static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { 1487static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
1488 .mode_fixup = intel_tv_mode_fixup, 1488 .mode_fixup = intel_tv_mode_fixup,
1489 .mode_set = intel_tv_mode_set, 1489 .mode_set = intel_tv_mode_set,
1490 .disable = intel_encoder_noop,
1491}; 1490};
1492 1491
1493static const struct drm_connector_funcs intel_tv_connector_funcs = { 1492static const struct drm_connector_funcs intel_tv_connector_funcs = {
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c
index 5c69b432f99a..d2253f639481 100644
--- a/drivers/gpu/drm/mgag200/mgag200_fb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -13,6 +13,7 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <drm/drmP.h> 14#include <drm/drmP.h>
15#include <drm/drm_fb_helper.h> 15#include <drm/drm_fb_helper.h>
16#include <drm/drm_crtc_helper.h>
16 17
17#include <linux/fb.h> 18#include <linux/fb.h>
18 19
@@ -120,9 +121,10 @@ static int mgag200fb_create_object(struct mga_fbdev *afbdev,
120 return ret; 121 return ret;
121} 122}
122 123
123static int mgag200fb_create(struct mga_fbdev *mfbdev, 124static int mgag200fb_create(struct drm_fb_helper *helper,
124 struct drm_fb_helper_surface_size *sizes) 125 struct drm_fb_helper_surface_size *sizes)
125{ 126{
127 struct mga_fbdev *mfbdev = (struct mga_fbdev *)helper;
126 struct drm_device *dev = mfbdev->helper.dev; 128 struct drm_device *dev = mfbdev->helper.dev;
127 struct drm_mode_fb_cmd2 mode_cmd; 129 struct drm_mode_fb_cmd2 mode_cmd;
128 struct mga_device *mdev = dev->dev_private; 130 struct mga_device *mdev = dev->dev_private;
@@ -209,23 +211,6 @@ out:
209 return ret; 211 return ret;
210} 212}
211 213
212static int mga_fb_find_or_create_single(struct drm_fb_helper *helper,
213 struct drm_fb_helper_surface_size
214 *sizes)
215{
216 struct mga_fbdev *mfbdev = (struct mga_fbdev *)helper;
217 int new_fb = 0;
218 int ret;
219
220 if (!helper->fb) {
221 ret = mgag200fb_create(mfbdev, sizes);
222 if (ret)
223 return ret;
224 new_fb = 1;
225 }
226 return new_fb;
227}
228
229static int mga_fbdev_destroy(struct drm_device *dev, 214static int mga_fbdev_destroy(struct drm_device *dev,
230 struct mga_fbdev *mfbdev) 215 struct mga_fbdev *mfbdev)
231{ 216{
@@ -256,7 +241,7 @@ static int mga_fbdev_destroy(struct drm_device *dev,
256static struct drm_fb_helper_funcs mga_fb_helper_funcs = { 241static struct drm_fb_helper_funcs mga_fb_helper_funcs = {
257 .gamma_set = mga_crtc_fb_gamma_set, 242 .gamma_set = mga_crtc_fb_gamma_set,
258 .gamma_get = mga_crtc_fb_gamma_get, 243 .gamma_get = mga_crtc_fb_gamma_get,
259 .fb_probe = mga_fb_find_or_create_single, 244 .fb_probe = mgag200fb_create,
260}; 245};
261 246
262int mgag200_fbdev_init(struct mga_device *mdev) 247int mgag200_fbdev_init(struct mga_device *mdev)
@@ -278,6 +263,10 @@ int mgag200_fbdev_init(struct mga_device *mdev)
278 return ret; 263 return ret;
279 } 264 }
280 drm_fb_helper_single_add_all_connectors(&mfbdev->helper); 265 drm_fb_helper_single_add_all_connectors(&mfbdev->helper);
266
267 /* disable all the possible outputs/crtcs before entering KMS mode */
268 drm_helper_disable_unused_functions(mdev->dev);
269
281 drm_fb_helper_initial_config(&mfbdev->helper, 32); 270 drm_fb_helper_initial_config(&mfbdev->helper, 32);
282 271
283 return 0; 272 return 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index d4ecb4deb484..b03531781580 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -251,9 +251,10 @@ nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon)
251} 251}
252 252
253static int 253static int
254nouveau_fbcon_create(struct nouveau_fbdev *fbcon, 254nouveau_fbcon_create(struct drm_fb_helper *helper,
255 struct drm_fb_helper_surface_size *sizes) 255 struct drm_fb_helper_surface_size *sizes)
256{ 256{
257 struct nouveau_fbdev *fbcon = (struct nouveau_fbdev *)helper;
257 struct drm_device *dev = fbcon->dev; 258 struct drm_device *dev = fbcon->dev;
258 struct nouveau_drm *drm = nouveau_drm(dev); 259 struct nouveau_drm *drm = nouveau_drm(dev);
259 struct nouveau_device *device = nv_device(drm->device); 260 struct nouveau_device *device = nv_device(drm->device);
@@ -388,23 +389,6 @@ out:
388 return ret; 389 return ret;
389} 390}
390 391
391static int
392nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper,
393 struct drm_fb_helper_surface_size *sizes)
394{
395 struct nouveau_fbdev *fbcon = (struct nouveau_fbdev *)helper;
396 int new_fb = 0;
397 int ret;
398
399 if (!helper->fb) {
400 ret = nouveau_fbcon_create(fbcon, sizes);
401 if (ret)
402 return ret;
403 new_fb = 1;
404 }
405 return new_fb;
406}
407
408void 392void
409nouveau_fbcon_output_poll_changed(struct drm_device *dev) 393nouveau_fbcon_output_poll_changed(struct drm_device *dev)
410{ 394{
@@ -450,7 +434,7 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info)
450static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { 434static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
451 .gamma_set = nouveau_fbcon_gamma_set, 435 .gamma_set = nouveau_fbcon_gamma_set,
452 .gamma_get = nouveau_fbcon_gamma_get, 436 .gamma_get = nouveau_fbcon_gamma_get,
453 .fb_probe = nouveau_fbcon_find_or_create_single, 437 .fb_probe = nouveau_fbcon_create,
454}; 438};
455 439
456 440
@@ -491,6 +475,9 @@ nouveau_fbcon_init(struct drm_device *dev)
491 else 475 else
492 preferred_bpp = 32; 476 preferred_bpp = 32;
493 477
478 /* disable all the possible outputs/crtcs before entering KMS mode */
479 drm_helper_disable_unused_functions(dev);
480
494 drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp); 481 drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp);
495 return 0; 482 return 0;
496} 483}
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 515e5ee1f9ee..b1746741bc59 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -187,9 +187,10 @@ out_unref:
187 return ret; 187 return ret;
188} 188}
189 189
190static int radeonfb_create(struct radeon_fbdev *rfbdev, 190static int radeonfb_create(struct drm_fb_helper *helper,
191 struct drm_fb_helper_surface_size *sizes) 191 struct drm_fb_helper_surface_size *sizes)
192{ 192{
193 struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper;
193 struct radeon_device *rdev = rfbdev->rdev; 194 struct radeon_device *rdev = rfbdev->rdev;
194 struct fb_info *info; 195 struct fb_info *info;
195 struct drm_framebuffer *fb = NULL; 196 struct drm_framebuffer *fb = NULL;
@@ -300,22 +301,6 @@ out_unref:
300 return ret; 301 return ret;
301} 302}
302 303
303static int radeon_fb_find_or_create_single(struct drm_fb_helper *helper,
304 struct drm_fb_helper_surface_size *sizes)
305{
306 struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper;
307 int new_fb = 0;
308 int ret;
309
310 if (!helper->fb) {
311 ret = radeonfb_create(rfbdev, sizes);
312 if (ret)
313 return ret;
314 new_fb = 1;
315 }
316 return new_fb;
317}
318
319void radeon_fb_output_poll_changed(struct radeon_device *rdev) 304void radeon_fb_output_poll_changed(struct radeon_device *rdev)
320{ 305{
321 drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper); 306 drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper);
@@ -349,7 +334,7 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb
349static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { 334static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
350 .gamma_set = radeon_crtc_fb_gamma_set, 335 .gamma_set = radeon_crtc_fb_gamma_set,
351 .gamma_get = radeon_crtc_fb_gamma_get, 336 .gamma_get = radeon_crtc_fb_gamma_get,
352 .fb_probe = radeon_fb_find_or_create_single, 337 .fb_probe = radeonfb_create,
353}; 338};
354 339
355int radeon_fbdev_init(struct radeon_device *rdev) 340int radeon_fbdev_init(struct radeon_device *rdev)
@@ -379,6 +364,10 @@ int radeon_fbdev_init(struct radeon_device *rdev)
379 } 364 }
380 365
381 drm_fb_helper_single_add_all_connectors(&rfbdev->helper); 366 drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
367
368 /* disable all the possible outputs/crtcs before entering KMS mode */
369 drm_helper_disable_unused_functions(rdev->ddev);
370
382 drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); 371 drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
383 return 0; 372 return 0;
384} 373}
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index 97993c6835fd..03914953cb1c 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -39,10 +39,6 @@ int tegra_drm_fb_init(struct drm_device *drm)
39 if (IS_ERR(fbdev)) 39 if (IS_ERR(fbdev))
40 return PTR_ERR(fbdev); 40 return PTR_ERR(fbdev);
41 41
42#ifndef CONFIG_FRAMEBUFFER_CONSOLE
43 drm_fbdev_cma_restore_mode(fbdev);
44#endif
45
46 host1x->fbdev = fbdev; 42 host1x->fbdev = fbdev;
47 43
48 return 0; 44 return 0;
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index b9feec9d08d3..9f4be3d4a02e 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -476,9 +476,10 @@ udl_framebuffer_init(struct drm_device *dev,
476} 476}
477 477
478 478
479static int udlfb_create(struct udl_fbdev *ufbdev, 479static int udlfb_create(struct drm_fb_helper *helper,
480 struct drm_fb_helper_surface_size *sizes) 480 struct drm_fb_helper_surface_size *sizes)
481{ 481{
482 struct udl_fbdev *ufbdev = (struct udl_fbdev *)helper;
482 struct drm_device *dev = ufbdev->helper.dev; 483 struct drm_device *dev = ufbdev->helper.dev;
483 struct fb_info *info; 484 struct fb_info *info;
484 struct device *device = &dev->usbdev->dev; 485 struct device *device = &dev->usbdev->dev;
@@ -556,27 +557,10 @@ out:
556 return ret; 557 return ret;
557} 558}
558 559
559static int udl_fb_find_or_create_single(struct drm_fb_helper *helper,
560 struct drm_fb_helper_surface_size *sizes)
561{
562 struct udl_fbdev *ufbdev = (struct udl_fbdev *)helper;
563 int new_fb = 0;
564 int ret;
565
566 if (!helper->fb) {
567 ret = udlfb_create(ufbdev, sizes);
568 if (ret)
569 return ret;
570
571 new_fb = 1;
572 }
573 return new_fb;
574}
575
576static struct drm_fb_helper_funcs udl_fb_helper_funcs = { 560static struct drm_fb_helper_funcs udl_fb_helper_funcs = {
577 .gamma_set = udl_crtc_fb_gamma_set, 561 .gamma_set = udl_crtc_fb_gamma_set,
578 .gamma_get = udl_crtc_fb_gamma_get, 562 .gamma_get = udl_crtc_fb_gamma_get,
579 .fb_probe = udl_fb_find_or_create_single, 563 .fb_probe = udlfb_create,
580}; 564};
581 565
582static void udl_fbdev_destroy(struct drm_device *dev, 566static void udl_fbdev_destroy(struct drm_device *dev,
@@ -619,6 +603,10 @@ int udl_fbdev_init(struct drm_device *dev)
619 } 603 }
620 604
621 drm_fb_helper_single_add_all_connectors(&ufbdev->helper); 605 drm_fb_helper_single_add_all_connectors(&ufbdev->helper);
606
607 /* disable all the possible outputs/crtcs before entering KMS mode */
608 drm_helper_disable_unused_functions(dev);
609
622 drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel); 610 drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel);
623 return 0; 611 return 0;
624} 612}
diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c
index 2728e37e02be..caefdf9430f8 100644
--- a/drivers/staging/omapdrm/omap_fbdev.c
+++ b/drivers/staging/omapdrm/omap_fbdev.c
@@ -296,25 +296,10 @@ static void omap_crtc_fb_gamma_get(struct drm_crtc *crtc,
296 DBG("fbdev: get gamma"); 296 DBG("fbdev: get gamma");
297} 297}
298 298
299static int omap_fbdev_probe(struct drm_fb_helper *helper,
300 struct drm_fb_helper_surface_size *sizes)
301{
302 int new_fb = 0;
303 int ret;
304
305 if (!helper->fb) {
306 ret = omap_fbdev_create(helper, sizes);
307 if (ret)
308 return ret;
309 new_fb = 1;
310 }
311 return new_fb;
312}
313
314static struct drm_fb_helper_funcs omap_fb_helper_funcs = { 299static struct drm_fb_helper_funcs omap_fb_helper_funcs = {
315 .gamma_set = omap_crtc_fb_gamma_set, 300 .gamma_set = omap_crtc_fb_gamma_set,
316 .gamma_get = omap_crtc_fb_gamma_get, 301 .gamma_get = omap_crtc_fb_gamma_get,
317 .fb_probe = omap_fbdev_probe, 302 .fb_probe = omap_fbdev_create,
318}; 303};
319 304
320static struct drm_fb_helper *get_fb(struct fb_info *fbi) 305static struct drm_fb_helper *get_fb(struct fb_info *fbi)
@@ -369,6 +354,10 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev)
369 } 354 }
370 355
371 drm_fb_helper_single_add_all_connectors(helper); 356 drm_fb_helper_single_add_all_connectors(helper);
357
358 /* disable all the possible outputs/crtcs before entering KMS mode */
359 drm_helper_disable_unused_functions(dev);
360
372 drm_fb_helper_initial_config(helper, 32); 361 drm_fb_helper_initial_config(helper, 32);
373 362
374 priv->fbdev = helper; 363 priv->fbdev = helper;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index e90c8dcc028d..8b7762728639 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -867,6 +867,7 @@ struct drm_prop_enum_list {
867 867
868extern void drm_modeset_lock_all(struct drm_device *dev); 868extern void drm_modeset_lock_all(struct drm_device *dev);
869extern void drm_modeset_unlock_all(struct drm_device *dev); 869extern void drm_modeset_unlock_all(struct drm_device *dev);
870extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
870 871
871extern int drm_crtc_init(struct drm_device *dev, 872extern int drm_crtc_init(struct drm_device *dev,
872 struct drm_crtc *crtc, 873 struct drm_crtc *crtc,
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 5120b01c2eeb..c09511625a11 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -48,6 +48,18 @@ struct drm_fb_helper_surface_size {
48 u32 surface_depth; 48 u32 surface_depth;
49}; 49};
50 50
51/**
52 * struct drm_fb_helper_funcs - driver callbacks for the fbdev emulation library
53 * @gamma_set: - Set the given gamma lut register on the given crtc.
54 * @gamma_get: - Read the given gamma lut register on the given crtc, used to
55 * save the current lut when force-restoring the fbdev for e.g.
56 * kdbg.
57 * @fb_probe: - Driver callback to allocate and initialize the fbdev info
58 * structure. Futhermore it also needs to allocate the drm
59 * framebuffer used to back the fbdev.
60 *
61 * Driver callbacks used by the fbdev emulation helper library.
62 */
51struct drm_fb_helper_funcs { 63struct drm_fb_helper_funcs {
52 void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green, 64 void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
53 u16 blue, int regno); 65 u16 blue, int regno);
@@ -65,9 +77,7 @@ struct drm_fb_helper_connector {
65 77
66struct drm_fb_helper { 78struct drm_fb_helper {
67 struct drm_framebuffer *fb; 79 struct drm_framebuffer *fb;
68 struct drm_framebuffer *saved_fb;
69 struct drm_device *dev; 80 struct drm_device *dev;
70 struct drm_display_mode *mode;
71 int crtc_count; 81 int crtc_count;
72 struct drm_fb_helper_crtc *crtc_info; 82 struct drm_fb_helper_crtc *crtc_info;
73 int connector_count; 83 int connector_count;
@@ -82,9 +92,6 @@ struct drm_fb_helper {
82 bool delayed_hotplug; 92 bool delayed_hotplug;
83}; 93};
84 94
85int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper,
86 int preferred_bpp);
87
88int drm_fb_helper_init(struct drm_device *dev, 95int drm_fb_helper_init(struct drm_device *dev,
89 struct drm_fb_helper *helper, int crtc_count, 96 struct drm_fb_helper *helper, int crtc_count,
90 int max_conn); 97 int max_conn);
@@ -103,7 +110,6 @@ int drm_fb_helper_setcolreg(unsigned regno,
103 struct fb_info *info); 110 struct fb_info *info);
104 111
105bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper); 112bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper);
106void drm_fb_helper_restore(void);
107void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, 113void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
108 uint32_t fb_width, uint32_t fb_height); 114 uint32_t fb_width, uint32_t fb_height);
109void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, 115void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,