aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_ddi.c
diff options
context:
space:
mode:
authorPaulo Zanoni <paulo.r.zanoni@intel.com>2012-10-05 11:05:58 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-10-10 10:53:02 -0400
commit6441ab5f8ffdf7e99eefe0fb747858e0c12b567e (patch)
tree4408fc4fb3eeba522abf3a91ddd3b5a8af575b8f /drivers/gpu/drm/i915/intel_ddi.c
parentee2b0b382a7e6cbf3549559ec7dc86c63f5aa3d1 (diff)
drm/i915: completely rewrite the Haswell PLL handling code
Problems with the previous code: - HDMI just uses WRPLL1 for everything, so dual head cases might not work sometimes. - At encoder->mode_set we just write the PLL register without doing any kind of check (e.g., check if the PLL is already being used). - There is no way to fail and return error codes at encoder->mode_set. - We write to PORT_CLK_SEL at mode_set and we never disable it. - Machines hang due to wrong clock enable/disable sequence. So here we rewrite the code, making it a little more like the pre-Haswell PLL mode set code: - Check PLL availability at ironlake_crtc_mode_set. - Try to use both WRPLLs. - Check if PLLs are used before actually trying to use them, and properly fail with error messages. - Enable/disable PORT_CLK_SEL at the right place. - Add some WARNs to check for bugs. The next improvement will be to try to reuse PLLs if the timings match, but this is content for another patch and it's already documented with a TODO comment. Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: Damien Lespiau <damien.lespiau@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_ddi.c')
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c263
1 files changed, 210 insertions, 53 deletions
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 8740a5cf1359..ab48083ffcec 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -152,18 +152,6 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
152 int pipe = intel_crtc->pipe; 152 int pipe = intel_crtc->pipe;
153 u32 reg, temp, i; 153 u32 reg, temp, i;
154 154
155 /* Configure CPU PLL, wait for warmup */
156 I915_WRITE(SPLL_CTL,
157 SPLL_PLL_ENABLE |
158 SPLL_PLL_FREQ_1350MHz |
159 SPLL_PLL_SCC);
160
161 /* Use SPLL to drive the output when in FDI mode */
162 I915_WRITE(PORT_CLK_SEL(PORT_E),
163 PORT_CLK_SEL_SPLL);
164
165 udelay(20);
166
167 /* Start the training iterating through available voltages and emphasis */ 155 /* Start the training iterating through available voltages and emphasis */
168 for (i=0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) { 156 for (i=0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) {
169 /* Configure DP_TP_CTL with auto-training */ 157 /* Configure DP_TP_CTL with auto-training */
@@ -654,58 +642,17 @@ void intel_ddi_mode_set(struct drm_encoder *encoder,
654 struct drm_display_mode *mode, 642 struct drm_display_mode *mode,
655 struct drm_display_mode *adjusted_mode) 643 struct drm_display_mode *adjusted_mode)
656{ 644{
657 struct drm_device *dev = encoder->dev;
658 struct drm_i915_private *dev_priv = dev->dev_private;
659 struct drm_crtc *crtc = encoder->crtc; 645 struct drm_crtc *crtc = encoder->crtc;
660 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 646 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
661 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 647 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
662 int port = intel_hdmi->ddi_port; 648 int port = intel_hdmi->ddi_port;
663 int pipe = intel_crtc->pipe; 649 int pipe = intel_crtc->pipe;
664 int p, n2, r2;
665 u32 i;
666 650
667 /* On Haswell, we need to enable the clocks and prepare DDI function to 651 /* On Haswell, we need to enable the clocks and prepare DDI function to
668 * work in HDMI mode for this pipe. 652 * work in HDMI mode for this pipe.
669 */ 653 */
670 DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe)); 654 DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe));
671 655
672 for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++)
673 if (crtc->mode.clock <= wrpll_tmds_clock_table[i].clock)
674 break;
675
676 if (i == ARRAY_SIZE(wrpll_tmds_clock_table))
677 i--;
678
679 p = wrpll_tmds_clock_table[i].p;
680 n2 = wrpll_tmds_clock_table[i].n2;
681 r2 = wrpll_tmds_clock_table[i].r2;
682
683 if (wrpll_tmds_clock_table[i].clock != crtc->mode.clock)
684 DRM_INFO("WR PLL: using settings for %dKHz on %dKHz mode\n",
685 wrpll_tmds_clock_table[i].clock, crtc->mode.clock);
686
687 DRM_DEBUG_KMS("WR PLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n",
688 crtc->mode.clock, p, n2, r2);
689
690 /* Configure WR PLL 1, program the correct divider values for
691 * the desired frequency and wait for warmup */
692 I915_WRITE(WRPLL_CTL1,
693 WRPLL_PLL_ENABLE |
694 WRPLL_PLL_SELECT_LCPLL_2700 |
695 WRPLL_DIVIDER_REFERENCE(r2) |
696 WRPLL_DIVIDER_FEEDBACK(n2) |
697 WRPLL_DIVIDER_POST(p));
698
699 udelay(20);
700
701 /* Use WRPLL1 clock to drive the output to the port, and tell the pipe to use
702 * this port for connection.
703 */
704 I915_WRITE(PORT_CLK_SEL(port),
705 PORT_CLK_SEL_WRPLL1);
706
707 udelay(20);
708
709 if (intel_hdmi->has_audio) { 656 if (intel_hdmi->has_audio) {
710 /* Proper support for digital audio needs a new logic and a new set 657 /* Proper support for digital audio needs a new logic and a new set
711 * of registers, so we leave it for future patch bombing. 658 * of registers, so we leave it for future patch bombing.
@@ -742,6 +689,144 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc)
742 return ret; 689 return ret;
743} 690}
744 691
692void intel_ddi_put_crtc_pll(struct drm_crtc *crtc)
693{
694 struct drm_i915_private *dev_priv = crtc->dev->dev_private;
695 struct intel_ddi_plls *plls = &dev_priv->ddi_plls;
696 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
697 uint32_t val;
698
699 switch (intel_crtc->ddi_pll_sel) {
700 case PORT_CLK_SEL_SPLL:
701 plls->spll_refcount--;
702 if (plls->spll_refcount == 0) {
703 DRM_DEBUG_KMS("Disabling SPLL\n");
704 val = I915_READ(SPLL_CTL);
705 WARN_ON(!(val & SPLL_PLL_ENABLE));
706 I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
707 POSTING_READ(SPLL_CTL);
708 }
709 break;
710 case PORT_CLK_SEL_WRPLL1:
711 plls->wrpll1_refcount--;
712 if (plls->wrpll1_refcount == 0) {
713 DRM_DEBUG_KMS("Disabling WRPLL 1\n");
714 val = I915_READ(WRPLL_CTL1);
715 WARN_ON(!(val & WRPLL_PLL_ENABLE));
716 I915_WRITE(WRPLL_CTL1, val & ~WRPLL_PLL_ENABLE);
717 POSTING_READ(WRPLL_CTL1);
718 }
719 break;
720 case PORT_CLK_SEL_WRPLL2:
721 plls->wrpll2_refcount--;
722 if (plls->wrpll2_refcount == 0) {
723 DRM_DEBUG_KMS("Disabling WRPLL 2\n");
724 val = I915_READ(WRPLL_CTL2);
725 WARN_ON(!(val & WRPLL_PLL_ENABLE));
726 I915_WRITE(WRPLL_CTL2, val & ~WRPLL_PLL_ENABLE);
727 POSTING_READ(WRPLL_CTL2);
728 }
729 break;
730 }
731
732 WARN(plls->spll_refcount < 0, "Invalid SPLL refcount\n");
733 WARN(plls->wrpll1_refcount < 0, "Invalid WRPLL1 refcount\n");
734 WARN(plls->wrpll2_refcount < 0, "Invalid WRPLL2 refcount\n");
735
736 intel_crtc->ddi_pll_sel = PORT_CLK_SEL_NONE;
737}
738
739static void intel_ddi_calculate_wrpll(int clock, int *p, int *n2, int *r2)
740{
741 u32 i;
742
743 for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++)
744 if (clock <= wrpll_tmds_clock_table[i].clock)
745 break;
746
747 if (i == ARRAY_SIZE(wrpll_tmds_clock_table))
748 i--;
749
750 *p = wrpll_tmds_clock_table[i].p;
751 *n2 = wrpll_tmds_clock_table[i].n2;
752 *r2 = wrpll_tmds_clock_table[i].r2;
753
754 if (wrpll_tmds_clock_table[i].clock != clock)
755 DRM_INFO("WRPLL: using settings for %dKHz on %dKHz mode\n",
756 wrpll_tmds_clock_table[i].clock, clock);
757
758 DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n",
759 clock, *p, *n2, *r2);
760}
761
762bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock)
763{
764 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
765 struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
766 struct drm_i915_private *dev_priv = crtc->dev->dev_private;
767 struct intel_ddi_plls *plls = &dev_priv->ddi_plls;
768 int type = intel_encoder->type;
769 enum pipe pipe = intel_crtc->pipe;
770 uint32_t reg, val;
771
772 /* TODO: reuse PLLs when possible (compare values) */
773
774 intel_ddi_put_crtc_pll(crtc);
775
776 if (type == INTEL_OUTPUT_HDMI) {
777 int p, n2, r2;
778
779 if (plls->wrpll1_refcount == 0) {
780 DRM_DEBUG_KMS("Using WRPLL 1 on pipe %c\n",
781 pipe_name(pipe));
782 plls->wrpll1_refcount++;
783 reg = WRPLL_CTL1;
784 intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1;
785 } else if (plls->wrpll2_refcount == 0) {
786 DRM_DEBUG_KMS("Using WRPLL 2 on pipe %c\n",
787 pipe_name(pipe));
788 plls->wrpll2_refcount++;
789 reg = WRPLL_CTL2;
790 intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL2;
791 } else {
792 DRM_ERROR("No WRPLLs available!\n");
793 return false;
794 }
795
796 WARN(I915_READ(reg) & WRPLL_PLL_ENABLE,
797 "WRPLL already enabled\n");
798
799 intel_ddi_calculate_wrpll(clock, &p, &n2, &r2);
800
801 val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 |
802 WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
803 WRPLL_DIVIDER_POST(p);
804
805 } else if (type == INTEL_OUTPUT_ANALOG) {
806 if (plls->spll_refcount == 0) {
807 DRM_DEBUG_KMS("Using SPLL on pipe %c\n",
808 pipe_name(pipe));
809 plls->spll_refcount++;
810 reg = SPLL_CTL;
811 intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL;
812 }
813
814 WARN(I915_READ(reg) & SPLL_PLL_ENABLE,
815 "SPLL already enabled\n");
816
817 val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SCC;
818
819 } else {
820 WARN(1, "Invalid DDI encoder type %d\n", type);
821 return false;
822 }
823
824 I915_WRITE(reg, val);
825 udelay(20);
826
827 return true;
828}
829
745void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) 830void intel_ddi_enable_pipe_func(struct drm_crtc *crtc)
746{ 831{
747 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 832 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -837,6 +922,57 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
837 return true; 922 return true;
838} 923}
839 924
925static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv,
926 enum pipe pipe)
927{
928 uint32_t temp, ret;
929 enum port port;
930 int i;
931
932 temp = I915_READ(DDI_FUNC_CTL(pipe));
933 temp &= PIPE_DDI_PORT_MASK;
934 for (i = PORT_A; i <= PORT_E; i++)
935 if (temp == PIPE_DDI_SELECT_PORT(i))
936 port = i;
937
938 ret = I915_READ(PORT_CLK_SEL(port));
939
940 DRM_DEBUG_KMS("Pipe %c connected to port %c using clock 0x%08x\n",
941 pipe_name(pipe), port_name(port), ret);
942
943 return ret;
944}
945
946void intel_ddi_setup_hw_pll_state(struct drm_device *dev)
947{
948 struct drm_i915_private *dev_priv = dev->dev_private;
949 enum pipe pipe;
950 struct intel_crtc *intel_crtc;
951
952 for_each_pipe(pipe) {
953 intel_crtc =
954 to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
955
956 if (!intel_crtc->active)
957 continue;
958
959 intel_crtc->ddi_pll_sel = intel_ddi_get_crtc_pll(dev_priv,
960 pipe);
961
962 switch (intel_crtc->ddi_pll_sel) {
963 case PORT_CLK_SEL_SPLL:
964 dev_priv->ddi_plls.spll_refcount++;
965 break;
966 case PORT_CLK_SEL_WRPLL1:
967 dev_priv->ddi_plls.wrpll1_refcount++;
968 break;
969 case PORT_CLK_SEL_WRPLL2:
970 dev_priv->ddi_plls.wrpll2_refcount++;
971 break;
972 }
973 }
974}
975
840void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) 976void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
841{ 977{
842 struct drm_crtc *crtc = &intel_crtc->base; 978 struct drm_crtc *crtc = &intel_crtc->base;
@@ -854,6 +990,27 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc)
854 I915_WRITE(PIPE_CLK_SEL(intel_crtc->pipe), PIPE_CLK_SEL_DISABLED); 990 I915_WRITE(PIPE_CLK_SEL(intel_crtc->pipe), PIPE_CLK_SEL_DISABLED);
855} 991}
856 992
993void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
994{
995 struct drm_crtc *crtc = intel_encoder->base.crtc;
996 struct drm_i915_private *dev_priv = crtc->dev->dev_private;
997 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
998 enum port port = intel_ddi_get_encoder_port(intel_encoder);
999
1000 WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE);
1001
1002 I915_WRITE(PORT_CLK_SEL(port), intel_crtc->ddi_pll_sel);
1003}
1004
1005void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
1006{
1007 struct drm_encoder *encoder = &intel_encoder->base;
1008 struct drm_i915_private *dev_priv = encoder->dev->dev_private;
1009 enum port port = intel_ddi_get_encoder_port(intel_encoder);
1010
1011 I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE);
1012}
1013
857void intel_enable_ddi(struct intel_encoder *encoder) 1014void intel_enable_ddi(struct intel_encoder *encoder)
858{ 1015{
859 struct drm_device *dev = encoder->base.dev; 1016 struct drm_device *dev = encoder->base.dev;