diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_mixer.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_mixer.c | 376 |
1 files changed, 237 insertions, 139 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e7fbb823fd8e..21db89530fc7 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
@@ -36,14 +36,13 @@ | |||
36 | 36 | ||
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 | #include "exynos_drm_iommu.h" | ||
39 | 40 | ||
40 | #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev)) | 41 | #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev)) |
41 | 42 | ||
42 | struct hdmi_win_data { | 43 | struct hdmi_win_data { |
43 | dma_addr_t dma_addr; | 44 | dma_addr_t dma_addr; |
44 | void __iomem *vaddr; | ||
45 | dma_addr_t chroma_dma_addr; | 45 | dma_addr_t chroma_dma_addr; |
46 | void __iomem *chroma_vaddr; | ||
47 | uint32_t pixel_format; | 46 | uint32_t pixel_format; |
48 | unsigned int bpp; | 47 | unsigned int bpp; |
49 | unsigned int crtc_x; | 48 | unsigned int crtc_x; |
@@ -59,6 +58,8 @@ struct hdmi_win_data { | |||
59 | unsigned int mode_width; | 58 | unsigned int mode_width; |
60 | unsigned int mode_height; | 59 | unsigned int mode_height; |
61 | unsigned int scan_flags; | 60 | unsigned int scan_flags; |
61 | bool enabled; | ||
62 | bool resume; | ||
62 | }; | 63 | }; |
63 | 64 | ||
64 | struct mixer_resources { | 65 | struct mixer_resources { |
@@ -80,6 +81,7 @@ enum mixer_version_id { | |||
80 | 81 | ||
81 | struct mixer_context { | 82 | struct mixer_context { |
82 | struct device *dev; | 83 | struct device *dev; |
84 | struct drm_device *drm_dev; | ||
83 | int pipe; | 85 | int pipe; |
84 | bool interlace; | 86 | bool interlace; |
85 | bool powered; | 87 | bool powered; |
@@ -90,6 +92,9 @@ struct mixer_context { | |||
90 | struct mixer_resources mixer_res; | 92 | struct mixer_resources mixer_res; |
91 | struct hdmi_win_data win_data[MIXER_WIN_NR]; | 93 | struct hdmi_win_data win_data[MIXER_WIN_NR]; |
92 | enum mixer_version_id mxr_ver; | 94 | enum mixer_version_id mxr_ver; |
95 | void *parent_ctx; | ||
96 | wait_queue_head_t wait_vsync_queue; | ||
97 | atomic_t wait_vsync_event; | ||
93 | }; | 98 | }; |
94 | 99 | ||
95 | struct mixer_drv_data { | 100 | struct mixer_drv_data { |
@@ -665,58 +670,22 @@ static void mixer_win_reset(struct mixer_context *ctx) | |||
665 | spin_unlock_irqrestore(&res->reg_slock, flags); | 670 | spin_unlock_irqrestore(&res->reg_slock, flags); |
666 | } | 671 | } |
667 | 672 | ||
668 | static void mixer_poweron(struct mixer_context *ctx) | 673 | static int mixer_iommu_on(void *ctx, bool enable) |
669 | { | ||
670 | struct mixer_resources *res = &ctx->mixer_res; | ||
671 | |||
672 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
673 | |||
674 | mutex_lock(&ctx->mixer_mutex); | ||
675 | if (ctx->powered) { | ||
676 | mutex_unlock(&ctx->mixer_mutex); | ||
677 | return; | ||
678 | } | ||
679 | ctx->powered = true; | ||
680 | mutex_unlock(&ctx->mixer_mutex); | ||
681 | |||
682 | pm_runtime_get_sync(ctx->dev); | ||
683 | |||
684 | clk_enable(res->mixer); | ||
685 | if (ctx->vp_enabled) { | ||
686 | clk_enable(res->vp); | ||
687 | clk_enable(res->sclk_mixer); | ||
688 | } | ||
689 | |||
690 | mixer_reg_write(res, MXR_INT_EN, ctx->int_en); | ||
691 | mixer_win_reset(ctx); | ||
692 | } | ||
693 | |||
694 | static void mixer_poweroff(struct mixer_context *ctx) | ||
695 | { | 674 | { |
696 | struct mixer_resources *res = &ctx->mixer_res; | 675 | struct exynos_drm_hdmi_context *drm_hdmi_ctx; |
697 | 676 | struct mixer_context *mdata = ctx; | |
698 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | 677 | struct drm_device *drm_dev; |
699 | 678 | ||
700 | mutex_lock(&ctx->mixer_mutex); | 679 | drm_hdmi_ctx = mdata->parent_ctx; |
701 | if (!ctx->powered) | 680 | drm_dev = drm_hdmi_ctx->drm_dev; |
702 | goto out; | ||
703 | mutex_unlock(&ctx->mixer_mutex); | ||
704 | 681 | ||
705 | ctx->int_en = mixer_reg_read(res, MXR_INT_EN); | 682 | if (is_drm_iommu_supported(drm_dev)) { |
683 | if (enable) | ||
684 | return drm_iommu_attach_device(drm_dev, mdata->dev); | ||
706 | 685 | ||
707 | clk_disable(res->mixer); | 686 | drm_iommu_detach_device(drm_dev, mdata->dev); |
708 | if (ctx->vp_enabled) { | ||
709 | clk_disable(res->vp); | ||
710 | clk_disable(res->sclk_mixer); | ||
711 | } | 687 | } |
712 | 688 | return 0; | |
713 | pm_runtime_put_sync(ctx->dev); | ||
714 | |||
715 | mutex_lock(&ctx->mixer_mutex); | ||
716 | ctx->powered = false; | ||
717 | |||
718 | out: | ||
719 | mutex_unlock(&ctx->mixer_mutex); | ||
720 | } | 689 | } |
721 | 690 | ||
722 | static int mixer_enable_vblank(void *ctx, int pipe) | 691 | static int mixer_enable_vblank(void *ctx, int pipe) |
@@ -746,39 +715,6 @@ static void mixer_disable_vblank(void *ctx) | |||
746 | mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); | 715 | mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); |
747 | } | 716 | } |
748 | 717 | ||
749 | static void mixer_dpms(void *ctx, int mode) | ||
750 | { | ||
751 | struct mixer_context *mixer_ctx = ctx; | ||
752 | |||
753 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
754 | |||
755 | switch (mode) { | ||
756 | case DRM_MODE_DPMS_ON: | ||
757 | mixer_poweron(mixer_ctx); | ||
758 | break; | ||
759 | case DRM_MODE_DPMS_STANDBY: | ||
760 | case DRM_MODE_DPMS_SUSPEND: | ||
761 | case DRM_MODE_DPMS_OFF: | ||
762 | mixer_poweroff(mixer_ctx); | ||
763 | break; | ||
764 | default: | ||
765 | DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); | ||
766 | break; | ||
767 | } | ||
768 | } | ||
769 | |||
770 | static void mixer_wait_for_vblank(void *ctx) | ||
771 | { | ||
772 | struct mixer_context *mixer_ctx = ctx; | ||
773 | struct mixer_resources *res = &mixer_ctx->mixer_res; | ||
774 | int ret; | ||
775 | |||
776 | ret = wait_for((mixer_reg_read(res, MXR_INT_STATUS) & | ||
777 | MXR_INT_STATUS_VSYNC), 50); | ||
778 | if (ret < 0) | ||
779 | DRM_DEBUG_KMS("vblank wait timed out.\n"); | ||
780 | } | ||
781 | |||
782 | static void mixer_win_mode_set(void *ctx, | 718 | static void mixer_win_mode_set(void *ctx, |
783 | struct exynos_drm_overlay *overlay) | 719 | struct exynos_drm_overlay *overlay) |
784 | { | 720 | { |
@@ -811,9 +747,7 @@ static void mixer_win_mode_set(void *ctx, | |||
811 | win_data = &mixer_ctx->win_data[win]; | 747 | win_data = &mixer_ctx->win_data[win]; |
812 | 748 | ||
813 | win_data->dma_addr = overlay->dma_addr[0]; | 749 | win_data->dma_addr = overlay->dma_addr[0]; |
814 | win_data->vaddr = overlay->vaddr[0]; | ||
815 | win_data->chroma_dma_addr = overlay->dma_addr[1]; | 750 | win_data->chroma_dma_addr = overlay->dma_addr[1]; |
816 | win_data->chroma_vaddr = overlay->vaddr[1]; | ||
817 | win_data->pixel_format = overlay->pixel_format; | 751 | win_data->pixel_format = overlay->pixel_format; |
818 | win_data->bpp = overlay->bpp; | 752 | win_data->bpp = overlay->bpp; |
819 | 753 | ||
@@ -845,6 +779,8 @@ static void mixer_win_commit(void *ctx, int win) | |||
845 | vp_video_buffer(mixer_ctx, win); | 779 | vp_video_buffer(mixer_ctx, win); |
846 | else | 780 | else |
847 | mixer_graph_buffer(mixer_ctx, win); | 781 | mixer_graph_buffer(mixer_ctx, win); |
782 | |||
783 | mixer_ctx->win_data[win].enabled = true; | ||
848 | } | 784 | } |
849 | 785 | ||
850 | static void mixer_win_disable(void *ctx, int win) | 786 | static void mixer_win_disable(void *ctx, int win) |
@@ -855,6 +791,14 @@ static void mixer_win_disable(void *ctx, int win) | |||
855 | 791 | ||
856 | DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); | 792 | DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); |
857 | 793 | ||
794 | mutex_lock(&mixer_ctx->mixer_mutex); | ||
795 | if (!mixer_ctx->powered) { | ||
796 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
797 | mixer_ctx->win_data[win].resume = false; | ||
798 | return; | ||
799 | } | ||
800 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
801 | |||
858 | spin_lock_irqsave(&res->reg_slock, flags); | 802 | spin_lock_irqsave(&res->reg_slock, flags); |
859 | mixer_vsync_set_update(mixer_ctx, false); | 803 | mixer_vsync_set_update(mixer_ctx, false); |
860 | 804 | ||
@@ -862,16 +806,144 @@ static void mixer_win_disable(void *ctx, int win) | |||
862 | 806 | ||
863 | mixer_vsync_set_update(mixer_ctx, true); | 807 | mixer_vsync_set_update(mixer_ctx, true); |
864 | spin_unlock_irqrestore(&res->reg_slock, flags); | 808 | spin_unlock_irqrestore(&res->reg_slock, flags); |
809 | |||
810 | mixer_ctx->win_data[win].enabled = false; | ||
811 | } | ||
812 | |||
813 | static void mixer_wait_for_vblank(void *ctx) | ||
814 | { | ||
815 | struct mixer_context *mixer_ctx = ctx; | ||
816 | |||
817 | mutex_lock(&mixer_ctx->mixer_mutex); | ||
818 | if (!mixer_ctx->powered) { | ||
819 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
820 | return; | ||
821 | } | ||
822 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
823 | |||
824 | atomic_set(&mixer_ctx->wait_vsync_event, 1); | ||
825 | |||
826 | /* | ||
827 | * wait for MIXER to signal VSYNC interrupt or return after | ||
828 | * timeout which is set to 50ms (refresh rate of 20). | ||
829 | */ | ||
830 | if (!wait_event_timeout(mixer_ctx->wait_vsync_queue, | ||
831 | !atomic_read(&mixer_ctx->wait_vsync_event), | ||
832 | DRM_HZ/20)) | ||
833 | DRM_DEBUG_KMS("vblank wait timed out.\n"); | ||
834 | } | ||
835 | |||
836 | static void mixer_window_suspend(struct mixer_context *ctx) | ||
837 | { | ||
838 | struct hdmi_win_data *win_data; | ||
839 | int i; | ||
840 | |||
841 | for (i = 0; i < MIXER_WIN_NR; i++) { | ||
842 | win_data = &ctx->win_data[i]; | ||
843 | win_data->resume = win_data->enabled; | ||
844 | mixer_win_disable(ctx, i); | ||
845 | } | ||
846 | mixer_wait_for_vblank(ctx); | ||
847 | } | ||
848 | |||
849 | static void mixer_window_resume(struct mixer_context *ctx) | ||
850 | { | ||
851 | struct hdmi_win_data *win_data; | ||
852 | int i; | ||
853 | |||
854 | for (i = 0; i < MIXER_WIN_NR; i++) { | ||
855 | win_data = &ctx->win_data[i]; | ||
856 | win_data->enabled = win_data->resume; | ||
857 | win_data->resume = false; | ||
858 | } | ||
859 | } | ||
860 | |||
861 | static void mixer_poweron(struct mixer_context *ctx) | ||
862 | { | ||
863 | struct mixer_resources *res = &ctx->mixer_res; | ||
864 | |||
865 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
866 | |||
867 | mutex_lock(&ctx->mixer_mutex); | ||
868 | if (ctx->powered) { | ||
869 | mutex_unlock(&ctx->mixer_mutex); | ||
870 | return; | ||
871 | } | ||
872 | ctx->powered = true; | ||
873 | mutex_unlock(&ctx->mixer_mutex); | ||
874 | |||
875 | clk_enable(res->mixer); | ||
876 | if (ctx->vp_enabled) { | ||
877 | clk_enable(res->vp); | ||
878 | clk_enable(res->sclk_mixer); | ||
879 | } | ||
880 | |||
881 | mixer_reg_write(res, MXR_INT_EN, ctx->int_en); | ||
882 | mixer_win_reset(ctx); | ||
883 | |||
884 | mixer_window_resume(ctx); | ||
885 | } | ||
886 | |||
887 | static void mixer_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 | mutex_lock(&ctx->mixer_mutex); | ||
894 | if (!ctx->powered) | ||
895 | goto out; | ||
896 | mutex_unlock(&ctx->mixer_mutex); | ||
897 | |||
898 | mixer_window_suspend(ctx); | ||
899 | |||
900 | ctx->int_en = mixer_reg_read(res, MXR_INT_EN); | ||
901 | |||
902 | clk_disable(res->mixer); | ||
903 | if (ctx->vp_enabled) { | ||
904 | clk_disable(res->vp); | ||
905 | clk_disable(res->sclk_mixer); | ||
906 | } | ||
907 | |||
908 | mutex_lock(&ctx->mixer_mutex); | ||
909 | ctx->powered = false; | ||
910 | |||
911 | out: | ||
912 | mutex_unlock(&ctx->mixer_mutex); | ||
913 | } | ||
914 | |||
915 | static void mixer_dpms(void *ctx, int mode) | ||
916 | { | ||
917 | struct mixer_context *mixer_ctx = ctx; | ||
918 | |||
919 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
920 | |||
921 | switch (mode) { | ||
922 | case DRM_MODE_DPMS_ON: | ||
923 | if (pm_runtime_suspended(mixer_ctx->dev)) | ||
924 | pm_runtime_get_sync(mixer_ctx->dev); | ||
925 | break; | ||
926 | case DRM_MODE_DPMS_STANDBY: | ||
927 | case DRM_MODE_DPMS_SUSPEND: | ||
928 | case DRM_MODE_DPMS_OFF: | ||
929 | if (!pm_runtime_suspended(mixer_ctx->dev)) | ||
930 | pm_runtime_put_sync(mixer_ctx->dev); | ||
931 | break; | ||
932 | default: | ||
933 | DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); | ||
934 | break; | ||
935 | } | ||
865 | } | 936 | } |
866 | 937 | ||
867 | static struct exynos_mixer_ops mixer_ops = { | 938 | static struct exynos_mixer_ops mixer_ops = { |
868 | /* manager */ | 939 | /* manager */ |
940 | .iommu_on = mixer_iommu_on, | ||
869 | .enable_vblank = mixer_enable_vblank, | 941 | .enable_vblank = mixer_enable_vblank, |
870 | .disable_vblank = mixer_disable_vblank, | 942 | .disable_vblank = mixer_disable_vblank, |
943 | .wait_for_vblank = mixer_wait_for_vblank, | ||
871 | .dpms = mixer_dpms, | 944 | .dpms = mixer_dpms, |
872 | 945 | ||
873 | /* overlay */ | 946 | /* overlay */ |
874 | .wait_for_vblank = mixer_wait_for_vblank, | ||
875 | .win_mode_set = mixer_win_mode_set, | 947 | .win_mode_set = mixer_win_mode_set, |
876 | .win_commit = mixer_win_commit, | 948 | .win_commit = mixer_win_commit, |
877 | .win_disable = mixer_win_disable, | 949 | .win_disable = mixer_win_disable, |
@@ -884,7 +956,6 @@ static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc) | |||
884 | struct drm_pending_vblank_event *e, *t; | 956 | struct drm_pending_vblank_event *e, *t; |
885 | struct timeval now; | 957 | struct timeval now; |
886 | unsigned long flags; | 958 | unsigned long flags; |
887 | bool is_checked = false; | ||
888 | 959 | ||
889 | spin_lock_irqsave(&drm_dev->event_lock, flags); | 960 | spin_lock_irqsave(&drm_dev->event_lock, flags); |
890 | 961 | ||
@@ -894,7 +965,6 @@ static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc) | |||
894 | if (crtc != e->pipe) | 965 | if (crtc != e->pipe) |
895 | continue; | 966 | continue; |
896 | 967 | ||
897 | is_checked = true; | ||
898 | do_gettimeofday(&now); | 968 | do_gettimeofday(&now); |
899 | e->event.sequence = 0; | 969 | e->event.sequence = 0; |
900 | e->event.tv_sec = now.tv_sec; | 970 | e->event.tv_sec = now.tv_sec; |
@@ -902,16 +972,9 @@ static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc) | |||
902 | 972 | ||
903 | list_move_tail(&e->base.link, &e->base.file_priv->event_list); | 973 | list_move_tail(&e->base.link, &e->base.file_priv->event_list); |
904 | wake_up_interruptible(&e->base.file_priv->event_wait); | 974 | wake_up_interruptible(&e->base.file_priv->event_wait); |
975 | drm_vblank_put(drm_dev, crtc); | ||
905 | } | 976 | } |
906 | 977 | ||
907 | if (is_checked) | ||
908 | /* | ||
909 | * call drm_vblank_put only in case that drm_vblank_get was | ||
910 | * called. | ||
911 | */ | ||
912 | if (atomic_read(&drm_dev->vblank_refcount[crtc]) > 0) | ||
913 | drm_vblank_put(drm_dev, crtc); | ||
914 | |||
915 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); | 978 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); |
916 | } | 979 | } |
917 | 980 | ||
@@ -944,6 +1007,12 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) | |||
944 | 1007 | ||
945 | drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe); | 1008 | drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe); |
946 | mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe); | 1009 | mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe); |
1010 | |||
1011 | /* set wait vsync event to zero and wake up queue. */ | ||
1012 | if (atomic_read(&ctx->wait_vsync_event)) { | ||
1013 | atomic_set(&ctx->wait_vsync_event, 0); | ||
1014 | DRM_WAKEUP(&ctx->wait_vsync_queue); | ||
1015 | } | ||
947 | } | 1016 | } |
948 | 1017 | ||
949 | out: | 1018 | out: |
@@ -971,57 +1040,45 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, | |||
971 | 1040 | ||
972 | spin_lock_init(&mixer_res->reg_slock); | 1041 | spin_lock_init(&mixer_res->reg_slock); |
973 | 1042 | ||
974 | mixer_res->mixer = clk_get(dev, "mixer"); | 1043 | mixer_res->mixer = devm_clk_get(dev, "mixer"); |
975 | if (IS_ERR_OR_NULL(mixer_res->mixer)) { | 1044 | if (IS_ERR_OR_NULL(mixer_res->mixer)) { |
976 | dev_err(dev, "failed to get clock 'mixer'\n"); | 1045 | dev_err(dev, "failed to get clock 'mixer'\n"); |
977 | ret = -ENODEV; | 1046 | return -ENODEV; |
978 | goto fail; | ||
979 | } | 1047 | } |
980 | 1048 | ||
981 | mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi"); | 1049 | mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); |
982 | if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) { | 1050 | if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) { |
983 | dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); | 1051 | dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); |
984 | ret = -ENODEV; | 1052 | return -ENODEV; |
985 | goto fail; | ||
986 | } | 1053 | } |
987 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1054 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
988 | if (res == NULL) { | 1055 | if (res == NULL) { |
989 | dev_err(dev, "get memory resource failed.\n"); | 1056 | dev_err(dev, "get memory resource failed.\n"); |
990 | ret = -ENXIO; | 1057 | return -ENXIO; |
991 | goto fail; | ||
992 | } | 1058 | } |
993 | 1059 | ||
994 | mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start, | 1060 | mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start, |
995 | resource_size(res)); | 1061 | resource_size(res)); |
996 | if (mixer_res->mixer_regs == NULL) { | 1062 | if (mixer_res->mixer_regs == NULL) { |
997 | dev_err(dev, "register mapping failed.\n"); | 1063 | dev_err(dev, "register mapping failed.\n"); |
998 | ret = -ENXIO; | 1064 | return -ENXIO; |
999 | goto fail; | ||
1000 | } | 1065 | } |
1001 | 1066 | ||
1002 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 1067 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
1003 | if (res == NULL) { | 1068 | if (res == NULL) { |
1004 | dev_err(dev, "get interrupt resource failed.\n"); | 1069 | dev_err(dev, "get interrupt resource failed.\n"); |
1005 | ret = -ENXIO; | 1070 | return -ENXIO; |
1006 | goto fail; | ||
1007 | } | 1071 | } |
1008 | 1072 | ||
1009 | ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler, | 1073 | ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler, |
1010 | 0, "drm_mixer", ctx); | 1074 | 0, "drm_mixer", ctx); |
1011 | if (ret) { | 1075 | if (ret) { |
1012 | dev_err(dev, "request interrupt failed.\n"); | 1076 | dev_err(dev, "request interrupt failed.\n"); |
1013 | goto fail; | 1077 | return ret; |
1014 | } | 1078 | } |
1015 | mixer_res->irq = res->start; | 1079 | mixer_res->irq = res->start; |
1016 | 1080 | ||
1017 | return 0; | 1081 | return 0; |
1018 | |||
1019 | fail: | ||
1020 | if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) | ||
1021 | clk_put(mixer_res->sclk_hdmi); | ||
1022 | if (!IS_ERR_OR_NULL(mixer_res->mixer)) | ||
1023 | clk_put(mixer_res->mixer); | ||
1024 | return ret; | ||
1025 | } | 1082 | } |
1026 | 1083 | ||
1027 | static int __devinit vp_resources_init(struct exynos_drm_hdmi_context *ctx, | 1084 | static int __devinit vp_resources_init(struct exynos_drm_hdmi_context *ctx, |
@@ -1031,25 +1088,21 @@ static int __devinit vp_resources_init(struct exynos_drm_hdmi_context *ctx, | |||
1031 | struct device *dev = &pdev->dev; | 1088 | struct device *dev = &pdev->dev; |
1032 | struct mixer_resources *mixer_res = &mixer_ctx->mixer_res; | 1089 | struct mixer_resources *mixer_res = &mixer_ctx->mixer_res; |
1033 | struct resource *res; | 1090 | struct resource *res; |
1034 | int ret; | ||
1035 | 1091 | ||
1036 | mixer_res->vp = clk_get(dev, "vp"); | 1092 | mixer_res->vp = devm_clk_get(dev, "vp"); |
1037 | if (IS_ERR_OR_NULL(mixer_res->vp)) { | 1093 | if (IS_ERR_OR_NULL(mixer_res->vp)) { |
1038 | dev_err(dev, "failed to get clock 'vp'\n"); | 1094 | dev_err(dev, "failed to get clock 'vp'\n"); |
1039 | ret = -ENODEV; | 1095 | return -ENODEV; |
1040 | goto fail; | ||
1041 | } | 1096 | } |
1042 | mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer"); | 1097 | mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer"); |
1043 | if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) { | 1098 | if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) { |
1044 | dev_err(dev, "failed to get clock 'sclk_mixer'\n"); | 1099 | dev_err(dev, "failed to get clock 'sclk_mixer'\n"); |
1045 | ret = -ENODEV; | 1100 | return -ENODEV; |
1046 | goto fail; | ||
1047 | } | 1101 | } |
1048 | mixer_res->sclk_dac = clk_get(dev, "sclk_dac"); | 1102 | mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac"); |
1049 | if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) { | 1103 | if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) { |
1050 | dev_err(dev, "failed to get clock 'sclk_dac'\n"); | 1104 | dev_err(dev, "failed to get clock 'sclk_dac'\n"); |
1051 | ret = -ENODEV; | 1105 | return -ENODEV; |
1052 | goto fail; | ||
1053 | } | 1106 | } |
1054 | 1107 | ||
1055 | if (mixer_res->sclk_hdmi) | 1108 | if (mixer_res->sclk_hdmi) |
@@ -1058,28 +1111,17 @@ static int __devinit vp_resources_init(struct exynos_drm_hdmi_context *ctx, | |||
1058 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 1111 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
1059 | if (res == NULL) { | 1112 | if (res == NULL) { |
1060 | dev_err(dev, "get memory resource failed.\n"); | 1113 | dev_err(dev, "get memory resource failed.\n"); |
1061 | ret = -ENXIO; | 1114 | return -ENXIO; |
1062 | goto fail; | ||
1063 | } | 1115 | } |
1064 | 1116 | ||
1065 | mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start, | 1117 | mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start, |
1066 | resource_size(res)); | 1118 | resource_size(res)); |
1067 | if (mixer_res->vp_regs == NULL) { | 1119 | if (mixer_res->vp_regs == NULL) { |
1068 | dev_err(dev, "register mapping failed.\n"); | 1120 | dev_err(dev, "register mapping failed.\n"); |
1069 | ret = -ENXIO; | 1121 | return -ENXIO; |
1070 | goto fail; | ||
1071 | } | 1122 | } |
1072 | 1123 | ||
1073 | return 0; | 1124 | return 0; |
1074 | |||
1075 | fail: | ||
1076 | if (!IS_ERR_OR_NULL(mixer_res->sclk_dac)) | ||
1077 | clk_put(mixer_res->sclk_dac); | ||
1078 | if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer)) | ||
1079 | clk_put(mixer_res->sclk_mixer); | ||
1080 | if (!IS_ERR_OR_NULL(mixer_res->vp)) | ||
1081 | clk_put(mixer_res->vp); | ||
1082 | return ret; | ||
1083 | } | 1125 | } |
1084 | 1126 | ||
1085 | static struct mixer_drv_data exynos5_mxr_drv_data = { | 1127 | static struct mixer_drv_data exynos5_mxr_drv_data = { |
@@ -1149,9 +1191,12 @@ static int __devinit mixer_probe(struct platform_device *pdev) | |||
1149 | } | 1191 | } |
1150 | 1192 | ||
1151 | ctx->dev = &pdev->dev; | 1193 | ctx->dev = &pdev->dev; |
1194 | ctx->parent_ctx = (void *)drm_hdmi_ctx; | ||
1152 | drm_hdmi_ctx->ctx = (void *)ctx; | 1195 | drm_hdmi_ctx->ctx = (void *)ctx; |
1153 | ctx->vp_enabled = drv->is_vp_enabled; | 1196 | ctx->vp_enabled = drv->is_vp_enabled; |
1154 | ctx->mxr_ver = drv->version; | 1197 | ctx->mxr_ver = drv->version; |
1198 | DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue); | ||
1199 | atomic_set(&ctx->wait_vsync_event, 0); | ||
1155 | 1200 | ||
1156 | platform_set_drvdata(pdev, drm_hdmi_ctx); | 1201 | platform_set_drvdata(pdev, drm_hdmi_ctx); |
1157 | 1202 | ||
@@ -1202,13 +1247,66 @@ static int mixer_suspend(struct device *dev) | |||
1202 | struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); | 1247 | struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); |
1203 | struct mixer_context *ctx = drm_hdmi_ctx->ctx; | 1248 | struct mixer_context *ctx = drm_hdmi_ctx->ctx; |
1204 | 1249 | ||
1250 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
1251 | |||
1252 | if (pm_runtime_suspended(dev)) { | ||
1253 | DRM_DEBUG_KMS("%s : Already suspended\n", __func__); | ||
1254 | return 0; | ||
1255 | } | ||
1256 | |||
1205 | mixer_poweroff(ctx); | 1257 | mixer_poweroff(ctx); |
1206 | 1258 | ||
1207 | return 0; | 1259 | return 0; |
1208 | } | 1260 | } |
1261 | |||
1262 | static int mixer_resume(struct device *dev) | ||
1263 | { | ||
1264 | struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); | ||
1265 | struct mixer_context *ctx = drm_hdmi_ctx->ctx; | ||
1266 | |||
1267 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
1268 | |||
1269 | if (!pm_runtime_suspended(dev)) { | ||
1270 | DRM_DEBUG_KMS("%s : Already resumed\n", __func__); | ||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | mixer_poweron(ctx); | ||
1275 | |||
1276 | return 0; | ||
1277 | } | ||
1209 | #endif | 1278 | #endif |
1210 | 1279 | ||
1211 | static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL); | 1280 | #ifdef CONFIG_PM_RUNTIME |
1281 | static int mixer_runtime_suspend(struct device *dev) | ||
1282 | { | ||
1283 | struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); | ||
1284 | struct mixer_context *ctx = drm_hdmi_ctx->ctx; | ||
1285 | |||
1286 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
1287 | |||
1288 | mixer_poweroff(ctx); | ||
1289 | |||
1290 | return 0; | ||
1291 | } | ||
1292 | |||
1293 | static int mixer_runtime_resume(struct device *dev) | ||
1294 | { | ||
1295 | struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); | ||
1296 | struct mixer_context *ctx = drm_hdmi_ctx->ctx; | ||
1297 | |||
1298 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
1299 | |||
1300 | mixer_poweron(ctx); | ||
1301 | |||
1302 | return 0; | ||
1303 | } | ||
1304 | #endif | ||
1305 | |||
1306 | static const struct dev_pm_ops mixer_pm_ops = { | ||
1307 | SET_SYSTEM_SLEEP_PM_OPS(mixer_suspend, mixer_resume) | ||
1308 | SET_RUNTIME_PM_OPS(mixer_runtime_suspend, mixer_runtime_resume, NULL) | ||
1309 | }; | ||
1212 | 1310 | ||
1213 | struct platform_driver mixer_driver = { | 1311 | struct platform_driver mixer_driver = { |
1214 | .driver = { | 1312 | .driver = { |