diff options
author | Kristian Høgsberg <krh@bitplanet.net> | 2009-11-18 11:25:18 -0500 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-12-01 12:10:35 -0500 |
commit | 6b95a207c1fd552e7d017837c5eaf1b0173a48c9 (patch) | |
tree | 02aed1633ab954faa3eea4b2a12775c28a1c5410 /drivers/gpu/drm/i915/intel_display.c | |
parent | f40d6817a5c2bf84f5fe7b5d1a83f1e8f8669951 (diff) |
drm/i915: Add intel implementation of the pageflip ioctl
Acked-by: Jakob Bornecrantz <jakob@vmware.com>
Acked-by: Thomas Hellström <thomas@shipmail.org>
Review-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Jesse "Orange Smoothie" Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Kristian Høgsberg <krh@bitplanet.net>
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.c | 228 |
1 files changed, 196 insertions, 32 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 002c07daf9b8..b63a25f0f86d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -1191,6 +1191,51 @@ out_disable: | |||
1191 | } | 1191 | } |
1192 | 1192 | ||
1193 | static int | 1193 | static int |
1194 | intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj) | ||
1195 | { | ||
1196 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1197 | u32 alignment; | ||
1198 | int ret; | ||
1199 | |||
1200 | switch (obj_priv->tiling_mode) { | ||
1201 | case I915_TILING_NONE: | ||
1202 | alignment = 64 * 1024; | ||
1203 | break; | ||
1204 | case I915_TILING_X: | ||
1205 | /* pin() will align the object as required by fence */ | ||
1206 | alignment = 0; | ||
1207 | break; | ||
1208 | case I915_TILING_Y: | ||
1209 | /* FIXME: Is this true? */ | ||
1210 | DRM_ERROR("Y tiled not allowed for scan out buffers\n"); | ||
1211 | return -EINVAL; | ||
1212 | default: | ||
1213 | BUG(); | ||
1214 | } | ||
1215 | |||
1216 | alignment = 256 * 1024; | ||
1217 | ret = i915_gem_object_pin(obj, alignment); | ||
1218 | if (ret != 0) | ||
1219 | return ret; | ||
1220 | |||
1221 | /* Install a fence for tiled scan-out. Pre-i965 always needs a | ||
1222 | * fence, whereas 965+ only requires a fence if using | ||
1223 | * framebuffer compression. For simplicity, we always install | ||
1224 | * a fence as the cost is not that onerous. | ||
1225 | */ | ||
1226 | if (obj_priv->fence_reg == I915_FENCE_REG_NONE && | ||
1227 | obj_priv->tiling_mode != I915_TILING_NONE) { | ||
1228 | ret = i915_gem_object_get_fence_reg(obj); | ||
1229 | if (ret != 0) { | ||
1230 | i915_gem_object_unpin(obj); | ||
1231 | return ret; | ||
1232 | } | ||
1233 | } | ||
1234 | |||
1235 | return 0; | ||
1236 | } | ||
1237 | |||
1238 | static int | ||
1194 | intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, | 1239 | intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, |
1195 | struct drm_framebuffer *old_fb) | 1240 | struct drm_framebuffer *old_fb) |
1196 | { | 1241 | { |
@@ -1209,7 +1254,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, | |||
1209 | int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE; | 1254 | int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE; |
1210 | int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF); | 1255 | int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF); |
1211 | int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; | 1256 | int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; |
1212 | u32 dspcntr, alignment; | 1257 | u32 dspcntr; |
1213 | int ret; | 1258 | int ret; |
1214 | 1259 | ||
1215 | /* no fb bound */ | 1260 | /* no fb bound */ |
@@ -1231,24 +1276,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, | |||
1231 | obj = intel_fb->obj; | 1276 | obj = intel_fb->obj; |
1232 | obj_priv = obj->driver_private; | 1277 | obj_priv = obj->driver_private; |
1233 | 1278 | ||
1234 | switch (obj_priv->tiling_mode) { | ||
1235 | case I915_TILING_NONE: | ||
1236 | alignment = 64 * 1024; | ||
1237 | break; | ||
1238 | case I915_TILING_X: | ||
1239 | /* pin() will align the object as required by fence */ | ||
1240 | alignment = 0; | ||
1241 | break; | ||
1242 | case I915_TILING_Y: | ||
1243 | /* FIXME: Is this true? */ | ||
1244 | DRM_ERROR("Y tiled not allowed for scan out buffers\n"); | ||
1245 | return -EINVAL; | ||
1246 | default: | ||
1247 | BUG(); | ||
1248 | } | ||
1249 | |||
1250 | mutex_lock(&dev->struct_mutex); | 1279 | mutex_lock(&dev->struct_mutex); |
1251 | ret = i915_gem_object_pin(obj, alignment); | 1280 | ret = intel_pin_and_fence_fb_obj(dev, obj); |
1252 | if (ret != 0) { | 1281 | if (ret != 0) { |
1253 | mutex_unlock(&dev->struct_mutex); | 1282 | mutex_unlock(&dev->struct_mutex); |
1254 | return ret; | 1283 | return ret; |
@@ -1261,20 +1290,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, | |||
1261 | return ret; | 1290 | return ret; |
1262 | } | 1291 | } |
1263 | 1292 | ||
1264 | /* Install a fence for tiled scan-out. Pre-i965 always needs a fence, | ||
1265 | * whereas 965+ only requires a fence if using framebuffer compression. | ||
1266 | * For simplicity, we always install a fence as the cost is not that onerous. | ||
1267 | */ | ||
1268 | if (obj_priv->fence_reg == I915_FENCE_REG_NONE && | ||
1269 | obj_priv->tiling_mode != I915_TILING_NONE) { | ||
1270 | ret = i915_gem_object_get_fence_reg(obj); | ||
1271 | if (ret != 0) { | ||
1272 | i915_gem_object_unpin(obj); | ||
1273 | mutex_unlock(&dev->struct_mutex); | ||
1274 | return ret; | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | dspcntr = I915_READ(dspcntr_reg); | 1293 | dspcntr = I915_READ(dspcntr_reg); |
1279 | /* Mask out pixel format bits in case we change it */ | 1294 | /* Mask out pixel format bits in case we change it */ |
1280 | dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; | 1295 | dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; |
@@ -4068,6 +4083,153 @@ static void intel_crtc_destroy(struct drm_crtc *crtc) | |||
4068 | kfree(intel_crtc); | 4083 | kfree(intel_crtc); |
4069 | } | 4084 | } |
4070 | 4085 | ||
4086 | struct intel_unpin_work { | ||
4087 | struct work_struct work; | ||
4088 | struct drm_device *dev; | ||
4089 | struct drm_gem_object *obj; | ||
4090 | struct drm_pending_vblank_event *event; | ||
4091 | int pending; | ||
4092 | }; | ||
4093 | |||
4094 | static void intel_unpin_work_fn(struct work_struct *__work) | ||
4095 | { | ||
4096 | struct intel_unpin_work *work = | ||
4097 | container_of(__work, struct intel_unpin_work, work); | ||
4098 | |||
4099 | mutex_lock(&work->dev->struct_mutex); | ||
4100 | i915_gem_object_unpin(work->obj); | ||
4101 | drm_gem_object_unreference(work->obj); | ||
4102 | mutex_unlock(&work->dev->struct_mutex); | ||
4103 | kfree(work); | ||
4104 | } | ||
4105 | |||
4106 | void intel_finish_page_flip(struct drm_device *dev, int pipe) | ||
4107 | { | ||
4108 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
4109 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; | ||
4110 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
4111 | struct intel_unpin_work *work; | ||
4112 | struct drm_i915_gem_object *obj_priv; | ||
4113 | struct drm_pending_vblank_event *e; | ||
4114 | struct timeval now; | ||
4115 | unsigned long flags; | ||
4116 | |||
4117 | /* Ignore early vblank irqs */ | ||
4118 | if (intel_crtc == NULL) | ||
4119 | return; | ||
4120 | |||
4121 | spin_lock_irqsave(&dev->event_lock, flags); | ||
4122 | work = intel_crtc->unpin_work; | ||
4123 | if (work == NULL || !work->pending) { | ||
4124 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
4125 | return; | ||
4126 | } | ||
4127 | |||
4128 | intel_crtc->unpin_work = NULL; | ||
4129 | drm_vblank_put(dev, intel_crtc->pipe); | ||
4130 | |||
4131 | if (work->event) { | ||
4132 | e = work->event; | ||
4133 | do_gettimeofday(&now); | ||
4134 | e->event.sequence = drm_vblank_count(dev, intel_crtc->pipe); | ||
4135 | e->event.tv_sec = now.tv_sec; | ||
4136 | e->event.tv_usec = now.tv_usec; | ||
4137 | list_add_tail(&e->base.link, | ||
4138 | &e->base.file_priv->event_list); | ||
4139 | wake_up_interruptible(&e->base.file_priv->event_wait); | ||
4140 | } | ||
4141 | |||
4142 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
4143 | |||
4144 | obj_priv = work->obj->driver_private; | ||
4145 | if (atomic_dec_and_test(&obj_priv->pending_flip)) | ||
4146 | DRM_WAKEUP(&dev_priv->pending_flip_queue); | ||
4147 | schedule_work(&work->work); | ||
4148 | } | ||
4149 | |||
4150 | void intel_prepare_page_flip(struct drm_device *dev, int plane) | ||
4151 | { | ||
4152 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
4153 | struct intel_crtc *intel_crtc = | ||
4154 | to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]); | ||
4155 | unsigned long flags; | ||
4156 | |||
4157 | spin_lock_irqsave(&dev->event_lock, flags); | ||
4158 | if (intel_crtc->unpin_work) | ||
4159 | intel_crtc->unpin_work->pending = 1; | ||
4160 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
4161 | } | ||
4162 | |||
4163 | static int intel_crtc_page_flip(struct drm_crtc *crtc, | ||
4164 | struct drm_framebuffer *fb, | ||
4165 | struct drm_pending_vblank_event *event) | ||
4166 | { | ||
4167 | struct drm_device *dev = crtc->dev; | ||
4168 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
4169 | struct intel_framebuffer *intel_fb; | ||
4170 | struct drm_i915_gem_object *obj_priv; | ||
4171 | struct drm_gem_object *obj; | ||
4172 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
4173 | struct intel_unpin_work *work; | ||
4174 | unsigned long flags; | ||
4175 | int ret; | ||
4176 | RING_LOCALS; | ||
4177 | |||
4178 | work = kzalloc(sizeof *work, GFP_KERNEL); | ||
4179 | if (work == NULL) | ||
4180 | return -ENOMEM; | ||
4181 | |||
4182 | mutex_lock(&dev->struct_mutex); | ||
4183 | |||
4184 | work->event = event; | ||
4185 | work->dev = crtc->dev; | ||
4186 | intel_fb = to_intel_framebuffer(crtc->fb); | ||
4187 | work->obj = intel_fb->obj; | ||
4188 | INIT_WORK(&work->work, intel_unpin_work_fn); | ||
4189 | |||
4190 | /* We borrow the event spin lock for protecting unpin_work */ | ||
4191 | spin_lock_irqsave(&dev->event_lock, flags); | ||
4192 | if (intel_crtc->unpin_work) { | ||
4193 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
4194 | kfree(work); | ||
4195 | mutex_unlock(&dev->struct_mutex); | ||
4196 | return -EBUSY; | ||
4197 | } | ||
4198 | intel_crtc->unpin_work = work; | ||
4199 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
4200 | |||
4201 | intel_fb = to_intel_framebuffer(fb); | ||
4202 | obj = intel_fb->obj; | ||
4203 | |||
4204 | ret = intel_pin_and_fence_fb_obj(dev, obj); | ||
4205 | if (ret != 0) { | ||
4206 | kfree(work); | ||
4207 | mutex_unlock(&dev->struct_mutex); | ||
4208 | return ret; | ||
4209 | } | ||
4210 | |||
4211 | /* Reference the old fb object for the scheduled work. */ | ||
4212 | drm_gem_object_reference(work->obj); | ||
4213 | |||
4214 | crtc->fb = fb; | ||
4215 | i915_gem_object_flush_write_domain(obj); | ||
4216 | drm_vblank_get(dev, intel_crtc->pipe); | ||
4217 | obj_priv = obj->driver_private; | ||
4218 | atomic_inc(&obj_priv->pending_flip); | ||
4219 | |||
4220 | BEGIN_LP_RING(4); | ||
4221 | OUT_RING(MI_DISPLAY_FLIP | | ||
4222 | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); | ||
4223 | OUT_RING(fb->pitch); | ||
4224 | OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode); | ||
4225 | OUT_RING((fb->width << 16) | fb->height); | ||
4226 | ADVANCE_LP_RING(); | ||
4227 | |||
4228 | mutex_unlock(&dev->struct_mutex); | ||
4229 | |||
4230 | return 0; | ||
4231 | } | ||
4232 | |||
4071 | static const struct drm_crtc_helper_funcs intel_helper_funcs = { | 4233 | static const struct drm_crtc_helper_funcs intel_helper_funcs = { |
4072 | .dpms = intel_crtc_dpms, | 4234 | .dpms = intel_crtc_dpms, |
4073 | .mode_fixup = intel_crtc_mode_fixup, | 4235 | .mode_fixup = intel_crtc_mode_fixup, |
@@ -4084,12 +4246,14 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { | |||
4084 | .gamma_set = intel_crtc_gamma_set, | 4246 | .gamma_set = intel_crtc_gamma_set, |
4085 | .set_config = drm_crtc_helper_set_config, | 4247 | .set_config = drm_crtc_helper_set_config, |
4086 | .destroy = intel_crtc_destroy, | 4248 | .destroy = intel_crtc_destroy, |
4249 | .page_flip = intel_crtc_page_flip, | ||
4087 | }; | 4250 | }; |
4088 | 4251 | ||
4089 | 4252 | ||
4090 | static void intel_crtc_init(struct drm_device *dev, int pipe) | 4253 | static void intel_crtc_init(struct drm_device *dev, int pipe) |
4091 | { | 4254 | { |
4092 | struct intel_crtc *intel_crtc; | 4255 | struct intel_crtc *intel_crtc; |
4256 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
4093 | int i; | 4257 | int i; |
4094 | 4258 | ||
4095 | intel_crtc = kzalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); | 4259 | intel_crtc = kzalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); |