diff options
Diffstat (limited to 'drivers/video/omap2/dss/dss.c')
-rw-r--r-- | drivers/video/omap2/dss/dss.c | 101 |
1 files changed, 96 insertions, 5 deletions
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 602102cebcbf..054c2a22b3f1 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c | |||
@@ -32,6 +32,7 @@ | |||
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 | #include <linux/gfp.h> |
35 | #include <linux/sizes.h> | ||
35 | 36 | ||
36 | #include <video/omapdss.h> | 37 | #include <video/omapdss.h> |
37 | 38 | ||
@@ -76,6 +77,7 @@ static struct { | |||
76 | 77 | ||
77 | struct clk *dpll4_m4_ck; | 78 | struct clk *dpll4_m4_ck; |
78 | struct clk *dss_clk; | 79 | struct clk *dss_clk; |
80 | unsigned long dss_clk_rate; | ||
79 | 81 | ||
80 | unsigned long cache_req_pck; | 82 | unsigned long cache_req_pck; |
81 | unsigned long cache_prate; | 83 | unsigned long cache_prate; |
@@ -96,6 +98,8 @@ static const char * const dss_generic_clk_source_names[] = { | |||
96 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", | 98 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", |
97 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", | 99 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", |
98 | [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", | 100 | [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", |
101 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC", | ||
102 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI", | ||
99 | }; | 103 | }; |
100 | 104 | ||
101 | static inline void dss_write_reg(const struct dss_reg idx, u32 val) | 105 | static inline void dss_write_reg(const struct dss_reg idx, u32 val) |
@@ -151,6 +155,21 @@ static void dss_restore_context(void) | |||
151 | #undef SR | 155 | #undef SR |
152 | #undef RR | 156 | #undef RR |
153 | 157 | ||
158 | int dss_get_ctx_loss_count(void) | ||
159 | { | ||
160 | struct omap_dss_board_info *board_data = dss.pdev->dev.platform_data; | ||
161 | int cnt; | ||
162 | |||
163 | if (!board_data->get_context_loss_count) | ||
164 | return -ENOENT; | ||
165 | |||
166 | cnt = board_data->get_context_loss_count(&dss.pdev->dev); | ||
167 | |||
168 | WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); | ||
169 | |||
170 | return cnt; | ||
171 | } | ||
172 | |||
154 | void dss_sdi_init(int datapairs) | 173 | void dss_sdi_init(int datapairs) |
155 | { | 174 | { |
156 | u32 l; | 175 | u32 l; |
@@ -301,7 +320,7 @@ static void dss_dump_regs(struct seq_file *s) | |||
301 | #undef DUMPREG | 320 | #undef DUMPREG |
302 | } | 321 | } |
303 | 322 | ||
304 | void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) | 323 | static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) |
305 | { | 324 | { |
306 | struct platform_device *dsidev; | 325 | struct platform_device *dsidev; |
307 | int b; | 326 | int b; |
@@ -372,8 +391,10 @@ void dss_select_lcd_clk_source(enum omap_channel channel, | |||
372 | struct platform_device *dsidev; | 391 | struct platform_device *dsidev; |
373 | int b, ix, pos; | 392 | int b, ix, pos; |
374 | 393 | ||
375 | if (!dss_has_feature(FEAT_LCD_CLK_SRC)) | 394 | if (!dss_has_feature(FEAT_LCD_CLK_SRC)) { |
395 | dss_select_dispc_clk_source(clk_src); | ||
376 | return; | 396 | return; |
397 | } | ||
377 | 398 | ||
378 | switch (clk_src) { | 399 | switch (clk_src) { |
379 | case OMAP_DSS_CLK_SRC_FCK: | 400 | case OMAP_DSS_CLK_SRC_FCK: |
@@ -429,6 +450,29 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) | |||
429 | } | 450 | } |
430 | } | 451 | } |
431 | 452 | ||
453 | /* calculate clock rates using dividers in cinfo */ | ||
454 | int dss_calc_clock_rates(struct dss_clock_info *cinfo) | ||
455 | { | ||
456 | if (dss.dpll4_m4_ck) { | ||
457 | unsigned long prate; | ||
458 | |||
459 | if (cinfo->fck_div > dss.feat->fck_div_max || | ||
460 | cinfo->fck_div == 0) | ||
461 | return -EINVAL; | ||
462 | |||
463 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | ||
464 | |||
465 | cinfo->fck = prate / cinfo->fck_div * | ||
466 | dss.feat->dss_fck_multiplier; | ||
467 | } else { | ||
468 | if (cinfo->fck_div != 0) | ||
469 | return -EINVAL; | ||
470 | cinfo->fck = clk_get_rate(dss.dss_clk); | ||
471 | } | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
432 | int dss_set_clock_div(struct dss_clock_info *cinfo) | 476 | int dss_set_clock_div(struct dss_clock_info *cinfo) |
433 | { | 477 | { |
434 | if (dss.dpll4_m4_ck) { | 478 | if (dss.dpll4_m4_ck) { |
@@ -446,6 +490,10 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) | |||
446 | return -EINVAL; | 490 | return -EINVAL; |
447 | } | 491 | } |
448 | 492 | ||
493 | dss.dss_clk_rate = clk_get_rate(dss.dss_clk); | ||
494 | |||
495 | WARN_ONCE(dss.dss_clk_rate != cinfo->fck, "clk rate mismatch"); | ||
496 | |||
449 | DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); | 497 | DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); |
450 | 498 | ||
451 | return 0; | 499 | return 0; |
@@ -459,6 +507,41 @@ unsigned long dss_get_dpll4_rate(void) | |||
459 | return 0; | 507 | return 0; |
460 | } | 508 | } |
461 | 509 | ||
510 | unsigned long dss_get_dispc_clk_rate(void) | ||
511 | { | ||
512 | return dss.dss_clk_rate; | ||
513 | } | ||
514 | |||
515 | static int dss_setup_default_clock(void) | ||
516 | { | ||
517 | unsigned long max_dss_fck, prate; | ||
518 | unsigned fck_div; | ||
519 | struct dss_clock_info dss_cinfo = { 0 }; | ||
520 | int r; | ||
521 | |||
522 | if (dss.dpll4_m4_ck == NULL) | ||
523 | return 0; | ||
524 | |||
525 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | ||
526 | |||
527 | prate = dss_get_dpll4_rate(); | ||
528 | |||
529 | fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier, | ||
530 | max_dss_fck); | ||
531 | |||
532 | dss_cinfo.fck_div = fck_div; | ||
533 | |||
534 | r = dss_calc_clock_rates(&dss_cinfo); | ||
535 | if (r) | ||
536 | return r; | ||
537 | |||
538 | r = dss_set_clock_div(&dss_cinfo); | ||
539 | if (r) | ||
540 | return r; | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
462 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | 545 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, |
463 | struct dispc_clock_info *dispc_cinfo) | 546 | struct dispc_clock_info *dispc_cinfo) |
464 | { | 547 | { |
@@ -748,7 +831,7 @@ static void dss_runtime_put(void) | |||
748 | } | 831 | } |
749 | 832 | ||
750 | /* DEBUGFS */ | 833 | /* DEBUGFS */ |
751 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) | 834 | #if defined(CONFIG_OMAP2_DSS_DEBUGFS) |
752 | void dss_debug_dump_clocks(struct seq_file *s) | 835 | void dss_debug_dump_clocks(struct seq_file *s) |
753 | { | 836 | { |
754 | dss_dump_clocks(s); | 837 | dss_dump_clocks(s); |
@@ -796,7 +879,6 @@ static const struct dss_features omap54xx_dss_feats __initconst = { | |||
796 | 879 | ||
797 | static int __init dss_init_features(struct platform_device *pdev) | 880 | static int __init dss_init_features(struct platform_device *pdev) |
798 | { | 881 | { |
799 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
800 | const struct dss_features *src; | 882 | const struct dss_features *src; |
801 | struct dss_features *dst; | 883 | struct dss_features *dst; |
802 | 884 | ||
@@ -806,7 +888,7 @@ static int __init dss_init_features(struct platform_device *pdev) | |||
806 | return -ENOMEM; | 888 | return -ENOMEM; |
807 | } | 889 | } |
808 | 890 | ||
809 | switch (pdata->version) { | 891 | switch (omapdss_get_version()) { |
810 | case OMAPDSS_VER_OMAP24xx: | 892 | case OMAPDSS_VER_OMAP24xx: |
811 | src = &omap24xx_dss_feats; | 893 | src = &omap24xx_dss_feats; |
812 | break; | 894 | break; |
@@ -871,15 +953,23 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) | |||
871 | if (r) | 953 | if (r) |
872 | return r; | 954 | return r; |
873 | 955 | ||
956 | r = dss_setup_default_clock(); | ||
957 | if (r) | ||
958 | goto err_setup_clocks; | ||
959 | |||
874 | pm_runtime_enable(&pdev->dev); | 960 | pm_runtime_enable(&pdev->dev); |
875 | 961 | ||
876 | r = dss_runtime_get(); | 962 | r = dss_runtime_get(); |
877 | if (r) | 963 | if (r) |
878 | goto err_runtime_get; | 964 | goto err_runtime_get; |
879 | 965 | ||
966 | dss.dss_clk_rate = clk_get_rate(dss.dss_clk); | ||
967 | |||
880 | /* Select DPLL */ | 968 | /* Select DPLL */ |
881 | REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); | 969 | REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); |
882 | 970 | ||
971 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | ||
972 | |||
883 | #ifdef CONFIG_OMAP2_DSS_VENC | 973 | #ifdef CONFIG_OMAP2_DSS_VENC |
884 | REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ | 974 | REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ |
885 | REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ | 975 | REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ |
@@ -903,6 +993,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) | |||
903 | 993 | ||
904 | err_runtime_get: | 994 | err_runtime_get: |
905 | pm_runtime_disable(&pdev->dev); | 995 | pm_runtime_disable(&pdev->dev); |
996 | err_setup_clocks: | ||
906 | dss_put_clocks(); | 997 | dss_put_clocks(); |
907 | return r; | 998 | return r; |
908 | } | 999 | } |