aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBeeresh Gopal <gbeeresh@codeaurora.org>2015-01-13 17:18:04 -0500
committerRob Clark <robdclark@gmail.com>2015-02-01 15:32:46 -0500
commite172d10a9c4acc69bb07cbe9142ded2df791ff1f (patch)
tree6e3e0a70cc54b875128b834064f100d451542973
parent5eba5d870f7234ecd25ec704dcfeb743c402dbe1 (diff)
drm/msm/mdp5: Add hardware cursor support
This patch implements the hardware accelarated cursor support for MDP5 platforms. Signed-off-by: Beeresh Gopal <gbeeresh@codeaurora.org> Signed-off-by: Wentao Xu <wentaox@codeaurora.org> Signed-off-by: Stephane Viau <sviau@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 7416cae60479..46fac545dc2b 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -24,6 +24,9 @@
24#include "drm_crtc_helper.h" 24#include "drm_crtc_helper.h"
25#include "drm_flip_work.h" 25#include "drm_flip_work.h"
26 26
27#define CURSOR_WIDTH 64
28#define CURSOR_HEIGHT 64
29
27#define SSPP_MAX (SSPP_RGB3 + 1) /* TODO: Add SSPP_MAX in mdp5.xml.h */ 30#define SSPP_MAX (SSPP_RGB3 + 1) /* TODO: Add SSPP_MAX in mdp5.xml.h */
28 31
29struct mdp5_crtc { 32struct mdp5_crtc {
@@ -47,8 +50,21 @@ struct mdp5_crtc {
47#define PENDING_FLIP 0x2 50#define PENDING_FLIP 0x2
48 atomic_t pending; 51 atomic_t pending;
49 52
53 /* for unref'ing cursor bo's after scanout completes: */
54 struct drm_flip_work unref_cursor_work;
55
50 struct mdp_irq vblank; 56 struct mdp_irq vblank;
51 struct mdp_irq err; 57 struct mdp_irq err;
58
59 struct {
60 /* protect REG_MDP5_LM_CURSOR* registers and cursor scanout_bo*/
61 spinlock_t lock;
62
63 /* current cursor being scanned out: */
64 struct drm_gem_object *scanout_bo;
65 uint32_t width;
66 uint32_t height;
67 } cursor;
52}; 68};
53#define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base) 69#define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base)
54 70
@@ -129,11 +145,22 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
129 } 145 }
130} 146}
131 147
148static void unref_cursor_worker(struct drm_flip_work *work, void *val)
149{
150 struct mdp5_crtc *mdp5_crtc =
151 container_of(work, struct mdp5_crtc, unref_cursor_work);
152 struct mdp5_kms *mdp5_kms = get_kms(&mdp5_crtc->base);
153
154 msm_gem_put_iova(val, mdp5_kms->id);
155 drm_gem_object_unreference_unlocked(val);
156}
157
132static void mdp5_crtc_destroy(struct drm_crtc *crtc) 158static void mdp5_crtc_destroy(struct drm_crtc *crtc)
133{ 159{
134 struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); 160 struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
135 161
136 drm_crtc_cleanup(crtc); 162 drm_crtc_cleanup(crtc);
163 drm_flip_work_cleanup(&mdp5_crtc->unref_cursor_work);
137 164
138 kfree(mdp5_crtc); 165 kfree(mdp5_crtc);
139} 166}
@@ -376,6 +403,132 @@ static int mdp5_crtc_set_property(struct drm_crtc *crtc,
376 return -EINVAL; 403 return -EINVAL;
377} 404}
378 405
406static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
407 struct drm_file *file, uint32_t handle,
408 uint32_t width, uint32_t height)
409{
410 struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
411 struct drm_device *dev = crtc->dev;
412 struct mdp5_kms *mdp5_kms = get_kms(crtc);
413 struct drm_gem_object *cursor_bo, *old_bo;
414 uint32_t blendcfg, cursor_addr, stride;
415 int ret, bpp, lm;
416 unsigned int depth;
417 enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
418 uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
419 unsigned long flags;
420
421 if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
422 dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height);
423 return -EINVAL;
424 }
425
426 if (NULL == mdp5_crtc->ctl)
427 return -EINVAL;
428
429 if (!handle) {
430 DBG("Cursor off");
431 return mdp5_ctl_set_cursor(mdp5_crtc->ctl, false);
432 }
433
434 cursor_bo = drm_gem_object_lookup(dev, file, handle);
435 if (!cursor_bo)
436 return -ENOENT;
437
438 ret = msm_gem_get_iova(cursor_bo, mdp5_kms->id, &cursor_addr);
439 if (ret)
440 return -EINVAL;
441
442 lm = mdp5_crtc->lm;
443 drm_fb_get_bpp_depth(DRM_FORMAT_ARGB8888, &depth, &bpp);
444 stride = width * (bpp >> 3);
445
446 spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
447 old_bo = mdp5_crtc->cursor.scanout_bo;
448
449 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride);
450 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm),
451 MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888));
452 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_IMG_SIZE(lm),
453 MDP5_LM_CURSOR_IMG_SIZE_SRC_H(height) |
454 MDP5_LM_CURSOR_IMG_SIZE_SRC_W(width));
455 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
456 MDP5_LM_CURSOR_SIZE_ROI_H(height) |
457 MDP5_LM_CURSOR_SIZE_ROI_W(width));
458 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm), cursor_addr);
459
460
461 blendcfg = MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN;
462 blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_TRANSP_EN;
463 blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(cur_alpha);
464 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BLEND_CONFIG(lm), blendcfg);
465
466 mdp5_crtc->cursor.scanout_bo = cursor_bo;
467 mdp5_crtc->cursor.width = width;
468 mdp5_crtc->cursor.height = height;
469 spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
470
471 ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true);
472 if (ret)
473 goto end;
474
475 flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
476 crtc_flush(crtc, flush_mask);
477
478end:
479 if (old_bo) {
480 drm_flip_work_queue(&mdp5_crtc->unref_cursor_work, old_bo);
481 /* enable vblank to complete cursor work: */
482 request_pending(crtc, PENDING_CURSOR);
483 }
484 return ret;
485}
486
487static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
488{
489 struct mdp5_kms *mdp5_kms = get_kms(crtc);
490 struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
491 uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
492 uint32_t xres = crtc->mode.hdisplay;
493 uint32_t yres = crtc->mode.vdisplay;
494 uint32_t roi_w;
495 uint32_t roi_h;
496 unsigned long flags;
497
498 x = (x > 0) ? x : 0;
499 y = (y > 0) ? y : 0;
500
501 /*
502 * Cursor Region Of Interest (ROI) is a plane read from cursor
503 * buffer to render. The ROI region is determined by the visiblity of
504 * the cursor point. In the default Cursor image the cursor point will
505 * be at the top left of the cursor image, unless it is specified
506 * otherwise using hotspot feature.
507 *
508 * If the cursor point reaches the right (xres - x < cursor.width) or
509 * bottom (yres - y < cursor.height) boundary of the screen, then ROI
510 * width and ROI height need to be evaluated to crop the cursor image
511 * accordingly.
512 * (xres-x) will be new cursor width when x > (xres - cursor.width)
513 * (yres-y) will be new cursor height when y > (yres - cursor.height)
514 */
515 roi_w = min(mdp5_crtc->cursor.width, xres - x);
516 roi_h = min(mdp5_crtc->cursor.height, yres - y);
517
518 spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
519 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(mdp5_crtc->lm),
520 MDP5_LM_CURSOR_SIZE_ROI_H(roi_h) |
521 MDP5_LM_CURSOR_SIZE_ROI_W(roi_w));
522 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_START_XY(mdp5_crtc->lm),
523 MDP5_LM_CURSOR_START_XY_Y_START(y) |
524 MDP5_LM_CURSOR_START_XY_X_START(x));
525 spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
526
527 crtc_flush(crtc, flush_mask);
528
529 return 0;
530}
531
379static const struct drm_crtc_funcs mdp5_crtc_funcs = { 532static const struct drm_crtc_funcs mdp5_crtc_funcs = {
380 .set_config = drm_atomic_helper_set_config, 533 .set_config = drm_atomic_helper_set_config,
381 .destroy = mdp5_crtc_destroy, 534 .destroy = mdp5_crtc_destroy,
@@ -384,6 +537,8 @@ static const struct drm_crtc_funcs mdp5_crtc_funcs = {
384 .reset = drm_atomic_helper_crtc_reset, 537 .reset = drm_atomic_helper_crtc_reset,
385 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 538 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
386 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 539 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
540 .cursor_set = mdp5_crtc_cursor_set,
541 .cursor_move = mdp5_crtc_cursor_move,
387}; 542};
388 543
389static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = { 544static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
@@ -400,6 +555,7 @@ static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
400{ 555{
401 struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, vblank); 556 struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, vblank);
402 struct drm_crtc *crtc = &mdp5_crtc->base; 557 struct drm_crtc *crtc = &mdp5_crtc->base;
558 struct msm_drm_private *priv = crtc->dev->dev_private;
403 unsigned pending; 559 unsigned pending;
404 560
405 mdp_irq_unregister(&get_kms(crtc)->base, &mdp5_crtc->vblank); 561 mdp_irq_unregister(&get_kms(crtc)->base, &mdp5_crtc->vblank);
@@ -409,6 +565,9 @@ static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
409 if (pending & PENDING_FLIP) { 565 if (pending & PENDING_FLIP) {
410 complete_flip(crtc, NULL); 566 complete_flip(crtc, NULL);
411 } 567 }
568
569 if (pending & PENDING_CURSOR)
570 drm_flip_work_commit(&mdp5_crtc->unref_cursor_work, priv->wq);
412} 571}
413 572
414static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus) 573static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
@@ -508,6 +667,7 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
508 mdp5_crtc->lm = GET_LM_ID(id); 667 mdp5_crtc->lm = GET_LM_ID(id);
509 668
510 spin_lock_init(&mdp5_crtc->lm_lock); 669 spin_lock_init(&mdp5_crtc->lm_lock);
670 spin_lock_init(&mdp5_crtc->cursor.lock);
511 671
512 mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq; 672 mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq;
513 mdp5_crtc->err.irq = mdp5_crtc_err_irq; 673 mdp5_crtc->err.irq = mdp5_crtc_err_irq;
@@ -516,6 +676,10 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
516 pipe2name(mdp5_plane_pipe(plane)), id); 676 pipe2name(mdp5_plane_pipe(plane)), id);
517 677
518 drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs); 678 drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs);
679
680 drm_flip_work_init(&mdp5_crtc->unref_cursor_work,
681 "unref cursor", unref_cursor_worker);
682
519 drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs); 683 drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
520 plane->crtc = crtc; 684 plane->crtc = crtc;
521 685