Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright © 2007 David Airlie
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice (including the next
0012  * paragraph) shall be included in all copies or substantial portions of the
0013  * Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0020  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0021  * DEALINGS IN THE SOFTWARE.
0022  *
0023  * Authors:
0024  *     David Airlie
0025  */
0026 
0027 #include <linux/async.h>
0028 #include <linux/console.h>
0029 #include <linux/delay.h>
0030 #include <linux/errno.h>
0031 #include <linux/init.h>
0032 #include <linux/kernel.h>
0033 #include <linux/mm.h>
0034 #include <linux/module.h>
0035 #include <linux/string.h>
0036 #include <linux/sysrq.h>
0037 #include <linux/tty.h>
0038 #include <linux/vga_switcheroo.h>
0039 
0040 #include <drm/drm_crtc.h>
0041 #include <drm/drm_fb_helper.h>
0042 #include <drm/drm_fourcc.h>
0043 
0044 #include "gem/i915_gem_lmem.h"
0045 
0046 #include "i915_drv.h"
0047 #include "intel_display_types.h"
0048 #include "intel_fb.h"
0049 #include "intel_fb_pin.h"
0050 #include "intel_fbdev.h"
0051 #include "intel_frontbuffer.h"
0052 
0053 struct intel_fbdev {
0054     struct drm_fb_helper helper;
0055     struct intel_framebuffer *fb;
0056     struct i915_vma *vma;
0057     unsigned long vma_flags;
0058     async_cookie_t cookie;
0059     int preferred_bpp;
0060 
0061     /* Whether or not fbdev hpd processing is temporarily suspended */
0062     bool hpd_suspended: 1;
0063     /* Set when a hotplug was received while HPD processing was suspended */
0064     bool hpd_waiting: 1;
0065 
0066     /* Protects hpd_suspended */
0067     struct mutex hpd_lock;
0068 };
0069 
0070 static struct intel_frontbuffer *to_frontbuffer(struct intel_fbdev *ifbdev)
0071 {
0072     return ifbdev->fb->frontbuffer;
0073 }
0074 
0075 static void intel_fbdev_invalidate(struct intel_fbdev *ifbdev)
0076 {
0077     intel_frontbuffer_invalidate(to_frontbuffer(ifbdev), ORIGIN_CPU);
0078 }
0079 
0080 static int intel_fbdev_set_par(struct fb_info *info)
0081 {
0082     struct drm_fb_helper *fb_helper = info->par;
0083     struct intel_fbdev *ifbdev =
0084         container_of(fb_helper, struct intel_fbdev, helper);
0085     int ret;
0086 
0087     ret = drm_fb_helper_set_par(info);
0088     if (ret == 0)
0089         intel_fbdev_invalidate(ifbdev);
0090 
0091     return ret;
0092 }
0093 
0094 static int intel_fbdev_blank(int blank, struct fb_info *info)
0095 {
0096     struct drm_fb_helper *fb_helper = info->par;
0097     struct intel_fbdev *ifbdev =
0098         container_of(fb_helper, struct intel_fbdev, helper);
0099     int ret;
0100 
0101     ret = drm_fb_helper_blank(blank, info);
0102     if (ret == 0)
0103         intel_fbdev_invalidate(ifbdev);
0104 
0105     return ret;
0106 }
0107 
0108 static int intel_fbdev_pan_display(struct fb_var_screeninfo *var,
0109                    struct fb_info *info)
0110 {
0111     struct drm_fb_helper *fb_helper = info->par;
0112     struct intel_fbdev *ifbdev =
0113         container_of(fb_helper, struct intel_fbdev, helper);
0114     int ret;
0115 
0116     ret = drm_fb_helper_pan_display(var, info);
0117     if (ret == 0)
0118         intel_fbdev_invalidate(ifbdev);
0119 
0120     return ret;
0121 }
0122 
0123 static const struct fb_ops intelfb_ops = {
0124     .owner = THIS_MODULE,
0125     DRM_FB_HELPER_DEFAULT_OPS,
0126     .fb_set_par = intel_fbdev_set_par,
0127     .fb_fillrect = drm_fb_helper_cfb_fillrect,
0128     .fb_copyarea = drm_fb_helper_cfb_copyarea,
0129     .fb_imageblit = drm_fb_helper_cfb_imageblit,
0130     .fb_pan_display = intel_fbdev_pan_display,
0131     .fb_blank = intel_fbdev_blank,
0132 };
0133 
0134 static int intelfb_alloc(struct drm_fb_helper *helper,
0135              struct drm_fb_helper_surface_size *sizes)
0136 {
0137     struct intel_fbdev *ifbdev =
0138         container_of(helper, struct intel_fbdev, helper);
0139     struct drm_framebuffer *fb;
0140     struct drm_device *dev = helper->dev;
0141     struct drm_i915_private *dev_priv = to_i915(dev);
0142     struct drm_mode_fb_cmd2 mode_cmd = {};
0143     struct drm_i915_gem_object *obj;
0144     int size;
0145 
0146     /* we don't do packed 24bpp */
0147     if (sizes->surface_bpp == 24)
0148         sizes->surface_bpp = 32;
0149 
0150     mode_cmd.width = sizes->surface_width;
0151     mode_cmd.height = sizes->surface_height;
0152 
0153     mode_cmd.pitches[0] = ALIGN(mode_cmd.width *
0154                     DIV_ROUND_UP(sizes->surface_bpp, 8), 64);
0155     mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
0156                               sizes->surface_depth);
0157 
0158     size = mode_cmd.pitches[0] * mode_cmd.height;
0159     size = PAGE_ALIGN(size);
0160 
0161     obj = ERR_PTR(-ENODEV);
0162     if (HAS_LMEM(dev_priv)) {
0163         obj = i915_gem_object_create_lmem(dev_priv, size,
0164                           I915_BO_ALLOC_CONTIGUOUS);
0165     } else {
0166         /*
0167          * If the FB is too big, just don't use it since fbdev is not very
0168          * important and we should probably use that space with FBC or other
0169          * features.
0170          */
0171         if (size * 2 < dev_priv->stolen_usable_size)
0172             obj = i915_gem_object_create_stolen(dev_priv, size);
0173         if (IS_ERR(obj))
0174             obj = i915_gem_object_create_shmem(dev_priv, size);
0175     }
0176 
0177     if (IS_ERR(obj)) {
0178         drm_err(&dev_priv->drm, "failed to allocate framebuffer\n");
0179         return PTR_ERR(obj);
0180     }
0181 
0182     fb = intel_framebuffer_create(obj, &mode_cmd);
0183     i915_gem_object_put(obj);
0184     if (IS_ERR(fb))
0185         return PTR_ERR(fb);
0186 
0187     ifbdev->fb = to_intel_framebuffer(fb);
0188     return 0;
0189 }
0190 
0191 static int intelfb_create(struct drm_fb_helper *helper,
0192               struct drm_fb_helper_surface_size *sizes)
0193 {
0194     struct intel_fbdev *ifbdev =
0195         container_of(helper, struct intel_fbdev, helper);
0196     struct intel_framebuffer *intel_fb = ifbdev->fb;
0197     struct drm_device *dev = helper->dev;
0198     struct drm_i915_private *dev_priv = to_i915(dev);
0199     struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
0200     struct i915_ggtt *ggtt = to_gt(dev_priv)->ggtt;
0201     const struct i915_ggtt_view view = {
0202         .type = I915_GGTT_VIEW_NORMAL,
0203     };
0204     intel_wakeref_t wakeref;
0205     struct fb_info *info;
0206     struct i915_vma *vma;
0207     unsigned long flags = 0;
0208     bool prealloc = false;
0209     void __iomem *vaddr;
0210     struct drm_i915_gem_object *obj;
0211     int ret;
0212 
0213     if (intel_fb &&
0214         (sizes->fb_width > intel_fb->base.width ||
0215          sizes->fb_height > intel_fb->base.height)) {
0216         drm_dbg_kms(&dev_priv->drm,
0217                 "BIOS fb too small (%dx%d), we require (%dx%d),"
0218                 " releasing it\n",
0219                 intel_fb->base.width, intel_fb->base.height,
0220                 sizes->fb_width, sizes->fb_height);
0221         drm_framebuffer_put(&intel_fb->base);
0222         intel_fb = ifbdev->fb = NULL;
0223     }
0224     if (!intel_fb || drm_WARN_ON(dev, !intel_fb_obj(&intel_fb->base))) {
0225         drm_dbg_kms(&dev_priv->drm,
0226                 "no BIOS fb, allocating a new one\n");
0227         ret = intelfb_alloc(helper, sizes);
0228         if (ret)
0229             return ret;
0230         intel_fb = ifbdev->fb;
0231     } else {
0232         drm_dbg_kms(&dev_priv->drm, "re-using BIOS fb\n");
0233         prealloc = true;
0234         sizes->fb_width = intel_fb->base.width;
0235         sizes->fb_height = intel_fb->base.height;
0236     }
0237 
0238     wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
0239 
0240     /* Pin the GGTT vma for our access via info->screen_base.
0241      * This also validates that any existing fb inherited from the
0242      * BIOS is suitable for own access.
0243      */
0244     vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, false,
0245                      &view, false, &flags);
0246     if (IS_ERR(vma)) {
0247         ret = PTR_ERR(vma);
0248         goto out_unlock;
0249     }
0250 
0251     info = drm_fb_helper_alloc_fbi(helper);
0252     if (IS_ERR(info)) {
0253         drm_err(&dev_priv->drm, "Failed to allocate fb_info\n");
0254         ret = PTR_ERR(info);
0255         goto out_unpin;
0256     }
0257 
0258     ifbdev->helper.fb = &ifbdev->fb->base;
0259 
0260     info->fbops = &intelfb_ops;
0261 
0262     /* setup aperture base/size for vesafb takeover */
0263     obj = intel_fb_obj(&intel_fb->base);
0264     if (i915_gem_object_is_lmem(obj)) {
0265         struct intel_memory_region *mem = obj->mm.region;
0266 
0267         info->apertures->ranges[0].base = mem->io_start;
0268         info->apertures->ranges[0].size = mem->io_size;
0269 
0270         /* Use fbdev's framebuffer from lmem for discrete */
0271         info->fix.smem_start =
0272             (unsigned long)(mem->io_start +
0273                     i915_gem_object_get_dma_address(obj, 0));
0274         info->fix.smem_len = obj->base.size;
0275     } else {
0276         info->apertures->ranges[0].base = ggtt->gmadr.start;
0277         info->apertures->ranges[0].size = ggtt->mappable_end;
0278 
0279         /* Our framebuffer is the entirety of fbdev's system memory */
0280         info->fix.smem_start =
0281             (unsigned long)(ggtt->gmadr.start + vma->node.start);
0282         info->fix.smem_len = vma->size;
0283     }
0284 
0285     vaddr = i915_vma_pin_iomap(vma);
0286     if (IS_ERR(vaddr)) {
0287         drm_err(&dev_priv->drm,
0288             "Failed to remap framebuffer into virtual memory\n");
0289         ret = PTR_ERR(vaddr);
0290         goto out_unpin;
0291     }
0292     info->screen_base = vaddr;
0293     info->screen_size = vma->size;
0294 
0295     drm_fb_helper_fill_info(info, &ifbdev->helper, sizes);
0296 
0297     /* If the object is shmemfs backed, it will have given us zeroed pages.
0298      * If the object is stolen however, it will be full of whatever
0299      * garbage was left in there.
0300      */
0301     if (!i915_gem_object_is_shmem(vma->obj) && !prealloc)
0302         memset_io(info->screen_base, 0, info->screen_size);
0303 
0304     /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
0305 
0306     drm_dbg_kms(&dev_priv->drm, "allocated %dx%d fb: 0x%08x\n",
0307             ifbdev->fb->base.width, ifbdev->fb->base.height,
0308             i915_ggtt_offset(vma));
0309     ifbdev->vma = vma;
0310     ifbdev->vma_flags = flags;
0311 
0312     intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
0313     vga_switcheroo_client_fb_set(pdev, info);
0314     return 0;
0315 
0316 out_unpin:
0317     intel_unpin_fb_vma(vma, flags);
0318 out_unlock:
0319     intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
0320     return ret;
0321 }
0322 
0323 static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
0324     .fb_probe = intelfb_create,
0325 };
0326 
0327 static void intel_fbdev_destroy(struct intel_fbdev *ifbdev)
0328 {
0329     /* We rely on the object-free to release the VMA pinning for
0330      * the info->screen_base mmaping. Leaking the VMA is simpler than
0331      * trying to rectify all the possible error paths leading here.
0332      */
0333 
0334     drm_fb_helper_fini(&ifbdev->helper);
0335 
0336     if (ifbdev->vma)
0337         intel_unpin_fb_vma(ifbdev->vma, ifbdev->vma_flags);
0338 
0339     if (ifbdev->fb)
0340         drm_framebuffer_remove(&ifbdev->fb->base);
0341 
0342     kfree(ifbdev);
0343 }
0344 
0345 /*
0346  * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible.
0347  * The core display code will have read out the current plane configuration,
0348  * so we use that to figure out if there's an object for us to use as the
0349  * fb, and if so, we re-use it for the fbdev configuration.
0350  *
0351  * Note we only support a single fb shared across pipes for boot (mostly for
0352  * fbcon), so we just find the biggest and use that.
0353  */
0354 static bool intel_fbdev_init_bios(struct drm_device *dev,
0355                   struct intel_fbdev *ifbdev)
0356 {
0357     struct drm_i915_private *i915 = to_i915(dev);
0358     struct intel_framebuffer *fb = NULL;
0359     struct intel_crtc *crtc;
0360     unsigned int max_size = 0;
0361 
0362     /* Find the largest fb */
0363     for_each_intel_crtc(dev, crtc) {
0364         struct intel_crtc_state *crtc_state =
0365             to_intel_crtc_state(crtc->base.state);
0366         struct intel_plane *plane =
0367             to_intel_plane(crtc->base.primary);
0368         struct intel_plane_state *plane_state =
0369             to_intel_plane_state(plane->base.state);
0370         struct drm_i915_gem_object *obj =
0371             intel_fb_obj(plane_state->uapi.fb);
0372 
0373         if (!crtc_state->uapi.active) {
0374             drm_dbg_kms(&i915->drm,
0375                     "[CRTC:%d:%s] not active, skipping\n",
0376                     crtc->base.base.id, crtc->base.name);
0377             continue;
0378         }
0379 
0380         if (!obj) {
0381             drm_dbg_kms(&i915->drm,
0382                     "[PLANE:%d:%s] no fb, skipping\n",
0383                     plane->base.base.id, plane->base.name);
0384             continue;
0385         }
0386 
0387         if (obj->base.size > max_size) {
0388             drm_dbg_kms(&i915->drm,
0389                     "found possible fb from [PLANE:%d:%s]\n",
0390                     plane->base.base.id, plane->base.name);
0391             fb = to_intel_framebuffer(plane_state->uapi.fb);
0392             max_size = obj->base.size;
0393         }
0394     }
0395 
0396     if (!fb) {
0397         drm_dbg_kms(&i915->drm,
0398                 "no active fbs found, not using BIOS config\n");
0399         goto out;
0400     }
0401 
0402     /* Now make sure all the pipes will fit into it */
0403     for_each_intel_crtc(dev, crtc) {
0404         struct intel_crtc_state *crtc_state =
0405             to_intel_crtc_state(crtc->base.state);
0406         struct intel_plane *plane =
0407             to_intel_plane(crtc->base.primary);
0408         unsigned int cur_size;
0409 
0410         if (!crtc_state->uapi.active) {
0411             drm_dbg_kms(&i915->drm,
0412                     "[CRTC:%d:%s] not active, skipping\n",
0413                     crtc->base.base.id, crtc->base.name);
0414             continue;
0415         }
0416 
0417         drm_dbg_kms(&i915->drm, "checking [PLANE:%d:%s] for BIOS fb\n",
0418                 plane->base.base.id, plane->base.name);
0419 
0420         /*
0421          * See if the plane fb we found above will fit on this
0422          * pipe.  Note we need to use the selected fb's pitch and bpp
0423          * rather than the current pipe's, since they differ.
0424          */
0425         cur_size = crtc_state->uapi.adjusted_mode.crtc_hdisplay;
0426         cur_size = cur_size * fb->base.format->cpp[0];
0427         if (fb->base.pitches[0] < cur_size) {
0428             drm_dbg_kms(&i915->drm,
0429                     "fb not wide enough for [PLANE:%d:%s] (%d vs %d)\n",
0430                     plane->base.base.id, plane->base.name,
0431                     cur_size, fb->base.pitches[0]);
0432             fb = NULL;
0433             break;
0434         }
0435 
0436         cur_size = crtc_state->uapi.adjusted_mode.crtc_vdisplay;
0437         cur_size = intel_fb_align_height(&fb->base, 0, cur_size);
0438         cur_size *= fb->base.pitches[0];
0439         drm_dbg_kms(&i915->drm,
0440                 "[CRTC:%d:%s] area: %dx%d, bpp: %d, size: %d\n",
0441                 crtc->base.base.id, crtc->base.name,
0442                 crtc_state->uapi.adjusted_mode.crtc_hdisplay,
0443                 crtc_state->uapi.adjusted_mode.crtc_vdisplay,
0444                 fb->base.format->cpp[0] * 8,
0445                 cur_size);
0446 
0447         if (cur_size > max_size) {
0448             drm_dbg_kms(&i915->drm,
0449                     "fb not big enough for [PLANE:%d:%s] (%d vs %d)\n",
0450                     plane->base.base.id, plane->base.name,
0451                     cur_size, max_size);
0452             fb = NULL;
0453             break;
0454         }
0455 
0456         drm_dbg_kms(&i915->drm,
0457                 "fb big enough [PLANE:%d:%s] (%d >= %d)\n",
0458                 plane->base.base.id, plane->base.name,
0459                 max_size, cur_size);
0460     }
0461 
0462     if (!fb) {
0463         drm_dbg_kms(&i915->drm,
0464                 "BIOS fb not suitable for all pipes, not using\n");
0465         goto out;
0466     }
0467 
0468     ifbdev->preferred_bpp = fb->base.format->cpp[0] * 8;
0469     ifbdev->fb = fb;
0470 
0471     drm_framebuffer_get(&ifbdev->fb->base);
0472 
0473     /* Final pass to check if any active pipes don't have fbs */
0474     for_each_intel_crtc(dev, crtc) {
0475         struct intel_crtc_state *crtc_state =
0476             to_intel_crtc_state(crtc->base.state);
0477         struct intel_plane *plane =
0478             to_intel_plane(crtc->base.primary);
0479         struct intel_plane_state *plane_state =
0480             to_intel_plane_state(plane->base.state);
0481 
0482         if (!crtc_state->uapi.active)
0483             continue;
0484 
0485         drm_WARN(dev, !plane_state->uapi.fb,
0486              "re-used BIOS config but lost an fb on [PLANE:%d:%s]\n",
0487              plane->base.base.id, plane->base.name);
0488     }
0489 
0490 
0491     drm_dbg_kms(&i915->drm, "using BIOS fb for initial console\n");
0492     return true;
0493 
0494 out:
0495 
0496     return false;
0497 }
0498 
0499 static void intel_fbdev_suspend_worker(struct work_struct *work)
0500 {
0501     intel_fbdev_set_suspend(&container_of(work,
0502                           struct drm_i915_private,
0503                           fbdev_suspend_work)->drm,
0504                 FBINFO_STATE_RUNNING,
0505                 true);
0506 }
0507 
0508 int intel_fbdev_init(struct drm_device *dev)
0509 {
0510     struct drm_i915_private *dev_priv = to_i915(dev);
0511     struct intel_fbdev *ifbdev;
0512     int ret;
0513 
0514     if (drm_WARN_ON(dev, !HAS_DISPLAY(dev_priv)))
0515         return -ENODEV;
0516 
0517     ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
0518     if (ifbdev == NULL)
0519         return -ENOMEM;
0520 
0521     mutex_init(&ifbdev->hpd_lock);
0522     drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs);
0523 
0524     if (!intel_fbdev_init_bios(dev, ifbdev))
0525         ifbdev->preferred_bpp = 32;
0526 
0527     ret = drm_fb_helper_init(dev, &ifbdev->helper);
0528     if (ret) {
0529         kfree(ifbdev);
0530         return ret;
0531     }
0532 
0533     dev_priv->fbdev = ifbdev;
0534     INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker);
0535 
0536     return 0;
0537 }
0538 
0539 static void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
0540 {
0541     struct intel_fbdev *ifbdev = data;
0542 
0543     /* Due to peculiar init order wrt to hpd handling this is separate. */
0544     if (drm_fb_helper_initial_config(&ifbdev->helper,
0545                      ifbdev->preferred_bpp))
0546         intel_fbdev_unregister(to_i915(ifbdev->helper.dev));
0547 }
0548 
0549 void intel_fbdev_initial_config_async(struct drm_device *dev)
0550 {
0551     struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
0552 
0553     if (!ifbdev)
0554         return;
0555 
0556     ifbdev->cookie = async_schedule(intel_fbdev_initial_config, ifbdev);
0557 }
0558 
0559 static void intel_fbdev_sync(struct intel_fbdev *ifbdev)
0560 {
0561     if (!ifbdev->cookie)
0562         return;
0563 
0564     /* Only serialises with all preceding async calls, hence +1 */
0565     async_synchronize_cookie(ifbdev->cookie + 1);
0566     ifbdev->cookie = 0;
0567 }
0568 
0569 void intel_fbdev_unregister(struct drm_i915_private *dev_priv)
0570 {
0571     struct intel_fbdev *ifbdev = dev_priv->fbdev;
0572 
0573     if (!ifbdev)
0574         return;
0575 
0576     cancel_work_sync(&dev_priv->fbdev_suspend_work);
0577     if (!current_is_async())
0578         intel_fbdev_sync(ifbdev);
0579 
0580     drm_fb_helper_unregister_fbi(&ifbdev->helper);
0581 }
0582 
0583 void intel_fbdev_fini(struct drm_i915_private *dev_priv)
0584 {
0585     struct intel_fbdev *ifbdev = fetch_and_zero(&dev_priv->fbdev);
0586 
0587     if (!ifbdev)
0588         return;
0589 
0590     intel_fbdev_destroy(ifbdev);
0591 }
0592 
0593 /* Suspends/resumes fbdev processing of incoming HPD events. When resuming HPD
0594  * processing, fbdev will perform a full connector reprobe if a hotplug event
0595  * was received while HPD was suspended.
0596  */
0597 static void intel_fbdev_hpd_set_suspend(struct drm_i915_private *i915, int state)
0598 {
0599     struct intel_fbdev *ifbdev = i915->fbdev;
0600     bool send_hpd = false;
0601 
0602     mutex_lock(&ifbdev->hpd_lock);
0603     ifbdev->hpd_suspended = state == FBINFO_STATE_SUSPENDED;
0604     send_hpd = !ifbdev->hpd_suspended && ifbdev->hpd_waiting;
0605     ifbdev->hpd_waiting = false;
0606     mutex_unlock(&ifbdev->hpd_lock);
0607 
0608     if (send_hpd) {
0609         drm_dbg_kms(&i915->drm, "Handling delayed fbcon HPD event\n");
0610         drm_fb_helper_hotplug_event(&ifbdev->helper);
0611     }
0612 }
0613 
0614 void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
0615 {
0616     struct drm_i915_private *dev_priv = to_i915(dev);
0617     struct intel_fbdev *ifbdev = dev_priv->fbdev;
0618     struct fb_info *info;
0619 
0620     if (!ifbdev || !ifbdev->vma)
0621         return;
0622 
0623     info = ifbdev->helper.fbdev;
0624 
0625     if (synchronous) {
0626         /* Flush any pending work to turn the console on, and then
0627          * wait to turn it off. It must be synchronous as we are
0628          * about to suspend or unload the driver.
0629          *
0630          * Note that from within the work-handler, we cannot flush
0631          * ourselves, so only flush outstanding work upon suspend!
0632          */
0633         if (state != FBINFO_STATE_RUNNING)
0634             flush_work(&dev_priv->fbdev_suspend_work);
0635 
0636         console_lock();
0637     } else {
0638         /*
0639          * The console lock can be pretty contented on resume due
0640          * to all the printk activity.  Try to keep it out of the hot
0641          * path of resume if possible.
0642          */
0643         drm_WARN_ON(dev, state != FBINFO_STATE_RUNNING);
0644         if (!console_trylock()) {
0645             /* Don't block our own workqueue as this can
0646              * be run in parallel with other i915.ko tasks.
0647              */
0648             schedule_work(&dev_priv->fbdev_suspend_work);
0649             return;
0650         }
0651     }
0652 
0653     /* On resume from hibernation: If the object is shmemfs backed, it has
0654      * been restored from swap. If the object is stolen however, it will be
0655      * full of whatever garbage was left in there.
0656      */
0657     if (state == FBINFO_STATE_RUNNING &&
0658         !i915_gem_object_is_shmem(intel_fb_obj(&ifbdev->fb->base)))
0659         memset_io(info->screen_base, 0, info->screen_size);
0660 
0661     drm_fb_helper_set_suspend(&ifbdev->helper, state);
0662     console_unlock();
0663 
0664     intel_fbdev_hpd_set_suspend(dev_priv, state);
0665 }
0666 
0667 void intel_fbdev_output_poll_changed(struct drm_device *dev)
0668 {
0669     struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
0670     bool send_hpd;
0671 
0672     if (!ifbdev)
0673         return;
0674 
0675     intel_fbdev_sync(ifbdev);
0676 
0677     mutex_lock(&ifbdev->hpd_lock);
0678     send_hpd = !ifbdev->hpd_suspended;
0679     ifbdev->hpd_waiting = true;
0680     mutex_unlock(&ifbdev->hpd_lock);
0681 
0682     if (send_hpd && (ifbdev->vma || ifbdev->helper.deferred_setup))
0683         drm_fb_helper_hotplug_event(&ifbdev->helper);
0684 }
0685 
0686 void intel_fbdev_restore_mode(struct drm_device *dev)
0687 {
0688     struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
0689 
0690     if (!ifbdev)
0691         return;
0692 
0693     intel_fbdev_sync(ifbdev);
0694     if (!ifbdev->vma)
0695         return;
0696 
0697     if (drm_fb_helper_restore_fbdev_mode_unlocked(&ifbdev->helper) == 0)
0698         intel_fbdev_invalidate(ifbdev);
0699 }
0700 
0701 struct intel_framebuffer *intel_fbdev_framebuffer(struct intel_fbdev *fbdev)
0702 {
0703     if (!fbdev || !fbdev->helper.fb)
0704         return NULL;
0705 
0706     return to_intel_framebuffer(fbdev->helper.fb);
0707 }