1 /* Copyright 2018 Advanced Micro Devices, Inc. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a 4 * copy of this software and associated documentation files (the "Software"), 5 * to deal in the Software without restriction, including without limitation 6 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 * and/or sell copies of the Software, and to permit persons to whom the 8 * Software is furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 17 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 18 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 19 * OTHER DEALINGS IN THE SOFTWARE. 20 * 21 * Authors: AMD 22 * 23 */ 24 25 #include "power_helpers.h" 26 #include "dc/inc/hw/dmcu.h" 27 #include "dc/inc/hw/abm.h" 28 #include "dc.h" 29 #include "core_types.h" 30 #include "dmub_cmd.h" 31 32 #define DIV_ROUNDUP(a, b) (((a)+((b)/2))/(b)) 33 #define bswap16_based_on_endian(big_endian, value) \ 34 ((big_endian) ? cpu_to_be16(value) : cpu_to_le16(value)) 35 36 /* 37 * is_psr_su_specific_panel() - check if sink is AMD vendor-specific PSR-SU 38 * supported eDP device. 39 * 40 * @link: dc link pointer 41 * 42 * Return: true if AMDGPU vendor specific PSR-SU eDP panel 43 */ 44 bool is_psr_su_specific_panel(struct dc_link *link) 45 { 46 bool isPSRSUSupported = false; 47 struct dpcd_caps *dpcd_caps = &link->dpcd_caps; 48 49 if (dpcd_caps->edp_rev >= DP_EDP_14) { 50 if (dpcd_caps->psr_info.psr_version >= DP_PSR2_WITH_Y_COORD_ET_SUPPORTED) 51 isPSRSUSupported = true; 52 /* 53 * Some panels will report PSR capabilities over additional DPCD bits. 54 * Such panels are approved despite reporting only PSR v3, as long as 55 * the additional bits are reported. 56 */ 57 if (dpcd_caps->sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8) { 58 /* 59 * This is the temporary workaround to disable PSRSU when system turned on 60 * DSC function on the sepcific sink. 61 */ 62 if (dpcd_caps->psr_info.psr_version < DP_PSR2_WITH_Y_COORD_IS_SUPPORTED) 63 isPSRSUSupported = false; 64 else if (dpcd_caps->dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT && 65 ((dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x08) || 66 (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x07))) 67 isPSRSUSupported = false; 68 else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x03) 69 isPSRSUSupported = false; 70 else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x01) 71 isPSRSUSupported = false; 72 else if (dpcd_caps->psr_info.force_psrsu_cap == 0x1) 73 isPSRSUSupported = true; 74 } 75 } 76 77 return isPSRSUSupported; 78 } 79 80 /** 81 * mod_power_calc_psr_configs() - calculate/update generic psr configuration fields. 82 * @psr_config: [output], psr configuration structure to be updated 83 * @link: [input] dc link pointer 84 * @stream: [input] dc stream state pointer 85 * 86 * calculate and update the psr configuration fields that are not DM specific, i.e. such 87 * fields which are based on DPCD caps or timing information. To setup PSR in DMUB FW, 88 * this helper is assumed to be called before the call of the DC helper dc_link_setup_psr(). 89 * 90 * PSR config fields to be updated within the helper: 91 * - psr_rfb_setup_time 92 * - psr_sdp_transmit_line_num_deadline 93 * - line_time_in_us 94 * - su_y_granularity 95 * - su_granularity_required 96 * - psr_frame_capture_indication_req 97 * - psr_exit_link_training_required 98 * 99 * PSR config fields that are DM specific and NOT updated within the helper: 100 * - allow_smu_optimizations 101 * - allow_multi_disp_optimizations 102 */ 103 void mod_power_calc_psr_configs(struct psr_config *psr_config, 104 struct dc_link *link, 105 const struct dc_stream_state *stream) 106 { 107 unsigned int num_vblank_lines = 0; 108 unsigned int vblank_time_in_us = 0; 109 unsigned int sdp_tx_deadline_in_us = 0; 110 unsigned int line_time_in_us = 0; 111 struct dpcd_caps *dpcd_caps = &link->dpcd_caps; 112 const int psr_setup_time_step_in_us = 55; /* refer to eDP spec DPCD 0x071h */ 113 114 /* timing parameters */ 115 num_vblank_lines = stream->timing.v_total - 116 stream->timing.v_addressable - 117 stream->timing.v_border_top - 118 stream->timing.v_border_bottom; 119 120 vblank_time_in_us = (stream->timing.h_total * num_vblank_lines * 1000) / (stream->timing.pix_clk_100hz / 10); 121 122 line_time_in_us = ((stream->timing.h_total * 1000) / (stream->timing.pix_clk_100hz / 10)) + 1; 123 124 /** 125 * psr configuration fields 126 * 127 * as per eDP 1.5 pg. 377 of 459, DPCD 0x071h bits [3:1], psr setup time bits interpreted as below 128 * 000b <--> 330 us (default) 129 * 001b <--> 275 us 130 * 010b <--> 220 us 131 * 011b <--> 165 us 132 * 100b <--> 110 us 133 * 101b <--> 055 us 134 * 110b <--> 000 us 135 */ 136 psr_config->psr_rfb_setup_time = 137 (6 - dpcd_caps->psr_info.psr_dpcd_caps.bits.PSR_SETUP_TIME) * psr_setup_time_step_in_us; 138 139 if (psr_config->psr_rfb_setup_time > vblank_time_in_us) { 140 link->psr_settings.psr_frame_capture_indication_req = true; 141 link->psr_settings.psr_sdp_transmit_line_num_deadline = num_vblank_lines; 142 } else { 143 sdp_tx_deadline_in_us = vblank_time_in_us - psr_config->psr_rfb_setup_time; 144 145 /* Set the last possible line SDP may be transmitted without violating the RFB setup time */ 146 link->psr_settings.psr_frame_capture_indication_req = false; 147 link->psr_settings.psr_sdp_transmit_line_num_deadline = sdp_tx_deadline_in_us / line_time_in_us; 148 } 149 150 psr_config->psr_sdp_transmit_line_num_deadline = link->psr_settings.psr_sdp_transmit_line_num_deadline; 151 psr_config->line_time_in_us = line_time_in_us; 152 psr_config->su_y_granularity = dpcd_caps->psr_info.psr2_su_y_granularity_cap; 153 psr_config->su_granularity_required = dpcd_caps->psr_info.psr_dpcd_caps.bits.SU_GRANULARITY_REQUIRED; 154 psr_config->psr_frame_capture_indication_req = link->psr_settings.psr_frame_capture_indication_req; 155 psr_config->psr_exit_link_training_required = 156 !link->dpcd_caps.psr_info.psr_dpcd_caps.bits.LINK_TRAINING_ON_EXIT_NOT_REQUIRED; 157 } 158 159 void init_replay_config(struct dc_link *link, struct replay_config *pr_config) 160 { 161 link->replay_settings.config = *pr_config; 162 } 163 164 bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_state *stream) 165 { 166 return context && context->stream_count == 1 && dc_is_embedded_signal(stream->signal); 167 } 168 169 bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link, 170 struct dc_stream_state *stream, 171 struct psr_config *config) 172 { 173 uint32_t pic_height; 174 uint32_t slice_height; 175 176 config->dsc_slice_height = 0; 177 if (!(link->connector_signal & SIGNAL_TYPE_EDP) || 178 !dc->caps.edp_dsc_support || 179 link->panel_config.dsc.disable_dsc_edp || 180 !link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT || 181 !stream->timing.dsc_cfg.num_slices_v) 182 return true; 183 184 pic_height = stream->timing.v_addressable + 185 stream->timing.v_border_top + stream->timing.v_border_bottom; 186 187 if (stream->timing.dsc_cfg.num_slices_v == 0) 188 return false; 189 190 slice_height = pic_height / stream->timing.dsc_cfg.num_slices_v; 191 config->dsc_slice_height = (uint16_t)slice_height; 192 193 if (slice_height) { 194 if (config->su_y_granularity && 195 (slice_height % config->su_y_granularity)) { 196 ASSERT(0); 197 return false; 198 } 199 } 200 201 return true; 202 } 203 204 void set_replay_frame_skip_number(struct dc_link *link, 205 enum replay_coasting_vtotal_type type, 206 uint32_t coasting_vtotal_refresh_rate_uhz, 207 uint32_t flicker_free_refresh_rate_uhz, 208 bool is_defer) 209 { 210 uint32_t *frame_skip_number_array = NULL; 211 uint32_t frame_skip_number = 0; 212 213 if (link == NULL) 214 return; 215 216 if (false == link->replay_settings.config.frame_skip_supported) 217 return; 218 219 if (flicker_free_refresh_rate_uhz == 0 || coasting_vtotal_refresh_rate_uhz == 0) 220 return; 221 222 if (is_defer) 223 frame_skip_number_array = link->replay_settings.defer_frame_skip_number_table; 224 else 225 frame_skip_number_array = link->replay_settings.frame_skip_number_table; 226 227 if (frame_skip_number_array == NULL) 228 return; 229 230 frame_skip_number = (coasting_vtotal_refresh_rate_uhz + 500000) / flicker_free_refresh_rate_uhz; 231 232 if (frame_skip_number >= 1) 233 frame_skip_number_array[type] = frame_skip_number - 1; 234 else 235 frame_skip_number_array[type] = 0; 236 } 237 238 void set_replay_defer_update_coasting_vtotal(struct dc_link *link, 239 enum replay_coasting_vtotal_type type, 240 uint32_t vtotal) 241 { 242 link->replay_settings.defer_update_coasting_vtotal_table[type] = vtotal; 243 } 244 245 void update_replay_coasting_vtotal_from_defer(struct dc_link *link, 246 enum replay_coasting_vtotal_type type) 247 { 248 link->replay_settings.coasting_vtotal_table[type] = 249 link->replay_settings.defer_update_coasting_vtotal_table[type]; 250 link->replay_settings.frame_skip_number_table[type] = 251 link->replay_settings.defer_frame_skip_number_table[type]; 252 } 253 254 void set_replay_coasting_vtotal(struct dc_link *link, 255 enum replay_coasting_vtotal_type type, 256 uint32_t vtotal) 257 { 258 link->replay_settings.coasting_vtotal_table[type] = vtotal; 259 } 260 261 void set_replay_low_rr_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal) 262 { 263 link->replay_settings.low_rr_full_screen_video_pseudo_vtotal = vtotal; 264 } 265 266 void calculate_replay_link_off_frame_count(struct dc_link *link, 267 uint16_t vtotal, uint16_t htotal) 268 { 269 uint32_t max_link_off_frame_count = 0; 270 uint16_t max_deviation_line = 0, pixel_deviation_per_line = 0; 271 272 if (!link || link->replay_settings.config.replay_version != DC_FREESYNC_REPLAY) 273 return; 274 275 max_deviation_line = link->dpcd_caps.pr_info.max_deviation_line; 276 pixel_deviation_per_line = link->dpcd_caps.pr_info.pixel_deviation_per_line; 277 278 if (htotal != 0 && vtotal != 0 && pixel_deviation_per_line != 0) 279 max_link_off_frame_count = htotal * max_deviation_line / (pixel_deviation_per_line * vtotal); 280 else 281 ASSERT(0); 282 283 link->replay_settings.link_off_frame_count = max_link_off_frame_count; 284 } 285 286 void reset_replay_dsync_error_count(struct dc_link *link) 287 { 288 link->replay_settings.replay_desync_error_fail_count = 0; 289 } 290