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 
24c182615fSSam Ravnborg #include <linux/seq_file.h>
25c182615fSSam Ravnborg 
26c182615fSSam Ravnborg #include <drm/drm_pci.h>
27c182615fSSam Ravnborg 
28c182615fSSam Ravnborg #include "r600_dpm.h"
29d70229f7SAlex Deucher #include "radeon.h"
3001467a9bSMichele Curti #include "radeon_asic.h"
31d70229f7SAlex Deucher #include "trinity_dpm.h"
32c182615fSSam Ravnborg #include "trinityd.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 
121d70229f7SAlex Deucher static const u32 trinity_mgcg_shls_enable[] =
122d70229f7SAlex Deucher {
123d70229f7SAlex Deucher 	/* Register, Value, Mask */
124d70229f7SAlex Deucher 	0x0000802c, 0xc0000000, 0xffffffff,
125d70229f7SAlex Deucher 	0x000008f8, 0x00000000, 0xffffffff,
126d70229f7SAlex Deucher 	0x000008fc, 0x00000000, 0x000133FF,
127d70229f7SAlex Deucher 	0x000008f8, 0x00000001, 0xffffffff,
128d70229f7SAlex Deucher 	0x000008fc, 0x00000000, 0xE00B03FC,
129d70229f7SAlex Deucher 	0x00009150, 0x96944200, 0xffffffff
130d70229f7SAlex Deucher };
131d70229f7SAlex Deucher 
132d70229f7SAlex Deucher static const u32 trinity_mgcg_shls_disable[] =
133d70229f7SAlex Deucher {
134d70229f7SAlex Deucher 	/* Register, Value, Mask */
135d70229f7SAlex Deucher 	0x0000802c, 0xc0000000, 0xffffffff,
136d70229f7SAlex Deucher 	0x00009150, 0x00600000, 0xffffffff,
137d70229f7SAlex Deucher 	0x000008f8, 0x00000000, 0xffffffff,
138d70229f7SAlex Deucher 	0x000008fc, 0xffffffff, 0x000133FF,
139d70229f7SAlex Deucher 	0x000008f8, 0x00000001, 0xffffffff,
140d70229f7SAlex Deucher 	0x000008fc, 0xffffffff, 0xE00B03FC
141d70229f7SAlex Deucher };
142d70229f7SAlex Deucher #endif
143d70229f7SAlex Deucher 
144d70229f7SAlex Deucher #ifndef TRINITY_SYSLS_SEQUENCE
145d70229f7SAlex Deucher #define TRINITY_SYSLS_SEQUENCE  100
146d70229f7SAlex Deucher 
147d70229f7SAlex Deucher static const u32 trinity_sysls_default[] =
148d70229f7SAlex Deucher {
149d70229f7SAlex Deucher 	/* Register, Value, Mask */
150d70229f7SAlex Deucher 	0x000055e8, 0x00000000, 0xffffffff,
151d70229f7SAlex Deucher 	0x0000d0bc, 0x00000000, 0xffffffff,
152d70229f7SAlex Deucher 	0x0000d8bc, 0x00000000, 0xffffffff,
153d70229f7SAlex Deucher 	0x000015c0, 0x000c1401, 0xffffffff,
154d70229f7SAlex Deucher 	0x0000264c, 0x000c0400, 0xffffffff,
155d70229f7SAlex Deucher 	0x00002648, 0x000c0400, 0xffffffff,
156d70229f7SAlex Deucher 	0x00002650, 0x000c0400, 0xffffffff,
157d70229f7SAlex Deucher 	0x000020b8, 0x000c0400, 0xffffffff,
158d70229f7SAlex Deucher 	0x000020bc, 0x000c0400, 0xffffffff,
159d70229f7SAlex Deucher 	0x000020c0, 0x000c0c80, 0xffffffff,
160d70229f7SAlex Deucher 	0x0000f4a0, 0x000000c0, 0xffffffff,
161d70229f7SAlex Deucher 	0x0000f4a4, 0x00680fff, 0xffffffff,
162d70229f7SAlex Deucher 	0x00002f50, 0x00000404, 0xffffffff,
163d70229f7SAlex Deucher 	0x000004c8, 0x00000001, 0xffffffff,
164d70229f7SAlex Deucher 	0x0000641c, 0x00000000, 0xffffffff,
165d70229f7SAlex Deucher 	0x00000c7c, 0x00000000, 0xffffffff,
166d70229f7SAlex Deucher 	0x00006dfc, 0x00000000, 0xffffffff
167d70229f7SAlex Deucher };
168d70229f7SAlex Deucher 
169d70229f7SAlex Deucher static const u32 trinity_sysls_disable[] =
170d70229f7SAlex Deucher {
171d70229f7SAlex Deucher 	/* Register, Value, Mask */
172d70229f7SAlex Deucher 	0x0000d0c0, 0x00000000, 0xffffffff,
173d70229f7SAlex Deucher 	0x0000d8c0, 0x00000000, 0xffffffff,
174d70229f7SAlex Deucher 	0x000055e8, 0x00000000, 0xffffffff,
175d70229f7SAlex Deucher 	0x0000d0bc, 0x00000000, 0xffffffff,
176d70229f7SAlex Deucher 	0x0000d8bc, 0x00000000, 0xffffffff,
177d70229f7SAlex Deucher 	0x000015c0, 0x00041401, 0xffffffff,
178d70229f7SAlex Deucher 	0x0000264c, 0x00040400, 0xffffffff,
179d70229f7SAlex Deucher 	0x00002648, 0x00040400, 0xffffffff,
180d70229f7SAlex Deucher 	0x00002650, 0x00040400, 0xffffffff,
181d70229f7SAlex Deucher 	0x000020b8, 0x00040400, 0xffffffff,
182d70229f7SAlex Deucher 	0x000020bc, 0x00040400, 0xffffffff,
183d70229f7SAlex Deucher 	0x000020c0, 0x00040c80, 0xffffffff,
184d70229f7SAlex Deucher 	0x0000f4a0, 0x000000c0, 0xffffffff,
185d70229f7SAlex Deucher 	0x0000f4a4, 0x00680000, 0xffffffff,
186d70229f7SAlex Deucher 	0x00002f50, 0x00000404, 0xffffffff,
187d70229f7SAlex Deucher 	0x000004c8, 0x00000001, 0xffffffff,
188d70229f7SAlex Deucher 	0x0000641c, 0x00007ffd, 0xffffffff,
189d70229f7SAlex Deucher 	0x00000c7c, 0x0000ff00, 0xffffffff,
190d70229f7SAlex Deucher 	0x00006dfc, 0x0000007f, 0xffffffff
191d70229f7SAlex Deucher };
192d70229f7SAlex Deucher 
193d70229f7SAlex Deucher static const u32 trinity_sysls_enable[] =
194d70229f7SAlex Deucher {
195d70229f7SAlex Deucher 	/* Register, Value, Mask */
196d70229f7SAlex Deucher 	0x000055e8, 0x00000001, 0xffffffff,
197d70229f7SAlex Deucher 	0x0000d0bc, 0x00000100, 0xffffffff,
198d70229f7SAlex Deucher 	0x0000d8bc, 0x00000100, 0xffffffff,
199d70229f7SAlex Deucher 	0x000015c0, 0x000c1401, 0xffffffff,
200d70229f7SAlex Deucher 	0x0000264c, 0x000c0400, 0xffffffff,
201d70229f7SAlex Deucher 	0x00002648, 0x000c0400, 0xffffffff,
202d70229f7SAlex Deucher 	0x00002650, 0x000c0400, 0xffffffff,
203d70229f7SAlex Deucher 	0x000020b8, 0x000c0400, 0xffffffff,
204d70229f7SAlex Deucher 	0x000020bc, 0x000c0400, 0xffffffff,
205d70229f7SAlex Deucher 	0x000020c0, 0x000c0c80, 0xffffffff,
206d70229f7SAlex Deucher 	0x0000f4a0, 0x000000c0, 0xffffffff,
207d70229f7SAlex Deucher 	0x0000f4a4, 0x00680fff, 0xffffffff,
208d70229f7SAlex Deucher 	0x00002f50, 0x00000903, 0xffffffff,
209d70229f7SAlex Deucher 	0x000004c8, 0x00000000, 0xffffffff,
210d70229f7SAlex Deucher 	0x0000641c, 0x00000000, 0xffffffff,
211d70229f7SAlex Deucher 	0x00000c7c, 0x00000000, 0xffffffff,
212d70229f7SAlex Deucher 	0x00006dfc, 0x00000000, 0xffffffff
213d70229f7SAlex Deucher };
214d70229f7SAlex Deucher #endif
215d70229f7SAlex Deucher 
216d70229f7SAlex Deucher static const u32 trinity_override_mgpg_sequences[] =
217d70229f7SAlex Deucher {
218d70229f7SAlex Deucher 	/* Register, Value */
219d70229f7SAlex Deucher 	0x00000200, 0xE030032C,
220d70229f7SAlex Deucher 	0x00000204, 0x00000FFF,
221d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
222d70229f7SAlex Deucher 	0x00000204, 0x00030301,
223d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
224d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
225d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
226d70229f7SAlex Deucher 	0x00000204, 0x00030301,
227d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
228d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
229d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
230d70229f7SAlex Deucher 	0x00000204, 0x00030301,
231d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
232d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
233d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
234d70229f7SAlex Deucher 	0x00000204, 0x00030301,
235d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
236d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
237d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
238d70229f7SAlex Deucher 	0x00000204, 0x00030301,
239d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
240d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
241d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
242d70229f7SAlex Deucher 	0x00000204, 0x00030301,
243d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
244d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
245d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
246d70229f7SAlex Deucher 	0x00000204, 0x00030301,
247d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
248d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
249d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
250d70229f7SAlex Deucher 	0x00000204, 0x00030303,
251d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
252d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
253d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
254d70229f7SAlex Deucher 	0x00000204, 0x00030303,
255d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
256d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
257d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
258d70229f7SAlex Deucher 	0x00000204, 0x00030303,
259d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
260d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
261d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
262d70229f7SAlex Deucher 	0x00000204, 0x00030303,
263d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
264d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
265d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
266d70229f7SAlex Deucher 	0x00000204, 0x00030303,
267d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
268d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
269d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
270d70229f7SAlex Deucher 	0x00000204, 0x00030303,
271d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
272d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
273d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
274d70229f7SAlex Deucher 	0x00000204, 0x00030303,
275d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
276d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
277d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
278d70229f7SAlex Deucher 	0x00000204, 0x00030303,
279d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
280d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
281d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
282d70229f7SAlex Deucher 	0x00000204, 0x00030303,
283d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
284d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
285d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
286d70229f7SAlex Deucher 	0x00000204, 0x00030303,
287d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
288d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
289d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
290d70229f7SAlex Deucher 	0x00000204, 0x00030303,
291d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
292d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
293d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
294d70229f7SAlex Deucher 	0x00000204, 0x00030303,
295d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
296d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
297d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
298d70229f7SAlex Deucher 	0x00000204, 0x00030303,
299d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
300d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
301d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
302d70229f7SAlex Deucher 	0x00000204, 0x00030303,
303d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
304d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
305d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
306d70229f7SAlex Deucher 	0x00000204, 0x00010303,
307d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
308d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
309d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
310d70229f7SAlex Deucher 	0x00000204, 0x00010303,
311d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
312d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
313d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
314d70229f7SAlex Deucher 	0x00000204, 0x00010303,
315d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
316d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
317d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
318d70229f7SAlex Deucher 	0x00000204, 0x00010303,
319d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
320d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
321d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
322d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
323d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
324d70229f7SAlex Deucher 	0x00000204, 0x00010303,
325d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
326d70229f7SAlex Deucher 	0x00000204, 0x00010303,
327d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
328d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
329d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
330d70229f7SAlex Deucher 	0x00000204, 0x00010303,
331d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
332d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
333d70229f7SAlex Deucher 	0x00000200, 0x0001f198,
334d70229f7SAlex Deucher 	0x00000204, 0x0003ffff,
335d70229f7SAlex Deucher 	0x00000200, 0x0001f19C,
336d70229f7SAlex Deucher 	0x00000204, 0x3fffffff,
337d70229f7SAlex Deucher 	0x00000200, 0xE030032C,
338d70229f7SAlex Deucher 	0x00000204, 0x00000000,
339d70229f7SAlex Deucher };
340d70229f7SAlex Deucher 
34184bcd469SAlex Deucher extern void vce_v1_0_enable_mgcg(struct radeon_device *rdev, bool enable);
342d70229f7SAlex Deucher static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
343d70229f7SAlex Deucher 						   const u32 *seq, u32 count);
344d70229f7SAlex Deucher static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev);
345940eea8eSAlex Deucher static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
346940eea8eSAlex Deucher 					     struct radeon_ps *new_rps,
347940eea8eSAlex Deucher 					     struct radeon_ps *old_rps);
348d70229f7SAlex Deucher 
349fbb74bceSAlex Deucher static struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
350d70229f7SAlex Deucher {
351d70229f7SAlex Deucher 	struct trinity_ps *ps = rps->ps_priv;
352d70229f7SAlex Deucher 
353d70229f7SAlex Deucher 	return ps;
354d70229f7SAlex Deucher }
355d70229f7SAlex Deucher 
356fbb74bceSAlex Deucher static struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)
357d70229f7SAlex Deucher {
358d70229f7SAlex Deucher 	struct trinity_power_info *pi = rdev->pm.dpm.priv;
359d70229f7SAlex Deucher 
360d70229f7SAlex Deucher 	return pi;
361d70229f7SAlex Deucher }
362d70229f7SAlex Deucher 
363d70229f7SAlex Deucher static void trinity_gfx_powergating_initialize(struct radeon_device *rdev)
364d70229f7SAlex Deucher {
365d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
366d70229f7SAlex Deucher 	u32 p, u;
367d70229f7SAlex Deucher 	u32 value;
368d70229f7SAlex Deucher 	struct atom_clock_dividers dividers;
3699d45ad5aSAlex Deucher 	u32 xclk = radeon_get_xclk(rdev);
370d70229f7SAlex Deucher 	u32 sssd = 1;
371d70229f7SAlex Deucher 	int ret;
372d70229f7SAlex Deucher 	u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
373d70229f7SAlex Deucher 
374d70229f7SAlex Deucher 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
375d70229f7SAlex Deucher 					     25000, false, &dividers);
376d70229f7SAlex Deucher 	if (ret)
377d70229f7SAlex Deucher 		return;
378d70229f7SAlex Deucher 
379d70229f7SAlex Deucher 	value = RREG32_SMC(GFX_POWER_GATING_CNTL);
380d70229f7SAlex Deucher 	value &= ~(SSSD_MASK | PDS_DIV_MASK);
381d70229f7SAlex Deucher 	if (sssd)
382d70229f7SAlex Deucher 		value |= SSSD(1);
383d70229f7SAlex Deucher 	value |= PDS_DIV(dividers.post_div);
384d70229f7SAlex Deucher 	WREG32_SMC(GFX_POWER_GATING_CNTL, value);
385d70229f7SAlex Deucher 
386d70229f7SAlex Deucher 	r600_calculate_u_and_p(500, xclk, 16, &p, &u);
387d70229f7SAlex Deucher 
388d70229f7SAlex Deucher 	WREG32(CG_PG_CTRL, SP(p) | SU(u));
389d70229f7SAlex Deucher 
390d70229f7SAlex Deucher 	WREG32_P(CG_GIPOTS, CG_GIPOT(p), ~CG_GIPOT_MASK);
391d70229f7SAlex Deucher 
392d70229f7SAlex Deucher 	/* XXX double check hw_rev */
393d70229f7SAlex Deucher 	if (pi->override_dynamic_mgpg && (hw_rev == 0))
394d70229f7SAlex Deucher 		trinity_override_dynamic_mg_powergating(rdev);
395d70229f7SAlex Deucher 
396d70229f7SAlex Deucher }
397d70229f7SAlex Deucher 
398d70229f7SAlex Deucher #define CGCG_CGTT_LOCAL0_MASK       0xFFFF33FF
399d70229f7SAlex Deucher #define CGCG_CGTT_LOCAL1_MASK       0xFFFB0FFE
400d70229f7SAlex Deucher #define CGTS_SM_CTRL_REG_DISABLE    0x00600000
401d70229f7SAlex Deucher #define CGTS_SM_CTRL_REG_ENABLE     0x96944200
402d70229f7SAlex Deucher 
403d70229f7SAlex Deucher static void trinity_mg_clockgating_enable(struct radeon_device *rdev,
404d70229f7SAlex Deucher 					  bool enable)
405d70229f7SAlex Deucher {
406d70229f7SAlex Deucher 	u32 local0;
407d70229f7SAlex Deucher 	u32 local1;
408d70229f7SAlex Deucher 
409d70229f7SAlex Deucher 	if (enable) {
410d70229f7SAlex Deucher 		local0 = RREG32_CG(CG_CGTT_LOCAL_0);
411d70229f7SAlex Deucher 		local1 = RREG32_CG(CG_CGTT_LOCAL_1);
412d70229f7SAlex Deucher 
413d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_0,
414d70229f7SAlex Deucher 			  (0x00380000 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
415d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_1,
416d70229f7SAlex Deucher 			  (0x0E000000 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
417d70229f7SAlex Deucher 
418d70229f7SAlex Deucher 		WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_ENABLE);
419d70229f7SAlex Deucher 	} else {
420d70229f7SAlex Deucher 		WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_DISABLE);
421d70229f7SAlex Deucher 
422d70229f7SAlex Deucher 		local0 = RREG32_CG(CG_CGTT_LOCAL_0);
423d70229f7SAlex Deucher 		local1 = RREG32_CG(CG_CGTT_LOCAL_1);
424d70229f7SAlex Deucher 
425d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_0,
426d70229f7SAlex Deucher 			  CGCG_CGTT_LOCAL0_MASK | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
427d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_1,
428d70229f7SAlex Deucher 			  CGCG_CGTT_LOCAL1_MASK | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
429d70229f7SAlex Deucher 	}
430d70229f7SAlex Deucher }
431d70229f7SAlex Deucher 
432d70229f7SAlex Deucher static void trinity_mg_clockgating_initialize(struct radeon_device *rdev)
433d70229f7SAlex Deucher {
434d70229f7SAlex Deucher 	u32 count;
435d70229f7SAlex Deucher 	const u32 *seq = NULL;
436d70229f7SAlex Deucher 
437d70229f7SAlex Deucher 	seq = &trinity_mgcg_shls_default[0];
438d70229f7SAlex Deucher 	count = sizeof(trinity_mgcg_shls_default) / (3 * sizeof(u32));
439d70229f7SAlex Deucher 
440d70229f7SAlex Deucher 	trinity_program_clk_gating_hw_sequence(rdev, seq, count);
441d70229f7SAlex Deucher }
442d70229f7SAlex Deucher 
443d70229f7SAlex Deucher static void trinity_gfx_clockgating_enable(struct radeon_device *rdev,
444d70229f7SAlex Deucher 					   bool enable)
445d70229f7SAlex Deucher {
446d70229f7SAlex Deucher 	if (enable) {
447d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
448d70229f7SAlex Deucher 	} else {
449d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
450d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
451d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
452d70229f7SAlex Deucher 		RREG32(GB_ADDR_CONFIG);
453d70229f7SAlex Deucher 	}
454d70229f7SAlex Deucher }
455d70229f7SAlex Deucher 
456d70229f7SAlex Deucher static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
457d70229f7SAlex Deucher 						   const u32 *seq, u32 count)
458d70229f7SAlex Deucher {
459d70229f7SAlex Deucher 	u32 i, length = count * 3;
460d70229f7SAlex Deucher 
461d70229f7SAlex Deucher 	for (i = 0; i < length; i += 3)
462d70229f7SAlex Deucher 		WREG32_P(seq[i], seq[i+1], ~seq[i+2]);
463d70229f7SAlex Deucher }
464d70229f7SAlex Deucher 
465d70229f7SAlex Deucher static void trinity_program_override_mgpg_sequences(struct radeon_device *rdev,
466d70229f7SAlex Deucher 						    const u32 *seq, u32 count)
467d70229f7SAlex Deucher {
468d70229f7SAlex Deucher 	u32  i, length = count * 2;
469d70229f7SAlex Deucher 
470d70229f7SAlex Deucher 	for (i = 0; i < length; i += 2)
471d70229f7SAlex Deucher 		WREG32(seq[i], seq[i+1]);
472d70229f7SAlex Deucher 
473d70229f7SAlex Deucher }
474d70229f7SAlex Deucher 
475d70229f7SAlex Deucher static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev)
476d70229f7SAlex Deucher {
477d70229f7SAlex Deucher 	u32 count;
478d70229f7SAlex Deucher 	const u32 *seq = NULL;
479d70229f7SAlex Deucher 
480d70229f7SAlex Deucher 	seq = &trinity_override_mgpg_sequences[0];
481d70229f7SAlex Deucher 	count = sizeof(trinity_override_mgpg_sequences) / (2 * sizeof(u32));
482d70229f7SAlex Deucher 
483d70229f7SAlex Deucher 	trinity_program_override_mgpg_sequences(rdev, seq, count);
484d70229f7SAlex Deucher }
485d70229f7SAlex Deucher 
486d70229f7SAlex Deucher static void trinity_ls_clockgating_enable(struct radeon_device *rdev,
487d70229f7SAlex Deucher 					  bool enable)
488d70229f7SAlex Deucher {
489d70229f7SAlex Deucher 	u32 count;
490d70229f7SAlex Deucher 	const u32 *seq = NULL;
491d70229f7SAlex Deucher 
492d70229f7SAlex Deucher 	if (enable) {
493d70229f7SAlex Deucher 		seq = &trinity_sysls_enable[0];
494d70229f7SAlex Deucher 		count = sizeof(trinity_sysls_enable) / (3 * sizeof(u32));
495d70229f7SAlex Deucher 	} else {
496d70229f7SAlex Deucher 		seq = &trinity_sysls_disable[0];
497d70229f7SAlex Deucher 		count = sizeof(trinity_sysls_disable) / (3 * sizeof(u32));
498d70229f7SAlex Deucher 	}
499d70229f7SAlex Deucher 
500d70229f7SAlex Deucher 	trinity_program_clk_gating_hw_sequence(rdev, seq, count);
501d70229f7SAlex Deucher }
502d70229f7SAlex Deucher 
503d70229f7SAlex Deucher static void trinity_gfx_powergating_enable(struct radeon_device *rdev,
504d70229f7SAlex Deucher 					   bool enable)
505d70229f7SAlex Deucher {
506d70229f7SAlex Deucher 	if (enable) {
507d70229f7SAlex Deucher 		if (RREG32_SMC(CC_SMU_TST_EFUSE1_MISC) & RB_BACKEND_DISABLE_MASK)
508d70229f7SAlex Deucher 			WREG32_SMC(SMU_SCRATCH_A, (RREG32_SMC(SMU_SCRATCH_A) | 0x01));
509d70229f7SAlex Deucher 
510d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
511d70229f7SAlex Deucher 	} else {
512d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_PWR_DOWN_EN);
513d70229f7SAlex Deucher 		RREG32(GB_ADDR_CONFIG);
514d70229f7SAlex Deucher 	}
515d70229f7SAlex Deucher }
516d70229f7SAlex Deucher 
517d70229f7SAlex Deucher static void trinity_gfx_dynamic_mgpg_enable(struct radeon_device *rdev,
518d70229f7SAlex Deucher 					    bool enable)
519d70229f7SAlex Deucher {
520d70229f7SAlex Deucher 	u32 value;
521d70229f7SAlex Deucher 
522d70229f7SAlex Deucher 	if (enable) {
523d70229f7SAlex Deucher 		value = RREG32_SMC(PM_I_CNTL_1);
524d70229f7SAlex Deucher 		value &= ~DS_PG_CNTL_MASK;
525d70229f7SAlex Deucher 		value |= DS_PG_CNTL(1);
526d70229f7SAlex Deucher 		WREG32_SMC(PM_I_CNTL_1, value);
527d70229f7SAlex Deucher 
528d70229f7SAlex Deucher 		value = RREG32_SMC(SMU_S_PG_CNTL);
529d70229f7SAlex Deucher 		value &= ~DS_PG_EN_MASK;
530d70229f7SAlex Deucher 		value |= DS_PG_EN(1);
531d70229f7SAlex Deucher 		WREG32_SMC(SMU_S_PG_CNTL, value);
532d70229f7SAlex Deucher 	} else {
533d70229f7SAlex Deucher 		value = RREG32_SMC(SMU_S_PG_CNTL);
534d70229f7SAlex Deucher 		value &= ~DS_PG_EN_MASK;
535d70229f7SAlex Deucher 		WREG32_SMC(SMU_S_PG_CNTL, value);
536d70229f7SAlex Deucher 
537d70229f7SAlex Deucher 		value = RREG32_SMC(PM_I_CNTL_1);
538d70229f7SAlex Deucher 		value &= ~DS_PG_CNTL_MASK;
539d70229f7SAlex Deucher 		WREG32_SMC(PM_I_CNTL_1, value);
540d70229f7SAlex Deucher 	}
541d70229f7SAlex Deucher 
542d70229f7SAlex Deucher 	trinity_gfx_dynamic_mgpg_config(rdev);
543d70229f7SAlex Deucher 
544d70229f7SAlex Deucher }
545d70229f7SAlex Deucher 
546d70229f7SAlex Deucher static void trinity_enable_clock_power_gating(struct radeon_device *rdev)
547d70229f7SAlex Deucher {
548d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
549d70229f7SAlex Deucher 
550d70229f7SAlex Deucher 	if (pi->enable_gfx_clock_gating)
551d70229f7SAlex Deucher 		sumo_gfx_clockgating_initialize(rdev);
552d70229f7SAlex Deucher 	if (pi->enable_mg_clock_gating)
553d70229f7SAlex Deucher 		trinity_mg_clockgating_initialize(rdev);
554d70229f7SAlex Deucher 	if (pi->enable_gfx_power_gating)
555d70229f7SAlex Deucher 		trinity_gfx_powergating_initialize(rdev);
556d70229f7SAlex Deucher 	if (pi->enable_mg_clock_gating) {
557d70229f7SAlex Deucher 		trinity_ls_clockgating_enable(rdev, true);
558d70229f7SAlex Deucher 		trinity_mg_clockgating_enable(rdev, true);
559d70229f7SAlex Deucher 	}
560d70229f7SAlex Deucher 	if (pi->enable_gfx_clock_gating)
561d70229f7SAlex Deucher 		trinity_gfx_clockgating_enable(rdev, true);
562d70229f7SAlex Deucher 	if (pi->enable_gfx_dynamic_mgpg)
563d70229f7SAlex Deucher 		trinity_gfx_dynamic_mgpg_enable(rdev, true);
564d70229f7SAlex Deucher 	if (pi->enable_gfx_power_gating)
565d70229f7SAlex Deucher 		trinity_gfx_powergating_enable(rdev, true);
566d70229f7SAlex Deucher }
567d70229f7SAlex Deucher 
568d70229f7SAlex Deucher static void trinity_disable_clock_power_gating(struct radeon_device *rdev)
569d70229f7SAlex Deucher {
570d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
571d70229f7SAlex Deucher 
572d70229f7SAlex Deucher 	if (pi->enable_gfx_power_gating)
573d70229f7SAlex Deucher 		trinity_gfx_powergating_enable(rdev, false);
574d70229f7SAlex Deucher 	if (pi->enable_gfx_dynamic_mgpg)
575d70229f7SAlex Deucher 		trinity_gfx_dynamic_mgpg_enable(rdev, false);
576d70229f7SAlex Deucher 	if (pi->enable_gfx_clock_gating)
577d70229f7SAlex Deucher 		trinity_gfx_clockgating_enable(rdev, false);
578d70229f7SAlex Deucher 	if (pi->enable_mg_clock_gating) {
579d70229f7SAlex Deucher 		trinity_mg_clockgating_enable(rdev, false);
580d70229f7SAlex Deucher 		trinity_ls_clockgating_enable(rdev, false);
581d70229f7SAlex Deucher 	}
582d70229f7SAlex Deucher }
583d70229f7SAlex Deucher 
584d70229f7SAlex Deucher static void trinity_set_divider_value(struct radeon_device *rdev,
585d70229f7SAlex Deucher 				      u32 index, u32 sclk)
586d70229f7SAlex Deucher {
587d70229f7SAlex Deucher 	struct atom_clock_dividers  dividers;
588d70229f7SAlex Deucher 	int ret;
589d70229f7SAlex Deucher 	u32 value;
590d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
591d70229f7SAlex Deucher 
592d70229f7SAlex Deucher 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
593d70229f7SAlex Deucher 					     sclk, false, &dividers);
594d70229f7SAlex Deucher 	if (ret)
595d70229f7SAlex Deucher 		return;
596d70229f7SAlex Deucher 
597d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
598d70229f7SAlex Deucher 	value &= ~CLK_DIVIDER_MASK;
599d70229f7SAlex Deucher 	value |= CLK_DIVIDER(dividers.post_div);
600d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
601d70229f7SAlex Deucher 
602d70229f7SAlex Deucher 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
603d70229f7SAlex Deucher 					     sclk/2, false, &dividers);
604d70229f7SAlex Deucher 	if (ret)
605d70229f7SAlex Deucher 		return;
606d70229f7SAlex Deucher 
607d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix);
608d70229f7SAlex Deucher 	value &= ~PD_SCLK_DIVIDER_MASK;
609d70229f7SAlex Deucher 	value |= PD_SCLK_DIVIDER(dividers.post_div);
610d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix, value);
611d70229f7SAlex Deucher }
612d70229f7SAlex Deucher 
613d70229f7SAlex Deucher static void trinity_set_ds_dividers(struct radeon_device *rdev,
614d70229f7SAlex Deucher 				    u32 index, u32 divider)
615d70229f7SAlex Deucher {
616d70229f7SAlex Deucher 	u32 value;
617d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
618d70229f7SAlex Deucher 
619d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
620d70229f7SAlex Deucher 	value &= ~DS_DIV_MASK;
621d70229f7SAlex Deucher 	value |= DS_DIV(divider);
622d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
623d70229f7SAlex Deucher }
624d70229f7SAlex Deucher 
625d70229f7SAlex Deucher static void trinity_set_ss_dividers(struct radeon_device *rdev,
626d70229f7SAlex Deucher 				    u32 index, u32 divider)
627d70229f7SAlex Deucher {
628d70229f7SAlex Deucher 	u32 value;
629d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
630d70229f7SAlex Deucher 
631d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
632d70229f7SAlex Deucher 	value &= ~DS_SH_DIV_MASK;
633d70229f7SAlex Deucher 	value |= DS_SH_DIV(divider);
634d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
635d70229f7SAlex Deucher }
636d70229f7SAlex Deucher 
637d70229f7SAlex Deucher static void trinity_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
638d70229f7SAlex Deucher {
639d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
640d70229f7SAlex Deucher 	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid);
641d70229f7SAlex Deucher 	u32 value;
642d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
643d70229f7SAlex Deucher 
644d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
645d70229f7SAlex Deucher 	value &= ~VID_MASK;
646d70229f7SAlex Deucher 	value |= VID(vid_7bit);
647d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
648d70229f7SAlex Deucher 
649d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
650d70229f7SAlex Deucher 	value &= ~LVRT_MASK;
651d70229f7SAlex Deucher 	value |= LVRT(0);
652d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
653d70229f7SAlex Deucher }
654d70229f7SAlex Deucher 
655d70229f7SAlex Deucher static void trinity_set_allos_gnb_slow(struct radeon_device *rdev,
656d70229f7SAlex Deucher 				       u32 index, u32 gnb_slow)
657d70229f7SAlex Deucher {
658d70229f7SAlex Deucher 	u32 value;
659d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
660d70229f7SAlex Deucher 
661d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
662d70229f7SAlex Deucher 	value &= ~GNB_SLOW_MASK;
663d70229f7SAlex Deucher 	value |= GNB_SLOW(gnb_slow);
664d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
665d70229f7SAlex Deucher }
666d70229f7SAlex Deucher 
667d70229f7SAlex Deucher static void trinity_set_force_nbp_state(struct radeon_device *rdev,
668d70229f7SAlex Deucher 					u32 index, u32 force_nbp_state)
669d70229f7SAlex Deucher {
670d70229f7SAlex Deucher 	u32 value;
671d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
672d70229f7SAlex Deucher 
673d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
674d70229f7SAlex Deucher 	value &= ~FORCE_NBPS1_MASK;
675d70229f7SAlex Deucher 	value |= FORCE_NBPS1(force_nbp_state);
676d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
677d70229f7SAlex Deucher }
678d70229f7SAlex Deucher 
679d70229f7SAlex Deucher static void trinity_set_display_wm(struct radeon_device *rdev,
680d70229f7SAlex Deucher 				   u32 index, u32 wm)
681d70229f7SAlex Deucher {
682d70229f7SAlex Deucher 	u32 value;
683d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
684d70229f7SAlex Deucher 
685d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
686d70229f7SAlex Deucher 	value &= ~DISPLAY_WM_MASK;
687d70229f7SAlex Deucher 	value |= DISPLAY_WM(wm);
688d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
689d70229f7SAlex Deucher }
690d70229f7SAlex Deucher 
691d70229f7SAlex Deucher static void trinity_set_vce_wm(struct radeon_device *rdev,
692d70229f7SAlex Deucher 			       u32 index, u32 wm)
693d70229f7SAlex Deucher {
694d70229f7SAlex Deucher 	u32 value;
695d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
696d70229f7SAlex Deucher 
697d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
698d70229f7SAlex Deucher 	value &= ~VCE_WM_MASK;
699d70229f7SAlex Deucher 	value |= VCE_WM(wm);
700d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
701d70229f7SAlex Deucher }
702d70229f7SAlex Deucher 
703d70229f7SAlex Deucher static void trinity_set_at(struct radeon_device *rdev,
704d70229f7SAlex Deucher 			   u32 index, u32 at)
705d70229f7SAlex Deucher {
706d70229f7SAlex Deucher 	u32 value;
707d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
708d70229f7SAlex Deucher 
709d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix);
710d70229f7SAlex Deucher 	value &= ~AT_MASK;
711d70229f7SAlex Deucher 	value |= AT(at);
712d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix, value);
713d70229f7SAlex Deucher }
714d70229f7SAlex Deucher 
715d70229f7SAlex Deucher static void trinity_program_power_level(struct radeon_device *rdev,
716d70229f7SAlex Deucher 					struct trinity_pl *pl, u32 index)
717d70229f7SAlex Deucher {
718d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
719d70229f7SAlex Deucher 
720d70229f7SAlex Deucher 	if (index >= SUMO_MAX_HARDWARE_POWERLEVELS)
721d70229f7SAlex Deucher 		return;
722d70229f7SAlex Deucher 
723d70229f7SAlex Deucher 	trinity_set_divider_value(rdev, index, pl->sclk);
724d70229f7SAlex Deucher 	trinity_set_vid(rdev, index, pl->vddc_index);
725d70229f7SAlex Deucher 	trinity_set_ss_dividers(rdev, index, pl->ss_divider_index);
726d70229f7SAlex Deucher 	trinity_set_ds_dividers(rdev, index, pl->ds_divider_index);
727d70229f7SAlex Deucher 	trinity_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
728d70229f7SAlex Deucher 	trinity_set_force_nbp_state(rdev, index, pl->force_nbp_state);
729d70229f7SAlex Deucher 	trinity_set_display_wm(rdev, index, pl->display_wm);
730d70229f7SAlex Deucher 	trinity_set_vce_wm(rdev, index, pl->vce_wm);
731d70229f7SAlex Deucher 	trinity_set_at(rdev, index, pi->at[index]);
732d70229f7SAlex Deucher }
733d70229f7SAlex Deucher 
734d70229f7SAlex Deucher static void trinity_power_level_enable_disable(struct radeon_device *rdev,
735d70229f7SAlex Deucher 					       u32 index, bool enable)
736d70229f7SAlex Deucher {
737d70229f7SAlex Deucher 	u32 value;
738d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
739d70229f7SAlex Deucher 
740d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
741d70229f7SAlex Deucher 	value &= ~STATE_VALID_MASK;
742d70229f7SAlex Deucher 	if (enable)
743d70229f7SAlex Deucher 		value |= STATE_VALID(1);
744d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
745d70229f7SAlex Deucher }
746d70229f7SAlex Deucher 
747d70229f7SAlex Deucher static bool trinity_dpm_enabled(struct radeon_device *rdev)
748d70229f7SAlex Deucher {
749d70229f7SAlex Deucher 	if (RREG32_SMC(SMU_SCLK_DPM_CNTL) & SCLK_DPM_EN(1))
750d70229f7SAlex Deucher 		return true;
751d70229f7SAlex Deucher 	else
752d70229f7SAlex Deucher 		return false;
753d70229f7SAlex Deucher }
754d70229f7SAlex Deucher 
755d70229f7SAlex Deucher static void trinity_start_dpm(struct radeon_device *rdev)
756d70229f7SAlex Deucher {
757d70229f7SAlex Deucher 	u32 value = RREG32_SMC(SMU_SCLK_DPM_CNTL);
758d70229f7SAlex Deucher 
759d70229f7SAlex Deucher 	value &= ~(SCLK_DPM_EN_MASK | SCLK_DPM_BOOT_STATE_MASK | VOLTAGE_CHG_EN_MASK);
760d70229f7SAlex Deucher 	value |= SCLK_DPM_EN(1) | SCLK_DPM_BOOT_STATE(0) | VOLTAGE_CHG_EN(1);
761d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_CNTL, value);
762d70229f7SAlex Deucher 
763d70229f7SAlex Deucher 	WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
764d70229f7SAlex Deucher 	WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~EN);
765d70229f7SAlex Deucher 
766d70229f7SAlex Deucher 	trinity_dpm_config(rdev, true);
767d70229f7SAlex Deucher }
768d70229f7SAlex Deucher 
769d70229f7SAlex Deucher static void trinity_wait_for_dpm_enabled(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(SCLK_PWRMGT_CNTL) & DYNAMIC_PM_EN)
775d70229f7SAlex Deucher 			break;
776d70229f7SAlex Deucher 		udelay(1);
777d70229f7SAlex Deucher 	}
778d70229f7SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
779d70229f7SAlex Deucher 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_STATE_MASK) == 0)
780d70229f7SAlex Deucher 			break;
781d70229f7SAlex Deucher 		udelay(1);
782d70229f7SAlex Deucher 	}
783d70229f7SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
784d70229f7SAlex Deucher 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
785d70229f7SAlex Deucher 			break;
786d70229f7SAlex Deucher 		udelay(1);
787d70229f7SAlex Deucher 	}
788d70229f7SAlex Deucher }
789d70229f7SAlex Deucher 
790d70229f7SAlex Deucher static void trinity_stop_dpm(struct radeon_device *rdev)
791d70229f7SAlex Deucher {
792d70229f7SAlex Deucher 	u32 sclk_dpm_cntl;
793d70229f7SAlex Deucher 
794d70229f7SAlex Deucher 	WREG32_P(CG_CG_VOLTAGE_CNTL, EN, ~EN);
795d70229f7SAlex Deucher 
796d70229f7SAlex Deucher 	sclk_dpm_cntl = RREG32_SMC(SMU_SCLK_DPM_CNTL);
797d70229f7SAlex Deucher 	sclk_dpm_cntl &= ~(SCLK_DPM_EN_MASK | VOLTAGE_CHG_EN_MASK);
798d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_CNTL, sclk_dpm_cntl);
799d70229f7SAlex Deucher 
800d70229f7SAlex Deucher 	trinity_dpm_config(rdev, false);
801d70229f7SAlex Deucher }
802d70229f7SAlex Deucher 
803d70229f7SAlex Deucher static void trinity_start_am(struct radeon_device *rdev)
804d70229f7SAlex Deucher {
805d70229f7SAlex Deucher 	WREG32_P(SCLK_PWRMGT_CNTL, 0, ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
806d70229f7SAlex Deucher }
807d70229f7SAlex Deucher 
808d70229f7SAlex Deucher static void trinity_reset_am(struct radeon_device *rdev)
809d70229f7SAlex Deucher {
810d70229f7SAlex Deucher 	WREG32_P(SCLK_PWRMGT_CNTL, RESET_SCLK_CNT | RESET_BUSY_CNT,
811d70229f7SAlex Deucher 		 ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
812d70229f7SAlex Deucher }
813d70229f7SAlex Deucher 
814d70229f7SAlex Deucher static void trinity_wait_for_level_0(struct radeon_device *rdev)
815d70229f7SAlex Deucher {
816d70229f7SAlex Deucher 	int i;
817d70229f7SAlex Deucher 
818d70229f7SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
819d70229f7SAlex Deucher 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
820d70229f7SAlex Deucher 			break;
821d70229f7SAlex Deucher 		udelay(1);
822d70229f7SAlex Deucher 	}
823d70229f7SAlex Deucher }
824d70229f7SAlex Deucher 
825d70229f7SAlex Deucher static void trinity_enable_power_level_0(struct radeon_device *rdev)
826d70229f7SAlex Deucher {
827d70229f7SAlex Deucher 	trinity_power_level_enable_disable(rdev, 0, true);
828d70229f7SAlex Deucher }
829d70229f7SAlex Deucher 
830d70229f7SAlex Deucher static void trinity_force_level_0(struct radeon_device *rdev)
831d70229f7SAlex Deucher {
832d70229f7SAlex Deucher 	trinity_dpm_force_state(rdev, 0);
833d70229f7SAlex Deucher }
834d70229f7SAlex Deucher 
835d70229f7SAlex Deucher static void trinity_unforce_levels(struct radeon_device *rdev)
836d70229f7SAlex Deucher {
837d70229f7SAlex Deucher 	trinity_dpm_no_forced_level(rdev);
838d70229f7SAlex Deucher }
839d70229f7SAlex Deucher 
840940eea8eSAlex Deucher static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev,
841940eea8eSAlex Deucher 						struct radeon_ps *new_rps,
842940eea8eSAlex Deucher 						struct radeon_ps *old_rps)
843d70229f7SAlex Deucher {
844940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
845940eea8eSAlex Deucher 	struct trinity_ps *old_ps = trinity_get_ps(old_rps);
846d70229f7SAlex Deucher 	u32 i;
847d70229f7SAlex Deucher 	u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
848d70229f7SAlex Deucher 
849d70229f7SAlex Deucher 	for (i = 0; i < new_ps->num_levels; i++) {
850d70229f7SAlex Deucher 		trinity_program_power_level(rdev, &new_ps->levels[i], i);
851d70229f7SAlex Deucher 		trinity_power_level_enable_disable(rdev, i, true);
852d70229f7SAlex Deucher 	}
853d70229f7SAlex Deucher 
854d70229f7SAlex Deucher 	for (i = new_ps->num_levels; i < n_current_state_levels; i++)
855d70229f7SAlex Deucher 		trinity_power_level_enable_disable(rdev, i, false);
856d70229f7SAlex Deucher }
857d70229f7SAlex Deucher 
858d70229f7SAlex Deucher static void trinity_program_bootup_state(struct radeon_device *rdev)
859d70229f7SAlex Deucher {
860d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
861d70229f7SAlex Deucher 	u32 i;
862d70229f7SAlex Deucher 
863d70229f7SAlex Deucher 	trinity_program_power_level(rdev, &pi->boot_pl, 0);
864d70229f7SAlex Deucher 	trinity_power_level_enable_disable(rdev, 0, true);
865d70229f7SAlex Deucher 
866d70229f7SAlex Deucher 	for (i = 1; i < 8; i++)
867d70229f7SAlex Deucher 		trinity_power_level_enable_disable(rdev, i, false);
868d70229f7SAlex Deucher }
869d70229f7SAlex Deucher 
8700c4aaeaeSAlex Deucher static void trinity_setup_uvd_clock_table(struct radeon_device *rdev,
8710c4aaeaeSAlex Deucher 					  struct radeon_ps *rps)
8720c4aaeaeSAlex Deucher {
8730c4aaeaeSAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
8740c4aaeaeSAlex Deucher 	u32 uvdstates = (ps->vclk_low_divider |
8750c4aaeaeSAlex Deucher 			 ps->vclk_high_divider << 8 |
8760c4aaeaeSAlex Deucher 			 ps->dclk_low_divider << 16 |
8770c4aaeaeSAlex Deucher 			 ps->dclk_high_divider << 24);
8780c4aaeaeSAlex Deucher 
8790c4aaeaeSAlex Deucher 	WREG32_SMC(SMU_UVD_DPM_STATES, uvdstates);
8800c4aaeaeSAlex Deucher }
8810c4aaeaeSAlex Deucher 
8820c4aaeaeSAlex Deucher static void trinity_setup_uvd_dpm_interval(struct radeon_device *rdev,
8830c4aaeaeSAlex Deucher 					   u32 interval)
8840c4aaeaeSAlex Deucher {
8850c4aaeaeSAlex Deucher 	u32 p, u;
8860c4aaeaeSAlex Deucher 	u32 tp = RREG32_SMC(PM_TP);
8870c4aaeaeSAlex Deucher 	u32 val;
8889d45ad5aSAlex Deucher 	u32 xclk = radeon_get_xclk(rdev);
8890c4aaeaeSAlex Deucher 
8900c4aaeaeSAlex Deucher 	r600_calculate_u_and_p(interval, xclk, 16, &p, &u);
8910c4aaeaeSAlex Deucher 
8920c4aaeaeSAlex Deucher 	val = (p + tp - 1) / tp;
8930c4aaeaeSAlex Deucher 
8940c4aaeaeSAlex Deucher 	WREG32_SMC(SMU_UVD_DPM_CNTL, val);
8950c4aaeaeSAlex Deucher }
8960c4aaeaeSAlex Deucher 
8970c4aaeaeSAlex Deucher static bool trinity_uvd_clocks_zero(struct radeon_ps *rps)
8980c4aaeaeSAlex Deucher {
8990c4aaeaeSAlex Deucher 	if ((rps->vclk == 0) && (rps->dclk == 0))
9000c4aaeaeSAlex Deucher 		return true;
9010c4aaeaeSAlex Deucher 	else
9020c4aaeaeSAlex Deucher 		return false;
9030c4aaeaeSAlex Deucher }
9040c4aaeaeSAlex Deucher 
9050c4aaeaeSAlex Deucher static bool trinity_uvd_clocks_equal(struct radeon_ps *rps1,
9060c4aaeaeSAlex Deucher 				     struct radeon_ps *rps2)
9070c4aaeaeSAlex Deucher {
9080c4aaeaeSAlex Deucher 	struct trinity_ps *ps1 = trinity_get_ps(rps1);
9090c4aaeaeSAlex Deucher 	struct trinity_ps *ps2 = trinity_get_ps(rps2);
9100c4aaeaeSAlex Deucher 
9110c4aaeaeSAlex Deucher 	if ((rps1->vclk == rps2->vclk) &&
9120c4aaeaeSAlex Deucher 	    (rps1->dclk == rps2->dclk) &&
9130c4aaeaeSAlex Deucher 	    (ps1->vclk_low_divider == ps2->vclk_low_divider) &&
9140c4aaeaeSAlex Deucher 	    (ps1->vclk_high_divider == ps2->vclk_high_divider) &&
9150c4aaeaeSAlex Deucher 	    (ps1->dclk_low_divider == ps2->dclk_low_divider) &&
9160c4aaeaeSAlex Deucher 	    (ps1->dclk_high_divider == ps2->dclk_high_divider))
9170c4aaeaeSAlex Deucher 		return true;
9180c4aaeaeSAlex Deucher 	else
9190c4aaeaeSAlex Deucher 		return false;
9200c4aaeaeSAlex Deucher }
9210c4aaeaeSAlex Deucher 
9220c4aaeaeSAlex Deucher static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
923940eea8eSAlex Deucher 				     struct radeon_ps *new_rps,
924940eea8eSAlex Deucher 				     struct radeon_ps *old_rps)
9250c4aaeaeSAlex Deucher {
9260c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
9270c4aaeaeSAlex Deucher 
92862fa44bfSAlex Deucher 	if (pi->enable_gfx_power_gating) {
92962fa44bfSAlex Deucher 		trinity_gfx_powergating_enable(rdev, false);
93062fa44bfSAlex Deucher 	}
93162fa44bfSAlex Deucher 
9320c4aaeaeSAlex Deucher 	if (pi->uvd_dpm) {
9330c4aaeaeSAlex Deucher 		if (trinity_uvd_clocks_zero(new_rps) &&
934940eea8eSAlex Deucher 		    !trinity_uvd_clocks_zero(old_rps)) {
9350c4aaeaeSAlex Deucher 			trinity_setup_uvd_dpm_interval(rdev, 0);
9360c4aaeaeSAlex Deucher 		} else if (!trinity_uvd_clocks_zero(new_rps)) {
9370c4aaeaeSAlex Deucher 			trinity_setup_uvd_clock_table(rdev, new_rps);
9380c4aaeaeSAlex Deucher 
939940eea8eSAlex Deucher 			if (trinity_uvd_clocks_zero(old_rps)) {
9400c4aaeaeSAlex Deucher 				u32 tmp = RREG32(CG_MISC_REG);
9410c4aaeaeSAlex Deucher 				tmp &= 0xfffffffd;
9420c4aaeaeSAlex Deucher 				WREG32(CG_MISC_REG, tmp);
9430c4aaeaeSAlex Deucher 
9440c4aaeaeSAlex Deucher 				radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
9450c4aaeaeSAlex Deucher 
9460c4aaeaeSAlex Deucher 				trinity_setup_uvd_dpm_interval(rdev, 3000);
9470c4aaeaeSAlex Deucher 			}
9480c4aaeaeSAlex Deucher 		}
9490c4aaeaeSAlex Deucher 		trinity_uvd_dpm_config(rdev);
9500c4aaeaeSAlex Deucher 	} else {
9510c4aaeaeSAlex Deucher 		if (trinity_uvd_clocks_zero(new_rps) ||
952940eea8eSAlex Deucher 		    trinity_uvd_clocks_equal(new_rps, old_rps))
9530c4aaeaeSAlex Deucher 			return;
9540c4aaeaeSAlex Deucher 
9550c4aaeaeSAlex Deucher 		radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
9560c4aaeaeSAlex Deucher 	}
95762fa44bfSAlex Deucher 
95862fa44bfSAlex Deucher 	if (pi->enable_gfx_power_gating) {
95962fa44bfSAlex Deucher 		trinity_gfx_powergating_enable(rdev, true);
96062fa44bfSAlex Deucher 	}
9610c4aaeaeSAlex Deucher }
9620c4aaeaeSAlex Deucher 
963940eea8eSAlex Deucher static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
964940eea8eSAlex Deucher 						       struct radeon_ps *new_rps,
965940eea8eSAlex Deucher 						       struct radeon_ps *old_rps)
9660c4aaeaeSAlex Deucher {
967940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
968940eea8eSAlex Deucher 	struct trinity_ps *current_ps = trinity_get_ps(new_rps);
9690c4aaeaeSAlex Deucher 
9700c4aaeaeSAlex Deucher 	if (new_ps->levels[new_ps->num_levels - 1].sclk >=
9710c4aaeaeSAlex Deucher 	    current_ps->levels[current_ps->num_levels - 1].sclk)
9720c4aaeaeSAlex Deucher 		return;
9730c4aaeaeSAlex Deucher 
974940eea8eSAlex Deucher 	trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
9750c4aaeaeSAlex Deucher }
9760c4aaeaeSAlex Deucher 
977940eea8eSAlex Deucher static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
978940eea8eSAlex Deucher 						      struct radeon_ps *new_rps,
979940eea8eSAlex Deucher 						      struct radeon_ps *old_rps)
9800c4aaeaeSAlex Deucher {
981940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
982940eea8eSAlex Deucher 	struct trinity_ps *current_ps = trinity_get_ps(old_rps);
9830c4aaeaeSAlex Deucher 
9840c4aaeaeSAlex Deucher 	if (new_ps->levels[new_ps->num_levels - 1].sclk <
9850c4aaeaeSAlex Deucher 	    current_ps->levels[current_ps->num_levels - 1].sclk)
9860c4aaeaeSAlex Deucher 		return;
9870c4aaeaeSAlex Deucher 
988940eea8eSAlex Deucher 	trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
9890c4aaeaeSAlex Deucher }
9900c4aaeaeSAlex Deucher 
99111fe3d6eSAlex Deucher static void trinity_set_vce_clock(struct radeon_device *rdev,
99211fe3d6eSAlex Deucher 				  struct radeon_ps *new_rps,
99311fe3d6eSAlex Deucher 				  struct radeon_ps *old_rps)
99411fe3d6eSAlex Deucher {
99511fe3d6eSAlex Deucher 	if ((old_rps->evclk != new_rps->evclk) ||
99684bcd469SAlex Deucher 	    (old_rps->ecclk != new_rps->ecclk)) {
99784bcd469SAlex Deucher 		/* turn the clocks on when encoding, off otherwise */
99884bcd469SAlex Deucher 		if (new_rps->evclk || new_rps->ecclk)
99984bcd469SAlex Deucher 			vce_v1_0_enable_mgcg(rdev, false);
100084bcd469SAlex Deucher 		else
100184bcd469SAlex Deucher 			vce_v1_0_enable_mgcg(rdev, true);
100211fe3d6eSAlex Deucher 		radeon_set_vce_clocks(rdev, new_rps->evclk, new_rps->ecclk);
100311fe3d6eSAlex Deucher 	}
100484bcd469SAlex Deucher }
100511fe3d6eSAlex Deucher 
1006d70229f7SAlex Deucher static void trinity_program_ttt(struct radeon_device *rdev)
1007d70229f7SAlex Deucher {
1008d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1009d70229f7SAlex Deucher 	u32 value = RREG32_SMC(SMU_SCLK_DPM_TTT);
1010d70229f7SAlex Deucher 
1011d70229f7SAlex Deucher 	value &= ~(HT_MASK | LT_MASK);
1012d70229f7SAlex Deucher 	value |= HT((pi->thermal_auto_throttling + 49) * 8);
1013d70229f7SAlex Deucher 	value |= LT((pi->thermal_auto_throttling + 49 - pi->sys_info.htc_hyst_lmt) * 8);
1014d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_TTT, value);
1015d70229f7SAlex Deucher }
1016d70229f7SAlex Deucher 
1017d70229f7SAlex Deucher static void trinity_enable_att(struct radeon_device *rdev)
1018d70229f7SAlex Deucher {
1019d70229f7SAlex Deucher 	u32 value = RREG32_SMC(SMU_SCLK_DPM_TT_CNTL);
1020d70229f7SAlex Deucher 
1021d70229f7SAlex Deucher 	value &= ~SCLK_TT_EN_MASK;
1022d70229f7SAlex Deucher 	value |= SCLK_TT_EN(1);
1023d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_TT_CNTL, value);
1024d70229f7SAlex Deucher }
1025d70229f7SAlex Deucher 
1026d70229f7SAlex Deucher static void trinity_program_sclk_dpm(struct radeon_device *rdev)
1027d70229f7SAlex Deucher {
1028d70229f7SAlex Deucher 	u32 p, u;
1029d70229f7SAlex Deucher 	u32 tp = RREG32_SMC(PM_TP);
1030d70229f7SAlex Deucher 	u32 ni;
10319d45ad5aSAlex Deucher 	u32 xclk = radeon_get_xclk(rdev);
1032d70229f7SAlex Deucher 	u32 value;
1033d70229f7SAlex Deucher 
1034d70229f7SAlex Deucher 	r600_calculate_u_and_p(400, xclk, 16, &p, &u);
1035d70229f7SAlex Deucher 
1036d70229f7SAlex Deucher 	ni = (p + tp - 1) / tp;
1037d70229f7SAlex Deucher 
1038d70229f7SAlex Deucher 	value = RREG32_SMC(PM_I_CNTL_1);
1039d70229f7SAlex Deucher 	value &= ~SCLK_DPM_MASK;
1040d70229f7SAlex Deucher 	value |= SCLK_DPM(ni);
1041d70229f7SAlex Deucher 	WREG32_SMC(PM_I_CNTL_1, value);
1042d70229f7SAlex Deucher }
1043d70229f7SAlex Deucher 
1044d70229f7SAlex Deucher static int trinity_set_thermal_temperature_range(struct radeon_device *rdev,
1045d70229f7SAlex Deucher 						 int min_temp, int max_temp)
1046d70229f7SAlex Deucher {
1047d70229f7SAlex Deucher 	int low_temp = 0 * 1000;
1048d70229f7SAlex Deucher 	int high_temp = 255 * 1000;
1049d70229f7SAlex Deucher 
1050d70229f7SAlex Deucher 	if (low_temp < min_temp)
1051d70229f7SAlex Deucher 		low_temp = min_temp;
1052d70229f7SAlex Deucher 	if (high_temp > max_temp)
1053d70229f7SAlex Deucher 		high_temp = max_temp;
1054d70229f7SAlex Deucher 	if (high_temp < low_temp) {
1055d70229f7SAlex Deucher 		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
1056d70229f7SAlex Deucher 		return -EINVAL;
1057d70229f7SAlex Deucher 	}
1058d70229f7SAlex Deucher 
1059d70229f7SAlex Deucher 	WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
1060d70229f7SAlex Deucher 	WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
1061d70229f7SAlex Deucher 
1062d70229f7SAlex Deucher 	rdev->pm.dpm.thermal.min_temp = low_temp;
1063d70229f7SAlex Deucher 	rdev->pm.dpm.thermal.max_temp = high_temp;
1064d70229f7SAlex Deucher 
1065d70229f7SAlex Deucher 	return 0;
1066d70229f7SAlex Deucher }
1067d70229f7SAlex Deucher 
1068a284c48aSAlex Deucher static void trinity_update_current_ps(struct radeon_device *rdev,
1069a284c48aSAlex Deucher 				      struct radeon_ps *rps)
1070a284c48aSAlex Deucher {
1071a284c48aSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(rps);
1072a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1073a284c48aSAlex Deucher 
1074a284c48aSAlex Deucher 	pi->current_rps = *rps;
1075a284c48aSAlex Deucher 	pi->current_ps = *new_ps;
1076a284c48aSAlex Deucher 	pi->current_rps.ps_priv = &pi->current_ps;
1077a284c48aSAlex Deucher }
1078a284c48aSAlex Deucher 
1079a284c48aSAlex Deucher static void trinity_update_requested_ps(struct radeon_device *rdev,
1080a284c48aSAlex Deucher 					struct radeon_ps *rps)
1081a284c48aSAlex Deucher {
1082a284c48aSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(rps);
1083a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1084a284c48aSAlex Deucher 
1085a284c48aSAlex Deucher 	pi->requested_rps = *rps;
1086a284c48aSAlex Deucher 	pi->requested_ps = *new_ps;
1087a284c48aSAlex Deucher 	pi->requested_rps.ps_priv = &pi->requested_ps;
1088a284c48aSAlex Deucher }
1089a284c48aSAlex Deucher 
109011877060SAlex Deucher void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable)
109111877060SAlex Deucher {
109211877060SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
109311877060SAlex Deucher 
109411877060SAlex Deucher 	if (pi->enable_bapm) {
109511877060SAlex Deucher 		trinity_acquire_mutex(rdev);
109611877060SAlex Deucher 		trinity_dpm_bapm_enable(rdev, enable);
109711877060SAlex Deucher 		trinity_release_mutex(rdev);
109811877060SAlex Deucher 	}
109911877060SAlex Deucher }
110011877060SAlex Deucher 
1101d70229f7SAlex Deucher int trinity_dpm_enable(struct radeon_device *rdev)
1102d70229f7SAlex Deucher {
1103d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1104d70229f7SAlex Deucher 
1105d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1106d70229f7SAlex Deucher 
1107d70229f7SAlex Deucher 	if (trinity_dpm_enabled(rdev)) {
1108d70229f7SAlex Deucher 		trinity_release_mutex(rdev);
1109d70229f7SAlex Deucher 		return -EINVAL;
1110d70229f7SAlex Deucher 	}
1111d70229f7SAlex Deucher 
1112d70229f7SAlex Deucher 	trinity_program_bootup_state(rdev);
1113d70229f7SAlex Deucher 	sumo_program_vc(rdev, 0x00C00033);
1114d70229f7SAlex Deucher 	trinity_start_am(rdev);
1115d70229f7SAlex Deucher 	if (pi->enable_auto_thermal_throttling) {
1116d70229f7SAlex Deucher 		trinity_program_ttt(rdev);
1117d70229f7SAlex Deucher 		trinity_enable_att(rdev);
1118d70229f7SAlex Deucher 	}
1119d70229f7SAlex Deucher 	trinity_program_sclk_dpm(rdev);
1120d70229f7SAlex Deucher 	trinity_start_dpm(rdev);
1121d70229f7SAlex Deucher 	trinity_wait_for_dpm_enabled(rdev);
1122ef4e0365SAlex Deucher 	trinity_dpm_bapm_enable(rdev, false);
1123d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1124d70229f7SAlex Deucher 
1125a284c48aSAlex Deucher 	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
1126a284c48aSAlex Deucher 
1127d70229f7SAlex Deucher 	return 0;
1128d70229f7SAlex Deucher }
1129d70229f7SAlex Deucher 
1130bda44c1aSAlex Deucher int trinity_dpm_late_enable(struct radeon_device *rdev)
1131bda44c1aSAlex Deucher {
1132bda44c1aSAlex Deucher 	int ret;
1133bda44c1aSAlex Deucher 
1134bda44c1aSAlex Deucher 	trinity_acquire_mutex(rdev);
1135bda44c1aSAlex Deucher 	trinity_enable_clock_power_gating(rdev);
1136bda44c1aSAlex Deucher 
1137bda44c1aSAlex Deucher 	if (rdev->irq.installed &&
1138bda44c1aSAlex Deucher 	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
1139bda44c1aSAlex Deucher 		ret = trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
1140bda44c1aSAlex Deucher 		if (ret) {
1141bda44c1aSAlex Deucher 			trinity_release_mutex(rdev);
1142bda44c1aSAlex Deucher 			return ret;
1143bda44c1aSAlex Deucher 		}
1144bda44c1aSAlex Deucher 		rdev->irq.dpm_thermal = true;
1145bda44c1aSAlex Deucher 		radeon_irq_set(rdev);
1146bda44c1aSAlex Deucher 	}
1147bda44c1aSAlex Deucher 	trinity_release_mutex(rdev);
1148bda44c1aSAlex Deucher 
1149bda44c1aSAlex Deucher 	return 0;
1150bda44c1aSAlex Deucher }
1151bda44c1aSAlex Deucher 
1152d70229f7SAlex Deucher void trinity_dpm_disable(struct radeon_device *rdev)
1153d70229f7SAlex Deucher {
1154d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1155d70229f7SAlex Deucher 	if (!trinity_dpm_enabled(rdev)) {
1156d70229f7SAlex Deucher 		trinity_release_mutex(rdev);
1157d70229f7SAlex Deucher 		return;
1158d70229f7SAlex Deucher 	}
1159ef4e0365SAlex Deucher 	trinity_dpm_bapm_enable(rdev, false);
1160d70229f7SAlex Deucher 	trinity_disable_clock_power_gating(rdev);
1161d70229f7SAlex Deucher 	sumo_clear_vc(rdev);
1162d70229f7SAlex Deucher 	trinity_wait_for_level_0(rdev);
1163d70229f7SAlex Deucher 	trinity_stop_dpm(rdev);
1164d70229f7SAlex Deucher 	trinity_reset_am(rdev);
1165d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1166d70229f7SAlex Deucher 
1167d70229f7SAlex Deucher 	if (rdev->irq.installed &&
1168d70229f7SAlex Deucher 	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
1169d70229f7SAlex Deucher 		rdev->irq.dpm_thermal = false;
1170d70229f7SAlex Deucher 		radeon_irq_set(rdev);
1171d70229f7SAlex Deucher 	}
1172a284c48aSAlex Deucher 
1173a284c48aSAlex Deucher 	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
1174d70229f7SAlex Deucher }
1175d70229f7SAlex Deucher 
1176d70229f7SAlex Deucher static void trinity_get_min_sclk_divider(struct radeon_device *rdev)
1177d70229f7SAlex Deucher {
1178d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1179d70229f7SAlex Deucher 
1180d70229f7SAlex Deucher 	pi->min_sclk_did =
1181d70229f7SAlex Deucher 		(RREG32_SMC(CC_SMU_MISC_FUSES) & MinSClkDid_MASK) >> MinSClkDid_SHIFT;
1182d70229f7SAlex Deucher }
1183d70229f7SAlex Deucher 
1184940eea8eSAlex Deucher static void trinity_setup_nbp_sim(struct radeon_device *rdev,
1185940eea8eSAlex Deucher 				  struct radeon_ps *rps)
1186d70229f7SAlex Deucher {
1187d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1188940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(rps);
1189d70229f7SAlex Deucher 	u32 nbpsconfig;
1190d70229f7SAlex Deucher 
1191d70229f7SAlex Deucher 	if (pi->sys_info.nb_dpm_enable) {
1192d70229f7SAlex Deucher 		nbpsconfig = RREG32_SMC(NB_PSTATE_CONFIG);
1193d70229f7SAlex Deucher 		nbpsconfig &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | DpmXNbPsLo_MASK | DpmXNbPsHi_MASK);
1194d70229f7SAlex Deucher 		nbpsconfig |= (Dpm0PgNbPsLo(new_ps->Dpm0PgNbPsLo) |
1195d70229f7SAlex Deucher 			       Dpm0PgNbPsHi(new_ps->Dpm0PgNbPsHi) |
1196d70229f7SAlex Deucher 			       DpmXNbPsLo(new_ps->DpmXNbPsLo) |
1197d70229f7SAlex Deucher 			       DpmXNbPsHi(new_ps->DpmXNbPsHi));
1198d70229f7SAlex Deucher 		WREG32_SMC(NB_PSTATE_CONFIG, nbpsconfig);
1199d70229f7SAlex Deucher 	}
1200d70229f7SAlex Deucher }
1201d70229f7SAlex Deucher 
12029b5de596SAlex Deucher int trinity_dpm_force_performance_level(struct radeon_device *rdev,
12039b5de596SAlex Deucher 					enum radeon_dpm_forced_level level)
12049b5de596SAlex Deucher {
12059b5de596SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
12069b5de596SAlex Deucher 	struct radeon_ps *rps = &pi->current_rps;
12079b5de596SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
12089b5de596SAlex Deucher 	int i, ret;
12099b5de596SAlex Deucher 
12109b5de596SAlex Deucher 	if (ps->num_levels <= 1)
12119b5de596SAlex Deucher 		return 0;
12129b5de596SAlex Deucher 
12139b5de596SAlex Deucher 	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
12149b5de596SAlex Deucher 		/* not supported by the hw */
12159b5de596SAlex Deucher 		return -EINVAL;
12169b5de596SAlex Deucher 	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
12179b5de596SAlex Deucher 		ret = trinity_dpm_n_levels_disabled(rdev, ps->num_levels - 1);
12189b5de596SAlex Deucher 		if (ret)
12199b5de596SAlex Deucher 			return ret;
12209b5de596SAlex Deucher 	} else {
12219b5de596SAlex Deucher 		for (i = 0; i < ps->num_levels; i++) {
12229b5de596SAlex Deucher 			ret = trinity_dpm_n_levels_disabled(rdev, 0);
12239b5de596SAlex Deucher 			if (ret)
12249b5de596SAlex Deucher 				return ret;
12259b5de596SAlex Deucher 		}
12269b5de596SAlex Deucher 	}
12279b5de596SAlex Deucher 
12289b5de596SAlex Deucher 	rdev->pm.dpm.forced_level = level;
12299b5de596SAlex Deucher 
12309b5de596SAlex Deucher 	return 0;
12319b5de596SAlex Deucher }
12329b5de596SAlex Deucher 
1233a284c48aSAlex Deucher int trinity_dpm_pre_set_power_state(struct radeon_device *rdev)
1234a284c48aSAlex Deucher {
1235a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1236a284c48aSAlex Deucher 	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
1237a284c48aSAlex Deucher 	struct radeon_ps *new_ps = &requested_ps;
1238a284c48aSAlex Deucher 
1239a284c48aSAlex Deucher 	trinity_update_requested_ps(rdev, new_ps);
1240a284c48aSAlex Deucher 
1241a284c48aSAlex Deucher 	trinity_apply_state_adjust_rules(rdev,
1242a284c48aSAlex Deucher 					 &pi->requested_rps,
1243a284c48aSAlex Deucher 					 &pi->current_rps);
1244a284c48aSAlex Deucher 
1245a284c48aSAlex Deucher 	return 0;
1246a284c48aSAlex Deucher }
1247a284c48aSAlex Deucher 
1248d70229f7SAlex Deucher int trinity_dpm_set_power_state(struct radeon_device *rdev)
1249d70229f7SAlex Deucher {
1250d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1251a284c48aSAlex Deucher 	struct radeon_ps *new_ps = &pi->requested_rps;
1252a284c48aSAlex Deucher 	struct radeon_ps *old_ps = &pi->current_rps;
1253d70229f7SAlex Deucher 
1254d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1255d70229f7SAlex Deucher 	if (pi->enable_dpm) {
125611877060SAlex Deucher 		if (pi->enable_bapm)
125711877060SAlex Deucher 			trinity_dpm_bapm_enable(rdev, rdev->pm.dpm.ac_power);
1258940eea8eSAlex Deucher 		trinity_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
1259d70229f7SAlex Deucher 		trinity_enable_power_level_0(rdev);
1260d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1261d70229f7SAlex Deucher 		trinity_wait_for_level_0(rdev);
1262940eea8eSAlex Deucher 		trinity_setup_nbp_sim(rdev, new_ps);
1263940eea8eSAlex Deucher 		trinity_program_power_levels_0_to_n(rdev, new_ps, old_ps);
1264d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1265d70229f7SAlex Deucher 		trinity_unforce_levels(rdev);
1266940eea8eSAlex Deucher 		trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
126711fe3d6eSAlex Deucher 		trinity_set_vce_clock(rdev, new_ps, old_ps);
1268d70229f7SAlex Deucher 	}
1269d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1270d70229f7SAlex Deucher 
1271d70229f7SAlex Deucher 	return 0;
1272d70229f7SAlex Deucher }
1273d70229f7SAlex Deucher 
1274a284c48aSAlex Deucher void trinity_dpm_post_set_power_state(struct radeon_device *rdev)
1275a284c48aSAlex Deucher {
1276a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1277a284c48aSAlex Deucher 	struct radeon_ps *new_ps = &pi->requested_rps;
1278a284c48aSAlex Deucher 
1279a284c48aSAlex Deucher 	trinity_update_current_ps(rdev, new_ps);
1280a284c48aSAlex Deucher }
1281a284c48aSAlex Deucher 
1282d70229f7SAlex Deucher void trinity_dpm_setup_asic(struct radeon_device *rdev)
1283d70229f7SAlex Deucher {
1284d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1285d70229f7SAlex Deucher 	sumo_program_sstp(rdev);
1286d70229f7SAlex Deucher 	sumo_take_smu_control(rdev, true);
1287d70229f7SAlex Deucher 	trinity_get_min_sclk_divider(rdev);
1288d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1289d70229f7SAlex Deucher }
1290d70229f7SAlex Deucher 
12916421d612SAlex Deucher #if 0
1292d70229f7SAlex Deucher void trinity_dpm_reset_asic(struct radeon_device *rdev)
1293d70229f7SAlex Deucher {
1294d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1295d70229f7SAlex Deucher 
1296d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1297d70229f7SAlex Deucher 	if (pi->enable_dpm) {
1298d70229f7SAlex Deucher 		trinity_enable_power_level_0(rdev);
1299d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1300d70229f7SAlex Deucher 		trinity_wait_for_level_0(rdev);
1301d70229f7SAlex Deucher 		trinity_program_bootup_state(rdev);
1302d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1303d70229f7SAlex Deucher 		trinity_unforce_levels(rdev);
1304d70229f7SAlex Deucher 	}
1305d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1306d70229f7SAlex Deucher }
13076421d612SAlex Deucher #endif
1308d70229f7SAlex Deucher 
1309d70229f7SAlex Deucher static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
1310d70229f7SAlex Deucher 						  u32 vid_2bit)
1311d70229f7SAlex Deucher {
1312d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1313d70229f7SAlex Deucher 	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
1314d70229f7SAlex Deucher 	u32 svi_mode = (RREG32_SMC(PM_CONFIG) & SVI_Mode) ? 1 : 0;
1315d70229f7SAlex Deucher 	u32 step = (svi_mode == 0) ? 1250 : 625;
1316d70229f7SAlex Deucher 	u32 delta = vid_7bit * step + 50;
1317d70229f7SAlex Deucher 
1318d70229f7SAlex Deucher 	if (delta > 155000)
1319d70229f7SAlex Deucher 		return 0;
1320d70229f7SAlex Deucher 
1321d70229f7SAlex Deucher 	return (155000 - delta) / 100;
1322d70229f7SAlex Deucher }
1323d70229f7SAlex Deucher 
1324d70229f7SAlex Deucher static void trinity_patch_boot_state(struct radeon_device *rdev,
1325d70229f7SAlex Deucher 				     struct trinity_ps *ps)
1326d70229f7SAlex Deucher {
1327d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1328d70229f7SAlex Deucher 
1329d70229f7SAlex Deucher 	ps->num_levels = 1;
1330d70229f7SAlex Deucher 	ps->nbps_flags = 0;
1331d70229f7SAlex Deucher 	ps->bapm_flags = 0;
1332d70229f7SAlex Deucher 	ps->levels[0] = pi->boot_pl;
1333d70229f7SAlex Deucher }
1334d70229f7SAlex Deucher 
1335d70229f7SAlex Deucher static u8 trinity_calculate_vce_wm(struct radeon_device *rdev, u32 sclk)
1336d70229f7SAlex Deucher {
1337d70229f7SAlex Deucher 	if (sclk < 20000)
1338d70229f7SAlex Deucher 		return 1;
1339d70229f7SAlex Deucher 	return 0;
1340d70229f7SAlex Deucher }
1341d70229f7SAlex Deucher 
1342d70229f7SAlex Deucher static void trinity_construct_boot_state(struct radeon_device *rdev)
1343d70229f7SAlex Deucher {
1344d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1345d70229f7SAlex Deucher 
1346d70229f7SAlex Deucher 	pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
1347d70229f7SAlex Deucher 	pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
1348d70229f7SAlex Deucher 	pi->boot_pl.ds_divider_index = 0;
1349d70229f7SAlex Deucher 	pi->boot_pl.ss_divider_index = 0;
1350d70229f7SAlex Deucher 	pi->boot_pl.allow_gnb_slow = 1;
1351d70229f7SAlex Deucher 	pi->boot_pl.force_nbp_state = 0;
1352d70229f7SAlex Deucher 	pi->boot_pl.display_wm = 0;
1353d70229f7SAlex Deucher 	pi->boot_pl.vce_wm = 0;
1354d70229f7SAlex Deucher 	pi->current_ps.num_levels = 1;
1355d70229f7SAlex Deucher 	pi->current_ps.levels[0] = pi->boot_pl;
1356d70229f7SAlex Deucher }
1357d70229f7SAlex Deucher 
1358d70229f7SAlex Deucher static u8 trinity_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
1359d70229f7SAlex Deucher 						  u32 sclk, u32 min_sclk_in_sr)
1360d70229f7SAlex Deucher {
1361d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1362d70229f7SAlex Deucher 	u32 i;
1363d70229f7SAlex Deucher 	u32 temp;
1364d70229f7SAlex Deucher 	u32 min = (min_sclk_in_sr > TRINITY_MINIMUM_ENGINE_CLOCK) ?
1365d70229f7SAlex Deucher 		min_sclk_in_sr : TRINITY_MINIMUM_ENGINE_CLOCK;
1366d70229f7SAlex Deucher 
1367d70229f7SAlex Deucher 	if (sclk < min)
1368d70229f7SAlex Deucher 		return 0;
1369d70229f7SAlex Deucher 
1370d70229f7SAlex Deucher 	if (!pi->enable_sclk_ds)
1371d70229f7SAlex Deucher 		return 0;
1372d70229f7SAlex Deucher 
1373d70229f7SAlex Deucher 	for (i = TRINITY_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
1374d70229f7SAlex Deucher 		temp = sclk / sumo_get_sleep_divider_from_id(i);
1375d70229f7SAlex Deucher 		if (temp >= min || i == 0)
1376d70229f7SAlex Deucher 			break;
1377d70229f7SAlex Deucher 	}
1378d70229f7SAlex Deucher 
1379d70229f7SAlex Deucher 	return (u8)i;
1380d70229f7SAlex Deucher }
1381d70229f7SAlex Deucher 
1382d70229f7SAlex Deucher static u32 trinity_get_valid_engine_clock(struct radeon_device *rdev,
1383d70229f7SAlex Deucher 					  u32 lower_limit)
1384d70229f7SAlex Deucher {
1385d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1386d70229f7SAlex Deucher 	u32 i;
1387d70229f7SAlex Deucher 
1388d70229f7SAlex Deucher 	for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
1389d70229f7SAlex Deucher 		if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
1390d70229f7SAlex Deucher 			return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
1391d70229f7SAlex Deucher 	}
1392d70229f7SAlex Deucher 
1393d70229f7SAlex Deucher 	if (i == pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries)
1394d70229f7SAlex Deucher 		DRM_ERROR("engine clock out of range!");
1395d70229f7SAlex Deucher 
1396d70229f7SAlex Deucher 	return 0;
1397d70229f7SAlex Deucher }
1398d70229f7SAlex Deucher 
1399d70229f7SAlex Deucher static void trinity_patch_thermal_state(struct radeon_device *rdev,
1400d70229f7SAlex Deucher 					struct trinity_ps *ps,
1401d70229f7SAlex Deucher 					struct trinity_ps *current_ps)
1402d70229f7SAlex Deucher {
1403d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1404d70229f7SAlex Deucher 	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
1405d70229f7SAlex Deucher 	u32 current_vddc;
1406d70229f7SAlex Deucher 	u32 current_sclk;
1407d70229f7SAlex Deucher 	u32 current_index = 0;
1408d70229f7SAlex Deucher 
1409d70229f7SAlex Deucher 	if (current_ps) {
1410d70229f7SAlex Deucher 		current_vddc = current_ps->levels[current_index].vddc_index;
1411d70229f7SAlex Deucher 		current_sclk = current_ps->levels[current_index].sclk;
1412d70229f7SAlex Deucher 	} else {
1413d70229f7SAlex Deucher 		current_vddc = pi->boot_pl.vddc_index;
1414d70229f7SAlex Deucher 		current_sclk = pi->boot_pl.sclk;
1415d70229f7SAlex Deucher 	}
1416d70229f7SAlex Deucher 
1417d70229f7SAlex Deucher 	ps->levels[0].vddc_index = current_vddc;
1418d70229f7SAlex Deucher 
1419d70229f7SAlex Deucher 	if (ps->levels[0].sclk > current_sclk)
1420d70229f7SAlex Deucher 		ps->levels[0].sclk = current_sclk;
1421d70229f7SAlex Deucher 
1422d70229f7SAlex Deucher 	ps->levels[0].ds_divider_index =
1423d70229f7SAlex Deucher 		trinity_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
1424d70229f7SAlex Deucher 	ps->levels[0].ss_divider_index = ps->levels[0].ds_divider_index;
1425d70229f7SAlex Deucher 	ps->levels[0].allow_gnb_slow = 1;
1426d70229f7SAlex Deucher 	ps->levels[0].force_nbp_state = 0;
1427d70229f7SAlex Deucher 	ps->levels[0].display_wm = 0;
1428d70229f7SAlex Deucher 	ps->levels[0].vce_wm =
1429d70229f7SAlex Deucher 		trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
1430d70229f7SAlex Deucher }
1431d70229f7SAlex Deucher 
1432d70229f7SAlex Deucher static u8 trinity_calculate_display_wm(struct radeon_device *rdev,
1433d70229f7SAlex Deucher 				       struct trinity_ps *ps, u32 index)
1434d70229f7SAlex Deucher {
1435d70229f7SAlex Deucher 	if (ps == NULL || ps->num_levels <= 1)
1436d70229f7SAlex Deucher 		return 0;
1437d70229f7SAlex Deucher 	else if (ps->num_levels == 2) {
1438d70229f7SAlex Deucher 		if (index == 0)
1439d70229f7SAlex Deucher 			return 0;
1440d70229f7SAlex Deucher 		else
1441d70229f7SAlex Deucher 			return 1;
1442d70229f7SAlex Deucher 	} else {
1443d70229f7SAlex Deucher 		if (index == 0)
1444d70229f7SAlex Deucher 			return 0;
1445d70229f7SAlex Deucher 		else if (ps->levels[index].sclk < 30000)
1446d70229f7SAlex Deucher 			return 0;
1447d70229f7SAlex Deucher 		else
1448d70229f7SAlex Deucher 			return 1;
1449d70229f7SAlex Deucher 	}
1450d70229f7SAlex Deucher }
1451d70229f7SAlex Deucher 
14520c4aaeaeSAlex Deucher static u32 trinity_get_uvd_clock_index(struct radeon_device *rdev,
14530c4aaeaeSAlex Deucher 				       struct radeon_ps *rps)
14540c4aaeaeSAlex Deucher {
14550c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
14560c4aaeaeSAlex Deucher 	u32 i = 0;
14570c4aaeaeSAlex Deucher 
14580c4aaeaeSAlex Deucher 	for (i = 0; i < 4; i++) {
14590c4aaeaeSAlex Deucher 		if ((rps->vclk == pi->sys_info.uvd_clock_table_entries[i].vclk) &&
14600c4aaeaeSAlex Deucher 		    (rps->dclk == pi->sys_info.uvd_clock_table_entries[i].dclk))
14610c4aaeaeSAlex Deucher 		    break;
14620c4aaeaeSAlex Deucher 	}
14630c4aaeaeSAlex Deucher 
14640c4aaeaeSAlex Deucher 	if (i >= 4) {
14650c4aaeaeSAlex Deucher 		DRM_ERROR("UVD clock index not found!\n");
14660c4aaeaeSAlex Deucher 		i = 3;
14670c4aaeaeSAlex Deucher 	}
14680c4aaeaeSAlex Deucher 	return i;
14690c4aaeaeSAlex Deucher }
14700c4aaeaeSAlex Deucher 
14710c4aaeaeSAlex Deucher static void trinity_adjust_uvd_state(struct radeon_device *rdev,
14720c4aaeaeSAlex Deucher 				     struct radeon_ps *rps)
14730c4aaeaeSAlex Deucher {
14740c4aaeaeSAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
14750c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
14760c4aaeaeSAlex Deucher 	u32 high_index = 0;
14770c4aaeaeSAlex Deucher 	u32 low_index = 0;
14780c4aaeaeSAlex Deucher 
14790c4aaeaeSAlex Deucher 	if (pi->uvd_dpm && r600_is_uvd_state(rps->class, rps->class2)) {
14800c4aaeaeSAlex Deucher 		high_index = trinity_get_uvd_clock_index(rdev, rps);
14810c4aaeaeSAlex Deucher 
14820c4aaeaeSAlex Deucher 		switch(high_index) {
14830c4aaeaeSAlex Deucher 		case 3:
14840c4aaeaeSAlex Deucher 		case 2:
14850c4aaeaeSAlex Deucher 			low_index = 1;
14860c4aaeaeSAlex Deucher 			break;
14870c4aaeaeSAlex Deucher 		case 1:
14880c4aaeaeSAlex Deucher 		case 0:
14890c4aaeaeSAlex Deucher 		default:
14900c4aaeaeSAlex Deucher 			low_index = 0;
14910c4aaeaeSAlex Deucher 			break;
14920c4aaeaeSAlex Deucher 		}
14930c4aaeaeSAlex Deucher 
14940c4aaeaeSAlex Deucher 		ps->vclk_low_divider =
14950c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[high_index].vclk_did;
14960c4aaeaeSAlex Deucher 		ps->dclk_low_divider =
14970c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[high_index].dclk_did;
14980c4aaeaeSAlex Deucher 		ps->vclk_high_divider =
14990c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[low_index].vclk_did;
15000c4aaeaeSAlex Deucher 		ps->dclk_high_divider =
15010c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[low_index].dclk_did;
15020c4aaeaeSAlex Deucher 	}
15030c4aaeaeSAlex Deucher }
15040c4aaeaeSAlex Deucher 
150511fe3d6eSAlex Deucher static int trinity_get_vce_clock_voltage(struct radeon_device *rdev,
150611fe3d6eSAlex Deucher 					 u32 evclk, u32 ecclk, u16 *voltage)
150711fe3d6eSAlex Deucher {
150811fe3d6eSAlex Deucher 	u32 i;
150911fe3d6eSAlex Deucher 	int ret = -EINVAL;
151011fe3d6eSAlex Deucher 	struct radeon_vce_clock_voltage_dependency_table *table =
151111fe3d6eSAlex Deucher 		&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
15120c4aaeaeSAlex Deucher 
151311fe3d6eSAlex Deucher 	if (((evclk == 0) && (ecclk == 0)) ||
151411fe3d6eSAlex Deucher 	    (table && (table->count == 0))) {
151511fe3d6eSAlex Deucher 		*voltage = 0;
151611fe3d6eSAlex Deucher 		return 0;
151711fe3d6eSAlex Deucher 	}
151811fe3d6eSAlex Deucher 
151911fe3d6eSAlex Deucher 	for (i = 0; i < table->count; i++) {
152011fe3d6eSAlex Deucher 		if ((evclk <= table->entries[i].evclk) &&
152111fe3d6eSAlex Deucher 		    (ecclk <= table->entries[i].ecclk)) {
152211fe3d6eSAlex Deucher 			*voltage = table->entries[i].v;
152311fe3d6eSAlex Deucher 			ret = 0;
152411fe3d6eSAlex Deucher 			break;
152511fe3d6eSAlex Deucher 		}
152611fe3d6eSAlex Deucher 	}
152711fe3d6eSAlex Deucher 
152811fe3d6eSAlex Deucher 	/* if no match return the highest voltage */
152911fe3d6eSAlex Deucher 	if (ret)
153011fe3d6eSAlex Deucher 		*voltage = table->entries[table->count - 1].v;
153111fe3d6eSAlex Deucher 
153211fe3d6eSAlex Deucher 	return ret;
153311fe3d6eSAlex Deucher }
15340c4aaeaeSAlex Deucher 
1535940eea8eSAlex Deucher static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
1536940eea8eSAlex Deucher 					     struct radeon_ps *new_rps,
1537940eea8eSAlex Deucher 					     struct radeon_ps *old_rps)
1538d70229f7SAlex Deucher {
1539940eea8eSAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(new_rps);
1540940eea8eSAlex Deucher 	struct trinity_ps *current_ps = trinity_get_ps(old_rps);
1541d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1542d70229f7SAlex Deucher 	u32 min_voltage = 0; /* ??? */
1543d70229f7SAlex Deucher 	u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
1544d70229f7SAlex Deucher 	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
1545d70229f7SAlex Deucher 	u32 i;
154611fe3d6eSAlex Deucher 	u16 min_vce_voltage;
1547d70229f7SAlex Deucher 	bool force_high;
1548d70229f7SAlex Deucher 	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
1549d70229f7SAlex Deucher 
1550940eea8eSAlex Deucher 	if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
1551d70229f7SAlex Deucher 		return trinity_patch_thermal_state(rdev, ps, current_ps);
1552d70229f7SAlex Deucher 
1553940eea8eSAlex Deucher 	trinity_adjust_uvd_state(rdev, new_rps);
15540c4aaeaeSAlex Deucher 
155511fe3d6eSAlex Deucher 	if (new_rps->vce_active) {
155611fe3d6eSAlex Deucher 		new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
155711fe3d6eSAlex Deucher 		new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
155811fe3d6eSAlex Deucher 	} else {
155911fe3d6eSAlex Deucher 		new_rps->evclk = 0;
156011fe3d6eSAlex Deucher 		new_rps->ecclk = 0;
156111fe3d6eSAlex Deucher 	}
156211fe3d6eSAlex Deucher 
1563d70229f7SAlex Deucher 	for (i = 0; i < ps->num_levels; i++) {
1564d70229f7SAlex Deucher 		if (ps->levels[i].vddc_index < min_voltage)
1565d70229f7SAlex Deucher 			ps->levels[i].vddc_index = min_voltage;
1566d70229f7SAlex Deucher 
1567d70229f7SAlex Deucher 		if (ps->levels[i].sclk < min_sclk)
1568d70229f7SAlex Deucher 			ps->levels[i].sclk =
1569d70229f7SAlex Deucher 				trinity_get_valid_engine_clock(rdev, min_sclk);
1570d70229f7SAlex Deucher 
157111fe3d6eSAlex Deucher 		/* patch in vce limits */
157211fe3d6eSAlex Deucher 		if (new_rps->vce_active) {
157311fe3d6eSAlex Deucher 			/* sclk */
157411fe3d6eSAlex Deucher 			if (ps->levels[i].sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
157511fe3d6eSAlex Deucher 				ps->levels[i].sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
157611fe3d6eSAlex Deucher 			/* vddc */
157711fe3d6eSAlex Deucher 			trinity_get_vce_clock_voltage(rdev, new_rps->evclk, new_rps->ecclk, &min_vce_voltage);
157811fe3d6eSAlex Deucher 			if (ps->levels[i].vddc_index < min_vce_voltage)
157911fe3d6eSAlex Deucher 				ps->levels[i].vddc_index = min_vce_voltage;
158011fe3d6eSAlex Deucher 		}
158111fe3d6eSAlex Deucher 
1582d70229f7SAlex Deucher 		ps->levels[i].ds_divider_index =
1583d70229f7SAlex Deucher 			sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
1584d70229f7SAlex Deucher 
1585d70229f7SAlex Deucher 		ps->levels[i].ss_divider_index = ps->levels[i].ds_divider_index;
1586d70229f7SAlex Deucher 
1587d70229f7SAlex Deucher 		ps->levels[i].allow_gnb_slow = 1;
1588d70229f7SAlex Deucher 		ps->levels[i].force_nbp_state = 0;
1589d70229f7SAlex Deucher 		ps->levels[i].display_wm =
1590d70229f7SAlex Deucher 			trinity_calculate_display_wm(rdev, ps, i);
1591d70229f7SAlex Deucher 		ps->levels[i].vce_wm =
1592d70229f7SAlex Deucher 			trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
1593d70229f7SAlex Deucher 	}
1594d70229f7SAlex Deucher 
1595940eea8eSAlex Deucher 	if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
1596940eea8eSAlex Deucher 	    ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY))
1597d70229f7SAlex Deucher 		ps->bapm_flags |= TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE;
1598d70229f7SAlex Deucher 
1599d70229f7SAlex Deucher 	if (pi->sys_info.nb_dpm_enable) {
1600d70229f7SAlex Deucher 		ps->Dpm0PgNbPsLo = 0x1;
1601d70229f7SAlex Deucher 		ps->Dpm0PgNbPsHi = 0x0;
1602d70229f7SAlex Deucher 		ps->DpmXNbPsLo = 0x2;
1603d70229f7SAlex Deucher 		ps->DpmXNbPsHi = 0x1;
1604d70229f7SAlex Deucher 
1605940eea8eSAlex Deucher 		if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
1606940eea8eSAlex Deucher 		    ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) {
1607940eea8eSAlex Deucher 			force_high = ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ||
1608940eea8eSAlex Deucher 				      ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) &&
1609d70229f7SAlex Deucher 				       (pi->sys_info.uma_channel_number == 1)));
1610d70229f7SAlex Deucher 			force_high = (num_active_displays >= 3) || force_high;
1611d70229f7SAlex Deucher 			ps->Dpm0PgNbPsLo = force_high ? 0x2 : 0x3;
1612d70229f7SAlex Deucher 			ps->Dpm0PgNbPsHi = 0x1;
1613d70229f7SAlex Deucher 			ps->DpmXNbPsLo = force_high ? 0x2 : 0x3;
1614d70229f7SAlex Deucher 			ps->DpmXNbPsHi = 0x2;
1615d70229f7SAlex Deucher 			ps->levels[ps->num_levels - 1].allow_gnb_slow = 0;
1616d70229f7SAlex Deucher 		}
1617d70229f7SAlex Deucher 	}
1618d70229f7SAlex Deucher }
1619d70229f7SAlex Deucher 
1620d70229f7SAlex Deucher static void trinity_cleanup_asic(struct radeon_device *rdev)
1621d70229f7SAlex Deucher {
1622d70229f7SAlex Deucher 	sumo_take_smu_control(rdev, false);
1623d70229f7SAlex Deucher }
1624d70229f7SAlex Deucher 
1625d70229f7SAlex Deucher #if 0
1626d70229f7SAlex Deucher static void trinity_pre_display_configuration_change(struct radeon_device *rdev)
1627d70229f7SAlex Deucher {
1628d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1629d70229f7SAlex Deucher 
1630d70229f7SAlex Deucher 	if (pi->voltage_drop_in_dce)
1631d70229f7SAlex Deucher 		trinity_dce_enable_voltage_adjustment(rdev, false);
1632d70229f7SAlex Deucher }
1633d70229f7SAlex Deucher #endif
1634d70229f7SAlex Deucher 
1635d70229f7SAlex Deucher static void trinity_add_dccac_value(struct radeon_device *rdev)
1636d70229f7SAlex Deucher {
1637d70229f7SAlex Deucher 	u32 gpu_cac_avrg_cntl_window_size;
1638d70229f7SAlex Deucher 	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
1639d70229f7SAlex Deucher 	u64 disp_clk = rdev->clock.default_dispclk / 100;
1640d70229f7SAlex Deucher 	u32 dc_cac_value;
1641d70229f7SAlex Deucher 
1642d70229f7SAlex Deucher 	gpu_cac_avrg_cntl_window_size =
1643d70229f7SAlex Deucher 		(RREG32_SMC(GPU_CAC_AVRG_CNTL) & WINDOW_SIZE_MASK) >> WINDOW_SIZE_SHIFT;
1644d70229f7SAlex Deucher 
1645d70229f7SAlex Deucher 	dc_cac_value = (u32)((14213 * disp_clk * disp_clk * (u64)num_active_displays) >>
1646d70229f7SAlex Deucher 			     (32 - gpu_cac_avrg_cntl_window_size));
1647d70229f7SAlex Deucher 
1648d70229f7SAlex Deucher 	WREG32_SMC(DC_CAC_VALUE, dc_cac_value);
1649d70229f7SAlex Deucher }
1650d70229f7SAlex Deucher 
1651d70229f7SAlex Deucher void trinity_dpm_display_configuration_changed(struct radeon_device *rdev)
1652d70229f7SAlex Deucher {
1653d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1654d70229f7SAlex Deucher 
1655d70229f7SAlex Deucher 	if (pi->voltage_drop_in_dce)
1656d70229f7SAlex Deucher 		trinity_dce_enable_voltage_adjustment(rdev, true);
1657d70229f7SAlex Deucher 	trinity_add_dccac_value(rdev);
1658d70229f7SAlex Deucher }
1659d70229f7SAlex Deucher 
1660d70229f7SAlex Deucher union power_info {
1661d70229f7SAlex Deucher 	struct _ATOM_POWERPLAY_INFO info;
1662d70229f7SAlex Deucher 	struct _ATOM_POWERPLAY_INFO_V2 info_2;
1663d70229f7SAlex Deucher 	struct _ATOM_POWERPLAY_INFO_V3 info_3;
1664d70229f7SAlex Deucher 	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
1665d70229f7SAlex Deucher 	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
1666d70229f7SAlex Deucher 	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
1667d70229f7SAlex Deucher };
1668d70229f7SAlex Deucher 
1669d70229f7SAlex Deucher union pplib_clock_info {
1670d70229f7SAlex Deucher 	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
1671d70229f7SAlex Deucher 	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
1672d70229f7SAlex Deucher 	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
1673d70229f7SAlex Deucher 	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
1674d70229f7SAlex Deucher };
1675d70229f7SAlex Deucher 
1676d70229f7SAlex Deucher union pplib_power_state {
1677d70229f7SAlex Deucher 	struct _ATOM_PPLIB_STATE v1;
1678d70229f7SAlex Deucher 	struct _ATOM_PPLIB_STATE_V2 v2;
1679d70229f7SAlex Deucher };
1680d70229f7SAlex Deucher 
1681d70229f7SAlex Deucher static void trinity_parse_pplib_non_clock_info(struct radeon_device *rdev,
1682d70229f7SAlex Deucher 					       struct radeon_ps *rps,
1683d70229f7SAlex Deucher 					       struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
1684d70229f7SAlex Deucher 					       u8 table_rev)
1685d70229f7SAlex Deucher {
1686d70229f7SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
1687d70229f7SAlex Deucher 
1688d70229f7SAlex Deucher 	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
1689d70229f7SAlex Deucher 	rps->class = le16_to_cpu(non_clock_info->usClassification);
1690d70229f7SAlex Deucher 	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
1691d70229f7SAlex Deucher 
1692d70229f7SAlex Deucher 	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
1693d70229f7SAlex Deucher 		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
1694d70229f7SAlex Deucher 		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
1695d70229f7SAlex Deucher 	} else {
1696d70229f7SAlex Deucher 		rps->vclk = 0;
1697d70229f7SAlex Deucher 		rps->dclk = 0;
1698d70229f7SAlex Deucher 	}
1699d70229f7SAlex Deucher 
1700d70229f7SAlex Deucher 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
1701d70229f7SAlex Deucher 		rdev->pm.dpm.boot_ps = rps;
1702d70229f7SAlex Deucher 		trinity_patch_boot_state(rdev, ps);
1703d70229f7SAlex Deucher 	}
1704d70229f7SAlex Deucher 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
1705d70229f7SAlex Deucher 		rdev->pm.dpm.uvd_ps = rps;
1706d70229f7SAlex Deucher }
1707d70229f7SAlex Deucher 
1708d70229f7SAlex Deucher static void trinity_parse_pplib_clock_info(struct radeon_device *rdev,
1709d70229f7SAlex Deucher 					   struct radeon_ps *rps, int index,
1710d70229f7SAlex Deucher 					   union pplib_clock_info *clock_info)
1711d70229f7SAlex Deucher {
1712d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1713d70229f7SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
1714d70229f7SAlex Deucher 	struct trinity_pl *pl = &ps->levels[index];
1715d70229f7SAlex Deucher 	u32 sclk;
1716d70229f7SAlex Deucher 
1717d70229f7SAlex Deucher 	sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
1718d70229f7SAlex Deucher 	sclk |= clock_info->sumo.ucEngineClockHigh << 16;
1719d70229f7SAlex Deucher 	pl->sclk = sclk;
1720d70229f7SAlex Deucher 	pl->vddc_index = clock_info->sumo.vddcIndex;
1721d70229f7SAlex Deucher 
1722d70229f7SAlex Deucher 	ps->num_levels = index + 1;
1723d70229f7SAlex Deucher 
1724d70229f7SAlex Deucher 	if (pi->enable_sclk_ds) {
1725d70229f7SAlex Deucher 		pl->ds_divider_index = 5;
1726d70229f7SAlex Deucher 		pl->ss_divider_index = 5;
1727d70229f7SAlex Deucher 	}
1728d70229f7SAlex Deucher }
1729d70229f7SAlex Deucher 
1730d70229f7SAlex Deucher static int trinity_parse_power_table(struct radeon_device *rdev)
1731d70229f7SAlex Deucher {
1732d70229f7SAlex Deucher 	struct radeon_mode_info *mode_info = &rdev->mode_info;
1733d70229f7SAlex Deucher 	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
1734d70229f7SAlex Deucher 	union pplib_power_state *power_state;
1735d70229f7SAlex Deucher 	int i, j, k, non_clock_array_index, clock_array_index;
1736d70229f7SAlex Deucher 	union pplib_clock_info *clock_info;
1737d70229f7SAlex Deucher 	struct _StateArray *state_array;
1738d70229f7SAlex Deucher 	struct _ClockInfoArray *clock_info_array;
1739d70229f7SAlex Deucher 	struct _NonClockInfoArray *non_clock_info_array;
1740d70229f7SAlex Deucher 	union power_info *power_info;
1741d70229f7SAlex Deucher 	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
1742d70229f7SAlex Deucher 	u16 data_offset;
1743d70229f7SAlex Deucher 	u8 frev, crev;
1744d70229f7SAlex Deucher 	u8 *power_state_offset;
1745d70229f7SAlex Deucher 	struct sumo_ps *ps;
1746d70229f7SAlex Deucher 
1747d70229f7SAlex Deucher 	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
1748d70229f7SAlex Deucher 				   &frev, &crev, &data_offset))
1749d70229f7SAlex Deucher 		return -EINVAL;
1750d70229f7SAlex Deucher 	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
1751d70229f7SAlex Deucher 
1752d70229f7SAlex Deucher 	state_array = (struct _StateArray *)
1753d70229f7SAlex Deucher 		(mode_info->atom_context->bios + data_offset +
1754d70229f7SAlex Deucher 		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
1755d70229f7SAlex Deucher 	clock_info_array = (struct _ClockInfoArray *)
1756d70229f7SAlex Deucher 		(mode_info->atom_context->bios + data_offset +
1757d70229f7SAlex Deucher 		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
1758d70229f7SAlex Deucher 	non_clock_info_array = (struct _NonClockInfoArray *)
1759d70229f7SAlex Deucher 		(mode_info->atom_context->bios + data_offset +
1760d70229f7SAlex Deucher 		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
1761d70229f7SAlex Deucher 
17626396bb22SKees Cook 	rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries,
17636396bb22SKees Cook 				  sizeof(struct radeon_ps),
17646396bb22SKees Cook 				  GFP_KERNEL);
1765d70229f7SAlex Deucher 	if (!rdev->pm.dpm.ps)
1766d70229f7SAlex Deucher 		return -ENOMEM;
1767d70229f7SAlex Deucher 	power_state_offset = (u8 *)state_array->states;
1768d70229f7SAlex Deucher 	for (i = 0; i < state_array->ucNumEntries; i++) {
17695e250d20SAlex Deucher 		u8 *idx;
1770d70229f7SAlex Deucher 		power_state = (union pplib_power_state *)power_state_offset;
1771d70229f7SAlex Deucher 		non_clock_array_index = power_state->v2.nonClockInfoIndex;
1772d70229f7SAlex Deucher 		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
1773d70229f7SAlex Deucher 			&non_clock_info_array->nonClockInfo[non_clock_array_index];
1774d70229f7SAlex Deucher 		if (!rdev->pm.power_state[i].clock_info)
1775d70229f7SAlex Deucher 			return -EINVAL;
1776d70229f7SAlex Deucher 		ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
1777d70229f7SAlex Deucher 		if (ps == NULL) {
1778d70229f7SAlex Deucher 			kfree(rdev->pm.dpm.ps);
1779d70229f7SAlex Deucher 			return -ENOMEM;
1780d70229f7SAlex Deucher 		}
1781d70229f7SAlex Deucher 		rdev->pm.dpm.ps[i].ps_priv = ps;
1782d70229f7SAlex Deucher 		k = 0;
17835e250d20SAlex Deucher 		idx = (u8 *)&power_state->v2.clockInfoIndex[0];
1784d70229f7SAlex Deucher 		for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
17855e250d20SAlex Deucher 			clock_array_index = idx[j];
1786d70229f7SAlex Deucher 			if (clock_array_index >= clock_info_array->ucNumEntries)
1787d70229f7SAlex Deucher 				continue;
1788d70229f7SAlex Deucher 			if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
1789d70229f7SAlex Deucher 				break;
1790d70229f7SAlex Deucher 			clock_info = (union pplib_clock_info *)
17915e250d20SAlex Deucher 				((u8 *)&clock_info_array->clockInfo[0] +
17925e250d20SAlex Deucher 				 (clock_array_index * clock_info_array->ucEntrySize));
1793d70229f7SAlex Deucher 			trinity_parse_pplib_clock_info(rdev,
1794d70229f7SAlex Deucher 						       &rdev->pm.dpm.ps[i], k,
1795d70229f7SAlex Deucher 						       clock_info);
1796d70229f7SAlex Deucher 			k++;
1797d70229f7SAlex Deucher 		}
1798d70229f7SAlex Deucher 		trinity_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
1799d70229f7SAlex Deucher 						   non_clock_info,
1800d70229f7SAlex Deucher 						   non_clock_info_array->ucEntrySize);
1801d70229f7SAlex Deucher 		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
1802d70229f7SAlex Deucher 	}
1803d70229f7SAlex Deucher 	rdev->pm.dpm.num_ps = state_array->ucNumEntries;
180411fe3d6eSAlex Deucher 
180511fe3d6eSAlex Deucher 	/* fill in the vce power states */
180611fe3d6eSAlex Deucher 	for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
180711fe3d6eSAlex Deucher 		u32 sclk;
180811fe3d6eSAlex Deucher 		clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
180911fe3d6eSAlex Deucher 		clock_info = (union pplib_clock_info *)
181011fe3d6eSAlex Deucher 			&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
181111fe3d6eSAlex Deucher 		sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
181211fe3d6eSAlex Deucher 		sclk |= clock_info->sumo.ucEngineClockHigh << 16;
181311fe3d6eSAlex Deucher 		rdev->pm.dpm.vce_states[i].sclk = sclk;
181411fe3d6eSAlex Deucher 		rdev->pm.dpm.vce_states[i].mclk = 0;
181511fe3d6eSAlex Deucher 	}
181611fe3d6eSAlex Deucher 
1817d70229f7SAlex Deucher 	return 0;
1818d70229f7SAlex Deucher }
1819d70229f7SAlex Deucher 
1820d70229f7SAlex Deucher union igp_info {
1821d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
1822d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
1823d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
1824d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
1825d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
1826d70229f7SAlex Deucher };
1827d70229f7SAlex Deucher 
18280c4aaeaeSAlex Deucher static u32 trinity_convert_did_to_freq(struct radeon_device *rdev, u8 did)
18290c4aaeaeSAlex Deucher {
18300c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
18310c4aaeaeSAlex Deucher 	u32 divider;
18320c4aaeaeSAlex Deucher 
18330c4aaeaeSAlex Deucher 	if (did >= 8 && did <= 0x3f)
18340c4aaeaeSAlex Deucher 		divider = did * 25;
18350c4aaeaeSAlex Deucher 	else if (did > 0x3f && did <= 0x5f)
18360c4aaeaeSAlex Deucher 		divider = (did - 64) * 50 + 1600;
18370c4aaeaeSAlex Deucher 	else if (did > 0x5f && did <= 0x7e)
18380c4aaeaeSAlex Deucher 		divider = (did - 96) * 100 + 3200;
18390c4aaeaeSAlex Deucher 	else if (did == 0x7f)
18400c4aaeaeSAlex Deucher 		divider = 128 * 100;
18410c4aaeaeSAlex Deucher 	else
18420c4aaeaeSAlex Deucher 		return 10000;
18430c4aaeaeSAlex Deucher 
18440c4aaeaeSAlex Deucher 	return ((pi->sys_info.dentist_vco_freq * 100) + (divider - 1)) / divider;
18450c4aaeaeSAlex Deucher }
18460c4aaeaeSAlex Deucher 
1847d70229f7SAlex Deucher static int trinity_parse_sys_info_table(struct radeon_device *rdev)
1848d70229f7SAlex Deucher {
1849d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1850d70229f7SAlex Deucher 	struct radeon_mode_info *mode_info = &rdev->mode_info;
1851d70229f7SAlex Deucher 	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
1852d70229f7SAlex Deucher 	union igp_info *igp_info;
1853d70229f7SAlex Deucher 	u8 frev, crev;
1854d70229f7SAlex Deucher 	u16 data_offset;
1855d70229f7SAlex Deucher 	int i;
1856d70229f7SAlex Deucher 
1857d70229f7SAlex Deucher 	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1858d70229f7SAlex Deucher 				   &frev, &crev, &data_offset)) {
1859d70229f7SAlex Deucher 		igp_info = (union igp_info *)(mode_info->atom_context->bios +
1860d70229f7SAlex Deucher 					      data_offset);
1861d70229f7SAlex Deucher 
1862d70229f7SAlex Deucher 		if (crev != 7) {
1863d70229f7SAlex Deucher 			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
1864d70229f7SAlex Deucher 			return -EINVAL;
1865d70229f7SAlex Deucher 		}
1866d70229f7SAlex Deucher 		pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock);
1867d70229f7SAlex Deucher 		pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock);
1868d70229f7SAlex Deucher 		pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock);
18690c4aaeaeSAlex Deucher 		pi->sys_info.dentist_vco_freq = le32_to_cpu(igp_info->info_7.ulDentistVCOFreq);
1870d70229f7SAlex Deucher 		pi->sys_info.bootup_nb_voltage_index =
1871d70229f7SAlex Deucher 			le16_to_cpu(igp_info->info_7.usBootUpNBVoltage);
1872d70229f7SAlex Deucher 		if (igp_info->info_7.ucHtcTmpLmt == 0)
1873d70229f7SAlex Deucher 			pi->sys_info.htc_tmp_lmt = 203;
1874d70229f7SAlex Deucher 		else
1875d70229f7SAlex Deucher 			pi->sys_info.htc_tmp_lmt = igp_info->info_7.ucHtcTmpLmt;
1876d70229f7SAlex Deucher 		if (igp_info->info_7.ucHtcHystLmt == 0)
1877d70229f7SAlex Deucher 			pi->sys_info.htc_hyst_lmt = 5;
1878d70229f7SAlex Deucher 		else
1879d70229f7SAlex Deucher 			pi->sys_info.htc_hyst_lmt = igp_info->info_7.ucHtcHystLmt;
1880d70229f7SAlex Deucher 		if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
1881d70229f7SAlex Deucher 			DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
1882d70229f7SAlex Deucher 		}
1883d70229f7SAlex Deucher 
1884d70229f7SAlex Deucher 		if (pi->enable_nbps_policy)
1885d70229f7SAlex Deucher 			pi->sys_info.nb_dpm_enable = igp_info->info_7.ucNBDPMEnable;
1886d70229f7SAlex Deucher 		else
1887d70229f7SAlex Deucher 			pi->sys_info.nb_dpm_enable = 0;
1888d70229f7SAlex Deucher 
1889d70229f7SAlex Deucher 		for (i = 0; i < TRINITY_NUM_NBPSTATES; i++) {
1890d70229f7SAlex Deucher 			pi->sys_info.nbp_mclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateMemclkFreq[i]);
1891d70229f7SAlex Deucher 			pi->sys_info.nbp_nclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateNClkFreq[i]);
1892d70229f7SAlex Deucher 		}
1893d70229f7SAlex Deucher 
1894d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[0] = le16_to_cpu(igp_info->info_7.usNBP0Voltage);
1895d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[1] = le16_to_cpu(igp_info->info_7.usNBP1Voltage);
1896d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[2] = le16_to_cpu(igp_info->info_7.usNBP2Voltage);
1897d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[3] = le16_to_cpu(igp_info->info_7.usNBP3Voltage);
1898d70229f7SAlex Deucher 
1899d70229f7SAlex Deucher 		if (!pi->sys_info.nb_dpm_enable) {
1900d70229f7SAlex Deucher 			for (i = 1; i < TRINITY_NUM_NBPSTATES; i++) {
1901d70229f7SAlex Deucher 				pi->sys_info.nbp_mclk[i] = pi->sys_info.nbp_mclk[0];
1902d70229f7SAlex Deucher 				pi->sys_info.nbp_nclk[i] = pi->sys_info.nbp_nclk[0];
1903d70229f7SAlex Deucher 				pi->sys_info.nbp_voltage_index[i] = pi->sys_info.nbp_voltage_index[0];
1904d70229f7SAlex Deucher 			}
1905d70229f7SAlex Deucher 		}
1906d70229f7SAlex Deucher 
1907d70229f7SAlex Deucher 		pi->sys_info.uma_channel_number = igp_info->info_7.ucUMAChannelNumber;
1908d70229f7SAlex Deucher 
1909d70229f7SAlex Deucher 		sumo_construct_sclk_voltage_mapping_table(rdev,
1910d70229f7SAlex Deucher 							  &pi->sys_info.sclk_voltage_mapping_table,
1911d70229f7SAlex Deucher 							  igp_info->info_7.sAvail_SCLK);
1912d70229f7SAlex Deucher 		sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
1913d70229f7SAlex Deucher 						 igp_info->info_7.sAvail_SCLK);
1914d70229f7SAlex Deucher 
19150c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[0].vclk_did =
19160c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState0VclkFid;
19170c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[1].vclk_did =
19180c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState1VclkFid;
19190c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[2].vclk_did =
19200c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState2VclkFid;
19210c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[3].vclk_did =
19220c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState3VclkFid;
19230c4aaeaeSAlex Deucher 
19240c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[0].dclk_did =
19250c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState0DclkFid;
19260c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[1].dclk_did =
19270c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState1DclkFid;
19280c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[2].dclk_did =
19290c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState2DclkFid;
19300c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[3].dclk_did =
19310c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState3DclkFid;
19320c4aaeaeSAlex Deucher 
19330c4aaeaeSAlex Deucher 		for (i = 0; i < 4; i++) {
19340c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[i].vclk =
19350c4aaeaeSAlex Deucher 				trinity_convert_did_to_freq(rdev,
19360c4aaeaeSAlex Deucher 							    pi->sys_info.uvd_clock_table_entries[i].vclk_did);
19370c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[i].dclk =
19380c4aaeaeSAlex Deucher 				trinity_convert_did_to_freq(rdev,
19390c4aaeaeSAlex Deucher 							    pi->sys_info.uvd_clock_table_entries[i].dclk_did);
19400c4aaeaeSAlex Deucher 		}
19410c4aaeaeSAlex Deucher 
19420c4aaeaeSAlex Deucher 
19430c4aaeaeSAlex Deucher 
1944d70229f7SAlex Deucher 	}
1945d70229f7SAlex Deucher 	return 0;
1946d70229f7SAlex Deucher }
1947d70229f7SAlex Deucher 
1948d70229f7SAlex Deucher int trinity_dpm_init(struct radeon_device *rdev)
1949d70229f7SAlex Deucher {
1950d70229f7SAlex Deucher 	struct trinity_power_info *pi;
1951d70229f7SAlex Deucher 	int ret, i;
1952d70229f7SAlex Deucher 
1953d70229f7SAlex Deucher 	pi = kzalloc(sizeof(struct trinity_power_info), GFP_KERNEL);
1954d70229f7SAlex Deucher 	if (pi == NULL)
1955d70229f7SAlex Deucher 		return -ENOMEM;
1956d70229f7SAlex Deucher 	rdev->pm.dpm.priv = pi;
1957d70229f7SAlex Deucher 
1958d70229f7SAlex Deucher 	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
1959d70229f7SAlex Deucher 		pi->at[i] = TRINITY_AT_DFLT;
1960d70229f7SAlex Deucher 
19616e909f74SAlex Deucher 	if (radeon_bapm == -1) {
1962730a336cSAlex Deucher 		/* There are stability issues reported on with
1963730a336cSAlex Deucher 		 * bapm enabled when switching between AC and battery
1964730a336cSAlex Deucher 		 * power.  At the same time, some MSI boards hang
1965730a336cSAlex Deucher 		 * if it's not enabled and dpm is enabled.  Just enable
1966730a336cSAlex Deucher 		 * it for MSI boards right now.
19670c78a449SAlex Deucher 		 */
1968730a336cSAlex Deucher 		if (rdev->pdev->subsystem_vendor == 0x1462)
19690c78a449SAlex Deucher 			pi->enable_bapm = true;
1970730a336cSAlex Deucher 		else
1971730a336cSAlex Deucher 			pi->enable_bapm = false;
19726e909f74SAlex Deucher 	} else if (radeon_bapm == 0) {
19736e909f74SAlex Deucher 		pi->enable_bapm = false;
19746e909f74SAlex Deucher 	} else {
19756e909f74SAlex Deucher 		pi->enable_bapm = true;
19766e909f74SAlex Deucher 	}
1977d70229f7SAlex Deucher 	pi->enable_nbps_policy = true;
1978d70229f7SAlex Deucher 	pi->enable_sclk_ds = true;
1979d70229f7SAlex Deucher 	pi->enable_gfx_power_gating = true;
1980d70229f7SAlex Deucher 	pi->enable_gfx_clock_gating = true;
1981958b84fbSAlex Deucher 	pi->enable_mg_clock_gating = false;
1982958b84fbSAlex Deucher 	pi->enable_gfx_dynamic_mgpg = false;
1983958b84fbSAlex Deucher 	pi->override_dynamic_mgpg = false;
1984d70229f7SAlex Deucher 	pi->enable_auto_thermal_throttling = true;
1985d70229f7SAlex Deucher 	pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
19860c4aaeaeSAlex Deucher 	pi->uvd_dpm = true; /* ??? */
1987d70229f7SAlex Deucher 
1988d70229f7SAlex Deucher 	ret = trinity_parse_sys_info_table(rdev);
1989d70229f7SAlex Deucher 	if (ret)
1990d70229f7SAlex Deucher 		return ret;
1991d70229f7SAlex Deucher 
1992d70229f7SAlex Deucher 	trinity_construct_boot_state(rdev);
1993d70229f7SAlex Deucher 
199482f79cc5SAlex Deucher 	ret = r600_get_platform_caps(rdev);
199582f79cc5SAlex Deucher 	if (ret)
199682f79cc5SAlex Deucher 		return ret;
199782f79cc5SAlex Deucher 
199811fe3d6eSAlex Deucher 	ret = r600_parse_extended_power_table(rdev);
199911fe3d6eSAlex Deucher 	if (ret)
200011fe3d6eSAlex Deucher 		return ret;
200111fe3d6eSAlex Deucher 
2002d70229f7SAlex Deucher 	ret = trinity_parse_power_table(rdev);
2003d70229f7SAlex Deucher 	if (ret)
2004d70229f7SAlex Deucher 		return ret;
2005d70229f7SAlex Deucher 
2006d70229f7SAlex Deucher 	pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
2007d70229f7SAlex Deucher 	pi->enable_dpm = true;
2008d70229f7SAlex Deucher 
2009d70229f7SAlex Deucher 	return 0;
2010d70229f7SAlex Deucher }
2011d70229f7SAlex Deucher 
2012d70229f7SAlex Deucher void trinity_dpm_print_power_state(struct radeon_device *rdev,
2013d70229f7SAlex Deucher 				   struct radeon_ps *rps)
2014d70229f7SAlex Deucher {
2015d70229f7SAlex Deucher 	int i;
2016d70229f7SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
2017d70229f7SAlex Deucher 
2018d70229f7SAlex Deucher 	r600_dpm_print_class_info(rps->class, rps->class2);
2019d70229f7SAlex Deucher 	r600_dpm_print_cap_info(rps->caps);
2020d70229f7SAlex Deucher 	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
2021d70229f7SAlex Deucher 	for (i = 0; i < ps->num_levels; i++) {
2022d70229f7SAlex Deucher 		struct trinity_pl *pl = &ps->levels[i];
2023d70229f7SAlex Deucher 		printk("\t\tpower level %d    sclk: %u vddc: %u\n",
2024d70229f7SAlex Deucher 		       i, pl->sclk,
2025d70229f7SAlex Deucher 		       trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
2026d70229f7SAlex Deucher 	}
2027d70229f7SAlex Deucher 	r600_dpm_print_ps_status(rdev, rps);
2028d70229f7SAlex Deucher }
2029d70229f7SAlex Deucher 
2030490ab931SAlex Deucher void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
2031490ab931SAlex Deucher 							 struct seq_file *m)
2032490ab931SAlex Deucher {
20339f3f63f2SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
20349f3f63f2SAlex Deucher 	struct radeon_ps *rps = &pi->current_rps;
2035490ab931SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
2036490ab931SAlex Deucher 	struct trinity_pl *pl;
2037490ab931SAlex Deucher 	u32 current_index =
2038490ab931SAlex Deucher 		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
2039490ab931SAlex Deucher 		CURRENT_STATE_SHIFT;
2040490ab931SAlex Deucher 
2041490ab931SAlex Deucher 	if (current_index >= ps->num_levels) {
2042490ab931SAlex Deucher 		seq_printf(m, "invalid dpm profile %d\n", current_index);
2043490ab931SAlex Deucher 	} else {
2044490ab931SAlex Deucher 		pl = &ps->levels[current_index];
2045490ab931SAlex Deucher 		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
2046490ab931SAlex Deucher 		seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
2047490ab931SAlex Deucher 			   current_index, pl->sclk,
2048490ab931SAlex Deucher 			   trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
2049490ab931SAlex Deucher 	}
2050490ab931SAlex Deucher }
2051490ab931SAlex Deucher 
20527ce9cdaeSAlex Deucher u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev)
20537ce9cdaeSAlex Deucher {
20547ce9cdaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
20557ce9cdaeSAlex Deucher 	struct radeon_ps *rps = &pi->current_rps;
20567ce9cdaeSAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
20577ce9cdaeSAlex Deucher 	struct trinity_pl *pl;
20587ce9cdaeSAlex Deucher 	u32 current_index =
20597ce9cdaeSAlex Deucher 		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
20607ce9cdaeSAlex Deucher 		CURRENT_STATE_SHIFT;
20617ce9cdaeSAlex Deucher 
20627ce9cdaeSAlex Deucher 	if (current_index >= ps->num_levels) {
20637ce9cdaeSAlex Deucher 		return 0;
20647ce9cdaeSAlex Deucher 	} else {
20657ce9cdaeSAlex Deucher 		pl = &ps->levels[current_index];
20667ce9cdaeSAlex Deucher 		return pl->sclk;
20677ce9cdaeSAlex Deucher 	}
20687ce9cdaeSAlex Deucher }
20697ce9cdaeSAlex Deucher 
20707ce9cdaeSAlex Deucher u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev)
20717ce9cdaeSAlex Deucher {
20727ce9cdaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
20737ce9cdaeSAlex Deucher 
20747ce9cdaeSAlex Deucher 	return pi->sys_info.bootup_uma_clk;
20757ce9cdaeSAlex Deucher }
20767ce9cdaeSAlex Deucher 
2077d70229f7SAlex Deucher void trinity_dpm_fini(struct radeon_device *rdev)
2078d70229f7SAlex Deucher {
2079d70229f7SAlex Deucher 	int i;
2080d70229f7SAlex Deucher 
2081d70229f7SAlex Deucher 	trinity_cleanup_asic(rdev); /* ??? */
2082d70229f7SAlex Deucher 
2083d70229f7SAlex Deucher 	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
2084d70229f7SAlex Deucher 		kfree(rdev->pm.dpm.ps[i].ps_priv);
2085d70229f7SAlex Deucher 	}
2086d70229f7SAlex Deucher 	kfree(rdev->pm.dpm.ps);
2087d70229f7SAlex Deucher 	kfree(rdev->pm.dpm.priv);
208811fe3d6eSAlex Deucher 	r600_free_extended_power_table(rdev);
2089d70229f7SAlex Deucher }
2090d70229f7SAlex Deucher 
2091d70229f7SAlex Deucher u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
2092d70229f7SAlex Deucher {
2093a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
2094a284c48aSAlex Deucher 	struct trinity_ps *requested_state = trinity_get_ps(&pi->requested_rps);
2095d70229f7SAlex Deucher 
2096d70229f7SAlex Deucher 	if (low)
2097d70229f7SAlex Deucher 		return requested_state->levels[0].sclk;
2098d70229f7SAlex Deucher 	else
2099d70229f7SAlex Deucher 		return requested_state->levels[requested_state->num_levels - 1].sclk;
2100d70229f7SAlex Deucher }
2101d70229f7SAlex Deucher 
2102d70229f7SAlex Deucher u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low)
2103d70229f7SAlex Deucher {
2104d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
2105d70229f7SAlex Deucher 
2106d70229f7SAlex Deucher 	return pi->sys_info.bootup_uma_clk;
2107d70229f7SAlex Deucher }
2108