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