1d70229f7SAlex Deucher /*
2d70229f7SAlex Deucher  * Copyright 2012 Advanced Micro Devices, Inc.
3d70229f7SAlex Deucher  *
4d70229f7SAlex Deucher  * Permission is hereby granted, free of charge, to any person obtaining a
5d70229f7SAlex Deucher  * copy of this software and associated documentation files (the "Software"),
6d70229f7SAlex Deucher  * to deal in the Software without restriction, including without limitation
7d70229f7SAlex Deucher  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8d70229f7SAlex Deucher  * and/or sell copies of the Software, and to permit persons to whom the
9d70229f7SAlex Deucher  * Software is furnished to do so, subject to the following conditions:
10d70229f7SAlex Deucher  *
11d70229f7SAlex Deucher  * The above copyright notice and this permission notice shall be included in
12d70229f7SAlex Deucher  * all copies or substantial portions of the Software.
13d70229f7SAlex Deucher  *
14d70229f7SAlex Deucher  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15d70229f7SAlex Deucher  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16d70229f7SAlex Deucher  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17d70229f7SAlex Deucher  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18d70229f7SAlex Deucher  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19d70229f7SAlex Deucher  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20d70229f7SAlex Deucher  * OTHER DEALINGS IN THE SOFTWARE.
21d70229f7SAlex Deucher  *
22d70229f7SAlex Deucher  */
23d70229f7SAlex Deucher 
242ef79416SThomas Zimmermann #include <linux/pci.h>
25c182615fSSam Ravnborg #include <linux/seq_file.h>
26c182615fSSam Ravnborg 
27c182615fSSam Ravnborg #include "r600_dpm.h"
28d70229f7SAlex Deucher #include "radeon.h"
2901467a9bSMichele Curti #include "radeon_asic.h"
30d70229f7SAlex Deucher #include "trinity_dpm.h"
31c182615fSSam Ravnborg #include "trinityd.h"
32adfc56d5SLee Jones #include "vce.h"
33d70229f7SAlex Deucher 
34d70229f7SAlex Deucher #define TRINITY_MAX_DEEPSLEEP_DIVIDER_ID 5
35d70229f7SAlex Deucher #define TRINITY_MINIMUM_ENGINE_CLOCK 800
36d70229f7SAlex Deucher #define SCLK_MIN_DIV_INTV_SHIFT     12
37d70229f7SAlex Deucher #define TRINITY_DISPCLK_BYPASS_THRESHOLD 10000
38d70229f7SAlex Deucher 
39d70229f7SAlex Deucher #ifndef TRINITY_MGCG_SEQUENCE
40d70229f7SAlex Deucher #define TRINITY_MGCG_SEQUENCE  100
41d70229f7SAlex Deucher 
42d70229f7SAlex Deucher static const u32 trinity_mgcg_shls_default[] =
43d70229f7SAlex Deucher {
44d70229f7SAlex Deucher 	/* Register, Value, Mask */
45d70229f7SAlex Deucher 	0x0000802c, 0xc0000000, 0xffffffff,
46d70229f7SAlex Deucher 	0x00003fc4, 0xc0000000, 0xffffffff,
47d70229f7SAlex Deucher 	0x00005448, 0x00000100, 0xffffffff,
48d70229f7SAlex Deucher 	0x000055e4, 0x00000100, 0xffffffff,
49d70229f7SAlex Deucher 	0x0000160c, 0x00000100, 0xffffffff,
50d70229f7SAlex Deucher 	0x00008984, 0x06000100, 0xffffffff,
51d70229f7SAlex Deucher 	0x0000c164, 0x00000100, 0xffffffff,
52d70229f7SAlex Deucher 	0x00008a18, 0x00000100, 0xffffffff,
53d70229f7SAlex Deucher 	0x0000897c, 0x06000100, 0xffffffff,
54d70229f7SAlex Deucher 	0x00008b28, 0x00000100, 0xffffffff,
55d70229f7SAlex Deucher 	0x00009144, 0x00800200, 0xffffffff,
56d70229f7SAlex Deucher 	0x00009a60, 0x00000100, 0xffffffff,
57d70229f7SAlex Deucher 	0x00009868, 0x00000100, 0xffffffff,
58d70229f7SAlex Deucher 	0x00008d58, 0x00000100, 0xffffffff,
59d70229f7SAlex Deucher 	0x00009510, 0x00000100, 0xffffffff,
60d70229f7SAlex Deucher 	0x0000949c, 0x00000100, 0xffffffff,
61d70229f7SAlex Deucher 	0x00009654, 0x00000100, 0xffffffff,
62d70229f7SAlex Deucher 	0x00009030, 0x00000100, 0xffffffff,
63d70229f7SAlex Deucher 	0x00009034, 0x00000100, 0xffffffff,
64d70229f7SAlex Deucher 	0x00009038, 0x00000100, 0xffffffff,
65d70229f7SAlex Deucher 	0x0000903c, 0x00000100, 0xffffffff,
66d70229f7SAlex Deucher 	0x00009040, 0x00000100, 0xffffffff,
67d70229f7SAlex Deucher 	0x0000a200, 0x00000100, 0xffffffff,
68d70229f7SAlex Deucher 	0x0000a204, 0x00000100, 0xffffffff,
69d70229f7SAlex Deucher 	0x0000a208, 0x00000100, 0xffffffff,
70d70229f7SAlex Deucher 	0x0000a20c, 0x00000100, 0xffffffff,
71d70229f7SAlex Deucher 	0x00009744, 0x00000100, 0xffffffff,
72d70229f7SAlex Deucher 	0x00003f80, 0x00000100, 0xffffffff,
73d70229f7SAlex Deucher 	0x0000a210, 0x00000100, 0xffffffff,
74d70229f7SAlex Deucher 	0x0000a214, 0x00000100, 0xffffffff,
75d70229f7SAlex Deucher 	0x000004d8, 0x00000100, 0xffffffff,
76d70229f7SAlex Deucher 	0x00009664, 0x00000100, 0xffffffff,
77d70229f7SAlex Deucher 	0x00009698, 0x00000100, 0xffffffff,
78d70229f7SAlex Deucher 	0x000004d4, 0x00000200, 0xffffffff,
79d70229f7SAlex Deucher 	0x000004d0, 0x00000000, 0xffffffff,
80d70229f7SAlex Deucher 	0x000030cc, 0x00000104, 0xffffffff,
81d70229f7SAlex Deucher 	0x0000d0c0, 0x00000100, 0xffffffff,
82d70229f7SAlex Deucher 	0x0000d8c0, 0x00000100, 0xffffffff,
83d70229f7SAlex Deucher 	0x0000951c, 0x00010000, 0xffffffff,
84d70229f7SAlex Deucher 	0x00009160, 0x00030002, 0xffffffff,
85d70229f7SAlex Deucher 	0x00009164, 0x00050004, 0xffffffff,
86d70229f7SAlex Deucher 	0x00009168, 0x00070006, 0xffffffff,
87d70229f7SAlex Deucher 	0x00009178, 0x00070000, 0xffffffff,
88d70229f7SAlex Deucher 	0x0000917c, 0x00030002, 0xffffffff,
89d70229f7SAlex Deucher 	0x00009180, 0x00050004, 0xffffffff,
90d70229f7SAlex Deucher 	0x0000918c, 0x00010006, 0xffffffff,
91d70229f7SAlex Deucher 	0x00009190, 0x00090008, 0xffffffff,
92d70229f7SAlex Deucher 	0x00009194, 0x00070000, 0xffffffff,
93d70229f7SAlex Deucher 	0x00009198, 0x00030002, 0xffffffff,
94d70229f7SAlex Deucher 	0x0000919c, 0x00050004, 0xffffffff,
95d70229f7SAlex Deucher 	0x000091a8, 0x00010006, 0xffffffff,
96d70229f7SAlex Deucher 	0x000091ac, 0x00090008, 0xffffffff,
97d70229f7SAlex Deucher 	0x000091b0, 0x00070000, 0xffffffff,
98d70229f7SAlex Deucher 	0x000091b4, 0x00030002, 0xffffffff,
99d70229f7SAlex Deucher 	0x000091b8, 0x00050004, 0xffffffff,
100d70229f7SAlex Deucher 	0x000091c4, 0x00010006, 0xffffffff,
101d70229f7SAlex Deucher 	0x000091c8, 0x00090008, 0xffffffff,
102d70229f7SAlex Deucher 	0x000091cc, 0x00070000, 0xffffffff,
103d70229f7SAlex Deucher 	0x000091d0, 0x00030002, 0xffffffff,
104d70229f7SAlex Deucher 	0x000091d4, 0x00050004, 0xffffffff,
105d70229f7SAlex Deucher 	0x000091e0, 0x00010006, 0xffffffff,
106d70229f7SAlex Deucher 	0x000091e4, 0x00090008, 0xffffffff,
107d70229f7SAlex Deucher 	0x000091e8, 0x00000000, 0xffffffff,
108d70229f7SAlex Deucher 	0x000091ec, 0x00070000, 0xffffffff,
109d70229f7SAlex Deucher 	0x000091f0, 0x00030002, 0xffffffff,
110d70229f7SAlex Deucher 	0x000091f4, 0x00050004, 0xffffffff,
111d70229f7SAlex Deucher 	0x00009200, 0x00010006, 0xffffffff,
112d70229f7SAlex Deucher 	0x00009204, 0x00090008, 0xffffffff,
113d70229f7SAlex Deucher 	0x00009208, 0x00070000, 0xffffffff,
114d70229f7SAlex Deucher 	0x0000920c, 0x00030002, 0xffffffff,
115d70229f7SAlex Deucher 	0x00009210, 0x00050004, 0xffffffff,
116d70229f7SAlex Deucher 	0x0000921c, 0x00010006, 0xffffffff,
117d70229f7SAlex Deucher 	0x00009220, 0x00090008, 0xffffffff,
118d70229f7SAlex Deucher 	0x00009294, 0x00000000, 0xffffffff
119d70229f7SAlex Deucher };
120d70229f7SAlex Deucher #endif
121d70229f7SAlex Deucher 
122d70229f7SAlex Deucher #ifndef TRINITY_SYSLS_SEQUENCE
123d70229f7SAlex Deucher #define TRINITY_SYSLS_SEQUENCE  100
124d70229f7SAlex Deucher 
125d70229f7SAlex Deucher static const u32 trinity_sysls_disable[] =
126d70229f7SAlex Deucher {
127d70229f7SAlex Deucher 	/* Register, Value, Mask */
128d70229f7SAlex Deucher 	0x0000d0c0, 0x00000000, 0xffffffff,
129d70229f7SAlex Deucher 	0x0000d8c0, 0x00000000, 0xffffffff,
130d70229f7SAlex Deucher 	0x000055e8, 0x00000000, 0xffffffff,
131d70229f7SAlex Deucher 	0x0000d0bc, 0x00000000, 0xffffffff,
132d70229f7SAlex Deucher 	0x0000d8bc, 0x00000000, 0xffffffff,
133d70229f7SAlex Deucher 	0x000015c0, 0x00041401, 0xffffffff,
134d70229f7SAlex Deucher 	0x0000264c, 0x00040400, 0xffffffff,
135d70229f7SAlex Deucher 	0x00002648, 0x00040400, 0xffffffff,
136d70229f7SAlex Deucher 	0x00002650, 0x00040400, 0xffffffff,
137d70229f7SAlex Deucher 	0x000020b8, 0x00040400, 0xffffffff,
138d70229f7SAlex Deucher 	0x000020bc, 0x00040400, 0xffffffff,
139d70229f7SAlex Deucher 	0x000020c0, 0x00040c80, 0xffffffff,
140d70229f7SAlex Deucher 	0x0000f4a0, 0x000000c0, 0xffffffff,
141d70229f7SAlex Deucher 	0x0000f4a4, 0x00680000, 0xffffffff,
142d70229f7SAlex Deucher 	0x00002f50, 0x00000404, 0xffffffff,
143d70229f7SAlex Deucher 	0x000004c8, 0x00000001, 0xffffffff,
144d70229f7SAlex Deucher 	0x0000641c, 0x00007ffd, 0xffffffff,
145d70229f7SAlex Deucher 	0x00000c7c, 0x0000ff00, 0xffffffff,
146d70229f7SAlex Deucher 	0x00006dfc, 0x0000007f, 0xffffffff
147d70229f7SAlex Deucher };
148d70229f7SAlex Deucher 
149d70229f7SAlex Deucher static const u32 trinity_sysls_enable[] =
150d70229f7SAlex Deucher {
151d70229f7SAlex Deucher 	/* Register, Value, Mask */
152d70229f7SAlex Deucher 	0x000055e8, 0x00000001, 0xffffffff,
153d70229f7SAlex Deucher 	0x0000d0bc, 0x00000100, 0xffffffff,
154d70229f7SAlex Deucher 	0x0000d8bc, 0x00000100, 0xffffffff,
155d70229f7SAlex Deucher 	0x000015c0, 0x000c1401, 0xffffffff,
156d70229f7SAlex Deucher 	0x0000264c, 0x000c0400, 0xffffffff,
157d70229f7SAlex Deucher 	0x00002648, 0x000c0400, 0xffffffff,
158d70229f7SAlex Deucher 	0x00002650, 0x000c0400, 0xffffffff,
159d70229f7SAlex Deucher 	0x000020b8, 0x000c0400, 0xffffffff,
160d70229f7SAlex Deucher 	0x000020bc, 0x000c0400, 0xffffffff,
161d70229f7SAlex Deucher 	0x000020c0, 0x000c0c80, 0xffffffff,
162d70229f7SAlex Deucher 	0x0000f4a0, 0x000000c0, 0xffffffff,
163d70229f7SAlex Deucher 	0x0000f4a4, 0x00680fff, 0xffffffff,
164d70229f7SAlex Deucher 	0x00002f50, 0x00000903, 0xffffffff,
165d70229f7SAlex Deucher 	0x000004c8, 0x00000000, 0xffffffff,
166d70229f7SAlex Deucher 	0x0000641c, 0x00000000, 0xffffffff,
167d70229f7SAlex Deucher 	0x00000c7c, 0x00000000, 0xffffffff,
168d70229f7SAlex Deucher 	0x00006dfc, 0x00000000, 0xffffffff
169d70229f7SAlex Deucher };
170d70229f7SAlex Deucher #endif
171d70229f7SAlex Deucher 
172d70229f7SAlex Deucher static const u32 trinity_override_mgpg_sequences[] =
173d70229f7SAlex Deucher {
174d70229f7SAlex Deucher 	/* Register, Value */
175d70229f7SAlex Deucher 	0x00000200, 0xE030032C,
176d70229f7SAlex Deucher 	0x00000204, 0x00000FFF,
177d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
178d70229f7SAlex Deucher 	0x00000204, 0x00030301,
179d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
180d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
181d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
182d70229f7SAlex Deucher 	0x00000204, 0x00030301,
183d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
184d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
185d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
186d70229f7SAlex Deucher 	0x00000204, 0x00030301,
187d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
188d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
189d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
190d70229f7SAlex Deucher 	0x00000204, 0x00030301,
191d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
192d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
193d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
194d70229f7SAlex Deucher 	0x00000204, 0x00030301,
195d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
196d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
197d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
198d70229f7SAlex Deucher 	0x00000204, 0x00030301,
199d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
200d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
201d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
202d70229f7SAlex Deucher 	0x00000204, 0x00030301,
203d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
204d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
205d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
206d70229f7SAlex Deucher 	0x00000204, 0x00030303,
207d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
208d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
209d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
210d70229f7SAlex Deucher 	0x00000204, 0x00030303,
211d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
212d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
213d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
214d70229f7SAlex Deucher 	0x00000204, 0x00030303,
215d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
216d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
217d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
218d70229f7SAlex Deucher 	0x00000204, 0x00030303,
219d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
220d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
221d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
222d70229f7SAlex Deucher 	0x00000204, 0x00030303,
223d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
224d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
225d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
226d70229f7SAlex Deucher 	0x00000204, 0x00030303,
227d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
228d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
229d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
230d70229f7SAlex Deucher 	0x00000204, 0x00030303,
231d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
232d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
233d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
234d70229f7SAlex Deucher 	0x00000204, 0x00030303,
235d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
236d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
237d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
238d70229f7SAlex Deucher 	0x00000204, 0x00030303,
239d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
240d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
241d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
242d70229f7SAlex Deucher 	0x00000204, 0x00030303,
243d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
244d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
245d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
246d70229f7SAlex Deucher 	0x00000204, 0x00030303,
247d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
248d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
249d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
250d70229f7SAlex Deucher 	0x00000204, 0x00030303,
251d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
252d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
253d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
254d70229f7SAlex Deucher 	0x00000204, 0x00030303,
255d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
256d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
257d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
258d70229f7SAlex Deucher 	0x00000204, 0x00030303,
259d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
260d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
261d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
262d70229f7SAlex Deucher 	0x00000204, 0x00010303,
263d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
264d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
265d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
266d70229f7SAlex Deucher 	0x00000204, 0x00010303,
267d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
268d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
269d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
270d70229f7SAlex Deucher 	0x00000204, 0x00010303,
271d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
272d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
273d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
274d70229f7SAlex Deucher 	0x00000204, 0x00010303,
275d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
276d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
277d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
278d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
279d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
280d70229f7SAlex Deucher 	0x00000204, 0x00010303,
281d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
282d70229f7SAlex Deucher 	0x00000204, 0x00010303,
283d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
284d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
285d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
286d70229f7SAlex Deucher 	0x00000204, 0x00010303,
287d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
288d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
289d70229f7SAlex Deucher 	0x00000200, 0x0001f198,
290d70229f7SAlex Deucher 	0x00000204, 0x0003ffff,
291d70229f7SAlex Deucher 	0x00000200, 0x0001f19C,
292d70229f7SAlex Deucher 	0x00000204, 0x3fffffff,
293d70229f7SAlex Deucher 	0x00000200, 0xE030032C,
294d70229f7SAlex Deucher 	0x00000204, 0x00000000,
295d70229f7SAlex Deucher };
296d70229f7SAlex Deucher 
297d70229f7SAlex Deucher static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
298d70229f7SAlex Deucher 						   const u32 *seq, u32 count);
299d70229f7SAlex Deucher static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev);
300940eea8eSAlex Deucher static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
301940eea8eSAlex Deucher 					     struct radeon_ps *new_rps,
302940eea8eSAlex Deucher 					     struct radeon_ps *old_rps);
303d70229f7SAlex Deucher 
trinity_get_ps(struct radeon_ps * rps)304fbb74bceSAlex Deucher static struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
305d70229f7SAlex Deucher {
306d70229f7SAlex Deucher 	struct trinity_ps *ps = rps->ps_priv;
307d70229f7SAlex Deucher 
308d70229f7SAlex Deucher 	return ps;
309d70229f7SAlex Deucher }
310d70229f7SAlex Deucher 
trinity_get_pi(struct radeon_device * rdev)311fbb74bceSAlex Deucher static struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)
312d70229f7SAlex Deucher {
313d70229f7SAlex Deucher 	struct trinity_power_info *pi = rdev->pm.dpm.priv;
314d70229f7SAlex Deucher 
315d70229f7SAlex Deucher 	return pi;
316d70229f7SAlex Deucher }
317d70229f7SAlex Deucher 
trinity_gfx_powergating_initialize(struct radeon_device * rdev)318d70229f7SAlex Deucher static void trinity_gfx_powergating_initialize(struct radeon_device *rdev)
319d70229f7SAlex Deucher {
320d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
321d70229f7SAlex Deucher 	u32 p, u;
322d70229f7SAlex Deucher 	u32 value;
323d70229f7SAlex Deucher 	struct atom_clock_dividers dividers;
3249d45ad5aSAlex Deucher 	u32 xclk = radeon_get_xclk(rdev);
325d70229f7SAlex Deucher 	u32 sssd = 1;
326d70229f7SAlex Deucher 	int ret;
327d70229f7SAlex Deucher 	u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
328d70229f7SAlex Deucher 
329d70229f7SAlex Deucher 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
330d70229f7SAlex Deucher 					     25000, false, &dividers);
331d70229f7SAlex Deucher 	if (ret)
332d70229f7SAlex Deucher 		return;
333d70229f7SAlex Deucher 
334d70229f7SAlex Deucher 	value = RREG32_SMC(GFX_POWER_GATING_CNTL);
335d70229f7SAlex Deucher 	value &= ~(SSSD_MASK | PDS_DIV_MASK);
336d70229f7SAlex Deucher 	if (sssd)
337d70229f7SAlex Deucher 		value |= SSSD(1);
338d70229f7SAlex Deucher 	value |= PDS_DIV(dividers.post_div);
339d70229f7SAlex Deucher 	WREG32_SMC(GFX_POWER_GATING_CNTL, value);
340d70229f7SAlex Deucher 
341d70229f7SAlex Deucher 	r600_calculate_u_and_p(500, xclk, 16, &p, &u);
342d70229f7SAlex Deucher 
343d70229f7SAlex Deucher 	WREG32(CG_PG_CTRL, SP(p) | SU(u));
344d70229f7SAlex Deucher 
345d70229f7SAlex Deucher 	WREG32_P(CG_GIPOTS, CG_GIPOT(p), ~CG_GIPOT_MASK);
346d70229f7SAlex Deucher 
347d70229f7SAlex Deucher 	/* XXX double check hw_rev */
348d70229f7SAlex Deucher 	if (pi->override_dynamic_mgpg && (hw_rev == 0))
349d70229f7SAlex Deucher 		trinity_override_dynamic_mg_powergating(rdev);
350d70229f7SAlex Deucher 
351d70229f7SAlex Deucher }
352d70229f7SAlex Deucher 
353d70229f7SAlex Deucher #define CGCG_CGTT_LOCAL0_MASK       0xFFFF33FF
354d70229f7SAlex Deucher #define CGCG_CGTT_LOCAL1_MASK       0xFFFB0FFE
355d70229f7SAlex Deucher #define CGTS_SM_CTRL_REG_DISABLE    0x00600000
356d70229f7SAlex Deucher #define CGTS_SM_CTRL_REG_ENABLE     0x96944200
357d70229f7SAlex Deucher 
trinity_mg_clockgating_enable(struct radeon_device * rdev,bool enable)358d70229f7SAlex Deucher static void trinity_mg_clockgating_enable(struct radeon_device *rdev,
359d70229f7SAlex Deucher 					  bool enable)
360d70229f7SAlex Deucher {
361d70229f7SAlex Deucher 	u32 local0;
362d70229f7SAlex Deucher 	u32 local1;
363d70229f7SAlex Deucher 
364d70229f7SAlex Deucher 	if (enable) {
365d70229f7SAlex Deucher 		local0 = RREG32_CG(CG_CGTT_LOCAL_0);
366d70229f7SAlex Deucher 		local1 = RREG32_CG(CG_CGTT_LOCAL_1);
367d70229f7SAlex Deucher 
368d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_0,
369d70229f7SAlex Deucher 			  (0x00380000 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
370d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_1,
371d70229f7SAlex Deucher 			  (0x0E000000 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
372d70229f7SAlex Deucher 
373d70229f7SAlex Deucher 		WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_ENABLE);
374d70229f7SAlex Deucher 	} else {
375d70229f7SAlex Deucher 		WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_DISABLE);
376d70229f7SAlex Deucher 
377d70229f7SAlex Deucher 		local0 = RREG32_CG(CG_CGTT_LOCAL_0);
378d70229f7SAlex Deucher 		local1 = RREG32_CG(CG_CGTT_LOCAL_1);
379d70229f7SAlex Deucher 
380d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_0,
381d70229f7SAlex Deucher 			  CGCG_CGTT_LOCAL0_MASK | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
382d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_1,
383d70229f7SAlex Deucher 			  CGCG_CGTT_LOCAL1_MASK | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
384d70229f7SAlex Deucher 	}
385d70229f7SAlex Deucher }
386d70229f7SAlex Deucher 
trinity_mg_clockgating_initialize(struct radeon_device * rdev)387d70229f7SAlex Deucher static void trinity_mg_clockgating_initialize(struct radeon_device *rdev)
388d70229f7SAlex Deucher {
389d70229f7SAlex Deucher 	u32 count;
390d70229f7SAlex Deucher 	const u32 *seq = NULL;
391d70229f7SAlex Deucher 
392d70229f7SAlex Deucher 	seq = &trinity_mgcg_shls_default[0];
393d70229f7SAlex Deucher 	count = sizeof(trinity_mgcg_shls_default) / (3 * sizeof(u32));
394d70229f7SAlex Deucher 
395d70229f7SAlex Deucher 	trinity_program_clk_gating_hw_sequence(rdev, seq, count);
396d70229f7SAlex Deucher }
397d70229f7SAlex Deucher 
trinity_gfx_clockgating_enable(struct radeon_device * rdev,bool enable)398d70229f7SAlex Deucher static void trinity_gfx_clockgating_enable(struct radeon_device *rdev,
399d70229f7SAlex Deucher 					   bool enable)
400d70229f7SAlex Deucher {
401d70229f7SAlex Deucher 	if (enable) {
402d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
403d70229f7SAlex Deucher 	} else {
404d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
405d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
406d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
407d70229f7SAlex Deucher 		RREG32(GB_ADDR_CONFIG);
408d70229f7SAlex Deucher 	}
409d70229f7SAlex Deucher }
410d70229f7SAlex Deucher 
trinity_program_clk_gating_hw_sequence(struct radeon_device * rdev,const u32 * seq,u32 count)411d70229f7SAlex Deucher static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
412d70229f7SAlex Deucher 						   const u32 *seq, u32 count)
413d70229f7SAlex Deucher {
414d70229f7SAlex Deucher 	u32 i, length = count * 3;
415d70229f7SAlex Deucher 
416d70229f7SAlex Deucher 	for (i = 0; i < length; i += 3)
417d70229f7SAlex Deucher 		WREG32_P(seq[i], seq[i+1], ~seq[i+2]);
418d70229f7SAlex Deucher }
419d70229f7SAlex Deucher 
trinity_program_override_mgpg_sequences(struct radeon_device * rdev,const u32 * seq,u32 count)420d70229f7SAlex Deucher static void trinity_program_override_mgpg_sequences(struct radeon_device *rdev,
421d70229f7SAlex Deucher 						    const u32 *seq, u32 count)
422d70229f7SAlex Deucher {
423d70229f7SAlex Deucher 	u32  i, length = count * 2;
424d70229f7SAlex Deucher 
425d70229f7SAlex Deucher 	for (i = 0; i < length; i += 2)
426d70229f7SAlex Deucher 		WREG32(seq[i], seq[i+1]);
427d70229f7SAlex Deucher 
428d70229f7SAlex Deucher }
429d70229f7SAlex Deucher 
trinity_override_dynamic_mg_powergating(struct radeon_device * rdev)430d70229f7SAlex Deucher static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev)
431d70229f7SAlex Deucher {
432d70229f7SAlex Deucher 	u32 count;
433d70229f7SAlex Deucher 	const u32 *seq = NULL;
434d70229f7SAlex Deucher 
435d70229f7SAlex Deucher 	seq = &trinity_override_mgpg_sequences[0];
436d70229f7SAlex Deucher 	count = sizeof(trinity_override_mgpg_sequences) / (2 * sizeof(u32));
437d70229f7SAlex Deucher 
438d70229f7SAlex Deucher 	trinity_program_override_mgpg_sequences(rdev, seq, count);
439d70229f7SAlex Deucher }
440d70229f7SAlex Deucher 
trinity_ls_clockgating_enable(struct radeon_device * rdev,bool enable)441d70229f7SAlex Deucher static void trinity_ls_clockgating_enable(struct radeon_device *rdev,
442d70229f7SAlex Deucher 					  bool enable)
443d70229f7SAlex Deucher {
444d70229f7SAlex Deucher 	u32 count;
445d70229f7SAlex Deucher 	const u32 *seq = NULL;
446d70229f7SAlex Deucher 
447d70229f7SAlex Deucher 	if (enable) {
448d70229f7SAlex Deucher 		seq = &trinity_sysls_enable[0];
449d70229f7SAlex Deucher 		count = sizeof(trinity_sysls_enable) / (3 * sizeof(u32));
450d70229f7SAlex Deucher 	} else {
451d70229f7SAlex Deucher 		seq = &trinity_sysls_disable[0];
452d70229f7SAlex Deucher 		count = sizeof(trinity_sysls_disable) / (3 * sizeof(u32));
453d70229f7SAlex Deucher 	}
454d70229f7SAlex Deucher 
455d70229f7SAlex Deucher 	trinity_program_clk_gating_hw_sequence(rdev, seq, count);
456d70229f7SAlex Deucher }
457d70229f7SAlex Deucher 
trinity_gfx_powergating_enable(struct radeon_device * rdev,bool enable)458d70229f7SAlex Deucher static void trinity_gfx_powergating_enable(struct radeon_device *rdev,
459d70229f7SAlex Deucher 					   bool enable)
460d70229f7SAlex Deucher {
461d70229f7SAlex Deucher 	if (enable) {
462d70229f7SAlex Deucher 		if (RREG32_SMC(CC_SMU_TST_EFUSE1_MISC) & RB_BACKEND_DISABLE_MASK)
463d70229f7SAlex Deucher 			WREG32_SMC(SMU_SCRATCH_A, (RREG32_SMC(SMU_SCRATCH_A) | 0x01));
464d70229f7SAlex Deucher 
465d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
466d70229f7SAlex Deucher 	} else {
467d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_PWR_DOWN_EN);
468d70229f7SAlex Deucher 		RREG32(GB_ADDR_CONFIG);
469d70229f7SAlex Deucher 	}
470d70229f7SAlex Deucher }
471d70229f7SAlex Deucher 
trinity_gfx_dynamic_mgpg_enable(struct radeon_device * rdev,bool enable)472d70229f7SAlex Deucher static void trinity_gfx_dynamic_mgpg_enable(struct radeon_device *rdev,
473d70229f7SAlex Deucher 					    bool enable)
474d70229f7SAlex Deucher {
475d70229f7SAlex Deucher 	u32 value;
476d70229f7SAlex Deucher 
477d70229f7SAlex Deucher 	if (enable) {
478d70229f7SAlex Deucher 		value = RREG32_SMC(PM_I_CNTL_1);
479d70229f7SAlex Deucher 		value &= ~DS_PG_CNTL_MASK;
480d70229f7SAlex Deucher 		value |= DS_PG_CNTL(1);
481d70229f7SAlex Deucher 		WREG32_SMC(PM_I_CNTL_1, value);
482d70229f7SAlex Deucher 
483d70229f7SAlex Deucher 		value = RREG32_SMC(SMU_S_PG_CNTL);
484d70229f7SAlex Deucher 		value &= ~DS_PG_EN_MASK;
485d70229f7SAlex Deucher 		value |= DS_PG_EN(1);
486d70229f7SAlex Deucher 		WREG32_SMC(SMU_S_PG_CNTL, value);
487d70229f7SAlex Deucher 	} else {
488d70229f7SAlex Deucher 		value = RREG32_SMC(SMU_S_PG_CNTL);
489d70229f7SAlex Deucher 		value &= ~DS_PG_EN_MASK;
490d70229f7SAlex Deucher 		WREG32_SMC(SMU_S_PG_CNTL, value);
491d70229f7SAlex Deucher 
492d70229f7SAlex Deucher 		value = RREG32_SMC(PM_I_CNTL_1);
493d70229f7SAlex Deucher 		value &= ~DS_PG_CNTL_MASK;
494d70229f7SAlex Deucher 		WREG32_SMC(PM_I_CNTL_1, value);
495d70229f7SAlex Deucher 	}
496d70229f7SAlex Deucher 
497d70229f7SAlex Deucher 	trinity_gfx_dynamic_mgpg_config(rdev);
498d70229f7SAlex Deucher 
499d70229f7SAlex Deucher }
500d70229f7SAlex Deucher 
trinity_enable_clock_power_gating(struct radeon_device * rdev)501d70229f7SAlex Deucher static void trinity_enable_clock_power_gating(struct radeon_device *rdev)
502d70229f7SAlex Deucher {
503d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
504d70229f7SAlex Deucher 
505d70229f7SAlex Deucher 	if (pi->enable_gfx_clock_gating)
506d70229f7SAlex Deucher 		sumo_gfx_clockgating_initialize(rdev);
507d70229f7SAlex Deucher 	if (pi->enable_mg_clock_gating)
508d70229f7SAlex Deucher 		trinity_mg_clockgating_initialize(rdev);
509d70229f7SAlex Deucher 	if (pi->enable_gfx_power_gating)
510d70229f7SAlex Deucher 		trinity_gfx_powergating_initialize(rdev);
511d70229f7SAlex Deucher 	if (pi->enable_mg_clock_gating) {
512d70229f7SAlex Deucher 		trinity_ls_clockgating_enable(rdev, true);
513d70229f7SAlex Deucher 		trinity_mg_clockgating_enable(rdev, true);
514d70229f7SAlex Deucher 	}
515d70229f7SAlex Deucher 	if (pi->enable_gfx_clock_gating)
516d70229f7SAlex Deucher 		trinity_gfx_clockgating_enable(rdev, true);
517d70229f7SAlex Deucher 	if (pi->enable_gfx_dynamic_mgpg)
518d70229f7SAlex Deucher 		trinity_gfx_dynamic_mgpg_enable(rdev, true);
519d70229f7SAlex Deucher 	if (pi->enable_gfx_power_gating)
520d70229f7SAlex Deucher 		trinity_gfx_powergating_enable(rdev, true);
521d70229f7SAlex Deucher }
522d70229f7SAlex Deucher 
trinity_disable_clock_power_gating(struct radeon_device * rdev)523d70229f7SAlex Deucher static void trinity_disable_clock_power_gating(struct radeon_device *rdev)
524d70229f7SAlex Deucher {
525d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
526d70229f7SAlex Deucher 
527d70229f7SAlex Deucher 	if (pi->enable_gfx_power_gating)
528d70229f7SAlex Deucher 		trinity_gfx_powergating_enable(rdev, false);
529d70229f7SAlex Deucher 	if (pi->enable_gfx_dynamic_mgpg)
530d70229f7SAlex Deucher 		trinity_gfx_dynamic_mgpg_enable(rdev, false);
531d70229f7SAlex Deucher 	if (pi->enable_gfx_clock_gating)
532d70229f7SAlex Deucher 		trinity_gfx_clockgating_enable(rdev, false);
533d70229f7SAlex Deucher 	if (pi->enable_mg_clock_gating) {
534d70229f7SAlex Deucher 		trinity_mg_clockgating_enable(rdev, false);
535d70229f7SAlex Deucher 		trinity_ls_clockgating_enable(rdev, false);
536d70229f7SAlex Deucher 	}
537d70229f7SAlex Deucher }
538d70229f7SAlex Deucher 
trinity_set_divider_value(struct radeon_device * rdev,u32 index,u32 sclk)539d70229f7SAlex Deucher static void trinity_set_divider_value(struct radeon_device *rdev,
540d70229f7SAlex Deucher 				      u32 index, u32 sclk)
541d70229f7SAlex Deucher {
542d70229f7SAlex Deucher 	struct atom_clock_dividers  dividers;
543d70229f7SAlex Deucher 	int ret;
544d70229f7SAlex Deucher 	u32 value;
545d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
546d70229f7SAlex Deucher 
547d70229f7SAlex Deucher 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
548d70229f7SAlex Deucher 					     sclk, false, &dividers);
549d70229f7SAlex Deucher 	if (ret)
550d70229f7SAlex Deucher 		return;
551d70229f7SAlex Deucher 
552d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
553d70229f7SAlex Deucher 	value &= ~CLK_DIVIDER_MASK;
554d70229f7SAlex Deucher 	value |= CLK_DIVIDER(dividers.post_div);
555d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
556d70229f7SAlex Deucher 
557d70229f7SAlex Deucher 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
558d70229f7SAlex Deucher 					     sclk/2, false, &dividers);
559d70229f7SAlex Deucher 	if (ret)
560d70229f7SAlex Deucher 		return;
561d70229f7SAlex Deucher 
562d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix);
563d70229f7SAlex Deucher 	value &= ~PD_SCLK_DIVIDER_MASK;
564d70229f7SAlex Deucher 	value |= PD_SCLK_DIVIDER(dividers.post_div);
565d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix, value);
566d70229f7SAlex Deucher }
567d70229f7SAlex Deucher 
trinity_set_ds_dividers(struct radeon_device * rdev,u32 index,u32 divider)568d70229f7SAlex Deucher static void trinity_set_ds_dividers(struct radeon_device *rdev,
569d70229f7SAlex Deucher 				    u32 index, u32 divider)
570d70229f7SAlex Deucher {
571d70229f7SAlex Deucher 	u32 value;
572d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
573d70229f7SAlex Deucher 
574d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
575d70229f7SAlex Deucher 	value &= ~DS_DIV_MASK;
576d70229f7SAlex Deucher 	value |= DS_DIV(divider);
577d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
578d70229f7SAlex Deucher }
579d70229f7SAlex Deucher 
trinity_set_ss_dividers(struct radeon_device * rdev,u32 index,u32 divider)580d70229f7SAlex Deucher static void trinity_set_ss_dividers(struct radeon_device *rdev,
581d70229f7SAlex Deucher 				    u32 index, u32 divider)
582d70229f7SAlex Deucher {
583d70229f7SAlex Deucher 	u32 value;
584d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
585d70229f7SAlex Deucher 
586d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
587d70229f7SAlex Deucher 	value &= ~DS_SH_DIV_MASK;
588d70229f7SAlex Deucher 	value |= DS_SH_DIV(divider);
589d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
590d70229f7SAlex Deucher }
591d70229f7SAlex Deucher 
trinity_set_vid(struct radeon_device * rdev,u32 index,u32 vid)592d70229f7SAlex Deucher static void trinity_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
593d70229f7SAlex Deucher {
594d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
595d70229f7SAlex Deucher 	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid);
596d70229f7SAlex Deucher 	u32 value;
597d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
598d70229f7SAlex Deucher 
599d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
600d70229f7SAlex Deucher 	value &= ~VID_MASK;
601d70229f7SAlex Deucher 	value |= VID(vid_7bit);
602d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
603d70229f7SAlex Deucher 
604d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
605d70229f7SAlex Deucher 	value &= ~LVRT_MASK;
606d70229f7SAlex Deucher 	value |= LVRT(0);
607d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
608d70229f7SAlex Deucher }
609d70229f7SAlex Deucher 
trinity_set_allos_gnb_slow(struct radeon_device * rdev,u32 index,u32 gnb_slow)610d70229f7SAlex Deucher static void trinity_set_allos_gnb_slow(struct radeon_device *rdev,
611d70229f7SAlex Deucher 				       u32 index, u32 gnb_slow)
612d70229f7SAlex Deucher {
613d70229f7SAlex Deucher 	u32 value;
614d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
615d70229f7SAlex Deucher 
616d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
617d70229f7SAlex Deucher 	value &= ~GNB_SLOW_MASK;
618d70229f7SAlex Deucher 	value |= GNB_SLOW(gnb_slow);
619d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
620d70229f7SAlex Deucher }
621d70229f7SAlex Deucher 
trinity_set_force_nbp_state(struct radeon_device * rdev,u32 index,u32 force_nbp_state)622d70229f7SAlex Deucher static void trinity_set_force_nbp_state(struct radeon_device *rdev,
623d70229f7SAlex Deucher 					u32 index, u32 force_nbp_state)
624d70229f7SAlex Deucher {
625d70229f7SAlex Deucher 	u32 value;
626d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
627d70229f7SAlex Deucher 
628d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
629d70229f7SAlex Deucher 	value &= ~FORCE_NBPS1_MASK;
630d70229f7SAlex Deucher 	value |= FORCE_NBPS1(force_nbp_state);
631d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
632d70229f7SAlex Deucher }
633d70229f7SAlex Deucher 
trinity_set_display_wm(struct radeon_device * rdev,u32 index,u32 wm)634d70229f7SAlex Deucher static void trinity_set_display_wm(struct radeon_device *rdev,
635d70229f7SAlex Deucher 				   u32 index, u32 wm)
636d70229f7SAlex Deucher {
637d70229f7SAlex Deucher 	u32 value;
638d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
639d70229f7SAlex Deucher 
640d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
641d70229f7SAlex Deucher 	value &= ~DISPLAY_WM_MASK;
642d70229f7SAlex Deucher 	value |= DISPLAY_WM(wm);
643d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
644d70229f7SAlex Deucher }
645d70229f7SAlex Deucher 
trinity_set_vce_wm(struct radeon_device * rdev,u32 index,u32 wm)646d70229f7SAlex Deucher static void trinity_set_vce_wm(struct radeon_device *rdev,
647d70229f7SAlex Deucher 			       u32 index, u32 wm)
648d70229f7SAlex Deucher {
649d70229f7SAlex Deucher 	u32 value;
650d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
651d70229f7SAlex Deucher 
652d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
653d70229f7SAlex Deucher 	value &= ~VCE_WM_MASK;
654d70229f7SAlex Deucher 	value |= VCE_WM(wm);
655d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
656d70229f7SAlex Deucher }
657d70229f7SAlex Deucher 
trinity_set_at(struct radeon_device * rdev,u32 index,u32 at)658d70229f7SAlex Deucher static void trinity_set_at(struct radeon_device *rdev,
659d70229f7SAlex Deucher 			   u32 index, u32 at)
660d70229f7SAlex Deucher {
661d70229f7SAlex Deucher 	u32 value;
662d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
663d70229f7SAlex Deucher 
664d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix);
665d70229f7SAlex Deucher 	value &= ~AT_MASK;
666d70229f7SAlex Deucher 	value |= AT(at);
667d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix, value);
668d70229f7SAlex Deucher }
669d70229f7SAlex Deucher 
trinity_program_power_level(struct radeon_device * rdev,struct trinity_pl * pl,u32 index)670d70229f7SAlex Deucher static void trinity_program_power_level(struct radeon_device *rdev,
671d70229f7SAlex Deucher 					struct trinity_pl *pl, u32 index)
672d70229f7SAlex Deucher {
673d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
674d70229f7SAlex Deucher 
675d70229f7SAlex Deucher 	if (index >= SUMO_MAX_HARDWARE_POWERLEVELS)
676d70229f7SAlex Deucher 		return;
677d70229f7SAlex Deucher 
678d70229f7SAlex Deucher 	trinity_set_divider_value(rdev, index, pl->sclk);
679d70229f7SAlex Deucher 	trinity_set_vid(rdev, index, pl->vddc_index);
680d70229f7SAlex Deucher 	trinity_set_ss_dividers(rdev, index, pl->ss_divider_index);
681d70229f7SAlex Deucher 	trinity_set_ds_dividers(rdev, index, pl->ds_divider_index);
682d70229f7SAlex Deucher 	trinity_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
683d70229f7SAlex Deucher 	trinity_set_force_nbp_state(rdev, index, pl->force_nbp_state);
684d70229f7SAlex Deucher 	trinity_set_display_wm(rdev, index, pl->display_wm);
685d70229f7SAlex Deucher 	trinity_set_vce_wm(rdev, index, pl->vce_wm);
686d70229f7SAlex Deucher 	trinity_set_at(rdev, index, pi->at[index]);
687d70229f7SAlex Deucher }
688d70229f7SAlex Deucher 
trinity_power_level_enable_disable(struct radeon_device * rdev,u32 index,bool enable)689d70229f7SAlex Deucher static void trinity_power_level_enable_disable(struct radeon_device *rdev,
690d70229f7SAlex Deucher 					       u32 index, bool enable)
691d70229f7SAlex Deucher {
692d70229f7SAlex Deucher 	u32 value;
693d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
694d70229f7SAlex Deucher 
695d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
696d70229f7SAlex Deucher 	value &= ~STATE_VALID_MASK;
697d70229f7SAlex Deucher 	if (enable)
698d70229f7SAlex Deucher 		value |= STATE_VALID(1);
699d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
700d70229f7SAlex Deucher }
701d70229f7SAlex Deucher 
trinity_dpm_enabled(struct radeon_device * rdev)702d70229f7SAlex Deucher static bool trinity_dpm_enabled(struct radeon_device *rdev)
703d70229f7SAlex Deucher {
704d70229f7SAlex Deucher 	if (RREG32_SMC(SMU_SCLK_DPM_CNTL) & SCLK_DPM_EN(1))
705d70229f7SAlex Deucher 		return true;
706d70229f7SAlex Deucher 	else
707d70229f7SAlex Deucher 		return false;
708d70229f7SAlex Deucher }
709d70229f7SAlex Deucher 
trinity_start_dpm(struct radeon_device * rdev)710d70229f7SAlex Deucher static void trinity_start_dpm(struct radeon_device *rdev)
711d70229f7SAlex Deucher {
712d70229f7SAlex Deucher 	u32 value = RREG32_SMC(SMU_SCLK_DPM_CNTL);
713d70229f7SAlex Deucher 
714d70229f7SAlex Deucher 	value &= ~(SCLK_DPM_EN_MASK | SCLK_DPM_BOOT_STATE_MASK | VOLTAGE_CHG_EN_MASK);
715d70229f7SAlex Deucher 	value |= SCLK_DPM_EN(1) | SCLK_DPM_BOOT_STATE(0) | VOLTAGE_CHG_EN(1);
716d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_CNTL, value);
717d70229f7SAlex Deucher 
718d70229f7SAlex Deucher 	WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
719d70229f7SAlex Deucher 	WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~EN);
720d70229f7SAlex Deucher 
721d70229f7SAlex Deucher 	trinity_dpm_config(rdev, true);
722d70229f7SAlex Deucher }
723d70229f7SAlex Deucher 
trinity_wait_for_dpm_enabled(struct radeon_device * rdev)724d70229f7SAlex Deucher static void trinity_wait_for_dpm_enabled(struct radeon_device *rdev)
725d70229f7SAlex Deucher {
726d70229f7SAlex Deucher 	int i;
727d70229f7SAlex Deucher 
728d70229f7SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
729d70229f7SAlex Deucher 		if (RREG32(SCLK_PWRMGT_CNTL) & DYNAMIC_PM_EN)
730d70229f7SAlex Deucher 			break;
731d70229f7SAlex Deucher 		udelay(1);
732d70229f7SAlex Deucher 	}
733d70229f7SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
734d70229f7SAlex Deucher 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_STATE_MASK) == 0)
735d70229f7SAlex Deucher 			break;
736d70229f7SAlex Deucher 		udelay(1);
737d70229f7SAlex Deucher 	}
738d70229f7SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
739d70229f7SAlex Deucher 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
740d70229f7SAlex Deucher 			break;
741d70229f7SAlex Deucher 		udelay(1);
742d70229f7SAlex Deucher 	}
743d70229f7SAlex Deucher }
744d70229f7SAlex Deucher 
trinity_stop_dpm(struct radeon_device * rdev)745d70229f7SAlex Deucher static void trinity_stop_dpm(struct radeon_device *rdev)
746d70229f7SAlex Deucher {
747d70229f7SAlex Deucher 	u32 sclk_dpm_cntl;
748d70229f7SAlex Deucher 
749d70229f7SAlex Deucher 	WREG32_P(CG_CG_VOLTAGE_CNTL, EN, ~EN);
750d70229f7SAlex Deucher 
751d70229f7SAlex Deucher 	sclk_dpm_cntl = RREG32_SMC(SMU_SCLK_DPM_CNTL);
752d70229f7SAlex Deucher 	sclk_dpm_cntl &= ~(SCLK_DPM_EN_MASK | VOLTAGE_CHG_EN_MASK);
753d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_CNTL, sclk_dpm_cntl);
754d70229f7SAlex Deucher 
755d70229f7SAlex Deucher 	trinity_dpm_config(rdev, false);
756d70229f7SAlex Deucher }
757d70229f7SAlex Deucher 
trinity_start_am(struct radeon_device * rdev)758d70229f7SAlex Deucher static void trinity_start_am(struct radeon_device *rdev)
759d70229f7SAlex Deucher {
760d70229f7SAlex Deucher 	WREG32_P(SCLK_PWRMGT_CNTL, 0, ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
761d70229f7SAlex Deucher }
762d70229f7SAlex Deucher 
trinity_reset_am(struct radeon_device * rdev)763d70229f7SAlex Deucher static void trinity_reset_am(struct radeon_device *rdev)
764d70229f7SAlex Deucher {
765d70229f7SAlex Deucher 	WREG32_P(SCLK_PWRMGT_CNTL, RESET_SCLK_CNT | RESET_BUSY_CNT,
766d70229f7SAlex Deucher 		 ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
767d70229f7SAlex Deucher }
768d70229f7SAlex Deucher 
trinity_wait_for_level_0(struct radeon_device * rdev)769d70229f7SAlex Deucher static void trinity_wait_for_level_0(struct radeon_device *rdev)
770d70229f7SAlex Deucher {
771d70229f7SAlex Deucher 	int i;
772d70229f7SAlex Deucher 
773d70229f7SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
774d70229f7SAlex Deucher 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
775d70229f7SAlex Deucher 			break;
776d70229f7SAlex Deucher 		udelay(1);
777d70229f7SAlex Deucher 	}
778d70229f7SAlex Deucher }
779d70229f7SAlex Deucher 
trinity_enable_power_level_0(struct radeon_device * rdev)780d70229f7SAlex Deucher static void trinity_enable_power_level_0(struct radeon_device *rdev)
781d70229f7SAlex Deucher {
782d70229f7SAlex Deucher 	trinity_power_level_enable_disable(rdev, 0, true);
783d70229f7SAlex Deucher }
784d70229f7SAlex Deucher 
trinity_force_level_0(struct radeon_device * rdev)785d70229f7SAlex Deucher static void trinity_force_level_0(struct radeon_device *rdev)
786d70229f7SAlex Deucher {
787d70229f7SAlex Deucher 	trinity_dpm_force_state(rdev, 0);
788d70229f7SAlex Deucher }
789d70229f7SAlex Deucher 
trinity_unforce_levels(struct radeon_device * rdev)790d70229f7SAlex Deucher static void trinity_unforce_levels(struct radeon_device *rdev)
791d70229f7SAlex Deucher {
792d70229f7SAlex Deucher 	trinity_dpm_no_forced_level(rdev);
793d70229f7SAlex Deucher }
794d70229f7SAlex Deucher 
trinity_program_power_levels_0_to_n(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)795940eea8eSAlex Deucher static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev,
796940eea8eSAlex Deucher 						struct radeon_ps *new_rps,
797940eea8eSAlex Deucher 						struct radeon_ps *old_rps)
798d70229f7SAlex Deucher {
799940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
800940eea8eSAlex Deucher 	struct trinity_ps *old_ps = trinity_get_ps(old_rps);
801d70229f7SAlex Deucher 	u32 i;
802d70229f7SAlex Deucher 	u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
803d70229f7SAlex Deucher 
804d70229f7SAlex Deucher 	for (i = 0; i < new_ps->num_levels; i++) {
805d70229f7SAlex Deucher 		trinity_program_power_level(rdev, &new_ps->levels[i], i);
806d70229f7SAlex Deucher 		trinity_power_level_enable_disable(rdev, i, true);
807d70229f7SAlex Deucher 	}
808d70229f7SAlex Deucher 
809d70229f7SAlex Deucher 	for (i = new_ps->num_levels; i < n_current_state_levels; i++)
810d70229f7SAlex Deucher 		trinity_power_level_enable_disable(rdev, i, false);
811d70229f7SAlex Deucher }
812d70229f7SAlex Deucher 
trinity_program_bootup_state(struct radeon_device * rdev)813d70229f7SAlex Deucher static void trinity_program_bootup_state(struct radeon_device *rdev)
814d70229f7SAlex Deucher {
815d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
816d70229f7SAlex Deucher 	u32 i;
817d70229f7SAlex Deucher 
818d70229f7SAlex Deucher 	trinity_program_power_level(rdev, &pi->boot_pl, 0);
819d70229f7SAlex Deucher 	trinity_power_level_enable_disable(rdev, 0, true);
820d70229f7SAlex Deucher 
821d70229f7SAlex Deucher 	for (i = 1; i < 8; i++)
822d70229f7SAlex Deucher 		trinity_power_level_enable_disable(rdev, i, false);
823d70229f7SAlex Deucher }
824d70229f7SAlex Deucher 
trinity_setup_uvd_clock_table(struct radeon_device * rdev,struct radeon_ps * rps)8250c4aaeaeSAlex Deucher static void trinity_setup_uvd_clock_table(struct radeon_device *rdev,
8260c4aaeaeSAlex Deucher 					  struct radeon_ps *rps)
8270c4aaeaeSAlex Deucher {
8280c4aaeaeSAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
8290c4aaeaeSAlex Deucher 	u32 uvdstates = (ps->vclk_low_divider |
8300c4aaeaeSAlex Deucher 			 ps->vclk_high_divider << 8 |
8310c4aaeaeSAlex Deucher 			 ps->dclk_low_divider << 16 |
8320c4aaeaeSAlex Deucher 			 ps->dclk_high_divider << 24);
8330c4aaeaeSAlex Deucher 
8340c4aaeaeSAlex Deucher 	WREG32_SMC(SMU_UVD_DPM_STATES, uvdstates);
8350c4aaeaeSAlex Deucher }
8360c4aaeaeSAlex Deucher 
trinity_setup_uvd_dpm_interval(struct radeon_device * rdev,u32 interval)8370c4aaeaeSAlex Deucher static void trinity_setup_uvd_dpm_interval(struct radeon_device *rdev,
8380c4aaeaeSAlex Deucher 					   u32 interval)
8390c4aaeaeSAlex Deucher {
8400c4aaeaeSAlex Deucher 	u32 p, u;
8410c4aaeaeSAlex Deucher 	u32 tp = RREG32_SMC(PM_TP);
8420c4aaeaeSAlex Deucher 	u32 val;
8439d45ad5aSAlex Deucher 	u32 xclk = radeon_get_xclk(rdev);
8440c4aaeaeSAlex Deucher 
8450c4aaeaeSAlex Deucher 	r600_calculate_u_and_p(interval, xclk, 16, &p, &u);
8460c4aaeaeSAlex Deucher 
8470c4aaeaeSAlex Deucher 	val = (p + tp - 1) / tp;
8480c4aaeaeSAlex Deucher 
8490c4aaeaeSAlex Deucher 	WREG32_SMC(SMU_UVD_DPM_CNTL, val);
8500c4aaeaeSAlex Deucher }
8510c4aaeaeSAlex Deucher 
trinity_uvd_clocks_zero(struct radeon_ps * rps)8520c4aaeaeSAlex Deucher static bool trinity_uvd_clocks_zero(struct radeon_ps *rps)
8530c4aaeaeSAlex Deucher {
8540c4aaeaeSAlex Deucher 	if ((rps->vclk == 0) && (rps->dclk == 0))
8550c4aaeaeSAlex Deucher 		return true;
8560c4aaeaeSAlex Deucher 	else
8570c4aaeaeSAlex Deucher 		return false;
8580c4aaeaeSAlex Deucher }
8590c4aaeaeSAlex Deucher 
trinity_uvd_clocks_equal(struct radeon_ps * rps1,struct radeon_ps * rps2)8600c4aaeaeSAlex Deucher static bool trinity_uvd_clocks_equal(struct radeon_ps *rps1,
8610c4aaeaeSAlex Deucher 				     struct radeon_ps *rps2)
8620c4aaeaeSAlex Deucher {
8630c4aaeaeSAlex Deucher 	struct trinity_ps *ps1 = trinity_get_ps(rps1);
8640c4aaeaeSAlex Deucher 	struct trinity_ps *ps2 = trinity_get_ps(rps2);
8650c4aaeaeSAlex Deucher 
8660c4aaeaeSAlex Deucher 	if ((rps1->vclk == rps2->vclk) &&
8670c4aaeaeSAlex Deucher 	    (rps1->dclk == rps2->dclk) &&
8680c4aaeaeSAlex Deucher 	    (ps1->vclk_low_divider == ps2->vclk_low_divider) &&
8690c4aaeaeSAlex Deucher 	    (ps1->vclk_high_divider == ps2->vclk_high_divider) &&
8700c4aaeaeSAlex Deucher 	    (ps1->dclk_low_divider == ps2->dclk_low_divider) &&
8710c4aaeaeSAlex Deucher 	    (ps1->dclk_high_divider == ps2->dclk_high_divider))
8720c4aaeaeSAlex Deucher 		return true;
8730c4aaeaeSAlex Deucher 	else
8740c4aaeaeSAlex Deucher 		return false;
8750c4aaeaeSAlex Deucher }
8760c4aaeaeSAlex Deucher 
trinity_setup_uvd_clocks(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)8770c4aaeaeSAlex Deucher static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
878940eea8eSAlex Deucher 				     struct radeon_ps *new_rps,
879940eea8eSAlex Deucher 				     struct radeon_ps *old_rps)
8800c4aaeaeSAlex Deucher {
8810c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
8820c4aaeaeSAlex Deucher 
88362fa44bfSAlex Deucher 	if (pi->enable_gfx_power_gating) {
88462fa44bfSAlex Deucher 		trinity_gfx_powergating_enable(rdev, false);
88562fa44bfSAlex Deucher 	}
88662fa44bfSAlex Deucher 
8870c4aaeaeSAlex Deucher 	if (pi->uvd_dpm) {
8880c4aaeaeSAlex Deucher 		if (trinity_uvd_clocks_zero(new_rps) &&
889940eea8eSAlex Deucher 		    !trinity_uvd_clocks_zero(old_rps)) {
8900c4aaeaeSAlex Deucher 			trinity_setup_uvd_dpm_interval(rdev, 0);
8910c4aaeaeSAlex Deucher 		} else if (!trinity_uvd_clocks_zero(new_rps)) {
8920c4aaeaeSAlex Deucher 			trinity_setup_uvd_clock_table(rdev, new_rps);
8930c4aaeaeSAlex Deucher 
894940eea8eSAlex Deucher 			if (trinity_uvd_clocks_zero(old_rps)) {
8950c4aaeaeSAlex Deucher 				u32 tmp = RREG32(CG_MISC_REG);
8960c4aaeaeSAlex Deucher 				tmp &= 0xfffffffd;
8970c4aaeaeSAlex Deucher 				WREG32(CG_MISC_REG, tmp);
8980c4aaeaeSAlex Deucher 
8990c4aaeaeSAlex Deucher 				radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
9000c4aaeaeSAlex Deucher 
9010c4aaeaeSAlex Deucher 				trinity_setup_uvd_dpm_interval(rdev, 3000);
9020c4aaeaeSAlex Deucher 			}
9030c4aaeaeSAlex Deucher 		}
9040c4aaeaeSAlex Deucher 		trinity_uvd_dpm_config(rdev);
9050c4aaeaeSAlex Deucher 	} else {
9060c4aaeaeSAlex Deucher 		if (trinity_uvd_clocks_zero(new_rps) ||
907940eea8eSAlex Deucher 		    trinity_uvd_clocks_equal(new_rps, old_rps))
9080c4aaeaeSAlex Deucher 			return;
9090c4aaeaeSAlex Deucher 
9100c4aaeaeSAlex Deucher 		radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
9110c4aaeaeSAlex Deucher 	}
91262fa44bfSAlex Deucher 
91362fa44bfSAlex Deucher 	if (pi->enable_gfx_power_gating) {
91462fa44bfSAlex Deucher 		trinity_gfx_powergating_enable(rdev, true);
91562fa44bfSAlex Deucher 	}
9160c4aaeaeSAlex Deucher }
9170c4aaeaeSAlex Deucher 
trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)918940eea8eSAlex Deucher static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
919940eea8eSAlex Deucher 						       struct radeon_ps *new_rps,
920940eea8eSAlex Deucher 						       struct radeon_ps *old_rps)
9210c4aaeaeSAlex Deucher {
922940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
923940eea8eSAlex Deucher 	struct trinity_ps *current_ps = trinity_get_ps(new_rps);
9240c4aaeaeSAlex Deucher 
9250c4aaeaeSAlex Deucher 	if (new_ps->levels[new_ps->num_levels - 1].sclk >=
9260c4aaeaeSAlex Deucher 	    current_ps->levels[current_ps->num_levels - 1].sclk)
9270c4aaeaeSAlex Deucher 		return;
9280c4aaeaeSAlex Deucher 
929940eea8eSAlex Deucher 	trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
9300c4aaeaeSAlex Deucher }
9310c4aaeaeSAlex Deucher 
trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)932940eea8eSAlex Deucher static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
933940eea8eSAlex Deucher 						      struct radeon_ps *new_rps,
934940eea8eSAlex Deucher 						      struct radeon_ps *old_rps)
9350c4aaeaeSAlex Deucher {
936940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
937940eea8eSAlex Deucher 	struct trinity_ps *current_ps = trinity_get_ps(old_rps);
9380c4aaeaeSAlex Deucher 
9390c4aaeaeSAlex Deucher 	if (new_ps->levels[new_ps->num_levels - 1].sclk <
9400c4aaeaeSAlex Deucher 	    current_ps->levels[current_ps->num_levels - 1].sclk)
9410c4aaeaeSAlex Deucher 		return;
9420c4aaeaeSAlex Deucher 
943940eea8eSAlex Deucher 	trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
9440c4aaeaeSAlex Deucher }
9450c4aaeaeSAlex Deucher 
trinity_set_vce_clock(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)94611fe3d6eSAlex Deucher static void trinity_set_vce_clock(struct radeon_device *rdev,
94711fe3d6eSAlex Deucher 				  struct radeon_ps *new_rps,
94811fe3d6eSAlex Deucher 				  struct radeon_ps *old_rps)
94911fe3d6eSAlex Deucher {
95011fe3d6eSAlex Deucher 	if ((old_rps->evclk != new_rps->evclk) ||
95184bcd469SAlex Deucher 	    (old_rps->ecclk != new_rps->ecclk)) {
95284bcd469SAlex Deucher 		/* turn the clocks on when encoding, off otherwise */
95384bcd469SAlex Deucher 		if (new_rps->evclk || new_rps->ecclk)
95484bcd469SAlex Deucher 			vce_v1_0_enable_mgcg(rdev, false);
95584bcd469SAlex Deucher 		else
95684bcd469SAlex Deucher 			vce_v1_0_enable_mgcg(rdev, true);
95711fe3d6eSAlex Deucher 		radeon_set_vce_clocks(rdev, new_rps->evclk, new_rps->ecclk);
95811fe3d6eSAlex Deucher 	}
95984bcd469SAlex Deucher }
96011fe3d6eSAlex Deucher 
trinity_program_ttt(struct radeon_device * rdev)961d70229f7SAlex Deucher static void trinity_program_ttt(struct radeon_device *rdev)
962d70229f7SAlex Deucher {
963d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
964d70229f7SAlex Deucher 	u32 value = RREG32_SMC(SMU_SCLK_DPM_TTT);
965d70229f7SAlex Deucher 
966d70229f7SAlex Deucher 	value &= ~(HT_MASK | LT_MASK);
967d70229f7SAlex Deucher 	value |= HT((pi->thermal_auto_throttling + 49) * 8);
968d70229f7SAlex Deucher 	value |= LT((pi->thermal_auto_throttling + 49 - pi->sys_info.htc_hyst_lmt) * 8);
969d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_TTT, value);
970d70229f7SAlex Deucher }
971d70229f7SAlex Deucher 
trinity_enable_att(struct radeon_device * rdev)972d70229f7SAlex Deucher static void trinity_enable_att(struct radeon_device *rdev)
973d70229f7SAlex Deucher {
974d70229f7SAlex Deucher 	u32 value = RREG32_SMC(SMU_SCLK_DPM_TT_CNTL);
975d70229f7SAlex Deucher 
976d70229f7SAlex Deucher 	value &= ~SCLK_TT_EN_MASK;
977d70229f7SAlex Deucher 	value |= SCLK_TT_EN(1);
978d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_TT_CNTL, value);
979d70229f7SAlex Deucher }
980d70229f7SAlex Deucher 
trinity_program_sclk_dpm(struct radeon_device * rdev)981d70229f7SAlex Deucher static void trinity_program_sclk_dpm(struct radeon_device *rdev)
982d70229f7SAlex Deucher {
983d70229f7SAlex Deucher 	u32 p, u;
984d70229f7SAlex Deucher 	u32 tp = RREG32_SMC(PM_TP);
985d70229f7SAlex Deucher 	u32 ni;
9869d45ad5aSAlex Deucher 	u32 xclk = radeon_get_xclk(rdev);
987d70229f7SAlex Deucher 	u32 value;
988d70229f7SAlex Deucher 
989d70229f7SAlex Deucher 	r600_calculate_u_and_p(400, xclk, 16, &p, &u);
990d70229f7SAlex Deucher 
991d70229f7SAlex Deucher 	ni = (p + tp - 1) / tp;
992d70229f7SAlex Deucher 
993d70229f7SAlex Deucher 	value = RREG32_SMC(PM_I_CNTL_1);
994d70229f7SAlex Deucher 	value &= ~SCLK_DPM_MASK;
995d70229f7SAlex Deucher 	value |= SCLK_DPM(ni);
996d70229f7SAlex Deucher 	WREG32_SMC(PM_I_CNTL_1, value);
997d70229f7SAlex Deucher }
998d70229f7SAlex Deucher 
trinity_set_thermal_temperature_range(struct radeon_device * rdev,int min_temp,int max_temp)999d70229f7SAlex Deucher static int trinity_set_thermal_temperature_range(struct radeon_device *rdev,
1000d70229f7SAlex Deucher 						 int min_temp, int max_temp)
1001d70229f7SAlex Deucher {
1002d70229f7SAlex Deucher 	int low_temp = 0 * 1000;
1003d70229f7SAlex Deucher 	int high_temp = 255 * 1000;
1004d70229f7SAlex Deucher 
1005d70229f7SAlex Deucher 	if (low_temp < min_temp)
1006d70229f7SAlex Deucher 		low_temp = min_temp;
1007d70229f7SAlex Deucher 	if (high_temp > max_temp)
1008d70229f7SAlex Deucher 		high_temp = max_temp;
1009d70229f7SAlex Deucher 	if (high_temp < low_temp) {
1010d70229f7SAlex Deucher 		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
1011d70229f7SAlex Deucher 		return -EINVAL;
1012d70229f7SAlex Deucher 	}
1013d70229f7SAlex Deucher 
1014d70229f7SAlex Deucher 	WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
1015d70229f7SAlex Deucher 	WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
1016d70229f7SAlex Deucher 
1017d70229f7SAlex Deucher 	rdev->pm.dpm.thermal.min_temp = low_temp;
1018d70229f7SAlex Deucher 	rdev->pm.dpm.thermal.max_temp = high_temp;
1019d70229f7SAlex Deucher 
1020d70229f7SAlex Deucher 	return 0;
1021d70229f7SAlex Deucher }
1022d70229f7SAlex Deucher 
trinity_update_current_ps(struct radeon_device * rdev,struct radeon_ps * rps)1023a284c48aSAlex Deucher static void trinity_update_current_ps(struct radeon_device *rdev,
1024a284c48aSAlex Deucher 				      struct radeon_ps *rps)
1025a284c48aSAlex Deucher {
1026a284c48aSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(rps);
1027a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1028a284c48aSAlex Deucher 
1029a284c48aSAlex Deucher 	pi->current_rps = *rps;
1030a284c48aSAlex Deucher 	pi->current_ps = *new_ps;
1031a284c48aSAlex Deucher 	pi->current_rps.ps_priv = &pi->current_ps;
1032a284c48aSAlex Deucher }
1033a284c48aSAlex Deucher 
trinity_update_requested_ps(struct radeon_device * rdev,struct radeon_ps * rps)1034a284c48aSAlex Deucher static void trinity_update_requested_ps(struct radeon_device *rdev,
1035a284c48aSAlex Deucher 					struct radeon_ps *rps)
1036a284c48aSAlex Deucher {
1037a284c48aSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(rps);
1038a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1039a284c48aSAlex Deucher 
1040a284c48aSAlex Deucher 	pi->requested_rps = *rps;
1041a284c48aSAlex Deucher 	pi->requested_ps = *new_ps;
1042a284c48aSAlex Deucher 	pi->requested_rps.ps_priv = &pi->requested_ps;
1043a284c48aSAlex Deucher }
1044a284c48aSAlex Deucher 
trinity_dpm_enable_bapm(struct radeon_device * rdev,bool enable)104511877060SAlex Deucher void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable)
104611877060SAlex Deucher {
104711877060SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
104811877060SAlex Deucher 
104911877060SAlex Deucher 	if (pi->enable_bapm) {
105011877060SAlex Deucher 		trinity_acquire_mutex(rdev);
105111877060SAlex Deucher 		trinity_dpm_bapm_enable(rdev, enable);
105211877060SAlex Deucher 		trinity_release_mutex(rdev);
105311877060SAlex Deucher 	}
105411877060SAlex Deucher }
105511877060SAlex Deucher 
trinity_dpm_enable(struct radeon_device * rdev)1056d70229f7SAlex Deucher int trinity_dpm_enable(struct radeon_device *rdev)
1057d70229f7SAlex Deucher {
1058d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1059d70229f7SAlex Deucher 
1060d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1061d70229f7SAlex Deucher 
1062d70229f7SAlex Deucher 	if (trinity_dpm_enabled(rdev)) {
1063d70229f7SAlex Deucher 		trinity_release_mutex(rdev);
1064d70229f7SAlex Deucher 		return -EINVAL;
1065d70229f7SAlex Deucher 	}
1066d70229f7SAlex Deucher 
1067d70229f7SAlex Deucher 	trinity_program_bootup_state(rdev);
1068d70229f7SAlex Deucher 	sumo_program_vc(rdev, 0x00C00033);
1069d70229f7SAlex Deucher 	trinity_start_am(rdev);
1070d70229f7SAlex Deucher 	if (pi->enable_auto_thermal_throttling) {
1071d70229f7SAlex Deucher 		trinity_program_ttt(rdev);
1072d70229f7SAlex Deucher 		trinity_enable_att(rdev);
1073d70229f7SAlex Deucher 	}
1074d70229f7SAlex Deucher 	trinity_program_sclk_dpm(rdev);
1075d70229f7SAlex Deucher 	trinity_start_dpm(rdev);
1076d70229f7SAlex Deucher 	trinity_wait_for_dpm_enabled(rdev);
1077ef4e0365SAlex Deucher 	trinity_dpm_bapm_enable(rdev, false);
1078d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1079d70229f7SAlex Deucher 
1080a284c48aSAlex Deucher 	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
1081a284c48aSAlex Deucher 
1082d70229f7SAlex Deucher 	return 0;
1083d70229f7SAlex Deucher }
1084d70229f7SAlex Deucher 
trinity_dpm_late_enable(struct radeon_device * rdev)1085bda44c1aSAlex Deucher int trinity_dpm_late_enable(struct radeon_device *rdev)
1086bda44c1aSAlex Deucher {
1087bda44c1aSAlex Deucher 	int ret;
1088bda44c1aSAlex Deucher 
1089bda44c1aSAlex Deucher 	trinity_acquire_mutex(rdev);
1090bda44c1aSAlex Deucher 	trinity_enable_clock_power_gating(rdev);
1091bda44c1aSAlex Deucher 
1092bda44c1aSAlex Deucher 	if (rdev->irq.installed &&
1093bda44c1aSAlex Deucher 	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
1094bda44c1aSAlex Deucher 		ret = trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
1095bda44c1aSAlex Deucher 		if (ret) {
1096bda44c1aSAlex Deucher 			trinity_release_mutex(rdev);
1097bda44c1aSAlex Deucher 			return ret;
1098bda44c1aSAlex Deucher 		}
1099bda44c1aSAlex Deucher 		rdev->irq.dpm_thermal = true;
1100bda44c1aSAlex Deucher 		radeon_irq_set(rdev);
1101bda44c1aSAlex Deucher 	}
1102bda44c1aSAlex Deucher 	trinity_release_mutex(rdev);
1103bda44c1aSAlex Deucher 
1104bda44c1aSAlex Deucher 	return 0;
1105bda44c1aSAlex Deucher }
1106bda44c1aSAlex Deucher 
trinity_dpm_disable(struct radeon_device * rdev)1107d70229f7SAlex Deucher void trinity_dpm_disable(struct radeon_device *rdev)
1108d70229f7SAlex Deucher {
1109d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1110d70229f7SAlex Deucher 	if (!trinity_dpm_enabled(rdev)) {
1111d70229f7SAlex Deucher 		trinity_release_mutex(rdev);
1112d70229f7SAlex Deucher 		return;
1113d70229f7SAlex Deucher 	}
1114ef4e0365SAlex Deucher 	trinity_dpm_bapm_enable(rdev, false);
1115d70229f7SAlex Deucher 	trinity_disable_clock_power_gating(rdev);
1116d70229f7SAlex Deucher 	sumo_clear_vc(rdev);
1117d70229f7SAlex Deucher 	trinity_wait_for_level_0(rdev);
1118d70229f7SAlex Deucher 	trinity_stop_dpm(rdev);
1119d70229f7SAlex Deucher 	trinity_reset_am(rdev);
1120d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1121d70229f7SAlex Deucher 
1122d70229f7SAlex Deucher 	if (rdev->irq.installed &&
1123d70229f7SAlex Deucher 	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
1124d70229f7SAlex Deucher 		rdev->irq.dpm_thermal = false;
1125d70229f7SAlex Deucher 		radeon_irq_set(rdev);
1126d70229f7SAlex Deucher 	}
1127a284c48aSAlex Deucher 
1128a284c48aSAlex Deucher 	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
1129d70229f7SAlex Deucher }
1130d70229f7SAlex Deucher 
trinity_get_min_sclk_divider(struct radeon_device * rdev)1131d70229f7SAlex Deucher static void trinity_get_min_sclk_divider(struct radeon_device *rdev)
1132d70229f7SAlex Deucher {
1133d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1134d70229f7SAlex Deucher 
1135d70229f7SAlex Deucher 	pi->min_sclk_did =
1136d70229f7SAlex Deucher 		(RREG32_SMC(CC_SMU_MISC_FUSES) & MinSClkDid_MASK) >> MinSClkDid_SHIFT;
1137d70229f7SAlex Deucher }
1138d70229f7SAlex Deucher 
trinity_setup_nbp_sim(struct radeon_device * rdev,struct radeon_ps * rps)1139940eea8eSAlex Deucher static void trinity_setup_nbp_sim(struct radeon_device *rdev,
1140940eea8eSAlex Deucher 				  struct radeon_ps *rps)
1141d70229f7SAlex Deucher {
1142d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1143940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(rps);
1144d70229f7SAlex Deucher 	u32 nbpsconfig;
1145d70229f7SAlex Deucher 
1146d70229f7SAlex Deucher 	if (pi->sys_info.nb_dpm_enable) {
1147d70229f7SAlex Deucher 		nbpsconfig = RREG32_SMC(NB_PSTATE_CONFIG);
1148d70229f7SAlex Deucher 		nbpsconfig &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | DpmXNbPsLo_MASK | DpmXNbPsHi_MASK);
1149d70229f7SAlex Deucher 		nbpsconfig |= (Dpm0PgNbPsLo(new_ps->Dpm0PgNbPsLo) |
1150d70229f7SAlex Deucher 			       Dpm0PgNbPsHi(new_ps->Dpm0PgNbPsHi) |
1151d70229f7SAlex Deucher 			       DpmXNbPsLo(new_ps->DpmXNbPsLo) |
1152d70229f7SAlex Deucher 			       DpmXNbPsHi(new_ps->DpmXNbPsHi));
1153d70229f7SAlex Deucher 		WREG32_SMC(NB_PSTATE_CONFIG, nbpsconfig);
1154d70229f7SAlex Deucher 	}
1155d70229f7SAlex Deucher }
1156d70229f7SAlex Deucher 
trinity_dpm_force_performance_level(struct radeon_device * rdev,enum radeon_dpm_forced_level level)11579b5de596SAlex Deucher int trinity_dpm_force_performance_level(struct radeon_device *rdev,
11589b5de596SAlex Deucher 					enum radeon_dpm_forced_level level)
11599b5de596SAlex Deucher {
11609b5de596SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
11619b5de596SAlex Deucher 	struct radeon_ps *rps = &pi->current_rps;
11629b5de596SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
11639b5de596SAlex Deucher 	int i, ret;
11649b5de596SAlex Deucher 
11659b5de596SAlex Deucher 	if (ps->num_levels <= 1)
11669b5de596SAlex Deucher 		return 0;
11679b5de596SAlex Deucher 
11689b5de596SAlex Deucher 	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
11699b5de596SAlex Deucher 		/* not supported by the hw */
11709b5de596SAlex Deucher 		return -EINVAL;
11719b5de596SAlex Deucher 	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
11729b5de596SAlex Deucher 		ret = trinity_dpm_n_levels_disabled(rdev, ps->num_levels - 1);
11739b5de596SAlex Deucher 		if (ret)
11749b5de596SAlex Deucher 			return ret;
11759b5de596SAlex Deucher 	} else {
11769b5de596SAlex Deucher 		for (i = 0; i < ps->num_levels; i++) {
11779b5de596SAlex Deucher 			ret = trinity_dpm_n_levels_disabled(rdev, 0);
11789b5de596SAlex Deucher 			if (ret)
11799b5de596SAlex Deucher 				return ret;
11809b5de596SAlex Deucher 		}
11819b5de596SAlex Deucher 	}
11829b5de596SAlex Deucher 
11839b5de596SAlex Deucher 	rdev->pm.dpm.forced_level = level;
11849b5de596SAlex Deucher 
11859b5de596SAlex Deucher 	return 0;
11869b5de596SAlex Deucher }
11879b5de596SAlex Deucher 
trinity_dpm_pre_set_power_state(struct radeon_device * rdev)1188a284c48aSAlex Deucher int trinity_dpm_pre_set_power_state(struct radeon_device *rdev)
1189a284c48aSAlex Deucher {
1190a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1191a284c48aSAlex Deucher 	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
1192a284c48aSAlex Deucher 	struct radeon_ps *new_ps = &requested_ps;
1193a284c48aSAlex Deucher 
1194a284c48aSAlex Deucher 	trinity_update_requested_ps(rdev, new_ps);
1195a284c48aSAlex Deucher 
1196a284c48aSAlex Deucher 	trinity_apply_state_adjust_rules(rdev,
1197a284c48aSAlex Deucher 					 &pi->requested_rps,
1198a284c48aSAlex Deucher 					 &pi->current_rps);
1199a284c48aSAlex Deucher 
1200a284c48aSAlex Deucher 	return 0;
1201a284c48aSAlex Deucher }
1202a284c48aSAlex Deucher 
trinity_dpm_set_power_state(struct radeon_device * rdev)1203d70229f7SAlex Deucher int trinity_dpm_set_power_state(struct radeon_device *rdev)
1204d70229f7SAlex Deucher {
1205d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1206a284c48aSAlex Deucher 	struct radeon_ps *new_ps = &pi->requested_rps;
1207a284c48aSAlex Deucher 	struct radeon_ps *old_ps = &pi->current_rps;
1208d70229f7SAlex Deucher 
1209d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1210d70229f7SAlex Deucher 	if (pi->enable_dpm) {
121111877060SAlex Deucher 		if (pi->enable_bapm)
121211877060SAlex Deucher 			trinity_dpm_bapm_enable(rdev, rdev->pm.dpm.ac_power);
1213940eea8eSAlex Deucher 		trinity_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
1214d70229f7SAlex Deucher 		trinity_enable_power_level_0(rdev);
1215d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1216d70229f7SAlex Deucher 		trinity_wait_for_level_0(rdev);
1217940eea8eSAlex Deucher 		trinity_setup_nbp_sim(rdev, new_ps);
1218940eea8eSAlex Deucher 		trinity_program_power_levels_0_to_n(rdev, new_ps, old_ps);
1219d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1220d70229f7SAlex Deucher 		trinity_unforce_levels(rdev);
1221940eea8eSAlex Deucher 		trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
122211fe3d6eSAlex Deucher 		trinity_set_vce_clock(rdev, new_ps, old_ps);
1223d70229f7SAlex Deucher 	}
1224d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1225d70229f7SAlex Deucher 
1226d70229f7SAlex Deucher 	return 0;
1227d70229f7SAlex Deucher }
1228d70229f7SAlex Deucher 
trinity_dpm_post_set_power_state(struct radeon_device * rdev)1229a284c48aSAlex Deucher void trinity_dpm_post_set_power_state(struct radeon_device *rdev)
1230a284c48aSAlex Deucher {
1231a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1232a284c48aSAlex Deucher 	struct radeon_ps *new_ps = &pi->requested_rps;
1233a284c48aSAlex Deucher 
1234a284c48aSAlex Deucher 	trinity_update_current_ps(rdev, new_ps);
1235a284c48aSAlex Deucher }
1236a284c48aSAlex Deucher 
trinity_dpm_setup_asic(struct radeon_device * rdev)1237d70229f7SAlex Deucher void trinity_dpm_setup_asic(struct radeon_device *rdev)
1238d70229f7SAlex Deucher {
1239d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1240d70229f7SAlex Deucher 	sumo_program_sstp(rdev);
1241d70229f7SAlex Deucher 	sumo_take_smu_control(rdev, true);
1242d70229f7SAlex Deucher 	trinity_get_min_sclk_divider(rdev);
1243d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1244d70229f7SAlex Deucher }
1245d70229f7SAlex Deucher 
12466421d612SAlex Deucher #if 0
1247d70229f7SAlex Deucher void trinity_dpm_reset_asic(struct radeon_device *rdev)
1248d70229f7SAlex Deucher {
1249d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1250d70229f7SAlex Deucher 
1251d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1252d70229f7SAlex Deucher 	if (pi->enable_dpm) {
1253d70229f7SAlex Deucher 		trinity_enable_power_level_0(rdev);
1254d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1255d70229f7SAlex Deucher 		trinity_wait_for_level_0(rdev);
1256d70229f7SAlex Deucher 		trinity_program_bootup_state(rdev);
1257d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1258d70229f7SAlex Deucher 		trinity_unforce_levels(rdev);
1259d70229f7SAlex Deucher 	}
1260d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1261d70229f7SAlex Deucher }
12626421d612SAlex Deucher #endif
1263d70229f7SAlex Deucher 
trinity_convert_voltage_index_to_value(struct radeon_device * rdev,u32 vid_2bit)1264d70229f7SAlex Deucher static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
1265d70229f7SAlex Deucher 						  u32 vid_2bit)
1266d70229f7SAlex Deucher {
1267d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1268d70229f7SAlex Deucher 	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
1269d70229f7SAlex Deucher 	u32 svi_mode = (RREG32_SMC(PM_CONFIG) & SVI_Mode) ? 1 : 0;
1270d70229f7SAlex Deucher 	u32 step = (svi_mode == 0) ? 1250 : 625;
1271d70229f7SAlex Deucher 	u32 delta = vid_7bit * step + 50;
1272d70229f7SAlex Deucher 
1273d70229f7SAlex Deucher 	if (delta > 155000)
1274d70229f7SAlex Deucher 		return 0;
1275d70229f7SAlex Deucher 
1276d70229f7SAlex Deucher 	return (155000 - delta) / 100;
1277d70229f7SAlex Deucher }
1278d70229f7SAlex Deucher 
trinity_patch_boot_state(struct radeon_device * rdev,struct trinity_ps * ps)1279d70229f7SAlex Deucher static void trinity_patch_boot_state(struct radeon_device *rdev,
1280d70229f7SAlex Deucher 				     struct trinity_ps *ps)
1281d70229f7SAlex Deucher {
1282d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1283d70229f7SAlex Deucher 
1284d70229f7SAlex Deucher 	ps->num_levels = 1;
1285d70229f7SAlex Deucher 	ps->nbps_flags = 0;
1286d70229f7SAlex Deucher 	ps->bapm_flags = 0;
1287d70229f7SAlex Deucher 	ps->levels[0] = pi->boot_pl;
1288d70229f7SAlex Deucher }
1289d70229f7SAlex Deucher 
trinity_calculate_vce_wm(struct radeon_device * rdev,u32 sclk)1290d70229f7SAlex Deucher static u8 trinity_calculate_vce_wm(struct radeon_device *rdev, u32 sclk)
1291d70229f7SAlex Deucher {
1292d70229f7SAlex Deucher 	if (sclk < 20000)
1293d70229f7SAlex Deucher 		return 1;
1294d70229f7SAlex Deucher 	return 0;
1295d70229f7SAlex Deucher }
1296d70229f7SAlex Deucher 
trinity_construct_boot_state(struct radeon_device * rdev)1297d70229f7SAlex Deucher static void trinity_construct_boot_state(struct radeon_device *rdev)
1298d70229f7SAlex Deucher {
1299d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1300d70229f7SAlex Deucher 
1301d70229f7SAlex Deucher 	pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
1302d70229f7SAlex Deucher 	pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
1303d70229f7SAlex Deucher 	pi->boot_pl.ds_divider_index = 0;
1304d70229f7SAlex Deucher 	pi->boot_pl.ss_divider_index = 0;
1305d70229f7SAlex Deucher 	pi->boot_pl.allow_gnb_slow = 1;
1306d70229f7SAlex Deucher 	pi->boot_pl.force_nbp_state = 0;
1307d70229f7SAlex Deucher 	pi->boot_pl.display_wm = 0;
1308d70229f7SAlex Deucher 	pi->boot_pl.vce_wm = 0;
1309d70229f7SAlex Deucher 	pi->current_ps.num_levels = 1;
1310d70229f7SAlex Deucher 	pi->current_ps.levels[0] = pi->boot_pl;
1311d70229f7SAlex Deucher }
1312d70229f7SAlex Deucher 
trinity_get_sleep_divider_id_from_clock(struct radeon_device * rdev,u32 sclk,u32 min_sclk_in_sr)1313d70229f7SAlex Deucher static u8 trinity_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
1314d70229f7SAlex Deucher 						  u32 sclk, u32 min_sclk_in_sr)
1315d70229f7SAlex Deucher {
1316d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1317d70229f7SAlex Deucher 	u32 i;
1318d70229f7SAlex Deucher 	u32 temp;
1319d70229f7SAlex Deucher 	u32 min = (min_sclk_in_sr > TRINITY_MINIMUM_ENGINE_CLOCK) ?
1320d70229f7SAlex Deucher 		min_sclk_in_sr : TRINITY_MINIMUM_ENGINE_CLOCK;
1321d70229f7SAlex Deucher 
1322d70229f7SAlex Deucher 	if (sclk < min)
1323d70229f7SAlex Deucher 		return 0;
1324d70229f7SAlex Deucher 
1325d70229f7SAlex Deucher 	if (!pi->enable_sclk_ds)
1326d70229f7SAlex Deucher 		return 0;
1327d70229f7SAlex Deucher 
1328d70229f7SAlex Deucher 	for (i = TRINITY_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
1329d70229f7SAlex Deucher 		temp = sclk / sumo_get_sleep_divider_from_id(i);
1330d70229f7SAlex Deucher 		if (temp >= min || i == 0)
1331d70229f7SAlex Deucher 			break;
1332d70229f7SAlex Deucher 	}
1333d70229f7SAlex Deucher 
1334d70229f7SAlex Deucher 	return (u8)i;
1335d70229f7SAlex Deucher }
1336d70229f7SAlex Deucher 
trinity_get_valid_engine_clock(struct radeon_device * rdev,u32 lower_limit)1337d70229f7SAlex Deucher static u32 trinity_get_valid_engine_clock(struct radeon_device *rdev,
1338d70229f7SAlex Deucher 					  u32 lower_limit)
1339d70229f7SAlex Deucher {
1340d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1341d70229f7SAlex Deucher 	u32 i;
1342d70229f7SAlex Deucher 
1343d70229f7SAlex Deucher 	for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
1344d70229f7SAlex Deucher 		if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
1345d70229f7SAlex Deucher 			return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
1346d70229f7SAlex Deucher 	}
1347d70229f7SAlex Deucher 
1348d70229f7SAlex Deucher 	if (i == pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries)
1349d70229f7SAlex Deucher 		DRM_ERROR("engine clock out of range!");
1350d70229f7SAlex Deucher 
1351d70229f7SAlex Deucher 	return 0;
1352d70229f7SAlex Deucher }
1353d70229f7SAlex Deucher 
trinity_patch_thermal_state(struct radeon_device * rdev,struct trinity_ps * ps,struct trinity_ps * current_ps)1354d70229f7SAlex Deucher static void trinity_patch_thermal_state(struct radeon_device *rdev,
1355d70229f7SAlex Deucher 					struct trinity_ps *ps,
1356d70229f7SAlex Deucher 					struct trinity_ps *current_ps)
1357d70229f7SAlex Deucher {
1358d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1359d70229f7SAlex Deucher 	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
1360d70229f7SAlex Deucher 	u32 current_vddc;
1361d70229f7SAlex Deucher 	u32 current_sclk;
1362d70229f7SAlex Deucher 	u32 current_index = 0;
1363d70229f7SAlex Deucher 
1364d70229f7SAlex Deucher 	if (current_ps) {
1365d70229f7SAlex Deucher 		current_vddc = current_ps->levels[current_index].vddc_index;
1366d70229f7SAlex Deucher 		current_sclk = current_ps->levels[current_index].sclk;
1367d70229f7SAlex Deucher 	} else {
1368d70229f7SAlex Deucher 		current_vddc = pi->boot_pl.vddc_index;
1369d70229f7SAlex Deucher 		current_sclk = pi->boot_pl.sclk;
1370d70229f7SAlex Deucher 	}
1371d70229f7SAlex Deucher 
1372d70229f7SAlex Deucher 	ps->levels[0].vddc_index = current_vddc;
1373d70229f7SAlex Deucher 
1374d70229f7SAlex Deucher 	if (ps->levels[0].sclk > current_sclk)
1375d70229f7SAlex Deucher 		ps->levels[0].sclk = current_sclk;
1376d70229f7SAlex Deucher 
1377d70229f7SAlex Deucher 	ps->levels[0].ds_divider_index =
1378d70229f7SAlex Deucher 		trinity_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
1379d70229f7SAlex Deucher 	ps->levels[0].ss_divider_index = ps->levels[0].ds_divider_index;
1380d70229f7SAlex Deucher 	ps->levels[0].allow_gnb_slow = 1;
1381d70229f7SAlex Deucher 	ps->levels[0].force_nbp_state = 0;
1382d70229f7SAlex Deucher 	ps->levels[0].display_wm = 0;
1383d70229f7SAlex Deucher 	ps->levels[0].vce_wm =
1384d70229f7SAlex Deucher 		trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
1385d70229f7SAlex Deucher }
1386d70229f7SAlex Deucher 
trinity_calculate_display_wm(struct radeon_device * rdev,struct trinity_ps * ps,u32 index)1387d70229f7SAlex Deucher static u8 trinity_calculate_display_wm(struct radeon_device *rdev,
1388d70229f7SAlex Deucher 				       struct trinity_ps *ps, u32 index)
1389d70229f7SAlex Deucher {
1390d70229f7SAlex Deucher 	if (ps == NULL || ps->num_levels <= 1)
1391d70229f7SAlex Deucher 		return 0;
1392d70229f7SAlex Deucher 	else if (ps->num_levels == 2) {
1393d70229f7SAlex Deucher 		if (index == 0)
1394d70229f7SAlex Deucher 			return 0;
1395d70229f7SAlex Deucher 		else
1396d70229f7SAlex Deucher 			return 1;
1397d70229f7SAlex Deucher 	} else {
1398d70229f7SAlex Deucher 		if (index == 0)
1399d70229f7SAlex Deucher 			return 0;
1400d70229f7SAlex Deucher 		else if (ps->levels[index].sclk < 30000)
1401d70229f7SAlex Deucher 			return 0;
1402d70229f7SAlex Deucher 		else
1403d70229f7SAlex Deucher 			return 1;
1404d70229f7SAlex Deucher 	}
1405d70229f7SAlex Deucher }
1406d70229f7SAlex Deucher 
trinity_get_uvd_clock_index(struct radeon_device * rdev,struct radeon_ps * rps)14070c4aaeaeSAlex Deucher static u32 trinity_get_uvd_clock_index(struct radeon_device *rdev,
14080c4aaeaeSAlex Deucher 				       struct radeon_ps *rps)
14090c4aaeaeSAlex Deucher {
14100c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
14110c4aaeaeSAlex Deucher 	u32 i = 0;
14120c4aaeaeSAlex Deucher 
14130c4aaeaeSAlex Deucher 	for (i = 0; i < 4; i++) {
14140c4aaeaeSAlex Deucher 		if ((rps->vclk == pi->sys_info.uvd_clock_table_entries[i].vclk) &&
14150c4aaeaeSAlex Deucher 		    (rps->dclk == pi->sys_info.uvd_clock_table_entries[i].dclk))
14160c4aaeaeSAlex Deucher 		    break;
14170c4aaeaeSAlex Deucher 	}
14180c4aaeaeSAlex Deucher 
14190c4aaeaeSAlex Deucher 	if (i >= 4) {
14200c4aaeaeSAlex Deucher 		DRM_ERROR("UVD clock index not found!\n");
14210c4aaeaeSAlex Deucher 		i = 3;
14220c4aaeaeSAlex Deucher 	}
14230c4aaeaeSAlex Deucher 	return i;
14240c4aaeaeSAlex Deucher }
14250c4aaeaeSAlex Deucher 
trinity_adjust_uvd_state(struct radeon_device * rdev,struct radeon_ps * rps)14260c4aaeaeSAlex Deucher static void trinity_adjust_uvd_state(struct radeon_device *rdev,
14270c4aaeaeSAlex Deucher 				     struct radeon_ps *rps)
14280c4aaeaeSAlex Deucher {
14290c4aaeaeSAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
14300c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
14310c4aaeaeSAlex Deucher 	u32 high_index = 0;
14320c4aaeaeSAlex Deucher 	u32 low_index = 0;
14330c4aaeaeSAlex Deucher 
14340c4aaeaeSAlex Deucher 	if (pi->uvd_dpm && r600_is_uvd_state(rps->class, rps->class2)) {
14350c4aaeaeSAlex Deucher 		high_index = trinity_get_uvd_clock_index(rdev, rps);
14360c4aaeaeSAlex Deucher 
14370c4aaeaeSAlex Deucher 		switch(high_index) {
14380c4aaeaeSAlex Deucher 		case 3:
14390c4aaeaeSAlex Deucher 		case 2:
14400c4aaeaeSAlex Deucher 			low_index = 1;
14410c4aaeaeSAlex Deucher 			break;
14420c4aaeaeSAlex Deucher 		case 1:
14430c4aaeaeSAlex Deucher 		case 0:
14440c4aaeaeSAlex Deucher 		default:
14450c4aaeaeSAlex Deucher 			low_index = 0;
14460c4aaeaeSAlex Deucher 			break;
14470c4aaeaeSAlex Deucher 		}
14480c4aaeaeSAlex Deucher 
14490c4aaeaeSAlex Deucher 		ps->vclk_low_divider =
14500c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[high_index].vclk_did;
14510c4aaeaeSAlex Deucher 		ps->dclk_low_divider =
14520c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[high_index].dclk_did;
14530c4aaeaeSAlex Deucher 		ps->vclk_high_divider =
14540c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[low_index].vclk_did;
14550c4aaeaeSAlex Deucher 		ps->dclk_high_divider =
14560c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[low_index].dclk_did;
14570c4aaeaeSAlex Deucher 	}
14580c4aaeaeSAlex Deucher }
14590c4aaeaeSAlex Deucher 
trinity_get_vce_clock_voltage(struct radeon_device * rdev,u32 evclk,u32 ecclk,u16 * voltage)146011fe3d6eSAlex Deucher static int trinity_get_vce_clock_voltage(struct radeon_device *rdev,
146111fe3d6eSAlex Deucher 					 u32 evclk, u32 ecclk, u16 *voltage)
146211fe3d6eSAlex Deucher {
146311fe3d6eSAlex Deucher 	u32 i;
146411fe3d6eSAlex Deucher 	int ret = -EINVAL;
146511fe3d6eSAlex Deucher 	struct radeon_vce_clock_voltage_dependency_table *table =
146611fe3d6eSAlex Deucher 		&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
14670c4aaeaeSAlex Deucher 
146811fe3d6eSAlex Deucher 	if (((evclk == 0) && (ecclk == 0)) ||
146911fe3d6eSAlex Deucher 	    (table && (table->count == 0))) {
147011fe3d6eSAlex Deucher 		*voltage = 0;
147111fe3d6eSAlex Deucher 		return 0;
147211fe3d6eSAlex Deucher 	}
147311fe3d6eSAlex Deucher 
147411fe3d6eSAlex Deucher 	for (i = 0; i < table->count; i++) {
147511fe3d6eSAlex Deucher 		if ((evclk <= table->entries[i].evclk) &&
147611fe3d6eSAlex Deucher 		    (ecclk <= table->entries[i].ecclk)) {
147711fe3d6eSAlex Deucher 			*voltage = table->entries[i].v;
147811fe3d6eSAlex Deucher 			ret = 0;
147911fe3d6eSAlex Deucher 			break;
148011fe3d6eSAlex Deucher 		}
148111fe3d6eSAlex Deucher 	}
148211fe3d6eSAlex Deucher 
148311fe3d6eSAlex Deucher 	/* if no match return the highest voltage */
148411fe3d6eSAlex Deucher 	if (ret)
148511fe3d6eSAlex Deucher 		*voltage = table->entries[table->count - 1].v;
148611fe3d6eSAlex Deucher 
148711fe3d6eSAlex Deucher 	return ret;
148811fe3d6eSAlex Deucher }
14890c4aaeaeSAlex Deucher 
trinity_apply_state_adjust_rules(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)1490940eea8eSAlex Deucher static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
1491940eea8eSAlex Deucher 					     struct radeon_ps *new_rps,
1492940eea8eSAlex Deucher 					     struct radeon_ps *old_rps)
1493d70229f7SAlex Deucher {
1494940eea8eSAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(new_rps);
1495940eea8eSAlex Deucher 	struct trinity_ps *current_ps = trinity_get_ps(old_rps);
1496d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1497d70229f7SAlex Deucher 	u32 min_voltage = 0; /* ??? */
1498d70229f7SAlex Deucher 	u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
1499d70229f7SAlex Deucher 	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
1500d70229f7SAlex Deucher 	u32 i;
150111fe3d6eSAlex Deucher 	u16 min_vce_voltage;
1502d70229f7SAlex Deucher 	bool force_high;
1503d70229f7SAlex Deucher 	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
1504d70229f7SAlex Deucher 
1505940eea8eSAlex Deucher 	if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
1506d70229f7SAlex Deucher 		return trinity_patch_thermal_state(rdev, ps, current_ps);
1507d70229f7SAlex Deucher 
1508940eea8eSAlex Deucher 	trinity_adjust_uvd_state(rdev, new_rps);
15090c4aaeaeSAlex Deucher 
151011fe3d6eSAlex Deucher 	if (new_rps->vce_active) {
151111fe3d6eSAlex Deucher 		new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
151211fe3d6eSAlex Deucher 		new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
151311fe3d6eSAlex Deucher 	} else {
151411fe3d6eSAlex Deucher 		new_rps->evclk = 0;
151511fe3d6eSAlex Deucher 		new_rps->ecclk = 0;
151611fe3d6eSAlex Deucher 	}
151711fe3d6eSAlex Deucher 
1518d70229f7SAlex Deucher 	for (i = 0; i < ps->num_levels; i++) {
1519d70229f7SAlex Deucher 		if (ps->levels[i].vddc_index < min_voltage)
1520d70229f7SAlex Deucher 			ps->levels[i].vddc_index = min_voltage;
1521d70229f7SAlex Deucher 
1522d70229f7SAlex Deucher 		if (ps->levels[i].sclk < min_sclk)
1523d70229f7SAlex Deucher 			ps->levels[i].sclk =
1524d70229f7SAlex Deucher 				trinity_get_valid_engine_clock(rdev, min_sclk);
1525d70229f7SAlex Deucher 
152611fe3d6eSAlex Deucher 		/* patch in vce limits */
152711fe3d6eSAlex Deucher 		if (new_rps->vce_active) {
152811fe3d6eSAlex Deucher 			/* sclk */
152911fe3d6eSAlex Deucher 			if (ps->levels[i].sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
153011fe3d6eSAlex Deucher 				ps->levels[i].sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
153111fe3d6eSAlex Deucher 			/* vddc */
153211fe3d6eSAlex Deucher 			trinity_get_vce_clock_voltage(rdev, new_rps->evclk, new_rps->ecclk, &min_vce_voltage);
153311fe3d6eSAlex Deucher 			if (ps->levels[i].vddc_index < min_vce_voltage)
153411fe3d6eSAlex Deucher 				ps->levels[i].vddc_index = min_vce_voltage;
153511fe3d6eSAlex Deucher 		}
153611fe3d6eSAlex Deucher 
1537d70229f7SAlex Deucher 		ps->levels[i].ds_divider_index =
1538d70229f7SAlex Deucher 			sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
1539d70229f7SAlex Deucher 
1540d70229f7SAlex Deucher 		ps->levels[i].ss_divider_index = ps->levels[i].ds_divider_index;
1541d70229f7SAlex Deucher 
1542d70229f7SAlex Deucher 		ps->levels[i].allow_gnb_slow = 1;
1543d70229f7SAlex Deucher 		ps->levels[i].force_nbp_state = 0;
1544d70229f7SAlex Deucher 		ps->levels[i].display_wm =
1545d70229f7SAlex Deucher 			trinity_calculate_display_wm(rdev, ps, i);
1546d70229f7SAlex Deucher 		ps->levels[i].vce_wm =
1547d70229f7SAlex Deucher 			trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
1548d70229f7SAlex Deucher 	}
1549d70229f7SAlex Deucher 
1550940eea8eSAlex Deucher 	if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
1551940eea8eSAlex Deucher 	    ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY))
1552d70229f7SAlex Deucher 		ps->bapm_flags |= TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE;
1553d70229f7SAlex Deucher 
1554d70229f7SAlex Deucher 	if (pi->sys_info.nb_dpm_enable) {
1555d70229f7SAlex Deucher 		ps->Dpm0PgNbPsLo = 0x1;
1556d70229f7SAlex Deucher 		ps->Dpm0PgNbPsHi = 0x0;
1557d70229f7SAlex Deucher 		ps->DpmXNbPsLo = 0x2;
1558d70229f7SAlex Deucher 		ps->DpmXNbPsHi = 0x1;
1559d70229f7SAlex Deucher 
1560940eea8eSAlex Deucher 		if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
1561940eea8eSAlex Deucher 		    ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) {
1562940eea8eSAlex Deucher 			force_high = ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ||
1563940eea8eSAlex Deucher 				      ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) &&
1564d70229f7SAlex Deucher 				       (pi->sys_info.uma_channel_number == 1)));
1565d70229f7SAlex Deucher 			force_high = (num_active_displays >= 3) || force_high;
1566d70229f7SAlex Deucher 			ps->Dpm0PgNbPsLo = force_high ? 0x2 : 0x3;
1567d70229f7SAlex Deucher 			ps->Dpm0PgNbPsHi = 0x1;
1568d70229f7SAlex Deucher 			ps->DpmXNbPsLo = force_high ? 0x2 : 0x3;
1569d70229f7SAlex Deucher 			ps->DpmXNbPsHi = 0x2;
1570d70229f7SAlex Deucher 			ps->levels[ps->num_levels - 1].allow_gnb_slow = 0;
1571d70229f7SAlex Deucher 		}
1572d70229f7SAlex Deucher 	}
1573d70229f7SAlex Deucher }
1574d70229f7SAlex Deucher 
trinity_cleanup_asic(struct radeon_device * rdev)1575d70229f7SAlex Deucher static void trinity_cleanup_asic(struct radeon_device *rdev)
1576d70229f7SAlex Deucher {
1577d70229f7SAlex Deucher 	sumo_take_smu_control(rdev, false);
1578d70229f7SAlex Deucher }
1579d70229f7SAlex Deucher 
1580d70229f7SAlex Deucher #if 0
1581d70229f7SAlex Deucher static void trinity_pre_display_configuration_change(struct radeon_device *rdev)
1582d70229f7SAlex Deucher {
1583d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1584d70229f7SAlex Deucher 
1585d70229f7SAlex Deucher 	if (pi->voltage_drop_in_dce)
1586d70229f7SAlex Deucher 		trinity_dce_enable_voltage_adjustment(rdev, false);
1587d70229f7SAlex Deucher }
1588d70229f7SAlex Deucher #endif
1589d70229f7SAlex Deucher 
trinity_add_dccac_value(struct radeon_device * rdev)1590d70229f7SAlex Deucher static void trinity_add_dccac_value(struct radeon_device *rdev)
1591d70229f7SAlex Deucher {
1592d70229f7SAlex Deucher 	u32 gpu_cac_avrg_cntl_window_size;
1593d70229f7SAlex Deucher 	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
1594d70229f7SAlex Deucher 	u64 disp_clk = rdev->clock.default_dispclk / 100;
1595d70229f7SAlex Deucher 	u32 dc_cac_value;
1596d70229f7SAlex Deucher 
1597d70229f7SAlex Deucher 	gpu_cac_avrg_cntl_window_size =
1598d70229f7SAlex Deucher 		(RREG32_SMC(GPU_CAC_AVRG_CNTL) & WINDOW_SIZE_MASK) >> WINDOW_SIZE_SHIFT;
1599d70229f7SAlex Deucher 
1600d70229f7SAlex Deucher 	dc_cac_value = (u32)((14213 * disp_clk * disp_clk * (u64)num_active_displays) >>
1601d70229f7SAlex Deucher 			     (32 - gpu_cac_avrg_cntl_window_size));
1602d70229f7SAlex Deucher 
1603d70229f7SAlex Deucher 	WREG32_SMC(DC_CAC_VALUE, dc_cac_value);
1604d70229f7SAlex Deucher }
1605d70229f7SAlex Deucher 
trinity_dpm_display_configuration_changed(struct radeon_device * rdev)1606d70229f7SAlex Deucher void trinity_dpm_display_configuration_changed(struct radeon_device *rdev)
1607d70229f7SAlex Deucher {
1608d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1609d70229f7SAlex Deucher 
1610d70229f7SAlex Deucher 	if (pi->voltage_drop_in_dce)
1611d70229f7SAlex Deucher 		trinity_dce_enable_voltage_adjustment(rdev, true);
1612d70229f7SAlex Deucher 	trinity_add_dccac_value(rdev);
1613d70229f7SAlex Deucher }
1614d70229f7SAlex Deucher 
1615d70229f7SAlex Deucher union power_info {
1616d70229f7SAlex Deucher 	struct _ATOM_POWERPLAY_INFO info;
1617d70229f7SAlex Deucher 	struct _ATOM_POWERPLAY_INFO_V2 info_2;
1618d70229f7SAlex Deucher 	struct _ATOM_POWERPLAY_INFO_V3 info_3;
1619d70229f7SAlex Deucher 	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
1620d70229f7SAlex Deucher 	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
1621d70229f7SAlex Deucher 	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
1622d70229f7SAlex Deucher };
1623d70229f7SAlex Deucher 
1624d70229f7SAlex Deucher union pplib_clock_info {
1625d70229f7SAlex Deucher 	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
1626d70229f7SAlex Deucher 	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
1627d70229f7SAlex Deucher 	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
1628d70229f7SAlex Deucher 	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
1629d70229f7SAlex Deucher };
1630d70229f7SAlex Deucher 
1631d70229f7SAlex Deucher union pplib_power_state {
1632d70229f7SAlex Deucher 	struct _ATOM_PPLIB_STATE v1;
1633d70229f7SAlex Deucher 	struct _ATOM_PPLIB_STATE_V2 v2;
1634d70229f7SAlex Deucher };
1635d70229f7SAlex Deucher 
trinity_parse_pplib_non_clock_info(struct radeon_device * rdev,struct radeon_ps * rps,struct _ATOM_PPLIB_NONCLOCK_INFO * non_clock_info,u8 table_rev)1636d70229f7SAlex Deucher static void trinity_parse_pplib_non_clock_info(struct radeon_device *rdev,
1637d70229f7SAlex Deucher 					       struct radeon_ps *rps,
1638d70229f7SAlex Deucher 					       struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
1639d70229f7SAlex Deucher 					       u8 table_rev)
1640d70229f7SAlex Deucher {
1641d70229f7SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
1642d70229f7SAlex Deucher 
1643d70229f7SAlex Deucher 	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
1644d70229f7SAlex Deucher 	rps->class = le16_to_cpu(non_clock_info->usClassification);
1645d70229f7SAlex Deucher 	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
1646d70229f7SAlex Deucher 
1647d70229f7SAlex Deucher 	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
1648d70229f7SAlex Deucher 		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
1649d70229f7SAlex Deucher 		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
1650d70229f7SAlex Deucher 	} else {
1651d70229f7SAlex Deucher 		rps->vclk = 0;
1652d70229f7SAlex Deucher 		rps->dclk = 0;
1653d70229f7SAlex Deucher 	}
1654d70229f7SAlex Deucher 
1655d70229f7SAlex Deucher 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
1656d70229f7SAlex Deucher 		rdev->pm.dpm.boot_ps = rps;
1657d70229f7SAlex Deucher 		trinity_patch_boot_state(rdev, ps);
1658d70229f7SAlex Deucher 	}
1659d70229f7SAlex Deucher 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
1660d70229f7SAlex Deucher 		rdev->pm.dpm.uvd_ps = rps;
1661d70229f7SAlex Deucher }
1662d70229f7SAlex Deucher 
trinity_parse_pplib_clock_info(struct radeon_device * rdev,struct radeon_ps * rps,int index,union pplib_clock_info * clock_info)1663d70229f7SAlex Deucher static void trinity_parse_pplib_clock_info(struct radeon_device *rdev,
1664d70229f7SAlex Deucher 					   struct radeon_ps *rps, int index,
1665d70229f7SAlex Deucher 					   union pplib_clock_info *clock_info)
1666d70229f7SAlex Deucher {
1667d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1668d70229f7SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
1669d70229f7SAlex Deucher 	struct trinity_pl *pl = &ps->levels[index];
1670d70229f7SAlex Deucher 	u32 sclk;
1671d70229f7SAlex Deucher 
1672d70229f7SAlex Deucher 	sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
1673d70229f7SAlex Deucher 	sclk |= clock_info->sumo.ucEngineClockHigh << 16;
1674d70229f7SAlex Deucher 	pl->sclk = sclk;
1675d70229f7SAlex Deucher 	pl->vddc_index = clock_info->sumo.vddcIndex;
1676d70229f7SAlex Deucher 
1677d70229f7SAlex Deucher 	ps->num_levels = index + 1;
1678d70229f7SAlex Deucher 
1679d70229f7SAlex Deucher 	if (pi->enable_sclk_ds) {
1680d70229f7SAlex Deucher 		pl->ds_divider_index = 5;
1681d70229f7SAlex Deucher 		pl->ss_divider_index = 5;
1682d70229f7SAlex Deucher 	}
1683d70229f7SAlex Deucher }
1684d70229f7SAlex Deucher 
trinity_parse_power_table(struct radeon_device * rdev)1685d70229f7SAlex Deucher static int trinity_parse_power_table(struct radeon_device *rdev)
1686d70229f7SAlex Deucher {
1687d70229f7SAlex Deucher 	struct radeon_mode_info *mode_info = &rdev->mode_info;
1688d70229f7SAlex Deucher 	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
1689d70229f7SAlex Deucher 	union pplib_power_state *power_state;
1690d70229f7SAlex Deucher 	int i, j, k, non_clock_array_index, clock_array_index;
1691d70229f7SAlex Deucher 	union pplib_clock_info *clock_info;
1692d70229f7SAlex Deucher 	struct _StateArray *state_array;
1693d70229f7SAlex Deucher 	struct _ClockInfoArray *clock_info_array;
1694d70229f7SAlex Deucher 	struct _NonClockInfoArray *non_clock_info_array;
1695d70229f7SAlex Deucher 	union power_info *power_info;
1696d70229f7SAlex Deucher 	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
1697d70229f7SAlex Deucher 	u16 data_offset;
1698d70229f7SAlex Deucher 	u8 frev, crev;
1699d70229f7SAlex Deucher 	u8 *power_state_offset;
1700d70229f7SAlex Deucher 	struct sumo_ps *ps;
1701d70229f7SAlex Deucher 
1702d70229f7SAlex Deucher 	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
1703d70229f7SAlex Deucher 				   &frev, &crev, &data_offset))
1704d70229f7SAlex Deucher 		return -EINVAL;
1705d70229f7SAlex Deucher 	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
1706d70229f7SAlex Deucher 
1707d70229f7SAlex Deucher 	state_array = (struct _StateArray *)
1708d70229f7SAlex Deucher 		(mode_info->atom_context->bios + data_offset +
1709d70229f7SAlex Deucher 		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
1710d70229f7SAlex Deucher 	clock_info_array = (struct _ClockInfoArray *)
1711d70229f7SAlex Deucher 		(mode_info->atom_context->bios + data_offset +
1712d70229f7SAlex Deucher 		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
1713d70229f7SAlex Deucher 	non_clock_info_array = (struct _NonClockInfoArray *)
1714d70229f7SAlex Deucher 		(mode_info->atom_context->bios + data_offset +
1715d70229f7SAlex Deucher 		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
1716d70229f7SAlex Deucher 
17176396bb22SKees Cook 	rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries,
17186396bb22SKees Cook 				  sizeof(struct radeon_ps),
17196396bb22SKees Cook 				  GFP_KERNEL);
1720d70229f7SAlex Deucher 	if (!rdev->pm.dpm.ps)
1721d70229f7SAlex Deucher 		return -ENOMEM;
1722d70229f7SAlex Deucher 	power_state_offset = (u8 *)state_array->states;
1723d70229f7SAlex Deucher 	for (i = 0; i < state_array->ucNumEntries; i++) {
17245e250d20SAlex Deucher 		u8 *idx;
1725d70229f7SAlex Deucher 		power_state = (union pplib_power_state *)power_state_offset;
1726d70229f7SAlex Deucher 		non_clock_array_index = power_state->v2.nonClockInfoIndex;
1727d70229f7SAlex Deucher 		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
1728d70229f7SAlex Deucher 			&non_clock_info_array->nonClockInfo[non_clock_array_index];
1729*0564e8a4SZhipeng Lu 		if (!rdev->pm.power_state[i].clock_info) {
1730*0564e8a4SZhipeng Lu 			kfree(rdev->pm.dpm.ps);
1731d70229f7SAlex Deucher 			return -EINVAL;
1732*0564e8a4SZhipeng Lu 		}
1733d70229f7SAlex Deucher 		ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
1734d70229f7SAlex Deucher 		if (ps == NULL) {
1735d70229f7SAlex Deucher 			kfree(rdev->pm.dpm.ps);
1736d70229f7SAlex Deucher 			return -ENOMEM;
1737d70229f7SAlex Deucher 		}
1738d70229f7SAlex Deucher 		rdev->pm.dpm.ps[i].ps_priv = ps;
1739d70229f7SAlex Deucher 		k = 0;
17405e250d20SAlex Deucher 		idx = (u8 *)&power_state->v2.clockInfoIndex[0];
1741d70229f7SAlex Deucher 		for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
17425e250d20SAlex Deucher 			clock_array_index = idx[j];
1743d70229f7SAlex Deucher 			if (clock_array_index >= clock_info_array->ucNumEntries)
1744d70229f7SAlex Deucher 				continue;
1745d70229f7SAlex Deucher 			if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
1746d70229f7SAlex Deucher 				break;
1747d70229f7SAlex Deucher 			clock_info = (union pplib_clock_info *)
17485e250d20SAlex Deucher 				((u8 *)&clock_info_array->clockInfo[0] +
17495e250d20SAlex Deucher 				 (clock_array_index * clock_info_array->ucEntrySize));
1750d70229f7SAlex Deucher 			trinity_parse_pplib_clock_info(rdev,
1751d70229f7SAlex Deucher 						       &rdev->pm.dpm.ps[i], k,
1752d70229f7SAlex Deucher 						       clock_info);
1753d70229f7SAlex Deucher 			k++;
1754d70229f7SAlex Deucher 		}
1755d70229f7SAlex Deucher 		trinity_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
1756d70229f7SAlex Deucher 						   non_clock_info,
1757d70229f7SAlex Deucher 						   non_clock_info_array->ucEntrySize);
1758d70229f7SAlex Deucher 		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
1759d70229f7SAlex Deucher 	}
1760d70229f7SAlex Deucher 	rdev->pm.dpm.num_ps = state_array->ucNumEntries;
176111fe3d6eSAlex Deucher 
176211fe3d6eSAlex Deucher 	/* fill in the vce power states */
176311fe3d6eSAlex Deucher 	for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
176411fe3d6eSAlex Deucher 		u32 sclk;
176511fe3d6eSAlex Deucher 		clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
176611fe3d6eSAlex Deucher 		clock_info = (union pplib_clock_info *)
176711fe3d6eSAlex Deucher 			&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
176811fe3d6eSAlex Deucher 		sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
176911fe3d6eSAlex Deucher 		sclk |= clock_info->sumo.ucEngineClockHigh << 16;
177011fe3d6eSAlex Deucher 		rdev->pm.dpm.vce_states[i].sclk = sclk;
177111fe3d6eSAlex Deucher 		rdev->pm.dpm.vce_states[i].mclk = 0;
177211fe3d6eSAlex Deucher 	}
177311fe3d6eSAlex Deucher 
1774d70229f7SAlex Deucher 	return 0;
1775d70229f7SAlex Deucher }
1776d70229f7SAlex Deucher 
1777d70229f7SAlex Deucher union igp_info {
1778d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
1779d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
1780d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
1781d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
1782d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
1783d70229f7SAlex Deucher };
1784d70229f7SAlex Deucher 
trinity_convert_did_to_freq(struct radeon_device * rdev,u8 did)17850c4aaeaeSAlex Deucher static u32 trinity_convert_did_to_freq(struct radeon_device *rdev, u8 did)
17860c4aaeaeSAlex Deucher {
17870c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
17880c4aaeaeSAlex Deucher 	u32 divider;
17890c4aaeaeSAlex Deucher 
17900c4aaeaeSAlex Deucher 	if (did >= 8 && did <= 0x3f)
17910c4aaeaeSAlex Deucher 		divider = did * 25;
17920c4aaeaeSAlex Deucher 	else if (did > 0x3f && did <= 0x5f)
17930c4aaeaeSAlex Deucher 		divider = (did - 64) * 50 + 1600;
17940c4aaeaeSAlex Deucher 	else if (did > 0x5f && did <= 0x7e)
17950c4aaeaeSAlex Deucher 		divider = (did - 96) * 100 + 3200;
17960c4aaeaeSAlex Deucher 	else if (did == 0x7f)
17970c4aaeaeSAlex Deucher 		divider = 128 * 100;
17980c4aaeaeSAlex Deucher 	else
17990c4aaeaeSAlex Deucher 		return 10000;
18000c4aaeaeSAlex Deucher 
18010c4aaeaeSAlex Deucher 	return ((pi->sys_info.dentist_vco_freq * 100) + (divider - 1)) / divider;
18020c4aaeaeSAlex Deucher }
18030c4aaeaeSAlex Deucher 
trinity_parse_sys_info_table(struct radeon_device * rdev)1804d70229f7SAlex Deucher static int trinity_parse_sys_info_table(struct radeon_device *rdev)
1805d70229f7SAlex Deucher {
1806d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1807d70229f7SAlex Deucher 	struct radeon_mode_info *mode_info = &rdev->mode_info;
1808d70229f7SAlex Deucher 	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
1809d70229f7SAlex Deucher 	union igp_info *igp_info;
1810d70229f7SAlex Deucher 	u8 frev, crev;
1811d70229f7SAlex Deucher 	u16 data_offset;
1812d70229f7SAlex Deucher 	int i;
1813d70229f7SAlex Deucher 
1814d70229f7SAlex Deucher 	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1815d70229f7SAlex Deucher 				   &frev, &crev, &data_offset)) {
1816d70229f7SAlex Deucher 		igp_info = (union igp_info *)(mode_info->atom_context->bios +
1817d70229f7SAlex Deucher 					      data_offset);
1818d70229f7SAlex Deucher 
1819d70229f7SAlex Deucher 		if (crev != 7) {
1820d70229f7SAlex Deucher 			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
1821d70229f7SAlex Deucher 			return -EINVAL;
1822d70229f7SAlex Deucher 		}
1823d70229f7SAlex Deucher 		pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock);
1824d70229f7SAlex Deucher 		pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock);
1825d70229f7SAlex Deucher 		pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock);
18260c4aaeaeSAlex Deucher 		pi->sys_info.dentist_vco_freq = le32_to_cpu(igp_info->info_7.ulDentistVCOFreq);
1827d70229f7SAlex Deucher 		pi->sys_info.bootup_nb_voltage_index =
1828d70229f7SAlex Deucher 			le16_to_cpu(igp_info->info_7.usBootUpNBVoltage);
1829d70229f7SAlex Deucher 		if (igp_info->info_7.ucHtcTmpLmt == 0)
1830d70229f7SAlex Deucher 			pi->sys_info.htc_tmp_lmt = 203;
1831d70229f7SAlex Deucher 		else
1832d70229f7SAlex Deucher 			pi->sys_info.htc_tmp_lmt = igp_info->info_7.ucHtcTmpLmt;
1833d70229f7SAlex Deucher 		if (igp_info->info_7.ucHtcHystLmt == 0)
1834d70229f7SAlex Deucher 			pi->sys_info.htc_hyst_lmt = 5;
1835d70229f7SAlex Deucher 		else
1836d70229f7SAlex Deucher 			pi->sys_info.htc_hyst_lmt = igp_info->info_7.ucHtcHystLmt;
1837d70229f7SAlex Deucher 		if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
1838d70229f7SAlex Deucher 			DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
1839d70229f7SAlex Deucher 		}
1840d70229f7SAlex Deucher 
1841d70229f7SAlex Deucher 		if (pi->enable_nbps_policy)
1842d70229f7SAlex Deucher 			pi->sys_info.nb_dpm_enable = igp_info->info_7.ucNBDPMEnable;
1843d70229f7SAlex Deucher 		else
1844d70229f7SAlex Deucher 			pi->sys_info.nb_dpm_enable = 0;
1845d70229f7SAlex Deucher 
1846d70229f7SAlex Deucher 		for (i = 0; i < TRINITY_NUM_NBPSTATES; i++) {
1847d70229f7SAlex Deucher 			pi->sys_info.nbp_mclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateMemclkFreq[i]);
1848d70229f7SAlex Deucher 			pi->sys_info.nbp_nclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateNClkFreq[i]);
1849d70229f7SAlex Deucher 		}
1850d70229f7SAlex Deucher 
1851d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[0] = le16_to_cpu(igp_info->info_7.usNBP0Voltage);
1852d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[1] = le16_to_cpu(igp_info->info_7.usNBP1Voltage);
1853d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[2] = le16_to_cpu(igp_info->info_7.usNBP2Voltage);
1854d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[3] = le16_to_cpu(igp_info->info_7.usNBP3Voltage);
1855d70229f7SAlex Deucher 
1856d70229f7SAlex Deucher 		if (!pi->sys_info.nb_dpm_enable) {
1857d70229f7SAlex Deucher 			for (i = 1; i < TRINITY_NUM_NBPSTATES; i++) {
1858d70229f7SAlex Deucher 				pi->sys_info.nbp_mclk[i] = pi->sys_info.nbp_mclk[0];
1859d70229f7SAlex Deucher 				pi->sys_info.nbp_nclk[i] = pi->sys_info.nbp_nclk[0];
1860d70229f7SAlex Deucher 				pi->sys_info.nbp_voltage_index[i] = pi->sys_info.nbp_voltage_index[0];
1861d70229f7SAlex Deucher 			}
1862d70229f7SAlex Deucher 		}
1863d70229f7SAlex Deucher 
1864d70229f7SAlex Deucher 		pi->sys_info.uma_channel_number = igp_info->info_7.ucUMAChannelNumber;
1865d70229f7SAlex Deucher 
1866d70229f7SAlex Deucher 		sumo_construct_sclk_voltage_mapping_table(rdev,
1867d70229f7SAlex Deucher 							  &pi->sys_info.sclk_voltage_mapping_table,
1868d70229f7SAlex Deucher 							  igp_info->info_7.sAvail_SCLK);
1869d70229f7SAlex Deucher 		sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
1870d70229f7SAlex Deucher 						 igp_info->info_7.sAvail_SCLK);
1871d70229f7SAlex Deucher 
18720c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[0].vclk_did =
18730c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState0VclkFid;
18740c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[1].vclk_did =
18750c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState1VclkFid;
18760c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[2].vclk_did =
18770c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState2VclkFid;
18780c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[3].vclk_did =
18790c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState3VclkFid;
18800c4aaeaeSAlex Deucher 
18810c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[0].dclk_did =
18820c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState0DclkFid;
18830c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[1].dclk_did =
18840c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState1DclkFid;
18850c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[2].dclk_did =
18860c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState2DclkFid;
18870c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[3].dclk_did =
18880c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState3DclkFid;
18890c4aaeaeSAlex Deucher 
18900c4aaeaeSAlex Deucher 		for (i = 0; i < 4; i++) {
18910c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[i].vclk =
18920c4aaeaeSAlex Deucher 				trinity_convert_did_to_freq(rdev,
18930c4aaeaeSAlex Deucher 							    pi->sys_info.uvd_clock_table_entries[i].vclk_did);
18940c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[i].dclk =
18950c4aaeaeSAlex Deucher 				trinity_convert_did_to_freq(rdev,
18960c4aaeaeSAlex Deucher 							    pi->sys_info.uvd_clock_table_entries[i].dclk_did);
18970c4aaeaeSAlex Deucher 		}
18980c4aaeaeSAlex Deucher 
18990c4aaeaeSAlex Deucher 
19000c4aaeaeSAlex Deucher 
1901d70229f7SAlex Deucher 	}
1902d70229f7SAlex Deucher 	return 0;
1903d70229f7SAlex Deucher }
1904d70229f7SAlex Deucher 
trinity_dpm_init(struct radeon_device * rdev)1905d70229f7SAlex Deucher int trinity_dpm_init(struct radeon_device *rdev)
1906d70229f7SAlex Deucher {
1907d70229f7SAlex Deucher 	struct trinity_power_info *pi;
1908d70229f7SAlex Deucher 	int ret, i;
1909d70229f7SAlex Deucher 
1910d70229f7SAlex Deucher 	pi = kzalloc(sizeof(struct trinity_power_info), GFP_KERNEL);
1911d70229f7SAlex Deucher 	if (pi == NULL)
1912d70229f7SAlex Deucher 		return -ENOMEM;
1913d70229f7SAlex Deucher 	rdev->pm.dpm.priv = pi;
1914d70229f7SAlex Deucher 
1915d70229f7SAlex Deucher 	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
1916d70229f7SAlex Deucher 		pi->at[i] = TRINITY_AT_DFLT;
1917d70229f7SAlex Deucher 
19186e909f74SAlex Deucher 	if (radeon_bapm == -1) {
1919730a336cSAlex Deucher 		/* There are stability issues reported on with
1920730a336cSAlex Deucher 		 * bapm enabled when switching between AC and battery
1921730a336cSAlex Deucher 		 * power.  At the same time, some MSI boards hang
1922730a336cSAlex Deucher 		 * if it's not enabled and dpm is enabled.  Just enable
1923730a336cSAlex Deucher 		 * it for MSI boards right now.
19240c78a449SAlex Deucher 		 */
1925730a336cSAlex Deucher 		if (rdev->pdev->subsystem_vendor == 0x1462)
19260c78a449SAlex Deucher 			pi->enable_bapm = true;
1927730a336cSAlex Deucher 		else
1928730a336cSAlex Deucher 			pi->enable_bapm = false;
19296e909f74SAlex Deucher 	} else if (radeon_bapm == 0) {
19306e909f74SAlex Deucher 		pi->enable_bapm = false;
19316e909f74SAlex Deucher 	} else {
19326e909f74SAlex Deucher 		pi->enable_bapm = true;
19336e909f74SAlex Deucher 	}
1934d70229f7SAlex Deucher 	pi->enable_nbps_policy = true;
1935d70229f7SAlex Deucher 	pi->enable_sclk_ds = true;
1936d70229f7SAlex Deucher 	pi->enable_gfx_power_gating = true;
1937d70229f7SAlex Deucher 	pi->enable_gfx_clock_gating = true;
1938958b84fbSAlex Deucher 	pi->enable_mg_clock_gating = false;
1939958b84fbSAlex Deucher 	pi->enable_gfx_dynamic_mgpg = false;
1940958b84fbSAlex Deucher 	pi->override_dynamic_mgpg = false;
1941d70229f7SAlex Deucher 	pi->enable_auto_thermal_throttling = true;
1942d70229f7SAlex Deucher 	pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
19430c4aaeaeSAlex Deucher 	pi->uvd_dpm = true; /* ??? */
1944d70229f7SAlex Deucher 
1945d70229f7SAlex Deucher 	ret = trinity_parse_sys_info_table(rdev);
1946d70229f7SAlex Deucher 	if (ret)
1947d70229f7SAlex Deucher 		return ret;
1948d70229f7SAlex Deucher 
1949d70229f7SAlex Deucher 	trinity_construct_boot_state(rdev);
1950d70229f7SAlex Deucher 
195182f79cc5SAlex Deucher 	ret = r600_get_platform_caps(rdev);
195282f79cc5SAlex Deucher 	if (ret)
195382f79cc5SAlex Deucher 		return ret;
195482f79cc5SAlex Deucher 
195511fe3d6eSAlex Deucher 	ret = r600_parse_extended_power_table(rdev);
195611fe3d6eSAlex Deucher 	if (ret)
195711fe3d6eSAlex Deucher 		return ret;
195811fe3d6eSAlex Deucher 
1959d70229f7SAlex Deucher 	ret = trinity_parse_power_table(rdev);
1960d70229f7SAlex Deucher 	if (ret)
1961d70229f7SAlex Deucher 		return ret;
1962d70229f7SAlex Deucher 
1963d70229f7SAlex Deucher 	pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
1964d70229f7SAlex Deucher 	pi->enable_dpm = true;
1965d70229f7SAlex Deucher 
1966d70229f7SAlex Deucher 	return 0;
1967d70229f7SAlex Deucher }
1968d70229f7SAlex Deucher 
trinity_dpm_print_power_state(struct radeon_device * rdev,struct radeon_ps * rps)1969d70229f7SAlex Deucher void trinity_dpm_print_power_state(struct radeon_device *rdev,
1970d70229f7SAlex Deucher 				   struct radeon_ps *rps)
1971d70229f7SAlex Deucher {
1972d70229f7SAlex Deucher 	int i;
1973d70229f7SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
1974d70229f7SAlex Deucher 
1975d70229f7SAlex Deucher 	r600_dpm_print_class_info(rps->class, rps->class2);
1976d70229f7SAlex Deucher 	r600_dpm_print_cap_info(rps->caps);
1977d70229f7SAlex Deucher 	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
1978d70229f7SAlex Deucher 	for (i = 0; i < ps->num_levels; i++) {
1979d70229f7SAlex Deucher 		struct trinity_pl *pl = &ps->levels[i];
1980d70229f7SAlex Deucher 		printk("\t\tpower level %d    sclk: %u vddc: %u\n",
1981d70229f7SAlex Deucher 		       i, pl->sclk,
1982d70229f7SAlex Deucher 		       trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
1983d70229f7SAlex Deucher 	}
1984d70229f7SAlex Deucher 	r600_dpm_print_ps_status(rdev, rps);
1985d70229f7SAlex Deucher }
1986d70229f7SAlex Deucher 
trinity_dpm_debugfs_print_current_performance_level(struct radeon_device * rdev,struct seq_file * m)1987490ab931SAlex Deucher void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
1988490ab931SAlex Deucher 							 struct seq_file *m)
1989490ab931SAlex Deucher {
19909f3f63f2SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
19919f3f63f2SAlex Deucher 	struct radeon_ps *rps = &pi->current_rps;
1992490ab931SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
1993490ab931SAlex Deucher 	struct trinity_pl *pl;
1994490ab931SAlex Deucher 	u32 current_index =
1995490ab931SAlex Deucher 		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
1996490ab931SAlex Deucher 		CURRENT_STATE_SHIFT;
1997490ab931SAlex Deucher 
1998490ab931SAlex Deucher 	if (current_index >= ps->num_levels) {
1999490ab931SAlex Deucher 		seq_printf(m, "invalid dpm profile %d\n", current_index);
2000490ab931SAlex Deucher 	} else {
2001490ab931SAlex Deucher 		pl = &ps->levels[current_index];
2002490ab931SAlex Deucher 		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
2003490ab931SAlex Deucher 		seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
2004490ab931SAlex Deucher 			   current_index, pl->sclk,
2005490ab931SAlex Deucher 			   trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
2006490ab931SAlex Deucher 	}
2007490ab931SAlex Deucher }
2008490ab931SAlex Deucher 
trinity_dpm_get_current_sclk(struct radeon_device * rdev)20097ce9cdaeSAlex Deucher u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev)
20107ce9cdaeSAlex Deucher {
20117ce9cdaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
20127ce9cdaeSAlex Deucher 	struct radeon_ps *rps = &pi->current_rps;
20137ce9cdaeSAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
20147ce9cdaeSAlex Deucher 	struct trinity_pl *pl;
20157ce9cdaeSAlex Deucher 	u32 current_index =
20167ce9cdaeSAlex Deucher 		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
20177ce9cdaeSAlex Deucher 		CURRENT_STATE_SHIFT;
20187ce9cdaeSAlex Deucher 
20197ce9cdaeSAlex Deucher 	if (current_index >= ps->num_levels) {
20207ce9cdaeSAlex Deucher 		return 0;
20217ce9cdaeSAlex Deucher 	} else {
20227ce9cdaeSAlex Deucher 		pl = &ps->levels[current_index];
20237ce9cdaeSAlex Deucher 		return pl->sclk;
20247ce9cdaeSAlex Deucher 	}
20257ce9cdaeSAlex Deucher }
20267ce9cdaeSAlex Deucher 
trinity_dpm_get_current_mclk(struct radeon_device * rdev)20277ce9cdaeSAlex Deucher u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev)
20287ce9cdaeSAlex Deucher {
20297ce9cdaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
20307ce9cdaeSAlex Deucher 
20317ce9cdaeSAlex Deucher 	return pi->sys_info.bootup_uma_clk;
20327ce9cdaeSAlex Deucher }
20337ce9cdaeSAlex Deucher 
trinity_dpm_fini(struct radeon_device * rdev)2034d70229f7SAlex Deucher void trinity_dpm_fini(struct radeon_device *rdev)
2035d70229f7SAlex Deucher {
2036d70229f7SAlex Deucher 	int i;
2037d70229f7SAlex Deucher 
2038d70229f7SAlex Deucher 	trinity_cleanup_asic(rdev); /* ??? */
2039d70229f7SAlex Deucher 
2040d70229f7SAlex Deucher 	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
2041d70229f7SAlex Deucher 		kfree(rdev->pm.dpm.ps[i].ps_priv);
2042d70229f7SAlex Deucher 	}
2043d70229f7SAlex Deucher 	kfree(rdev->pm.dpm.ps);
2044d70229f7SAlex Deucher 	kfree(rdev->pm.dpm.priv);
204511fe3d6eSAlex Deucher 	r600_free_extended_power_table(rdev);
2046d70229f7SAlex Deucher }
2047d70229f7SAlex Deucher 
trinity_dpm_get_sclk(struct radeon_device * rdev,bool low)2048d70229f7SAlex Deucher u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
2049d70229f7SAlex Deucher {
2050a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
2051a284c48aSAlex Deucher 	struct trinity_ps *requested_state = trinity_get_ps(&pi->requested_rps);
2052d70229f7SAlex Deucher 
2053d70229f7SAlex Deucher 	if (low)
2054d70229f7SAlex Deucher 		return requested_state->levels[0].sclk;
2055d70229f7SAlex Deucher 	else
2056d70229f7SAlex Deucher 		return requested_state->levels[requested_state->num_levels - 1].sclk;
2057d70229f7SAlex Deucher }
2058d70229f7SAlex Deucher 
trinity_dpm_get_mclk(struct radeon_device * rdev,bool low)2059d70229f7SAlex Deucher u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low)
2060d70229f7SAlex Deucher {
2061d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
2062d70229f7SAlex Deucher 
2063d70229f7SAlex Deucher 	return pi->sys_info.bootup_uma_clk;
2064d70229f7SAlex Deucher }
2065