aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-03-30 01:34:13 -0400
committerDave Airlie <airlied@redhat.com>2010-04-06 20:21:03 -0400
commit386516744ba45d50f42c6999151cc210cb4f96e4 (patch)
tree88e3b6aeb83040a8bd512eb7aad087e6c0fcd556 /drivers/gpu/drm/nouveau
parent643acacf02679befd0f98ac3c5fecb805f1c9548 (diff)
drm/fb: fix fbdev object model + cleanup properly.
The fbdev layer in the kms code should act like a consumer of the kms services and avoid having relying on information being store in the kms core structures in order for it to work. This patch a) removes the info pointer/psuedo palette from the core drm_framebuffer structure and moves it to the fbdev helper layer, it also removes the core drm keeping a list of kernel kms fbdevs. b) migrated all the fb helper functions out of the crtc helper file into the fb helper file. c) pushed the fb probing/hotplug control into the driver d) makes the surface sizes into a structure for ease of passing This changes the intel/radeon/nouveau drivers to use the new helper. Signed-off-by: Dave Airlie <airlied@redhat.com>
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