aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/exynos/exynos_mixer.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2012-12-16 00:49:46 -0500
committerDave Airlie <airlied@redhat.com>2012-12-16 00:49:46 -0500
commit2f3f24061c5c489074ad492bf694a5a76ebd8fc5 (patch)
treea02e00a7e98a4fa543b1e7fc4eda2fbd62d16b6d /drivers/gpu/drm/exynos/exynos_mixer.c
parent652a187664902399d34f5b3a084fdbb51b2ca12f (diff)
parentf2646380655b32481b5e76c666e1793dfef184bd (diff)
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
Inki writes: "- add dmabuf attach/detach feature . This patch would resolve performance deterioration issue when v4l2-based driver is using the buffer imported from gem. - drm/exynos: use DMA_ATTR_NO_KERNEL_MAPPING attribute . With gem allocation, kernel space mapping isn't allocated and also physical pages aren't mapped with the kernel space. The physical pages are mapped with kernel space though vmap function only for console framebuffer. - add the below two patches I missed. drm: exynos: moved exynos drm device registration to drm driver drm: exynos: moved exynos drm hdmi device registration to drm driver - add IPP subsystem framework and its-based device drivers. . This patch set includes fimc, rotator and gsc drivers to perform image scaling, rotation and color space conversion. - add runtime pm support to hdmi driver. - And fixups and cleanups." * 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (30 commits) drm/exynos: add gsc ipp driver drm/exynos: add rotator ipp driver drm/exynos: add fimc ipp driver drm/exynos: add iommu support for ipp drm/exynos: add ipp subsystem drm/exynos: support device tree for fimd drm/exynos: support extended screen coordinate of fimd drm/exynos: fix x, y coordinates for right bottom pixel drm/exynos: fix fb offset calculation for plane drm/exynos: hdmi: Fix potential NULL pointer dereference error drm/exynos: hdmi: Add CONFIG_OF and use of_match_ptr() macro drm/exynos: add support for hdmiphy power control for exynos5 drm/exynos: add runtime pm support for mixer drm/exynos: added runtime pm support for hdmi drm/exynos: fix allocation and cache mapping type drm/exynos: reorder framebuffer init sequence drm/exynos/iommu: fix return value check in drm_create_iommu_mapping() drm/exynos: remove unused vaddr member drm/exynos: use DMA_ATTR_NO_KERNEL_MAPPING attribute drm/exynos: add exception codes to exynos_drm_fbdev_create() ...
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_mixer.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c297
1 files changed, 204 insertions, 93 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 40a6e1906fbb..21db89530fc7 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -42,9 +42,7 @@
42 42
43struct hdmi_win_data { 43struct hdmi_win_data {
44 dma_addr_t dma_addr; 44 dma_addr_t dma_addr;
45 void __iomem *vaddr;
46 dma_addr_t chroma_dma_addr; 45 dma_addr_t chroma_dma_addr;
47 void __iomem *chroma_vaddr;
48 uint32_t pixel_format; 46 uint32_t pixel_format;
49 unsigned int bpp; 47 unsigned int bpp;
50 unsigned int crtc_x; 48 unsigned int crtc_x;
@@ -60,6 +58,8 @@ struct hdmi_win_data {
60 unsigned int mode_width; 58 unsigned int mode_width;
61 unsigned int mode_height; 59 unsigned int mode_height;
62 unsigned int scan_flags; 60 unsigned int scan_flags;
61 bool enabled;
62 bool resume;
63}; 63};
64 64
65struct mixer_resources { 65struct mixer_resources {
@@ -93,6 +93,8 @@ struct mixer_context {
93 struct hdmi_win_data win_data[MIXER_WIN_NR]; 93 struct hdmi_win_data win_data[MIXER_WIN_NR];
94 enum mixer_version_id mxr_ver; 94 enum mixer_version_id mxr_ver;
95 void *parent_ctx; 95 void *parent_ctx;
96 wait_queue_head_t wait_vsync_queue;
97 atomic_t wait_vsync_event;
96}; 98};
97 99
98struct mixer_drv_data { 100struct mixer_drv_data {
@@ -686,60 +688,6 @@ static int mixer_iommu_on(void *ctx, bool enable)
686 return 0; 688 return 0;
687} 689}
688 690
689static void mixer_poweron(struct mixer_context *ctx)
690{
691 struct mixer_resources *res = &ctx->mixer_res;
692
693 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
694
695 mutex_lock(&ctx->mixer_mutex);
696 if (ctx->powered) {
697 mutex_unlock(&ctx->mixer_mutex);
698 return;
699 }
700 ctx->powered = true;
701 mutex_unlock(&ctx->mixer_mutex);
702
703 pm_runtime_get_sync(ctx->dev);
704
705 clk_enable(res->mixer);
706 if (ctx->vp_enabled) {
707 clk_enable(res->vp);
708 clk_enable(res->sclk_mixer);
709 }
710
711 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
712 mixer_win_reset(ctx);
713}
714
715static void mixer_poweroff(struct mixer_context *ctx)
716{
717 struct mixer_resources *res = &ctx->mixer_res;
718
719 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
720
721 mutex_lock(&ctx->mixer_mutex);
722 if (!ctx->powered)
723 goto out;
724 mutex_unlock(&ctx->mixer_mutex);
725
726 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
727
728 clk_disable(res->mixer);
729 if (ctx->vp_enabled) {
730 clk_disable(res->vp);
731 clk_disable(res->sclk_mixer);
732 }
733
734 pm_runtime_put_sync(ctx->dev);
735
736 mutex_lock(&ctx->mixer_mutex);
737 ctx->powered = false;
738
739out:
740 mutex_unlock(&ctx->mixer_mutex);
741}
742
743static int mixer_enable_vblank(void *ctx, int pipe) 691static int mixer_enable_vblank(void *ctx, int pipe)
744{ 692{
745 struct mixer_context *mixer_ctx = ctx; 693 struct mixer_context *mixer_ctx = ctx;
@@ -767,39 +715,6 @@ static void mixer_disable_vblank(void *ctx)
767 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);
768} 716}
769 717
770static void mixer_dpms(void *ctx, int mode)
771{
772 struct mixer_context *mixer_ctx = ctx;
773
774 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
775
776 switch (mode) {
777 case DRM_MODE_DPMS_ON:
778 mixer_poweron(mixer_ctx);
779 break;
780 case DRM_MODE_DPMS_STANDBY:
781 case DRM_MODE_DPMS_SUSPEND:
782 case DRM_MODE_DPMS_OFF:
783 mixer_poweroff(mixer_ctx);
784 break;
785 default:
786 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
787 break;
788 }
789}
790
791static void mixer_wait_for_vblank(void *ctx)
792{
793 struct mixer_context *mixer_ctx = ctx;
794 struct mixer_resources *res = &mixer_ctx->mixer_res;
795 int ret;
796
797 ret = wait_for((mixer_reg_read(res, MXR_INT_STATUS) &
798 MXR_INT_STATUS_VSYNC), 50);
799 if (ret < 0)
800 DRM_DEBUG_KMS("vblank wait timed out.\n");
801}
802
803static void mixer_win_mode_set(void *ctx, 718static void mixer_win_mode_set(void *ctx,
804 struct exynos_drm_overlay *overlay) 719 struct exynos_drm_overlay *overlay)
805{ 720{
@@ -832,9 +747,7 @@ static void mixer_win_mode_set(void *ctx,
832 win_data = &mixer_ctx->win_data[win]; 747 win_data = &mixer_ctx->win_data[win];
833 748
834 win_data->dma_addr = overlay->dma_addr[0]; 749 win_data->dma_addr = overlay->dma_addr[0];
835 win_data->vaddr = overlay->vaddr[0];
836 win_data->chroma_dma_addr = overlay->dma_addr[1]; 750 win_data->chroma_dma_addr = overlay->dma_addr[1];
837 win_data->chroma_vaddr = overlay->vaddr[1];
838 win_data->pixel_format = overlay->pixel_format; 751 win_data->pixel_format = overlay->pixel_format;
839 win_data->bpp = overlay->bpp; 752 win_data->bpp = overlay->bpp;
840 753
@@ -866,6 +779,8 @@ static void mixer_win_commit(void *ctx, int win)
866 vp_video_buffer(mixer_ctx, win); 779 vp_video_buffer(mixer_ctx, win);
867 else 780 else
868 mixer_graph_buffer(mixer_ctx, win); 781 mixer_graph_buffer(mixer_ctx, win);
782
783 mixer_ctx->win_data[win].enabled = true;
869} 784}
870 785
871static void mixer_win_disable(void *ctx, int win) 786static void mixer_win_disable(void *ctx, int win)
@@ -876,6 +791,14 @@ static void mixer_win_disable(void *ctx, int win)
876 791
877 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); 792 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
878 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
879 spin_lock_irqsave(&res->reg_slock, flags); 802 spin_lock_irqsave(&res->reg_slock, flags);
880 mixer_vsync_set_update(mixer_ctx, false); 803 mixer_vsync_set_update(mixer_ctx, false);
881 804
@@ -883,6 +806,133 @@ static void mixer_win_disable(void *ctx, int win)
883 806
884 mixer_vsync_set_update(mixer_ctx, true); 807 mixer_vsync_set_update(mixer_ctx, true);
885 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
813static 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
836static 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
849static 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
861static 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
887static 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
911out:
912 mutex_unlock(&ctx->mixer_mutex);
913}
914
915static 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 }
886} 936}
887 937
888static struct exynos_mixer_ops mixer_ops = { 938static struct exynos_mixer_ops mixer_ops = {
@@ -890,10 +940,10 @@ static struct exynos_mixer_ops mixer_ops = {
890 .iommu_on = mixer_iommu_on, 940 .iommu_on = mixer_iommu_on,
891 .enable_vblank = mixer_enable_vblank, 941 .enable_vblank = mixer_enable_vblank,
892 .disable_vblank = mixer_disable_vblank, 942 .disable_vblank = mixer_disable_vblank,
943 .wait_for_vblank = mixer_wait_for_vblank,
893 .dpms = mixer_dpms, 944 .dpms = mixer_dpms,
894 945
895 /* overlay */ 946 /* overlay */
896 .wait_for_vblank = mixer_wait_for_vblank,
897 .win_mode_set = mixer_win_mode_set, 947 .win_mode_set = mixer_win_mode_set,
898 .win_commit = mixer_win_commit, 948 .win_commit = mixer_win_commit,
899 .win_disable = mixer_win_disable, 949 .win_disable = mixer_win_disable,
@@ -957,6 +1007,12 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
957 1007
958 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe); 1008 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
959 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 }
960 } 1016 }
961 1017
962out: 1018out:
@@ -1139,6 +1195,8 @@ static int __devinit mixer_probe(struct platform_device *pdev)
1139 drm_hdmi_ctx->ctx = (void *)ctx; 1195 drm_hdmi_ctx->ctx = (void *)ctx;
1140 ctx->vp_enabled = drv->is_vp_enabled; 1196 ctx->vp_enabled = drv->is_vp_enabled;
1141 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);
1142 1200
1143 platform_set_drvdata(pdev, drm_hdmi_ctx); 1201 platform_set_drvdata(pdev, drm_hdmi_ctx);
1144 1202
@@ -1189,13 +1247,66 @@ static int mixer_suspend(struct device *dev)
1189 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);
1190 struct mixer_context *ctx = drm_hdmi_ctx->ctx; 1248 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1191 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
1192 mixer_poweroff(ctx); 1257 mixer_poweroff(ctx);
1193 1258
1194 return 0; 1259 return 0;
1195} 1260}
1261
1262static 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}
1196#endif 1278#endif
1197 1279
1198static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL); 1280#ifdef CONFIG_PM_RUNTIME
1281static 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
1293static 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
1306static 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};
1199 1310
1200struct platform_driver mixer_driver = { 1311struct platform_driver mixer_driver = {
1201 .driver = { 1312 .driver = {