aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2015-08-30 20:25:45 -0400
committerDave Airlie <airlied@redhat.com>2015-08-30 20:25:45 -0400
commit879a37d00f1882b1e56a66e626af4194d592d257 (patch)
tree94400b07a9d12d4a672097eab494085a5476adfe /drivers/gpu/drm
parent701078d538e5b2bec95cbbc53cca71c120cd063f (diff)
parent50002d4c2176da6b2ed5a2529a2367c05f0fd73b (diff)
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
This is a second pull-request which adds last part of atomic modeset/pageflip support, render node support, clean-up, and fix-up. * 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: drm/exynos: fix build warning to exynos_drm_gem.c drm/exynos: Properly report supported formats for each device drm/exynos: add render node support drm/exynos: implement atomic_{begin/flush} of DECON drm/exynos: remove legacy ->suspend()/resume() drm/exynos: Enable atomic modesetting feature drm/exynos: remove wait queue for pending page flip drm/exynos: wait all planes updates to finish drm/exynos: add atomic asynchronous commit drm/exynos: fimd: only finish update if START == START_S drm/exynos: add macro to get the address of START_S reg drm/exynos: check for pending fb before finish update drm/exynos: fimd: move window protect code to prepare/cleanup_plane drm/exynos: add prepare and cleanup phases for planes drm/exynos: fimd: unify call to exynos_drm_crtc_finish_pageflip() drm/exynos: don't track enabled state at exynos_crtc
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c54
-rw-r--r--drivers/gpu/drm/exynos/exynos7_drm_decon.c55
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c69
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.h4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c196
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h24
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c35
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c92
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c13
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.h1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c19
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c40
13 files changed, 451 insertions, 153 deletions
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
index 484e312e0a22..b3c730770b0f 100644
--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -54,6 +54,13 @@ static const char * const decon_clks_name[] = {
54 "sclk_decon_eclk", 54 "sclk_decon_eclk",
55}; 55};
56 56
57static const uint32_t decon_formats[] = {
58 DRM_FORMAT_XRGB1555,
59 DRM_FORMAT_RGB565,
60 DRM_FORMAT_XRGB8888,
61 DRM_FORMAT_ARGB8888,
62};
63
57static int decon_enable_vblank(struct exynos_drm_crtc *crtc) 64static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
58{ 65{
59 struct decon_context *ctx = crtc->ctx; 66 struct decon_context *ctx = crtc->ctx;
@@ -219,6 +226,17 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win,
219 writel(val, ctx->addr + DECON_SHADOWCON); 226 writel(val, ctx->addr + DECON_SHADOWCON);
220} 227}
221 228
229static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
230 struct exynos_drm_plane *plane)
231{
232 struct decon_context *ctx = crtc->ctx;
233
234 if (ctx->suspended)
235 return;
236
237 decon_shadow_protect_win(ctx, plane->zpos, true);
238}
239
222static void decon_update_plane(struct exynos_drm_crtc *crtc, 240static void decon_update_plane(struct exynos_drm_crtc *crtc,
223 struct exynos_drm_plane *plane) 241 struct exynos_drm_plane *plane)
224{ 242{
@@ -232,8 +250,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
232 if (ctx->suspended) 250 if (ctx->suspended)
233 return; 251 return;
234 252
235 decon_shadow_protect_win(ctx, win, true);
236
237 val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); 253 val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y);
238 writel(val, ctx->addr + DECON_VIDOSDxA(win)); 254 writel(val, ctx->addr + DECON_VIDOSDxA(win));
239 255
@@ -265,15 +281,10 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
265 val |= WINCONx_ENWIN_F; 281 val |= WINCONx_ENWIN_F;
266 writel(val, ctx->addr + DECON_WINCONx(win)); 282 writel(val, ctx->addr + DECON_WINCONx(win));
267 283
268 decon_shadow_protect_win(ctx, win, false);
269
270 /* standalone update */ 284 /* standalone update */
271 val = readl(ctx->addr + DECON_UPDATE); 285 val = readl(ctx->addr + DECON_UPDATE);
272 val |= STANDALONE_UPDATE_F; 286 val |= STANDALONE_UPDATE_F;
273 writel(val, ctx->addr + DECON_UPDATE); 287 writel(val, ctx->addr + DECON_UPDATE);
274
275 if (ctx->i80_if)
276 atomic_set(&ctx->win_updated, 1);
277} 288}
278 289
279static void decon_disable_plane(struct exynos_drm_crtc *crtc, 290static void decon_disable_plane(struct exynos_drm_crtc *crtc,
@@ -301,6 +312,20 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
301 writel(val, ctx->addr + DECON_UPDATE); 312 writel(val, ctx->addr + DECON_UPDATE);
302} 313}
303 314
315static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
316 struct exynos_drm_plane *plane)
317{
318 struct decon_context *ctx = crtc->ctx;
319
320 if (ctx->suspended)
321 return;
322
323 decon_shadow_protect_win(ctx, plane->zpos, false);
324
325 if (ctx->i80_if)
326 atomic_set(&ctx->win_updated, 1);
327}
328
304static void decon_swreset(struct decon_context *ctx) 329static void decon_swreset(struct decon_context *ctx)
305{ 330{
306 unsigned int tries; 331 unsigned int tries;
@@ -455,8 +480,10 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = {
455 .enable_vblank = decon_enable_vblank, 480 .enable_vblank = decon_enable_vblank,
456 .disable_vblank = decon_disable_vblank, 481 .disable_vblank = decon_disable_vblank,
457 .commit = decon_commit, 482 .commit = decon_commit,
483 .atomic_begin = decon_atomic_begin,
458 .update_plane = decon_update_plane, 484 .update_plane = decon_update_plane,
459 .disable_plane = decon_disable_plane, 485 .disable_plane = decon_disable_plane,
486 .atomic_flush = decon_atomic_flush,
460 .te_handler = decon_te_irq_handler, 487 .te_handler = decon_te_irq_handler,
461}; 488};
462 489
@@ -477,7 +504,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
477 type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : 504 type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
478 DRM_PLANE_TYPE_OVERLAY; 505 DRM_PLANE_TYPE_OVERLAY;
479 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 506 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
480 1 << ctx->pipe, type, zpos); 507 1 << ctx->pipe, type, decon_formats,
508 ARRAY_SIZE(decon_formats), zpos);
481 if (ret) 509 if (ret)
482 return ret; 510 return ret;
483 } 511 }
@@ -542,13 +570,21 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
542{ 570{
543 struct decon_context *ctx = dev_id; 571 struct decon_context *ctx = dev_id;
544 u32 val; 572 u32 val;
573 int win;
545 574
546 if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled)) 575 if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
547 goto out; 576 goto out;
548 577
549 val = readl(ctx->addr + DECON_VIDINTCON1); 578 val = readl(ctx->addr + DECON_VIDINTCON1);
550 if (val & VIDINTCON1_INTFRMDONEPEND) { 579 if (val & VIDINTCON1_INTFRMDONEPEND) {
551 exynos_drm_crtc_finish_pageflip(ctx->crtc); 580 for (win = 0 ; win < WINDOWS_NR ; win++) {
581 struct exynos_drm_plane *plane = &ctx->planes[win];
582
583 if (!plane->pending_fb)
584 continue;
585
586 exynos_drm_crtc_finish_update(ctx->crtc, plane);
587 }
552 588
553 /* clear */ 589 /* clear */
554 writel(VIDINTCON1_INTFRMDONEPEND, 590 writel(VIDINTCON1_INTFRMDONEPEND,
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
index 07926547c94f..cbdb78ef3bac 100644
--- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -70,6 +70,18 @@ static const struct of_device_id decon_driver_dt_match[] = {
70}; 70};
71MODULE_DEVICE_TABLE(of, decon_driver_dt_match); 71MODULE_DEVICE_TABLE(of, decon_driver_dt_match);
72 72
73static const uint32_t decon_formats[] = {
74 DRM_FORMAT_RGB565,
75 DRM_FORMAT_XRGB8888,
76 DRM_FORMAT_XBGR8888,
77 DRM_FORMAT_RGBX8888,
78 DRM_FORMAT_BGRX8888,
79 DRM_FORMAT_ARGB8888,
80 DRM_FORMAT_ABGR8888,
81 DRM_FORMAT_RGBA8888,
82 DRM_FORMAT_BGRA8888,
83};
84
73static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc) 85static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc)
74{ 86{
75 struct decon_context *ctx = crtc->ctx; 87 struct decon_context *ctx = crtc->ctx;
@@ -383,6 +395,17 @@ static void decon_shadow_protect_win(struct decon_context *ctx,
383 writel(val, ctx->regs + SHADOWCON); 395 writel(val, ctx->regs + SHADOWCON);
384} 396}
385 397
398static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
399 struct exynos_drm_plane *plane)
400{
401 struct decon_context *ctx = crtc->ctx;
402
403 if (ctx->suspended)
404 return;
405
406 decon_shadow_protect_win(ctx, plane->zpos, true);
407}
408
386static void decon_update_plane(struct exynos_drm_crtc *crtc, 409static void decon_update_plane(struct exynos_drm_crtc *crtc,
387 struct exynos_drm_plane *plane) 410 struct exynos_drm_plane *plane)
388{ 411{
@@ -410,9 +433,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
410 * is set. 433 * is set.
411 */ 434 */
412 435
413 /* protect windows */
414 decon_shadow_protect_win(ctx, win, true);
415
416 /* buffer start address */ 436 /* buffer start address */
417 val = (unsigned long)plane->dma_addr[0]; 437 val = (unsigned long)plane->dma_addr[0];
418 writel(val, ctx->regs + VIDW_BUF_START(win)); 438 writel(val, ctx->regs + VIDW_BUF_START(win));
@@ -510,14 +530,22 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
510 val &= ~WINCONx_ENWIN; 530 val &= ~WINCONx_ENWIN;
511 writel(val, ctx->regs + WINCON(win)); 531 writel(val, ctx->regs + WINCON(win));
512 532
513 /* unprotect windows */
514 decon_shadow_protect_win(ctx, win, false);
515
516 val = readl(ctx->regs + DECON_UPDATE); 533 val = readl(ctx->regs + DECON_UPDATE);
517 val |= DECON_UPDATE_STANDALONE_F; 534 val |= DECON_UPDATE_STANDALONE_F;
518 writel(val, ctx->regs + DECON_UPDATE); 535 writel(val, ctx->regs + DECON_UPDATE);
519} 536}
520 537
538static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
539 struct exynos_drm_plane *plane)
540{
541 struct decon_context *ctx = crtc->ctx;
542
543 if (ctx->suspended)
544 return;
545
546 decon_shadow_protect_win(ctx, plane->zpos, false);
547}
548
521static void decon_init(struct decon_context *ctx) 549static void decon_init(struct decon_context *ctx)
522{ 550{
523 u32 val; 551 u32 val;
@@ -614,8 +642,10 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = {
614 .enable_vblank = decon_enable_vblank, 642 .enable_vblank = decon_enable_vblank,
615 .disable_vblank = decon_disable_vblank, 643 .disable_vblank = decon_disable_vblank,
616 .wait_for_vblank = decon_wait_for_vblank, 644 .wait_for_vblank = decon_wait_for_vblank,
645 .atomic_begin = decon_atomic_begin,
617 .update_plane = decon_update_plane, 646 .update_plane = decon_update_plane,
618 .disable_plane = decon_disable_plane, 647 .disable_plane = decon_disable_plane,
648 .atomic_flush = decon_atomic_flush,
619}; 649};
620 650
621 651
@@ -623,6 +653,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
623{ 653{
624 struct decon_context *ctx = (struct decon_context *)dev_id; 654 struct decon_context *ctx = (struct decon_context *)dev_id;
625 u32 val, clear_bit; 655 u32 val, clear_bit;
656 int win;
626 657
627 val = readl(ctx->regs + VIDINTCON1); 658 val = readl(ctx->regs + VIDINTCON1);
628 659
@@ -636,7 +667,14 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
636 667
637 if (!ctx->i80_if) { 668 if (!ctx->i80_if) {
638 drm_crtc_handle_vblank(&ctx->crtc->base); 669 drm_crtc_handle_vblank(&ctx->crtc->base);
639 exynos_drm_crtc_finish_pageflip(ctx->crtc); 670 for (win = 0 ; win < WINDOWS_NR ; win++) {
671 struct exynos_drm_plane *plane = &ctx->planes[win];
672
673 if (!plane->pending_fb)
674 continue;
675
676 exynos_drm_crtc_finish_update(ctx->crtc, plane);
677 }
640 678
641 /* set wait vsync event to zero and wake up queue. */ 679 /* set wait vsync event to zero and wake up queue. */
642 if (atomic_read(&ctx->wait_vsync_event)) { 680 if (atomic_read(&ctx->wait_vsync_event)) {
@@ -667,7 +705,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
667 type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : 705 type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
668 DRM_PLANE_TYPE_OVERLAY; 706 DRM_PLANE_TYPE_OVERLAY;
669 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 707 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
670 1 << ctx->pipe, type, zpos); 708 1 << ctx->pipe, type, decon_formats,
709 ARRAY_SIZE(decon_formats), zpos);
671 if (ret) 710 if (ret)
672 return ret; 711 return ret;
673 } 712 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index c47899738eb4..0872aa2f450f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -25,14 +25,9 @@ static void exynos_drm_crtc_enable(struct drm_crtc *crtc)
25{ 25{
26 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 26 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
27 27
28 if (exynos_crtc->enabled)
29 return;
30
31 if (exynos_crtc->ops->enable) 28 if (exynos_crtc->ops->enable)
32 exynos_crtc->ops->enable(exynos_crtc); 29 exynos_crtc->ops->enable(exynos_crtc);
33 30
34 exynos_crtc->enabled = true;
35
36 drm_crtc_vblank_on(crtc); 31 drm_crtc_vblank_on(crtc);
37} 32}
38 33
@@ -40,20 +35,10 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
40{ 35{
41 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 36 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
42 37
43 if (!exynos_crtc->enabled)
44 return;
45
46 /* wait for the completion of page flip. */
47 if (!wait_event_timeout(exynos_crtc->pending_flip_queue,
48 (exynos_crtc->event == NULL), HZ/20))
49 exynos_crtc->event = NULL;
50
51 drm_crtc_vblank_off(crtc); 38 drm_crtc_vblank_off(crtc);
52 39
53 if (exynos_crtc->ops->disable) 40 if (exynos_crtc->ops->disable)
54 exynos_crtc->ops->disable(exynos_crtc); 41 exynos_crtc->ops->disable(exynos_crtc);
55
56 exynos_crtc->enabled = false;
57} 42}
58 43
59static bool 44static bool
@@ -83,16 +68,32 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
83 struct drm_crtc_state *old_crtc_state) 68 struct drm_crtc_state *old_crtc_state)
84{ 69{
85 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 70 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
71 struct drm_plane *plane;
72
73 exynos_crtc->event = crtc->state->event;
86 74
87 if (crtc->state->event) { 75 drm_atomic_crtc_for_each_plane(plane, crtc) {
88 WARN_ON(drm_crtc_vblank_get(crtc) != 0); 76 struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
89 exynos_crtc->event = crtc->state->event; 77
78 if (exynos_crtc->ops->atomic_begin)
79 exynos_crtc->ops->atomic_begin(exynos_crtc,
80 exynos_plane);
90 } 81 }
91} 82}
92 83
93static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, 84static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
94 struct drm_crtc_state *old_crtc_state) 85 struct drm_crtc_state *old_crtc_state)
95{ 86{
87 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
88 struct drm_plane *plane;
89
90 drm_atomic_crtc_for_each_plane(plane, crtc) {
91 struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
92
93 if (exynos_crtc->ops->atomic_flush)
94 exynos_crtc->ops->atomic_flush(exynos_crtc,
95 exynos_plane);
96 }
96} 97}
97 98
98static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { 99static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
@@ -140,13 +141,13 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
140 if (!exynos_crtc) 141 if (!exynos_crtc)
141 return ERR_PTR(-ENOMEM); 142 return ERR_PTR(-ENOMEM);
142 143
143 init_waitqueue_head(&exynos_crtc->pending_flip_queue);
144
145 exynos_crtc->pipe = pipe; 144 exynos_crtc->pipe = pipe;
146 exynos_crtc->type = type; 145 exynos_crtc->type = type;
147 exynos_crtc->ops = ops; 146 exynos_crtc->ops = ops;
148 exynos_crtc->ctx = ctx; 147 exynos_crtc->ctx = ctx;
149 148
149 init_waitqueue_head(&exynos_crtc->wait_update);
150
150 crtc = &exynos_crtc->base; 151 crtc = &exynos_crtc->base;
151 152
152 private->crtc[pipe] = crtc; 153 private->crtc[pipe] = crtc;
@@ -172,9 +173,6 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
172 struct exynos_drm_crtc *exynos_crtc = 173 struct exynos_drm_crtc *exynos_crtc =
173 to_exynos_crtc(private->crtc[pipe]); 174 to_exynos_crtc(private->crtc[pipe]);
174 175
175 if (!exynos_crtc->enabled)
176 return -EPERM;
177
178 if (exynos_crtc->ops->enable_vblank) 176 if (exynos_crtc->ops->enable_vblank)
179 return exynos_crtc->ops->enable_vblank(exynos_crtc); 177 return exynos_crtc->ops->enable_vblank(exynos_crtc);
180 178
@@ -187,26 +185,31 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
187 struct exynos_drm_crtc *exynos_crtc = 185 struct exynos_drm_crtc *exynos_crtc =
188 to_exynos_crtc(private->crtc[pipe]); 186 to_exynos_crtc(private->crtc[pipe]);
189 187
190 if (!exynos_crtc->enabled)
191 return;
192
193 if (exynos_crtc->ops->disable_vblank) 188 if (exynos_crtc->ops->disable_vblank)
194 exynos_crtc->ops->disable_vblank(exynos_crtc); 189 exynos_crtc->ops->disable_vblank(exynos_crtc);
195} 190}
196 191
197void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc) 192void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc)
193{
194 wait_event_timeout(exynos_crtc->wait_update,
195 (atomic_read(&exynos_crtc->pending_update) == 0),
196 msecs_to_jiffies(50));
197}
198
199void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc,
200 struct exynos_drm_plane *exynos_plane)
198{ 201{
199 struct drm_crtc *crtc = &exynos_crtc->base; 202 struct drm_crtc *crtc = &exynos_crtc->base;
200 unsigned long flags; 203 unsigned long flags;
201 204
202 spin_lock_irqsave(&crtc->dev->event_lock, flags); 205 exynos_plane->pending_fb = NULL;
203 if (exynos_crtc->event) {
204 206
205 drm_crtc_send_vblank_event(crtc, exynos_crtc->event); 207 if (atomic_dec_and_test(&exynos_crtc->pending_update))
206 drm_crtc_vblank_put(crtc); 208 wake_up(&exynos_crtc->wait_update);
207 wake_up(&exynos_crtc->pending_flip_queue);
208 209
209 } 210 spin_lock_irqsave(&crtc->dev->event_lock, flags);
211 if (exynos_crtc->event)
212 drm_crtc_send_vblank_event(crtc, exynos_crtc->event);
210 213
211 exynos_crtc->event = NULL; 214 exynos_crtc->event = NULL;
212 spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 215 spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index 9e7027d6c2f6..f87d4abda6f7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -25,7 +25,9 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
25 void *context); 25 void *context);
26int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); 26int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
27void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); 27void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
28void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc); 28void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc);
29void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc,
30 struct exynos_drm_plane *exynos_plane);
29void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); 31void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
30 32
31/* This function gets pipe value to crtc device matched with out_type. */ 33/* This function gets pipe value to crtc device matched with out_type. */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index fa5194caf259..831d2e4cacf9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -13,6 +13,8 @@
13 13
14#include <linux/pm_runtime.h> 14#include <linux/pm_runtime.h>
15#include <drm/drmP.h> 15#include <drm/drmP.h>
16#include <drm/drm_atomic.h>
17#include <drm/drm_atomic_helper.h>
16#include <drm/drm_crtc_helper.h> 18#include <drm/drm_crtc_helper.h>
17 19
18#include <linux/component.h> 20#include <linux/component.h>
@@ -36,6 +38,98 @@
36#define DRIVER_MAJOR 1 38#define DRIVER_MAJOR 1
37#define DRIVER_MINOR 0 39#define DRIVER_MINOR 0
38 40
41struct exynos_atomic_commit {
42 struct work_struct work;
43 struct drm_device *dev;
44 struct drm_atomic_state *state;
45 u32 crtcs;
46};
47
48static void exynos_atomic_wait_for_commit(struct drm_atomic_state *state)
49{
50 struct drm_crtc_state *crtc_state;
51 struct drm_crtc *crtc;
52 int i, ret;
53
54 for_each_crtc_in_state(state, crtc, crtc_state, i) {
55 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
56
57 if (!crtc->state->enable)
58 continue;
59
60 ret = drm_crtc_vblank_get(crtc);
61 if (ret)
62 continue;
63
64 exynos_drm_crtc_wait_pending_update(exynos_crtc);
65 drm_crtc_vblank_put(crtc);
66 }
67}
68
69static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit)
70{
71 struct drm_device *dev = commit->dev;
72 struct exynos_drm_private *priv = dev->dev_private;
73 struct drm_atomic_state *state = commit->state;
74 struct drm_plane *plane;
75 struct drm_crtc *crtc;
76 struct drm_plane_state *plane_state;
77 struct drm_crtc_state *crtc_state;
78 int i;
79
80 drm_atomic_helper_commit_modeset_disables(dev, state);
81
82 drm_atomic_helper_commit_modeset_enables(dev, state);
83
84 /*
85 * Exynos can't update planes with CRTCs and encoders disabled,
86 * its updates routines, specially for FIMD, requires the clocks
87 * to be enabled. So it is necessary to handle the modeset operations
88 * *before* the commit_planes() step, this way it will always
89 * have the relevant clocks enabled to perform the update.
90 */
91
92 for_each_crtc_in_state(state, crtc, crtc_state, i) {
93 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
94
95 atomic_set(&exynos_crtc->pending_update, 0);
96 }
97
98 for_each_plane_in_state(state, plane, plane_state, i) {
99 struct exynos_drm_crtc *exynos_crtc =
100 to_exynos_crtc(plane->crtc);
101
102 if (!plane->crtc)
103 continue;
104
105 atomic_inc(&exynos_crtc->pending_update);
106 }
107
108 drm_atomic_helper_commit_planes(dev, state);
109
110 exynos_atomic_wait_for_commit(state);
111
112 drm_atomic_helper_cleanup_planes(dev, state);
113
114 drm_atomic_state_free(state);
115
116 spin_lock(&priv->lock);
117 priv->pending &= ~commit->crtcs;
118 spin_unlock(&priv->lock);
119
120 wake_up_all(&priv->wait);
121
122 kfree(commit);
123}
124
125static void exynos_drm_atomic_work(struct work_struct *work)
126{
127 struct exynos_atomic_commit *commit = container_of(work,
128 struct exynos_atomic_commit, work);
129
130 exynos_atomic_commit_complete(commit);
131}
132
39static int exynos_drm_load(struct drm_device *dev, unsigned long flags) 133static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
40{ 134{
41 struct exynos_drm_private *private; 135 struct exynos_drm_private *private;
@@ -47,6 +141,9 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
47 if (!private) 141 if (!private)
48 return -ENOMEM; 142 return -ENOMEM;
49 143
144 init_waitqueue_head(&private->wait);
145 spin_lock_init(&private->lock);
146
50 dev_set_drvdata(dev->dev, dev); 147 dev_set_drvdata(dev->dev, dev);
51 dev->dev_private = (void *)private; 148 dev->dev_private = (void *)private;
52 149
@@ -149,6 +246,64 @@ static int exynos_drm_unload(struct drm_device *dev)
149 return 0; 246 return 0;
150} 247}
151 248
249static int commit_is_pending(struct exynos_drm_private *priv, u32 crtcs)
250{
251 bool pending;
252
253 spin_lock(&priv->lock);
254 pending = priv->pending & crtcs;
255 spin_unlock(&priv->lock);
256
257 return pending;
258}
259
260int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
261 bool async)
262{
263 struct exynos_drm_private *priv = dev->dev_private;
264 struct exynos_atomic_commit *commit;
265 int i, ret;
266
267 commit = kzalloc(sizeof(*commit), GFP_KERNEL);
268 if (!commit)
269 return -ENOMEM;
270
271 ret = drm_atomic_helper_prepare_planes(dev, state);
272 if (ret) {
273 kfree(commit);
274 return ret;
275 }
276
277 /* This is the point of no return */
278
279 INIT_WORK(&commit->work, exynos_drm_atomic_work);
280 commit->dev = dev;
281 commit->state = state;
282
283 /* Wait until all affected CRTCs have completed previous commits and
284 * mark them as pending.
285 */
286 for (i = 0; i < dev->mode_config.num_crtc; ++i) {
287 if (state->crtcs[i])
288 commit->crtcs |= 1 << drm_crtc_index(state->crtcs[i]);
289 }
290
291 wait_event(priv->wait, !commit_is_pending(priv, commit->crtcs));
292
293 spin_lock(&priv->lock);
294 priv->pending |= commit->crtcs;
295 spin_unlock(&priv->lock);
296
297 drm_atomic_helper_swap_state(dev, state);
298
299 if (async)
300 schedule_work(&commit->work);
301 else
302 exynos_atomic_commit_complete(commit);
303
304 return 0;
305}
306
152static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state) 307static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state)
153{ 308{
154 struct drm_connector *connector; 309 struct drm_connector *connector;
@@ -248,25 +403,25 @@ static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
248 403
249static const struct drm_ioctl_desc exynos_ioctls[] = { 404static const struct drm_ioctl_desc exynos_ioctls[] = {
250 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl, 405 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl,
406 DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
407 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET, exynos_drm_gem_get_ioctl,
408 DRM_UNLOCKED | DRM_RENDER_ALLOW),
409 DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, vidi_connection_ioctl,
251 DRM_UNLOCKED | DRM_AUTH), 410 DRM_UNLOCKED | DRM_AUTH),
252 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET, 411 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER, exynos_g2d_get_ver_ioctl,
253 exynos_drm_gem_get_ioctl, DRM_UNLOCKED), 412 DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
254 DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, 413 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST, exynos_g2d_set_cmdlist_ioctl,
255 vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH), 414 DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
256 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER, 415 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl,
257 exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH), 416 DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
258 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST, 417 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY, exynos_drm_ipp_get_property,
259 exynos_g2d_set_cmdlist_ioctl, DRM_UNLOCKED | DRM_AUTH), 418 DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
260 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, 419 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY, exynos_drm_ipp_set_property,
261 exynos_g2d_exec_ioctl, DRM_UNLOCKED | DRM_AUTH), 420 DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
262 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY, 421 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF, exynos_drm_ipp_queue_buf,
263 exynos_drm_ipp_get_property, DRM_UNLOCKED | DRM_AUTH), 422 DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
264 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY, 423 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL, exynos_drm_ipp_cmd_ctrl,
265 exynos_drm_ipp_set_property, DRM_UNLOCKED | DRM_AUTH), 424 DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
266 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF,
267 exynos_drm_ipp_queue_buf, DRM_UNLOCKED | DRM_AUTH),
268 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL,
269 exynos_drm_ipp_cmd_ctrl, DRM_UNLOCKED | DRM_AUTH),
270}; 425};
271 426
272static const struct file_operations exynos_drm_driver_fops = { 427static const struct file_operations exynos_drm_driver_fops = {
@@ -283,11 +438,10 @@ static const struct file_operations exynos_drm_driver_fops = {
283}; 438};
284 439
285static struct drm_driver exynos_drm_driver = { 440static struct drm_driver exynos_drm_driver = {
286 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, 441 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME
442 | DRIVER_ATOMIC | DRIVER_RENDER,
287 .load = exynos_drm_load, 443 .load = exynos_drm_load,
288 .unload = exynos_drm_unload, 444 .unload = exynos_drm_unload,
289 .suspend = exynos_drm_suspend,
290 .resume = exynos_drm_resume,
291 .open = exynos_drm_open, 445 .open = exynos_drm_open,
292 .preclose = exynos_drm_preclose, 446 .preclose = exynos_drm_preclose,
293 .lastclose = exynos_drm_lastclose, 447 .lastclose = exynos_drm_lastclose,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 6b8a30f23473..b7ba21dfb696 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -74,6 +74,7 @@ struct exynos_drm_plane {
74 unsigned int v_ratio; 74 unsigned int v_ratio;
75 dma_addr_t dma_addr[MAX_FB_BUFFER]; 75 dma_addr_t dma_addr[MAX_FB_BUFFER];
76 unsigned int zpos; 76 unsigned int zpos;
77 struct drm_framebuffer *pending_fb;
77}; 78};
78 79
79/* 80/*
@@ -87,6 +88,8 @@ struct exynos_drm_plane {
87 * @disable_vblank: specific driver callback for disabling vblank interrupt. 88 * @disable_vblank: specific driver callback for disabling vblank interrupt.
88 * @wait_for_vblank: wait for vblank interrupt to make sure that 89 * @wait_for_vblank: wait for vblank interrupt to make sure that
89 * hardware overlay is updated. 90 * hardware overlay is updated.
91 * @atomic_begin: prepare a window to receive a update
92 * @atomic_flush: mark the end of a window update
90 * @update_plane: apply hardware specific overlay data to registers. 93 * @update_plane: apply hardware specific overlay data to registers.
91 * @disable_plane: disable hardware specific overlay. 94 * @disable_plane: disable hardware specific overlay.
92 * @te_handler: trigger to transfer video image at the tearing effect 95 * @te_handler: trigger to transfer video image at the tearing effect
@@ -107,10 +110,14 @@ struct exynos_drm_crtc_ops {
107 int (*enable_vblank)(struct exynos_drm_crtc *crtc); 110 int (*enable_vblank)(struct exynos_drm_crtc *crtc);
108 void (*disable_vblank)(struct exynos_drm_crtc *crtc); 111 void (*disable_vblank)(struct exynos_drm_crtc *crtc);
109 void (*wait_for_vblank)(struct exynos_drm_crtc *crtc); 112 void (*wait_for_vblank)(struct exynos_drm_crtc *crtc);
113 void (*atomic_begin)(struct exynos_drm_crtc *crtc,
114 struct exynos_drm_plane *plane);
110 void (*update_plane)(struct exynos_drm_crtc *crtc, 115 void (*update_plane)(struct exynos_drm_crtc *crtc,
111 struct exynos_drm_plane *plane); 116 struct exynos_drm_plane *plane);
112 void (*disable_plane)(struct exynos_drm_crtc *crtc, 117 void (*disable_plane)(struct exynos_drm_crtc *crtc,
113 struct exynos_drm_plane *plane); 118 struct exynos_drm_plane *plane);
119 void (*atomic_flush)(struct exynos_drm_crtc *crtc,
120 struct exynos_drm_plane *plane);
114 void (*te_handler)(struct exynos_drm_crtc *crtc); 121 void (*te_handler)(struct exynos_drm_crtc *crtc);
115 void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); 122 void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable);
116}; 123};
@@ -129,6 +136,8 @@ struct exynos_drm_crtc_ops {
129 * this pipe value. 136 * this pipe value.
130 * @enabled: if the crtc is enabled or not 137 * @enabled: if the crtc is enabled or not
131 * @event: vblank event that is currently queued for flip 138 * @event: vblank event that is currently queued for flip
139 * @wait_update: wait all pending planes updates to finish
140 * @pending_update: number of pending plane updates in this crtc
132 * @ops: pointer to callbacks for exynos drm specific functionality 141 * @ops: pointer to callbacks for exynos drm specific functionality
133 * @ctx: A pointer to the crtc's implementation specific context 142 * @ctx: A pointer to the crtc's implementation specific context
134 */ 143 */
@@ -136,9 +145,9 @@ struct exynos_drm_crtc {
136 struct drm_crtc base; 145 struct drm_crtc base;
137 enum exynos_drm_output_type type; 146 enum exynos_drm_output_type type;
138 unsigned int pipe; 147 unsigned int pipe;
139 bool enabled;
140 wait_queue_head_t pending_flip_queue;
141 struct drm_pending_vblank_event *event; 148 struct drm_pending_vblank_event *event;
149 wait_queue_head_t wait_update;
150 atomic_t pending_update;
142 const struct exynos_drm_crtc_ops *ops; 151 const struct exynos_drm_crtc_ops *ops;
143 void *ctx; 152 void *ctx;
144}; 153};
@@ -164,6 +173,9 @@ struct drm_exynos_file_private {
164 * @da_space_size: size of device address space. 173 * @da_space_size: size of device address space.
165 * if 0 then default value is used for it. 174 * if 0 then default value is used for it.
166 * @pipe: the pipe number for this crtc/manager. 175 * @pipe: the pipe number for this crtc/manager.
176 * @pending: the crtcs that have pending updates to finish
177 * @lock: protect access to @pending
178 * @wait: wait an atomic commit to finish
167 */ 179 */
168struct exynos_drm_private { 180struct exynos_drm_private {
169 struct drm_fb_helper *fb_helper; 181 struct drm_fb_helper *fb_helper;
@@ -179,6 +191,11 @@ struct exynos_drm_private {
179 unsigned long da_space_size; 191 unsigned long da_space_size;
180 192
181 unsigned int pipe; 193 unsigned int pipe;
194
195 /* for atomic commit */
196 u32 pending;
197 spinlock_t lock;
198 wait_queue_head_t wait;
182}; 199};
183 200
184/* 201/*
@@ -237,6 +254,9 @@ static inline int exynos_dpi_bind(struct drm_device *dev,
237} 254}
238#endif 255#endif
239 256
257int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
258 bool async);
259
240 260
241extern struct platform_driver fimd_driver; 261extern struct platform_driver fimd_driver;
242extern struct platform_driver exynos5433_decon_driver; 262extern struct platform_driver exynos5433_decon_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 9738f4e0c6eb..59ebbe547290 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -267,41 +267,6 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev)
267 exynos_drm_fbdev_init(dev); 267 exynos_drm_fbdev_init(dev);
268} 268}
269 269
270static int exynos_atomic_commit(struct drm_device *dev,
271 struct drm_atomic_state *state,
272 bool async)
273{
274 int ret;
275
276 ret = drm_atomic_helper_prepare_planes(dev, state);
277 if (ret)
278 return ret;
279
280 /* This is the point of no return */
281
282 drm_atomic_helper_swap_state(dev, state);
283
284 drm_atomic_helper_commit_modeset_disables(dev, state);
285
286 drm_atomic_helper_commit_modeset_enables(dev, state);
287
288 /*
289 * Exynos can't update planes with CRTCs and encoders disabled,
290 * its updates routines, specially for FIMD, requires the clocks
291 * to be enabled. So it is necessary to handle the modeset operations
292 * *before* the commit_planes() step, this way it will always
293 * have the relevant clocks enabled to perform the update.
294 */
295
296 drm_atomic_helper_commit_planes(dev, state);
297
298 drm_atomic_helper_cleanup_planes(dev, state);
299
300 drm_atomic_state_free(state);
301
302 return 0;
303}
304
305static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { 270static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
306 .fb_create = exynos_user_fb_create, 271 .fb_create = exynos_user_fb_create,
307 .output_poll_changed = exynos_drm_output_poll_changed, 272 .output_poll_changed = exynos_drm_output_poll_changed,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 5def6bc073eb..750a9e6b9e8d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -59,6 +59,7 @@
59#define VIDWnALPHA1(win) (VIDW_ALPHA + 0x04 + (win) * 8) 59#define VIDWnALPHA1(win) (VIDW_ALPHA + 0x04 + (win) * 8)
60 60
61#define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8) 61#define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8)
62#define VIDWx_BUF_START_S(win, buf) (VIDW_BUF_START_S(buf) + (win) * 8)
62#define VIDWx_BUF_END(win, buf) (VIDW_BUF_END(buf) + (win) * 8) 63#define VIDWx_BUF_END(win, buf) (VIDW_BUF_END(buf) + (win) * 8)
63#define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4) 64#define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4)
64 65
@@ -187,6 +188,14 @@ static const struct of_device_id fimd_driver_dt_match[] = {
187}; 188};
188MODULE_DEVICE_TABLE(of, fimd_driver_dt_match); 189MODULE_DEVICE_TABLE(of, fimd_driver_dt_match);
189 190
191static const uint32_t fimd_formats[] = {
192 DRM_FORMAT_C8,
193 DRM_FORMAT_XRGB1555,
194 DRM_FORMAT_RGB565,
195 DRM_FORMAT_XRGB8888,
196 DRM_FORMAT_ARGB8888,
197};
198
190static inline struct fimd_driver_data *drm_fimd_get_driver_data( 199static inline struct fimd_driver_data *drm_fimd_get_driver_data(
191 struct platform_device *pdev) 200 struct platform_device *pdev)
192{ 201{
@@ -591,6 +600,16 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
591{ 600{
592 u32 reg, bits, val; 601 u32 reg, bits, val;
593 602
603 /*
604 * SHADOWCON/PRTCON register is used for enabling timing.
605 *
606 * for example, once only width value of a register is set,
607 * if the dma is started then fimd hardware could malfunction so
608 * with protect window setting, the register fields with prefix '_F'
609 * wouldn't be updated at vsync also but updated once unprotect window
610 * is set.
611 */
612
594 if (ctx->driver_data->has_shadowcon) { 613 if (ctx->driver_data->has_shadowcon) {
595 reg = SHADOWCON; 614 reg = SHADOWCON;
596 bits = SHADOWCON_WINx_PROTECT(win); 615 bits = SHADOWCON_WINx_PROTECT(win);
@@ -607,6 +626,28 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
607 writel(val, ctx->regs + reg); 626 writel(val, ctx->regs + reg);
608} 627}
609 628
629static void fimd_atomic_begin(struct exynos_drm_crtc *crtc,
630 struct exynos_drm_plane *plane)
631{
632 struct fimd_context *ctx = crtc->ctx;
633
634 if (ctx->suspended)
635 return;
636
637 fimd_shadow_protect_win(ctx, plane->zpos, true);
638}
639
640static void fimd_atomic_flush(struct exynos_drm_crtc *crtc,
641 struct exynos_drm_plane *plane)
642{
643 struct fimd_context *ctx = crtc->ctx;
644
645 if (ctx->suspended)
646 return;
647
648 fimd_shadow_protect_win(ctx, plane->zpos, false);
649}
650
610static void fimd_update_plane(struct exynos_drm_crtc *crtc, 651static void fimd_update_plane(struct exynos_drm_crtc *crtc,
611 struct exynos_drm_plane *plane) 652 struct exynos_drm_plane *plane)
612{ 653{
@@ -622,20 +663,6 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc,
622 if (ctx->suspended) 663 if (ctx->suspended)
623 return; 664 return;
624 665
625 /*
626 * SHADOWCON/PRTCON register is used for enabling timing.
627 *
628 * for example, once only width value of a register is set,
629 * if the dma is started then fimd hardware could malfunction so
630 * with protect window setting, the register fields with prefix '_F'
631 * wouldn't be updated at vsync also but updated once unprotect window
632 * is set.
633 */
634
635 /* protect windows */
636 fimd_shadow_protect_win(ctx, win, true);
637
638
639 offset = plane->src_x * bpp; 666 offset = plane->src_x * bpp;
640 offset += plane->src_y * pitch; 667 offset += plane->src_y * pitch;
641 668
@@ -707,9 +734,6 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc,
707 if (ctx->driver_data->has_shadowcon) 734 if (ctx->driver_data->has_shadowcon)
708 fimd_enable_shadow_channel_path(ctx, win, true); 735 fimd_enable_shadow_channel_path(ctx, win, true);
709 736
710 /* Enable DMA channel and unprotect windows */
711 fimd_shadow_protect_win(ctx, win, false);
712
713 if (ctx->i80_if) 737 if (ctx->i80_if)
714 atomic_set(&ctx->win_updated, 1); 738 atomic_set(&ctx->win_updated, 1);
715} 739}
@@ -723,16 +747,10 @@ static void fimd_disable_plane(struct exynos_drm_crtc *crtc,
723 if (ctx->suspended) 747 if (ctx->suspended)
724 return; 748 return;
725 749
726 /* protect windows */
727 fimd_shadow_protect_win(ctx, win, true);
728
729 fimd_enable_video_output(ctx, win, false); 750 fimd_enable_video_output(ctx, win, false);
730 751
731 if (ctx->driver_data->has_shadowcon) 752 if (ctx->driver_data->has_shadowcon)
732 fimd_enable_shadow_channel_path(ctx, win, false); 753 fimd_enable_shadow_channel_path(ctx, win, false);
733
734 /* unprotect windows */
735 fimd_shadow_protect_win(ctx, win, false);
736} 754}
737 755
738static void fimd_enable(struct exynos_drm_crtc *crtc) 756static void fimd_enable(struct exynos_drm_crtc *crtc)
@@ -875,8 +893,10 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
875 .enable_vblank = fimd_enable_vblank, 893 .enable_vblank = fimd_enable_vblank,
876 .disable_vblank = fimd_disable_vblank, 894 .disable_vblank = fimd_disable_vblank,
877 .wait_for_vblank = fimd_wait_for_vblank, 895 .wait_for_vblank = fimd_wait_for_vblank,
896 .atomic_begin = fimd_atomic_begin,
878 .update_plane = fimd_update_plane, 897 .update_plane = fimd_update_plane,
879 .disable_plane = fimd_disable_plane, 898 .disable_plane = fimd_disable_plane,
899 .atomic_flush = fimd_atomic_flush,
880 .te_handler = fimd_te_handler, 900 .te_handler = fimd_te_handler,
881 .clock_enable = fimd_dp_clock_enable, 901 .clock_enable = fimd_dp_clock_enable,
882}; 902};
@@ -884,7 +904,8 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
884static irqreturn_t fimd_irq_handler(int irq, void *dev_id) 904static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
885{ 905{
886 struct fimd_context *ctx = (struct fimd_context *)dev_id; 906 struct fimd_context *ctx = (struct fimd_context *)dev_id;
887 u32 val, clear_bit; 907 u32 val, clear_bit, start, start_s;
908 int win;
888 909
889 val = readl(ctx->regs + VIDINTCON1); 910 val = readl(ctx->regs + VIDINTCON1);
890 911
@@ -896,15 +917,25 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
896 if (ctx->pipe < 0 || !ctx->drm_dev) 917 if (ctx->pipe < 0 || !ctx->drm_dev)
897 goto out; 918 goto out;
898 919
899 if (ctx->i80_if) { 920 if (!ctx->i80_if)
900 exynos_drm_crtc_finish_pageflip(ctx->crtc); 921 drm_crtc_handle_vblank(&ctx->crtc->base);
922
923 for (win = 0 ; win < WINDOWS_NR ; win++) {
924 struct exynos_drm_plane *plane = &ctx->planes[win];
901 925
926 if (!plane->pending_fb)
927 continue;
928
929 start = readl(ctx->regs + VIDWx_BUF_START(win, 0));
930 start_s = readl(ctx->regs + VIDWx_BUF_START_S(win, 0));
931 if (start == start_s)
932 exynos_drm_crtc_finish_update(ctx->crtc, plane);
933 }
934
935 if (ctx->i80_if) {
902 /* Exits triggering mode */ 936 /* Exits triggering mode */
903 atomic_set(&ctx->triggering, 0); 937 atomic_set(&ctx->triggering, 0);
904 } else { 938 } else {
905 drm_crtc_handle_vblank(&ctx->crtc->base);
906 exynos_drm_crtc_finish_pageflip(ctx->crtc);
907
908 /* set wait vsync event to zero and wake up queue. */ 939 /* set wait vsync event to zero and wake up queue. */
909 if (atomic_read(&ctx->wait_vsync_event)) { 940 if (atomic_read(&ctx->wait_vsync_event)) {
910 atomic_set(&ctx->wait_vsync_event, 0); 941 atomic_set(&ctx->wait_vsync_event, 0);
@@ -933,7 +964,8 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
933 type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : 964 type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
934 DRM_PLANE_TYPE_OVERLAY; 965 DRM_PLANE_TYPE_OVERLAY;
935 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 966 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
936 1 << ctx->pipe, type, zpos); 967 1 << ctx->pipe, type, fimd_formats,
968 ARRAY_SIZE(fimd_formats), zpos);
937 if (ret) 969 if (ret)
938 return ret; 970 return ret;
939 } 971 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 67461b77f040..62b9ea1b07fb 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -668,7 +668,7 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
668 exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size); 668 exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size);
669 if (IS_ERR(exynos_gem_obj)) { 669 if (IS_ERR(exynos_gem_obj)) {
670 ret = PTR_ERR(exynos_gem_obj); 670 ret = PTR_ERR(exynos_gem_obj);
671 goto err; 671 return ERR_PTR(ret);
672 } 672 }
673 673
674 exynos_gem_obj->dma_addr = sg_dma_address(sgt->sgl); 674 exynos_gem_obj->dma_addr = sg_dma_address(sgt->sgl);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index d9a68fd83120..865d6eb0c845 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -20,12 +20,6 @@
20#include "exynos_drm_gem.h" 20#include "exynos_drm_gem.h"
21#include "exynos_drm_plane.h" 21#include "exynos_drm_plane.h"
22 22
23static const uint32_t formats[] = {
24 DRM_FORMAT_XRGB8888,
25 DRM_FORMAT_ARGB8888,
26 DRM_FORMAT_NV12,
27};
28
29/* 23/*
30 * This function is to get X or Y size shown via screen. This needs length and 24 * This function is to get X or Y size shown via screen. This needs length and
31 * start position of CRTC. 25 * start position of CRTC.
@@ -168,6 +162,8 @@ static void exynos_plane_atomic_update(struct drm_plane *plane,
168 state->src_x >> 16, state->src_y >> 16, 162 state->src_x >> 16, state->src_y >> 16,
169 state->src_w >> 16, state->src_h >> 16); 163 state->src_w >> 16, state->src_h >> 16);
170 164
165 exynos_plane->pending_fb = state->fb;
166
171 if (exynos_crtc->ops->update_plane) 167 if (exynos_crtc->ops->update_plane)
172 exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane); 168 exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane);
173} 169}
@@ -215,13 +211,14 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
215int exynos_plane_init(struct drm_device *dev, 211int exynos_plane_init(struct drm_device *dev,
216 struct exynos_drm_plane *exynos_plane, 212 struct exynos_drm_plane *exynos_plane,
217 unsigned long possible_crtcs, enum drm_plane_type type, 213 unsigned long possible_crtcs, enum drm_plane_type type,
214 const uint32_t *formats, unsigned int fcount,
218 unsigned int zpos) 215 unsigned int zpos)
219{ 216{
220 int err; 217 int err;
221 218
222 err = drm_universal_plane_init(dev, &exynos_plane->base, possible_crtcs, 219 err = drm_universal_plane_init(dev, &exynos_plane->base, possible_crtcs,
223 &exynos_plane_funcs, formats, 220 &exynos_plane_funcs, formats, fcount,
224 ARRAY_SIZE(formats), type); 221 type);
225 if (err) { 222 if (err) {
226 DRM_ERROR("failed to initialize plane\n"); 223 DRM_ERROR("failed to initialize plane\n");
227 return err; 224 return err;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h
index 8c88ae983c38..476c9340b591 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h
@@ -12,4 +12,5 @@
12int exynos_plane_init(struct drm_device *dev, 12int exynos_plane_init(struct drm_device *dev,
13 struct exynos_drm_plane *exynos_plane, 13 struct exynos_drm_plane *exynos_plane,
14 unsigned long possible_crtcs, enum drm_plane_type type, 14 unsigned long possible_crtcs, enum drm_plane_type type,
15 const uint32_t *formats, unsigned int fcount,
15 unsigned int zpos); 16 unsigned int zpos);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 581af35861a6..75718e1bc3dd 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -83,6 +83,12 @@ static const char fake_edid_info[] = {
83 0x00, 0x00, 0x00, 0x06 83 0x00, 0x00, 0x00, 0x06
84}; 84};
85 85
86static const uint32_t formats[] = {
87 DRM_FORMAT_XRGB8888,
88 DRM_FORMAT_ARGB8888,
89 DRM_FORMAT_NV12,
90};
91
86static int vidi_enable_vblank(struct exynos_drm_crtc *crtc) 92static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
87{ 93{
88 struct vidi_context *ctx = crtc->ctx; 94 struct vidi_context *ctx = crtc->ctx;
@@ -179,6 +185,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
179{ 185{
180 struct vidi_context *ctx = container_of(work, struct vidi_context, 186 struct vidi_context *ctx = container_of(work, struct vidi_context,
181 work); 187 work);
188 int win;
182 189
183 if (ctx->pipe < 0) 190 if (ctx->pipe < 0)
184 return; 191 return;
@@ -197,7 +204,14 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
197 204
198 mutex_unlock(&ctx->lock); 205 mutex_unlock(&ctx->lock);
199 206
200 exynos_drm_crtc_finish_pageflip(ctx->crtc); 207 for (win = 0 ; win < WINDOWS_NR ; win++) {
208 struct exynos_drm_plane *plane = &ctx->planes[win];
209
210 if (!plane->pending_fb)
211 continue;
212
213 exynos_drm_crtc_finish_update(ctx->crtc, plane);
214 }
201} 215}
202 216
203static int vidi_show_connection(struct device *dev, 217static int vidi_show_connection(struct device *dev,
@@ -435,7 +449,8 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
435 type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : 449 type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
436 DRM_PLANE_TYPE_OVERLAY; 450 DRM_PLANE_TYPE_OVERLAY;
437 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 451 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
438 1 << ctx->pipe, type, zpos); 452 1 << ctx->pipe, type, formats,
453 ARRAY_SIZE(formats), zpos);
439 if (ret) 454 if (ret)
440 return ret; 455 return ret;
441 } 456 }
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index e68340c77676..7f81cce966d4 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -43,6 +43,7 @@
43 43
44#define MIXER_WIN_NR 3 44#define MIXER_WIN_NR 3
45#define MIXER_DEFAULT_WIN 0 45#define MIXER_DEFAULT_WIN 0
46#define VP_DEFAULT_WIN 2
46 47
47/* The pixelformats that are natively supported by the mixer. */ 48/* The pixelformats that are natively supported by the mixer. */
48#define MXR_FORMAT_RGB565 4 49#define MXR_FORMAT_RGB565 4
@@ -74,6 +75,19 @@ enum mixer_flag_bits {
74 MXR_BIT_VSYNC, 75 MXR_BIT_VSYNC,
75}; 76};
76 77
78static const uint32_t mixer_formats[] = {
79 DRM_FORMAT_XRGB4444,
80 DRM_FORMAT_XRGB1555,
81 DRM_FORMAT_RGB565,
82 DRM_FORMAT_XRGB8888,
83 DRM_FORMAT_ARGB8888,
84};
85
86static const uint32_t vp_formats[] = {
87 DRM_FORMAT_NV12,
88 DRM_FORMAT_NV21,
89};
90
77struct mixer_context { 91struct mixer_context {
78 struct platform_device *pdev; 92 struct platform_device *pdev;
79 struct device *dev; 93 struct device *dev;
@@ -716,6 +730,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
716 struct mixer_context *ctx = arg; 730 struct mixer_context *ctx = arg;
717 struct mixer_resources *res = &ctx->mixer_res; 731 struct mixer_resources *res = &ctx->mixer_res;
718 u32 val, base, shadow; 732 u32 val, base, shadow;
733 int win;
719 734
720 spin_lock(&res->reg_slock); 735 spin_lock(&res->reg_slock);
721 736
@@ -742,7 +757,14 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
742 } 757 }
743 758
744 drm_crtc_handle_vblank(&ctx->crtc->base); 759 drm_crtc_handle_vblank(&ctx->crtc->base);
745 exynos_drm_crtc_finish_pageflip(ctx->crtc); 760 for (win = 0 ; win < MIXER_WIN_NR ; win++) {
761 struct exynos_drm_plane *plane = &ctx->planes[win];
762
763 if (!plane->pending_fb)
764 continue;
765
766 exynos_drm_crtc_finish_update(ctx->crtc, plane);
767 }
746 768
747 /* set wait vsync event to zero and wake up queue. */ 769 /* set wait vsync event to zero and wake up queue. */
748 if (atomic_read(&ctx->wait_vsync_event)) { 770 if (atomic_read(&ctx->wait_vsync_event)) {
@@ -1163,7 +1185,6 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
1163 struct mixer_context *ctx = dev_get_drvdata(dev); 1185 struct mixer_context *ctx = dev_get_drvdata(dev);
1164 struct drm_device *drm_dev = data; 1186 struct drm_device *drm_dev = data;
1165 struct exynos_drm_plane *exynos_plane; 1187 struct exynos_drm_plane *exynos_plane;
1166 enum drm_plane_type type;
1167 unsigned int zpos; 1188 unsigned int zpos;
1168 int ret; 1189 int ret;
1169 1190
@@ -1172,10 +1193,23 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
1172 return ret; 1193 return ret;
1173 1194
1174 for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) { 1195 for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
1196 enum drm_plane_type type;
1197 const uint32_t *formats;
1198 unsigned int fcount;
1199
1175 type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : 1200 type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
1176 DRM_PLANE_TYPE_OVERLAY; 1201 DRM_PLANE_TYPE_OVERLAY;
1202 if (zpos < VP_DEFAULT_WIN) {
1203 formats = mixer_formats;
1204 fcount = ARRAY_SIZE(mixer_formats);
1205 } else {
1206 formats = vp_formats;
1207 fcount = ARRAY_SIZE(vp_formats);
1208 }
1209
1177 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 1210 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
1178 1 << ctx->pipe, type, zpos); 1211 1 << ctx->pipe, type, formats, fcount,
1212 zpos);
1179 if (ret) 1213 if (ret)
1180 return ret; 1214 return ret;
1181 } 1215 }