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 <linux/slab.h> 27 28 #include "reg_helper.h" 29 #include "core_types.h" 30 #include "clk_mgr_internal.h" 31 #include "rv1_clk_mgr.h" 32 #include "dce100/dce_clk_mgr.h" 33 #include "dce112/dce112_clk_mgr.h" 34 #include "rv1_clk_mgr_vbios_smu.h" 35 #include "rv1_clk_mgr_clk.h" 36 37 void rv1_init_clocks(struct clk_mgr *clk_mgr) 38 { 39 memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks)); 40 } 41 42 static int rv1_determine_dppclk_threshold(struct clk_mgr_internal *clk_mgr, struct dc_clocks *new_clocks) 43 { 44 bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; 45 bool dispclk_increase = new_clocks->dispclk_khz > clk_mgr->base.clks.dispclk_khz; 46 int disp_clk_threshold = new_clocks->max_supported_dppclk_khz; 47 bool cur_dpp_div = clk_mgr->base.clks.dispclk_khz > clk_mgr->base.clks.dppclk_khz; 48 49 /* increase clock, looking for div is 0 for current, request div is 1*/ 50 if (dispclk_increase) { 51 /* already divided by 2, no need to reach target clk with 2 steps*/ 52 if (cur_dpp_div) 53 return new_clocks->dispclk_khz; 54 55 /* request disp clk is lower than maximum supported dpp clk, 56 * no need to reach target clk with two steps. 57 */ 58 if (new_clocks->dispclk_khz <= disp_clk_threshold) 59 return new_clocks->dispclk_khz; 60 61 /* target dpp clk not request divided by 2, still within threshold */ 62 if (!request_dpp_div) 63 return new_clocks->dispclk_khz; 64 65 } else { 66 /* decrease clock, looking for current dppclk divided by 2, 67 * request dppclk not divided by 2. 68 */ 69 70 /* current dpp clk not divided by 2, no need to ramp*/ 71 if (!cur_dpp_div) 72 return new_clocks->dispclk_khz; 73 74 /* current disp clk is lower than current maximum dpp clk, 75 * no need to ramp 76 */ 77 if (clk_mgr->base.clks.dispclk_khz <= disp_clk_threshold) 78 return new_clocks->dispclk_khz; 79 80 /* request dpp clk need to be divided by 2 */ 81 if (request_dpp_div) 82 return new_clocks->dispclk_khz; 83 } 84 85 return disp_clk_threshold; 86 } 87 88 static void ramp_up_dispclk_with_dpp(struct clk_mgr_internal *clk_mgr, struct dc *dc, struct dc_clocks *new_clocks) 89 { 90 int i; 91 int dispclk_to_dpp_threshold = rv1_determine_dppclk_threshold(clk_mgr, new_clocks); 92 bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; 93 94 /* set disp clk to dpp clk threshold */ 95 96 clk_mgr->funcs->set_dispclk(clk_mgr, dispclk_to_dpp_threshold); 97 clk_mgr->funcs->set_dprefclk(clk_mgr); 98 99 100 /* update request dpp clk division option */ 101 for (i = 0; i < dc->res_pool->pipe_count; i++) { 102 struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 103 104 if (!pipe_ctx->plane_state) 105 continue; 106 107 pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control( 108 pipe_ctx->plane_res.dpp, 109 request_dpp_div, 110 true); 111 } 112 113 /* If target clk not same as dppclk threshold, set to target clock */ 114 if (dispclk_to_dpp_threshold != new_clocks->dispclk_khz) { 115 clk_mgr->funcs->set_dispclk(clk_mgr, new_clocks->dispclk_khz); 116 clk_mgr->funcs->set_dprefclk(clk_mgr); 117 } 118 119 120 clk_mgr->base.clks.dispclk_khz = new_clocks->dispclk_khz; 121 clk_mgr->base.clks.dppclk_khz = new_clocks->dppclk_khz; 122 clk_mgr->base.clks.max_supported_dppclk_khz = new_clocks->max_supported_dppclk_khz; 123 } 124 125 static void rv1_update_clocks(struct clk_mgr *clk_mgr_base, 126 struct dc_state *context, 127 bool safe_to_lower) 128 { 129 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 130 struct dc *dc = clk_mgr_base->ctx->dc; 131 struct dc_debug_options *debug = &dc->debug; 132 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; 133 struct pp_smu_funcs_rv *pp_smu = NULL; 134 bool send_request_to_increase = false; 135 bool send_request_to_lower = false; 136 int display_count; 137 138 bool enter_display_off = false; 139 140 ASSERT(clk_mgr->pp_smu); 141 142 pp_smu = &clk_mgr->pp_smu->rv_funcs; 143 144 display_count = clk_mgr_helper_get_active_display_cnt(dc, context); 145 146 if (display_count == 0) 147 enter_display_off = true; 148 149 if (enter_display_off == safe_to_lower) { 150 /* 151 * Notify SMU active displays 152 * if function pointer not set up, this message is 153 * sent as part of pplib_apply_display_requirements. 154 */ 155 if (pp_smu->set_display_count) 156 pp_smu->set_display_count(&pp_smu->pp_smu, display_count); 157 } 158 159 if (new_clocks->dispclk_khz > clk_mgr_base->clks.dispclk_khz 160 || new_clocks->phyclk_khz > clk_mgr_base->clks.phyclk_khz 161 || new_clocks->fclk_khz > clk_mgr_base->clks.fclk_khz 162 || new_clocks->dcfclk_khz > clk_mgr_base->clks.dcfclk_khz) 163 send_request_to_increase = true; 164 165 if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr_base->clks.phyclk_khz)) { 166 clk_mgr_base->clks.phyclk_khz = new_clocks->phyclk_khz; 167 send_request_to_lower = true; 168 } 169 170 // F Clock 171 if (debug->force_fclk_khz != 0) 172 new_clocks->fclk_khz = debug->force_fclk_khz; 173 174 if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, clk_mgr_base->clks.fclk_khz)) { 175 clk_mgr_base->clks.fclk_khz = new_clocks->fclk_khz; 176 send_request_to_lower = true; 177 } 178 179 //DCF Clock 180 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { 181 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; 182 send_request_to_lower = true; 183 } 184 185 if (should_set_clock(safe_to_lower, 186 new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { 187 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 188 send_request_to_lower = true; 189 } 190 191 /* make sure dcf clk is before dpp clk to 192 * make sure we have enough voltage to run dpp clk 193 */ 194 if (send_request_to_increase) { 195 /*use dcfclk to request voltage*/ 196 if (pp_smu->set_hard_min_fclk_by_freq && 197 pp_smu->set_hard_min_dcfclk_by_freq && 198 pp_smu->set_min_deep_sleep_dcfclk) { 199 pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, new_clocks->fclk_khz / 1000); 200 pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, new_clocks->dcfclk_khz / 1000); 201 pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, (new_clocks->dcfclk_deep_sleep_khz + 999) / 1000); 202 } 203 } 204 205 /* dcn1 dppclk is tied to dispclk */ 206 /* program dispclk on = as a w/a for sleep resume clock ramping issues */ 207 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) 208 || new_clocks->dispclk_khz == clk_mgr_base->clks.dispclk_khz) { 209 ramp_up_dispclk_with_dpp(clk_mgr, dc, new_clocks); 210 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; 211 send_request_to_lower = true; 212 } 213 214 if (!send_request_to_increase && send_request_to_lower) { 215 /*use dcfclk to request voltage*/ 216 if (pp_smu->set_hard_min_fclk_by_freq && 217 pp_smu->set_hard_min_dcfclk_by_freq && 218 pp_smu->set_min_deep_sleep_dcfclk) { 219 pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, new_clocks->fclk_khz / 1000); 220 pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, new_clocks->dcfclk_khz / 1000); 221 pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, (new_clocks->dcfclk_deep_sleep_khz + 999) / 1000); 222 } 223 } 224 } 225 226 static void rv1_enable_pme_wa(struct clk_mgr *clk_mgr_base) 227 { 228 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 229 struct pp_smu_funcs_rv *pp_smu = NULL; 230 231 if (clk_mgr->pp_smu) { 232 pp_smu = &clk_mgr->pp_smu->rv_funcs; 233 234 if (pp_smu->set_pme_wa_enable) 235 pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); 236 } 237 } 238 239 static struct clk_mgr_funcs rv1_clk_funcs = { 240 .init_clocks = rv1_init_clocks, 241 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, 242 .update_clocks = rv1_update_clocks, 243 .enable_pme_wa = rv1_enable_pme_wa, 244 }; 245 246 static struct clk_mgr_internal_funcs rv1_clk_internal_funcs = { 247 .set_dispclk = rv1_vbios_smu_set_dispclk, 248 .set_dprefclk = dce112_set_dprefclk 249 }; 250 251 void rv1_clk_mgr_construct(struct dc_context *ctx, struct clk_mgr_internal *clk_mgr, struct pp_smu_funcs *pp_smu) 252 { 253 struct dc_debug_options *debug = &ctx->dc->debug; 254 struct dc_bios *bp = ctx->dc_bios; 255 256 clk_mgr->base.ctx = ctx; 257 clk_mgr->pp_smu = pp_smu; 258 clk_mgr->base.funcs = &rv1_clk_funcs; 259 clk_mgr->funcs = &rv1_clk_internal_funcs; 260 261 clk_mgr->dfs_bypass_disp_clk = 0; 262 263 clk_mgr->dprefclk_ss_percentage = 0; 264 clk_mgr->dprefclk_ss_divider = 1000; 265 clk_mgr->ss_on_dprefclk = false; 266 clk_mgr->base.dprefclk_khz = 600000; 267 268 if (bp->integrated_info) 269 clk_mgr->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq; 270 if (bp->fw_info_valid && clk_mgr->dentist_vco_freq_khz == 0) { 271 clk_mgr->dentist_vco_freq_khz = bp->fw_info.smu_gpu_pll_output_freq; 272 if (clk_mgr->dentist_vco_freq_khz == 0) 273 clk_mgr->dentist_vco_freq_khz = 3600000; 274 } 275 276 if (!debug->disable_dfs_bypass && bp->integrated_info) 277 if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) 278 clk_mgr->dfs_bypass_enabled = true; 279 280 dce_clock_read_ss_info(clk_mgr); 281 } 282 283 284