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