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, ÷rs);
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, ÷rs);
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, ÷rs);
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