diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.c | 19 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fb.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.c | 149 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.h | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_irq.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 5 |
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 cf1c5c0a0ab..9d7928f40fd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -34,10 +34,6 @@ static void | |||
34 | nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) | 34 | nouveau_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 | ||
64 | struct drm_framebuffer * | 60 | int |
65 | nouveau_framebuffer_create(struct drm_device *dev, struct nouveau_bo *nvbo, | 61 | nouveau_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 | ||
87 | static struct drm_framebuffer * | 76 | static 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 | ||
108 | const struct drm_mode_config_funcs nouveau_mode_config_funcs = { | 102 | const 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 1de974acbc6..c6079e36669 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 | ||
238 | out_abort: | 236 | out_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 d8b55901177..93459e07e82 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 | ||
633 | static inline struct drm_nouveau_private * | 633 | static inline struct drm_nouveau_private * |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fb.h b/drivers/gpu/drm/nouveau/nouveau_fb.h index 4a3f31aa194..d432134b71e 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 | ||
41 | extern const struct drm_mode_config_funcs nouveau_mode_config_funcs; | 41 | extern const struct drm_mode_config_funcs nouveau_mode_config_funcs; |
42 | 42 | ||
43 | struct drm_framebuffer * | 43 | int nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb, |
44 | nouveau_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 68cedd9194f..712ee42e3cf 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 | ||
202 | void | 202 | static void |
203 | nouveau_fbcon_zfill(struct drm_device *dev) | 203 | nouveau_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 | ||
221 | static int | 220 | static int |
222 | nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, | 221 | nouveau_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 | ||
383 | int | 374 | static int |
375 | nouveau_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 | |||
403 | static int | ||
384 | nouveau_fbcon_probe(struct drm_device *dev) | 404 | nouveau_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 | ||
391 | int | 411 | int |
392 | nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb) | 412 | nouveau_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 | |||
440 | int nouveau_fbcon_init(struct drm_device *dev) | ||
441 | { | ||
442 | drm_helper_initial_config(dev); | ||
443 | nouveau_fbcon_probe(dev); | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | void 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 | |||
454 | void 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 | |||
462 | void 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 | |||
468 | void 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 | |||
474 | void 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 f9c34e1a8c1..fa66cb9fa4d 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" | ||
32 | struct nouveau_fbcon_par { | 33 | struct 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 | ||
38 | int nouveau_fbcon_probe(struct drm_device *dev); | ||
39 | int nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb); | ||
40 | void nouveau_fbcon_restore(void); | 41 | void nouveau_fbcon_restore(void); |
41 | void nouveau_fbcon_zfill(struct drm_device *dev); | ||
42 | 42 | ||
43 | void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); | 43 | void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); |
44 | void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); | 44 | void 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); | |||
50 | int nv50_fbcon_accel_init(struct fb_info *info); | 50 | int nv50_fbcon_accel_init(struct fb_info *info); |
51 | 51 | ||
52 | void nouveau_fbcon_gpu_lockup(struct fb_info *info); | 52 | void nouveau_fbcon_gpu_lockup(struct fb_info *info); |
53 | |||
54 | int nouveau_fbcon_init(struct drm_device *dev); | ||
55 | void nouveau_fbcon_fini(struct drm_device *dev); | ||
56 | void nouveau_fbcon_set_suspend(struct drm_device *dev, int state); | ||
57 | void nouveau_fbcon_zfill_all(struct drm_device *dev); | ||
58 | void nouveau_fbcon_save_disable_accel(struct drm_device *dev); | ||
59 | void 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 2bd59a92fee..0aa08b3be37 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 58b46807de2..23e67bf0898 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 | ||
38 | static void nouveau_stub_takedown(struct drm_device *dev) {} | 39 | static 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 |