drm/i915: export error state ref handling
[deliverable/linux.git] / drivers / gpu / drm / radeon / trinity_dpm.c
CommitLineData
d70229f7
AD
1/*
2 * Copyright 2012 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 */
23
24#include "drmP.h"
25#include "radeon.h"
26#include "trinityd.h"
27#include "r600_dpm.h"
28#include "trinity_dpm.h"
29
30#define TRINITY_MAX_DEEPSLEEP_DIVIDER_ID 5
31#define TRINITY_MINIMUM_ENGINE_CLOCK 800
32#define SCLK_MIN_DIV_INTV_SHIFT 12
33#define TRINITY_DISPCLK_BYPASS_THRESHOLD 10000
34
35#ifndef TRINITY_MGCG_SEQUENCE
36#define TRINITY_MGCG_SEQUENCE 100
37
38static const u32 trinity_mgcg_shls_default[] =
39{
40 /* Register, Value, Mask */
41 0x0000802c, 0xc0000000, 0xffffffff,
42 0x00003fc4, 0xc0000000, 0xffffffff,
43 0x00005448, 0x00000100, 0xffffffff,
44 0x000055e4, 0x00000100, 0xffffffff,
45 0x0000160c, 0x00000100, 0xffffffff,
46 0x00008984, 0x06000100, 0xffffffff,
47 0x0000c164, 0x00000100, 0xffffffff,
48 0x00008a18, 0x00000100, 0xffffffff,
49 0x0000897c, 0x06000100, 0xffffffff,
50 0x00008b28, 0x00000100, 0xffffffff,
51 0x00009144, 0x00800200, 0xffffffff,
52 0x00009a60, 0x00000100, 0xffffffff,
53 0x00009868, 0x00000100, 0xffffffff,
54 0x00008d58, 0x00000100, 0xffffffff,
55 0x00009510, 0x00000100, 0xffffffff,
56 0x0000949c, 0x00000100, 0xffffffff,
57 0x00009654, 0x00000100, 0xffffffff,
58 0x00009030, 0x00000100, 0xffffffff,
59 0x00009034, 0x00000100, 0xffffffff,
60 0x00009038, 0x00000100, 0xffffffff,
61 0x0000903c, 0x00000100, 0xffffffff,
62 0x00009040, 0x00000100, 0xffffffff,
63 0x0000a200, 0x00000100, 0xffffffff,
64 0x0000a204, 0x00000100, 0xffffffff,
65 0x0000a208, 0x00000100, 0xffffffff,
66 0x0000a20c, 0x00000100, 0xffffffff,
67 0x00009744, 0x00000100, 0xffffffff,
68 0x00003f80, 0x00000100, 0xffffffff,
69 0x0000a210, 0x00000100, 0xffffffff,
70 0x0000a214, 0x00000100, 0xffffffff,
71 0x000004d8, 0x00000100, 0xffffffff,
72 0x00009664, 0x00000100, 0xffffffff,
73 0x00009698, 0x00000100, 0xffffffff,
74 0x000004d4, 0x00000200, 0xffffffff,
75 0x000004d0, 0x00000000, 0xffffffff,
76 0x000030cc, 0x00000104, 0xffffffff,
77 0x0000d0c0, 0x00000100, 0xffffffff,
78 0x0000d8c0, 0x00000100, 0xffffffff,
79 0x0000951c, 0x00010000, 0xffffffff,
80 0x00009160, 0x00030002, 0xffffffff,
81 0x00009164, 0x00050004, 0xffffffff,
82 0x00009168, 0x00070006, 0xffffffff,
83 0x00009178, 0x00070000, 0xffffffff,
84 0x0000917c, 0x00030002, 0xffffffff,
85 0x00009180, 0x00050004, 0xffffffff,
86 0x0000918c, 0x00010006, 0xffffffff,
87 0x00009190, 0x00090008, 0xffffffff,
88 0x00009194, 0x00070000, 0xffffffff,
89 0x00009198, 0x00030002, 0xffffffff,
90 0x0000919c, 0x00050004, 0xffffffff,
91 0x000091a8, 0x00010006, 0xffffffff,
92 0x000091ac, 0x00090008, 0xffffffff,
93 0x000091b0, 0x00070000, 0xffffffff,
94 0x000091b4, 0x00030002, 0xffffffff,
95 0x000091b8, 0x00050004, 0xffffffff,
96 0x000091c4, 0x00010006, 0xffffffff,
97 0x000091c8, 0x00090008, 0xffffffff,
98 0x000091cc, 0x00070000, 0xffffffff,
99 0x000091d0, 0x00030002, 0xffffffff,
100 0x000091d4, 0x00050004, 0xffffffff,
101 0x000091e0, 0x00010006, 0xffffffff,
102 0x000091e4, 0x00090008, 0xffffffff,
103 0x000091e8, 0x00000000, 0xffffffff,
104 0x000091ec, 0x00070000, 0xffffffff,
105 0x000091f0, 0x00030002, 0xffffffff,
106 0x000091f4, 0x00050004, 0xffffffff,
107 0x00009200, 0x00010006, 0xffffffff,
108 0x00009204, 0x00090008, 0xffffffff,
109 0x00009208, 0x00070000, 0xffffffff,
110 0x0000920c, 0x00030002, 0xffffffff,
111 0x00009210, 0x00050004, 0xffffffff,
112 0x0000921c, 0x00010006, 0xffffffff,
113 0x00009220, 0x00090008, 0xffffffff,
114 0x00009294, 0x00000000, 0xffffffff
115};
116
117static const u32 trinity_mgcg_shls_enable[] =
118{
119 /* Register, Value, Mask */
120 0x0000802c, 0xc0000000, 0xffffffff,
121 0x000008f8, 0x00000000, 0xffffffff,
122 0x000008fc, 0x00000000, 0x000133FF,
123 0x000008f8, 0x00000001, 0xffffffff,
124 0x000008fc, 0x00000000, 0xE00B03FC,
125 0x00009150, 0x96944200, 0xffffffff
126};
127
128static const u32 trinity_mgcg_shls_disable[] =
129{
130 /* Register, Value, Mask */
131 0x0000802c, 0xc0000000, 0xffffffff,
132 0x00009150, 0x00600000, 0xffffffff,
133 0x000008f8, 0x00000000, 0xffffffff,
134 0x000008fc, 0xffffffff, 0x000133FF,
135 0x000008f8, 0x00000001, 0xffffffff,
136 0x000008fc, 0xffffffff, 0xE00B03FC
137};
138#endif
139
140#ifndef TRINITY_SYSLS_SEQUENCE
141#define TRINITY_SYSLS_SEQUENCE 100
142
143static const u32 trinity_sysls_default[] =
144{
145 /* Register, Value, Mask */
146 0x000055e8, 0x00000000, 0xffffffff,
147 0x0000d0bc, 0x00000000, 0xffffffff,
148 0x0000d8bc, 0x00000000, 0xffffffff,
149 0x000015c0, 0x000c1401, 0xffffffff,
150 0x0000264c, 0x000c0400, 0xffffffff,
151 0x00002648, 0x000c0400, 0xffffffff,
152 0x00002650, 0x000c0400, 0xffffffff,
153 0x000020b8, 0x000c0400, 0xffffffff,
154 0x000020bc, 0x000c0400, 0xffffffff,
155 0x000020c0, 0x000c0c80, 0xffffffff,
156 0x0000f4a0, 0x000000c0, 0xffffffff,
157 0x0000f4a4, 0x00680fff, 0xffffffff,
158 0x00002f50, 0x00000404, 0xffffffff,
159 0x000004c8, 0x00000001, 0xffffffff,
160 0x0000641c, 0x00000000, 0xffffffff,
161 0x00000c7c, 0x00000000, 0xffffffff,
162 0x00006dfc, 0x00000000, 0xffffffff
163};
164
165static const u32 trinity_sysls_disable[] =
166{
167 /* Register, Value, Mask */
168 0x0000d0c0, 0x00000000, 0xffffffff,
169 0x0000d8c0, 0x00000000, 0xffffffff,
170 0x000055e8, 0x00000000, 0xffffffff,
171 0x0000d0bc, 0x00000000, 0xffffffff,
172 0x0000d8bc, 0x00000000, 0xffffffff,
173 0x000015c0, 0x00041401, 0xffffffff,
174 0x0000264c, 0x00040400, 0xffffffff,
175 0x00002648, 0x00040400, 0xffffffff,
176 0x00002650, 0x00040400, 0xffffffff,
177 0x000020b8, 0x00040400, 0xffffffff,
178 0x000020bc, 0x00040400, 0xffffffff,
179 0x000020c0, 0x00040c80, 0xffffffff,
180 0x0000f4a0, 0x000000c0, 0xffffffff,
181 0x0000f4a4, 0x00680000, 0xffffffff,
182 0x00002f50, 0x00000404, 0xffffffff,
183 0x000004c8, 0x00000001, 0xffffffff,
184 0x0000641c, 0x00007ffd, 0xffffffff,
185 0x00000c7c, 0x0000ff00, 0xffffffff,
186 0x00006dfc, 0x0000007f, 0xffffffff
187};
188
189static const u32 trinity_sysls_enable[] =
190{
191 /* Register, Value, Mask */
192 0x000055e8, 0x00000001, 0xffffffff,
193 0x0000d0bc, 0x00000100, 0xffffffff,
194 0x0000d8bc, 0x00000100, 0xffffffff,
195 0x000015c0, 0x000c1401, 0xffffffff,
196 0x0000264c, 0x000c0400, 0xffffffff,
197 0x00002648, 0x000c0400, 0xffffffff,
198 0x00002650, 0x000c0400, 0xffffffff,
199 0x000020b8, 0x000c0400, 0xffffffff,
200 0x000020bc, 0x000c0400, 0xffffffff,
201 0x000020c0, 0x000c0c80, 0xffffffff,
202 0x0000f4a0, 0x000000c0, 0xffffffff,
203 0x0000f4a4, 0x00680fff, 0xffffffff,
204 0x00002f50, 0x00000903, 0xffffffff,
205 0x000004c8, 0x00000000, 0xffffffff,
206 0x0000641c, 0x00000000, 0xffffffff,
207 0x00000c7c, 0x00000000, 0xffffffff,
208 0x00006dfc, 0x00000000, 0xffffffff
209};
210#endif
211
212static const u32 trinity_override_mgpg_sequences[] =
213{
214 /* Register, Value */
215 0x00000200, 0xE030032C,
216 0x00000204, 0x00000FFF,
217 0x00000200, 0xE0300058,
218 0x00000204, 0x00030301,
219 0x00000200, 0xE0300054,
220 0x00000204, 0x500010FF,
221 0x00000200, 0xE0300074,
222 0x00000204, 0x00030301,
223 0x00000200, 0xE0300070,
224 0x00000204, 0x500010FF,
225 0x00000200, 0xE0300090,
226 0x00000204, 0x00030301,
227 0x00000200, 0xE030008C,
228 0x00000204, 0x500010FF,
229 0x00000200, 0xE03000AC,
230 0x00000204, 0x00030301,
231 0x00000200, 0xE03000A8,
232 0x00000204, 0x500010FF,
233 0x00000200, 0xE03000C8,
234 0x00000204, 0x00030301,
235 0x00000200, 0xE03000C4,
236 0x00000204, 0x500010FF,
237 0x00000200, 0xE03000E4,
238 0x00000204, 0x00030301,
239 0x00000200, 0xE03000E0,
240 0x00000204, 0x500010FF,
241 0x00000200, 0xE0300100,
242 0x00000204, 0x00030301,
243 0x00000200, 0xE03000FC,
244 0x00000204, 0x500010FF,
245 0x00000200, 0xE0300058,
246 0x00000204, 0x00030303,
247 0x00000200, 0xE0300054,
248 0x00000204, 0x600010FF,
249 0x00000200, 0xE0300074,
250 0x00000204, 0x00030303,
251 0x00000200, 0xE0300070,
252 0x00000204, 0x600010FF,
253 0x00000200, 0xE0300090,
254 0x00000204, 0x00030303,
255 0x00000200, 0xE030008C,
256 0x00000204, 0x600010FF,
257 0x00000200, 0xE03000AC,
258 0x00000204, 0x00030303,
259 0x00000200, 0xE03000A8,
260 0x00000204, 0x600010FF,
261 0x00000200, 0xE03000C8,
262 0x00000204, 0x00030303,
263 0x00000200, 0xE03000C4,
264 0x00000204, 0x600010FF,
265 0x00000200, 0xE03000E4,
266 0x00000204, 0x00030303,
267 0x00000200, 0xE03000E0,
268 0x00000204, 0x600010FF,
269 0x00000200, 0xE0300100,
270 0x00000204, 0x00030303,
271 0x00000200, 0xE03000FC,
272 0x00000204, 0x600010FF,
273 0x00000200, 0xE0300058,
274 0x00000204, 0x00030303,
275 0x00000200, 0xE0300054,
276 0x00000204, 0x700010FF,
277 0x00000200, 0xE0300074,
278 0x00000204, 0x00030303,
279 0x00000200, 0xE0300070,
280 0x00000204, 0x700010FF,
281 0x00000200, 0xE0300090,
282 0x00000204, 0x00030303,
283 0x00000200, 0xE030008C,
284 0x00000204, 0x700010FF,
285 0x00000200, 0xE03000AC,
286 0x00000204, 0x00030303,
287 0x00000200, 0xE03000A8,
288 0x00000204, 0x700010FF,
289 0x00000200, 0xE03000C8,
290 0x00000204, 0x00030303,
291 0x00000200, 0xE03000C4,
292 0x00000204, 0x700010FF,
293 0x00000200, 0xE03000E4,
294 0x00000204, 0x00030303,
295 0x00000200, 0xE03000E0,
296 0x00000204, 0x700010FF,
297 0x00000200, 0xE0300100,
298 0x00000204, 0x00030303,
299 0x00000200, 0xE03000FC,
300 0x00000204, 0x700010FF,
301 0x00000200, 0xE0300058,
302 0x00000204, 0x00010303,
303 0x00000200, 0xE0300054,
304 0x00000204, 0x800010FF,
305 0x00000200, 0xE0300074,
306 0x00000204, 0x00010303,
307 0x00000200, 0xE0300070,
308 0x00000204, 0x800010FF,
309 0x00000200, 0xE0300090,
310 0x00000204, 0x00010303,
311 0x00000200, 0xE030008C,
312 0x00000204, 0x800010FF,
313 0x00000200, 0xE03000AC,
314 0x00000204, 0x00010303,
315 0x00000200, 0xE03000A8,
316 0x00000204, 0x800010FF,
317 0x00000200, 0xE03000C4,
318 0x00000204, 0x800010FF,
319 0x00000200, 0xE03000C8,
320 0x00000204, 0x00010303,
321 0x00000200, 0xE03000E4,
322 0x00000204, 0x00010303,
323 0x00000200, 0xE03000E0,
324 0x00000204, 0x800010FF,
325 0x00000200, 0xE0300100,
326 0x00000204, 0x00010303,
327 0x00000200, 0xE03000FC,
328 0x00000204, 0x800010FF,
329 0x00000200, 0x0001f198,
330 0x00000204, 0x0003ffff,
331 0x00000200, 0x0001f19C,
332 0x00000204, 0x3fffffff,
333 0x00000200, 0xE030032C,
334 0x00000204, 0x00000000,
335};
336
337static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
338 const u32 *seq, u32 count);
339static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev);
940eea8e
AD
340static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
341 struct radeon_ps *new_rps,
342 struct radeon_ps *old_rps);
d70229f7
AD
343
344struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
345{
346 struct trinity_ps *ps = rps->ps_priv;
347
348 return ps;
349}
350
351struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)
352{
353 struct trinity_power_info *pi = rdev->pm.dpm.priv;
354
355 return pi;
356}
357
358static void trinity_gfx_powergating_initialize(struct radeon_device *rdev)
359{
360 struct trinity_power_info *pi = trinity_get_pi(rdev);
361 u32 p, u;
362 u32 value;
363 struct atom_clock_dividers dividers;
9d45ad5a 364 u32 xclk = radeon_get_xclk(rdev);
d70229f7
AD
365 u32 sssd = 1;
366 int ret;
367 u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
368
369 ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
370 25000, false, &dividers);
371 if (ret)
372 return;
373
374 value = RREG32_SMC(GFX_POWER_GATING_CNTL);
375 value &= ~(SSSD_MASK | PDS_DIV_MASK);
376 if (sssd)
377 value |= SSSD(1);
378 value |= PDS_DIV(dividers.post_div);
379 WREG32_SMC(GFX_POWER_GATING_CNTL, value);
380
381 r600_calculate_u_and_p(500, xclk, 16, &p, &u);
382
383 WREG32(CG_PG_CTRL, SP(p) | SU(u));
384
385 WREG32_P(CG_GIPOTS, CG_GIPOT(p), ~CG_GIPOT_MASK);
386
387 /* XXX double check hw_rev */
388 if (pi->override_dynamic_mgpg && (hw_rev == 0))
389 trinity_override_dynamic_mg_powergating(rdev);
390
391}
392
393#define CGCG_CGTT_LOCAL0_MASK 0xFFFF33FF
394#define CGCG_CGTT_LOCAL1_MASK 0xFFFB0FFE
395#define CGTS_SM_CTRL_REG_DISABLE 0x00600000
396#define CGTS_SM_CTRL_REG_ENABLE 0x96944200
397
398static void trinity_mg_clockgating_enable(struct radeon_device *rdev,
399 bool enable)
400{
401 u32 local0;
402 u32 local1;
403
404 if (enable) {
405 local0 = RREG32_CG(CG_CGTT_LOCAL_0);
406 local1 = RREG32_CG(CG_CGTT_LOCAL_1);
407
408 WREG32_CG(CG_CGTT_LOCAL_0,
409 (0x00380000 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
410 WREG32_CG(CG_CGTT_LOCAL_1,
411 (0x0E000000 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
412
413 WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_ENABLE);
414 } else {
415 WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_DISABLE);
416
417 local0 = RREG32_CG(CG_CGTT_LOCAL_0);
418 local1 = RREG32_CG(CG_CGTT_LOCAL_1);
419
420 WREG32_CG(CG_CGTT_LOCAL_0,
421 CGCG_CGTT_LOCAL0_MASK | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
422 WREG32_CG(CG_CGTT_LOCAL_1,
423 CGCG_CGTT_LOCAL1_MASK | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
424 }
425}
426
427static void trinity_mg_clockgating_initialize(struct radeon_device *rdev)
428{
429 u32 count;
430 const u32 *seq = NULL;
431
432 seq = &trinity_mgcg_shls_default[0];
433 count = sizeof(trinity_mgcg_shls_default) / (3 * sizeof(u32));
434
435 trinity_program_clk_gating_hw_sequence(rdev, seq, count);
436}
437
438static void trinity_gfx_clockgating_enable(struct radeon_device *rdev,
439 bool enable)
440{
441 if (enable) {
442 WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
443 } else {
444 WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
445 WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
446 WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
447 RREG32(GB_ADDR_CONFIG);
448 }
449}
450
451static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
452 const u32 *seq, u32 count)
453{
454 u32 i, length = count * 3;
455
456 for (i = 0; i < length; i += 3)
457 WREG32_P(seq[i], seq[i+1], ~seq[i+2]);
458}
459
460static void trinity_program_override_mgpg_sequences(struct radeon_device *rdev,
461 const u32 *seq, u32 count)
462{
463 u32 i, length = count * 2;
464
465 for (i = 0; i < length; i += 2)
466 WREG32(seq[i], seq[i+1]);
467
468}
469
470static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev)
471{
472 u32 count;
473 const u32 *seq = NULL;
474
475 seq = &trinity_override_mgpg_sequences[0];
476 count = sizeof(trinity_override_mgpg_sequences) / (2 * sizeof(u32));
477
478 trinity_program_override_mgpg_sequences(rdev, seq, count);
479}
480
481static void trinity_ls_clockgating_enable(struct radeon_device *rdev,
482 bool enable)
483{
484 u32 count;
485 const u32 *seq = NULL;
486
487 if (enable) {
488 seq = &trinity_sysls_enable[0];
489 count = sizeof(trinity_sysls_enable) / (3 * sizeof(u32));
490 } else {
491 seq = &trinity_sysls_disable[0];
492 count = sizeof(trinity_sysls_disable) / (3 * sizeof(u32));
493 }
494
495 trinity_program_clk_gating_hw_sequence(rdev, seq, count);
496}
497
498static void trinity_gfx_powergating_enable(struct radeon_device *rdev,
499 bool enable)
500{
501 if (enable) {
502 if (RREG32_SMC(CC_SMU_TST_EFUSE1_MISC) & RB_BACKEND_DISABLE_MASK)
503 WREG32_SMC(SMU_SCRATCH_A, (RREG32_SMC(SMU_SCRATCH_A) | 0x01));
504
505 WREG32_P(SCLK_PWRMGT_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
506 } else {
507 WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_PWR_DOWN_EN);
508 RREG32(GB_ADDR_CONFIG);
509 }
510}
511
512static void trinity_gfx_dynamic_mgpg_enable(struct radeon_device *rdev,
513 bool enable)
514{
515 u32 value;
516
517 if (enable) {
518 value = RREG32_SMC(PM_I_CNTL_1);
519 value &= ~DS_PG_CNTL_MASK;
520 value |= DS_PG_CNTL(1);
521 WREG32_SMC(PM_I_CNTL_1, value);
522
523 value = RREG32_SMC(SMU_S_PG_CNTL);
524 value &= ~DS_PG_EN_MASK;
525 value |= DS_PG_EN(1);
526 WREG32_SMC(SMU_S_PG_CNTL, value);
527 } else {
528 value = RREG32_SMC(SMU_S_PG_CNTL);
529 value &= ~DS_PG_EN_MASK;
530 WREG32_SMC(SMU_S_PG_CNTL, value);
531
532 value = RREG32_SMC(PM_I_CNTL_1);
533 value &= ~DS_PG_CNTL_MASK;
534 WREG32_SMC(PM_I_CNTL_1, value);
535 }
536
537 trinity_gfx_dynamic_mgpg_config(rdev);
538
539}
540
541static void trinity_enable_clock_power_gating(struct radeon_device *rdev)
542{
543 struct trinity_power_info *pi = trinity_get_pi(rdev);
544
545 if (pi->enable_gfx_clock_gating)
546 sumo_gfx_clockgating_initialize(rdev);
547 if (pi->enable_mg_clock_gating)
548 trinity_mg_clockgating_initialize(rdev);
549 if (pi->enable_gfx_power_gating)
550 trinity_gfx_powergating_initialize(rdev);
551 if (pi->enable_mg_clock_gating) {
552 trinity_ls_clockgating_enable(rdev, true);
553 trinity_mg_clockgating_enable(rdev, true);
554 }
555 if (pi->enable_gfx_clock_gating)
556 trinity_gfx_clockgating_enable(rdev, true);
557 if (pi->enable_gfx_dynamic_mgpg)
558 trinity_gfx_dynamic_mgpg_enable(rdev, true);
559 if (pi->enable_gfx_power_gating)
560 trinity_gfx_powergating_enable(rdev, true);
561}
562
563static void trinity_disable_clock_power_gating(struct radeon_device *rdev)
564{
565 struct trinity_power_info *pi = trinity_get_pi(rdev);
566
567 if (pi->enable_gfx_power_gating)
568 trinity_gfx_powergating_enable(rdev, false);
569 if (pi->enable_gfx_dynamic_mgpg)
570 trinity_gfx_dynamic_mgpg_enable(rdev, false);
571 if (pi->enable_gfx_clock_gating)
572 trinity_gfx_clockgating_enable(rdev, false);
573 if (pi->enable_mg_clock_gating) {
574 trinity_mg_clockgating_enable(rdev, false);
575 trinity_ls_clockgating_enable(rdev, false);
576 }
577}
578
579static void trinity_set_divider_value(struct radeon_device *rdev,
580 u32 index, u32 sclk)
581{
582 struct atom_clock_dividers dividers;
583 int ret;
584 u32 value;
585 u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
586
587 ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
588 sclk, false, &dividers);
589 if (ret)
590 return;
591
592 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
593 value &= ~CLK_DIVIDER_MASK;
594 value |= CLK_DIVIDER(dividers.post_div);
595 WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
596
597 ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
598 sclk/2, false, &dividers);
599 if (ret)
600 return;
601
602 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix);
603 value &= ~PD_SCLK_DIVIDER_MASK;
604 value |= PD_SCLK_DIVIDER(dividers.post_div);
605 WREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix, value);
606}
607
608static void trinity_set_ds_dividers(struct radeon_device *rdev,
609 u32 index, u32 divider)
610{
611 u32 value;
612 u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
613
614 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
615 value &= ~DS_DIV_MASK;
616 value |= DS_DIV(divider);
617 WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
618}
619
620static void trinity_set_ss_dividers(struct radeon_device *rdev,
621 u32 index, u32 divider)
622{
623 u32 value;
624 u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
625
626 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
627 value &= ~DS_SH_DIV_MASK;
628 value |= DS_SH_DIV(divider);
629 WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
630}
631
632static void trinity_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
633{
634 struct trinity_power_info *pi = trinity_get_pi(rdev);
635 u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid);
636 u32 value;
637 u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
638
639 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
640 value &= ~VID_MASK;
641 value |= VID(vid_7bit);
642 WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
643
644 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
645 value &= ~LVRT_MASK;
646 value |= LVRT(0);
647 WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
648}
649
650static void trinity_set_allos_gnb_slow(struct radeon_device *rdev,
651 u32 index, u32 gnb_slow)
652{
653 u32 value;
654 u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
655
656 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
657 value &= ~GNB_SLOW_MASK;
658 value |= GNB_SLOW(gnb_slow);
659 WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
660}
661
662static void trinity_set_force_nbp_state(struct radeon_device *rdev,
663 u32 index, u32 force_nbp_state)
664{
665 u32 value;
666 u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
667
668 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
669 value &= ~FORCE_NBPS1_MASK;
670 value |= FORCE_NBPS1(force_nbp_state);
671 WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
672}
673
674static void trinity_set_display_wm(struct radeon_device *rdev,
675 u32 index, u32 wm)
676{
677 u32 value;
678 u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
679
680 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
681 value &= ~DISPLAY_WM_MASK;
682 value |= DISPLAY_WM(wm);
683 WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
684}
685
686static void trinity_set_vce_wm(struct radeon_device *rdev,
687 u32 index, u32 wm)
688{
689 u32 value;
690 u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
691
692 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
693 value &= ~VCE_WM_MASK;
694 value |= VCE_WM(wm);
695 WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
696}
697
698static void trinity_set_at(struct radeon_device *rdev,
699 u32 index, u32 at)
700{
701 u32 value;
702 u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
703
704 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix);
705 value &= ~AT_MASK;
706 value |= AT(at);
707 WREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix, value);
708}
709
710static void trinity_program_power_level(struct radeon_device *rdev,
711 struct trinity_pl *pl, u32 index)
712{
713 struct trinity_power_info *pi = trinity_get_pi(rdev);
714
715 if (index >= SUMO_MAX_HARDWARE_POWERLEVELS)
716 return;
717
718 trinity_set_divider_value(rdev, index, pl->sclk);
719 trinity_set_vid(rdev, index, pl->vddc_index);
720 trinity_set_ss_dividers(rdev, index, pl->ss_divider_index);
721 trinity_set_ds_dividers(rdev, index, pl->ds_divider_index);
722 trinity_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
723 trinity_set_force_nbp_state(rdev, index, pl->force_nbp_state);
724 trinity_set_display_wm(rdev, index, pl->display_wm);
725 trinity_set_vce_wm(rdev, index, pl->vce_wm);
726 trinity_set_at(rdev, index, pi->at[index]);
727}
728
729static void trinity_power_level_enable_disable(struct radeon_device *rdev,
730 u32 index, bool enable)
731{
732 u32 value;
733 u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
734
735 value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
736 value &= ~STATE_VALID_MASK;
737 if (enable)
738 value |= STATE_VALID(1);
739 WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
740}
741
742static bool trinity_dpm_enabled(struct radeon_device *rdev)
743{
744 if (RREG32_SMC(SMU_SCLK_DPM_CNTL) & SCLK_DPM_EN(1))
745 return true;
746 else
747 return false;
748}
749
750static void trinity_start_dpm(struct radeon_device *rdev)
751{
752 u32 value = RREG32_SMC(SMU_SCLK_DPM_CNTL);
753
754 value &= ~(SCLK_DPM_EN_MASK | SCLK_DPM_BOOT_STATE_MASK | VOLTAGE_CHG_EN_MASK);
755 value |= SCLK_DPM_EN(1) | SCLK_DPM_BOOT_STATE(0) | VOLTAGE_CHG_EN(1);
756 WREG32_SMC(SMU_SCLK_DPM_CNTL, value);
757
758 WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
759 WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~EN);
760
761 trinity_dpm_config(rdev, true);
762}
763
764static void trinity_wait_for_dpm_enabled(struct radeon_device *rdev)
765{
766 int i;
767
768 for (i = 0; i < rdev->usec_timeout; i++) {
769 if (RREG32(SCLK_PWRMGT_CNTL) & DYNAMIC_PM_EN)
770 break;
771 udelay(1);
772 }
773 for (i = 0; i < rdev->usec_timeout; i++) {
774 if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_STATE_MASK) == 0)
775 break;
776 udelay(1);
777 }
778 for (i = 0; i < rdev->usec_timeout; i++) {
779 if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
780 break;
781 udelay(1);
782 }
783}
784
785static void trinity_stop_dpm(struct radeon_device *rdev)
786{
787 u32 sclk_dpm_cntl;
788
789 WREG32_P(CG_CG_VOLTAGE_CNTL, EN, ~EN);
790
791 sclk_dpm_cntl = RREG32_SMC(SMU_SCLK_DPM_CNTL);
792 sclk_dpm_cntl &= ~(SCLK_DPM_EN_MASK | VOLTAGE_CHG_EN_MASK);
793 WREG32_SMC(SMU_SCLK_DPM_CNTL, sclk_dpm_cntl);
794
795 trinity_dpm_config(rdev, false);
796}
797
798static void trinity_start_am(struct radeon_device *rdev)
799{
800 WREG32_P(SCLK_PWRMGT_CNTL, 0, ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
801}
802
803static void trinity_reset_am(struct radeon_device *rdev)
804{
805 WREG32_P(SCLK_PWRMGT_CNTL, RESET_SCLK_CNT | RESET_BUSY_CNT,
806 ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
807}
808
809static void trinity_wait_for_level_0(struct radeon_device *rdev)
810{
811 int i;
812
813 for (i = 0; i < rdev->usec_timeout; i++) {
814 if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
815 break;
816 udelay(1);
817 }
818}
819
820static void trinity_enable_power_level_0(struct radeon_device *rdev)
821{
822 trinity_power_level_enable_disable(rdev, 0, true);
823}
824
825static void trinity_force_level_0(struct radeon_device *rdev)
826{
827 trinity_dpm_force_state(rdev, 0);
828}
829
830static void trinity_unforce_levels(struct radeon_device *rdev)
831{
832 trinity_dpm_no_forced_level(rdev);
833}
834
940eea8e
AD
835static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev,
836 struct radeon_ps *new_rps,
837 struct radeon_ps *old_rps)
d70229f7 838{
940eea8e
AD
839 struct trinity_ps *new_ps = trinity_get_ps(new_rps);
840 struct trinity_ps *old_ps = trinity_get_ps(old_rps);
d70229f7
AD
841 u32 i;
842 u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
843
844 for (i = 0; i < new_ps->num_levels; i++) {
845 trinity_program_power_level(rdev, &new_ps->levels[i], i);
846 trinity_power_level_enable_disable(rdev, i, true);
847 }
848
849 for (i = new_ps->num_levels; i < n_current_state_levels; i++)
850 trinity_power_level_enable_disable(rdev, i, false);
851}
852
853static void trinity_program_bootup_state(struct radeon_device *rdev)
854{
855 struct trinity_power_info *pi = trinity_get_pi(rdev);
856 u32 i;
857
858 trinity_program_power_level(rdev, &pi->boot_pl, 0);
859 trinity_power_level_enable_disable(rdev, 0, true);
860
861 for (i = 1; i < 8; i++)
862 trinity_power_level_enable_disable(rdev, i, false);
863}
864
0c4aaeae
AD
865static void trinity_setup_uvd_clock_table(struct radeon_device *rdev,
866 struct radeon_ps *rps)
867{
868 struct trinity_ps *ps = trinity_get_ps(rps);
869 u32 uvdstates = (ps->vclk_low_divider |
870 ps->vclk_high_divider << 8 |
871 ps->dclk_low_divider << 16 |
872 ps->dclk_high_divider << 24);
873
874 WREG32_SMC(SMU_UVD_DPM_STATES, uvdstates);
875}
876
877static void trinity_setup_uvd_dpm_interval(struct radeon_device *rdev,
878 u32 interval)
879{
880 u32 p, u;
881 u32 tp = RREG32_SMC(PM_TP);
882 u32 val;
9d45ad5a 883 u32 xclk = radeon_get_xclk(rdev);
0c4aaeae
AD
884
885 r600_calculate_u_and_p(interval, xclk, 16, &p, &u);
886
887 val = (p + tp - 1) / tp;
888
889 WREG32_SMC(SMU_UVD_DPM_CNTL, val);
890}
891
892static bool trinity_uvd_clocks_zero(struct radeon_ps *rps)
893{
894 if ((rps->vclk == 0) && (rps->dclk == 0))
895 return true;
896 else
897 return false;
898}
899
900static bool trinity_uvd_clocks_equal(struct radeon_ps *rps1,
901 struct radeon_ps *rps2)
902{
903 struct trinity_ps *ps1 = trinity_get_ps(rps1);
904 struct trinity_ps *ps2 = trinity_get_ps(rps2);
905
906 if ((rps1->vclk == rps2->vclk) &&
907 (rps1->dclk == rps2->dclk) &&
908 (ps1->vclk_low_divider == ps2->vclk_low_divider) &&
909 (ps1->vclk_high_divider == ps2->vclk_high_divider) &&
910 (ps1->dclk_low_divider == ps2->dclk_low_divider) &&
911 (ps1->dclk_high_divider == ps2->dclk_high_divider))
912 return true;
913 else
914 return false;
915}
916
917static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
940eea8e
AD
918 struct radeon_ps *new_rps,
919 struct radeon_ps *old_rps)
0c4aaeae
AD
920{
921 struct trinity_power_info *pi = trinity_get_pi(rdev);
922
923 if (pi->uvd_dpm) {
924 if (trinity_uvd_clocks_zero(new_rps) &&
940eea8e 925 !trinity_uvd_clocks_zero(old_rps)) {
0c4aaeae
AD
926 trinity_setup_uvd_dpm_interval(rdev, 0);
927 } else if (!trinity_uvd_clocks_zero(new_rps)) {
928 trinity_setup_uvd_clock_table(rdev, new_rps);
929
940eea8e 930 if (trinity_uvd_clocks_zero(old_rps)) {
0c4aaeae
AD
931 u32 tmp = RREG32(CG_MISC_REG);
932 tmp &= 0xfffffffd;
933 WREG32(CG_MISC_REG, tmp);
934
935 radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
936
937 trinity_setup_uvd_dpm_interval(rdev, 3000);
938 }
939 }
940 trinity_uvd_dpm_config(rdev);
941 } else {
942 if (trinity_uvd_clocks_zero(new_rps) ||
940eea8e 943 trinity_uvd_clocks_equal(new_rps, old_rps))
0c4aaeae
AD
944 return;
945
946 radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
947 }
948}
949
940eea8e
AD
950static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
951 struct radeon_ps *new_rps,
952 struct radeon_ps *old_rps)
0c4aaeae 953{
940eea8e
AD
954 struct trinity_ps *new_ps = trinity_get_ps(new_rps);
955 struct trinity_ps *current_ps = trinity_get_ps(new_rps);
0c4aaeae
AD
956
957 if (new_ps->levels[new_ps->num_levels - 1].sclk >=
958 current_ps->levels[current_ps->num_levels - 1].sclk)
959 return;
960
940eea8e 961 trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
0c4aaeae
AD
962}
963
940eea8e
AD
964static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
965 struct radeon_ps *new_rps,
966 struct radeon_ps *old_rps)
0c4aaeae 967{
940eea8e
AD
968 struct trinity_ps *new_ps = trinity_get_ps(new_rps);
969 struct trinity_ps *current_ps = trinity_get_ps(old_rps);
0c4aaeae
AD
970
971 if (new_ps->levels[new_ps->num_levels - 1].sclk <
972 current_ps->levels[current_ps->num_levels - 1].sclk)
973 return;
974
940eea8e 975 trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
0c4aaeae
AD
976}
977
d70229f7
AD
978static void trinity_program_ttt(struct radeon_device *rdev)
979{
980 struct trinity_power_info *pi = trinity_get_pi(rdev);
981 u32 value = RREG32_SMC(SMU_SCLK_DPM_TTT);
982
983 value &= ~(HT_MASK | LT_MASK);
984 value |= HT((pi->thermal_auto_throttling + 49) * 8);
985 value |= LT((pi->thermal_auto_throttling + 49 - pi->sys_info.htc_hyst_lmt) * 8);
986 WREG32_SMC(SMU_SCLK_DPM_TTT, value);
987}
988
989static void trinity_enable_att(struct radeon_device *rdev)
990{
991 u32 value = RREG32_SMC(SMU_SCLK_DPM_TT_CNTL);
992
993 value &= ~SCLK_TT_EN_MASK;
994 value |= SCLK_TT_EN(1);
995 WREG32_SMC(SMU_SCLK_DPM_TT_CNTL, value);
996}
997
998static void trinity_program_sclk_dpm(struct radeon_device *rdev)
999{
1000 u32 p, u;
1001 u32 tp = RREG32_SMC(PM_TP);
1002 u32 ni;
9d45ad5a 1003 u32 xclk = radeon_get_xclk(rdev);
d70229f7
AD
1004 u32 value;
1005
1006 r600_calculate_u_and_p(400, xclk, 16, &p, &u);
1007
1008 ni = (p + tp - 1) / tp;
1009
1010 value = RREG32_SMC(PM_I_CNTL_1);
1011 value &= ~SCLK_DPM_MASK;
1012 value |= SCLK_DPM(ni);
1013 WREG32_SMC(PM_I_CNTL_1, value);
1014}
1015
1016static int trinity_set_thermal_temperature_range(struct radeon_device *rdev,
1017 int min_temp, int max_temp)
1018{
1019 int low_temp = 0 * 1000;
1020 int high_temp = 255 * 1000;
1021
1022 if (low_temp < min_temp)
1023 low_temp = min_temp;
1024 if (high_temp > max_temp)
1025 high_temp = max_temp;
1026 if (high_temp < low_temp) {
1027 DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
1028 return -EINVAL;
1029 }
1030
1031 WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
1032 WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
1033
1034 rdev->pm.dpm.thermal.min_temp = low_temp;
1035 rdev->pm.dpm.thermal.max_temp = high_temp;
1036
1037 return 0;
1038}
1039
a284c48a
AD
1040static void trinity_update_current_ps(struct radeon_device *rdev,
1041 struct radeon_ps *rps)
1042{
1043 struct trinity_ps *new_ps = trinity_get_ps(rps);
1044 struct trinity_power_info *pi = trinity_get_pi(rdev);
1045
1046 pi->current_rps = *rps;
1047 pi->current_ps = *new_ps;
1048 pi->current_rps.ps_priv = &pi->current_ps;
1049}
1050
1051static void trinity_update_requested_ps(struct radeon_device *rdev,
1052 struct radeon_ps *rps)
1053{
1054 struct trinity_ps *new_ps = trinity_get_ps(rps);
1055 struct trinity_power_info *pi = trinity_get_pi(rdev);
1056
1057 pi->requested_rps = *rps;
1058 pi->requested_ps = *new_ps;
1059 pi->requested_rps.ps_priv = &pi->requested_ps;
1060}
1061
d70229f7
AD
1062int trinity_dpm_enable(struct radeon_device *rdev)
1063{
1064 struct trinity_power_info *pi = trinity_get_pi(rdev);
c3efac0d 1065 int ret;
d70229f7
AD
1066
1067 trinity_acquire_mutex(rdev);
1068
1069 if (trinity_dpm_enabled(rdev)) {
1070 trinity_release_mutex(rdev);
1071 return -EINVAL;
1072 }
1073
1074 trinity_enable_clock_power_gating(rdev);
1075 trinity_program_bootup_state(rdev);
1076 sumo_program_vc(rdev, 0x00C00033);
1077 trinity_start_am(rdev);
1078 if (pi->enable_auto_thermal_throttling) {
1079 trinity_program_ttt(rdev);
1080 trinity_enable_att(rdev);
1081 }
1082 trinity_program_sclk_dpm(rdev);
1083 trinity_start_dpm(rdev);
1084 trinity_wait_for_dpm_enabled(rdev);
1085 trinity_release_mutex(rdev);
1086
1087 if (rdev->irq.installed &&
1088 r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
c3efac0d
AD
1089 ret = trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
1090 if (ret) {
1091 trinity_release_mutex(rdev);
1092 return ret;
1093 }
d70229f7
AD
1094 rdev->irq.dpm_thermal = true;
1095 radeon_irq_set(rdev);
1096 }
1097
a284c48a
AD
1098 trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
1099
d70229f7
AD
1100 return 0;
1101}
1102
1103void trinity_dpm_disable(struct radeon_device *rdev)
1104{
1105 trinity_acquire_mutex(rdev);
1106 if (!trinity_dpm_enabled(rdev)) {
1107 trinity_release_mutex(rdev);
1108 return;
1109 }
1110 trinity_disable_clock_power_gating(rdev);
1111 sumo_clear_vc(rdev);
1112 trinity_wait_for_level_0(rdev);
1113 trinity_stop_dpm(rdev);
1114 trinity_reset_am(rdev);
1115 trinity_release_mutex(rdev);
1116
1117 if (rdev->irq.installed &&
1118 r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
1119 rdev->irq.dpm_thermal = false;
1120 radeon_irq_set(rdev);
1121 }
a284c48a
AD
1122
1123 trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
d70229f7
AD
1124}
1125
1126static void trinity_get_min_sclk_divider(struct radeon_device *rdev)
1127{
1128 struct trinity_power_info *pi = trinity_get_pi(rdev);
1129
1130 pi->min_sclk_did =
1131 (RREG32_SMC(CC_SMU_MISC_FUSES) & MinSClkDid_MASK) >> MinSClkDid_SHIFT;
1132}
1133
940eea8e
AD
1134static void trinity_setup_nbp_sim(struct radeon_device *rdev,
1135 struct radeon_ps *rps)
d70229f7
AD
1136{
1137 struct trinity_power_info *pi = trinity_get_pi(rdev);
940eea8e 1138 struct trinity_ps *new_ps = trinity_get_ps(rps);
d70229f7
AD
1139 u32 nbpsconfig;
1140
1141 if (pi->sys_info.nb_dpm_enable) {
1142 nbpsconfig = RREG32_SMC(NB_PSTATE_CONFIG);
1143 nbpsconfig &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | DpmXNbPsLo_MASK | DpmXNbPsHi_MASK);
1144 nbpsconfig |= (Dpm0PgNbPsLo(new_ps->Dpm0PgNbPsLo) |
1145 Dpm0PgNbPsHi(new_ps->Dpm0PgNbPsHi) |
1146 DpmXNbPsLo(new_ps->DpmXNbPsLo) |
1147 DpmXNbPsHi(new_ps->DpmXNbPsHi));
1148 WREG32_SMC(NB_PSTATE_CONFIG, nbpsconfig);
1149 }
1150}
1151
a284c48a 1152int trinity_dpm_pre_set_power_state(struct radeon_device *rdev)
d70229f7
AD
1153{
1154 struct trinity_power_info *pi = trinity_get_pi(rdev);
a284c48a
AD
1155 struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
1156 struct radeon_ps *new_ps = &requested_ps;
1157
1158 trinity_update_requested_ps(rdev, new_ps);
d70229f7 1159
a284c48a
AD
1160 trinity_apply_state_adjust_rules(rdev,
1161 &pi->requested_rps,
1162 &pi->current_rps);
1163
1164 return 0;
1165}
1166
1167int trinity_dpm_set_power_state(struct radeon_device *rdev)
1168{
1169 struct trinity_power_info *pi = trinity_get_pi(rdev);
1170 struct radeon_ps *new_ps = &pi->requested_rps;
1171 struct radeon_ps *old_ps = &pi->current_rps;
d70229f7
AD
1172
1173 trinity_acquire_mutex(rdev);
1174 if (pi->enable_dpm) {
940eea8e 1175 trinity_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
d70229f7
AD
1176 trinity_enable_power_level_0(rdev);
1177 trinity_force_level_0(rdev);
1178 trinity_wait_for_level_0(rdev);
940eea8e
AD
1179 trinity_setup_nbp_sim(rdev, new_ps);
1180 trinity_program_power_levels_0_to_n(rdev, new_ps, old_ps);
d70229f7
AD
1181 trinity_force_level_0(rdev);
1182 trinity_unforce_levels(rdev);
940eea8e 1183 trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
d70229f7
AD
1184 }
1185 trinity_release_mutex(rdev);
1186
1187 return 0;
1188}
1189
a284c48a
AD
1190void trinity_dpm_post_set_power_state(struct radeon_device *rdev)
1191{
1192 struct trinity_power_info *pi = trinity_get_pi(rdev);
1193 struct radeon_ps *new_ps = &pi->requested_rps;
1194
1195 trinity_update_current_ps(rdev, new_ps);
1196}
1197
d70229f7
AD
1198void trinity_dpm_setup_asic(struct radeon_device *rdev)
1199{
1200 trinity_acquire_mutex(rdev);
1201 sumo_program_sstp(rdev);
1202 sumo_take_smu_control(rdev, true);
1203 trinity_get_min_sclk_divider(rdev);
1204 trinity_release_mutex(rdev);
1205}
1206
1207void trinity_dpm_reset_asic(struct radeon_device *rdev)
1208{
1209 struct trinity_power_info *pi = trinity_get_pi(rdev);
1210
1211 trinity_acquire_mutex(rdev);
1212 if (pi->enable_dpm) {
1213 trinity_enable_power_level_0(rdev);
1214 trinity_force_level_0(rdev);
1215 trinity_wait_for_level_0(rdev);
1216 trinity_program_bootup_state(rdev);
1217 trinity_force_level_0(rdev);
1218 trinity_unforce_levels(rdev);
1219 }
1220 trinity_release_mutex(rdev);
1221}
1222
1223static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
1224 u32 vid_2bit)
1225{
1226 struct trinity_power_info *pi = trinity_get_pi(rdev);
1227 u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
1228 u32 svi_mode = (RREG32_SMC(PM_CONFIG) & SVI_Mode) ? 1 : 0;
1229 u32 step = (svi_mode == 0) ? 1250 : 625;
1230 u32 delta = vid_7bit * step + 50;
1231
1232 if (delta > 155000)
1233 return 0;
1234
1235 return (155000 - delta) / 100;
1236}
1237
1238static void trinity_patch_boot_state(struct radeon_device *rdev,
1239 struct trinity_ps *ps)
1240{
1241 struct trinity_power_info *pi = trinity_get_pi(rdev);
1242
1243 ps->num_levels = 1;
1244 ps->nbps_flags = 0;
1245 ps->bapm_flags = 0;
1246 ps->levels[0] = pi->boot_pl;
1247}
1248
1249static u8 trinity_calculate_vce_wm(struct radeon_device *rdev, u32 sclk)
1250{
1251 if (sclk < 20000)
1252 return 1;
1253 return 0;
1254}
1255
1256static void trinity_construct_boot_state(struct radeon_device *rdev)
1257{
1258 struct trinity_power_info *pi = trinity_get_pi(rdev);
1259
1260 pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
1261 pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
1262 pi->boot_pl.ds_divider_index = 0;
1263 pi->boot_pl.ss_divider_index = 0;
1264 pi->boot_pl.allow_gnb_slow = 1;
1265 pi->boot_pl.force_nbp_state = 0;
1266 pi->boot_pl.display_wm = 0;
1267 pi->boot_pl.vce_wm = 0;
1268 pi->current_ps.num_levels = 1;
1269 pi->current_ps.levels[0] = pi->boot_pl;
1270}
1271
1272static u8 trinity_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
1273 u32 sclk, u32 min_sclk_in_sr)
1274{
1275 struct trinity_power_info *pi = trinity_get_pi(rdev);
1276 u32 i;
1277 u32 temp;
1278 u32 min = (min_sclk_in_sr > TRINITY_MINIMUM_ENGINE_CLOCK) ?
1279 min_sclk_in_sr : TRINITY_MINIMUM_ENGINE_CLOCK;
1280
1281 if (sclk < min)
1282 return 0;
1283
1284 if (!pi->enable_sclk_ds)
1285 return 0;
1286
1287 for (i = TRINITY_MAX_DEEPSLEEP_DIVIDER_ID; ; i--) {
1288 temp = sclk / sumo_get_sleep_divider_from_id(i);
1289 if (temp >= min || i == 0)
1290 break;
1291 }
1292
1293 return (u8)i;
1294}
1295
1296static u32 trinity_get_valid_engine_clock(struct radeon_device *rdev,
1297 u32 lower_limit)
1298{
1299 struct trinity_power_info *pi = trinity_get_pi(rdev);
1300 u32 i;
1301
1302 for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
1303 if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
1304 return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
1305 }
1306
1307 if (i == pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries)
1308 DRM_ERROR("engine clock out of range!");
1309
1310 return 0;
1311}
1312
1313static void trinity_patch_thermal_state(struct radeon_device *rdev,
1314 struct trinity_ps *ps,
1315 struct trinity_ps *current_ps)
1316{
1317 struct trinity_power_info *pi = trinity_get_pi(rdev);
1318 u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
1319 u32 current_vddc;
1320 u32 current_sclk;
1321 u32 current_index = 0;
1322
1323 if (current_ps) {
1324 current_vddc = current_ps->levels[current_index].vddc_index;
1325 current_sclk = current_ps->levels[current_index].sclk;
1326 } else {
1327 current_vddc = pi->boot_pl.vddc_index;
1328 current_sclk = pi->boot_pl.sclk;
1329 }
1330
1331 ps->levels[0].vddc_index = current_vddc;
1332
1333 if (ps->levels[0].sclk > current_sclk)
1334 ps->levels[0].sclk = current_sclk;
1335
1336 ps->levels[0].ds_divider_index =
1337 trinity_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
1338 ps->levels[0].ss_divider_index = ps->levels[0].ds_divider_index;
1339 ps->levels[0].allow_gnb_slow = 1;
1340 ps->levels[0].force_nbp_state = 0;
1341 ps->levels[0].display_wm = 0;
1342 ps->levels[0].vce_wm =
1343 trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
1344}
1345
1346static u8 trinity_calculate_display_wm(struct radeon_device *rdev,
1347 struct trinity_ps *ps, u32 index)
1348{
1349 if (ps == NULL || ps->num_levels <= 1)
1350 return 0;
1351 else if (ps->num_levels == 2) {
1352 if (index == 0)
1353 return 0;
1354 else
1355 return 1;
1356 } else {
1357 if (index == 0)
1358 return 0;
1359 else if (ps->levels[index].sclk < 30000)
1360 return 0;
1361 else
1362 return 1;
1363 }
1364}
1365
0c4aaeae
AD
1366static u32 trinity_get_uvd_clock_index(struct radeon_device *rdev,
1367 struct radeon_ps *rps)
1368{
1369 struct trinity_power_info *pi = trinity_get_pi(rdev);
1370 u32 i = 0;
1371
1372 for (i = 0; i < 4; i++) {
1373 if ((rps->vclk == pi->sys_info.uvd_clock_table_entries[i].vclk) &&
1374 (rps->dclk == pi->sys_info.uvd_clock_table_entries[i].dclk))
1375 break;
1376 }
1377
1378 if (i >= 4) {
1379 DRM_ERROR("UVD clock index not found!\n");
1380 i = 3;
1381 }
1382 return i;
1383}
1384
1385static void trinity_adjust_uvd_state(struct radeon_device *rdev,
1386 struct radeon_ps *rps)
1387{
1388 struct trinity_ps *ps = trinity_get_ps(rps);
1389 struct trinity_power_info *pi = trinity_get_pi(rdev);
1390 u32 high_index = 0;
1391 u32 low_index = 0;
1392
1393 if (pi->uvd_dpm && r600_is_uvd_state(rps->class, rps->class2)) {
1394 high_index = trinity_get_uvd_clock_index(rdev, rps);
1395
1396 switch(high_index) {
1397 case 3:
1398 case 2:
1399 low_index = 1;
1400 break;
1401 case 1:
1402 case 0:
1403 default:
1404 low_index = 0;
1405 break;
1406 }
1407
1408 ps->vclk_low_divider =
1409 pi->sys_info.uvd_clock_table_entries[high_index].vclk_did;
1410 ps->dclk_low_divider =
1411 pi->sys_info.uvd_clock_table_entries[high_index].dclk_did;
1412 ps->vclk_high_divider =
1413 pi->sys_info.uvd_clock_table_entries[low_index].vclk_did;
1414 ps->dclk_high_divider =
1415 pi->sys_info.uvd_clock_table_entries[low_index].dclk_did;
1416 }
1417}
1418
1419
1420
940eea8e
AD
1421static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
1422 struct radeon_ps *new_rps,
1423 struct radeon_ps *old_rps)
d70229f7 1424{
940eea8e
AD
1425 struct trinity_ps *ps = trinity_get_ps(new_rps);
1426 struct trinity_ps *current_ps = trinity_get_ps(old_rps);
d70229f7
AD
1427 struct trinity_power_info *pi = trinity_get_pi(rdev);
1428 u32 min_voltage = 0; /* ??? */
1429 u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
1430 u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
1431 u32 i;
1432 bool force_high;
1433 u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
1434
940eea8e 1435 if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
d70229f7
AD
1436 return trinity_patch_thermal_state(rdev, ps, current_ps);
1437
940eea8e 1438 trinity_adjust_uvd_state(rdev, new_rps);
0c4aaeae 1439
d70229f7
AD
1440 for (i = 0; i < ps->num_levels; i++) {
1441 if (ps->levels[i].vddc_index < min_voltage)
1442 ps->levels[i].vddc_index = min_voltage;
1443
1444 if (ps->levels[i].sclk < min_sclk)
1445 ps->levels[i].sclk =
1446 trinity_get_valid_engine_clock(rdev, min_sclk);
1447
1448 ps->levels[i].ds_divider_index =
1449 sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
1450
1451 ps->levels[i].ss_divider_index = ps->levels[i].ds_divider_index;
1452
1453 ps->levels[i].allow_gnb_slow = 1;
1454 ps->levels[i].force_nbp_state = 0;
1455 ps->levels[i].display_wm =
1456 trinity_calculate_display_wm(rdev, ps, i);
1457 ps->levels[i].vce_wm =
1458 trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
1459 }
1460
940eea8e
AD
1461 if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
1462 ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY))
d70229f7
AD
1463 ps->bapm_flags |= TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE;
1464
1465 if (pi->sys_info.nb_dpm_enable) {
1466 ps->Dpm0PgNbPsLo = 0x1;
1467 ps->Dpm0PgNbPsHi = 0x0;
1468 ps->DpmXNbPsLo = 0x2;
1469 ps->DpmXNbPsHi = 0x1;
1470
940eea8e
AD
1471 if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
1472 ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) {
1473 force_high = ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ||
1474 ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) &&
d70229f7
AD
1475 (pi->sys_info.uma_channel_number == 1)));
1476 force_high = (num_active_displays >= 3) || force_high;
1477 ps->Dpm0PgNbPsLo = force_high ? 0x2 : 0x3;
1478 ps->Dpm0PgNbPsHi = 0x1;
1479 ps->DpmXNbPsLo = force_high ? 0x2 : 0x3;
1480 ps->DpmXNbPsHi = 0x2;
1481 ps->levels[ps->num_levels - 1].allow_gnb_slow = 0;
1482 }
1483 }
1484}
1485
1486static void trinity_cleanup_asic(struct radeon_device *rdev)
1487{
1488 sumo_take_smu_control(rdev, false);
1489}
1490
1491#if 0
1492static void trinity_pre_display_configuration_change(struct radeon_device *rdev)
1493{
1494 struct trinity_power_info *pi = trinity_get_pi(rdev);
1495
1496 if (pi->voltage_drop_in_dce)
1497 trinity_dce_enable_voltage_adjustment(rdev, false);
1498}
1499#endif
1500
1501static void trinity_add_dccac_value(struct radeon_device *rdev)
1502{
1503 u32 gpu_cac_avrg_cntl_window_size;
1504 u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
1505 u64 disp_clk = rdev->clock.default_dispclk / 100;
1506 u32 dc_cac_value;
1507
1508 gpu_cac_avrg_cntl_window_size =
1509 (RREG32_SMC(GPU_CAC_AVRG_CNTL) & WINDOW_SIZE_MASK) >> WINDOW_SIZE_SHIFT;
1510
1511 dc_cac_value = (u32)((14213 * disp_clk * disp_clk * (u64)num_active_displays) >>
1512 (32 - gpu_cac_avrg_cntl_window_size));
1513
1514 WREG32_SMC(DC_CAC_VALUE, dc_cac_value);
1515}
1516
1517void trinity_dpm_display_configuration_changed(struct radeon_device *rdev)
1518{
1519 struct trinity_power_info *pi = trinity_get_pi(rdev);
1520
1521 if (pi->voltage_drop_in_dce)
1522 trinity_dce_enable_voltage_adjustment(rdev, true);
1523 trinity_add_dccac_value(rdev);
1524}
1525
1526union power_info {
1527 struct _ATOM_POWERPLAY_INFO info;
1528 struct _ATOM_POWERPLAY_INFO_V2 info_2;
1529 struct _ATOM_POWERPLAY_INFO_V3 info_3;
1530 struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
1531 struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
1532 struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
1533};
1534
1535union pplib_clock_info {
1536 struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
1537 struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
1538 struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
1539 struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
1540};
1541
1542union pplib_power_state {
1543 struct _ATOM_PPLIB_STATE v1;
1544 struct _ATOM_PPLIB_STATE_V2 v2;
1545};
1546
1547static void trinity_parse_pplib_non_clock_info(struct radeon_device *rdev,
1548 struct radeon_ps *rps,
1549 struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
1550 u8 table_rev)
1551{
1552 struct trinity_ps *ps = trinity_get_ps(rps);
1553
1554 rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
1555 rps->class = le16_to_cpu(non_clock_info->usClassification);
1556 rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
1557
1558 if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
1559 rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
1560 rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
1561 } else {
1562 rps->vclk = 0;
1563 rps->dclk = 0;
1564 }
1565
1566 if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
1567 rdev->pm.dpm.boot_ps = rps;
1568 trinity_patch_boot_state(rdev, ps);
1569 }
1570 if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
1571 rdev->pm.dpm.uvd_ps = rps;
1572}
1573
1574static void trinity_parse_pplib_clock_info(struct radeon_device *rdev,
1575 struct radeon_ps *rps, int index,
1576 union pplib_clock_info *clock_info)
1577{
1578 struct trinity_power_info *pi = trinity_get_pi(rdev);
1579 struct trinity_ps *ps = trinity_get_ps(rps);
1580 struct trinity_pl *pl = &ps->levels[index];
1581 u32 sclk;
1582
1583 sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
1584 sclk |= clock_info->sumo.ucEngineClockHigh << 16;
1585 pl->sclk = sclk;
1586 pl->vddc_index = clock_info->sumo.vddcIndex;
1587
1588 ps->num_levels = index + 1;
1589
1590 if (pi->enable_sclk_ds) {
1591 pl->ds_divider_index = 5;
1592 pl->ss_divider_index = 5;
1593 }
1594}
1595
1596static int trinity_parse_power_table(struct radeon_device *rdev)
1597{
1598 struct radeon_mode_info *mode_info = &rdev->mode_info;
1599 struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
1600 union pplib_power_state *power_state;
1601 int i, j, k, non_clock_array_index, clock_array_index;
1602 union pplib_clock_info *clock_info;
1603 struct _StateArray *state_array;
1604 struct _ClockInfoArray *clock_info_array;
1605 struct _NonClockInfoArray *non_clock_info_array;
1606 union power_info *power_info;
1607 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
1608 u16 data_offset;
1609 u8 frev, crev;
1610 u8 *power_state_offset;
1611 struct sumo_ps *ps;
1612
1613 if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
1614 &frev, &crev, &data_offset))
1615 return -EINVAL;
1616 power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
1617
1618 state_array = (struct _StateArray *)
1619 (mode_info->atom_context->bios + data_offset +
1620 le16_to_cpu(power_info->pplib.usStateArrayOffset));
1621 clock_info_array = (struct _ClockInfoArray *)
1622 (mode_info->atom_context->bios + data_offset +
1623 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
1624 non_clock_info_array = (struct _NonClockInfoArray *)
1625 (mode_info->atom_context->bios + data_offset +
1626 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
1627
1628 rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
1629 state_array->ucNumEntries, GFP_KERNEL);
1630 if (!rdev->pm.dpm.ps)
1631 return -ENOMEM;
1632 power_state_offset = (u8 *)state_array->states;
1633 rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
1634 rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
1635 rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
1636 for (i = 0; i < state_array->ucNumEntries; i++) {
1637 power_state = (union pplib_power_state *)power_state_offset;
1638 non_clock_array_index = power_state->v2.nonClockInfoIndex;
1639 non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
1640 &non_clock_info_array->nonClockInfo[non_clock_array_index];
1641 if (!rdev->pm.power_state[i].clock_info)
1642 return -EINVAL;
1643 ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
1644 if (ps == NULL) {
1645 kfree(rdev->pm.dpm.ps);
1646 return -ENOMEM;
1647 }
1648 rdev->pm.dpm.ps[i].ps_priv = ps;
1649 k = 0;
1650 for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
1651 clock_array_index = power_state->v2.clockInfoIndex[j];
1652 if (clock_array_index >= clock_info_array->ucNumEntries)
1653 continue;
1654 if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
1655 break;
1656 clock_info = (union pplib_clock_info *)
1657 &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
1658 trinity_parse_pplib_clock_info(rdev,
1659 &rdev->pm.dpm.ps[i], k,
1660 clock_info);
1661 k++;
1662 }
1663 trinity_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
1664 non_clock_info,
1665 non_clock_info_array->ucEntrySize);
1666 power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
1667 }
1668 rdev->pm.dpm.num_ps = state_array->ucNumEntries;
1669 return 0;
1670}
1671
1672union igp_info {
1673 struct _ATOM_INTEGRATED_SYSTEM_INFO info;
1674 struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
1675 struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
1676 struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
1677 struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
1678};
1679
0c4aaeae
AD
1680static u32 trinity_convert_did_to_freq(struct radeon_device *rdev, u8 did)
1681{
1682 struct trinity_power_info *pi = trinity_get_pi(rdev);
1683 u32 divider;
1684
1685 if (did >= 8 && did <= 0x3f)
1686 divider = did * 25;
1687 else if (did > 0x3f && did <= 0x5f)
1688 divider = (did - 64) * 50 + 1600;
1689 else if (did > 0x5f && did <= 0x7e)
1690 divider = (did - 96) * 100 + 3200;
1691 else if (did == 0x7f)
1692 divider = 128 * 100;
1693 else
1694 return 10000;
1695
1696 return ((pi->sys_info.dentist_vco_freq * 100) + (divider - 1)) / divider;
1697}
1698
d70229f7
AD
1699static int trinity_parse_sys_info_table(struct radeon_device *rdev)
1700{
1701 struct trinity_power_info *pi = trinity_get_pi(rdev);
1702 struct radeon_mode_info *mode_info = &rdev->mode_info;
1703 int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
1704 union igp_info *igp_info;
1705 u8 frev, crev;
1706 u16 data_offset;
1707 int i;
1708
1709 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1710 &frev, &crev, &data_offset)) {
1711 igp_info = (union igp_info *)(mode_info->atom_context->bios +
1712 data_offset);
1713
1714 if (crev != 7) {
1715 DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
1716 return -EINVAL;
1717 }
1718 pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock);
1719 pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock);
1720 pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock);
0c4aaeae 1721 pi->sys_info.dentist_vco_freq = le32_to_cpu(igp_info->info_7.ulDentistVCOFreq);
d70229f7
AD
1722 pi->sys_info.bootup_nb_voltage_index =
1723 le16_to_cpu(igp_info->info_7.usBootUpNBVoltage);
1724 if (igp_info->info_7.ucHtcTmpLmt == 0)
1725 pi->sys_info.htc_tmp_lmt = 203;
1726 else
1727 pi->sys_info.htc_tmp_lmt = igp_info->info_7.ucHtcTmpLmt;
1728 if (igp_info->info_7.ucHtcHystLmt == 0)
1729 pi->sys_info.htc_hyst_lmt = 5;
1730 else
1731 pi->sys_info.htc_hyst_lmt = igp_info->info_7.ucHtcHystLmt;
1732 if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
1733 DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
1734 }
1735
1736 if (pi->enable_nbps_policy)
1737 pi->sys_info.nb_dpm_enable = igp_info->info_7.ucNBDPMEnable;
1738 else
1739 pi->sys_info.nb_dpm_enable = 0;
1740
1741 for (i = 0; i < TRINITY_NUM_NBPSTATES; i++) {
1742 pi->sys_info.nbp_mclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateMemclkFreq[i]);
1743 pi->sys_info.nbp_nclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateNClkFreq[i]);
1744 }
1745
1746 pi->sys_info.nbp_voltage_index[0] = le16_to_cpu(igp_info->info_7.usNBP0Voltage);
1747 pi->sys_info.nbp_voltage_index[1] = le16_to_cpu(igp_info->info_7.usNBP1Voltage);
1748 pi->sys_info.nbp_voltage_index[2] = le16_to_cpu(igp_info->info_7.usNBP2Voltage);
1749 pi->sys_info.nbp_voltage_index[3] = le16_to_cpu(igp_info->info_7.usNBP3Voltage);
1750
1751 if (!pi->sys_info.nb_dpm_enable) {
1752 for (i = 1; i < TRINITY_NUM_NBPSTATES; i++) {
1753 pi->sys_info.nbp_mclk[i] = pi->sys_info.nbp_mclk[0];
1754 pi->sys_info.nbp_nclk[i] = pi->sys_info.nbp_nclk[0];
1755 pi->sys_info.nbp_voltage_index[i] = pi->sys_info.nbp_voltage_index[0];
1756 }
1757 }
1758
1759 pi->sys_info.uma_channel_number = igp_info->info_7.ucUMAChannelNumber;
1760
1761 sumo_construct_sclk_voltage_mapping_table(rdev,
1762 &pi->sys_info.sclk_voltage_mapping_table,
1763 igp_info->info_7.sAvail_SCLK);
1764 sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
1765 igp_info->info_7.sAvail_SCLK);
1766
0c4aaeae
AD
1767 pi->sys_info.uvd_clock_table_entries[0].vclk_did =
1768 igp_info->info_7.ucDPMState0VclkFid;
1769 pi->sys_info.uvd_clock_table_entries[1].vclk_did =
1770 igp_info->info_7.ucDPMState1VclkFid;
1771 pi->sys_info.uvd_clock_table_entries[2].vclk_did =
1772 igp_info->info_7.ucDPMState2VclkFid;
1773 pi->sys_info.uvd_clock_table_entries[3].vclk_did =
1774 igp_info->info_7.ucDPMState3VclkFid;
1775
1776 pi->sys_info.uvd_clock_table_entries[0].dclk_did =
1777 igp_info->info_7.ucDPMState0DclkFid;
1778 pi->sys_info.uvd_clock_table_entries[1].dclk_did =
1779 igp_info->info_7.ucDPMState1DclkFid;
1780 pi->sys_info.uvd_clock_table_entries[2].dclk_did =
1781 igp_info->info_7.ucDPMState2DclkFid;
1782 pi->sys_info.uvd_clock_table_entries[3].dclk_did =
1783 igp_info->info_7.ucDPMState3DclkFid;
1784
1785 for (i = 0; i < 4; i++) {
1786 pi->sys_info.uvd_clock_table_entries[i].vclk =
1787 trinity_convert_did_to_freq(rdev,
1788 pi->sys_info.uvd_clock_table_entries[i].vclk_did);
1789 pi->sys_info.uvd_clock_table_entries[i].dclk =
1790 trinity_convert_did_to_freq(rdev,
1791 pi->sys_info.uvd_clock_table_entries[i].dclk_did);
1792 }
1793
1794
1795
d70229f7
AD
1796 }
1797 return 0;
1798}
1799
1800int trinity_dpm_init(struct radeon_device *rdev)
1801{
1802 struct trinity_power_info *pi;
1803 int ret, i;
1804
1805 pi = kzalloc(sizeof(struct trinity_power_info), GFP_KERNEL);
1806 if (pi == NULL)
1807 return -ENOMEM;
1808 rdev->pm.dpm.priv = pi;
1809
1810 for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
1811 pi->at[i] = TRINITY_AT_DFLT;
1812
1813 pi->enable_nbps_policy = true;
1814 pi->enable_sclk_ds = true;
1815 pi->enable_gfx_power_gating = true;
1816 pi->enable_gfx_clock_gating = true;
1817 pi->enable_mg_clock_gating = true;
1818 pi->enable_gfx_dynamic_mgpg = true; /* ??? */
1819 pi->override_dynamic_mgpg = true;
1820 pi->enable_auto_thermal_throttling = true;
1821 pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
0c4aaeae 1822 pi->uvd_dpm = true; /* ??? */
d70229f7
AD
1823
1824 ret = trinity_parse_sys_info_table(rdev);
1825 if (ret)
1826 return ret;
1827
1828 trinity_construct_boot_state(rdev);
1829
1830 ret = trinity_parse_power_table(rdev);
1831 if (ret)
1832 return ret;
1833
1834 pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
1835 pi->enable_dpm = true;
1836
1837 return 0;
1838}
1839
1840void trinity_dpm_print_power_state(struct radeon_device *rdev,
1841 struct radeon_ps *rps)
1842{
1843 int i;
1844 struct trinity_ps *ps = trinity_get_ps(rps);
1845
1846 r600_dpm_print_class_info(rps->class, rps->class2);
1847 r600_dpm_print_cap_info(rps->caps);
1848 printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
1849 for (i = 0; i < ps->num_levels; i++) {
1850 struct trinity_pl *pl = &ps->levels[i];
1851 printk("\t\tpower level %d sclk: %u vddc: %u\n",
1852 i, pl->sclk,
1853 trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
1854 }
1855 r600_dpm_print_ps_status(rdev, rps);
1856}
1857
1858void trinity_dpm_fini(struct radeon_device *rdev)
1859{
1860 int i;
1861
1862 trinity_cleanup_asic(rdev); /* ??? */
1863
1864 for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
1865 kfree(rdev->pm.dpm.ps[i].ps_priv);
1866 }
1867 kfree(rdev->pm.dpm.ps);
1868 kfree(rdev->pm.dpm.priv);
1869}
1870
1871u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
1872{
a284c48a
AD
1873 struct trinity_power_info *pi = trinity_get_pi(rdev);
1874 struct trinity_ps *requested_state = trinity_get_ps(&pi->requested_rps);
d70229f7
AD
1875
1876 if (low)
1877 return requested_state->levels[0].sclk;
1878 else
1879 return requested_state->levels[requested_state->num_levels - 1].sclk;
1880}
1881
1882u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low)
1883{
1884 struct trinity_power_info *pi = trinity_get_pi(rdev);
1885
1886 return pi->sys_info.bootup_uma_clk;
1887}
This page took 0.184207 seconds and 5 git commands to generate.