aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/rv770.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/rv770.c')
-rw-r--r--drivers/gpu/drm/radeon/rv770.c110
1 files changed, 17 insertions, 93 deletions
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 91530d4c11c4..83f612a9500b 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -44,56 +44,9 @@ void rv770_fini(struct radeon_device *rdev);
44static void rv770_pcie_gen2_enable(struct radeon_device *rdev); 44static void rv770_pcie_gen2_enable(struct radeon_device *rdev);
45int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); 45int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
46 46
47static int rv770_uvd_calc_post_div(unsigned target_freq,
48 unsigned vco_freq,
49 unsigned *div)
50{
51 /* Fclk = Fvco / PDIV */
52 *div = vco_freq / target_freq;
53
54 /* we alway need a frequency less than or equal the target */
55 if ((vco_freq / *div) > target_freq)
56 *div += 1;
57
58 /* out of range ? */
59 if (*div > 30)
60 return -1; /* forget it */
61
62 *div -= 1;
63 return vco_freq / (*div + 1);
64}
65
66static int rv770_uvd_send_upll_ctlreq(struct radeon_device *rdev)
67{
68 unsigned i;
69
70 /* assert UPLL_CTLREQ */
71 WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK);
72
73 /* wait for CTLACK and CTLACK2 to get asserted */
74 for (i = 0; i < 100; ++i) {
75 uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK;
76 if ((RREG32(CG_UPLL_FUNC_CNTL) & mask) == mask)
77 break;
78 mdelay(10);
79 }
80 if (i == 100)
81 return -ETIMEDOUT;
82
83 /* deassert UPLL_CTLREQ */
84 WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_CTLREQ_MASK);
85
86 return 0;
87}
88
89int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) 47int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
90{ 48{
91 /* start off with something large */ 49 unsigned fb_div = 0, vclk_div = 0, dclk_div = 0;
92 int optimal_diff_score = 0x7FFFFFF;
93 unsigned optimal_fb_div = 0, optimal_vclk_div = 0;
94 unsigned optimal_dclk_div = 0, optimal_vco_freq = 0;
95 unsigned vco_freq, vco_min = 50000, vco_max = 160000;
96 unsigned ref_freq = rdev->clock.spll.reference_freq;
97 int r; 50 int r;
98 51
99 /* RV740 uses evergreen uvd clk programming */ 52 /* RV740 uses evergreen uvd clk programming */
@@ -111,44 +64,15 @@ int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
111 return 0; 64 return 0;
112 } 65 }
113 66
114 /* loop through vco from low to high */ 67 r = radeon_uvd_calc_upll_dividers(rdev, vclk, dclk, 50000, 160000,
115 vco_min = max(max(vco_min, vclk), dclk); 68 43663, 0x03FFFFFE, 1, 30, ~0,
116 for (vco_freq = vco_min; vco_freq <= vco_max; vco_freq += 500) { 69 &fb_div, &vclk_div, &dclk_div);
117 uint64_t fb_div = (uint64_t)vco_freq * 43663; 70 if (r)
118 int calc_clk, diff_score, diff_vclk, diff_dclk; 71 return r;
119 unsigned vclk_div, dclk_div; 72
120 73 fb_div |= 1;
121 do_div(fb_div, ref_freq); 74 vclk_div -= 1;
122 fb_div |= 1; 75 dclk_div -= 1;
123
124 /* fb div out of range ? */
125 if (fb_div > 0x03FFFFFF)
126 break; /* it can oly get worse */
127
128 /* calc vclk with current vco freq. */
129 calc_clk = rv770_uvd_calc_post_div(vclk, vco_freq, &vclk_div);
130 if (calc_clk == -1)
131 break; /* vco is too big, it has to stop. */
132 diff_vclk = vclk - calc_clk;
133
134 /* calc dclk with current vco freq. */
135 calc_clk = rv770_uvd_calc_post_div(dclk, vco_freq, &dclk_div);
136 if (calc_clk == -1)
137 break; /* vco is too big, it has to stop. */
138 diff_dclk = dclk - calc_clk;
139
140 /* determine if this vco setting is better than current optimal settings */
141 diff_score = abs(diff_vclk) + abs(diff_dclk);
142 if (diff_score < optimal_diff_score) {
143 optimal_fb_div = fb_div;
144 optimal_vclk_div = vclk_div;
145 optimal_dclk_div = dclk_div;
146 optimal_vco_freq = vco_freq;
147 optimal_diff_score = diff_score;
148 if (optimal_diff_score == 0)
149 break; /* it can't get better than this */
150 }
151 }
152 76
153 /* set UPLL_FB_DIV to 0x50000 */ 77 /* set UPLL_FB_DIV to 0x50000 */
154 WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(0x50000), ~UPLL_FB_DIV_MASK); 78 WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(0x50000), ~UPLL_FB_DIV_MASK);
@@ -160,7 +84,7 @@ int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
160 WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK); 84 WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK);
161 WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(1), ~UPLL_FB_DIV(1)); 85 WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(1), ~UPLL_FB_DIV(1));
162 86
163 r = rv770_uvd_send_upll_ctlreq(rdev); 87 r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL);
164 if (r) 88 if (r)
165 return r; 89 return r;
166 90
@@ -170,13 +94,13 @@ int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
170 /* set the required FB_DIV, REF_DIV, Post divder values */ 94 /* set the required FB_DIV, REF_DIV, Post divder values */
171 WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_REF_DIV(1), ~UPLL_REF_DIV_MASK); 95 WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_REF_DIV(1), ~UPLL_REF_DIV_MASK);
172 WREG32_P(CG_UPLL_FUNC_CNTL_2, 96 WREG32_P(CG_UPLL_FUNC_CNTL_2,
173 UPLL_SW_HILEN(optimal_vclk_div >> 1) | 97 UPLL_SW_HILEN(vclk_div >> 1) |
174 UPLL_SW_LOLEN((optimal_vclk_div >> 1) + (optimal_vclk_div & 1)) | 98 UPLL_SW_LOLEN((vclk_div >> 1) + (vclk_div & 1)) |
175 UPLL_SW_HILEN2(optimal_dclk_div >> 1) | 99 UPLL_SW_HILEN2(dclk_div >> 1) |
176 UPLL_SW_LOLEN2((optimal_dclk_div >> 1) + (optimal_dclk_div & 1)), 100 UPLL_SW_LOLEN2((dclk_div >> 1) + (dclk_div & 1)),
177 ~UPLL_SW_MASK); 101 ~UPLL_SW_MASK);
178 102
179 WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(optimal_fb_div), 103 WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(fb_div),
180 ~UPLL_FB_DIV_MASK); 104 ~UPLL_FB_DIV_MASK);
181 105
182 /* give the PLL some time to settle */ 106 /* give the PLL some time to settle */
@@ -191,7 +115,7 @@ int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
191 WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK); 115 WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK);
192 WREG32_P(CG_UPLL_FUNC_CNTL_3, 0, ~UPLL_FB_DIV(1)); 116 WREG32_P(CG_UPLL_FUNC_CNTL_3, 0, ~UPLL_FB_DIV(1));
193 117
194 r = rv770_uvd_send_upll_ctlreq(rdev); 118 r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL);
195 if (r) 119 if (r)
196 return r; 120 return r;
197 121