aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c41
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c19
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fb.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c149
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.h15
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c5
8 files changed, 147 insertions, 102 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index cf1c5c0a0abe..9d7928f40fdf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -34,10 +34,6 @@ static void
34nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) 34nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
35{ 35{
36 struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); 36 struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
37 struct drm_device *dev = drm_fb->dev;
38
39 if (drm_fb->fbdev)
40 nouveau_fbcon_remove(dev, drm_fb);
41 37
42 if (fb->nvbo) 38 if (fb->nvbo)
43 drm_gem_object_unreference_unlocked(fb->nvbo->gem); 39 drm_gem_object_unreference_unlocked(fb->nvbo->gem);
@@ -61,27 +57,20 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
61 .create_handle = nouveau_user_framebuffer_create_handle, 57 .create_handle = nouveau_user_framebuffer_create_handle,
62}; 58};
63 59
64struct drm_framebuffer * 60int
65nouveau_framebuffer_create(struct drm_device *dev, struct nouveau_bo *nvbo, 61nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb,
66 struct drm_mode_fb_cmd *mode_cmd) 62 struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo)
67{ 63{
68 struct nouveau_framebuffer *fb;
69 int ret; 64 int ret;
70 65
71 fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL); 66 ret = drm_framebuffer_init(dev, &nouveau_fb->base, &nouveau_framebuffer_funcs);
72 if (!fb)
73 return NULL;
74
75 ret = drm_framebuffer_init(dev, &fb->base, &nouveau_framebuffer_funcs);
76 if (ret) { 67 if (ret) {
77 kfree(fb); 68 return ret;
78 return NULL;
79 } 69 }
80 70
81 drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); 71 drm_helper_mode_fill_fb_struct(&nouveau_fb->base, mode_cmd);
82 72 nouveau_fb->nvbo = nvbo;
83 fb->nvbo = nvbo; 73 return 0;
84 return &fb->base;
85} 74}
86 75
87static struct drm_framebuffer * 76static struct drm_framebuffer *
@@ -89,24 +78,28 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
89 struct drm_file *file_priv, 78 struct drm_file *file_priv,
90 struct drm_mode_fb_cmd *mode_cmd) 79 struct drm_mode_fb_cmd *mode_cmd)
91{ 80{
92 struct drm_framebuffer *fb; 81 struct nouveau_framebuffer *nouveau_fb;
93 struct drm_gem_object *gem; 82 struct drm_gem_object *gem;
83 int ret;
94 84
95 gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); 85 gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
96 if (!gem) 86 if (!gem)
97 return NULL; 87 return NULL;
98 88
99 fb = nouveau_framebuffer_create(dev, nouveau_gem_object(gem), mode_cmd); 89 nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
100 if (!fb) { 90 if (!nouveau_fb)
91 return NULL;
92
93 ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
94 if (ret) {
101 drm_gem_object_unreference(gem); 95 drm_gem_object_unreference(gem);
102 return NULL; 96 return NULL;
103 } 97 }
104 98
105 return fb; 99 return &nouveau_fb->base;
106} 100}
107 101
108const struct drm_mode_config_funcs nouveau_mode_config_funcs = { 102const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
109 .fb_create = nouveau_user_framebuffer_create, 103 .fb_create = nouveau_user_framebuffer_create,
110 .fb_changed = nouveau_fbcon_probe,
111}; 104};
112 105
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 1de974acbc65..c6079e36669d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -153,7 +153,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
153 struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; 153 struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
154 struct nouveau_channel *chan; 154 struct nouveau_channel *chan;
155 struct drm_crtc *crtc; 155 struct drm_crtc *crtc;
156 uint32_t fbdev_flags;
157 int ret, i; 156 int ret, i;
158 157
159 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 158 if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -163,8 +162,7 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
163 return 0; 162 return 0;
164 163
165 NV_INFO(dev, "Disabling fbcon acceleration...\n"); 164 NV_INFO(dev, "Disabling fbcon acceleration...\n");
166 fbdev_flags = dev_priv->fbdev_info->flags; 165 nouveau_fbcon_save_disable_accel(dev);
167 dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
168 166
169 NV_INFO(dev, "Unpinning framebuffer(s)...\n"); 167 NV_INFO(dev, "Unpinning framebuffer(s)...\n");
170 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 168 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -230,9 +228,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
230 } 228 }
231 229
232 acquire_console_sem(); 230 acquire_console_sem();
233 fb_set_suspend(dev_priv->fbdev_info, 1); 231 nouveau_fbcon_set_suspend(dev, 1);
234 release_console_sem(); 232 release_console_sem();
235 dev_priv->fbdev_info->flags = fbdev_flags; 233 nouveau_fbcon_restore_accel(dev);
236 return 0; 234 return 0;
237 235
238out_abort: 236out_abort:
@@ -250,14 +248,12 @@ nouveau_pci_resume(struct pci_dev *pdev)
250 struct drm_nouveau_private *dev_priv = dev->dev_private; 248 struct drm_nouveau_private *dev_priv = dev->dev_private;
251 struct nouveau_engine *engine = &dev_priv->engine; 249 struct nouveau_engine *engine = &dev_priv->engine;
252 struct drm_crtc *crtc; 250 struct drm_crtc *crtc;
253 uint32_t fbdev_flags;
254 int ret, i; 251 int ret, i;
255 252
256 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 253 if (!drm_core_check_feature(dev, DRIVER_MODESET))
257 return -ENODEV; 254 return -ENODEV;
258 255
259 fbdev_flags = dev_priv->fbdev_info->flags; 256 nouveau_fbcon_save_disable_accel(dev);
260 dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
261 257
262 NV_INFO(dev, "We're back, enabling device...\n"); 258 NV_INFO(dev, "We're back, enabling device...\n");
263 pci_set_power_state(pdev, PCI_D0); 259 pci_set_power_state(pdev, PCI_D0);
@@ -332,13 +328,14 @@ nouveau_pci_resume(struct pci_dev *pdev)
332 } 328 }
333 329
334 acquire_console_sem(); 330 acquire_console_sem();
335 fb_set_suspend(dev_priv->fbdev_info, 0); 331 nouveau_fbcon_set_suspend(dev, 0);
336 release_console_sem(); 332 release_console_sem();
337 333
338 nouveau_fbcon_zfill(dev); 334 nouveau_fbcon_zfill_all(dev);
339 335
340 drm_helper_resume_force_mode(dev); 336 drm_helper_resume_force_mode(dev);
341 dev_priv->fbdev_info->flags = fbdev_flags; 337
338 nouveau_fbcon_restore_accel(dev);
342 return 0; 339 return 0;
343} 340}
344 341
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index d8b559011777..93459e07e829 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -531,8 +531,6 @@ struct drm_nouveau_private {
531 atomic_t validate_sequence; 531 atomic_t validate_sequence;
532 } ttm; 532 } ttm;
533 533
534 struct fb_info *fbdev_info;
535
536 int fifo_alloc_count; 534 int fifo_alloc_count;
537 struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; 535 struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
538 536
@@ -628,6 +626,8 @@ struct drm_nouveau_private {
628 struct { 626 struct {
629 struct dentry *channel_root; 627 struct dentry *channel_root;
630 } debugfs; 628 } debugfs;
629
630 struct nouveau_fbcon_par *nfbdev;
631}; 631};
632 632
633static inline struct drm_nouveau_private * 633static inline struct drm_nouveau_private *
diff --git a/drivers/gpu/drm/nouveau/nouveau_fb.h b/drivers/gpu/drm/nouveau/nouveau_fb.h
index 4a3f31aa1949..d432134b71e0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fb.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fb.h
@@ -40,8 +40,6 @@ nouveau_framebuffer(struct drm_framebuffer *fb)
40 40
41extern const struct drm_mode_config_funcs nouveau_mode_config_funcs; 41extern const struct drm_mode_config_funcs nouveau_mode_config_funcs;
42 42
43struct drm_framebuffer * 43int nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb,
44nouveau_framebuffer_create(struct drm_device *, struct nouveau_bo *, 44 struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo);
45 struct drm_mode_fb_cmd *);
46
47#endif /* __NOUVEAU_FB_H__ */ 45#endif /* __NOUVEAU_FB_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 68cedd9194fe..712ee42e3cf8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -199,11 +199,10 @@ not_fb:
199} 199}
200#endif 200#endif
201 201
202void 202static void
203nouveau_fbcon_zfill(struct drm_device *dev) 203nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbcon_par *fbpar)
204{ 204{
205 struct drm_nouveau_private *dev_priv = dev->dev_private; 205 struct fb_info *info = fbpar->helper.fbdev;
206 struct fb_info *info = dev_priv->fbdev_info;
207 struct fb_fillrect rect; 206 struct fb_fillrect rect;
208 207
209 /* Clear the entire fbcon. The drm will program every connector 208 /* Clear the entire fbcon. The drm will program every connector
@@ -219,10 +218,9 @@ nouveau_fbcon_zfill(struct drm_device *dev)
219} 218}
220 219
221static int 220static int
222nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, 221nouveau_fbcon_create(struct drm_device *dev,
223 uint32_t fb_height, uint32_t surface_width, 222 struct drm_fb_helper_surface_size *sizes,
224 uint32_t surface_height, uint32_t surface_depth, 223 struct nouveau_fbcon_par **fbpar_p)
225 uint32_t surface_bpp, struct drm_framebuffer **pfb)
226{ 224{
227 struct drm_nouveau_private *dev_priv = dev->dev_private; 225 struct drm_nouveau_private *dev_priv = dev->dev_private;
228 struct fb_info *info; 226 struct fb_info *info;
@@ -234,13 +232,13 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
234 struct device *device = &dev->pdev->dev; 232 struct device *device = &dev->pdev->dev;
235 int size, ret; 233 int size, ret;
236 234
237 mode_cmd.width = surface_width; 235 mode_cmd.width = sizes->surface_width;
238 mode_cmd.height = surface_height; 236 mode_cmd.height = sizes->surface_height;
239 237
240 mode_cmd.bpp = surface_bpp; 238 mode_cmd.bpp = sizes->surface_bpp;
241 mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3); 239 mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3);
242 mode_cmd.pitch = roundup(mode_cmd.pitch, 256); 240 mode_cmd.pitch = roundup(mode_cmd.pitch, 256);
243 mode_cmd.depth = surface_depth; 241 mode_cmd.depth = sizes->surface_depth;
244 242
245 size = mode_cmd.pitch * mode_cmd.height; 243 size = mode_cmd.pitch * mode_cmd.height;
246 size = roundup(size, PAGE_SIZE); 244 size = roundup(size, PAGE_SIZE);
@@ -269,18 +267,6 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
269 267
270 mutex_lock(&dev->struct_mutex); 268 mutex_lock(&dev->struct_mutex);
271 269
272 fb = nouveau_framebuffer_create(dev, nvbo, &mode_cmd);
273 if (!fb) {
274 ret = -ENOMEM;
275 NV_ERROR(dev, "failed to allocate fb.\n");
276 goto out_unref;
277 }
278
279 list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
280
281 nouveau_fb = nouveau_framebuffer(fb);
282 *pfb = fb;
283
284 info = framebuffer_alloc(sizeof(struct nouveau_fbcon_par), device); 270 info = framebuffer_alloc(sizeof(struct nouveau_fbcon_par), device);
285 if (!info) { 271 if (!info) {
286 ret = -ENOMEM; 272 ret = -ENOMEM;
@@ -288,12 +274,20 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
288 } 274 }
289 275
290 par = info->par; 276 par = info->par;
277 nouveau_framebuffer_init(dev, &par->nouveau_fb, &mode_cmd, nvbo);
278
279 fb = &par->nouveau_fb.base;
280 /* setup helper */
281 par->helper.fb = fb;
282 par->helper.fbdev = info;
291 par->helper.funcs = &nouveau_fbcon_helper_funcs; 283 par->helper.funcs = &nouveau_fbcon_helper_funcs;
292 par->helper.dev = dev; 284 par->helper.dev = dev;
285
286 *fbpar_p = par;
287
293 ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 4); 288 ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 4);
294 if (ret) 289 if (ret)
295 goto out_unref; 290 goto out_unref;
296 dev_priv->fbdev_info = info;
297 291
298 strcpy(info->fix.id, "nouveaufb"); 292 strcpy(info->fix.id, "nouveaufb");
299 if (nouveau_nofbaccel) 293 if (nouveau_nofbaccel)
@@ -311,7 +305,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
311 info->screen_size = size; 305 info->screen_size = size;
312 306
313 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); 307 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
314 drm_fb_helper_fill_var(info, fb, fb_width, fb_height); 308 drm_fb_helper_fill_var(info, &par->helper, sizes->fb_width, sizes->fb_height);
315 309
316 /* FIXME: we really shouldn't expose mmio space at all */ 310 /* FIXME: we really shouldn't expose mmio space at all */
317 info->fix.mmio_start = pci_resource_start(dev->pdev, 1); 311 info->fix.mmio_start = pci_resource_start(dev->pdev, 1);
@@ -344,9 +338,6 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
344 info->pixmap.flags = FB_PIXMAP_SYSTEM; 338 info->pixmap.flags = FB_PIXMAP_SYSTEM;
345 info->pixmap.scan_align = 1; 339 info->pixmap.scan_align = 1;
346 340
347 fb->fbdev = info;
348
349 par->nouveau_fb = nouveau_fb;
350 par->dev = dev; 341 par->dev = dev;
351 342
352 if (dev_priv->channel && !nouveau_nofbaccel) { 343 if (dev_priv->channel && !nouveau_nofbaccel) {
@@ -362,7 +353,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
362 }; 353 };
363 } 354 }
364 355
365 nouveau_fbcon_zfill(dev); 356 nouveau_fbcon_zfill(dev, par);
366 357
367 /* To allow resizeing without swapping buffers */ 358 /* To allow resizeing without swapping buffers */
368 NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n", 359 NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n",
@@ -380,35 +371,59 @@ out:
380 return ret; 371 return ret;
381} 372}
382 373
383int 374static int
375nouveau_fbcon_find_or_create_single(struct drm_device *dev,
376 struct drm_fb_helper_surface_size *sizes,
377 struct drm_fb_helper **fb_ptr)
378{
379 struct drm_nouveau_private *dev_priv = dev->dev_private;
380 struct nouveau_fbcon_par *fbpar;
381 int new_fb = 0;
382 int ret;
383
384 if (!dev_priv->nfbdev) {
385 ret = nouveau_fbcon_create(dev, sizes,
386 &fbpar);
387 if (ret)
388 return ret;
389 dev_priv->nfbdev = fbpar;
390 new_fb = 1;
391 } else {
392 fbpar = dev_priv->nfbdev;
393 if (fbpar->nouveau_fb.base.width < sizes->surface_width ||
394 fbpar->nouveau_fb.base.height < sizes->surface_height) {
395 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
396 return -EINVAL;
397 }
398 }
399 *fb_ptr = &fbpar->helper;
400 return new_fb;
401}
402
403static int
384nouveau_fbcon_probe(struct drm_device *dev) 404nouveau_fbcon_probe(struct drm_device *dev)
385{ 405{
386 NV_DEBUG_KMS(dev, "\n"); 406 NV_DEBUG_KMS(dev, "\n");
387 407
388 return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_create); 408 return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_find_or_create_single);
389} 409}
390 410
391int 411int
392nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb) 412nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbcon_par *fbpar)
393{ 413{
394 struct nouveau_framebuffer *nouveau_fb = nouveau_framebuffer(fb); 414 struct nouveau_framebuffer *nouveau_fb = &fbpar->nouveau_fb;
395 struct fb_info *info; 415 struct fb_info *info;
396 416
397 if (!fb) 417 info = fbpar->helper.fbdev;
398 return -EINVAL;
399 418
400 info = fb->fbdev; 419 unregister_framebuffer(info);
401 if (info) { 420 nouveau_bo_unmap(nouveau_fb->nvbo);
402 struct nouveau_fbcon_par *par = info->par; 421 drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
422 nouveau_fb->nvbo = NULL;
423 drm_fb_helper_free(&fbpar->helper);
403 424
404 unregister_framebuffer(info); 425 drm_framebuffer_cleanup(&nouveau_fb->base);
405 nouveau_bo_unmap(nouveau_fb->nvbo); 426 framebuffer_release(info);
406 drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
407 nouveau_fb->nvbo = NULL;
408 if (par)
409 drm_fb_helper_free(&par->helper);
410 framebuffer_release(info);
411 }
412 427
413 return 0; 428 return 0;
414} 429}
@@ -421,3 +436,43 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info)
421 NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); 436 NV_ERROR(dev, "GPU lockup - switching to software fbcon\n");
422 info->flags |= FBINFO_HWACCEL_DISABLED; 437 info->flags |= FBINFO_HWACCEL_DISABLED;
423} 438}
439
440int nouveau_fbcon_init(struct drm_device *dev)
441{
442 drm_helper_initial_config(dev);
443 nouveau_fbcon_probe(dev);
444 return 0;
445}
446
447void nouveau_fbcon_fini(struct drm_device *dev)
448{
449 struct drm_nouveau_private *dev_priv = dev->dev_private;
450 nouveau_fbcon_destroy(dev, dev_priv->nfbdev);
451 dev_priv->nfbdev = NULL;
452}
453
454void nouveau_fbcon_save_disable_accel(struct drm_device *dev)
455{
456 struct drm_nouveau_private *dev_priv = dev->dev_private;
457
458 dev_priv->nfbdev->saved_flags = dev_priv->nfbdev->helper.fbdev->flags;
459 dev_priv->nfbdev->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
460}
461
462void nouveau_fbcon_restore_accel(struct drm_device *dev)
463{
464 struct drm_nouveau_private *dev_priv = dev->dev_private;
465 dev_priv->nfbdev->helper.fbdev->flags = dev_priv->nfbdev->saved_flags;
466}
467
468void nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
469{
470 struct drm_nouveau_private *dev_priv = dev->dev_private;
471 fb_set_suspend(dev_priv->nfbdev->helper.fbdev, state);
472}
473
474void nouveau_fbcon_zfill_all(struct drm_device *dev)
475{
476 struct drm_nouveau_private *dev_priv = dev->dev_private;
477 nouveau_fbcon_zfill(dev, dev_priv->nfbdev);
478}
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index f9c34e1a8c11..fa66cb9fa4d4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -29,16 +29,16 @@
29 29
30#include "drm_fb_helper.h" 30#include "drm_fb_helper.h"
31 31
32#include "nouveau_fb.h"
32struct nouveau_fbcon_par { 33struct nouveau_fbcon_par {
33 struct drm_fb_helper helper; 34 struct drm_fb_helper helper;
35 struct nouveau_framebuffer nouveau_fb;
36 struct list_head fbdev_list;
34 struct drm_device *dev; 37 struct drm_device *dev;
35 struct nouveau_framebuffer *nouveau_fb; 38 unsigned int saved_flags;
36}; 39};
37 40
38int nouveau_fbcon_probe(struct drm_device *dev);
39int nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb);
40void nouveau_fbcon_restore(void); 41void nouveau_fbcon_restore(void);
41void nouveau_fbcon_zfill(struct drm_device *dev);
42 42
43void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); 43void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
44void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); 44void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
@@ -50,5 +50,12 @@ void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
50int nv50_fbcon_accel_init(struct fb_info *info); 50int nv50_fbcon_accel_init(struct fb_info *info);
51 51
52void nouveau_fbcon_gpu_lockup(struct fb_info *info); 52void nouveau_fbcon_gpu_lockup(struct fb_info *info);
53
54int nouveau_fbcon_init(struct drm_device *dev);
55void nouveau_fbcon_fini(struct drm_device *dev);
56void nouveau_fbcon_set_suspend(struct drm_device *dev, int state);
57void nouveau_fbcon_zfill_all(struct drm_device *dev);
58void nouveau_fbcon_save_disable_accel(struct drm_device *dev);
59void nouveau_fbcon_restore_accel(struct drm_device *dev);
53#endif /* __NV50_FBCON_H__ */ 60#endif /* __NV50_FBCON_H__ */
54 61
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 2bd59a92fee5..0aa08b3be375 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -1203,7 +1203,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
1203{ 1203{
1204 struct drm_device *dev = (struct drm_device *)arg; 1204 struct drm_device *dev = (struct drm_device *)arg;
1205 struct drm_nouveau_private *dev_priv = dev->dev_private; 1205 struct drm_nouveau_private *dev_priv = dev->dev_private;
1206 uint32_t status, fbdev_flags = 0; 1206 uint32_t status;
1207 unsigned long flags; 1207 unsigned long flags;
1208 1208
1209 status = nv_rd32(dev, NV03_PMC_INTR_0); 1209 status = nv_rd32(dev, NV03_PMC_INTR_0);
@@ -1212,11 +1212,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
1212 1212
1213 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 1213 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
1214 1214
1215 if (dev_priv->fbdev_info) {
1216 fbdev_flags = dev_priv->fbdev_info->flags;
1217 dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
1218 }
1219
1220 if (status & NV_PMC_INTR_0_PFIFO_PENDING) { 1215 if (status & NV_PMC_INTR_0_PFIFO_PENDING) {
1221 nouveau_fifo_irq_handler(dev); 1216 nouveau_fifo_irq_handler(dev);
1222 status &= ~NV_PMC_INTR_0_PFIFO_PENDING; 1217 status &= ~NV_PMC_INTR_0_PFIFO_PENDING;
@@ -1246,9 +1241,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
1246 if (status) 1241 if (status)
1247 NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status); 1242 NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status);
1248 1243
1249 if (dev_priv->fbdev_info)
1250 dev_priv->fbdev_info->flags = fbdev_flags;
1251
1252 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 1244 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
1253 1245
1254 return IRQ_HANDLED; 1246 return IRQ_HANDLED;
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 58b46807de23..23e67bf0898c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -33,6 +33,7 @@
33 33
34#include "nouveau_drv.h" 34#include "nouveau_drv.h"
35#include "nouveau_drm.h" 35#include "nouveau_drm.h"
36#include "nouveau_fbcon.h"
36#include "nv50_display.h" 37#include "nv50_display.h"
37 38
38static void nouveau_stub_takedown(struct drm_device *dev) {} 39static void nouveau_stub_takedown(struct drm_device *dev) {}
@@ -511,7 +512,7 @@ nouveau_card_init(struct drm_device *dev)
511 dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; 512 dev_priv->init_state = NOUVEAU_CARD_INIT_DONE;
512 513
513 if (drm_core_check_feature(dev, DRIVER_MODESET)) 514 if (drm_core_check_feature(dev, DRIVER_MODESET))
514 drm_helper_initial_config(dev); 515 nouveau_fbcon_init(dev);
515 516
516 return 0; 517 return 0;
517 518
@@ -552,6 +553,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
552 NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state); 553 NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
553 554
554 if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) { 555 if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) {
556
555 nouveau_backlight_exit(dev); 557 nouveau_backlight_exit(dev);
556 558
557 if (dev_priv->channel) { 559 if (dev_priv->channel) {
@@ -783,6 +785,7 @@ int nouveau_unload(struct drm_device *dev)
783 struct drm_nouveau_private *dev_priv = dev->dev_private; 785 struct drm_nouveau_private *dev_priv = dev->dev_private;
784 786
785 if (drm_core_check_feature(dev, DRIVER_MODESET)) { 787 if (drm_core_check_feature(dev, DRIVER_MODESET)) {
788 nouveau_fbcon_fini(dev);
786 if (dev_priv->card_type >= NV_50) 789 if (dev_priv->card_type >= NV_50)
787 nv50_display_destroy(dev); 790 nv50_display_destroy(dev);
788 else 791 else