Merge tag 'drm-next-2020-12-24' of git://anongit.freedesktop.org/drm/drm
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / display / dc / clk_mgr / dcn21 / rn_clk_mgr.c
1 /*
2  * Copyright 2018 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25
26 #include "dccg.h"
27 #include "clk_mgr_internal.h"
28
29
30 #include "dcn20/dcn20_clk_mgr.h"
31 #include "rn_clk_mgr.h"
32
33
34 #include "dce100/dce_clk_mgr.h"
35 #include "rn_clk_mgr_vbios_smu.h"
36 #include "reg_helper.h"
37 #include "core_types.h"
38 #include "dm_helpers.h"
39
40 #include "atomfirmware.h"
41 #include "clk/clk_10_0_2_offset.h"
42 #include "clk/clk_10_0_2_sh_mask.h"
43 #include "renoir_ip_offset.h"
44
45
46 /* Constants */
47
48 #define LPDDR_MEM_RETRAIN_LATENCY 4.977 /* Number obtained from LPDDR4 Training Counter Requirement doc */
49 #define SMU_VER_55_51_0 0x373300 /* SMU Version that is able to set DISPCLK below 100MHz */
50
51 /* Macros */
52
53 #define REG(reg_name) \
54         (CLK_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name)
55
56
57 /* TODO: evaluate how to lower or disable all dcn clocks in screen off case */
58 int rn_get_active_display_cnt_wa(
59                 struct dc *dc,
60                 struct dc_state *context)
61 {
62         int i, display_count;
63         bool tmds_present = false;
64
65         display_count = 0;
66         for (i = 0; i < context->stream_count; i++) {
67                 const struct dc_stream_state *stream = context->streams[i];
68
69                 if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
70                                 stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
71                                 stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK)
72                         tmds_present = true;
73         }
74
75         for (i = 0; i < dc->link_count; i++) {
76                 const struct dc_link *link = dc->links[i];
77
78                 /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */
79                 if (link->link_enc->funcs->is_dig_enabled(link->link_enc))
80                         display_count++;
81         }
82
83         /* WA for hang on HDMI after display off back back on*/
84         if (display_count == 0 && tmds_present)
85                 display_count = 1;
86
87         return display_count;
88 }
89
90 void rn_set_low_power_state(struct clk_mgr *clk_mgr_base)
91 {
92         struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
93
94         rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_LOW_POWER);
95         /* update power state */
96         clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
97 }
98
99 static void rn_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr,
100                 struct dc_state *context, int ref_dpp_clk, bool safe_to_lower)
101 {
102         int i;
103
104         clk_mgr->dccg->ref_dppclk = ref_dpp_clk;
105
106         for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
107                 int dpp_inst, dppclk_khz, prev_dppclk_khz;
108
109                 /* Loop index will match dpp->inst if resource exists,
110                  * and we want to avoid dependency on dpp object
111                  */
112                 dpp_inst = i;
113                 dppclk_khz = context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz;
114
115                 prev_dppclk_khz = clk_mgr->dccg->pipe_dppclk_khz[i];
116
117                 if (safe_to_lower || prev_dppclk_khz < dppclk_khz)
118                         clk_mgr->dccg->funcs->update_dpp_dto(
119                                                         clk_mgr->dccg, dpp_inst, dppclk_khz);
120         }
121 }
122
123
124 void rn_update_clocks(struct clk_mgr *clk_mgr_base,
125                         struct dc_state *context,
126                         bool safe_to_lower)
127 {
128         struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
129         struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
130         struct dc *dc = clk_mgr_base->ctx->dc;
131         int display_count;
132         bool update_dppclk = false;
133         bool update_dispclk = false;
134         bool dpp_clock_lowered = false;
135
136         struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;
137
138         if (dc->work_arounds.skip_clock_update)
139                 return;
140
141         /*
142          * if it is safe to lower, but we are already in the lower state, we don't have to do anything
143          * also if safe to lower is false, we just go in the higher state
144          */
145         if (safe_to_lower && !dc->debug.disable_48mhz_pwrdwn) {
146                 /* check that we're not already in lower */
147                 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
148
149                         display_count = rn_get_active_display_cnt_wa(dc, context);
150                         /* if we can go lower, go lower */
151                         if (display_count == 0) {
152                                 rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_LOW_POWER);
153                                 /* update power state */
154                                 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
155                         }
156                 }
157         } else {
158                 /* check that we're not already in D0 */
159                 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) {
160                         rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_MISSION_MODE);
161                         /* update power state */
162                         clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE;
163                 }
164         }
165
166         if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) {
167                 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz;
168                 rn_vbios_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz);
169         }
170
171         if (should_set_clock(safe_to_lower,
172                         new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) {
173                 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
174                 rn_vbios_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz);
175         }
176
177         // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow.
178         // Do not adjust dppclk if dppclk is 0 to avoid unexpected result
179         if (new_clocks->dppclk_khz < 100000 && new_clocks->dppclk_khz > 0)
180                 new_clocks->dppclk_khz = 100000;
181
182         /*
183          * Temporally ignore thew 0 cases for disp and dpp clks.
184          * We may have a new feature that requires 0 clks in the future.
185          */
186         if (new_clocks->dppclk_khz == 0 || new_clocks->dispclk_khz == 0) {
187                 new_clocks->dppclk_khz = clk_mgr_base->clks.dppclk_khz;
188                 new_clocks->dispclk_khz = clk_mgr_base->clks.dispclk_khz;
189         }
190
191         if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr_base->clks.dppclk_khz)) {
192                 if (clk_mgr_base->clks.dppclk_khz > new_clocks->dppclk_khz)
193                         dpp_clock_lowered = true;
194                 clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
195                 update_dppclk = true;
196         }
197
198         if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
199                 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
200                 clk_mgr_base->clks.actual_dispclk_khz = rn_vbios_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
201
202                 update_dispclk = true;
203         }
204
205         if (dpp_clock_lowered) {
206                 // increase per DPP DTO before lowering global dppclk with requested dppclk
207                 rn_update_clocks_update_dpp_dto(
208                                 clk_mgr,
209                                 context,
210                                 clk_mgr_base->clks.dppclk_khz,
211                                 safe_to_lower);
212
213                 clk_mgr_base->clks.actual_dppclk_khz =
214                                 rn_vbios_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
215
216                 //update dpp dto with actual dpp clk.
217                 rn_update_clocks_update_dpp_dto(
218                                 clk_mgr,
219                                 context,
220                                 clk_mgr_base->clks.actual_dppclk_khz,
221                                 safe_to_lower);
222
223         } else {
224                 // increase global DPPCLK before lowering per DPP DTO
225                 if (update_dppclk || update_dispclk)
226                         clk_mgr_base->clks.actual_dppclk_khz =
227                                         rn_vbios_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
228
229                 // always update dtos unless clock is lowered and not safe to lower
230                 rn_update_clocks_update_dpp_dto(
231                                 clk_mgr,
232                                 context,
233                                 clk_mgr_base->clks.actual_dppclk_khz,
234                                 safe_to_lower);
235         }
236
237         if (update_dispclk &&
238                         dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
239                 /*update dmcu for wait_loop count*/
240                 dmcu->funcs->set_psr_wait_loop(dmcu,
241                         clk_mgr_base->clks.dispclk_khz / 1000 / 7);
242         }
243 }
244
245 static int get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr)
246 {
247         /* get FbMult value */
248         struct fixed31_32 pll_req;
249         unsigned int fbmult_frac_val = 0;
250         unsigned int fbmult_int_val = 0;
251
252
253         /*
254          * Register value of fbmult is in 8.16 format, we are converting to 31.32
255          * to leverage the fix point operations available in driver
256          */
257
258         REG_GET(CLK1_CLK_PLL_REQ, FbMult_frac, &fbmult_frac_val); /* 16 bit fractional part*/
259         REG_GET(CLK1_CLK_PLL_REQ, FbMult_int, &fbmult_int_val); /* 8 bit integer part */
260
261         pll_req = dc_fixpt_from_int(fbmult_int_val);
262
263         /*
264          * since fractional part is only 16 bit in register definition but is 32 bit
265          * in our fix point definiton, need to shift left by 16 to obtain correct value
266          */
267         pll_req.value |= fbmult_frac_val << 16;
268
269         /* multiply by REFCLK period */
270         pll_req = dc_fixpt_mul_int(pll_req, clk_mgr->dfs_ref_freq_khz);
271
272         /* integer part is now VCO frequency in kHz */
273         return dc_fixpt_floor(pll_req);
274 }
275
276 static void rn_dump_clk_registers_internal(struct rn_clk_internal *internal, struct clk_mgr *clk_mgr_base)
277 {
278         struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
279
280         internal->CLK1_CLK3_CURRENT_CNT = REG_READ(CLK1_CLK3_CURRENT_CNT);
281         internal->CLK1_CLK3_BYPASS_CNTL = REG_READ(CLK1_CLK3_BYPASS_CNTL);
282
283         internal->CLK1_CLK3_DS_CNTL = REG_READ(CLK1_CLK3_DS_CNTL);      //dcf deep sleep divider
284         internal->CLK1_CLK3_ALLOW_DS = REG_READ(CLK1_CLK3_ALLOW_DS);
285
286         internal->CLK1_CLK1_CURRENT_CNT = REG_READ(CLK1_CLK1_CURRENT_CNT);
287         internal->CLK1_CLK1_BYPASS_CNTL = REG_READ(CLK1_CLK1_BYPASS_CNTL);
288
289         internal->CLK1_CLK2_CURRENT_CNT = REG_READ(CLK1_CLK2_CURRENT_CNT);
290         internal->CLK1_CLK2_BYPASS_CNTL = REG_READ(CLK1_CLK2_BYPASS_CNTL);
291
292         internal->CLK1_CLK0_CURRENT_CNT = REG_READ(CLK1_CLK0_CURRENT_CNT);
293         internal->CLK1_CLK0_BYPASS_CNTL = REG_READ(CLK1_CLK0_BYPASS_CNTL);
294 }
295
296 /* This function collect raw clk register values */
297 static void rn_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
298                 struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
299 {
300         struct rn_clk_internal internal = {0};
301         char *bypass_clks[5] = {"0x0 DFS", "0x1 REFCLK", "0x2 ERROR", "0x3 400 FCH", "0x4 600 FCH"};
302         unsigned int chars_printed = 0;
303         unsigned int remaining_buffer = log_info->bufSize;
304
305         rn_dump_clk_registers_internal(&internal, clk_mgr_base);
306
307         regs_and_bypass->dcfclk = internal.CLK1_CLK3_CURRENT_CNT / 10;
308         regs_and_bypass->dcf_deep_sleep_divider = internal.CLK1_CLK3_DS_CNTL / 10;
309         regs_and_bypass->dcf_deep_sleep_allow = internal.CLK1_CLK3_ALLOW_DS;
310         regs_and_bypass->dprefclk = internal.CLK1_CLK2_CURRENT_CNT / 10;
311         regs_and_bypass->dispclk = internal.CLK1_CLK0_CURRENT_CNT / 10;
312         regs_and_bypass->dppclk = internal.CLK1_CLK1_CURRENT_CNT / 10;
313
314         regs_and_bypass->dppclk_bypass = internal.CLK1_CLK1_BYPASS_CNTL & 0x0007;
315         if (regs_and_bypass->dppclk_bypass < 0 || regs_and_bypass->dppclk_bypass > 4)
316                 regs_and_bypass->dppclk_bypass = 0;
317         regs_and_bypass->dcfclk_bypass = internal.CLK1_CLK3_BYPASS_CNTL & 0x0007;
318         if (regs_and_bypass->dcfclk_bypass < 0 || regs_and_bypass->dcfclk_bypass > 4)
319                 regs_and_bypass->dcfclk_bypass = 0;
320         regs_and_bypass->dispclk_bypass = internal.CLK1_CLK0_BYPASS_CNTL & 0x0007;
321         if (regs_and_bypass->dispclk_bypass < 0 || regs_and_bypass->dispclk_bypass > 4)
322                 regs_and_bypass->dispclk_bypass = 0;
323         regs_and_bypass->dprefclk_bypass = internal.CLK1_CLK2_BYPASS_CNTL & 0x0007;
324         if (regs_and_bypass->dprefclk_bypass < 0 || regs_and_bypass->dprefclk_bypass > 4)
325                 regs_and_bypass->dprefclk_bypass = 0;
326
327         if (log_info->enabled) {
328                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "clk_type,clk_value,deepsleep_cntl,deepsleep_allow,bypass\n");
329                 remaining_buffer -= chars_printed;
330                 *log_info->sum_chars_printed += chars_printed;
331                 log_info->pBuf += chars_printed;
332
333                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "dcfclk,%d,%d,%d,%s\n",
334                         regs_and_bypass->dcfclk,
335                         regs_and_bypass->dcf_deep_sleep_divider,
336                         regs_and_bypass->dcf_deep_sleep_allow,
337                         bypass_clks[(int) regs_and_bypass->dcfclk_bypass]);
338                 remaining_buffer -= chars_printed;
339                 *log_info->sum_chars_printed += chars_printed;
340                 log_info->pBuf += chars_printed;
341
342                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "dprefclk,%d,N/A,N/A,%s\n",
343                         regs_and_bypass->dprefclk,
344                         bypass_clks[(int) regs_and_bypass->dprefclk_bypass]);
345                 remaining_buffer -= chars_printed;
346                 *log_info->sum_chars_printed += chars_printed;
347                 log_info->pBuf += chars_printed;
348
349                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "dispclk,%d,N/A,N/A,%s\n",
350                         regs_and_bypass->dispclk,
351                         bypass_clks[(int) regs_and_bypass->dispclk_bypass]);
352                 remaining_buffer -= chars_printed;
353                 *log_info->sum_chars_printed += chars_printed;
354                 log_info->pBuf += chars_printed;
355
356                 //split
357                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "SPLIT\n");
358                 remaining_buffer -= chars_printed;
359                 *log_info->sum_chars_printed += chars_printed;
360                 log_info->pBuf += chars_printed;
361
362                 // REGISTER VALUES
363                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "reg_name,value,clk_type\n");
364                 remaining_buffer -= chars_printed;
365                 *log_info->sum_chars_printed += chars_printed;
366                 log_info->pBuf += chars_printed;
367
368                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK3_CURRENT_CNT,%d,dcfclk\n",
369                                 internal.CLK1_CLK3_CURRENT_CNT);
370                 remaining_buffer -= chars_printed;
371                 *log_info->sum_chars_printed += chars_printed;
372                 log_info->pBuf += chars_printed;
373
374                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK3_DS_CNTL,%d,dcf_deep_sleep_divider\n",
375                                         internal.CLK1_CLK3_DS_CNTL);
376                 remaining_buffer -= chars_printed;
377                 *log_info->sum_chars_printed += chars_printed;
378                 log_info->pBuf += chars_printed;
379
380                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK3_ALLOW_DS,%d,dcf_deep_sleep_allow\n",
381                                         internal.CLK1_CLK3_ALLOW_DS);
382                 remaining_buffer -= chars_printed;
383                 *log_info->sum_chars_printed += chars_printed;
384                 log_info->pBuf += chars_printed;
385
386                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK2_CURRENT_CNT,%d,dprefclk\n",
387                                         internal.CLK1_CLK2_CURRENT_CNT);
388                 remaining_buffer -= chars_printed;
389                 *log_info->sum_chars_printed += chars_printed;
390                 log_info->pBuf += chars_printed;
391
392                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK0_CURRENT_CNT,%d,dispclk\n",
393                                         internal.CLK1_CLK0_CURRENT_CNT);
394                 remaining_buffer -= chars_printed;
395                 *log_info->sum_chars_printed += chars_printed;
396                 log_info->pBuf += chars_printed;
397
398                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK1_CURRENT_CNT,%d,dppclk\n",
399                                         internal.CLK1_CLK1_CURRENT_CNT);
400                 remaining_buffer -= chars_printed;
401                 *log_info->sum_chars_printed += chars_printed;
402                 log_info->pBuf += chars_printed;
403
404                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK3_BYPASS_CNTL,%d,dcfclk_bypass\n",
405                                         internal.CLK1_CLK3_BYPASS_CNTL);
406                 remaining_buffer -= chars_printed;
407                 *log_info->sum_chars_printed += chars_printed;
408                 log_info->pBuf += chars_printed;
409
410                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK2_BYPASS_CNTL,%d,dprefclk_bypass\n",
411                                         internal.CLK1_CLK2_BYPASS_CNTL);
412                 remaining_buffer -= chars_printed;
413                 *log_info->sum_chars_printed += chars_printed;
414                 log_info->pBuf += chars_printed;
415
416                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK0_BYPASS_CNTL,%d,dispclk_bypass\n",
417                                         internal.CLK1_CLK0_BYPASS_CNTL);
418                 remaining_buffer -= chars_printed;
419                 *log_info->sum_chars_printed += chars_printed;
420                 log_info->pBuf += chars_printed;
421
422                 chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK1_BYPASS_CNTL,%d,dppclk_bypass\n",
423                                         internal.CLK1_CLK1_BYPASS_CNTL);
424                 remaining_buffer -= chars_printed;
425                 *log_info->sum_chars_printed += chars_printed;
426                 log_info->pBuf += chars_printed;
427         }
428 }
429
430 /* This function produce translated logical clk state values*/
431 void rn_get_clk_states(struct clk_mgr *clk_mgr_base, struct clk_states *s)
432 {
433         struct clk_state_registers_and_bypass sb = { 0 };
434         struct clk_log_info log_info = { 0 };
435
436         rn_dump_clk_registers(&sb, clk_mgr_base, &log_info);
437
438         s->dprefclk_khz = sb.dprefclk * 1000;
439 }
440
441 void rn_enable_pme_wa(struct clk_mgr *clk_mgr_base)
442 {
443         struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
444
445         rn_vbios_smu_enable_pme_wa(clk_mgr);
446 }
447
448 void rn_init_clocks(struct clk_mgr *clk_mgr)
449 {
450         memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
451         // Assumption is that boot state always supports pstate
452         clk_mgr->clks.p_state_change_support = true;
453         clk_mgr->clks.prev_p_state_change_support = true;
454         clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN;
455 }
456
457 static void build_watermark_ranges(struct clk_bw_params *bw_params, struct pp_smu_wm_range_sets *ranges)
458 {
459         int i, num_valid_sets;
460
461         num_valid_sets = 0;
462
463         for (i = 0; i < WM_SET_COUNT; i++) {
464                 /* skip empty entries, the smu array has no holes*/
465                 if (!bw_params->wm_table.entries[i].valid)
466                         continue;
467
468                 ranges->reader_wm_sets[num_valid_sets].wm_inst = bw_params->wm_table.entries[i].wm_inst;
469                 ranges->reader_wm_sets[num_valid_sets].wm_type = bw_params->wm_table.entries[i].wm_type;
470                 /* We will not select WM based on fclk, so leave it as unconstrained */
471                 ranges->reader_wm_sets[num_valid_sets].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN;
472                 ranges->reader_wm_sets[num_valid_sets].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX;
473                 /* dcfclk wil be used to select WM*/
474
475                 if (ranges->reader_wm_sets[num_valid_sets].wm_type == WM_TYPE_PSTATE_CHG) {
476                         if (i == 0)
477                                 ranges->reader_wm_sets[num_valid_sets].min_drain_clk_mhz = 0;
478                         else {
479                                 /* add 1 to make it non-overlapping with next lvl */
480                                 ranges->reader_wm_sets[num_valid_sets].min_drain_clk_mhz = bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1;
481                         }
482                         ranges->reader_wm_sets[num_valid_sets].max_drain_clk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
483
484                 } else {
485                         /* unconstrained for memory retraining */
486                         ranges->reader_wm_sets[num_valid_sets].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN;
487                         ranges->reader_wm_sets[num_valid_sets].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX;
488
489                         /* Modify previous watermark range to cover up to max */
490                         ranges->reader_wm_sets[num_valid_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX;
491                 }
492                 num_valid_sets++;
493         }
494
495         ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */
496         ranges->num_reader_wm_sets = num_valid_sets;
497
498         /* modify the min and max to make sure we cover the whole range*/
499         ranges->reader_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN;
500         ranges->reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN;
501         ranges->reader_wm_sets[ranges->num_reader_wm_sets - 1].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX;
502         ranges->reader_wm_sets[ranges->num_reader_wm_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX;
503
504         /* This is for writeback only, does not matter currently as no writeback support*/
505         ranges->num_writer_wm_sets = 1;
506         ranges->writer_wm_sets[0].wm_inst = WM_A;
507         ranges->writer_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN;
508         ranges->writer_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX;
509         ranges->writer_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN;
510         ranges->writer_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX;
511
512 }
513
514 static void rn_notify_wm_ranges(struct clk_mgr *clk_mgr_base)
515 {
516         struct dc_debug_options *debug = &clk_mgr_base->ctx->dc->debug;
517         struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
518         struct pp_smu_funcs *pp_smu = clk_mgr->pp_smu;
519
520         if (!debug->disable_pplib_wm_range) {
521                 build_watermark_ranges(clk_mgr_base->bw_params, &clk_mgr_base->ranges);
522
523                 /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */
524                 if (pp_smu && pp_smu->rn_funcs.set_wm_ranges)
525                         pp_smu->rn_funcs.set_wm_ranges(&pp_smu->rn_funcs.pp_smu, &clk_mgr_base->ranges);
526         }
527
528 }
529
530 static bool rn_are_clock_states_equal(struct dc_clocks *a,
531                 struct dc_clocks *b)
532 {
533         if (a->dispclk_khz != b->dispclk_khz)
534                 return false;
535         else if (a->dppclk_khz != b->dppclk_khz)
536                 return false;
537         else if (a->dcfclk_khz != b->dcfclk_khz)
538                 return false;
539         else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz)
540                 return false;
541
542         return true;
543 }
544
545
546 /* Notify clk_mgr of a change in link rate, update phyclk frequency if necessary */
547 static void rn_notify_link_rate_change(struct clk_mgr *clk_mgr_base, struct dc_link *link)
548 {
549         struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
550         unsigned int i, max_phyclk_req = 0;
551
552         clk_mgr->cur_phyclk_req_table[link->link_index] = link->cur_link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
553
554         for (i = 0; i < MAX_PIPES * 2; i++) {
555                 if (clk_mgr->cur_phyclk_req_table[i] > max_phyclk_req)
556                         max_phyclk_req = clk_mgr->cur_phyclk_req_table[i];
557         }
558
559         if (max_phyclk_req != clk_mgr_base->clks.phyclk_khz) {
560                 clk_mgr_base->clks.phyclk_khz = max_phyclk_req;
561                 rn_vbios_smu_set_phyclk(clk_mgr, clk_mgr_base->clks.phyclk_khz);
562         }
563 }
564
565 static struct clk_mgr_funcs dcn21_funcs = {
566         .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
567         .update_clocks = rn_update_clocks,
568         .init_clocks = rn_init_clocks,
569         .enable_pme_wa = rn_enable_pme_wa,
570         .are_clock_states_equal = rn_are_clock_states_equal,
571         .set_low_power_state = rn_set_low_power_state,
572         .notify_wm_ranges = rn_notify_wm_ranges,
573         .notify_link_rate_change = rn_notify_link_rate_change,
574 };
575
576 static struct clk_bw_params rn_bw_params = {
577         .vram_type = Ddr4MemType,
578         .num_channels = 1,
579         .clk_table = {
580                 .entries = {
581                         {
582                                 .voltage = 0,
583                                 .dcfclk_mhz = 400,
584                                 .fclk_mhz = 400,
585                                 .memclk_mhz = 800,
586                                 .socclk_mhz = 0,
587                         },
588                         {
589                                 .voltage = 0,
590                                 .dcfclk_mhz = 483,
591                                 .fclk_mhz = 800,
592                                 .memclk_mhz = 1600,
593                                 .socclk_mhz = 0,
594                         },
595                         {
596                                 .voltage = 0,
597                                 .dcfclk_mhz = 602,
598                                 .fclk_mhz = 1067,
599                                 .memclk_mhz = 1067,
600                                 .socclk_mhz = 0,
601                         },
602                         {
603                                 .voltage = 0,
604                                 .dcfclk_mhz = 738,
605                                 .fclk_mhz = 1333,
606                                 .memclk_mhz = 1600,
607                                 .socclk_mhz = 0,
608                         },
609                 },
610
611                 .num_entries = 4,
612         },
613
614 };
615
616 static struct wm_table ddr4_wm_table_gs = {
617         .entries = {
618                 {
619                         .wm_inst = WM_A,
620                         .wm_type = WM_TYPE_PSTATE_CHG,
621                         .pstate_latency_us = 11.72,
622                         .sr_exit_time_us = 7.09,
623                         .sr_enter_plus_exit_time_us = 8.14,
624                         .valid = true,
625                 },
626                 {
627                         .wm_inst = WM_B,
628                         .wm_type = WM_TYPE_PSTATE_CHG,
629                         .pstate_latency_us = 11.72,
630                         .sr_exit_time_us = 10.12,
631                         .sr_enter_plus_exit_time_us = 11.48,
632                         .valid = true,
633                 },
634                 {
635                         .wm_inst = WM_C,
636                         .wm_type = WM_TYPE_PSTATE_CHG,
637                         .pstate_latency_us = 11.72,
638                         .sr_exit_time_us = 10.12,
639                         .sr_enter_plus_exit_time_us = 11.48,
640                         .valid = true,
641                 },
642                 {
643                         .wm_inst = WM_D,
644                         .wm_type = WM_TYPE_PSTATE_CHG,
645                         .pstate_latency_us = 11.72,
646                         .sr_exit_time_us = 10.12,
647                         .sr_enter_plus_exit_time_us = 11.48,
648                         .valid = true,
649                 },
650         }
651 };
652
653 static struct wm_table lpddr4_wm_table_gs = {
654         .entries = {
655                 {
656                         .wm_inst = WM_A,
657                         .wm_type = WM_TYPE_PSTATE_CHG,
658                         .pstate_latency_us = 11.65333,
659                         .sr_exit_time_us = 5.32,
660                         .sr_enter_plus_exit_time_us = 6.38,
661                         .valid = true,
662                 },
663                 {
664                         .wm_inst = WM_B,
665                         .wm_type = WM_TYPE_PSTATE_CHG,
666                         .pstate_latency_us = 11.65333,
667                         .sr_exit_time_us = 9.82,
668                         .sr_enter_plus_exit_time_us = 11.196,
669                         .valid = true,
670                 },
671                 {
672                         .wm_inst = WM_C,
673                         .wm_type = WM_TYPE_PSTATE_CHG,
674                         .pstate_latency_us = 11.65333,
675                         .sr_exit_time_us = 9.89,
676                         .sr_enter_plus_exit_time_us = 11.24,
677                         .valid = true,
678                 },
679                 {
680                         .wm_inst = WM_D,
681                         .wm_type = WM_TYPE_PSTATE_CHG,
682                         .pstate_latency_us = 11.65333,
683                         .sr_exit_time_us = 9.748,
684                         .sr_enter_plus_exit_time_us = 11.102,
685                         .valid = true,
686                 },
687         }
688 };
689
690 static struct wm_table lpddr4_wm_table_with_disabled_ppt = {
691         .entries = {
692                 {
693                         .wm_inst = WM_A,
694                         .wm_type = WM_TYPE_PSTATE_CHG,
695                         .pstate_latency_us = 11.65333,
696                         .sr_exit_time_us = 8.32,
697                         .sr_enter_plus_exit_time_us = 9.38,
698                         .valid = true,
699                 },
700                 {
701                         .wm_inst = WM_B,
702                         .wm_type = WM_TYPE_PSTATE_CHG,
703                         .pstate_latency_us = 11.65333,
704                         .sr_exit_time_us = 9.82,
705                         .sr_enter_plus_exit_time_us = 11.196,
706                         .valid = true,
707                 },
708                 {
709                         .wm_inst = WM_C,
710                         .wm_type = WM_TYPE_PSTATE_CHG,
711                         .pstate_latency_us = 11.65333,
712                         .sr_exit_time_us = 9.89,
713                         .sr_enter_plus_exit_time_us = 11.24,
714                         .valid = true,
715                 },
716                 {
717                         .wm_inst = WM_D,
718                         .wm_type = WM_TYPE_PSTATE_CHG,
719                         .pstate_latency_us = 11.65333,
720                         .sr_exit_time_us = 9.748,
721                         .sr_enter_plus_exit_time_us = 11.102,
722                         .valid = true,
723                 },
724         }
725 };
726
727 static struct wm_table ddr4_wm_table_rn = {
728         .entries = {
729                 {
730                         .wm_inst = WM_A,
731                         .wm_type = WM_TYPE_PSTATE_CHG,
732                         .pstate_latency_us = 11.72,
733                         .sr_exit_time_us = 11.90,
734                         .sr_enter_plus_exit_time_us = 12.80,
735                         .valid = true,
736                 },
737                 {
738                         .wm_inst = WM_B,
739                         .wm_type = WM_TYPE_PSTATE_CHG,
740                         .pstate_latency_us = 11.72,
741                         .sr_exit_time_us = 13.18,
742                         .sr_enter_plus_exit_time_us = 14.30,
743                         .valid = true,
744                 },
745                 {
746                         .wm_inst = WM_C,
747                         .wm_type = WM_TYPE_PSTATE_CHG,
748                         .pstate_latency_us = 11.72,
749                         .sr_exit_time_us = 13.18,
750                         .sr_enter_plus_exit_time_us = 14.30,
751                         .valid = true,
752                 },
753                 {
754                         .wm_inst = WM_D,
755                         .wm_type = WM_TYPE_PSTATE_CHG,
756                         .pstate_latency_us = 11.72,
757                         .sr_exit_time_us = 13.18,
758                         .sr_enter_plus_exit_time_us = 14.30,
759                         .valid = true,
760                 },
761         }
762 };
763
764 static struct wm_table lpddr4_wm_table_rn = {
765         .entries = {
766                 {
767                         .wm_inst = WM_A,
768                         .wm_type = WM_TYPE_PSTATE_CHG,
769                         .pstate_latency_us = 11.65333,
770                         .sr_exit_time_us = 7.32,
771                         .sr_enter_plus_exit_time_us = 8.38,
772                         .valid = true,
773                 },
774                 {
775                         .wm_inst = WM_B,
776                         .wm_type = WM_TYPE_PSTATE_CHG,
777                         .pstate_latency_us = 11.65333,
778                         .sr_exit_time_us = 9.82,
779                         .sr_enter_plus_exit_time_us = 11.196,
780                         .valid = true,
781                 },
782                 {
783                         .wm_inst = WM_C,
784                         .wm_type = WM_TYPE_PSTATE_CHG,
785                         .pstate_latency_us = 11.65333,
786                         .sr_exit_time_us = 9.89,
787                         .sr_enter_plus_exit_time_us = 11.24,
788                         .valid = true,
789                 },
790                 {
791                         .wm_inst = WM_D,
792                         .wm_type = WM_TYPE_PSTATE_CHG,
793                         .pstate_latency_us = 11.65333,
794                         .sr_exit_time_us = 9.748,
795                         .sr_enter_plus_exit_time_us = 11.102,
796                         .valid = true,
797                 },
798         }
799 };
800
801 static unsigned int find_dcfclk_for_voltage(struct dpm_clocks *clock_table, unsigned int voltage)
802 {
803         int i;
804
805         for (i = 0; i < PP_SMU_NUM_DCFCLK_DPM_LEVELS; i++) {
806                 if (clock_table->DcfClocks[i].Vol == voltage)
807                         return clock_table->DcfClocks[i].Freq;
808         }
809
810         ASSERT(0);
811         return 0;
812 }
813
814 static void rn_clk_mgr_helper_populate_bw_params(struct clk_bw_params *bw_params, struct dpm_clocks *clock_table, struct integrated_info *bios_info)
815 {
816         int i, j = 0;
817
818         j = -1;
819
820         ASSERT(PP_SMU_NUM_FCLK_DPM_LEVELS <= MAX_NUM_DPM_LVL);
821
822         /* Find lowest DPM, FCLK is filled in reverse order*/
823
824         for (i = PP_SMU_NUM_FCLK_DPM_LEVELS - 1; i >= 0; i--) {
825                 if (clock_table->FClocks[i].Freq != 0 && clock_table->FClocks[i].Vol != 0) {
826                         j = i;
827                         break;
828                 }
829         }
830
831         if (j == -1) {
832                 /* clock table is all 0s, just use our own hardcode */
833                 ASSERT(0);
834                 return;
835         }
836
837         bw_params->clk_table.num_entries = j + 1;
838
839         for (i = 0; i < bw_params->clk_table.num_entries; i++, j--) {
840                 bw_params->clk_table.entries[i].fclk_mhz = clock_table->FClocks[j].Freq;
841                 bw_params->clk_table.entries[i].memclk_mhz = clock_table->MemClocks[j].Freq;
842                 bw_params->clk_table.entries[i].voltage = clock_table->FClocks[j].Vol;
843                 bw_params->clk_table.entries[i].dcfclk_mhz = find_dcfclk_for_voltage(clock_table, clock_table->FClocks[j].Vol);
844         }
845
846         bw_params->vram_type = bios_info->memory_type;
847         bw_params->num_channels = bios_info->ma_channel_number;
848
849         for (i = 0; i < WM_SET_COUNT; i++) {
850                 bw_params->wm_table.entries[i].wm_inst = i;
851
852                 if (i >= bw_params->clk_table.num_entries) {
853                         bw_params->wm_table.entries[i].valid = false;
854                         continue;
855                 }
856
857                 bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG;
858                 bw_params->wm_table.entries[i].valid = true;
859         }
860
861         if (bw_params->vram_type == LpDdr4MemType) {
862                 /*
863                  * WM set D will be re-purposed for memory retraining
864                  */
865                 bw_params->wm_table.entries[WM_D].pstate_latency_us = LPDDR_MEM_RETRAIN_LATENCY;
866                 bw_params->wm_table.entries[WM_D].wm_inst = WM_D;
867                 bw_params->wm_table.entries[WM_D].wm_type = WM_TYPE_RETRAINING;
868                 bw_params->wm_table.entries[WM_D].valid = true;
869         }
870
871 }
872
873 void rn_clk_mgr_construct(
874                 struct dc_context *ctx,
875                 struct clk_mgr_internal *clk_mgr,
876                 struct pp_smu_funcs *pp_smu,
877                 struct dccg *dccg)
878 {
879         struct dc_debug_options *debug = &ctx->dc->debug;
880         struct dpm_clocks clock_table = { 0 };
881         enum pp_smu_status status = 0;
882         int is_green_sardine = 0;
883
884 #if defined(CONFIG_DRM_AMD_DC_DCN)
885         is_green_sardine = ASICREV_IS_GREEN_SARDINE(ctx->asic_id.hw_internal_rev);
886 #endif
887
888         clk_mgr->base.ctx = ctx;
889         clk_mgr->base.funcs = &dcn21_funcs;
890
891         clk_mgr->pp_smu = pp_smu;
892
893         clk_mgr->dccg = dccg;
894         clk_mgr->dfs_bypass_disp_clk = 0;
895
896         clk_mgr->dprefclk_ss_percentage = 0;
897         clk_mgr->dprefclk_ss_divider = 1000;
898         clk_mgr->ss_on_dprefclk = false;
899         clk_mgr->dfs_ref_freq_khz = 48000;
900
901         clk_mgr->smu_ver = rn_vbios_smu_get_smu_version(clk_mgr);
902
903         if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) {
904                 dcn21_funcs.update_clocks = dcn2_update_clocks_fpga;
905                 clk_mgr->base.dentist_vco_freq_khz = 3600000;
906         } else {
907                 struct clk_log_info log_info = {0};
908
909                 clk_mgr->periodic_retraining_disabled = rn_vbios_smu_is_periodic_retraining_disabled(clk_mgr);
910
911                 /* SMU Version 55.51.0 and up no longer have an issue
912                  * that needs to limit minimum dispclk */
913                 if (clk_mgr->smu_ver >= SMU_VER_55_51_0)
914                         debug->min_disp_clk_khz = 0;
915
916                 /* TODO: Check we get what we expect during bringup */
917                 clk_mgr->base.dentist_vco_freq_khz = get_vco_frequency_from_reg(clk_mgr);
918
919                 /* in case we don't get a value from the register, use default */
920                 if (clk_mgr->base.dentist_vco_freq_khz == 0)
921                         clk_mgr->base.dentist_vco_freq_khz = 3600000;
922
923                 if (ctx->dc_bios->integrated_info->memory_type == LpDdr4MemType) {
924                         if (clk_mgr->periodic_retraining_disabled) {
925                                 rn_bw_params.wm_table = lpddr4_wm_table_with_disabled_ppt;
926                         } else {
927                                 if (is_green_sardine)
928                                         rn_bw_params.wm_table = lpddr4_wm_table_gs;
929                                 else
930                                         rn_bw_params.wm_table = lpddr4_wm_table_rn;
931                         }
932                 } else {
933                         if (is_green_sardine)
934                                 rn_bw_params.wm_table = ddr4_wm_table_gs;
935                         else
936                                 rn_bw_params.wm_table = ddr4_wm_table_rn;
937                 }
938                 /* Saved clocks configured at boot for debug purposes */
939                 rn_dump_clk_registers(&clk_mgr->base.boot_snapshot, &clk_mgr->base, &log_info);
940         }
941
942         clk_mgr->base.dprefclk_khz = 600000;
943         dce_clock_read_ss_info(clk_mgr);
944
945
946         clk_mgr->base.bw_params = &rn_bw_params;
947
948         if (pp_smu && pp_smu->rn_funcs.get_dpm_clock_table) {
949                 status = pp_smu->rn_funcs.get_dpm_clock_table(&pp_smu->rn_funcs.pp_smu, &clock_table);
950
951                 if (status == PP_SMU_RESULT_OK &&
952                     ctx->dc_bios && ctx->dc_bios->integrated_info) {
953                         rn_clk_mgr_helper_populate_bw_params (clk_mgr->base.bw_params, &clock_table, ctx->dc_bios->integrated_info);
954                 }
955         }
956
957         if (!IS_FPGA_MAXIMUS_DC(ctx->dce_environment) && clk_mgr->smu_ver >= 0x00371500) {
958                 /* enable powerfeatures when displaycount goes to 0 */
959                 rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(clk_mgr, !debug->disable_48mhz_pwrdwn);
960         }
961 }
962