File: | dev/pci/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c |
Warning: | line 392, column 3 Value stored to 'remaining_buffer' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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_LATENCY4.977 4.977 /* Number obtained from LPDDR4 Training Counter Requirement doc */ |
49 | #define SMU_VER_55_51_00x373300 0x373300 /* SMU Version that is able to set DISPCLK below 100MHz */ |
50 | |
51 | /* Macros */ |
52 | |
53 | #define REG(reg_name)(CLK_BASE.instance[0].segment[mmreg_name_BASE_IDX] + mmreg_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_Bool tmds_present = false0; |
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 | /* Extend the WA to DP for Linux*/ |
70 | if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || |
71 | stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK || |
72 | stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK || |
73 | stream->signal == SIGNAL_TYPE_DISPLAY_PORT) |
74 | tmds_present = true1; |
75 | } |
76 | |
77 | for (i = 0; i < dc->link_count; i++) { |
78 | const struct dc_link *link = dc->links[i]; |
79 | |
80 | /* |
81 | * Only notify active stream or virtual stream. |
82 | * Need to notify virtual stream to work around |
83 | * headless case. HPD does not fire when system is in |
84 | * S0i2. |
85 | */ |
86 | /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */ |
87 | if (link->connector_signal == SIGNAL_TYPE_VIRTUAL || |
88 | link->link_enc->funcs->is_dig_enabled(link->link_enc)) |
89 | display_count++; |
90 | } |
91 | |
92 | /* WA for hang on HDMI after display off back back on*/ |
93 | if (display_count == 0 && tmds_present) |
94 | display_count = 1; |
95 | |
96 | return display_count; |
97 | } |
98 | |
99 | void rn_set_low_power_state(struct clk_mgr *clk_mgr_base) |
100 | { |
101 | struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base)({ const __typeof( ((struct clk_mgr_internal *)0)->base ) * __mptr = (clk_mgr_base); (struct clk_mgr_internal *)( (char * )__mptr - __builtin_offsetof(struct clk_mgr_internal, base) ) ;}); |
102 | |
103 | rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_LOW_POWER); |
104 | /* update power state */ |
105 | clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; |
106 | } |
107 | |
108 | void rn_update_clocks(struct clk_mgr *clk_mgr_base, |
109 | struct dc_state *context, |
110 | bool_Bool safe_to_lower) |
111 | { |
112 | struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base)({ const __typeof( ((struct clk_mgr_internal *)0)->base ) * __mptr = (clk_mgr_base); (struct clk_mgr_internal *)( (char * )__mptr - __builtin_offsetof(struct clk_mgr_internal, base) ) ;}); |
113 | struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; |
114 | struct dc *dc = clk_mgr_base->ctx->dc; |
115 | int display_count; |
116 | bool_Bool update_dppclk = false0; |
117 | bool_Bool update_dispclk = false0; |
118 | bool_Bool dpp_clock_lowered = false0; |
119 | |
120 | struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu; |
121 | |
122 | if (dc->work_arounds.skip_clock_update) |
123 | return; |
124 | |
125 | /* |
126 | * if it is safe to lower, but we are already in the lower state, we don't have to do anything |
127 | * also if safe to lower is false, we just go in the higher state |
128 | */ |
129 | if (safe_to_lower) { |
130 | /* check that we're not already in lower */ |
131 | if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { |
132 | |
133 | display_count = rn_get_active_display_cnt_wa(dc, context); |
134 | /* if we can go lower, go lower */ |
135 | if (display_count == 0) { |
136 | rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_LOW_POWER); |
137 | /* update power state */ |
138 | clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; |
139 | } |
140 | } |
141 | } else { |
142 | /* check that we're not already in D0 */ |
143 | if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) { |
144 | rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_MISSION_MODE); |
145 | /* update power state */ |
146 | clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE; |
147 | } |
148 | } |
149 | |
150 | if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { |
151 | clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; |
152 | rn_vbios_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz); |
153 | } |
154 | |
155 | if (should_set_clock(safe_to_lower, |
156 | new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { |
157 | clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; |
158 | rn_vbios_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz); |
159 | } |
160 | |
161 | // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow. |
162 | // Do not adjust dppclk if dppclk is 0 to avoid unexpected result |
163 | if (!IS_DIAG_DC(dc->ctx->dce_environment)((dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS) || ( dc->ctx->dce_environment == DCE_ENV_DIAG))) { |
164 | if (new_clocks->dppclk_khz < 100000 && new_clocks->dppclk_khz > 0) |
165 | new_clocks->dppclk_khz = 100000; |
166 | } |
167 | |
168 | /* |
169 | * Temporally ignore thew 0 cases for disp and dpp clks. |
170 | * We may have a new feature that requires 0 clks in the future. |
171 | */ |
172 | if (new_clocks->dppclk_khz == 0 || new_clocks->dispclk_khz == 0) { |
173 | new_clocks->dppclk_khz = clk_mgr_base->clks.dppclk_khz; |
174 | new_clocks->dispclk_khz = clk_mgr_base->clks.dispclk_khz; |
175 | } |
176 | |
177 | if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr_base->clks.dppclk_khz)) { |
178 | if (clk_mgr_base->clks.dppclk_khz > new_clocks->dppclk_khz) |
179 | dpp_clock_lowered = true1; |
180 | clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz; |
181 | update_dppclk = true1; |
182 | } |
183 | |
184 | if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { |
185 | clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; |
186 | rn_vbios_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); |
187 | |
188 | update_dispclk = true1; |
189 | } |
190 | |
191 | if (dpp_clock_lowered) { |
192 | // increase per DPP DTO before lowering global dppclk |
193 | dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); |
194 | rn_vbios_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); |
195 | } else { |
196 | // increase global DPPCLK before lowering per DPP DTO |
197 | if (update_dppclk || update_dispclk) |
198 | rn_vbios_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); |
199 | // always update dtos unless clock is lowered and not safe to lower |
200 | if (new_clocks->dppclk_khz >= dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz) |
201 | dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); |
202 | } |
203 | |
204 | if (update_dispclk && |
205 | dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { |
206 | /*update dmcu for wait_loop count*/ |
207 | dmcu->funcs->set_psr_wait_loop(dmcu, |
208 | clk_mgr_base->clks.dispclk_khz / 1000 / 7); |
209 | } |
210 | } |
211 | |
212 | |
213 | static int get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr) |
214 | { |
215 | /* get FbMult value */ |
216 | struct fixed31_32 pll_req; |
217 | unsigned int fbmult_frac_val = 0; |
218 | unsigned int fbmult_int_val = 0; |
219 | |
220 | |
221 | /* |
222 | * Register value of fbmult is in 8.16 format, we are converting to 31.32 |
223 | * to leverage the fix point operations available in driver |
224 | */ |
225 | |
226 | REG_GET(CLK1_CLK_PLL_REQ, FbMult_frac, &fbmult_frac_val)generic_reg_get(clk_mgr->base.ctx, (CLK_BASE.instance[0].segment [1] + 0x000f), 0x10, 0xFFFF0000L, &fbmult_frac_val); /* 16 bit fractional part*/ |
227 | REG_GET(CLK1_CLK_PLL_REQ, FbMult_int, &fbmult_int_val)generic_reg_get(clk_mgr->base.ctx, (CLK_BASE.instance[0].segment [1] + 0x000f), 0x0, 0x000001FFL, &fbmult_int_val); /* 8 bit integer part */ |
228 | |
229 | pll_req = dc_fixpt_from_int(fbmult_int_val); |
230 | |
231 | /* |
232 | * since fractional part is only 16 bit in register definition but is 32 bit |
233 | * in our fix point definiton, need to shift left by 16 to obtain correct value |
234 | */ |
235 | pll_req.value |= fbmult_frac_val << 16; |
236 | |
237 | /* multiply by REFCLK period */ |
238 | pll_req = dc_fixpt_mul_int(pll_req, clk_mgr->dfs_ref_freq_khz); |
239 | |
240 | /* integer part is now VCO frequency in kHz */ |
241 | return dc_fixpt_floor(pll_req); |
242 | } |
243 | |
244 | static void rn_dump_clk_registers_internal(struct rn_clk_internal *internal, struct clk_mgr *clk_mgr_base) |
245 | { |
246 | struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base)({ const __typeof( ((struct clk_mgr_internal *)0)->base ) * __mptr = (clk_mgr_base); (struct clk_mgr_internal *)( (char * )__mptr - __builtin_offsetof(struct clk_mgr_internal, base) ) ;}); |
247 | |
248 | internal->CLK1_CLK3_CURRENT_CNT = REG_READ(CLK1_CLK3_CURRENT_CNT)dm_read_reg_func(clk_mgr->base.ctx, (CLK_BASE.instance[0]. segment[1] + 0x008d), __func__); |
249 | internal->CLK1_CLK3_BYPASS_CNTL = REG_READ(CLK1_CLK3_BYPASS_CNTL)dm_read_reg_func(clk_mgr->base.ctx, (CLK_BASE.instance[0]. segment[1] + 0x0067), __func__); |
250 | |
251 | internal->CLK1_CLK3_DS_CNTL = REG_READ(CLK1_CLK3_DS_CNTL)dm_read_reg_func(clk_mgr->base.ctx, (CLK_BASE.instance[0]. segment[1] + 0x0060), __func__); //dcf deep sleep divider |
252 | internal->CLK1_CLK3_ALLOW_DS = REG_READ(CLK1_CLK3_ALLOW_DS)dm_read_reg_func(clk_mgr->base.ctx, (CLK_BASE.instance[0]. segment[1] + 0x0061), __func__); |
253 | |
254 | internal->CLK1_CLK1_CURRENT_CNT = REG_READ(CLK1_CLK1_CURRENT_CNT)dm_read_reg_func(clk_mgr->base.ctx, (CLK_BASE.instance[0]. segment[1] + 0x008b), __func__); |
255 | internal->CLK1_CLK1_BYPASS_CNTL = REG_READ(CLK1_CLK1_BYPASS_CNTL)dm_read_reg_func(clk_mgr->base.ctx, (CLK_BASE.instance[0]. segment[1] + 0x0053), __func__); |
256 | |
257 | internal->CLK1_CLK2_CURRENT_CNT = REG_READ(CLK1_CLK2_CURRENT_CNT)dm_read_reg_func(clk_mgr->base.ctx, (CLK_BASE.instance[0]. segment[1] + 0x008c), __func__); |
258 | internal->CLK1_CLK2_BYPASS_CNTL = REG_READ(CLK1_CLK2_BYPASS_CNTL)dm_read_reg_func(clk_mgr->base.ctx, (CLK_BASE.instance[0]. segment[1] + 0x005d), __func__); |
259 | |
260 | internal->CLK1_CLK0_CURRENT_CNT = REG_READ(CLK1_CLK0_CURRENT_CNT)dm_read_reg_func(clk_mgr->base.ctx, (CLK_BASE.instance[0]. segment[1] + 0x008a), __func__); |
261 | internal->CLK1_CLK0_BYPASS_CNTL = REG_READ(CLK1_CLK0_BYPASS_CNTL)dm_read_reg_func(clk_mgr->base.ctx, (CLK_BASE.instance[0]. segment[1] + 0x0049), __func__); |
262 | } |
263 | |
264 | /* This function collect raw clk register values */ |
265 | static void rn_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, |
266 | struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info) |
267 | { |
268 | struct rn_clk_internal internal = {0}; |
269 | char *bypass_clks[5] = {"0x0 DFS", "0x1 REFCLK", "0x2 ERROR", "0x3 400 FCH", "0x4 600 FCH"}; |
270 | unsigned int chars_printed = 0; |
271 | unsigned int remaining_buffer = log_info->bufSize; |
272 | |
273 | rn_dump_clk_registers_internal(&internal, clk_mgr_base); |
274 | |
275 | regs_and_bypass->dcfclk = internal.CLK1_CLK3_CURRENT_CNT / 10; |
276 | regs_and_bypass->dcf_deep_sleep_divider = internal.CLK1_CLK3_DS_CNTL / 10; |
277 | regs_and_bypass->dcf_deep_sleep_allow = internal.CLK1_CLK3_ALLOW_DS; |
278 | regs_and_bypass->dprefclk = internal.CLK1_CLK2_CURRENT_CNT / 10; |
279 | regs_and_bypass->dispclk = internal.CLK1_CLK0_CURRENT_CNT / 10; |
280 | regs_and_bypass->dppclk = internal.CLK1_CLK1_CURRENT_CNT / 10; |
281 | |
282 | regs_and_bypass->dppclk_bypass = internal.CLK1_CLK1_BYPASS_CNTL & 0x0007; |
283 | if (regs_and_bypass->dppclk_bypass < 0 || regs_and_bypass->dppclk_bypass > 4) |
284 | regs_and_bypass->dppclk_bypass = 0; |
285 | regs_and_bypass->dcfclk_bypass = internal.CLK1_CLK3_BYPASS_CNTL & 0x0007; |
286 | if (regs_and_bypass->dcfclk_bypass < 0 || regs_and_bypass->dcfclk_bypass > 4) |
287 | regs_and_bypass->dcfclk_bypass = 0; |
288 | regs_and_bypass->dispclk_bypass = internal.CLK1_CLK0_BYPASS_CNTL & 0x0007; |
289 | if (regs_and_bypass->dispclk_bypass < 0 || regs_and_bypass->dispclk_bypass > 4) |
290 | regs_and_bypass->dispclk_bypass = 0; |
291 | regs_and_bypass->dprefclk_bypass = internal.CLK1_CLK2_BYPASS_CNTL & 0x0007; |
292 | if (regs_and_bypass->dprefclk_bypass < 0 || regs_and_bypass->dprefclk_bypass > 4) |
293 | regs_and_bypass->dprefclk_bypass = 0; |
294 | |
295 | if (log_info->enabled) { |
296 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "clk_type,clk_value,deepsleep_cntl,deepsleep_allow,bypass\n"); |
297 | remaining_buffer -= chars_printed; |
298 | *log_info->sum_chars_printed += chars_printed; |
299 | log_info->pBuf += chars_printed; |
300 | |
301 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "dcfclk,%d,%d,%d,%s\n", |
302 | regs_and_bypass->dcfclk, |
303 | regs_and_bypass->dcf_deep_sleep_divider, |
304 | regs_and_bypass->dcf_deep_sleep_allow, |
305 | bypass_clks[(int) regs_and_bypass->dcfclk_bypass]); |
306 | remaining_buffer -= chars_printed; |
307 | *log_info->sum_chars_printed += chars_printed; |
308 | log_info->pBuf += chars_printed; |
309 | |
310 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "dprefclk,%d,N/A,N/A,%s\n", |
311 | regs_and_bypass->dprefclk, |
312 | bypass_clks[(int) regs_and_bypass->dprefclk_bypass]); |
313 | remaining_buffer -= chars_printed; |
314 | *log_info->sum_chars_printed += chars_printed; |
315 | log_info->pBuf += chars_printed; |
316 | |
317 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "dispclk,%d,N/A,N/A,%s\n", |
318 | regs_and_bypass->dispclk, |
319 | bypass_clks[(int) regs_and_bypass->dispclk_bypass]); |
320 | remaining_buffer -= chars_printed; |
321 | *log_info->sum_chars_printed += chars_printed; |
322 | log_info->pBuf += chars_printed; |
323 | |
324 | //split |
325 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "SPLIT\n"); |
326 | remaining_buffer -= chars_printed; |
327 | *log_info->sum_chars_printed += chars_printed; |
328 | log_info->pBuf += chars_printed; |
329 | |
330 | // REGISTER VALUES |
331 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "reg_name,value,clk_type\n"); |
332 | remaining_buffer -= chars_printed; |
333 | *log_info->sum_chars_printed += chars_printed; |
334 | log_info->pBuf += chars_printed; |
335 | |
336 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK3_CURRENT_CNT,%d,dcfclk\n", |
337 | internal.CLK1_CLK3_CURRENT_CNT); |
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, "CLK1_CLK3_DS_CNTL,%d,dcf_deep_sleep_divider\n", |
343 | internal.CLK1_CLK3_DS_CNTL); |
344 | remaining_buffer -= chars_printed; |
345 | *log_info->sum_chars_printed += chars_printed; |
346 | log_info->pBuf += chars_printed; |
347 | |
348 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK3_ALLOW_DS,%d,dcf_deep_sleep_allow\n", |
349 | internal.CLK1_CLK3_ALLOW_DS); |
350 | remaining_buffer -= chars_printed; |
351 | *log_info->sum_chars_printed += chars_printed; |
352 | log_info->pBuf += chars_printed; |
353 | |
354 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK2_CURRENT_CNT,%d,dprefclk\n", |
355 | internal.CLK1_CLK2_CURRENT_CNT); |
356 | remaining_buffer -= chars_printed; |
357 | *log_info->sum_chars_printed += chars_printed; |
358 | log_info->pBuf += chars_printed; |
359 | |
360 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK0_CURRENT_CNT,%d,dispclk\n", |
361 | internal.CLK1_CLK0_CURRENT_CNT); |
362 | remaining_buffer -= chars_printed; |
363 | *log_info->sum_chars_printed += chars_printed; |
364 | log_info->pBuf += chars_printed; |
365 | |
366 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK1_CURRENT_CNT,%d,dppclk\n", |
367 | internal.CLK1_CLK1_CURRENT_CNT); |
368 | remaining_buffer -= chars_printed; |
369 | *log_info->sum_chars_printed += chars_printed; |
370 | log_info->pBuf += chars_printed; |
371 | |
372 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK3_BYPASS_CNTL,%d,dcfclk_bypass\n", |
373 | internal.CLK1_CLK3_BYPASS_CNTL); |
374 | remaining_buffer -= chars_printed; |
375 | *log_info->sum_chars_printed += chars_printed; |
376 | log_info->pBuf += chars_printed; |
377 | |
378 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK2_BYPASS_CNTL,%d,dprefclk_bypass\n", |
379 | internal.CLK1_CLK2_BYPASS_CNTL); |
380 | remaining_buffer -= chars_printed; |
381 | *log_info->sum_chars_printed += chars_printed; |
382 | log_info->pBuf += chars_printed; |
383 | |
384 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK0_BYPASS_CNTL,%d,dispclk_bypass\n", |
385 | internal.CLK1_CLK0_BYPASS_CNTL); |
386 | remaining_buffer -= chars_printed; |
387 | *log_info->sum_chars_printed += chars_printed; |
388 | log_info->pBuf += chars_printed; |
389 | |
390 | chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK1_BYPASS_CNTL,%d,dppclk_bypass\n", |
391 | internal.CLK1_CLK1_BYPASS_CNTL); |
392 | remaining_buffer -= chars_printed; |
Value stored to 'remaining_buffer' is never read | |
393 | *log_info->sum_chars_printed += chars_printed; |
394 | log_info->pBuf += chars_printed; |
395 | } |
396 | } |
397 | |
398 | /* This function produce translated logical clk state values*/ |
399 | void rn_get_clk_states(struct clk_mgr *clk_mgr_base, struct clk_states *s) |
400 | { |
401 | struct clk_state_registers_and_bypass sb = { 0 }; |
402 | struct clk_log_info log_info = { 0 }; |
403 | |
404 | rn_dump_clk_registers(&sb, clk_mgr_base, &log_info); |
405 | |
406 | s->dprefclk_khz = sb.dprefclk * 1000; |
407 | } |
408 | |
409 | void rn_enable_pme_wa(struct clk_mgr *clk_mgr_base) |
410 | { |
411 | struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base)({ const __typeof( ((struct clk_mgr_internal *)0)->base ) * __mptr = (clk_mgr_base); (struct clk_mgr_internal *)( (char * )__mptr - __builtin_offsetof(struct clk_mgr_internal, base) ) ;}); |
412 | |
413 | rn_vbios_smu_enable_pme_wa(clk_mgr); |
414 | } |
415 | |
416 | void rn_init_clocks(struct clk_mgr *clk_mgr) |
417 | { |
418 | memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks))__builtin_memset((&(clk_mgr->clks)), (0), (sizeof(struct dc_clocks))); |
419 | // Assumption is that boot state always supports pstate |
420 | clk_mgr->clks.p_state_change_support = true1; |
421 | clk_mgr->clks.prev_p_state_change_support = true1; |
422 | clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN; |
423 | } |
424 | |
425 | static void build_watermark_ranges(struct clk_bw_params *bw_params, struct pp_smu_wm_range_sets *ranges) |
426 | { |
427 | int i, num_valid_sets; |
428 | |
429 | num_valid_sets = 0; |
430 | |
431 | for (i = 0; i < WM_SET_COUNT4; i++) { |
432 | /* skip empty entries, the smu array has no holes*/ |
433 | if (!bw_params->wm_table.entries[i].valid) |
434 | continue; |
435 | |
436 | ranges->reader_wm_sets[num_valid_sets].wm_inst = bw_params->wm_table.entries[i].wm_inst; |
437 | ranges->reader_wm_sets[num_valid_sets].wm_type = bw_params->wm_table.entries[i].wm_type; |
438 | /* We will not select WM based on fclk, so leave it as unconstrained */ |
439 | ranges->reader_wm_sets[num_valid_sets].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN0x0; |
440 | ranges->reader_wm_sets[num_valid_sets].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX0xFFFF; |
441 | /* dcfclk wil be used to select WM*/ |
442 | |
443 | if (ranges->reader_wm_sets[num_valid_sets].wm_type == WM_TYPE_PSTATE_CHG) { |
444 | if (i == 0) |
445 | ranges->reader_wm_sets[num_valid_sets].min_drain_clk_mhz = 0; |
446 | else { |
447 | /* add 1 to make it non-overlapping with next lvl */ |
448 | ranges->reader_wm_sets[num_valid_sets].min_drain_clk_mhz = bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1; |
449 | } |
450 | ranges->reader_wm_sets[num_valid_sets].max_drain_clk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz; |
451 | |
452 | } else { |
453 | /* unconstrained for memory retraining */ |
454 | ranges->reader_wm_sets[num_valid_sets].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN0x0; |
455 | ranges->reader_wm_sets[num_valid_sets].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX0xFFFF; |
456 | |
457 | /* Modify previous watermark range to cover up to max */ |
458 | ranges->reader_wm_sets[num_valid_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX0xFFFF; |
459 | } |
460 | num_valid_sets++; |
461 | } |
462 | |
463 | ASSERT(num_valid_sets != 0)do { if (({ static int __warned; int __ret = !!(!(num_valid_sets != 0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(num_valid_sets != 0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c" , 463); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); /* Must have at least one set of valid watermarks */ |
464 | ranges->num_reader_wm_sets = num_valid_sets; |
465 | |
466 | /* modify the min and max to make sure we cover the whole range*/ |
467 | ranges->reader_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN0x0; |
468 | ranges->reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN0x0; |
469 | ranges->reader_wm_sets[ranges->num_reader_wm_sets - 1].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX0xFFFF; |
470 | ranges->reader_wm_sets[ranges->num_reader_wm_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX0xFFFF; |
471 | |
472 | /* This is for writeback only, does not matter currently as no writeback support*/ |
473 | ranges->num_writer_wm_sets = 1; |
474 | ranges->writer_wm_sets[0].wm_inst = WM_A0; |
475 | ranges->writer_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN0x0; |
476 | ranges->writer_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX0xFFFF; |
477 | ranges->writer_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN0x0; |
478 | ranges->writer_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX0xFFFF; |
479 | |
480 | } |
481 | |
482 | static void rn_notify_wm_ranges(struct clk_mgr *clk_mgr_base) |
483 | { |
484 | struct dc_debug_options *debug = &clk_mgr_base->ctx->dc->debug; |
485 | struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base)({ const __typeof( ((struct clk_mgr_internal *)0)->base ) * __mptr = (clk_mgr_base); (struct clk_mgr_internal *)( (char * )__mptr - __builtin_offsetof(struct clk_mgr_internal, base) ) ;}); |
486 | struct pp_smu_funcs *pp_smu = clk_mgr->pp_smu; |
487 | |
488 | if (!debug->disable_pplib_wm_range) { |
489 | build_watermark_ranges(clk_mgr_base->bw_params, &clk_mgr_base->ranges); |
490 | |
491 | /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ |
492 | if (pp_smu && pp_smu->rn_funcs.set_wm_ranges) |
493 | pp_smu->rn_funcs.set_wm_ranges(&pp_smu->rn_funcs.pp_smu, &clk_mgr_base->ranges); |
494 | } |
495 | |
496 | } |
497 | |
498 | static bool_Bool rn_are_clock_states_equal(struct dc_clocks *a, |
499 | struct dc_clocks *b) |
500 | { |
501 | if (a->dispclk_khz != b->dispclk_khz) |
502 | return false0; |
503 | else if (a->dppclk_khz != b->dppclk_khz) |
504 | return false0; |
505 | else if (a->dcfclk_khz != b->dcfclk_khz) |
506 | return false0; |
507 | else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz) |
508 | return false0; |
509 | |
510 | return true1; |
511 | } |
512 | |
513 | |
514 | /* Notify clk_mgr of a change in link rate, update phyclk frequency if necessary */ |
515 | static void rn_notify_link_rate_change(struct clk_mgr *clk_mgr_base, struct dc_link *link) |
516 | { |
517 | struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base)({ const __typeof( ((struct clk_mgr_internal *)0)->base ) * __mptr = (clk_mgr_base); (struct clk_mgr_internal *)( (char * )__mptr - __builtin_offsetof(struct clk_mgr_internal, base) ) ;}); |
518 | unsigned int i, max_phyclk_req = 0; |
519 | |
520 | clk_mgr->cur_phyclk_req_table[link->link_index] = link->cur_link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ; |
521 | |
522 | for (i = 0; i < MAX_PIPES6 * 2; i++) { |
523 | if (clk_mgr->cur_phyclk_req_table[i] > max_phyclk_req) |
524 | max_phyclk_req = clk_mgr->cur_phyclk_req_table[i]; |
525 | } |
526 | |
527 | if (max_phyclk_req != clk_mgr_base->clks.phyclk_khz) { |
528 | clk_mgr_base->clks.phyclk_khz = max_phyclk_req; |
529 | rn_vbios_smu_set_phyclk(clk_mgr, clk_mgr_base->clks.phyclk_khz); |
530 | } |
531 | } |
532 | |
533 | static struct clk_mgr_funcs dcn21_funcs = { |
534 | .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, |
535 | .update_clocks = rn_update_clocks, |
536 | .init_clocks = rn_init_clocks, |
537 | .enable_pme_wa = rn_enable_pme_wa, |
538 | .are_clock_states_equal = rn_are_clock_states_equal, |
539 | .set_low_power_state = rn_set_low_power_state, |
540 | .notify_wm_ranges = rn_notify_wm_ranges, |
541 | .notify_link_rate_change = rn_notify_link_rate_change, |
542 | }; |
543 | |
544 | static struct clk_bw_params rn_bw_params = { |
545 | .vram_type = Ddr4MemType, |
546 | .num_channels = 1, |
547 | .clk_table = { |
548 | .entries = { |
549 | { |
550 | .voltage = 0, |
551 | .dcfclk_mhz = 400, |
552 | .fclk_mhz = 400, |
553 | .memclk_mhz = 800, |
554 | .socclk_mhz = 0, |
555 | }, |
556 | { |
557 | .voltage = 0, |
558 | .dcfclk_mhz = 483, |
559 | .fclk_mhz = 800, |
560 | .memclk_mhz = 1600, |
561 | .socclk_mhz = 0, |
562 | }, |
563 | { |
564 | .voltage = 0, |
565 | .dcfclk_mhz = 602, |
566 | .fclk_mhz = 1067, |
567 | .memclk_mhz = 1067, |
568 | .socclk_mhz = 0, |
569 | }, |
570 | { |
571 | .voltage = 0, |
572 | .dcfclk_mhz = 738, |
573 | .fclk_mhz = 1333, |
574 | .memclk_mhz = 1600, |
575 | .socclk_mhz = 0, |
576 | }, |
577 | }, |
578 | |
579 | .num_entries = 4, |
580 | }, |
581 | |
582 | }; |
583 | |
584 | static struct wm_table ddr4_wm_table_gs = { |
585 | .entries = { |
586 | { |
587 | .wm_inst = WM_A0, |
588 | .wm_type = WM_TYPE_PSTATE_CHG, |
589 | .pstate_latency_us = 11.72, |
590 | .sr_exit_time_us = 6.09, |
591 | .sr_enter_plus_exit_time_us = 7.14, |
592 | .valid = true1, |
593 | }, |
594 | { |
595 | .wm_inst = WM_B1, |
596 | .wm_type = WM_TYPE_PSTATE_CHG, |
597 | .pstate_latency_us = 11.72, |
598 | .sr_exit_time_us = 10.12, |
599 | .sr_enter_plus_exit_time_us = 11.48, |
600 | .valid = true1, |
601 | }, |
602 | { |
603 | .wm_inst = WM_C2, |
604 | .wm_type = WM_TYPE_PSTATE_CHG, |
605 | .pstate_latency_us = 11.72, |
606 | .sr_exit_time_us = 10.12, |
607 | .sr_enter_plus_exit_time_us = 11.48, |
608 | .valid = true1, |
609 | }, |
610 | { |
611 | .wm_inst = WM_D3, |
612 | .wm_type = WM_TYPE_PSTATE_CHG, |
613 | .pstate_latency_us = 11.72, |
614 | .sr_exit_time_us = 10.12, |
615 | .sr_enter_plus_exit_time_us = 11.48, |
616 | .valid = true1, |
617 | }, |
618 | } |
619 | }; |
620 | |
621 | static struct wm_table lpddr4_wm_table_gs = { |
622 | .entries = { |
623 | { |
624 | .wm_inst = WM_A0, |
625 | .wm_type = WM_TYPE_PSTATE_CHG, |
626 | .pstate_latency_us = 11.65333, |
627 | .sr_exit_time_us = 5.32, |
628 | .sr_enter_plus_exit_time_us = 6.38, |
629 | .valid = true1, |
630 | }, |
631 | { |
632 | .wm_inst = WM_B1, |
633 | .wm_type = WM_TYPE_PSTATE_CHG, |
634 | .pstate_latency_us = 11.65333, |
635 | .sr_exit_time_us = 9.82, |
636 | .sr_enter_plus_exit_time_us = 11.196, |
637 | .valid = true1, |
638 | }, |
639 | { |
640 | .wm_inst = WM_C2, |
641 | .wm_type = WM_TYPE_PSTATE_CHG, |
642 | .pstate_latency_us = 11.65333, |
643 | .sr_exit_time_us = 9.89, |
644 | .sr_enter_plus_exit_time_us = 11.24, |
645 | .valid = true1, |
646 | }, |
647 | { |
648 | .wm_inst = WM_D3, |
649 | .wm_type = WM_TYPE_PSTATE_CHG, |
650 | .pstate_latency_us = 11.65333, |
651 | .sr_exit_time_us = 9.748, |
652 | .sr_enter_plus_exit_time_us = 11.102, |
653 | .valid = true1, |
654 | }, |
655 | } |
656 | }; |
657 | |
658 | static struct wm_table lpddr4_wm_table_with_disabled_ppt = { |
659 | .entries = { |
660 | { |
661 | .wm_inst = WM_A0, |
662 | .wm_type = WM_TYPE_PSTATE_CHG, |
663 | .pstate_latency_us = 11.65333, |
664 | .sr_exit_time_us = 8.32, |
665 | .sr_enter_plus_exit_time_us = 9.38, |
666 | .valid = true1, |
667 | }, |
668 | { |
669 | .wm_inst = WM_B1, |
670 | .wm_type = WM_TYPE_PSTATE_CHG, |
671 | .pstate_latency_us = 11.65333, |
672 | .sr_exit_time_us = 9.82, |
673 | .sr_enter_plus_exit_time_us = 11.196, |
674 | .valid = true1, |
675 | }, |
676 | { |
677 | .wm_inst = WM_C2, |
678 | .wm_type = WM_TYPE_PSTATE_CHG, |
679 | .pstate_latency_us = 11.65333, |
680 | .sr_exit_time_us = 9.89, |
681 | .sr_enter_plus_exit_time_us = 11.24, |
682 | .valid = true1, |
683 | }, |
684 | { |
685 | .wm_inst = WM_D3, |
686 | .wm_type = WM_TYPE_PSTATE_CHG, |
687 | .pstate_latency_us = 11.65333, |
688 | .sr_exit_time_us = 9.748, |
689 | .sr_enter_plus_exit_time_us = 11.102, |
690 | .valid = true1, |
691 | }, |
692 | } |
693 | }; |
694 | |
695 | static struct wm_table ddr4_wm_table_rn = { |
696 | .entries = { |
697 | { |
698 | .wm_inst = WM_A0, |
699 | .wm_type = WM_TYPE_PSTATE_CHG, |
700 | .pstate_latency_us = 11.72, |
701 | .sr_exit_time_us = 9.09, |
702 | .sr_enter_plus_exit_time_us = 10.14, |
703 | .valid = true1, |
704 | }, |
705 | { |
706 | .wm_inst = WM_B1, |
707 | .wm_type = WM_TYPE_PSTATE_CHG, |
708 | .pstate_latency_us = 11.72, |
709 | .sr_exit_time_us = 11.12, |
710 | .sr_enter_plus_exit_time_us = 12.48, |
711 | .valid = true1, |
712 | }, |
713 | { |
714 | .wm_inst = WM_C2, |
715 | .wm_type = WM_TYPE_PSTATE_CHG, |
716 | .pstate_latency_us = 11.72, |
717 | .sr_exit_time_us = 11.12, |
718 | .sr_enter_plus_exit_time_us = 12.48, |
719 | .valid = true1, |
720 | }, |
721 | { |
722 | .wm_inst = WM_D3, |
723 | .wm_type = WM_TYPE_PSTATE_CHG, |
724 | .pstate_latency_us = 11.72, |
725 | .sr_exit_time_us = 11.12, |
726 | .sr_enter_plus_exit_time_us = 12.48, |
727 | .valid = true1, |
728 | }, |
729 | } |
730 | }; |
731 | |
732 | static struct wm_table lpddr4_wm_table_rn = { |
733 | .entries = { |
734 | { |
735 | .wm_inst = WM_A0, |
736 | .wm_type = WM_TYPE_PSTATE_CHG, |
737 | .pstate_latency_us = 11.65333, |
738 | .sr_exit_time_us = 7.32, |
739 | .sr_enter_plus_exit_time_us = 8.38, |
740 | .valid = true1, |
741 | }, |
742 | { |
743 | .wm_inst = WM_B1, |
744 | .wm_type = WM_TYPE_PSTATE_CHG, |
745 | .pstate_latency_us = 11.65333, |
746 | .sr_exit_time_us = 9.82, |
747 | .sr_enter_plus_exit_time_us = 11.196, |
748 | .valid = true1, |
749 | }, |
750 | { |
751 | .wm_inst = WM_C2, |
752 | .wm_type = WM_TYPE_PSTATE_CHG, |
753 | .pstate_latency_us = 11.65333, |
754 | .sr_exit_time_us = 9.89, |
755 | .sr_enter_plus_exit_time_us = 11.24, |
756 | .valid = true1, |
757 | }, |
758 | { |
759 | .wm_inst = WM_D3, |
760 | .wm_type = WM_TYPE_PSTATE_CHG, |
761 | .pstate_latency_us = 11.65333, |
762 | .sr_exit_time_us = 9.748, |
763 | .sr_enter_plus_exit_time_us = 11.102, |
764 | .valid = true1, |
765 | }, |
766 | } |
767 | }; |
768 | |
769 | static unsigned int find_dcfclk_for_voltage(struct dpm_clocks *clock_table, unsigned int voltage) |
770 | { |
771 | int i; |
772 | |
773 | for (i = 0; i < PP_SMU_NUM_DCFCLK_DPM_LEVELS8; i++) { |
774 | if (clock_table->DcfClocks[i].Vol == voltage) |
775 | return clock_table->DcfClocks[i].Freq; |
776 | } |
777 | |
778 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c" , 778); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
779 | return 0; |
780 | } |
781 | |
782 | 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) |
783 | { |
784 | int i, j = 0; |
785 | |
786 | j = -1; |
787 | |
788 | ASSERT(PP_SMU_NUM_FCLK_DPM_LEVELS <= MAX_NUM_DPM_LVL)do { if (({ static int __warned; int __ret = !!(!(4 <= 8)) ; if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(4 <= 8)", "/usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c" , 788); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
789 | |
790 | /* Find lowest DPM, FCLK is filled in reverse order*/ |
791 | |
792 | for (i = PP_SMU_NUM_FCLK_DPM_LEVELS4 - 1; i >= 0; i--) { |
793 | if (clock_table->FClocks[i].Freq != 0 && clock_table->FClocks[i].Vol != 0) { |
794 | j = i; |
795 | break; |
796 | } |
797 | } |
798 | |
799 | if (j == -1) { |
800 | /* clock table is all 0s, just use our own hardcode */ |
801 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c" , 801); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
802 | return; |
803 | } |
804 | |
805 | bw_params->clk_table.num_entries = j + 1; |
806 | |
807 | for (i = 0; i < bw_params->clk_table.num_entries; i++, j--) { |
808 | bw_params->clk_table.entries[i].fclk_mhz = clock_table->FClocks[j].Freq; |
809 | bw_params->clk_table.entries[i].memclk_mhz = clock_table->MemClocks[j].Freq; |
810 | bw_params->clk_table.entries[i].voltage = clock_table->FClocks[j].Vol; |
811 | bw_params->clk_table.entries[i].dcfclk_mhz = find_dcfclk_for_voltage(clock_table, clock_table->FClocks[j].Vol); |
812 | } |
813 | |
814 | bw_params->vram_type = bios_info->memory_type; |
815 | bw_params->num_channels = bios_info->ma_channel_number; |
816 | |
817 | for (i = 0; i < WM_SET_COUNT4; i++) { |
818 | bw_params->wm_table.entries[i].wm_inst = i; |
819 | |
820 | if (i >= bw_params->clk_table.num_entries) { |
821 | bw_params->wm_table.entries[i].valid = false0; |
822 | continue; |
823 | } |
824 | |
825 | bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG; |
826 | bw_params->wm_table.entries[i].valid = true1; |
827 | } |
828 | |
829 | if (bw_params->vram_type == LpDdr4MemType) { |
830 | /* |
831 | * WM set D will be re-purposed for memory retraining |
832 | */ |
833 | bw_params->wm_table.entries[WM_D3].pstate_latency_us = LPDDR_MEM_RETRAIN_LATENCY4.977; |
834 | bw_params->wm_table.entries[WM_D3].wm_inst = WM_D3; |
835 | bw_params->wm_table.entries[WM_D3].wm_type = WM_TYPE_RETRAINING; |
836 | bw_params->wm_table.entries[WM_D3].valid = true1; |
837 | } |
838 | |
839 | } |
840 | |
841 | void rn_clk_mgr_construct( |
842 | struct dc_context *ctx, |
843 | struct clk_mgr_internal *clk_mgr, |
844 | struct pp_smu_funcs *pp_smu, |
845 | struct dccg *dccg) |
846 | { |
847 | struct dc_debug_options *debug = &ctx->dc->debug; |
848 | struct dpm_clocks clock_table = { 0 }; |
849 | enum pp_smu_status status = 0; |
850 | int is_green_sardine = 0; |
851 | |
852 | #if defined(CONFIG_DRM_AMD_DC_DCN1) |
853 | is_green_sardine = ASICREV_IS_GREEN_SARDINE(ctx->asic_id.hw_internal_rev)((ctx->asic_id.hw_internal_rev >= 0xA1) && (ctx ->asic_id.hw_internal_rev < 0xFF)); |
854 | #endif |
855 | |
856 | clk_mgr->base.ctx = ctx; |
857 | clk_mgr->base.funcs = &dcn21_funcs; |
858 | |
859 | clk_mgr->pp_smu = pp_smu; |
860 | |
861 | clk_mgr->dccg = dccg; |
862 | clk_mgr->dfs_bypass_disp_clk = 0; |
863 | |
864 | clk_mgr->dprefclk_ss_percentage = 0; |
865 | clk_mgr->dprefclk_ss_divider = 1000; |
866 | clk_mgr->ss_on_dprefclk = false0; |
867 | clk_mgr->dfs_ref_freq_khz = 48000; |
868 | |
869 | clk_mgr->smu_ver = rn_vbios_smu_get_smu_version(clk_mgr); |
870 | |
871 | if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)(ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS)) { |
872 | dcn21_funcs.update_clocks = dcn2_update_clocks_fpga; |
873 | clk_mgr->base.dentist_vco_freq_khz = 3600000; |
874 | } else { |
875 | struct clk_log_info log_info = {0}; |
876 | |
877 | clk_mgr->periodic_retraining_disabled = rn_vbios_smu_is_periodic_retraining_disabled(clk_mgr); |
878 | |
879 | /* SMU Version 55.51.0 and up no longer have an issue |
880 | * that needs to limit minimum dispclk */ |
881 | if (clk_mgr->smu_ver >= SMU_VER_55_51_00x373300) |
882 | debug->min_disp_clk_khz = 0; |
883 | |
884 | /* TODO: Check we get what we expect during bringup */ |
885 | clk_mgr->base.dentist_vco_freq_khz = get_vco_frequency_from_reg(clk_mgr); |
886 | |
887 | /* in case we don't get a value from the register, use default */ |
888 | if (clk_mgr->base.dentist_vco_freq_khz == 0) |
889 | clk_mgr->base.dentist_vco_freq_khz = 3600000; |
890 | |
891 | if (ctx->dc_bios->integrated_info->memory_type == LpDdr4MemType) { |
892 | if (clk_mgr->periodic_retraining_disabled) { |
893 | rn_bw_params.wm_table = lpddr4_wm_table_with_disabled_ppt; |
894 | } else { |
895 | if (is_green_sardine) |
896 | rn_bw_params.wm_table = lpddr4_wm_table_gs; |
897 | else |
898 | rn_bw_params.wm_table = lpddr4_wm_table_rn; |
899 | } |
900 | } else { |
901 | if (is_green_sardine) |
902 | rn_bw_params.wm_table = ddr4_wm_table_gs; |
903 | else |
904 | rn_bw_params.wm_table = ddr4_wm_table_rn; |
905 | } |
906 | /* Saved clocks configured at boot for debug purposes */ |
907 | rn_dump_clk_registers(&clk_mgr->base.boot_snapshot, &clk_mgr->base, &log_info); |
908 | } |
909 | |
910 | clk_mgr->base.dprefclk_khz = 600000; |
911 | dce_clock_read_ss_info(clk_mgr); |
912 | |
913 | |
914 | clk_mgr->base.bw_params = &rn_bw_params; |
915 | |
916 | if (pp_smu && pp_smu->rn_funcs.get_dpm_clock_table) { |
917 | status = pp_smu->rn_funcs.get_dpm_clock_table(&pp_smu->rn_funcs.pp_smu, &clock_table); |
918 | |
919 | if (status == PP_SMU_RESULT_OK && |
920 | ctx->dc_bios && ctx->dc_bios->integrated_info) { |
921 | rn_clk_mgr_helper_populate_bw_params (clk_mgr->base.bw_params, &clock_table, ctx->dc_bios->integrated_info); |
922 | } |
923 | } |
924 | |
925 | if (!IS_FPGA_MAXIMUS_DC(ctx->dce_environment)(ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS) && clk_mgr->smu_ver >= 0x00371500) { |
926 | /* enable powerfeatures when displaycount goes to 0 */ |
927 | rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(clk_mgr, !debug->disable_48mhz_pwrdwn); |
928 | } |
929 | } |
930 |