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 = pnon_clock_info->ulVCLK;
 761                ps->uvd_clocks.DCLK = 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 = cgs_atom_get_data_table(hwmgr->device,
 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 + powerplay_table->usStateArrayOffset +
 941                                entry_index * powerplay_table->ucStateEntrySize);
 942
 943                pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)powerplay_table +
 944                                                le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset) +
 945                                                pstate_entry->ucNonClockStateIndex *
 946                                                powerplay_table->ucNonClockSize);
 947
 948                result = init_non_clock_fields(hwmgr, ps,
 949                                                        powerplay_table->ucNonClockSize,
 950                                                        pnon_clock_info);
 951
 952                for (i = 0; i < powerplay_table->ucStateEntrySize-1; i++) {
 953                        const void *pclock_info = (const void *)((unsigned long)powerplay_table +
 954                                                le16_to_cpu(powerplay_table->usClockInfoArrayOffset) +
 955                                                pstate_entry->ucClockStateIndices[i] *
 956                                                powerplay_table->ucClockInfoSize);
 957
 958                        int res = func(hwmgr, &ps->hardware, i, pclock_info);
 959
 960                        if ((0 == result) && (0 != res))
 961                                        result = res;
 962                }
 963        }
 964
 965        if ((0 == result) && (0 != (ps->classification.flags & PP_StateClassificationFlag_Boot))) {
 966                if (hwmgr->chip_family < AMDGPU_FAMILY_RV)
 967                        result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(ps->hardware));
 968        }
 969
 970        return result;
 971}
 972
 973static int init_powerplay_tables(
 974                        struct pp_hwmgr *hwmgr,
 975                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table
 976)
 977{
 978        return 0;
 979}
 980
 981
 982static int init_thermal_controller(
 983                        struct pp_hwmgr *hwmgr,
 984                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 985{
 986        return 0;
 987}
 988
 989static int init_overdrive_limits_V1_4(struct pp_hwmgr *hwmgr,
 990                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
 991                        const ATOM_FIRMWARE_INFO_V1_4 *fw_info)
 992{
 993        hwmgr->platform_descriptor.overdriveLimit.engineClock =
 994                                le32_to_cpu(fw_info->ulASICMaxEngineClock);
 995
 996        hwmgr->platform_descriptor.overdriveLimit.memoryClock =
 997                                le32_to_cpu(fw_info->ulASICMaxMemoryClock);
 998
 999        hwmgr->platform_descriptor.maxOverdriveVDDC =
1000                le32_to_cpu(fw_info->ul3DAccelerationEngineClock) & 0x7FF;
1001
1002        hwmgr->platform_descriptor.minOverdriveVDDC =
1003                           le16_to_cpu(fw_info->usBootUpVDDCVoltage);
1004
1005        hwmgr->platform_descriptor.maxOverdriveVDDC =
1006                           le16_to_cpu(fw_info->usBootUpVDDCVoltage);
1007
1008        hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1009        return 0;
1010}
1011
1012static int init_overdrive_limits_V2_1(struct pp_hwmgr *hwmgr,
1013                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
1014                        const ATOM_FIRMWARE_INFO_V2_1 *fw_info)
1015{
1016        const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3;
1017        const ATOM_PPLIB_EXTENDEDHEADER *header;
1018
1019        if (le16_to_cpu(powerplay_table->usTableSize) <
1020            sizeof(ATOM_PPLIB_POWERPLAYTABLE3))
1021                return 0;
1022
1023        powerplay_table3 = (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
1024
1025        if (0 == powerplay_table3->usExtendendedHeaderOffset)
1026                return 0;
1027
1028        header = (ATOM_PPLIB_EXTENDEDHEADER *)(((unsigned long) powerplay_table) +
1029                        le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
1030
1031        hwmgr->platform_descriptor.overdriveLimit.engineClock = le32_to_cpu(header->ulMaxEngineClock);
1032        hwmgr->platform_descriptor.overdriveLimit.memoryClock = le32_to_cpu(header->ulMaxMemoryClock);
1033
1034
1035        hwmgr->platform_descriptor.minOverdriveVDDC = 0;
1036        hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
1037        hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1038
1039        return 0;
1040}
1041
1042static int init_overdrive_limits(struct pp_hwmgr *hwmgr,
1043                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1044{
1045        int result = 0;
1046        uint8_t frev, crev;
1047        uint16_t size;
1048
1049        const ATOM_COMMON_TABLE_HEADER *fw_info = NULL;
1050
1051        hwmgr->platform_descriptor.overdriveLimit.engineClock = 0;
1052        hwmgr->platform_descriptor.overdriveLimit.memoryClock = 0;
1053        hwmgr->platform_descriptor.minOverdriveVDDC = 0;
1054        hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
1055        hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1056
1057        if (hwmgr->chip_id == CHIP_RAVEN)
1058                return 0;
1059
1060        /* We assume here that fw_info is unchanged if this call fails.*/
1061        fw_info = cgs_atom_get_data_table(hwmgr->device,
1062                         GetIndexIntoMasterTable(DATA, FirmwareInfo),
1063                         &size, &frev, &crev);
1064
1065        if ((fw_info->ucTableFormatRevision == 1)
1066                && (fw_info->usStructureSize >= sizeof(ATOM_FIRMWARE_INFO_V1_4)))
1067                result = init_overdrive_limits_V1_4(hwmgr,
1068                                powerplay_table,
1069                                (const ATOM_FIRMWARE_INFO_V1_4 *)fw_info);
1070
1071        else if ((fw_info->ucTableFormatRevision == 2)
1072                && (fw_info->usStructureSize >= sizeof(ATOM_FIRMWARE_INFO_V2_1)))
1073                result = init_overdrive_limits_V2_1(hwmgr,
1074                                powerplay_table,
1075                                (const ATOM_FIRMWARE_INFO_V2_1 *)fw_info);
1076
1077        if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0
1078                && hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) {
1079                hwmgr->od_enabled = false;
1080                pr_debug("OverDrive feature not support by VBIOS\n");
1081        }
1082
1083        return result;
1084}
1085
1086static int get_uvd_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1087                struct phm_uvd_clock_voltage_dependency_table **ptable,
1088                const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *table,
1089                const UVDClockInfoArray *array)
1090{
1091        unsigned long table_size, i;
1092        struct phm_uvd_clock_voltage_dependency_table *uvd_table;
1093
1094        table_size = sizeof(unsigned long) +
1095                 sizeof(struct phm_uvd_clock_voltage_dependency_table) *
1096                 table->numEntries;
1097
1098        uvd_table = kzalloc(table_size, GFP_KERNEL);
1099        if (NULL == uvd_table)
1100                return -ENOMEM;
1101
1102        uvd_table->count = table->numEntries;
1103
1104        for (i = 0; i < table->numEntries; i++) {
1105                const UVDClockInfo *entry =
1106                        &array->entries[table->entries[i].ucUVDClockInfoIndex];
1107                uvd_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1108                uvd_table->entries[i].vclk = ((unsigned long)entry->ucVClkHigh << 16)
1109                                         | le16_to_cpu(entry->usVClkLow);
1110                uvd_table->entries[i].dclk = ((unsigned long)entry->ucDClkHigh << 16)
1111                                         | le16_to_cpu(entry->usDClkLow);
1112        }
1113
1114        *ptable = uvd_table;
1115
1116        return 0;
1117}
1118
1119static int get_vce_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1120                struct phm_vce_clock_voltage_dependency_table **ptable,
1121                const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table,
1122                const VCEClockInfoArray    *array)
1123{
1124        unsigned long table_size, i;
1125        struct phm_vce_clock_voltage_dependency_table *vce_table = NULL;
1126
1127        table_size = sizeof(unsigned long) +
1128                        sizeof(struct phm_vce_clock_voltage_dependency_table)
1129                        * table->numEntries;
1130
1131        vce_table = kzalloc(table_size, GFP_KERNEL);
1132        if (NULL == vce_table)
1133                return -ENOMEM;
1134
1135        vce_table->count = table->numEntries;
1136        for (i = 0; i < table->numEntries; i++) {
1137                const VCEClockInfo *entry = &array->entries[table->entries[i].ucVCEClockInfoIndex];
1138
1139                vce_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1140                vce_table->entries[i].evclk = ((unsigned long)entry->ucEVClkHigh << 16)
1141                                        | le16_to_cpu(entry->usEVClkLow);
1142                vce_table->entries[i].ecclk = ((unsigned long)entry->ucECClkHigh << 16)
1143                                        | le16_to_cpu(entry->usECClkLow);
1144        }
1145
1146        *ptable = vce_table;
1147
1148        return 0;
1149}
1150
1151static int get_samu_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1152                 struct phm_samu_clock_voltage_dependency_table **ptable,
1153                 const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *table)
1154{
1155        unsigned long table_size, i;
1156        struct phm_samu_clock_voltage_dependency_table *samu_table;
1157
1158        table_size = sizeof(unsigned long) +
1159                sizeof(struct phm_samu_clock_voltage_dependency_table) *
1160                table->numEntries;
1161
1162        samu_table = kzalloc(table_size, GFP_KERNEL);
1163        if (NULL == samu_table)
1164                return -ENOMEM;
1165
1166        samu_table->count = table->numEntries;
1167
1168        for (i = 0; i < table->numEntries; i++) {
1169                samu_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1170                samu_table->entries[i].samclk = ((unsigned long)table->entries[i].ucSAMClockHigh << 16)
1171                                         | le16_to_cpu(table->entries[i].usSAMClockLow);
1172        }
1173
1174        *ptable = samu_table;
1175
1176        return 0;
1177}
1178
1179static int get_acp_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1180                struct phm_acp_clock_voltage_dependency_table **ptable,
1181                const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *table)
1182{
1183        unsigned table_size, i;
1184        struct phm_acp_clock_voltage_dependency_table *acp_table;
1185
1186        table_size = sizeof(unsigned long) +
1187                sizeof(struct phm_acp_clock_voltage_dependency_table) *
1188                table->numEntries;
1189
1190        acp_table = kzalloc(table_size, GFP_KERNEL);
1191        if (NULL == acp_table)
1192                return -ENOMEM;
1193
1194        acp_table->count = (unsigned long)table->numEntries;
1195
1196        for (i = 0; i < table->numEntries; i++) {
1197                acp_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1198                acp_table->entries[i].acpclk = ((unsigned long)table->entries[i].ucACPClockHigh << 16)
1199                                         | le16_to_cpu(table->entries[i].usACPClockLow);
1200        }
1201
1202        *ptable = acp_table;
1203
1204        return 0;
1205}
1206
1207static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr,
1208                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1209{
1210        ATOM_PPLIB_Clock_Voltage_Dependency_Table *table;
1211        ATOM_PPLIB_Clock_Voltage_Limit_Table *limit_table;
1212        int result = 0;
1213
1214        uint16_t vce_clock_info_array_offset;
1215        uint16_t uvd_clock_info_array_offset;
1216        uint16_t table_offset;
1217
1218        hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
1219        hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
1220        hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
1221        hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
1222        hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
1223        hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
1224        hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
1225        hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
1226        hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
1227        hwmgr->dyn_state.ppm_parameter_table = NULL;
1228        hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
1229
1230        vce_clock_info_array_offset = get_vce_clock_info_array_offset(
1231                                                hwmgr, powerplay_table);
1232        table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr,
1233                                                powerplay_table);
1234        if (vce_clock_info_array_offset > 0 && table_offset > 0) {
1235                const VCEClockInfoArray *array = (const VCEClockInfoArray *)
1236                                (((unsigned long) powerplay_table) +
1237                                vce_clock_info_array_offset);
1238                const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table =
1239                                (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)
1240                                (((unsigned long) powerplay_table) + table_offset);
1241                result = get_vce_clock_voltage_limit_table(hwmgr,
1242                                &hwmgr->dyn_state.vce_clock_voltage_dependency_table,
1243                                table, array);
1244        }
1245
1246        uvd_clock_info_array_offset = get_uvd_clock_info_array_offset(hwmgr, powerplay_table);
1247        table_offset = get_uvd_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
1248
1249        if (uvd_clock_info_array_offset > 0 && table_offset > 0) {
1250                const UVDClockInfoArray *array = (const UVDClockInfoArray *)
1251                                (((unsigned long) powerplay_table) +
1252                                uvd_clock_info_array_offset);
1253                const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *ptable =
1254                                (const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *)
1255                                (((unsigned long) powerplay_table) + table_offset);
1256                result = get_uvd_clock_voltage_limit_table(hwmgr,
1257                                &hwmgr->dyn_state.uvd_clock_voltage_dependency_table, ptable, array);
1258        }
1259
1260        table_offset = get_samu_clock_voltage_limit_table_offset(hwmgr,
1261                                                            powerplay_table);
1262
1263        if (table_offset > 0) {
1264                const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *ptable =
1265                                (const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *)
1266                                (((unsigned long) powerplay_table) + table_offset);
1267                result = get_samu_clock_voltage_limit_table(hwmgr,
1268                                &hwmgr->dyn_state.samu_clock_voltage_dependency_table, ptable);
1269        }
1270
1271        table_offset = get_acp_clock_voltage_limit_table_offset(hwmgr,
1272                                                             powerplay_table);
1273
1274        if (table_offset > 0) {
1275                const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *ptable =
1276                                (const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *)
1277                                (((unsigned long) powerplay_table) + table_offset);
1278                result = get_acp_clock_voltage_limit_table(hwmgr,
1279                                &hwmgr->dyn_state.acp_clock_voltage_dependency_table, ptable);
1280        }
1281
1282        table_offset = get_cacp_tdp_table_offset(hwmgr, powerplay_table);
1283        if (table_offset > 0) {
1284                UCHAR rev_id = *(UCHAR *)(((unsigned long)powerplay_table) + table_offset);
1285
1286                if (rev_id > 0) {
1287                        const ATOM_PPLIB_POWERTUNE_Table_V1 *tune_table =
1288                                (const ATOM_PPLIB_POWERTUNE_Table_V1 *)
1289                                (((unsigned long) powerplay_table) + table_offset);
1290                        result = get_cac_tdp_table(hwmgr, &hwmgr->dyn_state.cac_dtp_table,
1291                                &tune_table->power_tune_table,
1292                                le16_to_cpu(tune_table->usMaximumPowerDeliveryLimit));
1293                        hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
1294                                le16_to_cpu(tune_table->usTjMax);
1295                } else {
1296                        const ATOM_PPLIB_POWERTUNE_Table *tune_table =
1297                                (const ATOM_PPLIB_POWERTUNE_Table *)
1298                                (((unsigned long) powerplay_table) + table_offset);
1299                        result = get_cac_tdp_table(hwmgr,
1300                                &hwmgr->dyn_state.cac_dtp_table,
1301                                &tune_table->power_tune_table, 255);
1302                }
1303        }
1304
1305        if (le16_to_cpu(powerplay_table->usTableSize) >=
1306                sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
1307                const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
1308                                (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
1309                if (0 != powerplay_table4->usVddcDependencyOnSCLKOffset) {
1310                        table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1311                                (((unsigned long) powerplay_table4) +
1312                                powerplay_table4->usVddcDependencyOnSCLKOffset);
1313                        result = get_clock_voltage_dependency_table(hwmgr,
1314                                &hwmgr->dyn_state.vddc_dependency_on_sclk, table);
1315                }
1316
1317                if (result == 0 && (0 != powerplay_table4->usVddciDependencyOnMCLKOffset)) {
1318                        table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1319                                (((unsigned long) powerplay_table4) +
1320                                powerplay_table4->usVddciDependencyOnMCLKOffset);
1321                        result = get_clock_voltage_dependency_table(hwmgr,
1322                                &hwmgr->dyn_state.vddci_dependency_on_mclk, table);
1323                }
1324
1325                if (result == 0 && (0 != powerplay_table4->usVddcDependencyOnMCLKOffset)) {
1326                        table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1327                                (((unsigned long) powerplay_table4) +
1328                                powerplay_table4->usVddcDependencyOnMCLKOffset);
1329                        result = get_clock_voltage_dependency_table(hwmgr,
1330                                &hwmgr->dyn_state.vddc_dependency_on_mclk, table);
1331                }
1332
1333                if (result == 0 && (0 != powerplay_table4->usMaxClockVoltageOnDCOffset)) {
1334                        limit_table = (ATOM_PPLIB_Clock_Voltage_Limit_Table *)
1335                                (((unsigned long) powerplay_table4) +
1336                                powerplay_table4->usMaxClockVoltageOnDCOffset);
1337                        result = get_clock_voltage_limit(hwmgr,
1338                                &hwmgr->dyn_state.max_clock_voltage_on_dc, limit_table);
1339                }
1340
1341                if (result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_mclk) &&
1342                        (0 != hwmgr->dyn_state.vddc_dependency_on_mclk->count))
1343                        result = get_valid_clk(hwmgr, &hwmgr->dyn_state.valid_mclk_values,
1344                                        hwmgr->dyn_state.vddc_dependency_on_mclk);
1345
1346                if(result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_sclk) &&
1347                        (0 != hwmgr->dyn_state.vddc_dependency_on_sclk->count))
1348                        result = get_valid_clk(hwmgr,
1349                                &hwmgr->dyn_state.valid_sclk_values,
1350                                hwmgr->dyn_state.vddc_dependency_on_sclk);
1351
1352                if (result == 0 && (0 != powerplay_table4->usMvddDependencyOnMCLKOffset)) {
1353                        table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1354                                (((unsigned long) powerplay_table4) +
1355                                powerplay_table4->usMvddDependencyOnMCLKOffset);
1356                        result = get_clock_voltage_dependency_table(hwmgr,
1357                                &hwmgr->dyn_state.mvdd_dependency_on_mclk, table);
1358                }
1359        }
1360
1361        table_offset = get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(hwmgr,
1362                                                                powerplay_table);
1363
1364        if (table_offset > 0) {
1365                table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1366                        (((unsigned long) powerplay_table) + table_offset);
1367                result = get_clock_voltage_dependency_table(hwmgr,
1368                        &hwmgr->dyn_state.vdd_gfx_dependency_on_sclk, table);
1369        }
1370
1371        return result;
1372}
1373
1374static int get_cac_leakage_table(struct pp_hwmgr *hwmgr,
1375                                 struct phm_cac_leakage_table **ptable,
1376                                const ATOM_PPLIB_CAC_Leakage_Table *table)
1377{
1378        struct phm_cac_leakage_table  *cac_leakage_table;
1379        unsigned long            table_size, i;
1380
1381        if (hwmgr == NULL || table == NULL || ptable == NULL)
1382                return -EINVAL;
1383
1384        table_size = sizeof(ULONG) +
1385                (sizeof(struct phm_cac_leakage_table) * table->ucNumEntries);
1386
1387        cac_leakage_table = kzalloc(table_size, GFP_KERNEL);
1388
1389        if (cac_leakage_table == NULL)
1390                return -ENOMEM;
1391
1392        cac_leakage_table->count = (ULONG)table->ucNumEntries;
1393
1394        for (i = 0; i < cac_leakage_table->count; i++) {
1395                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1396                                PHM_PlatformCaps_EVV)) {
1397                        cac_leakage_table->entries[i].Vddc1 = le16_to_cpu(table->entries[i].usVddc1);
1398                        cac_leakage_table->entries[i].Vddc2 = le16_to_cpu(table->entries[i].usVddc2);
1399                        cac_leakage_table->entries[i].Vddc3 = le16_to_cpu(table->entries[i].usVddc3);
1400                } else {
1401                        cac_leakage_table->entries[i].Vddc    = le16_to_cpu(table->entries[i].usVddc);
1402                        cac_leakage_table->entries[i].Leakage = le32_to_cpu(table->entries[i].ulLeakageValue);
1403                }
1404        }
1405
1406        *ptable = cac_leakage_table;
1407
1408        return 0;
1409}
1410
1411static int get_platform_power_management_table(struct pp_hwmgr *hwmgr,
1412                        ATOM_PPLIB_PPM_Table *atom_ppm_table)
1413{
1414        struct phm_ppm_table *ptr = kzalloc(sizeof(struct phm_ppm_table), GFP_KERNEL);
1415
1416        if (NULL == ptr)
1417                return -ENOMEM;
1418
1419        ptr->ppm_design            = atom_ppm_table->ucPpmDesign;
1420        ptr->cpu_core_number        = le16_to_cpu(atom_ppm_table->usCpuCoreNumber);
1421        ptr->platform_tdp          = le32_to_cpu(atom_ppm_table->ulPlatformTDP);
1422        ptr->small_ac_platform_tdp   = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDP);
1423        ptr->platform_tdc          = le32_to_cpu(atom_ppm_table->ulPlatformTDC);
1424        ptr->small_ac_platform_tdc   = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDC);
1425        ptr->apu_tdp               = le32_to_cpu(atom_ppm_table->ulApuTDP);
1426        ptr->dgpu_tdp              = le32_to_cpu(atom_ppm_table->ulDGpuTDP);
1427        ptr->dgpu_ulv_power         = le32_to_cpu(atom_ppm_table->ulDGpuUlvPower);
1428        ptr->tj_max                = le32_to_cpu(atom_ppm_table->ulTjmax);
1429        hwmgr->dyn_state.ppm_parameter_table = ptr;
1430
1431        return 0;
1432}
1433
1434static int init_dpm2_parameters(struct pp_hwmgr *hwmgr,
1435                        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1436{
1437        int result = 0;
1438
1439        if (le16_to_cpu(powerplay_table->usTableSize) >=
1440            sizeof(ATOM_PPLIB_POWERPLAYTABLE5)) {
1441                const  ATOM_PPLIB_POWERPLAYTABLE5 *ptable5 =
1442                                (const ATOM_PPLIB_POWERPLAYTABLE5 *)powerplay_table;
1443                const  ATOM_PPLIB_POWERPLAYTABLE4 *ptable4 =
1444                                (const ATOM_PPLIB_POWERPLAYTABLE4 *)
1445                                (&ptable5->basicTable4);
1446                const  ATOM_PPLIB_POWERPLAYTABLE3 *ptable3 =
1447                                (const ATOM_PPLIB_POWERPLAYTABLE3 *)
1448                                (&ptable4->basicTable3);
1449                const  ATOM_PPLIB_EXTENDEDHEADER  *extended_header;
1450                uint16_t table_offset;
1451                ATOM_PPLIB_PPM_Table *atom_ppm_table;
1452
1453                hwmgr->platform_descriptor.TDPLimit     = le32_to_cpu(ptable5->ulTDPLimit);
1454                hwmgr->platform_descriptor.nearTDPLimit = le32_to_cpu(ptable5->ulNearTDPLimit);
1455
1456                hwmgr->platform_descriptor.TDPODLimit   = le16_to_cpu(ptable5->usTDPODLimit);
1457                hwmgr->platform_descriptor.TDPAdjustment = 0;
1458
1459                hwmgr->platform_descriptor.VidAdjustment = 0;
1460                hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
1461                hwmgr->platform_descriptor.VidMinLimit     = 0;
1462                hwmgr->platform_descriptor.VidMaxLimit     = 1500000;
1463                hwmgr->platform_descriptor.VidStep         = 6250;
1464
1465                hwmgr->platform_descriptor.nearTDPLimitAdjusted = le32_to_cpu(ptable5->ulNearTDPLimit);
1466
1467                if (hwmgr->platform_descriptor.TDPODLimit != 0)
1468                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1469                                        PHM_PlatformCaps_PowerControl);
1470
1471                hwmgr->platform_descriptor.SQRampingThreshold = le32_to_cpu(ptable5->ulSQRampingThreshold);
1472
1473                hwmgr->platform_descriptor.CACLeakage = le32_to_cpu(ptable5->ulCACLeakage);
1474
1475                hwmgr->dyn_state.cac_leakage_table = NULL;
1476
1477                if (0 != ptable5->usCACLeakageTableOffset) {
1478                        const ATOM_PPLIB_CAC_Leakage_Table *pCAC_leakage_table =
1479                                (ATOM_PPLIB_CAC_Leakage_Table *)(((unsigned long)ptable5) +
1480                                le16_to_cpu(ptable5->usCACLeakageTableOffset));
1481                        result = get_cac_leakage_table(hwmgr,
1482                                &hwmgr->dyn_state.cac_leakage_table, pCAC_leakage_table);
1483                }
1484
1485                hwmgr->platform_descriptor.LoadLineSlope = le16_to_cpu(ptable5->usLoadLineSlope);
1486
1487                hwmgr->dyn_state.ppm_parameter_table = NULL;
1488
1489                if (0 != ptable3->usExtendendedHeaderOffset) {
1490                        extended_header = (const ATOM_PPLIB_EXTENDEDHEADER *)
1491                                        (((unsigned long)powerplay_table) +
1492                                        le16_to_cpu(ptable3->usExtendendedHeaderOffset));
1493                        if ((extended_header->usPPMTableOffset > 0) &&
1494                                le16_to_cpu(extended_header->usSize) >=
1495                                    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) {
1496                                table_offset = le16_to_cpu(extended_header->usPPMTableOffset);
1497                                atom_ppm_table = (ATOM_PPLIB_PPM_Table *)
1498                                        (((unsigned long)powerplay_table) + table_offset);
1499                                if (0 == get_platform_power_management_table(hwmgr, atom_ppm_table))
1500                                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1501                                                PHM_PlatformCaps_EnablePlatformPowerManagement);
1502                        }
1503                }
1504        }
1505        return result;
1506}
1507
1508static int init_phase_shedding_table(struct pp_hwmgr *hwmgr,
1509                const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1510{
1511        if (le16_to_cpu(powerplay_table->usTableSize) >=
1512            sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
1513                const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
1514                                (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
1515
1516                if (0 != powerplay_table4->usVddcPhaseShedLimitsTableOffset) {
1517                        const ATOM_PPLIB_PhaseSheddingLimits_Table *ptable =
1518                                (ATOM_PPLIB_PhaseSheddingLimits_Table *)
1519                                (((unsigned long)powerplay_table4) +
1520                                le16_to_cpu(powerplay_table4->usVddcPhaseShedLimitsTableOffset));
1521                        struct phm_phase_shedding_limits_table *table;
1522                        unsigned long size, i;
1523
1524
1525                        size = sizeof(unsigned long) +
1526                                (sizeof(struct phm_phase_shedding_limits_table) *
1527                                ptable->ucNumEntries);
1528
1529                        table = kzalloc(size, GFP_KERNEL);
1530
1531                        if (table == NULL)
1532                                return -ENOMEM;
1533
1534                        table->count = (unsigned long)ptable->ucNumEntries;
1535
1536                        for (i = 0; i < table->count; i++) {
1537                                table->entries[i].Voltage = (unsigned long)le16_to_cpu(ptable->entries[i].usVoltage);
1538                                table->entries[i].Sclk    = ((unsigned long)ptable->entries[i].ucSclkHigh << 16)
1539                                                        | le16_to_cpu(ptable->entries[i].usSclkLow);
1540                                table->entries[i].Mclk    = ((unsigned long)ptable->entries[i].ucMclkHigh << 16)
1541                                                        | le16_to_cpu(ptable->entries[i].usMclkLow);
1542                        }
1543                        hwmgr->dyn_state.vddc_phase_shed_limits_table = table;
1544                }
1545        }
1546
1547        return 0;
1548}
1549
1550static int get_number_of_vce_state_table_entries(
1551                                                  struct pp_hwmgr *hwmgr)
1552{
1553        const ATOM_PPLIB_POWERPLAYTABLE *table =
1554                                             get_powerplay_table(hwmgr);
1555        const ATOM_PPLIB_VCE_State_Table *vce_table =
1556                                    get_vce_state_table(hwmgr, table);
1557
1558        if (vce_table)
1559                return vce_table->numEntries;
1560
1561        return 0;
1562}
1563
1564static int get_vce_state_table_entry(struct pp_hwmgr *hwmgr,
1565                                                        unsigned long i,
1566                                                        struct amd_vce_state *vce_state,
1567                                                        void **clock_info,
1568                                                        unsigned long *flag)
1569{
1570        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
1571
1572        const ATOM_PPLIB_VCE_State_Table *vce_state_table = get_vce_state_table(hwmgr, powerplay_table);
1573
1574        unsigned short vce_clock_info_array_offset = get_vce_clock_info_array_offset(hwmgr, powerplay_table);
1575
1576        const VCEClockInfoArray *vce_clock_info_array = (const VCEClockInfoArray *)(((unsigned long) powerplay_table) + vce_clock_info_array_offset);
1577
1578        const ClockInfoArray *clock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) + powerplay_table->usClockInfoArrayOffset);
1579
1580        const ATOM_PPLIB_VCE_State_Record *record = &vce_state_table->entries[i];
1581
1582        const VCEClockInfo *vce_clock_info = &vce_clock_info_array->entries[record->ucVCEClockInfoIndex];
1583
1584        unsigned long clockInfoIndex = record->ucClockInfoIndex & 0x3F;
1585
1586        *flag = (record->ucClockInfoIndex >> NUM_BITS_CLOCK_INFO_ARRAY_INDEX);
1587
1588        vce_state->evclk = ((uint32_t)vce_clock_info->ucEVClkHigh << 16) | vce_clock_info->usEVClkLow;
1589        vce_state->ecclk = ((uint32_t)vce_clock_info->ucECClkHigh << 16) | vce_clock_info->usECClkLow;
1590
1591        *clock_info = (void *)((unsigned long)(clock_arrays->clockInfo) + (clockInfoIndex * clock_arrays->ucEntrySize));
1592
1593        return 0;
1594}
1595
1596
1597static int pp_tables_initialize(struct pp_hwmgr *hwmgr)
1598{
1599        int result;
1600        const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table;
1601
1602        if (hwmgr->chip_id == CHIP_RAVEN)
1603                return 0;
1604
1605        hwmgr->need_pp_table_upload = true;
1606
1607        powerplay_table = get_powerplay_table(hwmgr);
1608
1609        result = init_powerplay_tables(hwmgr, powerplay_table);
1610
1611        PP_ASSERT_WITH_CODE((result == 0),
1612                            "init_powerplay_tables failed", return result);
1613
1614        result = set_platform_caps(hwmgr,
1615                                le32_to_cpu(powerplay_table->ulPlatformCaps));
1616
1617        PP_ASSERT_WITH_CODE((result == 0),
1618                            "set_platform_caps failed", return result);
1619
1620        result = init_thermal_controller(hwmgr, powerplay_table);
1621
1622        PP_ASSERT_WITH_CODE((result == 0),
1623                            "init_thermal_controller failed", return result);
1624
1625        result = init_overdrive_limits(hwmgr, powerplay_table);
1626
1627        PP_ASSERT_WITH_CODE((result == 0),
1628                            "init_overdrive_limits failed", return result);
1629
1630        result = init_clock_voltage_dependency(hwmgr,
1631                                               powerplay_table);
1632
1633        PP_ASSERT_WITH_CODE((result == 0),
1634                            "init_clock_voltage_dependency failed", return result);
1635
1636        result = init_dpm2_parameters(hwmgr, powerplay_table);
1637
1638        PP_ASSERT_WITH_CODE((result == 0),
1639                            "init_dpm2_parameters failed", return result);
1640
1641        result = init_phase_shedding_table(hwmgr, powerplay_table);
1642
1643        PP_ASSERT_WITH_CODE((result == 0),
1644                            "init_phase_shedding_table failed", return result);
1645
1646        return result;
1647}
1648
1649static int pp_tables_uninitialize(struct pp_hwmgr *hwmgr)
1650{
1651        if (hwmgr->chip_id == CHIP_RAVEN)
1652                return 0;
1653
1654        kfree(hwmgr->dyn_state.vddc_dependency_on_sclk);
1655        hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
1656
1657        kfree(hwmgr->dyn_state.vddci_dependency_on_mclk);
1658        hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
1659
1660        kfree(hwmgr->dyn_state.vddc_dependency_on_mclk);
1661        hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
1662
1663        kfree(hwmgr->dyn_state.mvdd_dependency_on_mclk);
1664        hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
1665
1666        kfree(hwmgr->dyn_state.valid_mclk_values);
1667        hwmgr->dyn_state.valid_mclk_values = NULL;
1668
1669        kfree(hwmgr->dyn_state.valid_sclk_values);
1670        hwmgr->dyn_state.valid_sclk_values = NULL;
1671
1672        kfree(hwmgr->dyn_state.cac_leakage_table);
1673        hwmgr->dyn_state.cac_leakage_table = NULL;
1674
1675        kfree(hwmgr->dyn_state.vddc_phase_shed_limits_table);
1676        hwmgr->dyn_state.vddc_phase_shed_limits_table = NULL;
1677
1678        kfree(hwmgr->dyn_state.vce_clock_voltage_dependency_table);
1679        hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
1680
1681        kfree(hwmgr->dyn_state.uvd_clock_voltage_dependency_table);
1682        hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
1683
1684        kfree(hwmgr->dyn_state.samu_clock_voltage_dependency_table);
1685        hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
1686
1687        kfree(hwmgr->dyn_state.acp_clock_voltage_dependency_table);
1688        hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
1689
1690        kfree(hwmgr->dyn_state.cac_dtp_table);
1691        hwmgr->dyn_state.cac_dtp_table = NULL;
1692
1693        kfree(hwmgr->dyn_state.ppm_parameter_table);
1694        hwmgr->dyn_state.ppm_parameter_table = NULL;
1695
1696        kfree(hwmgr->dyn_state.vdd_gfx_dependency_on_sclk);
1697        hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
1698
1699        return 0;
1700}
1701
1702const struct pp_table_func pptable_funcs = {
1703        .pptable_init = pp_tables_initialize,
1704        .pptable_fini = pp_tables_uninitialize,
1705        .pptable_get_number_of_vce_state_table_entries =
1706                                get_number_of_vce_state_table_entries,
1707        .pptable_get_vce_state_table_entry =
1708                                                get_vce_state_table_entry,
1709};
1710
1711