summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
authorJakob Bornecrantz <jakob@tungstengraphics.com>2008-01-28 03:12:29 +0100
committerJakob Bornecrantz <jakob@tungstengraphics.com>2008-01-28 03:14:56 +0100
commita2254c5a9670a3e865f0eb5acd46e905c9b146ce (patch)
tree080e144b12585dc3dd4c7e3cae63bb3dbe004486 /linux-core
parent98361cf28c62530e34758b27aa1eea805269e0e5 (diff)
Added cursor support
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/drm_crtc.c57
-rw-r--r--linux-core/drm_crtc.h22
-rw-r--r--linux-core/drm_drv.c1
-rw-r--r--linux-core/intel_display.c108
-rw-r--r--linux-core/intel_drv.h1
-rw-r--r--linux-core/intel_fb.c26
6 files changed, 208 insertions, 7 deletions
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index 1e69eca3..18fa02ce 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -1608,6 +1608,63 @@ out:
return ret;
}
+int drm_mode_cursor_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv)
+{
+ struct drm_mode_cursor *req = data;
+ struct drm_crtc *crtc;
+ struct drm_buffer_object *bo = NULL; /* must be set */
+ int ret = 0;
+
+ DRM_DEBUG("\n");
+
+ if (!req->flags) {
+ DRM_ERROR("no operation set\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->mode_config.mutex);
+ crtc = idr_find(&dev->mode_config.crtc_idr, req->crtc);
+ if (!crtc || (crtc->id != req->crtc)) {
+ DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (req->flags & DRM_MODE_CURSOR_BO) {
+ /* Turn of the cursor if handle is 0 */
+ if (req->handle)
+ ret = drm_get_buffer_object(dev, &bo, req->handle);
+
+ if (ret) {
+ DRM_ERROR("invalid buffer id\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (crtc->funcs->cursor_set) {
+ ret = crtc->funcs->cursor_set(crtc, bo, req->width, req->height);
+ } else {
+ DRM_ERROR("crtc does not support cursor\n");
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ if (req->flags & DRM_MODE_CURSOR_MOVE) {
+ if (crtc->funcs->cursor_move) {
+ ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
+ } else {
+ DRM_ERROR("crtc does not support cursor\n");
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+out:
+ mutex_unlock(&dev->mode_config.mutex);
+ return ret;
+}
+
/**
* drm_mode_addfb - add an FB to the graphics configuration
* @inode: inode from the ioctl
diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h
index 65c3704a..8f6a8938 100644
--- a/linux-core/drm_crtc.h
+++ b/linux-core/drm_crtc.h
@@ -329,6 +329,11 @@ struct drm_crtc_funcs {
/* Move the crtc on the current fb to the given position *optional* */
void (*mode_set_base)(struct drm_crtc *crtc, int x, int y);
+ /* cursor controls */
+ int (*cursor_set)(struct drm_crtc *crtc, struct drm_buffer_object *bo,
+ uint32_t width, uint32_t height);
+ int (*cursor_move)(struct drm_crtc *crtc, int x, int y);
+
/* Set gamma on the CRTC */
void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
int regno);
@@ -483,6 +488,21 @@ struct drm_output {
};
/**
+ * struct drm_mode_set
+ *
+ * Represents a single crtc the outputs that it drives with what mode
+ * and from which framebuffer it scans out from.
+ */
+struct drm_mode_set
+{
+ struct drm_framebuffer *fb;
+ struct drm_crtc *crtc;
+
+ struct drm_output **outputs;
+ size_t num_outputs;
+};
+
+/**
* struct drm_mode_config_funcs - configure CRTCs for a given screen layout
* @resize: adjust CRTCs as necessary for the proposed layout
*
@@ -603,6 +623,8 @@ extern int drm_mode_getoutput(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern int drm_mode_setcrtc(struct drm_device *dev,
void *data, struct drm_file *file_priv);
+extern int drm_mode_cursor_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
extern int drm_mode_addfb(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern int drm_mode_rmfb(struct drm_device *dev,
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index ab047ca3..b0b44c90 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -125,6 +125,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETOUTPUT, drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c
index 1498a51c..88cf653c 100644
--- a/linux-core/intel_display.c
+++ b/linux-core/intel_display.c
@@ -402,6 +402,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
}
}
+
+
/**
* Sets the power management mode of the pipe and plane.
*
@@ -956,6 +958,108 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
}
}
+#define CURSOR_A_CONTROL 0x70080
+#define CURSOR_A_BASE 0x70084
+#define CURSOR_A_POSITION 0x70088
+
+#define CURSOR_B_CONTROL 0x700C0
+#define CURSOR_B_BASE 0x700C4
+#define CURSOR_B_POSITION 0x700C8
+
+#define CURSOR_MODE_DISABLE 0x00
+#define CURSOR_MODE_64_32B_AX 0x07
+#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX)
+#define MCURSOR_GAMMA_ENABLE (1 << 26)
+
+#define CURSOR_POS_MASK 0x007FF
+#define CURSOR_POS_SIGN 0x8000
+#define CURSOR_X_SHIFT 0
+#define CURSOR_Y_SHIFT 16
+
+static int intel_crtc_cursor_set(struct drm_crtc *crtc,
+ struct drm_buffer_object *bo,
+ uint32_t width, uint32_t height)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = crtc->driver_private;
+ int pipe = intel_crtc->pipe;
+ uint32_t control = (pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL;
+ uint32_t temp;
+ size_t adder;
+
+ DRM_DEBUG("\n");
+
+ /* if we want to turn of the cursor ignore width and height */
+ if (!bo) {
+ DRM_DEBUG("cursor off\n");
+ /* turn of the cursor */
+ temp = 0;
+ temp |= CURSOR_MODE_DISABLE;
+
+ I915_WRITE(control, temp);
+ return 0;
+ }
+
+ /* Currently we only support 64x64 cursors */
+ if (width != 64 || height != 64) {
+ DRM_ERROR("we currently only support 64x64 cursors\n");
+ return -EINVAL;
+ }
+
+ if ((bo->mem.flags & DRM_BO_MASK_MEM) != DRM_BO_FLAG_MEM_VRAM) {
+ DRM_ERROR("buffer needs to be in VRAM\n");
+ return -ENOMEM;
+ }
+
+ if (bo->mem.size < width * height * 4) {
+ DRM_ERROR("buffer is to small\n");
+ return -ENOMEM;
+ }
+
+ adder = dev_priv->stolen_base + bo->offset;
+ intel_crtc->cursor_adder = adder;
+ temp = 0;
+ /* set the pipe for the cursor */
+ temp |= (pipe << 28);
+ temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+
+ DRM_DEBUG("cusror base %x\n", adder);
+
+ I915_WRITE((pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL, temp);
+ I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder);
+
+ return 0;
+}
+
+static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = crtc->driver_private;
+ int pipe = intel_crtc->pipe;
+ uint32_t temp = 0;
+ uint32_t adder;
+
+ if (x < 0) {
+ temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
+ x = -x;
+ }
+ if (y < 0) {
+ temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
+ y = -y;
+ }
+
+ temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
+ temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
+
+ adder = intel_crtc->cursor_adder;
+ I915_WRITE((pipe == 0) ? CURSOR_A_POSITION : CURSOR_B_POSITION, temp);
+ I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder);
+
+ return 0;
+}
+
/** Sets the color ramps on behalf of RandR */
static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno)
@@ -1084,6 +1188,8 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
.mode_fixup = intel_crtc_mode_fixup,
.mode_set = intel_crtc_mode_set,
.mode_set_base = intel_pipe_set_base,
+ .cursor_set = intel_crtc_cursor_set,
+ .cursor_move = intel_crtc_cursor_move,
.gamma_set = intel_crtc_gamma_set,
.prepare = intel_crtc_prepare,
.commit = intel_crtc_commit,
@@ -1113,6 +1219,8 @@ void intel_crtc_init(struct drm_device *dev, int pipe)
intel_crtc->lut_b[i] = i;
}
+ intel_crtc->cursor_adder = 0;
+
crtc->driver_private = intel_crtc;
}
diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h
index 06335b18..25c3a978 100644
--- a/linux-core/intel_drv.h
+++ b/linux-core/intel_drv.h
@@ -55,6 +55,7 @@ struct intel_output {
struct intel_crtc {
int pipe;
+ uint32_t cursor_adder;
u8 lut_r[256], lut_g[256], lut_b[256];
};
diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c
index b67c0fcc..bb42bc69 100644
--- a/linux-core/intel_fb.c
+++ b/linux-core/intel_fb.c
@@ -49,7 +49,7 @@ struct intelfb_par {
struct drm_crtc *crtc;
struct drm_display_mode *fb_mode;
};
-
+/*
static int
var_to_refresh(const struct fb_var_screeninfo *var)
{
@@ -59,7 +59,7 @@ var_to_refresh(const struct fb_var_screeninfo *var)
var->vsync_len;
return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot;
-}
+}*/
static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
@@ -106,10 +106,10 @@ static int intelfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct intelfb_par *par = info->par;
- struct drm_device *dev = par->dev;
+ /*struct drm_device *dev = par->dev;*/
struct drm_framebuffer *fb = par->crtc->fb;
- struct drm_output *output;
- int depth, found = 0;
+ /*struct drm_output *output;*/
+ int depth/*, found = 0*/;
if (!var->pixclock)
return -EINVAL;
@@ -254,6 +254,8 @@ static int intelfb_set_par(struct fb_info *info)
struct fb_var_screeninfo *var = &info->var;
int found = 0;
+ DRM_DEBUG("\n");
+
switch (var->bits_per_pixel) {
case 16:
fb->depth = (var->green.length == 6) ? 16 : 15;
@@ -321,9 +323,19 @@ static int intelfb_set_par(struct fb_info *info)
}
if (par->crtc->enabled) {
- if (!drm_mode_equal(&par->crtc->mode, drm_mode))
- if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0))
+ if (!drm_mode_equal(&par->crtc->mode, drm_mode)) {
+ if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset))
return -EINVAL;
+ } else if (par->crtc->x != var->xoffset || par->crtc->x != var->xoffset) {
+ if (!par->crtc->funcs->mode_set_base) {
+ if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset))
+ return -EINVAL;
+ } else {
+ par->crtc->funcs->mode_set_base(par->crtc, var->xoffset, var->yoffset);
+ par->crtc->x = var->xoffset;
+ par->crtc->y = var->yoffset;
+ }
+ }
}
return 0;
}