19f4b3541SRex Zhu /*
29f4b3541SRex Zhu * Copyright 2017 Advanced Micro Devices, Inc.
39f4b3541SRex Zhu *
49f4b3541SRex Zhu * Permission is hereby granted, free of charge, to any person obtaining a
59f4b3541SRex Zhu * copy of this software and associated documentation files (the "Software"),
69f4b3541SRex Zhu * to deal in the Software without restriction, including without limitation
79f4b3541SRex Zhu * the rights to use, copy, modify, merge, publish, distribute, sublicense,
89f4b3541SRex Zhu * and/or sell copies of the Software, and to permit persons to whom the
99f4b3541SRex Zhu * Software is furnished to do so, subject to the following conditions:
109f4b3541SRex Zhu *
119f4b3541SRex Zhu * The above copyright notice and this permission notice shall be included in
129f4b3541SRex Zhu * all copies or substantial portions of the Software.
139f4b3541SRex Zhu *
149f4b3541SRex Zhu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
159f4b3541SRex Zhu * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
169f4b3541SRex Zhu * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
179f4b3541SRex Zhu * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
189f4b3541SRex Zhu * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
199f4b3541SRex Zhu * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
209f4b3541SRex Zhu * OTHER DEALINGS IN THE SOFTWARE.
219f4b3541SRex Zhu *
229f4b3541SRex Zhu */
239f4b3541SRex Zhu #include <linux/module.h>
249f4b3541SRex Zhu #include <linux/slab.h>
259f4b3541SRex Zhu #include "linux/delay.h"
269f4b3541SRex Zhu #include <linux/types.h>
27f867723bSSam Ravnborg #include <linux/pci.h>
289f4b3541SRex Zhu
299f4b3541SRex Zhu #include "smumgr.h"
309f4b3541SRex Zhu #include "pp_debug.h"
319f4b3541SRex Zhu #include "ci_smumgr.h"
329f4b3541SRex Zhu #include "ppsmc.h"
339f4b3541SRex Zhu #include "smu7_hwmgr.h"
349f4b3541SRex Zhu #include "hardwaremanager.h"
359f4b3541SRex Zhu #include "ppatomctrl.h"
369f4b3541SRex Zhu #include "cgs_common.h"
379f4b3541SRex Zhu #include "atombios.h"
389f4b3541SRex Zhu #include "pppcielanes.h"
39177e38a4SSandeep Raghuraman #include "smu7_smumgr.h"
409f4b3541SRex Zhu
419f4b3541SRex Zhu #include "smu/smu_7_0_1_d.h"
429f4b3541SRex Zhu #include "smu/smu_7_0_1_sh_mask.h"
439f4b3541SRex Zhu
449f4b3541SRex Zhu #include "dce/dce_8_0_d.h"
459f4b3541SRex Zhu #include "dce/dce_8_0_sh_mask.h"
469f4b3541SRex Zhu
479f4b3541SRex Zhu #include "bif/bif_4_1_d.h"
489f4b3541SRex Zhu #include "bif/bif_4_1_sh_mask.h"
499f4b3541SRex Zhu
509f4b3541SRex Zhu #include "gca/gfx_7_2_d.h"
519f4b3541SRex Zhu #include "gca/gfx_7_2_sh_mask.h"
529f4b3541SRex Zhu
539f4b3541SRex Zhu #include "gmc/gmc_7_1_d.h"
549f4b3541SRex Zhu #include "gmc/gmc_7_1_sh_mask.h"
559f4b3541SRex Zhu
569f4b3541SRex Zhu #include "processpptables.h"
579f4b3541SRex Zhu
589f4b3541SRex Zhu #define MC_CG_ARB_FREQ_F0 0x0a
599f4b3541SRex Zhu #define MC_CG_ARB_FREQ_F1 0x0b
609f4b3541SRex Zhu #define MC_CG_ARB_FREQ_F2 0x0c
619f4b3541SRex Zhu #define MC_CG_ARB_FREQ_F3 0x0d
629f4b3541SRex Zhu
639f4b3541SRex Zhu #define SMC_RAM_END 0x40000
649f4b3541SRex Zhu
659f4b3541SRex Zhu #define CISLAND_MINIMUM_ENGINE_CLOCK 800
669f4b3541SRex Zhu #define CISLAND_MAX_DEEPSLEEP_DIVIDER_ID 5
679f4b3541SRex Zhu
689f4b3541SRex Zhu static const struct ci_pt_defaults defaults_hawaii_xt = {
699f4b3541SRex Zhu 1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000,
709f4b3541SRex Zhu { 0x2E, 0x00, 0x00, 0x88, 0x00, 0x00, 0x72, 0x60, 0x51, 0xA7, 0x79, 0x6B, 0x90, 0xBD, 0x79 },
719f4b3541SRex Zhu { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
729f4b3541SRex Zhu };
739f4b3541SRex Zhu
749f4b3541SRex Zhu static const struct ci_pt_defaults defaults_hawaii_pro = {
759f4b3541SRex Zhu 1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0x65062,
769f4b3541SRex Zhu { 0x2E, 0x00, 0x00, 0x88, 0x00, 0x00, 0x72, 0x60, 0x51, 0xA7, 0x79, 0x6B, 0x90, 0xBD, 0x79 },
779f4b3541SRex Zhu { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
789f4b3541SRex Zhu };
799f4b3541SRex Zhu
809f4b3541SRex Zhu static const struct ci_pt_defaults defaults_bonaire_xt = {
819f4b3541SRex Zhu 1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
829f4b3541SRex Zhu { 0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61 },
839f4b3541SRex Zhu { 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 }
849f4b3541SRex Zhu };
859f4b3541SRex Zhu
869f4b3541SRex Zhu
879f4b3541SRex Zhu static const struct ci_pt_defaults defaults_saturn_xt = {
889f4b3541SRex Zhu 1, 0xF, 0xFD, 0x19, 5, 55, 0, 0x70000,
899f4b3541SRex Zhu { 0x8C, 0x247, 0x249, 0xA6, 0x80, 0x81, 0x8B, 0x89, 0x86, 0xC9, 0xCA, 0xC9, 0x4D, 0x4D, 0x4D },
909f4b3541SRex Zhu { 0x187, 0x187, 0x187, 0x1C7, 0x1C7, 0x1C7, 0x210, 0x210, 0x210, 0x266, 0x266, 0x266, 0x2C9, 0x2C9, 0x2C9 }
919f4b3541SRex Zhu };
929f4b3541SRex Zhu
939f4b3541SRex Zhu
ci_set_smc_sram_address(struct pp_hwmgr * hwmgr,uint32_t smc_addr,uint32_t limit)94d3f8c0abSRex Zhu static int ci_set_smc_sram_address(struct pp_hwmgr *hwmgr,
959f4b3541SRex Zhu uint32_t smc_addr, uint32_t limit)
969f4b3541SRex Zhu {
979f4b3541SRex Zhu if ((0 != (3 & smc_addr))
989f4b3541SRex Zhu || ((smc_addr + 3) >= limit)) {
999f4b3541SRex Zhu pr_err("smc_addr invalid \n");
1009f4b3541SRex Zhu return -EINVAL;
1019f4b3541SRex Zhu }
1029f4b3541SRex Zhu
103d3f8c0abSRex Zhu cgs_write_register(hwmgr->device, mmSMC_IND_INDEX_0, smc_addr);
104a9eca3a6SRex Zhu PHM_WRITE_FIELD(hwmgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
1059f4b3541SRex Zhu return 0;
1069f4b3541SRex Zhu }
1079f4b3541SRex Zhu
ci_copy_bytes_to_smc(struct pp_hwmgr * hwmgr,uint32_t smc_start_address,const uint8_t * src,uint32_t byte_count,uint32_t limit)108d3f8c0abSRex Zhu static int ci_copy_bytes_to_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address,
1099f4b3541SRex Zhu const uint8_t *src, uint32_t byte_count, uint32_t limit)
1109f4b3541SRex Zhu {
1119f4b3541SRex Zhu int result;
1129f4b3541SRex Zhu uint32_t data = 0;
1139f4b3541SRex Zhu uint32_t original_data;
1149f4b3541SRex Zhu uint32_t addr = 0;
1159f4b3541SRex Zhu uint32_t extra_shift;
1169f4b3541SRex Zhu
1179f4b3541SRex Zhu if ((3 & smc_start_address)
1189f4b3541SRex Zhu || ((smc_start_address + byte_count) >= limit)) {
1199f4b3541SRex Zhu pr_err("smc_start_address invalid \n");
1209f4b3541SRex Zhu return -EINVAL;
1219f4b3541SRex Zhu }
1229f4b3541SRex Zhu
1239f4b3541SRex Zhu addr = smc_start_address;
1249f4b3541SRex Zhu
1259f4b3541SRex Zhu while (byte_count >= 4) {
1269f4b3541SRex Zhu /* Bytes are written into the SMC address space with the MSB first. */
1279f4b3541SRex Zhu data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
1289f4b3541SRex Zhu
129d3f8c0abSRex Zhu result = ci_set_smc_sram_address(hwmgr, addr, limit);
1309f4b3541SRex Zhu
1319f4b3541SRex Zhu if (0 != result)
1329f4b3541SRex Zhu return result;
1339f4b3541SRex Zhu
134d3f8c0abSRex Zhu cgs_write_register(hwmgr->device, mmSMC_IND_DATA_0, data);
1359f4b3541SRex Zhu
1369f4b3541SRex Zhu src += 4;
1379f4b3541SRex Zhu byte_count -= 4;
1389f4b3541SRex Zhu addr += 4;
1399f4b3541SRex Zhu }
1409f4b3541SRex Zhu
1419f4b3541SRex Zhu if (0 != byte_count) {
1429f4b3541SRex Zhu
1439f4b3541SRex Zhu data = 0;
1449f4b3541SRex Zhu
145d3f8c0abSRex Zhu result = ci_set_smc_sram_address(hwmgr, addr, limit);
1469f4b3541SRex Zhu
1479f4b3541SRex Zhu if (0 != result)
1489f4b3541SRex Zhu return result;
1499f4b3541SRex Zhu
1509f4b3541SRex Zhu
151d3f8c0abSRex Zhu original_data = cgs_read_register(hwmgr->device, mmSMC_IND_DATA_0);
1529f4b3541SRex Zhu
1539f4b3541SRex Zhu extra_shift = 8 * (4 - byte_count);
1549f4b3541SRex Zhu
1559f4b3541SRex Zhu while (byte_count > 0) {
1569f4b3541SRex Zhu /* Bytes are written into the SMC addres space with the MSB first. */
1579f4b3541SRex Zhu data = (0x100 * data) + *src++;
1589f4b3541SRex Zhu byte_count--;
1599f4b3541SRex Zhu }
1609f4b3541SRex Zhu
1619f4b3541SRex Zhu data <<= extra_shift;
1629f4b3541SRex Zhu
1639f4b3541SRex Zhu data |= (original_data & ~((~0UL) << extra_shift));
1649f4b3541SRex Zhu
165d3f8c0abSRex Zhu result = ci_set_smc_sram_address(hwmgr, addr, limit);
1669f4b3541SRex Zhu
1679f4b3541SRex Zhu if (0 != result)
1689f4b3541SRex Zhu return result;
1699f4b3541SRex Zhu
170d3f8c0abSRex Zhu cgs_write_register(hwmgr->device, mmSMC_IND_DATA_0, data);
1719f4b3541SRex Zhu }
1729f4b3541SRex Zhu
1739f4b3541SRex Zhu return 0;
1749f4b3541SRex Zhu }
1759f4b3541SRex Zhu
1769f4b3541SRex Zhu
ci_program_jump_on_start(struct pp_hwmgr * hwmgr)177d3f8c0abSRex Zhu static int ci_program_jump_on_start(struct pp_hwmgr *hwmgr)
1789f4b3541SRex Zhu {
1799f4b3541SRex Zhu static const unsigned char data[4] = { 0xE0, 0x00, 0x80, 0x40 };
1809f4b3541SRex Zhu
181d3f8c0abSRex Zhu ci_copy_bytes_to_smc(hwmgr, 0x0, data, 4, sizeof(data)+1);
1829f4b3541SRex Zhu
1839f4b3541SRex Zhu return 0;
1849f4b3541SRex Zhu }
1859f4b3541SRex Zhu
ci_is_smc_ram_running(struct pp_hwmgr * hwmgr)18638ed7b09SNirmoy Das static bool ci_is_smc_ram_running(struct pp_hwmgr *hwmgr)
1879f4b3541SRex Zhu {
188f0f6e375SRex Zhu return ((0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
1899f4b3541SRex Zhu CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
190d3f8c0abSRex Zhu && (0x20100 <= cgs_read_ind_register(hwmgr->device,
1919f4b3541SRex Zhu CGS_IND_REG__SMC, ixSMC_PC_C)));
1929f4b3541SRex Zhu }
1939f4b3541SRex Zhu
ci_read_smc_sram_dword(struct pp_hwmgr * hwmgr,uint32_t smc_addr,uint32_t * value,uint32_t limit)194d3f8c0abSRex Zhu static int ci_read_smc_sram_dword(struct pp_hwmgr *hwmgr, uint32_t smc_addr,
1959f4b3541SRex Zhu uint32_t *value, uint32_t limit)
1969f4b3541SRex Zhu {
1979f4b3541SRex Zhu int result;
1989f4b3541SRex Zhu
199d3f8c0abSRex Zhu result = ci_set_smc_sram_address(hwmgr, smc_addr, limit);
2009f4b3541SRex Zhu
2019f4b3541SRex Zhu if (result)
2029f4b3541SRex Zhu return result;
2039f4b3541SRex Zhu
204d3f8c0abSRex Zhu *value = cgs_read_register(hwmgr->device, mmSMC_IND_DATA_0);
2059f4b3541SRex Zhu return 0;
2069f4b3541SRex Zhu }
2079f4b3541SRex Zhu
ci_send_msg_to_smc(struct pp_hwmgr * hwmgr,uint16_t msg)20819048dc6SDave Airlie static int ci_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg)
2099f4b3541SRex Zhu {
210a685572cSGuchun Chen struct amdgpu_device *adev = hwmgr->adev;
2119f4b3541SRex Zhu int ret;
2129f4b3541SRex Zhu
2138db42a70SRex Zhu cgs_write_register(hwmgr->device, mmSMC_RESP_0, 0);
214d3f8c0abSRex Zhu cgs_write_register(hwmgr->device, mmSMC_MESSAGE_0, msg);
2159f4b3541SRex Zhu
216538fdf1fSRex Zhu PHM_WAIT_FIELD_UNEQUAL(hwmgr, SMC_RESP_0, SMC_RESP, 0);
2179f4b3541SRex Zhu
218515113f5SRex Zhu ret = PHM_READ_FIELD(hwmgr->device, SMC_RESP_0, SMC_RESP);
2199f4b3541SRex Zhu
2209f4b3541SRex Zhu if (ret != 1)
221a685572cSGuchun Chen dev_info(adev->dev,
222a685572cSGuchun Chen "failed to send message %x ret is %d\n", msg,ret);
2239f4b3541SRex Zhu
2249f4b3541SRex Zhu return 0;
2259f4b3541SRex Zhu }
2269f4b3541SRex Zhu
ci_send_msg_to_smc_with_parameter(struct pp_hwmgr * hwmgr,uint16_t msg,uint32_t parameter)22719048dc6SDave Airlie static int ci_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr,
2289f4b3541SRex Zhu uint16_t msg, uint32_t parameter)
2299f4b3541SRex Zhu {
230d3f8c0abSRex Zhu cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, parameter);
231d3f8c0abSRex Zhu return ci_send_msg_to_smc(hwmgr, msg);
2329f4b3541SRex Zhu }
2339f4b3541SRex Zhu
ci_initialize_power_tune_defaults(struct pp_hwmgr * hwmgr)2349f4b3541SRex Zhu static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
2359f4b3541SRex Zhu {
236b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
237ada6770eSRex Zhu struct amdgpu_device *adev = hwmgr->adev;
2389f4b3541SRex Zhu uint32_t dev_id;
2399f4b3541SRex Zhu
240ada6770eSRex Zhu dev_id = adev->pdev->device;
2419f4b3541SRex Zhu
2429f4b3541SRex Zhu switch (dev_id) {
2439f4b3541SRex Zhu case 0x67BA:
2445a84ae87SSandeep Raghuraman case 0x67B1:
2459f4b3541SRex Zhu smu_data->power_tune_defaults = &defaults_hawaii_pro;
2469f4b3541SRex Zhu break;
2479f4b3541SRex Zhu case 0x67B8:
2489f4b3541SRex Zhu case 0x66B0:
2499f4b3541SRex Zhu smu_data->power_tune_defaults = &defaults_hawaii_xt;
2509f4b3541SRex Zhu break;
2519f4b3541SRex Zhu case 0x6640:
2529f4b3541SRex Zhu case 0x6641:
2539f4b3541SRex Zhu case 0x6646:
2549f4b3541SRex Zhu case 0x6647:
2559f4b3541SRex Zhu smu_data->power_tune_defaults = &defaults_saturn_xt;
2569f4b3541SRex Zhu break;
2579f4b3541SRex Zhu case 0x6649:
2589f4b3541SRex Zhu case 0x6650:
2599f4b3541SRex Zhu case 0x6651:
2609f4b3541SRex Zhu case 0x6658:
2619f4b3541SRex Zhu case 0x665C:
2629f4b3541SRex Zhu case 0x665D:
2639f4b3541SRex Zhu case 0x67A0:
2649f4b3541SRex Zhu case 0x67A1:
2659f4b3541SRex Zhu case 0x67A2:
2669f4b3541SRex Zhu case 0x67A8:
2679f4b3541SRex Zhu case 0x67A9:
2689f4b3541SRex Zhu case 0x67AA:
2699f4b3541SRex Zhu case 0x67B9:
2709f4b3541SRex Zhu case 0x67BE:
2719f4b3541SRex Zhu default:
2729f4b3541SRex Zhu smu_data->power_tune_defaults = &defaults_bonaire_xt;
2739f4b3541SRex Zhu break;
2749f4b3541SRex Zhu }
2759f4b3541SRex Zhu }
2769f4b3541SRex Zhu
ci_get_dependency_volt_by_clk(struct pp_hwmgr * hwmgr,struct phm_clock_voltage_dependency_table * allowed_clock_voltage_table,uint32_t clock,uint32_t * vol)2779f4b3541SRex Zhu static int ci_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
2789f4b3541SRex Zhu struct phm_clock_voltage_dependency_table *allowed_clock_voltage_table,
2799f4b3541SRex Zhu uint32_t clock, uint32_t *vol)
2809f4b3541SRex Zhu {
2819f4b3541SRex Zhu uint32_t i = 0;
2829f4b3541SRex Zhu
2839f4b3541SRex Zhu if (allowed_clock_voltage_table->count == 0)
2849f4b3541SRex Zhu return -EINVAL;
2859f4b3541SRex Zhu
2869f4b3541SRex Zhu for (i = 0; i < allowed_clock_voltage_table->count; i++) {
2879f4b3541SRex Zhu if (allowed_clock_voltage_table->entries[i].clk >= clock) {
2889f4b3541SRex Zhu *vol = allowed_clock_voltage_table->entries[i].v;
2899f4b3541SRex Zhu return 0;
2909f4b3541SRex Zhu }
2919f4b3541SRex Zhu }
2929f4b3541SRex Zhu
2939f4b3541SRex Zhu *vol = allowed_clock_voltage_table->entries[i - 1].v;
2949f4b3541SRex Zhu return 0;
2959f4b3541SRex Zhu }
2969f4b3541SRex Zhu
ci_calculate_sclk_params(struct pp_hwmgr * hwmgr,uint32_t clock,struct SMU7_Discrete_GraphicsLevel * sclk)2979f4b3541SRex Zhu static int ci_calculate_sclk_params(struct pp_hwmgr *hwmgr,
2989f4b3541SRex Zhu uint32_t clock, struct SMU7_Discrete_GraphicsLevel *sclk)
2999f4b3541SRex Zhu {
3009f4b3541SRex Zhu const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3019f4b3541SRex Zhu struct pp_atomctrl_clock_dividers_vi dividers;
3029f4b3541SRex Zhu uint32_t spll_func_cntl = data->clock_registers.vCG_SPLL_FUNC_CNTL;
3039f4b3541SRex Zhu uint32_t spll_func_cntl_3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
3049f4b3541SRex Zhu uint32_t spll_func_cntl_4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
3059f4b3541SRex Zhu uint32_t cg_spll_spread_spectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
3069f4b3541SRex Zhu uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
3079f4b3541SRex Zhu uint32_t ref_clock;
3089f4b3541SRex Zhu uint32_t ref_divider;
3099f4b3541SRex Zhu uint32_t fbdiv;
3109f4b3541SRex Zhu int result;
3119f4b3541SRex Zhu
3129f4b3541SRex Zhu /* get the engine clock dividers for this clock value */
3139f4b3541SRex Zhu result = atomctrl_get_engine_pll_dividers_vi(hwmgr, clock, ÷rs);
3149f4b3541SRex Zhu
3159f4b3541SRex Zhu PP_ASSERT_WITH_CODE(result == 0,
3169f4b3541SRex Zhu "Error retrieving Engine Clock dividers from VBIOS.",
3179f4b3541SRex Zhu return result);
3189f4b3541SRex Zhu
3199f4b3541SRex Zhu /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
3209f4b3541SRex Zhu ref_clock = atomctrl_get_reference_clock(hwmgr);
3219f4b3541SRex Zhu ref_divider = 1 + dividers.uc_pll_ref_div;
3229f4b3541SRex Zhu
3239f4b3541SRex Zhu /* low 14 bits is fraction and high 12 bits is divider */
3249f4b3541SRex Zhu fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
3259f4b3541SRex Zhu
3269f4b3541SRex Zhu /* SPLL_FUNC_CNTL setup */
3279f4b3541SRex Zhu spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
3289f4b3541SRex Zhu SPLL_REF_DIV, dividers.uc_pll_ref_div);
3299f4b3541SRex Zhu spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
3309f4b3541SRex Zhu SPLL_PDIV_A, dividers.uc_pll_post_div);
3319f4b3541SRex Zhu
3329f4b3541SRex Zhu /* SPLL_FUNC_CNTL_3 setup*/
3339f4b3541SRex Zhu spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
3349f4b3541SRex Zhu SPLL_FB_DIV, fbdiv);
3359f4b3541SRex Zhu
3369f4b3541SRex Zhu /* set to use fractional accumulation*/
3379f4b3541SRex Zhu spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
3389f4b3541SRex Zhu SPLL_DITHEN, 1);
3399f4b3541SRex Zhu
3409f4b3541SRex Zhu if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3419f4b3541SRex Zhu PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
3429f4b3541SRex Zhu struct pp_atomctrl_internal_ss_info ss_info;
3439f4b3541SRex Zhu uint32_t vco_freq = clock * dividers.uc_pll_post_div;
3449f4b3541SRex Zhu
3459f4b3541SRex Zhu if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr,
3469f4b3541SRex Zhu vco_freq, &ss_info)) {
3479f4b3541SRex Zhu uint32_t clk_s = ref_clock * 5 /
3489f4b3541SRex Zhu (ref_divider * ss_info.speed_spectrum_rate);
3499f4b3541SRex Zhu uint32_t clk_v = 4 * ss_info.speed_spectrum_percentage *
3509f4b3541SRex Zhu fbdiv / (clk_s * 10000);
3519f4b3541SRex Zhu
3529f4b3541SRex Zhu cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
3539f4b3541SRex Zhu CG_SPLL_SPREAD_SPECTRUM, CLKS, clk_s);
3549f4b3541SRex Zhu cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
3559f4b3541SRex Zhu CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
3569f4b3541SRex Zhu cg_spll_spread_spectrum_2 = PHM_SET_FIELD(cg_spll_spread_spectrum_2,
3579f4b3541SRex Zhu CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clk_v);
3589f4b3541SRex Zhu }
3599f4b3541SRex Zhu }
3609f4b3541SRex Zhu
3619f4b3541SRex Zhu sclk->SclkFrequency = clock;
3629f4b3541SRex Zhu sclk->CgSpllFuncCntl3 = spll_func_cntl_3;
3639f4b3541SRex Zhu sclk->CgSpllFuncCntl4 = spll_func_cntl_4;
3649f4b3541SRex Zhu sclk->SpllSpreadSpectrum = cg_spll_spread_spectrum;
3659f4b3541SRex Zhu sclk->SpllSpreadSpectrum2 = cg_spll_spread_spectrum_2;
3669f4b3541SRex Zhu sclk->SclkDid = (uint8_t)dividers.pll_post_divider;
3679f4b3541SRex Zhu
3689f4b3541SRex Zhu return 0;
3699f4b3541SRex Zhu }
3709f4b3541SRex Zhu
ci_populate_phase_value_based_on_sclk(struct pp_hwmgr * hwmgr,const struct phm_phase_shedding_limits_table * pl,uint32_t sclk,uint32_t * p_shed)3719f4b3541SRex Zhu static void ci_populate_phase_value_based_on_sclk(struct pp_hwmgr *hwmgr,
3729f4b3541SRex Zhu const struct phm_phase_shedding_limits_table *pl,
3739f4b3541SRex Zhu uint32_t sclk, uint32_t *p_shed)
3749f4b3541SRex Zhu {
3759f4b3541SRex Zhu unsigned int i;
3769f4b3541SRex Zhu
3779f4b3541SRex Zhu /* use the minimum phase shedding */
3789f4b3541SRex Zhu *p_shed = 1;
3799f4b3541SRex Zhu
3809f4b3541SRex Zhu for (i = 0; i < pl->count; i++) {
3819f4b3541SRex Zhu if (sclk < pl->entries[i].Sclk) {
3829f4b3541SRex Zhu *p_shed = i;
3839f4b3541SRex Zhu break;
3849f4b3541SRex Zhu }
3859f4b3541SRex Zhu }
3869f4b3541SRex Zhu }
3879f4b3541SRex Zhu
ci_get_sleep_divider_id_from_clock(uint32_t clock,uint32_t clock_insr)3889f4b3541SRex Zhu static uint8_t ci_get_sleep_divider_id_from_clock(uint32_t clock,
3899f4b3541SRex Zhu uint32_t clock_insr)
3909f4b3541SRex Zhu {
3919f4b3541SRex Zhu uint8_t i;
3929f4b3541SRex Zhu uint32_t temp;
3939f4b3541SRex Zhu uint32_t min = min_t(uint32_t, clock_insr, CISLAND_MINIMUM_ENGINE_CLOCK);
3949f4b3541SRex Zhu
3959f4b3541SRex Zhu if (clock < min) {
3969f4b3541SRex Zhu pr_info("Engine clock can't satisfy stutter requirement!\n");
3979f4b3541SRex Zhu return 0;
3989f4b3541SRex Zhu }
3999f4b3541SRex Zhu for (i = CISLAND_MAX_DEEPSLEEP_DIVIDER_ID; ; i--) {
4009f4b3541SRex Zhu temp = clock >> i;
4019f4b3541SRex Zhu
4029f4b3541SRex Zhu if (temp >= min || i == 0)
4039f4b3541SRex Zhu break;
4049f4b3541SRex Zhu }
4059f4b3541SRex Zhu return i;
4069f4b3541SRex Zhu }
4079f4b3541SRex Zhu
ci_populate_single_graphic_level(struct pp_hwmgr * hwmgr,uint32_t clock,struct SMU7_Discrete_GraphicsLevel * level)4089f4b3541SRex Zhu static int ci_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
409c1f2fb6bSRex Zhu uint32_t clock, struct SMU7_Discrete_GraphicsLevel *level)
4109f4b3541SRex Zhu {
4119f4b3541SRex Zhu int result;
4129f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
4139f4b3541SRex Zhu
4149f4b3541SRex Zhu
4159f4b3541SRex Zhu result = ci_calculate_sclk_params(hwmgr, clock, level);
4169f4b3541SRex Zhu
4179f4b3541SRex Zhu /* populate graphics levels */
4189f4b3541SRex Zhu result = ci_get_dependency_volt_by_clk(hwmgr,
4199f4b3541SRex Zhu hwmgr->dyn_state.vddc_dependency_on_sclk, clock,
4209f4b3541SRex Zhu (uint32_t *)(&level->MinVddc));
4219f4b3541SRex Zhu if (result) {
4229f4b3541SRex Zhu pr_err("vdd_dep_on_sclk table is NULL\n");
4239f4b3541SRex Zhu return result;
4249f4b3541SRex Zhu }
4259f4b3541SRex Zhu
4269f4b3541SRex Zhu level->SclkFrequency = clock;
4279f4b3541SRex Zhu level->MinVddcPhases = 1;
4289f4b3541SRex Zhu
4299f4b3541SRex Zhu if (data->vddc_phase_shed_control)
4309f4b3541SRex Zhu ci_populate_phase_value_based_on_sclk(hwmgr,
4319f4b3541SRex Zhu hwmgr->dyn_state.vddc_phase_shed_limits_table,
4329f4b3541SRex Zhu clock,
4339f4b3541SRex Zhu &level->MinVddcPhases);
4349f4b3541SRex Zhu
435c1f2fb6bSRex Zhu level->ActivityLevel = data->current_profile_setting.sclk_activity;
4369f4b3541SRex Zhu level->CcPwrDynRm = 0;
4379f4b3541SRex Zhu level->CcPwrDynRm1 = 0;
4389f4b3541SRex Zhu level->EnabledForActivity = 0;
4399f4b3541SRex Zhu /* this level can be used for throttling.*/
4409f4b3541SRex Zhu level->EnabledForThrottle = 1;
441c7429b3aSRex Zhu level->UpH = data->current_profile_setting.sclk_up_hyst;
442c7429b3aSRex Zhu level->DownH = data->current_profile_setting.sclk_down_hyst;
4439f4b3541SRex Zhu level->VoltageDownH = 0;
4449f4b3541SRex Zhu level->PowerThrottle = 0;
4459f4b3541SRex Zhu
4469f4b3541SRex Zhu
4479f4b3541SRex Zhu if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4489f4b3541SRex Zhu PHM_PlatformCaps_SclkDeepSleep))
4499f4b3541SRex Zhu level->DeepSleepDivId =
4509f4b3541SRex Zhu ci_get_sleep_divider_id_from_clock(clock,
4519f4b3541SRex Zhu CISLAND_MINIMUM_ENGINE_CLOCK);
4529f4b3541SRex Zhu
4539f4b3541SRex Zhu /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
4549f4b3541SRex Zhu level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
4559f4b3541SRex Zhu
4569f4b3541SRex Zhu if (0 == result) {
4579f4b3541SRex Zhu level->MinVddc = PP_HOST_TO_SMC_UL(level->MinVddc * VOLTAGE_SCALE);
4589f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(level->MinVddcPhases);
4599f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(level->SclkFrequency);
4609f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel);
4619f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl3);
4629f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl4);
4639f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum);
4649f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum2);
4659f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm);
4669f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1);
4679f4b3541SRex Zhu }
4689f4b3541SRex Zhu
4699f4b3541SRex Zhu return result;
4709f4b3541SRex Zhu }
4719f4b3541SRex Zhu
ci_populate_all_graphic_levels(struct pp_hwmgr * hwmgr)47219048dc6SDave Airlie static int ci_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
4739f4b3541SRex Zhu {
4749f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
475b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
4769f4b3541SRex Zhu struct smu7_dpm_table *dpm_table = &data->dpm_table;
4779f4b3541SRex Zhu int result = 0;
4789f4b3541SRex Zhu uint32_t array = smu_data->dpm_table_start +
4799f4b3541SRex Zhu offsetof(SMU7_Discrete_DpmTable, GraphicsLevel);
4809f4b3541SRex Zhu uint32_t array_size = sizeof(struct SMU7_Discrete_GraphicsLevel) *
4819f4b3541SRex Zhu SMU7_MAX_LEVELS_GRAPHICS;
4829f4b3541SRex Zhu struct SMU7_Discrete_GraphicsLevel *levels =
4839f4b3541SRex Zhu smu_data->smc_state_table.GraphicsLevel;
4849f4b3541SRex Zhu uint32_t i;
4859f4b3541SRex Zhu
4869f4b3541SRex Zhu for (i = 0; i < dpm_table->sclk_table.count; i++) {
4879f4b3541SRex Zhu result = ci_populate_single_graphic_level(hwmgr,
4889f4b3541SRex Zhu dpm_table->sclk_table.dpm_levels[i].value,
4899f4b3541SRex Zhu &levels[i]);
4909f4b3541SRex Zhu if (result)
4919f4b3541SRex Zhu return result;
4929f4b3541SRex Zhu if (i > 1)
4939f4b3541SRex Zhu smu_data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
4949f4b3541SRex Zhu if (i == (dpm_table->sclk_table.count - 1))
4959f4b3541SRex Zhu smu_data->smc_state_table.GraphicsLevel[i].DisplayWatermark =
4969f4b3541SRex Zhu PPSMC_DISPLAY_WATERMARK_HIGH;
4979f4b3541SRex Zhu }
4989f4b3541SRex Zhu
4999f4b3541SRex Zhu smu_data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
5009f4b3541SRex Zhu
5019f4b3541SRex Zhu smu_data->smc_state_table.GraphicsDpmLevelCount = (u8)dpm_table->sclk_table.count;
5029f4b3541SRex Zhu data->dpm_level_enable_mask.sclk_dpm_enable_mask =
5039f4b3541SRex Zhu phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
5049f4b3541SRex Zhu
505d3f8c0abSRex Zhu result = ci_copy_bytes_to_smc(hwmgr, array,
5069f4b3541SRex Zhu (u8 *)levels, array_size,
5079f4b3541SRex Zhu SMC_RAM_END);
5089f4b3541SRex Zhu
5099f4b3541SRex Zhu return result;
5109f4b3541SRex Zhu
5119f4b3541SRex Zhu }
5129f4b3541SRex Zhu
ci_populate_svi_load_line(struct pp_hwmgr * hwmgr)5139f4b3541SRex Zhu static int ci_populate_svi_load_line(struct pp_hwmgr *hwmgr)
5149f4b3541SRex Zhu {
515b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
5169f4b3541SRex Zhu const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults;
5179f4b3541SRex Zhu
5189f4b3541SRex Zhu smu_data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en;
5199f4b3541SRex Zhu smu_data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddc;
5209f4b3541SRex Zhu smu_data->power_tune_table.SviLoadLineTrimVddC = 3;
5219f4b3541SRex Zhu smu_data->power_tune_table.SviLoadLineOffsetVddC = 0;
5229f4b3541SRex Zhu
5239f4b3541SRex Zhu return 0;
5249f4b3541SRex Zhu }
5259f4b3541SRex Zhu
ci_populate_tdc_limit(struct pp_hwmgr * hwmgr)5269f4b3541SRex Zhu static int ci_populate_tdc_limit(struct pp_hwmgr *hwmgr)
5279f4b3541SRex Zhu {
5289f4b3541SRex Zhu uint16_t tdc_limit;
529b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
5309f4b3541SRex Zhu const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults;
5319f4b3541SRex Zhu
5329f4b3541SRex Zhu tdc_limit = (uint16_t)(hwmgr->dyn_state.cac_dtp_table->usTDC * 256);
5339f4b3541SRex Zhu smu_data->power_tune_table.TDC_VDDC_PkgLimit =
5349f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
5359f4b3541SRex Zhu smu_data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
5369f4b3541SRex Zhu defaults->tdc_vddc_throttle_release_limit_perc;
5379f4b3541SRex Zhu smu_data->power_tune_table.TDC_MAWt = defaults->tdc_mawt;
5389f4b3541SRex Zhu
5399f4b3541SRex Zhu return 0;
5409f4b3541SRex Zhu }
5419f4b3541SRex Zhu
ci_populate_dw8(struct pp_hwmgr * hwmgr,uint32_t fuse_table_offset)5429f4b3541SRex Zhu static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
5439f4b3541SRex Zhu {
544b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
5459f4b3541SRex Zhu const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults;
5469f4b3541SRex Zhu uint32_t temp;
5479f4b3541SRex Zhu
548d3f8c0abSRex Zhu if (ci_read_smc_sram_dword(hwmgr,
5499f4b3541SRex Zhu fuse_table_offset +
5509f4b3541SRex Zhu offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl),
5519f4b3541SRex Zhu (uint32_t *)&temp, SMC_RAM_END))
5529f4b3541SRex Zhu PP_ASSERT_WITH_CODE(false,
5539f4b3541SRex Zhu "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
5549f4b3541SRex Zhu return -EINVAL);
5559f4b3541SRex Zhu else
5569f4b3541SRex Zhu smu_data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl;
5579f4b3541SRex Zhu
5589f4b3541SRex Zhu return 0;
5599f4b3541SRex Zhu }
5609f4b3541SRex Zhu
ci_populate_fuzzy_fan(struct pp_hwmgr * hwmgr,uint32_t fuse_table_offset)5619f4b3541SRex Zhu static int ci_populate_fuzzy_fan(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
5629f4b3541SRex Zhu {
563b3b03052SRex Zhu uint16_t tmp;
564b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
5659f4b3541SRex Zhu
5669f4b3541SRex Zhu if ((hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity & (1 << 15))
5679f4b3541SRex Zhu || 0 == hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity)
5689f4b3541SRex Zhu tmp = hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity;
5699f4b3541SRex Zhu else
5709f4b3541SRex Zhu tmp = hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity;
5719f4b3541SRex Zhu
5729f4b3541SRex Zhu smu_data->power_tune_table.FuzzyFan_PwmSetDelta = CONVERT_FROM_HOST_TO_SMC_US(tmp);
5739f4b3541SRex Zhu
5749f4b3541SRex Zhu return 0;
5759f4b3541SRex Zhu }
5769f4b3541SRex Zhu
ci_populate_bapm_vddc_vid_sidd(struct pp_hwmgr * hwmgr)5779f4b3541SRex Zhu static int ci_populate_bapm_vddc_vid_sidd(struct pp_hwmgr *hwmgr)
5789f4b3541SRex Zhu {
5799f4b3541SRex Zhu int i;
580b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
5819f4b3541SRex Zhu uint8_t *hi_vid = smu_data->power_tune_table.BapmVddCVidHiSidd;
5829f4b3541SRex Zhu uint8_t *lo_vid = smu_data->power_tune_table.BapmVddCVidLoSidd;
5839f4b3541SRex Zhu uint8_t *hi2_vid = smu_data->power_tune_table.BapmVddCVidHiSidd2;
5849f4b3541SRex Zhu
5859f4b3541SRex Zhu PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.cac_leakage_table,
5869f4b3541SRex Zhu "The CAC Leakage table does not exist!", return -EINVAL);
5879f4b3541SRex Zhu PP_ASSERT_WITH_CODE(hwmgr->dyn_state.cac_leakage_table->count <= 8,
5889f4b3541SRex Zhu "There should never be more than 8 entries for BapmVddcVid!!!", return -EINVAL);
5899f4b3541SRex Zhu PP_ASSERT_WITH_CODE(hwmgr->dyn_state.cac_leakage_table->count == hwmgr->dyn_state.vddc_dependency_on_sclk->count,
5909f4b3541SRex Zhu "CACLeakageTable->count and VddcDependencyOnSCLk->count not equal", return -EINVAL);
5919f4b3541SRex Zhu
5929f4b3541SRex Zhu for (i = 0; (uint32_t) i < hwmgr->dyn_state.cac_leakage_table->count; i++) {
5939f4b3541SRex Zhu if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EVV)) {
5949f4b3541SRex Zhu lo_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc1);
5959f4b3541SRex Zhu hi_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc2);
5969f4b3541SRex Zhu hi2_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc3);
5979f4b3541SRex Zhu } else {
5989f4b3541SRex Zhu lo_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc);
5999f4b3541SRex Zhu hi_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Leakage);
6009f4b3541SRex Zhu }
6019f4b3541SRex Zhu }
6029f4b3541SRex Zhu
6039f4b3541SRex Zhu return 0;
6049f4b3541SRex Zhu }
6059f4b3541SRex Zhu
ci_populate_vddc_vid(struct pp_hwmgr * hwmgr)6069f4b3541SRex Zhu static int ci_populate_vddc_vid(struct pp_hwmgr *hwmgr)
6079f4b3541SRex Zhu {
6089f4b3541SRex Zhu int i;
609b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
6109f4b3541SRex Zhu uint8_t *vid = smu_data->power_tune_table.VddCVid;
6119f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
6129f4b3541SRex Zhu
6139f4b3541SRex Zhu PP_ASSERT_WITH_CODE(data->vddc_voltage_table.count <= 8,
6149f4b3541SRex Zhu "There should never be more than 8 entries for VddcVid!!!",
6159f4b3541SRex Zhu return -EINVAL);
6169f4b3541SRex Zhu
6179f4b3541SRex Zhu for (i = 0; i < (int)data->vddc_voltage_table.count; i++)
6189f4b3541SRex Zhu vid[i] = convert_to_vid(data->vddc_voltage_table.entries[i].value);
6199f4b3541SRex Zhu
6209f4b3541SRex Zhu return 0;
6219f4b3541SRex Zhu }
6229f4b3541SRex Zhu
ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct pp_hwmgr * hwmgr)6239f4b3541SRex Zhu static int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct pp_hwmgr *hwmgr)
6249f4b3541SRex Zhu {
625b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
6269f4b3541SRex Zhu u8 *hi_vid = smu_data->power_tune_table.BapmVddCVidHiSidd;
6279f4b3541SRex Zhu u8 *lo_vid = smu_data->power_tune_table.BapmVddCVidLoSidd;
6289f4b3541SRex Zhu int i, min, max;
6299f4b3541SRex Zhu
6309f4b3541SRex Zhu min = max = hi_vid[0];
6319f4b3541SRex Zhu for (i = 0; i < 8; i++) {
6329f4b3541SRex Zhu if (0 != hi_vid[i]) {
6339f4b3541SRex Zhu if (min > hi_vid[i])
6349f4b3541SRex Zhu min = hi_vid[i];
6359f4b3541SRex Zhu if (max < hi_vid[i])
6369f4b3541SRex Zhu max = hi_vid[i];
6379f4b3541SRex Zhu }
6389f4b3541SRex Zhu
6399f4b3541SRex Zhu if (0 != lo_vid[i]) {
6409f4b3541SRex Zhu if (min > lo_vid[i])
6419f4b3541SRex Zhu min = lo_vid[i];
6429f4b3541SRex Zhu if (max < lo_vid[i])
6439f4b3541SRex Zhu max = lo_vid[i];
6449f4b3541SRex Zhu }
6459f4b3541SRex Zhu }
6469f4b3541SRex Zhu
6479f4b3541SRex Zhu if ((min == 0) || (max == 0))
6489f4b3541SRex Zhu return -EINVAL;
6499f4b3541SRex Zhu smu_data->power_tune_table.GnbLPMLMaxVid = (u8)max;
6509f4b3541SRex Zhu smu_data->power_tune_table.GnbLPMLMinVid = (u8)min;
6519f4b3541SRex Zhu
6529f4b3541SRex Zhu return 0;
6539f4b3541SRex Zhu }
6549f4b3541SRex Zhu
ci_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr * hwmgr)6559f4b3541SRex Zhu static int ci_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
6569f4b3541SRex Zhu {
657b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
658dde8c8dfSColin Ian King uint16_t HiSidd;
659dde8c8dfSColin Ian King uint16_t LoSidd;
6609f4b3541SRex Zhu struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table;
6619f4b3541SRex Zhu
6629f4b3541SRex Zhu HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
6639f4b3541SRex Zhu LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
6649f4b3541SRex Zhu
6659f4b3541SRex Zhu smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd =
6669f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
6679f4b3541SRex Zhu smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd =
6689f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
6699f4b3541SRex Zhu
6709f4b3541SRex Zhu return 0;
6719f4b3541SRex Zhu }
6729f4b3541SRex Zhu
ci_populate_pm_fuses(struct pp_hwmgr * hwmgr)6739f4b3541SRex Zhu static int ci_populate_pm_fuses(struct pp_hwmgr *hwmgr)
6749f4b3541SRex Zhu {
675b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
6769f4b3541SRex Zhu uint32_t pm_fuse_table_offset;
6779f4b3541SRex Zhu int ret = 0;
6789f4b3541SRex Zhu
6799f4b3541SRex Zhu if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
6809f4b3541SRex Zhu PHM_PlatformCaps_PowerContainment)) {
681d3f8c0abSRex Zhu if (ci_read_smc_sram_dword(hwmgr,
6829f4b3541SRex Zhu SMU7_FIRMWARE_HEADER_LOCATION +
6839f4b3541SRex Zhu offsetof(SMU7_Firmware_Header, PmFuseTable),
6849f4b3541SRex Zhu &pm_fuse_table_offset, SMC_RAM_END)) {
6859f4b3541SRex Zhu pr_err("Attempt to get pm_fuse_table_offset Failed!\n");
6869f4b3541SRex Zhu return -EINVAL;
6879f4b3541SRex Zhu }
6889f4b3541SRex Zhu
6899f4b3541SRex Zhu /* DW0 - DW3 */
6909f4b3541SRex Zhu ret = ci_populate_bapm_vddc_vid_sidd(hwmgr);
6919f4b3541SRex Zhu /* DW4 - DW5 */
6929f4b3541SRex Zhu ret |= ci_populate_vddc_vid(hwmgr);
6939f4b3541SRex Zhu /* DW6 */
6949f4b3541SRex Zhu ret |= ci_populate_svi_load_line(hwmgr);
6959f4b3541SRex Zhu /* DW7 */
6969f4b3541SRex Zhu ret |= ci_populate_tdc_limit(hwmgr);
6979f4b3541SRex Zhu /* DW8 */
6989f4b3541SRex Zhu ret |= ci_populate_dw8(hwmgr, pm_fuse_table_offset);
6999f4b3541SRex Zhu
7009f4b3541SRex Zhu ret |= ci_populate_fuzzy_fan(hwmgr, pm_fuse_table_offset);
7019f4b3541SRex Zhu
7029f4b3541SRex Zhu ret |= ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(hwmgr);
7039f4b3541SRex Zhu
7049f4b3541SRex Zhu ret |= ci_populate_bapm_vddc_base_leakage_sidd(hwmgr);
7059f4b3541SRex Zhu if (ret)
7069f4b3541SRex Zhu return ret;
7079f4b3541SRex Zhu
708d3f8c0abSRex Zhu ret = ci_copy_bytes_to_smc(hwmgr, pm_fuse_table_offset,
7099f4b3541SRex Zhu (uint8_t *)&smu_data->power_tune_table,
7109f4b3541SRex Zhu sizeof(struct SMU7_Discrete_PmFuses), SMC_RAM_END);
7119f4b3541SRex Zhu }
7129f4b3541SRex Zhu return ret;
7139f4b3541SRex Zhu }
7149f4b3541SRex Zhu
ci_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr * hwmgr)7159f4b3541SRex Zhu static int ci_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
7169f4b3541SRex Zhu {
717b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
7189f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
7199f4b3541SRex Zhu const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults;
7209f4b3541SRex Zhu SMU7_Discrete_DpmTable *dpm_table = &(smu_data->smc_state_table);
7219f4b3541SRex Zhu struct phm_cac_tdp_table *cac_dtp_table = hwmgr->dyn_state.cac_dtp_table;
7229f4b3541SRex Zhu struct phm_ppm_table *ppm = hwmgr->dyn_state.ppm_parameter_table;
7239f4b3541SRex Zhu const uint16_t *def1, *def2;
7249f4b3541SRex Zhu int i, j, k;
7259f4b3541SRex Zhu
7269f4b3541SRex Zhu dpm_table->DefaultTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 256));
7279f4b3541SRex Zhu dpm_table->TargetTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usConfigurableTDP * 256));
7289f4b3541SRex Zhu
7299f4b3541SRex Zhu dpm_table->DTETjOffset = 0;
7309f4b3541SRex Zhu dpm_table->GpuTjMax = (uint8_t)(data->thermal_temp_setting.temperature_high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES);
7319f4b3541SRex Zhu dpm_table->GpuTjHyst = 8;
7329f4b3541SRex Zhu
7339f4b3541SRex Zhu dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base;
7349f4b3541SRex Zhu
7359f4b3541SRex Zhu if (ppm) {
7369f4b3541SRex Zhu dpm_table->PPM_PkgPwrLimit = (uint16_t)ppm->dgpu_tdp * 256 / 1000;
7379f4b3541SRex Zhu dpm_table->PPM_TemperatureLimit = (uint16_t)ppm->tj_max * 256;
7389f4b3541SRex Zhu } else {
7399f4b3541SRex Zhu dpm_table->PPM_PkgPwrLimit = 0;
7409f4b3541SRex Zhu dpm_table->PPM_TemperatureLimit = 0;
7419f4b3541SRex Zhu }
7429f4b3541SRex Zhu
7439f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_PkgPwrLimit);
7449f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_TemperatureLimit);
7459f4b3541SRex Zhu
7469f4b3541SRex Zhu dpm_table->BAPM_TEMP_GRADIENT = PP_HOST_TO_SMC_UL(defaults->bapm_temp_gradient);
7479f4b3541SRex Zhu def1 = defaults->bapmti_r;
7489f4b3541SRex Zhu def2 = defaults->bapmti_rc;
7499f4b3541SRex Zhu
7509f4b3541SRex Zhu for (i = 0; i < SMU7_DTE_ITERATIONS; i++) {
7519f4b3541SRex Zhu for (j = 0; j < SMU7_DTE_SOURCES; j++) {
7529f4b3541SRex Zhu for (k = 0; k < SMU7_DTE_SINKS; k++) {
7539f4b3541SRex Zhu dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*def1);
7549f4b3541SRex Zhu dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*def2);
7559f4b3541SRex Zhu def1++;
7569f4b3541SRex Zhu def2++;
7579f4b3541SRex Zhu }
7589f4b3541SRex Zhu }
7599f4b3541SRex Zhu }
7609f4b3541SRex Zhu
7619f4b3541SRex Zhu return 0;
7629f4b3541SRex Zhu }
7639f4b3541SRex Zhu
ci_get_std_voltage_value_sidd(struct pp_hwmgr * hwmgr,pp_atomctrl_voltage_table_entry * tab,uint16_t * hi,uint16_t * lo)7649f4b3541SRex Zhu static int ci_get_std_voltage_value_sidd(struct pp_hwmgr *hwmgr,
7659f4b3541SRex Zhu pp_atomctrl_voltage_table_entry *tab, uint16_t *hi,
7669f4b3541SRex Zhu uint16_t *lo)
7679f4b3541SRex Zhu {
7689f4b3541SRex Zhu uint16_t v_index;
7699f4b3541SRex Zhu bool vol_found = false;
7709f4b3541SRex Zhu *hi = tab->value * VOLTAGE_SCALE;
7719f4b3541SRex Zhu *lo = tab->value * VOLTAGE_SCALE;
7729f4b3541SRex Zhu
7739f4b3541SRex Zhu PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.vddc_dependency_on_sclk,
7749f4b3541SRex Zhu "The SCLK/VDDC Dependency Table does not exist.\n",
7759f4b3541SRex Zhu return -EINVAL);
7769f4b3541SRex Zhu
7779f4b3541SRex Zhu if (NULL == hwmgr->dyn_state.cac_leakage_table) {
7789f4b3541SRex Zhu pr_warn("CAC Leakage Table does not exist, using vddc.\n");
7799f4b3541SRex Zhu return 0;
7809f4b3541SRex Zhu }
7819f4b3541SRex Zhu
7829f4b3541SRex Zhu for (v_index = 0; (uint32_t)v_index < hwmgr->dyn_state.vddc_dependency_on_sclk->count; v_index++) {
7839f4b3541SRex Zhu if (tab->value == hwmgr->dyn_state.vddc_dependency_on_sclk->entries[v_index].v) {
7849f4b3541SRex Zhu vol_found = true;
7859f4b3541SRex Zhu if ((uint32_t)v_index < hwmgr->dyn_state.cac_leakage_table->count) {
7869f4b3541SRex Zhu *lo = hwmgr->dyn_state.cac_leakage_table->entries[v_index].Vddc * VOLTAGE_SCALE;
7879f4b3541SRex Zhu *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[v_index].Leakage * VOLTAGE_SCALE);
7889f4b3541SRex Zhu } else {
7899f4b3541SRex Zhu pr_warn("Index from SCLK/VDDC Dependency Table exceeds the CAC Leakage Table index, using maximum index from CAC table.\n");
7909f4b3541SRex Zhu *lo = hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Vddc * VOLTAGE_SCALE;
7919f4b3541SRex Zhu *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Leakage * VOLTAGE_SCALE);
7929f4b3541SRex Zhu }
7939f4b3541SRex Zhu break;
7949f4b3541SRex Zhu }
7959f4b3541SRex Zhu }
7969f4b3541SRex Zhu
7979f4b3541SRex Zhu if (!vol_found) {
7989f4b3541SRex Zhu for (v_index = 0; (uint32_t)v_index < hwmgr->dyn_state.vddc_dependency_on_sclk->count; v_index++) {
7999f4b3541SRex Zhu if (tab->value <= hwmgr->dyn_state.vddc_dependency_on_sclk->entries[v_index].v) {
8009f4b3541SRex Zhu vol_found = true;
8019f4b3541SRex Zhu if ((uint32_t)v_index < hwmgr->dyn_state.cac_leakage_table->count) {
8029f4b3541SRex Zhu *lo = hwmgr->dyn_state.cac_leakage_table->entries[v_index].Vddc * VOLTAGE_SCALE;
8039f4b3541SRex Zhu *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[v_index].Leakage) * VOLTAGE_SCALE;
8049f4b3541SRex Zhu } else {
8059f4b3541SRex Zhu pr_warn("Index from SCLK/VDDC Dependency Table exceeds the CAC Leakage Table index in second look up, using maximum index from CAC table.");
8069f4b3541SRex Zhu *lo = hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Vddc * VOLTAGE_SCALE;
8079f4b3541SRex Zhu *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Leakage * VOLTAGE_SCALE);
8089f4b3541SRex Zhu }
8099f4b3541SRex Zhu break;
8109f4b3541SRex Zhu }
8119f4b3541SRex Zhu }
8129f4b3541SRex Zhu
8139f4b3541SRex Zhu if (!vol_found)
8149f4b3541SRex Zhu pr_warn("Unable to get std_vddc from SCLK/VDDC Dependency Table, using vddc.\n");
8159f4b3541SRex Zhu }
8169f4b3541SRex Zhu
8179f4b3541SRex Zhu return 0;
8189f4b3541SRex Zhu }
8199f4b3541SRex Zhu
ci_populate_smc_voltage_table(struct pp_hwmgr * hwmgr,pp_atomctrl_voltage_table_entry * tab,SMU7_Discrete_VoltageLevel * smc_voltage_tab)8209f4b3541SRex Zhu static int ci_populate_smc_voltage_table(struct pp_hwmgr *hwmgr,
8219f4b3541SRex Zhu pp_atomctrl_voltage_table_entry *tab,
8229f4b3541SRex Zhu SMU7_Discrete_VoltageLevel *smc_voltage_tab)
8239f4b3541SRex Zhu {
8249f4b3541SRex Zhu int result;
8259f4b3541SRex Zhu
8269f4b3541SRex Zhu result = ci_get_std_voltage_value_sidd(hwmgr, tab,
8279f4b3541SRex Zhu &smc_voltage_tab->StdVoltageHiSidd,
8289f4b3541SRex Zhu &smc_voltage_tab->StdVoltageLoSidd);
8299f4b3541SRex Zhu if (result) {
8309f4b3541SRex Zhu smc_voltage_tab->StdVoltageHiSidd = tab->value * VOLTAGE_SCALE;
8319f4b3541SRex Zhu smc_voltage_tab->StdVoltageLoSidd = tab->value * VOLTAGE_SCALE;
8329f4b3541SRex Zhu }
8339f4b3541SRex Zhu
8349f4b3541SRex Zhu smc_voltage_tab->Voltage = PP_HOST_TO_SMC_US(tab->value * VOLTAGE_SCALE);
8359f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(smc_voltage_tab->StdVoltageHiSidd);
8369f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(smc_voltage_tab->StdVoltageLoSidd);
8379f4b3541SRex Zhu
8389f4b3541SRex Zhu return 0;
8399f4b3541SRex Zhu }
8409f4b3541SRex Zhu
ci_populate_smc_vddc_table(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)8419f4b3541SRex Zhu static int ci_populate_smc_vddc_table(struct pp_hwmgr *hwmgr,
8429f4b3541SRex Zhu SMU7_Discrete_DpmTable *table)
8439f4b3541SRex Zhu {
8449f4b3541SRex Zhu unsigned int count;
8459f4b3541SRex Zhu int result;
8469f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
8479f4b3541SRex Zhu
8489f4b3541SRex Zhu table->VddcLevelCount = data->vddc_voltage_table.count;
8499f4b3541SRex Zhu for (count = 0; count < table->VddcLevelCount; count++) {
8509f4b3541SRex Zhu result = ci_populate_smc_voltage_table(hwmgr,
8519f4b3541SRex Zhu &(data->vddc_voltage_table.entries[count]),
8529f4b3541SRex Zhu &(table->VddcLevel[count]));
8539f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result, "do not populate SMC VDDC voltage table", return -EINVAL);
8549f4b3541SRex Zhu
8559f4b3541SRex Zhu /* GPIO voltage control */
856e8ea1b9aSRex Zhu if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control) {
857e8ea1b9aSRex Zhu table->VddcLevel[count].Smio = (uint8_t) count;
858e8ea1b9aSRex Zhu table->Smio[count] |= data->vddc_voltage_table.entries[count].smio_low;
859e8ea1b9aSRex Zhu table->SmioMaskVddcVid |= data->vddc_voltage_table.entries[count].smio_low;
860e8ea1b9aSRex Zhu } else {
8619f4b3541SRex Zhu table->VddcLevel[count].Smio = 0;
8629f4b3541SRex Zhu }
863e8ea1b9aSRex Zhu }
8649f4b3541SRex Zhu
8659f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount);
8669f4b3541SRex Zhu
8679f4b3541SRex Zhu return 0;
8689f4b3541SRex Zhu }
8699f4b3541SRex Zhu
ci_populate_smc_vdd_ci_table(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)8709f4b3541SRex Zhu static int ci_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr,
8719f4b3541SRex Zhu SMU7_Discrete_DpmTable *table)
8729f4b3541SRex Zhu {
8739f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
8749f4b3541SRex Zhu uint32_t count;
8759f4b3541SRex Zhu int result;
8769f4b3541SRex Zhu
8779f4b3541SRex Zhu table->VddciLevelCount = data->vddci_voltage_table.count;
8789f4b3541SRex Zhu
8799f4b3541SRex Zhu for (count = 0; count < table->VddciLevelCount; count++) {
8809f4b3541SRex Zhu result = ci_populate_smc_voltage_table(hwmgr,
8819f4b3541SRex Zhu &(data->vddci_voltage_table.entries[count]),
8829f4b3541SRex Zhu &(table->VddciLevel[count]));
8839f4b3541SRex Zhu PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC VDDCI voltage table", return -EINVAL);
884e8ea1b9aSRex Zhu if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
885e8ea1b9aSRex Zhu table->VddciLevel[count].Smio = (uint8_t) count;
886e8ea1b9aSRex Zhu table->Smio[count] |= data->vddci_voltage_table.entries[count].smio_low;
887e8ea1b9aSRex Zhu table->SmioMaskVddciVid |= data->vddci_voltage_table.entries[count].smio_low;
888e8ea1b9aSRex Zhu } else {
889e8ea1b9aSRex Zhu table->VddciLevel[count].Smio = 0;
890e8ea1b9aSRex Zhu }
8919f4b3541SRex Zhu }
8929f4b3541SRex Zhu
8939f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount);
8949f4b3541SRex Zhu
8959f4b3541SRex Zhu return 0;
8969f4b3541SRex Zhu }
8979f4b3541SRex Zhu
ci_populate_smc_mvdd_table(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)8989f4b3541SRex Zhu static int ci_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
8999f4b3541SRex Zhu SMU7_Discrete_DpmTable *table)
9009f4b3541SRex Zhu {
9019f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
9029f4b3541SRex Zhu uint32_t count;
9039f4b3541SRex Zhu int result;
9049f4b3541SRex Zhu
9059f4b3541SRex Zhu table->MvddLevelCount = data->mvdd_voltage_table.count;
9069f4b3541SRex Zhu
9079f4b3541SRex Zhu for (count = 0; count < table->MvddLevelCount; count++) {
9089f4b3541SRex Zhu result = ci_populate_smc_voltage_table(hwmgr,
9099f4b3541SRex Zhu &(data->mvdd_voltage_table.entries[count]),
9109f4b3541SRex Zhu &table->MvddLevel[count]);
9119f4b3541SRex Zhu PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC mvdd voltage table", return -EINVAL);
912e8ea1b9aSRex Zhu if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
913e8ea1b9aSRex Zhu table->MvddLevel[count].Smio = (uint8_t) count;
914e8ea1b9aSRex Zhu table->Smio[count] |= data->mvdd_voltage_table.entries[count].smio_low;
915e8ea1b9aSRex Zhu table->SmioMaskMvddVid |= data->mvdd_voltage_table.entries[count].smio_low;
916e8ea1b9aSRex Zhu } else {
917e8ea1b9aSRex Zhu table->MvddLevel[count].Smio = 0;
918e8ea1b9aSRex Zhu }
9199f4b3541SRex Zhu }
9209f4b3541SRex Zhu
9219f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount);
9229f4b3541SRex Zhu
9239f4b3541SRex Zhu return 0;
9249f4b3541SRex Zhu }
9259f4b3541SRex Zhu
9269f4b3541SRex Zhu
ci_populate_smc_voltage_tables(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)9279f4b3541SRex Zhu static int ci_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
9289f4b3541SRex Zhu SMU7_Discrete_DpmTable *table)
9299f4b3541SRex Zhu {
9309f4b3541SRex Zhu int result;
9319f4b3541SRex Zhu
9329f4b3541SRex Zhu result = ci_populate_smc_vddc_table(hwmgr, table);
9339f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
9349f4b3541SRex Zhu "can not populate VDDC voltage table to SMC", return -EINVAL);
9359f4b3541SRex Zhu
9369f4b3541SRex Zhu result = ci_populate_smc_vdd_ci_table(hwmgr, table);
9379f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
9389f4b3541SRex Zhu "can not populate VDDCI voltage table to SMC", return -EINVAL);
9399f4b3541SRex Zhu
9409f4b3541SRex Zhu result = ci_populate_smc_mvdd_table(hwmgr, table);
9419f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
9429f4b3541SRex Zhu "can not populate MVDD voltage table to SMC", return -EINVAL);
9439f4b3541SRex Zhu
9449f4b3541SRex Zhu return 0;
9459f4b3541SRex Zhu }
9469f4b3541SRex Zhu
ci_populate_ulv_level(struct pp_hwmgr * hwmgr,struct SMU7_Discrete_Ulv * state)9479f4b3541SRex Zhu static int ci_populate_ulv_level(struct pp_hwmgr *hwmgr,
9489f4b3541SRex Zhu struct SMU7_Discrete_Ulv *state)
9499f4b3541SRex Zhu {
9509f4b3541SRex Zhu uint32_t voltage_response_time, ulv_voltage;
9519f4b3541SRex Zhu int result;
9529f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
9539f4b3541SRex Zhu
9549f4b3541SRex Zhu state->CcPwrDynRm = 0;
9559f4b3541SRex Zhu state->CcPwrDynRm1 = 0;
9569f4b3541SRex Zhu
9579f4b3541SRex Zhu result = pp_tables_get_response_times(hwmgr, &voltage_response_time, &ulv_voltage);
9589f4b3541SRex Zhu PP_ASSERT_WITH_CODE((0 == result), "can not get ULV voltage value", return result;);
9599f4b3541SRex Zhu
9609f4b3541SRex Zhu if (ulv_voltage == 0) {
9619f4b3541SRex Zhu data->ulv_supported = false;
9629f4b3541SRex Zhu return 0;
9639f4b3541SRex Zhu }
9649f4b3541SRex Zhu
9659f4b3541SRex Zhu if (data->voltage_control != SMU7_VOLTAGE_CONTROL_BY_SVID2) {
9669f4b3541SRex Zhu /* use minimum voltage if ulv voltage in pptable is bigger than minimum voltage */
9679f4b3541SRex Zhu if (ulv_voltage > hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v)
9689f4b3541SRex Zhu state->VddcOffset = 0;
9699f4b3541SRex Zhu else
9709f4b3541SRex Zhu /* used in SMIO Mode. not implemented for now. this is backup only for CI. */
9719f4b3541SRex Zhu state->VddcOffset = (uint16_t)(hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v - ulv_voltage);
9729f4b3541SRex Zhu } else {
9739f4b3541SRex Zhu /* use minimum voltage if ulv voltage in pptable is bigger than minimum voltage */
9749f4b3541SRex Zhu if (ulv_voltage > hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v)
9759f4b3541SRex Zhu state->VddcOffsetVid = 0;
9769f4b3541SRex Zhu else /* used in SVI2 Mode */
9779f4b3541SRex Zhu state->VddcOffsetVid = (uint8_t)(
9789f4b3541SRex Zhu (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v - ulv_voltage)
9799f4b3541SRex Zhu * VOLTAGE_VID_OFFSET_SCALE2
9809f4b3541SRex Zhu / VOLTAGE_VID_OFFSET_SCALE1);
9819f4b3541SRex Zhu }
9829f4b3541SRex Zhu state->VddcPhase = 1;
9839f4b3541SRex Zhu
9849f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
9859f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
9869f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
9879f4b3541SRex Zhu
9889f4b3541SRex Zhu return 0;
9899f4b3541SRex Zhu }
9909f4b3541SRex Zhu
ci_populate_ulv_state(struct pp_hwmgr * hwmgr,SMU7_Discrete_Ulv * ulv_level)9919f4b3541SRex Zhu static int ci_populate_ulv_state(struct pp_hwmgr *hwmgr,
9929f4b3541SRex Zhu SMU7_Discrete_Ulv *ulv_level)
9939f4b3541SRex Zhu {
9949f4b3541SRex Zhu return ci_populate_ulv_level(hwmgr, ulv_level);
9959f4b3541SRex Zhu }
9969f4b3541SRex Zhu
ci_populate_smc_link_level(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)9979f4b3541SRex Zhu static int ci_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU7_Discrete_DpmTable *table)
9989f4b3541SRex Zhu {
9999f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
10009f4b3541SRex Zhu struct smu7_dpm_table *dpm_table = &data->dpm_table;
1001b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
10029f4b3541SRex Zhu uint32_t i;
10039f4b3541SRex Zhu
10049f4b3541SRex Zhu /* Index dpm_table->pcie_speed_table.count is reserved for PCIE boot level.*/
10059f4b3541SRex Zhu for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
10069f4b3541SRex Zhu table->LinkLevel[i].PcieGenSpeed =
10079f4b3541SRex Zhu (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
10089f4b3541SRex Zhu table->LinkLevel[i].PcieLaneCount =
10099f4b3541SRex Zhu (uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
10109f4b3541SRex Zhu table->LinkLevel[i].EnabledForActivity = 1;
10119f4b3541SRex Zhu table->LinkLevel[i].DownT = PP_HOST_TO_SMC_UL(5);
10129f4b3541SRex Zhu table->LinkLevel[i].UpT = PP_HOST_TO_SMC_UL(30);
10139f4b3541SRex Zhu }
10149f4b3541SRex Zhu
10159f4b3541SRex Zhu smu_data->smc_state_table.LinkLevelCount =
10169f4b3541SRex Zhu (uint8_t)dpm_table->pcie_speed_table.count;
10179f4b3541SRex Zhu data->dpm_level_enable_mask.pcie_dpm_enable_mask =
10189f4b3541SRex Zhu phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
10199f4b3541SRex Zhu
10209f4b3541SRex Zhu return 0;
10219f4b3541SRex Zhu }
10229f4b3541SRex Zhu
ci_calculate_mclk_params(struct pp_hwmgr * hwmgr,uint32_t memory_clock,SMU7_Discrete_MemoryLevel * mclk,bool strobe_mode,bool dllStateOn)10239f4b3541SRex Zhu static int ci_calculate_mclk_params(
10249f4b3541SRex Zhu struct pp_hwmgr *hwmgr,
10259f4b3541SRex Zhu uint32_t memory_clock,
10269f4b3541SRex Zhu SMU7_Discrete_MemoryLevel *mclk,
10279f4b3541SRex Zhu bool strobe_mode,
10289f4b3541SRex Zhu bool dllStateOn
10299f4b3541SRex Zhu )
10309f4b3541SRex Zhu {
10319f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
10329f4b3541SRex Zhu uint32_t dll_cntl = data->clock_registers.vDLL_CNTL;
10339f4b3541SRex Zhu uint32_t mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
10349f4b3541SRex Zhu uint32_t mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL;
10359f4b3541SRex Zhu uint32_t mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL;
10369f4b3541SRex Zhu uint32_t mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL;
10379f4b3541SRex Zhu uint32_t mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1;
10389f4b3541SRex Zhu uint32_t mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2;
10399f4b3541SRex Zhu uint32_t mpll_ss1 = data->clock_registers.vMPLL_SS1;
10409f4b3541SRex Zhu uint32_t mpll_ss2 = data->clock_registers.vMPLL_SS2;
10419f4b3541SRex Zhu
10429f4b3541SRex Zhu pp_atomctrl_memory_clock_param mpll_param;
10439f4b3541SRex Zhu int result;
10449f4b3541SRex Zhu
10459f4b3541SRex Zhu result = atomctrl_get_memory_pll_dividers_si(hwmgr,
10469f4b3541SRex Zhu memory_clock, &mpll_param, strobe_mode);
10479f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
10489f4b3541SRex Zhu "Error retrieving Memory Clock Parameters from VBIOS.", return result);
10499f4b3541SRex Zhu
10509f4b3541SRex Zhu mpll_func_cntl = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL, mpll_param.bw_ctrl);
10519f4b3541SRex Zhu
10529f4b3541SRex Zhu mpll_func_cntl_1 = PHM_SET_FIELD(mpll_func_cntl_1,
10539f4b3541SRex Zhu MPLL_FUNC_CNTL_1, CLKF, mpll_param.mpll_fb_divider.cl_kf);
10549f4b3541SRex Zhu mpll_func_cntl_1 = PHM_SET_FIELD(mpll_func_cntl_1,
10559f4b3541SRex Zhu MPLL_FUNC_CNTL_1, CLKFRAC, mpll_param.mpll_fb_divider.clk_frac);
10569f4b3541SRex Zhu mpll_func_cntl_1 = PHM_SET_FIELD(mpll_func_cntl_1,
10579f4b3541SRex Zhu MPLL_FUNC_CNTL_1, VCO_MODE, mpll_param.vco_mode);
10589f4b3541SRex Zhu
10599f4b3541SRex Zhu mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl,
10609f4b3541SRex Zhu MPLL_AD_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
10619f4b3541SRex Zhu
10629f4b3541SRex Zhu if (data->is_memory_gddr5) {
10639f4b3541SRex Zhu mpll_dq_func_cntl = PHM_SET_FIELD(mpll_dq_func_cntl,
10649f4b3541SRex Zhu MPLL_DQ_FUNC_CNTL, YCLK_SEL, mpll_param.yclk_sel);
10659f4b3541SRex Zhu mpll_dq_func_cntl = PHM_SET_FIELD(mpll_dq_func_cntl,
10669f4b3541SRex Zhu MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
10679f4b3541SRex Zhu }
10689f4b3541SRex Zhu
10699f4b3541SRex Zhu if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
10709f4b3541SRex Zhu PHM_PlatformCaps_MemorySpreadSpectrumSupport)) {
10719f4b3541SRex Zhu pp_atomctrl_internal_ss_info ss_info;
10729f4b3541SRex Zhu uint32_t freq_nom;
10739f4b3541SRex Zhu uint32_t tmp;
10749f4b3541SRex Zhu uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr);
10759f4b3541SRex Zhu
10769f4b3541SRex Zhu /* for GDDR5 for all modes and DDR3 */
10779f4b3541SRex Zhu if (1 == mpll_param.qdr)
10789f4b3541SRex Zhu freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider);
10799f4b3541SRex Zhu else
10809f4b3541SRex Zhu freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider);
10819f4b3541SRex Zhu
10829f4b3541SRex Zhu /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2 Note: S.I. reference_divider = 1*/
10839f4b3541SRex Zhu tmp = (freq_nom / reference_clock);
10849f4b3541SRex Zhu tmp = tmp * tmp;
10859f4b3541SRex Zhu
10869f4b3541SRex Zhu if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) {
10879f4b3541SRex Zhu uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate;
10889f4b3541SRex Zhu uint32_t clkv =
10899f4b3541SRex Zhu (uint32_t)((((131 * ss_info.speed_spectrum_percentage *
10909f4b3541SRex Zhu ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom);
10919f4b3541SRex Zhu
10929f4b3541SRex Zhu mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv);
10939f4b3541SRex Zhu mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks);
10949f4b3541SRex Zhu }
10959f4b3541SRex Zhu }
10969f4b3541SRex Zhu
10979f4b3541SRex Zhu mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
10989f4b3541SRex Zhu MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed);
10999f4b3541SRex Zhu mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
11009f4b3541SRex Zhu MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn);
11019f4b3541SRex Zhu mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
11029f4b3541SRex Zhu MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn);
11039f4b3541SRex Zhu
11049f4b3541SRex Zhu
11059f4b3541SRex Zhu mclk->MclkFrequency = memory_clock;
11069f4b3541SRex Zhu mclk->MpllFuncCntl = mpll_func_cntl;
11079f4b3541SRex Zhu mclk->MpllFuncCntl_1 = mpll_func_cntl_1;
11089f4b3541SRex Zhu mclk->MpllFuncCntl_2 = mpll_func_cntl_2;
11099f4b3541SRex Zhu mclk->MpllAdFuncCntl = mpll_ad_func_cntl;
11109f4b3541SRex Zhu mclk->MpllDqFuncCntl = mpll_dq_func_cntl;
11119f4b3541SRex Zhu mclk->MclkPwrmgtCntl = mclk_pwrmgt_cntl;
11129f4b3541SRex Zhu mclk->DllCntl = dll_cntl;
11139f4b3541SRex Zhu mclk->MpllSs1 = mpll_ss1;
11149f4b3541SRex Zhu mclk->MpllSs2 = mpll_ss2;
11159f4b3541SRex Zhu
11169f4b3541SRex Zhu return 0;
11179f4b3541SRex Zhu }
11189f4b3541SRex Zhu
ci_get_mclk_frequency_ratio(uint32_t memory_clock,bool strobe_mode)11199f4b3541SRex Zhu static uint8_t ci_get_mclk_frequency_ratio(uint32_t memory_clock,
11209f4b3541SRex Zhu bool strobe_mode)
11219f4b3541SRex Zhu {
11229f4b3541SRex Zhu uint8_t mc_para_index;
11239f4b3541SRex Zhu
11249f4b3541SRex Zhu if (strobe_mode) {
11259f4b3541SRex Zhu if (memory_clock < 12500)
11269f4b3541SRex Zhu mc_para_index = 0x00;
11279f4b3541SRex Zhu else if (memory_clock > 47500)
11289f4b3541SRex Zhu mc_para_index = 0x0f;
11299f4b3541SRex Zhu else
11309f4b3541SRex Zhu mc_para_index = (uint8_t)((memory_clock - 10000) / 2500);
11319f4b3541SRex Zhu } else {
11329f4b3541SRex Zhu if (memory_clock < 65000)
11339f4b3541SRex Zhu mc_para_index = 0x00;
11349f4b3541SRex Zhu else if (memory_clock > 135000)
11359f4b3541SRex Zhu mc_para_index = 0x0f;
11369f4b3541SRex Zhu else
11379f4b3541SRex Zhu mc_para_index = (uint8_t)((memory_clock - 60000) / 5000);
11389f4b3541SRex Zhu }
11399f4b3541SRex Zhu
11409f4b3541SRex Zhu return mc_para_index;
11419f4b3541SRex Zhu }
11429f4b3541SRex Zhu
ci_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)11439f4b3541SRex Zhu static uint8_t ci_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)
11449f4b3541SRex Zhu {
11459f4b3541SRex Zhu uint8_t mc_para_index;
11469f4b3541SRex Zhu
11479f4b3541SRex Zhu if (memory_clock < 10000)
11489f4b3541SRex Zhu mc_para_index = 0;
11499f4b3541SRex Zhu else if (memory_clock >= 80000)
11509f4b3541SRex Zhu mc_para_index = 0x0f;
11519f4b3541SRex Zhu else
11529f4b3541SRex Zhu mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1);
11539f4b3541SRex Zhu
11549f4b3541SRex Zhu return mc_para_index;
11559f4b3541SRex Zhu }
11569f4b3541SRex Zhu
ci_populate_phase_value_based_on_mclk(struct pp_hwmgr * hwmgr,const struct phm_phase_shedding_limits_table * pl,uint32_t memory_clock,uint32_t * p_shed)11579f4b3541SRex Zhu static int ci_populate_phase_value_based_on_mclk(struct pp_hwmgr *hwmgr, const struct phm_phase_shedding_limits_table *pl,
11589f4b3541SRex Zhu uint32_t memory_clock, uint32_t *p_shed)
11599f4b3541SRex Zhu {
11609f4b3541SRex Zhu unsigned int i;
11619f4b3541SRex Zhu
11629f4b3541SRex Zhu *p_shed = 1;
11639f4b3541SRex Zhu
11649f4b3541SRex Zhu for (i = 0; i < pl->count; i++) {
11659f4b3541SRex Zhu if (memory_clock < pl->entries[i].Mclk) {
11669f4b3541SRex Zhu *p_shed = i;
11679f4b3541SRex Zhu break;
11689f4b3541SRex Zhu }
11699f4b3541SRex Zhu }
11709f4b3541SRex Zhu
11719f4b3541SRex Zhu return 0;
11729f4b3541SRex Zhu }
11739f4b3541SRex Zhu
ci_populate_single_memory_level(struct pp_hwmgr * hwmgr,uint32_t memory_clock,SMU7_Discrete_MemoryLevel * memory_level)11749f4b3541SRex Zhu static int ci_populate_single_memory_level(
11759f4b3541SRex Zhu struct pp_hwmgr *hwmgr,
11769f4b3541SRex Zhu uint32_t memory_clock,
11779f4b3541SRex Zhu SMU7_Discrete_MemoryLevel *memory_level
11789f4b3541SRex Zhu )
11799f4b3541SRex Zhu {
11809f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
11819f4b3541SRex Zhu int result = 0;
11829f4b3541SRex Zhu bool dll_state_on;
11839f4b3541SRex Zhu uint32_t mclk_edc_wr_enable_threshold = 40000;
11849f4b3541SRex Zhu uint32_t mclk_edc_enable_threshold = 40000;
11859f4b3541SRex Zhu uint32_t mclk_strobe_mode_threshold = 40000;
11869f4b3541SRex Zhu
11879f4b3541SRex Zhu if (hwmgr->dyn_state.vddc_dependency_on_mclk != NULL) {
11889f4b3541SRex Zhu result = ci_get_dependency_volt_by_clk(hwmgr,
11899f4b3541SRex Zhu hwmgr->dyn_state.vddc_dependency_on_mclk, memory_clock, &memory_level->MinVddc);
11909f4b3541SRex Zhu PP_ASSERT_WITH_CODE((0 == result),
11919f4b3541SRex Zhu "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result);
11929f4b3541SRex Zhu }
11939f4b3541SRex Zhu
11949f4b3541SRex Zhu if (NULL != hwmgr->dyn_state.vddci_dependency_on_mclk) {
11959f4b3541SRex Zhu result = ci_get_dependency_volt_by_clk(hwmgr,
11969f4b3541SRex Zhu hwmgr->dyn_state.vddci_dependency_on_mclk,
11979f4b3541SRex Zhu memory_clock,
11989f4b3541SRex Zhu &memory_level->MinVddci);
11999f4b3541SRex Zhu PP_ASSERT_WITH_CODE((0 == result),
12009f4b3541SRex Zhu "can not find MinVddci voltage value from memory VDDCI voltage dependency table", return result);
12019f4b3541SRex Zhu }
12029f4b3541SRex Zhu
12039f4b3541SRex Zhu if (NULL != hwmgr->dyn_state.mvdd_dependency_on_mclk) {
12049f4b3541SRex Zhu result = ci_get_dependency_volt_by_clk(hwmgr,
12059f4b3541SRex Zhu hwmgr->dyn_state.mvdd_dependency_on_mclk,
12069f4b3541SRex Zhu memory_clock,
12079f4b3541SRex Zhu &memory_level->MinMvdd);
12089f4b3541SRex Zhu PP_ASSERT_WITH_CODE((0 == result),
12099f4b3541SRex Zhu "can not find MinVddci voltage value from memory MVDD voltage dependency table", return result);
12109f4b3541SRex Zhu }
12119f4b3541SRex Zhu
12129f4b3541SRex Zhu memory_level->MinVddcPhases = 1;
12139f4b3541SRex Zhu
12149f4b3541SRex Zhu if (data->vddc_phase_shed_control) {
12159f4b3541SRex Zhu ci_populate_phase_value_based_on_mclk(hwmgr, hwmgr->dyn_state.vddc_phase_shed_limits_table,
12169f4b3541SRex Zhu memory_clock, &memory_level->MinVddcPhases);
12179f4b3541SRex Zhu }
12189f4b3541SRex Zhu
12199f4b3541SRex Zhu memory_level->EnabledForThrottle = 1;
12209f4b3541SRex Zhu memory_level->EnabledForActivity = 1;
1221c7429b3aSRex Zhu memory_level->UpH = data->current_profile_setting.mclk_up_hyst;
1222c7429b3aSRex Zhu memory_level->DownH = data->current_profile_setting.mclk_down_hyst;
12239f4b3541SRex Zhu memory_level->VoltageDownH = 0;
12249f4b3541SRex Zhu
12259f4b3541SRex Zhu /* Indicates maximum activity level for this performance level.*/
1226c7429b3aSRex Zhu memory_level->ActivityLevel = data->current_profile_setting.mclk_activity;
12279f4b3541SRex Zhu memory_level->StutterEnable = 0;
12289f4b3541SRex Zhu memory_level->StrobeEnable = 0;
12299f4b3541SRex Zhu memory_level->EdcReadEnable = 0;
12309f4b3541SRex Zhu memory_level->EdcWriteEnable = 0;
12319f4b3541SRex Zhu memory_level->RttEnable = 0;
12329f4b3541SRex Zhu
12339f4b3541SRex Zhu /* default set to low watermark. Highest level will be set to high later.*/
12349f4b3541SRex Zhu memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
12359f4b3541SRex Zhu
1236555fd70cSRex Zhu data->display_timing.num_existing_displays = hwmgr->display_config->num_display;
1237ec2e082aSAlex Deucher data->display_timing.vrefresh = hwmgr->display_config->vrefresh;
12389f4b3541SRex Zhu
12399f4b3541SRex Zhu /* stutter mode not support on ci */
12409f4b3541SRex Zhu
12419f4b3541SRex Zhu /* decide strobe mode*/
12429f4b3541SRex Zhu memory_level->StrobeEnable = (mclk_strobe_mode_threshold != 0) &&
12439f4b3541SRex Zhu (memory_clock <= mclk_strobe_mode_threshold);
12449f4b3541SRex Zhu
12459f4b3541SRex Zhu /* decide EDC mode and memory clock ratio*/
12469f4b3541SRex Zhu if (data->is_memory_gddr5) {
12479f4b3541SRex Zhu memory_level->StrobeRatio = ci_get_mclk_frequency_ratio(memory_clock,
12489f4b3541SRex Zhu memory_level->StrobeEnable);
12499f4b3541SRex Zhu
12509f4b3541SRex Zhu if ((mclk_edc_enable_threshold != 0) &&
12519f4b3541SRex Zhu (memory_clock > mclk_edc_enable_threshold)) {
12529f4b3541SRex Zhu memory_level->EdcReadEnable = 1;
12539f4b3541SRex Zhu }
12549f4b3541SRex Zhu
12559f4b3541SRex Zhu if ((mclk_edc_wr_enable_threshold != 0) &&
12569f4b3541SRex Zhu (memory_clock > mclk_edc_wr_enable_threshold)) {
12579f4b3541SRex Zhu memory_level->EdcWriteEnable = 1;
12589f4b3541SRex Zhu }
12599f4b3541SRex Zhu
12609f4b3541SRex Zhu if (memory_level->StrobeEnable) {
12619f4b3541SRex Zhu if (ci_get_mclk_frequency_ratio(memory_clock, 1) >=
12629f4b3541SRex Zhu ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf))
12639f4b3541SRex Zhu dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
12649f4b3541SRex Zhu else
12659f4b3541SRex Zhu dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0;
12669f4b3541SRex Zhu } else
12679f4b3541SRex Zhu dll_state_on = data->dll_default_on;
12689f4b3541SRex Zhu } else {
12699f4b3541SRex Zhu memory_level->StrobeRatio =
12709f4b3541SRex Zhu ci_get_ddr3_mclk_frequency_ratio(memory_clock);
12719f4b3541SRex Zhu dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
12729f4b3541SRex Zhu }
12739f4b3541SRex Zhu
12749f4b3541SRex Zhu result = ci_calculate_mclk_params(hwmgr,
12759f4b3541SRex Zhu memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on);
12769f4b3541SRex Zhu
12779f4b3541SRex Zhu if (0 == result) {
12789f4b3541SRex Zhu memory_level->MinVddc = PP_HOST_TO_SMC_UL(memory_level->MinVddc * VOLTAGE_SCALE);
12799f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinVddcPhases);
12809f4b3541SRex Zhu memory_level->MinVddci = PP_HOST_TO_SMC_UL(memory_level->MinVddci * VOLTAGE_SCALE);
12819f4b3541SRex Zhu memory_level->MinMvdd = PP_HOST_TO_SMC_UL(memory_level->MinMvdd * VOLTAGE_SCALE);
12829f4b3541SRex Zhu /* MCLK frequency in units of 10KHz*/
12839f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency);
12849f4b3541SRex Zhu /* Indicates maximum activity level for this performance level.*/
12859f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel);
12869f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl);
12879f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1);
12889f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2);
12899f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl);
12909f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl);
12919f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl);
12929f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl);
12939f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1);
12949f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2);
12959f4b3541SRex Zhu }
12969f4b3541SRex Zhu
12979f4b3541SRex Zhu return result;
12989f4b3541SRex Zhu }
12999f4b3541SRex Zhu
ci_populate_all_memory_levels(struct pp_hwmgr * hwmgr)130019048dc6SDave Airlie static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
13019f4b3541SRex Zhu {
13029f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1303b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
13049f4b3541SRex Zhu struct smu7_dpm_table *dpm_table = &data->dpm_table;
13059f4b3541SRex Zhu int result;
1306ada6770eSRex Zhu struct amdgpu_device *adev = hwmgr->adev;
13079f4b3541SRex Zhu uint32_t dev_id;
13089f4b3541SRex Zhu
13099f4b3541SRex Zhu uint32_t level_array_address = smu_data->dpm_table_start + offsetof(SMU7_Discrete_DpmTable, MemoryLevel);
13109f4b3541SRex Zhu uint32_t level_array_size = sizeof(SMU7_Discrete_MemoryLevel) * SMU7_MAX_LEVELS_MEMORY;
13119f4b3541SRex Zhu SMU7_Discrete_MemoryLevel *levels = smu_data->smc_state_table.MemoryLevel;
13129f4b3541SRex Zhu uint32_t i;
13139f4b3541SRex Zhu
13149f4b3541SRex Zhu memset(levels, 0x00, level_array_size);
13159f4b3541SRex Zhu
13169f4b3541SRex Zhu for (i = 0; i < dpm_table->mclk_table.count; i++) {
13179f4b3541SRex Zhu PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
13189f4b3541SRex Zhu "can not populate memory level as memory clock is zero", return -EINVAL);
13199f4b3541SRex Zhu result = ci_populate_single_memory_level(hwmgr, dpm_table->mclk_table.dpm_levels[i].value,
13209f4b3541SRex Zhu &(smu_data->smc_state_table.MemoryLevel[i]));
13219f4b3541SRex Zhu if (0 != result)
13229f4b3541SRex Zhu return result;
13239f4b3541SRex Zhu }
13249f4b3541SRex Zhu
13259f4b3541SRex Zhu smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
13269f4b3541SRex Zhu
1327ada6770eSRex Zhu dev_id = adev->pdev->device;
13289f4b3541SRex Zhu
13299f4b3541SRex Zhu if ((dpm_table->mclk_table.count >= 2)
13309f4b3541SRex Zhu && ((dev_id == 0x67B0) || (dev_id == 0x67B1))) {
13319f4b3541SRex Zhu smu_data->smc_state_table.MemoryLevel[1].MinVddci =
13329f4b3541SRex Zhu smu_data->smc_state_table.MemoryLevel[0].MinVddci;
13339f4b3541SRex Zhu smu_data->smc_state_table.MemoryLevel[1].MinMvdd =
13349f4b3541SRex Zhu smu_data->smc_state_table.MemoryLevel[0].MinMvdd;
13359f4b3541SRex Zhu }
13369f4b3541SRex Zhu smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
13379f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel);
13389f4b3541SRex Zhu
13399f4b3541SRex Zhu smu_data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count;
13409f4b3541SRex Zhu data->dpm_level_enable_mask.mclk_dpm_enable_mask = phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
13419f4b3541SRex Zhu smu_data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
13429f4b3541SRex Zhu
1343d3f8c0abSRex Zhu result = ci_copy_bytes_to_smc(hwmgr,
13449f4b3541SRex Zhu level_array_address, (uint8_t *)levels, (uint32_t)level_array_size,
13459f4b3541SRex Zhu SMC_RAM_END);
13469f4b3541SRex Zhu
13479f4b3541SRex Zhu return result;
13489f4b3541SRex Zhu }
13499f4b3541SRex Zhu
ci_populate_mvdd_value(struct pp_hwmgr * hwmgr,uint32_t mclk,SMU7_Discrete_VoltageLevel * voltage)13509f4b3541SRex Zhu static int ci_populate_mvdd_value(struct pp_hwmgr *hwmgr, uint32_t mclk,
13519f4b3541SRex Zhu SMU7_Discrete_VoltageLevel *voltage)
13529f4b3541SRex Zhu {
13539f4b3541SRex Zhu const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
13549f4b3541SRex Zhu
13559f4b3541SRex Zhu uint32_t i = 0;
13569f4b3541SRex Zhu
13579f4b3541SRex Zhu if (SMU7_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
13589f4b3541SRex Zhu /* find mvdd value which clock is more than request */
13599f4b3541SRex Zhu for (i = 0; i < hwmgr->dyn_state.mvdd_dependency_on_mclk->count; i++) {
13609f4b3541SRex Zhu if (mclk <= hwmgr->dyn_state.mvdd_dependency_on_mclk->entries[i].clk) {
13619f4b3541SRex Zhu /* Always round to higher voltage. */
13629f4b3541SRex Zhu voltage->Voltage = data->mvdd_voltage_table.entries[i].value;
13639f4b3541SRex Zhu break;
13649f4b3541SRex Zhu }
13659f4b3541SRex Zhu }
13669f4b3541SRex Zhu
13679f4b3541SRex Zhu PP_ASSERT_WITH_CODE(i < hwmgr->dyn_state.mvdd_dependency_on_mclk->count,
13689f4b3541SRex Zhu "MVDD Voltage is outside the supported range.", return -EINVAL);
13699f4b3541SRex Zhu
13709f4b3541SRex Zhu } else {
13719f4b3541SRex Zhu return -EINVAL;
13729f4b3541SRex Zhu }
13739f4b3541SRex Zhu
13749f4b3541SRex Zhu return 0;
13759f4b3541SRex Zhu }
13769f4b3541SRex Zhu
ci_populate_smc_acpi_level(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)13779f4b3541SRex Zhu static int ci_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
13789f4b3541SRex Zhu SMU7_Discrete_DpmTable *table)
13799f4b3541SRex Zhu {
13809f4b3541SRex Zhu int result = 0;
13819f4b3541SRex Zhu const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
13829f4b3541SRex Zhu struct pp_atomctrl_clock_dividers_vi dividers;
13839f4b3541SRex Zhu
13849f4b3541SRex Zhu SMU7_Discrete_VoltageLevel voltage_level;
13859f4b3541SRex Zhu uint32_t spll_func_cntl = data->clock_registers.vCG_SPLL_FUNC_CNTL;
13869f4b3541SRex Zhu uint32_t spll_func_cntl_2 = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
13879f4b3541SRex Zhu uint32_t dll_cntl = data->clock_registers.vDLL_CNTL;
13889f4b3541SRex Zhu uint32_t mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
13899f4b3541SRex Zhu
13909f4b3541SRex Zhu
13919f4b3541SRex Zhu /* The ACPI state should not do DPM on DC (or ever).*/
13929f4b3541SRex Zhu table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
13939f4b3541SRex Zhu
13949f4b3541SRex Zhu if (data->acpi_vddc)
13959f4b3541SRex Zhu table->ACPILevel.MinVddc = PP_HOST_TO_SMC_UL(data->acpi_vddc * VOLTAGE_SCALE);
13969f4b3541SRex Zhu else
13979f4b3541SRex Zhu table->ACPILevel.MinVddc = PP_HOST_TO_SMC_UL(data->min_vddc_in_pptable * VOLTAGE_SCALE);
13989f4b3541SRex Zhu
13999f4b3541SRex Zhu table->ACPILevel.MinVddcPhases = data->vddc_phase_shed_control ? 0 : 1;
14009f4b3541SRex Zhu /* assign zero for now*/
14019f4b3541SRex Zhu table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr);
14029f4b3541SRex Zhu
14039f4b3541SRex Zhu /* get the engine clock dividers for this clock value*/
14049f4b3541SRex Zhu result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
14059f4b3541SRex Zhu table->ACPILevel.SclkFrequency, ÷rs);
14069f4b3541SRex Zhu
14079f4b3541SRex Zhu PP_ASSERT_WITH_CODE(result == 0,
14089f4b3541SRex Zhu "Error retrieving Engine Clock dividers from VBIOS.", return result);
14099f4b3541SRex Zhu
14109f4b3541SRex Zhu /* divider ID for required SCLK*/
14119f4b3541SRex Zhu table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
14129f4b3541SRex Zhu table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
14139f4b3541SRex Zhu table->ACPILevel.DeepSleepDivId = 0;
14149f4b3541SRex Zhu
14159f4b3541SRex Zhu spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
14169f4b3541SRex Zhu CG_SPLL_FUNC_CNTL, SPLL_PWRON, 0);
14179f4b3541SRex Zhu spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
14189f4b3541SRex Zhu CG_SPLL_FUNC_CNTL, SPLL_RESET, 1);
14199f4b3541SRex Zhu spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2,
14209f4b3541SRex Zhu CG_SPLL_FUNC_CNTL_2, SCLK_MUX_SEL, 4);
14219f4b3541SRex Zhu
14229f4b3541SRex Zhu table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
14239f4b3541SRex Zhu table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
14249f4b3541SRex Zhu table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
14259f4b3541SRex Zhu table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
14269f4b3541SRex Zhu table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
14279f4b3541SRex Zhu table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
14289f4b3541SRex Zhu table->ACPILevel.CcPwrDynRm = 0;
14299f4b3541SRex Zhu table->ACPILevel.CcPwrDynRm1 = 0;
14309f4b3541SRex Zhu
14319f4b3541SRex Zhu /* For various features to be enabled/disabled while this level is active.*/
14329f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
14339f4b3541SRex Zhu /* SCLK frequency in units of 10KHz*/
14349f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
14359f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
14369f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
14379f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
14389f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
14399f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
14409f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
14419f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
14429f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
14439f4b3541SRex Zhu
14449f4b3541SRex Zhu
14459f4b3541SRex Zhu /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
14469f4b3541SRex Zhu table->MemoryACPILevel.MinVddc = table->ACPILevel.MinVddc;
14479f4b3541SRex Zhu table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;
14489f4b3541SRex Zhu
14499f4b3541SRex Zhu if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
14509f4b3541SRex Zhu table->MemoryACPILevel.MinVddci = table->MemoryACPILevel.MinVddc;
14519f4b3541SRex Zhu else {
14529f4b3541SRex Zhu if (data->acpi_vddci != 0)
14539f4b3541SRex Zhu table->MemoryACPILevel.MinVddci = PP_HOST_TO_SMC_UL(data->acpi_vddci * VOLTAGE_SCALE);
14549f4b3541SRex Zhu else
14559f4b3541SRex Zhu table->MemoryACPILevel.MinVddci = PP_HOST_TO_SMC_UL(data->min_vddci_in_pptable * VOLTAGE_SCALE);
14569f4b3541SRex Zhu }
14579f4b3541SRex Zhu
14589f4b3541SRex Zhu if (0 == ci_populate_mvdd_value(hwmgr, 0, &voltage_level))
14599f4b3541SRex Zhu table->MemoryACPILevel.MinMvdd =
14609f4b3541SRex Zhu PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE);
14619f4b3541SRex Zhu else
14629f4b3541SRex Zhu table->MemoryACPILevel.MinMvdd = 0;
14639f4b3541SRex Zhu
14649f4b3541SRex Zhu /* Force reset on DLL*/
14659f4b3541SRex Zhu mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
14669f4b3541SRex Zhu MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1);
14679f4b3541SRex Zhu mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
14689f4b3541SRex Zhu MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1);
14699f4b3541SRex Zhu
14709f4b3541SRex Zhu /* Disable DLL in ACPIState*/
14719f4b3541SRex Zhu mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
14729f4b3541SRex Zhu MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0);
14739f4b3541SRex Zhu mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
14749f4b3541SRex Zhu MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0);
14759f4b3541SRex Zhu
14769f4b3541SRex Zhu /* Enable DLL bypass signal*/
14779f4b3541SRex Zhu dll_cntl = PHM_SET_FIELD(dll_cntl,
14789f4b3541SRex Zhu DLL_CNTL, MRDCK0_BYPASS, 0);
14799f4b3541SRex Zhu dll_cntl = PHM_SET_FIELD(dll_cntl,
14809f4b3541SRex Zhu DLL_CNTL, MRDCK1_BYPASS, 0);
14819f4b3541SRex Zhu
14829f4b3541SRex Zhu table->MemoryACPILevel.DllCntl =
14839f4b3541SRex Zhu PP_HOST_TO_SMC_UL(dll_cntl);
14849f4b3541SRex Zhu table->MemoryACPILevel.MclkPwrmgtCntl =
14859f4b3541SRex Zhu PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl);
14869f4b3541SRex Zhu table->MemoryACPILevel.MpllAdFuncCntl =
14879f4b3541SRex Zhu PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL);
14889f4b3541SRex Zhu table->MemoryACPILevel.MpllDqFuncCntl =
14899f4b3541SRex Zhu PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL);
14909f4b3541SRex Zhu table->MemoryACPILevel.MpllFuncCntl =
14919f4b3541SRex Zhu PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL);
14929f4b3541SRex Zhu table->MemoryACPILevel.MpllFuncCntl_1 =
14939f4b3541SRex Zhu PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1);
14949f4b3541SRex Zhu table->MemoryACPILevel.MpllFuncCntl_2 =
14959f4b3541SRex Zhu PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2);
14969f4b3541SRex Zhu table->MemoryACPILevel.MpllSs1 =
14979f4b3541SRex Zhu PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1);
14989f4b3541SRex Zhu table->MemoryACPILevel.MpllSs2 =
14999f4b3541SRex Zhu PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2);
15009f4b3541SRex Zhu
15019f4b3541SRex Zhu table->MemoryACPILevel.EnabledForThrottle = 0;
15029f4b3541SRex Zhu table->MemoryACPILevel.EnabledForActivity = 0;
15039f4b3541SRex Zhu table->MemoryACPILevel.UpH = 0;
15049f4b3541SRex Zhu table->MemoryACPILevel.DownH = 100;
15059f4b3541SRex Zhu table->MemoryACPILevel.VoltageDownH = 0;
15069f4b3541SRex Zhu /* Indicates maximum activity level for this performance level.*/
1507c7429b3aSRex Zhu table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity);
15089f4b3541SRex Zhu
15099f4b3541SRex Zhu table->MemoryACPILevel.StutterEnable = 0;
15109f4b3541SRex Zhu table->MemoryACPILevel.StrobeEnable = 0;
15119f4b3541SRex Zhu table->MemoryACPILevel.EdcReadEnable = 0;
15129f4b3541SRex Zhu table->MemoryACPILevel.EdcWriteEnable = 0;
15139f4b3541SRex Zhu table->MemoryACPILevel.RttEnable = 0;
15149f4b3541SRex Zhu
15159f4b3541SRex Zhu return result;
15169f4b3541SRex Zhu }
15179f4b3541SRex Zhu
ci_populate_smc_uvd_level(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)15189f4b3541SRex Zhu static int ci_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
15199f4b3541SRex Zhu SMU7_Discrete_DpmTable *table)
15209f4b3541SRex Zhu {
15219f4b3541SRex Zhu int result = 0;
15229f4b3541SRex Zhu uint8_t count;
15239f4b3541SRex Zhu struct pp_atomctrl_clock_dividers_vi dividers;
15249f4b3541SRex Zhu struct phm_uvd_clock_voltage_dependency_table *uvd_table =
15259f4b3541SRex Zhu hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
15269f4b3541SRex Zhu
15279f4b3541SRex Zhu table->UvdLevelCount = (uint8_t)(uvd_table->count);
15289f4b3541SRex Zhu
15299f4b3541SRex Zhu for (count = 0; count < table->UvdLevelCount; count++) {
15309f4b3541SRex Zhu table->UvdLevel[count].VclkFrequency =
15319f4b3541SRex Zhu uvd_table->entries[count].vclk;
15329f4b3541SRex Zhu table->UvdLevel[count].DclkFrequency =
15339f4b3541SRex Zhu uvd_table->entries[count].dclk;
15349f4b3541SRex Zhu table->UvdLevel[count].MinVddc =
15359f4b3541SRex Zhu uvd_table->entries[count].v * VOLTAGE_SCALE;
15369f4b3541SRex Zhu table->UvdLevel[count].MinVddcPhases = 1;
15379f4b3541SRex Zhu
15389f4b3541SRex Zhu result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
15399f4b3541SRex Zhu table->UvdLevel[count].VclkFrequency, ÷rs);
15409f4b3541SRex Zhu PP_ASSERT_WITH_CODE((0 == result),
15419f4b3541SRex Zhu "can not find divide id for Vclk clock", return result);
15429f4b3541SRex Zhu
15439f4b3541SRex Zhu table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
15449f4b3541SRex Zhu
15459f4b3541SRex Zhu result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
15469f4b3541SRex Zhu table->UvdLevel[count].DclkFrequency, ÷rs);
15479f4b3541SRex Zhu PP_ASSERT_WITH_CODE((0 == result),
15489f4b3541SRex Zhu "can not find divide id for Dclk clock", return result);
15499f4b3541SRex Zhu
15509f4b3541SRex Zhu table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
15519f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
15529f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
15539f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(table->UvdLevel[count].MinVddc);
15549f4b3541SRex Zhu }
15559f4b3541SRex Zhu
15569f4b3541SRex Zhu return result;
15579f4b3541SRex Zhu }
15589f4b3541SRex Zhu
ci_populate_smc_vce_level(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)15599f4b3541SRex Zhu static int ci_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
15609f4b3541SRex Zhu SMU7_Discrete_DpmTable *table)
15619f4b3541SRex Zhu {
15629f4b3541SRex Zhu int result = -EINVAL;
15639f4b3541SRex Zhu uint8_t count;
15649f4b3541SRex Zhu struct pp_atomctrl_clock_dividers_vi dividers;
15659f4b3541SRex Zhu struct phm_vce_clock_voltage_dependency_table *vce_table =
15669f4b3541SRex Zhu hwmgr->dyn_state.vce_clock_voltage_dependency_table;
15679f4b3541SRex Zhu
15689f4b3541SRex Zhu table->VceLevelCount = (uint8_t)(vce_table->count);
15699f4b3541SRex Zhu table->VceBootLevel = 0;
15709f4b3541SRex Zhu
15719f4b3541SRex Zhu for (count = 0; count < table->VceLevelCount; count++) {
15729f4b3541SRex Zhu table->VceLevel[count].Frequency = vce_table->entries[count].evclk;
15739f4b3541SRex Zhu table->VceLevel[count].MinVoltage =
15749f4b3541SRex Zhu vce_table->entries[count].v * VOLTAGE_SCALE;
15759f4b3541SRex Zhu table->VceLevel[count].MinPhases = 1;
15769f4b3541SRex Zhu
15779f4b3541SRex Zhu result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
15789f4b3541SRex Zhu table->VceLevel[count].Frequency, ÷rs);
15799f4b3541SRex Zhu PP_ASSERT_WITH_CODE((0 == result),
15809f4b3541SRex Zhu "can not find divide id for VCE engine clock",
15819f4b3541SRex Zhu return result);
15829f4b3541SRex Zhu
15839f4b3541SRex Zhu table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
15849f4b3541SRex Zhu
15859f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
15869f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(table->VceLevel[count].MinVoltage);
15879f4b3541SRex Zhu }
15889f4b3541SRex Zhu return result;
15899f4b3541SRex Zhu }
15909f4b3541SRex Zhu
ci_populate_smc_acp_level(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)15919f4b3541SRex Zhu static int ci_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
15929f4b3541SRex Zhu SMU7_Discrete_DpmTable *table)
15939f4b3541SRex Zhu {
15949f4b3541SRex Zhu int result = -EINVAL;
15959f4b3541SRex Zhu uint8_t count;
15969f4b3541SRex Zhu struct pp_atomctrl_clock_dividers_vi dividers;
15979f4b3541SRex Zhu struct phm_acp_clock_voltage_dependency_table *acp_table =
15989f4b3541SRex Zhu hwmgr->dyn_state.acp_clock_voltage_dependency_table;
15999f4b3541SRex Zhu
16009f4b3541SRex Zhu table->AcpLevelCount = (uint8_t)(acp_table->count);
16019f4b3541SRex Zhu table->AcpBootLevel = 0;
16029f4b3541SRex Zhu
16039f4b3541SRex Zhu for (count = 0; count < table->AcpLevelCount; count++) {
16049f4b3541SRex Zhu table->AcpLevel[count].Frequency = acp_table->entries[count].acpclk;
16059f4b3541SRex Zhu table->AcpLevel[count].MinVoltage = acp_table->entries[count].v;
16069f4b3541SRex Zhu table->AcpLevel[count].MinPhases = 1;
16079f4b3541SRex Zhu
16089f4b3541SRex Zhu result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
16099f4b3541SRex Zhu table->AcpLevel[count].Frequency, ÷rs);
16109f4b3541SRex Zhu PP_ASSERT_WITH_CODE((0 == result),
16119f4b3541SRex Zhu "can not find divide id for engine clock", return result);
16129f4b3541SRex Zhu
16139f4b3541SRex Zhu table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
16149f4b3541SRex Zhu
16159f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
16169f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(table->AcpLevel[count].MinVoltage);
16179f4b3541SRex Zhu }
16189f4b3541SRex Zhu return result;
16199f4b3541SRex Zhu }
16209f4b3541SRex Zhu
ci_populate_memory_timing_parameters(struct pp_hwmgr * hwmgr,uint32_t engine_clock,uint32_t memory_clock,struct SMU7_Discrete_MCArbDramTimingTableEntry * arb_regs)16219f4b3541SRex Zhu static int ci_populate_memory_timing_parameters(
16229f4b3541SRex Zhu struct pp_hwmgr *hwmgr,
16239f4b3541SRex Zhu uint32_t engine_clock,
16249f4b3541SRex Zhu uint32_t memory_clock,
16259f4b3541SRex Zhu struct SMU7_Discrete_MCArbDramTimingTableEntry *arb_regs
16269f4b3541SRex Zhu )
16279f4b3541SRex Zhu {
16289f4b3541SRex Zhu uint32_t dramTiming;
16299f4b3541SRex Zhu uint32_t dramTiming2;
16309f4b3541SRex Zhu uint32_t burstTime;
16319f4b3541SRex Zhu int result;
16329f4b3541SRex Zhu
16339f4b3541SRex Zhu result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
16349f4b3541SRex Zhu engine_clock, memory_clock);
16359f4b3541SRex Zhu
16369f4b3541SRex Zhu PP_ASSERT_WITH_CODE(result == 0,
16379f4b3541SRex Zhu "Error calling VBIOS to set DRAM_TIMING.", return result);
16389f4b3541SRex Zhu
16399f4b3541SRex Zhu dramTiming = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
16409f4b3541SRex Zhu dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
16419f4b3541SRex Zhu burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
16429f4b3541SRex Zhu
16439f4b3541SRex Zhu arb_regs->McArbDramTiming = PP_HOST_TO_SMC_UL(dramTiming);
16449f4b3541SRex Zhu arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2);
16459f4b3541SRex Zhu arb_regs->McArbBurstTime = (uint8_t)burstTime;
16469f4b3541SRex Zhu
16479f4b3541SRex Zhu return 0;
16489f4b3541SRex Zhu }
16499f4b3541SRex Zhu
ci_program_memory_timing_parameters(struct pp_hwmgr * hwmgr)16509f4b3541SRex Zhu static int ci_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
16519f4b3541SRex Zhu {
16529f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1653b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
16549f4b3541SRex Zhu int result = 0;
16559f4b3541SRex Zhu SMU7_Discrete_MCArbDramTimingTable arb_regs;
16569f4b3541SRex Zhu uint32_t i, j;
16579f4b3541SRex Zhu
16589f4b3541SRex Zhu memset(&arb_regs, 0x00, sizeof(SMU7_Discrete_MCArbDramTimingTable));
16599f4b3541SRex Zhu
16609f4b3541SRex Zhu for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
16619f4b3541SRex Zhu for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
16629f4b3541SRex Zhu result = ci_populate_memory_timing_parameters
16639f4b3541SRex Zhu (hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
16649f4b3541SRex Zhu data->dpm_table.mclk_table.dpm_levels[j].value,
16659f4b3541SRex Zhu &arb_regs.entries[i][j]);
16669f4b3541SRex Zhu
16679f4b3541SRex Zhu if (0 != result)
16689f4b3541SRex Zhu break;
16699f4b3541SRex Zhu }
16709f4b3541SRex Zhu }
16719f4b3541SRex Zhu
16729f4b3541SRex Zhu if (0 == result) {
16739f4b3541SRex Zhu result = ci_copy_bytes_to_smc(
1674d3f8c0abSRex Zhu hwmgr,
16759f4b3541SRex Zhu smu_data->arb_table_start,
16769f4b3541SRex Zhu (uint8_t *)&arb_regs,
16779f4b3541SRex Zhu sizeof(SMU7_Discrete_MCArbDramTimingTable),
16789f4b3541SRex Zhu SMC_RAM_END
16799f4b3541SRex Zhu );
16809f4b3541SRex Zhu }
16819f4b3541SRex Zhu
16829f4b3541SRex Zhu return result;
16839f4b3541SRex Zhu }
16849f4b3541SRex Zhu
ci_populate_smc_boot_level(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)16859f4b3541SRex Zhu static int ci_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
16869f4b3541SRex Zhu SMU7_Discrete_DpmTable *table)
16879f4b3541SRex Zhu {
16889f4b3541SRex Zhu int result = 0;
16899f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1690b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
16919f4b3541SRex Zhu
16929f4b3541SRex Zhu table->GraphicsBootLevel = 0;
16939f4b3541SRex Zhu table->MemoryBootLevel = 0;
16949f4b3541SRex Zhu
16959f4b3541SRex Zhu /* find boot level from dpm table*/
16969f4b3541SRex Zhu result = phm_find_boot_level(&(data->dpm_table.sclk_table),
16979f4b3541SRex Zhu data->vbios_boot_state.sclk_bootup_value,
16989f4b3541SRex Zhu (uint32_t *)&(smu_data->smc_state_table.GraphicsBootLevel));
16999f4b3541SRex Zhu
17009f4b3541SRex Zhu if (0 != result) {
17019f4b3541SRex Zhu smu_data->smc_state_table.GraphicsBootLevel = 0;
17024f42a2ddSJoe Perches pr_err("VBIOS did not find boot engine clock value in dependency table. Using Graphics DPM level 0!\n");
17039f4b3541SRex Zhu result = 0;
17049f4b3541SRex Zhu }
17059f4b3541SRex Zhu
17069f4b3541SRex Zhu result = phm_find_boot_level(&(data->dpm_table.mclk_table),
17079f4b3541SRex Zhu data->vbios_boot_state.mclk_bootup_value,
17089f4b3541SRex Zhu (uint32_t *)&(smu_data->smc_state_table.MemoryBootLevel));
17099f4b3541SRex Zhu
17109f4b3541SRex Zhu if (0 != result) {
17119f4b3541SRex Zhu smu_data->smc_state_table.MemoryBootLevel = 0;
17124f42a2ddSJoe Perches pr_err("VBIOS did not find boot engine clock value in dependency table. Using Memory DPM level 0!\n");
17139f4b3541SRex Zhu result = 0;
17149f4b3541SRex Zhu }
17159f4b3541SRex Zhu
17169f4b3541SRex Zhu table->BootVddc = data->vbios_boot_state.vddc_bootup_value;
17179f4b3541SRex Zhu table->BootVddci = data->vbios_boot_state.vddci_bootup_value;
17189f4b3541SRex Zhu table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value;
17199f4b3541SRex Zhu
17209f4b3541SRex Zhu return result;
17219f4b3541SRex Zhu }
17229f4b3541SRex Zhu
ci_populate_mc_reg_address(struct pp_hwmgr * hwmgr,SMU7_Discrete_MCRegisters * mc_reg_table)1723d3f8c0abSRex Zhu static int ci_populate_mc_reg_address(struct pp_hwmgr *hwmgr,
17249f4b3541SRex Zhu SMU7_Discrete_MCRegisters *mc_reg_table)
17259f4b3541SRex Zhu {
1726b3b03052SRex Zhu const struct ci_smumgr *smu_data = (struct ci_smumgr *)hwmgr->smu_backend;
17279f4b3541SRex Zhu
17289f4b3541SRex Zhu uint32_t i, j;
17299f4b3541SRex Zhu
17309f4b3541SRex Zhu for (i = 0, j = 0; j < smu_data->mc_reg_table.last; j++) {
17319f4b3541SRex Zhu if (smu_data->mc_reg_table.validflag & 1<<j) {
17329f4b3541SRex Zhu PP_ASSERT_WITH_CODE(i < SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE,
17339f4b3541SRex Zhu "Index of mc_reg_table->address[] array out of boundary", return -EINVAL);
17349f4b3541SRex Zhu mc_reg_table->address[i].s0 =
17359f4b3541SRex Zhu PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s0);
17369f4b3541SRex Zhu mc_reg_table->address[i].s1 =
17379f4b3541SRex Zhu PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s1);
17389f4b3541SRex Zhu i++;
17399f4b3541SRex Zhu }
17409f4b3541SRex Zhu }
17419f4b3541SRex Zhu
17429f4b3541SRex Zhu mc_reg_table->last = (uint8_t)i;
17439f4b3541SRex Zhu
17449f4b3541SRex Zhu return 0;
17459f4b3541SRex Zhu }
17469f4b3541SRex Zhu
ci_convert_mc_registers(const struct ci_mc_reg_entry * entry,SMU7_Discrete_MCRegisterSet * data,uint32_t num_entries,uint32_t valid_flag)17479f4b3541SRex Zhu static void ci_convert_mc_registers(
17489f4b3541SRex Zhu const struct ci_mc_reg_entry *entry,
17499f4b3541SRex Zhu SMU7_Discrete_MCRegisterSet *data,
17509f4b3541SRex Zhu uint32_t num_entries, uint32_t valid_flag)
17519f4b3541SRex Zhu {
17529f4b3541SRex Zhu uint32_t i, j;
17539f4b3541SRex Zhu
17549f4b3541SRex Zhu for (i = 0, j = 0; j < num_entries; j++) {
17559f4b3541SRex Zhu if (valid_flag & 1<<j) {
17569f4b3541SRex Zhu data->value[i] = PP_HOST_TO_SMC_UL(entry->mc_data[j]);
17579f4b3541SRex Zhu i++;
17589f4b3541SRex Zhu }
17599f4b3541SRex Zhu }
17609f4b3541SRex Zhu }
17619f4b3541SRex Zhu
ci_convert_mc_reg_table_entry_to_smc(struct pp_hwmgr * hwmgr,const uint32_t memory_clock,SMU7_Discrete_MCRegisterSet * mc_reg_table_data)17629f4b3541SRex Zhu static int ci_convert_mc_reg_table_entry_to_smc(
1763d3f8c0abSRex Zhu struct pp_hwmgr *hwmgr,
17649f4b3541SRex Zhu const uint32_t memory_clock,
17659f4b3541SRex Zhu SMU7_Discrete_MCRegisterSet *mc_reg_table_data
17669f4b3541SRex Zhu )
17679f4b3541SRex Zhu {
1768b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
17699f4b3541SRex Zhu uint32_t i = 0;
17709f4b3541SRex Zhu
17719f4b3541SRex Zhu for (i = 0; i < smu_data->mc_reg_table.num_entries; i++) {
17729f4b3541SRex Zhu if (memory_clock <=
17739f4b3541SRex Zhu smu_data->mc_reg_table.mc_reg_table_entry[i].mclk_max) {
17749f4b3541SRex Zhu break;
17759f4b3541SRex Zhu }
17769f4b3541SRex Zhu }
17779f4b3541SRex Zhu
17789f4b3541SRex Zhu if ((i == smu_data->mc_reg_table.num_entries) && (i > 0))
17799f4b3541SRex Zhu --i;
17809f4b3541SRex Zhu
17819f4b3541SRex Zhu ci_convert_mc_registers(&smu_data->mc_reg_table.mc_reg_table_entry[i],
17829f4b3541SRex Zhu mc_reg_table_data, smu_data->mc_reg_table.last,
17839f4b3541SRex Zhu smu_data->mc_reg_table.validflag);
17849f4b3541SRex Zhu
17859f4b3541SRex Zhu return 0;
17869f4b3541SRex Zhu }
17879f4b3541SRex Zhu
ci_convert_mc_reg_table_to_smc(struct pp_hwmgr * hwmgr,SMU7_Discrete_MCRegisters * mc_regs)17889f4b3541SRex Zhu static int ci_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr,
17899f4b3541SRex Zhu SMU7_Discrete_MCRegisters *mc_regs)
17909f4b3541SRex Zhu {
17919f4b3541SRex Zhu int result = 0;
17929f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
17939f4b3541SRex Zhu int res;
17949f4b3541SRex Zhu uint32_t i;
17959f4b3541SRex Zhu
17969f4b3541SRex Zhu for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
17979f4b3541SRex Zhu res = ci_convert_mc_reg_table_entry_to_smc(
1798d3f8c0abSRex Zhu hwmgr,
17999f4b3541SRex Zhu data->dpm_table.mclk_table.dpm_levels[i].value,
18009f4b3541SRex Zhu &mc_regs->data[i]
18019f4b3541SRex Zhu );
18029f4b3541SRex Zhu
18039f4b3541SRex Zhu if (0 != res)
18049f4b3541SRex Zhu result = res;
18059f4b3541SRex Zhu }
18069f4b3541SRex Zhu
18079f4b3541SRex Zhu return result;
18089f4b3541SRex Zhu }
18099f4b3541SRex Zhu
ci_update_and_upload_mc_reg_table(struct pp_hwmgr * hwmgr)18109f4b3541SRex Zhu static int ci_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr)
18119f4b3541SRex Zhu {
1812b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
18139f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
18149f4b3541SRex Zhu uint32_t address;
18159f4b3541SRex Zhu int32_t result;
18169f4b3541SRex Zhu
18179f4b3541SRex Zhu if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
18189f4b3541SRex Zhu return 0;
18199f4b3541SRex Zhu
18209f4b3541SRex Zhu
18219f4b3541SRex Zhu memset(&smu_data->mc_regs, 0, sizeof(SMU7_Discrete_MCRegisters));
18229f4b3541SRex Zhu
18239f4b3541SRex Zhu result = ci_convert_mc_reg_table_to_smc(hwmgr, &(smu_data->mc_regs));
18249f4b3541SRex Zhu
18259f4b3541SRex Zhu if (result != 0)
18269f4b3541SRex Zhu return result;
18279f4b3541SRex Zhu
18289f4b3541SRex Zhu address = smu_data->mc_reg_table_start + (uint32_t)offsetof(SMU7_Discrete_MCRegisters, data[0]);
18299f4b3541SRex Zhu
1830d3f8c0abSRex Zhu return ci_copy_bytes_to_smc(hwmgr, address,
18319f4b3541SRex Zhu (uint8_t *)&smu_data->mc_regs.data[0],
18329f4b3541SRex Zhu sizeof(SMU7_Discrete_MCRegisterSet) * data->dpm_table.mclk_table.count,
18339f4b3541SRex Zhu SMC_RAM_END);
18349f4b3541SRex Zhu }
18359f4b3541SRex Zhu
ci_populate_initial_mc_reg_table(struct pp_hwmgr * hwmgr)18369f4b3541SRex Zhu static int ci_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr)
18379f4b3541SRex Zhu {
18389f4b3541SRex Zhu int result;
1839b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
18409f4b3541SRex Zhu
18419f4b3541SRex Zhu memset(&smu_data->mc_regs, 0x00, sizeof(SMU7_Discrete_MCRegisters));
1842d3f8c0abSRex Zhu result = ci_populate_mc_reg_address(hwmgr, &(smu_data->mc_regs));
18439f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
18449f4b3541SRex Zhu "Failed to initialize MCRegTable for the MC register addresses!", return result;);
18459f4b3541SRex Zhu
18469f4b3541SRex Zhu result = ci_convert_mc_reg_table_to_smc(hwmgr, &smu_data->mc_regs);
18479f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
18489f4b3541SRex Zhu "Failed to initialize MCRegTable for driver state!", return result;);
18499f4b3541SRex Zhu
1850d3f8c0abSRex Zhu return ci_copy_bytes_to_smc(hwmgr, smu_data->mc_reg_table_start,
18519f4b3541SRex Zhu (uint8_t *)&smu_data->mc_regs, sizeof(SMU7_Discrete_MCRegisters), SMC_RAM_END);
18529f4b3541SRex Zhu }
18539f4b3541SRex Zhu
ci_populate_smc_initial_state(struct pp_hwmgr * hwmgr)18549f4b3541SRex Zhu static int ci_populate_smc_initial_state(struct pp_hwmgr *hwmgr)
18559f4b3541SRex Zhu {
18569f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1857b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
18589f4b3541SRex Zhu uint8_t count, level;
18599f4b3541SRex Zhu
18609f4b3541SRex Zhu count = (uint8_t)(hwmgr->dyn_state.vddc_dependency_on_sclk->count);
18619f4b3541SRex Zhu
18629f4b3541SRex Zhu for (level = 0; level < count; level++) {
18639f4b3541SRex Zhu if (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[level].clk
18649f4b3541SRex Zhu >= data->vbios_boot_state.sclk_bootup_value) {
18659f4b3541SRex Zhu smu_data->smc_state_table.GraphicsBootLevel = level;
18669f4b3541SRex Zhu break;
18679f4b3541SRex Zhu }
18689f4b3541SRex Zhu }
18699f4b3541SRex Zhu
18709f4b3541SRex Zhu count = (uint8_t)(hwmgr->dyn_state.vddc_dependency_on_mclk->count);
18719f4b3541SRex Zhu
18729f4b3541SRex Zhu for (level = 0; level < count; level++) {
18739f4b3541SRex Zhu if (hwmgr->dyn_state.vddc_dependency_on_mclk->entries[level].clk
18749f4b3541SRex Zhu >= data->vbios_boot_state.mclk_bootup_value) {
18759f4b3541SRex Zhu smu_data->smc_state_table.MemoryBootLevel = level;
18769f4b3541SRex Zhu break;
18779f4b3541SRex Zhu }
18789f4b3541SRex Zhu }
18799f4b3541SRex Zhu
18809f4b3541SRex Zhu return 0;
18819f4b3541SRex Zhu }
18829f4b3541SRex Zhu
ci_populate_smc_svi2_config(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)18839f4b3541SRex Zhu static int ci_populate_smc_svi2_config(struct pp_hwmgr *hwmgr,
18849f4b3541SRex Zhu SMU7_Discrete_DpmTable *table)
18859f4b3541SRex Zhu {
18869f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
18879f4b3541SRex Zhu
18889f4b3541SRex Zhu if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control)
18899f4b3541SRex Zhu table->SVI2Enable = 1;
18909f4b3541SRex Zhu else
18919f4b3541SRex Zhu table->SVI2Enable = 0;
18929f4b3541SRex Zhu return 0;
18939f4b3541SRex Zhu }
18949f4b3541SRex Zhu
ci_start_smc(struct pp_hwmgr * hwmgr)1895d3f8c0abSRex Zhu static int ci_start_smc(struct pp_hwmgr *hwmgr)
18969f4b3541SRex Zhu {
18979f4b3541SRex Zhu /* set smc instruct start point at 0x0 */
1898d3f8c0abSRex Zhu ci_program_jump_on_start(hwmgr);
18999f4b3541SRex Zhu
19009f4b3541SRex Zhu /* enable smc clock */
1901fbabae46SRex Zhu PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
19029f4b3541SRex Zhu
1903fbabae46SRex Zhu PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
19049f4b3541SRex Zhu
19050041e600SRex Zhu PHM_WAIT_INDIRECT_FIELD(hwmgr, SMC_IND, FIRMWARE_FLAGS,
19069f4b3541SRex Zhu INTERRUPTS_ENABLED, 1);
19079f4b3541SRex Zhu
19089f4b3541SRex Zhu return 0;
19099f4b3541SRex Zhu }
19109f4b3541SRex Zhu
ci_populate_vr_config(struct pp_hwmgr * hwmgr,SMU7_Discrete_DpmTable * table)191153241e01SRex Zhu static int ci_populate_vr_config(struct pp_hwmgr *hwmgr, SMU7_Discrete_DpmTable *table)
191253241e01SRex Zhu {
191353241e01SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
191453241e01SRex Zhu uint16_t config;
191553241e01SRex Zhu
191653241e01SRex Zhu config = VR_SVI2_PLANE_1;
191753241e01SRex Zhu table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
191853241e01SRex Zhu
191953241e01SRex Zhu if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
192053241e01SRex Zhu config = VR_SVI2_PLANE_2;
192153241e01SRex Zhu table->VRConfig |= config;
192253241e01SRex Zhu } else {
192353241e01SRex Zhu pr_info("VDDCshould be on SVI2 controller!");
192453241e01SRex Zhu }
192553241e01SRex Zhu
192653241e01SRex Zhu if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
192753241e01SRex Zhu config = VR_SVI2_PLANE_2;
192853241e01SRex Zhu table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
192953241e01SRex Zhu } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
193053241e01SRex Zhu config = VR_SMIO_PATTERN_1;
193153241e01SRex Zhu table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
193253241e01SRex Zhu }
193353241e01SRex Zhu
193453241e01SRex Zhu if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
193553241e01SRex Zhu config = VR_SMIO_PATTERN_2;
193653241e01SRex Zhu table->VRConfig |= (config<<VRCONF_MVDD_SHIFT);
193753241e01SRex Zhu }
193853241e01SRex Zhu
193953241e01SRex Zhu return 0;
194053241e01SRex Zhu }
194153241e01SRex Zhu
ci_init_smc_table(struct pp_hwmgr * hwmgr)194219048dc6SDave Airlie static int ci_init_smc_table(struct pp_hwmgr *hwmgr)
19439f4b3541SRex Zhu {
19449f4b3541SRex Zhu int result;
19459f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1946b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
19479f4b3541SRex Zhu SMU7_Discrete_DpmTable *table = &(smu_data->smc_state_table);
19489f4b3541SRex Zhu struct pp_atomctrl_gpio_pin_assignment gpio_pin;
19499f4b3541SRex Zhu u32 i;
19509f4b3541SRex Zhu
19519f4b3541SRex Zhu ci_initialize_power_tune_defaults(hwmgr);
19529f4b3541SRex Zhu memset(&(smu_data->smc_state_table), 0x00, sizeof(smu_data->smc_state_table));
19539f4b3541SRex Zhu
19549f4b3541SRex Zhu if (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control)
19559f4b3541SRex Zhu ci_populate_smc_voltage_tables(hwmgr, table);
19569f4b3541SRex Zhu
19579f4b3541SRex Zhu if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
19589f4b3541SRex Zhu PHM_PlatformCaps_AutomaticDCTransition))
19599f4b3541SRex Zhu table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
19609f4b3541SRex Zhu
19619f4b3541SRex Zhu
19629f4b3541SRex Zhu if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
19639f4b3541SRex Zhu PHM_PlatformCaps_StepVddc))
19649f4b3541SRex Zhu table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
19659f4b3541SRex Zhu
19669f4b3541SRex Zhu if (data->is_memory_gddr5)
19679f4b3541SRex Zhu table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
19689f4b3541SRex Zhu
19699f4b3541SRex Zhu if (data->ulv_supported) {
19709f4b3541SRex Zhu result = ci_populate_ulv_state(hwmgr, &(table->Ulv));
19719f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
19729f4b3541SRex Zhu "Failed to initialize ULV state!", return result);
19739f4b3541SRex Zhu
19749f4b3541SRex Zhu cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
19759f4b3541SRex Zhu ixCG_ULV_PARAMETER, 0x40035);
19769f4b3541SRex Zhu }
19779f4b3541SRex Zhu
19789f4b3541SRex Zhu result = ci_populate_all_graphic_levels(hwmgr);
19799f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
19809f4b3541SRex Zhu "Failed to initialize Graphics Level!", return result);
19819f4b3541SRex Zhu
19829f4b3541SRex Zhu result = ci_populate_all_memory_levels(hwmgr);
19839f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
19849f4b3541SRex Zhu "Failed to initialize Memory Level!", return result);
19859f4b3541SRex Zhu
19869f4b3541SRex Zhu result = ci_populate_smc_link_level(hwmgr, table);
19879f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
19889f4b3541SRex Zhu "Failed to initialize Link Level!", return result);
19899f4b3541SRex Zhu
19909f4b3541SRex Zhu result = ci_populate_smc_acpi_level(hwmgr, table);
19919f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
19929f4b3541SRex Zhu "Failed to initialize ACPI Level!", return result);
19939f4b3541SRex Zhu
19949f4b3541SRex Zhu result = ci_populate_smc_vce_level(hwmgr, table);
19959f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
19969f4b3541SRex Zhu "Failed to initialize VCE Level!", return result);
19979f4b3541SRex Zhu
19989f4b3541SRex Zhu result = ci_populate_smc_acp_level(hwmgr, table);
19999f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
20009f4b3541SRex Zhu "Failed to initialize ACP Level!", return result);
20019f4b3541SRex Zhu
20029f4b3541SRex Zhu /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */
20039f4b3541SRex Zhu /* need to populate the ARB settings for the initial state. */
20049f4b3541SRex Zhu result = ci_program_memory_timing_parameters(hwmgr);
20059f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
20069f4b3541SRex Zhu "Failed to Write ARB settings for the initial state.", return result);
20079f4b3541SRex Zhu
20089f4b3541SRex Zhu result = ci_populate_smc_uvd_level(hwmgr, table);
20099f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
20109f4b3541SRex Zhu "Failed to initialize UVD Level!", return result);
20119f4b3541SRex Zhu
20129f4b3541SRex Zhu table->UvdBootLevel = 0;
20139f4b3541SRex Zhu table->VceBootLevel = 0;
20149f4b3541SRex Zhu table->AcpBootLevel = 0;
20159f4b3541SRex Zhu table->SamuBootLevel = 0;
20169f4b3541SRex Zhu
20179f4b3541SRex Zhu table->GraphicsBootLevel = 0;
20189f4b3541SRex Zhu table->MemoryBootLevel = 0;
20199f4b3541SRex Zhu
20209f4b3541SRex Zhu result = ci_populate_smc_boot_level(hwmgr, table);
20219f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
20229f4b3541SRex Zhu "Failed to initialize Boot Level!", return result);
20239f4b3541SRex Zhu
20249f4b3541SRex Zhu result = ci_populate_smc_initial_state(hwmgr);
20259f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result, "Failed to initialize Boot State!", return result);
20269f4b3541SRex Zhu
20279f4b3541SRex Zhu result = ci_populate_bapm_parameters_in_dpm_table(hwmgr);
20289f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result, "Failed to populate BAPM Parameters!", return result);
20299f4b3541SRex Zhu
20309f4b3541SRex Zhu table->UVDInterval = 1;
20319f4b3541SRex Zhu table->VCEInterval = 1;
20329f4b3541SRex Zhu table->ACPInterval = 1;
20339f4b3541SRex Zhu table->SAMUInterval = 1;
20349f4b3541SRex Zhu table->GraphicsVoltageChangeEnable = 1;
20359f4b3541SRex Zhu table->GraphicsThermThrottleEnable = 1;
20369f4b3541SRex Zhu table->GraphicsInterval = 1;
20379f4b3541SRex Zhu table->VoltageInterval = 1;
20389f4b3541SRex Zhu table->ThermalInterval = 1;
20399f4b3541SRex Zhu
20409f4b3541SRex Zhu table->TemperatureLimitHigh =
20419f4b3541SRex Zhu (data->thermal_temp_setting.temperature_high *
20429f4b3541SRex Zhu SMU7_Q88_FORMAT_CONVERSION_UNIT) / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
20439f4b3541SRex Zhu table->TemperatureLimitLow =
20449f4b3541SRex Zhu (data->thermal_temp_setting.temperature_low *
20459f4b3541SRex Zhu SMU7_Q88_FORMAT_CONVERSION_UNIT) / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
20469f4b3541SRex Zhu
20479f4b3541SRex Zhu table->MemoryVoltageChangeEnable = 1;
20489f4b3541SRex Zhu table->MemoryInterval = 1;
20499f4b3541SRex Zhu table->VoltageResponseTime = 0;
20509f4b3541SRex Zhu table->VddcVddciDelta = 4000;
20519f4b3541SRex Zhu table->PhaseResponseTime = 0;
20529f4b3541SRex Zhu table->MemoryThermThrottleEnable = 1;
20539f4b3541SRex Zhu
20549f4b3541SRex Zhu PP_ASSERT_WITH_CODE((1 <= data->dpm_table.pcie_speed_table.count),
20559f4b3541SRex Zhu "There must be 1 or more PCIE levels defined in PPTable.",
20569f4b3541SRex Zhu return -EINVAL);
20579f4b3541SRex Zhu
20589f4b3541SRex Zhu table->PCIeBootLinkLevel = (uint8_t)data->dpm_table.pcie_speed_table.count;
20599f4b3541SRex Zhu table->PCIeGenInterval = 1;
20609f4b3541SRex Zhu
206153241e01SRex Zhu result = ci_populate_vr_config(hwmgr, table);
206253241e01SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
206353241e01SRex Zhu "Failed to populate VRConfig setting!", return result);
206453241e01SRex Zhu data->vr_config = table->VRConfig;
206553241e01SRex Zhu
20669f4b3541SRex Zhu ci_populate_smc_svi2_config(hwmgr, table);
20679f4b3541SRex Zhu
20689f4b3541SRex Zhu for (i = 0; i < SMU7_MAX_ENTRIES_SMIO; i++)
20699f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->Smio[i]);
20709f4b3541SRex Zhu
20719f4b3541SRex Zhu table->ThermGpio = 17;
20729f4b3541SRex Zhu table->SclkStepSize = 0x4000;
20739f4b3541SRex Zhu if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) {
20749f4b3541SRex Zhu table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift;
20759f4b3541SRex Zhu phm_cap_set(hwmgr->platform_descriptor.platformCaps,
20769f4b3541SRex Zhu PHM_PlatformCaps_RegulatorHot);
20779f4b3541SRex Zhu } else {
20789f4b3541SRex Zhu table->VRHotGpio = SMU7_UNUSED_GPIO_PIN;
20799f4b3541SRex Zhu phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
20809f4b3541SRex Zhu PHM_PlatformCaps_RegulatorHot);
20819f4b3541SRex Zhu }
20829f4b3541SRex Zhu
20839f4b3541SRex Zhu table->AcDcGpio = SMU7_UNUSED_GPIO_PIN;
20849f4b3541SRex Zhu
20859f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
208653241e01SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
20879f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcVid);
20889f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcPhase);
20899f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddciVid);
20909f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskMvddVid);
20919f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
20929f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
20939f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
20949f4b3541SRex Zhu table->VddcVddciDelta = PP_HOST_TO_SMC_US(table->VddcVddciDelta);
20959f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
20969f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
20979f4b3541SRex Zhu
20989f4b3541SRex Zhu table->BootVddc = PP_HOST_TO_SMC_US(table->BootVddc * VOLTAGE_SCALE);
20999f4b3541SRex Zhu table->BootVddci = PP_HOST_TO_SMC_US(table->BootVddci * VOLTAGE_SCALE);
21009f4b3541SRex Zhu table->BootMVdd = PP_HOST_TO_SMC_US(table->BootMVdd * VOLTAGE_SCALE);
21019f4b3541SRex Zhu
21029f4b3541SRex Zhu /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
2103d3f8c0abSRex Zhu result = ci_copy_bytes_to_smc(hwmgr, smu_data->dpm_table_start +
21049f4b3541SRex Zhu offsetof(SMU7_Discrete_DpmTable, SystemFlags),
21059f4b3541SRex Zhu (uint8_t *)&(table->SystemFlags),
21069f4b3541SRex Zhu sizeof(SMU7_Discrete_DpmTable)-3 * sizeof(SMU7_PIDController),
21079f4b3541SRex Zhu SMC_RAM_END);
21089f4b3541SRex Zhu
21099f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
21109f4b3541SRex Zhu "Failed to upload dpm data to SMC memory!", return result;);
21119f4b3541SRex Zhu
21129f4b3541SRex Zhu result = ci_populate_initial_mc_reg_table(hwmgr);
21139f4b3541SRex Zhu PP_ASSERT_WITH_CODE((0 == result),
21149f4b3541SRex Zhu "Failed to populate initialize MC Reg table!", return result);
21159f4b3541SRex Zhu
21169f4b3541SRex Zhu result = ci_populate_pm_fuses(hwmgr);
21179f4b3541SRex Zhu PP_ASSERT_WITH_CODE(0 == result,
21189f4b3541SRex Zhu "Failed to populate PM fuses to SMC memory!", return result);
21199f4b3541SRex Zhu
2120d3f8c0abSRex Zhu ci_start_smc(hwmgr);
21219f4b3541SRex Zhu
21229f4b3541SRex Zhu return 0;
21239f4b3541SRex Zhu }
21249f4b3541SRex Zhu
ci_thermal_setup_fan_table(struct pp_hwmgr * hwmgr)212519048dc6SDave Airlie static int ci_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
21269f4b3541SRex Zhu {
2127b3b03052SRex Zhu struct ci_smumgr *ci_data = (struct ci_smumgr *)(hwmgr->smu_backend);
21289f4b3541SRex Zhu SMU7_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
21299f4b3541SRex Zhu uint32_t duty100;
21309f4b3541SRex Zhu uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
21319f4b3541SRex Zhu uint16_t fdo_min, slope1, slope2;
21329f4b3541SRex Zhu uint32_t reference_clock;
21339f4b3541SRex Zhu int res;
21349f4b3541SRex Zhu uint64_t tmp64;
21359f4b3541SRex Zhu
21369f4b3541SRex Zhu if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
21379f4b3541SRex Zhu return 0;
21389f4b3541SRex Zhu
21399f4b3541SRex Zhu if (hwmgr->thermal_controller.fanInfo.bNoFan) {
21409f4b3541SRex Zhu phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
21419f4b3541SRex Zhu PHM_PlatformCaps_MicrocodeFanControl);
21429f4b3541SRex Zhu return 0;
21439f4b3541SRex Zhu }
21449f4b3541SRex Zhu
21459f4b3541SRex Zhu if (0 == ci_data->fan_table_start) {
21469f4b3541SRex Zhu phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
21479f4b3541SRex Zhu return 0;
21489f4b3541SRex Zhu }
21499f4b3541SRex Zhu
21509f4b3541SRex Zhu duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
21519f4b3541SRex Zhu
21529f4b3541SRex Zhu if (0 == duty100) {
21539f4b3541SRex Zhu phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
21549f4b3541SRex Zhu return 0;
21559f4b3541SRex Zhu }
21569f4b3541SRex Zhu
21579f4b3541SRex Zhu tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
21589f4b3541SRex Zhu do_div(tmp64, 10000);
21599f4b3541SRex Zhu fdo_min = (uint16_t)tmp64;
21609f4b3541SRex Zhu
21619f4b3541SRex Zhu t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
21629f4b3541SRex Zhu t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
21639f4b3541SRex Zhu
21649f4b3541SRex Zhu pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
21659f4b3541SRex Zhu pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
21669f4b3541SRex Zhu
21679f4b3541SRex Zhu slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
21689f4b3541SRex Zhu slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
21699f4b3541SRex Zhu
21709f4b3541SRex Zhu fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
21719f4b3541SRex Zhu fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
21729f4b3541SRex Zhu fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
21739f4b3541SRex Zhu
21749f4b3541SRex Zhu fan_table.Slope1 = cpu_to_be16(slope1);
21759f4b3541SRex Zhu fan_table.Slope2 = cpu_to_be16(slope2);
21769f4b3541SRex Zhu
21779f4b3541SRex Zhu fan_table.FdoMin = cpu_to_be16(fdo_min);
21789f4b3541SRex Zhu
21799f4b3541SRex Zhu fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
21809f4b3541SRex Zhu
21819f4b3541SRex Zhu fan_table.HystUp = cpu_to_be16(1);
21829f4b3541SRex Zhu
21839f4b3541SRex Zhu fan_table.HystSlope = cpu_to_be16(1);
21849f4b3541SRex Zhu
21859f4b3541SRex Zhu fan_table.TempRespLim = cpu_to_be16(5);
21869f4b3541SRex Zhu
21872538090cSRex Zhu reference_clock = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev);
21889f4b3541SRex Zhu
21899f4b3541SRex Zhu fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
21909f4b3541SRex Zhu
21919f4b3541SRex Zhu fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
21929f4b3541SRex Zhu
21939f4b3541SRex Zhu fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
21949f4b3541SRex Zhu
2195d3f8c0abSRex Zhu res = ci_copy_bytes_to_smc(hwmgr, ci_data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), SMC_RAM_END);
21969f4b3541SRex Zhu
2197cfcc59d4SAlex Deucher return res;
21989f4b3541SRex Zhu }
21999f4b3541SRex Zhu
ci_program_mem_timing_parameters(struct pp_hwmgr * hwmgr)22009f4b3541SRex Zhu static int ci_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
22019f4b3541SRex Zhu {
22029f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
22039f4b3541SRex Zhu
22049f4b3541SRex Zhu if (data->need_update_smu7_dpm_table &
2205e5975d78SDeepak R Varma (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK))
22069f4b3541SRex Zhu return ci_program_memory_timing_parameters(hwmgr);
22079f4b3541SRex Zhu
22089f4b3541SRex Zhu return 0;
22099f4b3541SRex Zhu }
22109f4b3541SRex Zhu
ci_update_sclk_threshold(struct pp_hwmgr * hwmgr)221119048dc6SDave Airlie static int ci_update_sclk_threshold(struct pp_hwmgr *hwmgr)
22129f4b3541SRex Zhu {
22139f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2214b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
22159f4b3541SRex Zhu
22169f4b3541SRex Zhu int result = 0;
22179f4b3541SRex Zhu uint32_t low_sclk_interrupt_threshold = 0;
22189f4b3541SRex Zhu
22199f4b3541SRex Zhu if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
22209f4b3541SRex Zhu PHM_PlatformCaps_SclkThrottleLowNotification)
222129411f05SRex Zhu && (data->low_sclk_interrupt_threshold != 0)) {
22229f4b3541SRex Zhu low_sclk_interrupt_threshold =
22239f4b3541SRex Zhu data->low_sclk_interrupt_threshold;
22249f4b3541SRex Zhu
22259f4b3541SRex Zhu CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
22269f4b3541SRex Zhu
22279f4b3541SRex Zhu result = ci_copy_bytes_to_smc(
2228d3f8c0abSRex Zhu hwmgr,
22299f4b3541SRex Zhu smu_data->dpm_table_start +
22309f4b3541SRex Zhu offsetof(SMU7_Discrete_DpmTable,
22319f4b3541SRex Zhu LowSclkInterruptT),
22329f4b3541SRex Zhu (uint8_t *)&low_sclk_interrupt_threshold,
22339f4b3541SRex Zhu sizeof(uint32_t),
22349f4b3541SRex Zhu SMC_RAM_END);
22359f4b3541SRex Zhu }
22369f4b3541SRex Zhu
22379f4b3541SRex Zhu result = ci_update_and_upload_mc_reg_table(hwmgr);
22389f4b3541SRex Zhu
22399f4b3541SRex Zhu PP_ASSERT_WITH_CODE((0 == result), "Failed to upload MC reg table!", return result);
22409f4b3541SRex Zhu
22419f4b3541SRex Zhu result = ci_program_mem_timing_parameters(hwmgr);
22429f4b3541SRex Zhu PP_ASSERT_WITH_CODE((result == 0),
22439f4b3541SRex Zhu "Failed to program memory timing parameters!",
22449f4b3541SRex Zhu );
22459f4b3541SRex Zhu
22469f4b3541SRex Zhu return result;
22479f4b3541SRex Zhu }
22489f4b3541SRex Zhu
ci_get_offsetof(uint32_t type,uint32_t member)224919048dc6SDave Airlie static uint32_t ci_get_offsetof(uint32_t type, uint32_t member)
22509f4b3541SRex Zhu {
22519f4b3541SRex Zhu switch (type) {
22529f4b3541SRex Zhu case SMU_SoftRegisters:
22539f4b3541SRex Zhu switch (member) {
22549f4b3541SRex Zhu case HandshakeDisables:
22559f4b3541SRex Zhu return offsetof(SMU7_SoftRegisters, HandshakeDisables);
22569f4b3541SRex Zhu case VoltageChangeTimeout:
22579f4b3541SRex Zhu return offsetof(SMU7_SoftRegisters, VoltageChangeTimeout);
22589f4b3541SRex Zhu case AverageGraphicsActivity:
22599f4b3541SRex Zhu return offsetof(SMU7_SoftRegisters, AverageGraphicsA);
2260767fb6b3SEvan Quan case AverageMemoryActivity:
2261767fb6b3SEvan Quan return offsetof(SMU7_SoftRegisters, AverageMemoryA);
22629f4b3541SRex Zhu case PreVBlankGap:
22639f4b3541SRex Zhu return offsetof(SMU7_SoftRegisters, PreVBlankGap);
22649f4b3541SRex Zhu case VBlankTimeout:
22659f4b3541SRex Zhu return offsetof(SMU7_SoftRegisters, VBlankTimeout);
226626f52781SRex Zhu case DRAM_LOG_ADDR_H:
226726f52781SRex Zhu return offsetof(SMU7_SoftRegisters, DRAM_LOG_ADDR_H);
226826f52781SRex Zhu case DRAM_LOG_ADDR_L:
226926f52781SRex Zhu return offsetof(SMU7_SoftRegisters, DRAM_LOG_ADDR_L);
227026f52781SRex Zhu case DRAM_LOG_PHY_ADDR_H:
227126f52781SRex Zhu return offsetof(SMU7_SoftRegisters, DRAM_LOG_PHY_ADDR_H);
227226f52781SRex Zhu case DRAM_LOG_PHY_ADDR_L:
227326f52781SRex Zhu return offsetof(SMU7_SoftRegisters, DRAM_LOG_PHY_ADDR_L);
227426f52781SRex Zhu case DRAM_LOG_BUFF_SIZE:
227526f52781SRex Zhu return offsetof(SMU7_SoftRegisters, DRAM_LOG_BUFF_SIZE);
22769f4b3541SRex Zhu }
227714b28483SColin Ian King break;
22789f4b3541SRex Zhu case SMU_Discrete_DpmTable:
22799f4b3541SRex Zhu switch (member) {
22809f4b3541SRex Zhu case LowSclkInterruptThreshold:
22819f4b3541SRex Zhu return offsetof(SMU7_Discrete_DpmTable, LowSclkInterruptT);
22829f4b3541SRex Zhu }
228314b28483SColin Ian King break;
22849f4b3541SRex Zhu }
22859f4b3541SRex Zhu pr_debug("can't get the offset of type %x member %x\n", type, member);
22869f4b3541SRex Zhu return 0;
22879f4b3541SRex Zhu }
22889f4b3541SRex Zhu
ci_get_mac_definition(uint32_t value)228919048dc6SDave Airlie static uint32_t ci_get_mac_definition(uint32_t value)
22909f4b3541SRex Zhu {
22919f4b3541SRex Zhu switch (value) {
22929f4b3541SRex Zhu case SMU_MAX_LEVELS_GRAPHICS:
22939f4b3541SRex Zhu return SMU7_MAX_LEVELS_GRAPHICS;
22949f4b3541SRex Zhu case SMU_MAX_LEVELS_MEMORY:
22959f4b3541SRex Zhu return SMU7_MAX_LEVELS_MEMORY;
22969f4b3541SRex Zhu case SMU_MAX_LEVELS_LINK:
22979f4b3541SRex Zhu return SMU7_MAX_LEVELS_LINK;
22989f4b3541SRex Zhu case SMU_MAX_ENTRIES_SMIO:
22999f4b3541SRex Zhu return SMU7_MAX_ENTRIES_SMIO;
23009f4b3541SRex Zhu case SMU_MAX_LEVELS_VDDC:
2301e48c8cbeSMario Limonciello case SMU_MAX_LEVELS_VDDGFX:
23029f4b3541SRex Zhu return SMU7_MAX_LEVELS_VDDC;
23039f4b3541SRex Zhu case SMU_MAX_LEVELS_VDDCI:
23049f4b3541SRex Zhu return SMU7_MAX_LEVELS_VDDCI;
23059f4b3541SRex Zhu case SMU_MAX_LEVELS_MVDD:
23069f4b3541SRex Zhu return SMU7_MAX_LEVELS_MVDD;
23079f4b3541SRex Zhu }
23089f4b3541SRex Zhu
23099f4b3541SRex Zhu pr_debug("can't get the mac of %x\n", value);
23109f4b3541SRex Zhu return 0;
23119f4b3541SRex Zhu }
23129f4b3541SRex Zhu
ci_load_smc_ucode(struct pp_hwmgr * hwmgr)2313d3f8c0abSRex Zhu static int ci_load_smc_ucode(struct pp_hwmgr *hwmgr)
23149f4b3541SRex Zhu {
23159f4b3541SRex Zhu uint32_t byte_count, start_addr;
23169f4b3541SRex Zhu uint8_t *src;
23179f4b3541SRex Zhu uint32_t data;
23189f4b3541SRex Zhu
23199f4b3541SRex Zhu struct cgs_firmware_info info = {0};
23209f4b3541SRex Zhu
2321d3f8c0abSRex Zhu cgs_get_firmware_info(hwmgr->device, CGS_UCODE_ID_SMU, &info);
23229f4b3541SRex Zhu
2323b3b03052SRex Zhu hwmgr->is_kicker = info.is_kicker;
232482eb0f30SRex Zhu hwmgr->smu_version = info.version;
23259f4b3541SRex Zhu byte_count = info.image_size;
23269f4b3541SRex Zhu src = (uint8_t *)info.kptr;
23279f4b3541SRex Zhu start_addr = info.ucode_start_address;
23289f4b3541SRex Zhu
23299f4b3541SRex Zhu if (byte_count > SMC_RAM_END) {
23309f4b3541SRex Zhu pr_err("SMC address is beyond the SMC RAM area.\n");
23319f4b3541SRex Zhu return -EINVAL;
23329f4b3541SRex Zhu }
23339f4b3541SRex Zhu
2334d3f8c0abSRex Zhu cgs_write_register(hwmgr->device, mmSMC_IND_INDEX_0, start_addr);
2335a9eca3a6SRex Zhu PHM_WRITE_FIELD(hwmgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
23369f4b3541SRex Zhu
23379f4b3541SRex Zhu for (; byte_count >= 4; byte_count -= 4) {
23389f4b3541SRex Zhu data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
2339d3f8c0abSRex Zhu cgs_write_register(hwmgr->device, mmSMC_IND_DATA_0, data);
23409f4b3541SRex Zhu src += 4;
23419f4b3541SRex Zhu }
2342a9eca3a6SRex Zhu PHM_WRITE_FIELD(hwmgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
23439f4b3541SRex Zhu
23449f4b3541SRex Zhu if (0 != byte_count) {
234545b19706SColin Ian King pr_err("SMC size must be divisible by 4\n");
23469f4b3541SRex Zhu return -EINVAL;
23479f4b3541SRex Zhu }
23489f4b3541SRex Zhu
23499f4b3541SRex Zhu return 0;
23509f4b3541SRex Zhu }
23519f4b3541SRex Zhu
ci_upload_firmware(struct pp_hwmgr * hwmgr)23529f4b3541SRex Zhu static int ci_upload_firmware(struct pp_hwmgr *hwmgr)
23539f4b3541SRex Zhu {
2354d3f8c0abSRex Zhu if (ci_is_smc_ram_running(hwmgr)) {
23559f4b3541SRex Zhu pr_info("smc is running, no need to load smc firmware\n");
23569f4b3541SRex Zhu return 0;
23579f4b3541SRex Zhu }
2358be49be40SRex Zhu PHM_WAIT_INDIRECT_FIELD(hwmgr, SMC_IND, RCU_UC_EVENTS,
23599f4b3541SRex Zhu boot_seq_done, 1);
23609f4b3541SRex Zhu PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_MISC_CNTL,
23619f4b3541SRex Zhu pre_fetcher_en, 1);
23629f4b3541SRex Zhu
23639f4b3541SRex Zhu PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1);
23649f4b3541SRex Zhu PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
2365d3f8c0abSRex Zhu return ci_load_smc_ucode(hwmgr);
23669f4b3541SRex Zhu }
23679f4b3541SRex Zhu
ci_process_firmware_header(struct pp_hwmgr * hwmgr)236819048dc6SDave Airlie static int ci_process_firmware_header(struct pp_hwmgr *hwmgr)
23699f4b3541SRex Zhu {
23709f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2371b3b03052SRex Zhu struct ci_smumgr *ci_data = (struct ci_smumgr *)(hwmgr->smu_backend);
23729f4b3541SRex Zhu
23739f4b3541SRex Zhu uint32_t tmp = 0;
23749f4b3541SRex Zhu int result;
23759f4b3541SRex Zhu bool error = false;
23769f4b3541SRex Zhu
23779f4b3541SRex Zhu if (ci_upload_firmware(hwmgr))
23789f4b3541SRex Zhu return -EINVAL;
23799f4b3541SRex Zhu
2380d3f8c0abSRex Zhu result = ci_read_smc_sram_dword(hwmgr,
23819f4b3541SRex Zhu SMU7_FIRMWARE_HEADER_LOCATION +
23829f4b3541SRex Zhu offsetof(SMU7_Firmware_Header, DpmTable),
23839f4b3541SRex Zhu &tmp, SMC_RAM_END);
23849f4b3541SRex Zhu
23859f4b3541SRex Zhu if (0 == result)
23869f4b3541SRex Zhu ci_data->dpm_table_start = tmp;
23879f4b3541SRex Zhu
23889f4b3541SRex Zhu error |= (0 != result);
23899f4b3541SRex Zhu
2390d3f8c0abSRex Zhu result = ci_read_smc_sram_dword(hwmgr,
23919f4b3541SRex Zhu SMU7_FIRMWARE_HEADER_LOCATION +
23929f4b3541SRex Zhu offsetof(SMU7_Firmware_Header, SoftRegisters),
23939f4b3541SRex Zhu &tmp, SMC_RAM_END);
23949f4b3541SRex Zhu
23959f4b3541SRex Zhu if (0 == result) {
23969f4b3541SRex Zhu data->soft_regs_start = tmp;
23979f4b3541SRex Zhu ci_data->soft_regs_start = tmp;
23989f4b3541SRex Zhu }
23999f4b3541SRex Zhu
24009f4b3541SRex Zhu error |= (0 != result);
24019f4b3541SRex Zhu
2402d3f8c0abSRex Zhu result = ci_read_smc_sram_dword(hwmgr,
24039f4b3541SRex Zhu SMU7_FIRMWARE_HEADER_LOCATION +
24049f4b3541SRex Zhu offsetof(SMU7_Firmware_Header, mcRegisterTable),
24059f4b3541SRex Zhu &tmp, SMC_RAM_END);
24069f4b3541SRex Zhu
24079f4b3541SRex Zhu if (0 == result)
24089f4b3541SRex Zhu ci_data->mc_reg_table_start = tmp;
24099f4b3541SRex Zhu
2410d3f8c0abSRex Zhu result = ci_read_smc_sram_dword(hwmgr,
24119f4b3541SRex Zhu SMU7_FIRMWARE_HEADER_LOCATION +
24129f4b3541SRex Zhu offsetof(SMU7_Firmware_Header, FanTable),
24139f4b3541SRex Zhu &tmp, SMC_RAM_END);
24149f4b3541SRex Zhu
24159f4b3541SRex Zhu if (0 == result)
24169f4b3541SRex Zhu ci_data->fan_table_start = tmp;
24179f4b3541SRex Zhu
24189f4b3541SRex Zhu error |= (0 != result);
24199f4b3541SRex Zhu
2420d3f8c0abSRex Zhu result = ci_read_smc_sram_dword(hwmgr,
24219f4b3541SRex Zhu SMU7_FIRMWARE_HEADER_LOCATION +
24229f4b3541SRex Zhu offsetof(SMU7_Firmware_Header, mcArbDramTimingTable),
24239f4b3541SRex Zhu &tmp, SMC_RAM_END);
24249f4b3541SRex Zhu
24259f4b3541SRex Zhu if (0 == result)
24269f4b3541SRex Zhu ci_data->arb_table_start = tmp;
24279f4b3541SRex Zhu
24289f4b3541SRex Zhu error |= (0 != result);
24299f4b3541SRex Zhu
2430d3f8c0abSRex Zhu result = ci_read_smc_sram_dword(hwmgr,
24319f4b3541SRex Zhu SMU7_FIRMWARE_HEADER_LOCATION +
24329f4b3541SRex Zhu offsetof(SMU7_Firmware_Header, Version),
24339f4b3541SRex Zhu &tmp, SMC_RAM_END);
24349f4b3541SRex Zhu
24359f4b3541SRex Zhu if (0 == result)
24369f4b3541SRex Zhu hwmgr->microcode_version_info.SMC = tmp;
24379f4b3541SRex Zhu
24389f4b3541SRex Zhu error |= (0 != result);
24399f4b3541SRex Zhu
24409f4b3541SRex Zhu return error ? 1 : 0;
24419f4b3541SRex Zhu }
24429f4b3541SRex Zhu
ci_get_memory_modile_index(struct pp_hwmgr * hwmgr)24439f4b3541SRex Zhu static uint8_t ci_get_memory_modile_index(struct pp_hwmgr *hwmgr)
24449f4b3541SRex Zhu {
24459f4b3541SRex Zhu return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16));
24469f4b3541SRex Zhu }
24479f4b3541SRex Zhu
ci_check_s0_mc_reg_index(uint16_t in_reg,uint16_t * out_reg)24489f4b3541SRex Zhu static bool ci_check_s0_mc_reg_index(uint16_t in_reg, uint16_t *out_reg)
24499f4b3541SRex Zhu {
24509f4b3541SRex Zhu bool result = true;
24519f4b3541SRex Zhu
24529f4b3541SRex Zhu switch (in_reg) {
24539f4b3541SRex Zhu case mmMC_SEQ_RAS_TIMING:
24549f4b3541SRex Zhu *out_reg = mmMC_SEQ_RAS_TIMING_LP;
24559f4b3541SRex Zhu break;
24569f4b3541SRex Zhu
24579f4b3541SRex Zhu case mmMC_SEQ_DLL_STBY:
24589f4b3541SRex Zhu *out_reg = mmMC_SEQ_DLL_STBY_LP;
24599f4b3541SRex Zhu break;
24609f4b3541SRex Zhu
24619f4b3541SRex Zhu case mmMC_SEQ_G5PDX_CMD0:
24629f4b3541SRex Zhu *out_reg = mmMC_SEQ_G5PDX_CMD0_LP;
24639f4b3541SRex Zhu break;
24649f4b3541SRex Zhu
24659f4b3541SRex Zhu case mmMC_SEQ_G5PDX_CMD1:
24669f4b3541SRex Zhu *out_reg = mmMC_SEQ_G5PDX_CMD1_LP;
24679f4b3541SRex Zhu break;
24689f4b3541SRex Zhu
24699f4b3541SRex Zhu case mmMC_SEQ_G5PDX_CTRL:
24709f4b3541SRex Zhu *out_reg = mmMC_SEQ_G5PDX_CTRL_LP;
24719f4b3541SRex Zhu break;
24729f4b3541SRex Zhu
24739f4b3541SRex Zhu case mmMC_SEQ_CAS_TIMING:
24749f4b3541SRex Zhu *out_reg = mmMC_SEQ_CAS_TIMING_LP;
24759f4b3541SRex Zhu break;
24769f4b3541SRex Zhu
24779f4b3541SRex Zhu case mmMC_SEQ_MISC_TIMING:
24789f4b3541SRex Zhu *out_reg = mmMC_SEQ_MISC_TIMING_LP;
24799f4b3541SRex Zhu break;
24809f4b3541SRex Zhu
24819f4b3541SRex Zhu case mmMC_SEQ_MISC_TIMING2:
24829f4b3541SRex Zhu *out_reg = mmMC_SEQ_MISC_TIMING2_LP;
24839f4b3541SRex Zhu break;
24849f4b3541SRex Zhu
24859f4b3541SRex Zhu case mmMC_SEQ_PMG_DVS_CMD:
24869f4b3541SRex Zhu *out_reg = mmMC_SEQ_PMG_DVS_CMD_LP;
24879f4b3541SRex Zhu break;
24889f4b3541SRex Zhu
24899f4b3541SRex Zhu case mmMC_SEQ_PMG_DVS_CTL:
24909f4b3541SRex Zhu *out_reg = mmMC_SEQ_PMG_DVS_CTL_LP;
24919f4b3541SRex Zhu break;
24929f4b3541SRex Zhu
24939f4b3541SRex Zhu case mmMC_SEQ_RD_CTL_D0:
24949f4b3541SRex Zhu *out_reg = mmMC_SEQ_RD_CTL_D0_LP;
24959f4b3541SRex Zhu break;
24969f4b3541SRex Zhu
24979f4b3541SRex Zhu case mmMC_SEQ_RD_CTL_D1:
24989f4b3541SRex Zhu *out_reg = mmMC_SEQ_RD_CTL_D1_LP;
24999f4b3541SRex Zhu break;
25009f4b3541SRex Zhu
25019f4b3541SRex Zhu case mmMC_SEQ_WR_CTL_D0:
25029f4b3541SRex Zhu *out_reg = mmMC_SEQ_WR_CTL_D0_LP;
25039f4b3541SRex Zhu break;
25049f4b3541SRex Zhu
25059f4b3541SRex Zhu case mmMC_SEQ_WR_CTL_D1:
25069f4b3541SRex Zhu *out_reg = mmMC_SEQ_WR_CTL_D1_LP;
25079f4b3541SRex Zhu break;
25089f4b3541SRex Zhu
25099f4b3541SRex Zhu case mmMC_PMG_CMD_EMRS:
25109f4b3541SRex Zhu *out_reg = mmMC_SEQ_PMG_CMD_EMRS_LP;
25119f4b3541SRex Zhu break;
25129f4b3541SRex Zhu
25139f4b3541SRex Zhu case mmMC_PMG_CMD_MRS:
25149f4b3541SRex Zhu *out_reg = mmMC_SEQ_PMG_CMD_MRS_LP;
25159f4b3541SRex Zhu break;
25169f4b3541SRex Zhu
25179f4b3541SRex Zhu case mmMC_PMG_CMD_MRS1:
25189f4b3541SRex Zhu *out_reg = mmMC_SEQ_PMG_CMD_MRS1_LP;
25199f4b3541SRex Zhu break;
25209f4b3541SRex Zhu
25219f4b3541SRex Zhu case mmMC_SEQ_PMG_TIMING:
25229f4b3541SRex Zhu *out_reg = mmMC_SEQ_PMG_TIMING_LP;
25239f4b3541SRex Zhu break;
25249f4b3541SRex Zhu
25259f4b3541SRex Zhu case mmMC_PMG_CMD_MRS2:
25269f4b3541SRex Zhu *out_reg = mmMC_SEQ_PMG_CMD_MRS2_LP;
25279f4b3541SRex Zhu break;
25289f4b3541SRex Zhu
25299f4b3541SRex Zhu case mmMC_SEQ_WR_CTL_2:
25309f4b3541SRex Zhu *out_reg = mmMC_SEQ_WR_CTL_2_LP;
25319f4b3541SRex Zhu break;
25329f4b3541SRex Zhu
25339f4b3541SRex Zhu default:
25349f4b3541SRex Zhu result = false;
25359f4b3541SRex Zhu break;
25369f4b3541SRex Zhu }
25379f4b3541SRex Zhu
25389f4b3541SRex Zhu return result;
25399f4b3541SRex Zhu }
25409f4b3541SRex Zhu
ci_set_s0_mc_reg_index(struct ci_mc_reg_table * table)25419f4b3541SRex Zhu static int ci_set_s0_mc_reg_index(struct ci_mc_reg_table *table)
25429f4b3541SRex Zhu {
25439f4b3541SRex Zhu uint32_t i;
25449f4b3541SRex Zhu uint16_t address;
25459f4b3541SRex Zhu
25469f4b3541SRex Zhu for (i = 0; i < table->last; i++) {
25479f4b3541SRex Zhu table->mc_reg_address[i].s0 =
25489f4b3541SRex Zhu ci_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address)
25499f4b3541SRex Zhu ? address : table->mc_reg_address[i].s1;
25509f4b3541SRex Zhu }
25519f4b3541SRex Zhu return 0;
25529f4b3541SRex Zhu }
25539f4b3541SRex Zhu
ci_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table * table,struct ci_mc_reg_table * ni_table)25549f4b3541SRex Zhu static int ci_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table,
25559f4b3541SRex Zhu struct ci_mc_reg_table *ni_table)
25569f4b3541SRex Zhu {
25579f4b3541SRex Zhu uint8_t i, j;
25589f4b3541SRex Zhu
25599f4b3541SRex Zhu PP_ASSERT_WITH_CODE((table->last <= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE),
25609f4b3541SRex Zhu "Invalid VramInfo table.", return -EINVAL);
25619f4b3541SRex Zhu PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES),
25629f4b3541SRex Zhu "Invalid VramInfo table.", return -EINVAL);
25639f4b3541SRex Zhu
25649f4b3541SRex Zhu for (i = 0; i < table->last; i++)
25659f4b3541SRex Zhu ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
25669f4b3541SRex Zhu
25679f4b3541SRex Zhu ni_table->last = table->last;
25689f4b3541SRex Zhu
25699f4b3541SRex Zhu for (i = 0; i < table->num_entries; i++) {
25709f4b3541SRex Zhu ni_table->mc_reg_table_entry[i].mclk_max =
25719f4b3541SRex Zhu table->mc_reg_table_entry[i].mclk_max;
25729f4b3541SRex Zhu for (j = 0; j < table->last; j++) {
25739f4b3541SRex Zhu ni_table->mc_reg_table_entry[i].mc_data[j] =
25749f4b3541SRex Zhu table->mc_reg_table_entry[i].mc_data[j];
25759f4b3541SRex Zhu }
25769f4b3541SRex Zhu }
25779f4b3541SRex Zhu
25789f4b3541SRex Zhu ni_table->num_entries = table->num_entries;
25799f4b3541SRex Zhu
25809f4b3541SRex Zhu return 0;
25819f4b3541SRex Zhu }
25829f4b3541SRex Zhu
ci_set_mc_special_registers(struct pp_hwmgr * hwmgr,struct ci_mc_reg_table * table)25839f4b3541SRex Zhu static int ci_set_mc_special_registers(struct pp_hwmgr *hwmgr,
25849f4b3541SRex Zhu struct ci_mc_reg_table *table)
25859f4b3541SRex Zhu {
25869f4b3541SRex Zhu uint8_t i, j, k;
25879f4b3541SRex Zhu uint32_t temp_reg;
25889f4b3541SRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
25899f4b3541SRex Zhu
25909f4b3541SRex Zhu for (i = 0, j = table->last; i < table->last; i++) {
25919f4b3541SRex Zhu PP_ASSERT_WITH_CODE((j < SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE),
25929f4b3541SRex Zhu "Invalid VramInfo table.", return -EINVAL);
25939f4b3541SRex Zhu
25949f4b3541SRex Zhu switch (table->mc_reg_address[i].s1) {
25959f4b3541SRex Zhu
25969f4b3541SRex Zhu case mmMC_SEQ_MISC1:
25979f4b3541SRex Zhu temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS);
25989f4b3541SRex Zhu table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
25999f4b3541SRex Zhu table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
26009f4b3541SRex Zhu for (k = 0; k < table->num_entries; k++) {
26019f4b3541SRex Zhu table->mc_reg_table_entry[k].mc_data[j] =
26029f4b3541SRex Zhu ((temp_reg & 0xffff0000)) |
26039f4b3541SRex Zhu ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
26049f4b3541SRex Zhu }
26059f4b3541SRex Zhu j++;
26068cdbad98SErnst Sjöstrand
26079f4b3541SRex Zhu PP_ASSERT_WITH_CODE((j < SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE),
26089f4b3541SRex Zhu "Invalid VramInfo table.", return -EINVAL);
26099f4b3541SRex Zhu temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS);
26109f4b3541SRex Zhu table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
26119f4b3541SRex Zhu table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
26129f4b3541SRex Zhu for (k = 0; k < table->num_entries; k++) {
26139f4b3541SRex Zhu table->mc_reg_table_entry[k].mc_data[j] =
26149f4b3541SRex Zhu (temp_reg & 0xffff0000) |
26159f4b3541SRex Zhu (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
26169f4b3541SRex Zhu
26179f4b3541SRex Zhu if (!data->is_memory_gddr5)
26189f4b3541SRex Zhu table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
26199f4b3541SRex Zhu }
26209f4b3541SRex Zhu j++;
26219f4b3541SRex Zhu
26228cdbad98SErnst Sjöstrand if (!data->is_memory_gddr5) {
26238cdbad98SErnst Sjöstrand PP_ASSERT_WITH_CODE((j < SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE),
26248cdbad98SErnst Sjöstrand "Invalid VramInfo table.", return -EINVAL);
26259f4b3541SRex Zhu table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
26269f4b3541SRex Zhu table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
26279f4b3541SRex Zhu for (k = 0; k < table->num_entries; k++) {
26289f4b3541SRex Zhu table->mc_reg_table_entry[k].mc_data[j] =
26299f4b3541SRex Zhu (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
26309f4b3541SRex Zhu }
26319f4b3541SRex Zhu j++;
26329f4b3541SRex Zhu }
26339f4b3541SRex Zhu
26349f4b3541SRex Zhu break;
26359f4b3541SRex Zhu
26369f4b3541SRex Zhu case mmMC_SEQ_RESERVE_M:
26379f4b3541SRex Zhu temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1);
26389f4b3541SRex Zhu table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
26399f4b3541SRex Zhu table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
26409f4b3541SRex Zhu for (k = 0; k < table->num_entries; k++) {
26419f4b3541SRex Zhu table->mc_reg_table_entry[k].mc_data[j] =
26429f4b3541SRex Zhu (temp_reg & 0xffff0000) |
26439f4b3541SRex Zhu (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
26449f4b3541SRex Zhu }
26459f4b3541SRex Zhu j++;
26469f4b3541SRex Zhu break;
26479f4b3541SRex Zhu
26489f4b3541SRex Zhu default:
26499f4b3541SRex Zhu break;
26509f4b3541SRex Zhu }
26519f4b3541SRex Zhu
26529f4b3541SRex Zhu }
26539f4b3541SRex Zhu
26549f4b3541SRex Zhu table->last = j;
26559f4b3541SRex Zhu
26569f4b3541SRex Zhu return 0;
26579f4b3541SRex Zhu }
26589f4b3541SRex Zhu
ci_set_valid_flag(struct ci_mc_reg_table * table)26599f4b3541SRex Zhu static int ci_set_valid_flag(struct ci_mc_reg_table *table)
26609f4b3541SRex Zhu {
26619f4b3541SRex Zhu uint8_t i, j;
26629f4b3541SRex Zhu
26639f4b3541SRex Zhu for (i = 0; i < table->last; i++) {
26649f4b3541SRex Zhu for (j = 1; j < table->num_entries; j++) {
26659f4b3541SRex Zhu if (table->mc_reg_table_entry[j-1].mc_data[i] !=
26669f4b3541SRex Zhu table->mc_reg_table_entry[j].mc_data[i]) {
26679f4b3541SRex Zhu table->validflag |= (1 << i);
26689f4b3541SRex Zhu break;
26699f4b3541SRex Zhu }
26709f4b3541SRex Zhu }
26719f4b3541SRex Zhu }
26729f4b3541SRex Zhu
26739f4b3541SRex Zhu return 0;
26749f4b3541SRex Zhu }
26759f4b3541SRex Zhu
ci_initialize_mc_reg_table(struct pp_hwmgr * hwmgr)267619048dc6SDave Airlie static int ci_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
26779f4b3541SRex Zhu {
26789f4b3541SRex Zhu int result;
2679b3b03052SRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
26809f4b3541SRex Zhu pp_atomctrl_mc_reg_table *table;
26819f4b3541SRex Zhu struct ci_mc_reg_table *ni_table = &smu_data->mc_reg_table;
26829f4b3541SRex Zhu uint8_t module_index = ci_get_memory_modile_index(hwmgr);
26839f4b3541SRex Zhu
26849f4b3541SRex Zhu table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
26859f4b3541SRex Zhu
26869f4b3541SRex Zhu if (NULL == table)
26879f4b3541SRex Zhu return -ENOMEM;
26889f4b3541SRex Zhu
26899f4b3541SRex Zhu /* Program additional LP registers that are no longer programmed by VBIOS */
26909f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
26919f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
26929f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY));
26939f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0));
26949f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1));
26959f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL));
26969f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD));
26979f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL));
26989f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING));
26999f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
27009f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS));
27019f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS));
27029f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1));
27039f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0));
27049f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
27059f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
27069f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
27079f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
27089f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
27099f4b3541SRex Zhu cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
27109f4b3541SRex Zhu
27119f4b3541SRex Zhu result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
27129f4b3541SRex Zhu
27139f4b3541SRex Zhu if (0 == result)
27149f4b3541SRex Zhu result = ci_copy_vbios_smc_reg_table(table, ni_table);
27159f4b3541SRex Zhu
27169f4b3541SRex Zhu if (0 == result) {
27179f4b3541SRex Zhu ci_set_s0_mc_reg_index(ni_table);
27189f4b3541SRex Zhu result = ci_set_mc_special_registers(hwmgr, ni_table);
27199f4b3541SRex Zhu }
27209f4b3541SRex Zhu
27219f4b3541SRex Zhu if (0 == result)
27229f4b3541SRex Zhu ci_set_valid_flag(ni_table);
27239f4b3541SRex Zhu
27249f4b3541SRex Zhu kfree(table);
27259f4b3541SRex Zhu
27269f4b3541SRex Zhu return result;
27279f4b3541SRex Zhu }
27289f4b3541SRex Zhu
ci_is_dpm_running(struct pp_hwmgr * hwmgr)272919048dc6SDave Airlie static bool ci_is_dpm_running(struct pp_hwmgr *hwmgr)
27309f4b3541SRex Zhu {
273152934da2SEvan Quan return ci_is_smc_ram_running(hwmgr);
27329f4b3541SRex Zhu }
27339f4b3541SRex Zhu
ci_smu_init(struct pp_hwmgr * hwmgr)273419048dc6SDave Airlie static int ci_smu_init(struct pp_hwmgr *hwmgr)
273519048dc6SDave Airlie {
27366f8e98b9SRuan Jinjie struct ci_smumgr *ci_priv;
273719048dc6SDave Airlie
273819048dc6SDave Airlie ci_priv = kzalloc(sizeof(struct ci_smumgr), GFP_KERNEL);
273919048dc6SDave Airlie
274019048dc6SDave Airlie if (ci_priv == NULL)
274119048dc6SDave Airlie return -ENOMEM;
274219048dc6SDave Airlie
274319048dc6SDave Airlie hwmgr->smu_backend = ci_priv;
274419048dc6SDave Airlie
274519048dc6SDave Airlie return 0;
274619048dc6SDave Airlie }
274719048dc6SDave Airlie
ci_smu_fini(struct pp_hwmgr * hwmgr)274819048dc6SDave Airlie static int ci_smu_fini(struct pp_hwmgr *hwmgr)
274919048dc6SDave Airlie {
275019048dc6SDave Airlie kfree(hwmgr->smu_backend);
275119048dc6SDave Airlie hwmgr->smu_backend = NULL;
275219048dc6SDave Airlie return 0;
275319048dc6SDave Airlie }
275419048dc6SDave Airlie
ci_start_smu(struct pp_hwmgr * hwmgr)275519048dc6SDave Airlie static int ci_start_smu(struct pp_hwmgr *hwmgr)
275619048dc6SDave Airlie {
275719048dc6SDave Airlie return 0;
275819048dc6SDave Airlie }
275919048dc6SDave Airlie
ci_update_dpm_settings(struct pp_hwmgr * hwmgr,void * profile_setting)27606dcd30aaSRex Zhu static int ci_update_dpm_settings(struct pp_hwmgr *hwmgr,
27616dcd30aaSRex Zhu void *profile_setting)
27626dcd30aaSRex Zhu {
27636dcd30aaSRex Zhu struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
27646dcd30aaSRex Zhu struct ci_smumgr *smu_data = (struct ci_smumgr *)
27656dcd30aaSRex Zhu (hwmgr->smu_backend);
27666dcd30aaSRex Zhu struct profile_mode_setting *setting;
27676dcd30aaSRex Zhu struct SMU7_Discrete_GraphicsLevel *levels =
27686dcd30aaSRex Zhu smu_data->smc_state_table.GraphicsLevel;
27696dcd30aaSRex Zhu uint32_t array = smu_data->dpm_table_start +
27706dcd30aaSRex Zhu offsetof(SMU7_Discrete_DpmTable, GraphicsLevel);
27716dcd30aaSRex Zhu
27726dcd30aaSRex Zhu uint32_t mclk_array = smu_data->dpm_table_start +
27736dcd30aaSRex Zhu offsetof(SMU7_Discrete_DpmTable, MemoryLevel);
27746dcd30aaSRex Zhu struct SMU7_Discrete_MemoryLevel *mclk_levels =
27756dcd30aaSRex Zhu smu_data->smc_state_table.MemoryLevel;
27766dcd30aaSRex Zhu uint32_t i;
27776dcd30aaSRex Zhu uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp;
27786dcd30aaSRex Zhu
27796dcd30aaSRex Zhu if (profile_setting == NULL)
27806dcd30aaSRex Zhu return -EINVAL;
27816dcd30aaSRex Zhu
27826dcd30aaSRex Zhu setting = (struct profile_mode_setting *)profile_setting;
27836dcd30aaSRex Zhu
27846dcd30aaSRex Zhu if (setting->bupdate_sclk) {
27856dcd30aaSRex Zhu if (!data->sclk_dpm_key_disabled)
2786a0ec2256SEvan Quan smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel, NULL);
27876dcd30aaSRex Zhu for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) {
27886dcd30aaSRex Zhu if (levels[i].ActivityLevel !=
27896dcd30aaSRex Zhu cpu_to_be16(setting->sclk_activity)) {
27906dcd30aaSRex Zhu levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity);
27916dcd30aaSRex Zhu
27926dcd30aaSRex Zhu clk_activity_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i)
27936dcd30aaSRex Zhu + offsetof(SMU7_Discrete_GraphicsLevel, ActivityLevel);
27946dcd30aaSRex Zhu offset = clk_activity_offset & ~0x3;
27956dcd30aaSRex Zhu tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
27966dcd30aaSRex Zhu tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t));
27976dcd30aaSRex Zhu cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
27986dcd30aaSRex Zhu
27996dcd30aaSRex Zhu }
28006dcd30aaSRex Zhu if (levels[i].UpH != setting->sclk_up_hyst ||
28016dcd30aaSRex Zhu levels[i].DownH != setting->sclk_down_hyst) {
28026dcd30aaSRex Zhu levels[i].UpH = setting->sclk_up_hyst;
28036dcd30aaSRex Zhu levels[i].DownH = setting->sclk_down_hyst;
28046dcd30aaSRex Zhu up_hyst_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i)
28056dcd30aaSRex Zhu + offsetof(SMU7_Discrete_GraphicsLevel, UpH);
28066dcd30aaSRex Zhu down_hyst_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i)
28076dcd30aaSRex Zhu + offsetof(SMU7_Discrete_GraphicsLevel, DownH);
28086dcd30aaSRex Zhu offset = up_hyst_offset & ~0x3;
28096dcd30aaSRex Zhu tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
28106dcd30aaSRex Zhu tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpH, sizeof(uint8_t));
28116dcd30aaSRex Zhu tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownH, sizeof(uint8_t));
28126dcd30aaSRex Zhu cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
28136dcd30aaSRex Zhu }
28146dcd30aaSRex Zhu }
28156dcd30aaSRex Zhu if (!data->sclk_dpm_key_disabled)
2816a0ec2256SEvan Quan smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel, NULL);
28176dcd30aaSRex Zhu }
28186dcd30aaSRex Zhu
28196dcd30aaSRex Zhu if (setting->bupdate_mclk) {
28206dcd30aaSRex Zhu if (!data->mclk_dpm_key_disabled)
2821a0ec2256SEvan Quan smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel, NULL);
28226dcd30aaSRex Zhu for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) {
28236dcd30aaSRex Zhu if (mclk_levels[i].ActivityLevel !=
28246dcd30aaSRex Zhu cpu_to_be16(setting->mclk_activity)) {
28256dcd30aaSRex Zhu mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity);
28266dcd30aaSRex Zhu
28276dcd30aaSRex Zhu clk_activity_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i)
28286dcd30aaSRex Zhu + offsetof(SMU7_Discrete_MemoryLevel, ActivityLevel);
28296dcd30aaSRex Zhu offset = clk_activity_offset & ~0x3;
28306dcd30aaSRex Zhu tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
28316dcd30aaSRex Zhu tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t));
28326dcd30aaSRex Zhu cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
28336dcd30aaSRex Zhu
28346dcd30aaSRex Zhu }
28356dcd30aaSRex Zhu if (mclk_levels[i].UpH != setting->mclk_up_hyst ||
28366dcd30aaSRex Zhu mclk_levels[i].DownH != setting->mclk_down_hyst) {
28376dcd30aaSRex Zhu mclk_levels[i].UpH = setting->mclk_up_hyst;
28386dcd30aaSRex Zhu mclk_levels[i].DownH = setting->mclk_down_hyst;
28396dcd30aaSRex Zhu up_hyst_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i)
28406dcd30aaSRex Zhu + offsetof(SMU7_Discrete_MemoryLevel, UpH);
28416dcd30aaSRex Zhu down_hyst_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i)
28426dcd30aaSRex Zhu + offsetof(SMU7_Discrete_MemoryLevel, DownH);
28436dcd30aaSRex Zhu offset = up_hyst_offset & ~0x3;
28446dcd30aaSRex Zhu tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
28456dcd30aaSRex Zhu tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpH, sizeof(uint8_t));
28466dcd30aaSRex Zhu tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownH, sizeof(uint8_t));
28476dcd30aaSRex Zhu cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
28486dcd30aaSRex Zhu }
28496dcd30aaSRex Zhu }
28506dcd30aaSRex Zhu if (!data->mclk_dpm_key_disabled)
2851a0ec2256SEvan Quan smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel, NULL);
28526dcd30aaSRex Zhu }
28536dcd30aaSRex Zhu return 0;
28546dcd30aaSRex Zhu }
28556dcd30aaSRex Zhu
ci_update_uvd_smc_table(struct pp_hwmgr * hwmgr)2856e1e36485SRex Zhu static int ci_update_uvd_smc_table(struct pp_hwmgr *hwmgr)
2857e1e36485SRex Zhu {
2858e1e36485SRex Zhu struct amdgpu_device *adev = hwmgr->adev;
2859e1e36485SRex Zhu struct smu7_hwmgr *data = hwmgr->backend;
2860e1e36485SRex Zhu struct ci_smumgr *smu_data = hwmgr->smu_backend;
2861e1e36485SRex Zhu struct phm_uvd_clock_voltage_dependency_table *uvd_table =
2862e1e36485SRex Zhu hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
2863e1e36485SRex Zhu uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
2864e1e36485SRex Zhu AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
2865e1e36485SRex Zhu AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
2866e1e36485SRex Zhu AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
2867e1e36485SRex Zhu uint32_t max_vddc = adev->pm.ac_power ? hwmgr->dyn_state.max_clock_voltage_on_ac.vddc :
2868e1e36485SRex Zhu hwmgr->dyn_state.max_clock_voltage_on_dc.vddc;
2869e1e36485SRex Zhu int32_t i;
2870e1e36485SRex Zhu
2871e1e36485SRex Zhu if (PP_CAP(PHM_PlatformCaps_UVDDPM) || uvd_table->count <= 0)
2872e1e36485SRex Zhu smu_data->smc_state_table.UvdBootLevel = 0;
2873e1e36485SRex Zhu else
2874e1e36485SRex Zhu smu_data->smc_state_table.UvdBootLevel = uvd_table->count - 1;
2875e1e36485SRex Zhu
2876e1e36485SRex Zhu PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, DPM_TABLE_475,
2877e1e36485SRex Zhu UvdBootLevel, smu_data->smc_state_table.UvdBootLevel);
2878e1e36485SRex Zhu
2879e1e36485SRex Zhu data->dpm_level_enable_mask.uvd_dpm_enable_mask = 0;
2880e1e36485SRex Zhu
2881e1e36485SRex Zhu for (i = uvd_table->count - 1; i >= 0; i--) {
2882e1e36485SRex Zhu if (uvd_table->entries[i].v <= max_vddc)
2883e1e36485SRex Zhu data->dpm_level_enable_mask.uvd_dpm_enable_mask |= 1 << i;
2884e1e36485SRex Zhu if (hwmgr->dpm_level & profile_mode_mask || !PP_CAP(PHM_PlatformCaps_UVDDPM))
2885e1e36485SRex Zhu break;
2886e1e36485SRex Zhu }
288722ecc966SEvan Quan smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_UVDDPM_SetEnabledMask,
2888a0ec2256SEvan Quan data->dpm_level_enable_mask.uvd_dpm_enable_mask,
2889a0ec2256SEvan Quan NULL);
2890e1e36485SRex Zhu
2891e1e36485SRex Zhu return 0;
2892e1e36485SRex Zhu }
2893e1e36485SRex Zhu
ci_update_vce_smc_table(struct pp_hwmgr * hwmgr)2894e1e36485SRex Zhu static int ci_update_vce_smc_table(struct pp_hwmgr *hwmgr)
2895e1e36485SRex Zhu {
2896e1e36485SRex Zhu struct amdgpu_device *adev = hwmgr->adev;
2897e1e36485SRex Zhu struct smu7_hwmgr *data = hwmgr->backend;
2898e1e36485SRex Zhu struct phm_vce_clock_voltage_dependency_table *vce_table =
2899e1e36485SRex Zhu hwmgr->dyn_state.vce_clock_voltage_dependency_table;
2900e1e36485SRex Zhu uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
2901e1e36485SRex Zhu AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
2902e1e36485SRex Zhu AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
2903e1e36485SRex Zhu AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
2904e1e36485SRex Zhu uint32_t max_vddc = adev->pm.ac_power ? hwmgr->dyn_state.max_clock_voltage_on_ac.vddc :
2905e1e36485SRex Zhu hwmgr->dyn_state.max_clock_voltage_on_dc.vddc;
2906e1e36485SRex Zhu int32_t i;
2907e1e36485SRex Zhu
2908e1e36485SRex Zhu PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, DPM_TABLE_475,
2909e1e36485SRex Zhu VceBootLevel, 0); /* temp hard code to level 0, vce can set min evclk*/
2910e1e36485SRex Zhu
2911e1e36485SRex Zhu data->dpm_level_enable_mask.vce_dpm_enable_mask = 0;
2912e1e36485SRex Zhu
2913e1e36485SRex Zhu for (i = vce_table->count - 1; i >= 0; i--) {
2914e1e36485SRex Zhu if (vce_table->entries[i].v <= max_vddc)
2915e1e36485SRex Zhu data->dpm_level_enable_mask.vce_dpm_enable_mask |= 1 << i;
2916e1e36485SRex Zhu if (hwmgr->dpm_level & profile_mode_mask || !PP_CAP(PHM_PlatformCaps_VCEDPM))
2917e1e36485SRex Zhu break;
2918e1e36485SRex Zhu }
291922ecc966SEvan Quan smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_VCEDPM_SetEnabledMask,
2920a0ec2256SEvan Quan data->dpm_level_enable_mask.vce_dpm_enable_mask,
2921a0ec2256SEvan Quan NULL);
2922e1e36485SRex Zhu
2923e1e36485SRex Zhu return 0;
2924e1e36485SRex Zhu }
2925e1e36485SRex Zhu
ci_update_smc_table(struct pp_hwmgr * hwmgr,uint32_t type)2926e1e36485SRex Zhu static int ci_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type)
2927e1e36485SRex Zhu {
2928e1e36485SRex Zhu switch (type) {
2929e1e36485SRex Zhu case SMU_UVD_TABLE:
2930e1e36485SRex Zhu ci_update_uvd_smc_table(hwmgr);
2931e1e36485SRex Zhu break;
2932e1e36485SRex Zhu case SMU_VCE_TABLE:
2933e1e36485SRex Zhu ci_update_vce_smc_table(hwmgr);
2934e1e36485SRex Zhu break;
2935e1e36485SRex Zhu default:
2936e1e36485SRex Zhu break;
2937e1e36485SRex Zhu }
2938e1e36485SRex Zhu return 0;
2939e1e36485SRex Zhu }
2940e1e36485SRex Zhu
ci_reset_smc(struct pp_hwmgr * hwmgr)2941e6bd6890SEvan Quan static void ci_reset_smc(struct pp_hwmgr *hwmgr)
2942e6bd6890SEvan Quan {
2943e6bd6890SEvan Quan PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
2944e6bd6890SEvan Quan SMC_SYSCON_RESET_CNTL,
2945e6bd6890SEvan Quan rst_reg, 1);
2946e6bd6890SEvan Quan }
2947e6bd6890SEvan Quan
2948e6bd6890SEvan Quan
ci_stop_smc_clock(struct pp_hwmgr * hwmgr)2949e6bd6890SEvan Quan static void ci_stop_smc_clock(struct pp_hwmgr *hwmgr)
2950e6bd6890SEvan Quan {
2951e6bd6890SEvan Quan PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
2952e6bd6890SEvan Quan SMC_SYSCON_CLOCK_CNTL_0,
2953e6bd6890SEvan Quan ck_disable, 1);
2954e6bd6890SEvan Quan }
2955e6bd6890SEvan Quan
ci_stop_smc(struct pp_hwmgr * hwmgr)2956e6bd6890SEvan Quan static int ci_stop_smc(struct pp_hwmgr *hwmgr)
2957e6bd6890SEvan Quan {
2958e6bd6890SEvan Quan ci_reset_smc(hwmgr);
2959e6bd6890SEvan Quan ci_stop_smc_clock(hwmgr);
2960e6bd6890SEvan Quan
2961e6bd6890SEvan Quan return 0;
2962e6bd6890SEvan Quan }
2963e6bd6890SEvan Quan
296419048dc6SDave Airlie const struct pp_smumgr_func ci_smu_funcs = {
296582973e07SPrike Liang .name = "ci_smu",
296619048dc6SDave Airlie .smu_init = ci_smu_init,
296719048dc6SDave Airlie .smu_fini = ci_smu_fini,
296819048dc6SDave Airlie .start_smu = ci_start_smu,
296919048dc6SDave Airlie .check_fw_load_finish = NULL,
297019048dc6SDave Airlie .request_smu_load_fw = NULL,
297119048dc6SDave Airlie .request_smu_load_specific_fw = NULL,
297219048dc6SDave Airlie .send_msg_to_smc = ci_send_msg_to_smc,
297319048dc6SDave Airlie .send_msg_to_smc_with_parameter = ci_send_msg_to_smc_with_parameter,
2974177e38a4SSandeep Raghuraman .get_argument = smu7_get_argument,
297519048dc6SDave Airlie .download_pptable_settings = NULL,
297619048dc6SDave Airlie .upload_pptable_settings = NULL,
297719048dc6SDave Airlie .get_offsetof = ci_get_offsetof,
297819048dc6SDave Airlie .process_firmware_header = ci_process_firmware_header,
297919048dc6SDave Airlie .init_smc_table = ci_init_smc_table,
298019048dc6SDave Airlie .update_sclk_threshold = ci_update_sclk_threshold,
298119048dc6SDave Airlie .thermal_setup_fan_table = ci_thermal_setup_fan_table,
298219048dc6SDave Airlie .populate_all_graphic_levels = ci_populate_all_graphic_levels,
298319048dc6SDave Airlie .populate_all_memory_levels = ci_populate_all_memory_levels,
298419048dc6SDave Airlie .get_mac_definition = ci_get_mac_definition,
298519048dc6SDave Airlie .initialize_mc_reg_table = ci_initialize_mc_reg_table,
298619048dc6SDave Airlie .is_dpm_running = ci_is_dpm_running,
29876dcd30aaSRex Zhu .update_dpm_settings = ci_update_dpm_settings,
2988e1e36485SRex Zhu .update_smc_table = ci_update_smc_table,
2989e6bd6890SEvan Quan .stop_smc = ci_stop_smc,
299019048dc6SDave Airlie };
2991