]> rtime.felk.cvut.cz Git - linux-imx.git/blob - drivers/gpu/drm/radeon/trinity_dpm.c
drm/radeon/dpm/trinity: properly catch errors in dpm setup
[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                                              struct radeon_ps *new_rps,
342                                              struct radeon_ps *old_rps);
343
344 struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
345 {
346         struct trinity_ps *ps = rps->ps_priv;
347
348         return ps;
349 }
350
351 struct 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
358 static 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;
364         u32 xclk = radeon_get_xclk(rdev);
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
398 static 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
427 static 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
438 static 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
451 static 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
460 static 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
470 static 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
481 static 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
498 static 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
512 static 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
541 static 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
563 static 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
579 static 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
608 static 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
620 static 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
632 static 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
650 static 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
662 static 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
674 static 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
686 static 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
698 static 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
710 static 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
729 static 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
742 static 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
750 static 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
764 static 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
785 static 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
798 static void trinity_start_am(struct radeon_device *rdev)
799 {
800         WREG32_P(SCLK_PWRMGT_CNTL, 0, ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
801 }
802
803 static 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
809 static 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
820 static void trinity_enable_power_level_0(struct radeon_device *rdev)
821 {
822         trinity_power_level_enable_disable(rdev, 0, true);
823 }
824
825 static void trinity_force_level_0(struct radeon_device *rdev)
826 {
827         trinity_dpm_force_state(rdev, 0);
828 }
829
830 static void trinity_unforce_levels(struct radeon_device *rdev)
831 {
832         trinity_dpm_no_forced_level(rdev);
833 }
834
835 static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev,
836                                                 struct radeon_ps *new_rps,
837                                                 struct radeon_ps *old_rps)
838 {
839         struct trinity_ps *new_ps = trinity_get_ps(new_rps);
840         struct trinity_ps *old_ps = trinity_get_ps(old_rps);
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
853 static 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
865 static 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
877 static 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;
883         u32 xclk = radeon_get_xclk(rdev);
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
892 static 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
900 static 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
917 static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
918                                      struct radeon_ps *new_rps,
919                                      struct radeon_ps *old_rps)
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) &&
925                     !trinity_uvd_clocks_zero(old_rps)) {
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
930                         if (trinity_uvd_clocks_zero(old_rps)) {
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) ||
943                     trinity_uvd_clocks_equal(new_rps, old_rps))
944                         return;
945
946                 radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
947         }
948 }
949
950 static 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)
953 {
954         struct trinity_ps *new_ps = trinity_get_ps(new_rps);
955         struct trinity_ps *current_ps = trinity_get_ps(new_rps);
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
961         trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
962 }
963
964 static 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)
967 {
968         struct trinity_ps *new_ps = trinity_get_ps(new_rps);
969         struct trinity_ps *current_ps = trinity_get_ps(old_rps);
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
975         trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
976 }
977
978 static 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
989 static 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
998 static void trinity_program_sclk_dpm(struct radeon_device *rdev)
999 {
1000         u32 p, u;
1001         u32 tp = RREG32_SMC(PM_TP);
1002         u32 ni;
1003         u32 xclk = radeon_get_xclk(rdev);
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
1016 static 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
1040 static 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
1051 static 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
1062 int trinity_dpm_enable(struct radeon_device *rdev)
1063 {
1064         struct trinity_power_info *pi = trinity_get_pi(rdev);
1065         int ret;
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)) {
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                 }
1094                 rdev->irq.dpm_thermal = true;
1095                 radeon_irq_set(rdev);
1096         }
1097
1098         trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
1099
1100         return 0;
1101 }
1102
1103 void 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         }
1122
1123         trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
1124 }
1125
1126 static 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
1134 static void trinity_setup_nbp_sim(struct radeon_device *rdev,
1135                                   struct radeon_ps *rps)
1136 {
1137         struct trinity_power_info *pi = trinity_get_pi(rdev);
1138         struct trinity_ps *new_ps = trinity_get_ps(rps);
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
1152 int trinity_dpm_pre_set_power_state(struct radeon_device *rdev)
1153 {
1154         struct trinity_power_info *pi = trinity_get_pi(rdev);
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);
1159
1160         trinity_apply_state_adjust_rules(rdev,
1161                                          &pi->requested_rps,
1162                                          &pi->current_rps);
1163
1164         return 0;
1165 }
1166
1167 int 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;
1172
1173         trinity_acquire_mutex(rdev);
1174         if (pi->enable_dpm) {
1175                 trinity_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
1176                 trinity_enable_power_level_0(rdev);
1177                 trinity_force_level_0(rdev);
1178                 trinity_wait_for_level_0(rdev);
1179                 trinity_setup_nbp_sim(rdev, new_ps);
1180                 trinity_program_power_levels_0_to_n(rdev, new_ps, old_ps);
1181                 trinity_force_level_0(rdev);
1182                 trinity_unforce_levels(rdev);
1183                 trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
1184         }
1185         trinity_release_mutex(rdev);
1186
1187         return 0;
1188 }
1189
1190 void 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
1198 void 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
1207 void 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
1223 static 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
1238 static 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
1249 static u8 trinity_calculate_vce_wm(struct radeon_device *rdev, u32 sclk)
1250 {
1251         if (sclk < 20000)
1252                 return 1;
1253         return 0;
1254 }
1255
1256 static 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
1272 static 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
1296 static 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
1313 static 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
1346 static 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
1366 static 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
1385 static 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
1421 static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
1422                                              struct radeon_ps *new_rps,
1423                                              struct radeon_ps *old_rps)
1424 {
1425         struct trinity_ps *ps = trinity_get_ps(new_rps);
1426         struct trinity_ps *current_ps = trinity_get_ps(old_rps);
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
1435         if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
1436                 return trinity_patch_thermal_state(rdev, ps, current_ps);
1437
1438         trinity_adjust_uvd_state(rdev, new_rps);
1439
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
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))
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
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) &&
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
1486 static void trinity_cleanup_asic(struct radeon_device *rdev)
1487 {
1488         sumo_take_smu_control(rdev, false);
1489 }
1490
1491 #if 0
1492 static 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
1501 static 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
1517 void 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
1526 union 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
1535 union 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
1542 union pplib_power_state {
1543         struct _ATOM_PPLIB_STATE v1;
1544         struct _ATOM_PPLIB_STATE_V2 v2;
1545 };
1546
1547 static 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
1574 static 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
1596 static 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
1672 union 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
1680 static 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
1699 static 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);
1721                 pi->sys_info.dentist_vco_freq = le32_to_cpu(igp_info->info_7.ulDentistVCOFreq);
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
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
1796         }
1797         return 0;
1798 }
1799
1800 int 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 */
1822         pi->uvd_dpm = true; /* ??? */
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
1840 void 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
1858 void 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
1871 u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
1872 {
1873         struct trinity_power_info *pi = trinity_get_pi(rdev);
1874         struct trinity_ps *requested_state = trinity_get_ps(&pi->requested_rps);
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
1882 u32 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 }