aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNeil Armstrong <narmstrong@baylibre.com>2018-11-06 05:54:35 -0500
committerNeil Armstrong <narmstrong@baylibre.com>2018-11-27 10:39:49 -0500
commitff217bc710e09360187ab5dd7d704f871c29e006 (patch)
tree6979baf6b5edd50e44e5620be6fb415fe8d89b6f /drivers
parent5d0bfe448481c9c109f5052c4ad36ef855aedc4f (diff)
drm/meson: Add support for VIC alternate timings
This change is an attempt to handle the alternate clock for the CEA mode. 60Hz vs. 59.94Hz, 30Hz vs 29.97Hz or 24Hz vs 23.97Hz on the Amlogic Meson SoC DRM Driver pixel clock generation. The actual clock generation will be moved to the Common Clock framework once all the video clock are handled by the Amlogic Meson SoC clock driver, then these alternate timings will be handled in the same time in a cleaner fashion. Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> Reviewed-by: Maxime Jourdan <mjourdan@baylibre.com> [narmstrong: fix maybe-uninitialized warnings after applying] Link: https://patchwork.freedesktop.org/patch/msgid/1541501675-3928-1-git-send-email-narmstrong@baylibre.com
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/meson/meson_dw_hdmi.c12
-rw-r--r--drivers/gpu/drm/meson/meson_vclk.c127
-rw-r--r--drivers/gpu/drm/meson/meson_vclk.h2
3 files changed, 89 insertions, 52 deletions
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index df7247cd93f9..d8c5cc34e22e 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -594,17 +594,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
594 dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__, 594 dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
595 vclk_freq, venc_freq, hdmi_freq); 595 vclk_freq, venc_freq, hdmi_freq);
596 596
597 /* Finally filter by configurable vclk frequencies for VIC modes */ 597 return meson_vclk_vic_supported_freq(vclk_freq);
598 switch (vclk_freq) {
599 case 54000:
600 case 74250:
601 case 148500:
602 case 297000:
603 case 594000:
604 return MODE_OK;
605 }
606
607 return MODE_CLOCK_RANGE;
608} 598}
609 599
610/* Encoder */ 600/* Encoder */
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);
diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h
index 869fa3a3073e..4bd8752da02a 100644
--- a/drivers/gpu/drm/meson/meson_vclk.h
+++ b/drivers/gpu/drm/meson/meson_vclk.h
@@ -32,6 +32,8 @@ enum {
32 32
33enum drm_mode_status 33enum drm_mode_status
34meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq); 34meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
35enum drm_mode_status
36meson_vclk_vic_supported_freq(unsigned int freq);
35 37
36void meson_vclk_setup(struct meson_drm *priv, unsigned int target, 38void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
37 unsigned int vclk_freq, unsigned int venc_freq, 39 unsigned int vclk_freq, unsigned int venc_freq,