radeon_fb.c 10.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * 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>
27
#include <linux/slab.h>
28 29 30 31 32 33 34 35 36
#include <linux/fb.h>

#include "drmP.h"
#include "drm.h"
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
#include "radeon_drm.h"
#include "radeon.h"

37 38
#include "drm_fb_helper.h"

39 40
#include <linux/vga_switcheroo.h>

41 42 43 44
/* object hierarchy -
   this contains a helper + a radeon fb
   the helper contains a pointer to radeon framebuffer baseclass.
*/
45
struct radeon_fbdev {
46
	struct drm_fb_helper helper;
47 48 49
	struct radeon_framebuffer rfb;
	struct list_head fbdev_list;
	struct radeon_device *rdev;
50 51 52 53
};

static struct fb_ops radeonfb_ops = {
	.owner = THIS_MODULE,
54
	.fb_check_var = drm_fb_helper_check_var,
55
	.fb_set_par = drm_fb_helper_set_par,
56 57 58
	.fb_fillrect = cfb_fillrect,
	.fb_copyarea = cfb_copyarea,
	.fb_imageblit = cfb_imageblit,
59 60
	.fb_pan_display = drm_fb_helper_pan_display,
	.fb_blank = drm_fb_helper_blank,
61
	.fb_setcmap = drm_fb_helper_setcmap,
62 63 64
};


65
static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
66 67
{
	int aligned = width;
68
	int align_large = (ASIC_IS_AVIVO(rdev)) || tiled;
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
	int pitch_mask = 0;

	switch (bpp / 8) {
	case 1:
		pitch_mask = align_large ? 255 : 127;
		break;
	case 2:
		pitch_mask = align_large ? 127 : 31;
		break;
	case 3:
	case 4:
		pitch_mask = align_large ? 63 : 15;
		break;
	}

	aligned += pitch_mask;
	aligned &= ~pitch_mask;
	return aligned;
}

89
static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj)
90
{
91 92 93 94 95 96
	struct radeon_bo *rbo = gobj->driver_private;
	int ret;

	ret = radeon_bo_reserve(rbo, false);
	if (likely(ret == 0)) {
		radeon_bo_kunmap(rbo);
97
		radeon_bo_unpin(rbo);
98 99
		radeon_bo_unreserve(rbo);
	}
100
	drm_gem_object_handle_unreference(gobj);
101 102
	drm_gem_object_unreference_unlocked(gobj);
}
103

104 105 106
static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev,
					 struct drm_mode_fb_cmd *mode_cmd,
					 struct drm_gem_object **gobj_p)
107
{
108
	struct radeon_device *rdev = rfbdev->rdev;
109
	struct drm_gem_object *gobj = NULL;
110
	struct radeon_bo *rbo = NULL;
111
	bool fb_tiled = false; /* useful for testing */
112
	u32 tiling_flags = 0;
113 114
	int ret;
	int aligned_size, size;
115 116

	/* need to align pitch with crtc limits */
117
	mode_cmd->pitch = radeon_align_pitch(rdev, mode_cmd->width, mode_cmd->bpp, fb_tiled) * ((mode_cmd->bpp + 1) / 8);
118

119
	size = mode_cmd->pitch * mode_cmd->height;
120 121
	aligned_size = ALIGN(size, PAGE_SIZE);
	ret = radeon_gem_object_create(rdev, aligned_size, 0,
122
				       RADEON_GEM_DOMAIN_VRAM,
123
				       false, true,
124
				       &gobj);
125
	if (ret) {
126 127 128
		printk(KERN_ERR "failed to allocate framebuffer (%d)\n",
		       aligned_size);
		return -ENOMEM;
129
	}
130
	rbo = gobj->driver_private;
131

132
	if (fb_tiled)
133 134 135
		tiling_flags = RADEON_TILING_MACRO;

#ifdef __BIG_ENDIAN
136
	switch (mode_cmd->bpp) {
137 138 139 140 141 142 143 144 145 146
	case 32:
		tiling_flags |= RADEON_TILING_SWAP_32BIT;
		break;
	case 16:
		tiling_flags |= RADEON_TILING_SWAP_16BIT;
	default:
		break;
	}
#endif

147 148
	if (tiling_flags) {
		ret = radeon_bo_set_tiling_flags(rbo,
149 150
						 tiling_flags | RADEON_TILING_SURFACE,
						 mode_cmd->pitch);
151 152 153
		if (ret)
			dev_err(rdev->dev, "FB failed to set tiling flags\n");
	}
154

155

156 157 158
	ret = radeon_bo_reserve(rbo, false);
	if (unlikely(ret != 0))
		goto out_unref;
159
	ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, NULL);
160 161 162 163 164 165
	if (ret) {
		radeon_bo_unreserve(rbo);
		goto out_unref;
	}
	if (fb_tiled)
		radeon_bo_check_tiling(rbo, 0, 0);
166
	ret = radeon_bo_kmap(rbo, NULL);
167
	radeon_bo_unreserve(rbo);
168 169 170
	if (ret) {
		goto out_unref;
	}
171

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
	*gobj_p = gobj;
	return 0;
out_unref:
	radeonfb_destroy_pinned_object(gobj);
	*gobj_p = NULL;
	return ret;
}

static int radeonfb_create(struct radeon_fbdev *rfbdev,
			   struct drm_fb_helper_surface_size *sizes)
{
	struct radeon_device *rdev = rfbdev->rdev;
	struct fb_info *info;
	struct drm_framebuffer *fb = NULL;
	struct drm_mode_fb_cmd mode_cmd;
	struct drm_gem_object *gobj = NULL;
	struct radeon_bo *rbo = NULL;
	struct device *device = &rdev->pdev->dev;
	int ret;
	unsigned long tmp;

	mode_cmd.width = sizes->surface_width;
	mode_cmd.height = sizes->surface_height;

	/* avivo can't scanout real 24bpp */
	if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
		sizes->surface_bpp = 32;

	mode_cmd.bpp = sizes->surface_bpp;
	mode_cmd.depth = sizes->surface_depth;
202

203 204
	ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj);
	rbo = gobj->driver_private;
205

206 207
	/* okay we have an object now allocate the framebuffer */
	info = framebuffer_alloc(0, device);
208 209 210 211
	if (info == NULL) {
		ret = -ENOMEM;
		goto out_unref;
	}
212

213
	info->par = rfbdev;
214

215 216
	radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);

217 218 219 220 221 222
	fb = &rfbdev->rfb.base;

	/* setup helper */
	rfbdev->helper.fb = fb;
	rfbdev->helper.fbdev = info;

223
	memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo));
224

225
	strcpy(info->fix.id, "radeondrmfb");
226

227
	drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
228

229
	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
230
	info->fbops = &radeonfb_ops;
231

232
	tmp = radeon_bo_gpu_offset(rbo) - rdev->mc.vram_start;
233
	info->fix.smem_start = rdev->mc.aper_base + tmp;
234 235 236
	info->fix.smem_len = radeon_bo_size(rbo);
	info->screen_base = rbo->kptr;
	info->screen_size = radeon_bo_size(rbo);
237

238
	drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
239 240

	/* setup aperture base/size for vesafb takeover */
241 242 243 244 245 246 247
	info->apertures = alloc_apertures(1);
	if (!info->apertures) {
		ret = -ENOMEM;
		goto out_unref;
	}
	info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base;
	info->apertures->ranges[0].size = rdev->mc.real_vram_size;
248

249 250
	info->fix.mmio_start = 0;
	info->fix.mmio_len = 0;
251 252 253 254 255
	info->pixmap.size = 64*1024;
	info->pixmap.buf_align = 8;
	info->pixmap.access_align = 32;
	info->pixmap.flags = FB_PIXMAP_SYSTEM;
	info->pixmap.scan_align = 1;
256

257 258 259 260
	if (info->screen_base == NULL) {
		ret = -ENOSPC;
		goto out_unref;
	}
261 262 263 264 265 266 267

	ret = fb_alloc_cmap(&info->cmap, 256, 0);
	if (ret) {
		ret = -ENOMEM;
		goto out_unref;
	}

268 269
	DRM_INFO("fb mappable at 0x%lX\n",  info->fix.smem_start);
	DRM_INFO("vram apper at 0x%lX\n",  (unsigned long)rdev->mc.aper_base);
270
	DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo));
271 272 273
	DRM_INFO("fb depth is %d\n", fb->depth);
	DRM_INFO("   pitch is %d\n", fb->pitch);

274
	vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
275 276 277
	return 0;

out_unref:
278
	if (rbo) {
279

280
	}
281
	if (fb && ret) {
282 283 284 285 286 287 288
		drm_gem_object_unreference(gobj);
		drm_framebuffer_cleanup(fb);
		kfree(fb);
	}
	return ret;
}

289 290
static int radeon_fb_find_or_create_single(struct drm_fb_helper *helper,
					   struct drm_fb_helper_surface_size *sizes)
291
{
292
	struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper;
293 294 295
	int new_fb = 0;
	int ret;

296 297
	if (!helper->fb) {
		ret = radeonfb_create(rfbdev, sizes);
298 299 300 301 302 303 304
		if (ret)
			return ret;
		new_fb = 1;
	}
	return new_fb;
}

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
static char *mode_option;
int radeon_parse_options(char *options)
{
	char *this_opt;

	if (!options || !*options)
		return 0;

	while ((this_opt = strsep(&options, ",")) != NULL) {
		if (!*this_opt)
			continue;
		mode_option = this_opt;
	}
	return 0;
}

321
void radeon_fb_output_poll_changed(struct radeon_device *rdev)
322
{
323
	drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper);
324 325
}

326
static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
327 328
{
	struct fb_info *info;
329
	struct radeon_framebuffer *rfb = &rfbdev->rfb;
330

331 332
	if (rfbdev->helper.fbdev) {
		info = rfbdev->helper.fbdev;
333

334
		unregister_framebuffer(info);
335 336
		if (info->cmap.len)
			fb_dealloc_cmap(&info->cmap);
337
		framebuffer_release(info);
338 339
	}

340
	if (rfb->obj) {
341 342
		radeonfb_destroy_pinned_object(rfb->obj);
		rfb->obj = NULL;
343
	}
344
	drm_fb_helper_fini(&rfbdev->helper);
345
	drm_framebuffer_cleanup(&rfb->base);
346 347 348

	return 0;
}
349

350 351 352 353 354
static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
	.gamma_set = radeon_crtc_fb_gamma_set,
	.gamma_get = radeon_crtc_fb_gamma_get,
	.fb_probe = radeon_fb_find_or_create_single,
};
355 356 357

int radeon_fbdev_init(struct radeon_device *rdev)
{
358
	struct radeon_fbdev *rfbdev;
359
	int bpp_sel = 32;
360
	int ret;
361 362 363 364

	/* select 8 bpp console on RN50 or 16MB cards */
	if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024))
		bpp_sel = 8;
365 366 367 368 369 370 371

	rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL);
	if (!rfbdev)
		return -ENOMEM;

	rfbdev->rdev = rdev;
	rdev->mode_info.rfbdev = rfbdev;
372
	rfbdev->helper.funcs = &radeon_fb_helper_funcs;
373

374 375 376 377 378 379 380 381
	ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper,
				 rdev->num_crtc,
				 RADEONFB_CONN_LIMIT);
	if (ret) {
		kfree(rfbdev);
		return ret;
	}

382
	drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
383
	drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
384
	return 0;
385 386 387 388
}

void radeon_fbdev_fini(struct radeon_device *rdev)
{
389 390 391
	if (!rdev->mode_info.rfbdev)
		return;

392
	radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
393
	kfree(rdev->mode_info.rfbdev);
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
	rdev->mode_info.rfbdev = NULL;
}

void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state)
{
	fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state);
}

int radeon_fbdev_total_size(struct radeon_device *rdev)
{
	struct radeon_bo *robj;
	int size = 0;

	robj = rdev->mode_info.rfbdev->rfb.obj->driver_private;
	size += radeon_bo_size(robj);
	return size;
}

bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
{
	if (robj == rdev->mode_info.rfbdev->rfb.obj->driver_private)
		return true;
	return false;
417
}