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