Line data Source code
1 : // SPDX-License-Identifier: MIT
2 : /*
3 : * Copyright 2022 Advanced Micro Devices, Inc.
4 : *
5 : * Permission is hereby granted, free of charge, to any person obtaining a
6 : * copy of this software and associated documentation files (the "Software"),
7 : * to deal in the Software without restriction, including without limitation
8 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 : * and/or sell copies of the Software, and to permit persons to whom the
10 : * Software is furnished to do so, subject to the following conditions:
11 : *
12 : * The above copyright notice and this permission notice shall be included in
13 : * all copies or substantial portions of the Software.
14 : *
15 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 : * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 : * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 : * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 : * OTHER DEALINGS IN THE SOFTWARE.
22 : *
23 : * Authors: AMD
24 : *
25 : */
26 :
27 :
28 :
29 : #include "core_types.h"
30 : #include "clk_mgr_internal.h"
31 : #include "reg_helper.h"
32 : #include "dm_helpers.h"
33 : #include "dcn314_smu.h"
34 :
35 : #include "mp/mp_13_0_5_offset.h"
36 :
37 : /* TODO: Use the real headers when they're correct */
38 : #define MP1_BASE__INST0_SEG0 0x00016000
39 : #define MP1_BASE__INST0_SEG1 0x0243FC00
40 : #define MP1_BASE__INST0_SEG2 0x00DC0000
41 : #define MP1_BASE__INST0_SEG3 0x00E00000
42 : #define MP1_BASE__INST0_SEG4 0x00E40000
43 : #define MP1_BASE__INST0_SEG5 0
44 :
45 : #ifdef BASE_INNER
46 : #undef BASE_INNER
47 : #endif
48 :
49 : #define BASE_INNER(seg) MP1_BASE__INST0_SEG ## seg
50 :
51 : #define BASE(seg) BASE_INNER(seg)
52 :
53 : #define REG(reg_name) (BASE(reg##reg_name##_BASE_IDX) + reg##reg_name)
54 :
55 : #define FN(reg_name, field) \
56 : FD(reg_name##__##field)
57 :
58 : #include "logger_types.h"
59 : #undef DC_LOGGER
60 : #define DC_LOGGER \
61 : CTX->logger
62 : #define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
63 :
64 : #define VBIOSSMC_MSG_TestMessage 0x1
65 : #define VBIOSSMC_MSG_GetSmuVersion 0x2
66 : #define VBIOSSMC_MSG_PowerUpGfx 0x3
67 : #define VBIOSSMC_MSG_SetDispclkFreq 0x4
68 : #define VBIOSSMC_MSG_SetDprefclkFreq 0x5 //Not used. DPRef is constant
69 : #define VBIOSSMC_MSG_SetDppclkFreq 0x6
70 : #define VBIOSSMC_MSG_SetHardMinDcfclkByFreq 0x7
71 : #define VBIOSSMC_MSG_SetMinDeepSleepDcfclk 0x8
72 : #define VBIOSSMC_MSG_SetPhyclkVoltageByFreq 0x9 //Keep it in case VMIN dees not support phy clk
73 : #define VBIOSSMC_MSG_GetFclkFrequency 0xA
74 : #define VBIOSSMC_MSG_SetDisplayCount 0xB //Not used anymore
75 : #define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xC //Not used anymore
76 : #define VBIOSSMC_MSG_UpdatePmeRestore 0xD
77 : #define VBIOSSMC_MSG_SetVbiosDramAddrHigh 0xE //Used for WM table txfr
78 : #define VBIOSSMC_MSG_SetVbiosDramAddrLow 0xF
79 : #define VBIOSSMC_MSG_TransferTableSmu2Dram 0x10
80 : #define VBIOSSMC_MSG_TransferTableDram2Smu 0x11
81 : #define VBIOSSMC_MSG_SetDisplayIdleOptimizations 0x12
82 : #define VBIOSSMC_MSG_GetDprefclkFreq 0x13
83 : #define VBIOSSMC_MSG_GetDtbclkFreq 0x14
84 : #define VBIOSSMC_MSG_AllowZstatesEntry 0x15
85 : #define VBIOSSMC_MSG_DisallowZstatesEntry 0x16
86 : #define VBIOSSMC_MSG_SetDtbClk 0x17
87 : #define VBIOSSMC_Message_Count 0x18
88 :
89 : #define VBIOSSMC_Status_BUSY 0x0
90 : #define VBIOSSMC_Result_OK 0x1
91 : #define VBIOSSMC_Result_Failed 0xFF
92 : #define VBIOSSMC_Result_UnknownCmd 0xFE
93 : #define VBIOSSMC_Result_CmdRejectedPrereq 0xFD
94 : #define VBIOSSMC_Result_CmdRejectedBusy 0xFC
95 :
96 : /*
97 : * Function to be used instead of REG_WAIT macro because the wait ends when
98 : * the register is NOT EQUAL to zero, and because the translation in msg_if.h
99 : * won't work with REG_WAIT.
100 : */
101 0 : static uint32_t dcn314_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
102 : {
103 0 : uint32_t res_val = VBIOSSMC_Status_BUSY;
104 :
105 : do {
106 0 : res_val = REG_READ(MP1_SMN_C2PMSG_91);
107 0 : if (res_val != VBIOSSMC_Status_BUSY)
108 : break;
109 :
110 0 : if (delay_us >= 1000)
111 0 : msleep(delay_us/1000);
112 0 : else if (delay_us > 0)
113 0 : udelay(delay_us);
114 0 : } while (max_retries--);
115 :
116 0 : return res_val;
117 : }
118 :
119 0 : static int dcn314_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
120 : unsigned int msg_id,
121 : unsigned int param)
122 : {
123 : uint32_t result;
124 :
125 0 : result = dcn314_smu_wait_for_response(clk_mgr, 10, 200000);
126 0 : ASSERT(result == VBIOSSMC_Result_OK);
127 :
128 : smu_print("SMU response after wait: %d\n", result);
129 :
130 0 : if (result == VBIOSSMC_Status_BUSY)
131 : return -1;
132 :
133 : /* First clear response register */
134 0 : REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
135 :
136 : /* Set the parameter register for the SMU message, unit is Mhz */
137 0 : REG_WRITE(MP1_SMN_C2PMSG_83, param);
138 :
139 : /* Trigger the message transaction by writing the message ID */
140 0 : REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
141 :
142 0 : result = dcn314_smu_wait_for_response(clk_mgr, 10, 200000);
143 :
144 0 : if (result == VBIOSSMC_Result_Failed) {
145 0 : if (msg_id == VBIOSSMC_MSG_TransferTableDram2Smu &&
146 0 : param == TABLE_WATERMARKS)
147 0 : DC_LOG_WARNING("Watermarks table not configured properly by SMU");
148 : else
149 0 : ASSERT(0);
150 0 : REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK);
151 0 : return -1;
152 : }
153 :
154 0 : if (IS_SMU_TIMEOUT(result)) {
155 0 : ASSERT(0);
156 0 : dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000);
157 : }
158 :
159 0 : return REG_READ(MP1_SMN_C2PMSG_83);
160 : }
161 :
162 0 : int dcn314_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
163 : {
164 0 : return dcn314_smu_send_msg_with_param(
165 : clk_mgr,
166 : VBIOSSMC_MSG_GetSmuVersion,
167 : 0);
168 : }
169 :
170 :
171 0 : int dcn314_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
172 : {
173 0 : int actual_dispclk_set_mhz = -1;
174 :
175 0 : if (!clk_mgr->smu_present)
176 : return requested_dispclk_khz;
177 :
178 : /* Unit of SMU msg parameter is Mhz */
179 0 : actual_dispclk_set_mhz = dcn314_smu_send_msg_with_param(
180 : clk_mgr,
181 : VBIOSSMC_MSG_SetDispclkFreq,
182 0 : khz_to_mhz_ceil(requested_dispclk_khz));
183 :
184 0 : return actual_dispclk_set_mhz * 1000;
185 : }
186 :
187 0 : int dcn314_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr)
188 : {
189 0 : int actual_dprefclk_set_mhz = -1;
190 :
191 0 : if (!clk_mgr->smu_present)
192 0 : return clk_mgr->base.dprefclk_khz;
193 :
194 0 : actual_dprefclk_set_mhz = dcn314_smu_send_msg_with_param(
195 : clk_mgr,
196 : VBIOSSMC_MSG_SetDprefclkFreq,
197 0 : khz_to_mhz_ceil(clk_mgr->base.dprefclk_khz));
198 :
199 : /* TODO: add code for programing DP DTO, currently this is down by command table */
200 :
201 0 : return actual_dprefclk_set_mhz * 1000;
202 : }
203 :
204 0 : int dcn314_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
205 : {
206 0 : int actual_dcfclk_set_mhz = -1;
207 :
208 0 : if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
209 : return -1;
210 :
211 0 : if (!clk_mgr->smu_present)
212 : return requested_dcfclk_khz;
213 :
214 0 : actual_dcfclk_set_mhz = dcn314_smu_send_msg_with_param(
215 : clk_mgr,
216 : VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
217 0 : khz_to_mhz_ceil(requested_dcfclk_khz));
218 :
219 0 : return actual_dcfclk_set_mhz * 1000;
220 : }
221 :
222 0 : int dcn314_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
223 : {
224 0 : int actual_min_ds_dcfclk_mhz = -1;
225 :
226 0 : if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
227 : return -1;
228 :
229 0 : if (!clk_mgr->smu_present)
230 : return requested_min_ds_dcfclk_khz;
231 :
232 0 : actual_min_ds_dcfclk_mhz = dcn314_smu_send_msg_with_param(
233 : clk_mgr,
234 : VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
235 0 : khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
236 :
237 0 : return actual_min_ds_dcfclk_mhz * 1000;
238 : }
239 :
240 0 : int dcn314_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
241 : {
242 0 : int actual_dppclk_set_mhz = -1;
243 :
244 0 : if (!clk_mgr->smu_present)
245 : return requested_dpp_khz;
246 :
247 0 : actual_dppclk_set_mhz = dcn314_smu_send_msg_with_param(
248 : clk_mgr,
249 : VBIOSSMC_MSG_SetDppclkFreq,
250 0 : khz_to_mhz_ceil(requested_dpp_khz));
251 :
252 0 : return actual_dppclk_set_mhz * 1000;
253 : }
254 :
255 0 : void dcn314_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
256 : {
257 0 : if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
258 : return;
259 :
260 0 : if (!clk_mgr->smu_present)
261 : return;
262 :
263 : //TODO: Work with smu team to define optimization options.
264 0 : dcn314_smu_send_msg_with_param(
265 : clk_mgr,
266 : VBIOSSMC_MSG_SetDisplayIdleOptimizations,
267 : idle_info);
268 : }
269 :
270 0 : void dcn314_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
271 : {
272 0 : union display_idle_optimization_u idle_info = { 0 };
273 :
274 0 : if (!clk_mgr->smu_present)
275 0 : return;
276 :
277 0 : if (enable) {
278 0 : idle_info.idle_info.df_request_disabled = 1;
279 0 : idle_info.idle_info.phy_ref_clk_off = 1;
280 : }
281 :
282 0 : dcn314_smu_send_msg_with_param(
283 : clk_mgr,
284 : VBIOSSMC_MSG_SetDisplayIdleOptimizations,
285 : idle_info.data);
286 : }
287 :
288 0 : void dcn314_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
289 : {
290 0 : if (!clk_mgr->smu_present)
291 : return;
292 :
293 0 : dcn314_smu_send_msg_with_param(
294 : clk_mgr,
295 : VBIOSSMC_MSG_UpdatePmeRestore,
296 : 0);
297 : }
298 :
299 0 : void dcn314_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
300 : {
301 0 : if (!clk_mgr->smu_present)
302 : return;
303 :
304 0 : dcn314_smu_send_msg_with_param(clk_mgr,
305 : VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
306 : }
307 :
308 0 : void dcn314_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
309 : {
310 0 : if (!clk_mgr->smu_present)
311 : return;
312 :
313 0 : dcn314_smu_send_msg_with_param(clk_mgr,
314 : VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
315 : }
316 :
317 0 : void dcn314_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
318 : {
319 0 : if (!clk_mgr->smu_present)
320 : return;
321 :
322 0 : dcn314_smu_send_msg_with_param(clk_mgr,
323 : VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
324 : }
325 :
326 0 : void dcn314_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
327 : {
328 0 : if (!clk_mgr->smu_present)
329 : return;
330 :
331 0 : dcn314_smu_send_msg_with_param(clk_mgr,
332 : VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
333 : }
334 :
335 0 : void dcn314_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zstate_support_state support)
336 : {
337 : unsigned int msg_id, param;
338 :
339 0 : if (!clk_mgr->smu_present)
340 : return;
341 :
342 0 : if (!clk_mgr->base.ctx->dc->debug.enable_z9_disable_interface &&
343 : (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY))
344 0 : support = DCN_ZSTATE_SUPPORT_DISALLOW;
345 :
346 :
347 : // Arg[15:0] = 8/9/0 for Z8/Z9/disallow -> existing bits
348 : // Arg[16] = Disallow Z9 -> new bit
349 : switch (support) {
350 :
351 : case DCN_ZSTATE_SUPPORT_ALLOW:
352 : msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
353 : param = 9;
354 : break;
355 :
356 : case DCN_ZSTATE_SUPPORT_DISALLOW:
357 : msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
358 : param = 8;
359 : break;
360 :
361 :
362 : case DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY:
363 : msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
364 : param = 0x00010008;
365 : break;
366 :
367 : default: //DCN_ZSTATE_SUPPORT_UNKNOWN
368 : msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
369 : param = 0;
370 : break;
371 : }
372 :
373 :
374 0 : dcn314_smu_send_msg_with_param(
375 : clk_mgr,
376 : msg_id,
377 : param);
378 :
379 : }
380 :
381 : /* Arg = 1: Turn DTB on; 0: Turn DTB CLK OFF. when it is on, it is 600MHZ */
382 0 : void dcn314_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
383 : {
384 0 : if (!clk_mgr->smu_present)
385 : return;
386 :
387 0 : dcn314_smu_send_msg_with_param(
388 : clk_mgr,
389 : VBIOSSMC_MSG_SetDtbClk,
390 : enable);
391 : }
|