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
rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal * clk_mgr,unsigned int msg_id,unsigned int param)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
rn_vbios_smu_get_smu_version(struct clk_mgr_internal * clk_mgr)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
rn_vbios_smu_set_dispclk(struct clk_mgr_internal * clk_mgr,int requested_dispclk_khz)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
rn_vbios_smu_set_dprefclk(struct clk_mgr_internal * clk_mgr)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
rn_vbios_smu_set_hard_min_dcfclk(struct clk_mgr_internal * clk_mgr,int requested_dcfclk_khz)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
rn_vbios_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal * clk_mgr,int requested_min_ds_dcfclk_khz)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
rn_vbios_smu_set_phyclk(struct clk_mgr_internal * clk_mgr,int requested_phyclk_khz)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
rn_vbios_smu_set_dppclk(struct clk_mgr_internal * clk_mgr,int requested_dpp_khz)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
rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal * clk_mgr,enum dcn_pwr_state state)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
rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal * clk_mgr,bool enable)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
rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal * clk_mgr)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