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 97 98 99 100
	struct radeon_bo *rbo = gobj->driver_private;
	int ret;

	ret = radeon_bo_reserve(rbo, false);
	if (likely(ret == 0)) {
		radeon_bo_kunmap(rbo);
		radeon_bo_unreserve(rbo);
	}
	drm_gem_object_unreference_unlocked(gobj);
}
101

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

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

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

130
	if (fb_tiled)
131 132 133
		tiling_flags = RADEON_TILING_MACRO;

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

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

153

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

170 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
	*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;
200

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

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

211
	info->par = rfbdev;
212

213 214
	radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);

215 216 217 218 219 220
	fb = &rfbdev->rfb.base;

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

221
	memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo));
222

223
	strcpy(info->fix.id, "radeondrmfb");
224

225
	drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
226

227 228
	info->flags = FBINFO_DEFAULT;
	info->fbops = &radeonfb_ops;
229

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

236
	drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
237 238

	/* setup aperture base/size for vesafb takeover */
239 240 241 242 243 244 245
	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;
246

247 248
	info->fix.mmio_start = 0;
	info->fix.mmio_len = 0;
249 250 251 252 253
	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;
254

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

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

266 267
	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);
268
	DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo));
269 270 271
	DRM_INFO("fb depth is %d\n", fb->depth);
	DRM_INFO("   pitch is %d\n", fb->pitch);

272
	vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
273 274 275
	return 0;

out_unref:
276
	if (rbo) {
277

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

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

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

303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
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;
}

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

324
static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
325 326
{
	struct fb_info *info;
327
	struct radeon_framebuffer *rfb = &rfbdev->rfb;
328 329
	struct radeon_bo *rbo;
	int r;
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 343 344 345 346 347
		rbo = rfb->obj->driver_private;
		r = radeon_bo_reserve(rbo, false);
		if (likely(r == 0)) {
			radeon_bo_kunmap(rbo);
			radeon_bo_unpin(rbo);
			radeon_bo_unreserve(rbo);
		}
348
		drm_gem_object_unreference_unlocked(rfb->obj);
349
	}
350
	drm_fb_helper_fini(&rfbdev->helper);
351
	drm_framebuffer_cleanup(&rfb->base);
352 353 354

	return 0;
}
355

356 357 358 359 360
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,
};
361 362 363

int radeon_fbdev_init(struct radeon_device *rdev)
{
364
	struct radeon_fbdev *rfbdev;
365 366 367 368 369
	int bpp_sel = 32;

	/* 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;
370 371 372 373 374 375 376

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

	rfbdev->rdev = rdev;
	rdev->mode_info.rfbdev = rfbdev;
377
	rfbdev->helper.funcs = &radeon_fb_helper_funcs;
378

379 380
	drm_fb_helper_init(rdev->ddev, &rfbdev->helper,
			   rdev->num_crtc,
381
			   RADEONFB_CONN_LIMIT);
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
}