diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_fbdev.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_fbdev.c | 85 |
1 files changed, 51 insertions, 34 deletions
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 4babefc51eb2..86b00c6db1a6 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c | |||
@@ -362,23 +362,24 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
362 | bool *enabled, int width, int height) | 362 | bool *enabled, int width, int height) |
363 | { | 363 | { |
364 | struct drm_device *dev = fb_helper->dev; | 364 | struct drm_device *dev = fb_helper->dev; |
365 | unsigned long conn_configured, mask; | ||
366 | unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG); | ||
365 | int i, j; | 367 | int i, j; |
366 | bool *save_enabled; | 368 | bool *save_enabled; |
367 | bool fallback = true; | 369 | bool fallback = true; |
368 | int num_connectors_enabled = 0; | 370 | int num_connectors_enabled = 0; |
369 | int num_connectors_detected = 0; | 371 | int num_connectors_detected = 0; |
370 | uint64_t conn_configured = 0, mask; | ||
371 | int pass = 0; | 372 | int pass = 0; |
372 | 373 | ||
373 | save_enabled = kcalloc(fb_helper->connector_count, sizeof(bool), | 374 | save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL); |
374 | GFP_KERNEL); | ||
375 | if (!save_enabled) | 375 | if (!save_enabled) |
376 | return false; | 376 | return false; |
377 | 377 | ||
378 | memcpy(save_enabled, enabled, fb_helper->connector_count); | 378 | memcpy(save_enabled, enabled, count); |
379 | mask = (1 << fb_helper->connector_count) - 1; | 379 | mask = BIT(count) - 1; |
380 | conn_configured = 0; | ||
380 | retry: | 381 | retry: |
381 | for (i = 0; i < fb_helper->connector_count; i++) { | 382 | for (i = 0; i < count; i++) { |
382 | struct drm_fb_helper_connector *fb_conn; | 383 | struct drm_fb_helper_connector *fb_conn; |
383 | struct drm_connector *connector; | 384 | struct drm_connector *connector; |
384 | struct drm_encoder *encoder; | 385 | struct drm_encoder *encoder; |
@@ -388,7 +389,7 @@ retry: | |||
388 | fb_conn = fb_helper->connector_info[i]; | 389 | fb_conn = fb_helper->connector_info[i]; |
389 | connector = fb_conn->connector; | 390 | connector = fb_conn->connector; |
390 | 391 | ||
391 | if (conn_configured & (1 << i)) | 392 | if (conn_configured & BIT(i)) |
392 | continue; | 393 | continue; |
393 | 394 | ||
394 | if (pass == 0 && !connector->has_tile) | 395 | if (pass == 0 && !connector->has_tile) |
@@ -400,7 +401,7 @@ retry: | |||
400 | if (!enabled[i]) { | 401 | if (!enabled[i]) { |
401 | DRM_DEBUG_KMS("connector %s not enabled, skipping\n", | 402 | DRM_DEBUG_KMS("connector %s not enabled, skipping\n", |
402 | connector->name); | 403 | connector->name); |
403 | conn_configured |= (1 << i); | 404 | conn_configured |= BIT(i); |
404 | continue; | 405 | continue; |
405 | } | 406 | } |
406 | 407 | ||
@@ -419,7 +420,7 @@ retry: | |||
419 | DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", | 420 | DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", |
420 | connector->name); | 421 | connector->name); |
421 | enabled[i] = false; | 422 | enabled[i] = false; |
422 | conn_configured |= (1 << i); | 423 | conn_configured |= BIT(i); |
423 | continue; | 424 | continue; |
424 | } | 425 | } |
425 | 426 | ||
@@ -432,14 +433,15 @@ retry: | |||
432 | intel_crtc->lut_b[j] = j; | 433 | intel_crtc->lut_b[j] = j; |
433 | } | 434 | } |
434 | 435 | ||
435 | new_crtc = intel_fb_helper_crtc(fb_helper, connector->state->crtc); | 436 | new_crtc = intel_fb_helper_crtc(fb_helper, |
437 | connector->state->crtc); | ||
436 | 438 | ||
437 | /* | 439 | /* |
438 | * Make sure we're not trying to drive multiple connectors | 440 | * Make sure we're not trying to drive multiple connectors |
439 | * with a single CRTC, since our cloning support may not | 441 | * with a single CRTC, since our cloning support may not |
440 | * match the BIOS. | 442 | * match the BIOS. |
441 | */ | 443 | */ |
442 | for (j = 0; j < fb_helper->connector_count; j++) { | 444 | for (j = 0; j < count; j++) { |
443 | if (crtcs[j] == new_crtc) { | 445 | if (crtcs[j] == new_crtc) { |
444 | DRM_DEBUG_KMS("fallback: cloned configuration\n"); | 446 | DRM_DEBUG_KMS("fallback: cloned configuration\n"); |
445 | goto bail; | 447 | goto bail; |
@@ -498,7 +500,7 @@ retry: | |||
498 | modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :""); | 500 | modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :""); |
499 | 501 | ||
500 | fallback = false; | 502 | fallback = false; |
501 | conn_configured |= (1 << i); | 503 | conn_configured |= BIT(i); |
502 | } | 504 | } |
503 | 505 | ||
504 | if ((conn_configured & mask) != mask) { | 506 | if ((conn_configured & mask) != mask) { |
@@ -522,7 +524,7 @@ retry: | |||
522 | if (fallback) { | 524 | if (fallback) { |
523 | bail: | 525 | bail: |
524 | DRM_DEBUG_KMS("Not using firmware configuration\n"); | 526 | DRM_DEBUG_KMS("Not using firmware configuration\n"); |
525 | memcpy(enabled, save_enabled, fb_helper->connector_count); | 527 | memcpy(enabled, save_enabled, count); |
526 | kfree(save_enabled); | 528 | kfree(save_enabled); |
527 | return false; | 529 | return false; |
528 | } | 530 | } |
@@ -538,8 +540,7 @@ static const struct drm_fb_helper_funcs intel_fb_helper_funcs = { | |||
538 | .fb_probe = intelfb_create, | 540 | .fb_probe = intelfb_create, |
539 | }; | 541 | }; |
540 | 542 | ||
541 | static void intel_fbdev_destroy(struct drm_device *dev, | 543 | static void intel_fbdev_destroy(struct intel_fbdev *ifbdev) |
542 | struct intel_fbdev *ifbdev) | ||
543 | { | 544 | { |
544 | /* We rely on the object-free to release the VMA pinning for | 545 | /* We rely on the object-free to release the VMA pinning for |
545 | * the info->screen_base mmaping. Leaking the VMA is simpler than | 546 | * the info->screen_base mmaping. Leaking the VMA is simpler than |
@@ -552,12 +553,14 @@ static void intel_fbdev_destroy(struct drm_device *dev, | |||
552 | drm_fb_helper_fini(&ifbdev->helper); | 553 | drm_fb_helper_fini(&ifbdev->helper); |
553 | 554 | ||
554 | if (ifbdev->fb) { | 555 | if (ifbdev->fb) { |
555 | mutex_lock(&dev->struct_mutex); | 556 | mutex_lock(&ifbdev->helper.dev->struct_mutex); |
556 | intel_unpin_fb_obj(&ifbdev->fb->base, BIT(DRM_ROTATE_0)); | 557 | intel_unpin_fb_obj(&ifbdev->fb->base, BIT(DRM_ROTATE_0)); |
557 | mutex_unlock(&dev->struct_mutex); | 558 | mutex_unlock(&ifbdev->helper.dev->struct_mutex); |
558 | 559 | ||
559 | drm_framebuffer_remove(&ifbdev->fb->base); | 560 | drm_framebuffer_remove(&ifbdev->fb->base); |
560 | } | 561 | } |
562 | |||
563 | kfree(ifbdev); | ||
561 | } | 564 | } |
562 | 565 | ||
563 | /* | 566 | /* |
@@ -690,9 +693,9 @@ out: | |||
690 | 693 | ||
691 | static void intel_fbdev_suspend_worker(struct work_struct *work) | 694 | static void intel_fbdev_suspend_worker(struct work_struct *work) |
692 | { | 695 | { |
693 | intel_fbdev_set_suspend(container_of(work, | 696 | intel_fbdev_set_suspend(&container_of(work, |
694 | struct drm_i915_private, | 697 | struct drm_i915_private, |
695 | fbdev_suspend_work)->dev, | 698 | fbdev_suspend_work)->drm, |
696 | FBINFO_STATE_RUNNING, | 699 | FBINFO_STATE_RUNNING, |
697 | true); | 700 | true); |
698 | } | 701 | } |
@@ -700,7 +703,7 @@ static void intel_fbdev_suspend_worker(struct work_struct *work) | |||
700 | int intel_fbdev_init(struct drm_device *dev) | 703 | int intel_fbdev_init(struct drm_device *dev) |
701 | { | 704 | { |
702 | struct intel_fbdev *ifbdev; | 705 | struct intel_fbdev *ifbdev; |
703 | struct drm_i915_private *dev_priv = dev->dev_private; | 706 | struct drm_i915_private *dev_priv = to_i915(dev); |
704 | int ret; | 707 | int ret; |
705 | 708 | ||
706 | if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0)) | 709 | if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0)) |
@@ -732,38 +735,50 @@ int intel_fbdev_init(struct drm_device *dev) | |||
732 | 735 | ||
733 | static void intel_fbdev_initial_config(void *data, async_cookie_t cookie) | 736 | static void intel_fbdev_initial_config(void *data, async_cookie_t cookie) |
734 | { | 737 | { |
735 | struct drm_i915_private *dev_priv = data; | 738 | struct intel_fbdev *ifbdev = data; |
736 | struct intel_fbdev *ifbdev = dev_priv->fbdev; | ||
737 | 739 | ||
738 | /* Due to peculiar init order wrt to hpd handling this is separate. */ | 740 | /* Due to peculiar init order wrt to hpd handling this is separate. */ |
739 | if (drm_fb_helper_initial_config(&ifbdev->helper, | 741 | if (drm_fb_helper_initial_config(&ifbdev->helper, |
740 | ifbdev->preferred_bpp)) | 742 | ifbdev->preferred_bpp)) |
741 | intel_fbdev_fini(dev_priv->dev); | 743 | intel_fbdev_fini(ifbdev->helper.dev); |
742 | } | 744 | } |
743 | 745 | ||
744 | void intel_fbdev_initial_config_async(struct drm_device *dev) | 746 | void intel_fbdev_initial_config_async(struct drm_device *dev) |
745 | { | 747 | { |
746 | async_schedule(intel_fbdev_initial_config, to_i915(dev)); | 748 | struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; |
749 | |||
750 | ifbdev->cookie = async_schedule(intel_fbdev_initial_config, ifbdev); | ||
751 | } | ||
752 | |||
753 | static void intel_fbdev_sync(struct intel_fbdev *ifbdev) | ||
754 | { | ||
755 | if (!ifbdev->cookie) | ||
756 | return; | ||
757 | |||
758 | /* Only serialises with all preceding async calls, hence +1 */ | ||
759 | async_synchronize_cookie(ifbdev->cookie + 1); | ||
760 | ifbdev->cookie = 0; | ||
747 | } | 761 | } |
748 | 762 | ||
749 | void intel_fbdev_fini(struct drm_device *dev) | 763 | void intel_fbdev_fini(struct drm_device *dev) |
750 | { | 764 | { |
751 | struct drm_i915_private *dev_priv = dev->dev_private; | 765 | struct drm_i915_private *dev_priv = to_i915(dev); |
752 | if (!dev_priv->fbdev) | 766 | struct intel_fbdev *ifbdev = dev_priv->fbdev; |
767 | |||
768 | if (!ifbdev) | ||
753 | return; | 769 | return; |
754 | 770 | ||
755 | flush_work(&dev_priv->fbdev_suspend_work); | 771 | flush_work(&dev_priv->fbdev_suspend_work); |
756 | |||
757 | if (!current_is_async()) | 772 | if (!current_is_async()) |
758 | async_synchronize_full(); | 773 | intel_fbdev_sync(ifbdev); |
759 | intel_fbdev_destroy(dev, dev_priv->fbdev); | 774 | |
760 | kfree(dev_priv->fbdev); | 775 | intel_fbdev_destroy(ifbdev); |
761 | dev_priv->fbdev = NULL; | 776 | dev_priv->fbdev = NULL; |
762 | } | 777 | } |
763 | 778 | ||
764 | void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous) | 779 | void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous) |
765 | { | 780 | { |
766 | struct drm_i915_private *dev_priv = dev->dev_private; | 781 | struct drm_i915_private *dev_priv = to_i915(dev); |
767 | struct intel_fbdev *ifbdev = dev_priv->fbdev; | 782 | struct intel_fbdev *ifbdev = dev_priv->fbdev; |
768 | struct fb_info *info; | 783 | struct fb_info *info; |
769 | 784 | ||
@@ -812,7 +827,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous | |||
812 | 827 | ||
813 | void intel_fbdev_output_poll_changed(struct drm_device *dev) | 828 | void intel_fbdev_output_poll_changed(struct drm_device *dev) |
814 | { | 829 | { |
815 | struct drm_i915_private *dev_priv = dev->dev_private; | 830 | struct drm_i915_private *dev_priv = to_i915(dev); |
816 | if (dev_priv->fbdev) | 831 | if (dev_priv->fbdev) |
817 | drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); | 832 | drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); |
818 | } | 833 | } |
@@ -820,13 +835,15 @@ void intel_fbdev_output_poll_changed(struct drm_device *dev) | |||
820 | void intel_fbdev_restore_mode(struct drm_device *dev) | 835 | void intel_fbdev_restore_mode(struct drm_device *dev) |
821 | { | 836 | { |
822 | int ret; | 837 | int ret; |
823 | struct drm_i915_private *dev_priv = dev->dev_private; | 838 | struct drm_i915_private *dev_priv = to_i915(dev); |
824 | struct intel_fbdev *ifbdev = dev_priv->fbdev; | 839 | struct intel_fbdev *ifbdev = dev_priv->fbdev; |
825 | struct drm_fb_helper *fb_helper; | 840 | struct drm_fb_helper *fb_helper; |
826 | 841 | ||
827 | if (!ifbdev) | 842 | if (!ifbdev) |
828 | return; | 843 | return; |
829 | 844 | ||
845 | intel_fbdev_sync(ifbdev); | ||
846 | |||
830 | fb_helper = &ifbdev->helper; | 847 | fb_helper = &ifbdev->helper; |
831 | 848 | ||
832 | ret = drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); | 849 | ret = drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); |