aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/exynos/exynos_mixer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_mixer.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c401
1 files changed, 199 insertions, 202 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index e15438c01129..68ef01028375 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -37,9 +37,6 @@
37#include "exynos_drm_drv.h" 37#include "exynos_drm_drv.h"
38#include "exynos_drm_hdmi.h" 38#include "exynos_drm_hdmi.h"
39 39
40#define MIXER_WIN_NR 3
41#define MIXER_DEFAULT_WIN 0
42
43#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev)) 40#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
44 41
45struct hdmi_win_data { 42struct hdmi_win_data {
@@ -57,13 +54,14 @@ struct hdmi_win_data {
57 unsigned int fb_y; 54 unsigned int fb_y;
58 unsigned int fb_width; 55 unsigned int fb_width;
59 unsigned int fb_height; 56 unsigned int fb_height;
57 unsigned int src_width;
58 unsigned int src_height;
60 unsigned int mode_width; 59 unsigned int mode_width;
61 unsigned int mode_height; 60 unsigned int mode_height;
62 unsigned int scan_flags; 61 unsigned int scan_flags;
63}; 62};
64 63
65struct mixer_resources { 64struct mixer_resources {
66 struct device *dev;
67 int irq; 65 int irq;
68 void __iomem *mixer_regs; 66 void __iomem *mixer_regs;
69 void __iomem *vp_regs; 67 void __iomem *vp_regs;
@@ -76,10 +74,13 @@ struct mixer_resources {
76}; 74};
77 75
78struct mixer_context { 76struct mixer_context {
79 unsigned int irq; 77 struct device *dev;
80 int pipe; 78 int pipe;
81 bool interlace; 79 bool interlace;
80 bool powered;
81 u32 int_en;
82 82
83 struct mutex mixer_mutex;
83 struct mixer_resources mixer_res; 84 struct mixer_resources mixer_res;
84 struct hdmi_win_data win_data[MIXER_WIN_NR]; 85 struct hdmi_win_data win_data[MIXER_WIN_NR];
85}; 86};
@@ -352,10 +353,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
352 struct mixer_resources *res = &ctx->mixer_res; 353 struct mixer_resources *res = &ctx->mixer_res;
353 unsigned long flags; 354 unsigned long flags;
354 struct hdmi_win_data *win_data; 355 struct hdmi_win_data *win_data;
355 unsigned int full_width, full_height, width, height;
356 unsigned int x_ratio, y_ratio; 356 unsigned int x_ratio, y_ratio;
357 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
358 unsigned int mode_width, mode_height;
359 unsigned int buf_num; 357 unsigned int buf_num;
360 dma_addr_t luma_addr[2], chroma_addr[2]; 358 dma_addr_t luma_addr[2], chroma_addr[2];
361 bool tiled_mode = false; 359 bool tiled_mode = false;
@@ -382,21 +380,9 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
382 return; 380 return;
383 } 381 }
384 382
385 full_width = win_data->fb_width;
386 full_height = win_data->fb_height;
387 width = win_data->crtc_width;
388 height = win_data->crtc_height;
389 mode_width = win_data->mode_width;
390 mode_height = win_data->mode_height;
391
392 /* scaling feature: (src << 16) / dst */ 383 /* scaling feature: (src << 16) / dst */
393 x_ratio = (width << 16) / width; 384 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
394 y_ratio = (height << 16) / height; 385 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
395
396 src_x_offset = win_data->fb_x;
397 src_y_offset = win_data->fb_y;
398 dst_x_offset = win_data->crtc_x;
399 dst_y_offset = win_data->crtc_y;
400 386
401 if (buf_num == 2) { 387 if (buf_num == 2) {
402 luma_addr[0] = win_data->dma_addr; 388 luma_addr[0] = win_data->dma_addr;
@@ -404,7 +390,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
404 } else { 390 } else {
405 luma_addr[0] = win_data->dma_addr; 391 luma_addr[0] = win_data->dma_addr;
406 chroma_addr[0] = win_data->dma_addr 392 chroma_addr[0] = win_data->dma_addr
407 + (full_width * full_height); 393 + (win_data->fb_width * win_data->fb_height);
408 } 394 }
409 395
410 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) { 396 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
@@ -413,8 +399,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
413 luma_addr[1] = luma_addr[0] + 0x40; 399 luma_addr[1] = luma_addr[0] + 0x40;
414 chroma_addr[1] = chroma_addr[0] + 0x40; 400 chroma_addr[1] = chroma_addr[0] + 0x40;
415 } else { 401 } else {
416 luma_addr[1] = luma_addr[0] + full_width; 402 luma_addr[1] = luma_addr[0] + win_data->fb_width;
417 chroma_addr[1] = chroma_addr[0] + full_width; 403 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
418 } 404 }
419 } else { 405 } else {
420 ctx->interlace = false; 406 ctx->interlace = false;
@@ -435,26 +421,26 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
435 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); 421 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
436 422
437 /* setting size of input image */ 423 /* setting size of input image */
438 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(full_width) | 424 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
439 VP_IMG_VSIZE(full_height)); 425 VP_IMG_VSIZE(win_data->fb_height));
440 /* chroma height has to reduced by 2 to avoid chroma distorions */ 426 /* chroma height has to reduced by 2 to avoid chroma distorions */
441 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(full_width) | 427 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
442 VP_IMG_VSIZE(full_height / 2)); 428 VP_IMG_VSIZE(win_data->fb_height / 2));
443 429
444 vp_reg_write(res, VP_SRC_WIDTH, width); 430 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
445 vp_reg_write(res, VP_SRC_HEIGHT, height); 431 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
446 vp_reg_write(res, VP_SRC_H_POSITION, 432 vp_reg_write(res, VP_SRC_H_POSITION,
447 VP_SRC_H_POSITION_VAL(src_x_offset)); 433 VP_SRC_H_POSITION_VAL(win_data->fb_x));
448 vp_reg_write(res, VP_SRC_V_POSITION, src_y_offset); 434 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
449 435
450 vp_reg_write(res, VP_DST_WIDTH, width); 436 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
451 vp_reg_write(res, VP_DST_H_POSITION, dst_x_offset); 437 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
452 if (ctx->interlace) { 438 if (ctx->interlace) {
453 vp_reg_write(res, VP_DST_HEIGHT, height / 2); 439 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
454 vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset / 2); 440 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
455 } else { 441 } else {
456 vp_reg_write(res, VP_DST_HEIGHT, height); 442 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
457 vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset); 443 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
458 } 444 }
459 445
460 vp_reg_write(res, VP_H_RATIO, x_ratio); 446 vp_reg_write(res, VP_H_RATIO, x_ratio);
@@ -468,8 +454,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
468 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]); 454 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
469 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]); 455 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
470 456
471 mixer_cfg_scan(ctx, mode_height); 457 mixer_cfg_scan(ctx, win_data->mode_height);
472 mixer_cfg_rgb_fmt(ctx, mode_height); 458 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
473 mixer_cfg_layer(ctx, win, true); 459 mixer_cfg_layer(ctx, win, true);
474 mixer_run(ctx); 460 mixer_run(ctx);
475 461
@@ -484,10 +470,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
484 struct mixer_resources *res = &ctx->mixer_res; 470 struct mixer_resources *res = &ctx->mixer_res;
485 unsigned long flags; 471 unsigned long flags;
486 struct hdmi_win_data *win_data; 472 struct hdmi_win_data *win_data;
487 unsigned int full_width, width, height;
488 unsigned int x_ratio, y_ratio; 473 unsigned int x_ratio, y_ratio;
489 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; 474 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
490 unsigned int mode_width, mode_height;
491 dma_addr_t dma_addr; 475 dma_addr_t dma_addr;
492 unsigned int fmt; 476 unsigned int fmt;
493 u32 val; 477 u32 val;
@@ -510,26 +494,17 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
510 fmt = ARGB8888; 494 fmt = ARGB8888;
511 } 495 }
512 496
513 dma_addr = win_data->dma_addr;
514 full_width = win_data->fb_width;
515 width = win_data->crtc_width;
516 height = win_data->crtc_height;
517 mode_width = win_data->mode_width;
518 mode_height = win_data->mode_height;
519
520 /* 2x scaling feature */ 497 /* 2x scaling feature */
521 x_ratio = 0; 498 x_ratio = 0;
522 y_ratio = 0; 499 y_ratio = 0;
523 500
524 src_x_offset = win_data->fb_x;
525 src_y_offset = win_data->fb_y;
526 dst_x_offset = win_data->crtc_x; 501 dst_x_offset = win_data->crtc_x;
527 dst_y_offset = win_data->crtc_y; 502 dst_y_offset = win_data->crtc_y;
528 503
529 /* converting dma address base and source offset */ 504 /* converting dma address base and source offset */
530 dma_addr = dma_addr 505 dma_addr = win_data->dma_addr
531 + (src_x_offset * win_data->bpp >> 3) 506 + (win_data->fb_x * win_data->bpp >> 3)
532 + (src_y_offset * full_width * win_data->bpp >> 3); 507 + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
533 src_x_offset = 0; 508 src_x_offset = 0;
534 src_y_offset = 0; 509 src_y_offset = 0;
535 510
@@ -546,10 +521,10 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
546 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK); 521 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
547 522
548 /* setup geometry */ 523 /* setup geometry */
549 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), full_width); 524 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
550 525
551 val = MXR_GRP_WH_WIDTH(width); 526 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
552 val |= MXR_GRP_WH_HEIGHT(height); 527 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
553 val |= MXR_GRP_WH_H_SCALE(x_ratio); 528 val |= MXR_GRP_WH_H_SCALE(x_ratio);
554 val |= MXR_GRP_WH_V_SCALE(y_ratio); 529 val |= MXR_GRP_WH_V_SCALE(y_ratio);
555 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val); 530 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
@@ -567,8 +542,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
567 /* set buffer address to mixer */ 542 /* set buffer address to mixer */
568 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr); 543 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
569 544
570 mixer_cfg_scan(ctx, mode_height); 545 mixer_cfg_scan(ctx, win_data->mode_height);
571 mixer_cfg_rgb_fmt(ctx, mode_height); 546 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
572 mixer_cfg_layer(ctx, win, true); 547 mixer_cfg_layer(ctx, win, true);
573 mixer_run(ctx); 548 mixer_run(ctx);
574 549
@@ -591,6 +566,116 @@ static void vp_win_reset(struct mixer_context *ctx)
591 WARN(tries == 0, "failed to reset Video Processor\n"); 566 WARN(tries == 0, "failed to reset Video Processor\n");
592} 567}
593 568
569static void mixer_win_reset(struct mixer_context *ctx)
570{
571 struct mixer_resources *res = &ctx->mixer_res;
572 unsigned long flags;
573 u32 val; /* value stored to register */
574
575 spin_lock_irqsave(&res->reg_slock, flags);
576 mixer_vsync_set_update(ctx, false);
577
578 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
579
580 /* set output in RGB888 mode */
581 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
582
583 /* 16 beat burst in DMA */
584 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
585 MXR_STATUS_BURST_MASK);
586
587 /* setting default layer priority: layer1 > layer0 > video
588 * because typical usage scenario would be
589 * layer1 - OSD
590 * layer0 - framebuffer
591 * video - video overlay
592 */
593 val = MXR_LAYER_CFG_GRP1_VAL(3);
594 val |= MXR_LAYER_CFG_GRP0_VAL(2);
595 val |= MXR_LAYER_CFG_VP_VAL(1);
596 mixer_reg_write(res, MXR_LAYER_CFG, val);
597
598 /* setting background color */
599 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
600 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
601 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
602
603 /* setting graphical layers */
604
605 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
606 val |= MXR_GRP_CFG_WIN_BLEND_EN;
607 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
608
609 /* the same configuration for both layers */
610 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
611
612 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
613 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
614 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
615
616 /* configuration of Video Processor Registers */
617 vp_win_reset(ctx);
618 vp_default_filter(res);
619
620 /* disable all layers */
621 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
622 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
623 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
624
625 mixer_vsync_set_update(ctx, true);
626 spin_unlock_irqrestore(&res->reg_slock, flags);
627}
628
629static void mixer_poweron(struct mixer_context *ctx)
630{
631 struct mixer_resources *res = &ctx->mixer_res;
632
633 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
634
635 mutex_lock(&ctx->mixer_mutex);
636 if (ctx->powered) {
637 mutex_unlock(&ctx->mixer_mutex);
638 return;
639 }
640 ctx->powered = true;
641 mutex_unlock(&ctx->mixer_mutex);
642
643 pm_runtime_get_sync(ctx->dev);
644
645 clk_enable(res->mixer);
646 clk_enable(res->vp);
647 clk_enable(res->sclk_mixer);
648
649 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
650 mixer_win_reset(ctx);
651}
652
653static void mixer_poweroff(struct mixer_context *ctx)
654{
655 struct mixer_resources *res = &ctx->mixer_res;
656
657 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
658
659 mutex_lock(&ctx->mixer_mutex);
660 if (!ctx->powered)
661 goto out;
662 mutex_unlock(&ctx->mixer_mutex);
663
664 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
665
666 clk_disable(res->mixer);
667 clk_disable(res->vp);
668 clk_disable(res->sclk_mixer);
669
670 pm_runtime_put_sync(ctx->dev);
671
672 mutex_lock(&ctx->mixer_mutex);
673 ctx->powered = false;
674
675out:
676 mutex_unlock(&ctx->mixer_mutex);
677}
678
594static int mixer_enable_vblank(void *ctx, int pipe) 679static int mixer_enable_vblank(void *ctx, int pipe)
595{ 680{
596 struct mixer_context *mixer_ctx = ctx; 681 struct mixer_context *mixer_ctx = ctx;
@@ -618,6 +703,27 @@ static void mixer_disable_vblank(void *ctx)
618 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); 703 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
619} 704}
620 705
706static void mixer_dpms(void *ctx, int mode)
707{
708 struct mixer_context *mixer_ctx = ctx;
709
710 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
711
712 switch (mode) {
713 case DRM_MODE_DPMS_ON:
714 mixer_poweron(mixer_ctx);
715 break;
716 case DRM_MODE_DPMS_STANDBY:
717 case DRM_MODE_DPMS_SUSPEND:
718 case DRM_MODE_DPMS_OFF:
719 mixer_poweroff(mixer_ctx);
720 break;
721 default:
722 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
723 break;
724 }
725}
726
621static void mixer_win_mode_set(void *ctx, 727static void mixer_win_mode_set(void *ctx,
622 struct exynos_drm_overlay *overlay) 728 struct exynos_drm_overlay *overlay)
623{ 729{
@@ -643,7 +749,7 @@ static void mixer_win_mode_set(void *ctx,
643 win = MIXER_DEFAULT_WIN; 749 win = MIXER_DEFAULT_WIN;
644 750
645 if (win < 0 || win > MIXER_WIN_NR) { 751 if (win < 0 || win > MIXER_WIN_NR) {
646 DRM_ERROR("overlay plane[%d] is wrong\n", win); 752 DRM_ERROR("mixer window[%d] is wrong\n", win);
647 return; 753 return;
648 } 754 }
649 755
@@ -665,6 +771,8 @@ static void mixer_win_mode_set(void *ctx,
665 win_data->fb_y = overlay->fb_y; 771 win_data->fb_y = overlay->fb_y;
666 win_data->fb_width = overlay->fb_width; 772 win_data->fb_width = overlay->fb_width;
667 win_data->fb_height = overlay->fb_height; 773 win_data->fb_height = overlay->fb_height;
774 win_data->src_width = overlay->src_width;
775 win_data->src_height = overlay->src_height;
668 776
669 win_data->mode_width = overlay->mode_width; 777 win_data->mode_width = overlay->mode_width;
670 win_data->mode_height = overlay->mode_height; 778 win_data->mode_height = overlay->mode_height;
@@ -672,44 +780,26 @@ static void mixer_win_mode_set(void *ctx,
672 win_data->scan_flags = overlay->scan_flag; 780 win_data->scan_flags = overlay->scan_flag;
673} 781}
674 782
675static void mixer_win_commit(void *ctx, int zpos) 783static void mixer_win_commit(void *ctx, int win)
676{ 784{
677 struct mixer_context *mixer_ctx = ctx; 785 struct mixer_context *mixer_ctx = ctx;
678 int win = zpos;
679 786
680 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); 787 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
681 788
682 if (win == DEFAULT_ZPOS)
683 win = MIXER_DEFAULT_WIN;
684
685 if (win < 0 || win > MIXER_WIN_NR) {
686 DRM_ERROR("overlay plane[%d] is wrong\n", win);
687 return;
688 }
689
690 if (win > 1) 789 if (win > 1)
691 vp_video_buffer(mixer_ctx, win); 790 vp_video_buffer(mixer_ctx, win);
692 else 791 else
693 mixer_graph_buffer(mixer_ctx, win); 792 mixer_graph_buffer(mixer_ctx, win);
694} 793}
695 794
696static void mixer_win_disable(void *ctx, int zpos) 795static void mixer_win_disable(void *ctx, int win)
697{ 796{
698 struct mixer_context *mixer_ctx = ctx; 797 struct mixer_context *mixer_ctx = ctx;
699 struct mixer_resources *res = &mixer_ctx->mixer_res; 798 struct mixer_resources *res = &mixer_ctx->mixer_res;
700 unsigned long flags; 799 unsigned long flags;
701 int win = zpos;
702 800
703 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); 801 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
704 802
705 if (win == DEFAULT_ZPOS)
706 win = MIXER_DEFAULT_WIN;
707
708 if (win < 0 || win > MIXER_WIN_NR) {
709 DRM_ERROR("overlay plane[%d] is wrong\n", win);
710 return;
711 }
712
713 spin_lock_irqsave(&res->reg_slock, flags); 803 spin_lock_irqsave(&res->reg_slock, flags);
714 mixer_vsync_set_update(mixer_ctx, false); 804 mixer_vsync_set_update(mixer_ctx, false);
715 805
@@ -723,6 +813,7 @@ static struct exynos_mixer_ops mixer_ops = {
723 /* manager */ 813 /* manager */
724 .enable_vblank = mixer_enable_vblank, 814 .enable_vblank = mixer_enable_vblank,
725 .disable_vblank = mixer_disable_vblank, 815 .disable_vblank = mixer_disable_vblank,
816 .dpms = mixer_dpms,
726 817
727 /* overlay */ 818 /* overlay */
728 .win_mode_set = mixer_win_mode_set, 819 .win_mode_set = mixer_win_mode_set,
@@ -773,7 +864,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
773 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg; 864 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
774 struct mixer_context *ctx = drm_hdmi_ctx->ctx; 865 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
775 struct mixer_resources *res = &ctx->mixer_res; 866 struct mixer_resources *res = &ctx->mixer_res;
776 u32 val, val_base; 867 u32 val, base, shadow;
777 868
778 spin_lock(&res->reg_slock); 869 spin_lock(&res->reg_slock);
779 870
@@ -784,12 +875,14 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
784 if (val & MXR_INT_STATUS_VSYNC) { 875 if (val & MXR_INT_STATUS_VSYNC) {
785 /* interlace scan need to check shadow register */ 876 /* interlace scan need to check shadow register */
786 if (ctx->interlace) { 877 if (ctx->interlace) {
787 val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0)); 878 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
788 if (ctx->win_data[0].dma_addr != val_base) 879 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
880 if (base != shadow)
789 goto out; 881 goto out;
790 882
791 val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1)); 883 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
792 if (ctx->win_data[1].dma_addr != val_base) 884 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
885 if (base != shadow)
793 goto out; 886 goto out;
794 } 887 }
795 888
@@ -811,117 +904,6 @@ out:
811 return IRQ_HANDLED; 904 return IRQ_HANDLED;
812} 905}
813 906
814static void mixer_win_reset(struct mixer_context *ctx)
815{
816 struct mixer_resources *res = &ctx->mixer_res;
817 unsigned long flags;
818 u32 val; /* value stored to register */
819
820 spin_lock_irqsave(&res->reg_slock, flags);
821 mixer_vsync_set_update(ctx, false);
822
823 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
824
825 /* set output in RGB888 mode */
826 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
827
828 /* 16 beat burst in DMA */
829 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
830 MXR_STATUS_BURST_MASK);
831
832 /* setting default layer priority: layer1 > layer0 > video
833 * because typical usage scenario would be
834 * layer1 - OSD
835 * layer0 - framebuffer
836 * video - video overlay
837 */
838 val = MXR_LAYER_CFG_GRP1_VAL(3);
839 val |= MXR_LAYER_CFG_GRP0_VAL(2);
840 val |= MXR_LAYER_CFG_VP_VAL(1);
841 mixer_reg_write(res, MXR_LAYER_CFG, val);
842
843 /* setting background color */
844 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
845 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
846 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
847
848 /* setting graphical layers */
849
850 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
851 val |= MXR_GRP_CFG_WIN_BLEND_EN;
852 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
853
854 /* the same configuration for both layers */
855 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
856
857 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
858 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
859 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
860
861 /* configuration of Video Processor Registers */
862 vp_win_reset(ctx);
863 vp_default_filter(res);
864
865 /* disable all layers */
866 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
867 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
868 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
869
870 mixer_vsync_set_update(ctx, true);
871 spin_unlock_irqrestore(&res->reg_slock, flags);
872}
873
874static void mixer_resource_poweron(struct mixer_context *ctx)
875{
876 struct mixer_resources *res = &ctx->mixer_res;
877
878 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
879
880 clk_enable(res->mixer);
881 clk_enable(res->vp);
882 clk_enable(res->sclk_mixer);
883
884 mixer_win_reset(ctx);
885}
886
887static void mixer_resource_poweroff(struct mixer_context *ctx)
888{
889 struct mixer_resources *res = &ctx->mixer_res;
890
891 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
892
893 clk_disable(res->mixer);
894 clk_disable(res->vp);
895 clk_disable(res->sclk_mixer);
896}
897
898static int mixer_runtime_resume(struct device *dev)
899{
900 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
901
902 DRM_DEBUG_KMS("resume - start\n");
903
904 mixer_resource_poweron(ctx->ctx);
905
906 return 0;
907}
908
909static int mixer_runtime_suspend(struct device *dev)
910{
911 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
912
913 DRM_DEBUG_KMS("suspend - start\n");
914
915 mixer_resource_poweroff(ctx->ctx);
916
917 return 0;
918}
919
920static const struct dev_pm_ops mixer_pm_ops = {
921 .runtime_suspend = mixer_runtime_suspend,
922 .runtime_resume = mixer_runtime_resume,
923};
924
925static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, 907static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
926 struct platform_device *pdev) 908 struct platform_device *pdev)
927{ 909{
@@ -931,7 +913,6 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
931 struct resource *res; 913 struct resource *res;
932 int ret; 914 int ret;
933 915
934 mixer_res->dev = dev;
935 spin_lock_init(&mixer_res->reg_slock); 916 spin_lock_init(&mixer_res->reg_slock);
936 917
937 mixer_res->mixer = clk_get(dev, "mixer"); 918 mixer_res->mixer = clk_get(dev, "mixer");
@@ -1027,7 +1008,6 @@ fail:
1027 clk_put(mixer_res->vp); 1008 clk_put(mixer_res->vp);
1028 if (!IS_ERR_OR_NULL(mixer_res->mixer)) 1009 if (!IS_ERR_OR_NULL(mixer_res->mixer))
1029 clk_put(mixer_res->mixer); 1010 clk_put(mixer_res->mixer);
1030 mixer_res->dev = NULL;
1031 return ret; 1011 return ret;
1032} 1012}
1033 1013
@@ -1035,7 +1015,6 @@ static void mixer_resources_cleanup(struct mixer_context *ctx)
1035{ 1015{
1036 struct mixer_resources *res = &ctx->mixer_res; 1016 struct mixer_resources *res = &ctx->mixer_res;
1037 1017
1038 disable_irq(res->irq);
1039 free_irq(res->irq, ctx); 1018 free_irq(res->irq, ctx);
1040 1019
1041 iounmap(res->vp_regs); 1020 iounmap(res->vp_regs);
@@ -1064,6 +1043,9 @@ static int __devinit mixer_probe(struct platform_device *pdev)
1064 return -ENOMEM; 1043 return -ENOMEM;
1065 } 1044 }
1066 1045
1046 mutex_init(&ctx->mixer_mutex);
1047
1048 ctx->dev = &pdev->dev;
1067 drm_hdmi_ctx->ctx = (void *)ctx; 1049 drm_hdmi_ctx->ctx = (void *)ctx;
1068 1050
1069 platform_set_drvdata(pdev, drm_hdmi_ctx); 1051 platform_set_drvdata(pdev, drm_hdmi_ctx);
@@ -1076,7 +1058,7 @@ static int __devinit mixer_probe(struct platform_device *pdev)
1076 /* register specific callback point to common hdmi. */ 1058 /* register specific callback point to common hdmi. */
1077 exynos_mixer_ops_register(&mixer_ops); 1059 exynos_mixer_ops_register(&mixer_ops);
1078 1060
1079 mixer_resource_poweron(ctx); 1061 pm_runtime_enable(dev);
1080 1062
1081 return 0; 1063 return 0;
1082 1064
@@ -1095,12 +1077,27 @@ static int mixer_remove(struct platform_device *pdev)
1095 1077
1096 dev_info(dev, "remove successful\n"); 1078 dev_info(dev, "remove successful\n");
1097 1079
1098 mixer_resource_poweroff(ctx); 1080 pm_runtime_disable(&pdev->dev);
1081
1099 mixer_resources_cleanup(ctx); 1082 mixer_resources_cleanup(ctx);
1100 1083
1101 return 0; 1084 return 0;
1102} 1085}
1103 1086
1087#ifdef CONFIG_PM_SLEEP
1088static int mixer_suspend(struct device *dev)
1089{
1090 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1091 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1092
1093 mixer_poweroff(ctx);
1094
1095 return 0;
1096}
1097#endif
1098
1099static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL);
1100
1104struct platform_driver mixer_driver = { 1101struct platform_driver mixer_driver = {
1105 .driver = { 1102 .driver = {
1106 .name = "s5p-mixer", 1103 .name = "s5p-mixer",