aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/dss/venc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss/venc.c')
-rw-r--r--drivers/video/omap2/dss/venc.c183
1 files changed, 146 insertions, 37 deletions
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 980f919ed987..173c66430dad 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -33,11 +33,13 @@
33#include <linux/seq_file.h> 33#include <linux/seq_file.h>
34#include <linux/platform_device.h> 34#include <linux/platform_device.h>
35#include <linux/regulator/consumer.h> 35#include <linux/regulator/consumer.h>
36#include <linux/pm_runtime.h>
36 37
37#include <video/omapdss.h> 38#include <video/omapdss.h>
38#include <plat/cpu.h> 39#include <plat/cpu.h>
39 40
40#include "dss.h" 41#include "dss.h"
42#include "dss_features.h"
41 43
42/* Venc registers */ 44/* Venc registers */
43#define VENC_REV_ID 0x00 45#define VENC_REV_ID 0x00
@@ -292,6 +294,9 @@ static struct {
292 struct mutex venc_lock; 294 struct mutex venc_lock;
293 u32 wss_data; 295 u32 wss_data;
294 struct regulator *vdda_dac_reg; 296 struct regulator *vdda_dac_reg;
297
298 struct clk *tv_clk;
299 struct clk *tv_dac_clk;
295} venc; 300} venc;
296 301
297static inline void venc_write_reg(int idx, u32 val) 302static inline void venc_write_reg(int idx, u32 val)
@@ -380,14 +385,25 @@ static void venc_reset(void)
380#endif 385#endif
381} 386}
382 387
383static void venc_enable_clocks(int enable) 388static int venc_runtime_get(void)
389{
390 int r;
391
392 DSSDBG("venc_runtime_get\n");
393
394 r = pm_runtime_get_sync(&venc.pdev->dev);
395 WARN_ON(r < 0);
396 return r < 0 ? r : 0;
397}
398
399static void venc_runtime_put(void)
384{ 400{
385 if (enable) 401 int r;
386 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK | 402
387 DSS_CLK_VIDFCK); 403 DSSDBG("venc_runtime_put\n");
388 else 404
389 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK | 405 r = pm_runtime_put(&venc.pdev->dev);
390 DSS_CLK_VIDFCK); 406 WARN_ON(r < 0);
391} 407}
392 408
393static const struct venc_config *venc_timings_to_config( 409static const struct venc_config *venc_timings_to_config(
@@ -406,8 +422,6 @@ static void venc_power_on(struct omap_dss_device *dssdev)
406{ 422{
407 u32 l; 423 u32 l;
408 424
409 venc_enable_clocks(1);
410
411 venc_reset(); 425 venc_reset();
412 venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); 426 venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
413 427
@@ -448,8 +462,6 @@ static void venc_power_off(struct omap_dss_device *dssdev)
448 dssdev->platform_disable(dssdev); 462 dssdev->platform_disable(dssdev);
449 463
450 regulator_disable(venc.vdda_dac_reg); 464 regulator_disable(venc.vdda_dac_reg);
451
452 venc_enable_clocks(0);
453} 465}
454 466
455 467
@@ -487,6 +499,10 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
487 goto err1; 499 goto err1;
488 } 500 }
489 501
502 r = venc_runtime_get();
503 if (r)
504 goto err1;
505
490 venc_power_on(dssdev); 506 venc_power_on(dssdev);
491 507
492 venc.wss_data = 0; 508 venc.wss_data = 0;
@@ -520,6 +536,8 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
520 536
521 venc_power_off(dssdev); 537 venc_power_off(dssdev);
522 538
539 venc_runtime_put();
540
523 dssdev->state = OMAP_DSS_DISPLAY_DISABLED; 541 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
524 542
525 omap_dss_stop_device(dssdev); 543 omap_dss_stop_device(dssdev);
@@ -538,20 +556,6 @@ static int venc_panel_resume(struct omap_dss_device *dssdev)
538 return venc_panel_enable(dssdev); 556 return venc_panel_enable(dssdev);
539} 557}
540 558
541static enum omap_dss_update_mode venc_get_update_mode(
542 struct omap_dss_device *dssdev)
543{
544 return OMAP_DSS_UPDATE_AUTO;
545}
546
547static int venc_set_update_mode(struct omap_dss_device *dssdev,
548 enum omap_dss_update_mode mode)
549{
550 if (mode != OMAP_DSS_UPDATE_AUTO)
551 return -EINVAL;
552 return 0;
553}
554
555static void venc_get_timings(struct omap_dss_device *dssdev, 559static void venc_get_timings(struct omap_dss_device *dssdev,
556 struct omap_video_timings *timings) 560 struct omap_video_timings *timings)
557{ 561{
@@ -598,6 +602,7 @@ static u32 venc_get_wss(struct omap_dss_device *dssdev)
598static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) 602static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
599{ 603{
600 const struct venc_config *config; 604 const struct venc_config *config;
605 int r;
601 606
602 DSSDBG("venc_set_wss\n"); 607 DSSDBG("venc_set_wss\n");
603 608
@@ -608,16 +613,19 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
608 /* Invert due to VENC_L21_WC_CTL:INV=1 */ 613 /* Invert due to VENC_L21_WC_CTL:INV=1 */
609 venc.wss_data = (wss ^ 0xfffff) << 8; 614 venc.wss_data = (wss ^ 0xfffff) << 8;
610 615
611 venc_enable_clocks(1); 616 r = venc_runtime_get();
617 if (r)
618 goto err;
612 619
613 venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | 620 venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
614 venc.wss_data); 621 venc.wss_data);
615 622
616 venc_enable_clocks(0); 623 venc_runtime_put();
617 624
625err:
618 mutex_unlock(&venc.venc_lock); 626 mutex_unlock(&venc.venc_lock);
619 627
620 return 0; 628 return r;
621} 629}
622 630
623static struct omap_dss_driver venc_driver = { 631static struct omap_dss_driver venc_driver = {
@@ -632,9 +640,6 @@ static struct omap_dss_driver venc_driver = {
632 .get_resolution = omapdss_default_get_resolution, 640 .get_resolution = omapdss_default_get_resolution,
633 .get_recommended_bpp = omapdss_default_get_recommended_bpp, 641 .get_recommended_bpp = omapdss_default_get_recommended_bpp,
634 642
635 .set_update_mode = venc_set_update_mode,
636 .get_update_mode = venc_get_update_mode,
637
638 .get_timings = venc_get_timings, 643 .get_timings = venc_get_timings,
639 .set_timings = venc_set_timings, 644 .set_timings = venc_set_timings,
640 .check_timings = venc_check_timings, 645 .check_timings = venc_check_timings,
@@ -673,7 +678,8 @@ void venc_dump_regs(struct seq_file *s)
673{ 678{
674#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) 679#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
675 680
676 venc_enable_clocks(1); 681 if (venc_runtime_get())
682 return;
677 683
678 DUMPREG(VENC_F_CONTROL); 684 DUMPREG(VENC_F_CONTROL);
679 DUMPREG(VENC_VIDOUT_CTRL); 685 DUMPREG(VENC_VIDOUT_CTRL);
@@ -717,16 +723,56 @@ void venc_dump_regs(struct seq_file *s)
717 DUMPREG(VENC_OUTPUT_CONTROL); 723 DUMPREG(VENC_OUTPUT_CONTROL);
718 DUMPREG(VENC_OUTPUT_TEST); 724 DUMPREG(VENC_OUTPUT_TEST);
719 725
720 venc_enable_clocks(0); 726 venc_runtime_put();
721 727
722#undef DUMPREG 728#undef DUMPREG
723} 729}
724 730
731static int venc_get_clocks(struct platform_device *pdev)
732{
733 struct clk *clk;
734
735 clk = clk_get(&pdev->dev, "fck");
736 if (IS_ERR(clk)) {
737 DSSERR("can't get fck\n");
738 return PTR_ERR(clk);
739 }
740
741 venc.tv_clk = clk;
742
743 if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
744 if (cpu_is_omap34xx() || cpu_is_omap3630())
745 clk = clk_get(&pdev->dev, "dss_96m_fck");
746 else
747 clk = clk_get(&pdev->dev, "tv_dac_clk");
748 if (IS_ERR(clk)) {
749 DSSERR("can't get tv_dac_clk\n");
750 clk_put(venc.tv_clk);
751 return PTR_ERR(clk);
752 }
753 } else {
754 clk = NULL;
755 }
756
757 venc.tv_dac_clk = clk;
758
759 return 0;
760}
761
762static void venc_put_clocks(void)
763{
764 if (venc.tv_clk)
765 clk_put(venc.tv_clk);
766 if (venc.tv_dac_clk)
767 clk_put(venc.tv_dac_clk);
768}
769
725/* VENC HW IP initialisation */ 770/* VENC HW IP initialisation */
726static int omap_venchw_probe(struct platform_device *pdev) 771static int omap_venchw_probe(struct platform_device *pdev)
727{ 772{
728 u8 rev_id; 773 u8 rev_id;
729 struct resource *venc_mem; 774 struct resource *venc_mem;
775 int r;
730 776
731 venc.pdev = pdev; 777 venc.pdev = pdev;
732 778
@@ -737,22 +783,40 @@ static int omap_venchw_probe(struct platform_device *pdev)
737 venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0); 783 venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
738 if (!venc_mem) { 784 if (!venc_mem) {
739 DSSERR("can't get IORESOURCE_MEM VENC\n"); 785 DSSERR("can't get IORESOURCE_MEM VENC\n");
740 return -EINVAL; 786 r = -EINVAL;
787 goto err_ioremap;
741 } 788 }
742 venc.base = ioremap(venc_mem->start, resource_size(venc_mem)); 789 venc.base = ioremap(venc_mem->start, resource_size(venc_mem));
743 if (!venc.base) { 790 if (!venc.base) {
744 DSSERR("can't ioremap VENC\n"); 791 DSSERR("can't ioremap VENC\n");
745 return -ENOMEM; 792 r = -ENOMEM;
793 goto err_ioremap;
746 } 794 }
747 795
748 venc_enable_clocks(1); 796 r = venc_get_clocks(pdev);
797 if (r)
798 goto err_get_clk;
799
800 pm_runtime_enable(&pdev->dev);
801
802 r = venc_runtime_get();
803 if (r)
804 goto err_get_venc;
749 805
750 rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); 806 rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
751 dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id); 807 dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
752 808
753 venc_enable_clocks(0); 809 venc_runtime_put();
754 810
755 return omap_dss_register_driver(&venc_driver); 811 return omap_dss_register_driver(&venc_driver);
812
813err_get_venc:
814 pm_runtime_disable(&pdev->dev);
815 venc_put_clocks();
816err_get_clk:
817 iounmap(venc.base);
818err_ioremap:
819 return r;
756} 820}
757 821
758static int omap_venchw_remove(struct platform_device *pdev) 822static int omap_venchw_remove(struct platform_device *pdev)
@@ -763,16 +827,61 @@ static int omap_venchw_remove(struct platform_device *pdev)
763 } 827 }
764 omap_dss_unregister_driver(&venc_driver); 828 omap_dss_unregister_driver(&venc_driver);
765 829
830 pm_runtime_disable(&pdev->dev);
831 venc_put_clocks();
832
766 iounmap(venc.base); 833 iounmap(venc.base);
767 return 0; 834 return 0;
768} 835}
769 836
837static int venc_runtime_suspend(struct device *dev)
838{
839 if (venc.tv_dac_clk)
840 clk_disable(venc.tv_dac_clk);
841 clk_disable(venc.tv_clk);
842
843 dispc_runtime_put();
844 dss_runtime_put();
845
846 return 0;
847}
848
849static int venc_runtime_resume(struct device *dev)
850{
851 int r;
852
853 r = dss_runtime_get();
854 if (r < 0)
855 goto err_get_dss;
856
857 r = dispc_runtime_get();
858 if (r < 0)
859 goto err_get_dispc;
860
861 clk_enable(venc.tv_clk);
862 if (venc.tv_dac_clk)
863 clk_enable(venc.tv_dac_clk);
864
865 return 0;
866
867err_get_dispc:
868 dss_runtime_put();
869err_get_dss:
870 return r;
871}
872
873static const struct dev_pm_ops venc_pm_ops = {
874 .runtime_suspend = venc_runtime_suspend,
875 .runtime_resume = venc_runtime_resume,
876};
877
770static struct platform_driver omap_venchw_driver = { 878static struct platform_driver omap_venchw_driver = {
771 .probe = omap_venchw_probe, 879 .probe = omap_venchw_probe,
772 .remove = omap_venchw_remove, 880 .remove = omap_venchw_remove,
773 .driver = { 881 .driver = {
774 .name = "omapdss_venc", 882 .name = "omapdss_venc",
775 .owner = THIS_MODULE, 883 .owner = THIS_MODULE,
884 .pm = &venc_pm_ops,
776 }, 885 },
777}; 886};
778 887