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