diff options
| author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
|---|---|---|
| committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
| commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
| tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/gpu/drm/i915/intel_overlay.c | |
| parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
| parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) | |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/gpu/drm/i915/intel_overlay.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_overlay.c | 1066 |
1 files changed, 583 insertions, 483 deletions
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 1d306a458be6..9e2959bc91cd 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c | |||
| @@ -170,91 +170,180 @@ struct overlay_registers { | |||
| 170 | u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; | 170 | u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; |
| 171 | }; | 171 | }; |
| 172 | 172 | ||
| 173 | /* overlay flip addr flag */ | 173 | struct intel_overlay { |
| 174 | #define OFC_UPDATE 0x1 | 174 | struct drm_device *dev; |
| 175 | 175 | struct intel_crtc *crtc; | |
| 176 | #define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev)) | 176 | struct drm_i915_gem_object *vid_bo; |
| 177 | #define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev)) | 177 | struct drm_i915_gem_object *old_vid_bo; |
| 178 | 178 | int active; | |
| 179 | int pfit_active; | ||
| 180 | u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */ | ||
| 181 | u32 color_key; | ||
| 182 | u32 brightness, contrast, saturation; | ||
| 183 | u32 old_xscale, old_yscale; | ||
| 184 | /* register access */ | ||
| 185 | u32 flip_addr; | ||
| 186 | struct drm_i915_gem_object *reg_bo; | ||
| 187 | /* flip handling */ | ||
| 188 | uint32_t last_flip_req; | ||
| 189 | void (*flip_tail)(struct intel_overlay *); | ||
| 190 | }; | ||
| 179 | 191 | ||
| 180 | static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay) | 192 | static struct overlay_registers * |
| 193 | intel_overlay_map_regs(struct intel_overlay *overlay) | ||
| 181 | { | 194 | { |
| 182 | drm_i915_private_t *dev_priv = overlay->dev->dev_private; | 195 | drm_i915_private_t *dev_priv = overlay->dev->dev_private; |
| 183 | struct overlay_registers *regs; | 196 | struct overlay_registers *regs; |
| 184 | 197 | ||
| 185 | /* no recursive mappings */ | 198 | if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) |
| 186 | BUG_ON(overlay->virt_addr); | 199 | regs = overlay->reg_bo->phys_obj->handle->vaddr; |
| 200 | else | ||
| 201 | regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping, | ||
| 202 | overlay->reg_bo->gtt_offset); | ||
| 187 | 203 | ||
| 188 | if (OVERLAY_NONPHYSICAL(overlay->dev)) { | 204 | return regs; |
| 189 | regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, | 205 | } |
| 190 | overlay->reg_bo->gtt_offset, | ||
| 191 | KM_USER0); | ||
| 192 | 206 | ||
| 193 | if (!regs) { | 207 | static void intel_overlay_unmap_regs(struct intel_overlay *overlay, |
| 194 | DRM_ERROR("failed to map overlay regs in GTT\n"); | 208 | struct overlay_registers *regs) |
| 195 | return NULL; | 209 | { |
| 196 | } | 210 | if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) |
| 197 | } else | 211 | io_mapping_unmap(regs); |
| 198 | regs = overlay->reg_bo->phys_obj->handle->vaddr; | 212 | } |
| 213 | |||
| 214 | static int intel_overlay_do_wait_request(struct intel_overlay *overlay, | ||
| 215 | struct drm_i915_gem_request *request, | ||
| 216 | void (*tail)(struct intel_overlay *)) | ||
| 217 | { | ||
| 218 | struct drm_device *dev = overlay->dev; | ||
| 219 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 220 | int ret; | ||
| 199 | 221 | ||
| 200 | return overlay->virt_addr = regs; | 222 | BUG_ON(overlay->last_flip_req); |
| 223 | ret = i915_add_request(LP_RING(dev_priv), NULL, request); | ||
| 224 | if (ret) { | ||
| 225 | kfree(request); | ||
| 226 | return ret; | ||
| 227 | } | ||
| 228 | overlay->last_flip_req = request->seqno; | ||
| 229 | overlay->flip_tail = tail; | ||
| 230 | ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req); | ||
| 231 | if (ret) | ||
| 232 | return ret; | ||
| 233 | |||
| 234 | overlay->last_flip_req = 0; | ||
| 235 | return 0; | ||
| 201 | } | 236 | } |
| 202 | 237 | ||
| 203 | static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay) | 238 | /* Workaround for i830 bug where pipe a must be enable to change control regs */ |
| 239 | static int | ||
| 240 | i830_activate_pipe_a(struct drm_device *dev) | ||
| 204 | { | 241 | { |
| 205 | if (OVERLAY_NONPHYSICAL(overlay->dev)) | 242 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 206 | io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0); | 243 | struct intel_crtc *crtc; |
| 244 | struct drm_crtc_helper_funcs *crtc_funcs; | ||
| 245 | struct drm_display_mode vesa_640x480 = { | ||
| 246 | DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, | ||
| 247 | 752, 800, 0, 480, 489, 492, 525, 0, | ||
| 248 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) | ||
| 249 | }, *mode; | ||
| 250 | |||
| 251 | crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]); | ||
| 252 | if (crtc->dpms_mode == DRM_MODE_DPMS_ON) | ||
| 253 | return 0; | ||
| 207 | 254 | ||
| 208 | overlay->virt_addr = NULL; | 255 | /* most i8xx have pipe a forced on, so don't trust dpms mode */ |
| 256 | if (I915_READ(_PIPEACONF) & PIPECONF_ENABLE) | ||
| 257 | return 0; | ||
| 209 | 258 | ||
| 210 | return; | 259 | crtc_funcs = crtc->base.helper_private; |
| 260 | if (crtc_funcs->dpms == NULL) | ||
| 261 | return 0; | ||
| 262 | |||
| 263 | DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n"); | ||
| 264 | |||
| 265 | mode = drm_mode_duplicate(dev, &vesa_640x480); | ||
| 266 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | ||
| 267 | if(!drm_crtc_helper_set_mode(&crtc->base, mode, | ||
| 268 | crtc->base.x, crtc->base.y, | ||
| 269 | crtc->base.fb)) | ||
| 270 | return 0; | ||
| 271 | |||
| 272 | crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON); | ||
| 273 | return 1; | ||
| 274 | } | ||
| 275 | |||
| 276 | static void | ||
| 277 | i830_deactivate_pipe_a(struct drm_device *dev) | ||
| 278 | { | ||
| 279 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 280 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0]; | ||
| 281 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
| 282 | |||
| 283 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
| 211 | } | 284 | } |
| 212 | 285 | ||
| 213 | /* overlay needs to be disable in OCMD reg */ | 286 | /* overlay needs to be disable in OCMD reg */ |
| 214 | static int intel_overlay_on(struct intel_overlay *overlay) | 287 | static int intel_overlay_on(struct intel_overlay *overlay) |
| 215 | { | 288 | { |
| 216 | struct drm_device *dev = overlay->dev; | 289 | struct drm_device *dev = overlay->dev; |
| 290 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 291 | struct drm_i915_gem_request *request; | ||
| 292 | int pipe_a_quirk = 0; | ||
| 217 | int ret; | 293 | int ret; |
| 218 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 219 | 294 | ||
| 220 | BUG_ON(overlay->active); | 295 | BUG_ON(overlay->active); |
| 221 | |||
| 222 | overlay->active = 1; | 296 | overlay->active = 1; |
| 223 | overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP; | ||
| 224 | 297 | ||
| 225 | BEGIN_LP_RING(4); | 298 | if (IS_I830(dev)) { |
| 299 | pipe_a_quirk = i830_activate_pipe_a(dev); | ||
| 300 | if (pipe_a_quirk < 0) | ||
| 301 | return pipe_a_quirk; | ||
| 302 | } | ||
| 303 | |||
| 304 | request = kzalloc(sizeof(*request), GFP_KERNEL); | ||
| 305 | if (request == NULL) { | ||
| 306 | ret = -ENOMEM; | ||
| 307 | goto out; | ||
| 308 | } | ||
| 309 | |||
| 310 | ret = BEGIN_LP_RING(4); | ||
| 311 | if (ret) { | ||
| 312 | kfree(request); | ||
| 313 | goto out; | ||
| 314 | } | ||
| 315 | |||
| 226 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); | 316 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); |
| 227 | OUT_RING(overlay->flip_addr | OFC_UPDATE); | 317 | OUT_RING(overlay->flip_addr | OFC_UPDATE); |
| 228 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); | 318 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); |
| 229 | OUT_RING(MI_NOOP); | 319 | OUT_RING(MI_NOOP); |
| 230 | ADVANCE_LP_RING(); | 320 | ADVANCE_LP_RING(); |
| 231 | 321 | ||
| 232 | overlay->last_flip_req = | 322 | ret = intel_overlay_do_wait_request(overlay, request, NULL); |
| 233 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | 323 | out: |
| 234 | if (overlay->last_flip_req == 0) | 324 | if (pipe_a_quirk) |
| 235 | return -ENOMEM; | 325 | i830_deactivate_pipe_a(dev); |
| 236 | 326 | ||
| 237 | ret = i915_do_wait_request(dev, | 327 | return ret; |
| 238 | overlay->last_flip_req, 1, &dev_priv->render_ring); | ||
| 239 | if (ret != 0) | ||
| 240 | return ret; | ||
| 241 | |||
| 242 | overlay->hw_wedged = 0; | ||
| 243 | overlay->last_flip_req = 0; | ||
| 244 | return 0; | ||
| 245 | } | 328 | } |
| 246 | 329 | ||
| 247 | /* overlay needs to be enabled in OCMD reg */ | 330 | /* overlay needs to be enabled in OCMD reg */ |
| 248 | static void intel_overlay_continue(struct intel_overlay *overlay, | 331 | static int intel_overlay_continue(struct intel_overlay *overlay, |
| 249 | bool load_polyphase_filter) | 332 | bool load_polyphase_filter) |
| 250 | { | 333 | { |
| 251 | struct drm_device *dev = overlay->dev; | 334 | struct drm_device *dev = overlay->dev; |
| 252 | drm_i915_private_t *dev_priv = dev->dev_private; | 335 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 336 | struct drm_i915_gem_request *request; | ||
| 253 | u32 flip_addr = overlay->flip_addr; | 337 | u32 flip_addr = overlay->flip_addr; |
| 254 | u32 tmp; | 338 | u32 tmp; |
| 339 | int ret; | ||
| 255 | 340 | ||
| 256 | BUG_ON(!overlay->active); | 341 | BUG_ON(!overlay->active); |
| 257 | 342 | ||
| 343 | request = kzalloc(sizeof(*request), GFP_KERNEL); | ||
| 344 | if (request == NULL) | ||
| 345 | return -ENOMEM; | ||
| 346 | |||
| 258 | if (load_polyphase_filter) | 347 | if (load_polyphase_filter) |
| 259 | flip_addr |= OFC_UPDATE; | 348 | flip_addr |= OFC_UPDATE; |
| 260 | 349 | ||
| @@ -263,226 +352,154 @@ static void intel_overlay_continue(struct intel_overlay *overlay, | |||
| 263 | if (tmp & (1 << 17)) | 352 | if (tmp & (1 << 17)) |
| 264 | DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp); | 353 | DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp); |
| 265 | 354 | ||
| 266 | BEGIN_LP_RING(2); | 355 | ret = BEGIN_LP_RING(2); |
| 356 | if (ret) { | ||
| 357 | kfree(request); | ||
| 358 | return ret; | ||
| 359 | } | ||
| 267 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); | 360 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); |
| 268 | OUT_RING(flip_addr); | 361 | OUT_RING(flip_addr); |
| 269 | ADVANCE_LP_RING(); | 362 | ADVANCE_LP_RING(); |
| 270 | 363 | ||
| 271 | overlay->last_flip_req = | 364 | ret = i915_add_request(LP_RING(dev_priv), NULL, request); |
| 272 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | 365 | if (ret) { |
| 366 | kfree(request); | ||
| 367 | return ret; | ||
| 368 | } | ||
| 369 | |||
| 370 | overlay->last_flip_req = request->seqno; | ||
| 371 | return 0; | ||
| 273 | } | 372 | } |
| 274 | 373 | ||
| 275 | static int intel_overlay_wait_flip(struct intel_overlay *overlay) | 374 | static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) |
| 276 | { | 375 | { |
| 277 | struct drm_device *dev = overlay->dev; | 376 | struct drm_i915_gem_object *obj = overlay->old_vid_bo; |
| 278 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 279 | int ret; | ||
| 280 | u32 tmp; | ||
| 281 | |||
| 282 | if (overlay->last_flip_req != 0) { | ||
| 283 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | ||
| 284 | 1, &dev_priv->render_ring); | ||
| 285 | if (ret == 0) { | ||
| 286 | overlay->last_flip_req = 0; | ||
| 287 | |||
| 288 | tmp = I915_READ(ISR); | ||
| 289 | 377 | ||
| 290 | if (!(tmp & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT)) | 378 | i915_gem_object_unpin(obj); |
| 291 | return 0; | 379 | drm_gem_object_unreference(&obj->base); |
| 292 | } | ||
| 293 | } | ||
| 294 | 380 | ||
| 295 | /* synchronous slowpath */ | 381 | overlay->old_vid_bo = NULL; |
| 296 | overlay->hw_wedged = RELEASE_OLD_VID; | 382 | } |
| 297 | 383 | ||
| 298 | BEGIN_LP_RING(2); | 384 | static void intel_overlay_off_tail(struct intel_overlay *overlay) |
| 299 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); | 385 | { |
| 300 | OUT_RING(MI_NOOP); | 386 | struct drm_i915_gem_object *obj = overlay->vid_bo; |
| 301 | ADVANCE_LP_RING(); | ||
| 302 | 387 | ||
| 303 | overlay->last_flip_req = | 388 | /* never have the overlay hw on without showing a frame */ |
| 304 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | 389 | BUG_ON(!overlay->vid_bo); |
| 305 | if (overlay->last_flip_req == 0) | ||
| 306 | return -ENOMEM; | ||
| 307 | 390 | ||
| 308 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | 391 | i915_gem_object_unpin(obj); |
| 309 | 1, &dev_priv->render_ring); | 392 | drm_gem_object_unreference(&obj->base); |
| 310 | if (ret != 0) | 393 | overlay->vid_bo = NULL; |
| 311 | return ret; | ||
| 312 | 394 | ||
| 313 | overlay->hw_wedged = 0; | 395 | overlay->crtc->overlay = NULL; |
| 314 | overlay->last_flip_req = 0; | 396 | overlay->crtc = NULL; |
| 315 | return 0; | 397 | overlay->active = 0; |
| 316 | } | 398 | } |
| 317 | 399 | ||
| 318 | /* overlay needs to be disabled in OCMD reg */ | 400 | /* overlay needs to be disabled in OCMD reg */ |
| 319 | static int intel_overlay_off(struct intel_overlay *overlay) | 401 | static int intel_overlay_off(struct intel_overlay *overlay) |
| 320 | { | 402 | { |
| 321 | u32 flip_addr = overlay->flip_addr; | ||
| 322 | struct drm_device *dev = overlay->dev; | 403 | struct drm_device *dev = overlay->dev; |
| 323 | drm_i915_private_t *dev_priv = dev->dev_private; | 404 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 405 | u32 flip_addr = overlay->flip_addr; | ||
| 406 | struct drm_i915_gem_request *request; | ||
| 324 | int ret; | 407 | int ret; |
| 325 | 408 | ||
| 326 | BUG_ON(!overlay->active); | 409 | BUG_ON(!overlay->active); |
| 327 | 410 | ||
| 411 | request = kzalloc(sizeof(*request), GFP_KERNEL); | ||
| 412 | if (request == NULL) | ||
| 413 | return -ENOMEM; | ||
| 414 | |||
| 328 | /* According to intel docs the overlay hw may hang (when switching | 415 | /* According to intel docs the overlay hw may hang (when switching |
| 329 | * off) without loading the filter coeffs. It is however unclear whether | 416 | * off) without loading the filter coeffs. It is however unclear whether |
| 330 | * this applies to the disabling of the overlay or to the switching off | 417 | * this applies to the disabling of the overlay or to the switching off |
| 331 | * of the hw. Do it in both cases */ | 418 | * of the hw. Do it in both cases */ |
| 332 | flip_addr |= OFC_UPDATE; | 419 | flip_addr |= OFC_UPDATE; |
| 333 | 420 | ||
| 421 | ret = BEGIN_LP_RING(6); | ||
| 422 | if (ret) { | ||
| 423 | kfree(request); | ||
| 424 | return ret; | ||
| 425 | } | ||
| 334 | /* wait for overlay to go idle */ | 426 | /* wait for overlay to go idle */ |
| 335 | overlay->hw_wedged = SWITCH_OFF_STAGE_1; | ||
| 336 | |||
| 337 | BEGIN_LP_RING(4); | ||
| 338 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); | 427 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); |
| 339 | OUT_RING(flip_addr); | 428 | OUT_RING(flip_addr); |
| 340 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); | 429 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); |
| 341 | OUT_RING(MI_NOOP); | ||
| 342 | ADVANCE_LP_RING(); | ||
| 343 | |||
| 344 | overlay->last_flip_req = | ||
| 345 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | ||
| 346 | if (overlay->last_flip_req == 0) | ||
| 347 | return -ENOMEM; | ||
| 348 | |||
| 349 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | ||
| 350 | 1, &dev_priv->render_ring); | ||
| 351 | if (ret != 0) | ||
| 352 | return ret; | ||
| 353 | |||
| 354 | /* turn overlay off */ | 430 | /* turn overlay off */ |
| 355 | overlay->hw_wedged = SWITCH_OFF_STAGE_2; | 431 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); |
| 356 | |||
| 357 | BEGIN_LP_RING(4); | ||
| 358 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); | ||
| 359 | OUT_RING(flip_addr); | 432 | OUT_RING(flip_addr); |
| 360 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); | 433 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); |
| 361 | OUT_RING(MI_NOOP); | ||
| 362 | ADVANCE_LP_RING(); | 434 | ADVANCE_LP_RING(); |
| 363 | 435 | ||
| 364 | overlay->last_flip_req = | 436 | return intel_overlay_do_wait_request(overlay, request, |
| 365 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | 437 | intel_overlay_off_tail); |
| 366 | if (overlay->last_flip_req == 0) | ||
| 367 | return -ENOMEM; | ||
| 368 | |||
| 369 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | ||
| 370 | 1, &dev_priv->render_ring); | ||
| 371 | if (ret != 0) | ||
| 372 | return ret; | ||
| 373 | |||
| 374 | overlay->hw_wedged = 0; | ||
| 375 | overlay->last_flip_req = 0; | ||
| 376 | return ret; | ||
| 377 | } | ||
| 378 | |||
| 379 | static void intel_overlay_off_tail(struct intel_overlay *overlay) | ||
| 380 | { | ||
| 381 | struct drm_gem_object *obj; | ||
| 382 | |||
| 383 | /* never have the overlay hw on without showing a frame */ | ||
| 384 | BUG_ON(!overlay->vid_bo); | ||
| 385 | obj = &overlay->vid_bo->base; | ||
| 386 | |||
| 387 | i915_gem_object_unpin(obj); | ||
| 388 | drm_gem_object_unreference(obj); | ||
| 389 | overlay->vid_bo = NULL; | ||
| 390 | |||
| 391 | overlay->crtc->overlay = NULL; | ||
| 392 | overlay->crtc = NULL; | ||
| 393 | overlay->active = 0; | ||
| 394 | } | 438 | } |
| 395 | 439 | ||
| 396 | /* recover from an interruption due to a signal | 440 | /* recover from an interruption due to a signal |
| 397 | * We have to be careful not to repeat work forever an make forward progess. */ | 441 | * We have to be careful not to repeat work forever an make forward progess. */ |
| 398 | int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, | 442 | static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay) |
| 399 | int interruptible) | ||
| 400 | { | 443 | { |
| 401 | struct drm_device *dev = overlay->dev; | 444 | struct drm_device *dev = overlay->dev; |
| 402 | struct drm_gem_object *obj; | ||
| 403 | drm_i915_private_t *dev_priv = dev->dev_private; | 445 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 404 | u32 flip_addr; | ||
| 405 | int ret; | 446 | int ret; |
| 406 | 447 | ||
| 407 | if (overlay->hw_wedged == HW_WEDGED) | 448 | if (overlay->last_flip_req == 0) |
| 408 | return -EIO; | 449 | return 0; |
| 409 | |||
| 410 | if (overlay->last_flip_req == 0) { | ||
| 411 | overlay->last_flip_req = | ||
| 412 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | ||
| 413 | if (overlay->last_flip_req == 0) | ||
| 414 | return -ENOMEM; | ||
| 415 | } | ||
| 416 | 450 | ||
| 417 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | 451 | ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req); |
| 418 | interruptible, &dev_priv->render_ring); | 452 | if (ret) |
| 419 | if (ret != 0) | ||
| 420 | return ret; | 453 | return ret; |
| 421 | 454 | ||
| 422 | switch (overlay->hw_wedged) { | 455 | if (overlay->flip_tail) |
| 423 | case RELEASE_OLD_VID: | 456 | overlay->flip_tail(overlay); |
| 424 | obj = &overlay->old_vid_bo->base; | ||
| 425 | i915_gem_object_unpin(obj); | ||
| 426 | drm_gem_object_unreference(obj); | ||
| 427 | overlay->old_vid_bo = NULL; | ||
| 428 | break; | ||
| 429 | case SWITCH_OFF_STAGE_1: | ||
| 430 | flip_addr = overlay->flip_addr; | ||
| 431 | flip_addr |= OFC_UPDATE; | ||
| 432 | |||
| 433 | overlay->hw_wedged = SWITCH_OFF_STAGE_2; | ||
| 434 | |||
| 435 | BEGIN_LP_RING(4); | ||
| 436 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); | ||
| 437 | OUT_RING(flip_addr); | ||
| 438 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); | ||
| 439 | OUT_RING(MI_NOOP); | ||
| 440 | ADVANCE_LP_RING(); | ||
| 441 | |||
| 442 | overlay->last_flip_req = i915_add_request(dev, NULL, | ||
| 443 | 0, &dev_priv->render_ring); | ||
| 444 | if (overlay->last_flip_req == 0) | ||
| 445 | return -ENOMEM; | ||
| 446 | |||
| 447 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | ||
| 448 | interruptible, &dev_priv->render_ring); | ||
| 449 | if (ret != 0) | ||
| 450 | return ret; | ||
| 451 | |||
| 452 | case SWITCH_OFF_STAGE_2: | ||
| 453 | intel_overlay_off_tail(overlay); | ||
| 454 | break; | ||
| 455 | default: | ||
| 456 | BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP); | ||
| 457 | } | ||
| 458 | 457 | ||
| 459 | overlay->hw_wedged = 0; | ||
| 460 | overlay->last_flip_req = 0; | 458 | overlay->last_flip_req = 0; |
| 461 | return 0; | 459 | return 0; |
| 462 | } | 460 | } |
| 463 | 461 | ||
| 464 | /* Wait for pending overlay flip and release old frame. | 462 | /* Wait for pending overlay flip and release old frame. |
| 465 | * Needs to be called before the overlay register are changed | 463 | * Needs to be called before the overlay register are changed |
| 466 | * via intel_overlay_(un)map_regs_atomic */ | 464 | * via intel_overlay_(un)map_regs |
| 465 | */ | ||
| 467 | static int intel_overlay_release_old_vid(struct intel_overlay *overlay) | 466 | static int intel_overlay_release_old_vid(struct intel_overlay *overlay) |
| 468 | { | 467 | { |
| 468 | struct drm_device *dev = overlay->dev; | ||
| 469 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 469 | int ret; | 470 | int ret; |
| 470 | struct drm_gem_object *obj; | ||
| 471 | 471 | ||
| 472 | /* only wait if there is actually an old frame to release to | 472 | /* Only wait if there is actually an old frame to release to |
| 473 | * guarantee forward progress */ | 473 | * guarantee forward progress. |
| 474 | */ | ||
| 474 | if (!overlay->old_vid_bo) | 475 | if (!overlay->old_vid_bo) |
| 475 | return 0; | 476 | return 0; |
| 476 | 477 | ||
| 477 | ret = intel_overlay_wait_flip(overlay); | 478 | if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) { |
| 478 | if (ret != 0) | 479 | struct drm_i915_gem_request *request; |
| 479 | return ret; | ||
| 480 | 480 | ||
| 481 | obj = &overlay->old_vid_bo->base; | 481 | /* synchronous slowpath */ |
| 482 | i915_gem_object_unpin(obj); | 482 | request = kzalloc(sizeof(*request), GFP_KERNEL); |
| 483 | drm_gem_object_unreference(obj); | 483 | if (request == NULL) |
| 484 | overlay->old_vid_bo = NULL; | 484 | return -ENOMEM; |
| 485 | |||
| 486 | ret = BEGIN_LP_RING(2); | ||
| 487 | if (ret) { | ||
| 488 | kfree(request); | ||
| 489 | return ret; | ||
| 490 | } | ||
| 491 | |||
| 492 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); | ||
| 493 | OUT_RING(MI_NOOP); | ||
| 494 | ADVANCE_LP_RING(); | ||
| 495 | |||
| 496 | ret = intel_overlay_do_wait_request(overlay, request, | ||
| 497 | intel_overlay_release_old_vid_tail); | ||
| 498 | if (ret) | ||
| 499 | return ret; | ||
| 500 | } | ||
| 485 | 501 | ||
| 502 | intel_overlay_release_old_vid_tail(overlay); | ||
| 486 | return 0; | 503 | return 0; |
| 487 | } | 504 | } |
| 488 | 505 | ||
| @@ -506,65 +523,65 @@ struct put_image_params { | |||
| 506 | static int packed_depth_bytes(u32 format) | 523 | static int packed_depth_bytes(u32 format) |
| 507 | { | 524 | { |
| 508 | switch (format & I915_OVERLAY_DEPTH_MASK) { | 525 | switch (format & I915_OVERLAY_DEPTH_MASK) { |
| 509 | case I915_OVERLAY_YUV422: | 526 | case I915_OVERLAY_YUV422: |
| 510 | return 4; | 527 | return 4; |
| 511 | case I915_OVERLAY_YUV411: | 528 | case I915_OVERLAY_YUV411: |
| 512 | /* return 6; not implemented */ | 529 | /* return 6; not implemented */ |
| 513 | default: | 530 | default: |
| 514 | return -EINVAL; | 531 | return -EINVAL; |
| 515 | } | 532 | } |
| 516 | } | 533 | } |
| 517 | 534 | ||
| 518 | static int packed_width_bytes(u32 format, short width) | 535 | static int packed_width_bytes(u32 format, short width) |
| 519 | { | 536 | { |
| 520 | switch (format & I915_OVERLAY_DEPTH_MASK) { | 537 | switch (format & I915_OVERLAY_DEPTH_MASK) { |
| 521 | case I915_OVERLAY_YUV422: | 538 | case I915_OVERLAY_YUV422: |
| 522 | return width << 1; | 539 | return width << 1; |
| 523 | default: | 540 | default: |
| 524 | return -EINVAL; | 541 | return -EINVAL; |
| 525 | } | 542 | } |
| 526 | } | 543 | } |
| 527 | 544 | ||
| 528 | static int uv_hsubsampling(u32 format) | 545 | static int uv_hsubsampling(u32 format) |
| 529 | { | 546 | { |
| 530 | switch (format & I915_OVERLAY_DEPTH_MASK) { | 547 | switch (format & I915_OVERLAY_DEPTH_MASK) { |
| 531 | case I915_OVERLAY_YUV422: | 548 | case I915_OVERLAY_YUV422: |
| 532 | case I915_OVERLAY_YUV420: | 549 | case I915_OVERLAY_YUV420: |
| 533 | return 2; | 550 | return 2; |
| 534 | case I915_OVERLAY_YUV411: | 551 | case I915_OVERLAY_YUV411: |
| 535 | case I915_OVERLAY_YUV410: | 552 | case I915_OVERLAY_YUV410: |
| 536 | return 4; | 553 | return 4; |
| 537 | default: | 554 | default: |
| 538 | return -EINVAL; | 555 | return -EINVAL; |
| 539 | } | 556 | } |
| 540 | } | 557 | } |
| 541 | 558 | ||
| 542 | static int uv_vsubsampling(u32 format) | 559 | static int uv_vsubsampling(u32 format) |
| 543 | { | 560 | { |
| 544 | switch (format & I915_OVERLAY_DEPTH_MASK) { | 561 | switch (format & I915_OVERLAY_DEPTH_MASK) { |
| 545 | case I915_OVERLAY_YUV420: | 562 | case I915_OVERLAY_YUV420: |
| 546 | case I915_OVERLAY_YUV410: | 563 | case I915_OVERLAY_YUV410: |
| 547 | return 2; | 564 | return 2; |
| 548 | case I915_OVERLAY_YUV422: | 565 | case I915_OVERLAY_YUV422: |
| 549 | case I915_OVERLAY_YUV411: | 566 | case I915_OVERLAY_YUV411: |
| 550 | return 1; | 567 | return 1; |
| 551 | default: | 568 | default: |
| 552 | return -EINVAL; | 569 | return -EINVAL; |
| 553 | } | 570 | } |
| 554 | } | 571 | } |
| 555 | 572 | ||
| 556 | static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width) | 573 | static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width) |
| 557 | { | 574 | { |
| 558 | u32 mask, shift, ret; | 575 | u32 mask, shift, ret; |
| 559 | if (IS_I9XX(dev)) { | 576 | if (IS_GEN2(dev)) { |
| 560 | mask = 0x3f; | ||
| 561 | shift = 6; | ||
| 562 | } else { | ||
| 563 | mask = 0x1f; | 577 | mask = 0x1f; |
| 564 | shift = 5; | 578 | shift = 5; |
| 579 | } else { | ||
| 580 | mask = 0x3f; | ||
| 581 | shift = 6; | ||
| 565 | } | 582 | } |
| 566 | ret = ((offset + width + mask) >> shift) - (offset >> shift); | 583 | ret = ((offset + width + mask) >> shift) - (offset >> shift); |
| 567 | if (IS_I9XX(dev)) | 584 | if (!IS_GEN2(dev)) |
| 568 | ret <<= 1; | 585 | ret <<= 1; |
| 569 | ret -=1; | 586 | ret -=1; |
| 570 | return ret << 2; | 587 | return ret << 2; |
| @@ -587,7 +604,9 @@ static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = { | |||
| 587 | 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060, | 604 | 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060, |
| 588 | 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040, | 605 | 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040, |
| 589 | 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020, | 606 | 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020, |
| 590 | 0xb000, 0x3000, 0x0800, 0x3000, 0xb000}; | 607 | 0xb000, 0x3000, 0x0800, 0x3000, 0xb000 |
| 608 | }; | ||
| 609 | |||
| 591 | static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { | 610 | static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { |
| 592 | 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60, | 611 | 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60, |
| 593 | 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40, | 612 | 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40, |
| @@ -597,7 +616,8 @@ static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { | |||
| 597 | 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0, | 616 | 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0, |
| 598 | 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240, | 617 | 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240, |
| 599 | 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0, | 618 | 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0, |
| 600 | 0x3000, 0x0800, 0x3000}; | 619 | 0x3000, 0x0800, 0x3000 |
| 620 | }; | ||
| 601 | 621 | ||
| 602 | static void update_polyphase_filter(struct overlay_registers *regs) | 622 | static void update_polyphase_filter(struct overlay_registers *regs) |
| 603 | { | 623 | { |
| @@ -630,29 +650,31 @@ static bool update_scaling_factors(struct intel_overlay *overlay, | |||
| 630 | yscale = 1 << FP_SHIFT; | 650 | yscale = 1 << FP_SHIFT; |
| 631 | 651 | ||
| 632 | /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/ | 652 | /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/ |
| 633 | xscale_UV = xscale/uv_hscale; | 653 | xscale_UV = xscale/uv_hscale; |
| 634 | yscale_UV = yscale/uv_vscale; | 654 | yscale_UV = yscale/uv_vscale; |
| 635 | /* make the Y scale to UV scale ratio an exact multiply */ | 655 | /* make the Y scale to UV scale ratio an exact multiply */ |
| 636 | xscale = xscale_UV * uv_hscale; | 656 | xscale = xscale_UV * uv_hscale; |
| 637 | yscale = yscale_UV * uv_vscale; | 657 | yscale = yscale_UV * uv_vscale; |
| 638 | /*} else { | 658 | /*} else { |
| 639 | xscale_UV = 0; | 659 | xscale_UV = 0; |
| 640 | yscale_UV = 0; | 660 | yscale_UV = 0; |
| 641 | }*/ | 661 | }*/ |
| 642 | 662 | ||
| 643 | if (xscale != overlay->old_xscale || yscale != overlay->old_yscale) | 663 | if (xscale != overlay->old_xscale || yscale != overlay->old_yscale) |
| 644 | scale_changed = true; | 664 | scale_changed = true; |
| 645 | overlay->old_xscale = xscale; | 665 | overlay->old_xscale = xscale; |
| 646 | overlay->old_yscale = yscale; | 666 | overlay->old_yscale = yscale; |
| 647 | 667 | ||
| 648 | regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20) | 668 | regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) | |
| 649 | | ((xscale >> FP_SHIFT) << 16) | 669 | ((xscale >> FP_SHIFT) << 16) | |
| 650 | | ((xscale & FRACT_MASK) << 3); | 670 | ((xscale & FRACT_MASK) << 3)); |
| 651 | regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20) | 671 | |
| 652 | | ((xscale_UV >> FP_SHIFT) << 16) | 672 | regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) | |
| 653 | | ((xscale_UV & FRACT_MASK) << 3); | 673 | ((xscale_UV >> FP_SHIFT) << 16) | |
| 654 | regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16) | 674 | ((xscale_UV & FRACT_MASK) << 3)); |
| 655 | | ((yscale_UV >> FP_SHIFT) << 0); | 675 | |
| 676 | regs->UVSCALEV = ((((yscale >> FP_SHIFT) << 16) | | ||
| 677 | ((yscale_UV >> FP_SHIFT) << 0))); | ||
| 656 | 678 | ||
| 657 | if (scale_changed) | 679 | if (scale_changed) |
| 658 | update_polyphase_filter(regs); | 680 | update_polyphase_filter(regs); |
| @@ -664,22 +686,28 @@ static void update_colorkey(struct intel_overlay *overlay, | |||
| 664 | struct overlay_registers *regs) | 686 | struct overlay_registers *regs) |
| 665 | { | 687 | { |
| 666 | u32 key = overlay->color_key; | 688 | u32 key = overlay->color_key; |
| 689 | |||
| 667 | switch (overlay->crtc->base.fb->bits_per_pixel) { | 690 | switch (overlay->crtc->base.fb->bits_per_pixel) { |
| 668 | case 8: | 691 | case 8: |
| 669 | regs->DCLRKV = 0; | 692 | regs->DCLRKV = 0; |
| 670 | regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE; | 693 | regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE; |
| 671 | case 16: | 694 | break; |
| 672 | if (overlay->crtc->base.fb->depth == 15) { | 695 | |
| 673 | regs->DCLRKV = RGB15_TO_COLORKEY(key); | 696 | case 16: |
| 674 | regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE; | 697 | if (overlay->crtc->base.fb->depth == 15) { |
| 675 | } else { | 698 | regs->DCLRKV = RGB15_TO_COLORKEY(key); |
| 676 | regs->DCLRKV = RGB16_TO_COLORKEY(key); | 699 | regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE; |
| 677 | regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE; | 700 | } else { |
| 678 | } | 701 | regs->DCLRKV = RGB16_TO_COLORKEY(key); |
| 679 | case 24: | 702 | regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE; |
| 680 | case 32: | 703 | } |
| 681 | regs->DCLRKV = key; | 704 | break; |
| 682 | regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE; | 705 | |
| 706 | case 24: | ||
| 707 | case 32: | ||
| 708 | regs->DCLRKV = key; | ||
| 709 | regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE; | ||
| 710 | break; | ||
| 683 | } | 711 | } |
| 684 | } | 712 | } |
| 685 | 713 | ||
| @@ -689,53 +717,52 @@ static u32 overlay_cmd_reg(struct put_image_params *params) | |||
| 689 | 717 | ||
| 690 | if (params->format & I915_OVERLAY_YUV_PLANAR) { | 718 | if (params->format & I915_OVERLAY_YUV_PLANAR) { |
| 691 | switch (params->format & I915_OVERLAY_DEPTH_MASK) { | 719 | switch (params->format & I915_OVERLAY_DEPTH_MASK) { |
| 692 | case I915_OVERLAY_YUV422: | 720 | case I915_OVERLAY_YUV422: |
| 693 | cmd |= OCMD_YUV_422_PLANAR; | 721 | cmd |= OCMD_YUV_422_PLANAR; |
| 694 | break; | 722 | break; |
| 695 | case I915_OVERLAY_YUV420: | 723 | case I915_OVERLAY_YUV420: |
| 696 | cmd |= OCMD_YUV_420_PLANAR; | 724 | cmd |= OCMD_YUV_420_PLANAR; |
| 697 | break; | 725 | break; |
| 698 | case I915_OVERLAY_YUV411: | 726 | case I915_OVERLAY_YUV411: |
| 699 | case I915_OVERLAY_YUV410: | 727 | case I915_OVERLAY_YUV410: |
| 700 | cmd |= OCMD_YUV_410_PLANAR; | 728 | cmd |= OCMD_YUV_410_PLANAR; |
| 701 | break; | 729 | break; |
| 702 | } | 730 | } |
| 703 | } else { /* YUV packed */ | 731 | } else { /* YUV packed */ |
| 704 | switch (params->format & I915_OVERLAY_DEPTH_MASK) { | 732 | switch (params->format & I915_OVERLAY_DEPTH_MASK) { |
| 705 | case I915_OVERLAY_YUV422: | 733 | case I915_OVERLAY_YUV422: |
| 706 | cmd |= OCMD_YUV_422_PACKED; | 734 | cmd |= OCMD_YUV_422_PACKED; |
| 707 | break; | 735 | break; |
| 708 | case I915_OVERLAY_YUV411: | 736 | case I915_OVERLAY_YUV411: |
| 709 | cmd |= OCMD_YUV_411_PACKED; | 737 | cmd |= OCMD_YUV_411_PACKED; |
| 710 | break; | 738 | break; |
| 711 | } | 739 | } |
| 712 | 740 | ||
| 713 | switch (params->format & I915_OVERLAY_SWAP_MASK) { | 741 | switch (params->format & I915_OVERLAY_SWAP_MASK) { |
| 714 | case I915_OVERLAY_NO_SWAP: | 742 | case I915_OVERLAY_NO_SWAP: |
| 715 | break; | 743 | break; |
| 716 | case I915_OVERLAY_UV_SWAP: | 744 | case I915_OVERLAY_UV_SWAP: |
| 717 | cmd |= OCMD_UV_SWAP; | 745 | cmd |= OCMD_UV_SWAP; |
| 718 | break; | 746 | break; |
| 719 | case I915_OVERLAY_Y_SWAP: | 747 | case I915_OVERLAY_Y_SWAP: |
| 720 | cmd |= OCMD_Y_SWAP; | 748 | cmd |= OCMD_Y_SWAP; |
| 721 | break; | 749 | break; |
| 722 | case I915_OVERLAY_Y_AND_UV_SWAP: | 750 | case I915_OVERLAY_Y_AND_UV_SWAP: |
| 723 | cmd |= OCMD_Y_AND_UV_SWAP; | 751 | cmd |= OCMD_Y_AND_UV_SWAP; |
| 724 | break; | 752 | break; |
| 725 | } | 753 | } |
| 726 | } | 754 | } |
| 727 | 755 | ||
| 728 | return cmd; | 756 | return cmd; |
| 729 | } | 757 | } |
| 730 | 758 | ||
| 731 | int intel_overlay_do_put_image(struct intel_overlay *overlay, | 759 | static int intel_overlay_do_put_image(struct intel_overlay *overlay, |
| 732 | struct drm_gem_object *new_bo, | 760 | struct drm_i915_gem_object *new_bo, |
| 733 | struct put_image_params *params) | 761 | struct put_image_params *params) |
| 734 | { | 762 | { |
| 735 | int ret, tmp_width; | 763 | int ret, tmp_width; |
| 736 | struct overlay_registers *regs; | 764 | struct overlay_registers *regs; |
| 737 | bool scale_changed = false; | 765 | bool scale_changed = false; |
| 738 | struct drm_i915_gem_object *bo_priv = to_intel_bo(new_bo); | ||
| 739 | struct drm_device *dev = overlay->dev; | 766 | struct drm_device *dev = overlay->dev; |
| 740 | 767 | ||
| 741 | BUG_ON(!mutex_is_locked(&dev->struct_mutex)); | 768 | BUG_ON(!mutex_is_locked(&dev->struct_mutex)); |
| @@ -746,7 +773,7 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, | |||
| 746 | if (ret != 0) | 773 | if (ret != 0) |
| 747 | return ret; | 774 | return ret; |
| 748 | 775 | ||
| 749 | ret = i915_gem_object_pin(new_bo, PAGE_SIZE); | 776 | ret = i915_gem_object_pin(new_bo, PAGE_SIZE, true); |
| 750 | if (ret != 0) | 777 | if (ret != 0) |
| 751 | return ret; | 778 | return ret; |
| 752 | 779 | ||
| @@ -754,25 +781,29 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, | |||
| 754 | if (ret != 0) | 781 | if (ret != 0) |
| 755 | goto out_unpin; | 782 | goto out_unpin; |
| 756 | 783 | ||
| 784 | ret = i915_gem_object_put_fence(new_bo); | ||
| 785 | if (ret) | ||
| 786 | goto out_unpin; | ||
| 787 | |||
| 757 | if (!overlay->active) { | 788 | if (!overlay->active) { |
| 758 | regs = intel_overlay_map_regs_atomic(overlay); | 789 | regs = intel_overlay_map_regs(overlay); |
| 759 | if (!regs) { | 790 | if (!regs) { |
| 760 | ret = -ENOMEM; | 791 | ret = -ENOMEM; |
| 761 | goto out_unpin; | 792 | goto out_unpin; |
| 762 | } | 793 | } |
| 763 | regs->OCONFIG = OCONF_CC_OUT_8BIT; | 794 | regs->OCONFIG = OCONF_CC_OUT_8BIT; |
| 764 | if (IS_I965GM(overlay->dev)) | 795 | if (IS_GEN4(overlay->dev)) |
| 765 | regs->OCONFIG |= OCONF_CSC_MODE_BT709; | 796 | regs->OCONFIG |= OCONF_CSC_MODE_BT709; |
| 766 | regs->OCONFIG |= overlay->crtc->pipe == 0 ? | 797 | regs->OCONFIG |= overlay->crtc->pipe == 0 ? |
| 767 | OCONF_PIPE_A : OCONF_PIPE_B; | 798 | OCONF_PIPE_A : OCONF_PIPE_B; |
| 768 | intel_overlay_unmap_regs_atomic(overlay); | 799 | intel_overlay_unmap_regs(overlay, regs); |
| 769 | 800 | ||
| 770 | ret = intel_overlay_on(overlay); | 801 | ret = intel_overlay_on(overlay); |
| 771 | if (ret != 0) | 802 | if (ret != 0) |
| 772 | goto out_unpin; | 803 | goto out_unpin; |
| 773 | } | 804 | } |
| 774 | 805 | ||
| 775 | regs = intel_overlay_map_regs_atomic(overlay); | 806 | regs = intel_overlay_map_regs(overlay); |
| 776 | if (!regs) { | 807 | if (!regs) { |
| 777 | ret = -ENOMEM; | 808 | ret = -ENOMEM; |
| 778 | goto out_unpin; | 809 | goto out_unpin; |
| @@ -788,9 +819,9 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, | |||
| 788 | 819 | ||
| 789 | regs->SWIDTH = params->src_w; | 820 | regs->SWIDTH = params->src_w; |
| 790 | regs->SWIDTHSW = calc_swidthsw(overlay->dev, | 821 | regs->SWIDTHSW = calc_swidthsw(overlay->dev, |
| 791 | params->offset_Y, tmp_width); | 822 | params->offset_Y, tmp_width); |
| 792 | regs->SHEIGHT = params->src_h; | 823 | regs->SHEIGHT = params->src_h; |
| 793 | regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y; | 824 | regs->OBUF_0Y = new_bo->gtt_offset + params-> offset_Y; |
| 794 | regs->OSTRIDE = params->stride_Y; | 825 | regs->OSTRIDE = params->stride_Y; |
| 795 | 826 | ||
| 796 | if (params->format & I915_OVERLAY_YUV_PLANAR) { | 827 | if (params->format & I915_OVERLAY_YUV_PLANAR) { |
| @@ -799,13 +830,13 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, | |||
| 799 | u32 tmp_U, tmp_V; | 830 | u32 tmp_U, tmp_V; |
| 800 | regs->SWIDTH |= (params->src_w/uv_hscale) << 16; | 831 | regs->SWIDTH |= (params->src_w/uv_hscale) << 16; |
| 801 | tmp_U = calc_swidthsw(overlay->dev, params->offset_U, | 832 | tmp_U = calc_swidthsw(overlay->dev, params->offset_U, |
| 802 | params->src_w/uv_hscale); | 833 | params->src_w/uv_hscale); |
| 803 | tmp_V = calc_swidthsw(overlay->dev, params->offset_V, | 834 | tmp_V = calc_swidthsw(overlay->dev, params->offset_V, |
| 804 | params->src_w/uv_hscale); | 835 | params->src_w/uv_hscale); |
| 805 | regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16; | 836 | regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16; |
| 806 | regs->SHEIGHT |= (params->src_h/uv_vscale) << 16; | 837 | regs->SHEIGHT |= (params->src_h/uv_vscale) << 16; |
| 807 | regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U; | 838 | regs->OBUF_0U = new_bo->gtt_offset + params->offset_U; |
| 808 | regs->OBUF_0V = bo_priv->gtt_offset + params->offset_V; | 839 | regs->OBUF_0V = new_bo->gtt_offset + params->offset_V; |
| 809 | regs->OSTRIDE |= params->stride_UV << 16; | 840 | regs->OSTRIDE |= params->stride_UV << 16; |
| 810 | } | 841 | } |
| 811 | 842 | ||
| @@ -815,12 +846,14 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, | |||
| 815 | 846 | ||
| 816 | regs->OCMD = overlay_cmd_reg(params); | 847 | regs->OCMD = overlay_cmd_reg(params); |
| 817 | 848 | ||
| 818 | intel_overlay_unmap_regs_atomic(overlay); | 849 | intel_overlay_unmap_regs(overlay, regs); |
| 819 | 850 | ||
| 820 | intel_overlay_continue(overlay, scale_changed); | 851 | ret = intel_overlay_continue(overlay, scale_changed); |
| 852 | if (ret) | ||
| 853 | goto out_unpin; | ||
| 821 | 854 | ||
| 822 | overlay->old_vid_bo = overlay->vid_bo; | 855 | overlay->old_vid_bo = overlay->vid_bo; |
| 823 | overlay->vid_bo = to_intel_bo(new_bo); | 856 | overlay->vid_bo = new_bo; |
| 824 | 857 | ||
| 825 | return 0; | 858 | return 0; |
| 826 | 859 | ||
| @@ -831,18 +864,16 @@ out_unpin: | |||
| 831 | 864 | ||
| 832 | int intel_overlay_switch_off(struct intel_overlay *overlay) | 865 | int intel_overlay_switch_off(struct intel_overlay *overlay) |
| 833 | { | 866 | { |
| 834 | int ret; | ||
| 835 | struct overlay_registers *regs; | 867 | struct overlay_registers *regs; |
| 836 | struct drm_device *dev = overlay->dev; | 868 | struct drm_device *dev = overlay->dev; |
| 869 | int ret; | ||
| 837 | 870 | ||
| 838 | BUG_ON(!mutex_is_locked(&dev->struct_mutex)); | 871 | BUG_ON(!mutex_is_locked(&dev->struct_mutex)); |
| 839 | BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); | 872 | BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); |
| 840 | 873 | ||
| 841 | if (overlay->hw_wedged) { | 874 | ret = intel_overlay_recover_from_interrupt(overlay); |
| 842 | ret = intel_overlay_recover_from_interrupt(overlay, 1); | 875 | if (ret != 0) |
| 843 | if (ret != 0) | 876 | return ret; |
| 844 | return ret; | ||
| 845 | } | ||
| 846 | 877 | ||
| 847 | if (!overlay->active) | 878 | if (!overlay->active) |
| 848 | return 0; | 879 | return 0; |
| @@ -851,33 +882,29 @@ int intel_overlay_switch_off(struct intel_overlay *overlay) | |||
| 851 | if (ret != 0) | 882 | if (ret != 0) |
| 852 | return ret; | 883 | return ret; |
| 853 | 884 | ||
| 854 | regs = intel_overlay_map_regs_atomic(overlay); | 885 | regs = intel_overlay_map_regs(overlay); |
| 855 | regs->OCMD = 0; | 886 | regs->OCMD = 0; |
| 856 | intel_overlay_unmap_regs_atomic(overlay); | 887 | intel_overlay_unmap_regs(overlay, regs); |
| 857 | 888 | ||
| 858 | ret = intel_overlay_off(overlay); | 889 | ret = intel_overlay_off(overlay); |
| 859 | if (ret != 0) | 890 | if (ret != 0) |
| 860 | return ret; | 891 | return ret; |
| 861 | 892 | ||
| 862 | intel_overlay_off_tail(overlay); | 893 | intel_overlay_off_tail(overlay); |
| 863 | |||
| 864 | return 0; | 894 | return 0; |
| 865 | } | 895 | } |
| 866 | 896 | ||
| 867 | static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, | 897 | static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, |
| 868 | struct intel_crtc *crtc) | 898 | struct intel_crtc *crtc) |
| 869 | { | 899 | { |
| 870 | drm_i915_private_t *dev_priv = overlay->dev->dev_private; | 900 | drm_i915_private_t *dev_priv = overlay->dev->dev_private; |
| 871 | u32 pipeconf; | ||
| 872 | int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
| 873 | 901 | ||
| 874 | if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON) | 902 | if (!crtc->active) |
| 875 | return -EINVAL; | 903 | return -EINVAL; |
| 876 | 904 | ||
| 877 | pipeconf = I915_READ(pipeconf_reg); | ||
| 878 | |||
| 879 | /* can't use the overlay with double wide pipe */ | 905 | /* can't use the overlay with double wide pipe */ |
| 880 | if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE) | 906 | if (INTEL_INFO(overlay->dev)->gen < 4 && |
| 907 | (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE) | ||
| 881 | return -EINVAL; | 908 | return -EINVAL; |
| 882 | 909 | ||
| 883 | return 0; | 910 | return 0; |
| @@ -886,20 +913,22 @@ static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, | |||
| 886 | static void update_pfit_vscale_ratio(struct intel_overlay *overlay) | 913 | static void update_pfit_vscale_ratio(struct intel_overlay *overlay) |
| 887 | { | 914 | { |
| 888 | struct drm_device *dev = overlay->dev; | 915 | struct drm_device *dev = overlay->dev; |
| 889 | drm_i915_private_t *dev_priv = dev->dev_private; | 916 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 890 | u32 ratio; | ||
| 891 | u32 pfit_control = I915_READ(PFIT_CONTROL); | 917 | u32 pfit_control = I915_READ(PFIT_CONTROL); |
| 918 | u32 ratio; | ||
| 892 | 919 | ||
| 893 | /* XXX: This is not the same logic as in the xorg driver, but more in | 920 | /* XXX: This is not the same logic as in the xorg driver, but more in |
| 894 | * line with the intel documentation for the i965 */ | 921 | * line with the intel documentation for the i965 |
| 895 | if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) { | 922 | */ |
| 896 | ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT; | 923 | if (INTEL_INFO(dev)->gen >= 4) { |
| 897 | } else { /* on i965 use the PGM reg to read out the autoscaler values */ | 924 | /* on i965 use the PGM reg to read out the autoscaler values */ |
| 898 | ratio = I915_READ(PFIT_PGM_RATIOS); | 925 | ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965; |
| 899 | if (IS_I965G(dev)) | 926 | } else { |
| 900 | ratio >>= PFIT_VERT_SCALE_SHIFT_965; | 927 | if (pfit_control & VERT_AUTO_SCALE) |
| 928 | ratio = I915_READ(PFIT_AUTO_RATIOS); | ||
| 901 | else | 929 | else |
| 902 | ratio >>= PFIT_VERT_SCALE_SHIFT; | 930 | ratio = I915_READ(PFIT_PGM_RATIOS); |
| 931 | ratio >>= PFIT_VERT_SCALE_SHIFT; | ||
| 903 | } | 932 | } |
| 904 | 933 | ||
| 905 | overlay->pfit_vscale_ratio = ratio; | 934 | overlay->pfit_vscale_ratio = ratio; |
| @@ -910,12 +939,10 @@ static int check_overlay_dst(struct intel_overlay *overlay, | |||
| 910 | { | 939 | { |
| 911 | struct drm_display_mode *mode = &overlay->crtc->base.mode; | 940 | struct drm_display_mode *mode = &overlay->crtc->base.mode; |
| 912 | 941 | ||
| 913 | if ((rec->dst_x < mode->crtc_hdisplay) | 942 | if (rec->dst_x < mode->crtc_hdisplay && |
| 914 | && (rec->dst_x + rec->dst_width | 943 | rec->dst_x + rec->dst_width <= mode->crtc_hdisplay && |
| 915 | <= mode->crtc_hdisplay) | 944 | rec->dst_y < mode->crtc_vdisplay && |
| 916 | && (rec->dst_y < mode->crtc_vdisplay) | 945 | rec->dst_y + rec->dst_height <= mode->crtc_vdisplay) |
| 917 | && (rec->dst_y + rec->dst_height | ||
| 918 | <= mode->crtc_vdisplay)) | ||
| 919 | return 0; | 946 | return 0; |
| 920 | else | 947 | else |
| 921 | return -EINVAL; | 948 | return -EINVAL; |
| @@ -938,55 +965,61 @@ static int check_overlay_scaling(struct put_image_params *rec) | |||
| 938 | 965 | ||
| 939 | static int check_overlay_src(struct drm_device *dev, | 966 | static int check_overlay_src(struct drm_device *dev, |
| 940 | struct drm_intel_overlay_put_image *rec, | 967 | struct drm_intel_overlay_put_image *rec, |
| 941 | struct drm_gem_object *new_bo) | 968 | struct drm_i915_gem_object *new_bo) |
| 942 | { | 969 | { |
| 943 | u32 stride_mask; | ||
| 944 | int depth; | ||
| 945 | int uv_hscale = uv_hsubsampling(rec->flags); | 970 | int uv_hscale = uv_hsubsampling(rec->flags); |
| 946 | int uv_vscale = uv_vsubsampling(rec->flags); | 971 | int uv_vscale = uv_vsubsampling(rec->flags); |
| 947 | size_t tmp; | 972 | u32 stride_mask; |
| 973 | int depth; | ||
| 974 | u32 tmp; | ||
| 948 | 975 | ||
| 949 | /* check src dimensions */ | 976 | /* check src dimensions */ |
| 950 | if (IS_845G(dev) || IS_I830(dev)) { | 977 | if (IS_845G(dev) || IS_I830(dev)) { |
| 951 | if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY | 978 | if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY || |
| 952 | || rec->src_width > IMAGE_MAX_WIDTH_LEGACY) | 979 | rec->src_width > IMAGE_MAX_WIDTH_LEGACY) |
| 953 | return -EINVAL; | 980 | return -EINVAL; |
| 954 | } else { | 981 | } else { |
| 955 | if (rec->src_height > IMAGE_MAX_HEIGHT | 982 | if (rec->src_height > IMAGE_MAX_HEIGHT || |
| 956 | || rec->src_width > IMAGE_MAX_WIDTH) | 983 | rec->src_width > IMAGE_MAX_WIDTH) |
| 957 | return -EINVAL; | 984 | return -EINVAL; |
| 958 | } | 985 | } |
| 986 | |||
| 959 | /* better safe than sorry, use 4 as the maximal subsampling ratio */ | 987 | /* better safe than sorry, use 4 as the maximal subsampling ratio */ |
| 960 | if (rec->src_height < N_VERT_Y_TAPS*4 | 988 | if (rec->src_height < N_VERT_Y_TAPS*4 || |
| 961 | || rec->src_width < N_HORIZ_Y_TAPS*4) | 989 | rec->src_width < N_HORIZ_Y_TAPS*4) |
| 962 | return -EINVAL; | 990 | return -EINVAL; |
| 963 | 991 | ||
| 964 | /* check alignment constraints */ | 992 | /* check alignment constraints */ |
| 965 | switch (rec->flags & I915_OVERLAY_TYPE_MASK) { | 993 | switch (rec->flags & I915_OVERLAY_TYPE_MASK) { |
| 966 | case I915_OVERLAY_RGB: | 994 | case I915_OVERLAY_RGB: |
| 967 | /* not implemented */ | 995 | /* not implemented */ |
| 996 | return -EINVAL; | ||
| 997 | |||
| 998 | case I915_OVERLAY_YUV_PACKED: | ||
| 999 | if (uv_vscale != 1) | ||
| 968 | return -EINVAL; | 1000 | return -EINVAL; |
| 969 | case I915_OVERLAY_YUV_PACKED: | 1001 | |
| 970 | depth = packed_depth_bytes(rec->flags); | 1002 | depth = packed_depth_bytes(rec->flags); |
| 971 | if (uv_vscale != 1) | 1003 | if (depth < 0) |
| 972 | return -EINVAL; | 1004 | return depth; |
| 973 | if (depth < 0) | 1005 | |
| 974 | return depth; | 1006 | /* ignore UV planes */ |
| 975 | /* ignore UV planes */ | 1007 | rec->stride_UV = 0; |
| 976 | rec->stride_UV = 0; | 1008 | rec->offset_U = 0; |
| 977 | rec->offset_U = 0; | 1009 | rec->offset_V = 0; |
| 978 | rec->offset_V = 0; | 1010 | /* check pixel alignment */ |
| 979 | /* check pixel alignment */ | 1011 | if (rec->offset_Y % depth) |
| 980 | if (rec->offset_Y % depth) | ||
| 981 | return -EINVAL; | ||
| 982 | break; | ||
| 983 | case I915_OVERLAY_YUV_PLANAR: | ||
| 984 | if (uv_vscale < 0 || uv_hscale < 0) | ||
| 985 | return -EINVAL; | ||
| 986 | /* no offset restrictions for planar formats */ | ||
| 987 | break; | ||
| 988 | default: | ||
| 989 | return -EINVAL; | 1012 | return -EINVAL; |
| 1013 | break; | ||
| 1014 | |||
| 1015 | case I915_OVERLAY_YUV_PLANAR: | ||
| 1016 | if (uv_vscale < 0 || uv_hscale < 0) | ||
| 1017 | return -EINVAL; | ||
| 1018 | /* no offset restrictions for planar formats */ | ||
| 1019 | break; | ||
| 1020 | |||
| 1021 | default: | ||
| 1022 | return -EINVAL; | ||
| 990 | } | 1023 | } |
| 991 | 1024 | ||
| 992 | if (rec->src_width % uv_hscale) | 1025 | if (rec->src_width % uv_hscale) |
| @@ -1000,47 +1033,74 @@ static int check_overlay_src(struct drm_device *dev, | |||
| 1000 | 1033 | ||
| 1001 | if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) | 1034 | if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) |
| 1002 | return -EINVAL; | 1035 | return -EINVAL; |
| 1003 | if (IS_I965G(dev) && rec->stride_Y < 512) | 1036 | if (IS_GEN4(dev) && rec->stride_Y < 512) |
| 1004 | return -EINVAL; | 1037 | return -EINVAL; |
| 1005 | 1038 | ||
| 1006 | tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? | 1039 | tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? |
| 1007 | 4 : 8; | 1040 | 4096 : 8192; |
| 1008 | if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024) | 1041 | if (rec->stride_Y > tmp || rec->stride_UV > 2*1024) |
| 1009 | return -EINVAL; | 1042 | return -EINVAL; |
| 1010 | 1043 | ||
| 1011 | /* check buffer dimensions */ | 1044 | /* check buffer dimensions */ |
| 1012 | switch (rec->flags & I915_OVERLAY_TYPE_MASK) { | 1045 | switch (rec->flags & I915_OVERLAY_TYPE_MASK) { |
| 1013 | case I915_OVERLAY_RGB: | 1046 | case I915_OVERLAY_RGB: |
| 1014 | case I915_OVERLAY_YUV_PACKED: | 1047 | case I915_OVERLAY_YUV_PACKED: |
| 1015 | /* always 4 Y values per depth pixels */ | 1048 | /* always 4 Y values per depth pixels */ |
| 1016 | if (packed_width_bytes(rec->flags, rec->src_width) | 1049 | if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y) |
| 1017 | > rec->stride_Y) | 1050 | return -EINVAL; |
| 1018 | return -EINVAL; | 1051 | |
| 1019 | 1052 | tmp = rec->stride_Y*rec->src_height; | |
| 1020 | tmp = rec->stride_Y*rec->src_height; | 1053 | if (rec->offset_Y + tmp > new_bo->base.size) |
| 1021 | if (rec->offset_Y + tmp > new_bo->size) | 1054 | return -EINVAL; |
| 1022 | return -EINVAL; | 1055 | break; |
| 1023 | break; | 1056 | |
| 1024 | case I915_OVERLAY_YUV_PLANAR: | 1057 | case I915_OVERLAY_YUV_PLANAR: |
| 1025 | if (rec->src_width > rec->stride_Y) | 1058 | if (rec->src_width > rec->stride_Y) |
| 1026 | return -EINVAL; | 1059 | return -EINVAL; |
| 1027 | if (rec->src_width/uv_hscale > rec->stride_UV) | 1060 | if (rec->src_width/uv_hscale > rec->stride_UV) |
| 1028 | return -EINVAL; | 1061 | return -EINVAL; |
| 1029 | 1062 | ||
| 1030 | tmp = rec->stride_Y*rec->src_height; | 1063 | tmp = rec->stride_Y * rec->src_height; |
| 1031 | if (rec->offset_Y + tmp > new_bo->size) | 1064 | if (rec->offset_Y + tmp > new_bo->base.size) |
| 1032 | return -EINVAL; | 1065 | return -EINVAL; |
| 1033 | tmp = rec->stride_UV*rec->src_height; | 1066 | |
| 1034 | tmp /= uv_vscale; | 1067 | tmp = rec->stride_UV * (rec->src_height / uv_vscale); |
| 1035 | if (rec->offset_U + tmp > new_bo->size | 1068 | if (rec->offset_U + tmp > new_bo->base.size || |
| 1036 | || rec->offset_V + tmp > new_bo->size) | 1069 | rec->offset_V + tmp > new_bo->base.size) |
| 1037 | return -EINVAL; | 1070 | return -EINVAL; |
| 1038 | break; | 1071 | break; |
| 1039 | } | 1072 | } |
| 1040 | 1073 | ||
| 1041 | return 0; | 1074 | return 0; |
| 1042 | } | 1075 | } |
| 1043 | 1076 | ||
| 1077 | /** | ||
| 1078 | * Return the pipe currently connected to the panel fitter, | ||
| 1079 | * or -1 if the panel fitter is not present or not in use | ||
| 1080 | */ | ||
| 1081 | static int intel_panel_fitter_pipe(struct drm_device *dev) | ||
| 1082 | { | ||
| 1083 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 1084 | u32 pfit_control; | ||
| 1085 | |||
| 1086 | /* i830 doesn't have a panel fitter */ | ||
| 1087 | if (IS_I830(dev)) | ||
| 1088 | return -1; | ||
| 1089 | |||
| 1090 | pfit_control = I915_READ(PFIT_CONTROL); | ||
| 1091 | |||
| 1092 | /* See if the panel fitter is in use */ | ||
| 1093 | if ((pfit_control & PFIT_ENABLE) == 0) | ||
| 1094 | return -1; | ||
| 1095 | |||
| 1096 | /* 965 can place panel fitter on either pipe */ | ||
| 1097 | if (IS_GEN4(dev)) | ||
| 1098 | return (pfit_control >> 29) & 0x3; | ||
| 1099 | |||
| 1100 | /* older chips can only use pipe 1 */ | ||
| 1101 | return 1; | ||
| 1102 | } | ||
| 1103 | |||
| 1044 | int intel_overlay_put_image(struct drm_device *dev, void *data, | 1104 | int intel_overlay_put_image(struct drm_device *dev, void *data, |
| 1045 | struct drm_file *file_priv) | 1105 | struct drm_file *file_priv) |
| 1046 | { | 1106 | { |
| @@ -1049,7 +1109,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
| 1049 | struct intel_overlay *overlay; | 1109 | struct intel_overlay *overlay; |
| 1050 | struct drm_mode_object *drmmode_obj; | 1110 | struct drm_mode_object *drmmode_obj; |
| 1051 | struct intel_crtc *crtc; | 1111 | struct intel_crtc *crtc; |
| 1052 | struct drm_gem_object *new_bo; | 1112 | struct drm_i915_gem_object *new_bo; |
| 1053 | struct put_image_params *params; | 1113 | struct put_image_params *params; |
| 1054 | int ret; | 1114 | int ret; |
| 1055 | 1115 | ||
| @@ -1081,16 +1141,16 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
| 1081 | return -ENOMEM; | 1141 | return -ENOMEM; |
| 1082 | 1142 | ||
| 1083 | drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id, | 1143 | drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id, |
| 1084 | DRM_MODE_OBJECT_CRTC); | 1144 | DRM_MODE_OBJECT_CRTC); |
| 1085 | if (!drmmode_obj) { | 1145 | if (!drmmode_obj) { |
| 1086 | ret = -ENOENT; | 1146 | ret = -ENOENT; |
| 1087 | goto out_free; | 1147 | goto out_free; |
| 1088 | } | 1148 | } |
| 1089 | crtc = to_intel_crtc(obj_to_crtc(drmmode_obj)); | 1149 | crtc = to_intel_crtc(obj_to_crtc(drmmode_obj)); |
| 1090 | 1150 | ||
| 1091 | new_bo = drm_gem_object_lookup(dev, file_priv, | 1151 | new_bo = to_intel_bo(drm_gem_object_lookup(dev, file_priv, |
| 1092 | put_image_rec->bo_handle); | 1152 | put_image_rec->bo_handle)); |
| 1093 | if (!new_bo) { | 1153 | if (&new_bo->base == NULL) { |
| 1094 | ret = -ENOENT; | 1154 | ret = -ENOENT; |
| 1095 | goto out_free; | 1155 | goto out_free; |
| 1096 | } | 1156 | } |
| @@ -1098,12 +1158,16 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
| 1098 | mutex_lock(&dev->mode_config.mutex); | 1158 | mutex_lock(&dev->mode_config.mutex); |
| 1099 | mutex_lock(&dev->struct_mutex); | 1159 | mutex_lock(&dev->struct_mutex); |
| 1100 | 1160 | ||
| 1101 | if (overlay->hw_wedged) { | 1161 | if (new_bo->tiling_mode) { |
| 1102 | ret = intel_overlay_recover_from_interrupt(overlay, 1); | 1162 | DRM_ERROR("buffer used for overlay image can not be tiled\n"); |
| 1103 | if (ret != 0) | 1163 | ret = -EINVAL; |
| 1104 | goto out_unlock; | 1164 | goto out_unlock; |
| 1105 | } | 1165 | } |
| 1106 | 1166 | ||
| 1167 | ret = intel_overlay_recover_from_interrupt(overlay); | ||
| 1168 | if (ret != 0) | ||
| 1169 | goto out_unlock; | ||
| 1170 | |||
| 1107 | if (overlay->crtc != crtc) { | 1171 | if (overlay->crtc != crtc) { |
| 1108 | struct drm_display_mode *mode = &crtc->base.mode; | 1172 | struct drm_display_mode *mode = &crtc->base.mode; |
| 1109 | ret = intel_overlay_switch_off(overlay); | 1173 | ret = intel_overlay_switch_off(overlay); |
| @@ -1117,9 +1181,9 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
| 1117 | overlay->crtc = crtc; | 1181 | overlay->crtc = crtc; |
| 1118 | crtc->overlay = overlay; | 1182 | crtc->overlay = overlay; |
| 1119 | 1183 | ||
| 1120 | if (intel_panel_fitter_pipe(dev) == crtc->pipe | 1184 | /* line too wide, i.e. one-line-mode */ |
| 1121 | /* and line to wide, i.e. one-line-mode */ | 1185 | if (mode->hdisplay > 1024 && |
| 1122 | && mode->hdisplay > 1024) { | 1186 | intel_panel_fitter_pipe(dev) == crtc->pipe) { |
| 1123 | overlay->pfit_active = 1; | 1187 | overlay->pfit_active = 1; |
| 1124 | update_pfit_vscale_ratio(overlay); | 1188 | update_pfit_vscale_ratio(overlay); |
| 1125 | } else | 1189 | } else |
| @@ -1132,10 +1196,10 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
| 1132 | 1196 | ||
| 1133 | if (overlay->pfit_active) { | 1197 | if (overlay->pfit_active) { |
| 1134 | params->dst_y = ((((u32)put_image_rec->dst_y) << 12) / | 1198 | params->dst_y = ((((u32)put_image_rec->dst_y) << 12) / |
| 1135 | overlay->pfit_vscale_ratio); | 1199 | overlay->pfit_vscale_ratio); |
| 1136 | /* shifting right rounds downwards, so add 1 */ | 1200 | /* shifting right rounds downwards, so add 1 */ |
| 1137 | params->dst_h = ((((u32)put_image_rec->dst_height) << 12) / | 1201 | params->dst_h = ((((u32)put_image_rec->dst_height) << 12) / |
| 1138 | overlay->pfit_vscale_ratio) + 1; | 1202 | overlay->pfit_vscale_ratio) + 1; |
| 1139 | } else { | 1203 | } else { |
| 1140 | params->dst_y = put_image_rec->dst_y; | 1204 | params->dst_y = put_image_rec->dst_y; |
| 1141 | params->dst_h = put_image_rec->dst_height; | 1205 | params->dst_h = put_image_rec->dst_height; |
| @@ -1147,8 +1211,8 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
| 1147 | params->src_h = put_image_rec->src_height; | 1211 | params->src_h = put_image_rec->src_height; |
| 1148 | params->src_scan_w = put_image_rec->src_scan_width; | 1212 | params->src_scan_w = put_image_rec->src_scan_width; |
| 1149 | params->src_scan_h = put_image_rec->src_scan_height; | 1213 | params->src_scan_h = put_image_rec->src_scan_height; |
| 1150 | if (params->src_scan_h > params->src_h | 1214 | if (params->src_scan_h > params->src_h || |
| 1151 | || params->src_scan_w > params->src_w) { | 1215 | params->src_scan_w > params->src_w) { |
| 1152 | ret = -EINVAL; | 1216 | ret = -EINVAL; |
| 1153 | goto out_unlock; | 1217 | goto out_unlock; |
| 1154 | } | 1218 | } |
| @@ -1182,7 +1246,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
| 1182 | out_unlock: | 1246 | out_unlock: |
| 1183 | mutex_unlock(&dev->struct_mutex); | 1247 | mutex_unlock(&dev->struct_mutex); |
| 1184 | mutex_unlock(&dev->mode_config.mutex); | 1248 | mutex_unlock(&dev->mode_config.mutex); |
| 1185 | drm_gem_object_unreference_unlocked(new_bo); | 1249 | drm_gem_object_unreference_unlocked(&new_bo->base); |
| 1186 | out_free: | 1250 | out_free: |
| 1187 | kfree(params); | 1251 | kfree(params); |
| 1188 | 1252 | ||
| @@ -1204,7 +1268,7 @@ static bool check_gamma_bounds(u32 gamma1, u32 gamma2) | |||
| 1204 | return false; | 1268 | return false; |
| 1205 | 1269 | ||
| 1206 | for (i = 0; i < 3; i++) { | 1270 | for (i = 0; i < 3; i++) { |
| 1207 | if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff)) | 1271 | if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff)) |
| 1208 | return false; | 1272 | return false; |
| 1209 | } | 1273 | } |
| 1210 | 1274 | ||
| @@ -1225,16 +1289,18 @@ static bool check_gamma5_errata(u32 gamma5) | |||
| 1225 | 1289 | ||
| 1226 | static int check_gamma(struct drm_intel_overlay_attrs *attrs) | 1290 | static int check_gamma(struct drm_intel_overlay_attrs *attrs) |
| 1227 | { | 1291 | { |
| 1228 | if (!check_gamma_bounds(0, attrs->gamma0) | 1292 | if (!check_gamma_bounds(0, attrs->gamma0) || |
| 1229 | || !check_gamma_bounds(attrs->gamma0, attrs->gamma1) | 1293 | !check_gamma_bounds(attrs->gamma0, attrs->gamma1) || |
| 1230 | || !check_gamma_bounds(attrs->gamma1, attrs->gamma2) | 1294 | !check_gamma_bounds(attrs->gamma1, attrs->gamma2) || |
| 1231 | || !check_gamma_bounds(attrs->gamma2, attrs->gamma3) | 1295 | !check_gamma_bounds(attrs->gamma2, attrs->gamma3) || |
| 1232 | || !check_gamma_bounds(attrs->gamma3, attrs->gamma4) | 1296 | !check_gamma_bounds(attrs->gamma3, attrs->gamma4) || |
| 1233 | || !check_gamma_bounds(attrs->gamma4, attrs->gamma5) | 1297 | !check_gamma_bounds(attrs->gamma4, attrs->gamma5) || |
| 1234 | || !check_gamma_bounds(attrs->gamma5, 0x00ffffff)) | 1298 | !check_gamma_bounds(attrs->gamma5, 0x00ffffff)) |
| 1235 | return -EINVAL; | 1299 | return -EINVAL; |
| 1300 | |||
| 1236 | if (!check_gamma5_errata(attrs->gamma5)) | 1301 | if (!check_gamma5_errata(attrs->gamma5)) |
| 1237 | return -EINVAL; | 1302 | return -EINVAL; |
| 1303 | |||
| 1238 | return 0; | 1304 | return 0; |
| 1239 | } | 1305 | } |
| 1240 | 1306 | ||
| @@ -1261,13 +1327,14 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
| 1261 | mutex_lock(&dev->mode_config.mutex); | 1327 | mutex_lock(&dev->mode_config.mutex); |
| 1262 | mutex_lock(&dev->struct_mutex); | 1328 | mutex_lock(&dev->struct_mutex); |
| 1263 | 1329 | ||
| 1330 | ret = -EINVAL; | ||
| 1264 | if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { | 1331 | if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { |
| 1265 | attrs->color_key = overlay->color_key; | 1332 | attrs->color_key = overlay->color_key; |
| 1266 | attrs->brightness = overlay->brightness; | 1333 | attrs->brightness = overlay->brightness; |
| 1267 | attrs->contrast = overlay->contrast; | 1334 | attrs->contrast = overlay->contrast; |
| 1268 | attrs->saturation = overlay->saturation; | 1335 | attrs->saturation = overlay->saturation; |
| 1269 | 1336 | ||
| 1270 | if (IS_I9XX(dev)) { | 1337 | if (!IS_GEN2(dev)) { |
| 1271 | attrs->gamma0 = I915_READ(OGAMC0); | 1338 | attrs->gamma0 = I915_READ(OGAMC0); |
| 1272 | attrs->gamma1 = I915_READ(OGAMC1); | 1339 | attrs->gamma1 = I915_READ(OGAMC1); |
| 1273 | attrs->gamma2 = I915_READ(OGAMC2); | 1340 | attrs->gamma2 = I915_READ(OGAMC2); |
| @@ -1275,29 +1342,20 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
| 1275 | attrs->gamma4 = I915_READ(OGAMC4); | 1342 | attrs->gamma4 = I915_READ(OGAMC4); |
| 1276 | attrs->gamma5 = I915_READ(OGAMC5); | 1343 | attrs->gamma5 = I915_READ(OGAMC5); |
| 1277 | } | 1344 | } |
| 1278 | ret = 0; | ||
| 1279 | } else { | 1345 | } else { |
| 1280 | overlay->color_key = attrs->color_key; | 1346 | if (attrs->brightness < -128 || attrs->brightness > 127) |
| 1281 | if (attrs->brightness >= -128 && attrs->brightness <= 127) { | ||
| 1282 | overlay->brightness = attrs->brightness; | ||
| 1283 | } else { | ||
| 1284 | ret = -EINVAL; | ||
| 1285 | goto out_unlock; | 1347 | goto out_unlock; |
| 1286 | } | 1348 | if (attrs->contrast > 255) |
| 1287 | if (attrs->contrast <= 255) { | ||
| 1288 | overlay->contrast = attrs->contrast; | ||
| 1289 | } else { | ||
| 1290 | ret = -EINVAL; | ||
| 1291 | goto out_unlock; | 1349 | goto out_unlock; |
| 1292 | } | 1350 | if (attrs->saturation > 1023) |
| 1293 | if (attrs->saturation <= 1023) { | ||
| 1294 | overlay->saturation = attrs->saturation; | ||
| 1295 | } else { | ||
| 1296 | ret = -EINVAL; | ||
| 1297 | goto out_unlock; | 1351 | goto out_unlock; |
| 1298 | } | ||
| 1299 | 1352 | ||
| 1300 | regs = intel_overlay_map_regs_atomic(overlay); | 1353 | overlay->color_key = attrs->color_key; |
| 1354 | overlay->brightness = attrs->brightness; | ||
| 1355 | overlay->contrast = attrs->contrast; | ||
| 1356 | overlay->saturation = attrs->saturation; | ||
| 1357 | |||
| 1358 | regs = intel_overlay_map_regs(overlay); | ||
| 1301 | if (!regs) { | 1359 | if (!regs) { |
| 1302 | ret = -ENOMEM; | 1360 | ret = -ENOMEM; |
| 1303 | goto out_unlock; | 1361 | goto out_unlock; |
| @@ -1305,13 +1363,11 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
| 1305 | 1363 | ||
| 1306 | update_reg_attrs(overlay, regs); | 1364 | update_reg_attrs(overlay, regs); |
| 1307 | 1365 | ||
| 1308 | intel_overlay_unmap_regs_atomic(overlay); | 1366 | intel_overlay_unmap_regs(overlay, regs); |
| 1309 | 1367 | ||
| 1310 | if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { | 1368 | if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { |
| 1311 | if (!IS_I9XX(dev)) { | 1369 | if (IS_GEN2(dev)) |
| 1312 | ret = -EINVAL; | ||
| 1313 | goto out_unlock; | 1370 | goto out_unlock; |
| 1314 | } | ||
| 1315 | 1371 | ||
| 1316 | if (overlay->active) { | 1372 | if (overlay->active) { |
| 1317 | ret = -EBUSY; | 1373 | ret = -EBUSY; |
| @@ -1319,7 +1375,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
| 1319 | } | 1375 | } |
| 1320 | 1376 | ||
| 1321 | ret = check_gamma(attrs); | 1377 | ret = check_gamma(attrs); |
| 1322 | if (ret != 0) | 1378 | if (ret) |
| 1323 | goto out_unlock; | 1379 | goto out_unlock; |
| 1324 | 1380 | ||
| 1325 | I915_WRITE(OGAMC0, attrs->gamma0); | 1381 | I915_WRITE(OGAMC0, attrs->gamma0); |
| @@ -1329,9 +1385,9 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
| 1329 | I915_WRITE(OGAMC4, attrs->gamma4); | 1385 | I915_WRITE(OGAMC4, attrs->gamma4); |
| 1330 | I915_WRITE(OGAMC5, attrs->gamma5); | 1386 | I915_WRITE(OGAMC5, attrs->gamma5); |
| 1331 | } | 1387 | } |
| 1332 | ret = 0; | ||
| 1333 | } | 1388 | } |
| 1334 | 1389 | ||
| 1390 | ret = 0; | ||
| 1335 | out_unlock: | 1391 | out_unlock: |
| 1336 | mutex_unlock(&dev->struct_mutex); | 1392 | mutex_unlock(&dev->struct_mutex); |
| 1337 | mutex_unlock(&dev->mode_config.mutex); | 1393 | mutex_unlock(&dev->mode_config.mutex); |
| @@ -1343,39 +1399,50 @@ void intel_setup_overlay(struct drm_device *dev) | |||
| 1343 | { | 1399 | { |
| 1344 | drm_i915_private_t *dev_priv = dev->dev_private; | 1400 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 1345 | struct intel_overlay *overlay; | 1401 | struct intel_overlay *overlay; |
| 1346 | struct drm_gem_object *reg_bo; | 1402 | struct drm_i915_gem_object *reg_bo; |
| 1347 | struct overlay_registers *regs; | 1403 | struct overlay_registers *regs; |
| 1348 | int ret; | 1404 | int ret; |
| 1349 | 1405 | ||
| 1350 | if (!OVERLAY_EXISTS(dev)) | 1406 | if (!HAS_OVERLAY(dev)) |
| 1351 | return; | 1407 | return; |
| 1352 | 1408 | ||
| 1353 | overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL); | 1409 | overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL); |
| 1354 | if (!overlay) | 1410 | if (!overlay) |
| 1355 | return; | 1411 | return; |
| 1412 | |||
| 1413 | mutex_lock(&dev->struct_mutex); | ||
| 1414 | if (WARN_ON(dev_priv->overlay)) | ||
| 1415 | goto out_free; | ||
| 1416 | |||
| 1356 | overlay->dev = dev; | 1417 | overlay->dev = dev; |
| 1357 | 1418 | ||
| 1358 | reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE); | 1419 | reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE); |
| 1359 | if (!reg_bo) | 1420 | if (!reg_bo) |
| 1360 | goto out_free; | 1421 | goto out_free; |
| 1361 | overlay->reg_bo = to_intel_bo(reg_bo); | 1422 | overlay->reg_bo = reg_bo; |
| 1362 | 1423 | ||
| 1363 | if (OVERLAY_NONPHYSICAL(dev)) { | 1424 | if (OVERLAY_NEEDS_PHYSICAL(dev)) { |
| 1364 | ret = i915_gem_object_pin(reg_bo, PAGE_SIZE); | ||
| 1365 | if (ret) { | ||
| 1366 | DRM_ERROR("failed to pin overlay register bo\n"); | ||
| 1367 | goto out_free_bo; | ||
| 1368 | } | ||
| 1369 | overlay->flip_addr = overlay->reg_bo->gtt_offset; | ||
| 1370 | } else { | ||
| 1371 | ret = i915_gem_attach_phys_object(dev, reg_bo, | 1425 | ret = i915_gem_attach_phys_object(dev, reg_bo, |
| 1372 | I915_GEM_PHYS_OVERLAY_REGS, | 1426 | I915_GEM_PHYS_OVERLAY_REGS, |
| 1373 | 0); | 1427 | PAGE_SIZE); |
| 1374 | if (ret) { | 1428 | if (ret) { |
| 1375 | DRM_ERROR("failed to attach phys overlay regs\n"); | 1429 | DRM_ERROR("failed to attach phys overlay regs\n"); |
| 1376 | goto out_free_bo; | 1430 | goto out_free_bo; |
| 1377 | } | 1431 | } |
| 1378 | overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr; | 1432 | overlay->flip_addr = reg_bo->phys_obj->handle->busaddr; |
| 1433 | } else { | ||
| 1434 | ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true); | ||
| 1435 | if (ret) { | ||
| 1436 | DRM_ERROR("failed to pin overlay register bo\n"); | ||
| 1437 | goto out_free_bo; | ||
| 1438 | } | ||
| 1439 | overlay->flip_addr = reg_bo->gtt_offset; | ||
| 1440 | |||
| 1441 | ret = i915_gem_object_set_to_gtt_domain(reg_bo, true); | ||
| 1442 | if (ret) { | ||
| 1443 | DRM_ERROR("failed to move overlay register bo into the GTT\n"); | ||
| 1444 | goto out_unpin_bo; | ||
| 1445 | } | ||
| 1379 | } | 1446 | } |
| 1380 | 1447 | ||
| 1381 | /* init all values */ | 1448 | /* init all values */ |
| @@ -1384,42 +1451,51 @@ void intel_setup_overlay(struct drm_device *dev) | |||
| 1384 | overlay->contrast = 75; | 1451 | overlay->contrast = 75; |
| 1385 | overlay->saturation = 146; | 1452 | overlay->saturation = 146; |
| 1386 | 1453 | ||
| 1387 | regs = intel_overlay_map_regs_atomic(overlay); | 1454 | regs = intel_overlay_map_regs(overlay); |
| 1388 | if (!regs) | 1455 | if (!regs) |
| 1389 | goto out_free_bo; | 1456 | goto out_unpin_bo; |
| 1390 | 1457 | ||
| 1391 | memset(regs, 0, sizeof(struct overlay_registers)); | 1458 | memset(regs, 0, sizeof(struct overlay_registers)); |
| 1392 | update_polyphase_filter(regs); | 1459 | update_polyphase_filter(regs); |
| 1393 | |||
| 1394 | update_reg_attrs(overlay, regs); | 1460 | update_reg_attrs(overlay, regs); |
| 1395 | 1461 | ||
| 1396 | intel_overlay_unmap_regs_atomic(overlay); | 1462 | intel_overlay_unmap_regs(overlay, regs); |
| 1397 | 1463 | ||
| 1398 | dev_priv->overlay = overlay; | 1464 | dev_priv->overlay = overlay; |
| 1465 | mutex_unlock(&dev->struct_mutex); | ||
| 1399 | DRM_INFO("initialized overlay support\n"); | 1466 | DRM_INFO("initialized overlay support\n"); |
| 1400 | return; | 1467 | return; |
| 1401 | 1468 | ||
| 1469 | out_unpin_bo: | ||
| 1470 | if (!OVERLAY_NEEDS_PHYSICAL(dev)) | ||
| 1471 | i915_gem_object_unpin(reg_bo); | ||
| 1402 | out_free_bo: | 1472 | out_free_bo: |
| 1403 | drm_gem_object_unreference(reg_bo); | 1473 | drm_gem_object_unreference(®_bo->base); |
| 1404 | out_free: | 1474 | out_free: |
| 1475 | mutex_unlock(&dev->struct_mutex); | ||
| 1405 | kfree(overlay); | 1476 | kfree(overlay); |
| 1406 | return; | 1477 | return; |
| 1407 | } | 1478 | } |
| 1408 | 1479 | ||
| 1409 | void intel_cleanup_overlay(struct drm_device *dev) | 1480 | void intel_cleanup_overlay(struct drm_device *dev) |
| 1410 | { | 1481 | { |
| 1411 | drm_i915_private_t *dev_priv = dev->dev_private; | 1482 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 1412 | 1483 | ||
| 1413 | if (dev_priv->overlay) { | 1484 | if (!dev_priv->overlay) |
| 1414 | /* The bo's should be free'd by the generic code already. | 1485 | return; |
| 1415 | * Furthermore modesetting teardown happens beforehand so the | ||
| 1416 | * hardware should be off already */ | ||
| 1417 | BUG_ON(dev_priv->overlay->active); | ||
| 1418 | 1486 | ||
| 1419 | kfree(dev_priv->overlay); | 1487 | /* The bo's should be free'd by the generic code already. |
| 1420 | } | 1488 | * Furthermore modesetting teardown happens beforehand so the |
| 1489 | * hardware should be off already */ | ||
| 1490 | BUG_ON(dev_priv->overlay->active); | ||
| 1491 | |||
| 1492 | drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base); | ||
| 1493 | kfree(dev_priv->overlay); | ||
| 1421 | } | 1494 | } |
| 1422 | 1495 | ||
| 1496 | #ifdef CONFIG_DEBUG_FS | ||
| 1497 | #include <linux/seq_file.h> | ||
| 1498 | |||
| 1423 | struct intel_overlay_error_state { | 1499 | struct intel_overlay_error_state { |
| 1424 | struct overlay_registers regs; | 1500 | struct overlay_registers regs; |
| 1425 | unsigned long base; | 1501 | unsigned long base; |
| @@ -1427,6 +1503,29 @@ struct intel_overlay_error_state { | |||
| 1427 | u32 isr; | 1503 | u32 isr; |
| 1428 | }; | 1504 | }; |
| 1429 | 1505 | ||
| 1506 | static struct overlay_registers * | ||
| 1507 | intel_overlay_map_regs_atomic(struct intel_overlay *overlay) | ||
| 1508 | { | ||
| 1509 | drm_i915_private_t *dev_priv = overlay->dev->dev_private; | ||
| 1510 | struct overlay_registers *regs; | ||
| 1511 | |||
| 1512 | if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) | ||
| 1513 | regs = overlay->reg_bo->phys_obj->handle->vaddr; | ||
| 1514 | else | ||
| 1515 | regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, | ||
| 1516 | overlay->reg_bo->gtt_offset); | ||
| 1517 | |||
| 1518 | return regs; | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay, | ||
| 1522 | struct overlay_registers *regs) | ||
| 1523 | { | ||
| 1524 | if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) | ||
| 1525 | io_mapping_unmap_atomic(regs); | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | |||
| 1430 | struct intel_overlay_error_state * | 1529 | struct intel_overlay_error_state * |
| 1431 | intel_overlay_capture_error_state(struct drm_device *dev) | 1530 | intel_overlay_capture_error_state(struct drm_device *dev) |
| 1432 | { | 1531 | { |
| @@ -1444,17 +1543,17 @@ intel_overlay_capture_error_state(struct drm_device *dev) | |||
| 1444 | 1543 | ||
| 1445 | error->dovsta = I915_READ(DOVSTA); | 1544 | error->dovsta = I915_READ(DOVSTA); |
| 1446 | error->isr = I915_READ(ISR); | 1545 | error->isr = I915_READ(ISR); |
| 1447 | if (OVERLAY_NONPHYSICAL(overlay->dev)) | 1546 | if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) |
| 1448 | error->base = (long) overlay->reg_bo->gtt_offset; | ||
| 1449 | else | ||
| 1450 | error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr; | 1547 | error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr; |
| 1548 | else | ||
| 1549 | error->base = (long) overlay->reg_bo->gtt_offset; | ||
| 1451 | 1550 | ||
| 1452 | regs = intel_overlay_map_regs_atomic(overlay); | 1551 | regs = intel_overlay_map_regs_atomic(overlay); |
| 1453 | if (!regs) | 1552 | if (!regs) |
| 1454 | goto err; | 1553 | goto err; |
| 1455 | 1554 | ||
| 1456 | memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); | 1555 | memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); |
| 1457 | intel_overlay_unmap_regs_atomic(overlay); | 1556 | intel_overlay_unmap_regs_atomic(overlay, regs); |
| 1458 | 1557 | ||
| 1459 | return error; | 1558 | return error; |
| 1460 | 1559 | ||
| @@ -1515,3 +1614,4 @@ intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_s | |||
| 1515 | P(UVSCALEV); | 1614 | P(UVSCALEV); |
| 1516 | #undef P | 1615 | #undef P |
| 1517 | } | 1616 | } |
| 1617 | #endif | ||
