bochs_fbdev.c 4.6 KB
Newer Older
G
Gerd Hoffmann 已提交
1 2 3 4 5 6 7 8 9 10 11
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include "bochs.h"

/* ---------------------------------------------------------------------- */

G
Gerd Hoffmann 已提交
12 13 14 15 16 17 18 19 20 21 22
static int bochsfb_mmap(struct fb_info *info,
			struct vm_area_struct *vma)
{
	struct drm_fb_helper *fb_helper = info->par;
	struct bochs_device *bochs =
		container_of(fb_helper, struct bochs_device, fb.helper);
	struct bochs_bo *bo = gem_to_bochs_bo(bochs->fb.gfb.obj);

	return ttm_fbdev_mmap(vma, &bo->bo);
}

G
Gerd Hoffmann 已提交
23 24
static struct fb_ops bochsfb_ops = {
	.owner = THIS_MODULE,
25
	DRM_FB_HELPER_DEFAULT_OPS,
26 27 28
	.fb_fillrect = drm_fb_helper_cfb_fillrect,
	.fb_copyarea = drm_fb_helper_cfb_copyarea,
	.fb_imageblit = drm_fb_helper_cfb_imageblit,
G
Gerd Hoffmann 已提交
29
	.fb_mmap = bochsfb_mmap,
G
Gerd Hoffmann 已提交
30 31 32
};

static int bochsfb_create_object(struct bochs_device *bochs,
33
				 const struct drm_mode_fb_cmd2 *mode_cmd,
G
Gerd Hoffmann 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
				 struct drm_gem_object **gobj_p)
{
	struct drm_device *dev = bochs->dev;
	struct drm_gem_object *gobj;
	u32 size;
	int ret = 0;

	size = mode_cmd->pitches[0] * mode_cmd->height;
	ret = bochs_gem_create(dev, size, true, &gobj);
	if (ret)
		return ret;

	*gobj_p = gobj;
	return ret;
}

static int bochsfb_create(struct drm_fb_helper *helper,
			  struct drm_fb_helper_surface_size *sizes)
{
	struct bochs_device *bochs =
		container_of(helper, struct bochs_device, fb.helper);
	struct fb_info *info;
	struct drm_framebuffer *fb;
	struct drm_mode_fb_cmd2 mode_cmd;
	struct drm_gem_object *gobj = NULL;
	struct bochs_bo *bo = NULL;
	int size, ret;

	if (sizes->surface_bpp != 32)
		return -EINVAL;

	mode_cmd.width = sizes->surface_width;
	mode_cmd.height = sizes->surface_height;
	mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
							  sizes->surface_depth);
	size = mode_cmd.pitches[0] * mode_cmd.height;

	/* alloc, pin & map bo */
	ret = bochsfb_create_object(bochs, &mode_cmd, &gobj);
	if (ret) {
		DRM_ERROR("failed to create fbcon backing object %d\n", ret);
		return ret;
	}

	bo = gem_to_bochs_bo(gobj);

81
	ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
G
Gerd Hoffmann 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
	if (ret)
		return ret;

	ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
	if (ret) {
		DRM_ERROR("failed to pin fbcon\n");
		ttm_bo_unreserve(&bo->bo);
		return ret;
	}

	ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages,
			  &bo->kmap);
	if (ret) {
		DRM_ERROR("failed to kmap fbcon\n");
		ttm_bo_unreserve(&bo->bo);
		return ret;
	}

	ttm_bo_unreserve(&bo->bo);

	/* init fb device */
103 104 105
	info = drm_fb_helper_alloc_fbi(helper);
	if (IS_ERR(info))
		return PTR_ERR(info);
G
Gerd Hoffmann 已提交
106 107 108 109

	info->par = &bochs->fb.helper;

	ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj);
110
	if (ret)
G
Gerd Hoffmann 已提交
111 112 113 114 115 116 117 118 119 120 121 122
		return ret;

	bochs->fb.size = size;

	/* setup helper */
	fb = &bochs->fb.gfb.base;
	bochs->fb.helper.fb = fb;

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

	info->fbops = &bochsfb_ops;

V
Ville Syrjälä 已提交
123
	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
G
Gerd Hoffmann 已提交
124 125 126 127 128 129
	drm_fb_helper_fill_var(info, &bochs->fb.helper, sizes->fb_width,
			       sizes->fb_height);

	info->screen_base = bo->kmap.virtual;
	info->screen_size = size;

G
Gerd Hoffmann 已提交
130 131
	drm_vma_offset_remove(&bo->bo.bdev->vma_manager, &bo->bo.vma_node);
	info->fix.smem_start = 0;
G
Gerd Hoffmann 已提交
132 133
	info->fix.smem_len = size;

134
	bochs->fb.initialized = true;
G
Gerd Hoffmann 已提交
135 136 137 138 139 140 141 142 143
	return 0;
}

static int bochs_fbdev_destroy(struct bochs_device *bochs)
{
	struct bochs_framebuffer *gfb = &bochs->fb.gfb;

	DRM_DEBUG_DRIVER("\n");

144
	drm_fb_helper_unregister_fbi(&bochs->fb.helper);
G
Gerd Hoffmann 已提交
145 146 147 148 149 150 151 152 153 154 155 156

	if (gfb->obj) {
		drm_gem_object_unreference_unlocked(gfb->obj);
		gfb->obj = NULL;
	}

	drm_framebuffer_unregister_private(&gfb->base);
	drm_framebuffer_cleanup(&gfb->base);

	return 0;
}

157
static const struct drm_fb_helper_funcs bochs_fb_helper_funcs = {
G
Gerd Hoffmann 已提交
158 159 160 161 162 163 164
	.fb_probe = bochsfb_create,
};

int bochs_fbdev_init(struct bochs_device *bochs)
{
	int ret;

165 166
	drm_fb_helper_prepare(bochs->dev, &bochs->fb.helper,
			      &bochs_fb_helper_funcs);
G
Gerd Hoffmann 已提交
167

168
	ret = drm_fb_helper_init(bochs->dev, &bochs->fb.helper, 1);
G
Gerd Hoffmann 已提交
169 170 171
	if (ret)
		return ret;

172 173 174 175
	ret = drm_fb_helper_single_add_all_connectors(&bochs->fb.helper);
	if (ret)
		goto fini;

G
Gerd Hoffmann 已提交
176
	drm_helper_disable_unused_functions(bochs->dev);
177 178 179 180

	ret = drm_fb_helper_initial_config(&bochs->fb.helper, 32);
	if (ret)
		goto fini;
G
Gerd Hoffmann 已提交
181 182

	return 0;
183 184 185 186

fini:
	drm_fb_helper_fini(&bochs->fb.helper);
	return ret;
G
Gerd Hoffmann 已提交
187 188 189 190
}

void bochs_fbdev_fini(struct bochs_device *bochs)
{
191 192
	if (bochs->fb.initialized)
		bochs_fbdev_destroy(bochs);
G
Gerd Hoffmann 已提交
193

194 195 196
	if (bochs->fb.helper.fbdev)
		drm_fb_helper_fini(&bochs->fb.helper);

G
Gerd Hoffmann 已提交
197 198
	bochs->fb.initialized = false;
}