353 lines · c
1/*2 * Copyright 2012-16 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * 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 OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: AMD23 *24 */25 26#ifndef __DAL_CLK_MGR_H__27#define __DAL_CLK_MGR_H__28 29#include "dc.h"30#include "dm_pp_smu.h"31 32/* Constants */33#define DDR4_DRAM_WIDTH 6434#define WM_A 035#define WM_B 136#define WM_C 237#define WM_D 338#define WM_SET_COUNT 439#define WM_1A 240#define WM_1B 341 42#define DCN_MINIMUM_DISPCLK_Khz 10000043#define DCN_MINIMUM_DPPCLK_Khz 10000044 45struct dcn3_clk_internal {46 int dummy;47// TODO:48 uint32_t CLK1_CLK0_CURRENT_CNT; //dispclk49 uint32_t CLK1_CLK1_CURRENT_CNT; //dppclk50 uint32_t CLK1_CLK2_CURRENT_CNT; //dprefclk51 uint32_t CLK1_CLK3_CURRENT_CNT; //dcfclk52 uint32_t CLK1_CLK4_CURRENT_CNT;53 uint32_t CLK1_CLK3_DS_CNTL; //dcf_deep_sleep_divider54 uint32_t CLK1_CLK3_ALLOW_DS; //dcf_deep_sleep_allow55 56 uint32_t CLK1_CLK0_BYPASS_CNTL; //dispclk bypass57 uint32_t CLK1_CLK1_BYPASS_CNTL; //dppclk bypass58 uint32_t CLK1_CLK2_BYPASS_CNTL; //dprefclk bypass59 uint32_t CLK1_CLK3_BYPASS_CNTL; //dcfclk bypass60 61 uint32_t CLK4_CLK0_CURRENT_CNT; //fclk62};63 64struct dcn35_clk_internal {65 int dummy;66 uint32_t CLK1_CLK0_CURRENT_CNT; //dispclk67 uint32_t CLK1_CLK1_CURRENT_CNT; //dppclk68 uint32_t CLK1_CLK2_CURRENT_CNT; //dprefclk69 uint32_t CLK1_CLK3_CURRENT_CNT; //dcfclk70 uint32_t CLK1_CLK4_CURRENT_CNT; //dtbclk71 //uint32_t CLK1_CLK5_CURRENT_CNT; //dpiaclk72 //uint32_t CLK1_CLK6_CURRENT_CNT; //srdbgclk73 uint32_t CLK1_CLK3_DS_CNTL; //dcf_deep_sleep_divider74 uint32_t CLK1_CLK3_ALLOW_DS; //dcf_deep_sleep_allow75 76 uint32_t CLK1_CLK0_BYPASS_CNTL; //dispclk bypass77 uint32_t CLK1_CLK1_BYPASS_CNTL; //dppclk bypass78 uint32_t CLK1_CLK2_BYPASS_CNTL; //dprefclk bypass79 uint32_t CLK1_CLK3_BYPASS_CNTL; //dcfclk bypass80 uint32_t CLK1_CLK4_BYPASS_CNTL; //dtbclk bypass81};82 83struct dcn301_clk_internal {84 int dummy;85 uint32_t CLK1_CLK0_CURRENT_CNT; //dispclk86 uint32_t CLK1_CLK1_CURRENT_CNT; //dppclk87 uint32_t CLK1_CLK2_CURRENT_CNT; //dprefclk88 uint32_t CLK1_CLK3_CURRENT_CNT; //dcfclk89 uint32_t CLK1_CLK3_DS_CNTL; //dcf_deep_sleep_divider90 uint32_t CLK1_CLK3_ALLOW_DS; //dcf_deep_sleep_allow91 92 uint32_t CLK1_CLK0_BYPASS_CNTL; //dispclk bypass93 uint32_t CLK1_CLK1_BYPASS_CNTL; //dppclk bypass94 uint32_t CLK1_CLK2_BYPASS_CNTL; //dprefclk bypass95 uint32_t CLK1_CLK3_BYPASS_CNTL; //dcfclk bypass96};97 98/* Will these bw structures be ASIC specific? */99 100#define MAX_NUM_DPM_LVL 8101#define WM_SET_COUNT 4102 103 104struct clk_limit_table_entry {105 unsigned int voltage; /* milivolts withh 2 fractional bits */106 unsigned int dcfclk_mhz;107 unsigned int fclk_mhz;108 unsigned int memclk_mhz;109 unsigned int socclk_mhz;110 unsigned int dtbclk_mhz;111 unsigned int dispclk_mhz;112 unsigned int dppclk_mhz;113 unsigned int phyclk_mhz;114 unsigned int phyclk_d18_mhz;115 unsigned int wck_ratio;116};117 118struct clk_limit_num_entries {119 unsigned int num_dcfclk_levels;120 unsigned int num_fclk_levels;121 unsigned int num_memclk_levels;122 unsigned int num_socclk_levels;123 unsigned int num_dtbclk_levels;124 unsigned int num_dispclk_levels;125 unsigned int num_dppclk_levels;126 unsigned int num_phyclk_levels;127 unsigned int num_phyclk_d18_levels;128};129 130/* This table is contiguous */131struct clk_limit_table {132 struct clk_limit_table_entry entries[MAX_NUM_DPM_LVL];133 struct clk_limit_num_entries num_entries_per_clk;134 unsigned int num_entries; /* highest populated dpm level for back compatibility */135};136 137struct wm_range_table_entry {138 unsigned int wm_inst;139 unsigned int wm_type;140 double pstate_latency_us;141 double sr_exit_time_us;142 double sr_enter_plus_exit_time_us;143 bool valid;144};145 146struct nv_wm_range_entry {147 bool valid;148 149 struct {150 uint8_t wm_type;151 uint16_t min_dcfclk;152 uint16_t max_dcfclk;153 uint16_t min_uclk;154 uint16_t max_uclk;155 } pmfw_breakdown;156 157 struct {158 double pstate_latency_us;159 double sr_exit_time_us;160 double sr_enter_plus_exit_time_us;161 double fclk_change_latency_us;162 } dml_input;163};164 165struct clk_log_info {166 bool enabled;167 char *pBuf;168 unsigned int bufSize;169 unsigned int *sum_chars_printed;170};171 172struct clk_state_registers_and_bypass {173 uint32_t dcfclk;174 uint32_t dcf_deep_sleep_divider;175 uint32_t dcf_deep_sleep_allow;176 uint32_t dprefclk;177 uint32_t dispclk;178 uint32_t dppclk;179 uint32_t dtbclk;180 uint32_t fclk;181 182 uint32_t dppclk_bypass;183 uint32_t dcfclk_bypass;184 uint32_t dprefclk_bypass;185 uint32_t dispclk_bypass;186};187 188struct rv1_clk_internal {189 uint32_t CLK0_CLK8_CURRENT_CNT; //dcfclk190 uint32_t CLK0_CLK8_DS_CNTL; //dcf_deep_sleep_divider191 uint32_t CLK0_CLK8_ALLOW_DS; //dcf_deep_sleep_allow192 uint32_t CLK0_CLK10_CURRENT_CNT; //dprefclk193 uint32_t CLK0_CLK11_CURRENT_CNT; //dispclk194 195 uint32_t CLK0_CLK8_BYPASS_CNTL; //dcfclk bypass196 uint32_t CLK0_CLK10_BYPASS_CNTL; //dprefclk bypass197 uint32_t CLK0_CLK11_BYPASS_CNTL; //dispclk bypass198};199 200struct rn_clk_internal {201 uint32_t CLK1_CLK0_CURRENT_CNT; //dispclk202 uint32_t CLK1_CLK1_CURRENT_CNT; //dppclk203 uint32_t CLK1_CLK2_CURRENT_CNT; //dprefclk204 uint32_t CLK1_CLK3_CURRENT_CNT; //dcfclk205 uint32_t CLK1_CLK3_DS_CNTL; //dcf_deep_sleep_divider206 uint32_t CLK1_CLK3_ALLOW_DS; //dcf_deep_sleep_allow207 208 uint32_t CLK1_CLK0_BYPASS_CNTL; //dispclk bypass209 uint32_t CLK1_CLK1_BYPASS_CNTL; //dppclk bypass210 uint32_t CLK1_CLK2_BYPASS_CNTL; //dprefclk bypass211 uint32_t CLK1_CLK3_BYPASS_CNTL; //dcfclk bypass212 213};214 215/* For dtn logging and debugging */216struct clk_state_registers {217 uint32_t CLK0_CLK8_CURRENT_CNT; //dcfclk218 uint32_t CLK0_CLK8_DS_CNTL; //dcf_deep_sleep_divider219 uint32_t CLK0_CLK8_ALLOW_DS; //dcf_deep_sleep_allow220 uint32_t CLK0_CLK10_CURRENT_CNT; //dprefclk221 uint32_t CLK0_CLK11_CURRENT_CNT; //dispclk222};223 224/* TODO: combine this with the above */225struct clk_bypass {226 uint32_t dcfclk_bypass;227 uint32_t dispclk_pypass;228 uint32_t dprefclk_bypass;229};230/*231 * This table is not contiguous, can have holes, each232 * entry correspond to one set of WM. For example if233 * we have 2 DPM and LPDDR, we will WM set A, B and234 * D occupied, C will be emptry.235 */236struct wm_table {237 union {238 struct nv_wm_range_entry nv_entries[WM_SET_COUNT];239 struct wm_range_table_entry entries[WM_SET_COUNT];240 };241};242 243struct dummy_pstate_entry {244 unsigned int dram_speed_mts;245 unsigned int dummy_pstate_latency_us;246};247 248struct clk_bw_params {249 unsigned int vram_type;250 unsigned int num_channels;251 unsigned int dram_channel_width_bytes;252 unsigned int dispclk_vco_khz;253 unsigned int dc_mode_softmax_memclk;254 unsigned int max_memclk_mhz;255 struct clk_limit_table clk_table;256 struct wm_table wm_table;257 struct dummy_pstate_entry dummy_pstate_table[4];258 struct clk_limit_table_entry dc_mode_limit;259};260/* Public interfaces */261 262struct clk_states {263 uint32_t dprefclk_khz;264};265 266struct clk_mgr_funcs {267 /*268 * This function should set new clocks based on the input "safe_to_lower".269 * If safe_to_lower == false, then only clocks which are to be increased270 * should changed.271 * If safe_to_lower == true, then only clocks which are to be decreased272 * should be changed.273 */274 void (*update_clocks)(struct clk_mgr *clk_mgr,275 struct dc_state *context,276 bool safe_to_lower);277 278 int (*get_dp_ref_clk_frequency)(struct clk_mgr *clk_mgr);279 int (*get_dtb_ref_clk_frequency)(struct clk_mgr *clk_mgr);280 281 void (*set_low_power_state)(struct clk_mgr *clk_mgr);282 void (*exit_low_power_state)(struct clk_mgr *clk_mgr);283 bool (*is_ips_supported)(struct clk_mgr *clk_mgr);284 285 void (*init_clocks)(struct clk_mgr *clk_mgr);286 287 void (*dump_clk_registers)(struct clk_state_registers_and_bypass *regs_and_bypass,288 struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info);289 290 void (*enable_pme_wa) (struct clk_mgr *clk_mgr);291 void (*get_clock)(struct clk_mgr *clk_mgr,292 struct dc_state *context,293 enum dc_clock_type clock_type,294 struct dc_clock_config *clock_cfg);295 296 bool (*are_clock_states_equal) (struct dc_clocks *a,297 struct dc_clocks *b);298 void (*notify_wm_ranges)(struct clk_mgr *clk_mgr);299 300 /* Notify clk_mgr of a change in link rate, update phyclk frequency if necessary */301 void (*notify_link_rate_change)(struct clk_mgr *clk_mgr, struct dc_link *link);302 /*303 * Send message to PMFW to set hard min memclk frequency304 * When current_mode = false, set DPM0305 * When current_mode = true, set required clock for current mode306 */307 void (*set_hard_min_memclk)(struct clk_mgr *clk_mgr, bool current_mode);308 309 /* Send message to PMFW to set hard max memclk frequency to highest DPM */310 void (*set_hard_max_memclk)(struct clk_mgr *clk_mgr);311 312 /* Custom set a memclk freq range*/313 void (*set_max_memclk)(struct clk_mgr *clk_mgr, unsigned int memclk_mhz);314 void (*set_min_memclk)(struct clk_mgr *clk_mgr, unsigned int memclk_mhz);315 316 /* Get current memclk states from PMFW, update relevant structures */317 void (*get_memclk_states_from_smu)(struct clk_mgr *clk_mgr);318 319 /* Get SMU present */320 bool (*is_smu_present)(struct clk_mgr *clk_mgr);321 322 int (*get_dispclk_from_dentist)(struct clk_mgr *clk_mgr_base);323 324};325 326struct clk_mgr {327 struct dc_context *ctx;328 struct clk_mgr_funcs *funcs;329 struct dc_clocks clks;330 bool psr_allow_active_cache;331 bool force_smu_not_present;332 bool dc_mode_softmax_enabled;333 int dprefclk_khz; // Used by program pixel clock in clock source funcs, need to figureout where this goes334 int dp_dto_source_clock_in_khz; // Used to program DP DTO with ss adjustment on DCN314335 int dentist_vco_freq_khz;336 struct clk_state_registers_and_bypass boot_snapshot;337 struct clk_bw_params *bw_params;338 struct pp_smu_wm_range_sets ranges;339};340 341/* forward declarations */342struct dccg;343 344struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *pp_smu, struct dccg *dccg);345 346void dc_destroy_clk_mgr(struct clk_mgr *clk_mgr);347 348void clk_mgr_exit_optimized_pwr_state(const struct dc *dc, struct clk_mgr *clk_mgr);349 350void clk_mgr_optimize_pwr_state(const struct dc *dc, struct clk_mgr *clk_mgr);351 352#endif /* __DAL_CLK_MGR_H__ */353