diff options
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 144 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 1 |
2 files changed, 128 insertions, 17 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e1fcd89562df..a47e5ee5dcaa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -5481,6 +5481,92 @@ static struct drm_display_mode load_detect_mode = { | |||
5481 | 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | 5481 | 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
5482 | }; | 5482 | }; |
5483 | 5483 | ||
5484 | static struct drm_framebuffer * | ||
5485 | intel_framebuffer_create(struct drm_device *dev, | ||
5486 | struct drm_mode_fb_cmd *mode_cmd, | ||
5487 | struct drm_i915_gem_object *obj) | ||
5488 | { | ||
5489 | struct intel_framebuffer *intel_fb; | ||
5490 | int ret; | ||
5491 | |||
5492 | intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); | ||
5493 | if (!intel_fb) { | ||
5494 | drm_gem_object_unreference_unlocked(&obj->base); | ||
5495 | return ERR_PTR(-ENOMEM); | ||
5496 | } | ||
5497 | |||
5498 | ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); | ||
5499 | if (ret) { | ||
5500 | drm_gem_object_unreference_unlocked(&obj->base); | ||
5501 | kfree(intel_fb); | ||
5502 | return ERR_PTR(ret); | ||
5503 | } | ||
5504 | |||
5505 | return &intel_fb->base; | ||
5506 | } | ||
5507 | |||
5508 | static u32 | ||
5509 | intel_framebuffer_pitch_for_width(int width, int bpp) | ||
5510 | { | ||
5511 | u32 pitch = DIV_ROUND_UP(width * bpp, 8); | ||
5512 | return ALIGN(pitch, 64); | ||
5513 | } | ||
5514 | |||
5515 | static u32 | ||
5516 | intel_framebuffer_size_for_mode(struct drm_display_mode *mode, int bpp) | ||
5517 | { | ||
5518 | u32 pitch = intel_framebuffer_pitch_for_width(mode->hdisplay, bpp); | ||
5519 | return ALIGN(pitch * mode->vdisplay, PAGE_SIZE); | ||
5520 | } | ||
5521 | |||
5522 | static struct drm_framebuffer * | ||
5523 | intel_framebuffer_create_for_mode(struct drm_device *dev, | ||
5524 | struct drm_display_mode *mode, | ||
5525 | int depth, int bpp) | ||
5526 | { | ||
5527 | struct drm_i915_gem_object *obj; | ||
5528 | struct drm_mode_fb_cmd mode_cmd; | ||
5529 | |||
5530 | obj = i915_gem_alloc_object(dev, | ||
5531 | intel_framebuffer_size_for_mode(mode, bpp)); | ||
5532 | if (obj == NULL) | ||
5533 | return ERR_PTR(-ENOMEM); | ||
5534 | |||
5535 | mode_cmd.width = mode->hdisplay; | ||
5536 | mode_cmd.height = mode->vdisplay; | ||
5537 | mode_cmd.depth = depth; | ||
5538 | mode_cmd.bpp = bpp; | ||
5539 | mode_cmd.pitch = intel_framebuffer_pitch_for_width(mode_cmd.width, bpp); | ||
5540 | |||
5541 | return intel_framebuffer_create(dev, &mode_cmd, obj); | ||
5542 | } | ||
5543 | |||
5544 | static struct drm_framebuffer * | ||
5545 | mode_fits_in_fbdev(struct drm_device *dev, | ||
5546 | struct drm_display_mode *mode) | ||
5547 | { | ||
5548 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
5549 | struct drm_i915_gem_object *obj; | ||
5550 | struct drm_framebuffer *fb; | ||
5551 | |||
5552 | if (dev_priv->fbdev == NULL) | ||
5553 | return NULL; | ||
5554 | |||
5555 | obj = dev_priv->fbdev->ifb.obj; | ||
5556 | if (obj == NULL) | ||
5557 | return NULL; | ||
5558 | |||
5559 | fb = &dev_priv->fbdev->ifb.base; | ||
5560 | if (fb->pitch < intel_framebuffer_pitch_for_width(mode->hdisplay, | ||
5561 | fb->bits_per_pixel)) | ||
5562 | return NULL; | ||
5563 | |||
5564 | if (obj->base.size < mode->vdisplay * fb->pitch) | ||
5565 | return NULL; | ||
5566 | |||
5567 | return fb; | ||
5568 | } | ||
5569 | |||
5484 | bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, | 5570 | bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, |
5485 | struct drm_connector *connector, | 5571 | struct drm_connector *connector, |
5486 | struct drm_display_mode *mode, | 5572 | struct drm_display_mode *mode, |
@@ -5491,8 +5577,13 @@ bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, | |||
5491 | struct drm_encoder *encoder = &intel_encoder->base; | 5577 | struct drm_encoder *encoder = &intel_encoder->base; |
5492 | struct drm_crtc *crtc = NULL; | 5578 | struct drm_crtc *crtc = NULL; |
5493 | struct drm_device *dev = encoder->dev; | 5579 | struct drm_device *dev = encoder->dev; |
5580 | struct drm_framebuffer *old_fb; | ||
5494 | int i = -1; | 5581 | int i = -1; |
5495 | 5582 | ||
5583 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", | ||
5584 | connector->base.id, drm_get_connector_name(connector), | ||
5585 | encoder->base.id, drm_get_encoder_name(encoder)); | ||
5586 | |||
5496 | /* | 5587 | /* |
5497 | * Algorithm gets a little messy: | 5588 | * Algorithm gets a little messy: |
5498 | * | 5589 | * |
@@ -5551,12 +5642,38 @@ bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, | |||
5551 | intel_crtc = to_intel_crtc(crtc); | 5642 | intel_crtc = to_intel_crtc(crtc); |
5552 | old->dpms_mode = intel_crtc->dpms_mode; | 5643 | old->dpms_mode = intel_crtc->dpms_mode; |
5553 | old->load_detect_temp = true; | 5644 | old->load_detect_temp = true; |
5645 | old->release_fb = NULL; | ||
5554 | 5646 | ||
5555 | if (!mode) | 5647 | if (!mode) |
5556 | mode = &load_detect_mode; | 5648 | mode = &load_detect_mode; |
5557 | 5649 | ||
5558 | if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb)) { | 5650 | old_fb = crtc->fb; |
5651 | |||
5652 | /* We need a framebuffer large enough to accommodate all accesses | ||
5653 | * that the plane may generate whilst we perform load detection. | ||
5654 | * We can not rely on the fbcon either being present (we get called | ||
5655 | * during its initialisation to detect all boot displays, or it may | ||
5656 | * not even exist) or that it is large enough to satisfy the | ||
5657 | * requested mode. | ||
5658 | */ | ||
5659 | crtc->fb = mode_fits_in_fbdev(dev, mode); | ||
5660 | if (crtc->fb == NULL) { | ||
5661 | DRM_DEBUG_KMS("creating tmp fb for load-detection\n"); | ||
5662 | crtc->fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32); | ||
5663 | old->release_fb = crtc->fb; | ||
5664 | } else | ||
5665 | DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); | ||
5666 | if (IS_ERR(crtc->fb)) { | ||
5667 | DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); | ||
5668 | crtc->fb = old_fb; | ||
5669 | return false; | ||
5670 | } | ||
5671 | |||
5672 | if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_fb)) { | ||
5559 | DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); | 5673 | DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); |
5674 | if (old->release_fb) | ||
5675 | old->release_fb->funcs->destroy(old->release_fb); | ||
5676 | crtc->fb = old_fb; | ||
5560 | return false; | 5677 | return false; |
5561 | } | 5678 | } |
5562 | 5679 | ||
@@ -5576,9 +5693,17 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, | |||
5576 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | 5693 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
5577 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | 5694 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
5578 | 5695 | ||
5696 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", | ||
5697 | connector->base.id, drm_get_connector_name(connector), | ||
5698 | encoder->base.id, drm_get_encoder_name(encoder)); | ||
5699 | |||
5579 | if (old->load_detect_temp) { | 5700 | if (old->load_detect_temp) { |
5580 | connector->encoder = NULL; | 5701 | connector->encoder = NULL; |
5581 | drm_helper_disable_unused_functions(dev); | 5702 | drm_helper_disable_unused_functions(dev); |
5703 | |||
5704 | if (old->release_fb) | ||
5705 | old->release_fb->funcs->destroy(old->release_fb); | ||
5706 | |||
5582 | return; | 5707 | return; |
5583 | } | 5708 | } |
5584 | 5709 | ||
@@ -6566,27 +6691,12 @@ intel_user_framebuffer_create(struct drm_device *dev, | |||
6566 | struct drm_mode_fb_cmd *mode_cmd) | 6691 | struct drm_mode_fb_cmd *mode_cmd) |
6567 | { | 6692 | { |
6568 | struct drm_i915_gem_object *obj; | 6693 | struct drm_i915_gem_object *obj; |
6569 | struct intel_framebuffer *intel_fb; | ||
6570 | int ret; | ||
6571 | 6694 | ||
6572 | obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle)); | 6695 | obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle)); |
6573 | if (&obj->base == NULL) | 6696 | if (&obj->base == NULL) |
6574 | return ERR_PTR(-ENOENT); | 6697 | return ERR_PTR(-ENOENT); |
6575 | 6698 | ||
6576 | intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); | 6699 | return intel_framebuffer_create(dev, mode_cmd, obj); |
6577 | if (!intel_fb) { | ||
6578 | drm_gem_object_unreference_unlocked(&obj->base); | ||
6579 | return ERR_PTR(-ENOMEM); | ||
6580 | } | ||
6581 | |||
6582 | ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); | ||
6583 | if (ret) { | ||
6584 | drm_gem_object_unreference_unlocked(&obj->base); | ||
6585 | kfree(intel_fb); | ||
6586 | return ERR_PTR(ret); | ||
6587 | } | ||
6588 | |||
6589 | return &intel_fb->base; | ||
6590 | } | 6700 | } |
6591 | 6701 | ||
6592 | static const struct drm_mode_config_funcs intel_mode_funcs = { | 6702 | static const struct drm_mode_config_funcs intel_mode_funcs = { |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3ceb3daeb61f..2e49b62da9a5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -292,6 +292,7 @@ extern void intel_wait_for_vblank(struct drm_device *dev, int pipe); | |||
292 | extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe); | 292 | extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe); |
293 | 293 | ||
294 | struct intel_load_detect_pipe { | 294 | struct intel_load_detect_pipe { |
295 | struct drm_framebuffer *release_fb; | ||
295 | bool load_detect_temp; | 296 | bool load_detect_temp; |
296 | int dpms_mode; | 297 | int dpms_mode; |
297 | }; | 298 | }; |