diff options
| -rw-r--r-- | drivers/video/omap2/dss/dss.c | 120 |
1 files changed, 79 insertions, 41 deletions
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index e2e0fa453c66..31a553a6ee6f 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c | |||
| @@ -31,6 +31,7 @@ | |||
| 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 | ||
| @@ -65,6 +66,12 @@ struct dss_reg { | |||
| 65 | static int dss_runtime_get(void); | 66 | static int dss_runtime_get(void); |
| 66 | static void dss_runtime_put(void); | 67 | static void dss_runtime_put(void); |
| 67 | 68 | ||
| 69 | struct dss_features { | ||
| 70 | u8 fck_div_max; | ||
| 71 | u8 dss_fck_multiplier; | ||
| 72 | const char *clk_name; | ||
| 73 | }; | ||
| 74 | |||
| 68 | static struct { | 75 | static 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 | ||
| 88 | static const char * const dss_generic_clk_source_names[] = { | 97 | static const char * const dss_generic_clk_source_names[] = { |
| @@ -91,6 +100,30 @@ static const char * const dss_generic_clk_source_names[] = { | |||
| 91 | [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", | 100 | [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", |
| 92 | }; | 101 | }; |
| 93 | 102 | ||
| 103 | static const struct dss_features omap24xx_dss_feats __initconst = { | ||
| 104 | .fck_div_max = 16, | ||
| 105 | .dss_fck_multiplier = 2, | ||
| 106 | .clk_name = NULL, | ||
| 107 | }; | ||
| 108 | |||
| 109 | static const struct dss_features omap34xx_dss_feats __initconst = { | ||
| 110 | .fck_div_max = 16, | ||
| 111 | .dss_fck_multiplier = 2, | ||
| 112 | .clk_name = "dpll4_m4_ck", | ||
| 113 | }; | ||
| 114 | |||
| 115 | static const struct dss_features omap3630_dss_feats __initconst = { | ||
| 116 | .fck_div_max = 32, | ||
| 117 | .dss_fck_multiplier = 1, | ||
| 118 | .clk_name = "dpll4_m4_ck", | ||
| 119 | }; | ||
| 120 | |||
| 121 | static const struct dss_features omap44xx_dss_feats __initconst = { | ||
| 122 | .fck_div_max = 32, | ||
| 123 | .dss_fck_multiplier = 1, | ||
| 124 | .clk_name = "dpll_per_m5x2_ck", | ||
| 125 | }; | ||
| 126 | |||
| 94 | static inline void dss_write_reg(const struct dss_reg idx, u32 val) | 127 | static inline void dss_write_reg(const struct dss_reg idx, u32 val) |
| 95 | { | 128 | { |
| 96 | __raw_writel(val, dss.base + idx.idx); | 129 | __raw_writel(val, dss.base + idx.idx); |
| @@ -236,7 +269,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]; | 269 | return dss_generic_clk_source_names[clk_src]; |
| 237 | } | 270 | } |
| 238 | 271 | ||
| 239 | |||
| 240 | void dss_dump_clocks(struct seq_file *s) | 272 | void dss_dump_clocks(struct seq_file *s) |
| 241 | { | 273 | { |
| 242 | unsigned long dpll4_ck_rate; | 274 | unsigned long dpll4_ck_rate; |
| @@ -259,18 +291,10 @@ void dss_dump_clocks(struct seq_file *s) | |||
| 259 | 291 | ||
| 260 | seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); | 292 | seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); |
| 261 | 293 | ||
| 262 | if (cpu_is_omap3630() || cpu_is_omap44xx()) | 294 | seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n", |
| 263 | seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", | 295 | fclk_name, fclk_real_name, dpll4_ck_rate, |
| 264 | fclk_name, fclk_real_name, | 296 | dpll4_ck_rate / dpll4_m4_ck_rate, |
| 265 | dpll4_ck_rate, | 297 | 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 { | 298 | } else { |
| 275 | seq_printf(s, "%s (%s) = %lu\n", | 299 | seq_printf(s, "%s (%s) = %lu\n", |
| 276 | fclk_name, fclk_real_name, | 300 | fclk_name, fclk_real_name, |
| @@ -470,7 +494,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | |||
| 470 | 494 | ||
| 471 | unsigned long fck, max_dss_fck; | 495 | unsigned long fck, max_dss_fck; |
| 472 | 496 | ||
| 473 | u16 fck_div, fck_div_max = 16; | 497 | u16 fck_div; |
| 474 | 498 | ||
| 475 | int match = 0; | 499 | int match = 0; |
| 476 | int min_fck_per_pck; | 500 | int min_fck_per_pck; |
| @@ -480,9 +504,8 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | |||
| 480 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | 504 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); |
| 481 | 505 | ||
| 482 | fck = clk_get_rate(dss.dss_clk); | 506 | fck = clk_get_rate(dss.dss_clk); |
| 483 | if (req_pck == dss.cache_req_pck && | 507 | if (req_pck == dss.cache_req_pck && prate == dss.cache_prate && |
| 484 | ((cpu_is_omap34xx() && prate == dss.cache_prate) || | 508 | dss.cache_dss_cinfo.fck == fck) { |
| 485 | dss.cache_dss_cinfo.fck == fck)) { | ||
| 486 | DSSDBG("dispc clock info found from cache.\n"); | 509 | DSSDBG("dispc clock info found from cache.\n"); |
| 487 | *dss_cinfo = dss.cache_dss_cinfo; | 510 | *dss_cinfo = dss.cache_dss_cinfo; |
| 488 | *dispc_cinfo = dss.cache_dispc_cinfo; | 511 | *dispc_cinfo = dss.cache_dispc_cinfo; |
| @@ -519,16 +542,10 @@ retry: | |||
| 519 | 542 | ||
| 520 | goto found; | 543 | goto found; |
| 521 | } else { | 544 | } else { |
| 522 | if (cpu_is_omap3630() || cpu_is_omap44xx()) | 545 | for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) { |
| 523 | fck_div_max = 32; | ||
| 524 | |||
| 525 | for (fck_div = fck_div_max; fck_div > 0; --fck_div) { | ||
| 526 | struct dispc_clock_info cur_dispc; | 546 | struct dispc_clock_info cur_dispc; |
| 527 | 547 | ||
| 528 | if (fck_div_max == 32) | 548 | fck = prate / fck_div * dss.feat->dss_fck_multiplier; |
| 529 | fck = prate / fck_div; | ||
| 530 | else | ||
| 531 | fck = prate / fck_div * 2; | ||
| 532 | 549 | ||
| 533 | if (fck > max_dss_fck) | 550 | if (fck > max_dss_fck) |
| 534 | continue; | 551 | continue; |
| @@ -645,22 +662,11 @@ static int dss_get_clocks(void) | |||
| 645 | 662 | ||
| 646 | dss.dss_clk = clk; | 663 | dss.dss_clk = clk; |
| 647 | 664 | ||
| 648 | if (cpu_is_omap34xx()) { | 665 | clk = clk_get(NULL, dss.feat->clk_name); |
| 649 | clk = clk_get(NULL, "dpll4_m4_ck"); | 666 | if (IS_ERR(clk)) { |
| 650 | if (IS_ERR(clk)) { | 667 | DSSERR("Failed to get %s\n", dss.feat->clk_name); |
| 651 | DSSERR("Failed to get dpll4_m4_ck\n"); | 668 | r = PTR_ERR(clk); |
| 652 | r = PTR_ERR(clk); | 669 | goto err; |
| 653 | goto err; | ||
| 654 | } | ||
| 655 | } else if (cpu_is_omap44xx()) { | ||
| 656 | clk = clk_get(NULL, "dpll_per_m5x2_ck"); | ||
| 657 | if (IS_ERR(clk)) { | ||
| 658 | DSSERR("Failed to get dpll_per_m5x2_ck\n"); | ||
| 659 | r = PTR_ERR(clk); | ||
| 660 | goto err; | ||
| 661 | } | ||
| 662 | } else { /* omap24xx */ | ||
| 663 | clk = NULL; | ||
| 664 | } | 670 | } |
| 665 | 671 | ||
| 666 | dss.dpll4_m4_ck = clk; | 672 | dss.dpll4_m4_ck = clk; |
| @@ -716,6 +722,34 @@ void dss_debug_dump_clocks(struct seq_file *s) | |||
| 716 | } | 722 | } |
| 717 | #endif | 723 | #endif |
| 718 | 724 | ||
| 725 | static int __init dss_init_features(struct device *dev) | ||
| 726 | { | ||
| 727 | const struct dss_features *src; | ||
| 728 | struct dss_features *dst; | ||
| 729 | |||
| 730 | dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); | ||
| 731 | if (!dst) { | ||
| 732 | dev_err(dev, "Failed to allocate local DSS Features\n"); | ||
| 733 | return -ENOMEM; | ||
| 734 | } | ||
| 735 | |||
| 736 | if (cpu_is_omap24xx()) | ||
| 737 | src = &omap24xx_dss_feats; | ||
| 738 | else if (cpu_is_omap34xx()) | ||
| 739 | src = &omap34xx_dss_feats; | ||
| 740 | else if (cpu_is_omap3630()) | ||
| 741 | src = &omap3630_dss_feats; | ||
| 742 | else if (cpu_is_omap44xx()) | ||
| 743 | src = &omap44xx_dss_feats; | ||
| 744 | else | ||
| 745 | return -ENODEV; | ||
| 746 | |||
| 747 | memcpy(dst, src, sizeof(*dst)); | ||
| 748 | dss.feat = dst; | ||
| 749 | |||
| 750 | return 0; | ||
| 751 | } | ||
| 752 | |||
| 719 | /* DSS HW IP initialisation */ | 753 | /* DSS HW IP initialisation */ |
| 720 | static int __init omap_dsshw_probe(struct platform_device *pdev) | 754 | static int __init omap_dsshw_probe(struct platform_device *pdev) |
| 721 | { | 755 | { |
| @@ -725,6 +759,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) | |||
| 725 | 759 | ||
| 726 | dss.pdev = pdev; | 760 | dss.pdev = pdev; |
| 727 | 761 | ||
| 762 | r = dss_init_features(&dss.pdev->dev); | ||
| 763 | if (r) | ||
| 764 | return r; | ||
| 765 | |||
| 728 | dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); | 766 | dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); |
| 729 | if (!dss_mem) { | 767 | if (!dss_mem) { |
| 730 | DSSERR("can't get IORESOURCE_MEM DSS\n"); | 768 | DSSERR("can't get IORESOURCE_MEM DSS\n"); |
