aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/si.c
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2013-04-29 05:55:02 -0400
committerAlex Deucher <alexander.deucher@amd.com>2013-05-02 10:09:48 -0400
commitfacd112d1395fb6a0b6e460778aefc32197afcfc (patch)
tree69cc696021ccfe1eb1d78a7aedfb32f984675118 /drivers/gpu/drm/radeon/si.c
parent092fbc4ca29a3d78895673479f794ee162a13ac5 (diff)
drm/radeon: consolidate UVD clock programming
Instead of duplicating the code over and over again, just use a single function to handle the clock calculations. Signed-off-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/si.c')
-rw-r--r--drivers/gpu/drm/radeon/si.c104
1 files changed, 11 insertions, 93 deletions
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index fe6b14e0021c..f0b6c2f87c4d 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -5415,62 +5415,9 @@ uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev)
5415 return clock; 5415 return clock;
5416} 5416}
5417 5417
5418static int si_uvd_calc_post_div(unsigned target_freq,
5419 unsigned vco_freq,
5420 unsigned *div)
5421{
5422 /* target larger than vco frequency ? */
5423 if (vco_freq < target_freq)
5424 return -1; /* forget it */
5425
5426 /* Fclk = Fvco / PDIV */
5427 *div = vco_freq / target_freq;
5428
5429 /* we alway need a frequency less than or equal the target */
5430 if ((vco_freq / *div) > target_freq)
5431 *div += 1;
5432
5433 /* dividers above 5 must be even */
5434 if (*div > 5 && *div % 2)
5435 *div += 1;
5436
5437 /* out of range ? */
5438 if (*div >= 128)
5439 return -1; /* forget it */
5440
5441 return vco_freq / *div;
5442}
5443
5444static int si_uvd_send_upll_ctlreq(struct radeon_device *rdev)
5445{
5446 unsigned i;
5447
5448 /* assert UPLL_CTLREQ */
5449 WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK);
5450
5451 /* wait for CTLACK and CTLACK2 to get asserted */
5452 for (i = 0; i < 100; ++i) {
5453 uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK;
5454 if ((RREG32(CG_UPLL_FUNC_CNTL) & mask) == mask)
5455 break;
5456 mdelay(10);
5457 }
5458 if (i == 100)
5459 return -ETIMEDOUT;
5460
5461 /* deassert UPLL_CTLREQ */
5462 WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_CTLREQ_MASK);
5463
5464 return 0;
5465}
5466
5467int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) 5418int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
5468{ 5419{
5469 /* start off with something large */ 5420 unsigned fb_div = 0, vclk_div = 0, dclk_div = 0;
5470 int optimal_diff_score = 0x7FFFFFF;
5471 unsigned optimal_fb_div = 0, optimal_vclk_div = 0;
5472 unsigned optimal_dclk_div = 0, optimal_vco_freq = 0;
5473 unsigned vco_freq;
5474 int r; 5421 int r;
5475 5422
5476 /* bypass vclk and dclk with bclk */ 5423 /* bypass vclk and dclk with bclk */
@@ -5487,40 +5434,11 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
5487 return 0; 5434 return 0;
5488 } 5435 }
5489 5436
5490 /* loop through vco from low to high */ 5437 r = radeon_uvd_calc_upll_dividers(rdev, vclk, dclk, 125000, 250000,
5491 for (vco_freq = 125000; vco_freq <= 250000; vco_freq += 100) { 5438 16384, 0x03FFFFFF, 0, 128, 5,
5492 unsigned fb_div = vco_freq / rdev->clock.spll.reference_freq * 16384; 5439 &fb_div, &vclk_div, &dclk_div);
5493 int calc_clk, diff_score, diff_vclk, diff_dclk; 5440 if (r)
5494 unsigned vclk_div, dclk_div; 5441 return r;
5495
5496 /* fb div out of range ? */
5497 if (fb_div > 0x03FFFFFF)
5498 break; /* it can oly get worse */
5499
5500 /* calc vclk with current vco freq. */
5501 calc_clk = si_uvd_calc_post_div(vclk, vco_freq, &vclk_div);
5502 if (calc_clk == -1)
5503 break; /* vco is too big, it has to stop. */
5504 diff_vclk = vclk - calc_clk;
5505
5506 /* calc dclk with current vco freq. */
5507 calc_clk = si_uvd_calc_post_div(dclk, vco_freq, &dclk_div);
5508 if (calc_clk == -1)
5509 break; /* vco is too big, it has to stop. */
5510 diff_dclk = dclk - calc_clk;
5511
5512 /* determine if this vco setting is better than current optimal settings */
5513 diff_score = abs(diff_vclk) + abs(diff_dclk);
5514 if (diff_score < optimal_diff_score) {
5515 optimal_fb_div = fb_div;
5516 optimal_vclk_div = vclk_div;
5517 optimal_dclk_div = dclk_div;
5518 optimal_vco_freq = vco_freq;
5519 optimal_diff_score = diff_score;
5520 if (optimal_diff_score == 0)
5521 break; /* it can't get better than this */
5522 }
5523 }
5524 5442
5525 /* set RESET_ANTI_MUX to 0 */ 5443 /* set RESET_ANTI_MUX to 0 */
5526 WREG32_P(CG_UPLL_FUNC_CNTL_5, 0, ~RESET_ANTI_MUX_MASK); 5444 WREG32_P(CG_UPLL_FUNC_CNTL_5, 0, ~RESET_ANTI_MUX_MASK);
@@ -5537,7 +5455,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
5537 5455
5538 mdelay(1); 5456 mdelay(1);
5539 5457
5540 r = si_uvd_send_upll_ctlreq(rdev); 5458 r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL);
5541 if (r) 5459 if (r)
5542 return r; 5460 return r;
5543 5461
@@ -5548,19 +5466,19 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
5548 WREG32_P(CG_UPLL_SPREAD_SPECTRUM, 0, ~SSEN_MASK); 5466 WREG32_P(CG_UPLL_SPREAD_SPECTRUM, 0, ~SSEN_MASK);
5549 5467
5550 /* set feedback divider */ 5468 /* set feedback divider */
5551 WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(optimal_fb_div), ~UPLL_FB_DIV_MASK); 5469 WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(fb_div), ~UPLL_FB_DIV_MASK);
5552 5470
5553 /* set ref divider to 0 */ 5471 /* set ref divider to 0 */
5554 WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_REF_DIV_MASK); 5472 WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_REF_DIV_MASK);
5555 5473
5556 if (optimal_vco_freq < 187500) 5474 if (fb_div < 307200)
5557 WREG32_P(CG_UPLL_FUNC_CNTL_4, 0, ~UPLL_SPARE_ISPARE9); 5475 WREG32_P(CG_UPLL_FUNC_CNTL_4, 0, ~UPLL_SPARE_ISPARE9);
5558 else 5476 else
5559 WREG32_P(CG_UPLL_FUNC_CNTL_4, UPLL_SPARE_ISPARE9, ~UPLL_SPARE_ISPARE9); 5477 WREG32_P(CG_UPLL_FUNC_CNTL_4, UPLL_SPARE_ISPARE9, ~UPLL_SPARE_ISPARE9);
5560 5478
5561 /* set PDIV_A and PDIV_B */ 5479 /* set PDIV_A and PDIV_B */
5562 WREG32_P(CG_UPLL_FUNC_CNTL_2, 5480 WREG32_P(CG_UPLL_FUNC_CNTL_2,
5563 UPLL_PDIV_A(optimal_vclk_div) | UPLL_PDIV_B(optimal_dclk_div), 5481 UPLL_PDIV_A(vclk_div) | UPLL_PDIV_B(dclk_div),
5564 ~(UPLL_PDIV_A_MASK | UPLL_PDIV_B_MASK)); 5482 ~(UPLL_PDIV_A_MASK | UPLL_PDIV_B_MASK));
5565 5483
5566 /* give the PLL some time to settle */ 5484 /* give the PLL some time to settle */
@@ -5574,7 +5492,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
5574 /* switch from bypass mode to normal mode */ 5492 /* switch from bypass mode to normal mode */
5575 WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK); 5493 WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK);
5576 5494
5577 r = si_uvd_send_upll_ctlreq(rdev); 5495 r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL);
5578 if (r) 5496 if (r)
5579 return r; 5497 return r;
5580 5498