diff options
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 77 |
1 files changed, 51 insertions, 26 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index e6c3c5488259..8d99d5ee8014 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
| @@ -840,6 +840,38 @@ static void avivo_reduce_ratio(unsigned *nom, unsigned *den, | |||
| 840 | } | 840 | } |
| 841 | 841 | ||
| 842 | /** | 842 | /** |
| 843 | * avivo_get_fb_ref_div - feedback and ref divider calculation | ||
| 844 | * | ||
| 845 | * @nom: nominator | ||
| 846 | * @den: denominator | ||
| 847 | * @post_div: post divider | ||
| 848 | * @fb_div_max: feedback divider maximum | ||
| 849 | * @ref_div_max: reference divider maximum | ||
| 850 | * @fb_div: resulting feedback divider | ||
| 851 | * @ref_div: resulting reference divider | ||
| 852 | * | ||
| 853 | * Calculate feedback and reference divider for a given post divider. Makes | ||
| 854 | * sure we stay within the limits. | ||
| 855 | */ | ||
| 856 | static void avivo_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div, | ||
| 857 | unsigned fb_div_max, unsigned ref_div_max, | ||
| 858 | unsigned *fb_div, unsigned *ref_div) | ||
| 859 | { | ||
| 860 | /* limit reference * post divider to a maximum */ | ||
| 861 | ref_div_max = min(210 / post_div, ref_div_max); | ||
| 862 | |||
| 863 | /* get matching reference and feedback divider */ | ||
| 864 | *ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max); | ||
| 865 | *fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den); | ||
| 866 | |||
| 867 | /* limit fb divider to its maximum */ | ||
| 868 | if (*fb_div > fb_div_max) { | ||
| 869 | *ref_div = DIV_ROUND_CLOSEST(*ref_div * fb_div_max, *fb_div); | ||
| 870 | *fb_div = fb_div_max; | ||
| 871 | } | ||
| 872 | } | ||
| 873 | |||
| 874 | /** | ||
| 843 | * radeon_compute_pll_avivo - compute PLL paramaters | 875 | * radeon_compute_pll_avivo - compute PLL paramaters |
| 844 | * | 876 | * |
| 845 | * @pll: information about the PLL | 877 | * @pll: information about the PLL |
| @@ -860,6 +892,9 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, | |||
| 860 | u32 *ref_div_p, | 892 | u32 *ref_div_p, |
| 861 | u32 *post_div_p) | 893 | u32 *post_div_p) |
| 862 | { | 894 | { |
| 895 | unsigned target_clock = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? | ||
| 896 | freq : freq / 10; | ||
| 897 | |||
| 863 | unsigned fb_div_min, fb_div_max, fb_div; | 898 | unsigned fb_div_min, fb_div_max, fb_div; |
| 864 | unsigned post_div_min, post_div_max, post_div; | 899 | unsigned post_div_min, post_div_max, post_div; |
| 865 | unsigned ref_div_min, ref_div_max, ref_div; | 900 | unsigned ref_div_min, ref_div_max, ref_div; |
| @@ -892,7 +927,6 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, | |||
| 892 | post_div_min = pll->post_div; | 927 | post_div_min = pll->post_div; |
| 893 | post_div_max = pll->post_div; | 928 | post_div_max = pll->post_div; |
| 894 | } else { | 929 | } else { |
| 895 | unsigned target_clock = freq / 10; | ||
| 896 | unsigned vco_min, vco_max; | 930 | unsigned vco_min, vco_max; |
| 897 | 931 | ||
| 898 | if (pll->flags & RADEON_PLL_IS_LCD) { | 932 | if (pll->flags & RADEON_PLL_IS_LCD) { |
| @@ -903,6 +937,11 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, | |||
| 903 | vco_max = pll->pll_out_max; | 937 | vco_max = pll->pll_out_max; |
| 904 | } | 938 | } |
| 905 | 939 | ||
| 940 | if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { | ||
| 941 | vco_min *= 10; | ||
| 942 | vco_max *= 10; | ||
| 943 | } | ||
| 944 | |||
| 906 | post_div_min = vco_min / target_clock; | 945 | post_div_min = vco_min / target_clock; |
| 907 | if ((target_clock * post_div_min) < vco_min) | 946 | if ((target_clock * post_div_min) < vco_min) |
| 908 | ++post_div_min; | 947 | ++post_div_min; |
| @@ -917,7 +956,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, | |||
| 917 | } | 956 | } |
| 918 | 957 | ||
| 919 | /* represent the searched ratio as fractional number */ | 958 | /* represent the searched ratio as fractional number */ |
| 920 | nom = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? freq : freq / 10; | 959 | nom = target_clock; |
| 921 | den = pll->reference_freq; | 960 | den = pll->reference_freq; |
| 922 | 961 | ||
| 923 | /* reduce the numbers to a simpler ratio */ | 962 | /* reduce the numbers to a simpler ratio */ |
| @@ -931,7 +970,12 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, | |||
| 931 | diff_best = ~0; | 970 | diff_best = ~0; |
| 932 | 971 | ||
| 933 | for (post_div = post_div_min; post_div <= post_div_max; ++post_div) { | 972 | for (post_div = post_div_min; post_div <= post_div_max; ++post_div) { |
| 934 | unsigned diff = abs(den - den / post_div * post_div); | 973 | unsigned diff; |
| 974 | avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, | ||
| 975 | ref_div_max, &fb_div, &ref_div); | ||
| 976 | diff = abs(target_clock - (pll->reference_freq * fb_div) / | ||
| 977 | (ref_div * post_div)); | ||
| 978 | |||
| 935 | if (diff < diff_best || (diff == diff_best && | 979 | if (diff < diff_best || (diff == diff_best && |
| 936 | !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) { | 980 | !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) { |
| 937 | 981 | ||
| @@ -941,28 +985,9 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, | |||
| 941 | } | 985 | } |
| 942 | post_div = post_div_best; | 986 | post_div = post_div_best; |
| 943 | 987 | ||
| 944 | /* limit reference * post divider to a maximum */ | 988 | /* get the feedback and reference divider for the optimal value */ |
| 945 | ref_div_max = min(210 / post_div, ref_div_max); | 989 | avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, ref_div_max, |
| 946 | 990 | &fb_div, &ref_div); | |
| 947 | /* get matching reference and feedback divider */ | ||
| 948 | ref_div = max(DIV_ROUND_CLOSEST(den, post_div), 1u); | ||
| 949 | fb_div = DIV_ROUND_CLOSEST(nom * ref_div * post_div, den); | ||
| 950 | |||
| 951 | /* we're almost done, but reference and feedback | ||
| 952 | divider might be to large now */ | ||
| 953 | |||
| 954 | nom = fb_div; | ||
| 955 | den = ref_div; | ||
| 956 | |||
| 957 | if (fb_div > fb_div_max) { | ||
| 958 | ref_div = DIV_ROUND_CLOSEST(den * fb_div_max, nom); | ||
| 959 | fb_div = fb_div_max; | ||
| 960 | } | ||
| 961 | |||
| 962 | if (ref_div > ref_div_max) { | ||
| 963 | ref_div = ref_div_max; | ||
| 964 | fb_div = DIV_ROUND_CLOSEST(nom * ref_div_max, den); | ||
| 965 | } | ||
| 966 | 991 | ||
| 967 | /* reduce the numbers to a simpler ratio once more */ | 992 | /* reduce the numbers to a simpler ratio once more */ |
| 968 | /* this also makes sure that the reference divider is large enough */ | 993 | /* this also makes sure that the reference divider is large enough */ |
| @@ -984,7 +1009,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, | |||
| 984 | *post_div_p = post_div; | 1009 | *post_div_p = post_div; |
| 985 | 1010 | ||
| 986 | DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n", | 1011 | DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n", |
| 987 | freq, *dot_clock_p, *fb_div_p, *frac_fb_div_p, | 1012 | freq, *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p, |
| 988 | ref_div, post_div); | 1013 | ref_div, post_div); |
| 989 | } | 1014 | } |
| 990 | 1015 | ||
