radeondrm

make radeondrm(1) work with iMac 11,1
Log | Files | Refs | README

imac_radeondrm_display.diff (9811B)


      1 Index: radeon/radeon_display.c
      2 ===================================================================
      3 RCS file: /cvs/src/sys/dev/pci/drm/radeon/radeon_display.c,v
      4 retrieving revision 1.24
      5 diff -u -p -r1.24 radeon_display.c
      6 --- radeon/radeon_display.c	14 Jan 2022 06:53:15 -0000	1.24
      7 +++ radeon/radeon_display.c	23 Apr 2022 18:10:55 -0000
      8 @@ -864,76 +864,66 @@ static bool radeon_setup_enc_conn(struct
      9  }
     10  
     11  /* avivo */
     12 +static void avivo_get_fb_div(struct radeon_pll *pll,
     13 +			     u32 target_clock,
     14 +			     u32 post_div,
     15 +			     u32 ref_div,
     16 +			     u32 *fb_div,
     17 +			     u32 *frac_fb_div)
     18 +{
     19 +	u32 tmp = post_div * ref_div;
     20  
     21 -/**
     22 - * avivo_reduce_ratio - fractional number reduction
     23 - *
     24 - * @nom: nominator
     25 - * @den: denominator
     26 - * @nom_min: minimum value for nominator
     27 - * @den_min: minimum value for denominator
     28 - *
     29 - * Find the greatest common divisor and apply it on both nominator and
     30 - * denominator, but make nominator and denominator are at least as large
     31 - * as their minimum values.
     32 - */
     33 -static void avivo_reduce_ratio(unsigned *nom, unsigned *den,
     34 -			       unsigned nom_min, unsigned den_min)
     35 +	tmp *= target_clock;
     36 +	*fb_div = tmp / pll->reference_freq;
     37 +	*frac_fb_div = tmp % pll->reference_freq;
     38 +
     39 +        if (*fb_div > pll->max_feedback_div)
     40 +		*fb_div = pll->max_feedback_div;
     41 +        else if (*fb_div < pll->min_feedback_div)
     42 +                *fb_div = pll->min_feedback_div;
     43 +}
     44 +
     45 +static u32 avivo_get_post_div(struct radeon_pll *pll,
     46 +			      u32 target_clock)
     47  {
     48 -	unsigned tmp;
     49 +	u32 vco, post_div, tmp;
     50  
     51 -	/* reduce the numbers to a simpler ratio */
     52 -	tmp = gcd(*nom, *den);
     53 -	*nom /= tmp;
     54 -	*den /= tmp;
     55 -
     56 -	/* make sure nominator is large enough */
     57 -	if (*nom < nom_min) {
     58 -		tmp = DIV_ROUND_UP(nom_min, *nom);
     59 -		*nom *= tmp;
     60 -		*den *= tmp;
     61 +	if (pll->flags & RADEON_PLL_USE_POST_DIV)
     62 +		return pll->post_div;
     63 +
     64 +	if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) {
     65 +		if (pll->flags & RADEON_PLL_IS_LCD)
     66 +			vco = pll->lcd_pll_out_min;
     67 +		else
     68 +			vco = pll->pll_out_min;
     69 +	} else {
     70 +		if (pll->flags & RADEON_PLL_IS_LCD)
     71 +			vco = pll->lcd_pll_out_max;
     72 +		else
     73 +			vco = pll->pll_out_max;
     74  	}
     75  
     76 -	/* make sure the denominator is large enough */
     77 -	if (*den < den_min) {
     78 -		tmp = DIV_ROUND_UP(den_min, *den);
     79 -		*nom *= tmp;
     80 -		*den *= tmp;
     81 +	post_div = vco / target_clock;
     82 +	tmp = vco % target_clock;
     83 +
     84 +	if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) {
     85 +		if (tmp)
     86 +			post_div++;
     87 +	} else {
     88 +		if (!tmp)
     89 +			post_div--;
     90  	}
     91 -}
     92  
     93 -/**
     94 - * avivo_get_fb_ref_div - feedback and ref divider calculation
     95 - *
     96 - * @nom: nominator
     97 - * @den: denominator
     98 - * @post_div: post divider
     99 - * @fb_div_max: feedback divider maximum
    100 - * @ref_div_max: reference divider maximum
    101 - * @fb_div: resulting feedback divider
    102 - * @ref_div: resulting reference divider
    103 - *
    104 - * Calculate feedback and reference divider for a given post divider. Makes
    105 - * sure we stay within the limits.
    106 - */
    107 -static void avivo_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div,
    108 -				 unsigned fb_div_max, unsigned ref_div_max,
    109 -				 unsigned *fb_div, unsigned *ref_div)
    110 -{
    111 -	/* limit reference * post divider to a maximum */
    112 -	ref_div_max = max(min(100 / post_div, ref_div_max), 1u);
    113 +	if (post_div > pll->max_post_div)
    114 +		post_div = pll->max_post_div;
    115 +	else if (post_div < pll->min_post_div)
    116 +		post_div = pll->min_post_div;
    117  
    118 -	/* get matching reference and feedback divider */
    119 -	*ref_div = min(max(den/post_div, 1u), ref_div_max);
    120 -	*fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den);
    121 -
    122 -	/* limit fb divider to its maximum */
    123 -	if (*fb_div > fb_div_max) {
    124 -		*ref_div = (*ref_div * fb_div_max)/(*fb_div);
    125 -		*fb_div = fb_div_max;
    126 -	}
    127 +	return post_div;
    128  }
    129  
    130 +#define MAX_TOLERANCE 10
    131 +
    132  /**
    133   * radeon_compute_pll_avivo - compute PLL paramaters
    134   *
    135 @@ -956,138 +946,55 @@ void radeon_compute_pll_avivo(struct rad
    136  			      u32 *ref_div_p,
    137  			      u32 *post_div_p)
    138  {
    139 -	unsigned target_clock = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ?
    140 -		freq : freq / 10;
    141 -
    142 -	unsigned fb_div_min, fb_div_max, fb_div;
    143 -	unsigned post_div_min, post_div_max, post_div;
    144 -	unsigned ref_div_min, ref_div_max, ref_div;
    145 -	unsigned post_div_best, diff_best;
    146 -	unsigned nom, den;
    147 -
    148 -	/* determine allowed feedback divider range */
    149 -	fb_div_min = pll->min_feedback_div;
    150 -	fb_div_max = pll->max_feedback_div;
    151 -
    152 -	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
    153 -		fb_div_min *= 10;
    154 -		fb_div_max *= 10;
    155 -	}
    156 +       u32 target_clock = freq / 10;
    157 +       u32 post_div = avivo_get_post_div(pll, target_clock);
    158 +       u32 ref_div = pll->min_ref_div;
    159 +       u32 fb_div = 0, frac_fb_div = 0, tmp;
    160  
    161 -	/* determine allowed ref divider range */
    162  	if (pll->flags & RADEON_PLL_USE_REF_DIV)
    163 -		ref_div_min = pll->reference_div;
    164 -	else
    165 -		ref_div_min = pll->min_ref_div;
    166 -
    167 -	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV &&
    168 -	    pll->flags & RADEON_PLL_USE_REF_DIV)
    169 -		ref_div_max = pll->reference_div;
    170 -	else if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP)
    171 -		/* fix for problems on RS880 */
    172 -		ref_div_max = min(pll->max_ref_div, 7u);
    173 -	else
    174 -		ref_div_max = pll->max_ref_div;
    175 -
    176 -	/* determine allowed post divider range */
    177 -	if (pll->flags & RADEON_PLL_USE_POST_DIV) {
    178 -		post_div_min = pll->post_div;
    179 -		post_div_max = pll->post_div;
    180 -	} else {
    181 -		unsigned vco_min, vco_max;
    182 +               ref_div = pll->reference_div;
    183  
    184 -		if (pll->flags & RADEON_PLL_IS_LCD) {
    185 -			vco_min = pll->lcd_pll_out_min;
    186 -			vco_max = pll->lcd_pll_out_max;
    187 -		} else {
    188 -			vco_min = pll->pll_out_min;
    189 -			vco_max = pll->pll_out_max;
    190 +       if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
    191 +               avivo_get_fb_div(pll, target_clock, post_div, ref_div, &fb_div,
    192 + &frac_fb_div);
    193 +               frac_fb_div = (100 * frac_fb_div) / pll->reference_freq;
    194 +               if (frac_fb_div >= 5) {
    195 +                       frac_fb_div -= 5;
    196 +                       frac_fb_div = frac_fb_div / 10;
    197 +                       frac_fb_div++;
    198  		}
    199  
    200 -		if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
    201 -			vco_min *= 10;
    202 -			vco_max *= 10;
    203 +               if (frac_fb_div >= 10) {
    204 +                       fb_div++;
    205 +                       frac_fb_div = 0;
    206  		}
    207 -
    208 -		post_div_min = vco_min / target_clock;
    209 -		if ((target_clock * post_div_min) < vco_min)
    210 -			++post_div_min;
    211 -		if (post_div_min < pll->min_post_div)
    212 -			post_div_min = pll->min_post_div;
    213 -
    214 -		post_div_max = vco_max / target_clock;
    215 -		if ((target_clock * post_div_max) > vco_max)
    216 -			--post_div_max;
    217 -		if (post_div_max > pll->max_post_div)
    218 -			post_div_max = pll->max_post_div;
    219 -	}
    220 -
    221 -	/* represent the searched ratio as fractional number */
    222 -	nom = target_clock;
    223 -	den = pll->reference_freq;
    224 -
    225 -	/* reduce the numbers to a simpler ratio */
    226 -	avivo_reduce_ratio(&nom, &den, fb_div_min, post_div_min);
    227 -
    228 -	/* now search for a post divider */
    229 -	if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP)
    230 -		post_div_best = post_div_min;
    231 -	else
    232 -		post_div_best = post_div_max;
    233 -	diff_best = ~0;
    234 -
    235 -	for (post_div = post_div_min; post_div <= post_div_max; ++post_div) {
    236 -		unsigned diff;
    237 -		avivo_get_fb_ref_div(nom, den, post_div, fb_div_max,
    238 -				     ref_div_max, &fb_div, &ref_div);
    239 -		diff = abs(target_clock - (pll->reference_freq * fb_div) /
    240 -			(ref_div * post_div));
    241 -
    242 -		if (diff < diff_best || (diff == diff_best &&
    243 -		    !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) {
    244 -
    245 -			post_div_best = post_div;
    246 -			diff_best = diff;
    247 -		}
    248 -	}
    249 -	post_div = post_div_best;
    250 -
    251 -	/* get the feedback and reference divider for the optimal value */
    252 -	avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, ref_div_max,
    253 -			     &fb_div, &ref_div);
    254 -
    255 -	/* reduce the numbers to a simpler ratio once more */
    256 -	/* this also makes sure that the reference divider is large enough */
    257 -	avivo_reduce_ratio(&fb_div, &ref_div, fb_div_min, ref_div_min);
    258 -
    259 -	/* avoid high jitter with small fractional dividers */
    260 -	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV && (fb_div % 10)) {
    261 -		fb_div_min = max(fb_div_min, (9 - (fb_div % 10)) * 20 + 50);
    262 -		if (fb_div < fb_div_min) {
    263 -			unsigned tmp = DIV_ROUND_UP(fb_div_min, fb_div);
    264 -			fb_div *= tmp;
    265 -			ref_div *= tmp;
    266 -		}
    267 -	}
    268 -
    269 -	/* and finally save the result */
    270 -	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
    271 -		*fb_div_p = fb_div / 10;
    272 -		*frac_fb_div_p = fb_div % 10;
    273  	} else {
    274 -		*fb_div_p = fb_div;
    275 -		*frac_fb_div_p = 0;
    276 -	}
    277 -
    278 -	*dot_clock_p = ((pll->reference_freq * *fb_div_p * 10) +
    279 -			(pll->reference_freq * *frac_fb_div_p)) /
    280 -		       (ref_div * post_div * 10);
    281 +               while (ref_div <= pll->max_ref_div) {
    282 +                       avivo_get_fb_div(pll, target_clock, post_div, ref_div,
    283 +                                        &fb_div, &frac_fb_div);
    284 +                       if (frac_fb_div >= (pll->reference_freq / 2))
    285 +                               fb_div++;
    286 +                       frac_fb_div = 0;
    287 +                       tmp = (pll->reference_freq * fb_div) / (post_div * ref_div);
    288 +                       tmp = (tmp * 10000) / target_clock;
    289 +
    290 +                       if (tmp > (10000 + MAX_TOLERANCE))
    291 +                               ref_div++;
    292 +                       else if (tmp >= (10000 - MAX_TOLERANCE))
    293 +                               break;
    294 +                       else
    295 +                               ref_div++;
    296 +               }
    297 +	}
    298 +
    299 +       *dot_clock_p = ((pll->reference_freq * fb_div * 10) + (pll->reference_freq * frac_fb_div)) / (ref_div * post_div * 10);
    300 +       *fb_div_p = fb_div;
    301 +       *frac_fb_div_p = frac_fb_div;
    302  	*ref_div_p = ref_div;
    303  	*post_div_p = post_div;
    304  
    305 -	DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
    306 -		      freq, *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p,
    307 -		      ref_div, post_div);
    308 +       DRM_DEBUG_KMS("%d, pll dividers - fb: %d.%d ref: %d, post %d\n",
    309 +                     *dot_clock_p, fb_div, frac_fb_div, ref_div, post_div);
    310  }
    311  
    312  /* pre-avivo */