1 /* 2 * Copyright 2017 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 DM_PP_SMU_IF__H 27 #define DM_PP_SMU_IF__H 28 29 /* 30 * interface to PPLIB/SMU to setup clocks and pstate requirements on SoC 31 */ 32 33 enum pp_smu_ver { 34 /* 35 * PP_SMU_INTERFACE_X should be interpreted as the interface defined 36 * starting from X, where X is some family of ASICs. This is as 37 * opposed to interfaces used only for X. There will be some degree 38 * of interface sharing between families of ASIcs. 39 */ 40 PP_SMU_UNSUPPORTED, 41 PP_SMU_VER_RV, 42 PP_SMU_VER_NV, 43 PP_SMU_VER_RN, 44 45 PP_SMU_VER_MAX 46 }; 47 48 struct pp_smu { 49 enum pp_smu_ver ver; 50 const void *pp; 51 52 /* 53 * interim extra handle for backwards compatibility 54 * as some existing functionality not yet implemented 55 * by ppsmu 56 */ 57 const void *dm; 58 }; 59 60 enum pp_smu_status { 61 PP_SMU_RESULT_UNDEFINED = 0, 62 PP_SMU_RESULT_OK = 1, 63 PP_SMU_RESULT_FAIL, 64 PP_SMU_RESULT_UNSUPPORTED 65 }; 66 67 #define PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN 0x0 68 #define PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX 0xFFFF 69 70 enum wm_type { 71 WM_TYPE_PSTATE_CHG = 0, 72 WM_TYPE_RETRAINING = 1, 73 }; 74 75 /* This structure is a copy of WatermarkRowGeneric_t defined by smuxx_driver_if.h*/ 76 struct pp_smu_wm_set_range { 77 uint16_t min_fill_clk_mhz; 78 uint16_t max_fill_clk_mhz; 79 uint16_t min_drain_clk_mhz; 80 uint16_t max_drain_clk_mhz; 81 82 uint8_t wm_inst; 83 uint8_t wm_type; 84 }; 85 86 #define MAX_WATERMARK_SETS 4 87 88 struct pp_smu_wm_range_sets { 89 unsigned int num_reader_wm_sets; 90 struct pp_smu_wm_set_range reader_wm_sets[MAX_WATERMARK_SETS]; 91 92 unsigned int num_writer_wm_sets; 93 struct pp_smu_wm_set_range writer_wm_sets[MAX_WATERMARK_SETS]; 94 }; 95 96 struct pp_smu_funcs_rv { 97 struct pp_smu pp_smu; 98 99 /* PPSMC_MSG_SetDisplayCount 100 * 0 triggers S0i2 optimization 101 */ 102 103 void (*set_display_count)(struct pp_smu *pp, int count); 104 105 /* reader and writer WM's are sent together as part of one table*/ 106 /* 107 * PPSMC_MSG_SetDriverDramAddrHigh 108 * PPSMC_MSG_SetDriverDramAddrLow 109 * PPSMC_MSG_TransferTableDram2Smu 110 * 111 * */ 112 void (*set_wm_ranges)(struct pp_smu *pp, 113 struct pp_smu_wm_range_sets *ranges); 114 115 /* PPSMC_MSG_SetHardMinDcfclkByFreq 116 * fixed clock at requested freq, either from FCH bypass or DFS 117 */ 118 void (*set_hard_min_dcfclk_by_freq)(struct pp_smu *pp, int mhz); 119 120 /* PPSMC_MSG_SetMinDeepSleepDcfclk 121 * when DF is in cstate, dcf clock is further divided down 122 * to just above given frequency 123 */ 124 void (*set_min_deep_sleep_dcfclk)(struct pp_smu *pp, int mhz); 125 126 /* PPSMC_MSG_SetHardMinFclkByFreq 127 * FCLK will vary with DPM, but never below requested hard min 128 */ 129 void (*set_hard_min_fclk_by_freq)(struct pp_smu *pp, int mhz); 130 131 /* PPSMC_MSG_SetHardMinSocclkByFreq 132 * Needed for DWB support 133 */ 134 void (*set_hard_min_socclk_by_freq)(struct pp_smu *pp, int mhz); 135 136 /* PME w/a */ 137 void (*set_pme_wa_enable)(struct pp_smu *pp); 138 }; 139 140 /* Used by pp_smu_funcs_nv.set_voltage_by_freq 141 * 142 */ 143 enum pp_smu_nv_clock_id { 144 PP_SMU_NV_DISPCLK, 145 PP_SMU_NV_PHYCLK, 146 PP_SMU_NV_PIXELCLK 147 }; 148 149 /* 150 * Used by pp_smu_funcs_nv.get_maximum_sustainable_clocks 151 */ 152 struct pp_smu_nv_clock_table { 153 // voltage managed SMU, freq set by driver 154 unsigned int displayClockInKhz; 155 unsigned int dppClockInKhz; 156 unsigned int phyClockInKhz; 157 unsigned int pixelClockInKhz; 158 unsigned int dscClockInKhz; 159 160 // freq/voltage managed by SMU 161 unsigned int fabricClockInKhz; 162 unsigned int socClockInKhz; 163 unsigned int dcfClockInKhz; 164 unsigned int uClockInKhz; 165 }; 166 167 struct pp_smu_funcs_nv { 168 struct pp_smu pp_smu; 169 170 /* PPSMC_MSG_SetDisplayCount 171 * 0 triggers S0i2 optimization 172 */ 173 enum pp_smu_status (*set_display_count)(struct pp_smu *pp, int count); 174 175 /* PPSMC_MSG_SetHardMinDcfclkByFreq 176 * fixed clock at requested freq, either from FCH bypass or DFS 177 */ 178 enum pp_smu_status (*set_hard_min_dcfclk_by_freq)(struct pp_smu *pp, int Mhz); 179 180 /* PPSMC_MSG_SetMinDeepSleepDcfclk 181 * when DF is in cstate, dcf clock is further divided down 182 * to just above given frequency 183 */ 184 enum pp_smu_status (*set_min_deep_sleep_dcfclk)(struct pp_smu *pp, int Mhz); 185 186 /* PPSMC_MSG_SetHardMinUclkByFreq 187 * UCLK will vary with DPM, but never below requested hard min 188 */ 189 enum pp_smu_status (*set_hard_min_uclk_by_freq)(struct pp_smu *pp, int Mhz); 190 191 /* PPSMC_MSG_SetHardMinSocclkByFreq 192 * Needed for DWB support 193 */ 194 enum pp_smu_status (*set_hard_min_socclk_by_freq)(struct pp_smu *pp, int Mhz); 195 196 /* PME w/a */ 197 enum pp_smu_status (*set_pme_wa_enable)(struct pp_smu *pp); 198 199 /* PPSMC_MSG_SetHardMinByFreq 200 * Needed to set ASIC voltages for clocks programmed by DAL 201 */ 202 enum pp_smu_status (*set_voltage_by_freq)(struct pp_smu *pp, 203 enum pp_smu_nv_clock_id clock_id, int Mhz); 204 205 /* reader and writer WM's are sent together as part of one table*/ 206 /* 207 * PPSMC_MSG_SetDriverDramAddrHigh 208 * PPSMC_MSG_SetDriverDramAddrLow 209 * PPSMC_MSG_TransferTableDram2Smu 210 * 211 * on DCN20: 212 * reader fill clk = uclk 213 * reader drain clk = dcfclk 214 * writer fill clk = socclk 215 * writer drain clk = uclk 216 * */ 217 enum pp_smu_status (*set_wm_ranges)(struct pp_smu *pp, 218 struct pp_smu_wm_range_sets *ranges); 219 220 /* Not a single SMU message. This call should return maximum sustainable limit for all 221 * clocks that DC depends on. These will be used as basis for mode enumeration. 222 */ 223 enum pp_smu_status (*get_maximum_sustainable_clocks)(struct pp_smu *pp, 224 struct pp_smu_nv_clock_table *max_clocks); 225 226 /* This call should return the discrete uclk DPM states available 227 */ 228 enum pp_smu_status (*get_uclk_dpm_states)(struct pp_smu *pp, 229 unsigned int *clock_values_in_khz, unsigned int *num_states); 230 231 /* Not a single SMU message. This call informs PPLIB that display will not be able 232 * to perform pstate handshaking in its current state. Typically this handshake 233 * is used to perform uCLK switching, so disabling pstate disables uCLK switching. 234 * 235 * Note that when setting handshake to unsupported, the call is pre-emptive. That means 236 * DC will make the call BEFORE setting up the display state which would cause pstate 237 * request to go un-acked. Only when the call completes should such a state be applied to 238 * DC hardware 239 */ 240 enum pp_smu_status (*set_pstate_handshake_support)(struct pp_smu *pp, 241 bool pstate_handshake_supported); 242 }; 243 244 #define PP_SMU_NUM_SOCCLK_DPM_LEVELS 8 245 #define PP_SMU_NUM_DCFCLK_DPM_LEVELS 8 246 #define PP_SMU_NUM_FCLK_DPM_LEVELS 4 247 #define PP_SMU_NUM_MEMCLK_DPM_LEVELS 4 248 249 struct dpm_clock { 250 uint32_t Freq; // In MHz 251 uint32_t Vol; // Millivolts with 2 fractional bits 252 }; 253 254 255 /* this is a copy of the structure defined in smuxx_driver_if.h*/ 256 struct dpm_clocks { 257 struct dpm_clock DcfClocks[PP_SMU_NUM_DCFCLK_DPM_LEVELS]; 258 struct dpm_clock SocClocks[PP_SMU_NUM_SOCCLK_DPM_LEVELS]; 259 struct dpm_clock FClocks[PP_SMU_NUM_FCLK_DPM_LEVELS]; 260 struct dpm_clock MemClocks[PP_SMU_NUM_MEMCLK_DPM_LEVELS]; 261 }; 262 263 264 struct pp_smu_funcs_rn { 265 struct pp_smu pp_smu; 266 267 /* 268 * reader and writer WM's are sent together as part of one table 269 * 270 * PPSMC_MSG_SetDriverDramAddrHigh 271 * PPSMC_MSG_SetDriverDramAddrLow 272 * PPSMC_MSG_TransferTableDram2Smu 273 * 274 */ 275 enum pp_smu_status (*set_wm_ranges)(struct pp_smu *pp, 276 struct pp_smu_wm_range_sets *ranges); 277 278 enum pp_smu_status (*get_dpm_clock_table) (struct pp_smu *pp, 279 struct dpm_clocks *clock_table); 280 }; 281 282 struct pp_smu_funcs_vgh { 283 struct pp_smu pp_smu; 284 285 /* 286 * reader and writer WM's are sent together as part of one table 287 * 288 * PPSMC_MSG_SetDriverDramAddrHigh 289 * PPSMC_MSG_SetDriverDramAddrLow 290 * PPSMC_MSG_TransferTableDram2Smu 291 * 292 */ 293 // TODO: Check whether this is moved to DAL, and remove as needed 294 enum pp_smu_status (*set_wm_ranges)(struct pp_smu *pp, 295 struct pp_smu_wm_range_sets *ranges); 296 297 // TODO: Check whether this is moved to DAL, and remove as needed 298 enum pp_smu_status (*get_dpm_clock_table) (struct pp_smu *pp, 299 struct dpm_clocks *clock_table); 300 301 enum pp_smu_status (*notify_smu_timeout) (struct pp_smu *pp); 302 }; 303 304 struct pp_smu_funcs { 305 struct pp_smu ctx; 306 union { 307 struct pp_smu_funcs_rv rv_funcs; 308 struct pp_smu_funcs_nv nv_funcs; 309 struct pp_smu_funcs_rn rn_funcs; 310 struct pp_smu_funcs_vgh vgh_funcs; 311 }; 312 }; 313 314 #endif /* DM_PP_SMU_IF__H */ 315