aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/meson/meson_vclk.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/meson/meson_vclk.c')
-rw-r--r--drivers/gpu/drm/meson/meson_vclk.c127
1 files changed, 86 insertions, 41 deletions
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
index ae5473257f72..f6ba35a405f8 100644
--- a/drivers/gpu/drm/meson/meson_vclk.c
+++ b/drivers/gpu/drm/meson/meson_vclk.c
@@ -117,6 +117,8 @@
117#define HDMI_PLL_RESET BIT(28) 117#define HDMI_PLL_RESET BIT(28)
118#define HDMI_PLL_LOCK BIT(31) 118#define HDMI_PLL_LOCK BIT(31)
119 119
120#define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001)
121
120/* VID PLL Dividers */ 122/* VID PLL Dividers */
121enum { 123enum {
122 VID_PLL_DIV_1 = 0, 124 VID_PLL_DIV_1 = 0,
@@ -323,7 +325,7 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
323enum { 325enum {
324/* PLL O1 O2 O3 VP DV EN TX */ 326/* PLL O1 O2 O3 VP DV EN TX */
325/* 4320 /4 /4 /1 /5 /1 => /2 /2 */ 327/* 4320 /4 /4 /1 /5 /1 => /2 /2 */
326 MESON_VCLK_HDMI_ENCI_54000 = 1, 328 MESON_VCLK_HDMI_ENCI_54000 = 0,
327/* 4320 /4 /4 /1 /5 /1 => /1 /2 */ 329/* 4320 /4 /4 /1 /5 /1 => /1 /2 */
328 MESON_VCLK_HDMI_DDR_54000, 330 MESON_VCLK_HDMI_DDR_54000,
329/* 2970 /4 /1 /1 /5 /1 => /1 /2 */ 331/* 2970 /4 /1 /1 /5 /1 => /1 /2 */
@@ -339,6 +341,7 @@ enum {
339}; 341};
340 342
341struct meson_vclk_params { 343struct meson_vclk_params {
344 unsigned int pixel_freq;
342 unsigned int pll_base_freq; 345 unsigned int pll_base_freq;
343 unsigned int pll_od1; 346 unsigned int pll_od1;
344 unsigned int pll_od2; 347 unsigned int pll_od2;
@@ -347,6 +350,7 @@ struct meson_vclk_params {
347 unsigned int vclk_div; 350 unsigned int vclk_div;
348} params[] = { 351} params[] = {
349 [MESON_VCLK_HDMI_ENCI_54000] = { 352 [MESON_VCLK_HDMI_ENCI_54000] = {
353 .pixel_freq = 54000,
350 .pll_base_freq = 4320000, 354 .pll_base_freq = 4320000,
351 .pll_od1 = 4, 355 .pll_od1 = 4,
352 .pll_od2 = 4, 356 .pll_od2 = 4,
@@ -355,6 +359,7 @@ struct meson_vclk_params {
355 .vclk_div = 1, 359 .vclk_div = 1,
356 }, 360 },
357 [MESON_VCLK_HDMI_DDR_54000] = { 361 [MESON_VCLK_HDMI_DDR_54000] = {
362 .pixel_freq = 54000,
358 .pll_base_freq = 4320000, 363 .pll_base_freq = 4320000,
359 .pll_od1 = 4, 364 .pll_od1 = 4,
360 .pll_od2 = 4, 365 .pll_od2 = 4,
@@ -363,6 +368,7 @@ struct meson_vclk_params {
363 .vclk_div = 1, 368 .vclk_div = 1,
364 }, 369 },
365 [MESON_VCLK_HDMI_DDR_148500] = { 370 [MESON_VCLK_HDMI_DDR_148500] = {
371 .pixel_freq = 148500,
366 .pll_base_freq = 2970000, 372 .pll_base_freq = 2970000,
367 .pll_od1 = 4, 373 .pll_od1 = 4,
368 .pll_od2 = 1, 374 .pll_od2 = 1,
@@ -371,6 +377,7 @@ struct meson_vclk_params {
371 .vclk_div = 1, 377 .vclk_div = 1,
372 }, 378 },
373 [MESON_VCLK_HDMI_74250] = { 379 [MESON_VCLK_HDMI_74250] = {
380 .pixel_freq = 74250,
374 .pll_base_freq = 2970000, 381 .pll_base_freq = 2970000,
375 .pll_od1 = 2, 382 .pll_od1 = 2,
376 .pll_od2 = 2, 383 .pll_od2 = 2,
@@ -379,6 +386,7 @@ struct meson_vclk_params {
379 .vclk_div = 1, 386 .vclk_div = 1,
380 }, 387 },
381 [MESON_VCLK_HDMI_148500] = { 388 [MESON_VCLK_HDMI_148500] = {
389 .pixel_freq = 148500,
382 .pll_base_freq = 2970000, 390 .pll_base_freq = 2970000,
383 .pll_od1 = 1, 391 .pll_od1 = 1,
384 .pll_od2 = 2, 392 .pll_od2 = 2,
@@ -387,6 +395,7 @@ struct meson_vclk_params {
387 .vclk_div = 1, 395 .vclk_div = 1,
388 }, 396 },
389 [MESON_VCLK_HDMI_297000] = { 397 [MESON_VCLK_HDMI_297000] = {
398 .pixel_freq = 297000,
390 .pll_base_freq = 2970000, 399 .pll_base_freq = 2970000,
391 .pll_od1 = 1, 400 .pll_od1 = 1,
392 .pll_od2 = 1, 401 .pll_od2 = 1,
@@ -395,6 +404,7 @@ struct meson_vclk_params {
395 .vclk_div = 2, 404 .vclk_div = 2,
396 }, 405 },
397 [MESON_VCLK_HDMI_594000] = { 406 [MESON_VCLK_HDMI_594000] = {
407 .pixel_freq = 594000,
398 .pll_base_freq = 5940000, 408 .pll_base_freq = 5940000,
399 .pll_od1 = 1, 409 .pll_od1 = 1,
400 .pll_od2 = 1, 410 .pll_od2 = 1,
@@ -402,6 +412,7 @@ struct meson_vclk_params {
402 .vid_pll_div = VID_PLL_DIV_5, 412 .vid_pll_div = VID_PLL_DIV_5,
403 .vclk_div = 1, 413 .vclk_div = 1,
404 }, 414 },
415 { /* sentinel */ },
405}; 416};
406 417
407static inline unsigned int pll_od_to_reg(unsigned int od) 418static inline unsigned int pll_od_to_reg(unsigned int od)
@@ -626,12 +637,37 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
626 pll_freq); 637 pll_freq);
627} 638}
628 639
640enum drm_mode_status
641meson_vclk_vic_supported_freq(unsigned int freq)
642{
643 int i;
644
645 DRM_DEBUG_DRIVER("freq = %d\n", freq);
646
647 for (i = 0 ; params[i].pixel_freq ; ++i) {
648 DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
649 i, params[i].pixel_freq,
650 FREQ_1000_1001(params[i].pixel_freq));
651 /* Match strict frequency */
652 if (freq == params[i].pixel_freq)
653 return MODE_OK;
654 /* Match 1000/1001 variant */
655 if (freq == FREQ_1000_1001(params[i].pixel_freq))
656 return MODE_OK;
657 }
658
659 return MODE_CLOCK_RANGE;
660}
661EXPORT_SYMBOL_GPL(meson_vclk_vic_supported_freq);
662
629static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, 663static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
630 unsigned int od1, unsigned int od2, unsigned int od3, 664 unsigned int od1, unsigned int od2, unsigned int od3,
631 unsigned int vid_pll_div, unsigned int vclk_div, 665 unsigned int vid_pll_div, unsigned int vclk_div,
632 unsigned int hdmi_tx_div, unsigned int venc_div, 666 unsigned int hdmi_tx_div, unsigned int venc_div,
633 bool hdmi_use_enci) 667 bool hdmi_use_enci, bool vic_alternate_clock)
634{ 668{
669 unsigned int m = 0, frac = 0;
670
635 /* Set HDMI-TX sys clock */ 671 /* Set HDMI-TX sys clock */
636 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 672 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
637 CTS_HDMI_SYS_SEL_MASK, 0); 673 CTS_HDMI_SYS_SEL_MASK, 0);
@@ -646,34 +682,38 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
646 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { 682 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
647 switch (pll_base_freq) { 683 switch (pll_base_freq) {
648 case 2970000: 684 case 2970000:
649 meson_hdmi_pll_set_params(priv, 0x3d, 0xe00, 685 m = 0x3d;
650 od1, od2, od3); 686 frac = vic_alternate_clock ? 0xd02 : 0xe00;
651 break; 687 break;
652 case 4320000: 688 case 4320000:
653 meson_hdmi_pll_set_params(priv, 0x5a, 0, 689 m = vic_alternate_clock ? 0x59 : 0x5a;
654 od1, od2, od3); 690 frac = vic_alternate_clock ? 0xe8f : 0;
655 break; 691 break;
656 case 5940000: 692 case 5940000:
657 meson_hdmi_pll_set_params(priv, 0x7b, 0xc00, 693 m = 0x7b;
658 od1, od2, od3); 694 frac = vic_alternate_clock ? 0xa05 : 0xc00;
659 break; 695 break;
660 } 696 }
697
698 meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
661 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || 699 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
662 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { 700 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
663 switch (pll_base_freq) { 701 switch (pll_base_freq) {
664 case 2970000: 702 case 2970000:
665 meson_hdmi_pll_set_params(priv, 0x7b, 0x300, 703 m = 0x7b;
666 od1, od2, od3); 704 frac = vic_alternate_clock ? 0x281 : 0x300;
667 break; 705 break;
668 case 4320000: 706 case 4320000:
669 meson_hdmi_pll_set_params(priv, 0xb4, 0, 707 m = vic_alternate_clock ? 0xb3 : 0xb4;
670 od1, od2, od3); 708 frac = vic_alternate_clock ? 0x347 : 0;
671 break; 709 break;
672 case 5940000: 710 case 5940000:
673 meson_hdmi_pll_set_params(priv, 0xf7, 0x200, 711 m = 0xf7;
674 od1, od2, od3); 712 frac = vic_alternate_clock ? 0x102 : 0x200;
675 break; 713 break;
676 } 714 }
715
716 meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
677 } 717 }
678 718
679 /* Setup vid_pll divider */ 719 /* Setup vid_pll divider */
@@ -826,6 +866,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
826 unsigned int vclk_freq, unsigned int venc_freq, 866 unsigned int vclk_freq, unsigned int venc_freq,
827 unsigned int dac_freq, bool hdmi_use_enci) 867 unsigned int dac_freq, bool hdmi_use_enci)
828{ 868{
869 bool vic_alternate_clock = false;
829 unsigned int freq; 870 unsigned int freq;
830 unsigned int hdmi_tx_div; 871 unsigned int hdmi_tx_div;
831 unsigned int venc_div; 872 unsigned int venc_div;
@@ -843,7 +884,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
843 * - encp encoder 884 * - encp encoder
844 */ 885 */
845 meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0, 886 meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
846 VID_PLL_DIV_5, 2, 1, 1, false); 887 VID_PLL_DIV_5, 2, 1, 1, false, false);
847 return; 888 return;
848 } 889 }
849 890
@@ -863,31 +904,35 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
863 return; 904 return;
864 } 905 }
865 906
866 switch (vclk_freq) { 907 for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
867 case 54000: 908 if (vclk_freq == params[freq].pixel_freq ||
868 if (hdmi_use_enci) 909 vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) {
869 freq = MESON_VCLK_HDMI_ENCI_54000; 910 if (vclk_freq != params[freq].pixel_freq)
870 else 911 vic_alternate_clock = true;
871 freq = MESON_VCLK_HDMI_DDR_54000; 912 else
872 break; 913 vic_alternate_clock = false;
873 case 74250: 914
874 freq = MESON_VCLK_HDMI_74250; 915 if (freq == MESON_VCLK_HDMI_ENCI_54000 &&
875 break; 916 !hdmi_use_enci)
876 case 148500: 917 continue;
877 if (dac_freq != 148500) 918
878 freq = MESON_VCLK_HDMI_DDR_148500; 919 if (freq == MESON_VCLK_HDMI_DDR_54000 &&
879 else 920 hdmi_use_enci)
880 freq = MESON_VCLK_HDMI_148500; 921 continue;
881 break; 922
882 case 297000: 923 if (freq == MESON_VCLK_HDMI_DDR_148500 &&
883 freq = MESON_VCLK_HDMI_297000; 924 dac_freq == vclk_freq)
884 break; 925 continue;
885 case 594000: 926
886 freq = MESON_VCLK_HDMI_594000; 927 if (freq == MESON_VCLK_HDMI_148500 &&
887 break; 928 dac_freq != vclk_freq)
888 default: 929 continue;
889 pr_err("Fatal Error, invalid HDMI vclk freq %d\n", 930 break;
890 vclk_freq); 931 }
932 }
933
934 if (!params[freq].pixel_freq) {
935 pr_err("Fatal Error, invalid HDMI vclk freq %d\n", vclk_freq);
891 return; 936 return;
892 } 937 }
893 938
@@ -895,6 +940,6 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
895 params[freq].pll_od1, params[freq].pll_od2, 940 params[freq].pll_od1, params[freq].pll_od2,
896 params[freq].pll_od3, params[freq].vid_pll_div, 941 params[freq].pll_od3, params[freq].vid_pll_div,
897 params[freq].vclk_div, hdmi_tx_div, venc_div, 942 params[freq].vclk_div, hdmi_tx_div, venc_div,
898 hdmi_use_enci); 943 hdmi_use_enci, vic_alternate_clock);
899} 944}
900EXPORT_SYMBOL_GPL(meson_vclk_setup); 945EXPORT_SYMBOL_GPL(meson_vclk_setup);