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