diff options
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 329 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_fb.c | 93 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.c | 121 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_fbcon.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_fbcon.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_fb.c | 240 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 4 |
11 files changed, 398 insertions, 434 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 9d23f54673d3..b142ac260d97 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -625,10 +625,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
625 | ret = -EINVAL; | 625 | ret = -EINVAL; |
626 | goto fail; | 626 | goto fail; |
627 | } | 627 | } |
628 | /* TODO are these needed? */ | ||
629 | set->crtc->desired_x = set->x; | ||
630 | set->crtc->desired_y = set->y; | ||
631 | set->crtc->desired_mode = set->mode; | ||
632 | } | 628 | } |
633 | drm_helper_disable_unused_functions(dev); | 629 | drm_helper_disable_unused_functions(dev); |
634 | } else if (fb_changed) { | 630 | } else if (fb_changed) { |
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 055b5be78877..2515563063ce 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -292,6 +292,7 @@ static void drm_fb_helper_on(struct fb_info *info) | |||
292 | struct drm_fb_helper *fb_helper = info->par; | 292 | struct drm_fb_helper *fb_helper = info->par; |
293 | struct drm_device *dev = fb_helper->dev; | 293 | struct drm_device *dev = fb_helper->dev; |
294 | struct drm_crtc *crtc; | 294 | struct drm_crtc *crtc; |
295 | struct drm_crtc_helper_funcs *crtc_funcs; | ||
295 | struct drm_encoder *encoder; | 296 | struct drm_encoder *encoder; |
296 | int i; | 297 | int i; |
297 | 298 | ||
@@ -299,33 +300,28 @@ static void drm_fb_helper_on(struct fb_info *info) | |||
299 | * For each CRTC in this fb, turn the crtc on then, | 300 | * For each CRTC in this fb, turn the crtc on then, |
300 | * find all associated encoders and turn them on. | 301 | * find all associated encoders and turn them on. |
301 | */ | 302 | */ |
303 | mutex_lock(&dev->mode_config.mutex); | ||
302 | for (i = 0; i < fb_helper->crtc_count; i++) { | 304 | for (i = 0; i < fb_helper->crtc_count; i++) { |
303 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 305 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
304 | struct drm_crtc_helper_funcs *crtc_funcs = | 306 | crtc_funcs = crtc->helper_private; |
305 | crtc->helper_private; | ||
306 | 307 | ||
307 | /* Only mess with CRTCs in this fb */ | 308 | if (!crtc->enabled) |
308 | if (crtc->base.id != fb_helper->crtc_info[i].crtc_id || | 309 | continue; |
309 | !crtc->enabled) | 310 | |
310 | continue; | 311 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); |
311 | 312 | ||
312 | mutex_lock(&dev->mode_config.mutex); | ||
313 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
314 | mutex_unlock(&dev->mode_config.mutex); | ||
315 | 313 | ||
316 | /* Found a CRTC on this fb, now find encoders */ | 314 | /* Found a CRTC on this fb, now find encoders */ |
317 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | 315 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
318 | if (encoder->crtc == crtc) { | 316 | if (encoder->crtc == crtc) { |
319 | struct drm_encoder_helper_funcs *encoder_funcs; | 317 | struct drm_encoder_helper_funcs *encoder_funcs; |
320 | 318 | ||
321 | encoder_funcs = encoder->helper_private; | 319 | encoder_funcs = encoder->helper_private; |
322 | mutex_lock(&dev->mode_config.mutex); | 320 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); |
323 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
324 | mutex_unlock(&dev->mode_config.mutex); | ||
325 | } | ||
326 | } | 321 | } |
327 | } | 322 | } |
328 | } | 323 | } |
324 | mutex_unlock(&dev->mode_config.mutex); | ||
329 | } | 325 | } |
330 | 326 | ||
331 | static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) | 327 | static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) |
@@ -333,6 +329,7 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) | |||
333 | struct drm_fb_helper *fb_helper = info->par; | 329 | struct drm_fb_helper *fb_helper = info->par; |
334 | struct drm_device *dev = fb_helper->dev; | 330 | struct drm_device *dev = fb_helper->dev; |
335 | struct drm_crtc *crtc; | 331 | struct drm_crtc *crtc; |
332 | struct drm_crtc_helper_funcs *crtc_funcs; | ||
336 | struct drm_encoder *encoder; | 333 | struct drm_encoder *encoder; |
337 | int i; | 334 | int i; |
338 | 335 | ||
@@ -340,32 +337,26 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) | |||
340 | * For each CRTC in this fb, find all associated encoders | 337 | * For each CRTC in this fb, find all associated encoders |
341 | * and turn them off, then turn off the CRTC. | 338 | * and turn them off, then turn off the CRTC. |
342 | */ | 339 | */ |
340 | mutex_lock(&dev->mode_config.mutex); | ||
343 | for (i = 0; i < fb_helper->crtc_count; i++) { | 341 | for (i = 0; i < fb_helper->crtc_count; i++) { |
344 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 342 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
345 | struct drm_crtc_helper_funcs *crtc_funcs = | 343 | crtc_funcs = crtc->helper_private; |
346 | crtc->helper_private; | ||
347 | 344 | ||
348 | /* Only mess with CRTCs in this fb */ | 345 | if (!crtc->enabled) |
349 | if (crtc->base.id != fb_helper->crtc_info[i].crtc_id || | 346 | continue; |
350 | !crtc->enabled) | ||
351 | continue; | ||
352 | 347 | ||
353 | /* Found a CRTC on this fb, now find encoders */ | 348 | /* Found a CRTC on this fb, now find encoders */ |
354 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | 349 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
355 | if (encoder->crtc == crtc) { | 350 | if (encoder->crtc == crtc) { |
356 | struct drm_encoder_helper_funcs *encoder_funcs; | 351 | struct drm_encoder_helper_funcs *encoder_funcs; |
357 | 352 | ||
358 | encoder_funcs = encoder->helper_private; | 353 | encoder_funcs = encoder->helper_private; |
359 | mutex_lock(&dev->mode_config.mutex); | 354 | encoder_funcs->dpms(encoder, dpms_mode); |
360 | encoder_funcs->dpms(encoder, dpms_mode); | ||
361 | mutex_unlock(&dev->mode_config.mutex); | ||
362 | } | ||
363 | } | 355 | } |
364 | mutex_lock(&dev->mode_config.mutex); | ||
365 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
366 | mutex_unlock(&dev->mode_config.mutex); | ||
367 | } | 356 | } |
357 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
368 | } | 358 | } |
359 | mutex_unlock(&dev->mode_config.mutex); | ||
369 | } | 360 | } |
370 | 361 | ||
371 | int drm_fb_helper_blank(int blank, struct fb_info *info) | 362 | int drm_fb_helper_blank(int blank, struct fb_info *info) |
@@ -405,17 +396,19 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) | |||
405 | kfree(helper->crtc_info); | 396 | kfree(helper->crtc_info); |
406 | } | 397 | } |
407 | 398 | ||
408 | int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count) | 399 | int drm_fb_helper_init_crtc_count(struct drm_device *dev, |
400 | struct drm_fb_helper *helper, | ||
401 | int crtc_count, int max_conn_count) | ||
409 | { | 402 | { |
410 | struct drm_device *dev = helper->dev; | ||
411 | struct drm_crtc *crtc; | 403 | struct drm_crtc *crtc; |
412 | int ret = 0; | 404 | int ret = 0; |
413 | int i; | 405 | int i; |
414 | 406 | ||
407 | INIT_LIST_HEAD(&helper->kernel_fb_list); | ||
408 | helper->dev = dev; | ||
415 | helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); | 409 | helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); |
416 | if (!helper->crtc_info) | 410 | if (!helper->crtc_info) |
417 | return -ENOMEM; | 411 | return -ENOMEM; |
418 | |||
419 | helper->crtc_count = crtc_count; | 412 | helper->crtc_count = crtc_count; |
420 | 413 | ||
421 | for (i = 0; i < crtc_count; i++) { | 414 | for (i = 0; i < crtc_count; i++) { |
@@ -507,20 +500,15 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, | |||
507 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) | 500 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) |
508 | { | 501 | { |
509 | struct drm_fb_helper *fb_helper = info->par; | 502 | struct drm_fb_helper *fb_helper = info->par; |
510 | struct drm_device *dev = fb_helper->dev; | 503 | struct drm_crtc_helper_funcs *crtc_funcs; |
511 | u16 *red, *green, *blue, *transp; | 504 | u16 *red, *green, *blue, *transp; |
512 | struct drm_crtc *crtc; | 505 | struct drm_crtc *crtc; |
513 | int i, rc = 0; | 506 | int i, rc = 0; |
514 | int start; | 507 | int start; |
515 | 508 | ||
516 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 509 | for (i = 0; i < fb_helper->crtc_count; i++) { |
517 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | 510 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
518 | for (i = 0; i < fb_helper->crtc_count; i++) { | 511 | crtc_funcs = crtc->helper_private; |
519 | if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) | ||
520 | break; | ||
521 | } | ||
522 | if (i == fb_helper->crtc_count) | ||
523 | continue; | ||
524 | 512 | ||
525 | red = cmap->red; | 513 | red = cmap->red; |
526 | green = cmap->green; | 514 | green = cmap->green; |
@@ -556,22 +544,17 @@ int drm_fb_helper_setcolreg(unsigned regno, | |||
556 | struct fb_info *info) | 544 | struct fb_info *info) |
557 | { | 545 | { |
558 | struct drm_fb_helper *fb_helper = info->par; | 546 | struct drm_fb_helper *fb_helper = info->par; |
559 | struct drm_device *dev = fb_helper->dev; | ||
560 | struct drm_crtc *crtc; | 547 | struct drm_crtc *crtc; |
548 | struct drm_crtc_helper_funcs *crtc_funcs; | ||
561 | int i; | 549 | int i; |
562 | int ret; | 550 | int ret; |
563 | 551 | ||
564 | if (regno > 255) | 552 | if (regno > 255) |
565 | return 1; | 553 | return 1; |
566 | 554 | ||
567 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 555 | for (i = 0; i < fb_helper->crtc_count; i++) { |
568 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | 556 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
569 | for (i = 0; i < fb_helper->crtc_count; i++) { | 557 | crtc_funcs = crtc->helper_private; |
570 | if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) | ||
571 | break; | ||
572 | } | ||
573 | if (i == fb_helper->crtc_count) | ||
574 | continue; | ||
575 | 558 | ||
576 | ret = setcolreg(crtc, red, green, blue, regno, info); | 559 | ret = setcolreg(crtc, red, green, blue, regno, info); |
577 | if (ret) | 560 | if (ret) |
@@ -686,23 +669,20 @@ int drm_fb_helper_set_par(struct fb_info *info) | |||
686 | return -EINVAL; | 669 | return -EINVAL; |
687 | } | 670 | } |
688 | 671 | ||
689 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 672 | mutex_lock(&dev->mode_config.mutex); |
690 | 673 | for (i = 0; i < fb_helper->crtc_count; i++) { | |
691 | for (i = 0; i < fb_helper->crtc_count; i++) { | 674 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
692 | if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) | ||
693 | break; | ||
694 | } | ||
695 | if (i == fb_helper->crtc_count) | ||
696 | continue; | ||
697 | 675 | ||
698 | if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) { | 676 | if (crtc->fb != fb_helper->crtc_info[i].mode_set.fb) { |
699 | mutex_lock(&dev->mode_config.mutex); | ||
700 | ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); | 677 | ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); |
701 | mutex_unlock(&dev->mode_config.mutex); | 678 | |
702 | if (ret) | 679 | if (ret) { |
680 | mutex_unlock(&dev->mode_config.mutex); | ||
703 | return ret; | 681 | return ret; |
682 | } | ||
704 | } | 683 | } |
705 | } | 684 | } |
685 | mutex_unlock(&dev->mode_config.mutex); | ||
706 | return 0; | 686 | return 0; |
707 | } | 687 | } |
708 | EXPORT_SYMBOL(drm_fb_helper_set_par); | 688 | EXPORT_SYMBOL(drm_fb_helper_set_par); |
@@ -717,14 +697,9 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, | |||
717 | int ret = 0; | 697 | int ret = 0; |
718 | int i; | 698 | int i; |
719 | 699 | ||
720 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 700 | mutex_lock(&dev->mode_config.mutex); |
721 | for (i = 0; i < fb_helper->crtc_count; i++) { | 701 | for (i = 0; i < fb_helper->crtc_count; i++) { |
722 | if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) | 702 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
723 | break; | ||
724 | } | ||
725 | |||
726 | if (i == fb_helper->crtc_count) | ||
727 | continue; | ||
728 | 703 | ||
729 | modeset = &fb_helper->crtc_info[i].mode_set; | 704 | modeset = &fb_helper->crtc_info[i].mode_set; |
730 | 705 | ||
@@ -732,34 +707,29 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, | |||
732 | modeset->y = var->yoffset; | 707 | modeset->y = var->yoffset; |
733 | 708 | ||
734 | if (modeset->num_connectors) { | 709 | if (modeset->num_connectors) { |
735 | mutex_lock(&dev->mode_config.mutex); | ||
736 | ret = crtc->funcs->set_config(modeset); | 710 | ret = crtc->funcs->set_config(modeset); |
737 | mutex_unlock(&dev->mode_config.mutex); | ||
738 | if (!ret) { | 711 | if (!ret) { |
739 | info->var.xoffset = var->xoffset; | 712 | info->var.xoffset = var->xoffset; |
740 | info->var.yoffset = var->yoffset; | 713 | info->var.yoffset = var->yoffset; |
741 | } | 714 | } |
742 | } | 715 | } |
743 | } | 716 | } |
717 | mutex_unlock(&dev->mode_config.mutex); | ||
744 | return ret; | 718 | return ret; |
745 | } | 719 | } |
746 | EXPORT_SYMBOL(drm_fb_helper_pan_display); | 720 | EXPORT_SYMBOL(drm_fb_helper_pan_display); |
747 | 721 | ||
748 | int drm_fb_helper_single_fb_probe(struct drm_device *dev, | 722 | int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, |
749 | int preferred_bpp, | 723 | int preferred_bpp) |
750 | int (*fb_find_or_create)(struct drm_device *dev, | ||
751 | struct drm_fb_helper_surface_size *sizes, | ||
752 | struct drm_fb_helper **fb_ptr)) | ||
753 | { | 724 | { |
754 | struct drm_crtc *crtc; | 725 | struct drm_device *dev = fb_helper->dev; |
755 | struct drm_connector *connector; | 726 | struct drm_connector *connector; |
756 | int new_fb = 0; | 727 | int new_fb = 0; |
757 | int crtc_count = 0; | 728 | int crtc_count = 0; |
758 | int ret, i, conn_count = 0; | 729 | int ret, i; |
759 | struct fb_info *info; | 730 | struct fb_info *info; |
760 | struct drm_mode_set *modeset = NULL; | ||
761 | struct drm_fb_helper *fb_helper; | ||
762 | struct drm_fb_helper_surface_size sizes; | 731 | struct drm_fb_helper_surface_size sizes; |
732 | int gamma_size = 0; | ||
763 | 733 | ||
764 | memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); | 734 | memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); |
765 | sizes.surface_depth = 24; | 735 | sizes.surface_depth = 24; |
@@ -775,7 +745,6 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, | |||
775 | /* first up get a count of crtcs now in use and new min/maxes width/heights */ | 745 | /* first up get a count of crtcs now in use and new min/maxes width/heights */ |
776 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 746 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
777 | struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; | 747 | struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; |
778 | |||
779 | struct drm_fb_helper_cmdline_mode *cmdline_mode; | 748 | struct drm_fb_helper_cmdline_mode *cmdline_mode; |
780 | 749 | ||
781 | if (!fb_help_conn) | 750 | if (!fb_help_conn) |
@@ -807,21 +776,22 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, | |||
807 | } | 776 | } |
808 | } | 777 | } |
809 | 778 | ||
810 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 779 | crtc_count = 0; |
811 | if (drm_helper_crtc_in_use(crtc)) { | 780 | for (i = 0; i < fb_helper->crtc_count; i++) { |
812 | if (crtc->desired_mode) { | 781 | struct drm_display_mode *desired_mode; |
813 | if (crtc->desired_mode->hdisplay < sizes.fb_width) | 782 | desired_mode = fb_helper->crtc_info[i].desired_mode; |
814 | sizes.fb_width = crtc->desired_mode->hdisplay; | 783 | |
815 | 784 | if (desired_mode) { | |
816 | if (crtc->desired_mode->vdisplay < sizes.fb_height) | 785 | if (gamma_size == 0) |
817 | sizes.fb_height = crtc->desired_mode->vdisplay; | 786 | gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; |
818 | 787 | if (desired_mode->hdisplay < sizes.fb_width) | |
819 | if (crtc->desired_mode->hdisplay > sizes.surface_width) | 788 | sizes.fb_width = desired_mode->hdisplay; |
820 | sizes.surface_width = crtc->desired_mode->hdisplay; | 789 | if (desired_mode->vdisplay < sizes.fb_height) |
821 | 790 | sizes.fb_height = desired_mode->vdisplay; | |
822 | if (crtc->desired_mode->vdisplay > sizes.surface_height) | 791 | if (desired_mode->hdisplay > sizes.surface_width) |
823 | sizes.surface_height = crtc->desired_mode->vdisplay; | 792 | sizes.surface_width = desired_mode->hdisplay; |
824 | } | 793 | if (desired_mode->vdisplay > sizes.surface_height) |
794 | sizes.surface_height = desired_mode->vdisplay; | ||
825 | crtc_count++; | 795 | crtc_count++; |
826 | } | 796 | } |
827 | } | 797 | } |
@@ -833,48 +803,20 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, | |||
833 | } | 803 | } |
834 | 804 | ||
835 | /* push down into drivers */ | 805 | /* push down into drivers */ |
836 | new_fb = (*fb_find_or_create)(dev, &sizes, | 806 | new_fb = (*fb_helper->fb_probe)(fb_helper, &sizes); |
837 | &fb_helper); | ||
838 | if (new_fb < 0) | 807 | if (new_fb < 0) |
839 | return new_fb; | 808 | return new_fb; |
840 | 809 | ||
841 | info = fb_helper->fbdev; | 810 | info = fb_helper->fbdev; |
842 | 811 | ||
843 | crtc_count = 0; | 812 | /* set the fb pointer */ |
844 | /* okay we need to setup new connector sets in the crtcs */ | 813 | for (i = 0; i < fb_helper->crtc_count; i++) { |
845 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 814 | fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; |
846 | modeset = &fb_helper->crtc_info[crtc_count].mode_set; | ||
847 | modeset->fb = fb_helper->fb; | ||
848 | conn_count = 0; | ||
849 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
850 | if (connector->encoder) | ||
851 | if (connector->encoder->crtc == modeset->crtc) { | ||
852 | modeset->connectors[conn_count] = connector; | ||
853 | conn_count++; | ||
854 | if (conn_count > fb_helper->conn_limit) | ||
855 | BUG(); | ||
856 | } | ||
857 | } | ||
858 | |||
859 | for (i = conn_count; i < fb_helper->conn_limit; i++) | ||
860 | modeset->connectors[i] = NULL; | ||
861 | |||
862 | modeset->crtc = crtc; | ||
863 | crtc_count++; | ||
864 | |||
865 | modeset->num_connectors = conn_count; | ||
866 | if (modeset->crtc->desired_mode) { | ||
867 | if (modeset->mode) | ||
868 | drm_mode_destroy(dev, modeset->mode); | ||
869 | modeset->mode = drm_mode_duplicate(dev, | ||
870 | modeset->crtc->desired_mode); | ||
871 | } | ||
872 | } | 815 | } |
873 | fb_helper->crtc_count = crtc_count; | ||
874 | 816 | ||
875 | if (new_fb) { | 817 | if (new_fb) { |
876 | info->var.pixclock = 0; | 818 | info->var.pixclock = 0; |
877 | ret = fb_alloc_cmap(&info->cmap, modeset->crtc->gamma_size, 0); | 819 | ret = fb_alloc_cmap(&info->cmap, gamma_size, 0); |
878 | if (ret) | 820 | if (ret) |
879 | return ret; | 821 | return ret; |
880 | if (register_framebuffer(info) < 0) { | 822 | if (register_framebuffer(info) < 0) { |
@@ -906,15 +848,18 @@ EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); | |||
906 | 848 | ||
907 | void drm_fb_helper_free(struct drm_fb_helper *helper) | 849 | void drm_fb_helper_free(struct drm_fb_helper *helper) |
908 | { | 850 | { |
909 | list_del(&helper->kernel_fb_list); | 851 | if (!list_empty(&helper->kernel_fb_list)) { |
910 | if (list_empty(&kernel_fb_helper_list)) { | 852 | list_del(&helper->kernel_fb_list); |
911 | printk(KERN_INFO "unregistered panic notifier\n"); | 853 | if (list_empty(&kernel_fb_helper_list)) { |
912 | atomic_notifier_chain_unregister(&panic_notifier_list, | 854 | printk(KERN_INFO "unregistered panic notifier\n"); |
913 | &paniced); | 855 | atomic_notifier_chain_unregister(&panic_notifier_list, |
914 | unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); | 856 | &paniced); |
857 | unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); | ||
858 | } | ||
915 | } | 859 | } |
916 | drm_fb_helper_crtc_free(helper); | 860 | drm_fb_helper_crtc_free(helper); |
917 | fb_dealloc_cmap(&helper->fbdev->cmap); | 861 | if (helper->fbdev->cmap.len) |
862 | fb_dealloc_cmap(&helper->fbdev->cmap); | ||
918 | } | 863 | } |
919 | EXPORT_SYMBOL(drm_fb_helper_free); | 864 | EXPORT_SYMBOL(drm_fb_helper_free); |
920 | 865 | ||
@@ -1168,20 +1113,21 @@ static bool drm_target_preferred(struct drm_device *dev, | |||
1168 | return true; | 1113 | return true; |
1169 | } | 1114 | } |
1170 | 1115 | ||
1171 | static int drm_pick_crtcs(struct drm_device *dev, | 1116 | static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, |
1172 | struct drm_crtc **best_crtcs, | 1117 | struct drm_fb_helper_crtc **best_crtcs, |
1173 | struct drm_display_mode **modes, | 1118 | struct drm_display_mode **modes, |
1174 | int n, int width, int height) | 1119 | int n, int width, int height) |
1175 | { | 1120 | { |
1176 | int c, o; | 1121 | int c, o; |
1122 | struct drm_device *dev = fb_helper->dev; | ||
1177 | struct drm_connector *connector; | 1123 | struct drm_connector *connector; |
1178 | struct drm_connector_helper_funcs *connector_funcs; | 1124 | struct drm_connector_helper_funcs *connector_funcs; |
1179 | struct drm_encoder *encoder; | 1125 | struct drm_encoder *encoder; |
1180 | struct drm_crtc *best_crtc; | 1126 | struct drm_fb_helper_crtc *best_crtc; |
1181 | int my_score, best_score, score; | 1127 | int my_score, best_score, score; |
1182 | struct drm_crtc **crtcs, *crtc; | 1128 | struct drm_fb_helper_crtc **crtcs, *crtc; |
1183 | 1129 | ||
1184 | if (n == dev->mode_config.num_connector) | 1130 | if (n == fb_helper->dev->mode_config.num_connector) |
1185 | return 0; | 1131 | return 0; |
1186 | c = 0; | 1132 | c = 0; |
1187 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 1133 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
@@ -1192,12 +1138,12 @@ static int drm_pick_crtcs(struct drm_device *dev, | |||
1192 | 1138 | ||
1193 | best_crtcs[n] = NULL; | 1139 | best_crtcs[n] = NULL; |
1194 | best_crtc = NULL; | 1140 | best_crtc = NULL; |
1195 | best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); | 1141 | best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height); |
1196 | if (modes[n] == NULL) | 1142 | if (modes[n] == NULL) |
1197 | return best_score; | 1143 | return best_score; |
1198 | 1144 | ||
1199 | crtcs = kmalloc(dev->mode_config.num_connector * | 1145 | crtcs = kzalloc(dev->mode_config.num_connector * |
1200 | sizeof(struct drm_crtc *), GFP_KERNEL); | 1146 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); |
1201 | if (!crtcs) | 1147 | if (!crtcs) |
1202 | return best_score; | 1148 | return best_score; |
1203 | 1149 | ||
@@ -1214,15 +1160,12 @@ static int drm_pick_crtcs(struct drm_device *dev, | |||
1214 | if (!encoder) | 1160 | if (!encoder) |
1215 | goto out; | 1161 | goto out; |
1216 | 1162 | ||
1217 | connector->encoder = encoder; | ||
1218 | |||
1219 | /* select a crtc for this connector and then attempt to configure | 1163 | /* select a crtc for this connector and then attempt to configure |
1220 | remaining connectors */ | 1164 | remaining connectors */ |
1221 | c = 0; | 1165 | for (c = 0; c < fb_helper->crtc_count; c++) { |
1222 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 1166 | crtc = &fb_helper->crtc_info[c]; |
1223 | 1167 | ||
1224 | if ((encoder->possible_crtcs & (1 << c)) == 0) { | 1168 | if ((encoder->possible_crtcs & (1 << c)) == 0) { |
1225 | c++; | ||
1226 | continue; | 1169 | continue; |
1227 | } | 1170 | } |
1228 | 1171 | ||
@@ -1232,34 +1175,34 @@ static int drm_pick_crtcs(struct drm_device *dev, | |||
1232 | 1175 | ||
1233 | if (o < n) { | 1176 | if (o < n) { |
1234 | /* ignore cloning for now */ | 1177 | /* ignore cloning for now */ |
1235 | c++; | ||
1236 | continue; | 1178 | continue; |
1237 | } | 1179 | } |
1238 | 1180 | ||
1239 | crtcs[n] = crtc; | 1181 | crtcs[n] = crtc; |
1240 | memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *)); | 1182 | memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *)); |
1241 | score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1, | 1183 | score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1, |
1242 | width, height); | 1184 | width, height); |
1243 | if (score > best_score) { | 1185 | if (score > best_score) { |
1244 | best_crtc = crtc; | 1186 | best_crtc = crtc; |
1245 | best_score = score; | 1187 | best_score = score; |
1246 | memcpy(best_crtcs, crtcs, | 1188 | memcpy(best_crtcs, crtcs, |
1247 | dev->mode_config.num_connector * | 1189 | dev->mode_config.num_connector * |
1248 | sizeof(struct drm_crtc *)); | 1190 | sizeof(struct drm_fb_helper_crtc *)); |
1249 | } | 1191 | } |
1250 | c++; | ||
1251 | } | 1192 | } |
1252 | out: | 1193 | out: |
1253 | kfree(crtcs); | 1194 | kfree(crtcs); |
1254 | return best_score; | 1195 | return best_score; |
1255 | } | 1196 | } |
1256 | 1197 | ||
1257 | static void drm_setup_crtcs(struct drm_device *dev) | 1198 | static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) |
1258 | { | 1199 | { |
1259 | struct drm_crtc **crtcs; | 1200 | struct drm_device *dev = fb_helper->dev; |
1201 | struct drm_fb_helper_crtc **crtcs; | ||
1260 | struct drm_display_mode **modes; | 1202 | struct drm_display_mode **modes; |
1261 | struct drm_encoder *encoder; | 1203 | struct drm_encoder *encoder; |
1262 | struct drm_connector *connector; | 1204 | struct drm_connector *connector; |
1205 | struct drm_mode_set *modeset; | ||
1263 | bool *enabled; | 1206 | bool *enabled; |
1264 | int width, height; | 1207 | int width, height; |
1265 | int i, ret; | 1208 | int i, ret; |
@@ -1275,7 +1218,7 @@ static void drm_setup_crtcs(struct drm_device *dev) | |||
1275 | } | 1218 | } |
1276 | 1219 | ||
1277 | crtcs = kcalloc(dev->mode_config.num_connector, | 1220 | crtcs = kcalloc(dev->mode_config.num_connector, |
1278 | sizeof(struct drm_crtc *), GFP_KERNEL); | 1221 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); |
1279 | modes = kcalloc(dev->mode_config.num_connector, | 1222 | modes = kcalloc(dev->mode_config.num_connector, |
1280 | sizeof(struct drm_display_mode *), GFP_KERNEL); | 1223 | sizeof(struct drm_display_mode *), GFP_KERNEL); |
1281 | enabled = kcalloc(dev->mode_config.num_connector, | 1224 | enabled = kcalloc(dev->mode_config.num_connector, |
@@ -1289,26 +1232,30 @@ static void drm_setup_crtcs(struct drm_device *dev) | |||
1289 | 1232 | ||
1290 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); | 1233 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); |
1291 | 1234 | ||
1292 | drm_pick_crtcs(dev, crtcs, modes, 0, width, height); | 1235 | drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height); |
1236 | |||
1237 | /* need to set the modesets up here for use later */ | ||
1238 | /* fill out the connector<->crtc mappings into the modesets */ | ||
1239 | for (i = 0; i < fb_helper->crtc_count; i++) { | ||
1240 | modeset = &fb_helper->crtc_info[i].mode_set; | ||
1241 | modeset->num_connectors = 0; | ||
1242 | } | ||
1293 | 1243 | ||
1294 | i = 0; | 1244 | i = 0; |
1295 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 1245 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
1296 | struct drm_display_mode *mode = modes[i]; | 1246 | struct drm_display_mode *mode = modes[i]; |
1297 | struct drm_crtc *crtc = crtcs[i]; | 1247 | struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; |
1298 | 1248 | modeset = &fb_crtc->mode_set; | |
1299 | if (connector->encoder == NULL) { | ||
1300 | i++; | ||
1301 | continue; | ||
1302 | } | ||
1303 | 1249 | ||
1304 | if (mode && crtc) { | 1250 | if (mode && fb_crtc) { |
1305 | DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", | 1251 | DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", |
1306 | mode->name, crtc->base.id); | 1252 | mode->name, fb_crtc->mode_set.crtc->base.id); |
1307 | crtc->desired_mode = mode; | 1253 | fb_crtc->desired_mode = mode; |
1308 | connector->encoder->crtc = crtc; | 1254 | if (modeset->mode) |
1309 | } else { | 1255 | drm_mode_destroy(dev, modeset->mode); |
1310 | connector->encoder->crtc = NULL; | 1256 | modeset->mode = drm_mode_duplicate(dev, |
1311 | connector->encoder = NULL; | 1257 | fb_crtc->desired_mode); |
1258 | modeset->connectors[modeset->num_connectors++] = connector; | ||
1312 | } | 1259 | } |
1313 | i++; | 1260 | i++; |
1314 | } | 1261 | } |
@@ -1332,14 +1279,15 @@ static void drm_setup_crtcs(struct drm_device *dev) | |||
1332 | * RETURNS: | 1279 | * RETURNS: |
1333 | * Zero if everything went ok, nonzero otherwise. | 1280 | * Zero if everything went ok, nonzero otherwise. |
1334 | */ | 1281 | */ |
1335 | bool drm_helper_initial_config(struct drm_device *dev) | 1282 | bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) |
1336 | { | 1283 | { |
1284 | struct drm_device *dev = fb_helper->dev; | ||
1337 | int count = 0; | 1285 | int count = 0; |
1338 | 1286 | ||
1339 | /* disable all the possible outputs/crtcs before entering KMS mode */ | 1287 | /* disable all the possible outputs/crtcs before entering KMS mode */ |
1340 | drm_helper_disable_unused_functions(dev); | 1288 | drm_helper_disable_unused_functions(fb_helper->dev); |
1341 | 1289 | ||
1342 | drm_fb_helper_parse_command_line(dev); | 1290 | drm_fb_helper_parse_command_line(fb_helper->dev); |
1343 | 1291 | ||
1344 | count = drm_helper_probe_connector_modes(dev, | 1292 | count = drm_helper_probe_connector_modes(dev, |
1345 | dev->mode_config.max_width, | 1293 | dev->mode_config.max_width, |
@@ -1351,20 +1299,21 @@ bool drm_helper_initial_config(struct drm_device *dev) | |||
1351 | if (count == 0) | 1299 | if (count == 0) |
1352 | printk(KERN_INFO "No connectors reported connected with modes\n"); | 1300 | printk(KERN_INFO "No connectors reported connected with modes\n"); |
1353 | 1301 | ||
1354 | drm_setup_crtcs(dev); | 1302 | drm_setup_crtcs(fb_helper); |
1355 | 1303 | ||
1356 | return 0; | 1304 | return 0; |
1357 | } | 1305 | } |
1358 | EXPORT_SYMBOL(drm_helper_initial_config); | 1306 | EXPORT_SYMBOL(drm_fb_helper_initial_config); |
1359 | 1307 | ||
1360 | bool drm_helper_fb_hotplug_event(struct drm_device *dev) | 1308 | bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, |
1309 | u32 max_width, u32 max_height) | ||
1361 | { | 1310 | { |
1362 | DRM_DEBUG_KMS("\n"); | 1311 | DRM_DEBUG_KMS("\n"); |
1363 | 1312 | ||
1364 | drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, | 1313 | drm_helper_probe_connector_modes(fb_helper->dev, max_width, |
1365 | dev->mode_config.max_height); | 1314 | max_height); |
1366 | 1315 | ||
1367 | drm_setup_crtcs(dev); | 1316 | drm_setup_crtcs(fb_helper); |
1368 | 1317 | ||
1369 | return true; | 1318 | return true; |
1370 | } | 1319 | } |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 601f354e467e..0405a7460594 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -220,7 +220,7 @@ enum no_fbc_reason { | |||
220 | FBC_NOT_TILED, /* buffer not tiled */ | 220 | FBC_NOT_TILED, /* buffer not tiled */ |
221 | }; | 221 | }; |
222 | 222 | ||
223 | struct intel_kernel_fbdev; | 223 | struct intel_fbdev; |
224 | 224 | ||
225 | typedef struct drm_i915_private { | 225 | typedef struct drm_i915_private { |
226 | struct drm_device *dev; | 226 | struct drm_device *dev; |
@@ -630,7 +630,8 @@ typedef struct drm_i915_private { | |||
630 | 630 | ||
631 | enum no_fbc_reason no_fbc_reason; | 631 | enum no_fbc_reason no_fbc_reason; |
632 | 632 | ||
633 | struct intel_kernel_fbdev *fbdev; | 633 | /* list of fbdev register on this device */ |
634 | struct intel_fbdev *fbdev; | ||
634 | } drm_i915_private_t; | 635 | } drm_i915_private_t; |
635 | 636 | ||
636 | /** driver private structure attached to each drm_gem_object */ | 637 | /** driver private structure attached to each drm_gem_object */ |
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index b0de9bbde34a..ff6912edf0c6 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c | |||
@@ -45,7 +45,7 @@ | |||
45 | #include "i915_drm.h" | 45 | #include "i915_drm.h" |
46 | #include "i915_drv.h" | 46 | #include "i915_drv.h" |
47 | 47 | ||
48 | struct intel_kernel_fbdev { | 48 | struct intel_fbdev { |
49 | struct drm_fb_helper helper; | 49 | struct drm_fb_helper helper; |
50 | struct intel_framebuffer ifb; | 50 | struct intel_framebuffer ifb; |
51 | struct list_head fbdev_list; | 51 | struct list_head fbdev_list; |
@@ -71,14 +71,12 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = { | |||
71 | }; | 71 | }; |
72 | 72 | ||
73 | 73 | ||
74 | static int intelfb_create(struct drm_device *dev, | 74 | static int intelfb_create(struct intel_fbdev *ifbdev, |
75 | struct drm_fb_helper_surface_size *sizes, | 75 | struct drm_fb_helper_surface_size *sizes) |
76 | struct intel_kernel_fbdev **ifbdev_p) | ||
77 | { | 76 | { |
77 | struct drm_device *dev = ifbdev->helper.dev; | ||
78 | struct fb_info *info; | 78 | struct fb_info *info; |
79 | struct intel_kernel_fbdev *ifbdev; | ||
80 | struct drm_framebuffer *fb; | 79 | struct drm_framebuffer *fb; |
81 | struct intel_framebuffer *intel_fb; | ||
82 | struct drm_mode_fb_cmd mode_cmd; | 80 | struct drm_mode_fb_cmd mode_cmd; |
83 | struct drm_gem_object *fbo = NULL; | 81 | struct drm_gem_object *fbo = NULL; |
84 | struct drm_i915_gem_object *obj_priv; | 82 | struct drm_i915_gem_object *obj_priv; |
@@ -117,13 +115,14 @@ static int intelfb_create(struct drm_device *dev, | |||
117 | /* Flush everything out, we'll be doing GTT only from now on */ | 115 | /* Flush everything out, we'll be doing GTT only from now on */ |
118 | i915_gem_object_set_to_gtt_domain(fbo, 1); | 116 | i915_gem_object_set_to_gtt_domain(fbo, 1); |
119 | 117 | ||
120 | info = framebuffer_alloc(sizeof(struct intel_kernel_fbdev), device); | 118 | info = framebuffer_alloc(0, device); |
121 | if (!info) { | 119 | if (!info) { |
122 | ret = -ENOMEM; | 120 | ret = -ENOMEM; |
123 | goto out_unpin; | 121 | goto out_unpin; |
124 | } | 122 | } |
125 | 123 | ||
126 | ifbdev = info->par; | 124 | info->par = ifbdev; |
125 | |||
127 | intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo); | 126 | intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo); |
128 | 127 | ||
129 | fb = &ifbdev->ifb.base; | 128 | fb = &ifbdev->ifb.base; |
@@ -131,22 +130,12 @@ static int intelfb_create(struct drm_device *dev, | |||
131 | ifbdev->helper.fb = fb; | 130 | ifbdev->helper.fb = fb; |
132 | ifbdev->helper.fbdev = info; | 131 | ifbdev->helper.fbdev = info; |
133 | ifbdev->helper.funcs = &intel_fb_helper_funcs; | 132 | ifbdev->helper.funcs = &intel_fb_helper_funcs; |
134 | ifbdev->helper.dev = dev; | ||
135 | |||
136 | *ifbdev_p = ifbdev; | ||
137 | |||
138 | ret = drm_fb_helper_init_crtc_count(&ifbdev->helper, 2, | ||
139 | INTELFB_CONN_LIMIT); | ||
140 | if (ret) | ||
141 | goto out_unref; | ||
142 | 133 | ||
143 | strcpy(info->fix.id, "inteldrmfb"); | 134 | strcpy(info->fix.id, "inteldrmfb"); |
144 | 135 | ||
145 | info->flags = FBINFO_DEFAULT; | 136 | info->flags = FBINFO_DEFAULT; |
146 | |||
147 | info->fbops = &intelfb_ops; | 137 | info->fbops = &intelfb_ops; |
148 | 138 | ||
149 | |||
150 | /* setup aperture base/size for vesafb takeover */ | 139 | /* setup aperture base/size for vesafb takeover */ |
151 | info->aperture_base = dev->mode_config.fb_base; | 140 | info->aperture_base = dev->mode_config.fb_base; |
152 | if (IS_I9XX(dev)) | 141 | if (IS_I9XX(dev)) |
@@ -183,8 +172,8 @@ static int intelfb_create(struct drm_device *dev, | |||
183 | info->pixmap.scan_align = 1; | 172 | info->pixmap.scan_align = 1; |
184 | 173 | ||
185 | DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", | 174 | DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", |
186 | intel_fb->base.width, intel_fb->base.height, | 175 | fb->width, fb->height, |
187 | obj_priv->gtt_offset, fbo); | 176 | obj_priv->gtt_offset, fbo); |
188 | 177 | ||
189 | 178 | ||
190 | mutex_unlock(&dev->struct_mutex); | 179 | mutex_unlock(&dev->struct_mutex); |
@@ -200,76 +189,80 @@ out: | |||
200 | return ret; | 189 | return ret; |
201 | } | 190 | } |
202 | 191 | ||
203 | static int intel_fb_find_or_create_single(struct drm_device *dev, | 192 | static int intel_fb_find_or_create_single(struct drm_fb_helper *helper, |
204 | struct drm_fb_helper_surface_size *sizes, | 193 | struct drm_fb_helper_surface_size *sizes) |
205 | struct drm_fb_helper **fb_ptr) | ||
206 | { | 194 | { |
207 | drm_i915_private_t *dev_priv = dev->dev_private; | 195 | struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper; |
208 | struct intel_kernel_fbdev *ifbdev = NULL; | ||
209 | int new_fb = 0; | 196 | int new_fb = 0; |
210 | int ret; | 197 | int ret; |
211 | 198 | ||
212 | if (!dev_priv->fbdev) { | 199 | if (!helper->fb) { |
213 | ret = intelfb_create(dev, sizes, | 200 | ret = intelfb_create(ifbdev, sizes); |
214 | &ifbdev); | ||
215 | if (ret) | 201 | if (ret) |
216 | return ret; | 202 | return ret; |
217 | |||
218 | dev_priv->fbdev = ifbdev; | ||
219 | new_fb = 1; | 203 | new_fb = 1; |
220 | } else { | ||
221 | ifbdev = dev_priv->fbdev; | ||
222 | if (ifbdev->ifb.base.width < sizes->surface_width || | ||
223 | ifbdev->ifb.base.height < sizes->surface_height) { | ||
224 | DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | } | 204 | } |
228 | |||
229 | *fb_ptr = &ifbdev->helper; | ||
230 | return new_fb; | 205 | return new_fb; |
231 | } | 206 | } |
232 | 207 | ||
233 | static int intelfb_probe(struct drm_device *dev) | 208 | static int intelfb_probe(struct intel_fbdev *ifbdev) |
234 | { | 209 | { |
235 | int ret; | 210 | int ret; |
236 | 211 | ||
237 | DRM_DEBUG_KMS("\n"); | 212 | DRM_DEBUG_KMS("\n"); |
238 | ret = drm_fb_helper_single_fb_probe(dev, 32, intel_fb_find_or_create_single); | 213 | ret = drm_fb_helper_single_fb_probe(&ifbdev->helper, 32); |
239 | return ret; | 214 | return ret; |
240 | } | 215 | } |
241 | 216 | ||
242 | int intel_fbdev_destroy(struct drm_device *dev, | 217 | int intel_fbdev_destroy(struct drm_device *dev, |
243 | struct intel_kernel_fbdev *ifbdev) | 218 | struct intel_fbdev *ifbdev) |
244 | { | 219 | { |
245 | struct fb_info *info; | 220 | struct fb_info *info; |
246 | struct intel_framebuffer *ifb = &ifbdev->ifb; | 221 | struct intel_framebuffer *ifb = &ifbdev->ifb; |
247 | 222 | ||
248 | info = ifbdev->helper.fbdev; | 223 | if (ifbdev->helper.fbdev) { |
224 | info = ifbdev->helper.fbdev; | ||
225 | unregister_framebuffer(info); | ||
226 | iounmap(info->screen_base); | ||
227 | framebuffer_release(info); | ||
228 | } | ||
249 | 229 | ||
250 | unregister_framebuffer(info); | ||
251 | iounmap(info->screen_base); | ||
252 | drm_fb_helper_free(&ifbdev->helper); | 230 | drm_fb_helper_free(&ifbdev->helper); |
253 | 231 | ||
254 | drm_framebuffer_cleanup(&ifb->base); | 232 | drm_framebuffer_cleanup(&ifb->base); |
255 | drm_gem_object_unreference_unlocked(ifb->obj); | 233 | if (ifb->obj) |
256 | 234 | drm_gem_object_unreference_unlocked(ifb->obj); | |
257 | framebuffer_release(info); | ||
258 | 235 | ||
259 | return 0; | 236 | return 0; |
260 | } | 237 | } |
261 | 238 | ||
262 | int intel_fbdev_init(struct drm_device *dev) | 239 | int intel_fbdev_init(struct drm_device *dev) |
263 | { | 240 | { |
264 | drm_helper_initial_config(dev); | 241 | struct intel_fbdev *ifbdev; |
265 | intelfb_probe(dev); | 242 | drm_i915_private_t *dev_priv = dev->dev_private; |
243 | |||
244 | ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); | ||
245 | if (!ifbdev) | ||
246 | return -ENOMEM; | ||
247 | |||
248 | dev_priv->fbdev = ifbdev; | ||
249 | |||
250 | drm_fb_helper_init_crtc_count(dev, &ifbdev->helper, 2, | ||
251 | INTELFB_CONN_LIMIT); | ||
252 | ifbdev->helper.fb_probe = intel_fb_find_or_create_single; | ||
253 | drm_fb_helper_initial_config(&ifbdev->helper); | ||
254 | intelfb_probe(ifbdev); | ||
266 | return 0; | 255 | return 0; |
267 | } | 256 | } |
268 | 257 | ||
269 | void intel_fbdev_fini(struct drm_device *dev) | 258 | void intel_fbdev_fini(struct drm_device *dev) |
270 | { | 259 | { |
271 | drm_i915_private_t *dev_priv = dev->dev_private; | 260 | drm_i915_private_t *dev_priv = dev->dev_private; |
261 | if (!dev_priv->fbdev) | ||
262 | return; | ||
263 | |||
272 | intel_fbdev_destroy(dev, dev_priv->fbdev); | 264 | intel_fbdev_destroy(dev, dev_priv->fbdev); |
265 | kfree(dev_priv->fbdev); | ||
273 | dev_priv->fbdev = NULL; | 266 | dev_priv->fbdev = NULL; |
274 | } | 267 | } |
275 | MODULE_LICENSE("GPL and additional rights"); | 268 | MODULE_LICENSE("GPL and additional rights"); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 93459e07e829..941339cb8d8b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -627,7 +627,7 @@ struct drm_nouveau_private { | |||
627 | struct dentry *channel_root; | 627 | struct dentry *channel_root; |
628 | } debugfs; | 628 | } debugfs; |
629 | 629 | ||
630 | struct nouveau_fbcon_par *nfbdev; | 630 | struct nouveau_fbdev *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_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 712ee42e3cf8..90843b62d9b1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c | |||
@@ -53,8 +53,8 @@ | |||
53 | static int | 53 | static int |
54 | nouveau_fbcon_sync(struct fb_info *info) | 54 | nouveau_fbcon_sync(struct fb_info *info) |
55 | { | 55 | { |
56 | struct nouveau_fbcon_par *par = info->par; | 56 | struct nouveau_fbdev *nfbdev = info->par; |
57 | struct drm_device *dev = par->dev; | 57 | struct drm_device *dev = nfbdev->dev; |
58 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 58 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
59 | struct nouveau_channel *chan = dev_priv->channel; | 59 | struct nouveau_channel *chan = dev_priv->channel; |
60 | int ret, i; | 60 | int ret, i; |
@@ -200,9 +200,9 @@ not_fb: | |||
200 | #endif | 200 | #endif |
201 | 201 | ||
202 | static void | 202 | static void |
203 | nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) | 203 | nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *nfbdev) |
204 | { | 204 | { |
205 | struct fb_info *info = fbpar->helper.fbdev; | 205 | struct fb_info *info = nfbdev->helper.fbdev; |
206 | struct fb_fillrect rect; | 206 | struct fb_fillrect rect; |
207 | 207 | ||
208 | /* Clear the entire fbcon. The drm will program every connector | 208 | /* Clear the entire fbcon. The drm will program every connector |
@@ -218,13 +218,12 @@ nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) | |||
218 | } | 218 | } |
219 | 219 | ||
220 | static int | 220 | static int |
221 | nouveau_fbcon_create(struct drm_device *dev, | 221 | nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, |
222 | struct drm_fb_helper_surface_size *sizes, | 222 | struct drm_fb_helper_surface_size *sizes) |
223 | struct nouveau_fbcon_par **fbpar_p) | ||
224 | { | 223 | { |
224 | struct drm_device *dev = nfbdev->dev; | ||
225 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 225 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
226 | struct fb_info *info; | 226 | struct fb_info *info; |
227 | struct nouveau_fbcon_par *par; | ||
228 | struct drm_framebuffer *fb; | 227 | struct drm_framebuffer *fb; |
229 | struct nouveau_framebuffer *nouveau_fb; | 228 | struct nouveau_framebuffer *nouveau_fb; |
230 | struct nouveau_bo *nvbo; | 229 | struct nouveau_bo *nvbo; |
@@ -267,27 +266,23 @@ nouveau_fbcon_create(struct drm_device *dev, | |||
267 | 266 | ||
268 | mutex_lock(&dev->struct_mutex); | 267 | mutex_lock(&dev->struct_mutex); |
269 | 268 | ||
270 | info = framebuffer_alloc(sizeof(struct nouveau_fbcon_par), device); | 269 | info = framebuffer_alloc(0, device); |
271 | if (!info) { | 270 | if (!info) { |
272 | ret = -ENOMEM; | 271 | ret = -ENOMEM; |
273 | goto out_unref; | 272 | goto out_unref; |
274 | } | 273 | } |
275 | 274 | ||
276 | par = info->par; | 275 | info->par = nfbdev; |
277 | nouveau_framebuffer_init(dev, &par->nouveau_fb, &mode_cmd, nvbo); | ||
278 | 276 | ||
279 | fb = &par->nouveau_fb.base; | 277 | nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo); |
280 | /* setup helper */ | ||
281 | par->helper.fb = fb; | ||
282 | par->helper.fbdev = info; | ||
283 | par->helper.funcs = &nouveau_fbcon_helper_funcs; | ||
284 | par->helper.dev = dev; | ||
285 | 278 | ||
286 | *fbpar_p = par; | 279 | nouveau_fb = &nfbdev->nouveau_fb; |
280 | fb = &nouveau_fb->base; | ||
287 | 281 | ||
288 | ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 4); | 282 | /* setup helper */ |
289 | if (ret) | 283 | nfbdev->helper.fb = fb; |
290 | goto out_unref; | 284 | nfbdev->helper.fbdev = info; |
285 | nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs; | ||
291 | 286 | ||
292 | strcpy(info->fix.id, "nouveaufb"); | 287 | strcpy(info->fix.id, "nouveaufb"); |
293 | if (nouveau_nofbaccel) | 288 | if (nouveau_nofbaccel) |
@@ -305,7 +300,7 @@ nouveau_fbcon_create(struct drm_device *dev, | |||
305 | info->screen_size = size; | 300 | info->screen_size = size; |
306 | 301 | ||
307 | drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); | 302 | drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); |
308 | drm_fb_helper_fill_var(info, &par->helper, sizes->fb_width, sizes->fb_height); | 303 | drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height); |
309 | 304 | ||
310 | /* FIXME: we really shouldn't expose mmio space at all */ | 305 | /* FIXME: we really shouldn't expose mmio space at all */ |
311 | info->fix.mmio_start = pci_resource_start(dev->pdev, 1); | 306 | info->fix.mmio_start = pci_resource_start(dev->pdev, 1); |
@@ -338,8 +333,6 @@ nouveau_fbcon_create(struct drm_device *dev, | |||
338 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | 333 | info->pixmap.flags = FB_PIXMAP_SYSTEM; |
339 | info->pixmap.scan_align = 1; | 334 | info->pixmap.scan_align = 1; |
340 | 335 | ||
341 | par->dev = dev; | ||
342 | |||
343 | if (dev_priv->channel && !nouveau_nofbaccel) { | 336 | if (dev_priv->channel && !nouveau_nofbaccel) { |
344 | switch (dev_priv->card_type) { | 337 | switch (dev_priv->card_type) { |
345 | case NV_50: | 338 | case NV_50: |
@@ -353,7 +346,7 @@ nouveau_fbcon_create(struct drm_device *dev, | |||
353 | }; | 346 | }; |
354 | } | 347 | } |
355 | 348 | ||
356 | nouveau_fbcon_zfill(dev, par); | 349 | nouveau_fbcon_zfill(dev, nfbdev); |
357 | 350 | ||
358 | /* To allow resizeing without swapping buffers */ | 351 | /* To allow resizeing without swapping buffers */ |
359 | NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n", | 352 | NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n", |
@@ -372,66 +365,56 @@ out: | |||
372 | } | 365 | } |
373 | 366 | ||
374 | static int | 367 | static int |
375 | nouveau_fbcon_find_or_create_single(struct drm_device *dev, | 368 | nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper, |
376 | struct drm_fb_helper_surface_size *sizes, | 369 | struct drm_fb_helper_surface_size *sizes) |
377 | struct drm_fb_helper **fb_ptr) | ||
378 | { | 370 | { |
379 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 371 | struct nouveau_fbdev *nfbdev = (struct nouveau_fbdev *)helper; |
380 | struct nouveau_fbcon_par *fbpar; | ||
381 | int new_fb = 0; | 372 | int new_fb = 0; |
382 | int ret; | 373 | int ret; |
383 | 374 | ||
384 | if (!dev_priv->nfbdev) { | 375 | if (!helper->fb) { |
385 | ret = nouveau_fbcon_create(dev, sizes, | 376 | ret = nouveau_fbcon_create(nfbdev, sizes); |
386 | &fbpar); | ||
387 | if (ret) | 377 | if (ret) |
388 | return ret; | 378 | return ret; |
389 | dev_priv->nfbdev = fbpar; | ||
390 | new_fb = 1; | 379 | 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 | } | 380 | } |
399 | *fb_ptr = &fbpar->helper; | ||
400 | return new_fb; | 381 | return new_fb; |
401 | } | 382 | } |
402 | 383 | ||
403 | static int | 384 | static int |
404 | nouveau_fbcon_probe(struct drm_device *dev) | 385 | nouveau_fbcon_probe(struct nouveau_fbdev *nfbdev) |
405 | { | 386 | { |
406 | NV_DEBUG_KMS(dev, "\n"); | 387 | NV_DEBUG_KMS(nfbdev->dev, "\n"); |
407 | 388 | ||
408 | return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_find_or_create_single); | 389 | return drm_fb_helper_single_fb_probe(&nfbdev->helper, 32); |
409 | } | 390 | } |
410 | 391 | ||
411 | int | 392 | int |
412 | nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) | 393 | nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev) |
413 | { | 394 | { |
414 | struct nouveau_framebuffer *nouveau_fb = &fbpar->nouveau_fb; | 395 | struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb; |
415 | struct fb_info *info; | 396 | struct fb_info *info; |
416 | 397 | ||
417 | info = fbpar->helper.fbdev; | 398 | if (nfbdev->helper.fbdev) { |
418 | 399 | info = nfbdev->helper.fbdev; | |
419 | unregister_framebuffer(info); | 400 | unregister_framebuffer(info); |
420 | nouveau_bo_unmap(nouveau_fb->nvbo); | 401 | framebuffer_release(info); |
421 | drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); | 402 | } |
422 | nouveau_fb->nvbo = NULL; | ||
423 | drm_fb_helper_free(&fbpar->helper); | ||
424 | 403 | ||
404 | if (nouveau_fb->nvbo) { | ||
405 | nouveau_bo_unmap(nouveau_fb->nvbo); | ||
406 | drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); | ||
407 | nouveau_fb->nvbo = NULL; | ||
408 | } | ||
409 | drm_fb_helper_free(&nfbdev->helper); | ||
425 | drm_framebuffer_cleanup(&nouveau_fb->base); | 410 | drm_framebuffer_cleanup(&nouveau_fb->base); |
426 | framebuffer_release(info); | ||
427 | |||
428 | return 0; | 411 | return 0; |
429 | } | 412 | } |
430 | 413 | ||
431 | void nouveau_fbcon_gpu_lockup(struct fb_info *info) | 414 | void nouveau_fbcon_gpu_lockup(struct fb_info *info) |
432 | { | 415 | { |
433 | struct nouveau_fbcon_par *par = info->par; | 416 | struct nouveau_fbdev *nfbdev = info->par; |
434 | struct drm_device *dev = par->dev; | 417 | struct drm_device *dev = nfbdev->dev; |
435 | 418 | ||
436 | NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); | 419 | NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); |
437 | info->flags |= FBINFO_HWACCEL_DISABLED; | 420 | info->flags |= FBINFO_HWACCEL_DISABLED; |
@@ -439,15 +422,33 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info) | |||
439 | 422 | ||
440 | int nouveau_fbcon_init(struct drm_device *dev) | 423 | int nouveau_fbcon_init(struct drm_device *dev) |
441 | { | 424 | { |
442 | drm_helper_initial_config(dev); | 425 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
443 | nouveau_fbcon_probe(dev); | 426 | struct nouveau_fbdev *nfbdev; |
427 | |||
428 | nfbdev = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL); | ||
429 | if (!nfbdev) | ||
430 | return -ENOMEM; | ||
431 | |||
432 | nfbdev->dev = dev; | ||
433 | dev_priv->nfbdev = nfbdev; | ||
434 | |||
435 | drm_fb_helper_init_crtc_count(dev, &nfbdev->helper, | ||
436 | 2, 4); | ||
437 | nfbdev->helper.fb_probe = nouveau_fbcon_find_or_create_single; | ||
438 | drm_fb_helper_initial_config(&nfbdev->helper); | ||
439 | nouveau_fbcon_probe(nfbdev); | ||
444 | return 0; | 440 | return 0; |
445 | } | 441 | } |
446 | 442 | ||
447 | void nouveau_fbcon_fini(struct drm_device *dev) | 443 | void nouveau_fbcon_fini(struct drm_device *dev) |
448 | { | 444 | { |
449 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 445 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
446 | |||
447 | if (!dev_priv->nfbdev) | ||
448 | return; | ||
449 | |||
450 | nouveau_fbcon_destroy(dev, dev_priv->nfbdev); | 450 | nouveau_fbcon_destroy(dev, dev_priv->nfbdev); |
451 | kfree(dev_priv->nfbdev); | ||
451 | dev_priv->nfbdev = NULL; | 452 | dev_priv->nfbdev = NULL; |
452 | } | 453 | } |
453 | 454 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index fa66cb9fa4d4..7835b5685555 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h | |||
@@ -30,7 +30,7 @@ | |||
30 | #include "drm_fb_helper.h" | 30 | #include "drm_fb_helper.h" |
31 | 31 | ||
32 | #include "nouveau_fb.h" | 32 | #include "nouveau_fb.h" |
33 | struct nouveau_fbcon_par { | 33 | struct nouveau_fbdev { |
34 | struct drm_fb_helper helper; | 34 | struct drm_fb_helper helper; |
35 | struct nouveau_framebuffer nouveau_fb; | 35 | struct nouveau_framebuffer nouveau_fb; |
36 | struct list_head fbdev_list; | 36 | struct list_head fbdev_list; |
diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index 813b25cec726..603090ee6ac7 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c | |||
@@ -30,8 +30,8 @@ | |||
30 | void | 30 | void |
31 | nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) | 31 | nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) |
32 | { | 32 | { |
33 | struct nouveau_fbcon_par *par = info->par; | 33 | struct nouveau_fbdev *nfbdev = info->par; |
34 | struct drm_device *dev = par->dev; | 34 | struct drm_device *dev = nfbdev->dev; |
35 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 35 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
36 | struct nouveau_channel *chan = dev_priv->channel; | 36 | struct nouveau_channel *chan = dev_priv->channel; |
37 | 37 | ||
@@ -57,8 +57,8 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) | |||
57 | void | 57 | void |
58 | nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | 58 | nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) |
59 | { | 59 | { |
60 | struct nouveau_fbcon_par *par = info->par; | 60 | struct nouveau_fbdev *nfbdev = info->par; |
61 | struct drm_device *dev = par->dev; | 61 | struct drm_device *dev = nfbdev->dev; |
62 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 62 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
63 | struct nouveau_channel *chan = dev_priv->channel; | 63 | struct nouveau_channel *chan = dev_priv->channel; |
64 | 64 | ||
@@ -91,8 +91,8 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | |||
91 | void | 91 | void |
92 | nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) | 92 | nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) |
93 | { | 93 | { |
94 | struct nouveau_fbcon_par *par = info->par; | 94 | struct nouveau_fbdev *nfbdev = info->par; |
95 | struct drm_device *dev = par->dev; | 95 | struct drm_device *dev = nfbdev->dev; |
96 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 96 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
97 | struct nouveau_channel *chan = dev_priv->channel; | 97 | struct nouveau_channel *chan = dev_priv->channel; |
98 | uint32_t fg; | 98 | uint32_t fg; |
@@ -179,8 +179,8 @@ nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle) | |||
179 | int | 179 | int |
180 | nv04_fbcon_accel_init(struct fb_info *info) | 180 | nv04_fbcon_accel_init(struct fb_info *info) |
181 | { | 181 | { |
182 | struct nouveau_fbcon_par *par = info->par; | 182 | struct nouveau_fbdev *nfbdev = info->par; |
183 | struct drm_device *dev = par->dev; | 183 | struct drm_device *dev = nfbdev->dev; |
184 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 184 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
185 | struct nouveau_channel *chan = dev_priv->channel; | 185 | struct nouveau_channel *chan = dev_priv->channel; |
186 | const int sub = NvSubCtxSurf2D; | 186 | const int sub = NvSubCtxSurf2D; |
diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 25a3cd8794f9..f2410489cd35 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c | |||
@@ -6,8 +6,8 @@ | |||
6 | void | 6 | void |
7 | nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | 7 | nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) |
8 | { | 8 | { |
9 | struct nouveau_fbcon_par *par = info->par; | 9 | struct nouveau_fbdev *nfbdev = info->par; |
10 | struct drm_device *dev = par->dev; | 10 | struct drm_device *dev = nfbdev->dev; |
11 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 11 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
12 | struct nouveau_channel *chan = dev_priv->channel; | 12 | struct nouveau_channel *chan = dev_priv->channel; |
13 | 13 | ||
@@ -49,8 +49,8 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | |||
49 | void | 49 | void |
50 | nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) | 50 | nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) |
51 | { | 51 | { |
52 | struct nouveau_fbcon_par *par = info->par; | 52 | struct nouveau_fbdev *nfbdev = info->par; |
53 | struct drm_device *dev = par->dev; | 53 | struct drm_device *dev = nfbdev->dev; |
54 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 54 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
55 | struct nouveau_channel *chan = dev_priv->channel; | 55 | struct nouveau_channel *chan = dev_priv->channel; |
56 | 56 | ||
@@ -84,8 +84,8 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) | |||
84 | void | 84 | void |
85 | nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) | 85 | nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) |
86 | { | 86 | { |
87 | struct nouveau_fbcon_par *par = info->par; | 87 | struct nouveau_fbdev *nfbdev = info->par; |
88 | struct drm_device *dev = par->dev; | 88 | struct drm_device *dev = nfbdev->dev; |
89 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 89 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
90 | struct nouveau_channel *chan = dev_priv->channel; | 90 | struct nouveau_channel *chan = dev_priv->channel; |
91 | uint32_t width, dwords, *data = (uint32_t *)image->data; | 91 | uint32_t width, dwords, *data = (uint32_t *)image->data; |
@@ -152,8 +152,8 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) | |||
152 | int | 152 | int |
153 | nv50_fbcon_accel_init(struct fb_info *info) | 153 | nv50_fbcon_accel_init(struct fb_info *info) |
154 | { | 154 | { |
155 | struct nouveau_fbcon_par *par = info->par; | 155 | struct nouveau_fbdev *nfbdev = info->par; |
156 | struct drm_device *dev = par->dev; | 156 | struct drm_device *dev = nfbdev->dev; |
157 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 157 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
158 | struct nouveau_channel *chan = dev_priv->channel; | 158 | struct nouveau_channel *chan = dev_priv->channel; |
159 | struct nouveau_gpuobj *eng2d = NULL; | 159 | struct nouveau_gpuobj *eng2d = NULL; |
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index a7e4c2a89ee0..705425defba0 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c | |||
@@ -23,10 +23,6 @@ | |||
23 | * Authors: | 23 | * Authors: |
24 | * David Airlie | 24 | * David Airlie |
25 | */ | 25 | */ |
26 | /* | ||
27 | * Modularization | ||
28 | */ | ||
29 | |||
30 | #include <linux/module.h> | 26 | #include <linux/module.h> |
31 | #include <linux/fb.h> | 27 | #include <linux/fb.h> |
32 | 28 | ||
@@ -45,7 +41,7 @@ | |||
45 | this contains a helper + a radeon fb | 41 | this contains a helper + a radeon fb |
46 | the helper contains a pointer to radeon framebuffer baseclass. | 42 | the helper contains a pointer to radeon framebuffer baseclass. |
47 | */ | 43 | */ |
48 | struct radeon_kernel_fbdev { | 44 | struct radeon_fbdev { |
49 | struct drm_fb_helper helper; | 45 | struct drm_fb_helper helper; |
50 | struct radeon_framebuffer rfb; | 46 | struct radeon_framebuffer rfb; |
51 | struct list_head fbdev_list; | 47 | struct list_head fbdev_list; |
@@ -95,49 +91,44 @@ static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { | |||
95 | .gamma_get = radeon_crtc_fb_gamma_get, | 91 | .gamma_get = radeon_crtc_fb_gamma_get, |
96 | }; | 92 | }; |
97 | 93 | ||
98 | static int radeonfb_create(struct drm_device *dev, | 94 | static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj) |
99 | struct drm_fb_helper_surface_size *sizes, | ||
100 | struct radeon_kernel_fbdev **rfbdev_p) | ||
101 | { | 95 | { |
102 | struct radeon_device *rdev = dev->dev_private; | 96 | struct radeon_bo *rbo = gobj->driver_private; |
103 | struct fb_info *info; | 97 | int ret; |
104 | struct radeon_kernel_fbdev *rfbdev; | 98 | |
105 | struct drm_framebuffer *fb = NULL; | 99 | ret = radeon_bo_reserve(rbo, false); |
106 | struct drm_mode_fb_cmd mode_cmd; | 100 | if (likely(ret == 0)) { |
101 | radeon_bo_kunmap(rbo); | ||
102 | radeon_bo_unreserve(rbo); | ||
103 | } | ||
104 | drm_gem_object_unreference_unlocked(gobj); | ||
105 | } | ||
106 | |||
107 | static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, | ||
108 | struct drm_mode_fb_cmd *mode_cmd, | ||
109 | struct drm_gem_object **gobj_p) | ||
110 | { | ||
111 | struct radeon_device *rdev = rfbdev->rdev; | ||
107 | struct drm_gem_object *gobj = NULL; | 112 | struct drm_gem_object *gobj = NULL; |
108 | struct radeon_bo *rbo = NULL; | 113 | struct radeon_bo *rbo = NULL; |
109 | struct device *device = &rdev->pdev->dev; | ||
110 | int size, aligned_size, ret; | ||
111 | u64 fb_gpuaddr; | ||
112 | void *fbptr = NULL; | ||
113 | unsigned long tmp; | ||
114 | bool fb_tiled = false; /* useful for testing */ | 114 | bool fb_tiled = false; /* useful for testing */ |
115 | u32 tiling_flags = 0; | 115 | u32 tiling_flags = 0; |
116 | int ret; | ||
117 | int aligned_size, size; | ||
116 | 118 | ||
117 | mode_cmd.width = sizes->surface_width; | ||
118 | mode_cmd.height = sizes->surface_height; | ||
119 | |||
120 | /* avivo can't scanout real 24bpp */ | ||
121 | if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev)) | ||
122 | sizes->surface_bpp = 32; | ||
123 | |||
124 | mode_cmd.bpp = sizes->surface_bpp; | ||
125 | /* need to align pitch with crtc limits */ | 119 | /* need to align pitch with crtc limits */ |
126 | mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8); | 120 | mode_cmd->pitch = radeon_align_pitch(rdev, mode_cmd->width, mode_cmd->bpp, fb_tiled) * ((mode_cmd->bpp + 1) / 8); |
127 | mode_cmd.depth = sizes->surface_depth; | ||
128 | 121 | ||
129 | size = mode_cmd.pitch * mode_cmd.height; | 122 | size = mode_cmd->pitch * mode_cmd->height; |
130 | aligned_size = ALIGN(size, PAGE_SIZE); | 123 | aligned_size = ALIGN(size, PAGE_SIZE); |
131 | |||
132 | ret = radeon_gem_object_create(rdev, aligned_size, 0, | 124 | ret = radeon_gem_object_create(rdev, aligned_size, 0, |
133 | RADEON_GEM_DOMAIN_VRAM, | 125 | RADEON_GEM_DOMAIN_VRAM, |
134 | false, ttm_bo_type_kernel, | 126 | false, ttm_bo_type_kernel, |
135 | &gobj); | 127 | &gobj); |
136 | if (ret) { | 128 | if (ret) { |
137 | printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n", | 129 | printk(KERN_ERR "failed to allocate framebuffer (%d)\n", |
138 | sizes->surface_width, sizes->surface_height); | 130 | aligned_size); |
139 | ret = -ENOMEM; | 131 | return -ENOMEM; |
140 | goto out; | ||
141 | } | 132 | } |
142 | rbo = gobj->driver_private; | 133 | rbo = gobj->driver_private; |
143 | 134 | ||
@@ -145,7 +136,7 @@ static int radeonfb_create(struct drm_device *dev, | |||
145 | tiling_flags = RADEON_TILING_MACRO; | 136 | tiling_flags = RADEON_TILING_MACRO; |
146 | 137 | ||
147 | #ifdef __BIG_ENDIAN | 138 | #ifdef __BIG_ENDIAN |
148 | switch (mode_cmd.bpp) { | 139 | switch (mode_cmd->bpp) { |
149 | case 32: | 140 | case 32: |
150 | tiling_flags |= RADEON_TILING_SWAP_32BIT; | 141 | tiling_flags |= RADEON_TILING_SWAP_32BIT; |
151 | break; | 142 | break; |
@@ -158,54 +149,82 @@ static int radeonfb_create(struct drm_device *dev, | |||
158 | 149 | ||
159 | if (tiling_flags) { | 150 | if (tiling_flags) { |
160 | ret = radeon_bo_set_tiling_flags(rbo, | 151 | ret = radeon_bo_set_tiling_flags(rbo, |
161 | tiling_flags | RADEON_TILING_SURFACE, | 152 | tiling_flags | RADEON_TILING_SURFACE, |
162 | mode_cmd.pitch); | 153 | mode_cmd->pitch); |
163 | if (ret) | 154 | if (ret) |
164 | dev_err(rdev->dev, "FB failed to set tiling flags\n"); | 155 | dev_err(rdev->dev, "FB failed to set tiling flags\n"); |
165 | } | 156 | } |
166 | mutex_lock(&rdev->ddev->struct_mutex); | 157 | |
167 | 158 | ||
168 | ret = radeon_bo_reserve(rbo, false); | 159 | ret = radeon_bo_reserve(rbo, false); |
169 | if (unlikely(ret != 0)) | 160 | if (unlikely(ret != 0)) |
170 | goto out_unref; | 161 | goto out_unref; |
171 | ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr); | 162 | ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, NULL); |
172 | if (ret) { | 163 | if (ret) { |
173 | radeon_bo_unreserve(rbo); | 164 | radeon_bo_unreserve(rbo); |
174 | goto out_unref; | 165 | goto out_unref; |
175 | } | 166 | } |
176 | if (fb_tiled) | 167 | if (fb_tiled) |
177 | radeon_bo_check_tiling(rbo, 0, 0); | 168 | radeon_bo_check_tiling(rbo, 0, 0); |
178 | ret = radeon_bo_kmap(rbo, &fbptr); | 169 | ret = radeon_bo_kmap(rbo, NULL); |
179 | radeon_bo_unreserve(rbo); | 170 | radeon_bo_unreserve(rbo); |
180 | if (ret) { | 171 | if (ret) { |
181 | goto out_unref; | 172 | goto out_unref; |
182 | } | 173 | } |
183 | 174 | ||
184 | info = framebuffer_alloc(sizeof(struct radeon_kernel_fbdev), device); | 175 | *gobj_p = gobj; |
176 | return 0; | ||
177 | out_unref: | ||
178 | radeonfb_destroy_pinned_object(gobj); | ||
179 | *gobj_p = NULL; | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | static int radeonfb_create(struct radeon_fbdev *rfbdev, | ||
184 | struct drm_fb_helper_surface_size *sizes) | ||
185 | { | ||
186 | struct radeon_device *rdev = rfbdev->rdev; | ||
187 | struct fb_info *info; | ||
188 | struct drm_framebuffer *fb = NULL; | ||
189 | struct drm_mode_fb_cmd mode_cmd; | ||
190 | struct drm_gem_object *gobj = NULL; | ||
191 | struct radeon_bo *rbo = NULL; | ||
192 | struct device *device = &rdev->pdev->dev; | ||
193 | int ret; | ||
194 | unsigned long tmp; | ||
195 | |||
196 | mode_cmd.width = sizes->surface_width; | ||
197 | mode_cmd.height = sizes->surface_height; | ||
198 | |||
199 | /* avivo can't scanout real 24bpp */ | ||
200 | if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev)) | ||
201 | sizes->surface_bpp = 32; | ||
202 | |||
203 | mode_cmd.bpp = sizes->surface_bpp; | ||
204 | mode_cmd.depth = sizes->surface_depth; | ||
205 | |||
206 | ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj); | ||
207 | rbo = gobj->driver_private; | ||
208 | |||
209 | /* okay we have an object now allocate the framebuffer */ | ||
210 | info = framebuffer_alloc(0, device); | ||
185 | if (info == NULL) { | 211 | if (info == NULL) { |
186 | ret = -ENOMEM; | 212 | ret = -ENOMEM; |
187 | goto out_unref; | 213 | goto out_unref; |
188 | } | 214 | } |
189 | 215 | ||
190 | rfbdev = info->par; | 216 | info->par = rfbdev; |
191 | rfbdev->rdev = rdev; | 217 | |
192 | radeon_framebuffer_init(dev, &rfbdev->rfb, &mode_cmd, gobj); | 218 | radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj); |
219 | |||
193 | fb = &rfbdev->rfb.base; | 220 | fb = &rfbdev->rfb.base; |
194 | 221 | ||
195 | /* setup helper */ | 222 | /* setup helper */ |
196 | rfbdev->helper.fb = fb; | 223 | rfbdev->helper.fb = fb; |
197 | rfbdev->helper.fbdev = info; | 224 | rfbdev->helper.fbdev = info; |
198 | rfbdev->helper.funcs = &radeon_fb_helper_funcs; | 225 | rfbdev->helper.funcs = &radeon_fb_helper_funcs; |
199 | rfbdev->helper.dev = dev; | ||
200 | |||
201 | *rfbdev_p = rfbdev; | ||
202 | 226 | ||
203 | ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc, | 227 | memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo)); |
204 | RADEONFB_CONN_LIMIT); | ||
205 | if (ret) | ||
206 | goto out_unref; | ||
207 | |||
208 | memset_io(fbptr, 0x0, aligned_size); | ||
209 | 228 | ||
210 | strcpy(info->fix.id, "radeondrmfb"); | 229 | strcpy(info->fix.id, "radeondrmfb"); |
211 | 230 | ||
@@ -214,11 +233,11 @@ static int radeonfb_create(struct drm_device *dev, | |||
214 | info->flags = FBINFO_DEFAULT; | 233 | info->flags = FBINFO_DEFAULT; |
215 | info->fbops = &radeonfb_ops; | 234 | info->fbops = &radeonfb_ops; |
216 | 235 | ||
217 | tmp = fb_gpuaddr - rdev->mc.vram_start; | 236 | tmp = radeon_bo_gpu_offset(rbo) - rdev->mc.vram_start; |
218 | info->fix.smem_start = rdev->mc.aper_base + tmp; | 237 | info->fix.smem_start = rdev->mc.aper_base + tmp; |
219 | info->fix.smem_len = size; | 238 | info->fix.smem_len = radeon_bo_size(rbo); |
220 | info->screen_base = fbptr; | 239 | info->screen_base = rbo->kptr; |
221 | info->screen_size = size; | 240 | info->screen_size = radeon_bo_size(rbo); |
222 | 241 | ||
223 | drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height); | 242 | drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height); |
224 | 243 | ||
@@ -239,60 +258,40 @@ static int radeonfb_create(struct drm_device *dev, | |||
239 | } | 258 | } |
240 | DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); | 259 | DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); |
241 | DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); | 260 | DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); |
242 | DRM_INFO("size %lu\n", (unsigned long)size); | 261 | DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo)); |
243 | DRM_INFO("fb depth is %d\n", fb->depth); | 262 | DRM_INFO("fb depth is %d\n", fb->depth); |
244 | DRM_INFO(" pitch is %d\n", fb->pitch); | 263 | DRM_INFO(" pitch is %d\n", fb->pitch); |
245 | 264 | ||
246 | |||
247 | mutex_unlock(&rdev->ddev->struct_mutex); | ||
248 | vga_switcheroo_client_fb_set(rdev->ddev->pdev, info); | 265 | vga_switcheroo_client_fb_set(rdev->ddev->pdev, info); |
249 | return 0; | 266 | return 0; |
250 | 267 | ||
251 | out_unref: | 268 | out_unref: |
252 | if (rbo) { | 269 | if (rbo) { |
253 | ret = radeon_bo_reserve(rbo, false); | 270 | |
254 | if (likely(ret == 0)) { | ||
255 | radeon_bo_kunmap(rbo); | ||
256 | radeon_bo_unreserve(rbo); | ||
257 | } | ||
258 | } | 271 | } |
259 | if (fb && ret) { | 272 | if (fb && ret) { |
260 | drm_gem_object_unreference(gobj); | 273 | drm_gem_object_unreference(gobj); |
261 | drm_framebuffer_cleanup(fb); | 274 | drm_framebuffer_cleanup(fb); |
262 | kfree(fb); | 275 | kfree(fb); |
263 | } | 276 | } |
264 | drm_gem_object_unreference(gobj); | 277 | |
265 | mutex_unlock(&rdev->ddev->struct_mutex); | ||
266 | out: | 278 | out: |
267 | return ret; | 279 | return ret; |
268 | } | 280 | } |
269 | 281 | ||
270 | static int radeon_fb_find_or_create_single(struct drm_device *dev, | 282 | static int radeon_fb_find_or_create_single(struct drm_fb_helper *helper, |
271 | struct drm_fb_helper_surface_size *sizes, | 283 | struct drm_fb_helper_surface_size *sizes) |
272 | struct drm_fb_helper **fb_ptr) | ||
273 | { | 284 | { |
274 | struct radeon_device *rdev = dev->dev_private; | 285 | struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper; |
275 | struct radeon_kernel_fbdev *rfbdev = NULL; | ||
276 | int new_fb = 0; | 286 | int new_fb = 0; |
277 | int ret; | 287 | int ret; |
278 | 288 | ||
279 | if (!rdev->mode_info.rfbdev) { | 289 | if (!helper->fb) { |
280 | ret = radeonfb_create(dev, sizes, | 290 | ret = radeonfb_create(rfbdev, sizes); |
281 | &rfbdev); | ||
282 | if (ret) | 291 | if (ret) |
283 | return ret; | 292 | return ret; |
284 | rdev->mode_info.rfbdev = rfbdev; | ||
285 | new_fb = 1; | 293 | new_fb = 1; |
286 | } else { | ||
287 | rfbdev = rdev->mode_info.rfbdev; | ||
288 | if (rfbdev->rfb.base.width < sizes->surface_width || | ||
289 | rfbdev->rfb.base.height < sizes->surface_height) { | ||
290 | DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | } | 294 | } |
294 | |||
295 | *fb_ptr = &rfbdev->helper; | ||
296 | return new_fb; | 295 | return new_fb; |
297 | } | 296 | } |
298 | 297 | ||
@@ -312,48 +311,55 @@ int radeon_parse_options(char *options) | |||
312 | return 0; | 311 | return 0; |
313 | } | 312 | } |
314 | 313 | ||
315 | static int radeonfb_probe(struct drm_device *dev) | 314 | static int radeonfb_probe(struct radeon_fbdev *rfbdev) |
316 | { | 315 | { |
317 | struct radeon_device *rdev = dev->dev_private; | 316 | struct radeon_device *rdev = rfbdev->rdev; |
318 | int bpp_sel = 32; | 317 | int bpp_sel = 32; |
319 | 318 | ||
320 | /* select 8 bpp console on RN50 or 16MB cards */ | 319 | /* select 8 bpp console on RN50 or 16MB cards */ |
321 | if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) | 320 | if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) |
322 | bpp_sel = 8; | 321 | bpp_sel = 8; |
323 | 322 | ||
324 | return drm_fb_helper_single_fb_probe(dev, bpp_sel, &radeon_fb_find_or_create_single); | 323 | return drm_fb_helper_single_fb_probe(&rfbdev->helper, bpp_sel); |
325 | } | 324 | } |
326 | 325 | ||
327 | void radeonfb_hotplug(struct drm_device *dev) | 326 | void radeonfb_hotplug(struct drm_device *dev) |
328 | { | 327 | { |
329 | drm_helper_fb_hotplug_event(dev); | 328 | struct radeon_device *rdev = dev->dev_private; |
329 | int max_width, max_height; | ||
330 | |||
331 | max_width = rdev->mode_info.rfbdev->rfb.base.width; | ||
332 | max_height = rdev->mode_info.rfbdev->rfb.base.height; | ||
333 | drm_helper_fb_hotplug_event(&rdev->mode_info.rfbdev->helper, max_width, max_height); | ||
330 | 334 | ||
331 | radeonfb_probe(dev); | 335 | radeonfb_probe(rdev->mode_info.rfbdev); |
332 | } | 336 | } |
333 | 337 | ||
334 | static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_kernel_fbdev *rfbdev) | 338 | static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) |
335 | { | 339 | { |
336 | struct fb_info *info; | 340 | struct fb_info *info; |
337 | struct radeon_framebuffer *rfb = &rfbdev->rfb; | 341 | struct radeon_framebuffer *rfb = &rfbdev->rfb; |
338 | struct radeon_bo *rbo; | 342 | struct radeon_bo *rbo; |
339 | int r; | 343 | int r; |
340 | 344 | ||
341 | rbo = rfb->obj->driver_private; | 345 | if (rfbdev->helper.fbdev) { |
342 | info = rfbdev->helper.fbdev; | 346 | info = rfbdev->helper.fbdev; |
343 | unregister_framebuffer(info); | 347 | unregister_framebuffer(info); |
344 | r = radeon_bo_reserve(rbo, false); | 348 | framebuffer_release(info); |
345 | if (likely(r == 0)) { | ||
346 | radeon_bo_kunmap(rbo); | ||
347 | radeon_bo_unpin(rbo); | ||
348 | radeon_bo_unreserve(rbo); | ||
349 | } | 349 | } |
350 | 350 | ||
351 | if (rfb->obj) { | ||
352 | rbo = rfb->obj->driver_private; | ||
353 | r = radeon_bo_reserve(rbo, false); | ||
354 | if (likely(r == 0)) { | ||
355 | radeon_bo_kunmap(rbo); | ||
356 | radeon_bo_unpin(rbo); | ||
357 | radeon_bo_unreserve(rbo); | ||
358 | } | ||
359 | drm_gem_object_unreference_unlocked(rfb->obj); | ||
360 | } | ||
351 | drm_fb_helper_free(&rfbdev->helper); | 361 | drm_fb_helper_free(&rfbdev->helper); |
352 | drm_framebuffer_cleanup(&rfb->base); | 362 | drm_framebuffer_cleanup(&rfb->base); |
353 | if (rfb->obj) | ||
354 | drm_gem_object_unreference_unlocked(rfb->obj); | ||
355 | |||
356 | framebuffer_release(info); | ||
357 | 363 | ||
358 | return 0; | 364 | return 0; |
359 | } | 365 | } |
@@ -361,14 +367,32 @@ MODULE_LICENSE("GPL"); | |||
361 | 367 | ||
362 | int radeon_fbdev_init(struct radeon_device *rdev) | 368 | int radeon_fbdev_init(struct radeon_device *rdev) |
363 | { | 369 | { |
364 | drm_helper_initial_config(rdev->ddev); | 370 | struct radeon_fbdev *rfbdev; |
365 | radeonfb_probe(rdev->ddev); | 371 | |
372 | rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL); | ||
373 | if (!rfbdev) | ||
374 | return -ENOMEM; | ||
375 | |||
376 | rfbdev->rdev = rdev; | ||
377 | rdev->mode_info.rfbdev = rfbdev; | ||
378 | |||
379 | drm_fb_helper_init_crtc_count(rdev->ddev, &rfbdev->helper, | ||
380 | rdev->num_crtc, | ||
381 | RADEONFB_CONN_LIMIT); | ||
382 | rfbdev->helper.fb_probe = radeon_fb_find_or_create_single; | ||
383 | drm_fb_helper_initial_config(&rfbdev->helper); | ||
384 | radeonfb_probe(rfbdev); | ||
366 | return 0; | 385 | return 0; |
386 | |||
367 | } | 387 | } |
368 | 388 | ||
369 | void radeon_fbdev_fini(struct radeon_device *rdev) | 389 | void radeon_fbdev_fini(struct radeon_device *rdev) |
370 | { | 390 | { |
391 | if (!rdev->mode_info.rfbdev) | ||
392 | return; | ||
393 | |||
371 | radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev); | 394 | radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev); |
395 | kfree(rdev->mode_info.rfbdev); | ||
372 | rdev->mode_info.rfbdev = NULL; | 396 | rdev->mode_info.rfbdev = NULL; |
373 | } | 397 | } |
374 | 398 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 1e9138bf5592..165f6025a3bc 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -203,7 +203,7 @@ enum radeon_dvo_chip { | |||
203 | DVO_SIL1178, | 203 | DVO_SIL1178, |
204 | }; | 204 | }; |
205 | 205 | ||
206 | struct radeon_kernel_fbdev; | 206 | struct radeon_fbdev; |
207 | 207 | ||
208 | struct radeon_mode_info { | 208 | struct radeon_mode_info { |
209 | struct atom_context *atom_context; | 209 | struct atom_context *atom_context; |
@@ -223,7 +223,7 @@ struct radeon_mode_info { | |||
223 | struct edid *bios_hardcoded_edid; | 223 | struct edid *bios_hardcoded_edid; |
224 | 224 | ||
225 | /* pointer to fbdev info structure */ | 225 | /* pointer to fbdev info structure */ |
226 | struct radeon_kernel_fbdev *rfbdev; | 226 | struct radeon_fbdev *rfbdev; |
227 | }; | 227 | }; |
228 | 228 | ||
229 | #define MAX_H_CODE_TIMING_LEN 32 | 229 | #define MAX_H_CODE_TIMING_LEN 32 |