radeon_fb.c 9.9 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 27 28 29 30 31 32 33 34 35 36 37 38 39
/*
 * 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
 */
    /*
     *  Modularization
     */

#include <linux/module.h>
#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"

40 41
#include "drm_fb_helper.h"

42 43
#include <linux/vga_switcheroo.h>

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

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


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

93 94
static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
	.gamma_set = radeon_crtc_fb_gamma_set,
95
	.gamma_get = radeon_crtc_fb_gamma_get,
96 97
};

98 99 100
static int radeonfb_create(struct drm_device *dev,
			   struct drm_fb_helper_surface_size *sizes,
			   struct radeon_kernel_fbdev **rfbdev_p)
101
{
102
	struct radeon_device *rdev = dev->dev_private;
103
	struct fb_info *info;
104
	struct radeon_kernel_fbdev *rfbdev;
105
	struct drm_framebuffer *fb = NULL;
106 107
	struct drm_mode_fb_cmd mode_cmd;
	struct drm_gem_object *gobj = NULL;
108
	struct radeon_bo *rbo = NULL;
109 110
	struct device *device = &rdev->pdev->dev;
	int size, aligned_size, ret;
111
	u64 fb_gpuaddr;
112
	void *fbptr = NULL;
113
	unsigned long tmp;
114
	bool fb_tiled = false; /* useful for testing */
115
	u32 tiling_flags = 0;
116

117 118
	mode_cmd.width = sizes->surface_width;
	mode_cmd.height = sizes->surface_height;
119 120

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

124
	mode_cmd.bpp = sizes->surface_bpp;
125
	/* need to align pitch with crtc limits */
126
	mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8);
127
	mode_cmd.depth = sizes->surface_depth;
128 129 130 131 132

	size = mode_cmd.pitch * mode_cmd.height;
	aligned_size = ALIGN(size, PAGE_SIZE);

	ret = radeon_gem_object_create(rdev, aligned_size, 0,
133 134
			RADEON_GEM_DOMAIN_VRAM,
			false, ttm_bo_type_kernel,
135
			&gobj);
136
	if (ret) {
137
		printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n",
138
		       sizes->surface_width, sizes->surface_height);
139 140 141
		ret = -ENOMEM;
		goto out;
	}
142
	rbo = gobj->driver_private;
143

144
	if (fb_tiled)
145 146 147 148 149 150 151 152 153 154 155 156 157 158
		tiling_flags = RADEON_TILING_MACRO;

#ifdef __BIG_ENDIAN
	switch (mode_cmd.bpp) {
	case 32:
		tiling_flags |= RADEON_TILING_SWAP_32BIT;
		break;
	case 16:
		tiling_flags |= RADEON_TILING_SWAP_16BIT;
	default:
		break;
	}
#endif

159 160 161 162 163 164 165
	if (tiling_flags) {
		ret = radeon_bo_set_tiling_flags(rbo,
					tiling_flags | RADEON_TILING_SURFACE,
					mode_cmd.pitch);
		if (ret)
			dev_err(rdev->dev, "FB failed to set tiling flags\n");
	}
166
	mutex_lock(&rdev->ddev->struct_mutex);
167

168 169 170 171 172 173 174 175 176 177 178 179
	ret = radeon_bo_reserve(rbo, false);
	if (unlikely(ret != 0))
		goto out_unref;
	ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr);
	if (ret) {
		radeon_bo_unreserve(rbo);
		goto out_unref;
	}
	if (fb_tiled)
		radeon_bo_check_tiling(rbo, 0, 0);
	ret = radeon_bo_kmap(rbo, &fbptr);
	radeon_bo_unreserve(rbo);
180 181 182
	if (ret) {
		goto out_unref;
	}
183

184
	info = framebuffer_alloc(sizeof(struct radeon_kernel_fbdev), device);
185 186 187 188
	if (info == NULL) {
		ret = -ENOMEM;
		goto out_unref;
	}
189

190
	rfbdev = info->par;
191 192 193 194 195 196 197
	rfbdev->rdev = rdev;
	radeon_framebuffer_init(dev, &rfbdev->rfb, &mode_cmd, gobj);
	fb = &rfbdev->rfb.base;

	/* setup helper */
	rfbdev->helper.fb = fb;
	rfbdev->helper.fbdev = info;
198 199
	rfbdev->helper.funcs = &radeon_fb_helper_funcs;
	rfbdev->helper.dev = dev;
200 201 202

	*rfbdev_p = rfbdev;

203
	ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc,
204 205 206
					    RADEONFB_CONN_LIMIT);
	if (ret)
		goto out_unref;
207

208
	memset_io(fbptr, 0x0, aligned_size);
209

210
	strcpy(info->fix.id, "radeondrmfb");
211

212
	drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
213

214 215
	info->flags = FBINFO_DEFAULT;
	info->fbops = &radeonfb_ops;
216

217
	tmp = fb_gpuaddr - rdev->mc.vram_start;
218
	info->fix.smem_start = rdev->mc.aper_base + tmp;
219 220 221
	info->fix.smem_len = size;
	info->screen_base = fbptr;
	info->screen_size = size;
222

223
	drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
224 225 226 227 228

	/* setup aperture base/size for vesafb takeover */
	info->aperture_base = rdev->ddev->mode_config.fb_base;
	info->aperture_size = rdev->mc.real_vram_size;

229 230
	info->fix.mmio_start = 0;
	info->fix.mmio_len = 0;
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
	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;
	if (info->screen_base == NULL) {
		ret = -ENOSPC;
		goto out_unref;
	}
	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);
	DRM_INFO("size %lu\n", (unsigned long)size);
	DRM_INFO("fb depth is %d\n", fb->depth);
	DRM_INFO("   pitch is %d\n", fb->pitch);


	mutex_unlock(&rdev->ddev->struct_mutex);
248
	vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
249 250 251
	return 0;

out_unref:
252 253 254 255 256 257
	if (rbo) {
		ret = radeon_bo_reserve(rbo, false);
		if (likely(ret == 0)) {
			radeon_bo_kunmap(rbo);
			radeon_bo_unreserve(rbo);
		}
258
	}
259
	if (fb && ret) {
260 261 262 263 264 265 266 267 268 269
		drm_gem_object_unreference(gobj);
		drm_framebuffer_cleanup(fb);
		kfree(fb);
	}
	drm_gem_object_unreference(gobj);
	mutex_unlock(&rdev->ddev->struct_mutex);
out:
	return ret;
}

270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
static int radeon_fb_find_or_create_single(struct drm_device *dev,
					   struct drm_fb_helper_surface_size *sizes,
					   struct drm_fb_helper **fb_ptr)
{
	struct radeon_device *rdev = dev->dev_private;
	struct radeon_kernel_fbdev *rfbdev = NULL;
	int new_fb = 0;
	int ret;

	if (!rdev->mode_info.rfbdev) {
		ret = radeonfb_create(dev, sizes,
				      &rfbdev);
		if (ret)
			return ret;
		rdev->mode_info.rfbdev = rfbdev;
		new_fb = 1;
	} else {
		rfbdev = rdev->mode_info.rfbdev;
		if (rfbdev->rfb.base.width < sizes->surface_width ||
		    rfbdev->rfb.base.height < sizes->surface_height) {
			DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
			return -EINVAL;
		}
	}

	*fb_ptr = &rfbdev->helper;
	return new_fb;
}

299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
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;
}

315
static int radeonfb_probe(struct drm_device *dev)
316
{
317 318 319 320 321 322 323
	struct radeon_device *rdev = dev->dev_private;
	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;

324 325 326 327 328 329 330 331
	return drm_fb_helper_single_fb_probe(dev, bpp_sel, &radeon_fb_find_or_create_single);
}

void radeonfb_hotplug(struct drm_device *dev)
{
	drm_helper_fb_hotplug_event(dev);

	radeonfb_probe(dev);
332 333
}

334
static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_kernel_fbdev *rfbdev)
335 336
{
	struct fb_info *info;
337
	struct radeon_framebuffer *rfb = &rfbdev->rfb;
338 339
	struct radeon_bo *rbo;
	int r;
340

341 342 343 344 345 346 347 348
	rbo = rfb->obj->driver_private;
	info = rfbdev->helper.fbdev;
	unregister_framebuffer(info);
	r = radeon_bo_reserve(rbo, false);
	if (likely(r == 0)) {
		radeon_bo_kunmap(rbo);
		radeon_bo_unpin(rbo);
		radeon_bo_unreserve(rbo);
349 350
	}

351 352 353 354 355 356
	drm_fb_helper_free(&rfbdev->helper);
	drm_framebuffer_cleanup(&rfb->base);
	if (rfb->obj)
		drm_gem_object_unreference_unlocked(rfb->obj);

	framebuffer_release(info);
357

358 359 360
	return 0;
}
MODULE_LICENSE("GPL");
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396

int radeon_fbdev_init(struct radeon_device *rdev)
{
	drm_helper_initial_config(rdev->ddev);
	radeonfb_probe(rdev->ddev);
	return 0;
}

void radeon_fbdev_fini(struct radeon_device *rdev)
{
	radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
	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;
}