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