LCOV - code coverage report
Current view: top level - dev/pci/drm/radeon - trinity_dpm.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1060 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 90 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2012 Advanced Micro Devices, Inc.
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the "Software"),
       6             :  * to deal in the Software without restriction, including without limitation
       7             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       8             :  * and/or sell copies of the Software, and to permit persons to whom the
       9             :  * Software is furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      17             :  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
      18             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      19             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      20             :  * OTHER DEALINGS IN THE SOFTWARE.
      21             :  *
      22             :  */
      23             : 
      24             : #include <dev/pci/drm/drmP.h>
      25             : #include "radeon.h"
      26             : #include "radeon_asic.h"
      27             : #include "trinityd.h"
      28             : #include "r600_dpm.h"
      29             : #include "trinity_dpm.h"
      30             : 
      31             : #define TRINITY_MAX_DEEPSLEEP_DIVIDER_ID 5
      32             : #define TRINITY_MINIMUM_ENGINE_CLOCK 800
      33             : #define SCLK_MIN_DIV_INTV_SHIFT     12
      34             : #define TRINITY_DISPCLK_BYPASS_THRESHOLD 10000
      35             : 
      36             : #ifndef TRINITY_MGCG_SEQUENCE
      37             : #define TRINITY_MGCG_SEQUENCE  100
      38             : 
      39             : static const u32 trinity_mgcg_shls_default[] =
      40             : {
      41             :         /* Register, Value, Mask */
      42             :         0x0000802c, 0xc0000000, 0xffffffff,
      43             :         0x00003fc4, 0xc0000000, 0xffffffff,
      44             :         0x00005448, 0x00000100, 0xffffffff,
      45             :         0x000055e4, 0x00000100, 0xffffffff,
      46             :         0x0000160c, 0x00000100, 0xffffffff,
      47             :         0x00008984, 0x06000100, 0xffffffff,
      48             :         0x0000c164, 0x00000100, 0xffffffff,
      49             :         0x00008a18, 0x00000100, 0xffffffff,
      50             :         0x0000897c, 0x06000100, 0xffffffff,
      51             :         0x00008b28, 0x00000100, 0xffffffff,
      52             :         0x00009144, 0x00800200, 0xffffffff,
      53             :         0x00009a60, 0x00000100, 0xffffffff,
      54             :         0x00009868, 0x00000100, 0xffffffff,
      55             :         0x00008d58, 0x00000100, 0xffffffff,
      56             :         0x00009510, 0x00000100, 0xffffffff,
      57             :         0x0000949c, 0x00000100, 0xffffffff,
      58             :         0x00009654, 0x00000100, 0xffffffff,
      59             :         0x00009030, 0x00000100, 0xffffffff,
      60             :         0x00009034, 0x00000100, 0xffffffff,
      61             :         0x00009038, 0x00000100, 0xffffffff,
      62             :         0x0000903c, 0x00000100, 0xffffffff,
      63             :         0x00009040, 0x00000100, 0xffffffff,
      64             :         0x0000a200, 0x00000100, 0xffffffff,
      65             :         0x0000a204, 0x00000100, 0xffffffff,
      66             :         0x0000a208, 0x00000100, 0xffffffff,
      67             :         0x0000a20c, 0x00000100, 0xffffffff,
      68             :         0x00009744, 0x00000100, 0xffffffff,
      69             :         0x00003f80, 0x00000100, 0xffffffff,
      70             :         0x0000a210, 0x00000100, 0xffffffff,
      71             :         0x0000a214, 0x00000100, 0xffffffff,
      72             :         0x000004d8, 0x00000100, 0xffffffff,
      73             :         0x00009664, 0x00000100, 0xffffffff,
      74             :         0x00009698, 0x00000100, 0xffffffff,
      75             :         0x000004d4, 0x00000200, 0xffffffff,
      76             :         0x000004d0, 0x00000000, 0xffffffff,
      77             :         0x000030cc, 0x00000104, 0xffffffff,
      78             :         0x0000d0c0, 0x00000100, 0xffffffff,
      79             :         0x0000d8c0, 0x00000100, 0xffffffff,
      80             :         0x0000951c, 0x00010000, 0xffffffff,
      81             :         0x00009160, 0x00030002, 0xffffffff,
      82             :         0x00009164, 0x00050004, 0xffffffff,
      83             :         0x00009168, 0x00070006, 0xffffffff,
      84             :         0x00009178, 0x00070000, 0xffffffff,
      85             :         0x0000917c, 0x00030002, 0xffffffff,
      86             :         0x00009180, 0x00050004, 0xffffffff,
      87             :         0x0000918c, 0x00010006, 0xffffffff,
      88             :         0x00009190, 0x00090008, 0xffffffff,
      89             :         0x00009194, 0x00070000, 0xffffffff,
      90             :         0x00009198, 0x00030002, 0xffffffff,
      91             :         0x0000919c, 0x00050004, 0xffffffff,
      92             :         0x000091a8, 0x00010006, 0xffffffff,
      93             :         0x000091ac, 0x00090008, 0xffffffff,
      94             :         0x000091b0, 0x00070000, 0xffffffff,
      95             :         0x000091b4, 0x00030002, 0xffffffff,
      96             :         0x000091b8, 0x00050004, 0xffffffff,
      97             :         0x000091c4, 0x00010006, 0xffffffff,
      98             :         0x000091c8, 0x00090008, 0xffffffff,
      99             :         0x000091cc, 0x00070000, 0xffffffff,
     100             :         0x000091d0, 0x00030002, 0xffffffff,
     101             :         0x000091d4, 0x00050004, 0xffffffff,
     102             :         0x000091e0, 0x00010006, 0xffffffff,
     103             :         0x000091e4, 0x00090008, 0xffffffff,
     104             :         0x000091e8, 0x00000000, 0xffffffff,
     105             :         0x000091ec, 0x00070000, 0xffffffff,
     106             :         0x000091f0, 0x00030002, 0xffffffff,
     107             :         0x000091f4, 0x00050004, 0xffffffff,
     108             :         0x00009200, 0x00010006, 0xffffffff,
     109             :         0x00009204, 0x00090008, 0xffffffff,
     110             :         0x00009208, 0x00070000, 0xffffffff,
     111             :         0x0000920c, 0x00030002, 0xffffffff,
     112             :         0x00009210, 0x00050004, 0xffffffff,
     113             :         0x0000921c, 0x00010006, 0xffffffff,
     114             :         0x00009220, 0x00090008, 0xffffffff,
     115             :         0x00009294, 0x00000000, 0xffffffff
     116             : };
     117             : 
     118             : static const u32 trinity_mgcg_shls_enable[] =
     119             : {
     120             :         /* Register, Value, Mask */
     121             :         0x0000802c, 0xc0000000, 0xffffffff,
     122             :         0x000008f8, 0x00000000, 0xffffffff,
     123             :         0x000008fc, 0x00000000, 0x000133FF,
     124             :         0x000008f8, 0x00000001, 0xffffffff,
     125             :         0x000008fc, 0x00000000, 0xE00B03FC,
     126             :         0x00009150, 0x96944200, 0xffffffff
     127             : };
     128             : 
     129             : static const u32 trinity_mgcg_shls_disable[] =
     130             : {
     131             :         /* Register, Value, Mask */
     132             :         0x0000802c, 0xc0000000, 0xffffffff,
     133             :         0x00009150, 0x00600000, 0xffffffff,
     134             :         0x000008f8, 0x00000000, 0xffffffff,
     135             :         0x000008fc, 0xffffffff, 0x000133FF,
     136             :         0x000008f8, 0x00000001, 0xffffffff,
     137             :         0x000008fc, 0xffffffff, 0xE00B03FC
     138             : };
     139             : #endif
     140             : 
     141             : #ifndef TRINITY_SYSLS_SEQUENCE
     142             : #define TRINITY_SYSLS_SEQUENCE  100
     143             : 
     144             : static const u32 trinity_sysls_default[] =
     145             : {
     146             :         /* Register, Value, Mask */
     147             :         0x000055e8, 0x00000000, 0xffffffff,
     148             :         0x0000d0bc, 0x00000000, 0xffffffff,
     149             :         0x0000d8bc, 0x00000000, 0xffffffff,
     150             :         0x000015c0, 0x000c1401, 0xffffffff,
     151             :         0x0000264c, 0x000c0400, 0xffffffff,
     152             :         0x00002648, 0x000c0400, 0xffffffff,
     153             :         0x00002650, 0x000c0400, 0xffffffff,
     154             :         0x000020b8, 0x000c0400, 0xffffffff,
     155             :         0x000020bc, 0x000c0400, 0xffffffff,
     156             :         0x000020c0, 0x000c0c80, 0xffffffff,
     157             :         0x0000f4a0, 0x000000c0, 0xffffffff,
     158             :         0x0000f4a4, 0x00680fff, 0xffffffff,
     159             :         0x00002f50, 0x00000404, 0xffffffff,
     160             :         0x000004c8, 0x00000001, 0xffffffff,
     161             :         0x0000641c, 0x00000000, 0xffffffff,
     162             :         0x00000c7c, 0x00000000, 0xffffffff,
     163             :         0x00006dfc, 0x00000000, 0xffffffff
     164             : };
     165             : 
     166             : static const u32 trinity_sysls_disable[] =
     167             : {
     168             :         /* Register, Value, Mask */
     169             :         0x0000d0c0, 0x00000000, 0xffffffff,
     170             :         0x0000d8c0, 0x00000000, 0xffffffff,
     171             :         0x000055e8, 0x00000000, 0xffffffff,
     172             :         0x0000d0bc, 0x00000000, 0xffffffff,
     173             :         0x0000d8bc, 0x00000000, 0xffffffff,
     174             :         0x000015c0, 0x00041401, 0xffffffff,
     175             :         0x0000264c, 0x00040400, 0xffffffff,
     176             :         0x00002648, 0x00040400, 0xffffffff,
     177             :         0x00002650, 0x00040400, 0xffffffff,
     178             :         0x000020b8, 0x00040400, 0xffffffff,
     179             :         0x000020bc, 0x00040400, 0xffffffff,
     180             :         0x000020c0, 0x00040c80, 0xffffffff,
     181             :         0x0000f4a0, 0x000000c0, 0xffffffff,
     182             :         0x0000f4a4, 0x00680000, 0xffffffff,
     183             :         0x00002f50, 0x00000404, 0xffffffff,
     184             :         0x000004c8, 0x00000001, 0xffffffff,
     185             :         0x0000641c, 0x00007ffd, 0xffffffff,
     186             :         0x00000c7c, 0x0000ff00, 0xffffffff,
     187             :         0x00006dfc, 0x0000007f, 0xffffffff
     188             : };
     189             : 
     190             : static const u32 trinity_sysls_enable[] =
     191             : {
     192             :         /* Register, Value, Mask */
     193             :         0x000055e8, 0x00000001, 0xffffffff,
     194             :         0x0000d0bc, 0x00000100, 0xffffffff,
     195             :         0x0000d8bc, 0x00000100, 0xffffffff,
     196             :         0x000015c0, 0x000c1401, 0xffffffff,
     197             :         0x0000264c, 0x000c0400, 0xffffffff,
     198             :         0x00002648, 0x000c0400, 0xffffffff,
     199             :         0x00002650, 0x000c0400, 0xffffffff,
     200             :         0x000020b8, 0x000c0400, 0xffffffff,
     201             :         0x000020bc, 0x000c0400, 0xffffffff,
     202             :         0x000020c0, 0x000c0c80, 0xffffffff,
     203             :         0x0000f4a0, 0x000000c0, 0xffffffff,
     204             :         0x0000f4a4, 0x00680fff, 0xffffffff,
     205             :         0x00002f50, 0x00000903, 0xffffffff,
     206             :         0x000004c8, 0x00000000, 0xffffffff,
     207             :         0x0000641c, 0x00000000, 0xffffffff,
     208             :         0x00000c7c, 0x00000000, 0xffffffff,
     209             :         0x00006dfc, 0x00000000, 0xffffffff
     210             : };
     211             : #endif
     212             : 
     213             : static const u32 trinity_override_mgpg_sequences[] =
     214             : {
     215             :         /* Register, Value */
     216             :         0x00000200, 0xE030032C,
     217             :         0x00000204, 0x00000FFF,
     218             :         0x00000200, 0xE0300058,
     219             :         0x00000204, 0x00030301,
     220             :         0x00000200, 0xE0300054,
     221             :         0x00000204, 0x500010FF,
     222             :         0x00000200, 0xE0300074,
     223             :         0x00000204, 0x00030301,
     224             :         0x00000200, 0xE0300070,
     225             :         0x00000204, 0x500010FF,
     226             :         0x00000200, 0xE0300090,
     227             :         0x00000204, 0x00030301,
     228             :         0x00000200, 0xE030008C,
     229             :         0x00000204, 0x500010FF,
     230             :         0x00000200, 0xE03000AC,
     231             :         0x00000204, 0x00030301,
     232             :         0x00000200, 0xE03000A8,
     233             :         0x00000204, 0x500010FF,
     234             :         0x00000200, 0xE03000C8,
     235             :         0x00000204, 0x00030301,
     236             :         0x00000200, 0xE03000C4,
     237             :         0x00000204, 0x500010FF,
     238             :         0x00000200, 0xE03000E4,
     239             :         0x00000204, 0x00030301,
     240             :         0x00000200, 0xE03000E0,
     241             :         0x00000204, 0x500010FF,
     242             :         0x00000200, 0xE0300100,
     243             :         0x00000204, 0x00030301,
     244             :         0x00000200, 0xE03000FC,
     245             :         0x00000204, 0x500010FF,
     246             :         0x00000200, 0xE0300058,
     247             :         0x00000204, 0x00030303,
     248             :         0x00000200, 0xE0300054,
     249             :         0x00000204, 0x600010FF,
     250             :         0x00000200, 0xE0300074,
     251             :         0x00000204, 0x00030303,
     252             :         0x00000200, 0xE0300070,
     253             :         0x00000204, 0x600010FF,
     254             :         0x00000200, 0xE0300090,
     255             :         0x00000204, 0x00030303,
     256             :         0x00000200, 0xE030008C,
     257             :         0x00000204, 0x600010FF,
     258             :         0x00000200, 0xE03000AC,
     259             :         0x00000204, 0x00030303,
     260             :         0x00000200, 0xE03000A8,
     261             :         0x00000204, 0x600010FF,
     262             :         0x00000200, 0xE03000C8,
     263             :         0x00000204, 0x00030303,
     264             :         0x00000200, 0xE03000C4,
     265             :         0x00000204, 0x600010FF,
     266             :         0x00000200, 0xE03000E4,
     267             :         0x00000204, 0x00030303,
     268             :         0x00000200, 0xE03000E0,
     269             :         0x00000204, 0x600010FF,
     270             :         0x00000200, 0xE0300100,
     271             :         0x00000204, 0x00030303,
     272             :         0x00000200, 0xE03000FC,
     273             :         0x00000204, 0x600010FF,
     274             :         0x00000200, 0xE0300058,
     275             :         0x00000204, 0x00030303,
     276             :         0x00000200, 0xE0300054,
     277             :         0x00000204, 0x700010FF,
     278             :         0x00000200, 0xE0300074,
     279             :         0x00000204, 0x00030303,
     280             :         0x00000200, 0xE0300070,
     281             :         0x00000204, 0x700010FF,
     282             :         0x00000200, 0xE0300090,
     283             :         0x00000204, 0x00030303,
     284             :         0x00000200, 0xE030008C,
     285             :         0x00000204, 0x700010FF,
     286             :         0x00000200, 0xE03000AC,
     287             :         0x00000204, 0x00030303,
     288             :         0x00000200, 0xE03000A8,
     289             :         0x00000204, 0x700010FF,
     290             :         0x00000200, 0xE03000C8,
     291             :         0x00000204, 0x00030303,
     292             :         0x00000200, 0xE03000C4,
     293             :         0x00000204, 0x700010FF,
     294             :         0x00000200, 0xE03000E4,
     295             :         0x00000204, 0x00030303,
     296             :         0x00000200, 0xE03000E0,
     297             :         0x00000204, 0x700010FF,
     298             :         0x00000200, 0xE0300100,
     299             :         0x00000204, 0x00030303,
     300             :         0x00000200, 0xE03000FC,
     301             :         0x00000204, 0x700010FF,
     302             :         0x00000200, 0xE0300058,
     303             :         0x00000204, 0x00010303,
     304             :         0x00000200, 0xE0300054,
     305             :         0x00000204, 0x800010FF,
     306             :         0x00000200, 0xE0300074,
     307             :         0x00000204, 0x00010303,
     308             :         0x00000200, 0xE0300070,
     309             :         0x00000204, 0x800010FF,
     310             :         0x00000200, 0xE0300090,
     311             :         0x00000204, 0x00010303,
     312             :         0x00000200, 0xE030008C,
     313             :         0x00000204, 0x800010FF,
     314             :         0x00000200, 0xE03000AC,
     315             :         0x00000204, 0x00010303,
     316             :         0x00000200, 0xE03000A8,
     317             :         0x00000204, 0x800010FF,
     318             :         0x00000200, 0xE03000C4,
     319             :         0x00000204, 0x800010FF,
     320             :         0x00000200, 0xE03000C8,
     321             :         0x00000204, 0x00010303,
     322             :         0x00000200, 0xE03000E4,
     323             :         0x00000204, 0x00010303,
     324             :         0x00000200, 0xE03000E0,
     325             :         0x00000204, 0x800010FF,
     326             :         0x00000200, 0xE0300100,
     327             :         0x00000204, 0x00010303,
     328             :         0x00000200, 0xE03000FC,
     329             :         0x00000204, 0x800010FF,
     330             :         0x00000200, 0x0001f198,
     331             :         0x00000204, 0x0003ffff,
     332             :         0x00000200, 0x0001f19C,
     333             :         0x00000204, 0x3fffffff,
     334             :         0x00000200, 0xE030032C,
     335             :         0x00000204, 0x00000000,
     336             : };
     337             : 
     338             : extern void vce_v1_0_enable_mgcg(struct radeon_device *rdev, bool enable);
     339             : static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
     340             :                                                    const u32 *seq, u32 count);
     341             : static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev);
     342             : static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
     343             :                                              struct radeon_ps *new_rps,
     344             :                                              struct radeon_ps *old_rps);
     345             : 
     346           0 : static struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
     347             : {
     348           0 :         struct trinity_ps *ps = rps->ps_priv;
     349             : 
     350           0 :         return ps;
     351             : }
     352             : 
     353           0 : static struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)
     354             : {
     355           0 :         struct trinity_power_info *pi = rdev->pm.dpm.priv;
     356             : 
     357           0 :         return pi;
     358             : }
     359             : 
     360           0 : static void trinity_gfx_powergating_initialize(struct radeon_device *rdev)
     361             : {
     362           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
     363           0 :         u32 p, u;
     364             :         u32 value;
     365           0 :         struct atom_clock_dividers dividers;
     366           0 :         u32 xclk = radeon_get_xclk(rdev);
     367             :         u32 sssd = 1;
     368             :         int ret;
     369           0 :         u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
     370             : 
     371           0 :         ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
     372             :                                              25000, false, &dividers);
     373           0 :         if (ret)
     374           0 :                 return;
     375             : 
     376           0 :         value = RREG32_SMC(GFX_POWER_GATING_CNTL);
     377           0 :         value &= ~(SSSD_MASK | PDS_DIV_MASK);
     378           0 :         if (sssd)
     379           0 :                 value |= SSSD(1);
     380           0 :         value |= PDS_DIV(dividers.post_div);
     381           0 :         WREG32_SMC(GFX_POWER_GATING_CNTL, value);
     382             : 
     383           0 :         r600_calculate_u_and_p(500, xclk, 16, &p, &u);
     384             : 
     385           0 :         WREG32(CG_PG_CTRL, SP(p) | SU(u));
     386             : 
     387           0 :         WREG32_P(CG_GIPOTS, CG_GIPOT(p), ~CG_GIPOT_MASK);
     388             : 
     389             :         /* XXX double check hw_rev */
     390           0 :         if (pi->override_dynamic_mgpg && (hw_rev == 0))
     391           0 :                 trinity_override_dynamic_mg_powergating(rdev);
     392             : 
     393           0 : }
     394             : 
     395             : #define CGCG_CGTT_LOCAL0_MASK       0xFFFF33FF
     396             : #define CGCG_CGTT_LOCAL1_MASK       0xFFFB0FFE
     397             : #define CGTS_SM_CTRL_REG_DISABLE    0x00600000
     398             : #define CGTS_SM_CTRL_REG_ENABLE     0x96944200
     399             : 
     400           0 : static void trinity_mg_clockgating_enable(struct radeon_device *rdev,
     401             :                                           bool enable)
     402             : {
     403             :         u32 local0;
     404             :         u32 local1;
     405             : 
     406           0 :         if (enable) {
     407           0 :                 local0 = RREG32_CG(CG_CGTT_LOCAL_0);
     408           0 :                 local1 = RREG32_CG(CG_CGTT_LOCAL_1);
     409             : 
     410           0 :                 WREG32_CG(CG_CGTT_LOCAL_0,
     411             :                           (0x00380000 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
     412           0 :                 WREG32_CG(CG_CGTT_LOCAL_1,
     413             :                           (0x0E000000 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
     414             : 
     415           0 :                 WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_ENABLE);
     416           0 :         } else {
     417           0 :                 WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_DISABLE);
     418             : 
     419           0 :                 local0 = RREG32_CG(CG_CGTT_LOCAL_0);
     420           0 :                 local1 = RREG32_CG(CG_CGTT_LOCAL_1);
     421             : 
     422           0 :                 WREG32_CG(CG_CGTT_LOCAL_0,
     423             :                           CGCG_CGTT_LOCAL0_MASK | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
     424           0 :                 WREG32_CG(CG_CGTT_LOCAL_1,
     425             :                           CGCG_CGTT_LOCAL1_MASK | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
     426             :         }
     427           0 : }
     428             : 
     429           0 : static void trinity_mg_clockgating_initialize(struct radeon_device *rdev)
     430             : {
     431             :         u32 count;
     432             :         const u32 *seq = NULL;
     433             : 
     434             :         seq = &trinity_mgcg_shls_default[0];
     435             :         count = sizeof(trinity_mgcg_shls_default) / (3 * sizeof(u32));
     436             : 
     437           0 :         trinity_program_clk_gating_hw_sequence(rdev, seq, count);
     438           0 : }
     439             : 
     440           0 : static void trinity_gfx_clockgating_enable(struct radeon_device *rdev,
     441             :                                            bool enable)
     442             : {
     443           0 :         if (enable) {
     444           0 :                 WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
     445           0 :         } else {
     446           0 :                 WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
     447           0 :                 WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
     448           0 :                 WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
     449           0 :                 RREG32(GB_ADDR_CONFIG);
     450             :         }
     451           0 : }
     452             : 
     453           0 : static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
     454             :                                                    const u32 *seq, u32 count)
     455             : {
     456           0 :         u32 i, length = count * 3;
     457             : 
     458           0 :         for (i = 0; i < length; i += 3)
     459           0 :                 WREG32_P(seq[i], seq[i+1], ~seq[i+2]);
     460           0 : }
     461             : 
     462           0 : static void trinity_program_override_mgpg_sequences(struct radeon_device *rdev,
     463             :                                                     const u32 *seq, u32 count)
     464             : {
     465           0 :         u32  i, length = count * 2;
     466             : 
     467           0 :         for (i = 0; i < length; i += 2)
     468           0 :                 WREG32(seq[i], seq[i+1]);
     469             : 
     470           0 : }
     471             : 
     472           0 : static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev)
     473             : {
     474             :         u32 count;
     475             :         const u32 *seq = NULL;
     476             : 
     477             :         seq = &trinity_override_mgpg_sequences[0];
     478             :         count = sizeof(trinity_override_mgpg_sequences) / (2 * sizeof(u32));
     479             : 
     480           0 :         trinity_program_override_mgpg_sequences(rdev, seq, count);
     481           0 : }
     482             : 
     483           0 : static void trinity_ls_clockgating_enable(struct radeon_device *rdev,
     484             :                                           bool enable)
     485             : {
     486             :         u32 count;
     487             :         const u32 *seq = NULL;
     488             : 
     489           0 :         if (enable) {
     490             :                 seq = &trinity_sysls_enable[0];
     491             :                 count = sizeof(trinity_sysls_enable) / (3 * sizeof(u32));
     492           0 :         } else {
     493             :                 seq = &trinity_sysls_disable[0];
     494             :                 count = sizeof(trinity_sysls_disable) / (3 * sizeof(u32));
     495             :         }
     496             : 
     497           0 :         trinity_program_clk_gating_hw_sequence(rdev, seq, count);
     498           0 : }
     499             : 
     500           0 : static void trinity_gfx_powergating_enable(struct radeon_device *rdev,
     501             :                                            bool enable)
     502             : {
     503           0 :         if (enable) {
     504           0 :                 if (RREG32_SMC(CC_SMU_TST_EFUSE1_MISC) & RB_BACKEND_DISABLE_MASK)
     505           0 :                         WREG32_SMC(SMU_SCRATCH_A, (RREG32_SMC(SMU_SCRATCH_A) | 0x01));
     506             : 
     507           0 :                 WREG32_P(SCLK_PWRMGT_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
     508           0 :         } else {
     509           0 :                 WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_PWR_DOWN_EN);
     510           0 :                 RREG32(GB_ADDR_CONFIG);
     511             :         }
     512           0 : }
     513             : 
     514           0 : static void trinity_gfx_dynamic_mgpg_enable(struct radeon_device *rdev,
     515             :                                             bool enable)
     516             : {
     517             :         u32 value;
     518             : 
     519           0 :         if (enable) {
     520           0 :                 value = RREG32_SMC(PM_I_CNTL_1);
     521           0 :                 value &= ~DS_PG_CNTL_MASK;
     522           0 :                 value |= DS_PG_CNTL(1);
     523           0 :                 WREG32_SMC(PM_I_CNTL_1, value);
     524             : 
     525           0 :                 value = RREG32_SMC(SMU_S_PG_CNTL);
     526           0 :                 value &= ~DS_PG_EN_MASK;
     527           0 :                 value |= DS_PG_EN(1);
     528           0 :                 WREG32_SMC(SMU_S_PG_CNTL, value);
     529           0 :         } else {
     530           0 :                 value = RREG32_SMC(SMU_S_PG_CNTL);
     531           0 :                 value &= ~DS_PG_EN_MASK;
     532           0 :                 WREG32_SMC(SMU_S_PG_CNTL, value);
     533             : 
     534           0 :                 value = RREG32_SMC(PM_I_CNTL_1);
     535           0 :                 value &= ~DS_PG_CNTL_MASK;
     536           0 :                 WREG32_SMC(PM_I_CNTL_1, value);
     537             :         }
     538             : 
     539           0 :         trinity_gfx_dynamic_mgpg_config(rdev);
     540             : 
     541           0 : }
     542             : 
     543           0 : static void trinity_enable_clock_power_gating(struct radeon_device *rdev)
     544             : {
     545           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
     546             : 
     547           0 :         if (pi->enable_gfx_clock_gating)
     548           0 :                 sumo_gfx_clockgating_initialize(rdev);
     549           0 :         if (pi->enable_mg_clock_gating)
     550           0 :                 trinity_mg_clockgating_initialize(rdev);
     551           0 :         if (pi->enable_gfx_power_gating)
     552           0 :                 trinity_gfx_powergating_initialize(rdev);
     553           0 :         if (pi->enable_mg_clock_gating) {
     554           0 :                 trinity_ls_clockgating_enable(rdev, true);
     555           0 :                 trinity_mg_clockgating_enable(rdev, true);
     556           0 :         }
     557           0 :         if (pi->enable_gfx_clock_gating)
     558           0 :                 trinity_gfx_clockgating_enable(rdev, true);
     559           0 :         if (pi->enable_gfx_dynamic_mgpg)
     560           0 :                 trinity_gfx_dynamic_mgpg_enable(rdev, true);
     561           0 :         if (pi->enable_gfx_power_gating)
     562           0 :                 trinity_gfx_powergating_enable(rdev, true);
     563           0 : }
     564             : 
     565           0 : static void trinity_disable_clock_power_gating(struct radeon_device *rdev)
     566             : {
     567           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
     568             : 
     569           0 :         if (pi->enable_gfx_power_gating)
     570           0 :                 trinity_gfx_powergating_enable(rdev, false);
     571           0 :         if (pi->enable_gfx_dynamic_mgpg)
     572           0 :                 trinity_gfx_dynamic_mgpg_enable(rdev, false);
     573           0 :         if (pi->enable_gfx_clock_gating)
     574           0 :                 trinity_gfx_clockgating_enable(rdev, false);
     575           0 :         if (pi->enable_mg_clock_gating) {
     576           0 :                 trinity_mg_clockgating_enable(rdev, false);
     577           0 :                 trinity_ls_clockgating_enable(rdev, false);
     578           0 :         }
     579           0 : }
     580             : 
     581           0 : static void trinity_set_divider_value(struct radeon_device *rdev,
     582             :                                       u32 index, u32 sclk)
     583             : {
     584           0 :         struct atom_clock_dividers  dividers;
     585             :         int ret;
     586             :         u32 value;
     587           0 :         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
     588             : 
     589           0 :         ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
     590             :                                              sclk, false, &dividers);
     591           0 :         if (ret)
     592           0 :                 return;
     593             : 
     594           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
     595           0 :         value &= ~CLK_DIVIDER_MASK;
     596           0 :         value |= CLK_DIVIDER(dividers.post_div);
     597           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
     598             : 
     599           0 :         ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
     600           0 :                                              sclk/2, false, &dividers);
     601           0 :         if (ret)
     602           0 :                 return;
     603             : 
     604           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix);
     605           0 :         value &= ~PD_SCLK_DIVIDER_MASK;
     606           0 :         value |= PD_SCLK_DIVIDER(dividers.post_div);
     607           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix, value);
     608           0 : }
     609             : 
     610           0 : static void trinity_set_ds_dividers(struct radeon_device *rdev,
     611             :                                     u32 index, u32 divider)
     612             : {
     613             :         u32 value;
     614           0 :         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
     615             : 
     616           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
     617           0 :         value &= ~DS_DIV_MASK;
     618           0 :         value |= DS_DIV(divider);
     619           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
     620           0 : }
     621             : 
     622           0 : static void trinity_set_ss_dividers(struct radeon_device *rdev,
     623             :                                     u32 index, u32 divider)
     624             : {
     625             :         u32 value;
     626           0 :         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
     627             : 
     628           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
     629           0 :         value &= ~DS_SH_DIV_MASK;
     630           0 :         value |= DS_SH_DIV(divider);
     631           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
     632           0 : }
     633             : 
     634           0 : static void trinity_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
     635             : {
     636           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
     637           0 :         u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid);
     638             :         u32 value;
     639           0 :         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
     640             : 
     641           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
     642           0 :         value &= ~VID_MASK;
     643           0 :         value |= VID(vid_7bit);
     644           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
     645             : 
     646           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
     647           0 :         value &= ~LVRT_MASK;
     648             :         value |= LVRT(0);
     649           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
     650           0 : }
     651             : 
     652           0 : static void trinity_set_allos_gnb_slow(struct radeon_device *rdev,
     653             :                                        u32 index, u32 gnb_slow)
     654             : {
     655             :         u32 value;
     656           0 :         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
     657             : 
     658           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
     659           0 :         value &= ~GNB_SLOW_MASK;
     660           0 :         value |= GNB_SLOW(gnb_slow);
     661           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
     662           0 : }
     663             : 
     664           0 : static void trinity_set_force_nbp_state(struct radeon_device *rdev,
     665             :                                         u32 index, u32 force_nbp_state)
     666             : {
     667             :         u32 value;
     668           0 :         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
     669             : 
     670           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
     671           0 :         value &= ~FORCE_NBPS1_MASK;
     672           0 :         value |= FORCE_NBPS1(force_nbp_state);
     673           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
     674           0 : }
     675             : 
     676           0 : static void trinity_set_display_wm(struct radeon_device *rdev,
     677             :                                    u32 index, u32 wm)
     678             : {
     679             :         u32 value;
     680           0 :         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
     681             : 
     682           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
     683           0 :         value &= ~DISPLAY_WM_MASK;
     684           0 :         value |= DISPLAY_WM(wm);
     685           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
     686           0 : }
     687             : 
     688           0 : static void trinity_set_vce_wm(struct radeon_device *rdev,
     689             :                                u32 index, u32 wm)
     690             : {
     691             :         u32 value;
     692           0 :         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
     693             : 
     694           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
     695           0 :         value &= ~VCE_WM_MASK;
     696           0 :         value |= VCE_WM(wm);
     697           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
     698           0 : }
     699             : 
     700           0 : static void trinity_set_at(struct radeon_device *rdev,
     701             :                            u32 index, u32 at)
     702             : {
     703             :         u32 value;
     704           0 :         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
     705             : 
     706           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix);
     707           0 :         value &= ~AT_MASK;
     708           0 :         value |= AT(at);
     709           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix, value);
     710           0 : }
     711             : 
     712           0 : static void trinity_program_power_level(struct radeon_device *rdev,
     713             :                                         struct trinity_pl *pl, u32 index)
     714             : {
     715           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
     716             : 
     717           0 :         if (index >= SUMO_MAX_HARDWARE_POWERLEVELS)
     718           0 :                 return;
     719             : 
     720           0 :         trinity_set_divider_value(rdev, index, pl->sclk);
     721           0 :         trinity_set_vid(rdev, index, pl->vddc_index);
     722           0 :         trinity_set_ss_dividers(rdev, index, pl->ss_divider_index);
     723           0 :         trinity_set_ds_dividers(rdev, index, pl->ds_divider_index);
     724           0 :         trinity_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
     725           0 :         trinity_set_force_nbp_state(rdev, index, pl->force_nbp_state);
     726           0 :         trinity_set_display_wm(rdev, index, pl->display_wm);
     727           0 :         trinity_set_vce_wm(rdev, index, pl->vce_wm);
     728           0 :         trinity_set_at(rdev, index, pi->at[index]);
     729           0 : }
     730             : 
     731           0 : static void trinity_power_level_enable_disable(struct radeon_device *rdev,
     732             :                                                u32 index, bool enable)
     733             : {
     734             :         u32 value;
     735           0 :         u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
     736             : 
     737           0 :         value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
     738           0 :         value &= ~STATE_VALID_MASK;
     739           0 :         if (enable)
     740           0 :                 value |= STATE_VALID(1);
     741           0 :         WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
     742           0 : }
     743             : 
     744           0 : static bool trinity_dpm_enabled(struct radeon_device *rdev)
     745             : {
     746           0 :         if (RREG32_SMC(SMU_SCLK_DPM_CNTL) & SCLK_DPM_EN(1))
     747           0 :                 return true;
     748             :         else
     749           0 :                 return false;
     750           0 : }
     751             : 
     752           0 : static void trinity_start_dpm(struct radeon_device *rdev)
     753             : {
     754           0 :         u32 value = RREG32_SMC(SMU_SCLK_DPM_CNTL);
     755             : 
     756           0 :         value &= ~(SCLK_DPM_EN_MASK | SCLK_DPM_BOOT_STATE_MASK | VOLTAGE_CHG_EN_MASK);
     757           0 :         value |= SCLK_DPM_EN(1) | SCLK_DPM_BOOT_STATE(0) | VOLTAGE_CHG_EN(1);
     758           0 :         WREG32_SMC(SMU_SCLK_DPM_CNTL, value);
     759             : 
     760           0 :         WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
     761           0 :         WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~EN);
     762             : 
     763           0 :         trinity_dpm_config(rdev, true);
     764           0 : }
     765             : 
     766           0 : static void trinity_wait_for_dpm_enabled(struct radeon_device *rdev)
     767             : {
     768             :         int i;
     769             : 
     770           0 :         for (i = 0; i < rdev->usec_timeout; i++) {
     771           0 :                 if (RREG32(SCLK_PWRMGT_CNTL) & DYNAMIC_PM_EN)
     772             :                         break;
     773           0 :                 udelay(1);
     774             :         }
     775           0 :         for (i = 0; i < rdev->usec_timeout; i++) {
     776           0 :                 if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_STATE_MASK) == 0)
     777             :                         break;
     778           0 :                 udelay(1);
     779             :         }
     780           0 :         for (i = 0; i < rdev->usec_timeout; i++) {
     781           0 :                 if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
     782             :                         break;
     783           0 :                 udelay(1);
     784             :         }
     785           0 : }
     786             : 
     787           0 : static void trinity_stop_dpm(struct radeon_device *rdev)
     788             : {
     789             :         u32 sclk_dpm_cntl;
     790             : 
     791           0 :         WREG32_P(CG_CG_VOLTAGE_CNTL, EN, ~EN);
     792             : 
     793           0 :         sclk_dpm_cntl = RREG32_SMC(SMU_SCLK_DPM_CNTL);
     794           0 :         sclk_dpm_cntl &= ~(SCLK_DPM_EN_MASK | VOLTAGE_CHG_EN_MASK);
     795           0 :         WREG32_SMC(SMU_SCLK_DPM_CNTL, sclk_dpm_cntl);
     796             : 
     797           0 :         trinity_dpm_config(rdev, false);
     798           0 : }
     799             : 
     800           0 : static void trinity_start_am(struct radeon_device *rdev)
     801             : {
     802           0 :         WREG32_P(SCLK_PWRMGT_CNTL, 0, ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
     803           0 : }
     804             : 
     805           0 : static void trinity_reset_am(struct radeon_device *rdev)
     806             : {
     807           0 :         WREG32_P(SCLK_PWRMGT_CNTL, RESET_SCLK_CNT | RESET_BUSY_CNT,
     808             :                  ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
     809           0 : }
     810             : 
     811           0 : static void trinity_wait_for_level_0(struct radeon_device *rdev)
     812             : {
     813             :         int i;
     814             : 
     815           0 :         for (i = 0; i < rdev->usec_timeout; i++) {
     816           0 :                 if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
     817             :                         break;
     818           0 :                 udelay(1);
     819             :         }
     820           0 : }
     821             : 
     822           0 : static void trinity_enable_power_level_0(struct radeon_device *rdev)
     823             : {
     824           0 :         trinity_power_level_enable_disable(rdev, 0, true);
     825           0 : }
     826             : 
     827           0 : static void trinity_force_level_0(struct radeon_device *rdev)
     828             : {
     829           0 :         trinity_dpm_force_state(rdev, 0);
     830           0 : }
     831             : 
     832           0 : static void trinity_unforce_levels(struct radeon_device *rdev)
     833             : {
     834           0 :         trinity_dpm_no_forced_level(rdev);
     835           0 : }
     836             : 
     837           0 : static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev,
     838             :                                                 struct radeon_ps *new_rps,
     839             :                                                 struct radeon_ps *old_rps)
     840             : {
     841           0 :         struct trinity_ps *new_ps = trinity_get_ps(new_rps);
     842           0 :         struct trinity_ps *old_ps = trinity_get_ps(old_rps);
     843             :         u32 i;
     844           0 :         u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
     845             : 
     846           0 :         for (i = 0; i < new_ps->num_levels; i++) {
     847           0 :                 trinity_program_power_level(rdev, &new_ps->levels[i], i);
     848           0 :                 trinity_power_level_enable_disable(rdev, i, true);
     849             :         }
     850             : 
     851           0 :         for (i = new_ps->num_levels; i < n_current_state_levels; i++)
     852           0 :                 trinity_power_level_enable_disable(rdev, i, false);
     853           0 : }
     854             : 
     855           0 : static void trinity_program_bootup_state(struct radeon_device *rdev)
     856             : {
     857           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
     858             :         u32 i;
     859             : 
     860           0 :         trinity_program_power_level(rdev, &pi->boot_pl, 0);
     861           0 :         trinity_power_level_enable_disable(rdev, 0, true);
     862             : 
     863           0 :         for (i = 1; i < 8; i++)
     864           0 :                 trinity_power_level_enable_disable(rdev, i, false);
     865           0 : }
     866             : 
     867           0 : static void trinity_setup_uvd_clock_table(struct radeon_device *rdev,
     868             :                                           struct radeon_ps *rps)
     869             : {
     870           0 :         struct trinity_ps *ps = trinity_get_ps(rps);
     871           0 :         u32 uvdstates = (ps->vclk_low_divider |
     872           0 :                          ps->vclk_high_divider << 8 |
     873           0 :                          ps->dclk_low_divider << 16 |
     874           0 :                          ps->dclk_high_divider << 24);
     875             : 
     876           0 :         WREG32_SMC(SMU_UVD_DPM_STATES, uvdstates);
     877           0 : }
     878             : 
     879           0 : static void trinity_setup_uvd_dpm_interval(struct radeon_device *rdev,
     880             :                                            u32 interval)
     881             : {
     882           0 :         u32 p, u;
     883           0 :         u32 tp = RREG32_SMC(PM_TP);
     884             :         u32 val;
     885           0 :         u32 xclk = radeon_get_xclk(rdev);
     886             : 
     887           0 :         r600_calculate_u_and_p(interval, xclk, 16, &p, &u);
     888             : 
     889           0 :         val = (p + tp - 1) / tp;
     890             : 
     891           0 :         WREG32_SMC(SMU_UVD_DPM_CNTL, val);
     892           0 : }
     893             : 
     894           0 : static bool trinity_uvd_clocks_zero(struct radeon_ps *rps)
     895             : {
     896           0 :         if ((rps->vclk == 0) && (rps->dclk == 0))
     897           0 :                 return true;
     898             :         else
     899           0 :                 return false;
     900           0 : }
     901             : 
     902           0 : static bool trinity_uvd_clocks_equal(struct radeon_ps *rps1,
     903             :                                      struct radeon_ps *rps2)
     904             : {
     905           0 :         struct trinity_ps *ps1 = trinity_get_ps(rps1);
     906           0 :         struct trinity_ps *ps2 = trinity_get_ps(rps2);
     907             : 
     908           0 :         if ((rps1->vclk == rps2->vclk) &&
     909           0 :             (rps1->dclk == rps2->dclk) &&
     910           0 :             (ps1->vclk_low_divider == ps2->vclk_low_divider) &&
     911           0 :             (ps1->vclk_high_divider == ps2->vclk_high_divider) &&
     912           0 :             (ps1->dclk_low_divider == ps2->dclk_low_divider) &&
     913           0 :             (ps1->dclk_high_divider == ps2->dclk_high_divider))
     914           0 :                 return true;
     915             :         else
     916           0 :                 return false;
     917           0 : }
     918             : 
     919           0 : static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
     920             :                                      struct radeon_ps *new_rps,
     921             :                                      struct radeon_ps *old_rps)
     922             : {
     923           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
     924             : 
     925           0 :         if (pi->enable_gfx_power_gating) {
     926           0 :                 trinity_gfx_powergating_enable(rdev, false);
     927           0 :         }
     928             : 
     929           0 :         if (pi->uvd_dpm) {
     930           0 :                 if (trinity_uvd_clocks_zero(new_rps) &&
     931           0 :                     !trinity_uvd_clocks_zero(old_rps)) {
     932           0 :                         trinity_setup_uvd_dpm_interval(rdev, 0);
     933           0 :                 } else if (!trinity_uvd_clocks_zero(new_rps)) {
     934           0 :                         trinity_setup_uvd_clock_table(rdev, new_rps);
     935             : 
     936           0 :                         if (trinity_uvd_clocks_zero(old_rps)) {
     937           0 :                                 u32 tmp = RREG32(CG_MISC_REG);
     938           0 :                                 tmp &= 0xfffffffd;
     939           0 :                                 WREG32(CG_MISC_REG, tmp);
     940             : 
     941           0 :                                 radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
     942             : 
     943           0 :                                 trinity_setup_uvd_dpm_interval(rdev, 3000);
     944           0 :                         }
     945             :                 }
     946           0 :                 trinity_uvd_dpm_config(rdev);
     947           0 :         } else {
     948           0 :                 if (trinity_uvd_clocks_zero(new_rps) ||
     949           0 :                     trinity_uvd_clocks_equal(new_rps, old_rps))
     950           0 :                         return;
     951             : 
     952           0 :                 radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
     953             :         }
     954             : 
     955           0 :         if (pi->enable_gfx_power_gating) {
     956           0 :                 trinity_gfx_powergating_enable(rdev, true);
     957           0 :         }
     958           0 : }
     959             : 
     960           0 : static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
     961             :                                                        struct radeon_ps *new_rps,
     962             :                                                        struct radeon_ps *old_rps)
     963             : {
     964           0 :         struct trinity_ps *new_ps = trinity_get_ps(new_rps);
     965           0 :         struct trinity_ps *current_ps = trinity_get_ps(new_rps);
     966             : 
     967           0 :         if (new_ps->levels[new_ps->num_levels - 1].sclk >=
     968           0 :             current_ps->levels[current_ps->num_levels - 1].sclk)
     969           0 :                 return;
     970             : 
     971           0 :         trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
     972           0 : }
     973             : 
     974           0 : static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
     975             :                                                       struct radeon_ps *new_rps,
     976             :                                                       struct radeon_ps *old_rps)
     977             : {
     978           0 :         struct trinity_ps *new_ps = trinity_get_ps(new_rps);
     979           0 :         struct trinity_ps *current_ps = trinity_get_ps(old_rps);
     980             : 
     981           0 :         if (new_ps->levels[new_ps->num_levels - 1].sclk <
     982           0 :             current_ps->levels[current_ps->num_levels - 1].sclk)
     983           0 :                 return;
     984             : 
     985           0 :         trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
     986           0 : }
     987             : 
     988           0 : static void trinity_set_vce_clock(struct radeon_device *rdev,
     989             :                                   struct radeon_ps *new_rps,
     990             :                                   struct radeon_ps *old_rps)
     991             : {
     992           0 :         if ((old_rps->evclk != new_rps->evclk) ||
     993           0 :             (old_rps->ecclk != new_rps->ecclk)) {
     994             :                 /* turn the clocks on when encoding, off otherwise */
     995           0 :                 if (new_rps->evclk || new_rps->ecclk)
     996           0 :                         vce_v1_0_enable_mgcg(rdev, false);
     997             :                 else
     998           0 :                         vce_v1_0_enable_mgcg(rdev, true);
     999           0 :                 radeon_set_vce_clocks(rdev, new_rps->evclk, new_rps->ecclk);
    1000           0 :         }
    1001           0 : }
    1002             : 
    1003           0 : static void trinity_program_ttt(struct radeon_device *rdev)
    1004             : {
    1005           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1006           0 :         u32 value = RREG32_SMC(SMU_SCLK_DPM_TTT);
    1007             : 
    1008             :         value &= ~(HT_MASK | LT_MASK);
    1009           0 :         value |= HT((pi->thermal_auto_throttling + 49) * 8);
    1010           0 :         value |= LT((pi->thermal_auto_throttling + 49 - pi->sys_info.htc_hyst_lmt) * 8);
    1011           0 :         WREG32_SMC(SMU_SCLK_DPM_TTT, value);
    1012           0 : }
    1013             : 
    1014           0 : static void trinity_enable_att(struct radeon_device *rdev)
    1015             : {
    1016           0 :         u32 value = RREG32_SMC(SMU_SCLK_DPM_TT_CNTL);
    1017             : 
    1018           0 :         value &= ~SCLK_TT_EN_MASK;
    1019           0 :         value |= SCLK_TT_EN(1);
    1020           0 :         WREG32_SMC(SMU_SCLK_DPM_TT_CNTL, value);
    1021           0 : }
    1022             : 
    1023           0 : static void trinity_program_sclk_dpm(struct radeon_device *rdev)
    1024             : {
    1025           0 :         u32 p, u;
    1026           0 :         u32 tp = RREG32_SMC(PM_TP);
    1027             :         u32 ni;
    1028           0 :         u32 xclk = radeon_get_xclk(rdev);
    1029             :         u32 value;
    1030             : 
    1031           0 :         r600_calculate_u_and_p(400, xclk, 16, &p, &u);
    1032             : 
    1033           0 :         ni = (p + tp - 1) / tp;
    1034             : 
    1035           0 :         value = RREG32_SMC(PM_I_CNTL_1);
    1036           0 :         value &= ~SCLK_DPM_MASK;
    1037           0 :         value |= SCLK_DPM(ni);
    1038           0 :         WREG32_SMC(PM_I_CNTL_1, value);
    1039           0 : }
    1040             : 
    1041           0 : static int trinity_set_thermal_temperature_range(struct radeon_device *rdev,
    1042             :                                                  int min_temp, int max_temp)
    1043             : {
    1044             :         int low_temp = 0 * 1000;
    1045             :         int high_temp = 255 * 1000;
    1046             : 
    1047           0 :         if (low_temp < min_temp)
    1048           0 :                 low_temp = min_temp;
    1049           0 :         if (high_temp > max_temp)
    1050           0 :                 high_temp = max_temp;
    1051           0 :         if (high_temp < low_temp) {
    1052           0 :                 DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
    1053           0 :                 return -EINVAL;
    1054             :         }
    1055             : 
    1056           0 :         WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
    1057           0 :         WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
    1058             : 
    1059           0 :         rdev->pm.dpm.thermal.min_temp = low_temp;
    1060           0 :         rdev->pm.dpm.thermal.max_temp = high_temp;
    1061             : 
    1062           0 :         return 0;
    1063           0 : }
    1064             : 
    1065           0 : static void trinity_update_current_ps(struct radeon_device *rdev,
    1066             :                                       struct radeon_ps *rps)
    1067             : {
    1068           0 :         struct trinity_ps *new_ps = trinity_get_ps(rps);
    1069           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1070             : 
    1071           0 :         pi->current_rps = *rps;
    1072           0 :         pi->current_ps = *new_ps;
    1073           0 :         pi->current_rps.ps_priv = &pi->current_ps;
    1074           0 : }
    1075             : 
    1076           0 : static void trinity_update_requested_ps(struct radeon_device *rdev,
    1077             :                                         struct radeon_ps *rps)
    1078             : {
    1079           0 :         struct trinity_ps *new_ps = trinity_get_ps(rps);
    1080           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1081             : 
    1082           0 :         pi->requested_rps = *rps;
    1083           0 :         pi->requested_ps = *new_ps;
    1084           0 :         pi->requested_rps.ps_priv = &pi->requested_ps;
    1085           0 : }
    1086             : 
    1087           0 : void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable)
    1088             : {
    1089           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1090             : 
    1091           0 :         if (pi->enable_bapm) {
    1092           0 :                 trinity_acquire_mutex(rdev);
    1093           0 :                 trinity_dpm_bapm_enable(rdev, enable);
    1094           0 :                 trinity_release_mutex(rdev);
    1095           0 :         }
    1096           0 : }
    1097             : 
    1098           0 : int trinity_dpm_enable(struct radeon_device *rdev)
    1099             : {
    1100           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1101             : 
    1102           0 :         trinity_acquire_mutex(rdev);
    1103             : 
    1104           0 :         if (trinity_dpm_enabled(rdev)) {
    1105           0 :                 trinity_release_mutex(rdev);
    1106           0 :                 return -EINVAL;
    1107             :         }
    1108             : 
    1109           0 :         trinity_program_bootup_state(rdev);
    1110           0 :         sumo_program_vc(rdev, 0x00C00033);
    1111           0 :         trinity_start_am(rdev);
    1112           0 :         if (pi->enable_auto_thermal_throttling) {
    1113           0 :                 trinity_program_ttt(rdev);
    1114           0 :                 trinity_enable_att(rdev);
    1115           0 :         }
    1116           0 :         trinity_program_sclk_dpm(rdev);
    1117           0 :         trinity_start_dpm(rdev);
    1118           0 :         trinity_wait_for_dpm_enabled(rdev);
    1119           0 :         trinity_dpm_bapm_enable(rdev, false);
    1120           0 :         trinity_release_mutex(rdev);
    1121             : 
    1122           0 :         trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
    1123             : 
    1124           0 :         return 0;
    1125           0 : }
    1126             : 
    1127           0 : int trinity_dpm_late_enable(struct radeon_device *rdev)
    1128             : {
    1129             :         int ret;
    1130             : 
    1131           0 :         trinity_acquire_mutex(rdev);
    1132           0 :         trinity_enable_clock_power_gating(rdev);
    1133             : 
    1134           0 :         if (rdev->irq.installed &&
    1135           0 :             r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
    1136           0 :                 ret = trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
    1137           0 :                 if (ret) {
    1138           0 :                         trinity_release_mutex(rdev);
    1139           0 :                         return ret;
    1140             :                 }
    1141           0 :                 rdev->irq.dpm_thermal = true;
    1142           0 :                 radeon_irq_set(rdev);
    1143           0 :         }
    1144           0 :         trinity_release_mutex(rdev);
    1145             : 
    1146           0 :         return 0;
    1147           0 : }
    1148             : 
    1149           0 : void trinity_dpm_disable(struct radeon_device *rdev)
    1150             : {
    1151           0 :         trinity_acquire_mutex(rdev);
    1152           0 :         if (!trinity_dpm_enabled(rdev)) {
    1153           0 :                 trinity_release_mutex(rdev);
    1154           0 :                 return;
    1155             :         }
    1156           0 :         trinity_dpm_bapm_enable(rdev, false);
    1157           0 :         trinity_disable_clock_power_gating(rdev);
    1158           0 :         sumo_clear_vc(rdev);
    1159           0 :         trinity_wait_for_level_0(rdev);
    1160           0 :         trinity_stop_dpm(rdev);
    1161           0 :         trinity_reset_am(rdev);
    1162           0 :         trinity_release_mutex(rdev);
    1163             : 
    1164           0 :         if (rdev->irq.installed &&
    1165           0 :             r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
    1166           0 :                 rdev->irq.dpm_thermal = false;
    1167           0 :                 radeon_irq_set(rdev);
    1168           0 :         }
    1169             : 
    1170           0 :         trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
    1171           0 : }
    1172             : 
    1173           0 : static void trinity_get_min_sclk_divider(struct radeon_device *rdev)
    1174             : {
    1175           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1176             : 
    1177           0 :         pi->min_sclk_did =
    1178           0 :                 (RREG32_SMC(CC_SMU_MISC_FUSES) & MinSClkDid_MASK) >> MinSClkDid_SHIFT;
    1179           0 : }
    1180             : 
    1181           0 : static void trinity_setup_nbp_sim(struct radeon_device *rdev,
    1182             :                                   struct radeon_ps *rps)
    1183             : {
    1184           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1185           0 :         struct trinity_ps *new_ps = trinity_get_ps(rps);
    1186             :         u32 nbpsconfig;
    1187             : 
    1188           0 :         if (pi->sys_info.nb_dpm_enable) {
    1189           0 :                 nbpsconfig = RREG32_SMC(NB_PSTATE_CONFIG);
    1190           0 :                 nbpsconfig &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | DpmXNbPsLo_MASK | DpmXNbPsHi_MASK);
    1191           0 :                 nbpsconfig |= (Dpm0PgNbPsLo(new_ps->Dpm0PgNbPsLo) |
    1192           0 :                                Dpm0PgNbPsHi(new_ps->Dpm0PgNbPsHi) |
    1193           0 :                                DpmXNbPsLo(new_ps->DpmXNbPsLo) |
    1194           0 :                                DpmXNbPsHi(new_ps->DpmXNbPsHi));
    1195           0 :                 WREG32_SMC(NB_PSTATE_CONFIG, nbpsconfig);
    1196           0 :         }
    1197           0 : }
    1198             : 
    1199           0 : int trinity_dpm_force_performance_level(struct radeon_device *rdev,
    1200             :                                         enum radeon_dpm_forced_level level)
    1201             : {
    1202           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1203           0 :         struct radeon_ps *rps = &pi->current_rps;
    1204           0 :         struct trinity_ps *ps = trinity_get_ps(rps);
    1205             :         int i, ret;
    1206             : 
    1207           0 :         if (ps->num_levels <= 1)
    1208           0 :                 return 0;
    1209             : 
    1210           0 :         if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
    1211             :                 /* not supported by the hw */
    1212           0 :                 return -EINVAL;
    1213           0 :         } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
    1214           0 :                 ret = trinity_dpm_n_levels_disabled(rdev, ps->num_levels - 1);
    1215           0 :                 if (ret)
    1216           0 :                         return ret;
    1217             :         } else {
    1218           0 :                 for (i = 0; i < ps->num_levels; i++) {
    1219           0 :                         ret = trinity_dpm_n_levels_disabled(rdev, 0);
    1220           0 :                         if (ret)
    1221           0 :                                 return ret;
    1222             :                 }
    1223             :         }
    1224             : 
    1225           0 :         rdev->pm.dpm.forced_level = level;
    1226             : 
    1227           0 :         return 0;
    1228           0 : }
    1229             : 
    1230           0 : int trinity_dpm_pre_set_power_state(struct radeon_device *rdev)
    1231             : {
    1232           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1233           0 :         struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
    1234             :         struct radeon_ps *new_ps = &requested_ps;
    1235             : 
    1236           0 :         trinity_update_requested_ps(rdev, new_ps);
    1237             : 
    1238           0 :         trinity_apply_state_adjust_rules(rdev,
    1239           0 :                                          &pi->requested_rps,
    1240           0 :                                          &pi->current_rps);
    1241             : 
    1242           0 :         return 0;
    1243           0 : }
    1244             : 
    1245           0 : int trinity_dpm_set_power_state(struct radeon_device *rdev)
    1246             : {
    1247           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1248           0 :         struct radeon_ps *new_ps = &pi->requested_rps;
    1249           0 :         struct radeon_ps *old_ps = &pi->current_rps;
    1250             : 
    1251           0 :         trinity_acquire_mutex(rdev);
    1252           0 :         if (pi->enable_dpm) {
    1253           0 :                 if (pi->enable_bapm)
    1254           0 :                         trinity_dpm_bapm_enable(rdev, rdev->pm.dpm.ac_power);
    1255           0 :                 trinity_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
    1256           0 :                 trinity_enable_power_level_0(rdev);
    1257           0 :                 trinity_force_level_0(rdev);
    1258           0 :                 trinity_wait_for_level_0(rdev);
    1259           0 :                 trinity_setup_nbp_sim(rdev, new_ps);
    1260           0 :                 trinity_program_power_levels_0_to_n(rdev, new_ps, old_ps);
    1261           0 :                 trinity_force_level_0(rdev);
    1262           0 :                 trinity_unforce_levels(rdev);
    1263           0 :                 trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
    1264           0 :                 trinity_set_vce_clock(rdev, new_ps, old_ps);
    1265           0 :         }
    1266           0 :         trinity_release_mutex(rdev);
    1267             : 
    1268           0 :         return 0;
    1269             : }
    1270             : 
    1271           0 : void trinity_dpm_post_set_power_state(struct radeon_device *rdev)
    1272             : {
    1273           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1274           0 :         struct radeon_ps *new_ps = &pi->requested_rps;
    1275             : 
    1276           0 :         trinity_update_current_ps(rdev, new_ps);
    1277           0 : }
    1278             : 
    1279           0 : void trinity_dpm_setup_asic(struct radeon_device *rdev)
    1280             : {
    1281           0 :         trinity_acquire_mutex(rdev);
    1282           0 :         sumo_program_sstp(rdev);
    1283           0 :         sumo_take_smu_control(rdev, true);
    1284           0 :         trinity_get_min_sclk_divider(rdev);
    1285           0 :         trinity_release_mutex(rdev);
    1286           0 : }
    1287             : 
    1288             : #if 0
    1289             : void trinity_dpm_reset_asic(struct radeon_device *rdev)
    1290             : {
    1291             :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1292             : 
    1293             :         trinity_acquire_mutex(rdev);
    1294             :         if (pi->enable_dpm) {
    1295             :                 trinity_enable_power_level_0(rdev);
    1296             :                 trinity_force_level_0(rdev);
    1297             :                 trinity_wait_for_level_0(rdev);
    1298             :                 trinity_program_bootup_state(rdev);
    1299             :                 trinity_force_level_0(rdev);
    1300             :                 trinity_unforce_levels(rdev);
    1301             :         }
    1302             :         trinity_release_mutex(rdev);
    1303             : }
    1304             : #endif
    1305             : 
    1306           0 : static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
    1307             :                                                   u32 vid_2bit)
    1308             : {
    1309           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1310           0 :         u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
    1311           0 :         u32 svi_mode = (RREG32_SMC(PM_CONFIG) & SVI_Mode) ? 1 : 0;
    1312           0 :         u32 step = (svi_mode == 0) ? 1250 : 625;
    1313           0 :         u32 delta = vid_7bit * step + 50;
    1314             : 
    1315           0 :         if (delta > 155000)
    1316           0 :                 return 0;
    1317             : 
    1318           0 :         return (155000 - delta) / 100;
    1319           0 : }
    1320             : 
    1321           0 : static void trinity_patch_boot_state(struct radeon_device *rdev,
    1322             :                                      struct trinity_ps *ps)
    1323             : {
    1324           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1325             : 
    1326           0 :         ps->num_levels = 1;
    1327           0 :         ps->nbps_flags = 0;
    1328           0 :         ps->bapm_flags = 0;
    1329           0 :         ps->levels[0] = pi->boot_pl;
    1330           0 : }
    1331             : 
    1332           0 : static u8 trinity_calculate_vce_wm(struct radeon_device *rdev, u32 sclk)
    1333             : {
    1334           0 :         if (sclk < 20000)
    1335           0 :                 return 1;
    1336           0 :         return 0;
    1337           0 : }
    1338             : 
    1339           0 : static void trinity_construct_boot_state(struct radeon_device *rdev)
    1340             : {
    1341           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1342             : 
    1343           0 :         pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
    1344           0 :         pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
    1345           0 :         pi->boot_pl.ds_divider_index = 0;
    1346           0 :         pi->boot_pl.ss_divider_index = 0;
    1347           0 :         pi->boot_pl.allow_gnb_slow = 1;
    1348           0 :         pi->boot_pl.force_nbp_state = 0;
    1349           0 :         pi->boot_pl.display_wm = 0;
    1350           0 :         pi->boot_pl.vce_wm = 0;
    1351           0 :         pi->current_ps.num_levels = 1;
    1352           0 :         pi->current_ps.levels[0] = pi->boot_pl;
    1353           0 : }
    1354             : 
    1355           0 : static u8 trinity_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
    1356             :                                                   u32 sclk, u32 min_sclk_in_sr)
    1357             : {
    1358           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1359             :         u32 i;
    1360             :         u32 temp;
    1361           0 :         u32 min = (min_sclk_in_sr > TRINITY_MINIMUM_ENGINE_CLOCK) ?
    1362             :                 min_sclk_in_sr : TRINITY_MINIMUM_ENGINE_CLOCK;
    1363             : 
    1364           0 :         if (sclk < min)
    1365           0 :                 return 0;
    1366             : 
    1367           0 :         if (!pi->enable_sclk_ds)
    1368           0 :                 return 0;
    1369             : 
    1370           0 :         for (i = TRINITY_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
    1371           0 :                 temp = sclk / sumo_get_sleep_divider_from_id(i);
    1372           0 :                 if (temp >= min || i == 0)
    1373             :                         break;
    1374             :         }
    1375             : 
    1376           0 :         return (u8)i;
    1377           0 : }
    1378             : 
    1379           0 : static u32 trinity_get_valid_engine_clock(struct radeon_device *rdev,
    1380             :                                           u32 lower_limit)
    1381             : {
    1382           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1383             :         u32 i;
    1384             : 
    1385           0 :         for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
    1386           0 :                 if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
    1387           0 :                         return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
    1388             :         }
    1389             : 
    1390           0 :         if (i == pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries)
    1391           0 :                 DRM_ERROR("engine clock out of range!");
    1392             : 
    1393           0 :         return 0;
    1394           0 : }
    1395             : 
    1396           0 : static void trinity_patch_thermal_state(struct radeon_device *rdev,
    1397             :                                         struct trinity_ps *ps,
    1398             :                                         struct trinity_ps *current_ps)
    1399             : {
    1400           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1401           0 :         u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
    1402             :         u32 current_vddc;
    1403             :         u32 current_sclk;
    1404             :         u32 current_index = 0;
    1405             : 
    1406           0 :         if (current_ps) {
    1407           0 :                 current_vddc = current_ps->levels[current_index].vddc_index;
    1408           0 :                 current_sclk = current_ps->levels[current_index].sclk;
    1409           0 :         } else {
    1410           0 :                 current_vddc = pi->boot_pl.vddc_index;
    1411           0 :                 current_sclk = pi->boot_pl.sclk;
    1412             :         }
    1413             : 
    1414           0 :         ps->levels[0].vddc_index = current_vddc;
    1415             : 
    1416           0 :         if (ps->levels[0].sclk > current_sclk)
    1417           0 :                 ps->levels[0].sclk = current_sclk;
    1418             : 
    1419           0 :         ps->levels[0].ds_divider_index =
    1420           0 :                 trinity_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
    1421           0 :         ps->levels[0].ss_divider_index = ps->levels[0].ds_divider_index;
    1422           0 :         ps->levels[0].allow_gnb_slow = 1;
    1423           0 :         ps->levels[0].force_nbp_state = 0;
    1424           0 :         ps->levels[0].display_wm = 0;
    1425           0 :         ps->levels[0].vce_wm =
    1426           0 :                 trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
    1427           0 : }
    1428             : 
    1429           0 : static u8 trinity_calculate_display_wm(struct radeon_device *rdev,
    1430             :                                        struct trinity_ps *ps, u32 index)
    1431             : {
    1432           0 :         if (ps == NULL || ps->num_levels <= 1)
    1433           0 :                 return 0;
    1434           0 :         else if (ps->num_levels == 2) {
    1435           0 :                 if (index == 0)
    1436           0 :                         return 0;
    1437             :                 else
    1438           0 :                         return 1;
    1439             :         } else {
    1440           0 :                 if (index == 0)
    1441           0 :                         return 0;
    1442           0 :                 else if (ps->levels[index].sclk < 30000)
    1443           0 :                         return 0;
    1444             :                 else
    1445           0 :                         return 1;
    1446             :         }
    1447           0 : }
    1448             : 
    1449           0 : static u32 trinity_get_uvd_clock_index(struct radeon_device *rdev,
    1450             :                                        struct radeon_ps *rps)
    1451             : {
    1452           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1453             :         u32 i = 0;
    1454             : 
    1455           0 :         for (i = 0; i < 4; i++) {
    1456           0 :                 if ((rps->vclk == pi->sys_info.uvd_clock_table_entries[i].vclk) &&
    1457           0 :                     (rps->dclk == pi->sys_info.uvd_clock_table_entries[i].dclk))
    1458             :                     break;
    1459             :         }
    1460             : 
    1461           0 :         if (i >= 4) {
    1462           0 :                 DRM_ERROR("UVD clock index not found!\n");
    1463             :                 i = 3;
    1464           0 :         }
    1465           0 :         return i;
    1466             : }
    1467             : 
    1468           0 : static void trinity_adjust_uvd_state(struct radeon_device *rdev,
    1469             :                                      struct radeon_ps *rps)
    1470             : {
    1471           0 :         struct trinity_ps *ps = trinity_get_ps(rps);
    1472           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1473             :         u32 high_index = 0;
    1474             :         u32 low_index = 0;
    1475             : 
    1476           0 :         if (pi->uvd_dpm && r600_is_uvd_state(rps->class, rps->class2)) {
    1477           0 :                 high_index = trinity_get_uvd_clock_index(rdev, rps);
    1478             : 
    1479           0 :                 switch(high_index) {
    1480             :                 case 3:
    1481             :                 case 2:
    1482             :                         low_index = 1;
    1483           0 :                         break;
    1484             :                 case 1:
    1485             :                 case 0:
    1486             :                 default:
    1487             :                         low_index = 0;
    1488           0 :                         break;
    1489             :                 }
    1490             : 
    1491           0 :                 ps->vclk_low_divider =
    1492           0 :                         pi->sys_info.uvd_clock_table_entries[high_index].vclk_did;
    1493           0 :                 ps->dclk_low_divider =
    1494           0 :                         pi->sys_info.uvd_clock_table_entries[high_index].dclk_did;
    1495           0 :                 ps->vclk_high_divider =
    1496           0 :                         pi->sys_info.uvd_clock_table_entries[low_index].vclk_did;
    1497           0 :                 ps->dclk_high_divider =
    1498           0 :                         pi->sys_info.uvd_clock_table_entries[low_index].dclk_did;
    1499           0 :         }
    1500           0 : }
    1501             : 
    1502           0 : static int trinity_get_vce_clock_voltage(struct radeon_device *rdev,
    1503             :                                          u32 evclk, u32 ecclk, u16 *voltage)
    1504             : {
    1505             :         u32 i;
    1506             :         int ret = -EINVAL;
    1507             :         struct radeon_vce_clock_voltage_dependency_table *table =
    1508           0 :                 &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
    1509             : 
    1510           0 :         if (((evclk == 0) && (ecclk == 0)) ||
    1511           0 :             (table && (table->count == 0))) {
    1512           0 :                 *voltage = 0;
    1513           0 :                 return 0;
    1514             :         }
    1515             : 
    1516           0 :         for (i = 0; i < table->count; i++) {
    1517           0 :                 if ((evclk <= table->entries[i].evclk) &&
    1518           0 :                     (ecclk <= table->entries[i].ecclk)) {
    1519           0 :                         *voltage = table->entries[i].v;
    1520             :                         ret = 0;
    1521           0 :                         break;
    1522             :                 }
    1523             :         }
    1524             : 
    1525             :         /* if no match return the highest voltage */
    1526           0 :         if (ret)
    1527           0 :                 *voltage = table->entries[table->count - 1].v;
    1528             : 
    1529           0 :         return ret;
    1530           0 : }
    1531             : 
    1532           0 : static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
    1533             :                                              struct radeon_ps *new_rps,
    1534             :                                              struct radeon_ps *old_rps)
    1535             : {
    1536           0 :         struct trinity_ps *ps = trinity_get_ps(new_rps);
    1537           0 :         struct trinity_ps *current_ps = trinity_get_ps(old_rps);
    1538           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1539             :         u32 min_voltage = 0; /* ??? */
    1540           0 :         u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
    1541             :         u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
    1542             :         u32 i;
    1543           0 :         u16 min_vce_voltage;
    1544             :         bool force_high;
    1545           0 :         u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
    1546             : 
    1547           0 :         if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
    1548           0 :                 return trinity_patch_thermal_state(rdev, ps, current_ps);
    1549             : 
    1550           0 :         trinity_adjust_uvd_state(rdev, new_rps);
    1551             : 
    1552           0 :         if (new_rps->vce_active) {
    1553           0 :                 new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
    1554           0 :                 new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
    1555           0 :         } else {
    1556           0 :                 new_rps->evclk = 0;
    1557           0 :                 new_rps->ecclk = 0;
    1558             :         }
    1559             : 
    1560           0 :         for (i = 0; i < ps->num_levels; i++) {
    1561           0 :                 if (ps->levels[i].vddc_index < min_voltage)
    1562           0 :                         ps->levels[i].vddc_index = min_voltage;
    1563             : 
    1564           0 :                 if (ps->levels[i].sclk < min_sclk)
    1565           0 :                         ps->levels[i].sclk =
    1566           0 :                                 trinity_get_valid_engine_clock(rdev, min_sclk);
    1567             : 
    1568             :                 /* patch in vce limits */
    1569           0 :                 if (new_rps->vce_active) {
    1570             :                         /* sclk */
    1571           0 :                         if (ps->levels[i].sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
    1572           0 :                                 ps->levels[i].sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
    1573             :                         /* vddc */
    1574           0 :                         trinity_get_vce_clock_voltage(rdev, new_rps->evclk, new_rps->ecclk, &min_vce_voltage);
    1575           0 :                         if (ps->levels[i].vddc_index < min_vce_voltage)
    1576           0 :                                 ps->levels[i].vddc_index = min_vce_voltage;
    1577             :                 }
    1578             : 
    1579           0 :                 ps->levels[i].ds_divider_index =
    1580           0 :                         sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
    1581             : 
    1582           0 :                 ps->levels[i].ss_divider_index = ps->levels[i].ds_divider_index;
    1583             : 
    1584           0 :                 ps->levels[i].allow_gnb_slow = 1;
    1585           0 :                 ps->levels[i].force_nbp_state = 0;
    1586           0 :                 ps->levels[i].display_wm =
    1587           0 :                         trinity_calculate_display_wm(rdev, ps, i);
    1588           0 :                 ps->levels[i].vce_wm =
    1589           0 :                         trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
    1590             :         }
    1591             : 
    1592           0 :         if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
    1593           0 :             ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY))
    1594           0 :                 ps->bapm_flags |= TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE;
    1595             : 
    1596           0 :         if (pi->sys_info.nb_dpm_enable) {
    1597           0 :                 ps->Dpm0PgNbPsLo = 0x1;
    1598           0 :                 ps->Dpm0PgNbPsHi = 0x0;
    1599           0 :                 ps->DpmXNbPsLo = 0x2;
    1600           0 :                 ps->DpmXNbPsHi = 0x1;
    1601             : 
    1602           0 :                 if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
    1603           0 :                     ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) {
    1604           0 :                         force_high = ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ||
    1605           0 :                                       ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) &&
    1606           0 :                                        (pi->sys_info.uma_channel_number == 1)));
    1607           0 :                         force_high = (num_active_displays >= 3) || force_high;
    1608           0 :                         ps->Dpm0PgNbPsLo = force_high ? 0x2 : 0x3;
    1609           0 :                         ps->Dpm0PgNbPsHi = 0x1;
    1610           0 :                         ps->DpmXNbPsLo = force_high ? 0x2 : 0x3;
    1611           0 :                         ps->DpmXNbPsHi = 0x2;
    1612           0 :                         ps->levels[ps->num_levels - 1].allow_gnb_slow = 0;
    1613           0 :                 }
    1614             :         }
    1615           0 : }
    1616             : 
    1617           0 : static void trinity_cleanup_asic(struct radeon_device *rdev)
    1618             : {
    1619           0 :         sumo_take_smu_control(rdev, false);
    1620           0 : }
    1621             : 
    1622             : #if 0
    1623             : static void trinity_pre_display_configuration_change(struct radeon_device *rdev)
    1624             : {
    1625             :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1626             : 
    1627             :         if (pi->voltage_drop_in_dce)
    1628             :                 trinity_dce_enable_voltage_adjustment(rdev, false);
    1629             : }
    1630             : #endif
    1631             : 
    1632           0 : static void trinity_add_dccac_value(struct radeon_device *rdev)
    1633             : {
    1634             :         u32 gpu_cac_avrg_cntl_window_size;
    1635           0 :         u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
    1636           0 :         u64 disp_clk = rdev->clock.default_dispclk / 100;
    1637             :         u32 dc_cac_value;
    1638             : 
    1639             :         gpu_cac_avrg_cntl_window_size =
    1640           0 :                 (RREG32_SMC(GPU_CAC_AVRG_CNTL) & WINDOW_SIZE_MASK) >> WINDOW_SIZE_SHIFT;
    1641             : 
    1642           0 :         dc_cac_value = (u32)((14213 * disp_clk * disp_clk * (u64)num_active_displays) >>
    1643           0 :                              (32 - gpu_cac_avrg_cntl_window_size));
    1644             : 
    1645           0 :         WREG32_SMC(DC_CAC_VALUE, dc_cac_value);
    1646           0 : }
    1647             : 
    1648           0 : void trinity_dpm_display_configuration_changed(struct radeon_device *rdev)
    1649             : {
    1650           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1651             : 
    1652           0 :         if (pi->voltage_drop_in_dce)
    1653           0 :                 trinity_dce_enable_voltage_adjustment(rdev, true);
    1654           0 :         trinity_add_dccac_value(rdev);
    1655           0 : }
    1656             : 
    1657             : union power_info {
    1658             :         struct _ATOM_POWERPLAY_INFO info;
    1659             :         struct _ATOM_POWERPLAY_INFO_V2 info_2;
    1660             :         struct _ATOM_POWERPLAY_INFO_V3 info_3;
    1661             :         struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
    1662             :         struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
    1663             :         struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
    1664             : };
    1665             : 
    1666             : union pplib_clock_info {
    1667             :         struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
    1668             :         struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
    1669             :         struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
    1670             :         struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
    1671             : };
    1672             : 
    1673             : union pplib_power_state {
    1674             :         struct _ATOM_PPLIB_STATE v1;
    1675             :         struct _ATOM_PPLIB_STATE_V2 v2;
    1676             : };
    1677             : 
    1678           0 : static void trinity_parse_pplib_non_clock_info(struct radeon_device *rdev,
    1679             :                                                struct radeon_ps *rps,
    1680             :                                                struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
    1681             :                                                u8 table_rev)
    1682             : {
    1683           0 :         struct trinity_ps *ps = trinity_get_ps(rps);
    1684             : 
    1685           0 :         rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
    1686           0 :         rps->class = le16_to_cpu(non_clock_info->usClassification);
    1687           0 :         rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
    1688             : 
    1689           0 :         if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
    1690           0 :                 rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
    1691           0 :                 rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
    1692           0 :         } else {
    1693           0 :                 rps->vclk = 0;
    1694           0 :                 rps->dclk = 0;
    1695             :         }
    1696             : 
    1697           0 :         if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
    1698           0 :                 rdev->pm.dpm.boot_ps = rps;
    1699           0 :                 trinity_patch_boot_state(rdev, ps);
    1700           0 :         }
    1701           0 :         if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
    1702           0 :                 rdev->pm.dpm.uvd_ps = rps;
    1703           0 : }
    1704             : 
    1705           0 : static void trinity_parse_pplib_clock_info(struct radeon_device *rdev,
    1706             :                                            struct radeon_ps *rps, int index,
    1707             :                                            union pplib_clock_info *clock_info)
    1708             : {
    1709           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1710           0 :         struct trinity_ps *ps = trinity_get_ps(rps);
    1711           0 :         struct trinity_pl *pl = &ps->levels[index];
    1712             :         u32 sclk;
    1713             : 
    1714           0 :         sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
    1715           0 :         sclk |= clock_info->sumo.ucEngineClockHigh << 16;
    1716           0 :         pl->sclk = sclk;
    1717           0 :         pl->vddc_index = clock_info->sumo.vddcIndex;
    1718             : 
    1719           0 :         ps->num_levels = index + 1;
    1720             : 
    1721           0 :         if (pi->enable_sclk_ds) {
    1722           0 :                 pl->ds_divider_index = 5;
    1723           0 :                 pl->ss_divider_index = 5;
    1724           0 :         }
    1725           0 : }
    1726             : 
    1727           0 : static int trinity_parse_power_table(struct radeon_device *rdev)
    1728             : {
    1729           0 :         struct radeon_mode_info *mode_info = &rdev->mode_info;
    1730             :         struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
    1731             :         union pplib_power_state *power_state;
    1732             :         int i, j, k, non_clock_array_index, clock_array_index;
    1733             :         union pplib_clock_info *clock_info;
    1734             :         struct _StateArray *state_array;
    1735             :         struct _ClockInfoArray *clock_info_array;
    1736             :         struct _NonClockInfoArray *non_clock_info_array;
    1737             :         union power_info *power_info;
    1738             :         int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
    1739           0 :         u16 data_offset;
    1740           0 :         u8 frev, crev;
    1741             :         u8 *power_state_offset;
    1742             :         struct sumo_ps *ps;
    1743             : 
    1744           0 :         if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
    1745             :                                    &frev, &crev, &data_offset))
    1746           0 :                 return -EINVAL;
    1747           0 :         power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
    1748             : 
    1749           0 :         state_array = (struct _StateArray *)
    1750           0 :                 (mode_info->atom_context->bios + data_offset +
    1751           0 :                  le16_to_cpu(power_info->pplib.usStateArrayOffset));
    1752           0 :         clock_info_array = (struct _ClockInfoArray *)
    1753           0 :                 (mode_info->atom_context->bios + data_offset +
    1754           0 :                  le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
    1755           0 :         non_clock_info_array = (struct _NonClockInfoArray *)
    1756           0 :                 (mode_info->atom_context->bios + data_offset +
    1757           0 :                  le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
    1758             : 
    1759           0 :         rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
    1760           0 :                                   state_array->ucNumEntries, GFP_KERNEL);
    1761           0 :         if (!rdev->pm.dpm.ps)
    1762           0 :                 return -ENOMEM;
    1763           0 :         power_state_offset = (u8 *)state_array->states;
    1764           0 :         for (i = 0; i < state_array->ucNumEntries; i++) {
    1765             :                 u8 *idx;
    1766           0 :                 power_state = (union pplib_power_state *)power_state_offset;
    1767           0 :                 non_clock_array_index = power_state->v2.nonClockInfoIndex;
    1768             :                 non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
    1769           0 :                         &non_clock_info_array->nonClockInfo[non_clock_array_index];
    1770           0 :                 if (!rdev->pm.power_state[i].clock_info)
    1771           0 :                         return -EINVAL;
    1772           0 :                 ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
    1773           0 :                 if (ps == NULL) {
    1774           0 :                         kfree(rdev->pm.dpm.ps);
    1775           0 :                         return -ENOMEM;
    1776             :                 }
    1777           0 :                 rdev->pm.dpm.ps[i].ps_priv = ps;
    1778             :                 k = 0;
    1779           0 :                 idx = (u8 *)&power_state->v2.clockInfoIndex[0];
    1780           0 :                 for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
    1781           0 :                         clock_array_index = idx[j];
    1782           0 :                         if (clock_array_index >= clock_info_array->ucNumEntries)
    1783             :                                 continue;
    1784           0 :                         if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
    1785             :                                 break;
    1786           0 :                         clock_info = (union pplib_clock_info *)
    1787           0 :                                 ((u8 *)&clock_info_array->clockInfo[0] +
    1788           0 :                                  (clock_array_index * clock_info_array->ucEntrySize));
    1789           0 :                         trinity_parse_pplib_clock_info(rdev,
    1790           0 :                                                        &rdev->pm.dpm.ps[i], k,
    1791             :                                                        clock_info);
    1792           0 :                         k++;
    1793           0 :                 }
    1794           0 :                 trinity_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
    1795             :                                                    non_clock_info,
    1796           0 :                                                    non_clock_info_array->ucEntrySize);
    1797           0 :                 power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
    1798           0 :         }
    1799           0 :         rdev->pm.dpm.num_ps = state_array->ucNumEntries;
    1800             : 
    1801             :         /* fill in the vce power states */
    1802           0 :         for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
    1803             :                 u32 sclk;
    1804           0 :                 clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
    1805           0 :                 clock_info = (union pplib_clock_info *)
    1806           0 :                         &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
    1807           0 :                 sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
    1808           0 :                 sclk |= clock_info->sumo.ucEngineClockHigh << 16;
    1809           0 :                 rdev->pm.dpm.vce_states[i].sclk = sclk;
    1810           0 :                 rdev->pm.dpm.vce_states[i].mclk = 0;
    1811             :         }
    1812             : 
    1813           0 :         return 0;
    1814           0 : }
    1815             : 
    1816             : union igp_info {
    1817             :         struct _ATOM_INTEGRATED_SYSTEM_INFO info;
    1818             :         struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
    1819             :         struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
    1820             :         struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
    1821             :         struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
    1822             : };
    1823             : 
    1824           0 : static u32 trinity_convert_did_to_freq(struct radeon_device *rdev, u8 did)
    1825             : {
    1826           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1827             :         u32 divider;
    1828             : 
    1829           0 :         if (did >= 8 && did <= 0x3f)
    1830           0 :                 divider = did * 25;
    1831           0 :         else if (did > 0x3f && did <= 0x5f)
    1832           0 :                 divider = (did - 64) * 50 + 1600;
    1833           0 :         else if (did > 0x5f && did <= 0x7e)
    1834           0 :                 divider = (did - 96) * 100 + 3200;
    1835           0 :         else if (did == 0x7f)
    1836             :                 divider = 128 * 100;
    1837             :         else
    1838           0 :                 return 10000;
    1839             : 
    1840           0 :         return ((pi->sys_info.dentist_vco_freq * 100) + (divider - 1)) / divider;
    1841           0 : }
    1842             : 
    1843           0 : static int trinity_parse_sys_info_table(struct radeon_device *rdev)
    1844             : {
    1845           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    1846           0 :         struct radeon_mode_info *mode_info = &rdev->mode_info;
    1847             :         int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
    1848             :         union igp_info *igp_info;
    1849           0 :         u8 frev, crev;
    1850           0 :         u16 data_offset;
    1851             :         int i;
    1852             : 
    1853           0 :         if (atom_parse_data_header(mode_info->atom_context, index, NULL,
    1854             :                                    &frev, &crev, &data_offset)) {
    1855           0 :                 igp_info = (union igp_info *)(mode_info->atom_context->bios +
    1856           0 :                                               data_offset);
    1857             : 
    1858           0 :                 if (crev != 7) {
    1859           0 :                         DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
    1860           0 :                         return -EINVAL;
    1861             :                 }
    1862           0 :                 pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock);
    1863           0 :                 pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock);
    1864           0 :                 pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock);
    1865           0 :                 pi->sys_info.dentist_vco_freq = le32_to_cpu(igp_info->info_7.ulDentistVCOFreq);
    1866           0 :                 pi->sys_info.bootup_nb_voltage_index =
    1867           0 :                         le16_to_cpu(igp_info->info_7.usBootUpNBVoltage);
    1868           0 :                 if (igp_info->info_7.ucHtcTmpLmt == 0)
    1869           0 :                         pi->sys_info.htc_tmp_lmt = 203;
    1870             :                 else
    1871           0 :                         pi->sys_info.htc_tmp_lmt = igp_info->info_7.ucHtcTmpLmt;
    1872           0 :                 if (igp_info->info_7.ucHtcHystLmt == 0)
    1873           0 :                         pi->sys_info.htc_hyst_lmt = 5;
    1874             :                 else
    1875           0 :                         pi->sys_info.htc_hyst_lmt = igp_info->info_7.ucHtcHystLmt;
    1876           0 :                 if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
    1877           0 :                         DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
    1878           0 :                 }
    1879             : 
    1880           0 :                 if (pi->enable_nbps_policy)
    1881           0 :                         pi->sys_info.nb_dpm_enable = igp_info->info_7.ucNBDPMEnable;
    1882             :                 else
    1883           0 :                         pi->sys_info.nb_dpm_enable = 0;
    1884             : 
    1885           0 :                 for (i = 0; i < TRINITY_NUM_NBPSTATES; i++) {
    1886           0 :                         pi->sys_info.nbp_mclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateMemclkFreq[i]);
    1887           0 :                         pi->sys_info.nbp_nclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateNClkFreq[i]);
    1888             :                 }
    1889             : 
    1890           0 :                 pi->sys_info.nbp_voltage_index[0] = le16_to_cpu(igp_info->info_7.usNBP0Voltage);
    1891           0 :                 pi->sys_info.nbp_voltage_index[1] = le16_to_cpu(igp_info->info_7.usNBP1Voltage);
    1892           0 :                 pi->sys_info.nbp_voltage_index[2] = le16_to_cpu(igp_info->info_7.usNBP2Voltage);
    1893           0 :                 pi->sys_info.nbp_voltage_index[3] = le16_to_cpu(igp_info->info_7.usNBP3Voltage);
    1894             : 
    1895           0 :                 if (!pi->sys_info.nb_dpm_enable) {
    1896           0 :                         for (i = 1; i < TRINITY_NUM_NBPSTATES; i++) {
    1897           0 :                                 pi->sys_info.nbp_mclk[i] = pi->sys_info.nbp_mclk[0];
    1898           0 :                                 pi->sys_info.nbp_nclk[i] = pi->sys_info.nbp_nclk[0];
    1899           0 :                                 pi->sys_info.nbp_voltage_index[i] = pi->sys_info.nbp_voltage_index[0];
    1900             :                         }
    1901             :                 }
    1902             : 
    1903           0 :                 pi->sys_info.uma_channel_number = igp_info->info_7.ucUMAChannelNumber;
    1904             : 
    1905           0 :                 sumo_construct_sclk_voltage_mapping_table(rdev,
    1906           0 :                                                           &pi->sys_info.sclk_voltage_mapping_table,
    1907           0 :                                                           igp_info->info_7.sAvail_SCLK);
    1908           0 :                 sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
    1909             :                                                  igp_info->info_7.sAvail_SCLK);
    1910             : 
    1911           0 :                 pi->sys_info.uvd_clock_table_entries[0].vclk_did =
    1912           0 :                         igp_info->info_7.ucDPMState0VclkFid;
    1913           0 :                 pi->sys_info.uvd_clock_table_entries[1].vclk_did =
    1914           0 :                         igp_info->info_7.ucDPMState1VclkFid;
    1915           0 :                 pi->sys_info.uvd_clock_table_entries[2].vclk_did =
    1916           0 :                         igp_info->info_7.ucDPMState2VclkFid;
    1917           0 :                 pi->sys_info.uvd_clock_table_entries[3].vclk_did =
    1918           0 :                         igp_info->info_7.ucDPMState3VclkFid;
    1919             : 
    1920           0 :                 pi->sys_info.uvd_clock_table_entries[0].dclk_did =
    1921           0 :                         igp_info->info_7.ucDPMState0DclkFid;
    1922           0 :                 pi->sys_info.uvd_clock_table_entries[1].dclk_did =
    1923           0 :                         igp_info->info_7.ucDPMState1DclkFid;
    1924           0 :                 pi->sys_info.uvd_clock_table_entries[2].dclk_did =
    1925           0 :                         igp_info->info_7.ucDPMState2DclkFid;
    1926           0 :                 pi->sys_info.uvd_clock_table_entries[3].dclk_did =
    1927           0 :                         igp_info->info_7.ucDPMState3DclkFid;
    1928             : 
    1929           0 :                 for (i = 0; i < 4; i++) {
    1930           0 :                         pi->sys_info.uvd_clock_table_entries[i].vclk =
    1931           0 :                                 trinity_convert_did_to_freq(rdev,
    1932           0 :                                                             pi->sys_info.uvd_clock_table_entries[i].vclk_did);
    1933           0 :                         pi->sys_info.uvd_clock_table_entries[i].dclk =
    1934           0 :                                 trinity_convert_did_to_freq(rdev,
    1935           0 :                                                             pi->sys_info.uvd_clock_table_entries[i].dclk_did);
    1936             :                 }
    1937             : 
    1938             : 
    1939             : 
    1940             :         }
    1941           0 :         return 0;
    1942           0 : }
    1943             : 
    1944           0 : int trinity_dpm_init(struct radeon_device *rdev)
    1945             : {
    1946             :         struct trinity_power_info *pi;
    1947             :         int ret, i;
    1948             : 
    1949           0 :         pi = kzalloc(sizeof(struct trinity_power_info), GFP_KERNEL);
    1950           0 :         if (pi == NULL)
    1951           0 :                 return -ENOMEM;
    1952           0 :         rdev->pm.dpm.priv = pi;
    1953             : 
    1954           0 :         for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
    1955           0 :                 pi->at[i] = TRINITY_AT_DFLT;
    1956             : 
    1957           0 :         if (radeon_bapm == -1) {
    1958             :                 /* There are stability issues reported on with
    1959             :                  * bapm enabled when switching between AC and battery
    1960             :                  * power.  At the same time, some MSI boards hang
    1961             :                  * if it's not enabled and dpm is enabled.  Just enable
    1962             :                  * it for MSI boards right now.
    1963             :                  */
    1964           0 :                 if (rdev->pdev->subsystem_vendor == 0x1462)
    1965           0 :                         pi->enable_bapm = true;
    1966             :                 else
    1967           0 :                         pi->enable_bapm = false;
    1968           0 :         } else if (radeon_bapm == 0) {
    1969           0 :                 pi->enable_bapm = false;
    1970           0 :         } else {
    1971           0 :                 pi->enable_bapm = true;
    1972             :         }
    1973           0 :         pi->enable_nbps_policy = true;
    1974           0 :         pi->enable_sclk_ds = true;
    1975           0 :         pi->enable_gfx_power_gating = true;
    1976           0 :         pi->enable_gfx_clock_gating = true;
    1977           0 :         pi->enable_mg_clock_gating = false;
    1978           0 :         pi->enable_gfx_dynamic_mgpg = false;
    1979           0 :         pi->override_dynamic_mgpg = false;
    1980           0 :         pi->enable_auto_thermal_throttling = true;
    1981           0 :         pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
    1982           0 :         pi->uvd_dpm = true; /* ??? */
    1983             : 
    1984           0 :         ret = trinity_parse_sys_info_table(rdev);
    1985           0 :         if (ret)
    1986           0 :                 return ret;
    1987             : 
    1988           0 :         trinity_construct_boot_state(rdev);
    1989             : 
    1990           0 :         ret = r600_get_platform_caps(rdev);
    1991           0 :         if (ret)
    1992           0 :                 return ret;
    1993             : 
    1994           0 :         ret = r600_parse_extended_power_table(rdev);
    1995           0 :         if (ret)
    1996           0 :                 return ret;
    1997             : 
    1998           0 :         ret = trinity_parse_power_table(rdev);
    1999           0 :         if (ret)
    2000           0 :                 return ret;
    2001             : 
    2002           0 :         pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
    2003           0 :         pi->enable_dpm = true;
    2004             : 
    2005           0 :         return 0;
    2006           0 : }
    2007             : 
    2008           0 : void trinity_dpm_print_power_state(struct radeon_device *rdev,
    2009             :                                    struct radeon_ps *rps)
    2010             : {
    2011             :         int i;
    2012           0 :         struct trinity_ps *ps = trinity_get_ps(rps);
    2013             : 
    2014           0 :         r600_dpm_print_class_info(rps->class, rps->class2);
    2015           0 :         r600_dpm_print_cap_info(rps->caps);
    2016           0 :         printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
    2017           0 :         for (i = 0; i < ps->num_levels; i++) {
    2018           0 :                 struct trinity_pl *pl = &ps->levels[i];
    2019           0 :                 printk("\t\tpower level %d    sclk: %u vddc: %u\n",
    2020             :                        i, pl->sclk,
    2021             :                        trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
    2022             :         }
    2023           0 :         r600_dpm_print_ps_status(rdev, rps);
    2024           0 : }
    2025             : 
    2026           0 : void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
    2027             :                                                          struct seq_file *m)
    2028             : {
    2029           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    2030           0 :         struct radeon_ps *rps = &pi->current_rps;
    2031           0 :         struct trinity_ps *ps = trinity_get_ps(rps);
    2032             :         struct trinity_pl *pl;
    2033             :         u32 current_index =
    2034           0 :                 (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
    2035             :                 CURRENT_STATE_SHIFT;
    2036             : 
    2037           0 :         if (current_index >= ps->num_levels) {
    2038           0 :                 seq_printf(m, "invalid dpm profile %d\n", current_index);
    2039           0 :         } else {
    2040           0 :                 pl = &ps->levels[current_index];
    2041           0 :                 seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
    2042           0 :                 seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
    2043           0 :                            current_index, pl->sclk,
    2044           0 :                            trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
    2045             :         }
    2046           0 : }
    2047             : 
    2048           0 : u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev)
    2049             : {
    2050           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    2051           0 :         struct radeon_ps *rps = &pi->current_rps;
    2052           0 :         struct trinity_ps *ps = trinity_get_ps(rps);
    2053             :         struct trinity_pl *pl;
    2054             :         u32 current_index =
    2055           0 :                 (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
    2056             :                 CURRENT_STATE_SHIFT;
    2057             : 
    2058           0 :         if (current_index >= ps->num_levels) {
    2059           0 :                 return 0;
    2060             :         } else {
    2061           0 :                 pl = &ps->levels[current_index];
    2062           0 :                 return pl->sclk;
    2063             :         }
    2064           0 : }
    2065             : 
    2066           0 : u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev)
    2067             : {
    2068           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    2069             : 
    2070           0 :         return pi->sys_info.bootup_uma_clk;
    2071             : }
    2072             : 
    2073           0 : void trinity_dpm_fini(struct radeon_device *rdev)
    2074             : {
    2075             :         int i;
    2076             : 
    2077           0 :         trinity_cleanup_asic(rdev); /* ??? */
    2078             : 
    2079           0 :         for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
    2080           0 :                 kfree(rdev->pm.dpm.ps[i].ps_priv);
    2081             :         }
    2082           0 :         kfree(rdev->pm.dpm.ps);
    2083           0 :         kfree(rdev->pm.dpm.priv);
    2084           0 :         r600_free_extended_power_table(rdev);
    2085           0 : }
    2086             : 
    2087           0 : u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
    2088             : {
    2089           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    2090           0 :         struct trinity_ps *requested_state = trinity_get_ps(&pi->requested_rps);
    2091             : 
    2092           0 :         if (low)
    2093           0 :                 return requested_state->levels[0].sclk;
    2094             :         else
    2095           0 :                 return requested_state->levels[requested_state->num_levels - 1].sclk;
    2096           0 : }
    2097             : 
    2098           0 : u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low)
    2099             : {
    2100           0 :         struct trinity_power_info *pi = trinity_get_pi(rdev);
    2101             : 
    2102           0 :         return pi->sys_info.bootup_uma_clk;
    2103             : }

Generated by: LCOV version 1.13