1 /* $NetBSD: amdgpu_rn_clk_mgr_vbios_smu.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $ */ 2 3 /* 4 * Copyright 2012-16 Advanced Micro Devices, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: AMD 25 * 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: amdgpu_rn_clk_mgr_vbios_smu.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $"); 30 31 #include "core_types.h" 32 #include "clk_mgr_internal.h" 33 #include "reg_helper.h" 34 35 #include "renoir_ip_offset.h" 36 37 #include "mp/mp_12_0_0_offset.h" 38 #include "mp/mp_12_0_0_sh_mask.h" 39 40 #define REG(reg_name) \ 41 (MP0_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name) 42 43 #define FN(reg_name, field) \ 44 FD(reg_name##__##field) 45 46 #define VBIOSSMC_MSG_TestMessage 0x1 47 #define VBIOSSMC_MSG_GetSmuVersion 0x2 48 #define VBIOSSMC_MSG_PowerUpGfx 0x3 49 #define VBIOSSMC_MSG_SetDispclkFreq 0x4 50 #define VBIOSSMC_MSG_SetDprefclkFreq 0x5 51 #define VBIOSSMC_MSG_PowerDownGfx 0x6 52 #define VBIOSSMC_MSG_SetDppclkFreq 0x7 53 #define VBIOSSMC_MSG_SetHardMinDcfclkByFreq 0x8 54 #define VBIOSSMC_MSG_SetMinDeepSleepDcfclk 0x9 55 #define VBIOSSMC_MSG_SetPhyclkVoltageByFreq 0xA 56 #define VBIOSSMC_MSG_GetFclkFrequency 0xB 57 #define VBIOSSMC_MSG_SetDisplayCount 0xC 58 #define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xD 59 #define VBIOSSMC_MSG_UpdatePmeRestore 0xE 60 61 int rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param) 62 { 63 /* First clear response register */ 64 REG_WRITE(MP1_SMN_C2PMSG_91, 0); 65 66 /* Set the parameter register for the SMU message, unit is Mhz */ 67 REG_WRITE(MP1_SMN_C2PMSG_83, param); 68 69 /* Trigger the message transaction by writing the message ID */ 70 REG_WRITE(MP1_SMN_C2PMSG_67, msg_id); 71 72 REG_WAIT(MP1_SMN_C2PMSG_91, CONTENT, 1, 10, 200000); 73 74 /* Actual dispclk set is returned in the parameter register */ 75 return REG_READ(MP1_SMN_C2PMSG_83); 76 } 77 78 int rn_vbios_smu_get_smu_version(struct clk_mgr_internal *clk_mgr) 79 { 80 return rn_vbios_smu_send_msg_with_param( 81 clk_mgr, 82 VBIOSSMC_MSG_GetSmuVersion, 83 0); 84 } 85 86 87 int rn_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz) 88 { 89 int actual_dispclk_set_mhz = -1; 90 struct dc *dc = clk_mgr->base.ctx->dc; 91 struct dmcu *dmcu = dc->res_pool->dmcu; 92 93 /* Unit of SMU msg parameter is Mhz */ 94 actual_dispclk_set_mhz = rn_vbios_smu_send_msg_with_param( 95 clk_mgr, 96 VBIOSSMC_MSG_SetDispclkFreq, 97 requested_dispclk_khz / 1000); 98 99 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { 100 if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { 101 if (clk_mgr->dfs_bypass_disp_clk != actual_dispclk_set_mhz) 102 dmcu->funcs->set_psr_wait_loop(dmcu, 103 actual_dispclk_set_mhz / 7); 104 } 105 } 106 107 return actual_dispclk_set_mhz * 1000; 108 } 109 110 int rn_vbios_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr) 111 { 112 int actual_dprefclk_set_mhz = -1; 113 114 actual_dprefclk_set_mhz = rn_vbios_smu_send_msg_with_param( 115 clk_mgr, 116 VBIOSSMC_MSG_SetDprefclkFreq, 117 clk_mgr->base.dprefclk_khz / 1000); 118 119 /* TODO: add code for programing DP DTO, currently this is down by command table */ 120 121 return actual_dprefclk_set_mhz * 1000; 122 } 123 124 int rn_vbios_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz) 125 { 126 int actual_dcfclk_set_mhz = -1; 127 128 if (clk_mgr->smu_ver < 0x370c00) 129 return actual_dcfclk_set_mhz; 130 131 actual_dcfclk_set_mhz = rn_vbios_smu_send_msg_with_param( 132 clk_mgr, 133 VBIOSSMC_MSG_SetHardMinDcfclkByFreq, 134 requested_dcfclk_khz / 1000); 135 136 return actual_dcfclk_set_mhz * 1000; 137 } 138 139 int rn_vbios_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz) 140 { 141 int actual_min_ds_dcfclk_mhz = -1; 142 143 if (clk_mgr->smu_ver < 0x370c00) 144 return actual_min_ds_dcfclk_mhz; 145 146 actual_min_ds_dcfclk_mhz = rn_vbios_smu_send_msg_with_param( 147 clk_mgr, 148 VBIOSSMC_MSG_SetMinDeepSleepDcfclk, 149 requested_min_ds_dcfclk_khz / 1000); 150 151 return actual_min_ds_dcfclk_mhz * 1000; 152 } 153 154 void rn_vbios_smu_set_phyclk(struct clk_mgr_internal *clk_mgr, int requested_phyclk_khz) 155 { 156 rn_vbios_smu_send_msg_with_param( 157 clk_mgr, 158 VBIOSSMC_MSG_SetPhyclkVoltageByFreq, 159 requested_phyclk_khz / 1000); 160 } 161 162 int rn_vbios_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz) 163 { 164 int actual_dppclk_set_mhz = -1; 165 166 actual_dppclk_set_mhz = rn_vbios_smu_send_msg_with_param( 167 clk_mgr, 168 VBIOSSMC_MSG_SetDppclkFreq, 169 requested_dpp_khz / 1000); 170 171 return actual_dppclk_set_mhz * 1000; 172 } 173 174 void rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal *clk_mgr, enum dcn_pwr_state state) 175 { 176 int disp_count; 177 178 if (state == DCN_PWR_STATE_LOW_POWER) 179 disp_count = 0; 180 else 181 disp_count = 1; 182 183 rn_vbios_smu_send_msg_with_param( 184 clk_mgr, 185 VBIOSSMC_MSG_SetDisplayCount, 186 disp_count); 187 } 188 189 void rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable) 190 { 191 rn_vbios_smu_send_msg_with_param( 192 clk_mgr, 193 VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown, 194 enable); 195 } 196 197 void rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr) 198 { 199 rn_vbios_smu_send_msg_with_param( 200 clk_mgr, 201 VBIOSSMC_MSG_UpdatePmeRestore, 202 0); 203 } 204