diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_display.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 111 |
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 | */ | ||
860 | static 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 | ||