1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2025 Advanced Micro Devices, Inc.
4
5 #include "dccg.h"
6 #include "clk_mgr_internal.h"
7 #include "dcn60/dcn60_clk_mgr_smu_msg.h"
8 #include "hw_sequencer.h"
9 #include "dce100/dce_clk_mgr.h"
10 #include "dcn20/dcn20_clk_mgr.h"
11 #include "dcn401/dcn401_clk_mgr.h"
12 #include "dcn60/dcn60_clk_mgr.h"
13 #include "soc_and_ip_translator.h"
14 #include "bounding_boxes/utm_qos_model_types.h"
15 #include "bounding_boxes/utm_qos_model_dchub_v3.h"
16 #include "reg_helper.h"
17 #include "core_types.h"
18 #include "dm_helpers.h"
19 #include "link_service.h"
20 #include "dc_state_priv.h"
21 #include "atomfirmware.h"
22
23 #include "dcn401/dcn401_smu14_driver_if.h"
24
25 #include "dcn/dcn_6_0_0_offset.h"
26 #include "dcn/dcn_6_0_0_sh_mask.h"
27
28 #undef DC_LOGGER
29 #define DC_LOGGER \
30 clk_mgr_base->ctx->logger
31
32 #define mmCLK08_CLK8_CLK0_CURRENT_CNT 0x1B83F
33 #define mmCLK08_CLK8_CLK1_CURRENT_CNT 0x1B840
34 #define mmCLK08_CLK8_CLK2_CURRENT_CNT 0x1B841
35 #define mmCLK08_CLK8_CLK3_CURRENT_CNT 0x1B842
36 #define mmCLK08_CLK8_CLK4_CURRENT_CNT 0x1B843
37
38 #define mmCLK08_CLK8_CLK0_BYPASS_CNTL 0x1B816
39 #define mmCLK08_CLK8_CLK1_BYPASS_CNTL 0x1B81E
40 #define mmCLK08_CLK8_CLK2_BYPASS_CNTL 0x1B826
41 #define mmCLK08_CLK8_CLK3_BYPASS_CNTL 0x1B82E
42 #define mmCLK08_CLK8_CLK4_BYPASS_CNTL 0x1B836
43
44 #define mmCLK08_CLK8_CLK0_DS_CNTL 0x1B810
45 #define mmCLK08_CLK8_CLK1_DS_CNTL 0x1B818
46 #define mmCLK08_CLK8_CLK2_DS_CNTL 0x1B820
47 #define mmCLK08_CLK8_CLK3_DS_CNTL 0x1B828
48 #define mmCLK08_CLK8_CLK4_DS_CNTL 0x1B830
49
50 #define mmCLK08_CLK8_CLK_TICK_CNT_CONFIG_REG 0x1B83D
51
52 #define DCN_BASE__INST0_SEG1 0x000000C0
53
54 #define CLK8_CLK_TICK_CNT_CONFIG_REG__TIMER_THRESHOLD__SHIFT 0x0
55 #define CLK8_CLK_TICK_CNT_CONFIG_REG__TIMER_THRESHOLD_MASK 0x00FFFFFFL
56 #define CLK8_CLK0_BYPASS_CNTL__CLK0_BYPASS_SEL__SHIFT 0x0
57 #define CLK8_CLK0_BYPASS_CNTL__CLK0_BYPASS_SEL_MASK 0x00000007L
58 #define CLK8_CLK1_BYPASS_CNTL__CLK1_BYPASS_SEL__SHIFT 0x0
59 #define CLK8_CLK1_BYPASS_CNTL__CLK1_BYPASS_SEL_MASK 0x00000007L
60 #define CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL__SHIFT 0x0
61 #define CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL_MASK 0x00000007L
62 #define CLK8_CLK3_BYPASS_CNTL__CLK3_BYPASS_SEL__SHIFT 0x0
63 #define CLK8_CLK3_BYPASS_CNTL__CLK3_BYPASS_SEL_MASK 0x00000007L
64 #define CLK8_CLK4_BYPASS_CNTL__CLK4_BYPASS_SEL__SHIFT 0x0
65 #define CLK8_CLK4_BYPASS_CNTL__CLK4_BYPASS_SEL_MASK 0x00000007L
66 #define CLK8_CLK0_DS_CNTL__CLK0_DS_DIV_ID__SHIFT 0x0
67 #define CLK8_CLK0_DS_CNTL__CLK0_ALLOW_DS__SHIFT 0x4
68 #define CLK8_CLK0_DS_CNTL__CLK0_DS_DIV_ID_MASK 0x0000000FL
69 #define CLK8_CLK0_DS_CNTL__CLK0_ALLOW_DS_MASK 0x00000010L
70 #define CLK8_CLK1_DS_CNTL__CLK1_DS_DIV_ID__SHIFT 0x0
71 #define CLK8_CLK1_DS_CNTL__CLK1_ALLOW_DS__SHIFT 0x4
72 #define CLK8_CLK1_DS_CNTL__CLK1_DS_DIV_ID_MASK 0x0000000FL
73 #define CLK8_CLK1_DS_CNTL__CLK1_ALLOW_DS_MASK 0x00000010L
74 #define CLK8_CLK2_DS_CNTL__CLK2_DS_DIV_ID__SHIFT 0x0
75 #define CLK8_CLK2_DS_CNTL__CLK2_ALLOW_DS__SHIFT 0x4
76 #define CLK8_CLK2_DS_CNTL__CLK2_DS_DIV_ID_MASK 0x0000000FL
77 #define CLK8_CLK2_DS_CNTL__CLK2_ALLOW_DS_MASK 0x00000010L
78 #define CLK8_CLK3_DS_CNTL__CLK3_DS_DIV_ID__SHIFT 0x0
79 #define CLK8_CLK3_DS_CNTL__CLK3_ALLOW_DS__SHIFT 0x4
80 #define CLK8_CLK3_DS_CNTL__CLK3_DS_DIV_ID_MASK 0x0000000FL
81 #define CLK8_CLK3_DS_CNTL__CLK3_ALLOW_DS_MASK 0x00000010L
82 #define CLK8_CLK4_DS_CNTL__CLK4_DS_DIV_ID__SHIFT 0x0
83 #define CLK8_CLK4_DS_CNTL__CLK4_ALLOW_DS__SHIFT 0x4
84 #define CLK8_CLK4_DS_CNTL__CLK4_DS_DIV_ID_MASK 0x0000000FL
85 #define CLK8_CLK4_DS_CNTL__CLK4_ALLOW_DS_MASK 0x00000010L
86
87 #define DCN60_CLKIP_REFCLK_KHZ 48000 /* 48 MHz */
88
89 #undef FN
90 #define FN(reg_name, field_name) \
91 clk_mgr->clk_mgr_shift->field_name, clk_mgr->clk_mgr_mask->field_name
92
93 #define REG(reg) \
94 (clk_mgr->regs->reg)
95
96 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
97
98 #define BASE(seg) BASE_INNER(seg)
99
100 #define SR(reg_name)\
101 .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \
102 reg ## reg_name
103
104 #define CLK_SR_DCN60(reg_name, block, inst)\
105 .reg_name = mm ## block ## _ ## reg_name
106
107 static const struct clk_mgr_registers clk_mgr_regs_dcn60 = {
108 CLK_REG_LIST_DCN60()
109 };
110
111 static const struct clk_mgr_shift clk_mgr_shift_dcn60 = {
112 CLK_COMMON_MASK_SH_LIST_DCN60(__SHIFT)
113 };
114
115 static const struct clk_mgr_mask clk_mgr_mask_dcn60 = {
116 CLK_COMMON_MASK_SH_LIST_DCN60(_MASK)
117 };
118
119 #define TO_DCN60_CLK_MGR(clk_mgr)\
120 container_of(clk_mgr, struct dcn60_clk_mgr, base)
121
dcn60_is_ppclk_dpm_enabled(struct clk_mgr_internal * clk_mgr,PPCLK_e clk)122 static bool dcn60_is_ppclk_dpm_enabled(struct clk_mgr_internal *clk_mgr, PPCLK_e clk)
123 {
124 bool ppclk_dpm_enabled = false;
125
126 switch (clk) {
127 case PPCLK_SOCCLK:
128 ppclk_dpm_enabled =
129 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_socclk_levels > 1;
130 break;
131 case PPCLK_UCLK:
132 ppclk_dpm_enabled =
133 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_memclk_levels > 1;
134 break;
135 case PPCLK_FCLK:
136 ppclk_dpm_enabled =
137 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_fclk_levels > 1;
138 break;
139 case PPCLK_DISPCLK:
140 ppclk_dpm_enabled =
141 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dispclk_levels > 1;
142 break;
143 case PPCLK_DPPCLK:
144 ppclk_dpm_enabled =
145 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dppclk_levels > 1;
146 break;
147 case PPCLK_DPREFCLK:
148 ppclk_dpm_enabled = false;
149 break;
150 case PPCLK_DCFCLK:
151 ppclk_dpm_enabled =
152 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels > 1;
153 break;
154 case PPCLK_DTBCLK:
155 ppclk_dpm_enabled =
156 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels > 1;
157 break;
158 default:
159 ppclk_dpm_enabled = false;
160 }
161
162 ppclk_dpm_enabled &= clk_mgr->smu_present;
163
164 return ppclk_dpm_enabled;
165 }
166
dcn60_check_native_scaling(struct pipe_ctx * pipe)167 static bool dcn60_check_native_scaling(struct pipe_ctx *pipe)
168 {
169 bool is_native_scaling = false;
170 int width = pipe->plane_state->src_rect.width;
171 int height = pipe->plane_state->src_rect.height;
172
173 if (pipe->stream->timing.h_addressable == width &&
174 pipe->stream->timing.v_addressable == height &&
175 pipe->plane_state->dst_rect.width == width &&
176 pipe->plane_state->dst_rect.height == height)
177 is_native_scaling = true;
178
179 return is_native_scaling;
180 }
181
dcn60_update_clocks_update_dpp_dto(struct clk_mgr_internal * clk_mgr,struct dc_state * context,bool safe_to_lower,int ref_dppclk_khz)182 static void dcn60_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr,
183 struct dc_state *context, bool safe_to_lower, int ref_dppclk_khz)
184 {
185 uint32_t i;
186
187 clk_mgr->dccg->ref_dppclk = ref_dppclk_khz;
188 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
189 int dpp_inst = 0, dppclk_khz, prev_dppclk_khz;
190
191 dppclk_khz = context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz;
192
193 if (context->res_ctx.pipe_ctx[i].plane_res.dpp)
194 dpp_inst = context->res_ctx.pipe_ctx[i].plane_res.dpp->inst;
195 else if (!context->res_ctx.pipe_ctx[i].plane_res.dpp && dppclk_khz == 0) {
196 /* dpp == NULL && dppclk_khz == 0 is valid because of pipe harvesting.
197 * In this case just continue in loop
198 */
199 continue;
200 } else if (!context->res_ctx.pipe_ctx[i].plane_res.dpp && dppclk_khz > 0) {
201 /* The software state is not valid if dpp resource is NULL and
202 * dppclk_khz > 0.
203 */
204 ASSERT(false);
205 continue;
206 }
207
208 prev_dppclk_khz = clk_mgr->dccg->pipe_dppclk_khz[i];
209
210 if (safe_to_lower || prev_dppclk_khz < dppclk_khz)
211 clk_mgr->dccg->funcs->update_dpp_dto(
212 clk_mgr->dccg, dpp_inst, dppclk_khz);
213 }
214 }
215
dcn60_set_hard_min_by_freq_optimized(struct clk_mgr_internal * clk_mgr,PPCLK_e clk,int requested_clk_khz)216 static int dcn60_set_hard_min_by_freq_optimized(struct clk_mgr_internal *clk_mgr, PPCLK_e clk, int requested_clk_khz)
217 {
218 if (!clk_mgr->smu_present || !dcn60_is_ppclk_dpm_enabled(clk_mgr, clk))
219 return 0;
220
221 /*
222 * SMU set hard min interface takes requested clock in mhz and return
223 * actual clock configured in khz. If we floor requested clk to mhz,
224 * there is a chance that the actual clock configured in khz is less
225 * than requested. If we ceil it to mhz, there is a chance that it
226 * unnecessarily dumps up to a higher dpm level, which burns more power.
227 * The solution is to set by flooring it to mhz first. If the actual
228 * clock returned is less than requested, then we will ceil the
229 * requested value to mhz and call it again.
230 */
231 int actual_clk_khz = dcn60_smu_set_hard_min_by_freq(clk_mgr, clk,
232 (uint16_t)khz_to_mhz_floor(requested_clk_khz));
233
234 if (actual_clk_khz < requested_clk_khz)
235 actual_clk_khz = dcn60_smu_set_hard_min_by_freq(clk_mgr, clk,
236 (uint16_t)khz_to_mhz_ceil(requested_clk_khz));
237
238 return actual_clk_khz;
239 }
240
dcn60_update_clocks_update_dtb_dto(struct clk_mgr_internal * clk_mgr,struct dc_state * context,int ref_dtbclk_khz)241 static void dcn60_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
242 struct dc_state *context,
243 int ref_dtbclk_khz)
244 {
245 (void)ref_dtbclk_khz;
246 int i;
247 struct dccg *dccg = clk_mgr->dccg;
248 struct pipe_ctx *otg_master;
249 bool use_hpo_encoder;
250
251 for (i = 0; i < context->stream_count; i++) {
252 otg_master = resource_get_otg_master_for_stream(
253 &context->res_ctx, context->streams[i]);
254
255 ASSERT(otg_master);
256 if (!otg_master)
257 continue;
258
259 ASSERT(otg_master->clock_source);
260 ASSERT(otg_master->clock_source->funcs->program_pix_clk);
261 ASSERT(otg_master->stream_res.pix_clk_params.controller_id >= CONTROLLER_ID_D0);
262
263 use_hpo_encoder = dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(otg_master);
264 use_hpo_encoder |= dc_is_hdmi_frl_signal(otg_master->stream->signal);
265 if (!use_hpo_encoder)
266 continue;
267
268 if (otg_master->stream_res.pix_clk_params.controller_id > CONTROLLER_ID_UNDEFINED)
269 otg_master->clock_source->funcs->program_pix_clk(
270 otg_master->clock_source,
271 &otg_master->stream_res.pix_clk_params,
272 dccg->ctx->dc->link_srv->dp_get_encoding_format(
273 &otg_master->link_config.dp_link_settings),
274 &otg_master->pll_settings);
275 }
276 }
277
dcn60_build_update_display_clocks_sequence(struct clk_mgr * clk_mgr_base,struct dc_state * context,struct dc_clocks * new_clocks,bool safe_to_lower,unsigned int num_steps_start)278 static unsigned int dcn60_build_update_display_clocks_sequence(
279 struct clk_mgr *clk_mgr_base,
280 struct dc_state *context,
281 struct dc_clocks *new_clocks,
282 bool safe_to_lower,
283 unsigned int num_steps_start)
284 {
285 struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base);
286 struct dcn60_clk_mgr *clk_mgr60 = TO_DCN60_CLK_MGR(clk_mgr_internal);
287 struct dc *dc = clk_mgr_base->ctx->dc;
288 struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;
289 struct dcn60_clk_mgr_block_sequence *block_sequence = clk_mgr60->block_sequence;
290 bool force_reset = false;
291 bool update_dispclk = false;
292 bool update_dppclk = false;
293 bool dppclk_lowered = false;
294 struct pipe_ctx *otg_master;
295 bool frl_present = false;
296 unsigned int i;
297
298 unsigned int num_steps = num_steps_start;
299
300 /* CLK_MGR60_READ_CLOCKS_FROM_DENTIST */
301 if (clk_mgr_base->clks.dispclk_khz == 0 ||
302 (dc->debug.force_clock_mode & 0x1)) {
303 /* This is from resume or boot up, if forced_clock cfg option used,
304 * we bypass program dispclk and DPPCLK, but need set them for S3.
305 * Force_clock_mode 0x1: force reset the clock even it is the same clock
306 * as long as it is in Passive level.
307 */
308 force_reset = true;
309
310 clk_mgr_base->clks.dispclk_khz = clk_mgr_base->boot_snapshot.dispclk;
311 clk_mgr_base->clks.actual_dispclk_khz = clk_mgr_base->clks.dispclk_khz;
312
313 clk_mgr_base->clks.dppclk_khz = clk_mgr_base->boot_snapshot.dppclk;
314 clk_mgr_base->clks.actual_dppclk_khz = clk_mgr_base->clks.dppclk_khz;
315 }
316
317 /* DTBCLK */
318 if (!new_clocks->dtbclk_en && dcn60_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DTBCLK)) {
319 new_clocks->ref_dtbclk_khz = clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
320 }
321
322 /* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */
323 if (!dc->debug.disable_dtb_ref_clk_switch &&
324 should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000, clk_mgr_base->clks.ref_dtbclk_khz / 1000) && //TODO these should be ceiled
325 dcn60_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DTBCLK)) {
326 /* DCCG requires KHz precision for DTBCLK */
327 block_sequence[num_steps].params.update_hardmin_params.ppclk = PPCLK_DTBCLK;
328 block_sequence[num_steps].params.update_hardmin_params.freq_mhz =
329 (uint16_t)khz_to_mhz_ceil(new_clocks->ref_dtbclk_khz);
330 for (i = 0; i < context->stream_count; i++) {
331 otg_master = resource_get_otg_master_for_stream(
332 &context->res_ctx, context->streams[i]);
333 if (otg_master != NULL &&
334 otg_master->stream != NULL &&
335 dc_is_hdmi_frl_signal(otg_master->stream->signal)) {
336 frl_present = true;
337 break;
338 }
339 }
340 if (frl_present)
341 block_sequence[num_steps].params.update_hardmin_params.freq_mhz =
342 (uint16_t)clk_mgr_base->bw_params->clk_table.entries[
343 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels - 1].dtbclk_mhz;
344 block_sequence[num_steps].params.update_hardmin_params.response = &clk_mgr_base->clks.ref_dtbclk_khz;
345 block_sequence[num_steps].func = CLK_MGR60_UPDATE_HARDMIN_PPCLK;
346 num_steps++;
347
348 /* Update DTO in DCCG */
349 block_sequence[num_steps].params.update_dtbclk_dto_params.context = context;
350 block_sequence[num_steps].params.update_dtbclk_dto_params.ref_dtbclk_khz = &clk_mgr_base->clks.ref_dtbclk_khz;
351 block_sequence[num_steps].func = CLK_MGR60_UPDATE_DTBCLK_DTO;
352 num_steps++;
353 }
354
355 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr_base->clks.dppclk_khz)) {
356 if (clk_mgr_base->clks.dppclk_khz > new_clocks->dppclk_khz)
357 dppclk_lowered = true;
358
359 clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
360 clk_mgr_base->clks.actual_dppclk_khz = new_clocks->dppclk_khz;
361
362 update_dppclk = true;
363 }
364
365 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
366 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
367
368 if (dcn60_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DISPCLK)) {
369 block_sequence[num_steps].params.update_hardmin_optimized_params.ppclk = PPCLK_DISPCLK;
370 block_sequence[num_steps].params.update_hardmin_optimized_params.freq_khz = clk_mgr_base->clks.dispclk_khz;
371 block_sequence[num_steps].params.update_hardmin_optimized_params.response = &clk_mgr_base->clks.actual_dispclk_khz;
372 block_sequence[num_steps].func = CLK_MGR60_UPDATE_HARDMIN_PPCLK_OPTIMIZED;
373 num_steps++;
374 }
375
376 update_dispclk = true;
377 }
378
379 if (dc->config.forced_clocks == false || (force_reset && safe_to_lower)) {
380 if (dppclk_lowered) {
381 /* if clock is being lowered, increase DTO before lowering refclk */
382 block_sequence[num_steps].params.update_dppclk_dto_params.context = context;
383 block_sequence[num_steps].params.update_dppclk_dto_params.ref_dppclk_khz = &clk_mgr_base->clks.dppclk_khz;
384 block_sequence[num_steps].params.update_dppclk_dto_params.safe_to_lower = safe_to_lower;
385 block_sequence[num_steps].func = CLK_MGR60_UPDATE_DPPCLK_DTO;
386 num_steps++;
387
388 if (dcn60_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DPPCLK)) {
389 block_sequence[num_steps].params.update_hardmin_optimized_params.ppclk = PPCLK_DPPCLK;
390 block_sequence[num_steps].params.update_hardmin_optimized_params.freq_khz = clk_mgr_base->clks.dppclk_khz;
391 block_sequence[num_steps].params.update_hardmin_optimized_params.response = &clk_mgr_base->clks.actual_dppclk_khz;
392 block_sequence[num_steps].func = CLK_MGR60_UPDATE_HARDMIN_PPCLK_OPTIMIZED;
393 num_steps++;
394
395 block_sequence[num_steps].params.update_dppclk_dto_params.context = context;
396 block_sequence[num_steps].params.update_dppclk_dto_params.ref_dppclk_khz = &clk_mgr_base->clks.actual_dppclk_khz;
397 block_sequence[num_steps].params.update_dppclk_dto_params.safe_to_lower = safe_to_lower;
398 block_sequence[num_steps].func = CLK_MGR60_UPDATE_DPPCLK_DTO;
399 num_steps++;
400 }
401 } else {
402 /* if clock is being raised, increase refclk before lowering DTO */
403 if (update_dppclk && dcn60_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DPPCLK)) {
404 block_sequence[num_steps].params.update_hardmin_optimized_params.ppclk = PPCLK_DPPCLK;
405 block_sequence[num_steps].params.update_hardmin_optimized_params.freq_khz = clk_mgr_base->clks.dppclk_khz;
406 block_sequence[num_steps].params.update_hardmin_optimized_params.response = &clk_mgr_base->clks.actual_dppclk_khz;
407 block_sequence[num_steps].func = CLK_MGR60_UPDATE_HARDMIN_PPCLK_OPTIMIZED;
408 num_steps++;
409 }
410
411 block_sequence[num_steps].params.update_dppclk_dto_params.context = context;
412 block_sequence[num_steps].params.update_dppclk_dto_params.ref_dppclk_khz = &clk_mgr_base->clks.actual_dppclk_khz;
413 block_sequence[num_steps].params.update_dppclk_dto_params.safe_to_lower = safe_to_lower;
414 block_sequence[num_steps].func = CLK_MGR60_UPDATE_DPPCLK_DTO;
415 num_steps++;
416 }
417 }
418
419 if (update_dispclk && dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
420 /*update dmcu for wait_loop count*/
421 block_sequence[num_steps].params.update_psr_wait_loop_params.dmcu = dmcu;
422 block_sequence[num_steps].params.update_psr_wait_loop_params.wait = clk_mgr_base->clks.dispclk_khz / 1000 / 7;
423 block_sequence[num_steps].func = CLK_MGR60_UPDATE_PSR_WAIT_LOOP;
424 num_steps++;
425 }
426
427 return num_steps;
428 }
429
dcn60_get_vco_frequency_from_reg(struct clk_mgr_internal * clk_mgr)430 static uint32_t dcn60_get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr)
431 {
432 (void)clk_mgr;
433 //TODO: Get VCO frequency
434 return 0;
435 }
436
dcn60_are_clock_states_equal(struct dc_clocks * a,struct dc_clocks * b)437 static bool dcn60_are_clock_states_equal(struct dc_clocks *a,
438 struct dc_clocks *b)
439 {
440 if (a->dispclk_khz != b->dispclk_khz)
441 return false;
442 else if (a->dppclk_khz != b->dppclk_khz)
443 return false;
444 else if (a->dcfclk_khz != b->dcfclk_khz)
445 return false;
446 else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz)
447 return false;
448 else if (a->dramclk_khz != b->dramclk_khz)
449 return false;
450 else if (a->p_state_change_support != b->p_state_change_support)
451 return false;
452 else if (a->fclk_p_state_change_support != b->fclk_p_state_change_support)
453 return false;
454
455 return true;
456 }
457
dcn60_is_smu_present(struct clk_mgr * clk_mgr_base)458 static bool dcn60_is_smu_present(struct clk_mgr *clk_mgr_base)
459 {
460 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
461 return clk_mgr->smu_present;
462 }
463
dcn60_get_dtb_ref_freq_khz(struct clk_mgr * clk_mgr_base)464 static int dcn60_get_dtb_ref_freq_khz(struct clk_mgr *clk_mgr_base)
465 {
466 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
467
468 int dtb_ref_clk_khz = 0;
469
470 if (clk_mgr->smu_present && dcn60_is_ppclk_dpm_enabled(clk_mgr, PPCLK_DTBCLK)) {
471 /* DPM enabled, use currently set value */
472 dtb_ref_clk_khz = clk_mgr_base->clks.ref_dtbclk_khz;
473 } else {
474 /* DPM disabled, so use boot snapshot */
475 dtb_ref_clk_khz = clk_mgr_base->boot_snapshot.dtbclk;
476 }
477
478 return dtb_ref_clk_khz;
479 }
480
dcn60_get_dc_mode_limit_mhz(const DpmClock_t * dpm_clk)481 static unsigned int dcn60_get_dc_mode_limit_mhz(const DpmClock_t *dpm_clk)
482 {
483 if (dpm_clk->NumClocks
484 && dpm_clk->DcMaxClock == dpm_clk->Clocks[dpm_clk->NumClocks - 1])
485 return 0;
486
487 return dpm_clk->DcMaxClock;
488 }
489
490 /**
491 * dcn60_populate_dc_mode_limit - Populate DC mode limits from DAL init table.
492 * @dc_limit: output DC mode limit to populate
493 * @init_table: DAL init table transferred from PMFW
494 *
495 * Sets the DC mode max frequency for each clock. If DcMaxClock equals the
496 * highest DPM level, the limit is set to 0 (no DC-specific cap).
497 */
dcn60_populate_dc_mode_limit(struct clk_limit_table_entry * dc_limit,const DalInitTable_t * init_table)498 static void dcn60_populate_dc_mode_limit(
499 struct clk_limit_table_entry *dc_limit,
500 const DalInitTable_t *init_table)
501 {
502 dc_limit->dcfclk_mhz = dcn60_get_dc_mode_limit_mhz(&init_table->PPClocks[PPCLK_DCFCLK]);
503 dc_limit->socclk_mhz = dcn60_get_dc_mode_limit_mhz(&init_table->PPClocks[PPCLK_SOCCLK]);
504 dc_limit->dtbclk_mhz = dcn60_get_dc_mode_limit_mhz(&init_table->PPClocks[PPCLK_DTBCLK]);
505 dc_limit->dispclk_mhz = dcn60_get_dc_mode_limit_mhz(&init_table->PPClocks[PPCLK_DISPCLK]);
506 dc_limit->memclk_mhz = dcn60_get_dc_mode_limit_mhz(&init_table->PPClocks[PPCLK_UCLK]);
507 dc_limit->fclk_mhz = dcn60_get_dc_mode_limit_mhz(&init_table->PPClocks[PPCLK_FCLK]);
508 }
509
510 /**
511 * dcn60_populate_clk_table - Populate clock table from DAL init table.
512 * @clk_mgr: clock manager instance
513 * @clk_table: output clock table to populate
514 * @init_table: DAL init table transferred from PMFW
515 *
516 * Reads the DPM clock levels from the PPClocks array within the DalInitTable_t
517 * populated by PMFW via TABLE_DAL_INIT transfer.
518 */
dcn60_populate_clk_table(struct clk_mgr_internal * clk_mgr,struct clk_limit_table * clk_table,const DalInitTable_t * init_table)519 static void dcn60_populate_clk_table(struct clk_mgr_internal *clk_mgr,
520 struct clk_limit_table *clk_table,
521 const DalInitTable_t *init_table)
522 {
523 struct clk_limit_num_entries *num_entries = &clk_table->num_entries_per_clk;
524 const DpmClock_t *dpm_clk;
525 unsigned int i;
526
527 /* DCFCLK */
528 dpm_clk = &init_table->PPClocks[PPCLK_DCFCLK];
529 num_entries->num_dcfclk_levels = dpm_clk->NumClocks;
530 for (i = 0; i < dpm_clk->NumClocks && i < NUM_CLOCK_LEVELS; i++)
531 clk_table->entries[i].dcfclk_mhz = dpm_clk->Clocks[i];
532
533 /* SOCCLK */
534 dpm_clk = &init_table->PPClocks[PPCLK_SOCCLK];
535 num_entries->num_socclk_levels = dpm_clk->NumClocks;
536 for (i = 0; i < dpm_clk->NumClocks && i < NUM_CLOCK_LEVELS; i++)
537 clk_table->entries[i].socclk_mhz = dpm_clk->Clocks[i];
538
539 /* DTBCLK */
540 dpm_clk = &init_table->PPClocks[PPCLK_DTBCLK];
541 num_entries->num_dtbclk_levels = dpm_clk->NumClocks;
542 for (i = 0; i < dpm_clk->NumClocks && i < NUM_CLOCK_LEVELS; i++)
543 clk_table->entries[i].dtbclk_mhz = dpm_clk->Clocks[i];
544
545 /* DISPCLK */
546 dpm_clk = &init_table->PPClocks[PPCLK_DISPCLK];
547 num_entries->num_dispclk_levels = dpm_clk->NumClocks;
548 for (i = 0; i < dpm_clk->NumClocks && i < NUM_CLOCK_LEVELS; i++)
549 clk_table->entries[i].dispclk_mhz = dpm_clk->Clocks[i];
550
551 /* DPPCLK */
552 dpm_clk = &init_table->PPClocks[PPCLK_DPPCLK];
553 num_entries->num_dppclk_levels = dpm_clk->NumClocks;
554 for (i = 0; i < dpm_clk->NumClocks && i < NUM_CLOCK_LEVELS; i++)
555 clk_table->entries[i].dppclk_mhz = dpm_clk->Clocks[i];
556
557 /* UCLK */
558 dpm_clk = &init_table->PPClocks[PPCLK_UCLK];
559 num_entries->num_memclk_levels = dpm_clk->NumClocks;
560 for (i = 0; i < dpm_clk->NumClocks && i < NUM_CLOCK_LEVELS; i++)
561 clk_table->entries[i].memclk_mhz = dpm_clk->Clocks[i];
562 if (num_entries->num_memclk_levels)
563 clk_mgr->base.bw_params->max_memclk_mhz =
564 clk_table->entries[num_entries->num_memclk_levels - 1].memclk_mhz;
565
566 /* FCLK */
567 dpm_clk = &init_table->PPClocks[PPCLK_FCLK];
568 num_entries->num_fclk_levels = dpm_clk->NumClocks;
569 for (i = 0; i < dpm_clk->NumClocks && i < NUM_CLOCK_LEVELS; i++)
570 clk_table->entries[i].fclk_mhz = dpm_clk->Clocks[i];
571
572 if (num_entries->num_memclk_levels >= num_entries->num_fclk_levels)
573 clk_table->num_entries = num_entries->num_memclk_levels;
574 else
575 clk_table->num_entries = num_entries->num_fclk_levels;
576 if (!clk_table->num_entries)
577 clk_table->num_entries = 1;
578 }
579
dcn60_override_bw_params(struct clk_mgr_internal * clk_mgr,struct clk_bw_params * bw_params)580 static void dcn60_override_bw_params(struct clk_mgr_internal *clk_mgr,
581 struct clk_bw_params *bw_params)
582 {
583 struct clk_limit_table *clk_table = &bw_params->clk_table;
584 unsigned int i;
585
586 if (clk_mgr->base.ctx->dc->debug.min_disp_clk_khz) {
587 for (i = 0; i < clk_table->num_entries_per_clk.num_dispclk_levels; i++)
588 if (clk_table->entries[i].dispclk_mhz
589 < (unsigned int)khz_to_mhz_ceil(clk_mgr->base.ctx->dc->debug.min_disp_clk_khz))
590 clk_table->entries[i].dispclk_mhz
591 = (unsigned int)khz_to_mhz_ceil(clk_mgr->base.ctx->dc->debug.min_disp_clk_khz);
592 }
593
594 if (clk_mgr->base.ctx->dc->debug.min_dpp_clk_khz) {
595 for (i = 0; i < clk_table->num_entries_per_clk.num_dppclk_levels; i++)
596 if (clk_table->entries[i].dppclk_mhz
597 < (unsigned int)khz_to_mhz_ceil(clk_mgr->base.ctx->dc->debug.min_dpp_clk_khz))
598 clk_table->entries[i].dppclk_mhz
599 = (unsigned int)khz_to_mhz_ceil(clk_mgr->base.ctx->dc->debug.min_dpp_clk_khz);
600 }
601
602 if (clk_mgr->base.ctx->dc->debug.disable_dtb_ref_clk_switch)
603 bw_params->dc_mode_limit.dtbclk_mhz = 0;
604
605 bw_params->dc_mode_softmax_memclk = bw_params->dc_mode_limit.memclk_mhz;
606 }
607
608 /**
609 * dcn60_fetch_dal_init_table - Transfer and apply the DAL init table from PMFW.
610 * @clk_mgr: clock manager instance
611 *
612 * Issues TABLE_DAL_INIT transfer, populates clock table and bounding box.
613 *
614 * Return: true on success, false if transfer failed
615 */
dcn60_populate_utm_qos_model(struct clk_mgr_internal * clk_mgr,const struct utm_qos_model ** qos_model,const DalInitTable_t * init_table)616 static void dcn60_populate_utm_qos_model(
617 struct clk_mgr_internal *clk_mgr,
618 const struct utm_qos_model **qos_model,
619 const DalInitTable_t *init_table)
620 {
621 struct dcn60_clk_mgr *dcn60_clk_mgr =
622 container_of(clk_mgr, struct dcn60_clk_mgr, base);
623 struct utm_qos_model *model = &dcn60_clk_mgr->utm_qos_model;
624 struct utm_qos_model_dchub_v3 *dchub = &dcn60_clk_mgr->dchub_v3;
625 const SocUtmTable_t *utm_table = &init_table->UtmTable;
626 unsigned int ll, sop;
627
628 memset(dchub, 0, sizeof(*dchub));
629 dchub->load_level_count = (uint8_t)utm_table->Header.LoadLevelCount;
630 dchub->sop_count = (uint8_t)utm_table->Header.SopCount;
631
632 for (ll = 0; ll < dchub->load_level_count
633 && ll < UTM_QOS_MODEL_V3_MAX_LOAD_LEVEL_COUNT; ll++) {
634 for (sop = 0; sop < dchub->sop_count
635 && sop < UTM_QOS_MODEL_V3_MAX_SOP_COUNT; sop++) {
636 const SocUtmSopEntry_t *src = &utm_table->Sops[ll][sop];
637 struct utm_qos_model_dchub_v3_sop_entry *dst =
638 &dchub->sops[ll][sop];
639
640 dst->urgent_ramp_ps = src->UrgentRampPs;
641 dst->t_trip_ps = src->TripPs;
642 dst->meta_trip_to_mem_ps = src->MetaTripToMemPs;
643 dst->max_req_latency_urg_ps = src->MaxReqLatencyUrgPs;
644 dst->avg_req_latency_urg_ps = src->AvgReqLatencyUrgPs;
645 dst->max_req_latency_non_urg_ps = src->MaxReqLatencyNonUrgPs;
646 dst->avg_req_latency_non_urg_ps = src->AvgReqLatencyNonUrgPs;
647 dst->df_response_time_ps = src->DfResponseTimePs;
648 dst->urgent_bandwidth_KBps = src->UrgentBandwidthKBps;
649 dst->nominal_bandwidth_KBps = src->NominalBandwidthKBps;
650 dst->lsdma_bandwidth_KBps = src->LsdmaBandwidthKBps;
651 }
652 }
653
654 model->version = utm_qos_model_version_v3;
655 model->dchub_v3 = dchub;
656 *qos_model = model;
657 }
658
dcn60_fetch_dal_init_table(struct clk_mgr_internal * clk_mgr)659 static bool dcn60_fetch_dal_init_table(struct clk_mgr_internal *clk_mgr)
660 {
661 struct clk_bw_params *bw_params = clk_mgr->base.bw_params;
662 const DalInitTable_t *init_table;
663
664 if (!dcn60_smu_get_dal_init_table(clk_mgr, &init_table))
665 return false;
666
667 clk_mgr->smu_ver = init_table->Header.SmuVersion;
668
669 dcn60_populate_clk_table(clk_mgr, &bw_params->clk_table, init_table);
670 dcn60_populate_dc_mode_limit(&bw_params->dc_mode_limit, init_table);
671
672 bw_params->num_channels = init_table->MemoryConfig.NumUmcChannels;
673 bw_params->dram_channel_width_bytes =
674 clk_mgr->base.ctx->dc_bios->vram_info.dram_channel_width_bytes;
675
676 dcn60_populate_utm_qos_model(clk_mgr, &bw_params->utm_qos_model, init_table);
677
678 dcn60_override_bw_params(clk_mgr, bw_params);
679
680 return true;
681 }
682
dcn60_init_clocks(struct clk_mgr * clk_mgr_base)683 void dcn60_init_clocks(struct clk_mgr *clk_mgr_base)
684 {
685 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
686 uint32_t smu_header_ver = 0;
687
688 memset(&(clk_mgr_base->clks), 0, sizeof(struct dc_clocks));
689 clk_mgr_base->clks.p_state_change_support = true;
690 clk_mgr_base->clks.fclk_p_state_change_support = false;
691 clk_mgr_base->force_smu_not_present = true; // temporary until SMU ready
692 clk_mgr->smu_present = !clk_mgr_base->force_smu_not_present /* not force-disabled */
693 && dcn60_smu_get_msg_header_version(clk_mgr, &smu_header_ver)
694 && smu_header_ver != 0;
695
696 clk_mgr->dpm_present = clk_mgr->smu_present
697 && dcn60_fetch_dal_init_table(clk_mgr)
698 && clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels
699 && clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels
700 && clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dispclk_levels;
701
702 if (clk_mgr->dpm_present)
703 clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
704 clk_mgr_base->ctx->dc, clk_mgr_base->bw_params);
705 }
706
count_to_khz(uint32_t count,uint32_t timer_ths,uint32_t refclk_khz)707 static inline uint32_t count_to_khz(uint32_t count, uint32_t timer_ths, uint32_t refclk_khz)
708 {
709 if (timer_ths == 0)
710 return 0;
711
712 return (uint32_t)div_u64((uint64_t)count * (uint64_t)refclk_khz, timer_ths);
713 }
714
dcn60_dump_clk_registers_internal(struct dcn42_clk_internal * internal,struct clk_mgr * clk_mgr_base)715 static void dcn60_dump_clk_registers_internal(struct dcn42_clk_internal *internal, struct clk_mgr *clk_mgr_base)
716 {
717 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
718
719 // read ths
720 REG_GET(CLK8_CLK_TICK_CNT_CONFIG_REG, TIMER_THRESHOLD, &internal->CLK8_CLK_TICK_CNT__TIMER_THRESHOLD);
721
722 // read dtbclk
723 internal->CLK8_CLK4_CURRENT_CNT = REG_READ(CLK8_CLK4_CURRENT_CNT);
724 internal->CLK8_CLK4_BYPASS_CNTL = REG_READ(CLK8_CLK4_BYPASS_CNTL);
725
726 // read dcfclk
727 internal->CLK8_CLK0_CURRENT_CNT = REG_READ(CLK8_CLK0_CURRENT_CNT);
728 internal->CLK8_CLK0_BYPASS_CNTL = REG_READ(CLK8_CLK0_BYPASS_CNTL);
729
730 // read dcf deep sleep divider
731 internal->CLK8_CLK0_DS_CNTL = REG_READ(CLK8_CLK0_DS_CNTL);
732 internal->CLK8_CLK3_DS_CNTL = REG_READ(CLK8_CLK3_DS_CNTL);
733
734 // read dppclk
735 internal->CLK8_CLK2_CURRENT_CNT = REG_READ(CLK8_CLK2_CURRENT_CNT);
736 internal->CLK8_CLK2_BYPASS_CNTL = REG_READ(CLK8_CLK2_BYPASS_CNTL);
737
738 // read dprefclk
739 internal->CLK8_CLK3_CURRENT_CNT = REG_READ(CLK8_CLK3_CURRENT_CNT);
740 internal->CLK8_CLK3_BYPASS_CNTL = REG_READ(CLK8_CLK3_BYPASS_CNTL);
741
742 // read dispclk
743 internal->CLK8_CLK1_CURRENT_CNT = REG_READ(CLK8_CLK1_CURRENT_CNT);
744 internal->CLK8_CLK1_BYPASS_CNTL = REG_READ(CLK8_CLK1_BYPASS_CNTL);
745 }
746
dcn60_dump_clk_registers(struct clk_state_registers_and_bypass * regs_and_bypass,struct clk_mgr * clk_mgr_base,struct clk_log_info * log_info)747 static void dcn60_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
748 struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
749 {
750 (void)log_info;
751 struct dcn42_clk_internal internal = {0};
752 char *bypass_clks[5] = {"0x0 DFS", "0x1 REFCLK", "0x2 ERROR", "0x3 400 FCH", "0x4 600 FCH"};
753 const uint32_t refclk_khz = DCN60_CLKIP_REFCLK_KHZ;
754 uint32_t timer_ths;
755
756 dcn60_dump_clk_registers_internal(&internal, clk_mgr_base);
757 regs_and_bypass->timer_threshold = internal.CLK8_CLK_TICK_CNT__TIMER_THRESHOLD;
758 timer_ths = internal.CLK8_CLK_TICK_CNT__TIMER_THRESHOLD;
759
760 regs_and_bypass->dcfclk = count_to_khz(internal.CLK8_CLK0_CURRENT_CNT, timer_ths, refclk_khz);
761 regs_and_bypass->dcf_deep_sleep_divider = internal.CLK8_CLK0_DS_CNTL / 10;
762 regs_and_bypass->dcf_deep_sleep_allow = true;
763 regs_and_bypass->dprefclk = count_to_khz(internal.CLK8_CLK3_CURRENT_CNT, timer_ths, refclk_khz);
764 regs_and_bypass->dispclk = count_to_khz(internal.CLK8_CLK1_CURRENT_CNT, timer_ths, refclk_khz);
765 regs_and_bypass->dppclk = count_to_khz(internal.CLK8_CLK2_CURRENT_CNT, timer_ths, refclk_khz);
766 regs_and_bypass->dtbclk = count_to_khz(internal.CLK8_CLK4_CURRENT_CNT, timer_ths, refclk_khz);
767
768 regs_and_bypass->dispclk_bypass = get_reg_field_value(internal.CLK8_CLK0_BYPASS_CNTL, CLK8_CLK0_BYPASS_CNTL, CLK0_BYPASS_SEL);
769 regs_and_bypass->dppclk_bypass = get_reg_field_value(internal.CLK8_CLK1_BYPASS_CNTL, CLK8_CLK1_BYPASS_CNTL, CLK1_BYPASS_SEL);
770 regs_and_bypass->dprefclk_bypass = get_reg_field_value(internal.CLK8_CLK2_BYPASS_CNTL, CLK8_CLK2_BYPASS_CNTL, CLK2_BYPASS_SEL);
771 regs_and_bypass->dcfclk_bypass = get_reg_field_value(internal.CLK8_CLK3_BYPASS_CNTL, CLK8_CLK3_BYPASS_CNTL, CLK3_BYPASS_SEL);
772
773 if (clk_mgr_base->ctx->dc->debug.pstate_enabled) {
774 DC_LOG_SMU("clk_type,clk_value,deepsleep_cntl,deepsleep_allow,bypass\n");
775
776 DC_LOG_SMU("dcfclk,%d,%d,%d,%s\n",
777 regs_and_bypass->dcfclk,
778 regs_and_bypass->dcf_deep_sleep_divider,
779 regs_and_bypass->dcf_deep_sleep_allow,
780 bypass_clks[(int) regs_and_bypass->dcfclk_bypass]);
781
782 DC_LOG_SMU("dprefclk,%d,N/A,N/A,%s\n",
783 regs_and_bypass->dprefclk,
784 bypass_clks[(int) regs_and_bypass->dprefclk_bypass]);
785
786 DC_LOG_SMU("dispclk,%d,N/A,N/A,%s\n",
787 regs_and_bypass->dispclk,
788 bypass_clks[(int) regs_and_bypass->dispclk_bypass]);
789
790 //split
791 DC_LOG_SMU("SPLIT\n");
792
793 // REGISTER VALUES
794 DC_LOG_SMU("reg_name,value,clk_type\n");
795 DC_LOG_SMU("CLK1_CLK3_CURRENT_CNT,%d,dcfclk\n",
796 internal.CLK8_CLK3_CURRENT_CNT);
797
798 DC_LOG_SMU("CLK1_CLK3_DS_CNTL,%d,dcf_deep_sleep_divider\n",
799 internal.CLK8_CLK3_DS_CNTL);
800
801 DC_LOG_SMU("CLK1_CLK3_ALLOW_DS,%d,dcf_deep_sleep_allow\n",
802 (internal.CLK8_CLK3_DS_CNTL & 0x10));
803
804 DC_LOG_SMU("CLK1_CLK2_CURRENT_CNT,%d,dprefclk\n",
805 internal.CLK8_CLK2_CURRENT_CNT);
806
807 DC_LOG_SMU("CLK1_CLK0_CURRENT_CNT,%d,dispclk\n",
808 internal.CLK8_CLK0_CURRENT_CNT);
809
810 DC_LOG_SMU("CLK1_CLK1_CURRENT_CNT,%d,dppclk\n",
811 internal.CLK8_CLK1_CURRENT_CNT);
812
813 DC_LOG_SMU("CLK1_CLK3_BYPASS_CNTL,%d,dcfclk_bypass\n",
814 internal.CLK8_CLK3_BYPASS_CNTL);
815
816 DC_LOG_SMU("CLK1_CLK2_BYPASS_CNTL,%d,dprefclk_bypass\n",
817 internal.CLK8_CLK2_BYPASS_CNTL);
818
819 DC_LOG_SMU("CLK1_CLK0_BYPASS_CNTL,%d,dispclk_bypass\n",
820 internal.CLK8_CLK0_BYPASS_CNTL);
821
822 DC_LOG_SMU("CLK1_CLK1_BYPASS_CNTL,%d,dppclk_bypass\n",
823 internal.CLK8_CLK1_BYPASS_CNTL);
824 }
825 }
826
dcn60_auto_dpm_test_log(struct dc_clocks * new_clocks,struct clk_mgr_internal * clk_mgr,struct dc_state * context)827 static void dcn60_auto_dpm_test_log(
828 struct dc_clocks *new_clocks,
829 struct clk_mgr_internal *clk_mgr,
830 struct dc_state *context)
831 {
832 unsigned int mall_ss_size_bytes;
833 int dramclk_khz_override, fclk_khz_override, num_fclk_levels;
834 struct clk_mgr *clk_mgr_base = &clk_mgr->base;
835
836 struct pipe_ctx *pipe_ctx_list[MAX_PIPES];
837 int active_pipe_count = 0;
838
839 for (int i = 0; i < MAX_PIPES; i++) {
840 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
841
842 if (pipe_ctx->stream && dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) {
843 pipe_ctx_list[active_pipe_count] = pipe_ctx;
844 active_pipe_count++;
845 }
846 }
847
848 msleep(5);
849
850 mall_ss_size_bytes = context->bw_ctx.bw.dcn.mall_ss_size_bytes;
851
852 struct clk_log_info log_info = {0};
853 struct clk_state_registers_and_bypass clk_register_dump;
854
855 dcn60_dump_clk_registers(&clk_register_dump, clk_mgr_base, &log_info);
856
857 // Overrides for these clocks in case there is no p_state change support
858 dramclk_khz_override = new_clocks->dramclk_khz;
859 fclk_khz_override = new_clocks->fclk_khz;
860
861 num_fclk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_fclk_levels - 1;
862
863 if (!new_clocks->p_state_change_support)
864 dramclk_khz_override = clk_mgr->base.bw_params->max_memclk_mhz * 1000;
865
866 if (!new_clocks->fclk_p_state_change_support)
867 fclk_khz_override = clk_mgr->base.bw_params->clk_table.entries[num_fclk_levels].fclk_mhz * 1000;
868
869 ////////////////////////////////////////////////////////////////////////////
870 // IMPORTANT: When adding more clocks to these logs, do NOT put a newline
871 // anywhere other than at the very end of the string.
872 //
873 // Formatting example (make sure to have " - " between each entry):
874 //
875 // AutoDPMTest: clk1:%d - clk2:%d - clk3:%d - clk4:%d\n"
876 ////////////////////////////////////////////////////////////////////////////
877 if (active_pipe_count > 0 &&
878 new_clocks->dramclk_khz > 0 &&
879 new_clocks->fclk_khz > 0 &&
880 new_clocks->dcfclk_khz > 0 &&
881 new_clocks->dppclk_khz > 0) {
882
883 uint32_t pix_clk_list[MAX_PIPES] = {0};
884 int p_state_list[MAX_PIPES] = {0};
885 int disp_src_width_list[MAX_PIPES] = {0};
886 int disp_src_height_list[MAX_PIPES] = {0};
887 uint64_t disp_src_refresh_list[MAX_PIPES] = {0};
888 bool is_scaled_list[MAX_PIPES] = {0};
889
890 for (int i = 0; i < active_pipe_count; i++) {
891 struct pipe_ctx *curr_pipe_ctx = pipe_ctx_list[i];
892 uint64_t refresh_rate;
893
894 pix_clk_list[i] = curr_pipe_ctx->stream->timing.pix_clk_100hz;
895 p_state_list[i] = curr_pipe_ctx->p_state_type;
896
897 refresh_rate = (curr_pipe_ctx->stream->timing.pix_clk_100hz * (uint64_t)100 +
898 curr_pipe_ctx->stream->timing.v_total
899 * (uint64_t) curr_pipe_ctx->stream->timing.h_total - (uint64_t)1);
900 refresh_rate = div_u64(refresh_rate, curr_pipe_ctx->stream->timing.v_total);
901 refresh_rate = div_u64(refresh_rate, curr_pipe_ctx->stream->timing.h_total);
902 disp_src_refresh_list[i] = refresh_rate;
903
904 if (curr_pipe_ctx->plane_state) {
905 is_scaled_list[i] = !(dcn60_check_native_scaling(curr_pipe_ctx));
906 disp_src_width_list[i] = curr_pipe_ctx->plane_state->src_rect.width;
907 disp_src_height_list[i] = curr_pipe_ctx->plane_state->src_rect.height;
908 }
909 }
910
911 DC_LOG_AUTO_DPM_TEST("AutoDPMTest: dramclk:%d - fclk:%d - "
912 "dcfclk:%d - dppclk:%d - dispclk_hw:%d - "
913 "dppclk_hw:%d - dprefclk_hw:%d - dcfclk_hw:%d - "
914 "dtbclk_hw:%d - fclk_hw:%d - pix_clk_0:%d - pix_clk_1:%d - "
915 "pix_clk_2:%d - pix_clk_3:%d - mall_ss_size:%d - p_state_type_0:%d - "
916 "p_state_type_1:%d - p_state_type_2:%d - p_state_type_3:%d - "
917 "pix_width_0:%d - pix_height_0:%d - refresh_rate_0:%lld - is_scaled_0:%d - "
918 "pix_width_1:%d - pix_height_1:%d - refresh_rate_1:%lld - is_scaled_1:%d - "
919 "pix_width_2:%d - pix_height_2:%d - refresh_rate_2:%lld - is_scaled_2:%d - "
920 "pix_width_3:%d - pix_height_3:%d - refresh_rate_3:%lld - is_scaled_3:%d - LOG_END\n",
921 dramclk_khz_override,
922 fclk_khz_override,
923 new_clocks->dcfclk_khz,
924 new_clocks->dppclk_khz,
925 clk_register_dump.dispclk,
926 clk_register_dump.dppclk,
927 clk_register_dump.dprefclk,
928 clk_register_dump.dcfclk,
929 clk_register_dump.dtbclk,
930 clk_register_dump.fclk,
931 pix_clk_list[0], pix_clk_list[1], pix_clk_list[3], pix_clk_list[2],
932 mall_ss_size_bytes,
933 p_state_list[0], p_state_list[1], p_state_list[2], p_state_list[3],
934 disp_src_width_list[0], disp_src_height_list[0], disp_src_refresh_list[0], is_scaled_list[0],
935 disp_src_width_list[1], disp_src_height_list[1], disp_src_refresh_list[1], is_scaled_list[1],
936 disp_src_width_list[2], disp_src_height_list[2], disp_src_refresh_list[2], is_scaled_list[2],
937 disp_src_width_list[3], disp_src_height_list[3], disp_src_refresh_list[3], is_scaled_list[3]);
938 }
939 }
940
dcn60_execute_block_sequence(struct clk_mgr * clk_mgr_base,unsigned int num_steps)941 static void dcn60_execute_block_sequence(struct clk_mgr *clk_mgr_base, unsigned int num_steps)
942 {
943 struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base);
944 struct dcn60_clk_mgr *clk_mgr60 = TO_DCN60_CLK_MGR(clk_mgr_internal);
945
946 unsigned int i;
947 union dcn60_clk_mgr_block_sequence_params *params;
948
949 /* execute sequence */
950 for (i = 0; i < num_steps; i++) {
951 params = &clk_mgr60->block_sequence[i].params;
952
953 switch (clk_mgr60->block_sequence[i].func) {
954 case CLK_MGR60_UPDATE_HARDMIN_PPCLK:
955 if (params->update_hardmin_params.response)
956 *params->update_hardmin_params.response = dcn60_smu_set_hard_min_by_freq(
957 clk_mgr_internal,
958 params->update_hardmin_params.ppclk,
959 params->update_hardmin_params.freq_mhz);
960 else
961 dcn60_smu_set_hard_min_by_freq(clk_mgr_internal,
962 params->update_hardmin_params.ppclk,
963 params->update_hardmin_params.freq_mhz);
964 break;
965 case CLK_MGR60_UPDATE_HARDMIN_PPCLK_OPTIMIZED:
966 if (params->update_hardmin_optimized_params.response)
967 *params->update_hardmin_optimized_params.response =
968 dcn60_set_hard_min_by_freq_optimized(
969 clk_mgr_internal,
970 params->update_hardmin_optimized_params.ppclk,
971 params->update_hardmin_optimized_params.freq_khz);
972 else
973 dcn60_set_hard_min_by_freq_optimized(clk_mgr_internal,
974 params->update_hardmin_optimized_params.ppclk,
975 params->update_hardmin_optimized_params.freq_khz);
976 break;
977 case CLK_MGR60_UPDATE_DEEP_SLEEP_DCFCLK:
978 dcn60_smu_set_min_deep_sleep_dcfclk(
979 clk_mgr_internal,
980 params->update_deep_sleep_dcfclk_params.freq_mhz);
981 break;
982 case CLK_MGR60_INDICATE_PSTATE_STATUS:
983 dcn60_smu_indicate_pstate_status(
984 clk_mgr_internal,
985 params->indicate_pstate_status_params.allow_fclk,
986 params->indicate_pstate_status_params.allow_uclk,
987 params->indicate_pstate_status_params.wait_resp,
988 params->indicate_pstate_status_params.drr_enable,
989 params->indicate_pstate_status_params.alt_ch_enable);
990 break;
991 case CLK_MGR60_UPDATE_DPPCLK_DTO:
992 dcn60_update_clocks_update_dpp_dto(
993 clk_mgr_internal,
994 params->update_dppclk_dto_params.context,
995 params->update_dppclk_dto_params.safe_to_lower,
996 *params->update_dppclk_dto_params.ref_dppclk_khz);
997 break;
998 case CLK_MGR60_UPDATE_DTBCLK_DTO:
999 dcn60_update_clocks_update_dtb_dto(
1000 clk_mgr_internal,
1001 params->update_dtbclk_dto_params.context,
1002 *params->update_dtbclk_dto_params.ref_dtbclk_khz);
1003 break;
1004 case CLK_MGR60_UPDATE_PSR_WAIT_LOOP:
1005 params->update_psr_wait_loop_params.dmcu->funcs->set_psr_wait_loop(
1006 params->update_psr_wait_loop_params.dmcu,
1007 params->update_psr_wait_loop_params.wait);
1008 break;
1009 case CLK_MGR60_UPDATE_STUTTER_EFFICIENCY:
1010 dcn60_smu_set_stutter_efficiency(
1011 clk_mgr_internal,
1012 params->update_stutter_efficiency_params.base_efficiency,
1013 params->update_stutter_efficiency_params.low_power_efficiency);
1014 break;
1015 case CLK_MGR60_UPDATE_UTM_QOS_REQUEST:
1016 dcn60_smu_update_utm_qos_request(clk_mgr_internal,
1017 params->update_utm_qos_request_params.utm_latency_ub_index,
1018 params->update_utm_qos_request_params.utm_nominal_bandwidth_lb_KBps,
1019 params->update_utm_qos_request_params.utm_urgent_bandwidth_lb_KBps,
1020 params->update_utm_qos_request_params.utm_lsdma_bandwidth_lb_KBps);
1021 break;
1022 default:
1023 /* this should never happen */
1024 BREAK_TO_DEBUGGER();
1025 break;
1026 }
1027 }
1028 }
1029
1030 /**
1031 * dcn60_make_bandwidth_clocks_update_action - Determine what clock and p-state
1032 * updates are needed by comparing new_clocks against current clk_mgr state.
1033 * @action: output action struct, zeroed and populated by this function
1034 * @clk_mgr_base: current clock manager state (read-only)
1035 * @context: dc state with active plane information
1036 * @new_clocks: requested clock values to compare against current state
1037 * @safe_to_lower: whether clocks are allowed to decrease
1038 */
dcn60_make_bandwidth_clocks_update_action(struct dcn60_bandwidth_clocks_update_action * action,struct clk_mgr * clk_mgr_base,struct dc_state * context,struct dc_clocks * new_clocks,bool safe_to_lower)1039 static void dcn60_make_bandwidth_clocks_update_action(
1040 struct dcn60_bandwidth_clocks_update_action *action,
1041 struct clk_mgr *clk_mgr_base,
1042 struct dc_state *context,
1043 struct dc_clocks *new_clocks,
1044 bool safe_to_lower)
1045 {
1046 struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base);
1047 int total_plane_count = clk_mgr_helper_get_active_plane_cnt(
1048 clk_mgr_base->ctx->dc, context);
1049 bool dcfclk_dpm_enabled = dcn60_is_ppclk_dpm_enabled(clk_mgr_internal,
1050 PPCLK_DCFCLK);
1051 bool uclk_pstate_supported = new_clocks->p_state_change_support
1052 || (total_plane_count == 0);
1053
1054 bool fclk_pstate_supported = new_clocks->fclk_p_state_change_support
1055 || (total_plane_count == 0);
1056
1057 memset(action, 0, sizeof(*action));
1058 /* clock actions */
1059 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz,
1060 clk_mgr_base->clks.dcfclk_khz)) {
1061 action->dcfclk.update = true;
1062 action->dcfclk.send_message = dcfclk_dpm_enabled;
1063 }
1064
1065 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_deep_sleep_khz,
1066 clk_mgr_base->clks.dcfclk_deep_sleep_khz)) {
1067 action->deep_sleep_dcfclk.update = true;
1068 action->deep_sleep_dcfclk.send_message = dcfclk_dpm_enabled;
1069 }
1070
1071 if (should_set_clock(safe_to_lower, new_clocks->socclk_khz,
1072 clk_mgr_base->clks.socclk_khz)) {
1073 action->socclk.update = true;
1074 /* state tracking only — no SMU hardmin message for socclk */
1075 action->socclk.send_message = false;
1076 }
1077
1078 if (clk_mgr_base->clks.stutter_efficiency.base_efficiency
1079 != new_clocks->stutter_efficiency.base_efficiency
1080 || clk_mgr_base->clks.stutter_efficiency.low_power_efficiency
1081 != new_clocks->stutter_efficiency.low_power_efficiency) {
1082 action->stutter.update = true;
1083 action->stutter.send_message = true;
1084 }
1085
1086 if (new_clocks->utm_nominal_bandwidth_lb_KBps != clk_mgr_base->clks.utm_nominal_bandwidth_lb_KBps
1087 || new_clocks->utm_urgent_bandwidth_lb_KBps != clk_mgr_base->clks.utm_urgent_bandwidth_lb_KBps
1088 || new_clocks->utm_lsdma_bandwidth_lb_KBps != clk_mgr_base->clks.utm_lsdma_bandwidth_lb_KBps
1089 || new_clocks->utm_latency_ub_index != clk_mgr_base->clks.utm_latency_ub_index) {
1090 action->utm_qos.update = true;
1091 action->utm_qos.send_message = true;
1092 }
1093
1094 /* p-state actions */
1095 if (should_update_pstate_support(safe_to_lower,
1096 uclk_pstate_supported,
1097 clk_mgr_base->clks.p_state_change_support)) {
1098 action->uclk_pstate.enable = uclk_pstate_supported;
1099 action->uclk_pstate.disable = !uclk_pstate_supported;
1100 action->uclk_pstate.send_message =
1101 dcn60_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_UCLK);
1102 }
1103
1104 if (should_update_pstate_support(safe_to_lower,
1105 fclk_pstate_supported,
1106 clk_mgr_base->clks.fclk_p_state_change_support)) {
1107 action->fclk_pstate.enable = fclk_pstate_supported;
1108 action->fclk_pstate.disable = !fclk_pstate_supported;
1109 action->fclk_pstate.send_message =
1110 dcn60_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_FCLK);
1111 }
1112
1113 if (new_clocks->fw_based_mclk_switching
1114 != clk_mgr_base->clks.fw_based_mclk_switching) {
1115 action->fams.enable = new_clocks->fw_based_mclk_switching;
1116 action->fams.disable = !new_clocks->fw_based_mclk_switching
1117 && safe_to_lower;
1118 action->fams.send_message = action->fams.enable
1119 || action->fams.disable;
1120 }
1121
1122 if (new_clocks->alt_ch_pstate_switch != clk_mgr_base->clks.alt_ch_pstate_switch) {
1123 action->alt_ch.enable = new_clocks->alt_ch_pstate_switch;
1124 action->alt_ch.disable = !new_clocks->alt_ch_pstate_switch
1125 && safe_to_lower;
1126 action->alt_ch.send_message = action->alt_ch.enable
1127 || action->alt_ch.disable;
1128 }
1129 }
1130
1131 /**
1132 * dcn60_build_bandwidth_clocks_block_sequence_with_action - Build the SMU
1133 * message sequence from the action struct without mutating clk_mgr state.
1134 * @block_sequence: output array of block sequence steps
1135 * @action: action struct populated by dcn60_make_bandwidth_clocks_update_action
1136 * @clk_mgr_base: current clock manager state (read-only, used for original values)
1137 * @new_clocks: requested clock values for message parameters
1138 *
1139 * Return: number of steps written to block_sequence
1140 */
dcn60_build_bandwidth_clocks_block_sequence_with_action(struct dcn60_clk_mgr_block_sequence * block_sequence,struct dcn60_bandwidth_clocks_update_action * action,struct clk_mgr * clk_mgr_base,struct dc_clocks * new_clocks)1141 static unsigned int dcn60_build_bandwidth_clocks_block_sequence_with_action(
1142 struct dcn60_clk_mgr_block_sequence *block_sequence,
1143 struct dcn60_bandwidth_clocks_update_action *action,
1144 struct clk_mgr *clk_mgr_base,
1145 struct dc_clocks *new_clocks)
1146 {
1147 unsigned int num_steps = 0;
1148
1149 /* CLK_MGR60_INDICATE_PSTATE_STATUS — enable */
1150 if ((action->uclk_pstate.enable && action->uclk_pstate.send_message)
1151 || (action->fclk_pstate.enable && action->fclk_pstate.send_message)
1152 || (action->fams.enable && action->fams.send_message)
1153 || (action->alt_ch.enable && action->alt_ch.send_message)) {
1154 block_sequence[num_steps].params.indicate_pstate_status_params.allow_uclk =
1155 action->uclk_pstate.enable
1156 || clk_mgr_base->clks.p_state_change_support;
1157 block_sequence[num_steps].params.indicate_pstate_status_params.allow_fclk =
1158 action->fclk_pstate.enable
1159 || clk_mgr_base->clks.fclk_p_state_change_support;
1160 block_sequence[num_steps].params.indicate_pstate_status_params.drr_enable =
1161 action->fams.enable
1162 || clk_mgr_base->clks.fw_based_mclk_switching;
1163 block_sequence[num_steps].params.indicate_pstate_status_params.wait_resp =
1164 action->fams.enable;
1165 block_sequence[num_steps].params.indicate_pstate_status_params.alt_ch_enable =
1166 action->alt_ch.enable
1167 || clk_mgr_base->clks.alt_ch_pstate_switch;
1168 block_sequence[num_steps].func = CLK_MGR60_INDICATE_PSTATE_STATUS;
1169 num_steps++;
1170 }
1171
1172 /* CLK_MGR60_UPDATE_HARDMIN_PPCLK — DCFCLK */
1173 if (action->dcfclk.send_message) {
1174 block_sequence[num_steps].params.update_hardmin_params.ppclk = PPCLK_DCFCLK;
1175 block_sequence[num_steps].params.update_hardmin_params.freq_mhz =
1176 (uint16_t)khz_to_mhz_ceil(new_clocks->dcfclk_khz);
1177 block_sequence[num_steps].params.update_hardmin_params.response = NULL;
1178 block_sequence[num_steps].func = CLK_MGR60_UPDATE_HARDMIN_PPCLK;
1179 num_steps++;
1180 }
1181
1182 /* CLK_MGR60_UPDATE_DEEP_SLEEP_DCFCLK */
1183 if (action->deep_sleep_dcfclk.send_message) {
1184 block_sequence[num_steps].params.update_deep_sleep_dcfclk_params.freq_mhz =
1185 (uint16_t)khz_to_mhz_ceil(new_clocks->dcfclk_deep_sleep_khz);
1186 block_sequence[num_steps].func = CLK_MGR60_UPDATE_DEEP_SLEEP_DCFCLK;
1187 num_steps++;
1188 }
1189
1190 /* CLK_MGR60_UPDATE_UTM_QOS_REQUEST */
1191 if (action->utm_qos.send_message) {
1192 block_sequence[num_steps].params.update_utm_qos_request_params.utm_nominal_bandwidth_lb_KBps =
1193 new_clocks->utm_nominal_bandwidth_lb_KBps;
1194 block_sequence[num_steps].params.update_utm_qos_request_params.utm_urgent_bandwidth_lb_KBps =
1195 new_clocks->utm_urgent_bandwidth_lb_KBps;
1196 block_sequence[num_steps].params.update_utm_qos_request_params.utm_lsdma_bandwidth_lb_KBps =
1197 new_clocks->utm_lsdma_bandwidth_lb_KBps;
1198 block_sequence[num_steps].params.update_utm_qos_request_params.utm_latency_ub_index =
1199 new_clocks->utm_latency_ub_index;
1200 block_sequence[num_steps].func = CLK_MGR60_UPDATE_UTM_QOS_REQUEST;
1201 num_steps++;
1202 }
1203
1204 /* CLK_MGR60_INDICATE_PSTATE_STATUS — disable */
1205 if ((action->uclk_pstate.disable && action->uclk_pstate.send_message)
1206 || (action->fclk_pstate.disable && action->fclk_pstate.send_message)
1207 || (action->fams.disable && action->fams.send_message)
1208 || (action->alt_ch.disable && action->alt_ch.send_message)) {
1209 block_sequence[num_steps].params.indicate_pstate_status_params.allow_uclk =
1210 !action->uclk_pstate.disable
1211 && (action->uclk_pstate.enable
1212 || clk_mgr_base->clks.p_state_change_support);
1213 block_sequence[num_steps].params.indicate_pstate_status_params.allow_fclk =
1214 !action->fclk_pstate.disable
1215 && (action->fclk_pstate.enable
1216 || clk_mgr_base->clks.fclk_p_state_change_support);
1217 block_sequence[num_steps].params.indicate_pstate_status_params.drr_enable =
1218 !action->fams.disable
1219 && (action->fams.enable
1220 || clk_mgr_base->clks.fw_based_mclk_switching);
1221 block_sequence[num_steps].params.indicate_pstate_status_params.alt_ch_enable =
1222 !action->alt_ch.disable
1223 && (action->alt_ch.enable
1224 || clk_mgr_base->clks.alt_ch_pstate_switch);
1225 block_sequence[num_steps].params.indicate_pstate_status_params.wait_resp = false;
1226 block_sequence[num_steps].func = CLK_MGR60_INDICATE_PSTATE_STATUS;
1227 num_steps++;
1228 }
1229
1230 /* CLK_MGR60_UPDATE_STUTTER_EFFICIENCY */
1231 if (action->stutter.send_message) {
1232 block_sequence[num_steps].params.update_stutter_efficiency_params.base_efficiency =
1233 new_clocks->stutter_efficiency.base_efficiency;
1234 block_sequence[num_steps].params.update_stutter_efficiency_params.low_power_efficiency =
1235 new_clocks->stutter_efficiency.low_power_efficiency;
1236 block_sequence[num_steps].func = CLK_MGR60_UPDATE_STUTTER_EFFICIENCY;
1237 num_steps++;
1238 }
1239
1240 return num_steps;
1241 }
1242
1243 /**
1244 * dcn60_update_bandwidth_clocks_state_with_action - Apply all pending clock
1245 * and p-state changes to clk_mgr state based on the action struct.
1246 * @clk_mgr_base: clock manager state to update
1247 * @action: action struct populated by dcn60_make_bandwidth_clocks_update_action
1248 * @new_clocks: new clock values to copy into clk_mgr state
1249 */
dcn60_update_bandwidth_clocks_state_with_action(struct clk_mgr * clk_mgr_base,struct dcn60_bandwidth_clocks_update_action * action,struct dc_clocks * new_clocks)1250 static void dcn60_update_bandwidth_clocks_state_with_action(
1251 struct clk_mgr *clk_mgr_base,
1252 struct dcn60_bandwidth_clocks_update_action *action,
1253 struct dc_clocks *new_clocks)
1254 {
1255 if (action->uclk_pstate.enable)
1256 clk_mgr_base->clks.p_state_change_support = true;
1257 if (action->uclk_pstate.disable)
1258 clk_mgr_base->clks.p_state_change_support = false;
1259 if (action->fclk_pstate.enable)
1260 clk_mgr_base->clks.fclk_p_state_change_support = true;
1261 if (action->fclk_pstate.disable)
1262 clk_mgr_base->clks.fclk_p_state_change_support = false;
1263 if (action->fams.enable)
1264 clk_mgr_base->clks.fw_based_mclk_switching = true;
1265 if (action->fams.disable)
1266 clk_mgr_base->clks.fw_based_mclk_switching = false;
1267 if (action->alt_ch.enable)
1268 clk_mgr_base->clks.alt_ch_pstate_switch = true;
1269 if (action->alt_ch.disable)
1270 clk_mgr_base->clks.alt_ch_pstate_switch = false;
1271 if (action->dcfclk.update)
1272 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz;
1273 if (action->deep_sleep_dcfclk.update)
1274 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
1275 if (action->socclk.update)
1276 clk_mgr_base->clks.socclk_khz = new_clocks->socclk_khz;
1277 if (action->utm_qos.update) {
1278 clk_mgr_base->clks.utm_nominal_bandwidth_lb_KBps = new_clocks->utm_nominal_bandwidth_lb_KBps;
1279 clk_mgr_base->clks.utm_urgent_bandwidth_lb_KBps = new_clocks->utm_urgent_bandwidth_lb_KBps;
1280 clk_mgr_base->clks.utm_lsdma_bandwidth_lb_KBps = new_clocks->utm_lsdma_bandwidth_lb_KBps;
1281 clk_mgr_base->clks.utm_latency_ub_index = new_clocks->utm_latency_ub_index;
1282 }
1283 if (action->stutter.update) {
1284 clk_mgr_base->clks.stutter_efficiency.base_efficiency =
1285 new_clocks->stutter_efficiency.base_efficiency;
1286 clk_mgr_base->clks.stutter_efficiency.low_power_efficiency =
1287 new_clocks->stutter_efficiency.low_power_efficiency;
1288 }
1289 }
1290
1291 /**
1292 * dcn60_build_update_bandwidth_clocks_sequence - Build block sequence for
1293 * bandwidth clock updates and apply new clock values to clk_mgr state.
1294 * @clk_mgr_base: clock manager to update
1295 * @context: dc state with active plane information
1296 * @new_clocks: requested clock values from bandwidth calculation
1297 * @safe_to_lower: whether clocks are allowed to decrease
1298 *
1299 * Return: number of block sequence steps to execute
1300 */
dcn60_build_update_bandwidth_clocks_sequence(struct clk_mgr * clk_mgr_base,struct dc_state * context,struct dc_clocks * new_clocks,bool safe_to_lower)1301 static unsigned int dcn60_build_update_bandwidth_clocks_sequence(
1302 struct clk_mgr *clk_mgr_base,
1303 struct dc_state *context,
1304 struct dc_clocks *new_clocks,
1305 bool safe_to_lower)
1306 {
1307 struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base);
1308 struct dcn60_clk_mgr *clk_mgr60 = TO_DCN60_CLK_MGR(clk_mgr_internal);
1309 struct dcn60_bandwidth_clocks_update_action action = {0};
1310 unsigned int num_steps;
1311
1312 dcn60_make_bandwidth_clocks_update_action(&action,
1313 clk_mgr_base, context, new_clocks, safe_to_lower);
1314
1315 num_steps = dcn60_build_bandwidth_clocks_block_sequence_with_action(
1316 clk_mgr60->block_sequence, &action,
1317 clk_mgr_base, new_clocks);
1318
1319 dcn60_update_bandwidth_clocks_state_with_action(clk_mgr_base, &action, new_clocks);
1320
1321 return num_steps;
1322 }
1323
dcn60_update_clocks(struct clk_mgr * clk_mgr_base,struct dc_state * context,bool safe_to_lower)1324 static void dcn60_update_clocks(struct clk_mgr *clk_mgr_base,
1325 struct dc_state *context,
1326 bool safe_to_lower)
1327 {
1328 struct dc *dc = clk_mgr_base->ctx->dc;
1329 unsigned int num_steps = 0;
1330
1331 /* TODO: mutates context bw clocks. This is a side effect */
1332 if (dc->debug.force_min_dcfclk_mhz > 0) {
1333 int force_min_dcfclk_khz =
1334 dc->debug.force_min_dcfclk_mhz * 1000;
1335
1336 if (context->bw_ctx.bw.dcn.clk.dcfclk_khz < force_min_dcfclk_khz)
1337 context->bw_ctx.bw.dcn.clk.dcfclk_khz = force_min_dcfclk_khz;
1338 }
1339
1340 /* build bandwidth related clocks update sequence */
1341 num_steps = dcn60_build_update_bandwidth_clocks_sequence(clk_mgr_base,
1342 context,
1343 &context->bw_ctx.bw.dcn.clk,
1344 safe_to_lower);
1345
1346 /* execute sequence */
1347 dcn60_execute_block_sequence(clk_mgr_base, num_steps);
1348
1349 /* build display related clocks update sequence */
1350 num_steps = dcn60_build_update_display_clocks_sequence(clk_mgr_base,
1351 context,
1352 &context->bw_ctx.bw.dcn.clk,
1353 safe_to_lower,
1354 0);
1355
1356 /* execute sequence */
1357 dcn60_execute_block_sequence(clk_mgr_base, num_steps);
1358
1359 if (dc->config.enable_auto_dpm_test_logs)
1360 dcn60_auto_dpm_test_log(&context->bw_ctx.bw.dcn.clk, TO_CLK_MGR_INTERNAL(clk_mgr_base), context);
1361
1362 }
1363
dcn60_clock_read_ss_info(struct clk_mgr_internal * clk_mgr)1364 static void dcn60_clock_read_ss_info(struct clk_mgr_internal *clk_mgr)
1365 {
1366 struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
1367 int ss_info_num = bp->funcs->get_ss_entry_number(
1368 bp, AS_SIGNAL_TYPE_GPU_PLL);
1369
1370 if (ss_info_num) {
1371 struct spread_spectrum_info info = { { 0 } };
1372 enum bp_result result = bp->funcs->get_spread_spectrum_info(
1373 bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
1374
1375 /* SSInfo.spreadSpectrumPercentage !=0 would be sign
1376 * that SS is enabled
1377 */
1378 if (result == BP_RESULT_OK &&
1379 info.spread_spectrum_percentage != 0) {
1380 clk_mgr->ss_on_dprefclk = true;
1381 clk_mgr->dprefclk_ss_divider = info.spread_percentage_divider;
1382
1383 if (info.type.CENTER_MODE == 0) {
1384 /* Currently for DP Reference clock we
1385 * need only SS percentage for
1386 * downspread
1387 */
1388 clk_mgr->dprefclk_ss_percentage =
1389 info.spread_spectrum_percentage;
1390 }
1391 }
1392 }
1393 }
1394
1395 /* Set min memclk to minimum, either constrained by the current mode or DPM0 */
dcn60_set_hard_min_memclk(struct clk_mgr * clk_mgr_base,bool current_mode)1396 static void dcn60_set_hard_min_memclk(struct clk_mgr *clk_mgr_base, bool current_mode)
1397 {
1398 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
1399 const struct dc *dc = clk_mgr->base.ctx->dc;
1400 struct dc_state *context = dc->current_state;
1401 struct dc_clocks new_clocks;
1402 int num_steps;
1403
1404 if (!clk_mgr->smu_present || !dcn60_is_ppclk_dpm_enabled(clk_mgr, PPCLK_UCLK))
1405 return;
1406
1407 /* build clock update */
1408 memcpy(&new_clocks, &clk_mgr_base->clks, sizeof(struct dc_clocks));
1409
1410 if (current_mode) {
1411 new_clocks.dramclk_khz = context->bw_ctx.bw.dcn.clk.dramclk_khz;
1412 new_clocks.idle_dramclk_khz = context->bw_ctx.bw.dcn.clk.idle_dramclk_khz;
1413 new_clocks.p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support;
1414 } else {
1415 new_clocks.dramclk_khz = clk_mgr_base->bw_params->clk_table.entries[0].memclk_mhz * 1000;
1416 new_clocks.idle_dramclk_khz = new_clocks.dramclk_khz;
1417 new_clocks.p_state_change_support = true;
1418 }
1419
1420 num_steps = dcn60_build_update_bandwidth_clocks_sequence(clk_mgr_base,
1421 context,
1422 &new_clocks,
1423 true);
1424
1425 /* execute sequence */
1426 dcn60_execute_block_sequence(clk_mgr_base, num_steps);
1427 }
1428
dcn60_get_memclk_states_from_smu(struct clk_mgr * clk_mgr_base)1429 static void dcn60_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
1430 {
1431 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
1432
1433 if (!clk_mgr->smu_present)
1434 return;
1435
1436 if (!dcn60_fetch_dal_init_table(clk_mgr))
1437 return;
1438
1439 clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
1440 clk_mgr_base->ctx->dc, clk_mgr_base->bw_params);
1441 }
1442
dcn60_enable_pme_wa(struct clk_mgr * clk_mgr_base)1443 static void dcn60_enable_pme_wa(struct clk_mgr *clk_mgr_base)
1444 {
1445 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
1446
1447 if (!clk_mgr->smu_present)
1448 return;
1449
1450 dcn60_smu_set_pme_workaround(clk_mgr);
1451 }
1452
dcn60_get_max_active_utm_bandwidth_kbps(struct clk_mgr * clk_mgr_base)1453 static unsigned int dcn60_get_max_active_utm_bandwidth_kbps(
1454 struct clk_mgr *clk_mgr_base)
1455 {
1456 const struct utm_qos_model *qos_model = clk_mgr_base->bw_params->utm_qos_model;
1457 const struct utm_qos_model_dchub_v3 *dchub;
1458 unsigned int highest;
1459
1460 if (!qos_model
1461 || qos_model->version != utm_qos_model_version_v3
1462 || !qos_model->dchub_v3)
1463 return 0;
1464
1465 dchub = qos_model->dchub_v3;
1466 highest = dchub->sop_count - 1;
1467
1468 return dchub->sops[UTM_QOS_MODEL_V3_LOAD_LEVEL_ACTIVE_ALTERNATE_PSTATE]
1469 [highest].nominal_bandwidth_KBps;
1470 }
1471
dcn60_get_requested_memory_qos(struct clk_mgr * clk_mgr_base,struct dc_requested_memory_qos * qos)1472 static void dcn60_get_requested_memory_qos(
1473 struct clk_mgr *clk_mgr_base,
1474 struct dc_requested_memory_qos *qos)
1475 {
1476 const struct dc_clocks *clks = &clk_mgr_base->clks;
1477
1478 qos->bandwidth_lb_in_mbps = clks->utm_nominal_bandwidth_lb_KBps / 1000;
1479 qos->calculated_avg_bw_in_mbps = clks->required_avg_active_bandwidth_KBps / 1000;
1480 qos->max_latency_ub_in_ns = clks->utm_nominal_max_latency_ub_ns;
1481 qos->avg_latency_ub_in_ns = clks->utm_nominal_avg_latency_ub_ns;
1482 qos->max_bw_budget_in_mbps = dcn60_get_max_active_utm_bandwidth_kbps(clk_mgr_base) / 1000;
1483 }
1484
dcn60_override_memory_bandwidth_request(struct clk_mgr * clk_mgr_base,unsigned int bw_kbps)1485 static unsigned int dcn60_override_memory_bandwidth_request(
1486 struct clk_mgr *clk_mgr_base,
1487 unsigned int bw_kbps)
1488 {
1489 const struct dc *dc = clk_mgr_base->ctx->dc;
1490 struct dc_clocks new_clocks;
1491 unsigned int max_bw_kbps;
1492 unsigned int capped_bw_kbps;
1493 int num_steps;
1494
1495 memcpy(&new_clocks, &clk_mgr_base->clks, sizeof(struct dc_clocks));
1496
1497 if (bw_kbps == 0) {
1498 new_clocks.utm_nominal_bandwidth_lb_KBps = 0;
1499 new_clocks.utm_urgent_bandwidth_lb_KBps = 0;
1500 } else {
1501 max_bw_kbps = dcn60_get_max_active_utm_bandwidth_kbps(clk_mgr_base);
1502 capped_bw_kbps = (bw_kbps > max_bw_kbps) ? max_bw_kbps : bw_kbps;
1503
1504 new_clocks.utm_nominal_bandwidth_lb_KBps = capped_bw_kbps;
1505 if (new_clocks.utm_urgent_bandwidth_lb_KBps < capped_bw_kbps)
1506 new_clocks.utm_urgent_bandwidth_lb_KBps = capped_bw_kbps;
1507 }
1508
1509 num_steps = dcn60_build_update_bandwidth_clocks_sequence(clk_mgr_base,
1510 dc->current_state, &new_clocks, true);
1511
1512 dcn60_execute_block_sequence(clk_mgr_base, num_steps);
1513
1514 return new_clocks.utm_nominal_bandwidth_lb_KBps;
1515 }
1516
dcn60_set_idle_power_optimizations(struct clk_mgr * clk_mgr_base,bool enable)1517 static void dcn60_set_idle_power_optimizations(struct clk_mgr *clk_mgr_base, bool enable)
1518 {
1519 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
1520
1521 if (!clk_mgr->smu_present)
1522 return;
1523
1524 dcn60_smu_set_display_idle_optimization(clk_mgr, enable);
1525 }
1526
1527 /*
1528 * Build-for-BLS functions.
1529 * These build both bandwidth and display clock sequences into the clk_mgr's
1530 * internal block sequence array, then add a single CLK_MGR_UPDATE_CLOCKS step
1531 * to the HWSS block sequence whose executor will call
1532 * execute_clk_mgr_block_sequence to dispatch all accumulated steps.
1533 */
dcn60_build_clock_update_for_bls(struct clk_mgr * clk_mgr_base,struct dc_state * context,bool safe_to_lower,struct block_sequence_state * seq_state)1534 void dcn60_build_clock_update_for_bls(
1535 struct clk_mgr *clk_mgr_base,
1536 struct dc_state *context,
1537 bool safe_to_lower,
1538 struct block_sequence_state *seq_state)
1539 {
1540 struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base);
1541 struct dcn60_clk_mgr *clk_mgr60 = TO_DCN60_CLK_MGR(clk_mgr_internal);
1542 unsigned int num_bw_steps;
1543 unsigned int total_steps;
1544
1545 /* Build bandwidth clocks sequence starting at index 0 */
1546 num_bw_steps = dcn60_build_update_bandwidth_clocks_sequence(clk_mgr_base,
1547 context,
1548 &context->bw_ctx.bw.dcn.clk,
1549 safe_to_lower);
1550
1551 /* Build display clocks sequence appended after bandwidth steps */
1552 total_steps = dcn60_build_update_display_clocks_sequence(clk_mgr_base,
1553 context,
1554 &context->bw_ctx.bw.dcn.clk,
1555 safe_to_lower,
1556 num_bw_steps);
1557
1558 /* Store total step count for the executor */
1559 clk_mgr60->num_block_sequence_steps = total_steps;
1560
1561 /* Add single HWSS step that will execute all clk_mgr block sequence steps */
1562 hwss_add_clk_mgr_update_clocks(seq_state, clk_mgr_base);
1563 }
1564
dcn60_execute_clk_mgr_block_sequence_bls(struct clk_mgr * clk_mgr_base)1565 static void dcn60_execute_clk_mgr_block_sequence_bls(struct clk_mgr *clk_mgr_base)
1566 {
1567 struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base);
1568 struct dcn60_clk_mgr *clk_mgr60 = TO_DCN60_CLK_MGR(clk_mgr_internal);
1569
1570 dcn60_execute_block_sequence(clk_mgr_base, clk_mgr60->num_block_sequence_steps);
1571 }
1572
1573 static struct clk_mgr_funcs dcn60_funcs = {
1574 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
1575 .get_dtb_ref_clk_frequency = dcn60_get_dtb_ref_freq_khz,
1576 .update_clocks = dcn60_update_clocks,
1577 .dump_clk_registers = dcn60_dump_clk_registers,
1578 .init_clocks = dcn60_init_clocks,
1579 .set_hard_min_memclk = dcn60_set_hard_min_memclk,
1580 .get_memclk_states_from_smu = dcn60_get_memclk_states_from_smu,
1581 .are_clock_states_equal = dcn60_are_clock_states_equal,
1582 .enable_pme_wa = dcn60_enable_pme_wa,
1583 .is_smu_present = dcn60_is_smu_present,
1584 .get_dispclk_from_dentist = NULL,
1585 .get_max_clock_khz = dcn401_get_max_clock_khz,
1586 .override_memory_bandwidth_request = dcn60_override_memory_bandwidth_request,
1587 .get_requested_memory_qos = dcn60_get_requested_memory_qos,
1588 .set_idle_power_optimizations = dcn60_set_idle_power_optimizations,
1589 .build_clock_update_for_bls = dcn60_build_clock_update_for_bls,
1590 .execute_clk_mgr_block_sequence = dcn60_execute_clk_mgr_block_sequence_bls,
1591 };
1592
dcn60_clk_mgr_construct(struct dc_context * ctx,struct dccg * dccg)1593 struct clk_mgr_internal *dcn60_clk_mgr_construct(
1594 struct dc_context *ctx,
1595 struct dccg *dccg)
1596 {
1597 struct clk_log_info log_info = {0};
1598 struct dcn60_clk_mgr *clk_mgr60 = kzalloc_obj(struct dcn60_clk_mgr);
1599 struct clk_mgr_internal *clk_mgr;
1600
1601 if (!clk_mgr60)
1602 return NULL;
1603
1604 clk_mgr = &clk_mgr60->base;
1605 clk_mgr->base.ctx = ctx;
1606 clk_mgr->base.funcs = &dcn60_funcs;
1607 clk_mgr->regs = &clk_mgr_regs_dcn60;
1608 clk_mgr->clk_mgr_shift = &clk_mgr_shift_dcn60;
1609 clk_mgr->clk_mgr_mask = &clk_mgr_mask_dcn60;
1610
1611 clk_mgr->dccg = dccg;
1612 clk_mgr->dfs_bypass_disp_clk = 0;
1613
1614 clk_mgr->dprefclk_ss_percentage = 0;
1615 clk_mgr->dprefclk_ss_divider = 1000;
1616 clk_mgr->ss_on_dprefclk = false;
1617 clk_mgr->dfs_ref_freq_khz = 100000;
1618
1619 /* Changed from DCN3.2_clock_frequency doc to match
1620 * dcn60_dump_clk_registers from 4 * dentist_vco_freq_khz /
1621 * dprefclk DID divider
1622 */
1623 clk_mgr->base.dprefclk_khz = 720000;
1624
1625 /* integer part is now VCO frequency in kHz */
1626 clk_mgr->base.dentist_vco_freq_khz = dcn60_get_vco_frequency_from_reg(clk_mgr);
1627
1628 /* in case we don't get a value from the register, use default */
1629 if (clk_mgr->base.dentist_vco_freq_khz == 0)
1630 clk_mgr->base.dentist_vco_freq_khz = 4500000;
1631
1632 dcn60_dump_clk_registers(&clk_mgr->base.boot_snapshot, &clk_mgr->base, &log_info);
1633
1634 if (ctx->dc->debug.disable_dtb_ref_clk_switch &&
1635 clk_mgr->base.clks.ref_dtbclk_khz != clk_mgr->base.boot_snapshot.dtbclk) {
1636 clk_mgr->base.clks.ref_dtbclk_khz = clk_mgr->base.boot_snapshot.dtbclk;
1637 }
1638
1639 if (clk_mgr->base.boot_snapshot.dprefclk != 0)
1640 clk_mgr->base.dprefclk_khz = clk_mgr->base.boot_snapshot.dprefclk;
1641 dcn60_clock_read_ss_info(clk_mgr);
1642
1643 clk_mgr->dfs_bypass_enabled = false;
1644
1645 clk_mgr->smu_present = false;
1646
1647 clk_mgr->base.bw_params = kzalloc_obj(*clk_mgr->base.bw_params);
1648 if (!clk_mgr->base.bw_params)
1649 goto fail;
1650
1651 clk_mgr->dal_init_table = dm_helpers_allocate_gpu_mem(clk_mgr->base.ctx,
1652 DC_MEM_ALLOC_TYPE_GART, sizeof(DalInitTable_t),
1653 &clk_mgr->dal_init_table_addr);
1654 if (!clk_mgr->dal_init_table)
1655 goto fail;
1656
1657 return &clk_mgr60->base;
1658
1659 fail:
1660 BREAK_TO_DEBUGGER();
1661 dcn60_clk_mgr_destroy(clk_mgr);
1662 kfree(clk_mgr60);
1663 return NULL;
1664 }
1665
dcn60_clk_mgr_destroy(struct clk_mgr_internal * clk_mgr)1666 void dcn60_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr)
1667 {
1668 kfree(clk_mgr->base.bw_params);
1669
1670 if (clk_mgr->dal_init_table)
1671 dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART,
1672 (void *)clk_mgr->dal_init_table);
1673 }
1674