|
@@ -454,13 +454,13 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d)
|
|
|
return n;
|
|
|
}
|
|
|
|
|
|
-static void radeon_compute_pll_legacy(struct radeon_pll *pll,
|
|
|
- uint64_t freq,
|
|
|
- uint32_t *dot_clock_p,
|
|
|
- uint32_t *fb_div_p,
|
|
|
- uint32_t *frac_fb_div_p,
|
|
|
- uint32_t *ref_div_p,
|
|
|
- uint32_t *post_div_p)
|
|
|
+void radeon_compute_pll(struct radeon_pll *pll,
|
|
|
+ uint64_t freq,
|
|
|
+ uint32_t *dot_clock_p,
|
|
|
+ uint32_t *fb_div_p,
|
|
|
+ uint32_t *frac_fb_div_p,
|
|
|
+ uint32_t *ref_div_p,
|
|
|
+ uint32_t *post_div_p)
|
|
|
{
|
|
|
uint32_t min_ref_div = pll->min_ref_div;
|
|
|
uint32_t max_ref_div = pll->max_ref_div;
|
|
@@ -609,214 +609,6 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
|
|
|
*post_div_p = best_post_div;
|
|
|
}
|
|
|
|
|
|
-static bool
|
|
|
-calc_fb_div(struct radeon_pll *pll,
|
|
|
- uint32_t freq,
|
|
|
- uint32_t post_div,
|
|
|
- uint32_t ref_div,
|
|
|
- uint32_t *fb_div,
|
|
|
- uint32_t *fb_div_frac)
|
|
|
-{
|
|
|
- fixed20_12 feedback_divider, a, b;
|
|
|
- u32 vco_freq;
|
|
|
-
|
|
|
- vco_freq = freq * post_div;
|
|
|
- /* feedback_divider = vco_freq * ref_div / pll->reference_freq; */
|
|
|
- a.full = dfixed_const(pll->reference_freq);
|
|
|
- feedback_divider.full = dfixed_const(vco_freq);
|
|
|
- feedback_divider.full = dfixed_div(feedback_divider, a);
|
|
|
- a.full = dfixed_const(ref_div);
|
|
|
- feedback_divider.full = dfixed_mul(feedback_divider, a);
|
|
|
-
|
|
|
- if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
|
|
|
- /* feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; */
|
|
|
- a.full = dfixed_const(10);
|
|
|
- feedback_divider.full = dfixed_mul(feedback_divider, a);
|
|
|
- feedback_divider.full += dfixed_const_half(0);
|
|
|
- feedback_divider.full = dfixed_floor(feedback_divider);
|
|
|
- feedback_divider.full = dfixed_div(feedback_divider, a);
|
|
|
-
|
|
|
- /* *fb_div = floor(feedback_divider); */
|
|
|
- a.full = dfixed_floor(feedback_divider);
|
|
|
- *fb_div = dfixed_trunc(a);
|
|
|
- /* *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; */
|
|
|
- a.full = dfixed_const(10);
|
|
|
- b.full = dfixed_mul(feedback_divider, a);
|
|
|
-
|
|
|
- feedback_divider.full = dfixed_floor(feedback_divider);
|
|
|
- feedback_divider.full = dfixed_mul(feedback_divider, a);
|
|
|
- feedback_divider.full = b.full - feedback_divider.full;
|
|
|
- *fb_div_frac = dfixed_trunc(feedback_divider);
|
|
|
- } else {
|
|
|
- /* *fb_div = floor(feedback_divider + 0.5); */
|
|
|
- feedback_divider.full += dfixed_const_half(0);
|
|
|
- feedback_divider.full = dfixed_floor(feedback_divider);
|
|
|
-
|
|
|
- *fb_div = dfixed_trunc(feedback_divider);
|
|
|
- *fb_div_frac = 0;
|
|
|
- }
|
|
|
-
|
|
|
- if (((*fb_div) < pll->min_feedback_div) || ((*fb_div) > pll->max_feedback_div))
|
|
|
- return false;
|
|
|
- else
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-static bool
|
|
|
-calc_fb_ref_div(struct radeon_pll *pll,
|
|
|
- uint32_t freq,
|
|
|
- uint32_t post_div,
|
|
|
- uint32_t *fb_div,
|
|
|
- uint32_t *fb_div_frac,
|
|
|
- uint32_t *ref_div)
|
|
|
-{
|
|
|
- fixed20_12 ffreq, max_error, error, pll_out, a;
|
|
|
- u32 vco;
|
|
|
- u32 pll_out_min, pll_out_max;
|
|
|
-
|
|
|
- if (pll->flags & RADEON_PLL_IS_LCD) {
|
|
|
- pll_out_min = pll->lcd_pll_out_min;
|
|
|
- pll_out_max = pll->lcd_pll_out_max;
|
|
|
- } else {
|
|
|
- pll_out_min = pll->pll_out_min;
|
|
|
- pll_out_max = pll->pll_out_max;
|
|
|
- }
|
|
|
-
|
|
|
- ffreq.full = dfixed_const(freq);
|
|
|
- /* max_error = ffreq * 0.0025; */
|
|
|
- a.full = dfixed_const(400);
|
|
|
- max_error.full = dfixed_div(ffreq, a);
|
|
|
-
|
|
|
- for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) {
|
|
|
- if (calc_fb_div(pll, freq, post_div, (*ref_div), fb_div, fb_div_frac)) {
|
|
|
- vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
|
|
|
- vco = vco / ((*ref_div) * 10);
|
|
|
-
|
|
|
- if ((vco < pll_out_min) || (vco > pll_out_max))
|
|
|
- continue;
|
|
|
-
|
|
|
- /* pll_out = vco / post_div; */
|
|
|
- a.full = dfixed_const(post_div);
|
|
|
- pll_out.full = dfixed_const(vco);
|
|
|
- pll_out.full = dfixed_div(pll_out, a);
|
|
|
-
|
|
|
- if (pll_out.full >= ffreq.full) {
|
|
|
- error.full = pll_out.full - ffreq.full;
|
|
|
- if (error.full <= max_error.full)
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static void radeon_compute_pll_new(struct radeon_pll *pll,
|
|
|
- uint64_t freq,
|
|
|
- uint32_t *dot_clock_p,
|
|
|
- uint32_t *fb_div_p,
|
|
|
- uint32_t *frac_fb_div_p,
|
|
|
- uint32_t *ref_div_p,
|
|
|
- uint32_t *post_div_p)
|
|
|
-{
|
|
|
- u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0;
|
|
|
- u32 best_freq = 0, vco_frequency;
|
|
|
- u32 pll_out_min, pll_out_max;
|
|
|
-
|
|
|
- if (pll->flags & RADEON_PLL_IS_LCD) {
|
|
|
- pll_out_min = pll->lcd_pll_out_min;
|
|
|
- pll_out_max = pll->lcd_pll_out_max;
|
|
|
- } else {
|
|
|
- pll_out_min = pll->pll_out_min;
|
|
|
- pll_out_max = pll->pll_out_max;
|
|
|
- }
|
|
|
-
|
|
|
- /* freq = freq / 10; */
|
|
|
- do_div(freq, 10);
|
|
|
-
|
|
|
- if (pll->flags & RADEON_PLL_USE_POST_DIV) {
|
|
|
- post_div = pll->post_div;
|
|
|
- if ((post_div < pll->min_post_div) || (post_div > pll->max_post_div))
|
|
|
- goto done;
|
|
|
-
|
|
|
- vco_frequency = freq * post_div;
|
|
|
- if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
|
|
|
- goto done;
|
|
|
-
|
|
|
- if (pll->flags & RADEON_PLL_USE_REF_DIV) {
|
|
|
- ref_div = pll->reference_div;
|
|
|
- if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
|
|
|
- goto done;
|
|
|
- if (!calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
|
|
|
- goto done;
|
|
|
- }
|
|
|
- } else {
|
|
|
- for (post_div = pll->max_post_div; post_div >= pll->min_post_div; --post_div) {
|
|
|
- if (pll->flags & RADEON_PLL_LEGACY) {
|
|
|
- if ((post_div == 5) ||
|
|
|
- (post_div == 7) ||
|
|
|
- (post_div == 9) ||
|
|
|
- (post_div == 10) ||
|
|
|
- (post_div == 11))
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
|
|
|
- continue;
|
|
|
-
|
|
|
- vco_frequency = freq * post_div;
|
|
|
- if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
|
|
|
- continue;
|
|
|
- if (pll->flags & RADEON_PLL_USE_REF_DIV) {
|
|
|
- ref_div = pll->reference_div;
|
|
|
- if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
|
|
|
- goto done;
|
|
|
- if (calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
|
|
|
- break;
|
|
|
- } else {
|
|
|
- if (calc_fb_ref_div(pll, freq, post_div, &fb_div, &fb_div_frac, &ref_div))
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- best_freq = pll->reference_freq * 10 * fb_div;
|
|
|
- best_freq += pll->reference_freq * fb_div_frac;
|
|
|
- best_freq = best_freq / (ref_div * post_div);
|
|
|
-
|
|
|
-done:
|
|
|
- if (best_freq == 0)
|
|
|
- DRM_ERROR("Couldn't find valid PLL dividers\n");
|
|
|
-
|
|
|
- *dot_clock_p = best_freq / 10;
|
|
|
- *fb_div_p = fb_div;
|
|
|
- *frac_fb_div_p = fb_div_frac;
|
|
|
- *ref_div_p = ref_div;
|
|
|
- *post_div_p = post_div;
|
|
|
-
|
|
|
- DRM_DEBUG_KMS("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
|
|
|
-}
|
|
|
-
|
|
|
-void radeon_compute_pll(struct radeon_pll *pll,
|
|
|
- uint64_t freq,
|
|
|
- uint32_t *dot_clock_p,
|
|
|
- uint32_t *fb_div_p,
|
|
|
- uint32_t *frac_fb_div_p,
|
|
|
- uint32_t *ref_div_p,
|
|
|
- uint32_t *post_div_p)
|
|
|
-{
|
|
|
- switch (pll->algo) {
|
|
|
- case PLL_ALGO_NEW:
|
|
|
- radeon_compute_pll_new(pll, freq, dot_clock_p, fb_div_p,
|
|
|
- frac_fb_div_p, ref_div_p, post_div_p);
|
|
|
- break;
|
|
|
- case PLL_ALGO_LEGACY:
|
|
|
- default:
|
|
|
- radeon_compute_pll_legacy(pll, freq, dot_clock_p, fb_div_p,
|
|
|
- frac_fb_div_p, ref_div_p, post_div_p);
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
|
|
|
{
|
|
|
struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
|