Re: 回复: Re: 回复: Re: [PATCH] drm:Fix the blank screen problem of some 1920x1080 75Hz monitors using R520 graphics card

Christian König christian.koenig at amd.com
Wed Sep 14 08:40:35 UTC 2022


> If the *diff* is smaller when the value of *ref_div_max* is 100, set 
> the value of *ref_div_max* to 100. Otherwise, set the value of 
> *ref_div_max* to 128. In this way, the value of *ref_div_max* can be 
> determined according to the value of *diff*, in order to adapt to all 
> monitors. After our verification on different monitors, those monitors 
> that have a blank screen problem when the value of *ref_div_max* is 
> 100 or 128 can work normally under this scheme.

Well sorry to say that, but once more: This approach is just blank nonsense!

The problem with a larger reference/post dividers is that you your 
intermediate frequency becomes to large and the PLL starts to swing 
between two frequencies which are above and below the desired result.

So a maximum ref_div of 128 is simply not acceptable for the hardware.

Regards,
Christian.

Am 14.09.22 um 04:17 schrieb 钟沛:
>
> Sorry to trouble you, we ran some tests on this patch and want to 
> communicate with you.
>
>
> *static void amdgpu_pll_get_fb_ref_div(struct amdgpu_device *adev, 
> unsigned nom, unsigned den, unsigned post_div,*
>
> *unsigned fb_div_max, unsigned ref_div_max,*
>
> *unsigned *fb_div, unsigned *ref_div)*
>
> *{*
>
>
> *   /* limit reference * post divider to a maximum */*
>
> *if (adev->family == AMDGPU_FAMILY_SI)*
>
> *ref_div_max = min(100 / post_div, ref_div_max);*
>
> *else*
>
> *ref_div_max = min(128 / post_div, ref_div_max);*
>
>
> *   /* get matching reference and feedback divider */*
>
> *    *ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), 
> ref_div_max);*
>
> *    *fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den);*
>
>
> *   /* limit fb divider to its maximum */*
>
> *if (*fb_div > fb_div_max) {*
>
> *        *ref_div = DIV_ROUND_CLOSEST(*ref_div * fb_div_max, *fb_div);*
>
> *        *fb_div = fb_div_max;*
>
> *    }*
>
> *}*
>
>
> For R520, the max value of the ref_div_max in this function used to be 
> 128. In order to fix the black screen problem of some monitors, it was 
> changed to 100. From the commit message at the time, we learned that 
> this was a temporary solution. When the value of ref_div_max is 100, 
> it will also cause problems with some monitors.
>
>
> *void amdgpu_pll_compute(struct amdgpu_device *adev, struct amdgpu_pll 
> *pll, u32 freq, u32 *dot_clock_p,*
>
> *                                            u32 *fb_div_p,*
>
> *                                            u32 *frac_fb_div_p,*
>
> *                                            u32 *ref_div_p,*
>
> *                                            u32 *post_div_p)*
>
> *{*
>
> *    ......
> *
>
> **
>
> */* now search for a post divider */*
>
> *if (pll->flags & AMDGPU_PLL_PREFER_MINM_OVER_MAXP)*
>
> *post_div_best = post_div_min;*
>
> *    else*
>
> *post_div_best = post_div_max;*
>
> *diff_best = ~0;*
>
>
> *for (post_div = post_div_min; post_div <= post_div_max; ++post_div) {*
>
> *unsigned diff;*
>
> *amdgpu_pll_get_fb_ref_div(adev, nom, den, post_div, fb_div_max,*
>
> *ref_div_max, &fb_div, &ref_div**);*
>
> *diff = abs(target_clock - (pll->reference_freq * fb_div) /*
>
> *                (ref_div * post_div));*
>
>
> *if (diff < diff_best || (diff == diff_best &&*
>
> *                !(pll->flags & AMDGPU_PLL_PREFER_MINM_OVER_MAXP))) {*
>
>
> *post_div_best = post_div;*
>
> *diff_best = diff;*
>
> *        }*
>
> *    }*
>
> *post_div = post_div_best;*
>
> *    ......
> *
>
> *}*
>
>
> This piece of code in the above function is to find a post_div, so 
> that the value of *diff = abs(target_clock - (pll->reference_freq * 
> fb_div) /(ref_div * post_div))* is the smallest. The pixel clock 
> closest to the target frequency when the value of the *diff* is the 
> smallest. The values of the reference divider(*ref_div*) and feedback 
> divider(*fb_div*) in the above formula are affected by *ref_div_max*, 
> so when the value of *ref_div_max* is different, the value of *diff* 
> may also be different. The larger value of *diff* may cause the blank 
> screen problem of some monitors.
>
>
> A value of 100 or 128 for *ref_div_max* is not suitable for all 
> monitors. So we set it to 100 and 128 in turn to calculate the 
> corresponding ref_div and fb_div values, and then calculate *diff = 
> abs(target_clock - (pll->reference_freq * fb_div) /(ref_div * 
> post_div))*. If the *diff* is smaller when the value of *ref_div_max* 
> is 100, set the value of *ref_div_max* to 100. Otherwise, set the 
> value of *ref_div_max* to 128. In this way, the value of *ref_div_max* 
> can be determined according to the value of *diff*, in order to adapt 
> to all monitors. After our verification on different monitors, those 
> monitors that have a blank screen problem when the value of 
> *ref_div_max* is 100 or 128 can work normally under this scheme.
>
>
> We believe that temporarily adopting this method to replace the 
> previous method can improve the compatibility of the graphics card.
>
>
> Best Regards.
>
> ----
>
>
>
>
>
>
>
> *主 题:*Re: 回复: Re: [PATCH] drm:Fix the blank screen problem of some 
> 1920x1080 75Hz monitors using R520 graphics card
> *日 期:*2022-09-05 19:12
> *发件人:*Christian König
> *收件人:*钟沛alexander.deucher at amd.comXinhui.Pan@amd.comairlied at linux.iedaniel@ffwll.chisabbasso at riseup.net 
>
>
>
> Am 05.09.22 um 10:10 schrieb 钟沛:
>
> Thanks for your reply!
>
>
> We found that in the amdgpu_pll_compute function, when the   
>  target_clock is the value contained in the drm_dmt_modes defined     
>    in drm_edid.c, the diff is 0. When target_clock is some special     
>    value, we cannot find a diff value of 0, so we need to find the     
>    smallest diff value to fit the current target_clock. For the       
>  monitor that has the blank screen problem here, we found that       
>  when the ref_div_max is 128, the diff value is smaller and the       
>  blank screen problem can be solved. We tested some other       
>  monitors and added log printing to the code. We found that this       
>  change did not affect those monitors, and in the analysis of the 
>  logs, we found that the solution with a smaller diff value    always 
> displayed normally.
>
>
> Changing the value of ref_div_max from 128 to 100 can solve the       
>  blank screen problem of some monitors, but it will also cause       
>  some normal monitors to go black, so is it a more reasonable       
>  solution to determine the value of ref_div_max according to the       
>  value of diff?
>
>
>    Nope, exactly that's just utterly nonsense.
>
>    What we could maybe do is to prefer a smaller ref_div over a larger 
>    ref_div, but I don't see how this will help you.
>
>    Regards,
>    Christian.
>
>
>      Thank you for taking the time to read my email.
>
>
> Best Regards.
>
> ----
>
>
>
>
>
>
>
> *主 题:*Re: [PATCH] drm:Fix the          blank screen problem of some 
> 1920x1080 75Hz monitors using          R520 graphics card
> *日 期:*2022-09-05 14:05
> *发件人:*Christian König
> *收件人:*钟沛alexander.deucher at amd.comXinhui.Pan@amd.comairlied at linux.iedaniel@ffwll.chisabbasso at riseup.net 
>
>
>
> Am 05.09.22 um 05:23 schrieb zhongpei:
>        > We found that in the scenario of AMD R520 graphics card
>        > and some 1920x1080 monitors,when we switch the refresh rate
>        > of the monitor to 75Hz,the monitor will have a blank screen   
>      problem,
>        > and the restart cannot be restored.After testing, it is       
>  found that
>        > when we limit the maximum value of ref_div_max to 128,
>        > the problem can be solved.In order to keep the previous       
>  modification
>        > to be compatible with other monitors,we added a judgment
>        > when finding the minimum diff value in the loop of the
>        > amdgpu_pll_compute/radeon_compute_pll_avivo function.
>        > If no diff value of 0 is found when the maximum value of     
>    ref_div_max
>        > is limited to 100,continue to search when it is 128,
>        > and take the parameter with the smallest diff value.
>
>        Well that's at least better than what I've seen in previous     
>    tries to fix
>        this.
>
>        But as far as I can see this will certainly break some other   
>      monitors,
>        so that is pretty much a NAK.
>
>        Regards,
>        Christian.
>
>        >
>        > Signed-off-by: zhongpei <zhongpei at kylinos.cn>
>        > ---
>        >   drivers/gpu/drm/amd/amdgpu/amdgpu_pll.c | 17  +++++++++++++----
>        >   drivers/gpu/drm/radeon/radeon_display.c | 15  +++++++++++----
>        >   2 files changed, 24 insertions(+), 8 deletions(-)
>        >
>        > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pll.c       
>  b/drivers/gpu/drm/amd/amdgpu/amdgpu_pll.c
>        > index 0bb2466d539a..0c298faa0f94 100644
>        > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pll.c
>        > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pll.c
>        > @@ -84,12 +84,13 @@ static void 
>  amdgpu_pll_reduce_ratio(unsigned *nom, unsigned *den,
>        >   static void amdgpu_pll_get_fb_ref_div(struct  amdgpu_device 
> *adev, unsigned int nom,
>        >        unsigned int den, unsigned int post_div,
>        >        unsigned int fb_div_max, unsigned int ref_div_max,
>        > -      unsigned int *fb_div, unsigned int *ref_div)
>        > +      unsigned int ref_div_limit, unsigned int *fb_div,
>        > +      unsigned int *ref_div)
>        >   {
>        >
>        >   /* limit reference * post divider to a maximum */
>        >   if (adev->family == AMDGPU_FAMILY_SI)
>        > - ref_div_max = min(100 / post_div, ref_div_max);
>        > + ref_div_max = min(ref_div_limit / post_div, ref_div_max);
>        >   else
>        >   ref_div_max = min(128 / post_div, ref_div_max);
>        >
>        > @@ -136,6 +137,7 @@ void amdgpu_pll_compute(struct     
>  amdgpu_device *adev,
>        >   unsigned ref_div_min, ref_div_max, ref_div;
>        >   unsigned post_div_best, diff_best;
>        >   unsigned nom, den;
>        > + unsigned ref_div_limit, ref_limit_best;
>        >
>        >   /* determine allowed feedback divider range */
>        >   fb_div_min = pll->min_feedback_div;
>        > @@ -204,11 +206,12 @@ void amdgpu_pll_compute(struct       
>  amdgpu_device *adev,
>        >   else
>        >   post_div_best = post_div_max;
>        >   diff_best = ~0;
>        > + ref_div_limit = ref_limit_best = 100;
>        >
>        >   for (post_div = post_div_min; post_div <=  post_div_max; 
> ++post_div) {
>        >   unsigned diff;
>        >   amdgpu_pll_get_fb_ref_div(adev, nom, den, post_div,       
>  fb_div_max,
>        > -  ref_div_max, &fb_div, &ref_div);
>        > +  ref_div_max, ref_div_limit, &fb_div, &ref_div);
>        >   diff = abs(target_clock - (pll->reference_freq *       
>  fb_div) /
>        >   (ref_div * post_div));
>        >
>        > @@ -217,13 +220,19 @@ void amdgpu_pll_compute(struct       
>  amdgpu_device *adev,
>        >
>        >   post_div_best = post_div;
>        >   diff_best = diff;
>        > + ref_limit_best = ref_div_limit;
>        >   }
>        > + if (post_div >= post_div_max && diff_best != 0        && 
> ref_div_limit != 128) {
>        > + ref_div_limit = 128;
>        > + post_div = post_div_min - 1;
>        > + }
>        > +
>        >   }
>        >   post_div = post_div_best;
>        >
>        >   /* get the feedback and reference divider for the optimal   
>      value */
>        >   amdgpu_pll_get_fb_ref_div(adev, nom, den, post_div,       
>  fb_div_max, ref_div_max,
>        > -  &fb_div, &ref_div);
>        > +  ref_limit_best, &fb_div, &ref_div);
>        >
>        >   /* reduce the numbers to a simpler ratio once more */
>        >   /* this also makes sure that the reference divider is       
>  large enough */
>        > diff --git a/drivers/gpu/drm/radeon/radeon_display.c       
>  b/drivers/gpu/drm/radeon/radeon_display.c
>        > index f12675e3d261..0fcbf45a68db 100644
>        > --- a/drivers/gpu/drm/radeon/radeon_display.c
>        > +++ b/drivers/gpu/drm/radeon/radeon_display.c
>        > @@ -925,10 +925,10 @@ static void 
>  avivo_reduce_ratio(unsigned *nom, unsigned *den,
>        >    */
>        >   static void avivo_get_fb_ref_div(unsigned nom, unsigned     
>    den, unsigned post_div,
>        >   unsigned fb_div_max, unsigned ref_div_max,
>        > - unsigned *fb_div, unsigned *ref_div)
>        > + unsigned ref_div_limit, unsigned *fb_div, unsigned       
>  *ref_div)
>        >   {
>        >   /* limit reference * post divider to a maximum */
>        > - ref_div_max = max(min(100 / post_div, ref_div_max), 1u);
>        > + ref_div_max = max(min(ref_div_limit / post_div,     
>  ref_div_max), 1u);
>        >
>        >   /* get matching reference and feedback divider */
>        >   *ref_div = min(max(den/post_div, 1u), ref_div_max);
>        > @@ -971,6 +971,7 @@ void radeon_compute_pll_avivo(struct     
>    radeon_pll *pll,
>        >   unsigned ref_div_min, ref_div_max, ref_div;
>        >   unsigned post_div_best, diff_best;
>        >   unsigned nom, den;
>        > + unsigned ref_div_limit, ref_limit_best;
>        >
>        >   /* determine allowed feedback divider range */
>        >   fb_div_min = pll->min_feedback_div;
>        > @@ -1042,11 +1043,12 @@ void  radeon_compute_pll_avivo(struct 
> radeon_pll *pll,
>        >   else
>        >   post_div_best = post_div_max;
>        >   diff_best = ~0;
>        > + ref_div_limit = ref_limit_best = 100;
>        >
>        >   for (post_div = post_div_min; post_div <=  post_div_max; 
> ++post_div) {
>        >   unsigned diff;
>        >   avivo_get_fb_ref_div(nom, den, post_div, fb_div_max,
>        > -     ref_div_max, &fb_div, &ref_div);
>        > +     ref_div_max, ref_div_limit, &fb_div,  &ref_div);
>        >   diff = abs(target_clock - (pll->reference_freq *       
>  fb_div) /
>        >   (ref_div * post_div));
>        >
>        > @@ -1055,13 +1057,18 @@ void  radeon_compute_pll_avivo(struct 
> radeon_pll *pll,
>        >
>        >   post_div_best = post_div;
>        >   diff_best = diff;
>        > + ref_limit_best = ref_div_limit;
>        > + }
>        > + if (post_div >= post_div_max && diff_best != 0        && 
> ref_div_limit != 128) {
>        > + ref_div_limit = 128;
>        > + post_div = post_div_min - 1;
>        >   }
>        >   }
>        >   post_div = post_div_best;
>        >
>        >   /* get the feedback and reference divider for the optimal   
>      value */
>        >   avivo_get_fb_ref_div(nom, den, post_div, fb_div_max,       
>  ref_div_max,
>        > -     &fb_div, &ref_div);
>        > +     ref_limit_best, &fb_div, &ref_div);
>        >
>        >   /* reduce the numbers to a simpler ratio once more */
>        >   /* this also makes sure that the reference divider is       
>  large enough */
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/amd-gfx/attachments/20220914/af0a7197/attachment-0001.htm>


More information about the amd-gfx mailing list