linux/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
<<
>>
Prefs
   1/*
   2 * Copyright 2015 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#include "pp_debug.h"
  24#include <linux/types.h>
  25#include <linux/kernel.h>
  26#include <linux/slab.h>
  27#include <drm/amdgpu_drm.h>
  28#include "processpptables.h"
  29#include <atom-types.h>
  30#include <atombios.h>
  31#include "pptable.h"
  32#include "power_state.h"
  33#include "hwmgr.h"
  34#include "hardwaremanager.h"
  35
  36
  37#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
  38#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
  39#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16
  40#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18
  41#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20
  42#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22
  43#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8 24
  44#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V9 26
  45
  46#define NUM_BITS_CLOCK_INFO_ARRAY_INDEX 6
  47
  48static uint16_t get_vce_table_offset(struct pp_hwmgr *hwmgr,
  49                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
  50{
  51        uint16_t vce_table_offset = 0;
  52
  53        if (le16_to_cpu(powerplay_table->usTableSize) >=
  54           sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
  55                const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
  56                        (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
  57
  58                if (powerplay_table3->usExtendendedHeaderOffset > 0) {
  59                        const ATOM_PPLIB_EXTENDEDHEADER  *extended_header =
  60                                                (const ATOM_PPLIB_EXTENDEDHEADER *)
  61                                                (((unsigned long)powerplay_table3) +
  62                                                le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
  63                        if (le16_to_cpu(extended_header->usSize) >=
  64                           SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2)
  65                                vce_table_offset = le16_to_cpu(extended_header->usVCETableOffset);
  66                }
  67        }
  68
  69        return vce_table_offset;
  70}
  71
  72static uint16_t get_vce_clock_info_array_offset(struct pp_hwmgr *hwmgr,
  73                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
  74{
  75        uint16_t table_offset = get_vce_table_offset(hwmgr,
  76                                                powerplay_table);
  77
  78        if (table_offset > 0)
  79                return table_offset + 1;
  80
  81        return 0;
  82}
  83
  84static uint16_t get_vce_clock_info_array_size(struct pp_hwmgr *hwmgr,
  85                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
  86{
  87        uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
  88                                                        powerplay_table);
  89        uint16_t table_size = 0;
  90
  91        if (table_offset > 0) {
  92                const VCEClockInfoArray *p = (const VCEClockInfoArray *)
  93                        (((unsigned long) powerplay_table) + table_offset);
  94                table_size = sizeof(uint8_t) + p->ucNumEntries * sizeof(VCEClockInfo);
  95        }
  96
  97        return table_size;
  98}
  99
 100static uint16_t get_vce_clock_voltage_limit_table_offset(struct pp_hwmgr *hwmgr,
 101                                const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 102{
 103        uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
 104                                                        powerplay_table);
 105
 106        if (table_offset > 0)
 107                return table_offset + get_vce_clock_info_array_size(hwmgr,
 108                                                        powerplay_table);
 109
 110        return 0;
 111}
 112
 113static uint16_t get_vce_clock_voltage_limit_table_size(struct pp_hwmgr *hwmgr,
 114                                                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 115{
 116        uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
 117        uint16_t table_size = 0;
 118
 119        if (table_offset > 0) {
 120                const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *ptable =
 121                        (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)(((unsigned long) powerplay_table) + table_offset);
 122
 123                table_size = sizeof(uint8_t) + ptable->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record);
 124        }
 125        return table_size;
 126}
 127
 128static uint16_t get_vce_state_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 129{
 130        uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
 131
 132        if (table_offset > 0)
 133                return table_offset + get_vce_clock_voltage_limit_table_size(hwmgr, powerplay_table);
 134
 135        return 0;
 136}
 137
 138static const ATOM_PPLIB_VCE_State_Table *get_vce_state_table(
 139                                                struct pp_hwmgr *hwmgr,
 140                                                const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 141{
 142        uint16_t table_offset = get_vce_state_table_offset(hwmgr, powerplay_table);
 143
 144        if (table_offset > 0)
 145                return (const ATOM_PPLIB_VCE_State_Table *)(((unsigned long) powerplay_table) + table_offset);
 146
 147        return NULL;
 148}
 149
 150static uint16_t get_uvd_table_offset(struct pp_hwmgr *hwmgr,
 151                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 152{
 153        uint16_t uvd_table_offset = 0;
 154
 155        if (le16_to_cpu(powerplay_table->usTableSize) >=
 156            sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
 157                const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
 158                        (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
 159                if (powerplay_table3->usExtendendedHeaderOffset > 0) {
 160                        const ATOM_PPLIB_EXTENDEDHEADER  *extended_header =
 161                                        (const ATOM_PPLIB_EXTENDEDHEADER *)
 162                                        (((unsigned long)powerplay_table3) +
 163                                le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
 164                        if (le16_to_cpu(extended_header->usSize) >=
 165                            SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3)
 166                                uvd_table_offset = le16_to_cpu(extended_header->usUVDTableOffset);
 167                }
 168        }
 169        return uvd_table_offset;
 170}
 171
 172static uint16_t get_uvd_clock_info_array_offset(struct pp_hwmgr *hwmgr,
 173                         const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 174{
 175        uint16_t table_offset = get_uvd_table_offset(hwmgr,
 176                                                    powerplay_table);
 177
 178        if (table_offset > 0)
 179                return table_offset + 1;
 180        return 0;
 181}
 182
 183static uint16_t get_uvd_clock_info_array_size(struct pp_hwmgr *hwmgr,
 184                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 185{
 186        uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
 187                                                    powerplay_table);
 188        uint16_t table_size = 0;
 189
 190        if (table_offset > 0) {
 191                const UVDClockInfoArray *p = (const UVDClockInfoArray *)
 192                                        (((unsigned long) powerplay_table)
 193                                        + table_offset);
 194                table_size = sizeof(UCHAR) +
 195                             p->ucNumEntries * sizeof(UVDClockInfo);
 196        }
 197
 198        return table_size;
 199}
 200
 201static uint16_t get_uvd_clock_voltage_limit_table_offset(
 202                        struct pp_hwmgr *hwmgr,
 203                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 204{
 205        uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
 206                                                     powerplay_table);
 207
 208        if (table_offset > 0)
 209                return table_offset +
 210                        get_uvd_clock_info_array_size(hwmgr, powerplay_table);
 211
 212        return 0;
 213}
 214
 215static uint16_t get_samu_table_offset(struct pp_hwmgr *hwmgr,
 216                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 217{
 218        uint16_t samu_table_offset = 0;
 219
 220        if (le16_to_cpu(powerplay_table->usTableSize) >=
 221            sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
 222                const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
 223                        (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
 224                if (powerplay_table3->usExtendendedHeaderOffset > 0) {
 225                        const ATOM_PPLIB_EXTENDEDHEADER  *extended_header =
 226                                (const ATOM_PPLIB_EXTENDEDHEADER *)
 227                                (((unsigned long)powerplay_table3) +
 228                                le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
 229                        if (le16_to_cpu(extended_header->usSize) >=
 230                            SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4)
 231                                samu_table_offset = le16_to_cpu(extended_header->usSAMUTableOffset);
 232                }
 233        }
 234
 235        return samu_table_offset;
 236}
 237
 238static uint16_t get_samu_clock_voltage_limit_table_offset(
 239                        struct pp_hwmgr *hwmgr,
 240                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 241{
 242        uint16_t table_offset = get_samu_table_offset(hwmgr,
 243                                            powerplay_table);
 244
 245        if (table_offset > 0)
 246                return table_offset + 1;
 247
 248        return 0;
 249}
 250
 251static uint16_t get_acp_table_offset(struct pp_hwmgr *hwmgr,
 252                                const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 253{
 254        uint16_t acp_table_offset = 0;
 255
 256        if (le16_to_cpu(powerplay_table->usTableSize) >=
 257            sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
 258                const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
 259                        (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
 260                if (powerplay_table3->usExtendendedHeaderOffset > 0) {
 261                        const ATOM_PPLIB_EXTENDEDHEADER  *pExtendedHeader =
 262                                (const ATOM_PPLIB_EXTENDEDHEADER *)
 263                                (((unsigned long)powerplay_table3) +
 264                                le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
 265                        if (le16_to_cpu(pExtendedHeader->usSize) >=
 266                            SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6)
 267                                acp_table_offset = le16_to_cpu(pExtendedHeader->usACPTableOffset);
 268                }
 269        }
 270
 271        return acp_table_offset;
 272}
 273
 274static uint16_t get_acp_clock_voltage_limit_table_offset(
 275                                struct pp_hwmgr *hwmgr,
 276                                const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 277{
 278        uint16_t tableOffset = get_acp_table_offset(hwmgr, powerplay_table);
 279
 280        if (tableOffset > 0)
 281                return tableOffset + 1;
 282
 283        return 0;
 284}
 285
 286static uint16_t get_cacp_tdp_table_offset(
 287                                struct pp_hwmgr *hwmgr,
 288                                const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 289{
 290        uint16_t cacTdpTableOffset = 0;
 291
 292        if (le16_to_cpu(powerplay_table->usTableSize) >=
 293            sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
 294                const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
 295                                (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
 296                if (powerplay_table3->usExtendendedHeaderOffset > 0) {
 297                        const ATOM_PPLIB_EXTENDEDHEADER  *pExtendedHeader =
 298                                        (const ATOM_PPLIB_EXTENDEDHEADER *)
 299                                        (((unsigned long)powerplay_table3) +
 300                                le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
 301                        if (le16_to_cpu(pExtendedHeader->usSize) >=
 302                            SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7)
 303                                cacTdpTableOffset = le16_to_cpu(pExtendedHeader->usPowerTuneTableOffset);
 304                }
 305        }
 306
 307        return cacTdpTableOffset;
 308}
 309
 310static int get_cac_tdp_table(struct pp_hwmgr *hwmgr,
 311                                struct phm_cac_tdp_table **ptable,
 312                                const ATOM_PowerTune_Table *table,
 313                                uint16_t us_maximum_power_delivery_limit)
 314{
 315        unsigned long table_size;
 316        struct phm_cac_tdp_table *tdp_table;
 317
 318        table_size = sizeof(unsigned long) + sizeof(struct phm_cac_tdp_table);
 319
 320        tdp_table = kzalloc(table_size, GFP_KERNEL);
 321        if (NULL == tdp_table)
 322                return -ENOMEM;
 323
 324        tdp_table->usTDP = le16_to_cpu(table->usTDP);
 325        tdp_table->usConfigurableTDP = le16_to_cpu(table->usConfigurableTDP);
 326        tdp_table->usTDC = le16_to_cpu(table->usTDC);
 327        tdp_table->usBatteryPowerLimit = le16_to_cpu(table->usBatteryPowerLimit);
 328        tdp_table->usSmallPowerLimit = le16_to_cpu(table->usSmallPowerLimit);
 329        tdp_table->usLowCACLeakage = le16_to_cpu(table->usLowCACLeakage);
 330        tdp_table->usHighCACLeakage = le16_to_cpu(table->usHighCACLeakage);
 331        tdp_table->usMaximumPowerDeliveryLimit = us_maximum_power_delivery_limit;
 332
 333        *ptable = tdp_table;
 334
 335        return 0;
 336}
 337
 338static uint16_t get_sclk_vdd_gfx_table_offset(struct pp_hwmgr *hwmgr,
 339                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 340{
 341        uint16_t sclk_vdd_gfx_table_offset = 0;
 342
 343        if (le16_to_cpu(powerplay_table->usTableSize) >=
 344            sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
 345                const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
 346                                (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
 347                if (powerplay_table3->usExtendendedHeaderOffset > 0) {
 348                        const ATOM_PPLIB_EXTENDEDHEADER  *pExtendedHeader =
 349                                (const ATOM_PPLIB_EXTENDEDHEADER *)
 350                                (((unsigned long)powerplay_table3) +
 351                                le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
 352                        if (le16_to_cpu(pExtendedHeader->usSize) >=
 353                            SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8)
 354                                sclk_vdd_gfx_table_offset =
 355                                        le16_to_cpu(pExtendedHeader->usSclkVddgfxTableOffset);
 356                }
 357        }
 358
 359        return sclk_vdd_gfx_table_offset;
 360}
 361
 362static uint16_t get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(
 363                        struct pp_hwmgr *hwmgr,
 364                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 365{
 366        uint16_t tableOffset = get_sclk_vdd_gfx_table_offset(hwmgr, powerplay_table);
 367
 368        if (tableOffset > 0)
 369                return tableOffset;
 370
 371        return 0;
 372}
 373
 374
 375static int get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr,
 376                struct phm_clock_voltage_dependency_table **ptable,
 377                const ATOM_PPLIB_Clock_Voltage_Dependency_Table *table)
 378{
 379
 380        unsigned long table_size, i;
 381        struct phm_clock_voltage_dependency_table *dep_table;
 382
 383        table_size = sizeof(unsigned long) +
 384                sizeof(struct phm_clock_voltage_dependency_table)
 385                * table->ucNumEntries;
 386
 387        dep_table = kzalloc(table_size, GFP_KERNEL);
 388        if (NULL == dep_table)
 389                return -ENOMEM;
 390
 391        dep_table->count = (unsigned long)table->ucNumEntries;
 392
 393        for (i = 0; i < dep_table->count; i++) {
 394                dep_table->entries[i].clk =
 395                        ((unsigned long)table->entries[i].ucClockHigh << 16) |
 396                        le16_to_cpu(table->entries[i].usClockLow);
 397                dep_table->entries[i].v =
 398                        (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
 399        }
 400
 401        *ptable = dep_table;
 402
 403        return 0;
 404}
 405
 406static int get_valid_clk(struct pp_hwmgr *hwmgr,
 407                        struct phm_clock_array **ptable,
 408                        const struct phm_clock_voltage_dependency_table *table)
 409{
 410        unsigned long table_size, i;
 411        struct phm_clock_array *clock_table;
 412
 413        table_size = sizeof(unsigned long) + sizeof(unsigned long) * table->count;
 414        clock_table = kzalloc(table_size, GFP_KERNEL);
 415        if (NULL == clock_table)
 416                return -ENOMEM;
 417
 418        clock_table->count = (unsigned long)table->count;
 419
 420        for (i = 0; i < clock_table->count; i++)
 421                clock_table->values[i] = (unsigned long)table->entries[i].clk;
 422
 423        *ptable = clock_table;
 424
 425        return 0;
 426}
 427
 428static int get_clock_voltage_limit(struct pp_hwmgr *hwmgr,
 429                        struct phm_clock_and_voltage_limits *limits,
 430                        const ATOM_PPLIB_Clock_Voltage_Limit_Table *table)
 431{
 432        limits->sclk = ((unsigned long)table->entries[0].ucSclkHigh << 16) |
 433                        le16_to_cpu(table->entries[0].usSclkLow);
 434        limits->mclk = ((unsigned long)table->entries[0].ucMclkHigh << 16) |
 435                        le16_to_cpu(table->entries[0].usMclkLow);
 436        limits->vddc = (unsigned long)le16_to_cpu(table->entries[0].usVddc);
 437        limits->vddci = (unsigned long)le16_to_cpu(table->entries[0].usVddci);
 438
 439        return 0;
 440}
 441
 442
 443static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable,
 444                       enum phm_platform_caps cap)
 445{
 446        if (enable)
 447                phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
 448        else
 449                phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
 450}
 451
 452static int set_platform_caps(struct pp_hwmgr *hwmgr,
 453                        unsigned long powerplay_caps)
 454{
 455        set_hw_cap(
 456                hwmgr,
 457                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_POWERPLAY),
 458                PHM_PlatformCaps_PowerPlaySupport
 459        );
 460
 461        set_hw_cap(
 462                hwmgr,
 463                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
 464                PHM_PlatformCaps_BiosPowerSourceControl
 465        );
 466
 467        set_hw_cap(
 468                hwmgr,
 469                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s),
 470                PHM_PlatformCaps_EnableASPML0s
 471        );
 472
 473        set_hw_cap(
 474                hwmgr,
 475                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1),
 476                PHM_PlatformCaps_EnableASPML1
 477        );
 478
 479        set_hw_cap(
 480                hwmgr,
 481                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS),
 482                PHM_PlatformCaps_EnableBackbias
 483        );
 484
 485        set_hw_cap(
 486                hwmgr,
 487                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC),
 488                PHM_PlatformCaps_AutomaticDCTransition
 489        );
 490
 491        set_hw_cap(
 492                hwmgr,
 493                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY),
 494                PHM_PlatformCaps_GeminiPrimary
 495        );
 496
 497        set_hw_cap(
 498                hwmgr,
 499                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC),
 500                PHM_PlatformCaps_StepVddc
 501        );
 502
 503        set_hw_cap(
 504                hwmgr,
 505                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL),
 506                PHM_PlatformCaps_EnableVoltageControl
 507        );
 508
 509        set_hw_cap(
 510                hwmgr,
 511                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL),
 512                PHM_PlatformCaps_EnableSideportControl
 513        );
 514
 515        set_hw_cap(
 516                hwmgr,
 517                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1),
 518                PHM_PlatformCaps_TurnOffPll_ASPML1
 519        );
 520
 521        set_hw_cap(
 522                hwmgr,
 523                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HTLINKCONTROL),
 524                PHM_PlatformCaps_EnableHTLinkControl
 525        );
 526
 527        set_hw_cap(
 528                hwmgr,
 529                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL),
 530                PHM_PlatformCaps_EnableMVDDControl
 531        );
 532
 533        set_hw_cap(
 534                hwmgr,
 535                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL),
 536                PHM_PlatformCaps_ControlVDDCI
 537        );
 538
 539        set_hw_cap(
 540                hwmgr,
 541                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT),
 542                PHM_PlatformCaps_RegulatorHot
 543        );
 544
 545        set_hw_cap(
 546                hwmgr,
 547                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT),
 548                PHM_PlatformCaps_BootStateOnAlert
 549        );
 550
 551        set_hw_cap(
 552                hwmgr,
 553                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT),
 554                PHM_PlatformCaps_DontWaitForVBlankOnAlert
 555        );
 556
 557        set_hw_cap(
 558                hwmgr,
 559                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACO),
 560                PHM_PlatformCaps_BACO
 561        );
 562
 563        set_hw_cap(
 564                hwmgr,
 565                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE),
 566                PHM_PlatformCaps_NewCACVoltage
 567        );
 568
 569        set_hw_cap(
 570                hwmgr,
 571                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY),
 572                PHM_PlatformCaps_RevertGPIO5Polarity
 573        );
 574
 575        set_hw_cap(
 576                hwmgr,
 577                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17),
 578                PHM_PlatformCaps_Thermal2GPIO17
 579        );
 580
 581        set_hw_cap(
 582                hwmgr,
 583                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE),
 584                PHM_PlatformCaps_VRHotGPIOConfigurable
 585        );
 586
 587        set_hw_cap(
 588                hwmgr,
 589                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TEMP_INVERSION),
 590                PHM_PlatformCaps_TempInversion
 591        );
 592
 593        set_hw_cap(
 594                hwmgr,
 595                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_EVV),
 596                PHM_PlatformCaps_EVV
 597        );
 598
 599        set_hw_cap(
 600                hwmgr,
 601                0 != (powerplay_caps & ATOM_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
 602                PHM_PlatformCaps_CombinePCCWithThermalSignal
 603        );
 604
 605        set_hw_cap(
 606                hwmgr,
 607                0 != (powerplay_caps & ATOM_PP_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
 608                PHM_PlatformCaps_LoadPostProductionFirmware
 609        );
 610
 611        set_hw_cap(
 612                hwmgr,
 613                0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DISABLE_USING_ACTUAL_TEMPERATURE_FOR_POWER_CALC),
 614                PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc
 615        );
 616
 617        return 0;
 618}
 619
 620static PP_StateClassificationFlags make_classification_flags(
 621                                                   struct pp_hwmgr *hwmgr,
 622                                                    USHORT classification,
 623                                                   USHORT classification2)
 624{
 625        PP_StateClassificationFlags result = 0;
 626
 627        if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
 628                result |= PP_StateClassificationFlag_Boot;
 629
 630        if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
 631                result |= PP_StateClassificationFlag_Thermal;
 632
 633        if (classification &
 634                        ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
 635                result |= PP_StateClassificationFlag_LimitedPowerSource;
 636
 637        if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
 638                result |= PP_StateClassificationFlag_Rest;
 639
 640        if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
 641                result |= PP_StateClassificationFlag_Forced;
 642
 643        if (classification & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
 644                result |= PP_StateClassificationFlag_3DPerformance;
 645
 646
 647        if (classification & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
 648                result |= PP_StateClassificationFlag_ACOverdriveTemplate;
 649
 650        if (classification & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
 651                result |= PP_StateClassificationFlag_Uvd;
 652
 653        if (classification & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
 654                result |= PP_StateClassificationFlag_UvdHD;
 655
 656        if (classification & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
 657                result |= PP_StateClassificationFlag_UvdSD;
 658
 659        if (classification & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
 660                result |= PP_StateClassificationFlag_HD2;
 661
 662        if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
 663                result |= PP_StateClassificationFlag_ACPI;
 664
 665        if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
 666                result |= PP_StateClassificationFlag_LimitedPowerSource_2;
 667
 668
 669        if (classification2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
 670                result |= PP_StateClassificationFlag_ULV;
 671
 672        if (classification2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
 673                result |= PP_StateClassificationFlag_UvdMVC;
 674
 675        return result;
 676}
 677
 678static int init_non_clock_fields(struct pp_hwmgr *hwmgr,
 679                                                struct pp_power_state *ps,
 680                                                            uint8_t version,
 681                         const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info) {
 682        unsigned long rrr_index;
 683        unsigned long tmp;
 684
 685        ps->classification.ui_label = (le16_to_cpu(pnon_clock_info->usClassification) &
 686                                        ATOM_PPLIB_CLASSIFICATION_UI_MASK) >> ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
 687        ps->classification.flags = make_classification_flags(hwmgr,
 688                                le16_to_cpu(pnon_clock_info->usClassification),
 689                                le16_to_cpu(pnon_clock_info->usClassification2));
 690
 691        ps->classification.temporary_state = false;
 692        ps->classification.to_be_deleted = false;
 693        tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 694                ATOM_PPLIB_SINGLE_DISPLAY_ONLY;
 695
 696        ps->validation.singleDisplayOnly = (0 != tmp);
 697
 698        tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 699                ATOM_PPLIB_DISALLOW_ON_DC;
 700
 701        ps->validation.disallowOnDC = (0 != tmp);
 702
 703        ps->pcie.lanes = ((le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 704                                ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
 705                                ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
 706
 707        ps->pcie.lanes = 0;
 708
 709        ps->display.disableFrameModulation = false;
 710
 711        rrr_index = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 712                        ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK) >>
 713                        ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT;
 714
 715        if (rrr_index != ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED) {
 716                static const uint8_t look_up[(ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK >> ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT) + 1] = \
 717                                                                { 0, 50, 0 };
 718
 719                ps->display.refreshrateSource = PP_RefreshrateSource_Explicit;
 720                ps->display.explicitRefreshrate = look_up[rrr_index];
 721                ps->display.limitRefreshrate = true;
 722
 723                if (ps->display.explicitRefreshrate == 0)
 724                        ps->display.limitRefreshrate = false;
 725        } else
 726                ps->display.limitRefreshrate = false;
 727
 728        tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 729                ATOM_PPLIB_ENABLE_VARIBRIGHT;
 730
 731        ps->display.enableVariBright = (0 != tmp);
 732
 733        tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 734                ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF;
 735
 736        ps->memory.dllOff = (0 != tmp);
 737
 738        ps->memory.m3arb = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 739                            ATOM_PPLIB_M3ARB_MASK) >> ATOM_PPLIB_M3ARB_SHIFT;
 740
 741        ps->temperatures.min = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
 742                                     pnon_clock_info->ucMinTemperature;
 743
 744        ps->temperatures.max = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
 745                                     pnon_clock_info->ucMaxTemperature;
 746
 747        tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 748                ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING;
 749
 750        ps->software.disableLoadBalancing = tmp;
 751
 752        tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 753                ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS;
 754
 755        ps->software.enableSleepForTimestamps = (0 != tmp);
 756
 757        ps->validation.supportedPowerLevels = pnon_clock_info->ucRequiredPower;
 758
 759        if (ATOM_PPLIB_NONCLOCKINFO_VER1 < version) {
 760                ps->uvd_clocks.VCLK = le32_to_cpu(pnon_clock_info->ulVCLK);
 761                ps->uvd_clocks.DCLK = le32_to_cpu(pnon_clock_info->ulDCLK);
 762        } else {
 763                ps->uvd_clocks.VCLK = 0;
 764                ps->uvd_clocks.DCLK = 0;
 765        }
 766
 767        return 0;
 768}
 769
 770static ULONG size_of_entry_v2(ULONG num_dpm_levels)
 771{
 772        return (sizeof(UCHAR) + sizeof(UCHAR) +
 773                        (num_dpm_levels * sizeof(UCHAR)));
 774}
 775
 776static const ATOM_PPLIB_STATE_V2 *get_state_entry_v2(
 777                                        const StateArray * pstate_arrays,
 778                                                         ULONG entry_index)
 779{
 780        ULONG i;
 781        const ATOM_PPLIB_STATE_V2 *pstate;
 782
 783        pstate = pstate_arrays->states;
 784        if (entry_index <= pstate_arrays->ucNumEntries) {
 785                for (i = 0; i < entry_index; i++)
 786                        pstate = (ATOM_PPLIB_STATE_V2 *)(
 787                                                  (unsigned long)pstate +
 788                             size_of_entry_v2(pstate->ucNumDPMLevels));
 789        }
 790        return pstate;
 791}
 792
 793static const unsigned char soft_dummy_pp_table[] = {
 794        0xe1, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x4a, 0x00, 0x6c, 0x00, 0x00,
 795        0x00, 0x00, 0x00, 0x42, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
 796        0x00, 0x4e, 0x00, 0x88, 0x00, 0x00, 0x9e, 0x00, 0x17, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
 797        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 798        0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
 799        0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 800        0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x18, 0x05, 0x00,
 801        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 802        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 803        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00,
 804        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00,
 805        0x8e, 0x01, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c,
 806        0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x70, 0x00, 0x91, 0xf4, 0x00,
 807        0x64, 0x00, 0x40, 0x19, 0x01, 0x5a, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a,
 808        0x00, 0x00, 0x09, 0x30, 0x75, 0x00, 0x30, 0x75, 0x00, 0x40, 0x9c, 0x00, 0x40, 0x9c, 0x00, 0x59,
 809        0xd8, 0x00, 0x59, 0xd8, 0x00, 0x91, 0xf4, 0x00, 0x91, 0xf4, 0x00, 0x0e, 0x28, 0x01, 0x0e, 0x28,
 810        0x01, 0x90, 0x5f, 0x01, 0x90, 0x5f, 0x01, 0x00, 0x77, 0x01, 0x00, 0x77, 0x01, 0xca, 0x91, 0x01,
 811        0xca, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01,
 812        0x7c, 0x00, 0x02, 0x70, 0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a,
 813        0x00, 0x07, 0x08, 0x08, 0x00, 0x08, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03,
 814        0x02, 0x04, 0x02, 0x00, 0x08, 0x40, 0x9c, 0x00, 0x30, 0x75, 0x00, 0x74, 0xb5, 0x00, 0xa0, 0x8c,
 815        0x00, 0x60, 0xea, 0x00, 0x74, 0xb5, 0x00, 0x0e, 0x28, 0x01, 0x60, 0xea, 0x00, 0x90, 0x5f, 0x01,
 816        0x40, 0x19, 0x01, 0xb2, 0xb0, 0x01, 0x90, 0x5f, 0x01, 0xc0, 0xd4, 0x01, 0x00, 0x77, 0x01, 0x5e,
 817        0xff, 0x01, 0xca, 0x91, 0x01, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01, 0x7c, 0x00, 0x02, 0x70,
 818        0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a, 0x00, 0x07, 0x00, 0x08,
 819        0x80, 0x00, 0x30, 0x75, 0x00, 0x7e, 0x00, 0x40, 0x9c, 0x00, 0x7c, 0x00, 0x59, 0xd8, 0x00, 0x70,
 820        0x00, 0xdc, 0x0b, 0x01, 0x64, 0x00, 0x80, 0x38, 0x01, 0x5a, 0x00, 0x80, 0x38, 0x01, 0x52, 0x00,
 821        0x80, 0x38, 0x01, 0x4a, 0x00, 0x80, 0x38, 0x01, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c,
 822        0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x74, 0x00, 0x91, 0xf4, 0x00,
 823        0x66, 0x00, 0x40, 0x19, 0x01, 0x58, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a,
 824        0x00
 825};
 826
 827static const ATOM_PPLIB_POWERPLAYTABLE *get_powerplay_table(
 828                                     struct pp_hwmgr *hwmgr)
 829{
 830        const void *table_addr = hwmgr->soft_pp_table;
 831        uint8_t frev, crev;
 832        uint16_t size;
 833
 834        if (!table_addr) {
 835                if (hwmgr->chip_id == CHIP_RAVEN) {
 836                        table_addr = &soft_dummy_pp_table[0];
 837                        hwmgr->soft_pp_table = &soft_dummy_pp_table[0];
 838                        hwmgr->soft_pp_table_size = sizeof(soft_dummy_pp_table);
 839                } else {
 840                        table_addr = smu_atom_get_data_table(hwmgr->adev,
 841                                        GetIndexIntoMasterTable(DATA, PowerPlayInfo),
 842                                        &size, &frev, &crev);
 843                        hwmgr->soft_pp_table = table_addr;
 844                        hwmgr->soft_pp_table_size = size;
 845                }
 846        }
 847
 848        return (const ATOM_PPLIB_POWERPLAYTABLE *)table_addr;
 849}
 850
 851int pp_tables_get_response_times(struct pp_hwmgr *hwmgr,
 852                                uint32_t *vol_rep_time, uint32_t *bb_rep_time)
 853{
 854        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_tab = get_powerplay_table(hwmgr);
 855
 856        PP_ASSERT_WITH_CODE(NULL != powerplay_tab,
 857                            "Missing PowerPlay Table!", return -EINVAL);
 858
 859        *vol_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usVoltageTime);
 860        *bb_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usBackbiasTime);
 861
 862        return 0;
 863}
 864
 865int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr,
 866                                     unsigned long *num_of_entries)
 867{
 868        const StateArray *pstate_arrays;
 869        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
 870
 871        if (powerplay_table == NULL)
 872                return -1;
 873
 874        if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
 875                pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
 876                                        le16_to_cpu(powerplay_table->usStateArrayOffset));
 877
 878                *num_of_entries = (unsigned long)(pstate_arrays->ucNumEntries);
 879        } else
 880                *num_of_entries = (unsigned long)(powerplay_table->ucNumStates);
 881
 882        return 0;
 883}
 884
 885int pp_tables_get_entry(struct pp_hwmgr *hwmgr,
 886                                unsigned long entry_index,
 887                                struct pp_power_state *ps,
 888                         pp_tables_hw_clock_info_callback func)
 889{
 890        int i;
 891        const StateArray *pstate_arrays;
 892        const ATOM_PPLIB_STATE_V2 *pstate_entry_v2;
 893        const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info;
 894        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
 895        int result = 0;
 896        int res = 0;
 897
 898        const ClockInfoArray *pclock_arrays;
 899
 900        const NonClockInfoArray *pnon_clock_arrays;
 901
 902        const ATOM_PPLIB_STATE *pstate_entry;
 903
 904        if (powerplay_table == NULL)
 905                return -1;
 906
 907        ps->classification.bios_index = entry_index;
 908
 909        if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
 910                pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
 911                                        le16_to_cpu(powerplay_table->usStateArrayOffset));
 912
 913                if (entry_index > pstate_arrays->ucNumEntries)
 914                        return -1;
 915
 916                pstate_entry_v2 = get_state_entry_v2(pstate_arrays, entry_index);
 917                pclock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
 918                                        le16_to_cpu(powerplay_table->usClockInfoArrayOffset));
 919
 920                pnon_clock_arrays = (NonClockInfoArray *)(((unsigned long)powerplay_table) +
 921                                                le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset));
 922
 923                pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)(pnon_clock_arrays->nonClockInfo) +
 924                                        (pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize));
 925
 926                result = init_non_clock_fields(hwmgr, ps, pnon_clock_arrays->ucEntrySize, pnon_clock_info);
 927
 928                for (i = 0; i < pstate_entry_v2->ucNumDPMLevels; i++) {
 929                        const void *pclock_info = (const void *)(
 930                                                        (unsigned long)(pclock_arrays->clockInfo) +
 931                                                        (pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize));
 932                        res = func(hwmgr, &ps->hardware, i, pclock_info);
 933                        if ((0 == result) && (0 != res))
 934                                result = res;
 935                }
 936        } else {
 937                if (entry_index > powerplay_table->ucNumStates)
 938                        return -1;
 939
 940                pstate_entry = (ATOM_PPLIB_STATE *)((unsigned long)powerplay_table +
 941                                                    le16_to_cpu(powerplay_table->usStateArrayOffset) +
 942                                                    entry_index * powerplay_table->ucStateEntrySize);
 943
 944                pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)powerplay_table +
 945                                                le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset) +
 946                                                pstate_entry->ucNonClockStateIndex *
 947                                                powerplay_table->ucNonClockSize);
 948
 949                result = init_non_clock_fields(hwmgr, ps,
 950                                                        powerplay_table->ucNonClockSize,
 951                                                        pnon_clock_info);
 952
 953                for (i = 0; i < powerplay_table->ucStateEntrySize-1; i++) {
 954                        const void *pclock_info = (const void *)((unsigned long)powerplay_table +
 955                                                le16_to_cpu(powerplay_table->usClockInfoArrayOffset) +
 956                                                pstate_entry->ucClockStateIndices[i] *
 957                                                powerplay_table->ucClockInfoSize);
 958
 959                        int res = func(hwmgr, &ps->hardware, i, pclock_info);
 960
 961                        if ((0 == result) && (0 != res))
 962                                        result = res;
 963                }
 964        }
 965
 966        if ((0 == result) && (0 != (ps->classification.flags & PP_StateClassificationFlag_Boot))) {
 967                if (hwmgr->chip_family < AMDGPU_FAMILY_RV)
 968                        result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(ps->hardware));
 969        }
 970
 971        return result;
 972}
 973
 974static int init_powerplay_tables(
 975                        struct pp_hwmgr *hwmgr,
 976                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table
 977)
 978{
 979        return 0;
 980}
 981
 982
 983static int init_thermal_controller(
 984                        struct pp_hwmgr *hwmgr,
 985                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 986{
 987        return 0;
 988}
 989
 990static int init_overdrive_limits_V1_4(struct pp_hwmgr *hwmgr,
 991                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
 992                        const ATOM_FIRMWARE_INFO_V1_4 *fw_info)
 993{
 994        hwmgr->platform_descriptor.overdriveLimit.engineClock =
 995                                le32_to_cpu(fw_info->ulASICMaxEngineClock);
 996
 997        hwmgr->platform_descriptor.overdriveLimit.memoryClock =
 998                                le32_to_cpu(fw_info->ulASICMaxMemoryClock);
 999
1000        hwmgr->platform_descriptor.maxOverdriveVDDC =
1001                le32_to_cpu(fw_info->ul3DAccelerationEngineClock) & 0x7FF;
1002
1003        hwmgr->platform_descriptor.minOverdriveVDDC =
1004                           le16_to_cpu(fw_info->usBootUpVDDCVoltage);
1005
1006        hwmgr->platform_descriptor.maxOverdriveVDDC =
1007                           le16_to_cpu(fw_info->usBootUpVDDCVoltage);
1008
1009        hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1010        return 0;
1011}
1012
1013static int init_overdrive_limits_V2_1(struct pp_hwmgr *hwmgr,
1014                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
1015                        const ATOM_FIRMWARE_INFO_V2_1 *fw_info)
1016{
1017        const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3;
1018        const ATOM_PPLIB_EXTENDEDHEADER *header;
1019
1020        if (le16_to_cpu(powerplay_table->usTableSize) <
1021            sizeof(ATOM_PPLIB_POWERPLAYTABLE3))
1022                return 0;
1023
1024        powerplay_table3 = (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
1025
1026        if (0 == powerplay_table3->usExtendendedHeaderOffset)
1027                return 0;
1028
1029        header = (ATOM_PPLIB_EXTENDEDHEADER *)(((unsigned long) powerplay_table) +
1030                        le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
1031
1032        hwmgr->platform_descriptor.overdriveLimit.engineClock = le32_to_cpu(header->ulMaxEngineClock);
1033        hwmgr->platform_descriptor.overdriveLimit.memoryClock = le32_to_cpu(header->ulMaxMemoryClock);
1034
1035
1036        hwmgr->platform_descriptor.minOverdriveVDDC = 0;
1037        hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
1038        hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1039
1040        return 0;
1041}
1042
1043static int init_overdrive_limits(struct pp_hwmgr *hwmgr,
1044                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1045{
1046        int result = 0;
1047        uint8_t frev, crev;
1048        uint16_t size;
1049
1050        const ATOM_COMMON_TABLE_HEADER *fw_info = NULL;
1051
1052        hwmgr->platform_descriptor.overdriveLimit.engineClock = 0;
1053        hwmgr->platform_descriptor.overdriveLimit.memoryClock = 0;
1054        hwmgr->platform_descriptor.minOverdriveVDDC = 0;
1055        hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
1056        hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1057
1058        if (hwmgr->chip_id == CHIP_RAVEN)
1059                return 0;
1060
1061        /* We assume here that fw_info is unchanged if this call fails.*/
1062        fw_info = smu_atom_get_data_table(hwmgr->adev,
1063                         GetIndexIntoMasterTable(DATA, FirmwareInfo),
1064                         &size, &frev, &crev);
1065
1066        if ((fw_info->ucTableFormatRevision == 1)
1067            && (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V1_4)))
1068                result = init_overdrive_limits_V1_4(hwmgr,
1069                                powerplay_table,
1070                                (const ATOM_FIRMWARE_INFO_V1_4 *)fw_info);
1071
1072        else if ((fw_info->ucTableFormatRevision == 2)
1073                 && (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V2_1)))
1074                result = init_overdrive_limits_V2_1(hwmgr,
1075                                powerplay_table,
1076                                (const ATOM_FIRMWARE_INFO_V2_1 *)fw_info);
1077
1078        return result;
1079}
1080
1081static int get_uvd_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1082                struct phm_uvd_clock_voltage_dependency_table **ptable,
1083                const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *table,
1084                const UVDClockInfoArray *array)
1085{
1086        unsigned long table_size, i;
1087        struct phm_uvd_clock_voltage_dependency_table *uvd_table;
1088
1089        table_size = sizeof(unsigned long) +
1090                 sizeof(struct phm_uvd_clock_voltage_dependency_table) *
1091                 table->numEntries;
1092
1093        uvd_table = kzalloc(table_size, GFP_KERNEL);
1094        if (NULL == uvd_table)
1095                return -ENOMEM;
1096
1097        uvd_table->count = table->numEntries;
1098
1099        for (i = 0; i < table->numEntries; i++) {
1100                const UVDClockInfo *entry =
1101                        &array->entries[table->entries[i].ucUVDClockInfoIndex];
1102                uvd_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1103                uvd_table->entries[i].vclk = ((unsigned long)entry->ucVClkHigh << 16)
1104                                         | le16_to_cpu(entry->usVClkLow);
1105                uvd_table->entries[i].dclk = ((unsigned long)entry->ucDClkHigh << 16)
1106                                         | le16_to_cpu(entry->usDClkLow);
1107        }
1108
1109        *ptable = uvd_table;
1110
1111        return 0;
1112}
1113
1114static int get_vce_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1115                struct phm_vce_clock_voltage_dependency_table **ptable,
1116                const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table,
1117                const VCEClockInfoArray    *array)
1118{
1119        unsigned long table_size, i;
1120        struct phm_vce_clock_voltage_dependency_table *vce_table = NULL;
1121
1122        table_size = sizeof(unsigned long) +
1123                        sizeof(struct phm_vce_clock_voltage_dependency_table)
1124                        * table->numEntries;
1125
1126        vce_table = kzalloc(table_size, GFP_KERNEL);
1127        if (NULL == vce_table)
1128                return -ENOMEM;
1129
1130        vce_table->count = table->numEntries;
1131        for (i = 0; i < table->numEntries; i++) {
1132                const VCEClockInfo *entry = &array->entries[table->entries[i].ucVCEClockInfoIndex];
1133
1134                vce_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1135                vce_table->entries[i].evclk = ((unsigned long)entry->ucEVClkHigh << 16)
1136                                        | le16_to_cpu(entry->usEVClkLow);
1137                vce_table->entries[i].ecclk = ((unsigned long)entry->ucECClkHigh << 16)
1138                                        | le16_to_cpu(entry->usECClkLow);
1139        }
1140
1141        *ptable = vce_table;
1142
1143        return 0;
1144}
1145
1146static int get_samu_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1147                 struct phm_samu_clock_voltage_dependency_table **ptable,
1148                 const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *table)
1149{
1150        unsigned long table_size, i;
1151        struct phm_samu_clock_voltage_dependency_table *samu_table;
1152
1153        table_size = sizeof(unsigned long) +
1154                sizeof(struct phm_samu_clock_voltage_dependency_table) *
1155                table->numEntries;
1156
1157        samu_table = kzalloc(table_size, GFP_KERNEL);
1158        if (NULL == samu_table)
1159                return -ENOMEM;
1160
1161        samu_table->count = table->numEntries;
1162
1163        for (i = 0; i < table->numEntries; i++) {
1164                samu_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1165                samu_table->entries[i].samclk = ((unsigned long)table->entries[i].ucSAMClockHigh << 16)
1166                                         | le16_to_cpu(table->entries[i].usSAMClockLow);
1167        }
1168
1169        *ptable = samu_table;
1170
1171        return 0;
1172}
1173
1174static int get_acp_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1175                struct phm_acp_clock_voltage_dependency_table **ptable,
1176                const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *table)
1177{
1178        unsigned table_size, i;
1179        struct phm_acp_clock_voltage_dependency_table *acp_table;
1180
1181        table_size = sizeof(unsigned long) +
1182                sizeof(struct phm_acp_clock_voltage_dependency_table) *
1183                table->numEntries;
1184
1185        acp_table = kzalloc(table_size, GFP_KERNEL);
1186        if (NULL == acp_table)
1187                return -ENOMEM;
1188
1189        acp_table->count = (unsigned long)table->numEntries;
1190
1191        for (i = 0; i < table->numEntries; i++) {
1192                acp_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1193                acp_table->entries[i].acpclk = ((unsigned long)table->entries[i].ucACPClockHigh << 16)
1194                                         | le16_to_cpu(table->entries[i].usACPClockLow);
1195        }
1196
1197        *ptable = acp_table;
1198
1199        return 0;
1200}
1201
1202static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr,
1203                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1204{
1205        ATOM_PPLIB_Clock_Voltage_Dependency_Table *table;
1206        ATOM_PPLIB_Clock_Voltage_Limit_Table *limit_table;
1207        int result = 0;
1208
1209        uint16_t vce_clock_info_array_offset;
1210        uint16_t uvd_clock_info_array_offset;
1211        uint16_t table_offset;
1212
1213        hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
1214        hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
1215        hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
1216        hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
1217        hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
1218        hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
1219        hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
1220        hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
1221        hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
1222        hwmgr->dyn_state.ppm_parameter_table = NULL;
1223        hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
1224
1225        vce_clock_info_array_offset = get_vce_clock_info_array_offset(
1226                                                hwmgr, powerplay_table);
1227        table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr,
1228                                                powerplay_table);
1229        if (vce_clock_info_array_offset > 0 && table_offset > 0) {
1230                const VCEClockInfoArray *array = (const VCEClockInfoArray *)
1231                                (((unsigned long) powerplay_table) +
1232                                vce_clock_info_array_offset);
1233                const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table =
1234                                (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)
1235                                (((unsigned long) powerplay_table) + table_offset);
1236                result = get_vce_clock_voltage_limit_table(hwmgr,
1237                                &hwmgr->dyn_state.vce_clock_voltage_dependency_table,
1238                                table, array);
1239        }
1240
1241        uvd_clock_info_array_offset = get_uvd_clock_info_array_offset(hwmgr, powerplay_table);
1242        table_offset = get_uvd_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
1243
1244        if (uvd_clock_info_array_offset > 0 && table_offset > 0) {
1245                const UVDClockInfoArray *array = (const UVDClockInfoArray *)
1246                                (((unsigned long) powerplay_table) +
1247                                uvd_clock_info_array_offset);
1248                const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *ptable =
1249                                (const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *)
1250                                (((unsigned long) powerplay_table) + table_offset);
1251                result = get_uvd_clock_voltage_limit_table(hwmgr,
1252                                &hwmgr->dyn_state.uvd_clock_voltage_dependency_table, ptable, array);
1253        }
1254
1255        table_offset = get_samu_clock_voltage_limit_table_offset(hwmgr,
1256                                                            powerplay_table);
1257
1258        if (table_offset > 0) {
1259                const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *ptable =
1260                                (const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *)
1261                                (((unsigned long) powerplay_table) + table_offset);
1262                result = get_samu_clock_voltage_limit_table(hwmgr,
1263                                &hwmgr->dyn_state.samu_clock_voltage_dependency_table, ptable);
1264        }
1265
1266        table_offset = get_acp_clock_voltage_limit_table_offset(hwmgr,
1267                                                             powerplay_table);
1268
1269        if (table_offset > 0) {
1270                const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *ptable =
1271                                (const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *)
1272                                (((unsigned long) powerplay_table) + table_offset);
1273                result = get_acp_clock_voltage_limit_table(hwmgr,
1274                                &hwmgr->dyn_state.acp_clock_voltage_dependency_table, ptable);
1275        }
1276
1277        table_offset = get_cacp_tdp_table_offset(hwmgr, powerplay_table);
1278        if (table_offset > 0) {
1279                UCHAR rev_id = *(UCHAR *)(((unsigned long)powerplay_table) + table_offset);
1280
1281                if (rev_id > 0) {
1282                        const ATOM_PPLIB_POWERTUNE_Table_V1 *tune_table =
1283                                (const ATOM_PPLIB_POWERTUNE_Table_V1 *)
1284                                (((unsigned long) powerplay_table) + table_offset);
1285                        result = get_cac_tdp_table(hwmgr, &hwmgr->dyn_state.cac_dtp_table,
1286                                &tune_table->power_tune_table,
1287                                le16_to_cpu(tune_table->usMaximumPowerDeliveryLimit));
1288                        hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
1289                                le16_to_cpu(tune_table->usTjMax);
1290                } else {
1291                        const ATOM_PPLIB_POWERTUNE_Table *tune_table =
1292                                (const ATOM_PPLIB_POWERTUNE_Table *)
1293                                (((unsigned long) powerplay_table) + table_offset);
1294                        result = get_cac_tdp_table(hwmgr,
1295                                &hwmgr->dyn_state.cac_dtp_table,
1296                                &tune_table->power_tune_table, 255);
1297                }
1298        }
1299
1300        if (le16_to_cpu(powerplay_table->usTableSize) >=
1301                sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
1302                const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
1303                                (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
1304                if (0 != powerplay_table4->usVddcDependencyOnSCLKOffset) {
1305                        table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1306                                (((unsigned long) powerplay_table4) +
1307                                 le16_to_cpu(powerplay_table4->usVddcDependencyOnSCLKOffset));
1308                        result = get_clock_voltage_dependency_table(hwmgr,
1309                                &hwmgr->dyn_state.vddc_dependency_on_sclk, table);
1310                }
1311
1312                if (result == 0 && (0 != powerplay_table4->usVddciDependencyOnMCLKOffset)) {
1313                        table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1314                                (((unsigned long) powerplay_table4) +
1315                                 le16_to_cpu(powerplay_table4->usVddciDependencyOnMCLKOffset));
1316                        result = get_clock_voltage_dependency_table(hwmgr,
1317                                &hwmgr->dyn_state.vddci_dependency_on_mclk, table);
1318                }
1319
1320                if (result == 0 && (0 != powerplay_table4->usVddcDependencyOnMCLKOffset)) {
1321                        table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1322                                (((unsigned long) powerplay_table4) +
1323                                 le16_to_cpu(powerplay_table4->usVddcDependencyOnMCLKOffset));
1324                        result = get_clock_voltage_dependency_table(hwmgr,
1325                                &hwmgr->dyn_state.vddc_dependency_on_mclk, table);
1326                }
1327
1328                if (result == 0 && (0 != powerplay_table4->usMaxClockVoltageOnDCOffset)) {
1329                        limit_table = (ATOM_PPLIB_Clock_Voltage_Limit_Table *)
1330                                (((unsigned long) powerplay_table4) +
1331                                 le16_to_cpu(powerplay_table4->usMaxClockVoltageOnDCOffset));
1332                        result = get_clock_voltage_limit(hwmgr,
1333                                &hwmgr->dyn_state.max_clock_voltage_on_dc, limit_table);
1334                }
1335
1336                if (result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_mclk) &&
1337                        (0 != hwmgr->dyn_state.vddc_dependency_on_mclk->count))
1338                        result = get_valid_clk(hwmgr, &hwmgr->dyn_state.valid_mclk_values,
1339                                        hwmgr->dyn_state.vddc_dependency_on_mclk);
1340
1341                if(result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_sclk) &&
1342                        (0 != hwmgr->dyn_state.vddc_dependency_on_sclk->count))
1343                        result = get_valid_clk(hwmgr,
1344                                &hwmgr->dyn_state.valid_sclk_values,
1345                                hwmgr->dyn_state.vddc_dependency_on_sclk);
1346
1347                if (result == 0 && (0 != powerplay_table4->usMvddDependencyOnMCLKOffset)) {
1348                        table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1349                                (((unsigned long) powerplay_table4) +
1350                                 le16_to_cpu(powerplay_table4->usMvddDependencyOnMCLKOffset));
1351                        result = get_clock_voltage_dependency_table(hwmgr,
1352                                &hwmgr->dyn_state.mvdd_dependency_on_mclk, table);
1353                }
1354        }
1355
1356        table_offset = get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(hwmgr,
1357                                                                powerplay_table);
1358
1359        if (table_offset > 0) {
1360                table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1361                        (((unsigned long) powerplay_table) + table_offset);
1362                result = get_clock_voltage_dependency_table(hwmgr,
1363                        &hwmgr->dyn_state.vdd_gfx_dependency_on_sclk, table);
1364        }
1365
1366        return result;
1367}
1368
1369static int get_cac_leakage_table(struct pp_hwmgr *hwmgr,
1370                                 struct phm_cac_leakage_table **ptable,
1371                                const ATOM_PPLIB_CAC_Leakage_Table *table)
1372{
1373        struct phm_cac_leakage_table  *cac_leakage_table;
1374        unsigned long            table_size, i;
1375
1376        if (hwmgr == NULL || table == NULL || ptable == NULL)
1377                return -EINVAL;
1378
1379        table_size = sizeof(ULONG) +
1380                (sizeof(struct phm_cac_leakage_table) * table->ucNumEntries);
1381
1382        cac_leakage_table = kzalloc(table_size, GFP_KERNEL);
1383
1384        if (cac_leakage_table == NULL)
1385                return -ENOMEM;
1386
1387        cac_leakage_table->count = (ULONG)table->ucNumEntries;
1388
1389        for (i = 0; i < cac_leakage_table->count; i++) {
1390                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1391                                PHM_PlatformCaps_EVV)) {
1392                        cac_leakage_table->entries[i].Vddc1 = le16_to_cpu(table->entries[i].usVddc1);
1393                        cac_leakage_table->entries[i].Vddc2 = le16_to_cpu(table->entries[i].usVddc2);
1394                        cac_leakage_table->entries[i].Vddc3 = le16_to_cpu(table->entries[i].usVddc3);
1395                } else {
1396                        cac_leakage_table->entries[i].Vddc    = le16_to_cpu(table->entries[i].usVddc);
1397                        cac_leakage_table->entries[i].Leakage = le32_to_cpu(table->entries[i].ulLeakageValue);
1398                }
1399        }
1400
1401        *ptable = cac_leakage_table;
1402
1403        return 0;
1404}
1405
1406static int get_platform_power_management_table(struct pp_hwmgr *hwmgr,
1407                        ATOM_PPLIB_PPM_Table *atom_ppm_table)
1408{
1409        struct phm_ppm_table *ptr = kzalloc(sizeof(struct phm_ppm_table), GFP_KERNEL);
1410
1411        if (NULL == ptr)
1412                return -ENOMEM;
1413
1414        ptr->ppm_design            = atom_ppm_table->ucPpmDesign;
1415        ptr->cpu_core_number        = le16_to_cpu(atom_ppm_table->usCpuCoreNumber);
1416        ptr->platform_tdp          = le32_to_cpu(atom_ppm_table->ulPlatformTDP);
1417        ptr->small_ac_platform_tdp   = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDP);
1418        ptr->platform_tdc          = le32_to_cpu(atom_ppm_table->ulPlatformTDC);
1419        ptr->small_ac_platform_tdc   = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDC);
1420        ptr->apu_tdp               = le32_to_cpu(atom_ppm_table->ulApuTDP);
1421        ptr->dgpu_tdp              = le32_to_cpu(atom_ppm_table->ulDGpuTDP);
1422        ptr->dgpu_ulv_power         = le32_to_cpu(atom_ppm_table->ulDGpuUlvPower);
1423        ptr->tj_max                = le32_to_cpu(atom_ppm_table->ulTjmax);
1424        hwmgr->dyn_state.ppm_parameter_table = ptr;
1425
1426        return 0;
1427}
1428
1429static int init_dpm2_parameters(struct pp_hwmgr *hwmgr,
1430                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1431{
1432        int result = 0;
1433
1434        if (le16_to_cpu(powerplay_table->usTableSize) >=
1435            sizeof(ATOM_PPLIB_POWERPLAYTABLE5)) {
1436                const  ATOM_PPLIB_POWERPLAYTABLE5 *ptable5 =
1437                                (const ATOM_PPLIB_POWERPLAYTABLE5 *)powerplay_table;
1438                const  ATOM_PPLIB_POWERPLAYTABLE4 *ptable4 =
1439                                (const ATOM_PPLIB_POWERPLAYTABLE4 *)
1440                                (&ptable5->basicTable4);
1441                const  ATOM_PPLIB_POWERPLAYTABLE3 *ptable3 =
1442                                (const ATOM_PPLIB_POWERPLAYTABLE3 *)
1443                                (&ptable4->basicTable3);
1444                const  ATOM_PPLIB_EXTENDEDHEADER  *extended_header;
1445                uint16_t table_offset;
1446                ATOM_PPLIB_PPM_Table *atom_ppm_table;
1447
1448                hwmgr->platform_descriptor.TDPLimit     = le32_to_cpu(ptable5->ulTDPLimit);
1449                hwmgr->platform_descriptor.nearTDPLimit = le32_to_cpu(ptable5->ulNearTDPLimit);
1450
1451                hwmgr->platform_descriptor.TDPODLimit   = le16_to_cpu(ptable5->usTDPODLimit);
1452                hwmgr->platform_descriptor.TDPAdjustment = 0;
1453
1454                hwmgr->platform_descriptor.VidAdjustment = 0;
1455                hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
1456                hwmgr->platform_descriptor.VidMinLimit     = 0;
1457                hwmgr->platform_descriptor.VidMaxLimit     = 1500000;
1458                hwmgr->platform_descriptor.VidStep         = 6250;
1459
1460                hwmgr->platform_descriptor.nearTDPLimitAdjusted = le32_to_cpu(ptable5->ulNearTDPLimit);
1461
1462                if (hwmgr->platform_descriptor.TDPODLimit != 0)
1463                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1464                                        PHM_PlatformCaps_PowerControl);
1465
1466                hwmgr->platform_descriptor.SQRampingThreshold = le32_to_cpu(ptable5->ulSQRampingThreshold);
1467
1468                hwmgr->platform_descriptor.CACLeakage = le32_to_cpu(ptable5->ulCACLeakage);
1469
1470                hwmgr->dyn_state.cac_leakage_table = NULL;
1471
1472                if (0 != ptable5->usCACLeakageTableOffset) {
1473                        const ATOM_PPLIB_CAC_Leakage_Table *pCAC_leakage_table =
1474                                (ATOM_PPLIB_CAC_Leakage_Table *)(((unsigned long)ptable5) +
1475                                le16_to_cpu(ptable5->usCACLeakageTableOffset));
1476                        result = get_cac_leakage_table(hwmgr,
1477                                &hwmgr->dyn_state.cac_leakage_table, pCAC_leakage_table);
1478                }
1479
1480                hwmgr->platform_descriptor.LoadLineSlope = le16_to_cpu(ptable5->usLoadLineSlope);
1481
1482                hwmgr->dyn_state.ppm_parameter_table = NULL;
1483
1484                if (0 != ptable3->usExtendendedHeaderOffset) {
1485                        extended_header = (const ATOM_PPLIB_EXTENDEDHEADER *)
1486                                        (((unsigned long)powerplay_table) +
1487                                        le16_to_cpu(ptable3->usExtendendedHeaderOffset));
1488                        if ((extended_header->usPPMTableOffset > 0) &&
1489                                le16_to_cpu(extended_header->usSize) >=
1490                                    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) {
1491                                table_offset = le16_to_cpu(extended_header->usPPMTableOffset);
1492                                atom_ppm_table = (ATOM_PPLIB_PPM_Table *)
1493                                        (((unsigned long)powerplay_table) + table_offset);
1494                                if (0 == get_platform_power_management_table(hwmgr, atom_ppm_table))
1495                                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1496                                                PHM_PlatformCaps_EnablePlatformPowerManagement);
1497                        }
1498                }
1499        }
1500        return result;
1501}
1502
1503static int init_phase_shedding_table(struct pp_hwmgr *hwmgr,
1504                const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1505{
1506        if (le16_to_cpu(powerplay_table->usTableSize) >=
1507            sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
1508                const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
1509                                (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
1510
1511                if (0 != powerplay_table4->usVddcPhaseShedLimitsTableOffset) {
1512                        const ATOM_PPLIB_PhaseSheddingLimits_Table *ptable =
1513                                (ATOM_PPLIB_PhaseSheddingLimits_Table *)
1514                                (((unsigned long)powerplay_table4) +
1515                                le16_to_cpu(powerplay_table4->usVddcPhaseShedLimitsTableOffset));
1516                        struct phm_phase_shedding_limits_table *table;
1517                        unsigned long size, i;
1518
1519
1520                        size = sizeof(unsigned long) +
1521                                (sizeof(struct phm_phase_shedding_limits_table) *
1522                                ptable->ucNumEntries);
1523
1524                        table = kzalloc(size, GFP_KERNEL);
1525
1526                        if (table == NULL)
1527                                return -ENOMEM;
1528
1529                        table->count = (unsigned long)ptable->ucNumEntries;
1530
1531                        for (i = 0; i < table->count; i++) {
1532                                table->entries[i].Voltage = (unsigned long)le16_to_cpu(ptable->entries[i].usVoltage);
1533                                table->entries[i].Sclk    = ((unsigned long)ptable->entries[i].ucSclkHigh << 16)
1534                                                        | le16_to_cpu(ptable->entries[i].usSclkLow);
1535                                table->entries[i].Mclk    = ((unsigned long)ptable->entries[i].ucMclkHigh << 16)
1536                                                        | le16_to_cpu(ptable->entries[i].usMclkLow);
1537                        }
1538                        hwmgr->dyn_state.vddc_phase_shed_limits_table = table;
1539                }
1540        }
1541
1542        return 0;
1543}
1544
1545static int get_number_of_vce_state_table_entries(
1546                                                  struct pp_hwmgr *hwmgr)
1547{
1548        const ATOM_PPLIB_POWERPLAYTABLE *table =
1549                                             get_powerplay_table(hwmgr);
1550        const ATOM_PPLIB_VCE_State_Table *vce_table =
1551                                    get_vce_state_table(hwmgr, table);
1552
1553        if (vce_table)
1554                return vce_table->numEntries;
1555
1556        return 0;
1557}
1558
1559static int get_vce_state_table_entry(struct pp_hwmgr *hwmgr,
1560                                                        unsigned long i,
1561                                                        struct amd_vce_state *vce_state,
1562                                                        void **clock_info,
1563                                                        unsigned long *flag)
1564{
1565        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
1566
1567        const ATOM_PPLIB_VCE_State_Table *vce_state_table = get_vce_state_table(hwmgr, powerplay_table);
1568
1569        unsigned short vce_clock_info_array_offset = get_vce_clock_info_array_offset(hwmgr, powerplay_table);
1570
1571        const VCEClockInfoArray *vce_clock_info_array = (const VCEClockInfoArray *)(((unsigned long) powerplay_table) + vce_clock_info_array_offset);
1572
1573        const ClockInfoArray *clock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
1574                                                                le16_to_cpu(powerplay_table->usClockInfoArrayOffset));
1575
1576        const ATOM_PPLIB_VCE_State_Record *record = &vce_state_table->entries[i];
1577
1578        const VCEClockInfo *vce_clock_info = &vce_clock_info_array->entries[record->ucVCEClockInfoIndex];
1579
1580        unsigned long clockInfoIndex = record->ucClockInfoIndex & 0x3F;
1581
1582        *flag = (record->ucClockInfoIndex >> NUM_BITS_CLOCK_INFO_ARRAY_INDEX);
1583
1584        vce_state->evclk = ((uint32_t)vce_clock_info->ucEVClkHigh << 16) | le16_to_cpu(vce_clock_info->usEVClkLow);
1585        vce_state->ecclk = ((uint32_t)vce_clock_info->ucECClkHigh << 16) | le16_to_cpu(vce_clock_info->usECClkLow);
1586
1587        *clock_info = (void *)((unsigned long)(clock_arrays->clockInfo) + (clockInfoIndex * clock_arrays->ucEntrySize));
1588
1589        return 0;
1590}
1591
1592
1593static int pp_tables_initialize(struct pp_hwmgr *hwmgr)
1594{
1595        int result;
1596        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table;
1597
1598        if (hwmgr->chip_id == CHIP_RAVEN)
1599                return 0;
1600
1601        hwmgr->need_pp_table_upload = true;
1602
1603        powerplay_table = get_powerplay_table(hwmgr);
1604
1605        result = init_powerplay_tables(hwmgr, powerplay_table);
1606
1607        PP_ASSERT_WITH_CODE((result == 0),
1608                            "init_powerplay_tables failed", return result);
1609
1610        result = set_platform_caps(hwmgr,
1611                                le32_to_cpu(powerplay_table->ulPlatformCaps));
1612
1613        PP_ASSERT_WITH_CODE((result == 0),
1614                            "set_platform_caps failed", return result);
1615
1616        result = init_thermal_controller(hwmgr, powerplay_table);
1617
1618        PP_ASSERT_WITH_CODE((result == 0),
1619                            "init_thermal_controller failed", return result);
1620
1621        result = init_overdrive_limits(hwmgr, powerplay_table);
1622
1623        PP_ASSERT_WITH_CODE((result == 0),
1624                            "init_overdrive_limits failed", return result);
1625
1626        result = init_clock_voltage_dependency(hwmgr,
1627                                               powerplay_table);
1628
1629        PP_ASSERT_WITH_CODE((result == 0),
1630                            "init_clock_voltage_dependency failed", return result);
1631
1632        result = init_dpm2_parameters(hwmgr, powerplay_table);
1633
1634        PP_ASSERT_WITH_CODE((result == 0),
1635                            "init_dpm2_parameters failed", return result);
1636
1637        result = init_phase_shedding_table(hwmgr, powerplay_table);
1638
1639        PP_ASSERT_WITH_CODE((result == 0),
1640                            "init_phase_shedding_table failed", return result);
1641
1642        return result;
1643}
1644
1645static int pp_tables_uninitialize(struct pp_hwmgr *hwmgr)
1646{
1647        if (hwmgr->chip_id == CHIP_RAVEN)
1648                return 0;
1649
1650        kfree(hwmgr->dyn_state.vddc_dependency_on_sclk);
1651        hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
1652
1653        kfree(hwmgr->dyn_state.vddci_dependency_on_mclk);
1654        hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
1655
1656        kfree(hwmgr->dyn_state.vddc_dependency_on_mclk);
1657        hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
1658
1659        kfree(hwmgr->dyn_state.mvdd_dependency_on_mclk);
1660        hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
1661
1662        kfree(hwmgr->dyn_state.valid_mclk_values);
1663        hwmgr->dyn_state.valid_mclk_values = NULL;
1664
1665        kfree(hwmgr->dyn_state.valid_sclk_values);
1666        hwmgr->dyn_state.valid_sclk_values = NULL;
1667
1668        kfree(hwmgr->dyn_state.cac_leakage_table);
1669        hwmgr->dyn_state.cac_leakage_table = NULL;
1670
1671        kfree(hwmgr->dyn_state.vddc_phase_shed_limits_table);
1672        hwmgr->dyn_state.vddc_phase_shed_limits_table = NULL;
1673
1674        kfree(hwmgr->dyn_state.vce_clock_voltage_dependency_table);
1675        hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
1676
1677        kfree(hwmgr->dyn_state.uvd_clock_voltage_dependency_table);
1678        hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
1679
1680        kfree(hwmgr->dyn_state.samu_clock_voltage_dependency_table);
1681        hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
1682
1683        kfree(hwmgr->dyn_state.acp_clock_voltage_dependency_table);
1684        hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
1685
1686        kfree(hwmgr->dyn_state.cac_dtp_table);
1687        hwmgr->dyn_state.cac_dtp_table = NULL;
1688
1689        kfree(hwmgr->dyn_state.ppm_parameter_table);
1690        hwmgr->dyn_state.ppm_parameter_table = NULL;
1691
1692        kfree(hwmgr->dyn_state.vdd_gfx_dependency_on_sclk);
1693        hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
1694
1695        return 0;
1696}
1697
1698const struct pp_table_func pptable_funcs = {
1699        .pptable_init = pp_tables_initialize,
1700        .pptable_fini = pp_tables_uninitialize,
1701        .pptable_get_number_of_vce_state_table_entries =
1702                                get_number_of_vce_state_table_entries,
1703        .pptable_get_vce_state_table_entry =
1704                                                get_vce_state_table_entry,
1705};
1706
1707