xref: /openbsd-src/sys/dev/pci/drm/radeon/trinity_dpm.c (revision 6ee266b038160761b783d5ed8c3bee55c648f443)
17ccd5a2cSjsg /*
27ccd5a2cSjsg  * Copyright 2012 Advanced Micro Devices, Inc.
37ccd5a2cSjsg  *
47ccd5a2cSjsg  * Permission is hereby granted, free of charge, to any person obtaining a
57ccd5a2cSjsg  * copy of this software and associated documentation files (the "Software"),
67ccd5a2cSjsg  * to deal in the Software without restriction, including without limitation
77ccd5a2cSjsg  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ccd5a2cSjsg  * and/or sell copies of the Software, and to permit persons to whom the
97ccd5a2cSjsg  * Software is furnished to do so, subject to the following conditions:
107ccd5a2cSjsg  *
117ccd5a2cSjsg  * The above copyright notice and this permission notice shall be included in
127ccd5a2cSjsg  * all copies or substantial portions of the Software.
137ccd5a2cSjsg  *
147ccd5a2cSjsg  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
157ccd5a2cSjsg  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167ccd5a2cSjsg  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
177ccd5a2cSjsg  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
187ccd5a2cSjsg  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
197ccd5a2cSjsg  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
207ccd5a2cSjsg  * OTHER DEALINGS IN THE SOFTWARE.
217ccd5a2cSjsg  *
227ccd5a2cSjsg  */
237ccd5a2cSjsg 
24c349dbc7Sjsg #include <linux/pci.h>
25c349dbc7Sjsg #include <linux/seq_file.h>
26c349dbc7Sjsg 
27c349dbc7Sjsg #include "r600_dpm.h"
287ccd5a2cSjsg #include "radeon.h"
297ccd5a2cSjsg #include "radeon_asic.h"
307ccd5a2cSjsg #include "trinity_dpm.h"
31c349dbc7Sjsg #include "trinityd.h"
325ca02815Sjsg #include "vce.h"
337ccd5a2cSjsg 
347ccd5a2cSjsg #define TRINITY_MAX_DEEPSLEEP_DIVIDER_ID 5
357ccd5a2cSjsg #define TRINITY_MINIMUM_ENGINE_CLOCK 800
367ccd5a2cSjsg #define SCLK_MIN_DIV_INTV_SHIFT     12
377ccd5a2cSjsg #define TRINITY_DISPCLK_BYPASS_THRESHOLD 10000
387ccd5a2cSjsg 
397ccd5a2cSjsg #ifndef TRINITY_MGCG_SEQUENCE
407ccd5a2cSjsg #define TRINITY_MGCG_SEQUENCE  100
417ccd5a2cSjsg 
427ccd5a2cSjsg static const u32 trinity_mgcg_shls_default[] =
437ccd5a2cSjsg {
447ccd5a2cSjsg 	/* Register, Value, Mask */
457ccd5a2cSjsg 	0x0000802c, 0xc0000000, 0xffffffff,
467ccd5a2cSjsg 	0x00003fc4, 0xc0000000, 0xffffffff,
477ccd5a2cSjsg 	0x00005448, 0x00000100, 0xffffffff,
487ccd5a2cSjsg 	0x000055e4, 0x00000100, 0xffffffff,
497ccd5a2cSjsg 	0x0000160c, 0x00000100, 0xffffffff,
507ccd5a2cSjsg 	0x00008984, 0x06000100, 0xffffffff,
517ccd5a2cSjsg 	0x0000c164, 0x00000100, 0xffffffff,
527ccd5a2cSjsg 	0x00008a18, 0x00000100, 0xffffffff,
537ccd5a2cSjsg 	0x0000897c, 0x06000100, 0xffffffff,
547ccd5a2cSjsg 	0x00008b28, 0x00000100, 0xffffffff,
557ccd5a2cSjsg 	0x00009144, 0x00800200, 0xffffffff,
567ccd5a2cSjsg 	0x00009a60, 0x00000100, 0xffffffff,
577ccd5a2cSjsg 	0x00009868, 0x00000100, 0xffffffff,
587ccd5a2cSjsg 	0x00008d58, 0x00000100, 0xffffffff,
597ccd5a2cSjsg 	0x00009510, 0x00000100, 0xffffffff,
607ccd5a2cSjsg 	0x0000949c, 0x00000100, 0xffffffff,
617ccd5a2cSjsg 	0x00009654, 0x00000100, 0xffffffff,
627ccd5a2cSjsg 	0x00009030, 0x00000100, 0xffffffff,
637ccd5a2cSjsg 	0x00009034, 0x00000100, 0xffffffff,
647ccd5a2cSjsg 	0x00009038, 0x00000100, 0xffffffff,
657ccd5a2cSjsg 	0x0000903c, 0x00000100, 0xffffffff,
667ccd5a2cSjsg 	0x00009040, 0x00000100, 0xffffffff,
677ccd5a2cSjsg 	0x0000a200, 0x00000100, 0xffffffff,
687ccd5a2cSjsg 	0x0000a204, 0x00000100, 0xffffffff,
697ccd5a2cSjsg 	0x0000a208, 0x00000100, 0xffffffff,
707ccd5a2cSjsg 	0x0000a20c, 0x00000100, 0xffffffff,
717ccd5a2cSjsg 	0x00009744, 0x00000100, 0xffffffff,
727ccd5a2cSjsg 	0x00003f80, 0x00000100, 0xffffffff,
737ccd5a2cSjsg 	0x0000a210, 0x00000100, 0xffffffff,
747ccd5a2cSjsg 	0x0000a214, 0x00000100, 0xffffffff,
757ccd5a2cSjsg 	0x000004d8, 0x00000100, 0xffffffff,
767ccd5a2cSjsg 	0x00009664, 0x00000100, 0xffffffff,
777ccd5a2cSjsg 	0x00009698, 0x00000100, 0xffffffff,
787ccd5a2cSjsg 	0x000004d4, 0x00000200, 0xffffffff,
797ccd5a2cSjsg 	0x000004d0, 0x00000000, 0xffffffff,
807ccd5a2cSjsg 	0x000030cc, 0x00000104, 0xffffffff,
817ccd5a2cSjsg 	0x0000d0c0, 0x00000100, 0xffffffff,
827ccd5a2cSjsg 	0x0000d8c0, 0x00000100, 0xffffffff,
837ccd5a2cSjsg 	0x0000951c, 0x00010000, 0xffffffff,
847ccd5a2cSjsg 	0x00009160, 0x00030002, 0xffffffff,
857ccd5a2cSjsg 	0x00009164, 0x00050004, 0xffffffff,
867ccd5a2cSjsg 	0x00009168, 0x00070006, 0xffffffff,
877ccd5a2cSjsg 	0x00009178, 0x00070000, 0xffffffff,
887ccd5a2cSjsg 	0x0000917c, 0x00030002, 0xffffffff,
897ccd5a2cSjsg 	0x00009180, 0x00050004, 0xffffffff,
907ccd5a2cSjsg 	0x0000918c, 0x00010006, 0xffffffff,
917ccd5a2cSjsg 	0x00009190, 0x00090008, 0xffffffff,
927ccd5a2cSjsg 	0x00009194, 0x00070000, 0xffffffff,
937ccd5a2cSjsg 	0x00009198, 0x00030002, 0xffffffff,
947ccd5a2cSjsg 	0x0000919c, 0x00050004, 0xffffffff,
957ccd5a2cSjsg 	0x000091a8, 0x00010006, 0xffffffff,
967ccd5a2cSjsg 	0x000091ac, 0x00090008, 0xffffffff,
977ccd5a2cSjsg 	0x000091b0, 0x00070000, 0xffffffff,
987ccd5a2cSjsg 	0x000091b4, 0x00030002, 0xffffffff,
997ccd5a2cSjsg 	0x000091b8, 0x00050004, 0xffffffff,
1007ccd5a2cSjsg 	0x000091c4, 0x00010006, 0xffffffff,
1017ccd5a2cSjsg 	0x000091c8, 0x00090008, 0xffffffff,
1027ccd5a2cSjsg 	0x000091cc, 0x00070000, 0xffffffff,
1037ccd5a2cSjsg 	0x000091d0, 0x00030002, 0xffffffff,
1047ccd5a2cSjsg 	0x000091d4, 0x00050004, 0xffffffff,
1057ccd5a2cSjsg 	0x000091e0, 0x00010006, 0xffffffff,
1067ccd5a2cSjsg 	0x000091e4, 0x00090008, 0xffffffff,
1077ccd5a2cSjsg 	0x000091e8, 0x00000000, 0xffffffff,
1087ccd5a2cSjsg 	0x000091ec, 0x00070000, 0xffffffff,
1097ccd5a2cSjsg 	0x000091f0, 0x00030002, 0xffffffff,
1107ccd5a2cSjsg 	0x000091f4, 0x00050004, 0xffffffff,
1117ccd5a2cSjsg 	0x00009200, 0x00010006, 0xffffffff,
1127ccd5a2cSjsg 	0x00009204, 0x00090008, 0xffffffff,
1137ccd5a2cSjsg 	0x00009208, 0x00070000, 0xffffffff,
1147ccd5a2cSjsg 	0x0000920c, 0x00030002, 0xffffffff,
1157ccd5a2cSjsg 	0x00009210, 0x00050004, 0xffffffff,
1167ccd5a2cSjsg 	0x0000921c, 0x00010006, 0xffffffff,
1177ccd5a2cSjsg 	0x00009220, 0x00090008, 0xffffffff,
1187ccd5a2cSjsg 	0x00009294, 0x00000000, 0xffffffff
1197ccd5a2cSjsg };
1207ccd5a2cSjsg #endif
1217ccd5a2cSjsg 
1227ccd5a2cSjsg #ifndef TRINITY_SYSLS_SEQUENCE
1237ccd5a2cSjsg #define TRINITY_SYSLS_SEQUENCE  100
1247ccd5a2cSjsg 
1257ccd5a2cSjsg static const u32 trinity_sysls_disable[] =
1267ccd5a2cSjsg {
1277ccd5a2cSjsg 	/* Register, Value, Mask */
1287ccd5a2cSjsg 	0x0000d0c0, 0x00000000, 0xffffffff,
1297ccd5a2cSjsg 	0x0000d8c0, 0x00000000, 0xffffffff,
1307ccd5a2cSjsg 	0x000055e8, 0x00000000, 0xffffffff,
1317ccd5a2cSjsg 	0x0000d0bc, 0x00000000, 0xffffffff,
1327ccd5a2cSjsg 	0x0000d8bc, 0x00000000, 0xffffffff,
1337ccd5a2cSjsg 	0x000015c0, 0x00041401, 0xffffffff,
1347ccd5a2cSjsg 	0x0000264c, 0x00040400, 0xffffffff,
1357ccd5a2cSjsg 	0x00002648, 0x00040400, 0xffffffff,
1367ccd5a2cSjsg 	0x00002650, 0x00040400, 0xffffffff,
1377ccd5a2cSjsg 	0x000020b8, 0x00040400, 0xffffffff,
1387ccd5a2cSjsg 	0x000020bc, 0x00040400, 0xffffffff,
1397ccd5a2cSjsg 	0x000020c0, 0x00040c80, 0xffffffff,
1407ccd5a2cSjsg 	0x0000f4a0, 0x000000c0, 0xffffffff,
1417ccd5a2cSjsg 	0x0000f4a4, 0x00680000, 0xffffffff,
1427ccd5a2cSjsg 	0x00002f50, 0x00000404, 0xffffffff,
1437ccd5a2cSjsg 	0x000004c8, 0x00000001, 0xffffffff,
1447ccd5a2cSjsg 	0x0000641c, 0x00007ffd, 0xffffffff,
1457ccd5a2cSjsg 	0x00000c7c, 0x0000ff00, 0xffffffff,
1467ccd5a2cSjsg 	0x00006dfc, 0x0000007f, 0xffffffff
1477ccd5a2cSjsg };
1487ccd5a2cSjsg 
1497ccd5a2cSjsg static const u32 trinity_sysls_enable[] =
1507ccd5a2cSjsg {
1517ccd5a2cSjsg 	/* Register, Value, Mask */
1527ccd5a2cSjsg 	0x000055e8, 0x00000001, 0xffffffff,
1537ccd5a2cSjsg 	0x0000d0bc, 0x00000100, 0xffffffff,
1547ccd5a2cSjsg 	0x0000d8bc, 0x00000100, 0xffffffff,
1557ccd5a2cSjsg 	0x000015c0, 0x000c1401, 0xffffffff,
1567ccd5a2cSjsg 	0x0000264c, 0x000c0400, 0xffffffff,
1577ccd5a2cSjsg 	0x00002648, 0x000c0400, 0xffffffff,
1587ccd5a2cSjsg 	0x00002650, 0x000c0400, 0xffffffff,
1597ccd5a2cSjsg 	0x000020b8, 0x000c0400, 0xffffffff,
1607ccd5a2cSjsg 	0x000020bc, 0x000c0400, 0xffffffff,
1617ccd5a2cSjsg 	0x000020c0, 0x000c0c80, 0xffffffff,
1627ccd5a2cSjsg 	0x0000f4a0, 0x000000c0, 0xffffffff,
1637ccd5a2cSjsg 	0x0000f4a4, 0x00680fff, 0xffffffff,
1647ccd5a2cSjsg 	0x00002f50, 0x00000903, 0xffffffff,
1657ccd5a2cSjsg 	0x000004c8, 0x00000000, 0xffffffff,
1667ccd5a2cSjsg 	0x0000641c, 0x00000000, 0xffffffff,
1677ccd5a2cSjsg 	0x00000c7c, 0x00000000, 0xffffffff,
1687ccd5a2cSjsg 	0x00006dfc, 0x00000000, 0xffffffff
1697ccd5a2cSjsg };
1707ccd5a2cSjsg #endif
1717ccd5a2cSjsg 
1727ccd5a2cSjsg static const u32 trinity_override_mgpg_sequences[] =
1737ccd5a2cSjsg {
1747ccd5a2cSjsg 	/* Register, Value */
1757ccd5a2cSjsg 	0x00000200, 0xE030032C,
1767ccd5a2cSjsg 	0x00000204, 0x00000FFF,
1777ccd5a2cSjsg 	0x00000200, 0xE0300058,
1787ccd5a2cSjsg 	0x00000204, 0x00030301,
1797ccd5a2cSjsg 	0x00000200, 0xE0300054,
1807ccd5a2cSjsg 	0x00000204, 0x500010FF,
1817ccd5a2cSjsg 	0x00000200, 0xE0300074,
1827ccd5a2cSjsg 	0x00000204, 0x00030301,
1837ccd5a2cSjsg 	0x00000200, 0xE0300070,
1847ccd5a2cSjsg 	0x00000204, 0x500010FF,
1857ccd5a2cSjsg 	0x00000200, 0xE0300090,
1867ccd5a2cSjsg 	0x00000204, 0x00030301,
1877ccd5a2cSjsg 	0x00000200, 0xE030008C,
1887ccd5a2cSjsg 	0x00000204, 0x500010FF,
1897ccd5a2cSjsg 	0x00000200, 0xE03000AC,
1907ccd5a2cSjsg 	0x00000204, 0x00030301,
1917ccd5a2cSjsg 	0x00000200, 0xE03000A8,
1927ccd5a2cSjsg 	0x00000204, 0x500010FF,
1937ccd5a2cSjsg 	0x00000200, 0xE03000C8,
1947ccd5a2cSjsg 	0x00000204, 0x00030301,
1957ccd5a2cSjsg 	0x00000200, 0xE03000C4,
1967ccd5a2cSjsg 	0x00000204, 0x500010FF,
1977ccd5a2cSjsg 	0x00000200, 0xE03000E4,
1987ccd5a2cSjsg 	0x00000204, 0x00030301,
1997ccd5a2cSjsg 	0x00000200, 0xE03000E0,
2007ccd5a2cSjsg 	0x00000204, 0x500010FF,
2017ccd5a2cSjsg 	0x00000200, 0xE0300100,
2027ccd5a2cSjsg 	0x00000204, 0x00030301,
2037ccd5a2cSjsg 	0x00000200, 0xE03000FC,
2047ccd5a2cSjsg 	0x00000204, 0x500010FF,
2057ccd5a2cSjsg 	0x00000200, 0xE0300058,
2067ccd5a2cSjsg 	0x00000204, 0x00030303,
2077ccd5a2cSjsg 	0x00000200, 0xE0300054,
2087ccd5a2cSjsg 	0x00000204, 0x600010FF,
2097ccd5a2cSjsg 	0x00000200, 0xE0300074,
2107ccd5a2cSjsg 	0x00000204, 0x00030303,
2117ccd5a2cSjsg 	0x00000200, 0xE0300070,
2127ccd5a2cSjsg 	0x00000204, 0x600010FF,
2137ccd5a2cSjsg 	0x00000200, 0xE0300090,
2147ccd5a2cSjsg 	0x00000204, 0x00030303,
2157ccd5a2cSjsg 	0x00000200, 0xE030008C,
2167ccd5a2cSjsg 	0x00000204, 0x600010FF,
2177ccd5a2cSjsg 	0x00000200, 0xE03000AC,
2187ccd5a2cSjsg 	0x00000204, 0x00030303,
2197ccd5a2cSjsg 	0x00000200, 0xE03000A8,
2207ccd5a2cSjsg 	0x00000204, 0x600010FF,
2217ccd5a2cSjsg 	0x00000200, 0xE03000C8,
2227ccd5a2cSjsg 	0x00000204, 0x00030303,
2237ccd5a2cSjsg 	0x00000200, 0xE03000C4,
2247ccd5a2cSjsg 	0x00000204, 0x600010FF,
2257ccd5a2cSjsg 	0x00000200, 0xE03000E4,
2267ccd5a2cSjsg 	0x00000204, 0x00030303,
2277ccd5a2cSjsg 	0x00000200, 0xE03000E0,
2287ccd5a2cSjsg 	0x00000204, 0x600010FF,
2297ccd5a2cSjsg 	0x00000200, 0xE0300100,
2307ccd5a2cSjsg 	0x00000204, 0x00030303,
2317ccd5a2cSjsg 	0x00000200, 0xE03000FC,
2327ccd5a2cSjsg 	0x00000204, 0x600010FF,
2337ccd5a2cSjsg 	0x00000200, 0xE0300058,
2347ccd5a2cSjsg 	0x00000204, 0x00030303,
2357ccd5a2cSjsg 	0x00000200, 0xE0300054,
2367ccd5a2cSjsg 	0x00000204, 0x700010FF,
2377ccd5a2cSjsg 	0x00000200, 0xE0300074,
2387ccd5a2cSjsg 	0x00000204, 0x00030303,
2397ccd5a2cSjsg 	0x00000200, 0xE0300070,
2407ccd5a2cSjsg 	0x00000204, 0x700010FF,
2417ccd5a2cSjsg 	0x00000200, 0xE0300090,
2427ccd5a2cSjsg 	0x00000204, 0x00030303,
2437ccd5a2cSjsg 	0x00000200, 0xE030008C,
2447ccd5a2cSjsg 	0x00000204, 0x700010FF,
2457ccd5a2cSjsg 	0x00000200, 0xE03000AC,
2467ccd5a2cSjsg 	0x00000204, 0x00030303,
2477ccd5a2cSjsg 	0x00000200, 0xE03000A8,
2487ccd5a2cSjsg 	0x00000204, 0x700010FF,
2497ccd5a2cSjsg 	0x00000200, 0xE03000C8,
2507ccd5a2cSjsg 	0x00000204, 0x00030303,
2517ccd5a2cSjsg 	0x00000200, 0xE03000C4,
2527ccd5a2cSjsg 	0x00000204, 0x700010FF,
2537ccd5a2cSjsg 	0x00000200, 0xE03000E4,
2547ccd5a2cSjsg 	0x00000204, 0x00030303,
2557ccd5a2cSjsg 	0x00000200, 0xE03000E0,
2567ccd5a2cSjsg 	0x00000204, 0x700010FF,
2577ccd5a2cSjsg 	0x00000200, 0xE0300100,
2587ccd5a2cSjsg 	0x00000204, 0x00030303,
2597ccd5a2cSjsg 	0x00000200, 0xE03000FC,
2607ccd5a2cSjsg 	0x00000204, 0x700010FF,
2617ccd5a2cSjsg 	0x00000200, 0xE0300058,
2627ccd5a2cSjsg 	0x00000204, 0x00010303,
2637ccd5a2cSjsg 	0x00000200, 0xE0300054,
2647ccd5a2cSjsg 	0x00000204, 0x800010FF,
2657ccd5a2cSjsg 	0x00000200, 0xE0300074,
2667ccd5a2cSjsg 	0x00000204, 0x00010303,
2677ccd5a2cSjsg 	0x00000200, 0xE0300070,
2687ccd5a2cSjsg 	0x00000204, 0x800010FF,
2697ccd5a2cSjsg 	0x00000200, 0xE0300090,
2707ccd5a2cSjsg 	0x00000204, 0x00010303,
2717ccd5a2cSjsg 	0x00000200, 0xE030008C,
2727ccd5a2cSjsg 	0x00000204, 0x800010FF,
2737ccd5a2cSjsg 	0x00000200, 0xE03000AC,
2747ccd5a2cSjsg 	0x00000204, 0x00010303,
2757ccd5a2cSjsg 	0x00000200, 0xE03000A8,
2767ccd5a2cSjsg 	0x00000204, 0x800010FF,
2777ccd5a2cSjsg 	0x00000200, 0xE03000C4,
2787ccd5a2cSjsg 	0x00000204, 0x800010FF,
2797ccd5a2cSjsg 	0x00000200, 0xE03000C8,
2807ccd5a2cSjsg 	0x00000204, 0x00010303,
2817ccd5a2cSjsg 	0x00000200, 0xE03000E4,
2827ccd5a2cSjsg 	0x00000204, 0x00010303,
2837ccd5a2cSjsg 	0x00000200, 0xE03000E0,
2847ccd5a2cSjsg 	0x00000204, 0x800010FF,
2857ccd5a2cSjsg 	0x00000200, 0xE0300100,
2867ccd5a2cSjsg 	0x00000204, 0x00010303,
2877ccd5a2cSjsg 	0x00000200, 0xE03000FC,
2887ccd5a2cSjsg 	0x00000204, 0x800010FF,
2897ccd5a2cSjsg 	0x00000200, 0x0001f198,
2907ccd5a2cSjsg 	0x00000204, 0x0003ffff,
2917ccd5a2cSjsg 	0x00000200, 0x0001f19C,
2927ccd5a2cSjsg 	0x00000204, 0x3fffffff,
2937ccd5a2cSjsg 	0x00000200, 0xE030032C,
2947ccd5a2cSjsg 	0x00000204, 0x00000000,
2957ccd5a2cSjsg };
2967ccd5a2cSjsg 
2977ccd5a2cSjsg static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
2987ccd5a2cSjsg 						   const u32 *seq, u32 count);
2997ccd5a2cSjsg static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev);
3007ccd5a2cSjsg static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
3017ccd5a2cSjsg 					     struct radeon_ps *new_rps,
3027ccd5a2cSjsg 					     struct radeon_ps *old_rps);
3037ccd5a2cSjsg 
trinity_get_ps(struct radeon_ps * rps)3047ccd5a2cSjsg static struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
3057ccd5a2cSjsg {
3067ccd5a2cSjsg 	struct trinity_ps *ps = rps->ps_priv;
3077ccd5a2cSjsg 
3087ccd5a2cSjsg 	return ps;
3097ccd5a2cSjsg }
3107ccd5a2cSjsg 
trinity_get_pi(struct radeon_device * rdev)3117ccd5a2cSjsg static struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)
3127ccd5a2cSjsg {
3137ccd5a2cSjsg 	struct trinity_power_info *pi = rdev->pm.dpm.priv;
3147ccd5a2cSjsg 
3157ccd5a2cSjsg 	return pi;
3167ccd5a2cSjsg }
3177ccd5a2cSjsg 
trinity_gfx_powergating_initialize(struct radeon_device * rdev)3187ccd5a2cSjsg static void trinity_gfx_powergating_initialize(struct radeon_device *rdev)
3197ccd5a2cSjsg {
3207ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
3217ccd5a2cSjsg 	u32 p, u;
3227ccd5a2cSjsg 	u32 value;
3237ccd5a2cSjsg 	struct atom_clock_dividers dividers;
3247ccd5a2cSjsg 	u32 xclk = radeon_get_xclk(rdev);
3257ccd5a2cSjsg 	u32 sssd = 1;
3267ccd5a2cSjsg 	int ret;
3277ccd5a2cSjsg 	u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
3287ccd5a2cSjsg 
3297ccd5a2cSjsg 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
3307ccd5a2cSjsg 					     25000, false, &dividers);
3317ccd5a2cSjsg 	if (ret)
3327ccd5a2cSjsg 		return;
3337ccd5a2cSjsg 
3347ccd5a2cSjsg 	value = RREG32_SMC(GFX_POWER_GATING_CNTL);
3357ccd5a2cSjsg 	value &= ~(SSSD_MASK | PDS_DIV_MASK);
3367ccd5a2cSjsg 	if (sssd)
3377ccd5a2cSjsg 		value |= SSSD(1);
3387ccd5a2cSjsg 	value |= PDS_DIV(dividers.post_div);
3397ccd5a2cSjsg 	WREG32_SMC(GFX_POWER_GATING_CNTL, value);
3407ccd5a2cSjsg 
3417ccd5a2cSjsg 	r600_calculate_u_and_p(500, xclk, 16, &p, &u);
3427ccd5a2cSjsg 
3437ccd5a2cSjsg 	WREG32(CG_PG_CTRL, SP(p) | SU(u));
3447ccd5a2cSjsg 
3457ccd5a2cSjsg 	WREG32_P(CG_GIPOTS, CG_GIPOT(p), ~CG_GIPOT_MASK);
3467ccd5a2cSjsg 
3477ccd5a2cSjsg 	/* XXX double check hw_rev */
3487ccd5a2cSjsg 	if (pi->override_dynamic_mgpg && (hw_rev == 0))
3497ccd5a2cSjsg 		trinity_override_dynamic_mg_powergating(rdev);
3507ccd5a2cSjsg 
3517ccd5a2cSjsg }
3527ccd5a2cSjsg 
3537ccd5a2cSjsg #define CGCG_CGTT_LOCAL0_MASK       0xFFFF33FF
3547ccd5a2cSjsg #define CGCG_CGTT_LOCAL1_MASK       0xFFFB0FFE
3557ccd5a2cSjsg #define CGTS_SM_CTRL_REG_DISABLE    0x00600000
3567ccd5a2cSjsg #define CGTS_SM_CTRL_REG_ENABLE     0x96944200
3577ccd5a2cSjsg 
trinity_mg_clockgating_enable(struct radeon_device * rdev,bool enable)3587ccd5a2cSjsg static void trinity_mg_clockgating_enable(struct radeon_device *rdev,
3597ccd5a2cSjsg 					  bool enable)
3607ccd5a2cSjsg {
3617ccd5a2cSjsg 	u32 local0;
3627ccd5a2cSjsg 	u32 local1;
3637ccd5a2cSjsg 
3647ccd5a2cSjsg 	if (enable) {
3657ccd5a2cSjsg 		local0 = RREG32_CG(CG_CGTT_LOCAL_0);
3667ccd5a2cSjsg 		local1 = RREG32_CG(CG_CGTT_LOCAL_1);
3677ccd5a2cSjsg 
3687ccd5a2cSjsg 		WREG32_CG(CG_CGTT_LOCAL_0,
3697ccd5a2cSjsg 			  (0x00380000 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
3707ccd5a2cSjsg 		WREG32_CG(CG_CGTT_LOCAL_1,
3717ccd5a2cSjsg 			  (0x0E000000 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
3727ccd5a2cSjsg 
3737ccd5a2cSjsg 		WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_ENABLE);
3747ccd5a2cSjsg 	} else {
3757ccd5a2cSjsg 		WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_DISABLE);
3767ccd5a2cSjsg 
3777ccd5a2cSjsg 		local0 = RREG32_CG(CG_CGTT_LOCAL_0);
3787ccd5a2cSjsg 		local1 = RREG32_CG(CG_CGTT_LOCAL_1);
3797ccd5a2cSjsg 
3807ccd5a2cSjsg 		WREG32_CG(CG_CGTT_LOCAL_0,
3817ccd5a2cSjsg 			  CGCG_CGTT_LOCAL0_MASK | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
3827ccd5a2cSjsg 		WREG32_CG(CG_CGTT_LOCAL_1,
3837ccd5a2cSjsg 			  CGCG_CGTT_LOCAL1_MASK | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
3847ccd5a2cSjsg 	}
3857ccd5a2cSjsg }
3867ccd5a2cSjsg 
trinity_mg_clockgating_initialize(struct radeon_device * rdev)3877ccd5a2cSjsg static void trinity_mg_clockgating_initialize(struct radeon_device *rdev)
3887ccd5a2cSjsg {
3897ccd5a2cSjsg 	u32 count;
3907ccd5a2cSjsg 	const u32 *seq = NULL;
3917ccd5a2cSjsg 
3927ccd5a2cSjsg 	seq = &trinity_mgcg_shls_default[0];
3937ccd5a2cSjsg 	count = sizeof(trinity_mgcg_shls_default) / (3 * sizeof(u32));
3947ccd5a2cSjsg 
3957ccd5a2cSjsg 	trinity_program_clk_gating_hw_sequence(rdev, seq, count);
3967ccd5a2cSjsg }
3977ccd5a2cSjsg 
trinity_gfx_clockgating_enable(struct radeon_device * rdev,bool enable)3987ccd5a2cSjsg static void trinity_gfx_clockgating_enable(struct radeon_device *rdev,
3997ccd5a2cSjsg 					   bool enable)
4007ccd5a2cSjsg {
4017ccd5a2cSjsg 	if (enable) {
4027ccd5a2cSjsg 		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
4037ccd5a2cSjsg 	} else {
4047ccd5a2cSjsg 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
4057ccd5a2cSjsg 		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
4067ccd5a2cSjsg 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
4077ccd5a2cSjsg 		RREG32(GB_ADDR_CONFIG);
4087ccd5a2cSjsg 	}
4097ccd5a2cSjsg }
4107ccd5a2cSjsg 
trinity_program_clk_gating_hw_sequence(struct radeon_device * rdev,const u32 * seq,u32 count)4117ccd5a2cSjsg static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
4127ccd5a2cSjsg 						   const u32 *seq, u32 count)
4137ccd5a2cSjsg {
4147ccd5a2cSjsg 	u32 i, length = count * 3;
4157ccd5a2cSjsg 
4167ccd5a2cSjsg 	for (i = 0; i < length; i += 3)
4177ccd5a2cSjsg 		WREG32_P(seq[i], seq[i+1], ~seq[i+2]);
4187ccd5a2cSjsg }
4197ccd5a2cSjsg 
trinity_program_override_mgpg_sequences(struct radeon_device * rdev,const u32 * seq,u32 count)4207ccd5a2cSjsg static void trinity_program_override_mgpg_sequences(struct radeon_device *rdev,
4217ccd5a2cSjsg 						    const u32 *seq, u32 count)
4227ccd5a2cSjsg {
4237ccd5a2cSjsg 	u32  i, length = count * 2;
4247ccd5a2cSjsg 
4257ccd5a2cSjsg 	for (i = 0; i < length; i += 2)
4267ccd5a2cSjsg 		WREG32(seq[i], seq[i+1]);
4277ccd5a2cSjsg 
4287ccd5a2cSjsg }
4297ccd5a2cSjsg 
trinity_override_dynamic_mg_powergating(struct radeon_device * rdev)4307ccd5a2cSjsg static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev)
4317ccd5a2cSjsg {
4327ccd5a2cSjsg 	u32 count;
4337ccd5a2cSjsg 	const u32 *seq = NULL;
4347ccd5a2cSjsg 
4357ccd5a2cSjsg 	seq = &trinity_override_mgpg_sequences[0];
4367ccd5a2cSjsg 	count = sizeof(trinity_override_mgpg_sequences) / (2 * sizeof(u32));
4377ccd5a2cSjsg 
4387ccd5a2cSjsg 	trinity_program_override_mgpg_sequences(rdev, seq, count);
4397ccd5a2cSjsg }
4407ccd5a2cSjsg 
trinity_ls_clockgating_enable(struct radeon_device * rdev,bool enable)4417ccd5a2cSjsg static void trinity_ls_clockgating_enable(struct radeon_device *rdev,
4427ccd5a2cSjsg 					  bool enable)
4437ccd5a2cSjsg {
4447ccd5a2cSjsg 	u32 count;
4457ccd5a2cSjsg 	const u32 *seq = NULL;
4467ccd5a2cSjsg 
4477ccd5a2cSjsg 	if (enable) {
4487ccd5a2cSjsg 		seq = &trinity_sysls_enable[0];
4497ccd5a2cSjsg 		count = sizeof(trinity_sysls_enable) / (3 * sizeof(u32));
4507ccd5a2cSjsg 	} else {
4517ccd5a2cSjsg 		seq = &trinity_sysls_disable[0];
4527ccd5a2cSjsg 		count = sizeof(trinity_sysls_disable) / (3 * sizeof(u32));
4537ccd5a2cSjsg 	}
4547ccd5a2cSjsg 
4557ccd5a2cSjsg 	trinity_program_clk_gating_hw_sequence(rdev, seq, count);
4567ccd5a2cSjsg }
4577ccd5a2cSjsg 
trinity_gfx_powergating_enable(struct radeon_device * rdev,bool enable)4587ccd5a2cSjsg static void trinity_gfx_powergating_enable(struct radeon_device *rdev,
4597ccd5a2cSjsg 					   bool enable)
4607ccd5a2cSjsg {
4617ccd5a2cSjsg 	if (enable) {
4627ccd5a2cSjsg 		if (RREG32_SMC(CC_SMU_TST_EFUSE1_MISC) & RB_BACKEND_DISABLE_MASK)
4637ccd5a2cSjsg 			WREG32_SMC(SMU_SCRATCH_A, (RREG32_SMC(SMU_SCRATCH_A) | 0x01));
4647ccd5a2cSjsg 
4657ccd5a2cSjsg 		WREG32_P(SCLK_PWRMGT_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
4667ccd5a2cSjsg 	} else {
4677ccd5a2cSjsg 		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_PWR_DOWN_EN);
4687ccd5a2cSjsg 		RREG32(GB_ADDR_CONFIG);
4697ccd5a2cSjsg 	}
4707ccd5a2cSjsg }
4717ccd5a2cSjsg 
trinity_gfx_dynamic_mgpg_enable(struct radeon_device * rdev,bool enable)4727ccd5a2cSjsg static void trinity_gfx_dynamic_mgpg_enable(struct radeon_device *rdev,
4737ccd5a2cSjsg 					    bool enable)
4747ccd5a2cSjsg {
4757ccd5a2cSjsg 	u32 value;
4767ccd5a2cSjsg 
4777ccd5a2cSjsg 	if (enable) {
4787ccd5a2cSjsg 		value = RREG32_SMC(PM_I_CNTL_1);
4797ccd5a2cSjsg 		value &= ~DS_PG_CNTL_MASK;
4807ccd5a2cSjsg 		value |= DS_PG_CNTL(1);
4817ccd5a2cSjsg 		WREG32_SMC(PM_I_CNTL_1, value);
4827ccd5a2cSjsg 
4837ccd5a2cSjsg 		value = RREG32_SMC(SMU_S_PG_CNTL);
4847ccd5a2cSjsg 		value &= ~DS_PG_EN_MASK;
4857ccd5a2cSjsg 		value |= DS_PG_EN(1);
4867ccd5a2cSjsg 		WREG32_SMC(SMU_S_PG_CNTL, value);
4877ccd5a2cSjsg 	} else {
4887ccd5a2cSjsg 		value = RREG32_SMC(SMU_S_PG_CNTL);
4897ccd5a2cSjsg 		value &= ~DS_PG_EN_MASK;
4907ccd5a2cSjsg 		WREG32_SMC(SMU_S_PG_CNTL, value);
4917ccd5a2cSjsg 
4927ccd5a2cSjsg 		value = RREG32_SMC(PM_I_CNTL_1);
4937ccd5a2cSjsg 		value &= ~DS_PG_CNTL_MASK;
4947ccd5a2cSjsg 		WREG32_SMC(PM_I_CNTL_1, value);
4957ccd5a2cSjsg 	}
4967ccd5a2cSjsg 
4977ccd5a2cSjsg 	trinity_gfx_dynamic_mgpg_config(rdev);
4987ccd5a2cSjsg 
4997ccd5a2cSjsg }
5007ccd5a2cSjsg 
trinity_enable_clock_power_gating(struct radeon_device * rdev)5017ccd5a2cSjsg static void trinity_enable_clock_power_gating(struct radeon_device *rdev)
5027ccd5a2cSjsg {
5037ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
5047ccd5a2cSjsg 
5057ccd5a2cSjsg 	if (pi->enable_gfx_clock_gating)
5067ccd5a2cSjsg 		sumo_gfx_clockgating_initialize(rdev);
5077ccd5a2cSjsg 	if (pi->enable_mg_clock_gating)
5087ccd5a2cSjsg 		trinity_mg_clockgating_initialize(rdev);
5097ccd5a2cSjsg 	if (pi->enable_gfx_power_gating)
5107ccd5a2cSjsg 		trinity_gfx_powergating_initialize(rdev);
5117ccd5a2cSjsg 	if (pi->enable_mg_clock_gating) {
5127ccd5a2cSjsg 		trinity_ls_clockgating_enable(rdev, true);
5137ccd5a2cSjsg 		trinity_mg_clockgating_enable(rdev, true);
5147ccd5a2cSjsg 	}
5157ccd5a2cSjsg 	if (pi->enable_gfx_clock_gating)
5167ccd5a2cSjsg 		trinity_gfx_clockgating_enable(rdev, true);
5177ccd5a2cSjsg 	if (pi->enable_gfx_dynamic_mgpg)
5187ccd5a2cSjsg 		trinity_gfx_dynamic_mgpg_enable(rdev, true);
5197ccd5a2cSjsg 	if (pi->enable_gfx_power_gating)
5207ccd5a2cSjsg 		trinity_gfx_powergating_enable(rdev, true);
5217ccd5a2cSjsg }
5227ccd5a2cSjsg 
trinity_disable_clock_power_gating(struct radeon_device * rdev)5237ccd5a2cSjsg static void trinity_disable_clock_power_gating(struct radeon_device *rdev)
5247ccd5a2cSjsg {
5257ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
5267ccd5a2cSjsg 
5277ccd5a2cSjsg 	if (pi->enable_gfx_power_gating)
5287ccd5a2cSjsg 		trinity_gfx_powergating_enable(rdev, false);
5297ccd5a2cSjsg 	if (pi->enable_gfx_dynamic_mgpg)
5307ccd5a2cSjsg 		trinity_gfx_dynamic_mgpg_enable(rdev, false);
5317ccd5a2cSjsg 	if (pi->enable_gfx_clock_gating)
5327ccd5a2cSjsg 		trinity_gfx_clockgating_enable(rdev, false);
5337ccd5a2cSjsg 	if (pi->enable_mg_clock_gating) {
5347ccd5a2cSjsg 		trinity_mg_clockgating_enable(rdev, false);
5357ccd5a2cSjsg 		trinity_ls_clockgating_enable(rdev, false);
5367ccd5a2cSjsg 	}
5377ccd5a2cSjsg }
5387ccd5a2cSjsg 
trinity_set_divider_value(struct radeon_device * rdev,u32 index,u32 sclk)5397ccd5a2cSjsg static void trinity_set_divider_value(struct radeon_device *rdev,
5407ccd5a2cSjsg 				      u32 index, u32 sclk)
5417ccd5a2cSjsg {
5427ccd5a2cSjsg 	struct atom_clock_dividers  dividers;
5437ccd5a2cSjsg 	int ret;
5447ccd5a2cSjsg 	u32 value;
5457ccd5a2cSjsg 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
5467ccd5a2cSjsg 
5477ccd5a2cSjsg 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
5487ccd5a2cSjsg 					     sclk, false, &dividers);
5497ccd5a2cSjsg 	if (ret)
5507ccd5a2cSjsg 		return;
5517ccd5a2cSjsg 
5527ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
5537ccd5a2cSjsg 	value &= ~CLK_DIVIDER_MASK;
5547ccd5a2cSjsg 	value |= CLK_DIVIDER(dividers.post_div);
5557ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
5567ccd5a2cSjsg 
5577ccd5a2cSjsg 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
5587ccd5a2cSjsg 					     sclk/2, false, &dividers);
5597ccd5a2cSjsg 	if (ret)
5607ccd5a2cSjsg 		return;
5617ccd5a2cSjsg 
5627ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix);
5637ccd5a2cSjsg 	value &= ~PD_SCLK_DIVIDER_MASK;
5647ccd5a2cSjsg 	value |= PD_SCLK_DIVIDER(dividers.post_div);
5657ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix, value);
5667ccd5a2cSjsg }
5677ccd5a2cSjsg 
trinity_set_ds_dividers(struct radeon_device * rdev,u32 index,u32 divider)5687ccd5a2cSjsg static void trinity_set_ds_dividers(struct radeon_device *rdev,
5697ccd5a2cSjsg 				    u32 index, u32 divider)
5707ccd5a2cSjsg {
5717ccd5a2cSjsg 	u32 value;
5727ccd5a2cSjsg 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
5737ccd5a2cSjsg 
5747ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
5757ccd5a2cSjsg 	value &= ~DS_DIV_MASK;
5767ccd5a2cSjsg 	value |= DS_DIV(divider);
5777ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
5787ccd5a2cSjsg }
5797ccd5a2cSjsg 
trinity_set_ss_dividers(struct radeon_device * rdev,u32 index,u32 divider)5807ccd5a2cSjsg static void trinity_set_ss_dividers(struct radeon_device *rdev,
5817ccd5a2cSjsg 				    u32 index, u32 divider)
5827ccd5a2cSjsg {
5837ccd5a2cSjsg 	u32 value;
5847ccd5a2cSjsg 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
5857ccd5a2cSjsg 
5867ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
5877ccd5a2cSjsg 	value &= ~DS_SH_DIV_MASK;
5887ccd5a2cSjsg 	value |= DS_SH_DIV(divider);
5897ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
5907ccd5a2cSjsg }
5917ccd5a2cSjsg 
trinity_set_vid(struct radeon_device * rdev,u32 index,u32 vid)5927ccd5a2cSjsg static void trinity_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
5937ccd5a2cSjsg {
5947ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
5957ccd5a2cSjsg 	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid);
5967ccd5a2cSjsg 	u32 value;
5977ccd5a2cSjsg 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
5987ccd5a2cSjsg 
5997ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
6007ccd5a2cSjsg 	value &= ~VID_MASK;
6017ccd5a2cSjsg 	value |= VID(vid_7bit);
6027ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
6037ccd5a2cSjsg 
6047ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
6057ccd5a2cSjsg 	value &= ~LVRT_MASK;
6067ccd5a2cSjsg 	value |= LVRT(0);
6077ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
6087ccd5a2cSjsg }
6097ccd5a2cSjsg 
trinity_set_allos_gnb_slow(struct radeon_device * rdev,u32 index,u32 gnb_slow)6107ccd5a2cSjsg static void trinity_set_allos_gnb_slow(struct radeon_device *rdev,
6117ccd5a2cSjsg 				       u32 index, u32 gnb_slow)
6127ccd5a2cSjsg {
6137ccd5a2cSjsg 	u32 value;
6147ccd5a2cSjsg 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
6157ccd5a2cSjsg 
6167ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
6177ccd5a2cSjsg 	value &= ~GNB_SLOW_MASK;
6187ccd5a2cSjsg 	value |= GNB_SLOW(gnb_slow);
6197ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
6207ccd5a2cSjsg }
6217ccd5a2cSjsg 
trinity_set_force_nbp_state(struct radeon_device * rdev,u32 index,u32 force_nbp_state)6227ccd5a2cSjsg static void trinity_set_force_nbp_state(struct radeon_device *rdev,
6237ccd5a2cSjsg 					u32 index, u32 force_nbp_state)
6247ccd5a2cSjsg {
6257ccd5a2cSjsg 	u32 value;
6267ccd5a2cSjsg 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
6277ccd5a2cSjsg 
6287ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
6297ccd5a2cSjsg 	value &= ~FORCE_NBPS1_MASK;
6307ccd5a2cSjsg 	value |= FORCE_NBPS1(force_nbp_state);
6317ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
6327ccd5a2cSjsg }
6337ccd5a2cSjsg 
trinity_set_display_wm(struct radeon_device * rdev,u32 index,u32 wm)6347ccd5a2cSjsg static void trinity_set_display_wm(struct radeon_device *rdev,
6357ccd5a2cSjsg 				   u32 index, u32 wm)
6367ccd5a2cSjsg {
6377ccd5a2cSjsg 	u32 value;
6387ccd5a2cSjsg 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
6397ccd5a2cSjsg 
6407ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
6417ccd5a2cSjsg 	value &= ~DISPLAY_WM_MASK;
6427ccd5a2cSjsg 	value |= DISPLAY_WM(wm);
6437ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
6447ccd5a2cSjsg }
6457ccd5a2cSjsg 
trinity_set_vce_wm(struct radeon_device * rdev,u32 index,u32 wm)6467ccd5a2cSjsg static void trinity_set_vce_wm(struct radeon_device *rdev,
6477ccd5a2cSjsg 			       u32 index, u32 wm)
6487ccd5a2cSjsg {
6497ccd5a2cSjsg 	u32 value;
6507ccd5a2cSjsg 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
6517ccd5a2cSjsg 
6527ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
6537ccd5a2cSjsg 	value &= ~VCE_WM_MASK;
6547ccd5a2cSjsg 	value |= VCE_WM(wm);
6557ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
6567ccd5a2cSjsg }
6577ccd5a2cSjsg 
trinity_set_at(struct radeon_device * rdev,u32 index,u32 at)6587ccd5a2cSjsg static void trinity_set_at(struct radeon_device *rdev,
6597ccd5a2cSjsg 			   u32 index, u32 at)
6607ccd5a2cSjsg {
6617ccd5a2cSjsg 	u32 value;
6627ccd5a2cSjsg 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
6637ccd5a2cSjsg 
6647ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix);
6657ccd5a2cSjsg 	value &= ~AT_MASK;
6667ccd5a2cSjsg 	value |= AT(at);
6677ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix, value);
6687ccd5a2cSjsg }
6697ccd5a2cSjsg 
trinity_program_power_level(struct radeon_device * rdev,struct trinity_pl * pl,u32 index)6707ccd5a2cSjsg static void trinity_program_power_level(struct radeon_device *rdev,
6717ccd5a2cSjsg 					struct trinity_pl *pl, u32 index)
6727ccd5a2cSjsg {
6737ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
6747ccd5a2cSjsg 
6757ccd5a2cSjsg 	if (index >= SUMO_MAX_HARDWARE_POWERLEVELS)
6767ccd5a2cSjsg 		return;
6777ccd5a2cSjsg 
6787ccd5a2cSjsg 	trinity_set_divider_value(rdev, index, pl->sclk);
6797ccd5a2cSjsg 	trinity_set_vid(rdev, index, pl->vddc_index);
6807ccd5a2cSjsg 	trinity_set_ss_dividers(rdev, index, pl->ss_divider_index);
6817ccd5a2cSjsg 	trinity_set_ds_dividers(rdev, index, pl->ds_divider_index);
6827ccd5a2cSjsg 	trinity_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
6837ccd5a2cSjsg 	trinity_set_force_nbp_state(rdev, index, pl->force_nbp_state);
6847ccd5a2cSjsg 	trinity_set_display_wm(rdev, index, pl->display_wm);
6857ccd5a2cSjsg 	trinity_set_vce_wm(rdev, index, pl->vce_wm);
6867ccd5a2cSjsg 	trinity_set_at(rdev, index, pi->at[index]);
6877ccd5a2cSjsg }
6887ccd5a2cSjsg 
trinity_power_level_enable_disable(struct radeon_device * rdev,u32 index,bool enable)6897ccd5a2cSjsg static void trinity_power_level_enable_disable(struct radeon_device *rdev,
6907ccd5a2cSjsg 					       u32 index, bool enable)
6917ccd5a2cSjsg {
6927ccd5a2cSjsg 	u32 value;
6937ccd5a2cSjsg 	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
6947ccd5a2cSjsg 
6957ccd5a2cSjsg 	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
6967ccd5a2cSjsg 	value &= ~STATE_VALID_MASK;
6977ccd5a2cSjsg 	if (enable)
6987ccd5a2cSjsg 		value |= STATE_VALID(1);
6997ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
7007ccd5a2cSjsg }
7017ccd5a2cSjsg 
trinity_dpm_enabled(struct radeon_device * rdev)7027ccd5a2cSjsg static bool trinity_dpm_enabled(struct radeon_device *rdev)
7037ccd5a2cSjsg {
7047ccd5a2cSjsg 	if (RREG32_SMC(SMU_SCLK_DPM_CNTL) & SCLK_DPM_EN(1))
7057ccd5a2cSjsg 		return true;
7067ccd5a2cSjsg 	else
7077ccd5a2cSjsg 		return false;
7087ccd5a2cSjsg }
7097ccd5a2cSjsg 
trinity_start_dpm(struct radeon_device * rdev)7107ccd5a2cSjsg static void trinity_start_dpm(struct radeon_device *rdev)
7117ccd5a2cSjsg {
7127ccd5a2cSjsg 	u32 value = RREG32_SMC(SMU_SCLK_DPM_CNTL);
7137ccd5a2cSjsg 
7147ccd5a2cSjsg 	value &= ~(SCLK_DPM_EN_MASK | SCLK_DPM_BOOT_STATE_MASK | VOLTAGE_CHG_EN_MASK);
7157ccd5a2cSjsg 	value |= SCLK_DPM_EN(1) | SCLK_DPM_BOOT_STATE(0) | VOLTAGE_CHG_EN(1);
7167ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_CNTL, value);
7177ccd5a2cSjsg 
7187ccd5a2cSjsg 	WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
7197ccd5a2cSjsg 	WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~EN);
7207ccd5a2cSjsg 
7217ccd5a2cSjsg 	trinity_dpm_config(rdev, true);
7227ccd5a2cSjsg }
7237ccd5a2cSjsg 
trinity_wait_for_dpm_enabled(struct radeon_device * rdev)7247ccd5a2cSjsg static void trinity_wait_for_dpm_enabled(struct radeon_device *rdev)
7257ccd5a2cSjsg {
7267ccd5a2cSjsg 	int i;
7277ccd5a2cSjsg 
7287ccd5a2cSjsg 	for (i = 0; i < rdev->usec_timeout; i++) {
7297ccd5a2cSjsg 		if (RREG32(SCLK_PWRMGT_CNTL) & DYNAMIC_PM_EN)
7307ccd5a2cSjsg 			break;
7317ccd5a2cSjsg 		udelay(1);
7327ccd5a2cSjsg 	}
7337ccd5a2cSjsg 	for (i = 0; i < rdev->usec_timeout; i++) {
7347ccd5a2cSjsg 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_STATE_MASK) == 0)
7357ccd5a2cSjsg 			break;
7367ccd5a2cSjsg 		udelay(1);
7377ccd5a2cSjsg 	}
7387ccd5a2cSjsg 	for (i = 0; i < rdev->usec_timeout; i++) {
7397ccd5a2cSjsg 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
7407ccd5a2cSjsg 			break;
7417ccd5a2cSjsg 		udelay(1);
7427ccd5a2cSjsg 	}
7437ccd5a2cSjsg }
7447ccd5a2cSjsg 
trinity_stop_dpm(struct radeon_device * rdev)7457ccd5a2cSjsg static void trinity_stop_dpm(struct radeon_device *rdev)
7467ccd5a2cSjsg {
7477ccd5a2cSjsg 	u32 sclk_dpm_cntl;
7487ccd5a2cSjsg 
7497ccd5a2cSjsg 	WREG32_P(CG_CG_VOLTAGE_CNTL, EN, ~EN);
7507ccd5a2cSjsg 
7517ccd5a2cSjsg 	sclk_dpm_cntl = RREG32_SMC(SMU_SCLK_DPM_CNTL);
7527ccd5a2cSjsg 	sclk_dpm_cntl &= ~(SCLK_DPM_EN_MASK | VOLTAGE_CHG_EN_MASK);
7537ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_CNTL, sclk_dpm_cntl);
7547ccd5a2cSjsg 
7557ccd5a2cSjsg 	trinity_dpm_config(rdev, false);
7567ccd5a2cSjsg }
7577ccd5a2cSjsg 
trinity_start_am(struct radeon_device * rdev)7587ccd5a2cSjsg static void trinity_start_am(struct radeon_device *rdev)
7597ccd5a2cSjsg {
7607ccd5a2cSjsg 	WREG32_P(SCLK_PWRMGT_CNTL, 0, ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
7617ccd5a2cSjsg }
7627ccd5a2cSjsg 
trinity_reset_am(struct radeon_device * rdev)7637ccd5a2cSjsg static void trinity_reset_am(struct radeon_device *rdev)
7647ccd5a2cSjsg {
7657ccd5a2cSjsg 	WREG32_P(SCLK_PWRMGT_CNTL, RESET_SCLK_CNT | RESET_BUSY_CNT,
7667ccd5a2cSjsg 		 ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
7677ccd5a2cSjsg }
7687ccd5a2cSjsg 
trinity_wait_for_level_0(struct radeon_device * rdev)7697ccd5a2cSjsg static void trinity_wait_for_level_0(struct radeon_device *rdev)
7707ccd5a2cSjsg {
7717ccd5a2cSjsg 	int i;
7727ccd5a2cSjsg 
7737ccd5a2cSjsg 	for (i = 0; i < rdev->usec_timeout; i++) {
7747ccd5a2cSjsg 		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
7757ccd5a2cSjsg 			break;
7767ccd5a2cSjsg 		udelay(1);
7777ccd5a2cSjsg 	}
7787ccd5a2cSjsg }
7797ccd5a2cSjsg 
trinity_enable_power_level_0(struct radeon_device * rdev)7807ccd5a2cSjsg static void trinity_enable_power_level_0(struct radeon_device *rdev)
7817ccd5a2cSjsg {
7827ccd5a2cSjsg 	trinity_power_level_enable_disable(rdev, 0, true);
7837ccd5a2cSjsg }
7847ccd5a2cSjsg 
trinity_force_level_0(struct radeon_device * rdev)7857ccd5a2cSjsg static void trinity_force_level_0(struct radeon_device *rdev)
7867ccd5a2cSjsg {
7877ccd5a2cSjsg 	trinity_dpm_force_state(rdev, 0);
7887ccd5a2cSjsg }
7897ccd5a2cSjsg 
trinity_unforce_levels(struct radeon_device * rdev)7907ccd5a2cSjsg static void trinity_unforce_levels(struct radeon_device *rdev)
7917ccd5a2cSjsg {
7927ccd5a2cSjsg 	trinity_dpm_no_forced_level(rdev);
7937ccd5a2cSjsg }
7947ccd5a2cSjsg 
trinity_program_power_levels_0_to_n(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)7957ccd5a2cSjsg static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev,
7967ccd5a2cSjsg 						struct radeon_ps *new_rps,
7977ccd5a2cSjsg 						struct radeon_ps *old_rps)
7987ccd5a2cSjsg {
7997ccd5a2cSjsg 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
8007ccd5a2cSjsg 	struct trinity_ps *old_ps = trinity_get_ps(old_rps);
8017ccd5a2cSjsg 	u32 i;
8027ccd5a2cSjsg 	u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
8037ccd5a2cSjsg 
8047ccd5a2cSjsg 	for (i = 0; i < new_ps->num_levels; i++) {
8057ccd5a2cSjsg 		trinity_program_power_level(rdev, &new_ps->levels[i], i);
8067ccd5a2cSjsg 		trinity_power_level_enable_disable(rdev, i, true);
8077ccd5a2cSjsg 	}
8087ccd5a2cSjsg 
8097ccd5a2cSjsg 	for (i = new_ps->num_levels; i < n_current_state_levels; i++)
8107ccd5a2cSjsg 		trinity_power_level_enable_disable(rdev, i, false);
8117ccd5a2cSjsg }
8127ccd5a2cSjsg 
trinity_program_bootup_state(struct radeon_device * rdev)8137ccd5a2cSjsg static void trinity_program_bootup_state(struct radeon_device *rdev)
8147ccd5a2cSjsg {
8157ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
8167ccd5a2cSjsg 	u32 i;
8177ccd5a2cSjsg 
8187ccd5a2cSjsg 	trinity_program_power_level(rdev, &pi->boot_pl, 0);
8197ccd5a2cSjsg 	trinity_power_level_enable_disable(rdev, 0, true);
8207ccd5a2cSjsg 
8217ccd5a2cSjsg 	for (i = 1; i < 8; i++)
8227ccd5a2cSjsg 		trinity_power_level_enable_disable(rdev, i, false);
8237ccd5a2cSjsg }
8247ccd5a2cSjsg 
trinity_setup_uvd_clock_table(struct radeon_device * rdev,struct radeon_ps * rps)8257ccd5a2cSjsg static void trinity_setup_uvd_clock_table(struct radeon_device *rdev,
8267ccd5a2cSjsg 					  struct radeon_ps *rps)
8277ccd5a2cSjsg {
8287ccd5a2cSjsg 	struct trinity_ps *ps = trinity_get_ps(rps);
8297ccd5a2cSjsg 	u32 uvdstates = (ps->vclk_low_divider |
8307ccd5a2cSjsg 			 ps->vclk_high_divider << 8 |
8317ccd5a2cSjsg 			 ps->dclk_low_divider << 16 |
8327ccd5a2cSjsg 			 ps->dclk_high_divider << 24);
8337ccd5a2cSjsg 
8347ccd5a2cSjsg 	WREG32_SMC(SMU_UVD_DPM_STATES, uvdstates);
8357ccd5a2cSjsg }
8367ccd5a2cSjsg 
trinity_setup_uvd_dpm_interval(struct radeon_device * rdev,u32 interval)8377ccd5a2cSjsg static void trinity_setup_uvd_dpm_interval(struct radeon_device *rdev,
8387ccd5a2cSjsg 					   u32 interval)
8397ccd5a2cSjsg {
8407ccd5a2cSjsg 	u32 p, u;
8417ccd5a2cSjsg 	u32 tp = RREG32_SMC(PM_TP);
8427ccd5a2cSjsg 	u32 val;
8437ccd5a2cSjsg 	u32 xclk = radeon_get_xclk(rdev);
8447ccd5a2cSjsg 
8457ccd5a2cSjsg 	r600_calculate_u_and_p(interval, xclk, 16, &p, &u);
8467ccd5a2cSjsg 
8477ccd5a2cSjsg 	val = (p + tp - 1) / tp;
8487ccd5a2cSjsg 
8497ccd5a2cSjsg 	WREG32_SMC(SMU_UVD_DPM_CNTL, val);
8507ccd5a2cSjsg }
8517ccd5a2cSjsg 
trinity_uvd_clocks_zero(struct radeon_ps * rps)8527ccd5a2cSjsg static bool trinity_uvd_clocks_zero(struct radeon_ps *rps)
8537ccd5a2cSjsg {
8547ccd5a2cSjsg 	if ((rps->vclk == 0) && (rps->dclk == 0))
8557ccd5a2cSjsg 		return true;
8567ccd5a2cSjsg 	else
8577ccd5a2cSjsg 		return false;
8587ccd5a2cSjsg }
8597ccd5a2cSjsg 
trinity_uvd_clocks_equal(struct radeon_ps * rps1,struct radeon_ps * rps2)8607ccd5a2cSjsg static bool trinity_uvd_clocks_equal(struct radeon_ps *rps1,
8617ccd5a2cSjsg 				     struct radeon_ps *rps2)
8627ccd5a2cSjsg {
8637ccd5a2cSjsg 	struct trinity_ps *ps1 = trinity_get_ps(rps1);
8647ccd5a2cSjsg 	struct trinity_ps *ps2 = trinity_get_ps(rps2);
8657ccd5a2cSjsg 
8667ccd5a2cSjsg 	if ((rps1->vclk == rps2->vclk) &&
8677ccd5a2cSjsg 	    (rps1->dclk == rps2->dclk) &&
8687ccd5a2cSjsg 	    (ps1->vclk_low_divider == ps2->vclk_low_divider) &&
8697ccd5a2cSjsg 	    (ps1->vclk_high_divider == ps2->vclk_high_divider) &&
8707ccd5a2cSjsg 	    (ps1->dclk_low_divider == ps2->dclk_low_divider) &&
8717ccd5a2cSjsg 	    (ps1->dclk_high_divider == ps2->dclk_high_divider))
8727ccd5a2cSjsg 		return true;
8737ccd5a2cSjsg 	else
8747ccd5a2cSjsg 		return false;
8757ccd5a2cSjsg }
8767ccd5a2cSjsg 
trinity_setup_uvd_clocks(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)8777ccd5a2cSjsg static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
8787ccd5a2cSjsg 				     struct radeon_ps *new_rps,
8797ccd5a2cSjsg 				     struct radeon_ps *old_rps)
8807ccd5a2cSjsg {
8817ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
8827ccd5a2cSjsg 
8837ccd5a2cSjsg 	if (pi->enable_gfx_power_gating) {
8847ccd5a2cSjsg 		trinity_gfx_powergating_enable(rdev, false);
8857ccd5a2cSjsg 	}
8867ccd5a2cSjsg 
8877ccd5a2cSjsg 	if (pi->uvd_dpm) {
8887ccd5a2cSjsg 		if (trinity_uvd_clocks_zero(new_rps) &&
8897ccd5a2cSjsg 		    !trinity_uvd_clocks_zero(old_rps)) {
8907ccd5a2cSjsg 			trinity_setup_uvd_dpm_interval(rdev, 0);
8917ccd5a2cSjsg 		} else if (!trinity_uvd_clocks_zero(new_rps)) {
8927ccd5a2cSjsg 			trinity_setup_uvd_clock_table(rdev, new_rps);
8937ccd5a2cSjsg 
8947ccd5a2cSjsg 			if (trinity_uvd_clocks_zero(old_rps)) {
8957ccd5a2cSjsg 				u32 tmp = RREG32(CG_MISC_REG);
8967ccd5a2cSjsg 				tmp &= 0xfffffffd;
8977ccd5a2cSjsg 				WREG32(CG_MISC_REG, tmp);
8987ccd5a2cSjsg 
8997ccd5a2cSjsg 				radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
9007ccd5a2cSjsg 
9017ccd5a2cSjsg 				trinity_setup_uvd_dpm_interval(rdev, 3000);
9027ccd5a2cSjsg 			}
9037ccd5a2cSjsg 		}
9047ccd5a2cSjsg 		trinity_uvd_dpm_config(rdev);
9057ccd5a2cSjsg 	} else {
9067ccd5a2cSjsg 		if (trinity_uvd_clocks_zero(new_rps) ||
9077ccd5a2cSjsg 		    trinity_uvd_clocks_equal(new_rps, old_rps))
9087ccd5a2cSjsg 			return;
9097ccd5a2cSjsg 
9107ccd5a2cSjsg 		radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
9117ccd5a2cSjsg 	}
9127ccd5a2cSjsg 
9137ccd5a2cSjsg 	if (pi->enable_gfx_power_gating) {
9147ccd5a2cSjsg 		trinity_gfx_powergating_enable(rdev, true);
9157ccd5a2cSjsg 	}
9167ccd5a2cSjsg }
9177ccd5a2cSjsg 
trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)9187ccd5a2cSjsg static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
9197ccd5a2cSjsg 						       struct radeon_ps *new_rps,
9207ccd5a2cSjsg 						       struct radeon_ps *old_rps)
9217ccd5a2cSjsg {
9227ccd5a2cSjsg 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
9237ccd5a2cSjsg 	struct trinity_ps *current_ps = trinity_get_ps(new_rps);
9247ccd5a2cSjsg 
9257ccd5a2cSjsg 	if (new_ps->levels[new_ps->num_levels - 1].sclk >=
9267ccd5a2cSjsg 	    current_ps->levels[current_ps->num_levels - 1].sclk)
9277ccd5a2cSjsg 		return;
9287ccd5a2cSjsg 
9297ccd5a2cSjsg 	trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
9307ccd5a2cSjsg }
9317ccd5a2cSjsg 
trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)9327ccd5a2cSjsg static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
9337ccd5a2cSjsg 						      struct radeon_ps *new_rps,
9347ccd5a2cSjsg 						      struct radeon_ps *old_rps)
9357ccd5a2cSjsg {
9367ccd5a2cSjsg 	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
9377ccd5a2cSjsg 	struct trinity_ps *current_ps = trinity_get_ps(old_rps);
9387ccd5a2cSjsg 
9397ccd5a2cSjsg 	if (new_ps->levels[new_ps->num_levels - 1].sclk <
9407ccd5a2cSjsg 	    current_ps->levels[current_ps->num_levels - 1].sclk)
9417ccd5a2cSjsg 		return;
9427ccd5a2cSjsg 
9437ccd5a2cSjsg 	trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
9447ccd5a2cSjsg }
9457ccd5a2cSjsg 
trinity_set_vce_clock(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)9467ccd5a2cSjsg static void trinity_set_vce_clock(struct radeon_device *rdev,
9477ccd5a2cSjsg 				  struct radeon_ps *new_rps,
9487ccd5a2cSjsg 				  struct radeon_ps *old_rps)
9497ccd5a2cSjsg {
9507ccd5a2cSjsg 	if ((old_rps->evclk != new_rps->evclk) ||
9517ccd5a2cSjsg 	    (old_rps->ecclk != new_rps->ecclk)) {
9527ccd5a2cSjsg 		/* turn the clocks on when encoding, off otherwise */
9537ccd5a2cSjsg 		if (new_rps->evclk || new_rps->ecclk)
9547ccd5a2cSjsg 			vce_v1_0_enable_mgcg(rdev, false);
9557ccd5a2cSjsg 		else
9567ccd5a2cSjsg 			vce_v1_0_enable_mgcg(rdev, true);
9577ccd5a2cSjsg 		radeon_set_vce_clocks(rdev, new_rps->evclk, new_rps->ecclk);
9587ccd5a2cSjsg 	}
9597ccd5a2cSjsg }
9607ccd5a2cSjsg 
trinity_program_ttt(struct radeon_device * rdev)9617ccd5a2cSjsg static void trinity_program_ttt(struct radeon_device *rdev)
9627ccd5a2cSjsg {
9637ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
9647ccd5a2cSjsg 	u32 value = RREG32_SMC(SMU_SCLK_DPM_TTT);
9657ccd5a2cSjsg 
9667ccd5a2cSjsg 	value &= ~(HT_MASK | LT_MASK);
9677ccd5a2cSjsg 	value |= HT((pi->thermal_auto_throttling + 49) * 8);
9687ccd5a2cSjsg 	value |= LT((pi->thermal_auto_throttling + 49 - pi->sys_info.htc_hyst_lmt) * 8);
9697ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_TTT, value);
9707ccd5a2cSjsg }
9717ccd5a2cSjsg 
trinity_enable_att(struct radeon_device * rdev)9727ccd5a2cSjsg static void trinity_enable_att(struct radeon_device *rdev)
9737ccd5a2cSjsg {
9747ccd5a2cSjsg 	u32 value = RREG32_SMC(SMU_SCLK_DPM_TT_CNTL);
9757ccd5a2cSjsg 
9767ccd5a2cSjsg 	value &= ~SCLK_TT_EN_MASK;
9777ccd5a2cSjsg 	value |= SCLK_TT_EN(1);
9787ccd5a2cSjsg 	WREG32_SMC(SMU_SCLK_DPM_TT_CNTL, value);
9797ccd5a2cSjsg }
9807ccd5a2cSjsg 
trinity_program_sclk_dpm(struct radeon_device * rdev)9817ccd5a2cSjsg static void trinity_program_sclk_dpm(struct radeon_device *rdev)
9827ccd5a2cSjsg {
9837ccd5a2cSjsg 	u32 p, u;
9847ccd5a2cSjsg 	u32 tp = RREG32_SMC(PM_TP);
9857ccd5a2cSjsg 	u32 ni;
9867ccd5a2cSjsg 	u32 xclk = radeon_get_xclk(rdev);
9877ccd5a2cSjsg 	u32 value;
9887ccd5a2cSjsg 
9897ccd5a2cSjsg 	r600_calculate_u_and_p(400, xclk, 16, &p, &u);
9907ccd5a2cSjsg 
9917ccd5a2cSjsg 	ni = (p + tp - 1) / tp;
9927ccd5a2cSjsg 
9937ccd5a2cSjsg 	value = RREG32_SMC(PM_I_CNTL_1);
9947ccd5a2cSjsg 	value &= ~SCLK_DPM_MASK;
9957ccd5a2cSjsg 	value |= SCLK_DPM(ni);
9967ccd5a2cSjsg 	WREG32_SMC(PM_I_CNTL_1, value);
9977ccd5a2cSjsg }
9987ccd5a2cSjsg 
trinity_set_thermal_temperature_range(struct radeon_device * rdev,int min_temp,int max_temp)9997ccd5a2cSjsg static int trinity_set_thermal_temperature_range(struct radeon_device *rdev,
10007ccd5a2cSjsg 						 int min_temp, int max_temp)
10017ccd5a2cSjsg {
10027ccd5a2cSjsg 	int low_temp = 0 * 1000;
10037ccd5a2cSjsg 	int high_temp = 255 * 1000;
10047ccd5a2cSjsg 
10057ccd5a2cSjsg 	if (low_temp < min_temp)
10067ccd5a2cSjsg 		low_temp = min_temp;
10077ccd5a2cSjsg 	if (high_temp > max_temp)
10087ccd5a2cSjsg 		high_temp = max_temp;
10097ccd5a2cSjsg 	if (high_temp < low_temp) {
10107ccd5a2cSjsg 		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
10117ccd5a2cSjsg 		return -EINVAL;
10127ccd5a2cSjsg 	}
10137ccd5a2cSjsg 
10147ccd5a2cSjsg 	WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
10157ccd5a2cSjsg 	WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
10167ccd5a2cSjsg 
10177ccd5a2cSjsg 	rdev->pm.dpm.thermal.min_temp = low_temp;
10187ccd5a2cSjsg 	rdev->pm.dpm.thermal.max_temp = high_temp;
10197ccd5a2cSjsg 
10207ccd5a2cSjsg 	return 0;
10217ccd5a2cSjsg }
10227ccd5a2cSjsg 
trinity_update_current_ps(struct radeon_device * rdev,struct radeon_ps * rps)10237ccd5a2cSjsg static void trinity_update_current_ps(struct radeon_device *rdev,
10247ccd5a2cSjsg 				      struct radeon_ps *rps)
10257ccd5a2cSjsg {
10267ccd5a2cSjsg 	struct trinity_ps *new_ps = trinity_get_ps(rps);
10277ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
10287ccd5a2cSjsg 
10297ccd5a2cSjsg 	pi->current_rps = *rps;
10307ccd5a2cSjsg 	pi->current_ps = *new_ps;
10317ccd5a2cSjsg 	pi->current_rps.ps_priv = &pi->current_ps;
10327ccd5a2cSjsg }
10337ccd5a2cSjsg 
trinity_update_requested_ps(struct radeon_device * rdev,struct radeon_ps * rps)10347ccd5a2cSjsg static void trinity_update_requested_ps(struct radeon_device *rdev,
10357ccd5a2cSjsg 					struct radeon_ps *rps)
10367ccd5a2cSjsg {
10377ccd5a2cSjsg 	struct trinity_ps *new_ps = trinity_get_ps(rps);
10387ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
10397ccd5a2cSjsg 
10407ccd5a2cSjsg 	pi->requested_rps = *rps;
10417ccd5a2cSjsg 	pi->requested_ps = *new_ps;
10427ccd5a2cSjsg 	pi->requested_rps.ps_priv = &pi->requested_ps;
10437ccd5a2cSjsg }
10447ccd5a2cSjsg 
trinity_dpm_enable_bapm(struct radeon_device * rdev,bool enable)10457ccd5a2cSjsg void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable)
10467ccd5a2cSjsg {
10477ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
10487ccd5a2cSjsg 
10497ccd5a2cSjsg 	if (pi->enable_bapm) {
10507ccd5a2cSjsg 		trinity_acquire_mutex(rdev);
10517ccd5a2cSjsg 		trinity_dpm_bapm_enable(rdev, enable);
10527ccd5a2cSjsg 		trinity_release_mutex(rdev);
10537ccd5a2cSjsg 	}
10547ccd5a2cSjsg }
10557ccd5a2cSjsg 
trinity_dpm_enable(struct radeon_device * rdev)10567ccd5a2cSjsg int trinity_dpm_enable(struct radeon_device *rdev)
10577ccd5a2cSjsg {
10587ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
10597ccd5a2cSjsg 
10607ccd5a2cSjsg 	trinity_acquire_mutex(rdev);
10617ccd5a2cSjsg 
10627ccd5a2cSjsg 	if (trinity_dpm_enabled(rdev)) {
10637ccd5a2cSjsg 		trinity_release_mutex(rdev);
10647ccd5a2cSjsg 		return -EINVAL;
10657ccd5a2cSjsg 	}
10667ccd5a2cSjsg 
10677ccd5a2cSjsg 	trinity_program_bootup_state(rdev);
10687ccd5a2cSjsg 	sumo_program_vc(rdev, 0x00C00033);
10697ccd5a2cSjsg 	trinity_start_am(rdev);
10707ccd5a2cSjsg 	if (pi->enable_auto_thermal_throttling) {
10717ccd5a2cSjsg 		trinity_program_ttt(rdev);
10727ccd5a2cSjsg 		trinity_enable_att(rdev);
10737ccd5a2cSjsg 	}
10747ccd5a2cSjsg 	trinity_program_sclk_dpm(rdev);
10757ccd5a2cSjsg 	trinity_start_dpm(rdev);
10767ccd5a2cSjsg 	trinity_wait_for_dpm_enabled(rdev);
10777ccd5a2cSjsg 	trinity_dpm_bapm_enable(rdev, false);
10787ccd5a2cSjsg 	trinity_release_mutex(rdev);
10797ccd5a2cSjsg 
10807ccd5a2cSjsg 	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
10817ccd5a2cSjsg 
10827ccd5a2cSjsg 	return 0;
10837ccd5a2cSjsg }
10847ccd5a2cSjsg 
trinity_dpm_late_enable(struct radeon_device * rdev)10857ccd5a2cSjsg int trinity_dpm_late_enable(struct radeon_device *rdev)
10867ccd5a2cSjsg {
10877ccd5a2cSjsg 	int ret;
10887ccd5a2cSjsg 
10897ccd5a2cSjsg 	trinity_acquire_mutex(rdev);
10907ccd5a2cSjsg 	trinity_enable_clock_power_gating(rdev);
10917ccd5a2cSjsg 
10927ccd5a2cSjsg 	if (rdev->irq.installed &&
10937ccd5a2cSjsg 	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
10947ccd5a2cSjsg 		ret = trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
10957ccd5a2cSjsg 		if (ret) {
10967ccd5a2cSjsg 			trinity_release_mutex(rdev);
10977ccd5a2cSjsg 			return ret;
10987ccd5a2cSjsg 		}
10997ccd5a2cSjsg 		rdev->irq.dpm_thermal = true;
11007ccd5a2cSjsg 		radeon_irq_set(rdev);
11017ccd5a2cSjsg 	}
11027ccd5a2cSjsg 	trinity_release_mutex(rdev);
11037ccd5a2cSjsg 
11047ccd5a2cSjsg 	return 0;
11057ccd5a2cSjsg }
11067ccd5a2cSjsg 
trinity_dpm_disable(struct radeon_device * rdev)11077ccd5a2cSjsg void trinity_dpm_disable(struct radeon_device *rdev)
11087ccd5a2cSjsg {
11097ccd5a2cSjsg 	trinity_acquire_mutex(rdev);
11107ccd5a2cSjsg 	if (!trinity_dpm_enabled(rdev)) {
11117ccd5a2cSjsg 		trinity_release_mutex(rdev);
11127ccd5a2cSjsg 		return;
11137ccd5a2cSjsg 	}
11147ccd5a2cSjsg 	trinity_dpm_bapm_enable(rdev, false);
11157ccd5a2cSjsg 	trinity_disable_clock_power_gating(rdev);
11167ccd5a2cSjsg 	sumo_clear_vc(rdev);
11177ccd5a2cSjsg 	trinity_wait_for_level_0(rdev);
11187ccd5a2cSjsg 	trinity_stop_dpm(rdev);
11197ccd5a2cSjsg 	trinity_reset_am(rdev);
11207ccd5a2cSjsg 	trinity_release_mutex(rdev);
11217ccd5a2cSjsg 
11227ccd5a2cSjsg 	if (rdev->irq.installed &&
11237ccd5a2cSjsg 	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
11247ccd5a2cSjsg 		rdev->irq.dpm_thermal = false;
11257ccd5a2cSjsg 		radeon_irq_set(rdev);
11267ccd5a2cSjsg 	}
11277ccd5a2cSjsg 
11287ccd5a2cSjsg 	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
11297ccd5a2cSjsg }
11307ccd5a2cSjsg 
trinity_get_min_sclk_divider(struct radeon_device * rdev)11317ccd5a2cSjsg static void trinity_get_min_sclk_divider(struct radeon_device *rdev)
11327ccd5a2cSjsg {
11337ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
11347ccd5a2cSjsg 
11357ccd5a2cSjsg 	pi->min_sclk_did =
11367ccd5a2cSjsg 		(RREG32_SMC(CC_SMU_MISC_FUSES) & MinSClkDid_MASK) >> MinSClkDid_SHIFT;
11377ccd5a2cSjsg }
11387ccd5a2cSjsg 
trinity_setup_nbp_sim(struct radeon_device * rdev,struct radeon_ps * rps)11397ccd5a2cSjsg static void trinity_setup_nbp_sim(struct radeon_device *rdev,
11407ccd5a2cSjsg 				  struct radeon_ps *rps)
11417ccd5a2cSjsg {
11427ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
11437ccd5a2cSjsg 	struct trinity_ps *new_ps = trinity_get_ps(rps);
11447ccd5a2cSjsg 	u32 nbpsconfig;
11457ccd5a2cSjsg 
11467ccd5a2cSjsg 	if (pi->sys_info.nb_dpm_enable) {
11477ccd5a2cSjsg 		nbpsconfig = RREG32_SMC(NB_PSTATE_CONFIG);
11487ccd5a2cSjsg 		nbpsconfig &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | DpmXNbPsLo_MASK | DpmXNbPsHi_MASK);
11497ccd5a2cSjsg 		nbpsconfig |= (Dpm0PgNbPsLo(new_ps->Dpm0PgNbPsLo) |
11507ccd5a2cSjsg 			       Dpm0PgNbPsHi(new_ps->Dpm0PgNbPsHi) |
11517ccd5a2cSjsg 			       DpmXNbPsLo(new_ps->DpmXNbPsLo) |
11527ccd5a2cSjsg 			       DpmXNbPsHi(new_ps->DpmXNbPsHi));
11537ccd5a2cSjsg 		WREG32_SMC(NB_PSTATE_CONFIG, nbpsconfig);
11547ccd5a2cSjsg 	}
11557ccd5a2cSjsg }
11567ccd5a2cSjsg 
trinity_dpm_force_performance_level(struct radeon_device * rdev,enum radeon_dpm_forced_level level)11577ccd5a2cSjsg int trinity_dpm_force_performance_level(struct radeon_device *rdev,
11587ccd5a2cSjsg 					enum radeon_dpm_forced_level level)
11597ccd5a2cSjsg {
11607ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
11617ccd5a2cSjsg 	struct radeon_ps *rps = &pi->current_rps;
11627ccd5a2cSjsg 	struct trinity_ps *ps = trinity_get_ps(rps);
11637ccd5a2cSjsg 	int i, ret;
11647ccd5a2cSjsg 
11657ccd5a2cSjsg 	if (ps->num_levels <= 1)
11667ccd5a2cSjsg 		return 0;
11677ccd5a2cSjsg 
11687ccd5a2cSjsg 	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
11697ccd5a2cSjsg 		/* not supported by the hw */
11707ccd5a2cSjsg 		return -EINVAL;
11717ccd5a2cSjsg 	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
11727ccd5a2cSjsg 		ret = trinity_dpm_n_levels_disabled(rdev, ps->num_levels - 1);
11737ccd5a2cSjsg 		if (ret)
11747ccd5a2cSjsg 			return ret;
11757ccd5a2cSjsg 	} else {
11767ccd5a2cSjsg 		for (i = 0; i < ps->num_levels; i++) {
11777ccd5a2cSjsg 			ret = trinity_dpm_n_levels_disabled(rdev, 0);
11787ccd5a2cSjsg 			if (ret)
11797ccd5a2cSjsg 				return ret;
11807ccd5a2cSjsg 		}
11817ccd5a2cSjsg 	}
11827ccd5a2cSjsg 
11837ccd5a2cSjsg 	rdev->pm.dpm.forced_level = level;
11847ccd5a2cSjsg 
11857ccd5a2cSjsg 	return 0;
11867ccd5a2cSjsg }
11877ccd5a2cSjsg 
trinity_dpm_pre_set_power_state(struct radeon_device * rdev)11887ccd5a2cSjsg int trinity_dpm_pre_set_power_state(struct radeon_device *rdev)
11897ccd5a2cSjsg {
11907ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
11917ccd5a2cSjsg 	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
11927ccd5a2cSjsg 	struct radeon_ps *new_ps = &requested_ps;
11937ccd5a2cSjsg 
11947ccd5a2cSjsg 	trinity_update_requested_ps(rdev, new_ps);
11957ccd5a2cSjsg 
11967ccd5a2cSjsg 	trinity_apply_state_adjust_rules(rdev,
11977ccd5a2cSjsg 					 &pi->requested_rps,
11987ccd5a2cSjsg 					 &pi->current_rps);
11997ccd5a2cSjsg 
12007ccd5a2cSjsg 	return 0;
12017ccd5a2cSjsg }
12027ccd5a2cSjsg 
trinity_dpm_set_power_state(struct radeon_device * rdev)12037ccd5a2cSjsg int trinity_dpm_set_power_state(struct radeon_device *rdev)
12047ccd5a2cSjsg {
12057ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
12067ccd5a2cSjsg 	struct radeon_ps *new_ps = &pi->requested_rps;
12077ccd5a2cSjsg 	struct radeon_ps *old_ps = &pi->current_rps;
12087ccd5a2cSjsg 
12097ccd5a2cSjsg 	trinity_acquire_mutex(rdev);
12107ccd5a2cSjsg 	if (pi->enable_dpm) {
12117ccd5a2cSjsg 		if (pi->enable_bapm)
12127ccd5a2cSjsg 			trinity_dpm_bapm_enable(rdev, rdev->pm.dpm.ac_power);
12137ccd5a2cSjsg 		trinity_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
12147ccd5a2cSjsg 		trinity_enable_power_level_0(rdev);
12157ccd5a2cSjsg 		trinity_force_level_0(rdev);
12167ccd5a2cSjsg 		trinity_wait_for_level_0(rdev);
12177ccd5a2cSjsg 		trinity_setup_nbp_sim(rdev, new_ps);
12187ccd5a2cSjsg 		trinity_program_power_levels_0_to_n(rdev, new_ps, old_ps);
12197ccd5a2cSjsg 		trinity_force_level_0(rdev);
12207ccd5a2cSjsg 		trinity_unforce_levels(rdev);
12217ccd5a2cSjsg 		trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
12227ccd5a2cSjsg 		trinity_set_vce_clock(rdev, new_ps, old_ps);
12237ccd5a2cSjsg 	}
12247ccd5a2cSjsg 	trinity_release_mutex(rdev);
12257ccd5a2cSjsg 
12267ccd5a2cSjsg 	return 0;
12277ccd5a2cSjsg }
12287ccd5a2cSjsg 
trinity_dpm_post_set_power_state(struct radeon_device * rdev)12297ccd5a2cSjsg void trinity_dpm_post_set_power_state(struct radeon_device *rdev)
12307ccd5a2cSjsg {
12317ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
12327ccd5a2cSjsg 	struct radeon_ps *new_ps = &pi->requested_rps;
12337ccd5a2cSjsg 
12347ccd5a2cSjsg 	trinity_update_current_ps(rdev, new_ps);
12357ccd5a2cSjsg }
12367ccd5a2cSjsg 
trinity_dpm_setup_asic(struct radeon_device * rdev)12377ccd5a2cSjsg void trinity_dpm_setup_asic(struct radeon_device *rdev)
12387ccd5a2cSjsg {
12397ccd5a2cSjsg 	trinity_acquire_mutex(rdev);
12407ccd5a2cSjsg 	sumo_program_sstp(rdev);
12417ccd5a2cSjsg 	sumo_take_smu_control(rdev, true);
12427ccd5a2cSjsg 	trinity_get_min_sclk_divider(rdev);
12437ccd5a2cSjsg 	trinity_release_mutex(rdev);
12447ccd5a2cSjsg }
12457ccd5a2cSjsg 
12467ccd5a2cSjsg #if 0
12477ccd5a2cSjsg void trinity_dpm_reset_asic(struct radeon_device *rdev)
12487ccd5a2cSjsg {
12497ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
12507ccd5a2cSjsg 
12517ccd5a2cSjsg 	trinity_acquire_mutex(rdev);
12527ccd5a2cSjsg 	if (pi->enable_dpm) {
12537ccd5a2cSjsg 		trinity_enable_power_level_0(rdev);
12547ccd5a2cSjsg 		trinity_force_level_0(rdev);
12557ccd5a2cSjsg 		trinity_wait_for_level_0(rdev);
12567ccd5a2cSjsg 		trinity_program_bootup_state(rdev);
12577ccd5a2cSjsg 		trinity_force_level_0(rdev);
12587ccd5a2cSjsg 		trinity_unforce_levels(rdev);
12597ccd5a2cSjsg 	}
12607ccd5a2cSjsg 	trinity_release_mutex(rdev);
12617ccd5a2cSjsg }
12627ccd5a2cSjsg #endif
12637ccd5a2cSjsg 
trinity_convert_voltage_index_to_value(struct radeon_device * rdev,u32 vid_2bit)12647ccd5a2cSjsg static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
12657ccd5a2cSjsg 						  u32 vid_2bit)
12667ccd5a2cSjsg {
12677ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
12687ccd5a2cSjsg 	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
12697ccd5a2cSjsg 	u32 svi_mode = (RREG32_SMC(PM_CONFIG) & SVI_Mode) ? 1 : 0;
12707ccd5a2cSjsg 	u32 step = (svi_mode == 0) ? 1250 : 625;
12717ccd5a2cSjsg 	u32 delta = vid_7bit * step + 50;
12727ccd5a2cSjsg 
12737ccd5a2cSjsg 	if (delta > 155000)
12747ccd5a2cSjsg 		return 0;
12757ccd5a2cSjsg 
12767ccd5a2cSjsg 	return (155000 - delta) / 100;
12777ccd5a2cSjsg }
12787ccd5a2cSjsg 
trinity_patch_boot_state(struct radeon_device * rdev,struct trinity_ps * ps)12797ccd5a2cSjsg static void trinity_patch_boot_state(struct radeon_device *rdev,
12807ccd5a2cSjsg 				     struct trinity_ps *ps)
12817ccd5a2cSjsg {
12827ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
12837ccd5a2cSjsg 
12847ccd5a2cSjsg 	ps->num_levels = 1;
12857ccd5a2cSjsg 	ps->nbps_flags = 0;
12867ccd5a2cSjsg 	ps->bapm_flags = 0;
12877ccd5a2cSjsg 	ps->levels[0] = pi->boot_pl;
12887ccd5a2cSjsg }
12897ccd5a2cSjsg 
trinity_calculate_vce_wm(struct radeon_device * rdev,u32 sclk)12907ccd5a2cSjsg static u8 trinity_calculate_vce_wm(struct radeon_device *rdev, u32 sclk)
12917ccd5a2cSjsg {
12927ccd5a2cSjsg 	if (sclk < 20000)
12937ccd5a2cSjsg 		return 1;
12947ccd5a2cSjsg 	return 0;
12957ccd5a2cSjsg }
12967ccd5a2cSjsg 
trinity_construct_boot_state(struct radeon_device * rdev)12977ccd5a2cSjsg static void trinity_construct_boot_state(struct radeon_device *rdev)
12987ccd5a2cSjsg {
12997ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
13007ccd5a2cSjsg 
13017ccd5a2cSjsg 	pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
13027ccd5a2cSjsg 	pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
13037ccd5a2cSjsg 	pi->boot_pl.ds_divider_index = 0;
13047ccd5a2cSjsg 	pi->boot_pl.ss_divider_index = 0;
13057ccd5a2cSjsg 	pi->boot_pl.allow_gnb_slow = 1;
13067ccd5a2cSjsg 	pi->boot_pl.force_nbp_state = 0;
13077ccd5a2cSjsg 	pi->boot_pl.display_wm = 0;
13087ccd5a2cSjsg 	pi->boot_pl.vce_wm = 0;
13097ccd5a2cSjsg 	pi->current_ps.num_levels = 1;
13107ccd5a2cSjsg 	pi->current_ps.levels[0] = pi->boot_pl;
13117ccd5a2cSjsg }
13127ccd5a2cSjsg 
trinity_get_sleep_divider_id_from_clock(struct radeon_device * rdev,u32 sclk,u32 min_sclk_in_sr)13137ccd5a2cSjsg static u8 trinity_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
13147ccd5a2cSjsg 						  u32 sclk, u32 min_sclk_in_sr)
13157ccd5a2cSjsg {
13167ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
13177ccd5a2cSjsg 	u32 i;
13187ccd5a2cSjsg 	u32 temp;
13197ccd5a2cSjsg 	u32 min = (min_sclk_in_sr > TRINITY_MINIMUM_ENGINE_CLOCK) ?
13207ccd5a2cSjsg 		min_sclk_in_sr : TRINITY_MINIMUM_ENGINE_CLOCK;
13217ccd5a2cSjsg 
13227ccd5a2cSjsg 	if (sclk < min)
13237ccd5a2cSjsg 		return 0;
13247ccd5a2cSjsg 
13257ccd5a2cSjsg 	if (!pi->enable_sclk_ds)
13267ccd5a2cSjsg 		return 0;
13277ccd5a2cSjsg 
13287ccd5a2cSjsg 	for (i = TRINITY_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
13297ccd5a2cSjsg 		temp = sclk / sumo_get_sleep_divider_from_id(i);
13307ccd5a2cSjsg 		if (temp >= min || i == 0)
13317ccd5a2cSjsg 			break;
13327ccd5a2cSjsg 	}
13337ccd5a2cSjsg 
13347ccd5a2cSjsg 	return (u8)i;
13357ccd5a2cSjsg }
13367ccd5a2cSjsg 
trinity_get_valid_engine_clock(struct radeon_device * rdev,u32 lower_limit)13377ccd5a2cSjsg static u32 trinity_get_valid_engine_clock(struct radeon_device *rdev,
13387ccd5a2cSjsg 					  u32 lower_limit)
13397ccd5a2cSjsg {
13407ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
13417ccd5a2cSjsg 	u32 i;
13427ccd5a2cSjsg 
13437ccd5a2cSjsg 	for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
13447ccd5a2cSjsg 		if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
13457ccd5a2cSjsg 			return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
13467ccd5a2cSjsg 	}
13477ccd5a2cSjsg 
13487ccd5a2cSjsg 	if (i == pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries)
13497ccd5a2cSjsg 		DRM_ERROR("engine clock out of range!");
13507ccd5a2cSjsg 
13517ccd5a2cSjsg 	return 0;
13527ccd5a2cSjsg }
13537ccd5a2cSjsg 
trinity_patch_thermal_state(struct radeon_device * rdev,struct trinity_ps * ps,struct trinity_ps * current_ps)13547ccd5a2cSjsg static void trinity_patch_thermal_state(struct radeon_device *rdev,
13557ccd5a2cSjsg 					struct trinity_ps *ps,
13567ccd5a2cSjsg 					struct trinity_ps *current_ps)
13577ccd5a2cSjsg {
13587ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
13597ccd5a2cSjsg 	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
13607ccd5a2cSjsg 	u32 current_vddc;
13617ccd5a2cSjsg 	u32 current_sclk;
13627ccd5a2cSjsg 	u32 current_index = 0;
13637ccd5a2cSjsg 
13647ccd5a2cSjsg 	if (current_ps) {
13657ccd5a2cSjsg 		current_vddc = current_ps->levels[current_index].vddc_index;
13667ccd5a2cSjsg 		current_sclk = current_ps->levels[current_index].sclk;
13677ccd5a2cSjsg 	} else {
13687ccd5a2cSjsg 		current_vddc = pi->boot_pl.vddc_index;
13697ccd5a2cSjsg 		current_sclk = pi->boot_pl.sclk;
13707ccd5a2cSjsg 	}
13717ccd5a2cSjsg 
13727ccd5a2cSjsg 	ps->levels[0].vddc_index = current_vddc;
13737ccd5a2cSjsg 
13747ccd5a2cSjsg 	if (ps->levels[0].sclk > current_sclk)
13757ccd5a2cSjsg 		ps->levels[0].sclk = current_sclk;
13767ccd5a2cSjsg 
13777ccd5a2cSjsg 	ps->levels[0].ds_divider_index =
13787ccd5a2cSjsg 		trinity_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
13797ccd5a2cSjsg 	ps->levels[0].ss_divider_index = ps->levels[0].ds_divider_index;
13807ccd5a2cSjsg 	ps->levels[0].allow_gnb_slow = 1;
13817ccd5a2cSjsg 	ps->levels[0].force_nbp_state = 0;
13827ccd5a2cSjsg 	ps->levels[0].display_wm = 0;
13837ccd5a2cSjsg 	ps->levels[0].vce_wm =
13847ccd5a2cSjsg 		trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
13857ccd5a2cSjsg }
13867ccd5a2cSjsg 
trinity_calculate_display_wm(struct radeon_device * rdev,struct trinity_ps * ps,u32 index)13877ccd5a2cSjsg static u8 trinity_calculate_display_wm(struct radeon_device *rdev,
13887ccd5a2cSjsg 				       struct trinity_ps *ps, u32 index)
13897ccd5a2cSjsg {
13907ccd5a2cSjsg 	if (ps == NULL || ps->num_levels <= 1)
13917ccd5a2cSjsg 		return 0;
13927ccd5a2cSjsg 	else if (ps->num_levels == 2) {
13937ccd5a2cSjsg 		if (index == 0)
13947ccd5a2cSjsg 			return 0;
13957ccd5a2cSjsg 		else
13967ccd5a2cSjsg 			return 1;
13977ccd5a2cSjsg 	} else {
13987ccd5a2cSjsg 		if (index == 0)
13997ccd5a2cSjsg 			return 0;
14007ccd5a2cSjsg 		else if (ps->levels[index].sclk < 30000)
14017ccd5a2cSjsg 			return 0;
14027ccd5a2cSjsg 		else
14037ccd5a2cSjsg 			return 1;
14047ccd5a2cSjsg 	}
14057ccd5a2cSjsg }
14067ccd5a2cSjsg 
trinity_get_uvd_clock_index(struct radeon_device * rdev,struct radeon_ps * rps)14077ccd5a2cSjsg static u32 trinity_get_uvd_clock_index(struct radeon_device *rdev,
14087ccd5a2cSjsg 				       struct radeon_ps *rps)
14097ccd5a2cSjsg {
14107ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
14117ccd5a2cSjsg 	u32 i = 0;
14127ccd5a2cSjsg 
14137ccd5a2cSjsg 	for (i = 0; i < 4; i++) {
14147ccd5a2cSjsg 		if ((rps->vclk == pi->sys_info.uvd_clock_table_entries[i].vclk) &&
14157ccd5a2cSjsg 		    (rps->dclk == pi->sys_info.uvd_clock_table_entries[i].dclk))
14167ccd5a2cSjsg 		    break;
14177ccd5a2cSjsg 	}
14187ccd5a2cSjsg 
14197ccd5a2cSjsg 	if (i >= 4) {
14207ccd5a2cSjsg 		DRM_ERROR("UVD clock index not found!\n");
14217ccd5a2cSjsg 		i = 3;
14227ccd5a2cSjsg 	}
14237ccd5a2cSjsg 	return i;
14247ccd5a2cSjsg }
14257ccd5a2cSjsg 
trinity_adjust_uvd_state(struct radeon_device * rdev,struct radeon_ps * rps)14267ccd5a2cSjsg static void trinity_adjust_uvd_state(struct radeon_device *rdev,
14277ccd5a2cSjsg 				     struct radeon_ps *rps)
14287ccd5a2cSjsg {
14297ccd5a2cSjsg 	struct trinity_ps *ps = trinity_get_ps(rps);
14307ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
14317ccd5a2cSjsg 	u32 high_index = 0;
14327ccd5a2cSjsg 	u32 low_index = 0;
14337ccd5a2cSjsg 
14347ccd5a2cSjsg 	if (pi->uvd_dpm && r600_is_uvd_state(rps->class, rps->class2)) {
14357ccd5a2cSjsg 		high_index = trinity_get_uvd_clock_index(rdev, rps);
14367ccd5a2cSjsg 
14377ccd5a2cSjsg 		switch(high_index) {
14387ccd5a2cSjsg 		case 3:
14397ccd5a2cSjsg 		case 2:
14407ccd5a2cSjsg 			low_index = 1;
14417ccd5a2cSjsg 			break;
14427ccd5a2cSjsg 		case 1:
14437ccd5a2cSjsg 		case 0:
14447ccd5a2cSjsg 		default:
14457ccd5a2cSjsg 			low_index = 0;
14467ccd5a2cSjsg 			break;
14477ccd5a2cSjsg 		}
14487ccd5a2cSjsg 
14497ccd5a2cSjsg 		ps->vclk_low_divider =
14507ccd5a2cSjsg 			pi->sys_info.uvd_clock_table_entries[high_index].vclk_did;
14517ccd5a2cSjsg 		ps->dclk_low_divider =
14527ccd5a2cSjsg 			pi->sys_info.uvd_clock_table_entries[high_index].dclk_did;
14537ccd5a2cSjsg 		ps->vclk_high_divider =
14547ccd5a2cSjsg 			pi->sys_info.uvd_clock_table_entries[low_index].vclk_did;
14557ccd5a2cSjsg 		ps->dclk_high_divider =
14567ccd5a2cSjsg 			pi->sys_info.uvd_clock_table_entries[low_index].dclk_did;
14577ccd5a2cSjsg 	}
14587ccd5a2cSjsg }
14597ccd5a2cSjsg 
trinity_get_vce_clock_voltage(struct radeon_device * rdev,u32 evclk,u32 ecclk,u16 * voltage)14607ccd5a2cSjsg static int trinity_get_vce_clock_voltage(struct radeon_device *rdev,
14617ccd5a2cSjsg 					 u32 evclk, u32 ecclk, u16 *voltage)
14627ccd5a2cSjsg {
14637ccd5a2cSjsg 	u32 i;
14647ccd5a2cSjsg 	int ret = -EINVAL;
14657ccd5a2cSjsg 	struct radeon_vce_clock_voltage_dependency_table *table =
14667ccd5a2cSjsg 		&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
14677ccd5a2cSjsg 
14687ccd5a2cSjsg 	if (((evclk == 0) && (ecclk == 0)) ||
14697ccd5a2cSjsg 	    (table && (table->count == 0))) {
14707ccd5a2cSjsg 		*voltage = 0;
14717ccd5a2cSjsg 		return 0;
14727ccd5a2cSjsg 	}
14737ccd5a2cSjsg 
14747ccd5a2cSjsg 	for (i = 0; i < table->count; i++) {
14757ccd5a2cSjsg 		if ((evclk <= table->entries[i].evclk) &&
14767ccd5a2cSjsg 		    (ecclk <= table->entries[i].ecclk)) {
14777ccd5a2cSjsg 			*voltage = table->entries[i].v;
14787ccd5a2cSjsg 			ret = 0;
14797ccd5a2cSjsg 			break;
14807ccd5a2cSjsg 		}
14817ccd5a2cSjsg 	}
14827ccd5a2cSjsg 
14837ccd5a2cSjsg 	/* if no match return the highest voltage */
14847ccd5a2cSjsg 	if (ret)
14857ccd5a2cSjsg 		*voltage = table->entries[table->count - 1].v;
14867ccd5a2cSjsg 
14877ccd5a2cSjsg 	return ret;
14887ccd5a2cSjsg }
14897ccd5a2cSjsg 
trinity_apply_state_adjust_rules(struct radeon_device * rdev,struct radeon_ps * new_rps,struct radeon_ps * old_rps)14907ccd5a2cSjsg static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
14917ccd5a2cSjsg 					     struct radeon_ps *new_rps,
14927ccd5a2cSjsg 					     struct radeon_ps *old_rps)
14937ccd5a2cSjsg {
14947ccd5a2cSjsg 	struct trinity_ps *ps = trinity_get_ps(new_rps);
14957ccd5a2cSjsg 	struct trinity_ps *current_ps = trinity_get_ps(old_rps);
14967ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
14977ccd5a2cSjsg 	u32 min_voltage = 0; /* ??? */
14987ccd5a2cSjsg 	u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
14997ccd5a2cSjsg 	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
15007ccd5a2cSjsg 	u32 i;
15017ccd5a2cSjsg 	u16 min_vce_voltage;
15027ccd5a2cSjsg 	bool force_high;
15037ccd5a2cSjsg 	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
15047ccd5a2cSjsg 
15057ccd5a2cSjsg 	if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
15067ccd5a2cSjsg 		return trinity_patch_thermal_state(rdev, ps, current_ps);
15077ccd5a2cSjsg 
15087ccd5a2cSjsg 	trinity_adjust_uvd_state(rdev, new_rps);
15097ccd5a2cSjsg 
15107ccd5a2cSjsg 	if (new_rps->vce_active) {
15117ccd5a2cSjsg 		new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
15127ccd5a2cSjsg 		new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
15137ccd5a2cSjsg 	} else {
15147ccd5a2cSjsg 		new_rps->evclk = 0;
15157ccd5a2cSjsg 		new_rps->ecclk = 0;
15167ccd5a2cSjsg 	}
15177ccd5a2cSjsg 
15187ccd5a2cSjsg 	for (i = 0; i < ps->num_levels; i++) {
15197ccd5a2cSjsg 		if (ps->levels[i].vddc_index < min_voltage)
15207ccd5a2cSjsg 			ps->levels[i].vddc_index = min_voltage;
15217ccd5a2cSjsg 
15227ccd5a2cSjsg 		if (ps->levels[i].sclk < min_sclk)
15237ccd5a2cSjsg 			ps->levels[i].sclk =
15247ccd5a2cSjsg 				trinity_get_valid_engine_clock(rdev, min_sclk);
15257ccd5a2cSjsg 
15267ccd5a2cSjsg 		/* patch in vce limits */
15277ccd5a2cSjsg 		if (new_rps->vce_active) {
15287ccd5a2cSjsg 			/* sclk */
15297ccd5a2cSjsg 			if (ps->levels[i].sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
15307ccd5a2cSjsg 				ps->levels[i].sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
15317ccd5a2cSjsg 			/* vddc */
15327ccd5a2cSjsg 			trinity_get_vce_clock_voltage(rdev, new_rps->evclk, new_rps->ecclk, &min_vce_voltage);
15337ccd5a2cSjsg 			if (ps->levels[i].vddc_index < min_vce_voltage)
15347ccd5a2cSjsg 				ps->levels[i].vddc_index = min_vce_voltage;
15357ccd5a2cSjsg 		}
15367ccd5a2cSjsg 
15377ccd5a2cSjsg 		ps->levels[i].ds_divider_index =
15387ccd5a2cSjsg 			sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
15397ccd5a2cSjsg 
15407ccd5a2cSjsg 		ps->levels[i].ss_divider_index = ps->levels[i].ds_divider_index;
15417ccd5a2cSjsg 
15427ccd5a2cSjsg 		ps->levels[i].allow_gnb_slow = 1;
15437ccd5a2cSjsg 		ps->levels[i].force_nbp_state = 0;
15447ccd5a2cSjsg 		ps->levels[i].display_wm =
15457ccd5a2cSjsg 			trinity_calculate_display_wm(rdev, ps, i);
15467ccd5a2cSjsg 		ps->levels[i].vce_wm =
15477ccd5a2cSjsg 			trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
15487ccd5a2cSjsg 	}
15497ccd5a2cSjsg 
15507ccd5a2cSjsg 	if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
15517ccd5a2cSjsg 	    ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY))
15527ccd5a2cSjsg 		ps->bapm_flags |= TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE;
15537ccd5a2cSjsg 
15547ccd5a2cSjsg 	if (pi->sys_info.nb_dpm_enable) {
15557ccd5a2cSjsg 		ps->Dpm0PgNbPsLo = 0x1;
15567ccd5a2cSjsg 		ps->Dpm0PgNbPsHi = 0x0;
15577ccd5a2cSjsg 		ps->DpmXNbPsLo = 0x2;
15587ccd5a2cSjsg 		ps->DpmXNbPsHi = 0x1;
15597ccd5a2cSjsg 
15607ccd5a2cSjsg 		if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
15617ccd5a2cSjsg 		    ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) {
15627ccd5a2cSjsg 			force_high = ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ||
15637ccd5a2cSjsg 				      ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) &&
15647ccd5a2cSjsg 				       (pi->sys_info.uma_channel_number == 1)));
15657ccd5a2cSjsg 			force_high = (num_active_displays >= 3) || force_high;
15667ccd5a2cSjsg 			ps->Dpm0PgNbPsLo = force_high ? 0x2 : 0x3;
15677ccd5a2cSjsg 			ps->Dpm0PgNbPsHi = 0x1;
15687ccd5a2cSjsg 			ps->DpmXNbPsLo = force_high ? 0x2 : 0x3;
15697ccd5a2cSjsg 			ps->DpmXNbPsHi = 0x2;
15707ccd5a2cSjsg 			ps->levels[ps->num_levels - 1].allow_gnb_slow = 0;
15717ccd5a2cSjsg 		}
15727ccd5a2cSjsg 	}
15737ccd5a2cSjsg }
15747ccd5a2cSjsg 
trinity_cleanup_asic(struct radeon_device * rdev)15757ccd5a2cSjsg static void trinity_cleanup_asic(struct radeon_device *rdev)
15767ccd5a2cSjsg {
15777ccd5a2cSjsg 	sumo_take_smu_control(rdev, false);
15787ccd5a2cSjsg }
15797ccd5a2cSjsg 
15807ccd5a2cSjsg #if 0
15817ccd5a2cSjsg static void trinity_pre_display_configuration_change(struct radeon_device *rdev)
15827ccd5a2cSjsg {
15837ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
15847ccd5a2cSjsg 
15857ccd5a2cSjsg 	if (pi->voltage_drop_in_dce)
15867ccd5a2cSjsg 		trinity_dce_enable_voltage_adjustment(rdev, false);
15877ccd5a2cSjsg }
15887ccd5a2cSjsg #endif
15897ccd5a2cSjsg 
trinity_add_dccac_value(struct radeon_device * rdev)15907ccd5a2cSjsg static void trinity_add_dccac_value(struct radeon_device *rdev)
15917ccd5a2cSjsg {
15927ccd5a2cSjsg 	u32 gpu_cac_avrg_cntl_window_size;
15937ccd5a2cSjsg 	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
15947ccd5a2cSjsg 	u64 disp_clk = rdev->clock.default_dispclk / 100;
15957ccd5a2cSjsg 	u32 dc_cac_value;
15967ccd5a2cSjsg 
15977ccd5a2cSjsg 	gpu_cac_avrg_cntl_window_size =
15987ccd5a2cSjsg 		(RREG32_SMC(GPU_CAC_AVRG_CNTL) & WINDOW_SIZE_MASK) >> WINDOW_SIZE_SHIFT;
15997ccd5a2cSjsg 
16007ccd5a2cSjsg 	dc_cac_value = (u32)((14213 * disp_clk * disp_clk * (u64)num_active_displays) >>
16017ccd5a2cSjsg 			     (32 - gpu_cac_avrg_cntl_window_size));
16027ccd5a2cSjsg 
16037ccd5a2cSjsg 	WREG32_SMC(DC_CAC_VALUE, dc_cac_value);
16047ccd5a2cSjsg }
16057ccd5a2cSjsg 
trinity_dpm_display_configuration_changed(struct radeon_device * rdev)16067ccd5a2cSjsg void trinity_dpm_display_configuration_changed(struct radeon_device *rdev)
16077ccd5a2cSjsg {
16087ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
16097ccd5a2cSjsg 
16107ccd5a2cSjsg 	if (pi->voltage_drop_in_dce)
16117ccd5a2cSjsg 		trinity_dce_enable_voltage_adjustment(rdev, true);
16127ccd5a2cSjsg 	trinity_add_dccac_value(rdev);
16137ccd5a2cSjsg }
16147ccd5a2cSjsg 
16157ccd5a2cSjsg union power_info {
16167ccd5a2cSjsg 	struct _ATOM_POWERPLAY_INFO info;
16177ccd5a2cSjsg 	struct _ATOM_POWERPLAY_INFO_V2 info_2;
16187ccd5a2cSjsg 	struct _ATOM_POWERPLAY_INFO_V3 info_3;
16197ccd5a2cSjsg 	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
16207ccd5a2cSjsg 	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
16217ccd5a2cSjsg 	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
16227ccd5a2cSjsg };
16237ccd5a2cSjsg 
16247ccd5a2cSjsg union pplib_clock_info {
16257ccd5a2cSjsg 	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
16267ccd5a2cSjsg 	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
16277ccd5a2cSjsg 	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
16287ccd5a2cSjsg 	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
16297ccd5a2cSjsg };
16307ccd5a2cSjsg 
16317ccd5a2cSjsg union pplib_power_state {
16327ccd5a2cSjsg 	struct _ATOM_PPLIB_STATE v1;
16337ccd5a2cSjsg 	struct _ATOM_PPLIB_STATE_V2 v2;
16347ccd5a2cSjsg };
16357ccd5a2cSjsg 
trinity_parse_pplib_non_clock_info(struct radeon_device * rdev,struct radeon_ps * rps,struct _ATOM_PPLIB_NONCLOCK_INFO * non_clock_info,u8 table_rev)16367ccd5a2cSjsg static void trinity_parse_pplib_non_clock_info(struct radeon_device *rdev,
16377ccd5a2cSjsg 					       struct radeon_ps *rps,
16387ccd5a2cSjsg 					       struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
16397ccd5a2cSjsg 					       u8 table_rev)
16407ccd5a2cSjsg {
16417ccd5a2cSjsg 	struct trinity_ps *ps = trinity_get_ps(rps);
16427ccd5a2cSjsg 
16437ccd5a2cSjsg 	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
16447ccd5a2cSjsg 	rps->class = le16_to_cpu(non_clock_info->usClassification);
16457ccd5a2cSjsg 	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
16467ccd5a2cSjsg 
16477ccd5a2cSjsg 	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
16487ccd5a2cSjsg 		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
16497ccd5a2cSjsg 		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
16507ccd5a2cSjsg 	} else {
16517ccd5a2cSjsg 		rps->vclk = 0;
16527ccd5a2cSjsg 		rps->dclk = 0;
16537ccd5a2cSjsg 	}
16547ccd5a2cSjsg 
16557ccd5a2cSjsg 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
16567ccd5a2cSjsg 		rdev->pm.dpm.boot_ps = rps;
16577ccd5a2cSjsg 		trinity_patch_boot_state(rdev, ps);
16587ccd5a2cSjsg 	}
16597ccd5a2cSjsg 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
16607ccd5a2cSjsg 		rdev->pm.dpm.uvd_ps = rps;
16617ccd5a2cSjsg }
16627ccd5a2cSjsg 
trinity_parse_pplib_clock_info(struct radeon_device * rdev,struct radeon_ps * rps,int index,union pplib_clock_info * clock_info)16637ccd5a2cSjsg static void trinity_parse_pplib_clock_info(struct radeon_device *rdev,
16647ccd5a2cSjsg 					   struct radeon_ps *rps, int index,
16657ccd5a2cSjsg 					   union pplib_clock_info *clock_info)
16667ccd5a2cSjsg {
16677ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
16687ccd5a2cSjsg 	struct trinity_ps *ps = trinity_get_ps(rps);
16697ccd5a2cSjsg 	struct trinity_pl *pl = &ps->levels[index];
16707ccd5a2cSjsg 	u32 sclk;
16717ccd5a2cSjsg 
16727ccd5a2cSjsg 	sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
16737ccd5a2cSjsg 	sclk |= clock_info->sumo.ucEngineClockHigh << 16;
16747ccd5a2cSjsg 	pl->sclk = sclk;
16757ccd5a2cSjsg 	pl->vddc_index = clock_info->sumo.vddcIndex;
16767ccd5a2cSjsg 
16777ccd5a2cSjsg 	ps->num_levels = index + 1;
16787ccd5a2cSjsg 
16797ccd5a2cSjsg 	if (pi->enable_sclk_ds) {
16807ccd5a2cSjsg 		pl->ds_divider_index = 5;
16817ccd5a2cSjsg 		pl->ss_divider_index = 5;
16827ccd5a2cSjsg 	}
16837ccd5a2cSjsg }
16847ccd5a2cSjsg 
trinity_parse_power_table(struct radeon_device * rdev)16857ccd5a2cSjsg static int trinity_parse_power_table(struct radeon_device *rdev)
16867ccd5a2cSjsg {
16877ccd5a2cSjsg 	struct radeon_mode_info *mode_info = &rdev->mode_info;
16887ccd5a2cSjsg 	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
16897ccd5a2cSjsg 	union pplib_power_state *power_state;
16907ccd5a2cSjsg 	int i, j, k, non_clock_array_index, clock_array_index;
16917ccd5a2cSjsg 	union pplib_clock_info *clock_info;
16927ccd5a2cSjsg 	struct _StateArray *state_array;
16937ccd5a2cSjsg 	struct _ClockInfoArray *clock_info_array;
16947ccd5a2cSjsg 	struct _NonClockInfoArray *non_clock_info_array;
16957ccd5a2cSjsg 	union power_info *power_info;
16967ccd5a2cSjsg 	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
16977ccd5a2cSjsg 	u16 data_offset;
16987ccd5a2cSjsg 	u8 frev, crev;
16997ccd5a2cSjsg 	u8 *power_state_offset;
17007ccd5a2cSjsg 	struct sumo_ps *ps;
17017ccd5a2cSjsg 
17027ccd5a2cSjsg 	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
17037ccd5a2cSjsg 				   &frev, &crev, &data_offset))
17047ccd5a2cSjsg 		return -EINVAL;
17057ccd5a2cSjsg 	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
17067ccd5a2cSjsg 
17077ccd5a2cSjsg 	state_array = (struct _StateArray *)
17087ccd5a2cSjsg 		(mode_info->atom_context->bios + data_offset +
17097ccd5a2cSjsg 		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
17107ccd5a2cSjsg 	clock_info_array = (struct _ClockInfoArray *)
17117ccd5a2cSjsg 		(mode_info->atom_context->bios + data_offset +
17127ccd5a2cSjsg 		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
17137ccd5a2cSjsg 	non_clock_info_array = (struct _NonClockInfoArray *)
17147ccd5a2cSjsg 		(mode_info->atom_context->bios + data_offset +
17157ccd5a2cSjsg 		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
17167ccd5a2cSjsg 
17177f4dd379Sjsg 	rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries,
17187f4dd379Sjsg 				  sizeof(struct radeon_ps),
17197f4dd379Sjsg 				  GFP_KERNEL);
17207ccd5a2cSjsg 	if (!rdev->pm.dpm.ps)
17217ccd5a2cSjsg 		return -ENOMEM;
17227ccd5a2cSjsg 	power_state_offset = (u8 *)state_array->states;
17237ccd5a2cSjsg 	for (i = 0; i < state_array->ucNumEntries; i++) {
17247ccd5a2cSjsg 		u8 *idx;
17257ccd5a2cSjsg 		power_state = (union pplib_power_state *)power_state_offset;
17267ccd5a2cSjsg 		non_clock_array_index = power_state->v2.nonClockInfoIndex;
17277ccd5a2cSjsg 		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
17287ccd5a2cSjsg 			&non_clock_info_array->nonClockInfo[non_clock_array_index];
1729*6ee266b0Sjsg 		if (!rdev->pm.power_state[i].clock_info) {
1730*6ee266b0Sjsg 			kfree(rdev->pm.dpm.ps);
17317ccd5a2cSjsg 			return -EINVAL;
1732*6ee266b0Sjsg 		}
17337ccd5a2cSjsg 		ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
17347ccd5a2cSjsg 		if (ps == NULL) {
17357ccd5a2cSjsg 			kfree(rdev->pm.dpm.ps);
17367ccd5a2cSjsg 			return -ENOMEM;
17377ccd5a2cSjsg 		}
17387ccd5a2cSjsg 		rdev->pm.dpm.ps[i].ps_priv = ps;
17397ccd5a2cSjsg 		k = 0;
17407ccd5a2cSjsg 		idx = (u8 *)&power_state->v2.clockInfoIndex[0];
17417ccd5a2cSjsg 		for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
17427ccd5a2cSjsg 			clock_array_index = idx[j];
17437ccd5a2cSjsg 			if (clock_array_index >= clock_info_array->ucNumEntries)
17447ccd5a2cSjsg 				continue;
17457ccd5a2cSjsg 			if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
17467ccd5a2cSjsg 				break;
17477ccd5a2cSjsg 			clock_info = (union pplib_clock_info *)
17487ccd5a2cSjsg 				((u8 *)&clock_info_array->clockInfo[0] +
17497ccd5a2cSjsg 				 (clock_array_index * clock_info_array->ucEntrySize));
17507ccd5a2cSjsg 			trinity_parse_pplib_clock_info(rdev,
17517ccd5a2cSjsg 						       &rdev->pm.dpm.ps[i], k,
17527ccd5a2cSjsg 						       clock_info);
17537ccd5a2cSjsg 			k++;
17547ccd5a2cSjsg 		}
17557ccd5a2cSjsg 		trinity_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
17567ccd5a2cSjsg 						   non_clock_info,
17577ccd5a2cSjsg 						   non_clock_info_array->ucEntrySize);
17587ccd5a2cSjsg 		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
17597ccd5a2cSjsg 	}
17607ccd5a2cSjsg 	rdev->pm.dpm.num_ps = state_array->ucNumEntries;
17617ccd5a2cSjsg 
17627ccd5a2cSjsg 	/* fill in the vce power states */
17637ccd5a2cSjsg 	for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
17647ccd5a2cSjsg 		u32 sclk;
17657ccd5a2cSjsg 		clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
17667ccd5a2cSjsg 		clock_info = (union pplib_clock_info *)
17677ccd5a2cSjsg 			&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
17687ccd5a2cSjsg 		sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
17697ccd5a2cSjsg 		sclk |= clock_info->sumo.ucEngineClockHigh << 16;
17707ccd5a2cSjsg 		rdev->pm.dpm.vce_states[i].sclk = sclk;
17717ccd5a2cSjsg 		rdev->pm.dpm.vce_states[i].mclk = 0;
17727ccd5a2cSjsg 	}
17737ccd5a2cSjsg 
17747ccd5a2cSjsg 	return 0;
17757ccd5a2cSjsg }
17767ccd5a2cSjsg 
17777ccd5a2cSjsg union igp_info {
17787ccd5a2cSjsg 	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
17797ccd5a2cSjsg 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
17807ccd5a2cSjsg 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
17817ccd5a2cSjsg 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
17827ccd5a2cSjsg 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
17837ccd5a2cSjsg };
17847ccd5a2cSjsg 
trinity_convert_did_to_freq(struct radeon_device * rdev,u8 did)17857ccd5a2cSjsg static u32 trinity_convert_did_to_freq(struct radeon_device *rdev, u8 did)
17867ccd5a2cSjsg {
17877ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
17887ccd5a2cSjsg 	u32 divider;
17897ccd5a2cSjsg 
17907ccd5a2cSjsg 	if (did >= 8 && did <= 0x3f)
17917ccd5a2cSjsg 		divider = did * 25;
17927ccd5a2cSjsg 	else if (did > 0x3f && did <= 0x5f)
17937ccd5a2cSjsg 		divider = (did - 64) * 50 + 1600;
17947ccd5a2cSjsg 	else if (did > 0x5f && did <= 0x7e)
17957ccd5a2cSjsg 		divider = (did - 96) * 100 + 3200;
17967ccd5a2cSjsg 	else if (did == 0x7f)
17977ccd5a2cSjsg 		divider = 128 * 100;
17987ccd5a2cSjsg 	else
17997ccd5a2cSjsg 		return 10000;
18007ccd5a2cSjsg 
18017ccd5a2cSjsg 	return ((pi->sys_info.dentist_vco_freq * 100) + (divider - 1)) / divider;
18027ccd5a2cSjsg }
18037ccd5a2cSjsg 
trinity_parse_sys_info_table(struct radeon_device * rdev)18047ccd5a2cSjsg static int trinity_parse_sys_info_table(struct radeon_device *rdev)
18057ccd5a2cSjsg {
18067ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
18077ccd5a2cSjsg 	struct radeon_mode_info *mode_info = &rdev->mode_info;
18087ccd5a2cSjsg 	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
18097ccd5a2cSjsg 	union igp_info *igp_info;
18107ccd5a2cSjsg 	u8 frev, crev;
18117ccd5a2cSjsg 	u16 data_offset;
18127ccd5a2cSjsg 	int i;
18137ccd5a2cSjsg 
18147ccd5a2cSjsg 	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
18157ccd5a2cSjsg 				   &frev, &crev, &data_offset)) {
18167ccd5a2cSjsg 		igp_info = (union igp_info *)(mode_info->atom_context->bios +
18177ccd5a2cSjsg 					      data_offset);
18187ccd5a2cSjsg 
18197ccd5a2cSjsg 		if (crev != 7) {
18207ccd5a2cSjsg 			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
18217ccd5a2cSjsg 			return -EINVAL;
18227ccd5a2cSjsg 		}
18237ccd5a2cSjsg 		pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock);
18247ccd5a2cSjsg 		pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock);
18257ccd5a2cSjsg 		pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock);
18267ccd5a2cSjsg 		pi->sys_info.dentist_vco_freq = le32_to_cpu(igp_info->info_7.ulDentistVCOFreq);
18277ccd5a2cSjsg 		pi->sys_info.bootup_nb_voltage_index =
18287ccd5a2cSjsg 			le16_to_cpu(igp_info->info_7.usBootUpNBVoltage);
18297ccd5a2cSjsg 		if (igp_info->info_7.ucHtcTmpLmt == 0)
18307ccd5a2cSjsg 			pi->sys_info.htc_tmp_lmt = 203;
18317ccd5a2cSjsg 		else
18327ccd5a2cSjsg 			pi->sys_info.htc_tmp_lmt = igp_info->info_7.ucHtcTmpLmt;
18337ccd5a2cSjsg 		if (igp_info->info_7.ucHtcHystLmt == 0)
18347ccd5a2cSjsg 			pi->sys_info.htc_hyst_lmt = 5;
18357ccd5a2cSjsg 		else
18367ccd5a2cSjsg 			pi->sys_info.htc_hyst_lmt = igp_info->info_7.ucHtcHystLmt;
18377ccd5a2cSjsg 		if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
18387ccd5a2cSjsg 			DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
18397ccd5a2cSjsg 		}
18407ccd5a2cSjsg 
18417ccd5a2cSjsg 		if (pi->enable_nbps_policy)
18427ccd5a2cSjsg 			pi->sys_info.nb_dpm_enable = igp_info->info_7.ucNBDPMEnable;
18437ccd5a2cSjsg 		else
18447ccd5a2cSjsg 			pi->sys_info.nb_dpm_enable = 0;
18457ccd5a2cSjsg 
18467ccd5a2cSjsg 		for (i = 0; i < TRINITY_NUM_NBPSTATES; i++) {
18477ccd5a2cSjsg 			pi->sys_info.nbp_mclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateMemclkFreq[i]);
18487ccd5a2cSjsg 			pi->sys_info.nbp_nclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateNClkFreq[i]);
18497ccd5a2cSjsg 		}
18507ccd5a2cSjsg 
18517ccd5a2cSjsg 		pi->sys_info.nbp_voltage_index[0] = le16_to_cpu(igp_info->info_7.usNBP0Voltage);
18527ccd5a2cSjsg 		pi->sys_info.nbp_voltage_index[1] = le16_to_cpu(igp_info->info_7.usNBP1Voltage);
18537ccd5a2cSjsg 		pi->sys_info.nbp_voltage_index[2] = le16_to_cpu(igp_info->info_7.usNBP2Voltage);
18547ccd5a2cSjsg 		pi->sys_info.nbp_voltage_index[3] = le16_to_cpu(igp_info->info_7.usNBP3Voltage);
18557ccd5a2cSjsg 
18567ccd5a2cSjsg 		if (!pi->sys_info.nb_dpm_enable) {
18577ccd5a2cSjsg 			for (i = 1; i < TRINITY_NUM_NBPSTATES; i++) {
18587ccd5a2cSjsg 				pi->sys_info.nbp_mclk[i] = pi->sys_info.nbp_mclk[0];
18597ccd5a2cSjsg 				pi->sys_info.nbp_nclk[i] = pi->sys_info.nbp_nclk[0];
18607ccd5a2cSjsg 				pi->sys_info.nbp_voltage_index[i] = pi->sys_info.nbp_voltage_index[0];
18617ccd5a2cSjsg 			}
18627ccd5a2cSjsg 		}
18637ccd5a2cSjsg 
18647ccd5a2cSjsg 		pi->sys_info.uma_channel_number = igp_info->info_7.ucUMAChannelNumber;
18657ccd5a2cSjsg 
18667ccd5a2cSjsg 		sumo_construct_sclk_voltage_mapping_table(rdev,
18677ccd5a2cSjsg 							  &pi->sys_info.sclk_voltage_mapping_table,
18687ccd5a2cSjsg 							  igp_info->info_7.sAvail_SCLK);
18697ccd5a2cSjsg 		sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
18707ccd5a2cSjsg 						 igp_info->info_7.sAvail_SCLK);
18717ccd5a2cSjsg 
18727ccd5a2cSjsg 		pi->sys_info.uvd_clock_table_entries[0].vclk_did =
18737ccd5a2cSjsg 			igp_info->info_7.ucDPMState0VclkFid;
18747ccd5a2cSjsg 		pi->sys_info.uvd_clock_table_entries[1].vclk_did =
18757ccd5a2cSjsg 			igp_info->info_7.ucDPMState1VclkFid;
18767ccd5a2cSjsg 		pi->sys_info.uvd_clock_table_entries[2].vclk_did =
18777ccd5a2cSjsg 			igp_info->info_7.ucDPMState2VclkFid;
18787ccd5a2cSjsg 		pi->sys_info.uvd_clock_table_entries[3].vclk_did =
18797ccd5a2cSjsg 			igp_info->info_7.ucDPMState3VclkFid;
18807ccd5a2cSjsg 
18817ccd5a2cSjsg 		pi->sys_info.uvd_clock_table_entries[0].dclk_did =
18827ccd5a2cSjsg 			igp_info->info_7.ucDPMState0DclkFid;
18837ccd5a2cSjsg 		pi->sys_info.uvd_clock_table_entries[1].dclk_did =
18847ccd5a2cSjsg 			igp_info->info_7.ucDPMState1DclkFid;
18857ccd5a2cSjsg 		pi->sys_info.uvd_clock_table_entries[2].dclk_did =
18867ccd5a2cSjsg 			igp_info->info_7.ucDPMState2DclkFid;
18877ccd5a2cSjsg 		pi->sys_info.uvd_clock_table_entries[3].dclk_did =
18887ccd5a2cSjsg 			igp_info->info_7.ucDPMState3DclkFid;
18897ccd5a2cSjsg 
18907ccd5a2cSjsg 		for (i = 0; i < 4; i++) {
18917ccd5a2cSjsg 			pi->sys_info.uvd_clock_table_entries[i].vclk =
18927ccd5a2cSjsg 				trinity_convert_did_to_freq(rdev,
18937ccd5a2cSjsg 							    pi->sys_info.uvd_clock_table_entries[i].vclk_did);
18947ccd5a2cSjsg 			pi->sys_info.uvd_clock_table_entries[i].dclk =
18957ccd5a2cSjsg 				trinity_convert_did_to_freq(rdev,
18967ccd5a2cSjsg 							    pi->sys_info.uvd_clock_table_entries[i].dclk_did);
18977ccd5a2cSjsg 		}
18987ccd5a2cSjsg 
18997ccd5a2cSjsg 
19007ccd5a2cSjsg 
19017ccd5a2cSjsg 	}
19027ccd5a2cSjsg 	return 0;
19037ccd5a2cSjsg }
19047ccd5a2cSjsg 
trinity_dpm_init(struct radeon_device * rdev)19057ccd5a2cSjsg int trinity_dpm_init(struct radeon_device *rdev)
19067ccd5a2cSjsg {
19077ccd5a2cSjsg 	struct trinity_power_info *pi;
19087ccd5a2cSjsg 	int ret, i;
19097ccd5a2cSjsg 
19107ccd5a2cSjsg 	pi = kzalloc(sizeof(struct trinity_power_info), GFP_KERNEL);
19117ccd5a2cSjsg 	if (pi == NULL)
19127ccd5a2cSjsg 		return -ENOMEM;
19137ccd5a2cSjsg 	rdev->pm.dpm.priv = pi;
19147ccd5a2cSjsg 
19157ccd5a2cSjsg 	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
19167ccd5a2cSjsg 		pi->at[i] = TRINITY_AT_DFLT;
19177ccd5a2cSjsg 
19187ccd5a2cSjsg 	if (radeon_bapm == -1) {
19197ccd5a2cSjsg 		/* There are stability issues reported on with
19207ccd5a2cSjsg 		 * bapm enabled when switching between AC and battery
19217ccd5a2cSjsg 		 * power.  At the same time, some MSI boards hang
19227ccd5a2cSjsg 		 * if it's not enabled and dpm is enabled.  Just enable
19237ccd5a2cSjsg 		 * it for MSI boards right now.
19247ccd5a2cSjsg 		 */
19257ccd5a2cSjsg 		if (rdev->pdev->subsystem_vendor == 0x1462)
19267ccd5a2cSjsg 			pi->enable_bapm = true;
19277ccd5a2cSjsg 		else
19287ccd5a2cSjsg 			pi->enable_bapm = false;
19297ccd5a2cSjsg 	} else if (radeon_bapm == 0) {
19307ccd5a2cSjsg 		pi->enable_bapm = false;
19317ccd5a2cSjsg 	} else {
19327ccd5a2cSjsg 		pi->enable_bapm = true;
19337ccd5a2cSjsg 	}
19347ccd5a2cSjsg 	pi->enable_nbps_policy = true;
19357ccd5a2cSjsg 	pi->enable_sclk_ds = true;
19367ccd5a2cSjsg 	pi->enable_gfx_power_gating = true;
19377ccd5a2cSjsg 	pi->enable_gfx_clock_gating = true;
19387ccd5a2cSjsg 	pi->enable_mg_clock_gating = false;
19397ccd5a2cSjsg 	pi->enable_gfx_dynamic_mgpg = false;
19407ccd5a2cSjsg 	pi->override_dynamic_mgpg = false;
19417ccd5a2cSjsg 	pi->enable_auto_thermal_throttling = true;
19427ccd5a2cSjsg 	pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
19437ccd5a2cSjsg 	pi->uvd_dpm = true; /* ??? */
19447ccd5a2cSjsg 
19457ccd5a2cSjsg 	ret = trinity_parse_sys_info_table(rdev);
19467ccd5a2cSjsg 	if (ret)
19477ccd5a2cSjsg 		return ret;
19487ccd5a2cSjsg 
19497ccd5a2cSjsg 	trinity_construct_boot_state(rdev);
19507ccd5a2cSjsg 
19517ccd5a2cSjsg 	ret = r600_get_platform_caps(rdev);
19527ccd5a2cSjsg 	if (ret)
19537ccd5a2cSjsg 		return ret;
19547ccd5a2cSjsg 
19557ccd5a2cSjsg 	ret = r600_parse_extended_power_table(rdev);
19567ccd5a2cSjsg 	if (ret)
19577ccd5a2cSjsg 		return ret;
19587ccd5a2cSjsg 
19597ccd5a2cSjsg 	ret = trinity_parse_power_table(rdev);
19607ccd5a2cSjsg 	if (ret)
19617ccd5a2cSjsg 		return ret;
19627ccd5a2cSjsg 
19637ccd5a2cSjsg 	pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
19647ccd5a2cSjsg 	pi->enable_dpm = true;
19657ccd5a2cSjsg 
19667ccd5a2cSjsg 	return 0;
19677ccd5a2cSjsg }
19687ccd5a2cSjsg 
trinity_dpm_print_power_state(struct radeon_device * rdev,struct radeon_ps * rps)19697ccd5a2cSjsg void trinity_dpm_print_power_state(struct radeon_device *rdev,
19707ccd5a2cSjsg 				   struct radeon_ps *rps)
19717ccd5a2cSjsg {
19727ccd5a2cSjsg 	int i;
19737ccd5a2cSjsg 	struct trinity_ps *ps = trinity_get_ps(rps);
19747ccd5a2cSjsg 
19757ccd5a2cSjsg 	r600_dpm_print_class_info(rps->class, rps->class2);
19767ccd5a2cSjsg 	r600_dpm_print_cap_info(rps->caps);
19777ccd5a2cSjsg 	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
19787ccd5a2cSjsg 	for (i = 0; i < ps->num_levels; i++) {
19797ccd5a2cSjsg 		struct trinity_pl *pl = &ps->levels[i];
19807ccd5a2cSjsg 		printk("\t\tpower level %d    sclk: %u vddc: %u\n",
19817ccd5a2cSjsg 		       i, pl->sclk,
19827ccd5a2cSjsg 		       trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
19837ccd5a2cSjsg 	}
19847ccd5a2cSjsg 	r600_dpm_print_ps_status(rdev, rps);
19857ccd5a2cSjsg }
19867ccd5a2cSjsg 
trinity_dpm_debugfs_print_current_performance_level(struct radeon_device * rdev,struct seq_file * m)19877ccd5a2cSjsg void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
19887ccd5a2cSjsg 							 struct seq_file *m)
19897ccd5a2cSjsg {
19907ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
19917ccd5a2cSjsg 	struct radeon_ps *rps = &pi->current_rps;
19927ccd5a2cSjsg 	struct trinity_ps *ps = trinity_get_ps(rps);
19937ccd5a2cSjsg 	struct trinity_pl *pl;
19947ccd5a2cSjsg 	u32 current_index =
19957ccd5a2cSjsg 		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
19967ccd5a2cSjsg 		CURRENT_STATE_SHIFT;
19977ccd5a2cSjsg 
19987ccd5a2cSjsg 	if (current_index >= ps->num_levels) {
19997ccd5a2cSjsg 		seq_printf(m, "invalid dpm profile %d\n", current_index);
20007ccd5a2cSjsg 	} else {
20017ccd5a2cSjsg 		pl = &ps->levels[current_index];
20027ccd5a2cSjsg 		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
20037ccd5a2cSjsg 		seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
20047ccd5a2cSjsg 			   current_index, pl->sclk,
20057ccd5a2cSjsg 			   trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
20067ccd5a2cSjsg 	}
20077ccd5a2cSjsg }
20087ccd5a2cSjsg 
trinity_dpm_get_current_sclk(struct radeon_device * rdev)20097ccd5a2cSjsg u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev)
20107ccd5a2cSjsg {
20117ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
20127ccd5a2cSjsg 	struct radeon_ps *rps = &pi->current_rps;
20137ccd5a2cSjsg 	struct trinity_ps *ps = trinity_get_ps(rps);
20147ccd5a2cSjsg 	struct trinity_pl *pl;
20157ccd5a2cSjsg 	u32 current_index =
20167ccd5a2cSjsg 		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
20177ccd5a2cSjsg 		CURRENT_STATE_SHIFT;
20187ccd5a2cSjsg 
20197ccd5a2cSjsg 	if (current_index >= ps->num_levels) {
20207ccd5a2cSjsg 		return 0;
20217ccd5a2cSjsg 	} else {
20227ccd5a2cSjsg 		pl = &ps->levels[current_index];
20237ccd5a2cSjsg 		return pl->sclk;
20247ccd5a2cSjsg 	}
20257ccd5a2cSjsg }
20267ccd5a2cSjsg 
trinity_dpm_get_current_mclk(struct radeon_device * rdev)20277ccd5a2cSjsg u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev)
20287ccd5a2cSjsg {
20297ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
20307ccd5a2cSjsg 
20317ccd5a2cSjsg 	return pi->sys_info.bootup_uma_clk;
20327ccd5a2cSjsg }
20337ccd5a2cSjsg 
trinity_dpm_fini(struct radeon_device * rdev)20347ccd5a2cSjsg void trinity_dpm_fini(struct radeon_device *rdev)
20357ccd5a2cSjsg {
20367ccd5a2cSjsg 	int i;
20377ccd5a2cSjsg 
20387ccd5a2cSjsg 	trinity_cleanup_asic(rdev); /* ??? */
20397ccd5a2cSjsg 
20407ccd5a2cSjsg 	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
20417ccd5a2cSjsg 		kfree(rdev->pm.dpm.ps[i].ps_priv);
20427ccd5a2cSjsg 	}
20437ccd5a2cSjsg 	kfree(rdev->pm.dpm.ps);
20447ccd5a2cSjsg 	kfree(rdev->pm.dpm.priv);
20457ccd5a2cSjsg 	r600_free_extended_power_table(rdev);
20467ccd5a2cSjsg }
20477ccd5a2cSjsg 
trinity_dpm_get_sclk(struct radeon_device * rdev,bool low)20487ccd5a2cSjsg u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
20497ccd5a2cSjsg {
20507ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
20517ccd5a2cSjsg 	struct trinity_ps *requested_state = trinity_get_ps(&pi->requested_rps);
20527ccd5a2cSjsg 
20537ccd5a2cSjsg 	if (low)
20547ccd5a2cSjsg 		return requested_state->levels[0].sclk;
20557ccd5a2cSjsg 	else
20567ccd5a2cSjsg 		return requested_state->levels[requested_state->num_levels - 1].sclk;
20577ccd5a2cSjsg }
20587ccd5a2cSjsg 
trinity_dpm_get_mclk(struct radeon_device * rdev,bool low)20597ccd5a2cSjsg u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low)
20607ccd5a2cSjsg {
20617ccd5a2cSjsg 	struct trinity_power_info *pi = trinity_get_pi(rdev);
20627ccd5a2cSjsg 
20637ccd5a2cSjsg 	return pi->sys_info.bootup_uma_clk;
20647ccd5a2cSjsg }
2065