From a2254c5a9670a3e865f0eb5acd46e905c9b146ce Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 28 Jan 2008 03:12:29 +0100 Subject: Added cursor support --- linux-core/drm_crtc.c | 57 ++++++++++++++++++++++++ linux-core/drm_crtc.h | 22 +++++++++ linux-core/drm_drv.c | 1 + linux-core/intel_display.c | 108 +++++++++++++++++++++++++++++++++++++++++++++ linux-core/intel_drv.h | 1 + linux-core/intel_fb.c | 26 ++++++++--- 6 files changed, 208 insertions(+), 7 deletions(-) (limited to 'linux-core') 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); @@ -482,6 +487,21 @@ struct drm_output { uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; }; +/** + * 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; } -- cgit v1.2.3