diff options
author | Dave Airlie <airlied@redhat.com> | 2010-03-30 01:34:14 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-04-06 20:24:56 -0400 |
commit | 8be48d924c307e72e3797ab5bde81b07a1ccc52d (patch) | |
tree | 7d2fec8d40b0a6e9f7bd8a5aef5bb100783ecd44 | |
parent | 386516744ba45d50f42c6999151cc210cb4f96e4 (diff) |
drm/kms/fb: move to using fb helper crtc grouping instead of core crtc list
This move to using the list of crtcs in the fb helper and cleans up the
whole picking code, now we store the crtc/connectors we want directly
into the modeset and we use the modeset directly to set the mode.
Fixes from James Simmons and Ben Skeggs.
Signed-off-by: Dave Airlie <airlied@redhat.com>
-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 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 5 | ||||
-rw-r--r-- | include/drm/drm_fb_helper.h | 21 |
13 files changed, 411 insertions, 447 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 |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c70814b184e8..e4e34bae22cd 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -367,9 +367,6 @@ struct drm_crtc_funcs { | |||
367 | * @enabled: is this CRTC enabled? | 367 | * @enabled: is this CRTC enabled? |
368 | * @x: x position on screen | 368 | * @x: x position on screen |
369 | * @y: y position on screen | 369 | * @y: y position on screen |
370 | * @desired_mode: new desired mode | ||
371 | * @desired_x: desired x for desired_mode | ||
372 | * @desired_y: desired y for desired_mode | ||
373 | * @funcs: CRTC control functions | 370 | * @funcs: CRTC control functions |
374 | * | 371 | * |
375 | * Each CRTC may have one or more connectors associated with it. This structure | 372 | * Each CRTC may have one or more connectors associated with it. This structure |
@@ -389,8 +386,6 @@ struct drm_crtc { | |||
389 | struct drm_display_mode mode; | 386 | struct drm_display_mode mode; |
390 | 387 | ||
391 | int x, y; | 388 | int x, y; |
392 | struct drm_display_mode *desired_mode; | ||
393 | int desired_x, desired_y; | ||
394 | const struct drm_crtc_funcs *funcs; | 389 | const struct drm_crtc_funcs *funcs; |
395 | 390 | ||
396 | /* CRTC gamma size for reporting to userspace */ | 391 | /* CRTC gamma size for reporting to userspace */ |
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 38ab0daffd1f..b1ea66f11ded 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h | |||
@@ -33,6 +33,7 @@ | |||
33 | struct drm_fb_helper_crtc { | 33 | struct drm_fb_helper_crtc { |
34 | uint32_t crtc_id; | 34 | uint32_t crtc_id; |
35 | struct drm_mode_set mode_set; | 35 | struct drm_mode_set mode_set; |
36 | struct drm_display_mode *desired_mode; | ||
36 | }; | 37 | }; |
37 | 38 | ||
38 | 39 | ||
@@ -81,14 +82,16 @@ struct drm_fb_helper { | |||
81 | struct fb_info *fbdev; | 82 | struct fb_info *fbdev; |
82 | u32 pseudo_palette[17]; | 83 | u32 pseudo_palette[17]; |
83 | struct list_head kernel_fb_list; | 84 | struct list_head kernel_fb_list; |
85 | |||
86 | int (*fb_probe)(struct drm_fb_helper *helper, | ||
87 | struct drm_fb_helper_surface_size *sizes); | ||
84 | }; | 88 | }; |
85 | 89 | ||
86 | int drm_fb_helper_single_fb_probe(struct drm_device *dev, | 90 | int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper, |
87 | int preferred_bpp, | 91 | int preferred_bpp); |
88 | int (*fb_create)(struct drm_device *dev, | 92 | |
89 | struct drm_fb_helper_surface_size *sizes, | 93 | int drm_fb_helper_init_crtc_count(struct drm_device *dev, |
90 | struct drm_fb_helper **fb_ptr)); | 94 | struct drm_fb_helper *helper, int crtc_count, |
91 | int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, | ||
92 | int max_conn); | 95 | int max_conn); |
93 | void drm_fb_helper_free(struct drm_fb_helper *helper); | 96 | void drm_fb_helper_free(struct drm_fb_helper *helper); |
94 | int drm_fb_helper_blank(int blank, struct fb_info *info); | 97 | int drm_fb_helper_blank(int blank, struct fb_info *info); |
@@ -114,6 +117,8 @@ int drm_fb_helper_add_connector(struct drm_connector *connector); | |||
114 | int drm_fb_helper_parse_command_line(struct drm_device *dev); | 117 | int drm_fb_helper_parse_command_line(struct drm_device *dev); |
115 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); | 118 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); |
116 | 119 | ||
117 | bool drm_helper_fb_hotplug_event(struct drm_device *dev); | 120 | bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, u32 max_width, |
118 | bool drm_helper_initial_config(struct drm_device *dev); | 121 | u32 max_height); |
122 | bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); | ||
123 | |||
119 | #endif | 124 | #endif |