]> rtime.felk.cvut.cz Git - linux-imx.git/blob - drivers/gpu/drm/radeon/trinity_dpm.c
drm/radeon/kms: add dpm support for trinity asics
[linux-imx.git] / drivers / gpu / drm / radeon / trinity_dpm.c
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
38 static 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
117 static 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
128 static 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
143 static 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
165 static 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
189 static 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
212 static 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
337 static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
338                                                    const u32 *seq, u32 count);
339 static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev);
340 static void trinity_apply_state_adjust_rules(struct radeon_device *rdev);
341
342 struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
343 {
344         struct trinity_ps *ps = rps->ps_priv;
345
346         return ps;
347 }
348
349 struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)
350 {
351         struct trinity_power_info *pi = rdev->pm.dpm.priv;
352
353         return pi;
354 }
355
356 static void trinity_gfx_powergating_initialize(struct radeon_device *rdev)
357 {
358         struct trinity_power_info *pi = trinity_get_pi(rdev);
359         u32 p, u;
360         u32 value;
361         struct atom_clock_dividers dividers;
362         u32 xclk = sumo_get_xclk(rdev);
363         u32 sssd = 1;
364         int ret;
365         u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
366
367         ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
368                                              25000, false, &dividers);
369         if (ret)
370                 return;
371
372         value = RREG32_SMC(GFX_POWER_GATING_CNTL);
373         value &= ~(SSSD_MASK | PDS_DIV_MASK);
374         if (sssd)
375                 value |= SSSD(1);
376         value |= PDS_DIV(dividers.post_div);
377         WREG32_SMC(GFX_POWER_GATING_CNTL, value);
378
379         r600_calculate_u_and_p(500, xclk, 16, &p, &u);
380
381         WREG32(CG_PG_CTRL, SP(p) | SU(u));
382
383         WREG32_P(CG_GIPOTS, CG_GIPOT(p), ~CG_GIPOT_MASK);
384
385         /* XXX double check hw_rev */
386         if (pi->override_dynamic_mgpg && (hw_rev == 0))
387                 trinity_override_dynamic_mg_powergating(rdev);
388
389 }
390
391 #define CGCG_CGTT_LOCAL0_MASK       0xFFFF33FF
392 #define CGCG_CGTT_LOCAL1_MASK       0xFFFB0FFE
393 #define CGTS_SM_CTRL_REG_DISABLE    0x00600000
394 #define CGTS_SM_CTRL_REG_ENABLE     0x96944200
395
396 static void trinity_mg_clockgating_enable(struct radeon_device *rdev,
397                                           bool enable)
398 {
399         u32 local0;
400         u32 local1;
401
402         if (enable) {
403                 local0 = RREG32_CG(CG_CGTT_LOCAL_0);
404                 local1 = RREG32_CG(CG_CGTT_LOCAL_1);
405
406                 WREG32_CG(CG_CGTT_LOCAL_0,
407                           (0x00380000 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
408                 WREG32_CG(CG_CGTT_LOCAL_1,
409                           (0x0E000000 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
410
411                 WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_ENABLE);
412         } else {
413                 WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_DISABLE);
414
415                 local0 = RREG32_CG(CG_CGTT_LOCAL_0);
416                 local1 = RREG32_CG(CG_CGTT_LOCAL_1);
417
418                 WREG32_CG(CG_CGTT_LOCAL_0,
419                           CGCG_CGTT_LOCAL0_MASK | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
420                 WREG32_CG(CG_CGTT_LOCAL_1,
421                           CGCG_CGTT_LOCAL1_MASK | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
422         }
423 }
424
425 static void trinity_mg_clockgating_initialize(struct radeon_device *rdev)
426 {
427         u32 count;
428         const u32 *seq = NULL;
429
430         seq = &trinity_mgcg_shls_default[0];
431         count = sizeof(trinity_mgcg_shls_default) / (3 * sizeof(u32));
432
433         trinity_program_clk_gating_hw_sequence(rdev, seq, count);
434 }
435
436 static void trinity_gfx_clockgating_enable(struct radeon_device *rdev,
437                                            bool enable)
438 {
439         if (enable) {
440                 WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
441         } else {
442                 WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
443                 WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
444                 WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
445                 RREG32(GB_ADDR_CONFIG);
446         }
447 }
448
449 static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
450                                                    const u32 *seq, u32 count)
451 {
452         u32 i, length = count * 3;
453
454         for (i = 0; i < length; i += 3)
455                 WREG32_P(seq[i], seq[i+1], ~seq[i+2]);
456 }
457
458 static void trinity_program_override_mgpg_sequences(struct radeon_device *rdev,
459                                                     const u32 *seq, u32 count)
460 {
461         u32  i, length = count * 2;
462
463         for (i = 0; i < length; i += 2)
464                 WREG32(seq[i], seq[i+1]);
465
466 }
467
468 static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev)
469 {
470         u32 count;
471         const u32 *seq = NULL;
472
473         seq = &trinity_override_mgpg_sequences[0];
474         count = sizeof(trinity_override_mgpg_sequences) / (2 * sizeof(u32));
475
476         trinity_program_override_mgpg_sequences(rdev, seq, count);
477 }
478
479 static void trinity_ls_clockgating_enable(struct radeon_device *rdev,
480                                           bool enable)
481 {
482         u32 count;
483         const u32 *seq = NULL;
484
485         if (enable) {
486                 seq = &trinity_sysls_enable[0];
487                 count = sizeof(trinity_sysls_enable) / (3 * sizeof(u32));
488         } else {
489                 seq = &trinity_sysls_disable[0];
490                 count = sizeof(trinity_sysls_disable) / (3 * sizeof(u32));
491         }
492
493         trinity_program_clk_gating_hw_sequence(rdev, seq, count);
494 }
495
496 static void trinity_gfx_powergating_enable(struct radeon_device *rdev,
497                                            bool enable)
498 {
499         if (enable) {
500                 if (RREG32_SMC(CC_SMU_TST_EFUSE1_MISC) & RB_BACKEND_DISABLE_MASK)
501                         WREG32_SMC(SMU_SCRATCH_A, (RREG32_SMC(SMU_SCRATCH_A) | 0x01));
502
503                 WREG32_P(SCLK_PWRMGT_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
504         } else {
505                 WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_PWR_DOWN_EN);
506                 RREG32(GB_ADDR_CONFIG);
507         }
508 }
509
510 static void trinity_gfx_dynamic_mgpg_enable(struct radeon_device *rdev,
511                                             bool enable)
512 {
513         u32 value;
514
515         if (enable) {
516                 value = RREG32_SMC(PM_I_CNTL_1);
517                 value &= ~DS_PG_CNTL_MASK;
518                 value |= DS_PG_CNTL(1);
519                 WREG32_SMC(PM_I_CNTL_1, value);
520
521                 value = RREG32_SMC(SMU_S_PG_CNTL);
522                 value &= ~DS_PG_EN_MASK;
523                 value |= DS_PG_EN(1);
524                 WREG32_SMC(SMU_S_PG_CNTL, value);
525         } else {
526                 value = RREG32_SMC(SMU_S_PG_CNTL);
527                 value &= ~DS_PG_EN_MASK;
528                 WREG32_SMC(SMU_S_PG_CNTL, value);
529
530                 value = RREG32_SMC(PM_I_CNTL_1);
531                 value &= ~DS_PG_CNTL_MASK;
532                 WREG32_SMC(PM_I_CNTL_1, value);
533         }
534
535         trinity_gfx_dynamic_mgpg_config(rdev);
536
537 }
538
539 static void trinity_enable_clock_power_gating(struct radeon_device *rdev)
540 {
541         struct trinity_power_info *pi = trinity_get_pi(rdev);
542
543         if (pi->enable_gfx_clock_gating)
544                 sumo_gfx_clockgating_initialize(rdev);
545         if (pi->enable_mg_clock_gating)
546                 trinity_mg_clockgating_initialize(rdev);
547         if (pi->enable_gfx_power_gating)
548                 trinity_gfx_powergating_initialize(rdev);
549         if (pi->enable_mg_clock_gating) {
550                 trinity_ls_clockgating_enable(rdev, true);
551                 trinity_mg_clockgating_enable(rdev, true);
552         }
553         if (pi->enable_gfx_clock_gating)
554                 trinity_gfx_clockgating_enable(rdev, true);
555         if (pi->enable_gfx_dynamic_mgpg)
556                 trinity_gfx_dynamic_mgpg_enable(rdev, true);
557         if (pi->enable_gfx_power_gating)
558                 trinity_gfx_powergating_enable(rdev, true);
559 }
560
561 static void trinity_disable_clock_power_gating(struct radeon_device *rdev)
562 {
563         struct trinity_power_info *pi = trinity_get_pi(rdev);
564
565         if (pi->enable_gfx_power_gating)
566                 trinity_gfx_powergating_enable(rdev, false);
567         if (pi->enable_gfx_dynamic_mgpg)
568                 trinity_gfx_dynamic_mgpg_enable(rdev, false);
569         if (pi->enable_gfx_clock_gating)
570                 trinity_gfx_clockgating_enable(rdev, false);
571         if (pi->enable_mg_clock_gating) {
572                 trinity_mg_clockgating_enable(rdev, false);
573                 trinity_ls_clockgating_enable(rdev, false);
574         }
575 }
576
577 static void trinity_set_divider_value(struct radeon_device *rdev,
578                                       u32 index, u32 sclk)
579 {
580         struct atom_clock_dividers  dividers;
581         int ret;
582         u32 value;
583         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
584
585         ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
586                                              sclk, false, &dividers);
587         if (ret)
588                 return;
589
590         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
591         value &= ~CLK_DIVIDER_MASK;
592         value |= CLK_DIVIDER(dividers.post_div);
593         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
594
595         ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
596                                              sclk/2, false, &dividers);
597         if (ret)
598                 return;
599
600         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix);
601         value &= ~PD_SCLK_DIVIDER_MASK;
602         value |= PD_SCLK_DIVIDER(dividers.post_div);
603         WREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix, value);
604 }
605
606 static void trinity_set_ds_dividers(struct radeon_device *rdev,
607                                     u32 index, u32 divider)
608 {
609         u32 value;
610         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
611
612         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
613         value &= ~DS_DIV_MASK;
614         value |= DS_DIV(divider);
615         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
616 }
617
618 static void trinity_set_ss_dividers(struct radeon_device *rdev,
619                                     u32 index, u32 divider)
620 {
621         u32 value;
622         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
623
624         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
625         value &= ~DS_SH_DIV_MASK;
626         value |= DS_SH_DIV(divider);
627         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
628 }
629
630 static void trinity_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
631 {
632         struct trinity_power_info *pi = trinity_get_pi(rdev);
633         u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid);
634         u32 value;
635         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
636
637         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
638         value &= ~VID_MASK;
639         value |= VID(vid_7bit);
640         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
641
642         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
643         value &= ~LVRT_MASK;
644         value |= LVRT(0);
645         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
646 }
647
648 static void trinity_set_allos_gnb_slow(struct radeon_device *rdev,
649                                        u32 index, u32 gnb_slow)
650 {
651         u32 value;
652         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
653
654         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
655         value &= ~GNB_SLOW_MASK;
656         value |= GNB_SLOW(gnb_slow);
657         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
658 }
659
660 static void trinity_set_force_nbp_state(struct radeon_device *rdev,
661                                         u32 index, u32 force_nbp_state)
662 {
663         u32 value;
664         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
665
666         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
667         value &= ~FORCE_NBPS1_MASK;
668         value |= FORCE_NBPS1(force_nbp_state);
669         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
670 }
671
672 static void trinity_set_display_wm(struct radeon_device *rdev,
673                                    u32 index, u32 wm)
674 {
675         u32 value;
676         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
677
678         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
679         value &= ~DISPLAY_WM_MASK;
680         value |= DISPLAY_WM(wm);
681         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
682 }
683
684 static void trinity_set_vce_wm(struct radeon_device *rdev,
685                                u32 index, u32 wm)
686 {
687         u32 value;
688         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
689
690         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
691         value &= ~VCE_WM_MASK;
692         value |= VCE_WM(wm);
693         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
694 }
695
696 static void trinity_set_at(struct radeon_device *rdev,
697                            u32 index, u32 at)
698 {
699         u32 value;
700         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
701
702         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix);
703         value &= ~AT_MASK;
704         value |= AT(at);
705         WREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix, value);
706 }
707
708 static void trinity_program_power_level(struct radeon_device *rdev,
709                                         struct trinity_pl *pl, u32 index)
710 {
711         struct trinity_power_info *pi = trinity_get_pi(rdev);
712
713         if (index >= SUMO_MAX_HARDWARE_POWERLEVELS)
714                 return;
715
716         trinity_set_divider_value(rdev, index, pl->sclk);
717         trinity_set_vid(rdev, index, pl->vddc_index);
718         trinity_set_ss_dividers(rdev, index, pl->ss_divider_index);
719         trinity_set_ds_dividers(rdev, index, pl->ds_divider_index);
720         trinity_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
721         trinity_set_force_nbp_state(rdev, index, pl->force_nbp_state);
722         trinity_set_display_wm(rdev, index, pl->display_wm);
723         trinity_set_vce_wm(rdev, index, pl->vce_wm);
724         trinity_set_at(rdev, index, pi->at[index]);
725 }
726
727 static void trinity_power_level_enable_disable(struct radeon_device *rdev,
728                                                u32 index, bool enable)
729 {
730         u32 value;
731         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
732
733         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
734         value &= ~STATE_VALID_MASK;
735         if (enable)
736                 value |= STATE_VALID(1);
737         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
738 }
739
740 static bool trinity_dpm_enabled(struct radeon_device *rdev)
741 {
742         if (RREG32_SMC(SMU_SCLK_DPM_CNTL) & SCLK_DPM_EN(1))
743                 return true;
744         else
745                 return false;
746 }
747
748 static void trinity_start_dpm(struct radeon_device *rdev)
749 {
750         u32 value = RREG32_SMC(SMU_SCLK_DPM_CNTL);
751
752         value &= ~(SCLK_DPM_EN_MASK | SCLK_DPM_BOOT_STATE_MASK | VOLTAGE_CHG_EN_MASK);
753         value |= SCLK_DPM_EN(1) | SCLK_DPM_BOOT_STATE(0) | VOLTAGE_CHG_EN(1);
754         WREG32_SMC(SMU_SCLK_DPM_CNTL, value);
755
756         WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
757         WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~EN);
758
759         trinity_dpm_config(rdev, true);
760 }
761
762 static void trinity_wait_for_dpm_enabled(struct radeon_device *rdev)
763 {
764         int i;
765
766         for (i = 0; i < rdev->usec_timeout; i++) {
767                 if (RREG32(SCLK_PWRMGT_CNTL) & DYNAMIC_PM_EN)
768                         break;
769                 udelay(1);
770         }
771         for (i = 0; i < rdev->usec_timeout; i++) {
772                 if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_STATE_MASK) == 0)
773                         break;
774                 udelay(1);
775         }
776         for (i = 0; i < rdev->usec_timeout; i++) {
777                 if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
778                         break;
779                 udelay(1);
780         }
781 }
782
783 static void trinity_stop_dpm(struct radeon_device *rdev)
784 {
785         u32 sclk_dpm_cntl;
786
787         WREG32_P(CG_CG_VOLTAGE_CNTL, EN, ~EN);
788
789         sclk_dpm_cntl = RREG32_SMC(SMU_SCLK_DPM_CNTL);
790         sclk_dpm_cntl &= ~(SCLK_DPM_EN_MASK | VOLTAGE_CHG_EN_MASK);
791         WREG32_SMC(SMU_SCLK_DPM_CNTL, sclk_dpm_cntl);
792
793         trinity_dpm_config(rdev, false);
794 }
795
796 static void trinity_start_am(struct radeon_device *rdev)
797 {
798         WREG32_P(SCLK_PWRMGT_CNTL, 0, ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
799 }
800
801 static void trinity_reset_am(struct radeon_device *rdev)
802 {
803         WREG32_P(SCLK_PWRMGT_CNTL, RESET_SCLK_CNT | RESET_BUSY_CNT,
804                  ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
805 }
806
807 static void trinity_wait_for_level_0(struct radeon_device *rdev)
808 {
809         int i;
810
811         for (i = 0; i < rdev->usec_timeout; i++) {
812                 if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
813                         break;
814                 udelay(1);
815         }
816 }
817
818 static void trinity_enable_power_level_0(struct radeon_device *rdev)
819 {
820         trinity_power_level_enable_disable(rdev, 0, true);
821 }
822
823 static void trinity_force_level_0(struct radeon_device *rdev)
824 {
825         trinity_dpm_force_state(rdev, 0);
826 }
827
828 static void trinity_unforce_levels(struct radeon_device *rdev)
829 {
830         trinity_dpm_no_forced_level(rdev);
831 }
832
833 static void trinity_update_current_power_levels(struct radeon_device *rdev)
834 {
835         struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
836         struct trinity_power_info *pi = trinity_get_pi(rdev);
837
838         pi->current_ps = *new_ps;
839 }
840
841 static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev)
842 {
843         struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
844         struct trinity_ps *old_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
845         u32 i;
846         u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
847
848         for (i = 0; i < new_ps->num_levels; i++) {
849                 trinity_program_power_level(rdev, &new_ps->levels[i], i);
850                 trinity_power_level_enable_disable(rdev, i, true);
851         }
852
853         for (i = new_ps->num_levels; i < n_current_state_levels; i++)
854                 trinity_power_level_enable_disable(rdev, i, false);
855 }
856
857 static void trinity_program_bootup_state(struct radeon_device *rdev)
858 {
859         struct trinity_power_info *pi = trinity_get_pi(rdev);
860         u32 i;
861
862         trinity_program_power_level(rdev, &pi->boot_pl, 0);
863         trinity_power_level_enable_disable(rdev, 0, true);
864
865         for (i = 1; i < 8; i++)
866                 trinity_power_level_enable_disable(rdev, i, false);
867 }
868
869 static void trinity_program_ttt(struct radeon_device *rdev)
870 {
871         struct trinity_power_info *pi = trinity_get_pi(rdev);
872         u32 value = RREG32_SMC(SMU_SCLK_DPM_TTT);
873
874         value &= ~(HT_MASK | LT_MASK);
875         value |= HT((pi->thermal_auto_throttling + 49) * 8);
876         value |= LT((pi->thermal_auto_throttling + 49 - pi->sys_info.htc_hyst_lmt) * 8);
877         WREG32_SMC(SMU_SCLK_DPM_TTT, value);
878 }
879
880 static void trinity_enable_att(struct radeon_device *rdev)
881 {
882         u32 value = RREG32_SMC(SMU_SCLK_DPM_TT_CNTL);
883
884         value &= ~SCLK_TT_EN_MASK;
885         value |= SCLK_TT_EN(1);
886         WREG32_SMC(SMU_SCLK_DPM_TT_CNTL, value);
887 }
888
889 static void trinity_program_sclk_dpm(struct radeon_device *rdev)
890 {
891         u32 p, u;
892         u32 tp = RREG32_SMC(PM_TP);
893         u32 ni;
894         u32 xclk = sumo_get_xclk(rdev);
895         u32 value;
896
897         r600_calculate_u_and_p(400, xclk, 16, &p, &u);
898
899         ni = (p + tp - 1) / tp;
900
901         value = RREG32_SMC(PM_I_CNTL_1);
902         value &= ~SCLK_DPM_MASK;
903         value |= SCLK_DPM(ni);
904         WREG32_SMC(PM_I_CNTL_1, value);
905 }
906
907 static int trinity_set_thermal_temperature_range(struct radeon_device *rdev,
908                                                  int min_temp, int max_temp)
909 {
910         int low_temp = 0 * 1000;
911         int high_temp = 255 * 1000;
912
913         if (low_temp < min_temp)
914                 low_temp = min_temp;
915         if (high_temp > max_temp)
916                 high_temp = max_temp;
917         if (high_temp < low_temp) {
918                 DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
919                 return -EINVAL;
920         }
921
922         WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
923         WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
924
925         rdev->pm.dpm.thermal.min_temp = low_temp;
926         rdev->pm.dpm.thermal.max_temp = high_temp;
927
928         return 0;
929 }
930
931 int trinity_dpm_enable(struct radeon_device *rdev)
932 {
933         struct trinity_power_info *pi = trinity_get_pi(rdev);
934
935         trinity_acquire_mutex(rdev);
936
937         if (trinity_dpm_enabled(rdev)) {
938                 trinity_release_mutex(rdev);
939                 return -EINVAL;
940         }
941
942         trinity_enable_clock_power_gating(rdev);
943         trinity_program_bootup_state(rdev);
944         sumo_program_vc(rdev, 0x00C00033);
945         trinity_start_am(rdev);
946         if (pi->enable_auto_thermal_throttling) {
947                 trinity_program_ttt(rdev);
948                 trinity_enable_att(rdev);
949         }
950         trinity_program_sclk_dpm(rdev);
951         trinity_start_dpm(rdev);
952         trinity_wait_for_dpm_enabled(rdev);
953         trinity_release_mutex(rdev);
954
955         if (rdev->irq.installed &&
956             r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
957                 trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
958                 rdev->irq.dpm_thermal = true;
959                 radeon_irq_set(rdev);
960         }
961
962         return 0;
963 }
964
965 void trinity_dpm_disable(struct radeon_device *rdev)
966 {
967         trinity_acquire_mutex(rdev);
968         if (!trinity_dpm_enabled(rdev)) {
969                 trinity_release_mutex(rdev);
970                 return;
971         }
972         trinity_disable_clock_power_gating(rdev);
973         sumo_clear_vc(rdev);
974         trinity_wait_for_level_0(rdev);
975         trinity_stop_dpm(rdev);
976         trinity_reset_am(rdev);
977         trinity_release_mutex(rdev);
978
979         if (rdev->irq.installed &&
980             r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
981                 rdev->irq.dpm_thermal = false;
982                 radeon_irq_set(rdev);
983         }
984 }
985
986 static void trinity_get_min_sclk_divider(struct radeon_device *rdev)
987 {
988         struct trinity_power_info *pi = trinity_get_pi(rdev);
989
990         pi->min_sclk_did =
991                 (RREG32_SMC(CC_SMU_MISC_FUSES) & MinSClkDid_MASK) >> MinSClkDid_SHIFT;
992 }
993
994 static void trinity_setup_nbp_sim(struct radeon_device *rdev)
995 {
996         struct trinity_power_info *pi = trinity_get_pi(rdev);
997         struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
998         u32 nbpsconfig;
999
1000         if (pi->sys_info.nb_dpm_enable) {
1001                 nbpsconfig = RREG32_SMC(NB_PSTATE_CONFIG);
1002                 nbpsconfig &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | DpmXNbPsLo_MASK | DpmXNbPsHi_MASK);
1003                 nbpsconfig |= (Dpm0PgNbPsLo(new_ps->Dpm0PgNbPsLo) |
1004                                Dpm0PgNbPsHi(new_ps->Dpm0PgNbPsHi) |
1005                                DpmXNbPsLo(new_ps->DpmXNbPsLo) |
1006                                DpmXNbPsHi(new_ps->DpmXNbPsHi));
1007                 WREG32_SMC(NB_PSTATE_CONFIG, nbpsconfig);
1008         }
1009 }
1010
1011 int trinity_dpm_set_power_state(struct radeon_device *rdev)
1012 {
1013         struct trinity_power_info *pi = trinity_get_pi(rdev);
1014
1015         trinity_apply_state_adjust_rules(rdev);
1016         trinity_update_current_power_levels(rdev);
1017
1018         trinity_acquire_mutex(rdev);
1019         if (pi->enable_dpm) {
1020                 trinity_enable_power_level_0(rdev);
1021                 trinity_force_level_0(rdev);
1022                 trinity_wait_for_level_0(rdev);
1023                 trinity_setup_nbp_sim(rdev);
1024                 trinity_program_power_levels_0_to_n(rdev);
1025                 trinity_force_level_0(rdev);
1026                 trinity_unforce_levels(rdev);
1027         }
1028         trinity_release_mutex(rdev);
1029
1030         return 0;
1031 }
1032
1033 void trinity_dpm_setup_asic(struct radeon_device *rdev)
1034 {
1035         trinity_acquire_mutex(rdev);
1036         sumo_program_sstp(rdev);
1037         sumo_take_smu_control(rdev, true);
1038         trinity_get_min_sclk_divider(rdev);
1039         trinity_release_mutex(rdev);
1040 }
1041
1042 void trinity_dpm_reset_asic(struct radeon_device *rdev)
1043 {
1044         struct trinity_power_info *pi = trinity_get_pi(rdev);
1045
1046         trinity_acquire_mutex(rdev);
1047         if (pi->enable_dpm) {
1048                 trinity_enable_power_level_0(rdev);
1049                 trinity_force_level_0(rdev);
1050                 trinity_wait_for_level_0(rdev);
1051                 trinity_program_bootup_state(rdev);
1052                 trinity_force_level_0(rdev);
1053                 trinity_unforce_levels(rdev);
1054         }
1055         trinity_release_mutex(rdev);
1056 }
1057
1058 static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
1059                                                   u32 vid_2bit)
1060 {
1061         struct trinity_power_info *pi = trinity_get_pi(rdev);
1062         u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
1063         u32 svi_mode = (RREG32_SMC(PM_CONFIG) & SVI_Mode) ? 1 : 0;
1064         u32 step = (svi_mode == 0) ? 1250 : 625;
1065         u32 delta = vid_7bit * step + 50;
1066
1067         if (delta > 155000)
1068                 return 0;
1069
1070         return (155000 - delta) / 100;
1071 }
1072
1073 static void trinity_patch_boot_state(struct radeon_device *rdev,
1074                                      struct trinity_ps *ps)
1075 {
1076         struct trinity_power_info *pi = trinity_get_pi(rdev);
1077
1078         ps->num_levels = 1;
1079         ps->nbps_flags = 0;
1080         ps->bapm_flags = 0;
1081         ps->levels[0] = pi->boot_pl;
1082 }
1083
1084 static u8 trinity_calculate_vce_wm(struct radeon_device *rdev, u32 sclk)
1085 {
1086         if (sclk < 20000)
1087                 return 1;
1088         return 0;
1089 }
1090
1091 static void trinity_construct_boot_state(struct radeon_device *rdev)
1092 {
1093         struct trinity_power_info *pi = trinity_get_pi(rdev);
1094
1095         pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
1096         pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
1097         pi->boot_pl.ds_divider_index = 0;
1098         pi->boot_pl.ss_divider_index = 0;
1099         pi->boot_pl.allow_gnb_slow = 1;
1100         pi->boot_pl.force_nbp_state = 0;
1101         pi->boot_pl.display_wm = 0;
1102         pi->boot_pl.vce_wm = 0;
1103         pi->current_ps.num_levels = 1;
1104         pi->current_ps.levels[0] = pi->boot_pl;
1105 }
1106
1107 static u8 trinity_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
1108                                                   u32 sclk, u32 min_sclk_in_sr)
1109 {
1110         struct trinity_power_info *pi = trinity_get_pi(rdev);
1111         u32 i;
1112         u32 temp;
1113         u32 min = (min_sclk_in_sr > TRINITY_MINIMUM_ENGINE_CLOCK) ?
1114                 min_sclk_in_sr : TRINITY_MINIMUM_ENGINE_CLOCK;
1115
1116         if (sclk < min)
1117                 return 0;
1118
1119         if (!pi->enable_sclk_ds)
1120                 return 0;
1121
1122         for (i = TRINITY_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
1123                 temp = sclk / sumo_get_sleep_divider_from_id(i);
1124                 if (temp >= min || i == 0)
1125                         break;
1126         }
1127
1128         return (u8)i;
1129 }
1130
1131 static u32 trinity_get_valid_engine_clock(struct radeon_device *rdev,
1132                                           u32 lower_limit)
1133 {
1134         struct trinity_power_info *pi = trinity_get_pi(rdev);
1135         u32 i;
1136
1137         for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
1138                 if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
1139                         return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
1140         }
1141
1142         if (i == pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries)
1143                 DRM_ERROR("engine clock out of range!");
1144
1145         return 0;
1146 }
1147
1148 static void trinity_patch_thermal_state(struct radeon_device *rdev,
1149                                         struct trinity_ps *ps,
1150                                         struct trinity_ps *current_ps)
1151 {
1152         struct trinity_power_info *pi = trinity_get_pi(rdev);
1153         u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
1154         u32 current_vddc;
1155         u32 current_sclk;
1156         u32 current_index = 0;
1157
1158         if (current_ps) {
1159                 current_vddc = current_ps->levels[current_index].vddc_index;
1160                 current_sclk = current_ps->levels[current_index].sclk;
1161         } else {
1162                 current_vddc = pi->boot_pl.vddc_index;
1163                 current_sclk = pi->boot_pl.sclk;
1164         }
1165
1166         ps->levels[0].vddc_index = current_vddc;
1167
1168         if (ps->levels[0].sclk > current_sclk)
1169                 ps->levels[0].sclk = current_sclk;
1170
1171         ps->levels[0].ds_divider_index =
1172                 trinity_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
1173         ps->levels[0].ss_divider_index = ps->levels[0].ds_divider_index;
1174         ps->levels[0].allow_gnb_slow = 1;
1175         ps->levels[0].force_nbp_state = 0;
1176         ps->levels[0].display_wm = 0;
1177         ps->levels[0].vce_wm =
1178                 trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
1179 }
1180
1181 static u8 trinity_calculate_display_wm(struct radeon_device *rdev,
1182                                        struct trinity_ps *ps, u32 index)
1183 {
1184         if (ps == NULL || ps->num_levels <= 1)
1185                 return 0;
1186         else if (ps->num_levels == 2) {
1187                 if (index == 0)
1188                         return 0;
1189                 else
1190                         return 1;
1191         } else {
1192                 if (index == 0)
1193                         return 0;
1194                 else if (ps->levels[index].sclk < 30000)
1195                         return 0;
1196                 else
1197                         return 1;
1198         }
1199 }
1200
1201 static void trinity_apply_state_adjust_rules(struct radeon_device *rdev)
1202 {
1203         struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
1204         struct trinity_ps *ps = trinity_get_ps(rps);
1205         struct trinity_ps *current_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
1206         struct trinity_power_info *pi = trinity_get_pi(rdev);
1207         u32 min_voltage = 0; /* ??? */
1208         u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
1209         u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
1210         u32 i;
1211         bool force_high;
1212         u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
1213
1214         if (rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
1215                 return trinity_patch_thermal_state(rdev, ps, current_ps);
1216
1217         for (i = 0; i < ps->num_levels; i++) {
1218                 if (ps->levels[i].vddc_index < min_voltage)
1219                         ps->levels[i].vddc_index = min_voltage;
1220
1221                 if (ps->levels[i].sclk < min_sclk)
1222                         ps->levels[i].sclk =
1223                                 trinity_get_valid_engine_clock(rdev, min_sclk);
1224
1225                 ps->levels[i].ds_divider_index =
1226                         sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
1227
1228                 ps->levels[i].ss_divider_index = ps->levels[i].ds_divider_index;
1229
1230                 ps->levels[i].allow_gnb_slow = 1;
1231                 ps->levels[i].force_nbp_state = 0;
1232                 ps->levels[i].display_wm =
1233                         trinity_calculate_display_wm(rdev, ps, i);
1234                 ps->levels[i].vce_wm =
1235                         trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
1236         }
1237
1238         if ((rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
1239             ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY))
1240                 ps->bapm_flags |= TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE;
1241
1242         if (pi->sys_info.nb_dpm_enable) {
1243                 ps->Dpm0PgNbPsLo = 0x1;
1244                 ps->Dpm0PgNbPsHi = 0x0;
1245                 ps->DpmXNbPsLo = 0x2;
1246                 ps->DpmXNbPsHi = 0x1;
1247
1248                 if ((rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
1249                     ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) {
1250                         force_high = ((rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ||
1251                                       ((rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) &&
1252                                        (pi->sys_info.uma_channel_number == 1)));
1253                         force_high = (num_active_displays >= 3) || force_high;
1254                         ps->Dpm0PgNbPsLo = force_high ? 0x2 : 0x3;
1255                         ps->Dpm0PgNbPsHi = 0x1;
1256                         ps->DpmXNbPsLo = force_high ? 0x2 : 0x3;
1257                         ps->DpmXNbPsHi = 0x2;
1258                         ps->levels[ps->num_levels - 1].allow_gnb_slow = 0;
1259                 }
1260         }
1261 }
1262
1263 static void trinity_cleanup_asic(struct radeon_device *rdev)
1264 {
1265         sumo_take_smu_control(rdev, false);
1266 }
1267
1268 #if 0
1269 static void trinity_pre_display_configuration_change(struct radeon_device *rdev)
1270 {
1271         struct trinity_power_info *pi = trinity_get_pi(rdev);
1272
1273         if (pi->voltage_drop_in_dce)
1274                 trinity_dce_enable_voltage_adjustment(rdev, false);
1275 }
1276 #endif
1277
1278 static void trinity_add_dccac_value(struct radeon_device *rdev)
1279 {
1280         u32 gpu_cac_avrg_cntl_window_size;
1281         u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
1282         u64 disp_clk = rdev->clock.default_dispclk / 100;
1283         u32 dc_cac_value;
1284
1285         gpu_cac_avrg_cntl_window_size =
1286                 (RREG32_SMC(GPU_CAC_AVRG_CNTL) & WINDOW_SIZE_MASK) >> WINDOW_SIZE_SHIFT;
1287
1288         dc_cac_value = (u32)((14213 * disp_clk * disp_clk * (u64)num_active_displays) >>
1289                              (32 - gpu_cac_avrg_cntl_window_size));
1290
1291         WREG32_SMC(DC_CAC_VALUE, dc_cac_value);
1292 }
1293
1294 void trinity_dpm_display_configuration_changed(struct radeon_device *rdev)
1295 {
1296         struct trinity_power_info *pi = trinity_get_pi(rdev);
1297
1298         if (pi->voltage_drop_in_dce)
1299                 trinity_dce_enable_voltage_adjustment(rdev, true);
1300         trinity_add_dccac_value(rdev);
1301 }
1302
1303 union power_info {
1304         struct _ATOM_POWERPLAY_INFO info;
1305         struct _ATOM_POWERPLAY_INFO_V2 info_2;
1306         struct _ATOM_POWERPLAY_INFO_V3 info_3;
1307         struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
1308         struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
1309         struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
1310 };
1311
1312 union pplib_clock_info {
1313         struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
1314         struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
1315         struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
1316         struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
1317 };
1318
1319 union pplib_power_state {
1320         struct _ATOM_PPLIB_STATE v1;
1321         struct _ATOM_PPLIB_STATE_V2 v2;
1322 };
1323
1324 static void trinity_parse_pplib_non_clock_info(struct radeon_device *rdev,
1325                                                struct radeon_ps *rps,
1326                                                struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
1327                                                u8 table_rev)
1328 {
1329         struct trinity_ps *ps = trinity_get_ps(rps);
1330
1331         rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
1332         rps->class = le16_to_cpu(non_clock_info->usClassification);
1333         rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
1334
1335         if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
1336                 rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
1337                 rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
1338         } else {
1339                 rps->vclk = 0;
1340                 rps->dclk = 0;
1341         }
1342
1343         if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
1344                 rdev->pm.dpm.boot_ps = rps;
1345                 trinity_patch_boot_state(rdev, ps);
1346         }
1347         if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
1348                 rdev->pm.dpm.uvd_ps = rps;
1349 }
1350
1351 static void trinity_parse_pplib_clock_info(struct radeon_device *rdev,
1352                                            struct radeon_ps *rps, int index,
1353                                            union pplib_clock_info *clock_info)
1354 {
1355         struct trinity_power_info *pi = trinity_get_pi(rdev);
1356         struct trinity_ps *ps = trinity_get_ps(rps);
1357         struct trinity_pl *pl = &ps->levels[index];
1358         u32 sclk;
1359
1360         sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
1361         sclk |= clock_info->sumo.ucEngineClockHigh << 16;
1362         pl->sclk = sclk;
1363         pl->vddc_index = clock_info->sumo.vddcIndex;
1364
1365         ps->num_levels = index + 1;
1366
1367         if (pi->enable_sclk_ds) {
1368                 pl->ds_divider_index = 5;
1369                 pl->ss_divider_index = 5;
1370         }
1371 }
1372
1373 static int trinity_parse_power_table(struct radeon_device *rdev)
1374 {
1375         struct radeon_mode_info *mode_info = &rdev->mode_info;
1376         struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
1377         union pplib_power_state *power_state;
1378         int i, j, k, non_clock_array_index, clock_array_index;
1379         union pplib_clock_info *clock_info;
1380         struct _StateArray *state_array;
1381         struct _ClockInfoArray *clock_info_array;
1382         struct _NonClockInfoArray *non_clock_info_array;
1383         union power_info *power_info;
1384         int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
1385         u16 data_offset;
1386         u8 frev, crev;
1387         u8 *power_state_offset;
1388         struct sumo_ps *ps;
1389
1390         if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
1391                                    &frev, &crev, &data_offset))
1392                 return -EINVAL;
1393         power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
1394
1395         state_array = (struct _StateArray *)
1396                 (mode_info->atom_context->bios + data_offset +
1397                  le16_to_cpu(power_info->pplib.usStateArrayOffset));
1398         clock_info_array = (struct _ClockInfoArray *)
1399                 (mode_info->atom_context->bios + data_offset +
1400                  le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
1401         non_clock_info_array = (struct _NonClockInfoArray *)
1402                 (mode_info->atom_context->bios + data_offset +
1403                  le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
1404
1405         rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
1406                                   state_array->ucNumEntries, GFP_KERNEL);
1407         if (!rdev->pm.dpm.ps)
1408                 return -ENOMEM;
1409         power_state_offset = (u8 *)state_array->states;
1410         rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
1411         rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
1412         rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
1413         for (i = 0; i < state_array->ucNumEntries; i++) {
1414                 power_state = (union pplib_power_state *)power_state_offset;
1415                 non_clock_array_index = power_state->v2.nonClockInfoIndex;
1416                 non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
1417                         &non_clock_info_array->nonClockInfo[non_clock_array_index];
1418                 if (!rdev->pm.power_state[i].clock_info)
1419                         return -EINVAL;
1420                 ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
1421                 if (ps == NULL) {
1422                         kfree(rdev->pm.dpm.ps);
1423                         return -ENOMEM;
1424                 }
1425                 rdev->pm.dpm.ps[i].ps_priv = ps;
1426                 k = 0;
1427                 for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
1428                         clock_array_index = power_state->v2.clockInfoIndex[j];
1429                         if (clock_array_index >= clock_info_array->ucNumEntries)
1430                                 continue;
1431                         if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
1432                                 break;
1433                         clock_info = (union pplib_clock_info *)
1434                                 &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
1435                         trinity_parse_pplib_clock_info(rdev,
1436                                                        &rdev->pm.dpm.ps[i], k,
1437                                                        clock_info);
1438                         k++;
1439                 }
1440                 trinity_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
1441                                                    non_clock_info,
1442                                                    non_clock_info_array->ucEntrySize);
1443                 power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
1444         }
1445         rdev->pm.dpm.num_ps = state_array->ucNumEntries;
1446         return 0;
1447 }
1448
1449 union igp_info {
1450         struct _ATOM_INTEGRATED_SYSTEM_INFO info;
1451         struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
1452         struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
1453         struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
1454         struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
1455 };
1456
1457 static int trinity_parse_sys_info_table(struct radeon_device *rdev)
1458 {
1459         struct trinity_power_info *pi = trinity_get_pi(rdev);
1460         struct radeon_mode_info *mode_info = &rdev->mode_info;
1461         int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
1462         union igp_info *igp_info;
1463         u8 frev, crev;
1464         u16 data_offset;
1465         int i;
1466
1467         if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1468                                    &frev, &crev, &data_offset)) {
1469                 igp_info = (union igp_info *)(mode_info->atom_context->bios +
1470                                               data_offset);
1471
1472                 if (crev != 7) {
1473                         DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
1474                         return -EINVAL;
1475                 }
1476                 pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock);
1477                 pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock);
1478                 pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock);
1479                 pi->sys_info.bootup_nb_voltage_index =
1480                         le16_to_cpu(igp_info->info_7.usBootUpNBVoltage);
1481                 if (igp_info->info_7.ucHtcTmpLmt == 0)
1482                         pi->sys_info.htc_tmp_lmt = 203;
1483                 else
1484                         pi->sys_info.htc_tmp_lmt = igp_info->info_7.ucHtcTmpLmt;
1485                 if (igp_info->info_7.ucHtcHystLmt == 0)
1486                         pi->sys_info.htc_hyst_lmt = 5;
1487                 else
1488                         pi->sys_info.htc_hyst_lmt = igp_info->info_7.ucHtcHystLmt;
1489                 if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
1490                         DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
1491                 }
1492
1493                 if (pi->enable_nbps_policy)
1494                         pi->sys_info.nb_dpm_enable = igp_info->info_7.ucNBDPMEnable;
1495                 else
1496                         pi->sys_info.nb_dpm_enable = 0;
1497
1498                 for (i = 0; i < TRINITY_NUM_NBPSTATES; i++) {
1499                         pi->sys_info.nbp_mclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateMemclkFreq[i]);
1500                         pi->sys_info.nbp_nclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateNClkFreq[i]);
1501                 }
1502
1503                 pi->sys_info.nbp_voltage_index[0] = le16_to_cpu(igp_info->info_7.usNBP0Voltage);
1504                 pi->sys_info.nbp_voltage_index[1] = le16_to_cpu(igp_info->info_7.usNBP1Voltage);
1505                 pi->sys_info.nbp_voltage_index[2] = le16_to_cpu(igp_info->info_7.usNBP2Voltage);
1506                 pi->sys_info.nbp_voltage_index[3] = le16_to_cpu(igp_info->info_7.usNBP3Voltage);
1507
1508                 if (!pi->sys_info.nb_dpm_enable) {
1509                         for (i = 1; i < TRINITY_NUM_NBPSTATES; i++) {
1510                                 pi->sys_info.nbp_mclk[i] = pi->sys_info.nbp_mclk[0];
1511                                 pi->sys_info.nbp_nclk[i] = pi->sys_info.nbp_nclk[0];
1512                                 pi->sys_info.nbp_voltage_index[i] = pi->sys_info.nbp_voltage_index[0];
1513                         }
1514                 }
1515
1516                 pi->sys_info.uma_channel_number = igp_info->info_7.ucUMAChannelNumber;
1517
1518                 sumo_construct_sclk_voltage_mapping_table(rdev,
1519                                                           &pi->sys_info.sclk_voltage_mapping_table,
1520                                                           igp_info->info_7.sAvail_SCLK);
1521                 sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
1522                                                  igp_info->info_7.sAvail_SCLK);
1523
1524         }
1525         return 0;
1526 }
1527
1528 int trinity_dpm_init(struct radeon_device *rdev)
1529 {
1530         struct trinity_power_info *pi;
1531         int ret, i;
1532
1533         pi = kzalloc(sizeof(struct trinity_power_info), GFP_KERNEL);
1534         if (pi == NULL)
1535                 return -ENOMEM;
1536         rdev->pm.dpm.priv = pi;
1537
1538         for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
1539                 pi->at[i] = TRINITY_AT_DFLT;
1540
1541         pi->enable_nbps_policy = true;
1542         pi->enable_sclk_ds = true;
1543         pi->enable_gfx_power_gating = true;
1544         pi->enable_gfx_clock_gating = true;
1545         pi->enable_mg_clock_gating = true;
1546         pi->enable_gfx_dynamic_mgpg = true; /* ??? */
1547         pi->override_dynamic_mgpg = true;
1548         pi->enable_auto_thermal_throttling = true;
1549         pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
1550
1551         ret = trinity_parse_sys_info_table(rdev);
1552         if (ret)
1553                 return ret;
1554
1555         trinity_construct_boot_state(rdev);
1556
1557         ret = trinity_parse_power_table(rdev);
1558         if (ret)
1559                 return ret;
1560
1561         pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
1562         pi->enable_dpm = true;
1563
1564         return 0;
1565 }
1566
1567 void trinity_dpm_print_power_state(struct radeon_device *rdev,
1568                                    struct radeon_ps *rps)
1569 {
1570         int i;
1571         struct trinity_ps *ps = trinity_get_ps(rps);
1572
1573         r600_dpm_print_class_info(rps->class, rps->class2);
1574         r600_dpm_print_cap_info(rps->caps);
1575         printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
1576         for (i = 0; i < ps->num_levels; i++) {
1577                 struct trinity_pl *pl = &ps->levels[i];
1578                 printk("\t\tpower level %d    sclk: %u vddc: %u\n",
1579                        i, pl->sclk,
1580                        trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
1581         }
1582         r600_dpm_print_ps_status(rdev, rps);
1583 }
1584
1585 void trinity_dpm_fini(struct radeon_device *rdev)
1586 {
1587         int i;
1588
1589         trinity_cleanup_asic(rdev); /* ??? */
1590
1591         for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
1592                 kfree(rdev->pm.dpm.ps[i].ps_priv);
1593         }
1594         kfree(rdev->pm.dpm.ps);
1595         kfree(rdev->pm.dpm.priv);
1596 }
1597
1598 u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
1599 {
1600         struct trinity_ps *requested_state = trinity_get_ps(rdev->pm.dpm.requested_ps);
1601
1602         if (low)
1603                 return requested_state->levels[0].sclk;
1604         else
1605                 return requested_state->levels[requested_state->num_levels - 1].sclk;
1606 }
1607
1608 u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low)
1609 {
1610         struct trinity_power_info *pi = trinity_get_pi(rdev);
1611
1612         return pi->sys_info.bootup_uma_clk;
1613 }