radeon_fb.c 10.3 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
	.fb_debug_enter = drm_fb_helper_debug_enter,
	.fb_debug_leave = drm_fb_helper_debug_leave,
64 65 66
};


67
int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
68 69
{
	int aligned = width;
70
	int align_large = (ASIC_IS_AVIVO(rdev)) || tiled;
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
	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;
}

91
static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj)
92
{
93
	struct radeon_bo *rbo = gem_to_radeon_bo(gobj);
94 95 96 97 98
	int ret;

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

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

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

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

136
	if (fb_tiled)
137 138 139
		tiling_flags = RADEON_TILING_MACRO;

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

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

159

160 161 162
	ret = radeon_bo_reserve(rbo, false);
	if (unlikely(ret != 0))
		goto out_unref;
163
	ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, NULL);
164 165 166 167 168 169
	if (ret) {
		radeon_bo_unreserve(rbo);
		goto out_unref;
	}
	if (fb_tiled)
		radeon_bo_check_tiling(rbo, 0, 0);
170
	ret = radeon_bo_kmap(rbo, NULL);
171
	radeon_bo_unreserve(rbo);
172 173 174
	if (ret) {
		goto out_unref;
	}
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 202 203 204 205
	*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;
206

207
	ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj);
208
	rbo = gem_to_radeon_bo(gobj);
209

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

217
	info->par = rfbdev;
218

219 220
	radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);

221 222 223 224 225 226
	fb = &rfbdev->rfb.base;

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

227
	memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo));
228

229
	strcpy(info->fix.id, "radeondrmfb");
230

231 232
	drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);

233
	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
234
	info->fbops = &radeonfb_ops;
235

236
	tmp = radeon_bo_gpu_offset(rbo) - rdev->mc.vram_start;
237
	info->fix.smem_start = rdev->mc.aper_base + tmp;
238 239 240
	info->fix.smem_len = radeon_bo_size(rbo);
	info->screen_base = rbo->kptr;
	info->screen_size = radeon_bo_size(rbo);
241

242
	drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
243 244

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

253 254 255 256 257
	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;
258

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

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

270 271
	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);
272
	DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo));
273 274 275
	DRM_INFO("fb depth is %d\n", fb->depth);
	DRM_INFO("   pitch is %d\n", fb->pitch);

276
	vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
277 278 279
	return 0;

out_unref:
280
	if (rbo) {
281

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

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

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

307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
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;
}

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

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

333 334
	if (rfbdev->helper.fbdev) {
		info = rfbdev->helper.fbdev;
335

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

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

	return 0;
}
351

352 353 354 355 356
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,
};
357 358 359

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

	/* 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;
367 368 369 370 371 372 373

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

	rfbdev->rdev = rdev;
	rdev->mode_info.rfbdev = rfbdev;
374
	rfbdev->helper.funcs = &radeon_fb_helper_funcs;
375

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

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

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

394
	radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
395
	kfree(rdev->mode_info.rfbdev);
396 397 398 399 400 401 402 403 404 405 406 407 408
	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;

409
	robj = gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj);
410 411 412 413 414 415
	size += radeon_bo_size(robj);
	return size;
}

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