pll_4.diff (4989B)
1 commit c2fb3094669a3205f16a32f4119d0afe40b1a1fd 2 Author: Christian König <christian.koenig@amd.com> 3 Date: Sun Apr 20 13:24:32 2014 +0200 4 5 drm/radeon: improve PLL limit handling in post div calculation 6 7 This improves the PLL parameters when we work at 8 the limits of the allowed ranges. 9 10 Signed-off-by: Christian König <christian.koenig@amd.com> 11 12 diff --git b/drivers/gpu/drm/radeon/radeon_display.c a/drivers/gpu/drm/radeon/radeon_display.c 13 index 8d99d5ee8014..e6c3c5488259 100644 14 --- b/drivers/gpu/drm/radeon/radeon_display.c 15 +++ a/drivers/gpu/drm/radeon/radeon_display.c 16 @@ -839,38 +839,6 @@ static void avivo_reduce_ratio(unsigned *nom, unsigned *den, 17 } 18 } 19 20 -/** 21 - * avivo_get_fb_ref_div - feedback and ref divider calculation 22 - * 23 - * @nom: nominator 24 - * @den: denominator 25 - * @post_div: post divider 26 - * @fb_div_max: feedback divider maximum 27 - * @ref_div_max: reference divider maximum 28 - * @fb_div: resulting feedback divider 29 - * @ref_div: resulting reference divider 30 - * 31 - * Calculate feedback and reference divider for a given post divider. Makes 32 - * sure we stay within the limits. 33 - */ 34 -static void avivo_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div, 35 - unsigned fb_div_max, unsigned ref_div_max, 36 - unsigned *fb_div, unsigned *ref_div) 37 -{ 38 - /* limit reference * post divider to a maximum */ 39 - ref_div_max = min(210 / post_div, ref_div_max); 40 - 41 - /* get matching reference and feedback divider */ 42 - *ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max); 43 - *fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den); 44 - 45 - /* limit fb divider to its maximum */ 46 - if (*fb_div > fb_div_max) { 47 - *ref_div = DIV_ROUND_CLOSEST(*ref_div * fb_div_max, *fb_div); 48 - *fb_div = fb_div_max; 49 - } 50 -} 51 - 52 /** 53 * radeon_compute_pll_avivo - compute PLL paramaters 54 * 55 @@ -892,9 +860,6 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, 56 u32 *ref_div_p, 57 u32 *post_div_p) 58 { 59 - unsigned target_clock = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? 60 - freq : freq / 10; 61 - 62 unsigned fb_div_min, fb_div_max, fb_div; 63 unsigned post_div_min, post_div_max, post_div; 64 unsigned ref_div_min, ref_div_max, ref_div; 65 @@ -927,6 +892,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, 66 post_div_min = pll->post_div; 67 post_div_max = pll->post_div; 68 } else { 69 + unsigned target_clock = freq / 10; 70 unsigned vco_min, vco_max; 71 72 if (pll->flags & RADEON_PLL_IS_LCD) { 73 @@ -937,11 +903,6 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, 74 vco_max = pll->pll_out_max; 75 } 76 77 - if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { 78 - vco_min *= 10; 79 - vco_max *= 10; 80 - } 81 - 82 post_div_min = vco_min / target_clock; 83 if ((target_clock * post_div_min) < vco_min) 84 ++post_div_min; 85 @@ -956,7 +917,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, 86 } 87 88 /* represent the searched ratio as fractional number */ 89 - nom = target_clock; 90 + nom = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? freq : freq / 10; 91 den = pll->reference_freq; 92 93 /* reduce the numbers to a simpler ratio */ 94 @@ -970,12 +931,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, 95 diff_best = ~0; 96 97 for (post_div = post_div_min; post_div <= post_div_max; ++post_div) { 98 - unsigned diff; 99 - avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, 100 - ref_div_max, &fb_div, &ref_div); 101 - diff = abs(target_clock - (pll->reference_freq * fb_div) / 102 - (ref_div * post_div)); 103 - 104 + unsigned diff = abs(den - den / post_div * post_div); 105 if (diff < diff_best || (diff == diff_best && 106 !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) { 107 108 @@ -985,9 +941,28 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, 109 } 110 post_div = post_div_best; 111 112 - /* get the feedback and reference divider for the optimal value */ 113 - avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, ref_div_max, 114 - &fb_div, &ref_div); 115 + /* limit reference * post divider to a maximum */ 116 + ref_div_max = min(210 / post_div, ref_div_max); 117 + 118 + /* get matching reference and feedback divider */ 119 + ref_div = max(DIV_ROUND_CLOSEST(den, post_div), 1u); 120 + fb_div = DIV_ROUND_CLOSEST(nom * ref_div * post_div, den); 121 + 122 + /* we're almost done, but reference and feedback 123 + divider might be to large now */ 124 + 125 + nom = fb_div; 126 + den = ref_div; 127 + 128 + if (fb_div > fb_div_max) { 129 + ref_div = DIV_ROUND_CLOSEST(den * fb_div_max, nom); 130 + fb_div = fb_div_max; 131 + } 132 + 133 + if (ref_div > ref_div_max) { 134 + ref_div = ref_div_max; 135 + fb_div = DIV_ROUND_CLOSEST(nom * ref_div_max, den); 136 + } 137 138 /* reduce the numbers to a simpler ratio once more */ 139 /* this also makes sure that the reference divider is large enough */ 140 @@ -1009,7 +984,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, 141 *post_div_p = post_div; 142 143 DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n", 144 - freq, *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p, 145 + freq, *dot_clock_p, *fb_div_p, *frac_fb_div_p, 146 ref_div, post_div); 147 } 148