summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_fbdev.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-04-03 07:51:54 +1000
committerDave Airlie <airlied@redhat.com>2014-04-03 07:51:54 +1000
commit66e514c14a1cb9c2540c685c40d94dc6ef6b6bb5 (patch)
treeb21a13e80e7a27e8829fa1f1693c46bf2cab4507 /drivers/gpu/drm/i915/intel_fbdev.c
parent2844ea3f252331cc0ecf3ae74f6226db2f580f8a (diff)
parent698b3135acb94e838a33a69f1a7a684fe0d90734 (diff)
downloadop-kernel-dev-66e514c14a1cb9c2540c685c40d94dc6ef6b6bb5.zip
op-kernel-dev-66e514c14a1cb9c2540c685c40d94dc6ef6b6bb5.tar.gz
Merge tag 'drm-intel-next-2014-03-21' of git://anongit.freedesktop.org/drm-intel into drm-next
- Inherit/reuse firmwar framebuffers (for real this time) from Jesse, less flicker for fastbooting. - More flexible cloning for hdmi (Ville). - Some PPGTT fixes from Ben. - Ring init fixes from Naresh Kumar. - set_cache_level regression fixes for the vma conversion from Ville&Chris. - Conversion to the new dp aux helpers (Jani). - Unification of runtime pm with pc8 support from Paulo, prep work for runtime pm on other platforms than HSW. - Larger cursor sizes (Sagar Kamble). - Piles of improvements and fixes all over, as usual. * tag 'drm-intel-next-2014-03-21' of git://anongit.freedesktop.org/drm-intel: (75 commits) drm/i915: Include a note about the dangers of I915_READ64/I915_WRITE64 drm/i915/sdvo: fix questionable return value check drm/i915: Fix unsafe loop iteration over vma whilst unbinding them drm/i915: Enabling 128x128 and 256x256 ARGB Cursor Support drm/i915: Print how many objects are shared in per-process stats drm/i915: Per-process stats work better when evaluated per-process drm/i915: remove rps local variables drm/i915: Remove extraneous MMIO for RPS drm/i915: Rename and comment all the RPS *stuff* drm/i915: Store the HW min frequency as min_freq drm/i915: Fix coding style for RPS drm/i915: Reorganize the overclock code drm/i915: init pm.suspended earlier drm/i915: update the PC8 and runtime PM documentation drm/i915: rename __hsw_do_{en, dis}able_pc8 drm/i915: kill struct i915_package_c8 drm/i915: move pc8.irqs_disabled to pm.irqs_disabled drm/i915: remove dev_priv->pc8.enabled drm/i915: don't get/put PC8 when getting/putting power wells drm/i915: make intel_aux_display_runtime_get get runtime PM, not PC8 ... Conflicts: drivers/gpu/drm/i915/intel_display.c drivers/gpu/drm/i915/intel_dp.c
Diffstat (limited to 'drivers/gpu/drm/i915/intel_fbdev.c')
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c144
1 files changed, 135 insertions, 9 deletions
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 6b5beed..2b1d42d 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -128,6 +128,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
struct drm_framebuffer *fb;
struct drm_i915_gem_object *obj;
int size, ret;
+ bool prealloc = false;
mutex_lock(&dev->struct_mutex);
@@ -139,6 +140,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
intel_fb = ifbdev->fb;
} else {
DRM_DEBUG_KMS("re-using BIOS fb\n");
+ prealloc = true;
sizes->fb_width = intel_fb->base.width;
sizes->fb_height = intel_fb->base.height;
}
@@ -200,7 +202,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
* If the object is stolen however, it will be full of whatever
* garbage was left in there.
*/
- if (ifbdev->fb->obj->stolen)
+ if (ifbdev->fb->obj->stolen && !prealloc)
memset_io(info->screen_base, 0, info->screen_size);
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
@@ -454,27 +456,149 @@ static void intel_fbdev_destroy(struct drm_device *dev,
drm_framebuffer_remove(&ifbdev->fb->base);
}
+/*
+ * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible.
+ * The core display code will have read out the current plane configuration,
+ * so we use that to figure out if there's an object for us to use as the
+ * fb, and if so, we re-use it for the fbdev configuration.
+ *
+ * Note we only support a single fb shared across pipes for boot (mostly for
+ * fbcon), so we just find the biggest and use that.
+ */
+static bool intel_fbdev_init_bios(struct drm_device *dev,
+ struct intel_fbdev *ifbdev)
+{
+ struct intel_framebuffer *fb = NULL;
+ struct drm_crtc *crtc;
+ struct intel_crtc *intel_crtc;
+ struct intel_plane_config *plane_config = NULL;
+ unsigned int max_size = 0;
+
+ if (!i915.fastboot)
+ return false;
+
+ /* Find the largest fb */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ intel_crtc = to_intel_crtc(crtc);
+
+ if (!intel_crtc->active || !crtc->primary->fb) {
+ DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
+ pipe_name(intel_crtc->pipe));
+ continue;
+ }
+
+ if (intel_crtc->plane_config.size > max_size) {
+ DRM_DEBUG_KMS("found possible fb from plane %c\n",
+ pipe_name(intel_crtc->pipe));
+ plane_config = &intel_crtc->plane_config;
+ fb = to_intel_framebuffer(crtc->primary->fb);
+ max_size = plane_config->size;
+ }
+ }
+
+ if (!fb) {
+ DRM_DEBUG_KMS("no active fbs found, not using BIOS config\n");
+ goto out;
+ }
+
+ /* Now make sure all the pipes will fit into it */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ unsigned int cur_size;
+
+ intel_crtc = to_intel_crtc(crtc);
+
+ if (!intel_crtc->active) {
+ DRM_DEBUG_KMS("pipe %c not active, skipping\n",
+ pipe_name(intel_crtc->pipe));
+ continue;
+ }
+
+ DRM_DEBUG_KMS("checking plane %c for BIOS fb\n",
+ pipe_name(intel_crtc->pipe));
+
+ /*
+ * See if the plane fb we found above will fit on this
+ * pipe. Note we need to use the selected fb's bpp rather
+ * than the current pipe's, since they could be different.
+ */
+ cur_size = intel_crtc->config.adjusted_mode.crtc_hdisplay *
+ intel_crtc->config.adjusted_mode.crtc_vdisplay;
+ DRM_DEBUG_KMS("pipe %c area: %d\n", pipe_name(intel_crtc->pipe),
+ cur_size);
+ cur_size *= fb->base.bits_per_pixel / 8;
+ DRM_DEBUG_KMS("total size %d (bpp %d)\n", cur_size,
+ fb->base.bits_per_pixel / 8);
+
+ if (cur_size > max_size) {
+ DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n",
+ pipe_name(intel_crtc->pipe),
+ cur_size, max_size);
+ plane_config = NULL;
+ fb = NULL;
+ break;
+ }
+
+ DRM_DEBUG_KMS("fb big enough for plane %c (%d >= %d)\n",
+ pipe_name(intel_crtc->pipe),
+ max_size, cur_size);
+ }
+
+ if (!fb) {
+ DRM_DEBUG_KMS("BIOS fb not suitable for all pipes, not using\n");
+ goto out;
+ }
+
+ ifbdev->preferred_bpp = fb->base.bits_per_pixel;
+ ifbdev->fb = fb;
+
+ drm_framebuffer_reference(&ifbdev->fb->base);
+
+ /* Final pass to check if any active pipes don't have fbs */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ intel_crtc = to_intel_crtc(crtc);
+
+ if (!intel_crtc->active)
+ continue;
+
+ WARN(!crtc->primary->fb,
+ "re-used BIOS config but lost an fb on crtc %d\n",
+ crtc->base.id);
+ }
+
+
+ DRM_DEBUG_KMS("using BIOS fb for initial console\n");
+ return true;
+
+out:
+
+ return false;
+}
+
int intel_fbdev_init(struct drm_device *dev)
{
struct intel_fbdev *ifbdev;
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
- ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL);
- if (!ifbdev)
+ if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0))
+ return -ENODEV;
+
+ ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
+ if (ifbdev == NULL)
return -ENOMEM;
- dev_priv->fbdev = ifbdev;
ifbdev->helper.funcs = &intel_fb_helper_funcs;
+ if (!intel_fbdev_init_bios(dev, ifbdev))
+ ifbdev->preferred_bpp = 32;
ret = drm_fb_helper_init(dev, &ifbdev->helper,
- INTEL_INFO(dev)->num_pipes,
- 4);
+ INTEL_INFO(dev)->num_pipes, 4);
if (ret) {
kfree(ifbdev);
return ret;
}
+ dev_priv->fbdev = ifbdev;
drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
return 0;
@@ -483,9 +607,10 @@ int intel_fbdev_init(struct drm_device *dev)
void intel_fbdev_initial_config(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_fbdev *ifbdev = dev_priv->fbdev;
/* Due to peculiar init order wrt to hpd handling this is separate. */
- drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32);
+ drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp);
}
void intel_fbdev_fini(struct drm_device *dev)
@@ -523,7 +648,8 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
void intel_fbdev_output_poll_changed(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
+ if (dev_priv->fbdev)
+ drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
}
void intel_fbdev_restore_mode(struct drm_device *dev)
@@ -531,7 +657,7 @@ void intel_fbdev_restore_mode(struct drm_device *dev)
int ret;
struct drm_i915_private *dev_priv = dev->dev_private;
- if (INTEL_INFO(dev)->num_pipes == 0)
+ if (!dev_priv->fbdev)
return;
drm_modeset_lock_all(dev);
OpenPOWER on IntegriCloud