1f9490399SQingqing Zhuo /* 2f9490399SQingqing Zhuo * Copyright 2021 Advanced Micro Devices, Inc. 3f9490399SQingqing Zhuo * 4f9490399SQingqing Zhuo * Permission is hereby granted, free of charge, to any person obtaining a 5f9490399SQingqing Zhuo * copy of this software and associated documentation files (the "Software"), 6f9490399SQingqing Zhuo * to deal in the Software without restriction, including without limitation 7f9490399SQingqing Zhuo * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8f9490399SQingqing Zhuo * and/or sell copies of the Software, and to permit persons to whom the 9f9490399SQingqing Zhuo * Software is furnished to do so, subject to the following conditions: 10f9490399SQingqing Zhuo * 11f9490399SQingqing Zhuo * The above copyright notice and this permission notice shall be included in 12f9490399SQingqing Zhuo * all copies or substantial portions of the Software. 13f9490399SQingqing Zhuo * 14f9490399SQingqing Zhuo * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15f9490399SQingqing Zhuo * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16f9490399SQingqing Zhuo * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17f9490399SQingqing Zhuo * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18f9490399SQingqing Zhuo * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19f9490399SQingqing Zhuo * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20f9490399SQingqing Zhuo * OTHER DEALINGS IN THE SOFTWARE. 21f9490399SQingqing Zhuo * 22f9490399SQingqing Zhuo * Authors: AMD 23f9490399SQingqing Zhuo * 24f9490399SQingqing Zhuo */ 25f9490399SQingqing Zhuo 26f9490399SQingqing Zhuo 27f9490399SQingqing Zhuo 28f9490399SQingqing Zhuo #include "dccg.h" 29f9490399SQingqing Zhuo #include "clk_mgr_internal.h" 30f9490399SQingqing Zhuo 31f9490399SQingqing Zhuo // For dce12_get_dp_ref_freq_khz 32f9490399SQingqing Zhuo #include "dce100/dce_clk_mgr.h" 33f9490399SQingqing Zhuo // For dcn20_update_clocks_update_dpp_dto 34f9490399SQingqing Zhuo #include "dcn20/dcn20_clk_mgr.h" 35f9490399SQingqing Zhuo #include "dcn31/dcn31_clk_mgr.h" 36f9490399SQingqing Zhuo #include "dcn315_clk_mgr.h" 37f9490399SQingqing Zhuo 38f9490399SQingqing Zhuo #include "core_types.h" 39f9490399SQingqing Zhuo #include "dcn315_smu.h" 40f9490399SQingqing Zhuo #include "dm_helpers.h" 41f9490399SQingqing Zhuo 42f9490399SQingqing Zhuo #include "dc_dmub_srv.h" 43f9490399SQingqing Zhuo 44c8b1d0feSLeo Chen #include "logger_types.h" 45c8b1d0feSLeo Chen #undef DC_LOGGER 46c8b1d0feSLeo Chen #define DC_LOGGER \ 47c8b1d0feSLeo Chen clk_mgr->base.base.ctx->logger 48c8b1d0feSLeo Chen 49f9490399SQingqing Zhuo #include "dc_link_dp.h" 50f9490399SQingqing Zhuo 51f9490399SQingqing Zhuo #define TO_CLK_MGR_DCN315(clk_mgr)\ 52f9490399SQingqing Zhuo container_of(clk_mgr, struct clk_mgr_dcn315, base) 53f9490399SQingqing Zhuo 54f9490399SQingqing Zhuo static int dcn315_get_active_display_cnt_wa( 55f9490399SQingqing Zhuo struct dc *dc, 56f9490399SQingqing Zhuo struct dc_state *context) 57f9490399SQingqing Zhuo { 58f9490399SQingqing Zhuo int i, display_count; 59f9490399SQingqing Zhuo bool tmds_present = false; 60f9490399SQingqing Zhuo 61f9490399SQingqing Zhuo display_count = 0; 62f9490399SQingqing Zhuo for (i = 0; i < context->stream_count; i++) { 63f9490399SQingqing Zhuo const struct dc_stream_state *stream = context->streams[i]; 64f9490399SQingqing Zhuo 65f9490399SQingqing Zhuo if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || 66f9490399SQingqing Zhuo stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK || 67f9490399SQingqing Zhuo stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) 68f9490399SQingqing Zhuo tmds_present = true; 69f9490399SQingqing Zhuo } 70f9490399SQingqing Zhuo 71f9490399SQingqing Zhuo for (i = 0; i < dc->link_count; i++) { 72f9490399SQingqing Zhuo const struct dc_link *link = dc->links[i]; 73f9490399SQingqing Zhuo 74f9490399SQingqing Zhuo /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */ 75f9490399SQingqing Zhuo if (link->link_enc && link->link_enc->funcs->is_dig_enabled && 76f9490399SQingqing Zhuo link->link_enc->funcs->is_dig_enabled(link->link_enc)) 77f9490399SQingqing Zhuo display_count++; 78f9490399SQingqing Zhuo } 79f9490399SQingqing Zhuo 80f9490399SQingqing Zhuo /* WA for hang on HDMI after display off back back on*/ 81f9490399SQingqing Zhuo if (display_count == 0 && tmds_present) 82f9490399SQingqing Zhuo display_count = 1; 83f9490399SQingqing Zhuo 84f9490399SQingqing Zhuo return display_count; 85f9490399SQingqing Zhuo } 86f9490399SQingqing Zhuo 87*abffd871SMeenakshikumar Somasundaram static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable) 88f9490399SQingqing Zhuo { 89f9490399SQingqing Zhuo struct dc *dc = clk_mgr_base->ctx->dc; 90f9490399SQingqing Zhuo int i; 91f9490399SQingqing Zhuo 92f9490399SQingqing Zhuo for (i = 0; i < dc->res_pool->pipe_count; ++i) { 93165ab7b4SNicholas Kazlauskas struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; 94f9490399SQingqing Zhuo 95f9490399SQingqing Zhuo if (pipe->top_pipe || pipe->prev_odm_pipe) 96f9490399SQingqing Zhuo continue; 9766a19720SNicholas Kazlauskas if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL || 9866a19720SNicholas Kazlauskas dc_is_virtual_signal(pipe->stream->signal))) { 99*abffd871SMeenakshikumar Somasundaram if (disable) { 100f9490399SQingqing Zhuo pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); 101*abffd871SMeenakshikumar Somasundaram reset_sync_context_for_pipe(dc, context, i); 102*abffd871SMeenakshikumar Somasundaram } else 103f9490399SQingqing Zhuo pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); 104f9490399SQingqing Zhuo } 105f9490399SQingqing Zhuo } 106f9490399SQingqing Zhuo } 107f9490399SQingqing Zhuo 108f9490399SQingqing Zhuo static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, 109f9490399SQingqing Zhuo struct dc_state *context, 110f9490399SQingqing Zhuo bool safe_to_lower) 111f9490399SQingqing Zhuo { 112f9490399SQingqing Zhuo union dmub_rb_cmd cmd; 113f9490399SQingqing Zhuo struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 114f9490399SQingqing Zhuo struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; 115f9490399SQingqing Zhuo struct dc *dc = clk_mgr_base->ctx->dc; 116f9490399SQingqing Zhuo int display_count; 117f9490399SQingqing Zhuo bool update_dppclk = false; 118f9490399SQingqing Zhuo bool update_dispclk = false; 119f9490399SQingqing Zhuo bool dpp_clock_lowered = false; 120f9490399SQingqing Zhuo 121f9490399SQingqing Zhuo if (dc->work_arounds.skip_clock_update) 122f9490399SQingqing Zhuo return; 123f9490399SQingqing Zhuo 124f9490399SQingqing Zhuo clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; 125f9490399SQingqing Zhuo /* 126f9490399SQingqing Zhuo * if it is safe to lower, but we are already in the lower state, we don't have to do anything 127f9490399SQingqing Zhuo * also if safe to lower is false, we just go in the higher state 128f9490399SQingqing Zhuo */ 129f9490399SQingqing Zhuo clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; 130f9490399SQingqing Zhuo if (safe_to_lower) { 131f9490399SQingqing Zhuo /* check that we're not already in lower */ 132f9490399SQingqing Zhuo if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { 133f9490399SQingqing Zhuo display_count = dcn315_get_active_display_cnt_wa(dc, context); 134f9490399SQingqing Zhuo /* if we can go lower, go lower */ 135f9490399SQingqing Zhuo if (display_count == 0) { 136f9490399SQingqing Zhuo union display_idle_optimization_u idle_info = { 0 }; 137f9490399SQingqing Zhuo idle_info.idle_info.df_request_disabled = 1; 138f9490399SQingqing Zhuo idle_info.idle_info.phy_ref_clk_off = 1; 139e7145aaeSCharlene Liu idle_info.idle_info.s0i2_rdy = 1; 140f9490399SQingqing Zhuo dcn315_smu_set_display_idle_optimization(clk_mgr, idle_info.data); 141f9490399SQingqing Zhuo /* update power state */ 142f9490399SQingqing Zhuo clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; 143f9490399SQingqing Zhuo } 144f9490399SQingqing Zhuo } 145f9490399SQingqing Zhuo } else { 146f9490399SQingqing Zhuo /* check that we're not already in D0 */ 147f9490399SQingqing Zhuo if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) { 148f9490399SQingqing Zhuo union display_idle_optimization_u idle_info = { 0 }; 149f9490399SQingqing Zhuo dcn315_smu_set_display_idle_optimization(clk_mgr, idle_info.data); 150f9490399SQingqing Zhuo /* update power state */ 151f9490399SQingqing Zhuo clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE; 152f9490399SQingqing Zhuo } 153f9490399SQingqing Zhuo } 154f9490399SQingqing Zhuo 155f9490399SQingqing Zhuo if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { 156f9490399SQingqing Zhuo clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; 157f9490399SQingqing Zhuo dcn315_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz); 158f9490399SQingqing Zhuo } 159f9490399SQingqing Zhuo 160f9490399SQingqing Zhuo if (should_set_clock(safe_to_lower, 161f9490399SQingqing Zhuo new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { 162f9490399SQingqing Zhuo clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 163f9490399SQingqing Zhuo dcn315_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz); 164f9490399SQingqing Zhuo } 165f9490399SQingqing Zhuo 166f9490399SQingqing Zhuo // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow. 167f9490399SQingqing Zhuo if (!IS_DIAG_DC(dc->ctx->dce_environment)) { 168f9490399SQingqing Zhuo if (new_clocks->dppclk_khz < 100000) 169f9490399SQingqing Zhuo new_clocks->dppclk_khz = 100000; 170f9490399SQingqing Zhuo if (new_clocks->dispclk_khz < 100000) 171f9490399SQingqing Zhuo new_clocks->dispclk_khz = 100000; 172f9490399SQingqing Zhuo } 173f9490399SQingqing Zhuo 174f9490399SQingqing Zhuo if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { 175f9490399SQingqing Zhuo if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz) 176f9490399SQingqing Zhuo dpp_clock_lowered = true; 177f9490399SQingqing Zhuo clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz; 178f9490399SQingqing Zhuo update_dppclk = true; 179f9490399SQingqing Zhuo } 180f9490399SQingqing Zhuo 181f9490399SQingqing Zhuo if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { 1828a077d9cSDmytro Laktyushkin /* No need to apply the w/a if we haven't taken over from bios yet */ 1838a077d9cSDmytro Laktyushkin if (clk_mgr_base->clks.dispclk_khz) 184*abffd871SMeenakshikumar Somasundaram dcn315_disable_otg_wa(clk_mgr_base, context, true); 185f9490399SQingqing Zhuo 186f9490399SQingqing Zhuo clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; 187f9490399SQingqing Zhuo dcn315_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); 1888a077d9cSDmytro Laktyushkin if (clk_mgr_base->clks.dispclk_khz) 189*abffd871SMeenakshikumar Somasundaram dcn315_disable_otg_wa(clk_mgr_base, context, false); 190f9490399SQingqing Zhuo 191f9490399SQingqing Zhuo update_dispclk = true; 192f9490399SQingqing Zhuo } 193f9490399SQingqing Zhuo 194f9490399SQingqing Zhuo if (dpp_clock_lowered) { 195f9490399SQingqing Zhuo // increase per DPP DTO before lowering global dppclk 196f9490399SQingqing Zhuo dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 197f9490399SQingqing Zhuo dcn315_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); 198f9490399SQingqing Zhuo } else { 199f9490399SQingqing Zhuo // increase global DPPCLK before lowering per DPP DTO 200f9490399SQingqing Zhuo if (update_dppclk || update_dispclk) 201f9490399SQingqing Zhuo dcn315_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); 202f9490399SQingqing Zhuo // always update dtos unless clock is lowered and not safe to lower 203f9490399SQingqing Zhuo if (new_clocks->dppclk_khz >= dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz) 204f9490399SQingqing Zhuo dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 205f9490399SQingqing Zhuo } 206f9490399SQingqing Zhuo 207f9490399SQingqing Zhuo // notify DMCUB of latest clocks 208f9490399SQingqing Zhuo memset(&cmd, 0, sizeof(cmd)); 209f9490399SQingqing Zhuo cmd.notify_clocks.header.type = DMUB_CMD__CLK_MGR; 210f9490399SQingqing Zhuo cmd.notify_clocks.header.sub_type = DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS; 211f9490399SQingqing Zhuo cmd.notify_clocks.clocks.dcfclk_khz = clk_mgr_base->clks.dcfclk_khz; 212f9490399SQingqing Zhuo cmd.notify_clocks.clocks.dcfclk_deep_sleep_khz = 213f9490399SQingqing Zhuo clk_mgr_base->clks.dcfclk_deep_sleep_khz; 214f9490399SQingqing Zhuo cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz; 215f9490399SQingqing Zhuo cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz; 216f9490399SQingqing Zhuo 217f9490399SQingqing Zhuo dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd); 218f9490399SQingqing Zhuo dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv); 219f9490399SQingqing Zhuo dc_dmub_srv_wait_idle(dc->ctx->dmub_srv); 220f9490399SQingqing Zhuo } 221f9490399SQingqing Zhuo 222f9490399SQingqing Zhuo static void dcn315_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, 223f9490399SQingqing Zhuo struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info) 224f9490399SQingqing Zhuo { 225f9490399SQingqing Zhuo return; 226f9490399SQingqing Zhuo } 227f9490399SQingqing Zhuo 228f9490399SQingqing Zhuo static struct clk_bw_params dcn315_bw_params = { 229f9490399SQingqing Zhuo .vram_type = Ddr4MemType, 23089c342a9SDmytro Laktyushkin .num_channels = 2, 231f9490399SQingqing Zhuo .clk_table = { 23289c342a9SDmytro Laktyushkin .entries = { 23389c342a9SDmytro Laktyushkin { 23489c342a9SDmytro Laktyushkin .voltage = 0, 23589c342a9SDmytro Laktyushkin .dispclk_mhz = 640, 23689c342a9SDmytro Laktyushkin .dppclk_mhz = 640, 23789c342a9SDmytro Laktyushkin .phyclk_mhz = 810, 23889c342a9SDmytro Laktyushkin .phyclk_d18_mhz = 667, 23989c342a9SDmytro Laktyushkin .dtbclk_mhz = 600, 24089c342a9SDmytro Laktyushkin }, 24189c342a9SDmytro Laktyushkin { 24289c342a9SDmytro Laktyushkin .voltage = 1, 24389c342a9SDmytro Laktyushkin .dispclk_mhz = 739, 24489c342a9SDmytro Laktyushkin .dppclk_mhz = 739, 24589c342a9SDmytro Laktyushkin .phyclk_mhz = 810, 24689c342a9SDmytro Laktyushkin .phyclk_d18_mhz = 667, 24789c342a9SDmytro Laktyushkin .dtbclk_mhz = 600, 24889c342a9SDmytro Laktyushkin }, 24989c342a9SDmytro Laktyushkin { 25089c342a9SDmytro Laktyushkin .voltage = 2, 25189c342a9SDmytro Laktyushkin .dispclk_mhz = 960, 25289c342a9SDmytro Laktyushkin .dppclk_mhz = 960, 25389c342a9SDmytro Laktyushkin .phyclk_mhz = 810, 25489c342a9SDmytro Laktyushkin .phyclk_d18_mhz = 667, 25589c342a9SDmytro Laktyushkin .dtbclk_mhz = 600, 25689c342a9SDmytro Laktyushkin }, 25789c342a9SDmytro Laktyushkin { 25889c342a9SDmytro Laktyushkin .voltage = 3, 25989c342a9SDmytro Laktyushkin .dispclk_mhz = 1200, 26089c342a9SDmytro Laktyushkin .dppclk_mhz = 1200, 26189c342a9SDmytro Laktyushkin .phyclk_mhz = 810, 26289c342a9SDmytro Laktyushkin .phyclk_d18_mhz = 667, 26389c342a9SDmytro Laktyushkin .dtbclk_mhz = 600, 26489c342a9SDmytro Laktyushkin }, 26589c342a9SDmytro Laktyushkin { 26689c342a9SDmytro Laktyushkin .voltage = 4, 26789c342a9SDmytro Laktyushkin .dispclk_mhz = 1372, 26889c342a9SDmytro Laktyushkin .dppclk_mhz = 1372, 26989c342a9SDmytro Laktyushkin .phyclk_mhz = 810, 27089c342a9SDmytro Laktyushkin .phyclk_d18_mhz = 667, 27189c342a9SDmytro Laktyushkin .dtbclk_mhz = 600, 27289c342a9SDmytro Laktyushkin }, 27389c342a9SDmytro Laktyushkin }, 274f9490399SQingqing Zhuo .num_entries = 5, 275f9490399SQingqing Zhuo }, 276f9490399SQingqing Zhuo 277f9490399SQingqing Zhuo }; 278f9490399SQingqing Zhuo 279f9490399SQingqing Zhuo static struct wm_table ddr5_wm_table = { 280f9490399SQingqing Zhuo .entries = { 281f9490399SQingqing Zhuo { 282f9490399SQingqing Zhuo .wm_inst = WM_A, 283f9490399SQingqing Zhuo .wm_type = WM_TYPE_PSTATE_CHG, 284f9490399SQingqing Zhuo .pstate_latency_us = 64.0, 285f9490399SQingqing Zhuo .sr_exit_time_us = 11.5, 286f9490399SQingqing Zhuo .sr_enter_plus_exit_time_us = 14.5, 287f9490399SQingqing Zhuo .valid = true, 288f9490399SQingqing Zhuo }, 289f9490399SQingqing Zhuo { 290f9490399SQingqing Zhuo .wm_inst = WM_B, 291f9490399SQingqing Zhuo .wm_type = WM_TYPE_PSTATE_CHG, 292f9490399SQingqing Zhuo .pstate_latency_us = 64.0, 293f9490399SQingqing Zhuo .sr_exit_time_us = 11.5, 294f9490399SQingqing Zhuo .sr_enter_plus_exit_time_us = 14.5, 295f9490399SQingqing Zhuo .valid = true, 296f9490399SQingqing Zhuo }, 297f9490399SQingqing Zhuo { 298f9490399SQingqing Zhuo .wm_inst = WM_C, 299f9490399SQingqing Zhuo .wm_type = WM_TYPE_PSTATE_CHG, 300f9490399SQingqing Zhuo .pstate_latency_us = 64.0, 301f9490399SQingqing Zhuo .sr_exit_time_us = 11.5, 302f9490399SQingqing Zhuo .sr_enter_plus_exit_time_us = 14.5, 303f9490399SQingqing Zhuo .valid = true, 304f9490399SQingqing Zhuo }, 305f9490399SQingqing Zhuo { 306f9490399SQingqing Zhuo .wm_inst = WM_D, 307f9490399SQingqing Zhuo .wm_type = WM_TYPE_PSTATE_CHG, 308f9490399SQingqing Zhuo .pstate_latency_us = 64.0, 309f9490399SQingqing Zhuo .sr_exit_time_us = 11.5, 310f9490399SQingqing Zhuo .sr_enter_plus_exit_time_us = 14.5, 311f9490399SQingqing Zhuo .valid = true, 312f9490399SQingqing Zhuo }, 313f9490399SQingqing Zhuo } 314f9490399SQingqing Zhuo }; 315f9490399SQingqing Zhuo 316f9490399SQingqing Zhuo static struct wm_table lpddr5_wm_table = { 317f9490399SQingqing Zhuo .entries = { 318f9490399SQingqing Zhuo { 319f9490399SQingqing Zhuo .wm_inst = WM_A, 320f9490399SQingqing Zhuo .wm_type = WM_TYPE_PSTATE_CHG, 321f9490399SQingqing Zhuo .pstate_latency_us = 11.65333, 322f9490399SQingqing Zhuo .sr_exit_time_us = 11.5, 323f9490399SQingqing Zhuo .sr_enter_plus_exit_time_us = 14.5, 324f9490399SQingqing Zhuo .valid = true, 325f9490399SQingqing Zhuo }, 326f9490399SQingqing Zhuo { 327f9490399SQingqing Zhuo .wm_inst = WM_B, 328f9490399SQingqing Zhuo .wm_type = WM_TYPE_PSTATE_CHG, 329f9490399SQingqing Zhuo .pstate_latency_us = 11.65333, 330f9490399SQingqing Zhuo .sr_exit_time_us = 11.5, 331f9490399SQingqing Zhuo .sr_enter_plus_exit_time_us = 14.5, 332f9490399SQingqing Zhuo .valid = true, 333f9490399SQingqing Zhuo }, 334f9490399SQingqing Zhuo { 335f9490399SQingqing Zhuo .wm_inst = WM_C, 336f9490399SQingqing Zhuo .wm_type = WM_TYPE_PSTATE_CHG, 337f9490399SQingqing Zhuo .pstate_latency_us = 11.65333, 338f9490399SQingqing Zhuo .sr_exit_time_us = 11.5, 339f9490399SQingqing Zhuo .sr_enter_plus_exit_time_us = 14.5, 340f9490399SQingqing Zhuo .valid = true, 341f9490399SQingqing Zhuo }, 342f9490399SQingqing Zhuo { 343f9490399SQingqing Zhuo .wm_inst = WM_D, 344f9490399SQingqing Zhuo .wm_type = WM_TYPE_PSTATE_CHG, 345f9490399SQingqing Zhuo .pstate_latency_us = 11.65333, 346f9490399SQingqing Zhuo .sr_exit_time_us = 11.5, 347f9490399SQingqing Zhuo .sr_enter_plus_exit_time_us = 14.5, 348f9490399SQingqing Zhuo .valid = true, 349f9490399SQingqing Zhuo }, 350f9490399SQingqing Zhuo } 351f9490399SQingqing Zhuo }; 352f9490399SQingqing Zhuo 35389c342a9SDmytro Laktyushkin /* Temporary Place holder until we can get them from fuse */ 35489c342a9SDmytro Laktyushkin static DpmClocks_315_t dummy_clocks = { 0 }; 355f9490399SQingqing Zhuo static struct dcn315_watermarks dummy_wms = { 0 }; 356f9490399SQingqing Zhuo 357f9490399SQingqing Zhuo static void dcn315_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn315_watermarks *table) 358f9490399SQingqing Zhuo { 359f9490399SQingqing Zhuo int i, num_valid_sets; 360f9490399SQingqing Zhuo 361f9490399SQingqing Zhuo num_valid_sets = 0; 362f9490399SQingqing Zhuo 363f9490399SQingqing Zhuo for (i = 0; i < WM_SET_COUNT; i++) { 364f9490399SQingqing Zhuo /* skip empty entries, the smu array has no holes*/ 365f9490399SQingqing Zhuo if (!bw_params->wm_table.entries[i].valid) 366f9490399SQingqing Zhuo continue; 367f9490399SQingqing Zhuo 368f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmSetting = bw_params->wm_table.entries[i].wm_inst; 369f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType = bw_params->wm_table.entries[i].wm_type; 370f9490399SQingqing Zhuo /* We will not select WM based on fclk, so leave it as unconstrained */ 371f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0; 372f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF; 373f9490399SQingqing Zhuo 374f9490399SQingqing Zhuo if (table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType == WM_TYPE_PSTATE_CHG) { 375f9490399SQingqing Zhuo if (i == 0) 376f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 0; 377f9490399SQingqing Zhuo else { 378f9490399SQingqing Zhuo /* add 1 to make it non-overlapping with next lvl */ 379f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 380f9490399SQingqing Zhuo bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1; 381f9490399SQingqing Zhuo } 382f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxMclk = 383f9490399SQingqing Zhuo bw_params->clk_table.entries[i].dcfclk_mhz; 384f9490399SQingqing Zhuo 385f9490399SQingqing Zhuo } else { 386f9490399SQingqing Zhuo /* unconstrained for memory retraining */ 387f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0; 388f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF; 389f9490399SQingqing Zhuo 390f9490399SQingqing Zhuo /* Modify previous watermark range to cover up to max */ 391f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF; 392f9490399SQingqing Zhuo } 393f9490399SQingqing Zhuo num_valid_sets++; 394f9490399SQingqing Zhuo } 395f9490399SQingqing Zhuo 396f9490399SQingqing Zhuo ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */ 397f9490399SQingqing Zhuo 398f9490399SQingqing Zhuo /* modify the min and max to make sure we cover the whole range*/ 399f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][0].MinMclk = 0; 400f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][0].MinClock = 0; 401f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxMclk = 0xFFFF; 402f9490399SQingqing Zhuo table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF; 403f9490399SQingqing Zhuo 404f9490399SQingqing Zhuo /* This is for writeback only, does not matter currently as no writeback support*/ 405f9490399SQingqing Zhuo table->WatermarkRow[WM_SOCCLK][0].WmSetting = WM_A; 406f9490399SQingqing Zhuo table->WatermarkRow[WM_SOCCLK][0].MinClock = 0; 407f9490399SQingqing Zhuo table->WatermarkRow[WM_SOCCLK][0].MaxClock = 0xFFFF; 408f9490399SQingqing Zhuo table->WatermarkRow[WM_SOCCLK][0].MinMclk = 0; 409f9490399SQingqing Zhuo table->WatermarkRow[WM_SOCCLK][0].MaxMclk = 0xFFFF; 410f9490399SQingqing Zhuo } 411f9490399SQingqing Zhuo 412f9490399SQingqing Zhuo static void dcn315_notify_wm_ranges(struct clk_mgr *clk_mgr_base) 413f9490399SQingqing Zhuo { 414f9490399SQingqing Zhuo struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 415f9490399SQingqing Zhuo struct clk_mgr_dcn315 *clk_mgr_dcn315 = TO_CLK_MGR_DCN315(clk_mgr); 416f9490399SQingqing Zhuo struct dcn315_watermarks *table = clk_mgr_dcn315->smu_wm_set.wm_set; 417f9490399SQingqing Zhuo 418f9490399SQingqing Zhuo if (!clk_mgr->smu_ver) 419f9490399SQingqing Zhuo return; 420f9490399SQingqing Zhuo 421f9490399SQingqing Zhuo if (!table || clk_mgr_dcn315->smu_wm_set.mc_address.quad_part == 0) 422f9490399SQingqing Zhuo return; 423f9490399SQingqing Zhuo 424f9490399SQingqing Zhuo memset(table, 0, sizeof(*table)); 425f9490399SQingqing Zhuo 426f9490399SQingqing Zhuo dcn315_build_watermark_ranges(clk_mgr_base->bw_params, table); 427f9490399SQingqing Zhuo 428f9490399SQingqing Zhuo dcn315_smu_set_dram_addr_high(clk_mgr, 429f9490399SQingqing Zhuo clk_mgr_dcn315->smu_wm_set.mc_address.high_part); 430f9490399SQingqing Zhuo dcn315_smu_set_dram_addr_low(clk_mgr, 431f9490399SQingqing Zhuo clk_mgr_dcn315->smu_wm_set.mc_address.low_part); 432f9490399SQingqing Zhuo dcn315_smu_transfer_wm_table_dram_2_smu(clk_mgr); 433f9490399SQingqing Zhuo } 434f9490399SQingqing Zhuo 435f9490399SQingqing Zhuo static void dcn315_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr, 436f9490399SQingqing Zhuo struct dcn315_smu_dpm_clks *smu_dpm_clks) 437f9490399SQingqing Zhuo { 438f9490399SQingqing Zhuo DpmClocks_315_t *table = smu_dpm_clks->dpm_clks; 439f9490399SQingqing Zhuo 440f9490399SQingqing Zhuo if (!clk_mgr->smu_ver) 441f9490399SQingqing Zhuo return; 442f9490399SQingqing Zhuo 443f9490399SQingqing Zhuo if (!table || smu_dpm_clks->mc_address.quad_part == 0) 444f9490399SQingqing Zhuo return; 445f9490399SQingqing Zhuo 446f9490399SQingqing Zhuo memset(table, 0, sizeof(*table)); 447f9490399SQingqing Zhuo 448f9490399SQingqing Zhuo dcn315_smu_set_dram_addr_high(clk_mgr, 449f9490399SQingqing Zhuo smu_dpm_clks->mc_address.high_part); 450f9490399SQingqing Zhuo dcn315_smu_set_dram_addr_low(clk_mgr, 451f9490399SQingqing Zhuo smu_dpm_clks->mc_address.low_part); 452f9490399SQingqing Zhuo dcn315_smu_transfer_dpm_table_smu_2_dram(clk_mgr); 453f9490399SQingqing Zhuo } 454f9490399SQingqing Zhuo 455f9490399SQingqing Zhuo static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks) 456f9490399SQingqing Zhuo { 457f9490399SQingqing Zhuo uint32_t max = 0; 458f9490399SQingqing Zhuo int i; 459f9490399SQingqing Zhuo 460f9490399SQingqing Zhuo for (i = 0; i < num_clocks; ++i) { 461f9490399SQingqing Zhuo if (clocks[i] > max) 462f9490399SQingqing Zhuo max = clocks[i]; 463f9490399SQingqing Zhuo } 464f9490399SQingqing Zhuo 465f9490399SQingqing Zhuo return max; 466f9490399SQingqing Zhuo } 467f9490399SQingqing Zhuo 468f728eb3aSMagali Lemes static void dcn315_clk_mgr_helper_populate_bw_params( 469f9490399SQingqing Zhuo struct clk_mgr_internal *clk_mgr, 470f9490399SQingqing Zhuo struct integrated_info *bios_info, 471f9490399SQingqing Zhuo const DpmClocks_315_t *clock_table) 472f9490399SQingqing Zhuo { 47360f6fe66SDmytro Laktyushkin int i; 474f9490399SQingqing Zhuo struct clk_bw_params *bw_params = clk_mgr->base.bw_params; 47589c342a9SDmytro Laktyushkin uint32_t max_pstate = 0, max_fclk = 0, min_pstate = 0; 47660f6fe66SDmytro Laktyushkin struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1]; 477f9490399SQingqing Zhuo 47860f6fe66SDmytro Laktyushkin /* Find highest fclk pstate */ 47960f6fe66SDmytro Laktyushkin for (i = 0; i < clock_table->NumDfPstatesEnabled; i++) { 48060f6fe66SDmytro Laktyushkin if (clock_table->DfPstateTable[i].FClk > max_fclk) { 48160f6fe66SDmytro Laktyushkin max_fclk = clock_table->DfPstateTable[i].FClk; 48260f6fe66SDmytro Laktyushkin max_pstate = i; 48360f6fe66SDmytro Laktyushkin } 484f9490399SQingqing Zhuo } 485f9490399SQingqing Zhuo 48660f6fe66SDmytro Laktyushkin /* For 315 we want to base clock table on dcfclk, need at least one entry regardless of pmfw table */ 48760f6fe66SDmytro Laktyushkin for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) { 48860f6fe66SDmytro Laktyushkin int j; 48960f6fe66SDmytro Laktyushkin uint32_t min_fclk = clock_table->DfPstateTable[0].FClk; 490f9490399SQingqing Zhuo 49160f6fe66SDmytro Laktyushkin for (j = 1; j < clock_table->NumDfPstatesEnabled; j++) { 49260f6fe66SDmytro Laktyushkin if (clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i] 49360f6fe66SDmytro Laktyushkin && clock_table->DfPstateTable[j].FClk < min_fclk) { 49460f6fe66SDmytro Laktyushkin min_fclk = clock_table->DfPstateTable[j].FClk; 49560f6fe66SDmytro Laktyushkin min_pstate = j; 49660f6fe66SDmytro Laktyushkin } 49760f6fe66SDmytro Laktyushkin } 49860f6fe66SDmytro Laktyushkin 49989c342a9SDmytro Laktyushkin /* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */ 50089c342a9SDmytro Laktyushkin for (j = bw_params->clk_table.num_entries - 1; j > 0; j--) 50189c342a9SDmytro Laktyushkin if (bw_params->clk_table.entries[j].dcfclk_mhz <= clock_table->DcfClocks[i]) 50289c342a9SDmytro Laktyushkin break; 50389c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].phyclk_mhz = bw_params->clk_table.entries[j].phyclk_mhz; 50489c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].phyclk_d18_mhz = bw_params->clk_table.entries[j].phyclk_d18_mhz; 50589c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz; 50689c342a9SDmytro Laktyushkin 50789c342a9SDmytro Laktyushkin /* Now update clocks we do read */ 50860f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].fclk_mhz = min_fclk; 50960f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[min_pstate].MemClk; 51060f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[min_pstate].Voltage; 51160f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i]; 51260f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i]; 51389c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].dispclk_mhz = clock_table->DispClocks[i]; 51489c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].dppclk_mhz = clock_table->DppClocks[i]; 51560f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].wck_ratio = 1; 516b34e44bcSmin tang } 517f9490399SQingqing Zhuo 51860f6fe66SDmytro Laktyushkin /* Make sure to include at least one entry and highest pstate */ 51989c342a9SDmytro Laktyushkin if (max_pstate != min_pstate || i == 0) { 52060f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].fclk_mhz = max_fclk; 52160f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk; 52260f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[max_pstate].Voltage; 52389c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].dcfclk_mhz = find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS); 52460f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].wck_ratio = 1; 52560f6fe66SDmytro Laktyushkin i++; 52660f6fe66SDmytro Laktyushkin } 52789c342a9SDmytro Laktyushkin bw_params->clk_table.num_entries = i--; 52860f6fe66SDmytro Laktyushkin 52989c342a9SDmytro Laktyushkin /* Make sure all highest clocks are included*/ 53089c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS); 53189c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].dispclk_mhz = find_max_clk_value(clock_table->DispClocks, NUM_DISPCLK_DPM_LEVELS); 53289c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].dppclk_mhz = find_max_clk_value(clock_table->DppClocks, NUM_DPPCLK_DPM_LEVELS); 53389c342a9SDmytro Laktyushkin ASSERT(clock_table->DcfClocks[i] == find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS)); 53489c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz; 53589c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz; 53689c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz; 53760f6fe66SDmytro Laktyushkin 53860f6fe66SDmytro Laktyushkin /* Set any 0 clocks to max default setting. Not an issue for 53960f6fe66SDmytro Laktyushkin * power since we aren't doing switching in such case anyway 54060f6fe66SDmytro Laktyushkin */ 54160f6fe66SDmytro Laktyushkin for (i = 0; i < bw_params->clk_table.num_entries; i++) { 54260f6fe66SDmytro Laktyushkin if (!bw_params->clk_table.entries[i].fclk_mhz) { 54360f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz; 54460f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].memclk_mhz = def_max.memclk_mhz; 54560f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].voltage = def_max.voltage; 54660f6fe66SDmytro Laktyushkin } 54760f6fe66SDmytro Laktyushkin if (!bw_params->clk_table.entries[i].dcfclk_mhz) 54860f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].dcfclk_mhz = def_max.dcfclk_mhz; 54960f6fe66SDmytro Laktyushkin if (!bw_params->clk_table.entries[i].socclk_mhz) 55060f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].socclk_mhz = def_max.socclk_mhz; 55160f6fe66SDmytro Laktyushkin if (!bw_params->clk_table.entries[i].dispclk_mhz) 55260f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].dispclk_mhz = def_max.dispclk_mhz; 55360f6fe66SDmytro Laktyushkin if (!bw_params->clk_table.entries[i].dppclk_mhz) 55460f6fe66SDmytro Laktyushkin bw_params->clk_table.entries[i].dppclk_mhz = def_max.dppclk_mhz; 55589c342a9SDmytro Laktyushkin if (!bw_params->clk_table.entries[i].phyclk_mhz) 55689c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz; 55789c342a9SDmytro Laktyushkin if (!bw_params->clk_table.entries[i].phyclk_d18_mhz) 55889c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz; 55989c342a9SDmytro Laktyushkin if (!bw_params->clk_table.entries[i].dtbclk_mhz) 56089c342a9SDmytro Laktyushkin bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz; 56160f6fe66SDmytro Laktyushkin } 562f173fbe5SQingqing Zhuo ASSERT(bw_params->clk_table.entries[i-1].dcfclk_mhz); 563f9490399SQingqing Zhuo bw_params->vram_type = bios_info->memory_type; 564f9490399SQingqing Zhuo bw_params->num_channels = bios_info->ma_channel_number; 56562f0576cSDmytro Laktyushkin bw_params->dram_channel_width_bytes = bios_info->memory_type == 0x22 ? 8 : 4; 566f9490399SQingqing Zhuo 567f9490399SQingqing Zhuo for (i = 0; i < WM_SET_COUNT; i++) { 568f9490399SQingqing Zhuo bw_params->wm_table.entries[i].wm_inst = i; 569f9490399SQingqing Zhuo 570f9490399SQingqing Zhuo if (i >= bw_params->clk_table.num_entries) { 571f9490399SQingqing Zhuo bw_params->wm_table.entries[i].valid = false; 572f9490399SQingqing Zhuo continue; 573f9490399SQingqing Zhuo } 574f9490399SQingqing Zhuo 575f9490399SQingqing Zhuo bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG; 576f9490399SQingqing Zhuo bw_params->wm_table.entries[i].valid = true; 577f9490399SQingqing Zhuo } 578f9490399SQingqing Zhuo } 579f9490399SQingqing Zhuo 580f9490399SQingqing Zhuo static void dcn315_enable_pme_wa(struct clk_mgr *clk_mgr_base) 581f9490399SQingqing Zhuo { 582f9490399SQingqing Zhuo struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 583f9490399SQingqing Zhuo 584f9490399SQingqing Zhuo dcn315_smu_enable_pme_wa(clk_mgr); 585f9490399SQingqing Zhuo } 586f9490399SQingqing Zhuo 587f9490399SQingqing Zhuo static struct clk_mgr_funcs dcn315_funcs = { 588f9490399SQingqing Zhuo .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, 5890ec74408SLeung, Martin .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz, 590f9490399SQingqing Zhuo .update_clocks = dcn315_update_clocks, 591f9490399SQingqing Zhuo .init_clocks = dcn31_init_clocks, 592f9490399SQingqing Zhuo .enable_pme_wa = dcn315_enable_pme_wa, 593f9490399SQingqing Zhuo .are_clock_states_equal = dcn31_are_clock_states_equal, 594f9490399SQingqing Zhuo .notify_wm_ranges = dcn315_notify_wm_ranges 595f9490399SQingqing Zhuo }; 596f9490399SQingqing Zhuo extern struct clk_mgr_funcs dcn3_fpga_funcs; 597f9490399SQingqing Zhuo 598f9490399SQingqing Zhuo void dcn315_clk_mgr_construct( 599f9490399SQingqing Zhuo struct dc_context *ctx, 600f9490399SQingqing Zhuo struct clk_mgr_dcn315 *clk_mgr, 601f9490399SQingqing Zhuo struct pp_smu_funcs *pp_smu, 602f9490399SQingqing Zhuo struct dccg *dccg) 603f9490399SQingqing Zhuo { 604f9490399SQingqing Zhuo struct dcn315_smu_dpm_clks smu_dpm_clks = { 0 }; 605f9490399SQingqing Zhuo 606f9490399SQingqing Zhuo clk_mgr->base.base.ctx = ctx; 607f9490399SQingqing Zhuo clk_mgr->base.base.funcs = &dcn315_funcs; 608f9490399SQingqing Zhuo 609f9490399SQingqing Zhuo clk_mgr->base.pp_smu = pp_smu; 610f9490399SQingqing Zhuo 611f9490399SQingqing Zhuo clk_mgr->base.dccg = dccg; 612f9490399SQingqing Zhuo clk_mgr->base.dfs_bypass_disp_clk = 0; 613f9490399SQingqing Zhuo 614f9490399SQingqing Zhuo clk_mgr->base.dprefclk_ss_percentage = 0; 615f9490399SQingqing Zhuo clk_mgr->base.dprefclk_ss_divider = 1000; 616f9490399SQingqing Zhuo clk_mgr->base.ss_on_dprefclk = false; 617f9490399SQingqing Zhuo clk_mgr->base.dfs_ref_freq_khz = 48000; 618f9490399SQingqing Zhuo 619f9490399SQingqing Zhuo clk_mgr->smu_wm_set.wm_set = (struct dcn315_watermarks *)dm_helpers_allocate_gpu_mem( 620f9490399SQingqing Zhuo clk_mgr->base.base.ctx, 621f9490399SQingqing Zhuo DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 622f9490399SQingqing Zhuo sizeof(struct dcn315_watermarks), 623f9490399SQingqing Zhuo &clk_mgr->smu_wm_set.mc_address.quad_part); 624f9490399SQingqing Zhuo 625f9490399SQingqing Zhuo if (!clk_mgr->smu_wm_set.wm_set) { 626f9490399SQingqing Zhuo clk_mgr->smu_wm_set.wm_set = &dummy_wms; 627f9490399SQingqing Zhuo clk_mgr->smu_wm_set.mc_address.quad_part = 0; 628f9490399SQingqing Zhuo } 629f9490399SQingqing Zhuo ASSERT(clk_mgr->smu_wm_set.wm_set); 630f9490399SQingqing Zhuo 631f9490399SQingqing Zhuo smu_dpm_clks.dpm_clks = (DpmClocks_315_t *)dm_helpers_allocate_gpu_mem( 632f9490399SQingqing Zhuo clk_mgr->base.base.ctx, 633f9490399SQingqing Zhuo DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 634f9490399SQingqing Zhuo sizeof(DpmClocks_315_t), 635f9490399SQingqing Zhuo &smu_dpm_clks.mc_address.quad_part); 636f9490399SQingqing Zhuo 637f9490399SQingqing Zhuo if (smu_dpm_clks.dpm_clks == NULL) { 638f9490399SQingqing Zhuo smu_dpm_clks.dpm_clks = &dummy_clocks; 639f9490399SQingqing Zhuo smu_dpm_clks.mc_address.quad_part = 0; 640f9490399SQingqing Zhuo } 641f9490399SQingqing Zhuo 642f9490399SQingqing Zhuo ASSERT(smu_dpm_clks.dpm_clks); 643f9490399SQingqing Zhuo 644f9490399SQingqing Zhuo if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { 645f9490399SQingqing Zhuo clk_mgr->base.base.funcs = &dcn3_fpga_funcs; 646f9490399SQingqing Zhuo } else { 647f9490399SQingqing Zhuo struct clk_log_info log_info = {0}; 648f9490399SQingqing Zhuo 649f9490399SQingqing Zhuo clk_mgr->base.smu_ver = dcn315_smu_get_smu_version(&clk_mgr->base); 650f9490399SQingqing Zhuo 651f9490399SQingqing Zhuo if (clk_mgr->base.smu_ver > 0) 652f9490399SQingqing Zhuo clk_mgr->base.smu_present = true; 653f9490399SQingqing Zhuo 654f9490399SQingqing Zhuo if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) { 655f9490399SQingqing Zhuo dcn315_bw_params.wm_table = lpddr5_wm_table; 656f9490399SQingqing Zhuo } else { 657f9490399SQingqing Zhuo dcn315_bw_params.wm_table = ddr5_wm_table; 658f9490399SQingqing Zhuo } 659f9490399SQingqing Zhuo /* Saved clocks configured at boot for debug purposes */ 660203dc777SJiapeng Chong dcn315_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, 661203dc777SJiapeng Chong &clk_mgr->base.base, &log_info); 662f9490399SQingqing Zhuo 663f9490399SQingqing Zhuo } 664f9490399SQingqing Zhuo 665f9490399SQingqing Zhuo clk_mgr->base.base.dprefclk_khz = 600000; 6663b8b44a4SCharlene Liu clk_mgr->base.base.dprefclk_khz = dcn315_smu_get_dpref_clk(&clk_mgr->base); 6670ec74408SLeung, Martin clk_mgr->base.base.clks.ref_dtbclk_khz = clk_mgr->base.base.dprefclk_khz; 668f9490399SQingqing Zhuo dce_clock_read_ss_info(&clk_mgr->base); 6690ec74408SLeung, Martin clk_mgr->base.base.clks.ref_dtbclk_khz = dce_adjust_dp_ref_freq_for_ss(&clk_mgr->base, clk_mgr->base.base.dprefclk_khz); 670f9490399SQingqing Zhuo 671f9490399SQingqing Zhuo clk_mgr->base.base.bw_params = &dcn315_bw_params; 672f9490399SQingqing Zhuo 673f9490399SQingqing Zhuo if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) { 674c8b1d0feSLeo Chen int i; 675c8b1d0feSLeo Chen 676f9490399SQingqing Zhuo dcn315_get_dpm_table_from_smu(&clk_mgr->base, &smu_dpm_clks); 677c8b1d0feSLeo Chen DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n" 678c8b1d0feSLeo Chen "NumDispClkLevelsEnabled: %d\n" 679c8b1d0feSLeo Chen "NumSocClkLevelsEnabled: %d\n" 680c8b1d0feSLeo Chen "VcnClkLevelsEnabled: %d\n" 681c8b1d0feSLeo Chen "NumDfPst atesEnabled: %d\n" 682c8b1d0feSLeo Chen "MinGfxClk: %d\n" 683c8b1d0feSLeo Chen "MaxGfxClk: %d\n", 684c8b1d0feSLeo Chen smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled, 685c8b1d0feSLeo Chen smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled, 686c8b1d0feSLeo Chen smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled, 687c8b1d0feSLeo Chen smu_dpm_clks.dpm_clks->VcnClkLevelsEnabled, 688c8b1d0feSLeo Chen smu_dpm_clks.dpm_clks->NumDfPstatesEnabled, 689c8b1d0feSLeo Chen smu_dpm_clks.dpm_clks->MinGfxClk, 690c8b1d0feSLeo Chen smu_dpm_clks.dpm_clks->MaxGfxClk); 691c8b1d0feSLeo Chen for (i = 0; i < smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled; i++) { 692c8b1d0feSLeo Chen DC_LOG_SMU("smu_dpm_clks.dpm_clks->DcfClocks[%d] = %d\n", 693c8b1d0feSLeo Chen i, 694c8b1d0feSLeo Chen smu_dpm_clks.dpm_clks->DcfClocks[i]); 695c8b1d0feSLeo Chen } 696c8b1d0feSLeo Chen for (i = 0; i < smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled; i++) { 697c8b1d0feSLeo Chen DC_LOG_SMU("smu_dpm_clks.dpm_clks->DispClocks[%d] = %d\n", 698c8b1d0feSLeo Chen i, smu_dpm_clks.dpm_clks->DispClocks[i]); 699c8b1d0feSLeo Chen } 700c8b1d0feSLeo Chen for (i = 0; i < smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled; i++) { 701c8b1d0feSLeo Chen DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocClocks[%d] = %d\n", 702c8b1d0feSLeo Chen i, smu_dpm_clks.dpm_clks->SocClocks[i]); 703c8b1d0feSLeo Chen } 704c8b1d0feSLeo Chen for (i = 0; i < NUM_SOC_VOLTAGE_LEVELS; i++) 705c8b1d0feSLeo Chen DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocVoltage[%d] = %d\n", 706c8b1d0feSLeo Chen i, smu_dpm_clks.dpm_clks->SocVoltage[i]); 707c8b1d0feSLeo Chen 708c8b1d0feSLeo Chen for (i = 0; i < NUM_DF_PSTATE_LEVELS; i++) { 709c8b1d0feSLeo Chen DC_LOG_SMU("smu_dpm_clks.dpm_clks.DfPstateTable[%d].FClk = %d\n" 710c8b1d0feSLeo Chen "smu_dpm_clks.dpm_clks->DfPstateTable[%d].MemClk= %d\n" 711c8b1d0feSLeo Chen "smu_dpm_clks.dpm_clks->DfPstateTable[%d].Voltage = %d\n", 712c8b1d0feSLeo Chen i, smu_dpm_clks.dpm_clks->DfPstateTable[i].FClk, 713c8b1d0feSLeo Chen i, smu_dpm_clks.dpm_clks->DfPstateTable[i].MemClk, 714c8b1d0feSLeo Chen i, smu_dpm_clks.dpm_clks->DfPstateTable[i].Voltage); 715c8b1d0feSLeo Chen } 716f9490399SQingqing Zhuo 717f9490399SQingqing Zhuo if (ctx->dc_bios && ctx->dc_bios->integrated_info) { 718f9490399SQingqing Zhuo dcn315_clk_mgr_helper_populate_bw_params( 719f9490399SQingqing Zhuo &clk_mgr->base, 720f9490399SQingqing Zhuo ctx->dc_bios->integrated_info, 721f9490399SQingqing Zhuo smu_dpm_clks.dpm_clks); 722f9490399SQingqing Zhuo } 723f9490399SQingqing Zhuo } 724f9490399SQingqing Zhuo 725f9490399SQingqing Zhuo if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0) 726f9490399SQingqing Zhuo dm_helpers_free_gpu_mem(clk_mgr->base.base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 727f9490399SQingqing Zhuo smu_dpm_clks.dpm_clks); 728f9490399SQingqing Zhuo } 729f9490399SQingqing Zhuo 730f9490399SQingqing Zhuo void dcn315_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int) 731f9490399SQingqing Zhuo { 732f9490399SQingqing Zhuo struct clk_mgr_dcn315 *clk_mgr = TO_CLK_MGR_DCN315(clk_mgr_int); 733f9490399SQingqing Zhuo 734f9490399SQingqing Zhuo if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0) 735f9490399SQingqing Zhuo dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 736f9490399SQingqing Zhuo clk_mgr->smu_wm_set.wm_set); 737f9490399SQingqing Zhuo } 738