1 | /* |
2 | * Copyright 2012-16 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 "core_types.h" |
27 | #include "clk_mgr_internal.h" |
28 | |
29 | #include "dce112/dce112_clk_mgr.h" |
30 | #include "dce110/dce110_clk_mgr.h" |
31 | #include "dce120_clk_mgr.h" |
32 | #include "dce100/dce_clk_mgr.h" |
33 | #include "dce120/dce120_hwseq.h" |
34 | |
35 | static const struct state_dependent_clocks dce120_max_clks_by_state[] = { |
36 | /*ClocksStateInvalid - should not be used*/ |
37 | { .display_clk_khz = 0, .pixel_clk_khz = 0 }, |
38 | /*ClocksStateUltraLow - currently by HW design team not supposed to be used*/ |
39 | { .display_clk_khz = 0, .pixel_clk_khz = 0 }, |
40 | /*ClocksStateLow*/ |
41 | { .display_clk_khz = 460000, .pixel_clk_khz = 400000 }, |
42 | /*ClocksStateNominal*/ |
43 | { .display_clk_khz = 670000, .pixel_clk_khz = 600000 }, |
44 | /*ClocksStatePerformance*/ |
45 | { .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } }; |
46 | |
47 | /** |
48 | * dce121_clock_patch_xgmi_ss_info() - Save XGMI spread spectrum info |
49 | * @clk_mgr_dce: clock manager internal structure |
50 | * |
51 | * Reads from VBIOS the XGMI spread spectrum info and saves it within |
52 | * the dce clock manager. This operation will overwrite the existing dprefclk |
53 | * SS values if the vBIOS query succeeds. Otherwise, it does nothing. It also |
54 | * sets the ->xgmi_enabled flag. |
55 | */ |
56 | static void dce121_clock_patch_xgmi_ss_info(struct clk_mgr_internal *clk_mgr_dce) |
57 | { |
58 | enum bp_result result; |
59 | struct spread_spectrum_info info = { { 0 } }; |
60 | struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios; |
61 | |
62 | clk_mgr_dce->xgmi_enabled = false; |
63 | |
64 | result = bp->funcs->get_spread_spectrum_info(bp, AS_SIGNAL_TYPE_XGMI, |
65 | 0, &info); |
66 | if (result == BP_RESULT_OK && info.spread_spectrum_percentage != 0) { |
67 | clk_mgr_dce->xgmi_enabled = true; |
68 | clk_mgr_dce->ss_on_dprefclk = true; |
69 | clk_mgr_dce->dprefclk_ss_divider = |
70 | info.spread_percentage_divider; |
71 | |
72 | if (info.type.CENTER_MODE == 0) { |
73 | /* |
74 | * Currently for DP Reference clock we |
75 | * need only SS percentage for |
76 | * downspread |
77 | */ |
78 | clk_mgr_dce->dprefclk_ss_percentage = |
79 | info.spread_spectrum_percentage; |
80 | } |
81 | } |
82 | } |
83 | |
84 | static void dce12_update_clocks(struct clk_mgr *clk_mgr_base, |
85 | struct dc_state *context, |
86 | bool safe_to_lower) |
87 | { |
88 | struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base); |
89 | struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; |
90 | int max_pix_clk = dce_get_max_pixel_clock_for_all_paths(context); |
91 | int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz; |
92 | |
93 | /*TODO: W/A for dal3 linux, investigate why this works */ |
94 | if (!clk_mgr_dce->dfs_bypass_active) |
95 | patched_disp_clk = patched_disp_clk * 115 / 100; |
96 | |
97 | if (should_set_clock(safe_to_lower, calc_clk: patched_disp_clk, cur_clk: clk_mgr_base->clks.dispclk_khz)) { |
98 | clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; |
99 | /* |
100 | * When xGMI is enabled, the display clk needs to be adjusted |
101 | * with the WAFL link's SS percentage. |
102 | */ |
103 | if (clk_mgr_dce->xgmi_enabled) |
104 | patched_disp_clk = dce_adjust_dp_ref_freq_for_ss( |
105 | clk_mgr_dce, dp_ref_clk_khz: patched_disp_clk); |
106 | clock_voltage_req.clocks_in_khz = patched_disp_clk; |
107 | clk_mgr_base->clks.dispclk_khz = dce112_set_clock(clk_mgr_base, requested_clk_khz: patched_disp_clk); |
108 | |
109 | dm_pp_apply_clock_for_voltage_request(ctx: clk_mgr_base->ctx, clock_for_voltage_req: &clock_voltage_req); |
110 | } |
111 | |
112 | if (should_set_clock(safe_to_lower, calc_clk: max_pix_clk, cur_clk: clk_mgr_base->clks.phyclk_khz)) { |
113 | clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK; |
114 | clock_voltage_req.clocks_in_khz = max_pix_clk; |
115 | clk_mgr_base->clks.phyclk_khz = max_pix_clk; |
116 | |
117 | dm_pp_apply_clock_for_voltage_request(ctx: clk_mgr_base->ctx, clock_for_voltage_req: &clock_voltage_req); |
118 | } |
119 | dce11_pplib_apply_display_requirements(dc: clk_mgr_base->ctx->dc, context); |
120 | } |
121 | |
122 | |
123 | static struct clk_mgr_funcs dce120_funcs = { |
124 | .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, |
125 | .update_clocks = dce12_update_clocks |
126 | }; |
127 | |
128 | void dce120_clk_mgr_construct(struct dc_context *ctx, struct clk_mgr_internal *clk_mgr) |
129 | { |
130 | dce_clk_mgr_construct(ctx, clk_mgr_dce: clk_mgr); |
131 | |
132 | memcpy(clk_mgr->max_clks_by_state, |
133 | dce120_max_clks_by_state, |
134 | sizeof(dce120_max_clks_by_state)); |
135 | |
136 | clk_mgr->base.dprefclk_khz = 600000; |
137 | clk_mgr->base.funcs = &dce120_funcs; |
138 | } |
139 | |
140 | void dce121_clk_mgr_construct(struct dc_context *ctx, struct clk_mgr_internal *clk_mgr) |
141 | { |
142 | dce120_clk_mgr_construct(ctx, clk_mgr); |
143 | clk_mgr->base.dprefclk_khz = 625000; |
144 | |
145 | /* |
146 | * The xGMI enabled info is used to determine if audio and display |
147 | * clocks need to be adjusted with the WAFL link's SS info. |
148 | */ |
149 | if (dce121_xgmi_enabled(hws: ctx->dc->hwseq)) |
150 | dce121_clock_patch_xgmi_ss_info(clk_mgr_dce: clk_mgr); |
151 | |
152 | } |
153 | |
154 | |