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 | #ifndef __DAL_CLK_MGR_INTERNAL_H__ |
27 | #define __DAL_CLK_MGR_INTERNAL_H__ |
28 | |
29 | #include "clk_mgr.h" |
30 | #include "dc.h" |
31 | |
32 | /* |
33 | * only thing needed from here is MEMORY_TYPE_MULTIPLIER_CZ, which is also |
34 | * used in resource, perhaps this should be defined somewhere more common. |
35 | */ |
36 | #include "resource.h" |
37 | |
38 | |
39 | /* Starting DID for each range */ |
40 | enum dentist_base_divider_id { |
41 | DENTIST_BASE_DID_1 = 0x08, |
42 | DENTIST_BASE_DID_2 = 0x40, |
43 | DENTIST_BASE_DID_3 = 0x60, |
44 | DENTIST_BASE_DID_4 = 0x7e, |
45 | DENTIST_MAX_DID = 0x7f |
46 | }; |
47 | |
48 | /* Starting point and step size for each divider range.*/ |
49 | enum dentist_divider_range { |
50 | DENTIST_DIVIDER_RANGE_1_START = 8, /* 2.00 */ |
51 | DENTIST_DIVIDER_RANGE_1_STEP = 1, /* 0.25 */ |
52 | DENTIST_DIVIDER_RANGE_2_START = 64, /* 16.00 */ |
53 | DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */ |
54 | DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */ |
55 | DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */ |
56 | DENTIST_DIVIDER_RANGE_4_START = 248, /* 62.00 */ |
57 | DENTIST_DIVIDER_RANGE_4_STEP = 264, /* 66.00 */ |
58 | DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4 |
59 | }; |
60 | |
61 | /* |
62 | *************************************************************************************** |
63 | ****************** Clock Manager Private Macros and Defines *************************** |
64 | *************************************************************************************** |
65 | */ |
66 | |
67 | /* Macros */ |
68 | |
69 | #define TO_CLK_MGR_INTERNAL(clk_mgr)\ |
70 | container_of(clk_mgr, struct clk_mgr_internal, base) |
71 | |
72 | #define CTX \ |
73 | clk_mgr->base.ctx |
74 | |
75 | #define DC_LOGGER \ |
76 | dc->ctx->logger |
77 | |
78 | |
79 | |
80 | |
81 | #define CLK_BASE(inst) \ |
82 | CLK_BASE_INNER(inst) |
83 | |
84 | #define CLK_SRI(reg_name, block, inst)\ |
85 | .reg_name = CLK_BASE(mm ## block ## _ ## inst ## _ ## reg_name ## _BASE_IDX) + \ |
86 | mm ## block ## _ ## inst ## _ ## reg_name |
87 | |
88 | #define CLK_COMMON_REG_LIST_DCE_BASE() \ |
89 | .DPREFCLK_CNTL = mmDPREFCLK_CNTL, \ |
90 | .DENTIST_DISPCLK_CNTL = mmDENTIST_DISPCLK_CNTL |
91 | |
92 | #if defined(CONFIG_DRM_AMD_DC_SI) |
93 | #define CLK_COMMON_REG_LIST_DCE60_BASE() \ |
94 | SR(DENTIST_DISPCLK_CNTL) |
95 | #endif |
96 | |
97 | #define CLK_COMMON_REG_LIST_DCN_BASE() \ |
98 | SR(DENTIST_DISPCLK_CNTL) |
99 | |
100 | #define VBIOS_SMU_MSG_BOX_REG_LIST_RV() \ |
101 | .MP1_SMN_C2PMSG_91 = mmMP1_SMN_C2PMSG_91, \ |
102 | .MP1_SMN_C2PMSG_83 = mmMP1_SMN_C2PMSG_83, \ |
103 | .MP1_SMN_C2PMSG_67 = mmMP1_SMN_C2PMSG_67 |
104 | |
105 | #define CLK_COMMON_REG_LIST_DCN_201() \ |
106 | SR(DENTIST_DISPCLK_CNTL), \ |
107 | CLK_SRI(CLK4_CLK_PLL_REQ, CLK4, 0), \ |
108 | CLK_SRI(CLK4_CLK2_CURRENT_CNT, CLK4, 0) |
109 | |
110 | #define CLK_REG_LIST_NV10() \ |
111 | SR(DENTIST_DISPCLK_CNTL), \ |
112 | CLK_SRI(CLK3_CLK_PLL_REQ, CLK3, 0), \ |
113 | CLK_SRI(CLK3_CLK2_DFS_CNTL, CLK3, 0) |
114 | |
115 | #define CLK_REG_LIST_DCN3() \ |
116 | CLK_COMMON_REG_LIST_DCN_BASE(), \ |
117 | CLK_SRI(CLK0_CLK_PLL_REQ, CLK02, 0), \ |
118 | CLK_SRI(CLK0_CLK2_DFS_CNTL, CLK02, 0) |
119 | |
120 | #define CLK_SF(reg_name, field_name, post_fix)\ |
121 | .field_name = reg_name ## __ ## field_name ## post_fix |
122 | |
123 | #define CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh) \ |
124 | CLK_SF(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, mask_sh), \ |
125 | CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, mask_sh) |
126 | |
127 | #if defined(CONFIG_DRM_AMD_DC_SI) |
128 | #define CLK_COMMON_MASK_SH_LIST_DCE60_COMMON_BASE(mask_sh) \ |
129 | CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh),\ |
130 | CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, mask_sh) |
131 | #endif |
132 | |
133 | #define CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \ |
134 | CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh),\ |
135 | CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, mask_sh) |
136 | |
137 | #define CLK_MASK_SH_LIST_RV1(mask_sh) \ |
138 | CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh),\ |
139 | CLK_SF(MP1_SMN_C2PMSG_67, CONTENT, mask_sh),\ |
140 | CLK_SF(MP1_SMN_C2PMSG_83, CONTENT, mask_sh),\ |
141 | CLK_SF(MP1_SMN_C2PMSG_91, CONTENT, mask_sh), |
142 | |
143 | #define CLK_COMMON_MASK_SH_LIST_DCN20_BASE(mask_sh) \ |
144 | CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh),\ |
145 | CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, mask_sh),\ |
146 | CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, mask_sh) |
147 | |
148 | #define CLK_MASK_SH_LIST_NV10(mask_sh) \ |
149 | CLK_COMMON_MASK_SH_LIST_DCN20_BASE(mask_sh),\ |
150 | CLK_SF(CLK3_0_CLK3_CLK_PLL_REQ, FbMult_int, mask_sh),\ |
151 | CLK_SF(CLK3_0_CLK3_CLK_PLL_REQ, FbMult_frac, mask_sh) |
152 | |
153 | #define CLK_COMMON_MASK_SH_LIST_DCN201_BASE(mask_sh) \ |
154 | CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh),\ |
155 | CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, mask_sh),\ |
156 | CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, mask_sh),\ |
157 | CLK_SF(CLK4_0_CLK4_CLK_PLL_REQ, FbMult_int, mask_sh) |
158 | |
159 | #define CLK_REG_LIST_DCN32() \ |
160 | SR(DENTIST_DISPCLK_CNTL), \ |
161 | CLK_SR_DCN32(CLK1_CLK_PLL_REQ), \ |
162 | CLK_SR_DCN32(CLK1_CLK0_DFS_CNTL), \ |
163 | CLK_SR_DCN32(CLK1_CLK1_DFS_CNTL), \ |
164 | CLK_SR_DCN32(CLK1_CLK2_DFS_CNTL), \ |
165 | CLK_SR_DCN32(CLK1_CLK3_DFS_CNTL), \ |
166 | CLK_SR_DCN32(CLK1_CLK4_DFS_CNTL), \ |
167 | CLK_SR_DCN32(CLK1_CLK0_CURRENT_CNT), \ |
168 | CLK_SR_DCN32(CLK1_CLK1_CURRENT_CNT), \ |
169 | CLK_SR_DCN32(CLK1_CLK2_CURRENT_CNT), \ |
170 | CLK_SR_DCN32(CLK1_CLK3_CURRENT_CNT), \ |
171 | CLK_SR_DCN32(CLK1_CLK4_CURRENT_CNT), \ |
172 | CLK_SR_DCN32(CLK4_CLK0_CURRENT_CNT) |
173 | |
174 | #define CLK_COMMON_MASK_SH_LIST_DCN32(mask_sh) \ |
175 | CLK_COMMON_MASK_SH_LIST_DCN20_BASE(mask_sh),\ |
176 | CLK_SF(CLK1_CLK_PLL_REQ, FbMult_int, mask_sh),\ |
177 | CLK_SF(CLK1_CLK_PLL_REQ, FbMult_frac, mask_sh) |
178 | |
179 | #define CLK_REG_LIST_DCN321() \ |
180 | SR(DENTIST_DISPCLK_CNTL), \ |
181 | CLK_SR_DCN321(CLK0_CLK_PLL_REQ, CLK01, 0), \ |
182 | CLK_SR_DCN321(CLK0_CLK0_DFS_CNTL, CLK01, 0), \ |
183 | CLK_SR_DCN321(CLK0_CLK1_DFS_CNTL, CLK01, 0), \ |
184 | CLK_SR_DCN321(CLK0_CLK2_DFS_CNTL, CLK01, 0), \ |
185 | CLK_SR_DCN321(CLK0_CLK3_DFS_CNTL, CLK01, 0), \ |
186 | CLK_SR_DCN321(CLK0_CLK4_DFS_CNTL, CLK01, 0) |
187 | |
188 | #define CLK_COMMON_MASK_SH_LIST_DCN321(mask_sh) \ |
189 | CLK_COMMON_MASK_SH_LIST_DCN20_BASE(mask_sh),\ |
190 | CLK_SF(CLK0_CLK_PLL_REQ, FbMult_int, mask_sh),\ |
191 | CLK_SF(CLK0_CLK_PLL_REQ, FbMult_frac, mask_sh) |
192 | |
193 | #define CLK_REG_FIELD_LIST(type) \ |
194 | type DPREFCLK_SRC_SEL; \ |
195 | type DENTIST_DPREFCLK_WDIVIDER; \ |
196 | type DENTIST_DISPCLK_WDIVIDER; \ |
197 | type DENTIST_DISPCLK_CHG_DONE; |
198 | |
199 | /* |
200 | *************************************************************************************** |
201 | ****************** Clock Manager Private Structures *********************************** |
202 | *************************************************************************************** |
203 | */ |
204 | #define CLK20_REG_FIELD_LIST(type) \ |
205 | type DENTIST_DPPCLK_WDIVIDER; \ |
206 | type DENTIST_DPPCLK_CHG_DONE; \ |
207 | type FbMult_int; \ |
208 | type FbMult_frac; |
209 | |
210 | #define VBIOS_SMU_REG_FIELD_LIST(type) \ |
211 | type CONTENT; |
212 | |
213 | struct clk_mgr_shift { |
214 | CLK_REG_FIELD_LIST(uint8_t) |
215 | CLK20_REG_FIELD_LIST(uint8_t) |
216 | VBIOS_SMU_REG_FIELD_LIST(uint32_t) |
217 | }; |
218 | |
219 | struct clk_mgr_mask { |
220 | CLK_REG_FIELD_LIST(uint32_t) |
221 | CLK20_REG_FIELD_LIST(uint32_t) |
222 | VBIOS_SMU_REG_FIELD_LIST(uint32_t) |
223 | }; |
224 | |
225 | struct clk_mgr_registers { |
226 | uint32_t DPREFCLK_CNTL; |
227 | uint32_t DENTIST_DISPCLK_CNTL; |
228 | uint32_t CLK4_CLK2_CURRENT_CNT; |
229 | uint32_t CLK4_CLK_PLL_REQ; |
230 | |
231 | uint32_t CLK4_CLK0_CURRENT_CNT; |
232 | |
233 | uint32_t CLK3_CLK2_DFS_CNTL; |
234 | uint32_t CLK3_CLK_PLL_REQ; |
235 | |
236 | uint32_t CLK0_CLK2_DFS_CNTL; |
237 | uint32_t CLK0_CLK_PLL_REQ; |
238 | |
239 | uint32_t CLK1_CLK_PLL_REQ; |
240 | uint32_t CLK1_CLK0_DFS_CNTL; |
241 | uint32_t CLK1_CLK1_DFS_CNTL; |
242 | uint32_t CLK1_CLK2_DFS_CNTL; |
243 | uint32_t CLK1_CLK3_DFS_CNTL; |
244 | uint32_t CLK1_CLK4_DFS_CNTL; |
245 | |
246 | uint32_t CLK1_CLK0_CURRENT_CNT; |
247 | uint32_t CLK1_CLK1_CURRENT_CNT; |
248 | uint32_t CLK1_CLK2_CURRENT_CNT; |
249 | uint32_t CLK1_CLK3_CURRENT_CNT; |
250 | uint32_t CLK1_CLK4_CURRENT_CNT; |
251 | |
252 | uint32_t CLK0_CLK0_DFS_CNTL; |
253 | uint32_t CLK0_CLK1_DFS_CNTL; |
254 | uint32_t CLK0_CLK3_DFS_CNTL; |
255 | uint32_t CLK0_CLK4_DFS_CNTL; |
256 | |
257 | uint32_t MP1_SMN_C2PMSG_67; |
258 | uint32_t MP1_SMN_C2PMSG_83; |
259 | uint32_t MP1_SMN_C2PMSG_91; |
260 | }; |
261 | |
262 | enum clock_type { |
263 | clock_type_dispclk = 1, |
264 | clock_type_dcfclk, |
265 | clock_type_socclk, |
266 | clock_type_pixelclk, |
267 | clock_type_phyclk, |
268 | clock_type_dppclk, |
269 | clock_type_fclk, |
270 | clock_type_dcfdsclk, |
271 | clock_type_dscclk, |
272 | clock_type_uclk, |
273 | clock_type_dramclk, |
274 | }; |
275 | |
276 | |
277 | struct state_dependent_clocks { |
278 | int display_clk_khz; |
279 | int pixel_clk_khz; |
280 | }; |
281 | |
282 | struct clk_mgr_internal { |
283 | struct clk_mgr base; |
284 | int smu_ver; |
285 | struct pp_smu_funcs *pp_smu; |
286 | struct clk_mgr_internal_funcs *funcs; |
287 | |
288 | struct dccg *dccg; |
289 | |
290 | /* |
291 | * For backwards compatbility with previous implementation |
292 | * TODO: remove these after everything transitions to new pattern |
293 | * Rationale is that clk registers change a lot across DCE versions |
294 | * and a shared data structure doesn't really make sense. |
295 | */ |
296 | const struct clk_mgr_registers *regs; |
297 | const struct clk_mgr_shift *clk_mgr_shift; |
298 | const struct clk_mgr_mask *clk_mgr_mask; |
299 | |
300 | struct state_dependent_clocks max_clks_by_state[DM_PP_CLOCKS_MAX_STATES]; |
301 | |
302 | /*TODO: figure out which of the below fields should be here vs in asic specific portion */ |
303 | /* Cache the status of DFS-bypass feature*/ |
304 | bool dfs_bypass_enabled; |
305 | /* True if the DFS-bypass feature is enabled and active. */ |
306 | bool dfs_bypass_active; |
307 | |
308 | uint32_t dfs_ref_freq_khz; |
309 | /* |
310 | * Cache the display clock returned by VBIOS if DFS-bypass is enabled. |
311 | * This is basically "Crystal Frequency In KHz" (XTALIN) frequency |
312 | */ |
313 | int dfs_bypass_disp_clk; |
314 | |
315 | /** |
316 | * @ss_on_dprefclk: |
317 | * |
318 | * True if spread spectrum is enabled on the DP ref clock. |
319 | */ |
320 | bool ss_on_dprefclk; |
321 | |
322 | /** |
323 | * @xgmi_enabled: |
324 | * |
325 | * True if xGMI is enabled. On VG20, both audio and display clocks need |
326 | * to be adjusted with the WAFL link's SS info if xGMI is enabled. |
327 | */ |
328 | bool xgmi_enabled; |
329 | |
330 | /** |
331 | * @dprefclk_ss_percentage: |
332 | * |
333 | * DPREFCLK SS percentage (if down-spread enabled). |
334 | * |
335 | * Note that if XGMI is enabled, the SS info (percentage and divider) |
336 | * from the WAFL link is used instead. This is decided during |
337 | * dce_clk_mgr initialization. |
338 | */ |
339 | int dprefclk_ss_percentage; |
340 | |
341 | /** |
342 | * @dprefclk_ss_divider: |
343 | * |
344 | * DPREFCLK SS percentage Divider (100 or 1000). |
345 | */ |
346 | int dprefclk_ss_divider; |
347 | |
348 | enum dm_pp_clocks_state max_clks_state; |
349 | enum dm_pp_clocks_state cur_min_clks_state; |
350 | bool periodic_retraining_disabled; |
351 | |
352 | unsigned int cur_phyclk_req_table[MAX_PIPES * 2]; |
353 | |
354 | bool smu_present; |
355 | void *wm_range_table; |
356 | long long wm_range_table_addr; |
357 | |
358 | bool dpm_present; |
359 | bool pme_trigger_pending; |
360 | }; |
361 | |
362 | struct clk_mgr_internal_funcs { |
363 | int (*set_dispclk)(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz); |
364 | int (*set_dprefclk)(struct clk_mgr_internal *clk_mgr); |
365 | }; |
366 | |
367 | |
368 | /* |
369 | *************************************************************************************** |
370 | ****************** Clock Manager Level Helper functions ******************************* |
371 | *************************************************************************************** |
372 | */ |
373 | |
374 | |
375 | static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_clk) |
376 | { |
377 | return ((safe_to_lower && calc_clk < cur_clk) || calc_clk > cur_clk); |
378 | } |
379 | |
380 | static inline bool should_update_pstate_support(bool safe_to_lower, bool calc_support, bool cur_support) |
381 | { |
382 | if (cur_support != calc_support) { |
383 | if (calc_support && safe_to_lower) |
384 | return true; |
385 | else if (!calc_support && !safe_to_lower) |
386 | return true; |
387 | } |
388 | |
389 | return false; |
390 | } |
391 | |
392 | static inline int khz_to_mhz_ceil(int khz) |
393 | { |
394 | return (khz + 999) / 1000; |
395 | } |
396 | |
397 | static inline int khz_to_mhz_floor(int khz) |
398 | { |
399 | return khz / 1000; |
400 | } |
401 | |
402 | int clk_mgr_helper_get_active_display_cnt( |
403 | struct dc *dc, |
404 | struct dc_state *context); |
405 | |
406 | int clk_mgr_helper_get_active_plane_cnt( |
407 | struct dc *dc, |
408 | struct dc_state *context); |
409 | |
410 | |
411 | |
412 | #endif //__DAL_CLK_MGR_INTERNAL_H__ |
413 | |