aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/dss/dss.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss/dss.c')
-rw-r--r--drivers/video/omap2/dss/dss.c257
1 files changed, 167 insertions, 90 deletions
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 04b4586113e3..2ab1c3e96553 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -31,11 +31,11 @@
31#include <linux/clk.h> 31#include <linux/clk.h>
32#include <linux/platform_device.h> 32#include <linux/platform_device.h>
33#include <linux/pm_runtime.h> 33#include <linux/pm_runtime.h>
34#include <linux/gfp.h>
34 35
35#include <video/omapdss.h> 36#include <video/omapdss.h>
36 37
37#include <plat/cpu.h> 38#include <plat/cpu.h>
38#include <plat/clock.h>
39 39
40#include "dss.h" 40#include "dss.h"
41#include "dss_features.h" 41#include "dss_features.h"
@@ -65,6 +65,13 @@ struct dss_reg {
65static int dss_runtime_get(void); 65static int dss_runtime_get(void);
66static void dss_runtime_put(void); 66static void dss_runtime_put(void);
67 67
68struct dss_features {
69 u8 fck_div_max;
70 u8 dss_fck_multiplier;
71 const char *clk_name;
72 int (*dpi_select_source)(enum omap_channel channel);
73};
74
68static struct { 75static struct {
69 struct platform_device *pdev; 76 struct platform_device *pdev;
70 void __iomem *base; 77 void __iomem *base;
@@ -83,6 +90,8 @@ static struct {
83 90
84 bool ctx_valid; 91 bool ctx_valid;
85 u32 ctx[DSS_SZ_REGS / sizeof(u32)]; 92 u32 ctx[DSS_SZ_REGS / sizeof(u32)];
93
94 const struct dss_features *feat;
86} dss; 95} dss;
87 96
88static const char * const dss_generic_clk_source_names[] = { 97static const char * const dss_generic_clk_source_names[] = {
@@ -144,7 +153,7 @@ static void dss_restore_context(void)
144#undef SR 153#undef SR
145#undef RR 154#undef RR
146 155
147void dss_sdi_init(u8 datapairs) 156void dss_sdi_init(int datapairs)
148{ 157{
149 u32 l; 158 u32 l;
150 159
@@ -236,7 +245,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
236 return dss_generic_clk_source_names[clk_src]; 245 return dss_generic_clk_source_names[clk_src];
237} 246}
238 247
239
240void dss_dump_clocks(struct seq_file *s) 248void dss_dump_clocks(struct seq_file *s)
241{ 249{
242 unsigned long dpll4_ck_rate; 250 unsigned long dpll4_ck_rate;
@@ -259,18 +267,10 @@ void dss_dump_clocks(struct seq_file *s)
259 267
260 seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); 268 seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
261 269
262 if (cpu_is_omap3630() || cpu_is_omap44xx()) 270 seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n",
263 seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", 271 fclk_name, fclk_real_name, dpll4_ck_rate,
264 fclk_name, fclk_real_name, 272 dpll4_ck_rate / dpll4_m4_ck_rate,
265 dpll4_ck_rate, 273 dss.feat->dss_fck_multiplier, fclk_rate);
266 dpll4_ck_rate / dpll4_m4_ck_rate,
267 fclk_rate);
268 else
269 seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
270 fclk_name, fclk_real_name,
271 dpll4_ck_rate,
272 dpll4_ck_rate / dpll4_m4_ck_rate,
273 fclk_rate);
274 } else { 274 } else {
275 seq_printf(s, "%s (%s) = %lu\n", 275 seq_printf(s, "%s (%s) = %lu\n",
276 fclk_name, fclk_real_name, 276 fclk_name, fclk_real_name,
@@ -431,31 +431,6 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
431 } 431 }
432} 432}
433 433
434/* calculate clock rates using dividers in cinfo */
435int dss_calc_clock_rates(struct dss_clock_info *cinfo)
436{
437 if (dss.dpll4_m4_ck) {
438 unsigned long prate;
439 u16 fck_div_max = 16;
440
441 if (cpu_is_omap3630() || cpu_is_omap44xx())
442 fck_div_max = 32;
443
444 if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0)
445 return -EINVAL;
446
447 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
448
449 cinfo->fck = prate / cinfo->fck_div;
450 } else {
451 if (cinfo->fck_div != 0)
452 return -EINVAL;
453 cinfo->fck = clk_get_rate(dss.dss_clk);
454 }
455
456 return 0;
457}
458
459int dss_set_clock_div(struct dss_clock_info *cinfo) 434int dss_set_clock_div(struct dss_clock_info *cinfo)
460{ 435{
461 if (dss.dpll4_m4_ck) { 436 if (dss.dpll4_m4_ck) {
@@ -478,26 +453,6 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
478 return 0; 453 return 0;
479} 454}
480 455
481int dss_get_clock_div(struct dss_clock_info *cinfo)
482{
483 cinfo->fck = clk_get_rate(dss.dss_clk);
484
485 if (dss.dpll4_m4_ck) {
486 unsigned long prate;
487
488 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
489
490 if (cpu_is_omap3630() || cpu_is_omap44xx())
491 cinfo->fck_div = prate / (cinfo->fck);
492 else
493 cinfo->fck_div = prate / (cinfo->fck / 2);
494 } else {
495 cinfo->fck_div = 0;
496 }
497
498 return 0;
499}
500
501unsigned long dss_get_dpll4_rate(void) 456unsigned long dss_get_dpll4_rate(void)
502{ 457{
503 if (dss.dpll4_m4_ck) 458 if (dss.dpll4_m4_ck)
@@ -515,7 +470,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
515 470
516 unsigned long fck, max_dss_fck; 471 unsigned long fck, max_dss_fck;
517 472
518 u16 fck_div, fck_div_max = 16; 473 u16 fck_div;
519 474
520 int match = 0; 475 int match = 0;
521 int min_fck_per_pck; 476 int min_fck_per_pck;
@@ -525,9 +480,8 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
525 max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); 480 max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
526 481
527 fck = clk_get_rate(dss.dss_clk); 482 fck = clk_get_rate(dss.dss_clk);
528 if (req_pck == dss.cache_req_pck && 483 if (req_pck == dss.cache_req_pck && prate == dss.cache_prate &&
529 ((cpu_is_omap34xx() && prate == dss.cache_prate) || 484 dss.cache_dss_cinfo.fck == fck) {
530 dss.cache_dss_cinfo.fck == fck)) {
531 DSSDBG("dispc clock info found from cache.\n"); 485 DSSDBG("dispc clock info found from cache.\n");
532 *dss_cinfo = dss.cache_dss_cinfo; 486 *dss_cinfo = dss.cache_dss_cinfo;
533 *dispc_cinfo = dss.cache_dispc_cinfo; 487 *dispc_cinfo = dss.cache_dispc_cinfo;
@@ -564,16 +518,10 @@ retry:
564 518
565 goto found; 519 goto found;
566 } else { 520 } else {
567 if (cpu_is_omap3630() || cpu_is_omap44xx()) 521 for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) {
568 fck_div_max = 32;
569
570 for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
571 struct dispc_clock_info cur_dispc; 522 struct dispc_clock_info cur_dispc;
572 523
573 if (fck_div_max == 32) 524 fck = prate / fck_div * dss.feat->dss_fck_multiplier;
574 fck = prate / fck_div;
575 else
576 fck = prate / fck_div * 2;
577 525
578 if (fck > max_dss_fck) 526 if (fck > max_dss_fck)
579 continue; 527 continue;
@@ -648,9 +596,18 @@ void dss_set_dac_pwrdn_bgz(bool enable)
648 REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ 596 REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
649} 597}
650 598
651void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) 599void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)
652{ 600{
653 REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ 601 enum omap_display_type dp;
602 dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
603
604 /* Complain about invalid selections */
605 WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC));
606 WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI));
607
608 /* Select only if we have options */
609 if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI))
610 REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */
654} 611}
655 612
656enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) 613enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
@@ -661,9 +618,71 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
661 if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0) 618 if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
662 return DSS_VENC_TV_CLK; 619 return DSS_VENC_TV_CLK;
663 620
621 if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0)
622 return DSS_HDMI_M_PCLK;
623
664 return REG_GET(DSS_CONTROL, 15, 15); 624 return REG_GET(DSS_CONTROL, 15, 15);
665} 625}
666 626
627static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
628{
629 if (channel != OMAP_DSS_CHANNEL_LCD)
630 return -EINVAL;
631
632 return 0;
633}
634
635static int dss_dpi_select_source_omap4(enum omap_channel channel)
636{
637 int val;
638
639 switch (channel) {
640 case OMAP_DSS_CHANNEL_LCD2:
641 val = 0;
642 break;
643 case OMAP_DSS_CHANNEL_DIGIT:
644 val = 1;
645 break;
646 default:
647 return -EINVAL;
648 }
649
650 REG_FLD_MOD(DSS_CONTROL, val, 17, 17);
651
652 return 0;
653}
654
655static int dss_dpi_select_source_omap5(enum omap_channel channel)
656{
657 int val;
658
659 switch (channel) {
660 case OMAP_DSS_CHANNEL_LCD:
661 val = 1;
662 break;
663 case OMAP_DSS_CHANNEL_LCD2:
664 val = 2;
665 break;
666 case OMAP_DSS_CHANNEL_LCD3:
667 val = 3;
668 break;
669 case OMAP_DSS_CHANNEL_DIGIT:
670 val = 0;
671 break;
672 default:
673 return -EINVAL;
674 }
675
676 REG_FLD_MOD(DSS_CONTROL, val, 17, 16);
677
678 return 0;
679}
680
681int dss_dpi_select_source(enum omap_channel channel)
682{
683 return dss.feat->dpi_select_source(channel);
684}
685
667static int dss_get_clocks(void) 686static int dss_get_clocks(void)
668{ 687{
669 struct clk *clk; 688 struct clk *clk;
@@ -678,22 +697,11 @@ static int dss_get_clocks(void)
678 697
679 dss.dss_clk = clk; 698 dss.dss_clk = clk;
680 699
681 if (cpu_is_omap34xx()) { 700 clk = clk_get(NULL, dss.feat->clk_name);
682 clk = clk_get(NULL, "dpll4_m4_ck"); 701 if (IS_ERR(clk)) {
683 if (IS_ERR(clk)) { 702 DSSERR("Failed to get %s\n", dss.feat->clk_name);
684 DSSERR("Failed to get dpll4_m4_ck\n"); 703 r = PTR_ERR(clk);
685 r = PTR_ERR(clk); 704 goto err;
686 goto err;
687 }
688 } else if (cpu_is_omap44xx()) {
689 clk = clk_get(NULL, "dpll_per_m5x2_ck");
690 if (IS_ERR(clk)) {
691 DSSERR("Failed to get dpll_per_m5x2_ck\n");
692 r = PTR_ERR(clk);
693 goto err;
694 }
695 } else { /* omap24xx */
696 clk = NULL;
697 } 705 }
698 706
699 dss.dpll4_m4_ck = clk; 707 dss.dpll4_m4_ck = clk;
@@ -749,6 +757,71 @@ void dss_debug_dump_clocks(struct seq_file *s)
749} 757}
750#endif 758#endif
751 759
760static const struct dss_features omap24xx_dss_feats __initconst = {
761 .fck_div_max = 16,
762 .dss_fck_multiplier = 2,
763 .clk_name = NULL,
764 .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
765};
766
767static const struct dss_features omap34xx_dss_feats __initconst = {
768 .fck_div_max = 16,
769 .dss_fck_multiplier = 2,
770 .clk_name = "dpll4_m4_ck",
771 .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
772};
773
774static const struct dss_features omap3630_dss_feats __initconst = {
775 .fck_div_max = 32,
776 .dss_fck_multiplier = 1,
777 .clk_name = "dpll4_m4_ck",
778 .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
779};
780
781static const struct dss_features omap44xx_dss_feats __initconst = {
782 .fck_div_max = 32,
783 .dss_fck_multiplier = 1,
784 .clk_name = "dpll_per_m5x2_ck",
785 .dpi_select_source = &dss_dpi_select_source_omap4,
786};
787
788static const struct dss_features omap54xx_dss_feats __initconst = {
789 .fck_div_max = 64,
790 .dss_fck_multiplier = 1,
791 .clk_name = "dpll_per_h12x2_ck",
792 .dpi_select_source = &dss_dpi_select_source_omap5,
793};
794
795static int __init dss_init_features(struct device *dev)
796{
797 const struct dss_features *src;
798 struct dss_features *dst;
799
800 dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL);
801 if (!dst) {
802 dev_err(dev, "Failed to allocate local DSS Features\n");
803 return -ENOMEM;
804 }
805
806 if (cpu_is_omap24xx())
807 src = &omap24xx_dss_feats;
808 else if (cpu_is_omap34xx())
809 src = &omap34xx_dss_feats;
810 else if (cpu_is_omap3630())
811 src = &omap3630_dss_feats;
812 else if (cpu_is_omap44xx())
813 src = &omap44xx_dss_feats;
814 else if (soc_is_omap54xx())
815 src = &omap54xx_dss_feats;
816 else
817 return -ENODEV;
818
819 memcpy(dst, src, sizeof(*dst));
820 dss.feat = dst;
821
822 return 0;
823}
824
752/* DSS HW IP initialisation */ 825/* DSS HW IP initialisation */
753static int __init omap_dsshw_probe(struct platform_device *pdev) 826static int __init omap_dsshw_probe(struct platform_device *pdev)
754{ 827{
@@ -758,6 +831,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
758 831
759 dss.pdev = pdev; 832 dss.pdev = pdev;
760 833
834 r = dss_init_features(&dss.pdev->dev);
835 if (r)
836 return r;
837
761 dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); 838 dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
762 if (!dss_mem) { 839 if (!dss_mem) {
763 DSSERR("can't get IORESOURCE_MEM DSS\n"); 840 DSSERR("can't get IORESOURCE_MEM DSS\n");