Skip to content

Commit

Permalink
drm/radeon/kms: add new pll algo for avivo asics
Browse files Browse the repository at this point in the history
Based on the vbios code.  This should hopefully
fix the pll problems on a number of avivo asics
once it's enabled.

Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Cc: stable@kernel.org
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Alex Deucher authored and Dave Airlie committed Feb 2, 2011
1 parent 51d4bf8 commit f523f74
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 19 deletions.
4 changes: 2 additions & 2 deletions drivers/gpu/drm/radeon/atombios_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -951,8 +951,8 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
/* adjust pixel clock as needed */
adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss);

radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
&ref_div, &post_div);
radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
&ref_div, &post_div);

atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss);

Expand Down
123 changes: 116 additions & 7 deletions drivers/gpu/drm/radeon/radeon_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,115 @@ static int radeon_ddc_dump(struct drm_connector *connector)
return ret;
}

/* avivo */
static void avivo_get_fb_div(struct radeon_pll *pll,
u32 target_clock,
u32 post_div,
u32 ref_div,
u32 *fb_div,
u32 *frac_fb_div)
{
u32 tmp = post_div * ref_div;

tmp *= target_clock;
*fb_div = tmp / pll->reference_freq;
*frac_fb_div = tmp % pll->reference_freq;
}

static u32 avivo_get_post_div(struct radeon_pll *pll,
u32 target_clock)
{
u32 vco, post_div, tmp;

if (pll->flags & RADEON_PLL_USE_POST_DIV)
return pll->post_div;

if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) {
if (pll->flags & RADEON_PLL_IS_LCD)
vco = pll->lcd_pll_out_min;
else
vco = pll->pll_out_min;
} else {
if (pll->flags & RADEON_PLL_IS_LCD)
vco = pll->lcd_pll_out_max;
else
vco = pll->pll_out_max;
}

post_div = vco / target_clock;
tmp = vco % target_clock;

if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) {
if (tmp)
post_div++;
} else {
if (!tmp)
post_div--;
}

return post_div;
}

#define MAX_TOLERANCE 10

void radeon_compute_pll_avivo(struct radeon_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)
{
u32 target_clock = freq / 10;
u32 post_div = avivo_get_post_div(pll, target_clock);
u32 ref_div = pll->min_ref_div;
u32 fb_div = 0, frac_fb_div = 0, tmp;

if (pll->flags & RADEON_PLL_USE_REF_DIV)
ref_div = pll->reference_div;

if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
avivo_get_fb_div(pll, target_clock, post_div, ref_div, &fb_div, &frac_fb_div);
frac_fb_div = (100 * frac_fb_div) / pll->reference_freq;
if (frac_fb_div >= 5) {
frac_fb_div -= 5;
frac_fb_div = frac_fb_div / 10;
frac_fb_div++;
}
if (frac_fb_div >= 10) {
fb_div++;
frac_fb_div = 0;
}
} else {
while (ref_div <= pll->max_ref_div) {
avivo_get_fb_div(pll, target_clock, post_div, ref_div,
&fb_div, &frac_fb_div);
if (frac_fb_div >= (pll->reference_freq / 2))
fb_div++;
frac_fb_div = 0;
tmp = (pll->reference_freq * fb_div) / (post_div * ref_div);
tmp = (tmp * 10000) / target_clock;

if (tmp > (10000 + MAX_TOLERANCE))
ref_div++;
else if (tmp >= (10000 - MAX_TOLERANCE))
break;
else
ref_div++;
}
}

*dot_clock_p = ((pll->reference_freq * fb_div * 10) + (pll->reference_freq * frac_fb_div)) /
(ref_div * post_div * 10);
*fb_div_p = fb_div;
*frac_fb_div_p = frac_fb_div;
*ref_div_p = ref_div;
*post_div_p = post_div;
DRM_DEBUG_KMS("%d, pll dividers - fb: %d.%d ref: %d, post %d\n",
*dot_clock_p, fb_div, frac_fb_div, ref_div, post_div);
}

/* pre-avivo */
static inline uint32_t radeon_div(uint64_t n, uint32_t d)
{
uint64_t mod;
Expand All @@ -790,13 +899,13 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d)
return n;
}

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)
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)
{
uint32_t min_ref_div = pll->min_ref_div;
uint32_t max_ref_div = pll->max_ref_div;
Expand Down
6 changes: 3 additions & 3 deletions drivers/gpu/drm/radeon/radeon_legacy_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -778,9 +778,9 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
DRM_DEBUG_KMS("\n");

if (!use_bios_divs) {
radeon_compute_pll(pll, mode->clock,
&freq, &feedback_div, &frac_fb_div,
&reference_div, &post_divider);
radeon_compute_pll_legacy(pll, mode->clock,
&freq, &feedback_div, &frac_fb_div,
&reference_div, &post_divider);

for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
if (post_div->divider == post_divider)
Expand Down
23 changes: 16 additions & 7 deletions drivers/gpu/drm/radeon/radeon_mode.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ struct radeon_tmds_pll {
#define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11)
#define RADEON_PLL_USE_POST_DIV (1 << 12)
#define RADEON_PLL_IS_LCD (1 << 13)
#define RADEON_PLL_PREFER_MINM_OVER_MAXP (1 << 14)

struct radeon_pll {
/* reference frequency */
Expand Down Expand Up @@ -510,13 +511,21 @@ extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
struct radeon_atom_ss *ss,
int id, u32 clock);

extern 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);
extern 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);

extern void radeon_compute_pll_avivo(struct radeon_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);

extern void radeon_setup_encoder_clones(struct drm_device *dev);

Expand Down

0 comments on commit f523f74

Please sign in to comment.