diff options
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 | ||
45 | static void ast_dirty_update(struct ast_fbdev *afbdev, | 46 | static 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 | ||
148 | static int astfb_create(struct ast_fbdev *afbdev, | 149 | static 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 | ||
251 | static 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 | |||
267 | static struct drm_fb_helper_funcs ast_fb_helper_funcs = { | 253 | static 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 | ||
273 | static void ast_fbdev_destroy(struct drm_device *dev, | 259 | static 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 | ||
123 | static int cirrusfb_create(struct cirrus_fbdev *gfbdev, | 124 | static 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 | ||
222 | static 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 | |||
239 | static int cirrus_fbdev_destroy(struct drm_device *dev, | 224 | static 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, | |||
267 | static struct drm_fb_helper_funcs cirrus_fb_helper_funcs = { | 252 | static 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 | ||
273 | int cirrus_fbdev_init(struct cirrus_device *cdev) | 258 | int 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 | |||
72 | EXPORT_SYMBOL(drm_modeset_unlock_all); | 71 | EXPORT_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 | */ | ||
77 | void 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 | } | ||
86 | EXPORT_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 | ||
278 | static 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 | |||
293 | static struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = { | 278 | static 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 | */ |
390 | void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma) | 378 | void 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 | } |
395 | EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode); | 385 | EXPORT_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 | */ | ||
58 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) | 85 | int 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 | */ | ||
166 | int drm_fb_helper_debug_enter(struct fb_info *info) | 197 | int 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 | */ | ||
211 | int drm_fb_helper_debug_leave(struct fb_info *info) | 246 | int 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 | } |
240 | EXPORT_SYMBOL(drm_fb_helper_debug_leave); | 275 | EXPORT_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 | */ | ||
242 | bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) | 285 | bool 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 | } |
254 | EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode); | 300 | EXPORT_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 | */ | ||
256 | static bool drm_fb_helper_force_kernel_mode(void) | 306 | static 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 | ||
275 | int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed, | 325 | static 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 | } |
288 | EXPORT_SYMBOL(drm_fb_helper_panic); | ||
289 | 338 | ||
290 | static struct notifier_block paniced = { | 339 | static 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 | */ | ||
299 | void 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 | } | ||
306 | EXPORT_SYMBOL(drm_fb_helper_restore); | ||
307 | |||
308 | static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) | 343 | static 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 |
327 | static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) | 362 | static 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 | } |
331 | static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn); | 369 | static 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 | */ | ||
381 | int drm_fb_helper_blank(int blank, struct fb_info *info) | 432 | int 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 | */ | ||
424 | int drm_fb_helper_init(struct drm_device *dev, | 493 | int 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 | */ | ||
552 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) | 626 | int 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 | } |
589 | EXPORT_SYMBOL(drm_fb_helper_setcmap); | 663 | EXPORT_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 | */ | ||
591 | int drm_fb_helper_check_var(struct fb_var_screeninfo *var, | 670 | int 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 | } |
681 | EXPORT_SYMBOL(drm_fb_helper_check_var); | 760 | EXPORT_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 | */ | ||
684 | int drm_fb_helper_set_par(struct fb_info *info) | 770 | int 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 | } |
715 | EXPORT_SYMBOL(drm_fb_helper_set_par); | 799 | EXPORT_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 | */ | ||
717 | int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, | 806 | int 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 | } |
752 | EXPORT_SYMBOL(drm_fb_helper_pan_display); | 841 | EXPORT_SYMBOL(drm_fb_helper_pan_display); |
753 | 842 | ||
754 | int 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 | */ | ||
848 | static 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 | } |
870 | EXPORT_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 | */ | ||
872 | void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, | 981 | void 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 | } |
890 | EXPORT_SYMBOL(drm_fb_helper_fill_fix); | 999 | EXPORT_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 | */ | ||
892 | void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, | 1015 | void 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 | } | ||
1334 | out: | 1470 | out: |
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 | } |
1423 | EXPORT_SYMBOL(drm_fb_helper_hotplug_event); | 1568 | EXPORT_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 | ||
229 | static 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 | |||
257 | static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = { | 229 | static 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 | ||
261 | int exynos_drm_fbdev_init(struct drm_device *dev) | 233 | int 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 | ||
574 | static struct drm_fb_helper_funcs psb_fb_helper_funcs = { | 566 | static 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) | |||
685 | static const struct drm_encoder_helper_funcs crt_encoder_funcs = { | 685 | static 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 | ||
691 | static const struct drm_connector_funcs intel_crt_connector_funcs = { | 690 | static 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 = { | |||
1481 | static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { | 1481 | static 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 | ||
1487 | void intel_ddi_init(struct drm_device *dev, enum port port) | 1486 | void 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 | ||
3721 | static void intel_crtc_noop(struct drm_crtc *crtc) | ||
3722 | { | ||
3723 | } | ||
3724 | |||
3725 | static void intel_crtc_disable(struct drm_crtc *crtc) | 3721 | static 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 | ||
3773 | void intel_encoder_noop(struct drm_encoder *encoder) | ||
3774 | { | ||
3775 | } | ||
3776 | |||
3777 | void intel_encoder_destroy(struct drm_encoder *encoder) | 3769 | void 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: | |||
7277 | static struct drm_crtc_helper_funcs intel_helper_funcs = { | 7269 | static 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 | ||
7283 | bool intel_encoder_check_is_cloned(struct intel_encoder *encoder) | 7274 | bool 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) | |||
2561 | static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { | 2561 | static 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 | ||
2567 | static const struct drm_connector_funcs intel_dp_connector_funcs = { | 2566 | static 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); | |||
521 | extern void intel_crtc_restore_mode(struct drm_crtc *crtc); | 521 | extern void intel_crtc_restore_mode(struct drm_crtc *crtc); |
522 | extern void intel_crtc_load_lut(struct drm_crtc *crtc); | 522 | extern void intel_crtc_load_lut(struct drm_crtc *crtc); |
523 | extern void intel_crtc_update_dpms(struct drm_crtc *crtc); | 523 | extern void intel_crtc_update_dpms(struct drm_crtc *crtc); |
524 | extern void intel_encoder_noop(struct drm_encoder *encoder); | ||
525 | extern void intel_encoder_destroy(struct drm_encoder *encoder); | 524 | extern void intel_encoder_destroy(struct drm_encoder *encoder); |
526 | extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); | 525 | extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); |
527 | extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder); | 526 | extern 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) | |||
345 | static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { | 345 | static 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 | ||
351 | static const struct drm_connector_funcs intel_dvo_connector_funcs = { | 350 | static 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 | ||
60 | static int intelfb_create(struct intel_fbdev *ifbdev, | 60 | static 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 | ||
184 | static 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 | |||
200 | static struct drm_fb_helper_funcs intel_fb_helper_funcs = { | 185 | static 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 | ||
206 | static void intel_fbdev_destroy(struct drm_device *dev, | 191 | static 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) | |||
972 | static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { | 972 | static 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 | ||
978 | static const struct drm_connector_funcs intel_hdmi_connector_funcs = { | 977 | static 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, | |||
656 | static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { | 656 | static 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 | ||
662 | static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { | 661 | static 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: | |||
2043 | static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { | 2043 | static 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 | ||
2049 | static const struct drm_connector_funcs intel_sdvo_connector_funcs = { | 2048 | static 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: | |||
1487 | static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { | 1487 | static 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 | ||
1493 | static const struct drm_connector_funcs intel_tv_connector_funcs = { | 1492 | static 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 | ||
123 | static int mgag200fb_create(struct mga_fbdev *mfbdev, | 124 | static 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 | ||
212 | static 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 | |||
229 | static int mga_fbdev_destroy(struct drm_device *dev, | 214 | static 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, | |||
256 | static struct drm_fb_helper_funcs mga_fb_helper_funcs = { | 241 | static 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 | ||
262 | int mgag200_fbdev_init(struct mga_device *mdev) | 247 | int 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 | ||
253 | static int | 253 | static int |
254 | nouveau_fbcon_create(struct nouveau_fbdev *fbcon, | 254 | nouveau_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 | ||
391 | static int | ||
392 | nouveau_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 | |||
408 | void | 392 | void |
409 | nouveau_fbcon_output_poll_changed(struct drm_device *dev) | 393 | nouveau_fbcon_output_poll_changed(struct drm_device *dev) |
410 | { | 394 | { |
@@ -450,7 +434,7 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info) | |||
450 | static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { | 434 | static 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 | ||
190 | static int radeonfb_create(struct radeon_fbdev *rfbdev, | 190 | static 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 | ||
303 | static 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 | |||
319 | void radeon_fb_output_poll_changed(struct radeon_device *rdev) | 304 | void 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 | |||
349 | static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { | 334 | static 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 | ||
355 | int radeon_fbdev_init(struct radeon_device *rdev) | 340 | int 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 | ||
479 | static int udlfb_create(struct udl_fbdev *ufbdev, | 479 | static 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 | ||
559 | static 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 | |||
576 | static struct drm_fb_helper_funcs udl_fb_helper_funcs = { | 560 | static 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 | ||
582 | static void udl_fbdev_destroy(struct drm_device *dev, | 566 | static 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 | ||
299 | static 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 | |||
314 | static struct drm_fb_helper_funcs omap_fb_helper_funcs = { | 299 | static 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 | ||
320 | static struct drm_fb_helper *get_fb(struct fb_info *fbi) | 305 | static 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 | ||
868 | extern void drm_modeset_lock_all(struct drm_device *dev); | 868 | extern void drm_modeset_lock_all(struct drm_device *dev); |
869 | extern void drm_modeset_unlock_all(struct drm_device *dev); | 869 | extern void drm_modeset_unlock_all(struct drm_device *dev); |
870 | extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); | ||
870 | 871 | ||
871 | extern int drm_crtc_init(struct drm_device *dev, | 872 | extern 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 | */ | ||
51 | struct drm_fb_helper_funcs { | 63 | struct 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 | ||
66 | struct drm_fb_helper { | 78 | struct 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 | ||
85 | int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper, | ||
86 | int preferred_bpp); | ||
87 | |||
88 | int drm_fb_helper_init(struct drm_device *dev, | 95 | int 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 | ||
105 | bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper); | 112 | bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper); |
106 | void drm_fb_helper_restore(void); | ||
107 | void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, | 113 | void 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); |
109 | void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, | 115 | void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, |