aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-07-09 03:45:04 -0400
committerEric Anholt <eric@anholt.net>2010-08-01 22:58:28 -0400
commitcda4b7d3a5b1dcbc0d8e7bad52134347798e9047 (patch)
tree100b176cd81d7cdf16c546b19ece124ab6a2588e /drivers/gpu/drm/i915/intel_display.c
parent86f100b136626e91f4f66f3776303475e2e58998 (diff)
drm/i915: Unset cursor if out-of-bounds upon mode change (v4)
The docs warn that to position the cursor such that no part of it is visible on the pipe is an undefined operation. Avoid such circumstances upon changing the mode, or at any other time, by unsetting the cursor if it moves out of bounds. "For normal high resolution display modes, the cursor must have at least a single pixel positioned over the active screen.” (p143, p148 of the hardware registers docs). Fixes: Bug 24748 - [965G] Graphics crashes when resolution is changed with KMS enabled https://bugs.freedesktop.org/show_bug.cgi?id=24748 v2: Only update the cursor registers if they change. v3: Fix the unsigned comparision of x,y against width,height. v4: Always set CUR.BASE or else the cursor may become corrupt. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reported-by: Christian Eggers <ceggers@gmx.de> Cc: Christopher James Halse Rogers <chalserogers@gmail.com> Cc: stable@kernel.org Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c144
1 files changed, 93 insertions, 51 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 132314e2bf21..ca3b8a8933c6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -43,6 +43,7 @@
43bool intel_pipe_has_type (struct drm_crtc *crtc, int type); 43bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
44static void intel_update_watermarks(struct drm_device *dev); 44static void intel_update_watermarks(struct drm_device *dev);
45static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule); 45static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule);
46static void intel_crtc_update_cursor(struct drm_crtc *crtc);
46 47
47typedef struct { 48typedef struct {
48 /* given values */ 49 /* given values */
@@ -3575,6 +3576,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
3575 return -EINVAL; 3576 return -EINVAL;
3576 } 3577 }
3577 3578
3579 /* Ensure that the cursor is valid for the new mode before changing... */
3580 intel_crtc_update_cursor(crtc);
3581
3578 if (is_lvds && dev_priv->lvds_downclock_avail) { 3582 if (is_lvds && dev_priv->lvds_downclock_avail) {
3579 has_reduced_clock = limit->find_pll(limit, crtc, 3583 has_reduced_clock = limit->find_pll(limit, crtc,
3580 dev_priv->lvds_downclock, 3584 dev_priv->lvds_downclock,
@@ -4111,6 +4115,85 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
4111 } 4115 }
4112} 4116}
4113 4117
4118/* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
4119static void intel_crtc_update_cursor(struct drm_crtc *crtc)
4120{
4121 struct drm_device *dev = crtc->dev;
4122 struct drm_i915_private *dev_priv = dev->dev_private;
4123 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
4124 int pipe = intel_crtc->pipe;
4125 int x = intel_crtc->cursor_x;
4126 int y = intel_crtc->cursor_y;
4127 uint32_t base, pos;
4128 bool visible;
4129
4130 pos = 0;
4131
4132 if (crtc->fb) {
4133 base = intel_crtc->cursor_addr;
4134 if (x > (int) crtc->fb->width)
4135 base = 0;
4136
4137 if (y > (int) crtc->fb->height)
4138 base = 0;
4139 } else
4140 base = 0;
4141
4142 if (x < 0) {
4143 if (x + intel_crtc->cursor_width < 0)
4144 base = 0;
4145
4146 pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
4147 x = -x;
4148 }
4149 pos |= x << CURSOR_X_SHIFT;
4150
4151 if (y < 0) {
4152 if (y + intel_crtc->cursor_height < 0)
4153 base = 0;
4154
4155 pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
4156 y = -y;
4157 }
4158 pos |= y << CURSOR_Y_SHIFT;
4159
4160 visible = base != 0;
4161 if (!visible && !intel_crtc->cursor_visble)
4162 return;
4163
4164 I915_WRITE(pipe == 0 ? CURAPOS : CURBPOS, pos);
4165 if (intel_crtc->cursor_visble != visible) {
4166 uint32_t cntl = I915_READ(pipe == 0 ? CURACNTR : CURBCNTR);
4167 if (base) {
4168 /* Hooray for CUR*CNTR differences */
4169 if (IS_MOBILE(dev) || IS_I9XX(dev)) {
4170 cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
4171 cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
4172 cntl |= pipe << 28; /* Connect to correct pipe */
4173 } else {
4174 cntl &= ~(CURSOR_FORMAT_MASK);
4175 cntl |= CURSOR_ENABLE;
4176 cntl |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE;
4177 }
4178 } else {
4179 if (IS_MOBILE(dev) || IS_I9XX(dev)) {
4180 cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
4181 cntl |= CURSOR_MODE_DISABLE;
4182 } else {
4183 cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
4184 }
4185 }
4186 I915_WRITE(pipe == 0 ? CURACNTR : CURBCNTR, cntl);
4187
4188 intel_crtc->cursor_visble = visible;
4189 }
4190 /* and commit changes on next vblank */
4191 I915_WRITE(pipe == 0 ? CURABASE : CURBBASE, base);
4192
4193 if (visible)
4194 intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj);
4195}
4196
4114static int intel_crtc_cursor_set(struct drm_crtc *crtc, 4197static int intel_crtc_cursor_set(struct drm_crtc *crtc,
4115 struct drm_file *file_priv, 4198 struct drm_file *file_priv,
4116 uint32_t handle, 4199 uint32_t handle,
@@ -4121,11 +4204,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
4121 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 4204 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
4122 struct drm_gem_object *bo; 4205 struct drm_gem_object *bo;
4123 struct drm_i915_gem_object *obj_priv; 4206 struct drm_i915_gem_object *obj_priv;
4124 int pipe = intel_crtc->pipe; 4207 uint32_t addr;
4125 uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
4126 uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
4127 uint32_t temp = I915_READ(control);
4128 size_t addr;
4129 int ret; 4208 int ret;
4130 4209
4131 DRM_DEBUG_KMS("\n"); 4210 DRM_DEBUG_KMS("\n");
@@ -4133,12 +4212,6 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
4133 /* if we want to turn off the cursor ignore width and height */ 4212 /* if we want to turn off the cursor ignore width and height */
4134 if (!handle) { 4213 if (!handle) {
4135 DRM_DEBUG_KMS("cursor off\n"); 4214 DRM_DEBUG_KMS("cursor off\n");
4136 if (IS_MOBILE(dev) || IS_I9XX(dev)) {
4137 temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
4138 temp |= CURSOR_MODE_DISABLE;
4139 } else {
4140 temp &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
4141 }
4142 addr = 0; 4215 addr = 0;
4143 bo = NULL; 4216 bo = NULL;
4144 mutex_lock(&dev->struct_mutex); 4217 mutex_lock(&dev->struct_mutex);
@@ -4180,7 +4253,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
4180 4253
4181 addr = obj_priv->gtt_offset; 4254 addr = obj_priv->gtt_offset;
4182 } else { 4255 } else {
4183 ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1); 4256 ret = i915_gem_attach_phys_object(dev, bo,
4257 (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
4184 if (ret) { 4258 if (ret) {
4185 DRM_ERROR("failed to attach phys object\n"); 4259 DRM_ERROR("failed to attach phys object\n");
4186 goto fail_locked; 4260 goto fail_locked;
@@ -4191,21 +4265,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
4191 if (!IS_I9XX(dev)) 4265 if (!IS_I9XX(dev))
4192 I915_WRITE(CURSIZE, (height << 12) | width); 4266 I915_WRITE(CURSIZE, (height << 12) | width);
4193 4267
4194 /* Hooray for CUR*CNTR differences */
4195 if (IS_MOBILE(dev) || IS_I9XX(dev)) {
4196 temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
4197 temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
4198 temp |= (pipe << 28); /* Connect to correct pipe */
4199 } else {
4200 temp &= ~(CURSOR_FORMAT_MASK);
4201 temp |= CURSOR_ENABLE;
4202 temp |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE;
4203 }
4204
4205 finish: 4268 finish:
4206 I915_WRITE(control, temp);
4207 I915_WRITE(base, addr);
4208
4209 if (intel_crtc->cursor_bo) { 4269 if (intel_crtc->cursor_bo) {
4210 if (dev_priv->info->cursor_needs_physical) { 4270 if (dev_priv->info->cursor_needs_physical) {
4211 if (intel_crtc->cursor_bo != bo) 4271 if (intel_crtc->cursor_bo != bo)
@@ -4219,6 +4279,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
4219 4279
4220 intel_crtc->cursor_addr = addr; 4280 intel_crtc->cursor_addr = addr;
4221 intel_crtc->cursor_bo = bo; 4281 intel_crtc->cursor_bo = bo;
4282 intel_crtc->cursor_width = width;
4283 intel_crtc->cursor_height = height;
4284
4285 intel_crtc_update_cursor(crtc);
4222 4286
4223 return 0; 4287 return 0;
4224fail_unpin: 4288fail_unpin:
@@ -4232,34 +4296,12 @@ fail:
4232 4296
4233static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) 4297static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
4234{ 4298{
4235 struct drm_device *dev = crtc->dev;
4236 struct drm_i915_private *dev_priv = dev->dev_private;
4237 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 4299 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
4238 struct intel_framebuffer *intel_fb;
4239 int pipe = intel_crtc->pipe;
4240 uint32_t temp = 0;
4241 uint32_t adder;
4242
4243 if (crtc->fb) {
4244 intel_fb = to_intel_framebuffer(crtc->fb);
4245 intel_mark_busy(dev, intel_fb->obj);
4246 }
4247
4248 if (x < 0) {
4249 temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
4250 x = -x;
4251 }
4252 if (y < 0) {
4253 temp |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
4254 y = -y;
4255 }
4256 4300
4257 temp |= x << CURSOR_X_SHIFT; 4301 intel_crtc->cursor_x = x;
4258 temp |= y << CURSOR_Y_SHIFT; 4302 intel_crtc->cursor_y = y;
4259 4303
4260 adder = intel_crtc->cursor_addr; 4304 intel_crtc_update_cursor(crtc);
4261 I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp);
4262 I915_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder);
4263 4305
4264 return 0; 4306 return 0;
4265} 4307}