diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-15 14:19:54 +0900 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-15 14:19:54 +0900 | 
| commit | 049ffa8ab33a63b3bff672d1a0ee6a35ad253fe8 (patch) | |
| tree | 70f4c684818b1c9871fa800088427e40d260592e /drivers/gpu/drm/i915/intel_fbdev.c | |
| parent | c681427e5ca22925fcc1be76a2e260a11e0a8498 (diff) | |
| parent | 0846c728e20a0cd1e43fb75a3015f3b176a26466 (diff) | |
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
 "This is a combo of -next and some -fixes that came in in the
  intervening time.
  Highlights:
  New drivers:
    ARM Armada driver for Marvell Armada 510 SOCs
  Intel:
    Broadwell initial support under a default off switch,
    Stereo/3D HDMI mode support
    Valleyview improvements
    Displayport improvements
    Haswell fixes
    initial mipi dsi panel support
    CRC support for debugging
    build with CONFIG_FB=n
  Radeon:
    enable DPM on a number of GPUs by default
    secondary GPU powerdown support
    enable HDMI audio by default
    Hawaii support
  Nouveau:
    dynamic pm code infrastructure reworked, does nothing major yet
    GK208 modesetting support
    MSI fixes, on by default again
    PMPEG improvements
    pageflipping fixes
  GMA500:
    minnowboard SDVO support
  VMware:
    misc fixes
  MSM:
    prime, plane and rendernodes support
  Tegra:
    rearchitected to put the drm driver into the drm subsystem.
    HDMI and gr2d support for tegra 114 SoC
  QXL:
    oops fix, and multi-head fixes
  DRM core:
    sysfs lifetime fixes
    client capability ioctl
    further cleanups to device midlayer
    more vblank timestamp fixes"
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (789 commits)
  drm/nouveau: do not map evicted vram buffers in nouveau_bo_vma_add
  drm/nvc0-/gr: shift wrapping bug in nvc0_grctx_generate_r406800
  drm/nouveau/pwr: fix missing mutex unlock in a failure path
  drm/nv40/therm: fix slowing down fan when pstate undefined
  drm/nv11-: synchronise flips to vblank, unless async flip requested
  drm/nvc0-: remove nasty fifo swmthd hack for flip completion method
  drm/nv10-: we no longer need to create nvsw object on user channels
  drm/nouveau: always queue flips relative to kernel channel activity
  drm/nouveau: there is no need to reserve/fence the new fb when flipping
  drm/nouveau: when bailing out of a pushbuf ioctl, do not remove previous fence
  drm/nouveau: allow nouveau_fence_ref() to be a noop
  drm/nvc8/mc: msi rearm is via the nvc0 method
  drm/ttm: Fix vma page_prot bit manipulation
  drm/vmwgfx: Fix a couple of compile / sparse warnings and errors
  drm/vmwgfx: Resource evict fixes
  drm/edid: compare actual vrefresh for all modes for quirks
  drm: shmob_drm: Convert to clk_prepare/unprepare
  drm/nouveau: fix 32-bit build
  drm/i915/opregion: fix build error on CONFIG_ACPI=n
  Revert "drm/radeon/audio: don't set speaker allocation on DCE4+"
  ...
Diffstat (limited to 'drivers/gpu/drm/i915/intel_fbdev.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_fbdev.c | 323 | 
1 files changed, 323 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c new file mode 100644 index 000000000000..895fcb4fbd94 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -0,0 +1,323 @@ +/* + * Copyright © 2007 David Airlie + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + *     David Airlie + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/sysrq.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/vga_switcheroo.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_fb_helper.h> +#include "intel_drv.h" +#include <drm/i915_drm.h> +#include "i915_drv.h" + +static struct fb_ops intelfb_ops = { +	.owner = THIS_MODULE, +	.fb_check_var = drm_fb_helper_check_var, +	.fb_set_par = drm_fb_helper_set_par, +	.fb_fillrect = cfb_fillrect, +	.fb_copyarea = cfb_copyarea, +	.fb_imageblit = cfb_imageblit, +	.fb_pan_display = drm_fb_helper_pan_display, +	.fb_blank = drm_fb_helper_blank, +	.fb_setcmap = drm_fb_helper_setcmap, +	.fb_debug_enter = drm_fb_helper_debug_enter, +	.fb_debug_leave = drm_fb_helper_debug_leave, +}; + +static int intelfb_create(struct drm_fb_helper *helper, +			  struct drm_fb_helper_surface_size *sizes) +{ +	struct intel_fbdev *ifbdev = +		container_of(helper, struct intel_fbdev, helper); +	struct drm_device *dev = helper->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct fb_info *info; +	struct drm_framebuffer *fb; +	struct drm_mode_fb_cmd2 mode_cmd = {}; +	struct drm_i915_gem_object *obj; +	struct device *device = &dev->pdev->dev; +	int size, ret; + +	/* we don't do packed 24bpp */ +	if (sizes->surface_bpp == 24) +		sizes->surface_bpp = 32; + +	mode_cmd.width = sizes->surface_width; +	mode_cmd.height = sizes->surface_height; + +	mode_cmd.pitches[0] = ALIGN(mode_cmd.width * +				    DIV_ROUND_UP(sizes->surface_bpp, 8), 64); +	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, +							  sizes->surface_depth); + +	size = mode_cmd.pitches[0] * mode_cmd.height; +	size = ALIGN(size, PAGE_SIZE); +	obj = i915_gem_object_create_stolen(dev, size); +	if (obj == NULL) +		obj = i915_gem_alloc_object(dev, size); +	if (!obj) { +		DRM_ERROR("failed to allocate framebuffer\n"); +		ret = -ENOMEM; +		goto out; +	} + +	mutex_lock(&dev->struct_mutex); + +	/* Flush everything out, we'll be doing GTT only from now on */ +	ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); +	if (ret) { +		DRM_ERROR("failed to pin fb: %d\n", ret); +		goto out_unref; +	} + +	info = framebuffer_alloc(0, device); +	if (!info) { +		ret = -ENOMEM; +		goto out_unpin; +	} + +	info->par = helper; + +	ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); +	if (ret) +		goto out_unpin; + +	fb = &ifbdev->ifb.base; + +	ifbdev->helper.fb = fb; +	ifbdev->helper.fbdev = info; + +	strcpy(info->fix.id, "inteldrmfb"); + +	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; +	info->fbops = &intelfb_ops; + +	ret = fb_alloc_cmap(&info->cmap, 256, 0); +	if (ret) { +		ret = -ENOMEM; +		goto out_unpin; +	} +	/* setup aperture base/size for vesafb takeover */ +	info->apertures = alloc_apertures(1); +	if (!info->apertures) { +		ret = -ENOMEM; +		goto out_unpin; +	} +	info->apertures->ranges[0].base = dev->mode_config.fb_base; +	info->apertures->ranges[0].size = dev_priv->gtt.mappable_end; + +	info->fix.smem_start = dev->mode_config.fb_base + i915_gem_obj_ggtt_offset(obj); +	info->fix.smem_len = size; + +	info->screen_base = +		ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj), +			   size); +	if (!info->screen_base) { +		ret = -ENOSPC; +		goto out_unpin; +	} +	info->screen_size = size; + +	/* This driver doesn't need a VT switch to restore the mode on resume */ +	info->skip_vt_switch = true; + +	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); +	drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); + +	/* 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 (ifbdev->ifb.obj->stolen) +		memset_io(info->screen_base, 0, info->screen_size); + +	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ + +	DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08lx, bo %p\n", +		      fb->width, fb->height, +		      i915_gem_obj_ggtt_offset(obj), obj); + + +	mutex_unlock(&dev->struct_mutex); +	vga_switcheroo_client_fb_set(dev->pdev, info); +	return 0; + +out_unpin: +	i915_gem_object_unpin(obj); +out_unref: +	drm_gem_object_unreference(&obj->base); +	mutex_unlock(&dev->struct_mutex); +out: +	return ret; +} + +/** Sets the color ramps on behalf of RandR */ +static void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, +				    u16 blue, int regno) +{ +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + +	intel_crtc->lut_r[regno] = red >> 8; +	intel_crtc->lut_g[regno] = green >> 8; +	intel_crtc->lut_b[regno] = blue >> 8; +} + +static void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, +				    u16 *blue, int regno) +{ +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + +	*red = intel_crtc->lut_r[regno] << 8; +	*green = intel_crtc->lut_g[regno] << 8; +	*blue = intel_crtc->lut_b[regno] << 8; +} + +static struct drm_fb_helper_funcs intel_fb_helper_funcs = { +	.gamma_set = intel_crtc_fb_gamma_set, +	.gamma_get = intel_crtc_fb_gamma_get, +	.fb_probe = intelfb_create, +}; + +static void intel_fbdev_destroy(struct drm_device *dev, +				struct intel_fbdev *ifbdev) +{ +	if (ifbdev->helper.fbdev) { +		struct fb_info *info = ifbdev->helper.fbdev; + +		unregister_framebuffer(info); +		iounmap(info->screen_base); +		if (info->cmap.len) +			fb_dealloc_cmap(&info->cmap); + +		framebuffer_release(info); +	} + +	drm_fb_helper_fini(&ifbdev->helper); + +	drm_framebuffer_unregister_private(&ifbdev->ifb.base); +	intel_framebuffer_fini(&ifbdev->ifb); +} + +int intel_fbdev_init(struct drm_device *dev) +{ +	struct intel_fbdev *ifbdev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	int ret; + +	ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL); +	if (!ifbdev) +		return -ENOMEM; + +	dev_priv->fbdev = ifbdev; +	ifbdev->helper.funcs = &intel_fb_helper_funcs; + +	ret = drm_fb_helper_init(dev, &ifbdev->helper, +				 INTEL_INFO(dev)->num_pipes, +				 4); +	if (ret) { +		kfree(ifbdev); +		return ret; +	} + +	drm_fb_helper_single_add_all_connectors(&ifbdev->helper); + +	return 0; +} + +void intel_fbdev_initial_config(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; + +	/* Due to peculiar init order wrt to hpd handling this is separate. */ +	drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32); +} + +void intel_fbdev_fini(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	if (!dev_priv->fbdev) +		return; + +	intel_fbdev_destroy(dev, dev_priv->fbdev); +	kfree(dev_priv->fbdev); +	dev_priv->fbdev = NULL; +} + +void intel_fbdev_set_suspend(struct drm_device *dev, int state) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_fbdev *ifbdev = dev_priv->fbdev; +	struct fb_info *info; + +	if (!ifbdev) +		return; + +	info = ifbdev->helper.fbdev; + +	/* 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 && ifbdev->ifb.obj->stolen) +		memset_io(info->screen_base, 0, info->screen_size); + +	fb_set_suspend(info, state); +} + +MODULE_LICENSE("GPL and additional rights"); + +void intel_fbdev_output_poll_changed(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); +} + +void intel_fbdev_restore_mode(struct drm_device *dev) +{ +	int ret; +	struct drm_i915_private *dev_priv = dev->dev_private; + +	if (INTEL_INFO(dev)->num_pipes == 0) +		return; + +	drm_modeset_lock_all(dev); + +	ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); +	if (ret) +		DRM_DEBUG("failed to restore crtc mode\n"); + +	drm_modeset_unlock_all(dev); +}  | 
