7326b756584610b9c7d54f35925bb0ece88102b9
[linux-2.6-block.git] / drivers / gpu / drm / amd / display / dc / clk_mgr / dcn314 / dcn314_clk_mgr.c
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 "dcn314_clk_mgr.h"
30
31 #include "dccg.h"
32 #include "clk_mgr_internal.h"
33
34 // For dce12_get_dp_ref_freq_khz
35 #include "dce100/dce_clk_mgr.h"
36
37 // For dcn20_update_clocks_update_dpp_dto
38 #include "dcn20/dcn20_clk_mgr.h"
39
40
41
42 #include "reg_helper.h"
43 #include "core_types.h"
44 #include "dm_helpers.h"
45
46 /* TODO: remove this include once we ported over remaining clk mgr functions*/
47 #include "dcn30/dcn30_clk_mgr.h"
48 #include "dcn31/dcn31_clk_mgr.h"
49
50 #include "dc_dmub_srv.h"
51 #include "link.h"
52 #include "dcn314_smu.h"
53
54
55 #include "logger_types.h"
56 #undef DC_LOGGER
57 #define DC_LOGGER \
58         clk_mgr->base.base.ctx->logger
59
60
61 #define MAX_INSTANCE                                        7
62 #define MAX_SEGMENT                                         8
63
64 struct IP_BASE_INSTANCE {
65         unsigned int segment[MAX_SEGMENT];
66 };
67
68 struct IP_BASE {
69         struct IP_BASE_INSTANCE instance[MAX_INSTANCE];
70 };
71
72 static const struct IP_BASE CLK_BASE = { { { { 0x00016C00, 0x02401800, 0, 0, 0, 0, 0, 0 } },
73                                         { { 0x00016E00, 0x02401C00, 0, 0, 0, 0, 0, 0 } },
74                                         { { 0x00017000, 0x02402000, 0, 0, 0, 0, 0, 0 } },
75                                         { { 0x00017200, 0x02402400, 0, 0, 0, 0, 0, 0 } },
76                                         { { 0x0001B000, 0x0242D800, 0, 0, 0, 0, 0, 0 } },
77                                         { { 0x0001B200, 0x0242DC00, 0, 0, 0, 0, 0, 0 } },
78                                         { { 0x0001B400, 0x0242E000, 0, 0, 0, 0, 0, 0 } } } };
79
80 #define regCLK1_CLK_PLL_REQ                     0x0237
81 #define regCLK1_CLK_PLL_REQ_BASE_IDX            0
82
83 #define CLK1_CLK_PLL_REQ__FbMult_int__SHIFT     0x0
84 #define CLK1_CLK_PLL_REQ__PllSpineDiv__SHIFT    0xc
85 #define CLK1_CLK_PLL_REQ__FbMult_frac__SHIFT    0x10
86 #define CLK1_CLK_PLL_REQ__FbMult_int_MASK       0x000001FFL
87 #define CLK1_CLK_PLL_REQ__PllSpineDiv_MASK      0x0000F000L
88 #define CLK1_CLK_PLL_REQ__FbMult_frac_MASK      0xFFFF0000L
89
90 #define REG(reg_name) \
91         (CLK_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
92
93 #define TO_CLK_MGR_DCN314(clk_mgr)\
94         container_of(clk_mgr, struct clk_mgr_dcn314, base)
95
96 static int dcn314_get_active_display_cnt_wa(
97                 struct dc *dc,
98                 struct dc_state *context)
99 {
100         int i, display_count;
101         bool tmds_present = false;
102
103         display_count = 0;
104         for (i = 0; i < context->stream_count; i++) {
105                 const struct dc_stream_state *stream = context->streams[i];
106
107                 if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
108                                 stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
109                                 stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK)
110                         tmds_present = true;
111
112                 /* Checking stream / link detection ensuring that PHY is active*/
113                 if (dc_is_dp_signal(stream->signal) && !stream->dpms_off)
114                         display_count++;
115
116         }
117
118         for (i = 0; i < dc->link_count; i++) {
119                 const struct dc_link *link = dc->links[i];
120
121                 /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */
122                 if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
123                                 link->link_enc->funcs->is_dig_enabled(link->link_enc))
124                         display_count++;
125         }
126
127         /* WA for hang on HDMI after display off back on*/
128         if (display_count == 0 && tmds_present)
129                 display_count = 1;
130
131         return display_count;
132 }
133
134 static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable)
135 {
136         struct dc *dc = clk_mgr_base->ctx->dc;
137         int i;
138
139         for (i = 0; i < dc->res_pool->pipe_count; ++i) {
140                 struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
141
142                 if (pipe->top_pipe || pipe->prev_odm_pipe)
143                         continue;
144                 if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) {
145                         struct stream_encoder *stream_enc = pipe->stream_res.stream_enc;
146
147                         if (disable) {
148                                 if (stream_enc && stream_enc->funcs->disable_fifo)
149                                         pipe->stream_res.stream_enc->funcs->disable_fifo(stream_enc);
150
151                                 pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
152                                 reset_sync_context_for_pipe(dc, context, i);
153                         } else {
154                                 pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
155
156                                 if (stream_enc && stream_enc->funcs->enable_fifo)
157                                         pipe->stream_res.stream_enc->funcs->enable_fifo(stream_enc);
158                         }
159                 }
160         }
161 }
162
163 void dcn314_update_clocks(struct clk_mgr *clk_mgr_base,
164                         struct dc_state *context,
165                         bool safe_to_lower)
166 {
167         union dmub_rb_cmd cmd;
168         struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
169         struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
170         struct dc *dc = clk_mgr_base->ctx->dc;
171         int display_count;
172         bool update_dppclk = false;
173         bool update_dispclk = false;
174         bool dpp_clock_lowered = false;
175
176         if (dc->work_arounds.skip_clock_update)
177                 return;
178
179         /*
180          * if it is safe to lower, but we are already in the lower state, we don't have to do anything
181          * also if safe to lower is false, we just go in the higher state
182          */
183         if (safe_to_lower) {
184                 if (new_clocks->zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW &&
185                                 new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
186                         dcn314_smu_set_zstate_support(clk_mgr, new_clocks->zstate_support);
187                         dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, true);
188                         clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
189                 }
190
191                 if (clk_mgr_base->clks.dtbclk_en && !new_clocks->dtbclk_en) {
192                         dcn314_smu_set_dtbclk(clk_mgr, false);
193                         clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en;
194                 }
195                 /* check that we're not already in lower */
196                 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
197                         display_count = dcn314_get_active_display_cnt_wa(dc, context);
198                         /* if we can go lower, go lower */
199                         if (display_count == 0) {
200                                 union display_idle_optimization_u idle_info = { 0 };
201                                 idle_info.idle_info.df_request_disabled = 1;
202                                 idle_info.idle_info.phy_ref_clk_off = 1;
203                                 idle_info.idle_info.s0i2_rdy = 1;
204                                 dcn314_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
205                                 /* update power state */
206                                 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
207                         }
208                 }
209         } else {
210                 if (new_clocks->zstate_support == DCN_ZSTATE_SUPPORT_DISALLOW &&
211                                 new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
212                         dcn314_smu_set_zstate_support(clk_mgr, DCN_ZSTATE_SUPPORT_DISALLOW);
213                         dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, false);
214                         clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
215                 }
216
217                 if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) {
218                         dcn314_smu_set_dtbclk(clk_mgr, true);
219                         clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en;
220                 }
221
222                 /* check that we're not already in D0 */
223                 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) {
224                         union display_idle_optimization_u idle_info = { 0 };
225
226                         dcn314_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
227                         /* update power state */
228                         clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE;
229                 }
230         }
231
232         if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) {
233                 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz;
234                 dcn314_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz);
235         }
236
237         if (should_set_clock(safe_to_lower,
238                         new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) {
239                 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
240                 dcn314_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz);
241         }
242
243         // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow.
244         if (new_clocks->dppclk_khz < 100000)
245                 new_clocks->dppclk_khz = 100000;
246
247         if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
248                 if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
249                         dpp_clock_lowered = true;
250                 clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
251                 update_dppclk = true;
252         }
253
254         if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
255                 dcn314_disable_otg_wa(clk_mgr_base, context, true);
256
257                 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
258                 dcn314_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
259                 dcn314_disable_otg_wa(clk_mgr_base, context, false);
260
261                 update_dispclk = true;
262         }
263
264         if (dpp_clock_lowered) {
265                 // increase per DPP DTO before lowering global dppclk
266                 dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
267                 dcn314_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
268         } else {
269                 // increase global DPPCLK before lowering per DPP DTO
270                 if (update_dppclk || update_dispclk)
271                         dcn314_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
272                 // always update dtos unless clock is lowered and not safe to lower
273                 if (new_clocks->dppclk_khz >= dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz)
274                         dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
275         }
276
277         // notify DMCUB of latest clocks
278         memset(&cmd, 0, sizeof(cmd));
279         cmd.notify_clocks.header.type = DMUB_CMD__CLK_MGR;
280         cmd.notify_clocks.header.sub_type = DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS;
281         cmd.notify_clocks.clocks.dcfclk_khz = clk_mgr_base->clks.dcfclk_khz;
282         cmd.notify_clocks.clocks.dcfclk_deep_sleep_khz =
283                 clk_mgr_base->clks.dcfclk_deep_sleep_khz;
284         cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz;
285         cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz;
286
287         dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
288 }
289
290 static int get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr)
291 {
292         /* get FbMult value */
293         struct fixed31_32 pll_req;
294         unsigned int fbmult_frac_val = 0;
295         unsigned int fbmult_int_val = 0;
296
297         /*
298          * Register value of fbmult is in 8.16 format, we are converting to 314.32
299          * to leverage the fix point operations available in driver
300          */
301
302         REG_GET(CLK1_CLK_PLL_REQ, FbMult_frac, &fbmult_frac_val); /* 16 bit fractional part*/
303         REG_GET(CLK1_CLK_PLL_REQ, FbMult_int, &fbmult_int_val); /* 8 bit integer part */
304
305         pll_req = dc_fixpt_from_int(fbmult_int_val);
306
307         /*
308          * since fractional part is only 16 bit in register definition but is 32 bit
309          * in our fix point definiton, need to shift left by 16 to obtain correct value
310          */
311         pll_req.value |= fbmult_frac_val << 16;
312
313         /* multiply by REFCLK period */
314         pll_req = dc_fixpt_mul_int(pll_req, clk_mgr->dfs_ref_freq_khz);
315
316         /* integer part is now VCO frequency in kHz */
317         return dc_fixpt_floor(pll_req);
318 }
319
320 static void dcn314_enable_pme_wa(struct clk_mgr *clk_mgr_base)
321 {
322         struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
323
324         dcn314_smu_enable_pme_wa(clk_mgr);
325 }
326
327 bool dcn314_are_clock_states_equal(struct dc_clocks *a,
328                 struct dc_clocks *b)
329 {
330         if (a->dispclk_khz != b->dispclk_khz)
331                 return false;
332         else if (a->dppclk_khz != b->dppclk_khz)
333                 return false;
334         else if (a->dcfclk_khz != b->dcfclk_khz)
335                 return false;
336         else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz)
337                 return false;
338         else if (a->zstate_support != b->zstate_support)
339                 return false;
340         else if (a->dtbclk_en != b->dtbclk_en)
341                 return false;
342
343         return true;
344 }
345
346 static void dcn314_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
347                 struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
348 {
349         return;
350 }
351
352 static struct clk_bw_params dcn314_bw_params = {
353         .vram_type = Ddr4MemType,
354         .num_channels = 1,
355         .clk_table = {
356                 .num_entries = 4,
357         },
358
359 };
360
361 static struct wm_table ddr5_wm_table = {
362         .entries = {
363                 {
364                         .wm_inst = WM_A,
365                         .wm_type = WM_TYPE_PSTATE_CHG,
366                         .pstate_latency_us = 11.72,
367                         .sr_exit_time_us = 12.5,
368                         .sr_enter_plus_exit_time_us = 14.5,
369                         .valid = true,
370                 },
371                 {
372                         .wm_inst = WM_B,
373                         .wm_type = WM_TYPE_PSTATE_CHG,
374                         .pstate_latency_us = 11.72,
375                         .sr_exit_time_us = 12.5,
376                         .sr_enter_plus_exit_time_us = 14.5,
377                         .valid = true,
378                 },
379                 {
380                         .wm_inst = WM_C,
381                         .wm_type = WM_TYPE_PSTATE_CHG,
382                         .pstate_latency_us = 11.72,
383                         .sr_exit_time_us = 12.5,
384                         .sr_enter_plus_exit_time_us = 14.5,
385                         .valid = true,
386                 },
387                 {
388                         .wm_inst = WM_D,
389                         .wm_type = WM_TYPE_PSTATE_CHG,
390                         .pstate_latency_us = 11.72,
391                         .sr_exit_time_us = 12.5,
392                         .sr_enter_plus_exit_time_us = 14.5,
393                         .valid = true,
394                 },
395         }
396 };
397
398 static struct wm_table lpddr5_wm_table = {
399         .entries = {
400                 {
401                         .wm_inst = WM_A,
402                         .wm_type = WM_TYPE_PSTATE_CHG,
403                         .pstate_latency_us = 11.65333,
404                         .sr_exit_time_us = 30.0,
405                         .sr_enter_plus_exit_time_us = 32.0,
406                         .valid = true,
407                 },
408                 {
409                         .wm_inst = WM_B,
410                         .wm_type = WM_TYPE_PSTATE_CHG,
411                         .pstate_latency_us = 11.65333,
412                         .sr_exit_time_us = 30.0,
413                         .sr_enter_plus_exit_time_us = 32.0,
414                         .valid = true,
415                 },
416                 {
417                         .wm_inst = WM_C,
418                         .wm_type = WM_TYPE_PSTATE_CHG,
419                         .pstate_latency_us = 11.65333,
420                         .sr_exit_time_us = 30.0,
421                         .sr_enter_plus_exit_time_us = 32.0,
422                         .valid = true,
423                 },
424                 {
425                         .wm_inst = WM_D,
426                         .wm_type = WM_TYPE_PSTATE_CHG,
427                         .pstate_latency_us = 11.65333,
428                         .sr_exit_time_us = 30.0,
429                         .sr_enter_plus_exit_time_us = 32.0,
430                         .valid = true,
431                 },
432         }
433 };
434
435 static DpmClocks314_t dummy_clocks;
436
437 static struct dcn314_watermarks dummy_wms = { 0 };
438
439 static void dcn314_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn314_watermarks *table)
440 {
441         int i, num_valid_sets;
442
443         num_valid_sets = 0;
444
445         for (i = 0; i < WM_SET_COUNT; i++) {
446                 /* skip empty entries, the smu array has no holes*/
447                 if (!bw_params->wm_table.entries[i].valid)
448                         continue;
449
450                 table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmSetting = bw_params->wm_table.entries[i].wm_inst;
451                 table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType = bw_params->wm_table.entries[i].wm_type;
452                 /* We will not select WM based on fclk, so leave it as unconstrained */
453                 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
454                 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
455
456                 if (table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType == WM_TYPE_PSTATE_CHG) {
457                         if (i == 0)
458                                 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 0;
459                         else {
460                                 /* add 1 to make it non-overlapping with next lvl */
461                                 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk =
462                                                 bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1;
463                         }
464                         table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxMclk =
465                                         bw_params->clk_table.entries[i].dcfclk_mhz;
466
467                 } else {
468                         /* unconstrained for memory retraining */
469                         table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
470                         table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
471
472                         /* Modify previous watermark range to cover up to max */
473                         table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
474                 }
475                 num_valid_sets++;
476         }
477
478         ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */
479
480         /* modify the min and max to make sure we cover the whole range*/
481         table->WatermarkRow[WM_DCFCLK][0].MinMclk = 0;
482         table->WatermarkRow[WM_DCFCLK][0].MinClock = 0;
483         table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxMclk = 0xFFFF;
484         table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
485
486         /* This is for writeback only, does not matter currently as no writeback support*/
487         table->WatermarkRow[WM_SOCCLK][0].WmSetting = WM_A;
488         table->WatermarkRow[WM_SOCCLK][0].MinClock = 0;
489         table->WatermarkRow[WM_SOCCLK][0].MaxClock = 0xFFFF;
490         table->WatermarkRow[WM_SOCCLK][0].MinMclk = 0;
491         table->WatermarkRow[WM_SOCCLK][0].MaxMclk = 0xFFFF;
492 }
493
494 static void dcn314_notify_wm_ranges(struct clk_mgr *clk_mgr_base)
495 {
496         struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
497         struct clk_mgr_dcn314 *clk_mgr_dcn314 = TO_CLK_MGR_DCN314(clk_mgr);
498         struct dcn314_watermarks *table = clk_mgr_dcn314->smu_wm_set.wm_set;
499
500         if (!clk_mgr->smu_ver)
501                 return;
502
503         if (!table || clk_mgr_dcn314->smu_wm_set.mc_address.quad_part == 0)
504                 return;
505
506         memset(table, 0, sizeof(*table));
507
508         dcn314_build_watermark_ranges(clk_mgr_base->bw_params, table);
509
510         dcn314_smu_set_dram_addr_high(clk_mgr,
511                         clk_mgr_dcn314->smu_wm_set.mc_address.high_part);
512         dcn314_smu_set_dram_addr_low(clk_mgr,
513                         clk_mgr_dcn314->smu_wm_set.mc_address.low_part);
514         dcn314_smu_transfer_wm_table_dram_2_smu(clk_mgr);
515 }
516
517 static void dcn314_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
518                 struct dcn314_smu_dpm_clks *smu_dpm_clks)
519 {
520         DpmClocks314_t *table = smu_dpm_clks->dpm_clks;
521
522         if (!clk_mgr->smu_ver)
523                 return;
524
525         if (!table || smu_dpm_clks->mc_address.quad_part == 0)
526                 return;
527
528         memset(table, 0, sizeof(*table));
529
530         dcn314_smu_set_dram_addr_high(clk_mgr,
531                         smu_dpm_clks->mc_address.high_part);
532         dcn314_smu_set_dram_addr_low(clk_mgr,
533                         smu_dpm_clks->mc_address.low_part);
534         dcn314_smu_transfer_dpm_table_smu_2_dram(clk_mgr);
535 }
536
537 static inline bool is_valid_clock_value(uint32_t clock_value)
538 {
539         return clock_value > 1 && clock_value < 100000;
540 }
541
542 static unsigned int convert_wck_ratio(uint8_t wck_ratio)
543 {
544         switch (wck_ratio) {
545         case WCK_RATIO_1_2:
546                 return 2;
547
548         case WCK_RATIO_1_4:
549                 return 4;
550
551         default:
552                 break;
553         }
554         return 1;
555 }
556
557 static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks)
558 {
559         uint32_t max = 0;
560         int i;
561
562         for (i = 0; i < num_clocks; ++i) {
563                 if (clocks[i] > max)
564                         max = clocks[i];
565         }
566
567         return max;
568 }
569
570 static void dcn314_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk_mgr,
571                                                     struct integrated_info *bios_info,
572                                                     const DpmClocks314_t *clock_table)
573 {
574         struct clk_bw_params *bw_params = clk_mgr->base.bw_params;
575         struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1];
576         uint32_t max_pstate = 0,  max_fclk = 0,  min_pstate = 0, max_dispclk = 0, max_dppclk = 0;
577         int i;
578
579         /* Find highest valid fclk pstate */
580         for (i = 0; i < clock_table->NumDfPstatesEnabled; i++) {
581                 if (is_valid_clock_value(clock_table->DfPstateTable[i].FClk) &&
582                     clock_table->DfPstateTable[i].FClk > max_fclk) {
583                         max_fclk = clock_table->DfPstateTable[i].FClk;
584                         max_pstate = i;
585                 }
586         }
587
588         /* We expect the table to contain at least one valid fclk entry. */
589         ASSERT(is_valid_clock_value(max_fclk));
590
591         /* Dispclk and dppclk can be max at any voltage, same number of levels for both */
592         if (clock_table->NumDispClkLevelsEnabled <= NUM_DISPCLK_DPM_LEVELS &&
593             clock_table->NumDispClkLevelsEnabled <= NUM_DPPCLK_DPM_LEVELS) {
594                 max_dispclk = find_max_clk_value(clock_table->DispClocks, clock_table->NumDispClkLevelsEnabled);
595                 max_dppclk = find_max_clk_value(clock_table->DppClocks, clock_table->NumDispClkLevelsEnabled);
596         } else {
597                 /* Invalid number of entries in the table from PMFW. */
598                 ASSERT(0);
599         }
600
601         /* Base the clock table on dcfclk, need at least one entry regardless of pmfw table */
602         for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) {
603                 uint32_t min_fclk = clock_table->DfPstateTable[0].FClk;
604                 int j;
605
606                 for (j = 1; j < clock_table->NumDfPstatesEnabled; j++) {
607                         if (is_valid_clock_value(clock_table->DfPstateTable[j].FClk) &&
608                             clock_table->DfPstateTable[j].FClk < min_fclk &&
609                             clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i]) {
610                                 min_fclk = clock_table->DfPstateTable[j].FClk;
611                                 min_pstate = j;
612                         }
613                 }
614
615                 /* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */
616                 for (j = bw_params->clk_table.num_entries - 1; j > 0; j--)
617                         if (bw_params->clk_table.entries[j].dcfclk_mhz <= clock_table->DcfClocks[i])
618                                 break;
619
620                 bw_params->clk_table.entries[i].phyclk_mhz = bw_params->clk_table.entries[j].phyclk_mhz;
621                 bw_params->clk_table.entries[i].phyclk_d18_mhz = bw_params->clk_table.entries[j].phyclk_d18_mhz;
622                 bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz;
623
624                 /* Now update clocks we do read */
625                 bw_params->clk_table.entries[i].fclk_mhz = min_fclk;
626                 bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[min_pstate].MemClk;
627                 bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[min_pstate].Voltage;
628                 bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i];
629                 bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i];
630                 bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk;
631                 bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk;
632                 bw_params->clk_table.entries[i].wck_ratio = convert_wck_ratio(
633                         clock_table->DfPstateTable[min_pstate].WckRatio);
634         }
635
636         /* Make sure to include at least one entry at highest pstate */
637         if (max_pstate != min_pstate || i == 0) {
638                 if (i > MAX_NUM_DPM_LVL - 1)
639                         i = MAX_NUM_DPM_LVL - 1;
640
641                 bw_params->clk_table.entries[i].fclk_mhz = max_fclk;
642                 bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk;
643                 bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[max_pstate].Voltage;
644                 bw_params->clk_table.entries[i].dcfclk_mhz = find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS);
645                 bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS);
646                 bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk;
647                 bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk;
648                 bw_params->clk_table.entries[i].wck_ratio = convert_wck_ratio(
649                         clock_table->DfPstateTable[max_pstate].WckRatio);
650                 i++;
651         }
652         bw_params->clk_table.num_entries = i--;
653
654         /* Make sure all highest clocks are included*/
655         bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS);
656         bw_params->clk_table.entries[i].dispclk_mhz = find_max_clk_value(clock_table->DispClocks, NUM_DISPCLK_DPM_LEVELS);
657         bw_params->clk_table.entries[i].dppclk_mhz = find_max_clk_value(clock_table->DppClocks, NUM_DPPCLK_DPM_LEVELS);
658         ASSERT(clock_table->DcfClocks[i] == find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS));
659         bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz;
660         bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz;
661         bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz;
662
663         /*
664          * Set any 0 clocks to max default setting. Not an issue for
665          * power since we aren't doing switching in such case anyway
666          */
667         for (i = 0; i < bw_params->clk_table.num_entries; i++) {
668                 if (!bw_params->clk_table.entries[i].fclk_mhz) {
669                         bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz;
670                         bw_params->clk_table.entries[i].memclk_mhz = def_max.memclk_mhz;
671                         bw_params->clk_table.entries[i].voltage = def_max.voltage;
672                 }
673                 if (!bw_params->clk_table.entries[i].dcfclk_mhz)
674                         bw_params->clk_table.entries[i].dcfclk_mhz = def_max.dcfclk_mhz;
675                 if (!bw_params->clk_table.entries[i].socclk_mhz)
676                         bw_params->clk_table.entries[i].socclk_mhz = def_max.socclk_mhz;
677                 if (!bw_params->clk_table.entries[i].dispclk_mhz)
678                         bw_params->clk_table.entries[i].dispclk_mhz = def_max.dispclk_mhz;
679                 if (!bw_params->clk_table.entries[i].dppclk_mhz)
680                         bw_params->clk_table.entries[i].dppclk_mhz = def_max.dppclk_mhz;
681                 if (!bw_params->clk_table.entries[i].phyclk_mhz)
682                         bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz;
683                 if (!bw_params->clk_table.entries[i].phyclk_d18_mhz)
684                         bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz;
685                 if (!bw_params->clk_table.entries[i].dtbclk_mhz)
686                         bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz;
687         }
688         ASSERT(bw_params->clk_table.entries[i-1].dcfclk_mhz);
689         bw_params->vram_type = bios_info->memory_type;
690
691         bw_params->dram_channel_width_bytes = bios_info->memory_type == 0x22 ? 8 : 4;
692         bw_params->num_channels = bios_info->ma_channel_number ? bios_info->ma_channel_number : 4;
693
694         for (i = 0; i < WM_SET_COUNT; i++) {
695                 bw_params->wm_table.entries[i].wm_inst = i;
696
697                 if (i >= bw_params->clk_table.num_entries) {
698                         bw_params->wm_table.entries[i].valid = false;
699                         continue;
700                 }
701
702                 bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG;
703                 bw_params->wm_table.entries[i].valid = true;
704         }
705 }
706
707 static struct clk_mgr_funcs dcn314_funcs = {
708         .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
709         .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
710         .update_clocks = dcn314_update_clocks,
711         .init_clocks = dcn31_init_clocks,
712         .enable_pme_wa = dcn314_enable_pme_wa,
713         .are_clock_states_equal = dcn314_are_clock_states_equal,
714         .notify_wm_ranges = dcn314_notify_wm_ranges
715 };
716 extern struct clk_mgr_funcs dcn3_fpga_funcs;
717
718 void dcn314_clk_mgr_construct(
719                 struct dc_context *ctx,
720                 struct clk_mgr_dcn314 *clk_mgr,
721                 struct pp_smu_funcs *pp_smu,
722                 struct dccg *dccg)
723 {
724         struct dcn314_smu_dpm_clks smu_dpm_clks = { 0 };
725         struct clk_log_info log_info = {0};
726
727         clk_mgr->base.base.ctx = ctx;
728         clk_mgr->base.base.funcs = &dcn314_funcs;
729
730         clk_mgr->base.pp_smu = pp_smu;
731
732         clk_mgr->base.dccg = dccg;
733         clk_mgr->base.dfs_bypass_disp_clk = 0;
734
735         clk_mgr->base.dprefclk_ss_percentage = 0;
736         clk_mgr->base.dprefclk_ss_divider = 1000;
737         clk_mgr->base.ss_on_dprefclk = false;
738         clk_mgr->base.dfs_ref_freq_khz = 48000;
739
740         clk_mgr->smu_wm_set.wm_set = (struct dcn314_watermarks *)dm_helpers_allocate_gpu_mem(
741                                 clk_mgr->base.base.ctx,
742                                 DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
743                                 sizeof(struct dcn314_watermarks),
744                                 &clk_mgr->smu_wm_set.mc_address.quad_part);
745
746         if (!clk_mgr->smu_wm_set.wm_set) {
747                 clk_mgr->smu_wm_set.wm_set = &dummy_wms;
748                 clk_mgr->smu_wm_set.mc_address.quad_part = 0;
749         }
750         ASSERT(clk_mgr->smu_wm_set.wm_set);
751
752         smu_dpm_clks.dpm_clks = (DpmClocks314_t *)dm_helpers_allocate_gpu_mem(
753                                 clk_mgr->base.base.ctx,
754                                 DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
755                                 sizeof(DpmClocks314_t),
756                                 &smu_dpm_clks.mc_address.quad_part);
757
758         if (smu_dpm_clks.dpm_clks == NULL) {
759                 smu_dpm_clks.dpm_clks = &dummy_clocks;
760                 smu_dpm_clks.mc_address.quad_part = 0;
761         }
762
763         ASSERT(smu_dpm_clks.dpm_clks);
764
765         clk_mgr->base.smu_ver = dcn314_smu_get_smu_version(&clk_mgr->base);
766
767         if (clk_mgr->base.smu_ver)
768                 clk_mgr->base.smu_present = true;
769
770         /* TODO: Check we get what we expect during bringup */
771         clk_mgr->base.base.dentist_vco_freq_khz = get_vco_frequency_from_reg(&clk_mgr->base);
772
773         if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType)
774                 dcn314_bw_params.wm_table = lpddr5_wm_table;
775         else
776                 dcn314_bw_params.wm_table = ddr5_wm_table;
777
778         /* Saved clocks configured at boot for debug purposes */
779         dcn314_dump_clk_registers(&clk_mgr->base.base.boot_snapshot,
780                                   &clk_mgr->base.base, &log_info);
781
782         clk_mgr->base.base.dprefclk_khz = 600000;
783         clk_mgr->base.base.clks.ref_dtbclk_khz = 600000;
784         dce_clock_read_ss_info(&clk_mgr->base);
785         /*if bios enabled SS, driver needs to adjust dtb clock, only enable with correct bios*/
786
787         clk_mgr->base.base.bw_params = &dcn314_bw_params;
788
789         if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) {
790                 int i;
791
792                 dcn314_get_dpm_table_from_smu(&clk_mgr->base, &smu_dpm_clks);
793                 DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n"
794                                    "NumDispClkLevelsEnabled: %d\n"
795                                    "NumSocClkLevelsEnabled: %d\n"
796                                    "VcnClkLevelsEnabled: %d\n"
797                                    "NumDfPst atesEnabled: %d\n"
798                                    "MinGfxClk: %d\n"
799                                    "MaxGfxClk: %d\n",
800                                    smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled,
801                                    smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled,
802                                    smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled,
803                                    smu_dpm_clks.dpm_clks->VcnClkLevelsEnabled,
804                                    smu_dpm_clks.dpm_clks->NumDfPstatesEnabled,
805                                    smu_dpm_clks.dpm_clks->MinGfxClk,
806                                    smu_dpm_clks.dpm_clks->MaxGfxClk);
807                 for (i = 0; i < smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled; i++) {
808                         DC_LOG_SMU("smu_dpm_clks.dpm_clks->DcfClocks[%d] = %d\n",
809                                            i,
810                                            smu_dpm_clks.dpm_clks->DcfClocks[i]);
811                 }
812                 for (i = 0; i < smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled; i++) {
813                         DC_LOG_SMU("smu_dpm_clks.dpm_clks->DispClocks[%d] = %d\n",
814                                            i, smu_dpm_clks.dpm_clks->DispClocks[i]);
815                 }
816                 for (i = 0; i < smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled; i++) {
817                         DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocClocks[%d] = %d\n",
818                                            i, smu_dpm_clks.dpm_clks->SocClocks[i]);
819                 }
820                 for (i = 0; i < NUM_SOC_VOLTAGE_LEVELS; i++)
821                         DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocVoltage[%d] = %d\n",
822                                            i, smu_dpm_clks.dpm_clks->SocVoltage[i]);
823
824                 for (i = 0; i < NUM_DF_PSTATE_LEVELS; i++) {
825                         DC_LOG_SMU("smu_dpm_clks.dpm_clks.DfPstateTable[%d].FClk = %d\n"
826                                            "smu_dpm_clks.dpm_clks->DfPstateTable[%d].MemClk= %d\n"
827                                            "smu_dpm_clks.dpm_clks->DfPstateTable[%d].Voltage = %d\n",
828                                            i, smu_dpm_clks.dpm_clks->DfPstateTable[i].FClk,
829                                            i, smu_dpm_clks.dpm_clks->DfPstateTable[i].MemClk,
830                                            i, smu_dpm_clks.dpm_clks->DfPstateTable[i].Voltage);
831                 }
832
833                 if (ctx->dc_bios && ctx->dc_bios->integrated_info && ctx->dc->config.use_default_clock_table == false) {
834                         dcn314_clk_mgr_helper_populate_bw_params(
835                                         &clk_mgr->base,
836                                         ctx->dc_bios->integrated_info,
837                                         smu_dpm_clks.dpm_clks);
838                 }
839         }
840
841         if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0)
842                 dm_helpers_free_gpu_mem(clk_mgr->base.base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
843                                 smu_dpm_clks.dpm_clks);
844 }
845
846 void dcn314_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int)
847 {
848         struct clk_mgr_dcn314 *clk_mgr = TO_CLK_MGR_DCN314(clk_mgr_int);
849
850         if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0)
851                 dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
852                                 clk_mgr->smu_wm_set.wm_set);
853 }