aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/dispnv04/overlay.c
diff options
context:
space:
mode:
authorIlia Mirkin <imirkin@alum.mit.edu>2013-11-15 11:26:45 -0500
committerBen Skeggs <bskeggs@redhat.com>2014-01-22 22:38:28 -0500
commitab9b18a6a13c438505d3419bd59dcd8e1856cedd (patch)
tree517745d3d875fd0e4c460b813f2772b076e4a3e2 /drivers/gpu/drm/nouveau/dispnv04/overlay.c
parent7ffb078172d6906c4712914321c551d4f595875f (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.c176
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
60static uint32_t formats[] = { 62static uint32_t formats[] = {
@@ -183,9 +185,9 @@ nv10_disable_plane(struct drm_plane *plane)
183} 185}
184 186
185static void 187static void
186nv10_destroy_plane(struct drm_plane *plane) 188nv_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
220static int 222static int
221nv10_set_property(struct drm_plane *plane, 223nv_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
246static const struct drm_plane_funcs nv10_plane_funcs = { 249static 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
253static void 256static 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;
332cleanup:
333 drm_plane_cleanup(&plane->base);
334err:
335 kfree(plane);
336 nv_error(dev, "Failed to create plane\n");
337}
338
339static int
340nv04_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
422static int
423nv04_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
440static 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
447static void
448nv04_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;
328cleanup: 482cleanup:
329 drm_plane_cleanup(&plane->base); 483 drm_plane_cleanup(&plane->base);
@@ -336,6 +490,8 @@ void
336nouveau_overlay_init(struct drm_device *device) 490nouveau_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}