LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/pm/powerplay/smumgr - tonga_smumgr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 1436 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 53 0.0 %

          Line data    Source code
       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/pci.h>
      27             : #include <linux/slab.h>
      28             : #include <linux/gfp.h>
      29             : 
      30             : #include "smumgr.h"
      31             : #include "tonga_smumgr.h"
      32             : #include "smu_ucode_xfer_vi.h"
      33             : #include "tonga_ppsmc.h"
      34             : #include "smu/smu_7_1_2_d.h"
      35             : #include "smu/smu_7_1_2_sh_mask.h"
      36             : #include "cgs_common.h"
      37             : #include "smu7_smumgr.h"
      38             : 
      39             : #include "smu7_dyn_defaults.h"
      40             : 
      41             : #include "smu7_hwmgr.h"
      42             : #include "hardwaremanager.h"
      43             : #include "ppatomctrl.h"
      44             : 
      45             : #include "atombios.h"
      46             : 
      47             : #include "pppcielanes.h"
      48             : #include "pp_endian.h"
      49             : 
      50             : #include "gmc/gmc_8_1_d.h"
      51             : #include "gmc/gmc_8_1_sh_mask.h"
      52             : 
      53             : #include "bif/bif_5_0_d.h"
      54             : #include "bif/bif_5_0_sh_mask.h"
      55             : 
      56             : #include "dce/dce_10_0_d.h"
      57             : #include "dce/dce_10_0_sh_mask.h"
      58             : 
      59             : #define POWERTUNE_DEFAULT_SET_MAX    1
      60             : #define MC_CG_ARB_FREQ_F1           0x0b
      61             : #define VDDC_VDDCI_DELTA            200
      62             : 
      63             : 
      64             : static const struct tonga_pt_defaults tonga_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
      65             : /* sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc,  TDC_MAWt,
      66             :  * TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac,        BAPM_TEMP_GRADIENT
      67             :  */
      68             :         {1,               0xF,             0xFD,                0x19,
      69             :          5,               45,                 0,              0xB0000,
      70             :          {0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8,
      71             :                 0xC9, 0xC9, 0x2F, 0x4D, 0x61},
      72             :          {0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203,
      73             :                 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4}
      74             :         },
      75             : };
      76             : 
      77             : /* [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] */
      78             : static const uint16_t tonga_clock_stretcher_lookup_table[2][4] = {
      79             :         {600, 1050, 3, 0},
      80             :         {600, 1050, 6, 1}
      81             : };
      82             : 
      83             : /* [FF, SS] type, [] 4 voltage ranges,
      84             :  * and [Floor Freq, Boundary Freq, VID min , VID max]
      85             :  */
      86             : static const uint32_t tonga_clock_stretcher_ddt_table[2][4][4] = {
      87             :         { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
      88             :         { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} }
      89             : };
      90             : 
      91             : /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] */
      92             : static const uint8_t tonga_clock_stretch_amount_conversion[2][6] = {
      93             :         {0, 1, 3, 2, 4, 5},
      94             :         {0, 2, 4, 5, 6, 5}
      95             : };
      96             : 
      97           0 : static int tonga_start_in_protection_mode(struct pp_hwmgr *hwmgr)
      98             : {
      99             :         int result;
     100             : 
     101             :         /* Assert reset */
     102           0 :         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
     103             :                 SMC_SYSCON_RESET_CNTL, rst_reg, 1);
     104             : 
     105           0 :         result = smu7_upload_smu_firmware_image(hwmgr);
     106           0 :         if (result)
     107             :                 return result;
     108             : 
     109             :         /* Clear status */
     110           0 :         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
     111             :                 ixSMU_STATUS, 0);
     112             : 
     113             :         /* Enable clock */
     114           0 :         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
     115             :                 SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
     116             : 
     117             :         /* De-assert reset */
     118           0 :         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
     119             :                 SMC_SYSCON_RESET_CNTL, rst_reg, 0);
     120             : 
     121             :         /* Set SMU Auto Start */
     122           0 :         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
     123             :                 SMU_INPUT_DATA, AUTO_START, 1);
     124             : 
     125             :         /* Clear firmware interrupt enable flag */
     126           0 :         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
     127             :                 ixFIRMWARE_FLAGS, 0);
     128             : 
     129           0 :         PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, SMC_IND,
     130             :                 RCU_UC_EVENTS, INTERRUPTS_ENABLED, 1);
     131             : 
     132             :         /**
     133             :          * Call Test SMU message with 0x20000 offset to trigger SMU start
     134             :          */
     135           0 :         smu7_send_msg_to_smc_offset(hwmgr);
     136             : 
     137             :         /* Wait for done bit to be set */
     138           0 :         PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, SMC_IND,
     139             :                 SMU_STATUS, SMU_DONE, 0);
     140             : 
     141             :         /* Check pass/failed indicator */
     142           0 :         if (1 != PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
     143             :                                 CGS_IND_REG__SMC, SMU_STATUS, SMU_PASS)) {
     144           0 :                 pr_err("SMU Firmware start failed\n");
     145           0 :                 return -EINVAL;
     146             :         }
     147             : 
     148             :         /* Wait for firmware to initialize */
     149           0 :         PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, SMC_IND,
     150             :                 FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
     151             : 
     152           0 :         return 0;
     153             : }
     154             : 
     155           0 : static int tonga_start_in_non_protection_mode(struct pp_hwmgr *hwmgr)
     156             : {
     157           0 :         int result = 0;
     158             : 
     159             :         /* wait for smc boot up */
     160           0 :         PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, SMC_IND,
     161             :                 RCU_UC_EVENTS, boot_seq_done, 0);
     162             : 
     163             :         /*Clear firmware interrupt enable flag*/
     164           0 :         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
     165             :                 ixFIRMWARE_FLAGS, 0);
     166             : 
     167             : 
     168           0 :         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
     169             :                 SMC_SYSCON_RESET_CNTL, rst_reg, 1);
     170             : 
     171           0 :         result = smu7_upload_smu_firmware_image(hwmgr);
     172             : 
     173           0 :         if (result != 0)
     174             :                 return result;
     175             : 
     176             :         /* Set smc instruct start point at 0x0 */
     177           0 :         smu7_program_jump_on_start(hwmgr);
     178             : 
     179             : 
     180           0 :         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
     181             :                 SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
     182             : 
     183             :         /*De-assert reset*/
     184           0 :         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
     185             :                 SMC_SYSCON_RESET_CNTL, rst_reg, 0);
     186             : 
     187             :         /* Wait for firmware to initialize */
     188           0 :         PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, SMC_IND,
     189             :                 FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
     190             : 
     191           0 :         return result;
     192             : }
     193             : 
     194           0 : static int tonga_start_smu(struct pp_hwmgr *hwmgr)
     195             : {
     196           0 :         struct tonga_smumgr *priv = hwmgr->smu_backend;
     197             :         int result;
     198             : 
     199             :         /* Only start SMC if SMC RAM is not running */
     200           0 :         if (!smu7_is_smc_ram_running(hwmgr) && hwmgr->not_vf) {
     201             :                 /*Check if SMU is running in protected mode*/
     202           0 :                 if (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
     203             :                                         SMU_FIRMWARE, SMU_MODE)) {
     204           0 :                         result = tonga_start_in_non_protection_mode(hwmgr);
     205           0 :                         if (result)
     206             :                                 return result;
     207             :                 } else {
     208           0 :                         result = tonga_start_in_protection_mode(hwmgr);
     209           0 :                         if (result)
     210             :                                 return result;
     211             :                 }
     212             :         }
     213             : 
     214             :         /* Setup SoftRegsStart here to visit the register UcodeLoadStatus
     215             :          * to check fw loading state
     216             :          */
     217           0 :         smu7_read_smc_sram_dword(hwmgr,
     218             :                         SMU72_FIRMWARE_HEADER_LOCATION +
     219             :                         offsetof(SMU72_Firmware_Header, SoftRegisters),
     220             :                         &(priv->smu7_data.soft_regs_start), 0x40000);
     221             : 
     222           0 :         result = smu7_request_smu_load_fw(hwmgr);
     223             : 
     224           0 :         return result;
     225             : }
     226             : 
     227           0 : static int tonga_smu_init(struct pp_hwmgr *hwmgr)
     228             : {
     229           0 :         struct tonga_smumgr *tonga_priv = NULL;
     230             : 
     231           0 :         tonga_priv = kzalloc(sizeof(struct tonga_smumgr), GFP_KERNEL);
     232           0 :         if (tonga_priv == NULL)
     233             :                 return -ENOMEM;
     234             : 
     235           0 :         hwmgr->smu_backend = tonga_priv;
     236             : 
     237           0 :         if (smu7_init(hwmgr)) {
     238           0 :                 kfree(tonga_priv);
     239           0 :                 return -EINVAL;
     240             :         }
     241             : 
     242             :         return 0;
     243             : }
     244             : 
     245             : 
     246           0 : static int tonga_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
     247             :         phm_ppt_v1_clock_voltage_dependency_table *allowed_clock_voltage_table,
     248             :         uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
     249             : {
     250           0 :         uint32_t i = 0;
     251           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     252           0 :         struct phm_ppt_v1_information *pptable_info =
     253             :                            (struct phm_ppt_v1_information *)(hwmgr->pptable);
     254             : 
     255             :         /* clock - voltage dependency table is empty table */
     256           0 :         if (allowed_clock_voltage_table->count == 0)
     257             :                 return -EINVAL;
     258             : 
     259           0 :         for (i = 0; i < allowed_clock_voltage_table->count; i++) {
     260             :                 /* find first sclk bigger than request */
     261           0 :                 if (allowed_clock_voltage_table->entries[i].clk >= clock) {
     262           0 :                         voltage->VddGfx = phm_get_voltage_index(
     263             :                                         pptable_info->vddgfx_lookup_table,
     264           0 :                                 allowed_clock_voltage_table->entries[i].vddgfx);
     265           0 :                         voltage->Vddc = phm_get_voltage_index(
     266             :                                                 pptable_info->vddc_lookup_table,
     267           0 :                                   allowed_clock_voltage_table->entries[i].vddc);
     268             : 
     269           0 :                         if (allowed_clock_voltage_table->entries[i].vddci)
     270           0 :                                 voltage->Vddci =
     271           0 :                                         phm_get_voltage_id(&data->vddci_voltage_table, allowed_clock_voltage_table->entries[i].vddci);
     272             :                         else
     273           0 :                                 voltage->Vddci =
     274           0 :                                         phm_get_voltage_id(&data->vddci_voltage_table,
     275           0 :                                                 allowed_clock_voltage_table->entries[i].vddc - VDDC_VDDCI_DELTA);
     276             : 
     277             : 
     278           0 :                         if (allowed_clock_voltage_table->entries[i].mvdd)
     279           0 :                                 *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i].mvdd;
     280             : 
     281           0 :                         voltage->Phases = 1;
     282             :                         return 0;
     283             :                 }
     284             :         }
     285             : 
     286             :         /* sclk is bigger than max sclk in the dependence table */
     287           0 :         voltage->VddGfx = phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
     288           0 :                 allowed_clock_voltage_table->entries[i-1].vddgfx);
     289           0 :         voltage->Vddc = phm_get_voltage_index(pptable_info->vddc_lookup_table,
     290           0 :                 allowed_clock_voltage_table->entries[i-1].vddc);
     291             : 
     292           0 :         if (allowed_clock_voltage_table->entries[i-1].vddci)
     293           0 :                 voltage->Vddci = phm_get_voltage_id(&data->vddci_voltage_table,
     294             :                         allowed_clock_voltage_table->entries[i-1].vddci);
     295             : 
     296           0 :         if (allowed_clock_voltage_table->entries[i-1].mvdd)
     297           0 :                 *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i-1].mvdd;
     298             : 
     299             :         return 0;
     300             : }
     301             : 
     302           0 : static int tonga_populate_smc_vddc_table(struct pp_hwmgr *hwmgr,
     303             :                         SMU72_Discrete_DpmTable *table)
     304             : {
     305             :         unsigned int count;
     306           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     307             : 
     308           0 :         if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
     309           0 :                 table->VddcLevelCount = data->vddc_voltage_table.count;
     310           0 :                 for (count = 0; count < table->VddcLevelCount; count++) {
     311           0 :                         table->VddcTable[count] =
     312           0 :                                 PP_HOST_TO_SMC_US(data->vddc_voltage_table.entries[count].value * VOLTAGE_SCALE);
     313             :                 }
     314           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount);
     315             :         }
     316           0 :         return 0;
     317             : }
     318             : 
     319           0 : static int tonga_populate_smc_vdd_gfx_table(struct pp_hwmgr *hwmgr,
     320             :                         SMU72_Discrete_DpmTable *table)
     321             : {
     322             :         unsigned int count;
     323           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     324             : 
     325           0 :         if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
     326           0 :                 table->VddGfxLevelCount = data->vddgfx_voltage_table.count;
     327           0 :                 for (count = 0; count < data->vddgfx_voltage_table.count; count++) {
     328           0 :                         table->VddGfxTable[count] =
     329           0 :                                 PP_HOST_TO_SMC_US(data->vddgfx_voltage_table.entries[count].value * VOLTAGE_SCALE);
     330             :                 }
     331           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(table->VddGfxLevelCount);
     332             :         }
     333           0 :         return 0;
     334             : }
     335             : 
     336           0 : static int tonga_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr,
     337             :                         SMU72_Discrete_DpmTable *table)
     338             : {
     339           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     340             :         uint32_t count;
     341             : 
     342           0 :         table->VddciLevelCount = data->vddci_voltage_table.count;
     343           0 :         for (count = 0; count < table->VddciLevelCount; count++) {
     344           0 :                 if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
     345           0 :                         table->VddciTable[count] =
     346           0 :                                 PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
     347           0 :                 } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
     348           0 :                         table->SmioTable1.Pattern[count].Voltage =
     349           0 :                                 PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
     350             :                         /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level. */
     351           0 :                         table->SmioTable1.Pattern[count].Smio =
     352           0 :                                 (uint8_t) count;
     353           0 :                         table->Smio[count] |=
     354           0 :                                 data->vddci_voltage_table.entries[count].smio_low;
     355           0 :                         table->VddciTable[count] =
     356           0 :                                 PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
     357             :                 }
     358             :         }
     359             : 
     360           0 :         table->SmioMask1 = data->vddci_voltage_table.mask_low;
     361           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount);
     362             : 
     363           0 :         return 0;
     364             : }
     365             : 
     366           0 : static int tonga_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
     367             :                         SMU72_Discrete_DpmTable *table)
     368             : {
     369           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     370             :         uint32_t count;
     371             : 
     372           0 :         if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
     373           0 :                 table->MvddLevelCount = data->mvdd_voltage_table.count;
     374           0 :                 for (count = 0; count < table->MvddLevelCount; count++) {
     375           0 :                         table->SmioTable2.Pattern[count].Voltage =
     376           0 :                                 PP_HOST_TO_SMC_US(data->mvdd_voltage_table.entries[count].value * VOLTAGE_SCALE);
     377             :                         /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
     378           0 :                         table->SmioTable2.Pattern[count].Smio =
     379           0 :                                 (uint8_t) count;
     380           0 :                         table->Smio[count] |=
     381           0 :                                 data->mvdd_voltage_table.entries[count].smio_low;
     382             :                 }
     383           0 :                 table->SmioMask2 = data->mvdd_voltage_table.mask_low;
     384             : 
     385           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount);
     386             :         }
     387             : 
     388           0 :         return 0;
     389             : }
     390             : 
     391           0 : static int tonga_populate_cac_tables(struct pp_hwmgr *hwmgr,
     392             :                         SMU72_Discrete_DpmTable *table)
     393             : {
     394             :         uint32_t count;
     395           0 :         uint8_t index = 0;
     396           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     397           0 :         struct phm_ppt_v1_information *pptable_info =
     398             :                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
     399           0 :         struct phm_ppt_v1_voltage_lookup_table *vddgfx_lookup_table =
     400             :                                            pptable_info->vddgfx_lookup_table;
     401           0 :         struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table =
     402             :                                                 pptable_info->vddc_lookup_table;
     403             : 
     404             :         /* table is already swapped, so in order to use the value from it
     405             :          * we need to swap it back.
     406             :          */
     407           0 :         uint32_t vddc_level_count = PP_SMC_TO_HOST_UL(table->VddcLevelCount);
     408           0 :         uint32_t vddgfx_level_count = PP_SMC_TO_HOST_UL(table->VddGfxLevelCount);
     409             : 
     410           0 :         for (count = 0; count < vddc_level_count; count++) {
     411             :                 /* We are populating vddc CAC data to BapmVddc table in split and merged mode */
     412           0 :                 index = phm_get_voltage_index(vddc_lookup_table,
     413           0 :                         data->vddc_voltage_table.entries[count].value);
     414           0 :                 table->BapmVddcVidLoSidd[count] =
     415           0 :                         convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
     416           0 :                 table->BapmVddcVidHiSidd[count] =
     417           0 :                         convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
     418           0 :                 table->BapmVddcVidHiSidd2[count] =
     419           0 :                         convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
     420             :         }
     421             : 
     422           0 :         if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
     423             :                 /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */
     424           0 :                 for (count = 0; count < vddgfx_level_count; count++) {
     425           0 :                         index = phm_get_voltage_index(vddgfx_lookup_table,
     426           0 :                                 convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_mid));
     427           0 :                         table->BapmVddGfxVidHiSidd2[count] =
     428           0 :                                 convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_high);
     429             :                 }
     430             :         } else {
     431           0 :                 for (count = 0; count < vddc_level_count; count++) {
     432           0 :                         index = phm_get_voltage_index(vddc_lookup_table,
     433           0 :                                 data->vddc_voltage_table.entries[count].value);
     434           0 :                         table->BapmVddGfxVidLoSidd[count] =
     435           0 :                                 convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
     436           0 :                         table->BapmVddGfxVidHiSidd[count] =
     437           0 :                                 convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
     438           0 :                         table->BapmVddGfxVidHiSidd2[count] =
     439           0 :                                 convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
     440             :                 }
     441             :         }
     442             : 
     443           0 :         return 0;
     444             : }
     445             : 
     446           0 : static int tonga_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
     447             :         SMU72_Discrete_DpmTable *table)
     448             : {
     449             :         int result;
     450             : 
     451           0 :         result = tonga_populate_smc_vddc_table(hwmgr, table);
     452           0 :         PP_ASSERT_WITH_CODE(!result,
     453             :                         "can not populate VDDC voltage table to SMC",
     454             :                         return -EINVAL);
     455             : 
     456           0 :         result = tonga_populate_smc_vdd_ci_table(hwmgr, table);
     457           0 :         PP_ASSERT_WITH_CODE(!result,
     458             :                         "can not populate VDDCI voltage table to SMC",
     459             :                         return -EINVAL);
     460             : 
     461           0 :         result = tonga_populate_smc_vdd_gfx_table(hwmgr, table);
     462           0 :         PP_ASSERT_WITH_CODE(!result,
     463             :                         "can not populate VDDGFX voltage table to SMC",
     464             :                         return -EINVAL);
     465             : 
     466           0 :         result = tonga_populate_smc_mvdd_table(hwmgr, table);
     467           0 :         PP_ASSERT_WITH_CODE(!result,
     468             :                         "can not populate MVDD voltage table to SMC",
     469             :                         return -EINVAL);
     470             : 
     471           0 :         result = tonga_populate_cac_tables(hwmgr, table);
     472           0 :         PP_ASSERT_WITH_CODE(!result,
     473             :                         "can not populate CAC voltage tables to SMC",
     474             :                         return -EINVAL);
     475             : 
     476             :         return 0;
     477             : }
     478             : 
     479             : static int tonga_populate_ulv_level(struct pp_hwmgr *hwmgr,
     480             :                 struct SMU72_Discrete_Ulv *state)
     481             : {
     482           0 :         struct phm_ppt_v1_information *table_info =
     483             :                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
     484             : 
     485           0 :         state->CcPwrDynRm = 0;
     486           0 :         state->CcPwrDynRm1 = 0;
     487             : 
     488           0 :         state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
     489           0 :         state->VddcOffsetVid = (uint8_t)(table_info->us_ulv_voltage_offset *
     490           0 :                         VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
     491             : 
     492           0 :         state->VddcPhase = 1;
     493             : 
     494             :         CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
     495             :         CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
     496           0 :         CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
     497             : 
     498             :         return 0;
     499             : }
     500             : 
     501             : static int tonga_populate_ulv_state(struct pp_hwmgr *hwmgr,
     502             :                 struct SMU72_Discrete_DpmTable *table)
     503             : {
     504           0 :         return tonga_populate_ulv_level(hwmgr, &table->Ulv);
     505             : }
     506             : 
     507           0 : static int tonga_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU72_Discrete_DpmTable *table)
     508             : {
     509           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     510           0 :         struct smu7_dpm_table *dpm_table = &data->dpm_table;
     511           0 :         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
     512             :         uint32_t i;
     513             : 
     514             :         /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
     515           0 :         for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
     516           0 :                 table->LinkLevel[i].PcieGenSpeed  =
     517           0 :                         (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
     518           0 :                 table->LinkLevel[i].PcieLaneCount =
     519           0 :                         (uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
     520           0 :                 table->LinkLevel[i].EnabledForActivity =
     521             :                         1;
     522           0 :                 table->LinkLevel[i].SPC =
     523           0 :                         (uint8_t)(data->pcie_spc_cap & 0xff);
     524           0 :                 table->LinkLevel[i].DownThreshold =
     525             :                         PP_HOST_TO_SMC_UL(5);
     526           0 :                 table->LinkLevel[i].UpThreshold =
     527             :                         PP_HOST_TO_SMC_UL(30);
     528             :         }
     529             : 
     530           0 :         smu_data->smc_state_table.LinkLevelCount =
     531           0 :                 (uint8_t)dpm_table->pcie_speed_table.count;
     532           0 :         data->dpm_level_enable_mask.pcie_dpm_enable_mask =
     533           0 :                 phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
     534             : 
     535           0 :         return 0;
     536             : }
     537             : 
     538           0 : static int tonga_calculate_sclk_params(struct pp_hwmgr *hwmgr,
     539             :                 uint32_t engine_clock, SMU72_Discrete_GraphicsLevel *sclk)
     540             : {
     541           0 :         const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     542             :         pp_atomctrl_clock_dividers_vi dividers;
     543           0 :         uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
     544           0 :         uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
     545           0 :         uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
     546           0 :         uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
     547           0 :         uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
     548             :         uint32_t    reference_clock;
     549             :         uint32_t reference_divider;
     550             :         uint32_t fbdiv;
     551             :         int result;
     552             : 
     553             :         /* get the engine clock dividers for this clock value*/
     554           0 :         result = atomctrl_get_engine_pll_dividers_vi(hwmgr, engine_clock,  &dividers);
     555             : 
     556           0 :         PP_ASSERT_WITH_CODE(result == 0,
     557             :                 "Error retrieving Engine Clock dividers from VBIOS.", return result);
     558             : 
     559             :         /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
     560           0 :         reference_clock = atomctrl_get_reference_clock(hwmgr);
     561             : 
     562           0 :         reference_divider = 1 + dividers.uc_pll_ref_div;
     563             : 
     564             :         /* low 14 bits is fraction and high 12 bits is divider*/
     565           0 :         fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
     566             : 
     567             :         /* SPLL_FUNC_CNTL setup*/
     568           0 :         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
     569             :                 CG_SPLL_FUNC_CNTL, SPLL_REF_DIV, dividers.uc_pll_ref_div);
     570           0 :         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
     571             :                 CG_SPLL_FUNC_CNTL, SPLL_PDIV_A,  dividers.uc_pll_post_div);
     572             : 
     573             :         /* SPLL_FUNC_CNTL_3 setup*/
     574           0 :         spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
     575             :                 CG_SPLL_FUNC_CNTL_3, SPLL_FB_DIV, fbdiv);
     576             : 
     577             :         /* set to use fractional accumulation*/
     578           0 :         spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
     579             :                 CG_SPLL_FUNC_CNTL_3, SPLL_DITHEN, 1);
     580             : 
     581           0 :         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
     582             :                         PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
     583             :                 pp_atomctrl_internal_ss_info ss_info;
     584             : 
     585           0 :                 uint32_t vcoFreq = engine_clock * dividers.uc_pll_post_div;
     586           0 :                 if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr, vcoFreq, &ss_info)) {
     587             :                         /*
     588             :                         * ss_info.speed_spectrum_percentage -- in unit of 0.01%
     589             :                         * ss_info.speed_spectrum_rate -- in unit of khz
     590             :                         */
     591             :                         /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
     592           0 :                         uint32_t clkS = reference_clock * 5 / (reference_divider * ss_info.speed_spectrum_rate);
     593             : 
     594             :                         /* clkv = 2 * D * fbdiv / NS */
     595           0 :                         uint32_t clkV = 4 * ss_info.speed_spectrum_percentage * fbdiv / (clkS * 10000);
     596             : 
     597           0 :                         cg_spll_spread_spectrum =
     598           0 :                                 PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, CLKS, clkS);
     599           0 :                         cg_spll_spread_spectrum =
     600             :                                 PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
     601           0 :                         cg_spll_spread_spectrum_2 =
     602           0 :                                 PHM_SET_FIELD(cg_spll_spread_spectrum_2, CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clkV);
     603             :                 }
     604             :         }
     605             : 
     606           0 :         sclk->SclkFrequency        = engine_clock;
     607           0 :         sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
     608           0 :         sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
     609           0 :         sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
     610           0 :         sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
     611           0 :         sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
     612             : 
     613           0 :         return 0;
     614             : }
     615             : 
     616           0 : static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
     617             :                                                 uint32_t engine_clock,
     618             :                                 SMU72_Discrete_GraphicsLevel *graphic_level)
     619             : {
     620             :         int result;
     621             :         uint32_t mvdd;
     622           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     623           0 :         struct phm_ppt_v1_information *pptable_info =
     624             :                             (struct phm_ppt_v1_information *)(hwmgr->pptable);
     625           0 :         phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL;
     626             : 
     627           0 :         result = tonga_calculate_sclk_params(hwmgr, engine_clock, graphic_level);
     628             : 
     629           0 :         if (hwmgr->od_enabled)
     630           0 :                 vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk;
     631             :         else
     632           0 :                 vdd_dep_table = pptable_info->vdd_dep_on_sclk;
     633             : 
     634             :         /* populate graphics levels*/
     635           0 :         result = tonga_get_dependency_volt_by_clk(hwmgr,
     636             :                 vdd_dep_table, engine_clock,
     637             :                 &graphic_level->MinVoltage, &mvdd);
     638           0 :         PP_ASSERT_WITH_CODE((!result),
     639             :                 "can not find VDDC voltage value for VDDC "
     640             :                 "engine clock dependency table", return result);
     641             : 
     642             :         /* SCLK frequency in units of 10KHz*/
     643           0 :         graphic_level->SclkFrequency = engine_clock;
     644             :         /* Indicates maximum activity level for this performance level. 50% for now*/
     645           0 :         graphic_level->ActivityLevel = data->current_profile_setting.sclk_activity;
     646             : 
     647           0 :         graphic_level->CcPwrDynRm = 0;
     648           0 :         graphic_level->CcPwrDynRm1 = 0;
     649             :         /* this level can be used if activity is high enough.*/
     650           0 :         graphic_level->EnabledForActivity = 0;
     651             :         /* this level can be used for throttling.*/
     652           0 :         graphic_level->EnabledForThrottle = 1;
     653           0 :         graphic_level->UpHyst = data->current_profile_setting.sclk_up_hyst;
     654           0 :         graphic_level->DownHyst = data->current_profile_setting.sclk_down_hyst;
     655           0 :         graphic_level->VoltageDownHyst = 0;
     656           0 :         graphic_level->PowerThrottle = 0;
     657             : 
     658           0 :         data->display_timing.min_clock_in_sr =
     659           0 :                         hwmgr->display_config->min_core_set_clock_in_sr;
     660             : 
     661           0 :         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
     662             :                         PHM_PlatformCaps_SclkDeepSleep))
     663           0 :                 graphic_level->DeepSleepDivId =
     664           0 :                                 smu7_get_sleep_divider_id_from_clock(engine_clock,
     665             :                                                 data->display_timing.min_clock_in_sr);
     666             : 
     667             :         /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
     668           0 :         graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
     669             : 
     670             :         if (!result) {
     671             :                 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/
     672             :                 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);*/
     673           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SclkFrequency);
     674           0 :                 CONVERT_FROM_HOST_TO_SMC_US(graphic_level->ActivityLevel);
     675           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl3);
     676           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl4);
     677           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum);
     678           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum2);
     679           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm);
     680           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm1);
     681             :         }
     682             : 
     683           0 :         return result;
     684             : }
     685             : 
     686           0 : static int tonga_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
     687             : {
     688           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     689           0 :         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
     690           0 :         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
     691           0 :         struct smu7_dpm_table *dpm_table = &data->dpm_table;
     692           0 :         struct phm_ppt_v1_pcie_table *pcie_table = pptable_info->pcie_table;
     693           0 :         uint8_t pcie_entry_count = (uint8_t) data->dpm_table.pcie_speed_table.count;
     694           0 :         uint32_t level_array_address = smu_data->smu7_data.dpm_table_start +
     695             :                                 offsetof(SMU72_Discrete_DpmTable, GraphicsLevel);
     696             : 
     697           0 :         uint32_t level_array_size = sizeof(SMU72_Discrete_GraphicsLevel) *
     698             :                                                 SMU72_MAX_LEVELS_GRAPHICS;
     699             : 
     700           0 :         SMU72_Discrete_GraphicsLevel *levels = smu_data->smc_state_table.GraphicsLevel;
     701             : 
     702             :         uint32_t i, max_entry;
     703           0 :         uint8_t highest_pcie_level_enabled = 0;
     704           0 :         uint8_t lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0;
     705           0 :         uint8_t count = 0;
     706           0 :         int result = 0;
     707             : 
     708           0 :         memset(levels, 0x00, level_array_size);
     709             : 
     710           0 :         for (i = 0; i < dpm_table->sclk_table.count; i++) {
     711           0 :                 result = tonga_populate_single_graphic_level(hwmgr,
     712             :                                         dpm_table->sclk_table.dpm_levels[i].value,
     713             :                                         &(smu_data->smc_state_table.GraphicsLevel[i]));
     714           0 :                 if (result != 0)
     715             :                         return result;
     716             : 
     717             :                 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
     718           0 :                 if (i > 1)
     719           0 :                         smu_data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
     720             :         }
     721             : 
     722             :         /* Only enable level 0 for now. */
     723           0 :         smu_data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
     724             : 
     725             :         /* set highest level watermark to high */
     726           0 :         if (dpm_table->sclk_table.count > 1)
     727           0 :                 smu_data->smc_state_table.GraphicsLevel[dpm_table->sclk_table.count-1].DisplayWatermark =
     728             :                         PPSMC_DISPLAY_WATERMARK_HIGH;
     729             : 
     730           0 :         smu_data->smc_state_table.GraphicsDpmLevelCount =
     731           0 :                 (uint8_t)dpm_table->sclk_table.count;
     732           0 :         data->dpm_level_enable_mask.sclk_dpm_enable_mask =
     733           0 :                 phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
     734             : 
     735           0 :         if (pcie_table != NULL) {
     736           0 :                 PP_ASSERT_WITH_CODE((pcie_entry_count >= 1),
     737             :                         "There must be 1 or more PCIE levels defined in PPTable.",
     738             :                         return -EINVAL);
     739           0 :                 max_entry = pcie_entry_count - 1; /* for indexing, we need to decrement by 1.*/
     740           0 :                 for (i = 0; i < dpm_table->sclk_table.count; i++) {
     741           0 :                         smu_data->smc_state_table.GraphicsLevel[i].pcieDpmLevel =
     742           0 :                                 (uint8_t) ((i < max_entry) ? i : max_entry);
     743             :                 }
     744             :         } else {
     745           0 :                 if (0 == data->dpm_level_enable_mask.pcie_dpm_enable_mask)
     746           0 :                         pr_err("Pcie Dpm Enablemask is 0 !");
     747             : 
     748           0 :                 while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
     749           0 :                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
     750           0 :                                         (1<<(highest_pcie_level_enabled+1))) != 0)) {
     751           0 :                         highest_pcie_level_enabled++;
     752             :                 }
     753             : 
     754           0 :                 while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
     755           0 :                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
     756           0 :                                         (1<<lowest_pcie_level_enabled)) == 0)) {
     757           0 :                         lowest_pcie_level_enabled++;
     758             :                 }
     759             : 
     760           0 :                 while ((count < highest_pcie_level_enabled) &&
     761           0 :                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
     762           0 :                                         (1<<(lowest_pcie_level_enabled+1+count))) == 0)) {
     763           0 :                         count++;
     764             :                 }
     765           0 :                 mid_pcie_level_enabled = (lowest_pcie_level_enabled+1+count) < highest_pcie_level_enabled ?
     766           0 :                         (lowest_pcie_level_enabled+1+count) : highest_pcie_level_enabled;
     767             : 
     768             : 
     769             :                 /* set pcieDpmLevel to highest_pcie_level_enabled*/
     770           0 :                 for (i = 2; i < dpm_table->sclk_table.count; i++)
     771           0 :                         smu_data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = highest_pcie_level_enabled;
     772             : 
     773             :                 /* set pcieDpmLevel to lowest_pcie_level_enabled*/
     774           0 :                 smu_data->smc_state_table.GraphicsLevel[0].pcieDpmLevel = lowest_pcie_level_enabled;
     775             : 
     776             :                 /* set pcieDpmLevel to mid_pcie_level_enabled*/
     777           0 :                 smu_data->smc_state_table.GraphicsLevel[1].pcieDpmLevel = mid_pcie_level_enabled;
     778             :         }
     779             :         /* level count will send to smc once at init smc table and never change*/
     780           0 :         result = smu7_copy_bytes_to_smc(hwmgr, level_array_address,
     781             :                                 (uint8_t *)levels, (uint32_t)level_array_size,
     782             :                                                                 SMC_RAM_END);
     783             : 
     784           0 :         return result;
     785             : }
     786             : 
     787           0 : static int tonga_calculate_mclk_params(
     788             :                 struct pp_hwmgr *hwmgr,
     789             :                 uint32_t memory_clock,
     790             :                 SMU72_Discrete_MemoryLevel *mclk,
     791             :                 bool strobe_mode,
     792             :                 bool dllStateOn
     793             :                 )
     794             : {
     795           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     796             : 
     797           0 :         uint32_t dll_cntl = data->clock_registers.vDLL_CNTL;
     798           0 :         uint32_t mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
     799           0 :         uint32_t mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL;
     800           0 :         uint32_t mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL;
     801           0 :         uint32_t mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL;
     802           0 :         uint32_t mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1;
     803           0 :         uint32_t mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2;
     804           0 :         uint32_t mpll_ss1 = data->clock_registers.vMPLL_SS1;
     805           0 :         uint32_t mpll_ss2 = data->clock_registers.vMPLL_SS2;
     806             : 
     807             :         pp_atomctrl_memory_clock_param mpll_param;
     808             :         int result;
     809             : 
     810           0 :         result = atomctrl_get_memory_pll_dividers_si(hwmgr,
     811             :                                 memory_clock, &mpll_param, strobe_mode);
     812           0 :         PP_ASSERT_WITH_CODE(
     813             :                         !result,
     814             :                         "Error retrieving Memory Clock Parameters from VBIOS.",
     815             :                         return result);
     816             : 
     817             :         /* MPLL_FUNC_CNTL setup*/
     818           0 :         mpll_func_cntl = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL,
     819             :                                         mpll_param.bw_ctrl);
     820             : 
     821             :         /* MPLL_FUNC_CNTL_1 setup*/
     822           0 :         mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
     823             :                                         MPLL_FUNC_CNTL_1, CLKF,
     824             :                                         mpll_param.mpll_fb_divider.cl_kf);
     825           0 :         mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
     826             :                                         MPLL_FUNC_CNTL_1, CLKFRAC,
     827             :                                         mpll_param.mpll_fb_divider.clk_frac);
     828           0 :         mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
     829             :                                                 MPLL_FUNC_CNTL_1, VCO_MODE,
     830             :                                                 mpll_param.vco_mode);
     831             : 
     832             :         /* MPLL_AD_FUNC_CNTL setup*/
     833           0 :         mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl,
     834             :                                         MPLL_AD_FUNC_CNTL, YCLK_POST_DIV,
     835             :                                         mpll_param.mpll_post_divider);
     836             : 
     837           0 :         if (data->is_memory_gddr5) {
     838             :                 /* MPLL_DQ_FUNC_CNTL setup*/
     839           0 :                 mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
     840             :                                                 MPLL_DQ_FUNC_CNTL, YCLK_SEL,
     841             :                                                 mpll_param.yclk_sel);
     842           0 :                 mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
     843             :                                                 MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV,
     844             :                                                 mpll_param.mpll_post_divider);
     845             :         }
     846             : 
     847           0 :         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
     848             :                         PHM_PlatformCaps_MemorySpreadSpectrumSupport)) {
     849             :                 /*
     850             :                  ************************************
     851             :                  Fref = Reference Frequency
     852             :                  NF = Feedback divider ratio
     853             :                  NR = Reference divider ratio
     854             :                  Fnom = Nominal VCO output frequency = Fref * NF / NR
     855             :                  Fs = Spreading Rate
     856             :                  D = Percentage down-spread / 2
     857             :                  Fint = Reference input frequency to PFD = Fref / NR
     858             :                  NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
     859             :                  CLKS = NS - 1 = ISS_STEP_NUM[11:0]
     860             :                  NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
     861             :                  CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
     862             :                  *************************************
     863             :                  */
     864             :                 pp_atomctrl_internal_ss_info ss_info;
     865             :                 uint32_t freq_nom;
     866             :                 uint32_t tmp;
     867           0 :                 uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr);
     868             : 
     869             :                 /* for GDDR5 for all modes and DDR3 */
     870           0 :                 if (1 == mpll_param.qdr)
     871           0 :                         freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider);
     872             :                 else
     873           0 :                         freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider);
     874             : 
     875             :                 /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2  Note: S.I. reference_divider = 1*/
     876           0 :                 tmp = (freq_nom / reference_clock);
     877           0 :                 tmp = tmp * tmp;
     878             : 
     879           0 :                 if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) {
     880             :                         /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
     881             :                         /* ss.Info.speed_spectrum_rate -- in unit of khz */
     882             :                         /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
     883             :                         /*     = reference_clock * 5 / speed_spectrum_rate */
     884           0 :                         uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate;
     885             : 
     886             :                         /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
     887             :                         /*     = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
     888           0 :                         uint32_t clkv =
     889           0 :                                 (uint32_t)((((131 * ss_info.speed_spectrum_percentage *
     890           0 :                                                         ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom);
     891             : 
     892           0 :                         mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv);
     893           0 :                         mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks);
     894             :                 }
     895             :         }
     896             : 
     897             :         /* MCLK_PWRMGT_CNTL setup */
     898           0 :         mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
     899             :                 MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed);
     900           0 :         mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
     901             :                 MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn);
     902           0 :         mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
     903             :                 MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn);
     904             : 
     905             :         /* Save the result data to outpupt memory level structure */
     906           0 :         mclk->MclkFrequency   = memory_clock;
     907           0 :         mclk->MpllFuncCntl    = mpll_func_cntl;
     908           0 :         mclk->MpllFuncCntl_1  = mpll_func_cntl_1;
     909           0 :         mclk->MpllFuncCntl_2  = mpll_func_cntl_2;
     910           0 :         mclk->MpllAdFuncCntl  = mpll_ad_func_cntl;
     911           0 :         mclk->MpllDqFuncCntl  = mpll_dq_func_cntl;
     912           0 :         mclk->MclkPwrmgtCntl  = mclk_pwrmgt_cntl;
     913           0 :         mclk->DllCntl         = dll_cntl;
     914           0 :         mclk->MpllSs1         = mpll_ss1;
     915           0 :         mclk->MpllSs2         = mpll_ss2;
     916             : 
     917           0 :         return 0;
     918             : }
     919             : 
     920             : static uint8_t tonga_get_mclk_frequency_ratio(uint32_t memory_clock,
     921             :                 bool strobe_mode)
     922             : {
     923             :         uint8_t mc_para_index;
     924             : 
     925           0 :         if (strobe_mode) {
     926           0 :                 if (memory_clock < 12500)
     927             :                         mc_para_index = 0x00;
     928           0 :                 else if (memory_clock > 47500)
     929             :                         mc_para_index = 0x0f;
     930             :                 else
     931           0 :                         mc_para_index = (uint8_t)((memory_clock - 10000) / 2500);
     932             :         } else {
     933           0 :                 if (memory_clock < 65000)
     934             :                         mc_para_index = 0x00;
     935           0 :                 else if (memory_clock > 135000)
     936             :                         mc_para_index = 0x0f;
     937             :                 else
     938           0 :                         mc_para_index = (uint8_t)((memory_clock - 60000) / 5000);
     939             :         }
     940             : 
     941             :         return mc_para_index;
     942             : }
     943             : 
     944             : static uint8_t tonga_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)
     945             : {
     946             :         uint8_t mc_para_index;
     947             : 
     948           0 :         if (memory_clock < 10000)
     949             :                 mc_para_index = 0;
     950           0 :         else if (memory_clock >= 80000)
     951             :                 mc_para_index = 0x0f;
     952             :         else
     953           0 :                 mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1);
     954             : 
     955             :         return mc_para_index;
     956             : }
     957             : 
     958             : 
     959           0 : static int tonga_populate_single_memory_level(
     960             :                 struct pp_hwmgr *hwmgr,
     961             :                 uint32_t memory_clock,
     962             :                 SMU72_Discrete_MemoryLevel *memory_level
     963             :                 )
     964             : {
     965           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
     966           0 :         struct phm_ppt_v1_information *pptable_info =
     967             :                           (struct phm_ppt_v1_information *)(hwmgr->pptable);
     968           0 :         uint32_t mclk_edc_wr_enable_threshold = 40000;
     969           0 :         uint32_t mclk_stutter_mode_threshold = 30000;
     970           0 :         uint32_t mclk_edc_enable_threshold = 40000;
     971           0 :         uint32_t mclk_strobe_mode_threshold = 40000;
     972           0 :         phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL;
     973           0 :         int result = 0;
     974             :         bool dll_state_on;
     975           0 :         uint32_t mvdd = 0;
     976             : 
     977           0 :         if (hwmgr->od_enabled)
     978           0 :                 vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_mclk;
     979             :         else
     980           0 :                 vdd_dep_table = pptable_info->vdd_dep_on_mclk;
     981             : 
     982           0 :         if (NULL != vdd_dep_table) {
     983           0 :                 result = tonga_get_dependency_volt_by_clk(hwmgr,
     984             :                                 vdd_dep_table,
     985             :                                 memory_clock,
     986             :                                 &memory_level->MinVoltage, &mvdd);
     987           0 :                 PP_ASSERT_WITH_CODE(
     988             :                         !result,
     989             :                         "can not find MinVddc voltage value from memory VDDC "
     990             :                         "voltage dependency table",
     991             :                         return result);
     992             :         }
     993             : 
     994           0 :         if (data->mvdd_control == SMU7_VOLTAGE_CONTROL_NONE)
     995           0 :                 memory_level->MinMvdd = data->vbios_boot_state.mvdd_bootup_value;
     996             :         else
     997           0 :                 memory_level->MinMvdd = mvdd;
     998             : 
     999           0 :         memory_level->EnabledForThrottle = 1;
    1000           0 :         memory_level->EnabledForActivity = 0;
    1001           0 :         memory_level->UpHyst = data->current_profile_setting.mclk_up_hyst;
    1002           0 :         memory_level->DownHyst = data->current_profile_setting.mclk_down_hyst;
    1003           0 :         memory_level->VoltageDownHyst = 0;
    1004             : 
    1005             :         /* Indicates maximum activity level for this performance level.*/
    1006           0 :         memory_level->ActivityLevel = data->current_profile_setting.mclk_activity;
    1007           0 :         memory_level->StutterEnable = 0;
    1008           0 :         memory_level->StrobeEnable = 0;
    1009           0 :         memory_level->EdcReadEnable = 0;
    1010           0 :         memory_level->EdcWriteEnable = 0;
    1011           0 :         memory_level->RttEnable = 0;
    1012             : 
    1013             :         /* default set to low watermark. Highest level will be set to high later.*/
    1014           0 :         memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
    1015             : 
    1016           0 :         data->display_timing.num_existing_displays = hwmgr->display_config->num_display;
    1017           0 :         data->display_timing.vrefresh = hwmgr->display_config->vrefresh;
    1018             : 
    1019           0 :         if ((mclk_stutter_mode_threshold != 0) &&
    1020           0 :             (memory_clock <= mclk_stutter_mode_threshold) &&
    1021           0 :             (!data->is_uvd_enabled)
    1022           0 :             && (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL, STUTTER_ENABLE) & 0x1)
    1023           0 :             && (data->display_timing.num_existing_displays <= 2)
    1024           0 :             && (data->display_timing.num_existing_displays != 0))
    1025           0 :                 memory_level->StutterEnable = 1;
    1026             : 
    1027             :         /* decide strobe mode*/
    1028           0 :         memory_level->StrobeEnable = (mclk_strobe_mode_threshold != 0) &&
    1029           0 :                 (memory_clock <= mclk_strobe_mode_threshold);
    1030             : 
    1031             :         /* decide EDC mode and memory clock ratio*/
    1032           0 :         if (data->is_memory_gddr5) {
    1033           0 :                 memory_level->StrobeRatio = tonga_get_mclk_frequency_ratio(memory_clock,
    1034             :                                         memory_level->StrobeEnable);
    1035             : 
    1036           0 :                 if ((mclk_edc_enable_threshold != 0) &&
    1037             :                                 (memory_clock > mclk_edc_enable_threshold)) {
    1038           0 :                         memory_level->EdcReadEnable = 1;
    1039             :                 }
    1040             : 
    1041           0 :                 if ((mclk_edc_wr_enable_threshold != 0) &&
    1042             :                                 (memory_clock > mclk_edc_wr_enable_threshold)) {
    1043           0 :                         memory_level->EdcWriteEnable = 1;
    1044             :                 }
    1045             : 
    1046           0 :                 if (memory_level->StrobeEnable) {
    1047           0 :                         if (tonga_get_mclk_frequency_ratio(memory_clock, 1) >=
    1048           0 :                                         ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf)) {
    1049           0 :                                 dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
    1050             :                         } else {
    1051           0 :                                 dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0;
    1052             :                         }
    1053             : 
    1054             :                 } else {
    1055           0 :                         dll_state_on = data->dll_default_on;
    1056             :                 }
    1057             :         } else {
    1058           0 :                 memory_level->StrobeRatio =
    1059           0 :                         tonga_get_ddr3_mclk_frequency_ratio(memory_clock);
    1060           0 :                 dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
    1061             :         }
    1062             : 
    1063           0 :         result = tonga_calculate_mclk_params(hwmgr,
    1064           0 :                 memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on);
    1065             : 
    1066           0 :         if (!result) {
    1067           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinMvdd);
    1068             :                 /* MCLK frequency in units of 10KHz*/
    1069           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency);
    1070             :                 /* Indicates maximum activity level for this performance level.*/
    1071           0 :                 CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel);
    1072           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl);
    1073           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1);
    1074           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2);
    1075           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl);
    1076           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl);
    1077           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl);
    1078           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl);
    1079           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1);
    1080           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2);
    1081             :         }
    1082             : 
    1083             :         return result;
    1084             : }
    1085             : 
    1086           0 : static int tonga_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
    1087             : {
    1088           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    1089           0 :         struct tonga_smumgr *smu_data =
    1090             :                         (struct tonga_smumgr *)(hwmgr->smu_backend);
    1091           0 :         struct smu7_dpm_table *dpm_table = &data->dpm_table;
    1092             :         int result;
    1093             : 
    1094             :         /* populate MCLK dpm table to SMU7 */
    1095           0 :         uint32_t level_array_address =
    1096           0 :                                 smu_data->smu7_data.dpm_table_start +
    1097             :                                 offsetof(SMU72_Discrete_DpmTable, MemoryLevel);
    1098           0 :         uint32_t level_array_size =
    1099             :                                 sizeof(SMU72_Discrete_MemoryLevel) *
    1100             :                                 SMU72_MAX_LEVELS_MEMORY;
    1101           0 :         SMU72_Discrete_MemoryLevel *levels =
    1102             :                                 smu_data->smc_state_table.MemoryLevel;
    1103             :         uint32_t i;
    1104             : 
    1105           0 :         memset(levels, 0x00, level_array_size);
    1106             : 
    1107           0 :         for (i = 0; i < dpm_table->mclk_table.count; i++) {
    1108           0 :                 PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
    1109             :                         "can not populate memory level as memory clock is zero",
    1110             :                         return -EINVAL);
    1111           0 :                 result = tonga_populate_single_memory_level(
    1112             :                                 hwmgr,
    1113             :                                 dpm_table->mclk_table.dpm_levels[i].value,
    1114             :                                 &(smu_data->smc_state_table.MemoryLevel[i]));
    1115           0 :                 if (result)
    1116             :                         return result;
    1117             :         }
    1118             : 
    1119             :         /* Only enable level 0 for now.*/
    1120           0 :         smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
    1121             : 
    1122             :         /*
    1123             :         * in order to prevent MC activity from stutter mode to push DPM up.
    1124             :         * the UVD change complements this by putting the MCLK in a higher state
    1125             :         * by default such that we are not effected by up threshold or and MCLK DPM latency.
    1126             :         */
    1127             :         smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
    1128           0 :         CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel);
    1129             : 
    1130           0 :         smu_data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count;
    1131           0 :         data->dpm_level_enable_mask.mclk_dpm_enable_mask = phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
    1132             :         /* set highest level watermark to high*/
    1133           0 :         smu_data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
    1134             : 
    1135             :         /* level count will send to smc once at init smc table and never change*/
    1136           0 :         result = smu7_copy_bytes_to_smc(hwmgr,
    1137             :                 level_array_address, (uint8_t *)levels, (uint32_t)level_array_size,
    1138             :                 SMC_RAM_END);
    1139             : 
    1140           0 :         return result;
    1141             : }
    1142             : 
    1143           0 : static int tonga_populate_mvdd_value(struct pp_hwmgr *hwmgr,
    1144             :                                 uint32_t mclk, SMIO_Pattern *smio_pattern)
    1145             : {
    1146           0 :         const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    1147           0 :         struct phm_ppt_v1_information *table_info =
    1148             :                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
    1149           0 :         uint32_t i = 0;
    1150             : 
    1151           0 :         if (SMU7_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
    1152             :                 /* find mvdd value which clock is more than request */
    1153           0 :                 for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
    1154           0 :                         if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
    1155             :                                 /* Always round to higher voltage. */
    1156           0 :                                 smio_pattern->Voltage =
    1157           0 :                                       data->mvdd_voltage_table.entries[i].value;
    1158             :                                 break;
    1159             :                         }
    1160             :                 }
    1161             : 
    1162           0 :                 PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
    1163             :                         "MVDD Voltage is outside the supported range.",
    1164             :                         return -EINVAL);
    1165             :         } else {
    1166             :                 return -EINVAL;
    1167             :         }
    1168             : 
    1169             :         return 0;
    1170             : }
    1171             : 
    1172             : 
    1173           0 : static int tonga_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
    1174             :         SMU72_Discrete_DpmTable *table)
    1175             : {
    1176           0 :         int result = 0;
    1177           0 :         struct tonga_smumgr *smu_data =
    1178             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    1179           0 :         const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    1180             :         struct pp_atomctrl_clock_dividers_vi dividers;
    1181             : 
    1182             :         SMIO_Pattern voltage_level;
    1183           0 :         uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
    1184           0 :         uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
    1185           0 :         uint32_t dll_cntl          = data->clock_registers.vDLL_CNTL;
    1186           0 :         uint32_t mclk_pwrmgt_cntl  = data->clock_registers.vMCLK_PWRMGT_CNTL;
    1187             : 
    1188             :         /* The ACPI state should not do DPM on DC (or ever).*/
    1189           0 :         table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
    1190             : 
    1191           0 :         table->ACPILevel.MinVoltage =
    1192             :                         smu_data->smc_state_table.GraphicsLevel[0].MinVoltage;
    1193             : 
    1194             :         /* assign zero for now*/
    1195           0 :         table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr);
    1196             : 
    1197             :         /* get the engine clock dividers for this clock value*/
    1198           0 :         result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
    1199             :                 table->ACPILevel.SclkFrequency,  &dividers);
    1200             : 
    1201           0 :         PP_ASSERT_WITH_CODE(result == 0,
    1202             :                 "Error retrieving Engine Clock dividers from VBIOS.",
    1203             :                 return result);
    1204             : 
    1205             :         /* divider ID for required SCLK*/
    1206           0 :         table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
    1207           0 :         table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
    1208           0 :         table->ACPILevel.DeepSleepDivId = 0;
    1209             : 
    1210           0 :         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
    1211             :                                         SPLL_PWRON, 0);
    1212           0 :         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
    1213             :                                                 SPLL_RESET, 1);
    1214           0 :         spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, CG_SPLL_FUNC_CNTL_2,
    1215             :                                                 SCLK_MUX_SEL, 4);
    1216             : 
    1217           0 :         table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
    1218           0 :         table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
    1219           0 :         table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
    1220           0 :         table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
    1221           0 :         table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
    1222           0 :         table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
    1223           0 :         table->ACPILevel.CcPwrDynRm = 0;
    1224           0 :         table->ACPILevel.CcPwrDynRm1 = 0;
    1225             : 
    1226             : 
    1227             :         /* For various features to be enabled/disabled while this level is active.*/
    1228           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
    1229             :         /* SCLK frequency in units of 10KHz*/
    1230           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
    1231           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
    1232           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
    1233           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
    1234           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
    1235           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
    1236           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
    1237             :         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
    1238             :         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
    1239             : 
    1240             :         /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
    1241           0 :         table->MemoryACPILevel.MinVoltage =
    1242             :                             smu_data->smc_state_table.MemoryLevel[0].MinVoltage;
    1243             : 
    1244             :         /*  CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/
    1245             : 
    1246           0 :         if (0 == tonga_populate_mvdd_value(hwmgr, 0, &voltage_level))
    1247           0 :                 table->MemoryACPILevel.MinMvdd =
    1248           0 :                         PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE);
    1249             :         else
    1250           0 :                 table->MemoryACPILevel.MinMvdd = 0;
    1251             : 
    1252             :         /* Force reset on DLL*/
    1253           0 :         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
    1254             :                 MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1);
    1255           0 :         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
    1256             :                 MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1);
    1257             : 
    1258             :         /* Disable DLL in ACPIState*/
    1259           0 :         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
    1260             :                 MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0);
    1261           0 :         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
    1262             :                 MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0);
    1263             : 
    1264             :         /* Enable DLL bypass signal*/
    1265           0 :         dll_cntl            = PHM_SET_FIELD(dll_cntl,
    1266             :                 DLL_CNTL, MRDCK0_BYPASS, 0);
    1267           0 :         dll_cntl            = PHM_SET_FIELD(dll_cntl,
    1268             :                 DLL_CNTL, MRDCK1_BYPASS, 0);
    1269             : 
    1270           0 :         table->MemoryACPILevel.DllCntl            =
    1271           0 :                 PP_HOST_TO_SMC_UL(dll_cntl);
    1272           0 :         table->MemoryACPILevel.MclkPwrmgtCntl     =
    1273           0 :                 PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl);
    1274           0 :         table->MemoryACPILevel.MpllAdFuncCntl     =
    1275           0 :                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL);
    1276           0 :         table->MemoryACPILevel.MpllDqFuncCntl     =
    1277           0 :                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL);
    1278           0 :         table->MemoryACPILevel.MpllFuncCntl       =
    1279           0 :                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL);
    1280           0 :         table->MemoryACPILevel.MpllFuncCntl_1     =
    1281           0 :                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1);
    1282           0 :         table->MemoryACPILevel.MpllFuncCntl_2     =
    1283           0 :                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2);
    1284           0 :         table->MemoryACPILevel.MpllSs1            =
    1285           0 :                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1);
    1286           0 :         table->MemoryACPILevel.MpllSs2            =
    1287           0 :                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2);
    1288             : 
    1289           0 :         table->MemoryACPILevel.EnabledForThrottle = 0;
    1290           0 :         table->MemoryACPILevel.EnabledForActivity = 0;
    1291           0 :         table->MemoryACPILevel.UpHyst = 0;
    1292           0 :         table->MemoryACPILevel.DownHyst = 100;
    1293           0 :         table->MemoryACPILevel.VoltageDownHyst = 0;
    1294             :         /* Indicates maximum activity level for this performance level.*/
    1295           0 :         table->MemoryACPILevel.ActivityLevel =
    1296           0 :                         PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity);
    1297             : 
    1298           0 :         table->MemoryACPILevel.StutterEnable = 0;
    1299           0 :         table->MemoryACPILevel.StrobeEnable = 0;
    1300           0 :         table->MemoryACPILevel.EdcReadEnable = 0;
    1301           0 :         table->MemoryACPILevel.EdcWriteEnable = 0;
    1302           0 :         table->MemoryACPILevel.RttEnable = 0;
    1303             : 
    1304           0 :         return result;
    1305             : }
    1306             : 
    1307           0 : static int tonga_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
    1308             :                                         SMU72_Discrete_DpmTable *table)
    1309             : {
    1310           0 :         int result = 0;
    1311             : 
    1312             :         uint8_t count;
    1313             :         pp_atomctrl_clock_dividers_vi dividers;
    1314           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    1315           0 :         struct phm_ppt_v1_information *pptable_info =
    1316             :                                 (struct phm_ppt_v1_information *)(hwmgr->pptable);
    1317           0 :         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
    1318             :                                                 pptable_info->mm_dep_table;
    1319             : 
    1320           0 :         table->UvdLevelCount = (uint8_t) (mm_table->count);
    1321           0 :         table->UvdBootLevel = 0;
    1322             : 
    1323           0 :         for (count = 0; count < table->UvdLevelCount; count++) {
    1324           0 :                 table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
    1325           0 :                 table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
    1326           0 :                 table->UvdLevel[count].MinVoltage.Vddc =
    1327           0 :                         phm_get_voltage_index(pptable_info->vddc_lookup_table,
    1328           0 :                                                 mm_table->entries[count].vddc);
    1329           0 :                 table->UvdLevel[count].MinVoltage.VddGfx =
    1330           0 :                         (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ?
    1331           0 :                         phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
    1332           0 :                                                 mm_table->entries[count].vddgfx) : 0;
    1333           0 :                 table->UvdLevel[count].MinVoltage.Vddci =
    1334           0 :                         phm_get_voltage_id(&data->vddci_voltage_table,
    1335           0 :                                              mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
    1336           0 :                 table->UvdLevel[count].MinVoltage.Phases = 1;
    1337             : 
    1338             :                 /* retrieve divider value for VBIOS */
    1339           0 :                 result = atomctrl_get_dfs_pll_dividers_vi(
    1340             :                                         hwmgr,
    1341             :                                         table->UvdLevel[count].VclkFrequency,
    1342             :                                         &dividers);
    1343             : 
    1344           0 :                 PP_ASSERT_WITH_CODE((!result),
    1345             :                                     "can not find divide id for Vclk clock",
    1346             :                                         return result);
    1347             : 
    1348           0 :                 table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
    1349             : 
    1350           0 :                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
    1351             :                                                           table->UvdLevel[count].DclkFrequency, &dividers);
    1352           0 :                 PP_ASSERT_WITH_CODE((!result),
    1353             :                                     "can not find divide id for Dclk clock",
    1354             :                                         return result);
    1355             : 
    1356           0 :                 table->UvdLevel[count].DclkDivider =
    1357           0 :                                         (uint8_t)dividers.pll_post_divider;
    1358             : 
    1359           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
    1360           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
    1361             :         }
    1362             : 
    1363             :         return result;
    1364             : 
    1365             : }
    1366             : 
    1367           0 : static int tonga_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
    1368             :                 SMU72_Discrete_DpmTable *table)
    1369             : {
    1370           0 :         int result = 0;
    1371             : 
    1372             :         uint8_t count;
    1373             :         pp_atomctrl_clock_dividers_vi dividers;
    1374           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    1375           0 :         struct phm_ppt_v1_information *pptable_info =
    1376             :                               (struct phm_ppt_v1_information *)(hwmgr->pptable);
    1377           0 :         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
    1378             :                                                      pptable_info->mm_dep_table;
    1379             : 
    1380           0 :         table->VceLevelCount = (uint8_t) (mm_table->count);
    1381           0 :         table->VceBootLevel = 0;
    1382             : 
    1383           0 :         for (count = 0; count < table->VceLevelCount; count++) {
    1384           0 :                 table->VceLevel[count].Frequency =
    1385           0 :                         mm_table->entries[count].eclk;
    1386           0 :                 table->VceLevel[count].MinVoltage.Vddc =
    1387           0 :                         phm_get_voltage_index(pptable_info->vddc_lookup_table,
    1388           0 :                                 mm_table->entries[count].vddc);
    1389           0 :                 table->VceLevel[count].MinVoltage.VddGfx =
    1390           0 :                         (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ?
    1391           0 :                         phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
    1392           0 :                                 mm_table->entries[count].vddgfx) : 0;
    1393           0 :                 table->VceLevel[count].MinVoltage.Vddci =
    1394           0 :                         phm_get_voltage_id(&data->vddci_voltage_table,
    1395           0 :                                 mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
    1396           0 :                 table->VceLevel[count].MinVoltage.Phases = 1;
    1397             : 
    1398             :                 /* retrieve divider value for VBIOS */
    1399           0 :                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
    1400             :                                         table->VceLevel[count].Frequency, &dividers);
    1401           0 :                 PP_ASSERT_WITH_CODE((!result),
    1402             :                                 "can not find divide id for VCE engine clock",
    1403             :                                 return result);
    1404             : 
    1405           0 :                 table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
    1406             : 
    1407           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
    1408             :         }
    1409             : 
    1410             :         return result;
    1411             : }
    1412             : 
    1413           0 : static int tonga_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
    1414             :                 SMU72_Discrete_DpmTable *table)
    1415             : {
    1416           0 :         int result = 0;
    1417             :         uint8_t count;
    1418             :         pp_atomctrl_clock_dividers_vi dividers;
    1419           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    1420           0 :         struct phm_ppt_v1_information *pptable_info =
    1421             :                              (struct phm_ppt_v1_information *)(hwmgr->pptable);
    1422           0 :         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
    1423             :                                                     pptable_info->mm_dep_table;
    1424             : 
    1425           0 :         table->AcpLevelCount = (uint8_t) (mm_table->count);
    1426           0 :         table->AcpBootLevel = 0;
    1427             : 
    1428           0 :         for (count = 0; count < table->AcpLevelCount; count++) {
    1429           0 :                 table->AcpLevel[count].Frequency =
    1430           0 :                         pptable_info->mm_dep_table->entries[count].aclk;
    1431           0 :                 table->AcpLevel[count].MinVoltage.Vddc =
    1432           0 :                         phm_get_voltage_index(pptable_info->vddc_lookup_table,
    1433           0 :                         mm_table->entries[count].vddc);
    1434           0 :                 table->AcpLevel[count].MinVoltage.VddGfx =
    1435           0 :                         (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ?
    1436           0 :                         phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
    1437           0 :                                 mm_table->entries[count].vddgfx) : 0;
    1438           0 :                 table->AcpLevel[count].MinVoltage.Vddci =
    1439           0 :                         phm_get_voltage_id(&data->vddci_voltage_table,
    1440           0 :                                 mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
    1441           0 :                 table->AcpLevel[count].MinVoltage.Phases = 1;
    1442             : 
    1443             :                 /* retrieve divider value for VBIOS */
    1444           0 :                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
    1445             :                         table->AcpLevel[count].Frequency, &dividers);
    1446           0 :                 PP_ASSERT_WITH_CODE((!result),
    1447             :                         "can not find divide id for engine clock", return result);
    1448             : 
    1449           0 :                 table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
    1450             : 
    1451           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
    1452             :         }
    1453             : 
    1454             :         return result;
    1455             : }
    1456             : 
    1457           0 : static int tonga_populate_memory_timing_parameters(
    1458             :                 struct pp_hwmgr *hwmgr,
    1459             :                 uint32_t engine_clock,
    1460             :                 uint32_t memory_clock,
    1461             :                 struct SMU72_Discrete_MCArbDramTimingTableEntry *arb_regs
    1462             :                 )
    1463             : {
    1464             :         uint32_t dramTiming;
    1465             :         uint32_t dramTiming2;
    1466             :         uint32_t burstTime;
    1467             :         int result;
    1468             : 
    1469           0 :         result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
    1470             :                                 engine_clock, memory_clock);
    1471             : 
    1472           0 :         PP_ASSERT_WITH_CODE(result == 0,
    1473             :                 "Error calling VBIOS to set DRAM_TIMING.", return result);
    1474             : 
    1475           0 :         dramTiming  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
    1476           0 :         dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
    1477           0 :         burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
    1478             : 
    1479           0 :         arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dramTiming);
    1480           0 :         arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2);
    1481           0 :         arb_regs->McArbBurstTime = (uint8_t)burstTime;
    1482             : 
    1483           0 :         return 0;
    1484             : }
    1485             : 
    1486           0 : static int tonga_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
    1487             : {
    1488           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    1489           0 :         struct tonga_smumgr *smu_data =
    1490             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    1491           0 :         int result = 0;
    1492             :         SMU72_Discrete_MCArbDramTimingTable  arb_regs;
    1493             :         uint32_t i, j;
    1494             : 
    1495           0 :         memset(&arb_regs, 0x00, sizeof(SMU72_Discrete_MCArbDramTimingTable));
    1496             : 
    1497           0 :         for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
    1498           0 :                 for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
    1499           0 :                         result = tonga_populate_memory_timing_parameters
    1500             :                                 (hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
    1501             :                                  data->dpm_table.mclk_table.dpm_levels[j].value,
    1502           0 :                                  &arb_regs.entries[i][j]);
    1503             : 
    1504           0 :                         if (result)
    1505             :                                 break;
    1506             :                 }
    1507             :         }
    1508             : 
    1509           0 :         if (!result) {
    1510           0 :                 result = smu7_copy_bytes_to_smc(
    1511             :                                 hwmgr,
    1512             :                                 smu_data->smu7_data.arb_table_start,
    1513             :                                 (uint8_t *)&arb_regs,
    1514             :                                 sizeof(SMU72_Discrete_MCArbDramTimingTable),
    1515             :                                 SMC_RAM_END
    1516             :                                 );
    1517             :         }
    1518             : 
    1519           0 :         return result;
    1520             : }
    1521             : 
    1522           0 : static int tonga_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
    1523             :                         SMU72_Discrete_DpmTable *table)
    1524             : {
    1525           0 :         int result = 0;
    1526           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    1527           0 :         struct tonga_smumgr *smu_data =
    1528             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    1529           0 :         table->GraphicsBootLevel = 0;
    1530           0 :         table->MemoryBootLevel = 0;
    1531             : 
    1532             :         /* find boot level from dpm table*/
    1533           0 :         result = phm_find_boot_level(&(data->dpm_table.sclk_table),
    1534             :         data->vbios_boot_state.sclk_bootup_value,
    1535           0 :         (uint32_t *)&(smu_data->smc_state_table.GraphicsBootLevel));
    1536             : 
    1537           0 :         if (result != 0) {
    1538           0 :                 smu_data->smc_state_table.GraphicsBootLevel = 0;
    1539           0 :                 pr_err("[powerplay] VBIOS did not find boot engine "
    1540             :                                 "clock value in dependency table. "
    1541             :                                 "Using Graphics DPM level 0 !");
    1542           0 :                 result = 0;
    1543             :         }
    1544             : 
    1545           0 :         result = phm_find_boot_level(&(data->dpm_table.mclk_table),
    1546             :                 data->vbios_boot_state.mclk_bootup_value,
    1547           0 :                 (uint32_t *)&(smu_data->smc_state_table.MemoryBootLevel));
    1548             : 
    1549           0 :         if (result != 0) {
    1550           0 :                 smu_data->smc_state_table.MemoryBootLevel = 0;
    1551           0 :                 pr_err("[powerplay] VBIOS did not find boot "
    1552             :                                 "engine clock value in dependency table."
    1553             :                                 "Using Memory DPM level 0 !");
    1554           0 :                 result = 0;
    1555             :         }
    1556             : 
    1557           0 :         table->BootVoltage.Vddc =
    1558           0 :                 phm_get_voltage_id(&(data->vddc_voltage_table),
    1559           0 :                         data->vbios_boot_state.vddc_bootup_value);
    1560           0 :         table->BootVoltage.VddGfx =
    1561           0 :                 phm_get_voltage_id(&(data->vddgfx_voltage_table),
    1562           0 :                         data->vbios_boot_state.vddgfx_bootup_value);
    1563           0 :         table->BootVoltage.Vddci =
    1564           0 :                 phm_get_voltage_id(&(data->vddci_voltage_table),
    1565           0 :                         data->vbios_boot_state.vddci_bootup_value);
    1566           0 :         table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value;
    1567             : 
    1568           0 :         CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
    1569             : 
    1570           0 :         return result;
    1571             : }
    1572             : 
    1573           0 : static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
    1574             : {
    1575             :         uint32_t ro, efuse, efuse2, clock_freq, volt_without_cks,
    1576             :                         volt_with_cks, value;
    1577             :         uint16_t clock_freq_u16;
    1578           0 :         struct tonga_smumgr *smu_data =
    1579             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    1580             :         uint8_t type, i, j, cks_setting, stretch_amount, stretch_amount2,
    1581           0 :                         volt_offset = 0;
    1582           0 :         struct phm_ppt_v1_information *table_info =
    1583             :                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
    1584           0 :         struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
    1585             :                         table_info->vdd_dep_on_sclk;
    1586             :         uint32_t hw_revision, dev_id;
    1587           0 :         struct amdgpu_device *adev = hwmgr->adev;
    1588             : 
    1589           0 :         stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
    1590             : 
    1591           0 :         hw_revision = adev->pdev->revision;
    1592           0 :         dev_id = adev->pdev->device;
    1593             : 
    1594             :         /* Read SMU_Eefuse to read and calculate RO and determine
    1595             :          * if the part is SS or FF. if RO >= 1660MHz, part is FF.
    1596             :          */
    1597           0 :         efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
    1598             :                         ixSMU_EFUSE_0 + (146 * 4));
    1599           0 :         efuse2 = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
    1600             :                         ixSMU_EFUSE_0 + (148 * 4));
    1601           0 :         efuse &= 0xFF000000;
    1602           0 :         efuse = efuse >> 24;
    1603           0 :         efuse2 &= 0xF;
    1604             : 
    1605           0 :         if (efuse2 == 1)
    1606           0 :                 ro = (2300 - 1350) * efuse / 255 + 1350;
    1607             :         else
    1608           0 :                 ro = (2500 - 1000) * efuse / 255 + 1000;
    1609             : 
    1610           0 :         if (ro >= 1660)
    1611             :                 type = 0;
    1612             :         else
    1613           0 :                 type = 1;
    1614             : 
    1615             :         /* Populate Stretch amount */
    1616           0 :         smu_data->smc_state_table.ClockStretcherAmount = stretch_amount;
    1617             : 
    1618             : 
    1619             :         /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
    1620           0 :         for (i = 0; i < sclk_table->count; i++) {
    1621           0 :                 smu_data->smc_state_table.Sclk_CKS_masterEn0_7 |=
    1622           0 :                                 sclk_table->entries[i].cks_enable << i;
    1623           0 :                 if (ASICID_IS_TONGA_P(dev_id, hw_revision)) {
    1624           0 :                         volt_without_cks = (uint32_t)((7732 + 60 - ro - 20838 *
    1625           0 :                                 (sclk_table->entries[i].clk/100) / 10000) * 1000 /
    1626           0 :                                 (8730 - (5301 * (sclk_table->entries[i].clk/100) / 1000)));
    1627           0 :                         volt_with_cks = (uint32_t)((5250 + 51 - ro - 2404 *
    1628           0 :                                 (sclk_table->entries[i].clk/100) / 100000) * 1000 /
    1629           0 :                                 (6146 - (3193 * (sclk_table->entries[i].clk/100) / 1000)));
    1630             :                 } else {
    1631           0 :                         volt_without_cks = (uint32_t)((14041 *
    1632           0 :                                 (sclk_table->entries[i].clk/100) / 10000 + 3571 + 75 - ro) * 1000 /
    1633           0 :                                 (4026 - (13924 * (sclk_table->entries[i].clk/100) / 10000)));
    1634           0 :                         volt_with_cks = (uint32_t)((13946 *
    1635           0 :                                 (sclk_table->entries[i].clk/100) / 10000 + 3320 + 45 - ro) * 1000 /
    1636           0 :                                 (3664 - (11454 * (sclk_table->entries[i].clk/100) / 10000)));
    1637             :                 }
    1638           0 :                 if (volt_without_cks >= volt_with_cks)
    1639           0 :                         volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
    1640           0 :                                         sclk_table->entries[i].cks_voffset) * 100 / 625) + 1);
    1641           0 :                 smu_data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
    1642             :         }
    1643             : 
    1644           0 :         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
    1645             :                         STRETCH_ENABLE, 0x0);
    1646           0 :         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
    1647             :                         masterReset, 0x1);
    1648           0 :         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
    1649             :                         staticEnable, 0x1);
    1650           0 :         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
    1651             :                         masterReset, 0x0);
    1652             : 
    1653             :         /* Populate CKS Lookup Table */
    1654           0 :         if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
    1655             :                 stretch_amount2 = 0;
    1656           0 :         else if (stretch_amount == 3 || stretch_amount == 4)
    1657             :                 stretch_amount2 = 1;
    1658             :         else {
    1659           0 :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
    1660             :                                 PHM_PlatformCaps_ClockStretcher);
    1661           0 :                 PP_ASSERT_WITH_CODE(false,
    1662             :                                 "Stretch Amount in PPTable not supported",
    1663             :                                 return -EINVAL);
    1664             :         }
    1665             : 
    1666           0 :         value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
    1667             :                         ixPWR_CKS_CNTL);
    1668           0 :         value &= 0xFFC2FF87;
    1669             :         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].minFreq =
    1670           0 :                         tonga_clock_stretcher_lookup_table[stretch_amount2][0];
    1671             :         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].maxFreq =
    1672           0 :                         tonga_clock_stretcher_lookup_table[stretch_amount2][1];
    1673           0 :         clock_freq_u16 = (uint16_t)(PP_SMC_TO_HOST_UL(smu_data->smc_state_table.
    1674             :                         GraphicsLevel[smu_data->smc_state_table.GraphicsDpmLevelCount - 1].
    1675           0 :                         SclkFrequency) / 100);
    1676           0 :         if (tonga_clock_stretcher_lookup_table[stretch_amount2][0] <
    1677           0 :                         clock_freq_u16 &&
    1678             :             tonga_clock_stretcher_lookup_table[stretch_amount2][1] >
    1679             :                         clock_freq_u16) {
    1680             :                 /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
    1681           0 :                 value |= (tonga_clock_stretcher_lookup_table[stretch_amount2][3]) << 16;
    1682             :                 /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
    1683           0 :                 value |= (tonga_clock_stretcher_lookup_table[stretch_amount2][2]) << 18;
    1684             :                 /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
    1685           0 :                 value |= (tonga_clock_stretch_amount_conversion
    1686             :                                 [tonga_clock_stretcher_lookup_table[stretch_amount2][3]]
    1687           0 :                                  [stretch_amount]) << 3;
    1688             :         }
    1689           0 :         CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable.
    1690             :                         CKS_LOOKUPTableEntry[0].minFreq);
    1691           0 :         CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable.
    1692             :                         CKS_LOOKUPTableEntry[0].maxFreq);
    1693             :         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting =
    1694           0 :                         tonga_clock_stretcher_lookup_table[stretch_amount2][2] & 0x7F;
    1695           0 :         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting |=
    1696           0 :                         (tonga_clock_stretcher_lookup_table[stretch_amount2][3]) << 7;
    1697             : 
    1698           0 :         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
    1699             :                         ixPWR_CKS_CNTL, value);
    1700             : 
    1701             :         /* Populate DDT Lookup Table */
    1702           0 :         for (i = 0; i < 4; i++) {
    1703             :                 /* Assign the minimum and maximum VID stored
    1704             :                  * in the last row of Clock Stretcher Voltage Table.
    1705             :                  */
    1706             :                 smu_data->smc_state_table.ClockStretcherDataTable.
    1707           0 :                 ClockStretcherDataTableEntry[i].minVID =
    1708           0 :                                 (uint8_t) tonga_clock_stretcher_ddt_table[type][i][2];
    1709             :                 smu_data->smc_state_table.ClockStretcherDataTable.
    1710           0 :                 ClockStretcherDataTableEntry[i].maxVID =
    1711           0 :                                 (uint8_t) tonga_clock_stretcher_ddt_table[type][i][3];
    1712             :                 /* Loop through each SCLK and check the frequency
    1713             :                  * to see if it lies within the frequency for clock stretcher.
    1714             :                  */
    1715           0 :                 for (j = 0; j < smu_data->smc_state_table.GraphicsDpmLevelCount; j++) {
    1716           0 :                         cks_setting = 0;
    1717           0 :                         clock_freq = PP_SMC_TO_HOST_UL(
    1718             :                                         smu_data->smc_state_table.GraphicsLevel[j].SclkFrequency);
    1719             :                         /* Check the allowed frequency against the sclk level[j].
    1720             :                          *  Sclk's endianness has already been converted,
    1721             :                          *  and it's in 10Khz unit,
    1722             :                          *  as opposed to Data table, which is in Mhz unit.
    1723             :                          */
    1724           0 :                         if (clock_freq >= tonga_clock_stretcher_ddt_table[type][i][0] * 100) {
    1725           0 :                                 cks_setting |= 0x2;
    1726           0 :                                 if (clock_freq < tonga_clock_stretcher_ddt_table[type][i][1] * 100)
    1727           0 :                                         cks_setting |= 0x1;
    1728             :                         }
    1729             :                         smu_data->smc_state_table.ClockStretcherDataTable.
    1730           0 :                         ClockStretcherDataTableEntry[i].setting |= cks_setting << (j * 2);
    1731             :                 }
    1732           0 :                 CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.
    1733             :                                 ClockStretcherDataTable.
    1734             :                                 ClockStretcherDataTableEntry[i].setting);
    1735             :         }
    1736             : 
    1737           0 :         value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
    1738             :                                         ixPWR_CKS_CNTL);
    1739           0 :         value &= 0xFFFFFFFE;
    1740           0 :         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
    1741             :                                         ixPWR_CKS_CNTL, value);
    1742             : 
    1743           0 :         return 0;
    1744             : }
    1745             : 
    1746           0 : static int tonga_populate_vr_config(struct pp_hwmgr *hwmgr,
    1747             :                         SMU72_Discrete_DpmTable *table)
    1748             : {
    1749           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    1750             :         uint16_t config;
    1751             : 
    1752           0 :         if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
    1753             :                 /*  Splitted mode */
    1754           0 :                 config = VR_SVI2_PLANE_1;
    1755           0 :                 table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
    1756             : 
    1757           0 :                 if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
    1758           0 :                         config = VR_SVI2_PLANE_2;
    1759           0 :                         table->VRConfig |= config;
    1760             :                 } else {
    1761           0 :                         pr_err("VDDC and VDDGFX should "
    1762             :                                 "be both on SVI2 control in splitted mode !\n");
    1763             :                 }
    1764             :         } else {
    1765             :                 /* Merged mode  */
    1766           0 :                 config = VR_MERGED_WITH_VDDC;
    1767           0 :                 table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
    1768             : 
    1769             :                 /* Set Vddc Voltage Controller  */
    1770           0 :                 if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
    1771           0 :                         config = VR_SVI2_PLANE_1;
    1772           0 :                         table->VRConfig |= config;
    1773             :                 } else {
    1774           0 :                         pr_err("VDDC should be on "
    1775             :                                         "SVI2 control in merged mode !\n");
    1776             :                 }
    1777             :         }
    1778             : 
    1779             :         /* Set Vddci Voltage Controller  */
    1780           0 :         if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
    1781           0 :                 config = VR_SVI2_PLANE_2;  /* only in merged mode */
    1782           0 :                 table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
    1783           0 :         } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
    1784           0 :                 config = VR_SMIO_PATTERN_1;
    1785           0 :                 table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
    1786             :         }
    1787             : 
    1788             :         /* Set Mvdd Voltage Controller */
    1789           0 :         if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
    1790           0 :                 config = VR_SMIO_PATTERN_2;
    1791           0 :                 table->VRConfig |= (config<<VRCONF_MVDD_SHIFT);
    1792             :         }
    1793             : 
    1794           0 :         return 0;
    1795             : }
    1796             : 
    1797           0 : static int tonga_init_arb_table_index(struct pp_hwmgr *hwmgr)
    1798             : {
    1799           0 :         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
    1800             :         uint32_t tmp;
    1801             :         int result;
    1802             : 
    1803             :         /*
    1804             :         * This is a read-modify-write on the first byte of the ARB table.
    1805             :         * The first byte in the SMU72_Discrete_MCArbDramTimingTable structure
    1806             :         * is the field 'current'.
    1807             :         * This solution is ugly, but we never write the whole table only
    1808             :         * individual fields in it.
    1809             :         * In reality this field should not be in that structure
    1810             :         * but in a soft register.
    1811             :         */
    1812           0 :         result = smu7_read_smc_sram_dword(hwmgr,
    1813             :                                 smu_data->smu7_data.arb_table_start, &tmp, SMC_RAM_END);
    1814             : 
    1815           0 :         if (result != 0)
    1816             :                 return result;
    1817             : 
    1818           0 :         tmp &= 0x00FFFFFF;
    1819           0 :         tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
    1820             : 
    1821           0 :         return smu7_write_smc_sram_dword(hwmgr,
    1822             :                         smu_data->smu7_data.arb_table_start, tmp, SMC_RAM_END);
    1823             : }
    1824             : 
    1825             : 
    1826           0 : static int tonga_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
    1827             : {
    1828           0 :         struct tonga_smumgr *smu_data =
    1829             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    1830           0 :         const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
    1831           0 :         SMU72_Discrete_DpmTable  *dpm_table = &(smu_data->smc_state_table);
    1832           0 :         struct phm_ppt_v1_information *table_info =
    1833             :                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
    1834           0 :         struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
    1835             :         int  i, j, k;
    1836             :         const uint16_t *pdef1, *pdef2;
    1837             : 
    1838           0 :         dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
    1839             :                         (uint16_t)(cac_dtp_table->usTDP * 256));
    1840           0 :         dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
    1841             :                         (uint16_t)(cac_dtp_table->usConfigurableTDP * 256));
    1842             : 
    1843           0 :         PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
    1844             :                         "Target Operating Temp is out of Range !",
    1845             :                         );
    1846             : 
    1847           0 :         dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
    1848           0 :         dpm_table->GpuTjHyst = 8;
    1849             : 
    1850           0 :         dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base;
    1851             : 
    1852           0 :         dpm_table->BAPM_TEMP_GRADIENT =
    1853           0 :                                 PP_HOST_TO_SMC_UL(defaults->bapm_temp_gradient);
    1854           0 :         pdef1 = defaults->bapmti_r;
    1855           0 :         pdef2 = defaults->bapmti_rc;
    1856             : 
    1857           0 :         for (i = 0; i < SMU72_DTE_ITERATIONS; i++) {
    1858           0 :                 for (j = 0; j < SMU72_DTE_SOURCES; j++) {
    1859           0 :                         for (k = 0; k < SMU72_DTE_SINKS; k++) {
    1860           0 :                                 dpm_table->BAPMTI_R[i][j][k] =
    1861           0 :                                                 PP_HOST_TO_SMC_US(*pdef1);
    1862           0 :                                 dpm_table->BAPMTI_RC[i][j][k] =
    1863           0 :                                                 PP_HOST_TO_SMC_US(*pdef2);
    1864           0 :                                 pdef1++;
    1865           0 :                                 pdef2++;
    1866             :                         }
    1867             :                 }
    1868             :         }
    1869             : 
    1870           0 :         return 0;
    1871             : }
    1872             : 
    1873             : static int tonga_populate_svi_load_line(struct pp_hwmgr *hwmgr)
    1874             : {
    1875           0 :         struct tonga_smumgr *smu_data =
    1876             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    1877           0 :         const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
    1878             : 
    1879           0 :         smu_data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en;
    1880           0 :         smu_data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddC;
    1881           0 :         smu_data->power_tune_table.SviLoadLineTrimVddC = 3;
    1882           0 :         smu_data->power_tune_table.SviLoadLineOffsetVddC = 0;
    1883             : 
    1884             :         return 0;
    1885             : }
    1886             : 
    1887             : static int tonga_populate_tdc_limit(struct pp_hwmgr *hwmgr)
    1888             : {
    1889             :         uint16_t tdc_limit;
    1890           0 :         struct tonga_smumgr *smu_data =
    1891             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    1892           0 :         const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
    1893           0 :         struct phm_ppt_v1_information *table_info =
    1894             :                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
    1895             : 
    1896             :         /* TDC number of fraction bits are changed from 8 to 7
    1897             :          * for Fiji as requested by SMC team
    1898             :          */
    1899           0 :         tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 256);
    1900           0 :         smu_data->power_tune_table.TDC_VDDC_PkgLimit =
    1901           0 :                         CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
    1902           0 :         smu_data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
    1903           0 :                         defaults->tdc_vddc_throttle_release_limit_perc;
    1904           0 :         smu_data->power_tune_table.TDC_MAWt = defaults->tdc_mawt;
    1905             : 
    1906             :         return 0;
    1907             : }
    1908             : 
    1909           0 : static int tonga_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
    1910             : {
    1911           0 :         struct tonga_smumgr *smu_data =
    1912             :                         (struct tonga_smumgr *)(hwmgr->smu_backend);
    1913           0 :         const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
    1914             :         uint32_t temp;
    1915             : 
    1916           0 :         if (smu7_read_smc_sram_dword(hwmgr,
    1917             :                         fuse_table_offset +
    1918             :                         offsetof(SMU72_Discrete_PmFuses, TdcWaterfallCtl),
    1919             :                         (uint32_t *)&temp, SMC_RAM_END))
    1920           0 :                 PP_ASSERT_WITH_CODE(false,
    1921             :                                 "Attempt to read PmFuses.DW6 "
    1922             :                                 "(SviLoadLineEn) from SMC Failed !",
    1923             :                                 return -EINVAL);
    1924             :         else
    1925           0 :                 smu_data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl;
    1926             : 
    1927           0 :         return 0;
    1928             : }
    1929             : 
    1930             : static int tonga_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
    1931             : {
    1932             :         int i;
    1933           0 :         struct tonga_smumgr *smu_data =
    1934             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    1935             : 
    1936             :         /* Currently not used. Set all to zero. */
    1937           0 :         for (i = 0; i < 16; i++)
    1938           0 :                 smu_data->power_tune_table.LPMLTemperatureScaler[i] = 0;
    1939             : 
    1940             :         return 0;
    1941             : }
    1942             : 
    1943             : static int tonga_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
    1944             : {
    1945           0 :         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
    1946             : 
    1947           0 :         if ((hwmgr->thermal_controller.advanceFanControlParameters.
    1948           0 :                         usFanOutputSensitivity & (1 << 15)) ||
    1949             :                 (hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity == 0))
    1950             :                 hwmgr->thermal_controller.advanceFanControlParameters.
    1951           0 :                 usFanOutputSensitivity = hwmgr->thermal_controller.
    1952           0 :                         advanceFanControlParameters.usDefaultFanOutputSensitivity;
    1953             : 
    1954           0 :         smu_data->power_tune_table.FuzzyFan_PwmSetDelta =
    1955           0 :                         PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
    1956             :                                         advanceFanControlParameters.usFanOutputSensitivity);
    1957             :         return 0;
    1958             : }
    1959             : 
    1960             : static int tonga_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
    1961             : {
    1962             :         int i;
    1963           0 :         struct tonga_smumgr *smu_data =
    1964             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    1965             : 
    1966             :         /* Currently not used. Set all to zero. */
    1967           0 :         for (i = 0; i < 16; i++)
    1968           0 :                 smu_data->power_tune_table.GnbLPML[i] = 0;
    1969             : 
    1970             :         return 0;
    1971             : }
    1972             : 
    1973             : static int tonga_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
    1974             : {
    1975           0 :         struct tonga_smumgr *smu_data =
    1976             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    1977           0 :         struct phm_ppt_v1_information *table_info =
    1978             :                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
    1979           0 :         uint16_t hi_sidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd;
    1980           0 :         uint16_t lo_sidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd;
    1981           0 :         struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
    1982             : 
    1983           0 :         hi_sidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
    1984           0 :         lo_sidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
    1985             : 
    1986           0 :         smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd =
    1987           0 :                         CONVERT_FROM_HOST_TO_SMC_US(hi_sidd);
    1988           0 :         smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd =
    1989           0 :                         CONVERT_FROM_HOST_TO_SMC_US(lo_sidd);
    1990             : 
    1991             :         return 0;
    1992             : }
    1993             : 
    1994           0 : static int tonga_populate_pm_fuses(struct pp_hwmgr *hwmgr)
    1995             : {
    1996           0 :         struct tonga_smumgr *smu_data =
    1997             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    1998             :         uint32_t pm_fuse_table_offset;
    1999             : 
    2000           0 :         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
    2001             :                         PHM_PlatformCaps_PowerContainment)) {
    2002           0 :                 if (smu7_read_smc_sram_dword(hwmgr,
    2003             :                                 SMU72_FIRMWARE_HEADER_LOCATION +
    2004             :                                 offsetof(SMU72_Firmware_Header, PmFuseTable),
    2005             :                                 &pm_fuse_table_offset, SMC_RAM_END))
    2006           0 :                         PP_ASSERT_WITH_CODE(false,
    2007             :                                 "Attempt to get pm_fuse_table_offset Failed !",
    2008             :                                 return -EINVAL);
    2009             : 
    2010             :                 /* DW6 */
    2011           0 :                 if (tonga_populate_svi_load_line(hwmgr))
    2012             :                         PP_ASSERT_WITH_CODE(false,
    2013             :                                 "Attempt to populate SviLoadLine Failed !",
    2014             :                                 return -EINVAL);
    2015             :                 /* DW7 */
    2016           0 :                 if (tonga_populate_tdc_limit(hwmgr))
    2017             :                         PP_ASSERT_WITH_CODE(false,
    2018             :                                         "Attempt to populate TDCLimit Failed !",
    2019             :                                         return -EINVAL);
    2020             :                 /* DW8 */
    2021           0 :                 if (tonga_populate_dw8(hwmgr, pm_fuse_table_offset))
    2022           0 :                         PP_ASSERT_WITH_CODE(false,
    2023             :                                 "Attempt to populate TdcWaterfallCtl Failed !",
    2024             :                                 return -EINVAL);
    2025             : 
    2026             :                 /* DW9-DW12 */
    2027           0 :                 if (tonga_populate_temperature_scaler(hwmgr) != 0)
    2028             :                         PP_ASSERT_WITH_CODE(false,
    2029             :                                 "Attempt to populate LPMLTemperatureScaler Failed !",
    2030             :                                 return -EINVAL);
    2031             : 
    2032             :                 /* DW13-DW14 */
    2033           0 :                 if (tonga_populate_fuzzy_fan(hwmgr))
    2034             :                         PP_ASSERT_WITH_CODE(false,
    2035             :                                 "Attempt to populate Fuzzy Fan "
    2036             :                                 "Control parameters Failed !",
    2037             :                                 return -EINVAL);
    2038             : 
    2039             :                 /* DW15-DW18 */
    2040           0 :                 if (tonga_populate_gnb_lpml(hwmgr))
    2041             :                         PP_ASSERT_WITH_CODE(false,
    2042             :                                 "Attempt to populate GnbLPML Failed !",
    2043             :                                 return -EINVAL);
    2044             : 
    2045             :                 /* DW20 */
    2046           0 :                 if (tonga_populate_bapm_vddc_base_leakage_sidd(hwmgr))
    2047             :                         PP_ASSERT_WITH_CODE(
    2048             :                                 false,
    2049             :                                 "Attempt to populate BapmVddCBaseLeakage "
    2050             :                                 "Hi and Lo Sidd Failed !",
    2051             :                                 return -EINVAL);
    2052             : 
    2053           0 :                 if (smu7_copy_bytes_to_smc(hwmgr, pm_fuse_table_offset,
    2054           0 :                                 (uint8_t *)&smu_data->power_tune_table,
    2055             :                                 sizeof(struct SMU72_Discrete_PmFuses), SMC_RAM_END))
    2056           0 :                         PP_ASSERT_WITH_CODE(false,
    2057             :                                         "Attempt to download PmFuseTable Failed !",
    2058             :                                         return -EINVAL);
    2059             :         }
    2060             :         return 0;
    2061             : }
    2062             : 
    2063           0 : static int tonga_populate_mc_reg_address(struct pp_hwmgr *hwmgr,
    2064             :                                  SMU72_Discrete_MCRegisters *mc_reg_table)
    2065             : {
    2066           0 :         const struct tonga_smumgr *smu_data = (struct tonga_smumgr *)hwmgr->smu_backend;
    2067             : 
    2068             :         uint32_t i, j;
    2069             : 
    2070           0 :         for (i = 0, j = 0; j < smu_data->mc_reg_table.last; j++) {
    2071           0 :                 if (smu_data->mc_reg_table.validflag & 1<<j) {
    2072           0 :                         PP_ASSERT_WITH_CODE(
    2073             :                                 i < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE,
    2074             :                                 "Index of mc_reg_table->address[] array "
    2075             :                                 "out of boundary",
    2076             :                                 return -EINVAL);
    2077           0 :                         mc_reg_table->address[i].s0 =
    2078           0 :                                 PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s0);
    2079           0 :                         mc_reg_table->address[i].s1 =
    2080           0 :                                 PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s1);
    2081           0 :                         i++;
    2082             :                 }
    2083             :         }
    2084             : 
    2085           0 :         mc_reg_table->last = (uint8_t)i;
    2086             : 
    2087             :         return 0;
    2088             : }
    2089             : 
    2090             : /*convert register values from driver to SMC format */
    2091             : static void tonga_convert_mc_registers(
    2092             :         const struct tonga_mc_reg_entry *entry,
    2093             :         SMU72_Discrete_MCRegisterSet *data,
    2094             :         uint32_t num_entries, uint32_t valid_flag)
    2095             : {
    2096             :         uint32_t i, j;
    2097             : 
    2098           0 :         for (i = 0, j = 0; j < num_entries; j++) {
    2099           0 :                 if (valid_flag & 1<<j) {
    2100           0 :                         data->value[i] = PP_HOST_TO_SMC_UL(entry->mc_data[j]);
    2101           0 :                         i++;
    2102             :                 }
    2103             :         }
    2104             : }
    2105             : 
    2106           0 : static int tonga_convert_mc_reg_table_entry_to_smc(
    2107             :                 struct pp_hwmgr *hwmgr,
    2108             :                 const uint32_t memory_clock,
    2109             :                 SMU72_Discrete_MCRegisterSet *mc_reg_table_data
    2110             :                 )
    2111             : {
    2112           0 :         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
    2113           0 :         uint32_t i = 0;
    2114             : 
    2115           0 :         for (i = 0; i < smu_data->mc_reg_table.num_entries; i++) {
    2116           0 :                 if (memory_clock <=
    2117           0 :                         smu_data->mc_reg_table.mc_reg_table_entry[i].mclk_max) {
    2118             :                         break;
    2119             :                 }
    2120             :         }
    2121             : 
    2122           0 :         if ((i == smu_data->mc_reg_table.num_entries) && (i > 0))
    2123           0 :                 --i;
    2124             : 
    2125           0 :         tonga_convert_mc_registers(&smu_data->mc_reg_table.mc_reg_table_entry[i],
    2126           0 :                                 mc_reg_table_data, smu_data->mc_reg_table.last,
    2127           0 :                                 smu_data->mc_reg_table.validflag);
    2128             : 
    2129           0 :         return 0;
    2130             : }
    2131             : 
    2132           0 : static int tonga_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr,
    2133             :                 SMU72_Discrete_MCRegisters *mc_regs)
    2134             : {
    2135           0 :         int result = 0;
    2136           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    2137             :         int res;
    2138             :         uint32_t i;
    2139             : 
    2140           0 :         for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
    2141           0 :                 res = tonga_convert_mc_reg_table_entry_to_smc(
    2142             :                                 hwmgr,
    2143             :                                 data->dpm_table.mclk_table.dpm_levels[i].value,
    2144             :                                 &mc_regs->data[i]
    2145             :                                 );
    2146             : 
    2147           0 :                 if (0 != res)
    2148           0 :                         result = res;
    2149             :         }
    2150             : 
    2151           0 :         return result;
    2152             : }
    2153             : 
    2154           0 : static int tonga_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr)
    2155             : {
    2156           0 :         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
    2157           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    2158             :         uint32_t address;
    2159             :         int32_t result;
    2160             : 
    2161           0 :         if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
    2162             :                 return 0;
    2163             : 
    2164             : 
    2165           0 :         memset(&smu_data->mc_regs, 0, sizeof(SMU72_Discrete_MCRegisters));
    2166             : 
    2167           0 :         result = tonga_convert_mc_reg_table_to_smc(hwmgr, &(smu_data->mc_regs));
    2168             : 
    2169           0 :         if (result != 0)
    2170             :                 return result;
    2171             : 
    2172             : 
    2173           0 :         address = smu_data->smu7_data.mc_reg_table_start +
    2174             :                         (uint32_t)offsetof(SMU72_Discrete_MCRegisters, data[0]);
    2175             : 
    2176           0 :         return  smu7_copy_bytes_to_smc(
    2177             :                         hwmgr, address,
    2178           0 :                         (uint8_t *)&smu_data->mc_regs.data[0],
    2179             :                         sizeof(SMU72_Discrete_MCRegisterSet) *
    2180           0 :                         data->dpm_table.mclk_table.count,
    2181             :                         SMC_RAM_END);
    2182             : }
    2183             : 
    2184           0 : static int tonga_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr)
    2185             : {
    2186             :         int result;
    2187           0 :         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
    2188             : 
    2189           0 :         memset(&smu_data->mc_regs, 0x00, sizeof(SMU72_Discrete_MCRegisters));
    2190           0 :         result = tonga_populate_mc_reg_address(hwmgr, &(smu_data->mc_regs));
    2191           0 :         PP_ASSERT_WITH_CODE(!result,
    2192             :                 "Failed to initialize MCRegTable for the MC register addresses !",
    2193             :                 return result;);
    2194             : 
    2195           0 :         result = tonga_convert_mc_reg_table_to_smc(hwmgr, &smu_data->mc_regs);
    2196           0 :         PP_ASSERT_WITH_CODE(!result,
    2197             :                 "Failed to initialize MCRegTable for driver state !",
    2198             :                 return result;);
    2199             : 
    2200           0 :         return smu7_copy_bytes_to_smc(hwmgr, smu_data->smu7_data.mc_reg_table_start,
    2201             :                         (uint8_t *)&smu_data->mc_regs, sizeof(SMU72_Discrete_MCRegisters), SMC_RAM_END);
    2202             : }
    2203             : 
    2204             : static void tonga_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
    2205             : {
    2206           0 :         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
    2207           0 :         struct  phm_ppt_v1_information *table_info =
    2208             :                         (struct  phm_ppt_v1_information *)(hwmgr->pptable);
    2209             : 
    2210           0 :         if (table_info &&
    2211           0 :                         table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
    2212             :                         table_info->cac_dtp_table->usPowerTuneDataSetID)
    2213           0 :                 smu_data->power_tune_defaults =
    2214           0 :                                 &tonga_power_tune_data_set_array
    2215           0 :                                 [table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
    2216             :         else
    2217           0 :                 smu_data->power_tune_defaults = &tonga_power_tune_data_set_array[0];
    2218             : }
    2219             : 
    2220           0 : static int tonga_init_smc_table(struct pp_hwmgr *hwmgr)
    2221             : {
    2222             :         int result;
    2223           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    2224           0 :         struct tonga_smumgr *smu_data =
    2225             :                         (struct tonga_smumgr *)(hwmgr->smu_backend);
    2226           0 :         SMU72_Discrete_DpmTable *table = &(smu_data->smc_state_table);
    2227           0 :         struct phm_ppt_v1_information *table_info =
    2228             :                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
    2229             : 
    2230             :         uint8_t i;
    2231             :         pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
    2232             : 
    2233             : 
    2234           0 :         memset(&(smu_data->smc_state_table), 0x00, sizeof(smu_data->smc_state_table));
    2235             : 
    2236           0 :         tonga_initialize_power_tune_defaults(hwmgr);
    2237             : 
    2238           0 :         if (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control)
    2239           0 :                 tonga_populate_smc_voltage_tables(hwmgr, table);
    2240             : 
    2241           0 :         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
    2242             :                         PHM_PlatformCaps_AutomaticDCTransition))
    2243           0 :                 table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
    2244             : 
    2245             : 
    2246           0 :         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
    2247             :                         PHM_PlatformCaps_StepVddc))
    2248           0 :                 table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
    2249             : 
    2250           0 :         if (data->is_memory_gddr5)
    2251           0 :                 table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
    2252             : 
    2253           0 :         i = PHM_READ_FIELD(hwmgr->device, CC_MC_MAX_CHANNEL, NOOFCHAN);
    2254             : 
    2255           0 :         if (i == 1 || i == 0)
    2256           0 :                 table->SystemFlags |= 0x40;
    2257             : 
    2258           0 :         if (data->ulv_supported && table_info->us_ulv_voltage_offset) {
    2259           0 :                 result = tonga_populate_ulv_state(hwmgr, table);
    2260             :                 PP_ASSERT_WITH_CODE(!result,
    2261             :                         "Failed to initialize ULV state !",
    2262             :                         return result;);
    2263             : 
    2264           0 :                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
    2265             :                         ixCG_ULV_PARAMETER, 0x40035);
    2266             :         }
    2267             : 
    2268           0 :         result = tonga_populate_smc_link_level(hwmgr, table);
    2269           0 :         PP_ASSERT_WITH_CODE(!result,
    2270             :                 "Failed to initialize Link Level !", return result);
    2271             : 
    2272           0 :         result = tonga_populate_all_graphic_levels(hwmgr);
    2273           0 :         PP_ASSERT_WITH_CODE(!result,
    2274             :                 "Failed to initialize Graphics Level !", return result);
    2275             : 
    2276           0 :         result = tonga_populate_all_memory_levels(hwmgr);
    2277           0 :         PP_ASSERT_WITH_CODE(!result,
    2278             :                 "Failed to initialize Memory Level !", return result);
    2279             : 
    2280           0 :         result = tonga_populate_smc_acpi_level(hwmgr, table);
    2281           0 :         PP_ASSERT_WITH_CODE(!result,
    2282             :                 "Failed to initialize ACPI Level !", return result);
    2283             : 
    2284           0 :         result = tonga_populate_smc_vce_level(hwmgr, table);
    2285           0 :         PP_ASSERT_WITH_CODE(!result,
    2286             :                 "Failed to initialize VCE Level !", return result);
    2287             : 
    2288           0 :         result = tonga_populate_smc_acp_level(hwmgr, table);
    2289           0 :         PP_ASSERT_WITH_CODE(!result,
    2290             :                 "Failed to initialize ACP Level !", return result);
    2291             : 
    2292             :         /* Since only the initial state is completely set up at this
    2293             :         * point (the other states are just copies of the boot state) we only
    2294             :         * need to populate the  ARB settings for the initial state.
    2295             :         */
    2296           0 :         result = tonga_program_memory_timing_parameters(hwmgr);
    2297           0 :         PP_ASSERT_WITH_CODE(!result,
    2298             :                 "Failed to Write ARB settings for the initial state.",
    2299             :                 return result;);
    2300             : 
    2301           0 :         result = tonga_populate_smc_uvd_level(hwmgr, table);
    2302           0 :         PP_ASSERT_WITH_CODE(!result,
    2303             :                 "Failed to initialize UVD Level !", return result);
    2304             : 
    2305           0 :         result = tonga_populate_smc_boot_level(hwmgr, table);
    2306           0 :         PP_ASSERT_WITH_CODE(!result,
    2307             :                 "Failed to initialize Boot Level !", return result);
    2308             : 
    2309           0 :         tonga_populate_bapm_parameters_in_dpm_table(hwmgr);
    2310             :         PP_ASSERT_WITH_CODE(!result,
    2311             :                 "Failed to populate BAPM Parameters !", return result);
    2312             : 
    2313           0 :         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
    2314             :                         PHM_PlatformCaps_ClockStretcher)) {
    2315           0 :                 result = tonga_populate_clock_stretcher_data_table(hwmgr);
    2316           0 :                 PP_ASSERT_WITH_CODE(!result,
    2317             :                         "Failed to populate Clock Stretcher Data Table !",
    2318             :                         return result;);
    2319             :         }
    2320           0 :         table->GraphicsVoltageChangeEnable  = 1;
    2321           0 :         table->GraphicsThermThrottleEnable  = 1;
    2322           0 :         table->GraphicsInterval = 1;
    2323           0 :         table->VoltageInterval  = 1;
    2324           0 :         table->ThermalInterval  = 1;
    2325           0 :         table->TemperatureLimitHigh =
    2326           0 :                 table_info->cac_dtp_table->usTargetOperatingTemp *
    2327             :                 SMU7_Q88_FORMAT_CONVERSION_UNIT;
    2328           0 :         table->TemperatureLimitLow =
    2329           0 :                 (table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
    2330             :                 SMU7_Q88_FORMAT_CONVERSION_UNIT;
    2331           0 :         table->MemoryVoltageChangeEnable  = 1;
    2332           0 :         table->MemoryInterval  = 1;
    2333           0 :         table->VoltageResponseTime  = 0;
    2334           0 :         table->PhaseResponseTime  = 0;
    2335           0 :         table->MemoryThermThrottleEnable  = 1;
    2336             : 
    2337             :         /*
    2338             :         * Cail reads current link status and reports it as cap (we cannot
    2339             :         * change this due to some previous issues we had)
    2340             :         * SMC drops the link status to lowest level after enabling
    2341             :         * DPM by PowerPlay. After pnp or toggling CF, driver gets reloaded again
    2342             :         * but this time Cail reads current link status which was set to low by
    2343             :         * SMC and reports it as cap to powerplay
    2344             :         * To avoid it, we set PCIeBootLinkLevel to highest dpm level
    2345             :         */
    2346           0 :         PP_ASSERT_WITH_CODE((1 <= data->dpm_table.pcie_speed_table.count),
    2347             :                         "There must be 1 or more PCIE levels defined in PPTable.",
    2348             :                         return -EINVAL);
    2349             : 
    2350           0 :         table->PCIeBootLinkLevel = (uint8_t) (data->dpm_table.pcie_speed_table.count);
    2351             : 
    2352           0 :         table->PCIeGenInterval  = 1;
    2353             : 
    2354           0 :         result = tonga_populate_vr_config(hwmgr, table);
    2355           0 :         PP_ASSERT_WITH_CODE(!result,
    2356             :                 "Failed to populate VRConfig setting !", return result);
    2357           0 :         data->vr_config = table->VRConfig;
    2358           0 :         table->ThermGpio  = 17;
    2359           0 :         table->SclkStepSize = 0x4000;
    2360             : 
    2361           0 :         if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID,
    2362             :                                                 &gpio_pin_assignment)) {
    2363           0 :                 table->VRHotGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
    2364           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
    2365             :                         PHM_PlatformCaps_RegulatorHot);
    2366             :         } else {
    2367           0 :                 table->VRHotGpio = SMU7_UNUSED_GPIO_PIN;
    2368           0 :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
    2369             :                         PHM_PlatformCaps_RegulatorHot);
    2370             :         }
    2371             : 
    2372           0 :         if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
    2373             :                                                 &gpio_pin_assignment)) {
    2374           0 :                 table->AcDcGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
    2375           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
    2376             :                         PHM_PlatformCaps_AutomaticDCTransition);
    2377             :         } else {
    2378           0 :                 table->AcDcGpio = SMU7_UNUSED_GPIO_PIN;
    2379           0 :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
    2380             :                         PHM_PlatformCaps_AutomaticDCTransition);
    2381             :         }
    2382             : 
    2383           0 :         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
    2384             :                 PHM_PlatformCaps_Falcon_QuickTransition);
    2385             : 
    2386             :         if (0) {
    2387             :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
    2388             :                         PHM_PlatformCaps_AutomaticDCTransition);
    2389             :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
    2390             :                         PHM_PlatformCaps_Falcon_QuickTransition);
    2391             :         }
    2392             : 
    2393           0 :         if (atomctrl_get_pp_assign_pin(hwmgr,
    2394             :                         THERMAL_INT_OUTPUT_GPIO_PINID, &gpio_pin_assignment)) {
    2395           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
    2396             :                         PHM_PlatformCaps_ThermalOutGPIO);
    2397             : 
    2398           0 :                 table->ThermOutGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
    2399             : 
    2400           0 :                 table->ThermOutPolarity =
    2401           0 :                         (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
    2402           0 :                         (1 << gpio_pin_assignment.uc_gpio_pin_bit_shift))) ? 1 : 0;
    2403             : 
    2404           0 :                 table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
    2405             : 
    2406             :                 /* if required, combine VRHot/PCC with thermal out GPIO*/
    2407           0 :                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
    2408           0 :                         PHM_PlatformCaps_RegulatorHot) &&
    2409           0 :                         phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
    2410             :                         PHM_PlatformCaps_CombinePCCWithThermalSignal)){
    2411           0 :                         table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
    2412             :                 }
    2413             :         } else {
    2414           0 :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
    2415             :                         PHM_PlatformCaps_ThermalOutGPIO);
    2416             : 
    2417           0 :                 table->ThermOutGpio = 17;
    2418           0 :                 table->ThermOutPolarity = 1;
    2419           0 :                 table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
    2420             :         }
    2421             : 
    2422           0 :         for (i = 0; i < SMU72_MAX_ENTRIES_SMIO; i++)
    2423           0 :                 table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
    2424           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
    2425           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
    2426           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
    2427           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
    2428           0 :         CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
    2429           0 :         CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
    2430           0 :         CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
    2431           0 :         CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
    2432           0 :         CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
    2433             : 
    2434             :         /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
    2435           0 :         result = smu7_copy_bytes_to_smc(
    2436             :                         hwmgr,
    2437           0 :                         smu_data->smu7_data.dpm_table_start + offsetof(SMU72_Discrete_DpmTable, SystemFlags),
    2438           0 :                         (uint8_t *)&(table->SystemFlags),
    2439             :                         sizeof(SMU72_Discrete_DpmTable) - 3 * sizeof(SMU72_PIDController),
    2440             :                         SMC_RAM_END);
    2441             : 
    2442           0 :         PP_ASSERT_WITH_CODE(!result,
    2443             :                 "Failed to upload dpm data to SMC memory !", return result;);
    2444             : 
    2445           0 :         result = tonga_init_arb_table_index(hwmgr);
    2446           0 :         PP_ASSERT_WITH_CODE(!result,
    2447             :                         "Failed to upload arb data to SMC memory !", return result);
    2448             : 
    2449           0 :         tonga_populate_pm_fuses(hwmgr);
    2450             :         PP_ASSERT_WITH_CODE((!result),
    2451             :                 "Failed to populate initialize pm fuses !", return result);
    2452             : 
    2453           0 :         result = tonga_populate_initial_mc_reg_table(hwmgr);
    2454           0 :         PP_ASSERT_WITH_CODE((!result),
    2455             :                 "Failed to populate initialize MC Reg table !", return result);
    2456             : 
    2457             :         return 0;
    2458             : }
    2459             : 
    2460           0 : static int tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
    2461             : {
    2462           0 :         struct tonga_smumgr *smu_data =
    2463             :                         (struct tonga_smumgr *)(hwmgr->smu_backend);
    2464           0 :         SMU72_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
    2465             :         uint32_t duty100;
    2466             :         uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
    2467             :         uint16_t fdo_min, slope1, slope2;
    2468             :         uint32_t reference_clock;
    2469             :         int res;
    2470             :         uint64_t tmp64;
    2471             : 
    2472           0 :         if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
    2473             :                                         PHM_PlatformCaps_MicrocodeFanControl))
    2474             :                 return 0;
    2475             : 
    2476           0 :         if (hwmgr->thermal_controller.fanInfo.bNoFan) {
    2477           0 :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
    2478             :                         PHM_PlatformCaps_MicrocodeFanControl);
    2479           0 :                 return 0;
    2480             :         }
    2481             : 
    2482           0 :         if (0 == smu_data->smu7_data.fan_table_start) {
    2483           0 :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
    2484             :                                         PHM_PlatformCaps_MicrocodeFanControl);
    2485           0 :                 return 0;
    2486             :         }
    2487             : 
    2488           0 :         duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
    2489             :                                                 CGS_IND_REG__SMC,
    2490             :                                                 CG_FDO_CTRL1, FMAX_DUTY100);
    2491             : 
    2492           0 :         if (0 == duty100) {
    2493           0 :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
    2494             :                                 PHM_PlatformCaps_MicrocodeFanControl);
    2495           0 :                 return 0;
    2496             :         }
    2497             : 
    2498           0 :         tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
    2499           0 :         do_div(tmp64, 10000);
    2500           0 :         fdo_min = (uint16_t)tmp64;
    2501             : 
    2502           0 :         t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
    2503           0 :                    hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
    2504           0 :         t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
    2505             :                   hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
    2506             : 
    2507           0 :         pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
    2508           0 :                     hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
    2509           0 :         pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
    2510             :                     hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
    2511             : 
    2512           0 :         slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
    2513           0 :         slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
    2514             : 
    2515           0 :         fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
    2516           0 :         fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
    2517           0 :         fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
    2518             : 
    2519           0 :         fan_table.Slope1 = cpu_to_be16(slope1);
    2520           0 :         fan_table.Slope2 = cpu_to_be16(slope2);
    2521             : 
    2522           0 :         fan_table.FdoMin = cpu_to_be16(fdo_min);
    2523             : 
    2524           0 :         fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
    2525             : 
    2526           0 :         fan_table.HystUp = cpu_to_be16(1);
    2527             : 
    2528           0 :         fan_table.HystSlope = cpu_to_be16(1);
    2529             : 
    2530           0 :         fan_table.TempRespLim = cpu_to_be16(5);
    2531             : 
    2532           0 :         reference_clock = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev);
    2533             : 
    2534           0 :         fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
    2535             : 
    2536           0 :         fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
    2537             : 
    2538           0 :         fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
    2539             : 
    2540           0 :         fan_table.FanControl_GL_Flag = 1;
    2541             : 
    2542           0 :         res = smu7_copy_bytes_to_smc(hwmgr,
    2543             :                                         smu_data->smu7_data.fan_table_start,
    2544             :                                         (uint8_t *)&fan_table,
    2545             :                                         (uint32_t)sizeof(fan_table),
    2546             :                                         SMC_RAM_END);
    2547             : 
    2548           0 :         return res;
    2549             : }
    2550             : 
    2551             : 
    2552             : static int tonga_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
    2553             : {
    2554           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    2555             : 
    2556           0 :         if (data->need_update_smu7_dpm_table &
    2557             :                 (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
    2558           0 :                 return tonga_program_memory_timing_parameters(hwmgr);
    2559             : 
    2560             :         return 0;
    2561             : }
    2562             : 
    2563           0 : static int tonga_update_sclk_threshold(struct pp_hwmgr *hwmgr)
    2564             : {
    2565           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    2566           0 :         struct tonga_smumgr *smu_data =
    2567             :                         (struct tonga_smumgr *)(hwmgr->smu_backend);
    2568             : 
    2569           0 :         int result = 0;
    2570           0 :         uint32_t low_sclk_interrupt_threshold = 0;
    2571             : 
    2572           0 :         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
    2573             :                         PHM_PlatformCaps_SclkThrottleLowNotification)
    2574           0 :                 && (data->low_sclk_interrupt_threshold != 0)) {
    2575             :                 low_sclk_interrupt_threshold =
    2576             :                                 data->low_sclk_interrupt_threshold;
    2577             : 
    2578           0 :                 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
    2579             : 
    2580           0 :                 result = smu7_copy_bytes_to_smc(
    2581             :                                 hwmgr,
    2582           0 :                                 smu_data->smu7_data.dpm_table_start +
    2583             :                                 offsetof(SMU72_Discrete_DpmTable,
    2584             :                                         LowSclkInterruptThreshold),
    2585             :                                 (uint8_t *)&low_sclk_interrupt_threshold,
    2586             :                                 sizeof(uint32_t),
    2587             :                                 SMC_RAM_END);
    2588             :         }
    2589             : 
    2590           0 :         result = tonga_update_and_upload_mc_reg_table(hwmgr);
    2591             : 
    2592           0 :         PP_ASSERT_WITH_CODE((!result),
    2593             :                                 "Failed to upload MC reg table !",
    2594             :                                 return result);
    2595             : 
    2596           0 :         result = tonga_program_mem_timing_parameters(hwmgr);
    2597           0 :         PP_ASSERT_WITH_CODE((result == 0),
    2598             :                         "Failed to program memory timing parameters !",
    2599             :                         );
    2600             : 
    2601             :         return result;
    2602             : }
    2603             : 
    2604           0 : static uint32_t tonga_get_offsetof(uint32_t type, uint32_t member)
    2605             : {
    2606           0 :         switch (type) {
    2607             :         case SMU_SoftRegisters:
    2608           0 :                 switch (member) {
    2609             :                 case HandshakeDisables:
    2610             :                         return offsetof(SMU72_SoftRegisters, HandshakeDisables);
    2611             :                 case VoltageChangeTimeout:
    2612           0 :                         return offsetof(SMU72_SoftRegisters, VoltageChangeTimeout);
    2613             :                 case AverageGraphicsActivity:
    2614           0 :                         return offsetof(SMU72_SoftRegisters, AverageGraphicsActivity);
    2615             :                 case AverageMemoryActivity:
    2616           0 :                         return offsetof(SMU72_SoftRegisters, AverageMemoryActivity);
    2617             :                 case PreVBlankGap:
    2618           0 :                         return offsetof(SMU72_SoftRegisters, PreVBlankGap);
    2619             :                 case VBlankTimeout:
    2620           0 :                         return offsetof(SMU72_SoftRegisters, VBlankTimeout);
    2621             :                 case UcodeLoadStatus:
    2622           0 :                         return offsetof(SMU72_SoftRegisters, UcodeLoadStatus);
    2623             :                 case DRAM_LOG_ADDR_H:
    2624           0 :                         return offsetof(SMU72_SoftRegisters, DRAM_LOG_ADDR_H);
    2625             :                 case DRAM_LOG_ADDR_L:
    2626           0 :                         return offsetof(SMU72_SoftRegisters, DRAM_LOG_ADDR_L);
    2627             :                 case DRAM_LOG_PHY_ADDR_H:
    2628           0 :                         return offsetof(SMU72_SoftRegisters, DRAM_LOG_PHY_ADDR_H);
    2629             :                 case DRAM_LOG_PHY_ADDR_L:
    2630           0 :                         return offsetof(SMU72_SoftRegisters, DRAM_LOG_PHY_ADDR_L);
    2631             :                 case DRAM_LOG_BUFF_SIZE:
    2632           0 :                         return offsetof(SMU72_SoftRegisters, DRAM_LOG_BUFF_SIZE);
    2633             :                 }
    2634             :                 break;
    2635             :         case SMU_Discrete_DpmTable:
    2636           0 :                 switch (member) {
    2637             :                 case UvdBootLevel:
    2638             :                         return offsetof(SMU72_Discrete_DpmTable, UvdBootLevel);
    2639             :                 case VceBootLevel:
    2640           0 :                         return offsetof(SMU72_Discrete_DpmTable, VceBootLevel);
    2641             :                 case LowSclkInterruptThreshold:
    2642           0 :                         return offsetof(SMU72_Discrete_DpmTable, LowSclkInterruptThreshold);
    2643             :                 }
    2644             :                 break;
    2645             :         }
    2646           0 :         pr_warn("can't get the offset of type %x member %x\n", type, member);
    2647           0 :         return 0;
    2648             : }
    2649             : 
    2650           0 : static uint32_t tonga_get_mac_definition(uint32_t value)
    2651             : {
    2652           0 :         switch (value) {
    2653             :         case SMU_MAX_LEVELS_GRAPHICS:
    2654             :                 return SMU72_MAX_LEVELS_GRAPHICS;
    2655             :         case SMU_MAX_LEVELS_MEMORY:
    2656           0 :                 return SMU72_MAX_LEVELS_MEMORY;
    2657             :         case SMU_MAX_LEVELS_LINK:
    2658             :                 return SMU72_MAX_LEVELS_LINK;
    2659             :         case SMU_MAX_ENTRIES_SMIO:
    2660           0 :                 return SMU72_MAX_ENTRIES_SMIO;
    2661             :         case SMU_MAX_LEVELS_VDDC:
    2662           0 :                 return SMU72_MAX_LEVELS_VDDC;
    2663             :         case SMU_MAX_LEVELS_VDDGFX:
    2664           0 :                 return SMU72_MAX_LEVELS_VDDGFX;
    2665             :         case SMU_MAX_LEVELS_VDDCI:
    2666             :                 return SMU72_MAX_LEVELS_VDDCI;
    2667             :         case SMU_MAX_LEVELS_MVDD:
    2668           0 :                 return SMU72_MAX_LEVELS_MVDD;
    2669             :         }
    2670           0 :         pr_warn("can't get the mac value %x\n", value);
    2671             : 
    2672           0 :         return 0;
    2673             : }
    2674             : 
    2675           0 : static int tonga_update_uvd_smc_table(struct pp_hwmgr *hwmgr)
    2676             : {
    2677           0 :         struct tonga_smumgr *smu_data =
    2678             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    2679             :         uint32_t mm_boot_level_offset, mm_boot_level_value;
    2680           0 :         struct phm_ppt_v1_information *table_info =
    2681             :                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
    2682             : 
    2683           0 :         smu_data->smc_state_table.UvdBootLevel = 0;
    2684           0 :         if (table_info->mm_dep_table->count > 0)
    2685           0 :                 smu_data->smc_state_table.UvdBootLevel =
    2686           0 :                                 (uint8_t) (table_info->mm_dep_table->count - 1);
    2687           0 :         mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
    2688             :                                 offsetof(SMU72_Discrete_DpmTable, UvdBootLevel);
    2689           0 :         mm_boot_level_offset /= 4;
    2690           0 :         mm_boot_level_offset *= 4;
    2691           0 :         mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
    2692             :                         CGS_IND_REG__SMC, mm_boot_level_offset);
    2693           0 :         mm_boot_level_value &= 0x00FFFFFF;
    2694           0 :         mm_boot_level_value |= smu_data->smc_state_table.UvdBootLevel << 24;
    2695           0 :         cgs_write_ind_register(hwmgr->device,
    2696             :                                 CGS_IND_REG__SMC,
    2697             :                                 mm_boot_level_offset, mm_boot_level_value);
    2698             : 
    2699           0 :         if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
    2700           0 :                         PHM_PlatformCaps_UVDDPM) ||
    2701           0 :                 phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
    2702             :                         PHM_PlatformCaps_StablePState))
    2703           0 :                 smum_send_msg_to_smc_with_parameter(hwmgr,
    2704             :                                 PPSMC_MSG_UVDDPM_SetEnabledMask,
    2705           0 :                                 (uint32_t)(1 << smu_data->smc_state_table.UvdBootLevel),
    2706             :                                 NULL);
    2707           0 :         return 0;
    2708             : }
    2709             : 
    2710           0 : static int tonga_update_vce_smc_table(struct pp_hwmgr *hwmgr)
    2711             : {
    2712           0 :         struct tonga_smumgr *smu_data =
    2713             :                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
    2714             :         uint32_t mm_boot_level_offset, mm_boot_level_value;
    2715           0 :         struct phm_ppt_v1_information *table_info =
    2716             :                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
    2717             : 
    2718             : 
    2719           0 :         smu_data->smc_state_table.VceBootLevel =
    2720           0 :                 (uint8_t) (table_info->mm_dep_table->count - 1);
    2721             : 
    2722           0 :         mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
    2723             :                                         offsetof(SMU72_Discrete_DpmTable, VceBootLevel);
    2724           0 :         mm_boot_level_offset /= 4;
    2725           0 :         mm_boot_level_offset *= 4;
    2726           0 :         mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
    2727             :                         CGS_IND_REG__SMC, mm_boot_level_offset);
    2728           0 :         mm_boot_level_value &= 0xFF00FFFF;
    2729           0 :         mm_boot_level_value |= smu_data->smc_state_table.VceBootLevel << 16;
    2730           0 :         cgs_write_ind_register(hwmgr->device,
    2731             :                         CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
    2732             : 
    2733           0 :         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
    2734             :                                         PHM_PlatformCaps_StablePState))
    2735           0 :                 smum_send_msg_to_smc_with_parameter(hwmgr,
    2736             :                                 PPSMC_MSG_VCEDPM_SetEnabledMask,
    2737           0 :                                 (uint32_t)1 << smu_data->smc_state_table.VceBootLevel,
    2738             :                                 NULL);
    2739           0 :         return 0;
    2740             : }
    2741             : 
    2742           0 : static int tonga_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type)
    2743             : {
    2744           0 :         switch (type) {
    2745             :         case SMU_UVD_TABLE:
    2746           0 :                 tonga_update_uvd_smc_table(hwmgr);
    2747           0 :                 break;
    2748             :         case SMU_VCE_TABLE:
    2749           0 :                 tonga_update_vce_smc_table(hwmgr);
    2750           0 :                 break;
    2751             :         default:
    2752             :                 break;
    2753             :         }
    2754           0 :         return 0;
    2755             : }
    2756             : 
    2757           0 : static int tonga_process_firmware_header(struct pp_hwmgr *hwmgr)
    2758             : {
    2759           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    2760           0 :         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
    2761             : 
    2762             :         uint32_t tmp;
    2763             :         int result;
    2764           0 :         bool error = false;
    2765             : 
    2766           0 :         result = smu7_read_smc_sram_dword(hwmgr,
    2767             :                                 SMU72_FIRMWARE_HEADER_LOCATION +
    2768             :                                 offsetof(SMU72_Firmware_Header, DpmTable),
    2769             :                                 &tmp, SMC_RAM_END);
    2770             : 
    2771           0 :         if (!result)
    2772           0 :                 smu_data->smu7_data.dpm_table_start = tmp;
    2773             : 
    2774           0 :         error |= (result != 0);
    2775             : 
    2776           0 :         result = smu7_read_smc_sram_dword(hwmgr,
    2777             :                                 SMU72_FIRMWARE_HEADER_LOCATION +
    2778             :                                 offsetof(SMU72_Firmware_Header, SoftRegisters),
    2779             :                                 &tmp, SMC_RAM_END);
    2780             : 
    2781           0 :         if (!result) {
    2782           0 :                 data->soft_regs_start = tmp;
    2783           0 :                 smu_data->smu7_data.soft_regs_start = tmp;
    2784             :         }
    2785             : 
    2786           0 :         error |= (result != 0);
    2787             : 
    2788             : 
    2789           0 :         result = smu7_read_smc_sram_dword(hwmgr,
    2790             :                                 SMU72_FIRMWARE_HEADER_LOCATION +
    2791             :                                 offsetof(SMU72_Firmware_Header, mcRegisterTable),
    2792             :                                 &tmp, SMC_RAM_END);
    2793             : 
    2794           0 :         if (!result)
    2795           0 :                 smu_data->smu7_data.mc_reg_table_start = tmp;
    2796             : 
    2797           0 :         result = smu7_read_smc_sram_dword(hwmgr,
    2798             :                                 SMU72_FIRMWARE_HEADER_LOCATION +
    2799             :                                 offsetof(SMU72_Firmware_Header, FanTable),
    2800             :                                 &tmp, SMC_RAM_END);
    2801             : 
    2802           0 :         if (!result)
    2803           0 :                 smu_data->smu7_data.fan_table_start = tmp;
    2804             : 
    2805           0 :         error |= (result != 0);
    2806             : 
    2807           0 :         result = smu7_read_smc_sram_dword(hwmgr,
    2808             :                                 SMU72_FIRMWARE_HEADER_LOCATION +
    2809             :                                 offsetof(SMU72_Firmware_Header, mcArbDramTimingTable),
    2810             :                                 &tmp, SMC_RAM_END);
    2811             : 
    2812           0 :         if (!result)
    2813           0 :                 smu_data->smu7_data.arb_table_start = tmp;
    2814             : 
    2815           0 :         error |= (result != 0);
    2816             : 
    2817           0 :         result = smu7_read_smc_sram_dword(hwmgr,
    2818             :                                 SMU72_FIRMWARE_HEADER_LOCATION +
    2819             :                                 offsetof(SMU72_Firmware_Header, Version),
    2820             :                                 &tmp, SMC_RAM_END);
    2821             : 
    2822           0 :         if (!result)
    2823           0 :                 hwmgr->microcode_version_info.SMC = tmp;
    2824             : 
    2825           0 :         error |= (result != 0);
    2826             : 
    2827           0 :         return error ? 1 : 0;
    2828             : }
    2829             : 
    2830             : /*---------------------------MC----------------------------*/
    2831             : 
    2832             : static uint8_t tonga_get_memory_modile_index(struct pp_hwmgr *hwmgr)
    2833             : {
    2834           0 :         return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16));
    2835             : }
    2836             : 
    2837           0 : static bool tonga_check_s0_mc_reg_index(uint16_t in_reg, uint16_t *out_reg)
    2838             : {
    2839           0 :         bool result = true;
    2840             : 
    2841           0 :         switch (in_reg) {
    2842             :         case  mmMC_SEQ_RAS_TIMING:
    2843           0 :                 *out_reg = mmMC_SEQ_RAS_TIMING_LP;
    2844           0 :                 break;
    2845             : 
    2846             :         case  mmMC_SEQ_DLL_STBY:
    2847           0 :                 *out_reg = mmMC_SEQ_DLL_STBY_LP;
    2848           0 :                 break;
    2849             : 
    2850             :         case  mmMC_SEQ_G5PDX_CMD0:
    2851           0 :                 *out_reg = mmMC_SEQ_G5PDX_CMD0_LP;
    2852           0 :                 break;
    2853             : 
    2854             :         case  mmMC_SEQ_G5PDX_CMD1:
    2855           0 :                 *out_reg = mmMC_SEQ_G5PDX_CMD1_LP;
    2856           0 :                 break;
    2857             : 
    2858             :         case  mmMC_SEQ_G5PDX_CTRL:
    2859           0 :                 *out_reg = mmMC_SEQ_G5PDX_CTRL_LP;
    2860           0 :                 break;
    2861             : 
    2862             :         case mmMC_SEQ_CAS_TIMING:
    2863           0 :                 *out_reg = mmMC_SEQ_CAS_TIMING_LP;
    2864           0 :                 break;
    2865             : 
    2866             :         case mmMC_SEQ_MISC_TIMING:
    2867           0 :                 *out_reg = mmMC_SEQ_MISC_TIMING_LP;
    2868           0 :                 break;
    2869             : 
    2870             :         case mmMC_SEQ_MISC_TIMING2:
    2871           0 :                 *out_reg = mmMC_SEQ_MISC_TIMING2_LP;
    2872           0 :                 break;
    2873             : 
    2874             :         case mmMC_SEQ_PMG_DVS_CMD:
    2875           0 :                 *out_reg = mmMC_SEQ_PMG_DVS_CMD_LP;
    2876           0 :                 break;
    2877             : 
    2878             :         case mmMC_SEQ_PMG_DVS_CTL:
    2879           0 :                 *out_reg = mmMC_SEQ_PMG_DVS_CTL_LP;
    2880           0 :                 break;
    2881             : 
    2882             :         case mmMC_SEQ_RD_CTL_D0:
    2883           0 :                 *out_reg = mmMC_SEQ_RD_CTL_D0_LP;
    2884           0 :                 break;
    2885             : 
    2886             :         case mmMC_SEQ_RD_CTL_D1:
    2887           0 :                 *out_reg = mmMC_SEQ_RD_CTL_D1_LP;
    2888           0 :                 break;
    2889             : 
    2890             :         case mmMC_SEQ_WR_CTL_D0:
    2891           0 :                 *out_reg = mmMC_SEQ_WR_CTL_D0_LP;
    2892           0 :                 break;
    2893             : 
    2894             :         case mmMC_SEQ_WR_CTL_D1:
    2895           0 :                 *out_reg = mmMC_SEQ_WR_CTL_D1_LP;
    2896           0 :                 break;
    2897             : 
    2898             :         case mmMC_PMG_CMD_EMRS:
    2899           0 :                 *out_reg = mmMC_SEQ_PMG_CMD_EMRS_LP;
    2900           0 :                 break;
    2901             : 
    2902             :         case mmMC_PMG_CMD_MRS:
    2903           0 :                 *out_reg = mmMC_SEQ_PMG_CMD_MRS_LP;
    2904           0 :                 break;
    2905             : 
    2906             :         case mmMC_PMG_CMD_MRS1:
    2907           0 :                 *out_reg = mmMC_SEQ_PMG_CMD_MRS1_LP;
    2908           0 :                 break;
    2909             : 
    2910             :         case mmMC_SEQ_PMG_TIMING:
    2911           0 :                 *out_reg = mmMC_SEQ_PMG_TIMING_LP;
    2912           0 :                 break;
    2913             : 
    2914             :         case mmMC_PMG_CMD_MRS2:
    2915           0 :                 *out_reg = mmMC_SEQ_PMG_CMD_MRS2_LP;
    2916           0 :                 break;
    2917             : 
    2918             :         case mmMC_SEQ_WR_CTL_2:
    2919           0 :                 *out_reg = mmMC_SEQ_WR_CTL_2_LP;
    2920           0 :                 break;
    2921             : 
    2922             :         default:
    2923             :                 result = false;
    2924             :                 break;
    2925             :         }
    2926             : 
    2927           0 :         return result;
    2928             : }
    2929             : 
    2930           0 : static int tonga_set_s0_mc_reg_index(struct tonga_mc_reg_table *table)
    2931             : {
    2932             :         uint32_t i;
    2933             :         uint16_t address;
    2934             : 
    2935           0 :         for (i = 0; i < table->last; i++) {
    2936           0 :                 table->mc_reg_address[i].s0 =
    2937           0 :                         tonga_check_s0_mc_reg_index(table->mc_reg_address[i].s1,
    2938             :                                                         &address) ?
    2939             :                                                         address :
    2940             :                                                  table->mc_reg_address[i].s1;
    2941             :         }
    2942           0 :         return 0;
    2943             : }
    2944             : 
    2945           0 : static int tonga_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table,
    2946             :                                         struct tonga_mc_reg_table *ni_table)
    2947             : {
    2948             :         uint8_t i, j;
    2949             : 
    2950           0 :         PP_ASSERT_WITH_CODE((table->last <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
    2951             :                 "Invalid VramInfo table.", return -EINVAL);
    2952           0 :         PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES),
    2953             :                 "Invalid VramInfo table.", return -EINVAL);
    2954             : 
    2955           0 :         for (i = 0; i < table->last; i++)
    2956           0 :                 ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
    2957             : 
    2958           0 :         ni_table->last = table->last;
    2959             : 
    2960           0 :         for (i = 0; i < table->num_entries; i++) {
    2961           0 :                 ni_table->mc_reg_table_entry[i].mclk_max =
    2962           0 :                         table->mc_reg_table_entry[i].mclk_max;
    2963           0 :                 for (j = 0; j < table->last; j++) {
    2964           0 :                         ni_table->mc_reg_table_entry[i].mc_data[j] =
    2965           0 :                                 table->mc_reg_table_entry[i].mc_data[j];
    2966             :                 }
    2967             :         }
    2968             : 
    2969           0 :         ni_table->num_entries = table->num_entries;
    2970             : 
    2971           0 :         return 0;
    2972             : }
    2973             : 
    2974           0 : static int tonga_set_mc_special_registers(struct pp_hwmgr *hwmgr,
    2975             :                                         struct tonga_mc_reg_table *table)
    2976             : {
    2977             :         uint8_t i, j, k;
    2978             :         uint32_t temp_reg;
    2979           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    2980             : 
    2981           0 :         for (i = 0, j = table->last; i < table->last; i++) {
    2982           0 :                 PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
    2983             :                         "Invalid VramInfo table.", return -EINVAL);
    2984             : 
    2985           0 :                 switch (table->mc_reg_address[i].s1) {
    2986             : 
    2987             :                 case mmMC_SEQ_MISC1:
    2988           0 :                         temp_reg = cgs_read_register(hwmgr->device,
    2989             :                                                         mmMC_PMG_CMD_EMRS);
    2990           0 :                         table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
    2991           0 :                         table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
    2992           0 :                         for (k = 0; k < table->num_entries; k++) {
    2993           0 :                                 table->mc_reg_table_entry[k].mc_data[j] =
    2994           0 :                                         ((temp_reg & 0xffff0000)) |
    2995           0 :                                         ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
    2996             :                         }
    2997           0 :                         j++;
    2998             : 
    2999           0 :                         PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
    3000             :                                 "Invalid VramInfo table.", return -EINVAL);
    3001           0 :                         temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS);
    3002           0 :                         table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
    3003           0 :                         table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
    3004           0 :                         for (k = 0; k < table->num_entries; k++) {
    3005           0 :                                 table->mc_reg_table_entry[k].mc_data[j] =
    3006           0 :                                         (temp_reg & 0xffff0000) |
    3007           0 :                                         (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
    3008             : 
    3009           0 :                                 if (!data->is_memory_gddr5)
    3010           0 :                                         table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
    3011             :                         }
    3012           0 :                         j++;
    3013             : 
    3014           0 :                         if (!data->is_memory_gddr5) {
    3015           0 :                                 PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
    3016             :                                         "Invalid VramInfo table.", return -EINVAL);
    3017           0 :                                 table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
    3018           0 :                                 table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
    3019           0 :                                 for (k = 0; k < table->num_entries; k++)
    3020           0 :                                         table->mc_reg_table_entry[k].mc_data[j] =
    3021           0 :                                                 (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
    3022           0 :                                 j++;
    3023             :                         }
    3024             : 
    3025             :                         break;
    3026             : 
    3027             :                 case mmMC_SEQ_RESERVE_M:
    3028           0 :                         temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1);
    3029           0 :                         table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
    3030           0 :                         table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
    3031           0 :                         for (k = 0; k < table->num_entries; k++) {
    3032           0 :                                 table->mc_reg_table_entry[k].mc_data[j] =
    3033           0 :                                         (temp_reg & 0xffff0000) |
    3034           0 :                                         (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
    3035             :                         }
    3036           0 :                         j++;
    3037             :                         break;
    3038             : 
    3039             :                 default:
    3040             :                         break;
    3041             :                 }
    3042             : 
    3043             :         }
    3044             : 
    3045           0 :         table->last = j;
    3046             : 
    3047             :         return 0;
    3048             : }
    3049             : 
    3050             : static int tonga_set_valid_flag(struct tonga_mc_reg_table *table)
    3051             : {
    3052             :         uint8_t i, j;
    3053             : 
    3054           0 :         for (i = 0; i < table->last; i++) {
    3055           0 :                 for (j = 1; j < table->num_entries; j++) {
    3056           0 :                         if (table->mc_reg_table_entry[j-1].mc_data[i] !=
    3057           0 :                                 table->mc_reg_table_entry[j].mc_data[i]) {
    3058           0 :                                 table->validflag |= (1<<i);
    3059             :                                 break;
    3060             :                         }
    3061             :                 }
    3062             :         }
    3063             : 
    3064             :         return 0;
    3065             : }
    3066             : 
    3067           0 : static int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
    3068             : {
    3069             :         int result;
    3070           0 :         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
    3071             :         pp_atomctrl_mc_reg_table *table;
    3072           0 :         struct tonga_mc_reg_table *ni_table = &smu_data->mc_reg_table;
    3073           0 :         uint8_t module_index = tonga_get_memory_modile_index(hwmgr);
    3074             : 
    3075           0 :         table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
    3076             : 
    3077           0 :         if (table == NULL)
    3078             :                 return -ENOMEM;
    3079             : 
    3080             :         /* Program additional LP registers that are no longer programmed by VBIOS */
    3081           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP,
    3082             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
    3083           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP,
    3084             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
    3085           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP,
    3086             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY));
    3087           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP,
    3088             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0));
    3089           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP,
    3090             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1));
    3091           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP,
    3092             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL));
    3093           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP,
    3094             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD));
    3095           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP,
    3096             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL));
    3097           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP,
    3098             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING));
    3099           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP,
    3100             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
    3101           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP,
    3102             :                         cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS));
    3103           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP,
    3104             :                         cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS));
    3105           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP,
    3106             :                         cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1));
    3107           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP,
    3108             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0));
    3109           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP,
    3110             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
    3111           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP,
    3112             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
    3113           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP,
    3114             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
    3115           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP,
    3116             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
    3117           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP,
    3118             :                         cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
    3119           0 :         cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP,
    3120             :                         cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
    3121             : 
    3122           0 :         result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
    3123             : 
    3124           0 :         if (!result)
    3125           0 :                 result = tonga_copy_vbios_smc_reg_table(table, ni_table);
    3126             : 
    3127           0 :         if (!result) {
    3128           0 :                 tonga_set_s0_mc_reg_index(ni_table);
    3129           0 :                 result = tonga_set_mc_special_registers(hwmgr, ni_table);
    3130             :         }
    3131             : 
    3132           0 :         if (!result)
    3133             :                 tonga_set_valid_flag(ni_table);
    3134             : 
    3135           0 :         kfree(table);
    3136             : 
    3137           0 :         return result;
    3138             : }
    3139             : 
    3140           0 : static bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr)
    3141             : {
    3142           0 :         return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
    3143             :                         CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
    3144           0 :                         ? true : false;
    3145             : }
    3146             : 
    3147           0 : static int tonga_update_dpm_settings(struct pp_hwmgr *hwmgr,
    3148             :                                 void *profile_setting)
    3149             : {
    3150           0 :         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
    3151           0 :         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)
    3152             :                         (hwmgr->smu_backend);
    3153             :         struct profile_mode_setting *setting;
    3154           0 :         struct SMU72_Discrete_GraphicsLevel *levels =
    3155             :                         smu_data->smc_state_table.GraphicsLevel;
    3156           0 :         uint32_t array = smu_data->smu7_data.dpm_table_start +
    3157             :                         offsetof(SMU72_Discrete_DpmTable, GraphicsLevel);
    3158             : 
    3159           0 :         uint32_t mclk_array = smu_data->smu7_data.dpm_table_start +
    3160             :                         offsetof(SMU72_Discrete_DpmTable, MemoryLevel);
    3161           0 :         struct SMU72_Discrete_MemoryLevel *mclk_levels =
    3162             :                         smu_data->smc_state_table.MemoryLevel;
    3163             :         uint32_t i;
    3164             :         uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp;
    3165             : 
    3166           0 :         if (profile_setting == NULL)
    3167             :                 return -EINVAL;
    3168             : 
    3169           0 :         setting = (struct profile_mode_setting *)profile_setting;
    3170             : 
    3171           0 :         if (setting->bupdate_sclk) {
    3172           0 :                 if (!data->sclk_dpm_key_disabled)
    3173           0 :                         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel, NULL);
    3174           0 :                 for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) {
    3175           0 :                         if (levels[i].ActivityLevel !=
    3176           0 :                                 cpu_to_be16(setting->sclk_activity)) {
    3177           0 :                                 levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity);
    3178             : 
    3179           0 :                                 clk_activity_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i)
    3180             :                                                 + offsetof(SMU72_Discrete_GraphicsLevel, ActivityLevel);
    3181           0 :                                 offset = clk_activity_offset & ~0x3;
    3182           0 :                                 tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
    3183           0 :                                 tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t));
    3184           0 :                                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
    3185             : 
    3186             :                         }
    3187           0 :                         if (levels[i].UpHyst != setting->sclk_up_hyst ||
    3188           0 :                                 levels[i].DownHyst != setting->sclk_down_hyst) {
    3189           0 :                                 levels[i].UpHyst = setting->sclk_up_hyst;
    3190           0 :                                 levels[i].DownHyst = setting->sclk_down_hyst;
    3191           0 :                                 up_hyst_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i)
    3192             :                                                 + offsetof(SMU72_Discrete_GraphicsLevel, UpHyst);
    3193           0 :                                 down_hyst_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i)
    3194             :                                                 + offsetof(SMU72_Discrete_GraphicsLevel, DownHyst);
    3195           0 :                                 offset = up_hyst_offset & ~0x3;
    3196           0 :                                 tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
    3197           0 :                                 tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpHyst, sizeof(uint8_t));
    3198           0 :                                 tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownHyst, sizeof(uint8_t));
    3199           0 :                                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
    3200             :                         }
    3201             :                 }
    3202           0 :                 if (!data->sclk_dpm_key_disabled)
    3203           0 :                         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel, NULL);
    3204             :         }
    3205             : 
    3206           0 :         if (setting->bupdate_mclk) {
    3207           0 :                 if (!data->mclk_dpm_key_disabled)
    3208           0 :                         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel, NULL);
    3209           0 :                 for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) {
    3210           0 :                         if (mclk_levels[i].ActivityLevel !=
    3211           0 :                                 cpu_to_be16(setting->mclk_activity)) {
    3212           0 :                                 mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity);
    3213             : 
    3214           0 :                                 clk_activity_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i)
    3215             :                                                 + offsetof(SMU72_Discrete_MemoryLevel, ActivityLevel);
    3216           0 :                                 offset = clk_activity_offset & ~0x3;
    3217           0 :                                 tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
    3218           0 :                                 tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t));
    3219           0 :                                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
    3220             : 
    3221             :                         }
    3222           0 :                         if (mclk_levels[i].UpHyst != setting->mclk_up_hyst ||
    3223           0 :                                 mclk_levels[i].DownHyst != setting->mclk_down_hyst) {
    3224           0 :                                 mclk_levels[i].UpHyst = setting->mclk_up_hyst;
    3225           0 :                                 mclk_levels[i].DownHyst = setting->mclk_down_hyst;
    3226           0 :                                 up_hyst_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i)
    3227             :                                                 + offsetof(SMU72_Discrete_MemoryLevel, UpHyst);
    3228           0 :                                 down_hyst_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i)
    3229             :                                                 + offsetof(SMU72_Discrete_MemoryLevel, DownHyst);
    3230           0 :                                 offset = up_hyst_offset & ~0x3;
    3231           0 :                                 tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
    3232           0 :                                 tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpHyst, sizeof(uint8_t));
    3233           0 :                                 tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownHyst, sizeof(uint8_t));
    3234           0 :                                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
    3235             :                         }
    3236             :                 }
    3237           0 :                 if (!data->mclk_dpm_key_disabled)
    3238           0 :                         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel, NULL);
    3239             :         }
    3240             :         return 0;
    3241             : }
    3242             : 
    3243             : const struct pp_smumgr_func tonga_smu_funcs = {
    3244             :         .name = "tonga_smu",
    3245             :         .smu_init = &tonga_smu_init,
    3246             :         .smu_fini = &smu7_smu_fini,
    3247             :         .start_smu = &tonga_start_smu,
    3248             :         .check_fw_load_finish = &smu7_check_fw_load_finish,
    3249             :         .request_smu_load_fw = &smu7_request_smu_load_fw,
    3250             :         .request_smu_load_specific_fw = NULL,
    3251             :         .send_msg_to_smc = &smu7_send_msg_to_smc,
    3252             :         .send_msg_to_smc_with_parameter = &smu7_send_msg_to_smc_with_parameter,
    3253             :         .get_argument = smu7_get_argument,
    3254             :         .download_pptable_settings = NULL,
    3255             :         .upload_pptable_settings = NULL,
    3256             :         .update_smc_table = tonga_update_smc_table,
    3257             :         .get_offsetof = tonga_get_offsetof,
    3258             :         .process_firmware_header = tonga_process_firmware_header,
    3259             :         .init_smc_table = tonga_init_smc_table,
    3260             :         .update_sclk_threshold = tonga_update_sclk_threshold,
    3261             :         .thermal_setup_fan_table = tonga_thermal_setup_fan_table,
    3262             :         .populate_all_graphic_levels = tonga_populate_all_graphic_levels,
    3263             :         .populate_all_memory_levels = tonga_populate_all_memory_levels,
    3264             :         .get_mac_definition = tonga_get_mac_definition,
    3265             :         .initialize_mc_reg_table = tonga_initialize_mc_reg_table,
    3266             :         .is_dpm_running = tonga_is_dpm_running,
    3267             :         .update_dpm_settings = tonga_update_dpm_settings,
    3268             : };

Generated by: LCOV version 1.14