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