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 
24d70229f7SAlex Deucher #include "drmP.h"
25d70229f7SAlex Deucher #include "radeon.h"
26d70229f7SAlex Deucher #include "trinityd.h"
27d70229f7SAlex Deucher #include "r600_dpm.h"
28d70229f7SAlex Deucher #include "trinity_dpm.h"
29bf0936e1SMike Lothian #include <linux/seq_file.h>
30d70229f7SAlex Deucher 
31d70229f7SAlex Deucher #define TRINITY_MAX_DEEPSLEEP_DIVIDER_ID 5
32d70229f7SAlex Deucher #define TRINITY_MINIMUM_ENGINE_CLOCK 800
33d70229f7SAlex Deucher #define SCLK_MIN_DIV_INTV_SHIFT     12
34d70229f7SAlex Deucher #define TRINITY_DISPCLK_BYPASS_THRESHOLD 10000
35d70229f7SAlex Deucher 
36d70229f7SAlex Deucher #ifndef TRINITY_MGCG_SEQUENCE
37d70229f7SAlex Deucher #define TRINITY_MGCG_SEQUENCE  100
38d70229f7SAlex Deucher 
39d70229f7SAlex Deucher static const u32 trinity_mgcg_shls_default[] =
40d70229f7SAlex Deucher {
41d70229f7SAlex Deucher 	/* Register, Value, Mask */
42d70229f7SAlex Deucher 	0x0000802c, 0xc0000000, 0xffffffff,
43d70229f7SAlex Deucher 	0x00003fc4, 0xc0000000, 0xffffffff,
44d70229f7SAlex Deucher 	0x00005448, 0x00000100, 0xffffffff,
45d70229f7SAlex Deucher 	0x000055e4, 0x00000100, 0xffffffff,
46d70229f7SAlex Deucher 	0x0000160c, 0x00000100, 0xffffffff,
47d70229f7SAlex Deucher 	0x00008984, 0x06000100, 0xffffffff,
48d70229f7SAlex Deucher 	0x0000c164, 0x00000100, 0xffffffff,
49d70229f7SAlex Deucher 	0x00008a18, 0x00000100, 0xffffffff,
50d70229f7SAlex Deucher 	0x0000897c, 0x06000100, 0xffffffff,
51d70229f7SAlex Deucher 	0x00008b28, 0x00000100, 0xffffffff,
52d70229f7SAlex Deucher 	0x00009144, 0x00800200, 0xffffffff,
53d70229f7SAlex Deucher 	0x00009a60, 0x00000100, 0xffffffff,
54d70229f7SAlex Deucher 	0x00009868, 0x00000100, 0xffffffff,
55d70229f7SAlex Deucher 	0x00008d58, 0x00000100, 0xffffffff,
56d70229f7SAlex Deucher 	0x00009510, 0x00000100, 0xffffffff,
57d70229f7SAlex Deucher 	0x0000949c, 0x00000100, 0xffffffff,
58d70229f7SAlex Deucher 	0x00009654, 0x00000100, 0xffffffff,
59d70229f7SAlex Deucher 	0x00009030, 0x00000100, 0xffffffff,
60d70229f7SAlex Deucher 	0x00009034, 0x00000100, 0xffffffff,
61d70229f7SAlex Deucher 	0x00009038, 0x00000100, 0xffffffff,
62d70229f7SAlex Deucher 	0x0000903c, 0x00000100, 0xffffffff,
63d70229f7SAlex Deucher 	0x00009040, 0x00000100, 0xffffffff,
64d70229f7SAlex Deucher 	0x0000a200, 0x00000100, 0xffffffff,
65d70229f7SAlex Deucher 	0x0000a204, 0x00000100, 0xffffffff,
66d70229f7SAlex Deucher 	0x0000a208, 0x00000100, 0xffffffff,
67d70229f7SAlex Deucher 	0x0000a20c, 0x00000100, 0xffffffff,
68d70229f7SAlex Deucher 	0x00009744, 0x00000100, 0xffffffff,
69d70229f7SAlex Deucher 	0x00003f80, 0x00000100, 0xffffffff,
70d70229f7SAlex Deucher 	0x0000a210, 0x00000100, 0xffffffff,
71d70229f7SAlex Deucher 	0x0000a214, 0x00000100, 0xffffffff,
72d70229f7SAlex Deucher 	0x000004d8, 0x00000100, 0xffffffff,
73d70229f7SAlex Deucher 	0x00009664, 0x00000100, 0xffffffff,
74d70229f7SAlex Deucher 	0x00009698, 0x00000100, 0xffffffff,
75d70229f7SAlex Deucher 	0x000004d4, 0x00000200, 0xffffffff,
76d70229f7SAlex Deucher 	0x000004d0, 0x00000000, 0xffffffff,
77d70229f7SAlex Deucher 	0x000030cc, 0x00000104, 0xffffffff,
78d70229f7SAlex Deucher 	0x0000d0c0, 0x00000100, 0xffffffff,
79d70229f7SAlex Deucher 	0x0000d8c0, 0x00000100, 0xffffffff,
80d70229f7SAlex Deucher 	0x0000951c, 0x00010000, 0xffffffff,
81d70229f7SAlex Deucher 	0x00009160, 0x00030002, 0xffffffff,
82d70229f7SAlex Deucher 	0x00009164, 0x00050004, 0xffffffff,
83d70229f7SAlex Deucher 	0x00009168, 0x00070006, 0xffffffff,
84d70229f7SAlex Deucher 	0x00009178, 0x00070000, 0xffffffff,
85d70229f7SAlex Deucher 	0x0000917c, 0x00030002, 0xffffffff,
86d70229f7SAlex Deucher 	0x00009180, 0x00050004, 0xffffffff,
87d70229f7SAlex Deucher 	0x0000918c, 0x00010006, 0xffffffff,
88d70229f7SAlex Deucher 	0x00009190, 0x00090008, 0xffffffff,
89d70229f7SAlex Deucher 	0x00009194, 0x00070000, 0xffffffff,
90d70229f7SAlex Deucher 	0x00009198, 0x00030002, 0xffffffff,
91d70229f7SAlex Deucher 	0x0000919c, 0x00050004, 0xffffffff,
92d70229f7SAlex Deucher 	0x000091a8, 0x00010006, 0xffffffff,
93d70229f7SAlex Deucher 	0x000091ac, 0x00090008, 0xffffffff,
94d70229f7SAlex Deucher 	0x000091b0, 0x00070000, 0xffffffff,
95d70229f7SAlex Deucher 	0x000091b4, 0x00030002, 0xffffffff,
96d70229f7SAlex Deucher 	0x000091b8, 0x00050004, 0xffffffff,
97d70229f7SAlex Deucher 	0x000091c4, 0x00010006, 0xffffffff,
98d70229f7SAlex Deucher 	0x000091c8, 0x00090008, 0xffffffff,
99d70229f7SAlex Deucher 	0x000091cc, 0x00070000, 0xffffffff,
100d70229f7SAlex Deucher 	0x000091d0, 0x00030002, 0xffffffff,
101d70229f7SAlex Deucher 	0x000091d4, 0x00050004, 0xffffffff,
102d70229f7SAlex Deucher 	0x000091e0, 0x00010006, 0xffffffff,
103d70229f7SAlex Deucher 	0x000091e4, 0x00090008, 0xffffffff,
104d70229f7SAlex Deucher 	0x000091e8, 0x00000000, 0xffffffff,
105d70229f7SAlex Deucher 	0x000091ec, 0x00070000, 0xffffffff,
106d70229f7SAlex Deucher 	0x000091f0, 0x00030002, 0xffffffff,
107d70229f7SAlex Deucher 	0x000091f4, 0x00050004, 0xffffffff,
108d70229f7SAlex Deucher 	0x00009200, 0x00010006, 0xffffffff,
109d70229f7SAlex Deucher 	0x00009204, 0x00090008, 0xffffffff,
110d70229f7SAlex Deucher 	0x00009208, 0x00070000, 0xffffffff,
111d70229f7SAlex Deucher 	0x0000920c, 0x00030002, 0xffffffff,
112d70229f7SAlex Deucher 	0x00009210, 0x00050004, 0xffffffff,
113d70229f7SAlex Deucher 	0x0000921c, 0x00010006, 0xffffffff,
114d70229f7SAlex Deucher 	0x00009220, 0x00090008, 0xffffffff,
115d70229f7SAlex Deucher 	0x00009294, 0x00000000, 0xffffffff
116d70229f7SAlex Deucher };
117d70229f7SAlex Deucher 
118d70229f7SAlex Deucher static const u32 trinity_mgcg_shls_enable[] =
119d70229f7SAlex Deucher {
120d70229f7SAlex Deucher 	/* Register, Value, Mask */
121d70229f7SAlex Deucher 	0x0000802c, 0xc0000000, 0xffffffff,
122d70229f7SAlex Deucher 	0x000008f8, 0x00000000, 0xffffffff,
123d70229f7SAlex Deucher 	0x000008fc, 0x00000000, 0x000133FF,
124d70229f7SAlex Deucher 	0x000008f8, 0x00000001, 0xffffffff,
125d70229f7SAlex Deucher 	0x000008fc, 0x00000000, 0xE00B03FC,
126d70229f7SAlex Deucher 	0x00009150, 0x96944200, 0xffffffff
127d70229f7SAlex Deucher };
128d70229f7SAlex Deucher 
129d70229f7SAlex Deucher static const u32 trinity_mgcg_shls_disable[] =
130d70229f7SAlex Deucher {
131d70229f7SAlex Deucher 	/* Register, Value, Mask */
132d70229f7SAlex Deucher 	0x0000802c, 0xc0000000, 0xffffffff,
133d70229f7SAlex Deucher 	0x00009150, 0x00600000, 0xffffffff,
134d70229f7SAlex Deucher 	0x000008f8, 0x00000000, 0xffffffff,
135d70229f7SAlex Deucher 	0x000008fc, 0xffffffff, 0x000133FF,
136d70229f7SAlex Deucher 	0x000008f8, 0x00000001, 0xffffffff,
137d70229f7SAlex Deucher 	0x000008fc, 0xffffffff, 0xE00B03FC
138d70229f7SAlex Deucher };
139d70229f7SAlex Deucher #endif
140d70229f7SAlex Deucher 
141d70229f7SAlex Deucher #ifndef TRINITY_SYSLS_SEQUENCE
142d70229f7SAlex Deucher #define TRINITY_SYSLS_SEQUENCE  100
143d70229f7SAlex Deucher 
144d70229f7SAlex Deucher static const u32 trinity_sysls_default[] =
145d70229f7SAlex Deucher {
146d70229f7SAlex Deucher 	/* Register, Value, Mask */
147d70229f7SAlex Deucher 	0x000055e8, 0x00000000, 0xffffffff,
148d70229f7SAlex Deucher 	0x0000d0bc, 0x00000000, 0xffffffff,
149d70229f7SAlex Deucher 	0x0000d8bc, 0x00000000, 0xffffffff,
150d70229f7SAlex Deucher 	0x000015c0, 0x000c1401, 0xffffffff,
151d70229f7SAlex Deucher 	0x0000264c, 0x000c0400, 0xffffffff,
152d70229f7SAlex Deucher 	0x00002648, 0x000c0400, 0xffffffff,
153d70229f7SAlex Deucher 	0x00002650, 0x000c0400, 0xffffffff,
154d70229f7SAlex Deucher 	0x000020b8, 0x000c0400, 0xffffffff,
155d70229f7SAlex Deucher 	0x000020bc, 0x000c0400, 0xffffffff,
156d70229f7SAlex Deucher 	0x000020c0, 0x000c0c80, 0xffffffff,
157d70229f7SAlex Deucher 	0x0000f4a0, 0x000000c0, 0xffffffff,
158d70229f7SAlex Deucher 	0x0000f4a4, 0x00680fff, 0xffffffff,
159d70229f7SAlex Deucher 	0x00002f50, 0x00000404, 0xffffffff,
160d70229f7SAlex Deucher 	0x000004c8, 0x00000001, 0xffffffff,
161d70229f7SAlex Deucher 	0x0000641c, 0x00000000, 0xffffffff,
162d70229f7SAlex Deucher 	0x00000c7c, 0x00000000, 0xffffffff,
163d70229f7SAlex Deucher 	0x00006dfc, 0x00000000, 0xffffffff
164d70229f7SAlex Deucher };
165d70229f7SAlex Deucher 
166d70229f7SAlex Deucher static const u32 trinity_sysls_disable[] =
167d70229f7SAlex Deucher {
168d70229f7SAlex Deucher 	/* Register, Value, Mask */
169d70229f7SAlex Deucher 	0x0000d0c0, 0x00000000, 0xffffffff,
170d70229f7SAlex Deucher 	0x0000d8c0, 0x00000000, 0xffffffff,
171d70229f7SAlex Deucher 	0x000055e8, 0x00000000, 0xffffffff,
172d70229f7SAlex Deucher 	0x0000d0bc, 0x00000000, 0xffffffff,
173d70229f7SAlex Deucher 	0x0000d8bc, 0x00000000, 0xffffffff,
174d70229f7SAlex Deucher 	0x000015c0, 0x00041401, 0xffffffff,
175d70229f7SAlex Deucher 	0x0000264c, 0x00040400, 0xffffffff,
176d70229f7SAlex Deucher 	0x00002648, 0x00040400, 0xffffffff,
177d70229f7SAlex Deucher 	0x00002650, 0x00040400, 0xffffffff,
178d70229f7SAlex Deucher 	0x000020b8, 0x00040400, 0xffffffff,
179d70229f7SAlex Deucher 	0x000020bc, 0x00040400, 0xffffffff,
180d70229f7SAlex Deucher 	0x000020c0, 0x00040c80, 0xffffffff,
181d70229f7SAlex Deucher 	0x0000f4a0, 0x000000c0, 0xffffffff,
182d70229f7SAlex Deucher 	0x0000f4a4, 0x00680000, 0xffffffff,
183d70229f7SAlex Deucher 	0x00002f50, 0x00000404, 0xffffffff,
184d70229f7SAlex Deucher 	0x000004c8, 0x00000001, 0xffffffff,
185d70229f7SAlex Deucher 	0x0000641c, 0x00007ffd, 0xffffffff,
186d70229f7SAlex Deucher 	0x00000c7c, 0x0000ff00, 0xffffffff,
187d70229f7SAlex Deucher 	0x00006dfc, 0x0000007f, 0xffffffff
188d70229f7SAlex Deucher };
189d70229f7SAlex Deucher 
190d70229f7SAlex Deucher static const u32 trinity_sysls_enable[] =
191d70229f7SAlex Deucher {
192d70229f7SAlex Deucher 	/* Register, Value, Mask */
193d70229f7SAlex Deucher 	0x000055e8, 0x00000001, 0xffffffff,
194d70229f7SAlex Deucher 	0x0000d0bc, 0x00000100, 0xffffffff,
195d70229f7SAlex Deucher 	0x0000d8bc, 0x00000100, 0xffffffff,
196d70229f7SAlex Deucher 	0x000015c0, 0x000c1401, 0xffffffff,
197d70229f7SAlex Deucher 	0x0000264c, 0x000c0400, 0xffffffff,
198d70229f7SAlex Deucher 	0x00002648, 0x000c0400, 0xffffffff,
199d70229f7SAlex Deucher 	0x00002650, 0x000c0400, 0xffffffff,
200d70229f7SAlex Deucher 	0x000020b8, 0x000c0400, 0xffffffff,
201d70229f7SAlex Deucher 	0x000020bc, 0x000c0400, 0xffffffff,
202d70229f7SAlex Deucher 	0x000020c0, 0x000c0c80, 0xffffffff,
203d70229f7SAlex Deucher 	0x0000f4a0, 0x000000c0, 0xffffffff,
204d70229f7SAlex Deucher 	0x0000f4a4, 0x00680fff, 0xffffffff,
205d70229f7SAlex Deucher 	0x00002f50, 0x00000903, 0xffffffff,
206d70229f7SAlex Deucher 	0x000004c8, 0x00000000, 0xffffffff,
207d70229f7SAlex Deucher 	0x0000641c, 0x00000000, 0xffffffff,
208d70229f7SAlex Deucher 	0x00000c7c, 0x00000000, 0xffffffff,
209d70229f7SAlex Deucher 	0x00006dfc, 0x00000000, 0xffffffff
210d70229f7SAlex Deucher };
211d70229f7SAlex Deucher #endif
212d70229f7SAlex Deucher 
213d70229f7SAlex Deucher static const u32 trinity_override_mgpg_sequences[] =
214d70229f7SAlex Deucher {
215d70229f7SAlex Deucher 	/* Register, Value */
216d70229f7SAlex Deucher 	0x00000200, 0xE030032C,
217d70229f7SAlex Deucher 	0x00000204, 0x00000FFF,
218d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
219d70229f7SAlex Deucher 	0x00000204, 0x00030301,
220d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
221d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
222d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
223d70229f7SAlex Deucher 	0x00000204, 0x00030301,
224d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
225d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
226d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
227d70229f7SAlex Deucher 	0x00000204, 0x00030301,
228d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
229d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
230d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
231d70229f7SAlex Deucher 	0x00000204, 0x00030301,
232d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
233d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
234d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
235d70229f7SAlex Deucher 	0x00000204, 0x00030301,
236d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
237d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
238d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
239d70229f7SAlex Deucher 	0x00000204, 0x00030301,
240d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
241d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
242d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
243d70229f7SAlex Deucher 	0x00000204, 0x00030301,
244d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
245d70229f7SAlex Deucher 	0x00000204, 0x500010FF,
246d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
247d70229f7SAlex Deucher 	0x00000204, 0x00030303,
248d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
249d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
250d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
251d70229f7SAlex Deucher 	0x00000204, 0x00030303,
252d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
253d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
254d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
255d70229f7SAlex Deucher 	0x00000204, 0x00030303,
256d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
257d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
258d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
259d70229f7SAlex Deucher 	0x00000204, 0x00030303,
260d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
261d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
262d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
263d70229f7SAlex Deucher 	0x00000204, 0x00030303,
264d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
265d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
266d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
267d70229f7SAlex Deucher 	0x00000204, 0x00030303,
268d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
269d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
270d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
271d70229f7SAlex Deucher 	0x00000204, 0x00030303,
272d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
273d70229f7SAlex Deucher 	0x00000204, 0x600010FF,
274d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
275d70229f7SAlex Deucher 	0x00000204, 0x00030303,
276d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
277d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
278d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
279d70229f7SAlex Deucher 	0x00000204, 0x00030303,
280d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
281d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
282d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
283d70229f7SAlex Deucher 	0x00000204, 0x00030303,
284d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
285d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
286d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
287d70229f7SAlex Deucher 	0x00000204, 0x00030303,
288d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
289d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
290d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
291d70229f7SAlex Deucher 	0x00000204, 0x00030303,
292d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
293d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
294d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
295d70229f7SAlex Deucher 	0x00000204, 0x00030303,
296d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
297d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
298d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
299d70229f7SAlex Deucher 	0x00000204, 0x00030303,
300d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
301d70229f7SAlex Deucher 	0x00000204, 0x700010FF,
302d70229f7SAlex Deucher 	0x00000200, 0xE0300058,
303d70229f7SAlex Deucher 	0x00000204, 0x00010303,
304d70229f7SAlex Deucher 	0x00000200, 0xE0300054,
305d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
306d70229f7SAlex Deucher 	0x00000200, 0xE0300074,
307d70229f7SAlex Deucher 	0x00000204, 0x00010303,
308d70229f7SAlex Deucher 	0x00000200, 0xE0300070,
309d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
310d70229f7SAlex Deucher 	0x00000200, 0xE0300090,
311d70229f7SAlex Deucher 	0x00000204, 0x00010303,
312d70229f7SAlex Deucher 	0x00000200, 0xE030008C,
313d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
314d70229f7SAlex Deucher 	0x00000200, 0xE03000AC,
315d70229f7SAlex Deucher 	0x00000204, 0x00010303,
316d70229f7SAlex Deucher 	0x00000200, 0xE03000A8,
317d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
318d70229f7SAlex Deucher 	0x00000200, 0xE03000C4,
319d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
320d70229f7SAlex Deucher 	0x00000200, 0xE03000C8,
321d70229f7SAlex Deucher 	0x00000204, 0x00010303,
322d70229f7SAlex Deucher 	0x00000200, 0xE03000E4,
323d70229f7SAlex Deucher 	0x00000204, 0x00010303,
324d70229f7SAlex Deucher 	0x00000200, 0xE03000E0,
325d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
326d70229f7SAlex Deucher 	0x00000200, 0xE0300100,
327d70229f7SAlex Deucher 	0x00000204, 0x00010303,
328d70229f7SAlex Deucher 	0x00000200, 0xE03000FC,
329d70229f7SAlex Deucher 	0x00000204, 0x800010FF,
330d70229f7SAlex Deucher 	0x00000200, 0x0001f198,
331d70229f7SAlex Deucher 	0x00000204, 0x0003ffff,
332d70229f7SAlex Deucher 	0x00000200, 0x0001f19C,
333d70229f7SAlex Deucher 	0x00000204, 0x3fffffff,
334d70229f7SAlex Deucher 	0x00000200, 0xE030032C,
335d70229f7SAlex Deucher 	0x00000204, 0x00000000,
336d70229f7SAlex Deucher };
337d70229f7SAlex Deucher 
338d70229f7SAlex Deucher static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
339d70229f7SAlex Deucher 						   const u32 *seq, u32 count);
340d70229f7SAlex Deucher static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev);
341940eea8eSAlex Deucher static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
342940eea8eSAlex Deucher 					     struct radeon_ps *new_rps,
343940eea8eSAlex Deucher 					     struct radeon_ps *old_rps);
344d70229f7SAlex Deucher 
345fbb74bceSAlex Deucher static struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
346d70229f7SAlex Deucher {
347d70229f7SAlex Deucher 	struct trinity_ps *ps = rps->ps_priv;
348d70229f7SAlex Deucher 
349d70229f7SAlex Deucher 	return ps;
350d70229f7SAlex Deucher }
351d70229f7SAlex Deucher 
352fbb74bceSAlex Deucher static struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)
353d70229f7SAlex Deucher {
354d70229f7SAlex Deucher 	struct trinity_power_info *pi = rdev->pm.dpm.priv;
355d70229f7SAlex Deucher 
356d70229f7SAlex Deucher 	return pi;
357d70229f7SAlex Deucher }
358d70229f7SAlex Deucher 
359d70229f7SAlex Deucher static void trinity_gfx_powergating_initialize(struct radeon_device *rdev)
360d70229f7SAlex Deucher {
361d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
362d70229f7SAlex Deucher 	u32 p, u;
363d70229f7SAlex Deucher 	u32 value;
364d70229f7SAlex Deucher 	struct atom_clock_dividers dividers;
3659d45ad5aSAlex Deucher 	u32 xclk = radeon_get_xclk(rdev);
366d70229f7SAlex Deucher 	u32 sssd = 1;
367d70229f7SAlex Deucher 	int ret;
368d70229f7SAlex Deucher 	u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
369d70229f7SAlex Deucher 
370d70229f7SAlex Deucher         ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
371d70229f7SAlex Deucher                                              25000, false, &dividers);
372d70229f7SAlex Deucher 	if (ret)
373d70229f7SAlex Deucher 		return;
374d70229f7SAlex Deucher 
375d70229f7SAlex Deucher 	value = RREG32_SMC(GFX_POWER_GATING_CNTL);
376d70229f7SAlex Deucher 	value &= ~(SSSD_MASK | PDS_DIV_MASK);
377d70229f7SAlex Deucher 	if (sssd)
378d70229f7SAlex Deucher 		value |= SSSD(1);
379d70229f7SAlex Deucher 	value |= PDS_DIV(dividers.post_div);
380d70229f7SAlex Deucher 	WREG32_SMC(GFX_POWER_GATING_CNTL, value);
381d70229f7SAlex Deucher 
382d70229f7SAlex Deucher 	r600_calculate_u_and_p(500, xclk, 16, &p, &u);
383d70229f7SAlex Deucher 
384d70229f7SAlex Deucher 	WREG32(CG_PG_CTRL, SP(p) | SU(u));
385d70229f7SAlex Deucher 
386d70229f7SAlex Deucher 	WREG32_P(CG_GIPOTS, CG_GIPOT(p), ~CG_GIPOT_MASK);
387d70229f7SAlex Deucher 
388d70229f7SAlex Deucher 	/* XXX double check hw_rev */
389d70229f7SAlex Deucher 	if (pi->override_dynamic_mgpg && (hw_rev == 0))
390d70229f7SAlex Deucher 		trinity_override_dynamic_mg_powergating(rdev);
391d70229f7SAlex Deucher 
392d70229f7SAlex Deucher }
393d70229f7SAlex Deucher 
394d70229f7SAlex Deucher #define CGCG_CGTT_LOCAL0_MASK       0xFFFF33FF
395d70229f7SAlex Deucher #define CGCG_CGTT_LOCAL1_MASK       0xFFFB0FFE
396d70229f7SAlex Deucher #define CGTS_SM_CTRL_REG_DISABLE    0x00600000
397d70229f7SAlex Deucher #define CGTS_SM_CTRL_REG_ENABLE     0x96944200
398d70229f7SAlex Deucher 
399d70229f7SAlex Deucher static void trinity_mg_clockgating_enable(struct radeon_device *rdev,
400d70229f7SAlex Deucher 					  bool enable)
401d70229f7SAlex Deucher {
402d70229f7SAlex Deucher 	u32 local0;
403d70229f7SAlex Deucher 	u32 local1;
404d70229f7SAlex Deucher 
405d70229f7SAlex Deucher 	if (enable) {
406d70229f7SAlex Deucher 		local0 = RREG32_CG(CG_CGTT_LOCAL_0);
407d70229f7SAlex Deucher 		local1 = RREG32_CG(CG_CGTT_LOCAL_1);
408d70229f7SAlex Deucher 
409d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_0,
410d70229f7SAlex Deucher 			  (0x00380000 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
411d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_1,
412d70229f7SAlex Deucher 			  (0x0E000000 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
413d70229f7SAlex Deucher 
414d70229f7SAlex Deucher 		WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_ENABLE);
415d70229f7SAlex Deucher 	} else {
416d70229f7SAlex Deucher 		WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_DISABLE);
417d70229f7SAlex Deucher 
418d70229f7SAlex Deucher 		local0 = RREG32_CG(CG_CGTT_LOCAL_0);
419d70229f7SAlex Deucher 		local1 = RREG32_CG(CG_CGTT_LOCAL_1);
420d70229f7SAlex Deucher 
421d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_0,
422d70229f7SAlex Deucher 			  CGCG_CGTT_LOCAL0_MASK | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
423d70229f7SAlex Deucher 		WREG32_CG(CG_CGTT_LOCAL_1,
424d70229f7SAlex Deucher 			  CGCG_CGTT_LOCAL1_MASK | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
425d70229f7SAlex Deucher 	}
426d70229f7SAlex Deucher }
427d70229f7SAlex Deucher 
428d70229f7SAlex Deucher static void trinity_mg_clockgating_initialize(struct radeon_device *rdev)
429d70229f7SAlex Deucher {
430d70229f7SAlex Deucher 	u32 count;
431d70229f7SAlex Deucher 	const u32 *seq = NULL;
432d70229f7SAlex Deucher 
433d70229f7SAlex Deucher 	seq = &trinity_mgcg_shls_default[0];
434d70229f7SAlex Deucher 	count = sizeof(trinity_mgcg_shls_default) / (3 * sizeof(u32));
435d70229f7SAlex Deucher 
436d70229f7SAlex Deucher 	trinity_program_clk_gating_hw_sequence(rdev, seq, count);
437d70229f7SAlex Deucher }
438d70229f7SAlex Deucher 
439d70229f7SAlex Deucher static void trinity_gfx_clockgating_enable(struct radeon_device *rdev,
440d70229f7SAlex Deucher 					   bool enable)
441d70229f7SAlex Deucher {
442d70229f7SAlex Deucher 	if (enable) {
443d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
444d70229f7SAlex Deucher 	} else {
445d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
446d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
447d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
448d70229f7SAlex Deucher 		RREG32(GB_ADDR_CONFIG);
449d70229f7SAlex Deucher 	}
450d70229f7SAlex Deucher }
451d70229f7SAlex Deucher 
452d70229f7SAlex Deucher static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
453d70229f7SAlex Deucher 						   const u32 *seq, u32 count)
454d70229f7SAlex Deucher {
455d70229f7SAlex Deucher 	u32 i, length = count * 3;
456d70229f7SAlex Deucher 
457d70229f7SAlex Deucher 	for (i = 0; i < length; i += 3)
458d70229f7SAlex Deucher 		WREG32_P(seq[i], seq[i+1], ~seq[i+2]);
459d70229f7SAlex Deucher }
460d70229f7SAlex Deucher 
461d70229f7SAlex Deucher static void trinity_program_override_mgpg_sequences(struct radeon_device *rdev,
462d70229f7SAlex Deucher 						    const u32 *seq, u32 count)
463d70229f7SAlex Deucher {
464d70229f7SAlex Deucher 	u32  i, length = count * 2;
465d70229f7SAlex Deucher 
466d70229f7SAlex Deucher 	for (i = 0; i < length; i += 2)
467d70229f7SAlex Deucher 		WREG32(seq[i], seq[i+1]);
468d70229f7SAlex Deucher 
469d70229f7SAlex Deucher }
470d70229f7SAlex Deucher 
471d70229f7SAlex Deucher static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev)
472d70229f7SAlex Deucher {
473d70229f7SAlex Deucher 	u32 count;
474d70229f7SAlex Deucher 	const u32 *seq = NULL;
475d70229f7SAlex Deucher 
476d70229f7SAlex Deucher 	seq = &trinity_override_mgpg_sequences[0];
477d70229f7SAlex Deucher 	count = sizeof(trinity_override_mgpg_sequences) / (2 * sizeof(u32));
478d70229f7SAlex Deucher 
479d70229f7SAlex Deucher 	trinity_program_override_mgpg_sequences(rdev, seq, count);
480d70229f7SAlex Deucher }
481d70229f7SAlex Deucher 
482d70229f7SAlex Deucher static void trinity_ls_clockgating_enable(struct radeon_device *rdev,
483d70229f7SAlex Deucher 					  bool enable)
484d70229f7SAlex Deucher {
485d70229f7SAlex Deucher 	u32 count;
486d70229f7SAlex Deucher 	const u32 *seq = NULL;
487d70229f7SAlex Deucher 
488d70229f7SAlex Deucher 	if (enable) {
489d70229f7SAlex Deucher 		seq = &trinity_sysls_enable[0];
490d70229f7SAlex Deucher 		count = sizeof(trinity_sysls_enable) / (3 * sizeof(u32));
491d70229f7SAlex Deucher 	} else {
492d70229f7SAlex Deucher 		seq = &trinity_sysls_disable[0];
493d70229f7SAlex Deucher 		count = sizeof(trinity_sysls_disable) / (3 * sizeof(u32));
494d70229f7SAlex Deucher 	}
495d70229f7SAlex Deucher 
496d70229f7SAlex Deucher 	trinity_program_clk_gating_hw_sequence(rdev, seq, count);
497d70229f7SAlex Deucher }
498d70229f7SAlex Deucher 
499d70229f7SAlex Deucher static void trinity_gfx_powergating_enable(struct radeon_device *rdev,
500d70229f7SAlex Deucher 					   bool enable)
501d70229f7SAlex Deucher {
502d70229f7SAlex Deucher 	if (enable) {
503d70229f7SAlex Deucher 		if (RREG32_SMC(CC_SMU_TST_EFUSE1_MISC) & RB_BACKEND_DISABLE_MASK)
504d70229f7SAlex Deucher 			WREG32_SMC(SMU_SCRATCH_A, (RREG32_SMC(SMU_SCRATCH_A) | 0x01));
505d70229f7SAlex Deucher 
506d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
507d70229f7SAlex Deucher 	} else {
508d70229f7SAlex Deucher 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_PWR_DOWN_EN);
509d70229f7SAlex Deucher 		RREG32(GB_ADDR_CONFIG);
510d70229f7SAlex Deucher 	}
511d70229f7SAlex Deucher }
512d70229f7SAlex Deucher 
513d70229f7SAlex Deucher static void trinity_gfx_dynamic_mgpg_enable(struct radeon_device *rdev,
514d70229f7SAlex Deucher 					    bool enable)
515d70229f7SAlex Deucher {
516d70229f7SAlex Deucher 	u32 value;
517d70229f7SAlex Deucher 
518d70229f7SAlex Deucher 	if (enable) {
519d70229f7SAlex Deucher 		value = RREG32_SMC(PM_I_CNTL_1);
520d70229f7SAlex Deucher 		value &= ~DS_PG_CNTL_MASK;
521d70229f7SAlex Deucher 		value |= DS_PG_CNTL(1);
522d70229f7SAlex Deucher 		WREG32_SMC(PM_I_CNTL_1, value);
523d70229f7SAlex Deucher 
524d70229f7SAlex Deucher 		value = RREG32_SMC(SMU_S_PG_CNTL);
525d70229f7SAlex Deucher 		value &= ~DS_PG_EN_MASK;
526d70229f7SAlex Deucher 		value |= DS_PG_EN(1);
527d70229f7SAlex Deucher 		WREG32_SMC(SMU_S_PG_CNTL, value);
528d70229f7SAlex Deucher 	} else {
529d70229f7SAlex Deucher 		value = RREG32_SMC(SMU_S_PG_CNTL);
530d70229f7SAlex Deucher 		value &= ~DS_PG_EN_MASK;
531d70229f7SAlex Deucher 		WREG32_SMC(SMU_S_PG_CNTL, value);
532d70229f7SAlex Deucher 
533d70229f7SAlex Deucher 		value = RREG32_SMC(PM_I_CNTL_1);
534d70229f7SAlex Deucher 		value &= ~DS_PG_CNTL_MASK;
535d70229f7SAlex Deucher 		WREG32_SMC(PM_I_CNTL_1, value);
536d70229f7SAlex Deucher 	}
537d70229f7SAlex Deucher 
538d70229f7SAlex Deucher 	trinity_gfx_dynamic_mgpg_config(rdev);
539d70229f7SAlex Deucher 
540d70229f7SAlex Deucher }
541d70229f7SAlex Deucher 
542d70229f7SAlex Deucher static void trinity_enable_clock_power_gating(struct radeon_device *rdev)
543d70229f7SAlex Deucher {
544d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
545d70229f7SAlex Deucher 
546d70229f7SAlex Deucher 	if (pi->enable_gfx_clock_gating)
547d70229f7SAlex Deucher 		sumo_gfx_clockgating_initialize(rdev);
548d70229f7SAlex Deucher 	if (pi->enable_mg_clock_gating)
549d70229f7SAlex Deucher 		trinity_mg_clockgating_initialize(rdev);
550d70229f7SAlex Deucher 	if (pi->enable_gfx_power_gating)
551d70229f7SAlex Deucher 		trinity_gfx_powergating_initialize(rdev);
552d70229f7SAlex Deucher 	if (pi->enable_mg_clock_gating) {
553d70229f7SAlex Deucher 		trinity_ls_clockgating_enable(rdev, true);
554d70229f7SAlex Deucher 		trinity_mg_clockgating_enable(rdev, true);
555d70229f7SAlex Deucher 	}
556d70229f7SAlex Deucher 	if (pi->enable_gfx_clock_gating)
557d70229f7SAlex Deucher 		trinity_gfx_clockgating_enable(rdev, true);
558d70229f7SAlex Deucher 	if (pi->enable_gfx_dynamic_mgpg)
559d70229f7SAlex Deucher 		trinity_gfx_dynamic_mgpg_enable(rdev, true);
560d70229f7SAlex Deucher 	if (pi->enable_gfx_power_gating)
561d70229f7SAlex Deucher 		trinity_gfx_powergating_enable(rdev, true);
562d70229f7SAlex Deucher }
563d70229f7SAlex Deucher 
564d70229f7SAlex Deucher static void trinity_disable_clock_power_gating(struct radeon_device *rdev)
565d70229f7SAlex Deucher {
566d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
567d70229f7SAlex Deucher 
568d70229f7SAlex Deucher 	if (pi->enable_gfx_power_gating)
569d70229f7SAlex Deucher 		trinity_gfx_powergating_enable(rdev, false);
570d70229f7SAlex Deucher 	if (pi->enable_gfx_dynamic_mgpg)
571d70229f7SAlex Deucher 		trinity_gfx_dynamic_mgpg_enable(rdev, false);
572d70229f7SAlex Deucher 	if (pi->enable_gfx_clock_gating)
573d70229f7SAlex Deucher 		trinity_gfx_clockgating_enable(rdev, false);
574d70229f7SAlex Deucher 	if (pi->enable_mg_clock_gating) {
575d70229f7SAlex Deucher 		trinity_mg_clockgating_enable(rdev, false);
576d70229f7SAlex Deucher 		trinity_ls_clockgating_enable(rdev, false);
577d70229f7SAlex Deucher 	}
578d70229f7SAlex Deucher }
579d70229f7SAlex Deucher 
580d70229f7SAlex Deucher static void trinity_set_divider_value(struct radeon_device *rdev,
581d70229f7SAlex Deucher 				      u32 index, u32 sclk)
582d70229f7SAlex Deucher {
583d70229f7SAlex Deucher 	struct atom_clock_dividers  dividers;
584d70229f7SAlex Deucher 	int ret;
585d70229f7SAlex Deucher 	u32 value;
586d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
587d70229f7SAlex Deucher 
588d70229f7SAlex Deucher         ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
589d70229f7SAlex Deucher                                              sclk, false, &dividers);
590d70229f7SAlex Deucher 	if (ret)
591d70229f7SAlex Deucher 		return;
592d70229f7SAlex Deucher 
593d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
594d70229f7SAlex Deucher 	value &= ~CLK_DIVIDER_MASK;
595d70229f7SAlex Deucher 	value |= CLK_DIVIDER(dividers.post_div);
596d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
597d70229f7SAlex Deucher 
598d70229f7SAlex Deucher         ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
599d70229f7SAlex Deucher                                              sclk/2, false, &dividers);
600d70229f7SAlex Deucher 	if (ret)
601d70229f7SAlex Deucher 		return;
602d70229f7SAlex Deucher 
603d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix);
604d70229f7SAlex Deucher 	value &= ~PD_SCLK_DIVIDER_MASK;
605d70229f7SAlex Deucher 	value |= PD_SCLK_DIVIDER(dividers.post_div);
606d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix, value);
607d70229f7SAlex Deucher }
608d70229f7SAlex Deucher 
609d70229f7SAlex Deucher static void trinity_set_ds_dividers(struct radeon_device *rdev,
610d70229f7SAlex Deucher 				    u32 index, u32 divider)
611d70229f7SAlex Deucher {
612d70229f7SAlex Deucher 	u32 value;
613d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
614d70229f7SAlex Deucher 
615d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
616d70229f7SAlex Deucher 	value &= ~DS_DIV_MASK;
617d70229f7SAlex Deucher 	value |= DS_DIV(divider);
618d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
619d70229f7SAlex Deucher }
620d70229f7SAlex Deucher 
621d70229f7SAlex Deucher static void trinity_set_ss_dividers(struct radeon_device *rdev,
622d70229f7SAlex Deucher 				    u32 index, u32 divider)
623d70229f7SAlex Deucher {
624d70229f7SAlex Deucher 	u32 value;
625d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
626d70229f7SAlex Deucher 
627d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
628d70229f7SAlex Deucher 	value &= ~DS_SH_DIV_MASK;
629d70229f7SAlex Deucher 	value |= DS_SH_DIV(divider);
630d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
631d70229f7SAlex Deucher }
632d70229f7SAlex Deucher 
633d70229f7SAlex Deucher static void trinity_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
634d70229f7SAlex Deucher {
635d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
636d70229f7SAlex Deucher 	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid);
637d70229f7SAlex Deucher 	u32 value;
638d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
639d70229f7SAlex Deucher 
640d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
641d70229f7SAlex Deucher 	value &= ~VID_MASK;
642d70229f7SAlex Deucher 	value |= VID(vid_7bit);
643d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
644d70229f7SAlex Deucher 
645d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
646d70229f7SAlex Deucher 	value &= ~LVRT_MASK;
647d70229f7SAlex Deucher 	value |= LVRT(0);
648d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
649d70229f7SAlex Deucher }
650d70229f7SAlex Deucher 
651d70229f7SAlex Deucher static void trinity_set_allos_gnb_slow(struct radeon_device *rdev,
652d70229f7SAlex Deucher 				       u32 index, u32 gnb_slow)
653d70229f7SAlex Deucher {
654d70229f7SAlex Deucher 	u32 value;
655d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
656d70229f7SAlex Deucher 
657d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
658d70229f7SAlex Deucher 	value &= ~GNB_SLOW_MASK;
659d70229f7SAlex Deucher 	value |= GNB_SLOW(gnb_slow);
660d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
661d70229f7SAlex Deucher }
662d70229f7SAlex Deucher 
663d70229f7SAlex Deucher static void trinity_set_force_nbp_state(struct radeon_device *rdev,
664d70229f7SAlex Deucher 					u32 index, u32 force_nbp_state)
665d70229f7SAlex Deucher {
666d70229f7SAlex Deucher 	u32 value;
667d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
668d70229f7SAlex Deucher 
669d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
670d70229f7SAlex Deucher 	value &= ~FORCE_NBPS1_MASK;
671d70229f7SAlex Deucher 	value |= FORCE_NBPS1(force_nbp_state);
672d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
673d70229f7SAlex Deucher }
674d70229f7SAlex Deucher 
675d70229f7SAlex Deucher static void trinity_set_display_wm(struct radeon_device *rdev,
676d70229f7SAlex Deucher 				   u32 index, u32 wm)
677d70229f7SAlex Deucher {
678d70229f7SAlex Deucher 	u32 value;
679d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
680d70229f7SAlex Deucher 
681d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
682d70229f7SAlex Deucher 	value &= ~DISPLAY_WM_MASK;
683d70229f7SAlex Deucher 	value |= DISPLAY_WM(wm);
684d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
685d70229f7SAlex Deucher }
686d70229f7SAlex Deucher 
687d70229f7SAlex Deucher static void trinity_set_vce_wm(struct radeon_device *rdev,
688d70229f7SAlex Deucher 			       u32 index, u32 wm)
689d70229f7SAlex Deucher {
690d70229f7SAlex Deucher 	u32 value;
691d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
692d70229f7SAlex Deucher 
693d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
694d70229f7SAlex Deucher 	value &= ~VCE_WM_MASK;
695d70229f7SAlex Deucher 	value |= VCE_WM(wm);
696d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
697d70229f7SAlex Deucher }
698d70229f7SAlex Deucher 
699d70229f7SAlex Deucher static void trinity_set_at(struct radeon_device *rdev,
700d70229f7SAlex Deucher 			   u32 index, u32 at)
701d70229f7SAlex Deucher {
702d70229f7SAlex Deucher 	u32 value;
703d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
704d70229f7SAlex Deucher 
705d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix);
706d70229f7SAlex Deucher 	value &= ~AT_MASK;
707d70229f7SAlex Deucher 	value |= AT(at);
708d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix, value);
709d70229f7SAlex Deucher }
710d70229f7SAlex Deucher 
711d70229f7SAlex Deucher static void trinity_program_power_level(struct radeon_device *rdev,
712d70229f7SAlex Deucher 					struct trinity_pl *pl, u32 index)
713d70229f7SAlex Deucher {
714d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
715d70229f7SAlex Deucher 
716d70229f7SAlex Deucher 	if (index >= SUMO_MAX_HARDWARE_POWERLEVELS)
717d70229f7SAlex Deucher 		return;
718d70229f7SAlex Deucher 
719d70229f7SAlex Deucher 	trinity_set_divider_value(rdev, index, pl->sclk);
720d70229f7SAlex Deucher 	trinity_set_vid(rdev, index, pl->vddc_index);
721d70229f7SAlex Deucher 	trinity_set_ss_dividers(rdev, index, pl->ss_divider_index);
722d70229f7SAlex Deucher 	trinity_set_ds_dividers(rdev, index, pl->ds_divider_index);
723d70229f7SAlex Deucher 	trinity_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
724d70229f7SAlex Deucher 	trinity_set_force_nbp_state(rdev, index, pl->force_nbp_state);
725d70229f7SAlex Deucher 	trinity_set_display_wm(rdev, index, pl->display_wm);
726d70229f7SAlex Deucher 	trinity_set_vce_wm(rdev, index, pl->vce_wm);
727d70229f7SAlex Deucher 	trinity_set_at(rdev, index, pi->at[index]);
728d70229f7SAlex Deucher }
729d70229f7SAlex Deucher 
730d70229f7SAlex Deucher static void trinity_power_level_enable_disable(struct radeon_device *rdev,
731d70229f7SAlex Deucher 					       u32 index, bool enable)
732d70229f7SAlex Deucher {
733d70229f7SAlex Deucher 	u32 value;
734d70229f7SAlex Deucher 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
735d70229f7SAlex Deucher 
736d70229f7SAlex Deucher 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
737d70229f7SAlex Deucher 	value &= ~STATE_VALID_MASK;
738d70229f7SAlex Deucher 	if (enable)
739d70229f7SAlex Deucher 		value |= STATE_VALID(1);
740d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
741d70229f7SAlex Deucher }
742d70229f7SAlex Deucher 
743d70229f7SAlex Deucher static bool trinity_dpm_enabled(struct radeon_device *rdev)
744d70229f7SAlex Deucher {
745d70229f7SAlex Deucher 	if (RREG32_SMC(SMU_SCLK_DPM_CNTL) & SCLK_DPM_EN(1))
746d70229f7SAlex Deucher 		return true;
747d70229f7SAlex Deucher 	else
748d70229f7SAlex Deucher 		return false;
749d70229f7SAlex Deucher }
750d70229f7SAlex Deucher 
751d70229f7SAlex Deucher static void trinity_start_dpm(struct radeon_device *rdev)
752d70229f7SAlex Deucher {
753d70229f7SAlex Deucher 	u32 value = RREG32_SMC(SMU_SCLK_DPM_CNTL);
754d70229f7SAlex Deucher 
755d70229f7SAlex Deucher 	value &= ~(SCLK_DPM_EN_MASK | SCLK_DPM_BOOT_STATE_MASK | VOLTAGE_CHG_EN_MASK);
756d70229f7SAlex Deucher 	value |= SCLK_DPM_EN(1) | SCLK_DPM_BOOT_STATE(0) | VOLTAGE_CHG_EN(1);
757d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_CNTL, value);
758d70229f7SAlex Deucher 
759d70229f7SAlex Deucher 	WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
760d70229f7SAlex Deucher 	WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~EN);
761d70229f7SAlex Deucher 
762d70229f7SAlex Deucher 	trinity_dpm_config(rdev, true);
763d70229f7SAlex Deucher }
764d70229f7SAlex Deucher 
765d70229f7SAlex Deucher static void trinity_wait_for_dpm_enabled(struct radeon_device *rdev)
766d70229f7SAlex Deucher {
767d70229f7SAlex Deucher 	int i;
768d70229f7SAlex Deucher 
769d70229f7SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
770d70229f7SAlex Deucher 		if (RREG32(SCLK_PWRMGT_CNTL) & DYNAMIC_PM_EN)
771d70229f7SAlex Deucher 			break;
772d70229f7SAlex Deucher 		udelay(1);
773d70229f7SAlex Deucher 	}
774d70229f7SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
775d70229f7SAlex Deucher 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_STATE_MASK) == 0)
776d70229f7SAlex Deucher 			break;
777d70229f7SAlex Deucher 		udelay(1);
778d70229f7SAlex Deucher 	}
779d70229f7SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
780d70229f7SAlex Deucher 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
781d70229f7SAlex Deucher 			break;
782d70229f7SAlex Deucher 		udelay(1);
783d70229f7SAlex Deucher 	}
784d70229f7SAlex Deucher }
785d70229f7SAlex Deucher 
786d70229f7SAlex Deucher static void trinity_stop_dpm(struct radeon_device *rdev)
787d70229f7SAlex Deucher {
788d70229f7SAlex Deucher 	u32 sclk_dpm_cntl;
789d70229f7SAlex Deucher 
790d70229f7SAlex Deucher 	WREG32_P(CG_CG_VOLTAGE_CNTL, EN, ~EN);
791d70229f7SAlex Deucher 
792d70229f7SAlex Deucher 	sclk_dpm_cntl = RREG32_SMC(SMU_SCLK_DPM_CNTL);
793d70229f7SAlex Deucher 	sclk_dpm_cntl &= ~(SCLK_DPM_EN_MASK | VOLTAGE_CHG_EN_MASK);
794d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_CNTL, sclk_dpm_cntl);
795d70229f7SAlex Deucher 
796d70229f7SAlex Deucher 	trinity_dpm_config(rdev, false);
797d70229f7SAlex Deucher }
798d70229f7SAlex Deucher 
799d70229f7SAlex Deucher static void trinity_start_am(struct radeon_device *rdev)
800d70229f7SAlex Deucher {
801d70229f7SAlex Deucher 	WREG32_P(SCLK_PWRMGT_CNTL, 0, ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
802d70229f7SAlex Deucher }
803d70229f7SAlex Deucher 
804d70229f7SAlex Deucher static void trinity_reset_am(struct radeon_device *rdev)
805d70229f7SAlex Deucher {
806d70229f7SAlex Deucher 	WREG32_P(SCLK_PWRMGT_CNTL, RESET_SCLK_CNT | RESET_BUSY_CNT,
807d70229f7SAlex Deucher 		 ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
808d70229f7SAlex Deucher }
809d70229f7SAlex Deucher 
810d70229f7SAlex Deucher static void trinity_wait_for_level_0(struct radeon_device *rdev)
811d70229f7SAlex Deucher {
812d70229f7SAlex Deucher 	int i;
813d70229f7SAlex Deucher 
814d70229f7SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
815d70229f7SAlex Deucher 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
816d70229f7SAlex Deucher 			break;
817d70229f7SAlex Deucher 		udelay(1);
818d70229f7SAlex Deucher 	}
819d70229f7SAlex Deucher }
820d70229f7SAlex Deucher 
821d70229f7SAlex Deucher static void trinity_enable_power_level_0(struct radeon_device *rdev)
822d70229f7SAlex Deucher {
823d70229f7SAlex Deucher 	trinity_power_level_enable_disable(rdev, 0, true);
824d70229f7SAlex Deucher }
825d70229f7SAlex Deucher 
826d70229f7SAlex Deucher static void trinity_force_level_0(struct radeon_device *rdev)
827d70229f7SAlex Deucher {
828d70229f7SAlex Deucher 	trinity_dpm_force_state(rdev, 0);
829d70229f7SAlex Deucher }
830d70229f7SAlex Deucher 
831d70229f7SAlex Deucher static void trinity_unforce_levels(struct radeon_device *rdev)
832d70229f7SAlex Deucher {
833d70229f7SAlex Deucher 	trinity_dpm_no_forced_level(rdev);
834d70229f7SAlex Deucher }
835d70229f7SAlex Deucher 
836940eea8eSAlex Deucher static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev,
837940eea8eSAlex Deucher 						struct radeon_ps *new_rps,
838940eea8eSAlex Deucher 						struct radeon_ps *old_rps)
839d70229f7SAlex Deucher {
840940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
841940eea8eSAlex Deucher 	struct trinity_ps *old_ps = trinity_get_ps(old_rps);
842d70229f7SAlex Deucher 	u32 i;
843d70229f7SAlex Deucher 	u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
844d70229f7SAlex Deucher 
845d70229f7SAlex Deucher 	for (i = 0; i < new_ps->num_levels; i++) {
846d70229f7SAlex Deucher 		trinity_program_power_level(rdev, &new_ps->levels[i], i);
847d70229f7SAlex Deucher 		trinity_power_level_enable_disable(rdev, i, true);
848d70229f7SAlex Deucher 	}
849d70229f7SAlex Deucher 
850d70229f7SAlex Deucher 	for (i = new_ps->num_levels; i < n_current_state_levels; i++)
851d70229f7SAlex Deucher 		trinity_power_level_enable_disable(rdev, i, false);
852d70229f7SAlex Deucher }
853d70229f7SAlex Deucher 
854d70229f7SAlex Deucher static void trinity_program_bootup_state(struct radeon_device *rdev)
855d70229f7SAlex Deucher {
856d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
857d70229f7SAlex Deucher 	u32 i;
858d70229f7SAlex Deucher 
859d70229f7SAlex Deucher 	trinity_program_power_level(rdev, &pi->boot_pl, 0);
860d70229f7SAlex Deucher 	trinity_power_level_enable_disable(rdev, 0, true);
861d70229f7SAlex Deucher 
862d70229f7SAlex Deucher 	for (i = 1; i < 8; i++)
863d70229f7SAlex Deucher 		trinity_power_level_enable_disable(rdev, i, false);
864d70229f7SAlex Deucher }
865d70229f7SAlex Deucher 
8660c4aaeaeSAlex Deucher static void trinity_setup_uvd_clock_table(struct radeon_device *rdev,
8670c4aaeaeSAlex Deucher 					  struct radeon_ps *rps)
8680c4aaeaeSAlex Deucher {
8690c4aaeaeSAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
8700c4aaeaeSAlex Deucher 	u32 uvdstates = (ps->vclk_low_divider |
8710c4aaeaeSAlex Deucher 			 ps->vclk_high_divider << 8 |
8720c4aaeaeSAlex Deucher 			 ps->dclk_low_divider << 16 |
8730c4aaeaeSAlex Deucher 			 ps->dclk_high_divider << 24);
8740c4aaeaeSAlex Deucher 
8750c4aaeaeSAlex Deucher 	WREG32_SMC(SMU_UVD_DPM_STATES, uvdstates);
8760c4aaeaeSAlex Deucher }
8770c4aaeaeSAlex Deucher 
8780c4aaeaeSAlex Deucher static void trinity_setup_uvd_dpm_interval(struct radeon_device *rdev,
8790c4aaeaeSAlex Deucher 					   u32 interval)
8800c4aaeaeSAlex Deucher {
8810c4aaeaeSAlex Deucher 	u32 p, u;
8820c4aaeaeSAlex Deucher 	u32 tp = RREG32_SMC(PM_TP);
8830c4aaeaeSAlex Deucher 	u32 val;
8849d45ad5aSAlex Deucher 	u32 xclk = radeon_get_xclk(rdev);
8850c4aaeaeSAlex Deucher 
8860c4aaeaeSAlex Deucher 	r600_calculate_u_and_p(interval, xclk, 16, &p, &u);
8870c4aaeaeSAlex Deucher 
8880c4aaeaeSAlex Deucher 	val = (p + tp - 1) / tp;
8890c4aaeaeSAlex Deucher 
8900c4aaeaeSAlex Deucher 	WREG32_SMC(SMU_UVD_DPM_CNTL, val);
8910c4aaeaeSAlex Deucher }
8920c4aaeaeSAlex Deucher 
8930c4aaeaeSAlex Deucher static bool trinity_uvd_clocks_zero(struct radeon_ps *rps)
8940c4aaeaeSAlex Deucher {
8950c4aaeaeSAlex Deucher 	if ((rps->vclk == 0) && (rps->dclk == 0))
8960c4aaeaeSAlex Deucher 		return true;
8970c4aaeaeSAlex Deucher 	else
8980c4aaeaeSAlex Deucher 		return false;
8990c4aaeaeSAlex Deucher }
9000c4aaeaeSAlex Deucher 
9010c4aaeaeSAlex Deucher static bool trinity_uvd_clocks_equal(struct radeon_ps *rps1,
9020c4aaeaeSAlex Deucher 				     struct radeon_ps *rps2)
9030c4aaeaeSAlex Deucher {
9040c4aaeaeSAlex Deucher 	struct trinity_ps *ps1 = trinity_get_ps(rps1);
9050c4aaeaeSAlex Deucher 	struct trinity_ps *ps2 = trinity_get_ps(rps2);
9060c4aaeaeSAlex Deucher 
9070c4aaeaeSAlex Deucher 	if ((rps1->vclk == rps2->vclk) &&
9080c4aaeaeSAlex Deucher 	    (rps1->dclk == rps2->dclk) &&
9090c4aaeaeSAlex Deucher 	    (ps1->vclk_low_divider == ps2->vclk_low_divider) &&
9100c4aaeaeSAlex Deucher 	    (ps1->vclk_high_divider == ps2->vclk_high_divider) &&
9110c4aaeaeSAlex Deucher 	    (ps1->dclk_low_divider == ps2->dclk_low_divider) &&
9120c4aaeaeSAlex Deucher 	    (ps1->dclk_high_divider == ps2->dclk_high_divider))
9130c4aaeaeSAlex Deucher 		return true;
9140c4aaeaeSAlex Deucher 	else
9150c4aaeaeSAlex Deucher 		return false;
9160c4aaeaeSAlex Deucher }
9170c4aaeaeSAlex Deucher 
9180c4aaeaeSAlex Deucher static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
919940eea8eSAlex Deucher 				     struct radeon_ps *new_rps,
920940eea8eSAlex Deucher 				     struct radeon_ps *old_rps)
9210c4aaeaeSAlex Deucher {
9220c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
9230c4aaeaeSAlex Deucher 
92462fa44bfSAlex Deucher 	if (pi->enable_gfx_power_gating) {
92562fa44bfSAlex Deucher 		trinity_gfx_powergating_enable(rdev, false);
92662fa44bfSAlex Deucher 	}
92762fa44bfSAlex Deucher 
9280c4aaeaeSAlex Deucher 	if (pi->uvd_dpm) {
9290c4aaeaeSAlex Deucher 		if (trinity_uvd_clocks_zero(new_rps) &&
930940eea8eSAlex Deucher 		    !trinity_uvd_clocks_zero(old_rps)) {
9310c4aaeaeSAlex Deucher 			trinity_setup_uvd_dpm_interval(rdev, 0);
9320c4aaeaeSAlex Deucher 		} else if (!trinity_uvd_clocks_zero(new_rps)) {
9330c4aaeaeSAlex Deucher 			trinity_setup_uvd_clock_table(rdev, new_rps);
9340c4aaeaeSAlex Deucher 
935940eea8eSAlex Deucher 			if (trinity_uvd_clocks_zero(old_rps)) {
9360c4aaeaeSAlex Deucher 				u32 tmp = RREG32(CG_MISC_REG);
9370c4aaeaeSAlex Deucher 				tmp &= 0xfffffffd;
9380c4aaeaeSAlex Deucher 				WREG32(CG_MISC_REG, tmp);
9390c4aaeaeSAlex Deucher 
9400c4aaeaeSAlex Deucher 				radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
9410c4aaeaeSAlex Deucher 
9420c4aaeaeSAlex Deucher 				trinity_setup_uvd_dpm_interval(rdev, 3000);
9430c4aaeaeSAlex Deucher 			}
9440c4aaeaeSAlex Deucher 		}
9450c4aaeaeSAlex Deucher 		trinity_uvd_dpm_config(rdev);
9460c4aaeaeSAlex Deucher 	} else {
9470c4aaeaeSAlex Deucher 		if (trinity_uvd_clocks_zero(new_rps) ||
948940eea8eSAlex Deucher 		    trinity_uvd_clocks_equal(new_rps, old_rps))
9490c4aaeaeSAlex Deucher 			return;
9500c4aaeaeSAlex Deucher 
9510c4aaeaeSAlex Deucher 		radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
9520c4aaeaeSAlex Deucher 	}
95362fa44bfSAlex Deucher 
95462fa44bfSAlex Deucher 	if (pi->enable_gfx_power_gating) {
95562fa44bfSAlex Deucher 		trinity_gfx_powergating_enable(rdev, true);
95662fa44bfSAlex Deucher 	}
9570c4aaeaeSAlex Deucher }
9580c4aaeaeSAlex Deucher 
959940eea8eSAlex Deucher static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
960940eea8eSAlex Deucher 						       struct radeon_ps *new_rps,
961940eea8eSAlex Deucher 						       struct radeon_ps *old_rps)
9620c4aaeaeSAlex Deucher {
963940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
964940eea8eSAlex Deucher 	struct trinity_ps *current_ps = trinity_get_ps(new_rps);
9650c4aaeaeSAlex Deucher 
9660c4aaeaeSAlex Deucher 	if (new_ps->levels[new_ps->num_levels - 1].sclk >=
9670c4aaeaeSAlex Deucher 	    current_ps->levels[current_ps->num_levels - 1].sclk)
9680c4aaeaeSAlex Deucher 		return;
9690c4aaeaeSAlex Deucher 
970940eea8eSAlex Deucher 	trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
9710c4aaeaeSAlex Deucher }
9720c4aaeaeSAlex Deucher 
973940eea8eSAlex Deucher static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
974940eea8eSAlex Deucher 						      struct radeon_ps *new_rps,
975940eea8eSAlex Deucher 						      struct radeon_ps *old_rps)
9760c4aaeaeSAlex Deucher {
977940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
978940eea8eSAlex Deucher 	struct trinity_ps *current_ps = trinity_get_ps(old_rps);
9790c4aaeaeSAlex Deucher 
9800c4aaeaeSAlex Deucher 	if (new_ps->levels[new_ps->num_levels - 1].sclk <
9810c4aaeaeSAlex Deucher 	    current_ps->levels[current_ps->num_levels - 1].sclk)
9820c4aaeaeSAlex Deucher 		return;
9830c4aaeaeSAlex Deucher 
984940eea8eSAlex Deucher 	trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
9850c4aaeaeSAlex Deucher }
9860c4aaeaeSAlex Deucher 
987d70229f7SAlex Deucher static void trinity_program_ttt(struct radeon_device *rdev)
988d70229f7SAlex Deucher {
989d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
990d70229f7SAlex Deucher 	u32 value = RREG32_SMC(SMU_SCLK_DPM_TTT);
991d70229f7SAlex Deucher 
992d70229f7SAlex Deucher 	value &= ~(HT_MASK | LT_MASK);
993d70229f7SAlex Deucher 	value |= HT((pi->thermal_auto_throttling + 49) * 8);
994d70229f7SAlex Deucher 	value |= LT((pi->thermal_auto_throttling + 49 - pi->sys_info.htc_hyst_lmt) * 8);
995d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_TTT, value);
996d70229f7SAlex Deucher }
997d70229f7SAlex Deucher 
998d70229f7SAlex Deucher static void trinity_enable_att(struct radeon_device *rdev)
999d70229f7SAlex Deucher {
1000d70229f7SAlex Deucher 	u32 value = RREG32_SMC(SMU_SCLK_DPM_TT_CNTL);
1001d70229f7SAlex Deucher 
1002d70229f7SAlex Deucher 	value &= ~SCLK_TT_EN_MASK;
1003d70229f7SAlex Deucher 	value |= SCLK_TT_EN(1);
1004d70229f7SAlex Deucher 	WREG32_SMC(SMU_SCLK_DPM_TT_CNTL, value);
1005d70229f7SAlex Deucher }
1006d70229f7SAlex Deucher 
1007d70229f7SAlex Deucher static void trinity_program_sclk_dpm(struct radeon_device *rdev)
1008d70229f7SAlex Deucher {
1009d70229f7SAlex Deucher 	u32 p, u;
1010d70229f7SAlex Deucher 	u32 tp = RREG32_SMC(PM_TP);
1011d70229f7SAlex Deucher 	u32 ni;
10129d45ad5aSAlex Deucher 	u32 xclk = radeon_get_xclk(rdev);
1013d70229f7SAlex Deucher 	u32 value;
1014d70229f7SAlex Deucher 
1015d70229f7SAlex Deucher 	r600_calculate_u_and_p(400, xclk, 16, &p, &u);
1016d70229f7SAlex Deucher 
1017d70229f7SAlex Deucher 	ni = (p + tp - 1) / tp;
1018d70229f7SAlex Deucher 
1019d70229f7SAlex Deucher 	value = RREG32_SMC(PM_I_CNTL_1);
1020d70229f7SAlex Deucher 	value &= ~SCLK_DPM_MASK;
1021d70229f7SAlex Deucher 	value |= SCLK_DPM(ni);
1022d70229f7SAlex Deucher 	WREG32_SMC(PM_I_CNTL_1, value);
1023d70229f7SAlex Deucher }
1024d70229f7SAlex Deucher 
1025d70229f7SAlex Deucher static int trinity_set_thermal_temperature_range(struct radeon_device *rdev,
1026d70229f7SAlex Deucher 						 int min_temp, int max_temp)
1027d70229f7SAlex Deucher {
1028d70229f7SAlex Deucher 	int low_temp = 0 * 1000;
1029d70229f7SAlex Deucher 	int high_temp = 255 * 1000;
1030d70229f7SAlex Deucher 
1031d70229f7SAlex Deucher         if (low_temp < min_temp)
1032d70229f7SAlex Deucher 		low_temp = min_temp;
1033d70229f7SAlex Deucher         if (high_temp > max_temp)
1034d70229f7SAlex Deucher 		high_temp = max_temp;
1035d70229f7SAlex Deucher         if (high_temp < low_temp) {
1036d70229f7SAlex Deucher 		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
1037d70229f7SAlex Deucher                 return -EINVAL;
1038d70229f7SAlex Deucher         }
1039d70229f7SAlex Deucher 
1040d70229f7SAlex Deucher 	WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
1041d70229f7SAlex Deucher 	WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
1042d70229f7SAlex Deucher 
1043d70229f7SAlex Deucher 	rdev->pm.dpm.thermal.min_temp = low_temp;
1044d70229f7SAlex Deucher 	rdev->pm.dpm.thermal.max_temp = high_temp;
1045d70229f7SAlex Deucher 
1046d70229f7SAlex Deucher 	return 0;
1047d70229f7SAlex Deucher }
1048d70229f7SAlex Deucher 
1049a284c48aSAlex Deucher static void trinity_update_current_ps(struct radeon_device *rdev,
1050a284c48aSAlex Deucher 				      struct radeon_ps *rps)
1051a284c48aSAlex Deucher {
1052a284c48aSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(rps);
1053a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1054a284c48aSAlex Deucher 
1055a284c48aSAlex Deucher 	pi->current_rps = *rps;
1056a284c48aSAlex Deucher 	pi->current_ps = *new_ps;
1057a284c48aSAlex Deucher 	pi->current_rps.ps_priv = &pi->current_ps;
1058a284c48aSAlex Deucher }
1059a284c48aSAlex Deucher 
1060a284c48aSAlex Deucher static void trinity_update_requested_ps(struct radeon_device *rdev,
1061a284c48aSAlex Deucher 					struct radeon_ps *rps)
1062a284c48aSAlex Deucher {
1063a284c48aSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(rps);
1064a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1065a284c48aSAlex Deucher 
1066a284c48aSAlex Deucher 	pi->requested_rps = *rps;
1067a284c48aSAlex Deucher 	pi->requested_ps = *new_ps;
1068a284c48aSAlex Deucher 	pi->requested_rps.ps_priv = &pi->requested_ps;
1069a284c48aSAlex Deucher }
1070a284c48aSAlex Deucher 
107111877060SAlex Deucher void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable)
107211877060SAlex Deucher {
107311877060SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
107411877060SAlex Deucher 
107511877060SAlex Deucher 	if (pi->enable_bapm) {
107611877060SAlex Deucher 		trinity_acquire_mutex(rdev);
107711877060SAlex Deucher 		trinity_dpm_bapm_enable(rdev, enable);
107811877060SAlex Deucher 		trinity_release_mutex(rdev);
107911877060SAlex Deucher 	}
108011877060SAlex Deucher }
108111877060SAlex Deucher 
1082d70229f7SAlex Deucher int trinity_dpm_enable(struct radeon_device *rdev)
1083d70229f7SAlex Deucher {
1084d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1085d70229f7SAlex Deucher 
1086d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1087d70229f7SAlex Deucher 
1088d70229f7SAlex Deucher 	if (trinity_dpm_enabled(rdev)) {
1089d70229f7SAlex Deucher 		trinity_release_mutex(rdev);
1090d70229f7SAlex Deucher 		return -EINVAL;
1091d70229f7SAlex Deucher 	}
1092d70229f7SAlex Deucher 
1093d70229f7SAlex Deucher 	trinity_program_bootup_state(rdev);
1094d70229f7SAlex Deucher 	sumo_program_vc(rdev, 0x00C00033);
1095d70229f7SAlex Deucher 	trinity_start_am(rdev);
1096d70229f7SAlex Deucher 	if (pi->enable_auto_thermal_throttling) {
1097d70229f7SAlex Deucher 		trinity_program_ttt(rdev);
1098d70229f7SAlex Deucher 		trinity_enable_att(rdev);
1099d70229f7SAlex Deucher 	}
1100d70229f7SAlex Deucher 	trinity_program_sclk_dpm(rdev);
1101d70229f7SAlex Deucher 	trinity_start_dpm(rdev);
1102d70229f7SAlex Deucher 	trinity_wait_for_dpm_enabled(rdev);
1103ef4e0365SAlex Deucher 	trinity_dpm_bapm_enable(rdev, false);
1104d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1105d70229f7SAlex Deucher 
1106a284c48aSAlex Deucher 	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
1107a284c48aSAlex Deucher 
1108d70229f7SAlex Deucher 	return 0;
1109d70229f7SAlex Deucher }
1110d70229f7SAlex Deucher 
1111bda44c1aSAlex Deucher int trinity_dpm_late_enable(struct radeon_device *rdev)
1112bda44c1aSAlex Deucher {
1113bda44c1aSAlex Deucher 	int ret;
1114bda44c1aSAlex Deucher 
1115bda44c1aSAlex Deucher 	trinity_acquire_mutex(rdev);
1116bda44c1aSAlex Deucher 	trinity_enable_clock_power_gating(rdev);
1117bda44c1aSAlex Deucher 
1118bda44c1aSAlex Deucher 	if (rdev->irq.installed &&
1119bda44c1aSAlex Deucher 	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
1120bda44c1aSAlex Deucher 		ret = trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
1121bda44c1aSAlex Deucher 		if (ret) {
1122bda44c1aSAlex Deucher 			trinity_release_mutex(rdev);
1123bda44c1aSAlex Deucher 			return ret;
1124bda44c1aSAlex Deucher 		}
1125bda44c1aSAlex Deucher 		rdev->irq.dpm_thermal = true;
1126bda44c1aSAlex Deucher 		radeon_irq_set(rdev);
1127bda44c1aSAlex Deucher 	}
1128bda44c1aSAlex Deucher 	trinity_release_mutex(rdev);
1129bda44c1aSAlex Deucher 
1130bda44c1aSAlex Deucher 	return 0;
1131bda44c1aSAlex Deucher }
1132bda44c1aSAlex Deucher 
1133d70229f7SAlex Deucher void trinity_dpm_disable(struct radeon_device *rdev)
1134d70229f7SAlex Deucher {
1135d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1136d70229f7SAlex Deucher 	if (!trinity_dpm_enabled(rdev)) {
1137d70229f7SAlex Deucher 		trinity_release_mutex(rdev);
1138d70229f7SAlex Deucher 		return;
1139d70229f7SAlex Deucher 	}
1140ef4e0365SAlex Deucher 	trinity_dpm_bapm_enable(rdev, false);
1141d70229f7SAlex Deucher 	trinity_disable_clock_power_gating(rdev);
1142d70229f7SAlex Deucher 	sumo_clear_vc(rdev);
1143d70229f7SAlex Deucher 	trinity_wait_for_level_0(rdev);
1144d70229f7SAlex Deucher 	trinity_stop_dpm(rdev);
1145d70229f7SAlex Deucher 	trinity_reset_am(rdev);
1146d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1147d70229f7SAlex Deucher 
1148d70229f7SAlex Deucher 	if (rdev->irq.installed &&
1149d70229f7SAlex Deucher 	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
1150d70229f7SAlex Deucher 		rdev->irq.dpm_thermal = false;
1151d70229f7SAlex Deucher 		radeon_irq_set(rdev);
1152d70229f7SAlex Deucher 	}
1153a284c48aSAlex Deucher 
1154a284c48aSAlex Deucher 	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
1155d70229f7SAlex Deucher }
1156d70229f7SAlex Deucher 
1157d70229f7SAlex Deucher static void trinity_get_min_sclk_divider(struct radeon_device *rdev)
1158d70229f7SAlex Deucher {
1159d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1160d70229f7SAlex Deucher 
1161d70229f7SAlex Deucher 	pi->min_sclk_did =
1162d70229f7SAlex Deucher 		(RREG32_SMC(CC_SMU_MISC_FUSES) & MinSClkDid_MASK) >> MinSClkDid_SHIFT;
1163d70229f7SAlex Deucher }
1164d70229f7SAlex Deucher 
1165940eea8eSAlex Deucher static void trinity_setup_nbp_sim(struct radeon_device *rdev,
1166940eea8eSAlex Deucher 				  struct radeon_ps *rps)
1167d70229f7SAlex Deucher {
1168d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1169940eea8eSAlex Deucher 	struct trinity_ps *new_ps = trinity_get_ps(rps);
1170d70229f7SAlex Deucher 	u32 nbpsconfig;
1171d70229f7SAlex Deucher 
1172d70229f7SAlex Deucher 	if (pi->sys_info.nb_dpm_enable) {
1173d70229f7SAlex Deucher 		nbpsconfig = RREG32_SMC(NB_PSTATE_CONFIG);
1174d70229f7SAlex Deucher 		nbpsconfig &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | DpmXNbPsLo_MASK | DpmXNbPsHi_MASK);
1175d70229f7SAlex Deucher 		nbpsconfig |= (Dpm0PgNbPsLo(new_ps->Dpm0PgNbPsLo) |
1176d70229f7SAlex Deucher 			       Dpm0PgNbPsHi(new_ps->Dpm0PgNbPsHi) |
1177d70229f7SAlex Deucher 			       DpmXNbPsLo(new_ps->DpmXNbPsLo) |
1178d70229f7SAlex Deucher 			       DpmXNbPsHi(new_ps->DpmXNbPsHi));
1179d70229f7SAlex Deucher 		WREG32_SMC(NB_PSTATE_CONFIG, nbpsconfig);
1180d70229f7SAlex Deucher 	}
1181d70229f7SAlex Deucher }
1182d70229f7SAlex Deucher 
11839b5de596SAlex Deucher int trinity_dpm_force_performance_level(struct radeon_device *rdev,
11849b5de596SAlex Deucher 					enum radeon_dpm_forced_level level)
11859b5de596SAlex Deucher {
11869b5de596SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
11879b5de596SAlex Deucher 	struct radeon_ps *rps = &pi->current_rps;
11889b5de596SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
11899b5de596SAlex Deucher 	int i, ret;
11909b5de596SAlex Deucher 
11919b5de596SAlex Deucher 	if (ps->num_levels <= 1)
11929b5de596SAlex Deucher 		return 0;
11939b5de596SAlex Deucher 
11949b5de596SAlex Deucher 	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
11959b5de596SAlex Deucher 		/* not supported by the hw */
11969b5de596SAlex Deucher 		return -EINVAL;
11979b5de596SAlex Deucher 	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
11989b5de596SAlex Deucher 		ret = trinity_dpm_n_levels_disabled(rdev, ps->num_levels - 1);
11999b5de596SAlex Deucher 		if (ret)
12009b5de596SAlex Deucher 			return ret;
12019b5de596SAlex Deucher 	} else {
12029b5de596SAlex Deucher 		for (i = 0; i < ps->num_levels; i++) {
12039b5de596SAlex Deucher 			ret = trinity_dpm_n_levels_disabled(rdev, 0);
12049b5de596SAlex Deucher 			if (ret)
12059b5de596SAlex Deucher 				return ret;
12069b5de596SAlex Deucher 		}
12079b5de596SAlex Deucher 	}
12089b5de596SAlex Deucher 
12099b5de596SAlex Deucher 	rdev->pm.dpm.forced_level = level;
12109b5de596SAlex Deucher 
12119b5de596SAlex Deucher 	return 0;
12129b5de596SAlex Deucher }
12139b5de596SAlex Deucher 
1214a284c48aSAlex Deucher int trinity_dpm_pre_set_power_state(struct radeon_device *rdev)
1215a284c48aSAlex Deucher {
1216a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1217a284c48aSAlex Deucher 	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
1218a284c48aSAlex Deucher 	struct radeon_ps *new_ps = &requested_ps;
1219a284c48aSAlex Deucher 
1220a284c48aSAlex Deucher 	trinity_update_requested_ps(rdev, new_ps);
1221a284c48aSAlex Deucher 
1222a284c48aSAlex Deucher 	trinity_apply_state_adjust_rules(rdev,
1223a284c48aSAlex Deucher 					 &pi->requested_rps,
1224a284c48aSAlex Deucher 					 &pi->current_rps);
1225a284c48aSAlex Deucher 
1226a284c48aSAlex Deucher 	return 0;
1227a284c48aSAlex Deucher }
1228a284c48aSAlex Deucher 
1229d70229f7SAlex Deucher int trinity_dpm_set_power_state(struct radeon_device *rdev)
1230d70229f7SAlex Deucher {
1231d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1232a284c48aSAlex Deucher 	struct radeon_ps *new_ps = &pi->requested_rps;
1233a284c48aSAlex Deucher 	struct radeon_ps *old_ps = &pi->current_rps;
1234d70229f7SAlex Deucher 
1235d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1236d70229f7SAlex Deucher 	if (pi->enable_dpm) {
123711877060SAlex Deucher 		if (pi->enable_bapm)
123811877060SAlex Deucher 			trinity_dpm_bapm_enable(rdev, rdev->pm.dpm.ac_power);
1239940eea8eSAlex Deucher 		trinity_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
1240d70229f7SAlex Deucher 		trinity_enable_power_level_0(rdev);
1241d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1242d70229f7SAlex Deucher 		trinity_wait_for_level_0(rdev);
1243940eea8eSAlex Deucher 		trinity_setup_nbp_sim(rdev, new_ps);
1244940eea8eSAlex Deucher 		trinity_program_power_levels_0_to_n(rdev, new_ps, old_ps);
1245d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1246d70229f7SAlex Deucher 		trinity_unforce_levels(rdev);
1247940eea8eSAlex Deucher 		trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
1248d70229f7SAlex Deucher 	}
1249d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1250d70229f7SAlex Deucher 
1251d70229f7SAlex Deucher 	return 0;
1252d70229f7SAlex Deucher }
1253d70229f7SAlex Deucher 
1254a284c48aSAlex Deucher void trinity_dpm_post_set_power_state(struct radeon_device *rdev)
1255a284c48aSAlex Deucher {
1256a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1257a284c48aSAlex Deucher 	struct radeon_ps *new_ps = &pi->requested_rps;
1258a284c48aSAlex Deucher 
1259a284c48aSAlex Deucher 	trinity_update_current_ps(rdev, new_ps);
1260a284c48aSAlex Deucher }
1261a284c48aSAlex Deucher 
1262d70229f7SAlex Deucher void trinity_dpm_setup_asic(struct radeon_device *rdev)
1263d70229f7SAlex Deucher {
1264d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1265d70229f7SAlex Deucher 	sumo_program_sstp(rdev);
1266d70229f7SAlex Deucher 	sumo_take_smu_control(rdev, true);
1267d70229f7SAlex Deucher 	trinity_get_min_sclk_divider(rdev);
1268d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1269d70229f7SAlex Deucher }
1270d70229f7SAlex Deucher 
1271d70229f7SAlex Deucher void trinity_dpm_reset_asic(struct radeon_device *rdev)
1272d70229f7SAlex Deucher {
1273d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1274d70229f7SAlex Deucher 
1275d70229f7SAlex Deucher 	trinity_acquire_mutex(rdev);
1276d70229f7SAlex Deucher 	if (pi->enable_dpm) {
1277d70229f7SAlex Deucher 		trinity_enable_power_level_0(rdev);
1278d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1279d70229f7SAlex Deucher 		trinity_wait_for_level_0(rdev);
1280d70229f7SAlex Deucher 		trinity_program_bootup_state(rdev);
1281d70229f7SAlex Deucher 		trinity_force_level_0(rdev);
1282d70229f7SAlex Deucher 		trinity_unforce_levels(rdev);
1283d70229f7SAlex Deucher 	}
1284d70229f7SAlex Deucher 	trinity_release_mutex(rdev);
1285d70229f7SAlex Deucher }
1286d70229f7SAlex Deucher 
1287d70229f7SAlex Deucher static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
1288d70229f7SAlex Deucher 						  u32 vid_2bit)
1289d70229f7SAlex Deucher {
1290d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1291d70229f7SAlex Deucher 	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
1292d70229f7SAlex Deucher 	u32 svi_mode = (RREG32_SMC(PM_CONFIG) & SVI_Mode) ? 1 : 0;
1293d70229f7SAlex Deucher 	u32 step = (svi_mode == 0) ? 1250 : 625;
1294d70229f7SAlex Deucher 	u32 delta = vid_7bit * step + 50;
1295d70229f7SAlex Deucher 
1296d70229f7SAlex Deucher 	if (delta > 155000)
1297d70229f7SAlex Deucher 		return 0;
1298d70229f7SAlex Deucher 
1299d70229f7SAlex Deucher 	return (155000 - delta) / 100;
1300d70229f7SAlex Deucher }
1301d70229f7SAlex Deucher 
1302d70229f7SAlex Deucher static void trinity_patch_boot_state(struct radeon_device *rdev,
1303d70229f7SAlex Deucher 				     struct trinity_ps *ps)
1304d70229f7SAlex Deucher {
1305d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1306d70229f7SAlex Deucher 
1307d70229f7SAlex Deucher 	ps->num_levels = 1;
1308d70229f7SAlex Deucher 	ps->nbps_flags = 0;
1309d70229f7SAlex Deucher 	ps->bapm_flags = 0;
1310d70229f7SAlex Deucher 	ps->levels[0] = pi->boot_pl;
1311d70229f7SAlex Deucher }
1312d70229f7SAlex Deucher 
1313d70229f7SAlex Deucher static u8 trinity_calculate_vce_wm(struct radeon_device *rdev, u32 sclk)
1314d70229f7SAlex Deucher {
1315d70229f7SAlex Deucher 	if (sclk < 20000)
1316d70229f7SAlex Deucher 		return 1;
1317d70229f7SAlex Deucher 	return 0;
1318d70229f7SAlex Deucher }
1319d70229f7SAlex Deucher 
1320d70229f7SAlex Deucher static void trinity_construct_boot_state(struct radeon_device *rdev)
1321d70229f7SAlex Deucher {
1322d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1323d70229f7SAlex Deucher 
1324d70229f7SAlex Deucher 	pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
1325d70229f7SAlex Deucher 	pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
1326d70229f7SAlex Deucher 	pi->boot_pl.ds_divider_index = 0;
1327d70229f7SAlex Deucher 	pi->boot_pl.ss_divider_index = 0;
1328d70229f7SAlex Deucher 	pi->boot_pl.allow_gnb_slow = 1;
1329d70229f7SAlex Deucher 	pi->boot_pl.force_nbp_state = 0;
1330d70229f7SAlex Deucher 	pi->boot_pl.display_wm = 0;
1331d70229f7SAlex Deucher 	pi->boot_pl.vce_wm = 0;
1332d70229f7SAlex Deucher 	pi->current_ps.num_levels = 1;
1333d70229f7SAlex Deucher 	pi->current_ps.levels[0] = pi->boot_pl;
1334d70229f7SAlex Deucher }
1335d70229f7SAlex Deucher 
1336d70229f7SAlex Deucher static u8 trinity_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
1337d70229f7SAlex Deucher 						  u32 sclk, u32 min_sclk_in_sr)
1338d70229f7SAlex Deucher {
1339d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1340d70229f7SAlex Deucher 	u32 i;
1341d70229f7SAlex Deucher 	u32 temp;
1342d70229f7SAlex Deucher 	u32 min = (min_sclk_in_sr > TRINITY_MINIMUM_ENGINE_CLOCK) ?
1343d70229f7SAlex Deucher 		min_sclk_in_sr : TRINITY_MINIMUM_ENGINE_CLOCK;
1344d70229f7SAlex Deucher 
1345d70229f7SAlex Deucher 	if (sclk < min)
1346d70229f7SAlex Deucher 		return 0;
1347d70229f7SAlex Deucher 
1348d70229f7SAlex Deucher 	if (!pi->enable_sclk_ds)
1349d70229f7SAlex Deucher 		return 0;
1350d70229f7SAlex Deucher 
1351d70229f7SAlex Deucher 	for (i = TRINITY_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
1352d70229f7SAlex Deucher 		temp = sclk / sumo_get_sleep_divider_from_id(i);
1353d70229f7SAlex Deucher 		if (temp >= min || i == 0)
1354d70229f7SAlex Deucher 			break;
1355d70229f7SAlex Deucher 	}
1356d70229f7SAlex Deucher 
1357d70229f7SAlex Deucher 	return (u8)i;
1358d70229f7SAlex Deucher }
1359d70229f7SAlex Deucher 
1360d70229f7SAlex Deucher static u32 trinity_get_valid_engine_clock(struct radeon_device *rdev,
1361d70229f7SAlex Deucher 					  u32 lower_limit)
1362d70229f7SAlex Deucher {
1363d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1364d70229f7SAlex Deucher 	u32 i;
1365d70229f7SAlex Deucher 
1366d70229f7SAlex Deucher 	for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
1367d70229f7SAlex Deucher 		if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
1368d70229f7SAlex Deucher 			return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
1369d70229f7SAlex Deucher 	}
1370d70229f7SAlex Deucher 
1371d70229f7SAlex Deucher 	if (i == pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries)
1372d70229f7SAlex Deucher 		DRM_ERROR("engine clock out of range!");
1373d70229f7SAlex Deucher 
1374d70229f7SAlex Deucher 	return 0;
1375d70229f7SAlex Deucher }
1376d70229f7SAlex Deucher 
1377d70229f7SAlex Deucher static void trinity_patch_thermal_state(struct radeon_device *rdev,
1378d70229f7SAlex Deucher 					struct trinity_ps *ps,
1379d70229f7SAlex Deucher 					struct trinity_ps *current_ps)
1380d70229f7SAlex Deucher {
1381d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1382d70229f7SAlex Deucher 	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
1383d70229f7SAlex Deucher 	u32 current_vddc;
1384d70229f7SAlex Deucher 	u32 current_sclk;
1385d70229f7SAlex Deucher 	u32 current_index = 0;
1386d70229f7SAlex Deucher 
1387d70229f7SAlex Deucher 	if (current_ps) {
1388d70229f7SAlex Deucher 		current_vddc = current_ps->levels[current_index].vddc_index;
1389d70229f7SAlex Deucher 		current_sclk = current_ps->levels[current_index].sclk;
1390d70229f7SAlex Deucher 	} else {
1391d70229f7SAlex Deucher 		current_vddc = pi->boot_pl.vddc_index;
1392d70229f7SAlex Deucher 		current_sclk = pi->boot_pl.sclk;
1393d70229f7SAlex Deucher 	}
1394d70229f7SAlex Deucher 
1395d70229f7SAlex Deucher 	ps->levels[0].vddc_index = current_vddc;
1396d70229f7SAlex Deucher 
1397d70229f7SAlex Deucher 	if (ps->levels[0].sclk > current_sclk)
1398d70229f7SAlex Deucher 		ps->levels[0].sclk = current_sclk;
1399d70229f7SAlex Deucher 
1400d70229f7SAlex Deucher 	ps->levels[0].ds_divider_index =
1401d70229f7SAlex Deucher 		trinity_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
1402d70229f7SAlex Deucher 	ps->levels[0].ss_divider_index = ps->levels[0].ds_divider_index;
1403d70229f7SAlex Deucher 	ps->levels[0].allow_gnb_slow = 1;
1404d70229f7SAlex Deucher 	ps->levels[0].force_nbp_state = 0;
1405d70229f7SAlex Deucher 	ps->levels[0].display_wm = 0;
1406d70229f7SAlex Deucher 	ps->levels[0].vce_wm =
1407d70229f7SAlex Deucher 		trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
1408d70229f7SAlex Deucher }
1409d70229f7SAlex Deucher 
1410d70229f7SAlex Deucher static u8 trinity_calculate_display_wm(struct radeon_device *rdev,
1411d70229f7SAlex Deucher 				       struct trinity_ps *ps, u32 index)
1412d70229f7SAlex Deucher {
1413d70229f7SAlex Deucher 	if (ps == NULL || ps->num_levels <= 1)
1414d70229f7SAlex Deucher 		return 0;
1415d70229f7SAlex Deucher 	else if (ps->num_levels == 2) {
1416d70229f7SAlex Deucher 		if (index == 0)
1417d70229f7SAlex Deucher 			return 0;
1418d70229f7SAlex Deucher 		else
1419d70229f7SAlex Deucher 			return 1;
1420d70229f7SAlex Deucher 	} else {
1421d70229f7SAlex Deucher 		if (index == 0)
1422d70229f7SAlex Deucher 			return 0;
1423d70229f7SAlex Deucher 		else if (ps->levels[index].sclk < 30000)
1424d70229f7SAlex Deucher 			return 0;
1425d70229f7SAlex Deucher 		else
1426d70229f7SAlex Deucher 			return 1;
1427d70229f7SAlex Deucher 	}
1428d70229f7SAlex Deucher }
1429d70229f7SAlex Deucher 
14300c4aaeaeSAlex Deucher static u32 trinity_get_uvd_clock_index(struct radeon_device *rdev,
14310c4aaeaeSAlex Deucher 				       struct radeon_ps *rps)
14320c4aaeaeSAlex Deucher {
14330c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
14340c4aaeaeSAlex Deucher 	u32 i = 0;
14350c4aaeaeSAlex Deucher 
14360c4aaeaeSAlex Deucher 	for (i = 0; i < 4; i++) {
14370c4aaeaeSAlex Deucher 		if ((rps->vclk == pi->sys_info.uvd_clock_table_entries[i].vclk) &&
14380c4aaeaeSAlex Deucher 		    (rps->dclk == pi->sys_info.uvd_clock_table_entries[i].dclk))
14390c4aaeaeSAlex Deucher 		    break;
14400c4aaeaeSAlex Deucher 	}
14410c4aaeaeSAlex Deucher 
14420c4aaeaeSAlex Deucher 	if (i >= 4) {
14430c4aaeaeSAlex Deucher 		DRM_ERROR("UVD clock index not found!\n");
14440c4aaeaeSAlex Deucher 		i = 3;
14450c4aaeaeSAlex Deucher 	}
14460c4aaeaeSAlex Deucher 	return i;
14470c4aaeaeSAlex Deucher }
14480c4aaeaeSAlex Deucher 
14490c4aaeaeSAlex Deucher static void trinity_adjust_uvd_state(struct radeon_device *rdev,
14500c4aaeaeSAlex Deucher 				     struct radeon_ps *rps)
14510c4aaeaeSAlex Deucher {
14520c4aaeaeSAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
14530c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
14540c4aaeaeSAlex Deucher 	u32 high_index = 0;
14550c4aaeaeSAlex Deucher 	u32 low_index = 0;
14560c4aaeaeSAlex Deucher 
14570c4aaeaeSAlex Deucher 	if (pi->uvd_dpm && r600_is_uvd_state(rps->class, rps->class2)) {
14580c4aaeaeSAlex Deucher 		high_index = trinity_get_uvd_clock_index(rdev, rps);
14590c4aaeaeSAlex Deucher 
14600c4aaeaeSAlex Deucher 		switch(high_index) {
14610c4aaeaeSAlex Deucher 		case 3:
14620c4aaeaeSAlex Deucher 		case 2:
14630c4aaeaeSAlex Deucher 			low_index = 1;
14640c4aaeaeSAlex Deucher 			break;
14650c4aaeaeSAlex Deucher 		case 1:
14660c4aaeaeSAlex Deucher 		case 0:
14670c4aaeaeSAlex Deucher 		default:
14680c4aaeaeSAlex Deucher 			low_index = 0;
14690c4aaeaeSAlex Deucher 			break;
14700c4aaeaeSAlex Deucher 		}
14710c4aaeaeSAlex Deucher 
14720c4aaeaeSAlex Deucher 		ps->vclk_low_divider =
14730c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[high_index].vclk_did;
14740c4aaeaeSAlex Deucher 		ps->dclk_low_divider =
14750c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[high_index].dclk_did;
14760c4aaeaeSAlex Deucher 		ps->vclk_high_divider =
14770c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[low_index].vclk_did;
14780c4aaeaeSAlex Deucher 		ps->dclk_high_divider =
14790c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[low_index].dclk_did;
14800c4aaeaeSAlex Deucher 	}
14810c4aaeaeSAlex Deucher }
14820c4aaeaeSAlex Deucher 
14830c4aaeaeSAlex Deucher 
14840c4aaeaeSAlex Deucher 
1485940eea8eSAlex Deucher static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
1486940eea8eSAlex Deucher 					     struct radeon_ps *new_rps,
1487940eea8eSAlex Deucher 					     struct radeon_ps *old_rps)
1488d70229f7SAlex Deucher {
1489940eea8eSAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(new_rps);
1490940eea8eSAlex Deucher 	struct trinity_ps *current_ps = trinity_get_ps(old_rps);
1491d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1492d70229f7SAlex Deucher 	u32 min_voltage = 0; /* ??? */
1493d70229f7SAlex Deucher 	u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
1494d70229f7SAlex Deucher 	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
1495d70229f7SAlex Deucher 	u32 i;
1496d70229f7SAlex Deucher 	bool force_high;
1497d70229f7SAlex Deucher 	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
1498d70229f7SAlex Deucher 
1499940eea8eSAlex Deucher 	if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
1500d70229f7SAlex Deucher 		return trinity_patch_thermal_state(rdev, ps, current_ps);
1501d70229f7SAlex Deucher 
1502940eea8eSAlex Deucher 	trinity_adjust_uvd_state(rdev, new_rps);
15030c4aaeaeSAlex Deucher 
1504d70229f7SAlex Deucher 	for (i = 0; i < ps->num_levels; i++) {
1505d70229f7SAlex Deucher 		if (ps->levels[i].vddc_index < min_voltage)
1506d70229f7SAlex Deucher 			ps->levels[i].vddc_index = min_voltage;
1507d70229f7SAlex Deucher 
1508d70229f7SAlex Deucher 		if (ps->levels[i].sclk < min_sclk)
1509d70229f7SAlex Deucher 			ps->levels[i].sclk =
1510d70229f7SAlex Deucher 				trinity_get_valid_engine_clock(rdev, min_sclk);
1511d70229f7SAlex Deucher 
1512d70229f7SAlex Deucher 		ps->levels[i].ds_divider_index =
1513d70229f7SAlex Deucher 			sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
1514d70229f7SAlex Deucher 
1515d70229f7SAlex Deucher 		ps->levels[i].ss_divider_index = ps->levels[i].ds_divider_index;
1516d70229f7SAlex Deucher 
1517d70229f7SAlex Deucher 		ps->levels[i].allow_gnb_slow = 1;
1518d70229f7SAlex Deucher 		ps->levels[i].force_nbp_state = 0;
1519d70229f7SAlex Deucher 		ps->levels[i].display_wm =
1520d70229f7SAlex Deucher 			trinity_calculate_display_wm(rdev, ps, i);
1521d70229f7SAlex Deucher 		ps->levels[i].vce_wm =
1522d70229f7SAlex Deucher 			trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
1523d70229f7SAlex Deucher 	}
1524d70229f7SAlex Deucher 
1525940eea8eSAlex Deucher 	if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
1526940eea8eSAlex Deucher 	    ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY))
1527d70229f7SAlex Deucher 		ps->bapm_flags |= TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE;
1528d70229f7SAlex Deucher 
1529d70229f7SAlex Deucher 	if (pi->sys_info.nb_dpm_enable) {
1530d70229f7SAlex Deucher 		ps->Dpm0PgNbPsLo = 0x1;
1531d70229f7SAlex Deucher 		ps->Dpm0PgNbPsHi = 0x0;
1532d70229f7SAlex Deucher 		ps->DpmXNbPsLo = 0x2;
1533d70229f7SAlex Deucher 		ps->DpmXNbPsHi = 0x1;
1534d70229f7SAlex Deucher 
1535940eea8eSAlex Deucher 		if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
1536940eea8eSAlex Deucher 		    ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) {
1537940eea8eSAlex Deucher 			force_high = ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ||
1538940eea8eSAlex Deucher 				      ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) &&
1539d70229f7SAlex Deucher 				       (pi->sys_info.uma_channel_number == 1)));
1540d70229f7SAlex Deucher 			force_high = (num_active_displays >= 3) || force_high;
1541d70229f7SAlex Deucher 			ps->Dpm0PgNbPsLo = force_high ? 0x2 : 0x3;
1542d70229f7SAlex Deucher 			ps->Dpm0PgNbPsHi = 0x1;
1543d70229f7SAlex Deucher 			ps->DpmXNbPsLo = force_high ? 0x2 : 0x3;
1544d70229f7SAlex Deucher 			ps->DpmXNbPsHi = 0x2;
1545d70229f7SAlex Deucher 			ps->levels[ps->num_levels - 1].allow_gnb_slow = 0;
1546d70229f7SAlex Deucher 		}
1547d70229f7SAlex Deucher 	}
1548d70229f7SAlex Deucher }
1549d70229f7SAlex Deucher 
1550d70229f7SAlex Deucher static void trinity_cleanup_asic(struct radeon_device *rdev)
1551d70229f7SAlex Deucher {
1552d70229f7SAlex Deucher 	sumo_take_smu_control(rdev, false);
1553d70229f7SAlex Deucher }
1554d70229f7SAlex Deucher 
1555d70229f7SAlex Deucher #if 0
1556d70229f7SAlex Deucher static void trinity_pre_display_configuration_change(struct radeon_device *rdev)
1557d70229f7SAlex Deucher {
1558d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1559d70229f7SAlex Deucher 
1560d70229f7SAlex Deucher 	if (pi->voltage_drop_in_dce)
1561d70229f7SAlex Deucher 		trinity_dce_enable_voltage_adjustment(rdev, false);
1562d70229f7SAlex Deucher }
1563d70229f7SAlex Deucher #endif
1564d70229f7SAlex Deucher 
1565d70229f7SAlex Deucher static void trinity_add_dccac_value(struct radeon_device *rdev)
1566d70229f7SAlex Deucher {
1567d70229f7SAlex Deucher 	u32 gpu_cac_avrg_cntl_window_size;
1568d70229f7SAlex Deucher 	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
1569d70229f7SAlex Deucher 	u64 disp_clk = rdev->clock.default_dispclk / 100;
1570d70229f7SAlex Deucher 	u32 dc_cac_value;
1571d70229f7SAlex Deucher 
1572d70229f7SAlex Deucher 	gpu_cac_avrg_cntl_window_size =
1573d70229f7SAlex Deucher 		(RREG32_SMC(GPU_CAC_AVRG_CNTL) & WINDOW_SIZE_MASK) >> WINDOW_SIZE_SHIFT;
1574d70229f7SAlex Deucher 
1575d70229f7SAlex Deucher 	dc_cac_value = (u32)((14213 * disp_clk * disp_clk * (u64)num_active_displays) >>
1576d70229f7SAlex Deucher 			     (32 - gpu_cac_avrg_cntl_window_size));
1577d70229f7SAlex Deucher 
1578d70229f7SAlex Deucher 	WREG32_SMC(DC_CAC_VALUE, dc_cac_value);
1579d70229f7SAlex Deucher }
1580d70229f7SAlex Deucher 
1581d70229f7SAlex Deucher void trinity_dpm_display_configuration_changed(struct radeon_device *rdev)
1582d70229f7SAlex Deucher {
1583d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1584d70229f7SAlex Deucher 
1585d70229f7SAlex Deucher 	if (pi->voltage_drop_in_dce)
1586d70229f7SAlex Deucher 		trinity_dce_enable_voltage_adjustment(rdev, true);
1587d70229f7SAlex Deucher 	trinity_add_dccac_value(rdev);
1588d70229f7SAlex Deucher }
1589d70229f7SAlex Deucher 
1590d70229f7SAlex Deucher union power_info {
1591d70229f7SAlex Deucher 	struct _ATOM_POWERPLAY_INFO info;
1592d70229f7SAlex Deucher 	struct _ATOM_POWERPLAY_INFO_V2 info_2;
1593d70229f7SAlex Deucher 	struct _ATOM_POWERPLAY_INFO_V3 info_3;
1594d70229f7SAlex Deucher 	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
1595d70229f7SAlex Deucher 	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
1596d70229f7SAlex Deucher 	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
1597d70229f7SAlex Deucher };
1598d70229f7SAlex Deucher 
1599d70229f7SAlex Deucher union pplib_clock_info {
1600d70229f7SAlex Deucher 	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
1601d70229f7SAlex Deucher 	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
1602d70229f7SAlex Deucher 	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
1603d70229f7SAlex Deucher 	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
1604d70229f7SAlex Deucher };
1605d70229f7SAlex Deucher 
1606d70229f7SAlex Deucher union pplib_power_state {
1607d70229f7SAlex Deucher 	struct _ATOM_PPLIB_STATE v1;
1608d70229f7SAlex Deucher 	struct _ATOM_PPLIB_STATE_V2 v2;
1609d70229f7SAlex Deucher };
1610d70229f7SAlex Deucher 
1611d70229f7SAlex Deucher static void trinity_parse_pplib_non_clock_info(struct radeon_device *rdev,
1612d70229f7SAlex Deucher 					       struct radeon_ps *rps,
1613d70229f7SAlex Deucher 					       struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
1614d70229f7SAlex Deucher 					       u8 table_rev)
1615d70229f7SAlex Deucher {
1616d70229f7SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
1617d70229f7SAlex Deucher 
1618d70229f7SAlex Deucher 	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
1619d70229f7SAlex Deucher 	rps->class = le16_to_cpu(non_clock_info->usClassification);
1620d70229f7SAlex Deucher 	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
1621d70229f7SAlex Deucher 
1622d70229f7SAlex Deucher 	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
1623d70229f7SAlex Deucher 		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
1624d70229f7SAlex Deucher 		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
1625d70229f7SAlex Deucher 	} else {
1626d70229f7SAlex Deucher 		rps->vclk = 0;
1627d70229f7SAlex Deucher 		rps->dclk = 0;
1628d70229f7SAlex Deucher 	}
1629d70229f7SAlex Deucher 
1630d70229f7SAlex Deucher 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
1631d70229f7SAlex Deucher 		rdev->pm.dpm.boot_ps = rps;
1632d70229f7SAlex Deucher 		trinity_patch_boot_state(rdev, ps);
1633d70229f7SAlex Deucher 	}
1634d70229f7SAlex Deucher 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
1635d70229f7SAlex Deucher 		rdev->pm.dpm.uvd_ps = rps;
1636d70229f7SAlex Deucher }
1637d70229f7SAlex Deucher 
1638d70229f7SAlex Deucher static void trinity_parse_pplib_clock_info(struct radeon_device *rdev,
1639d70229f7SAlex Deucher 					   struct radeon_ps *rps, int index,
1640d70229f7SAlex Deucher 					   union pplib_clock_info *clock_info)
1641d70229f7SAlex Deucher {
1642d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1643d70229f7SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
1644d70229f7SAlex Deucher 	struct trinity_pl *pl = &ps->levels[index];
1645d70229f7SAlex Deucher 	u32 sclk;
1646d70229f7SAlex Deucher 
1647d70229f7SAlex Deucher 	sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
1648d70229f7SAlex Deucher 	sclk |= clock_info->sumo.ucEngineClockHigh << 16;
1649d70229f7SAlex Deucher 	pl->sclk = sclk;
1650d70229f7SAlex Deucher 	pl->vddc_index = clock_info->sumo.vddcIndex;
1651d70229f7SAlex Deucher 
1652d70229f7SAlex Deucher 	ps->num_levels = index + 1;
1653d70229f7SAlex Deucher 
1654d70229f7SAlex Deucher 	if (pi->enable_sclk_ds) {
1655d70229f7SAlex Deucher 		pl->ds_divider_index = 5;
1656d70229f7SAlex Deucher 		pl->ss_divider_index = 5;
1657d70229f7SAlex Deucher 	}
1658d70229f7SAlex Deucher }
1659d70229f7SAlex Deucher 
1660d70229f7SAlex Deucher static int trinity_parse_power_table(struct radeon_device *rdev)
1661d70229f7SAlex Deucher {
1662d70229f7SAlex Deucher 	struct radeon_mode_info *mode_info = &rdev->mode_info;
1663d70229f7SAlex Deucher 	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
1664d70229f7SAlex Deucher 	union pplib_power_state *power_state;
1665d70229f7SAlex Deucher 	int i, j, k, non_clock_array_index, clock_array_index;
1666d70229f7SAlex Deucher 	union pplib_clock_info *clock_info;
1667d70229f7SAlex Deucher 	struct _StateArray *state_array;
1668d70229f7SAlex Deucher 	struct _ClockInfoArray *clock_info_array;
1669d70229f7SAlex Deucher 	struct _NonClockInfoArray *non_clock_info_array;
1670d70229f7SAlex Deucher 	union power_info *power_info;
1671d70229f7SAlex Deucher 	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
1672d70229f7SAlex Deucher         u16 data_offset;
1673d70229f7SAlex Deucher 	u8 frev, crev;
1674d70229f7SAlex Deucher 	u8 *power_state_offset;
1675d70229f7SAlex Deucher 	struct sumo_ps *ps;
1676d70229f7SAlex Deucher 
1677d70229f7SAlex Deucher 	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
1678d70229f7SAlex Deucher 				   &frev, &crev, &data_offset))
1679d70229f7SAlex Deucher 		return -EINVAL;
1680d70229f7SAlex Deucher 	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
1681d70229f7SAlex Deucher 
1682d70229f7SAlex Deucher 	state_array = (struct _StateArray *)
1683d70229f7SAlex Deucher 		(mode_info->atom_context->bios + data_offset +
1684d70229f7SAlex Deucher 		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
1685d70229f7SAlex Deucher 	clock_info_array = (struct _ClockInfoArray *)
1686d70229f7SAlex Deucher 		(mode_info->atom_context->bios + data_offset +
1687d70229f7SAlex Deucher 		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
1688d70229f7SAlex Deucher 	non_clock_info_array = (struct _NonClockInfoArray *)
1689d70229f7SAlex Deucher 		(mode_info->atom_context->bios + data_offset +
1690d70229f7SAlex Deucher 		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
1691d70229f7SAlex Deucher 
1692d70229f7SAlex Deucher 	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
1693d70229f7SAlex Deucher 				  state_array->ucNumEntries, GFP_KERNEL);
1694d70229f7SAlex Deucher 	if (!rdev->pm.dpm.ps)
1695d70229f7SAlex Deucher 		return -ENOMEM;
1696d70229f7SAlex Deucher 	power_state_offset = (u8 *)state_array->states;
1697d70229f7SAlex Deucher 	for (i = 0; i < state_array->ucNumEntries; i++) {
16985e250d20SAlex Deucher 		u8 *idx;
1699d70229f7SAlex Deucher 		power_state = (union pplib_power_state *)power_state_offset;
1700d70229f7SAlex Deucher 		non_clock_array_index = power_state->v2.nonClockInfoIndex;
1701d70229f7SAlex Deucher 		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
1702d70229f7SAlex Deucher 			&non_clock_info_array->nonClockInfo[non_clock_array_index];
1703d70229f7SAlex Deucher 		if (!rdev->pm.power_state[i].clock_info)
1704d70229f7SAlex Deucher 			return -EINVAL;
1705d70229f7SAlex Deucher 		ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
1706d70229f7SAlex Deucher 		if (ps == NULL) {
1707d70229f7SAlex Deucher 			kfree(rdev->pm.dpm.ps);
1708d70229f7SAlex Deucher 			return -ENOMEM;
1709d70229f7SAlex Deucher 		}
1710d70229f7SAlex Deucher 		rdev->pm.dpm.ps[i].ps_priv = ps;
1711d70229f7SAlex Deucher 		k = 0;
17125e250d20SAlex Deucher 		idx = (u8 *)&power_state->v2.clockInfoIndex[0];
1713d70229f7SAlex Deucher 		for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
17145e250d20SAlex Deucher 			clock_array_index = idx[j];
1715d70229f7SAlex Deucher 			if (clock_array_index >= clock_info_array->ucNumEntries)
1716d70229f7SAlex Deucher 				continue;
1717d70229f7SAlex Deucher 			if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
1718d70229f7SAlex Deucher 				break;
1719d70229f7SAlex Deucher 			clock_info = (union pplib_clock_info *)
17205e250d20SAlex Deucher 				((u8 *)&clock_info_array->clockInfo[0] +
17215e250d20SAlex Deucher 				 (clock_array_index * clock_info_array->ucEntrySize));
1722d70229f7SAlex Deucher 			trinity_parse_pplib_clock_info(rdev,
1723d70229f7SAlex Deucher 						       &rdev->pm.dpm.ps[i], k,
1724d70229f7SAlex Deucher 						       clock_info);
1725d70229f7SAlex Deucher 			k++;
1726d70229f7SAlex Deucher 		}
1727d70229f7SAlex Deucher 		trinity_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
1728d70229f7SAlex Deucher 						   non_clock_info,
1729d70229f7SAlex Deucher 						   non_clock_info_array->ucEntrySize);
1730d70229f7SAlex Deucher 		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
1731d70229f7SAlex Deucher 	}
1732d70229f7SAlex Deucher 	rdev->pm.dpm.num_ps = state_array->ucNumEntries;
1733d70229f7SAlex Deucher 	return 0;
1734d70229f7SAlex Deucher }
1735d70229f7SAlex Deucher 
1736d70229f7SAlex Deucher union igp_info {
1737d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
1738d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
1739d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
1740d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
1741d70229f7SAlex Deucher 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
1742d70229f7SAlex Deucher };
1743d70229f7SAlex Deucher 
17440c4aaeaeSAlex Deucher static u32 trinity_convert_did_to_freq(struct radeon_device *rdev, u8 did)
17450c4aaeaeSAlex Deucher {
17460c4aaeaeSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
17470c4aaeaeSAlex Deucher 	u32 divider;
17480c4aaeaeSAlex Deucher 
17490c4aaeaeSAlex Deucher 	if (did >= 8 && did <= 0x3f)
17500c4aaeaeSAlex Deucher 		divider = did * 25;
17510c4aaeaeSAlex Deucher 	else if (did > 0x3f && did <= 0x5f)
17520c4aaeaeSAlex Deucher 		divider = (did - 64) * 50 + 1600;
17530c4aaeaeSAlex Deucher 	else if (did > 0x5f && did <= 0x7e)
17540c4aaeaeSAlex Deucher 		divider = (did - 96) * 100 + 3200;
17550c4aaeaeSAlex Deucher 	else if (did == 0x7f)
17560c4aaeaeSAlex Deucher 		divider = 128 * 100;
17570c4aaeaeSAlex Deucher 	else
17580c4aaeaeSAlex Deucher 		return 10000;
17590c4aaeaeSAlex Deucher 
17600c4aaeaeSAlex Deucher 	return ((pi->sys_info.dentist_vco_freq * 100) + (divider - 1)) / divider;
17610c4aaeaeSAlex Deucher }
17620c4aaeaeSAlex Deucher 
1763d70229f7SAlex Deucher static int trinity_parse_sys_info_table(struct radeon_device *rdev)
1764d70229f7SAlex Deucher {
1765d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1766d70229f7SAlex Deucher 	struct radeon_mode_info *mode_info = &rdev->mode_info;
1767d70229f7SAlex Deucher 	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
1768d70229f7SAlex Deucher 	union igp_info *igp_info;
1769d70229f7SAlex Deucher 	u8 frev, crev;
1770d70229f7SAlex Deucher 	u16 data_offset;
1771d70229f7SAlex Deucher 	int i;
1772d70229f7SAlex Deucher 
1773d70229f7SAlex Deucher 	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1774d70229f7SAlex Deucher 				   &frev, &crev, &data_offset)) {
1775d70229f7SAlex Deucher 		igp_info = (union igp_info *)(mode_info->atom_context->bios +
1776d70229f7SAlex Deucher 					      data_offset);
1777d70229f7SAlex Deucher 
1778d70229f7SAlex Deucher 		if (crev != 7) {
1779d70229f7SAlex Deucher 			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
1780d70229f7SAlex Deucher 			return -EINVAL;
1781d70229f7SAlex Deucher 		}
1782d70229f7SAlex Deucher 		pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock);
1783d70229f7SAlex Deucher 		pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock);
1784d70229f7SAlex Deucher 		pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock);
17850c4aaeaeSAlex Deucher 		pi->sys_info.dentist_vco_freq = le32_to_cpu(igp_info->info_7.ulDentistVCOFreq);
1786d70229f7SAlex Deucher 		pi->sys_info.bootup_nb_voltage_index =
1787d70229f7SAlex Deucher 			le16_to_cpu(igp_info->info_7.usBootUpNBVoltage);
1788d70229f7SAlex Deucher 		if (igp_info->info_7.ucHtcTmpLmt == 0)
1789d70229f7SAlex Deucher 			pi->sys_info.htc_tmp_lmt = 203;
1790d70229f7SAlex Deucher 		else
1791d70229f7SAlex Deucher 			pi->sys_info.htc_tmp_lmt = igp_info->info_7.ucHtcTmpLmt;
1792d70229f7SAlex Deucher 		if (igp_info->info_7.ucHtcHystLmt == 0)
1793d70229f7SAlex Deucher 			pi->sys_info.htc_hyst_lmt = 5;
1794d70229f7SAlex Deucher 		else
1795d70229f7SAlex Deucher 			pi->sys_info.htc_hyst_lmt = igp_info->info_7.ucHtcHystLmt;
1796d70229f7SAlex Deucher 		if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
1797d70229f7SAlex Deucher 			DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
1798d70229f7SAlex Deucher 		}
1799d70229f7SAlex Deucher 
1800d70229f7SAlex Deucher 		if (pi->enable_nbps_policy)
1801d70229f7SAlex Deucher 			pi->sys_info.nb_dpm_enable = igp_info->info_7.ucNBDPMEnable;
1802d70229f7SAlex Deucher 		else
1803d70229f7SAlex Deucher 			pi->sys_info.nb_dpm_enable = 0;
1804d70229f7SAlex Deucher 
1805d70229f7SAlex Deucher 		for (i = 0; i < TRINITY_NUM_NBPSTATES; i++) {
1806d70229f7SAlex Deucher 			pi->sys_info.nbp_mclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateMemclkFreq[i]);
1807d70229f7SAlex Deucher 			pi->sys_info.nbp_nclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateNClkFreq[i]);
1808d70229f7SAlex Deucher 		}
1809d70229f7SAlex Deucher 
1810d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[0] = le16_to_cpu(igp_info->info_7.usNBP0Voltage);
1811d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[1] = le16_to_cpu(igp_info->info_7.usNBP1Voltage);
1812d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[2] = le16_to_cpu(igp_info->info_7.usNBP2Voltage);
1813d70229f7SAlex Deucher 		pi->sys_info.nbp_voltage_index[3] = le16_to_cpu(igp_info->info_7.usNBP3Voltage);
1814d70229f7SAlex Deucher 
1815d70229f7SAlex Deucher 		if (!pi->sys_info.nb_dpm_enable) {
1816d70229f7SAlex Deucher 			for (i = 1; i < TRINITY_NUM_NBPSTATES; i++) {
1817d70229f7SAlex Deucher 				pi->sys_info.nbp_mclk[i] = pi->sys_info.nbp_mclk[0];
1818d70229f7SAlex Deucher 				pi->sys_info.nbp_nclk[i] = pi->sys_info.nbp_nclk[0];
1819d70229f7SAlex Deucher 				pi->sys_info.nbp_voltage_index[i] = pi->sys_info.nbp_voltage_index[0];
1820d70229f7SAlex Deucher 			}
1821d70229f7SAlex Deucher 		}
1822d70229f7SAlex Deucher 
1823d70229f7SAlex Deucher 		pi->sys_info.uma_channel_number = igp_info->info_7.ucUMAChannelNumber;
1824d70229f7SAlex Deucher 
1825d70229f7SAlex Deucher 		sumo_construct_sclk_voltage_mapping_table(rdev,
1826d70229f7SAlex Deucher 							  &pi->sys_info.sclk_voltage_mapping_table,
1827d70229f7SAlex Deucher 							  igp_info->info_7.sAvail_SCLK);
1828d70229f7SAlex Deucher 		sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
1829d70229f7SAlex Deucher 						 igp_info->info_7.sAvail_SCLK);
1830d70229f7SAlex Deucher 
18310c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[0].vclk_did =
18320c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState0VclkFid;
18330c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[1].vclk_did =
18340c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState1VclkFid;
18350c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[2].vclk_did =
18360c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState2VclkFid;
18370c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[3].vclk_did =
18380c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState3VclkFid;
18390c4aaeaeSAlex Deucher 
18400c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[0].dclk_did =
18410c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState0DclkFid;
18420c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[1].dclk_did =
18430c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState1DclkFid;
18440c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[2].dclk_did =
18450c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState2DclkFid;
18460c4aaeaeSAlex Deucher 		pi->sys_info.uvd_clock_table_entries[3].dclk_did =
18470c4aaeaeSAlex Deucher 			igp_info->info_7.ucDPMState3DclkFid;
18480c4aaeaeSAlex Deucher 
18490c4aaeaeSAlex Deucher 		for (i = 0; i < 4; i++) {
18500c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[i].vclk =
18510c4aaeaeSAlex Deucher 				trinity_convert_did_to_freq(rdev,
18520c4aaeaeSAlex Deucher 							    pi->sys_info.uvd_clock_table_entries[i].vclk_did);
18530c4aaeaeSAlex Deucher 			pi->sys_info.uvd_clock_table_entries[i].dclk =
18540c4aaeaeSAlex Deucher 				trinity_convert_did_to_freq(rdev,
18550c4aaeaeSAlex Deucher 							    pi->sys_info.uvd_clock_table_entries[i].dclk_did);
18560c4aaeaeSAlex Deucher 		}
18570c4aaeaeSAlex Deucher 
18580c4aaeaeSAlex Deucher 
18590c4aaeaeSAlex Deucher 
1860d70229f7SAlex Deucher 	}
1861d70229f7SAlex Deucher 	return 0;
1862d70229f7SAlex Deucher }
1863d70229f7SAlex Deucher 
1864d70229f7SAlex Deucher int trinity_dpm_init(struct radeon_device *rdev)
1865d70229f7SAlex Deucher {
1866d70229f7SAlex Deucher 	struct trinity_power_info *pi;
1867d70229f7SAlex Deucher 	int ret, i;
1868d70229f7SAlex Deucher 
1869d70229f7SAlex Deucher 	pi = kzalloc(sizeof(struct trinity_power_info), GFP_KERNEL);
1870d70229f7SAlex Deucher 	if (pi == NULL)
1871d70229f7SAlex Deucher 		return -ENOMEM;
1872d70229f7SAlex Deucher 	rdev->pm.dpm.priv = pi;
1873d70229f7SAlex Deucher 
1874d70229f7SAlex Deucher 	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
1875d70229f7SAlex Deucher 		pi->at[i] = TRINITY_AT_DFLT;
1876d70229f7SAlex Deucher 
18776e909f74SAlex Deucher 	if (radeon_bapm == -1) {
1878730a336cSAlex Deucher 		/* There are stability issues reported on with
1879730a336cSAlex Deucher 		 * bapm enabled when switching between AC and battery
1880730a336cSAlex Deucher 		 * power.  At the same time, some MSI boards hang
1881730a336cSAlex Deucher 		 * if it's not enabled and dpm is enabled.  Just enable
1882730a336cSAlex Deucher 		 * it for MSI boards right now.
18830c78a449SAlex Deucher 		 */
1884730a336cSAlex Deucher 		if (rdev->pdev->subsystem_vendor == 0x1462)
18850c78a449SAlex Deucher 			pi->enable_bapm = true;
1886730a336cSAlex Deucher 		else
1887730a336cSAlex Deucher 			pi->enable_bapm = false;
18886e909f74SAlex Deucher 	} else if (radeon_bapm == 0) {
18896e909f74SAlex Deucher 		pi->enable_bapm = false;
18906e909f74SAlex Deucher 	} else {
18916e909f74SAlex Deucher 		pi->enable_bapm = true;
18926e909f74SAlex Deucher 	}
1893d70229f7SAlex Deucher 	pi->enable_nbps_policy = true;
1894d70229f7SAlex Deucher 	pi->enable_sclk_ds = true;
1895d70229f7SAlex Deucher 	pi->enable_gfx_power_gating = true;
1896d70229f7SAlex Deucher 	pi->enable_gfx_clock_gating = true;
1897958b84fbSAlex Deucher 	pi->enable_mg_clock_gating = false;
1898958b84fbSAlex Deucher 	pi->enable_gfx_dynamic_mgpg = false;
1899958b84fbSAlex Deucher 	pi->override_dynamic_mgpg = false;
1900d70229f7SAlex Deucher 	pi->enable_auto_thermal_throttling = true;
1901d70229f7SAlex Deucher 	pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
19020c4aaeaeSAlex Deucher 	pi->uvd_dpm = true; /* ??? */
1903d70229f7SAlex Deucher 
1904d70229f7SAlex Deucher 	ret = trinity_parse_sys_info_table(rdev);
1905d70229f7SAlex Deucher 	if (ret)
1906d70229f7SAlex Deucher 		return ret;
1907d70229f7SAlex Deucher 
1908d70229f7SAlex Deucher 	trinity_construct_boot_state(rdev);
1909d70229f7SAlex Deucher 
191082f79cc5SAlex Deucher 	ret = r600_get_platform_caps(rdev);
191182f79cc5SAlex Deucher 	if (ret)
191282f79cc5SAlex Deucher 		return ret;
191382f79cc5SAlex Deucher 
1914d70229f7SAlex Deucher 	ret = trinity_parse_power_table(rdev);
1915d70229f7SAlex Deucher 	if (ret)
1916d70229f7SAlex Deucher 		return ret;
1917d70229f7SAlex Deucher 
1918d70229f7SAlex Deucher 	pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
1919d70229f7SAlex Deucher 	pi->enable_dpm = true;
1920d70229f7SAlex Deucher 
1921d70229f7SAlex Deucher 	return 0;
1922d70229f7SAlex Deucher }
1923d70229f7SAlex Deucher 
1924d70229f7SAlex Deucher void trinity_dpm_print_power_state(struct radeon_device *rdev,
1925d70229f7SAlex Deucher 				   struct radeon_ps *rps)
1926d70229f7SAlex Deucher {
1927d70229f7SAlex Deucher 	int i;
1928d70229f7SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
1929d70229f7SAlex Deucher 
1930d70229f7SAlex Deucher 	r600_dpm_print_class_info(rps->class, rps->class2);
1931d70229f7SAlex Deucher 	r600_dpm_print_cap_info(rps->caps);
1932d70229f7SAlex Deucher 	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
1933d70229f7SAlex Deucher 	for (i = 0; i < ps->num_levels; i++) {
1934d70229f7SAlex Deucher 		struct trinity_pl *pl = &ps->levels[i];
1935d70229f7SAlex Deucher 		printk("\t\tpower level %d    sclk: %u vddc: %u\n",
1936d70229f7SAlex Deucher 		       i, pl->sclk,
1937d70229f7SAlex Deucher 		       trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
1938d70229f7SAlex Deucher 	}
1939d70229f7SAlex Deucher 	r600_dpm_print_ps_status(rdev, rps);
1940d70229f7SAlex Deucher }
1941d70229f7SAlex Deucher 
1942490ab931SAlex Deucher void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
1943490ab931SAlex Deucher 							 struct seq_file *m)
1944490ab931SAlex Deucher {
19459f3f63f2SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
19469f3f63f2SAlex Deucher 	struct radeon_ps *rps = &pi->current_rps;
1947490ab931SAlex Deucher 	struct trinity_ps *ps = trinity_get_ps(rps);
1948490ab931SAlex Deucher 	struct trinity_pl *pl;
1949490ab931SAlex Deucher 	u32 current_index =
1950490ab931SAlex Deucher 		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
1951490ab931SAlex Deucher 		CURRENT_STATE_SHIFT;
1952490ab931SAlex Deucher 
1953490ab931SAlex Deucher 	if (current_index >= ps->num_levels) {
1954490ab931SAlex Deucher 		seq_printf(m, "invalid dpm profile %d\n", current_index);
1955490ab931SAlex Deucher 	} else {
1956490ab931SAlex Deucher 		pl = &ps->levels[current_index];
1957490ab931SAlex Deucher 		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
1958490ab931SAlex Deucher 		seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
1959490ab931SAlex Deucher 			   current_index, pl->sclk,
1960490ab931SAlex Deucher 			   trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
1961490ab931SAlex Deucher 	}
1962490ab931SAlex Deucher }
1963490ab931SAlex Deucher 
1964d70229f7SAlex Deucher void trinity_dpm_fini(struct radeon_device *rdev)
1965d70229f7SAlex Deucher {
1966d70229f7SAlex Deucher 	int i;
1967d70229f7SAlex Deucher 
1968d70229f7SAlex Deucher 	trinity_cleanup_asic(rdev); /* ??? */
1969d70229f7SAlex Deucher 
1970d70229f7SAlex Deucher 	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
1971d70229f7SAlex Deucher 		kfree(rdev->pm.dpm.ps[i].ps_priv);
1972d70229f7SAlex Deucher 	}
1973d70229f7SAlex Deucher 	kfree(rdev->pm.dpm.ps);
1974d70229f7SAlex Deucher 	kfree(rdev->pm.dpm.priv);
1975d70229f7SAlex Deucher }
1976d70229f7SAlex Deucher 
1977d70229f7SAlex Deucher u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
1978d70229f7SAlex Deucher {
1979a284c48aSAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1980a284c48aSAlex Deucher 	struct trinity_ps *requested_state = trinity_get_ps(&pi->requested_rps);
1981d70229f7SAlex Deucher 
1982d70229f7SAlex Deucher 	if (low)
1983d70229f7SAlex Deucher 		return requested_state->levels[0].sclk;
1984d70229f7SAlex Deucher 	else
1985d70229f7SAlex Deucher 		return requested_state->levels[requested_state->num_levels - 1].sclk;
1986d70229f7SAlex Deucher }
1987d70229f7SAlex Deucher 
1988d70229f7SAlex Deucher u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low)
1989d70229f7SAlex Deucher {
1990d70229f7SAlex Deucher 	struct trinity_power_info *pi = trinity_get_pi(rdev);
1991d70229f7SAlex Deucher 
1992d70229f7SAlex Deucher 	return pi->sys_info.bootup_uma_clk;
1993d70229f7SAlex Deucher }
1994