summaryrefslogtreecommitdiff
path: root/libdrm
AgeCommit message (Expand)Author
2006-10-18Merging drm-ttm-0-2-branchThomas Hellstrom
2006-10-17Remove some debugging messages.Thomas Hellstrom
2006-10-17Remove max number of locked pages check and call, sinceThomas Hellstrom
2006-10-17Implement mm_lock and mm_unlock functions.Thomas Hellstrom
2006-10-17Extend generality for more memory types.Thomas Hellstrom
2006-10-11Compatibility code for 2.6.15-2.6.18. It is ugly but a little comfort is thatThomas Hellstrom
2006-10-11Big update:Thomas Hellstrom
2006-10-02Bug 6242: [mach64] Use private DMA buffers, part #3.George Sapountzis
2006-10-02Make the user_token 44-bit for TTMs, and have them occupy a unique file spaceThomas Hellstrom
2006-09-29Core vsync: Add flag DRM_VBLANK_NEXTONMISS.Michel Dänzer
2006-09-29Add definition of DRM_VBLANK_SECONDARY.Michel Dänzer
2006-09-29Add support for tracking drawable information to coreMichel Dänzer
2006-09-28Core vsync: Add flag DRM_VBLANK_NEXTONMISS.Michel Dänzer
2006-09-28Add definition of DRM_VBLANK_SECONDARY.Michel Dänzer
2006-09-28Add support for tracking drawable information to coreMichel Dänzer
2006-09-26Silence valgrind.Thomas Hellstrom
2006-09-20Allow for 64-bit map handles of ttms and buffer objects.Thomas Hellstrom
2006-09-18Alternative implementation of page table zeroing using zap page_range.Thomas Hellstrom
2006-09-18More verbose error reporting in some cases.Thomas Hellstrom
2006-09-15Some bugfixes.Thomas Hellstrom
2006-09-12Use lazy fence wait when possible even for RW fences. Saves some CPU.Thomas Hellstrom
2006-09-12More bugfixes.Thomas Hellstrom
2006-09-08Various bugfixes.Thomas Hellstrom
2006-09-05Multithreaded application note.Thomas Hellstrom
2006-09-05Fence all unfenced buffers function.Thomas Hellstrom
2006-09-04Libdrm function headers. Some renaming.Thomas Hellstrom
2006-09-01Flag bit pattern bugfixes. Remove some error messages.Thomas Hellstrom
2006-09-01Export buffer info on map and validate ioctls.Thomas Hellstrom
2006-09-01Various bugfixes.Thomas Hellstrom
2006-08-31More mapping synchronization.Thomas Hellstrom
2006-08-30Remove the buffer object hint field and use it onlyThomas Hellstrom
2006-08-30Add missing map flags.Thomas Hellstrom
2006-08-30Buffer object mapping and mapping synchronization for multiple clients.Thomas Hellstrom
2006-08-30Memory manager init and takedown.Thomas Hellstrom
2006-08-29Part of buffer object libdrm interface.Thomas Hellstrom
2006-08-29Checkpoint commit. Buffer object flags and IOCTL argument list.Thomas Hellstrom
2006-08-2964-bit IOCTL integer (Michel Dänzer & Brian Paul)Thomas Hellstrom
2006-08-28Add a 64-bit drm unsigned type for 64-bit clean IOCTLS.Thomas Hellstrom
2006-08-27Bugfixes.Thomas Hellstrom
2006-08-27Remove the ioctl multiplexing, and instead allow for genericThomas Hellstrom
2006-08-22Add a fence object class field for future use (For example VSYNC fence objects)Thomas Hellstrom
2006-08-21User / Kernel space fence objects (device-independent part).Thomas Hellstrom
2006-07-19.cvsignore -> .gitignoreMichel Dänzer
2006-03-15Avoid walking off the end of the hash table. (Coverity report #465)Adam Jackson
2006-02-20Formatting cleanup, dead code removal. Remove N() namespacing macro,Adam Jackson
2005-12-31Initialize sv.drm_dd_minor to "don't care" along with dd_major, to appeaseEric Anholt
2005-11-30Bump package and DSO numbers to 2.0 to reflect 32/64 ABI changeAdam Jackson
2005-11-30Resync from Xorg head: conditional include of xorg-config.hAdam Jackson
2005-11-30Resync from Xorg head (Bug #3815, GNU/kFreeBSD hack)Adam Jackson
2005-11-29Add TODO based on my email from a while agoAdam Jackson
' href='#n372'>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 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
/*
 * Copyright © 2007 David Airlie
 * Copyright © 2007 Jerome Glisse
 *
 * All Rights Reserved.
 *
 * 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 on 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
 * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
 * THEIR SUPPLIERS 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.
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>

#include "drmP.h"
#include "drm.h"
#include "drm_crtc.h"
#include "radeon_ms.h"
#include "amd.h"


static int radeonfb_setcolreg(unsigned regno, unsigned red,
			       unsigned green, unsigned blue,
			       unsigned transp, struct fb_info *info)
{
	struct amd_fb *par = info->par;
	struct drm_framebuffer *fb = par->fb;
	struct drm_crtc *crtc = par->crtc;

	if (regno > 255) {
		return 1;
	}
	//	if (crtc->funcs->gamma_set) {
	//		crtc->funcs->gamma_set(crtc, red, green, blue, regno);
	//	}
	if (regno < 16) {
		switch (fb->depth) {
		case 15:
			fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) |
				((green & 0xf800) >>  6) |
				((blue & 0xf800) >> 11);
			break;
		case 16:
			fb->pseudo_palette[regno] = (red & 0xf800) |
				((green & 0xfc00) >>  5) |
				((blue  & 0xf800) >> 11);
			break;
		case 24:
		case 32:
			fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
				(green & 0xff00) |
				((blue  & 0xff00) >> 8);
			break;
		}
	}
	return 0;
}

static int radeonfb_check_var(struct fb_var_screeninfo *var,
			       struct fb_info *info)
{
        struct amd_fb *par = info->par;
	struct drm_framebuffer *fb = par->fb;

        if (!var->pixclock)
                return -EINVAL;

        /* Need to resize the fb object !!! */
        if (var->xres > fb->width || var->yres > fb->height) {
                DRM_ERROR("Requested width/height is greater than "
			  "current fb object %dx%d > %dx%d\n",
			  var->xres, var->yres, fb->width, fb->height);
                DRM_ERROR("Need resizing code.\n");
                return -EINVAL;
        }

        switch (var->bits_per_pixel) {
        case 16:
		if (var->green.length == 5) {
			var->red.offset = 10;
			var->green.offset = 5;
			var->blue.offset = 0;
			var->red.length = 5;
			var->green.length = 5;
			var->blue.length = 5;
			var->transp.length = 0;
			var->transp.offset = 0;
		} else {
	                var->red.offset = 11;
			var->green.offset = 6;
			var->blue.offset = 0;
			var->red.length = 5;
			var->green.length = 6;
			var->blue.length = 5;
			var->transp.length = 0;
			var->transp.offset = 0;
		}
                break;
	case 32:
                if (var->transp.length) {
			var->red.offset = 16;
			var->green.offset = 8;
			var->blue.offset = 0;
			var->red.length = 8;
			var->green.length = 8;
			var->blue.length = 8;
			var->transp.length = 8;
			var->transp.offset = 24;
		} else {
			var->red.offset = 16;
			var->green.offset = 8;
			var->blue.offset = 0;
			var->red.length = 8;
			var->green.length = 8;
			var->blue.length = 8;
			var->transp.length = 0;
			var->transp.offset = 0;
		}
		break;
        default:
		return -EINVAL; 
        }
	return 0;
}

static bool radeonfb_mode_equal(struct drm_display_mode *mode1,
			        struct drm_display_mode *mode2)
{
	if (mode1->hdisplay == mode2->hdisplay &&
	    mode1->hsync_start == mode2->hsync_start &&
	    mode1->hsync_end == mode2->hsync_end &&
	    mode1->htotal == mode2->htotal &&
	    mode1->hskew == mode2->hskew &&
	    mode1->vdisplay == mode2->vdisplay &&
	    mode1->vsync_start == mode2->vsync_start &&
	    mode1->vsync_end == mode2->vsync_end &&
	    mode1->vtotal == mode2->vtotal &&
	    mode1->vscan == mode2->vscan &&
	    mode1->flags == mode2->flags) {
	    	/* FIXME: what about adding a margin for clock ? */
		if (mode1->clock == mode2->clock)
			return true;
		return false;
	}
	
	return false;
}

static int radeonfb_set_par(struct fb_info *info)
{
	struct amd_fb *par = info->par;
	struct drm_framebuffer *fb = par->fb;
	struct drm_device *dev = par->dev;
        struct drm_display_mode *drm_mode, *search_mode;
        struct drm_output *output;
        struct fb_var_screeninfo *var = &info->var;
	int found = 0;

        switch (var->bits_per_pixel) {
        case 16:
		fb->depth = (var->green.length == 6) ? 16 : 15;
		break;
        case 32:
		fb->depth = (var->transp.length > 0) ? 32 : 24;
		break;
	default:
		return -EINVAL; 
	}
	fb->bits_per_pixel = var->bits_per_pixel;

	info->fix.line_length = fb->pitch;
	info->fix.smem_len = info->fix.line_length * fb->height;
	info->fix.visual = FB_VISUAL_TRUECOLOR;
	info->screen_size = info->fix.smem_len; /* ??? */

        /* Should we walk the output's modelist or just create our own ???
         * For now, we create and destroy a mode based on the incoming 
         * parameters. But there's commented out code below which scans 
         * the output list too.
         */
	drm_mode = drm_mode_create(dev);
	drm_mode->hdisplay = var->xres;
	drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
	drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
	drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
	drm_mode->vdisplay = var->yres;
	drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
	drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
	drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
	drm_mode->clock = PICOS2KHZ(var->pixclock);
	drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
	drm_mode_set_name(drm_mode);
	drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);

        list_for_each_entry(output, &dev->mode_config.output_list, head) {
                if (output->crtc == par->crtc)
                        break;
        }

	drm_mode_debug_printmodeline(drm_mode);    
        list_for_each_entry(search_mode, &output->modes, head) {
		drm_mode_debug_printmodeline(search_mode);
		if (radeonfb_mode_equal(drm_mode, search_mode)) {
			drm_mode_destroy(dev, drm_mode);
			drm_mode = search_mode;
			found = 1;
			break;
		}
	}

	if (!found) {
		if (par->fb_mode) {
			drm_mode_detachmode_crtc(dev, par->fb_mode);
		}
		par->fb_mode = drm_mode;
		drm_mode_debug_printmodeline(drm_mode);
		/* attach mode */
		drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode);
	}

	if (par->crtc->enabled) {
		if (!drm_mode_equal(&par->crtc->mode, drm_mode) ||
		    par->crtc->fb != par->fb) {
			par->crtc->fb = par->fb;
			if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) {
				return -EINVAL;
			}
		}
	}

	return 0;
}

static struct fb_ops radeonfb_ops = {
	.owner = THIS_MODULE,
	//	.fb_open = radeonfb_open,
	//	.fb_read = radeonfb_read,
	//	.fb_write = radeonfb_write,
	//	.fb_release = radeonfb_release,
	//	.fb_ioctl = radeonfb_ioctl,
	.fb_check_var = radeonfb_check_var,
	.fb_set_par = radeonfb_set_par,
	.fb_setcolreg = radeonfb_setcolreg,
	.fb_fillrect = cfb_fillrect,
	.fb_copyarea = cfb_copyarea,
	.fb_imageblit = cfb_imageblit,
};

int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output)
{
	struct drm_radeon_private *dev_priv = dev->dev_private;
	struct fb_info *info;
	struct amd_fb *par;
	struct device *device = &dev->pdev->dev; 
	struct drm_framebuffer *fb;
	struct drm_display_mode *mode = crtc->desired_mode;
	int ret;

	info = framebuffer_alloc(sizeof(struct amd_fb), device);
	if (!info){
		DRM_INFO("[radeon_ms] framebuffer_alloc failed\n");
		return -EINVAL;
	}

	fb = drm_framebuffer_create(dev);
	if (!fb) {
		framebuffer_release(info);
		DRM_ERROR("[radeon_ms] failed to allocate fb.\n");
		return -EINVAL;
	}
	crtc->fb = fb;

	fb->width = crtc->desired_mode->hdisplay;
	fb->height = crtc->desired_mode->vdisplay;
	fb->bits_per_pixel = 32;
	fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8);
	fb->depth = 24;
	/* one page alignment should be fine for constraint (micro|macro tiling,
	 * bit depth, color buffer offset, ...) */
	ret = drm_buffer_object_create(dev, fb->width * fb->height * 4, 
				       drm_bo_type_kernel,
				       DRM_BO_FLAG_READ |
				       DRM_BO_FLAG_WRITE |
				       DRM_BO_FLAG_NO_EVICT |
				       DRM_BO_FLAG_MEM_VRAM,
				       DRM_BO_HINT_DONT_FENCE,
				       1,
				       0,
				       &fb->bo);
	if (ret || fb->bo == NULL) {
		DRM_ERROR("[radeon_ms] failed to allocate framebuffer\n");
		drm_framebuffer_destroy(fb);
		framebuffer_release(info);
		return -EINVAL;
	}

	DRM_INFO("[radeon_ms] framebuffer %dx%d at 0x%08lX\n",
		 fb->width, fb->height, fb->bo->offset);

	fb->fbdev = info;
	par = info->par;
	dev_priv->fb = par;
	par->dev = dev;
	par->crtc = crtc;
	par->fb = fb;
	info->fbops = &radeonfb_ops;
	strcpy(info->fix.id, "radeonfb");
	info->fix.type = FB_TYPE_PACKED_PIXELS;
	info->fix.visual = FB_VISUAL_TRUECOLOR;
	info->fix.type_aux = 0;
	info->fix.xpanstep = 8;
	info->fix.ypanstep = 1;
	info->fix.ywrapstep = 0;
	info->fix.accel = FB_ACCEL_ATI_RADEON;
	info->fix.type_aux = 0;
	info->fix.mmio_start = 0;
	info->fix.mmio_len = 0;
	info->fix.line_length = fb->pitch;
	info->fix.smem_start = fb->bo->offset + dev->mode_config.fb_base;
	info->fix.smem_len = info->fix.line_length * fb->height;
	info->flags = FBINFO_DEFAULT;
	DRM_INFO("[radeon_ms] fb physical start : 0x%lX\n", info->fix.smem_start);
	DRM_INFO("[radeon_ms] fb physical size  : %d\n", info->fix.smem_len);

 	ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap);
  	if (ret) {
  		DRM_ERROR("error mapping fb: %d\n", ret);
	}
	info->screen_base = fb->kmap.virtual;
	info->screen_size = info->fix.smem_len; /* FIXME */
	info->pseudo_palette = fb->pseudo_palette;
	info->var.xres_virtual = fb->width;
	info->var.yres_virtual = fb->height;
	info->var.bits_per_pixel = fb->bits_per_pixel;
	info->var.xoffset = 0;
	info->var.yoffset = 0;
	info->var.activate = FB_ACTIVATE_NOW;
	info->var.height = -1;
	info->var.width = -1;
	info->var.vmode = FB_VMODE_NONINTERLACED;

	info->var.xres = mode->hdisplay;
	info->var.right_margin = mode->hsync_start - mode->hdisplay;
	info->var.hsync_len = mode->hsync_end - mode->hsync_start;
	info->var.left_margin = mode->htotal - mode->hsync_end;
	info->var.yres = mode->vdisplay;
	info->var.lower_margin = mode->vsync_start - mode->vdisplay;
	info->var.vsync_len = mode->vsync_end - mode->vsync_start;
	info->var.upper_margin = mode->vtotal - mode->vsync_end;
	info->var.pixclock = 10000000 / mode->htotal * 1000 /
		mode->vtotal * 100;
	/* avoid overflow */
	info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;

	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;

	DRM_DEBUG("fb depth is %d\n", fb->depth);
	DRM_DEBUG("   pitch is %d\n", fb->pitch);
	switch(fb->depth) {
 	case 15:
                info->var.red.offset = 10;
		info->var.green.offset = 5;
		info->var.blue.offset = 0;
		info->var.red.length = info->var.green.length =
			info->var.blue.length = 5;
		info->var.transp.offset = 15;
                info->var.transp.length = 1;
                break;
	case 16:
                info->var.red.offset = 11;
                info->var.green.offset = 5;
                info->var.blue.offset = 0;
                info->var.red.length = 5;
                info->var.green.length = 6;
                info->var.blue.length = 5;
                info->var.transp.offset = 0;
 		break;
	case 24:
                info->var.red.offset = 16;
                info->var.green.offset = 8;
                info->var.blue.offset = 0;
                info->var.red.length = info->var.green.length =
                        info->var.blue.length = 8;
                info->var.transp.offset = 0;
                info->var.transp.length = 0;
                break;
	case 32:
		info->var.red.offset = 16;
		info->var.green.offset = 8;
		info->var.blue.offset = 0;
		info->var.red.length = info->var.green.length =
			info->var.blue.length = 8;
		info->var.transp.offset = 24;
		info->var.transp.length = 8;
		break;
	default:
		DRM_ERROR("only support 15, 16, 24 or 32bits per pixel "
			  "got %d\n", fb->depth);
		return -EINVAL;
		break;
	}

	if (register_framebuffer(info) < 0) {
		return -EINVAL;
	}

	DRM_INFO("[radeon_ms] fb%d: %s frame buffer device\n", info->node,
		 info->fix.id);
	return 0;
}
EXPORT_SYMBOL(radeonfb_probe);

int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *kern_fb)
{
	struct drm_radeon_private *dev_priv = dev->dev_private;
	struct amd_fb *fb = dev_priv->fb;
	struct fb_info *info;

	if (fb == NULL || fb->fb == NULL || fb->fb->fbdev == NULL) {
		DRM_INFO("[radeon_ms] %s: no crtc, or fb or fbdev\n",
			 __func__);
		return 0;
	}
	info = fb->fb->fbdev;
	unregister_framebuffer(info);
	drm_bo_kunmap(&fb->fb->kmap);
	drm_bo_usage_deref_unlocked(&fb->fb->bo);
	drm_framebuffer_destroy(fb->fb);
	framebuffer_release(info);
	dev_priv->fb = NULL;
	return 0;
}
EXPORT_SYMBOL(radeonfb_remove);
MODULE_LICENSE("GPL");