aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_display.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c111
1 files changed, 79 insertions, 32 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 386cfa4c194d..408b6ac53f0b 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -284,6 +284,10 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
284 u32 update_pending; 284 u32 update_pending;
285 int vpos, hpos; 285 int vpos, hpos;
286 286
287 /* can happen during initialization */
288 if (radeon_crtc == NULL)
289 return;
290
287 spin_lock_irqsave(&rdev->ddev->event_lock, flags); 291 spin_lock_irqsave(&rdev->ddev->event_lock, flags);
288 work = radeon_crtc->unpin_work; 292 work = radeon_crtc->unpin_work;
289 if (work == NULL || 293 if (work == NULL ||
@@ -759,19 +763,18 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
759 763
760 if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != 764 if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) !=
761 ENCODER_OBJECT_ID_NONE) { 765 ENCODER_OBJECT_ID_NONE) {
762 struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; 766 if (radeon_connector->ddc_bus->has_aux)
763
764 if (dig->dp_i2c_bus)
765 radeon_connector->edid = drm_get_edid(&radeon_connector->base, 767 radeon_connector->edid = drm_get_edid(&radeon_connector->base,
766 &dig->dp_i2c_bus->adapter); 768 &radeon_connector->ddc_bus->aux.ddc);
767 } else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || 769 } else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
768 (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { 770 (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
769 struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; 771 struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
770 772
771 if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || 773 if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
772 dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus) 774 dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) &&
775 radeon_connector->ddc_bus->has_aux)
773 radeon_connector->edid = drm_get_edid(&radeon_connector->base, 776 radeon_connector->edid = drm_get_edid(&radeon_connector->base,
774 &dig->dp_i2c_bus->adapter); 777 &radeon_connector->ddc_bus->aux.ddc);
775 else if (radeon_connector->ddc_bus && !radeon_connector->edid) 778 else if (radeon_connector->ddc_bus && !radeon_connector->edid)
776 radeon_connector->edid = drm_get_edid(&radeon_connector->base, 779 radeon_connector->edid = drm_get_edid(&radeon_connector->base,
777 &radeon_connector->ddc_bus->adapter); 780 &radeon_connector->ddc_bus->adapter);
@@ -827,20 +830,52 @@ static void avivo_reduce_ratio(unsigned *nom, unsigned *den,
827 830
828 /* make sure nominator is large enough */ 831 /* make sure nominator is large enough */
829 if (*nom < nom_min) { 832 if (*nom < nom_min) {
830 tmp = (nom_min + *nom - 1) / *nom; 833 tmp = DIV_ROUND_UP(nom_min, *nom);
831 *nom *= tmp; 834 *nom *= tmp;
832 *den *= tmp; 835 *den *= tmp;
833 } 836 }
834 837
835 /* make sure the denominator is large enough */ 838 /* make sure the denominator is large enough */
836 if (*den < den_min) { 839 if (*den < den_min) {
837 tmp = (den_min + *den - 1) / *den; 840 tmp = DIV_ROUND_UP(den_min, *den);
838 *nom *= tmp; 841 *nom *= tmp;
839 *den *= tmp; 842 *den *= tmp;
840 } 843 }
841} 844}
842 845
843/** 846/**
847 * avivo_get_fb_ref_div - feedback and ref divider calculation
848 *
849 * @nom: nominator
850 * @den: denominator
851 * @post_div: post divider
852 * @fb_div_max: feedback divider maximum
853 * @ref_div_max: reference divider maximum
854 * @fb_div: resulting feedback divider
855 * @ref_div: resulting reference divider
856 *
857 * Calculate feedback and reference divider for a given post divider. Makes
858 * sure we stay within the limits.
859 */
860static void avivo_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div,
861 unsigned fb_div_max, unsigned ref_div_max,
862 unsigned *fb_div, unsigned *ref_div)
863{
864 /* limit reference * post divider to a maximum */
865 ref_div_max = min(128 / post_div, ref_div_max);
866
867 /* get matching reference and feedback divider */
868 *ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max);
869 *fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den);
870
871 /* limit fb divider to its maximum */
872 if (*fb_div > fb_div_max) {
873 *ref_div = DIV_ROUND_CLOSEST(*ref_div * fb_div_max, *fb_div);
874 *fb_div = fb_div_max;
875 }
876}
877
878/**
844 * radeon_compute_pll_avivo - compute PLL paramaters 879 * radeon_compute_pll_avivo - compute PLL paramaters
845 * 880 *
846 * @pll: information about the PLL 881 * @pll: information about the PLL
@@ -861,11 +896,14 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
861 u32 *ref_div_p, 896 u32 *ref_div_p,
862 u32 *post_div_p) 897 u32 *post_div_p)
863{ 898{
899 unsigned target_clock = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ?
900 freq : freq / 10;
901
864 unsigned fb_div_min, fb_div_max, fb_div; 902 unsigned fb_div_min, fb_div_max, fb_div;
865 unsigned post_div_min, post_div_max, post_div; 903 unsigned post_div_min, post_div_max, post_div;
866 unsigned ref_div_min, ref_div_max, ref_div; 904 unsigned ref_div_min, ref_div_max, ref_div;
867 unsigned post_div_best, diff_best; 905 unsigned post_div_best, diff_best;
868 unsigned nom, den, tmp; 906 unsigned nom, den;
869 907
870 /* determine allowed feedback divider range */ 908 /* determine allowed feedback divider range */
871 fb_div_min = pll->min_feedback_div; 909 fb_div_min = pll->min_feedback_div;
@@ -881,14 +919,18 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
881 ref_div_min = pll->reference_div; 919 ref_div_min = pll->reference_div;
882 else 920 else
883 ref_div_min = pll->min_ref_div; 921 ref_div_min = pll->min_ref_div;
884 ref_div_max = pll->max_ref_div; 922
923 if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV &&
924 pll->flags & RADEON_PLL_USE_REF_DIV)
925 ref_div_max = pll->reference_div;
926 else
927 ref_div_max = pll->max_ref_div;
885 928
886 /* determine allowed post divider range */ 929 /* determine allowed post divider range */
887 if (pll->flags & RADEON_PLL_USE_POST_DIV) { 930 if (pll->flags & RADEON_PLL_USE_POST_DIV) {
888 post_div_min = pll->post_div; 931 post_div_min = pll->post_div;
889 post_div_max = pll->post_div; 932 post_div_max = pll->post_div;
890 } else { 933 } else {
891 unsigned target_clock = freq / 10;
892 unsigned vco_min, vco_max; 934 unsigned vco_min, vco_max;
893 935
894 if (pll->flags & RADEON_PLL_IS_LCD) { 936 if (pll->flags & RADEON_PLL_IS_LCD) {
@@ -899,6 +941,11 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
899 vco_max = pll->pll_out_max; 941 vco_max = pll->pll_out_max;
900 } 942 }
901 943
944 if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
945 vco_min *= 10;
946 vco_max *= 10;
947 }
948
902 post_div_min = vco_min / target_clock; 949 post_div_min = vco_min / target_clock;
903 if ((target_clock * post_div_min) < vco_min) 950 if ((target_clock * post_div_min) < vco_min)
904 ++post_div_min; 951 ++post_div_min;
@@ -913,7 +960,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
913 } 960 }
914 961
915 /* represent the searched ratio as fractional number */ 962 /* represent the searched ratio as fractional number */
916 nom = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? freq : freq / 10; 963 nom = target_clock;
917 den = pll->reference_freq; 964 den = pll->reference_freq;
918 965
919 /* reduce the numbers to a simpler ratio */ 966 /* reduce the numbers to a simpler ratio */
@@ -927,7 +974,12 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
927 diff_best = ~0; 974 diff_best = ~0;
928 975
929 for (post_div = post_div_min; post_div <= post_div_max; ++post_div) { 976 for (post_div = post_div_min; post_div <= post_div_max; ++post_div) {
930 unsigned diff = abs(den - den / post_div * post_div); 977 unsigned diff;
978 avivo_get_fb_ref_div(nom, den, post_div, fb_div_max,
979 ref_div_max, &fb_div, &ref_div);
980 diff = abs(target_clock - (pll->reference_freq * fb_div) /
981 (ref_div * post_div));
982
931 if (diff < diff_best || (diff == diff_best && 983 if (diff < diff_best || (diff == diff_best &&
932 !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) { 984 !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) {
933 985
@@ -937,29 +989,24 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
937 } 989 }
938 post_div = post_div_best; 990 post_div = post_div_best;
939 991
940 /* get matching reference and feedback divider */ 992 /* get the feedback and reference divider for the optimal value */
941 ref_div = max(den / post_div, 1u); 993 avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, ref_div_max,
942 fb_div = nom; 994 &fb_div, &ref_div);
943
944 /* we're almost done, but reference and feedback
945 divider might be to large now */
946
947 tmp = ref_div;
948
949 if (fb_div > fb_div_max) {
950 ref_div = ref_div * fb_div_max / fb_div;
951 fb_div = fb_div_max;
952 }
953
954 if (ref_div > ref_div_max) {
955 ref_div = ref_div_max;
956 fb_div = nom * ref_div_max / tmp;
957 }
958 995
959 /* reduce the numbers to a simpler ratio once more */ 996 /* reduce the numbers to a simpler ratio once more */
960 /* this also makes sure that the reference divider is large enough */ 997 /* this also makes sure that the reference divider is large enough */
961 avivo_reduce_ratio(&fb_div, &ref_div, fb_div_min, ref_div_min); 998 avivo_reduce_ratio(&fb_div, &ref_div, fb_div_min, ref_div_min);
962 999
1000 /* avoid high jitter with small fractional dividers */
1001 if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV && (fb_div % 10)) {
1002 fb_div_min = max(fb_div_min, (9 - (fb_div % 10)) * 20 + 60);
1003 if (fb_div < fb_div_min) {
1004 unsigned tmp = DIV_ROUND_UP(fb_div_min, fb_div);
1005 fb_div *= tmp;
1006 ref_div *= tmp;
1007 }
1008 }
1009
963 /* and finally save the result */ 1010 /* and finally save the result */
964 if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { 1011 if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
965 *fb_div_p = fb_div / 10; 1012 *fb_div_p = fb_div / 10;
@@ -976,7 +1023,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
976 *post_div_p = post_div; 1023 *post_div_p = post_div;
977 1024
978 DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n", 1025 DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
979 freq, *dot_clock_p, *fb_div_p, *frac_fb_div_p, 1026 freq, *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p,
980 ref_div, post_div); 1027 ref_div, post_div);
981} 1028}
982 1029