aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i915/intel_display.c144
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
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
5484static struct drm_framebuffer *
5485intel_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
5508static u32
5509intel_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
5515static u32
5516intel_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
5522static struct drm_framebuffer *
5523intel_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
5544static struct drm_framebuffer *
5545mode_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
5484bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, 5570bool 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
6592static const struct drm_mode_config_funcs intel_mode_funcs = { 6702static 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);
292extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe); 292extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
293 293
294struct intel_load_detect_pipe { 294struct 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};