diff options
author | Ilia Mirkin <imirkin@alum.mit.edu> | 2013-11-15 11:26:45 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-01-22 22:38:28 -0500 |
commit | ab9b18a6a13c438505d3419bd59dcd8e1856cedd (patch) | |
tree | 517745d3d875fd0e4c460b813f2772b076e4a3e2 /drivers/gpu/drm/nouveau/dispnv04/overlay.c | |
parent | 7ffb078172d6906c4712914321c551d4f595875f (diff) |
drm/nv04/plane: add support for nv04/nv05 video overlay
Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/dispnv04/overlay.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv04/overlay.c | 176 |
1 files changed, 166 insertions, 10 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index ba40c7be3787..ab03f7719d2d 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c | |||
@@ -55,6 +55,8 @@ struct nouveau_plane { | |||
55 | int hue; | 55 | int hue; |
56 | int saturation; | 56 | int saturation; |
57 | int iturbt_709; | 57 | int iturbt_709; |
58 | |||
59 | void (*set_params)(struct nouveau_plane *); | ||
58 | }; | 60 | }; |
59 | 61 | ||
60 | static uint32_t formats[] = { | 62 | static uint32_t formats[] = { |
@@ -183,9 +185,9 @@ nv10_disable_plane(struct drm_plane *plane) | |||
183 | } | 185 | } |
184 | 186 | ||
185 | static void | 187 | static void |
186 | nv10_destroy_plane(struct drm_plane *plane) | 188 | nv_destroy_plane(struct drm_plane *plane) |
187 | { | 189 | { |
188 | nv10_disable_plane(plane); | 190 | plane->funcs->disable_plane(plane); |
189 | drm_plane_cleanup(plane); | 191 | drm_plane_cleanup(plane); |
190 | kfree(plane); | 192 | kfree(plane); |
191 | } | 193 | } |
@@ -218,9 +220,9 @@ nv10_set_params(struct nouveau_plane *plane) | |||
218 | } | 220 | } |
219 | 221 | ||
220 | static int | 222 | static int |
221 | nv10_set_property(struct drm_plane *plane, | 223 | nv_set_property(struct drm_plane *plane, |
222 | struct drm_property *property, | 224 | struct drm_property *property, |
223 | uint64_t value) | 225 | uint64_t value) |
224 | { | 226 | { |
225 | struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane; | 227 | struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane; |
226 | 228 | ||
@@ -239,15 +241,16 @@ nv10_set_property(struct drm_plane *plane, | |||
239 | else | 241 | else |
240 | return -EINVAL; | 242 | return -EINVAL; |
241 | 243 | ||
242 | nv10_set_params(nv_plane); | 244 | if (nv_plane->set_params) |
245 | nv_plane->set_params(nv_plane); | ||
243 | return 0; | 246 | return 0; |
244 | } | 247 | } |
245 | 248 | ||
246 | static const struct drm_plane_funcs nv10_plane_funcs = { | 249 | static const struct drm_plane_funcs nv10_plane_funcs = { |
247 | .update_plane = nv10_update_plane, | 250 | .update_plane = nv10_update_plane, |
248 | .disable_plane = nv10_disable_plane, | 251 | .disable_plane = nv10_disable_plane, |
249 | .set_property = nv10_set_property, | 252 | .set_property = nv_set_property, |
250 | .destroy = nv10_destroy_plane, | 253 | .destroy = nv_destroy_plane, |
251 | }; | 254 | }; |
252 | 255 | ||
253 | static void | 256 | static void |
@@ -322,8 +325,159 @@ nv10_overlay_init(struct drm_device *device) | |||
322 | drm_object_attach_property(&plane->base.base, | 325 | drm_object_attach_property(&plane->base.base, |
323 | plane->props.iturbt_709, plane->iturbt_709); | 326 | plane->props.iturbt_709, plane->iturbt_709); |
324 | 327 | ||
328 | plane->set_params = nv10_set_params; | ||
325 | nv10_set_params(plane); | 329 | nv10_set_params(plane); |
326 | nv_wr32(dev, NV_PVIDEO_STOP, 1); | 330 | nv10_disable_plane(&plane->base); |
331 | return; | ||
332 | cleanup: | ||
333 | drm_plane_cleanup(&plane->base); | ||
334 | err: | ||
335 | kfree(plane); | ||
336 | nv_error(dev, "Failed to create plane\n"); | ||
337 | } | ||
338 | |||
339 | static int | ||
340 | nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, | ||
341 | struct drm_framebuffer *fb, int crtc_x, int crtc_y, | ||
342 | unsigned int crtc_w, unsigned int crtc_h, | ||
343 | uint32_t src_x, uint32_t src_y, | ||
344 | uint32_t src_w, uint32_t src_h) | ||
345 | { | ||
346 | struct nouveau_device *dev = nouveau_dev(plane->dev); | ||
347 | struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane; | ||
348 | struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); | ||
349 | struct nouveau_bo *cur = nv_plane->cur; | ||
350 | uint32_t overlay = 1; | ||
351 | int brightness = (nv_plane->brightness - 512) * 62 / 512; | ||
352 | int pitch, ret, i; | ||
353 | |||
354 | /* Source parameters given in 16.16 fixed point, ignore fractional. */ | ||
355 | src_x >>= 16; | ||
356 | src_y >>= 16; | ||
357 | src_w >>= 16; | ||
358 | src_h >>= 16; | ||
359 | |||
360 | pitch = ALIGN(src_w * 4, 0x100); | ||
361 | |||
362 | if (pitch > 0xffff) | ||
363 | return -ERANGE; | ||
364 | |||
365 | /* TODO: Compute an offset? Not sure how to do this for YUYV. */ | ||
366 | if (src_x != 0 || src_y != 0) | ||
367 | return -ERANGE; | ||
368 | |||
369 | if (crtc_w < src_w || crtc_h < src_h) | ||
370 | return -ERANGE; | ||
371 | |||
372 | ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM); | ||
373 | if (ret) | ||
374 | return ret; | ||
375 | |||
376 | nv_plane->cur = nv_fb->nvbo; | ||
377 | |||
378 | nv_wr32(dev, NV_PVIDEO_OE_STATE, 0); | ||
379 | nv_wr32(dev, NV_PVIDEO_SU_STATE, 0); | ||
380 | nv_wr32(dev, NV_PVIDEO_RM_STATE, 0); | ||
381 | |||
382 | for (i = 0; i < 2; i++) { | ||
383 | nv_wr32(dev, NV_PVIDEO_BUFF0_START_ADDRESS + 4 * i, | ||
384 | nv_fb->nvbo->bo.offset); | ||
385 | nv_wr32(dev, NV_PVIDEO_BUFF0_PITCH_LENGTH + 4 * i, pitch); | ||
386 | nv_wr32(dev, NV_PVIDEO_BUFF0_OFFSET + 4 * i, 0); | ||
387 | } | ||
388 | nv_wr32(dev, NV_PVIDEO_WINDOW_START, crtc_y << 16 | crtc_x); | ||
389 | nv_wr32(dev, NV_PVIDEO_WINDOW_SIZE, crtc_h << 16 | crtc_w); | ||
390 | nv_wr32(dev, NV_PVIDEO_STEP_SIZE, | ||
391 | (uint32_t)(((src_h - 1) << 11) / (crtc_h - 1)) << 16 | (uint32_t)(((src_w - 1) << 11) / (crtc_w - 1))); | ||
392 | |||
393 | /* It should be possible to convert hue/contrast to this */ | ||
394 | nv_wr32(dev, NV_PVIDEO_RED_CSC_OFFSET, 0x69 - brightness); | ||
395 | nv_wr32(dev, NV_PVIDEO_GREEN_CSC_OFFSET, 0x3e + brightness); | ||
396 | nv_wr32(dev, NV_PVIDEO_BLUE_CSC_OFFSET, 0x89 - brightness); | ||
397 | nv_wr32(dev, NV_PVIDEO_CSC_ADJUST, 0); | ||
398 | |||
399 | nv_wr32(dev, NV_PVIDEO_CONTROL_Y, 0x001); /* (BLUR_ON, LINE_HALF) */ | ||
400 | nv_wr32(dev, NV_PVIDEO_CONTROL_X, 0x111); /* (WEIGHT_HEAVY, SHARPENING_ON, SMOOTHING_ON) */ | ||
401 | |||
402 | nv_wr32(dev, NV_PVIDEO_FIFO_BURST_LENGTH, 0x03); | ||
403 | nv_wr32(dev, NV_PVIDEO_FIFO_THRES_SIZE, 0x38); | ||
404 | |||
405 | nv_wr32(dev, NV_PVIDEO_KEY, nv_plane->colorkey); | ||
406 | |||
407 | if (nv_plane->colorkey & (1 << 24)) | ||
408 | overlay |= 0x10; | ||
409 | if (fb->pixel_format == DRM_FORMAT_YUYV) | ||
410 | overlay |= 0x100; | ||
411 | |||
412 | nv_wr32(dev, NV_PVIDEO_OVERLAY, overlay); | ||
413 | |||
414 | nv_wr32(dev, NV_PVIDEO_SU_STATE, nv_rd32(dev, NV_PVIDEO_SU_STATE) ^ (1 << 16)); | ||
415 | |||
416 | if (cur) | ||
417 | nouveau_bo_unpin(cur); | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static int | ||
423 | nv04_disable_plane(struct drm_plane *plane) | ||
424 | { | ||
425 | struct nouveau_device *dev = nouveau_dev(plane->dev); | ||
426 | struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane; | ||
427 | |||
428 | nv_mask(dev, NV_PVIDEO_OVERLAY, 1, 0); | ||
429 | nv_wr32(dev, NV_PVIDEO_OE_STATE, 0); | ||
430 | nv_wr32(dev, NV_PVIDEO_SU_STATE, 0); | ||
431 | nv_wr32(dev, NV_PVIDEO_RM_STATE, 0); | ||
432 | if (nv_plane->cur) { | ||
433 | nouveau_bo_unpin(nv_plane->cur); | ||
434 | nv_plane->cur = NULL; | ||
435 | } | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static const struct drm_plane_funcs nv04_plane_funcs = { | ||
441 | .update_plane = nv04_update_plane, | ||
442 | .disable_plane = nv04_disable_plane, | ||
443 | .set_property = nv_set_property, | ||
444 | .destroy = nv_destroy_plane, | ||
445 | }; | ||
446 | |||
447 | static void | ||
448 | nv04_overlay_init(struct drm_device *device) | ||
449 | { | ||
450 | struct nouveau_device *dev = nouveau_dev(device); | ||
451 | struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL); | ||
452 | int ret; | ||
453 | |||
454 | if (!plane) | ||
455 | return; | ||
456 | |||
457 | ret = drm_plane_init(device, &plane->base, 1 /* single crtc */, | ||
458 | &nv04_plane_funcs, | ||
459 | formats, 2, false); | ||
460 | if (ret) | ||
461 | goto err; | ||
462 | |||
463 | /* Set up the plane properties */ | ||
464 | plane->props.colorkey = drm_property_create_range( | ||
465 | device, 0, "colorkey", 0, 0x01ffffff); | ||
466 | plane->props.brightness = drm_property_create_range( | ||
467 | device, 0, "brightness", 0, 1024); | ||
468 | if (!plane->props.colorkey || | ||
469 | !plane->props.brightness) | ||
470 | goto cleanup; | ||
471 | |||
472 | plane->colorkey = 0; | ||
473 | drm_object_attach_property(&plane->base.base, | ||
474 | plane->props.colorkey, plane->colorkey); | ||
475 | |||
476 | plane->brightness = 512; | ||
477 | drm_object_attach_property(&plane->base.base, | ||
478 | plane->props.brightness, plane->brightness); | ||
479 | |||
480 | nv04_disable_plane(&plane->base); | ||
327 | return; | 481 | return; |
328 | cleanup: | 482 | cleanup: |
329 | drm_plane_cleanup(&plane->base); | 483 | drm_plane_cleanup(&plane->base); |
@@ -336,6 +490,8 @@ void | |||
336 | nouveau_overlay_init(struct drm_device *device) | 490 | nouveau_overlay_init(struct drm_device *device) |
337 | { | 491 | { |
338 | struct nouveau_device *dev = nouveau_dev(device); | 492 | struct nouveau_device *dev = nouveau_dev(device); |
339 | if (dev->chipset >= 0x10 && dev->chipset <= 0x40) | 493 | if (dev->chipset < 0x10) |
494 | nv04_overlay_init(device); | ||
495 | else if (dev->chipset <= 0x40) | ||
340 | nv10_overlay_init(device); | 496 | nv10_overlay_init(device); |
341 | } | 497 | } |