1*717f4a47SSascha Wildner /* 2*717f4a47SSascha Wildner * Copyright © 2007 David Airlie 3*717f4a47SSascha Wildner * 4*717f4a47SSascha Wildner * Permission is hereby granted, free of charge, to any person obtaining a 5*717f4a47SSascha Wildner * copy of this software and associated documentation files (the "Software"), 6*717f4a47SSascha Wildner * to deal in the Software without restriction, including without limitation 7*717f4a47SSascha Wildner * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8*717f4a47SSascha Wildner * and/or sell copies of the Software, and to permit persons to whom the 9*717f4a47SSascha Wildner * Software is furnished to do so, subject to the following conditions: 10*717f4a47SSascha Wildner * 11*717f4a47SSascha Wildner * The above copyright notice and this permission notice (including the next 12*717f4a47SSascha Wildner * paragraph) shall be included in all copies or substantial portions of the 13*717f4a47SSascha Wildner * Software. 14*717f4a47SSascha Wildner * 15*717f4a47SSascha Wildner * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16*717f4a47SSascha Wildner * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17*717f4a47SSascha Wildner * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18*717f4a47SSascha Wildner * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19*717f4a47SSascha Wildner * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20*717f4a47SSascha Wildner * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21*717f4a47SSascha Wildner * DEALINGS IN THE SOFTWARE. 22*717f4a47SSascha Wildner * 23*717f4a47SSascha Wildner * Authors: 24*717f4a47SSascha Wildner * David Airlie 25*717f4a47SSascha Wildner */ 26*717f4a47SSascha Wildner 27*717f4a47SSascha Wildner #include <drm/drmP.h> 28*717f4a47SSascha Wildner #include <linux/module.h> 29*717f4a47SSascha Wildner #include <linux/kernel.h> 30*717f4a47SSascha Wildner #include <linux/errno.h> 31*717f4a47SSascha Wildner #include <linux/string.h> 32*717f4a47SSascha Wildner #include <linux/mm.h> 33*717f4a47SSascha Wildner #include <linux/delay.h> 34*717f4a47SSascha Wildner #include <linux/fb.h> 35*717f4a47SSascha Wildner 36*717f4a47SSascha Wildner #include <drm/drm_crtc.h> 37*717f4a47SSascha Wildner #include <drm/drm_fb_helper.h> 38*717f4a47SSascha Wildner #include "intel_drv.h" 39*717f4a47SSascha Wildner #include <drm/i915_drm.h> 40*717f4a47SSascha Wildner #include "i915_drv.h" 41*717f4a47SSascha Wildner 42*717f4a47SSascha Wildner #if 0 43*717f4a47SSascha Wildner static struct fb_ops intelfb_ops = { 44*717f4a47SSascha Wildner .owner = THIS_MODULE, 45*717f4a47SSascha Wildner .fb_check_var = drm_fb_helper_check_var, 46*717f4a47SSascha Wildner .fb_set_par = drm_fb_helper_set_par, 47*717f4a47SSascha Wildner .fb_fillrect = cfb_fillrect, 48*717f4a47SSascha Wildner .fb_copyarea = cfb_copyarea, 49*717f4a47SSascha Wildner .fb_imageblit = cfb_imageblit, 50*717f4a47SSascha Wildner .fb_pan_display = drm_fb_helper_pan_display, 51*717f4a47SSascha Wildner .fb_blank = drm_fb_helper_blank, 52*717f4a47SSascha Wildner .fb_setcmap = drm_fb_helper_setcmap, 53*717f4a47SSascha Wildner .fb_debug_enter = drm_fb_helper_debug_enter, 54*717f4a47SSascha Wildner .fb_debug_leave = drm_fb_helper_debug_leave, 55*717f4a47SSascha Wildner }; 56*717f4a47SSascha Wildner #endif 57*717f4a47SSascha Wildner 58*717f4a47SSascha Wildner static int intelfb_alloc(struct drm_fb_helper *helper, 59*717f4a47SSascha Wildner struct drm_fb_helper_surface_size *sizes) 60*717f4a47SSascha Wildner { 61*717f4a47SSascha Wildner struct intel_fbdev *ifbdev = 62*717f4a47SSascha Wildner container_of(helper, struct intel_fbdev, helper); 63*717f4a47SSascha Wildner struct drm_device *dev = helper->dev; 64*717f4a47SSascha Wildner struct drm_mode_fb_cmd2 mode_cmd = {}; 65*717f4a47SSascha Wildner struct drm_i915_gem_object *obj; 66*717f4a47SSascha Wildner int size, ret; 67*717f4a47SSascha Wildner 68*717f4a47SSascha Wildner /* we don't do packed 24bpp */ 69*717f4a47SSascha Wildner if (sizes->surface_bpp == 24) 70*717f4a47SSascha Wildner sizes->surface_bpp = 32; 71*717f4a47SSascha Wildner 72*717f4a47SSascha Wildner mode_cmd.width = sizes->surface_width; 73*717f4a47SSascha Wildner mode_cmd.height = sizes->surface_height; 74*717f4a47SSascha Wildner 75*717f4a47SSascha Wildner mode_cmd.pitches[0] = ALIGN(mode_cmd.width * 76*717f4a47SSascha Wildner DIV_ROUND_UP(sizes->surface_bpp, 8), 64); 77*717f4a47SSascha Wildner mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, 78*717f4a47SSascha Wildner sizes->surface_depth); 79*717f4a47SSascha Wildner 80*717f4a47SSascha Wildner size = mode_cmd.pitches[0] * mode_cmd.height; 81*717f4a47SSascha Wildner size = ALIGN(size, PAGE_SIZE); 82*717f4a47SSascha Wildner obj = i915_gem_object_create_stolen(dev, size); 83*717f4a47SSascha Wildner if (obj == NULL) 84*717f4a47SSascha Wildner obj = i915_gem_alloc_object(dev, size); 85*717f4a47SSascha Wildner if (!obj) { 86*717f4a47SSascha Wildner DRM_ERROR("failed to allocate framebuffer\n"); 87*717f4a47SSascha Wildner ret = -ENOMEM; 88*717f4a47SSascha Wildner goto out; 89*717f4a47SSascha Wildner } 90*717f4a47SSascha Wildner 91*717f4a47SSascha Wildner /* Flush everything out, we'll be doing GTT only from now on */ 92*717f4a47SSascha Wildner ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); 93*717f4a47SSascha Wildner if (ret) { 94*717f4a47SSascha Wildner DRM_ERROR("failed to pin fb: %d\n", ret); 95*717f4a47SSascha Wildner goto out_unref; 96*717f4a47SSascha Wildner } 97*717f4a47SSascha Wildner 98*717f4a47SSascha Wildner ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); 99*717f4a47SSascha Wildner if (ret) 100*717f4a47SSascha Wildner goto out_unpin; 101*717f4a47SSascha Wildner 102*717f4a47SSascha Wildner return 0; 103*717f4a47SSascha Wildner 104*717f4a47SSascha Wildner out_unpin: 105*717f4a47SSascha Wildner i915_gem_object_unpin(obj); 106*717f4a47SSascha Wildner out_unref: 107*717f4a47SSascha Wildner drm_gem_object_unreference(&obj->base); 108*717f4a47SSascha Wildner out: 109*717f4a47SSascha Wildner return ret; 110*717f4a47SSascha Wildner } 111*717f4a47SSascha Wildner 112*717f4a47SSascha Wildner static int intelfb_create(struct drm_fb_helper *helper, 113*717f4a47SSascha Wildner struct drm_fb_helper_surface_size *sizes) 114*717f4a47SSascha Wildner { 115*717f4a47SSascha Wildner struct intel_fbdev *ifbdev = 116*717f4a47SSascha Wildner container_of(helper, struct intel_fbdev, helper); 117*717f4a47SSascha Wildner struct intel_framebuffer *intel_fb = &ifbdev->ifb; 118*717f4a47SSascha Wildner struct drm_device *dev = helper->dev; 119*717f4a47SSascha Wildner #if 0 120*717f4a47SSascha Wildner struct drm_i915_private *dev_priv = dev->dev_private; 121*717f4a47SSascha Wildner #endif 122*717f4a47SSascha Wildner struct fb_info *info; 123*717f4a47SSascha Wildner struct drm_framebuffer *fb; 124*717f4a47SSascha Wildner struct drm_i915_gem_object *obj; 125*717f4a47SSascha Wildner device_t vga_dev; 126*717f4a47SSascha Wildner int size, ret; 127*717f4a47SSascha Wildner 128*717f4a47SSascha Wildner mutex_lock(&dev->struct_mutex); 129*717f4a47SSascha Wildner 130*717f4a47SSascha Wildner if (!intel_fb->obj) { 131*717f4a47SSascha Wildner DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n"); 132*717f4a47SSascha Wildner ret = intelfb_alloc(helper, sizes); 133*717f4a47SSascha Wildner if (ret) 134*717f4a47SSascha Wildner goto out_unlock; 135*717f4a47SSascha Wildner } else { 136*717f4a47SSascha Wildner DRM_DEBUG_KMS("re-using BIOS fb\n"); 137*717f4a47SSascha Wildner sizes->fb_width = intel_fb->base.width; 138*717f4a47SSascha Wildner sizes->fb_height = intel_fb->base.height; 139*717f4a47SSascha Wildner } 140*717f4a47SSascha Wildner 141*717f4a47SSascha Wildner obj = intel_fb->obj; 142*717f4a47SSascha Wildner size = obj->base.size; 143*717f4a47SSascha Wildner 144*717f4a47SSascha Wildner #if 0 145*717f4a47SSascha Wildner info = framebuffer_alloc(0, &dev->pdev->dev); 146*717f4a47SSascha Wildner if (!info) { 147*717f4a47SSascha Wildner ret = -ENOMEM; 148*717f4a47SSascha Wildner goto out_unpin; 149*717f4a47SSascha Wildner } 150*717f4a47SSascha Wildner 151*717f4a47SSascha Wildner info->par = helper; 152*717f4a47SSascha Wildner #endif 153*717f4a47SSascha Wildner vga_dev = device_get_parent(dev->dev); 154*717f4a47SSascha Wildner info = kmalloc(sizeof(struct fb_info), M_DRM, M_WAITOK | M_ZERO); 155*717f4a47SSascha Wildner info->width = sizes->fb_width; 156*717f4a47SSascha Wildner info->height = sizes->fb_height; 157*717f4a47SSascha Wildner info->stride = 158*717f4a47SSascha Wildner ALIGN(sizes->surface_width * ((sizes->surface_bpp + 7) / 8), 64); 159*717f4a47SSascha Wildner info->depth = sizes->surface_bpp; 160*717f4a47SSascha Wildner info->paddr = dev->agp->base + i915_gem_obj_ggtt_offset(obj); 161*717f4a47SSascha Wildner info->is_vga_boot_display = vga_pci_is_boot_display(vga_dev); 162*717f4a47SSascha Wildner info->vaddr = 163*717f4a47SSascha Wildner (vm_offset_t)pmap_mapdev_attr(info->paddr, 164*717f4a47SSascha Wildner sizes->surface_height * info->stride, 165*717f4a47SSascha Wildner VM_MEMATTR_WRITE_COMBINING); 166*717f4a47SSascha Wildner 167*717f4a47SSascha Wildner fb = &ifbdev->ifb.base; 168*717f4a47SSascha Wildner 169*717f4a47SSascha Wildner ifbdev->helper.fb = fb; 170*717f4a47SSascha Wildner ifbdev->helper.fbdev = info; 171*717f4a47SSascha Wildner 172*717f4a47SSascha Wildner #if 0 173*717f4a47SSascha Wildner strcpy(info->fix.id, "inteldrmfb"); 174*717f4a47SSascha Wildner 175*717f4a47SSascha Wildner info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; 176*717f4a47SSascha Wildner info->fbops = &intelfb_ops; 177*717f4a47SSascha Wildner 178*717f4a47SSascha Wildner ret = fb_alloc_cmap(&info->cmap, 256, 0); 179*717f4a47SSascha Wildner if (ret) { 180*717f4a47SSascha Wildner ret = -ENOMEM; 181*717f4a47SSascha Wildner goto out_unpin; 182*717f4a47SSascha Wildner } 183*717f4a47SSascha Wildner /* setup aperture base/size for vesafb takeover */ 184*717f4a47SSascha Wildner info->apertures = alloc_apertures(1); 185*717f4a47SSascha Wildner if (!info->apertures) { 186*717f4a47SSascha Wildner ret = -ENOMEM; 187*717f4a47SSascha Wildner goto out_unpin; 188*717f4a47SSascha Wildner } 189*717f4a47SSascha Wildner info->apertures->ranges[0].base = dev->mode_config.fb_base; 190*717f4a47SSascha Wildner info->apertures->ranges[0].size = dev_priv->gtt.mappable_end; 191*717f4a47SSascha Wildner 192*717f4a47SSascha Wildner info->fix.smem_start = dev->mode_config.fb_base + i915_gem_obj_ggtt_offset(obj); 193*717f4a47SSascha Wildner info->fix.smem_len = size; 194*717f4a47SSascha Wildner 195*717f4a47SSascha Wildner info->screen_base = 196*717f4a47SSascha Wildner ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj), 197*717f4a47SSascha Wildner size); 198*717f4a47SSascha Wildner if (!info->screen_base) { 199*717f4a47SSascha Wildner ret = -ENOSPC; 200*717f4a47SSascha Wildner goto out_unpin; 201*717f4a47SSascha Wildner } 202*717f4a47SSascha Wildner info->screen_size = size; 203*717f4a47SSascha Wildner 204*717f4a47SSascha Wildner /* This driver doesn't need a VT switch to restore the mode on resume */ 205*717f4a47SSascha Wildner info->skip_vt_switch = true; 206*717f4a47SSascha Wildner 207*717f4a47SSascha Wildner drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); 208*717f4a47SSascha Wildner drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); 209*717f4a47SSascha Wildner 210*717f4a47SSascha Wildner /* If the object is shmemfs backed, it will have given us zeroed pages. 211*717f4a47SSascha Wildner * If the object is stolen however, it will be full of whatever 212*717f4a47SSascha Wildner * garbage was left in there. 213*717f4a47SSascha Wildner */ 214*717f4a47SSascha Wildner if (ifbdev->ifb.obj->stolen) 215*717f4a47SSascha Wildner memset_io(info->screen_base, 0, info->screen_size); 216*717f4a47SSascha Wildner 217*717f4a47SSascha Wildner /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ 218*717f4a47SSascha Wildner #endif 219*717f4a47SSascha Wildner 220*717f4a47SSascha Wildner DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08lx, bo %p\n", 221*717f4a47SSascha Wildner fb->width, fb->height, 222*717f4a47SSascha Wildner i915_gem_obj_ggtt_offset(obj), obj); 223*717f4a47SSascha Wildner 224*717f4a47SSascha Wildner mutex_unlock(&dev->struct_mutex); 225*717f4a47SSascha Wildner #if 0 226*717f4a47SSascha Wildner vga_switcheroo_client_fb_set(dev->pdev, info); 227*717f4a47SSascha Wildner #endif 228*717f4a47SSascha Wildner return 0; 229*717f4a47SSascha Wildner 230*717f4a47SSascha Wildner #if 0 231*717f4a47SSascha Wildner out_unpin: 232*717f4a47SSascha Wildner i915_gem_object_unpin(obj); 233*717f4a47SSascha Wildner drm_gem_object_unreference(&obj->base); 234*717f4a47SSascha Wildner #endif 235*717f4a47SSascha Wildner out_unlock: 236*717f4a47SSascha Wildner mutex_unlock(&dev->struct_mutex); 237*717f4a47SSascha Wildner return ret; 238*717f4a47SSascha Wildner } 239*717f4a47SSascha Wildner 240*717f4a47SSascha Wildner /** Sets the color ramps on behalf of RandR */ 241*717f4a47SSascha Wildner static void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, 242*717f4a47SSascha Wildner u16 blue, int regno) 243*717f4a47SSascha Wildner { 244*717f4a47SSascha Wildner struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 245*717f4a47SSascha Wildner 246*717f4a47SSascha Wildner intel_crtc->lut_r[regno] = red >> 8; 247*717f4a47SSascha Wildner intel_crtc->lut_g[regno] = green >> 8; 248*717f4a47SSascha Wildner intel_crtc->lut_b[regno] = blue >> 8; 249*717f4a47SSascha Wildner } 250*717f4a47SSascha Wildner 251*717f4a47SSascha Wildner static void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, 252*717f4a47SSascha Wildner u16 *blue, int regno) 253*717f4a47SSascha Wildner { 254*717f4a47SSascha Wildner struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 255*717f4a47SSascha Wildner 256*717f4a47SSascha Wildner *red = intel_crtc->lut_r[regno] << 8; 257*717f4a47SSascha Wildner *green = intel_crtc->lut_g[regno] << 8; 258*717f4a47SSascha Wildner *blue = intel_crtc->lut_b[regno] << 8; 259*717f4a47SSascha Wildner } 260*717f4a47SSascha Wildner 261*717f4a47SSascha Wildner static struct drm_fb_helper_funcs intel_fb_helper_funcs = { 262*717f4a47SSascha Wildner .gamma_set = intel_crtc_fb_gamma_set, 263*717f4a47SSascha Wildner .gamma_get = intel_crtc_fb_gamma_get, 264*717f4a47SSascha Wildner .fb_probe = intelfb_create, 265*717f4a47SSascha Wildner }; 266*717f4a47SSascha Wildner 267*717f4a47SSascha Wildner static void intel_fbdev_destroy(struct drm_device *dev, 268*717f4a47SSascha Wildner struct intel_fbdev *ifbdev) 269*717f4a47SSascha Wildner { 270*717f4a47SSascha Wildner #if 0 271*717f4a47SSascha Wildner if (ifbdev->helper.fbdev) { 272*717f4a47SSascha Wildner struct fb_info *info = ifbdev->helper.fbdev; 273*717f4a47SSascha Wildner 274*717f4a47SSascha Wildner unregister_framebuffer(info); 275*717f4a47SSascha Wildner iounmap(info->screen_base); 276*717f4a47SSascha Wildner if (info->cmap.len) 277*717f4a47SSascha Wildner fb_dealloc_cmap(&info->cmap); 278*717f4a47SSascha Wildner 279*717f4a47SSascha Wildner framebuffer_release(info); 280*717f4a47SSascha Wildner } 281*717f4a47SSascha Wildner #endif 282*717f4a47SSascha Wildner 283*717f4a47SSascha Wildner drm_fb_helper_fini(&ifbdev->helper); 284*717f4a47SSascha Wildner 285*717f4a47SSascha Wildner drm_framebuffer_unregister_private(&ifbdev->ifb.base); 286*717f4a47SSascha Wildner intel_framebuffer_fini(&ifbdev->ifb); 287*717f4a47SSascha Wildner } 288*717f4a47SSascha Wildner 289*717f4a47SSascha Wildner int intel_fbdev_init(struct drm_device *dev) 290*717f4a47SSascha Wildner { 291*717f4a47SSascha Wildner struct intel_fbdev *ifbdev; 292*717f4a47SSascha Wildner struct drm_i915_private *dev_priv = dev->dev_private; 293*717f4a47SSascha Wildner int ret; 294*717f4a47SSascha Wildner 295*717f4a47SSascha Wildner ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL); 296*717f4a47SSascha Wildner if (!ifbdev) 297*717f4a47SSascha Wildner return -ENOMEM; 298*717f4a47SSascha Wildner 299*717f4a47SSascha Wildner dev_priv->fbdev = ifbdev; 300*717f4a47SSascha Wildner ifbdev->helper.funcs = &intel_fb_helper_funcs; 301*717f4a47SSascha Wildner 302*717f4a47SSascha Wildner ret = drm_fb_helper_init(dev, &ifbdev->helper, 303*717f4a47SSascha Wildner INTEL_INFO(dev)->num_pipes, 304*717f4a47SSascha Wildner 4); 305*717f4a47SSascha Wildner if (ret) { 306*717f4a47SSascha Wildner kfree(ifbdev); 307*717f4a47SSascha Wildner return ret; 308*717f4a47SSascha Wildner } 309*717f4a47SSascha Wildner 310*717f4a47SSascha Wildner drm_fb_helper_single_add_all_connectors(&ifbdev->helper); 311*717f4a47SSascha Wildner 312*717f4a47SSascha Wildner return 0; 313*717f4a47SSascha Wildner } 314*717f4a47SSascha Wildner 315*717f4a47SSascha Wildner void intel_fbdev_initial_config(struct drm_device *dev) 316*717f4a47SSascha Wildner { 317*717f4a47SSascha Wildner struct drm_i915_private *dev_priv = dev->dev_private; 318*717f4a47SSascha Wildner 319*717f4a47SSascha Wildner /* Due to peculiar init order wrt to hpd handling this is separate. */ 320*717f4a47SSascha Wildner drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32); 321*717f4a47SSascha Wildner } 322*717f4a47SSascha Wildner 323*717f4a47SSascha Wildner void intel_fbdev_fini(struct drm_device *dev) 324*717f4a47SSascha Wildner { 325*717f4a47SSascha Wildner struct drm_i915_private *dev_priv = dev->dev_private; 326*717f4a47SSascha Wildner if (!dev_priv->fbdev) 327*717f4a47SSascha Wildner return; 328*717f4a47SSascha Wildner 329*717f4a47SSascha Wildner intel_fbdev_destroy(dev, dev_priv->fbdev); 330*717f4a47SSascha Wildner kfree(dev_priv->fbdev); 331*717f4a47SSascha Wildner dev_priv->fbdev = NULL; 332*717f4a47SSascha Wildner } 333*717f4a47SSascha Wildner 334*717f4a47SSascha Wildner void intel_fbdev_set_suspend(struct drm_device *dev, int state) 335*717f4a47SSascha Wildner { 336*717f4a47SSascha Wildner #if 0 337*717f4a47SSascha Wildner struct drm_i915_private *dev_priv = dev->dev_private; 338*717f4a47SSascha Wildner struct intel_fbdev *ifbdev = dev_priv->fbdev; 339*717f4a47SSascha Wildner struct fb_info *info; 340*717f4a47SSascha Wildner 341*717f4a47SSascha Wildner if (!ifbdev) 342*717f4a47SSascha Wildner return; 343*717f4a47SSascha Wildner 344*717f4a47SSascha Wildner info = ifbdev->helper.fbdev; 345*717f4a47SSascha Wildner 346*717f4a47SSascha Wildner /* On resume from hibernation: If the object is shmemfs backed, it has 347*717f4a47SSascha Wildner * been restored from swap. If the object is stolen however, it will be 348*717f4a47SSascha Wildner * full of whatever garbage was left in there. 349*717f4a47SSascha Wildner */ 350*717f4a47SSascha Wildner if (state == FBINFO_STATE_RUNNING && ifbdev->ifb.obj->stolen) 351*717f4a47SSascha Wildner memset_io(info->screen_base, 0, info->screen_size); 352*717f4a47SSascha Wildner 353*717f4a47SSascha Wildner fb_set_suspend(info, state); 354*717f4a47SSascha Wildner #endif 355*717f4a47SSascha Wildner } 356*717f4a47SSascha Wildner 357*717f4a47SSascha Wildner void intel_fbdev_output_poll_changed(struct drm_device *dev) 358*717f4a47SSascha Wildner { 359*717f4a47SSascha Wildner struct drm_i915_private *dev_priv = dev->dev_private; 360*717f4a47SSascha Wildner drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); 361*717f4a47SSascha Wildner } 362*717f4a47SSascha Wildner 363*717f4a47SSascha Wildner void intel_fbdev_restore_mode(struct drm_device *dev) 364*717f4a47SSascha Wildner { 365*717f4a47SSascha Wildner int ret; 366*717f4a47SSascha Wildner struct drm_i915_private *dev_priv = dev->dev_private; 367*717f4a47SSascha Wildner 368*717f4a47SSascha Wildner if (INTEL_INFO(dev)->num_pipes == 0) 369*717f4a47SSascha Wildner return; 370*717f4a47SSascha Wildner 371*717f4a47SSascha Wildner drm_modeset_lock_all(dev); 372*717f4a47SSascha Wildner 373*717f4a47SSascha Wildner ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); 374*717f4a47SSascha Wildner if (ret) 375*717f4a47SSascha Wildner DRM_DEBUG("failed to restore crtc mode\n"); 376*717f4a47SSascha Wildner 377*717f4a47SSascha Wildner drm_modeset_unlock_all(dev); 378*717f4a47SSascha Wildner } 379