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