diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_fbdev.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_fbdev.c | 487 |
1 files changed, 168 insertions, 319 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 99894a855ef0..2dc4029d71ed 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -24,7 +24,6 @@ * David Airlie */ -#include <linux/async.h> #include <linux/console.h> #include <linux/delay.h> #include <linux/errno.h> @@ -38,14 +37,20 @@ #include <linux/tty.h> #include <linux/vga_switcheroo.h> +#include <drm/clients/drm_client_setup.h> #include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> +#include <drm/drm_gem.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_managed.h> +#include <drm/drm_print.h> -#include "gem/i915_gem_mman.h" - -#include "i915_drv.h" +#include "i915_vma.h" +#include "intel_bo.h" +#include "intel_display_core.h" +#include "intel_display_rpm.h" #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fb_pin.h" @@ -54,25 +59,16 @@ #include "intel_frontbuffer.h" struct intel_fbdev { - struct drm_fb_helper helper; struct intel_framebuffer *fb; struct i915_vma *vma; unsigned long vma_flags; - async_cookie_t cookie; - int preferred_bpp; - - /* Whether or not fbdev hpd processing is temporarily suspended */ - bool hpd_suspended: 1; - /* Set when a hotplug was received while HPD processing was suspended */ - bool hpd_waiting: 1; - - /* Protects hpd_suspended */ - struct mutex hpd_lock; }; static struct intel_fbdev *to_intel_fbdev(struct drm_fb_helper *fb_helper) { - return container_of(fb_helper, struct intel_fbdev, helper); + struct intel_display *display = to_intel_display(fb_helper->client.dev); + + return display->fbdev.fbdev; } static struct intel_frontbuffer *to_frontbuffer(struct intel_fbdev *ifbdev) @@ -128,13 +124,35 @@ static int intel_fbdev_pan_display(struct fb_var_screeninfo *var, static int intel_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma) { - struct intel_fbdev *fbdev = to_intel_fbdev(info->par); - struct drm_gem_object *bo = drm_gem_fb_get_obj(&fbdev->fb->base, 0); - struct drm_i915_gem_object *obj = to_intel_bo(bo); + struct drm_fb_helper *fb_helper = info->par; + struct drm_gem_object *obj = drm_gem_fb_get_obj(fb_helper->fb, 0); + + return intel_bo_fb_mmap(obj, vma); +} + +static void intel_fbdev_fb_destroy(struct fb_info *info) +{ + struct drm_fb_helper *fb_helper = info->par; + struct intel_fbdev *ifbdev = to_intel_fbdev(fb_helper); + + drm_fb_helper_fini(fb_helper); + + /* + * We rely on the object-free to release the VMA pinning for + * the info->screen_base mmaping. Leaking the VMA is simpler than + * trying to rectify all the possible error paths leading here. + */ + intel_fb_unpin_vma(ifbdev->vma, ifbdev->vma_flags); + drm_framebuffer_remove(fb_helper->fb); - return i915_gem_fb_mmap(obj, vma); + drm_client_release(&fb_helper->client); + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); } +__diag_push(); +__diag_ignore_all("-Woverride-init", "Allow field initialization overrides for fb ops"); + static const struct fb_ops intelfb_ops = { .owner = THIS_MODULE, __FB_DEFAULT_DEFERRED_OPS_RDWR(intel_fbdev), @@ -144,67 +162,102 @@ static const struct fb_ops intelfb_ops = { .fb_pan_display = intel_fbdev_pan_display, __FB_DEFAULT_DEFERRED_OPS_DRAW(intel_fbdev), .fb_mmap = intel_fbdev_mmap, + .fb_destroy = intel_fbdev_fb_destroy, }; -static int intelfb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) +__diag_pop(); + +static int intelfb_dirty(struct drm_fb_helper *helper, struct drm_clip_rect *clip) { + if (!(clip->x1 < clip->x2 && clip->y1 < clip->y2)) + return 0; + + if (helper->fb->funcs->dirty) + return helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1); + + return 0; +} + +static void intelfb_restore(struct drm_fb_helper *fb_helper) +{ + struct intel_fbdev *ifbdev = to_intel_fbdev(fb_helper); + + intel_fbdev_invalidate(ifbdev); +} + +static void intelfb_set_suspend(struct drm_fb_helper *fb_helper, bool suspend) +{ + struct fb_info *info = fb_helper->info; + + /* + * When resuming from hibernation, Linux restores the object's + * content from swap if the buffer is backed by shmemfs. If the + * object is stolen however, it will be full of whatever garbage + * was left in there. Clear it to zero in this case. + */ + if (!suspend && !intel_bo_is_shmem(intel_fb_bo(fb_helper->fb))) + memset_io(info->screen_base, 0, info->screen_size); + + fb_set_suspend(info, suspend); +} + +static const struct drm_fb_helper_funcs intel_fb_helper_funcs = { + .fb_dirty = intelfb_dirty, + .fb_restore = intelfb_restore, + .fb_set_suspend = intelfb_set_suspend, +}; + +int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct intel_display *display = to_intel_display(helper->dev); struct intel_fbdev *ifbdev = to_intel_fbdev(helper); - struct intel_framebuffer *intel_fb = ifbdev->fb; - struct drm_device *dev = helper->dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); - const struct i915_gtt_view view = { - .type = I915_GTT_VIEW_NORMAL, - }; - intel_wakeref_t wakeref; + struct intel_framebuffer *fb = ifbdev->fb; + struct ref_tracker *wakeref; struct fb_info *info; struct i915_vma *vma; unsigned long flags = 0; bool prealloc = false; - struct drm_i915_gem_object *obj; + struct drm_gem_object *obj; int ret; - mutex_lock(&ifbdev->hpd_lock); - ret = ifbdev->hpd_suspended ? -EAGAIN : 0; - mutex_unlock(&ifbdev->hpd_lock); - if (ret) - return ret; + ifbdev->fb = NULL; - if (intel_fb && - (sizes->fb_width > intel_fb->base.width || - sizes->fb_height > intel_fb->base.height)) { - drm_dbg_kms(&dev_priv->drm, + if (fb && + (sizes->fb_width > fb->base.width || + sizes->fb_height > fb->base.height)) { + drm_dbg_kms(display->drm, "BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", - intel_fb->base.width, intel_fb->base.height, + fb->base.width, fb->base.height, sizes->fb_width, sizes->fb_height); - drm_framebuffer_put(&intel_fb->base); - intel_fb = ifbdev->fb = NULL; + drm_framebuffer_put(&fb->base); + fb = NULL; } - if (!intel_fb || drm_WARN_ON(dev, !intel_fb_obj(&intel_fb->base))) { - struct drm_framebuffer *fb; - drm_dbg_kms(&dev_priv->drm, + if (!fb || drm_WARN_ON(display->drm, !intel_fb_bo(&fb->base))) { + drm_dbg_kms(display->drm, "no BIOS fb, allocating a new one\n"); fb = intel_fbdev_fb_alloc(helper, sizes); if (IS_ERR(fb)) return PTR_ERR(fb); - intel_fb = ifbdev->fb = to_intel_framebuffer(fb); } else { - drm_dbg_kms(&dev_priv->drm, "re-using BIOS fb\n"); + drm_dbg_kms(display->drm, "re-using BIOS fb\n"); prealloc = true; - sizes->fb_width = intel_fb->base.width; - sizes->fb_height = intel_fb->base.height; + sizes->fb_width = fb->base.width; + sizes->fb_height = fb->base.height; } - wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); + wakeref = intel_display_rpm_get(display); /* Pin the GGTT vma for our access via info->screen_base. * This also validates that any existing fb inherited from the * BIOS is suitable for own access. */ - vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, false, - &view, false, &flags); + vma = intel_fb_pin_to_ggtt(&fb->base, &fb->normal_view.gtt, + fb->min_alignment, 0, + intel_fb_view_vtd_guard(&fb->base, &fb->normal_view, + DRM_MODE_ROTATE_0), + false, &flags); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto out_unlock; @@ -212,82 +265,50 @@ static int intelfb_create(struct drm_fb_helper *helper, info = drm_fb_helper_alloc_info(helper); if (IS_ERR(info)) { - drm_err(&dev_priv->drm, "Failed to allocate fb_info (%pe)\n", info); + drm_err(display->drm, "Failed to allocate fb_info (%pe)\n", info); ret = PTR_ERR(info); goto out_unpin; } - ifbdev->helper.fb = &ifbdev->fb->base; + helper->funcs = &intel_fb_helper_funcs; + helper->fb = &fb->base; info->fbops = &intelfb_ops; - obj = intel_fb_obj(&intel_fb->base); + obj = intel_fb_bo(&fb->base); - ret = intel_fbdev_fb_fill_info(dev_priv, info, obj, vma); + ret = intel_fbdev_fb_fill_info(display, info, obj, vma); if (ret) goto out_unpin; - drm_fb_helper_fill_info(info, &ifbdev->helper, sizes); + drm_fb_helper_fill_info(info, display->drm->fb_helper, sizes); /* If the object is shmemfs backed, it will have given us zeroed pages. * If the object is stolen however, it will be full of whatever * garbage was left in there. */ - if (!i915_gem_object_is_shmem(obj) && !prealloc) + if (!intel_bo_is_shmem(obj) && !prealloc) memset_io(info->screen_base, 0, info->screen_size); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ - drm_dbg_kms(&dev_priv->drm, "allocated %dx%d fb: 0x%08x\n", - ifbdev->fb->base.width, ifbdev->fb->base.height, + drm_dbg_kms(display->drm, "allocated %dx%d fb: 0x%08x\n", + fb->base.width, fb->base.height, i915_ggtt_offset(vma)); + ifbdev->fb = fb; ifbdev->vma = vma; ifbdev->vma_flags = flags; - intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); - vga_switcheroo_client_fb_set(pdev, info); + intel_display_rpm_put(display, wakeref); + return 0; out_unpin: - intel_unpin_fb_vma(vma, flags); + intel_fb_unpin_vma(vma, flags); out_unlock: - intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); - return ret; -} - -static int intelfb_dirty(struct drm_fb_helper *helper, struct drm_clip_rect *clip) -{ - if (!(clip->x1 < clip->x2 && clip->y1 < clip->y2)) - return 0; - - if (helper->fb->funcs->dirty) - return helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1); - - return 0; -} - -static const struct drm_fb_helper_funcs intel_fb_helper_funcs = { - .fb_probe = intelfb_create, - .fb_dirty = intelfb_dirty, -}; - -static void intel_fbdev_destroy(struct intel_fbdev *ifbdev) -{ - /* We rely on the object-free to release the VMA pinning for - * the info->screen_base mmaping. Leaking the VMA is simpler than - * trying to rectify all the possible error paths leading here. - */ - - drm_fb_helper_fini(&ifbdev->helper); - - if (ifbdev->vma) - intel_unpin_fb_vma(ifbdev->vma, ifbdev->vma_flags); + intel_display_rpm_put(display, wakeref); - if (ifbdev->fb) - drm_framebuffer_remove(&ifbdev->fb->base); - - drm_fb_helper_unprepare(&ifbdev->helper); - kfree(ifbdev); + return ret; } /* @@ -299,56 +320,54 @@ static void intel_fbdev_destroy(struct intel_fbdev *ifbdev) * 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, +static bool intel_fbdev_init_bios(struct intel_display *display, struct intel_fbdev *ifbdev) { - struct drm_i915_private *i915 = to_i915(dev); struct intel_framebuffer *fb = NULL; struct intel_crtc *crtc; unsigned int max_size = 0; /* Find the largest fb */ - for_each_intel_crtc(dev, crtc) { + for_each_intel_crtc(display->drm, crtc) { struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); struct intel_plane *plane = to_intel_plane(crtc->base.primary); struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state); - struct drm_i915_gem_object *obj = - intel_fb_obj(plane_state->uapi.fb); + struct drm_gem_object *obj = intel_fb_bo(plane_state->uapi.fb); if (!crtc_state->uapi.active) { - drm_dbg_kms(&i915->drm, + drm_dbg_kms(display->drm, "[CRTC:%d:%s] not active, skipping\n", crtc->base.base.id, crtc->base.name); continue; } if (!obj) { - drm_dbg_kms(&i915->drm, + drm_dbg_kms(display->drm, "[PLANE:%d:%s] no fb, skipping\n", plane->base.base.id, plane->base.name); continue; } - if (intel_bo_to_drm_bo(obj)->size > max_size) { - drm_dbg_kms(&i915->drm, + if (obj->size > max_size) { + drm_dbg_kms(display->drm, "found possible fb from [PLANE:%d:%s]\n", plane->base.base.id, plane->base.name); fb = to_intel_framebuffer(plane_state->uapi.fb); - max_size = intel_bo_to_drm_bo(obj)->size; + max_size = obj->size; } } if (!fb) { - drm_dbg_kms(&i915->drm, + drm_dbg_kms(display->drm, "no active fbs found, not using BIOS config\n"); goto out; } /* Now make sure all the pipes will fit into it */ - for_each_intel_crtc(dev, crtc) { + for_each_intel_crtc(display->drm, crtc) { struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); struct intel_plane *plane = @@ -356,13 +375,13 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, unsigned int cur_size; if (!crtc_state->uapi.active) { - drm_dbg_kms(&i915->drm, + drm_dbg_kms(display->drm, "[CRTC:%d:%s] not active, skipping\n", crtc->base.base.id, crtc->base.name); continue; } - drm_dbg_kms(&i915->drm, "checking [PLANE:%d:%s] for BIOS fb\n", + drm_dbg_kms(display->drm, "checking [PLANE:%d:%s] for BIOS fb\n", plane->base.base.id, plane->base.name); /* @@ -373,7 +392,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, cur_size = crtc_state->uapi.adjusted_mode.crtc_hdisplay; cur_size = cur_size * fb->base.format->cpp[0]; if (fb->base.pitches[0] < cur_size) { - drm_dbg_kms(&i915->drm, + drm_dbg_kms(display->drm, "fb not wide enough for [PLANE:%d:%s] (%d vs %d)\n", plane->base.base.id, plane->base.name, cur_size, fb->base.pitches[0]); @@ -384,7 +403,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, cur_size = crtc_state->uapi.adjusted_mode.crtc_vdisplay; cur_size = intel_fb_align_height(&fb->base, 0, cur_size); cur_size *= fb->base.pitches[0]; - drm_dbg_kms(&i915->drm, + drm_dbg_kms(display->drm, "[CRTC:%d:%s] area: %dx%d, bpp: %d, size: %d\n", crtc->base.base.id, crtc->base.name, crtc_state->uapi.adjusted_mode.crtc_hdisplay, @@ -393,7 +412,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, cur_size); if (cur_size > max_size) { - drm_dbg_kms(&i915->drm, + drm_dbg_kms(display->drm, "fb not big enough for [PLANE:%d:%s] (%d vs %d)\n", plane->base.base.id, plane->base.name, cur_size, max_size); @@ -401,25 +420,24 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, break; } - drm_dbg_kms(&i915->drm, + drm_dbg_kms(display->drm, "fb big enough [PLANE:%d:%s] (%d >= %d)\n", plane->base.base.id, plane->base.name, max_size, cur_size); } if (!fb) { - drm_dbg_kms(&i915->drm, + drm_dbg_kms(display->drm, "BIOS fb not suitable for all pipes, not using\n"); goto out; } - ifbdev->preferred_bpp = fb->base.format->cpp[0] * 8; ifbdev->fb = fb; drm_framebuffer_get(&ifbdev->fb->base); /* Final pass to check if any active pipes don't have fbs */ - for_each_intel_crtc(dev, crtc) { + for_each_intel_crtc(display->drm, crtc) { struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); struct intel_plane *plane = @@ -430,13 +448,13 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, if (!crtc_state->uapi.active) continue; - drm_WARN(dev, !plane_state->uapi.fb, + drm_WARN(display->drm, !plane_state->uapi.fb, "re-used BIOS config but lost an fb on [PLANE:%d:%s]\n", plane->base.base.id, plane->base.name); } - drm_dbg_kms(&i915->drm, "using BIOS fb for initial console\n"); + drm_dbg_kms(display->drm, "using BIOS fb for initial console\n"); return true; out: @@ -444,222 +462,53 @@ out: return false; } -static void intel_fbdev_suspend_worker(struct work_struct *work) -{ - intel_fbdev_set_suspend(&container_of(work, - struct drm_i915_private, - display.fbdev.suspend_work)->drm, - FBINFO_STATE_RUNNING, - true); -} - -int intel_fbdev_init(struct drm_device *dev) +static unsigned int intel_fbdev_color_mode(const struct drm_format_info *info) { - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_fbdev *ifbdev; - int ret; - - if (drm_WARN_ON(dev, !HAS_DISPLAY(dev_priv))) - return -ENODEV; - - ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); - if (ifbdev == NULL) - return -ENOMEM; + unsigned int bpp; - mutex_init(&ifbdev->hpd_lock); - drm_fb_helper_prepare(dev, &ifbdev->helper, 32, &intel_fb_helper_funcs); - - if (intel_fbdev_init_bios(dev, ifbdev)) - ifbdev->helper.preferred_bpp = ifbdev->preferred_bpp; - else - ifbdev->preferred_bpp = ifbdev->helper.preferred_bpp; - - ret = drm_fb_helper_init(dev, &ifbdev->helper); - if (ret) { - kfree(ifbdev); - return ret; - } - - dev_priv->display.fbdev.fbdev = ifbdev; - INIT_WORK(&dev_priv->display.fbdev.suspend_work, intel_fbdev_suspend_worker); - - return 0; -} - -static void intel_fbdev_initial_config(void *data, async_cookie_t cookie) -{ - struct intel_fbdev *ifbdev = data; - - /* Due to peculiar init order wrt to hpd handling this is separate. */ - if (drm_fb_helper_initial_config(&ifbdev->helper)) - intel_fbdev_unregister(to_i915(ifbdev->helper.dev)); -} - -void intel_fbdev_initial_config_async(struct drm_i915_private *dev_priv) -{ - struct intel_fbdev *ifbdev = dev_priv->display.fbdev.fbdev; - - if (!ifbdev) - return; - - ifbdev->cookie = async_schedule(intel_fbdev_initial_config, ifbdev); -} - -static void intel_fbdev_sync(struct intel_fbdev *ifbdev) -{ - if (!ifbdev->cookie) - return; - - /* Only serialises with all preceding async calls, hence +1 */ - async_synchronize_cookie(ifbdev->cookie + 1); - ifbdev->cookie = 0; -} - -void intel_fbdev_unregister(struct drm_i915_private *dev_priv) -{ - struct intel_fbdev *ifbdev = dev_priv->display.fbdev.fbdev; - - if (!ifbdev) - return; - - intel_fbdev_set_suspend(&dev_priv->drm, FBINFO_STATE_SUSPENDED, true); - - if (!current_is_async()) - intel_fbdev_sync(ifbdev); - - drm_fb_helper_unregister_info(&ifbdev->helper); -} - -void intel_fbdev_fini(struct drm_i915_private *dev_priv) -{ - struct intel_fbdev *ifbdev = fetch_and_zero(&dev_priv->display.fbdev.fbdev); - - if (!ifbdev) - return; + if (!info->depth || info->num_planes != 1 || info->has_alpha || info->is_yuv) + return 0; - intel_fbdev_destroy(ifbdev); -} + bpp = drm_format_info_bpp(info, 0); -/* Suspends/resumes fbdev processing of incoming HPD events. When resuming HPD - * processing, fbdev will perform a full connector reprobe if a hotplug event - * was received while HPD was suspended. - */ -static void intel_fbdev_hpd_set_suspend(struct drm_i915_private *i915, int state) -{ - struct intel_fbdev *ifbdev = i915->display.fbdev.fbdev; - bool send_hpd = false; - - mutex_lock(&ifbdev->hpd_lock); - ifbdev->hpd_suspended = state == FBINFO_STATE_SUSPENDED; - send_hpd = !ifbdev->hpd_suspended && ifbdev->hpd_waiting; - ifbdev->hpd_waiting = false; - mutex_unlock(&ifbdev->hpd_lock); - - if (send_hpd) { - drm_dbg_kms(&i915->drm, "Handling delayed fbcon HPD event\n"); - drm_fb_helper_hotplug_event(&ifbdev->helper); + switch (bpp) { + case 16: + return info->depth; // 15 or 16 + default: + return bpp; } } -void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous) +void intel_fbdev_setup(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_fbdev *ifbdev = dev_priv->display.fbdev.fbdev; - struct fb_info *info; - - if (!ifbdev) - return; + struct intel_fbdev *ifbdev; + unsigned int preferred_bpp = 0; - if (drm_WARN_ON(&dev_priv->drm, !HAS_DISPLAY(dev_priv))) + if (!HAS_DISPLAY(display)) return; - if (!ifbdev->vma) - goto set_suspend; - - info = ifbdev->helper.info; - - if (synchronous) { - /* Flush any pending work to turn the console on, and then - * wait to turn it off. It must be synchronous as we are - * about to suspend or unload the driver. - * - * Note that from within the work-handler, we cannot flush - * ourselves, so only flush outstanding work upon suspend! - */ - if (state != FBINFO_STATE_RUNNING) - flush_work(&dev_priv->display.fbdev.suspend_work); - - console_lock(); - } else { - /* - * The console lock can be pretty contented on resume due - * to all the printk activity. Try to keep it out of the hot - * path of resume if possible. - */ - drm_WARN_ON(dev, state != FBINFO_STATE_RUNNING); - if (!console_trylock()) { - /* Don't block our own workqueue as this can - * be run in parallel with other i915.ko tasks. - */ - queue_work(dev_priv->unordered_wq, - &dev_priv->display.fbdev.suspend_work); - return; - } - } - - /* On resume from hibernation: If the object is shmemfs backed, it has - * been restored from swap. If the object is stolen however, it will be - * full of whatever garbage was left in there. - */ - if (state == FBINFO_STATE_RUNNING && - !i915_gem_object_is_shmem(intel_fb_obj(&ifbdev->fb->base))) - memset_io(info->screen_base, 0, info->screen_size); - - drm_fb_helper_set_suspend(&ifbdev->helper, state); - console_unlock(); - -set_suspend: - intel_fbdev_hpd_set_suspend(dev_priv, state); -} - -void intel_fbdev_output_poll_changed(struct drm_device *dev) -{ - struct intel_fbdev *ifbdev = to_i915(dev)->display.fbdev.fbdev; - bool send_hpd; - + ifbdev = drmm_kzalloc(display->drm, sizeof(*ifbdev), GFP_KERNEL); if (!ifbdev) return; - intel_fbdev_sync(ifbdev); - - mutex_lock(&ifbdev->hpd_lock); - send_hpd = !ifbdev->hpd_suspended; - ifbdev->hpd_waiting = true; - mutex_unlock(&ifbdev->hpd_lock); + display->fbdev.fbdev = ifbdev; + if (intel_fbdev_init_bios(display, ifbdev)) + preferred_bpp = intel_fbdev_color_mode(ifbdev->fb->base.format); + if (!preferred_bpp) + preferred_bpp = 32; - if (send_hpd && (ifbdev->vma || ifbdev->helper.deferred_setup)) - drm_fb_helper_hotplug_event(&ifbdev->helper); + drm_client_setup_with_color_mode(display->drm, preferred_bpp); } -void intel_fbdev_restore_mode(struct drm_i915_private *dev_priv) +struct intel_framebuffer *intel_fbdev_framebuffer(struct intel_fbdev *fbdev) { - struct intel_fbdev *ifbdev = dev_priv->display.fbdev.fbdev; - - if (!ifbdev) - return; - - intel_fbdev_sync(ifbdev); - if (!ifbdev->vma) - return; + if (!fbdev) + return NULL; - if (drm_fb_helper_restore_fbdev_mode_unlocked(&ifbdev->helper) == 0) - intel_fbdev_invalidate(ifbdev); + return fbdev->fb; } -struct intel_framebuffer *intel_fbdev_framebuffer(struct intel_fbdev *fbdev) +struct i915_vma *intel_fbdev_vma_pointer(struct intel_fbdev *fbdev) { - if (!fbdev || !fbdev->helper.fb) - return NULL; - - return to_intel_framebuffer(fbdev->helper.fb); + return fbdev ? fbdev->vma : NULL; } |