Пример #1
0
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 intel_framebuffer *intel_fb = ifbdev->fb;
	struct drm_device *dev = helper->dev;
	struct drm_i915_private *dev_priv = to_i915(dev);
	struct pci_dev *pdev = dev_priv->drm.pdev;
	struct i915_ggtt *ggtt = &dev_priv->ggtt;
	struct fb_info *info;
	struct drm_framebuffer *fb;
	struct i915_vma *vma;
	unsigned long flags = 0;
	bool prealloc = false;
	void __iomem *vaddr;
	int ret;

	if (intel_fb &&
	    (sizes->fb_width > intel_fb->base.width ||
	     sizes->fb_height > intel_fb->base.height)) {
		DRM_DEBUG_KMS("BIOS fb too small (%dx%d), we require (%dx%d),"
			      " releasing it\n",
			      intel_fb->base.width, intel_fb->base.height,
			      sizes->fb_width, sizes->fb_height);
		drm_framebuffer_put(&intel_fb->base);
		intel_fb = ifbdev->fb = NULL;
	}
	if (!intel_fb || WARN_ON(!intel_fb_obj(&intel_fb->base))) {
		DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
		ret = intelfb_alloc(helper, sizes);
		if (ret)
			return ret;
		intel_fb = ifbdev->fb;
	} else {
		DRM_DEBUG_KMS("re-using BIOS fb\n");
		prealloc = true;
		sizes->fb_width = intel_fb->base.width;
		sizes->fb_height = intel_fb->base.height;
	}

	mutex_lock(&dev->struct_mutex);
	intel_runtime_pm_get(dev_priv);

	/* Pin the GGTT vma for our access via info->screen_base.
	 * This also validates that any existing fb inherited from the
	 * BIOS is suitable for own access.
	 */
	vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base,
					 DRM_MODE_ROTATE_0,
					 false, &flags);
	if (IS_ERR(vma)) {
		ret = PTR_ERR(vma);
		goto out_unlock;
	}

	fb = &ifbdev->fb->base;
	intel_fb_obj_flush(intel_fb_obj(fb), ORIGIN_DIRTYFB);

	info = drm_fb_helper_alloc_fbi(helper);
	if (IS_ERR(info)) {
		DRM_ERROR("Failed to allocate fb_info\n");
		ret = PTR_ERR(info);
		goto out_unpin;
	}

	info->par = helper;

	ifbdev->helper.fb = fb;

	strcpy(info->fix.id, "inteldrmfb");

	info->fbops = &intelfb_ops;

	/* setup aperture base/size for vesafb takeover */
	info->apertures->ranges[0].base = dev->mode_config.fb_base;
	info->apertures->ranges[0].size = ggtt->mappable_end;

	info->fix.smem_start = dev->mode_config.fb_base + i915_ggtt_offset(vma);
	info->fix.smem_len = vma->node.size;

	vaddr = i915_vma_pin_iomap(vma);
	if (IS_ERR(vaddr)) {
		DRM_ERROR("Failed to remap framebuffer into virtual memory\n");
		ret = PTR_ERR(vaddr);
		goto out_unpin;
	}
	info->screen_base = vaddr;
	info->screen_size = vma->node.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->format->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 (intel_fb_obj(fb)->stolen && !prealloc)
		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%08x\n",
		      fb->width, fb->height, i915_ggtt_offset(vma));
	ifbdev->vma = vma;
	ifbdev->vma_flags = flags;

	intel_runtime_pm_put(dev_priv);
	mutex_unlock(&dev->struct_mutex);
	vga_switcheroo_client_fb_set(pdev, info);
	return 0;

out_unpin:
	intel_unpin_fb_vma(vma, flags);
out_unlock:
	intel_runtime_pm_put(dev_priv);
	mutex_unlock(&dev->struct_mutex);
	return ret;
}
Пример #2
0
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 intel_framebuffer *intel_fb = &ifbdev->ifb;
	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_i915_gem_object *obj;
	int size, ret;

	mutex_lock(&dev->struct_mutex);

	if (!intel_fb->obj) {
		DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
		ret = intelfb_alloc(helper, sizes);
		if (ret)
			goto out_unlock;
	} else {
		DRM_DEBUG_KMS("re-using BIOS fb\n");
		sizes->fb_width = intel_fb->base.width;
		sizes->fb_height = intel_fb->base.height;
	}

	obj = intel_fb->obj;
	size = obj->base.size;

	info = framebuffer_alloc(0, &dev->pdev->dev);
	if (!info) {
		ret = -ENOMEM;
		goto out_unpin;
	}

	info->par = helper;

	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;
	}

	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;

	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);
	drm_gem_object_unreference(&obj->base);
out_unlock:
	mutex_unlock(&dev->struct_mutex);
	return ret;
}
Пример #3
0
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 intel_framebuffer *intel_fb = ifbdev->fb;
    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_i915_gem_object *obj;
    int size, ret;
    bool prealloc = false;

    mutex_lock(&dev->struct_mutex);

    if (intel_fb &&
            (sizes->fb_width > intel_fb->base.width ||
             sizes->fb_height > intel_fb->base.height)) {
        DRM_DEBUG_KMS("BIOS fb too small (%dx%d), we require (%dx%d),"
                      " releasing it\n",
                      intel_fb->base.width, intel_fb->base.height,
                      sizes->fb_width, sizes->fb_height);
        drm_framebuffer_unreference(&intel_fb->base);
        intel_fb = ifbdev->fb = NULL;
    }
    if (!intel_fb || WARN_ON(!intel_fb->obj)) {
        DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
        ret = intelfb_alloc(helper, sizes);
        if (ret)
            goto out_unlock;
        intel_fb = ifbdev->fb;
    } else {
        DRM_DEBUG_KMS("re-using BIOS fb\n");
        prealloc = true;
        sizes->fb_width = intel_fb->base.width;
        sizes->fb_height = intel_fb->base.height;
    }

    obj = intel_fb->obj;
    size = obj->base.size;

    info = framebuffer_alloc(0, &dev->pdev->dev);
    if (!info) {
        ret = -ENOMEM;
        goto out_unpin;
    }

    info->par = helper;

    fb = &ifbdev->fb->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->fb->obj->stolen && !prealloc)
        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_ggtt_unpin(obj);
    drm_gem_object_unreference(&obj->base);
out_unlock:
    mutex_unlock(&dev->struct_mutex);
    return ret;
}